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,