Skip to content

Commit

Permalink
ASoC: rsnd: add DeviceTree support
Browse files Browse the repository at this point in the history
Support for loading the Renesas R-Car sound driver via DeviceTree.

Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Signed-off-by: Mark Brown <broonie@linaro.org>
  • Loading branch information
Kuninori Morimoto authored and Mark Brown committed Mar 21, 2014
1 parent ba9c949 commit 90e8e50
Show file tree
Hide file tree
Showing 7 changed files with 334 additions and 3 deletions.
96 changes: 96 additions & 0 deletions Documentation/devicetree/bindings/sound/renesas,rsnd.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
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:
- 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-gen2";
reg = <0 0xec500000 0 0x1000>, /* SCU */
<0 0xec5a0000 0 0x100>, /* ADG */
<0 0xec540000 0 0x1000>, /* SSIU */
<0 0xec541000 0 0x1280>; /* SSI */

rcar_sound,src {
src0: src@0 { };
src1: src@1 { };
src2: src@2 { };
src3: src@3 { };
src4: src@4 { };
src5: src@5 { };
src6: src@6 { };
src7: src@7 { };
src8: src@8 { };
src9: src@9 { };
};

rcar_sound,ssi {
ssi0: ssi@0 {
interrupts = <0 370 IRQ_TYPE_LEVEL_HIGH>;
};
ssi1: ssi@1 {
interrupts = <0 371 IRQ_TYPE_LEVEL_HIGH>;
};
ssi2: ssi@2 {
interrupts = <0 372 IRQ_TYPE_LEVEL_HIGH>;
};
ssi3: ssi@3 {
interrupts = <0 373 IRQ_TYPE_LEVEL_HIGH>;
};
ssi4: ssi@4 {
interrupts = <0 374 IRQ_TYPE_LEVEL_HIGH>;
};
ssi5: ssi@5 {
interrupts = <0 375 IRQ_TYPE_LEVEL_HIGH>;
};
ssi6: ssi@6 {
interrupts = <0 376 IRQ_TYPE_LEVEL_HIGH>;
};
ssi7: ssi@7 {
interrupts = <0 377 IRQ_TYPE_LEVEL_HIGH>;
};
ssi8: ssi@8 {
interrupts = <0 378 IRQ_TYPE_LEVEL_HIGH>;
};
ssi9: ssi@9 {
interrupts = <0 379 IRQ_TYPE_LEVEL_HIGH>;
};
};

rcar_sound,dai {
dai0 {
playback = <&ssi5 &src5>;
capture = <&ssi6>;
};
dai1 {
playback = <&ssi3>;
};
dai2 {
capture = <&ssi4>;
};
dai3 {
playback = <&ssi7>;
};
dai4 {
capture = <&ssi8>;
};
};
};
1 change: 1 addition & 0 deletions sound/soc/sh/rcar/adg.c
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,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;
Expand Down
122 changes: 119 additions & 3 deletions sound/soc/sh/rcar/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand Down Expand Up @@ -620,21 +635,109 @@ static int rsnd_path_init(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 *src_node, *src_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, src_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");
src_node = of_get_child_by_name(dev->of_node, "rcar_sound,src");

#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(src);

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;
struct rcar_snd_info *info = rsnd_priv_to_info(priv);
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++) {
Expand Down Expand Up @@ -802,7 +905,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,
Expand All @@ -812,7 +918,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;
Expand All @@ -835,7 +950,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;
}
Expand Down Expand Up @@ -903,6 +1018,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,
Expand Down
15 changes: 15 additions & 0 deletions sound/soc/sh/rcar/gen.c
Original file line number Diff line number Diff line change
Expand Up @@ -359,13 +359,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");
Expand Down
11 changes: 11 additions & 0 deletions sound/soc/sh/rcar/rsnd.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
#include <linux/io.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/sh_dma.h>
#include <linux/workqueue.h>
#include <sound/rcar_snd.h>
Expand Down Expand Up @@ -113,6 +115,7 @@ enum rsnd_reg {
#define RSND_REG_SRCOUT_TIMSEL4 RSND_REG_SHARE18
#define RSND_REG_AUDIO_CLK_SEL2 RSND_REG_SHARE19

struct rsnd_of_data;
struct rsnd_priv;
struct rsnd_mod;
struct rsnd_dai;
Expand Down Expand Up @@ -260,6 +263,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 __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv,
struct rsnd_mod *mod,
Expand All @@ -273,6 +277,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);
int rsnd_adg_set_convert_clk_gen1(struct rsnd_priv *priv,
struct rsnd_mod *mod,
Expand All @@ -290,6 +295,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;
Expand Down Expand Up @@ -348,6 +357,7 @@ struct rsnd_priv {
* R-Car SRC
*/
int rsnd_src_probe(struct platform_device *pdev,
const struct rsnd_of_data *of_data,
struct rsnd_priv *priv);
struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id);
unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv,
Expand All @@ -366,6 +376,7 @@ int rsnd_src_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);
struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id);
struct rsnd_mod *rsnd_ssi_mod_get_frm_dai(struct rsnd_priv *priv,
Expand Down
Loading

0 comments on commit 90e8e50

Please sign in to comment.