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,