ASoC: rockchip: cleanup codes

Change-Id: Ieacbcc8311fa683394c57a21c69099620b294ffc
Signed-off-by: Sugar Zhang <sugar.zhang@rock-chips.com>
This commit is contained in:
Sugar Zhang
2017-04-19 11:47:22 +08:00
committed by Huang, Tao
parent 805a10e48f
commit 90da176da8
37 changed files with 0 additions and 9863 deletions

View File

@@ -1,136 +0,0 @@
/*
* card_info.c
*
* 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.
*
*/
#include <linux/module.h>
#include <linux/device.h>
#include <linux/of.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
/*
Get sound card infos:
audio-codec
audio-controller
format
continuous-clock
bitclock-inversion
frame-inversion
bitclock-master
frame-master
Get audio-codec and audio-controller in this fun,
and get oher infos in fun snd_soc_of_parse_daifmt().
Set in dts:
dais {
dai0 {
audio-codec = <&codec_of_node>;
audio-controller = <&cpu_of_node>;
format = "i2s";
//continuous-clock;
//bitclock-inversion;
//frame-inversion;
//bitclock-master;
//frame-master;
};
dai1 {
audio-codec = <&codec_of_node>;
audio-controller = <&cpu_of_node>;
format = "dsp_a";
//continuous-clock;
bitclock-inversion;
//frame-inversion;
//bitclock-master;
//frame-master;
};
};
*/
int rockchip_of_get_sound_card_info_(struct snd_soc_card *card,
bool is_need_fmt)
{
struct device_node *dai_node, *child_dai_node;
int dai_num;
dai_node = of_get_child_by_name(card->dev->of_node, "dais");
if (!dai_node) {
dev_err(card->dev, "%s() Can not get child: dais\n",
__func__);
return -EINVAL;
}
dai_num = 0;
for_each_child_of_node(dai_node, child_dai_node) {
if (is_need_fmt) {
card->dai_link[dai_num].dai_fmt =
snd_soc_of_parse_daifmt(child_dai_node, NULL);
if ((card->dai_link[dai_num].dai_fmt &
SND_SOC_DAIFMT_MASTER_MASK) == 0) {
dev_err(card->dev,
"Property 'format' missing or invalid\n");
return -EINVAL;
}
}
card->dai_link[dai_num].codec_name = NULL;
card->dai_link[dai_num].cpu_dai_name = NULL;
card->dai_link[dai_num].platform_name = NULL;
card->dai_link[dai_num].codec_of_node = of_parse_phandle(
child_dai_node,
"audio-codec", 0);
if (!card->dai_link[dai_num].codec_of_node) {
dev_err(card->dev,
"Property 'audio-codec' missing or invalid\n");
return -EINVAL;
}
card->dai_link[dai_num].cpu_of_node = of_parse_phandle(
child_dai_node,
"audio-controller", 0);
if (!card->dai_link[dai_num].cpu_of_node) {
dev_err(card->dev,
"Property 'audio-controller' missing or invalid\n");
return -EINVAL;
}
card->dai_link[dai_num].platform_of_node =
card->dai_link[dai_num].cpu_of_node;
if (++dai_num >= card->num_links)
break;
}
if (dai_num < card->num_links) {
dev_err(card->dev, "%s() Can not get enough property for dais, dai: %d, max dai num: %d\n",
__func__, dai_num, card->num_links);
return -EINVAL;
}
return 0;
}
EXPORT_SYMBOL_GPL(rockchip_of_get_sound_card_info_);
int rockchip_of_get_sound_card_info(struct snd_soc_card *card)
{
return rockchip_of_get_sound_card_info_(card, true);
}
EXPORT_SYMBOL_GPL(rockchip_of_get_sound_card_info);
/* Module information */
MODULE_AUTHOR("Jear <Jear.Chen@rock-chips.com>");
MODULE_DESCRIPTION("ROCKCHIP ASoC Interface");
MODULE_LICENSE("GPL");

View File

@@ -1,16 +0,0 @@
/*
* card_info.h - ALSA PCM interface for Rockchip
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _SND_SOC_ROCKCHIP_CARD_INFO_H
#define _SND_SOC_ROCKCHIP_CARD_INFO_H
int rockchip_of_get_sound_card_info_(struct snd_soc_card *card,
bool is_need_fmt);
int rockchip_of_get_sound_card_info(struct snd_soc_card *card);
#endif /* _SND_SOC_ROCKCHIP_CARD_INFO_H */

View File

@@ -1,145 +0,0 @@
/*
* rk2928-card.c -- SoC audio for RockChip RK2928
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#include <linux/delay.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include "card_info.h"
#include "rk_pcm.h"
#include "rk_i2s.h"
#ifdef DEBUG
#define DBG(format, ...) \
printk(KERN_INFO "RK2928 Card: " format "\n", ## __VA_ARGS__)
#else
#define DBG(format, ...)
#endif
static int rk2928_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
unsigned int pll_out = 0, dai_fmt = rtd->card->dai_link->dai_fmt;
int div_bclk,div_mclk;
int ret;
DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
/* set codec DAI configuration */
ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
if (ret < 0) {
printk("%s():failed to set the format for codec side\n", __FUNCTION__);
return ret;
}
/* set cpu DAI configuration */
ret = snd_soc_dai_set_fmt(cpu_dai, dai_fmt);
if (ret < 0) {
printk("%s():failed to set the format for cpu side\n", __FUNCTION__);
return ret;
}
DBG("Enter:%s, %d, rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
pll_out = 256 * params_rate(params);
snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
if ((dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBS_CFS) {
div_bclk = 63;
div_mclk = pll_out/(params_rate(params)*64) - 1;
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK,div_bclk);
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, div_mclk);
}
return 0;
}
static struct snd_soc_ops rk2928_dai_ops = {
.hw_params = rk2928_dai_hw_params,
};
static struct snd_soc_dai_link rk2928_dai[] = {
{
.name = "RK2928",
.stream_name = "RK2928",
.codec_dai_name = "rk2928-codec",
.ops = &rk2928_dai_ops,
},
};
/* Audio machine driver */
static struct snd_soc_card rockchip_rk2928_snd_card = {
.name = "RK2928",
.dai_link = rk2928_dai,
.num_links = ARRAY_SIZE(rk2928_dai),
};
static int rockchip_rk2928_audio_probe(struct platform_device *pdev)
{
int ret;
struct snd_soc_card *card = &rockchip_rk2928_snd_card;
card->dev = &pdev->dev;
ret = snd_soc_register_card(card);
if (ret)
printk("%s() register card failed:%d\n", __FUNCTION__, ret);
return ret;
}
static int rockchip_rk2928_audio_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
snd_soc_unregister_card(card);
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id rockchip_rk2928_of_match[] = {
{ .compatible = "rockchip-rk2928", },
{},
};
MODULE_DEVICE_TABLE(of, rockchip_rk2928_of_match);
#endif /* CONFIG_OF */
static struct platform_driver rockchip_rk2928_audio_driver = {
.driver = {
.name = "rockchip-rk2928",
.owner = THIS_MODULE,
.pm = &snd_soc_pm_ops,
.of_match_table = of_match_ptr(rockchip_rk2928_of_match),
},
.probe = rockchip_rk2928_audio_probe,
.remove = rockchip_rk2928_audio_remove,
};
module_platform_driver(rockchip_rk2928_audio_driver);
MODULE_DESCRIPTION("ALSA SoC RK2928");
MODULE_LICENSE("GPL");

View File

@@ -1,862 +0,0 @@
/*
* rk29_i2s.c -- ALSA SoC ROCKCHIP IIS Audio Layer Platform driver
*
* Driver for rockchip iis audio
*
*
* 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.
*
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/version.h>
#include <asm/dma.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/initval.h>
#include <sound/soc.h>
#include <asm/io.h>
#include <mach/hardware.h>
#include <mach/board.h>
#include <mach/rk29_iomap.h>
#include <mach/rk29-dma-pl330.h>
#include <mach/iomux.h>
#include <mach/cru.h>
#include "rk_pcm.h"
#include "rk_i2s.h"
#if 0
#define I2S_DBG(x...) printk(KERN_INFO x)
#else
#define I2S_DBG(x...) do { } while (0)
#endif
#define pheadi2s ((pI2S_REG)(i2s->regs))
#define MAX_I2S 2
struct rk29_i2s_info {
struct device *dev;
void __iomem *regs;
u32 feature;
struct clk *iis_clk;
struct clk *iis_pclk;
unsigned char master;
struct rockchip_pcm_dma_params *dma_playback;
struct rockchip_pcm_dma_params *dma_capture;
u32 suspend_iismod;
u32 suspend_iiscon;
u32 suspend_iispsr;
};
static struct rk29_dma_client rk29_dma_client_out = {
.name = "I2S PCM Stereo Out"
};
static struct rk29_dma_client rk29_dma_client_in = {
.name = "I2S PCM Stereo In"
};
static inline struct rk29_i2s_info *to_info(struct snd_soc_dai *cpu_dai)
{
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
return snd_soc_dai_get_drvdata(cpu_dai);
#else
return cpu_dai->private_data;
#endif
}
static struct rockchip_pcm_dma_params rk29_i2s_pcm_stereo_out[MAX_I2S];
static struct rockchip_pcm_dma_params rk29_i2s_pcm_stereo_in[MAX_I2S];
static struct rk29_i2s_info rk29_i2s[MAX_I2S];
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
struct snd_soc_dai_driver rk29_i2s_dai[MAX_I2S];
#else
struct snd_soc_dai rk29_i2s_dai[MAX_I2S];
#endif
EXPORT_SYMBOL_GPL(rk29_i2s_dai);
/*
static struct rockchip_pcm_dma_params rockchip_i2s_pcm_stereo_out[MAX_I2S] = {
[0] = {
.client = &rk29_dma_client_out,
.channel = DMACH_I2S_2CH_TX, ///0, //DMACH_I2S_OUT,
.dma_addr = RK29_I2S_2CH_PHYS + I2S_TXR_BUFF,
.dma_size = 4,
},
[1] = {
.client = &rk29_dma_client_out,
.channel = DMACH_I2S_8CH_TX, ///0, //DMACH_I2S_OUT,
.dma_addr = RK29_I2S_8CH_PHYS + I2S_TXR_BUFF,
.dma_size = 4,
},
};
static struct rockchip_pcm_dma_params rockchip_i2s_pcm_stereo_in[MAX_I2S] = {
[0] = {
.client = &rk29_dma_client_in,
.channel = DMACH_I2S_2CH_RX, ///1, //DMACH_I2S_IN,
.dma_addr = RK29_I2S_2CH_PHYS + I2S_RXR_BUFF,
.dma_size = 4,
},
[1] = {
.client = &rk29_dma_client_in,
.channel = DMACH_I2S_8CH_RX, ///1, //DMACH_I2S_IN,
.dma_addr = RK29_I2S_8CH_PHYS + I2S_RXR_BUFF,
.dma_size = 4,
},
};
*/
#if 1
static u32 i2s0_clk_enter(void)
{
u32 clk = cru_readl(CRU_CLKSEL3_CON);
cru_writel(0x1ffff, CRU_CLKSEL3_CON);
mdelay(1);
return clk;
}
static void i2s0_clk_exit(u32 clk)
{
mdelay(1);
cru_writel(clk, CRU_CLKSEL3_CON);
mdelay(1);
}
#else
static u32 i2s0_clk_enter()
{
return 0;
}
static void i2s0_clk_exit(u32 clk)
{
}
#endif
/*
*Turn on or off the transmission path.
*/
static int flag_i2s_tx = 0;
static int flag_i2s_rx = 0;
static void rockchip_snd_txctrl(struct rk29_i2s_info *i2s, int on, bool stopI2S)
{
u32 opr,xfer;
u32 clk;
opr = readl(&(pheadi2s->I2S_DMACR));
xfer = readl(&(pheadi2s->I2S_XFER));
if (on)
{
I2S_DBG("rockchip_snd_txctrl: on\n");
//start tx
//if ((flag_i2s_tx == 0) && (flag_i2s_rx == 0))
if ((xfer&I2S_TX_TRAN_START)==0 || (xfer&I2S_RX_TRAN_START)==0)
{
clk = i2s0_clk_enter();
//if start tx & rx clk, need reset i2s
xfer |= I2S_TX_TRAN_START;
xfer |= I2S_RX_TRAN_START;
writel(xfer, &(pheadi2s->I2S_XFER));
i2s0_clk_exit(clk);
}
if ((opr & I2S_TRAN_DMA_ENABLE) == 0)
{
opr |= I2S_TRAN_DMA_ENABLE;
writel(opr, &(pheadi2s->I2S_DMACR));
}
flag_i2s_tx = 1;
}
else
{
//stop tx
flag_i2s_tx = 0;
if ((flag_i2s_rx == 0) && (flag_i2s_tx == 0))
{
opr &= ~I2S_TRAN_DMA_ENABLE;
writel(opr, &(pheadi2s->I2S_DMACR));
if(stopI2S)
{
clk = i2s0_clk_enter();
xfer &= ~I2S_RX_TRAN_START;
xfer &= ~I2S_TX_TRAN_START;
writel(xfer, &(pheadi2s->I2S_XFER));
i2s0_clk_exit(clk);
}
//after stop rx & tx clk, reset i2s
//writel(0x001,&(pheadi2s->I2S_TXRST));
//writel(0x001,&(pheadi2s->I2S_RXRST));
}
I2S_DBG("rockchip_snd_txctrl: off\n");
}
}
static void rockchip_snd_rxctrl(struct rk29_i2s_info *i2s, int on, bool stopI2S)
{
u32 opr,xfer;
u32 clk;
opr = readl(&(pheadi2s->I2S_DMACR));
xfer = readl(&(pheadi2s->I2S_XFER));
if (on)
{
I2S_DBG("rockchip_snd_rxctrl: on\n");
//start rx
//if ((flag_i2s_tx == 0) && (flag_i2s_rx == 0))
if ((xfer&I2S_TX_TRAN_START)==0 || (xfer&I2S_RX_TRAN_START)==0)
{
clk = i2s0_clk_enter();
xfer |= I2S_TX_TRAN_START;
xfer |= I2S_RX_TRAN_START;
writel(xfer, &(pheadi2s->I2S_XFER));
i2s0_clk_exit(clk);
}
if ((opr & I2S_RECE_DMA_ENABLE) == 0)
{
opr |= I2S_RECE_DMA_ENABLE;
writel(opr, &(pheadi2s->I2S_DMACR));
}
flag_i2s_rx = 1;
#if (CONFIG_SND_SOC_RT5631)
//bard 7-16 s
schedule_delayed_work(&rt5631_delay_cap,HZ/4);
//bard 7-16 e
#endif
}
else
{
//stop rx
flag_i2s_rx = 0;
if ((flag_i2s_rx == 0) && (flag_i2s_tx == 0))
{
opr &= ~I2S_RECE_DMA_ENABLE;
writel(opr, &(pheadi2s->I2S_DMACR));
if(stopI2S)
{
clk = i2s0_clk_enter();
xfer &= ~I2S_RX_TRAN_START;
xfer &= ~I2S_TX_TRAN_START;
writel(xfer, &(pheadi2s->I2S_XFER));
i2s0_clk_exit(clk);
}
//after stop rx & tx clk, reset i2s
//writel(0x001,&(pheadi2s->I2S_TXRST));
//writel(0x001,&(pheadi2s->I2S_RXRST));
}
I2S_DBG("rockchip_snd_rxctrl: off\n");
}
}
/*
* Set Rockchip I2S DAI format
*/
static int rockchip_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
unsigned int fmt)
{
struct rk29_i2s_info *i2s = to_info(cpu_dai);
u32 tx_ctl,rx_ctl;
I2S_DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
tx_ctl = readl(&(pheadi2s->I2S_TXCR));
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM:
tx_ctl &= ~I2S_MODE_MASK;
tx_ctl |= I2S_MASTER_MODE;
break;
case SND_SOC_DAIFMT_CBS_CFS:
tx_ctl &= ~I2S_MODE_MASK;
tx_ctl |= I2S_SLAVE_MODE;
break;
default:
I2S_DBG("unknwon master/slave format\n");
return -EINVAL;
}
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_RIGHT_J:
tx_ctl &= ~I2S_BUS_MODE_MASK; //I2S Bus Mode
tx_ctl |= I2S_BUS_MODE_RSJM;
break;
case SND_SOC_DAIFMT_LEFT_J:
tx_ctl &= ~I2S_BUS_MODE_MASK; //I2S Bus Mode
tx_ctl |= I2S_BUS_MODE_LSJM;
break;
case SND_SOC_DAIFMT_I2S:
tx_ctl &= ~I2S_BUS_MODE_MASK; //I2S Bus Mode
tx_ctl |= I2S_BUS_MODE_NOR;
break;
default:
I2S_DBG("Unknown data format\n");
return -EINVAL;
}
I2S_DBG("Enter::%s----%d, I2S_TXCR=0x%X\n",__FUNCTION__,__LINE__,tx_ctl);
#if 0//defined(CONFIG_SND_RK_SOC_alc5631) || defined(CONFIG_SND_RK_SOC_alc5621)
rx_ctl = tx_ctl;
rx_ctl &= ~I2S_MODE_MASK;
rx_ctl |= I2S_SLAVE_MODE; // set tx slave, rx master
writel(rx_ctl, &(pheadi2s->I2S_TXCR));
#else
writel(tx_ctl, &(pheadi2s->I2S_TXCR));
#endif
rx_ctl = tx_ctl & 0x00007FFF;
writel(rx_ctl, &(pheadi2s->I2S_RXCR));
return 0;
}
static int rockchip_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, struct snd_soc_dai *socdai)
{
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
struct rk29_i2s_info *i2s = to_info(socdai);
#else
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai_link *dai = rtd->dai;
struct rk29_i2s_info *i2s = to_info(dai->cpu_dai);
#endif
u32 iismod;
u32 dmarc;
I2S_DBG("Enter %s, %d >>>>>>>>>>>\n", __func__, __LINE__);
/*by Vincent Hsiung for EQ Vol Change*/
#define HW_PARAMS_FLAG_EQVOL_ON 0x21
#define HW_PARAMS_FLAG_EQVOL_OFF 0x22
if ((params->flags == HW_PARAMS_FLAG_EQVOL_ON)||(params->flags == HW_PARAMS_FLAG_EQVOL_OFF))
{
return 0;
}
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
snd_soc_dai_set_dma_data(socdai, substream, i2s->dma_playback);
else
snd_soc_dai_set_dma_data(socdai, substream, i2s->dma_capture);
#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
dai->cpu_dai->playback.dma_data = i2s->dma_playback;
else
dai->cpu_dai->capture.dma_data = i2s->dma_capture;
#else
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
dai->cpu_dai->dma_data = i2s->dma_playback;
else
dai->cpu_dai->dma_data = i2s->dma_capture;
#endif
/* Working copies of register */
iismod = readl(&(pheadi2s->I2S_TXCR));
//iismod &= (~((1<<5)-1));
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S8:
iismod |= SAMPLE_DATA_8bit;
break;
case SNDRV_PCM_FORMAT_S16_LE:
iismod |= I2S_DATA_WIDTH(15);
break;
case SNDRV_PCM_FORMAT_S20_3LE:
iismod |= I2S_DATA_WIDTH(19);
break;
case SNDRV_PCM_FORMAT_S24_LE:
iismod |= I2S_DATA_WIDTH(23);
break;
case SNDRV_PCM_FORMAT_S32_LE:
iismod |= I2S_DATA_WIDTH(31);
break;
}
#if defined (CONFIG_SND_RK_CODEC_SOC_SLAVE)
iismod &= ~I2S_SLAVE_MODE;
#endif
#if defined (CONFIG_SND_RK_CODEC_SOC_MASTER)
iismod |= I2S_SLAVE_MODE;
#endif
//writel((16<<24) |(16<<18)|(16<<12)|(16<<6)|16, &(pheadi2s->I2S_FIFOLR));
dmarc = readl(&(pheadi2s->I2S_DMACR));
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
dmarc = ((dmarc & 0xFFFFFE00) | 16);
else
dmarc = ((dmarc & 0xFE00FFFF) | 16<<16);
writel(dmarc, &(pheadi2s->I2S_DMACR));
I2S_DBG("Enter %s, %d I2S_TXCR=0x%08X\n", __func__, __LINE__, iismod);
#if 0//defined(CONFIG_SND_RK_SOC_alc5631) || defined(CONFIG_SND_RK_SOC_alc5621)
dmarc = iismod;
dmarc &= ~I2S_MODE_MASK;
dmarc |= I2S_SLAVE_MODE; // set tx slave, rx master
writel(dmarc, &(pheadi2s->I2S_TXCR));
#else
writel(iismod, &(pheadi2s->I2S_TXCR));
#endif
iismod = iismod & 0x00007FFF;
writel(iismod, &(pheadi2s->I2S_RXCR));
return 0;
}
static int rockchip_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai)
{
int ret = 0;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
struct rk29_i2s_info *i2s = to_info(rtd->cpu_dai);
#else
struct rk29_i2s_info *i2s = to_info(rtd->dai->cpu_dai);
#endif
bool stopI2S = false;
I2S_DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
rockchip_snd_rxctrl(i2s, 1, stopI2S);
else
rockchip_snd_txctrl(i2s, 1, stopI2S);
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
stopI2S = true;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
rockchip_snd_rxctrl(i2s, 0, stopI2S);
else
rockchip_snd_txctrl(i2s, 0, stopI2S);
break;
default:
ret = -EINVAL;
break;
}
return ret;
}
/*
* Set Rockchip Clock source
*/
static int rockchip_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
int clk_id, unsigned int freq, int dir)
{
struct rk29_i2s_info *i2s;
i2s = to_info(cpu_dai);
I2S_DBG("Enter:%s, %d, i2s=0x%p, freq=%d\n", __FUNCTION__, __LINE__, i2s, freq);
/*add scu clk source and enable clk*/
clk_set_rate(i2s->iis_clk, freq);
return 0;
}
/*
* Set Rockchip Clock dividers
*/
static int rockchip_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai,
int div_id, int div)
{
struct rk29_i2s_info *i2s;
u32 reg;
i2s = to_info(cpu_dai);
/*stereo mode MCLK/SCK=4*/
reg = readl(&(pheadi2s->I2S_TXCKR));
I2S_DBG("Enter:%s, %d, div_id=0x%08X, div=0x%08X\n", __FUNCTION__, __LINE__, div_id, div);
/*when i2s in master mode ,must set codec pll div*/
switch (div_id) {
case ROCKCHIP_DIV_BCLK:
reg &= ~I2S_TX_SCLK_DIV_MASK;
reg |= I2S_TX_SCLK_DIV(div);
break;
case ROCKCHIP_DIV_MCLK:
reg &= ~I2S_MCLK_DIV_MASK;
reg |= I2S_MCLK_DIV(div);
break;
case ROCKCHIP_DIV_PRESCALER:
break;
default:
return -EINVAL;
}
writel(reg, &(pheadi2s->I2S_TXCKR));
writel(reg, &(pheadi2s->I2S_RXCKR));
return 0;
}
/*
* To avoid duplicating clock code, allow machine driver to
* get the clockrate from here.
*/
u32 rockchip_i2s_get_clockrate(void)
{
I2S_DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
return 0; ///clk_get_rate(s3c24xx_i2s.iis_clk);
}
EXPORT_SYMBOL_GPL(rockchip_i2s_get_clockrate);
#ifdef CONFIG_PM
int rockchip_i2s_suspend(struct snd_soc_dai *cpu_dai)
{
I2S_DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
//clk_disable(clk);
return 0;
}
int rockchip_i2s_resume(struct snd_soc_dai *cpu_dai)
{
I2S_DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
//clk_enable(clk);
return 0;
}
#else
#define rockchip_i2s_suspend NULL
#define rockchip_i2s_resume NULL
#endif
#if defined(CONFIG_SND_RK_SOC_alc5631) || defined(CONFIG_SND_RK_SOC_alc5621)
#define ROCKCHIP_I2S_RATES (SNDRV_PCM_RATE_44100) //zyy 20110704, playback and record use same sample rate
#else
#define ROCKCHIP_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
#endif
static struct snd_soc_dai_ops rockchip_i2s_dai_ops = {
.trigger = rockchip_i2s_trigger,
.hw_params = rockchip_i2s_hw_params,
.set_fmt = rockchip_i2s_set_fmt,
.set_clkdiv = rockchip_i2s_set_clkdiv,
.set_sysclk = rockchip_i2s_set_sysclk,
};
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
static int rockchip_i2s_dai_probe(struct snd_soc_dai *dai)
#else
static int rockchip_i2s_dai_probe(struct platform_device *pdev, struct snd_soc_dai *dai)
#endif
{
I2S_DBG("Enter %s, %d >>>>>>>>>>>\n", __func__, __LINE__);
switch(dai->id) {
case 0:
rk29_mux_api_set(GPIO2D0_I2S0CLK_MIIRXCLKIN_NAME, GPIO2H_I2S0_CLK);
rk29_mux_api_set(GPIO2D1_I2S0SCLK_MIICRS_NAME, GPIO2H_I2S0_SCLK);
rk29_mux_api_set(GPIO2D2_I2S0LRCKRX_MIITXERR_NAME, GPIO2H_I2S0_LRCK_RX);
rk29_mux_api_set(GPIO2D3_I2S0SDI_MIICOL_NAME, GPIO2H_I2S0_SDI);
rk29_mux_api_set(GPIO2D4_I2S0SDO0_MIIRXD2_NAME, GPIO2H_I2S0_SDO0);
rk29_mux_api_set(GPIO2D5_I2S0SDO1_MIIRXD3_NAME, GPIO2H_I2S0_SDO1);
rk29_mux_api_set(GPIO2D6_I2S0SDO2_MIITXD2_NAME, GPIO2H_I2S0_SDO2);
rk29_mux_api_set(GPIO2D7_I2S0SDO3_MIITXD3_NAME, GPIO2H_I2S0_SDO3);
rk29_mux_api_set(GPIO4D6_I2S0LRCKTX0_NAME, GPIO4H_I2S0_LRCK_TX0);
rk29_mux_api_set(GPIO4D7_I2S0LRCKTX1_NAME, GPIO4H_I2S0_LRCK_TX1);
break;
case 1:
rk29_mux_api_set(GPIO3A0_I2S1CLK_NAME, GPIO3L_I2S1_CLK);
rk29_mux_api_set(GPIO3A1_I2S1SCLK_NAME, GPIO3L_I2S1_SCLK);
rk29_mux_api_set(GPIO3A2_I2S1LRCKRX_NAME, GPIO3L_I2S1_LRCK_RX);
rk29_mux_api_set(GPIO3A3_I2S1SDI_NAME, GPIO3L_I2S1_SDI);
rk29_mux_api_set(GPIO3A4_I2S1SDO_NAME, GPIO3L_I2S1_SDO);
rk29_mux_api_set(GPIO3A5_I2S1LRCKTX_NAME, GPIO3L_I2S1_LRCK_TX);
break;
default:
I2S_DBG("Enter:%s, %d, Error For DevId!!!", __FUNCTION__, __LINE__);
return -EINVAL;
}
return 0;
}
static int rk29_i2s_probe(struct platform_device *pdev,
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
struct snd_soc_dai_driver *dai,
#else
struct snd_soc_dai *dai,
#endif
struct rk29_i2s_info *i2s,
unsigned long base)
{
struct device *dev = &pdev->dev;
struct resource *res;
I2S_DBG("Enter %s, %d >>>>>>>>>>>\n", __func__, __LINE__);
i2s->dev = dev;
/* record our i2s structure for later use in the callbacks */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
dev_set_drvdata(&pdev->dev, i2s);
#else
dai->private_data = i2s;
#endif
if (!base) {
res = platform_get_resource(pdev,
IORESOURCE_MEM,
0);
if (!res) {
dev_err(dev, "Unable to get register resource\n");
return -ENXIO;
}
if (!request_mem_region(res->start, resource_size(res),
"rk29_i2s")) {
dev_err(dev, "Unable to request register region\n");
return -EBUSY;
}
base = res->start;
}
i2s->regs = ioremap(base, (res->end - res->start) + 1); ////res));
if (i2s->regs == NULL) {
dev_err(dev, "cannot ioremap registers\n");
return -ENXIO;
}
i2s->iis_pclk = clk_get(dev, "i2s");
if (IS_ERR(i2s->iis_pclk)) {
dev_err(dev, "failed to get iis_clock\n");
iounmap(i2s->regs);
return -ENOENT;
}
clk_enable(i2s->iis_pclk);
/* Mark ourselves as in TXRX mode so we can run through our cleanup
* process without warnings. */
rockchip_snd_txctrl(i2s, 0, true);
rockchip_snd_rxctrl(i2s, 0, true);
return 0;
}
static int __devinit rockchip_i2s_probe(struct platform_device *pdev)
{
struct rk29_i2s_info *i2s;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
struct snd_soc_dai_driver *dai;
#else
struct snd_soc_dai *dai;
#endif
int ret;
I2S_DBG("Enter %s, %d pdev->id = %d >>>>>>>>>>>\n", __func__, __LINE__, pdev->id);
if(pdev->id >= MAX_I2S) {
dev_err(&pdev->dev, "id %d out of range\n", pdev->id);
return -EINVAL;
}
i2s = &rk29_i2s[pdev->id];
dai = &rk29_i2s_dai[pdev->id];
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37))
dai->dev = &pdev->dev;
#endif
dai->id = pdev->id;
dai->symmetric_rates = 1;
if(pdev->id == 0) {
dai->name = "rk_i2s.0";
dai->playback.channels_min = 2;
dai->playback.channels_max = 8;
}else{
dai->name = "rk_i2s.1";
dai->playback.channels_min = 2;
dai->playback.channels_max = 2;
}
dai->playback.rates = ROCKCHIP_I2S_RATES;
dai->playback.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE;
dai->capture.channels_min = 2;
dai->capture.channels_max = 2;
dai->capture.rates = ROCKCHIP_I2S_RATES;//;SNDRV_PCM_RATE_44100
dai->capture.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE;
dai->probe = rockchip_i2s_dai_probe;
dai->ops = &rockchip_i2s_dai_ops;
dai->suspend = rockchip_i2s_suspend;
dai->resume = rockchip_i2s_resume;
//i2s->feature |= S3C_FEATURE_CDCLKCON;
i2s->dma_capture = &rk29_i2s_pcm_stereo_in[pdev->id];
i2s->dma_playback = &rk29_i2s_pcm_stereo_out[pdev->id];
if (pdev->id == 1) {
i2s->dma_capture->channel = DMACH_I2S_2CH_RX;
i2s->dma_capture->dma_addr = RK29_I2S_2CH_PHYS + I2S_RXR_BUFF;
i2s->dma_playback->channel = DMACH_I2S_2CH_TX;
i2s->dma_playback->dma_addr = RK29_I2S_2CH_PHYS + I2S_TXR_BUFF;
} else {
i2s->dma_capture->channel = DMACH_I2S_8CH_RX;
i2s->dma_capture->dma_addr = RK29_I2S_8CH_PHYS + I2S_RXR_BUFF;
i2s->dma_playback->channel = DMACH_I2S_8CH_TX;
i2s->dma_playback->dma_addr = RK29_I2S_8CH_PHYS + I2S_TXR_BUFF;
}
i2s->dma_capture->client = &rk29_dma_client_in;
i2s->dma_capture->dma_size = 4;
i2s->dma_capture->flag = 0; //add by sxj, used for burst change
i2s->dma_playback->client = &rk29_dma_client_out;
i2s->dma_playback->dma_size = 4;
i2s->dma_playback->flag = 0; //add by sxj, used for burst change
#ifdef CONFIG_SND_I2S_DMA_EVENT_STATIC
WARN_ON(rk29_dma_request(i2s->dma_playback->channel, i2s->dma_playback->client, NULL));
WARN_ON(rk29_dma_request(i2s->dma_capture->channel, i2s->dma_capture->client, NULL));
#endif
i2s->iis_clk = clk_get(&pdev->dev, "i2s");
I2S_DBG("Enter:%s, %d, iis_clk=%p\n", __FUNCTION__, __LINE__, i2s->iis_clk);
if (IS_ERR(i2s->iis_clk)) {
dev_err(&pdev->dev, "failed to get i2s clk\n");
ret = PTR_ERR(i2s->iis_clk);
goto err;
}
clk_enable(i2s->iis_clk);
clk_set_rate(i2s->iis_clk, 11289600);
ret = rk29_i2s_probe(pdev, dai, i2s, 0);
if (ret)
goto err_clk;
ret = snd_soc_register_dai(&pdev->dev, dai);
if (ret != 0)
goto err_i2sv2;
return 0;
err_i2sv2:
/* Not implemented for I2Sv2 core yet */
err_clk:
clk_put(i2s->iis_clk);
err:
return ret;
}
static int __devexit rockchip_i2s_remove(struct platform_device *pdev)
{
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
snd_soc_unregister_dai(&pdev->dev);
#else
snd_soc_unregister_dai(&rk29_i2s_dai);
#endif
return 0;
}
static struct platform_driver rockchip_i2s_driver = {
.probe = rockchip_i2s_probe,
.remove = __devexit_p(rockchip_i2s_remove),
.driver = {
.name = "rk29_i2s",
.owner = THIS_MODULE,
},
};
static int __init rockchip_i2s_init(void)
{
I2S_DBG("Enter %s, %d >>>>>>>>>>>\n", __func__, __LINE__);
return platform_driver_register(&rockchip_i2s_driver);
}
module_init(rockchip_i2s_init);
static void __exit rockchip_i2s_exit(void)
{
platform_driver_unregister(&rockchip_i2s_driver);
}
module_exit(rockchip_i2s_exit);
/* Module information */
MODULE_AUTHOR("rockchip");
MODULE_DESCRIPTION("ROCKCHIP IIS ASoC Interface");
MODULE_LICENSE("GPL");
#ifdef CONFIG_PROC_FS
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
static int proc_i2s_show(struct seq_file *s, void *v)
{
struct rk29_i2s_info *i2s=&rk29_i2s[0];
printk("========Show I2S reg========\n");
printk("I2S_TXCR = 0x%08X\n", readl(&(pheadi2s->I2S_TXCR)));
printk("I2S_RXCR = 0x%08X\n", readl(&(pheadi2s->I2S_RXCR)));
printk("I2S_TXCKR = 0x%08X\n", readl(&(pheadi2s->I2S_TXCKR)));
printk("I2S_RXCKR = 0x%08X\n", readl(&(pheadi2s->I2S_RXCKR)));
printk("I2S_DMACR = 0x%08X\n", readl(&(pheadi2s->I2S_DMACR)));
printk("I2S_INTCR = 0x%08X\n", readl(&(pheadi2s->I2S_INTCR)));
printk("I2S_INTSR = 0x%08X\n", readl(&(pheadi2s->I2S_INTSR)));
printk("I2S_XFER = 0x%08X\n", readl(&(pheadi2s->I2S_XFER)));
printk("========Show I2S reg========\n");
return 0;
}
static int proc_i2s_open(struct inode *inode, struct file *file)
{
return single_open(file, proc_i2s_show, NULL);
}
static const struct file_operations proc_i2s_fops = {
.open = proc_i2s_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static int __init i2s_proc_init(void)
{
proc_create("i2s_reg", 0, NULL, &proc_i2s_fops);
return 0;
}
late_initcall(i2s_proc_init);
#endif /* CONFIG_PROC_FS */

View File

@@ -1,204 +0,0 @@
/*
* rk29_tlv320dac3100.c -- SoC audio for rockchip
*
* Driver for rockchip tlv320aic3100 audio
*
* 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.
*
*
*/
#include <linux/module.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include "../codecs/tlv320aic3111.h"
#include "card_info.h"
#include "rk_pcm.h"
#include "rk_i2s.h"
#if 0
#define AIC_DBG(x...) printk(KERN_INFO x)
#else
#define AIC_DBG(x...) do { } while (0)
#endif
#ifdef CODECHPDET
#define HP_DET_PIN RK29_PIN6_PA0
#endif
static int rk29_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int pll_out = 0, dai_fmt = rtd->dai_link->dai_fmt;
int ret;
AIC_DBG("Enter::%s----%d\n", __FUNCTION__, __LINE__);
/* set codec DAI configuration */
ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
if (ret < 0) {
printk("%s():failed to set the format for codec side\n", __FUNCTION__);
return ret;
}
/* set cpu DAI configuration */
ret = snd_soc_dai_set_fmt(cpu_dai, dai_fmt);
if (ret < 0) {
printk("%s():failed to set the format for cpu side\n", __FUNCTION__);
return ret;
}
switch(params_rate(params)) {
case 8000:
case 16000:
case 24000:
case 32000:
case 48000:
pll_out = 12288000;
break;
case 11025:
case 22050:
case 44100:
pll_out = 11289600;
break;
default:
printk("Enter:%s, %d, Error rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
return -EINVAL;
break;
}
AIC_DBG("Enter:%s, %d, rate=%d, pll_out = %d\n",__FUNCTION__,__LINE__,params_rate(params), pll_out);
//pll_out = 12000000;
snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
snd_soc_dai_set_sysclk(codec_dai, 0, pll_out, SND_SOC_CLOCK_IN);
return 0;
}
static const struct snd_soc_dapm_widget dac3100_dapm_widgets[] = {
/* SND_SOC_DAPM_LINE("Audio Out", NULL),
SND_SOC_DAPM_LINE("Line in", NULL),
SND_SOC_DAPM_MIC("Micn", NULL),
SND_SOC_DAPM_MIC("Micp", NULL),*/
};
static const struct snd_soc_dapm_route audio_map[]= {
/* {"Audio Out", NULL, "HPL"},
{"Audio Out", NULL, "HPR"},
{"Line in", NULL, "RINPUT1"},
{"Line in", NULL, "LINPUT1"},
{"Micn", NULL, "RINPUT2"},
{"Micp", NULL, "LINPUT2"},*/
};
/*
* Logic for a tlv320dac3100 as connected on a rockchip board.
*/
static int rk29_aic3111_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
AIC_DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
/* Add specific widgets */
snd_soc_dapm_new_controls(dapm, dac3100_dapm_widgets,
ARRAY_SIZE(dac3100_dapm_widgets));
/* Set up specific audio path audio_mapnects */
snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
AIC_DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
snd_soc_dapm_nc_pin(dapm, "HPL");
AIC_DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
snd_soc_dapm_nc_pin(dapm, "HPR");
AIC_DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
snd_soc_dapm_sync(dapm);
AIC_DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
return 0;
}
static struct snd_soc_ops rk29_ops = {
.hw_params = rk29_hw_params,
};
static struct snd_soc_dai_link rk29_dai = {
.name = "AIC3111",
.stream_name = "AIC3111 PCM",
.codec_dai_name = "AIC3111 HiFi",
.init = rk29_aic3111_init,
.ops = &rk29_ops,
};
static struct snd_soc_card rockchip_aic3111_snd_card = {
.name = "RK_AIC3111",
.dai_link = &rk29_dai,
.num_links = 1,
};
static int rockchip_aic3111_audio_probe(struct platform_device *pdev)
{
int ret;
struct snd_soc_card *card = &rockchip_aic3111_snd_card;
card->dev = &pdev->dev;
ret = rockchip_of_get_sound_card_info(card);
if (ret) {
printk("%s() get sound card info failed:%d\n", __FUNCTION__, ret);
return ret;
}
ret = snd_soc_register_card(card);
if (ret)
printk("%s() register card failed:%d\n", __FUNCTION__, ret);
return ret;
}
static int rockchip_aic3111_audio_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
snd_soc_unregister_card(card);
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id rockchip_aic3111_of_match[] = {
{ .compatible = "rockchip-aic3111", },
{},
};
MODULE_DEVICE_TABLE(of, rockchip_aic3111_of_match);
#endif /* CONFIG_OF */
static struct platform_driver rockchip_aic3111_audio_driver = {
.driver = {
.name = "rockchip-aic3111",
.owner = THIS_MODULE,
.pm = &snd_soc_pm_ops,
.of_match_table = of_match_ptr(rockchip_aic3111_of_match),
},
.probe = rockchip_aic3111_audio_probe,
.remove = rockchip_aic3111_audio_remove,
};
module_platform_driver(rockchip_aic3111_audio_driver);
/* Module information */
MODULE_AUTHOR("rockchip");
MODULE_DESCRIPTION("ROCKCHIP i2s ASoC Interface");
MODULE_LICENSE("GPL");

