From patchwork Tue Feb 25 06:17:10 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kuninori Morimoto X-Patchwork-Id: 3713081 Return-Path: X-Original-To: patchwork-alsa-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id E0FAEBF13A for ; Tue, 25 Feb 2014 06:29:17 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 83BD4201BF for ; Tue, 25 Feb 2014 06:29:16 +0000 (UTC) Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) by mail.kernel.org (Postfix) with ESMTP id 989B320108 for ; Tue, 25 Feb 2014 06:29:14 +0000 (UTC) Received: by alsa0.perex.cz (Postfix, from userid 1000) id A07D826566F; Tue, 25 Feb 2014 07:29:13 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Spam-Level: X-Spam-Status: No, score=-1.8 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, T_DKIM_INVALID, UNPARSEABLE_RELAY autolearn=no version=3.3.1 Received: from alsa0.perex.cz (localhost [IPv6:::1]) by alsa0.perex.cz (Postfix) with ESMTP id 4D903265616; Tue, 25 Feb 2014 07:20:33 +0100 (CET) X-Original-To: alsa-devel@alsa-project.org Delivered-To: alsa-devel@alsa-project.org Received: by alsa0.perex.cz (Postfix, from userid 1000) id 5E04B265616; Tue, 25 Feb 2014 07:20:31 +0100 (CET) Received: from mail-pd0-f171.google.com (mail-pd0-f171.google.com [209.85.192.171]) by alsa0.perex.cz (Postfix) with ESMTP id 68A32265619 for ; Tue, 25 Feb 2014 07:17:12 +0100 (CET) Received: by mail-pd0-f171.google.com with SMTP id r10so1825586pdi.30 for ; Mon, 24 Feb 2014 22:17:11 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=date:message-id:from:subject:user-agent:to:cc:in-reply-to :references:mime-version:content-type; bh=NozRJ8ojVqugRUQHDP/vakYxsTQ+hKmG9Qp6jBGPqKk=; b=bs9isJIRXd/eCsBSQcGZUv59MdqaHASQZlJNfO0AMguSyP3U5mMCHVt6CSbNtLVPlg 0kyNuqkwrr7hzDVa+g09IPyxhFgGcduUTAi1r5ZoZPVWWB/h3sPQC6DV0OCX61TNL5yq S0CWKbFKyN/qTJoKRWRMQuS5Ud5HUWV6DbEB/ihfYatYmE9qcTzEPaOAZAtA/lwID5Wu 3sYV5ifV1J5W5wrNBjx8u7aR2r7YjSbKXMfCsMICfCRoJAh8DxKgyMWwtt6KnYnFilx/ pyHvyMOw4hLYihh5GonvaO7TbMNyx3KzzSjBO98Hi49sgrS6vE6Jy9BpvGbQBcUssWS9 Fthw== X-Received: by 10.66.150.69 with SMTP id ug5mr29911862pab.55.1393309031443; Mon, 24 Feb 2014 22:17:11 -0800 (PST) Received: from morimoto-Dell-XPS420.gmail.com (49.14.32.202.bf.2iij.net. [202.32.14.49]) by mx.google.com with ESMTPSA id vx10sm135947570pac.17.2014.02.24.22.17.09 for (version=TLSv1.2 cipher=RC4-SHA bits=128/128); Mon, 24 Feb 2014 22:17:10 -0800 (PST) Date: Mon, 24 Feb 2014 22:17:10 -0800 (PST) Message-ID: <87lhwz7m3g.wl%kuninori.morimoto.gx@gmail.com> From: Kuninori Morimoto User-Agent: Wanderlust/2.14.0 Emacs/23.3 Mule/6.0 To: Mark Brown In-Reply-To: <87d2ib90t9.wl%kuninori.morimoto.gx@gmail.com> References: <87d2ib90t9.wl%kuninori.morimoto.gx@gmail.com> MIME-Version: 1.0 (generated by SEMI 1.14.6 - "Maruoka") Cc: Linux-ALSA , Simon , Liam Girdwood , Kuninori Morimoto Subject: [alsa-devel] [PATCH 19/19] ASoC: rsnd: add DeviceTree support X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: alsa-devel-bounces@alsa-project.org X-Virus-Scanned: ClamAV using ClamSMTP From: Kuninori Morimoto Support for loading the Renesas R-Car sound driver via DeviceTree. Signed-off-by: Kuninori Morimoto --- .../devicetree/bindings/sound/renesas,rsnd.txt | 101 ++++++++++++++++ sound/soc/sh/rcar/adg.c | 1 + sound/soc/sh/rcar/core.c | 122 +++++++++++++++++++- sound/soc/sh/rcar/gen.c | 15 +++ sound/soc/sh/rcar/rsnd.h | 11 ++ sound/soc/sh/rcar/scu.c | 36 ++++++ sound/soc/sh/rcar/ssi.c | 56 +++++++++ 7 files changed, 339 insertions(+), 3 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/renesas,rsnd.txt diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt new file mode 100644 index 0000000..47e3989 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt @@ -0,0 +1,101 @@ +Renesas R-Car sound + +Required properties: +- compatible : "renesas,rcar_sound-gen1" if generation1 + "renesas,rcar_sound-gen2" if generation2 +- reg : Should contain the register physical address. + required register is + SRU/ADG/SSI if generation1 + SRU/ADG/SSIU/SSI if generation2 +- rcar_sound,ssi : SSI subnode +- rcar_sound,scu : SCU subnode +- rcar_sound,dai : DAI subnode + +SSI subnode properties: +- interrupt-parent : Should contain SSI interrup parent +- interrupts : Should contain SSI interrupt for PIO transfer +- shared-pin : if shared clock pin + +DAI subnode properties: +- playback : list of playback modules +- capture : list of capture modules + +Example: + +rcar_sound: rcar_sound@0xffd90000 { + #sound-dai-cells = <1>; + compatible = "renesas,rcar_sound"; + reg = <0xffd90000 0x1000>, /* SRU */ + <0xfffe0000 0x24>, /* ADG */ + <0xffd91000 0x1240>; /* SSI */ + + rcar_sound,scu { + scu0: scu@0 { }; + scu1: scu@1 { }; + scu2: scu@2 { }; + scu3: scu@3 { }; + scu4: scu@4 { }; + scu5: scu@5 { }; + scu6: scu@6 { }; + scu7: scu@7 { }; + scu8: scu@8 { }; + }; + + rcar_sound,ssi { + ssi0: ssi@0 { + interrupt-parent = <&gic>; + interrupts = <0 101 0x4>; + }; + ssi1: ssi@1 { + interrupt-parent = <&gic>; + interrupts = <0 101 0x4>; + }; + ssi2: ssi@2 { + interrupt-parent = <&gic>; + interrupts = <0 101 0x4>; + }; + ssi3: ssi@3 { + interrupt-parent = <&gic>; + interrupts = <0 101 0x4>; + }; + ssi4: ssi@4 { + interrupt-parent = <&gic>; + interrupts = <0 101 0x4>; + }; + ssi5: ssi@5 { + interrupt-parent = <&gic>; + interrupts = <0 102 0x4>; + }; + ssi6: ssi@6 { + interrupt-parent = <&gic>; + interrupts = <0 102 0x4>; + }; + ssi7: ssi@7 { + interrupt-parent = <&gic>; + interrupts = <0 102 0x4>; + }; + ssi8: ssi@8 { + interrupt-parent = <&gic>; + interrupts = <0 102 0x4>; + }; + }; + + rcar_sound,dai { + dai0 { + playback = <&ssi5 &scu5>; + capture = <&ssi6 &scu6>; + }; + dai1 { + playback = <&ssi3>; + }; + dai2 { + capture = <&ssi4>; + }; + dai3 { + playback = <&ssi7>; + }; + dai4 { + capture = <&ssi8>; + }; + }; +}; diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index 69d9394..5a897701 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -391,6 +391,7 @@ static void rsnd_adg_ssi_clk_init(struct rsnd_priv *priv, struct rsnd_adg *adg) } int rsnd_adg_probe(struct platform_device *pdev, + const struct rsnd_of_data *of_data, struct rsnd_priv *priv) { struct rsnd_adg *adg; diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 7ad63c7..9b648c3 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -100,6 +100,21 @@ #define RSND_RATES SNDRV_PCM_RATE_8000_96000 #define RSND_FMTS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE) +static struct rsnd_of_data rsnd_of_data_gen1 = { + .flags = RSND_GEN1, +}; + +static struct rsnd_of_data rsnd_of_data_gen2 = { + .flags = RSND_GEN2, +}; + +static struct of_device_id rsnd_of_match[] = { + { .compatible = "renesas,rcar_sound-gen1", .data = &rsnd_of_data_gen1 }, + { .compatible = "renesas,rcar_sound-gen2", .data = &rsnd_of_data_gen2 }, + {}, +}; +MODULE_DEVICE_TABLE(of, rsnd_of_match); + /* * rsnd_platform functions */ @@ -656,7 +671,92 @@ static int rsnd_path_exit(struct rsnd_priv *priv, return ret; } +static void rsnd_of_parse_dai(struct platform_device *pdev, + const struct rsnd_of_data *of_data, + struct rsnd_priv *priv) +{ + struct device_node *dai_node, *dai_np; + struct device_node *ssi_node, *ssi_np; + struct device_node *scu_node, *scu_np; + struct device_node *playback, *capture; + struct rsnd_dai_platform_info *dai_info; + struct rcar_snd_info *info = rsnd_priv_to_info(priv); + struct device *dev = &pdev->dev; + int nr, i; + int dai_i, ssi_i, scu_i; + + if (!of_data) + return; + + dai_node = of_get_child_by_name(dev->of_node, "rcar_sound,dai"); + if (!dai_node) + return; + + nr = of_get_child_count(dai_node); + if (!nr) + return; + + dai_info = devm_kzalloc(dev, + sizeof(struct rsnd_dai_platform_info) * nr, + GFP_KERNEL); + if (!dai_info) { + dev_err(dev, "dai info allocation error\n"); + return; + } + + info->dai_info_nr = nr; + info->dai_info = dai_info; + + ssi_node = of_get_child_by_name(dev->of_node, "rcar_sound,ssi"); + scu_node = of_get_child_by_name(dev->of_node, "rcar_sound,scu"); + +#define mod_parse(name) \ +if (name##_node) { \ + struct rsnd_##name##_platform_info *name##_info; \ + \ + name##_i = 0; \ + for_each_child_of_node(name##_node, name##_np) { \ + name##_info = info->name##_info + name##_i; \ + \ + if (name##_np == playback) \ + dai_info->playback.name = name##_info; \ + if (name##_np == capture) \ + dai_info->capture.name = name##_info; \ + \ + name##_i++; \ + } \ +} + + /* + * parse all dai + */ + dai_i = 0; + for_each_child_of_node(dai_node, dai_np) { + dai_info = info->dai_info + dai_i; + + for (i = 0;; i++) { + + playback = of_parse_phandle(dai_np, "playback", i); + capture = of_parse_phandle(dai_np, "capture", i); + + if (!playback && !capture) + break; + + mod_parse(ssi); + mod_parse(scu); + + if (playback) + of_node_put(playback); + if (capture) + of_node_put(capture); + } + + dai_i++; + } +} + static int rsnd_dai_probe(struct platform_device *pdev, + const struct rsnd_of_data *of_data, struct rsnd_priv *priv) { struct snd_soc_dai_driver *drv; @@ -664,13 +764,16 @@ static int rsnd_dai_probe(struct platform_device *pdev, struct rsnd_dai *rdai; struct rsnd_mod *pmod, *cmod; struct device *dev = rsnd_priv_to_dev(priv); - int dai_nr = info->dai_info_nr; + int dai_nr; int i; + rsnd_of_parse_dai(pdev, of_data, priv); + /* * dai_nr should be set via dai_info_nr, * but allow it to keeping compatible */ + dai_nr = info->dai_info_nr; if (!dai_nr) { /* get max dai nr */ for (dai_nr = 0; dai_nr < 32; dai_nr++) { @@ -851,7 +954,10 @@ static int rsnd_probe(struct platform_device *pdev) struct rsnd_priv *priv; struct device *dev = &pdev->dev; struct rsnd_dai *rdai; + const struct of_device_id *of_id = of_match_device(rsnd_of_match, dev); + const struct rsnd_of_data *of_data; int (*probe_func[])(struct platform_device *pdev, + const struct rsnd_of_data *of_data, struct rsnd_priv *priv) = { rsnd_gen_probe, rsnd_ssi_probe, @@ -861,7 +967,16 @@ static int rsnd_probe(struct platform_device *pdev) }; int ret, i; - info = pdev->dev.platform_data; + info = NULL; + of_data = NULL; + if (of_id) { + info = devm_kzalloc(&pdev->dev, + sizeof(struct rcar_snd_info), GFP_KERNEL); + of_data = of_id->data; + } else { + info = pdev->dev.platform_data; + } + if (!info) { dev_err(dev, "driver needs R-Car sound information\n"); return -ENODEV; @@ -884,7 +999,7 @@ static int rsnd_probe(struct platform_device *pdev) * init each module */ for (i = 0; i < ARRAY_SIZE(probe_func); i++) { - ret = probe_func[i](pdev, priv); + ret = probe_func[i](pdev, of_data, priv); if (ret) return ret; } @@ -961,6 +1076,7 @@ static int rsnd_remove(struct platform_device *pdev) static struct platform_driver rsnd_driver = { .driver = { .name = "rcar_sound", + .of_match_table = rsnd_of_match, }, .probe = rsnd_probe, .remove = rsnd_remove, diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 4f2c1d0..8794711 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -360,13 +360,28 @@ static int rsnd_gen1_probe(struct platform_device *pdev, /* * Gen */ +static void rsnd_of_parse_gen(struct platform_device *pdev, + const struct rsnd_of_data *of_data, + struct rsnd_priv *priv) +{ + struct rcar_snd_info *info = priv->info; + + if (!of_data) + return; + + info->flags = of_data->flags; +} + int rsnd_gen_probe(struct platform_device *pdev, + const struct rsnd_of_data *of_data, struct rsnd_priv *priv) { struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_gen *gen; int ret; + rsnd_of_parse_gen(pdev, of_data, priv); + gen = devm_kzalloc(dev, sizeof(*gen), GFP_KERNEL); if (!gen) { dev_err(dev, "GEN allocate failed\n"); diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index ec6c58e..0e317e2 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -17,6 +17,8 @@ #include #include #include +#include +#include #include #include #include @@ -89,6 +91,7 @@ enum rsnd_reg { RSND_REG_MAX, }; +struct rsnd_of_data; struct rsnd_priv; struct rsnd_mod; struct rsnd_dai; @@ -236,6 +239,7 @@ int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional); * R-Car Gen1/Gen2 */ int rsnd_gen_probe(struct platform_device *pdev, + const struct rsnd_of_data *of_data, struct rsnd_priv *priv); void rsnd_gen_remove(struct platform_device *pdev, struct rsnd_priv *priv); @@ -251,6 +255,7 @@ void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv, int rsnd_adg_ssi_clk_stop(struct rsnd_mod *mod); int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate); int rsnd_adg_probe(struct platform_device *pdev, + const struct rsnd_of_data *of_data, struct rsnd_priv *priv); void rsnd_adg_remove(struct platform_device *pdev, struct rsnd_priv *priv); @@ -270,6 +275,10 @@ int rsnd_adg_set_convert_timing_gen2(struct rsnd_mod *mod, /* * R-Car sound priv */ +struct rsnd_of_data { + u32 flags; +}; + struct rsnd_priv { struct device *dev; @@ -328,6 +337,7 @@ struct rsnd_priv { * R-Car SCU */ int rsnd_scu_probe(struct platform_device *pdev, + const struct rsnd_of_data *of_data, struct rsnd_priv *priv); void rsnd_scu_remove(struct platform_device *pdev, struct rsnd_priv *priv); @@ -348,6 +358,7 @@ int rsnd_scu_enable_ssi_irq(struct rsnd_mod *ssi_mod, * R-Car SSI */ int rsnd_ssi_probe(struct platform_device *pdev, + const struct rsnd_of_data *of_data, struct rsnd_priv *priv); void rsnd_ssi_remove(struct platform_device *pdev, struct rsnd_priv *priv); diff --git a/sound/soc/sh/rcar/scu.c b/sound/soc/sh/rcar/scu.c index 40250ac..219ab27 100644 --- a/sound/soc/sh/rcar/scu.c +++ b/sound/soc/sh/rcar/scu.c @@ -628,7 +628,41 @@ struct rsnd_mod *rsnd_scu_mod_get(struct rsnd_priv *priv, int id) return &((struct rsnd_scu *)(priv->scu) + id)->mod; } +static void rsnd_of_parse_scu(struct platform_device *pdev, + const struct rsnd_of_data *of_data, + struct rsnd_priv *priv) +{ + struct device_node *scu_node; + struct rcar_snd_info *info = rsnd_priv_to_info(priv); + struct rsnd_scu_platform_info *scu_info; + struct device *dev = &pdev->dev; + int nr; + + if (!of_data) + return; + + scu_node = of_get_child_by_name(dev->of_node, "rcar_sound,scu"); + if (!scu_node) + return; + + nr = of_get_child_count(scu_node); + if (!nr) + return; + + scu_info = devm_kzalloc(dev, + sizeof(struct rsnd_scu_platform_info) * nr, + GFP_KERNEL); + if (!scu_info) { + dev_err(dev, "scu info allocation error\n"); + return; + } + + info->scu_info = scu_info; + info->scu_info_nr = nr; +} + int rsnd_scu_probe(struct platform_device *pdev, + const struct rsnd_of_data *of_data, struct rsnd_priv *priv) { struct rcar_snd_info *info = rsnd_priv_to_info(priv); @@ -639,6 +673,8 @@ int rsnd_scu_probe(struct platform_device *pdev, char name[RSND_SCU_NAME_SIZE]; int i, nr; + rsnd_of_parse_scu(pdev, of_data, priv); + /* * init SCU */ diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 0f3eeac..c9beef8 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -588,7 +588,61 @@ static void rsnd_ssi_parent_clk_setup(struct rsnd_priv *priv, struct rsnd_ssi *s } } + +static void rsnd_of_parse_ssi(struct platform_device *pdev, + const struct rsnd_of_data *of_data, + struct rsnd_priv *priv) +{ + struct device_node *node; + struct device_node *np; + struct rsnd_ssi_platform_info *ssi_info; + struct rcar_snd_info *info = rsnd_priv_to_info(priv); + struct device *dev = &pdev->dev; + int nr, i; + + if (!of_data) + return; + + node = of_get_child_by_name(dev->of_node, "rcar_sound,ssi"); + if (!node) + return; + + nr = of_get_child_count(node); + if (!nr) + return; + + ssi_info = devm_kzalloc(dev, + sizeof(struct rsnd_ssi_platform_info) * nr, + GFP_KERNEL); + if (!ssi_info) { + dev_err(dev, "ssi info allocation error\n"); + return; + } + + info->ssi_info = ssi_info; + info->ssi_info_nr = nr; + + i = -1; + for_each_child_of_node(node, np) { + i++; + + ssi_info = info->ssi_info + i; + + /* + * pin settings + */ + if (of_get_property(np, "shared-pin", NULL)) + ssi_info->flags |= RSND_SSI_CLK_PIN_SHARE; + + /* + * irq + */ + ssi_info->pio_irq = irq_of_parse_and_map(np, 0); + } +} + int rsnd_ssi_probe(struct platform_device *pdev, + const struct rsnd_of_data *of_data, struct rsnd_priv *priv) { struct rcar_snd_info *info = rsnd_priv_to_info(priv); @@ -600,6 +654,8 @@ int rsnd_ssi_probe(struct platform_device *pdev, char name[RSND_SSI_NAME_SIZE]; int i, nr; + rsnd_of_parse_ssi(pdev, of_data, priv); + /* * init SSI */