[alsa-devel] [PATCH 3/6 v2 resend] ASoC: add Renesas R-Car Generation feature

Kuninori Morimoto kuninori.morimoto.gx at renesas.com
Mon Jul 22 06:36:21 CEST 2013


Renesas R-Car series sound circuit consists of SSI and its peripheral.
But this peripheral circuit is different between
R-Car Generation1 (E1/M1/H1) and Generation2 (E2/M2/H2)
(Actually, there are many difference in Generation1 chips)

The main difference between Gen1 and Gen2 are
1) register offset, 2) data path

In order to control Gen1/Gen2 by same method,
this patch adds gen.c.

Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx at renesas.com>
---
v1 -> v2

 - checkpatch
 - rsnd_bset has dev_dbg()
 - removed unused gen2 functions

 include/sound/rcar_snd.h   |   10 +++
 sound/soc/sh/rcar/Makefile |    2 +-
 sound/soc/sh/rcar/core.c   |   58 ++++++++++++++++-
 sound/soc/sh/rcar/gen.c    |  154 ++++++++++++++++++++++++++++++++++++++++++++
 sound/soc/sh/rcar/rsnd.h   |   47 ++++++++++++++
 5 files changed, 269 insertions(+), 2 deletions(-)
 create mode 100644 sound/soc/sh/rcar/gen.c

diff --git a/include/sound/rcar_snd.h b/include/sound/rcar_snd.h
index 7272b2e..14942a8 100644
--- a/include/sound/rcar_snd.h
+++ b/include/sound/rcar_snd.h
@@ -22,6 +22,16 @@ struct rsnd_dai_platform_info {
 	int ssi_id_capture;
 };
 
+/*
+ * flags
+ *
+ * 0x0000000A
+ *
+ * A : generation
+ */
+#define RSND_GEN1	(1 << 0) /* fixme */
+#define RSND_GEN2	(2 << 0) /* fixme */
+
 struct rcar_snd_info {
 	u32 flags;
 	struct rsnd_dai_platform_info *dai_info;
diff --git a/sound/soc/sh/rcar/Makefile b/sound/soc/sh/rcar/Makefile
index cd8089f..b2d313b 100644
--- a/sound/soc/sh/rcar/Makefile
+++ b/sound/soc/sh/rcar/Makefile
@@ -1,2 +1,2 @@
-snd-soc-rcar-objs	:= core.o
+snd-soc-rcar-objs	:= core.o gen.o
 obj-$(CONFIG_SND_SOC_RCAR)	+= snd-soc-rcar.o
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
index a47fda2..bb8959f 100644
--- a/sound/soc/sh/rcar/core.c
+++ b/sound/soc/sh/rcar/core.c
@@ -108,6 +108,50 @@
 
 
 /*
+ *	basic function
+ */
+u32 rsnd_read(struct rsnd_priv *priv,
+	      struct rsnd_mod *mod, enum rsnd_reg reg)
+{
+	void __iomem *base = rsnd_gen_reg_get(priv, mod, reg);
+
+	BUG_ON(!base);
+
+	return ioread32(base);
+}
+
+void rsnd_write(struct rsnd_priv *priv,
+		struct rsnd_mod *mod,
+		enum rsnd_reg reg, u32 data)
+{
+	void __iomem *base = rsnd_gen_reg_get(priv, mod, reg);
+	struct device *dev = rsnd_priv_to_dev(priv);
+
+	BUG_ON(!base);
+
+	dev_dbg(dev, "w %p : %08x\n", base, data);
+
+	iowrite32(data, base);
+}
+
+void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod,
+	       enum rsnd_reg reg, u32 mask, u32 data)
+{
+	void __iomem *base = rsnd_gen_reg_get(priv, mod, reg);
+	struct device *dev = rsnd_priv_to_dev(priv);
+	u32 val;
+
+	BUG_ON(!base);
+
+	val = ioread32(base);
+	val &= ~mask;
+	val |= data & mask;
+	iowrite32(val, base);
+
+	dev_dbg(dev, "s %p : %08x\n", base, val);
+}
+
+/*
  *	rsnd_mod functions
  */
 char *rsnd_mod_name(struct rsnd_mod *mod)
@@ -289,6 +333,10 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
 		if (ret < 0)
 			goto dai_trigger_end;
 
+		ret = rsnd_gen_path_init(priv, rdai, io);
+		if (ret < 0)
+			goto dai_trigger_end;
+
 		ret = rsnd_dai_call(rdai, io, init);
 		if (ret < 0)
 			goto dai_trigger_end;