View File

@@ -1,499 +0,0 @@
/*
* rk29_aic3262.c -- SoC audio for rockchip
*
* Driver for rockchip aic3262 audio
* Copyright (C) 2009 lhh
*
* 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.
*
*
*/
#define DEBUG 1
#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/i2c.h>
#include <linux/i2c/twl.h>
#include <linux/regulator/consumer.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/jack.h>
#include <linux/switch.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <asm/mach-types.h>
#include <linux/module.h>
#include <linux/device.h>
#include "../codecs/wm8994.h"
#include "card_info.h"
#include "rk_pcm.h"
#include "rk_i2s.h"
#include <linux/clk.h>
#include <linux/mfd/tlv320aic3262-registers.h>
#include "../codecs/tlv320aic326x.h"
#if 0
#define DBG_AIC3262(x...) printk(KERN_INFO x)
#else
#define DBG_AIC3262(x...)
#endif
//struct regulator *vddhf_reg=NULL;
/* Headset jack */
//static struct snd_soc_jack hs_jack;
/*Headset jack detection DAPM pins */
/*static struct snd_soc_jack_pin hs_jack_pins[] = {
{
.pin = "Headset Mic",
.mask = SND_JACK_MICROPHONE,
},
{
.pin = "Headset Stereophone",
.mask = SND_JACK_HEADPHONE,
},
};
static int spk_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
//struct snd_soc_codec *codec = w->codec;
int ret;
if (SND_SOC_DAPM_EVENT_ON(event)) {
printk(" I am NULL is %d event is %d\n",vddhf_reg,event);
if (vddhf_reg) {
ret = regulator_enable(vddhf_reg);
if(ret) {
printk("failed to enable vddhf \n");
return ret;
}
}
}
else {
if (vddhf_reg) {
ret = regulator_disable(vddhf_reg);
if (ret) {
printk("failed to disable "
"VDDHF regulator %d\n", ret);
return ret;
}
}
}
return 0;
}*/
/* rk29 machine DAPM */
static const struct snd_soc_dapm_widget rk29_aic3262_dapm_widgets[] = {
SND_SOC_DAPM_MIC("Ext Mic", NULL),
SND_SOC_DAPM_SPK("Ext Spk", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
SND_SOC_DAPM_HP("Headset Stereophone", NULL),
SND_SOC_DAPM_SPK("Earphone Spk", NULL),
SND_SOC_DAPM_INPUT("FM Stereo In"),
SND_SOC_DAPM_LINE("FM Stereo Out",NULL),
};
static const struct snd_soc_dapm_route audio_map[] = {
/* External Mics: MAINMIC, SUBMIC with bias*/
{"IN1L", NULL, "Mic Bias Int"},
{"IN1R", NULL, "Mic Bias Int"},
{"IN4L", NULL, "Mic Bias Int"},
{"IN4R", NULL, "Mic Bias Int"},
{"Mic Bias Int", NULL, "Ext Mic"},
/* External Speakers: HFL, HFR */
{"Ext Spk", NULL, "SPKL"},
{"Ext Spk", NULL, "SPKR"},
/* Headset Mic: HSMIC with bias */
{"IN2L", NULL, "Mic Bias Ext"},
{"IN2R", NULL, "Mic Bias Ext"},
{"Mic Bias Ext", NULL, "Headset Mic"},
/* Headset Stereophone (Headphone): HPL, HPR */
{"Headset Stereophone", NULL, "HPL"},
{"Headset Stereophone", NULL, "HPR"},
/* Earphone speaker */
{"Earphone Spk", NULL, "RECP"},
{"Earphone Spk", NULL, "RECM"},
/* Aux/FM Stereo In: IN4L, IN4R */
{"IN3L", NULL, "FM Stereo In"},
{"IN3R", NULL, "FM Stereo In"},
/* Aux/FM Stereo Out: LOL, LOR */
{"FM Stereo Out", NULL, "LOL"},
{"FM Stereo Out", NULL, "LOR"},
};
static const struct snd_kcontrol_new rk29_aic326x_controls[] = {
SOC_DAPM_PIN_SWITCH("Ext Mic"),
SOC_DAPM_PIN_SWITCH("Ext Spk"),
SOC_DAPM_PIN_SWITCH("Headset Mic"),
SOC_DAPM_PIN_SWITCH("Headset Stereophone"),
SOC_DAPM_PIN_SWITCH("Earphone Spk"),
SOC_DAPM_PIN_SWITCH("FM Stereo In"),
SOC_DAPM_PIN_SWITCH("FM Stereo Out"),
};
static int rk29_aic3262_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
int ret;
DBG_AIC3262("rk29_aic3262_init\n");
/* Headset jack detection */
/*ret = snd_soc_jack_new(codec, "Headset Jack",
SND_JACK_HEADSET, &hs_jack);
if (ret)
return ret;
ret = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins),
hs_jack_pins);
aic3262_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADSET);*/
/* don't wait before switching of HS power */
rtd->pmdown_time = 0;
return ret;
}
static int rk29_aif1_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int pll_out = 0, dai_fmt = rtd->dai_link->dai_fmt;
int div_bclk,div_mclk;
int ret;
DBG("Enter::%s----%d\n", __FUNCTION__, __LINE__);
/* set codec DAI configuration */
ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
if (ret < 0) {
printk("%s():failed to set the format for codec side\n", __FUNCTION__);
return ret;
}
/* set cpu DAI configuration */
ret = snd_soc_dai_set_fmt(cpu_dai, dai_fmt);
if (ret < 0) {
printk("%s():failed to set the format for cpu side\n", __FUNCTION__);
return ret;
}
switch(params_rate(params)) {
case 8000:
case 16000:
case 24000:
case 32000:
case 48000:
pll_out = 12288000;
break;
case 11025:
case 22050:
case 44100:
pll_out = 11289600;
break;
default:
DBG_AIC3262("Enter:%s, %d, Error rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
return -EINVAL;
}
div_bclk=(pll_out/4)/params_rate(params)-1;
div_mclk=3;
DBG_AIC3262(" %s, pll_out=%d, div_bclk=%d, div_mclk=%d\n",__FUNCTION__,pll_out,div_bclk,div_mclk);
ret = snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
if(ret < 0)
{
DBG_AIC3262("rk29_hw_params_aic3262:failed to set the cpu sysclk for codec side\n");
return ret;
}
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK, div_bclk);
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, div_mclk);
DBG_AIC3262("Enter:%s, %d, LRCK=%d\n",__FUNCTION__,__LINE__,(pll_out/4)/params_rate(params));
//MCLK == 11289600 or 12288000
ret = snd_soc_dai_set_sysclk(codec_dai, 0, pll_out, 0);
if (ret < 0) {
DBG_AIC3262("rk29_hw_params_aic3262:failed to set the sysclk for codec side\n");
return ret;
}
return ret;
}
static int rk29_aif2_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int pll_out = 0;
int div_bclk,div_mclk;
int ret;
DBG("Enter:%s, %d, rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
/* set codec DAI configuration */
ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_LEFT_J |
SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
if (ret < 0)
{
printk("%s: snd_soc_dai_set_fmt err =%d\n",__FUNCTION__,ret);
return ret;
}
switch(params_rate(params)) {
case 8000:
case 16000:
case 24000:
case 32000:
case 48000:
pll_out = 12288000;
break;
case 11025:
case 22050:
case 44100:
pll_out = 11289600;
break;
default:
DBG("Enter:%s, %d, Error rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
return -EINVAL;
}
div_bclk=(pll_out/4)/params_rate(params)-1;
div_mclk=3;
DBG_AIC3262(" %s, pll_out=%d, div_bclk=%d, div_mclk=%d\n",__FUNCTION__,pll_out,div_bclk,div_mclk);
ret = snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
if(ret < 0)
{
DBG("rk29_hw_params_aic3262:failed to set the cpu sysclk for codec side\n");
return ret;
}
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK, div_bclk);
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, div_mclk);
DBG("Enter:%s, %d, LRCK=%d\n",__FUNCTION__,__LINE__,(pll_out/4)/params_rate(params));
/* set the codec system clock */
ret = snd_soc_dai_set_sysclk(codec_dai, 0, pll_out, 0);
if (ret < 0)
{
printk("%s: snd_soc_dai_set_sysclk err =%d\n",__FUNCTION__,ret);
return ret;
}
/* set the codec FLL */
ret = snd_soc_dai_set_pll(codec_dai, 0, AIC3262_PLL_CLKIN_MCLK1 , pll_out, 8000*256);
if (ret < 0)
{
printk("%s: snd_soc_dai_set_pll err =%d\n",__FUNCTION__,ret);
return ret;
}
return ret;
}
static int rk29_aif3_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int pll_out = 0;
int div_bclk,div_mclk;
int ret;
DBG("Enter:%s, %d, rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
/* set codec DAI configuration */
ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_LEFT_J |
SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
if (ret < 0)
{
printk("%s: snd_soc_dai_set_fmt err =%d\n",__FUNCTION__,ret);
return ret;
}
switch(params_rate(params)) {
case 8000:
case 16000:
case 24000:
case 32000:
case 48000:
pll_out = 12288000;
break;
case 11025:
case 22050:
case 44100:
pll_out = 11289600;
break;
default:
DBG("Enter:%s, %d, Error rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
return -EINVAL;
}
div_bclk=(pll_out/4)/params_rate(params)-1;
div_mclk=3;
DBG_AIC3262(" %s, pll_out=%d, div_bclk=%d, div_mclk=%d\n",__FUNCTION__,pll_out,div_bclk,div_mclk);
ret = snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
if(ret < 0)
{
DBG("rk29_hw_params_aic3262:failed to set the cpu sysclk for codec side\n");
return ret;
}
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK, div_bclk);
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, div_mclk);
DBG("Enter:%s, %d, LRCK=%d\n",__FUNCTION__,__LINE__,(pll_out/4)/params_rate(params));
/* set the codec system clock */
ret = snd_soc_dai_set_sysclk(codec_dai, 0, pll_out, 0);
if (ret < 0)
{
printk("%s: snd_soc_dai_set_sysclk err =%d\n",__FUNCTION__,ret);
return ret;
}
/* set the codec FLL */
ret = snd_soc_dai_set_pll(codec_dai, 0, AIC3262_PLL_CLKIN_MCLK1 , pll_out, 8000*256);
if (ret < 0)
{
printk("%s: snd_soc_dai_set_pll err =%d\n",__FUNCTION__,ret);
return ret;
}
return ret;
}
static struct snd_soc_ops rk29_aif1_ops = {
.hw_params = rk29_aif1_hw_params,
};
static struct snd_soc_ops rk29_aif2_ops = {
.hw_params = rk29_aif2_hw_params,
};
static struct snd_soc_ops rk29_aif3_ops = {
.hw_params = rk29_aif3_hw_params,
};
static struct snd_soc_dai_link rk29_dai[] = {
{
.name = "AIC3262 I2S1",
.stream_name = "AIC3262 PCM",
.codec_dai_name = "aic326x-asi1",
.ops = &rk29_aif1_ops,
.init = rk29_aic3262_init,
},
{
.name = "AIC3262 I2S2",
.stream_name = "AIC3262 PCM",
.codec_dai_name = "aic326x-asi2",
.ops = &rk29_aif2_ops,
},
{
.name = "AIC3262 I2S3",
.stream_name = "AIC3262 PCM",
.codec_dai_name = "aic326x-asi3",
.ops = &rk29_aif3_ops,
},
};
static struct snd_soc_card rockchip_aic3262_snd_card = {
.name = "RK_AIC3262",
.dai_link = rk29_dai,
.num_links = ARRAY_SIZE(rk29_dai),
.controls = rk29_aic326x_controls,
.num_controls = ARRAY_SIZE(rk29_aic326x_controls),
.dapm_widgets = rk29_aic3262_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(rk29_aic3262_dapm_widgets),
.dapm_routes = audio_map,
.num_dapm_routes = ARRAY_SIZE(audio_map),
};
static int rockchip_aic3262_audio_probe(struct platform_device *pdev)
{
int ret;
struct snd_soc_card *card = &rockchip_aic3262_snd_card;
card->dev = &pdev->dev;
ret = rockchip_of_get_sound_card_info(card);
if (ret) {
printk("%s() get sound card info failed:%d\n", __FUNCTION__, ret);
return ret;
}
ret = snd_soc_register_card(card);
if (ret)
printk("%s() register card failed:%d\n", __FUNCTION__, ret);
return ret;
}
static int rockchip_aic3262_audio_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
snd_soc_unregister_card(card);
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id rockchip_aic3262_of_match[] = {
{ .compatible = "rockchip-aic3262", },
{},
};
MODULE_DEVICE_TABLE(of, rockchip_aic3262_of_match);
#endif /* CONFIG_OF */
static struct platform_driver rockchip_aic3262_audio_driver = {
.driver = {
.name = "rockchip-aic3262",
.owner = THIS_MODULE,
.pm = &snd_soc_pm_ops,
.of_match_table = of_match_ptr(rockchip_aic3262_of_match),
},
.probe = rockchip_aic3262_audio_probe,
.remove = rockchip_aic3262_audio_remove,
};
module_platform_driver(rockchip_aic3262_audio_driver);
/* Module information */
MODULE_AUTHOR("rockchip");
MODULE_DESCRIPTION("ROCKCHIP i2s ASoC Interface");
MODULE_LICENSE("GPL");

View File

@@ -1,189 +0,0 @@
/*
* rk29_ak4396.c -- SoC audio for rockchip
*
* Driver for rockchip ak4396 audio
*
* 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.
*
*
*/
#include <linux/module.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include "card_info.h"
#include "rk_pcm.h"
#include "rk_i2s.h"
#if 1
#define DBG(x...) printk(KERN_INFO x)
#else
#define DBG(x...)
#endif
static int rk29_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int pll_out = 0, dai_fmt = rtd->dai_link->dai_fmt;
int ret;
DBG("Enter::%s----%d\n", __FUNCTION__, __LINE__);
/* set codec DAI configuration */
ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
if (ret < 0) {
printk("%s():failed to set the format for codec side\n", __FUNCTION__);
return ret;
}
/* set cpu DAI configuration */
ret = snd_soc_dai_set_fmt(cpu_dai, dai_fmt);
if (ret < 0) {
printk("%s():failed to set the format for cpu side\n", __FUNCTION__);
return ret;
}
switch(params_rate(params)) {
case 8000:
case 16000:
case 24000:
case 32000:
case 48000:
pll_out = 12288000;
break;
case 11025:
case 22050:
case 44100:
pll_out = 11289600;
break;
case 88200:
case 176400:
pll_out = 11289600*2;
break;
case 96000:
case 192000:
pll_out = 12288000*2;
break;
default:
DBG("Enter:%s, %d, Error rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
return -EINVAL;
}
DBG("Enter:%s, %d, rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
if ((dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFM)
return 0;
snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK, (2 * 32 )-1); //bclk = 2 * 32 * lrck
switch(params_rate(params)){
case 192000:
case 176400:
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK,1);
DBG("Enter:%s, %d, MCLK=%d BCLK=%d LRCK=%d\n",
__FUNCTION__,__LINE__,pll_out,pll_out/2,params_rate(params));
break;
default :
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, 3);
DBG("default:%s, %d, MCLK=%d BCLK=%d LRCK=%d\n",
__FUNCTION__,__LINE__,pll_out,pll_out/4,params_rate(params));
break;
}
snd_soc_dai_set_sysclk(codec_dai,0,pll_out,SND_SOC_CLOCK_IN);
return ret;
}
/*
* Logic for a ak4396 as connected on a rockchip board.
*/
static int rk29_ak4396_init(struct snd_soc_pcm_runtime *rtd)
{
DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
return 0;
}
static struct snd_soc_ops rk29_ops = {
.hw_params = rk29_hw_params,
};
static struct snd_soc_dai_link rk29_dai = {
.name = "AK4396",
.stream_name = "AK4396 PCM",
.codec_dai_name = "AK4396 HiFi",
.init = rk29_ak4396_init,
.ops = &rk29_ops,
};
static struct snd_soc_card rockchip_ak4396_snd_card = {
.name = "RK_AK4396",
.dai_link = &rk29_dai,
.num_links = 1,
};
static int rockchip_ak4396_audio_probe(struct platform_device *pdev)
{
int ret;
struct snd_soc_card *card = &rockchip_ak4396_snd_card;
card->dev = &pdev->dev;
ret = rockchip_of_get_sound_card_info(card);
if (ret) {
printk("%s() get sound card info failed:%d\n", __FUNCTION__, ret);
return ret;
}
ret = snd_soc_register_card(card);
if (ret)
printk("%s() register card failed:%d\n", __FUNCTION__, ret);
return ret;
}
static int rockchip_ak4396_audio_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
snd_soc_unregister_card(card);
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id rockchip_ak4396_of_match[] = {
{ .compatible = "rockchip-ak4396", },
{},
};
MODULE_DEVICE_TABLE(of, rockchip_ak4396_of_match);
#endif /* CONFIG_OF */
static struct platform_driver rockchip_ak4396_audio_driver = {
.driver = {
.name = "rockchip-ak4396",
.owner = THIS_MODULE,
.pm = &snd_soc_pm_ops,
.of_match_table = of_match_ptr(rockchip_ak4396_of_match),
},
.probe = rockchip_ak4396_audio_probe,
.remove = rockchip_ak4396_audio_remove,
};
module_platform_driver(rockchip_ak4396_audio_driver);
/* Module information */
MODULE_AUTHOR("rockchip");
MODULE_DESCRIPTION("ROCKCHIP i2s ASoC Interface");
MODULE_LICENSE("GPL");

View File

@@ -1,211 +0,0 @@
/*
* rk29_cs42l52.c -- SoC audio for rockchip
*
* Driver for rockchip cs42l52 audio
*
* 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.
*
*
*/
#include <linux/module.h>
#include <linux/device.h>
#include <linux/clk.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include "../codecs/cs42l52.h"
#include "card_info.h"
#include "rk_pcm.h"
#include "rk_i2s.h"
#define HW_PARAMS_FLAG_EQVOL_ON 0x21
#define HW_PARAMS_FLAG_EQVOL_OFF 0x22
static const struct snd_soc_dapm_widget cs42l52_dapm_widgets[] = {
SND_SOC_DAPM_LINE("Audio Out", NULL),
SND_SOC_DAPM_LINE("Line in", NULL),
SND_SOC_DAPM_MIC("Micn", NULL),
SND_SOC_DAPM_MIC("Micp", NULL),
};
static const struct snd_soc_dapm_route audio_map[]= {
{"Audio Out", NULL, "HPA"},
{"Audio Out", NULL, "HPB"},
{"Line in", NULL, "INPUT1A"},
{"Line in", NULL, "INPUT1B"},
{"Micn", NULL, "INPUT2A"},
{"Micp", NULL, "INPUT2B"},
};
static int rk29_cs42l52_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int pll_out = 0, dai_fmt = rtd->dai_link->dai_fmt;
unsigned int lrclk = 0;
int div_bclk,div_mclk;
struct clk *general_pll;
int ret;
/* set codec DAI configuration */
ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
if (ret < 0) {
printk("%s():failed to set the format for codec side\n", __FUNCTION__);
return ret;
}
/* set cpu DAI configuration */
ret = snd_soc_dai_set_fmt(cpu_dai, dai_fmt);
if (ret < 0) {
printk("%s():failed to set the format for cpu side\n", __FUNCTION__);
return ret;
}
switch(params_rate(params)) {
case 8000:
case 16000:
case 24000:
case 32000:
case 48000:
pll_out = 12288000;
break;
case 11025:
case 22050:
case 44100:
pll_out = 11289600;
break;
default:
return -EINVAL;
break;
}
if ((dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBS_CFS) {
general_pll=clk_get(NULL, "general_pll");
if(clk_get_rate(general_pll)>260000000)
{
div_bclk=(pll_out/4)/params_rate(params)-1;
//div_bclk= 63;
div_mclk= 3;
}
else if(clk_get_rate(general_pll)>130000000)
{
div_bclk=(pll_out/2)/params_rate(params)-1;
div_mclk=1;
}
else
{
pll_out=pll_out/4;
div_bclk=(pll_out)/params_rate(params)-1;
div_mclk=0;
}
//snd_soc_dai_set_sysclk(codec_dai, 0, pll_out, 0);
snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK,div_bclk);
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, div_mclk);
}
return 0;
}
static int rk29_cs42l52_dai_init(struct snd_soc_codec *codec)
{
struct snd_soc_dapm_context *dapm = &codec->dapm;
snd_soc_dapm_nc_pin(dapm, "INPUT1A");
snd_soc_dapm_nc_pin(dapm, "INPUT2A");
snd_soc_dapm_nc_pin(dapm, "INPUT3A");
snd_soc_dapm_nc_pin(dapm, "INPUT4A");
snd_soc_dapm_nc_pin(dapm, "INPUT1B");
snd_soc_dapm_nc_pin(dapm, "INPUT2B");
snd_soc_dapm_nc_pin(dapm, "INPUT3B");
snd_soc_dapm_nc_pin(dapm, "INPUT4B");
snd_soc_dapm_nc_pin(dapm, "MICB");
snd_soc_dapm_sync(dapm);
return 0;
}
static struct snd_soc_ops rk29_cs42l52_ops = {
.hw_params = rk29_cs42l52_hw_params,
};
static struct snd_soc_dai_link rk29_cs42l52_dai_link = {
.name = "CS42L52",
.stream_name = "CS42L52 PCM",
.codec_dai_name = "cs42l52-hifi",
.init = rk29_cs42l52_dai_init,
.ops = &rk29_cs42l52_ops,
};
static struct snd_soc_card rockchip_cs42l52_snd_card = {
.name = "RK_CS42L52",
.dai_link = &rk29_cs42l52_dai_link,
.num_links = 1,
};
static int rockchip_cs42l52_audio_probe(struct platform_device *pdev)
{
int ret;
struct snd_soc_card *card = &rockchip_cs42l52_snd_card;
card->dev = &pdev->dev;
ret = rockchip_of_get_sound_card_info(card);
if (ret) {
printk("%s() get sound card info failed:%d\n", __FUNCTION__, ret);
return ret;
}
ret = snd_soc_register_card(card);
if (ret)
printk("%s() register card failed:%d\n", __FUNCTION__, ret);
return ret;
}
static int rockchip_cs42l52_audio_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
snd_soc_unregister_card(card);
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id rockchip_cs42l52_of_match[] = {
{ .compatible = "rockchip-cs42l52", },
{},
};
MODULE_DEVICE_TABLE(of, rockchip_cs42l52_of_match);
#endif /* CONFIG_OF */
static struct platform_driver rockchip_cs42l52_audio_driver = {
.driver = {
.name = "rockchip-cs42l52",
.owner = THIS_MODULE,
.pm = &snd_soc_pm_ops,
.of_match_table = of_match_ptr(rockchip_cs42l52_of_match),
},
.probe = rockchip_cs42l52_audio_probe,
.remove = rockchip_cs42l52_audio_remove,
};
module_platform_driver(rockchip_cs42l52_audio_driver);
MODULE_AUTHOR("rockchip");
MODULE_DESCRIPTION("ROCKCHIP i2s ASoC Interface");
MODULE_LICENSE("GPL");

View File

