Commit 6e6d57d0 authored by Mark Brown's avatar Mark Brown

Merge remote-tracking branches 'asoc/topic/rcar', 'asoc/topic/rockchip',...

Merge remote-tracking branches 'asoc/topic/rcar', 'asoc/topic/rockchip', 'asoc/topic/rt286' and 'asoc/topic/rt5631' into asoc-next
Renesas R-Car sound Renesas R-Car sound
Required properties: Required properties:
- compatible : "renesas,rcar_sound-gen1" if generation1 - compatible : "renesas,rcar_sound-<soctype>", fallbacks
"renesas,rcar_sound-gen1" if generation1, and
"renesas,rcar_sound-gen2" if generation2 "renesas,rcar_sound-gen2" if generation2
Examples with soctypes are:
- "renesas,rcar_sound-r8a7790" (R-Car H2)
- "renesas,rcar_sound-r8a7791" (R-Car M2-W)
- reg : Should contain the register physical address. - reg : Should contain the register physical address.
required register is required register is
SRU/ADG/SSI if generation1 SRU/ADG/SSI if generation1
...@@ -35,9 +39,9 @@ DAI subnode properties: ...@@ -35,9 +39,9 @@ DAI subnode properties:
Example: Example:
rcar_sound: rcar_sound@0xffd90000 { rcar_sound: rcar_sound@ec500000 {
#sound-dai-cells = <1>; #sound-dai-cells = <1>;
compatible = "renesas,rcar_sound-gen2"; compatible = "renesas,rcar_sound-r8a7791", "renesas,rcar_sound-gen2";
reg = <0 0xec500000 0 0x1000>, /* SCU */ reg = <0 0xec500000 0 0x1000>, /* SCU */
<0 0xec5a0000 0 0x100>, /* ADG */ <0 0xec5a0000 0 0x100>, /* ADG */
<0 0xec540000 0 0x1000>, /* SSIU */ <0 0xec540000 0 0x1000>, /* SSIU */
......
ALC5631/RT5631 audio CODEC
This device supports I2C only.
Required properties:
- compatible : "realtek,alc5631" or "realtek,rt5631"
- reg : the I2C address of the device.
Pins on the device (for linking into audio routes):
* SPK_OUT_R_P
* SPK_OUT_R_N
* SPK_OUT_L_P
* SPK_OUT_L_N
* HP_OUT_L
* HP_OUT_R
* AUX_OUT2_LP
* AUX_OUT2_RN
* AUX_OUT1_LP
* AUX_OUT1_RN
* AUX_IN_L_JD
* AUX_IN_R_JD
* MONO_IN_P
* MONO_IN_N
* MIC1_P
* MIC1_N
* MIC2_P
* MIC2_N
* MONO_OUT_P
* MONO_OUT_N
* MICBIAS1
* MICBIAS2
Example:
alc5631: alc5631@1a {
compatible = "realtek,alc5631";
reg = <0x1a>;
};
or
rt5631: rt5631@1a {
compatible = "realtek,rt5631";
reg = <0x1a>;
};
...@@ -36,14 +36,14 @@ ...@@ -36,14 +36,14 @@
#define RSND_SSI_CLK_PIN_SHARE (1 << 31) #define RSND_SSI_CLK_PIN_SHARE (1 << 31)
#define RSND_SSI_NO_BUSIF (1 << 30) /* SSI+DMA without BUSIF */ #define RSND_SSI_NO_BUSIF (1 << 30) /* SSI+DMA without BUSIF */
#define RSND_SSI(_dma_id, _pio_irq, _flags) \ #define RSND_SSI(_dma_id, _irq, _flags) \
{ .dma_id = _dma_id, .pio_irq = _pio_irq, .flags = _flags } { .dma_id = _dma_id, .irq = _irq, .flags = _flags }
#define RSND_SSI_UNUSED \ #define RSND_SSI_UNUSED \
{ .dma_id = -1, .pio_irq = -1, .flags = 0 } { .dma_id = -1, .irq = -1, .flags = 0 }
struct rsnd_ssi_platform_info { struct rsnd_ssi_platform_info {
int dma_id; int dma_id;
int pio_irq; int irq;
u32 flags; u32 flags;
}; };
......
...@@ -501,7 +501,8 @@ config SND_SOC_RT286 ...@@ -501,7 +501,8 @@ config SND_SOC_RT286
depends on I2C depends on I2C
config SND_SOC_RT5631 config SND_SOC_RT5631
tristate tristate "Realtek ALC5631/RT5631 CODEC"
depends on I2C
config SND_SOC_RT5640 config SND_SOC_RT5640
tristate tristate
......
This diff is collapsed.
...@@ -1612,29 +1612,6 @@ static int rt5631_probe(struct snd_soc_codec *codec) ...@@ -1612,29 +1612,6 @@ static int rt5631_probe(struct snd_soc_codec *codec)
return 0; return 0;
} }
static int rt5631_remove(struct snd_soc_codec *codec)
{
rt5631_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
#ifdef CONFIG_PM
static int rt5631_suspend(struct snd_soc_codec *codec)
{
rt5631_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
static int rt5631_resume(struct snd_soc_codec *codec)
{
rt5631_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
}
#else
#define rt5631_suspend NULL
#define rt5631_resume NULL
#endif
#define RT5631_STEREO_RATES SNDRV_PCM_RATE_8000_96000 #define RT5631_STEREO_RATES SNDRV_PCM_RATE_8000_96000
#define RT5631_FORMAT (SNDRV_PCM_FMTBIT_S16_LE | \ #define RT5631_FORMAT (SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S20_3LE | \ SNDRV_PCM_FMTBIT_S20_3LE | \
...@@ -1672,10 +1649,8 @@ static struct snd_soc_dai_driver rt5631_dai[] = { ...@@ -1672,10 +1649,8 @@ static struct snd_soc_dai_driver rt5631_dai[] = {
static struct snd_soc_codec_driver soc_codec_dev_rt5631 = { static struct snd_soc_codec_driver soc_codec_dev_rt5631 = {
.probe = rt5631_probe, .probe = rt5631_probe,
.remove = rt5631_remove,
.suspend = rt5631_suspend,
.resume = rt5631_resume,
.set_bias_level = rt5631_set_bias_level, .set_bias_level = rt5631_set_bias_level,
.suspend_bias_off = true,
.controls = rt5631_snd_controls, .controls = rt5631_snd_controls,
.num_controls = ARRAY_SIZE(rt5631_snd_controls), .num_controls = ARRAY_SIZE(rt5631_snd_controls),
.dapm_widgets = rt5631_dapm_widgets, .dapm_widgets = rt5631_dapm_widgets,
...@@ -1686,10 +1661,20 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5631 = { ...@@ -1686,10 +1661,20 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5631 = {
static const struct i2c_device_id rt5631_i2c_id[] = { static const struct i2c_device_id rt5631_i2c_id[] = {
{ "rt5631", 0 }, { "rt5631", 0 },
{ "alc5631", 0 },
{ } { }
}; };
MODULE_DEVICE_TABLE(i2c, rt5631_i2c_id); MODULE_DEVICE_TABLE(i2c, rt5631_i2c_id);
#ifdef CONFIG_OF
static struct of_device_id rt5631_i2c_dt_ids[] = {
{ .compatible = "realtek,rt5631"},
{ .compatible = "realtek,alc5631"},
{ }
};
MODULE_DEVICE_TABLE(of, rt5631_i2c_dt_ids);
#endif
static const struct regmap_config rt5631_regmap_config = { static const struct regmap_config rt5631_regmap_config = {
.reg_bits = 8, .reg_bits = 8,
.val_bits = 16, .val_bits = 16,
...@@ -1734,6 +1719,7 @@ static struct i2c_driver rt5631_i2c_driver = { ...@@ -1734,6 +1719,7 @@ static struct i2c_driver rt5631_i2c_driver = {
.driver = { .driver = {
.name = "rt5631", .name = "rt5631",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.of_match_table = of_match_ptr(rt5631_i2c_dt_ids),
}, },
.probe = rt5631_i2c_probe, .probe = rt5631_i2c_probe,
.remove = rt5631_i2c_remove, .remove = rt5631_i2c_remove,
......
config SND_SOC_ROCKCHIP config SND_SOC_ROCKCHIP
tristate "ASoC support for Rockchip" tristate "ASoC support for Rockchip"
depends on COMPILE_TEST || ARCH_ROCKCHIP depends on COMPILE_TEST || ARCH_ROCKCHIP
select SND_SOC_GENERIC_DMAENGINE_PCM
help help
Say Y or M if you want to add support for codecs attached to Say Y or M if you want to add support for codecs attached to
the Rockchip SoCs' Audio interfaces. You will also need to the Rockchip SoCs' Audio interfaces. You will also need to
select the audio interfaces to support below. select the audio interfaces to support below.
config SND_SOC_ROCKCHIP_I2S config SND_SOC_ROCKCHIP_I2S
tristate tristate "Rockchip I2S Device Driver"
depends on CLKDEV_LOOKUP && SND_SOC_ROCKCHIP
select SND_SOC_GENERIC_DMAENGINE_PCM
help
Say Y or M if you want to add support for I2S driver for
Rockchip I2S device. The device supports upto maximum of
8 channels each for play and record.
...@@ -430,7 +430,7 @@ int rsnd_adg_probe(struct platform_device *pdev, ...@@ -430,7 +430,7 @@ int rsnd_adg_probe(struct platform_device *pdev,
adg->clk[CLKI] = devm_clk_get(dev, "clk_i"); adg->clk[CLKI] = devm_clk_get(dev, "clk_i");
for_each_rsnd_clk(clk, adg, i) for_each_rsnd_clk(clk, adg, i)
dev_dbg(dev, "clk %d : %p\n", i, clk); dev_dbg(dev, "clk %d : %p : %ld\n", i, clk, clk_get_rate(clk));
rsnd_adg_ssi_clk_init(priv, adg); rsnd_adg_ssi_clk_init(priv, adg);
......
...@@ -349,7 +349,7 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, ...@@ -349,7 +349,7 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma,
dma_name); dma_name);
if (!dma->chan) { if (!dma->chan) {
dev_err(dev, "can't get dma channel\n"); dev_err(dev, "can't get dma channel\n");
return -EIO; goto rsnd_dma_channel_err;
} }
ret = dmaengine_slave_config(dma->chan, &cfg); ret = dmaengine_slave_config(dma->chan, &cfg);
...@@ -363,8 +363,15 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, ...@@ -363,8 +363,15 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma,
rsnd_dma_init_err: rsnd_dma_init_err:
rsnd_dma_quit(priv, dma); rsnd_dma_quit(priv, dma);
rsnd_dma_channel_err:
return ret; /*
* DMA failed. try to PIO mode
* see
* rsnd_ssi_fallback()
* rsnd_rdai_continuance_probe()
*/
return -EAGAIN;
} }
void rsnd_dma_quit(struct rsnd_priv *priv, void rsnd_dma_quit(struct rsnd_priv *priv,
...@@ -409,9 +416,16 @@ u32 rsnd_get_adinr(struct rsnd_mod *mod) ...@@ -409,9 +416,16 @@ u32 rsnd_get_adinr(struct rsnd_mod *mod)
({ \ ({ \
struct rsnd_priv *priv = rsnd_mod_to_priv(mod); \ struct rsnd_priv *priv = rsnd_mod_to_priv(mod); \
struct device *dev = rsnd_priv_to_dev(priv); \ struct device *dev = rsnd_priv_to_dev(priv); \
dev_dbg(dev, "%s [%d] %s\n", \ u32 mask = 1 << __rsnd_mod_shift_##func; \
rsnd_mod_name(mod), rsnd_mod_id(mod), #func); \ u32 call = __rsnd_mod_call_##func << __rsnd_mod_shift_##func; \
(mod)->ops->func(mod, rdai); \ int ret = 0; \
if ((mod->status & mask) == call) { \
dev_dbg(dev, "%s[%d] %s\n", \
rsnd_mod_name(mod), rsnd_mod_id(mod), #func); \
ret = (mod)->ops->func(mod, rdai); \
mod->status = (mod->status & ~mask) | (~call & mask); \
} \
ret; \
}) })
#define rsnd_mod_call(mod, func, rdai...) \ #define rsnd_mod_call(mod, func, rdai...) \
...@@ -456,6 +470,13 @@ static int rsnd_dai_connect(struct rsnd_mod *mod, ...@@ -456,6 +470,13 @@ static int rsnd_dai_connect(struct rsnd_mod *mod,
return 0; return 0;
} }
static void rsnd_dai_disconnect(struct rsnd_mod *mod,
struct rsnd_dai_stream *io)
{
mod->io = NULL;
io->mod[mod->type] = NULL;
}
int rsnd_dai_id(struct rsnd_priv *priv, struct rsnd_dai *rdai) int rsnd_dai_id(struct rsnd_priv *priv, struct rsnd_dai *rdai)
{ {
int id = rdai - priv->rdai; int id = rdai - priv->rdai;
...@@ -686,6 +707,20 @@ static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { ...@@ -686,6 +707,20 @@ static const struct snd_soc_dai_ops rsnd_soc_dai_ops = {
ret; \ ret; \
}) })
#define rsnd_path_break(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); \
} \
} \
}
static int rsnd_path_init(struct rsnd_priv *priv, static int rsnd_path_init(struct rsnd_priv *priv,
struct rsnd_dai *rdai, struct rsnd_dai *rdai,
struct rsnd_dai_stream *io) struct rsnd_dai_stream *io)
...@@ -933,6 +968,150 @@ static struct snd_pcm_ops rsnd_pcm_ops = { ...@@ -933,6 +968,150 @@ static struct snd_pcm_ops rsnd_pcm_ops = {
.pointer = rsnd_pointer, .pointer = rsnd_pointer,
}; };
/*
* snd_kcontrol
*/
#define kcontrol_to_cfg(kctrl) ((struct rsnd_kctrl_cfg *)kctrl->private_value)
static int rsnd_kctrl_info(struct snd_kcontrol *kctrl,
struct snd_ctl_elem_info *uinfo)
{
struct rsnd_kctrl_cfg *cfg = kcontrol_to_cfg(kctrl);
if (cfg->texts) {
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
uinfo->count = cfg->size;
uinfo->value.enumerated.items = cfg->max;
if (uinfo->value.enumerated.item >= cfg->max)
uinfo->value.enumerated.item = cfg->max - 1;
strlcpy(uinfo->value.enumerated.name,
cfg->texts[uinfo->value.enumerated.item],
sizeof(uinfo->value.enumerated.name));
} else {
uinfo->count = cfg->size;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = cfg->max;
uinfo->type = (cfg->max == 1) ?
SNDRV_CTL_ELEM_TYPE_BOOLEAN :
SNDRV_CTL_ELEM_TYPE_INTEGER;
}
return 0;
}
static int rsnd_kctrl_get(struct snd_kcontrol *kctrl,
struct snd_ctl_elem_value *uc)
{
struct rsnd_kctrl_cfg *cfg = kcontrol_to_cfg(kctrl);
int i;
for (i = 0; i < cfg->size; i++)
if (cfg->texts)
uc->value.enumerated.item[i] = cfg->val[i];
else
uc->value.integer.value[i] = cfg->val[i];
return 0;
}
static int rsnd_kctrl_put(struct snd_kcontrol *kctrl,
struct snd_ctl_elem_value *uc)
{
struct rsnd_mod *mod = snd_kcontrol_chip(kctrl);
struct rsnd_kctrl_cfg *cfg = kcontrol_to_cfg(kctrl);
int i, change = 0;
for (i = 0; i < cfg->size; i++) {
if (cfg->texts) {
change |= (uc->value.enumerated.item[i] != cfg->val[i]);
cfg->val[i] = uc->value.enumerated.item[i];
} else {
change |= (uc->value.integer.value[i] != cfg->val[i]);
cfg->val[i] = uc->value.integer.value[i];
}
}
if (change)
cfg->update(mod);
return change;
}
static int __rsnd_kctrl_new(struct rsnd_mod *mod,
struct rsnd_dai *rdai,
struct snd_soc_pcm_runtime *rtd,
const unsigned char *name,
struct rsnd_kctrl_cfg *cfg,
void (*update)(struct rsnd_mod *mod))
{
struct snd_card *card = rtd->card->snd_card;
struct snd_kcontrol *kctrl;
struct snd_kcontrol_new knew = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = name,
.info = rsnd_kctrl_info,
.get = rsnd_kctrl_get,
.put = rsnd_kctrl_put,
.private_value = (unsigned long)cfg,
};
int ret;
kctrl = snd_ctl_new1(&knew, mod);
if (!kctrl)
return -ENOMEM;
ret = snd_ctl_add(card, kctrl);
if (ret < 0)
return ret;
cfg->update = update;
return 0;
}
int rsnd_kctrl_new_m(struct rsnd_mod *mod,
struct rsnd_dai *rdai,
struct snd_soc_pcm_runtime *rtd,
const unsigned char *name,
void (*update)(struct rsnd_mod *mod),
struct rsnd_kctrl_cfg_m *_cfg,
u32 max)
{
_cfg->cfg.max = max;
_cfg->cfg.size = RSND_DVC_CHANNELS;
_cfg->cfg.val = _cfg->val;
return __rsnd_kctrl_new(mod, rdai, rtd, name, &_cfg->cfg, update);
}
int rsnd_kctrl_new_s(struct rsnd_mod *mod,
struct rsnd_dai *rdai,
struct snd_soc_pcm_runtime *rtd,
const unsigned char *name,
void (*update)(struct rsnd_mod *mod),
struct rsnd_kctrl_cfg_s *_cfg,
u32 max)
{
_cfg->cfg.max = max;
_cfg->cfg.size = 1;
_cfg->cfg.val = &_cfg->val;
return __rsnd_kctrl_new(mod, rdai, rtd, name, &_cfg->cfg, update);
}
int rsnd_kctrl_new_e(struct rsnd_mod *mod,
struct rsnd_dai *rdai,
struct snd_soc_pcm_runtime *rtd,
const unsigned char *name,
struct rsnd_kctrl_cfg_s *_cfg,
void (*update)(struct rsnd_mod *mod),
const char * const *texts,
u32 max)
{
_cfg->cfg.max = max;
_cfg->cfg.size = 1;
_cfg->cfg.val = &_cfg->val;
_cfg->cfg.texts = texts;
return __rsnd_kctrl_new(mod, rdai, rtd, name, &_cfg->cfg, update);
}
/* /*
* snd_soc_platform * snd_soc_platform
*/ */
...@@ -976,6 +1155,49 @@ static const struct snd_soc_component_driver rsnd_soc_component = { ...@@ -976,6 +1155,49 @@ static const struct snd_soc_component_driver rsnd_soc_component = {
.name = "rsnd", .name = "rsnd",
}; };
static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv,
struct rsnd_dai *rdai,
int is_play)
{
struct rsnd_dai_stream *io = is_play ? &rdai->playback : &rdai->capture;
int ret;
ret = rsnd_dai_call(probe, io, rdai);
if (ret == -EAGAIN) {
/*
* Fallback to PIO mode
*/
/*
* call "remove" for SSI/SRC/DVC
* SSI will be switch to PIO mode if it was DMA mode
* see
* rsnd_dma_init()
* rsnd_ssi_fallback()
*/
rsnd_dai_call(remove, io, rdai);
/*
* remove SRC/DVC from DAI,
*/
rsnd_path_break(priv, io, src);
rsnd_path_break(priv, io, dvc);
/*
* fallback
*/
rsnd_dai_call(fallback, io, rdai);
/*
* retry to "probe".
* DAI has SSI which is PIO mode only now.
*/
ret = rsnd_dai_call(probe, io, rdai);
}
return ret;
}
/* /*
* rsnd probe * rsnd probe
*/ */
...@@ -1037,11 +1259,11 @@ static int rsnd_probe(struct platform_device *pdev) ...@@ -1037,11 +1259,11 @@ static int rsnd_probe(struct platform_device *pdev)
} }
for_each_rsnd_dai(rdai, priv, i) { for_each_rsnd_dai(rdai, priv, i) {
ret = rsnd_dai_call(probe, &rdai->playback, rdai); ret = rsnd_rdai_continuance_probe(priv, rdai, 1);
if (ret) if (ret)
goto exit_snd_probe; goto exit_snd_probe;
ret = rsnd_dai_call(probe, &rdai->capture, rdai); ret = rsnd_rdai_continuance_probe(priv, rdai, 0);
if (ret) if (ret)
goto exit_snd_probe; goto exit_snd_probe;
} }
......
...@@ -11,8 +11,6 @@ ...@@ -11,8 +11,6 @@
#include "rsnd.h" #include "rsnd.h"
#define RSND_DVC_NAME_SIZE 16 #define RSND_DVC_NAME_SIZE 16
#define RSND_DVC_VOLUME_MAX 100
#define RSND_DVC_VOLUME_NUM 2
#define DVC_NAME "dvc" #define DVC_NAME "dvc"
...@@ -20,8 +18,11 @@ struct rsnd_dvc { ...@@ -20,8 +18,11 @@ struct rsnd_dvc {
struct rsnd_dvc_platform_info *info; /* rcar_snd.h */ struct rsnd_dvc_platform_info *info; /* rcar_snd.h */
struct rsnd_mod mod; struct rsnd_mod mod;
struct clk *clk; struct clk *clk;
u8 volume[RSND_DVC_VOLUME_NUM]; struct rsnd_kctrl_cfg_m volume;
u8 mute[RSND_DVC_VOLUME_NUM]; struct rsnd_kctrl_cfg_m mute;
struct rsnd_kctrl_cfg_s ren; /* Ramp Enable */
struct rsnd_kctrl_cfg_s rup; /* Ramp Rate Up */
struct rsnd_kctrl_cfg_s rdown; /* Ramp Rate Down */
}; };
#define rsnd_mod_to_dvc(_mod) \ #define rsnd_mod_to_dvc(_mod) \
...@@ -33,23 +34,87 @@ struct rsnd_dvc { ...@@ -33,23 +34,87 @@ struct rsnd_dvc {
((pos) = (struct rsnd_dvc *)(priv)->dvc + i); \ ((pos) = (struct rsnd_dvc *)(priv)->dvc + i); \
i++) i++)
static const char const *dvc_ramp_rate[] = {
"128 dB/1 step", /* 00000 */
"64 dB/1 step", /* 00001 */
"32 dB/1 step", /* 00010 */
"16 dB/1 step", /* 00011 */
"8 dB/1 step", /* 00100 */
"4 dB/1 step", /* 00101 */
"2 dB/1 step", /* 00110 */
"1 dB/1 step", /* 00111 */
"0.5 dB/1 step", /* 01000 */
"0.25 dB/1 step", /* 01001 */
"0.125 dB/1 step", /* 01010 */
"0.125 dB/2 steps", /* 01011 */
"0.125 dB/4 steps", /* 01100 */
"0.125 dB/8 steps", /* 01101 */
"0.125 dB/16 steps", /* 01110 */
"0.125 dB/32 steps", /* 01111 */
"0.125 dB/64 steps", /* 10000 */
"0.125 dB/128 steps", /* 10001 */
"0.125 dB/256 steps", /* 10010 */
"0.125 dB/512 steps", /* 10011 */
"0.125 dB/1024 steps", /* 10100 */
"0.125 dB/2048 steps", /* 10101 */
"0.125 dB/4096 steps", /* 10110 */
"0.125 dB/8192 steps", /* 10111 */
};
static void rsnd_dvc_volume_update(struct rsnd_mod *mod) static void rsnd_dvc_volume_update(struct rsnd_mod *mod)
{ {
struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
u32 max = (0x00800000 - 1); u32 val[RSND_DVC_CHANNELS];
u32 vol[RSND_DVC_VOLUME_NUM]; u32 dvucr = 0;
u32 mute = 0; u32 mute = 0;
int i; int i;
for (i = 0; i < RSND_DVC_VOLUME_NUM; i++) { for (i = 0; i < dvc->mute.cfg.size; i++)
vol[i] = max / RSND_DVC_VOLUME_MAX * dvc->volume[i]; mute |= (!!dvc->mute.cfg.val[i]) << i;
mute |= (!!dvc->mute[i]) << i;
/* Disable DVC Register access */
rsnd_mod_write(mod, DVC_DVUER, 0);
/* 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];
}
/* 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);
} }
rsnd_mod_write(mod, DVC_VOL0R, vol[0]); rsnd_mod_write(mod, DVC_DVUCR, dvucr);
rsnd_mod_write(mod, DVC_VOL1R, vol[1]);
rsnd_mod_write(mod, DVC_ZCMCR, mute); /* Enable DVC Register access */
rsnd_mod_write(mod, DVC_DVUER, 1);
} }
static int rsnd_dvc_probe_gen2(struct rsnd_mod *mod, static int rsnd_dvc_probe_gen2(struct rsnd_mod *mod,
...@@ -58,7 +123,8 @@ static int rsnd_dvc_probe_gen2(struct rsnd_mod *mod, ...@@ -58,7 +123,8 @@ static int rsnd_dvc_probe_gen2(struct rsnd_mod *mod,
struct rsnd_priv *priv = rsnd_mod_to_priv(mod); struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
struct device *dev = rsnd_priv_to_dev(priv); struct device *dev = rsnd_priv_to_dev(priv);
dev_dbg(dev, "%s (Gen2) is probed\n", rsnd_mod_name(mod)); dev_dbg(dev, "%s[%d] (Gen2) is probed\n",
rsnd_mod_name(mod), rsnd_mod_id(mod));
return 0; return 0;
} }
...@@ -102,16 +168,11 @@ static int rsnd_dvc_init(struct rsnd_mod *dvc_mod, ...@@ -102,16 +168,11 @@ static int rsnd_dvc_init(struct rsnd_mod *dvc_mod,
rsnd_mod_write(dvc_mod, DVC_ADINR, rsnd_get_adinr(dvc_mod)); rsnd_mod_write(dvc_mod, DVC_ADINR, rsnd_get_adinr(dvc_mod));
/* enable Volume / Mute */
rsnd_mod_write(dvc_mod, DVC_DVUCR, 0x101);
/* ch0/ch1 Volume */ /* ch0/ch1 Volume */
rsnd_dvc_volume_update(dvc_mod); rsnd_dvc_volume_update(dvc_mod);
rsnd_mod_write(dvc_mod, DVC_DVUIR, 0); rsnd_mod_write(dvc_mod, DVC_DVUIR, 0);
rsnd_mod_write(dvc_mod, DVC_DVUER, 1);
rsnd_adg_set_cmd_timsel_gen2(rdai, dvc_mod, io); rsnd_adg_set_cmd_timsel_gen2(rdai, dvc_mod, io);
return 0; return 0;
...@@ -143,86 +204,6 @@ static int rsnd_dvc_stop(struct rsnd_mod *mod, ...@@ -143,86 +204,6 @@ static int rsnd_dvc_stop(struct rsnd_mod *mod,
return 0; return 0;
} }
static int rsnd_dvc_volume_info(struct snd_kcontrol *kctrl,
struct snd_ctl_elem_info *uinfo)
{
struct rsnd_mod *mod = snd_kcontrol_chip(kctrl);
struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
u8 *val = (u8 *)kctrl->private_value;
uinfo->count = RSND_DVC_VOLUME_NUM;
uinfo->value.integer.min = 0;
if (val == dvc->volume) {
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->value.integer.max = RSND_DVC_VOLUME_MAX;
} else {
uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
uinfo->value.integer.max = 1;
}
return 0;
}
static int rsnd_dvc_volume_get(struct snd_kcontrol *kctrl,
struct snd_ctl_elem_value *ucontrol)
{
u8 *val = (u8 *)kctrl->private_value;
int i;
for (i = 0; i < RSND_DVC_VOLUME_NUM; i++)
ucontrol->value.integer.value[i] = val[i];
return 0;
}
static int rsnd_dvc_volume_put(struct snd_kcontrol *kctrl,
struct snd_ctl_elem_value *ucontrol)
{
struct rsnd_mod *mod = snd_kcontrol_chip(kctrl);
u8 *val = (u8 *)kctrl->private_value;
int i, change = 0;
for (i = 0; i < RSND_DVC_VOLUME_NUM; i++) {
change |= (ucontrol->value.integer.value[i] != val[i]);
val[i] = ucontrol->value.integer.value[i];
}
if (change)
rsnd_dvc_volume_update(mod);
return change;
}
static int __rsnd_dvc_pcm_new(struct rsnd_mod *mod,
struct rsnd_dai *rdai,
struct snd_soc_pcm_runtime *rtd,
const unsigned char *name,
u8 *private)
{
struct snd_card *card = rtd->card->snd_card;
struct snd_kcontrol *kctrl;
struct snd_kcontrol_new knew = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = name,
.info = rsnd_dvc_volume_info,
.get = rsnd_dvc_volume_get,
.put = rsnd_dvc_volume_put,
.private_value = (unsigned long)private,
};
int ret;
kctrl = snd_ctl_new1(&knew, mod);
if (!kctrl)
return -ENOMEM;
ret = snd_ctl_add(card, kctrl);
if (ret < 0)
return ret;
return 0;
}
static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
struct rsnd_dai *rdai, struct rsnd_dai *rdai,
struct snd_soc_pcm_runtime *rtd) struct snd_soc_pcm_runtime *rtd)
...@@ -232,18 +213,48 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, ...@@ -232,18 +213,48 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
int ret; int ret;
/* Volume */ /* Volume */
ret = __rsnd_dvc_pcm_new(mod, rdai, rtd, ret = rsnd_kctrl_new_m(mod, rdai, rtd,
rsnd_dai_is_play(rdai, io) ? rsnd_dai_is_play(rdai, io) ?
"DVC Out Playback Volume" : "DVC In Capture Volume", "DVC Out Playback Volume" : "DVC In Capture Volume",
dvc->volume); rsnd_dvc_volume_update,
&dvc->volume, 0x00800000 - 1);
if (ret < 0) if (ret < 0)
return ret; return ret;
/* Mute */ /* Mute */
ret = __rsnd_dvc_pcm_new(mod, rdai, rtd, ret = rsnd_kctrl_new_m(mod, rdai, rtd,
rsnd_dai_is_play(rdai, io) ? rsnd_dai_is_play(rdai, io) ?
"DVC Out Mute Switch" : "DVC In Mute Switch", "DVC Out Mute Switch" : "DVC In Mute Switch",
dvc->mute); rsnd_dvc_volume_update,
&dvc->mute, 1);
if (ret < 0)
return ret;
/* Ramp */
ret = rsnd_kctrl_new_s(mod, rdai, rtd,
rsnd_dai_is_play(rdai, io) ?
"DVC Out Ramp Switch" : "DVC In Ramp Switch",
rsnd_dvc_volume_update,
&dvc->ren, 1);
if (ret < 0)
return ret;
ret = rsnd_kctrl_new_e(mod, rdai, rtd,
rsnd_dai_is_play(rdai, io) ?
"DVC Out Ramp Up Rate" : "DVC In Ramp Up Rate",
&dvc->rup,
rsnd_dvc_volume_update,
dvc_ramp_rate, ARRAY_SIZE(dvc_ramp_rate));
if (ret < 0)
return ret;
ret = rsnd_kctrl_new_e(mod, rdai, rtd,
rsnd_dai_is_play(rdai, io) ?
"DVC Out Ramp Down Rate" : "DVC In Ramp Down Rate",
&dvc->rdown,
rsnd_dvc_volume_update,
dvc_ramp_rate, ARRAY_SIZE(dvc_ramp_rate));
if (ret < 0) if (ret < 0)
return ret; return ret;
......
...@@ -8,6 +8,17 @@ ...@@ -8,6 +8,17 @@
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
/*
* #define DEBUG
*
* you can also add below in
* ${LINUX}/drivers/base/regmap/regmap.c
* for regmap debug
*
* #define LOG_DEVICE "xxxx.rcar_sound"
*/
#include "rsnd.h" #include "rsnd.h"
struct rsnd_gen { struct rsnd_gen {
...@@ -67,9 +78,10 @@ u32 rsnd_read(struct rsnd_priv *priv, ...@@ -67,9 +78,10 @@ u32 rsnd_read(struct rsnd_priv *priv,
if (!rsnd_is_accessible_reg(priv, gen, reg)) if (!rsnd_is_accessible_reg(priv, gen, reg))
return 0; return 0;
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 - 0x%04d : %08x\n", rsnd_mod_name(mod), reg, val); regmap_fields_read(gen->regs[reg], rsnd_mod_id(mod), &val);
return val; return val;
} }
...@@ -84,9 +96,10 @@ void rsnd_write(struct rsnd_priv *priv, ...@@ -84,9 +96,10 @@ void rsnd_write(struct rsnd_priv *priv,
if (!rsnd_is_accessible_reg(priv, gen, reg)) if (!rsnd_is_accessible_reg(priv, gen, reg))
return; return;
regmap_fields_write(gen->regs[reg], rsnd_mod_id(mod), data); dev_dbg(dev, "w %s[%d] - %4d : %08x\n",
rsnd_mod_name(mod), rsnd_mod_id(mod), reg, data);
dev_dbg(dev, "w %s - 0x%04d : %08x\n", rsnd_mod_name(mod), reg, data); regmap_fields_write(gen->regs[reg], rsnd_mod_id(mod), data);
} }
void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod,
...@@ -98,11 +111,11 @@ void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, ...@@ -98,11 +111,11 @@ void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod,
if (!rsnd_is_accessible_reg(priv, gen, reg)) if (!rsnd_is_accessible_reg(priv, gen, reg))
return; 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), regmap_fields_update_bits(gen->regs[reg], rsnd_mod_id(mod),
mask, data); mask, data);
dev_dbg(dev, "b %s - 0x%04d : %08x/%08x\n",
rsnd_mod_name(mod), reg, data, mask);
} }
#define rsnd_gen_regmap_init(priv, id_size, reg_id, conf) \ #define rsnd_gen_regmap_init(priv, id_size, reg_id, conf) \
...@@ -311,6 +324,9 @@ static int rsnd_gen2_probe(struct platform_device *pdev, ...@@ -311,6 +324,9 @@ static int rsnd_gen2_probe(struct platform_device *pdev,
RSND_GEN_M_REG(DVC_ADINR, 0xe08, 0x100), RSND_GEN_M_REG(DVC_ADINR, 0xe08, 0x100),
RSND_GEN_M_REG(DVC_DVUCR, 0xe10, 0x100), RSND_GEN_M_REG(DVC_DVUCR, 0xe10, 0x100),
RSND_GEN_M_REG(DVC_ZCMCR, 0xe14, 0x100), RSND_GEN_M_REG(DVC_ZCMCR, 0xe14, 0x100),
RSND_GEN_M_REG(DVC_VRCTR, 0xe18, 0x100),
RSND_GEN_M_REG(DVC_VRPDR, 0xe1c, 0x100),
RSND_GEN_M_REG(DVC_VRDBR, 0xe20, 0x100),
RSND_GEN_M_REG(DVC_VOL0R, 0xe28, 0x100), RSND_GEN_M_REG(DVC_VOL0R, 0xe28, 0x100),
RSND_GEN_M_REG(DVC_VOL1R, 0xe2c, 0x100), RSND_GEN_M_REG(DVC_VOL1R, 0xe2c, 0x100),
RSND_GEN_M_REG(DVC_DVUER, 0xe48, 0x100), RSND_GEN_M_REG(DVC_DVUER, 0xe48, 0x100),
......
...@@ -91,6 +91,9 @@ enum rsnd_reg { ...@@ -91,6 +91,9 @@ enum rsnd_reg {
RSND_REG_SHARE20, RSND_REG_SHARE20,
RSND_REG_SHARE21, RSND_REG_SHARE21,
RSND_REG_SHARE22, RSND_REG_SHARE22,
RSND_REG_SHARE23,
RSND_REG_SHARE24,
RSND_REG_SHARE25,
RSND_REG_MAX, RSND_REG_MAX,
}; };
...@@ -129,6 +132,9 @@ enum rsnd_reg { ...@@ -129,6 +132,9 @@ enum rsnd_reg {
#define RSND_REG_CMD_CTRL RSND_REG_SHARE20 #define RSND_REG_CMD_CTRL RSND_REG_SHARE20
#define RSND_REG_CMDOUT_TIMSEL RSND_REG_SHARE21 #define RSND_REG_CMDOUT_TIMSEL RSND_REG_SHARE21
#define RSND_REG_BUSIF_DALIGN RSND_REG_SHARE22 #define RSND_REG_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
struct rsnd_of_data; struct rsnd_of_data;
struct rsnd_priv; struct rsnd_priv;
...@@ -200,6 +206,8 @@ struct rsnd_mod_ops { ...@@ -200,6 +206,8 @@ struct rsnd_mod_ops {
int (*pcm_new)(struct rsnd_mod *mod, int (*pcm_new)(struct rsnd_mod *mod,
struct rsnd_dai *rdai, struct rsnd_dai *rdai,
struct snd_soc_pcm_runtime *rtd); struct snd_soc_pcm_runtime *rtd);
int (*fallback)(struct rsnd_mod *mod,
struct rsnd_dai *rdai);
}; };
struct rsnd_dai_stream; struct rsnd_dai_stream;
...@@ -210,7 +218,35 @@ struct rsnd_mod { ...@@ -210,7 +218,35 @@ struct rsnd_mod {
struct rsnd_mod_ops *ops; struct rsnd_mod_ops *ops;
struct rsnd_dma dma; struct rsnd_dma dma;
struct rsnd_dai_stream *io; struct rsnd_dai_stream *io;
u32 status;
}; };
/*
* status
*
* bit
* 0 0: probe 1: remove
* 1 0: init 1: quit
* 2 0: start 1: stop
* 3 0: pcm_new
* 4 0: fallback
*/
#define __rsnd_mod_shift_probe 0
#define __rsnd_mod_shift_remove 0
#define __rsnd_mod_shift_init 1
#define __rsnd_mod_shift_quit 1
#define __rsnd_mod_shift_start 2
#define __rsnd_mod_shift_stop 2
#define __rsnd_mod_shift_pcm_new 3
#define __rsnd_mod_shift_fallback 4
#define __rsnd_mod_call_probe 0
#define __rsnd_mod_call_remove 1
#define __rsnd_mod_call_init 0
#define __rsnd_mod_call_quit 1
#define __rsnd_mod_call_start 0
#define __rsnd_mod_call_stop 1
#define __rsnd_mod_call_pcm_new 0
#define __rsnd_mod_call_fallback 0
#define rsnd_mod_to_priv(mod) ((mod)->priv) #define rsnd_mod_to_priv(mod) ((mod)->priv)
#define rsnd_mod_to_dma(mod) (&(mod)->dma) #define rsnd_mod_to_dma(mod) (&(mod)->dma)
...@@ -267,7 +303,8 @@ struct rsnd_dai *rsnd_dai_get(struct rsnd_priv *priv, int id); ...@@ -267,7 +303,8 @@ struct rsnd_dai *rsnd_dai_get(struct rsnd_priv *priv, int id);
int rsnd_dai_is_play(struct rsnd_dai *rdai, struct rsnd_dai_stream *io); int rsnd_dai_is_play(struct rsnd_dai *rdai, struct rsnd_dai_stream *io);
int rsnd_dai_id(struct rsnd_priv *priv, struct rsnd_dai *rdai); int rsnd_dai_id(struct rsnd_priv *priv, struct rsnd_dai *rdai);
#define rsnd_dai_get_platform_info(rdai) ((rdai)->info) #define rsnd_dai_get_platform_info(rdai) ((rdai)->info)
#define rsnd_io_to_runtime(io) ((io)->substream->runtime) #define rsnd_io_to_runtime(io) ((io)->substream ? \
(io)->substream->runtime : NULL)
void rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int cnt); void rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int cnt);
int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional); int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional);
...@@ -381,6 +418,51 @@ struct rsnd_priv { ...@@ -381,6 +418,51 @@ struct rsnd_priv {
is_play; \ is_play; \
}) })
/*
* rsnd_kctrl
*/
struct rsnd_kctrl_cfg {
unsigned int max;
unsigned int size;
u32 *val;
const char * const *texts;
void (*update)(struct rsnd_mod *mod);
};
#define RSND_DVC_CHANNELS 2
struct rsnd_kctrl_cfg_m {
struct rsnd_kctrl_cfg cfg;
u32 val[RSND_DVC_CHANNELS];
};
struct rsnd_kctrl_cfg_s {
struct rsnd_kctrl_cfg cfg;
u32 val;
};
int rsnd_kctrl_new_m(struct rsnd_mod *mod,
struct rsnd_dai *rdai,
struct snd_soc_pcm_runtime *rtd,
const unsigned char *name,
void (*update)(struct rsnd_mod *mod),
struct rsnd_kctrl_cfg_m *_cfg,
u32 max);
int rsnd_kctrl_new_s(struct rsnd_mod *mod,
struct rsnd_dai *rdai,
struct snd_soc_pcm_runtime *rtd,
const unsigned char *name,
void (*update)(struct rsnd_mod *mod),
struct rsnd_kctrl_cfg_s *_cfg,
u32 max);
int rsnd_kctrl_new_e(struct rsnd_mod *mod,
struct rsnd_dai *rdai,
struct snd_soc_pcm_runtime *rtd,
const unsigned char *name,
struct rsnd_kctrl_cfg_s *_cfg,
void (*update)(struct rsnd_mod *mod),
const char * const *texts,
u32 max);
/* /*
* R-Car SRC * R-Car SRC
*/ */
...@@ -395,10 +477,11 @@ int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod, ...@@ -395,10 +477,11 @@ int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod,
struct rsnd_dai *rdai, struct rsnd_dai *rdai,
int use_busif); int use_busif);
int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod, int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod,
struct rsnd_dai *rdai, struct rsnd_dai *rdai);
int use_busif); int rsnd_src_ssi_irq_enable(struct rsnd_mod *ssi_mod,
int rsnd_src_enable_ssi_irq(struct rsnd_mod *ssi_mod,
struct rsnd_dai *rdai); struct rsnd_dai *rdai);
int rsnd_src_ssi_irq_disable(struct rsnd_mod *ssi_mod,
struct rsnd_dai *rdai);
#define rsnd_src_nr(priv) ((priv)->src_nr) #define rsnd_src_nr(priv) ((priv)->src_nr)
...@@ -410,6 +493,7 @@ int rsnd_ssi_probe(struct platform_device *pdev, ...@@ -410,6 +493,7 @@ int rsnd_ssi_probe(struct platform_device *pdev,
struct rsnd_priv *priv); struct rsnd_priv *priv);
struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id); struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id);
int rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod); int rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod);
int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod);
/* /*
* R-Car DVC * R-Car DVC
......
...@@ -175,30 +175,47 @@ int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod, ...@@ -175,30 +175,47 @@ int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod,
} }
int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod, int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod,
struct rsnd_dai *rdai, struct rsnd_dai *rdai)
int use_busif)
{ {
/* /*
* DMA settings for SSIU * DMA settings for SSIU
*/ */
if (use_busif) rsnd_mod_write(ssi_mod, SSI_CTRL, 0);
rsnd_mod_write(ssi_mod, SSI_CTRL, 0);
return 0; return 0;
} }
int rsnd_src_enable_ssi_irq(struct rsnd_mod *ssi_mod, int rsnd_src_ssi_irq_enable(struct rsnd_mod *ssi_mod,
struct rsnd_dai *rdai) struct rsnd_dai *rdai)
{ {
struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod); struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
/* enable PIO interrupt if Gen2 */ if (rsnd_is_gen1(priv))
if (rsnd_is_gen2(priv)) return 0;
/* enable SSI interrupt if Gen2 */
if (rsnd_ssi_is_dma_mode(ssi_mod))
rsnd_mod_write(ssi_mod, INT_ENABLE, 0x0e000000);
else
rsnd_mod_write(ssi_mod, INT_ENABLE, 0x0f000000); rsnd_mod_write(ssi_mod, INT_ENABLE, 0x0f000000);
return 0; return 0;
} }
int rsnd_src_ssi_irq_disable(struct rsnd_mod *ssi_mod,
struct rsnd_dai *rdai)
{
struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
if (rsnd_is_gen1(priv))
return 0;
/* disable SSI interrupt if Gen2 */
rsnd_mod_write(ssi_mod, INT_ENABLE, 0x00000000);
return 0;
}
unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv, unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv,
struct rsnd_dai_stream *io, struct rsnd_dai_stream *io,
struct snd_pcm_runtime *runtime) struct snd_pcm_runtime *runtime)
...@@ -239,12 +256,6 @@ static int rsnd_src_set_convert_rate(struct rsnd_mod *mod, ...@@ -239,12 +256,6 @@ static int rsnd_src_set_convert_rate(struct rsnd_mod *mod,
rsnd_mod_write(mod, SRC_SWRSR, 0); rsnd_mod_write(mod, SRC_SWRSR, 0);
rsnd_mod_write(mod, SRC_SWRSR, 1); rsnd_mod_write(mod, SRC_SWRSR, 1);
/*
* Initialize the operation of the SRC internal circuits
* see rsnd_src_start()
*/
rsnd_mod_write(mod, SRC_SRCIR, 1);
/* Set channel number and output bit length */ /* Set channel number and output bit length */
rsnd_mod_write(mod, SRC_ADINR, rsnd_get_adinr(mod)); rsnd_mod_write(mod, SRC_ADINR, rsnd_get_adinr(mod));
...@@ -269,6 +280,12 @@ static int rsnd_src_init(struct rsnd_mod *mod, ...@@ -269,6 +280,12 @@ static int rsnd_src_init(struct rsnd_mod *mod,
clk_prepare_enable(src->clk); clk_prepare_enable(src->clk);
/*
* Initialize the operation of the SRC internal circuits
* see rsnd_src_start()
*/
rsnd_mod_write(mod, SRC_SRCIR, 1);
return 0; return 0;
} }
...@@ -282,32 +299,20 @@ static int rsnd_src_quit(struct rsnd_mod *mod, ...@@ -282,32 +299,20 @@ static int rsnd_src_quit(struct rsnd_mod *mod,
return 0; return 0;
} }
static int rsnd_src_start(struct rsnd_mod *mod, static int rsnd_src_start(struct rsnd_mod *mod)
struct rsnd_dai *rdai)
{ {
struct rsnd_src *src = rsnd_mod_to_src(mod);
/* /*
* Cancel the initialization and operate the SRC function * Cancel the initialization and operate the SRC function
* see rsnd_src_set_convert_rate() * see rsnd_src_init()
*/ */
rsnd_mod_write(mod, SRC_SRCIR, 0); rsnd_mod_write(mod, SRC_SRCIR, 0);
if (rsnd_src_convert_rate(src))
rsnd_mod_write(mod, SRC_ROUTE_MODE0, 1);
return 0; return 0;
} }
static int rsnd_src_stop(struct rsnd_mod *mod)
static int rsnd_src_stop(struct rsnd_mod *mod,
struct rsnd_dai *rdai)
{ {
struct rsnd_src *src = rsnd_mod_to_src(mod); /* nothing to do */
if (rsnd_src_convert_rate(src))
rsnd_mod_write(mod, SRC_ROUTE_MODE0, 0);
return 0; return 0;
} }
...@@ -414,6 +419,7 @@ static int rsnd_src_set_convert_timing_gen1(struct rsnd_mod *mod, ...@@ -414,6 +419,7 @@ static int rsnd_src_set_convert_timing_gen1(struct rsnd_mod *mod,
static int rsnd_src_set_convert_rate_gen1(struct rsnd_mod *mod, static int rsnd_src_set_convert_rate_gen1(struct rsnd_mod *mod,
struct rsnd_dai *rdai) struct rsnd_dai *rdai)
{ {
struct rsnd_src *src = rsnd_mod_to_src(mod);
int ret; int ret;
ret = rsnd_src_set_convert_rate(mod, rdai); ret = rsnd_src_set_convert_rate(mod, rdai);
...@@ -427,6 +433,10 @@ static int rsnd_src_set_convert_rate_gen1(struct rsnd_mod *mod, ...@@ -427,6 +433,10 @@ static int rsnd_src_set_convert_rate_gen1(struct rsnd_mod *mod,
rsnd_mod_write(mod, SRC_MNFSR, rsnd_mod_write(mod, SRC_MNFSR,
rsnd_mod_read(mod, SRC_IFSVR) / 100 * 98); rsnd_mod_read(mod, SRC_IFSVR) / 100 * 98);
/* Gen1/Gen2 are not compatible */
if (rsnd_src_convert_rate(src))
rsnd_mod_write(mod, SRC_ROUTE_MODE0, 1);
/* no SRC_BFSSR settings, since SRC_SRCCR::BUFMD is 0 */ /* no SRC_BFSSR settings, since SRC_SRCCR::BUFMD is 0 */
return 0; return 0;
...@@ -438,7 +448,8 @@ static int rsnd_src_probe_gen1(struct rsnd_mod *mod, ...@@ -438,7 +448,8 @@ static int rsnd_src_probe_gen1(struct rsnd_mod *mod,
struct rsnd_priv *priv = rsnd_mod_to_priv(mod); struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
struct device *dev = rsnd_priv_to_dev(priv); struct device *dev = rsnd_priv_to_dev(priv);
dev_dbg(dev, "%s (Gen1) is probed\n", rsnd_mod_name(mod)); dev_dbg(dev, "%s[%d] (Gen1) is probed\n",
rsnd_mod_name(mod), rsnd_mod_id(mod));
return 0; return 0;
} }
...@@ -474,7 +485,7 @@ static int rsnd_src_start_gen1(struct rsnd_mod *mod, ...@@ -474,7 +485,7 @@ static int rsnd_src_start_gen1(struct rsnd_mod *mod,
rsnd_mod_bset(mod, SRC_ROUTE_CTRL, (1 << id), (1 << id)); rsnd_mod_bset(mod, SRC_ROUTE_CTRL, (1 << id), (1 << id));
return rsnd_src_start(mod, rdai); return rsnd_src_start(mod);
} }
static int rsnd_src_stop_gen1(struct rsnd_mod *mod, static int rsnd_src_stop_gen1(struct rsnd_mod *mod,
...@@ -484,7 +495,7 @@ static int rsnd_src_stop_gen1(struct rsnd_mod *mod, ...@@ -484,7 +495,7 @@ static int rsnd_src_stop_gen1(struct rsnd_mod *mod,
rsnd_mod_bset(mod, SRC_ROUTE_CTRL, (1 << id), 0); rsnd_mod_bset(mod, SRC_ROUTE_CTRL, (1 << id), 0);
return rsnd_src_stop(mod, rdai); return rsnd_src_stop(mod);
} }
static struct rsnd_mod_ops rsnd_src_gen1_ops = { static struct rsnd_mod_ops rsnd_src_gen1_ops = {
...@@ -507,16 +518,17 @@ static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod, ...@@ -507,16 +518,17 @@ static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod,
struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
struct rsnd_src *src = rsnd_mod_to_src(mod); struct rsnd_src *src = rsnd_mod_to_src(mod);
u32 convert_rate = rsnd_src_convert_rate(src);
uint ratio; uint ratio;
int ret; int ret;
/* 6 - 1/6 are very enough ratio for SRC_BSDSR */ /* 6 - 1/6 are very enough ratio for SRC_BSDSR */
if (!rsnd_src_convert_rate(src)) if (!convert_rate)
ratio = 0; ratio = 0;
else if (rsnd_src_convert_rate(src) > runtime->rate) else if (convert_rate > runtime->rate)
ratio = 100 * rsnd_src_convert_rate(src) / runtime->rate; ratio = 100 * convert_rate / runtime->rate;
else else
ratio = 100 * runtime->rate / rsnd_src_convert_rate(src); ratio = 100 * runtime->rate / convert_rate;
if (ratio > 600) { if (ratio > 600) {
dev_err(dev, "FSO/FSI ratio error\n"); dev_err(dev, "FSO/FSI ratio error\n");
...@@ -529,6 +541,11 @@ static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod, ...@@ -529,6 +541,11 @@ static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod,
rsnd_mod_write(mod, SRC_SRCCR, 0x00011110); rsnd_mod_write(mod, SRC_SRCCR, 0x00011110);
if (convert_rate) {
/* Gen1/Gen2 are not compatible */
rsnd_mod_write(mod, SRC_ROUTE_MODE0, 1);
}
switch (rsnd_mod_id(mod)) { switch (rsnd_mod_id(mod)) {
case 5: case 5:
case 6: case 6:
...@@ -578,9 +595,11 @@ static int rsnd_src_probe_gen2(struct rsnd_mod *mod, ...@@ -578,9 +595,11 @@ static int rsnd_src_probe_gen2(struct rsnd_mod *mod,
rsnd_info_is_playback(priv, src), rsnd_info_is_playback(priv, src),
src->info->dma_id); src->info->dma_id);
if (ret < 0) if (ret < 0)
dev_err(dev, "SRC DMA failed\n"); dev_err(dev, "%s[%d] (Gen2) failed\n",
rsnd_mod_name(mod), rsnd_mod_id(mod));
dev_dbg(dev, "%s (Gen2) is probed\n", rsnd_mod_name(mod)); else
dev_dbg(dev, "%s[%d] (Gen2) is probed\n",
rsnd_mod_name(mod), rsnd_mod_id(mod));
return ret; return ret;
} }
...@@ -624,7 +643,7 @@ static int rsnd_src_start_gen2(struct rsnd_mod *mod, ...@@ -624,7 +643,7 @@ static int rsnd_src_start_gen2(struct rsnd_mod *mod,
rsnd_mod_write(mod, SRC_CTRL, val); rsnd_mod_write(mod, SRC_CTRL, val);
return rsnd_src_start(mod, rdai); return rsnd_src_start(mod);
} }
static int rsnd_src_stop_gen2(struct rsnd_mod *mod, static int rsnd_src_stop_gen2(struct rsnd_mod *mod,
...@@ -636,7 +655,7 @@ static int rsnd_src_stop_gen2(struct rsnd_mod *mod, ...@@ -636,7 +655,7 @@ static int rsnd_src_stop_gen2(struct rsnd_mod *mod,
rsnd_dma_stop(rsnd_mod_to_dma(&src->mod)); rsnd_dma_stop(rsnd_mod_to_dma(&src->mod));
return rsnd_src_stop(mod, rdai); return rsnd_src_stop(mod);
} }
static struct rsnd_mod_ops rsnd_src_gen2_ops = { static struct rsnd_mod_ops rsnd_src_gen2_ops = {
......
...@@ -68,7 +68,6 @@ struct rsnd_ssi { ...@@ -68,7 +68,6 @@ struct rsnd_ssi {
struct rsnd_dai *rdai; struct rsnd_dai *rdai;
u32 cr_own; u32 cr_own;
u32 cr_clk; u32 cr_clk;
u32 cr_etc;
int err; int err;
unsigned int usrcnt; unsigned int usrcnt;
unsigned int rate; unsigned int rate;
...@@ -83,7 +82,7 @@ struct rsnd_ssi { ...@@ -83,7 +82,7 @@ struct rsnd_ssi {
#define rsnd_ssi_nr(priv) ((priv)->ssi_nr) #define rsnd_ssi_nr(priv) ((priv)->ssi_nr)
#define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod) #define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod)
#define rsnd_dma_to_ssi(dma) rsnd_mod_to_ssi(rsnd_dma_to_mod(dma)) #define rsnd_dma_to_ssi(dma) rsnd_mod_to_ssi(rsnd_dma_to_mod(dma))
#define rsnd_ssi_pio_available(ssi) ((ssi)->info->pio_irq > 0) #define rsnd_ssi_pio_available(ssi) ((ssi)->info->irq > 0)
#define rsnd_ssi_dma_available(ssi) \ #define rsnd_ssi_dma_available(ssi) \
rsnd_dma_available(rsnd_mod_to_dma(&(ssi)->mod)) rsnd_dma_available(rsnd_mod_to_dma(&(ssi)->mod))
#define rsnd_ssi_clk_from_parent(ssi) ((ssi)->parent) #define rsnd_ssi_clk_from_parent(ssi) ((ssi)->parent)
...@@ -96,6 +95,9 @@ static int rsnd_ssi_use_busif(struct rsnd_mod *mod) ...@@ -96,6 +95,9 @@ static int rsnd_ssi_use_busif(struct rsnd_mod *mod)
struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
int use_busif = 0; int use_busif = 0;
if (!rsnd_ssi_is_dma_mode(mod))
return 0;
if (!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_NO_BUSIF)) if (!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_NO_BUSIF))
use_busif = 1; use_busif = 1;
if (rsnd_io_to_mod_src(io)) if (rsnd_io_to_mod_src(io))
...@@ -159,7 +161,8 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi, ...@@ -159,7 +161,8 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi,
ssi->cr_clk = FORCE | SWL_32 | ssi->cr_clk = FORCE | SWL_32 |
SCKD | SWSD | CKDV(j); SCKD | SWSD | CKDV(j);
dev_dbg(dev, "ssi%d outputs %u Hz\n", dev_dbg(dev, "%s[%d] outputs %u Hz\n",
rsnd_mod_name(&ssi->mod),
rsnd_mod_id(&ssi->mod), rate); rsnd_mod_id(&ssi->mod), rate);
return 0; return 0;
...@@ -184,6 +187,7 @@ static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi, ...@@ -184,6 +187,7 @@ static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi,
{ {
struct rsnd_priv *priv = rsnd_mod_to_priv(&ssi->mod); struct rsnd_priv *priv = rsnd_mod_to_priv(&ssi->mod);
struct device *dev = rsnd_priv_to_dev(priv); struct device *dev = rsnd_priv_to_dev(priv);
u32 cr_mode;
u32 cr; u32 cr;
if (0 == ssi->usrcnt) { if (0 == ssi->usrcnt) {
...@@ -197,16 +201,29 @@ static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi, ...@@ -197,16 +201,29 @@ static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi,
} }
} }
cr_mode = rsnd_ssi_is_dma_mode(&ssi->mod) ?
DMEN : /* DMA : enable DMA */
DIEN; /* PIO : enable Data interrupt */
cr = ssi->cr_own | cr = ssi->cr_own |
ssi->cr_clk | ssi->cr_clk |
ssi->cr_etc | cr_mode |
EN; UIEN | OIEN | EN;
rsnd_mod_write(&ssi->mod, SSICR, cr); rsnd_mod_write(&ssi->mod, SSICR, cr);
/* enable WS continue */
if (rsnd_dai_is_clk_master(rdai))
rsnd_mod_write(&ssi->mod, SSIWSR, CONT);
/* clear error status */
rsnd_mod_write(&ssi->mod, SSISR, 0);
ssi->usrcnt++; ssi->usrcnt++;
dev_dbg(dev, "ssi%d hw started\n", rsnd_mod_id(&ssi->mod)); dev_dbg(dev, "%s[%d] hw started\n",
rsnd_mod_name(&ssi->mod), rsnd_mod_id(&ssi->mod));
} }
static void rsnd_ssi_hw_stop(struct rsnd_ssi *ssi, static void rsnd_ssi_hw_stop(struct rsnd_ssi *ssi,
...@@ -249,7 +266,8 @@ static void rsnd_ssi_hw_stop(struct rsnd_ssi *ssi, ...@@ -249,7 +266,8 @@ static void rsnd_ssi_hw_stop(struct rsnd_ssi *ssi,
clk_disable_unprepare(ssi->clk); clk_disable_unprepare(ssi->clk);
} }
dev_dbg(dev, "ssi%d hw stopped\n", rsnd_mod_id(&ssi->mod)); dev_dbg(dev, "%s[%d] hw stopped\n",
rsnd_mod_name(&ssi->mod), rsnd_mod_id(&ssi->mod));
} }
/* /*
...@@ -334,25 +352,54 @@ static void rsnd_ssi_record_error(struct rsnd_ssi *ssi, u32 status) ...@@ -334,25 +352,54 @@ static void rsnd_ssi_record_error(struct rsnd_ssi *ssi, u32 status)
} }
} }
/* static int rsnd_ssi_start(struct rsnd_mod *mod,
* SSI PIO struct rsnd_dai *rdai)
*/ {
static irqreturn_t rsnd_ssi_pio_interrupt(int irq, void *data) struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
rsnd_src_ssiu_start(mod, rdai, rsnd_ssi_use_busif(mod));
rsnd_ssi_hw_start(ssi, rdai, io);
rsnd_src_ssi_irq_enable(mod, rdai);
return 0;
}
static int rsnd_ssi_stop(struct rsnd_mod *mod,
struct rsnd_dai *rdai)
{
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
rsnd_src_ssi_irq_disable(mod, rdai);
rsnd_ssi_record_error(ssi, rsnd_mod_read(mod, SSISR));
rsnd_ssi_hw_stop(ssi, rdai);
rsnd_src_ssiu_stop(mod, rdai);
return 0;
}
static irqreturn_t rsnd_ssi_interrupt(int irq, void *data)
{ {
struct rsnd_ssi *ssi = data; struct rsnd_ssi *ssi = data;
struct rsnd_dai *rdai = ssi->rdai;
struct rsnd_mod *mod = &ssi->mod; struct rsnd_mod *mod = &ssi->mod;
struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
u32 status = rsnd_mod_read(mod, SSISR); u32 status = rsnd_mod_read(mod, SSISR);
irqreturn_t ret = IRQ_NONE;
if (io && (status & DIRQ)) { if (!io)
struct rsnd_dai *rdai = ssi->rdai; return IRQ_NONE;
/* PIO only */
if (status & DIRQ) {
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
u32 *buf = (u32 *)(runtime->dma_area + u32 *buf = (u32 *)(runtime->dma_area +
rsnd_dai_pointer_offset(io, 0)); rsnd_dai_pointer_offset(io, 0));
rsnd_ssi_record_error(ssi, status);
/* /*
* 8/16/32 data can be assesse to TDR/RDR register * 8/16/32 data can be assesse to TDR/RDR register
* directly as 32bit data * directly as 32bit data
...@@ -364,73 +411,60 @@ static irqreturn_t rsnd_ssi_pio_interrupt(int irq, void *data) ...@@ -364,73 +411,60 @@ static irqreturn_t rsnd_ssi_pio_interrupt(int irq, void *data)
*buf = rsnd_mod_read(mod, SSIRDR); *buf = rsnd_mod_read(mod, SSIRDR);
rsnd_dai_pointer_update(io, sizeof(*buf)); rsnd_dai_pointer_update(io, sizeof(*buf));
}
/* PIO / DMA */
if (status & (UIRQ | OIRQ)) {
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
struct device *dev = rsnd_priv_to_dev(priv);
/*
* restart SSI
*/
rsnd_ssi_stop(mod, rdai);
rsnd_ssi_start(mod, rdai);
ret = IRQ_HANDLED; dev_dbg(dev, "%s[%d] restart\n",
rsnd_mod_name(mod), rsnd_mod_id(mod));
} }
return ret; rsnd_ssi_record_error(ssi, status);
return IRQ_HANDLED;
} }
/*
* SSI PIO
*/
static int rsnd_ssi_pio_probe(struct rsnd_mod *mod, static int rsnd_ssi_pio_probe(struct rsnd_mod *mod,
struct rsnd_dai *rdai) struct rsnd_dai *rdai)
{ {
struct rsnd_priv *priv = rsnd_mod_to_priv(mod); struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
struct device *dev = rsnd_priv_to_dev(priv); struct device *dev = rsnd_priv_to_dev(priv);
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
int irq = ssi->info->pio_irq;
int ret; int ret;
ret = devm_request_irq(dev, irq, ret = devm_request_irq(dev, ssi->info->irq,
rsnd_ssi_pio_interrupt, rsnd_ssi_interrupt,
IRQF_SHARED, IRQF_SHARED,
dev_name(dev), ssi); dev_name(dev), ssi);
if (ret) if (ret)
dev_err(dev, "SSI request interrupt failed\n"); dev_err(dev, "%s[%d] (PIO) request interrupt failed\n",
rsnd_mod_name(mod), rsnd_mod_id(mod));
dev_dbg(dev, "%s (PIO) is probed\n", rsnd_mod_name(mod)); else
dev_dbg(dev, "%s[%d] (PIO) is probed\n",
rsnd_mod_name(mod), rsnd_mod_id(mod));
return ret; return ret;
} }
static int rsnd_ssi_pio_start(struct rsnd_mod *mod,
struct rsnd_dai *rdai)
{
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
/* enable PIO IRQ */
ssi->cr_etc = UIEN | OIEN | DIEN;
rsnd_src_ssiu_start(mod, rdai, 0);
rsnd_src_enable_ssi_irq(mod, rdai);
rsnd_ssi_hw_start(ssi, rdai, io);
return 0;
}
static int rsnd_ssi_pio_stop(struct rsnd_mod *mod,
struct rsnd_dai *rdai)
{
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
ssi->cr_etc = 0;
rsnd_ssi_hw_stop(ssi, rdai);
rsnd_src_ssiu_stop(mod, rdai, 0);
return 0;
}
static struct rsnd_mod_ops rsnd_ssi_pio_ops = { static struct rsnd_mod_ops rsnd_ssi_pio_ops = {
.name = SSI_NAME, .name = SSI_NAME,
.probe = rsnd_ssi_pio_probe, .probe = rsnd_ssi_pio_probe,
.init = rsnd_ssi_init, .init = rsnd_ssi_init,
.quit = rsnd_ssi_quit, .quit = rsnd_ssi_quit,
.start = rsnd_ssi_pio_start, .start = rsnd_ssi_start,
.stop = rsnd_ssi_pio_stop, .stop = rsnd_ssi_stop,
}; };
static int rsnd_ssi_dma_probe(struct rsnd_mod *mod, static int rsnd_ssi_dma_probe(struct rsnd_mod *mod,
...@@ -442,15 +476,28 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod, ...@@ -442,15 +476,28 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod,
int dma_id = ssi->info->dma_id; int dma_id = ssi->info->dma_id;
int ret; int ret;
ret = devm_request_irq(dev, ssi->info->irq,
rsnd_ssi_interrupt,
IRQF_SHARED,
dev_name(dev), ssi);
if (ret)
goto rsnd_ssi_dma_probe_fail;
ret = rsnd_dma_init( ret = rsnd_dma_init(
priv, rsnd_mod_to_dma(mod), priv, rsnd_mod_to_dma(mod),
rsnd_info_is_playback(priv, ssi), rsnd_info_is_playback(priv, ssi),
dma_id); dma_id);
if (ret)
goto rsnd_ssi_dma_probe_fail;
if (ret < 0) dev_dbg(dev, "%s[%d] (DMA) is probed\n",
dev_err(dev, "SSI DMA failed\n"); rsnd_mod_name(mod), rsnd_mod_id(mod));
return ret;
dev_dbg(dev, "%s (DMA) is probed\n", rsnd_mod_name(mod)); rsnd_ssi_dma_probe_fail:
dev_err(dev, "%s[%d] (DMA) is failed\n",
rsnd_mod_name(mod), rsnd_mod_id(mod));
return ret; return ret;
} }
...@@ -458,30 +505,48 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod, ...@@ -458,30 +505,48 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod,
static int rsnd_ssi_dma_remove(struct rsnd_mod *mod, static int rsnd_ssi_dma_remove(struct rsnd_mod *mod,
struct rsnd_dai *rdai) struct rsnd_dai *rdai)
{ {
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
struct device *dev = rsnd_priv_to_dev(priv);
int irq = ssi->info->irq;
rsnd_dma_quit(rsnd_mod_to_priv(mod), rsnd_mod_to_dma(mod)); rsnd_dma_quit(rsnd_mod_to_priv(mod), rsnd_mod_to_dma(mod));
/* PIO will request IRQ again */
devm_free_irq(dev, irq, ssi);
return 0; return 0;
} }
static int rsnd_ssi_dma_start(struct rsnd_mod *mod, static int rsnd_ssi_fallback(struct rsnd_mod *mod,
struct rsnd_dai *rdai) struct rsnd_dai *rdai)
{ {
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
struct rsnd_dma *dma = rsnd_mod_to_dma(&ssi->mod); struct device *dev = rsnd_priv_to_dev(priv);
struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
/* enable DMA transfer */ /*
ssi->cr_etc = DMEN; * fallback to PIO
*
* SSI .probe might be called again.
* see
* rsnd_rdai_continuance_probe()
*/
mod->ops = &rsnd_ssi_pio_ops;
rsnd_src_ssiu_start(mod, rdai, rsnd_ssi_use_busif(mod)); dev_info(dev, "%s[%d] fallback to PIO mode\n",
rsnd_mod_name(mod), rsnd_mod_id(mod));
rsnd_dma_start(dma); return 0;
}
rsnd_ssi_hw_start(ssi, ssi->rdai, io); static int rsnd_ssi_dma_start(struct rsnd_mod *mod,
struct rsnd_dai *rdai)
{
struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
/* enable WS continue */ rsnd_ssi_start(mod, rdai);
if (rsnd_dai_is_clk_master(rdai))
rsnd_mod_write(&ssi->mod, SSIWSR, CONT); rsnd_dma_start(dma);
return 0; return 0;
} }
...@@ -489,18 +554,11 @@ static int rsnd_ssi_dma_start(struct rsnd_mod *mod, ...@@ -489,18 +554,11 @@ static int rsnd_ssi_dma_start(struct rsnd_mod *mod,
static int rsnd_ssi_dma_stop(struct rsnd_mod *mod, static int rsnd_ssi_dma_stop(struct rsnd_mod *mod,
struct rsnd_dai *rdai) struct rsnd_dai *rdai)
{ {
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
struct rsnd_dma *dma = rsnd_mod_to_dma(&ssi->mod);
ssi->cr_etc = 0;
rsnd_ssi_record_error(ssi, rsnd_mod_read(mod, SSISR));
rsnd_ssi_hw_stop(ssi, rdai);
rsnd_dma_stop(dma); rsnd_dma_stop(dma);
rsnd_src_ssiu_stop(mod, rdai, 1); rsnd_ssi_stop(mod, rdai);
return 0; return 0;
} }
...@@ -519,8 +577,15 @@ static struct rsnd_mod_ops rsnd_ssi_dma_ops = { ...@@ -519,8 +577,15 @@ static struct rsnd_mod_ops rsnd_ssi_dma_ops = {
.quit = rsnd_ssi_quit, .quit = rsnd_ssi_quit,
.start = rsnd_ssi_dma_start, .start = rsnd_ssi_dma_start,
.stop = rsnd_ssi_dma_stop, .stop = rsnd_ssi_dma_stop,
.fallback = rsnd_ssi_fallback,
}; };
int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod)
{
return mod->ops == &rsnd_ssi_dma_ops;
}
/* /*
* Non SSI * Non SSI
*/ */
...@@ -614,7 +679,7 @@ static void rsnd_of_parse_ssi(struct platform_device *pdev, ...@@ -614,7 +679,7 @@ static void rsnd_of_parse_ssi(struct platform_device *pdev,
/* /*
* irq * irq
*/ */
ssi_info->pio_irq = irq_of_parse_and_map(np, 0); ssi_info->irq = irq_of_parse_and_map(np, 0);
/* /*
* DMA * DMA
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment