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

Commit 3337744a authored by Kuninori Morimoto's avatar Kuninori Morimoto Committed by Mark Brown
Browse files

ASoC: add Renesas R-Car Generation feature



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: default avatarKuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Signed-off-by: default avatarMark Brown <broonie@linaro.org>
parent cdaa3cdf
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -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;
+1 −1
Original line number Diff line number Diff line
snd-soc-rcar-objs	:= core.o
snd-soc-rcar-objs	:= core.o gen.o
obj-$(CONFIG_SND_SOC_RCAR)	+= snd-soc-rcar.o
+57 −1
Original line number Diff line number Diff line
@@ -107,6 +107,50 @@
	 priv->info->func(param))


/*
 *	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
 */
@@ -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;
}
+154 −0
Original line number Diff line number Diff line
/*
 * Renesas R-Car Gen1 SRU/SSI support
 *
 * Copyright (C) 2013 Renesas Solutions Corp.
 * Kuninori Morimoto <kuninori.morimoto.gx@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);
}
+47 −0
Original line number Diff line number Diff line
@@ -27,11 +27,35 @@
 * 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
 */
@@ -116,6 +140,24 @@ int rsnd_dai_is_play(struct rsnd_dai *rdai, struct rsnd_dai_stream *io);
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
 */
@@ -125,6 +167,11 @@ struct rsnd_priv {
	struct rcar_snd_info *info;
	spinlock_t lock;

	/*
	 * below value will be filled on rsnd_gen_probe()
	 */
	void *gen;

	/*
	 * below value will be filled on rsnd_dai_probe()
	 */