@@ -1,245 +0,0 @@
/*
* rk29_cx2070x.c
*
* 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.
*/
#include <linux/module.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/jack.h>
#include <linux/delay.h>
#include "card_info.h"
#include "rk_pcm.h"
#include "rk_i2s.h"
#if 1
#define DBG(x...) printk(KERN_INFO x)
#else
#define DBG(x...)
#endif
#include "../codecs/cx2070x.h"
static struct platform_device *rk29_snd_device;
static int rk29_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int pll_out = 0, dai_fmt = rtd->card->dai_link->dai_fmt;
//unsigned int pll_div;
int ret;
DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
/* set codec DAI configuration */
ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
if (ret < 0) {
printk("%s():failed to set the format for codec side\n", __FUNCTION__);
return ret;
}
/* set cpu DAI configuration */
ret = snd_soc_dai_set_fmt(cpu_dai, dai_fmt);
if (ret < 0) {
printk("%s():failed to set the format for cpu side\n", __FUNCTION__);
return ret;
}
switch(params_rate(params)) {
case 8000:
case 16000:
case 24000:
case 32000:
case 48000:
pll_out = 12288000;
break;
case 11025:
case 22050:
case 44100:
pll_out = 11289600;
break;
case 96000:
case 192000:
pll_out = 12288000*2;
break;
case 88200:
case 176400:
pll_out = 11289600*2;
break;
default:
DBG("Enter:%s, %d, Error rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
return -EINVAL;
break;
}
if ((dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFM)
goto skip__;
snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK, 64-1);//bclk = 2*32*lrck; 2*32fs
switch(params_rate(params)) {
case 176400:
case 192000:
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, 1);
DBG("Enter:%s, %d, MCLK=%d BCLK=%d LRCK=%d\n",
__FUNCTION__,__LINE__,pll_out,pll_out/2,params_rate(params));
break;
default:
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, 3);
DBG("default:%s, %d, MCLK=%d BCLK=%d LRCK=%d\n",
__FUNCTION__,__LINE__,pll_out,pll_out/4,params_rate(params));
break;
}
/*Set the system clk for codec*/
ret=snd_soc_dai_set_sysclk(codec_dai, 0,pll_out,SND_SOC_CLOCK_IN);
if (ret < 0)
{
DBG("rk29_hw_params_cx2070x:failed to set the sysclk for codec side\n");
return ret;
}
skip__:
if ((dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFM)
snd_soc_dai_set_sysclk(codec_dai,0,pll_out, SND_SOC_CLOCK_IN);
return 0;
}
//---------------------------------------------------------------------------------
/*
* cx2070x DAI operations.
*/
static struct snd_soc_ops rk29_ops = {
.hw_params = rk29_hw_params,
};
static const struct snd_soc_dapm_widget cx2070x_dapm_widgets[] = {
// Input
SND_SOC_DAPM_MIC("Mic Jack", NULL),
//SND_SOC_DAPM_LINE("Headset Jack", NULL),
SND_SOC_DAPM_INPUT("BT IN"),
// Output
SND_SOC_DAPM_SPK("Ext Spk", NULL),
SND_SOC_DAPM_HP("Headphone Jack", NULL),
SND_SOC_DAPM_LINE("ALineOut", NULL),
SND_SOC_DAPM_OUTPUT("BT OUT"),
};
static const struct snd_soc_dapm_route cx2070x_audio_map[] = {
// Input
{"MIC IN", NULL,"Mic Jack"},
{"PCM IN", NULL, "BT IN"},
// Output
{"Ext Spk", NULL, "SPK OUT"},
{"Headphone Jack", NULL, "HP OUT"},
{"ALineOut", NULL, "LINE OUT"},
{"BT OUT", NULL, "PCM OUT"},
};
static int cx2070x_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
//struct cx2070x_codec_chip *chip = snd_soc_codec_get_drvdata(codec);
//int err = 0;
printk(">>>>>>>>>>%s",__FUNCTION__);
snd_soc_dapm_new_controls(dapm, cx2070x_dapm_widgets,
ARRAY_SIZE(cx2070x_dapm_widgets));
snd_soc_dapm_add_routes(dapm, cx2070x_audio_map,
ARRAY_SIZE(cx2070x_audio_map));
#if FOR_MID
snd_soc_dapm_disable_pin(dapm, "Mic Jack");
snd_soc_dapm_disable_pin(dapm, "BT IN");
snd_soc_dapm_disable_pin(dapm, "Ext Spk");
snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
snd_soc_dapm_disable_pin(dapm, "ALineOut");
snd_soc_dapm_disable_pin(dapm, "BT OUT");
#endif
snd_soc_dapm_sync(dapm);
return 0;
}
static struct snd_soc_dai_link rk29_dai[] = {
{ /* Primary DAI i/f */
.name = "CX2070X AIF1",
.stream_name = "CX2070X PCM",
.codec_dai_name = "cx2070x-hifi",
.init = cx2070x_init,
.ops = &rk29_ops,
},
};
static struct snd_soc_card rockchip_cx2070x_snd_card = {
.name = "RK_CX2070X",
.dai_link = rk29_dai,
/* If you want to use sec_fifo device,
* changes the num_link = 2 or ARRAY_SIZE(snd_soc_card_rk29). */
.num_links = ARRAY_SIZE(rk29_dai),
};
static int rockchip_cx2070x_audio_probe(struct platform_device *pdev)
{
int ret;
struct snd_soc_card *card = &rockchip_cx2070x_snd_card;
card->dev = &pdev->dev;
ret = rockchip_of_get_sound_card_info(card);
if (ret) {
printk("%s() get sound card info failed:%d\n", __FUNCTION__, ret);
return ret;
}
ret = snd_soc_register_card(card);
if (ret)
printk("%s() register card failed:%d\n", __FUNCTION__, ret);
return ret;
}
static int rockchip_cx2070x_audio_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
snd_soc_unregister_card(card);
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id rockchip_cx2070x_of_match[] = {
{ .compatible = "rockchip-cx2070x", },
{},
};
MODULE_DEVICE_TABLE(of, rockchip_cx2070x_of_match);
#endif /* CONFIG_OF */
static struct platform_driver rockchip_cx2070x_audio_driver = {
.driver = {
.name = "rockchip-cx2070x",
.owner = THIS_MODULE,
.pm = &snd_soc_pm_ops,
.of_match_table = of_match_ptr(rockchip_cx2070x_of_match),
},
.probe = rockchip_cx2070x_audio_probe,
.remove = rockchip_cx2070x_audio_remove,
};
module_platform_driver(rockchip_cx2070x_audio_driver);
MODULE_DESCRIPTION("ROCKCHIP i2s ASoC Interface");
MODULE_AUTHOR("showy.zhang <showy.zhang@rock-chips.com>");
MODULE_LICENSE("GPL");

View File

@@ -1,203 +0,0 @@
/*
* rk29_es8316.c -- SoC audio for rockchip
*
* Driver for rockchip es8316 audio
*
* 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.
*
*
*/
#include <linux/module.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include "../codecs/es8316.h"
#include "card_info.h"
#include "rk_pcm.h"
#include "rk_i2s.h"
#ifdef CONFIG_MACH_RK_FAC
#include <plat/config.h>
/*extern int codec_type;*/
#endif
#if 1
#define DBG(x...) printk(x)
#else
#define DBG(x...)
#endif
static int rk29_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int pll_out = 0, dai_fmt = rtd->card->dai_link->dai_fmt;
int ret;
DBG("Enter::%s----%d\n", __func__, __LINE__);
/* set codec DAI configuration */
ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
if (ret < 0) {
DBG("%s():failed to set the format for codec side\n", __func__);
return ret;
}
/* set cpu DAI configuration */
ret = snd_soc_dai_set_fmt(cpu_dai, dai_fmt);
if (ret < 0) {
DBG("%s():failed to set the format for cpu side\n", __func__);
return ret;
}
switch (params_rate(params)) {
case 8000:
case 16000:
case 24000:
case 32000:
case 48000:
pll_out = 12288000;
break;
case 11025:
case 22050:
case 44100:
pll_out = 11289600;
break;
default:
DBG("Enter:%s, %d, Error rate=%d\n",
__func__, __LINE__, params_rate(params));
return -EINVAL;
}
DBG("Enter:%s, %d, rate=%d\n", __func__, __LINE__, params_rate(params));
if ((dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBS_CFS) {
snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK,
(pll_out/4)/params_rate(params)-1);
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, 3);
}
DBG("Enter:%s, %d, LRCK=%d\n", __func__, __LINE__,
(pll_out/4)/params_rate(params));
return 0;
}
static const struct snd_soc_dapm_widget rk29_dapm_widgets[] = {
SND_SOC_DAPM_LINE("Audio Out", NULL),
SND_SOC_DAPM_MIC("Micn", NULL),
SND_SOC_DAPM_MIC("Micp", NULL),
};
static const struct snd_soc_dapm_route audio_map[] = {
{"Audio Out", NULL, "LOUT1"},
{"Audio Out", NULL, "ROUT1"},
{"Micn", NULL, "RINPUT1"},
{"Micp", NULL, "LINPUT1"},
};
/*
* Logic for a es8316 as connected on a rockchip board.
*/
static int rk29_es8316_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_dai *codec_dai = rtd->codec_dai;
int ret;
DBG("Enter::%s----%d\n", __func__, __LINE__);
ret = snd_soc_dai_set_sysclk(codec_dai, 0,
11289600, SND_SOC_CLOCK_IN);
if (ret < 0) {
DBG(KERN_ERR "Failed to set es8316 SYSCLK: %d\n", ret);
return ret;
}
return 0;
}
static struct snd_soc_ops rk29_ops = {
.hw_params = rk29_hw_params,
};
static struct snd_soc_dai_link rk29_dai = {
.name = "ES8316",
.stream_name = "ES8316 PCM",
.codec_name = "ES8316.v01a",
.platform_name = "rockchip-audio",
.cpu_dai_name = "rk29_i2s.0",
.codec_dai_name = "ES8316 HiFi",
.init = rk29_es8316_init,
.ops = &rk29_ops,
};
static struct snd_soc_card rockchip_es8316_snd_card = {
.name = "RK_ES8316",
.dai_link = &rk29_dai,
.num_links = 1,
};
static int rockchip_es8316_audio_probe(struct platform_device *pdev)
{
int ret;
struct snd_soc_card *card = &rockchip_es8316_snd_card;
card->dev = &pdev->dev;
ret = rockchip_of_get_sound_card_info(card);
if (ret) {
DBG("%s() get sound card info failed:%d\n", __func__, ret);
return ret;
}
ret = snd_soc_register_card(card);
if (ret)
DBG("%s() register card failed:%d\n", __func__, ret);
return ret;
}
static int rockchip_es8316_audio_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
snd_soc_unregister_card(card);
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id rockchip_es8316_of_match[] = {
{ .compatible = "rockchip-es8316", },
{},
};
MODULE_DEVICE_TABLE(of, rockchip_es8316_of_match);
#endif /* CONFIG_OF */
static struct platform_driver rockchip_es8316_audio_driver = {
.driver = {
.name = "rockchip-es8316",
.owner = THIS_MODULE,
.pm = &snd_soc_pm_ops,
.of_match_table = of_match_ptr(rockchip_es8316_of_match),
},
.probe = rockchip_es8316_audio_probe,
.remove = rockchip_es8316_audio_remove,
};
module_platform_driver(rockchip_es8316_audio_driver);
/* Module information */
MODULE_AUTHOR("rockchip");
MODULE_DESCRIPTION("ROCKCHIP i2s ASoC Interface");
MODULE_LICENSE("GPL");

View File

@@ -1,219 +0,0 @@
/*
* rk29_es8323.c -- SoC audio for rockchip
*
* Driver for rockchip es8323 audio
*
* 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.
*
*
*/
#include <linux/module.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include "../codecs/es8323.h"
#include "card_info.h"
#include "rk_pcm.h"
#include "rk_i2s.h"
#ifdef CONFIG_MACH_RK_FAC
#include <plat/config.h>
extern int codec_type;
#endif
#if 0
#define DBG(x...) printk(KERN_INFO x)
#else
#define DBG(x...)
#endif
//static void *rk29_speaker = NULL;
static int rk29_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int pll_out = 0, dai_fmt = rtd->card->dai_link->dai_fmt;
int ret;
DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
/* set codec DAI configuration */
ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
if (ret < 0) {
printk("%s():failed to set the format for codec side\n", __FUNCTION__);
return ret;
}
/* set cpu DAI configuration */
ret = snd_soc_dai_set_fmt(cpu_dai, dai_fmt);
if (ret < 0) {
printk("%s():failed to set the format for cpu side\n", __FUNCTION__);
return ret;
}
switch(params_rate(params)) {
case 8000:
case 16000:
case 24000:
case 32000:
case 48000:
pll_out = 12288000;
break;
case 11025:
case 22050:
case 44100:
pll_out = 11289600;
break;
default:
DBG("Enter:%s, %d, Error rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
return -EINVAL;
break;
}
DBG("Enter:%s, %d, rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
if ((dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBS_CFS) {
snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK, (pll_out/4)/params_rate(params)-1);
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, 3);
}
DBG("Enter:%s, %d, LRCK=%d\n",__FUNCTION__,__LINE__,(pll_out/4)/params_rate(params));
return 0;
}
static const struct snd_soc_dapm_widget rk29_dapm_widgets[] = {
SND_SOC_DAPM_LINE("Audio Out", NULL),
SND_SOC_DAPM_LINE("Line in", NULL),
SND_SOC_DAPM_MIC("Micn", NULL),
SND_SOC_DAPM_MIC("Micp", NULL),
};
static const struct snd_soc_dapm_route audio_map[]= {
{"Audio Out", NULL, "LOUT1"},
{"Audio Out", NULL, "ROUT1"},
{"Line in", NULL, "RINPUT1"},
{"Line in", NULL, "LINPUT1"},
{"Micn", NULL, "RINPUT2"},
{"Micp", NULL, "LINPUT2"},
};
/*
* Logic for a es8323 as connected on a rockchip board.
*/
static int rk29_es8323_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
int ret;
DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
ret = snd_soc_dai_set_sysclk(codec_dai, 0,
/*12000000*/11289600, SND_SOC_CLOCK_IN);
if (ret < 0) {
printk(KERN_ERR "Failed to set es8323 SYSCLK: %d\n", ret);
return ret;
}
/* Add specific widgets */
#if 0
snd_soc_dapm_new_controls(dapm, rk29_dapm_widgets,
ARRAY_SIZE(rk29_dapm_widgets));
//snd_soc_dapm_nc_pin(codec, "LOUT2");
//snd_soc_dapm_nc_pin(codec, "ROUT2");
/* Set up specific audio path audio_mapnects */
snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
snd_soc_dapm_sync(dapm);
#endif
return 0;
}
static struct snd_soc_ops rk29_ops = {
.hw_params = rk29_hw_params,
};
static struct snd_soc_dai_link rk29_dai = {
.name = "ES8323",
.stream_name = "ES8323 PCM",
.codec_dai_name = "ES8323 HiFi",
.init = rk29_es8323_init,
.ops = &rk29_ops,
};
static struct snd_soc_card rockchip_es8323_snd_card = {
.name = "RK_ES8323",
.dai_link = &rk29_dai,
.num_links = 1,
};
static int rockchip_es8323_audio_probe(struct platform_device *pdev)
{
int ret;
struct snd_soc_card *card = &rockchip_es8323_snd_card;
card->dev = &pdev->dev;
ret = rockchip_of_get_sound_card_info(card);
if (ret) {
printk("%s() get sound card info failed:%d\n", __FUNCTION__, ret);
return ret;
}
ret = snd_soc_register_card(card);
if (ret)
printk("%s() register card failed:%d\n", __FUNCTION__, ret);
return ret;
}
static int rockchip_es8323_audio_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
snd_soc_unregister_card(card);
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id rockchip_es8323_of_match[] = {
{ .compatible = "rockchip-es8323", },
{},
};
MODULE_DEVICE_TABLE(of, rockchip_es8323_of_match);
#endif /* CONFIG_OF */
static struct platform_driver rockchip_es8323_audio_driver = {
.driver = {
.name = "rockchip-es8323",
.owner = THIS_MODULE,
.pm = &snd_soc_pm_ops,
.of_match_table = of_match_ptr(rockchip_es8323_of_match),
},
.probe = rockchip_es8323_audio_probe,
.remove = rockchip_es8323_audio_remove,
};
module_platform_driver(rockchip_es8323_audio_driver);
/* Module information */
MODULE_AUTHOR("rockchip");
MODULE_DESCRIPTION("ROCKCHIP i2s ASoC Interface");
MODULE_LICENSE("GPL");

View File

@@ -1,158 +0,0 @@
/*
* rk_hdmi_i2s.c -- HDMI i2s audio for rockchip
*
* Copyright (C) 2015 Fuzhou Rockchip Electronics Co., Ltd
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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/module.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include "card_info.h"
#include "rk_pcm.h"
#include "rk_i2s.h"
static int hdmi_i2s_hifi_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int pll_out = 0, dai_fmt = rtd->dai_link->dai_fmt;
int div_bclk, div_mclk;
int ret;
/* set cpu DAI configuration */
ret = snd_soc_dai_set_fmt(cpu_dai, dai_fmt);
if (ret < 0) {
pr_err("%s: failed to set format for cpu dai\n", __func__);
return ret;
}
switch (params_rate(params)) {
case 8000:
case 16000:
case 24000:
case 32000:
case 48000:
case 96000:
pll_out = 12288000;
break;
case 11025:
case 22050:
case 44100:
case 88200:
pll_out = 11289600;
break;
case 176400:
pll_out = 11289600*2;
break;
case 192000:
pll_out = 12288000*2;
break;
default:
pr_err("%s: %d: rate(%d) not support.\n",
__func__, __LINE__, params_rate(params));
return -EINVAL;
}
div_bclk = 127;
div_mclk = pll_out/(params_rate(params)*(div_bclk+1))-1;
snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK, div_bclk);
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, div_mclk);
pr_debug("%s: %d: div_bclk: %d, div_mclk: %d\n",
__func__, __LINE__, div_bclk, div_mclk);
return 0;
}
static struct snd_soc_ops hdmi_i2s_hifi_ops = {
.hw_params = hdmi_i2s_hifi_hw_params,
};
static struct snd_soc_dai_link hdmi_i2s_dai = {
.name = "HDMI I2S",
.stream_name = "HDMI PCM",
.codec_dai_name = "rk-hdmi-i2s-hifi",
.ops = &hdmi_i2s_hifi_ops,
};
static struct snd_soc_card rockchip_hdmi_i2s_snd_card = {
.name = "RK-HDMI-I2S",
.dai_link = &hdmi_i2s_dai,
.num_links = 1,
};
static int rockchip_hdmi_i2s_audio_probe(struct platform_device *pdev)
{
int ret;
struct snd_soc_card *card = &rockchip_hdmi_i2s_snd_card;
card->dev = &pdev->dev;
ret = rockchip_of_get_sound_card_info(card);
if (ret) {
pr_err("%s() get sound card info failed: %d\n",
__func__, ret);
return ret;
}
ret = snd_soc_register_card(card);
if (ret)
pr_err("%s() register card failed: %d\n",
__func__, ret);
return ret;
}
static int rockchip_hdmi_i2s_audio_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
snd_soc_unregister_card(card);
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id rockchip_hdmi_i2s_of_match[] = {
{ .compatible = "rockchip-hdmi-i2s", },
{},
};
MODULE_DEVICE_TABLE(of, rockchip_hdmi_i2s_of_match);
#endif /* CONFIG_OF */
static struct platform_driver rockchip_hdmi_i2s_audio_driver = {
.driver = {
.name = "rockchip-hdmi-i2s",
.pm = &snd_soc_pm_ops,
.of_match_table = of_match_ptr(rockchip_hdmi_i2s_of_match),
},
.probe = rockchip_hdmi_i2s_audio_probe,
.remove = rockchip_hdmi_i2s_audio_remove,
};
module_platform_driver(rockchip_hdmi_i2s_audio_driver);
MODULE_AUTHOR("rockchip");
MODULE_DESCRIPTION("Rockchip HDMI I2S Audio Card");
MODULE_LICENSE("GPL");

View File

@@ -1,138 +0,0 @@
/*
* rk_hdmi_spdif.c -- hdmi spdif for rockchip
*
* Copyright (C) 2015 Fuzhou Rockchip Electronics Co., Ltd
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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/module.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/clk.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include "card_info.h"
#include "rk_pcm.h"
#if defined(CONFIG_RK_HDMI) && defined(CONFIG_SND_SOC_HDMI_SPDIF)
extern int snd_config_hdmi_audio(struct snd_pcm_hw_params *params);
#endif
static int rk_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned long sclk;
int ret, ratio;
/* bmc: 2*32*fs*2 = 128fs */
ratio = 128;
switch (params_rate(params)) {
case 44100:
case 32000:
case 48000:
case 96000:
case 192000:
sclk = params_rate(params) * ratio;
break;
default:
pr_err("rk_spdif: params not support\n");
return -EINVAL;
}
ret = snd_soc_dai_set_sysclk(cpu_dai, 0,
sclk, SND_SOC_CLOCK_IN);
#if defined(CONFIG_RK_HDMI) && defined(CONFIG_SND_SOC_HDMI_SPDIF)
snd_config_hdmi_audio(params);
#endif
return ret;
}
static struct snd_soc_ops rk_spdif_ops = {
.hw_params = rk_hw_params,
};
static struct snd_soc_dai_link rk_dai = {
.name = "SPDIF",
.stream_name = "SPDIF PCM Playback",
.codec_dai_name = "rk-hdmi-spdif-hifi",
.ops = &rk_spdif_ops,
};
static struct snd_soc_card rockchip_hdmi_spdif_snd_card = {
.name = "RK-HDMI-SPDIF",
.dai_link = &rk_dai,
.num_links = 1,
};
static int rockchip_hdmi_spdif_audio_probe(struct platform_device *pdev)
{
int ret;
struct snd_soc_card *card = &rockchip_hdmi_spdif_snd_card;
card->dev = &pdev->dev;
ret = rockchip_of_get_sound_card_info_(card, false);
if (ret) {
pr_err("%s() get sound card info failed:%d\n",
__func__, ret);
return ret;
}
ret = snd_soc_register_card(card);
if (ret)
pr_err("%s() register card failed:%d\n",
__func__, ret);
return ret;
}
static int rockchip_hdmi_spdif_audio_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
snd_soc_unregister_card(card);
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id rockchip_hdmi_spdif_of_match[] = {
{ .compatible = "rockchip-hdmi-spdif", },
{},
};
MODULE_DEVICE_TABLE(of, rockchip_hdmi_spdif_of_match);
#endif /* CONFIG_OF */
static struct platform_driver rockchip_hdmi_spdif_audio_driver = {
.driver = {
.name = "rockchip-hdmi-spdif",
.pm = &snd_soc_pm_ops,
.of_match_table = of_match_ptr(rockchip_hdmi_spdif_of_match),
},
.probe = rockchip_hdmi_spdif_audio_probe,
.remove = rockchip_hdmi_spdif_audio_remove,
};
module_platform_driver(rockchip_hdmi_spdif_audio_driver);
MODULE_AUTHOR("hzb <hzb@rock-chips.com>");
MODULE_DESCRIPTION("Rockchip HDMI Spdif Card");
MODULE_LICENSE("GPL");

View File

