Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ca9e54c6 authored by Mark Brown's avatar Mark Brown
Browse files

Merge remote-tracking branch 'asoc/topic/rcar' into asoc-next

parents 980aac20 90e8e50f
Loading
Loading
Loading
Loading
+96 −0
Original line number Original line Diff line number Diff line
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 −0
Original line number Original line Diff line number Diff line
@@ -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,
int rsnd_adg_probe(struct platform_device *pdev,
		   const struct rsnd_of_data *of_data,
		   struct rsnd_priv *priv)
		   struct rsnd_priv *priv)
{
{
	struct rsnd_adg *adg;
	struct rsnd_adg *adg;
+119 −3
Original line number Original line Diff line number Diff line
@@ -100,6 +100,21 @@
#define RSND_RATES SNDRV_PCM_RATE_8000_96000
#define RSND_RATES SNDRV_PCM_RATE_8000_96000
#define RSND_FMTS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE)
#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
 *	rsnd_platform functions
 */
 */
@@ -620,7 +635,92 @@ static int rsnd_path_init(struct rsnd_priv *priv,
	return ret;
	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,
static int rsnd_dai_probe(struct platform_device *pdev,
			  const struct rsnd_of_data *of_data,
			  struct rsnd_priv *priv)
			  struct rsnd_priv *priv)
{
{
	struct snd_soc_dai_driver *drv;
	struct snd_soc_dai_driver *drv;
@@ -628,13 +728,16 @@ static int rsnd_dai_probe(struct platform_device *pdev,
	struct rsnd_dai *rdai;
	struct rsnd_dai *rdai;
	struct rsnd_mod *pmod, *cmod;
	struct rsnd_mod *pmod, *cmod;
	struct device *dev = rsnd_priv_to_dev(priv);
	struct device *dev = rsnd_priv_to_dev(priv);
	int dai_nr = info->dai_info_nr;
	int dai_nr;
	int i;
	int i;


	rsnd_of_parse_dai(pdev, of_data, priv);

	/*
	/*
	 * dai_nr should be set via dai_info_nr,
	 * dai_nr should be set via dai_info_nr,
	 * but allow it to keeping compatible
	 * but allow it to keeping compatible
	 */
	 */
	dai_nr = info->dai_info_nr;
	if (!dai_nr) {
	if (!dai_nr) {
		/* get max dai nr */
		/* get max dai nr */
		for (dai_nr = 0; dai_nr < 32; dai_nr++) {
		for (dai_nr = 0; dai_nr < 32; dai_nr++) {
@@ -802,7 +905,10 @@ static int rsnd_probe(struct platform_device *pdev)
	struct rsnd_priv *priv;
	struct rsnd_priv *priv;
	struct device *dev = &pdev->dev;
	struct device *dev = &pdev->dev;
	struct rsnd_dai *rdai;
	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,
	int (*probe_func[])(struct platform_device *pdev,
			    const struct rsnd_of_data *of_data,
			    struct rsnd_priv *priv) = {
			    struct rsnd_priv *priv) = {
		rsnd_gen_probe,
		rsnd_gen_probe,
		rsnd_ssi_probe,
		rsnd_ssi_probe,
@@ -812,7 +918,16 @@ static int rsnd_probe(struct platform_device *pdev)
	};
	};
	int ret, i;
	int ret, i;


	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;
		info = pdev->dev.platform_data;
	}

	if (!info) {
	if (!info) {
		dev_err(dev, "driver needs R-Car sound information\n");
		dev_err(dev, "driver needs R-Car sound information\n");
		return -ENODEV;
		return -ENODEV;
@@ -835,7 +950,7 @@ static int rsnd_probe(struct platform_device *pdev)
	 *	init each module
	 *	init each module
	 */
	 */
	for (i = 0; i < ARRAY_SIZE(probe_func); i++) {
	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)
		if (ret)
			return ret;
			return ret;
	}
	}
@@ -903,6 +1018,7 @@ static int rsnd_remove(struct platform_device *pdev)
static struct platform_driver rsnd_driver = {
static struct platform_driver rsnd_driver = {
	.driver	= {
	.driver	= {
		.name	= "rcar_sound",
		.name	= "rcar_sound",
		.of_match_table = rsnd_of_match,
	},
	},
	.probe		= rsnd_probe,
	.probe		= rsnd_probe,
	.remove		= rsnd_remove,
	.remove		= rsnd_remove,
+15 −0
Original line number Original line Diff line number Diff line
@@ -359,13 +359,28 @@ static int rsnd_gen1_probe(struct platform_device *pdev,
/*
/*
 *		Gen
 *		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,
int rsnd_gen_probe(struct platform_device *pdev,
		   const struct rsnd_of_data *of_data,
		   struct rsnd_priv *priv)
		   struct rsnd_priv *priv)
{
{
	struct device *dev = rsnd_priv_to_dev(priv);
	struct device *dev = rsnd_priv_to_dev(priv);
	struct rsnd_gen *gen;
	struct rsnd_gen *gen;
	int ret;
	int ret;


	rsnd_of_parse_gen(pdev, of_data, priv);

	gen = devm_kzalloc(dev, sizeof(*gen), GFP_KERNEL);
	gen = devm_kzalloc(dev, sizeof(*gen), GFP_KERNEL);
	if (!gen) {
	if (!gen) {
		dev_err(dev, "GEN allocate failed\n");
		dev_err(dev, "GEN allocate failed\n");
+11 −0
Original line number Original line Diff line number Diff line
@@ -17,6 +17,8 @@
#include <linux/io.h>
#include <linux/io.h>
#include <linux/list.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/sh_dma.h>
#include <linux/sh_dma.h>
#include <linux/workqueue.h>
#include <linux/workqueue.h>
#include <sound/rcar_snd.h>
#include <sound/rcar_snd.h>
@@ -113,6 +115,7 @@ enum rsnd_reg {
#define RSND_REG_SRCOUT_TIMSEL4		RSND_REG_SHARE18
#define RSND_REG_SRCOUT_TIMSEL4		RSND_REG_SHARE18
#define RSND_REG_AUDIO_CLK_SEL2		RSND_REG_SHARE19
#define RSND_REG_AUDIO_CLK_SEL2		RSND_REG_SHARE19


struct rsnd_of_data;
struct rsnd_priv;
struct rsnd_priv;
struct rsnd_mod;
struct rsnd_mod;
struct rsnd_dai;
struct rsnd_dai;
@@ -260,6 +263,7 @@ int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional);
 *	R-Car Gen1/Gen2
 *	R-Car Gen1/Gen2
 */
 */
int rsnd_gen_probe(struct platform_device *pdev,
int rsnd_gen_probe(struct platform_device *pdev,
		   const struct rsnd_of_data *of_data,
		   struct rsnd_priv *priv);
		   struct rsnd_priv *priv);
void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv,
void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv,
			       struct rsnd_mod *mod,
			       struct rsnd_mod *mod,
@@ -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_stop(struct rsnd_mod *mod);
int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate);
int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate);
int rsnd_adg_probe(struct platform_device *pdev,
int rsnd_adg_probe(struct platform_device *pdev,
		   const struct rsnd_of_data *of_data,
		   struct rsnd_priv *priv);
		   struct rsnd_priv *priv);
int rsnd_adg_set_convert_clk_gen1(struct rsnd_priv *priv,
int rsnd_adg_set_convert_clk_gen1(struct rsnd_priv *priv,
				  struct rsnd_mod *mod,
				  struct rsnd_mod *mod,
@@ -290,6 +295,10 @@ int rsnd_adg_set_convert_timing_gen2(struct rsnd_mod *mod,
/*
/*
 *	R-Car sound priv
 *	R-Car sound priv
 */
 */
struct rsnd_of_data {
	u32 flags;
};

struct rsnd_priv {
struct rsnd_priv {


	struct device *dev;
	struct device *dev;
@@ -348,6 +357,7 @@ struct rsnd_priv {
 *	R-Car SRC
 *	R-Car SRC
 */
 */
int rsnd_src_probe(struct platform_device *pdev,
int rsnd_src_probe(struct platform_device *pdev,
		   const struct rsnd_of_data *of_data,
		   struct rsnd_priv *priv);
		   struct rsnd_priv *priv);
struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id);
struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id);
unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv,
unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv,
@@ -366,6 +376,7 @@ int rsnd_src_enable_ssi_irq(struct rsnd_mod *ssi_mod,
 *	R-Car SSI
 *	R-Car SSI
 */
 */
int rsnd_ssi_probe(struct platform_device *pdev,
int rsnd_ssi_probe(struct platform_device *pdev,
		   const struct rsnd_of_data *of_data,
		   struct rsnd_priv *priv);
		   struct rsnd_priv *priv);
struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id);
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,
struct rsnd_mod *rsnd_ssi_mod_get_frm_dai(struct rsnd_priv *priv,
Loading