Merge remote-tracking branches 'asoc/topic/rcar', 'asoc/topic/rockchip', 'asoc/topic/rt286' and 'asoc/topic/rt5631' into asoc-next

This commit is contained in:
Mark Brown 2014-12-08 13:12:07 +00:00
14 changed files with 916 additions and 342 deletions

View file

@ -1,8 +1,12 @@
Renesas R-Car sound
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
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.
required register is
SRU/ADG/SSI if generation1
@ -35,9 +39,9 @@ DAI subnode properties:
Example:
rcar_sound: rcar_sound@0xffd90000 {
rcar_sound: rcar_sound@ec500000 {
#sound-dai-cells = <1>;
compatible = "renesas,rcar_sound-gen2";
compatible = "renesas,rcar_sound-r8a7791", "renesas,rcar_sound-gen2";
reg = <0 0xec500000 0 0x1000>, /* SCU */
<0 0xec5a0000 0 0x100>, /* ADG */
<0 0xec540000 0 0x1000>, /* SSIU */

View file

@ -0,0 +1,48 @@
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>;
};

View file

@ -36,14 +36,14 @@
#define RSND_SSI_CLK_PIN_SHARE (1 << 31)
#define RSND_SSI_NO_BUSIF (1 << 30) /* SSI+DMA without BUSIF */
#define RSND_SSI(_dma_id, _pio_irq, _flags) \
{ .dma_id = _dma_id, .pio_irq = _pio_irq, .flags = _flags }
#define RSND_SSI(_dma_id, _irq, _flags) \
{ .dma_id = _dma_id, .irq = _irq, .flags = _flags }
#define RSND_SSI_UNUSED \
{ .dma_id = -1, .pio_irq = -1, .flags = 0 }
{ .dma_id = -1, .irq = -1, .flags = 0 }
struct rsnd_ssi_platform_info {
int dma_id;
int pio_irq;
int irq;
u32 flags;
};

View file

@ -501,7 +501,8 @@ config SND_SOC_RT286
depends on I2C
config SND_SOC_RT5631
tristate
tristate "Realtek ALC5631/RT5631 CODEC"
depends on I2C
config SND_SOC_RT5640
tristate

View file

@ -17,6 +17,7 @@
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/dmi.h>
#include <linux/acpi.h>
#include <sound/core.h>
#include <sound/pcm.h>
@ -36,11 +37,13 @@
struct rt286_priv {
struct regmap *regmap;
struct snd_soc_codec *codec;
struct rt286_platform_data pdata;
struct i2c_client *i2c;
struct snd_soc_jack *jack;
struct delayed_work jack_detect_work;
int sys_clk;
int clk_id;
struct reg_default *index_cache;
};
@ -188,7 +191,7 @@ static int rt286_hw_write(void *context, unsigned int reg, unsigned int value)
u8 data[4];
int ret, i;
/*handle index registers*/
/* handle index registers */
if (reg <= 0xff) {
rt286_hw_write(client, RT286_COEF_INDEX, reg);
for (i = 0; i < INDEX_CACHE_SIZE; i++) {
@ -231,7 +234,7 @@ static int rt286_hw_read(void *context, unsigned int reg, unsigned int *value)
__be32 be_reg;
unsigned int index, vid, buf = 0x0;
/*handle index registers*/
/* handle index registers */
if (reg <= 0xff) {
rt286_hw_write(client, RT286_COEF_INDEX, reg);
reg = RT286_PROC_COEF;
@ -298,7 +301,6 @@ static int rt286_support_power_controls[] = {
static int rt286_jack_detect(struct rt286_priv *rt286, bool *hp, bool *mic)
{
unsigned int val, buf;
int i;
*hp = false;
*mic = false;
@ -309,67 +311,44 @@ static int rt286_jack_detect(struct rt286_priv *rt286, bool *hp, bool *mic)
if (*hp) {
/* power on HV,VERF */
regmap_update_bits(rt286->regmap,
RT286_POWER_CTRL1, 0x1001, 0x0);
RT286_DC_GAIN, 0x200, 0x200);
snd_soc_dapm_force_enable_pin(&rt286->codec->dapm,
"HV");
snd_soc_dapm_force_enable_pin(&rt286->codec->dapm,
"VREF");
/* power LDO1 */
regmap_update_bits(rt286->regmap,
RT286_POWER_CTRL2, 0x4, 0x4);
snd_soc_dapm_force_enable_pin(&rt286->codec->dapm,
"LDO1");
snd_soc_dapm_sync(&rt286->codec->dapm);
regmap_write(rt286->regmap, RT286_SET_MIC1, 0x24);
msleep(50);
regmap_update_bits(rt286->regmap,
RT286_CBJ_CTRL1, 0xfcc0, 0xd400);
msleep(300);
regmap_read(rt286->regmap, RT286_CBJ_CTRL2, &val);
msleep(200);
i = 40;
while (((val & 0x0800) == 0) && (i > 0)) {
if (0x0070 == (val & 0x0070)) {
*mic = true;
} else {
regmap_update_bits(rt286->regmap,
RT286_CBJ_CTRL1, 0xfcc0, 0xe400);
msleep(300);
regmap_read(rt286->regmap,
RT286_CBJ_CTRL2, &val);
i--;
msleep(20);
if (0x0070 == (val & 0x0070))
*mic = true;
else
*mic = false;
}
if (0x0400 == (val & 0x0700)) {
*mic = false;
regmap_write(rt286->regmap,
RT286_SET_MIC1, 0x20);
/* power off HV,VERF */
regmap_update_bits(rt286->regmap,
RT286_POWER_CTRL1, 0x1001, 0x1001);
regmap_update_bits(rt286->regmap,
RT286_A_BIAS_CTRL3, 0xc000, 0x0000);
regmap_update_bits(rt286->regmap,
RT286_CBJ_CTRL1, 0x0030, 0x0000);
regmap_update_bits(rt286->regmap,
RT286_A_BIAS_CTRL2, 0xc000, 0x0000);
} else if ((0x0200 == (val & 0x0700)) ||
(0x0100 == (val & 0x0700))) {
*mic = true;
regmap_update_bits(rt286->regmap,
RT286_A_BIAS_CTRL3, 0xc000, 0x8000);
regmap_update_bits(rt286->regmap,
RT286_CBJ_CTRL1, 0x0030, 0x0020);
regmap_update_bits(rt286->regmap,
RT286_A_BIAS_CTRL2, 0xc000, 0x8000);
} else {
*mic = false;
}
regmap_update_bits(rt286->regmap,
RT286_MISC_CTRL1,
0x0060, 0x0000);
RT286_DC_GAIN, 0x200, 0x0);
} else {
regmap_update_bits(rt286->regmap,
RT286_MISC_CTRL1,
0x0060, 0x0020);
regmap_update_bits(rt286->regmap,
RT286_A_BIAS_CTRL3,
0xc000, 0x8000);
regmap_update_bits(rt286->regmap,
RT286_CBJ_CTRL1,
0x0030, 0x0020);
regmap_update_bits(rt286->regmap,
RT286_A_BIAS_CTRL2,
0xc000, 0x8000);
*mic = false;
regmap_write(rt286->regmap, RT286_SET_MIC1, 0x20);
}
} else {
regmap_read(rt286->regmap, RT286_GET_HP_SENSE, &buf);
@ -378,6 +357,12 @@ static int rt286_jack_detect(struct rt286_priv *rt286, bool *hp, bool *mic)
*mic = buf & 0x80000000;
}
snd_soc_dapm_disable_pin(&rt286->codec->dapm, "HV");
snd_soc_dapm_disable_pin(&rt286->codec->dapm, "VREF");
if (!*hp)
snd_soc_dapm_disable_pin(&rt286->codec->dapm, "LDO1");
snd_soc_dapm_sync(&rt286->codec->dapm);
return 0;
}
@ -415,6 +400,17 @@ int rt286_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
}
EXPORT_SYMBOL_GPL(rt286_mic_detect);
static int is_mclk_mode(struct snd_soc_dapm_widget *source,
struct snd_soc_dapm_widget *sink)
{
struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(source->codec);
if (rt286->clk_id == RT286_SCLK_S_MCLK)
return 1;
else
return 0;
}
static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -6350, 50, 0);
static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 1000, 0);
@ -568,7 +564,84 @@ static int rt286_adc_event(struct snd_soc_dapm_widget *w,
return 0;
}
static int rt286_vref_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
snd_soc_update_bits(codec,
RT286_CBJ_CTRL1, 0x0400, 0x0000);
mdelay(50);
break;
default:
return 0;
}
return 0;
}
static int rt286_ldo2_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
switch (event) {
case SND_SOC_DAPM_POST_PMU:
snd_soc_update_bits(codec, RT286_POWER_CTRL2, 0x38, 0x08);
break;
case SND_SOC_DAPM_PRE_PMD:
snd_soc_update_bits(codec, RT286_POWER_CTRL2, 0x38, 0x30);
break;
default:
return 0;
}
return 0;
}
static int rt286_mic1_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
snd_soc_update_bits(codec,
RT286_A_BIAS_CTRL3, 0xc000, 0x8000);
snd_soc_update_bits(codec,
RT286_A_BIAS_CTRL2, 0xc000, 0x8000);
break;
case SND_SOC_DAPM_POST_PMD:
snd_soc_update_bits(codec,
RT286_A_BIAS_CTRL3, 0xc000, 0x0000);
snd_soc_update_bits(codec,
RT286_A_BIAS_CTRL2, 0xc000, 0x0000);
break;
default:
return 0;
}
return 0;
}
static const struct snd_soc_dapm_widget rt286_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY_S("HV", 1, RT286_POWER_CTRL1,
12, 1, NULL, 0),
SND_SOC_DAPM_SUPPLY("VREF", RT286_POWER_CTRL1,
0, 1, rt286_vref_event, SND_SOC_DAPM_PRE_PMU),
SND_SOC_DAPM_SUPPLY_S("LDO1", 1, RT286_POWER_CTRL2,
2, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY_S("LDO2", 2, RT286_POWER_CTRL1,
13, 1, rt286_ldo2_event, SND_SOC_DAPM_PRE_PMD |
SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_SUPPLY("MCLK MODE", RT286_PLL_CTRL1,
5, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("MIC1 Input Buffer", SND_SOC_NOPM,
0, 0, rt286_mic1_event, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMD),
/* Input Lines */
SND_SOC_DAPM_INPUT("DMIC1 Pin"),
SND_SOC_DAPM_INPUT("DMIC2 Pin"),
@ -642,6 +715,25 @@ static const struct snd_soc_dapm_widget rt286_dapm_widgets[] = {
};
static const struct snd_soc_dapm_route rt286_dapm_routes[] = {
{"ADC 0", NULL, "MCLK MODE", is_mclk_mode},
{"ADC 1", NULL, "MCLK MODE", is_mclk_mode},
{"Front", NULL, "MCLK MODE", is_mclk_mode},
{"Surround", NULL, "MCLK MODE", is_mclk_mode},
{"HP Power", NULL, "LDO1"},
{"HP Power", NULL, "LDO2"},
{"MIC1", NULL, "LDO1"},
{"MIC1", NULL, "LDO2"},
{"MIC1", NULL, "HV"},
{"MIC1", NULL, "VREF"},
{"MIC1", NULL, "MIC1 Input Buffer"},
{"SPO", NULL, "LDO1"},
{"SPO", NULL, "LDO2"},
{"SPO", NULL, "HV"},
{"SPO", NULL, "VREF"},
{"DMIC1", NULL, "DMIC1 Pin"},
{"DMIC2", NULL, "DMIC2 Pin"},
{"DMIC1", NULL, "DMIC Receiver"},
@ -880,6 +972,7 @@ static int rt286_set_dai_sysclk(struct snd_soc_dai *dai,
}
rt286->sys_clk = freq;
rt286->clk_id = clk_id;
return 0;
}
@ -915,13 +1008,18 @@ static int rt286_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_ON:
mdelay(10);
snd_soc_update_bits(codec,
RT286_CBJ_CTRL1, 0x0400, 0x0400);
snd_soc_update_bits(codec,
RT286_DC_GAIN, 0x200, 0x0);
break;
case SND_SOC_BIAS_STANDBY:
snd_soc_write(codec,
RT286_SET_AUDIO_POWER, AC_PWRST_D3);
snd_soc_update_bits(codec,
RT286_DC_GAIN, 0x200, 0x0);
RT286_CBJ_CTRL1, 0x0400, 0x0000);
break;
default:
@ -962,6 +1060,7 @@ static int rt286_probe(struct snd_soc_codec *codec)
{
struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec);
rt286->codec = codec;
codec->dapm.bias_level = SND_SOC_BIAS_OFF;
if (rt286->i2c->irq) {
@ -1107,6 +1206,16 @@ static const struct acpi_device_id rt286_acpi_match[] = {
};
MODULE_DEVICE_TABLE(acpi, rt286_acpi_match);
static struct dmi_system_id force_combo_jack_table[] = {
{
.ident = "Intel Wilson Beach",
.matches = {
DMI_MATCH(DMI_BOARD_NAME, "Wilson Beach SDS")
}
},
{ }
};
static int rt286_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
@ -1142,6 +1251,9 @@ static int rt286_i2c_probe(struct i2c_client *i2c,
if (pdata)
rt286->pdata = *pdata;
if (dmi_check_system(force_combo_jack_table))
rt286->pdata.cbj_en = true;
regmap_write(rt286->regmap, RT286_SET_AUDIO_POWER, AC_PWRST_D3);
for (i = 0; i < RT286_POWER_REG_LEN; i++)
@ -1152,7 +1264,6 @@ static int rt286_i2c_probe(struct i2c_client *i2c,
if (!rt286->pdata.cbj_en) {
regmap_write(rt286->regmap, RT286_CBJ_CTRL2, 0x0000);
regmap_write(rt286->regmap, RT286_MIC1_DET_CTRL, 0x0816);
regmap_write(rt286->regmap, RT286_MISC_CTRL1, 0x0000);
regmap_update_bits(rt286->regmap,
RT286_CBJ_CTRL1, 0xf000, 0xb000);
} else {
@ -1169,10 +1280,12 @@ static int rt286_i2c_probe(struct i2c_client *i2c,
mdelay(10);
/*Power down LDO2*/
regmap_update_bits(rt286->regmap, RT286_POWER_CTRL2, 0x8, 0x0);
regmap_write(rt286->regmap, RT286_MISC_CTRL1, 0x0000);
/* Power down LDO, VREF */
regmap_update_bits(rt286->regmap, RT286_POWER_CTRL2, 0xc, 0x0);
regmap_update_bits(rt286->regmap, RT286_POWER_CTRL1, 0x1001, 0x1001);
/*Set depop parameter*/
/* Set depop parameter */
regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL2, 0x403a, 0x401a);
regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL3, 0xf777, 0x4737);
regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL4, 0x00ff, 0x003f);

View file

@ -1612,29 +1612,6 @@ static int rt5631_probe(struct snd_soc_codec *codec)
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_FORMAT (SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S20_3LE | \
@ -1672,10 +1649,8 @@ static struct snd_soc_dai_driver rt5631_dai[] = {
static struct snd_soc_codec_driver soc_codec_dev_rt5631 = {
.probe = rt5631_probe,
.remove = rt5631_remove,
.suspend = rt5631_suspend,
.resume = rt5631_resume,
.set_bias_level = rt5631_set_bias_level,
.suspend_bias_off = true,
.controls = rt5631_snd_controls,
.num_controls = ARRAY_SIZE(rt5631_snd_controls),
.dapm_widgets = rt5631_dapm_widgets,
@ -1686,10 +1661,20 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5631 = {
static const struct i2c_device_id rt5631_i2c_id[] = {
{ "rt5631", 0 },
{ "alc5631", 0 },
{ }
};
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 = {
.reg_bits = 8,
.val_bits = 16,
@ -1734,6 +1719,7 @@ static struct i2c_driver rt5631_i2c_driver = {
.driver = {
.name = "rt5631",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(rt5631_i2c_dt_ids),
},
.probe = rt5631_i2c_probe,
.remove = rt5631_i2c_remove,

View file

@ -1,11 +1,16 @@
config SND_SOC_ROCKCHIP
tristate "ASoC support for Rockchip"
depends on COMPILE_TEST || ARCH_ROCKCHIP
select SND_SOC_GENERIC_DMAENGINE_PCM
help
Say Y or M if you want to add support for codecs attached to
the Rockchip SoCs' Audio interfaces. You will also need to
select the audio interfaces to support below.
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.

View file

@ -430,7 +430,7 @@ int rsnd_adg_probe(struct platform_device *pdev,
adg->clk[CLKI] = devm_clk_get(dev, "clk_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);

View file

@ -349,7 +349,7 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma,
dma_name);
if (!dma->chan) {
dev_err(dev, "can't get dma channel\n");
return -EIO;
goto rsnd_dma_channel_err;
}
ret = dmaengine_slave_config(dma->chan, &cfg);
@ -363,8 +363,15 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma,
rsnd_dma_init_err:
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,
@ -409,9 +416,16 @@ u32 rsnd_get_adinr(struct rsnd_mod *mod)
({ \
struct rsnd_priv *priv = rsnd_mod_to_priv(mod); \
struct device *dev = rsnd_priv_to_dev(priv); \
dev_dbg(dev, "%s [%d] %s\n", \
rsnd_mod_name(mod), rsnd_mod_id(mod), #func); \
(mod)->ops->func(mod, rdai); \
u32 mask = 1 << __rsnd_mod_shift_##func; \
u32 call = __rsnd_mod_call_##func << __rsnd_mod_shift_##func; \
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...) \
@ -456,6 +470,13 @@ static int rsnd_dai_connect(struct rsnd_mod *mod,
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 id = rdai - priv->rdai;
@ -686,6 +707,20 @@ static const struct snd_soc_dai_ops rsnd_soc_dai_ops = {
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,
struct rsnd_dai *rdai,
struct rsnd_dai_stream *io)
@ -933,6 +968,150 @@ static struct snd_pcm_ops rsnd_pcm_ops = {
.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
*/
@ -976,6 +1155,49 @@ static const struct snd_soc_component_driver rsnd_soc_component = {
.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
*/
@ -1037,11 +1259,11 @@ static int rsnd_probe(struct platform_device *pdev)
}
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)
goto exit_snd_probe;
ret = rsnd_dai_call(probe, &rdai->capture, rdai);
ret = rsnd_rdai_continuance_probe(priv, rdai, 0);
if (ret)
goto exit_snd_probe;
}

View file

@ -11,8 +11,6 @@
#include "rsnd.h"
#define RSND_DVC_NAME_SIZE 16
#define RSND_DVC_VOLUME_MAX 100
#define RSND_DVC_VOLUME_NUM 2
#define DVC_NAME "dvc"
@ -20,8 +18,11 @@ struct rsnd_dvc {
struct rsnd_dvc_platform_info *info; /* rcar_snd.h */
struct rsnd_mod mod;
struct clk *clk;
u8 volume[RSND_DVC_VOLUME_NUM];
u8 mute[RSND_DVC_VOLUME_NUM];
struct rsnd_kctrl_cfg_m volume;
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) \
@ -33,23 +34,87 @@ struct rsnd_dvc {
((pos) = (struct rsnd_dvc *)(priv)->dvc + 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)
{
struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
u32 max = (0x00800000 - 1);
u32 vol[RSND_DVC_VOLUME_NUM];
u32 val[RSND_DVC_CHANNELS];
u32 dvucr = 0;
u32 mute = 0;
int i;
for (i = 0; i < RSND_DVC_VOLUME_NUM; i++) {
vol[i] = max / RSND_DVC_VOLUME_MAX * dvc->volume[i];
mute |= (!!dvc->mute[i]) << i;
for (i = 0; i < dvc->mute.cfg.size; i++)
mute |= (!!dvc->mute.cfg.val[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];
}
rsnd_mod_write(mod, DVC_VOL0R, vol[0]);
rsnd_mod_write(mod, DVC_VOL1R, vol[1]);
/* Enable Digital Volume */
dvucr |= 0x100;
rsnd_mod_write(mod, DVC_VOL0R, val[0]);
rsnd_mod_write(mod, DVC_VOL1R, val[1]);
rsnd_mod_write(mod, DVC_ZCMCR, mute);
/* Enable Mute */
if (mute) {
dvucr |= 0x1;
rsnd_mod_write(mod, DVC_ZCMCR, mute);
}
rsnd_mod_write(mod, DVC_DVUCR, dvucr);
/* Enable DVC Register access */
rsnd_mod_write(mod, DVC_DVUER, 1);
}
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 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;
}
@ -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));
/* enable Volume / Mute */
rsnd_mod_write(dvc_mod, DVC_DVUCR, 0x101);
/* ch0/ch1 Volume */
rsnd_dvc_volume_update(dvc_mod);
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);
return 0;
@ -143,86 +204,6 @@ static int rsnd_dvc_stop(struct rsnd_mod *mod,
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,
struct rsnd_dai *rdai,
struct snd_soc_pcm_runtime *rtd)
@ -232,18 +213,48 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
int ret;
/* Volume */
ret = __rsnd_dvc_pcm_new(mod, rdai, rtd,
ret = rsnd_kctrl_new_m(mod, rdai, rtd,
rsnd_dai_is_play(rdai, io) ?
"DVC Out Playback Volume" : "DVC In Capture Volume",
dvc->volume);
rsnd_dvc_volume_update,
&dvc->volume, 0x00800000 - 1);
if (ret < 0)
return ret;
/* Mute */
ret = __rsnd_dvc_pcm_new(mod, rdai, rtd,
ret = rsnd_kctrl_new_m(mod, rdai, rtd,
rsnd_dai_is_play(rdai, io) ?
"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)
return ret;

View file

@ -8,6 +8,17 @@
* it under the terms of the GNU General Public License version 2 as
* 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"
struct rsnd_gen {
@ -67,9 +78,10 @@ u32 rsnd_read(struct rsnd_priv *priv,
if (!rsnd_is_accessible_reg(priv, gen, reg))
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;
}
@ -84,9 +96,10 @@ void rsnd_write(struct rsnd_priv *priv,
if (!rsnd_is_accessible_reg(priv, gen, reg))
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,
@ -98,11 +111,11 @@ 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 - 0x%04d : %08x/%08x\n",
rsnd_mod_name(mod), reg, data, mask);
}
#define rsnd_gen_regmap_init(priv, id_size, reg_id, conf) \
@ -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_DVUCR, 0xe10, 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_VOL1R, 0xe2c, 0x100),
RSND_GEN_M_REG(DVC_DVUER, 0xe48, 0x100),

View file

@ -91,6 +91,9 @@ enum rsnd_reg {
RSND_REG_SHARE20,
RSND_REG_SHARE21,
RSND_REG_SHARE22,
RSND_REG_SHARE23,
RSND_REG_SHARE24,
RSND_REG_SHARE25,
RSND_REG_MAX,
};
@ -129,6 +132,9 @@ enum rsnd_reg {
#define RSND_REG_CMD_CTRL RSND_REG_SHARE20
#define RSND_REG_CMDOUT_TIMSEL RSND_REG_SHARE21
#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_priv;
@ -200,6 +206,8 @@ struct rsnd_mod_ops {
int (*pcm_new)(struct rsnd_mod *mod,
struct rsnd_dai *rdai,
struct snd_soc_pcm_runtime *rtd);
int (*fallback)(struct rsnd_mod *mod,
struct rsnd_dai *rdai);
};
struct rsnd_dai_stream;
@ -210,7 +218,35 @@ struct rsnd_mod {
struct rsnd_mod_ops *ops;
struct rsnd_dma dma;
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_dma(mod) (&(mod)->dma)
@ -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_id(struct rsnd_priv *priv, struct rsnd_dai *rdai);
#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);
int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional);
@ -381,6 +418,51 @@ struct rsnd_priv {
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
*/
@ -395,10 +477,11 @@ int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod,
struct rsnd_dai *rdai,
int use_busif);
int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod,
struct rsnd_dai *rdai,
int use_busif);
int rsnd_src_enable_ssi_irq(struct rsnd_mod *ssi_mod,
struct rsnd_dai *rdai);
int rsnd_src_ssi_irq_enable(struct rsnd_mod *ssi_mod,
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)
@ -410,6 +493,7 @@ int rsnd_ssi_probe(struct platform_device *pdev,
struct rsnd_priv *priv);
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_dma_mode(struct rsnd_mod *mod);
/*
* R-Car DVC

View file

@ -175,30 +175,47 @@ int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod,
}
int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod,
struct rsnd_dai *rdai,
int use_busif)
struct rsnd_dai *rdai)
{
/*
* 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;
}
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_priv *priv = rsnd_mod_to_priv(ssi_mod);
/* enable PIO interrupt if Gen2 */
if (rsnd_is_gen2(priv))
if (rsnd_is_gen1(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);
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,
struct rsnd_dai_stream *io,
struct snd_pcm_runtime *runtime)
@ -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, 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 */
rsnd_mod_write(mod, SRC_ADINR, rsnd_get_adinr(mod));
@ -269,6 +280,12 @@ static int rsnd_src_init(struct rsnd_mod *mod,
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;
}
@ -282,32 +299,20 @@ static int rsnd_src_quit(struct rsnd_mod *mod,
return 0;
}
static int rsnd_src_start(struct rsnd_mod *mod,
struct rsnd_dai *rdai)
static int rsnd_src_start(struct rsnd_mod *mod)
{
struct rsnd_src *src = rsnd_mod_to_src(mod);
/*
* 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);
if (rsnd_src_convert_rate(src))
rsnd_mod_write(mod, SRC_ROUTE_MODE0, 1);
return 0;
}
static int rsnd_src_stop(struct rsnd_mod *mod,
struct rsnd_dai *rdai)
static int rsnd_src_stop(struct rsnd_mod *mod)
{
struct rsnd_src *src = rsnd_mod_to_src(mod);
if (rsnd_src_convert_rate(src))
rsnd_mod_write(mod, SRC_ROUTE_MODE0, 0);
/* nothing to do */
return 0;
}
@ -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,
struct rsnd_dai *rdai)
{
struct rsnd_src *src = rsnd_mod_to_src(mod);
int ret;
ret = rsnd_src_set_convert_rate(mod, rdai);
@ -427,6 +433,10 @@ static int rsnd_src_set_convert_rate_gen1(struct rsnd_mod *mod,
rsnd_mod_write(mod, SRC_MNFSR,
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 */
return 0;
@ -438,7 +448,8 @@ static int rsnd_src_probe_gen1(struct rsnd_mod *mod,
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
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;
}
@ -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));
return rsnd_src_start(mod, rdai);
return rsnd_src_start(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,
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 = {
@ -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 snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
struct rsnd_src *src = rsnd_mod_to_src(mod);
u32 convert_rate = rsnd_src_convert_rate(src);
uint ratio;
int ret;
/* 6 - 1/6 are very enough ratio for SRC_BSDSR */
if (!rsnd_src_convert_rate(src))
if (!convert_rate)
ratio = 0;
else if (rsnd_src_convert_rate(src) > runtime->rate)
ratio = 100 * rsnd_src_convert_rate(src) / runtime->rate;
else if (convert_rate > runtime->rate)
ratio = 100 * convert_rate / runtime->rate;
else
ratio = 100 * runtime->rate / rsnd_src_convert_rate(src);
ratio = 100 * runtime->rate / convert_rate;
if (ratio > 600) {
dev_err(dev, "FSO/FSI ratio error\n");
@ -529,6 +541,11 @@ static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod,
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)) {
case 5:
case 6:
@ -578,9 +595,11 @@ static int rsnd_src_probe_gen2(struct rsnd_mod *mod,
rsnd_info_is_playback(priv, src),
src->info->dma_id);
if (ret < 0)
dev_err(dev, "SRC DMA failed\n");
dev_dbg(dev, "%s (Gen2) is probed\n", rsnd_mod_name(mod));
dev_err(dev, "%s[%d] (Gen2) failed\n",
rsnd_mod_name(mod), rsnd_mod_id(mod));
else
dev_dbg(dev, "%s[%d] (Gen2) is probed\n",
rsnd_mod_name(mod), rsnd_mod_id(mod));
return ret;
}
@ -624,7 +643,7 @@ static int rsnd_src_start_gen2(struct rsnd_mod *mod,
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,
@ -636,7 +655,7 @@ static int rsnd_src_stop_gen2(struct rsnd_mod *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 = {

View file

@ -68,7 +68,6 @@ struct rsnd_ssi {
struct rsnd_dai *rdai;
u32 cr_own;
u32 cr_clk;
u32 cr_etc;
int err;
unsigned int usrcnt;
unsigned int rate;
@ -83,7 +82,7 @@ struct rsnd_ssi {
#define rsnd_ssi_nr(priv) ((priv)->ssi_nr)
#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_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) \
rsnd_dma_available(rsnd_mod_to_dma(&(ssi)->mod))
#define rsnd_ssi_clk_from_parent(ssi) ((ssi)->parent)
@ -96,6 +95,9 @@ static int rsnd_ssi_use_busif(struct rsnd_mod *mod)
struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
int use_busif = 0;
if (!rsnd_ssi_is_dma_mode(mod))
return 0;
if (!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_NO_BUSIF))
use_busif = 1;
if (rsnd_io_to_mod_src(io))
@ -159,7 +161,8 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi,
ssi->cr_clk = FORCE | SWL_32 |
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);
return 0;
@ -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 device *dev = rsnd_priv_to_dev(priv);
u32 cr_mode;
u32 cr;
if (0 == ssi->usrcnt) {
@ -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 |
ssi->cr_clk |
ssi->cr_etc |
EN;
cr_mode |
UIEN | OIEN | EN;
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++;
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,
@ -249,7 +266,8 @@ static void rsnd_ssi_hw_stop(struct rsnd_ssi *ssi,
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)
}
}
/*
* SSI PIO
*/
static irqreturn_t rsnd_ssi_pio_interrupt(int irq, void *data)
static int rsnd_ssi_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);
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_dai *rdai = ssi->rdai;
struct rsnd_mod *mod = &ssi->mod;
struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
u32 status = rsnd_mod_read(mod, SSISR);
irqreturn_t ret = IRQ_NONE;
if (io && (status & DIRQ)) {
struct rsnd_dai *rdai = ssi->rdai;
if (!io)
return IRQ_NONE;
/* PIO only */
if (status & DIRQ) {
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
u32 *buf = (u32 *)(runtime->dma_area +
rsnd_dai_pointer_offset(io, 0));
rsnd_ssi_record_error(ssi, status);
/*
* 8/16/32 data can be assesse to TDR/RDR register
* directly as 32bit data
@ -364,73 +411,60 @@ static irqreturn_t rsnd_ssi_pio_interrupt(int irq, void *data)
*buf = rsnd_mod_read(mod, SSIRDR);
rsnd_dai_pointer_update(io, sizeof(*buf));
ret = IRQ_HANDLED;
}
return ret;
/* 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);
dev_dbg(dev, "%s[%d] restart\n",
rsnd_mod_name(mod), rsnd_mod_id(mod));
}
rsnd_ssi_record_error(ssi, status);
return IRQ_HANDLED;
}
/*
* SSI PIO
*/
static int rsnd_ssi_pio_probe(struct rsnd_mod *mod,
struct rsnd_dai *rdai)
{
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
struct device *dev = rsnd_priv_to_dev(priv);
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
int irq = ssi->info->pio_irq;
int ret;
ret = devm_request_irq(dev, irq,
rsnd_ssi_pio_interrupt,
ret = devm_request_irq(dev, ssi->info->irq,
rsnd_ssi_interrupt,
IRQF_SHARED,
dev_name(dev), ssi);
if (ret)
dev_err(dev, "SSI request interrupt failed\n");
dev_dbg(dev, "%s (PIO) is probed\n", rsnd_mod_name(mod));
dev_err(dev, "%s[%d] (PIO) request interrupt failed\n",
rsnd_mod_name(mod), rsnd_mod_id(mod));
else
dev_dbg(dev, "%s[%d] (PIO) is probed\n",
rsnd_mod_name(mod), rsnd_mod_id(mod));
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 = {
.name = SSI_NAME,
.probe = rsnd_ssi_pio_probe,
.init = rsnd_ssi_init,
.quit = rsnd_ssi_quit,
.start = rsnd_ssi_pio_start,
.stop = rsnd_ssi_pio_stop,
.start = rsnd_ssi_start,
.stop = rsnd_ssi_stop,
};
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 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(
priv, rsnd_mod_to_dma(mod),
rsnd_info_is_playback(priv, ssi),
dma_id);
if (ret)
goto rsnd_ssi_dma_probe_fail;
if (ret < 0)
dev_err(dev, "SSI DMA failed\n");
dev_dbg(dev, "%s[%d] (DMA) is probed\n",
rsnd_mod_name(mod), rsnd_mod_id(mod));
dev_dbg(dev, "%s (DMA) is probed\n", rsnd_mod_name(mod));
return ret;
rsnd_ssi_dma_probe_fail:
dev_err(dev, "%s[%d] (DMA) is failed\n",
rsnd_mod_name(mod), rsnd_mod_id(mod));
return ret;
}
@ -458,49 +505,60 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod,
static int rsnd_ssi_dma_remove(struct rsnd_mod *mod,
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));
/* PIO will request IRQ again */
devm_free_irq(dev, irq, ssi);
return 0;
}
static int rsnd_ssi_fallback(struct rsnd_mod *mod,
struct rsnd_dai *rdai)
{
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
struct device *dev = rsnd_priv_to_dev(priv);
/*
* fallback to PIO
*
* SSI .probe might be called again.
* see
* rsnd_rdai_continuance_probe()
*/
mod->ops = &rsnd_ssi_pio_ops;
dev_info(dev, "%s[%d] fallback to PIO mode\n",
rsnd_mod_name(mod), rsnd_mod_id(mod));
return 0;
}
static int rsnd_ssi_dma_start(struct rsnd_mod *mod,
struct rsnd_dai *rdai)
{
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
struct rsnd_dma *dma = rsnd_mod_to_dma(&ssi->mod);
struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
/* enable DMA transfer */
ssi->cr_etc = DMEN;
rsnd_src_ssiu_start(mod, rdai, rsnd_ssi_use_busif(mod));
rsnd_ssi_start(mod, rdai);
rsnd_dma_start(dma);
rsnd_ssi_hw_start(ssi, ssi->rdai, io);
/* enable WS continue */
if (rsnd_dai_is_clk_master(rdai))
rsnd_mod_write(&ssi->mod, SSIWSR, CONT);
return 0;
}
static int rsnd_ssi_dma_stop(struct rsnd_mod *mod,
struct rsnd_dai *rdai)
{
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(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);
struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
rsnd_dma_stop(dma);
rsnd_src_ssiu_stop(mod, rdai, 1);
rsnd_ssi_stop(mod, rdai);
return 0;
}
@ -519,8 +577,15 @@ static struct rsnd_mod_ops rsnd_ssi_dma_ops = {
.quit = rsnd_ssi_quit,
.start = rsnd_ssi_dma_start,
.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
*/
@ -614,7 +679,7 @@ static void rsnd_of_parse_ssi(struct platform_device *pdev,
/*
* irq
*/
ssi_info->pio_irq = irq_of_parse_and_map(np, 0);
ssi_info->irq = irq_of_parse_and_map(np, 0);
/*
* DMA