/*
* Renesas R-Car SRU/SCU/SSIU/SSI support
*
* Copyright (C) 2013 Renesas Solutions Corp.
* Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
*
* Based on fsi.c
* Kuninori Morimoto <morimoto.kuninori@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.
*/
/*
* Renesas R-Car sound device structure
*
* Gen1
*
* SRU : Sound Routing Unit
* - SRC : Sampling Rate Converter
* - CMD
* - CTU : Channel Count Conversion Unit
* - MIX : Mixer
* - DVC : Digital Volume and Mute Function
* - SSI : Serial Sound Interface
*
* Gen2
*
* SCU : Sampling Rate Converter Unit
* - SRC : Sampling Rate Converter
* - CMD
* - CTU : Channel Count Conversion Unit
* - MIX : Mixer
* - DVC : Digital Volume and Mute Function
* SSIU : Serial Sound Interface Unit
* - SSI : Serial Sound Interface
*/
/*
* driver data Image
*
* rsnd_priv
* |
* | ** this depends on Gen1/Gen2
* |
* +- gen
* |
* | ** these depend on data path
* | ** gen and platform data control it
* |
* +- rdai[0]
* | | sru ssiu ssi
* | +- playback -> [mod] -> [mod] -> [mod] -> ...
* | |
* | | sru ssiu ssi
* | +- capture -> [mod] -> [mod] -> [mod] -> ...
* |
* +- rdai[1]
* | | sru ssiu ssi
* | +- playback -> [mod] -> [mod] -> [mod] -> ...
* | |
* | | sru ssiu ssi
* | +- capture -> [mod] -> [mod] -> [mod] -> ...
* ...
* |
* | ** these control ssi
* |
* +- ssi
* | |
* | +- ssi[0]
* | +- ssi[1]
* | +- ssi[2]
* | ...
* |
* | ** these control src
* |
* +- src
* |
* +- src[0]
* +- src[1]
* +- src[2]
* ...
*
*
* for_each_rsnd_dai(xx, priv, xx)
* rdai[0] => rdai[1] => rdai[2] => ...
*
* for_each_rsnd_mod(xx, rdai, xx)
* [mod] => [mod] => [mod] => ...
*
* rsnd_dai_call(xxx, fn )
* [mod]->fn() -> [mod]->fn() -> [mod]->fn()...
*
*/
#include <linux/pm_runtime.h>
#include "rsnd.h"
#define RSND_RATES SNDRV_PCM_RATE_8000_96000
#define RSND_FMTS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE)
static const struct rsnd_of_data rsnd_of_data_gen1 = {
.flags = RSND_GEN1,
};
static const struct rsnd_of_data rsnd_of_data_gen2 = {
.flags = RSND_GEN2,
};
static const 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
*/
#define rsnd_platform_call(priv, dai, func, param...) \
(!(priv->info->func) ? 0 : \
priv->info->func(param))
#define rsnd_is_enable_path(io, name) \
((io)->info ? (io)->info->name : NULL)
#define rsnd_info_id(priv, io, name) \
((io)->info->name - priv->info->name##_info)
/*
* rsnd_mod functions
*/
char *rsnd_mod_name(struct rsnd_mod *mod)
{
if (!mod || !mod->ops)
return "unknown";
return mod->ops->name;
}
struct dma_chan *rsnd_mod_dma_req(struct rsnd_dai_stream *io,
struct rsnd_mod *mod)
{
if (!mod || !mod->ops || !mod->ops->dma_req)
return NULL;
return mod->ops->dma_req(io, mod);
}
int rsnd_mod_init(struct rsnd_priv *priv,
struct rsnd_mod *mod,
struct rsnd_mod_ops *ops,
struct clk *clk,
enum rsnd_mod_type type,
int id)
{
int ret = clk_prepare(clk);
if (ret)
return ret;
mod->id = id;
mod->ops = ops;
mod->type = type;
mod->clk = clk;
mod->priv = priv;
return ret;
}
void rsnd_mod_quit(struct rsnd_mod *mod)
{
if (mod->clk)
clk_unprepare(mod->clk);
}
void rsnd_mod_interrupt(struct rsnd_mod *mod,
void