mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 11:50:43 +09:00
ASoC: rockchip: cleanup codes
Change-Id: Ieacbcc8311fa683394c57a21c69099620b294ffc Signed-off-by: Sugar Zhang <sugar.zhang@rock-chips.com>
This commit is contained in:
@@ -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");
|
||||
@@ -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 */
|
||||
@@ -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");
|
||||
@@ -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 */
|
||||
|
||||
@@ -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");
|
||||
@@ -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");
|
||||
|
||||
@@ -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");
|
||||
@@ -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");
|
||||
|
||||
@@ -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");
|
||||
@@ -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");
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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");
|
||||
@@ -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");
|
||||
@@ -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");
|
||||
@@ -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__ */
|
||||
@@ -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");
|
||||
@@ -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");
|
||||
@@ -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 */
|
||||
@@ -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");
|
||||
@@ -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");
|
||||
@@ -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");
|
||||
@@ -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");
|
||||
@@ -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");
|
||||
@@ -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");
|
||||
@@ -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");
|
||||
@@ -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");
|
||||
@@ -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");
|
||||
@@ -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");
|
||||
@@ -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");
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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");
|
||||
@@ -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");
|
||||
@@ -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");
|
||||
@@ -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");
|
||||
@@ -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");
|
||||
@@ -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");
|
||||
@@ -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");
|
||||
Reference in New Issue
Block a user