@@ -1,838 +0,0 @@
/*
* Rockchip I2S ALSA SoC Digital Audio Interface(DAI) driver
*
* Copyright (C) 2015 Fuzhou Rockchip Electronics Co., Ltd
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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/init.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/version.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/rockchip/cpu.h>
#include <linux/rockchip/cru.h>
#include <linux/rockchip/grf.h>
#include <linux/slab.h>
#include <asm/dma.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/initval.h>
#include <sound/soc.h>
#include <sound/dmaengine_pcm.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
#include "rk_pcm.h"
#include "rk_i2s.h"
#define CLK_SET_LATER
#define I2S_DEFAULT_FREQ (11289600)
#define I2S_DMA_BURST_SIZE (16) /* size * width: 16*4 = 64 bytes */
static DEFINE_SPINLOCK(lock);
#if defined(CONFIG_RK_HDMI) && defined(CONFIG_SND_RK_SOC_HDMI_I2S)
extern int snd_config_hdmi_audio(struct snd_pcm_hw_params *params);
#endif
struct rk_i2s_dev {
struct device *dev;
struct clk *clk; /* bclk */
struct clk *mclk; /*mclk output only */
struct clk *hclk; /*ahb clk */
struct snd_dmaengine_dai_dma_data capture_dma_data;
struct snd_dmaengine_dai_dma_data playback_dma_data;
struct regmap *regmap;
bool tx_start;
bool rx_start;
int xfer_mode; /* 0: i2s, 1: pcm */
#ifdef CLK_SET_LATER
struct delayed_work clk_delayed_work;
#endif
};
static inline struct rk_i2s_dev *to_info(struct snd_soc_dai *dai)
{
return snd_soc_dai_get_drvdata(dai);
}
static void rockchip_snd_txctrl(struct rk_i2s_dev *i2s, int on)
{
unsigned long flags;
unsigned int val = 0;
int retry = 10;
spin_lock_irqsave(&lock, flags);
dev_dbg(i2s->dev, "%s: %d: on: %d\n", __func__, __LINE__, on);
if (on) {
regmap_update_bits(i2s->regmap, I2S_DMACR,
I2S_DMACR_TDE_MASK, I2S_DMACR_TDE_ENABLE);
regmap_update_bits(i2s->regmap, I2S_XFER,
I2S_XFER_TXS_MASK | I2S_XFER_RXS_MASK,
I2S_XFER_TXS_START | I2S_XFER_RXS_START);
i2s->tx_start = true;
} else {
i2s->tx_start = false;
regmap_update_bits(i2s->regmap, I2S_DMACR,
I2S_DMACR_TDE_MASK, I2S_DMACR_TDE_DISABLE);
if (!i2s->rx_start) {
regmap_update_bits(i2s->regmap, I2S_XFER,
I2S_XFER_TXS_MASK |
I2S_XFER_RXS_MASK,
I2S_XFER_TXS_STOP |
I2S_XFER_RXS_STOP);
regmap_update_bits(i2s->regmap, I2S_CLR,
I2S_CLR_TXC_MASK | I2S_CLR_RXC_MASK,
I2S_CLR_TXC | I2S_CLR_RXC);
regmap_read(i2s->regmap, I2S_CLR, &val);
/* Should wait for clear operation to finish */
while (val) {
regmap_read(i2s->regmap, I2S_CLR, &val);
retry--;
if (!retry) {
dev_warn(i2s->dev, "fail to clear\n");
break;
}
}
dev_dbg(i2s->dev, "%s: %d: stop xfer\n",
__func__, __LINE__);
}
}
spin_unlock_irqrestore(&lock, flags);
}
static void rockchip_snd_rxctrl(struct rk_i2s_dev *i2s, int on)
{
unsigned long flags;
unsigned int val = 0;
int retry = 10;
spin_lock_irqsave(&lock, flags);
dev_dbg(i2s->dev, "%s: %d: on: %d\n", __func__, __LINE__, on);
if (on) {
regmap_update_bits(i2s->regmap, I2S_DMACR,
I2S_DMACR_RDE_MASK, I2S_DMACR_RDE_ENABLE);
regmap_update_bits(i2s->regmap, I2S_XFER,
I2S_XFER_TXS_MASK | I2S_XFER_RXS_MASK,
I2S_XFER_TXS_START | I2S_XFER_RXS_START);
i2s->rx_start = true;
} else {
i2s->rx_start = false;
regmap_update_bits(i2s->regmap, I2S_DMACR,
I2S_DMACR_RDE_MASK, I2S_DMACR_RDE_DISABLE);
if (!i2s->tx_start) {
regmap_update_bits(i2s->regmap, I2S_XFER,
I2S_XFER_TXS_MASK |
I2S_XFER_RXS_MASK,
I2S_XFER_TXS_STOP |
I2S_XFER_RXS_STOP);
regmap_update_bits(i2s->regmap, I2S_CLR,
I2S_CLR_TXC_MASK | I2S_CLR_RXC_MASK,
I2S_CLR_TXC | I2S_CLR_RXC);
regmap_read(i2s->regmap, I2S_CLR, &val);
/* Should wait for clear operation to finish */
while (val) {
regmap_read(i2s->regmap, I2S_CLR, &val);
retry--;
if (!retry) {
dev_warn(i2s->dev, "fail to clear\n");
break;
}
}
dev_dbg(i2s->dev, "%s: %d: stop xfer\n",
__func__, __LINE__);
}
}
spin_unlock_irqrestore(&lock, flags);
}
static int rockchip_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
unsigned int fmt)
{
struct rk_i2s_dev *i2s = to_info(cpu_dai);
unsigned int mask = 0, val = 0;
int ret = 0;
unsigned long flags;
spin_lock_irqsave(&lock, flags);
mask = I2S_CKR_MSS_MASK;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBS_CFS:
/* Codec is slave, so set cpu master */
val = I2S_CKR_MSS_MASTER;
break;
case SND_SOC_DAIFMT_CBM_CFM:
/* Codec is master, so set cpu slave */
val = I2S_CKR_MSS_SLAVE;
break;
default:
ret = -EINVAL;
goto err_fmt;
}
regmap_update_bits(i2s->regmap, I2S_CKR, mask, val);
mask = I2S_TXCR_IBM_MASK;
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_RIGHT_J:
val = I2S_TXCR_IBM_RSJM;
break;
case SND_SOC_DAIFMT_LEFT_J:
val = I2S_TXCR_IBM_LSJM;
break;
case SND_SOC_DAIFMT_I2S:
val = I2S_TXCR_IBM_NORMAL;
break;
default:
ret = -EINVAL;
goto err_fmt;
}
regmap_update_bits(i2s->regmap, I2S_TXCR, mask, val);
mask = I2S_RXCR_IBM_MASK;
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_RIGHT_J:
val = I2S_RXCR_IBM_RSJM;
break;
case SND_SOC_DAIFMT_LEFT_J:
val = I2S_RXCR_IBM_LSJM;
break;
case SND_SOC_DAIFMT_I2S:
val = I2S_RXCR_IBM_NORMAL;
break;
default:
ret = -EINVAL;
goto err_fmt;
}
regmap_update_bits(i2s->regmap, I2S_RXCR, mask, val);
err_fmt:
spin_unlock_irqrestore(&lock, flags);
return ret;
}
static int rockchip_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct rk_i2s_dev *i2s = to_info(dai);
unsigned int val = 0;
unsigned long flags;
spin_lock_irqsave(&lock, flags);
dev_dbg(i2s->dev, "%s: %d\n", __func__, __LINE__);
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S8:
val |= I2S_TXCR_VDW(8);
break;
case SNDRV_PCM_FORMAT_S16_LE:
val |= I2S_TXCR_VDW(16);
break;
case SNDRV_PCM_FORMAT_S20_3LE:
val |= I2S_TXCR_VDW(20);
break;
case SNDRV_PCM_FORMAT_S24_LE:
case SNDRV_PCM_FORMAT_S24_3LE:
val |= I2S_TXCR_VDW(24);
break;
case SNDRV_PCM_FORMAT_S32_LE:
val |= I2S_TXCR_VDW(32);
break;
default:
dev_err(i2s->dev, "invalid fmt: %d\n", params_format(params));
spin_unlock_irqrestore(&lock, flags);
return -EINVAL;
}
switch (params_channels(params)) {
case I2S_CHANNEL_8:
val |= I2S_TXCR_CHN_8;
break;
case I2S_CHANNEL_6:
val |= I2S_TXCR_CHN_6;
break;
case I2S_CHANNEL_4:
val |= I2S_TXCR_CHN_4;
break;
case I2S_CHANNEL_2:
val |= I2S_TXCR_CHN_2;
break;
default:
dev_err(i2s->dev, "invalid channel: %d\n",
params_channels(params));
spin_unlock_irqrestore(&lock, flags);
return -EINVAL;
}
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
regmap_update_bits(i2s->regmap, I2S_TXCR,
I2S_TXCR_VDW_MASK |
I2S_TXCR_CSR_MASK,
val);
} else {
regmap_update_bits(i2s->regmap, I2S_RXCR,
I2S_RXCR_VDW_MASK, val);
}
regmap_update_bits(i2s->regmap, I2S_DMACR,
I2S_DMACR_TDL_MASK | I2S_DMACR_RDL_MASK,
I2S_DMACR_TDL(16) | I2S_DMACR_RDL(16));
#if defined(CONFIG_RK_HDMI) && defined(CONFIG_SND_RK_SOC_HDMI_I2S)
snd_config_hdmi_audio(params);
#endif
spin_unlock_irqrestore(&lock, flags);
return 0;
}
static int rockchip_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
struct rk_i2s_dev *i2s = to_info(dai);
int ret = 0;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
rockchip_snd_rxctrl(i2s, 1);
else
rockchip_snd_txctrl(i2s, 1);
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
rockchip_snd_rxctrl(i2s, 0);
else
rockchip_snd_txctrl(i2s, 0);
break;
default:
ret = -EINVAL;
break;
}
return ret;
}
static int rockchip_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
int clk_id, unsigned int freq, int dir)
{
struct rk_i2s_dev *i2s = to_info(cpu_dai);
int ret;
ret = clk_set_rate(i2s->clk, freq);
if (ret)
dev_err(i2s->dev, "fail set clk: freq: %d\n", freq);
return ret;
}
static int rockchip_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai,
int div_id, int div)
{
struct rk_i2s_dev *i2s = to_info(cpu_dai);
unsigned int val = 0;
unsigned long flags;
spin_lock_irqsave(&lock, flags);
dev_dbg(i2s->dev, "%s: div_id=%d, div=%d\n", __func__, div_id, div);
switch (div_id) {
case ROCKCHIP_DIV_BCLK:
val |= I2S_CKR_TSD(div);
val |= I2S_CKR_RSD(div);
regmap_update_bits(i2s->regmap, I2S_CKR,
I2S_CKR_TSD_MASK | I2S_CKR_RSD_MASK,
val);
break;
case ROCKCHIP_DIV_MCLK:
val |= I2S_CKR_MDIV(div);
regmap_update_bits(i2s->regmap, I2S_CKR,
I2S_CKR_MDIV_MASK, val);
break;
default:
spin_unlock_irqrestore(&lock, flags);
return -EINVAL;
}
spin_unlock_irqrestore(&lock, flags);
return 0;
}
static int rockchip_i2s_dai_probe(struct snd_soc_dai *dai)
{
struct rk_i2s_dev *i2s = to_info(dai);
dai->capture_dma_data = &i2s->capture_dma_data;
dai->playback_dma_data = &i2s->playback_dma_data;
return 0;
}
static struct snd_soc_dai_ops rockchip_i2s_dai_ops = {
.trigger = rockchip_i2s_trigger,
.hw_params = rockchip_i2s_hw_params,
.set_fmt = rockchip_i2s_set_fmt,
.set_clkdiv = rockchip_i2s_set_clkdiv,
.set_sysclk = rockchip_i2s_set_sysclk,
};
#define ROCKCHIP_I2S_RATES SNDRV_PCM_RATE_8000_192000
#define ROCKCHIP_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S20_3LE | \
SNDRV_PCM_FMTBIT_S24_LE | \
SNDRV_PCM_FORMAT_S32_LE)
struct snd_soc_dai_driver rockchip_i2s_dai[] = {
{
.probe = rockchip_i2s_dai_probe,
.name = "rockchip-i2s.0",
.id = 0,
.playback = {
.channels_min = 2,
.channels_max = 8,
.rates = ROCKCHIP_I2S_RATES,
.formats = ROCKCHIP_I2S_FORMATS,
},
.capture = {
.channels_min = 2,
.channels_max = 2,
.rates = ROCKCHIP_I2S_RATES,
.formats = ROCKCHIP_I2S_FORMATS,
},
.ops = &rockchip_i2s_dai_ops,
.symmetric_rates = 1,
},
{
.probe = rockchip_i2s_dai_probe,
.name = "rockchip-i2s.1",
.id = 1,
.playback = {
.channels_min = 2,
.channels_max = 2,
.rates = ROCKCHIP_I2S_RATES,
.formats = ROCKCHIP_I2S_FORMATS,
},
.capture = {
.channels_min = 2,
.channels_max = 2,
.rates = ROCKCHIP_I2S_RATES,
.formats = ROCKCHIP_I2S_FORMATS,
},
.ops = &rockchip_i2s_dai_ops,
.symmetric_rates = 1,
},
};
static const struct snd_soc_component_driver rockchip_i2s_component = {
.name = "rockchip-i2s",
};
#ifdef CONFIG_PM
static int rockchip_i2s_runtime_suspend(struct device *dev)
{
struct rk_i2s_dev *i2s = dev_get_drvdata(dev);
dev_dbg(i2s->dev, "%s\n", __func__);
return 0;
}
static int rockchip_i2s_runtime_resume(struct device *dev)
{
struct rk_i2s_dev *i2s = dev_get_drvdata(dev);
dev_dbg(i2s->dev, "%s\n", __func__);
return 0;
}
#else
#define i2s_runtime_suspend NULL
#define i2s_runtime_resume NULL
#endif
#ifdef CLK_SET_LATER
static void set_clk_later_work(struct work_struct *work)
{
struct rk_i2s_dev *i2s = container_of(work, struct rk_i2s_dev,
clk_delayed_work.work);
clk_set_rate(i2s->clk, I2S_DEFAULT_FREQ);
if (!IS_ERR(i2s->mclk))
clk_set_rate(i2s->mclk, I2S_DEFAULT_FREQ);
}
#endif
static bool rockchip_i2s_wr_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case I2S_TXCR:
case I2S_RXCR:
case I2S_CKR:
case I2S_DMACR:
case I2S_INTCR:
case I2S_XFER:
case I2S_CLR:
case I2S_TXDR:
return true;
default:
return false;
}
}
static bool rockchip_i2s_rd_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case I2S_TXCR:
case I2S_RXCR:
case I2S_CKR:
case I2S_DMACR:
case I2S_INTCR:
case I2S_XFER:
case I2S_CLR:
case I2S_RXDR:
case I2S_FIFOLR:
case I2S_INTSR:
return true;
default:
return false;
}
}
static bool rockchip_i2s_volatile_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case I2S_INTSR:
case I2S_CLR:
return true;
default:
return false;
}
}
static bool rockchip_i2s_precious_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
default:
return false;
}
}
static const struct regmap_config rockchip_i2s_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
.max_register = I2S_RXDR,
.writeable_reg = rockchip_i2s_wr_reg,
.readable_reg = rockchip_i2s_rd_reg,
.volatile_reg = rockchip_i2s_volatile_reg,
.precious_reg = rockchip_i2s_precious_reg,
.cache_type = REGCACHE_FLAT,
};
static int rockchip_i2s_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
struct rk_i2s_dev *i2s;
struct resource *res;
void __iomem *regs;
int ret;
ret = of_property_read_u32(node, "i2s-id", &pdev->id);
if (ret < 0) {
dev_err(&pdev->dev, "Property 'i2s-id' missing or invalid\n");
ret = -EINVAL;
goto err;
}
if (soc_is_rk3126b()) {
int sdi_src = 0;
/* rk3126b has no i2s1 controller(i2s_8ch) */
if (1 == pdev->id) {
pr_info("rk3126b has no i2s1 controller\n");
ret = -ENODEV;
goto err;
}
ret = of_property_read_u32(node, "sdi_source",
&sdi_src);
if (ret < 0)
sdi_src = 0;
if (1 == sdi_src) {
int val;
/*GRF_SOC_CON*/
val = readl_relaxed(RK_GRF_VIRT + 0x0140);
val = val | 0x04000400;
writel_relaxed(val, RK_GRF_VIRT + 0x0140);
}
}
i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL);
if (!i2s) {
dev_err(&pdev->dev, "Can't allocate rk_i2s_dev\n");
ret = -ENOMEM;
goto err;
}
i2s->hclk = devm_clk_get(&pdev->dev, "i2s_hclk");
if (IS_ERR(i2s->hclk)) {
dev_err(&pdev->dev, "Can't retrieve i2s bus clock\n");
ret = PTR_ERR(i2s->hclk);
goto err;
} else {
clk_prepare_enable(i2s->hclk);
}
i2s->clk = devm_clk_get(&pdev->dev, "i2s_clk");
if (IS_ERR(i2s->clk)) {
dev_err(&pdev->dev, "Can't retrieve i2s clock\n");
ret = PTR_ERR(i2s->clk);
goto err;
}
#ifdef CLK_SET_LATER
INIT_DELAYED_WORK(&i2s->clk_delayed_work, set_clk_later_work);
schedule_delayed_work(&i2s->clk_delayed_work, msecs_to_jiffies(10));
#else
clk_set_rate(i2s->clk, I2S_DEFAULT_FREQ);
#endif
clk_prepare_enable(i2s->clk);
i2s->mclk = devm_clk_get(&pdev->dev, "i2s_mclk");
if (IS_ERR(i2s->mclk)) {
dev_info(&pdev->dev, "i2s%d has no mclk\n", pdev->id);
} else {
#ifndef CLK_SET_LATER
clk_set_rate(i2s->mclk, I2S_DEFAULT_FREQ);
#endif
clk_prepare_enable(i2s->mclk);
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(regs)) {
ret = PTR_ERR(regs);
goto err;
}
i2s->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
&rockchip_i2s_regmap_config);
if (IS_ERR(i2s->regmap)) {
dev_err(&pdev->dev,
"Failed to initialise managed register map\n");
ret = PTR_ERR(i2s->regmap);
goto err;
}
i2s->playback_dma_data.addr = res->start + I2S_TXDR;
i2s->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
i2s->playback_dma_data.maxburst = I2S_DMA_BURST_SIZE;
i2s->capture_dma_data.addr = res->start + I2S_RXDR;
i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
i2s->capture_dma_data.maxburst = I2S_DMA_BURST_SIZE;
i2s->tx_start = false;
i2s->rx_start = false;
i2s->dev = &pdev->dev;
dev_set_drvdata(&pdev->dev, i2s);
pm_runtime_enable(&pdev->dev);
if (!pm_runtime_enabled(&pdev->dev)) {
ret = rockchip_i2s_runtime_resume(&pdev->dev);
if (ret)
goto err_pm_disable;
}
ret = snd_soc_register_component(&pdev->dev, &rockchip_i2s_component,
&rockchip_i2s_dai[pdev->id], 1);
if (ret) {
dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
ret = -ENOMEM;
goto err_suspend;
}
ret = rockchip_pcm_platform_register(&pdev->dev);
if (ret) {
dev_err(&pdev->dev, "Could not register PCM: %d\n", ret);
goto err_unregister_component;
}
ret = of_property_read_u32(node, "rockchip,xfer-mode", &i2s->xfer_mode);
if (ret < 0)
i2s->xfer_mode = I2S_XFER_MODE;
if (PCM_XFER_MODE == i2s->xfer_mode) {
regmap_update_bits(i2s->regmap, I2S_TXCR,
I2S_TXCR_TFS_MASK,
I2S_TXCR_TFS_PCM);
regmap_update_bits(i2s->regmap, I2S_RXCR,
I2S_RXCR_TFS_MASK,
I2S_RXCR_TFS_PCM);
}
rockchip_snd_txctrl(i2s, 0);
rockchip_snd_rxctrl(i2s, 0);
return 0;
err_unregister_component:
snd_soc_unregister_component(&pdev->dev);
err_suspend:
if (!pm_runtime_status_suspended(&pdev->dev))
rockchip_i2s_runtime_suspend(&pdev->dev);
err_pm_disable:
pm_runtime_disable(&pdev->dev);
err:
return ret;
}
static int rockchip_i2s_remove(struct platform_device *pdev)
{
struct rk_i2s_dev *i2s = dev_get_drvdata(&pdev->dev);
pm_runtime_disable(&pdev->dev);
if (!pm_runtime_status_suspended(&pdev->dev))
rockchip_i2s_runtime_suspend(&pdev->dev);
if (!IS_ERR(i2s->mclk))
clk_disable_unprepare(i2s->mclk);
clk_disable_unprepare(i2s->clk);
clk_disable_unprepare(i2s->hclk);
rockchip_pcm_platform_unregister(&pdev->dev);
snd_soc_unregister_component(&pdev->dev);
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id rockchip_i2s_match[] = {
{ .compatible = "rockchip-i2s", },
{},
};
MODULE_DEVICE_TABLE(of, rockchip_i2s_match);
#endif
#ifdef CONFIG_PM_SLEEP
static int rockchip_i2s_suspend(struct device *dev)
{
struct rk_i2s_dev *i2s = dev_get_drvdata(dev);
dev_dbg(i2s->dev, "%s\n", __func__);
return pinctrl_pm_select_sleep_state(dev);
}
static int rockchip_i2s_resume(struct device *dev)
{
struct rk_i2s_dev *i2s = dev_get_drvdata(dev);
int ret;
ret = pm_runtime_get_sync(dev);
if (ret < 0)
return ret;
ret = pinctrl_pm_select_default_state(dev);
if (ret < 0)
return ret;
ret = regmap_reinit_cache(i2s->regmap, &rockchip_i2s_regmap_config);
if (PCM_XFER_MODE == i2s->xfer_mode) {
regmap_update_bits(i2s->regmap, I2S_TXCR,
I2S_TXCR_TFS_MASK,
I2S_TXCR_TFS_PCM);
regmap_update_bits(i2s->regmap, I2S_RXCR,
I2S_RXCR_TFS_MASK,
I2S_RXCR_TFS_PCM);
}
pm_runtime_put(dev);
dev_dbg(i2s->dev, "%s\n", __func__);
return ret;
}
#endif
static const struct dev_pm_ops rockchip_i2s_pm_ops = {
SET_RUNTIME_PM_OPS(rockchip_i2s_runtime_suspend, rockchip_i2s_runtime_resume,
NULL)
SET_SYSTEM_SLEEP_PM_OPS(rockchip_i2s_suspend, rockchip_i2s_resume)
};
static struct platform_driver rockchip_i2s_driver = {
.probe = rockchip_i2s_probe,
.remove = rockchip_i2s_remove,
.driver = {
.name = "rockchip-i2s",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(rockchip_i2s_match),
.pm = &rockchip_i2s_pm_ops,
},
};
static int __init rockchip_i2s_init(void)
{
return platform_driver_register(&rockchip_i2s_driver);
}
subsys_initcall_sync(rockchip_i2s_init);
static void __exit rockchip_i2s_exit(void)
{
platform_driver_unregister(&rockchip_i2s_driver);
}
module_exit(rockchip_i2s_exit);
MODULE_AUTHOR("Sugar <sugar.zhang@rock-chips.com>");
MODULE_DESCRIPTION("Rockchip I2S Controller Driver");
MODULE_LICENSE("GPL v2");

View File

@@ -1,231 +0,0 @@
/*
* Rockchip I2S ALSA SoC Digital Audio Interface(DAI) driver
*
* Copyright (C) 2015 Fuzhou Rockchip Electronics Co., Ltd
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 __RK_I2S_H__
#define __RK_I2S_H__
/*
* TXCR
* transmit operation control register
*/
#define I2S_TXCR_RCNT_SHIFT 17
#define I2S_TXCR_RCNT_MASK (0x3f << I2S_TXCR_RCNT_SHIFT)
#define I2S_TXCR_CSR_SHIFT 15
#define I2S_TXCR_CSR(x) (x << I2S_TXCR_CSR_SHIFT)
#define I2S_TXCR_CHN_2 (0 << I2S_TXCR_CSR_SHIFT)
#define I2S_TXCR_CHN_4 (1 << I2S_TXCR_CSR_SHIFT)
#define I2S_TXCR_CHN_6 (2 << I2S_TXCR_CSR_SHIFT)
#define I2S_TXCR_CHN_8 (3 << I2S_TXCR_CSR_SHIFT)
#define I2S_TXCR_CSR_MASK (3 << I2S_TXCR_CSR_SHIFT)
#define I2S_TXCR_HWT BIT(14)
#define I2S_TXCR_SJM_SHIFT 12
#define I2S_TXCR_SJM_R (0 << I2S_TXCR_SJM_SHIFT)
#define I2S_TXCR_SJM_L (1 << I2S_TXCR_SJM_SHIFT)
#define I2S_TXCR_FBM_SHIFT 11
#define I2S_TXCR_FBM_MSB (0 << I2S_TXCR_FBM_SHIFT)
#define I2S_TXCR_FBM_LSB (1 << I2S_TXCR_FBM_SHIFT)
#define I2S_TXCR_IBM_SHIFT 9
#define I2S_TXCR_IBM_NORMAL (0 << I2S_TXCR_IBM_SHIFT)
#define I2S_TXCR_IBM_LSJM (1 << I2S_TXCR_IBM_SHIFT)
#define I2S_TXCR_IBM_RSJM (2 << I2S_TXCR_IBM_SHIFT)
#define I2S_TXCR_IBM_MASK (3 << I2S_TXCR_IBM_SHIFT)
#define I2S_TXCR_PBM_SHIFT 7
#define I2S_TXCR_PBM_MODE(x) (x << I2S_TXCR_PBM_SHIFT)
#define I2S_TXCR_PBM_MASK (3 << I2S_TXCR_PBM_SHIFT)
#define I2S_TXCR_TFS_SHIFT 5
#define I2S_TXCR_TFS_I2S (0 << I2S_TXCR_TFS_SHIFT)
#define I2S_TXCR_TFS_PCM (1 << I2S_TXCR_TFS_SHIFT)
#define I2S_TXCR_TFS_MASK (1 << I2S_TXCR_TFS_SHIFT)
#define I2S_TXCR_VDW_SHIFT 0
#define I2S_TXCR_VDW(x) ((x - 1) << I2S_TXCR_VDW_SHIFT)
#define I2S_TXCR_VDW_MASK (0x1f << I2S_TXCR_VDW_SHIFT)
/*
* RXCR
* receive operation control register
*/
#define I2S_RXCR_HWT BIT(14)
#define I2S_RXCR_SJM_SHIFT 12
#define I2S_RXCR_SJM_R (0 << I2S_RXCR_SJM_SHIFT)
#define I2S_RXCR_SJM_L (1 << I2S_RXCR_SJM_SHIFT)
#define I2S_RXCR_FBM_SHIFT 11
#define I2S_RXCR_FBM_MSB (0 << I2S_RXCR_FBM_SHIFT)
#define I2S_RXCR_FBM_LSB (1 << I2S_RXCR_FBM_SHIFT)
#define I2S_RXCR_IBM_SHIFT 9
#define I2S_RXCR_IBM_NORMAL (0 << I2S_RXCR_IBM_SHIFT)
#define I2S_RXCR_IBM_LSJM (1 << I2S_RXCR_IBM_SHIFT)
#define I2S_RXCR_IBM_RSJM (2 << I2S_RXCR_IBM_SHIFT)
#define I2S_RXCR_IBM_MASK (3 << I2S_RXCR_IBM_SHIFT)
#define I2S_RXCR_PBM_SHIFT 7
#define I2S_RXCR_PBM_MODE(x) (x << I2S_RXCR_PBM_SHIFT)
#define I2S_RXCR_PBM_MASK (3 << I2S_RXCR_PBM_SHIFT)
#define I2S_RXCR_TFS_SHIFT 5
#define I2S_RXCR_TFS_I2S (0 << I2S_RXCR_TFS_SHIFT)
#define I2S_RXCR_TFS_PCM (1 << I2S_RXCR_TFS_SHIFT)
#define I2S_RXCR_TFS_MASK (1 << I2S_RXCR_TFS_SHIFT)
#define I2S_RXCR_VDW_SHIFT 0
#define I2S_RXCR_VDW(x) ((x - 1) << I2S_RXCR_VDW_SHIFT)
#define I2S_RXCR_VDW_MASK (0x1f << I2S_RXCR_VDW_SHIFT)
/*
* CKR
* clock generation register
*/
#define I2S_CKR_MSS_SHIFT 27
#define I2S_CKR_MSS_MASTER (0 << I2S_CKR_MSS_SHIFT)
#define I2S_CKR_MSS_SLAVE (1 << I2S_CKR_MSS_SHIFT)
#define I2S_CKR_MSS_MASK (1 << I2S_CKR_MSS_SHIFT)
#define I2S_CKR_CKP_SHIFT 26
#define I2S_CKR_CKP_NEG (0 << I2S_CKR_CKP_SHIFT)
#define I2S_CKR_CKP_POS (1 << I2S_CKR_CKP_SHIFT)
#define I2S_CKR_RLP_SHIFT 25
#define I2S_CKR_RLP_NORMAL (0 << I2S_CKR_RLP_SHIFT)
#define I2S_CKR_RLP_OPPSITE (1 << I2S_CKR_RLP_SHIFT)
#define I2S_CKR_TLP_SHIFT 24
#define I2S_CKR_TLP_NORMAL (0 << I2S_CKR_TLP_SHIFT)
#define I2S_CKR_TLP_OPPSITE (1 << I2S_CKR_TLP_SHIFT)
#define I2S_CKR_MDIV_SHIFT 16
#define I2S_CKR_MDIV(x) ((x) << I2S_CKR_MDIV_SHIFT)
#define I2S_CKR_MDIV_MASK (0xff << I2S_CKR_MDIV_SHIFT)
#define I2S_CKR_RSD_SHIFT 8
#define I2S_CKR_RSD(x) ((x) << I2S_CKR_RSD_SHIFT)
#define I2S_CKR_RSD_MASK (0xff << I2S_CKR_RSD_SHIFT)
#define I2S_CKR_TSD_SHIFT 0
#define I2S_CKR_TSD(x) ((x) << I2S_CKR_TSD_SHIFT)
#define I2S_CKR_TSD_MASK (0xff << I2S_CKR_TSD_SHIFT)
/*
* FIFOLR
* FIFO level register
*/
#define I2S_FIFOLR_RFL_SHIFT 24
#define I2S_FIFOLR_RFL_MASK (0x3f << I2S_FIFOLR_RFL_SHIFT)
#define I2S_FIFOLR_TFL3_SHIFT 18
#define I2S_FIFOLR_TFL3_MASK (0x3f << I2S_FIFOLR_TFL3_SHIFT)
#define I2S_FIFOLR_TFL2_SHIFT 12
#define I2S_FIFOLR_TFL2_MASK (0x3f << I2S_FIFOLR_TFL2_SHIFT)
#define I2S_FIFOLR_TFL1_SHIFT 6
#define I2S_FIFOLR_TFL1_MASK (0x3f << I2S_FIFOLR_TFL1_SHIFT)
#define I2S_FIFOLR_TFL0_SHIFT 0
#define I2S_FIFOLR_TFL0_MASK (0x3f << I2S_FIFOLR_TFL0_SHIFT)
/*
* DMACR
* DMA control register
*/
#define I2S_DMACR_RDE_SHIFT 24
#define I2S_DMACR_RDE_DISABLE (0 << I2S_DMACR_RDE_SHIFT)
#define I2S_DMACR_RDE_ENABLE (1 << I2S_DMACR_RDE_SHIFT)
#define I2S_DMACR_RDE_MASK (1 << I2S_DMACR_RDE_SHIFT)
#define I2S_DMACR_RDL_SHIFT 16
#define I2S_DMACR_RDL(x) ((x - 1) << I2S_DMACR_RDL_SHIFT)
#define I2S_DMACR_RDL_MASK (0x1f << I2S_DMACR_RDL_SHIFT)
#define I2S_DMACR_TDE_SHIFT 8
#define I2S_DMACR_TDE_DISABLE (0 << I2S_DMACR_TDE_SHIFT)
#define I2S_DMACR_TDE_ENABLE (1 << I2S_DMACR_TDE_SHIFT)
#define I2S_DMACR_TDE_MASK (1 << I2S_DMACR_TDE_SHIFT)
#define I2S_DMACR_TDL_SHIFT 0
#define I2S_DMACR_TDL(x) ((x) << I2S_DMACR_TDL_SHIFT)
#define I2S_DMACR_TDL_MASK (0x1f << I2S_DMACR_TDL_SHIFT)
/*
* INTCR
* interrupt control register
*/
#define I2S_INTCR_RFT_SHIFT 20
#define I2S_INTCR_RFT(x) ((x - 1) << I2S_INTCR_RFT_SHIFT)
#define I2S_INTCR_RXOIC BIT(18)
#define I2S_INTCR_RXOIE_SHIFT 17
#define I2S_INTCR_RXOIE_DISABLE (0 << I2S_INTCR_RXOIE_SHIFT)
#define I2S_INTCR_RXOIE_ENABLE (1 << I2S_INTCR_RXOIE_SHIFT)
#define I2S_INTCR_RXFIE_SHIFT 16
#define I2S_INTCR_RXFIE_DISABLE (0 << I2S_INTCR_RXFIE_SHIFT)
#define I2S_INTCR_RXFIE_ENABLE (1 << I2S_INTCR_RXFIE_SHIFT)
#define I2S_INTCR_TFT_SHIFT 4
#define I2S_INTCR_TFT(x) ((x - 1) << I2S_INTCR_TFT_SHIFT)
#define I2S_INTCR_TFT_MASK (0x1f << I2S_INTCR_TFT_SHIFT)
#define I2S_INTCR_TXUIC BIT(2)
#define I2S_INTCR_TXUIE_SHIFT 1
#define I2S_INTCR_TXUIE_DISABLE (0 << I2S_INTCR_TXUIE_SHIFT)
#define I2S_INTCR_TXUIE_ENABLE (1 << I2S_INTCR_TXUIE_SHIFT)
/*
* INTSR
* interrupt status register
*/
#define I2S_INTSR_RXOI_SHIFT 17
#define I2S_INTSR_RXOI_INA (0 << I2S_INTSR_RXOI_SHIFT)
#define I2S_INTSR_RXOI_ACT (1 << I2S_INTSR_RXOI_SHIFT)
#define I2S_INTSR_RXFI_SHIFT 16
#define I2S_INTSR_RXFI_INA (0 << I2S_INTSR_RXFI_SHIFT)
#define I2S_INTSR_RXFI_ACT (1 << I2S_INTSR_RXFI_SHIFT)
#define I2S_INTSR_TXUI_SHIFT 1
#define I2S_INTSR_TXUI_INA (0 << I2S_INTSR_TXUI_SHIFT)
#define I2S_INTSR_TXUI_ACT (1 << I2S_INTSR_TXUI_SHIFT)
#define I2S_INTSR_TXEI_SHIFT 0
#define I2S_INTSR_TXEI_INA (0 << I2S_INTSR_TXEI_SHIFT)
#define I2S_INTSR_TXEI_ACT (1 << I2S_INTSR_TXEI_SHIFT)
/*
* XFER
* Transfer start register
*/
#define I2S_XFER_RXS_SHIFT 1
#define I2S_XFER_RXS_STOP (0 << I2S_XFER_RXS_SHIFT)
#define I2S_XFER_RXS_START (1 << I2S_XFER_RXS_SHIFT)
#define I2S_XFER_RXS_MASK (1 << I2S_XFER_RXS_SHIFT)
#define I2S_XFER_TXS_SHIFT 0
#define I2S_XFER_TXS_STOP (0 << I2S_XFER_TXS_SHIFT)
#define I2S_XFER_TXS_START (1 << I2S_XFER_TXS_SHIFT)
#define I2S_XFER_TXS_MASK (1 << I2S_XFER_TXS_SHIFT)
/*
* CLR
* clear SCLK domain logic register
*/
#define I2S_CLR_RXC BIT(1)
#define I2S_CLR_RXC_MASK BIT(1)
#define I2S_CLR_TXC BIT(0)
#define I2S_CLR_TXC_MASK BIT(0)
/* I2S REGS */
#define I2S_TXCR (0x0000)
#define I2S_RXCR (0x0004)
#define I2S_CKR (0x0008)
#define I2S_FIFOLR (0x000c)
#define I2S_DMACR (0x0010)
#define I2S_INTCR (0x0014)
#define I2S_INTSR (0x0018)
#define I2S_XFER (0x001c)
#define I2S_CLR (0x0020)
#define I2S_TXDR (0x0024)
#define I2S_RXDR (0x0028)
/* Clock dividers */
#define ROCKCHIP_DIV_MCLK 0
#define ROCKCHIP_DIV_BCLK 1
#define ROCKCHIP_DIV_PRESCALER 2
/* channel */
#define I2S_CHANNEL_8 8
#define I2S_CHANNEL_6 6
#define I2S_CHANNEL_4 4
#define I2S_CHANNEL_2 2
#define I2S_XFER_MODE 0
#define PCM_XFER_MODE 1
#endif /* __RK_I2S_H__ */

View File

@@ -1,176 +0,0 @@
/*
* rk29_wm8988.c -- SoC audio for rockchip
*
* Driver for rockchip wm8988 audio
*
* 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.
*
*
*/
#include <linux/module.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include "../codecs/rk610_codec.h"
#include "card_info.h"
#include "rk_pcm.h"
#include "rk_i2s.h"
#ifdef CONFIG_MACH_RK_FAC
#include <plat/config.h>
extern int codec_type;
#endif
#if 0
#define DBG(x...) printk(KERN_ERR x)
#else
#define DBG(x...)
#endif
static int rk29_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret;
unsigned int pll_out = 0, dai_fmt = rtd->dai_link->dai_fmt;
int div_bclk,div_mclk;
// struct clk *general_pll;
DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
/* set codec DAI configuration */
ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
if (ret < 0) {
printk("%s():failed to set the format for codec side\n", __func__);
return ret;
}
/* set cpu DAI configuration */
ret = snd_soc_dai_set_fmt(cpu_dai, dai_fmt);
if (ret < 0) {
printk("%s():failed to set the format for cpu side\n", __func__);
return ret;
}
switch(params_rate(params)) {
case 8000:
case 16000:
case 24000:
case 32000:
case 48000:
case 96000:
pll_out = 12288000;
break;
case 11025:
case 22050:
case 44100:
case 88200:
pll_out = 11289600;
break;
case 176400:
pll_out = 11289600*2;
break;
case 192000:
pll_out = 12288000*2;
break;
default:
DBG("Enter:%s, %d, Error rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
return -EINVAL;
break;
}
DBG("Enter:%s, %d, rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
snd_soc_dai_set_sysclk(codec_dai, 0, pll_out, SND_SOC_CLOCK_IN);
if ((dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBS_CFS) {
div_bclk = 63;
div_mclk = pll_out/(params_rate(params)*64) - 1;
DBG("func is%s,pll_out=%d,div_mclk=%d div_bclk\n",
__FUNCTION__,pll_out,div_mclk, div_bclk);
snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK,div_bclk);
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, div_mclk);
// DBG("Enter:%s, %d, LRCK=%d\n",__FUNCTION__,__LINE__,(pll_out/4)/params_rate(params));
}
return 0;
}
static struct snd_soc_ops rk29_ops = {
.hw_params = rk29_hw_params,
};
static struct snd_soc_dai_link rk29_dai = {
.name = "RK610_CODEC",
.stream_name = "RK610 CODEC PCM",
.codec_dai_name = "rk610_codec",
.ops = &rk29_ops,
};
static struct snd_soc_card rockchip_rk610_snd_card = {
.name = "RK_RK610",
.dai_link = &rk29_dai,
.num_links = 1,
};
static int rockchip_rk610_audio_probe(struct platform_device *pdev)
{
int ret;
struct snd_soc_card *card = &rockchip_rk610_snd_card;
card->dev = &pdev->dev;
ret = rockchip_of_get_sound_card_info(card);
if (ret) {
printk("%s() get sound card info failed:%d\n", __FUNCTION__, ret);
return ret;
}
ret = snd_soc_register_card(card);
if (ret)
printk("%s() register card failed:%d\n", __FUNCTION__, ret);
return ret;
}
static int rockchip_rk610_audio_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
snd_soc_unregister_card(card);
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id rockchip_rk610_of_match[] = {
{ .compatible = "rockchip-rk610", },
{},
};
MODULE_DEVICE_TABLE(of, rockchip_rk610_of_match);
#endif /* CONFIG_OF */
static struct platform_driver rockchip_rk610_audio_driver = {
.driver = {
.name = "rockchip-rk610",
.owner = THIS_MODULE,
.pm = &snd_soc_pm_ops,
.of_match_table = of_match_ptr(rockchip_rk610_of_match),
},
.probe = rockchip_rk610_audio_probe,
.remove = rockchip_rk610_audio_remove,
};
module_platform_driver(rockchip_rk610_audio_driver);
/* Module information */
MODULE_AUTHOR("rockchip");
MODULE_DESCRIPTION("ROCKCHIP i2s ASoC Interface");
MODULE_LICENSE("GPL");

View File

@@ -1,70 +0,0 @@
/*
* rk_pcm.c -- ALSA SoC ROCKCHIP PCM Audio Layer Platform driver
*
* Driver for rockchip pcm audio
*
*
* 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.
*
*/
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/dmaengine_pcm.h>
#include "rk_pcm.h"
static const struct snd_pcm_hardware rockchip_pcm_hardware = {
.info = SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_PAUSE |
SNDRV_PCM_INFO_RESUME,
.formats = SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S20_3LE |
SNDRV_PCM_FMTBIT_S16_LE,
.channels_min = 2,
.channels_max = 8,
.buffer_bytes_max = 2*1024*1024,/*128*1024,*/
.period_bytes_min = 64,
.period_bytes_max = 512*1024,/*32*1024,//2048*4,///PAGE_SIZE*2,*/
.periods_min = 3,
.periods_max = 128,
.fifo_size = 16,
};
static const struct snd_dmaengine_pcm_config rockchip_dmaengine_pcm_config = {
.pcm_hardware = &rockchip_pcm_hardware,
.prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
.compat_filter_fn = NULL,
.prealloc_buffer_size = PAGE_SIZE * 512,
};
int rockchip_pcm_platform_register(struct device *dev)
{
return snd_dmaengine_pcm_register(dev, &rockchip_dmaengine_pcm_config,
SND_DMAENGINE_PCM_FLAG_COMPAT|
SND_DMAENGINE_PCM_FLAG_NO_RESIDUE);
}
EXPORT_SYMBOL_GPL(rockchip_pcm_platform_register);
int rockchip_pcm_platform_unregister(struct device *dev)
{
snd_dmaengine_pcm_unregister(dev);
return 0;
}
EXPORT_SYMBOL_GPL(rockchip_pcm_platform_unregister);
/* Module information */
MODULE_AUTHOR("rockchip");
MODULE_DESCRIPTION("ROCKCHIP PCM ASoC Interface");
MODULE_LICENSE("GPL");

View File

@@ -1,18 +0,0 @@
/*
* rockchip-pcm.h - ALSA PCM interface for the Rockchip rk28 SoC
*
* Driver for rockchip iis audio
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _ROCKCHIP_PCM_H
#define _ROCKCHIP_PCM_H
int rockchip_pcm_platform_register(struct device *dev);
int rockchip_pcm_platform_unregister(struct device *dev);
#endif /* _ROCKCHIP_PCM_H */

View File

@@ -1,177 +0,0 @@
/*
* rk29_wm8988.c -- SoC audio for rockchip
*
* Driver for rockchip wm8988 audio
*
* 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.
*
*
*/
#include <linux/module.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include "../codecs/rk1000_codec.h"
#include "card_info.h"
#include "rk_pcm.h"
#include "rk_i2s.h"
#define RK1000_CARD_DBG 0
#if RK1000_CARD_DBG
#define DBG(x...) pr_info(x)
#else
#define DBG(x...)
#endif
static int rk29_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int dai_fmt = rtd->dai_link->dai_fmt;
int ret;
unsigned int pll_out = 0;
int div_bclk, div_mclk;
DBG("Enter::%s----%d\n", __func__, __LINE__);
/* set codec DAI configuration */
ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
if (ret < 0) {
pr_err("%s():failed to set the format for codec side\n",
__func__);
return ret;
}
/* set cpu DAI configuration */
ret = snd_soc_dai_set_fmt(cpu_dai, dai_fmt);
if (ret < 0) {
pr_err("%s():failed to set the format for cpu side\n",
__func__);
return ret;
}
switch (params_rate(params)) {
case 8000:
case 16000:
case 24000:
case 32000:
case 48000:
case 96000:
pll_out = 12288000;
break;
case 11025:
case 22050:
case 44100:
case 88200:
pll_out = 11289600;
break;
case 176400:
pll_out = 11289600*2;
break;
case 192000:
pll_out = 12288000*2;
break;
default:
DBG("Enter:%s, %d, Error rate=%d\n", __func__,
__LINE__, params_rate(params));
return -EINVAL;
break;
}
DBG("Enter:%s, %d, rate=%d\n", __func__, __LINE__, params_rate(params));
snd_soc_dai_set_sysclk(codec_dai, 0, pll_out, SND_SOC_CLOCK_IN);
div_bclk = 127;
div_mclk = pll_out/(params_rate(params)*128) - 1;
snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK, div_bclk);
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, div_mclk);
return 0;
}
/*
* Logic for a rk1000 codec as connected on a rockchip board.
*/
static int rk29_rk1000_codec_init(struct snd_soc_pcm_runtime *rtd)
{
return 0;
}
static struct snd_soc_ops rk29_ops = {
.hw_params = rk29_hw_params,
};
static struct snd_soc_dai_link rk29_dai[] = {
{
.name = "RK1000",
.stream_name = "RK1000 CODEC PCM",
.codec_dai_name = "rk1000_codec",
.init = rk29_rk1000_codec_init,
.ops = &rk29_ops,
}
};
static struct snd_soc_card rockchip_rk1000_snd_card = {
.name = "RK_RK1000",
.dai_link = rk29_dai,
.num_links = 1,
};
static int rockchip_rk1000_audio_probe(struct platform_device *pdev)
{
int ret;
struct snd_soc_card *card = &rockchip_rk1000_snd_card;
card->dev = &pdev->dev;
ret = rockchip_of_get_sound_card_info(card);
if (ret) {
pr_err("%s() get sound card info failed:%d\n", __func__, ret);
return ret;
}
ret = snd_soc_register_card(card);
if (ret)
pr_err("%s() register card failed:%d\n", __func__, ret);
return ret;
}
static int rockchip_rk1000_audio_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
snd_soc_unregister_card(card);
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id rockchip_rk1000_of_match[] = {
{ .compatible = "rockchip-rk1000", },
{},
};
MODULE_DEVICE_TABLE(of, rockchip_rk1000_of_match);
#endif /* CONFIG_OF */
static struct platform_driver rockchip_rk1000_audio_driver = {
.driver = {
.name = "rockchip-rk1000",
.owner = THIS_MODULE,
.pm = &snd_soc_pm_ops,
.of_match_table = of_match_ptr(rockchip_rk1000_of_match),
},
.probe = rockchip_rk1000_audio_probe,
.remove = rockchip_rk1000_audio_remove,
};
module_platform_driver(rockchip_rk1000_audio_driver);
/* Module information */
MODULE_AUTHOR("rockchip");
MODULE_DESCRIPTION("ROCKCHIP i2s ASoC Interface");
MODULE_LICENSE("GPL");