@@ -306,10 +354,13 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
 		if (ret < 0)
 			goto dai_trigger_end;
 
-		ret = rsnd_platform_call(priv, dai, stop, ssi_id);
+		ret = rsnd_gen_path_exit(priv, rdai, io);
 		if (ret < 0)
 			goto dai_trigger_end;
 
+		ret = rsnd_platform_call(priv, dai, stop, ssi_id);
+		if (ret < 0)
+			goto dai_trigger_end;
 		break;
 	default:
 		ret = -EINVAL;
@@ -572,6 +623,10 @@ static int rsnd_probe(struct platform_device *pdev)
 	/*
 	 *	init each module
 	 */
+	ret = rsnd_gen_probe(pdev, info, priv);
+	if (ret < 0)
+		return ret;
+
 	ret = rsnd_dai_probe(pdev, info, priv);
 	if (ret < 0)
 		return ret;
@@ -615,6 +670,7 @@ static int rsnd_remove(struct platform_device *pdev)
 	 *	remove each module
 	 */
 	rsnd_dai_remove(pdev, priv);
+	rsnd_gen_remove(pdev, priv);
 
 	return 0;
 }
diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c
new file mode 100644
index 0000000..ec67a79
--- /dev/null
+++ b/sound/soc/sh/rcar/gen.c
@@ -0,0 +1,154 @@
+/*
+ * Renesas R-Car Gen1 SRU/SSI support
+ *
+ * Copyright (C) 2013 Renesas Solutions Corp.
+ * Kuninori Morimoto <kuninori.morimoto.gx at renesas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include "rsnd.h"
+
+struct rsnd_gen_ops {
+	int (*path_init)(struct rsnd_priv *priv,
+			 struct rsnd_dai *rdai,
+			 struct rsnd_dai_stream *io);
+	int (*path_exit)(struct rsnd_priv *priv,
+			 struct rsnd_dai *rdai,
+			 struct rsnd_dai_stream *io);
+};
+
+struct rsnd_gen_reg_map {
+	int index;	/* -1 : not supported */
+	u32 offset_id;	/* offset of ssi0, ssi1, ssi2... */
+	u32 offset_adr;	/* offset of SSICR, SSISR, ... */
+};
+
+struct rsnd_gen {
+	void __iomem *base[RSND_BASE_MAX];
+
+	struct rsnd_gen_reg_map reg_map[RSND_REG_MAX];
+	struct rsnd_gen_ops *ops;
+};
+
+#define rsnd_priv_to_gen(p)	((struct rsnd_gen *)(p)->gen)
+
+#define rsnd_is_gen1(s)		((s)->info->flags & RSND_GEN1)
+#define rsnd_is_gen2(s)		((s)->info->flags & RSND_GEN2)
+
+/*
+ *		Gen2
+ *		will be filled in the future
+ */
+
+/*
+ *		Gen1
+ */
+static int rsnd_gen1_probe(struct platform_device *pdev,
+			   struct rcar_snd_info *info,
+			   struct rsnd_priv *priv)
+{
+	return 0;
+}
+
+static void rsnd_gen1_remove(struct platform_device *pdev,
+			     struct rsnd_priv *priv)
+{
+}
+
+/*
+ *		Gen
+ */
+int rsnd_gen_path_init(struct rsnd_priv *priv,
+		       struct rsnd_dai *rdai,
+		       struct rsnd_dai_stream *io)
+{
+	struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
+
+	return gen->ops->path_init(priv, rdai, io);
+}
+
+int rsnd_gen_path_exit(struct rsnd_priv *priv,
+		       struct rsnd_dai *rdai,
+		       struct rsnd_dai_stream *io)
+{
+	struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
+
+	return gen->ops->path_exit(priv, rdai, io);
+}
+
+void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv,
+			       struct rsnd_mod *mod,
+			       enum rsnd_reg reg)
+{
+	struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
+	struct device *dev = rsnd_priv_to_dev(priv);
+	int index;
+	u32 offset_id, offset_adr;
+
+	if (reg >= RSND_REG_MAX) {
+		dev_err(dev, "rsnd_reg reg error\n");
+		return NULL;
+	}
+
+	index		= gen->reg_map[reg].index;
+	offset_id	= gen->reg_map[reg].offset_id;
+	offset_adr	= gen->reg_map[reg].offset_adr;
+
+	if (index < 0) {
+		dev_err(dev, "unsupported reg access %d\n", reg);
+		return NULL;
+	}
+
+	if (offset_id && mod)
+		offset_id *= rsnd_mod_id(mod);
+
+	/*
+	 * index/offset were set on gen1/gen2
+	 */
+
+	return gen->base[index] + offset_id + offset_adr;
+}
+
+int rsnd_gen_probe(struct platform_device *pdev,
+		   struct rcar_snd_info *info,
+		   struct rsnd_priv *priv)
+{
+	struct device *dev = rsnd_priv_to_dev(priv);
+	struct rsnd_gen *gen;
+	int i;
+
+	gen = devm_kzalloc(dev, sizeof(*gen), GFP_KERNEL);
+	if (!gen) {
+		dev_err(dev, "GEN allocate failed\n");
+		return -ENOMEM;
+	}
+
+	priv->gen = gen;
+
+	/*
+	 * see
+	 *	rsnd_reg_get()
+	 *	rsnd_gen_probe()
+	 */
+	for (i = 0; i < RSND_REG_MAX; i++)
+		gen->reg_map[i].index = -1;
+
+	/*
+	 *	init each module
+	 */
+	if (rsnd_is_gen1(priv))
+		return rsnd_gen1_probe(pdev, info, priv);
+
+	dev_err(dev, "unknown generation R-Car sound device\n");
+
+	return -ENODEV;
+}
+
+void rsnd_gen_remove(struct platform_device *pdev,
+		     struct rsnd_priv *priv)
+{
+	if (rsnd_is_gen1(priv))
+		rsnd_gen1_remove(pdev, priv);
+}
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h
index 65d3835..8cc3641 100644
--- a/sound/soc/sh/rcar/rsnd.h
+++ b/sound/soc/sh/rcar/rsnd.h
@@ -27,12 +27,36 @@
  * This driver uses pseudo register in order to hide it.
  * see gen1/gen2 for detail
  */
