Merge remote-tracking branches 'asoc/topic/pxa', 'asoc/topic/qcom', 'asoc/topic/rcar', 'asoc/topic/rk3036' and 'asoc/topic/rockchip' into asoc-next
Este commit está contenido en:
@@ -36,7 +36,6 @@ config SND_SOC_SH4_SIU
|
||||
|
||||
config SND_SOC_RCAR
|
||||
tristate "R-Car series SRU/SCU/SSIU/SSI support"
|
||||
depends on DMA_OF
|
||||
depends on COMMON_CLK
|
||||
select SND_SIMPLE_CARD
|
||||
select REGMAP_MMIO
|
||||
|
@@ -1,4 +1,4 @@
|
||||
snd-soc-rcar-objs := core.o gen.o dma.o adg.o ssi.o src.o ctu.o mix.o dvc.o
|
||||
snd-soc-rcar-objs := core.o gen.o dma.o adg.o ssi.o ssiu.o src.o ctu.o mix.o dvc.o cmd.o
|
||||
obj-$(CONFIG_SND_SOC_RCAR) += snd-soc-rcar.o
|
||||
|
||||
snd-soc-rsrc-card-objs := rsrc-card.o
|
||||
|
@@ -68,8 +68,8 @@ static u32 rsnd_adg_calculate_rbgx(unsigned long div)
|
||||
|
||||
static u32 rsnd_adg_ssi_ws_timing_gen2(struct rsnd_dai_stream *io)
|
||||
{
|
||||
struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io);
|
||||
int id = rsnd_mod_id(mod);
|
||||
struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io);
|
||||
int id = rsnd_mod_id(ssi_mod);
|
||||
int ws = id;
|
||||
|
||||
if (rsnd_ssi_is_pin_sharing(io)) {
|
||||
@@ -90,13 +90,13 @@ static u32 rsnd_adg_ssi_ws_timing_gen2(struct rsnd_dai_stream *io)
|
||||
return (0x6 + ws) << 8;
|
||||
}
|
||||
|
||||
int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *mod,
|
||||
int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *cmd_mod,
|
||||
struct rsnd_dai_stream *io)
|
||||
{
|
||||
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
|
||||
struct rsnd_priv *priv = rsnd_mod_to_priv(cmd_mod);
|
||||
struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
|
||||
struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
|
||||
int id = rsnd_mod_id(mod);
|
||||
int id = rsnd_mod_id(cmd_mod);
|
||||
int shift = (id % 2) ? 16 : 0;
|
||||
u32 mask, val;
|
||||
|
||||
@@ -242,68 +242,6 @@ int rsnd_adg_set_convert_timing_gen2(struct rsnd_mod *src_mod,
|
||||
return rsnd_adg_set_src_timsel_gen2(src_mod, io, val);
|
||||
}
|
||||
|
||||
int rsnd_adg_set_convert_clk_gen1(struct rsnd_priv *priv,
|
||||
struct rsnd_mod *mod,
|
||||
unsigned int src_rate,
|
||||
unsigned int dst_rate)
|
||||
{
|
||||
struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
|
||||
struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
|
||||
struct device *dev = rsnd_priv_to_dev(priv);
|
||||
int idx, sel, div, shift;
|
||||
u32 mask, val;
|
||||
int id = rsnd_mod_id(mod);
|
||||
unsigned int sel_rate [] = {
|
||||
clk_get_rate(adg->clk[CLKA]), /* 000: CLKA */
|
||||
clk_get_rate(adg->clk[CLKB]), /* 001: CLKB */
|
||||
clk_get_rate(adg->clk[CLKC]), /* 010: CLKC */
|
||||
0, /* 011: MLBCLK (not used) */
|
||||
adg->rbga_rate_for_441khz, /* 100: RBGA */
|
||||
adg->rbgb_rate_for_48khz, /* 101: RBGB */
|
||||
};
|
||||
|
||||
/* find div (= 1/128, 1/256, 1/512, 1/1024, 1/2048 */
|
||||
for (sel = 0; sel < ARRAY_SIZE(sel_rate); sel++) {
|
||||
for (div = 128, idx = 0;
|
||||
div <= 2048;
|
||||
div *= 2, idx++) {
|
||||
if (src_rate == sel_rate[sel] / div) {
|
||||
val = (idx << 4) | sel;
|
||||
goto find_rate;
|
||||
}
|
||||
}
|
||||
}
|
||||
dev_err(dev, "can't find convert src clk\n");
|
||||
return -EINVAL;
|
||||
|
||||
find_rate:
|
||||
shift = (id % 4) * 8;
|
||||
mask = 0xFF << shift;
|
||||
val = val << shift;
|
||||
|
||||
dev_dbg(dev, "adg convert src clk = %02x\n", val);
|
||||
|
||||
switch (id / 4) {
|
||||
case 0:
|
||||
rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL3, mask, val);
|
||||
break;
|
||||
case 1:
|
||||
rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL4, mask, val);
|
||||
break;
|
||||
case 2:
|
||||
rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL5, mask, val);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Gen1 doesn't need dst_rate settings,
|
||||
* since it uses SSI WS pin.
|
||||
* see also rsnd_src_set_route_if_gen1()
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rsnd_adg_set_ssi_clk(struct rsnd_mod *ssi_mod, u32 val)
|
||||
{
|
||||
struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
|
||||
@@ -337,20 +275,16 @@ static void rsnd_adg_set_ssi_clk(struct rsnd_mod *ssi_mod, u32 val)
|
||||
}
|
||||
}
|
||||
|
||||
int rsnd_adg_ssi_clk_stop(struct rsnd_mod *mod)
|
||||
int rsnd_adg_ssi_clk_stop(struct rsnd_mod *ssi_mod)
|
||||
{
|
||||
/*
|
||||
* "mod" = "ssi" here.
|
||||
* we can get "ssi id" from mod
|
||||
*/
|
||||
rsnd_adg_set_ssi_clk(mod, 0);
|
||||
rsnd_adg_set_ssi_clk(ssi_mod, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate)
|
||||
int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate)
|
||||
{
|
||||
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
|
||||
struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
|
||||
struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
|
||||
struct device *dev = rsnd_priv_to_dev(priv);
|
||||
struct clk *clk;
|
||||
@@ -394,14 +328,10 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate)
|
||||
|
||||
found_clock:
|
||||
|
||||
/*
|
||||
* This "mod" = "ssi" here.
|
||||
* we can get "ssi id" from mod
|
||||
*/
|
||||
rsnd_adg_set_ssi_clk(mod, data);
|
||||
rsnd_adg_set_ssi_clk(ssi_mod, data);
|
||||
|
||||
dev_dbg(dev, "ADG: %s[%d] selects 0x%x for %d\n",
|
||||
rsnd_mod_name(mod), rsnd_mod_id(mod),
|
||||
rsnd_mod_name(ssi_mod), rsnd_mod_id(ssi_mod),
|
||||
data, rate);
|
||||
|
||||
return 0;
|
||||
@@ -418,15 +348,20 @@ static void rsnd_adg_get_clkin(struct rsnd_priv *priv,
|
||||
[CLKC] = "clk_c",
|
||||
[CLKI] = "clk_i",
|
||||
};
|
||||
int i;
|
||||
int i, ret;
|
||||
|
||||
for (i = 0; i < CLKMAX; i++) {
|
||||
clk = devm_clk_get(dev, clk_name[i]);
|
||||
adg->clk[i] = IS_ERR(clk) ? NULL : clk;
|
||||
}
|
||||
|
||||
for_each_rsnd_clk(clk, adg, i)
|
||||
for_each_rsnd_clk(clk, adg, i) {
|
||||
ret = clk_prepare_enable(clk);
|
||||
if (ret < 0)
|
||||
dev_warn(dev, "can't use clk %d\n", i);
|
||||
|
||||
dev_dbg(dev, "clk %d : %p : %ld\n", i, clk, clk_get_rate(clk));
|
||||
}
|
||||
}
|
||||
|
||||
static void rsnd_adg_get_clkout(struct rsnd_priv *priv,
|
||||
@@ -437,7 +372,7 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv,
|
||||
struct device *dev = rsnd_priv_to_dev(priv);
|
||||
struct device_node *np = dev->of_node;
|
||||
u32 ckr, rbgx, rbga, rbgb;
|
||||
u32 rate, req_rate, div;
|
||||
u32 rate, req_rate = 0, div;
|
||||
uint32_t count = 0;
|
||||
unsigned long req_48kHz_rate, req_441kHz_rate;
|
||||
int i;
|
||||
@@ -572,9 +507,7 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv,
|
||||
ckr, rbga, rbgb);
|
||||
}
|
||||
|
||||
int rsnd_adg_probe(struct platform_device *pdev,
|
||||
const struct rsnd_of_data *of_data,
|
||||
struct rsnd_priv *priv)
|
||||
int rsnd_adg_probe(struct rsnd_priv *priv)
|
||||
{
|
||||
struct rsnd_adg *adg;
|
||||
struct device *dev = rsnd_priv_to_dev(priv);
|
||||
@@ -600,3 +533,14 @@ int rsnd_adg_probe(struct platform_device *pdev,
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rsnd_adg_remove(struct rsnd_priv *priv)
|
||||
{
|
||||
struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
|
||||
struct clk *clk;
|
||||
int i;
|
||||
|
||||
for_each_rsnd_clk(clk, adg, i) {
|
||||
clk_disable_unprepare(clk);
|
||||
}
|
||||
}
|
||||
|
171
sound/soc/sh/rcar/cmd.c
Archivo normal
171
sound/soc/sh/rcar/cmd.c
Archivo normal
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* Renesas R-Car CMD support
|
||||
*
|
||||
* Copyright (C) 2015 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_cmd {
|
||||
struct rsnd_mod mod;
|
||||
};
|
||||
|
||||
#define CMD_NAME "cmd"
|
||||
|
||||
#define rsnd_cmd_nr(priv) ((priv)->cmd_nr)
|
||||
#define for_each_rsnd_cmd(pos, priv, i) \
|
||||
for ((i) = 0; \
|
||||
((i) < rsnd_cmd_nr(priv)) && \
|
||||
((pos) = (struct rsnd_cmd *)(priv)->cmd + i); \
|
||||
i++)
|
||||
|
||||
static int rsnd_cmd_init(struct rsnd_mod *mod,
|
||||
struct rsnd_dai_stream *io,
|
||||
struct rsnd_priv *priv)
|
||||
{
|
||||
struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io);
|
||||
struct rsnd_mod *mix = rsnd_io_to_mod_mix(io);
|
||||
struct rsnd_mod *src = rsnd_io_to_mod_src(io);
|
||||
struct device *dev = rsnd_priv_to_dev(priv);
|
||||
u32 data;
|
||||
|
||||
if (!mix && !dvc)
|
||||
return 0;
|
||||
|
||||
if (mix) {
|
||||
struct rsnd_dai *rdai;
|
||||
int i;
|
||||
u32 path[] = {
|
||||
[0] = 0,
|
||||
[1] = 1 << 0,
|
||||
[2] = 0,
|
||||
[3] = 0,
|
||||
[4] = 0,
|
||||
[5] = 1 << 8
|
||||
};
|
||||
|
||||
/*
|
||||
* it is assuming that integrater is well understanding about
|
||||
* data path. Here doesn't check impossible connection,
|
||||
* like src2 + src5
|
||||
*/
|
||||
data = 0;
|
||||
for_each_rsnd_dai(rdai, priv, i) {
|
||||
io = &rdai->playback;
|
||||
if (mix == rsnd_io_to_mod_mix(io))
|
||||
data |= path[rsnd_mod_id(src)];
|
||||
|
||||
io = &rdai->capture;
|
||||
if (mix == rsnd_io_to_mod_mix(io))
|
||||
data |= path[rsnd_mod_id(src)];
|
||||
}
|
||||
|
||||
} else {
|
||||
u32 path[] = {
|
||||
[0] = 0x30000,
|
||||
[1] = 0x30001,
|
||||
[2] = 0x40000,
|
||||
[3] = 0x10000,
|
||||
[4] = 0x20000,
|
||||
[5] = 0x40100
|
||||
};
|
||||
|
||||
data = path[rsnd_mod_id(src)];
|
||||
}
|
||||
|
||||
dev_dbg(dev, "ctu/mix path = 0x%08x", data);
|
||||
|
||||
rsnd_mod_write(mod, CMD_ROUTE_SLCT, data);
|
||||
rsnd_mod_write(mod, CMD_BUSIF_DALIGN, rsnd_get_dalign(mod, io));
|
||||
|
||||
rsnd_adg_set_cmd_timsel_gen2(mod, io);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rsnd_cmd_start(struct rsnd_mod *mod,
|
||||
struct rsnd_dai_stream *io,
|
||||
struct rsnd_priv *priv)
|
||||
{
|
||||
rsnd_mod_write(mod, CMD_CTRL, 0x10);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rsnd_cmd_stop(struct rsnd_mod *mod,
|
||||
struct rsnd_dai_stream *io,
|
||||
struct rsnd_priv *priv)
|
||||
{
|
||||
rsnd_mod_write(mod, CMD_CTRL, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct rsnd_mod_ops rsnd_cmd_ops = {
|
||||
.name = CMD_NAME,
|
||||
.init = rsnd_cmd_init,
|
||||
.start = rsnd_cmd_start,
|
||||
.stop = rsnd_cmd_stop,
|
||||
};
|
||||
|
||||
int rsnd_cmd_attach(struct rsnd_dai_stream *io, int id)
|
||||
{
|
||||
struct rsnd_priv *priv = rsnd_io_to_priv(io);
|
||||
struct rsnd_mod *mod = rsnd_cmd_mod_get(priv, id);
|
||||
|
||||
return rsnd_dai_connect(mod, io, mod->type);
|
||||
}
|
||||
|
||||
struct rsnd_mod *rsnd_cmd_mod_get(struct rsnd_priv *priv, int id)
|
||||
{
|
||||
if (WARN_ON(id < 0 || id >= rsnd_cmd_nr(priv)))
|
||||
id = 0;
|
||||
|
||||
return rsnd_mod_get((struct rsnd_cmd *)(priv->cmd) + id);
|
||||
}
|
||||
|
||||
int rsnd_cmd_probe(struct rsnd_priv *priv)
|
||||
{
|
||||
struct device *dev = rsnd_priv_to_dev(priv);
|
||||
struct rsnd_cmd *cmd;
|
||||
int i, nr, ret;
|
||||
|
||||
/* This driver doesn't support Gen1 at this point */
|
||||
if (rsnd_is_gen1(priv))
|
||||
return 0;
|
||||
|
||||
/* same number as DVC */
|
||||
nr = priv->dvc_nr;
|
||||
if (!nr)
|
||||
return 0;
|
||||
|
||||
cmd = devm_kzalloc(dev, sizeof(*cmd) * nr, GFP_KERNEL);
|
||||
if (!cmd)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->cmd_nr = nr;
|
||||
priv->cmd = cmd;
|
||||
|
||||
for_each_rsnd_cmd(cmd, priv, i) {
|
||||
ret = rsnd_mod_init(priv, rsnd_mod_get(cmd),
|
||||
&rsnd_cmd_ops, NULL, RSND_MOD_CMD, i);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rsnd_cmd_remove(struct rsnd_priv *priv)
|
||||
{
|
||||
struct rsnd_cmd *cmd;
|
||||
int i;
|
||||
|
||||
for_each_rsnd_cmd(cmd, priv, i) {
|
||||
rsnd_mod_quit(rsnd_mod_get(cmd));
|
||||
}
|
||||
}
|
@@ -99,34 +99,17 @@
|
||||
#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 },
|
||||
{ .compatible = "renesas,rcar_sound-gen3", .data = &rsnd_of_data_gen2 }, /* gen2 compatible */
|
||||
{ .compatible = "renesas,rcar_sound-gen1", .data = (void *)RSND_GEN1 },
|
||||
{ .compatible = "renesas,rcar_sound-gen2", .data = (void *)RSND_GEN2 },
|
||||
{ .compatible = "renesas,rcar_sound-gen3", .data = (void *)RSND_GEN2 }, /* gen2 compatible */
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, rsnd_of_match);
|
||||
|
||||
/*
|
||||
* rsnd_platform functions
|
||||
* rsnd_mod 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)
|
||||
|
||||
void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type)
|
||||
{
|
||||
if (mod->type != type) {
|
||||
@@ -138,9 +121,6 @@ void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* rsnd_mod functions
|
||||
*/
|
||||
char *rsnd_mod_name(struct rsnd_mod *mod)
|
||||
{
|
||||
if (!mod || !mod->ops)
|
||||
@@ -192,19 +172,16 @@ void rsnd_mod_interrupt(struct rsnd_mod *mod,
|
||||
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
|
||||
struct rsnd_dai_stream *io;
|
||||
struct rsnd_dai *rdai;
|
||||
int i, j;
|
||||
int i;
|
||||
|
||||
for_each_rsnd_dai(rdai, priv, j) {
|
||||
for_each_rsnd_dai(rdai, priv, i) {
|
||||
io = &rdai->playback;
|
||||
if (mod == io->mod[mod->type])
|
||||
callback(mod, io);
|
||||
|
||||
for (i = 0; i < RSND_MOD_MAX; i++) {
|
||||
io = &rdai->playback;
|
||||
if (mod == io->mod[i])
|
||||
callback(mod, io);
|
||||
|
||||
io = &rdai->capture;
|
||||
if (mod == io->mod[i])
|
||||
callback(mod, io);
|
||||
}
|
||||
io = &rdai->capture;
|
||||
if (mod == io->mod[mod->type])
|
||||
callback(mod, io);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,6 +191,43 @@ int rsnd_io_is_working(struct rsnd_dai_stream *io)
|
||||
return !!io->substream;
|
||||
}
|
||||
|
||||
void rsnd_set_slot(struct rsnd_dai *rdai,
|
||||
int slots, int num)
|
||||
{
|
||||
rdai->slots = slots;
|
||||
rdai->slots_num = num;
|
||||
}
|
||||
|
||||
int rsnd_get_slot(struct rsnd_dai_stream *io)
|
||||
{
|
||||
struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
|
||||
|
||||
return rdai->slots;
|
||||
}
|
||||
|
||||
int rsnd_get_slot_num(struct rsnd_dai_stream *io)
|
||||
{
|
||||
struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
|
||||
|
||||
return rdai->slots_num;
|
||||
}
|
||||
|
||||
int rsnd_get_slot_width(struct rsnd_dai_stream *io)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
|
||||
int chan = runtime->channels;
|
||||
|
||||
/* Multi channel Mode */
|
||||
if (rsnd_ssi_multi_slaves(io))
|
||||
chan /= rsnd_get_slot_num(io);
|
||||
|
||||
/* TDM Extend Mode needs 8ch */
|
||||
if (chan == 6)
|
||||
chan = 8;
|
||||
|
||||
return chan;
|
||||
}
|
||||
|
||||
/*
|
||||
* ADINR function
|
||||
*/
|
||||
@@ -222,21 +236,17 @@ u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
|
||||
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
|
||||
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
|
||||
struct device *dev = rsnd_priv_to_dev(priv);
|
||||
u32 adinr = runtime->channels;
|
||||
|
||||
switch (runtime->sample_bits) {
|
||||
case 16:
|
||||
adinr |= (8 << 16);
|
||||
break;
|
||||
return 8 << 16;
|
||||
case 32:
|
||||
adinr |= (0 << 16);
|
||||
break;
|
||||
default:
|
||||
dev_warn(dev, "not supported sample bits\n");
|
||||
return 0;
|
||||
return 0 << 16;
|
||||
}
|
||||
|
||||
return adinr;
|
||||
dev_warn(dev, "not supported sample bits\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 rsnd_get_adinr_chan(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
|
||||
@@ -267,13 +277,22 @@ u32 rsnd_get_adinr_chan(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
|
||||
*/
|
||||
u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
|
||||
{
|
||||
struct rsnd_mod *src = rsnd_io_to_mod_src(io);
|
||||
struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io);
|
||||
struct rsnd_mod *target = src ? src : ssi;
|
||||
struct rsnd_mod *target;
|
||||
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
|
||||
u32 val = 0x76543210;
|
||||
u32 mask = ~0;
|
||||
|
||||
if (rsnd_io_is_play(io)) {
|
||||
struct rsnd_mod *src = rsnd_io_to_mod_src(io);
|
||||
|
||||
target = src ? src : ssi;
|
||||
} else {
|
||||
struct rsnd_mod *cmd = rsnd_io_to_mod_cmd(io);
|
||||
|
||||
target = cmd ? cmd : ssi;
|
||||
}
|
||||
|
||||
mask <<= runtime->channels * 4;
|
||||
val = val & mask;
|
||||
|
||||
@@ -300,20 +319,22 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
|
||||
/*
|
||||
* rsnd_dai functions
|
||||
*/
|
||||
#define rsnd_mod_call(mod, io, func, param...) \
|
||||
#define rsnd_mod_call(idx, io, func, param...) \
|
||||
({ \
|
||||
struct rsnd_priv *priv = rsnd_mod_to_priv(mod); \
|
||||
struct rsnd_mod *mod = (io)->mod[idx]; \
|
||||
struct device *dev = rsnd_priv_to_dev(priv); \
|
||||
u32 *status = (io)->mod_status + idx; \
|
||||
u32 mask = 0xF << __rsnd_mod_shift_##func; \
|
||||
u8 val = (mod->status >> __rsnd_mod_shift_##func) & 0xF; \
|
||||
u8 val = (*status >> __rsnd_mod_shift_##func) & 0xF; \
|
||||
u8 add = ((val + __rsnd_mod_add_##func) & 0xF); \
|
||||
int ret = 0; \
|
||||
int call = (val == __rsnd_mod_call_##func) && (mod)->ops->func; \
|
||||
mod->status = (mod->status & ~mask) + \
|
||||
*status = (*status & ~mask) + \
|
||||
(add << __rsnd_mod_shift_##func); \
|
||||
dev_dbg(dev, "%s[%d]\t0x%08x %s\n", \
|
||||
rsnd_mod_name(mod), rsnd_mod_id(mod), \
|
||||
mod->status, call ? #func : ""); \
|
||||
*status, call ? #func : ""); \
|
||||
if (call) \
|
||||
ret = (mod)->ops->func(mod, io, param); \
|
||||
ret; \
|
||||
@@ -327,13 +348,14 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
|
||||
mod = (io)->mod[i]; \
|
||||
if (!mod) \
|
||||
continue; \
|
||||
ret |= rsnd_mod_call(mod, io, fn, param); \
|
||||
ret |= rsnd_mod_call(i, io, fn, param); \
|
||||
} \
|
||||
ret; \
|
||||
})
|
||||
|
||||
static int rsnd_dai_connect(struct rsnd_mod *mod,
|
||||
struct rsnd_dai_stream *io)
|
||||
int rsnd_dai_connect(struct rsnd_mod *mod,
|
||||
struct rsnd_dai_stream *io,
|
||||
enum rsnd_mod_type type)
|
||||
{
|
||||
struct rsnd_priv *priv;
|
||||
struct device *dev;
|
||||
@@ -341,10 +363,13 @@ static int rsnd_dai_connect(struct rsnd_mod *mod,
|
||||
if (!mod)
|
||||
return -EIO;
|
||||
|
||||
if (io->mod[type])
|
||||
return -EINVAL;
|
||||
|
||||
priv = rsnd_mod_to_priv(mod);
|
||||
dev = rsnd_priv_to_dev(priv);
|
||||
|
||||
io->mod[mod->type] = mod;
|
||||
io->mod[type] = mod;
|
||||
|
||||
dev_dbg(dev, "%s[%d] is connected to io (%s)\n",
|
||||
rsnd_mod_name(mod), rsnd_mod_id(mod),
|
||||
@@ -354,9 +379,10 @@ static int rsnd_dai_connect(struct rsnd_mod *mod,
|
||||
}
|
||||
|
||||
static void rsnd_dai_disconnect(struct rsnd_mod *mod,
|
||||
struct rsnd_dai_stream *io)
|
||||
struct rsnd_dai_stream *io,
|
||||
enum rsnd_mod_type type)
|
||||
{
|
||||
io->mod[mod->type] = NULL;
|
||||
io->mod[type] = NULL;
|
||||
}
|
||||
|
||||
struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id)
|
||||
@@ -469,7 +495,6 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
|
||||
struct rsnd_priv *priv = rsnd_dai_to_priv(dai);
|
||||
struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
|
||||
struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
|
||||
int ssi_id = rsnd_mod_id(rsnd_io_to_mod_ssi(io));
|
||||
int ret;
|
||||
unsigned long flags;
|
||||
|
||||
@@ -479,10 +504,6 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
rsnd_dai_stream_init(io, substream);
|
||||
|
||||
ret = rsnd_platform_call(priv, dai, start, ssi_id);
|
||||
if (ret < 0)
|
||||
goto dai_trigger_end;
|
||||
|
||||
ret = rsnd_dai_call(init, io, priv);
|
||||
if (ret < 0)
|
||||
goto dai_trigger_end;
|
||||
@@ -496,8 +517,6 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
|
||||
|
||||
ret |= rsnd_dai_call(quit, io, priv);
|
||||
|
||||
ret |= rsnd_platform_call(priv, dai, stop, ssi_id);
|
||||
|
||||
rsnd_dai_stream_quit(io);
|
||||
break;
|
||||
default:
|
||||
@@ -567,332 +586,157 @@ static int rsnd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai,
|
||||
u32 tx_mask, u32 rx_mask,
|
||||
int slots, int slot_width)
|
||||
{
|
||||
struct rsnd_priv *priv = rsnd_dai_to_priv(dai);
|
||||
struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
|
||||
struct device *dev = rsnd_priv_to_dev(priv);
|
||||
|
||||
switch (slots) {
|
||||
case 6:
|
||||
/* TDM Extend Mode */
|
||||
rsnd_set_slot(rdai, slots, 1);
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "unsupported TDM slots (%d)\n", slots);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_soc_dai_ops rsnd_soc_dai_ops = {
|
||||
.trigger = rsnd_soc_dai_trigger,
|
||||
.set_fmt = rsnd_soc_dai_set_fmt,
|
||||
.set_tdm_slot = rsnd_soc_set_dai_tdm_slot,
|
||||
};
|
||||
|
||||
#define rsnd_path_add(priv, io, type) \
|
||||
({ \
|
||||
struct rsnd_mod *mod; \
|
||||
int ret = 0; \
|
||||
int id = -1; \
|
||||
\
|
||||
if (rsnd_is_enable_path(io, type)) { \
|
||||
id = rsnd_info_id(priv, io, type); \
|
||||
if (id >= 0) { \
|
||||
mod = rsnd_##type##_mod_get(priv, id); \
|
||||
ret = rsnd_dai_connect(mod, io); \
|
||||
} \
|
||||
} \
|
||||
ret; \
|
||||
})
|
||||
|
||||
#define rsnd_path_remove(priv, io, type) \
|
||||
{ \
|
||||
struct rsnd_mod *mod; \
|
||||
int id = -1; \
|
||||
\
|
||||
if (rsnd_is_enable_path(io, type)) { \
|
||||
id = rsnd_info_id(priv, io, type); \
|
||||
if (id >= 0) { \
|
||||
mod = rsnd_##type##_mod_get(priv, id); \
|
||||
rsnd_dai_disconnect(mod, io); \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
void rsnd_path_parse(struct rsnd_priv *priv,
|
||||
struct rsnd_dai_stream *io)
|
||||
void rsnd_parse_connect_common(struct rsnd_dai *rdai,
|
||||
struct rsnd_mod* (*mod_get)(struct rsnd_priv *priv, int id),
|
||||
struct device_node *node,
|
||||
struct device_node *playback,
|
||||
struct device_node *capture)
|
||||
{
|
||||
struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io);
|
||||
struct rsnd_mod *mix = rsnd_io_to_mod_mix(io);
|
||||
struct rsnd_mod *src = rsnd_io_to_mod_src(io);
|
||||
struct rsnd_mod *cmd;
|
||||
struct device *dev = rsnd_priv_to_dev(priv);
|
||||
u32 data;
|
||||
struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
|
||||
struct device_node *np;
|
||||
struct rsnd_mod *mod;
|
||||
int i;
|
||||
|
||||
/* Gen1 is not supported */
|
||||
if (rsnd_is_gen1(priv))
|
||||
if (!node)
|
||||
return;
|
||||
|
||||
if (!mix && !dvc)
|
||||
return;
|
||||
|
||||
if (mix) {
|
||||
struct rsnd_dai *rdai;
|
||||
int i;
|
||||
u32 path[] = {
|
||||
[0] = 0,
|
||||
[1] = 1 << 0,
|
||||
[2] = 0,
|
||||
[3] = 0,
|
||||
[4] = 0,
|
||||
[5] = 1 << 8
|
||||
};
|
||||
|
||||
/*
|
||||
* it is assuming that integrater is well understanding about
|
||||
* data path. Here doesn't check impossible connection,
|
||||
* like src2 + src5
|
||||
*/
|
||||
data = 0;
|
||||
for_each_rsnd_dai(rdai, priv, i) {
|
||||
io = &rdai->playback;
|
||||
if (mix == rsnd_io_to_mod_mix(io))
|
||||
data |= path[rsnd_mod_id(src)];
|
||||
|
||||
io = &rdai->capture;
|
||||
if (mix == rsnd_io_to_mod_mix(io))
|
||||
data |= path[rsnd_mod_id(src)];
|
||||
}
|
||||
|
||||
/*
|
||||
* We can't use ctu = rsnd_io_ctu() here.
|
||||
* Since, ID of dvc/mix are 0 or 1 (= same as CMD number)
|
||||
* but ctu IDs are 0 - 7 (= CTU00 - CTU13)
|
||||
*/
|
||||
cmd = mix;
|
||||
} else {
|
||||
u32 path[] = {
|
||||
[0] = 0x30000,
|
||||
[1] = 0x30001,
|
||||
[2] = 0x40000,
|
||||
[3] = 0x10000,
|
||||
[4] = 0x20000,
|
||||
[5] = 0x40100
|
||||
};
|
||||
|
||||
data = path[rsnd_mod_id(src)];
|
||||
|
||||
cmd = dvc;
|
||||
i = 0;
|
||||
for_each_child_of_node(node, np) {
|
||||
mod = mod_get(priv, i);
|
||||
if (np == playback)
|
||||
rsnd_dai_connect(mod, &rdai->playback, mod->type);
|
||||
if (np == capture)
|
||||
rsnd_dai_connect(mod, &rdai->capture, mod->type);
|
||||
i++;
|
||||
}
|
||||
|
||||
dev_dbg(dev, "ctu/mix path = 0x%08x", data);
|
||||
|
||||
rsnd_mod_write(cmd, CMD_ROUTE_SLCT, data);
|
||||
|
||||
rsnd_mod_write(cmd, CMD_CTRL, 0x10);
|
||||
of_node_put(node);
|
||||
}
|
||||
|
||||
static int rsnd_path_init(struct rsnd_priv *priv,
|
||||
struct rsnd_dai *rdai,
|
||||
struct rsnd_dai_stream *io)
|
||||
static int rsnd_dai_probe(struct rsnd_priv *priv)
|
||||
{
|
||||
struct device_node *dai_node;
|
||||
struct device_node *dai_np;
|
||||
struct device_node *playback, *capture;
|
||||
struct rsnd_dai_stream *io_playback;
|
||||
struct rsnd_dai_stream *io_capture;
|
||||
struct snd_soc_dai_driver *rdrv, *drv;
|
||||
struct rsnd_dai *rdai;
|
||||
struct device *dev = rsnd_priv_to_dev(priv);
|
||||
int nr, dai_i, io_i;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Gen1 is created by SRU/SSI, and this SRU is base module of
|
||||
* Gen2's SCU/SSIU/SSI. (Gen2 SCU/SSIU came from SRU)
|
||||
*
|
||||
* Easy image is..
|
||||
* Gen1 SRU = Gen2 SCU + SSIU + etc
|
||||
*
|
||||
* Gen2 SCU path is very flexible, but, Gen1 SRU (SCU parts) is
|
||||
* using fixed path.
|
||||
*/
|
||||
|
||||
/* SSI */
|
||||
ret = rsnd_path_add(priv, io, ssi);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* SRC */
|
||||
ret = rsnd_path_add(priv, io, src);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* CTU */
|
||||
ret = rsnd_path_add(priv, io, ctu);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* MIX */
|
||||
ret = rsnd_path_add(priv, io, mix);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* DVC */
|
||||
ret = rsnd_path_add(priv, io, dvc);
|
||||
if (ret < 0)
|
||||
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 *ctu_node, *ctu_np;
|
||||
struct device_node *mix_node, *mix_np;
|
||||
struct device_node *dvc_node, *dvc_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, ctu_i, mix_i, dvc_i;
|
||||
|
||||
if (!of_data)
|
||||
return;
|
||||
|
||||
dai_node = of_get_child_by_name(dev->of_node, "rcar_sound,dai");
|
||||
if (!dai_node)
|
||||
return;
|
||||
|
||||
dai_node = rsnd_dai_of_node(priv);
|
||||
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;
|
||||
if (!nr) {
|
||||
ret = -EINVAL;
|
||||
goto rsnd_dai_probe_done;
|
||||
}
|
||||
|
||||
info->dai_info_nr = nr;
|
||||
info->dai_info = dai_info;
|
||||
rdrv = devm_kzalloc(dev, sizeof(*rdrv) * nr, GFP_KERNEL);
|
||||
rdai = devm_kzalloc(dev, sizeof(*rdai) * nr, GFP_KERNEL);
|
||||
if (!rdrv || !rdai) {
|
||||
ret = -ENOMEM;
|
||||
goto rsnd_dai_probe_done;
|
||||
}
|
||||
|
||||
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");
|
||||
ctu_node = of_get_child_by_name(dev->of_node, "rcar_sound,ctu");
|
||||
mix_node = of_get_child_by_name(dev->of_node, "rcar_sound,mix");
|
||||
dvc_node = of_get_child_by_name(dev->of_node, "rcar_sound,dvc");
|
||||
|
||||
#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++; \
|
||||
} \
|
||||
}
|
||||
priv->rdai_nr = nr;
|
||||
priv->daidrv = rdrv;
|
||||
priv->rdai = rdai;
|
||||
|
||||
/*
|
||||
* parse all dai
|
||||
*/
|
||||
dai_i = 0;
|
||||
for_each_child_of_node(dai_node, dai_np) {
|
||||
dai_info = info->dai_info + dai_i;
|
||||
rdai = rsnd_rdai_get(priv, dai_i);
|
||||
drv = rdrv + dai_i;
|
||||
io_playback = &rdai->playback;
|
||||
io_capture = &rdai->capture;
|
||||
|
||||
for (i = 0;; i++) {
|
||||
snprintf(rdai->name, RSND_DAI_NAME_SIZE, "rsnd-dai.%d", dai_i);
|
||||
|
||||
playback = of_parse_phandle(dai_np, "playback", i);
|
||||
capture = of_parse_phandle(dai_np, "capture", i);
|
||||
rdai->priv = priv;
|
||||
drv->name = rdai->name;
|
||||
drv->ops = &rsnd_soc_dai_ops;
|
||||
|
||||
snprintf(rdai->playback.name, RSND_DAI_NAME_SIZE,
|
||||
"DAI%d Playback", dai_i);
|
||||
drv->playback.rates = RSND_RATES;
|
||||
drv->playback.formats = RSND_FMTS;
|
||||
drv->playback.channels_min = 2;
|
||||
drv->playback.channels_max = 6;
|
||||
drv->playback.stream_name = rdai->playback.name;
|
||||
|
||||
snprintf(rdai->capture.name, RSND_DAI_NAME_SIZE,
|
||||
"DAI%d Capture", dai_i);
|
||||
drv->capture.rates = RSND_RATES;
|
||||
drv->capture.formats = RSND_FMTS;
|
||||
drv->capture.channels_min = 2;
|
||||
drv->capture.channels_max = 6;
|
||||
drv->capture.stream_name = rdai->capture.name;
|
||||
|
||||
rdai->playback.rdai = rdai;
|
||||
rdai->capture.rdai = rdai;
|
||||
rsnd_set_slot(rdai, 2, 1); /* default */
|
||||
|
||||
for (io_i = 0;; io_i++) {
|
||||
playback = of_parse_phandle(dai_np, "playback", io_i);
|
||||
capture = of_parse_phandle(dai_np, "capture", io_i);
|
||||
|
||||
if (!playback && !capture)
|
||||
break;
|
||||
|
||||
mod_parse(ssi);
|
||||
mod_parse(src);
|
||||
mod_parse(ctu);
|
||||
mod_parse(mix);
|
||||
mod_parse(dvc);
|
||||
rsnd_parse_connect_ssi(rdai, playback, capture);
|
||||
rsnd_parse_connect_src(rdai, playback, capture);
|
||||
rsnd_parse_connect_ctu(rdai, playback, capture);
|
||||
rsnd_parse_connect_mix(rdai, playback, capture);
|
||||
rsnd_parse_connect_dvc(rdai, playback, capture);
|
||||
|
||||
of_node_put(playback);
|
||||
of_node_put(capture);
|
||||
}
|
||||
|
||||
dai_i++;
|
||||
}
|
||||
}
|
||||
|
||||
static int rsnd_dai_probe(struct platform_device *pdev,
|
||||
const struct rsnd_of_data *of_data,
|
||||
struct rsnd_priv *priv)
|
||||
{
|
||||
struct snd_soc_dai_driver *drv;
|
||||
struct rcar_snd_info *info = rsnd_priv_to_info(priv);
|
||||
struct rsnd_dai *rdai;
|
||||
struct rsnd_ssi_platform_info *pmod, *cmod;
|
||||
struct device *dev = rsnd_priv_to_dev(priv);
|
||||
int dai_nr;
|
||||
int i;
|
||||
|
||||
rsnd_of_parse_dai(pdev, of_data, priv);
|
||||
|
||||
dai_nr = info->dai_info_nr;
|
||||
if (!dai_nr) {
|
||||
dev_err(dev, "no dai\n");
|
||||
return -EIO;
|
||||
dev_dbg(dev, "%s (%s/%s)\n", rdai->name,
|
||||
rsnd_io_to_mod_ssi(io_playback) ? "play" : " -- ",
|
||||
rsnd_io_to_mod_ssi(io_capture) ? "capture" : " -- ");
|
||||
}
|
||||
|
||||
drv = devm_kzalloc(dev, sizeof(*drv) * dai_nr, GFP_KERNEL);
|
||||
rdai = devm_kzalloc(dev, sizeof(*rdai) * dai_nr, GFP_KERNEL);
|
||||
if (!drv || !rdai) {
|
||||
dev_err(dev, "dai allocate failed\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
ret = 0;
|
||||
|
||||
priv->rdai_nr = dai_nr;
|
||||
priv->daidrv = drv;
|
||||
priv->rdai = rdai;
|
||||
rsnd_dai_probe_done:
|
||||
of_node_put(dai_node);
|
||||
|
||||
for (i = 0; i < dai_nr; i++) {
|
||||
|
||||
pmod = info->dai_info[i].playback.ssi;
|
||||
cmod = info->dai_info[i].capture.ssi;
|
||||
|
||||
/*
|
||||
* init rsnd_dai
|
||||
*/
|
||||
snprintf(rdai[i].name, RSND_DAI_NAME_SIZE, "rsnd-dai.%d", i);
|
||||
rdai[i].priv = priv;
|
||||
|
||||
/*
|
||||
* init snd_soc_dai_driver
|
||||
*/
|
||||
drv[i].name = rdai[i].name;
|
||||
drv[i].ops = &rsnd_soc_dai_ops;
|
||||
if (pmod) {
|
||||
snprintf(rdai[i].playback.name, RSND_DAI_NAME_SIZE,
|
||||
"DAI%d Playback", i);
|
||||
|
||||
drv[i].playback.rates = RSND_RATES;
|
||||
drv[i].playback.formats = RSND_FMTS;
|
||||
drv[i].playback.channels_min = 2;
|
||||
drv[i].playback.channels_max = 2;
|
||||
drv[i].playback.stream_name = rdai[i].playback.name;
|
||||
|
||||
rdai[i].playback.info = &info->dai_info[i].playback;
|
||||
rdai[i].playback.rdai = rdai + i;
|
||||
rsnd_path_init(priv, &rdai[i], &rdai[i].playback);
|
||||
}
|
||||
if (cmod) {
|
||||
snprintf(rdai[i].capture.name, RSND_DAI_NAME_SIZE,
|
||||
"DAI%d Capture", i);
|
||||
|
||||
drv[i].capture.rates = RSND_RATES;
|
||||
drv[i].capture.formats = RSND_FMTS;
|
||||
drv[i].capture.channels_min = 2;
|
||||
drv[i].capture.channels_max = 2;
|
||||
drv[i].capture.stream_name = rdai[i].capture.name;
|
||||
|
||||
rdai[i].capture.info = &info->dai_info[i].capture;
|
||||
rdai[i].capture.rdai = rdai + i;
|
||||
rsnd_path_init(priv, &rdai[i], &rdai[i].capture);
|
||||
}
|
||||
|
||||
dev_dbg(dev, "%s (%s/%s)\n", rdai[i].name,
|
||||
pmod ? "play" : " -- ",
|
||||
cmod ? "capture" : " -- ");
|
||||
}
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1076,10 +920,14 @@ int rsnd_kctrl_new_m(struct rsnd_mod *mod,
|
||||
void (*update)(struct rsnd_dai_stream *io,
|
||||
struct rsnd_mod *mod),
|
||||
struct rsnd_kctrl_cfg_m *_cfg,
|
||||
int ch_size,
|
||||
u32 max)
|
||||
{
|
||||
if (ch_size > RSND_DVC_CHANNELS)
|
||||
return -EINVAL;
|
||||
|
||||
_cfg->cfg.max = max;
|
||||
_cfg->cfg.size = RSND_DVC_CHANNELS;
|
||||
_cfg->cfg.size = ch_size;
|
||||
_cfg->cfg.val = _cfg->val;
|
||||
return __rsnd_kctrl_new(mod, io, rtd, name, &_cfg->cfg, update);
|
||||
}
|
||||
@@ -1160,6 +1008,9 @@ static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv,
|
||||
|
||||
ret = rsnd_dai_call(probe, io, priv);
|
||||
if (ret == -EAGAIN) {
|
||||
struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io);
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Fallback to PIO mode
|
||||
*/
|
||||
@@ -1174,10 +1025,12 @@ static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv,
|
||||
rsnd_dai_call(remove, io, priv);
|
||||
|
||||
/*
|
||||
* remove SRC/DVC from DAI,
|
||||
* remove all mod from io
|
||||
* and, re connect ssi
|
||||
*/
|
||||
rsnd_path_remove(priv, io, src);
|
||||
rsnd_path_remove(priv, io, dvc);
|
||||
for (i = 0; i < RSND_MOD_MAX; i++)
|
||||
rsnd_dai_disconnect((io)->mod[i], io, i);
|
||||
rsnd_dai_connect(ssi_mod, io, RSND_MOD_SSI);
|
||||
|
||||
/*
|
||||
* fallback
|
||||
@@ -1199,33 +1052,25 @@ static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv,
|
||||
*/
|
||||
static int rsnd_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct rcar_snd_info *info;
|
||||
struct rsnd_priv *priv;
|
||||
struct device *dev = &pdev->dev;
|
||||
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,
|
||||
const struct rsnd_of_data *of_data,
|
||||
struct rsnd_priv *priv) = {
|
||||
int (*probe_func[])(struct rsnd_priv *priv) = {
|
||||
rsnd_gen_probe,
|
||||
rsnd_dma_probe,
|
||||
rsnd_ssi_probe,
|
||||
rsnd_ssiu_probe,
|
||||
rsnd_src_probe,
|
||||
rsnd_ctu_probe,
|
||||
rsnd_mix_probe,
|
||||
rsnd_dvc_probe,
|
||||
rsnd_cmd_probe,
|
||||
rsnd_adg_probe,
|
||||
rsnd_dai_probe,
|
||||
};
|
||||
int ret, i;
|
||||
|
||||
info = devm_kzalloc(&pdev->dev, sizeof(struct rcar_snd_info),
|
||||
GFP_KERNEL);
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
of_data = of_id->data;
|
||||
|
||||
/*
|
||||
* init priv data
|
||||
*/
|
||||
@@ -1236,14 +1081,14 @@ static int rsnd_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
priv->pdev = pdev;
|
||||
priv->info = info;
|
||||
priv->flags = (unsigned long)of_id->data;
|
||||
spin_lock_init(&priv->lock);
|
||||
|
||||
/*
|
||||
* init each module
|
||||
*/
|
||||
for (i = 0; i < ARRAY_SIZE(probe_func); i++) {
|
||||
ret = probe_func[i](pdev, of_data, priv);
|
||||
ret = probe_func[i](priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
@@ -1296,13 +1141,15 @@ static int rsnd_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct rsnd_priv *priv = dev_get_drvdata(&pdev->dev);
|
||||
struct rsnd_dai *rdai;
|
||||
void (*remove_func[])(struct platform_device *pdev,
|
||||
struct rsnd_priv *priv) = {
|
||||
void (*remove_func[])(struct rsnd_priv *priv) = {
|
||||
rsnd_ssi_remove,
|
||||
rsnd_ssiu_remove,
|
||||
rsnd_src_remove,
|
||||
rsnd_ctu_remove,
|
||||
rsnd_mix_remove,
|
||||
rsnd_dvc_remove,
|
||||
rsnd_cmd_remove,
|
||||
rsnd_adg_remove,
|
||||
};
|
||||
int ret = 0, i;
|
||||
|
||||
@@ -1314,7 +1161,7 @@ static int rsnd_remove(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(remove_func); i++)
|
||||
remove_func[i](pdev, priv);
|
||||
remove_func[i](priv);
|
||||
|
||||
snd_soc_unregister_component(&pdev->dev);
|
||||
snd_soc_unregister_platform(&pdev->dev);
|
||||
|
@@ -13,7 +13,6 @@
|
||||
#define CTU_NAME "ctu"
|
||||
|
||||
struct rsnd_ctu {
|
||||
struct rsnd_ctu_platform_info *info; /* rcar_snd.h */
|
||||
struct rsnd_mod mod;
|
||||
};
|
||||
|
||||
@@ -24,6 +23,7 @@ struct rsnd_ctu {
|
||||
((pos) = (struct rsnd_ctu *)(priv)->ctu + i); \
|
||||
i++)
|
||||
|
||||
#define rsnd_ctu_get(priv, id) ((struct rsnd_ctu *)(priv->ctu) + id)
|
||||
#define rsnd_ctu_initialize_lock(mod) __rsnd_ctu_initialize_lock(mod, 1)
|
||||
#define rsnd_ctu_initialize_unlock(mod) __rsnd_ctu_initialize_lock(mod, 0)
|
||||
static void __rsnd_ctu_initialize_lock(struct rsnd_mod *mod, u32 enable)
|
||||
@@ -31,6 +31,13 @@ static void __rsnd_ctu_initialize_lock(struct rsnd_mod *mod, u32 enable)
|
||||
rsnd_mod_write(mod, CTU_CTUIR, enable);
|
||||
}
|
||||
|
||||
static int rsnd_ctu_probe_(struct rsnd_mod *mod,
|
||||
struct rsnd_dai_stream *io,
|
||||
struct rsnd_priv *priv)
|
||||
{
|
||||
return rsnd_cmd_attach(io, rsnd_mod_id(mod) / 4);
|
||||
}
|
||||
|
||||
static int rsnd_ctu_init(struct rsnd_mod *mod,
|
||||
struct rsnd_dai_stream *io,
|
||||
struct rsnd_priv *priv)
|
||||
@@ -57,6 +64,7 @@ static int rsnd_ctu_quit(struct rsnd_mod *mod,
|
||||
|
||||
static struct rsnd_mod_ops rsnd_ctu_ops = {
|
||||
.name = CTU_NAME,
|
||||
.probe = rsnd_ctu_probe_,
|
||||
.init = rsnd_ctu_init,
|
||||
.quit = rsnd_ctu_quit,
|
||||
};
|
||||
@@ -66,51 +74,13 @@ struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id)
|
||||
if (WARN_ON(id < 0 || id >= rsnd_ctu_nr(priv)))
|
||||
id = 0;
|
||||
|
||||
return rsnd_mod_get((struct rsnd_ctu *)(priv->ctu) + id);
|
||||
return rsnd_mod_get(rsnd_ctu_get(priv, id));
|
||||
}
|
||||
|
||||
static void rsnd_of_parse_ctu(struct platform_device *pdev,
|
||||
const struct rsnd_of_data *of_data,
|
||||
struct rsnd_priv *priv)
|
||||
int rsnd_ctu_probe(struct rsnd_priv *priv)
|
||||
{
|
||||
struct device_node *node;
|
||||
struct rsnd_ctu_platform_info *ctu_info;
|
||||
struct rcar_snd_info *info = rsnd_priv_to_info(priv);
|
||||
struct device *dev = &pdev->dev;
|
||||
int nr;
|
||||
|
||||
if (!of_data)
|
||||
return;
|
||||
|
||||
node = of_get_child_by_name(dev->of_node, "rcar_sound,ctu");
|
||||
if (!node)
|
||||
return;
|
||||
|
||||
nr = of_get_child_count(node);
|
||||
if (!nr)
|
||||
goto rsnd_of_parse_ctu_end;
|
||||
|
||||
ctu_info = devm_kzalloc(dev,
|
||||
sizeof(struct rsnd_ctu_platform_info) * nr,
|
||||
GFP_KERNEL);
|
||||
if (!ctu_info) {
|
||||
dev_err(dev, "ctu info allocation error\n");
|
||||
goto rsnd_of_parse_ctu_end;
|
||||
}
|
||||
|
||||
info->ctu_info = ctu_info;
|
||||
info->ctu_info_nr = nr;
|
||||
|
||||
rsnd_of_parse_ctu_end:
|
||||
of_node_put(node);
|
||||
|
||||
}
|
||||
|
||||
int rsnd_ctu_probe(struct platform_device *pdev,
|
||||
const struct rsnd_of_data *of_data,
|
||||
struct rsnd_priv *priv)
|
||||
{
|
||||
struct rcar_snd_info *info = rsnd_priv_to_info(priv);
|
||||
struct device_node *np;
|
||||
struct device *dev = rsnd_priv_to_dev(priv);
|
||||
struct rsnd_ctu *ctu;
|
||||
struct clk *clk;
|
||||
@@ -121,20 +91,30 @@ int rsnd_ctu_probe(struct platform_device *pdev,
|
||||
if (rsnd_is_gen1(priv))
|
||||
return 0;
|
||||
|
||||
rsnd_of_parse_ctu(pdev, of_data, priv);
|
||||
node = rsnd_ctu_of_node(priv);
|
||||
if (!node)
|
||||
return 0; /* not used is not error */
|
||||
|
||||
nr = info->ctu_info_nr;
|
||||
if (!nr)
|
||||
return 0;
|
||||
nr = of_get_child_count(node);
|
||||
if (!nr) {
|
||||
ret = -EINVAL;
|
||||
goto rsnd_ctu_probe_done;
|
||||
}
|
||||
|
||||
ctu = devm_kzalloc(dev, sizeof(*ctu) * nr, GFP_KERNEL);
|
||||
if (!ctu)
|
||||
return -ENOMEM;
|
||||
if (!ctu) {
|
||||
ret = -ENOMEM;
|
||||
goto rsnd_ctu_probe_done;
|
||||
}
|
||||
|
||||
priv->ctu_nr = nr;
|
||||
priv->ctu = ctu;
|
||||
|
||||
for_each_rsnd_ctu(ctu, priv, i) {
|
||||
i = 0;
|
||||
ret = 0;
|
||||
for_each_child_of_node(node, np) {
|
||||
ctu = rsnd_ctu_get(priv, i);
|
||||
|
||||
/*
|
||||
* CTU00, CTU01, CTU02, CTU03 => CTU0
|
||||
* CTU10, CTU11, CTU12, CTU13 => CTU1
|
||||
@@ -143,22 +123,27 @@ int rsnd_ctu_probe(struct platform_device *pdev,
|
||||
CTU_NAME, i / 4);
|
||||
|
||||
clk = devm_clk_get(dev, name);
|
||||
if (IS_ERR(clk))
|
||||
return PTR_ERR(clk);
|
||||
|
||||
ctu->info = &info->ctu_info[i];
|
||||
if (IS_ERR(clk)) {
|
||||
ret = PTR_ERR(clk);
|
||||
goto rsnd_ctu_probe_done;
|
||||
}
|
||||
|
||||
ret = rsnd_mod_init(priv, rsnd_mod_get(ctu), &rsnd_ctu_ops,
|
||||
clk, RSND_MOD_CTU, i);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto rsnd_ctu_probe_done;
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
rsnd_ctu_probe_done:
|
||||
of_node_put(node);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void rsnd_ctu_remove(struct platform_device *pdev,
|
||||
struct rsnd_priv *priv)
|
||||
void rsnd_ctu_remove(struct rsnd_priv *priv)
|
||||
{
|
||||
struct rsnd_ctu *ctu;
|
||||
int i;
|
||||
|
@@ -22,21 +22,36 @@
|
||||
/* PDMACHCR */
|
||||
#define PDMACHCR_DE (1 << 0)
|
||||
|
||||
|
||||
struct rsnd_dmaen {
|
||||
struct dma_chan *chan;
|
||||
};
|
||||
|
||||
struct rsnd_dmapp {
|
||||
int dmapp_id;
|
||||
u32 chcr;
|
||||
};
|
||||
|
||||
struct rsnd_dma {
|
||||
struct rsnd_mod mod;
|
||||
dma_addr_t src_addr;
|
||||
dma_addr_t dst_addr;
|
||||
union {
|
||||
struct rsnd_dmaen en;
|
||||
struct rsnd_dmapp pp;
|
||||
} dma;
|
||||
};
|
||||
|
||||
struct rsnd_dma_ctrl {
|
||||
void __iomem *base;
|
||||
int dmaen_num;
|
||||
int dmapp_num;
|
||||
};
|
||||
|
||||
struct rsnd_dma_ops {
|
||||
char *name;
|
||||
void (*start)(struct rsnd_dai_stream *io, struct rsnd_dma *dma);
|
||||
void (*stop)(struct rsnd_dai_stream *io, struct rsnd_dma *dma);
|
||||
int (*init)(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id,
|
||||
struct rsnd_mod *mod_from, struct rsnd_mod *mod_to);
|
||||
void (*quit)(struct rsnd_dai_stream *io, struct rsnd_dma *dma);
|
||||
};
|
||||
|
||||
#define rsnd_priv_to_dmac(p) ((struct rsnd_dma_ctrl *)(p)->dma)
|
||||
#define rsnd_mod_to_dma(_mod) container_of((_mod), struct rsnd_dma, mod)
|
||||
#define rsnd_dma_to_dmaen(dma) (&(dma)->dma.en)
|
||||
#define rsnd_dma_to_dmapp(dma) (&(dma)->dma.pp)
|
||||
|
||||
/*
|
||||
* Audio DMAC
|
||||
@@ -77,18 +92,24 @@ static void rsnd_dmaen_complete(void *data)
|
||||
rsnd_mod_interrupt(mod, __rsnd_dmaen_complete);
|
||||
}
|
||||
|
||||
static void rsnd_dmaen_stop(struct rsnd_dai_stream *io, struct rsnd_dma *dma)
|
||||
static int rsnd_dmaen_stop(struct rsnd_mod *mod,
|
||||
struct rsnd_dai_stream *io,
|
||||
struct rsnd_priv *priv)
|
||||
{
|
||||
struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
|
||||
struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
|
||||
|
||||
dmaengine_terminate_all(dmaen->chan);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rsnd_dmaen_start(struct rsnd_dai_stream *io, struct rsnd_dma *dma)
|
||||
static int rsnd_dmaen_start(struct rsnd_mod *mod,
|
||||
struct rsnd_dai_stream *io,
|
||||
struct rsnd_priv *priv)
|
||||
{
|
||||
struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
|
||||
struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
|
||||
struct rsnd_mod *mod = rsnd_dma_to_mod(dma);
|
||||
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
|
||||
struct snd_pcm_substream *substream = io->substream;
|
||||
struct device *dev = rsnd_priv_to_dev(priv);
|
||||
struct dma_async_tx_descriptor *desc;
|
||||
@@ -103,18 +124,20 @@ static void rsnd_dmaen_start(struct rsnd_dai_stream *io, struct rsnd_dma *dma)
|
||||
|
||||
if (!desc) {
|
||||
dev_err(dev, "dmaengine_prep_slave_sg() fail\n");
|
||||
return;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
desc->callback = rsnd_dmaen_complete;
|
||||
desc->callback_param = mod;
|
||||
desc->callback_param = rsnd_mod_get(dma);
|
||||
|
||||
if (dmaengine_submit(desc) < 0) {
|
||||
dev_err(dev, "dmaengine_submit() fail\n");
|
||||
return;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
dma_async_issue_pending(dmaen->chan);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node,
|
||||
@@ -152,12 +175,29 @@ static struct dma_chan *rsnd_dmaen_request_channel(struct rsnd_dai_stream *io,
|
||||
return rsnd_mod_dma_req(io, mod_to);
|
||||
}
|
||||
|
||||
static int rsnd_dmaen_init(struct rsnd_dai_stream *io,
|
||||
static int rsnd_dmaen_remove(struct rsnd_mod *mod,
|
||||
struct rsnd_dai_stream *io,
|
||||
struct rsnd_priv *priv)
|
||||
{
|
||||
struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
|
||||
struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
|
||||
|
||||
if (dmaen->chan)
|
||||
dma_release_channel(dmaen->chan);
|
||||
|
||||
dmaen->chan = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rsnd_dmaen_attach(struct rsnd_dai_stream *io,
|
||||
struct rsnd_dma *dma, int id,
|
||||
struct rsnd_mod *mod_from, struct rsnd_mod *mod_to)
|
||||
{
|
||||
struct rsnd_mod *mod = rsnd_mod_get(dma);
|
||||
struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
|
||||
struct rsnd_priv *priv = rsnd_io_to_priv(io);
|
||||
struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
|
||||
struct device *dev = rsnd_priv_to_dev(priv);
|
||||
struct dma_slave_config cfg = {};
|
||||
int is_play = rsnd_io_is_play(io);
|
||||
@@ -191,18 +231,20 @@ static int rsnd_dmaen_init(struct rsnd_dai_stream *io,
|
||||
cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
|
||||
cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
|
||||
|
||||
dev_dbg(dev, "%s %pad -> %pad\n",
|
||||
dma->ops->name,
|
||||
dev_dbg(dev, "%s[%d] %pad -> %pad\n",
|
||||
rsnd_mod_name(mod), rsnd_mod_id(mod),
|
||||
&cfg.src_addr, &cfg.dst_addr);
|
||||
|
||||
ret = dmaengine_slave_config(dmaen->chan, &cfg);
|
||||
if (ret < 0)
|
||||
goto rsnd_dma_init_err;
|
||||
goto rsnd_dma_attach_err;
|
||||
|
||||
dmac->dmaen_num++;
|
||||
|
||||
return 0;
|
||||
|
||||
rsnd_dma_init_err:
|
||||
rsnd_dma_quit(io, dma);
|
||||
rsnd_dma_attach_err:
|
||||
rsnd_dmaen_remove(mod, io, priv);
|
||||
rsnd_dma_channel_err:
|
||||
|
||||
/*
|
||||
@@ -214,22 +256,11 @@ rsnd_dma_channel_err:
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
static void rsnd_dmaen_quit(struct rsnd_dai_stream *io, struct rsnd_dma *dma)
|
||||
{
|
||||
struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
|
||||
|
||||
if (dmaen->chan)
|
||||
dma_release_channel(dmaen->chan);
|
||||
|
||||
dmaen->chan = NULL;
|
||||
}
|
||||
|
||||
static struct rsnd_dma_ops rsnd_dmaen_ops = {
|
||||
static struct rsnd_mod_ops rsnd_dmaen_ops = {
|
||||
.name = "audmac",
|
||||
.start = rsnd_dmaen_start,
|
||||
.stop = rsnd_dmaen_stop,
|
||||
.init = rsnd_dmaen_init,
|
||||
.quit = rsnd_dmaen_quit,
|
||||
.remove = rsnd_dmaen_remove,
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -307,7 +338,7 @@ static u32 rsnd_dmapp_get_chcr(struct rsnd_dai_stream *io,
|
||||
(0x10 * rsnd_dma_to_dmapp(dma)->dmapp_id))
|
||||
static void rsnd_dmapp_write(struct rsnd_dma *dma, u32 data, u32 reg)
|
||||
{
|
||||
struct rsnd_mod *mod = rsnd_dma_to_mod(dma);
|
||||
struct rsnd_mod *mod = rsnd_mod_get(dma);
|
||||
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
|
||||
struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
|
||||
struct device *dev = rsnd_priv_to_dev(priv);
|
||||
@@ -319,38 +350,48 @@ static void rsnd_dmapp_write(struct rsnd_dma *dma, u32 data, u32 reg)
|
||||
|
||||
static u32 rsnd_dmapp_read(struct rsnd_dma *dma, u32 reg)
|
||||
{
|
||||
struct rsnd_mod *mod = rsnd_dma_to_mod(dma);
|
||||
struct rsnd_mod *mod = rsnd_mod_get(dma);
|
||||
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
|
||||
struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
|
||||
|
||||
return ioread32(rsnd_dmapp_addr(dmac, dma, reg));
|
||||
}
|
||||
|
||||
static void rsnd_dmapp_stop(struct rsnd_dai_stream *io, struct rsnd_dma *dma)
|
||||
static int rsnd_dmapp_stop(struct rsnd_mod *mod,
|
||||
struct rsnd_dai_stream *io,
|
||||
struct rsnd_priv *priv)
|
||||
{
|
||||
struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
|
||||
int i;
|
||||
|
||||
rsnd_dmapp_write(dma, 0, PDMACHCR);
|
||||
|
||||
for (i = 0; i < 1024; i++) {
|
||||
if (0 == rsnd_dmapp_read(dma, PDMACHCR))
|
||||
return;
|
||||
return 0;
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static void rsnd_dmapp_start(struct rsnd_dai_stream *io, struct rsnd_dma *dma)
|
||||
static int rsnd_dmapp_start(struct rsnd_mod *mod,
|
||||
struct rsnd_dai_stream *io,
|
||||
struct rsnd_priv *priv)
|
||||
{
|
||||
struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
|
||||
struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma);
|
||||
|
||||
rsnd_dmapp_write(dma, dma->src_addr, PDMASAR);
|
||||
rsnd_dmapp_write(dma, dma->dst_addr, PDMADAR);
|
||||
rsnd_dmapp_write(dma, dmapp->chcr, PDMACHCR);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rsnd_dmapp_init(struct rsnd_dai_stream *io,
|
||||
struct rsnd_dma *dma, int id,
|
||||
struct rsnd_mod *mod_from, struct rsnd_mod *mod_to)
|
||||
static int rsnd_dmapp_attach(struct rsnd_dai_stream *io,
|
||||
struct rsnd_dma *dma, int id,
|
||||
struct rsnd_mod *mod_from, struct rsnd_mod *mod_to)
|
||||
{
|
||||
struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma);
|
||||
struct rsnd_priv *priv = rsnd_io_to_priv(io);
|
||||
@@ -362,19 +403,16 @@ static int rsnd_dmapp_init(struct rsnd_dai_stream *io,
|
||||
|
||||
dmac->dmapp_num++;
|
||||
|
||||
rsnd_dmapp_stop(io, dma);
|
||||
|
||||
dev_dbg(dev, "id/src/dst/chcr = %d/%pad/%pad/%08x\n",
|
||||
dmapp->dmapp_id, &dma->src_addr, &dma->dst_addr, dmapp->chcr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct rsnd_dma_ops rsnd_dmapp_ops = {
|
||||
static struct rsnd_mod_ops rsnd_dmapp_ops = {
|
||||
.name = "audmac-pp",
|
||||
.start = rsnd_dmapp_start,
|
||||
.stop = rsnd_dmapp_stop,
|
||||
.init = rsnd_dmapp_init,
|
||||
.quit = rsnd_dmapp_stop,
|
||||
};
|
||||
|
||||
@@ -497,13 +535,12 @@ static dma_addr_t rsnd_dma_addr(struct rsnd_dai_stream *io,
|
||||
}
|
||||
|
||||
#define MOD_MAX (RSND_MOD_MAX + 1) /* +Memory */
|
||||
static void rsnd_dma_of_path(struct rsnd_dma *dma,
|
||||
static void rsnd_dma_of_path(struct rsnd_mod *this,
|
||||
struct rsnd_dai_stream *io,
|
||||
int is_play,
|
||||
struct rsnd_mod **mod_from,
|
||||
struct rsnd_mod **mod_to)
|
||||
{
|
||||
struct rsnd_mod *this = rsnd_dma_to_mod(dma);
|
||||
struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io);
|
||||
struct rsnd_mod *src = rsnd_io_to_mod_src(io);
|
||||
struct rsnd_mod *ctu = rsnd_io_to_mod_ctu(io);
|
||||
@@ -513,7 +550,7 @@ static void rsnd_dma_of_path(struct rsnd_dma *dma,
|
||||
struct rsnd_mod *mod_start, *mod_end;
|
||||
struct rsnd_priv *priv = rsnd_mod_to_priv(this);
|
||||
struct device *dev = rsnd_priv_to_dev(priv);
|
||||
int nr, i;
|
||||
int nr, i, idx;
|
||||
|
||||
if (!ssi)
|
||||
return;
|
||||
@@ -542,23 +579,24 @@ static void rsnd_dma_of_path(struct rsnd_dma *dma,
|
||||
mod_start = (is_play) ? NULL : ssi;
|
||||
mod_end = (is_play) ? ssi : NULL;
|
||||
|
||||
mod[0] = mod_start;
|
||||
idx = 0;
|
||||
mod[idx++] = mod_start;
|
||||
for (i = 1; i < nr; i++) {
|
||||
if (src) {
|
||||
mod[i] = src;
|
||||
mod[idx++] = src;
|
||||
src = NULL;
|
||||
} else if (ctu) {
|
||||
mod[i] = ctu;
|
||||
mod[idx++] = ctu;
|
||||
ctu = NULL;
|
||||
} else if (mix) {
|
||||
mod[i] = mix;
|
||||
mod[idx++] = mix;
|
||||
mix = NULL;
|
||||
} else if (dvc) {
|
||||
mod[i] = dvc;
|
||||
mod[idx++] = dvc;
|
||||
dvc = NULL;
|
||||
}
|
||||
}
|
||||
mod[i] = mod_end;
|
||||
mod[idx] = mod_end;
|
||||
|
||||
/*
|
||||
* | SSI | SRC |
|
||||
@@ -567,8 +605,8 @@ static void rsnd_dma_of_path(struct rsnd_dma *dma,
|
||||
* !is_play | * | o |
|
||||
*/
|
||||
if ((this == ssi) == (is_play)) {
|
||||
*mod_from = mod[nr - 1];
|
||||
*mod_to = mod[nr];
|
||||
*mod_from = mod[idx - 1];
|
||||
*mod_to = mod[idx];
|
||||
} else {
|
||||
*mod_from = mod[0];
|
||||
*mod_to = mod[1];
|
||||
@@ -576,7 +614,7 @@ static void rsnd_dma_of_path(struct rsnd_dma *dma,
|
||||
|
||||
dev_dbg(dev, "module connection (this is %s[%d])\n",
|
||||
rsnd_mod_name(this), rsnd_mod_id(this));
|
||||
for (i = 0; i <= nr; i++) {
|
||||
for (i = 0; i <= idx; i++) {
|
||||
dev_dbg(dev, " %s[%d]%s\n",
|
||||
rsnd_mod_name(mod[i]), rsnd_mod_id(mod[i]),
|
||||
(mod[i] == *mod_from) ? " from" :
|
||||
@@ -584,36 +622,22 @@ static void rsnd_dma_of_path(struct rsnd_dma *dma,
|
||||
}
|
||||
}
|
||||
|
||||
void rsnd_dma_stop(struct rsnd_dai_stream *io, struct rsnd_dma *dma)
|
||||
{
|
||||
dma->ops->stop(io, dma);
|
||||
}
|
||||
|
||||
void rsnd_dma_start(struct rsnd_dai_stream *io, struct rsnd_dma *dma)
|
||||
{
|
||||
dma->ops->start(io, dma);
|
||||
}
|
||||
|
||||
void rsnd_dma_quit(struct rsnd_dai_stream *io, struct rsnd_dma *dma)
|
||||
{
|
||||
struct rsnd_mod *mod = rsnd_dma_to_mod(dma);
|
||||
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
|
||||
struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
|
||||
|
||||
if (!dmac)
|
||||
return;
|
||||
|
||||
dma->ops->quit(io, dma);
|
||||
}
|
||||
|
||||
int rsnd_dma_init(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id)
|
||||
struct rsnd_mod *rsnd_dma_attach(struct rsnd_dai_stream *io,
|
||||
struct rsnd_mod *mod, int id)
|
||||
{
|
||||
struct rsnd_mod *dma_mod;
|
||||
struct rsnd_mod *mod_from = NULL;
|
||||
struct rsnd_mod *mod_to = NULL;
|
||||
struct rsnd_priv *priv = rsnd_io_to_priv(io);
|
||||
struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
|
||||
struct rsnd_dma *dma;
|
||||
struct device *dev = rsnd_priv_to_dev(priv);
|
||||
struct rsnd_mod_ops *ops;
|
||||
enum rsnd_mod_type type;
|
||||
int (*attach)(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id,
|
||||
struct rsnd_mod *mod_from, struct rsnd_mod *mod_to);
|
||||
int is_play = rsnd_io_is_play(io);
|
||||
int ret, dma_id;
|
||||
|
||||
/*
|
||||
* DMA failed. try to PIO mode
|
||||
@@ -622,35 +646,64 @@ int rsnd_dma_init(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id)
|
||||
* rsnd_rdai_continuance_probe()
|
||||
*/
|
||||
if (!dmac)
|
||||
return -EAGAIN;
|
||||
return ERR_PTR(-EAGAIN);
|
||||
|
||||
rsnd_dma_of_path(dma, io, is_play, &mod_from, &mod_to);
|
||||
dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL);
|
||||
if (!dma)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
rsnd_dma_of_path(mod, io, is_play, &mod_from, &mod_to);
|
||||
|
||||
dma->src_addr = rsnd_dma_addr(io, mod_from, is_play, 1);
|
||||
dma->dst_addr = rsnd_dma_addr(io, mod_to, is_play, 0);
|
||||
|
||||
/* for Gen2 */
|
||||
if (mod_from && mod_to)
|
||||
dma->ops = &rsnd_dmapp_ops;
|
||||
else
|
||||
dma->ops = &rsnd_dmaen_ops;
|
||||
if (mod_from && mod_to) {
|
||||
ops = &rsnd_dmapp_ops;
|
||||
attach = rsnd_dmapp_attach;
|
||||
dma_id = dmac->dmapp_num;
|
||||
type = RSND_MOD_AUDMAPP;
|
||||
} else {
|
||||
ops = &rsnd_dmaen_ops;
|
||||
attach = rsnd_dmaen_attach;
|
||||
dma_id = dmac->dmaen_num;
|
||||
type = RSND_MOD_AUDMA;
|
||||
}
|
||||
|
||||
/* for Gen1, overwrite */
|
||||
if (rsnd_is_gen1(priv))
|
||||
dma->ops = &rsnd_dmaen_ops;
|
||||
if (rsnd_is_gen1(priv)) {
|
||||
ops = &rsnd_dmaen_ops;
|
||||
attach = rsnd_dmaen_attach;
|
||||
dma_id = dmac->dmaen_num;
|
||||
type = RSND_MOD_AUDMA;
|
||||
}
|
||||
|
||||
dev_dbg(dev, "%s %s[%d] -> %s[%d]\n",
|
||||
dma->ops->name,
|
||||
dma_mod = rsnd_mod_get(dma);
|
||||
|
||||
ret = rsnd_mod_init(priv, dma_mod,
|
||||
ops, NULL, type, dma_id);
|
||||
if (ret < 0)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
dev_dbg(dev, "%s[%d] %s[%d] -> %s[%d]\n",
|
||||
rsnd_mod_name(dma_mod), rsnd_mod_id(dma_mod),
|
||||
rsnd_mod_name(mod_from), rsnd_mod_id(mod_from),
|
||||
rsnd_mod_name(mod_to), rsnd_mod_id(mod_to));
|
||||
|
||||
return dma->ops->init(io, dma, id, mod_from, mod_to);
|
||||
ret = attach(io, dma, id, mod_from, mod_to);
|
||||
if (ret < 0)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
ret = rsnd_dai_connect(dma_mod, io, type);
|
||||
if (ret < 0)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
return rsnd_mod_get(dma);
|
||||
}
|
||||
|
||||
int rsnd_dma_probe(struct platform_device *pdev,
|
||||
const struct rsnd_of_data *of_data,
|
||||
struct rsnd_priv *priv)
|
||||
int rsnd_dma_probe(struct rsnd_priv *priv)
|
||||
{
|
||||
struct platform_device *pdev = rsnd_priv_to_pdev(priv);
|
||||
struct device *dev = rsnd_priv_to_dev(priv);
|
||||
struct rsnd_dma_ctrl *dmac;
|
||||
struct resource *res;
|
||||
|
@@ -15,7 +15,6 @@
|
||||
#define DVC_NAME "dvc"
|
||||
|
||||
struct rsnd_dvc {
|
||||
struct rsnd_dvc_platform_info *info; /* rcar_snd.h */
|
||||
struct rsnd_mod mod;
|
||||
struct rsnd_kctrl_cfg_m volume;
|
||||
struct rsnd_kctrl_cfg_m mute;
|
||||
@@ -24,6 +23,7 @@ struct rsnd_dvc {
|
||||
struct rsnd_kctrl_cfg_s rdown; /* Ramp Rate Down */
|
||||
};
|
||||
|
||||
#define rsnd_dvc_get(priv, id) ((struct rsnd_dvc *)(priv->dvc) + id)
|
||||
#define rsnd_dvc_nr(priv) ((priv)->dvc_nr)
|
||||
#define rsnd_dvc_of_node(priv) \
|
||||
of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,dvc")
|
||||
@@ -64,79 +64,142 @@ static const char * const dvc_ramp_rate[] = {
|
||||
"0.125 dB/8192 steps", /* 10111 */
|
||||
};
|
||||
|
||||
static void rsnd_dvc_soft_reset(struct rsnd_mod *mod)
|
||||
static void rsnd_dvc_activation(struct rsnd_mod *mod)
|
||||
{
|
||||
rsnd_mod_write(mod, DVC_SWRSR, 0);
|
||||
rsnd_mod_write(mod, DVC_SWRSR, 1);
|
||||
}
|
||||
|
||||
#define rsnd_dvc_initialize_lock(mod) __rsnd_dvc_initialize_lock(mod, 1)
|
||||
#define rsnd_dvc_initialize_unlock(mod) __rsnd_dvc_initialize_lock(mod, 0)
|
||||
static void __rsnd_dvc_initialize_lock(struct rsnd_mod *mod, u32 enable)
|
||||
static void rsnd_dvc_halt(struct rsnd_mod *mod)
|
||||
{
|
||||
rsnd_mod_write(mod, DVC_DVUIR, enable);
|
||||
rsnd_mod_write(mod, DVC_DVUIR, 1);
|
||||
rsnd_mod_write(mod, DVC_SWRSR, 0);
|
||||
}
|
||||
|
||||
static void rsnd_dvc_volume_update(struct rsnd_dai_stream *io,
|
||||
struct rsnd_mod *mod)
|
||||
#define rsnd_dvc_get_vrpdr(dvc) (dvc->rup.val << 8 | dvc->rdown.val)
|
||||
#define rsnd_dvc_get_vrdbr(dvc) (0x3ff - (dvc->volume.val[0] >> 13))
|
||||
|
||||
static void rsnd_dvc_volume_parameter(struct rsnd_dai_stream *io,
|
||||
struct rsnd_mod *mod)
|
||||
{
|
||||
struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
|
||||
u32 val[RSND_DVC_CHANNELS];
|
||||
u32 dvucr = 0;
|
||||
u32 mute = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < dvc->mute.cfg.size; i++)
|
||||
mute |= (!!dvc->mute.cfg.val[i]) << i;
|
||||
/* Enable Ramp */
|
||||
if (dvc->ren.val)
|
||||
for (i = 0; i < RSND_DVC_CHANNELS; i++)
|
||||
val[i] = dvc->volume.cfg.max;
|
||||
else
|
||||
for (i = 0; i < RSND_DVC_CHANNELS; i++)
|
||||
val[i] = dvc->volume.val[i];
|
||||
|
||||
/* Disable DVC Register access */
|
||||
rsnd_mod_write(mod, DVC_DVUER, 0);
|
||||
/* Enable Digital Volume */
|
||||
rsnd_mod_write(mod, DVC_VOL0R, val[0]);
|
||||
rsnd_mod_write(mod, DVC_VOL1R, val[1]);
|
||||
rsnd_mod_write(mod, DVC_VOL2R, val[2]);
|
||||
rsnd_mod_write(mod, DVC_VOL3R, val[3]);
|
||||
rsnd_mod_write(mod, DVC_VOL4R, val[4]);
|
||||
rsnd_mod_write(mod, DVC_VOL5R, val[5]);
|
||||
rsnd_mod_write(mod, DVC_VOL6R, val[6]);
|
||||
rsnd_mod_write(mod, DVC_VOL7R, val[7]);
|
||||
}
|
||||
|
||||
static void rsnd_dvc_volume_init(struct rsnd_dai_stream *io,
|
||||
struct rsnd_mod *mod)
|
||||
{
|
||||
struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
|
||||
u32 adinr = 0;
|
||||
u32 dvucr = 0;
|
||||
u32 vrctr = 0;
|
||||
u32 vrpdr = 0;
|
||||
u32 vrdbr = 0;
|
||||
|
||||
adinr = rsnd_get_adinr_bit(mod, io) |
|
||||
rsnd_get_adinr_chan(mod, io);
|
||||
|
||||
/* Enable Digital Volume, Zero Cross Mute Mode */
|
||||
dvucr |= 0x101;
|
||||
|
||||
/* Enable Ramp */
|
||||
if (dvc->ren.val) {
|
||||
dvucr |= 0x10;
|
||||
|
||||
/* Digital Volume Max */
|
||||
for (i = 0; i < RSND_DVC_CHANNELS; i++)
|
||||
val[i] = dvc->volume.cfg.max;
|
||||
|
||||
rsnd_mod_write(mod, DVC_VRCTR, 0xff);
|
||||
rsnd_mod_write(mod, DVC_VRPDR, dvc->rup.val << 8 |
|
||||
dvc->rdown.val);
|
||||
/*
|
||||
* FIXME !!
|
||||
* use scale-downed Digital Volume
|
||||
* as Volume Ramp
|
||||
* 7F FFFF -> 3FF
|
||||
*/
|
||||
rsnd_mod_write(mod, DVC_VRDBR,
|
||||
0x3ff - (dvc->volume.val[0] >> 13));
|
||||
|
||||
} else {
|
||||
for (i = 0; i < RSND_DVC_CHANNELS; i++)
|
||||
val[i] = dvc->volume.val[i];
|
||||
vrctr = 0xff;
|
||||
vrpdr = rsnd_dvc_get_vrpdr(dvc);
|
||||
vrdbr = rsnd_dvc_get_vrdbr(dvc);
|
||||
}
|
||||
|
||||
/* Enable Digital Volume */
|
||||
dvucr |= 0x100;
|
||||
rsnd_mod_write(mod, DVC_VOL0R, val[0]);
|
||||
rsnd_mod_write(mod, DVC_VOL1R, val[1]);
|
||||
|
||||
/* Enable Mute */
|
||||
if (mute) {
|
||||
dvucr |= 0x1;
|
||||
rsnd_mod_write(mod, DVC_ZCMCR, mute);
|
||||
}
|
||||
/* Initialize operation */
|
||||
rsnd_mod_write(mod, DVC_DVUIR, 1);
|
||||
|
||||
/* General Information */
|
||||
rsnd_mod_write(mod, DVC_ADINR, adinr);
|
||||
rsnd_mod_write(mod, DVC_DVUCR, dvucr);
|
||||
|
||||
/* Volume Ramp Parameter */
|
||||
rsnd_mod_write(mod, DVC_VRCTR, vrctr);
|
||||
rsnd_mod_write(mod, DVC_VRPDR, vrpdr);
|
||||
rsnd_mod_write(mod, DVC_VRDBR, vrdbr);
|
||||
|
||||
/* Digital Volume Function Parameter */
|
||||
rsnd_dvc_volume_parameter(io, mod);
|
||||
|
||||
/* cancel operation */
|
||||
rsnd_mod_write(mod, DVC_DVUIR, 0);
|
||||
}
|
||||
|
||||
static void rsnd_dvc_volume_update(struct rsnd_dai_stream *io,
|
||||
struct rsnd_mod *mod)
|
||||
{
|
||||
struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
|
||||
u32 zcmcr = 0;
|
||||
u32 vrpdr = 0;
|
||||
u32 vrdbr = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < dvc->mute.cfg.size; i++)
|
||||
zcmcr |= (!!dvc->mute.cfg.val[i]) << i;
|
||||
|
||||
if (dvc->ren.val) {
|
||||
vrpdr = rsnd_dvc_get_vrpdr(dvc);
|
||||
vrdbr = rsnd_dvc_get_vrdbr(dvc);
|
||||
}
|
||||
|
||||
/* Disable DVC Register access */
|
||||
rsnd_mod_write(mod, DVC_DVUER, 0);
|
||||
|
||||
/* Zero Cross Mute Function */
|
||||
rsnd_mod_write(mod, DVC_ZCMCR, zcmcr);
|
||||
|
||||
/* Volume Ramp Function */
|
||||
rsnd_mod_write(mod, DVC_VRPDR, vrpdr);
|
||||
rsnd_mod_write(mod, DVC_VRDBR, vrdbr);
|
||||
/* add DVC_VRWTR here */
|
||||
|
||||
/* Digital Volume Function Parameter */
|
||||
rsnd_dvc_volume_parameter(io, mod);
|
||||
|
||||
/* Enable DVC Register access */
|
||||
rsnd_mod_write(mod, DVC_DVUER, 1);
|
||||
}
|
||||
|
||||
static int rsnd_dvc_remove_gen2(struct rsnd_mod *mod,
|
||||
struct rsnd_dai_stream *io,
|
||||
struct rsnd_priv *priv)
|
||||
static int rsnd_dvc_probe_(struct rsnd_mod *mod,
|
||||
struct rsnd_dai_stream *io,
|
||||
struct rsnd_priv *priv)
|
||||
{
|
||||
return rsnd_cmd_attach(io, rsnd_mod_id(mod));
|
||||
}
|
||||
|
||||
static int rsnd_dvc_remove_(struct rsnd_mod *mod,
|
||||
struct rsnd_dai_stream *io,
|
||||
struct rsnd_priv *priv)
|
||||
{
|
||||
struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
|
||||
|
||||
@@ -155,19 +218,12 @@ static int rsnd_dvc_init(struct rsnd_mod *mod,
|
||||
{
|
||||
rsnd_mod_power_on(mod);
|
||||
|
||||
rsnd_dvc_soft_reset(mod);
|
||||
rsnd_dvc_activation(mod);
|
||||
|
||||
rsnd_dvc_initialize_lock(mod);
|
||||
rsnd_dvc_volume_init(io, mod);
|
||||
|
||||
rsnd_path_parse(priv, io);
|
||||
|
||||
rsnd_mod_write(mod, DVC_ADINR, rsnd_get_adinr_bit(mod, io));
|
||||
|
||||
/* ch0/ch1 Volume */
|
||||
rsnd_dvc_volume_update(io, mod);
|
||||
|
||||
rsnd_adg_set_cmd_timsel_gen2(mod, io);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -175,37 +231,20 @@ static int rsnd_dvc_quit(struct rsnd_mod *mod,
|
||||
struct rsnd_dai_stream *io,
|
||||
struct rsnd_priv *priv)
|
||||
{
|
||||
rsnd_dvc_halt(mod);
|
||||
|
||||
rsnd_mod_power_off(mod);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rsnd_dvc_start(struct rsnd_mod *mod,
|
||||
struct rsnd_dai_stream *io,
|
||||
struct rsnd_priv *priv)
|
||||
{
|
||||
rsnd_dvc_initialize_unlock(mod);
|
||||
|
||||
rsnd_mod_write(mod, CMD_CTRL, 0x10);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rsnd_dvc_stop(struct rsnd_mod *mod,
|
||||
struct rsnd_dai_stream *io,
|
||||
struct rsnd_priv *priv)
|
||||
{
|
||||
rsnd_mod_write(mod, CMD_CTRL, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
|
||||
struct rsnd_dai_stream *io,
|
||||
struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
|
||||
int is_play = rsnd_io_is_play(io);
|
||||
int slots = rsnd_get_slot(io);
|
||||
int ret;
|
||||
|
||||
/* Volume */
|
||||
@@ -213,7 +252,8 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
|
||||
is_play ?
|
||||
"DVC Out Playback Volume" : "DVC In Capture Volume",
|
||||
rsnd_dvc_volume_update,
|
||||
&dvc->volume, 0x00800000 - 1);
|
||||
&dvc->volume, slots,
|
||||
0x00800000 - 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -222,7 +262,8 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
|
||||
is_play ?
|
||||
"DVC Out Mute Switch" : "DVC In Mute Switch",
|
||||
rsnd_dvc_volume_update,
|
||||
&dvc->mute, 1);
|
||||
&dvc->mute, slots,
|
||||
1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -269,11 +310,10 @@ static struct dma_chan *rsnd_dvc_dma_req(struct rsnd_dai_stream *io,
|
||||
static struct rsnd_mod_ops rsnd_dvc_ops = {
|
||||
.name = DVC_NAME,
|
||||
.dma_req = rsnd_dvc_dma_req,
|
||||
.remove = rsnd_dvc_remove_gen2,
|
||||
.probe = rsnd_dvc_probe_,
|
||||
.remove = rsnd_dvc_remove_,
|
||||
.init = rsnd_dvc_init,
|
||||
.quit = rsnd_dvc_quit,
|
||||
.start = rsnd_dvc_start,
|
||||
.stop = rsnd_dvc_stop,
|
||||
.pcm_new = rsnd_dvc_pcm_new,
|
||||
};
|
||||
|
||||
@@ -282,50 +322,13 @@ struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id)
|
||||
if (WARN_ON(id < 0 || id >= rsnd_dvc_nr(priv)))
|
||||
id = 0;
|
||||
|
||||
return rsnd_mod_get((struct rsnd_dvc *)(priv->dvc) + id);
|
||||
return rsnd_mod_get(rsnd_dvc_get(priv, id));
|
||||
}
|
||||
|
||||
static void rsnd_of_parse_dvc(struct platform_device *pdev,
|
||||
const struct rsnd_of_data *of_data,
|
||||
struct rsnd_priv *priv)
|
||||
int rsnd_dvc_probe(struct rsnd_priv *priv)
|
||||
{
|
||||
struct device_node *node;
|
||||
struct rsnd_dvc_platform_info *dvc_info;
|
||||
struct rcar_snd_info *info = rsnd_priv_to_info(priv);
|
||||
struct device *dev = &pdev->dev;
|
||||
int nr;
|
||||
|
||||
if (!of_data)
|
||||
return;
|
||||
|
||||
node = of_get_child_by_name(dev->of_node, "rcar_sound,dvc");
|
||||
if (!node)
|
||||
return;
|
||||
|
||||
nr = of_get_child_count(node);
|
||||
if (!nr)
|
||||
goto rsnd_of_parse_dvc_end;
|
||||
|
||||
dvc_info = devm_kzalloc(dev,
|
||||
sizeof(struct rsnd_dvc_platform_info) * nr,
|
||||
GFP_KERNEL);
|
||||
if (!dvc_info) {
|
||||
dev_err(dev, "dvc info allocation error\n");
|
||||
goto rsnd_of_parse_dvc_end;
|
||||
}
|
||||
|
||||
info->dvc_info = dvc_info;
|
||||
info->dvc_info_nr = nr;
|
||||
|
||||
rsnd_of_parse_dvc_end:
|
||||
of_node_put(node);
|
||||
}
|
||||
|
||||
int rsnd_dvc_probe(struct platform_device *pdev,
|
||||
const struct rsnd_of_data *of_data,
|
||||
struct rsnd_priv *priv)
|
||||
{
|
||||
struct rcar_snd_info *info = rsnd_priv_to_info(priv);
|
||||
struct device_node *np;
|
||||
struct device *dev = rsnd_priv_to_dev(priv);
|
||||
struct rsnd_dvc *dvc;
|
||||
struct clk *clk;
|
||||
@@ -336,40 +339,54 @@ int rsnd_dvc_probe(struct platform_device *pdev,
|
||||
if (rsnd_is_gen1(priv))
|
||||
return 0;
|
||||
|
||||
rsnd_of_parse_dvc(pdev, of_data, priv);
|
||||
node = rsnd_dvc_of_node(priv);
|
||||
if (!node)
|
||||
return 0; /* not used is not error */
|
||||
|
||||
nr = info->dvc_info_nr;
|
||||
if (!nr)
|
||||
return 0;
|
||||
nr = of_get_child_count(node);
|
||||
if (!nr) {
|
||||
ret = -EINVAL;
|
||||
goto rsnd_dvc_probe_done;
|
||||
}
|
||||
|
||||
dvc = devm_kzalloc(dev, sizeof(*dvc) * nr, GFP_KERNEL);
|
||||
if (!dvc)
|
||||
return -ENOMEM;
|
||||
if (!dvc) {
|
||||
ret = -ENOMEM;
|
||||
goto rsnd_dvc_probe_done;
|
||||
}
|
||||
|
||||
priv->dvc_nr = nr;
|
||||
priv->dvc = dvc;
|
||||
|
||||
for_each_rsnd_dvc(dvc, priv, i) {
|
||||
i = 0;
|
||||
ret = 0;
|
||||
for_each_child_of_node(node, np) {
|
||||
dvc = rsnd_dvc_get(priv, i);
|
||||
|
||||
snprintf(name, RSND_DVC_NAME_SIZE, "%s.%d",
|
||||
DVC_NAME, i);
|
||||
|
||||
clk = devm_clk_get(dev, name);
|
||||
if (IS_ERR(clk))
|
||||
return PTR_ERR(clk);
|
||||
|
||||
dvc->info = &info->dvc_info[i];
|
||||
if (IS_ERR(clk)) {
|
||||
ret = PTR_ERR(clk);
|
||||
goto rsnd_dvc_probe_done;
|
||||
}
|
||||
|
||||
ret = rsnd_mod_init(priv, rsnd_mod_get(dvc), &rsnd_dvc_ops,
|
||||
clk, RSND_MOD_DVC, i);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto rsnd_dvc_probe_done;
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
rsnd_dvc_probe_done:
|
||||
of_node_put(node);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void rsnd_dvc_remove(struct platform_device *pdev,
|
||||
struct rsnd_priv *priv)
|
||||
void rsnd_dvc_remove(struct rsnd_priv *priv)
|
||||
{
|
||||
struct rsnd_dvc *dvc;
|
||||
int i;
|
||||
|
@@ -31,29 +31,33 @@ struct rsnd_gen {
|
||||
|
||||
/* RSND_REG_MAX base */
|
||||
struct regmap_field *regs[RSND_REG_MAX];
|
||||
const char *reg_name[RSND_REG_MAX];
|
||||
};
|
||||
|
||||
#define rsnd_priv_to_gen(p) ((struct rsnd_gen *)(p)->gen)
|
||||
#define rsnd_reg_name(gen, id) ((gen)->reg_name[id])
|
||||
|
||||
struct rsnd_regmap_field_conf {
|
||||
int idx;
|
||||
unsigned int reg_offset;
|
||||
unsigned int id_offset;
|
||||
const char *reg_name;
|
||||
};
|
||||
|
||||
#define RSND_REG_SET(id, offset, _id_offset) \
|
||||
#define RSND_REG_SET(id, offset, _id_offset, n) \
|
||||
{ \
|
||||
.idx = id, \
|
||||
.reg_offset = offset, \
|
||||
.id_offset = _id_offset, \
|
||||
.reg_name = n, \
|
||||
}
|
||||
/* single address mapping */
|
||||
#define RSND_GEN_S_REG(id, offset) \
|
||||
RSND_REG_SET(RSND_REG_##id, offset, 0)
|
||||
RSND_REG_SET(RSND_REG_##id, offset, 0, #id)
|
||||
|
||||
/* multi address mapping */
|
||||
#define RSND_GEN_M_REG(id, offset, _id_offset) \
|
||||
RSND_REG_SET(RSND_REG_##id, offset, _id_offset)
|
||||
RSND_REG_SET(RSND_REG_##id, offset, _id_offset, #id)
|
||||
|
||||
/*
|
||||
* basic function
|
||||
@@ -83,8 +87,9 @@ u32 rsnd_read(struct rsnd_priv *priv,
|
||||
|
||||
regmap_fields_read(gen->regs[reg], rsnd_mod_id(mod), &val);
|
||||
|
||||
dev_dbg(dev, "r %s[%d] - %4d : %08x\n",
|
||||
rsnd_mod_name(mod), rsnd_mod_id(mod), reg, val);
|
||||
dev_dbg(dev, "r %s[%d] - %-18s (%4d) : %08x\n",
|
||||
rsnd_mod_name(mod), rsnd_mod_id(mod),
|
||||
rsnd_reg_name(gen, reg), reg, val);
|
||||
|
||||
return val;
|
||||
}
|
||||
@@ -99,10 +104,11 @@ void rsnd_write(struct rsnd_priv *priv,
|
||||
if (!rsnd_is_accessible_reg(priv, gen, reg))
|
||||
return;
|
||||
|
||||
dev_dbg(dev, "w %s[%d] - %4d : %08x\n",
|
||||
rsnd_mod_name(mod), rsnd_mod_id(mod), reg, data);
|
||||
|
||||
regmap_fields_write(gen->regs[reg], rsnd_mod_id(mod), data);
|
||||
|
||||
dev_dbg(dev, "w %s[%d] - %-18s (%4d) : %08x\n",
|
||||
rsnd_mod_name(mod), rsnd_mod_id(mod),
|
||||
rsnd_reg_name(gen, reg), reg, data);
|
||||
}
|
||||
|
||||
void rsnd_force_write(struct rsnd_priv *priv,
|
||||
@@ -115,10 +121,11 @@ void rsnd_force_write(struct rsnd_priv *priv,
|
||||
if (!rsnd_is_accessible_reg(priv, gen, reg))
|
||||
return;
|
||||
|
||||
dev_dbg(dev, "w %s[%d] - %4d : %08x\n",
|
||||
rsnd_mod_name(mod), rsnd_mod_id(mod), reg, data);
|
||||
|
||||
regmap_fields_force_write(gen->regs[reg], rsnd_mod_id(mod), data);
|
||||
|
||||
dev_dbg(dev, "w %s[%d] - %-18s (%4d) : %08x\n",
|
||||
rsnd_mod_name(mod), rsnd_mod_id(mod),
|
||||
rsnd_reg_name(gen, reg), reg, data);
|
||||
}
|
||||
|
||||
void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod,
|
||||
@@ -130,11 +137,13 @@ void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod,
|
||||
if (!rsnd_is_accessible_reg(priv, gen, reg))
|
||||
return;
|
||||
|
||||
dev_dbg(dev, "b %s[%d] - %4d : %08x/%08x\n",
|
||||
rsnd_mod_name(mod), rsnd_mod_id(mod), reg, data, mask);
|
||||
|
||||
regmap_fields_update_bits(gen->regs[reg], rsnd_mod_id(mod),
|
||||
mask, data);
|
||||
|
||||
dev_dbg(dev, "b %s[%d] - %-18s (%4d) : %08x/%08x\n",
|
||||
rsnd_mod_name(mod), rsnd_mod_id(mod),
|
||||
rsnd_reg_name(gen, reg), reg, data, mask);
|
||||
|
||||
}
|
||||
|
||||
phys_addr_t rsnd_gen_get_phy_addr(struct rsnd_priv *priv, int reg_id)
|
||||
@@ -150,7 +159,7 @@ static int _rsnd_gen_regmap_init(struct rsnd_priv *priv,
|
||||
int id_size,
|
||||
int reg_id,
|
||||
const char *name,
|
||||
struct rsnd_regmap_field_conf *conf,
|
||||
const struct rsnd_regmap_field_conf *conf,
|
||||
int conf_size)
|
||||
{
|
||||
struct platform_device *pdev = rsnd_priv_to_pdev(priv);
|
||||
@@ -203,6 +212,7 @@ static int _rsnd_gen_regmap_init(struct rsnd_priv *priv,
|
||||
|
||||
/* RSND_REG_MAX base */
|
||||
gen->regs[conf[i].idx] = regs;
|
||||
gen->reg_name[conf[i].idx] = conf[i].reg_name;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -211,25 +221,31 @@ static int _rsnd_gen_regmap_init(struct rsnd_priv *priv,
|
||||
/*
|
||||
* Gen2
|
||||
*/
|
||||
static int rsnd_gen2_probe(struct platform_device *pdev,
|
||||
struct rsnd_priv *priv)
|
||||
static int rsnd_gen2_probe(struct rsnd_priv *priv)
|
||||
{
|
||||
struct rsnd_regmap_field_conf conf_ssiu[] = {
|
||||
const static struct rsnd_regmap_field_conf conf_ssiu[] = {
|
||||
RSND_GEN_S_REG(SSI_MODE0, 0x800),
|
||||
RSND_GEN_S_REG(SSI_MODE1, 0x804),
|
||||
RSND_GEN_S_REG(SSI_MODE2, 0x808),
|
||||
RSND_GEN_S_REG(SSI_CONTROL, 0x810),
|
||||
|
||||
/* FIXME: it needs SSI_MODE2/3 in the future */
|
||||
RSND_GEN_M_REG(SSI_BUSIF_MODE, 0x0, 0x80),
|
||||
RSND_GEN_M_REG(SSI_BUSIF_ADINR, 0x4, 0x80),
|
||||
RSND_GEN_M_REG(SSI_BUSIF_DALIGN,0x8, 0x80),
|
||||
RSND_GEN_M_REG(SSI_MODE, 0xc, 0x80),
|
||||
RSND_GEN_M_REG(SSI_CTRL, 0x10, 0x80),
|
||||
RSND_GEN_M_REG(SSI_INT_ENABLE, 0x18, 0x80),
|
||||
};
|
||||
struct rsnd_regmap_field_conf conf_scu[] = {
|
||||
RSND_GEN_M_REG(SRC_BUSIF_MODE, 0x0, 0x20),
|
||||
|
||||
const static struct rsnd_regmap_field_conf conf_scu[] = {
|
||||
RSND_GEN_M_REG(SRC_I_BUSIF_MODE,0x0, 0x20),
|
||||
RSND_GEN_M_REG(SRC_O_BUSIF_MODE,0x4, 0x20),
|
||||
RSND_GEN_M_REG(SRC_BUSIF_DALIGN,0x8, 0x20),
|
||||
RSND_GEN_M_REG(SRC_ROUTE_MODE0, 0xc, 0x20),
|
||||
RSND_GEN_M_REG(SRC_CTRL, 0x10, 0x20),
|
||||
RSND_GEN_M_REG(SRC_INT_ENABLE0, 0x18, 0x20),
|
||||
RSND_GEN_M_REG(CMD_BUSIF_DALIGN,0x188, 0x20),
|
||||
RSND_GEN_M_REG(CMD_ROUTE_SLCT, 0x18c, 0x20),
|
||||
RSND_GEN_M_REG(CMD_CTRL, 0x190, 0x20),
|
||||
RSND_GEN_S_REG(SCU_SYS_STATUS0, 0x1c8),
|
||||
@@ -266,9 +282,15 @@ static int rsnd_gen2_probe(struct platform_device *pdev,
|
||||
RSND_GEN_M_REG(DVC_VRDBR, 0xe20, 0x100),
|
||||
RSND_GEN_M_REG(DVC_VOL0R, 0xe28, 0x100),
|
||||
RSND_GEN_M_REG(DVC_VOL1R, 0xe2c, 0x100),
|
||||
RSND_GEN_M_REG(DVC_VOL2R, 0xe30, 0x100),
|
||||
RSND_GEN_M_REG(DVC_VOL3R, 0xe34, 0x100),
|
||||
RSND_GEN_M_REG(DVC_VOL4R, 0xe38, 0x100),
|
||||
RSND_GEN_M_REG(DVC_VOL5R, 0xe3c, 0x100),
|
||||
RSND_GEN_M_REG(DVC_VOL6R, 0xe40, 0x100),
|
||||
RSND_GEN_M_REG(DVC_VOL7R, 0xe44, 0x100),
|
||||
RSND_GEN_M_REG(DVC_DVUER, 0xe48, 0x100),
|
||||
};
|
||||
struct rsnd_regmap_field_conf conf_adg[] = {
|
||||
const static struct rsnd_regmap_field_conf conf_adg[] = {
|
||||
RSND_GEN_S_REG(BRRA, 0x00),
|
||||
RSND_GEN_S_REG(BRRB, 0x04),
|
||||
RSND_GEN_S_REG(SSICKR, 0x08),
|
||||
@@ -288,7 +310,7 @@ static int rsnd_gen2_probe(struct platform_device *pdev,
|
||||
RSND_GEN_S_REG(SRCOUT_TIMSEL4, 0x58),
|
||||
RSND_GEN_S_REG(CMDOUT_TIMSEL, 0x5c),
|
||||
};
|
||||
struct rsnd_regmap_field_conf conf_ssi[] = {
|
||||
const static struct rsnd_regmap_field_conf conf_ssi[] = {
|
||||
RSND_GEN_M_REG(SSICR, 0x00, 0x40),
|
||||
RSND_GEN_M_REG(SSISR, 0x04, 0x40),
|
||||
RSND_GEN_M_REG(SSITDR, 0x08, 0x40),
|
||||
@@ -317,65 +339,30 @@ static int rsnd_gen2_probe(struct platform_device *pdev,
|
||||
* Gen1
|
||||
*/
|
||||
|
||||
static int rsnd_gen1_probe(struct platform_device *pdev,
|
||||
struct rsnd_priv *priv)
|
||||
static int rsnd_gen1_probe(struct rsnd_priv *priv)
|
||||
{
|
||||
struct rsnd_regmap_field_conf conf_sru[] = {
|
||||
RSND_GEN_S_REG(SRC_ROUTE_SEL, 0x00),
|
||||
RSND_GEN_S_REG(SRC_TMG_SEL0, 0x08),
|
||||
RSND_GEN_S_REG(SRC_TMG_SEL1, 0x0c),
|
||||
RSND_GEN_S_REG(SRC_TMG_SEL2, 0x10),
|
||||
RSND_GEN_S_REG(SRC_ROUTE_CTRL, 0xc0),
|
||||
RSND_GEN_S_REG(SSI_MODE0, 0xD0),
|
||||
RSND_GEN_S_REG(SSI_MODE1, 0xD4),
|
||||
RSND_GEN_M_REG(SRC_BUSIF_MODE, 0x20, 0x4),
|
||||
RSND_GEN_M_REG(SRC_ROUTE_MODE0, 0x50, 0x8),
|
||||
RSND_GEN_M_REG(SRC_SWRSR, 0x200, 0x40),
|
||||
RSND_GEN_M_REG(SRC_SRCIR, 0x204, 0x40),
|
||||
RSND_GEN_M_REG(SRC_ADINR, 0x214, 0x40),
|
||||
RSND_GEN_M_REG(SRC_IFSCR, 0x21c, 0x40),
|
||||
RSND_GEN_M_REG(SRC_IFSVR, 0x220, 0x40),
|
||||
RSND_GEN_M_REG(SRC_SRCCR, 0x224, 0x40),
|
||||
RSND_GEN_M_REG(SRC_MNFSR, 0x228, 0x40),
|
||||
/*
|
||||
* ADD US
|
||||
*
|
||||
* SRC_STATUS
|
||||
* SRC_INT_EN
|
||||
* SCU_SYS_STATUS0
|
||||
* SCU_SYS_STATUS1
|
||||
* SCU_SYS_INT_EN0
|
||||
* SCU_SYS_INT_EN1
|
||||
*/
|
||||
};
|
||||
struct rsnd_regmap_field_conf conf_adg[] = {
|
||||
const static struct rsnd_regmap_field_conf conf_adg[] = {
|
||||
RSND_GEN_S_REG(BRRA, 0x00),
|
||||
RSND_GEN_S_REG(BRRB, 0x04),
|
||||
RSND_GEN_S_REG(SSICKR, 0x08),
|
||||
RSND_GEN_S_REG(AUDIO_CLK_SEL0, 0x0c),
|
||||
RSND_GEN_S_REG(AUDIO_CLK_SEL1, 0x10),
|
||||
RSND_GEN_S_REG(AUDIO_CLK_SEL3, 0x18),
|
||||
RSND_GEN_S_REG(AUDIO_CLK_SEL4, 0x1c),
|
||||
RSND_GEN_S_REG(AUDIO_CLK_SEL5, 0x20),
|
||||
};
|
||||
struct rsnd_regmap_field_conf conf_ssi[] = {
|
||||
const static struct rsnd_regmap_field_conf conf_ssi[] = {
|
||||
RSND_GEN_M_REG(SSICR, 0x00, 0x40),
|
||||
RSND_GEN_M_REG(SSISR, 0x04, 0x40),
|
||||
RSND_GEN_M_REG(SSITDR, 0x08, 0x40),
|
||||
RSND_GEN_M_REG(SSIRDR, 0x0c, 0x40),
|
||||
RSND_GEN_M_REG(SSIWSR, 0x20, 0x40),
|
||||
};
|
||||
int ret_sru;
|
||||
int ret_adg;
|
||||
int ret_ssi;
|
||||
|
||||
ret_sru = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_SRU, "sru", conf_sru);
|
||||
ret_adg = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_ADG, "adg", conf_adg);
|
||||
ret_ssi = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_SSI, "ssi", conf_ssi);
|
||||
if (ret_sru < 0 ||
|
||||
ret_adg < 0 ||
|
||||
if (ret_adg < 0 ||
|
||||
ret_ssi < 0)
|
||||
return ret_sru | ret_adg | ret_ssi;
|
||||
return ret_adg | ret_ssi;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -383,28 +370,12 @@ static int rsnd_gen1_probe(struct platform_device *pdev,
|
||||
/*
|
||||
* 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,
|
||||
const struct rsnd_of_data *of_data,
|
||||
struct rsnd_priv *priv)
|
||||
int rsnd_gen_probe(struct rsnd_priv *priv)
|
||||
{
|
||||
struct device *dev = rsnd_priv_to_dev(priv);
|
||||
struct rsnd_gen *gen;
|
||||
int ret;
|
||||
|
||||
rsnd_of_parse_gen(pdev, of_data, priv);
|
||||
|
||||
gen = devm_kzalloc(dev, sizeof(*gen), GFP_KERNEL);
|
||||
if (!gen) {
|
||||
dev_err(dev, "GEN allocate failed\n");
|
||||
@@ -415,9 +386,9 @@ int rsnd_gen_probe(struct platform_device *pdev,
|
||||
|
||||
ret = -ENODEV;
|
||||
if (rsnd_is_gen1(priv))
|
||||
ret = rsnd_gen1_probe(pdev, priv);
|
||||
ret = rsnd_gen1_probe(priv);
|
||||
else if (rsnd_is_gen2(priv))
|
||||
ret = rsnd_gen2_probe(pdev, priv);
|
||||
ret = rsnd_gen2_probe(priv);
|
||||
|
||||
if (ret < 0)
|
||||
dev_err(dev, "unknown generation R-Car sound device\n");
|
||||
|
@@ -13,10 +13,10 @@
|
||||
#define MIX_NAME "mix"
|
||||
|
||||
struct rsnd_mix {
|
||||
struct rsnd_mix_platform_info *info; /* rcar_snd.h */
|
||||
struct rsnd_mod mod;
|
||||
};
|
||||
|
||||
#define rsnd_mix_get(priv, id) ((struct rsnd_mix *)(priv->mix) + id)
|
||||
#define rsnd_mix_nr(priv) ((priv)->mix_nr)
|
||||
#define for_each_rsnd_mix(pos, priv, i) \
|
||||
for ((i) = 0; \
|
||||
@@ -24,58 +24,77 @@ struct rsnd_mix {
|
||||
((pos) = (struct rsnd_mix *)(priv)->mix + i); \
|
||||
i++)
|
||||
|
||||
|
||||
static void rsnd_mix_soft_reset(struct rsnd_mod *mod)
|
||||
static void rsnd_mix_activation(struct rsnd_mod *mod)
|
||||
{
|
||||
rsnd_mod_write(mod, MIX_SWRSR, 0);
|
||||
rsnd_mod_write(mod, MIX_SWRSR, 1);
|
||||
}
|
||||
|
||||
#define rsnd_mix_initialize_lock(mod) __rsnd_mix_initialize_lock(mod, 1)
|
||||
#define rsnd_mix_initialize_unlock(mod) __rsnd_mix_initialize_lock(mod, 0)
|
||||
static void __rsnd_mix_initialize_lock(struct rsnd_mod *mod, u32 enable)
|
||||
static void rsnd_mix_halt(struct rsnd_mod *mod)
|
||||
{
|
||||
rsnd_mod_write(mod, MIX_MIXIR, enable);
|
||||
rsnd_mod_write(mod, MIX_MIXIR, 1);
|
||||
rsnd_mod_write(mod, MIX_SWRSR, 0);
|
||||
}
|
||||
|
||||
static void rsnd_mix_volume_parameter(struct rsnd_dai_stream *io,
|
||||
struct rsnd_mod *mod)
|
||||
{
|
||||
rsnd_mod_write(mod, MIX_MDBAR, 0);
|
||||
rsnd_mod_write(mod, MIX_MDBBR, 0);
|
||||
rsnd_mod_write(mod, MIX_MDBCR, 0);
|
||||
rsnd_mod_write(mod, MIX_MDBDR, 0);
|
||||
}
|
||||
|
||||
static void rsnd_mix_volume_init(struct rsnd_dai_stream *io,
|
||||
struct rsnd_mod *mod)
|
||||
{
|
||||
rsnd_mod_write(mod, MIX_MIXIR, 1);
|
||||
|
||||
/* General Information */
|
||||
rsnd_mod_write(mod, MIX_ADINR, rsnd_get_adinr_chan(mod, io));
|
||||
|
||||
/* volume step */
|
||||
rsnd_mod_write(mod, MIX_MIXMR, 0);
|
||||
rsnd_mod_write(mod, MIX_MVPDR, 0);
|
||||
|
||||
/* common volume parameter */
|
||||
rsnd_mix_volume_parameter(io, mod);
|
||||
|
||||
rsnd_mod_write(mod, MIX_MIXIR, 0);
|
||||
}
|
||||
|
||||
static void rsnd_mix_volume_update(struct rsnd_dai_stream *io,
|
||||
struct rsnd_mod *mod)
|
||||
{
|
||||
|
||||
/* Disable MIX dB setting */
|
||||
rsnd_mod_write(mod, MIX_MDBER, 0);
|
||||
|
||||
rsnd_mod_write(mod, MIX_MDBAR, 0);
|
||||
rsnd_mod_write(mod, MIX_MDBBR, 0);
|
||||
rsnd_mod_write(mod, MIX_MDBCR, 0);
|
||||
rsnd_mod_write(mod, MIX_MDBDR, 0);
|
||||
/* common volume parameter */
|
||||
rsnd_mix_volume_parameter(io, mod);
|
||||
|
||||
/* Enable MIX dB setting */
|
||||
rsnd_mod_write(mod, MIX_MDBER, 1);
|
||||
}
|
||||
|
||||
static int rsnd_mix_probe_(struct rsnd_mod *mod,
|
||||
struct rsnd_dai_stream *io,
|
||||
struct rsnd_priv *priv)
|
||||
{
|
||||
return rsnd_cmd_attach(io, rsnd_mod_id(mod));
|
||||
}
|
||||
|
||||
static int rsnd_mix_init(struct rsnd_mod *mod,
|
||||
struct rsnd_dai_stream *io,
|
||||
struct rsnd_priv *priv)
|
||||
{
|
||||
rsnd_mod_power_on(mod);
|
||||
|
||||
rsnd_mix_soft_reset(mod);
|
||||
rsnd_mix_activation(mod);
|
||||
|
||||
rsnd_mix_initialize_lock(mod);
|
||||
|
||||
rsnd_mod_write(mod, MIX_ADINR, rsnd_get_adinr_chan(mod, io));
|
||||
|
||||
rsnd_path_parse(priv, io);
|
||||
|
||||
/* volume step */
|
||||
rsnd_mod_write(mod, MIX_MIXMR, 0);
|
||||
rsnd_mod_write(mod, MIX_MVPDR, 0);
|
||||
rsnd_mix_volume_init(io, mod);
|
||||
|
||||
rsnd_mix_volume_update(io, mod);
|
||||
|
||||
rsnd_mix_initialize_unlock(mod);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -83,6 +102,8 @@ static int rsnd_mix_quit(struct rsnd_mod *mod,
|
||||
struct rsnd_dai_stream *io,
|
||||
struct rsnd_priv *priv)
|
||||
{
|
||||
rsnd_mix_halt(mod);
|
||||
|
||||
rsnd_mod_power_off(mod);
|
||||
|
||||
return 0;
|
||||
@@ -90,6 +111,7 @@ static int rsnd_mix_quit(struct rsnd_mod *mod,
|
||||
|
||||
static struct rsnd_mod_ops rsnd_mix_ops = {
|
||||
.name = MIX_NAME,
|
||||
.probe = rsnd_mix_probe_,
|
||||
.init = rsnd_mix_init,
|
||||
.quit = rsnd_mix_quit,
|
||||
};
|
||||
@@ -99,51 +121,13 @@ struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id)
|
||||
if (WARN_ON(id < 0 || id >= rsnd_mix_nr(priv)))
|
||||
id = 0;
|
||||
|
||||
return rsnd_mod_get((struct rsnd_mix *)(priv->mix) + id);
|
||||
return rsnd_mod_get(rsnd_mix_get(priv, id));
|
||||
}
|
||||
|
||||
static void rsnd_of_parse_mix(struct platform_device *pdev,
|
||||
const struct rsnd_of_data *of_data,
|
||||
struct rsnd_priv *priv)
|
||||
int rsnd_mix_probe(struct rsnd_priv *priv)
|
||||
{
|
||||
struct device_node *node;
|
||||
struct rsnd_mix_platform_info *mix_info;
|
||||
struct rcar_snd_info *info = rsnd_priv_to_info(priv);
|
||||
struct device *dev = &pdev->dev;
|
||||
int nr;
|
||||
|
||||
if (!of_data)
|
||||
return;
|
||||
|
||||
node = of_get_child_by_name(dev->of_node, "rcar_sound,mix");
|
||||
if (!node)
|
||||
return;
|
||||
|
||||
nr = of_get_child_count(node);
|
||||
if (!nr)
|
||||
goto rsnd_of_parse_mix_end;
|
||||
|
||||
mix_info = devm_kzalloc(dev,
|
||||
sizeof(struct rsnd_mix_platform_info) * nr,
|
||||
GFP_KERNEL);
|
||||
if (!mix_info) {
|
||||
dev_err(dev, "mix info allocation error\n");
|
||||
goto rsnd_of_parse_mix_end;
|
||||
}
|
||||
|
||||
info->mix_info = mix_info;
|
||||
info->mix_info_nr = nr;
|
||||
|
||||
rsnd_of_parse_mix_end:
|
||||
of_node_put(node);
|
||||
|
||||
}
|
||||
|
||||
int rsnd_mix_probe(struct platform_device *pdev,
|
||||
const struct rsnd_of_data *of_data,
|
||||
struct rsnd_priv *priv)
|
||||
{
|
||||
struct rcar_snd_info *info = rsnd_priv_to_info(priv);
|
||||
struct device_node *np;
|
||||
struct device *dev = rsnd_priv_to_dev(priv);
|
||||
struct rsnd_mix *mix;
|
||||
struct clk *clk;
|
||||
@@ -154,40 +138,54 @@ int rsnd_mix_probe(struct platform_device *pdev,
|
||||
if (rsnd_is_gen1(priv))
|
||||
return 0;
|
||||
|
||||
rsnd_of_parse_mix(pdev, of_data, priv);
|
||||
node = rsnd_mix_of_node(priv);
|
||||
if (!node)
|
||||
return 0; /* not used is not error */
|
||||
|
||||
nr = info->mix_info_nr;
|
||||
if (!nr)
|
||||
return 0;
|
||||
nr = of_get_child_count(node);
|
||||
if (!nr) {
|
||||
ret = -EINVAL;
|
||||
goto rsnd_mix_probe_done;
|
||||
}
|
||||
|
||||
mix = devm_kzalloc(dev, sizeof(*mix) * nr, GFP_KERNEL);
|
||||
if (!mix)
|
||||
return -ENOMEM;
|
||||
if (!mix) {
|
||||
ret = -ENOMEM;
|
||||
goto rsnd_mix_probe_done;
|
||||
}
|
||||
|
||||
priv->mix_nr = nr;
|
||||
priv->mix = mix;
|
||||
|
||||
for_each_rsnd_mix(mix, priv, i) {
|
||||
i = 0;
|
||||
ret = 0;
|
||||
for_each_child_of_node(node, np) {
|
||||
mix = rsnd_mix_get(priv, i);
|
||||
|
||||
snprintf(name, MIX_NAME_SIZE, "%s.%d",
|
||||
MIX_NAME, i);
|
||||
|
||||
clk = devm_clk_get(dev, name);
|
||||
if (IS_ERR(clk))
|
||||
return PTR_ERR(clk);
|
||||
|
||||
mix->info = &info->mix_info[i];
|
||||
if (IS_ERR(clk)) {
|
||||
ret = PTR_ERR(clk);
|
||||
goto rsnd_mix_probe_done;
|
||||
}
|
||||
|
||||
ret = rsnd_mod_init(priv, rsnd_mod_get(mix), &rsnd_mix_ops,
|
||||
clk, RSND_MOD_MIX, i);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto rsnd_mix_probe_done;
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
rsnd_mix_probe_done:
|
||||
of_node_put(node);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void rsnd_mix_remove(struct platform_device *pdev,
|
||||
struct rsnd_priv *priv)
|
||||
void rsnd_mix_remove(struct rsnd_priv *priv)
|
||||
{
|
||||
struct rsnd_mix *mix;
|
||||
int i;
|
||||
|
@@ -1,117 +0,0 @@
|
||||
/*
|
||||
* Renesas R-Car SRU/SCU/SSIU/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.
|
||||
*/
|
||||
|
||||
#ifndef RCAR_SND_H
|
||||
#define RCAR_SND_H
|
||||
|
||||
|
||||
#define RSND_GEN1_SRU 0
|
||||
#define RSND_GEN1_ADG 1
|
||||
#define RSND_GEN1_SSI 2
|
||||
|
||||
#define RSND_GEN2_SCU 0
|
||||
#define RSND_GEN2_ADG 1
|
||||
#define RSND_GEN2_SSIU 2
|
||||
#define RSND_GEN2_SSI 3
|
||||
|
||||
#define RSND_BASE_MAX 4
|
||||
|
||||
/*
|
||||
* flags
|
||||
*
|
||||
* 0xAB000000
|
||||
*
|
||||
* A : clock sharing settings
|
||||
* B : SSI direction
|
||||
*/
|
||||
#define RSND_SSI_CLK_PIN_SHARE (1 << 31)
|
||||
#define RSND_SSI_NO_BUSIF (1 << 30) /* SSI+DMA without BUSIF */
|
||||
|
||||
#define RSND_SSI(_dma_id, _irq, _flags) \
|
||||
{ .dma_id = _dma_id, .irq = _irq, .flags = _flags }
|
||||
#define RSND_SSI_UNUSED \
|
||||
{ .dma_id = -1, .irq = -1, .flags = 0 }
|
||||
|
||||
struct rsnd_ssi_platform_info {
|
||||
int dma_id;
|
||||
int irq;
|
||||
u32 flags;
|
||||
};
|
||||
|
||||
#define RSND_SRC(rate, _dma_id) \
|
||||
{ .convert_rate = rate, .dma_id = _dma_id, }
|
||||
#define RSND_SRC_UNUSED \
|
||||
{ .convert_rate = 0, .dma_id = -1, }
|
||||
|
||||
struct rsnd_src_platform_info {
|
||||
u32 convert_rate; /* sampling rate convert */
|
||||
int dma_id; /* for Gen2 SCU */
|
||||
int irq;
|
||||
};
|
||||
|
||||
/*
|
||||
* flags
|
||||
*/
|
||||
struct rsnd_ctu_platform_info {
|
||||
u32 flags;
|
||||
};
|
||||
|
||||
struct rsnd_mix_platform_info {
|
||||
u32 flags;
|
||||
};
|
||||
|
||||
struct rsnd_dvc_platform_info {
|
||||
u32 flags;
|
||||
};
|
||||
|
||||
struct rsnd_dai_path_info {
|
||||
struct rsnd_ssi_platform_info *ssi;
|
||||
struct rsnd_src_platform_info *src;
|
||||
struct rsnd_ctu_platform_info *ctu;
|
||||
struct rsnd_mix_platform_info *mix;
|
||||
struct rsnd_dvc_platform_info *dvc;
|
||||
};
|
||||
|
||||
struct rsnd_dai_platform_info {
|
||||
struct rsnd_dai_path_info playback;
|
||||
struct rsnd_dai_path_info capture;
|
||||
};
|
||||
|
||||
/*
|
||||
* flags
|
||||
*
|
||||
* 0x0000000A
|
||||
*
|
||||
* A : generation
|
||||
*/
|
||||
#define RSND_GEN_MASK (0xF << 0)
|
||||
#define RSND_GEN1 (1 << 0) /* fixme */
|
||||
#define RSND_GEN2 (2 << 0) /* fixme */
|
||||
|
||||
struct rcar_snd_info {
|
||||
u32 flags;
|
||||
struct rsnd_ssi_platform_info *ssi_info;
|
||||
int ssi_info_nr;
|
||||
struct rsnd_src_platform_info *src_info;
|
||||
int src_info_nr;
|
||||
struct rsnd_ctu_platform_info *ctu_info;
|
||||
int ctu_info_nr;
|
||||
struct rsnd_mix_platform_info *mix_info;
|
||||
int mix_info_nr;
|
||||
struct rsnd_dvc_platform_info *dvc_info;
|
||||
int dvc_info_nr;
|
||||
struct rsnd_dai_platform_info *dai_info;
|
||||
int dai_info_nr;
|
||||
int (*start)(int id);
|
||||
int (*stop)(int id);
|
||||
};
|
||||
|
||||
#endif
|
@@ -24,7 +24,16 @@
|
||||
#include <sound/soc.h>
|
||||
#include <sound/pcm_params.h>
|
||||
|
||||
#include "rcar_snd.h"
|
||||
#define RSND_GEN1_SRU 0
|
||||
#define RSND_GEN1_ADG 1
|
||||
#define RSND_GEN1_SSI 2
|
||||
|
||||
#define RSND_GEN2_SCU 0
|
||||
#define RSND_GEN2_ADG 1
|
||||
#define RSND_GEN2_SSIU 2
|
||||
#define RSND_GEN2_SSI 3
|
||||
|
||||
#define RSND_BASE_MAX 4
|
||||
|
||||
/*
|
||||
* pseudo register
|
||||
@@ -34,10 +43,19 @@
|
||||
* see gen1/gen2 for detail
|
||||
*/
|
||||
enum rsnd_reg {
|
||||
/* SRU/SCU/SSIU */
|
||||
/* SCU (SRC/SSIU/MIX/CTU/DVC) */
|
||||
RSND_REG_SSI_MODE, /* Gen2 only */
|
||||
RSND_REG_SSI_MODE0,
|
||||
RSND_REG_SSI_MODE1,
|
||||
RSND_REG_SRC_BUSIF_MODE,
|
||||
RSND_REG_SSI_MODE2,
|
||||
RSND_REG_SSI_CONTROL,
|
||||
RSND_REG_SSI_CTRL, /* Gen2 only */
|
||||
RSND_REG_SSI_BUSIF_MODE, /* Gen2 only */
|
||||
RSND_REG_SSI_BUSIF_ADINR, /* Gen2 only */
|
||||
RSND_REG_SSI_BUSIF_DALIGN, /* Gen2 only */
|
||||
RSND_REG_SSI_INT_ENABLE, /* Gen2 only */
|
||||
RSND_REG_SRC_I_BUSIF_MODE,
|
||||
RSND_REG_SRC_O_BUSIF_MODE,
|
||||
RSND_REG_SRC_ROUTE_MODE0,
|
||||
RSND_REG_SRC_SWRSR,
|
||||
RSND_REG_SRC_SRCIR,
|
||||
@@ -45,9 +63,29 @@ enum rsnd_reg {
|
||||
RSND_REG_SRC_IFSCR,
|
||||
RSND_REG_SRC_IFSVR,
|
||||
RSND_REG_SRC_SRCCR,
|
||||
RSND_REG_SRC_CTRL, /* Gen2 only */
|
||||
RSND_REG_SRC_BSDSR, /* Gen2 only */
|
||||
RSND_REG_SRC_BSISR, /* Gen2 only */
|
||||
RSND_REG_SRC_INT_ENABLE0, /* Gen2 only */
|
||||
RSND_REG_SRC_BUSIF_DALIGN, /* Gen2 only */
|
||||
RSND_REG_SRCIN_TIMSEL0, /* Gen2 only */
|
||||
RSND_REG_SRCIN_TIMSEL1, /* Gen2 only */
|
||||
RSND_REG_SRCIN_TIMSEL2, /* Gen2 only */
|
||||
RSND_REG_SRCIN_TIMSEL3, /* Gen2 only */
|
||||
RSND_REG_SRCIN_TIMSEL4, /* Gen2 only */
|
||||
RSND_REG_SRCOUT_TIMSEL0, /* Gen2 only */
|
||||
RSND_REG_SRCOUT_TIMSEL1, /* Gen2 only */
|
||||
RSND_REG_SRCOUT_TIMSEL2, /* Gen2 only */
|
||||
RSND_REG_SRCOUT_TIMSEL3, /* Gen2 only */
|
||||
RSND_REG_SRCOUT_TIMSEL4, /* Gen2 only */
|
||||
RSND_REG_SCU_SYS_STATUS0,
|
||||
RSND_REG_SCU_SYS_STATUS1, /* Gen2 only */
|
||||
RSND_REG_SCU_SYS_INT_EN0,
|
||||
RSND_REG_SCU_SYS_INT_EN1, /* Gen2 only */
|
||||
RSND_REG_CMD_CTRL, /* Gen2 only */
|
||||
RSND_REG_CMD_BUSIF_DALIGN, /* Gen2 only */
|
||||
RSND_REG_CMD_ROUTE_SLCT,
|
||||
RSND_REG_CMDOUT_TIMSEL, /* Gen2 only */
|
||||
RSND_REG_CTU_CTUIR,
|
||||
RSND_REG_CTU_ADINR,
|
||||
RSND_REG_MIX_SWRSR,
|
||||
@@ -67,14 +105,25 @@ enum rsnd_reg {
|
||||
RSND_REG_DVC_ZCMCR,
|
||||
RSND_REG_DVC_VOL0R,
|
||||
RSND_REG_DVC_VOL1R,
|
||||
RSND_REG_DVC_VOL2R,
|
||||
RSND_REG_DVC_VOL3R,
|
||||
RSND_REG_DVC_VOL4R,
|
||||
RSND_REG_DVC_VOL5R,
|
||||
RSND_REG_DVC_VOL6R,
|
||||
RSND_REG_DVC_VOL7R,
|
||||
RSND_REG_DVC_DVUER,
|
||||
RSND_REG_DVC_VRCTR, /* Gen2 only */
|
||||
RSND_REG_DVC_VRPDR, /* Gen2 only */
|
||||
RSND_REG_DVC_VRDBR, /* Gen2 only */
|
||||
|
||||
/* ADG */
|
||||
RSND_REG_BRRA,
|
||||
RSND_REG_BRRB,
|
||||
RSND_REG_SSICKR,
|
||||
RSND_REG_DIV_EN, /* Gen2 only */
|
||||
RSND_REG_AUDIO_CLK_SEL0,
|
||||
RSND_REG_AUDIO_CLK_SEL1,
|
||||
RSND_REG_AUDIO_CLK_SEL2, /* Gen2 only */
|
||||
|
||||
/* SSI */
|
||||
RSND_REG_SSICR,
|
||||
@@ -83,83 +132,9 @@ enum rsnd_reg {
|
||||
RSND_REG_SSIRDR,
|
||||
RSND_REG_SSIWSR,
|
||||
|
||||
/* SHARE see below */
|
||||
RSND_REG_SHARE01,
|
||||
RSND_REG_SHARE02,
|
||||
RSND_REG_SHARE03,
|
||||
RSND_REG_SHARE04,
|
||||
RSND_REG_SHARE05,
|
||||
RSND_REG_SHARE06,
|
||||
RSND_REG_SHARE07,
|
||||
RSND_REG_SHARE08,
|
||||
RSND_REG_SHARE09,
|
||||
RSND_REG_SHARE10,
|
||||
RSND_REG_SHARE11,
|
||||
RSND_REG_SHARE12,
|
||||
RSND_REG_SHARE13,
|
||||
RSND_REG_SHARE14,
|
||||
RSND_REG_SHARE15,
|
||||
RSND_REG_SHARE16,
|
||||
RSND_REG_SHARE17,
|
||||
RSND_REG_SHARE18,
|
||||
RSND_REG_SHARE19,
|
||||
RSND_REG_SHARE20,
|
||||
RSND_REG_SHARE21,
|
||||
RSND_REG_SHARE22,
|
||||
RSND_REG_SHARE23,
|
||||
RSND_REG_SHARE24,
|
||||
RSND_REG_SHARE25,
|
||||
RSND_REG_SHARE26,
|
||||
RSND_REG_SHARE27,
|
||||
RSND_REG_SHARE28,
|
||||
RSND_REG_SHARE29,
|
||||
|
||||
RSND_REG_MAX,
|
||||
};
|
||||
|
||||
/* Gen1 only */
|
||||
#define RSND_REG_SRC_ROUTE_SEL RSND_REG_SHARE01
|
||||
#define RSND_REG_SRC_TMG_SEL0 RSND_REG_SHARE02
|
||||
#define RSND_REG_SRC_TMG_SEL1 RSND_REG_SHARE03
|
||||
#define RSND_REG_SRC_TMG_SEL2 RSND_REG_SHARE04
|
||||
#define RSND_REG_SRC_ROUTE_CTRL RSND_REG_SHARE05
|
||||
#define RSND_REG_SRC_MNFSR RSND_REG_SHARE06
|
||||
#define RSND_REG_AUDIO_CLK_SEL3 RSND_REG_SHARE07
|
||||
#define RSND_REG_AUDIO_CLK_SEL4 RSND_REG_SHARE08
|
||||
#define RSND_REG_AUDIO_CLK_SEL5 RSND_REG_SHARE09
|
||||
|
||||
/* Gen2 only */
|
||||
#define RSND_REG_SRC_CTRL RSND_REG_SHARE01
|
||||
#define RSND_REG_SSI_CTRL RSND_REG_SHARE02
|
||||
#define RSND_REG_SSI_BUSIF_MODE RSND_REG_SHARE03
|
||||
#define RSND_REG_SSI_BUSIF_ADINR RSND_REG_SHARE04
|
||||
#define RSND_REG_SSI_INT_ENABLE RSND_REG_SHARE05
|
||||
#define RSND_REG_SRC_BSDSR RSND_REG_SHARE06
|
||||
#define RSND_REG_SRC_BSISR RSND_REG_SHARE07
|
||||
#define RSND_REG_DIV_EN RSND_REG_SHARE08
|
||||
#define RSND_REG_SRCIN_TIMSEL0 RSND_REG_SHARE09
|
||||
#define RSND_REG_SRCIN_TIMSEL1 RSND_REG_SHARE10
|
||||
#define RSND_REG_SRCIN_TIMSEL2 RSND_REG_SHARE11
|
||||
#define RSND_REG_SRCIN_TIMSEL3 RSND_REG_SHARE12
|
||||
#define RSND_REG_SRCIN_TIMSEL4 RSND_REG_SHARE13
|
||||
#define RSND_REG_SRCOUT_TIMSEL0 RSND_REG_SHARE14
|
||||
#define RSND_REG_SRCOUT_TIMSEL1 RSND_REG_SHARE15
|
||||
#define RSND_REG_SRCOUT_TIMSEL2 RSND_REG_SHARE16
|
||||
#define RSND_REG_SRCOUT_TIMSEL3 RSND_REG_SHARE17
|
||||
#define RSND_REG_SRCOUT_TIMSEL4 RSND_REG_SHARE18
|
||||
#define RSND_REG_AUDIO_CLK_SEL2 RSND_REG_SHARE19
|
||||
#define RSND_REG_CMD_CTRL RSND_REG_SHARE20
|
||||
#define RSND_REG_CMDOUT_TIMSEL RSND_REG_SHARE21
|
||||
#define RSND_REG_SSI_BUSIF_DALIGN RSND_REG_SHARE22
|
||||
#define RSND_REG_DVC_VRCTR RSND_REG_SHARE23
|
||||
#define RSND_REG_DVC_VRPDR RSND_REG_SHARE24
|
||||
#define RSND_REG_DVC_VRDBR RSND_REG_SHARE25
|
||||
#define RSND_REG_SCU_SYS_STATUS1 RSND_REG_SHARE26
|
||||
#define RSND_REG_SCU_SYS_INT_EN1 RSND_REG_SHARE27
|
||||
#define RSND_REG_SRC_INT_ENABLE0 RSND_REG_SHARE28
|
||||
#define RSND_REG_SRC_BUSIF_DALIGN RSND_REG_SHARE29
|
||||
|
||||
struct rsnd_of_data;
|
||||
struct rsnd_priv;
|
||||
struct rsnd_mod;
|
||||
struct rsnd_dai;
|
||||
@@ -187,43 +162,13 @@ void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg,
|
||||
u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io);
|
||||
u32 rsnd_get_adinr_chan(struct rsnd_mod *mod, struct rsnd_dai_stream *io);
|
||||
u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io);
|
||||
void rsnd_path_parse(struct rsnd_priv *priv,
|
||||
struct rsnd_dai_stream *io);
|
||||
|
||||
/*
|
||||
* R-Car DMA
|
||||
*/
|
||||
struct rsnd_dma;
|
||||
|
||||
struct rsnd_dmaen {
|
||||
struct dma_chan *chan;
|
||||
};
|
||||
|
||||
struct rsnd_dmapp {
|
||||
int dmapp_id;
|
||||
u32 chcr;
|
||||
};
|
||||
|
||||
struct rsnd_dma {
|
||||
struct rsnd_dma_ops *ops;
|
||||
dma_addr_t src_addr;
|
||||
dma_addr_t dst_addr;
|
||||
union {
|
||||
struct rsnd_dmaen en;
|
||||
struct rsnd_dmapp pp;
|
||||
} dma;
|
||||
};
|
||||
#define rsnd_dma_to_dmaen(dma) (&(dma)->dma.en)
|
||||
#define rsnd_dma_to_dmapp(dma) (&(dma)->dma.pp)
|
||||
#define rsnd_dma_to_mod(_dma) container_of((_dma), struct rsnd_mod, dma)
|
||||
|
||||
void rsnd_dma_start(struct rsnd_dai_stream *io, struct rsnd_dma *dma);
|
||||
void rsnd_dma_stop(struct rsnd_dai_stream *io, struct rsnd_dma *dma);
|
||||
int rsnd_dma_init(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id);
|
||||
void rsnd_dma_quit(struct rsnd_dai_stream *io, struct rsnd_dma *dma);
|
||||
int rsnd_dma_probe(struct platform_device *pdev,
|
||||
const struct rsnd_of_data *of_data,
|
||||
struct rsnd_priv *priv);
|
||||
struct rsnd_mod *rsnd_dma_attach(struct rsnd_dai_stream *io,
|
||||
struct rsnd_mod *mod, int id);
|
||||
int rsnd_dma_probe(struct rsnd_priv *priv);
|
||||
struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node,
|
||||
struct rsnd_mod *mod, char *name);
|
||||
|
||||
@@ -231,11 +176,19 @@ struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node,
|
||||
* R-Car sound mod
|
||||
*/
|
||||
enum rsnd_mod_type {
|
||||
RSND_MOD_DVC = 0,
|
||||
RSND_MOD_AUDMAPP,
|
||||
RSND_MOD_AUDMA,
|
||||
RSND_MOD_DVC,
|
||||
RSND_MOD_MIX,
|
||||
RSND_MOD_CTU,
|
||||
RSND_MOD_CMD,
|
||||
RSND_MOD_SRC,
|
||||
RSND_MOD_SSIM3, /* SSI multi 3 */
|
||||
RSND_MOD_SSIM2, /* SSI multi 2 */
|
||||
RSND_MOD_SSIM1, /* SSI multi 1 */
|
||||
RSND_MOD_SSIP, /* SSI parent */
|
||||
RSND_MOD_SSI,
|
||||
RSND_MOD_SSIU,
|
||||
RSND_MOD_MAX,
|
||||
};
|
||||
|
||||
@@ -278,10 +231,8 @@ struct rsnd_mod {
|
||||
int id;
|
||||
enum rsnd_mod_type type;
|
||||
struct rsnd_mod_ops *ops;
|
||||
struct rsnd_dma dma;
|
||||
struct rsnd_priv *priv;
|
||||
struct clk *clk;
|
||||
u32 status;
|
||||
};
|
||||
/*
|
||||
* status
|
||||
@@ -328,7 +279,6 @@ struct rsnd_mod {
|
||||
#define __rsnd_mod_call_hw_params 0
|
||||
|
||||
#define rsnd_mod_to_priv(mod) ((mod)->priv)
|
||||
#define rsnd_mod_to_dma(mod) (&(mod)->dma)
|
||||
#define rsnd_mod_id(mod) ((mod) ? (mod)->id : -1)
|
||||
#define rsnd_mod_power_on(mod) clk_enable((mod)->clk)
|
||||
#define rsnd_mod_power_off(mod) clk_disable((mod)->clk)
|
||||
@@ -347,6 +297,17 @@ struct dma_chan *rsnd_mod_dma_req(struct rsnd_dai_stream *io,
|
||||
void rsnd_mod_interrupt(struct rsnd_mod *mod,
|
||||
void (*callback)(struct rsnd_mod *mod,
|
||||
struct rsnd_dai_stream *io));
|
||||
void rsnd_parse_connect_common(struct rsnd_dai *rdai,
|
||||
struct rsnd_mod* (*mod_get)(struct rsnd_priv *priv, int id),
|
||||
struct device_node *node,
|
||||
struct device_node *playback,
|
||||
struct device_node *capture);
|
||||
|
||||
void rsnd_set_slot(struct rsnd_dai *rdai,
|
||||
int slots, int slots_total);
|
||||
int rsnd_get_slot(struct rsnd_dai_stream *io);
|
||||
int rsnd_get_slot_width(struct rsnd_dai_stream *io);
|
||||
int rsnd_get_slot_num(struct rsnd_dai_stream *io);
|
||||
|
||||
/*
|
||||
* R-Car sound DAI
|
||||
@@ -358,6 +319,7 @@ struct rsnd_dai_stream {
|
||||
struct rsnd_mod *mod[RSND_MOD_MAX];
|
||||
struct rsnd_dai_path_info *info; /* rcar_snd.h */
|
||||
struct rsnd_dai *rdai;
|
||||
u32 mod_status[RSND_MOD_MAX];
|
||||
int byte_pos;
|
||||
int period_pos;
|
||||
int byte_per_period;
|
||||
@@ -365,10 +327,12 @@ struct rsnd_dai_stream {
|
||||
};
|
||||
#define rsnd_io_to_mod(io, i) ((i) < RSND_MOD_MAX ? (io)->mod[(i)] : NULL)
|
||||
#define rsnd_io_to_mod_ssi(io) rsnd_io_to_mod((io), RSND_MOD_SSI)
|
||||
#define rsnd_io_to_mod_ssip(io) rsnd_io_to_mod((io), RSND_MOD_SSIP)
|
||||
#define rsnd_io_to_mod_src(io) rsnd_io_to_mod((io), RSND_MOD_SRC)
|
||||
#define rsnd_io_to_mod_ctu(io) rsnd_io_to_mod((io), RSND_MOD_CTU)
|
||||
#define rsnd_io_to_mod_mix(io) rsnd_io_to_mod((io), RSND_MOD_MIX)
|
||||
#define rsnd_io_to_mod_dvc(io) rsnd_io_to_mod((io), RSND_MOD_DVC)
|
||||
#define rsnd_io_to_mod_cmd(io) rsnd_io_to_mod((io), RSND_MOD_CMD)
|
||||
#define rsnd_io_to_rdai(io) ((io)->rdai)
|
||||
#define rsnd_io_to_priv(io) (rsnd_rdai_to_priv(rsnd_io_to_rdai(io)))
|
||||
#define rsnd_io_is_play(io) (&rsnd_io_to_rdai(io)->playback == io)
|
||||
@@ -382,6 +346,9 @@ struct rsnd_dai {
|
||||
struct rsnd_dai_stream capture;
|
||||
struct rsnd_priv *priv;
|
||||
|
||||
int slots;
|
||||
int slots_num;
|
||||
|
||||
unsigned int clk_master:1;
|
||||
unsigned int bit_clk_inv:1;
|
||||
unsigned int frm_clk_inv:1;
|
||||
@@ -403,33 +370,28 @@ struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id);
|
||||
bool rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int cnt);
|
||||
void rsnd_dai_period_elapsed(struct rsnd_dai_stream *io);
|
||||
int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional);
|
||||
int rsnd_dai_connect(struct rsnd_mod *mod,
|
||||
struct rsnd_dai_stream *io,
|
||||
enum rsnd_mod_type type);
|
||||
#define rsnd_dai_of_node(priv) \
|
||||
of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,dai")
|
||||
|
||||
/*
|
||||
* R-Car Gen1/Gen2
|
||||
*/
|
||||
int rsnd_gen_probe(struct platform_device *pdev,
|
||||
const struct rsnd_of_data *of_data,
|
||||
struct rsnd_priv *priv);
|
||||
int rsnd_gen_probe(struct rsnd_priv *priv);
|
||||
void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv,
|
||||
struct rsnd_mod *mod,
|
||||
enum rsnd_reg reg);
|
||||
phys_addr_t rsnd_gen_get_phy_addr(struct rsnd_priv *priv, int reg_id);
|
||||
|
||||
#define rsnd_is_gen1(s) (((s)->info->flags & RSND_GEN_MASK) == RSND_GEN1)
|
||||
#define rsnd_is_gen2(s) (((s)->info->flags & RSND_GEN_MASK) == RSND_GEN2)
|
||||
|
||||
/*
|
||||
* R-Car ADG
|
||||
*/
|
||||
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_probe(struct platform_device *pdev,
|
||||
const struct rsnd_of_data *of_data,
|
||||
struct rsnd_priv *priv);
|
||||
int rsnd_adg_set_convert_clk_gen1(struct rsnd_priv *priv,
|
||||
struct rsnd_mod *mod,
|
||||
unsigned int src_rate,
|
||||
unsigned int dst_rate);
|
||||
int rsnd_adg_probe(struct rsnd_priv *priv);
|
||||
void rsnd_adg_remove(struct rsnd_priv *priv);
|
||||
int rsnd_adg_set_convert_clk_gen2(struct rsnd_mod *mod,
|
||||
struct rsnd_dai_stream *io,
|
||||
unsigned int src_rate,
|
||||
@@ -442,15 +404,14 @@ int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *mod,
|
||||
/*
|
||||
* R-Car sound priv
|
||||
*/
|
||||
struct rsnd_of_data {
|
||||
u32 flags;
|
||||
};
|
||||
|
||||
struct rsnd_priv {
|
||||
|
||||
struct platform_device *pdev;
|
||||
struct rcar_snd_info *info;
|
||||
spinlock_t lock;
|
||||
unsigned long flags;
|
||||
#define RSND_GEN_MASK (0xF << 0)
|
||||
#define RSND_GEN1 (1 << 0)
|
||||
#define RSND_GEN2 (2 << 0)
|
||||
|
||||
/*
|
||||
* below value will be filled on rsnd_gen_probe()
|
||||
@@ -473,6 +434,12 @@ struct rsnd_priv {
|
||||
void *ssi;
|
||||
int ssi_nr;
|
||||
|
||||
/*
|
||||
* below value will be filled on rsnd_ssiu_probe()
|
||||
*/
|
||||
void *ssiu;
|
||||
int ssiu_nr;
|
||||
|
||||
/*
|
||||
* below value will be filled on rsnd_src_probe()
|
||||
*/
|
||||
@@ -497,6 +464,12 @@ struct rsnd_priv {
|
||||
void *dvc;
|
||||
int dvc_nr;
|
||||
|
||||
/*
|
||||
* below value will be filled on rsnd_cmd_probe()
|
||||
*/
|
||||
void *cmd;
|
||||
int cmd_nr;
|
||||
|
||||
/*
|
||||
* below value will be filled on rsnd_dai_probe()
|
||||
*/
|
||||
@@ -507,7 +480,9 @@ struct rsnd_priv {
|
||||
|
||||
#define rsnd_priv_to_pdev(priv) ((priv)->pdev)
|
||||
#define rsnd_priv_to_dev(priv) (&(rsnd_priv_to_pdev(priv)->dev))
|
||||
#define rsnd_priv_to_info(priv) ((priv)->info)
|
||||
|
||||
#define rsnd_is_gen1(priv) (((priv)->flags & RSND_GEN_MASK) == RSND_GEN1)
|
||||
#define rsnd_is_gen2(priv) (((priv)->flags & RSND_GEN_MASK) == RSND_GEN2)
|
||||
|
||||
/*
|
||||
* rsnd_kctrl
|
||||
@@ -523,7 +498,7 @@ struct rsnd_kctrl_cfg {
|
||||
struct snd_kcontrol *kctrl;
|
||||
};
|
||||
|
||||
#define RSND_DVC_CHANNELS 2
|
||||
#define RSND_DVC_CHANNELS 8
|
||||
struct rsnd_kctrl_cfg_m {
|
||||
struct rsnd_kctrl_cfg cfg;
|
||||
u32 val[RSND_DVC_CHANNELS];
|
||||
@@ -544,6 +519,7 @@ int rsnd_kctrl_new_m(struct rsnd_mod *mod,
|
||||
void (*update)(struct rsnd_dai_stream *io,
|
||||
struct rsnd_mod *mod),
|
||||
struct rsnd_kctrl_cfg_m *_cfg,
|
||||
int ch_size,
|
||||
u32 max);
|
||||
int rsnd_kctrl_new_s(struct rsnd_mod *mod,
|
||||
struct rsnd_dai_stream *io,
|
||||
@@ -566,70 +542,93 @@ int rsnd_kctrl_new_e(struct rsnd_mod *mod,
|
||||
/*
|
||||
* R-Car SSI
|
||||
*/
|
||||
int rsnd_ssi_probe(struct platform_device *pdev,
|
||||
const struct rsnd_of_data *of_data,
|
||||
struct rsnd_priv *priv);
|
||||
void rsnd_ssi_remove(struct platform_device *pdev,
|
||||
struct rsnd_priv *priv);
|
||||
int rsnd_ssi_probe(struct rsnd_priv *priv);
|
||||
void rsnd_ssi_remove(struct rsnd_priv *priv);
|
||||
struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id);
|
||||
int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod);
|
||||
int rsnd_ssi_use_busif(struct rsnd_dai_stream *io);
|
||||
u32 rsnd_ssi_multi_slaves(struct rsnd_dai_stream *io);
|
||||
|
||||
#define rsnd_ssi_is_pin_sharing(io) \
|
||||
__rsnd_ssi_is_pin_sharing(rsnd_io_to_mod_ssi(io))
|
||||
int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod);
|
||||
|
||||
#define rsnd_ssi_of_node(priv) \
|
||||
of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,ssi")
|
||||
void rsnd_parse_connect_ssi(struct rsnd_dai *rdai,
|
||||
struct device_node *playback,
|
||||
struct device_node *capture);
|
||||
|
||||
/*
|
||||
* R-Car SSIU
|
||||
*/
|
||||
int rsnd_ssiu_attach(struct rsnd_dai_stream *io,
|
||||
struct rsnd_mod *mod);
|
||||
int rsnd_ssiu_probe(struct rsnd_priv *priv);
|
||||
void rsnd_ssiu_remove(struct rsnd_priv *priv);
|
||||
|
||||
/*
|
||||
* R-Car SRC
|
||||
*/
|
||||
int rsnd_src_probe(struct platform_device *pdev,
|
||||
const struct rsnd_of_data *of_data,
|
||||
struct rsnd_priv *priv);
|
||||
void rsnd_src_remove(struct platform_device *pdev,
|
||||
struct rsnd_priv *priv);
|
||||
int rsnd_src_probe(struct rsnd_priv *priv);
|
||||
void rsnd_src_remove(struct rsnd_priv *priv);
|
||||
struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id);
|
||||
unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv,
|
||||
struct rsnd_dai_stream *io,
|
||||
struct snd_pcm_runtime *runtime);
|
||||
int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod,
|
||||
struct rsnd_dai_stream *io,
|
||||
int use_busif);
|
||||
int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod,
|
||||
struct rsnd_dai_stream *io);
|
||||
int rsnd_src_ssi_irq_enable(struct rsnd_mod *ssi_mod);
|
||||
int rsnd_src_ssi_irq_disable(struct rsnd_mod *ssi_mod);
|
||||
#define rsnd_src_of_node(priv) \
|
||||
of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,src")
|
||||
#define rsnd_parse_connect_src(rdai, playback, capture) \
|
||||
rsnd_parse_connect_common(rdai, rsnd_src_mod_get, \
|
||||
rsnd_src_of_node(rsnd_rdai_to_priv(rdai)), \
|
||||
playback, capture)
|
||||
|
||||
/*
|
||||
* R-Car CTU
|
||||
*/
|
||||
int rsnd_ctu_probe(struct platform_device *pdev,
|
||||
const struct rsnd_of_data *of_data,
|
||||
struct rsnd_priv *priv);
|
||||
|
||||
void rsnd_ctu_remove(struct platform_device *pdev,
|
||||
struct rsnd_priv *priv);
|
||||
int rsnd_ctu_probe(struct rsnd_priv *priv);
|
||||
void rsnd_ctu_remove(struct rsnd_priv *priv);
|
||||
struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id);
|
||||
#define rsnd_ctu_of_node(priv) \
|
||||
of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,ctu")
|
||||
#define rsnd_parse_connect_ctu(rdai, playback, capture) \
|
||||
rsnd_parse_connect_common(rdai, rsnd_ctu_mod_get, \
|
||||
rsnd_ctu_of_node(rsnd_rdai_to_priv(rdai)), \
|
||||
playback, capture)
|
||||
|
||||
/*
|
||||
* R-Car MIX
|
||||
*/
|
||||
int rsnd_mix_probe(struct platform_device *pdev,
|
||||
const struct rsnd_of_data *of_data,
|
||||
struct rsnd_priv *priv);
|
||||
|
||||
void rsnd_mix_remove(struct platform_device *pdev,
|
||||
struct rsnd_priv *priv);
|
||||
int rsnd_mix_probe(struct rsnd_priv *priv);
|
||||
void rsnd_mix_remove(struct rsnd_priv *priv);
|
||||
struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id);
|
||||
#define rsnd_mix_of_node(priv) \
|
||||
of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,mix")
|
||||
#define rsnd_parse_connect_mix(rdai, playback, capture) \
|
||||
rsnd_parse_connect_common(rdai, rsnd_mix_mod_get, \
|
||||
rsnd_mix_of_node(rsnd_rdai_to_priv(rdai)), \
|
||||
playback, capture)
|
||||
|
||||
/*
|
||||
* R-Car DVC
|
||||
*/
|
||||
int rsnd_dvc_probe(struct platform_device *pdev,
|
||||
const struct rsnd_of_data *of_data,
|
||||
struct rsnd_priv *priv);
|
||||
void rsnd_dvc_remove(struct platform_device *pdev,
|
||||
struct rsnd_priv *priv);
|
||||
int rsnd_dvc_probe(struct rsnd_priv *priv);
|
||||
void rsnd_dvc_remove(struct rsnd_priv *priv);
|
||||
struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id);
|
||||
#define rsnd_dvc_of_node(priv) \
|
||||
of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,dvc")
|
||||
#define rsnd_parse_connect_dvc(rdai, playback, capture) \
|
||||
rsnd_parse_connect_common(rdai, rsnd_dvc_mod_get, \
|
||||
rsnd_dvc_of_node(rsnd_rdai_to_priv(rdai)), \
|
||||
playback, capture)
|
||||
|
||||
/*
|
||||
* R-Car CMD
|
||||
*/
|
||||
int rsnd_cmd_probe(struct rsnd_priv *priv);
|
||||
void rsnd_cmd_remove(struct rsnd_priv *priv);
|
||||
int rsnd_cmd_attach(struct rsnd_dai_stream *io, int id);
|
||||
struct rsnd_mod *rsnd_cmd_mod_get(struct rsnd_priv *priv, int id);
|
||||
|
||||
#ifdef DEBUG
|
||||
void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type);
|
||||
|
@@ -48,8 +48,11 @@ MODULE_DEVICE_TABLE(of, rsrc_card_of_match);
|
||||
|
||||
#define DAI_NAME_NUM 32
|
||||
struct rsrc_card_dai {
|
||||
unsigned int fmt;
|
||||
unsigned int sysclk;
|
||||
unsigned int tx_slot_mask;
|
||||
unsigned int rx_slot_mask;
|
||||
int slots;
|
||||
int slot_width;
|
||||
struct clk *clk;
|
||||
char dai_name[DAI_NAME_NUM];
|
||||
};
|
||||
@@ -110,14 +113,6 @@ static int rsrc_card_dai_init(struct snd_soc_pcm_runtime *rtd)
|
||||
rtd->cpu_dai :
|
||||
rtd->codec_dai;
|
||||
|
||||
if (dai_props->fmt) {
|
||||
ret = snd_soc_dai_set_fmt(dai, dai_props->fmt);
|
||||
if (ret && ret != -ENOTSUPP) {
|
||||
dev_err(dai->dev, "set_fmt error\n");
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
if (dai_props->sysclk) {
|
||||
ret = snd_soc_dai_set_sysclk(dai, 0, dai_props->sysclk, 0);
|
||||
if (ret && ret != -ENOTSUPP) {
|
||||
@@ -126,6 +121,18 @@ static int rsrc_card_dai_init(struct snd_soc_pcm_runtime *rtd)
|
||||
}
|
||||
}
|
||||
|
||||
if (dai_props->slots) {
|
||||
ret = snd_soc_dai_set_tdm_slot(dai,
|
||||
dai_props->tx_slot_mask,
|
||||
dai_props->rx_slot_mask,
|
||||
dai_props->slots,
|
||||
dai_props->slot_width);
|
||||
if (ret && ret != -ENOTSUPP) {
|
||||
dev_err(dai->dev, "set_tdm_slot error\n");
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
err:
|
||||
@@ -148,14 +155,13 @@ static int rsrc_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
|
||||
}
|
||||
|
||||
static int rsrc_card_parse_daifmt(struct device_node *node,
|
||||
struct device_node *np,
|
||||
struct device_node *codec,
|
||||
struct rsrc_card_priv *priv,
|
||||
int idx, bool is_fe)
|
||||
struct snd_soc_dai_link *dai_link,
|
||||
unsigned int *retfmt)
|
||||
{
|
||||
struct rsrc_card_dai *dai_props = rsrc_priv_to_props(priv, idx);
|
||||
struct device_node *bitclkmaster = NULL;
|
||||
struct device_node *framemaster = NULL;
|
||||
struct device_node *codec = is_fe ? NULL : np;
|
||||
unsigned int daifmt;
|
||||
|
||||
daifmt = snd_soc_of_parse_daifmt(node, NULL,
|
||||
@@ -172,11 +178,11 @@ static int rsrc_card_parse_daifmt(struct device_node *node,
|
||||
daifmt |= (codec == framemaster) ?
|
||||
SND_SOC_DAIFMT_CBS_CFM : SND_SOC_DAIFMT_CBS_CFS;
|
||||
|
||||
dai_props->fmt = daifmt;
|
||||
|
||||
of_node_put(bitclkmaster);
|
||||
of_node_put(framemaster);
|
||||
|
||||
*retfmt = daifmt;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -198,6 +204,15 @@ static int rsrc_card_parse_links(struct device_node *np,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Parse TDM slot */
|
||||
ret = snd_soc_of_parse_tdm_slot(np,
|
||||
&dai_props->tx_slot_mask,
|
||||
&dai_props->rx_slot_mask,
|
||||
&dai_props->slots,
|
||||
&dai_props->slot_width);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (is_fe) {
|
||||
/* BE is dummy */
|
||||
dai_link->codec_of_node = NULL;
|
||||
@@ -208,7 +223,9 @@ static int rsrc_card_parse_links(struct device_node *np,
|
||||
dai_link->dynamic = 1;
|
||||
dai_link->dpcm_merged_format = 1;
|
||||
dai_link->cpu_of_node = args.np;
|
||||
snd_soc_of_get_dai_name(np, &dai_link->cpu_dai_name);
|
||||
ret = snd_soc_of_get_dai_name(np, &dai_link->cpu_dai_name);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* set dai_name */
|
||||
snprintf(dai_props->dai_name, DAI_NAME_NUM, "fe.%s",
|
||||
@@ -240,7 +257,9 @@ static int rsrc_card_parse_links(struct device_node *np,
|
||||
dai_link->no_pcm = 1;
|
||||
dai_link->be_hw_params_fixup = rsrc_card_be_hw_params_fixup;
|
||||
dai_link->codec_of_node = args.np;
|
||||
snd_soc_of_get_dai_name(np, &dai_link->codec_dai_name);
|
||||
ret = snd_soc_of_get_dai_name(np, &dai_link->codec_dai_name);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* additional name prefix */
|
||||
if (of_data) {
|
||||
@@ -305,23 +324,16 @@ static int rsrc_card_parse_clk(struct device_node *np,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rsrc_card_dai_link_of(struct device_node *node,
|
||||
struct device_node *np,
|
||||
struct rsrc_card_priv *priv,
|
||||
int idx)
|
||||
static int rsrc_card_dai_sub_link_of(struct device_node *node,
|
||||
struct device_node *np,
|
||||
struct rsrc_card_priv *priv,
|
||||
int idx, bool is_fe)
|
||||
{
|
||||
struct device *dev = rsrc_priv_to_dev(priv);
|
||||
struct snd_soc_dai_link *dai_link = rsrc_priv_to_link(priv, idx);
|
||||
struct rsrc_card_dai *dai_props = rsrc_priv_to_props(priv, idx);
|
||||
bool is_fe = false;
|
||||
int ret;
|
||||
|
||||
if (0 == strcmp(np->name, "cpu"))
|
||||
is_fe = true;
|
||||
|
||||
ret = rsrc_card_parse_daifmt(node, np, priv, idx, is_fe);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = rsrc_card_parse_links(np, priv, idx, is_fe);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@@ -332,12 +344,54 @@ static int rsrc_card_dai_link_of(struct device_node *node,
|
||||
|
||||
dev_dbg(dev, "\t%s / %04x / %d\n",
|
||||
dai_props->dai_name,
|
||||
dai_props->fmt,
|
||||
dai_link->dai_fmt,
|
||||
dai_props->sysclk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rsrc_card_dai_link_of(struct device_node *node,
|
||||
struct rsrc_card_priv *priv)
|
||||
{
|
||||
struct snd_soc_dai_link *dai_link;
|
||||
struct device_node *np;
|
||||
unsigned int daifmt = 0;
|
||||
int ret, i;
|
||||
bool is_fe;
|
||||
|
||||
/* find 1st codec */
|
||||
i = 0;
|
||||
for_each_child_of_node(node, np) {
|
||||
dai_link = rsrc_priv_to_link(priv, i);
|
||||
|
||||
if (strcmp(np->name, "codec") == 0) {
|
||||
ret = rsrc_card_parse_daifmt(node, np, priv,
|
||||
dai_link, &daifmt);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
for_each_child_of_node(node, np) {
|
||||
dai_link = rsrc_priv_to_link(priv, i);
|
||||
dai_link->dai_fmt = daifmt;
|
||||
|
||||
is_fe = false;
|
||||
if (strcmp(np->name, "cpu") == 0)
|
||||
is_fe = true;
|
||||
|
||||
ret = rsrc_card_dai_sub_link_of(node, np, priv, i, is_fe);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
i++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rsrc_card_parse_of(struct device_node *node,
|
||||
struct rsrc_card_priv *priv,
|
||||
struct device *dev)
|
||||
@@ -345,9 +399,8 @@ static int rsrc_card_parse_of(struct device_node *node,
|
||||
const struct rsrc_card_of_data *of_data = rsrc_dev_to_of_data(dev);
|
||||
struct rsrc_card_dai *props;
|
||||
struct snd_soc_dai_link *links;
|
||||
struct device_node *np;
|
||||
int ret;
|
||||
int i, num;
|
||||
int num;
|
||||
|
||||
if (!node)
|
||||
return -EINVAL;
|
||||
@@ -388,13 +441,9 @@ static int rsrc_card_parse_of(struct device_node *node,
|
||||
priv->snd_card.name ? priv->snd_card.name : "",
|
||||
priv->convert_rate);
|
||||
|
||||
i = 0;
|
||||
for_each_child_of_node(node, np) {
|
||||
ret = rsrc_card_dai_link_of(node, np, priv, i);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
i++;
|
||||
}
|
||||
ret = rsrc_card_dai_link_of(node, priv);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (!priv->snd_card.name)
|
||||
priv->snd_card.name = priv->snd_card.dai_link->name;
|
||||
|
La diferencia del archivo ha sido suprimido porque es demasiado grande
Cargar Diff
La diferencia del archivo ha sido suprimido porque es demasiado grande
Cargar Diff
225
sound/soc/sh/rcar/ssiu.c
Archivo normal
225
sound/soc/sh/rcar/ssiu.c
Archivo normal
@@ -0,0 +1,225 @@
|
||||
/*
|
||||
* Renesas R-Car SSIU support
|
||||
*
|
||||
* Copyright (c) 2015 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"
|
||||
|
||||
#define SSIU_NAME "ssiu"
|
||||
|
||||
struct rsnd_ssiu {
|
||||
struct rsnd_mod mod;
|
||||
};
|
||||
|
||||
#define rsnd_ssiu_nr(priv) ((priv)->ssiu_nr)
|
||||
#define for_each_rsnd_ssiu(pos, priv, i) \
|
||||
for (i = 0; \
|
||||
(i < rsnd_ssiu_nr(priv)) && \
|
||||
((pos) = ((struct rsnd_ssiu *)(priv)->ssiu + i)); \
|
||||
i++)
|
||||
|
||||
static int rsnd_ssiu_init(struct rsnd_mod *mod,
|
||||
struct rsnd_dai_stream *io,
|
||||
struct rsnd_priv *priv)
|
||||
{
|
||||
struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
|
||||
u32 multi_ssi_slaves = rsnd_ssi_multi_slaves(io);
|
||||
int use_busif = rsnd_ssi_use_busif(io);
|
||||
int id = rsnd_mod_id(mod);
|
||||
u32 mask1, val1;
|
||||
u32 mask2, val2;
|
||||
|
||||
/*
|
||||
* SSI_MODE0
|
||||
*/
|
||||
rsnd_mod_bset(mod, SSI_MODE0, (1 << id), !use_busif << id);
|
||||
|
||||
/*
|
||||
* SSI_MODE1
|
||||
*/
|
||||
mask1 = (1 << 4) | (1 << 20); /* mask sync bit */
|
||||
mask2 = (1 << 4); /* mask sync bit */
|
||||
val1 = val2 = 0;
|
||||
if (rsnd_ssi_is_pin_sharing(io)) {
|
||||
int shift = -1;
|
||||
|
||||
switch (id) {
|
||||
case 1:
|
||||
shift = 0;
|
||||
break;
|
||||
case 2:
|
||||
shift = 2;
|
||||
break;
|
||||
case 4:
|
||||
shift = 16;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mask1 |= 0x3 << shift;
|
||||
val1 = rsnd_rdai_is_clk_master(rdai) ?
|
||||
0x2 << shift : 0x1 << shift;
|
||||
|
||||
} else if (multi_ssi_slaves) {
|
||||
|
||||
mask2 |= 0x00000007;
|
||||
mask1 |= 0x0000000f;
|
||||
|
||||
switch (multi_ssi_slaves) {
|
||||
case 0x0206: /* SSI0/1/2/9 */
|
||||
val2 = (1 << 4) | /* SSI0129 sync */
|
||||
rsnd_rdai_is_clk_master(rdai) ? 0x2 : 0x1;
|
||||
/* fall through */
|
||||
case 0x0006: /* SSI0/1/2 */
|
||||
val1 = rsnd_rdai_is_clk_master(rdai) ?
|
||||
0xa : 0x5;
|
||||
|
||||
if (!val2) /* SSI012 sync */
|
||||
val1 |= (1 << 4);
|
||||
}
|
||||
}
|
||||
|
||||
rsnd_mod_bset(mod, SSI_MODE1, mask1, val1);
|
||||
rsnd_mod_bset(mod, SSI_MODE2, mask2, val2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct rsnd_mod_ops rsnd_ssiu_ops_gen1 = {
|
||||
.name = SSIU_NAME,
|
||||
.init = rsnd_ssiu_init,
|
||||
};
|
||||
|
||||
static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod,
|
||||
struct rsnd_dai_stream *io,
|
||||
struct rsnd_priv *priv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = rsnd_ssiu_init(mod, io, priv);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (rsnd_get_slot_width(io) >= 6) {
|
||||
/*
|
||||
* TDM Extend Mode
|
||||
* see
|
||||
* rsnd_ssi_config_init()
|
||||
*/
|
||||
rsnd_mod_write(mod, SSI_MODE, 0x1);
|
||||
}
|
||||
|
||||
if (rsnd_ssi_use_busif(io)) {
|
||||
u32 val = rsnd_get_dalign(mod, io);
|
||||
|
||||
rsnd_mod_write(mod, SSI_BUSIF_ADINR,
|
||||
rsnd_get_adinr_bit(mod, io) |
|
||||
rsnd_get_adinr_chan(mod, io));
|
||||
rsnd_mod_write(mod, SSI_BUSIF_MODE, 1);
|
||||
rsnd_mod_write(mod, SSI_BUSIF_DALIGN, val);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rsnd_ssiu_start_gen2(struct rsnd_mod *mod,
|
||||
struct rsnd_dai_stream *io,
|
||||
struct rsnd_priv *priv)
|
||||
{
|
||||
if (!rsnd_ssi_use_busif(io))
|
||||
return 0;
|
||||
|
||||
rsnd_mod_write(mod, SSI_CTRL, 0x1);
|
||||
|
||||
if (rsnd_ssi_multi_slaves(io))
|
||||
rsnd_mod_write(mod, SSI_CONTROL, 0x1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rsnd_ssiu_stop_gen2(struct rsnd_mod *mod,
|
||||
struct rsnd_dai_stream *io,
|
||||
struct rsnd_priv *priv)
|
||||
{
|
||||
if (!rsnd_ssi_use_busif(io))
|
||||
return 0;
|
||||
|
||||
rsnd_mod_write(mod, SSI_CTRL, 0);
|
||||
|
||||
if (rsnd_ssi_multi_slaves(io))
|
||||
rsnd_mod_write(mod, SSI_CONTROL, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct rsnd_mod_ops rsnd_ssiu_ops_gen2 = {
|
||||
.name = SSIU_NAME,
|
||||
.init = rsnd_ssiu_init_gen2,
|
||||
.start = rsnd_ssiu_start_gen2,
|
||||
.stop = rsnd_ssiu_stop_gen2,
|
||||
};
|
||||
|
||||
static struct rsnd_mod *rsnd_ssiu_mod_get(struct rsnd_priv *priv, int id)
|
||||
{
|
||||
if (WARN_ON(id < 0 || id >= rsnd_ssiu_nr(priv)))
|
||||
id = 0;
|
||||
|
||||
return rsnd_mod_get((struct rsnd_ssiu *)(priv->ssiu) + id);
|
||||
}
|
||||
|
||||
int rsnd_ssiu_attach(struct rsnd_dai_stream *io,
|
||||
struct rsnd_mod *ssi_mod)
|
||||
{
|
||||
struct rsnd_priv *priv = rsnd_io_to_priv(io);
|
||||
struct rsnd_mod *mod = rsnd_ssiu_mod_get(priv, rsnd_mod_id(ssi_mod));
|
||||
|
||||
rsnd_mod_confirm_ssi(ssi_mod);
|
||||
|
||||
return rsnd_dai_connect(mod, io, mod->type);
|
||||
}
|
||||
|
||||
int rsnd_ssiu_probe(struct rsnd_priv *priv)
|
||||
{
|
||||
struct device *dev = rsnd_priv_to_dev(priv);
|
||||
struct rsnd_ssiu *ssiu;
|
||||
static struct rsnd_mod_ops *ops;
|
||||
int i, nr, ret;
|
||||
|
||||
/* same number to SSI */
|
||||
nr = priv->ssi_nr;
|
||||
ssiu = devm_kzalloc(dev, sizeof(*ssiu) * nr, GFP_KERNEL);
|
||||
if (!ssiu)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->ssiu = ssiu;
|
||||
priv->ssiu_nr = nr;
|
||||
|
||||
if (rsnd_is_gen1(priv))
|
||||
ops = &rsnd_ssiu_ops_gen1;
|
||||
else
|
||||
ops = &rsnd_ssiu_ops_gen2;
|
||||
|
||||
for_each_rsnd_ssiu(ssiu, priv, i) {
|
||||
ret = rsnd_mod_init(priv, rsnd_mod_get(ssiu),
|
||||
ops, NULL, RSND_MOD_SSIU, i);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rsnd_ssiu_remove(struct rsnd_priv *priv)
|
||||
{
|
||||
struct rsnd_ssiu *ssiu;
|
||||
int i;
|
||||
|
||||
for_each_rsnd_ssiu(ssiu, priv, i) {
|
||||
rsnd_mod_quit(rsnd_mod_get(ssiu));
|
||||
}
|
||||
}
|
Referencia en una nueva incidencia
Block a user