View File

@@ -1,291 +0,0 @@
/*
* rk_rk3026.c -- SoC audio for rockchip
*
* Driver for rockchip rk3026 audio
*
* 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.
*
*
*/
#include <linux/module.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include "../codecs/rk3026_codec.h"
#include "card_info.h"
#include "rk_pcm.h"
#include "rk_i2s.h"
#if 0
#define DBG(x...) printk(KERN_INFO x)
#else
#define DBG(x...)
#endif
static const struct snd_soc_dapm_widget rk_dapm_widgets[] = {
SND_SOC_DAPM_MIC("Mic Jack", NULL),
SND_SOC_DAPM_MIC("Headset Jack", NULL),
SND_SOC_DAPM_SPK("Ext Spk", NULL),
SND_SOC_DAPM_HP("Headphone Jack", NULL),
};
static const struct snd_soc_dapm_route rk_audio_map[]={
/* Mic Jack --> MIC_IN*/
{"Mic Bias", NULL, "Mic Jack"},
{"MICP", NULL, "Mic Bias"},
{"MICN", NULL, "Mic Bias"},
// HP MIC
{"Mic Bias", NULL, "Headset Jack"},
{"Ext Spk", NULL, "HPOUTR"},
{"Ext Spk", NULL, "HPOUTL"},
{"Headphone Jack", NULL, "HPOUTR"},
{"Headphone Jack", NULL, "HPOUTL"},
} ;
static const struct snd_kcontrol_new rk_controls[] = {
SOC_DAPM_PIN_SWITCH("Mic Jack"),
SOC_DAPM_PIN_SWITCH("Headset Jack"),
SOC_DAPM_PIN_SWITCH("Ext Spk"),
SOC_DAPM_PIN_SWITCH("Headphone Jack"),
};
static int rk3026_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
mutex_lock(&dapm->card->dapm_mutex);
snd_soc_dapm_enable_pin(dapm, "Mic Jack");
snd_soc_dapm_enable_pin(dapm, "Headset Jack");
snd_soc_dapm_enable_pin(dapm, "Ext Spk");
snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
mutex_unlock(&dapm->card->dapm_mutex);
snd_soc_dapm_sync(dapm);
return 0;
}
static int rk_hifi_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int pll_out = 0, dai_fmt = rtd->dai_link->dai_fmt;
int ret;
DBG("Enter::%s----%d\n", __FUNCTION__, __LINE__);
/* set codec DAI configuration */
ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
if (ret < 0) {
printk("%s():failed to set the format for codec side\n", __FUNCTION__);
return ret;
}
/* set cpu DAI configuration */
ret = snd_soc_dai_set_fmt(cpu_dai, dai_fmt);
if (ret < 0) {
printk("%s():failed to set the format for cpu side\n", __FUNCTION__);
return ret;
}
switch(params_rate(params)) {
case 8000:
case 16000:
case 24000:
case 32000:
case 48000:
pll_out = 12288000;
break;
case 11025:
case 22050:
case 44100:
pll_out = 11289600;
break;
default:
DBG("Enter:%s, %d, Error rate=%d\n", __FUNCTION__, __LINE__, params_rate(params));
return -EINVAL;
break;
}
DBG("Enter:%s, %d, rate=%d\n", __FUNCTION__, __LINE__, params_rate(params));
/*Set the system clk for codec*/
ret = snd_soc_dai_set_sysclk(codec_dai, 0, pll_out, SND_SOC_CLOCK_IN);
if (ret < 0) {
DBG("rk_hifi_hw_params:failed to set the sysclk for codec side\n");
return ret;
}
snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK, (pll_out/4)/params_rate(params)-1);
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, 3);
DBG("Enter:%s, %d, pll_out/4/params_rate(params) = %d \n", __FUNCTION__, __LINE__, (pll_out/4)/params_rate(params));
return 0;
}
static int rk_voice_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int pll_out = 0, dai_fmt = rtd->dai_link->dai_fmt;
int ret;
DBG("Enter::%s----%d\n", __FUNCTION__, __LINE__);
/* set codec DAI configuration */
ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
if (ret < 0) {
printk("%s():failed to set the format for codec side\n", __FUNCTION__);
return ret;
}
/* set codec DAI configuration */
ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_A |
SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_CBS_CFS);
switch(params_rate(params)) {
case 8000:
case 16000:
case 24000:
case 32000:
case 48000:
pll_out = 12288000;
break;
case 11025:
case 22050:
case 44100:
pll_out = 11289600;
break;
default:
DBG("Enter:%s, %d, Error rate=%d\n", __FUNCTION__, __LINE__, params_rate(params));
return -EINVAL;
break;
}
/*Set the system clk for codec*/
ret = snd_soc_dai_set_sysclk(codec_dai, 0, pll_out, SND_SOC_CLOCK_IN);
if (ret < 0) {
printk("rk_voice_hw_params:failed to set the sysclk for codec side\n");
return ret;
}
ret = snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
return 0;
}
static struct snd_soc_ops rk3026_hifi_ops = {
.hw_params = rk_hifi_hw_params,
};
static struct snd_soc_ops rk3026_voice_ops = {
.hw_params = rk_voice_hw_params,
};
static struct snd_soc_dai_link rk_dai[] = {
{
.name = "RK3026 I2S1",
.stream_name = "RK3026 PCM",
.codec_dai_name = "rk3026-hifi",
.init = rk3026_init,
.ops = &rk3026_hifi_ops,
},
{
.name = "RK3026 I2S2",
.stream_name = "RK3026 PCM",
.codec_dai_name = "rk3026-voice",
.ops = &rk3026_voice_ops,
},
};
static struct snd_soc_card rockchip_rk3026_snd_card = {
.name = "RK_RK3026",
.dai_link = rk_dai,
.num_links = 2,
.controls = rk_controls,
.num_controls = ARRAY_SIZE(rk_controls),
.dapm_widgets = rk_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(rk_dapm_widgets),
.dapm_routes = rk_audio_map,
.num_dapm_routes = ARRAY_SIZE(rk_audio_map),
};
static int rockchip_rk3026_audio_probe(struct platform_device *pdev)
{
int ret;
struct snd_soc_card *card = &rockchip_rk3026_snd_card;
card->dev = &pdev->dev;
ret = rockchip_of_get_sound_card_info(card);
if (ret) {
printk("%s() get sound card info failed:%d\n", __FUNCTION__, ret);
return ret;
}
ret = snd_soc_register_card(card);
if (ret)
printk("%s() register card failed:%d\n", __FUNCTION__, ret);
return ret;
}
static int rockchip_rk3026_audio_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
snd_soc_unregister_card(card);
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id rockchip_rk3026_of_match[] = {
{ .compatible = "rockchip-rk3026", },
{},
};
MODULE_DEVICE_TABLE(of, rockchip_rk3026_of_match);
#endif /* CONFIG_OF */
static struct platform_driver rockchip_rk3026_audio_driver = {
.driver = {
.name = "rockchip-rk3026",
.owner = THIS_MODULE,
.pm = &snd_soc_pm_ops,
.of_match_table = of_match_ptr(rockchip_rk3026_of_match),
},
.probe = rockchip_rk3026_audio_probe,
.remove = rockchip_rk3026_audio_remove,
};
module_platform_driver(rockchip_rk3026_audio_driver);
/* Module information */
MODULE_AUTHOR("rockchip");
MODULE_DESCRIPTION("ROCKCHIP i2s ASoC Interface");
MODULE_LICENSE("GPL");

View File

@@ -1,173 +0,0 @@
/*
* rk_rk3036codec.c-- SoC audio for rockchip
*
* Driver for rockchip internal rk_rk3036codec audio
*
* 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.
*
*/
#include <linux/module.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include "../codecs/rk3036_codec.h"
#include "card_info.h"
#include "rk_pcm.h"
#include "rk_i2s.h"
#if 0
#define DBG(x...) pr_info("rk_rk3036" x)
#else
#define DBG(x...)
#endif
static int rk30_hw_params(struct snd_pcm_substream *
substream, struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int pll_out = 0, dai_fmt = rtd->dai_link->dai_fmt;
int ret;
DBG("Enter::%s----%d\n", __func__, __LINE__);
/* set codec DAI configuration */
ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
if (ret < 0) {
DBG("%s():failed to set the format for codec side\n",
__func__);
return ret;
}
/* set cpu DAI configuration */
ret = snd_soc_dai_set_fmt(cpu_dai, dai_fmt);
if (ret < 0) {
DBG("%s():failed to set the format for cpu side\n",
__func__);
return ret;
}
switch (params_rate(params)) {
case 8000:
case 16000:
case 24000:
case 32000:
case 48000:
pll_out = 12288000;
break;
case 11025:
case 22050:
case 44100:
pll_out = 11289600;
break;
default:
DBG("Enter:%s, %d, Error rate=%d\n",
__func__, __LINE__, params_rate(params));
return -EINVAL;
break;
}
DBG("Enter:%s, %d, rate=%d\n",
__func__, __LINE__, params_rate(params));
/*Set the system clk for codec*/
ret = snd_soc_dai_set_sysclk(codec_dai, 0, pll_out, SND_SOC_CLOCK_IN);
if (ret < 0) {
DBG("rk_hifi_hw_params:failed to set the sysclk for codec\n");
return ret;
}
snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK,
(pll_out/4)/params_rate(params)-1);
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, 3);
DBG("Enter:%s, %d, pll_out/4/params_rate(params) = %d \n",
__func__, __LINE__, (pll_out/4)/params_rate(params));
return 0;
}
/*
* Logic for a rk3036 codec as connected on a rockchip board.
*/
static int rk30_rk3036_codec_init(struct snd_soc_pcm_runtime *rtd)
{
return 0;
}
static struct snd_soc_ops rk30_ops = {
.hw_params = rk30_hw_params,
};
static struct snd_soc_dai_link rk30_dai[] = {
{
.name = "RK3036",
.stream_name = "RK3036 CODEC PCM",
.codec_dai_name = "rk3036-voice",
.init = rk30_rk3036_codec_init,
.ops = &rk30_ops,
}
};
static struct snd_soc_card rockchip_rk3036_snd_card = {
.name = "RK_RK3036",
.dai_link = rk30_dai,
.num_links = 1,
};
static int rockchip_rk3036_audio_probe(struct platform_device *pdev)
{
int ret;
struct snd_soc_card *card = &rockchip_rk3036_snd_card;
card->dev = &pdev->dev;
ret = rockchip_of_get_sound_card_info(card);
if (ret < 0)
return ret;
ret = snd_soc_register_card(card);
return ret;
}
static int rockchip_rk3036_audio_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
snd_soc_unregister_card(card);
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id rockchip_rk3036_of_match[] = {
{ .compatible = "rk3036-audio", },
{},
};
MODULE_DEVICE_TABLE(of, rockchip_rk3036_of_match);
#endif /* CONFIG_OF */
static struct platform_driver rockchip_rk3036_audio_driver = {
.driver = {
.name = "rk3036-audio",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(rockchip_rk3036_of_match),
},
.probe = rockchip_rk3036_audio_probe,
.remove = rockchip_rk3036_audio_remove,
};
module_platform_driver(rockchip_rk3036_audio_driver);
/* Module information */
MODULE_AUTHOR("rockchip");
MODULE_DESCRIPTION("ROCKCHIP i2s ASoC Interface");
MODULE_LICENSE("GPL");

View File

@@ -1,312 +0,0 @@
/*
* rk_rk312x.c -- SoC audio for rockchip
*
* Driver for rockchip rk312x audio
*
* 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.
*
*
*/
#include <linux/module.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/rockchip/cpu.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include "../codecs/rk312x_codec.h"
#include "card_info.h"
#include "rk_pcm.h"
#include "rk_i2s.h"
#if 0
#define DBG(x...) pr_info("rk_rk312x" x)
#else
#define DBG(x...)
#endif
static const struct snd_soc_dapm_widget rk_dapm_widgets[] = {
SND_SOC_DAPM_MIC("Mic Jack", NULL),
SND_SOC_DAPM_MIC("Headset Jack", NULL),
SND_SOC_DAPM_SPK("Ext Spk", NULL),
SND_SOC_DAPM_HP("Headphone Jack", NULL),
};
static const struct snd_soc_dapm_route rk_audio_map[] = {
/* Mic Jack --> MIC_IN*/
{"Mic Bias", NULL, "Mic Jack"},
{"MICP", NULL, "Mic Bias"},
{"MICN", NULL, "Mic Bias"},
/* HP MIC */
{"Mic Bias", NULL, "Headset Jack"},
{"Ext Spk", NULL, "HPOUTR"},
{"Ext Spk", NULL, "HPOUTL"},
{"Headphone Jack", NULL, "HPOUTR"},
{"Headphone Jack", NULL, "HPOUTL"},
};
static const struct snd_kcontrol_new rk_controls[] = {
SOC_DAPM_PIN_SWITCH("Mic Jack"),
SOC_DAPM_PIN_SWITCH("Headset Jack"),
SOC_DAPM_PIN_SWITCH("Ext Spk"),
SOC_DAPM_PIN_SWITCH("Headphone Jack"),
};
static int rk312x_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
DBG("Enter::%s----%d\n", __func__, __LINE__);
mutex_lock(&dapm->card->dapm_mutex);
snd_soc_dapm_enable_pin(dapm, "Mic Jack");
snd_soc_dapm_enable_pin(dapm, "Headset Jack");
snd_soc_dapm_enable_pin(dapm, "Ext Spk");
snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
mutex_unlock(&dapm->card->dapm_mutex);
snd_soc_dapm_sync(dapm);
return 0;
}
static int rk_hifi_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int pll_out = 0, dai_fmt = rtd->dai_link->dai_fmt;
int ret;
DBG("Enter::%s----%d\n", __func__, __LINE__);
/* set codec DAI configuration */
ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
if (ret < 0) {
DBG("%s():failed to set the format for codec side\n",
__func__);
return ret;
}
/* set cpu DAI configuration */
ret = snd_soc_dai_set_fmt(cpu_dai, dai_fmt);
if (ret < 0) {
DBG("%s():failed to set the format for cpu side\n",
__func__);
return ret;
}
switch (params_rate(params)) {
case 8000:
case 16000:
case 24000:
case 32000:
case 48000:
pll_out = 12288000;
break;
case 11025:
case 22050:
case 44100:
pll_out = 11289600;
break;
default:
DBG("Enter:%s, %d, Error rate=%d\n",
__func__, __LINE__, params_rate(params));
return -EINVAL;
break;
}
DBG("Enter:%s, %d, rate=%d\n",
__func__, __LINE__, params_rate(params));
/*Set the system clk for codec*/
ret = snd_soc_dai_set_sysclk(codec_dai, 0, pll_out, SND_SOC_CLOCK_IN);
if (ret < 0) {
DBG("rk_hifi_hw_params:failed to set the sysclk for codec\n");
return ret;
}
snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK,
(pll_out/4)/params_rate(params)-1);
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, 3);
DBG("Enter:%s, %d, pll_out/4/params_rate(params) = %d \n",
__func__, __LINE__, (pll_out/4)/params_rate(params));
return 0;
}
static int rk_voice_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int pll_out = 0, dai_fmt = rtd->dai_link->dai_fmt;
int ret;
DBG("Enter::%s----%d\n", __func__, __LINE__);
/* set codec DAI configuration */
ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
if (ret < 0) {
DBG("%s():failed to set the format for codec side\n",
__func__);
return ret;
}
/* set codec DAI configuration */
ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_A |
SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_CBS_CFS);
switch (params_rate(params)) {
case 8000:
case 16000:
case 24000:
case 32000:
case 48000:
pll_out = 12288000;
break;
case 11025:
case 22050:
case 44100:
pll_out = 11289600;
break;
default:
DBG("Enter:%s, %d, Error rate=%d\n",
__func__, __LINE__,
params_rate(params));
return -EINVAL;
break;
}
/*Set the system clk for codec*/
ret = snd_soc_dai_set_sysclk(codec_dai, 0, pll_out, SND_SOC_CLOCK_IN);
if (ret < 0) {
DBG("rk_voice_hw_params:failed to set codec side\n");
return ret;
}
ret = snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
return 0;
}
static struct snd_soc_ops rk312x_hifi_ops = {
.hw_params = rk_hifi_hw_params,
};
static struct snd_soc_ops rk312x_voice_ops = {
.hw_params = rk_voice_hw_params,
};
static struct snd_soc_dai_link rk_dai[] = {
{
.name = "RK312X I2S1",
.stream_name = "RK312X PCM",
.codec_dai_name = "rk312x-hifi",
.init = rk312x_init,
.ops = &rk312x_hifi_ops,
},
{
.name = "RK312X I2S2",
.stream_name = "RK312X PCM",
.codec_dai_name = "rk312x-voice",
.ops = &rk312x_voice_ops,
},
};
static struct snd_soc_card rockchip_rk312x_snd_card = {
.name = "RK_RK312X",
.dai_link = rk_dai,
.num_links = 2,
.controls = rk_controls,
.num_controls = ARRAY_SIZE(rk_controls),
.dapm_widgets = rk_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(rk_dapm_widgets),
.dapm_routes = rk_audio_map,
.num_dapm_routes = ARRAY_SIZE(rk_audio_map),
};
static int rockchip_rk312x_audio_probe(struct platform_device *pdev)
{
int ret;
struct snd_soc_card *card = &rockchip_rk312x_snd_card;
card->dev = &pdev->dev;
ret = rockchip_of_get_sound_card_info(card);
if (ret) {
DBG("%s() get sound card info failed:%d\n", __func__, ret);
return ret;
}
/* rk3126b workaround remap cpu dai node */
if (soc_is_rk3126b()) {
int i;
struct device_node *cpu_dai_node;
cpu_dai_node = of_find_node_by_name(NULL, "i2s0");
for (i = 0; i < card->num_links; i++) {
card->dai_link[i].cpu_of_node = cpu_dai_node;
card->dai_link[i].platform_of_node = cpu_dai_node;
}
}
ret = snd_soc_register_card(card);
if (ret)
DBG("%s() register card failed:%d\n", __func__, ret);
return ret;
}
static int rockchip_rk312x_audio_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
snd_soc_unregister_card(card);
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id rockchip_rk312x_of_match[] = {
{ .compatible = "audio-rk312x", },
{},
};
MODULE_DEVICE_TABLE(of, rockchip_rk312x_of_match);
#endif /* CONFIG_OF */
static struct platform_driver rockchip_rk312x_audio_driver = {
.driver = {
.name = "audio-rk312x",
.owner = THIS_MODULE,
.pm = &snd_soc_pm_ops,
.of_match_table = of_match_ptr(rockchip_rk312x_of_match),
},
.probe = rockchip_rk312x_audio_probe,
.remove = rockchip_rk312x_audio_remove,
};
module_platform_driver(rockchip_rk312x_audio_driver);
/* Module information */
MODULE_AUTHOR("rockchip");
MODULE_DESCRIPTION("ROCKCHIP i2s ASoC Interface");
MODULE_LICENSE("GPL");

View File

@@ -1,269 +0,0 @@
/*
* rk_rk3190.c -- SoC audio for rockchip
*
* Driver for rockchip rk3190 audio
*
* 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.
*
*
*/
#include <linux/module.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include "../codecs/rk3190_codec.h"
#include "card_info.h"
#include "rk_pcm.h"
#include "rk_i2s.h"
#if 0
#define DBG(x...) printk(KERN_INFO x)
#else
#define DBG(x...)
#endif
#if 0
static const struct snd_soc_dapm_widget rk_dapm_widgets[] = {
SND_SOC_DAPM_MIC("Mic Jack", NULL),
SND_SOC_DAPM_MIC("Headset Jack", NULL),
SND_SOC_DAPM_SPK("Ext Spk", NULL),
SND_SOC_DAPM_HP("Headphone Jack", NULL),
};
static const struct snd_soc_dapm_route rk_audio_map[]={
/* Mic Jack --> MIC_IN*/
{"Mic Bias", NULL, "Mic Jack"},
{"MICP", NULL, "Mic Bias"},
{"MICN", NULL, "Mic Bias"},
// HP MIC
{"Mic Bias", NULL, "Headset Jack"},
{"Ext Spk", NULL, "HPOUTR"},
{"Ext Spk", NULL, "HPOUTL"},
{"Headphone Jack", NULL, "HPOUTR"},
{"Headphone Jack", NULL, "HPOUTL"},
} ;
static const struct snd_kcontrol_new rk_controls[] = {
SOC_DAPM_PIN_SWITCH("Mic Jack"),
SOC_DAPM_PIN_SWITCH("Headset Jack"),
SOC_DAPM_PIN_SWITCH("Ext Spk"),
SOC_DAPM_PIN_SWITCH("Headphone Jack"),
};
#endif
static int rk3190_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
return 0;
}
static int rk_hifi_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int pll_out = 0, dai_fmt = rtd->dai_link->dai_fmt;
int ret;
DBG("Enter::%s----%d\n", __FUNCTION__, __LINE__);
/* set codec DAI configuration */
ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
if (ret < 0) {
printk("%s():failed to set the format for codec side\n", __FUNCTION__);
return ret;
}
/* set cpu DAI configuration */
ret = snd_soc_dai_set_fmt(cpu_dai, dai_fmt);
if (ret < 0) {
printk("%s():failed to set the format for cpu side\n", __FUNCTION__);
return ret;
}
switch(params_rate(params)) {
case 8000:
case 16000:
case 24000:
case 32000:
case 48000:
pll_out = 12288000;
break;
case 11025:
case 22050:
case 44100:
pll_out = 11289600;
break;
default:
DBG("Enter:%s, %d, Error rate=%d\n", __FUNCTION__, __LINE__, params_rate(params));
return -EINVAL;
break;
}
DBG("Enter:%s, %d, rate=%d\n", __FUNCTION__, __LINE__, params_rate(params));
/*Set the system clk for codec*/
ret = snd_soc_dai_set_sysclk(codec_dai, 0, pll_out, SND_SOC_CLOCK_IN);
if (ret < 0) {
DBG("rk_hifi_hw_params:failed to set the sysclk for codec side\n");
return ret;
}
snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK, (pll_out/4)/params_rate(params)-1);
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, 3);
DBG("Enter:%s, %d, pll_out/4/params_rate(params) = %d \n", __FUNCTION__, __LINE__, (pll_out/4)/params_rate(params));
return 0;
}
static int rk_voice_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int pll_out = 0, dai_fmt = rtd->dai_link->dai_fmt;
int ret;
DBG("Enter::%s----%d\n", __FUNCTION__, __LINE__);
/* set codec DAI configuration */
ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
if (ret < 0) {
printk("%s():failed to set the format for codec side\n", __FUNCTION__);
return ret;
}
switch(params_rate(params)) {
case 8000:
case 16000:
case 24000:
case 32000:
case 48000:
pll_out = 12288000;
break;
case 11025:
case 22050:
case 44100:
pll_out = 11289600;
break;
default:
DBG("Enter:%s, %d, Error rate=%d\n", __FUNCTION__, __LINE__, params_rate(params));
return -EINVAL;
break;
}
/*Set the system clk for codec*/
ret = snd_soc_dai_set_sysclk(codec_dai, 0, pll_out, SND_SOC_CLOCK_IN);
if (ret < 0) {
printk("rk_voice_hw_params:failed to set the sysclk for codec side\n");
return ret;
}
ret = snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
return 0;
}
static struct snd_soc_ops rk3190_hifi_ops = {
.hw_params = rk_hifi_hw_params,
};
static struct snd_soc_ops rk3190_voice_ops = {
.hw_params = rk_voice_hw_params,
};
static struct snd_soc_dai_link rk_dai[] = {
{
.name = "RK3190 I2S1",
.stream_name = "RK3190 PCM",
.codec_dai_name = "rk3190-hifi",
.init = rk3190_init,
.ops = &rk3190_hifi_ops,
},
{
.name = "RK3190 I2S2",
.stream_name = "RK3190 PCM",
.codec_dai_name = "rk3190-voice",
.ops = &rk3190_voice_ops,
},
};
static struct snd_soc_card rockchip_rk3190_snd_card = {
.name = "RK_RK3190",
.dai_link = rk_dai,
.num_links = 2,
};
static int rockchip_rk3190_audio_probe(struct platform_device *pdev)
{
int ret;
struct snd_soc_card *card = &rockchip_rk3190_snd_card;
card->dev = &pdev->dev;
ret = rockchip_of_get_sound_card_info(card);
if (ret) {
printk("%s() get sound card info failed:%d\n", __FUNCTION__, ret);
return ret;
}
ret = snd_soc_register_card(card);
if (ret)
printk("%s() register card failed:%d\n", __FUNCTION__, ret);
return ret;
}
static int rockchip_rk3190_audio_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
snd_soc_unregister_card(card);
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id rockchip_rk3190_of_match[] = {
{ .compatible = "rockchip-rk3190", },
{},
};
MODULE_DEVICE_TABLE(of, rockchip_rk3190_of_match);
#endif /* CONFIG_OF */
static struct platform_driver rockchip_rk3190_audio_driver = {
.driver = {
.name = "rockchip-rk3190",
.owner = THIS_MODULE,
.pm = &snd_soc_pm_ops,
.of_match_table = of_match_ptr(rockchip_rk3190_of_match),
},
.probe = rockchip_rk3190_audio_probe,
.remove = rockchip_rk3190_audio_remove,
};
module_platform_driver(rockchip_rk3190_audio_driver);
/* Module information */
MODULE_AUTHOR("rockchip");
MODULE_DESCRIPTION("ROCKCHIP i2s ASoC Interface");
MODULE_LICENSE("GPL");

View File

@@ -1,382 +0,0 @@
/*
* rk_rk616.c -- SoC audio for rockchip
*
* Driver for rockchip rk616 audio
*
* 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.
*
*
*/
#include <linux/module.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include "../codecs/rk616_codec.h"
#include "card_info.h"
#include "rk_pcm.h"
#include "rk_i2s.h"
#if 1
#define DBG(x...) pr_info(x)
#else
#define DBG(x...)
#endif
static bool get_hdmi_state(void)
{
#ifdef CONFIG_HDMI
if (hdmi_is_insert())
return true;
#endif
#ifdef CONFIG_HDMI_RK30
/*HDMI_HPD_ACTIVED*/
if (hdmi_get_hotplug() == 2)
return true;
#endif
return false;
}
static const struct snd_soc_dapm_widget rk_rk616_dapm_widgets[] = {
SND_SOC_DAPM_MIC("Mic Jack", NULL),
SND_SOC_DAPM_MIC("Headset Jack", NULL),
SND_SOC_DAPM_SPK("Ext Spk", NULL),
SND_SOC_DAPM_HP("Headphone Jack", NULL),
};
static const struct snd_soc_dapm_route rk_rk616_audio_map[] = {
/* Mic Jack --> MIC_IN*/
{"Mic1 Bias", NULL, "Mic Jack"},
{"MIC1P", NULL, "Mic1 Bias"},
{"MIC1N", NULL, "Mic1 Bias"},
/* HP MIC */
{"Mic2 Bias", NULL, "Headset Jack"},
{"MIC2P", NULL, "Mic2 Bias"},
{"MIC2N", NULL, "Mic2 Bias"},
{"Ext Spk", NULL, "SPKOUTR"},
{"Ext Spk", NULL, "SPKOUTL"},
{"Headphone Jack", NULL, "HPOUTR"},
{"Headphone Jack", NULL, "HPOUTL"},
};
static const struct snd_kcontrol_new rk_rk616_controls[] = {
SOC_DAPM_PIN_SWITCH("Mic Jack"),
SOC_DAPM_PIN_SWITCH("Headset Jack"),
SOC_DAPM_PIN_SWITCH("Ext Spk"),
SOC_DAPM_PIN_SWITCH("Headphone Jack"),
};
static int rk616_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
/*
* if is for mid that using tiny alsa,
* it don't need this controls and route, so return.
*/
if (rk616_get_for_mid())
return 0;
DBG("%s() %d\n", __func__, __LINE__);
mutex_lock(&dapm->card->dapm_mutex);
snd_soc_dapm_enable_pin(dapm, "Mic Jack");
snd_soc_dapm_enable_pin(dapm, "Headset Jack");
snd_soc_dapm_enable_pin(dapm, "Ext Spk");
snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
mutex_unlock(&dapm->card->dapm_mutex);
snd_soc_dapm_sync(dapm);
return 0;
}
static int rk_hifi_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int pll_out = 0, div = 4, dai_fmt = rtd->dai_link->dai_fmt;
int ret;
DBG("%s() %d\n", __func__, __LINE__);
/* set codec DAI configuration */
ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
if (ret < 0) {
pr_err("%s():failed to set the format for codec side\n",
__func__);
return ret;
}
/* set cpu DAI configuration */
ret = snd_soc_dai_set_fmt(cpu_dai, dai_fmt);
if (ret < 0) {
pr_err("%s():failed to set the format for cpu side\n",
__func__);
return ret;
}
switch (params_rate(params)) {
case 16000:
case 24000:
case 32000:
case 48000:
pll_out = 12288000;
break;
case 11025:
case 22050:
case 44100:
pll_out = 11289600;
break;
case 8000:
pll_out = 12000000;
div = 6;
break;
default:
DBG("Enter:%s, %d, Error rate=%d\n",
__func__, __LINE__,
params_rate(params));
return -EINVAL;
break;
}
DBG("Enter:%s, %d, rate=%d\n",
__func__, __LINE__,
params_rate(params));
#if defined(CONFIG_RK616_USE_MCLK_12M)
/* MCLK must be 12M when RK616 HDMI is in */
if (get_hdmi_state() && pll_out != 12000000) {
DBG("%s : HDMI is in, don't set sys clk %u\n",
__func__, pll_out);
goto __setdiv;
}
#endif
/* Set the system clk for codec
mclk will be setted in set_sysclk of codec_dai*/
ret = snd_soc_dai_set_sysclk(codec_dai, 0,
pll_out, SND_SOC_CLOCK_IN);
if (ret < 0) {
DBG("%s : failed to set the sysclk for codec side\n",
__func__);
return ret;
}
#if defined(CONFIG_RK616_USE_MCLK_12M)
__setdiv:
#endif
snd_soc_dai_set_clkdiv(cpu_dai,
ROCKCHIP_DIV_BCLK,
(pll_out / div)/params_rate(params)-1);
snd_soc_dai_set_clkdiv(cpu_dai,
ROCKCHIP_DIV_MCLK, div - 1);
DBG("Enter:%s, %d, pll_out/div/params_rate(params) = %d\n",
__func__, __LINE__, (pll_out/div)/params_rate(params));
return 0;
}
static int rk_voice_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int pll_out = 0, dai_fmt = rtd->dai_link->dai_fmt;
int ret;
DBG("%s() %d\n", __func__, __LINE__);
/* set codec DAI configuration */
ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
if (ret < 0) {
pr_err("rk_voice_hw_params:failed to set the format for codec side\n");
return ret;
}
switch (params_rate(params)) {
case 8000:
case 16000:
case 24000:
case 32000:
case 48000:
pll_out = 12288000;
break;
case 11025:
case 22050:
case 44100:
pll_out = 11289600;
break;
default:
DBG("Enter:%s, %d, Error rate=%d\n",
__func__, __LINE__,
params_rate(params));
return -EINVAL;
break;
}
/* MCLK must be 12M when RK616 HDMI is in */
#if defined(CONFIG_RK616_USE_MCLK_12M)
if (get_hdmi_state() && pll_out != 12000000) {
DBG("%s : HDMI is in, set mclk to 12Mn", __func__);
pll_out = 12000000;
}
#endif
/*Set the system clk for codec*/
ret = snd_soc_dai_set_sysclk(codec_dai, 0,
pll_out, SND_SOC_CLOCK_IN);
if (ret < 0) {
pr_err("rk_voice_hw_params:failed to set the sysclk for codec side\n");
return ret;
}
ret = snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
if (ret < 0) {
pr_err("rk_voice_hw_params:failed to set the sysclk for cpu side\n");
return ret;
}
return 0;
}
static struct snd_soc_ops rk616_hifi_ops = {
.hw_params = rk_hifi_hw_params,
};
static struct snd_soc_ops rk616_voice_ops = {
.hw_params = rk_voice_hw_params,
};
static struct snd_soc_dai_link rk_dai[] = {
{
.name = "RK616 I2S1",
.stream_name = "RK616 PCM",
.codec_dai_name = "rk616-hifi",
.init = rk616_init,
.ops = &rk616_hifi_ops,
},
{
.name = "RK616 I2S2",
.stream_name = "RK616 PCM",
.codec_dai_name = "rk616-voice",
.ops = &rk616_voice_ops,
},
};
static struct snd_soc_card rockchip_rk616_snd_card = {
.name = "RK_RK616",
.dai_link = rk_dai,
.num_links = 2,
.controls = rk_rk616_controls,
.num_controls = ARRAY_SIZE(rk_rk616_controls),
.dapm_widgets = rk_rk616_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(rk_rk616_dapm_widgets),
.dapm_routes = rk_rk616_audio_map,
.num_dapm_routes = ARRAY_SIZE(rk_rk616_audio_map),
};
/*
* dts:
* rockchip-rk616 {
* compatible = "rockchip-rk616";
* dais {
* dai0 {
* audio-codec = <&rk616>;
* audio-controller = <&i2s0>;
* format = "i2s";
* //continuous-clock;
* //bitclock-inversion;
* //frame-inversion;
* //bitclock-master;
* //frame-master;
* };
*
* dai1 {
* audio-codec = <&rk616>;
* audio-controller = <&i2s0>;
* format = "dsp_a";
* //continuous-clock;
* bitclock-inversion;
* //frame-inversion;
* //bitclock-master;
* //frame-master;
* };
* };
* };
*/
static int rockchip_rk616_audio_probe(struct platform_device *pdev)
{
int ret;
struct snd_soc_card *card = &rockchip_rk616_snd_card;
card->dev = &pdev->dev;
ret = rockchip_of_get_sound_card_info(card);
if (ret) {
pr_err("%s() get sound card info failed:%d\n",
__func__, ret);
return ret;
}
ret = snd_soc_register_card(card);
if (ret)
pr_err("%s() register card failed:%d\n",
__func__, ret);
return ret;
}
static int rockchip_rk616_audio_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
snd_soc_unregister_card(card);
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id rockchip_rk616_of_match[] = {
{ .compatible = "rockchip-rk616", },
{},
};
MODULE_DEVICE_TABLE(of, rockchip_rk616_of_match);
#endif /* CONFIG_OF */
static struct platform_driver rockchip_rk616_audio_driver = {
.driver = {
.name = "rockchip-rk616",
.owner = THIS_MODULE,
.pm = &snd_soc_pm_ops,
.of_match_table = of_match_ptr(rockchip_rk616_of_match),
},
.probe = rockchip_rk616_audio_probe,
.remove = rockchip_rk616_audio_remove,
};
module_platform_driver(rockchip_rk616_audio_driver);
/* Module information */
MODULE_AUTHOR("rockchip");
MODULE_DESCRIPTION("ROCKCHIP i2s ASoC Interface");
MODULE_LICENSE("GPL");

