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: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> Signed-off-by: Mark Brown <broonie@linaro.org>
This commit is contained in:
parent
cdaa3cdfb4
commit
3337744ac4
|
@ -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,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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,154 @@
|
|||
/*
|
||||
* 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);
|
||||
}
|
|
@ -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()
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue