Commit 0a5ff077 authored by Mark Brown's avatar Mark Brown

Merge remote-tracking branches 'asoc/topic/ssm2518', 'asoc/topic/sta529',...

Merge remote-tracking branches 'asoc/topic/ssm2518', 'asoc/topic/sta529', 'asoc/topic/sti' and 'asoc/topic/sti-sas' into asoc-next
STMicroelectronics sti ASoC cards
The sti ASoC Sound Card can be used, for all sti SoCs using internal sti-sas
codec or external codecs.
sti sound drivers allows to expose sti SoC audio interface through the
generic ASoC simple card. For details about sound card declaration please refer to
Documentation/devicetree/bindings/sound/simple-card.txt.
1) sti-uniperiph-dai: audio dai device.
---------------------------------------
Required properties:
- compatible: "st,sti-uni-player" or "st,sti-uni-reader"
- st,syscfg: phandle to boot-device system configuration registers
- clock-names: name of the clocks listed in clocks property in the same order
- reg: CPU DAI IP Base address and size entries, listed in same
order than the CPU_DAI properties.
- reg-names: names of the mapped memory regions listed in regs property in
the same order.
- interrupts: CPU_DAI interrupt line, listed in the same order than the
CPU_DAI properties.
- dma: CPU_DAI DMA controller phandle and DMA request line, listed in the same
order than the CPU_DAI properties.
- dma-names: identifier string for each DMA request line in the dmas property.
"tx" for "st,sti-uni-player" compatibility
"rx" for "st,sti-uni-reader" compatibility
- version: IP version integrated in SOC.
- dai-name: DAI name that describes the IP.
Required properties ("st,sti-uni-player" compatibility only):
- clocks: CPU_DAI IP clock source, listed in the same order than the
CPU_DAI properties.
- uniperiph-id: internal SOC IP instance ID.
- IP mode: IP working mode depending on associated codec.
"HDMI" connected to HDMI codec IP and IEC HDMI formats.
"SPDIF"connected to SPDIF codec and support SPDIF formats.
"PCM" PCM standard mode for I2S or TDM bus.
Optional properties:
- pinctrl-0: defined for CPU_DAI@1 and CPU_DAI@4 to describe I2S PIOs for
external codecs connection.
- pinctrl-names: should contain only one value - "default".
Example:
sti_uni_player2: sti-uni-player@2 {
compatible = "st,sti-uni-player";
status = "okay";
#sound-dai-cells = <0>;
st,syscfg = <&syscfg_core>;
clocks = <&clk_s_d0_flexgen CLK_PCM_2>;
reg = <0x8D82000 0x158>;
interrupts = <GIC_SPI 86 IRQ_TYPE_NONE>;
dmas = <&fdma0 4 0 1>;
dai-name = "Uni Player #1 (DAC)";
dma-names = "tx";
uniperiph-id = <2>;
version = <5>;
mode = "PCM";
};
sti_uni_player3: sti-uni-player@3 {
compatible = "st,sti-uni-player";
status = "okay";
#sound-dai-cells = <0>;
st,syscfg = <&syscfg_core>;
clocks = <&clk_s_d0_flexgen CLK_SPDIFF>;
reg = <0x8D85000 0x158>;
interrupts = <GIC_SPI 89 IRQ_TYPE_NONE>;
dmas = <&fdma0 7 0 1>;
dma-names = "tx";
dai-name = "Uni Player #1 (PIO)";
uniperiph-id = <3>;
version = <5>;
mode = "SPDIF";
};
sti_uni_reader1: sti-uni-reader@1 {
compatible = "st,sti-uni-reader";
status = "disabled";
#sound-dai-cells = <0>;
st,syscfg = <&syscfg_core>;
reg = <0x8D84000 0x158>;
interrupts = <GIC_SPI 88 IRQ_TYPE_NONE>;
dmas = <&fdma0 6 0 1>;
dma-names = "rx";
dai-name = "Uni Reader #1 (HDMI RX)";
version = <3>;
};
2) sti-sas-codec: internal audio codec IPs driver
-------------------------------------------------
Required properties:
- compatible: "st,sti<chip>-sas-codec" .
Should be chip "st,stih416-sas-codec" or "st,stih407-sas-codec"
- st,syscfg: phandle to boot-device system configuration registers.
- pinctrl-0: SPDIF PIO description.
- pinctrl-names: should contain only one value - "default".
Example:
sti_sas_codec: sti-sas-codec {
compatible = "st,stih407-sas-codec";
#sound-dai-cells = <1>;
st,reg_audio = <&syscfg_core>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_spdif_out >;
};
Example of audio card declaration:
sound {
compatible = "simple-audio-card";
simple-audio-card,name = "sti audio card";
status = "okay";
simple-audio-card,dai-link@0 {
/* DAC */
format = "i2s";
dai-tdm-slot-width = <32>;
cpu {
sound-dai = <&sti_uni_player2>;
};
codec {
sound-dai = <&sti_sasg_codec 1>;
};
};
simple-audio-card,dai-link@1 {
/* SPDIF */
format = "left_j";
cpu {
sound-dai = <&sti_uni_player3>;
};
codec {
sound-dai = <&sti_sasg_codec 0>;
};
};
};
......@@ -57,6 +57,7 @@ source "sound/soc/samsung/Kconfig"
source "sound/soc/sh/Kconfig"
source "sound/soc/sirf/Kconfig"
source "sound/soc/spear/Kconfig"
source "sound/soc/sti/Kconfig"
source "sound/soc/tegra/Kconfig"
source "sound/soc/txx9/Kconfig"
source "sound/soc/ux500/Kconfig"
......
......@@ -39,6 +39,7 @@ obj-$(CONFIG_SND_SOC) += samsung/
obj-$(CONFIG_SND_SOC) += sh/
obj-$(CONFIG_SND_SOC) += sirf/
obj-$(CONFIG_SND_SOC) += spear/
obj-$(CONFIG_SND_SOC) += sti/
obj-$(CONFIG_SND_SOC) += tegra/
obj-$(CONFIG_SND_SOC) += txx9/
obj-$(CONFIG_SND_SOC) += ux500/
......
......@@ -106,6 +106,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_STA350 if I2C
select SND_SOC_STA529 if I2C
select SND_SOC_STAC9766 if SND_SOC_AC97_BUS
select SND_SOC_STI_SAS
select SND_SOC_TAS2552 if I2C
select SND_SOC_TAS5086 if I2C
select SND_SOC_TAS571X if I2C
......@@ -631,6 +632,9 @@ config SND_SOC_STA529
config SND_SOC_STAC9766
tristate
config SND_SOC_STI_SAS
tristate "codec Audio support for STI SAS codec"
config SND_SOC_TAS2552
tristate "Texas Instruments TAS2552 Mono Audio amplifier"
depends on I2C
......
......@@ -110,6 +110,7 @@ snd-soc-sta32x-objs := sta32x.o
snd-soc-sta350-objs := sta350.o
snd-soc-sta529-objs := sta529.o
snd-soc-stac9766-objs := stac9766.o
snd-soc-sti-sas-objs := sti-sas.o
snd-soc-tas5086-objs := tas5086.o
snd-soc-tas571x-objs := tas571x.o
snd-soc-tfa9879-objs := tfa9879.o
......@@ -297,6 +298,7 @@ obj-$(CONFIG_SND_SOC_STA32X) += snd-soc-sta32x.o
obj-$(CONFIG_SND_SOC_STA350) += snd-soc-sta350.o
obj-$(CONFIG_SND_SOC_STA529) += snd-soc-sta529.o
obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o
obj-$(CONFIG_SND_SOC_STI_SAS) += snd-soc-sti-sas.o
obj-$(CONFIG_SND_SOC_TAS2552) += snd-soc-tas2552.o
obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o
obj-$(CONFIG_SND_SOC_TAS571X) += snd-soc-tas571x.o
......
......@@ -806,6 +806,14 @@ static int ssm2518_i2c_remove(struct i2c_client *client)
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id ssm2518_dt_ids[] = {
{ .compatible = "adi,ssm2518", },
{ }
};
MODULE_DEVICE_TABLE(of, ssm2518_dt_ids);
#endif
static const struct i2c_device_id ssm2518_i2c_ids[] = {
{ "ssm2518", 0 },
{ }
......@@ -815,6 +823,7 @@ MODULE_DEVICE_TABLE(i2c, ssm2518_i2c_ids);
static struct i2c_driver ssm2518_driver = {
.driver = {
.name = "ssm2518",
.of_match_table = of_match_ptr(ssm2518_dt_ids),
},
.probe = ssm2518_i2c_probe,
.remove = ssm2518_i2c_remove,
......
......@@ -339,9 +339,6 @@ static int sta529_i2c_probe(struct i2c_client *i2c,
struct sta529 *sta529;
int ret;
if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -EINVAL;
sta529 = devm_kzalloc(&i2c->dev, sizeof(struct sta529), GFP_KERNEL);
if (!sta529)
return -ENOMEM;
......
/*
* Copyright (C) STMicroelectronics SA 2015
* Authors: Arnaud Pouliquen <arnaud.pouliquen@st.com>
* for STMicroelectronics.
* License terms: GNU General Public License (GPL), version 2
*/
#include <linux/io.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/reset.h>
#include <linux/mfd/syscon.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
/* chipID supported */
#define CHIPID_STIH416 0
#define CHIPID_STIH407 1
/* DAC definitions */
/* stih416 DAC registers */
/* sysconf 2517: Audio-DAC-Control */
#define STIH416_AUDIO_DAC_CTRL 0x00000814
/* sysconf 2519: Audio-Gue-Control */
#define STIH416_AUDIO_GLUE_CTRL 0x0000081C
#define STIH416_DAC_NOT_STANDBY 0x3
#define STIH416_DAC_SOFTMUTE 0x4
#define STIH416_DAC_ANA_NOT_PWR 0x5
#define STIH416_DAC_NOT_PNDBG 0x6
#define STIH416_DAC_NOT_STANDBY_MASK BIT(STIH416_DAC_NOT_STANDBY)
#define STIH416_DAC_SOFTMUTE_MASK BIT(STIH416_DAC_SOFTMUTE)
#define STIH416_DAC_ANA_NOT_PWR_MASK BIT(STIH416_DAC_ANA_NOT_PWR)
#define STIH416_DAC_NOT_PNDBG_MASK BIT(STIH416_DAC_NOT_PNDBG)
/* stih407 DAC registers */
/* sysconf 5041: Audio-Gue-Control */
#define STIH407_AUDIO_GLUE_CTRL 0x000000A4
/* sysconf 5042: Audio-DAC-Control */
#define STIH407_AUDIO_DAC_CTRL 0x000000A8
/* DAC definitions */
#define STIH407_DAC_SOFTMUTE 0x0
#define STIH407_DAC_STANDBY_ANA 0x1
#define STIH407_DAC_STANDBY 0x2
#define STIH407_DAC_SOFTMUTE_MASK BIT(STIH407_DAC_SOFTMUTE)
#define STIH407_DAC_STANDBY_ANA_MASK BIT(STIH407_DAC_STANDBY_ANA)
#define STIH407_DAC_STANDBY_MASK BIT(STIH407_DAC_STANDBY)
/* SPDIF definitions */
#define SPDIF_BIPHASE_ENABLE 0x6
#define SPDIF_BIPHASE_IDLE 0x7
#define SPDIF_BIPHASE_ENABLE_MASK BIT(SPDIF_BIPHASE_ENABLE)
#define SPDIF_BIPHASE_IDLE_MASK BIT(SPDIF_BIPHASE_IDLE)
enum {
STI_SAS_DAI_SPDIF_OUT,
STI_SAS_DAI_ANALOG_OUT,
};
static const struct reg_default stih416_sas_reg_defaults[] = {
{ STIH407_AUDIO_GLUE_CTRL, 0x00000040 },
{ STIH407_AUDIO_DAC_CTRL, 0x000000000 },
};
static const struct reg_default stih407_sas_reg_defaults[] = {
{ STIH416_AUDIO_DAC_CTRL, 0x000000000 },
{ STIH416_AUDIO_GLUE_CTRL, 0x00000040 },
};
struct sti_dac_audio {
struct regmap *regmap;
struct regmap *virt_regmap;
struct regmap_field **field;
struct reset_control *rst;
int mclk;
};
struct sti_spdif_audio {
struct regmap *regmap;
struct regmap_field **field;
int mclk;
};
/* device data structure */
struct sti_sas_dev_data {
const int chipid; /* IC version */
const struct regmap_config *regmap;
const struct snd_soc_dai_ops *dac_ops; /* DAC function callbacks */
const struct snd_soc_dapm_widget *dapm_widgets; /* dapms declaration */
const int num_dapm_widgets; /* dapms declaration */
const struct snd_soc_dapm_route *dapm_routes; /* route declaration */
const int num_dapm_routes; /* route declaration */
};
/* driver data structure */
struct sti_sas_data {
struct device *dev;
const struct sti_sas_dev_data *dev_data;
struct sti_dac_audio dac;
struct sti_spdif_audio spdif;
};
/* Read a register from the sysconf reg bank */
static int sti_sas_read_reg(void *context, unsigned int reg,
unsigned int *value)
{
struct sti_sas_data *drvdata = context;
int status;
u32 val;
status = regmap_read(drvdata->dac.regmap, reg, &val);
*value = (unsigned int)val;
return status;
}
/* Read a register from the sysconf reg bank */
static int sti_sas_write_reg(void *context, unsigned int reg,
unsigned int value)
{
struct sti_sas_data *drvdata = context;
int status;
status = regmap_write(drvdata->dac.regmap, reg, value);
return status;
}
static int sti_sas_init_sas_registers(struct snd_soc_codec *codec,
struct sti_sas_data *data)
{
int ret;
/*
* DAC and SPDIF are activated by default
* put them in IDLE to save power
*/
/* Initialise bi-phase formatter to disabled */
ret = snd_soc_update_bits(codec, STIH407_AUDIO_GLUE_CTRL,
SPDIF_BIPHASE_ENABLE_MASK, 0);
if (!ret)
/* Initialise bi-phase formatter idle value to 0 */
ret = snd_soc_update_bits(codec, STIH407_AUDIO_GLUE_CTRL,
SPDIF_BIPHASE_IDLE_MASK, 0);
if (ret < 0) {
dev_err(codec->dev, "Failed to update SPDIF registers");
return ret;
}
/* Init DAC configuration */
switch (data->dev_data->chipid) {
case CHIPID_STIH407:
/* init configuration */
ret = snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL,
STIH407_DAC_STANDBY_MASK,
STIH407_DAC_STANDBY_MASK);
if (!ret)
ret = snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL,
STIH407_DAC_STANDBY_ANA_MASK,
STIH407_DAC_STANDBY_ANA_MASK);
if (!ret)
ret = snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL,
STIH407_DAC_SOFTMUTE_MASK,
STIH407_DAC_SOFTMUTE_MASK);
break;
case CHIPID_STIH416:
ret = snd_soc_update_bits(codec, STIH416_AUDIO_DAC_CTRL,
STIH416_DAC_NOT_STANDBY_MASK, 0);
if (!ret)
ret = snd_soc_update_bits(codec,
STIH416_AUDIO_DAC_CTRL,
STIH416_DAC_ANA_NOT_PWR, 0);
if (!ret)
ret = snd_soc_update_bits(codec,
STIH416_AUDIO_DAC_CTRL,
STIH416_DAC_NOT_PNDBG_MASK,
0);
if (!ret)
ret = snd_soc_update_bits(codec,
STIH416_AUDIO_DAC_CTRL,
STIH416_DAC_SOFTMUTE_MASK,
STIH416_DAC_SOFTMUTE_MASK);
break;
default:
return -EINVAL;
}
if (ret < 0) {
dev_err(codec->dev, "Failed to update DAC registers");
return ret;
}
return ret;
}
/*
* DAC
*/
static int sti_sas_dac_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
/* Sanity check only */
if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) {
dev_err(dai->codec->dev,
"%s: ERROR: Unsupporter master mask 0x%x\n",
__func__, fmt & SND_SOC_DAIFMT_MASTER_MASK);
return -EINVAL;
}
return 0;
}
static int stih416_dac_probe(struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
struct sti_sas_data *drvdata = dev_get_drvdata(codec->dev);
struct sti_dac_audio *dac = &drvdata->dac;
/* Get reset control */
dac->rst = devm_reset_control_get(codec->dev, "dac_rst");
if (IS_ERR(dac->rst)) {
dev_err(dai->codec->dev,
"%s: ERROR: DAC reset control not defined !\n",
__func__);
dac->rst = NULL;
return -EFAULT;
}
/* Put the DAC into reset */
reset_control_assert(dac->rst);
return 0;
}
static const struct snd_soc_dapm_widget stih416_sas_dapm_widgets[] = {
SND_SOC_DAPM_PGA("DAC bandgap", STIH416_AUDIO_DAC_CTRL,
STIH416_DAC_NOT_PNDBG_MASK, 0, NULL, 0),
SND_SOC_DAPM_OUT_DRV("DAC standby ana", STIH416_AUDIO_DAC_CTRL,
STIH416_DAC_ANA_NOT_PWR, 0, NULL, 0),
SND_SOC_DAPM_DAC("DAC standby", "dac_p", STIH416_AUDIO_DAC_CTRL,
STIH416_DAC_NOT_STANDBY, 0),
SND_SOC_DAPM_OUTPUT("DAC Output"),
};
static const struct snd_soc_dapm_widget stih407_sas_dapm_widgets[] = {
SND_SOC_DAPM_OUT_DRV("DAC standby ana", STIH407_AUDIO_DAC_CTRL,
STIH407_DAC_STANDBY_ANA, 1, NULL, 0),
SND_SOC_DAPM_DAC("DAC standby", "dac_p", STIH407_AUDIO_DAC_CTRL,
STIH407_DAC_STANDBY, 1),
SND_SOC_DAPM_OUTPUT("DAC Output"),
};
static const struct snd_soc_dapm_route stih416_sas_route[] = {
{"DAC Output", NULL, "DAC bandgap"},
{"DAC Output", NULL, "DAC standby ana"},
{"DAC standby ana", NULL, "DAC standby"},
};
static const struct snd_soc_dapm_route stih407_sas_route[] = {
{"DAC Output", NULL, "DAC standby ana"},
{"DAC standby ana", NULL, "DAC standby"},
};
static int stih416_sas_dac_mute(struct snd_soc_dai *dai, int mute, int stream)
{
struct snd_soc_codec *codec = dai->codec;
if (mute) {
return snd_soc_update_bits(codec, STIH416_AUDIO_DAC_CTRL,
STIH416_DAC_SOFTMUTE_MASK,
STIH416_DAC_SOFTMUTE_MASK);
} else {
return snd_soc_update_bits(codec, STIH416_AUDIO_DAC_CTRL,
STIH416_DAC_SOFTMUTE_MASK, 0);
}
}
static int stih407_sas_dac_mute(struct snd_soc_dai *dai, int mute, int stream)
{
struct snd_soc_codec *codec = dai->codec;
if (mute) {
return snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL,
STIH407_DAC_SOFTMUTE_MASK,
STIH407_DAC_SOFTMUTE_MASK);
} else {
return snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL,
STIH407_DAC_SOFTMUTE_MASK,
0);
}
}
/*
* SPDIF
*/
static int sti_sas_spdif_set_fmt(struct snd_soc_dai *dai,
unsigned int fmt)
{
if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) {
dev_err(dai->codec->dev,
"%s: ERROR: Unsupporter master mask 0x%x\n",
__func__, fmt & SND_SOC_DAIFMT_MASTER_MASK);
return -EINVAL;
}
return 0;
}
/*
* sti_sas_spdif_trigger:
* Trigger function is used to ensure that BiPhase Formater is disabled
* before CPU dai is stopped.
* This is mandatory to avoid that BPF is stalled
*/
static int sti_sas_spdif_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
return snd_soc_update_bits(codec, STIH407_AUDIO_GLUE_CTRL,
SPDIF_BIPHASE_ENABLE_MASK,
SPDIF_BIPHASE_ENABLE_MASK);
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
return snd_soc_update_bits(codec, STIH407_AUDIO_GLUE_CTRL,
SPDIF_BIPHASE_ENABLE_MASK,
0);
default:
return -EINVAL;
}
}
static bool sti_sas_volatile_register(struct device *dev, unsigned int reg)
{
if (reg == STIH407_AUDIO_GLUE_CTRL)
return true;
return false;
}
/*
* CODEC DAIS
*/
/*
* sti_sas_set_sysclk:
* get MCLK input frequency to check that MCLK-FS ratio is coherent
*/
static int sti_sas_set_sysclk(struct snd_soc_dai *dai, int clk_id,
unsigned int freq, int dir)
{
struct snd_soc_codec *codec = dai->codec;
struct sti_sas_data *drvdata = dev_get_drvdata(codec->dev);
if (dir == SND_SOC_CLOCK_OUT)
return 0;
if (clk_id != 0)
return -EINVAL;
switch (dai->id) {
case STI_SAS_DAI_SPDIF_OUT:
drvdata->spdif.mclk = freq;
break;
case STI_SAS_DAI_ANALOG_OUT:
drvdata->dac.mclk = freq;
break;
}
return 0;
}
static int sti_sas_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
struct sti_sas_data *drvdata = dev_get_drvdata(codec->dev);
struct snd_pcm_runtime *runtime = substream->runtime;
switch (dai->id) {
case STI_SAS_DAI_SPDIF_OUT:
if ((drvdata->spdif.mclk / runtime->rate) != 128) {
dev_err(codec->dev, "unexpected mclk-fs ratio");
return -EINVAL;
}
break;
case STI_SAS_DAI_ANALOG_OUT:
if ((drvdata->dac.mclk / runtime->rate) != 256) {
dev_err(codec->dev, "unexpected mclk-fs ratio");
return -EINVAL;
}
break;
}
return 0;
}
static const struct snd_soc_dai_ops stih416_dac_ops = {
.set_fmt = sti_sas_dac_set_fmt,
.mute_stream = stih416_sas_dac_mute,
.prepare = sti_sas_prepare,
.set_sysclk = sti_sas_set_sysclk,
};
static const struct snd_soc_dai_ops stih407_dac_ops = {
.set_fmt = sti_sas_dac_set_fmt,
.mute_stream = stih407_sas_dac_mute,
.prepare = sti_sas_prepare,
.set_sysclk = sti_sas_set_sysclk,
};
static const struct regmap_config stih407_sas_regmap = {
.reg_bits = 32,
.val_bits = 32,
.max_register = STIH407_AUDIO_DAC_CTRL,
.reg_defaults = stih407_sas_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(stih407_sas_reg_defaults),
.volatile_reg = sti_sas_volatile_register,
.cache_type = REGCACHE_RBTREE,
.reg_read = sti_sas_read_reg,
.reg_write = sti_sas_write_reg,
};
static const struct regmap_config stih416_sas_regmap = {
.reg_bits = 32,
.val_bits = 32,
.max_register = STIH416_AUDIO_DAC_CTRL,
.reg_defaults = stih416_sas_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(stih416_sas_reg_defaults),
.volatile_reg = sti_sas_volatile_register,
.cache_type = REGCACHE_RBTREE,
.reg_read = sti_sas_read_reg,
.reg_write = sti_sas_write_reg,
};
static const struct sti_sas_dev_data stih416_data = {
.chipid = CHIPID_STIH416,
.regmap = &stih416_sas_regmap,
.dac_ops = &stih416_dac_ops,
.dapm_widgets = stih416_sas_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(stih416_sas_dapm_widgets),
.dapm_routes = stih416_sas_route,
.num_dapm_routes = ARRAY_SIZE(stih416_sas_route),
};
static const struct sti_sas_dev_data stih407_data = {
.chipid = CHIPID_STIH407,
.regmap = &stih407_sas_regmap,
.dac_ops = &stih407_dac_ops,
.dapm_widgets = stih407_sas_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(stih407_sas_dapm_widgets),
.dapm_routes = stih407_sas_route,
.num_dapm_routes = ARRAY_SIZE(stih407_sas_route),
};
static struct snd_soc_dai_driver sti_sas_dai[] = {
{
.name = "sas-dai-spdif-out",
.id = STI_SAS_DAI_SPDIF_OUT,
.playback = {
.stream_name = "spdif_p",
.channels_min = 2,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 |
SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
SNDRV_PCM_RATE_192000,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S32_LE,
},
.ops = (struct snd_soc_dai_ops[]) {
{
.set_fmt = sti_sas_spdif_set_fmt,
.trigger = sti_sas_spdif_trigger,
.set_sysclk = sti_sas_set_sysclk,
.prepare = sti_sas_prepare,
}
},
},
{
.name = "sas-dai-dac",
.id = STI_SAS_DAI_ANALOG_OUT,
.playback = {
.stream_name = "dac_p",
.channels_min = 2,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_8000_48000,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S32_LE,
},
},
};
#ifdef CONFIG_PM_SLEEP
static int sti_sas_resume(struct snd_soc_codec *codec)
{
struct sti_sas_data *drvdata = dev_get_drvdata(codec->dev);
return sti_sas_init_sas_registers(codec, drvdata);
}
#else
#define sti_sas_resume NULL
#endif
static int sti_sas_codec_probe(struct snd_soc_codec *codec)
{
struct sti_sas_data *drvdata = dev_get_drvdata(codec->dev);
int ret;
ret = sti_sas_init_sas_registers(codec, drvdata);
return ret;
}
static struct snd_soc_codec_driver sti_sas_driver = {
.probe = sti_sas_codec_probe,
.resume = sti_sas_resume,
};
static const struct of_device_id sti_sas_dev_match[] = {
{
.compatible = "st,stih416-sas-codec",
.data = &stih416_data,
},
{
.compatible = "st,stih407-sas-codec",
.data = &stih407_data,
},
{},
};
static int sti_sas_driver_probe(struct platform_device *pdev)
{
struct device_node *pnode = pdev->dev.of_node;
struct sti_sas_data *drvdata;
const struct of_device_id *of_id;
/* Allocate device structure */
drvdata = devm_kzalloc(&pdev->dev, sizeof(struct sti_sas_data),
GFP_KERNEL);
if (!drvdata)
return -ENOMEM;
/* Populate data structure depending on compatibility */
of_id = of_match_node(sti_sas_dev_match, pnode);
if (!of_id->data) {
dev_err(&pdev->dev, "data associated to device is missing");
return -EINVAL;
}
drvdata->dev_data = (struct sti_sas_dev_data *)of_id->data;
/* Initialise device structure */
drvdata->dev = &pdev->dev;
/* Request the DAC & SPDIF registers memory region */
drvdata->dac.virt_regmap = devm_regmap_init(&pdev->dev, NULL, drvdata,
drvdata->dev_data->regmap);
if (IS_ERR(drvdata->dac.virt_regmap)) {
dev_err(&pdev->dev, "audio registers not enabled\n");
return PTR_ERR(drvdata->dac.virt_regmap);
}
/* Request the syscon region */
drvdata->dac.regmap =
syscon_regmap_lookup_by_phandle(pnode, "st,syscfg");
if (IS_ERR(drvdata->dac.regmap)) {
dev_err(&pdev->dev, "syscon registers not available\n");
return PTR_ERR(drvdata->dac.regmap);
}
drvdata->spdif.regmap = drvdata->dac.regmap;
/* Set DAC dai probe */
if (drvdata->dev_data->chipid == CHIPID_STIH416)
sti_sas_dai[STI_SAS_DAI_ANALOG_OUT].probe = stih416_dac_probe;
sti_sas_dai[STI_SAS_DAI_ANALOG_OUT].ops = drvdata->dev_data->dac_ops;
/* Set dapms*/
sti_sas_driver.dapm_widgets = drvdata->dev_data->dapm_widgets;
sti_sas_driver.num_dapm_widgets = drvdata->dev_data->num_dapm_widgets;
sti_sas_driver.dapm_routes = drvdata->dev_data->dapm_routes;
sti_sas_driver.num_dapm_routes = drvdata->dev_data->num_dapm_routes;
/* Store context */
dev_set_drvdata(&pdev->dev, drvdata);
return snd_soc_register_codec(&pdev->dev, &sti_sas_driver,
sti_sas_dai,
ARRAY_SIZE(sti_sas_dai));
}
static int sti_sas_driver_remove(struct platform_device *pdev)
{
snd_soc_unregister_codec(&pdev->dev);
return 0;
}
static struct platform_driver sti_sas_platform_driver = {
.driver = {
.name = "sti-sas-codec",
.of_match_table = sti_sas_dev_match,
},
.probe = sti_sas_driver_probe,
.remove = sti_sas_driver_remove,
};
module_platform_driver(sti_sas_platform_driver);
MODULE_DESCRIPTION("audio codec for STMicroelectronics sti platforms");
MODULE_AUTHOR("Arnaud.pouliquen@st.com");
MODULE_LICENSE("GPL v2");
#
# STM SoC audio configuration
#
menuconfig SND_SOC_STI
tristate "SoC Audio support for STI System-On-Chip"
depends on SND_SOC
depends on ARCH_STI || COMPILE_TEST
select SND_SOC_GENERIC_DMAENGINE_PCM
help
Say Y if you want to enable ASoC-support for
any of the STI platforms (e.g. STIH416).
# STI platform support
snd-soc-sti-objs := sti_uniperif.o uniperif_player.o uniperif_reader.o
obj-$(CONFIG_SND_SOC_STI) += snd-soc-sti.o
/*
* Copyright (C) STMicroelectronics SA 2015
* Authors: Arnaud Pouliquen <arnaud.pouliquen@st.com>
* for STMicroelectronics.
* License terms: GNU General Public License (GPL), version 2
*/
#include <linux/module.h>
#include <linux/pinctrl/consumer.h>
#include "uniperif.h"
/*
* sti_uniperiph_dai_create_ctrl
* This function is used to create Ctrl associated to DAI but also pcm device.
* Request is done by front end to associate ctrl with pcm device id
*/
static int sti_uniperiph_dai_create_ctrl(struct snd_soc_dai *dai)
{
struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai);
struct uniperif *uni = priv->dai_data.uni;
struct snd_kcontrol_new *ctrl;
int i;
if (!uni->num_ctrls)
return 0;
for (i = 0; i < uni->num_ctrls; i++) {
/*
* Several Control can have same name. Controls are indexed on
* Uniperipheral instance ID
*/
ctrl = &uni->snd_ctrls[i];
ctrl->index = uni->info->id;
ctrl->device = uni->info->id;
}
return snd_soc_add_dai_controls(dai, uni->snd_ctrls, uni->num_ctrls);
}
/*
* DAI
*/
int sti_uniperiph_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct snd_dmaengine_dai_dma_data *dma_data;
int transfer_size;
transfer_size = params_channels(params) * UNIPERIF_FIFO_FRAMES;
dma_data = snd_soc_dai_get_dma_data(dai, substream);
dma_data->maxburst = transfer_size;
return 0;
}
int sti_uniperiph_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai);
priv->dai_data.uni->daifmt = fmt;
return 0;
}
static int sti_uniperiph_dai_suspend(struct snd_soc_dai *dai)
{
struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai);
struct uniperif *uni = priv->dai_data.uni;
int ret;
/* The uniperipheral should be in stopped state */
if (uni->state != UNIPERIF_STATE_STOPPED) {
dev_err(uni->dev, "%s: invalid uni state( %d)",
__func__, (int)uni->state);
return -EBUSY;
}
/* Pinctrl: switch pinstate to sleep */
ret = pinctrl_pm_select_sleep_state(uni->dev);
if (ret)
dev_err(uni->dev, "%s: failed to select pinctrl state",
__func__);
return ret;
}
static int sti_uniperiph_dai_resume(struct snd_soc_dai *dai)
{
struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai);
struct uniperif *uni = priv->dai_data.uni;
int ret;
if (of_device_is_compatible(dai->dev->of_node, "st,sti-uni-player")) {
ret = uni_player_resume(uni);
if (ret)
return ret;
}
/* pinctrl: switch pinstate to default */
ret = pinctrl_pm_select_default_state(uni->dev);
if (ret)
dev_err(uni->dev, "%s: failed to select pinctrl state",
__func__);
return ret;
}
static int sti_uniperiph_dai_probe(struct snd_soc_dai *dai)
{
struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai);
struct sti_uniperiph_dai *dai_data = &priv->dai_data;
/* DMA settings*/
if (of_device_is_compatible(dai->dev->of_node, "st,sti-uni-player"))
snd_soc_dai_init_dma_data(dai, &dai_data->dma_data, NULL);
else
snd_soc_dai_init_dma_data(dai, NULL, &dai_data->dma_data);
dai_data->dma_data.addr = dai_data->uni->fifo_phys_address;
dai_data->dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
return sti_uniperiph_dai_create_ctrl(dai);
}
static const struct snd_soc_dai_driver sti_uniperiph_dai_template = {
.probe = sti_uniperiph_dai_probe,
.suspend = sti_uniperiph_dai_suspend,
.resume = sti_uniperiph_dai_resume
};
static const struct snd_soc_component_driver sti_uniperiph_dai_component = {
.name = "sti_cpu_dai",
};
static int sti_uniperiph_cpu_dai_of(struct device_node *node,
struct sti_uniperiph_data *priv)
{
const char *str;
int ret;
struct device *dev = &priv->pdev->dev;
struct sti_uniperiph_dai *dai_data = &priv->dai_data;
struct snd_soc_dai_driver *dai = priv->dai;
struct snd_soc_pcm_stream *stream;
struct uniperif *uni;
uni = devm_kzalloc(dev, sizeof(*uni), GFP_KERNEL);
if (!uni)
return -ENOMEM;
*dai = sti_uniperiph_dai_template;
ret = of_property_read_string(node, "dai-name", &str);
if (ret < 0) {
dev_err(dev, "%s: dai name missing.\n", __func__);
return -EINVAL;
}
dai->name = str;
/* Get resources */
uni->mem_region = platform_get_resource(priv->pdev, IORESOURCE_MEM, 0);
if (!uni->mem_region) {
dev_err(dev, "Failed to get memory resource");
return -ENODEV;
}
uni->base = devm_ioremap_resource(dev, uni->mem_region);
if (IS_ERR(uni->base))
return PTR_ERR(uni->base);
uni->fifo_phys_address = uni->mem_region->start +
UNIPERIF_FIFO_DATA_OFFSET(uni);
uni->irq = platform_get_irq(priv->pdev, 0);
if (uni->irq < 0) {
dev_err(dev, "Failed to get IRQ resource");
return -ENXIO;
}
dai_data->uni = uni;
if (of_device_is_compatible(node, "st,sti-uni-player")) {
uni_player_init(priv->pdev, uni);
stream = &dai->playback;
} else {
uni_reader_init(priv->pdev, uni);
stream = &dai->capture;
}
dai->ops = uni->dai_ops;
stream->stream_name = dai->name;
stream->channels_min = uni->hw->channels_min;
stream->channels_max = uni->hw->channels_max;
stream->rates = uni->hw->rates;
stream->formats = uni->hw->formats;
return 0;
}
static const struct snd_dmaengine_pcm_config dmaengine_pcm_config = {
.prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
};
static int sti_uniperiph_probe(struct platform_device *pdev)
{
struct sti_uniperiph_data *priv;
struct device_node *node = pdev->dev.of_node;
int ret;
/* Allocate the private data and the CPU_DAI array */
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->dai = devm_kzalloc(&pdev->dev, sizeof(*priv->dai), GFP_KERNEL);
if (!priv->dai)
return -ENOMEM;
priv->pdev = pdev;
ret = sti_uniperiph_cpu_dai_of(node, priv);
dev_set_drvdata(&pdev->dev, priv);
ret = devm_snd_soc_register_component(&pdev->dev,
&sti_uniperiph_dai_component,
priv->dai, 1);
if (ret < 0)
return ret;
return devm_snd_dmaengine_pcm_register(&pdev->dev,
&dmaengine_pcm_config, 0);
}
static const struct of_device_id snd_soc_sti_match[] = {
{ .compatible = "st,sti-uni-player", },
{ .compatible = "st,sti-uni-reader", },
{},
};
static struct platform_driver sti_uniperiph_driver = {
.driver = {
.name = "sti-uniperiph-dai",
.of_match_table = snd_soc_sti_match,
},
.probe = sti_uniperiph_probe,
};
module_platform_driver(sti_uniperiph_driver);
MODULE_DESCRIPTION("uniperipheral DAI driver");
MODULE_AUTHOR("Arnaud Pouliquen <arnaud.pouliquen@st.com>");
MODULE_LICENSE("GPL v2");
/*
* Copyright (C) STMicroelectronics SA 2015
* Authors: Arnaud Pouliquen <arnaud.pouliquen@st.com>
* for STMicroelectronics.
* License terms: GNU General Public License (GPL), version 2
*/
#ifndef __SND_ST_AUD_UNIPERIF_H
#define __SND_ST_AUD_UNIPERIF_H
#include <linux/regmap.h>
#include <sound/dmaengine_pcm.h>
/*
* Register access macros
*/
#define GET_UNIPERIF_REG(ip, offset, shift, mask) \
((readl_relaxed(ip->base + offset) >> shift) & mask)
#define SET_UNIPERIF_REG(ip, offset, shift, mask, value) \
writel_relaxed(((readl_relaxed(ip->base + offset) & \
~(mask << shift)) | (((value) & mask) << shift)), ip->base + offset)
#define SET_UNIPERIF_BIT_REG(ip, offset, shift, mask, value) \
writel_relaxed((((value) & mask) << shift), ip->base + offset)
/*
* AUD_UNIPERIF_SOFT_RST reg
*/
#define UNIPERIF_SOFT_RST_OFFSET(ip) 0x0000
#define GET_UNIPERIF_SOFT_RST(ip) \
((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? \
readl_relaxed(ip->base + UNIPERIF_SOFT_RST_OFFSET(ip)) : 0)
#define SET_UNIPERIF_SOFT_RST(ip, value) \
writel_relaxed(value, ip->base + UNIPERIF_SOFT_RST_OFFSET(ip))
/* SOFT_RST */
#define UNIPERIF_SOFT_RST_SOFT_RST_SHIFT(ip) 0x0
#define UNIPERIF_SOFT_RST_SOFT_RST_MASK(ip) 0x1
#define SET_UNIPERIF_SOFT_RST_SOFT_RST(ip) \
SET_UNIPERIF_BIT_REG(ip, \
UNIPERIF_SOFT_RST_OFFSET(ip), \
UNIPERIF_SOFT_RST_SOFT_RST_SHIFT(ip), \
UNIPERIF_SOFT_RST_SOFT_RST_MASK(ip), 1)
#define GET_UNIPERIF_SOFT_RST_SOFT_RST(ip) \
GET_UNIPERIF_REG(ip, \
UNIPERIF_SOFT_RST_OFFSET(ip), \
UNIPERIF_SOFT_RST_SOFT_RST_SHIFT(ip), \
UNIPERIF_SOFT_RST_SOFT_RST_MASK(ip))
/*
* AUD_UNIPERIF_FIFO_DATA reg
*/
#define UNIPERIF_FIFO_DATA_OFFSET(ip) 0x0004
#define SET_UNIPERIF_DATA(ip, value) \
writel_relaxed(value, ip->base + UNIPERIF_FIFO_DATA_OFFSET(ip))
/*
* AUD_UNIPERIF_CHANNEL_STA_REGN reg
*/
#define UNIPERIF_CHANNEL_STA_REGN(ip, n) (0x0060 + (4 * n))
#define GET_UNIPERIF_CHANNEL_STA_REGN(ip) \
readl_relaxed(ip->base + UNIPERIF_CHANNEL_STA_REGN(ip, n))
#define SET_UNIPERIF_CHANNEL_STA_REGN(ip, n, value) \
writel_relaxed(value, ip->base + \
UNIPERIF_CHANNEL_STA_REGN(ip, n))
#define UNIPERIF_CHANNEL_STA_REG0_OFFSET(ip) 0x0060
#define GET_UNIPERIF_CHANNEL_STA_REG0(ip) \
readl_relaxed(ip->base + UNIPERIF_CHANNEL_STA_REG0_OFFSET(ip))
#define SET_UNIPERIF_CHANNEL_STA_REG0(ip, value) \
writel_relaxed(value, ip->base + UNIPERIF_CHANNEL_STA_REG0_OFFSET(ip))
#define UNIPERIF_CHANNEL_STA_REG1_OFFSET(ip) 0x0064
#define GET_UNIPERIF_CHANNEL_STA_REG1(ip) \
readl_relaxed(ip->base + UNIPERIF_CHANNEL_STA_REG1_OFFSET(ip))
#define SET_UNIPERIF_CHANNEL_STA_REG1(ip, value) \
writel_relaxed(value, ip->base + UNIPERIF_CHANNEL_STA_REG1_OFFSET(ip))
#define UNIPERIF_CHANNEL_STA_REG2_OFFSET(ip) 0x0068
#define GET_UNIPERIF_CHANNEL_STA_REG2(ip) \
readl_relaxed(ip->base + UNIPERIF_CHANNEL_STA_REG2_OFFSET(ip))
#define SET_UNIPERIF_CHANNEL_STA_REG2(ip, value) \
writel_relaxed(value, ip->base + UNIPERIF_CHANNEL_STA_REG2_OFFSET(ip))
#define UNIPERIF_CHANNEL_STA_REG3_OFFSET(ip) 0x006C
#define GET_UNIPERIF_CHANNEL_STA_REG3(ip) \
readl_relaxed(ip->base + UNIPERIF_CHANNEL_STA_REG3_OFFSET(ip))
#define SET_UNIPERIF_CHANNEL_STA_REG3(ip, value) \
writel_relaxed(value, ip->base + UNIPERIF_CHANNEL_STA_REG3_OFFSET(ip))
#define UNIPERIF_CHANNEL_STA_REG4_OFFSET(ip) 0x0070
#define GET_UNIPERIF_CHANNEL_STA_REG4(ip) \
readl_relaxed(ip->base + UNIPERIF_CHANNEL_STA_REG4_OFFSET(ip))
#define SET_UNIPERIF_CHANNEL_STA_REG4(ip, value) \
writel_relaxed(value, ip->base + UNIPERIF_CHANNEL_STA_REG4_OFFSET(ip))
#define UNIPERIF_CHANNEL_STA_REG5_OFFSET(ip) 0x0074
#define GET_UNIPERIF_CHANNEL_STA_REG5(ip) \
readl_relaxed(ip->base + UNIPERIF_CHANNEL_STA_REG5_OFFSET(ip))
#define SET_UNIPERIF_CHANNEL_STA_REG5(ip, value) \
writel_relaxed(value, ip->base + UNIPERIF_CHANNEL_STA_REG5_OFFSET(ip))
/*
* AUD_UNIPERIF_ITS reg
*/
#define UNIPERIF_ITS_OFFSET(ip) 0x000C
#define GET_UNIPERIF_ITS(ip) \
readl_relaxed(ip->base + UNIPERIF_ITS_OFFSET(ip))
/* MEM_BLK_READ */
#define UNIPERIF_ITS_MEM_BLK_READ_SHIFT(ip) 5
#define UNIPERIF_ITS_MEM_BLK_READ_MASK(ip) \
(BIT(UNIPERIF_ITS_MEM_BLK_READ_SHIFT(ip)))
/* FIFO_ERROR */
#define UNIPERIF_ITS_FIFO_ERROR_SHIFT(ip) \
((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 0 : 8)
#define UNIPERIF_ITS_FIFO_ERROR_MASK(ip) \
(BIT(UNIPERIF_ITS_FIFO_ERROR_SHIFT(ip)))
/* DMA_ERROR */
#define UNIPERIF_ITS_DMA_ERROR_SHIFT(ip) 9
#define UNIPERIF_ITS_DMA_ERROR_MASK(ip) \
(BIT(UNIPERIF_ITS_DMA_ERROR_SHIFT(ip)))
/* UNDERFLOW_REC_DONE */
#define UNIPERIF_ITS_UNDERFLOW_REC_DONE_SHIFT(ip) \
((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? -1 : 12)
#define UNIPERIF_ITS_UNDERFLOW_REC_DONE_MASK(ip) \
((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? \
0 : (BIT(UNIPERIF_ITS_UNDERFLOW_REC_DONE_SHIFT(ip))))
/* UNDERFLOW_REC_FAILED */
#define UNIPERIF_ITS_UNDERFLOW_REC_FAILED_SHIFT(ip) \
((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? -1 : 13)
#define UNIPERIF_ITS_UNDERFLOW_REC_FAILED_MASK(ip) \
((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? \
0 : (BIT(UNIPERIF_ITS_UNDERFLOW_REC_FAILED_SHIFT(ip))))
/*
* AUD_UNIPERIF_ITS_BCLR reg
*/
/* FIFO_ERROR */
#define UNIPERIF_ITS_BCLR_FIFO_ERROR_SHIFT(ip) \
((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 0 : 8)
#define UNIPERIF_ITS_BCLR_FIFO_ERROR_MASK(ip) \
(BIT(UNIPERIF_ITS_BCLR_FIFO_ERROR_SHIFT(ip)))
#define SET_UNIPERIF_ITS_BCLR_FIFO_ERROR(ip) \
SET_UNIPERIF_ITS_BCLR(ip, \
UNIPERIF_ITS_BCLR_FIFO_ERROR_MASK(ip))
#define UNIPERIF_ITS_BCLR_OFFSET(ip) 0x0010
#define SET_UNIPERIF_ITS_BCLR(ip, value) \
writel_relaxed(value, ip->base + UNIPERIF_ITS_BCLR_OFFSET(ip))
/*
* AUD_UNIPERIF_ITM reg
*/
#define UNIPERIF_ITM_OFFSET(ip) 0x0018
#define GET_UNIPERIF_ITM(ip) \
readl_relaxed(ip->base + UNIPERIF_ITM_OFFSET(ip))
/* FIFO_ERROR */
#define UNIPERIF_ITM_FIFO_ERROR_SHIFT(ip) \
((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 0 : 8)
#define UNIPERIF_ITM_FIFO_ERROR_MASK(ip) \
(BIT(UNIPERIF_ITM_FIFO_ERROR_SHIFT(ip)))
/* UNDERFLOW_REC_DONE */
#define UNIPERIF_ITM_UNDERFLOW_REC_DONE_SHIFT(ip) \
((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? -1 : 12)
#define UNIPERIF_ITM_UNDERFLOW_REC_DONE_MASK(ip) \
((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? \
0 : (BIT(UNIPERIF_ITM_UNDERFLOW_REC_DONE_SHIFT(ip))))
/* UNDERFLOW_REC_FAILED */
#define UNIPERIF_ITM_UNDERFLOW_REC_FAILED_SHIFT(ip) \
((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? -1 : 13)
#define UNIPERIF_ITM_UNDERFLOW_REC_FAILED_MASK(ip) \
((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? \
0 : (BIT(UNIPERIF_ITM_UNDERFLOW_REC_FAILED_SHIFT(ip))))
/*
* AUD_UNIPERIF_ITM_BCLR reg
*/
#define UNIPERIF_ITM_BCLR_OFFSET(ip) 0x001c
#define SET_UNIPERIF_ITM_BCLR(ip, value) \
writel_relaxed(value, ip->base + UNIPERIF_ITM_BCLR_OFFSET(ip))
/* FIFO_ERROR */
#define UNIPERIF_ITM_BCLR_FIFO_ERROR_SHIFT(ip) \
((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 0 : 8)
#define UNIPERIF_ITM_BCLR_FIFO_ERROR_MASK(ip) \
(BIT(UNIPERIF_ITM_BCLR_FIFO_ERROR_SHIFT(ip)))
#define SET_UNIPERIF_ITM_BCLR_FIFO_ERROR(ip) \
SET_UNIPERIF_ITM_BCLR(ip, \
UNIPERIF_ITM_BCLR_FIFO_ERROR_MASK(ip))
/* DMA_ERROR */
#define UNIPERIF_ITM_BCLR_DMA_ERROR_SHIFT(ip) 9
#define UNIPERIF_ITM_BCLR_DMA_ERROR_MASK(ip) \
(BIT(UNIPERIF_ITM_BCLR_DMA_ERROR_SHIFT(ip)))
#define SET_UNIPERIF_ITM_BCLR_DMA_ERROR(ip) \
SET_UNIPERIF_ITM_BCLR(ip, \
UNIPERIF_ITM_BCLR_DMA_ERROR_MASK(ip))
/*
* AUD_UNIPERIF_ITM_BSET reg
*/
#define UNIPERIF_ITM_BSET_OFFSET(ip) 0x0020
#define SET_UNIPERIF_ITM_BSET(ip, value) \
writel_relaxed(value, ip->base + UNIPERIF_ITM_BSET_OFFSET(ip))
/* FIFO_ERROR */
#define UNIPERIF_ITM_BSET_FIFO_ERROR_SHIFT(ip) \
((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 0 : 8)
#define UNIPERIF_ITM_BSET_FIFO_ERROR_MASK(ip) \
(BIT(UNIPERIF_ITM_BSET_FIFO_ERROR_SHIFT(ip)))
#define SET_UNIPERIF_ITM_BSET_FIFO_ERROR(ip) \
SET_UNIPERIF_ITM_BSET(ip, \
UNIPERIF_ITM_BSET_FIFO_ERROR_MASK(ip))
/* MEM_BLK_READ */
#define UNIPERIF_ITM_BSET_MEM_BLK_READ_SHIFT(ip) 5
#define UNIPERIF_ITM_BSET_MEM_BLK_READ_MASK(ip) \
(BIT(UNIPERIF_ITM_BSET_MEM_BLK_READ_SHIFT(ip)))
#define SET_UNIPERIF_ITM_BSET_MEM_BLK_READ(ip) \
SET_UNIPERIF_ITM_BSET(ip, \
UNIPERIF_ITM_BSET_MEM_BLK_READ_MASK(ip))
/* DMA_ERROR */
#define UNIPERIF_ITM_BSET_DMA_ERROR_SHIFT(ip) 9
#define UNIPERIF_ITM_BSET_DMA_ERROR_MASK(ip) \
(BIT(UNIPERIF_ITM_BSET_DMA_ERROR_SHIFT(ip)))
#define SET_UNIPERIF_ITM_BSET_DMA_ERROR(ip) \
SET_UNIPERIF_ITM_BSET(ip, \
UNIPERIF_ITM_BSET_DMA_ERROR_MASK(ip))
/* UNDERFLOW_REC_DONE */
#define UNIPERIF_ITM_BSET_UNDERFLOW_REC_DONE_SHIFT(ip) \
((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? -1 : 12)
#define UNIPERIF_ITM_BSET_UNDERFLOW_REC_DONE_MASK(ip) \
((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? \
0 : (BIT(UNIPERIF_ITM_BSET_UNDERFLOW_REC_DONE_SHIFT(ip))))
#define SET_UNIPERIF_ITM_BSET_UNDERFLOW_REC_DONE(ip) \
SET_UNIPERIF_ITM_BSET(ip, \
UNIPERIF_ITM_BSET_UNDERFLOW_REC_DONE_MASK(ip))
/* UNDERFLOW_REC_FAILED */
#define UNIPERIF_ITM_BSET_UNDERFLOW_REC_FAILED_SHIFT(ip) \
((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? -1 : 13)
#define UNIPERIF_ITM_BSET_UNDERFLOW_REC_FAILED_MASK(ip) \
((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? \
0 : (BIT(UNIPERIF_ITM_BSET_UNDERFLOW_REC_FAILED_SHIFT(ip))))
#define SET_UNIPERIF_ITM_BSET_UNDERFLOW_REC_FAILED(ip) \
SET_UNIPERIF_ITM_BSET(ip, \
UNIPERIF_ITM_BSET_UNDERFLOW_REC_FAILED_MASK(ip))
/*
* UNIPERIF_CONFIG reg
*/
#define UNIPERIF_CONFIG_OFFSET(ip) 0x0040
#define GET_UNIPERIF_CONFIG(ip) \
readl_relaxed(ip->base + UNIPERIF_CONFIG_OFFSET(ip))
#define SET_UNIPERIF_CONFIG(ip, value) \
writel_relaxed(value, ip->base + UNIPERIF_CONFIG_OFFSET(ip))
/* PARITY_CNTR */
#define UNIPERIF_CONFIG_PARITY_CNTR_SHIFT(ip) 0
#define UNIPERIF_CONFIG_PARITY_CNTR_MASK(ip) 0x1
#define GET_UNIPERIF_CONFIG_PARITY_CNTR(ip) \
GET_UNIPERIF_REG(ip, \
UNIPERIF_CONFIG_OFFSET(ip), \
UNIPERIF_CONFIG_PARITY_CNTR_SHIFT(ip), \
UNIPERIF_CONFIG_PARITY_CNTR_MASK(ip))
#define SET_UNIPERIF_CONFIG_PARITY_CNTR_BY_HW(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_CONFIG_OFFSET(ip), \
UNIPERIF_CONFIG_PARITY_CNTR_SHIFT(ip), \
UNIPERIF_CONFIG_PARITY_CNTR_MASK(ip), 0)
#define SET_UNIPERIF_CONFIG_PARITY_CNTR_BY_SW(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_CONFIG_OFFSET(ip), \
UNIPERIF_CONFIG_PARITY_CNTR_SHIFT(ip), \
UNIPERIF_CONFIG_PARITY_CNTR_MASK(ip), 1)
/* CHANNEL_STA_CNTR */
#define UNIPERIF_CONFIG_CHANNEL_STA_CNTR_SHIFT(ip) 1
#define UNIPERIF_CONFIG_CHANNEL_STA_CNTR_MASK(ip) 0x1
#define GET_UNIPERIF_CONFIG_CHANNEL_STA_CNTR(ip) \
GET_UNIPERIF_REG(ip, \
UNIPERIF_CONFIG_OFFSET(ip), \
UNIPERIF_CONFIG_CHANNEL_STA_CNTR_SHIFT(ip), \
UNIPERIF_CONFIG_CHANNEL_STA_CNTR_MASK(ip))
#define SET_UNIPERIF_CONFIG_CHANNEL_STA_CNTR_BY_SW(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_CONFIG_OFFSET(ip), \
UNIPERIF_CONFIG_CHANNEL_STA_CNTR_SHIFT(ip), \
UNIPERIF_CONFIG_CHANNEL_STA_CNTR_MASK(ip), 0)
#define SET_UNIPERIF_CONFIG_CHANNEL_STA_CNTR_BY_HW(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_CONFIG_OFFSET(ip), \
UNIPERIF_CONFIG_CHANNEL_STA_CNTR_SHIFT(ip), \
UNIPERIF_CONFIG_CHANNEL_STA_CNTR_MASK(ip), 1)
/* USER_DAT_CNTR */
#define UNIPERIF_CONFIG_USER_DAT_CNTR_SHIFT(ip) 2
#define UNIPERIF_CONFIG_USER_DAT_CNTR_MASK(ip) 0x1
#define GET_UNIPERIF_CONFIG_USER_DAT_CNTR(ip) \
GET_UNIPERIF_REG(ip, \
UNIPERIF_CONFIG_OFFSET(ip), \
UNIPERIF_CONFIG_USER_DAT_CNTR_SHIFT(ip), \
UNIPERIF_CONFIG_USER_DAT_CNTR_MASK(ip))
#define SET_UNIPERIF_CONFIG_USER_DAT_CNTR_BY_HW(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_CONFIG_OFFSET(ip), \
UNIPERIF_CONFIG_USER_DAT_CNTR_SHIFT(ip), \
UNIPERIF_CONFIG_USER_DAT_CNTR_MASK(ip), 1)
#define SET_UNIPERIF_CONFIG_USER_DAT_CNTR_BY_SW(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_CONFIG_OFFSET(ip), \
UNIPERIF_CONFIG_USER_DAT_CNTR_SHIFT(ip), \
UNIPERIF_CONFIG_USER_DAT_CNTR_MASK(ip), 0)
/* VALIDITY_DAT_CNTR */
#define UNIPERIF_CONFIG_VALIDITY_DAT_CNTR_SHIFT(ip) 3
#define UNIPERIF_CONFIG_VALIDITY_DAT_CNTR_MASK(ip) 0x1
#define GET_UNIPERIF_CONFIG_VALIDITY_DAT_CNTR(ip) \
GET_UNIPERIF_REG(ip, \
UNIPERIF_CONFIG_OFFSET(ip), \
UNIPERIF_CONFIG_VALIDITY_DAT_CNTR_SHIFT(ip), \
UNIPERIF_CONFIG_VALIDITY_DAT_CNTR_MASK(ip))
#define SET_UNIPERIF_CONFIG_VALIDITY_DAT_CNTR_BY_SW(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_CONFIG_OFFSET(ip), \
UNIPERIF_CONFIG_VALIDITY_DAT_CNTR_SHIFT(ip), \
UNIPERIF_CONFIG_VALIDITY_DAT_CNTR_MASK(ip), 0)
#define SET_UNIPERIF_CONFIG_VALIDITY_DAT_CNTR_BY_HW(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_CONFIG_OFFSET(ip), \
UNIPERIF_CONFIG_VALIDITY_DAT_CNTR_SHIFT(ip), \
UNIPERIF_CONFIG_VALIDITY_DAT_CNTR_MASK(ip), 1)
/* ONE_BIT_AUD_SUPPORT */
#define UNIPERIF_CONFIG_ONE_BIT_AUD_SHIFT(ip) 4
#define UNIPERIF_CONFIG_ONE_BIT_AUD_MASK(ip) 0x1
#define GET_UNIPERIF_CONFIG_ONE_BIT_AUD(ip) \
GET_UNIPERIF_REG(ip, \
UNIPERIF_CONFIG_OFFSET(ip), \
UNIPERIF_CONFIG_ONE_BIT_AUD_SHIFT(ip), \
UNIPERIF_CONFIG_ONE_BIT_AUD_MASK(ip))
#define SET_UNIPERIF_CONFIG_ONE_BIT_AUD_DISABLE(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_CONFIG_OFFSET(ip), \
UNIPERIF_CONFIG_ONE_BIT_AUD_SHIFT(ip), \
UNIPERIF_CONFIG_ONE_BIT_AUD_MASK(ip), 0)
#define SET_UNIPERIF_CONFIG_ONE_BIT_AUD_ENABLE(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_CONFIG_OFFSET(ip), \
UNIPERIF_CONFIG_ONE_BIT_AUD_SHIFT(ip), \
UNIPERIF_CONFIG_ONE_BIT_AUD_MASK(ip), 1)
/* MEMORY_FMT */
#define UNIPERIF_CONFIG_MEM_FMT_SHIFT(ip) 5
#define UNIPERIF_CONFIG_MEM_FMT_MASK(ip) 0x1
#define VALUE_UNIPERIF_CONFIG_MEM_FMT_16_0(ip) 0
#define VALUE_UNIPERIF_CONFIG_MEM_FMT_16_16(ip) 1
#define GET_UNIPERIF_CONFIG_MEM_FMT(ip) \
GET_UNIPERIF_REG(ip, \
UNIPERIF_CONFIG_OFFSET(ip), \
UNIPERIF_CONFIG_MEM_FMT_SHIFT(ip), \
UNIPERIF_CONFIG_MEM_FMT_MASK(ip))
#define SET_UNIPERIF_CONFIG_MEM_FMT(ip, value) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_CONFIG_OFFSET(ip), \
UNIPERIF_CONFIG_MEM_FMT_SHIFT(ip), \
UNIPERIF_CONFIG_MEM_FMT_MASK(ip), value)
#define SET_UNIPERIF_CONFIG_MEM_FMT_16_0(ip) \
SET_UNIPERIF_CONFIG_MEM_FMT(ip, \
VALUE_UNIPERIF_CONFIG_MEM_FMT_16_0(ip))
#define SET_UNIPERIF_CONFIG_MEM_FMT_16_16(ip) \
SET_UNIPERIF_CONFIG_MEM_FMT(ip, \
VALUE_UNIPERIF_CONFIG_MEM_FMT_16_16(ip))
/* REPEAT_CHL_STS */
#define UNIPERIF_CONFIG_REPEAT_CHL_STS_SHIFT(ip) 6
#define UNIPERIF_CONFIG_REPEAT_CHL_STS_MASK(ip) 0x1
#define GET_UNIPERIF_CONFIG_REPEAT_CHL_STS(ip) \
GET_UNIPERIF_REG(ip, \
UNIPERIF_CONFIG_OFFSET(ip), \
UNIPERIF_CONFIG_REPEAT_CHL_STS_SHIFT(ip), \
UNIPERIF_CONFIG_REPEAT_CHL_STS_MASK(ip))
#define SET_UNIPERIF_CONFIG_REPEAT_CHL_STS_ENABLE(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_CONFIG_OFFSET(ip), \
UNIPERIF_CONFIG_REPEAT_CHL_STS_SHIFT(ip), \
UNIPERIF_CONFIG_REPEAT_CHL_STS_MASK(ip), 0)
#define SET_UNIPERIF_CONFIG_REPEAT_CHL_STS_DISABLE(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_CONFIG_OFFSET(ip), \
UNIPERIF_CONFIG_REPEAT_CHL_STS_SHIFT(ip), \
UNIPERIF_CONFIG_REPEAT_CHL_STS_MASK(ip), 1)
/* BACK_STALL_REQ */
#define UNIPERIF_CONFIG_BACK_STALL_REQ_SHIFT(ip) \
((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 7 : -1)
#define UNIPERIF_CONFIG_BACK_STALL_REQ_MASK(ip) 0x1
#define GET_UNIPERIF_CONFIG_BACK_STALL_REQ(ip) \
GET_UNIPERIF_REG(ip, \
UNIPERIF_CONFIG_OFFSET(ip), \
UNIPERIF_CONFIG_BACK_STALL_REQ_SHIFT(ip), \
UNIPERIF_CONFIG_BACK_STALL_REQ_MASK(ip))
#define SET_UNIPERIF_CONFIG_BACK_STALL_REQ_DISABLE(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_CONFIG_OFFSET(ip), \
UNIPERIF_CONFIG_BACK_STALL_REQ_SHIFT(ip), \
UNIPERIF_CONFIG_BACK_STALL_REQ_MASK(ip), 0)
#define SET_UNIPERIF_CONFIG_BACK_STALL_REQ_ENABLE(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_CONFIG_OFFSET(ip), \
UNIPERIF_CONFIG_BACK_STALL_REQ_SHIFT(ip), \
UNIPERIF_CONFIG_BACK_STALL_REQ_MASK(ip), 1)
/* FDMA_TRIGGER_LIMIT */
#define UNIPERIF_CONFIG_DMA_TRIG_LIMIT_SHIFT(ip) 8
#define UNIPERIF_CONFIG_DMA_TRIG_LIMIT_MASK(ip) 0x7F
#define GET_UNIPERIF_CONFIG_DMA_TRIG_LIMIT(ip) \
GET_UNIPERIF_REG(ip, \
UNIPERIF_CONFIG_OFFSET(ip), \
UNIPERIF_CONFIG_DMA_TRIG_LIMIT_SHIFT(ip), \
UNIPERIF_CONFIG_DMA_TRIG_LIMIT_MASK(ip))
#define SET_UNIPERIF_CONFIG_DMA_TRIG_LIMIT(ip, value) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_CONFIG_OFFSET(ip), \
UNIPERIF_CONFIG_DMA_TRIG_LIMIT_SHIFT(ip), \
UNIPERIF_CONFIG_DMA_TRIG_LIMIT_MASK(ip), value)
/* CHL_STS_UPDATE */
#define UNIPERIF_CONFIG_CHL_STS_UPDATE_SHIFT(ip) \
((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 16 : -1)
#define UNIPERIF_CONFIG_CHL_STS_UPDATE_MASK(ip) 0x1
#define GET_UNIPERIF_CONFIG_CHL_STS_UPDATE(ip) \
GET_UNIPERIF_REG(ip, \
UNIPERIF_CONFIG_OFFSET(ip), \
UNIPERIF_CONFIG_CHL_STS_UPDATE_SHIFT(ip), \
UNIPERIF_CONFIG_CHL_STS_UPDATE_MASK(ip))
#define SET_UNIPERIF_CONFIG_CHL_STS_UPDATE(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_CONFIG_OFFSET(ip), \
UNIPERIF_CONFIG_CHL_STS_UPDATE_SHIFT(ip), \
UNIPERIF_CONFIG_CHL_STS_UPDATE_MASK(ip), 1)
/* IDLE_MOD */
#define UNIPERIF_CONFIG_IDLE_MOD_SHIFT(ip) 18
#define UNIPERIF_CONFIG_IDLE_MOD_MASK(ip) 0x1
#define GET_UNIPERIF_CONFIG_IDLE_MOD(ip) \
GET_UNIPERIF_REG(ip, \
UNIPERIF_CONFIG_OFFSET(ip), \
UNIPERIF_CONFIG_IDLE_MOD_SHIFT(ip), \
UNIPERIF_CONFIG_IDLE_MOD_MASK(ip))
#define SET_UNIPERIF_CONFIG_IDLE_MOD_DISABLE(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_CONFIG_OFFSET(ip), \
UNIPERIF_CONFIG_IDLE_MOD_SHIFT(ip), \
UNIPERIF_CONFIG_IDLE_MOD_MASK(ip), 0)
#define SET_UNIPERIF_CONFIG_IDLE_MOD_ENABLE(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_CONFIG_OFFSET(ip), \
UNIPERIF_CONFIG_IDLE_MOD_SHIFT(ip), \
UNIPERIF_CONFIG_IDLE_MOD_MASK(ip), 1)
/* SUBFRAME_SELECTION */
#define UNIPERIF_CONFIG_SUBFRAME_SEL_SHIFT(ip) 19
#define UNIPERIF_CONFIG_SUBFRAME_SEL_MASK(ip) 0x1
#define GET_UNIPERIF_CONFIG_SUBFRAME_SEL(ip) \
GET_UNIPERIF_REG(ip, \
UNIPERIF_CONFIG_OFFSET(ip), \
UNIPERIF_CONFIG_SUBFRAME_SEL_SHIFT(ip), \
UNIPERIF_CONFIG_SUBFRAME_SEL_MASK(ip))
#define SET_UNIPERIF_CONFIG_SUBFRAME_SEL_SUBF1_SUBF0(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_CONFIG_OFFSET(ip), \
UNIPERIF_CONFIG_SUBFRAME_SEL_SHIFT(ip), \
UNIPERIF_CONFIG_SUBFRAME_SEL_MASK(ip), 1)
#define SET_UNIPERIF_CONFIG_SUBFRAME_SEL_SUBF0_SUBF1(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_CONFIG_OFFSET(ip), \
UNIPERIF_CONFIG_SUBFRAME_SEL_SHIFT(ip), \
UNIPERIF_CONFIG_SUBFRAME_SEL_MASK(ip), 0)
/* FULL_SW_CONTROL */
#define UNIPERIF_CONFIG_SPDIF_SW_CTRL_SHIFT(ip) 20
#define UNIPERIF_CONFIG_SPDIF_SW_CTRL_MASK(ip) 0x1
#define GET_UNIPERIF_CONFIG_SPDIF_SW_CTRL(ip) \
GET_UNIPERIF_REG(ip, \
UNIPERIF_CONFIG_OFFSET(ip), \
UNIPERIF_CONFIG_SPDIF_SW_CTRL_SHIFT(ip), \
UNIPERIF_CONFIG_SPDIF_SW_CTRL_MASK(ip))
#define SET_UNIPERIF_CONFIG_SPDIF_SW_CTRL_ENABLE(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_CONFIG_OFFSET(ip), \
UNIPERIF_CONFIG_SPDIF_SW_CTRL_SHIFT(ip), \
UNIPERIF_CONFIG_SPDIF_SW_CTRL_MASK(ip), 1)
#define SET_UNIPERIF_CONFIG_SPDIF_SW_CTRL_DISABLE(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_CONFIG_OFFSET(ip), \
UNIPERIF_CONFIG_SPDIF_SW_CTRL_SHIFT(ip), \
UNIPERIF_CONFIG_SPDIF_SW_CTRL_MASK(ip), 0)
/* MASTER_CLKEDGE */
#define UNIPERIF_CONFIG_MSTR_CLKEDGE_SHIFT(ip) \
((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 24 : -1)
#define UNIPERIF_CONFIG_MSTR_CLKEDGE_MASK(ip) 0x1
#define GET_UNIPERIF_CONFIG_MSTR_CLKEDGE(ip) \
GET_UNIPERIF_REG(ip, \
UNIPERIF_CONFIG_OFFSET(ip), \
UNIPERIF_CONFIG_MSTR_CLKEDGE_SHIFT(ip), \
UNIPERIF_CONFIG_MSTR_CLKEDGE_MASK(ip))
#define SET_UNIPERIF_CONFIG_MSTR_CLKEDGE_FALLING(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_CONFIG_OFFSET(ip), \
UNIPERIF_CONFIG_MSTR_CLKEDGE_SHIFT(ip), \
UNIPERIF_CONFIG_MSTR_CLKEDGE_MASK(ip), 1)
#define SET_UNIPERIF_CONFIG_MSTR_CLKEDGE_RISING(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_CONFIG_OFFSET(ip), \
UNIPERIF_CONFIG_MSTR_CLKEDGE_SHIFT(ip), \
UNIPERIF_CONFIG_MSTR_CLKEDGE_MASK(ip), 0)
/*
* UNIPERIF_CTRL reg
*/
#define UNIPERIF_CTRL_OFFSET(ip) 0x0044
#define GET_UNIPERIF_CTRL(ip) \
readl_relaxed(ip->base + UNIPERIF_CTRL_OFFSET(ip))
#define SET_UNIPERIF_CTRL(ip, value) \
writel_relaxed(value, ip->base + UNIPERIF_CTRL_OFFSET(ip))
/* OPERATION */
#define UNIPERIF_CTRL_OPERATION_SHIFT(ip) 0
#define UNIPERIF_CTRL_OPERATION_MASK(ip) 0x7
#define GET_UNIPERIF_CTRL_OPERATION(ip) \
GET_UNIPERIF_REG(ip, \
UNIPERIF_CTRL_OFFSET(ip), \
UNIPERIF_CTRL_OPERATION_SHIFT(ip), \
UNIPERIF_CTRL_OPERATION_MASK(ip))
#define VALUE_UNIPERIF_CTRL_OPERATION_OFF(ip) 0
#define SET_UNIPERIF_CTRL_OPERATION_OFF(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_CTRL_OFFSET(ip), \
UNIPERIF_CTRL_OPERATION_SHIFT(ip), \
UNIPERIF_CTRL_OPERATION_MASK(ip), \
VALUE_UNIPERIF_CTRL_OPERATION_OFF(ip))
#define VALUE_UNIPERIF_CTRL_OPERATION_MUTE_PCM_NULL(ip) \
((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 1 : -1)
#define SET_UNIPERIF_CTRL_OPERATION_MUTE_PCM_NULL(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_CTRL_OFFSET(ip), \
UNIPERIF_CTRL_OPERATION_SHIFT(ip), \
UNIPERIF_CTRL_OPERATION_MASK(ip), \
VALUE_UNIPERIF_CTRL_OPERATION_MUTE_PCM_NULL(ip))
#define VALUE_UNIPERIF_CTRL_OPERATION_MUTE_PAUSE_BURST(ip) \
((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 2 : -1)
#define SET_UNIPERIF_CTRL_OPERATION_MUTE_PAUSE_BURST(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_CTRL_OFFSET(ip), \
UNIPERIF_CTRL_OPERATION_SHIFT(ip), \
UNIPERIF_CTRL_OPERATION_MASK(ip), \
VALUE_UNIPERIF_CTRL_OPERATION_MUTE_PAUSE_BURST(ip))
#define VALUE_UNIPERIF_CTRL_OPERATION_PCM_DATA(ip) 3
#define SET_UNIPERIF_CTRL_OPERATION_PCM_DATA(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_CTRL_OFFSET(ip), \
UNIPERIF_CTRL_OPERATION_SHIFT(ip), \
UNIPERIF_CTRL_OPERATION_MASK(ip), \
VALUE_UNIPERIF_CTRL_OPERATION_PCM_DATA(ip))
/* This is the same as above! */
#define VALUE_UNIPERIF_CTRL_OPERATION_AUDIO_DATA(ip) 3
#define SET_UNIPERIF_CTRL_OPERATION_AUDIO_DATA(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_CTRL_OFFSET(ip), \
UNIPERIF_CTRL_OPERATION_SHIFT(ip), \
UNIPERIF_CTRL_OPERATION_MASK(ip), \
VALUE_UNIPERIF_CTRL_OPERATION_AUDIO_DATA(ip))
#define VALUE_UNIPERIF_CTRL_OPERATION_ENC_DATA(ip) 4
#define SET_UNIPERIF_CTRL_OPERATION_ENC_DATA(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_CTRL_OFFSET(ip), \
UNIPERIF_CTRL_OPERATION_SHIFT(ip), \
UNIPERIF_CTRL_OPERATION_MASK(ip), \
VALUE_UNIPERIF_CTRL_OPERATION_ENC_DATA(ip))
#define VALUE_UNIPERIF_CTRL_OPERATION_CD_DATA(ip) \
((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 5 : -1)
#define SET_UNIPERIF_CTRL_OPERATION_CD_DATA(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_CTRL_OFFSET(ip), \
UNIPERIF_CTRL_OPERATION_SHIFT(ip), \
UNIPERIF_CTRL_OPERATION_MASK(ip), \
VALUE_UNIPERIF_CTRL_OPERATION_CD_DATA(ip))
#define VALUE_UNIPERIF_CTRL_OPERATION_STANDBY(ip) \
((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? -1 : 7)
#define SET_UNIPERIF_CTRL_OPERATION_STANDBY(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_CTRL_OFFSET(ip), \
UNIPERIF_CTRL_OPERATION_SHIFT(ip), \
UNIPERIF_CTRL_OPERATION_MASK(ip), \
VALUE_UNIPERIF_CTRL_OPERATION_STANDBY(ip))
/* EXIT_STBY_ON_EOBLOCK */
#define UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_SHIFT(ip) \
((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? -1 : 3)
#define UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_MASK(ip) 0x1
#define GET_UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK(ip) \
GET_UNIPERIF_REG(ip, \
UNIPERIF_CTRL_OFFSET(ip), \
UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_SHIFT(ip), \
UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_MASK(ip))
#define SET_UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_OFF(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_CTRL_OFFSET(ip), \
UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_SHIFT(ip), \
UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_MASK(ip), 0)
#define SET_UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_ON(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_CTRL_OFFSET(ip), \
UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_SHIFT(ip), \
UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_MASK(ip), 1)
/* ROUNDING */
#define UNIPERIF_CTRL_ROUNDING_SHIFT(ip) 4
#define UNIPERIF_CTRL_ROUNDING_MASK(ip) 0x1
#define GET_UNIPERIF_CTRL_ROUNDING(ip) \
GET_UNIPERIF_REG(ip, \
UNIPERIF_CTRL_OFFSET(ip), \
UNIPERIF_CTRL_ROUNDING_SHIFT(ip), \
UNIPERIF_CTRL_ROUNDING_MASK(ip))
#define SET_UNIPERIF_CTRL_ROUNDING_OFF(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_CTRL_OFFSET(ip), \
UNIPERIF_CTRL_ROUNDING_SHIFT(ip), \
UNIPERIF_CTRL_ROUNDING_MASK(ip), 0)
#define SET_UNIPERIF_CTRL_ROUNDING_ON(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_CTRL_OFFSET(ip), \
UNIPERIF_CTRL_ROUNDING_SHIFT(ip), \
UNIPERIF_CTRL_ROUNDING_MASK(ip), 1)
/* DIVIDER */
#define UNIPERIF_CTRL_DIVIDER_SHIFT(ip) 5
#define UNIPERIF_CTRL_DIVIDER_MASK(ip) 0xff
#define GET_UNIPERIF_CTRL_DIVIDER(ip) \
GET_UNIPERIF_REG(ip, \
UNIPERIF_CTRL_OFFSET(ip), \
UNIPERIF_CTRL_DIVIDER_SHIFT(ip), \
UNIPERIF_CTRL_DIVIDER_MASK(ip))
#define SET_UNIPERIF_CTRL_DIVIDER(ip, value) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_CTRL_OFFSET(ip), \
UNIPERIF_CTRL_DIVIDER_SHIFT(ip), \
UNIPERIF_CTRL_DIVIDER_MASK(ip), value)
/* BYTE_SWAP */
#define UNIPERIF_CTRL_BYTE_SWP_SHIFT(ip) \
((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 13 : -1)
#define UNIPERIF_CTRL_BYTE_SWP_MASK(ip) 0x1
#define GET_UNIPERIF_CTRL_BYTE_SWP(ip) \
GET_UNIPERIF_REG(ip, \
UNIPERIF_CTRL_OFFSET(ip), \
UNIPERIF_CTRL_BYTE_SWP_SHIFT(ip), \
UNIPERIF_CTRL_BYTE_SWP_MASK(ip))
#define SET_UNIPERIF_CTRL_BYTE_SWP_OFF(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_CTRL_OFFSET(ip), \
UNIPERIF_CTRL_BYTE_SWP_SHIFT(ip), \
UNIPERIF_CTRL_BYTE_SWP_MASK(ip), 0)
#define SET_UNIPERIF_CTRL_BYTE_SWP_ON(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_CTRL_OFFSET(ip), \
UNIPERIF_CTRL_BYTE_SWP_SHIFT(ip), \
UNIPERIF_CTRL_BYTE_SWP_MASK(ip), 1)
/* ZERO_STUFFING_HW_SW */
#define UNIPERIF_CTRL_ZERO_STUFF_SHIFT(ip) \
((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 14 : -1)
#define UNIPERIF_CTRL_ZERO_STUFF_MASK(ip) 0x1
#define GET_UNIPERIF_CTRL_ZERO_STUFF(ip) \
GET_UNIPERIF_REG(ip, \
UNIPERIF_CTRL_OFFSET(ip), \
UNIPERIF_CTRL_ZERO_STUFF_SHIFT(ip), \
UNIPERIF_CTRL_ZERO_STUFF_MASK(ip))
#define SET_UNIPERIF_CTRL_ZERO_STUFF_HW(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_CTRL_OFFSET(ip), \
UNIPERIF_CTRL_ZERO_STUFF_SHIFT(ip), \
UNIPERIF_CTRL_ZERO_STUFF_MASK(ip), 1)
#define SET_UNIPERIF_CTRL_ZERO_STUFF_SW(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_CTRL_OFFSET(ip), \
UNIPERIF_CTRL_ZERO_STUFF_SHIFT(ip), \
UNIPERIF_CTRL_ZERO_STUFF_MASK(ip), 0)
/* SPDIF_LAT */
#define UNIPERIF_CTRL_SPDIF_LAT_SHIFT(ip) \
((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 16 : -1)
#define UNIPERIF_CTRL_SPDIF_LAT_MASK(ip) 0x1
#define GET_UNIPERIF_CTRL_SPDIF_LAT(ip) \
GET_UNIPERIF_REG(ip, \
UNIPERIF_CTRL_OFFSET(ip), \
UNIPERIF_CTRL_SPDIF_LAT_SHIFT(ip), \
UNIPERIF_CTRL_SPDIF_LAT_MASK(ip))
#define SET_UNIPERIF_CTRL_SPDIF_LAT_ON(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_CTRL_OFFSET(ip), \
UNIPERIF_CTRL_SPDIF_LAT_SHIFT(ip), \
UNIPERIF_CTRL_SPDIF_LAT_MASK(ip), 1)
#define SET_UNIPERIF_CTRL_SPDIF_LAT_OFF(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_CTRL_OFFSET(ip), \
UNIPERIF_CTRL_SPDIF_LAT_SHIFT(ip), \
UNIPERIF_CTRL_SPDIF_LAT_MASK(ip), 0)
/* EN_SPDIF_FORMATTING */
#define UNIPERIF_CTRL_SPDIF_FMT_SHIFT(ip) 17
#define UNIPERIF_CTRL_SPDIF_FMT_MASK(ip) 0x1
#define GET_UNIPERIF_CTRL_SPDIF_FMT(ip) \
GET_UNIPERIF_REG(ip, \
UNIPERIF_CTRL_OFFSET(ip), \
UNIPERIF_CTRL_SPDIF_FMT_SHIFT(ip), \
UNIPERIF_CTRL_SPDIF_FMT_MASK(ip))
#define SET_UNIPERIF_CTRL_SPDIF_FMT_ON(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_CTRL_OFFSET(ip), \
UNIPERIF_CTRL_SPDIF_FMT_SHIFT(ip), \
UNIPERIF_CTRL_SPDIF_FMT_MASK(ip), 1)
#define SET_UNIPERIF_CTRL_SPDIF_FMT_OFF(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_CTRL_OFFSET(ip), \
UNIPERIF_CTRL_SPDIF_FMT_SHIFT(ip), \
UNIPERIF_CTRL_SPDIF_FMT_MASK(ip), 0)
/* READER_OUT_SELECT */
#define UNIPERIF_CTRL_READER_OUT_SEL_SHIFT(ip) \
((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 18 : -1)
#define UNIPERIF_CTRL_READER_OUT_SEL_MASK(ip) 0x1
#define GET_UNIPERIF_CTRL_READER_OUT_SEL(ip) \
GET_UNIPERIF_REG(ip, \
UNIPERIF_CTRL_OFFSET(ip), \
UNIPERIF_CTRL_READER_OUT_SEL_SHIFT(ip), \
UNIPERIF_CTRL_READER_OUT_SEL_MASK(ip))
#define SET_UNIPERIF_CTRL_READER_OUT_SEL_IN_MEM(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_CTRL_OFFSET(ip), \
UNIPERIF_CTRL_READER_OUT_SEL_SHIFT(ip), \
UNIPERIF_CTRL_READER_OUT_SEL_MASK(ip), 0)
#define SET_UNIPERIF_CTRL_READER_OUT_SEL_ON_I2S_LINE(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_CTRL_OFFSET(ip), \
UNIPERIF_CTRL_READER_OUT_SEL_SHIFT(ip), \
CORAUD_UNIPERIF_CTRL_READER_OUT_SEL_MASK(ip), 1)
/* UNDERFLOW_REC_WINDOW */
#define UNIPERIF_CTRL_UNDERFLOW_REC_WINDOW_SHIFT(ip) 20
#define UNIPERIF_CTRL_UNDERFLOW_REC_WINDOW_MASK(ip) 0xff
#define GET_UNIPERIF_CTRL_UNDERFLOW_REC_WINDOW(ip) \
GET_UNIPERIF_REG(ip, \
UNIPERIF_CTRL_OFFSET(ip), \
UNIPERIF_CTRL_UNDERFLOW_REC_WINDOW_SHIFT(ip), \
UNIPERIF_CTRL_UNDERFLOW_REC_WINDOW_MASK(ip))
#define SET_UNIPERIF_CTRL_UNDERFLOW_REC_WINDOW(ip, value) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_CTRL_OFFSET(ip), \
UNIPERIF_CTRL_UNDERFLOW_REC_WINDOW_SHIFT(ip), \
UNIPERIF_CTRL_UNDERFLOW_REC_WINDOW_MASK(ip), value)
/*
* UNIPERIF_I2S_FMT a.k.a UNIPERIF_FORMAT reg
*/
#define UNIPERIF_I2S_FMT_OFFSET(ip) 0x0048
#define GET_UNIPERIF_I2S_FMT(ip) \
readl_relaxed(ip->base + UNIPERIF_I2S_FMT_OFFSET(ip))
#define SET_UNIPERIF_I2S_FMT(ip, value) \
writel_relaxed(value, ip->base + UNIPERIF_I2S_FMT_OFFSET(ip))
/* NBIT */
#define UNIPERIF_I2S_FMT_NBIT_SHIFT(ip) 0
#define UNIPERIF_I2S_FMT_NBIT_MASK(ip) 0x1
#define GET_UNIPERIF_I2S_FMT_NBIT(ip) \
GET_UNIPERIF_REG(ip, \
UNIPERIF_I2S_FMT_OFFSET(ip), \
UNIPERIF_I2S_FMT_NBIT_SHIFT(ip), \
UNIPERIF_I2S_FMT_NBIT_MASK(ip))
#define SET_UNIPERIF_I2S_FMT_NBIT_32(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_I2S_FMT_OFFSET(ip), \
UNIPERIF_I2S_FMT_NBIT_SHIFT(ip), \
UNIPERIF_I2S_FMT_NBIT_MASK(ip), 0)
#define SET_UNIPERIF_I2S_FMT_NBIT_16(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_I2S_FMT_OFFSET(ip), \
UNIPERIF_I2S_FMT_NBIT_SHIFT(ip), \
UNIPERIF_I2S_FMT_NBIT_MASK(ip), 1)
/* DATA_SIZE */
#define UNIPERIF_I2S_FMT_DATA_SIZE_SHIFT(ip) 1
#define UNIPERIF_I2S_FMT_DATA_SIZE_MASK(ip) 0x7
#define GET_UNIPERIF_I2S_FMT_DATA_SIZE(ip) \
GET_UNIPERIF_REG(ip, \
UNIPERIF_I2S_FMT_OFFSET(ip), \
UNIPERIF_I2S_FMT_DATA_SIZE_SHIFT(ip), \
UNIPERIF_I2S_FMT_DATA_SIZE_MASK(ip))
#define SET_UNIPERIF_I2S_FMT_DATA_SIZE_16(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_I2S_FMT_OFFSET(ip), \
UNIPERIF_I2S_FMT_DATA_SIZE_SHIFT(ip), \
UNIPERIF_I2S_FMT_DATA_SIZE_MASK(ip), 0)
#define SET_UNIPERIF_I2S_FMT_DATA_SIZE_18(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_I2S_FMT_OFFSET(ip), \
UNIPERIF_I2S_FMT_DATA_SIZE_SHIFT(ip), \
UNIPERIF_I2S_FMT_DATA_SIZE_MASK(ip), 1)
#define SET_UNIPERIF_I2S_FMT_DATA_SIZE_20(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_I2S_FMT_OFFSET(ip), \
UNIPERIF_I2S_FMT_DATA_SIZE_SHIFT(ip), \
UNIPERIF_I2S_FMT_DATA_SIZE_MASK(ip), 2)
#define SET_UNIPERIF_I2S_FMT_DATA_SIZE_24(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_I2S_FMT_OFFSET(ip), \
UNIPERIF_I2S_FMT_DATA_SIZE_SHIFT(ip), \
UNIPERIF_I2S_FMT_DATA_SIZE_MASK(ip), 3)
#define SET_UNIPERIF_I2S_FMTL_DATA_SIZE_28(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_I2S_FMT_OFFSET(ip), \
UNIPERIF_I2S_FMT_DATA_SIZE_SHIFT(ip), \
UNIPERIF_I2S_FMT_DATA_SIZE_MASK(ip), 4)
#define SET_UNIPERIF_I2S_FMT_DATA_SIZE_32(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_I2S_FMT_OFFSET(ip), \
UNIPERIF_I2S_FMT_DATA_SIZE_SHIFT(ip), \
UNIPERIF_I2S_FMT_DATA_SIZE_MASK(ip), 5)
/* LR_POL */
#define UNIPERIF_I2S_FMT_LR_POL_SHIFT(ip) 4
#define UNIPERIF_I2S_FMT_LR_POL_MASK(ip) 0x1
#define VALUE_UNIPERIF_I2S_FMT_LR_POL_LOW(ip) 0x0
#define VALUE_UNIPERIF_I2S_FMT_LR_POL_HIG(ip) 0x1
#define GET_UNIPERIF_I2S_FMT_LR_POL(ip) \
GET_UNIPERIF_REG(ip, \
UNIPERIF_I2S_FMT_OFFSET(ip), \
UNIPERIF_I2S_FMT_LR_POL_SHIFT(ip), \
UNIPERIF_I2S_FMT_LR_POL_MASK(ip))
#define SET_UNIPERIF_I2S_FMT_LR_POL(ip, value) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_I2S_FMT_OFFSET(ip), \
UNIPERIF_I2S_FMT_LR_POL_SHIFT(ip), \
UNIPERIF_I2S_FMT_LR_POL_MASK(ip), value)
#define SET_UNIPERIF_I2S_FMT_LR_POL_LOW(ip) \
SET_UNIPERIF_I2S_FMT_LR_POL(ip, \
VALUE_UNIPERIF_I2S_FMT_LR_POL_LOW(ip))
#define SET_UNIPERIF_I2S_FMT_LR_POL_HIG(ip) \
SET_UNIPERIF_I2S_FMT_LR_POL(ip, \
VALUE_UNIPERIF_I2S_FMT_LR_POL_HIG(ip))
/* SCLK_EDGE */
#define UNIPERIF_I2S_FMT_SCLK_EDGE_SHIFT(ip) 5
#define UNIPERIF_I2S_FMT_SCLK_EDGE_MASK(ip) 0x1
#define GET_UNIPERIF_I2S_FMT_SCLK_EDGE(ip) \
GET_UNIPERIF_REG(ip, \
UNIPERIF_I2S_FMT_OFFSET(ip), \
UNIPERIF_I2S_FMT_SCLK_EDGE_SHIFT(ip), \
UNIPERIF_I2S_FMT_SCLK_EDGE_MASK(ip))
#define SET_UNIPERIF_I2S_FMT_SCLK_EDGE_RISING(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_I2S_FMT_OFFSET(ip), \
UNIPERIF_I2S_FMT_SCLK_EDGE_SHIFT(ip), \
UNIPERIF_I2S_FMT_SCLK_EDGE_MASK(ip), 0)
#define SET_UNIPERIF_I2S_FMT_SCLK_EDGE_FALLING(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_I2S_FMT_OFFSET(ip), \
UNIPERIF_I2S_FMT_SCLK_EDGE_SHIFT(ip), \
UNIPERIF_I2S_FMT_SCLK_EDGE_MASK(ip), 1)
/* PADDING */
#define UNIPERIF_I2S_FMT_PADDING_SHIFT(ip) 6
#define UNIPERIF_I2S_FMT_PADDING_MASK(ip) 0x1
#define UNIPERIF_I2S_FMT_PADDING_MASK(ip) 0x1
#define VALUE_UNIPERIF_I2S_FMT_PADDING_I2S_MODE(ip) 0x0
#define VALUE_UNIPERIF_I2S_FMT_PADDING_SONY_MODE(ip) 0x1
#define GET_UNIPERIF_I2S_FMT_PADDING(ip) \
GET_UNIPERIF_REG(ip, \
UNIPERIF_I2S_FMT_OFFSET(ip), \
UNIPERIF_I2S_FMT_PADDING_SHIFT(ip), \
UNIPERIF_I2S_FMT_PADDING_MASK(ip))
#define SET_UNIPERIF_I2S_FMT_PADDING(ip, value) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_I2S_FMT_OFFSET(ip), \
UNIPERIF_I2S_FMT_PADDING_SHIFT(ip), \
UNIPERIF_I2S_FMT_PADDING_MASK(ip), value)
#define SET_UNIPERIF_I2S_FMT_PADDING_I2S_MODE(ip) \
SET_UNIPERIF_I2S_FMT_PADDING(ip, \
VALUE_UNIPERIF_I2S_FMT_PADDING_I2S_MODE(ip))
#define SET_UNIPERIF_I2S_FMT_PADDING_SONY_MODE(ip) \
SET_UNIPERIF_I2S_FMT_PADDING(ip, \
VALUE_UNIPERIF_I2S_FMT_PADDING_SONY_MODE(ip))
/* ALIGN */
#define UNIPERIF_I2S_FMT_ALIGN_SHIFT(ip) 7
#define UNIPERIF_I2S_FMT_ALIGN_MASK(ip) 0x1
#define GET_UNIPERIF_I2S_FMT_ALIGN(ip) \
GET_UNIPERIF_REG(ip, \
UNIPERIF_I2S_FMT_OFFSET(ip), \
UNIPERIF_I2S_FMT_ALIGN_SHIFT(ip), \
UNIPERIF_I2S_FMT_ALIGN_MASK(ip))
#define SET_UNIPERIF_I2S_FMT_ALIGN_LEFT(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_I2S_FMT_OFFSET(ip), \
UNIPERIF_I2S_FMT_ALIGN_SHIFT(ip), \
UNIPERIF_I2S_FMT_ALIGN_MASK(ip), 0)
#define SET_UNIPERIF_I2S_FMT_ALIGN_RIGHT(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_I2S_FMT_OFFSET(ip), \
UNIPERIF_I2S_FMT_ALIGN_SHIFT(ip), \
UNIPERIF_I2S_FMT_ALIGN_MASK(ip), 1)
/* ORDER */
#define UNIPERIF_I2S_FMT_ORDER_SHIFT(ip) 8
#define UNIPERIF_I2S_FMT_ORDER_MASK(ip) 0x1
#define GET_UNIPERIF_I2S_FMT_ORDER(ip) \
GET_UNIPERIF_REG(ip, \
UNIPERIF_I2S_FMT_OFFSET(ip), \
UNIPERIF_I2S_FMT_ORDER_SHIFT(ip), \
UNIPERIF_I2S_FMT_ORDER_MASK(ip))
#define SET_UNIPERIF_I2S_FMT_ORDER_LSB(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_I2S_FMT_OFFSET(ip), \
UNIPERIF_I2S_FMT_ORDER_SHIFT(ip), \
UNIPERIF_I2S_FMT_ORDER_MASK(ip), 0)
#define SET_UNIPERIF_I2S_FMT_ORDER_MSB(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_I2S_FMT_OFFSET(ip), \
UNIPERIF_I2S_FMT_ORDER_SHIFT(ip), \
UNIPERIF_I2S_FMT_ORDER_MASK(ip), 1)
/* NUM_CH */
#define UNIPERIF_I2S_FMT_NUM_CH_SHIFT(ip) 9
#define UNIPERIF_I2S_FMT_NUM_CH_MASK(ip) 0x7
#define GET_UNIPERIF_I2S_FMT_NUM_CH(ip) \
GET_UNIPERIF_REG(ip, \
UNIPERIF_I2S_FMT_OFFSET(ip), \
UNIPERIF_I2S_FMT_NUM_CH_SHIFT(ip), \
UNIPERIF_I2S_FMT_NUM_CH_MASK(ip))
#define SET_UNIPERIF_I2S_FMT_NUM_CH(ip, value) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_I2S_FMT_OFFSET(ip), \
UNIPERIF_I2S_FMT_NUM_CH_SHIFT(ip), \
UNIPERIF_I2S_FMT_NUM_CH_MASK(ip), value)
/* NO_OF_SAMPLES_TO_READ */
#define UNIPERIF_I2S_FMT_NO_OF_SAMPLES_TO_READ_SHIFT(ip) 12
#define UNIPERIF_I2S_FMT_NO_OF_SAMPLES_TO_READ_MASK(ip) 0xfffff
#define GET_UNIPERIF_I2S_FMT_NO_OF_SAMPLES_TO_READ(ip) \
GET_UNIPERIF_REG(ip, \
UNIPERIF_I2S_FMT_OFFSET(ip), \
UNIPERIF_I2S_FMT_NO_OF_SAMPLES_TO_READ_SHIFT(ip), \
UNIPERIF_I2S_FMT_NO_OF_SAMPLES_TO_READ_MASK(ip))
#define SET_UNIPERIF_I2S_FMT_NO_OF_SAMPLES_TO_READ(ip, value) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_I2S_FMT_OFFSET(ip), \
UNIPERIF_I2S_FMT_NO_OF_SAMPLES_TO_READ_SHIFT(ip), \
UNIPERIF_I2S_FMT_NO_OF_SAMPLES_TO_READ_MASK(ip), value)
/*
* UNIPERIF_BIT_CONTROL reg
*/
#define UNIPERIF_BIT_CONTROL_OFFSET(ip) \
((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? -1 : 0x004c)
#define GET_UNIPERIF_BIT_CONTROL(ip) \
readl_relaxed(ip->base + UNIPERIF_BIT_CONTROL_OFFSET(ip))
#define SET_UNIPERIF_BIT_CONTROL(ip, value) \
writel_relaxed(value, ip->base + UNIPERIF_BIT_CONTROL_OFFSET(ip))
/* CLR_UNDERFLOW_DURATION */
#define UNIPERIF_BIT_CONTROL_CLR_UNDERFLOW_DURATION_SHIFT(ip) 0
#define UNIPERIF_BIT_CONTROL_CLR_UNDERFLOW_DURATION_MASK(ip) 0x1
#define GET_UNIPERIF_BIT_CONTROL_CLR_UNDERFLOW_DURATION(ip) \
GET_UNIPERIF_REG(ip, \
UNIPERIF_BIT_CONTROL_OFFSET(ip), \
UNIPERIF_BIT_CONTROL_CLR_UNDERFLOW_DURATION_SHIFT(ip), \
UNIPERIF_BIT_CONTROL_CLR_UNDERFLOW_DURATION_MASK(ip))
#define SET_UNIPERIF_BIT_CONTROL_CLR_UNDERFLOW_DURATION(ip) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_BIT_CONTROL_OFFSET(ip), \
UNIPERIF_BIT_CONTROL_CLR_UNDERFLOW_DURATION_SHIFT(ip), \
UNIPERIF_BIT_CONTROL_CLR_UNDERFLOW_DURATION_MASK(ip), 1)
/* CHL_STS_UPDATE */
#define UNIPERIF_BIT_CONTROL_CHL_STS_UPDATE_SHIFT(ip) 1
#define UNIPERIF_BIT_CONTROL_CHL_STS_UPDATE_MASK(ip) 0x1
#define GET_UNIPERIF_BIT_CONTROL_CHL_STS_UPDATE(ip) \
GET_UNIPERIF_REG(ip, \
UNIPERIF_BIT_CONTROL_OFFSET(ip), \
UNIPERIF_BIT_CONTROL_CHL_STS_UPDATE_SHIFT(ip), \
UNIPERIF_BIT_CONTROL_CHL_STS_UPDATE_MASK(ip))
#define SET_UNIPERIF_BIT_CONTROL_CHL_STS_UPDATE(ip) \
SET_UNIPERIF_BIT_REG(ip, \
UNIPERIF_BIT_CONTROL_OFFSET(ip), \
UNIPERIF_BIT_CONTROL_CHL_STS_UPDATE_SHIFT(ip), \
UNIPERIF_BIT_CONTROL_CHL_STS_UPDATE_MASK(ip), 1)
/*
* UNIPERIF_STATUS_1 reg
*/
#define UNIPERIF_STATUS_1_OFFSET(ip) 0x0050
#define GET_UNIPERIF_STATUS_1(ip) \
readl_relaxed(ip->base + UNIPERIF_STATUS_1_OFFSET(ip))
#define SET_UNIPERIF_STATUS_1(ip, value) \
writel_relaxed(value, ip->base + UNIPERIF_STATUS_1_OFFSET(ip))
/* UNDERFLOW_DURATION */
#define UNIPERIF_STATUS_1_UNDERFLOW_DURATION_SHIFT(ip) \
((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? -1 : 0)
#define UNIPERIF_STATUS_1_UNDERFLOW_DURATION_MASK(ip) 0xff
#define GET_UNIPERIF_STATUS_1_UNDERFLOW_DURATION(ip) \
GET_UNIPERIF_REG(ip, \
UNIPERIF_STATUS_1_OFFSET(ip), \
UNIPERIF_STATUS_1_UNDERFLOW_DURATION_SHIFT(ip), \
UNIPERIF_STATUS_1_UNDERFLOW_DURATION_MASK(ip))
#define SET_UNIPERIF_STATUS_1_UNDERFLOW_DURATION(ip, value) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_STATUS_1_OFFSET(ip), \
UNIPERIF_STATUS_1_UNDERFLOW_DURATION_SHIFT(ip), \
UNIPERIF_STATUS_1_UNDERFLOW_DURATION_MASK(ip), value)
/*
* AUD_UNIPERIF_CHANNEL_STA_REGN reg
*/
#define UNIPERIF_CHANNEL_STA_REGN(ip, n) (0x0060 + (4 * n))
#define GET_UNIPERIF_CHANNEL_STA_REGN(ip) \
readl_relaxed(ip->base + UNIPERIF_CHANNEL_STA_REGN(ip, n))
#define SET_UNIPERIF_CHANNEL_STA_REGN(ip, n, value) \
writel_relaxed(value, ip->base + \
UNIPERIF_CHANNEL_STA_REGN(ip, n))
/*
* AUD_UNIPERIF_USER_VALIDITY reg
*/
#define UNIPERIF_USER_VALIDITY_OFFSET(ip) 0x0090
#define GET_UNIPERIF_USER_VALIDITY(ip) \
readl_relaxed(ip->base + UNIPERIF_USER_VALIDITY_OFFSET(ip))
#define SET_UNIPERIF_USER_VALIDITY(ip, value) \
writel_relaxed(value, ip->base + UNIPERIF_USER_VALIDITY_OFFSET(ip))
/* VALIDITY_LEFT_AND_RIGHT */
#define UNIPERIF_USER_VALIDITY_VALIDITY_LR_SHIFT(ip) 0
#define UNIPERIF_USER_VALIDITY_VALIDITY_LR_MASK(ip) 0x3
#define GET_UNIPERIF_USER_VALIDITY_VALIDITY_LR(ip) \
GET_UNIPERIF_REG(ip, \
UNIPERIF_USER_VALIDITY_OFFSET(ip), \
UNIPERIF_USER_VALIDITY_VALIDITY_LR_SHIFT(ip), \
UNIPERIF_USER_VALIDITY_VALIDITY_LR_MASK(ip))
#define SET_UNIPERIF_USER_VALIDITY_VALIDITY_LR(ip, value) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_USER_VALIDITY_OFFSET(ip), \
UNIPERIF_USER_VALIDITY_VALIDITY_LR_SHIFT(ip), \
UNIPERIF_USER_VALIDITY_VALIDITY_LR_MASK(ip), \
value ? 0x3 : 0)
/*
* UNIPERIF_DBG_STANDBY_LEFT_SP reg
*/
#define UNIPERIF_DBG_STANDBY_LEFT_SP_OFFSET(ip) 0x0150
#define UNIPERIF_DBG_STANDBY_LEFT_SP_SHIFT(ip) \
((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? -1 : 0)
#define UNIPERIF_DBG_STANDBY_LEFT_SP_MASK(ip) \
((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 0 : 0xFFFFFF)
#define GET_UNIPERIF_DBG_STANDBY_LEFT_SP(ip) \
GET_UNIPERIF_REG(ip, \
UNIPERIF_DBG_STANDBY_LEFT_SP_OFFSET(ip), \
UNIPERIF_DBG_STANDBY_LEFT_SP_SHIFT(ip), \
UNIPERIF_DBG_STANDBY_LEFT_SP_MASK(ip))
#define SET_UNIPERIF_DBG_STANDBY_LEFT_SP(ip, value) \
SET_UNIPERIF_REG(ip, \
UNIPERIF_DBG_STANDBY_LEFT_SP_OFFSET(ip), \
UNIPERIF_DBG_STANDBY_LEFT_SP_SHIFT(ip), \
UNIPERIF_DBG_STANDBY_LEFT_SP_MASK(ip), value)
/*
* uniperipheral IP capabilities
*/
#define UNIPERIF_FIFO_SIZE 70 /* FIFO is 70 cells deep */
#define UNIPERIF_FIFO_FRAMES 4 /* FDMA trigger limit in frames */
/*
* Uniperipheral IP revisions
*/
enum uniperif_version {
SND_ST_UNIPERIF_VERSION_UNKNOWN,
/* SASG1 (Orly), Newman */
SND_ST_UNIPERIF_VERSION_C6AUD0_UNI_1_0,
/* SASC1, SASG2 (Orly2) */
SND_ST_UNIPERIF_VERSION_UNI_PLR_1_0,
/* SASC1, SASG2 (Orly2), TELSS, Cannes */
SND_ST_UNIPERIF_VERSION_UNI_RDR_1_0,
/* TELSS (SASC1) */
SND_ST_UNIPERIF_VERSION_TDM_PLR_1_0,
/* Cannes/Monaco */
SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0
};
enum uniperif_type {
SND_ST_UNIPERIF_PLAYER_TYPE_NONE,
SND_ST_UNIPERIF_PLAYER_TYPE_HDMI,
SND_ST_UNIPERIF_PLAYER_TYPE_PCM,
SND_ST_UNIPERIF_PLAYER_TYPE_SPDIF
};
enum uniperif_state {
UNIPERIF_STATE_STOPPED,
UNIPERIF_STATE_STARTED,
UNIPERIF_STATE_STANDBY,
UNIPERIF_STATE_UNDERFLOW,
UNIPERIF_STATE_OVERFLOW = UNIPERIF_STATE_UNDERFLOW,
UNIPERIF_STATE_XRUN
};
enum uniperif_iec958_encoding_mode {
UNIPERIF_IEC958_ENCODING_MODE_PCM,
UNIPERIF_IEC958_ENCODING_MODE_ENCODED
};
struct uniperif_info {
int id; /* instance value of the uniperipheral IP */
enum uniperif_type player_type;
int underflow_enabled; /* Underflow recovery mode */
};
struct uniperif_iec958_settings {
enum uniperif_iec958_encoding_mode encoding_mode;
struct snd_aes_iec958 iec958;
};
struct uniperif {
/* System information */
struct uniperif_info *info;
struct device *dev;
int ver; /* IP version, used by register access macros */
struct regmap_field *clk_sel;
/* capabilities */
const struct snd_pcm_hardware *hw;
/* Resources */
struct resource *mem_region;
void __iomem *base;
unsigned long fifo_phys_address;
int irq;
/* Clocks */
struct clk *clk;
int mclk;
int clk_adj;
/* Runtime data */
enum uniperif_state state;
struct snd_pcm_substream *substream;
/* Specific to IEC958 player */
struct uniperif_iec958_settings stream_settings;
struct mutex ctrl_lock; /* For resource updated by stream and controls*/
/*alsa ctrl*/
struct snd_kcontrol_new *snd_ctrls;
int num_ctrls;
/* dai properties */
unsigned int daifmt;
/* DAI callbacks */
const struct snd_soc_dai_ops *dai_ops;
};
struct sti_uniperiph_dai {
int stream;
struct uniperif *uni;
struct snd_dmaengine_dai_dma_data dma_data;
};
struct sti_uniperiph_data {
struct platform_device *pdev;
struct snd_soc_dai_driver *dai;
struct sti_uniperiph_dai dai_data;
};
/* uniperiph player*/
int uni_player_init(struct platform_device *pdev,
struct uniperif *uni_player);
int uni_player_resume(struct uniperif *player);
/* uniperiph reader */
int uni_reader_init(struct platform_device *pdev,
struct uniperif *uni_reader);
/* common */
int sti_uniperiph_dai_set_fmt(struct snd_soc_dai *dai,
unsigned int fmt);
int sti_uniperiph_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai);
#endif
/*
* Copyright (C) STMicroelectronics SA 2015
* Authors: Arnaud Pouliquen <arnaud.pouliquen@st.com>
* for STMicroelectronics.
* License terms: GNU General Public License (GPL), version 2
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/mfd/syscon.h>
#include <sound/asoundef.h>
#include <sound/soc.h>
#include "uniperif.h"
/*
* Some hardware-related definitions
*/
/* sys config registers definitions */
#define SYS_CFG_AUDIO_GLUE 0xA4
#define SYS_CFG_AUDI0_GLUE_PCM_CLKX 8
/*
* Driver specific types.
*/
#define UNIPERIF_PLAYER_TYPE_IS_HDMI(p) \
((p)->info->player_type == SND_ST_UNIPERIF_PLAYER_TYPE_HDMI)
#define UNIPERIF_PLAYER_TYPE_IS_PCM(p) \
((p)->info->player_type == SND_ST_UNIPERIF_PLAYER_TYPE_PCM)
#define UNIPERIF_PLAYER_TYPE_IS_SPDIF(p) \
((p)->info->player_type == SND_ST_UNIPERIF_PLAYER_TYPE_SPDIF)
#define UNIPERIF_PLAYER_TYPE_IS_IEC958(p) \
(UNIPERIF_PLAYER_TYPE_IS_HDMI(p) || \
UNIPERIF_PLAYER_TYPE_IS_SPDIF(p))
#define UNIPERIF_PLAYER_CLK_ADJ_MIN -999999
#define UNIPERIF_PLAYER_CLK_ADJ_MAX 1000000
/*
* Note: snd_pcm_hardware is linked to DMA controller but is declared here to
* integrate DAI_CPU capability in term of rate and supported channels
*/
static const struct snd_pcm_hardware uni_player_pcm_hw = {
.info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID,
.formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE,
.rates = SNDRV_PCM_RATE_CONTINUOUS,
.rate_min = 8000,
.rate_max = 192000,
.channels_min = 2,
.channels_max = 8,
.periods_min = 2,
.periods_max = 48,
.period_bytes_min = 128,
.period_bytes_max = 64 * PAGE_SIZE,
.buffer_bytes_max = 256 * PAGE_SIZE
};
static inline int reset_player(struct uniperif *player)
{
int count = 10;
if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) {
while (GET_UNIPERIF_SOFT_RST_SOFT_RST(player) && count) {
udelay(5);
count--;
}
}
if (!count) {
dev_err(player->dev, "Failed to reset uniperif");
return -EIO;
}
return 0;
}
/*
* uni_player_irq_handler
* In case of error audio stream is stopped; stop action is protected via PCM
* stream lock to avoid race condition with trigger callback.
*/
static irqreturn_t uni_player_irq_handler(int irq, void *dev_id)
{
irqreturn_t ret = IRQ_NONE;
struct uniperif *player = dev_id;
unsigned int status;
unsigned int tmp;
if (player->state == UNIPERIF_STATE_STOPPED) {
/* Unexpected IRQ: do nothing */
return IRQ_NONE;
}
/* Get interrupt status & clear them immediately */
status = GET_UNIPERIF_ITS(player);
SET_UNIPERIF_ITS_BCLR(player, status);
/* Check for fifo error (underrun) */
if (unlikely(status & UNIPERIF_ITS_FIFO_ERROR_MASK(player))) {
dev_err(player->dev, "FIFO underflow error detected");
/* Interrupt is just for information when underflow recovery */
if (player->info->underflow_enabled) {
/* Update state to underflow */
player->state = UNIPERIF_STATE_UNDERFLOW;
} else {
/* Disable interrupt so doesn't continually fire */
SET_UNIPERIF_ITM_BCLR_FIFO_ERROR(player);
/* Stop the player */
snd_pcm_stream_lock(player->substream);
snd_pcm_stop(player->substream, SNDRV_PCM_STATE_XRUN);
snd_pcm_stream_unlock(player->substream);
}
ret = IRQ_HANDLED;
}
/* Check for dma error (overrun) */
if (unlikely(status & UNIPERIF_ITS_DMA_ERROR_MASK(player))) {
dev_err(player->dev, "DMA error detected");
/* Disable interrupt so doesn't continually fire */
SET_UNIPERIF_ITM_BCLR_DMA_ERROR(player);
/* Stop the player */
snd_pcm_stream_lock(player->substream);
snd_pcm_stop(player->substream, SNDRV_PCM_STATE_XRUN);
snd_pcm_stream_unlock(player->substream);
ret = IRQ_HANDLED;
}
/* Check for underflow recovery done */
if (unlikely(status & UNIPERIF_ITM_UNDERFLOW_REC_DONE_MASK(player))) {
if (!player->info->underflow_enabled) {
dev_err(player->dev, "unexpected Underflow recovering");
return -EPERM;
}
/* Read the underflow recovery duration */
tmp = GET_UNIPERIF_STATUS_1_UNDERFLOW_DURATION(player);
/* Clear the underflow recovery duration */
SET_UNIPERIF_BIT_CONTROL_CLR_UNDERFLOW_DURATION(player);
/* Update state to started */
player->state = UNIPERIF_STATE_STARTED;
ret = IRQ_HANDLED;
}
/* Check if underflow recovery failed */
if (unlikely(status &
UNIPERIF_ITM_UNDERFLOW_REC_FAILED_MASK(player))) {
dev_err(player->dev, "Underflow recovery failed");
/* Stop the player */
snd_pcm_stream_lock(player->substream);
snd_pcm_stop(player->substream, SNDRV_PCM_STATE_XRUN);
snd_pcm_stream_unlock(player->substream);
ret = IRQ_HANDLED;
}
return ret;
}
static int uni_player_clk_set_rate(struct uniperif *player, unsigned long rate)
{
int rate_adjusted, rate_achieved, delta, ret;
int adjustment = player->clk_adj;
/*
* a
* F = f + --------- * f = f + d
* 1000000
*
* a
* d = --------- * f
* 1000000
*
* where:
* f - nominal rate
* a - adjustment in ppm (parts per milion)
* F - rate to be set in synthesizer
* d - delta (difference) between f and F
*/
if (adjustment < 0) {
/* div64_64 operates on unsigned values... */
delta = -1;
adjustment = -adjustment;
} else {
delta = 1;
}
/* 500000 ppm is 0.5, which is used to round up values */
delta *= (int)div64_u64((uint64_t)rate *
(uint64_t)adjustment + 500000, 1000000);
rate_adjusted = rate + delta;
/* Adjusted rate should never be == 0 */
if (!rate_adjusted)
return -EINVAL;
ret = clk_set_rate(player->clk, rate_adjusted);
if (ret < 0)
return ret;
rate_achieved = clk_get_rate(player->clk);
if (!rate_achieved)
/* If value is 0 means that clock or parent not valid */
return -EINVAL;
/*
* Using ALSA's adjustment control, we can modify the rate to be up
* to twice as much as requested, but no more
*/
delta = rate_achieved - rate;
if (delta < 0) {
/* div64_64 operates on unsigned values... */
delta = -delta;
adjustment = -1;
} else {
adjustment = 1;
}
/* Frequency/2 is added to round up result */
adjustment *= (int)div64_u64((uint64_t)delta * 1000000 + rate / 2,
rate);
player->clk_adj = adjustment;
return 0;
}
static void uni_player_set_channel_status(struct uniperif *player,
struct snd_pcm_runtime *runtime)
{
int n;
unsigned int status;
/*
* Some AVRs and TVs require the channel status to contain a correct
* sampling frequency. If no sample rate is already specified, then
* set one.
*/
mutex_lock(&player->ctrl_lock);
if (runtime && (player->stream_settings.iec958.status[3]
== IEC958_AES3_CON_FS_NOTID)) {
switch (runtime->rate) {
case 22050:
player->stream_settings.iec958.status[3] =
IEC958_AES3_CON_FS_22050;
break;
case 44100:
player->stream_settings.iec958.status[3] =
IEC958_AES3_CON_FS_44100;
break;
case 88200:
player->stream_settings.iec958.status[3] =
IEC958_AES3_CON_FS_88200;
break;
case 176400:
player->stream_settings.iec958.status[3] =
IEC958_AES3_CON_FS_176400;
break;
case 24000:
player->stream_settings.iec958.status[3] =
IEC958_AES3_CON_FS_24000;
break;
case 48000:
player->stream_settings.iec958.status[3] =
IEC958_AES3_CON_FS_48000;
break;
case 96000:
player->stream_settings.iec958.status[3] =
IEC958_AES3_CON_FS_96000;
break;
case 192000:
player->stream_settings.iec958.status[3] =
IEC958_AES3_CON_FS_192000;
break;
case 32000:
player->stream_settings.iec958.status[3] =
IEC958_AES3_CON_FS_32000;
break;
default:
/* Mark as sampling frequency not indicated */
player->stream_settings.iec958.status[3] =
IEC958_AES3_CON_FS_NOTID;
break;
}
}
/* Audio mode:
* Use audio mode status to select PCM or encoded mode
*/
if (player->stream_settings.iec958.status[0] & IEC958_AES0_NONAUDIO)
player->stream_settings.encoding_mode =
UNIPERIF_IEC958_ENCODING_MODE_ENCODED;
else
player->stream_settings.encoding_mode =
UNIPERIF_IEC958_ENCODING_MODE_PCM;
if (player->stream_settings.encoding_mode ==
UNIPERIF_IEC958_ENCODING_MODE_PCM)
/* Clear user validity bits */
SET_UNIPERIF_USER_VALIDITY_VALIDITY_LR(player, 0);
else
/* Set user validity bits */
SET_UNIPERIF_USER_VALIDITY_VALIDITY_LR(player, 1);
/* Program the new channel status */
for (n = 0; n < 6; ++n) {
status =
player->stream_settings.iec958.status[0 + (n * 4)] & 0xf;
status |=
player->stream_settings.iec958.status[1 + (n * 4)] << 8;
status |=
player->stream_settings.iec958.status[2 + (n * 4)] << 16;
status |=
player->stream_settings.iec958.status[3 + (n * 4)] << 24;
SET_UNIPERIF_CHANNEL_STA_REGN(player, n, status);
}
mutex_unlock(&player->ctrl_lock);
/* Update the channel status */
if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0)
SET_UNIPERIF_CONFIG_CHL_STS_UPDATE(player);
else
SET_UNIPERIF_BIT_CONTROL_CHL_STS_UPDATE(player);
}
static int uni_player_prepare_iec958(struct uniperif *player,
struct snd_pcm_runtime *runtime)
{
int clk_div;
clk_div = player->mclk / runtime->rate;
/* Oversampling must be multiple of 128 as iec958 frame is 32-bits */
if ((clk_div % 128) || (clk_div <= 0)) {
dev_err(player->dev, "%s: invalid clk_div %d",
__func__, clk_div);
return -EINVAL;
}
switch (runtime->format) {
case SNDRV_PCM_FORMAT_S16_LE:
/* 16/16 memory format */
SET_UNIPERIF_CONFIG_MEM_FMT_16_16(player);
/* 16-bits per sub-frame */
SET_UNIPERIF_I2S_FMT_NBIT_32(player);
/* Set 16-bit sample precision */
SET_UNIPERIF_I2S_FMT_DATA_SIZE_16(player);
break;
case SNDRV_PCM_FORMAT_S32_LE:
/* 16/0 memory format */
SET_UNIPERIF_CONFIG_MEM_FMT_16_0(player);
/* 32-bits per sub-frame */
SET_UNIPERIF_I2S_FMT_NBIT_32(player);
/* Set 24-bit sample precision */
SET_UNIPERIF_I2S_FMT_DATA_SIZE_24(player);
break;
default:
dev_err(player->dev, "format not supported");
return -EINVAL;
}
/* Set parity to be calculated by the hardware */
SET_UNIPERIF_CONFIG_PARITY_CNTR_BY_HW(player);
/* Set channel status bits to be inserted by the hardware */
SET_UNIPERIF_CONFIG_CHANNEL_STA_CNTR_BY_HW(player);
/* Set user data bits to be inserted by the hardware */
SET_UNIPERIF_CONFIG_USER_DAT_CNTR_BY_HW(player);
/* Set validity bits to be inserted by the hardware */
SET_UNIPERIF_CONFIG_VALIDITY_DAT_CNTR_BY_HW(player);
/* Set full software control to disabled */
SET_UNIPERIF_CONFIG_SPDIF_SW_CTRL_DISABLE(player);
SET_UNIPERIF_CTRL_ZERO_STUFF_HW(player);
/* Update the channel status */
uni_player_set_channel_status(player, runtime);
/* Clear the user validity user bits */
SET_UNIPERIF_USER_VALIDITY_VALIDITY_LR(player, 0);
/* Disable one-bit audio mode */
SET_UNIPERIF_CONFIG_ONE_BIT_AUD_DISABLE(player);
/* Enable consecutive frames repetition of Z preamble (not for HBRA) */
SET_UNIPERIF_CONFIG_REPEAT_CHL_STS_ENABLE(player);
/* Change to SUF0_SUBF1 and left/right channels swap! */
SET_UNIPERIF_CONFIG_SUBFRAME_SEL_SUBF1_SUBF0(player);
/* Set data output as MSB first */
SET_UNIPERIF_I2S_FMT_ORDER_MSB(player);
if (player->stream_settings.encoding_mode ==
UNIPERIF_IEC958_ENCODING_MODE_ENCODED)
SET_UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_ON(player);
else
SET_UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_OFF(player);
SET_UNIPERIF_I2S_FMT_NUM_CH(player, runtime->channels / 2);
/* Set rounding to off */
SET_UNIPERIF_CTRL_ROUNDING_OFF(player);
/* Set clock divisor */
SET_UNIPERIF_CTRL_DIVIDER(player, clk_div / 128);
/* Set the spdif latency to not wait before starting player */
SET_UNIPERIF_CTRL_SPDIF_LAT_OFF(player);
/*
* Ensure iec958 formatting is off. It will be enabled in function
* uni_player_start() at the same time as the operation
* mode is set to work around a silicon issue.
*/
if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0)
SET_UNIPERIF_CTRL_SPDIF_FMT_OFF(player);
else
SET_UNIPERIF_CTRL_SPDIF_FMT_ON(player);
return 0;
}
static int uni_player_prepare_pcm(struct uniperif *player,
struct snd_pcm_runtime *runtime)
{
int output_frame_size, slot_width, clk_div;
/* Force slot width to 32 in I2S mode (HW constraint) */
if ((player->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) ==
SND_SOC_DAIFMT_I2S) {
slot_width = 32;
} else {
switch (runtime->format) {
case SNDRV_PCM_FORMAT_S16_LE:
slot_width = 16;
break;
default:
slot_width = 32;
break;
}
}
output_frame_size = slot_width * runtime->channels;
clk_div = player->mclk / runtime->rate;
/*
* For 32 bits subframe clk_div must be a multiple of 128,
* for 16 bits must be a multiple of 64
*/
if ((slot_width == 32) && (clk_div % 128)) {
dev_err(player->dev, "%s: invalid clk_div", __func__);
return -EINVAL;
}
if ((slot_width == 16) && (clk_div % 64)) {
dev_err(player->dev, "%s: invalid clk_div", __func__);
return -EINVAL;
}
/*
* Number of bits per subframe (which is one channel sample)
* on output - Transfer 16 or 32 bits from FIFO
*/
switch (slot_width) {
case 32:
SET_UNIPERIF_I2S_FMT_NBIT_32(player);
SET_UNIPERIF_I2S_FMT_DATA_SIZE_32(player);
break;
case 16:
SET_UNIPERIF_I2S_FMT_NBIT_16(player);
SET_UNIPERIF_I2S_FMT_DATA_SIZE_16(player);
break;
default:
dev_err(player->dev, "subframe format not supported");
return -EINVAL;
}
/* Configure data memory format */
switch (runtime->format) {
case SNDRV_PCM_FORMAT_S16_LE:
/* One data word contains two samples */
SET_UNIPERIF_CONFIG_MEM_FMT_16_16(player);
break;
case SNDRV_PCM_FORMAT_S32_LE:
/*
* Actually "16 bits/0 bits" means "32/28/24/20/18/16 bits
* on the left than zeros (if less than 32 bytes)"... ;-)
*/
SET_UNIPERIF_CONFIG_MEM_FMT_16_0(player);
break;
default:
dev_err(player->dev, "format not supported");
return -EINVAL;
}
/* Set rounding to off */
SET_UNIPERIF_CTRL_ROUNDING_OFF(player);
/* Set clock divisor */
SET_UNIPERIF_CTRL_DIVIDER(player, clk_div / (2 * output_frame_size));
/* Number of channelsmust be even*/
if ((runtime->channels % 2) || (runtime->channels < 2) ||
(runtime->channels > 10)) {
dev_err(player->dev, "%s: invalid nb of channels", __func__);
return -EINVAL;
}
SET_UNIPERIF_I2S_FMT_NUM_CH(player, runtime->channels / 2);
/* Set 1-bit audio format to disabled */
SET_UNIPERIF_CONFIG_ONE_BIT_AUD_DISABLE(player);
SET_UNIPERIF_I2S_FMT_ORDER_MSB(player);
SET_UNIPERIF_I2S_FMT_SCLK_EDGE_FALLING(player);
/* No iec958 formatting as outputting to DAC */
SET_UNIPERIF_CTRL_SPDIF_FMT_OFF(player);
return 0;
}
/*
* ALSA uniperipheral iec958 controls
*/
static int uni_player_ctl_iec958_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
uinfo->count = 1;
return 0;
}
static int uni_player_ctl_iec958_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai);
struct uniperif *player = priv->dai_data.uni;
struct snd_aes_iec958 *iec958 = &player->stream_settings.iec958;
mutex_lock(&player->ctrl_lock);
ucontrol->value.iec958.status[0] = iec958->status[0];
ucontrol->value.iec958.status[1] = iec958->status[1];
ucontrol->value.iec958.status[2] = iec958->status[2];
ucontrol->value.iec958.status[3] = iec958->status[3];
mutex_unlock(&player->ctrl_lock);
return 0;
}
static int uni_player_ctl_iec958_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai);
struct uniperif *player = priv->dai_data.uni;
struct snd_aes_iec958 *iec958 = &player->stream_settings.iec958;
mutex_lock(&player->ctrl_lock);
iec958->status[0] = ucontrol->value.iec958.status[0];
iec958->status[1] = ucontrol->value.iec958.status[1];
iec958->status[2] = ucontrol->value.iec958.status[2];
iec958->status[3] = ucontrol->value.iec958.status[3];
mutex_unlock(&player->ctrl_lock);
uni_player_set_channel_status(player, NULL);
return 0;
}
static struct snd_kcontrol_new uni_player_iec958_ctl = {
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
.info = uni_player_ctl_iec958_info,
.get = uni_player_ctl_iec958_get,
.put = uni_player_ctl_iec958_put,
};
/*
* uniperif rate adjustement control
*/
static int snd_sti_clk_adjustment_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 1;
uinfo->value.integer.min = UNIPERIF_PLAYER_CLK_ADJ_MIN;
uinfo->value.integer.max = UNIPERIF_PLAYER_CLK_ADJ_MAX;
uinfo->value.integer.step = 1;
return 0;
}
static int snd_sti_clk_adjustment_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai);
struct uniperif *player = priv->dai_data.uni;
mutex_lock(&player->ctrl_lock);
ucontrol->value.integer.value[0] = player->clk_adj;
mutex_unlock(&player->ctrl_lock);
return 0;
}
static int snd_sti_clk_adjustment_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai);
struct uniperif *player = priv->dai_data.uni;
int ret = 0;
if ((ucontrol->value.integer.value[0] < UNIPERIF_PLAYER_CLK_ADJ_MIN) ||
(ucontrol->value.integer.value[0] > UNIPERIF_PLAYER_CLK_ADJ_MAX))
return -EINVAL;
mutex_lock(&player->ctrl_lock);
player->clk_adj = ucontrol->value.integer.value[0];
if (player->mclk)
ret = uni_player_clk_set_rate(player, player->mclk);
mutex_unlock(&player->ctrl_lock);
return ret;
}
static struct snd_kcontrol_new uni_player_clk_adj_ctl = {
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = "PCM Playback Oversampling Freq. Adjustment",
.info = snd_sti_clk_adjustment_info,
.get = snd_sti_clk_adjustment_get,
.put = snd_sti_clk_adjustment_put,
};
static struct snd_kcontrol_new *snd_sti_pcm_ctl[] = {
&uni_player_clk_adj_ctl,
};
static struct snd_kcontrol_new *snd_sti_iec_ctl[] = {
&uni_player_iec958_ctl,
&uni_player_clk_adj_ctl,
};
static int uni_player_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai);
struct uniperif *player = priv->dai_data.uni;
player->clk_adj = 0;
return 0;
}
static int uni_player_set_sysclk(struct snd_soc_dai *dai, int clk_id,
unsigned int freq, int dir)
{
struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai);
struct uniperif *player = priv->dai_data.uni;
int ret;
if (dir == SND_SOC_CLOCK_IN)
return 0;
if (clk_id != 0)
return -EINVAL;
mutex_lock(&player->ctrl_lock);
ret = uni_player_clk_set_rate(player, freq);
if (!ret)
player->mclk = freq;
mutex_unlock(&player->ctrl_lock);
return ret;
}
static int uni_player_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai);
struct uniperif *player = priv->dai_data.uni;
struct snd_pcm_runtime *runtime = substream->runtime;
int transfer_size, trigger_limit;
int ret;
/* The player should be stopped */
if (player->state != UNIPERIF_STATE_STOPPED) {
dev_err(player->dev, "%s: invalid player state %d", __func__,
player->state);
return -EINVAL;
}
/* Calculate transfer size (in fifo cells and bytes) for frame count */
transfer_size = runtime->channels * UNIPERIF_FIFO_FRAMES;
/* Calculate number of empty cells available before asserting DREQ */
if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) {
trigger_limit = UNIPERIF_FIFO_SIZE - transfer_size;
} else {
/*
* Since SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0
* FDMA_TRIGGER_LIMIT also controls when the state switches
* from OFF or STANDBY to AUDIO DATA.
*/
trigger_limit = transfer_size;
}
/* Trigger limit must be an even number */
if ((!trigger_limit % 2) || (trigger_limit != 1 && transfer_size % 2) ||
(trigger_limit > UNIPERIF_CONFIG_DMA_TRIG_LIMIT_MASK(player))) {
dev_err(player->dev, "invalid trigger limit %d", trigger_limit);
return -EINVAL;
}
SET_UNIPERIF_CONFIG_DMA_TRIG_LIMIT(player, trigger_limit);
/* Uniperipheral setup depends on player type */
switch (player->info->player_type) {
case SND_ST_UNIPERIF_PLAYER_TYPE_HDMI:
ret = uni_player_prepare_iec958(player, runtime);
break;
case SND_ST_UNIPERIF_PLAYER_TYPE_PCM:
ret = uni_player_prepare_pcm(player, runtime);
break;
case SND_ST_UNIPERIF_PLAYER_TYPE_SPDIF:
ret = uni_player_prepare_iec958(player, runtime);
break;
default:
dev_err(player->dev, "invalid player type");
return -EINVAL;
}
if (ret)
return ret;
switch (player->daifmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF:
SET_UNIPERIF_I2S_FMT_LR_POL_LOW(player);
SET_UNIPERIF_I2S_FMT_SCLK_EDGE_RISING(player);
break;
case SND_SOC_DAIFMT_NB_IF:
SET_UNIPERIF_I2S_FMT_LR_POL_HIG(player);
SET_UNIPERIF_I2S_FMT_SCLK_EDGE_RISING(player);
break;
case SND_SOC_DAIFMT_IB_NF:
SET_UNIPERIF_I2S_FMT_LR_POL_LOW(player);
SET_UNIPERIF_I2S_FMT_SCLK_EDGE_FALLING(player);
break;
case SND_SOC_DAIFMT_IB_IF:
SET_UNIPERIF_I2S_FMT_LR_POL_HIG(player);
SET_UNIPERIF_I2S_FMT_SCLK_EDGE_FALLING(player);
break;
}
switch (player->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
SET_UNIPERIF_I2S_FMT_ALIGN_LEFT(player);
SET_UNIPERIF_I2S_FMT_PADDING_I2S_MODE(player);
break;
case SND_SOC_DAIFMT_LEFT_J:
SET_UNIPERIF_I2S_FMT_ALIGN_LEFT(player);
SET_UNIPERIF_I2S_FMT_PADDING_SONY_MODE(player);
break;
case SND_SOC_DAIFMT_RIGHT_J:
SET_UNIPERIF_I2S_FMT_ALIGN_RIGHT(player);
SET_UNIPERIF_I2S_FMT_PADDING_SONY_MODE(player);
break;
default:
dev_err(player->dev, "format not supported");
return -EINVAL;
}
SET_UNIPERIF_I2S_FMT_NO_OF_SAMPLES_TO_READ(player, 0);
/* Reset uniperipheral player */
SET_UNIPERIF_SOFT_RST_SOFT_RST(player);
return reset_player(player);
}
static int uni_player_start(struct uniperif *player)
{
int ret;
/* The player should be stopped */
if (player->state != UNIPERIF_STATE_STOPPED) {
dev_err(player->dev, "%s: invalid player state", __func__);
return -EINVAL;
}
ret = clk_prepare_enable(player->clk);
if (ret) {
dev_err(player->dev, "%s: Failed to enable clock", __func__);
return ret;
}
/* Clear any pending interrupts */
SET_UNIPERIF_ITS_BCLR(player, GET_UNIPERIF_ITS(player));
/* Set the interrupt mask */
SET_UNIPERIF_ITM_BSET_DMA_ERROR(player);
SET_UNIPERIF_ITM_BSET_FIFO_ERROR(player);
/* Enable underflow recovery interrupts */
if (player->info->underflow_enabled) {
SET_UNIPERIF_ITM_BSET_UNDERFLOW_REC_DONE(player);
SET_UNIPERIF_ITM_BSET_UNDERFLOW_REC_FAILED(player);
}
/* Reset uniperipheral player */
SET_UNIPERIF_SOFT_RST_SOFT_RST(player);
ret = reset_player(player);
if (ret < 0)
return ret;
/*
* Does not use IEC61937 features of the uniperipheral hardware.
* Instead it performs IEC61937 in software and inserts it directly
* into the audio data stream. As such, when encoded mode is selected,
* linear pcm mode is still used, but with the differences of the
* channel status bits set for encoded mode and the validity bits set.
*/
SET_UNIPERIF_CTRL_OPERATION_PCM_DATA(player);
/*
* If iec958 formatting is required for hdmi or spdif, then it must be
* enabled after the operation mode is set. If set prior to this, it
* will not take affect and hang the player.
*/
if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0)
if (UNIPERIF_PLAYER_TYPE_IS_IEC958(player))
SET_UNIPERIF_CTRL_SPDIF_FMT_ON(player);
/* Force channel status update (no update if clk disable) */
if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0)
SET_UNIPERIF_CONFIG_CHL_STS_UPDATE(player);
else
SET_UNIPERIF_BIT_CONTROL_CHL_STS_UPDATE(player);
/* Update state to started */
player->state = UNIPERIF_STATE_STARTED;
return 0;
}
static int uni_player_stop(struct uniperif *player)
{
int ret;
/* The player should not be in stopped state */
if (player->state == UNIPERIF_STATE_STOPPED) {
dev_err(player->dev, "%s: invalid player state", __func__);
return -EINVAL;
}
/* Turn the player off */
SET_UNIPERIF_CTRL_OPERATION_OFF(player);
/* Soft reset the player */
SET_UNIPERIF_SOFT_RST_SOFT_RST(player);
ret = reset_player(player);
if (ret < 0)
return ret;
/* Disable interrupts */
SET_UNIPERIF_ITM_BCLR(player, GET_UNIPERIF_ITM(player));
/* Disable clock */
clk_disable_unprepare(player->clk);
/* Update state to stopped and return */
player->state = UNIPERIF_STATE_STOPPED;
return 0;
}
int uni_player_resume(struct uniperif *player)
{
int ret;
/* Select the frequency synthesizer clock */
if (player->clk_sel) {
ret = regmap_field_write(player->clk_sel, 1);
if (ret) {
dev_err(player->dev,
"%s: Failed to select freq synth clock",
__func__);
return ret;
}
}
SET_UNIPERIF_CONFIG_BACK_STALL_REQ_DISABLE(player);
SET_UNIPERIF_CTRL_ROUNDING_OFF(player);
SET_UNIPERIF_CTRL_SPDIF_LAT_OFF(player);
SET_UNIPERIF_CONFIG_IDLE_MOD_DISABLE(player);
return 0;
}
EXPORT_SYMBOL_GPL(uni_player_resume);
static int uni_player_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai)
{
struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai);
struct uniperif *player = priv->dai_data.uni;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
return uni_player_start(player);
case SNDRV_PCM_TRIGGER_STOP:
return uni_player_stop(player);
case SNDRV_PCM_TRIGGER_RESUME:
return uni_player_resume(player);
default:
return -EINVAL;
}
}
static void uni_player_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai);
struct uniperif *player = priv->dai_data.uni;
if (player->state != UNIPERIF_STATE_STOPPED)
/* Stop the player */
uni_player_stop(player);
}
static int uni_player_parse_dt_clk_glue(struct platform_device *pdev,
struct uniperif *player)
{
int bit_offset;
struct device_node *node = pdev->dev.of_node;
struct regmap *regmap;
bit_offset = SYS_CFG_AUDI0_GLUE_PCM_CLKX + player->info->id;
regmap = syscon_regmap_lookup_by_phandle(node, "st,syscfg");
if (regmap) {
struct reg_field regfield =
REG_FIELD(SYS_CFG_AUDIO_GLUE, bit_offset, bit_offset);
player->clk_sel = regmap_field_alloc(regmap, regfield);
} else {
dev_err(&pdev->dev, "sti-audio-clk-glue syscf not found\n");
return -EINVAL;
}
return 0;
}
static int uni_player_parse_dt(struct platform_device *pdev,
struct uniperif *player)
{
struct uniperif_info *info;
struct device *dev = &pdev->dev;
struct device_node *pnode = pdev->dev.of_node;
const char *mode;
/* Allocate memory for the info structure */
info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
of_property_read_u32(pnode, "version", &player->ver);
if (player->ver == SND_ST_UNIPERIF_VERSION_UNKNOWN) {
dev_err(dev, "Unknown uniperipheral version ");
return -EINVAL;
}
/* Underflow recovery is only supported on later ip revisions */
if (player->ver >= SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0)
info->underflow_enabled = 1;
of_property_read_u32(pnode, "uniperiph-id", &info->id);
/* Read the device mode property */
of_property_read_string(pnode, "mode", &mode);
if (strcasecmp(mode, "hdmi") == 0)
info->player_type = SND_ST_UNIPERIF_PLAYER_TYPE_HDMI;
else if (strcasecmp(mode, "pcm") == 0)
info->player_type = SND_ST_UNIPERIF_PLAYER_TYPE_PCM;
else if (strcasecmp(mode, "spdif") == 0)
info->player_type = SND_ST_UNIPERIF_PLAYER_TYPE_SPDIF;
else
info->player_type = SND_ST_UNIPERIF_PLAYER_TYPE_NONE;
/* Save the info structure */
player->info = info;
/* Get the PCM_CLK_SEL bit from audio-glue-ctrl SoC register */
if (uni_player_parse_dt_clk_glue(pdev, player))
return -EINVAL;
return 0;
}
static const struct snd_soc_dai_ops uni_player_dai_ops = {
.startup = uni_player_startup,
.shutdown = uni_player_shutdown,
.prepare = uni_player_prepare,
.trigger = uni_player_trigger,
.hw_params = sti_uniperiph_dai_hw_params,
.set_fmt = sti_uniperiph_dai_set_fmt,
.set_sysclk = uni_player_set_sysclk
};
int uni_player_init(struct platform_device *pdev,
struct uniperif *player)
{
int ret = 0;
player->dev = &pdev->dev;
player->state = UNIPERIF_STATE_STOPPED;
player->hw = &uni_player_pcm_hw;
player->dai_ops = &uni_player_dai_ops;
ret = uni_player_parse_dt(pdev, player);
if (ret < 0) {
dev_err(player->dev, "Failed to parse DeviceTree");
return ret;
}
/* Get uniperif resource */
player->clk = of_clk_get(pdev->dev.of_node, 0);
if (IS_ERR(player->clk))
ret = PTR_ERR(player->clk);
/* Select the frequency synthesizer clock */
if (player->clk_sel) {
ret = regmap_field_write(player->clk_sel, 1);
if (ret) {
dev_err(player->dev,
"%s: Failed to select freq synth clock",
__func__);
return ret;
}
}
ret = devm_request_irq(&pdev->dev, player->irq,
uni_player_irq_handler, IRQF_SHARED,
dev_name(&pdev->dev), player);
if (ret < 0)
return ret;
mutex_init(&player->ctrl_lock);
/* Ensure that disabled by default */
SET_UNIPERIF_CONFIG_BACK_STALL_REQ_DISABLE(player);
SET_UNIPERIF_CTRL_ROUNDING_OFF(player);
SET_UNIPERIF_CTRL_SPDIF_LAT_OFF(player);
SET_UNIPERIF_CONFIG_IDLE_MOD_DISABLE(player);
if (UNIPERIF_PLAYER_TYPE_IS_IEC958(player)) {
/* Set default iec958 status bits */
/* Consumer, PCM, copyright, 2ch, mode 0 */
player->stream_settings.iec958.status[0] = 0x00;
/* Broadcast reception category */
player->stream_settings.iec958.status[1] =
IEC958_AES1_CON_GENERAL;
/* Do not take into account source or channel number */
player->stream_settings.iec958.status[2] =
IEC958_AES2_CON_SOURCE_UNSPEC;
/* Sampling frequency not indicated */
player->stream_settings.iec958.status[3] =
IEC958_AES3_CON_FS_NOTID;
/* Max sample word 24-bit, sample word length not indicated */
player->stream_settings.iec958.status[4] =
IEC958_AES4_CON_MAX_WORDLEN_24 |
IEC958_AES4_CON_WORDLEN_24_20;
player->num_ctrls = ARRAY_SIZE(snd_sti_iec_ctl);
player->snd_ctrls = snd_sti_iec_ctl[0];
} else {
player->num_ctrls = ARRAY_SIZE(snd_sti_pcm_ctl);
player->snd_ctrls = snd_sti_pcm_ctl[0];
}
return 0;
}
EXPORT_SYMBOL_GPL(uni_player_init);
/*
* Copyright (C) STMicroelectronics SA 2015
* Authors: Arnaud Pouliquen <arnaud.pouliquen@st.com>
* for STMicroelectronics.
* License terms: GNU General Public License (GPL), version 2
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <sound/soc.h>
#include "uniperif.h"
/*
* Note: snd_pcm_hardware is linked to DMA controller but is declared here to
* integrate unireader capability in term of rate and supported channels
*/
static const struct snd_pcm_hardware uni_reader_pcm_hw = {
.info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID,
.formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE,
.rates = SNDRV_PCM_RATE_CONTINUOUS,
.rate_min = 8000,
.rate_max = 96000,
.channels_min = 2,
.channels_max = 8,
.periods_min = 2,
.periods_max = 48,
.period_bytes_min = 128,
.period_bytes_max = 64 * PAGE_SIZE,
.buffer_bytes_max = 256 * PAGE_SIZE
};
/*
* uni_reader_irq_handler
* In case of error audio stream is stopped; stop action is protected via PCM
* stream lock to avoid race condition with trigger callback.
*/
static irqreturn_t uni_reader_irq_handler(int irq, void *dev_id)
{
irqreturn_t ret = IRQ_NONE;
struct uniperif *reader = dev_id;
unsigned int status;
if (reader->state == UNIPERIF_STATE_STOPPED) {
/* Unexpected IRQ: do nothing */
dev_warn(reader->dev, "unexpected IRQ ");
return IRQ_HANDLED;
}
/* Get interrupt status & clear them immediately */
status = GET_UNIPERIF_ITS(reader);
SET_UNIPERIF_ITS_BCLR(reader, status);
/* Check for fifo overflow error */
if (unlikely(status & UNIPERIF_ITS_FIFO_ERROR_MASK(reader))) {
dev_err(reader->dev, "FIFO error detected");
snd_pcm_stream_lock(reader->substream);
snd_pcm_stop(reader->substream, SNDRV_PCM_STATE_XRUN);
snd_pcm_stream_unlock(reader->substream);
return IRQ_HANDLED;
}
return ret;
}
static int uni_reader_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai);
struct uniperif *reader = priv->dai_data.uni;
struct snd_pcm_runtime *runtime = substream->runtime;
int transfer_size, trigger_limit;
int slot_width;
int count = 10;
/* The reader should be stopped */
if (reader->state != UNIPERIF_STATE_STOPPED) {
dev_err(reader->dev, "%s: invalid reader state %d", __func__,
reader->state);
return -EINVAL;
}
/* Calculate transfer size (in fifo cells and bytes) for frame count */
transfer_size = runtime->channels * UNIPERIF_FIFO_FRAMES;
/* Calculate number of empty cells available before asserting DREQ */
if (reader->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0)
trigger_limit = UNIPERIF_FIFO_SIZE - transfer_size;
else
/*
* Since SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0
* FDMA_TRIGGER_LIMIT also controls when the state switches
* from OFF or STANDBY to AUDIO DATA.
*/
trigger_limit = transfer_size;
/* Trigger limit must be an even number */
if ((!trigger_limit % 2) ||
(trigger_limit != 1 && transfer_size % 2) ||
(trigger_limit > UNIPERIF_CONFIG_DMA_TRIG_LIMIT_MASK(reader))) {
dev_err(reader->dev, "invalid trigger limit %d", trigger_limit);
return -EINVAL;
}
SET_UNIPERIF_CONFIG_DMA_TRIG_LIMIT(reader, trigger_limit);
switch (reader->daifmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_IB_IF:
case SND_SOC_DAIFMT_NB_IF:
SET_UNIPERIF_I2S_FMT_LR_POL_HIG(reader);
break;
default:
SET_UNIPERIF_I2S_FMT_LR_POL_LOW(reader);
}
/* Force slot width to 32 in I2S mode */
if ((reader->daifmt & SND_SOC_DAIFMT_FORMAT_MASK)
== SND_SOC_DAIFMT_I2S) {
slot_width = 32;
} else {
switch (runtime->format) {
case SNDRV_PCM_FORMAT_S16_LE:
slot_width = 16;
break;
default:
slot_width = 32;
break;
}
}
/* Number of bits per subframe (i.e one channel sample) on input. */
switch (slot_width) {
case 32:
SET_UNIPERIF_I2S_FMT_NBIT_32(reader);
SET_UNIPERIF_I2S_FMT_DATA_SIZE_32(reader);
break;
case 16:
SET_UNIPERIF_I2S_FMT_NBIT_16(reader);
SET_UNIPERIF_I2S_FMT_DATA_SIZE_16(reader);
break;
default:
dev_err(reader->dev, "subframe format not supported");
return -EINVAL;
}
/* Configure data memory format */
switch (runtime->format) {
case SNDRV_PCM_FORMAT_S16_LE:
/* One data word contains two samples */
SET_UNIPERIF_CONFIG_MEM_FMT_16_16(reader);
break;
case SNDRV_PCM_FORMAT_S32_LE:
/*
* Actually "16 bits/0 bits" means "32/28/24/20/18/16 bits
* on the MSB then zeros (if less than 32 bytes)"...
*/
SET_UNIPERIF_CONFIG_MEM_FMT_16_0(reader);
break;
default:
dev_err(reader->dev, "format not supported");
return -EINVAL;
}
switch (reader->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
SET_UNIPERIF_I2S_FMT_ALIGN_LEFT(reader);
SET_UNIPERIF_I2S_FMT_PADDING_I2S_MODE(reader);
break;
case SND_SOC_DAIFMT_LEFT_J:
SET_UNIPERIF_I2S_FMT_ALIGN_LEFT(reader);
SET_UNIPERIF_I2S_FMT_PADDING_SONY_MODE(reader);
break;
case SND_SOC_DAIFMT_RIGHT_J:
SET_UNIPERIF_I2S_FMT_ALIGN_RIGHT(reader);
SET_UNIPERIF_I2S_FMT_PADDING_SONY_MODE(reader);
break;
default:
dev_err(reader->dev, "format not supported");
return -EINVAL;
}
SET_UNIPERIF_I2S_FMT_ORDER_MSB(reader);
/* Data clocking (changing) on the rising edge */
SET_UNIPERIF_I2S_FMT_SCLK_EDGE_RISING(reader);
/* Number of channels must be even */
if ((runtime->channels % 2) || (runtime->channels < 2) ||
(runtime->channels > 10)) {
dev_err(reader->dev, "%s: invalid nb of channels", __func__);
return -EINVAL;
}
SET_UNIPERIF_I2S_FMT_NUM_CH(reader, runtime->channels / 2);
/* Clear any pending interrupts */
SET_UNIPERIF_ITS_BCLR(reader, GET_UNIPERIF_ITS(reader));
SET_UNIPERIF_I2S_FMT_NO_OF_SAMPLES_TO_READ(reader, 0);
/* Set the interrupt mask */
SET_UNIPERIF_ITM_BSET_DMA_ERROR(reader);
SET_UNIPERIF_ITM_BSET_FIFO_ERROR(reader);
SET_UNIPERIF_ITM_BSET_MEM_BLK_READ(reader);
/* Enable underflow recovery interrupts */
if (reader->info->underflow_enabled) {
SET_UNIPERIF_ITM_BSET_UNDERFLOW_REC_DONE(reader);
SET_UNIPERIF_ITM_BSET_UNDERFLOW_REC_FAILED(reader);
}
/* Reset uniperipheral reader */
SET_UNIPERIF_SOFT_RST_SOFT_RST(reader);
while (GET_UNIPERIF_SOFT_RST_SOFT_RST(reader)) {
udelay(5);
count--;
}
if (!count) {
dev_err(reader->dev, "Failed to reset uniperif");
return -EIO;
}
return 0;
}
static int uni_reader_start(struct uniperif *reader)
{
/* The reader should be stopped */
if (reader->state != UNIPERIF_STATE_STOPPED) {
dev_err(reader->dev, "%s: invalid reader state", __func__);
return -EINVAL;
}
/* Enable reader interrupts (and clear possible stalled ones) */
SET_UNIPERIF_ITS_BCLR_FIFO_ERROR(reader);
SET_UNIPERIF_ITM_BSET_FIFO_ERROR(reader);
/* Launch the reader */
SET_UNIPERIF_CTRL_OPERATION_PCM_DATA(reader);
/* Update state to started */
reader->state = UNIPERIF_STATE_STARTED;
return 0;
}
static int uni_reader_stop(struct uniperif *reader)
{
/* The reader should not be in stopped state */
if (reader->state == UNIPERIF_STATE_STOPPED) {
dev_err(reader->dev, "%s: invalid reader state", __func__);
return -EINVAL;
}
/* Turn the reader off */
SET_UNIPERIF_CTRL_OPERATION_OFF(reader);
/* Disable interrupts */
SET_UNIPERIF_ITM_BCLR(reader, GET_UNIPERIF_ITM(reader));
/* Update state to stopped and return */
reader->state = UNIPERIF_STATE_STOPPED;
return 0;
}
static int uni_reader_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai)
{
struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai);
struct uniperif *reader = priv->dai_data.uni;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
return uni_reader_start(reader);
case SNDRV_PCM_TRIGGER_STOP:
return uni_reader_stop(reader);
default:
return -EINVAL;
}
}
static void uni_reader_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai);
struct uniperif *reader = priv->dai_data.uni;
if (reader->state != UNIPERIF_STATE_STOPPED) {
/* Stop the reader */
uni_reader_stop(reader);
}
}
static int uni_reader_parse_dt(struct platform_device *pdev,
struct uniperif *reader)
{
struct uniperif_info *info;
struct device_node *node = pdev->dev.of_node;
/* Allocate memory for the info structure */
info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
of_property_read_u32(node, "version", &reader->ver);
/* Save the info structure */
reader->info = info;
return 0;
}
static const struct snd_soc_dai_ops uni_reader_dai_ops = {
.shutdown = uni_reader_shutdown,
.prepare = uni_reader_prepare,
.trigger = uni_reader_trigger,
.hw_params = sti_uniperiph_dai_hw_params,
.set_fmt = sti_uniperiph_dai_set_fmt,
};
int uni_reader_init(struct platform_device *pdev,
struct uniperif *reader)
{
int ret = 0;
reader->dev = &pdev->dev;
reader->state = UNIPERIF_STATE_STOPPED;
reader->hw = &uni_reader_pcm_hw;
reader->dai_ops = &uni_reader_dai_ops;
dev_err(reader->dev, "%s: enter\n", __func__);
ret = uni_reader_parse_dt(pdev, reader);
if (ret < 0) {
dev_err(reader->dev, "Failed to parse DeviceTree");
return ret;
}
ret = devm_request_irq(&pdev->dev, reader->irq,
uni_reader_irq_handler, IRQF_SHARED,
dev_name(&pdev->dev), reader);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to request IRQ");
return -EBUSY;
}
return 0;
}
EXPORT_SYMBOL_GPL(uni_reader_init);
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