View File

@@ -1,337 +0,0 @@
/*
* rk29_rt3261.c -- SoC audio for rockchip
*
* Driver for rockchip rt3261 audio
*
* 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.
*
*
*/
#include <linux/module.h>
#include <linux/device.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <asm/io.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include "../codecs/rt3261.h"
#include "card_info.h"
#include "rk_pcm.h"
#include "rk_i2s.h"
#if 0
#define DBG(x...) printk(KERN_INFO x)
#else
#define DBG(x...)
#endif
static int rockchip_rt3261_hifi_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int pll_out = 0, dai_fmt = rtd->dai_link->dai_fmt;
int ret;
DBG("Enter::%s----%d\n", __FUNCTION__, __LINE__);
/* set codec DAI configuration */
ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
if (ret < 0) {
printk("%s():failed to set the format for codec side\n", __FUNCTION__);
return ret;
}
/* set cpu DAI configuration */
ret = snd_soc_dai_set_fmt(cpu_dai, dai_fmt);
if (ret < 0) {
printk("%s():failed to set the format for cpu side\n", __FUNCTION__);
return ret;
}
switch(params_rate(params)) {
case 8000:
case 16000:
case 24000:
case 32000:
case 48000:
pll_out = 12288000;
break;
case 11025:
case 22050:
case 44100:
pll_out = 11289600;
break;
default:
DBG("Enter:%s, %d, Error rate=%d\n", __FUNCTION__, __LINE__, params_rate(params));
return -EINVAL;
break;
}
DBG("Enter:%s, %d, rate=%d\n", __FUNCTION__, __LINE__, params_rate(params));
/*Set the system clk for codec*/
snd_soc_dai_set_pll(codec_dai, 0, RT3261_PLL1_S_MCLK, pll_out, pll_out*2); //bard 8-29
ret = snd_soc_dai_set_sysclk(codec_dai, RT3261_SCLK_S_PLL1, pll_out*2, SND_SOC_CLOCK_IN); //bard 8-29
if (ret < 0)
{
DBG("rk29_hw_params_rt3261:failed to set the sysclk for codec side\n");
return ret;
}
snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK, (pll_out/4)/params_rate(params)-1);
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, 3);// 256k = 48-1 3M=3
DBG("Enter:%s, %d, pll_out/4/params_rate(params) = %d \n", __FUNCTION__, __LINE__, (pll_out/4)/params_rate(params));
return 0;
}
static int rockchip_rt3261_voice_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int pll_out = 0, dai_fmt = rtd->dai_link->dai_fmt;
int ret;
DBG("Enter::%s----%d\n", __FUNCTION__, __LINE__);
/* set codec DAI configuration */
ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
if (ret < 0) {
printk("%s():failed to set the format for codec side\n", __FUNCTION__);
return ret;
}
switch(params_rate(params)) {
case 8000:
case 16000:
case 24000:
case 32000:
case 48000:
pll_out = 12288000;
break;
case 11025:
case 22050:
case 44100:
pll_out = 11289600;
break;
default:
DBG("Enter:%s, %d, Error rate=%d\n", __FUNCTION__, __LINE__, params_rate(params));
return -EINVAL;
break;
}
DBG("Enter:%s, %d, rate=%d\n", __FUNCTION__, __LINE__, params_rate(params));
/*Set the system clk for codec*/
snd_soc_dai_set_pll(codec_dai, 0, RT3261_PLL1_S_MCLK, pll_out, pll_out*2); //bard 8-29
ret = snd_soc_dai_set_sysclk(codec_dai, RT3261_SCLK_S_PLL1, pll_out*2, SND_SOC_CLOCK_IN); //bard 8-29
if (ret < 0) {
printk("rk29_hw_params_rt3261:failed to set the sysclk for codec side\n");
return ret;
}
snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
//snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK, (pll_out/4)/params_rate(params)-1);
//snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, 3);
DBG("Enter:%s, %d, pll_out/4/params_rate(params) = %d \n", __FUNCTION__, __LINE__, (pll_out/4)/params_rate(params));
return 0;
}
static const struct snd_soc_dapm_widget rockchip_rt3261_dapm_widgets[] = {
SND_SOC_DAPM_MIC("Mic Jack", NULL),
SND_SOC_DAPM_MIC("Headset Jack", NULL),
SND_SOC_DAPM_SPK("Ext Spk", NULL),
SND_SOC_DAPM_HP("Headphone Jack", NULL),
};
static const struct snd_soc_dapm_route audio_map[]={
/* Mic Jack --> MIC_IN*/
{"micbias1", NULL, "Mic Jack"},
{"MIC1", NULL, "micbias1"},
// HP MIC
{"micbias1", NULL, "Headset Jack"},
{"MIC3", NULL, "micbias1"},
{"Ext Spk", NULL, "SPOLP"},
{"Ext Spk", NULL, "SPOLN"},
{"Ext Spk", NULL, "SPORP"},
{"Ext Spk", NULL, "SPORN"},
{"Headphone Jack", NULL, "HPOL"},
{"Headphone Jack", NULL, "HPOR"},
} ;
static const struct snd_kcontrol_new rockchip_rt3261_controls[] = {
SOC_DAPM_PIN_SWITCH("Mic Jack"),
SOC_DAPM_PIN_SWITCH("Headset Jack"),
SOC_DAPM_PIN_SWITCH("Ext Spk"),
SOC_DAPM_PIN_SWITCH("Headphone Jack"),
};
/*
* Logic for a rt3261 as connected on a rockchip board.
*/
static int rockchip_rt3261_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
mutex_lock(&dapm->card->dapm_mutex);
snd_soc_dapm_enable_pin(dapm, "Mic Jack");
snd_soc_dapm_enable_pin(dapm, "Headset Jack");
snd_soc_dapm_enable_pin(dapm, "Ext Spk");
snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
mutex_unlock(&dapm->card->dapm_mutex);
snd_soc_dapm_sync(dapm);
return 0;
}
static struct snd_soc_ops rockchip_rt3261_hifi_ops = {
.hw_params = rockchip_rt3261_hifi_hw_params,
};
static struct snd_soc_ops rockchip_rt3261_voice_ops = {
.hw_params = rockchip_rt3261_voice_hw_params,
};
static struct snd_soc_dai_link rockchip_rt3261_dai[] = {
{
.name = "RT3261 I2S1",
.stream_name = "RT3261 PCM1",
.codec_dai_name = "rt3261-aif1",
.init = rockchip_rt3261_init,
.ops = &rockchip_rt3261_hifi_ops,
},
{
.name = "RT3261 I2S2",
.stream_name = "RT3261 PCM2",
.codec_dai_name = "rt3261-aif2",
.ops = &rockchip_rt3261_voice_ops,
},
};
static struct snd_soc_card rockchip_rt3261_snd_card = {
#if defined (CONFIG_SND_SOC_RT3224)
.name = "RK_RT3224",
#else
.name = "RK_RT3261",
#endif
.owner = THIS_MODULE,
.dai_link = rockchip_rt3261_dai,
.num_links = ARRAY_SIZE(rockchip_rt3261_dai),
.controls = rockchip_rt3261_controls,
.num_controls = ARRAY_SIZE(rockchip_rt3261_controls),
.dapm_widgets = rockchip_rt3261_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(rockchip_rt3261_dapm_widgets),
.dapm_routes = audio_map,
.num_dapm_routes = ARRAY_SIZE(audio_map),
};
/*
dts:
rockchip-rt3261 {
compatible = "rockchip-rt3261";
dais {
dai0 {
audio-codec = <&rt3261>;
audio-controller = <&i2s0>;
format = "i2s";
//continuous-clock;
//bitclock-inversion;
//frame-inversion;
//bitclock-master;
//frame-master;
};
dai1 {
audio-codec = <&rt3261>;
audio-controller = <&i2s0>;
format = "dsp_a";
//continuous-clock;
bitclock-inversion;
//frame-inversion;
//bitclock-master;
//frame-master;
};
};
};
*/
static int rockchip_rt3261_audio_probe(struct platform_device *pdev)
{
int ret;
struct snd_soc_card *card = &rockchip_rt3261_snd_card;
card->dev = &pdev->dev;
ret = rockchip_of_get_sound_card_info(card);
if (ret) {
printk("%s() get sound card info failed:%d\n", __FUNCTION__, ret);
return ret;
}
ret = snd_soc_register_card(card);
if (ret)
printk("%s() register card failed:%d\n", __FUNCTION__, ret);
return ret;
}
static int rockchip_rt3261_audio_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
snd_soc_unregister_card(card);
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id rockchip_rt3261_of_match[] = {
{ .compatible = "rockchip-rt3261", },
{},
};
MODULE_DEVICE_TABLE(of, rockchip_rt3261_of_match);
#endif /* CONFIG_OF */
static struct platform_driver rockchip_rt3261_audio_driver = {
.driver = {
.name = "rockchip-rt3261",
.owner = THIS_MODULE,
.pm = &snd_soc_pm_ops,
.of_match_table = of_match_ptr(rockchip_rt3261_of_match),
},
.probe = rockchip_rt3261_audio_probe,
.remove = rockchip_rt3261_audio_remove,
};
module_platform_driver(rockchip_rt3261_audio_driver);
/* Module information */
MODULE_AUTHOR("rockchip");
MODULE_DESCRIPTION("ROCKCHIP i2s ASoC Interface");
MODULE_LICENSE("GPL");

View File

@@ -1,344 +0,0 @@
/*
* odroid_rt5512.c
*
* 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.
*/
#include <linux/module.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/jack.h>
#include <linux/delay.h>
#include "card_info.h"
#include "rk_pcm.h"
#include "rk_i2s.h"
#if 1
#define DBG(x...) printk(KERN_INFO x)
#else
#define DBG(x...)
#endif
#include "../codecs/rt5512.h"
static struct platform_device *rk29_snd_device;
static int rk29_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int pll_out = 0;
unsigned int pll_div, dai_fmt = rtd->dai_link->dai_fmt;
int ret;
DBG("Enter::%s----%d\n", __FUNCTION__, __LINE__);
/* set codec DAI configuration */
ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
if (ret < 0) {
printk("%s():failed to set the format for codec side\n", __FUNCTION__);
return ret;
}
/* set cpu DAI configuration */
ret = snd_soc_dai_set_fmt(cpu_dai, dai_fmt);
if (ret < 0) {
printk("%s():failed to set the format for cpu side\n", __FUNCTION__);
return ret;
}
switch(params_rate(params)) {
case 8000:
case 16000:
case 24000:
case 32000:
case 48000:
pll_out = 12288000;
break;
case 11025:
case 22050:
case 44100:
pll_out = 11289600;
break;
case 96000:
case 192000:
pll_out = 12288000*2;
break;
case 88200:
case 176400:
pll_out = 11289600*2;
break;
default:
DBG("Enter:%s, %d, Error rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
return -EINVAL;
break;
}
if ((dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFM)
goto skip__;
snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK, 64-1);//bclk = 2*32*lrck; 2*32fs
switch(params_rate(params)) {
case 176400:
case 192000:
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, 1);
DBG("Enter:%s, %d, MCLK=%d BCLK=%d LRCK=%d\n",
__FUNCTION__,__LINE__,pll_out,pll_out/2,params_rate(params));
break;
default:
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, 3);
DBG("default:%s, %d, MCLK=%d BCLK=%d LRCK=%d\n",
__FUNCTION__,__LINE__,pll_out,pll_out/4,params_rate(params));
break;
}
/*Set the system clk for codec*/
ret=snd_soc_dai_set_sysclk(codec_dai, 0,pll_out,SND_SOC_CLOCK_IN);
if (ret < 0)
{
DBG("rk29_hw_params_rt5512:failed to set the sysclk for codec side\n");
return ret;
}
switch (params_rate(params))
{
case 8000:
pll_div = 12;
break;
case 16000:
pll_div = 6;
break;
case 32000:
pll_div = 3;
break;
case 48000:
pll_div = 2;
break;
case 96000:
pll_div = 1;
break;
case 11025:
pll_div = 8;
break;
case 22050:
pll_div = 4;
break;
case 44100:
pll_div = 2;
break;
case 88200:
pll_div = 1;
break;
default:
printk("Not yet supported!\n");
return -EINVAL;
}
ret = snd_soc_dai_set_clkdiv(codec_dai, RT5512_CLK_DIV_ID, pll_div*4);
if (ret < 0)
return ret;
skip__:
if ((dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFM)
snd_soc_dai_set_sysclk(codec_dai,0,pll_out, SND_SOC_CLOCK_IN);
return 0;
}
//---------------------------------------------------------------------------------
/*
* rt5512 DAI operations.
*/
static struct snd_soc_ops rk29_ops = {
.hw_params = rk29_hw_params,
};
static const struct snd_soc_dapm_widget rt5512_dapm_widgets[] = {
// Input
SND_SOC_DAPM_MIC("Main Mic", NULL),
SND_SOC_DAPM_LINE("LineIn", NULL),
// Output
SND_SOC_DAPM_SPK("Ext Spk", NULL),
SND_SOC_DAPM_HP("Headphone Jack", NULL),
};
static const struct snd_soc_dapm_route rt5512_audio_map[] = {
// Input
{"MicBias1", NULL,"Main Mic"},
{"Mic2", NULL, "MicBias1"},
{"MicBias2", NULL, "LineIn"},
{"Aux", NULL, "MicBias2"},
// Output
{"Ext Spk", NULL, "LSpeaker"},
{"Ext Spk", NULL, "RSpeaker"},
{"Headphone Jack", NULL, "LHeadphone"},
{"Headphone Jack", NULL, "RHeadphone"},
};
#if 0
static struct snd_soc_jack rk29_soc_jack;
static struct snd_soc_jack_gpio odroid_soc_jack_gpio[] = {
{
.gpio = 28,
.name "headset event",
.report = SND_JACK_HEADSET,
.debounce_time = 200,
},
};
#endif
#if 0
static int rt5512_headset_keys(struct snd_soc_jack *jack)
{
int err = 0;
err = snd_jack_set_key(jack->jack, SND_JACK_BTN_0, 0x80);
if (err)
return err;
err = snd_jack_set_key(jack->jack, SND_JACK_BTN_1, 0x81);
if (err)
return err;
err = snd_jack_set_key(jack->jack, SND_JACK_BTN_2, 0x82);
if (err)
return err;
return 0;
}
#endif
static int rt5512_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
//struct rt5512_codec_chip *chip = snd_soc_codec_get_drvdata(codec);
//int err = 0;
snd_soc_dapm_new_controls(dapm, rt5512_dapm_widgets,
ARRAY_SIZE(rt5512_dapm_widgets));
snd_soc_dapm_add_routes(dapm, rt5512_audio_map,
ARRAY_SIZE(rt5512_audio_map));
#if FOR_MID
snd_soc_dapm_disable_pin(dapm, "Main Mic");
snd_soc_dapm_disable_pin(dapm, "LineIn");
snd_soc_dapm_disable_pin(dapm, "Ext Spk");
snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
#endif
#if 0
if (!chip->rt_jack)
{
err = snd_soc_jack_new(codec, "Headset Jack" , SND_JACK_HEADSET, &rk29_soc_jack);
if (err)
return err;
#if 0
// How-to use gpio, just declare snd_soc_jack_gpios, then it will
// help you to register a interrupt and set wakeup, and delayed schedule
// work
err = snd_soc_jack_add_gpios(&odroid_soc_jack, gpio_count, odroid_soc_jack_gpios);
if (err)
return err;
// If use this, when trigger, just use snd_soc_jack_get_type
// then snd_soc_jack_report to send the event to upper layer
err = snd_soc_jack_add_zones(&odroid_soc_jack, zone_count, tcc_soc_zones);
if (err)
return err;
#endif
err = rt5512_headset_keys(&rk29_soc_jack);
if (err)
return err;
chip->rt_jack = &rk29_soc_jack;
}
#endif
snd_soc_dapm_sync(dapm);
return 0;
}
static struct snd_soc_dai_link rk29_dai[] = {
{ /* Primary DAI i/f */
.name = "RT5512 AIF1",
.stream_name = "RT5512 PCM",
.codec_dai_name = "RT5512-aif1",
.init = rt5512_init,
.ops = &rk29_ops,
},
};
static struct snd_soc_card rockchip_rt5512_snd_card = {
.name = "RK_RT5512",
.dai_link = rk29_dai,
/* If you want to use sec_fifo device,
* changes the num_link = 2 or ARRAY_SIZE(odroid_dai). */
.num_links = ARRAY_SIZE(rk29_dai),
};
static int rockchip_rt5512_audio_probe(struct platform_device *pdev)
{
int ret;
struct snd_soc_card *card = &rockchip_rt5512_snd_card;
card->dev = &pdev->dev;
ret = rockchip_of_get_sound_card_info(card);
if (ret) {
printk("%s() get sound card info failed:%d\n", __FUNCTION__, ret);
return ret;
}
ret = snd_soc_register_card(card);
if (ret)
printk("%s() register card failed:%d\n", __FUNCTION__, ret);
return ret;
}
static int rockchip_rt5512_audio_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
snd_soc_unregister_card(card);
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id rockchip_rt5512_of_match[] = {
{ .compatible = "rockchip-rt5512", },
{},
};
MODULE_DEVICE_TABLE(of, rockchip_rt5512_of_match);
#endif /* CONFIG_OF */
static struct platform_driver rockchip_rt5512_audio_driver = {
.driver = {
.name = "rockchip-rt5512",
.owner = THIS_MODULE,
.pm = &snd_soc_pm_ops,
.of_match_table = of_match_ptr(rockchip_rt5512_of_match),
},
.probe = rockchip_rt5512_audio_probe,
.remove = rockchip_rt5512_audio_remove,
};
module_platform_driver(rockchip_rt5512_audio_driver);
MODULE_DESCRIPTION("ROCKCHIP i2s ASoC Interface");
MODULE_AUTHOR("cy_huang <cy_huang@richtek.com>");
MODULE_LICENSE("GPL");

View File

@@ -1,214 +0,0 @@
/*
* rk29_rt5621.c -- SoC audio for rockchip
*
* Driver for rockchip rt5621 audio
*
* 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.
*
*
*/
#include <linux/module.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include "../codecs/rt5621.h"
#include "card_info.h"
#include "rk_pcm.h"
#include "rk_i2s.h"
#if 0
#define DBG(x...) printk(KERN_INFO x)
#else
#define DBG(x...)
#endif
static int rk29_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int pll_out = 0;
unsigned int lrclk = 0, dai_fmt = rtd->dai_link->dai_fmt;
int ret;
DBG("Enter::%s----%d\n", __FUNCTION__, __LINE__);
/* set codec DAI configuration */
ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
if (ret < 0) {
printk("%s():failed to set the format for codec side\n", __FUNCTION__);
return ret;
}
/* set cpu DAI configuration */
ret = snd_soc_dai_set_fmt(cpu_dai, dai_fmt);
if (ret < 0) {
printk("%s():failed to set the format for cpu side\n", __FUNCTION__);
return ret;
}
switch(params_rate(params)) {
case 8000:
case 16000:
case 24000:
case 32000:
case 48000:
pll_out = 12288000;
break;
case 11025:
case 22050:
case 44100:
pll_out = 11289600;
break;
default:
DBG("Enter:%s, %d, Error rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
return -EINVAL;
break;
}
DBG("Enter:%s, %d, rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
if ((dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFM) {
if((24576000%params_rate(params))==0) //for 8k,16k,32k,48k
{
snd_soc_dai_set_pll(codec_dai,0,RT5621_PLL_FR_MCLK,pll_out, 24576000);
snd_soc_dai_set_sysclk(codec_dai,0, 24576000, SND_SOC_CLOCK_IN);
}
else if((22579200%params_rate(params))==0) //for 11k,22k,44k
{
snd_soc_dai_set_pll(codec_dai,0,RT5621_PLL_FR_MCLK,pll_out, 22579200);
snd_soc_dai_set_sysclk(codec_dai,0, 22579200, SND_SOC_CLOCK_IN);
}
}
if ((dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBS_CFS) {
/*Set the system clk for codec*/
ret=snd_soc_dai_set_sysclk(codec_dai, 0,pll_out,SND_SOC_CLOCK_IN);
if (ret < 0) {
DBG("rk29_hw_params_rt5621:failed to set the sysclk for codec side\n");
return ret;
}
snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK, (pll_out/4)/params_rate(params)-1);
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, 3);
}
DBG("Enter:%s, %d, LRCK=%d\n",__FUNCTION__,__LINE__,(pll_out/4)/params_rate(params));
return 0;
}
static const struct snd_soc_dapm_widget rt5621_dapm_widgets[] = {
SND_SOC_DAPM_MIC("Mic Jack", NULL),
SND_SOC_DAPM_SPK("Ext Spk", NULL),
SND_SOC_DAPM_HP("Headphone Jack", NULL),
};
static const struct snd_soc_dapm_route audio_map[]={
/* Mic Jack --> MIC_IN*/
{"Mic Bias1", NULL, "Mic Jack"},
{"MIC1", NULL, "Mic Bias1"},
/* HP_OUT --> Headphone Jack */
{"Headphone Jack", NULL, "HPOL"},
{"Headphone Jack", NULL, "HPOR"},
/* LINE_OUT --> Ext Speaker */
{"Ext Spk", NULL, "SPOL"},
{"Ext Spk", NULL, "SPOR"},
} ;
/*
* Logic for a rt5621 as connected on a rockchip board.
*/
static int rk29_rt5621_init(struct snd_soc_pcm_runtime *rtd)
{
return 0;
}
static struct snd_soc_ops rk29_ops = {
.hw_params = rk29_hw_params,
};
static struct snd_soc_dai_link rk29_dai = {
.name = "RT5621",
.stream_name = "RT5621 PCM",
.codec_dai_name = "RT5621 HiFi",
.init = rk29_rt5621_init,
.ops = &rk29_ops,
};
static struct snd_soc_card rockchip_rt5621_snd_card = {
.name = "RK_RT5621",
.dai_link = &rk29_dai,
.num_links = 1,
};
static int rockchip_rt5621_audio_probe(struct platform_device *pdev)
{
int ret;
struct snd_soc_card *card = &rockchip_rt5621_snd_card;
card->dev = &pdev->dev;
ret = rockchip_of_get_sound_card_info(card);
if (ret) {
printk("%s() get sound card info failed:%d\n", __FUNCTION__, ret);
return ret;
}
ret = snd_soc_register_card(card);
if (ret)
printk("%s() register card failed:%d\n", __FUNCTION__, ret);
return ret;
}
static int rockchip_rt5621_audio_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
snd_soc_unregister_card(card);
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id rockchip_rt5621_of_match[] = {
{ .compatible = "rockchip-rt5621", },
{},
};
MODULE_DEVICE_TABLE(of, rockchip_rt5621_of_match);
#endif /* CONFIG_OF */
static struct platform_driver rockchip_rt5621_audio_driver = {
.driver = {
.name = "rockchip-rt5621",
.owner = THIS_MODULE,
.pm = &snd_soc_pm_ops,
.of_match_table = of_match_ptr(rockchip_rt5621_of_match),
},
.probe = rockchip_rt5621_audio_probe,
.remove = rockchip_rt5621_audio_remove,
};
module_platform_driver(rockchip_rt5621_audio_driver);
/* Module information */
MODULE_AUTHOR("rockchip");
MODULE_DESCRIPTION("ROCKCHIP i2s ASoC Interface");
MODULE_LICENSE("GPL");

View File

@@ -1,231 +0,0 @@
/*
* rk29_rt5625.c -- SoC audio for rockchip
*
* Driver for rockchip rt5625 audio
*
* 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.
*
*
*/
#include <linux/module.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include "../codecs/rt5625.h"
#include "card_info.h"
#include "rk_pcm.h"
#include "rk_i2s.h"
#if 1
#define DBG(x...) printk(KERN_INFO x)
#else
#define DBG(x...)
#endif
static int rk29_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int pll_out = 0, dai_fmt = rtd->dai_link->dai_fmt;
int ret;
DBG("Enter::%s----%d\n", __FUNCTION__, __LINE__);
/* set codec DAI configuration */
ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
if (ret < 0) {
printk("%s():failed to set the format for codec side\n", __FUNCTION__);
return ret;
}
/* set cpu DAI configuration */
ret = snd_soc_dai_set_fmt(cpu_dai, dai_fmt);
if (ret < 0) {
printk("%s():failed to set the format for cpu side\n", __FUNCTION__);
return ret;
}
switch(params_rate(params)) {
case 8000:
case 16000:
case 24000:
case 32000:
case 48000:
pll_out = 12288000;
break;
case 11025:
case 22050:
case 44100:
pll_out = 11289600;
break;
default:
DBG("Enter:%s, %d, Error rate=%d\n", __FUNCTION__, __LINE__, params_rate(params));
return -EINVAL;
break;
}
DBG("Enter:%s, %d, rate=%d\n", __FUNCTION__, __LINE__, params_rate(params));
/*Set the system clk for codec*/
ret = snd_soc_dai_set_sysclk(codec_dai, 0, pll_out, SND_SOC_CLOCK_IN);
if (ret < 0)
{
DBG("rk29_hw_params_rt5625:failed to set the sysclk for codec side\n");
return ret;
}
snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK, (pll_out/4)/params_rate(params)-1);
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, 3);
DBG("Enter:%s, %d, pll_out/4/params_rate(params) = %d \n", __FUNCTION__, __LINE__, (pll_out/4)/params_rate(params));
return 0;
}
static int rt5625_voice_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int pll_out = 0, dai_fmt = rtd->dai_link->dai_fmt;
int ret;
DBG("Enter::%s----%d\n", __FUNCTION__, __LINE__);
/* set codec DAI configuration */
ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
if (ret < 0) {
printk("%s():failed to set the format for codec side\n", __FUNCTION__);
return ret;
}
switch(params_rate(params)) {
case 8000:
case 16000:
case 24000:
case 32000:
case 48000:
pll_out = 12288000;
break;
case 11025:
case 22050:
case 44100:
pll_out = 11289600;
break;
default:
DBG("Enter:%s, %d, Error rate=%d\n", __FUNCTION__, __LINE__, params_rate(params));
return -EINVAL;
break;
}
snd_soc_dai_set_pll(codec_dai, RT5625_PLL_MCLK_TO_VSYSCLK, 0, pll_out, 24576000);
/*Set the system clk for codec*/
ret = snd_soc_dai_set_sysclk(codec_dai, 0, 24576000, SND_SOC_CLOCK_IN);
if (ret < 0) {
printk("rk29_hw_params_rt5625:failed to set the sysclk for codec side\n");
return ret;
}
ret = snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
return 0;
}
static struct snd_soc_ops rk29_ops = {
.hw_params = rk29_hw_params,
};
static struct snd_soc_ops rt5625_voice_ops = {
.hw_params = rt5625_voice_hw_params,
};
static struct snd_soc_dai_link rk29_dai[] = {
{
.name = "RT5625 I2S1",
.stream_name = "RT5625 PCM",
.codec_dai_name = "rt5625-aif1",
.ops = &rk29_ops,
},
{
.name = "RT5625 I2S2",
.stream_name = "RT5625 PCM",
.codec_dai_name = "rt5625-aif2",
.ops = &rt5625_voice_ops,
},
};
static struct snd_soc_card rockchip_rt5625_snd_card = {
.name = "RK_RT5625",
.dai_link = rk29_dai,
.num_links = 2,
};
static int rockchip_rt5625_audio_probe(struct platform_device *pdev)
{
int ret;
struct snd_soc_card *card = &rockchip_rt5625_snd_card;
card->dev = &pdev->dev;
ret = rockchip_of_get_sound_card_info(card);
if (ret) {
printk("%s() get sound card info failed:%d\n", __FUNCTION__, ret);
return ret;
}
ret = snd_soc_register_card(card);
if (ret)
printk("%s() register card failed:%d\n", __FUNCTION__, ret);
return ret;
}
static int rockchip_rt5625_audio_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
snd_soc_unregister_card(card);
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id rockchip_rt5625_of_match[] = {
{ .compatible = "rockchip-rt5625", },
{},
};
MODULE_DEVICE_TABLE(of, rockchip_rt5625_of_match);
#endif /* CONFIG_OF */
static struct platform_driver rockchip_rt5625_audio_driver = {
.driver = {
.name = "rockchip-rt5625",
.owner = THIS_MODULE,
.pm = &snd_soc_pm_ops,
.of_match_table = of_match_ptr(rockchip_rt5625_of_match),
},
.probe = rockchip_rt5625_audio_probe,
.remove = rockchip_rt5625_audio_remove,
};
module_platform_driver(rockchip_rt5625_audio_driver);
/* Module information */
MODULE_AUTHOR("rockchip");
MODULE_DESCRIPTION("ROCKCHIP i2s ASoC Interface");
MODULE_LICENSE("GPL");

View File

