mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-09 12:17:12 +09:00
Add sound card 1 for HDMI i2s, RK616 codec:add path for tiny alsa
This commit is contained in:
@@ -327,7 +327,8 @@ CONFIG_SND_SOC=y
|
||||
CONFIG_SND_RK29_SOC=y
|
||||
CONFIG_SND_I2S_USE_33V=y
|
||||
CONFIG_SND_I2S_DMA_EVENT_STATIC=y
|
||||
CONFIG_SND_RK29_SOC_RK616=y
|
||||
CONFIG_SND_RK_SOC_HDMI_I2S=y
|
||||
CONFIG_SND_RK_SOC_RK616=y
|
||||
CONFIG_SND_RK29_CODEC_SOC_SLAVE=y
|
||||
CONFIG_UHID=y
|
||||
CONFIG_HID_A4TECH=y
|
||||
|
||||
@@ -327,8 +327,8 @@ CONFIG_SND=y
|
||||
CONFIG_SND_SOC=y
|
||||
CONFIG_SND_RK29_SOC=y
|
||||
CONFIG_SND_I2S_DMA_EVENT_DYNAMIC=y
|
||||
CONFIG_SND_RK_SOC_SPDIF=y
|
||||
CONFIG_SND_RK29_SOC_RK616=y
|
||||
CONFIG_SND_RK_SOC_HDMI_I2S=y
|
||||
CONFIG_SND_RK_SOC_RK616=y
|
||||
CONFIG_SND_RK29_CODEC_SOC_SLAVE=y
|
||||
CONFIG_UHID=y
|
||||
CONFIG_HID_A4TECH=y
|
||||
|
||||
@@ -326,7 +326,8 @@ CONFIG_SND=y
|
||||
CONFIG_SND_SOC=y
|
||||
CONFIG_SND_RK29_SOC=y
|
||||
CONFIG_SND_I2S_DMA_EVENT_STATIC=y
|
||||
CONFIG_SND_RK29_SOC_RK616=y
|
||||
CONFIG_SND_RK_SOC_HDMI_I2S=y
|
||||
CONFIG_SND_RK_SOC_RK616=y
|
||||
CONFIG_SND_RK29_CODEC_SOC_SLAVE=y
|
||||
CONFIG_UHID=y
|
||||
CONFIG_HID_A4TECH=y
|
||||
|
||||
@@ -13,7 +13,12 @@ enum{
|
||||
INPUT_IIS,
|
||||
INPUT_SPDIF
|
||||
};
|
||||
|
||||
#if defined(CONFIG_SND_RK_SOC_HDMI_SPDIF)
|
||||
#define HDMI_CODEC_SOURCE_SELECT INPUT_SPDIF
|
||||
#else
|
||||
#define HDMI_CODEC_SOURCE_SELECT INPUT_IIS
|
||||
#endif
|
||||
|
||||
extern void rk616_hdmi_control_output(int enable);
|
||||
extern int rk616_hdmi_register_hdcp_callbacks(void (*hdcp_cb)(void),
|
||||
|
||||
@@ -42,7 +42,8 @@ config SND_SOC_ALL_CODECS
|
||||
select SND_SOC_PCM3008
|
||||
select SND_SOC_SGTL5000 if I2C
|
||||
select SND_SOC_SN95031 if INTEL_SCU_IPC
|
||||
select SND_SOC_SPDIF
|
||||
select SND_SOC_HDMI_I2S
|
||||
select SND_SOC_HDMI_SPDIF
|
||||
select SND_SOC_SSM2602 if SND_SOC_I2C_AND_SPI
|
||||
select SND_SOC_STAC9766 if SND_SOC_AC97_BUS
|
||||
select SND_SOC_TLV320AIC23 if I2C
|
||||
@@ -230,7 +231,10 @@ config SND_SOC_SGTL5000
|
||||
config SND_SOC_SN95031
|
||||
tristate
|
||||
|
||||
config SND_SOC_SPDIF
|
||||
config SND_SOC_HDMI_I2S
|
||||
tristate
|
||||
|
||||
config SND_SOC_HDMI_SPDIF
|
||||
tristate
|
||||
|
||||
config SND_SOC_SSM2602
|
||||
|
||||
@@ -27,7 +27,8 @@ snd-soc-pcm3008-objs := pcm3008.o
|
||||
snd-soc-sgtl5000-objs := sgtl5000.o
|
||||
snd-soc-alc5623-objs := alc5623.o
|
||||
snd-soc-sn95031-objs := sn95031.o
|
||||
snd-soc-spdif-objs := spdif_transciever.o
|
||||
snd-soc-hdmi-i2s-objs := hdmi_i2s.o
|
||||
snd-soc-hdmi-spdif-objs := hdmi_spdif.o
|
||||
snd-soc-ssm2602-objs := ssm2602.o
|
||||
snd-soc-stac9766-objs := stac9766.o
|
||||
snd-soc-tlv320aic23-objs := tlv320aic23.o
|
||||
@@ -140,7 +141,8 @@ obj-$(CONFIG_SND_SOC_MAX9850) += snd-soc-max9850.o
|
||||
obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o
|
||||
obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o
|
||||
obj-$(CONFIG_SND_SOC_SN95031) +=snd-soc-sn95031.o
|
||||
obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif.o
|
||||
obj-$(CONFIG_SND_SOC_HDMI_I2S) += snd-soc-hdmi-i2s.o
|
||||
obj-$(CONFIG_SND_SOC_HDMI_SPDIF) += snd-soc-hdmi-spdif.o
|
||||
obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o
|
||||
obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o
|
||||
obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o
|
||||
|
||||
101
sound/soc/codecs/hdmi_i2s.c
Normal file
101
sound/soc/codecs/hdmi_i2s.c
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* hdmi_i2s.c -- HDMI i2s audio for rockchip
|
||||
*
|
||||
* Copyright 2013 Rockship
|
||||
* Author: chenjq <chenjq@rock-chips.com>
|
||||
*/
|
||||
|
||||
#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/board.h>
|
||||
#include <mach/hardware.h>
|
||||
#include <mach/io.h>
|
||||
#include <mach/gpio.h>
|
||||
#include <mach/iomux.h>
|
||||
|
||||
#if 0
|
||||
#define DBG(x...) printk(KERN_INFO "hdmi i2s:"x)
|
||||
#else
|
||||
#define DBG(x...) do { } while (0)
|
||||
#endif
|
||||
|
||||
struct snd_soc_dai_driver hdmi_i2s_dai = {
|
||||
.name = "rk-hdmi-i2s-hifi",
|
||||
.playback = {
|
||||
.stream_name = "HiFi Playback",
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.rates = (SNDRV_PCM_RATE_32000 |
|
||||
SNDRV_PCM_RATE_44100 |
|
||||
SNDRV_PCM_RATE_48000 |
|
||||
SNDRV_PCM_RATE_96000),
|
||||
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S20_3LE |
|
||||
SNDRV_PCM_FMTBIT_S24_LE),
|
||||
},
|
||||
};
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_hdmi_i2s;
|
||||
|
||||
static int hdmi_i2s_platform_probe(struct platform_device *pdev)
|
||||
{
|
||||
DBG("Entered %s\n", __func__);
|
||||
|
||||
return snd_soc_register_codec(&pdev->dev,
|
||||
&soc_codec_dev_hdmi_i2s,
|
||||
&hdmi_i2s_dai, 1);
|
||||
}
|
||||
|
||||
static int hdmi_i2s_platform_remove(struct platform_device *pdev)
|
||||
{
|
||||
DBG("Entered %s\n", __func__);
|
||||
|
||||
snd_soc_unregister_codec(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct platform_driver hdmi_i2s_driver = {
|
||||
.probe = hdmi_i2s_platform_probe,
|
||||
.remove = hdmi_i2s_platform_remove,
|
||||
.driver = {
|
||||
.name = "hdmi-i2s",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
static int __init hdmi_i2s_init(void)
|
||||
{
|
||||
DBG("Entered %s\n", __func__);
|
||||
|
||||
return platform_driver_register(&hdmi_i2s_driver);
|
||||
}
|
||||
|
||||
static void __exit hdmi_i2s_exit(void)
|
||||
{
|
||||
DBG("Entered %s\n", __func__);
|
||||
|
||||
platform_driver_unregister(&hdmi_i2s_driver);
|
||||
}
|
||||
module_init(hdmi_i2s_init);
|
||||
module_exit(hdmi_i2s_exit);
|
||||
|
||||
MODULE_DESCRIPTION("HDMI I2S Controller Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:hdmi-i2s");
|
||||
@@ -63,6 +63,10 @@ struct rk616_codec_priv {
|
||||
|
||||
int spk_ctl_gpio;
|
||||
int hp_ctl_gpio;
|
||||
|
||||
long int playback_path;
|
||||
long int capture_path;
|
||||
long int voice_call_path;
|
||||
};
|
||||
|
||||
static struct rk616_codec_priv *rk616_priv = NULL;
|
||||
@@ -899,6 +903,231 @@ static const struct snd_kcontrol_new rk616_snd_controls[] = {
|
||||
SOC_ENUM("I2S Loop Enable", rk616_loop_enum),
|
||||
};
|
||||
|
||||
//For tiny alsa playback/capture/voice call path
|
||||
static const char *rk616_playback_path_mode[] = {"OFF", "RCV", "SPK", "HP", "HP_NO_MIC", "BT", "SPK_HP", //0-6
|
||||
"RING_SPK", "RING_HP", "RING_HP_NO_MIC", "RING_SPK_HP"};//7-10
|
||||
|
||||
static const char *rk616_capture_path_mode[] = {"MIC OFF", "Main Mic", "Hands Free Mic", "BT Sco Mic"};
|
||||
|
||||
static const char *rk616_voice_call_path_mode[] = {"OFF", "RCV", "SPK", "HP", "HP_NO_MIC", "BT"};//0-5
|
||||
|
||||
static const SOC_ENUM_SINGLE_DECL(rk616_playback_path_type, 0, 0, rk616_playback_path_mode);
|
||||
|
||||
static const SOC_ENUM_SINGLE_DECL(rk616_capture_path_type, 0, 0, rk616_capture_path_mode);
|
||||
|
||||
static const SOC_ENUM_SINGLE_DECL(rk616_voice_call_path_type, 0, 0, rk616_voice_call_path_mode);
|
||||
|
||||
static int rk616_playback_path_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
if (!rk616_priv) {
|
||||
printk("%s : rk616_priv is NULL\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
DBG("%s : playback_path = %ld\n",__func__,ucontrol->value.integer.value[0]);
|
||||
|
||||
ucontrol->value.integer.value[0] = rk616_priv->playback_path;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk616_playback_path_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
|
||||
if (!rk616_priv) {
|
||||
printk("%s : rk616_priv is NULL\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (rk616_priv->playback_path == ucontrol->value.integer.value[0]){
|
||||
printk("%s : playback_path is not changed!\n",__func__);
|
||||
//return 0;
|
||||
}
|
||||
|
||||
rk616_priv->playback_path = ucontrol->value.integer.value[0];
|
||||
|
||||
DBG("%s : set playback_path = %ld, hdmi %s\n", __func__,
|
||||
rk616_priv->playback_path, get_hdmi_state() ? "in" : "out");
|
||||
|
||||
if(get_hdmi_state())
|
||||
return 0;
|
||||
|
||||
switch (rk616_priv->playback_path) {
|
||||
case OFF:
|
||||
snd_soc_dapm_disable_pin(&codec->dapm, "Headphone Jack");
|
||||
snd_soc_dapm_disable_pin(&codec->dapm, "Ext Spk");
|
||||
snd_soc_dapm_sync(&codec->dapm);
|
||||
break;
|
||||
case RCV:
|
||||
break;
|
||||
case SPK_PATH:
|
||||
case RING_SPK:
|
||||
snd_soc_dapm_disable_pin(&codec->dapm, "Headphone Jack");
|
||||
snd_soc_dapm_enable_pin(&codec->dapm, "Ext Spk");
|
||||
snd_soc_dapm_sync(&codec->dapm);
|
||||
break;
|
||||
case HP_PATH:
|
||||
case HP_NO_MIC:
|
||||
case RING_HP:
|
||||
case RING_HP_NO_MIC:
|
||||
snd_soc_dapm_disable_pin(&codec->dapm, "Ext Spk");
|
||||
snd_soc_dapm_enable_pin(&codec->dapm, "Headphone Jack");
|
||||
snd_soc_dapm_sync(&codec->dapm);
|
||||
break;
|
||||
case BT:
|
||||
break;
|
||||
case SPK_HP:
|
||||
case RING_SPK_HP:
|
||||
snd_soc_dapm_enable_pin(&codec->dapm, "Headphone Jack");
|
||||
snd_soc_dapm_enable_pin(&codec->dapm, "Ext Spk");
|
||||
snd_soc_dapm_sync(&codec->dapm);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk616_capture_path_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
if (!rk616_priv) {
|
||||
printk("%s : rk616_priv is NULL\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
DBG("%s : capture_path = %ld\n", __func__,
|
||||
ucontrol->value.integer.value[0]);
|
||||
|
||||
ucontrol->value.integer.value[0] = rk616_priv->capture_path;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk616_capture_path_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
|
||||
if (!rk616_priv) {
|
||||
printk("%s : rk616_priv is NULL\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (rk616_priv->capture_path == ucontrol->value.integer.value[0]){
|
||||
printk("%s : capture_path is not changed!\n", __func__);
|
||||
//return 0;
|
||||
}
|
||||
|
||||
rk616_priv->capture_path = ucontrol->value.integer.value[0];
|
||||
|
||||
DBG("%s : set capture_path = %ld\n", __func__, rk616_priv->capture_path);
|
||||
|
||||
switch (rk616_priv->capture_path) {
|
||||
case MIC_OFF:
|
||||
snd_soc_dapm_disable_pin(&codec->dapm, "Mic Jack");
|
||||
snd_soc_dapm_disable_pin(&codec->dapm, "Headset Jack");
|
||||
snd_soc_dapm_sync(&codec->dapm);
|
||||
break;
|
||||
case Main_Mic:
|
||||
snd_soc_dapm_enable_pin(&codec->dapm, "Mic Jack");
|
||||
snd_soc_dapm_disable_pin(&codec->dapm,"Headset Jack");
|
||||
snd_soc_dapm_sync(&codec->dapm);
|
||||
break;
|
||||
case Hands_Free_Mic:
|
||||
snd_soc_dapm_enable_pin(&codec->dapm, "Headset Jack");
|
||||
snd_soc_dapm_disable_pin(&codec->dapm, "Mic Jack");
|
||||
snd_soc_dapm_sync(&codec->dapm);
|
||||
break;
|
||||
case BT_Sco_Mic:
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk616_voice_call_path_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
if (!rk616_priv) {
|
||||
printk("%s : rk616_priv is NULL\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
DBG("%s : playback_path = %ld\n", __func__,
|
||||
ucontrol->value.integer.value[0]);
|
||||
|
||||
ucontrol->value.integer.value[0] = rk616_priv->voice_call_path;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk616_voice_call_path_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
|
||||
if (!rk616_priv) {
|
||||
printk("%s : rk616_priv is NULL\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (rk616_priv->voice_call_path == ucontrol->value.integer.value[0]){
|
||||
printk("%s : playback_path is not changed!\n",__func__);
|
||||
//return 0;
|
||||
}
|
||||
|
||||
rk616_priv->voice_call_path = ucontrol->value.integer.value[0];
|
||||
|
||||
DBG("%s : set playback_path = %ld\n", __func__,
|
||||
rk616_priv->voice_call_path);
|
||||
|
||||
switch (rk616_priv->voice_call_path) {
|
||||
case OFF:
|
||||
snd_soc_dapm_disable_pin(&codec->dapm, "Headphone Jack");
|
||||
snd_soc_dapm_disable_pin(&codec->dapm, "Ext Spk");
|
||||
snd_soc_dapm_sync(&codec->dapm);
|
||||
break;
|
||||
case RCV:
|
||||
break;
|
||||
case SPK_PATH:
|
||||
snd_soc_dapm_disable_pin(&codec->dapm, "Headphone Jack");
|
||||
snd_soc_dapm_enable_pin(&codec->dapm, "Ext Spk");
|
||||
snd_soc_dapm_sync(&codec->dapm);
|
||||
break;
|
||||
case HP_PATH:
|
||||
case HP_NO_MIC:
|
||||
snd_soc_dapm_disable_pin(&codec->dapm, "Ext Spk");
|
||||
snd_soc_dapm_enable_pin(&codec->dapm, "Headphone Jack");
|
||||
snd_soc_dapm_sync(&codec->dapm);
|
||||
break;
|
||||
case BT:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_kcontrol_new rk616_snd_path_controls[] = {
|
||||
SOC_ENUM_EXT("Playback Path", rk616_playback_path_type,
|
||||
rk616_playback_path_get, rk616_playback_path_put),
|
||||
|
||||
SOC_ENUM_EXT("Capture MIC Path", rk616_capture_path_type,
|
||||
rk616_capture_path_get, rk616_capture_path_put),
|
||||
|
||||
SOC_ENUM_EXT("Voice Call Path", rk616_voice_call_path_type,
|
||||
rk616_voice_call_path_get, rk616_voice_call_path_put),
|
||||
};
|
||||
|
||||
static int rk616_dacl_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
@@ -1683,18 +1912,18 @@ static struct rk616_reg_val_typ capture_power_up_list[] = {
|
||||
{0x89c, 0x7f}, //MICBIAS1 power up (bit 7, Vout = 1.7 * Vref(1.65V) = 2.8V (bit 3-5)
|
||||
{0x8a8, 0x09}, //ADCL/R power, and clear ADCL/R buf
|
||||
{0x8a8, 0x00}, //ADCL/R power, and clear ADCL/R buf
|
||||
{0x8c4, 0x57}, //L mod time
|
||||
//{0x904, 0x57}, //R mod time
|
||||
{0x828, 0x39}, //Set for Capture pop noise && enable agc control pga
|
||||
{0x8a4, 0x03}, //enable cross zero detect
|
||||
{0x8c0, 0x00}, //L agc choice mod 2
|
||||
//{0x900, 0x00}, //R agc choice mod 2
|
||||
{0x8d4, 0x13}, //max low
|
||||
{0x8d8, 0x08}, //max high
|
||||
{0x8dc, 0xc2}, //min low
|
||||
{0x8e0, 0x16}, //min high
|
||||
{0x8e4, 0x70}, //L enable agc
|
||||
//{0x924, 0x70}, //R enbale agc
|
||||
{0x8c4, 0x57}, //L mod time
|
||||
//{0x904, 0x57}, //R mod time
|
||||
{0x828, 0x39}, //Set for Capture pop noise && enable agc control pga
|
||||
{0x8a4, 0x03}, //enable cross zero detect
|
||||
{0x8c0, 0x00}, //L agc choice mod 2
|
||||
//{0x900, 0x00}, //R agc choice mod 2
|
||||
{0x8d4, 0x13}, //max low
|
||||
{0x8d8, 0x08}, //max high
|
||||
{0x8dc, 0xc2}, //min low
|
||||
{0x8e0, 0x16}, //min high
|
||||
{0x8e4, 0x70}, //L enable agc
|
||||
//{0x924, 0x70}, //R enbale agc
|
||||
};
|
||||
#define RK616_CODEC_CAPTURE_POWER_UP_LIST_LEN ARRAY_SIZE(capture_power_up_list)
|
||||
|
||||
@@ -1706,18 +1935,18 @@ static struct rk616_reg_val_typ capture_power_down_list[] = {
|
||||
{0x848, 0x1f}, //MIXINL power down and mute, MININL No selecting, MICMUX from BST_L
|
||||
{0x840, 0x99}, //BST_L power down, mute, and Single-Ended(bit 6), volume 0(bit 5)
|
||||
{0x83c, 0x7c}, //power down
|
||||
{0x8e4, 0x38}, //L disable agc
|
||||
//{0x924, 0x38}, //R disbale agc
|
||||
{0x8c4, 0x25},
|
||||
//{0x904, 0x25},
|
||||
{0x828, 0x09},
|
||||
{0x8a4, 0x0F},
|
||||
{0x8c0, 0x10},
|
||||
//{0x900, 0x10},
|
||||
{0x8d4, 0x26},
|
||||
{0x8d8, 0x40},
|
||||
{0x8dc, 0x36},
|
||||
{0x8e0, 0x20},
|
||||
{0x8e4, 0x38}, //L disable agc
|
||||
//{0x924, 0x38}, //R disbale agc
|
||||
{0x8c4, 0x25},
|
||||
//{0x904, 0x25},
|
||||
{0x828, 0x09},
|
||||
{0x8a4, 0x0F},
|
||||
{0x8c0, 0x10},
|
||||
//{0x900, 0x10},
|
||||
{0x8d4, 0x26},
|
||||
{0x8d8, 0x40},
|
||||
{0x8dc, 0x36},
|
||||
{0x8e0, 0x20},
|
||||
};
|
||||
#define RK616_CODEC_CAPTURE_POWER_DOWN_LIST_LEN ARRAY_SIZE(capture_power_down_list)
|
||||
|
||||
@@ -1736,11 +1965,11 @@ static int rk616_codec_power_up(int type)
|
||||
type == RK616_CODEC_CAPTURE ? "capture" : "");
|
||||
|
||||
if (type == RK616_CODEC_PALYBACK) {
|
||||
if(! get_hdmi_state())
|
||||
for (i = 0; i < RK616_CODEC_PALYBACK_POWER_UP_LIST_LEN; i++) {
|
||||
snd_soc_write(codec, palyback_power_up_list[i].reg,
|
||||
palyback_power_up_list[i].value);
|
||||
}
|
||||
codec_set_spk(!get_hdmi_state());
|
||||
} else if (type == RK616_CODEC_CAPTURE) {
|
||||
for (i = 0; i < RK616_CODEC_CAPTURE_POWER_UP_LIST_LEN; i++) {
|
||||
snd_soc_write(codec, capture_power_up_list[i].reg,
|
||||
|
||||
@@ -747,6 +747,27 @@ enum {
|
||||
RK616_STEREO,
|
||||
};
|
||||
|
||||
enum {
|
||||
OFF,
|
||||
RCV,
|
||||
SPK_PATH,
|
||||
HP_PATH,
|
||||
HP_NO_MIC,
|
||||
BT,
|
||||
SPK_HP,
|
||||
RING_SPK,
|
||||
RING_HP,
|
||||
RING_HP_NO_MIC,
|
||||
RING_SPK_HP,
|
||||
};
|
||||
|
||||
enum {
|
||||
MIC_OFF,
|
||||
Main_Mic,
|
||||
Hands_Free_Mic,
|
||||
BT_Sco_Mic,
|
||||
};
|
||||
|
||||
struct rk616_reg_val_typ {
|
||||
unsigned int reg;
|
||||
unsigned int value;
|
||||
|
||||
@@ -9,6 +9,9 @@ config SND_RK29_SOC
|
||||
config SND_RK29_SOC_I2S
|
||||
tristate
|
||||
|
||||
config SND_RK_SOC_SPDIF
|
||||
tristate
|
||||
|
||||
config SND_RK29_SOC_I2S_8CH
|
||||
bool "Soc RK29 I2S 8 Channel support(I2S0)"
|
||||
default y
|
||||
@@ -54,9 +57,6 @@ config SND_RK_SOC_I2S2_2CH
|
||||
help
|
||||
This supports the use of the 2 Channel I2S2 interface on rk30 processors.
|
||||
|
||||
config SND_ROCKCHIP_SPDIF
|
||||
tristate
|
||||
select SND_SOC_SPDIF
|
||||
if SND_RK29_SOC_I2S_2CH || SND_RK29_SOC_I2S_8CH || SND_RK_SOC_I2S2_2CH
|
||||
choice
|
||||
bool "Set i2s on DMA event mode"
|
||||
@@ -68,21 +68,24 @@ choice
|
||||
tristate "static mode"
|
||||
endchoice
|
||||
endif
|
||||
config SND_RK_SOC_SPDIF
|
||||
bool "spdif support for rockchip rk29 or rk30"
|
||||
depends on SND_RK29_SOC
|
||||
select SND_ROCKCHIP_SPDIF
|
||||
help
|
||||
Say Y if you want to add support for SoC audio on rockchip
|
||||
with the spdif.
|
||||
|
||||
config SND_RK29_SOC_SPDIF
|
||||
bool "Soc RK29 SPDIF support"
|
||||
depends on SND_RK29_SOC
|
||||
depends on SND_RK29_SOC_I2S
|
||||
help
|
||||
This supports the use of SPDIF interface on rk29 processors
|
||||
|
||||
|
||||
if SND_RK29_SOC && RK_HDMI
|
||||
choice
|
||||
bool "Set audio support for HDMI"
|
||||
default SND_RK_SOC_HDMI_I2S
|
||||
config SND_RK_SOC_HDMI_I2S
|
||||
select SND_RK29_SOC_I2S
|
||||
select SND_SOC_HDMI_I2S
|
||||
tristate "HDMI use I2S"
|
||||
|
||||
config SND_RK_SOC_HDMI_SPDIF
|
||||
depends on SND_RK_SOC_RK616
|
||||
select SND_RK_SOC_SPDIF
|
||||
select SND_SOC_HDMI_SPDIF
|
||||
tristate "HDMI use SPDIF"
|
||||
endchoice
|
||||
endif
|
||||
|
||||
config SND_RK29_SOC_ES8323
|
||||
tristate "SoC I2S Audio support for rockchip - ES8323"
|
||||
depends on SND_RK29_SOC
|
||||
@@ -256,14 +259,6 @@ config SND_RK29_SOC_RK1000
|
||||
Say Y if you want to add support for SoC audio on rockchip
|
||||
with the RK1000.
|
||||
|
||||
config SND_RK29_SOC_HDMI
|
||||
tristate "SoC I2S Audio support for rockchip - HDMI"
|
||||
depends on SND_RK29_SOC && HDMI_ITV
|
||||
select SND_RK29_SOC_I2S
|
||||
help
|
||||
Say Y if you want to add support for SoC audio on rockchip
|
||||
with the HDMI.
|
||||
|
||||
config SND_RK29_SOC_RK610
|
||||
tristate "SoC I2S Audio support for rockchip - RK610"
|
||||
depends on SND_RK29_SOC && MFD_RK610
|
||||
@@ -273,7 +268,7 @@ config SND_RK29_SOC_RK610
|
||||
Say Y if you want to add support for SoC audio on rockchip
|
||||
with the RK610(JETTA).
|
||||
|
||||
config SND_RK29_SOC_RK616
|
||||
config SND_RK_SOC_RK616
|
||||
tristate "SoC I2S Audio support for rockchip - RK616"
|
||||
depends on SND_RK29_SOC && MFD_RK616
|
||||
select SND_RK29_SOC_I2S
|
||||
|
||||
@@ -5,11 +5,11 @@ snd-soc-rockchip-i2s-objs := rk29_i2s.o
|
||||
else
|
||||
snd-soc-rockchip-i2s-objs := rk30_i2s.o
|
||||
endif
|
||||
snd-soc-rockchip-spdif-objs := spdif.o
|
||||
snd-soc-rockchip-spdif-objs := rk_spdif.o
|
||||
|
||||
obj-$(CONFIG_SND_RK29_SOC) += snd-soc-rockchip.o
|
||||
obj-$(CONFIG_SND_RK29_SOC_I2S) += snd-soc-rockchip-i2s.o
|
||||
obj-$(CONFIG_SND_ROCKCHIP_SPDIF) += snd-soc-rockchip-spdif.o
|
||||
obj-$(CONFIG_SND_RK_SOC_SPDIF) += snd-soc-rockchip-spdif.o
|
||||
|
||||
# ROCKCHIP Machine Support
|
||||
snd-soc-wm8900-objs := rk29_wm8900.o
|
||||
@@ -27,13 +27,13 @@ snd-soc-aic3111-objs := rk29_aic3111.o
|
||||
snd-soc-wm8988-objs := rk29_wm8988.o
|
||||
snd-soc-rk1000-objs := rk29_rk1000codec.o
|
||||
snd-soc-wm8994-objs := rk29_wm8994.o
|
||||
snd-soc-hdmi-objs := rk29_hdmi.o
|
||||
snd-soc-rk610-objs := rk29_jetta_codec.o
|
||||
snd-soc-rk616-objs := rk_rk616.o
|
||||
snd-soc-aic3262-objs := rk29_aic3262.o
|
||||
snd-soc-rk2928-objs := rk2928-card.o
|
||||
snd-soc-es8323-objs := rk29_es8323.o
|
||||
snd-soc-rk_spdif-objs := rk_spdif.o
|
||||
snd-soc-hdmi-i2s-objs := rk_hdmi_i2s.o
|
||||
snd-soc-hdmi-spdif-objs := rk_hdmi_spdif.o
|
||||
|
||||
obj-$(CONFIG_SND_RK29_SOC_WM8994) += snd-soc-wm8994.o
|
||||
obj-$(CONFIG_SND_RK29_SOC_WM8988) += snd-soc-wm8988.o
|
||||
@@ -51,9 +51,9 @@ obj-$(CONFIG_SND_RK29_SOC_RK1000) += snd-soc-rk1000.o
|
||||
obj-$(CONFIG_SND_RK29_SOC_CS42L52) += snd-soc-cs42l52.o
|
||||
obj-$(CONFIG_SND_RK29_SOC_AIC3111) += snd-soc-aic3111.o
|
||||
obj-$(CONFIG_SND_RK29_SOC_AIC3262) += snd-soc-aic3262.o
|
||||
obj-$(CONFIG_SND_RK29_SOC_HDMI) += snd-soc-hdmi.o
|
||||
obj-$(CONFIG_SND_RK29_SOC_RK610) += snd-soc-rk610.o
|
||||
obj-$(CONFIG_SND_RK29_SOC_RK616) += snd-soc-rk616.o
|
||||
obj-$(CONFIG_SND_RK_SOC_SPDIF) += snd-soc-rk_spdif.o
|
||||
obj-$(CONFIG_SND_RK_SOC_RK616) += snd-soc-rk616.o
|
||||
obj-$(CONFIG_SND_RK_SOC_HDMI_I2S) += snd-soc-hdmi-i2s.o
|
||||
obj-$(CONFIG_SND_RK_SOC_HDMI_SPDIF) += snd-soc-hdmi-spdif.o
|
||||
obj-$(CONFIG_SND_RK_SOC_RK2928) += snd-soc-rk2928.o
|
||||
obj-$(CONFIG_SND_RK29_SOC_ES8323) += snd-soc-es8323.o
|
||||
|
||||
151
sound/soc/rk29/rk_hdmi_i2s.c
Normal file
151
sound/soc/rk29/rk_hdmi_i2s.c
Normal file
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* rk_hdmi_i2s.c -- HDMI i2s audio for rockchip
|
||||
*
|
||||
* Copyright 2013 Rockship
|
||||
* Author: chenjq <chenjq@rock-chips.com>
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <sound/soc.h>
|
||||
#include <mach/iomux.h>
|
||||
|
||||
#include "rk29_pcm.h"
|
||||
#include "rk29_i2s.h"
|
||||
|
||||
#if 0
|
||||
#define DBG(x...) printk(KERN_INFO "rk_hdmi_i2s:"x)
|
||||
#else
|
||||
#define DBG(x...) do { } while (0)
|
||||
#endif
|
||||
|
||||
|
||||
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;
|
||||
int ret;
|
||||
|
||||
DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
|
||||
|
||||
/* set cpu DAI configuration */
|
||||
#if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE)
|
||||
ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
|
||||
SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
|
||||
#endif
|
||||
#if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER)
|
||||
ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
|
||||
SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
|
||||
#endif
|
||||
if (ret < 0)
|
||||
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;
|
||||
}
|
||||
|
||||
DBG("Enter:%s, %d, rate=%d\n", __FUNCTION__, __LINE__, params_rate(params));
|
||||
|
||||
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 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_name = "hdmi-i2s",
|
||||
.platform_name = "rockchip-audio",
|
||||
.cpu_dai_name = "rk29_i2s.1",
|
||||
.codec_dai_name = "rk-hdmi-i2s-hifi",
|
||||
.ops = &hdmi_i2s_hifi_ops,
|
||||
};
|
||||
|
||||
static struct snd_soc_card snd_soc_card_hdmi_i2s = {
|
||||
.name = "RK-HDMI-I2S",
|
||||
.dai_link = &hdmi_i2s_dai,
|
||||
.num_links = 1,
|
||||
};
|
||||
|
||||
static struct platform_device *hdmi_i2s_snd_device;
|
||||
static struct platform_device *hdmi_i2s_device;
|
||||
|
||||
static int __init audio_card_init(void)
|
||||
{
|
||||
int ret =0;
|
||||
|
||||
DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
|
||||
|
||||
hdmi_i2s_device = platform_device_alloc("hdmi-i2s", -1);
|
||||
|
||||
if (!hdmi_i2s_device){
|
||||
printk("spdif:platform_device_alloc hdmi-i2s\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = platform_device_add(hdmi_i2s_device);
|
||||
if (ret) {
|
||||
printk("platform device add hdmi-i2s failed\n");
|
||||
|
||||
platform_device_put(hdmi_i2s_device);
|
||||
return ret;
|
||||
}
|
||||
DBG("Enter::%s----%d 1\n",__FUNCTION__,__LINE__);
|
||||
hdmi_i2s_snd_device = platform_device_alloc("soc-audio", -3);
|
||||
if (!hdmi_i2s_snd_device) {
|
||||
printk("platform device allocation failed\n");
|
||||
|
||||
platform_device_put(hdmi_i2s_device);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
platform_set_drvdata(hdmi_i2s_snd_device, &snd_soc_card_hdmi_i2s);
|
||||
ret = platform_device_add(hdmi_i2s_snd_device);
|
||||
if (ret) {
|
||||
printk("platform device add soc-audio failed\n");
|
||||
|
||||
platform_device_put(hdmi_i2s_device);
|
||||
platform_device_put(hdmi_i2s_snd_device);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit audio_card_exit(void)
|
||||
{
|
||||
platform_device_unregister(hdmi_i2s_snd_device);
|
||||
}
|
||||
|
||||
late_initcall(audio_card_init);
|
||||
module_exit(audio_card_exit);
|
||||
/* Module information */
|
||||
MODULE_AUTHOR("rockchip");
|
||||
MODULE_DESCRIPTION("ROCKCHIP hdmi i2s ASoC Interface");
|
||||
MODULE_LICENSE("GPL");
|
||||
186
sound/soc/rk29/rk_hdmi_spdif.c
Normal file
186
sound/soc/rk29/rk_hdmi_spdif.c
Normal file
@@ -0,0 +1,186 @@
|
||||
/*$_FOR_ROCKCHIP_RBOX_$*/
|
||||
/*$_rbox_$_modify_$_huangzhibao for spdif output*/
|
||||
|
||||
/*
|
||||
* smdk_spdif.c -- S/PDIF audio for SMDK
|
||||
*
|
||||
* Copyright 2010 Samsung Electronics Co. Ltd.
|
||||
*
|
||||
* 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/clk.h>
|
||||
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include <mach/iomux.h>
|
||||
|
||||
#if 0
|
||||
#define RK_SPDIF_DBG(x...) printk(KERN_INFO "rk_hdmi_spdif:"x)
|
||||
#else
|
||||
#define RK_SPDIF_DBG(x...) do { } while (0)
|
||||
#endif
|
||||
|
||||
|
||||
static int set_audio_clock_rate(unsigned long pll_rate,
|
||||
unsigned long audio_rate)
|
||||
{
|
||||
struct clk *hclk_spdif, *sclk_spdif;
|
||||
|
||||
#if defined (CONFIG_ARCH_RK30) || (CONFIG_ARCH_RK3188)
|
||||
hclk_spdif = clk_get(NULL, "hclk_spdif");
|
||||
if (IS_ERR(hclk_spdif)) {
|
||||
printk(KERN_ERR "spdif:failed to get hclk_spdif\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
clk_set_rate(hclk_spdif, pll_rate);
|
||||
clk_put(hclk_spdif);
|
||||
#endif
|
||||
|
||||
sclk_spdif = clk_get(NULL, "spdif");
|
||||
if (IS_ERR(sclk_spdif)) {
|
||||
printk(KERN_ERR "spdif:failed to get sclk_spdif\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
clk_set_rate(sclk_spdif, audio_rate);
|
||||
clk_put(sclk_spdif);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 pll_out, rclk_rate;
|
||||
int ret, ratio;
|
||||
|
||||
RK_SPDIF_DBG("spdif:Entered %s\n", __func__);
|
||||
|
||||
switch (params_rate(params)) {
|
||||
case 44100:
|
||||
pll_out = 11289600;
|
||||
break;
|
||||
case 32000:
|
||||
pll_out = 8192000;
|
||||
break;
|
||||
case 48000:
|
||||
pll_out = 12288000;
|
||||
break;
|
||||
case 96000:
|
||||
pll_out = 24576000;
|
||||
break;
|
||||
default:
|
||||
printk("rk_spdif: params not support\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ratio = 256;
|
||||
rclk_rate = params_rate(params) * ratio;
|
||||
|
||||
/* Set audio source clock rates */
|
||||
ret = set_audio_clock_rate(pll_out, rclk_rate);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Set S/PDIF uses internal source clock */
|
||||
//ret = snd_soc_dai_set_sysclk(cpu_dai, SND_SOC_SPDIF_INT_MCLK,
|
||||
//rclk_rate, SND_SOC_CLOCK_IN);
|
||||
//if (ret < 0)
|
||||
//return ret;
|
||||
|
||||
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",
|
||||
.platform_name = "rockchip-audio",
|
||||
.cpu_dai_name = "rk-spdif.0",
|
||||
.codec_dai_name = "dit-hifi",
|
||||
.codec_name = "spdif-dit",
|
||||
.ops = &rk_spdif_ops,
|
||||
};
|
||||
|
||||
static struct snd_soc_card rk_spdif = {
|
||||
.name = "ROCKCHIP-SPDIF",
|
||||
.dai_link = &rk_dai,
|
||||
.num_links = 1,
|
||||
};
|
||||
|
||||
static struct platform_device *rk_snd_spdif_dit_device;
|
||||
static struct platform_device *rk_snd_spdif_device;
|
||||
|
||||
static int __init rk_spdif_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
RK_SPDIF_DBG("Entered %s\n", __func__);
|
||||
|
||||
rk_snd_spdif_dit_device = platform_device_alloc("spdif-dit", -1);
|
||||
if (!rk_snd_spdif_dit_device){
|
||||
printk("spdif:platform_device_alloc spdif-dit\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = platform_device_add(rk_snd_spdif_dit_device);
|
||||
if (ret)
|
||||
goto err1;
|
||||
|
||||
rk_snd_spdif_device = platform_device_alloc("soc-audio", -3);
|
||||
if (!rk_snd_spdif_device) {
|
||||
printk("spdif:platform_device_alloc rk_soc-audio\n");
|
||||
ret = -ENOMEM;
|
||||
goto err2;
|
||||
}
|
||||
|
||||
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
|
||||
platform_set_drvdata(rk_snd_spdif_device, &rk_spdif);
|
||||
#else
|
||||
platform_set_drvdata(rk_snd_spdif_device, &rk_spdif);
|
||||
rk_spdif.dev = &rk_snd_spdif_device->dev;
|
||||
#endif
|
||||
|
||||
//platform_set_drvdata(rk_snd_spdif_device, &rk_spdif);
|
||||
|
||||
ret = platform_device_add(rk_snd_spdif_device);
|
||||
if (ret)
|
||||
goto err3;
|
||||
|
||||
RK_SPDIF_DBG("rk_spdif_init ok\n");
|
||||
return ret;
|
||||
err3:
|
||||
platform_device_put(rk_snd_spdif_device);
|
||||
err2:
|
||||
platform_device_del(rk_snd_spdif_dit_device);
|
||||
err1:
|
||||
platform_device_put(rk_snd_spdif_dit_device);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit rk_spdif_exit(void)
|
||||
{
|
||||
platform_device_unregister(rk_snd_spdif_device);
|
||||
platform_device_unregister(rk_snd_spdif_dit_device);
|
||||
}
|
||||
|
||||
//using late_initcall to make sure spdif is after board codec. added by zxg.
|
||||
//module_init(rk_spdif_init);
|
||||
late_initcall(rk_spdif_init);
|
||||
module_exit(rk_spdif_exit);
|
||||
|
||||
MODULE_AUTHOR("hzb, <hzb@rock-chips.com>");
|
||||
MODULE_DESCRIPTION("ALSA SoC RK+S/PDIF");
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -1,25 +1,54 @@
|
||||
/*$_FOR_ROCKCHIP_RBOX_$*/
|
||||
/*$_rbox_$_modify_$_huangzhibao for spdif output*/
|
||||
|
||||
/*
|
||||
* smdk_spdif.c -- S/PDIF audio for SMDK
|
||||
/* sound/soc/rockchip/spdif.c
|
||||
*
|
||||
* Copyright 2010 Samsung Electronics Co. Ltd.
|
||||
* ALSA SoC Audio Layer - rockchip S/PDIF Controller driver
|
||||
*
|
||||
* 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.
|
||||
* Copyright (c) 2010 rockchip Electronics Co. Ltd
|
||||
* http://www.rockchip.com/
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#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 "spdif.h"
|
||||
#include <mach/board.h>
|
||||
#include <mach/hardware.h>
|
||||
#include <mach/io.h>
|
||||
#include <mach/gpio.h>
|
||||
#include <mach/iomux.h>
|
||||
|
||||
#if defined (CONFIG_ARCH_RK29)
|
||||
#include <mach/rk29-dma-pl330.h>
|
||||
#endif
|
||||
|
||||
#if defined (CONFIG_ARCH_RK30)
|
||||
#include <mach/dma-pl330.h>
|
||||
#endif
|
||||
|
||||
#if defined (CONFIG_ARCH_RK3188)
|
||||
#include <mach/dma-pl330.h>
|
||||
#endif
|
||||
|
||||
#include "rk29_pcm.h"
|
||||
|
||||
#if 0
|
||||
#define RK_SPDIF_DBG(x...) printk(KERN_INFO "rk_spdif:"x)
|
||||
#else
|
||||
@@ -27,160 +56,433 @@
|
||||
#endif
|
||||
|
||||
|
||||
static int set_audio_clock_rate(unsigned long pll_rate,
|
||||
unsigned long audio_rate)
|
||||
/* Registers */
|
||||
#define CFGR 0x00
|
||||
#define SDBLR 0x04
|
||||
#define DMACR 0x08
|
||||
#define INTCR 0x0C
|
||||
#define INTSR 0x10
|
||||
#define XFER 0x18
|
||||
#define SMPDR 0x20
|
||||
|
||||
#define DATA_OUTBUF 0x20
|
||||
|
||||
#define CFGR_MASK 0x0ffffff
|
||||
#define CFGR_VALID_DATA_16bit (00)
|
||||
#define CFGR_VALID_DATA_20bit (01)
|
||||
#define CFGR_VALID_DATA_24bit (10)
|
||||
#define CFGR_VALID_DATA_MASK (11)
|
||||
|
||||
#define CFGR_HALFWORD_TX_ENABLE (0x1 << 2)
|
||||
#define CFGR_HALFWORD_TX_DISABLE (0x0 << 2)
|
||||
#define CFGR_HALFWORD_TX_MASK (0x1 << 2)
|
||||
|
||||
#define CFGR_CLK_RATE_MASK (0xFF<<16)
|
||||
|
||||
#define CFGR_JUSTIFIED_RIGHT (0<<3)
|
||||
#define CFGR_JUSTIFIED_LEFT (1<<3)
|
||||
#define CFGR_JUSTIFIED_MASK (1<<3)
|
||||
|
||||
#define XFER_TRAN_STOP (0)
|
||||
#define XFER_TRAN_START (1)
|
||||
#define XFER_MASK (1)
|
||||
|
||||
#define DMACR_TRAN_DMA_DISABLE (0<<5)
|
||||
#define DMACR_TRAN_DMA_ENABLE (1<<5)
|
||||
#define DMACR_TRAN_DMA_CTL_MASK (1<<5)
|
||||
|
||||
#define DMACR_TRAN_DATA_LEVEL 0x10
|
||||
#define DMACR_TRAN_DATA_LEVEL_MASK 0x1F
|
||||
|
||||
#define DMACR_TRAN_DMA_MASK (0x3F)
|
||||
|
||||
|
||||
|
||||
struct rockchip_spdif_info {
|
||||
spinlock_t lock;
|
||||
struct device *dev;
|
||||
void __iomem *regs;
|
||||
unsigned long clk_rate;
|
||||
struct clk *hclk;
|
||||
struct clk *clk;
|
||||
u32 saved_clkcon;
|
||||
u32 saved_con;
|
||||
u32 saved_cstas;
|
||||
struct rockchip_pcm_dma_params *dma_playback;
|
||||
};
|
||||
|
||||
static struct rk29_dma_client spdif_dma_client_out = {
|
||||
.name = "SPDIF Stereo out"
|
||||
};
|
||||
|
||||
static struct rockchip_pcm_dma_params spdif_stereo_out;
|
||||
|
||||
static struct rockchip_spdif_info spdif_info;
|
||||
|
||||
static inline struct rockchip_spdif_info *to_info(struct snd_soc_dai *cpu_dai)
|
||||
{
|
||||
struct clk *hclk_spdif, *sclk_spdif;
|
||||
return snd_soc_dai_get_drvdata(cpu_dai);
|
||||
}
|
||||
|
||||
#if defined (CONFIG_ARCH_RK30) || (CONFIG_ARCH_RK3188)
|
||||
hclk_spdif = clk_get(NULL, "hclk_spdif");
|
||||
if (IS_ERR(hclk_spdif)) {
|
||||
printk(KERN_ERR "spdif:failed to get hclk_spdif\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
static void spdif_snd_txctrl(struct rockchip_spdif_info *spdif, int on)
|
||||
{
|
||||
void __iomem *regs = spdif->regs;
|
||||
u32 opr,xfer;
|
||||
|
||||
clk_set_rate(hclk_spdif, pll_rate);
|
||||
clk_put(hclk_spdif);
|
||||
#endif
|
||||
RK_SPDIF_DBG( "Entered %s\n", __func__);
|
||||
|
||||
sclk_spdif = clk_get(NULL, "spdif");
|
||||
if (IS_ERR(sclk_spdif)) {
|
||||
printk(KERN_ERR "spdif:failed to get sclk_spdif\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
xfer = readl(regs + XFER) & XFER_MASK;
|
||||
opr = readl(regs + DMACR) & DMACR_TRAN_DMA_MASK & (~DMACR_TRAN_DMA_CTL_MASK);
|
||||
|
||||
if (on){
|
||||
xfer |= XFER_TRAN_START;
|
||||
opr |= DMACR_TRAN_DMA_ENABLE;
|
||||
writel(xfer, regs + XFER);
|
||||
writel(opr|0x10, regs + DMACR);
|
||||
RK_SPDIF_DBG("on xfer=0x%x,opr=0x%x\n",readl(regs + XFER),readl(regs + DMACR));
|
||||
} else{
|
||||
xfer &= ~XFER_TRAN_START;
|
||||
opr &= ~DMACR_TRAN_DMA_ENABLE;
|
||||
writel(xfer, regs + XFER);
|
||||
writel(opr|0x10, regs + DMACR);
|
||||
}
|
||||
}
|
||||
|
||||
clk_set_rate(sclk_spdif, audio_rate);
|
||||
clk_put(sclk_spdif);
|
||||
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);
|
||||
u32 clkcon;
|
||||
|
||||
RK_SPDIF_DBG("Entered %s\n", __func__);
|
||||
|
||||
spdif->clk_rate = freq;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
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 snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
unsigned long pll_out, rclk_rate;
|
||||
int ret, ratio;
|
||||
struct rockchip_spdif_info *spdif = to_info(rtd->cpu_dai);
|
||||
unsigned long flags;
|
||||
|
||||
RK_SPDIF_DBG("spdif:Entered %s\n", __func__);
|
||||
|
||||
switch (params_rate(params)) {
|
||||
case 44100:
|
||||
pll_out = 11289600;
|
||||
RK_SPDIF_DBG( "Entered %s\n", __func__);
|
||||
|
||||
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 32000:
|
||||
pll_out = 8192000;
|
||||
break;
|
||||
case 48000:
|
||||
pll_out = 12288000;
|
||||
break;
|
||||
case 96000:
|
||||
pll_out = 24576000;
|
||||
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:
|
||||
printk("rk_spdif: params not support\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ratio = 256;
|
||||
rclk_rate = params_rate(params) * ratio;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Set audio source clock rates */
|
||||
ret = set_audio_clock_rate(pll_out, rclk_rate);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Set S/PDIF uses internal source clock */
|
||||
//ret = snd_soc_dai_set_sysclk(cpu_dai, SND_SOC_SPDIF_INT_MCLK,
|
||||
//rclk_rate, SND_SOC_CLOCK_IN);
|
||||
//if (ret < 0)
|
||||
//return ret;
|
||||
static int spdif_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *socdai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct rockchip_spdif_info *spdif = to_info(rtd->cpu_dai);
|
||||
void __iomem *regs = spdif->regs;
|
||||
struct rockchip_pcm_dma_params *dma_data;
|
||||
unsigned long flags;
|
||||
int i, cfgr, dmac;
|
||||
|
||||
RK_SPDIF_DBG("Entered %s\n", __func__);
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
dma_data = spdif->dma_playback;
|
||||
else {
|
||||
printk("spdif:Capture is not supported\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_data);
|
||||
spin_lock_irqsave(&spdif->lock, flags);
|
||||
|
||||
cfgr = readl(regs + CFGR) & CFGR_VALID_DATA_MASK;
|
||||
|
||||
cfgr &= ~CFGR_VALID_DATA_MASK;
|
||||
switch (params_format(params)) {
|
||||
case SNDRV_PCM_FORMAT_S16_LE:
|
||||
cfgr |= CFGR_VALID_DATA_16bit;
|
||||
break;
|
||||
case SNDRV_PCM_FMTBIT_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;
|
||||
|
||||
cfgr &= ~CFGR_CLK_RATE_MASK;
|
||||
cfgr |= (1<<16);
|
||||
|
||||
cfgr &= ~CFGR_JUSTIFIED_MASK;
|
||||
cfgr |= CFGR_JUSTIFIED_RIGHT;
|
||||
|
||||
writel(cfgr, regs + CFGR);
|
||||
|
||||
dmac = readl(regs + DMACR) & DMACR_TRAN_DMA_MASK & (~DMACR_TRAN_DATA_LEVEL_MASK);
|
||||
dmac |= 0x10;
|
||||
writel(dmac, regs + DMACR);
|
||||
|
||||
spin_unlock_irqrestore(&spdif->lock, flags);
|
||||
|
||||
return 0;
|
||||
err:
|
||||
spin_unlock_irqrestore(&spdif->lock, flags);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void spdif_shutdown(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct rockchip_spdif_info *spdif = to_info(rtd->cpu_dai);
|
||||
void __iomem *regs = spdif->regs;
|
||||
u32 con, clkcon;
|
||||
|
||||
RK_SPDIF_DBG( "spdif:Entered %s\n", __func__);
|
||||
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int spdif_suspend(struct snd_soc_dai *cpu_dai)
|
||||
{
|
||||
struct rockchip_spdif_info *spdif = to_info(cpu_dai);
|
||||
u32 con = spdif->saved_con;
|
||||
|
||||
RK_SPDIF_DBG( "spdif:Entered %s\n", __func__);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int spdif_resume(struct snd_soc_dai *cpu_dai)
|
||||
{
|
||||
struct rockchip_spdif_info *spdif = to_info(cpu_dai);
|
||||
|
||||
RK_SPDIF_DBG( "spdif:Entered %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,
|
||||
.shutdown = spdif_shutdown,
|
||||
};
|
||||
|
||||
struct snd_soc_dai_driver rockchip_spdif_dai = {
|
||||
.name = "rk-spdif",
|
||||
.playback = {
|
||||
.stream_name = "SPDIF Playback",
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.rates = (SNDRV_PCM_RATE_32000 |
|
||||
SNDRV_PCM_RATE_44100 |
|
||||
SNDRV_PCM_RATE_48000 |
|
||||
SNDRV_PCM_RATE_96000),
|
||||
.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 __devinit int spdif_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct s3c_audio_pdata *spdif_pdata;
|
||||
struct resource *mem_res, *dma_res;
|
||||
struct rockchip_spdif_info *spdif;
|
||||
int ret;
|
||||
|
||||
spdif_pdata = pdev->dev.platform_data;
|
||||
|
||||
RK_SPDIF_DBG("Entered %s\n", __func__);
|
||||
|
||||
#if defined (CONFIG_ARCH_RK29)
|
||||
rk29_mux_api_set(GPIO4A7_SPDIFTX_NAME, GPIO4L_SPDIF_TX);
|
||||
#endif
|
||||
|
||||
#if defined (CONFIG_ARCH_RK30)
|
||||
#if defined (CONFIG_ARCH_RK3066B)
|
||||
iomux_set(SPDIF_TX);
|
||||
#else
|
||||
rk30_mux_api_set(GPIO1B2_SPDIFTX_NAME, GPIO1B_SPDIF_TX);
|
||||
#endif
|
||||
#elif defined (CONFIG_ARCH_RK3188)
|
||||
iomux_set(SPDIF_TX);
|
||||
#endif
|
||||
|
||||
|
||||
dma_res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "spdif_dma");
|
||||
if (!dma_res) {
|
||||
printk("spdif:Unable to get dma resource.\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
mem_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "spdif_base");
|
||||
if (!mem_res) {
|
||||
printk("spdif:Unable to get register resource.\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
spdif = &spdif_info;
|
||||
spdif->dev = &pdev->dev;
|
||||
|
||||
spin_lock_init(&spdif->lock);
|
||||
|
||||
spdif->clk = clk_get(&pdev->dev, "spdif");
|
||||
if (IS_ERR(spdif->clk)) {
|
||||
printk("spdif:failed to get internal source clock\n");
|
||||
ret = -ENOENT;
|
||||
goto err1;
|
||||
}
|
||||
clk_enable(spdif->clk);
|
||||
clk_set_rate(spdif->clk, 11289600);
|
||||
|
||||
#if 1// defined (CONFIG_ARCH_RK30)
|
||||
spdif->hclk = clk_get(&pdev->dev, "hclk_spdif");
|
||||
if (IS_ERR(spdif->hclk)) {
|
||||
printk("spdif:failed to get spdif hclk\n");
|
||||
ret = -ENOENT;
|
||||
goto err0;
|
||||
}
|
||||
clk_enable(spdif->hclk);
|
||||
clk_set_rate(spdif->hclk, 11289600);
|
||||
#endif
|
||||
|
||||
/* Request S/PDIF Register's memory region */
|
||||
if (!request_mem_region(mem_res->start,
|
||||
resource_size(mem_res), "rockchip-spdif")) {
|
||||
printk("spdif:Unable to request register region\n");
|
||||
ret = -EBUSY;
|
||||
goto err2;
|
||||
}
|
||||
|
||||
spdif->regs = ioremap(mem_res->start, mem_res->end - mem_res->start + 1);
|
||||
if (spdif->regs == NULL) {
|
||||
printk("spdif:Cannot ioremap registers\n");
|
||||
ret = -ENXIO;
|
||||
goto err3;
|
||||
}
|
||||
|
||||
dev_set_drvdata(&pdev->dev, spdif);
|
||||
|
||||
ret = snd_soc_register_dai(&pdev->dev, &rockchip_spdif_dai);
|
||||
if (ret != 0) {
|
||||
printk("spdif:fail to register dai\n");
|
||||
goto err4;
|
||||
}
|
||||
|
||||
spdif_stereo_out.dma_size = 4;
|
||||
spdif_stereo_out.client = &spdif_dma_client_out;
|
||||
spdif_stereo_out.dma_addr = mem_res->start + DATA_OUTBUF;
|
||||
spdif_stereo_out.channel = dma_res->start;
|
||||
|
||||
spdif->dma_playback = &spdif_stereo_out;
|
||||
#ifdef CONFIG_SND_DMA_EVENT_STATIC
|
||||
WARN_ON(rk29_dma_request(spdif_stereo_out.channel, spdif_stereo_out.client, NULL));
|
||||
#endif
|
||||
|
||||
RK_SPDIF_DBG("spdif:spdif probe ok!\n");
|
||||
|
||||
return 0;
|
||||
|
||||
err4:
|
||||
iounmap(spdif->regs);
|
||||
err3:
|
||||
release_mem_region(mem_res->start, resource_size(mem_res));
|
||||
err2:
|
||||
clk_disable(spdif->clk);
|
||||
clk_put(spdif->clk);
|
||||
err1:
|
||||
clk_disable(spdif->hclk);
|
||||
clk_put(spdif->hclk);
|
||||
#if 1//defined (CONFIG_ARCH_RK30)
|
||||
err0:
|
||||
#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",
|
||||
.platform_name = "rockchip-audio",
|
||||
.cpu_dai_name = "rk-spdif.0",
|
||||
.codec_dai_name = "dit-hifi",
|
||||
.codec_name = "spdif-dit",
|
||||
.ops = &rk_spdif_ops,
|
||||
};
|
||||
|
||||
static struct snd_soc_card rk_spdif = {
|
||||
.name = "ROCKCHIP-SPDIF",
|
||||
.dai_link = &rk_dai,
|
||||
.num_links = 1,
|
||||
};
|
||||
|
||||
static struct platform_device *rk_snd_spdif_dit_device;
|
||||
static struct platform_device *rk_snd_spdif_device;
|
||||
|
||||
static int __init rk_spdif_init(void)
|
||||
static __devexit int spdif_remove(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
struct rockchip_spdif_info *spdif = &spdif_info;
|
||||
struct resource *mem_res;
|
||||
|
||||
RK_SPDIF_DBG("Entered %s\n", __func__);
|
||||
|
||||
rk_snd_spdif_dit_device = platform_device_alloc("spdif-dit", -1);
|
||||
if (!rk_snd_spdif_dit_device){
|
||||
printk("spdif:platform_device_alloc spdif-dit\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
ret = platform_device_add(rk_snd_spdif_dit_device);
|
||||
if (ret)
|
||||
goto err1;
|
||||
snd_soc_unregister_dai(&pdev->dev);
|
||||
|
||||
rk_snd_spdif_device = platform_device_alloc("soc-audio", -3);
|
||||
if (!rk_snd_spdif_device) {
|
||||
printk("spdif:platform_device_alloc rk_soc-audio\n");
|
||||
ret = -ENOMEM;
|
||||
goto err2;
|
||||
}
|
||||
|
||||
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
|
||||
platform_set_drvdata(rk_snd_spdif_device, &rk_spdif);
|
||||
#else
|
||||
platform_set_drvdata(rk_snd_spdif_device, &rk_spdif);
|
||||
rk_spdif.dev = &rk_snd_spdif_device->dev;
|
||||
#endif
|
||||
iounmap(spdif->regs);
|
||||
|
||||
//platform_set_drvdata(rk_snd_spdif_device, &rk_spdif);
|
||||
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (mem_res)
|
||||
release_mem_region(mem_res->start, resource_size(mem_res));
|
||||
|
||||
ret = platform_device_add(rk_snd_spdif_device);
|
||||
if (ret)
|
||||
goto err3;
|
||||
|
||||
RK_SPDIF_DBG("rk_spdif_init ok\n");
|
||||
return ret;
|
||||
err3:
|
||||
platform_device_put(rk_snd_spdif_device);
|
||||
err2:
|
||||
platform_device_del(rk_snd_spdif_dit_device);
|
||||
err1:
|
||||
platform_device_put(rk_snd_spdif_dit_device);
|
||||
|
||||
return ret;
|
||||
clk_disable(spdif->clk);
|
||||
clk_put(spdif->clk);
|
||||
clk_disable(spdif->hclk);
|
||||
clk_put(spdif->hclk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit rk_spdif_exit(void)
|
||||
|
||||
static struct platform_driver rockchip_spdif_driver = {
|
||||
.probe = spdif_probe,
|
||||
.remove = spdif_remove,
|
||||
.driver = {
|
||||
.name = "rk-spdif",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
static int __init spdif_init(void)
|
||||
{
|
||||
platform_device_unregister(rk_snd_spdif_device);
|
||||
platform_device_unregister(rk_snd_spdif_dit_device);
|
||||
RK_SPDIF_DBG("Entered %s\n", __func__);
|
||||
return platform_driver_register(&rockchip_spdif_driver);
|
||||
}
|
||||
module_init(spdif_init);
|
||||
|
||||
//using late_initcall to make sure spdif is after board codec. added by zxg.
|
||||
//module_init(rk_spdif_init);
|
||||
late_initcall(rk_spdif_init);
|
||||
module_exit(rk_spdif_exit);
|
||||
static void __exit spdif_exit(void)
|
||||
{
|
||||
RK_SPDIF_DBG("Entered %s\n", __func__);
|
||||
platform_driver_unregister(&rockchip_spdif_driver);
|
||||
}
|
||||
module_exit(spdif_exit);
|
||||
|
||||
MODULE_AUTHOR("hzb, <hzb@rock-chips.com>");
|
||||
MODULE_DESCRIPTION("ALSA SoC RK+S/PDIF");
|
||||
MODULE_AUTHOR("Seungwhan Youn, <sw.youn@rockchip.com>");
|
||||
MODULE_DESCRIPTION("rockchip S/PDIF Controller Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:rockchip-spdif");
|
||||
|
||||
@@ -1,489 +0,0 @@
|
||||
/*$_FOR_ROCKCHIP_RBOX_$*/
|
||||
/*$_rbox_$_modify_$_huangzhibao for spdif output*/
|
||||
|
||||
/* sound/soc/rockchip/spdif.c
|
||||
*
|
||||
* ALSA SoC Audio Layer - rockchip S/PDIF Controller driver
|
||||
*
|
||||
* Copyright (c) 2010 rockchip Electronics Co. Ltd
|
||||
* http://www.rockchip.com/
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#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/board.h>
|
||||
#include <mach/hardware.h>
|
||||
#include <mach/io.h>
|
||||
#include <mach/gpio.h>
|
||||
#include <mach/iomux.h>
|
||||
|
||||
#if defined (CONFIG_ARCH_RK29)
|
||||
#include <mach/rk29-dma-pl330.h>
|
||||
#endif
|
||||
|
||||
#if defined (CONFIG_ARCH_RK30)
|
||||
#include <mach/dma-pl330.h>
|
||||
#endif
|
||||
|
||||
#if defined (CONFIG_ARCH_RK3188)
|
||||
#include <mach/dma-pl330.h>
|
||||
#endif
|
||||
|
||||
#include "rk29_pcm.h"
|
||||
#include "spdif.h"
|
||||
|
||||
#if 1
|
||||
#define RK_SPDIF_DBG(x...) printk(KERN_INFO "spdif:"x)
|
||||
#else
|
||||
#define RK_SPDIF_DBG(x...) do { } while (0)
|
||||
#endif
|
||||
|
||||
|
||||
/* Registers */
|
||||
#define CFGR 0x00
|
||||
#define SDBLR 0x04
|
||||
#define DMACR 0x08
|
||||
#define INTCR 0x0C
|
||||
#define INTSR 0x10
|
||||
#define XFER 0x18
|
||||
#define SMPDR 0x20
|
||||
|
||||
#define DATA_OUTBUF 0x20
|
||||
|
||||
#define CFGR_MASK 0x0ffffff
|
||||
#define CFGR_VALID_DATA_16bit (00)
|
||||
#define CFGR_VALID_DATA_20bit (01)
|
||||
#define CFGR_VALID_DATA_24bit (10)
|
||||
#define CFGR_VALID_DATA_MASK (11)
|
||||
|
||||
#define CFGR_HALFWORD_TX_ENABLE (0x1 << 2)
|
||||
#define CFGR_HALFWORD_TX_DISABLE (0x0 << 2)
|
||||
#define CFGR_HALFWORD_TX_MASK (0x1 << 2)
|
||||
|
||||
#define CFGR_CLK_RATE_MASK (0xFF<<16)
|
||||
|
||||
#define CFGR_JUSTIFIED_RIGHT (0<<3)
|
||||
#define CFGR_JUSTIFIED_LEFT (1<<3)
|
||||
#define CFGR_JUSTIFIED_MASK (1<<3)
|
||||
|
||||
#define XFER_TRAN_STOP (0)
|
||||
#define XFER_TRAN_START (1)
|
||||
#define XFER_MASK (1)
|
||||
|
||||
#define DMACR_TRAN_DMA_DISABLE (0<<5)
|
||||
#define DMACR_TRAN_DMA_ENABLE (1<<5)
|
||||
#define DMACR_TRAN_DMA_CTL_MASK (1<<5)
|
||||
|
||||
#define DMACR_TRAN_DATA_LEVEL 0x10
|
||||
#define DMACR_TRAN_DATA_LEVEL_MASK 0x1F
|
||||
|
||||
#define DMACR_TRAN_DMA_MASK (0x3F)
|
||||
|
||||
|
||||
|
||||
struct rockchip_spdif_info {
|
||||
spinlock_t lock;
|
||||
struct device *dev;
|
||||
void __iomem *regs;
|
||||
unsigned long clk_rate;
|
||||
struct clk *hclk;
|
||||
struct clk *clk;
|
||||
u32 saved_clkcon;
|
||||
u32 saved_con;
|
||||
u32 saved_cstas;
|
||||
struct rockchip_pcm_dma_params *dma_playback;
|
||||
};
|
||||
|
||||
static struct rk29_dma_client spdif_dma_client_out = {
|
||||
.name = "SPDIF Stereo out"
|
||||
};
|
||||
|
||||
static struct rockchip_pcm_dma_params spdif_stereo_out;
|
||||
|
||||
static struct rockchip_spdif_info spdif_info;
|
||||
|
||||
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 opr,xfer;
|
||||
|
||||
RK_SPDIF_DBG( "Entered %s\n", __func__);
|
||||
|
||||
xfer = readl(regs + XFER) & XFER_MASK;
|
||||
opr = readl(regs + DMACR) & DMACR_TRAN_DMA_MASK & (~DMACR_TRAN_DMA_CTL_MASK);
|
||||
|
||||
if (on){
|
||||
xfer |= XFER_TRAN_START;
|
||||
opr |= DMACR_TRAN_DMA_ENABLE;
|
||||
writel(xfer, regs + XFER);
|
||||
writel(opr|0x10, regs + DMACR);
|
||||
RK_SPDIF_DBG("on xfer=0x%x,opr=0x%x\n",readl(regs + XFER),readl(regs + DMACR));
|
||||
} else{
|
||||
xfer &= ~XFER_TRAN_START;
|
||||
opr &= ~DMACR_TRAN_DMA_ENABLE;
|
||||
writel(xfer, regs + XFER);
|
||||
writel(opr|0x10, 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);
|
||||
u32 clkcon;
|
||||
|
||||
RK_SPDIF_DBG("Entered %s\n", __func__);
|
||||
|
||||
spdif->clk_rate = 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;
|
||||
|
||||
RK_SPDIF_DBG( "Entered %s\n", __func__);
|
||||
|
||||
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 *socdai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct rockchip_spdif_info *spdif = to_info(rtd->cpu_dai);
|
||||
void __iomem *regs = spdif->regs;
|
||||
struct rockchip_pcm_dma_params *dma_data;
|
||||
unsigned long flags;
|
||||
int i, cfgr, dmac;
|
||||
|
||||
RK_SPDIF_DBG("Entered %s\n", __func__);
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
dma_data = spdif->dma_playback;
|
||||
else {
|
||||
printk("spdif:Capture is not supported\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_data);
|
||||
spin_lock_irqsave(&spdif->lock, flags);
|
||||
|
||||
cfgr = readl(regs + CFGR) & CFGR_VALID_DATA_MASK;
|
||||
|
||||
cfgr &= ~CFGR_VALID_DATA_MASK;
|
||||
switch (params_format(params)) {
|
||||
case SNDRV_PCM_FORMAT_S16_LE:
|
||||
cfgr |= CFGR_VALID_DATA_16bit;
|
||||
break;
|
||||
case SNDRV_PCM_FMTBIT_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;
|
||||
|
||||
cfgr &= ~CFGR_CLK_RATE_MASK;
|
||||
cfgr |= (1<<16);
|
||||
|
||||
cfgr &= ~CFGR_JUSTIFIED_MASK;
|
||||
cfgr |= CFGR_JUSTIFIED_RIGHT;
|
||||
|
||||
writel(cfgr, regs + CFGR);
|
||||
|
||||
dmac = readl(regs + DMACR) & DMACR_TRAN_DMA_MASK & (~DMACR_TRAN_DATA_LEVEL_MASK);
|
||||
dmac |= 0x10;
|
||||
writel(dmac, regs + DMACR);
|
||||
|
||||
spin_unlock_irqrestore(&spdif->lock, flags);
|
||||
|
||||
return 0;
|
||||
err:
|
||||
spin_unlock_irqrestore(&spdif->lock, flags);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void spdif_shutdown(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct rockchip_spdif_info *spdif = to_info(rtd->cpu_dai);
|
||||
void __iomem *regs = spdif->regs;
|
||||
u32 con, clkcon;
|
||||
|
||||
RK_SPDIF_DBG( "spdif:Entered %s\n", __func__);
|
||||
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int spdif_suspend(struct snd_soc_dai *cpu_dai)
|
||||
{
|
||||
struct rockchip_spdif_info *spdif = to_info(cpu_dai);
|
||||
u32 con = spdif->saved_con;
|
||||
|
||||
RK_SPDIF_DBG( "spdif:Entered %s\n", __func__);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int spdif_resume(struct snd_soc_dai *cpu_dai)
|
||||
{
|
||||
struct rockchip_spdif_info *spdif = to_info(cpu_dai);
|
||||
|
||||
RK_SPDIF_DBG( "spdif:Entered %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,
|
||||
.shutdown = spdif_shutdown,
|
||||
};
|
||||
|
||||
struct snd_soc_dai_driver rockchip_spdif_dai = {
|
||||
.name = "rk-spdif",
|
||||
.playback = {
|
||||
.stream_name = "SPDIF Playback",
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.rates = (SNDRV_PCM_RATE_32000 |
|
||||
SNDRV_PCM_RATE_44100 |
|
||||
SNDRV_PCM_RATE_48000 |
|
||||
SNDRV_PCM_RATE_96000),
|
||||
.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 __devinit int spdif_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct s3c_audio_pdata *spdif_pdata;
|
||||
struct resource *mem_res, *dma_res;
|
||||
struct rockchip_spdif_info *spdif;
|
||||
int ret;
|
||||
|
||||
spdif_pdata = pdev->dev.platform_data;
|
||||
|
||||
RK_SPDIF_DBG("Entered %s\n", __func__);
|
||||
|
||||
#if defined (CONFIG_ARCH_RK29)
|
||||
rk29_mux_api_set(GPIO4A7_SPDIFTX_NAME, GPIO4L_SPDIF_TX);
|
||||
#endif
|
||||
|
||||
#if defined (CONFIG_ARCH_RK30)
|
||||
#if defined (CONFIG_ARCH_RK3066B)
|
||||
iomux_set(SPDIF_TX);
|
||||
#else
|
||||
rk30_mux_api_set(GPIO1B2_SPDIFTX_NAME, GPIO1B_SPDIF_TX);
|
||||
#endif
|
||||
#elif defined (CONFIG_ARCH_RK3188)
|
||||
iomux_set(SPDIF_TX);
|
||||
#endif
|
||||
|
||||
|
||||
dma_res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "spdif_dma");
|
||||
if (!dma_res) {
|
||||
printk("spdif:Unable to get dma resource.\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
mem_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "spdif_base");
|
||||
if (!mem_res) {
|
||||
printk("spdif:Unable to get register resource.\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
spdif = &spdif_info;
|
||||
spdif->dev = &pdev->dev;
|
||||
|
||||
spin_lock_init(&spdif->lock);
|
||||
|
||||
spdif->clk = clk_get(&pdev->dev, "spdif");
|
||||
if (IS_ERR(spdif->clk)) {
|
||||
printk("spdif:failed to get internal source clock\n");
|
||||
ret = -ENOENT;
|
||||
goto err1;
|
||||
}
|
||||
clk_enable(spdif->clk);
|
||||
clk_set_rate(spdif->clk, 11289600);
|
||||
|
||||
#if 1// defined (CONFIG_ARCH_RK30)
|
||||
spdif->hclk = clk_get(&pdev->dev, "hclk_spdif");
|
||||
if (IS_ERR(spdif->hclk)) {
|
||||
printk("spdif:failed to get spdif hclk\n");
|
||||
ret = -ENOENT;
|
||||
goto err0;
|
||||
}
|
||||
clk_enable(spdif->hclk);
|
||||
clk_set_rate(spdif->hclk, 11289600);
|
||||
#endif
|
||||
|
||||
/* Request S/PDIF Register's memory region */
|
||||
if (!request_mem_region(mem_res->start,
|
||||
resource_size(mem_res), "rockchip-spdif")) {
|
||||
printk("spdif:Unable to request register region\n");
|
||||
ret = -EBUSY;
|
||||
goto err2;
|
||||
}
|
||||
|
||||
spdif->regs = ioremap(mem_res->start, mem_res->end - mem_res->start + 1);
|
||||
if (spdif->regs == NULL) {
|
||||
printk("spdif:Cannot ioremap registers\n");
|
||||
ret = -ENXIO;
|
||||
goto err3;
|
||||
}
|
||||
|
||||
dev_set_drvdata(&pdev->dev, spdif);
|
||||
|
||||
ret = snd_soc_register_dai(&pdev->dev, &rockchip_spdif_dai);
|
||||
if (ret != 0) {
|
||||
printk("spdif:fail to register dai\n");
|
||||
goto err4;
|
||||
}
|
||||
|
||||
spdif_stereo_out.dma_size = 4;
|
||||
spdif_stereo_out.client = &spdif_dma_client_out;
|
||||
spdif_stereo_out.dma_addr = mem_res->start + DATA_OUTBUF;
|
||||
spdif_stereo_out.channel = dma_res->start;
|
||||
|
||||
spdif->dma_playback = &spdif_stereo_out;
|
||||
#ifdef CONFIG_SND_DMA_EVENT_STATIC
|
||||
WARN_ON(rk29_dma_request(spdif_stereo_out.channel, spdif_stereo_out.client, NULL));
|
||||
#endif
|
||||
|
||||
RK_SPDIF_DBG("spdif:spdif probe ok!\n");
|
||||
|
||||
return 0;
|
||||
|
||||
err4:
|
||||
iounmap(spdif->regs);
|
||||
err3:
|
||||
release_mem_region(mem_res->start, resource_size(mem_res));
|
||||
err2:
|
||||
clk_disable(spdif->clk);
|
||||
clk_put(spdif->clk);
|
||||
err1:
|
||||
clk_disable(spdif->hclk);
|
||||
clk_put(spdif->hclk);
|
||||
#if 1//defined (CONFIG_ARCH_RK30)
|
||||
err0:
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
static __devexit int spdif_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct rockchip_spdif_info *spdif = &spdif_info;
|
||||
struct resource *mem_res;
|
||||
|
||||
RK_SPDIF_DBG("Entered %s\n", __func__);
|
||||
|
||||
snd_soc_unregister_dai(&pdev->dev);
|
||||
|
||||
iounmap(spdif->regs);
|
||||
|
||||
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (mem_res)
|
||||
release_mem_region(mem_res->start, resource_size(mem_res));
|
||||
|
||||
clk_disable(spdif->clk);
|
||||
clk_put(spdif->clk);
|
||||
clk_disable(spdif->hclk);
|
||||
clk_put(spdif->hclk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct platform_driver rockchip_spdif_driver = {
|
||||
.probe = spdif_probe,
|
||||
.remove = spdif_remove,
|
||||
.driver = {
|
||||
.name = "rk-spdif",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
static int __init spdif_init(void)
|
||||
{
|
||||
RK_SPDIF_DBG("Entered %s\n", __func__);
|
||||
return platform_driver_register(&rockchip_spdif_driver);
|
||||
}
|
||||
module_init(spdif_init);
|
||||
|
||||
static void __exit spdif_exit(void)
|
||||
{
|
||||
RK_SPDIF_DBG("Entered %s\n", __func__);
|
||||
platform_driver_unregister(&rockchip_spdif_driver);
|
||||
}
|
||||
module_exit(spdif_exit);
|
||||
|
||||
MODULE_AUTHOR("Seungwhan Youn, <sw.youn@rockchip.com>");
|
||||
MODULE_DESCRIPTION("rockchip S/PDIF Controller Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:rockchip-spdif");
|
||||
@@ -1,18 +0,0 @@
|
||||
/*$_FOR_ROCKCHIP_RBOX_$*/
|
||||
/*$_rbox_$_modify_$_huangzhibao for spdif output*/
|
||||
|
||||
/*
|
||||
*
|
||||
* ALSA SoC Audio Layer -
|
||||
*
|
||||
*
|
||||
* 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_SAMSUNG_SPDIF_H
|
||||
#define __SND_SOC_SAMSUNG_SPDIF_H __FILE__
|
||||
|
||||
|
||||
#endif /* __SND_SOC_RK_SPDIF_H */
|
||||
Reference in New Issue
Block a user