[alsa-devel] [PATCH 0/5] ASoC: add simple-card DT support
Hi Mark, Simon
These patches add DT support on simple-card driver. #1 patch adds new snd_soc_of_parse_daifmt() function on soc-core.c and #5 patch will use it.
#2 - #5 patches are based on mark/topic/fsi branch
Simon
#2, #3 patches modify sh-arm platform settings. please check it
Kuninori Morimoto (5): ASoC: add snd_soc_of_parse_daifmt() ASoC: simple-card: use struct device pointer for dev_xxx() ASoC: simple-card: add asoc_simple_dai_set for initializing ASoC: simple-card: remove pointless struct asoc_simple_dai_init_info ASoC: simple-card: add Device Tree support
.../devicetree/bindings/sound/simple-card.txt | 53 ++++++++ arch/arm/mach-shmobile/board-ap4evb.c | 19 +-- arch/arm/mach-shmobile/board-armadillo800eva.c | 18 +-- arch/arm/mach-shmobile/board-kzm9g.c | 12 +- arch/arm/mach-shmobile/board-mackerel.c | 19 +-- arch/sh/boards/mach-ecovec24/setup.c | 11 +- arch/sh/boards/mach-se/7724/setup.c | 13 +- include/sound/simple_card.h | 11 +- include/sound/soc.h | 2 + sound/soc/generic/simple-card.c | 132 ++++++++++++++++---- sound/soc/soc-core.c | 115 +++++++++++++++++ 11 files changed, 307 insertions(+), 98 deletions(-)
Best regards --- Kuninori Morimoto
This patch adds snd_soc_of_parse_daifmt() and supports below style on DT.
[prefix]asoc,daifmt,fmt = "i2c"; [prefix]asoc,daifmt,closed = "continuous"; [prefix]asoc,daifmt,bitclock_inversion; [prefix]asoc,daifmt,bitclock_master; [prefix]asoc,daifmt,frame_master;
This sample will be SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CONT | SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_CBM_CFM
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- include/sound/soc.h | 2 + sound/soc/soc-core.c | 115 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+)
diff --git a/include/sound/soc.h b/include/sound/soc.h index 769e27c..e227880 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1169,6 +1169,8 @@ int snd_soc_of_parse_card_name(struct snd_soc_card *card, const char *propname); int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, const char *propname); +unsigned int snd_soc_of_parse_daifmt(struct device_node *np, + const char *prefix);
#include <sound/soc-dai.h>
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 91d592f..7e6fb5b 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -4179,6 +4179,121 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, } EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_routing);
+unsigned int snd_soc_of_parse_daifmt(struct device_node *np, + const char *prefix) +{ + int ret, i; + char prop[128]; + unsigned int format = 0; + int bit, frame; + const char *str; + struct { + char *name; + unsigned int val; + } of_fmt_table[] = { + { "i2s", SND_SOC_DAIFMT_I2S }, + { "right_j", SND_SOC_DAIFMT_RIGHT_J }, + { "left_j", SND_SOC_DAIFMT_LEFT_J }, + { "dsp_a", SND_SOC_DAIFMT_DSP_A }, + { "dsp_b", SND_SOC_DAIFMT_DSP_B }, + { "ac97", SND_SOC_DAIFMT_AC97 }, + { "pdm", SND_SOC_DAIFMT_PDM}, + { "msb", SND_SOC_DAIFMT_MSB }, + { "lsb", SND_SOC_DAIFMT_LSB }, + }, of_clock_table[] = { + { "continuous", SND_SOC_DAIFMT_CONT }, + { "gated", SND_SOC_DAIFMT_GATED }, + }; + + if (!prefix) + prefix = ""; + + /* + * check "[prefix]asoc,daifmt,fmt = xxx" + * SND_SOC_DAIFMT_FORMAT_MASK area + */ + snprintf(prop, sizeof(prop), "%sasoc,daifmt,fmt", prefix); + ret = of_property_read_string(np, prop, &str); + if (ret == 0) { + for (i = 0; i < ARRAY_SIZE(of_fmt_table); i++) { + if (strcmp(str, of_fmt_table[i].name) == 0) { + format |= of_fmt_table[i].val; + break; + } + } + } + + /* + * check "[prefix]asoc,daifmt,clock = xxx" + * SND_SOC_DAIFMT_CLOCK_MASK area + */ + snprintf(prop, sizeof(prop), "%sasoc,daifmt,clock", prefix); + ret = of_property_read_string(np, prop, &str); + if (ret == 0) { + for (i = 0; i < ARRAY_SIZE(of_clock_table); i++) { + if (strcmp(str, of_clock_table[i].name) == 0) { + format |= of_clock_table[i].val; + break; + } + } + } + + /* + * check "[prefix]asoc,daifmt,bitclock_inversion" + * check "[prefix]asoc,daifmt,frame_inversion" + * SND_SOC_DAIFMT_INV_MASK area + */ + snprintf(prop, sizeof(prop), "%sasoc,daifmt,bitclock_inversion", prefix); + bit = !!of_get_property(np, prop, NULL); + + snprintf(prop, sizeof(prop), "%sasoc,daifmt,frame_inversion", prefix); + frame = !!of_get_property(np, prop, NULL); + + switch((bit << 4) + frame) { + case 0x11: + format |= SND_SOC_DAIFMT_IB_IF; + break; + case 0x10: + format |= SND_SOC_DAIFMT_IB_NF; + break; + case 0x01: + format |= SND_SOC_DAIFMT_NB_IF; + break; + default: + /* SND_SOC_DAIFMT_NB_NF is default */ + break; + } + + /* + * check "[prefix]asoc,daifmt,bitclock_master" + * check "[prefix]asoc,daifmt,frame_master" + * SND_SOC_DAIFMT_MASTER_MASK area + */ + snprintf(prop, sizeof(prop), "%sasoc,daifmt,bitclock_master", prefix); + bit = !!of_get_property(np, prop, NULL); + + snprintf(prop, sizeof(prop), "%sasoc,daifmt,frame_master", prefix); + frame = !!of_get_property(np, prop, NULL); + + switch((bit << 4) + frame) { + case 0x11: + format |= SND_SOC_DAIFMT_CBM_CFM; + break; + case 0x10: + format |= SND_SOC_DAIFMT_CBM_CFS; + break; + case 0x01: + format |= SND_SOC_DAIFMT_CBS_CFM; + break; + default: + format |= SND_SOC_DAIFMT_CBS_CFS; + break; + } + + return format; +} +EXPORT_SYMBOL_GPL(snd_soc_of_parse_daifmt); + static int __init snd_soc_init(void) { #ifdef CONFIG_DEBUG_FS
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- sound/soc/generic/simple-card.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index b4b4cab..bc050ec 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -50,9 +50,10 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) static int asoc_simple_card_probe(struct platform_device *pdev) { struct asoc_simple_card_info *cinfo = pdev->dev.platform_data; + struct device *dev = &pdev->dev;
if (!cinfo) { - dev_err(&pdev->dev, "no info for asoc-simple-card\n"); + dev_err(dev, "no info for asoc-simple-card\n"); return -EINVAL; }
@@ -62,7 +63,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev) !cinfo->codec || !cinfo->platform || !cinfo->codec_dai) { - dev_err(&pdev->dev, "insufficient asoc_simple_card_info settings\n"); + dev_err(dev, "insufficient asoc_simple_card_info settings\n"); return -EINVAL; }
On Tue, Dec 25, 2012 at 10:52:33PM -0800, Kuninori Morimoto wrote:
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com
Applied, thanks.
Current simple-card supports sysclk settings but it is only for codec. In order to abolish deviation between cpu and codec, and in order to simplify processing, this patch adds asoc_simple_dai_set for initializing.
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- arch/arm/mach-shmobile/board-ap4evb.c | 11 +++--- arch/arm/mach-shmobile/board-armadillo800eva.c | 10 +++--- arch/arm/mach-shmobile/board-kzm9g.c | 8 ++--- arch/arm/mach-shmobile/board-mackerel.c | 11 +++--- arch/sh/boards/mach-ecovec24/setup.c | 7 ++-- arch/sh/boards/mach-se/7724/setup.c | 9 +++-- include/sound/simple_card.h | 12 ++++--- sound/soc/generic/simple-card.c | 44 ++++++++++++++---------- 8 files changed, 59 insertions(+), 53 deletions(-)
diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c index 4c97903..60e6be4 100644 --- a/arch/arm/mach-shmobile/board-ap4evb.c +++ b/arch/arm/mach-shmobile/board-ap4evb.c @@ -687,10 +687,10 @@ static struct platform_device fsi_device = { };
static struct asoc_simple_dai_init_info fsi2_ak4643_init_info = { - .fmt = SND_SOC_DAIFMT_LEFT_J, - .codec_daifmt = SND_SOC_DAIFMT_CBM_CFM, - .cpu_daifmt = SND_SOC_DAIFMT_CBS_CFS, - .sysclk = 11289600, + .daifmt = SND_SOC_DAIFMT_LEFT_J, + .cpu_set.daifmt = SND_SOC_DAIFMT_CBS_CFS, + .codec_set.daifmt = SND_SOC_DAIFMT_CBM_CFM, + .codec_set.sysclk = 11289600, };
static struct asoc_simple_card_info fsi2_ak4643_info = { @@ -810,8 +810,7 @@ static struct platform_device lcdc1_device = { };
static struct asoc_simple_dai_init_info fsi2_hdmi_init_info = { - .cpu_daifmt = SND_SOC_DAIFMT_CBM_CFM | - SND_SOC_DAIFMT_IB_NF, + .cpu_set.daifmt = SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_IB_NF, };
static struct asoc_simple_card_info fsi2_hdmi_info = { diff --git a/arch/arm/mach-shmobile/board-armadillo800eva.c b/arch/arm/mach-shmobile/board-armadillo800eva.c index 042a21e..278324c 100644 --- a/arch/arm/mach-shmobile/board-armadillo800eva.c +++ b/arch/arm/mach-shmobile/board-armadillo800eva.c @@ -808,10 +808,10 @@ static struct platform_device fsi_device = {
/* FSI-WM8978 */ static struct asoc_simple_dai_init_info fsi_wm8978_init_info = { - .fmt = SND_SOC_DAIFMT_I2S, - .codec_daifmt = SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_NB_NF, - .cpu_daifmt = SND_SOC_DAIFMT_CBS_CFS, - .sysclk = 12288000, + .daifmt = SND_SOC_DAIFMT_I2S, + .cpu_set.daifmt = SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_IB_NF, + .codec_set.daifmt = SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_NB_NF, + .codec_set.sysclk = 12288000, };
static struct asoc_simple_card_info fsi_wm8978_info = { @@ -834,7 +834,7 @@ static struct platform_device fsi_wm8978_device = {
/* FSI-HDMI */ static struct asoc_simple_dai_init_info fsi2_hdmi_init_info = { - .cpu_daifmt = SND_SOC_DAIFMT_CBM_CFM, + .cpu_set.daifmt = SND_SOC_DAIFMT_CBM_CFM, };
static struct asoc_simple_card_info fsi2_hdmi_info = { diff --git a/arch/arm/mach-shmobile/board-kzm9g.c b/arch/arm/mach-shmobile/board-kzm9g.c index 9ca7ce5..59a6dc3 100644 --- a/arch/arm/mach-shmobile/board-kzm9g.c +++ b/arch/arm/mach-shmobile/board-kzm9g.c @@ -527,10 +527,10 @@ static struct platform_device fsi_device = { };
static struct asoc_simple_dai_init_info fsi2_ak4648_init_info = { - .fmt = SND_SOC_DAIFMT_LEFT_J, - .codec_daifmt = SND_SOC_DAIFMT_CBM_CFM, - .cpu_daifmt = SND_SOC_DAIFMT_CBS_CFS, - .sysclk = 11289600, + .daifmt = SND_SOC_DAIFMT_LEFT_J, + .cpu_set.daifmt = SND_SOC_DAIFMT_CBS_CFS, + .codec_set.daifmt = SND_SOC_DAIFMT_CBM_CFM, + .codec_set.sysclk = 11289600, };
static struct asoc_simple_card_info fsi2_ak4648_info = { diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c index b5d210b..d6380be 100644 --- a/arch/arm/mach-shmobile/board-mackerel.c +++ b/arch/arm/mach-shmobile/board-mackerel.c @@ -503,8 +503,7 @@ static struct platform_device hdmi_lcdc_device = { };
static struct asoc_simple_dai_init_info fsi2_hdmi_init_info = { - .cpu_daifmt = SND_SOC_DAIFMT_CBM_CFM | - SND_SOC_DAIFMT_IB_NF, + .cpu_set.daifmt = SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_IB_NF, };
static struct asoc_simple_card_info fsi2_hdmi_info = { @@ -894,10 +893,10 @@ static struct platform_device fsi_device = { };
static struct asoc_simple_dai_init_info fsi2_ak4643_init_info = { - .fmt = SND_SOC_DAIFMT_LEFT_J, - .codec_daifmt = SND_SOC_DAIFMT_CBM_CFM, - .cpu_daifmt = SND_SOC_DAIFMT_CBS_CFS, - .sysclk = 11289600, + .daifmt = SND_SOC_DAIFMT_LEFT_J, + .cpu_set.daifmt = SND_SOC_DAIFMT_CBS_CFS, + .codec_set.daifmt = SND_SOC_DAIFMT_CBM_CFM, + .codec_set.sysclk = 11289600, };
static struct asoc_simple_card_info fsi2_ak4643_info = { diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c index 8ebe4c7..8e68d79 100644 --- a/arch/sh/boards/mach-ecovec24/setup.c +++ b/arch/sh/boards/mach-ecovec24/setup.c @@ -898,10 +898,9 @@ static struct platform_device fsi_device = { };
static struct asoc_simple_dai_init_info fsi_da7210_init_info = { - .fmt = SND_SOC_DAIFMT_I2S, - .codec_daifmt = SND_SOC_DAIFMT_CBM_CFM, - .cpu_daifmt = SND_SOC_DAIFMT_CBS_CFS | - SND_SOC_DAIFMT_IB_NF, + .daifmt = SND_SOC_DAIFMT_I2S, + .codec_set.daifmt = SND_SOC_DAIFMT_CBM_CFM, + .cpu_set.daifmt = SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_IB_NF, };
static struct asoc_simple_card_info fsi_da7210_info = { diff --git a/arch/sh/boards/mach-se/7724/setup.c b/arch/sh/boards/mach-se/7724/setup.c index 975608f..8bf853f 100644 --- a/arch/sh/boards/mach-se/7724/setup.c +++ b/arch/sh/boards/mach-se/7724/setup.c @@ -300,11 +300,10 @@ static struct platform_device fsi_device = { };
static struct asoc_simple_dai_init_info fsi2_ak4642_init_info = { - .fmt = SND_SOC_DAIFMT_LEFT_J, - .codec_daifmt = SND_SOC_DAIFMT_CBM_CFM, - .cpu_daifmt = SND_SOC_DAIFMT_CBS_CFS | - SND_SOC_DAIFMT_IB_NF, - .sysclk = 11289600, + .daifmt = SND_SOC_DAIFMT_LEFT_J, + .cpu_set.daifmt = SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_IB_NF, + .codec_set.daifmt = SND_SOC_DAIFMT_CBM_CFM, + .codec_set.sysclk = 11289600, };
static struct asoc_simple_card_info fsi_ak4642_info = { diff --git a/include/sound/simple_card.h b/include/sound/simple_card.h index 4b62b8d..f99b586 100644 --- a/include/sound/simple_card.h +++ b/include/sound/simple_card.h @@ -14,13 +14,17 @@
#include <sound/soc.h>
-struct asoc_simple_dai_init_info { - unsigned int fmt; - unsigned int cpu_daifmt; - unsigned int codec_daifmt; +struct asoc_simple_dai_set { + unsigned int daifmt; unsigned int sysclk; };
+struct asoc_simple_dai_init_info { + unsigned int daifmt; + struct asoc_simple_dai_set cpu_set; + struct asoc_simple_dai_set codec_set; +}; + struct asoc_simple_card_info { const char *name; const char *card; diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index bc050ec..aba6290 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -16,33 +16,39 @@ #define asoc_simple_get_card_info(p) \ container_of(p->dai_link, struct asoc_simple_card_info, snd_link)
+static int __asoc_simple_card_dai_init(struct snd_soc_dai *dai, + struct asoc_simple_dai_set *set, + unsigned int daifmt) +{ + int ret = 0; + + daifmt |= set->daifmt; + + if (!ret && daifmt) + ret = snd_soc_dai_set_fmt(dai, daifmt); + + if (!ret && set->sysclk) + ret = snd_soc_dai_set_sysclk(dai, 0, set->sysclk, 0); + + return ret; +} + static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) { struct asoc_simple_card_info *cinfo = asoc_simple_get_card_info(rtd); - struct asoc_simple_dai_init_info *iinfo = cinfo->init; + struct asoc_simple_dai_init_info *info = cinfo->init; struct snd_soc_dai *codec = rtd->codec_dai; struct snd_soc_dai *cpu = rtd->cpu_dai; - unsigned int cpu_daifmt = iinfo->fmt | iinfo->cpu_daifmt; - unsigned int codec_daifmt = iinfo->fmt | iinfo->codec_daifmt; + unsigned int daifmt = info->daifmt; int ret;
- if (codec_daifmt) { - ret = snd_soc_dai_set_fmt(codec, codec_daifmt); - if (ret < 0) - return ret; - } + ret = __asoc_simple_card_dai_init(codec, &info->codec_set, daifmt); + if (ret < 0) + return ret;
- if (iinfo->sysclk) { - ret = snd_soc_dai_set_sysclk(codec, 0, iinfo->sysclk, 0); - if (ret < 0) - return ret; - } - - if (cpu_daifmt) { - ret = snd_soc_dai_set_fmt(cpu, cpu_daifmt); - if (ret < 0) - return ret; - } + ret = __asoc_simple_card_dai_init(cpu, &info->cpu_set, daifmt); + if (ret < 0) + return ret;
return 0; }
Current simple-card driver calls asoc_simple_card_dai_init() if platform had a asoc_simple_card_dai_init pointer. And, this initialization function works only when platform has an applicable initial value for each snd_soc_dai_set_xxx(). And basically, almost all sound card requires certain initialization. This means that almost all platform has initialization settings, and driver do nothing if it doesn't have settings. Thus, this patch removed pointless struct asoc_simple_dai_init_info which was trigger of calling asoc_simple_card_dai_init().
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- arch/arm/mach-shmobile/board-ap4evb.c | 18 +++++------------- arch/arm/mach-shmobile/board-armadillo800eva.c | 18 +++++------------- arch/arm/mach-shmobile/board-kzm9g.c | 12 ++++-------- arch/arm/mach-shmobile/board-mackerel.c | 18 +++++------------- arch/sh/boards/mach-ecovec24/setup.c | 10 +++------- arch/sh/boards/mach-se/7724/setup.c | 12 ++++-------- include/sound/simple_card.h | 11 ++++------- sound/soc/generic/simple-card.c | 8 ++------ 8 files changed, 32 insertions(+), 75 deletions(-)
diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c index 60e6be4..1af1129 100644 --- a/arch/arm/mach-shmobile/board-ap4evb.c +++ b/arch/arm/mach-shmobile/board-ap4evb.c @@ -686,13 +686,6 @@ static struct platform_device fsi_device = { }, };
-static struct asoc_simple_dai_init_info fsi2_ak4643_init_info = { - .daifmt = SND_SOC_DAIFMT_LEFT_J, - .cpu_set.daifmt = SND_SOC_DAIFMT_CBS_CFS, - .codec_set.daifmt = SND_SOC_DAIFMT_CBM_CFM, - .codec_set.sysclk = 11289600, -}; - static struct asoc_simple_card_info fsi2_ak4643_info = { .name = "AK4643", .card = "FSI2A-AK4643", @@ -700,7 +693,10 @@ static struct asoc_simple_card_info fsi2_ak4643_info = { .codec = "ak4642-codec.0-0013", .platform = "sh_fsi2", .codec_dai = "ak4642-hifi", - .init = &fsi2_ak4643_init_info, + .daifmt = SND_SOC_DAIFMT_LEFT_J, + .cpu_set.daifmt = SND_SOC_DAIFMT_CBS_CFS, + .codec_set.daifmt = SND_SOC_DAIFMT_CBM_CFM, + .codec_set.sysclk = 11289600, };
static struct platform_device fsi_ak4643_device = { @@ -809,10 +805,6 @@ static struct platform_device lcdc1_device = { }, };
-static struct asoc_simple_dai_init_info fsi2_hdmi_init_info = { - .cpu_set.daifmt = SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_IB_NF, -}; - static struct asoc_simple_card_info fsi2_hdmi_info = { .name = "HDMI", .card = "FSI2B-HDMI", @@ -820,7 +812,7 @@ static struct asoc_simple_card_info fsi2_hdmi_info = { .codec = "sh-mobile-hdmi", .platform = "sh_fsi2", .codec_dai = "sh_mobile_hdmi-hifi", - .init = &fsi2_hdmi_init_info, + .cpu_set.daifmt = SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_IB_NF, };
static struct platform_device fsi_hdmi_device = { diff --git a/arch/arm/mach-shmobile/board-armadillo800eva.c b/arch/arm/mach-shmobile/board-armadillo800eva.c index 278324c..5d833f0 100644 --- a/arch/arm/mach-shmobile/board-armadillo800eva.c +++ b/arch/arm/mach-shmobile/board-armadillo800eva.c @@ -807,13 +807,6 @@ static struct platform_device fsi_device = { };
/* FSI-WM8978 */ -static struct asoc_simple_dai_init_info fsi_wm8978_init_info = { - .daifmt = SND_SOC_DAIFMT_I2S, - .cpu_set.daifmt = SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_IB_NF, - .codec_set.daifmt = SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_NB_NF, - .codec_set.sysclk = 12288000, -}; - static struct asoc_simple_card_info fsi_wm8978_info = { .name = "wm8978", .card = "FSI2A-WM8978", @@ -821,7 +814,10 @@ static struct asoc_simple_card_info fsi_wm8978_info = { .codec = "wm8978.0-001a", .platform = "sh_fsi2", .codec_dai = "wm8978-hifi", - .init = &fsi_wm8978_init_info, + .daifmt = SND_SOC_DAIFMT_I2S, + .cpu_set.daifmt = SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_IB_NF, + .codec_set.daifmt = SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_NB_NF, + .codec_set.sysclk = 12288000, };
static struct platform_device fsi_wm8978_device = { @@ -833,10 +829,6 @@ static struct platform_device fsi_wm8978_device = { };
/* FSI-HDMI */ -static struct asoc_simple_dai_init_info fsi2_hdmi_init_info = { - .cpu_set.daifmt = SND_SOC_DAIFMT_CBM_CFM, -}; - static struct asoc_simple_card_info fsi2_hdmi_info = { .name = "HDMI", .card = "FSI2B-HDMI", @@ -844,7 +836,7 @@ static struct asoc_simple_card_info fsi2_hdmi_info = { .codec = "sh-mobile-hdmi", .platform = "sh_fsi2", .codec_dai = "sh_mobile_hdmi-hifi", - .init = &fsi2_hdmi_init_info, + .cpu_set.daifmt = SND_SOC_DAIFMT_CBM_CFM, };
static struct platform_device fsi_hdmi_device = { diff --git a/arch/arm/mach-shmobile/board-kzm9g.c b/arch/arm/mach-shmobile/board-kzm9g.c index 59a6dc3..1c1be72 100644 --- a/arch/arm/mach-shmobile/board-kzm9g.c +++ b/arch/arm/mach-shmobile/board-kzm9g.c @@ -526,13 +526,6 @@ static struct platform_device fsi_device = { }, };
-static struct asoc_simple_dai_init_info fsi2_ak4648_init_info = { - .daifmt = SND_SOC_DAIFMT_LEFT_J, - .cpu_set.daifmt = SND_SOC_DAIFMT_CBS_CFS, - .codec_set.daifmt = SND_SOC_DAIFMT_CBM_CFM, - .codec_set.sysclk = 11289600, -}; - static struct asoc_simple_card_info fsi2_ak4648_info = { .name = "AK4648", .card = "FSI2A-AK4648", @@ -540,7 +533,10 @@ static struct asoc_simple_card_info fsi2_ak4648_info = { .codec = "ak4642-codec.0-0012", .platform = "sh_fsi2", .codec_dai = "ak4642-hifi", - .init = &fsi2_ak4648_init_info, + .daifmt = SND_SOC_DAIFMT_LEFT_J, + .cpu_set.daifmt = SND_SOC_DAIFMT_CBS_CFS, + .codec_set.daifmt = SND_SOC_DAIFMT_CBM_CFM, + .codec_set.sysclk = 11289600, };
static struct platform_device fsi_ak4648_device = { diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c index d6380be..93e144f 100644 --- a/arch/arm/mach-shmobile/board-mackerel.c +++ b/arch/arm/mach-shmobile/board-mackerel.c @@ -502,10 +502,6 @@ static struct platform_device hdmi_lcdc_device = { }, };
-static struct asoc_simple_dai_init_info fsi2_hdmi_init_info = { - .cpu_set.daifmt = SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_IB_NF, -}; - static struct asoc_simple_card_info fsi2_hdmi_info = { .name = "HDMI", .card = "FSI2B-HDMI", @@ -513,7 +509,7 @@ static struct asoc_simple_card_info fsi2_hdmi_info = { .codec = "sh-mobile-hdmi", .platform = "sh_fsi2", .codec_dai = "sh_mobile_hdmi-hifi", - .init = &fsi2_hdmi_init_info, + .cpu_set.daifmt = SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_IB_NF, };
static struct platform_device fsi_hdmi_device = { @@ -892,13 +888,6 @@ static struct platform_device fsi_device = { }, };
-static struct asoc_simple_dai_init_info fsi2_ak4643_init_info = { - .daifmt = SND_SOC_DAIFMT_LEFT_J, - .cpu_set.daifmt = SND_SOC_DAIFMT_CBS_CFS, - .codec_set.daifmt = SND_SOC_DAIFMT_CBM_CFM, - .codec_set.sysclk = 11289600, -}; - static struct asoc_simple_card_info fsi2_ak4643_info = { .name = "AK4643", .card = "FSI2A-AK4643", @@ -906,7 +895,10 @@ static struct asoc_simple_card_info fsi2_ak4643_info = { .codec = "ak4642-codec.0-0013", .platform = "sh_fsi2", .codec_dai = "ak4642-hifi", - .init = &fsi2_ak4643_init_info, + .daifmt = SND_SOC_DAIFMT_LEFT_J, + .cpu_set.daifmt = SND_SOC_DAIFMT_CBS_CFS, + .codec_set.daifmt = SND_SOC_DAIFMT_CBM_CFM, + .codec_set.sysclk = 11289600, };
static struct platform_device fsi_ak4643_device = { diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c index 8e68d79..6e534e3 100644 --- a/arch/sh/boards/mach-ecovec24/setup.c +++ b/arch/sh/boards/mach-ecovec24/setup.c @@ -897,12 +897,6 @@ static struct platform_device fsi_device = { .resource = fsi_resources, };
-static struct asoc_simple_dai_init_info fsi_da7210_init_info = { - .daifmt = SND_SOC_DAIFMT_I2S, - .codec_set.daifmt = SND_SOC_DAIFMT_CBM_CFM, - .cpu_set.daifmt = SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_IB_NF, -}; - static struct asoc_simple_card_info fsi_da7210_info = { .name = "DA7210", .card = "FSIB-DA7210", @@ -910,7 +904,9 @@ static struct asoc_simple_card_info fsi_da7210_info = { .codec = "da7210.0-001a", .platform = "sh_fsi.0", .codec_dai = "da7210-hifi", - .init = &fsi_da7210_init_info, + .daifmt = SND_SOC_DAIFMT_I2S, + .codec_set.daifmt = SND_SOC_DAIFMT_CBM_CFM, + .cpu_set.daifmt = SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_IB_NF, };
static struct platform_device fsi_da7210_device = { diff --git a/arch/sh/boards/mach-se/7724/setup.c b/arch/sh/boards/mach-se/7724/setup.c index 8bf853f..eb87bd4 100644 --- a/arch/sh/boards/mach-se/7724/setup.c +++ b/arch/sh/boards/mach-se/7724/setup.c @@ -299,13 +299,6 @@ static struct platform_device fsi_device = { .resource = fsi_resources, };
-static struct asoc_simple_dai_init_info fsi2_ak4642_init_info = { - .daifmt = SND_SOC_DAIFMT_LEFT_J, - .cpu_set.daifmt = SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_IB_NF, - .codec_set.daifmt = SND_SOC_DAIFMT_CBM_CFM, - .codec_set.sysclk = 11289600, -}; - static struct asoc_simple_card_info fsi_ak4642_info = { .name = "AK4642", .card = "FSIA-AK4642", @@ -313,7 +306,10 @@ static struct asoc_simple_card_info fsi_ak4642_info = { .codec = "ak4642-codec.0-0012", .platform = "sh_fsi.0", .codec_dai = "ak4642-hifi", - .init = &fsi2_ak4642_init_info, + .daifmt = SND_SOC_DAIFMT_LEFT_J, + .cpu_set.daifmt = SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_IB_NF, + .codec_set.daifmt = SND_SOC_DAIFMT_CBM_CFM, + .codec_set.sysclk = 11289600, };
static struct platform_device fsi_ak4642_device = { diff --git a/include/sound/simple_card.h b/include/sound/simple_card.h index f99b586..124cedc 100644 --- a/include/sound/simple_card.h +++ b/include/sound/simple_card.h @@ -19,12 +19,6 @@ struct asoc_simple_dai_set { unsigned int sysclk; };
-struct asoc_simple_dai_init_info { - unsigned int daifmt; - struct asoc_simple_dai_set cpu_set; - struct asoc_simple_dai_set codec_set; -}; - struct asoc_simple_card_info { const char *name; const char *card; @@ -32,7 +26,10 @@ struct asoc_simple_card_info { const char *codec; const char *platform; const char *codec_dai; - struct asoc_simple_dai_init_info *init; /* for snd_link.init */ + + unsigned int daifmt; + struct asoc_simple_dai_set cpu_set; + struct asoc_simple_dai_set codec_set;
/* used in simple-card.c */ struct snd_soc_dai_link snd_link; diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index aba6290..94faeb5 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -35,8 +35,7 @@ static int __asoc_simple_card_dai_init(struct snd_soc_dai *dai,
static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) { - struct asoc_simple_card_info *cinfo = asoc_simple_get_card_info(rtd); - struct asoc_simple_dai_init_info *info = cinfo->init; + struct asoc_simple_card_info *info = asoc_simple_get_card_info(rtd); struct snd_soc_dai *codec = rtd->codec_dai; struct snd_soc_dai *cpu = rtd->cpu_dai; unsigned int daifmt = info->daifmt; @@ -82,10 +81,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev) cinfo->snd_link.platform_name = cinfo->platform; cinfo->snd_link.codec_name = cinfo->codec; cinfo->snd_link.codec_dai_name = cinfo->codec_dai; - - /* enable snd_link.init if cinfo has settings */ - if (cinfo->init) - cinfo->snd_link.init = asoc_simple_card_dai_init; + cinfo->snd_link.init = asoc_simple_card_dai_init;
/* * init snd_soc_card
Support for loading the simple-card module via devicetree. It requests platform/codec driver's DT blob for probing.
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- .../devicetree/bindings/sound/simple-card.txt | 53 +++++++++++++ sound/soc/generic/simple-card.c | 81 +++++++++++++++++++- 2 files changed, 131 insertions(+), 3 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/simple-card.txt
diff --git a/Documentation/devicetree/bindings/sound/simple-card.txt b/Documentation/devicetree/bindings/sound/simple-card.txt new file mode 100644 index 0000000..9f069bc --- /dev/null +++ b/Documentation/devicetree/bindings/sound/simple-card.txt @@ -0,0 +1,53 @@ +Simple-Card + +Required properties: +for simple-card +- compatible : "asoc,simple-card" +- simple,asoc,name : simple card name +- simple,asoc,cpu : phandle for platform +- simple,asoc,codec : phandle for codec + +for platform +- simple,asoc,dai : dai name + +for codec +- simple,asoc,dai : dai name +- simple,asoc,name : codec name + +both platform/codec +- simple,asoc,daifmt,fmt : see snd_soc_of_parse_daifmt() +- simple,asoc,daifmt,clock : see snd_soc_of_parse_daifmt() +- simple,asoc,daifmt,bitclock_inversion : see snd_soc_of_parse_daifmt() +- simple,asoc,daifmt,bitclock_master : see snd_soc_of_parse_daifmt() +- simple,asoc,daifmt,frame_inversion : see snd_soc_of_parse_daifmt() +- simple,asoc,daifmt,frame_master : see snd_soc_of_parse_daifmt() +- simple,asoc,sysclk : system clock rate + +Example: + +fsi_ak4642 { + compatible = "asoc,simple-card"; + + simple,asoc,name = "FSI2A-AK4648"; + simple,asoc,cpu = <&sh_fsi2>; + simple,asoc,codec = <&ak4648>; +}; + +&i2c0 { + ak4648: ak4648@0x12 { + compatible = "asahi-kasei,ak4648"; + reg = <0x12>; + + simple,asoc,dai = "ak4642-hifi"; + simple,asoc,name = "ak4642-codec.0-0012"; + simple,asoc,daifmt,fmt = "left_j"; + simple,asoc,daifmt,bitclock_master; + simple,asoc,daifmt,frame_master; + simple,asoc,sysclk = <11289600>; + }; +}; + +&sh_fsi2 { + simple,asoc,dai = "fsia-dai"; + simple,asoc,daifmt,fmt = "left_j"; +}; diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 94faeb5..73532cd 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -9,6 +9,7 @@ * published by the Free Software Foundation. */
+#include <linux/of.h> #include <linux/platform_device.h> #include <linux/module.h> #include <sound/simple_card.h> @@ -52,11 +53,78 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) return 0; }
+static void __asoc_simple_card_parse_of(struct device_node *phandle, + struct asoc_simple_dai_set *set) +{ + /* get "simple,asoc,daifmt,xxx = xxx" */ + set->daifmt = snd_soc_of_parse_daifmt(phandle, "simple,"); + + /* get "simple,asoc,sysclk = xxx" */ + of_property_read_u32(phandle, "simple,asoc,sysclk", &set->sysclk); +} + +static struct device_node* +asoc_simple_card_parse_of(struct device_node *np, + struct asoc_simple_card_info *info, + struct device *dev) +{ + struct device_node *cpu, *codec; + + codec = of_parse_phandle(np, "simple,asoc,codec", 0); + if (!codec) { + dev_err(dev, "Can't find codec phandle\n"); + return NULL; + } + + cpu = of_parse_phandle(np, "simple,asoc,cpu", 0); + if (!cpu) { + dev_err(dev, "Can't find cpu phandle\n"); + goto cpu_fail; + } + + __asoc_simple_card_parse_of(cpu, &info->cpu_set); + __asoc_simple_card_parse_of(codec, &info->codec_set); + + info->name = codec->name; + of_property_read_string(np, "simple,asoc,name", &info->card); + of_property_read_string(cpu, "simple,asoc,dai", &info->cpu_dai); + of_property_read_string(codec, "simple,asoc,dai", &info->codec_dai); + of_property_read_string(codec, "simple,asoc,name", &info->codec); + + dev_dbg(dev, "name : %s\n", info->name); + dev_dbg(dev, "card : %s\n", info->card); + dev_dbg(dev, "cpu_dai : %s\n", info->cpu_dai); + dev_dbg(dev, "codec_dai : %s\n", info->codec_dai); + dev_dbg(dev, "codec_name : %s\n", info->codec); + dev_dbg(dev, "cpu daifmt : %x\n", info->cpu_set.daifmt); + dev_dbg(dev, "cpu sysclk : %d\n", info->cpu_set.sysclk); + dev_dbg(dev, "codec daifmt : %x\n", info->codec_set.daifmt); + dev_dbg(dev, "codec sysclk : %d\n", info->codec_set.sysclk); + + of_node_put(cpu); +cpu_fail: + of_node_put(codec); + + return cpu; +} + static int asoc_simple_card_probe(struct platform_device *pdev) { - struct asoc_simple_card_info *cinfo = pdev->dev.platform_data; + struct asoc_simple_card_info *cinfo; + struct device_node *np = pdev->dev.of_node; + struct device_node *platform; struct device *dev = &pdev->dev;
+ cinfo = NULL; + platform = NULL; + if (np && of_device_is_available(np)) { + cinfo = devm_kzalloc(dev, sizeof(*cinfo), GFP_KERNEL); + if (cinfo) + platform = asoc_simple_card_parse_of(np, cinfo, dev); + } else { + cinfo = pdev->dev.platform_data; + } + if (!cinfo) { dev_err(dev, "no info for asoc-simple-card\n"); return -EINVAL; @@ -66,8 +134,8 @@ static int asoc_simple_card_probe(struct platform_device *pdev) !cinfo->card || !cinfo->cpu_dai || !cinfo->codec || - !cinfo->platform || - !cinfo->codec_dai) { + !cinfo->codec_dai || + (!cinfo->platform && !platform)) { dev_err(dev, "insufficient asoc_simple_card_info settings\n"); return -EINVAL; } @@ -81,6 +149,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev) cinfo->snd_link.platform_name = cinfo->platform; cinfo->snd_link.codec_name = cinfo->codec; cinfo->snd_link.codec_dai_name = cinfo->codec_dai; + cinfo->snd_link.platform_of_node = platform; cinfo->snd_link.init = asoc_simple_card_dai_init;
/* @@ -102,9 +171,15 @@ static int asoc_simple_card_remove(struct platform_device *pdev) return snd_soc_unregister_card(&cinfo->snd_card); }
+static const struct of_device_id asoc_simple_of_match[] = { + { .compatible = "asoc,simple-card", }, + {}, +}; + static struct platform_driver asoc_simple_card = { .driver = { .name = "asoc-simple-card", + .of_match_table = asoc_simple_of_match, }, .probe = asoc_simple_card_probe, .remove = asoc_simple_card_remove,
On 12/25/2012 11:53 PM, Kuninori Morimoto wrote:
Support for loading the simple-card module via devicetree. It requests platform/codec driver's DT blob for probing.
This binding proposal should be sent to devicetree-discuss@lists.ozlabs.org; that's where all DT bindings are dicussed.
diff --git a/Documentation/devicetree/bindings/sound/simple-card.txt b/Documentation/devicetree/bindings/sound/simple-card.txt
+Required properties: +for simple-card +- compatible : "asoc,simple-card"
I don't think "asoc," is a good vendor prefix; DT should strive to describe the hardware, not a particular OS's driver structure.
Perhaps "simple-audio" would be better.
+- simple,asoc,name : simple card name
What is "simple,asoc,"? I've never seen properties with two vendor prefixes before... Perhaps "simple-audio," would be better.
What kind of name? Perhaps "simple-audio,model" would be better, and more consistent with the use of the word "model" in other audio-related DT bindings? Describe it as "user-visible card name"?
+- simple,asoc,cpu : phandle for platform
"cpu" isn't a very good name; it couuld mean anything. "platform" is an ASoC-specific term. I think this would be better written as:
simple-audio,cpu-audio-controller : phandle of the CPU's audio controller
or perhaps:
simple-audio,cpu-port : phandle of the CPU's audio port
or since I assume this binding assumes I2S rather than say AC'97 or SlimBus, perhaps:
simple-audio,i2c-controller : phandle of the CPU's I2S controller
+- simple,asoc,codec : phandle for codec
CODEC should be capitalized in the plain-text description (but not DT property name). Same for DAI below.
+for platform +- simple,asoc,dai : dai name
+for codec +- simple,asoc,dai : dai name +- simple,asoc,name : codec name
Why are names needed? The existing audio-related DT bindings don't put any names into the device tree; everything binds with phandles.
+both platform/codec +- simple,asoc,daifmt,fmt : see snd_soc_of_parse_daifmt() +- simple,asoc,daifmt,clock : see snd_soc_of_parse_daifmt() +- simple,asoc,daifmt,bitclock_inversion : see snd_soc_of_parse_daifmt() +- simple,asoc,daifmt,bitclock_master : see snd_soc_of_parse_daifmt() +- simple,asoc,daifmt,frame_inversion : see snd_soc_of_parse_daifmt() +- simple,asoc,daifmt,frame_master : see snd_soc_of_parse_daifmt()
DT bindings should be self-contained, i.e. they should describe everything required to write the device tree (with the possible exception of referring to other existing manuals or documentation for the HW). In particular, they shouldn't refer to code in some specific OS. As such, please explain what all those mean here.
It is more typical to use - not _ as a word separator in DT property names.
"bitclock_master" doesn't really describe who is the master. Perhaps "cpu-bitclk-master"?
What is "clock"?
+- simple,asoc,sysclk : system clock rate
"clock-frequency" rather than "sysclk" would be more consistent with other bindings.
+Example:
+fsi_ak4642 {
- compatible = "asoc,simple-card";
- simple,asoc,name = "FSI2A-AK4648";
- simple,asoc,cpu = <&sh_fsi2>;
- simple,asoc,codec = <&ak4648>;
+};
+&i2c0 {
- ak4648: ak4648@0x12 {
compatible = "asahi-kasei,ak4648";
reg = <0x12>;
simple,asoc,dai = "ak4642-hifi";
simple,asoc,name = "ak4642-codec.0-0012";
simple,asoc,daifmt,fmt = "left_j";
simple,asoc,daifmt,bitclock_master;
simple,asoc,daifmt,frame_master;
simple,asoc,sysclk = <11289600>;
- };
+};
+&sh_fsi2 {
- simple,asoc,dai = "fsia-dai";
- simple,asoc,daifmt,fmt = "left_j";
+};
Oh, I see. Nothing in the text above implies that the DAI format properties would exist in the CODEC and I2S controller nodes. That's rather an imposition on the DT bindings for the CODEC and I2S controller; the individual bindings for those devices should define all the properties that go into those nodes, and those devices won't always be used with a "simple" sound card. It feels to me like the DAI configuration properties should be part of the sound node, not the I2S/CODEC nodes.
On Fri, Jan 04, 2013 at 10:49:12AM -0700, Stephen Warren wrote:
On 12/25/2012 11:53 PM, Kuninori Morimoto wrote:
+- simple,asoc,cpu : phandle for platform
"cpu" isn't a very good name; it couuld mean anything. "platform" is an ASoC-specific term. I think this would be better written as:
simple-audio,cpu-audio-controller : phandle of the CPU's audio controller
or perhaps:
simple-audio,cpu-port : phandle of the CPU's audio port
or since I assume this binding assumes I2S rather than say AC'97 or SlimBus, perhaps:
simple-audio,i2c-controller : phandle of the CPU's I2S controller
The binding is pretty agnostic as to the interface given that the bus-specifics are in optional properties.
+- simple,asoc,sysclk : system clock rate
"clock-frequency" rather than "sysclk" would be more consistent with other bindings.
I think specifying the particular clock being referenced is useful here - we may also end up wanting to specify the BCLK or sample rate due to some hardware limitation on some system both of which are clocks too.
Hi Stephen, Mark
Support for loading the simple-card module via devicetree. It requests platform/codec driver's DT blob for probing.
This binding proposal should be sent to devicetree-discuss@lists.ozlabs.org; that's where all DT bindings are dicussed.
will do
+Required properties: +for simple-card +- compatible : "asoc,simple-card"
I don't think "asoc," is a good vendor prefix; DT should strive to describe the hardware, not a particular OS's driver structure.
Perhaps "simple-audio" would be better.
Thanks.
+- simple,asoc,cpu : phandle for platform
"cpu" isn't a very good name; it couuld mean anything. "platform" is an ASoC-specific term. I think this would be better written as:
simple-audio,cpu-audio-controller : phandle of the CPU's audio controller
or perhaps:
simple-audio,cpu-port : phandle of the CPU's audio port
Thank you. I would like to use "cpu-port" and "codec-port"
+for platform +- simple,asoc,dai : dai name
+for codec +- simple,asoc,dai : dai name +- simple,asoc,name : codec name
Why are names needed? The existing audio-related DT bindings don't put any names into the device tree; everything binds with phandles.
(snip)
Oh, I see. Nothing in the text above implies that the DAI format properties would exist in the CODEC and I2S controller nodes. That's rather an imposition on the DT bindings for the CODEC and I2S controller; the individual bindings for those devices should define all the properties that go into those nodes, and those devices won't always be used with a "simple" sound card. It feels to me like the DAI configuration properties should be part of the sound node, not the I2S/CODEC nodes.
Thank you for your advice. I modify this design.
+- simple,asoc,sysclk : system clock rate
"clock-frequency" rather than "sysclk" would be more consistent with other bindings.
(snip)
I think specifying the particular clock being referenced is useful here
- we may also end up wanting to specify the BCLK or sample rate due to
some hardware limitation on some system both of which are clocks too.
I will use "system-clock-frequency" here
Hi Mark, Stephen
These patches add snd_soc_of_parse_daifmt() and simple-card DT support
Kuninori Morimoto (2): ASoC: add snd_soc_of_parse_daifmt() for DeviceTree ASoC: simple-card: add Device Tree support
.../devicetree/bindings/sound/simple-card.txt | 77 +++++++++++++ include/sound/soc.h | 2 + sound/soc/generic/simple-card.c | 108 +++++++++++++++++- sound/soc/soc-core.c | 115 ++++++++++++++++++++ 4 files changed, 297 insertions(+), 5 deletions(-)
This patch adds snd_soc_of_parse_daifmt() and supports below style on DT.
[prefix]format = "i2c"; [prefix]clock-gating = "continuous"; [prefix]bitclock-inversion; [prefix]bitclock-master; [prefix]frame-master;
Each driver can use specific [prefix] (ex simple-card,cpu,dai,format = xxx;)
This sample will be SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CONT | SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_CBM_CFM
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com ---
v1 -> v2
- modify git log explain
include/sound/soc.h | 2 + sound/soc/soc-core.c | 115 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+)
diff --git a/include/sound/soc.h b/include/sound/soc.h index 769e27c..e227880 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1169,6 +1169,8 @@ int snd_soc_of_parse_card_name(struct snd_soc_card *card, const char *propname); int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, const char *propname); +unsigned int snd_soc_of_parse_daifmt(struct device_node *np, + const char *prefix);
#include <sound/soc-dai.h>
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 91d592f..cca411b 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -4179,6 +4179,121 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, } EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_routing);
+unsigned int snd_soc_of_parse_daifmt(struct device_node *np, + const char *prefix) +{ + int ret, i; + char prop[128]; + unsigned int format = 0; + int bit, frame; + const char *str; + struct { + char *name; + unsigned int val; + } of_fmt_table[] = { + { "i2s", SND_SOC_DAIFMT_I2S }, + { "right_j", SND_SOC_DAIFMT_RIGHT_J }, + { "left_j", SND_SOC_DAIFMT_LEFT_J }, + { "dsp_a", SND_SOC_DAIFMT_DSP_A }, + { "dsp_b", SND_SOC_DAIFMT_DSP_B }, + { "ac97", SND_SOC_DAIFMT_AC97 }, + { "pdm", SND_SOC_DAIFMT_PDM}, + { "msb", SND_SOC_DAIFMT_MSB }, + { "lsb", SND_SOC_DAIFMT_LSB }, + }, of_clock_table[] = { + { "continuous", SND_SOC_DAIFMT_CONT }, + { "gated", SND_SOC_DAIFMT_GATED }, + }; + + if (!prefix) + prefix = ""; + + /* + * check "[prefix]format = xxx" + * SND_SOC_DAIFMT_FORMAT_MASK area + */ + snprintf(prop, sizeof(prop), "%sformat", prefix); + ret = of_property_read_string(np, prop, &str); + if (ret == 0) { + for (i = 0; i < ARRAY_SIZE(of_fmt_table); i++) { + if (strcmp(str, of_fmt_table[i].name) == 0) { + format |= of_fmt_table[i].val; + break; + } + } + } + + /* + * check "[prefix]clock-gating = xxx" + * SND_SOC_DAIFMT_CLOCK_MASK area + */ + snprintf(prop, sizeof(prop), "%sclock-gating", prefix); + ret = of_property_read_string(np, prop, &str); + if (ret == 0) { + for (i = 0; i < ARRAY_SIZE(of_clock_table); i++) { + if (strcmp(str, of_clock_table[i].name) == 0) { + format |= of_clock_table[i].val; + break; + } + } + } + + /* + * check "[prefix]bitclock-inversion" + * check "[prefix]frame-inversion" + * SND_SOC_DAIFMT_INV_MASK area + */ + snprintf(prop, sizeof(prop), "%sbitclock-inversion", prefix); + bit = !!of_get_property(np, prop, NULL); + + snprintf(prop, sizeof(prop), "%sframe-inversion", prefix); + frame = !!of_get_property(np, prop, NULL); + + switch ((bit << 4) + frame) { + case 0x11: + format |= SND_SOC_DAIFMT_IB_IF; + break; + case 0x10: + format |= SND_SOC_DAIFMT_IB_NF; + break; + case 0x01: + format |= SND_SOC_DAIFMT_NB_IF; + break; + default: + /* SND_SOC_DAIFMT_NB_NF is default */ + break; + } + + /* + * check "[prefix]bitclock-master" + * check "[prefix]frame-master" + * SND_SOC_DAIFMT_MASTER_MASK area + */ + snprintf(prop, sizeof(prop), "%sbitclock-master", prefix); + bit = !!of_get_property(np, prop, NULL); + + snprintf(prop, sizeof(prop), "%sframe-master", prefix); + frame = !!of_get_property(np, prop, NULL); + + switch ((bit << 4) + frame) { + case 0x11: + format |= SND_SOC_DAIFMT_CBM_CFM; + break; + case 0x10: + format |= SND_SOC_DAIFMT_CBM_CFS; + break; + case 0x01: + format |= SND_SOC_DAIFMT_CBS_CFM; + break; + default: + format |= SND_SOC_DAIFMT_CBS_CFS; + break; + } + + return format; +} +EXPORT_SYMBOL_GPL(snd_soc_of_parse_daifmt); + static int __init snd_soc_init(void) { #ifdef CONFIG_DEBUG_FS
Hi Mark
This patch adds snd_soc_of_parse_daifmt() and supports below style on DT.
Applied, thanks.
Thank you.
Now, I'm afraid about this snd_soc_of_parse_daifmt() patch. I created this to be possible to share to get SND_SOC_xxxx flags between all drivers on DT. But now simple-card is the only user for it, and it seems can't use this snd_soc_of_parse_daifmt() directly. (snd_soc_of_parse_daifmt() will get all flags, but the flag field seems depends on driver/platform) of course, simple-card can use it with special mask, like flag = snd_soc_of_parse_daifmt() & SND_SOC_xxx_MASK.
I'm not sure what is the best way, but if it is no-sense to have this function under asoc-core, can you remove asoc/topic/of ?
Best regards --- Kuninori Morimoto
Hi Kuninori Morimoto
于 2013/1/15 10:36, Kuninori Morimoto 写道:
This patch adds snd_soc_of_parse_daifmt() and supports below style on DT.
[prefix]format = "i2c";
I think there should be "i2s".
Best Regards Bo Shen
Support for loading the simple-card module via devicetree. It requests cpu/codec/platform information for probing.
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com ---
v1 -> v2
- compatible used "simple-audio" - fixup each property names - properties are on "simple-audio" - add format/clock-gating explain on simple-audio.txt
This patch is using "simple-audio,xxx,controller" for phandle but should it use "simple-audio,xxx,dai,controller" ?
- simple-audio,xxx,controller ? - simple-audio,xxx,dai,controller ?
.../devicetree/bindings/sound/simple-card.txt | 77 ++++++++++++++ sound/soc/generic/simple-card.c | 108 +++++++++++++++++++- 2 files changed, 180 insertions(+), 5 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/simple-card.txt
diff --git a/Documentation/devicetree/bindings/sound/simple-card.txt b/Documentation/devicetree/bindings/sound/simple-card.txt new file mode 100644 index 0000000..5c7794a --- /dev/null +++ b/Documentation/devicetree/bindings/sound/simple-card.txt @@ -0,0 +1,77 @@ +Simple-Card: + +Required properties: + +- compatible : "simple-audio" +- simple-audio,card-name : simple-audio card name + +- simple-audio,platform,controller : phandle for platform +- simple-audio,platform,name : simple-audio platform name + +- simple-audio,cpu,controller : phandle for CPU DAI +- simple-audio,cpu,dai,name : simple-audio CPU DAI name +- simple-audio,cpu,dai,format : see below +- simple-audio,cpu,dai,clock-gating : if needed, see below +- simple-audio,cpu,dai,bitclock-inversion : if needed +- simple-audio,cpu,dai,bitclock-master : if needed +- simple-audio,cpu,dai,frame-inversion : if needed +- simple-audio,cpu,dai,frame-master : if needed +- simple-audio,cpu,dai,system-clock-frequency : system clock rate if needed + +- simple-audio,codec,controller : phandle for CODEC DAI +- simple-audio,codec,dai,name : simple-audio CODEC DAI name +- simple-audio,codec,dai,format : see below +- simple-audio,codec,dai,clock-gating : if needed, see below +- simple-audio,codec,dai,bitclock-inversion : if needed +- simple-audio,codec,dai,bitclock-master : if needed +- simple-audio,codec,dai,frame-inversion : if needed +- simple-audio,codec,dai,frame-master : if needed +- simple-audio,codec,dai,system-clock-frequency : system clock rate if needed + +simple-audio,xxx,dai,format + "i2s" + "right_j" + "left_j" + "dsp_a" + "dsp_b" + "ac97" + "pdm" + "msb" + "lsb" + +simple-audio,xxx,dai,clock-gating + "continuous" + "gated" + +Example: + +fsi_ak4642 { + compatible = "simple-audio"; + + simple-audio,card-name = "FSI2A-AK4648"; + simple-audio,platform,controller = <&sh_fsi2>; + + simple-audio,cpu,dai,name = "fsia-dai"; + simple-audio,cpu,dai,format = "left_j"; + + simple-audio,codec,controller = <&ak4648>; + simple-audio,codec,dai,name = "ak4642-hifi"; + simple-audio,codec,dai,format = "left_j"; + simple-audio,codec,dai,bitclock-master; + simple-audio,codec,dai,frame-master; + simple-audio,codec,dai,system-clock-frequency = <11289600>; +}; + +&i2c0 { + ak4648: ak4648@0x12 { + compatible = "asahi-kasei,ak4648"; + reg = <0x12>; + }; +}; + +sh_fsi2: sh_fsi2@0xec230000 { + compatible = "renesas,sh_fsi2"; + reg = <0xec230000 0x400>; + interrupt-parent = <&gic>; + interrupts = <0 146 0x4>; +}; diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 6cf8355..72dd8ae 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -9,6 +9,7 @@ * published by the Free Software Foundation. */
+#include <linux/of.h> #include <linux/platform_device.h> #include <linux/module.h> #include <sound/simple_card.h> @@ -52,11 +53,99 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) return 0; }
+static struct device_node* +__asoc_simple_card_parse_of(struct device_node *np, + const char *node_name1, + const char *node_name2, + const char **interface, + struct asoc_simple_dai *dai) +{ + struct device_node *node; + char prop[128]; + + /* node or name is required */ + snprintf(prop, sizeof(prop), + "simple-audio,%s,controller", node_name1); + node = of_parse_phandle(np, prop, 0); + if (node) + of_node_put(node); + + /* get "simple-audio,xxx,yyy,name = xxx" */ + snprintf(prop, sizeof(prop), + "simple-audio,%s%s,name", node_name1, node_name2); + of_property_read_string(np, prop, interface); + + if (dai) { + /* get "simple-audio,xxx,yyy,formart = xxx" */ + snprintf(prop, sizeof(prop), + "simple-audio,%s%s,", node_name1, node_name2); + dai->fmt = snd_soc_of_parse_daifmt(np, prop); + + /* get "simple-audio,xxx,yyy,system-clock-frequency = <xxx>" */ + snprintf(prop, sizeof(prop), + "simple-audio,%s%s,system-clock-frequency", + node_name1, node_name2); + of_property_read_u32(np, prop, &dai->sysclk); + } + + return node; +} + +static void asoc_simple_card_parse_of(struct device_node *np, + struct asoc_simple_card_info *info, + struct device *dev, + struct device_node **of_cpu, + struct device_node **of_codec, + struct device_node **of_platform) +{ + of_property_read_string(np, "simple-audio,card-name", &info->card); + info->name = info->card; + + *of_cpu = __asoc_simple_card_parse_of( + np, "cpu", ",dai", &info->cpu_dai.name, &info->cpu_dai); + *of_codec = __asoc_simple_card_parse_of( + np, "codec", ",dai", &info->codec_dai.name, &info->codec_dai); + *of_platform = __asoc_simple_card_parse_of( + np, "platform", "", &info->platform, NULL); + + dev_dbg(dev, "card-name : %s\n", info->card); + dev_dbg(dev, "cpu info : %s / %x / %d / %p\n", + info->cpu_dai.name, + info->cpu_dai.fmt, + info->cpu_dai.sysclk, + *of_cpu); + dev_dbg(dev, "codec_info : %s / %x / %d / %p\n", + info->codec_dai.name, + info->codec_dai.fmt, + info->codec_dai.sysclk, + *of_codec); + dev_dbg(dev, "platform_info : %s / %p\n", + info->platform, + *of_platform); +} + static int asoc_simple_card_probe(struct platform_device *pdev) { - struct asoc_simple_card_info *cinfo = pdev->dev.platform_data; + struct asoc_simple_card_info *cinfo; + struct device_node *np = pdev->dev.of_node; + struct device_node *of_cpu, *of_codec, *of_platform; struct device *dev = &pdev->dev;
+ cinfo = NULL; + of_cpu = NULL; + of_codec = NULL; + of_platform = NULL; + if (np && of_device_is_available(np)) { + cinfo = devm_kzalloc(dev, sizeof(*cinfo), GFP_KERNEL); + if (cinfo) + asoc_simple_card_parse_of(np, cinfo, dev, + &of_cpu, + &of_codec, + &of_platform); + } else { + cinfo = pdev->dev.platform_data; + } + if (!cinfo) { dev_err(dev, "no info for asoc-simple-card\n"); return -EINVAL; @@ -64,10 +153,10 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
if (!cinfo->name || !cinfo->card || - !cinfo->codec || - !cinfo->platform || - !cinfo->cpu_dai.name || - !cinfo->codec_dai.name) { + !cinfo->codec_dai.name || + !(cinfo->codec || of_codec) || + !(cinfo->platform || of_platform) || + !(cinfo->cpu_dai.name || of_cpu)) { dev_err(dev, "insufficient asoc_simple_card_info settings\n"); return -EINVAL; } @@ -81,6 +170,9 @@ static int asoc_simple_card_probe(struct platform_device *pdev) cinfo->snd_link.platform_name = cinfo->platform; cinfo->snd_link.codec_name = cinfo->codec; cinfo->snd_link.codec_dai_name = cinfo->codec_dai.name; + cinfo->snd_link.cpu_of_node = of_cpu; + cinfo->snd_link.codec_of_node = of_codec; + cinfo->snd_link.platform_of_node = of_platform; cinfo->snd_link.init = asoc_simple_card_dai_init;
/* @@ -102,9 +194,15 @@ static int asoc_simple_card_remove(struct platform_device *pdev) return snd_soc_unregister_card(&cinfo->snd_card); }
+static const struct of_device_id asoc_simple_of_match[] = { + { .compatible = "simple-audio", }, + {}, +}; + static struct platform_driver asoc_simple_card = { .driver = { .name = "asoc-simple-card", + .of_match_table = asoc_simple_of_match, }, .probe = asoc_simple_card_probe, .remove = asoc_simple_card_remove,
On Mon, Jan 14, 2013 at 06:40:37PM -0800, Kuninori Morimoto wrote:
Sorry about the delay in getting back to you on this.
+- simple-audio,cpu,dai,clock-gating : if needed, see below
A lot of these are listed as "if needed" - this means they should be listed separately as optional properties rather than in the required properties section.
+- simple-audio,codec,controller : phandle for CODEC DAI
It feels like this should just be simple-audio,codec - the controller is just redudnant. Though for idiomatic DT we ought to write something like
simple-audio,codec { simple-audio,dev = &phandle; simple-audio,system-clock-frequency = 122880000; };
rather than have these very long prefixes to the individual property names.
+- simple-audio,codec,dai,name : simple-audio CODEC DAI name +- simple-audio,codec,dai,format : see below +- simple-audio,codec,dai,clock-gating : if needed, see below +- simple-audio,codec,dai,bitclock-inversion : if needed +- simple-audio,codec,dai,bitclock-master : if needed +- simple-audio,codec,dai,frame-inversion : if needed +- simple-audio,codec,dai,frame-master : if needed +- simple-audio,codec,dai,system-clock-frequency : system clock rate if needed
I'm also thinking that for some of the above properties which really should be the same for both ends of the link we should just specify them at the card levle and copy them over. The format and inversion mainly.
+simple-audio,xxx,dai,format
- "i2s"
- "right_j"
- "left_j"
- "dsp_a"
- "dsp_b"
- "ac97"
- "pdm"
- "msb"
- "lsb"
+simple-audio,xxx,dai,clock-gating
- "continuous"
- "gated"
+Example:
+fsi_ak4642 {
- compatible = "simple-audio";
- simple-audio,card-name = "FSI2A-AK4648";
- simple-audio,platform,controller = <&sh_fsi2>;
- simple-audio,cpu,dai,name = "fsia-dai";
- simple-audio,cpu,dai,format = "left_j";
- simple-audio,codec,controller = <&ak4648>;
- simple-audio,codec,dai,name = "ak4642-hifi";
- simple-audio,codec,dai,format = "left_j";
- simple-audio,codec,dai,bitclock-master;
- simple-audio,codec,dai,frame-master;
- simple-audio,codec,dai,system-clock-frequency = <11289600>;
+};
+&i2c0 {
- ak4648: ak4648@0x12 {
compatible = "asahi-kasei,ak4648";
reg = <0x12>;
- };
+};
+sh_fsi2: sh_fsi2@0xec230000 {
- compatible = "renesas,sh_fsi2";
- reg = <0xec230000 0x400>;
- interrupt-parent = <&gic>;
- interrupts = <0 146 0x4>;
+}; diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 6cf8355..72dd8ae 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -9,6 +9,7 @@
- published by the Free Software Foundation.
*/
+#include <linux/of.h> #include <linux/platform_device.h> #include <linux/module.h> #include <sound/simple_card.h> @@ -52,11 +53,99 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) return 0; }
+static struct device_node* +__asoc_simple_card_parse_of(struct device_node *np,
const char *node_name1,
const char *node_name2,
const char **interface,
struct asoc_simple_dai *dai)
+{
- struct device_node *node;
- char prop[128];
- /* node or name is required */
- snprintf(prop, sizeof(prop),
"simple-audio,%s,controller", node_name1);
- node = of_parse_phandle(np, prop, 0);
- if (node)
of_node_put(node);
- /* get "simple-audio,xxx,yyy,name = xxx" */
- snprintf(prop, sizeof(prop),
"simple-audio,%s%s,name", node_name1, node_name2);
- of_property_read_string(np, prop, interface);
- if (dai) {
/* get "simple-audio,xxx,yyy,formart = xxx" */
snprintf(prop, sizeof(prop),
"simple-audio,%s%s,", node_name1, node_name2);
dai->fmt = snd_soc_of_parse_daifmt(np, prop);
/* get "simple-audio,xxx,yyy,system-clock-frequency = <xxx>" */
snprintf(prop, sizeof(prop),
"simple-audio,%s%s,system-clock-frequency",
node_name1, node_name2);
of_property_read_u32(np, prop, &dai->sysclk);
- }
- return node;
+}
+static void asoc_simple_card_parse_of(struct device_node *np,
struct asoc_simple_card_info *info,
struct device *dev,
struct device_node **of_cpu,
struct device_node **of_codec,
struct device_node **of_platform)
+{
- of_property_read_string(np, "simple-audio,card-name", &info->card);
- info->name = info->card;
- *of_cpu = __asoc_simple_card_parse_of(
np, "cpu", ",dai", &info->cpu_dai.name, &info->cpu_dai);
- *of_codec = __asoc_simple_card_parse_of(
np, "codec", ",dai", &info->codec_dai.name, &info->codec_dai);
- *of_platform = __asoc_simple_card_parse_of(
np, "platform", "", &info->platform, NULL);
- dev_dbg(dev, "card-name : %s\n", info->card);
- dev_dbg(dev, "cpu info : %s / %x / %d / %p\n",
info->cpu_dai.name,
info->cpu_dai.fmt,
info->cpu_dai.sysclk,
*of_cpu);
- dev_dbg(dev, "codec_info : %s / %x / %d / %p\n",
info->codec_dai.name,
info->codec_dai.fmt,
info->codec_dai.sysclk,
*of_codec);
- dev_dbg(dev, "platform_info : %s / %p\n",
info->platform,
*of_platform);
+}
static int asoc_simple_card_probe(struct platform_device *pdev) {
- struct asoc_simple_card_info *cinfo = pdev->dev.platform_data;
struct asoc_simple_card_info *cinfo;
struct device_node *np = pdev->dev.of_node;
struct device_node *of_cpu, *of_codec, *of_platform; struct device *dev = &pdev->dev;
cinfo = NULL;
of_cpu = NULL;
of_codec = NULL;
of_platform = NULL;
if (np && of_device_is_available(np)) {
cinfo = devm_kzalloc(dev, sizeof(*cinfo), GFP_KERNEL);
if (cinfo)
asoc_simple_card_parse_of(np, cinfo, dev,
&of_cpu,
&of_codec,
&of_platform);
} else {
cinfo = pdev->dev.platform_data;
}
if (!cinfo) { dev_err(dev, "no info for asoc-simple-card\n"); return -EINVAL;
@@ -64,10 +153,10 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
if (!cinfo->name || !cinfo->card ||
!cinfo->codec ||
!cinfo->platform ||
!cinfo->cpu_dai.name ||
!cinfo->codec_dai.name) {
!cinfo->codec_dai.name ||
!(cinfo->codec || of_codec) ||
!(cinfo->platform || of_platform) ||
dev_err(dev, "insufficient asoc_simple_card_info settings\n"); return -EINVAL; }!(cinfo->cpu_dai.name || of_cpu)) {
@@ -81,6 +170,9 @@ static int asoc_simple_card_probe(struct platform_device *pdev) cinfo->snd_link.platform_name = cinfo->platform; cinfo->snd_link.codec_name = cinfo->codec; cinfo->snd_link.codec_dai_name = cinfo->codec_dai.name;
cinfo->snd_link.cpu_of_node = of_cpu;
cinfo->snd_link.codec_of_node = of_codec;
cinfo->snd_link.platform_of_node = of_platform; cinfo->snd_link.init = asoc_simple_card_dai_init;
/*
@@ -102,9 +194,15 @@ static int asoc_simple_card_remove(struct platform_device *pdev) return snd_soc_unregister_card(&cinfo->snd_card); }
+static const struct of_device_id asoc_simple_of_match[] = {
- { .compatible = "simple-audio", },
- {},
+};
static struct platform_driver asoc_simple_card = { .driver = { .name = "asoc-simple-card",
}, .probe = asoc_simple_card_probe, .remove = asoc_simple_card_remove,.of_match_table = asoc_simple_of_match,
-- 1.7.9.5
Hi Mark
Thank you for checking patch
+- simple-audio,cpu,dai,clock-gating : if needed, see below
A lot of these are listed as "if needed" - this means they should be listed separately as optional properties rather than in the required properties section.
Sorry, Does this means under Documentation ? Or driver ?
+- simple-audio,codec,controller : phandle for CODEC DAI
It feels like this should just be simple-audio,codec - the controller is just redudnant. Though for idiomatic DT we ought to write something like
simple-audio,codec { simple-audio,dev = &phandle; simple-audio,system-clock-frequency = 122880000; };
rather than have these very long prefixes to the individual property names.
I see. will do in v3
+- simple-audio,codec,dai,name : simple-audio CODEC DAI name +- simple-audio,codec,dai,format : see below +- simple-audio,codec,dai,clock-gating : if needed, see below +- simple-audio,codec,dai,bitclock-inversion : if needed +- simple-audio,codec,dai,bitclock-master : if needed +- simple-audio,codec,dai,frame-inversion : if needed +- simple-audio,codec,dai,frame-master : if needed +- simple-audio,codec,dai,system-clock-frequency : system clock rate if needed
I'm also thinking that for some of the above properties which really should be the same for both ends of the link we should just specify them at the card levle and copy them over. The format and inversion mainly.
I guess it can share format between codec/dai, but it is difficult for inversion. Because it is depends on its default clock polarity. of course we can do simple-audio,platform,dai-bitlock-inversion simple-audio,platform,codec-bitlock-inversion but it is same thing.
Best regards --- Kuninori Morimoto
On Mon, Jan 28, 2013 at 05:31:33PM -0800, Kuninori Morimoto wrote:
+- simple-audio,cpu,dai,clock-gating : if needed, see below
A lot of these are listed as "if needed" - this means they should be listed separately as optional properties rather than in the required properties section.
Sorry, Does this means under Documentation ? Or driver ?
In the binding document.
I'm also thinking that for some of the above properties which really should be the same for both ends of the link we should just specify them at the card levle and copy them over. The format and inversion mainly.
I guess it can share format between codec/dai, but it is difficult for inversion. Because it is depends on its default clock polarity. of course we can do simple-audio,platform,dai-bitlock-inversion simple-audio,platform,codec-bitlock-inversion but it is same thing.
Inverted and non-inverted always mean the same thing in terms of ASoC and should always mean the same thing in terms of the device tree, if two devices are directly connected you should always be able to use the same ASoC format for them.
Hi Mark
Sorry, Does this means under Documentation ? Or driver ?
In the binding document.
I see.
I guess it can share format between codec/dai, but it is difficult for inversion. Because it is depends on its default clock polarity. of course we can do simple-audio,platform,dai-bitlock-inversion simple-audio,platform,codec-bitlock-inversion but it is same thing.
Inverted and non-inverted always mean the same thing in terms of ASoC and should always mean the same thing in terms of the device tree, if two devices are directly connected you should always be able to use the same ASoC format for them.
Ahh indeed. sorry for my confusion. I will fix it on v3
Best regards --- Kuninori Morimoto
Hi Mark, Stephen
simple-audio,codec { simple-audio,dev = &phandle; simple-audio,system-clock-frequency = 122880000; };
I would like to ask you before creating v3 patch. I got some opinions from you. - cpu/codec style (above) - "controller" naming - it is using "name" property (it is must item for matching)
Then, what do you think about this style ?
fai_ak4642 { compatible = "simple-audio";
simple-audio,card-name = "FSI2A-AK4648";
/* platform */ simple-audio,platform { compatible = "ak4642-hifi"; /* platform name (if needed) */ simple-audio,dev = <&sh_fsi2>;
/* format and inversion are here */ simple-audio,format = "left_j"; simple-audio,bitclock-inversion; }
/* codec and cpu are same style */
/* codec */ simple-audio,codec { compatible = "ak4642-hifi"; /* codec dai name (this is must item on ASoC) */ simple-audio,dev = <&ak4648>; simple-audio,bitclock-master;
/* clock gating is here */ simple-audio,clock-gating = "continuous"; }
/* cpu */ simple-audio,cpu { compatible = "fsia-dai"; /* cpu dai name (if needed) */ simple-audio,dev = <&sh_fsi2>; simple-audio,system-clock-frequency = <11289600>; } }
Best regards --- Kuninori Morimoto
On 01/29/2013 03:00 AM, Kuninori Morimoto wrote:
Hi Mark, Stephen
simple-audio,codec { simple-audio,dev = &phandle; simple-audio,system-clock-frequency = 122880000; };
I would like to ask you before creating v3 patch. I got some opinions from you.
- cpu/codec style (above)
- "controller" naming
- it is using "name" property (it is must item for matching)
Then, what do you think about this style ?
fai_ak4642 {
The node would usually be named after the type of object, not the identity of the object, so more like "sound".
compatible = "simple-audio"; simple-audio,card-name = "FSI2A-AK4648";
OK.
/* platform */ simple-audio,platform {
I still don't understand why you need to even represent the platform in DT.
Introducing sub-nodes seems to just add to the complexity without much gain.
compatible = "ak4642-hifi"; /* platform name (if needed) */
The "compatible" property has a very specific meaning in DT already. I don't think we should re-use that property name for other purposes.
simple-audio,dev = <&sh_fsi2>;
/* format and inversion are here */ simple-audio,format = "left_j"; simple-audio,bitclock-inversion;
Those properties appear more relevant to the I2S link than the ASoC platform object.
} /* codec and cpu are same style */ /* codec */ simple-audio,codec { compatible = "ak4642-hifi"; /* codec dai name (this is must item on ASoC) */
If you absolutely must use named-based binding here rather than the standard phandle+args style, rename that property to something more like simple-audio,dai-name.
simple-audio,dev = <&ak4648>; simple-audio,bitclock-master; /* clock gating is here */ simple-audio,clock-gating = "continuous";
I think this should be a Boolean property; present means yes, missing means no.
} /* cpu */ simple-audio,cpu { compatible = "fsia-dai"; /* cpu dai name (if needed) */ simple-audio,dev = <&sh_fsi2>; simple-audio,system-clock-frequency = <11289600>; }
}
Hi Mark
Kuninori Morimoto (2): ASoC: SND_SOC_DAIFMT_GATED become 0 as default settings ASoC: clock gating is decided by bool on snd_soc_of_parse_daifmt()
include/sound/soc-dai.h | 2 +- sound/soc/soc-core.c | 20 ++++++-------------- 2 files changed, 7 insertions(+), 15 deletions(-)
This patch fixup SND_SOC_DAIFMT_GATED value, and its operation in snd_soc_of_parse_daifmt()
Best regards --- Kuninori Morimoto
Current soc-dai.h defines SND_SOC_DAIFMT_GATED as (2 << 4), but gated clock should be default settings (= 0). This patch fixup SND_SOC_DAIFMT_GATED as (0 << 4).
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- include/sound/soc-dai.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 3953cea..4dbd3e7 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -45,7 +45,7 @@ struct snd_compr_stream; * sending or receiving PCM data in a frame. This can be used to save power. */ #define SND_SOC_DAIFMT_CONT (1 << 4) /* continuous clock */ -#define SND_SOC_DAIFMT_GATED (2 << 4) /* clock is gated */ +#define SND_SOC_DAIFMT_GATED (0 << 4) /* clock is gated */
/* * DAI hardware signal inversions.
ASoC clock gate settings are continuous/gated only. This patch decides it as bool, then, gated clock will be default. Special thanks to Stephen
Cc: Stephen Warren swarren@wwwdotorg.org Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- sound/soc/soc-core.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-)
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index cca411b..689eb04 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -4200,9 +4200,6 @@ unsigned int snd_soc_of_parse_daifmt(struct device_node *np, { "pdm", SND_SOC_DAIFMT_PDM}, { "msb", SND_SOC_DAIFMT_MSB }, { "lsb", SND_SOC_DAIFMT_LSB }, - }, of_clock_table[] = { - { "continuous", SND_SOC_DAIFMT_CONT }, - { "gated", SND_SOC_DAIFMT_GATED }, };
if (!prefix) @@ -4224,19 +4221,14 @@ unsigned int snd_soc_of_parse_daifmt(struct device_node *np, }
/* - * check "[prefix]clock-gating = xxx" + * check "[prefix]continuous-clock" * SND_SOC_DAIFMT_CLOCK_MASK area */ - snprintf(prop, sizeof(prop), "%sclock-gating", prefix); - ret = of_property_read_string(np, prop, &str); - if (ret == 0) { - for (i = 0; i < ARRAY_SIZE(of_clock_table); i++) { - if (strcmp(str, of_clock_table[i].name) == 0) { - format |= of_clock_table[i].val; - break; - } - } - } + snprintf(prop, sizeof(prop), "%scontinuous-clock", prefix); + if (of_get_property(np, prop, NULL)) + format |= SND_SOC_DAIFMT_CONT; + else + format |= SND_SOC_DAIFMT_GATED;
/* * check "[prefix]bitclock-inversion"
On 01/29/2013 10:03 PM, Kuninori Morimoto wrote:
ASoC clock gate settings are continuous/gated only. This patch decides it as bool, then, gated clock will be default. Special thanks to Stephen
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
- snprintf(prop, sizeof(prop), "%scontinuous-clock", prefix);
- if (of_get_property(np, prop, NULL))
That should really use of_property_read_bool(), although it makes little practical difference.
On Tue, Jan 29, 2013 at 09:02:32PM -0800, Kuninori Morimoto wrote:
Kuninori Morimoto (2): ASoC: SND_SOC_DAIFMT_GATED become 0 as default settings ASoC: clock gating is decided by bool on snd_soc_of_parse_daifmt()
Applied both, thanks.
Support for loading the simple-card module via devicetree. It requests cpu/codec information for probing.
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- v2 -> v3
- modify simple-card.txt - remove "platform" from DT - DT used sub-node
.../devicetree/bindings/sound/simple-card.txt | 71 +++++++++++++ sound/soc/generic/simple-card.c | 105 +++++++++++++++++++- 2 files changed, 171 insertions(+), 5 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/simple-card.txt
diff --git a/Documentation/devicetree/bindings/sound/simple-card.txt b/Documentation/devicetree/bindings/sound/simple-card.txt new file mode 100644 index 0000000..0d8627d --- /dev/null +++ b/Documentation/devicetree/bindings/sound/simple-card.txt @@ -0,0 +1,71 @@ +Simple-Card: + +Required properties: + +- compatible : "simple-audio" +- simple-audio,card-name : simple-audio card name +- simple-audio,format : see below + +Optional properties: + +- simple-audio,bitclock-inversion +- simple-audio,frame-inversion + +CPU / CODEC DAI is represented as a sub-node. +Then, sub-node name should be "simple-audio,cpu" or "simple-audio,codec". + +Required subnode properties: +- simple-audio,dev : phandle for CPU/CODEC + +Optional subnode properties: + +- simple-audio,dai-name : simple-audio CPU/CODEC DAI name +- simple-audio,system-clock-frequency : system clock rate +- simple-audio,frame-master +- simple-audio,bitclock-master + +simple-audio,format + "i2s" + "right_j" + "left_j" + "dsp_a" + "dsp_b" + "ac97" + "pdm" + "msb" + "lsb" + +Example: + +sound { + compatible = "simple-audio"; + + simple-audio,card-name = "FSI2A-AK4648"; + simple-audio,format = "left_j"; + + simple-audio,cpu { + simple-audio,dev = <&sh_fsi2>; + }; + + simple-audio,codec { + simple-audio,dev = <&ak4648>; + simple-audio,dai-name = "ak4642-hifi"; + simple-audio,bitclock-master; + simple-audio,frame-master; + simple-audio,system-clock-frequency = <11289600>; + }; +}; + +&i2c0 { + ak4648: ak4648@0x12 { + compatible = "asahi-kasei,ak4648"; + reg = <0x12>; + }; +}; + +sh_fsi2: sh_fsi2@0xec230000 { + compatible = "renesas,sh_fsi2"; + reg = <0xec230000 0x400>; + interrupt-parent = <&gic>; + interrupts = <0 146 0x4>; +}; diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 6cf8355..21ad779 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -9,6 +9,7 @@ * published by the Free Software Foundation. */
+#include <linux/of.h> #include <linux/platform_device.h> #include <linux/module.h> #include <sound/simple_card.h> @@ -52,11 +53,95 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) return 0; }
+static struct device_node* +__asoc_simple_card_parse_of(struct device_node *np, + struct asoc_simple_dai *dai) +{ + struct device_node *node; + + /* get "simple-audio,dev = <xxx>" */ + node = of_parse_phandle(np, "simple-audio,dev", 0); + if (node) + of_node_put(node); + + /* get "simple-audio,dai-name = xxx" */ + of_property_read_string(np, "simple-audio,dai-name", &dai->name); + + /* get dai specific format */ + dai->fmt = snd_soc_of_parse_daifmt(np, "simple-audio,"); + + /* get "simple-audio,system-clock-frequency = <xxx>" */ + of_property_read_u32(np, "simple-audio,system-clock-frequency", + &dai->sysclk); + + return node; +} + +static void asoc_simple_card_parse_of(struct device_node *node, + struct asoc_simple_card_info *info, + struct device *dev, + struct device_node **of_cpu, + struct device_node **of_codec, + struct device_node **of_platform) +{ + struct device_node *np; + + of_property_read_string(node, "simple-audio,card-name", &info->card); + info->name = info->card; + + info->daifmt = snd_soc_of_parse_daifmt(node, "simple-audio,") & + (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_INV_MASK); + + for_each_child_of_node(node, np) { + if (0 == strcmp("simple-audio,cpu", np->name)) + *of_cpu = __asoc_simple_card_parse_of( + np, &info->cpu_dai); + if (0 == strcmp("simple-audio,codec", np->name)) + *of_codec = __asoc_simple_card_parse_of( + np, &info->codec_dai); + } + + /* simple-card assumes platform == cpu */ + *of_platform = *of_cpu; + + dev_dbg(dev, "card-name : %s\n", info->card); + dev_dbg(dev, "platform : %04x / %p\n", + info->daifmt, + *of_platform); + dev_dbg(dev, "cpu : %s / %04x / %d / %p\n", + info->cpu_dai.name, + info->cpu_dai.fmt, + info->cpu_dai.sysclk, + *of_cpu); + dev_dbg(dev, "codec : %s / %04x / %d / %p\n", + info->codec_dai.name, + info->codec_dai.fmt, + info->codec_dai.sysclk, + *of_codec); +} + static int asoc_simple_card_probe(struct platform_device *pdev) { - struct asoc_simple_card_info *cinfo = pdev->dev.platform_data; + struct asoc_simple_card_info *cinfo; + struct device_node *np = pdev->dev.of_node; + struct device_node *of_cpu, *of_codec, *of_platform; struct device *dev = &pdev->dev;
+ cinfo = NULL; + of_cpu = NULL; + of_codec = NULL; + of_platform = NULL; + if (np && of_device_is_available(np)) { + cinfo = devm_kzalloc(dev, sizeof(*cinfo), GFP_KERNEL); + if (cinfo) + asoc_simple_card_parse_of(np, cinfo, dev, + &of_cpu, + &of_codec, + &of_platform); + } else { + cinfo = pdev->dev.platform_data; + } + if (!cinfo) { dev_err(dev, "no info for asoc-simple-card\n"); return -EINVAL; @@ -64,10 +149,10 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
if (!cinfo->name || !cinfo->card || - !cinfo->codec || - !cinfo->platform || - !cinfo->cpu_dai.name || - !cinfo->codec_dai.name) { + !cinfo->codec_dai.name || + !(cinfo->codec || of_codec) || + !(cinfo->platform || of_platform) || + !(cinfo->cpu_dai.name || of_cpu)) { dev_err(dev, "insufficient asoc_simple_card_info settings\n"); return -EINVAL; } @@ -81,6 +166,9 @@ static int asoc_simple_card_probe(struct platform_device *pdev) cinfo->snd_link.platform_name = cinfo->platform; cinfo->snd_link.codec_name = cinfo->codec; cinfo->snd_link.codec_dai_name = cinfo->codec_dai.name; + cinfo->snd_link.cpu_of_node = of_cpu; + cinfo->snd_link.codec_of_node = of_codec; + cinfo->snd_link.platform_of_node = of_platform; cinfo->snd_link.init = asoc_simple_card_dai_init;
/* @@ -102,9 +190,16 @@ static int asoc_simple_card_remove(struct platform_device *pdev) return snd_soc_unregister_card(&cinfo->snd_card); }
+static const struct of_device_id asoc_simple_of_match[] = { + { .compatible = "simple-audio", }, + {}, +}; +MODULE_DEVICE_TABLE(of, asoc_simple_of_match); + static struct platform_driver asoc_simple_card = { .driver = { .name = "asoc-simple-card", + .of_match_table = asoc_simple_of_match, }, .probe = asoc_simple_card_probe, .remove = asoc_simple_card_remove,
On 01/30/2013 02:09 AM, Kuninori Morimoto wrote:
Support for loading the simple-card module via devicetree. It requests cpu/codec information for probing.
diff --git a/Documentation/devicetree/bindings/sound/simple-card.txt b/Documentation/devicetree/bindings/sound/simple-card.txt
+Simple-Card:
+Required properties:
+- compatible : "simple-audio" +- simple-audio,card-name : simple-audio card name +- simple-audio,format : see below
+Optional properties:
+- simple-audio,bitclock-inversion +- simple-audio,frame-inversion
+CPU / CODEC DAI is represented as a sub-node. +Then, sub-node name should be "simple-audio,cpu" or "simple-audio,codec".
Why require sub-nodes? it seem over-complex.
+Required subnode properties: +- simple-audio,dev : phandle for CPU/CODEC
+Optional subnode properties:
+- simple-audio,dai-name : simple-audio CPU/CODEC DAI name
OK, I see those two are CPU-/CODEC-specific. However, you could easily just have different property names for the two.
I assume you didn't like my idea of not putting the DAI names into the DT, but using extra arguments after the phandles instead? Doing so would be more alike most existing DT bindings.
+- simple-audio,system-clock-frequency : system clock rate +- simple-audio,frame-master +- simple-audio,bitclock-master
Aren't those a property of the CPU<->CODEC link, hence the clock frequency is identical, and the two "master" properties are the inverse of each-other in between CPU and CODEC. Specifying these right in the top-level node seems simpler.
Hi Stephen
Thank you for checking patch
+Required properties:
+- compatible : "simple-audio" +- simple-audio,card-name : simple-audio card name +- simple-audio,format : see below
+Optional properties:
+- simple-audio,bitclock-inversion +- simple-audio,frame-inversion
+CPU / CODEC DAI is represented as a sub-node. +Then, sub-node name should be "simple-audio,cpu" or "simple-audio,codec".
Why require sub-nodes? it seem over-complex.
It was Mark's idea.
+- simple-audio,system-clock-frequency : system clock rate +- simple-audio,frame-master +- simple-audio,bitclock-master
Aren't those a property of the CPU<->CODEC link, hence the clock frequency is identical,
This clock connection/frequency depends on SoC/board. There is a case where system clock is not connected to both cpu/codec.
system clock bit/frame --------[codec]---------> [cpu]
and the two "master" properties are the inverse of each-other in between CPU and CODEC. Specifying these right in the top-level node seems simpler.
If I put these in top-level node, it needs
simple-audio,xxx,frame-master; simple-audio,xxx,bitclock-master; xxx = cpu / codec
This is same things ?
Of course I can do like
simple-audio,frame-master = "cpu"; simple-audio,bitclock-master = "cpu";
But, this style can't use snd_soc_of_parse_daifmt()
+Required subnode properties: +- simple-audio,dev : phandle for CPU/CODEC
+Optional subnode properties:
+- simple-audio,dai-name : simple-audio CPU/CODEC DAI name
OK, I see those two are CPU-/CODEC-specific. However, you could easily just have different property names for the two.
I assume you didn't like my idea of not putting the DAI names into the DT, but using extra arguments after the phandles instead? Doing so would be more alike most existing DT bindings.
I'm confusing about this. What does this "different property name" mean ?
If you agree with "sub-node", then I can use below style. it can remove "dai-name" ?
ak4642-hifi { simple-audio,type = "codec"; simple-audio,dev = <&xxx>; ... }
fsia-dai { simple-audio,type = "cpu"; simple-audio,dev = <&xxx>; ... }
Best regards --- Kuninori Morimoto
On 01/30/2013 05:49 PM, Kuninori Morimoto wrote:
+- simple-audio,system-clock-frequency : system clock rate +- simple-audio,frame-master +- simple-audio,bitclock-master
Aren't those a property of the CPU<->CODEC link, hence the clock frequency is identical,
This clock connection/frequency depends on SoC/board. There is a case where system clock is not connected to both cpu/codec.
system clock bit/frame --------[codec]---------> [cpu]
In that diagram, it looks like the CPU-side simply doesn't receive a system clock at all, so it's recovering any clock by multiplying up the bit clock.
That seems like a different case to the two ends both receiving a system clock but the frequency being different.
How does the CPU DAI driver know (based on the binding) whether it receives a system clock or not, or whether it should extract a clock from the bit clock? Perhaps the HW design of the CPU DAI determines this, so the binding doesn't need to specify it?
and the two "master" properties are the inverse of each-other in between CPU and CODEC. Specifying these right in the top-level node seems simpler.
If I put these in top-level node, it needs
simple-audio,xxx,frame-master; simple-audio,xxx,bitclock-master; xxx = cpu / codec
This is same things ?
Of course I can do like
simple-audio,frame-master = "cpu"; simple-audio,bitclock-master = "cpu";
But, this style can't use snd_soc_of_parse_daifmt()
I think the usual style for this would be a Boolean property indicating whether the CPU DAI is the master or slave, and same for bitclock. That'd be something like:
simple-audio,cpu-frame-master; simple-audio,cpu-bitclock-master;
and those two properties would be present (for true) or missing (for false).
+Required subnode properties: +- simple-audio,dev : phandle for CPU/CODEC
+Optional subnode properties:
+- simple-audio,dai-name : simple-audio CPU/CODEC DAI name
OK, I see those two are CPU-/CODEC-specific. However, you could easily just have different property names for the two.
I assume you didn't like my idea of not putting the DAI names into the DT, but using extra arguments after the phandles instead? Doing so would be more alike most existing DT bindings.
I'm confusing about this. What does this "different property name" mean ?
Instead of:
nodea { simple-audio,dev = ...; } nodeb { simple-audio,dev = ...; }
You'd have:
simple-audio,cpu-dai = ...; simple-audio,codec = ...;
On Thu, Jan 31, 2013 at 10:15:55AM -0700, Stephen Warren wrote:
In that diagram, it looks like the CPU-side simply doesn't receive a system clock at all, so it's recovering any clock by multiplying up the bit clock.
Practically speaking this is the case for most simple CPU DAIs, unless you're doing DSP or generating the clocks you just need a clock that is strictly faster than the data rate, synchronisation is irrelevant.
On Wed, Jan 30, 2013 at 01:14:07PM -0700, Stephen Warren wrote:
+CPU / CODEC DAI is represented as a sub-node. +Then, sub-node name should be "simple-audio,cpu" or "simple-audio,codec".
Why require sub-nodes? it seem over-complex.
I suggested this because it seemed more legible to repeat the properties by having a named structure for each property rather than by repeating them all with slightly different names.
On 01/30/2013 06:35 PM, Mark Brown wrote:
On Wed, Jan 30, 2013 at 01:14:07PM -0700, Stephen Warren wrote:
+CPU / CODEC DAI is represented as a sub-node. +Then, sub-node name should be "simple-audio,cpu" or "simple-audio,codec".
Why require sub-nodes? it seem over-complex.
I suggested this because it seemed more legible to repeat the properties by having a named structure for each property rather than by repeating them all with slightly different names.
So the only need to repeat them at all was if the two DAIs needed different values for some of the properties rather than being identical (e.g. signal polarity) or precise inversions (e.g. which end is master), right?
Is that actually likely - I can understand that for e.g. plain old GPIOs board designers might end up sticking random inverters between two devices for various reasons, but surely this wouldn't happen for an I2S interface where the polarities etc. mean something relative to the other signals? I would almost argue that since the simple case is for the signals to be connected 1:1 between the two DAIs, that if a particular board doesn't conform to that, it isn't a simple-audio case. That all said, we could extend simple-audio to handle it still without duplicating everything by specifying the DAI format for the CPU DAI once in the simple-audio node, "inverting" that when configuring the CODEC DAI, and then adding extra boolean properties to the DT later in a backwards-compatible fashion, for any strange cases the driver can end up handling.
On Thu, Jan 31, 2013 at 10:09:37AM -0700, Stephen Warren wrote:
On 01/30/2013 06:35 PM, Mark Brown wrote:
I suggested this because it seemed more legible to repeat the properties by having a named structure for each property rather than by repeating them all with slightly different names.
So the only need to repeat them at all was if the two DAIs needed different values for some of the properties rather than being identical (e.g. signal polarity) or precise inversions (e.g. which end is master), right?
There's more attributes that we might want to configure on the devices than just the actual DAI link. Clocks for example.
On 01/31/2013 10:11 AM, Mark Brown wrote:
On Thu, Jan 31, 2013 at 10:09:37AM -0700, Stephen Warren wrote:
On 01/30/2013 06:35 PM, Mark Brown wrote:
I suggested this because it seemed more legible to repeat the properties by having a named structure for each property rather than by repeating them all with slightly different names.
So the only need to repeat them at all was if the two DAIs needed different values for some of the properties rather than being identical (e.g. signal polarity) or precise inversions (e.g. which end is master), right?
There's more attributes that we might want to configure on the devices than just the actual DAI link. Clocks for example.
Sure, but this binding is *simple*-audio, right. If the intent is to create some more general/all-encompassing binding structure, I'd want to think about it and review it in a different way.
On Thu, Jan 31, 2013 at 10:17:20AM -0700, Stephen Warren wrote:
On 01/31/2013 10:11 AM, Mark Brown wrote:
There's more attributes that we might want to configure on the devices than just the actual DAI link. Clocks for example.
Sure, but this binding is *simple*-audio, right. If the intent is to create some more general/all-encompassing binding structure, I'd want to think about it and review it in a different way.
Right, but things like the clocks are basic enough.
Hi Mark, Stephen
There's more attributes that we might want to configure on the devices than just the actual DAI link. Clocks for example.
Sure, but this binding is *simple*-audio, right. If the intent is to create some more general/all-encompassing binding structure, I'd want to think about it and review it in a different way.
Right, but things like the clocks are basic enough.
I agree that "simple"-audio has "simple" settings.
But, there is a board which gets some data delay via external factor. Then, it needs special inversion, especially bit clock. Without this settings, that board can't get correct data. This is maybe special case, so, I need cpu/codec special settings as "option".
If you can agree this, "simple-audio,xxx = " will be common (for cpu/codec) settings, and "simple-audio,cpu,xxx" or "simple-audio,codec,xxx" can be used as "option" settings.
Best regards --- Kuninori Morimoto
On 01/31/2013 06:54 PM, Kuninori Morimoto wrote:
Hi Mark, Stephen
There's more attributes that we might want to configure on the devices than just the actual DAI link. Clocks for example.
Sure, but this binding is *simple*-audio, right. If the intent is to create some more general/all-encompassing binding structure, I'd want to think about it and review it in a different way.
Right, but things like the clocks are basic enough.
I agree that "simple"-audio has "simple" settings.
But, there is a board which gets some data delay via external factor. Then, it needs special inversion, especially bit clock. Without this settings, that board can't get correct data. This is maybe special case, so, I need cpu/codec special settings as "option".
It seems extremely odd to me that the data delay would just happen to end up meaning that inverting the clock works out to magically make everything work.
Still, if there really is a use-case for this in otherwise simple audio systems, then I guess specifying all the DAI properties in sub-nodes is indeed to simplest/most-flexible way to go.
On Mon, Feb 04, 2013 at 03:23:49PM -0700, Stephen Warren wrote:
It seems extremely odd to me that the data delay would just happen to end up meaning that inverting the clock works out to magically make everything work.
Still, if there really is a use-case for this in otherwise simple audio systems, then I guess specifying all the DAI properties in sub-nodes is indeed to simplest/most-flexible way to go.
I've heard of this before when things get routed through an inverter for buffering (or sometimes a FPGA for something more fancy).
Hi Stephen, Mark
+- simple-audio,dai-name : simple-audio CPU/CODEC DAI name
OK, I see those two are CPU-/CODEC-specific. However, you could easily just have different property names for the two.
I assume you didn't like my idea of not putting the DAI names into the DT, but using extra arguments after the phandles instead? Doing so would be more alike most existing DT bindings.
The reason why I need "dai-name" is that phandle can select "cpu/codec device" itself, but, it can't select "port". This port is called/controlled as "xxx_dai_name" on ASoC I think.
like this
+-------------+ | FSI port A |--> ak4642 | port B |--> HDMI +-------------+
Then, I would like to ask Stephen, Mark
Mark
Now, "codec_dai_name" is must item in ASoC, but "cpu_dai_name" is option. I guess codec can use same matching method like cpu. Can I modify codec side method ?
Stephen
Some board needs port selection. Can you agree that simple-audio has "port" (= dai-name) property as option ?
Best regards --- Kuninori Morimoto
Current ASoC always request codec_dai_name for matching, but it can be option. This patch set codec_dai_name as option.
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- sound/soc/soc-core.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-)
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 689eb04..ab3aafc 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -863,12 +863,13 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) * this CODEC */ list_for_each_entry(codec_dai, &dai_list, list) { - if (codec->dev == codec_dai->dev && - !strcmp(codec_dai->name, - dai_link->codec_dai_name)) { + if (codec->dev != codec_dai->dev) + continue; + if (dai_link->codec_dai_name && + strcmp(codec_dai->name, dai_link->codec_dai_name)) + continue;
- rtd->codec_dai = codec_dai; - } + rtd->codec_dai = codec_dai; }
if (!rtd->codec_dai) { @@ -3548,12 +3549,6 @@ int snd_soc_register_card(struct snd_soc_card *card) " name/of_node are set for %s\n", link->name); return -EINVAL; } - /* Codec DAI name must be specified */ - if (!link->codec_dai_name) { - dev_err(card->dev, "ASoC: codec_dai_name not" - " set for %s\n", link->name); - return -EINVAL; - }
/* * Platform may be specified by either name or OF node, but
On 01/31/2013 10:19 PM, Kuninori Morimoto wrote:
Current ASoC always request codec_dai_name for matching, but it can be option. This patch set codec_dai_name as option.
This seems reasonable to me. However, I don't think it helps solve the case you mentioned in your earlier email:
+-------------+ | FSI port A |--> ak4642 | port B |--> HDMI +-------------+
In that case there are two DAIs, and with this patch and no specified DAI name, you won't be able to control which of those two DAIs gets used by the DAI link.
So while I can see the utility of this patch in some cases, I think you really want to explicitly specify the DAI name (or DAI ID) in the device tree for the simple-audio use-case.
Hi Stephen
Current ASoC always request codec_dai_name for matching, but it can be option. This patch set codec_dai_name as option.
This seems reasonable to me. However, I don't think it helps solve the case you mentioned in your earlier email:
+-------------+ | FSI port A |--> ak4642 | port B |--> HDMI +-------------+
In that case there are two DAIs, and with this patch and no specified DAI name, you won't be able to control which of those two DAIs gets used by the DAI link.
In such case, first port (port A this case) is always selected.
So while I can see the utility of this patch in some cases, I think you really want to explicitly specify the DAI name (or DAI ID) in the device tree for the simple-audio use-case.
Some boards doesn't use port B. I guess port B selection can be "option" ?
Best regards --- Kuninori Morimoto
Support for loading the simple-card module via devicetree. It requests cpu/codec information for probing.
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- v3 -> v4
- dai-name -> port-name and option - removed sub-node
.../devicetree/bindings/sound/simple-card.txt | 62 +++++++++++ sound/soc/generic/simple-card.c | 110 +++++++++++++++++++- 2 files changed, 167 insertions(+), 5 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/simple-card.txt
diff --git a/Documentation/devicetree/bindings/sound/simple-card.txt b/Documentation/devicetree/bindings/sound/simple-card.txt new file mode 100644 index 0000000..7988c09 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/simple-card.txt @@ -0,0 +1,62 @@ +Simple-Card: + +Required properties: + + [prefix] means cpu/codec here + +- compatible : "simple-audio" +- simple-audio,card-name : simple-audio card name +- simple-audio,format : see below +- simple-audio,[prefix],dai : phandle for CPU/CODEC +- simple-audio,[prefix],frame-master : frame master +- simple-audio,[prefix],bitclock-master : bitclock master + +Optional properties: + +- simple-audio,system-clock-frequency : system clock rate if it is connected to both CPU/CODEC +- simple-audio,bitclock-inversion : bit clock inversion for both CPU/CODEC +- simple-audio,frame-inversion : frame inversion for both CPU/CODEC + +- simple-audio,[prefix],port-name : connected port name +- simple-audio,[prefix],bitclock-inversion : if CPU/CODEC needs clock inversion +- simple-audio,[prefix],frame-inversion : if CPU/CODEC needs frame inversion +- simple-audio,[prefix],system-clock-frequency : system clock rate for each CPU/CODEC + +simple-audio,format + "i2s" + "right_j" + "left_j" + "dsp_a" + "dsp_b" + "ac97" + "pdm" + "msb" + "lsb" + +Example: + +sound { + compatible = "simple-audio"; + + simple-audio,card-name = "FSI2A-AK4648"; + simple-audio,format = "left_j"; + simple-audio,cpu,dai = <&sh_fsi2>; + simple-audio,codec,dai = <&ak4648>; + simple-audio,codec,bitclock-master; + simple-audio,codec,frame-master; + simple-audio,codec,system-clock-frequency = <11289600>; +}; + +&i2c0 { + ak4648: ak4648@0x12 { + compatible = "asahi-kasei,ak4648"; + reg = <0x12>; + }; +}; + +sh_fsi2: sh_fsi2@0xec230000 { + compatible = "renesas,sh_fsi2"; + reg = <0xec230000 0x400>; + interrupt-parent = <&gic>; + interrupts = <0 146 0x4>; +}; diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 6cf8355..505c117 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -9,6 +9,7 @@ * published by the Free Software Foundation. */
+#include <linux/of.h> #include <linux/platform_device.h> #include <linux/module.h> #include <sound/simple_card.h> @@ -52,11 +53,101 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) return 0; }
+static struct device_node* +__asoc_simple_card_parse_of(struct device_node *np, + struct asoc_simple_dai *dai, + const char *prefix) +{ + struct device_node *node; + char prop[128]; + + /* get "[prefix],dai = <xxx>" */ + snprintf(prop, sizeof(prop), "%s,dai", prefix); + node = of_parse_phandle(np, prop, 0); + if (node) + of_node_put(node); + + /* get "[prefix],port-name = xxx" */ + snprintf(prop, sizeof(prop), "%s,port-name", prefix); + of_property_read_string(np, prop, &dai->name); + + /* get dai specific format */ + dai->fmt = snd_soc_of_parse_daifmt(np, prefix); + + /* get "[prefix],system-clock-frequency = <xxx>" */ + snprintf(prop, sizeof(prop), "%s,system-clock-frequency", prefix); + of_property_read_u32(np, prop, &dai->sysclk); + + return node; +} + +static void asoc_simple_card_parse_of(struct device_node *np, + struct asoc_simple_card_info *info, + struct device *dev, + struct device_node **of_cpu, + struct device_node **of_codec, + struct device_node **of_platform) +{ + u32 sysclk = 0; + + of_property_read_string(np, "simple-audio,card-name", &info->card); + info->name = info->card; + + info->daifmt = snd_soc_of_parse_daifmt(np, "simple-audio,") & + (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_INV_MASK); + + of_property_read_u32(np, + "simple-audio,system-clock-frequency", &sysclk); + + info->cpu_dai.sysclk = sysclk; + info->codec_dai.sysclk = sysclk; + + *of_cpu = __asoc_simple_card_parse_of(np, &info->cpu_dai, + "simple-audio,cpu"); + *of_codec = __asoc_simple_card_parse_of(np, &info->codec_dai, + "simple-audio,codec"); + + /* simple-card assumes platform == cpu */ + *of_platform = *of_cpu; + + dev_dbg(dev, "card-name : %s\n", info->card); + dev_dbg(dev, "platform : %04x / %p\n", + info->daifmt, + *of_platform); + dev_dbg(dev, "cpu : %s / %04x / %d / %p\n", + info->cpu_dai.name, + info->cpu_dai.fmt, + info->cpu_dai.sysclk, + *of_cpu); + dev_dbg(dev, "codec : %s / %04x / %d / %p\n", + info->codec_dai.name, + info->codec_dai.fmt, + info->codec_dai.sysclk, + *of_codec); +} + static int asoc_simple_card_probe(struct platform_device *pdev) { - struct asoc_simple_card_info *cinfo = pdev->dev.platform_data; + struct asoc_simple_card_info *cinfo; + struct device_node *np = pdev->dev.of_node; + struct device_node *of_cpu, *of_codec, *of_platform; struct device *dev = &pdev->dev;
+ cinfo = NULL; + of_cpu = NULL; + of_codec = NULL; + of_platform = NULL; + if (np && of_device_is_available(np)) { + cinfo = devm_kzalloc(dev, sizeof(*cinfo), GFP_KERNEL); + if (cinfo) + asoc_simple_card_parse_of(np, cinfo, dev, + &of_cpu, + &of_codec, + &of_platform); + } else { + cinfo = pdev->dev.platform_data; + } + if (!cinfo) { dev_err(dev, "no info for asoc-simple-card\n"); return -EINVAL; @@ -64,10 +155,9 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
if (!cinfo->name || !cinfo->card || - !cinfo->codec || - !cinfo->platform || - !cinfo->cpu_dai.name || - !cinfo->codec_dai.name) { + !(cinfo->codec || of_codec) || + !(cinfo->platform || of_platform) || + !(cinfo->cpu_dai.name || of_cpu)) { dev_err(dev, "insufficient asoc_simple_card_info settings\n"); return -EINVAL; } @@ -81,6 +171,9 @@ static int asoc_simple_card_probe(struct platform_device *pdev) cinfo->snd_link.platform_name = cinfo->platform; cinfo->snd_link.codec_name = cinfo->codec; cinfo->snd_link.codec_dai_name = cinfo->codec_dai.name; + cinfo->snd_link.cpu_of_node = of_cpu; + cinfo->snd_link.codec_of_node = of_codec; + cinfo->snd_link.platform_of_node = of_platform; cinfo->snd_link.init = asoc_simple_card_dai_init;
/* @@ -102,9 +195,16 @@ static int asoc_simple_card_remove(struct platform_device *pdev) return snd_soc_unregister_card(&cinfo->snd_card); }
+static const struct of_device_id asoc_simple_of_match[] = { + { .compatible = "simple-audio", }, + {}, +}; +MODULE_DEVICE_TABLE(of, asoc_simple_of_match); + static struct platform_driver asoc_simple_card = { .driver = { .name = "asoc-simple-card", + .of_match_table = asoc_simple_of_match, }, .probe = asoc_simple_card_probe, .remove = asoc_simple_card_remove,
On 01/31/2013 06:05 PM, Kuninori Morimoto wrote:
Hi Stephen, Mark
+- simple-audio,dai-name : simple-audio CPU/CODEC DAI name
OK, I see those two are CPU-/CODEC-specific. However, you could easily just have different property names for the two.
I assume you didn't like my idea of not putting the DAI names into the DT, but using extra arguments after the phandles instead? Doing so would be more alike most existing DT bindings.
The reason why I need "dai-name" is that phandle can select "cpu/codec device" itself, but, it can't select "port". This port is called/controlled as "xxx_dai_name" on ASoC I think.
like this
+-------------+ | FSI port A |--> ak4642 | port B |--> HDMI +-------------+
Then, I would like to ask Stephen, Mark
Yes it can.
In most DT bindings where phandles are used, you specify both a phandle and some arguments related to that phandle. The arguments could easily encode the port ID. In other words, instead of:
simple-audio,codec = <&phandle>;
you could write:
simple-audio,codec = <&phandle PORT_NUMBER>;
where PORT_NUMBER could be 0, 1, 2, or any other integer value or sequence of integer values, which the driver for the CODEC would interpret itself, and return an ASoC-internal port name.
Hi Stephen
In most DT bindings where phandles are used, you specify both a phandle and some arguments related to that phandle. The arguments could easily encode the port ID. In other words, instead of:
simple-audio,codec = <&phandle>;
you could write:
simple-audio,codec = <&phandle PORT_NUMBER>;
where PORT_NUMBER could be 0, 1, 2, or any other integer value or sequence of integer values, which the driver for the CODEC would interpret itself, and return an ASoC-internal port name.
I see. I will consider this logic on next patch
Best regards --- Kuninori Morimoto
Hi Stephen, Mark
These are v4 of simple-card DT support
Kuninori Morimoto (3): ASoC: use list_add_tail() instead of list_add() for platform/codec/dai list ASoC: add snd_soc_of_get_port_dai_name() ASoC: simple-card: add Device Tree support
#1, #2 enable to get cpu/codec_dai_name from device node and specific port number. #3 adds simple-card.
Best regards --- Kuninori Morimoto
Current ASoC is using list_add() in order to add new list to platform/codec/dai list. But it breaks added list's order. This patch use list_add_tail() instead of list_add() to solve this issue.
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- sound/soc/soc-core.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 689eb04..63f2627 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3738,7 +3738,7 @@ int snd_soc_register_dai(struct device *dev, if (!dai->codec) dai->dapm.idle_bias_off = 1;
- list_add(&dai->list, &dai_list); + list_add_tail(&dai->list, &dai_list);
mutex_unlock(&client_mutex);
@@ -3829,7 +3829,7 @@ int snd_soc_register_dais(struct device *dev, if (!dai->codec) dai->dapm.idle_bias_off = 1;
- list_add(&dai->list, &dai_list); + list_add_tail(&dai->list, &dai_list);
mutex_unlock(&client_mutex);
@@ -3892,7 +3892,7 @@ int snd_soc_register_platform(struct device *dev, mutex_init(&platform->mutex);
mutex_lock(&client_mutex); - list_add(&platform->list, &platform_list); + list_add_tail(&platform->list, &platform_list); mutex_unlock(&client_mutex);
dev_dbg(dev, "ASoC: Registered platform '%s'\n", platform->name); @@ -4043,7 +4043,7 @@ int snd_soc_register_codec(struct device *dev, }
mutex_lock(&client_mutex); - list_add(&codec->list, &codec_list); + list_add_tail(&codec->list, &codec_list); mutex_unlock(&client_mutex);
/* register any DAIs */
On 02/05/2013 03:11 AM, Kuninori Morimoto wrote:
Current ASoC is using list_add() in order to add new list to platform/codec/dai list. But it breaks added list's order. This patch use list_add_tail() instead of list_add() to solve this issue.
Do these lists have a defined order, such that changing the order does actually /break/ something?
I'm just curious what the motivation for this patch is really; is it just cosmetic?
This patch adds snd_soc_of_get_port_dai_name() to get dai name from device_node and port number.
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- include/sound/soc.h | 2 ++ sound/soc/soc-core.c | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+)
diff --git a/include/sound/soc.h b/include/sound/soc.h index e227880..be3cdd6 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1171,6 +1171,8 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, const char *propname); unsigned int snd_soc_of_parse_daifmt(struct device_node *np, const char *prefix); +const char *snd_soc_of_get_port_dai_name(struct device_node *of_node, + int port);
#include <sound/soc-dai.h>
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 63f2627..2cf3a94 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -4286,6 +4286,24 @@ unsigned int snd_soc_of_parse_daifmt(struct device_node *np, } EXPORT_SYMBOL_GPL(snd_soc_of_parse_daifmt);
+const char *snd_soc_of_get_port_dai_name(struct device_node *of_node, int port) +{ + struct snd_soc_dai *dai; + int i = 0; + + list_for_each_entry(dai, &dai_list, list) { + if (dai->dev->of_node == of_node) { + if (port == i) + return dai->name; + + i++; + } + } + + return NULL; +} +EXPORT_SYMBOL_GPL(snd_soc_of_get_port_dai_name); + static int __init snd_soc_init(void) { #ifdef CONFIG_DEBUG_FS
On 02/05/2013 03:11 AM, Kuninori Morimoto wrote:
This patch adds snd_soc_of_get_port_dai_name() to get dai name from device_node and port number.
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
+const char *snd_soc_of_get_port_dai_name(struct device_node *of_node, int port)
OK, that function prototype seems like /almost/ the right kind of thing to be doing.
"int port" should be "const struct of_phandle_args *portspec", since the port ID could be encoded into device tree with more than one cell, and the cells are uint32_t not int.
+{
- struct snd_soc_dai *dai;
- int i = 0;
- list_for_each_entry(dai, &dai_list, list) {
if (dai->dev->of_node == of_node) {
if (port == i)
return dai->name;
Is this the reason for the previous patch? This is horribly wrong. The only way this could work is with internal knowledge of how ASoC works, yet the device tree must be written in a completely OS-/driver-agnostic fashion, purely describing hardware.
This function should be implemented as follows:
1) Find the driver for dai->dev
2) Call an "of_xlate" function on that driver, passing it the "portspec" I mentioned above; the driver will interpret the portspec, maps it to the ASoC port name, and return it.
The DT binding for each audio component must define the list of valid port IDs, and the number of cells used to encode the value.
See for example the GPIO and PWM subsystem's of_xlate functions.
i++;
}
- }
- return NULL;
+} +EXPORT_SYMBOL_GPL(snd_soc_of_get_port_dai_name);
Hi Stephen
- Call an "of_xlate" function on that driver, passing it the "portspec"
I mentioned above; the driver will interpret the portspec, maps it to the ASoC port name, and return it.
The DT binding for each audio component must define the list of valid port IDs, and the number of cells used to encode the value.
See for example the GPIO and PWM subsystem's of_xlate functions.
Hmm... I guess this means struct snd_soc_dai_driver or similar has .of_xlate() callback ? But, this simple-audio is "independent" from cpu/codec.
For example, basically, we can use this simple-audio for FSI-wm8903 matching. But, this wm8903 is used on tegra too. Then, FSI-wm8903 (which use simple-audio) needs .of_xlate on wm8903 driver to get interpreted port name, but tegra-wm8903 don't need it.
Best regards --- Kuninori Morimoto
On 02/11/2013 10:37 PM, Kuninori Morimoto wrote:
Hi Stephen
- Call an "of_xlate" function on that driver, passing it the "portspec"
I mentioned above; the driver will interpret the portspec, maps it to the ASoC port name, and return it.
The DT binding for each audio component must define the list of valid port IDs, and the number of cells used to encode the value.
See for example the GPIO and PWM subsystem's of_xlate functions.
Hmm... I guess this means struct snd_soc_dai_driver or similar has .of_xlate() callback ?
Yes, something like that.
But, this simple-audio is "independent" from cpu/codec.
Well, any driver that could be used with it will need to implement the .of_xlate() callback. The simple-audio code would still be 100% independent from any CPU or CODEC, since of_xlate would be a standard interface/API that any CPU or CODEC driver could implement, and any ASoC machine driver could call.
For example, basically, we can use this simple-audio for FSI-wm8903 matching. But, this wm8903 is used on tegra too. Then, FSI-wm8903 (which use simple-audio) needs .of_xlate on wm8903 driver to get interpreted port name, but tegra-wm8903 don't need it.
Yes, .of_xlate() wouldn't have to be implemented by the WM8903 CODEC driver for the tegra-wm8903 machine driver to use the WM8903 CODEC. However, if it /was/ implemented, it wouldn't stop tegra-wm8903 from working. And later, it may help unify all the simple Tegra machine drivers into one, since they could also become CODEC-independent, and hence become unified (or at least mostly unified) code.
Hi Stephen
Thank you for your explain. I think I could understand, but not 100%.
Well, any driver that could be used with it will need to implement the .of_xlate() callback. The simple-audio code would still be 100% independent from any CPU or CODEC, since of_xlate would be a standard interface/API that any CPU or CODEC driver could implement, and any ASoC machine driver could call.
(snip)
Yes, .of_xlate() wouldn't have to be implemented by the WM8903 CODEC driver for the tegra-wm8903 machine driver to use the WM8903 CODEC. However, if it /was/ implemented, it wouldn't stop tegra-wm8903 from working. And later, it may help unify all the simple Tegra machine drivers into one, since they could also become CODEC-independent, and hence become unified (or at least mostly unified) code.
I guess, this .of_xlate should has "public" interface for all drivers, not simple-card special. Now, simple-card needs "dai name" from struct of_phandle_args. This .of_xlate can be used from other driver if there is such kind of driver. Now, as example, I assumed this "other driver" needs something other data pointer from .of_xlate here.
Then can .of_xlate has *void pointer for return ? In my check, the parameter of .of_xlate in gpio_chip and pmw has "driver specific" parameter.
My pseudo code now is below. But is this correct ??
simple-card OF has <&device port> : of_phandle_args will be used as "port" spec other driver OF has <xxxx yyy zzz> : of_phandle_args will be used as "something" spec
-- asoc -- struct snd_soc_dai_driver { ... int (*of_xlate)(struct snd_soc_dai_driver *driver, const struct of_phandle_args *spec, // driver specific spec void *data); // for return data ... }
-- MULTI .of_xlate support codec driver ---
#ifdef CONFIG_ASOC_SIMPLE_AUDIO_OF int codec_of_xlate(struct snd_soc_dai_driver *driver, const struct of_phandle_args *portspec, void *data); { /* * for simple-card which needs "dai name" * * of_phandle_args is used as "port" spec */ *data = port_to_dai_name(portspec); return 0; } #elif CONFIG_OTHER_DIRVER_IT_NEEDS_xxx_POINTER_OF int codec_of_xlate(struct snd_soc_dai_driver *driver, const struct of_phandle_args *something_spec, void *data); { /* * for "other" driver which needs something pointer * * of_phandle_args is used as "something" spec */ *data = something_necessary_pointer(something_spec); return 0; } #else #define codec_of_xlate() NULL #endif
struct snd_soc_dai_driver codec_driver = { ... .of_xlate = codec_of_xlate, ... }
Best regards --- Kuninori Morimoto
On 02/13/2013 06:16 PM, Kuninori Morimoto wrote:
Hi Stephen
Thank you for your explain. I think I could understand, but not 100%.
Well, any driver that could be used with it will need to implement the .of_xlate() callback. The simple-audio code would still be 100% independent from any CPU or CODEC, since of_xlate would be a standard interface/API that any CPU or CODEC driver could implement, and any ASoC machine driver could call.
(snip)
Yes, .of_xlate() wouldn't have to be implemented by the WM8903 CODEC driver for the tegra-wm8903 machine driver to use the WM8903 CODEC. However, if it /was/ implemented, it wouldn't stop tegra-wm8903 from working. And later, it may help unify all the simple Tegra machine drivers into one, since they could also become CODEC-independent, and hence become unified (or at least mostly unified) code.
I guess, this .of_xlate should has "public" interface for all drivers, not simple-card special.
Yes exactly. And this means that it always returns a particular type of object, not something different depending on who calls it; this is relevant to the discussion below.
Now, simple-card needs "dai name" from struct of_phandle_args.
Yes.
This .of_xlate can be used from other driver if there is such kind of driver. Now, as example, I assumed this "other driver" needs something other data pointer from .of_xlate here.
Well, .of_xlate is /defined/ as taking the of_phandle_args and returning the DAI name that the of_phandle_args represents. If there's ever a need to translate some of_phandle_args to something else, that should be a different function.
To that end, perhaps calling the function .of_xlate_dai_name might be more future-proof; if we ever needed to translate say a CODEC widget name, we could add a separate .of_xlate_widget_name function to do that later, with zero effect on the .of_xlate_dai_name function.
Then can .of_xlate has *void pointer for return ?
I think it would always return a string; the function parameter would be "char **dai_name".
In my check, the parameter of .of_xlate in gpio_chip and pmw has "driver specific" parameter.
It shouldn't. A GPIO driver's .of_xlate should /always/ take an of_phandle_args, and translate it to a Linux (or perhaps chip-relative) GPIO number, plus Linux GPIO flags. There should be nothing driver-specific about the data it returns. The format of the device tree cells that represent that data can be driver- (really, DT binding-) specific; the whole point of the .of_xlate function is to translate that binding-specific format into some standard internal Linux format.
My pseudo code now is below. But is this correct ??
simple-card OF has <&device port> : of_phandle_args will be used as "port" spec other driver OF has <xxxx yyy zzz> : of_phandle_args will be used as "something" spec
-- asoc -- struct snd_soc_dai_driver { ... int (*of_xlate)(struct snd_soc_dai_driver *driver, const struct of_phandle_args *spec, // driver specific spec void *data); // for return data
As I mentioned above, that last parameter should be "char **dai_name", and the function name probably of_xlate_dai_name.
...
}
-- MULTI .of_xlate support codec driver ---
#ifdef CONFIG_ASOC_SIMPLE_AUDIO_OF
No need to the ifdef; just provide a single definition which does one thing.
int codec_of_xlate(struct snd_soc_dai_driver *driver, const struct of_phandle_args *portspec, void *data); { /* * for simple-card which needs "dai name" * * of_phandle_args is used as "port" spec */ *data = port_to_dai_name(portspec);
Yes, that's about right. Given how simple the implementation of port_to_dai_name() is, I would simply write the code directly in the implementation of of_xlate(). I assume you were writing pseudo-code simply to avoid spelling out the implementation though.
return 0;
} #elif CONFIG_OTHER_DIRVER_IT_NEEDS_xxx_POINTER_OF int codec_of_xlate(struct snd_soc_dai_driver *driver, const struct of_phandle_args *something_spec, void *data); { /* * for "other" driver which needs something pointer * * of_phandle_args is used as "something" spec */ *data = something_necessary_pointer(something_spec); return 0; } #else #define codec_of_xlate() NULL #endif
struct snd_soc_dai_driver codec_driver = { ... .of_xlate = codec_of_xlate, ... }
Hi Stephen
Thank you for your explain
To that end, perhaps calling the function .of_xlate_dai_name might be more future-proof; if we ever needed to translate say a CODEC widget name, we could add a separate .of_xlate_widget_name function to do that later, with zero effect on the .of_xlate_dai_name function.
(snip)
struct snd_soc_dai_driver { ... int (*of_xlate)(struct snd_soc_dai_driver *driver, const struct of_phandle_args *spec, // driver specific spec void *data); // for return data
As I mentioned above, that last parameter should be "char **dai_name", and the function name probably of_xlate_dai_name.
OK, I understand. I create v6 patch which has .of_xlate_dai_name
Best regards --- Kuninori Morimoto
Hi Mar, Stephen
These are v6 of simple-card DT support
Kuninori Morimoto (4): ASoC: add .of_xlate_dai_name callback on struct snd_soc_dai_driver ASoC: ak4642: enable .of_xlate_dai_name on struct snd_soc_dai_driver ASoC: fsi: enable .of_xlate_dai_name on struct snd_soc_dai_driver ASoC: simple-card: add Device Tree support
Documentation/devicetree/bindings/sound/ak4642.txt | 5 + .../devicetree/bindings/sound/renesas,fsi.txt | 9 ++ .../devicetree/bindings/sound/simple-card.txt | 75 +++++++++++++ include/sound/soc-dai.h | 4 + include/sound/soc.h | 5 + sound/soc/codecs/ak4642.c | 1 + sound/soc/generic/simple-card.c | 118 +++++++++++++++++++- sound/soc/sh/fsi.c | 2 + sound/soc/soc-core.c | 40 +++++++ 9 files changed, 254 insertions(+), 5 deletions(-)
#1 adds .of_xlate_dai_name on snd_soc_dai_driver, #2,#3 add .of_xlate_dai_name support on FSI/AK4642 #4 adds simple-card DT support
Best regards --- Kuninori Morimoto
ASoC sound driver requires CPU/CODEC drivers for probing, and each CPU/CODEC has some DAI on it. Then, "dai name matching" have been used to identify CPU-CODEC DAI pair on ASoC.
But, the "dai port number matching" is now required from DeviceTree. The solution of this issue is to replace the dai port number into dai name, and it needs some kind of .of_xlate function on each driver.
This patch adds .of_xlate_dai_name callback interface on struct snd_soc_dai_driver, very basic/common snd_soc_common_of_xlate_dai_name() which replace the dai port number into dai name, and snd_soc_of_get_port_dai_name() which is using .of_xlate_dai_name.
Then, #sound-dai-cells which enables DAI specifier is required on CPU/CODEC device tree properties.
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- v5 -> v6
- adds of_xlate_dai_name()
include/sound/soc-dai.h | 4 ++++ include/sound/soc.h | 5 +++++ sound/soc/soc-core.c | 40 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+)
diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 4dbd3e7..0b5a02f 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -15,6 +15,7 @@
#include <linux/list.h> +#include <linux/of.h>
struct snd_pcm_substream; struct snd_soc_dapm_widget; @@ -206,6 +207,9 @@ struct snd_soc_dai_driver { int (*remove)(struct snd_soc_dai *dai); int (*suspend)(struct snd_soc_dai *dai); int (*resume)(struct snd_soc_dai *dai); + const char* (*of_xlate_dai_name)(struct snd_soc_dai *dai, + const struct of_phandle_args *args); + /* compress dai */ bool compress_dai;
diff --git a/include/sound/soc.h b/include/sound/soc.h index e227880..26a1ba6 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -21,6 +21,7 @@ #include <linux/kernel.h> #include <linux/regmap.h> #include <linux/log2.h> +#include <linux/of.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/compress_driver.h> @@ -1171,6 +1172,10 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, const char *propname); unsigned int snd_soc_of_parse_daifmt(struct device_node *np, const char *prefix); +const char *snd_soc_common_of_xlate_dai_name(struct snd_soc_dai *dai, + const struct of_phandle_args *args); +const char *snd_soc_of_get_port_dai_name(struct device_node *nf_node, + const char *prop);
#include <sound/soc-dai.h>
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 689eb04..e80fd27 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -4286,6 +4286,46 @@ unsigned int snd_soc_of_parse_daifmt(struct device_node *np, } EXPORT_SYMBOL_GPL(snd_soc_of_parse_daifmt);
+const char *snd_soc_common_of_xlate_dai_name(struct snd_soc_dai *dai, + const struct of_phandle_args *args) +{ + if (dai->id != args->args[0]) + return NULL; + + return dai->driver->name; +} +EXPORT_SYMBOL_GPL(snd_soc_common_of_xlate_dai_name); + +const char *snd_soc_of_get_port_dai_name(struct device_node *of_node, + const char *prop) +{ + struct snd_soc_dai *dai; + struct of_phandle_args args; + const char *name; + int ret; + + ret = of_parse_phandle_with_args(of_node, prop, + "#sound-dai-cells", 0, &args); + if (ret) + return NULL; + + of_node_put(args.np); + + list_for_each_entry(dai, &dai_list, list) { + if (dai->dev->of_node != args.np) + continue; + + if (dai->driver->of_xlate_dai_name) { + name = dai->driver->of_xlate_dai_name(dai, &args); + if (name) + return name; + } + } + + return NULL; +} +EXPORT_SYMBOL_GPL(snd_soc_of_get_port_dai_name); + static int __init snd_soc_init(void) { #ifdef CONFIG_DEBUG_FS
Hi Mark, Stephen
Sorry, this is self response, but...
ASoC sound driver requires CPU/CODEC drivers for probing, and each CPU/CODEC has some DAI on it. Then, "dai name matching" have been used to identify CPU-CODEC DAI pair on ASoC.
But, the "dai port number matching" is now required from DeviceTree. The solution of this issue is to replace the dai port number into dai name, and it needs some kind of .of_xlate function on each driver.
This patch adds .of_xlate_dai_name callback interface on struct snd_soc_dai_driver, very basic/common snd_soc_common_of_xlate_dai_name() which replace the dai port number into dai name, and snd_soc_of_get_port_dai_name() which is using .of_xlate_dai_name.
Then, #sound-dai-cells which enables DAI specifier is required on CPU/CODEC device tree properties.
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com
(snip)
+const char *snd_soc_common_of_xlate_dai_name(struct snd_soc_dai *dai,
const struct of_phandle_args *args)
+{
- if (dai->id != args->args[0])
return NULL;
- return dai->driver->name;
+} +EXPORT_SYMBOL_GPL(snd_soc_common_of_xlate_dai_name);
I used *common* for this function name, but *simple* or *basic* seems better name ?
Best regards --- Kuninori Morimoto
On 02/14/2013 10:21 AM, Kuninori Morimoto wrote: [...]
+const char *snd_soc_of_get_port_dai_name(struct device_node *of_node,
const char *prop)
+{
- struct snd_soc_dai *dai;
- struct of_phandle_args args;
- const char *name;
- int ret;
- ret = of_parse_phandle_with_args(of_node, prop,
"#sound-dai-cells", 0, &args);
- if (ret)
return NULL;
- of_node_put(args.np);
You should keep the reference until after the link.
- list_for_each_entry(dai, &dai_list, list) {
if (dai->dev->of_node != args.np)
continue;
if (dai->driver->of_xlate_dai_name) {
name = dai->driver->of_xlate_dai_name(dai, &args);
if (name)
return name;
}
Hm, this is not really a translate function, but rather a match function. It iterates over all dais of the device and returns the name of the first one which matches. But there is no translation going on. If the dai matches the callback will always want to return dai->driver->name. Anything else doesn't make much sense.
- }
- return NULL;
+}
Hi Lars
Thank you for checking patch
- list_for_each_entry(dai, &dai_list, list) {
if (dai->dev->of_node != args.np)
continue;
if (dai->driver->of_xlate_dai_name) {
name = dai->driver->of_xlate_dai_name(dai, &args);
if (name)
return name;
}
Hm, this is not really a translate function, but rather a match function. It iterates over all dais of the device and returns the name of the first one which matches. But there is no translation going on. If the dai matches the callback will always want to return dai->driver->name. Anything else doesn't make much sense.
I re-consider this including Stephen's opinion. Thank you
Best regards --- Kuninori Morimoto
On 02/14/2013 02:21 AM, Kuninori Morimoto wrote:
ASoC sound driver requires CPU/CODEC drivers for probing, and each CPU/CODEC has some DAI on it. Then, "dai name matching" have been used to identify CPU-CODEC DAI pair on ASoC.
But, the "dai port number matching" is now required from DeviceTree. The solution of this issue is to replace the dai port number into dai name, and it needs some kind of .of_xlate function on each driver.
This patch adds .of_xlate_dai_name callback interface on struct snd_soc_dai_driver, very basic/common snd_soc_common_of_xlate_dai_name() which replace the dai port number into dai name, and snd_soc_of_get_port_dai_name() which is using .of_xlate_dai_name.
Then, #sound-dai-cells which enables DAI specifier is required on CPU/CODEC device tree properties.
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
+const char *snd_soc_common_of_xlate_dai_name(struct snd_soc_dai *dai,
const struct of_phandle_args *args)
I assume you expect this to be the standard implementation that many/all CODECS will use as their of_xlate_dai_name function?
- if (dai->id != args->args[0])
return NULL;
This rather assumes that drivers with multiple DAIs will order the list of DAIs passed to snd_soc_register_dais() in the same order as the numbering in their device tree binding document. That seems a little optimistic.
The whole reason for adding an .of_xlate_dai_name function to the DAI driver was to allow drivers to implement their own translation without any dependency on ASoC internals, orders of lists of DAIs registered with ASoC, etc.
As such, I'm not sure that having a standardized implementation of .of_xlate_dai_name actually even makes sense.
- return dai->driver->name;
Surely this should return the DAI name not the DAI driver name?
+const char *snd_soc_of_get_port_dai_name(struct device_node *of_node,
const char *prop)
+{
- struct snd_soc_dai *dai;
- struct of_phandle_args args;
- const char *name;
- int ret;
- ret = of_parse_phandle_with_args(of_node, prop,
"#sound-dai-cells", 0, &args);
- if (ret)
return NULL;
I suspect returning an int error code would be better. That would allow you to "return ret" here, which would allow propagating details such as -EPROBE_DEFERRED.
- of_node_put(args.np);
- list_for_each_entry(dai, &dai_list, list) {
I think this should iterate over the list of CODEC drivers that are registered, and then ask the driver to translate from the args to the DAI name. Here, you're iterating over the list of registered DAIs, which is something entirely different.
if (dai->dev->of_node != args.np)
continue;
if (dai->driver->of_xlate_dai_name) {
name = dai->driver->of_xlate_dai_name(dai, &args);
if (name)
return name;
This probably also wants to return an integer to differentiate between e.g. "invalid value" and "no driver found yet".
}
- }
- return NULL;
If no driver has been registered for the phandle yet, you probably want to return -EPROBE_DEFERRED here too.
+} +EXPORT_SYMBOL_GPL(snd_soc_of_get_port_dai_name);
On 02/19/2013 01:53 PM, Stephen Warren wrote:
On 02/14/2013 02:21 AM, Kuninori Morimoto wrote:
ASoC sound driver requires CPU/CODEC drivers for probing, and each CPU/CODEC has some DAI on it. Then, "dai name matching" have been used to identify CPU-CODEC DAI pair on ASoC.
But, the "dai port number matching" is now required from DeviceTree. The solution of this issue is to replace the dai port number into dai name, and it needs some kind of .of_xlate function on each driver.
This patch adds .of_xlate_dai_name callback interface on struct snd_soc_dai_driver, very basic/common snd_soc_common_of_xlate_dai_name() which replace the dai port number into dai name, and snd_soc_of_get_port_dai_name() which is using .of_xlate_dai_name.
Then, #sound-dai-cells which enables DAI specifier is required on CPU/CODEC device tree properties.
...
+const char *snd_soc_of_get_port_dai_name(struct device_node *of_node,
const char *prop)
+{
- struct snd_soc_dai *dai;
- struct of_phandle_args args;
- const char *name;
- int ret;
- ret = of_parse_phandle_with_args(of_node, prop,
"#sound-dai-cells", 0, &args);
- if (ret)
return NULL;
- of_node_put(args.np);
- list_for_each_entry(dai, &dai_list, list) {
I think this should iterate over the list of CODEC drivers that are registered, and then ask the driver to translate from the args to the DAI name. Here, you're iterating over the list of registered DAIs, which is something entirely different.
Ah. I guess here is the issue:
For CODECs, ASoC actually knows about a CODEC object, so you can imagine asking the CODEC object to translate from some a DT DAI specifier to a DAI name, and then look up the DAI using the combination of CODEC plus DAI name.
However, the CPU DAIs, there is no object that contains the DAIs; only the DAIs exist. Thus, there's nothing to ask "which of your DAIs does this DT DAI specifier correspond to?".
Now presumably there is a platform device for the FSI device, just like there's a platform device for the AK4642 CODEC. Can we create an ASoC "CPU" device for the FSI device too, to act as the DAI container? Or can we alter this patch series to query the platform device rather than some ASoC device in order to do the DT DAI specifier to DAI name translation?
As an aside, I now recall this lack of symmetry from when I was working on enhancing the Tegra30 ASoC driver to support DPCM and similar; I ended up pretending that the CPU I2S interface was actually a CODEC with 1 DAI in order to model the CPU DAIs and real CODEC DAIs in a more similar fashion.
Hi Stephen
+const char *snd_soc_of_get_port_dai_name(struct device_node *of_node,
const char *prop)
+{
- struct snd_soc_dai *dai;
- struct of_phandle_args args;
- const char *name;
- int ret;
- ret = of_parse_phandle_with_args(of_node, prop,
"#sound-dai-cells", 0, &args);
- if (ret)
return NULL;
- of_node_put(args.np);
- list_for_each_entry(dai, &dai_list, list) {
I think this should iterate over the list of CODEC drivers that are registered, and then ask the driver to translate from the args to the DAI name. Here, you're iterating over the list of registered DAIs, which is something entirely different.
Ah. I guess here is the issue:
For CODECs, ASoC actually knows about a CODEC object, so you can imagine asking the CODEC object to translate from some a DT DAI specifier to a DAI name, and then look up the DAI using the combination of CODEC plus DAI name.
However, the CPU DAIs, there is no object that contains the DAIs; only the DAIs exist. Thus, there's nothing to ask "which of your DAIs does this DT DAI specifier correspond to?".
Now presumably there is a platform device for the FSI device, just like there's a platform device for the AK4642 CODEC. Can we create an ASoC "CPU" device for the FSI device too, to act as the DAI container? Or can we alter this patch series to query the platform device rather than some ASoC device in order to do the DT DAI specifier to DAI name translation?
As an aside, I now recall this lack of symmetry from when I was working on enhancing the Tegra30 ASoC driver to support DPCM and similar; I ended up pretending that the CPU I2S interface was actually a CODEC with 1 DAI in order to model the CPU DAIs and real CODEC DAIs in a more similar fashion.
Thank you for understanding my last resort :)
I don't want to create new feature (= snd_soc_register_cpu) on ASoC only for simple-card. But now, simple-card is assuming CPU device and Platform device is same one.
If my understanding was correct, struct snd_soc_platform_driver struct snd_soc_codec_driver will have new ".of_xlate_dai_name".
Best regards --- Kuninori Morimoto
On 02/19/2013 05:59 PM, Kuninori Morimoto wrote:
Hi Stephen
+const char *snd_soc_of_get_port_dai_name(struct device_node *of_node,
const char *prop)
+{
- struct snd_soc_dai *dai;
- struct of_phandle_args args;
- const char *name;
- int ret;
- ret = of_parse_phandle_with_args(of_node, prop,
"#sound-dai-cells", 0, &args);
- if (ret)
return NULL;
- of_node_put(args.np);
- list_for_each_entry(dai, &dai_list, list) {
I think this should iterate over the list of CODEC drivers that are registered, and then ask the driver to translate from the args to the DAI name. Here, you're iterating over the list of registered DAIs, which is something entirely different.
Ah. I guess here is the issue:
For CODECs, ASoC actually knows about a CODEC object, so you can imagine asking the CODEC object to translate from some a DT DAI specifier to a DAI name, and then look up the DAI using the combination of CODEC plus DAI name.
However, the CPU DAIs, there is no object that contains the DAIs; only the DAIs exist. Thus, there's nothing to ask "which of your DAIs does this DT DAI specifier correspond to?".
Now presumably there is a platform device for the FSI device, just like there's a platform device for the AK4642 CODEC. Can we create an ASoC "CPU" device for the FSI device too, to act as the DAI container? Or can we alter this patch series to query the platform device rather than some ASoC device in order to do the DT DAI specifier to DAI name translation?
As an aside, I now recall this lack of symmetry from when I was working on enhancing the Tegra30 ASoC driver to support DPCM and similar; I ended up pretending that the CPU I2S interface was actually a CODEC with 1 DAI in order to model the CPU DAIs and real CODEC DAIs in a more similar fashion.
Thank you for understanding my last resort :)
I don't want to create new feature (= snd_soc_register_cpu) on ASoC only for simple-card. But now, simple-card is assuming CPU device and Platform device is same one.
If my understanding was correct, struct snd_soc_platform_driver
I don't think a platform device would want an of_xlate_dai_name function; a platform device is not what provides the DAI and hence it shouldn't be involved in translating a DT DAI specifier into a DAI name.
struct snd_soc_codec_driver will have new ".of_xlate_dai_name".
Yes, putting the function into the CODEC driver makes sense.
I guess that snd_soc_register_dai() and snd_soc_register_dais() already are the equivalent of snd_soc_register_cpu(); they are already passed the struct device that implements the DAIs, and hence if you pass that struct back to the DAI driver's of_xlate_dai_name function, it should have enough information to do the mapping: the dev contains the platform data the DAI driver can use to perform the mapping.
I guess the algorithm should be:
* Find a CODEC device that was instantiated from the DT node referenced by the phandle.
* If found, ask the CODEC to translate, and use the result. This function would be passed the CODEC pointer and phandle args.
* Find any DAI, that is not part of a CODEC, that was instantiated from the DT node referenced by the phandle.
* If found, ask the driver of the DAI to translate. This function would probably have to be passed the DT node as well as the first DAI you found, plus the phandle args.
* If nothing found above, fail.
Hi Stephen
Thank you for checking patch
- if (dai->id != args->args[0])
return NULL;
This rather assumes that drivers with multiple DAIs will order the list of DAIs passed to snd_soc_register_dais() in the same order as the numbering in their device tree binding document. That seems a little optimistic.
The whole reason for adding an .of_xlate_dai_name function to the DAI driver was to allow drivers to implement their own translation without any dependency on ASoC internals, orders of lists of DAIs registered with ASoC, etc.
Ahh.. I see Thank you for pointing it.
if (dai->dev->of_node != args.np)
continue;
if (dai->driver->of_xlate_dai_name) {
name = dai->driver->of_xlate_dai_name(dai, &args);
if (name)
return name;
This probably also wants to return an integer to differentiate between e.g. "invalid value" and "no driver found yet".
I see, will fix it.
Best regards --- Kuninori Morimoto
ak4642 driver can be used from simple-card driver which requires .of_xlate_dai_name.
This patch supports .of_xlate_dai_name.
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- v5 -> v6
- new patch
Documentation/devicetree/bindings/sound/ak4642.txt | 5 +++++ sound/soc/codecs/ak4642.c | 1 + 2 files changed, 6 insertions(+)
diff --git a/Documentation/devicetree/bindings/sound/ak4642.txt b/Documentation/devicetree/bindings/sound/ak4642.txt index 623d4e7..c9bb4e5 100644 --- a/Documentation/devicetree/bindings/sound/ak4642.txt +++ b/Documentation/devicetree/bindings/sound/ak4642.txt @@ -7,10 +7,15 @@ Required properties: - compatible : "asahi-kasei,ak4642" or "asahi-kasei,ak4643" or "asahi-kasei,ak4648" - reg : The chip select number on the I2C bus
+Optional + + #sound-dai-cells : enable DAI specifier, it must be 1 + Example:
&i2c { ak4648: ak4648@0x12 { + #sound-dai-cells = <1>; compatible = "asahi-kasei,ak4642"; reg = <0x12>; }; diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index c78794d..4b212f9 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c @@ -452,6 +452,7 @@ static struct snd_soc_dai_driver ak4642_dai = { .formats = SNDRV_PCM_FMTBIT_S16_LE }, .ops = &ak4642_dai_ops, .symmetric_rates = 1, + .of_xlate_dai_name = snd_soc_common_of_xlate_dai_name, };
static int ak4642_resume(struct snd_soc_codec *codec)
fsi driver can be used from simple-card driver which requires .of_xlate_dai_name.
This patch supports .of_xlate_dai_name.
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- v5 -> v6
- new patch
.../devicetree/bindings/sound/renesas,fsi.txt | 9 +++++++++ sound/soc/sh/fsi.c | 2 ++ 2 files changed, 11 insertions(+)
diff --git a/Documentation/devicetree/bindings/sound/renesas,fsi.txt b/Documentation/devicetree/bindings/sound/renesas,fsi.txt index c5be003..a403ec1 100644 --- a/Documentation/devicetree/bindings/sound/renesas,fsi.txt +++ b/Documentation/devicetree/bindings/sound/renesas,fsi.txt @@ -13,9 +13,18 @@ Required properties: - fsib,stream-mode-support : same as fsia - fsib,use-internal-clock : same as fsia
+Optional + + #sound-dai-cells : enable DAI specifier, it must be 1 + + Valid values for the DAI specifier are: + 0: FSI port A + 1: FSI port B + Example:
sh_fsi2: sh_fsi2@0xec230000 { + #sound-dai-cells = <1>; compatible = "renesas,sh_fsi2"; reg = <0xec230000 0x400>; interrupts = <0 146 0x4>; diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index c724026a..afa6fd0 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -1861,6 +1861,7 @@ static struct snd_soc_dai_driver fsi_soc_dai[] = { .channels_max = 2, }, .ops = &fsi_dai_ops, + .of_xlate_dai_name = snd_soc_common_of_xlate_dai_name, }, { .name = "fsib-dai", @@ -1877,6 +1878,7 @@ static struct snd_soc_dai_driver fsi_soc_dai[] = { .channels_max = 2, }, .ops = &fsi_dai_ops, + .of_xlate_dai_name = snd_soc_common_of_xlate_dai_name, }, };
On 02/14/2013 02:22 AM, Kuninori Morimoto wrote:
fsi driver can be used from simple-card driver which requires .of_xlate_dai_name.
This patch supports .of_xlate_dai_name.
diff --git a/Documentation/devicetree/bindings/sound/renesas,fsi.txt b/Documentation/devicetree/bindings/sound/renesas,fsi.txt
The change to this file looks sane.
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c
@@ -1861,6 +1861,7 @@ static struct snd_soc_dai_driver fsi_soc_dai[] = { .channels_max = 2, }, .ops = &fsi_dai_ops,
},.of_xlate_dai_name = snd_soc_common_of_xlate_dai_name,
Hmm. I think that the .of_xlate_dai_name should be something related to the object (e.g. CODEC) that contains the DAIs, rather than the DAIs themselves. The intent is to ask some object (e.g. CODEC) which of its DAIs is represented by the DT DAI specifier, not to ask each DAI whether it is represented by that particular DT DAI specifier.
Aside from that, I'd expect the patch above to be something more like:
const char *fsi_xlate_dai_name(struct snd_soc_dai *dai, const struct of_phandle_args *args) { switch (args[0]) { case 0: return fsi_soc_dai[0].name; case 1: return fsi_soc_dai[1].name; default: return NULL; } }
@@ -1861,6 +1861,7 @@ static struct snd_soc_dai_driver fsi_soc_dai[] = { .channels_max = 2, }, .ops = &fsi_dai_ops, + .of_xlate_dai_name = fsi_xlate_dai_name, },
(although further modified according to my error handling comments before).
Hi Stephen
Hmm. I think that the .of_xlate_dai_name should be something related to the object (e.g. CODEC) that contains the DAIs, rather than the DAIs themselves. The intent is to ask some object (e.g. CODEC) which of its DAIs is represented by the DT DAI specifier, not to ask each DAI whether it is represented by that particular DT DAI specifier.
Aside from that, I'd expect the patch above to be something more like:
const char *fsi_xlate_dai_name(struct snd_soc_dai *dai, const struct of_phandle_args *args) { switch (args[0]) { case 0: return fsi_soc_dai[0].name; case 1: return fsi_soc_dai[1].name; default: return NULL; } }
Thank you for pointing it. I use this style in next patch.
Best regards --- Kuninori Morimoto
On 02/20/2013 02:04 AM, Kuninori Morimoto wrote:
Hi Stephen
Hmm. I think that the .of_xlate_dai_name should be something related to the object (e.g. CODEC) that contains the DAIs, rather than the DAIs themselves. The intent is to ask some object (e.g. CODEC) which of its DAIs is represented by the DT DAI specifier, not to ask each DAI whether it is represented by that particular DT DAI specifier.
Aside from that, I'd expect the patch above to be something more like:
const char *fsi_xlate_dai_name(struct snd_soc_dai *dai, const struct of_phandle_args *args) { switch (args[0]) { case 0: return fsi_soc_dai[0].name; case 1: return fsi_soc_dai[1].name; default: return NULL; } }
Thank you for pointing it. I use this style in next patch.
I don't think this makes any more sense than the current version. You still iterate over all dai instances and call the xlate function for the first dai where the _parent_ device's of_node matches. You also pass in the this dai as the first parameter to the xlate function, which makes even less sense since you can use it to lookup the correct name, which may either be the dai's name or any of its siblings.
If you want to use the xlate paradigm you really need to keep track of the cpu devices and make the xlate callback a property of the cpu device. Well or use a match paradigm instead of xlate.
- Lars
Support for loading the simple-card module via devicetree. It requests cpu/codec information, and .of_xlate_dai_name support on each driver for probing.
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- v5 -> v6
- cpu/codec become sub-node - it is using new .of_xlate_dai_name based snd_soc_of_get_port_dai_name() - update Documentation
.../devicetree/bindings/sound/simple-card.txt | 75 +++++++++++++ sound/soc/generic/simple-card.c | 118 +++++++++++++++++++- 2 files changed, 188 insertions(+), 5 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/simple-card.txt
diff --git a/Documentation/devicetree/bindings/sound/simple-card.txt b/Documentation/devicetree/bindings/sound/simple-card.txt new file mode 100644 index 0000000..86e0d9f --- /dev/null +++ b/Documentation/devicetree/bindings/sound/simple-card.txt @@ -0,0 +1,75 @@ +Simple-Card: + +Required properties: + +- compatible : "simple-audio" +- simple-audio,card-name : simple-audio card name +- simple-audio,format : see below +- simple-audio,cpu : CPU sub-node, see below +- simple-audio,codec : CODEC sub-node, see below + +Optional properties: + +- simple-audio,system-clock-frequency : system clock rate if it is connected to both CPU/CODEC +- simple-audio,bitclock-inversion : bit clock inversion for both CPU/CODEC +- simple-audio,frame-inversion : frame inversion for both CPU/CODEC + +Required cpu/codec subnode properties: + +- simple-audio,dev : phandle and port for CPU/CODEC +- simple-audio,frame-master : frame master +- simple-audio,bitclock-master : bitclock master +#sound-dai-cells integer is required on simple-audio,dev phandle's node + +Optional subnode properties: + +- simple-audio,bitclock-inversion : if CPU/CODEC needs clock inversion +- simple-audio,frame-inversion : if CPU/CODEC needs frame inversion +- simple-audio,system-clock-frequency : system clock rate for each CPU/CODEC + +simple-audio,format + "i2s" + "right_j" + "left_j" + "dsp_a" + "dsp_b" + "ac97" + "pdm" + "msb" + "lsb" + +Example: + +sound { + compatible = "simple-audio"; + + simple-audio,card-name = "FSI2A-AK4648"; + simple-audio,format = "left_j"; + + simple-audio,cpu { + simple-audio,dev = <&sh_fsi2 0>; + }; + + simple-audio,codec { + simple-audio,dev = <&ak4648 0>; + simple-audio,bitclock-master; + simple-audio,frame-master; + simple-audio,system-clock-frequency = <11289600>; + }; +}; + +&i2c0 { + ak4648: ak4648@0x12 { + #sound-dai-cells = <1>; + compatible = "asahi-kasei,ak4648"; + reg = <0x12>; + }; +}; + +sh_fsi2: sh_fsi2@0xec230000 { + #sound-dai-cells = <1>; + compatible = "renesas,sh_fsi2"; + reg = <0xec230000 0x400>; + interrupt-parent = <&gic>; + interrupts = <0 146 0x4>; +}; diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 6cf8355..e50e415 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -9,6 +9,7 @@ * published by the Free Software Foundation. */
+#include <linux/of.h> #include <linux/platform_device.h> #include <linux/module.h> #include <sound/simple_card.h> @@ -52,11 +53,108 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) return 0; }
+static struct device_node* +__asoc_simple_card_parse_of(struct device_node *np, + struct asoc_simple_dai *dai) +{ + struct device_node *node; + char prop[128]; + + /* get "simple-audio,dev = <&phandle port>" */ + snprintf(prop, sizeof(prop), "simple-audio,dev"); + node = of_parse_phandle(np, prop, 0); + if (!node) + return NULL; + + of_node_put(node); + + /* get dai-name */ + dai->name = snd_soc_of_get_port_dai_name(np, prop); + + /* get dai specific format */ + dai->fmt = snd_soc_of_parse_daifmt(np, "simple-audio,"); + + /* get "simple-audio,system-clock-frequency = <xxx>" */ + snprintf(prop, sizeof(prop), "simple-audio,system-clock-frequency"); + of_property_read_u32(np, prop, &dai->sysclk); + + return node; +} + +static void asoc_simple_card_parse_of(struct device_node *node, + struct asoc_simple_card_info *info, + struct device *dev, + struct device_node **of_cpu, + struct device_node **of_codec, + struct device_node **of_platform) +{ + struct device_node *np; + u32 sysclk = 0; + + of_property_read_string(node, "simple-audio,card-name", &info->card); + info->name = info->card; + + /* cpu/codec common daifmt */ + info->daifmt = snd_soc_of_parse_daifmt(node, "simple-audio,") & + (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_INV_MASK); + + /* cpu/codec common clock */ + of_property_read_u32(node, + "simple-audio,system-clock-frequency", &sysclk); + info->cpu_dai.sysclk = sysclk; + info->codec_dai.sysclk = sysclk; + + /* cpu/codec sub-node */ + for_each_child_of_node(node, np) { + if (0 == strcmp("simple-audio,cpu", np->name)) + *of_cpu = __asoc_simple_card_parse_of(np, + &info->cpu_dai); + if (0 == strcmp("simple-audio,codec", np->name)) + *of_codec = __asoc_simple_card_parse_of(np, + &info->codec_dai); + } + + /* simple-card assumes platform == cpu */ + *of_platform = *of_cpu; + + dev_dbg(dev, "card-name : %s\n", info->card); + dev_dbg(dev, "platform : %04x / %p\n", + info->daifmt, + *of_platform); + dev_dbg(dev, "cpu : %s / %04x / %d / %p\n", + info->cpu_dai.name, + info->cpu_dai.fmt, + info->cpu_dai.sysclk, + *of_cpu); + dev_dbg(dev, "codec : %s / %04x / %d / %p\n", + info->codec_dai.name, + info->codec_dai.fmt, + info->codec_dai.sysclk, + *of_codec); +} + static int asoc_simple_card_probe(struct platform_device *pdev) { - struct asoc_simple_card_info *cinfo = pdev->dev.platform_data; + struct asoc_simple_card_info *cinfo; + struct device_node *np = pdev->dev.of_node; + struct device_node *of_cpu, *of_codec, *of_platform; struct device *dev = &pdev->dev;
+ cinfo = NULL; + of_cpu = NULL; + of_codec = NULL; + of_platform = NULL; + if (np && of_device_is_available(np)) { + cinfo = devm_kzalloc(dev, sizeof(*cinfo), GFP_KERNEL); + if (cinfo) + asoc_simple_card_parse_of(np, cinfo, dev, + &of_cpu, + &of_codec, + &of_platform); + } else { + cinfo = pdev->dev.platform_data; + } + if (!cinfo) { dev_err(dev, "no info for asoc-simple-card\n"); return -EINVAL; @@ -64,10 +162,10 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
if (!cinfo->name || !cinfo->card || - !cinfo->codec || - !cinfo->platform || - !cinfo->cpu_dai.name || - !cinfo->codec_dai.name) { + !cinfo->codec_dai.name || + !(cinfo->codec || of_codec) || + !(cinfo->platform || of_platform) || + !(cinfo->cpu_dai.name || of_cpu)) { dev_err(dev, "insufficient asoc_simple_card_info settings\n"); return -EINVAL; } @@ -81,6 +179,9 @@ static int asoc_simple_card_probe(struct platform_device *pdev) cinfo->snd_link.platform_name = cinfo->platform; cinfo->snd_link.codec_name = cinfo->codec; cinfo->snd_link.codec_dai_name = cinfo->codec_dai.name; + cinfo->snd_link.cpu_of_node = of_cpu; + cinfo->snd_link.codec_of_node = of_codec; + cinfo->snd_link.platform_of_node = of_platform; cinfo->snd_link.init = asoc_simple_card_dai_init;
/* @@ -102,9 +203,16 @@ static int asoc_simple_card_remove(struct platform_device *pdev) return snd_soc_unregister_card(&cinfo->snd_card); }
+static const struct of_device_id asoc_simple_of_match[] = { + { .compatible = "simple-audio", }, + {}, +}; +MODULE_DEVICE_TABLE(of, asoc_simple_of_match); + static struct platform_driver asoc_simple_card = { .driver = { .name = "asoc-simple-card", + .of_match_table = asoc_simple_of_match, }, .probe = asoc_simple_card_probe, .remove = asoc_simple_card_remove,
On 02/14/2013 10:24 AM, Kuninori Morimoto wrote:
Support for loading the simple-card module via devicetree. It requests cpu/codec information, and .of_xlate_dai_name support on each driver for probing.
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com
v5 -> v6
- cpu/codec become sub-node
- it is using new .of_xlate_dai_name based snd_soc_of_get_port_dai_name()
- update Documentation
.../devicetree/bindings/sound/simple-card.txt | 75 +++++++++++++ sound/soc/generic/simple-card.c | 118 +++++++++++++++++++- 2 files changed, 188 insertions(+), 5 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/simple-card.txt
diff --git a/Documentation/devicetree/bindings/sound/simple-card.txt b/Documentation/devicetree/bindings/sound/simple-card.txt new file mode 100644 index 0000000..86e0d9f --- /dev/null +++ b/Documentation/devicetree/bindings/sound/simple-card.txt @@ -0,0 +1,75 @@ +Simple-Card:
+Required properties:
+- compatible : "simple-audio" +- simple-audio,card-name : simple-audio card name +- simple-audio,format : see below +- simple-audio,cpu : CPU sub-node, see below +- simple-audio,codec : CODEC sub-node, see below
+Optional properties:
+- simple-audio,system-clock-frequency : system clock rate if it is connected to both CPU/CODEC +- simple-audio,bitclock-inversion : bit clock inversion for both CPU/CODEC +- simple-audio,frame-inversion : frame inversion for both CPU/CODEC
+Required cpu/codec subnode properties:
+- simple-audio,dev : phandle and port for CPU/CODEC +- simple-audio,frame-master : frame master +- simple-audio,bitclock-master : bitclock master +#sound-dai-cells integer is required on simple-audio,dev phandle's node
Shouldn't the names of '#sound-dai-cells' and 'simple-audio,dev' kind of match? E.g. '#sound-dai-cells' and 'sound-dai'. Maybe drop the sound, since the a in dai kind of implies this.
[...]
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 6cf8355..e50e415 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -9,6 +9,7 @@
- published by the Free Software Foundation.
*/
+#include <linux/of.h> #include <linux/platform_device.h> #include <linux/module.h> #include <sound/simple_card.h> @@ -52,11 +53,108 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) return 0; }
+static struct device_node* +__asoc_simple_card_parse_of(struct device_node *np,
struct asoc_simple_dai *dai)
+{
- struct device_node *node;
- char prop[128];
- /* get "simple-audio,dev = <&phandle port>" */
- snprintf(prop, sizeof(prop), "simple-audio,dev");
Why do you need the extra buffer? Can you just pass, "simple-audio,dev" directly to of_parse_phandle?
- node = of_parse_phandle(np, prop, 0);
- if (!node)
return NULL;
- of_node_put(node);
You shouldn't drop the reference until you are done processing it. Which in this case is only after the device has been unregistered, since you pass the node on to the ASoC core.
- /* get dai-name */
- dai->name = snd_soc_of_get_port_dai_name(np, prop);
- /* get dai specific format */
- dai->fmt = snd_soc_of_parse_daifmt(np, "simple-audio,");
- /* get "simple-audio,system-clock-frequency = <xxx>" */
- snprintf(prop, sizeof(prop), "simple-audio,system-clock-frequency");
- of_property_read_u32(np, prop, &dai->sysclk);
- return node;
+}
Hi Lars
Thank you for checking patch
+- simple-audio,dev : phandle and port for CPU/CODEC +- simple-audio,frame-master : frame master +- simple-audio,bitclock-master : bitclock master +#sound-dai-cells integer is required on simple-audio,dev phandle's node
Shouldn't the names of '#sound-dai-cells' and 'simple-audio,dev' kind of match? E.g. '#sound-dai-cells' and 'sound-dai'. Maybe drop the sound, since the a in dai kind of implies this.
Thank you, but I would like to keep "simple-audio" name for it too. So, can I use simple-audio-dai #simple-audio-dai-cells
+static struct device_node* +__asoc_simple_card_parse_of(struct device_node *np,
struct asoc_simple_dai *dai)
+{
- struct device_node *node;
- char prop[128];
- /* get "simple-audio,dev = <&phandle port>" */
- snprintf(prop, sizeof(prop), "simple-audio,dev");
Why do you need the extra buffer? Can you just pass, "simple-audio,dev" directly to of_parse_phandle?
Indeed, thank you.
- node = of_parse_phandle(np, prop, 0);
- if (!node)
return NULL;
- of_node_put(node);
You shouldn't drop the reference until you are done processing it. Which in this case is only after the device has been unregistered, since you pass the node on to the ASoC core.
I see, will fix
Best regards --- Kuninori Morimoto
On 02/20/2013 01:48 AM, Kuninori Morimoto wrote:
Hi Lars
Thank you for checking patch
+- simple-audio,dev : phandle and port for CPU/CODEC +- simple-audio,frame-master : frame master +- simple-audio,bitclock-master : bitclock master +#sound-dai-cells integer is required on simple-audio,dev phandle's node
Shouldn't the names of '#sound-dai-cells' and 'simple-audio,dev' kind of match? E.g. '#sound-dai-cells' and 'sound-dai'. Maybe drop the sound, since the a in dai kind of implies this.
Thank you, but I would like to keep "simple-audio" name for it too. So, can I use simple-audio-dai #simple-audio-dai-cells
The requirement to be able to find the DAI via devicetree is not specific to the simple-audio driver. I'd prefer if we could come up with a common binding which can be used by multiple drivers. Since you also add the xlate (or match) function to the sound core it makes sense - in my option - to also have a generic phandle -> DAI look-up method in the core.
- Lars
+static struct device_node* +__asoc_simple_card_parse_of(struct device_node *np,
struct asoc_simple_dai *dai)
+{
- struct device_node *node;
- char prop[128];
- /* get "simple-audio,dev = <&phandle port>" */
- snprintf(prop, sizeof(prop), "simple-audio,dev");
Why do you need the extra buffer? Can you just pass, "simple-audio,dev" directly to of_parse_phandle?
Indeed, thank you.
- node = of_parse_phandle(np, prop, 0);
- if (!node)
return NULL;
- of_node_put(node);
You shouldn't drop the reference until you are done processing it. Which in this case is only after the device has been unregistered, since you pass the node on to the ASoC core.
I see, will fix
Best regards
Kuninori Morimoto _______________________________________________ Alsa-devel mailing list Alsa-devel@alsa-project.org http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
On 02/20/2013 05:17 AM, Lars-Peter Clausen wrote:
On 02/20/2013 01:48 AM, Kuninori Morimoto wrote:
Hi Lars
Thank you for checking patch
+- simple-audio,dev : phandle and port for CPU/CODEC +- simple-audio,frame-master : frame master +- simple-audio,bitclock-master : bitclock master +#sound-dai-cells integer is required on simple-audio,dev phandle's node
Shouldn't the names of '#sound-dai-cells' and 'simple-audio,dev' kind of match? E.g. '#sound-dai-cells' and 'sound-dai'. Maybe drop the sound, since the a in dai kind of implies this.
Thank you, but I would like to keep "simple-audio" name for it too. So, can I use simple-audio-dai #simple-audio-dai-cells
The requirement to be able to find the DAI via devicetree is not specific to the simple-audio driver. I'd prefer if we could come up with a common binding which can be used by multiple drivers. Since you also add the xlate (or match) function to the sound core it makes sense - in my option - to also have a generic phandle -> DAI look-up method in the core.
I agree here; the whole reason I've been pushing on creating a standardized of_xlate_dai_name function and a standardized #sound-dai-cells property is to allow the exact same property name and function to be used for any audio-related DT binding.
Hi Lars, Stephen
Thank you for your advice
The requirement to be able to find the DAI via devicetree is not specific to the simple-audio driver. I'd prefer if we could come up with a common binding which can be used by multiple drivers. Since you also add the xlate (or match) function to the sound core it makes sense - in my option - to also have a generic phandle -> DAI look-up method in the core.
I agree here; the whole reason I've been pushing on creating a standardized of_xlate_dai_name function and a standardized #sound-dai-cells property is to allow the exact same property name and function to be used for any audio-related DT binding.
I see. I will try it. But it will be next week
Best regards --- Kuninori Morimoto
Hi Mark, Stephen, Lars
These are v7 of simple-card DT support. I well considered your comments/advices. Then, I noticed that creating snd_soc_register_cpu() is better solution. It is very basic/simple version at this point, and I added [RFC] on these patches. I hope it is accepted by you, and updated to be more useful. Now, snd_soc_codec, and snd_soc_cpu has .of_xlate_dai_name() callback.
Kuninori Morimoto (5): ASoC: add snd_soc_register_cpu() ASoC: add .of_xlate_dai_name on snd_soc_cpu_cpu/codec_driver ASoC: simple-card: add Device Tree support ASoC: ak4642: add .of_xlate_dai_name support ASoC: fsi: add .of_xlate_dai_name support
Documentation/devicetree/bindings/sound/ak4642.txt | 5 + .../devicetree/bindings/sound/renesas,fsi.txt | 9 ++ .../devicetree/bindings/sound/simple-card.txt | 75 +++++++++++ include/sound/soc.h | 33 +++++ sound/soc/codecs/ak4642.c | 11 ++ sound/soc/generic/simple-card.c | 139 +++++++++++++++++++- sound/soc/sh/fsi.c | 22 +++- sound/soc/soc-core.c | 118 +++++++++++++++++ 8 files changed, 405 insertions(+), 7 deletions(-)
Best regards --- Kuninori Morimoto
Current ASoC has register function for platform/codec/dai/card, but doesn't have for cpu. It often produces confusion and fault on ASoC. This patch adds very basic register function for cpu
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- v6 -> v7
- new feature - based on snd_soc_register_codec()
include/sound/soc.h | 19 ++++++++++++ sound/soc/soc-core.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+)
diff --git a/include/sound/soc.h b/include/sound/soc.h index e227880..faffc9c 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -322,6 +322,8 @@ struct snd_soc_dai_link; struct snd_soc_platform_driver; struct snd_soc_codec; struct snd_soc_codec_driver; +struct snd_soc_cpu; +struct snd_soc_cpu_driver; struct soc_enum; struct snd_soc_jack; struct snd_soc_jack_zone; @@ -375,6 +377,10 @@ int snd_soc_register_codec(struct device *dev, const struct snd_soc_codec_driver *codec_drv, struct snd_soc_dai_driver *dai_drv, int num_dai); void snd_soc_unregister_codec(struct device *dev); +int snd_soc_register_cpu(struct device *dev, + const struct snd_soc_cpu_driver *cpu_drv, + struct snd_soc_dai_driver *dai_drv, int num_dai); +void snd_soc_unregister_cpu(struct device *dev); int snd_soc_codec_volatile_register(struct snd_soc_codec *codec, unsigned int reg); int snd_soc_codec_readable_register(struct snd_soc_codec *codec, @@ -839,6 +845,19 @@ struct snd_soc_platform { #endif };
+struct snd_soc_cpu_driver { +}; + +struct snd_soc_cpu { + const char *name; + int id; + int num_dai; + struct device *dev; + struct list_head list; + + const struct snd_soc_cpu_driver *driver; +}; + struct snd_soc_dai_link { /* config - must be set by machine driver */ const char *name; /* Codec name */ diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 5f44d22..14976ff 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -58,6 +58,7 @@ static DEFINE_MUTEX(client_mutex); static LIST_HEAD(dai_list); static LIST_HEAD(platform_list); static LIST_HEAD(codec_list); +static LIST_HEAD(cpu_list);
/* * This is a timeout to do a DAPM powerdown after a stream is closed(). @@ -4095,6 +4096,83 @@ found: } EXPORT_SYMBOL_GPL(snd_soc_unregister_codec);
+ +/** + * snd_soc_register_cpu - Register a cpu with the ASoC core + * + */ +int snd_soc_register_cpu(struct device *dev, + const struct snd_soc_cpu_driver *cpu_drv, + struct snd_soc_dai_driver *dai_drv, + int num_dai) +{ + struct snd_soc_cpu *cpu; + int ret; + + dev_dbg(dev, "cpu register %s\n", dev_name(dev)); + + cpu = kzalloc(sizeof(struct snd_soc_cpu), GFP_KERNEL); + if (!cpu) + return -ENOMEM; + + cpu->name = fmt_single_name(dev, &cpu->id); + if (!cpu->name) { + ret = -ENOMEM; + goto error_cpu; + } + + cpu->dev = dev; + cpu->driver = cpu_drv; + cpu->num_dai = num_dai; + + mutex_lock(&client_mutex); + list_add(&cpu->list, &cpu_list); + mutex_unlock(&client_mutex); + + ret = snd_soc_register_dais(dev, dai_drv, num_dai); + if (ret < 0) { + dev_err(cpu->dev, "ASoC: Failed to regster DAIs: %d\n", ret); + goto error_cpu_name; + } + + dev_dbg(cpu->dev, "ASoC: Registered cpu '%s'\n", cpu->name); + + return ret; + +error_cpu_name: + kfree(cpu->name); +error_cpu: + kfree(cpu); + + return ret; +} + +/** + * snd_soc_unregister_cpu - Unregister a cpu from the ASoC core + * + */ +void snd_soc_unregister_cpu(struct device *dev) +{ + struct snd_soc_cpu *cpu; + + list_for_each_entry(cpu, &cpu_list, list) { + if (dev == cpu->dev) + goto found; + } + return; + +found: + snd_soc_unregister_dais(dev, cpu->num_dai); + + mutex_lock(&client_mutex); + list_del(&cpu->list); + mutex_unlock(&client_mutex); + + dev_dbg(dev, "ASoC: Unregistered cpu '%s'\n", cpu->name); + kfree(cpu->name); + kfree(cpu); +} + /* Retrieve a card's name from device tree */ int snd_soc_of_parse_card_name(struct snd_soc_card *card, const char *propname)
On 02/25/2013 01:51 AM, Kuninori Morimoto wrote:
Current ASoC has register function for platform/codec/dai/card, but doesn't have for cpu. It often produces confusion and fault on ASoC. This patch adds very basic register function for cpu
This seems reasonable to me.
I can't recall how much influence the existing CODEC objects have on the various routing/matching decisions inside the ASoC core. While this patch does register and unregister CPU objects, I wonder if it should have more impact on any of the existing core code? Certainly I'd expect the CPU objects to show up in ASoC's debugfs and any similar files...
So as far as it goes, Reviewed-by: Stephen Warren swarren@nvidia.com
But I suspect this patch might need to do a bunch of other stuff too, or add a bunch of follow-on patches for that?
Hi Stephen
On 02/25/2013 01:51 AM, Kuninori Morimoto wrote:
Current ASoC has register function for platform/codec/dai/card, but doesn't have for cpu. It often produces confusion and fault on ASoC. This patch adds very basic register function for cpu
This seems reasonable to me.
I can't recall how much influence the existing CODEC objects have on the various routing/matching decisions inside the ASoC core. While this patch does register and unregister CPU objects, I wonder if it should have more impact on any of the existing core code? Certainly I'd expect the CPU objects to show up in ASoC's debugfs and any similar files...
This patch doesn't have any impact to existing drivers. It just added new cpu list.
So as far as it goes, Reviewed-by: Stephen Warren swarren@nvidia.com
But I suspect this patch might need to do a bunch of other stuff too, or add a bunch of follow-on patches for that?
If Mark can accept this new feature (= register CPU), I think we can start to switch to use it. But current struct CPU is very very simple, and it doesn't have any effect for existing code
Best regards --- Kuninori Morimoto
On 02/27/2013 05:42 PM, Kuninori Morimoto wrote:
Hi Stephen
On 02/25/2013 01:51 AM, Kuninori Morimoto wrote:
Current ASoC has register function for platform/codec/dai/card, but doesn't have for cpu. It often produces confusion and fault on ASoC. This patch adds very basic register function for cpu
This seems reasonable to me.
I can't recall how much influence the existing CODEC objects have on the various routing/matching decisions inside the ASoC core. While this patch does register and unregister CPU objects, I wonder if it should have more impact on any of the existing core code? Certainly I'd expect the CPU objects to show up in ASoC's debugfs and any similar files...
This patch doesn't have any impact to existing drivers. It just added new cpu list.
Sure. My point was that now you've added the list, perhaps the core ASoC code might want to make use of it in the same way it makes use of CODEC objects, since it's logically equivalent.
Perhaps this could be a separate set of follow-on patches. That's all entirely Mark's call.
On 02/28/2013 08:14 PM, Stephen Warren wrote:
On 02/27/2013 05:42 PM, Kuninori Morimoto wrote:
Hi Stephen
On 02/25/2013 01:51 AM, Kuninori Morimoto wrote:
Current ASoC has register function for platform/codec/dai/card, but doesn't have for cpu. It often produces confusion and fault on ASoC. This patch adds very basic register function for cpu
This seems reasonable to me.
I can't recall how much influence the existing CODEC objects have on the various routing/matching decisions inside the ASoC core. While this patch does register and unregister CPU objects, I wonder if it should have more impact on any of the existing core code? Certainly I'd expect the CPU objects to show up in ASoC's debugfs and any similar files...
This patch doesn't have any impact to existing drivers. It just added new cpu list.
Sure. My point was that now you've added the list, perhaps the core ASoC code might want to make use of it in the same way it makes use of CODEC objects, since it's logically equivalent.
In my opinion it makes sense to get rid of the distinction between CPU objects and CODEC objects in this case and instead introduce some kind of DAI container object. I mean the distinction is mostly for historic reasons from a time where it was only possible to bind a the cpu_dai of a link to a CPU DAI and the codec_dai to a CODEC DAI. But these dais both can for example be bound CODEC DAIs. I think to have a common base here would allow us to do some cleanups to the ASoC core and also avoid the duplication with snd_soc_of_get_cpu_dai_name and snd_soc_of_get_codec_dai_name which was introduced in this series.
- Lars
On Wed, Feb 27, 2013 at 03:45:45PM -0700, Stephen Warren wrote:
I can't recall how much influence the existing CODEC objects have on the various routing/matching decisions inside the ASoC core. While this patch does register and unregister CPU objects, I wonder if it should have more impact on any of the existing core code? Certainly I'd expect the CPU objects to show up in ASoC's debugfs and any similar files...
All that happens with routing is that routes will be bound within the current DAPM context before other objects are searched, otherwise everything is very flat.
ASoC sound driver requires CPU/CODEC drivers for probing, and each CPU/CODEC has some DAI on it. Then, "dai name matching" have been used to identify CPU-CODEC DAI pair on ASoC.
But, the "dai port number matching" is now required from DeviceTree. The solution of this issue is to replace the dai port number into dai name, and it needs some kind of .of_xlate function on each driver.
This patch adds .of_xlate_dai_name callback interface on each struct snd_soc_cpu/codec_driver, and snd_soc_of_get_cpu/codec_dai_name() which is using .of_xlate_dai_name.
Then, #sound-dai-cells which enables DAI specifier is required on CPU/CODEC device tree properties.
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- v6 -> v7
- return int instead of char* - for_each from cpu/codec list - used sound-dai and #sound-dai-cells
include/sound/soc.h | 14 ++++++++++++++ sound/soc/soc-core.c | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+)
diff --git a/include/sound/soc.h b/include/sound/soc.h index faffc9c..343a7c5 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -13,6 +13,7 @@ #ifndef __LINUX_SND_SOC_H #define __LINUX_SND_SOC_H
+#include <linux/of.h> #include <linux/platform_device.h> #include <linux/types.h> #include <linux/notifier.h> @@ -770,6 +771,11 @@ struct snd_soc_codec_driver { /* codec stream completion event */ int (*stream_event)(struct snd_soc_dapm_context *dapm, int event);
+ /* DT */ + int (*of_xlate_dai_name)(struct snd_soc_codec *codec, + struct of_phandle_args *args, + const char **dai_name); + bool ignore_pmdown_time; /* Doesn't benefit from pmdown delay */
/* probe ordering - for components with runtime dependencies */ @@ -846,6 +852,10 @@ struct snd_soc_platform { };
struct snd_soc_cpu_driver { + /* DT */ + int (*of_xlate_dai_name)(struct snd_soc_cpu *codec, + const struct of_phandle_args *args, + const char **dai_name); };
struct snd_soc_cpu { @@ -1190,6 +1200,10 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, const char *propname); unsigned int snd_soc_of_parse_daifmt(struct device_node *np, const char *prefix); +int snd_soc_of_get_codec_dai_name(struct device_node *of_node, + const char **dai_name); +int snd_soc_of_get_cpu_dai_name(struct device_node *of_node, + const char **dai_name);
#include <sound/soc-dai.h>
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 14976ff..da9a93d 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -4361,6 +4361,46 @@ unsigned int snd_soc_of_parse_daifmt(struct device_node *np, } EXPORT_SYMBOL_GPL(snd_soc_of_parse_daifmt);
+#define SND_SOC_OF_GET_DAI_NAME(contents) \ +int snd_soc_of_get_ ## contents ## _dai_name(struct device_node *of_node,\ + const char **dai_name) \ +{ \ + struct snd_soc_ ## contents *pos; \ + struct of_phandle_args args; \ + int ret; \ + \ + ret = of_parse_phandle_with_args(of_node, "sound-dai", \ + "#sound-dai-cells", 0, &args); \ + if (ret) \ + return ret; \ + \ + ret = -EPROBE_DEFER; \ + \ + mutex_lock(&client_mutex); \ + list_for_each_entry(pos, &contents ## _list, list) { \ + if (pos->dev->of_node != args.np) \ + continue; \ + \ + if (!pos->driver->of_xlate_dai_name) { \ + ret = -EIO; \ + break; \ + } \ + \ + ret = pos->driver->of_xlate_dai_name(pos, &args, dai_name);\ + break; \ + } \ + mutex_unlock(&client_mutex); \ + \ + of_node_put(args.np); \ + \ + return ret; \ +} + +SND_SOC_OF_GET_DAI_NAME(codec) +SND_SOC_OF_GET_DAI_NAME(cpu) +EXPORT_SYMBOL_GPL(snd_soc_of_get_codec_dai_name); +EXPORT_SYMBOL_GPL(snd_soc_of_get_cpu_dai_name); + static int __init snd_soc_init(void) { #ifdef CONFIG_DEBUG_FS
On 02/25/2013 01:53 AM, Kuninori Morimoto wrote:
ASoC sound driver requires CPU/CODEC drivers for probing, and each CPU/CODEC has some DAI on it. Then, "dai name matching" have been used to identify CPU-CODEC DAI pair on ASoC.
But, the "dai port number matching" is now required from DeviceTree. The solution of this issue is to replace the dai port number into dai name, and it needs some kind of .of_xlate function on each driver.
This patch adds .of_xlate_dai_name callback interface on each struct snd_soc_cpu/codec_driver, and snd_soc_of_get_cpu/codec_dai_name() which is using .of_xlate_dai_name.
Then, #sound-dai-cells which enables DAI specifier is required on CPU/CODEC device tree properties.
diff --git a/include/sound/soc.h b/include/sound/soc.h
struct snd_soc_cpu_driver {
- /* DT */
- int (*of_xlate_dai_name)(struct snd_soc_cpu *codec,
s/codec/cpu/
+int snd_soc_of_get_codec_dai_name(struct device_node *of_node,
const char **dai_name);
+int snd_soc_of_get_cpu_dai_name(struct device_node *of_node,
const char **dai_name);
I think you need to return the CODEC and CPU object or name here too. That'll be needed to fill in the machine driver's {codec,cpu}_of_node DAI link fields.
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
+#define SND_SOC_OF_GET_DAI_NAME(contents) \ +int snd_soc_of_get_ ## contents ## _dai_name(struct device_node *of_node,\
I would personally leave out the spaces around the ##; seems more readable to me, but maybe you'd disagree.
s/contents/type/?
...
- mutex_lock(&client_mutex); \
- list_for_each_entry(pos, &contents ## _list, list) { \
if (pos->dev->of_node != args.np) \
continue; \
\
if (!pos->driver->of_xlate_dai_name) { \
ret = -EIO; \
-ENOSYS seems more appropriate. Even if not, EIO doesn't seem right.
+EXPORT_SYMBOL_GPL(snd_soc_of_get_codec_dai_name);
I think you can put that macro call into SND_SOC_OF_GET_DAI_NAME().
Support for loading the simple-card module via devicetree. It requests cpu/codec information, and .of_xlate_dai_name support on each driver for probing.
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- v6 -> v7
- used snd_soc_of_get_cpu_dai_name(xxx); snd_soc_of_get_codec_dai_name(xxx); - simple-audio,dev -> sound-dai naming - remove proc copy on of_parse_phandle() - asoc_simple_card_parse_of() used return int
.../devicetree/bindings/sound/simple-card.txt | 75 +++++++++++ sound/soc/generic/simple-card.c | 139 +++++++++++++++++++- 2 files changed, 209 insertions(+), 5 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/simple-card.txt
diff --git a/Documentation/devicetree/bindings/sound/simple-card.txt b/Documentation/devicetree/bindings/sound/simple-card.txt new file mode 100644 index 0000000..dc6aa52 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/simple-card.txt @@ -0,0 +1,75 @@ +Simple-Card: + +Required properties: + +- compatible : "simple-audio" +- simple-audio,card-name : simple-audio card name +- simple-audio,format : see below +- simple-audio,cpu : CPU sub-node, see below +- simple-audio,codec : CODEC sub-node, see below + +Optional properties: + +- simple-audio,system-clock-frequency : system clock rate if it is connected to both CPU/CODEC +- simple-audio,bitclock-inversion : bit clock inversion for both CPU/CODEC +- simple-audio,frame-inversion : frame inversion for both CPU/CODEC + +Required cpu/codec subnode properties: + +- sound-dai : phandle and port for CPU/CODEC +- #sound-dai-cells : sound-dai phandle's node +- simple-audio,frame-master : frame master +- simple-audio,bitclock-master : bitclock master + +Optional subnode properties: + +- simple-audio,bitclock-inversion : if CPU/CODEC needs clock inversion +- simple-audio,frame-inversion : if CPU/CODEC needs frame inversion +- simple-audio,system-clock-frequency : system clock rate for each CPU/CODEC + +simple-audio,format + "i2s" + "right_j" + "left_j" + "dsp_a" + "dsp_b" + "ac97" + "pdm" + "msb" + "lsb" + +Example: + +sound { + compatible = "simple-audio"; + + simple-audio,card-name = "FSI2A-AK4648"; + simple-audio,format = "left_j"; + + simple-audio,cpu { + sound-dai = <&sh_fsi2 0>; + }; + + simple-audio,codec { + sound-dai = <&ak4648>; + simple-audio,bitclock-master; + simple-audio,frame-master; + simple-audio,system-clock-frequency = <11289600>; + }; +}; + +&i2c0 { + ak4648: ak4648@0x12 { + #sound-dai-cells = <0>; + compatible = "asahi-kasei,ak4648"; + reg = <0x12>; + }; +}; + +sh_fsi2: sh_fsi2@0xec230000 { + #sound-dai-cells = <1>; + compatible = "renesas,sh_fsi2"; + reg = <0xec230000 0x400>; + interrupt-parent = <&gic>; + interrupts = <0 146 0x4>; +}; diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 6cf8355..df8074c 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -9,6 +9,7 @@ * published by the Free Software Foundation. */
+#include <linux/of.h> #include <linux/platform_device.h> #include <linux/module.h> #include <sound/simple_card.h> @@ -52,11 +53,129 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) return 0; }
+static int +__asoc_simple_card_parse_of(struct device_node *np, + struct asoc_simple_dai *dai, + struct device_node **node, + int for_cpu) +{ + int ret; + + /* get "simple-audio,dev = <&phandle port>" */ + *node = of_parse_phandle(np, "sound-dai", 0); + if (!*node) + return -ENODEV; + + of_node_put(*node); + + /* get dai-name */ + if (for_cpu) + ret = snd_soc_of_get_cpu_dai_name(np, &dai->name); + else + ret = snd_soc_of_get_codec_dai_name(np, &dai->name); + + if (ret < 0) + return ret; + + /* get dai specific format */ + dai->fmt = snd_soc_of_parse_daifmt(np, "simple-audio,"); + + /* get "simple-audio,system-clock-frequency = <xxx>" */ + of_property_read_u32(np, + "simple-audio,system-clock-frequency", + &dai->sysclk); + + return 0; +} + +static int asoc_simple_card_parse_of(struct device_node *node, + struct asoc_simple_card_info *info, + struct device *dev, + struct device_node **of_cpu, + struct device_node **of_codec, + struct device_node **of_platform) +{ + struct device_node *np; + u32 sysclk = 0; + int ret = 0; + + of_property_read_string(node, "simple-audio,card-name", &info->card); + info->name = info->card; + + /* cpu/codec common daifmt */ + info->daifmt = snd_soc_of_parse_daifmt(node, "simple-audio,") & + (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_INV_MASK); + + /* cpu/codec common clock */ + of_property_read_u32(node, + "simple-audio,system-clock-frequency", &sysclk); + info->cpu_dai.sysclk = sysclk; + info->codec_dai.sysclk = sysclk; + + /* cpu/codec sub-node */ + for_each_child_of_node(node, np) { + if (0 == strcmp("simple-audio,cpu", np->name)) + ret = __asoc_simple_card_parse_of(np, + &info->cpu_dai, + of_cpu, 1); + if (0 == strcmp("simple-audio,codec", np->name)) + ret = __asoc_simple_card_parse_of(np, + &info->codec_dai, + of_codec, 0); + + if (ret < 0) + return ret; + } + + /* simple-card assumes platform == cpu */ + *of_platform = *of_cpu; + + dev_dbg(dev, "card-name : %s\n", info->card); + dev_dbg(dev, "platform : %04x / %p\n", + info->daifmt, + *of_platform); + dev_dbg(dev, "cpu : %s / %04x / %d / %p\n", + info->cpu_dai.name, + info->cpu_dai.fmt, + info->cpu_dai.sysclk, + *of_cpu); + dev_dbg(dev, "codec : %s / %04x / %d / %p\n", + info->codec_dai.name, + info->codec_dai.fmt, + info->codec_dai.sysclk, + *of_codec); + + return 0; +} + static int asoc_simple_card_probe(struct platform_device *pdev) { - struct asoc_simple_card_info *cinfo = pdev->dev.platform_data; + struct asoc_simple_card_info *cinfo; + struct device_node *np = pdev->dev.of_node; + struct device_node *of_cpu, *of_codec, *of_platform; struct device *dev = &pdev->dev;
+ cinfo = NULL; + of_cpu = NULL; + of_codec = NULL; + of_platform = NULL; + if (np && of_device_is_available(np)) { + cinfo = devm_kzalloc(dev, sizeof(*cinfo), GFP_KERNEL); + if (cinfo) { + int ret; + ret = asoc_simple_card_parse_of(np, cinfo, dev, + &of_cpu, + &of_codec, + &of_platform); + if (ret < 0) { + dev_err(dev, "parse error %d\n", ret); + return ret; + } + } + } else { + cinfo = pdev->dev.platform_data; + } + if (!cinfo) { dev_err(dev, "no info for asoc-simple-card\n"); return -EINVAL; @@ -64,10 +183,10 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
if (!cinfo->name || !cinfo->card || - !cinfo->codec || - !cinfo->platform || - !cinfo->cpu_dai.name || - !cinfo->codec_dai.name) { + !cinfo->codec_dai.name || + !(cinfo->codec || of_codec) || + !(cinfo->platform || of_platform) || + !(cinfo->cpu_dai.name || of_cpu)) { dev_err(dev, "insufficient asoc_simple_card_info settings\n"); return -EINVAL; } @@ -81,6 +200,9 @@ static int asoc_simple_card_probe(struct platform_device *pdev) cinfo->snd_link.platform_name = cinfo->platform; cinfo->snd_link.codec_name = cinfo->codec; cinfo->snd_link.codec_dai_name = cinfo->codec_dai.name; + cinfo->snd_link.cpu_of_node = of_cpu; + cinfo->snd_link.codec_of_node = of_codec; + cinfo->snd_link.platform_of_node = of_platform; cinfo->snd_link.init = asoc_simple_card_dai_init;
/* @@ -102,9 +224,16 @@ static int asoc_simple_card_remove(struct platform_device *pdev) return snd_soc_unregister_card(&cinfo->snd_card); }
+static const struct of_device_id asoc_simple_of_match[] = { + { .compatible = "simple-audio", }, + {}, +}; +MODULE_DEVICE_TABLE(of, asoc_simple_of_match); + static struct platform_driver asoc_simple_card = { .driver = { .name = "asoc-simple-card", + .of_match_table = asoc_simple_of_match, }, .probe = asoc_simple_card_probe, .remove = asoc_simple_card_remove,
On 02/25/2013 01:56 AM, Kuninori Morimoto wrote:
Support for loading the simple-card module via devicetree. It requests cpu/codec information, and .of_xlate_dai_name support on each driver for probing.
diff --git a/Documentation/devicetree/bindings/sound/simple-card.txt b/Documentation/devicetree/bindings/sound/simple-card.txt
+Optional properties:
...
+- simple-audio,bitclock-inversion : bit clock inversion for both CPU/CODEC +- simple-audio,frame-inversion : frame inversion for both CPU/CODEC
I think that Mark pointed out those would be best stored in the CPU and CODEC child nodes, since random buffering/inverting on the board might make the values at the two DAIs the opposite of each-other.
+Required cpu/codec subnode properties:
+- sound-dai : phandle and port for CPU/CODEC
I would be inclined to rename that simply "dai". "sound" is implicit since the property is part of a sound-related node. Still, this isn't a big deal.
+- #sound-dai-cells : sound-dai phandle's node
That property isn't part of the sound card's CPU/CODEC subnode, but rather part of the CPU or CODEC that's referred to by the phandle.
This document needs to describe 3 sets of nodes:
1) The sound node itself.
2) The CPU and CODEC child nodes of the sound node.
3) The nodes representing the CPU and CODEC HW devices. It is these that will contain #sound-dai-cells.
See for example how Documentation/devicetree/bindings/gpio/gpio.txt describes each of these 3 cases separately.
Note that I think #sound-dai-cells is the correct name for this property (and not #dai-cells), since the nodes they will appear in are more generic HW device nodes, and not a dedicated sound-card node.
+simple-audio,format
- "i2s"
- "right_j"
- "left_j"
- "dsp_a"
- "dsp_b"
- "ac97"
- "pdm"
- "msb"
- "lsb"
Now that we have a C pre-processor for device tree, I would be inclined to use an integer for that property, rather than strings.
+Example:
Overall, the example looks very much like what I hoped.
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
+static int +__asoc_simple_card_parse_of(struct device_node *np,
__ is a bit odd. Rename the function to asoc_simple_card_parse_of_dai() to avoid it having the same name as asoc_simple_card_parse_of() below, once you remove the __.
- /* get "simple-audio,dev = <&phandle port>" */
- *node = of_parse_phandle(np, "sound-dai", 0);
- if (!*node)
return -ENODEV;
I definitely think snd_soc_of_get_*_dai_name() should return this. Otherwise, you're just duplicating work that happens inside there.
- of_node_put(*node);
- /* get dai-name */
- if (for_cpu)
ret = snd_soc_of_get_cpu_dai_name(np, &dai->name);
- else
ret = snd_soc_of_get_codec_dai_name(np, &dai->name);
Why can't there be a single function that returns both the target DT node and the DAI name. It should simply search both the list of CPUs and list of CODECs until a match is found. That way, machine drivers won't need this "for_cpu" condition.
+static int asoc_simple_card_parse_of(struct device_node *node,
struct asoc_simple_card_info *info,
struct device *dev,
struct device_node **of_cpu,
struct device_node **of_codec,
struct device_node **of_platform)
+{
- struct device_node *np;
- u32 sysclk = 0;
- int ret = 0;
- of_property_read_string(node, "simple-audio,card-name", &info->card);
- info->name = info->card;
- /* cpu/codec common daifmt */
- info->daifmt = snd_soc_of_parse_daifmt(node, "simple-audio,") &
(SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_INV_MASK);
- /* cpu/codec common clock */
- of_property_read_u32(node,
"simple-audio,system-clock-frequency", &sysclk);
- info->cpu_dai.sysclk = sysclk;
- info->codec_dai.sysclk = sysclk;
- /* cpu/codec sub-node */
- for_each_child_of_node(node, np) {
What if there are 3 nodes because the DT author put random cruft in there.
I think you want to use of_find_node_by_name() instead, to look up a specific node name.
if (0 == strcmp("simple-audio,cpu", np->name))
s/0 ==/!/. (and I'm sure others disagree, but I rather dislike comparing a constant to see if it has a particular value, rather than comparing a value to the constant that you care if it matches or not).
static int asoc_simple_card_probe(struct platform_device *pdev)
...
- struct asoc_simple_card_info *cinfo;
...
- if (np && of_device_is_available(np)) {
cinfo = devm_kzalloc(dev, sizeof(*cinfo), GFP_KERNEL);
if (cinfo) {
int ret;
ret = asoc_simple_card_parse_of(np, cinfo, dev,
&of_cpu,
&of_codec,
&of_platform);
...
- cinfo->snd_link.cpu_of_node = of_cpu;
- cinfo->snd_link.codec_of_node = of_codec;
- cinfo->snd_link.platform_of_node = of_platform;
Why not just have asoc_simple_card_parse_of() directly fill in those values, rather than writing them to temporary variables only to copy them in here anyway. You pass cinfo to the function, so it could easily do this.
Hi Stephen
Thank you for your reply
Support for loading the simple-card module via devicetree. It requests cpu/codec information, and .of_xlate_dai_name support on each driver for probing.
diff --git a/Documentation/devicetree/bindings/sound/simple-card.txt b/Documentation/devicetree/bindings/sound/simple-card.txt
+Optional properties:
...
+- simple-audio,bitclock-inversion : bit clock inversion for both CPU/CODEC +- simple-audio,frame-inversion : frame inversion for both CPU/CODEC
I think that Mark pointed out those would be best stored in the CPU and CODEC child nodes, since random buffering/inverting on the board might make the values at the two DAIs the opposite of each-other.
Sub node has same properties too, and this is hybrid result of your/Mark comments.
If "sound node" has these properties, these will go to both CPU/CODEC, this means "cpu/codec common properties" if "cpu/codec sub node" has it, it will go to itself only. I guess "common property" is useful ?
Thank you for other comments, I will fix these in next version. But I'm busy now, so, it will be next week.
Best regards --- Kuninori Morimoto
On 02/27/2013 05:53 PM, Kuninori Morimoto wrote:
Hi Stephen
Thank you for your reply
Support for loading the simple-card module via devicetree. It requests cpu/codec information, and .of_xlate_dai_name support on each driver for probing.
diff --git a/Documentation/devicetree/bindings/sound/simple-card.txt b/Documentation/devicetree/bindings/sound/simple-card.txt
+Optional properties:
...
+- simple-audio,bitclock-inversion : bit clock inversion for both CPU/CODEC +- simple-audio,frame-inversion : frame inversion for both CPU/CODEC
I think that Mark pointed out those would be best stored in the CPU and CODEC child nodes, since random buffering/inverting on the board might make the values at the two DAIs the opposite of each-other.
Sub node has same properties too, and this is hybrid result of your/Mark comments.
If "sound node" has these properties, these will go to both CPU/CODEC, this means "cpu/codec common properties" if "cpu/codec sub node" has it, it will go to itself only. I guess "common property" is useful ?
OK, that makes sense. I didn't get that impression from reading the DT binding document though. Perhaps I read it too fast. The document should explicitly mention which nodes those properties can exist in.
ak4642 driver can be used from simple-card driver which requires .of_xlate_dai_name. This patch supports it.
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- v6 -> v7
- .of_xlate_dai_name is on codec driver
Documentation/devicetree/bindings/sound/ak4642.txt | 5 +++++ sound/soc/codecs/ak4642.c | 11 +++++++++++ 2 files changed, 16 insertions(+)
diff --git a/Documentation/devicetree/bindings/sound/ak4642.txt b/Documentation/devicetree/bindings/sound/ak4642.txt index 623d4e7..8b6df4d 100644 --- a/Documentation/devicetree/bindings/sound/ak4642.txt +++ b/Documentation/devicetree/bindings/sound/ak4642.txt @@ -7,10 +7,15 @@ Required properties: - compatible : "asahi-kasei,ak4642" or "asahi-kasei,ak4643" or "asahi-kasei,ak4648" - reg : The chip select number on the I2C bus
+Optional + + #sound-dai-cells : enable DAI specifier, it must be 0 + Example:
&i2c { ak4648: ak4648@0x12 { + #sound-dai-cells = <0>; compatible = "asahi-kasei,ak4642"; reg = <0x12>; }; diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index c78794d..5772af1 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c @@ -485,6 +485,15 @@ static int ak4642_remove(struct snd_soc_codec *codec) return 0; }
+static int ak4642_of_xlate_dai_name(struct snd_soc_codec *codec, + struct of_phandle_args *spec, + const char **dai_name) +{ + *dai_name = ak4642_dai.name; + + return 0; +} + static struct snd_soc_codec_driver soc_codec_dev_ak4642 = { .probe = ak4642_probe, .remove = ak4642_remove, @@ -497,6 +506,7 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4642 = { .num_dapm_widgets = ARRAY_SIZE(ak4642_dapm_widgets), .dapm_routes = ak4642_intercon, .num_dapm_routes = ARRAY_SIZE(ak4642_intercon), + .of_xlate_dai_name = ak4642_of_xlate_dai_name, };
static struct snd_soc_codec_driver soc_codec_dev_ak4648 = { @@ -511,6 +521,7 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4648 = { .num_dapm_widgets = ARRAY_SIZE(ak4642_dapm_widgets), .dapm_routes = ak4642_intercon, .num_dapm_routes = ARRAY_SIZE(ak4642_intercon), + .of_xlate_dai_name = ak4642_of_xlate_dai_name, };
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
On 02/25/2013 01:57 AM, Kuninori Morimoto wrote:
ak4642 driver can be used from simple-card driver which requires .of_xlate_dai_name. This patch supports it.
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c
+static int ak4642_of_xlate_dai_name(struct snd_soc_codec *codec,
struct of_phandle_args *spec,
const char **dai_name)
+{
- *dai_name = ak4642_dai.name;
- return 0;
+}
This seems fine, but I would be tempted to make that a common function; with body something like:
if codec->num_dai == 1: if spec->args_count: return error else: return codec->dais[0].name else: loop over all codec->dais if args->args[0] == dai->of_id: return dai return error
(similar to how drivers/gpio/gpiolib-of.c:of_gpio_simple_xlate() works).
That would allow the same function to be used by most CODECs/CPUs.
fsi driver can be used from simple-card driver which requires .of_xlate_dai_name, and snd_soc_register_cpu() This patch supports these.
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- v6 -> v7
- used snd_soc_register_cpu() - of_xlate_dai_name is on cpu driver
.../devicetree/bindings/sound/renesas,fsi.txt | 9 ++++++++ sound/soc/sh/fsi.c | 22 ++++++++++++++++++-- 2 files changed, 29 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/sound/renesas,fsi.txt b/Documentation/devicetree/bindings/sound/renesas,fsi.txt index c5be003..a403ec1 100644 --- a/Documentation/devicetree/bindings/sound/renesas,fsi.txt +++ b/Documentation/devicetree/bindings/sound/renesas,fsi.txt @@ -13,9 +13,18 @@ Required properties: - fsib,stream-mode-support : same as fsia - fsib,use-internal-clock : same as fsia
+Optional + + #sound-dai-cells : enable DAI specifier, it must be 1 + + Valid values for the DAI specifier are: + 0: FSI port A + 1: FSI port B + Example:
sh_fsi2: sh_fsi2@0xec230000 { + #sound-dai-cells = <1>; compatible = "renesas,sh_fsi2"; reg = <0xec230000 0x400>; interrupts = <0 146 0x4>; diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index c724026a..f40f731 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -1886,6 +1886,24 @@ static struct snd_soc_platform_driver fsi_soc_platform = { .pcm_free = fsi_pcm_free, };
+static int fsi_of_xlate_dai_name(struct snd_soc_cpu *codec, + const struct of_phandle_args *spec, + const char **dai_name) +{ + int id = spec->args[0]; + + if (ARRAY_SIZE(fsi_soc_dai) <= id) + return -ENODEV; + + *dai_name = fsi_soc_dai[id].name; + + return 0; +} + +static const struct snd_soc_cpu_driver fsi_soc_cpu = { + .of_xlate_dai_name = fsi_of_xlate_dai_name, +}; + /* * platform function */ @@ -2046,8 +2064,8 @@ static int fsi_probe(struct platform_device *pdev) goto exit_fsib; }
- ret = snd_soc_register_dais(&pdev->dev, fsi_soc_dai, - ARRAY_SIZE(fsi_soc_dai)); + ret = snd_soc_register_cpu(&pdev->dev, &fsi_soc_cpu, + fsi_soc_dai, ARRAY_SIZE(fsi_soc_dai)); if (ret < 0) { dev_err(&pdev->dev, "cannot snd dai register\n"); goto exit_snd_soc;
On 02/25/2013 01:57 AM, Kuninori Morimoto wrote:
fsi driver can be used from simple-card driver which requires .of_xlate_dai_name, and snd_soc_register_cpu() This patch supports these.
This also looks fine, although the same comments apply here as for patch 4/5.
Hi Kuninori,
On 25.02.2013 09:49, Kuninori Morimoto wrote:
Hi Mark, Stephen, Lars
These are v7 of simple-card DT support. I well considered your comments/advices. Then, I noticed that creating snd_soc_register_cpu() is better solution. It is very basic/simple version at this point, and I added [RFC] on these patches. I hope it is accepted by you, and updated to be more useful. Now, snd_soc_codec, and snd_soc_cpu has .of_xlate_dai_name() callback.
Kuninori Morimoto (5): ASoC: add snd_soc_register_cpu() ASoC: add .of_xlate_dai_name on snd_soc_cpu_cpu/codec_driver ASoC: simple-card: add Device Tree support ASoC: ak4642: add .of_xlate_dai_name support ASoC: fsi: add .of_xlate_dai_name support
May I ask what happened to this approach and the patch set?
Thanks, Daniel
Documentation/devicetree/bindings/sound/ak4642.txt | 5 + .../devicetree/bindings/sound/renesas,fsi.txt | 9 ++ .../devicetree/bindings/sound/simple-card.txt | 75 +++++++++++ include/sound/soc.h | 33 +++++ sound/soc/codecs/ak4642.c | 11 ++ sound/soc/generic/simple-card.c | 139 +++++++++++++++++++- sound/soc/sh/fsi.c | 22 +++- sound/soc/soc-core.c | 118 +++++++++++++++++ 8 files changed, 405 insertions(+), 7 deletions(-)
Best regards
Kuninori Morimoto _______________________________________________ devicetree-discuss mailing list devicetree-discuss@lists.ozlabs.org https://lists.ozlabs.org/listinfo/devicetree-discuss
Hi Daniel Cc Mark, Stephen
These are v7 of simple-card DT support. I well considered your comments/advices. Then, I noticed that creating snd_soc_register_cpu() is better solution. It is very basic/simple version at this point, and I added [RFC] on these patches. I hope it is accepted by you, and updated to be more useful. Now, snd_soc_codec, and snd_soc_cpu has .of_xlate_dai_name() callback.
Kuninori Morimoto (5): ASoC: add snd_soc_register_cpu() ASoC: add .of_xlate_dai_name on snd_soc_cpu_cpu/codec_driver ASoC: simple-card: add Device Tree support ASoC: ak4642: add .of_xlate_dai_name support ASoC: fsi: add .of_xlate_dai_name support
May I ask what happened to this approach and the patch set?
The 1st patch renamed as snd_soc_register_component() on a1422b8cb443c6cfc58da38394673b8b8eda6458 (ASoC: snd_soc_register_component() uses properly snd_soc_register_dai[s]())
In next step (2nd step), if my understanding was correct, current snd_soc_register_codec() will replaced to use snd_soc_register_component().
In 3rd step, snd_soc_register_component() will have name <-> id exchange function for DT suport. (DT use "ID", but ALSA use "name" for sound card matching)
In 4th step, simple-card can support DT
But, I'm busy now. and unfortunately, I don't know detail of how to do 2nd step at this point.
Best regards --- Kuninori Morimoto
Support for loading the simple-card module via devicetree. It requests cpu/codec information for probing.
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- v3 -> v4
- removed port-name - it gets dai_name from node and port number
.../devicetree/bindings/sound/simple-card.txt | 61 ++++++++++ sound/soc/generic/simple-card.c | 124 +++++++++++++++++++- 2 files changed, 180 insertions(+), 5 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/simple-card.txt
diff --git a/Documentation/devicetree/bindings/sound/simple-card.txt b/Documentation/devicetree/bindings/sound/simple-card.txt new file mode 100644 index 0000000..dc94b51 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/simple-card.txt @@ -0,0 +1,61 @@ +Simple-Card: + +Required properties: + + [prefix] means cpu/codec here + +- compatible : "simple-audio" +- simple-audio,card-name : simple-audio card name +- simple-audio,format : see below +- simple-audio,[prefix],dai : phandle and port for CPU/CODEC +- simple-audio,[prefix],frame-master : frame master +- simple-audio,[prefix],bitclock-master : bitclock master + +Optional properties: + +- simple-audio,system-clock-frequency : system clock rate if it is connected to both CPU/CODEC +- simple-audio,bitclock-inversion : bit clock inversion for both CPU/CODEC +- simple-audio,frame-inversion : frame inversion for both CPU/CODEC + +- simple-audio,[prefix],bitclock-inversion : if CPU/CODEC needs clock inversion +- simple-audio,[prefix],frame-inversion : if CPU/CODEC needs frame inversion +- simple-audio,[prefix],system-clock-frequency : system clock rate for each CPU/CODEC + +simple-audio,format + "i2s" + "right_j" + "left_j" + "dsp_a" + "dsp_b" + "ac97" + "pdm" + "msb" + "lsb" + +Example: + +sound { + compatible = "simple-audio"; + + simple-audio,card-name = "FSI2A-AK4648"; + simple-audio,format = "left_j"; + simple-audio,cpu,dai = <&sh_fsi2 0>; + simple-audio,codec,dai = <&ak4648 0>; + simple-audio,codec,bitclock-master; + simple-audio,codec,frame-master; + simple-audio,codec,system-clock-frequency = <11289600>; +}; + +&i2c0 { + ak4648: ak4648@0x12 { + compatible = "asahi-kasei,ak4648"; + reg = <0x12>; + }; +}; + +sh_fsi2: sh_fsi2@0xec230000 { + compatible = "renesas,sh_fsi2"; + reg = <0xec230000 0x400>; + interrupt-parent = <&gic>; + interrupts = <0 146 0x4>; +}; diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 6cf8355..c28ebcc 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -9,6 +9,7 @@ * published by the Free Software Foundation. */
+#include <linux/of.h> #include <linux/platform_device.h> #include <linux/module.h> #include <sound/simple_card.h> @@ -52,11 +53,114 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) return 0; }
+static struct device_node* +__asoc_simple_card_parse_of(struct device_node *np, + struct asoc_simple_dai *dai, + const char *prefix) +{ + const __be32 *list; + struct device_node *node; + char prop[128]; + int size, port; + + /* get [prefix]dai = <&phandle port-num> */ + snprintf(prop, sizeof(prop), "%s,dai", prefix); + list = of_get_property(np, prop, &size); + if (!list) + return NULL; + + if (2 != size / sizeof(*list)) + return NULL; + + node = of_find_node_by_phandle(be32_to_cpup(list++)); + if (!node) + return NULL; + + of_node_put(node); + + /* get port number */ + port = be32_to_cpup(list); + + /* get dai-name from node and port */ + dai->name = snd_soc_of_get_port_dai_name(node, port); + + /* get dai specific format */ + dai->fmt = snd_soc_of_parse_daifmt(np, prefix); + + /* get "[prefix]system-clock-frequency = <xxx>" */ + snprintf(prop, sizeof(prop), "%s,system-clock-frequency", prefix); + of_property_read_u32(np, prop, &dai->sysclk); + + return node; +} + +static void asoc_simple_card_parse_of(struct device_node *np, + struct asoc_simple_card_info *info, + struct device *dev, + struct device_node **of_cpu, + struct device_node **of_codec, + struct device_node **of_platform) +{ + u32 sysclk = 0; + + of_property_read_string(np, "simple-audio,card-name", &info->card); + info->name = info->card; + + info->daifmt = snd_soc_of_parse_daifmt(np, "simple-audio,") & + (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_INV_MASK); + + of_property_read_u32(np, + "simple-audio,system-clock-frequency", &sysclk); + + info->cpu_dai.sysclk = sysclk; + info->codec_dai.sysclk = sysclk; + + *of_cpu = __asoc_simple_card_parse_of(np, &info->cpu_dai, + "simple-audio,cpu"); + *of_codec = __asoc_simple_card_parse_of(np, &info->codec_dai, + "simple-audio,codec"); + + /* simple-card assumes platform == cpu */ + *of_platform = *of_cpu; + + dev_dbg(dev, "card-name : %s\n", info->card); + dev_dbg(dev, "platform : %04x / %p\n", + info->daifmt, + *of_platform); + dev_dbg(dev, "cpu : %s / %04x / %d / %p\n", + info->cpu_dai.name, + info->cpu_dai.fmt, + info->cpu_dai.sysclk, + *of_cpu); + dev_dbg(dev, "codec : %s / %04x / %d / %p\n", + info->codec_dai.name, + info->codec_dai.fmt, + info->codec_dai.sysclk, + *of_codec); +} + static int asoc_simple_card_probe(struct platform_device *pdev) { - struct asoc_simple_card_info *cinfo = pdev->dev.platform_data; + struct asoc_simple_card_info *cinfo; + struct device_node *np = pdev->dev.of_node; + struct device_node *of_cpu, *of_codec, *of_platform; struct device *dev = &pdev->dev;
+ cinfo = NULL; + of_cpu = NULL; + of_codec = NULL; + of_platform = NULL; + if (np && of_device_is_available(np)) { + cinfo = devm_kzalloc(dev, sizeof(*cinfo), GFP_KERNEL); + if (cinfo) + asoc_simple_card_parse_of(np, cinfo, dev, + &of_cpu, + &of_codec, + &of_platform); + } else { + cinfo = pdev->dev.platform_data; + } + if (!cinfo) { dev_err(dev, "no info for asoc-simple-card\n"); return -EINVAL; @@ -64,10 +168,10 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
if (!cinfo->name || !cinfo->card || - !cinfo->codec || - !cinfo->platform || - !cinfo->cpu_dai.name || - !cinfo->codec_dai.name) { + !cinfo->codec_dai.name || + !(cinfo->codec || of_codec) || + !(cinfo->platform || of_platform) || + !(cinfo->cpu_dai.name || of_cpu)) { dev_err(dev, "insufficient asoc_simple_card_info settings\n"); return -EINVAL; } @@ -81,6 +185,9 @@ static int asoc_simple_card_probe(struct platform_device *pdev) cinfo->snd_link.platform_name = cinfo->platform; cinfo->snd_link.codec_name = cinfo->codec; cinfo->snd_link.codec_dai_name = cinfo->codec_dai.name; + cinfo->snd_link.cpu_of_node = of_cpu; + cinfo->snd_link.codec_of_node = of_codec; + cinfo->snd_link.platform_of_node = of_platform; cinfo->snd_link.init = asoc_simple_card_dai_init;
/* @@ -102,9 +209,16 @@ static int asoc_simple_card_remove(struct platform_device *pdev) return snd_soc_unregister_card(&cinfo->snd_card); }
+static const struct of_device_id asoc_simple_of_match[] = { + { .compatible = "simple-audio", }, + {}, +}; +MODULE_DEVICE_TABLE(of, asoc_simple_of_match); + static struct platform_driver asoc_simple_card = { .driver = { .name = "asoc-simple-card", + .of_match_table = asoc_simple_of_match, }, .probe = asoc_simple_card_probe, .remove = asoc_simple_card_remove,
Support for loading the simple-card module via devicetree. It requests cpu/codec information for probing.
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- v3 -> v4
- removed port-name - it gets dai_name from node and port number
v4 -> v5
- fixup compile error on !CONFIG_OF
.../devicetree/bindings/sound/simple-card.txt | 61 +++++++++ sound/soc/generic/simple-card.c | 134 +++++++++++++++++++- 2 files changed, 190 insertions(+), 5 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/simple-card.txt
diff --git a/Documentation/devicetree/bindings/sound/simple-card.txt b/Documentation/devicetree/bindings/sound/simple-card.txt new file mode 100644 index 0000000..dc94b51 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/simple-card.txt @@ -0,0 +1,61 @@ +Simple-Card: + +Required properties: + + [prefix] means cpu/codec here + +- compatible : "simple-audio" +- simple-audio,card-name : simple-audio card name +- simple-audio,format : see below +- simple-audio,[prefix],dai : phandle and port for CPU/CODEC +- simple-audio,[prefix],frame-master : frame master +- simple-audio,[prefix],bitclock-master : bitclock master + +Optional properties: + +- simple-audio,system-clock-frequency : system clock rate if it is connected to both CPU/CODEC +- simple-audio,bitclock-inversion : bit clock inversion for both CPU/CODEC +- simple-audio,frame-inversion : frame inversion for both CPU/CODEC + +- simple-audio,[prefix],bitclock-inversion : if CPU/CODEC needs clock inversion +- simple-audio,[prefix],frame-inversion : if CPU/CODEC needs frame inversion +- simple-audio,[prefix],system-clock-frequency : system clock rate for each CPU/CODEC + +simple-audio,format + "i2s" + "right_j" + "left_j" + "dsp_a" + "dsp_b" + "ac97" + "pdm" + "msb" + "lsb" + +Example: + +sound { + compatible = "simple-audio"; + + simple-audio,card-name = "FSI2A-AK4648"; + simple-audio,format = "left_j"; + simple-audio,cpu,dai = <&sh_fsi2 0>; + simple-audio,codec,dai = <&ak4648 0>; + simple-audio,codec,bitclock-master; + simple-audio,codec,frame-master; + simple-audio,codec,system-clock-frequency = <11289600>; +}; + +&i2c0 { + ak4648: ak4648@0x12 { + compatible = "asahi-kasei,ak4648"; + reg = <0x12>; + }; +}; + +sh_fsi2: sh_fsi2@0xec230000 { + compatible = "renesas,sh_fsi2"; + reg = <0xec230000 0x400>; + interrupt-parent = <&gic>; + interrupts = <0 146 0x4>; +}; diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 6cf8355..0773655 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -9,6 +9,7 @@ * published by the Free Software Foundation. */
+#include <linux/of.h> #include <linux/platform_device.h> #include <linux/module.h> #include <sound/simple_card.h> @@ -52,11 +53,124 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) return 0; }
+#ifdef CONFIG_OF +static struct device_node* +__asoc_simple_card_parse_of(struct device_node *np, + struct asoc_simple_dai *dai, + const char *prefix) +{ + const __be32 *list; + struct device_node *node; + char prop[128]; + int size, port; + + /* get [prefix]dai = <&phandle port-num> */ + snprintf(prop, sizeof(prop), "%s,dai", prefix); + list = of_get_property(np, prop, &size); + if (!list) + return NULL; + + if (2 != size / sizeof(*list)) + return NULL; + + node = of_find_node_by_phandle(be32_to_cpup(list++)); + if (!node) + return NULL; + + of_node_put(node); + + /* get port number */ + port = be32_to_cpup(list); + + /* get dai-name from node and port */ + dai->name = snd_soc_of_get_port_dai_name(node, port); + + /* get dai specific format */ + dai->fmt = snd_soc_of_parse_daifmt(np, prefix); + + /* get "[prefix]system-clock-frequency = <xxx>" */ + snprintf(prop, sizeof(prop), "%s,system-clock-frequency", prefix); + of_property_read_u32(np, prop, &dai->sysclk); + + return node; +} + +static struct asoc_simple_card_info* +asoc_simple_card_parse_of(struct device_node *np, + struct device *dev, + struct device_node **of_cpu, + struct device_node **of_codec, + struct device_node **of_platform) +{ + struct asoc_simple_card_info *info; + u32 sysclk = 0; + + info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); + if (!info) { + dev_err(dev, "card info alloc failed\n"); + return NULL; + } + + of_property_read_string(np, "simple-audio,card-name", &info->card); + info->name = info->card; + + info->daifmt = snd_soc_of_parse_daifmt(np, "simple-audio,") & + (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_INV_MASK); + + of_property_read_u32(np, + "simple-audio,system-clock-frequency", &sysclk); + + info->cpu_dai.sysclk = sysclk; + info->codec_dai.sysclk = sysclk; + + *of_cpu = __asoc_simple_card_parse_of(np, &info->cpu_dai, + "simple-audio,cpu"); + *of_codec = __asoc_simple_card_parse_of(np, &info->codec_dai, + "simple-audio,codec"); + + /* simple-card assumes platform == cpu */ + *of_platform = *of_cpu; + + dev_dbg(dev, "card-name : %s\n", info->card); + dev_dbg(dev, "platform : %04x / %p\n", + info->daifmt, + *of_platform); + dev_dbg(dev, "cpu : %s / %04x / %d / %p\n", + info->cpu_dai.name, + info->cpu_dai.fmt, + info->cpu_dai.sysclk, + *of_cpu); + dev_dbg(dev, "codec : %s / %04x / %d / %p\n", + info->codec_dai.name, + info->codec_dai.fmt, + info->codec_dai.sysclk, + *of_codec); + + return info; +} +#else +#define asoc_simple_card_parse_of(...) NULL +#endif + static int asoc_simple_card_probe(struct platform_device *pdev) { - struct asoc_simple_card_info *cinfo = pdev->dev.platform_data; + struct asoc_simple_card_info *cinfo; + struct device_node *np = pdev->dev.of_node; + struct device_node *of_cpu, *of_codec, *of_platform; struct device *dev = &pdev->dev;
+ cinfo = NULL; + of_cpu = NULL; + of_codec = NULL; + of_platform = NULL; + if (np) + cinfo = asoc_simple_card_parse_of(np, dev, + &of_cpu, + &of_codec, + &of_platform); + else + cinfo = pdev->dev.platform_data; + if (!cinfo) { dev_err(dev, "no info for asoc-simple-card\n"); return -EINVAL; @@ -64,10 +178,10 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
if (!cinfo->name || !cinfo->card || - !cinfo->codec || - !cinfo->platform || - !cinfo->cpu_dai.name || - !cinfo->codec_dai.name) { + !cinfo->codec_dai.name || + !(cinfo->codec || of_codec) || + !(cinfo->platform || of_platform) || + !(cinfo->cpu_dai.name || of_cpu)) { dev_err(dev, "insufficient asoc_simple_card_info settings\n"); return -EINVAL; } @@ -81,6 +195,9 @@ static int asoc_simple_card_probe(struct platform_device *pdev) cinfo->snd_link.platform_name = cinfo->platform; cinfo->snd_link.codec_name = cinfo->codec; cinfo->snd_link.codec_dai_name = cinfo->codec_dai.name; + cinfo->snd_link.cpu_of_node = of_cpu; + cinfo->snd_link.codec_of_node = of_codec; + cinfo->snd_link.platform_of_node = of_platform; cinfo->snd_link.init = asoc_simple_card_dai_init;
/* @@ -102,9 +219,16 @@ static int asoc_simple_card_remove(struct platform_device *pdev) return snd_soc_unregister_card(&cinfo->snd_card); }
+static const struct of_device_id asoc_simple_of_match[] = { + { .compatible = "simple-audio", }, + {}, +}; +MODULE_DEVICE_TABLE(of, asoc_simple_of_match); + static struct platform_driver asoc_simple_card = { .driver = { .name = "asoc-simple-card", + .of_match_table = asoc_simple_of_match, }, .probe = asoc_simple_card_probe, .remove = asoc_simple_card_remove,
On 02/06/2013 05:55 PM, Kuninori Morimoto wrote:
Support for loading the simple-card module via devicetree. It requests cpu/codec information for probing.
+Simple-Card:
+Required properties:
- [prefix] means cpu/codec here
+- compatible : "simple-audio" +- simple-audio,card-name : simple-audio card name +- simple-audio,format : see below
+- simple-audio,[prefix],dai : phandle and port for CPU/CODEC +- simple-audio,[prefix],frame-master : frame master +- simple-audio,[prefix],bitclock-master : bitclock master
+Optional properties:
+- simple-audio,system-clock-frequency : system clock rate if it is connected to both CPU/CODEC +- simple-audio,bitclock-inversion : bit clock inversion for both CPU/CODEC +- simple-audio,frame-inversion : frame inversion for both CPU/CODEC
+- simple-audio,[prefix],bitclock-inversion : if CPU/CODEC needs clock inversion +- simple-audio,[prefix],frame-inversion : if CPU/CODEC needs frame inversion +- simple-audio,[prefix],system-clock-frequency : system clock rate for each CPU/CODEC
I know Mark had a preference to store DAI-specific data in sub-nodes rather than using this "[prefix]" thing... If that doesn't end up happening though, rather than "[prefix],", I think it'd be more typical to use "[prefix]-" since I've never seen a DT property name with two ","; "-" is typically used as the word separator in DT property names.
+sound {
- compatible = "simple-audio";
...
- simple-audio,codec,dai = <&ak4648 0>;
...
+sh_fsi2: sh_fsi2@0xec230000 {
- compatible = "renesas,sh_fsi2";
- reg = <0xec230000 0x400>;
- interrupt-parent = <&gic>;
- interrupts = <0 146 0x4>;
+};
Note that the DT binding documentation for renesas,sh_fsi2 needs to define:
a) The value of the #sound-dai-cells property that's missing from the sh_fsi2 node.
b) The legal values for the "0" in the "simple-audio,codec,dai" property in the "sound" node above, and which DAI on the device each value represents.
Hi Stephen
+sound {
- compatible = "simple-audio";
...
- simple-audio,codec,dai = <&ak4648 0>;
...
+sh_fsi2: sh_fsi2@0xec230000 {
- compatible = "renesas,sh_fsi2";
- reg = <0xec230000 0x400>;
- interrupt-parent = <&gic>;
- interrupts = <0 146 0x4>;
+};
Note that the DT binding documentation for renesas,sh_fsi2 needs to define:
a) The value of the #sound-dai-cells property that's missing from the sh_fsi2 node.
b) The legal values for the "0" in the "simple-audio,codec,dai" property in the "sound" node above, and which DAI on the device each value represents.
Sorry, I couldn't understand this. Do you mean like this ?
This example is assuming like this, and shows FSI-ak4642 sound
FSI port A -- ak4642 port B -- HDMI
sh_fsi2 has #sound-dai-cells, and ak4642 doesn't have it. Does this solved a) ?
Do you mean sh_fsi2 needs something like "port-a = xxx" settings for b) ??
sound { compatible = "simple-audio";
simple-audio,card-name = "FSI2A-AK4648"; simple-audio,format = "left_j"; simple-audio,cpu,dai = <&sh_fsi2 0>; simple-audio,codec,dai = <&ak4648>; simple-audio,codec,bitclock-master; simple-audio,codec,frame-master; simple-audio,codec,system-clock-frequency = <11289600>; };
&i2c0 { ak4648: ak4648@0x12 { compatible = "asahi-kasei,ak4648"; reg = <0x12>; }; };
sh_fsi2: sh_fsi2@0xec230000 { #sound-dai-cells = <2>; compatible = "renesas,sh_fsi2"; reg = <0xec230000 0x400>; interrupt-parent = <&gic>; interrupts = <0 146 0x4>; };
Best regards --- Kuninori Morimoto
On 02/11/2013 09:48 PM, Kuninori Morimoto wrote:
Hi Stephen
+sound {
- compatible = "simple-audio";
...
- simple-audio,codec,dai = <&ak4648 0>;
...
+sh_fsi2: sh_fsi2@0xec230000 {
- compatible = "renesas,sh_fsi2";
- reg = <0xec230000 0x400>;
- interrupt-parent = <&gic>;
- interrupts = <0 146 0x4>;
+};
Note that the DT binding documentation for renesas,sh_fsi2 needs to define:
a) The value of the #sound-dai-cells property that's missing from the sh_fsi2 node.
b) The legal values for the "0" in the "simple-audio,codec,dai" property in the "sound" node above, and which DAI on the device each value represents.
Sorry, I couldn't understand this. Do you mean like this ?
This example is assuming like this, and shows FSI-ak4642 sound
FSI port A -- ak4642 port B -- HDMI
sh_fsi2 has #sound-dai-cells, and ak4642 doesn't have it. Does this solved a) ?
There should be a file in Documentation/devicetree/bindings that describes how to create a "renesas,sh_fsi2" node. The document should specify what value that node's #sound-dai-cells property must contain.
Do you mean sh_fsi2 needs something like "port-a = xxx" settings for b) ??
The binding documentation must specify what values go into the "DAI specifier" DT cells. Something like:
Required properties: - #sound-dai-cells Integer, must be 1. Valid values for the DAI specifier are: 0: FSI port A 1: FSI port B
sound { compatible = "simple-audio";
simple-audio,card-name = "FSI2A-AK4648"; simple-audio,format = "left_j"; simple-audio,cpu,dai = <&sh_fsi2 0>; simple-audio,codec,dai = <&ak4648>; simple-audio,codec,bitclock-master; simple-audio,codec,frame-master; simple-audio,codec,system-clock-frequency = <11289600>; };
&i2c0 { ak4648: ak4648@0x12 { compatible = "asahi-kasei,ak4648"; reg = <0x12>;
There should be a #sound-dai-cells property in this node too, since it needs to be linked into the sound node.
Does this HW only have a single DAI? If so, the value of #sound-dai-cells can be 0, since there's no need to distinguish between different DAIs.
}; };
sh_fsi2: sh_fsi2@0xec230000 { #sound-dai-cells = <2>;
Shouldn't that be 1? This is specifying the number of cells that appear after the phandle in the simple-audio,cpu,dai property above, not the number of valid values that you could put into the cell.
compatible = "renesas,sh_fsi2"; reg = <0xec230000 0x400>; interrupt-parent = <&gic>; interrupts = <0 146 0x4>; };
Hi Stephen
+- simple-audio,[prefix],bitclock-inversion : if CPU/CODEC needs clock inversion +- simple-audio,[prefix],frame-inversion : if CPU/CODEC needs frame inversion +- simple-audio,[prefix],system-clock-frequency : system clock rate for each CPU/CODEC
I know Mark had a preference to store DAI-specific data in sub-nodes rather than using this "[prefix]" thing... If that doesn't end up happening though, rather than "[prefix],", I think it'd be more typical to use "[prefix]-" since I've never seen a DT property name with two ","; "-" is typically used as the word separator in DT property names.
Hmm... If I can use sub-node, I can use below style for getting dai name ? I guess it is easy/simple, but, what do you think about this ?
sound {
ak4642-hifi { simple-audio,codec; simple-audio,dev = <&ak4642>; ... } fsia-dai { simple-audio,cpu; simple-audio,dev = <&sh_fsi2>; ... } }
Best regards --- Kuninori Morimoto
On 02/12/2013 06:13 PM, Kuninori Morimoto wrote:
Hi Stephen
+- simple-audio,[prefix],bitclock-inversion : if CPU/CODEC needs clock inversion +- simple-audio,[prefix],frame-inversion : if CPU/CODEC needs frame inversion +- simple-audio,[prefix],system-clock-frequency : system clock rate for each CPU/CODEC
I know Mark had a preference to store DAI-specific data in sub-nodes rather than using this "[prefix]" thing... If that doesn't end up happening though, rather than "[prefix],", I think it'd be more typical to use "[prefix]-" since I've never seen a DT property name with two ","; "-" is typically used as the word separator in DT property names.
Hmm... If I can use sub-node, I can use below style for getting dai name ? I guess it is easy/simple, but, what do you think about this ?
sound { ak4642-hifi {
If you want the "simple-audio" binding and driver to be completely generic, you had better name this node something generic like "codec".
simple-audio,codec;
Then, you wouldn't need that property to identify what type of child node this is.
simple-audio,dev = <&ak4642>;
Make that value <&ak4642 0> in order to select which AK4642 port you want to connect.
...
} fsia-dai {
Name this node something generic like "CPU".
simple-audio,cpu; simple-audio,dev = <&sh_fsi2>; ...
} }
Hi Mark, Stephen
Kuninori Morimoto (3): ASoC: use list_add_tail() instead of list_add() for platform/codec/dai list ASoC: add snd_soc_of_get_port_dai_name() ASoC: simple-card: add Device Tree support
#1, #2 enable to get cpu/codec_dai_name from device node and specific port number. #3 adds simple-card.
I noticed that #3 patch has compile error without CONFIG_OF. Please give me v5 chance for it.
But, I still need any feedback about it.
Best regards --- Kuninori Morimoto
On 01/14/2013 07:40 PM, Kuninori Morimoto wrote:
Support for loading the simple-card module via devicetree. It requests cpu/codec/platform information for probing.
diff --git a/Documentation/devicetree/bindings/sound/simple-card.txt b/Documentation/devicetree/bindings/sound/simple-card.txt
+Required properties:
+- compatible : "simple-audio" +- simple-audio,card-name : simple-audio card name
+- simple-audio,platform,controller : phandle for platform
Rename that simple-audio,dma-controller perhaps? "platform" is a word specific to ASoC, and the bindings really should be generic across OSs.
But I wonder why you'd even need the ASoC platform to be specified in DT; instead, the following seem better:
a) Have the CPU DAI's driver register the platform itself. Tegra does this.
b) Assume the ASoC "platform" device simply does DMA via a standard dmaengine driber, and instead refer to the DMA controller using DMA engine DT bindings.
+- simple-audio,platform,name : simple-audio platform name
Can you explain why you'd need the platform name in the DT? Doesn't the phandle always uniquely identify it? The example doesn't use this property.
+- simple-audio,cpu,controller : phandle for CPU DAI +- simple-audio,cpu,dai,name : simple-audio CPU DAI name
It'd be a bit more typical of device-tree to have a single property that defines both the controller and any properties of the controller at once, e.g. something like:
simple-audio,cpu-interface = <&codec_phandle AK4648_I2S_ITF_A>;
where we assume something like:
#define AK4648_I2S_ITF_A 0 // Interface A's ID
That would remove the need to put string names into the DT.
+simple-audio,xxx,dai,clock-gating
- "continuous"
- "gated"
Don't you need to use the common clock bindings to define which clock to gate? Or, is the I2S/... node's binding supposed to provide that information?
On Mon, Jan 28, 2013 at 02:11:38PM -0700, Stephen Warren wrote:
On 01/14/2013 07:40 PM, Kuninori Morimoto wrote:
+simple-audio,xxx,dai,clock-gating
- "continuous"
- "gated"
Don't you need to use the common clock bindings to define which clock to gate? Or, is the I2S/... node's binding supposed to provide that information?
This is for the I2S bus - it's saying if the clocks should only be present when there is data or not.
To be honest using the common clock API for anything off-SoC still seems fairly hopeless right now, the architecture maintainers don't care about it and there's little interest in fixing it in the clock API itself.
Hi Stephen
Thank you for checking path
+Required properties:
+- compatible : "simple-audio" +- simple-audio,card-name : simple-audio card name
+- simple-audio,platform,controller : phandle for platform
Rename that simple-audio,dma-controller perhaps? "platform" is a word specific to ASoC, and the bindings really should be generic across OSs.
But I wonder why you'd even need the ASoC platform to be specified in DT; instead, the following seem better:
a) Have the CPU DAI's driver register the platform itself. Tegra does this.
b) Assume the ASoC "platform" device simply does DMA via a standard dmaengine driber, and instead refer to the DMA controller using DMA engine DT bindings.
This is the feature of this "simple-audio" driver. "simple-audio" produces board/SoC specific relationship between codec/cpu.
For example, we are using FSI for cpu, and AK4642/WM8978/DA7210 for codec. In our old style, we created fsi-ak4642, fsi-wm8978, fsi-da7210... This means that new fsi-xxx driver is required whenever new boards were created. This simple-audio was created to avoid it
+- simple-audio,platform,name : simple-audio platform name
Can you explain why you'd need the platform name in the DT? Doesn't the phandle always uniquely identify it? The example doesn't use this property.
Ahh yes, this simple-audio supports both phandle and name matching for compatibility. example showed phandle matching only.
+- simple-audio,cpu,controller : phandle for CPU DAI +- simple-audio,cpu,dai,name : simple-audio CPU DAI name
It'd be a bit more typical of device-tree to have a single property that defines both the controller and any properties of the controller at once, e.g. something like:
simple-audio,cpu-interface = <&codec_phandle AK4648_I2S_ITF_A>;
where we assume something like:
#define AK4648_I2S_ITF_A 0 // Interface A's ID
That would remove the need to put string names into the DT.
Hmm... this "name" is required on ASoC matching... Especially, "codec dai name" is must item.
Should I modify ASoC itself ?
+simple-audio,xxx,dai,clock-gating
- "continuous"
- "gated"
Don't you need to use the common clock bindings to define which clock to gate? Or, is the I2S/... node's binding supposed to provide that information?
I guess it is dependent on SoC/board. No ?
Best regards --- Kuninori Morimoto
On 01/28/2013 07:14 PM, Kuninori Morimoto wrote:
Hi Stephen
Thank you for checking path
+Required properties:
+- compatible : "simple-audio" +- simple-audio,card-name : simple-audio card name
+- simple-audio,platform,controller : phandle for platform
Rename that simple-audio,dma-controller perhaps? "platform" is a word specific to ASoC, and the bindings really should be generic across OSs.
But I wonder why you'd even need the ASoC platform to be specified in DT; instead, the following seem better:
a) Have the CPU DAI's driver register the platform itself. Tegra does this.
b) Assume the ASoC "platform" device simply does DMA via a standard dmaengine driber, and instead refer to the DMA controller using DMA engine DT bindings.
This is the feature of this "simple-audio" driver. "simple-audio" produces board/SoC specific relationship between codec/cpu.
For example, we are using FSI for cpu, and AK4642/WM8978/DA7210 for codec. In our old style, we created fsi-ak4642, fsi-wm8978, fsi-da7210... This means that new fsi-xxx driver is required whenever new boards were created. This simple-audio was created to avoid it
I still don't understand why the ASoC platform has to be exposed in device tree; it seems like something completely internal to the ASoC driver. Take a look at the Tegra ASoC DT bindings; the platform isn't in DT at all there.
+- simple-audio,platform,name : simple-audio platform name
Can you explain why you'd need the platform name in the DT? Doesn't the phandle always uniquely identify it? The example doesn't use this property.
Ahh yes, this simple-audio supports both phandle and name matching for compatibility. example showed phandle matching only.
I think the DT binding should only support phandle-based resolution. Name-based resolution would be quite odd for a device tree binding.
+- simple-audio,cpu,controller : phandle for CPU DAI +- simple-audio,cpu,dai,name : simple-audio CPU DAI name
It'd be a bit more typical of device-tree to have a single property that defines both the controller and any properties of the controller at once, e.g. something like:
simple-audio,cpu-interface = <&codec_phandle AK4648_I2S_ITF_A>;
where we assume something like:
#define AK4648_I2S_ITF_A 0 // Interface A's ID
That would remove the need to put string names into the DT.
Hmm... this "name" is required on ASoC matching... Especially, "codec dai name" is must item.
Should I modify ASoC itself ?
When I was thinking about a more generic DT binding for audio, quite a while ago, I certainly was planning to have each CODEC expose some kind of "of_xlate" function that could prase the integer interface ID in device tree, and convert it to a string name for internal use by ASoC.
+simple-audio,xxx,dai,clock-gating
- "continuous"
- "gated"
Don't you need to use the common clock bindings to define which clock to gate? Or, is the I2S/... node's binding supposed to provide that information?
I guess it is dependent on SoC/board. No ?
OK, I guess if this is I2S bus clock rather than I2S module clock, then this is fine as-is. Not all I2S controllers can implement this though.
Hi Stephen, Mark
Thank you for your checking
Rename that simple-audio,dma-controller perhaps? "platform" is a word specific to ASoC, and the bindings really should be generic across OSs.
(snip)
I still don't understand why the ASoC platform has to be exposed in device tree; it seems like something completely internal to the ASoC driver. Take a look at the Tegra ASoC DT bindings; the platform isn't in DT at all there.
OK, I checked Tegra sounds, and it is using same device pointer for platform and cpu. My FSI is same style. But I wonder is this normal style ? >> Mark If it is very normal style, I can remove "platform" from simple-audio.
Thank you
Ahh yes, this simple-audio supports both phandle and name matching for compatibility. example showed phandle matching only.
I think the DT binding should only support phandle-based resolution. Name-based resolution would be quite odd for a device tree binding.
I see. I will remove name-base matching from simple-audio
Best regards --- Kuninori Morimoto
Hi Mark, Stephen, and all
These patches add snd_soc_of_parse_daifmt() and simple-card DT support
Kuninori Morimoto (2): ASoC: add snd_soc_of_parse_daifmt() for DeviceTree ASoC: simple-card: add Device Tree support
.../devicetree/bindings/sound/simple-card.txt | 77 +++++++++++++ include/sound/soc.h | 2 + sound/soc/generic/simple-card.c | 108 +++++++++++++++++- sound/soc/soc-core.c | 115 ++++++++++++++++++++ 4 files changed, 297 insertions(+), 5 deletions(-)
Could you please teach me current status about these patches ?
Best regards --- Kuninori Morimoto
participants (6)
-
Bard Shen
-
Daniel Mack
-
Kuninori Morimoto
-
Lars-Peter Clausen
-
Mark Brown
-
Stephen Warren