本帖最后由 woody.lee 于 2016-3-24 15:31 编辑
總結一下, 遇到的問題有:
- dts 修改後未更新 resource.img (dtb包在resource.img)
- toolchain 請務必使用 arm-eabi-4.6, 驗證過使用 4.8, 遇到有編譯上與編譯完成後進不了系統的問題
- 文件有部分的 typo: chapter-05-general-register-file(grf).pdf
GRF_SOC_CON1[5] 基本上0,1值的描述與GRF_SOC_CON1[6]是一樣的
但是文件 chapter-28-i2s-2-channel.pdf 在 28.5 Interface description 中的描述
I2S has 2 IOMUX, which controlled by GRF_SOC_CON1[5].
假設 chapter-28-i2s-2-channel.pdf 為真, 兩組外部接腳只能選用一組音效輸出
目前個人的實做上, 兩組接腳只有成功 GRF_GPIO0B_IOMUX 一組
在嘗試 GRF_GPIO1A_IOMUX 一組, 驗證是不成功的, 失敗原因: 不明
就目前工作需求, 現階段已滿足後續測試需求, 如果其他先進驗證成功的也請回文告知, 感恩
- 有想嘗試編成模組(.ko), 但是功力不到位, 載入後系統提示:
rockchip-ssm2603 audio-ssm2603a.21: ASoC: CODEC (null) not registered
估計是因為在載入時, 源碼沒有去 dtb 撈出 iic addr. 的資訊, 所以驅動沒掛上,
如果其他先進知道如何處理, 也請回文告知, 感恩
# 4. 後來嘗試成功了, 想了下 codec 的code 應該可以先 built-in, 所以 make menuconfig
SoC I2S Audio support for rockchip - SSM2602/SSM2603/SSM2604
…
<*> Build all ASoC CODEC drivers
…
編譯失敗:
sound/built-in.o: In function rk610_codec_probe': last.c:(.text+0x8c274): undefined reference to rk610_control_init_codec’
sound/built-in.o: In function rk616_set_dai_sysclk': last.c:(.text+0x8d034): undefined reference to rk616_mclk_set_rate’
make: *** [vmlinux] Error 1
直接去掉編譯失敗的 codec
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index b7ef0b9..f520f3d 100644
— a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -117,8 +117,8 @@ config SND_SOC_ALL_CODECS
select SND_SOC_RT5639 if I2C
select SND_SOC_RT5616 if I2C
select SND_SOC_RT5512 if I2C
+# select SND_SOC_RK610 if I2C
+# select SND_SOC_RK616 if I2C
select SND_SOC_WM8903 if I2C && GENERIC_HARDIRQS
select SND_SOC_WM8904 if I2C
select SND_SOC_WM8940 if I2C
========================================================================================================
新增與更動檔案如下:
new file: sound/soc/rockchip/rk_ssm2602.c
modified: arch/arm/boot/dts/rk3128-fireprime.dts
modified: arch/arm/boot/dts/rk312x.dtsi
modified: arch/arm/configs/fireprime-linux_defconfig
modified: sound/soc/codecs/ssm2602.c
modified: sound/soc/codecs/ssm2602.h
modified: sound/soc/rockchip/Kconfig
modified: sound/soc/rockchip/Makefile
modified: sound/soc/rockchip/rk30_i2s.c
========================================================================================================
以下有省略一些 printk(…) 的輸出, 所以行號對不上, 但是看前後內容也可以知道關鍵點在哪
rk_ssm2602.c 基本上是拷貝 sound/soc/rockchip/rk_rk312x.c 做修改, 這裡就不浪費各位先進的眼力了
diff --git a/arch/arm/configs/fireprime-linux_defconfig b/arch/arm/configs/fireprime-linux_defconfig
index ab3a97f..8281284 100644
— a/arch/arm/configs/fireprime-linux_defconfig
+++ b/arch/arm/configs/fireprime-linux_defconfig
@@ -405,6 +405,7 @@ CONFIG_MALI_PLATFORM_THIRDPARTY_NAME=“rk”
CONFIG_MALI400=m
# CONFIG_MALI400_PROFILING is not set
CONFIG_MALI_SHARED_INTERRUPTS=y
+CONFIG_MALI_DT=y
CONFIG_FB=y
CONFIG_BACKLIGHT_LCD_SUPPORT=y
# CONFIG_LCD_CLASS_DEVICE is not set
@@ -444,6 +445,7 @@ CONFIG_SND_RK_SOC_RT5631=y
CONFIG_SND_RK_SOC_RT3224=y
CONFIG_SND_RK_SOC_RK3036=y
CONFIG_SND_RK_SOC_RK312X=y
+CONFIG_SND_RK_SOC_SSM2602=y
CONFIG_HIDRAW=y
CONFIG_UHID=y
CONFIG_HID_A4TECH=y
diff --git a/arch/arm/boot/dts/rk3128-fireprime.dts b/arch/arm/boot/dts/rk3128-fireprime.dts
index 303fe58..c362e9a 100755
— a/arch/arm/boot/dts/rk3128-fireprime.dts
+++ b/arch/arm/boot/dts/rk3128-fireprime.dts
@@ -122,6 +122,21 @@
test-power {
status = “okay”;
};
- audio-ssm2603a
- {
-
status = "okay";
-
compatible = "rockchip-ssm2603a";
-
dais {
-
dai0 {
-
audio-controller = <&i2s0>;
-
audio-codec = <&ssm2603a>;
-
format = "i2s";
-
//continuous-clock;
-
clocks = <&clk_i2s_2ch>, <&clk_i2s_2ch_out>, <&clk_gates7 2>;
-
clock-names = "i2s_clk", "i2s_mclk", "i2s_hclk";
-
};
-
};
- };
};
&i2c0 {
@@ -138,7 +153,16 @@ test-power {
//reset-gpio = <&gpio8 GPIO_A6 GPIO_ACTIVE_LOW>;
max-x = <1280>;
max-y = <800>;
-
};
-
ssm2603a: ssm2603@1a {
-
compatible = "adi,ssm2603";
-
reg = <0x1a>;
-
};
-
ssm2603b: ssm2603@1b {
-
compatible = "adi,ssm2603";
-
reg = <0x1b>;
-
};
};
diff --git a/sound/soc/rockchip/rk30_i2s.c b/sound/soc/rockchip/rk30_i2s.c
index 3c8b5d2..4796e8a 100755
— a/sound/soc/rockchip/rk30_i2s.c
+++ b/sound/soc/rockchip/rk30_i2s.c
@@ -63,6 +63,7 @@ struct rk30_i2s_info {
struct clk *i2s_clk;// i2s clk ,is bclk lrck
struct clk *i2s_mclk;//i2s mclk,rk32xx can different i2s clk.
struct clk *i2s_hclk;
@@ -447,7 +489,7 @@ static struct snd_soc_dai_ops rockchip_i2s_dai_ops = {
#define ROCKCHIP_I2S_STEREO_RATES SNDRV_PCM_RATE_8000_96000
#define ROCKCHIP_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
struct snd_soc_dai_driver rockchip_i2s_dai = {
{
+#define CLKFREQ 12000000 /* 24576000 */
+
#ifdef CLK_SET_lATER
static void set_clk_later_work(struct work_struct *work)
{
struct rk30_i2s_info *i2s = rk30_i2s;
}
#endif
@@ -563,6 +607,46 @@ static int rockchip_i2s_probe(struct platform_device *pdev)
}
}
- if ( pdev->id == 0 )
- {
-
int val;
-
/*GRF_SOC_CON1 sdi select GPIO0B6() or GPIO1A5(default)*/
-
val = 0;
-
val = readl_relaxed(RK_GRF_VIRT + RK312X_GRF_SOC_CON1);
-
if (1) /* 1: GPIO0B6; 0(default): GPIO1A5 */
-
{ // test OK
-
val = ( val | 0x00200020 );
-
writel_relaxed(val, RK_GRF_VIRT + RK312X_GRF_SOC_CON1);
-
printk("rk30_i2s.c: {%s} {%d} GPIO0B6 {0x%08x} val: {0x%08x}\r\n", __func__, __LINE__, RK312X_GRF_SOC_CON1, val);
-
// GPIO0B ( SSM2603 reg: 0x1a )
-
val = 0;
-
val = readl_relaxed(RK_GRF_VIRT + RK312X_GRF_GPIO0B_IOMUX);
-
val = val | 0x3DCD1545;
-
writel_relaxed(val, RK_GRF_VIRT + RK312X_GRF_GPIO0B_IOMUX);
-
}
-
else
-
{ // test FAIL
+#if 0 // if document errata
-
if ( ( val & 0x00000020) == 1 )
-
{
-
val = ( val | 0x00200000 ) & 0xFFFFFFDF;
-
writel_relaxed(val, RK_GRF_VIRT + RK312X_GRF_SOC_CON1);
-
}
+#else
-
val = ( val | 0x00200020 );
-
writel_relaxed(val, RK_GRF_VIRT + RK312X_GRF_SOC_CON1);
-
printk("rk30_i2s.c: {%s} {%d} GPIO0B6 {0x%08x} val: {0x%08x}\r\n", __func__, __LINE__, RK312X_GRF_SOC_CON1, val);
+#endif
-
printk("rk30_i2s.c: {%s} {%d} GPIO1A5 {0x%08x} val: {0x%08x}\r\n", __func__, __LINE__, RK312X_GRF_SOC_CON1, val);
-
// GPIO1A ( SSM2603 reg: 0x1b )
-
val = 0;
-
val = readl_relaxed(RK_GRF_VIRT + RK312X_GRF_GPIO1A_IOMUX);
-
val = val | 0x0f7f0555;
-
writel_relaxed(val, RK_GRF_VIRT + RK312X_GRF_GPIO1A_IOMUX);
-
}
- }
-
if(pdev->id >= MAX_I2S) {
dev_err(&pdev->dev, "id %d out of range\n", pdev->id);
ret = -ENOMEM;
@@ -595,22 +679,31 @@ static int rockchip_i2s_probe(struct platform_device *pdev)
INIT_DELAYED_WORK(&i2s->clk_delayed_work, set_clk_later_work);
schedule_delayed_work(&i2s->clk_delayed_work, msecs_to_jiffies(10));
#else
#endif
clk_prepare_enable(i2s->i2s_clk);
i2s->i2s_mclk= clk_get(&pdev->dev, "i2s_mclk");
if(IS_ERR(i2s->i2s_mclk) ) {
-
clk_set_rate(i2s->i2s_mclk, CLKFREQ);
#endif
clk_prepare_enable(i2s->i2s_mclk);
}
-
i2s->clk_i2s_2ch_out = clk_get(&pdev->dev, “clk_i2s_2ch_out”);
-
if (IS_ERR(i2s->clk_i2s_2ch_out)) {
-
dev_err(&pdev->dev, "Can't retrieve clk_i2s_2ch_out\n");
-
ret = PTR_ERR(i2s->clk_i2s_2ch_out);
-
goto err;
-
}
-
clk_prepare_enable(i2s->clk_i2s_2ch_out);
-
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mem) {
dev_err(&pdev->dev, "No memory resource\n");
diff --git a/arch/arm/boot/dts/rk312x.dtsi b/arch/arm/boot/dts/rk312x.dtsi
index 8e85546..49ab362 100755
— a/arch/arm/boot/dts/rk312x.dtsi
+++ b/arch/arm/boot/dts/rk312x.dtsi
@@ -480,10 +480,10 @@
dmas = <&pdma 0>, <&pdma 1>;
//#dma-cells = <2>;
dma-names = “tx”, “rx”;
-
//pinctrl-names = "default", "sleep";
-
//pinctrl-0 = <&i2s0_mclk &i2s0_sclk &i2s0_lrckrx &i2s0_lrcktx &i2s0_sdi &i2s0_sdo>;
-
//pinctrl-1 = <&i2s0_gpio>;
-
status = "disabled";
-
pinctrl-names = "default", "sleep";
-
pinctrl-0 = <&i2s0_mclk_mux0 &i2s0_sclk_mux0 &i2s0_lrckrx_mux0 &i2s0_lrcktx_mux0 &i2s0_sdi_mux0 &i2s0_sdo_mux0>;
-
pinctrl-1 = <&i2s0_gpio_mux0>;
-
status = "okay";
};
i2s1: i2s1@10200000 {
@@ -496,6 +496,7 @@
dmas = <&pdma 14>, <&pdma 15>;
//#dma-cells = <2>;
dma-names = “tx”, “rx”;
diff --git a/sound/soc/rockchip/Makefile b/sound/soc/rockchip/Makefile
index de59180..953ef9f 100755
— a/sound/soc/rockchip/Makefile
+++ b/sound/soc/rockchip/Makefile
@@ -42,6 +42,7 @@ snd-soc-hdmi-i2s-objs := rk_hdmi_i2s.o
snd-soc-hdmi-spdif-objs := rk_hdmi_spdif.o
snd-soc-rt5512-objs := rk_rt5512.o
snd-soc-cx2070x-objs := rk_cx2070x.o
+snd-soc-ssm2602-objs := rk_ssm2602.o
obj-$(CONFIG_SND_RK_SOC_WM8994) += snd-soc-wm8994.o
obj-$(CONFIG_SND_RK_SOC_WM8988) += snd-soc-wm8988.o
@@ -71,5 +72,6 @@ obj-$(CONFIG_SND_RK_SOC_RK3026) += snd-soc-rk3026.o
obj-$(CONFIG_SND_RK_SOC_RK3190) += snd-soc-rk3190.o
obj-$(CONFIG_SND_RK_SOC_RT5512) += snd-soc-rt5512.o
obj-$(CONFIG_SND_RK_SOC_CX2070X) += snd-soc-cx2070x.o
+obj-$(CONFIG_SND_RK_SOC_SSM2602) += snd-soc-ssm2602.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
diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c
index f8d30e5..e213d6d
— a/sound/soc/codecs/ssm2602.c
+++ b/sound/soc/codecs/ssm2602.c
@@ -773,16 +1151,25 @@ static const struct i2c_device_id ssm2602_i2c_id = {
};
MODULE_DEVICE_TABLE(i2c, ssm2602_i2c_id);
+static const struct of_device_id ssm2602_of_match = {
- { .compatible = “adi,ssm2602” },
- { .compatible = “adi,ssm2603” },
- { .compatible = “adi,ssm2604” },
- { /* Sentinel */ }
+};
/* corgi i2c codec control layer */
static struct i2c_driver ssm2602_i2c_driver = {
.driver = {
.name = “ssm2602”,
.owner = THIS_MODULE,
-
.of_match_table = of_match_ptr(ssm2602_of_match),
},
.probe = ssm2602_i2c_probe,
.remove = ssm2602_i2c_remove,
.id_table = ssm2602_i2c_id,
};
+
#endif
@@ -798,13 +1185,16 @@ static int __init ssm2602_modinit(void)
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
ret = i2c_add_driver(&ssm2602_i2c_driver);
-
if (ret != 0)
-
{
-
printk("ssm2602.c: fail to register i2c_add_driver %d {%s}{%d}\r\n", ret, __FUNCTION__, __LINE__);
return ret;
-
}
#endif
-
printk(“ssm2602.c: return 0 {%s}{%d}\r\n”, FUNCTION, LINE);
return ret;
}
-module_init(ssm2602_modinit);
static void __exit ssm2602_exit(void)
{
@@ -816,6 +1206,8 @@ static void __exit ssm2602_exit(void)
i2c_del_driver(&ssm2602_i2c_driver);
#endif
}
+MODULE_DEVICE_TABLE(i2c, ssm2602_i2c_id);
+module_init(ssm2602_modinit);
module_exit(ssm2602_exit);