@@ -1,238 +0,0 @@
/*
* rk29_rt5631.c -- SoC audio for rockchip
*
* Driver for rockchip rt5631 audio
*
* 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.
*
*
*/
#include <linux/module.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include "card_info.h"
#include "rk_pcm.h"
#include "rk_i2s.h"
#if 0
#define DBG(x...) printk(KERN_INFO x)
#else
#define DBG(x...)
#endif
static int rk29_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int pll_out = 0, dai_fmt = rtd->dai_link->dai_fmt;
int ret;
DBG("Enter::%s----%d\n", __FUNCTION__, __LINE__);
/* set codec DAI configuration */
ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
if (ret < 0) {
printk("%s():failed to set the format for codec side\n", __FUNCTION__);
return ret;
}
/* set cpu DAI configuration */
ret = snd_soc_dai_set_fmt(cpu_dai, dai_fmt);
if (ret < 0) {
printk("%s():failed to set the format for cpu side\n", __FUNCTION__);
return ret;
}
switch(params_rate(params)) {
case 8000:
case 16000:
case 24000:
case 32000:
case 48000:
pll_out = 12288000;
break;
case 11025:
case 22050:
case 44100:
pll_out = 11289600;
break;
case 96000:
case 192000:
pll_out = 12288000*2;
break;
case 88200:
case 176400:
pll_out = 11289600*2;
break;
default:
DBG("Enter:%s, %d, Error rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
return -EINVAL;
break;
}
snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
/*Set the system clk for codec*/
ret=snd_soc_dai_set_sysclk(codec_dai, 0,pll_out,SND_SOC_CLOCK_IN);
if (ret < 0)
{
DBG("rk29_hw_params_rt5631:failed to set the sysclk for codec side\n");
return ret;
}
//Codec is master, so is not need to set clkdiv for cpu.
if ((dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFM)
return 0;
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK, 64-1);//bclk = 2*32*lrck; 2*32fs
switch(params_rate(params)) {
case 176400:
case 192000:
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, 1);
DBG("Enter:%s, %d, MCLK=%d BCLK=%d LRCK=%d\n",
__FUNCTION__,__LINE__,pll_out,pll_out/2,params_rate(params));
break;
default:
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, 3);
DBG("default:%s, %d, MCLK=%d BCLK=%d LRCK=%d\n",
__FUNCTION__,__LINE__,pll_out,pll_out/4,params_rate(params));
break;
}
return 0;
}
static const struct snd_soc_dapm_widget rt5631_dapm_widgets[] = {
SND_SOC_DAPM_MIC("Mic Jack", NULL),
SND_SOC_DAPM_SPK("Ext Spk", NULL),
SND_SOC_DAPM_HP("Headphone Jack", NULL),
};
static const struct snd_soc_dapm_route audio_map[]={
/* Mic Jack --> MIC_IN*/
{"Mic Bias1", NULL, "Mic Jack"},
{"MIC1", NULL, "Mic Bias1"},
/* HP_OUT --> Headphone Jack */
{"Headphone Jack", NULL, "HPOL"},
{"Headphone Jack", NULL, "HPOR"},
/* LINE_OUT --> Ext Speaker */
{"Ext Spk", NULL, "SPOL"},
{"Ext Spk", NULL, "SPOR"},
} ;
/*
* Logic for a rt5631 as connected on a rockchip board.
*/
static int rk29_rt5631_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
/* Add specific widgets */
snd_soc_dapm_new_controls(dapm, rt5631_dapm_widgets,
ARRAY_SIZE(rt5631_dapm_widgets));
DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
/* Set up specific audio path audio_mapnects */
snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
snd_soc_dapm_nc_pin(dapm, "HP_L");
DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
snd_soc_dapm_nc_pin(dapm, "HP_R");
DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
snd_soc_dapm_sync(dapm);
DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
return 0;
}
static struct snd_soc_ops rk29_ops = {
.hw_params = rk29_hw_params,
};
static struct snd_soc_dai_link rk29_dai = {
.name = "rt5631",
.stream_name = "rt5631 PCM",
.codec_dai_name = "rt5631-hifi",
.init = rk29_rt5631_init,
.ops = &rk29_ops,
};
static struct snd_soc_card rockchip_rt5631_snd_card = {
.name = "RK_RT5631",
.dai_link = &rk29_dai,
.num_links = 1,
};
static int rockchip_rt5631_audio_probe(struct platform_device *pdev)
{
int ret;
struct snd_soc_card *card = &rockchip_rt5631_snd_card;
card->dev = &pdev->dev;
ret = rockchip_of_get_sound_card_info(card);
if (ret) {
printk("%s() get sound card info failed:%d\n", __FUNCTION__, ret);
return ret;
}
ret = snd_soc_register_card(card);
if (ret)
printk("%s() register card failed:%d\n", __FUNCTION__, ret);
return ret;
}
static int rockchip_rt5631_audio_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
snd_soc_unregister_card(card);
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id rockchip_rt5631_of_match[] = {
{ .compatible = "rockchip-rt5631", },
{},
};
MODULE_DEVICE_TABLE(of, rockchip_rt5631_of_match);
#endif /* CONFIG_OF */
static struct platform_driver rockchip_rt5631_audio_driver = {
.driver = {
.name = "rockchip-rt5631",
.owner = THIS_MODULE,
.pm = &snd_soc_pm_ops,
.of_match_table = of_match_ptr(rockchip_rt5631_of_match),
},
.probe = rockchip_rt5631_audio_probe,
.remove = rockchip_rt5631_audio_remove,
};
module_platform_driver(rockchip_rt5631_audio_driver);
/* Module information */
MODULE_AUTHOR("rockchip");
MODULE_DESCRIPTION("ROCKCHIP i2s ASoC Interface");
MODULE_LICENSE("GPL");

View File

@@ -1,291 +0,0 @@
/*
* rk_rt5631.c -- SoC audio for rockchip
*
* Driver for rockchip rt5631 audio
*
* 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.
*
*
*/
#include <linux/module.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include "../codecs/rt5631_phone.h"
#include "card_info.h"
#include "rk_pcm.h"
#include "rk_i2s.h"
#if 1
#define DBG(x...) printk(KERN_INFO x)
#else
#define DBG(x...)
#endif
static int rk29_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int pll_out = 0, dai_fmt = rtd->dai_link->dai_fmt;
int ret;
DBG("Enter::%s----%d\n", __FUNCTION__, __LINE__);
/* set codec DAI configuration */
ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
if (ret < 0) {
printk("%s():failed to set the format for codec side\n", __FUNCTION__);
return ret;
}
/* set cpu DAI configuration */
ret = snd_soc_dai_set_fmt(cpu_dai, dai_fmt);
if (ret < 0) {
printk("%s():failed to set the format for cpu side\n", __FUNCTION__);
return ret;
}
switch(params_rate(params)) {
case 8000:
case 16000:
case 24000:
case 32000:
case 48000:
pll_out = 12288000;
break;
case 11025:
case 22050:
case 44100:
pll_out = 11289600;
break;
default:
DBG("Enter:%s, %d, Error rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
return -EINVAL;
}
DBG("Enter:%s, %d, rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
if ((dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBS_CFS) {
/*Set the system clk for codec*/
ret=snd_soc_dai_set_sysclk(codec_dai, 0,pll_out,SND_SOC_CLOCK_IN);
if (ret < 0)
{
DBG("rk29_hw_params_rt5631:failed to set the sysclk for codec side\n");
return ret;
}
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK, (pll_out/4)/params_rate(params)-1);
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, 3);
}
if ((dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFM)
snd_soc_dai_set_sysclk(codec_dai,0,pll_out, SND_SOC_CLOCK_IN);
DBG("Enter:%s, %d, LRCK=%d\n",__FUNCTION__,__LINE__,(pll_out/4)/params_rate(params));
return 0;
}
static int rk29_hw_params_voice(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int pll_out = 0, dai_fmt = rtd->dai_link->dai_fmt;
int ret;
DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
//change to 8Khz
params->intervals[SNDRV_PCM_HW_PARAM_RATE - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL].min = 8000;
/* set codec DAI configuration */
ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
if (ret < 0) {
printk("%s():failed to set the format for codec side\n", __FUNCTION__);
return ret;
}
switch(params_rate(params)) {
case 8000:
case 16000:
case 24000:
case 32000:
case 48000:
// pll_out = 12288000;
// break;
case 11025:
case 22050:
case 44100:
// pll_out = 11289600;
pll_out = 2048000;
break;
default:
DBG("Enter:%s, %d, Error rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
return -EINVAL;
}
DBG("Enter:%s, %d, rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
if ((dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBS_CFS) {
/*Set the system clk for codec*/
ret=snd_soc_dai_set_sysclk(codec_dai, 0,pll_out,SND_SOC_CLOCK_IN);
if (ret < 0)
{
DBG("rk29_hw_params_rt5631:failed to set the sysclk for codec side\n");
return ret;
}
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK, (pll_out/4)/params_rate(params)-1);
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, 3);
}
if ((dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFM)
snd_soc_dai_set_sysclk(codec_dai,0,pll_out, SND_SOC_CLOCK_IN);
DBG("Enter:%s, %d, LRCK=%d\n",__FUNCTION__,__LINE__,(pll_out/4)/params_rate(params));
return 0;
}
static const struct snd_soc_dapm_widget rk_rt5631_dapm_widgets[] = {
SND_SOC_DAPM_MIC("Mic Jack", NULL),
SND_SOC_DAPM_SPK("Ext Spk", NULL),
SND_SOC_DAPM_HP("Headphone Jack", NULL),
};
static const struct snd_soc_dapm_route rk_rt5631_audio_map[]={
{"Headphone Jack", NULL, "HPOL"},
{"Headphone Jack", NULL, "HPOR"},
{"Ext Spk", NULL, "SPOL"},
{"Ext Spk", NULL, "SPOR"},
{"MIC1", NULL, "MIC Bias1"},
{"MIC Bias1", NULL, "Mic Jack"},
} ;
//bard 7-5 s
static const struct snd_kcontrol_new rk_rt5631_controls[] = {
SOC_DAPM_PIN_SWITCH("Mic Jack"),
SOC_DAPM_PIN_SWITCH("Ext Spk"),
SOC_DAPM_PIN_SWITCH("Headphone Jack"),
};
//bard 7-5 e
/*
* Logic for a rt5631 as connected on a rockchip board.
*/
static int rk29_rt5631_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
// snd_soc_dapm_nc_pin(dapm, "MONO");
// snd_soc_dapm_nc_pin(dapm, "MONOIN_RXN");
// snd_soc_dapm_nc_pin(dapm, "MONOIN_RXP");
snd_soc_dapm_nc_pin(dapm, "DMIC");
snd_soc_dapm_sync(dapm);
return 0;
}
static struct snd_soc_ops rk29_ops = {
.hw_params = rk29_hw_params,
};
static struct snd_soc_ops rk29_ops_voice = {
.hw_params = rk29_hw_params_voice,
};
static struct snd_soc_dai_link rk29_dai[] = {
{
.name = "RT5631 hifi",
.stream_name = "RT5631 hifi stream",
.codec_dai_name = "RT5631 HiFi",
.init = rk29_rt5631_init,
.ops = &rk29_ops,
},
{
.name = "RT5631 voice",
.stream_name = "RT5631 voice stream",
.codec_dai_name = "rt5631-voice",
.ops = &rk29_ops_voice,
},
};
static struct snd_soc_card rockchip_rt5631_snd_card = {
.name = "RK_RT5631",
.dai_link = rk29_dai,
.num_links = 2,
.controls = rk_rt5631_controls,
.num_controls = ARRAY_SIZE(rk_rt5631_controls),
.dapm_widgets = rk_rt5631_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(rk_rt5631_dapm_widgets),
.dapm_routes = rk_rt5631_audio_map,
.num_dapm_routes = ARRAY_SIZE(rk_rt5631_audio_map),
};
static int rockchip_rt5631_audio_probe(struct platform_device *pdev)
{
int ret;
struct snd_soc_card *card = &rockchip_rt5631_snd_card;
card->dev = &pdev->dev;
ret = rockchip_of_get_sound_card_info(card);
if (ret) {
printk("%s() get sound card info failed:%d\n", __FUNCTION__, ret);
return ret;
}
ret = snd_soc_register_card(card);
if (ret)
printk("%s() register card failed:%d\n", __FUNCTION__, ret);
return ret;
}
static int rockchip_rt5631_audio_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
snd_soc_unregister_card(card);
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id rockchip_rt5631_of_match[] = {
{ .compatible = "rockchip-rt5631-phone", },
{},
};
MODULE_DEVICE_TABLE(of, rockchip_rt5631_of_match);
#endif /* CONFIG_OF */
static struct platform_driver rockchip_rt5631_audio_driver = {
.driver = {
.name = "rockchip-rt5631-phone",
.owner = THIS_MODULE,
.pm = &snd_soc_pm_ops,
.of_match_table = of_match_ptr(rockchip_rt5631_of_match),
},
.probe = rockchip_rt5631_audio_probe,
.remove = rockchip_rt5631_audio_remove,
};
module_platform_driver(rockchip_rt5631_audio_driver);
/* Module information */
MODULE_AUTHOR("rockchip");
MODULE_DESCRIPTION("ROCKCHIP i2s ASoC Interface");
MODULE_LICENSE("GPL");

View File

@@ -1,231 +0,0 @@
/*
* rk29_rt5625.c -- SoC audio for rockchip
*
* Driver for rockchip rt5625 audio
*
* 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.
*
*
*/
#include <linux/module.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include "../codecs/rt5639.h"
#include "card_info.h"
#include "rk_pcm.h"
#include "rk_i2s.h"
#if 1
#define DBG(x...) printk(KERN_INFO x)
#else
#define DBG(x...)
#endif
static int rk29_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int pll_out = 0, dai_fmt = rtd->dai_link->dai_fmt;
int ret;
DBG("Enter::%s----%d\n", __FUNCTION__, __LINE__);
/* set codec DAI configuration */
ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
if (ret < 0) {
printk("%s():failed to set the format for codec side\n", __FUNCTION__);
return ret;
}
/* set cpu DAI configuration */
ret = snd_soc_dai_set_fmt(cpu_dai, dai_fmt);
if (ret < 0) {
printk("%s():failed to set the format for cpu side\n", __FUNCTION__);
return ret;
}
switch(params_rate(params)) {
case 8000:
case 16000:
case 24000:
case 32000:
case 48000:
pll_out = 12288000;
break;
case 11025:
case 22050:
case 44100:
pll_out = 11289600;
break;
default:
DBG("Enter:%s, %d, Error rate=%d\n", __FUNCTION__, __LINE__, params_rate(params));
return -EINVAL;
break;
}
DBG("Enter:%s, %d, rate=%d\n", __FUNCTION__, __LINE__, params_rate(params));
/*Set the system clk for codec*/
ret = snd_soc_dai_set_sysclk(codec_dai, 0, pll_out, SND_SOC_CLOCK_IN);
if (ret < 0)
{
DBG("rk29_hw_params_rt5625:failed to set the sysclk for codec side\n");
return ret;
}
snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK, (pll_out/4)/params_rate(params)-1);
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, 3);
DBG("Enter:%s, %d, pll_out/4/params_rate(params) = %d \n", __FUNCTION__, __LINE__, (pll_out/4)/params_rate(params));
return 0;
}
static int rt5639_voice_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int pll_out = 0, dai_fmt = rtd->dai_link->dai_fmt;
int ret;
DBG("Enter::%s----%d\n", __FUNCTION__, __LINE__);
/* set codec DAI configuration */
ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
if (ret < 0) {
printk("%s():failed to set the format for codec side\n", __FUNCTION__);
return ret;
}
switch(params_rate(params)) {
case 8000:
case 16000:
case 24000:
case 32000:
case 48000:
pll_out = 12288000;
break;
case 11025:
case 22050:
case 44100:
pll_out = 11289600;
break;
default:
DBG("Enter:%s, %d, Error rate=%d\n", __FUNCTION__, __LINE__, params_rate(params));
return -EINVAL;
break;
}
//snd_soc_dai_set_pll(codec_dai, RT5625_PLL_MCLK_TO_VSYSCLK, 0, pll_out, 24576000);???????
/*Set the system clk for codec*/
ret = snd_soc_dai_set_sysclk(codec_dai, 0, 24576000, SND_SOC_CLOCK_IN);
if (ret < 0) {
printk("rk29_hw_params_rt5625:failed to set the sysclk for codec side\n");
return ret;
}
ret = snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
return 0;
}
static struct snd_soc_ops rk29_ops = {
.hw_params = rk29_hw_params,
};
static struct snd_soc_ops rt5639_voice_ops = {
.hw_params = rt5639_voice_hw_params,
};
static struct snd_soc_dai_link rk29_dai[] = {
{
.name = "RT5639 I2S1",
.stream_name = "RT5639 PCM",
.codec_dai_name = "rt5639-aif1",
.ops = &rk29_ops,
},
{
.name = "RT5639 I2S2",
.stream_name = "RT5639 PCM",
.codec_dai_name = "rt5639-aif2",
.ops = &rt5639_voice_ops,
},
};
static struct snd_soc_card rockchip_rt5639_snd_card = {
.name = "RK_RT5639",
.dai_link = rk29_dai,
.num_links = 2,
};
static int rockchip_rt5639_audio_probe(struct platform_device *pdev)
{
int ret;
struct snd_soc_card *card = &rockchip_rt5639_snd_card;
card->dev = &pdev->dev;
ret = rockchip_of_get_sound_card_info(card);
if (ret) {
printk("%s() get sound card info failed:%d\n", __FUNCTION__, ret);
return ret;
}
ret = snd_soc_register_card(card);
if (ret)
printk("%s() register card failed:%d\n", __FUNCTION__, ret);
return ret;
}
static int rockchip_rt5639_audio_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
snd_soc_unregister_card(card);
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id rockchip_rt5639_of_match[] = {
{ .compatible = "rockchip-rt5639", },
{},
};
MODULE_DEVICE_TABLE(of, rockchip_rt5639_of_match);
#endif /* CONFIG_OF */
static struct platform_driver rockchip_rt5639_audio_driver = {
.driver = {
.name = "rockchip-rt5639",
.owner = THIS_MODULE,
.pm = &snd_soc_pm_ops,
.of_match_table = of_match_ptr(rockchip_rt5639_of_match),
},
.probe = rockchip_rt5639_audio_probe,
.remove = rockchip_rt5639_audio_remove,
};
module_platform_driver(rockchip_rt5639_audio_driver);
/* Module information */
MODULE_AUTHOR("rockchip");
MODULE_DESCRIPTION("ROCKCHIP i2s ASoC Interface");
MODULE_LICENSE("GPL");

View File

@@ -1,303 +0,0 @@
/*
* rk29_rt5640.c -- SoC audio for rockchip
*
* Driver for rockchip rt5640 audio
*
* 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.
*
*
*/
#include <linux/module.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include "../codecs/rt5640.h"
#include "card_info.h"
#include "rk_pcm.h"
#include "rk_i2s.h"
#if 0
#define DBG(x...) printk(KERN_INFO x)
#else
#define DBG(x...)
#endif
static int rk29_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int pll_out = 0, dai_fmt = rtd->dai_link->dai_fmt;
int ret;
DBG("Enter::%s----%d\n", __FUNCTION__, __LINE__);
/* set codec DAI configuration */
ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
if (ret < 0) {
printk("%s():failed to set the format for codec side\n", __FUNCTION__);
return ret;
}
/* set cpu DAI configuration */
ret = snd_soc_dai_set_fmt(cpu_dai, dai_fmt);
if (ret < 0) {
printk("%s():failed to set the format for cpu side\n", __FUNCTION__);
return ret;
}
switch(params_rate(params)) {
case 8000:
case 16000:
case 24000:
case 32000:
case 48000:
pll_out = 12288000;
break;
case 11025:
case 22050:
case 44100:
pll_out = 11289600;
break;
default:
DBG("Enter:%s, %d, Error rate=%d\n", __FUNCTION__, __LINE__, params_rate(params));
return -EINVAL;
break;
}
DBG("Enter:%s, %d, rate=%d\n", __FUNCTION__, __LINE__, params_rate(params));
/*Set the system clk for codec*/
ret = snd_soc_dai_set_sysclk(codec_dai, 0, pll_out, SND_SOC_CLOCK_IN);
if (ret < 0)
{
DBG("rk29_hw_params_rt5640:failed to set the sysclk for codec side\n");
return ret;
}
snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK, (pll_out/4)/params_rate(params)-1);
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, 3);
DBG("Enter:%s, %d, pll_out/4/params_rate(params) = %d \n", __FUNCTION__, __LINE__, (pll_out/4)/params_rate(params));
return 0;
}
static int rt5640_voice_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int pll_out = 0, dai_fmt = rtd->dai_link->dai_fmt;
int ret;
DBG("Enter::%s----%d\n", __FUNCTION__, __LINE__);
/* set codec DAI configuration */
ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
if (ret < 0) {
printk("%s():failed to set the format for codec side\n", __FUNCTION__);
return ret;
}
switch(params_rate(params)) {
case 8000:
case 16000:
case 24000:
case 32000:
case 48000:
pll_out = 12288000;
break;
case 11025:
case 22050:
case 44100:
pll_out = 11289600;
break;
default:
DBG("Enter:%s, %d, Error rate=%d\n", __FUNCTION__, __LINE__, params_rate(params));
return -EINVAL;
break;
}
DBG("Enter:%s, %d, rate=%d\n", __FUNCTION__, __LINE__, params_rate(params));
/*Set the system clk for codec*/
snd_soc_dai_set_pll(codec_dai, 0, RT5640_PLL1_S_MCLK, pll_out, 24576000);
ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_PLL1, 24576000, SND_SOC_CLOCK_IN);
if (ret < 0) {
printk("rk29_hw_params_rt5640:failed to set the sysclk for codec side\n");
return ret;
}
snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK, (pll_out/4)/params_rate(params)-1);
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, 3);
DBG("Enter:%s, %d, pll_out/4/params_rate(params) = %d \n", __FUNCTION__, __LINE__, (pll_out/4)/params_rate(params));
return 0;
}
static const struct snd_soc_dapm_widget rk_rt5640_dapm_widgets[] = {
SND_SOC_DAPM_MIC("Mic Jack", NULL),
SND_SOC_DAPM_MIC("Headset Jack", NULL),
SND_SOC_DAPM_SPK("Ext Spk", NULL),
SND_SOC_DAPM_HP("Headphone Jack", NULL),
};
static const struct snd_soc_dapm_route rk_rt5640_audio_map[]={
/* Mic Jack --> MIC_IN*/
{"micbias1", NULL, "Mic Jack"},
{"MIC1", NULL, "micbias1"},
// HP MIC
{"micbias1", NULL, "Headset Jack"},
{"MIC3", NULL, "micbias1"},
{"Ext Spk", NULL, "SPOLP"},
{"Ext Spk", NULL, "SPOLN"},
{"Ext Spk", NULL, "SPORP"},
{"Ext Spk", NULL, "SPORN"},
{"Headphone Jack", NULL, "HPOL"},
{"Headphone Jack", NULL, "HPOR"},
} ;
static const struct snd_kcontrol_new rk_rt5640_controls[] = {
SOC_DAPM_PIN_SWITCH("Mic Jack"),
SOC_DAPM_PIN_SWITCH("Headset Jack"),
SOC_DAPM_PIN_SWITCH("Ext Spk"),
SOC_DAPM_PIN_SWITCH("Headphone Jack"),
};
/*
* Logic for a rt5640 as connected on a rockchip board.
*/
static int rk29_rt5640_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
mutex_lock(&dapm->card->dapm_mutex);
snd_soc_dapm_enable_pin(dapm, "Mic Jack");
snd_soc_dapm_enable_pin(dapm, "Headset Jack");
snd_soc_dapm_enable_pin(dapm, "Ext Spk");
snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
mutex_unlock(&dapm->card->dapm_mutex);
snd_soc_dapm_sync(dapm);
return 0;
}
static struct snd_soc_ops rk29_ops = {
.hw_params = rk29_hw_params,
};
static struct snd_soc_ops rt5640_voice_ops = {
.hw_params = rt5640_voice_hw_params,
};
static struct snd_soc_dai_link rk29_dai[] = {
{
.name = "RT5640 I2S1",
.stream_name = "RT5640 PCM",
.codec_dai_name = "rt5640-aif1",
.init = rk29_rt5640_init,
.ops = &rk29_ops,
},
{
.name = "RT5640 I2S2",
.stream_name = "RT5640 PCM",
.codec_dai_name = "rt5640-aif2",
.ops = &rt5640_voice_ops,
},
};
static struct snd_soc_card rockchip_rt5640_snd_card = {
.name = "RK_RT5640",
.dai_link = rk29_dai,
.num_links = 2,
.controls = rk_rt5640_controls,
.num_controls = ARRAY_SIZE(rk_rt5640_controls),
.dapm_widgets = rk_rt5640_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(rk_rt5640_dapm_widgets),
.dapm_routes = rk_rt5640_audio_map,
.num_dapm_routes = ARRAY_SIZE(rk_rt5640_audio_map),
};
static int rockchip_rt5640_audio_probe(struct platform_device *pdev)
{
int ret;
struct snd_soc_card *card = &rockchip_rt5640_snd_card;
card->dev = &pdev->dev;
ret = rockchip_of_get_sound_card_info(card);
if (ret) {
printk("%s() get sound card info failed:%d\n", __FUNCTION__, ret);
return ret;
}
ret = snd_soc_register_card(card);
if (ret)
printk("%s() register card failed:%d\n", __FUNCTION__, ret);
return ret;
}
static int rockchip_rt5640_audio_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
snd_soc_unregister_card(card);
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id rockchip_rt5640_of_match[] = {
{ .compatible = "rockchip-rt5640", },
{},
};
MODULE_DEVICE_TABLE(of, rockchip_rt5640_of_match);
#endif /* CONFIG_OF */
static struct platform_driver rockchip_rt5640_audio_driver = {
.driver = {
.name = "rockchip-rt5640",
.owner = THIS_MODULE,
.pm = &snd_soc_pm_ops,
.of_match_table = of_match_ptr(rockchip_rt5640_of_match),
},
.probe = rockchip_rt5640_audio_probe,
.remove = rockchip_rt5640_audio_remove,
};
module_platform_driver(rockchip_rt5640_audio_driver);
/* Module information */
MODULE_AUTHOR("rockchip");
MODULE_DESCRIPTION("ROCKCHIP i2s ASoC Interface");
MODULE_LICENSE("GPL");

View File