+enum rsnd_reg {
+	RSND_REG_MAX,
+};
+
 struct rsnd_priv;
 struct rsnd_mod;
 struct rsnd_dai;
 struct rsnd_dai_stream;
 
 /*
+ *	R-Car basic functions
+ */
+#define rsnd_mod_read(m, r) \
+	rsnd_read(rsnd_mod_to_priv(m), m, RSND_REG_##r)
+#define rsnd_mod_write(m, r, d) \
+	rsnd_write(rsnd_mod_to_priv(m), m, RSND_REG_##r, d)
+#define rsnd_mod_bset(m, r, s, d) \
+	rsnd_bset(rsnd_mod_to_priv(m), m, RSND_REG_##r, s, d)
+
+#define rsnd_priv_read(p, r)		rsnd_read(p, NULL, RSND_REG_##r)
+#define rsnd_priv_write(p, r, d)	rsnd_write(p, NULL, RSND_REG_##r, d)
+#define rsnd_priv_bset(p, r, s, d)	rsnd_bset(p, NULL, RSND_REG_##r, s, d)
+
+u32 rsnd_read(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg);
+void rsnd_write(struct rsnd_priv *priv, struct rsnd_mod *mod,
+		enum rsnd_reg reg, u32 data);
+void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg,
+		    u32 mask, u32 data);
+
+/*
  *	R-Car sound mod
  */
 
@@ -117,6 +141,24 @@ void rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int cnt);
 int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional);
 
 /*
+ *	R-Car Gen1/Gen2
+ */
+int rsnd_gen_probe(struct platform_device *pdev,
+		   struct rcar_snd_info *info,
+		   struct rsnd_priv *priv);
+void rsnd_gen_remove(struct platform_device *pdev,
+		     struct rsnd_priv *priv);
+int rsnd_gen_path_init(struct rsnd_priv *priv,
+		       struct rsnd_dai *rdai,
+		       struct rsnd_dai_stream *io);
+int rsnd_gen_path_exit(struct rsnd_priv *priv,
+		       struct rsnd_dai *rdai,
+		       struct rsnd_dai_stream *io);
+void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv,
+			       struct rsnd_mod *mod,
+			       enum rsnd_reg reg);
+
+/*
  *	R-Car sound priv
  */
 struct rsnd_priv {
@@ -126,6 +168,11 @@ struct rsnd_priv {
 	spinlock_t lock;
 
 	/*
+	 * below value will be filled on rsnd_gen_probe()
+	 */
+	void *gen;
+
+	/*
 	 * below value will be filled on rsnd_dai_probe()
 	 */
 	struct snd_soc_dai_driver *daidrv;
-- 
1.7.9.5



More information about the Alsa-devel mailing list