@@ -1,513 +0,0 @@
/*
* Rockchip S/PDIF ALSA SoC Digital Audio Interface(DAI) driver
*
* Copyright (C) 2015 Fuzhou Rockchip Electronics Co., Ltd
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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/init.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/version.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/rockchip/iomap.h>
#include <linux/rockchip/grf.h>
#include <asm/dma.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/initval.h>
#include <sound/soc.h>
#include <sound/dmaengine_pcm.h>
#include <linux/spinlock.h>
#include "rk_pcm.h"
/*
* channel status register
* 192 frame channel status bits: include 384 subframe bits
*/
#define SPDIF_CHNSR00_ADDR 0xC0
#define SPDIF_CHNSR01_ADDR 0xC4
#define SPDIF_CHNSR02_ADDR 0xC8
#define SPDIF_CHNSR03_ADDR 0xCC
#define SPDIF_CHNSR04_ADDR 0xD0
#define SPDIF_CHNSR05_ADDR 0xD4
#define SPDIF_CHNSR06_ADDR 0xD8
#define SPDIF_CHNSR07_ADDR 0xDC
#define SPDIF_CHNSR08_ADDR 0xE0
#define SPDIF_CHNSR09_ADDR 0xE4
#define SPDIF_CHNSR10_ADDR 0xE8
#define SPDIF_CHNSR11_ADDR 0xEC
/*
* according to iec958, we only care about
* the first meaningful 5 bytes(40 bits)
*/
#define CHNSTA_BYTES (5)
#define BIT_1_LPCM (0X0<<1)
#define BIT_1_NLPCM (0x1<<1)
/* sample word length bit 32~35 */
#define CHNS_SAMPLE_WORD_LEN_16 (0x2)
#define CHNS_SAMPLE_WORD_LEN_24 (0xb)
/* sample frequency bit 24~27 */
#define CHNS_SAMPLE_FREQ_22P05K (0X4)
#define CHNS_SAMPLE_FREQ_44P1K (0X0)
#define CHNS_SAMPLE_FREQ_88P2K (0X8)
#define CHNS_SAMPLE_FREQ_176P4K (0Xc)
#define CHNS_SAMPLE_FREQ_24K (0X6)
#define CHNS_SAMPLE_FREQ_48K (0X2)
#define CHNS_SAMPLE_FREQ_96K (0Xa)
#define CHNS_SAMPLE_FREQ_192K (0Xe)
#define CHNS_SAMPLE_FREQ_32K (0X3)
#define CHNS_SAMPLE_FREQ_768K (0X9)
/* Registers */
#define CFGR 0x00
#define SDBLR 0x04
#define DMACR 0x08
#define INTCR 0x0C
#define INTSR 0x10
#define XFER 0x18
#define SMPDR 0x20
/* transfer configuration register */
#define CFGR_VALID_DATA_16bit (0x0 << 0)
#define CFGR_VALID_DATA_20bit (0x1 << 0)
#define CFGR_VALID_DATA_24bit (0x2 << 0)
#define CFGR_VALID_DATA_MASK (0x3 << 0)
#define CFGR_HALFWORD_TX_ENABLE (0x1 << 2)
#define CFGR_HALFWORD_TX_DISABLE (0x0 << 2)
#define CFGR_HALFWORD_TX_MASK (0x1 << 2)
#define CFGR_JUSTIFIED_RIGHT (0x0 << 3)
#define CFGR_JUSTIFIED_LEFT (0x1 << 3)
#define CFGR_JUSTIFIED_MASK (0x1 << 3)
#define CFGR_CSE_DISABLE (0x0 << 6)
#define CFGR_CSE_ENABLE (0x1 << 6)
#define CFGR_CSE_MASK (0x1 << 6)
#define CFGR_MCLK_CLR (0x1 << 7)
#define CFGR_LINEAR_PCM (0x0 << 8)
#define CFGR_NON_LINEAR_PCM (0x1 << 8)
#define CFGR_LINEAR_MASK (0x1 << 8)
#define CFGR_PRE_CHANGE_ENALBLE (0x1 << 9)
#define CFGR_PRE_CHANGE_DISABLE (0x0 << 9)
#define CFGR_PRE_CHANGE_MASK (0x1 << 9)
#define CFGR_CLK_RATE_MASK (0xFF << 16)
/* transfer start register */
#define XFER_TRAN_STOP (0x0 << 0)
#define XFER_TRAN_START (0x1 << 0)
#define XFER_MASK (0x1 << 0)
/* dma control register */
#define DMACR_TRAN_DMA_DISABLE (0x0 << 5)
#define DMACR_TRAN_DMA_ENABLE (0x1 << 5)
#define DMACR_TRAN_DMA_CTL_MASK (0x1 << 5)
#define DMACR_TRAN_DATA_LEVEL (0x10)
#define DMACR_TRAN_DATA_LEVEL_MASK (0x1F)
#define DMACR_TRAN_DMA_MASK (0x3F)
#define DMA_DATA_LEVEL_16 (0x10)
/* interrupt control register */
#define INTCR_SDBEIE_DISABLE (0x0 << 4)
#define INTCR_SDBEIE_ENABLE (0x1 << 4)
#define INTCR_SDBEIE_MASK (0x1 << 4)
/* size * width: 16*4 = 64 bytes */
#define SPDIF_DMA_BURST_SIZE (16)
struct rockchip_spdif_info {
spinlock_t lock;/*lock parmeter setting.*/
void __iomem *regs;
unsigned long clk_rate;
struct clk *hclk;
struct clk *clk;
struct device *dev;
struct snd_dmaengine_dai_dma_data dma_playback;
u32 cfgr;
u32 dmac;
};
static inline struct rockchip_spdif_info *to_info(struct snd_soc_dai *cpu_dai)
{
return snd_soc_dai_get_drvdata(cpu_dai);
}
static void spdif_snd_txctrl(struct rockchip_spdif_info *spdif, int on)
{
void __iomem *regs = spdif->regs;
u32 dmacr, xfer;
xfer = readl(regs + XFER) & (~XFER_MASK);
dmacr = readl(regs + DMACR) & (~DMACR_TRAN_DMA_CTL_MASK);
if (on) {
xfer |= XFER_TRAN_START;
dmacr |= DMACR_TRAN_DMA_ENABLE;
dmacr |= spdif->dmac;
writel(spdif->cfgr, regs + CFGR);
writel(dmacr, regs + DMACR);
writel(xfer, regs + XFER);
} else {
xfer &= XFER_TRAN_STOP;
dmacr &= DMACR_TRAN_DMA_DISABLE;
writel(xfer, regs + XFER);
writel(dmacr, regs + DMACR);
writel(CFGR_MCLK_CLR, regs + CFGR);
}
dev_dbg(spdif->dev, "on: %d, xfer = 0x%x, dmacr = 0x%x\n",
on, readl(regs + XFER), readl(regs + DMACR));
}
static int spdif_set_syclk(struct snd_soc_dai *cpu_dai, int clk_id,
unsigned int freq, int dir)
{
struct rockchip_spdif_info *spdif = to_info(cpu_dai);
dev_dbg(spdif->dev, "%s: sysclk = %d\n", __func__, freq);
spdif->clk_rate = freq;
clk_set_rate(spdif->clk, freq);
return 0;
}
static int spdif_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct rockchip_spdif_info *spdif = to_info(rtd->cpu_dai);
unsigned long flags;
dev_dbg(spdif->dev, "%s: cmd: %d\n", __func__, cmd);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
spin_lock_irqsave(&spdif->lock, flags);
spdif_snd_txctrl(spdif, 1);
spin_unlock_irqrestore(&spdif->lock, flags);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
spin_lock_irqsave(&spdif->lock, flags);
spdif_snd_txctrl(spdif, 0);
spin_unlock_irqrestore(&spdif->lock, flags);
break;
default:
return -EINVAL;
}
return 0;
}
static int spdif_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct rockchip_spdif_info *spdif = to_info(dai);
void __iomem *regs = spdif->regs;
unsigned long flags;
unsigned int val;
u32 cfgr, dmac, intcr, chnregval;
char chnsta[CHNSTA_BYTES];
dev_dbg(spdif->dev, "%s\n", __func__);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
dai->playback_dma_data = &spdif->dma_playback;
} else {
dev_err(spdif->dev, "capture is not supported\n");
return -EINVAL;
}
spin_lock_irqsave(&spdif->lock, flags);
cfgr = readl(regs + CFGR);
cfgr &= ~CFGR_VALID_DATA_MASK;
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
cfgr |= CFGR_VALID_DATA_16bit;
break;
case SNDRV_PCM_FORMAT_S20_3LE:
cfgr |= CFGR_VALID_DATA_20bit;
break;
case SNDRV_PCM_FORMAT_S24_LE:
cfgr |= CFGR_VALID_DATA_24bit;
break;
default:
goto err;
}
cfgr &= ~CFGR_HALFWORD_TX_MASK;
cfgr |= CFGR_HALFWORD_TX_ENABLE;
/* no need divder, let set_syclk care about this */
cfgr &= ~CFGR_CLK_RATE_MASK;
cfgr |= (0x0<<16);
cfgr &= ~CFGR_JUSTIFIED_MASK;
cfgr |= CFGR_JUSTIFIED_RIGHT;
cfgr &= ~CFGR_CSE_MASK;
cfgr |= CFGR_CSE_ENABLE;
cfgr &= ~CFGR_LINEAR_MASK;
cfgr |= CFGR_LINEAR_PCM;
cfgr &= ~CFGR_PRE_CHANGE_MASK;
cfgr |= CFGR_PRE_CHANGE_ENALBLE;
spdif->cfgr = cfgr;
writel(cfgr, regs + CFGR);
intcr = readl(regs + INTCR) & (~INTCR_SDBEIE_MASK);
intcr |= INTCR_SDBEIE_DISABLE;
writel(intcr, regs + INTCR);
dmac = readl(regs + DMACR) & (~DMACR_TRAN_DATA_LEVEL_MASK);
dmac |= DMA_DATA_LEVEL_16;
spdif->dmac = dmac;
writel(dmac, regs + DMACR);
/* channel status bit */
memset(chnsta, 0x0, CHNSTA_BYTES);
switch (params_rate(params)) {
case 44100:
val = CHNS_SAMPLE_FREQ_44P1K;
break;
case 48000:
val = CHNS_SAMPLE_FREQ_48K;
break;
case 88200:
val = CHNS_SAMPLE_FREQ_88P2K;
break;
case 96000:
val = CHNS_SAMPLE_FREQ_96K;
break;
case 176400:
val = CHNS_SAMPLE_FREQ_176P4K;
break;
case 192000:
val = CHNS_SAMPLE_FREQ_192K;
break;
default:
val = CHNS_SAMPLE_FREQ_44P1K;
break;
}
chnsta[0] |= BIT_1_LPCM;
chnsta[3] |= val;
chnsta[4] |= ((~val)<<4 | CHNS_SAMPLE_WORD_LEN_16);
chnregval = (chnsta[4] << 16) | (chnsta[4]);
writel(chnregval, regs + SPDIF_CHNSR02_ADDR);
chnregval = (chnsta[3] << 24) | (chnsta[3] << 8);
writel(chnregval, regs + SPDIF_CHNSR01_ADDR);
chnregval = (chnsta[1] << 24) | (chnsta[0] << 16) |
(chnsta[1] << 8) | (chnsta[0]);
writel(chnregval, regs + SPDIF_CHNSR00_ADDR);
spin_unlock_irqrestore(&spdif->lock, flags);
return 0;
err:
spin_unlock_irqrestore(&spdif->lock, flags);
return -EINVAL;
}
#ifdef CONFIG_PM
static int spdif_suspend(struct snd_soc_dai *cpu_dai)
{
struct rockchip_spdif_info *spdif = to_info(cpu_dai);
dev_dbg(spdif->dev, "%s\n", __func__);
return 0;
}
static int spdif_resume(struct snd_soc_dai *cpu_dai)
{
struct rockchip_spdif_info *spdif = to_info(cpu_dai);
dev_dbg(spdif->dev, "%s\n", __func__);
return 0;
}
#else
#define spdif_suspend NULL
#define spdif_resume NULL
#endif
static struct snd_soc_dai_ops spdif_dai_ops = {
.set_sysclk = spdif_set_syclk,
.trigger = spdif_trigger,
.hw_params = spdif_hw_params,
};
struct snd_soc_dai_driver rockchip_spdif_dai = {
.name = "rockchip-spdif",
.playback = {
.stream_name = "SPDIF Playback",
.channels_min = 2,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_8000_192000,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S20_3LE |
SNDRV_PCM_FMTBIT_S24_LE, },
.ops = &spdif_dai_ops,
.suspend = spdif_suspend,
.resume = spdif_resume,
};
static const struct snd_soc_component_driver rockchip_spdif_component = {
.name = "rockchip-spdif",
};
static int spdif_probe(struct platform_device *pdev)
{
struct resource *memregion;
struct resource *mem_res;
struct rockchip_spdif_info *spdif;
int ret;
spdif = devm_kzalloc(&pdev->dev, sizeof(
struct rockchip_spdif_info), GFP_KERNEL);
if (!spdif) {
dev_err(&pdev->dev, "Can't allocate spdif info\n");
return -ENOMEM;
}
spdif->dev = &pdev->dev;
platform_set_drvdata(pdev, spdif);
spin_lock_init(&spdif->lock);
/* get spdif register region. */
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mem_res) {
dev_err(&pdev->dev, "No memory resource\n");
ret = -ENOENT;
goto err_;
}
memregion = devm_request_mem_region(&pdev->dev,
mem_res->start,
resource_size(mem_res),
"rockchip-spdif");
if (!memregion) {
dev_err(&pdev->dev, "Memory region already claimed\n");
ret = -EBUSY;
goto err_;
}
spdif->regs = devm_ioremap(&pdev->dev,
memregion->start,
resource_size(memregion));
if (!spdif->regs) {
dev_err(&pdev->dev, "ioremap failed\n");
ret = -ENOMEM;
goto err_;
}
/* get spdif clock and init. */
spdif->hclk = devm_clk_get(&pdev->dev, "spdif_hclk");
if (IS_ERR(spdif->hclk)) {
dev_err(&pdev->dev, "Can't retrieve spdif hclk\n");
spdif->hclk = NULL;
}
clk_prepare_enable(spdif->hclk);
spdif->clk = devm_clk_get(&pdev->dev, "spdif_mclk");
if (IS_ERR(spdif->clk)) {
dev_err(&pdev->dev, "Can't retrieve spdif mclk\n");
ret = -ENOMEM;
goto err_;
}
/* init freq */
clk_set_rate(spdif->clk, 11289600);
clk_prepare_enable(spdif->clk);
spdif->dma_playback.addr = mem_res->start + SMPDR;
spdif->dma_playback.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
spdif->dma_playback.maxburst = SPDIF_DMA_BURST_SIZE;
ret = snd_soc_register_component(&pdev->dev,
&rockchip_spdif_component,
&rockchip_spdif_dai, 1);
if (ret) {
dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
ret = -ENOMEM;
goto err_;
}
ret = rockchip_pcm_platform_register(&pdev->dev);
if (ret) {
dev_err(&pdev->dev, "Could not register PCM: %d\n", ret);
goto err_;
}
dev_info(&pdev->dev, "spdif ready.\n");
return 0;
err_:
platform_set_drvdata(pdev, NULL);
return ret;
}
static int spdif_remove(struct platform_device *pdev)
{
rockchip_pcm_platform_unregister(&pdev->dev);
snd_soc_unregister_component(&pdev->dev);
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id rockchip_spdif_match[] = {
{ .compatible = "rockchip-spdif", },
{},
};
MODULE_DEVICE_TABLE(of, rockchip_spdif_match);
#endif
static struct platform_driver rockchip_spdif_driver = {
.probe = spdif_probe,
.remove = spdif_remove,
.driver = {
.name = "rockchip-spdif",
.of_match_table = of_match_ptr(rockchip_spdif_match),
},
};
module_platform_driver(rockchip_spdif_driver);
MODULE_AUTHOR("Sugar <sugar.zhang@rock-chips.com>");
MODULE_DESCRIPTION("Rockchip S/PDIF Controller Driver");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:rockchip-spdif");

View File

@@ -1,145 +0,0 @@
/*
* rk_spdif_card.c -- spdif card for rockchip
*
* Copyright (C) 2014 Fuzhou Rockchip Electronics Co., Ltd
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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/module.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/clk.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include "card_info.h"
#include "rk_pcm.h"
static int rk_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned long sclk;
int ret, ratio;
/* bmc: 2*32*fs*2 = 128fs */
ratio = 128;
switch (params_rate(params)) {
case 44100:
case 32000:
case 48000:
case 96000:
case 192000:
sclk = params_rate(params) * ratio;
break;
default:
pr_err("rk_spdif: params not support\n");
return -EINVAL;
}
ret = snd_soc_dai_set_sysclk(cpu_dai, 0,
sclk, SND_SOC_CLOCK_IN);
return ret;
}
static struct snd_soc_ops rk_spdif_ops = {
.hw_params = rk_hw_params,
};
static struct snd_soc_dai_link rk_dai = {
.name = "SPDIF",
.stream_name = "SPDIF PCM Playback",
.codec_dai_name = "rk-hdmi-spdif-hifi",
.ops = &rk_spdif_ops,
};
static struct snd_soc_card rockchip_spdif_card = {
.name = "RK-SPDIF-CARD",
.dai_link = &rk_dai,
.num_links = 1,
};
static int rockchip_spdif_card_probe(struct platform_device *pdev)
{
int ret;
struct snd_soc_card *card = &rockchip_spdif_card;
card->dev = &pdev->dev;
ret = rockchip_of_get_sound_card_info_(card, false);
if (ret) {
pr_err("%s() get sound card info failed:%d\n",
__func__, ret);
return ret;
}
ret = snd_soc_register_card(card);
if (ret)
pr_err("%s() register card failed:%d\n",
__func__, ret);
return ret;
}
static int rockchip_spdif_card_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
snd_soc_unregister_card(card);
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id rockchip_spdif_card_of_match[] = {
{ .compatible = "rockchip-spdif-card", },
{},
};
MODULE_DEVICE_TABLE(of, rockchip_spdif_card_of_match);
#endif /* CONFIG_OF */
static struct platform_driver rockchip_spdif_card_driver = {
.driver = {
.name = "rockchip-spdif-card",
.owner = THIS_MODULE,
.pm = &snd_soc_pm_ops,
.of_match_table = of_match_ptr(rockchip_spdif_card_of_match),
},
.probe = rockchip_spdif_card_probe,
.remove = rockchip_spdif_card_remove,
};
/* module_platform_driver(rockchip_spdif_card_driver); */
static int __init rockchip_spdif_init(void)
{
return platform_driver_register(&rockchip_spdif_card_driver);
};
late_initcall(rockchip_spdif_init);
static void __exit rockchip_spdif_exit(void)
{
platform_driver_unregister(&rockchip_spdif_card_driver);
}
module_exit(rockchip_spdif_exit);
MODULE_AUTHOR("hzb <hzb@rock-chips.com>");
MODULE_DESCRIPTION("ALSA SoC RK S/PDIF");
MODULE_LICENSE("GPL");

View File

@@ -1,234 +0,0 @@
/*
* rk29_wm8900.c -- SoC audio for rockchip
*
* Driver for rockchip wm8900 audio
*
* 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.
*
*
*/
#include <linux/module.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include "../codecs/wm8900.h"
#include "card_info.h"
#include "rk_pcm.h"
#include "rk_i2s.h"
#include <linux/clk.h>
#if 0
#define DBG(x...) printk(KERN_INFO x)
#else
#define DBG(x...)
#endif
static int rk29_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int pll_out = 0, dai_fmt = rtd->dai_link->dai_fmt;
int div_bclk,div_mclk;
int ret;
struct clk *general_pll;
DBG("Enter::%s----%d\n", __FUNCTION__, __LINE__);
/* set codec DAI configuration */
ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
if (ret < 0) {
printk("%s():failed to set the format for codec side\n", __FUNCTION__);
return ret;
}
/* set cpu DAI configuration */
ret = snd_soc_dai_set_fmt(cpu_dai, dai_fmt);
if (ret < 0) {
printk("%s():failed to set the format for cpu side\n", __FUNCTION__);
return ret;
}
switch(params_rate(params)) {
case 8000:
case 16000:
case 24000:
case 32000:
case 48000:
pll_out = 12288000;
break;
case 11025:
case 22050:
case 44100:
pll_out = 11289600;
break;
default:
DBG("Enter:%s, %d, Error rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
return -EINVAL;
break;
}
DBG("Enter:%s, %d, rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
//pll_out = 12000000;
//snd_soc_dai_set_pll(codec_dai, NULL, 12000000, pll_out);
snd_soc_dai_set_clkdiv(codec_dai, WM8900_LRCLK_MODE, 0x000);
if ((dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFM) {
snd_soc_dai_set_clkdiv(codec_dai, WM8900_BCLK_DIV, WM8900_BCLK_DIV_4);
snd_soc_dai_set_clkdiv(codec_dai, WM8900_DAC_LRCLK,(pll_out/4)/params_rate(params));
snd_soc_dai_set_clkdiv(codec_dai, WM8900_ADC_LRCLK,(pll_out/4)/params_rate(params));
} else {
general_pll=clk_get(NULL, "general_pll");
if(clk_get_rate(general_pll)>260000000)
{
div_bclk=(pll_out/4)/params_rate(params)-1;
div_mclk=3;
}
else if(clk_get_rate(general_pll)>130000000)
{
div_bclk=(pll_out/2)/params_rate(params)-1;
div_mclk=1;
}
else
{
pll_out=pll_out/4;
div_bclk=(pll_out)/params_rate(params)-1;
div_mclk=0;
}
DBG("func is%s,gpll=%ld,pll_out=%u,div_mclk=%d\n",
__FUNCTION__,clk_get_rate(general_pll),pll_out,div_mclk);
snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK,div_bclk);
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, div_mclk);
}
DBG("Enter:%s, %d, LRCK=%d\n",__FUNCTION__,__LINE__,(pll_out/4)/params_rate(params));
return 0;
}
static const struct snd_soc_dapm_widget wm8900_dapm_widgets[] = {
SND_SOC_DAPM_LINE("Audio Out", NULL),
SND_SOC_DAPM_LINE("Line in", NULL),
SND_SOC_DAPM_MIC("Micn", NULL),
SND_SOC_DAPM_MIC("Micp", NULL),
};
static const struct snd_soc_dapm_route audio_map[]= {
{"Audio Out", NULL, "HP_L"},
{"Audio Out", NULL, "HP_R"},
{"Line in", NULL, "RINPUT1"},
{"Line in", NULL, "LINPUT1"},
{"Micn", NULL, "RINPUT2"},
{"Micp", NULL, "LINPUT2"},
};
/*
* Logic for a wm8900 as connected on a rockchip board.
*/
static int rk29_wm8900_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
/* Add specific widgets */
snd_soc_dapm_new_controls(dapm, wm8900_dapm_widgets,
ARRAY_SIZE(wm8900_dapm_widgets));
DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
/* Set up specific audio path audio_mapnects */
snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
snd_soc_dapm_nc_pin(dapm, "HP_L");
DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
snd_soc_dapm_nc_pin(dapm, "HP_R");
DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
snd_soc_dapm_sync(dapm);
DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
return 0;
}
static struct snd_soc_ops rk29_ops = {
.hw_params = rk29_hw_params,
};
static struct snd_soc_dai_link rk29_dai = {
.name = "WM8900",
.stream_name = "WM8900 PCM",
.codec_dai_name = "WM8900 HiFi",
.init = rk29_wm8900_init,
.ops = &rk29_ops,
};
static struct snd_soc_card rockchip_wm8900_snd_card = {
.name = "RK_WM8900",
.dai_link = &rk29_dai,
.num_links = 1,
};
static int rockchip_wm8900_audio_probe(struct platform_device *pdev)
{
int ret;
struct snd_soc_card *card = &rockchip_wm8900_snd_card;
card->dev = &pdev->dev;
ret = rockchip_of_get_sound_card_info(card);
if (ret) {
printk("%s() get sound card info failed:%d\n", __FUNCTION__, ret);
return ret;
}
ret = snd_soc_register_card(card);
if (ret)
printk("%s() register card failed:%d\n", __FUNCTION__, ret);
return ret;
}
static int rockchip_wm8900_audio_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
snd_soc_unregister_card(card);
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id rockchip_wm8900_of_match[] = {
{ .compatible = "rockchip-wm8900", },
{},
};
MODULE_DEVICE_TABLE(of, rockchip_wm8900_of_match);
#endif /* CONFIG_OF */
static struct platform_driver rockchip_wm8900_audio_driver = {
.driver = {
.name = "rockchip-wm8900",
.owner = THIS_MODULE,
.pm = &snd_soc_pm_ops,
.of_match_table = of_match_ptr(rockchip_wm8900_of_match),
},
.probe = rockchip_wm8900_audio_probe,
.remove = rockchip_wm8900_audio_remove,
};
module_platform_driver(rockchip_wm8900_audio_driver);
/* Module information */
MODULE_AUTHOR("rockchip");
MODULE_DESCRIPTION("ROCKCHIP i2s ASoC Interface");
MODULE_LICENSE("GPL");

View File

@@ -1,185 +0,0 @@
/*
* rk29_wm8988.c -- SoC audio for rockchip
*
* Driver for rockchip wm8988 audio
*
* 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.
*
*
*/
#include <linux/module.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include "../codecs/wm8988.h"
#include "card_info.h"
#include "rk_pcm.h"
#include "rk_i2s.h"
#if 0
#define DBG(x...) printk(KERN_INFO x)
#else
#define DBG(x...)
#endif
//static void *rk29_speaker = NULL;
static int rk29_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int dai_fmt = rtd->dai_link->dai_fmt;
int ret;
DBG("Enter::%s----%d\n", __FUNCTION__, __LINE__);
/* set codec DAI configuration */
ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
if (ret < 0) {
printk("%s():failed to set the format for codec side\n", __FUNCTION__);
return ret;
}
/* set cpu DAI configuration */
ret = snd_soc_dai_set_fmt(cpu_dai, dai_fmt);
if (ret < 0) {
printk("%s():failed to set the format for cpu side\n", __FUNCTION__);
return ret;
}
return 0;
}
static const struct snd_soc_dapm_widget rk29_dapm_widgets[] = {
SND_SOC_DAPM_LINE("Audio Out", NULL),
SND_SOC_DAPM_LINE("Line in", NULL),
SND_SOC_DAPM_MIC("Micn", NULL),
SND_SOC_DAPM_MIC("Micp", NULL),
};
static const struct snd_soc_dapm_route audio_map[]= {
{"Audio Out", NULL, "LOUT1"},
{"Audio Out", NULL, "ROUT1"},
{"Line in", NULL, "RINPUT1"},
{"Line in", NULL, "LINPUT1"},
{"Micn", NULL, "RINPUT2"},
{"Micp", NULL, "LINPUT2"},
};
/*
* Logic for a wm8988 as connected on a rockchip board.
*/
static int rk29_wm8988_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
int ret;
DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
ret = snd_soc_dai_set_sysclk(codec_dai, 0,
/*12000000*/11289600, SND_SOC_CLOCK_IN);
if (ret < 0) {
printk(KERN_ERR "Failed to set WM8988 SYSCLK: %d\n", ret);
return ret;
}
/* Add specific widgets */
snd_soc_dapm_new_controls(dapm, rk29_dapm_widgets,
ARRAY_SIZE(rk29_dapm_widgets));
//snd_soc_dapm_nc_pin(codec, "LOUT2");
//snd_soc_dapm_nc_pin(codec, "ROUT2");
/* Set up specific audio path audio_mapnects */
snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
snd_soc_dapm_sync(dapm);
return 0;
}
static struct snd_soc_ops rk29_ops = {
.hw_params = rk29_hw_params,
};
static struct snd_soc_dai_link rk29_dai = {
.name = "WM8988",
.stream_name = "WM8988 PCM",
.codec_dai_name = "WM8988 HiFi",
.init = rk29_wm8988_init,
.ops = &rk29_ops,
};
static struct snd_soc_card rockchip_wm8988_snd_card = {
.name = "RK_WM8988",
.dai_link = &rk29_dai,
.num_links = 1,
};
static int rockchip_wm8988_audio_probe(struct platform_device *pdev)
{
int ret;
struct snd_soc_card *card = &rockchip_wm8988_snd_card;
card->dev = &pdev->dev;
ret = rockchip_of_get_sound_card_info(card);
if (ret) {
printk("%s() get sound card info failed:%d\n", __FUNCTION__, ret);
return ret;
}
ret = snd_soc_register_card(card);
if (ret)
printk("%s() register card failed:%d\n", __FUNCTION__, ret);
return ret;
}
static int rockchip_wm8988_audio_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
snd_soc_unregister_card(card);
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id rockchip_wm8988_of_match[] = {
{ .compatible = "rockchip-wm8988", },
{},
};
MODULE_DEVICE_TABLE(of, rockchip_wm8988_of_match);
#endif /* CONFIG_OF */
static struct platform_driver rockchip_wm8988_audio_driver = {
.driver = {
.name = "rockchip-wm8988",
.owner = THIS_MODULE,
.pm = &snd_soc_pm_ops,
.of_match_table = of_match_ptr(rockchip_wm8988_of_match),
},
.probe = rockchip_wm8988_audio_probe,
.remove = rockchip_wm8988_audio_remove,
};
module_platform_driver(rockchip_wm8988_audio_driver);
/* Module information */
MODULE_AUTHOR("rockchip");
MODULE_DESCRIPTION("ROCKCHIP i2s ASoC Interface");
MODULE_LICENSE("GPL");

View File

@@ -1,435 +0,0 @@
/*
* rk29_wm8994.c -- SoC audio for rockchip
*
* Driver for rockchip wm8994 audio
* Copyright (C) 2009 lhh
*
* 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.
*
*
*/
#include <linux/module.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include "../codecs/wm8994.h"
#include "card_info.h"
#include "rk_pcm.h"
#include "rk_i2s.h"
#include <linux/clk.h>
#if 0
#define DBG(x...) printk(KERN_INFO x)
#else
#define DBG(x...)
#endif
static int rk29_aif1_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int pll_out = 0, dai_fmt = rtd->dai_link->dai_fmt;
int div_bclk,div_mclk;
int ret;
struct clk *general_pll;
DBG("Enter::%s----%d\n", __FUNCTION__, __LINE__);
/* set codec DAI configuration */
ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
if (ret < 0) {
printk("%s():failed to set the format for codec side\n", __FUNCTION__);
return ret;
}
/* set cpu DAI configuration */
ret = snd_soc_dai_set_fmt(cpu_dai, dai_fmt);
if (ret < 0) {
printk("%s():failed to set the format for cpu side\n", __FUNCTION__);
return ret;
}
switch(params_rate(params)) {
case 8000:
case 16000:
case 24000:
case 32000:
case 48000:
pll_out = 12288000;
break;
case 11025:
case 22050:
case 44100:
pll_out = 11289600;
break;
default:
DBG("Enter:%s, %d, Error rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
return -EINVAL;
}
// DBG("Enter:%s, %d, rate=%d,pll_out = %d\n",__FUNCTION__,__LINE__,params_rate(params),pll_out);
#ifdef CONFIG_ARCH_RK29
general_pll=clk_get(NULL, "general_pll");
if(clk_get_rate(general_pll)>260000000)
{
div_bclk=(pll_out/4)/params_rate(params)-1;
div_mclk=3;
}
else if(clk_get_rate(general_pll)>130000000)
{
div_bclk=(pll_out/2)/params_rate(params)-1;
div_mclk=1;
}
else
{//96M
pll_out=pll_out/4;
div_bclk=(pll_out)/params_rate(params)-1;
div_mclk=0;
}
#else
div_bclk=(pll_out/4)/params_rate(params)-1;
div_mclk=3;
#endif
DBG("func is%s,gpll=%ld,pll_out=%d,div_mclk=%d\n",__FUNCTION__,clk_get_rate(general_pll),pll_out,div_mclk);
ret = snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
if(ret < 0)
{
DBG("rk29_hw_params_wm8994:failed to set the cpu sysclk for codec side\n");
return ret;
}
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK,div_bclk);
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, div_mclk);
DBG("Enter:%s, %d, LRCK=%d\n",__FUNCTION__,__LINE__,(pll_out/4)/params_rate(params));
if(div_mclk== 3)
{//MCLK == 11289600 or 12288000
ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_MCLK1, pll_out, 0);
if (ret < 0) {
DBG("rk29_hw_params_wm8994:failed to set the sysclk for codec side\n");
return ret;
}
}
else
{
/* set the codec FLL */
ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL1, WM8994_FLL_SRC_MCLK1, pll_out,
params_rate(params) * 256);
if (ret < 0)
{
printk("%s: snd_soc_dai_set_pll err =%d\n",__FUNCTION__,ret);
return ret;
}
/* set the codec system clock */
ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL1,
params_rate(params) * 256, SND_SOC_CLOCK_IN);
if (ret < 0)
{
printk("%s: snd_soc_dai_set_sysclk err =%d\n",__FUNCTION__,ret);
return ret;
}
}
return 0;
}
static int rk29_aif2_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int pll_out = 0;
int div_bclk,div_mclk;
int ret;
struct clk *general_pll;
//change to 8Khz
// params->intervals[SNDRV_PCM_HW_PARAM_RATE - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL].min = 8000;
DBG("Enter:%s, %d, rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
// if (params_rate(params) != 8000)
// return -EINVAL;
/* set codec DAI configuration */
ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_A |
SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_CBM_CFM);
if (ret < 0)
{
printk("%s: snd_soc_dai_set_fmt err =%d\n",__FUNCTION__,ret);
return ret;
}
switch(params_rate(params)) {
case 8000:
case 16000:
case 24000:
case 32000:
case 48000:
pll_out = 12288000;
break;
case 11025:
case 22050:
case 44100:
pll_out = 11289600;
break;
default:
DBG("Enter:%s, %d, Error rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
return -EINVAL;
}
general_pll=clk_get(NULL, "general_pll");
if(clk_get_rate(general_pll)>260000000)
{
div_bclk=(pll_out/4)/params_rate(params)-1;
div_mclk=3;
}
else if(clk_get_rate(general_pll)>130000000)
{
div_bclk=(pll_out/2)/params_rate(params)-1;
div_mclk=1;
}
else
{//96M
pll_out=pll_out/4;
div_bclk=(pll_out)/params_rate(params)-1;
div_mclk=0;
}
DBG("func is%s,gpll=%ld,pll_out=%d,div_mclk=%d\n",
__FUNCTION__,clk_get_rate(general_pll),pll_out,div_mclk);
ret = snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
if(ret < 0)
{
DBG("rk29_hw_params_wm8994:failed to set the cpu sysclk for codec side\n");
return ret;
}
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK,div_bclk);
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, div_mclk);
DBG("Enter:%s, %d, LRCK=%d\n",__FUNCTION__,__LINE__,(pll_out/4)/params_rate(params));
/* set the codec FLL */
ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL2, WM8994_FLL_SRC_MCLK1, pll_out,
8000 * 256);
if (ret < 0)
{
printk("%s: snd_soc_dai_set_pll err =%d\n",__FUNCTION__,ret);
return ret;
}
/* set the codec system clock */
ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL2,
8000 * 256, SND_SOC_CLOCK_IN);
if (ret < 0)
{
printk("%s: snd_soc_dai_set_sysclk err =%d\n",__FUNCTION__,ret);
return ret;
}
return ret;
}
static const struct snd_soc_dapm_widget rk29_dapm_widgets[] = {
SND_SOC_DAPM_SPK("Ext Left Spk", NULL),
SND_SOC_DAPM_SPK("Ext Right Spk", NULL),
SND_SOC_DAPM_SPK("Ext Rcv", NULL),
SND_SOC_DAPM_HP("Headset Stereophone", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
SND_SOC_DAPM_MIC("Main Mic", NULL),
SND_SOC_DAPM_MIC("2nd Mic", NULL),
// SND_SOC_DAPM_LINE("Radio In", NULL),
SND_SOC_DAPM_LINE("Line In", NULL),
SND_SOC_DAPM_LINE("Line Out", NULL),
};
static const struct snd_soc_dapm_route rk29_dapm_routes[] = {
{"Ext Left Spk", NULL, "SPKOUTLP"},
{"Ext Left Spk", NULL, "SPKOUTLN"},
{"Ext Right Spk", NULL, "SPKOUTRP"},
{"Ext Right Spk", NULL, "SPKOUTRN"},
{"Ext Rcv", NULL, "HPOUT2N"},
{"Ext Rcv", NULL, "HPOUT2P"},
{"Headset Stereophone", NULL, "HPOUT1L"},
{"Headset Stereophone", NULL, "HPOUT1R"},
{"IN1LN", NULL, "Headset Mic"},
{"IN1LP", NULL, "Headset Mic"},
{"IN1LN", NULL, "2nd Mic"},
{"IN1LP", NULL, "2nd Mic"},
{"IN1RN", NULL, "Main Mic"},
{"IN1RP", NULL, "Main Mic"},
// {"IN2LN", NULL, "Radio In"},
// {"IN2RN", NULL, "Radio In"},
{"IN2LP:VXRN", NULL, "Line In"},
{"IN2RP:VXRP", NULL, "Line In"},
{"Line Out", NULL, "LINEOUT1N"},
{"Line Out", NULL, "LINEOUT1P"},
};
static int rk29_wm8994_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
// int ret;
DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
/* add goni specific widgets */
snd_soc_dapm_new_controls(dapm, rk29_dapm_widgets,
ARRAY_SIZE(rk29_dapm_widgets));
/* set up goni specific audio routes */
snd_soc_dapm_add_routes(dapm, rk29_dapm_routes,
ARRAY_SIZE(rk29_dapm_routes));
/* set endpoints to not connected */
// snd_soc_dapm_nc_pin(dapm, "IN2LP:VXRN");
// snd_soc_dapm_nc_pin(dapm, "IN2RP:VXRP");
snd_soc_dapm_nc_pin(dapm, "IN2LN");
snd_soc_dapm_nc_pin(dapm, "IN2RN");
// snd_soc_dapm_nc_pin(dapm, "LINEOUT1N");
// snd_soc_dapm_nc_pin(dapm, "LINEOUT1P");
snd_soc_dapm_nc_pin(dapm, "LINEOUT2N");
snd_soc_dapm_nc_pin(dapm, "LINEOUT2P");
snd_soc_dapm_sync(dapm);
/* Headset jack detection */
/* ret = snd_soc_jack_new(codec, "Headset Jack",
SND_JACK_HEADSET | SND_JACK_MECHANICAL | SND_JACK_AVOUT,
&jack);
if (ret)
return ret;
ret = snd_soc_jack_add_pins(&jack, ARRAY_SIZE(jack_pins), jack_pins);
if (ret)
return ret;
ret = snd_soc_jack_add_gpios(&jack, ARRAY_SIZE(jack_gpios), jack_gpios);
if (ret)
return ret;
*/
return 0;
}
static struct snd_soc_ops rk29_aif1_ops = {
.hw_params = rk29_aif1_hw_params,
};
static struct snd_soc_ops rk29_aif2_ops = {
.hw_params = rk29_aif2_hw_params,
};
static struct snd_soc_dai_driver voice_dai = {
.name = "rk29-voice-dai",
.id = 0,
.playback = {
.channels_min = 1,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_8000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,},
.capture = {
.channels_min = 1,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_8000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,},
};
static struct snd_soc_dai_link rk29_dai[] = {
{
.name = "WM8994 I2S1",
.stream_name = "WM8994 PCM",
.codec_dai_name = "wm8994-aif1",
.ops = &rk29_aif1_ops,
.init = rk29_wm8994_init,
},
{
.name = "WM8994 I2S2",
.stream_name = "WM8994 PCM",
.codec_dai_name = "wm8994-aif2",
.ops = &rk29_aif2_ops,
},
};
static struct snd_soc_card rockchip_wm8994_snd_card = {
.name = "RK_WM8994",
.dai_link = rk29_dai,
.num_links = ARRAY_SIZE(rk29_dai),
};
static int rockchip_wm8994_audio_probe(struct platform_device *pdev)
{
int ret;
struct snd_soc_card *card = &rockchip_wm8994_snd_card;
card->dev = &pdev->dev;
ret = rockchip_of_get_sound_card_info(card);
if (ret) {
printk("%s() get sound card info failed:%d\n", __FUNCTION__, ret);
return ret;
}
ret = snd_soc_register_card(card);
if (ret)
printk("%s() register card failed:%d\n", __FUNCTION__, ret);
return ret;
}
static int rockchip_wm8994_audio_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
snd_soc_unregister_card(card);
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id rockchip_wm8994_of_match[] = {
{ .compatible = "rockchip-wm8994", },
{},
};
MODULE_DEVICE_TABLE(of, rockchip_wm8994_of_match);
#endif /* CONFIG_OF */
static struct platform_driver rockchip_wm8994_audio_driver = {
.driver = {
.name = "rockchip-wm8994",
.owner = THIS_MODULE,
.pm = &snd_soc_pm_ops,
.of_match_table = of_match_ptr(rockchip_wm8994_of_match),
},
.probe = rockchip_wm8994_audio_probe,
.remove = rockchip_wm8994_audio_remove,
};
module_platform_driver(rockchip_wm8994_audio_driver);
/* Module information */
MODULE_AUTHOR("rockchip");
MODULE_DESCRIPTION("ROCKCHIP i2s ASoC Interface");
MODULE_LICENSE("GPL");