Commit 7fa89d61 authored by Mark Brown's avatar Mark Brown

Merge remote-tracking branches 'asoc/topic/twl4030', 'asoc/topic/twl6040',...

Merge remote-tracking branches 'asoc/topic/twl4030', 'asoc/topic/twl6040', 'asoc/topic/uda134x', 'asoc/topic/uda1380' and 'asoc/topic/uniphier' into asoc-next
Socionext UniPhier SoC audio driver
The Socionext UniPhier audio subsystem consists of I2S and S/PDIF blocks in
the same register space.
Required properties:
- compatible : should be one of the following:
"socionext,uniphier-ld11-aio"
"socionext,uniphier-ld20-aio"
"socionext,uniphier-pxs2-aio"
- reg : offset and length of the register set for the device.
- interrupts : should contain I2S or S/PDIF interrupt.
- pinctrl-names : should be "default".
- pinctrl-0 : defined I2S signal pins for an external codec chip.
- clock-names : should include following entries:
"aio"
- clocks : a list of phandle, should contain an entry for each
entry in clock-names.
- reset-names : should include following entries:
"aio"
- resets : a list of phandle, should contain an entry for each
entry in reset-names.
- #sound-dai-cells: should be 1.
Optional properties:
- socionext,syscon: a phandle, should contain soc-glue.
The soc-glue is used for changing mode of S/PDIF signal pin
to Output from Hi-Z. This property is optional if you use
I2S signal pins only.
Example:
audio {
compatible = "socionext,uniphier-ld20-aio";
reg = <0x56000000 0x80000>;
interrupts = <0 144 4>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_aout>;
clock-names = "aio";
clocks = <&sys_clk 40>;
reset-names = "aio";
resets = <&sys_rst 40>;
#sound-dai-cells = <1>;
socionext,syscon = <&sg>;
};
......@@ -86,9 +86,9 @@ static void tw4030_init_ctl_cache(struct twl4030_priv *twl4030)
}
}
static unsigned int twl4030_read(struct snd_soc_codec *codec, unsigned int reg)
static unsigned int twl4030_read(struct snd_soc_component *component, unsigned int reg)
{
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
u8 value = 0;
if (reg >= TWL4030_CACHEREGNUM)
......@@ -151,10 +151,10 @@ static bool twl4030_can_write_to_chip(struct twl4030_priv *twl4030,
return write_to_reg;
}
static int twl4030_write(struct snd_soc_codec *codec, unsigned int reg,
static int twl4030_write(struct snd_soc_component *component, unsigned int reg,
unsigned int value)
{
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
/* Update the ctl cache */
switch (reg) {
......@@ -186,9 +186,9 @@ static inline void twl4030_wait_ms(int time)
}
}
static void twl4030_codec_enable(struct snd_soc_codec *codec, int enable)
static void twl4030_codec_enable(struct snd_soc_component *component, int enable)
{
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
int mode;
if (enable == twl4030->codec_powered)
......@@ -227,16 +227,16 @@ static void twl4030_setup_pdata_of(struct twl4030_codec_data *pdata,
pdata->hs_extmute = 1;
}
static struct twl4030_codec_data *twl4030_get_pdata(struct snd_soc_codec *codec)
static struct twl4030_codec_data *twl4030_get_pdata(struct snd_soc_component *component)
{
struct twl4030_codec_data *pdata = dev_get_platdata(codec->dev);
struct twl4030_codec_data *pdata = dev_get_platdata(component->dev);
struct device_node *twl4030_codec_node = NULL;
twl4030_codec_node = of_get_child_by_name(codec->dev->parent->of_node,
twl4030_codec_node = of_get_child_by_name(component->dev->parent->of_node,
"codec");
if (!pdata && twl4030_codec_node) {
pdata = devm_kzalloc(codec->dev,
pdata = devm_kzalloc(component->dev,
sizeof(struct twl4030_codec_data),
GFP_KERNEL);
if (!pdata) {
......@@ -250,28 +250,28 @@ static struct twl4030_codec_data *twl4030_get_pdata(struct snd_soc_codec *codec)
return pdata;
}
static void twl4030_init_chip(struct snd_soc_codec *codec)
static void twl4030_init_chip(struct snd_soc_component *component)
{
struct twl4030_codec_data *pdata;
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
u8 reg, byte;
int i = 0;
pdata = twl4030_get_pdata(codec);
pdata = twl4030_get_pdata(component);
if (pdata && pdata->hs_extmute) {
if (gpio_is_valid(pdata->hs_extmute_gpio)) {
int ret;
if (!pdata->hs_extmute_gpio)
dev_warn(codec->dev,
dev_warn(component->dev,
"Extmute GPIO is 0 is this correct?\n");
ret = gpio_request_one(pdata->hs_extmute_gpio,
GPIOF_OUT_INIT_LOW,
"hs_extmute");
if (ret) {
dev_err(codec->dev,
dev_err(component->dev,
"Failed to get hs_extmute GPIO\n");
pdata->hs_extmute_gpio = -1;
}
......@@ -292,16 +292,16 @@ static void twl4030_init_chip(struct snd_soc_codec *codec)
tw4030_init_ctl_cache(twl4030);
/* anti-pop when changing analog gain */
reg = twl4030_read(codec, TWL4030_REG_MISC_SET_1);
twl4030_write(codec, TWL4030_REG_MISC_SET_1,
reg = twl4030_read(component, TWL4030_REG_MISC_SET_1);
twl4030_write(component, TWL4030_REG_MISC_SET_1,
reg | TWL4030_SMOOTH_ANAVOL_EN);
twl4030_write(codec, TWL4030_REG_OPTION,
twl4030_write(component, TWL4030_REG_OPTION,
TWL4030_ATXL1_EN | TWL4030_ATXR1_EN |
TWL4030_ARXL2_EN | TWL4030_ARXR2_EN);
/* REG_ARXR2_APGA_CTL reset according to the TRM: 0dB, DA_EN */
twl4030_write(codec, TWL4030_REG_ARXR2_APGA_CTL, 0x32);
twl4030_write(component, TWL4030_REG_ARXR2_APGA_CTL, 0x32);
/* Machine dependent setup */
if (!pdata)
......@@ -309,18 +309,18 @@ static void twl4030_init_chip(struct snd_soc_codec *codec)
twl4030->pdata = pdata;
reg = twl4030_read(codec, TWL4030_REG_HS_POPN_SET);
reg = twl4030_read(component, TWL4030_REG_HS_POPN_SET);
reg &= ~TWL4030_RAMP_DELAY;
reg |= (pdata->ramp_delay_value << 2);
twl4030_write(codec, TWL4030_REG_HS_POPN_SET, reg);
twl4030_write(component, TWL4030_REG_HS_POPN_SET, reg);
/* initiate offset cancellation */
twl4030_codec_enable(codec, 1);
twl4030_codec_enable(component, 1);
reg = twl4030_read(codec, TWL4030_REG_ANAMICL);
reg = twl4030_read(component, TWL4030_REG_ANAMICL);
reg &= ~TWL4030_OFFSET_CNCL_SEL;
reg |= pdata->offset_cncl_path;
twl4030_write(codec, TWL4030_REG_ANAMICL,
twl4030_write(component, TWL4030_REG_ANAMICL,
reg | TWL4030_CNCL_OFFSET_START);
/*
......@@ -339,12 +339,12 @@ static void twl4030_init_chip(struct snd_soc_codec *codec)
((byte & TWL4030_CNCL_OFFSET_START) ==
TWL4030_CNCL_OFFSET_START));
twl4030_codec_enable(codec, 0);
twl4030_codec_enable(component, 0);
}
static void twl4030_apll_enable(struct snd_soc_codec *codec, int enable)
static void twl4030_apll_enable(struct snd_soc_component *component, int enable)
{
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
if (enable) {
twl4030->apll_enabled++;
......@@ -567,13 +567,13 @@ static const struct snd_kcontrol_new twl4030_dapm_dbypassv_control =
static int pin_name##pga_event(struct snd_soc_dapm_widget *w, \
struct snd_kcontrol *kcontrol, int event) \
{ \
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); \
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); \
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); \
struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component); \
\
switch (event) { \
case SND_SOC_DAPM_POST_PMU: \
twl4030->pin_name##_enabled = 1; \
twl4030_write(codec, reg, twl4030_read(codec, reg)); \
twl4030_write(component, reg, twl4030_read(component, reg)); \
break; \
case SND_SOC_DAPM_POST_PMD: \
twl4030->pin_name##_enabled = 0; \
......@@ -589,47 +589,47 @@ TWL4030_OUTPUT_PGA(predriver, TWL4030_REG_PREDR_CTL, TWL4030_PREDR_GAIN);
TWL4030_OUTPUT_PGA(carkitl, TWL4030_REG_PRECKL_CTL, TWL4030_PRECKL_GAIN);
TWL4030_OUTPUT_PGA(carkitr, TWL4030_REG_PRECKR_CTL, TWL4030_PRECKR_GAIN);
static void handsfree_ramp(struct snd_soc_codec *codec, int reg, int ramp)
static void handsfree_ramp(struct snd_soc_component *component, int reg, int ramp)
{
unsigned char hs_ctl;
hs_ctl = twl4030_read(codec, reg);
hs_ctl = twl4030_read(component, reg);
if (ramp) {
/* HF ramp-up */
hs_ctl |= TWL4030_HF_CTL_REF_EN;
twl4030_write(codec, reg, hs_ctl);
twl4030_write(component, reg, hs_ctl);
udelay(10);
hs_ctl |= TWL4030_HF_CTL_RAMP_EN;
twl4030_write(codec, reg, hs_ctl);
twl4030_write(component, reg, hs_ctl);
udelay(40);
hs_ctl |= TWL4030_HF_CTL_LOOP_EN;
hs_ctl |= TWL4030_HF_CTL_HB_EN;
twl4030_write(codec, reg, hs_ctl);
twl4030_write(component, reg, hs_ctl);
} else {
/* HF ramp-down */
hs_ctl &= ~TWL4030_HF_CTL_LOOP_EN;
hs_ctl &= ~TWL4030_HF_CTL_HB_EN;
twl4030_write(codec, reg, hs_ctl);
twl4030_write(component, reg, hs_ctl);
hs_ctl &= ~TWL4030_HF_CTL_RAMP_EN;
twl4030_write(codec, reg, hs_ctl);
twl4030_write(component, reg, hs_ctl);
udelay(40);
hs_ctl &= ~TWL4030_HF_CTL_REF_EN;
twl4030_write(codec, reg, hs_ctl);
twl4030_write(component, reg, hs_ctl);
}
}
static int handsfreelpga_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
switch (event) {
case SND_SOC_DAPM_POST_PMU:
handsfree_ramp(codec, TWL4030_REG_HFL_CTL, 1);
handsfree_ramp(component, TWL4030_REG_HFL_CTL, 1);
break;
case SND_SOC_DAPM_POST_PMD:
handsfree_ramp(codec, TWL4030_REG_HFL_CTL, 0);
handsfree_ramp(component, TWL4030_REG_HFL_CTL, 0);
break;
}
return 0;
......@@ -638,14 +638,14 @@ static int handsfreelpga_event(struct snd_soc_dapm_widget *w,
static int handsfreerpga_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
switch (event) {
case SND_SOC_DAPM_POST_PMU:
handsfree_ramp(codec, TWL4030_REG_HFR_CTL, 1);
handsfree_ramp(component, TWL4030_REG_HFR_CTL, 1);
break;
case SND_SOC_DAPM_POST_PMD:
handsfree_ramp(codec, TWL4030_REG_HFR_CTL, 0);
handsfree_ramp(component, TWL4030_REG_HFR_CTL, 0);
break;
}
return 0;
......@@ -654,23 +654,23 @@ static int handsfreerpga_event(struct snd_soc_dapm_widget *w,
static int vibramux_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
twl4030_write(codec, TWL4030_REG_VIBRA_SET, 0xff);
twl4030_write(component, TWL4030_REG_VIBRA_SET, 0xff);
return 0;
}
static int apll_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
twl4030_apll_enable(codec, 1);
twl4030_apll_enable(component, 1);
break;
case SND_SOC_DAPM_POST_PMD:
twl4030_apll_enable(codec, 0);
twl4030_apll_enable(component, 0);
break;
}
return 0;
......@@ -679,41 +679,41 @@ static int apll_event(struct snd_soc_dapm_widget *w,
static int aif_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
u8 audio_if;
audio_if = twl4030_read(codec, TWL4030_REG_AUDIO_IF);
audio_if = twl4030_read(component, TWL4030_REG_AUDIO_IF);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
/* Enable AIF */
/* enable the PLL before we use it to clock the DAI */
twl4030_apll_enable(codec, 1);
twl4030_apll_enable(component, 1);
twl4030_write(codec, TWL4030_REG_AUDIO_IF,
twl4030_write(component, TWL4030_REG_AUDIO_IF,
audio_if | TWL4030_AIF_EN);
break;
case SND_SOC_DAPM_POST_PMD:
/* disable the DAI before we stop it's source PLL */
twl4030_write(codec, TWL4030_REG_AUDIO_IF,
twl4030_write(component, TWL4030_REG_AUDIO_IF,
audio_if & ~TWL4030_AIF_EN);
twl4030_apll_enable(codec, 0);
twl4030_apll_enable(component, 0);
break;
}
return 0;
}
static void headset_ramp(struct snd_soc_codec *codec, int ramp)
static void headset_ramp(struct snd_soc_component *component, int ramp)
{
unsigned char hs_gain, hs_pop;
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
struct twl4030_codec_data *pdata = twl4030->pdata;
/* Base values for ramp delay calculation: 2^19 - 2^26 */
unsigned int ramp_base[] = {524288, 1048576, 2097152, 4194304,
8388608, 16777216, 33554432, 67108864};
unsigned int delay;
hs_gain = twl4030_read(codec, TWL4030_REG_HS_GAIN_SET);
hs_pop = twl4030_read(codec, TWL4030_REG_HS_POPN_SET);
hs_gain = twl4030_read(component, TWL4030_REG_HS_GAIN_SET);
hs_pop = twl4030_read(component, TWL4030_REG_HS_POPN_SET);
delay = (ramp_base[(hs_pop & TWL4030_RAMP_DELAY) >> 2] /
twl4030->sysclk) + 1;
......@@ -724,26 +724,26 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp)
gpio_set_value(pdata->hs_extmute_gpio, 1);
} else {
hs_pop |= TWL4030_EXTMUTE;
twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
twl4030_write(component, TWL4030_REG_HS_POPN_SET, hs_pop);
}
}
if (ramp) {
/* Headset ramp-up according to the TRM */
hs_pop |= TWL4030_VMID_EN;
twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
twl4030_write(component, TWL4030_REG_HS_POPN_SET, hs_pop);
/* Actually write to the register */
twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, hs_gain,
TWL4030_REG_HS_GAIN_SET);
hs_pop |= TWL4030_RAMP_EN;
twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
twl4030_write(component, TWL4030_REG_HS_POPN_SET, hs_pop);
/* Wait ramp delay time + 1, so the VMID can settle */
twl4030_wait_ms(delay);
} else {
/* Headset ramp-down _not_ according to
* the TRM, but in a way that it is working */
hs_pop &= ~TWL4030_RAMP_EN;
twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
twl4030_write(component, TWL4030_REG_HS_POPN_SET, hs_pop);
/* Wait ramp delay time + 1, so the VMID can settle */
twl4030_wait_ms(delay);
/* Bypass the reg_cache to mute the headset */
......@@ -751,7 +751,7 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp)
TWL4030_REG_HS_GAIN_SET);
hs_pop &= ~TWL4030_VMID_EN;
twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
twl4030_write(component, TWL4030_REG_HS_POPN_SET, hs_pop);
}
/* Disable external mute */
......@@ -760,7 +760,7 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp)
gpio_set_value(pdata->hs_extmute_gpio, 0);
} else {
hs_pop &= ~TWL4030_EXTMUTE;
twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
twl4030_write(component, TWL4030_REG_HS_POPN_SET, hs_pop);
}
}
}
......@@ -768,21 +768,21 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp)
static int headsetlpga_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
switch (event) {
case SND_SOC_DAPM_POST_PMU:
/* Do the ramp-up only once */
if (!twl4030->hsr_enabled)
headset_ramp(codec, 1);
headset_ramp(component, 1);
twl4030->hsl_enabled = 1;
break;
case SND_SOC_DAPM_POST_PMD:
/* Do the ramp-down only if both headsetL/R is disabled */
if (!twl4030->hsr_enabled)
headset_ramp(codec, 0);
headset_ramp(component, 0);
twl4030->hsl_enabled = 0;
break;
......@@ -793,21 +793,21 @@ static int headsetlpga_event(struct snd_soc_dapm_widget *w,
static int headsetrpga_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
switch (event) {
case SND_SOC_DAPM_POST_PMU:
/* Do the ramp-up only once */
if (!twl4030->hsl_enabled)
headset_ramp(codec, 1);
headset_ramp(component, 1);
twl4030->hsr_enabled = 1;
break;
case SND_SOC_DAPM_POST_PMD:
/* Do the ramp-down only if both headsetL/R is disabled */
if (!twl4030->hsl_enabled)
headset_ramp(codec, 0);
headset_ramp(component, 0);
twl4030->hsr_enabled = 0;
break;
......@@ -818,8 +818,8 @@ static int headsetrpga_event(struct snd_soc_dapm_widget *w,
static int digimic_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
struct twl4030_codec_data *pdata = twl4030->pdata;
if (pdata && pdata->digimic_delay)
......@@ -842,7 +842,7 @@ static int snd_soc_get_volsw_twl4030(struct snd_kcontrol *kcontrol,
{
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
unsigned int reg = mc->reg;
unsigned int shift = mc->shift;
unsigned int rshift = mc->rshift;
......@@ -850,14 +850,14 @@ static int snd_soc_get_volsw_twl4030(struct snd_kcontrol *kcontrol,
int mask = (1 << fls(max)) - 1;
ucontrol->value.integer.value[0] =
(twl4030_read(codec, reg) >> shift) & mask;
(twl4030_read(component, reg) >> shift) & mask;
if (ucontrol->value.integer.value[0])
ucontrol->value.integer.value[0] =
max + 1 - ucontrol->value.integer.value[0];
if (shift != rshift) {
ucontrol->value.integer.value[1] =
(twl4030_read(codec, reg) >> rshift) & mask;
(twl4030_read(component, reg) >> rshift) & mask;
if (ucontrol->value.integer.value[1])
ucontrol->value.integer.value[1] =
max + 1 - ucontrol->value.integer.value[1];
......@@ -871,7 +871,7 @@ static int snd_soc_put_volsw_twl4030(struct snd_kcontrol *kcontrol,
{
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
unsigned int reg = mc->reg;
unsigned int shift = mc->shift;
unsigned int rshift = mc->rshift;
......@@ -892,7 +892,7 @@ static int snd_soc_put_volsw_twl4030(struct snd_kcontrol *kcontrol,
val2 = max + 1 - val2;
val |= val2 << rshift;
}
return snd_soc_update_bits(codec, reg, val_mask, val);
return snd_soc_component_update_bits(component, reg, val_mask, val);
}
static int snd_soc_get_volsw_r2_twl4030(struct snd_kcontrol *kcontrol,
......@@ -900,7 +900,7 @@ static int snd_soc_get_volsw_r2_twl4030(struct snd_kcontrol *kcontrol,
{
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
unsigned int reg = mc->reg;
unsigned int reg2 = mc->rreg;
unsigned int shift = mc->shift;
......@@ -908,9 +908,9 @@ static int snd_soc_get_volsw_r2_twl4030(struct snd_kcontrol *kcontrol,
int mask = (1<<fls(max))-1;
ucontrol->value.integer.value[0] =
(twl4030_read(codec, reg) >> shift) & mask;
(twl4030_read(component, reg) >> shift) & mask;
ucontrol->value.integer.value[1] =
(twl4030_read(codec, reg2) >> shift) & mask;
(twl4030_read(component, reg2) >> shift) & mask;
if (ucontrol->value.integer.value[0])
ucontrol->value.integer.value[0] =
......@@ -927,7 +927,7 @@ static int snd_soc_put_volsw_r2_twl4030(struct snd_kcontrol *kcontrol,
{
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
unsigned int reg = mc->reg;
unsigned int reg2 = mc->rreg;
unsigned int shift = mc->shift;
......@@ -948,11 +948,11 @@ static int snd_soc_put_volsw_r2_twl4030(struct snd_kcontrol *kcontrol,
val = val << shift;
val2 = val2 << shift;
err = snd_soc_update_bits(codec, reg, val_mask, val);
err = snd_soc_component_update_bits(component, reg, val_mask, val);
if (err < 0)
return err;
err = snd_soc_update_bits(codec, reg2, val_mask, val2);
err = snd_soc_component_update_bits(component, reg2, val_mask, val2);
return err;
}
......@@ -968,11 +968,11 @@ static SOC_ENUM_SINGLE_DECL(twl4030_op_modes_enum,
static int snd_soc_put_twl4030_opmode_enum_double(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
if (twl4030->configured) {
dev_err(codec->dev,
dev_err(component->dev,
"operation mode cannot be changed on-the-fly\n");
return -EBUSY;
}
......@@ -1579,7 +1579,7 @@ static const struct snd_soc_dapm_route intercon[] = {
};
static int twl4030_set_bias_level(struct snd_soc_codec *codec,
static int twl4030_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
switch (level) {
......@@ -1588,11 +1588,11 @@ static int twl4030_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
twl4030_codec_enable(codec, 1);
if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
twl4030_codec_enable(component, 1);
break;
case SND_SOC_BIAS_OFF:
twl4030_codec_enable(codec, 0);
twl4030_codec_enable(component, 0);
break;
}
......@@ -1628,12 +1628,12 @@ static void twl4030_constraints(struct twl4030_priv *twl4030,
/* In case of 4 channel mode, the RX1 L/R for playback and the TX2 L/R for
* capture has to be enabled/disabled. */
static void twl4030_tdm_enable(struct snd_soc_codec *codec, int direction,
static void twl4030_tdm_enable(struct snd_soc_component *component, int direction,
int enable)
{
u8 reg, mask;
reg = twl4030_read(codec, TWL4030_REG_OPTION);
reg = twl4030_read(component, TWL4030_REG_OPTION);
if (direction == SNDRV_PCM_STREAM_PLAYBACK)
mask = TWL4030_ARXL1_VRX_EN | TWL4030_ARXR1_EN;
......@@ -1645,14 +1645,14 @@ static void twl4030_tdm_enable(struct snd_soc_codec *codec, int direction,
else
reg &= ~mask;
twl4030_write(codec, TWL4030_REG_OPTION, reg);
twl4030_write(component, TWL4030_REG_OPTION, reg);
}
static int twl4030_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
struct snd_soc_component *component = dai->component;
struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
if (twl4030->master_substream) {
twl4030->slave_substream = substream;
......@@ -1662,7 +1662,7 @@ static int twl4030_startup(struct snd_pcm_substream *substream,
if (twl4030->configured)
twl4030_constraints(twl4030, twl4030->master_substream);
} else {
if (!(twl4030_read(codec, TWL4030_REG_CODEC_MODE) &
if (!(twl4030_read(component, TWL4030_REG_CODEC_MODE) &
TWL4030_OPTION_1)) {
/* In option2 4 channel is not supported, set the
* constraint for the first stream for channels, the
......@@ -1680,8 +1680,8 @@ static int twl4030_startup(struct snd_pcm_substream *substream,
static void twl4030_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
struct snd_soc_component *component = dai->component;
struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
if (twl4030->master_substream == substream)
twl4030->master_substream = twl4030->slave_substream;
......@@ -1697,27 +1697,27 @@ static void twl4030_shutdown(struct snd_pcm_substream *substream,
/* If the closing substream had 4 channel, do the necessary cleanup */
if (substream->runtime->channels == 4)
twl4030_tdm_enable(codec, substream->stream, 0);
twl4030_tdm_enable(component, substream->stream, 0);
}
static int twl4030_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
struct snd_soc_component *component = dai->component;
struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
u8 mode, old_mode, format, old_format;
/* If the substream has 4 channel, do the necessary setup */
if (params_channels(params) == 4) {
format = twl4030_read(codec, TWL4030_REG_AUDIO_IF);
mode = twl4030_read(codec, TWL4030_REG_CODEC_MODE);
format = twl4030_read(component, TWL4030_REG_AUDIO_IF);
mode = twl4030_read(component, TWL4030_REG_CODEC_MODE);
/* Safety check: are we in the correct operating mode and
* the interface is in TDM mode? */
if ((mode & TWL4030_OPTION_1) &&
((format & TWL4030_AIF_FORMAT) == TWL4030_AIF_FORMAT_TDM))
twl4030_tdm_enable(codec, substream->stream, 1);
twl4030_tdm_enable(component, substream->stream, 1);
else
return -EINVAL;
}
......@@ -1727,7 +1727,7 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,
return 0;
/* bit rate */
old_mode = twl4030_read(codec,
old_mode = twl4030_read(component,
TWL4030_REG_CODEC_MODE) & ~TWL4030_CODECPDZ;
mode = old_mode & ~TWL4030_APLL_RATE;
......@@ -1763,13 +1763,13 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,
mode |= TWL4030_APLL_RATE_96000;
break;
default:
dev_err(codec->dev, "%s: unknown rate %d\n", __func__,
dev_err(component->dev, "%s: unknown rate %d\n", __func__,
params_rate(params));
return -EINVAL;
}
/* sample size */
old_format = twl4030_read(codec, TWL4030_REG_AUDIO_IF);
old_format = twl4030_read(component, TWL4030_REG_AUDIO_IF);
format = old_format;
format &= ~TWL4030_DATA_WIDTH;
switch (params_width(params)) {
......@@ -1780,7 +1780,7 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,
format |= TWL4030_DATA_WIDTH_32S_24W;
break;
default:
dev_err(codec->dev, "%s: unsupported bits/sample %d\n",
dev_err(component->dev, "%s: unsupported bits/sample %d\n",
__func__, params_width(params));
return -EINVAL;
}
......@@ -1791,13 +1791,13 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,
* If the codec is powered, than we need to toggle the
* codec power.
*/
twl4030_codec_enable(codec, 0);
twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode);
twl4030_write(codec, TWL4030_REG_AUDIO_IF, format);
twl4030_codec_enable(codec, 1);
twl4030_codec_enable(component, 0);
twl4030_write(component, TWL4030_REG_CODEC_MODE, mode);
twl4030_write(component, TWL4030_REG_AUDIO_IF, format);
twl4030_codec_enable(component, 1);
} else {
twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode);
twl4030_write(codec, TWL4030_REG_AUDIO_IF, format);
twl4030_write(component, TWL4030_REG_CODEC_MODE, mode);
twl4030_write(component, TWL4030_REG_AUDIO_IF, format);
}
}
......@@ -1821,8 +1821,8 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,
static int twl4030_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id,
unsigned int freq, int dir)
{
struct snd_soc_codec *codec = codec_dai->codec;
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
struct snd_soc_component *component = codec_dai->component;
struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
switch (freq) {
case 19200000:
......@@ -1830,12 +1830,12 @@ static int twl4030_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id,
case 38400000:
break;
default:
dev_err(codec->dev, "Unsupported HFCLKIN: %u\n", freq);
dev_err(component->dev, "Unsupported HFCLKIN: %u\n", freq);
return -EINVAL;
}
if ((freq / 1000) != twl4030->sysclk) {
dev_err(codec->dev,
dev_err(component->dev,
"Mismatch in HFCLKIN: %u (configured: %u)\n",
freq, twl4030->sysclk * 1000);
return -EINVAL;
......@@ -1846,12 +1846,12 @@ static int twl4030_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id,
static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
{
struct snd_soc_codec *codec = codec_dai->codec;
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
struct snd_soc_component *component = codec_dai->component;
struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
u8 old_format, format;
/* get format */
old_format = twl4030_read(codec, TWL4030_REG_AUDIO_IF);
old_format = twl4030_read(component, TWL4030_REG_AUDIO_IF);
format = old_format;
/* set master/slave audio interface */
......@@ -1887,11 +1887,11 @@ static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
* If the codec is powered, than we need to toggle the
* codec power.
*/
twl4030_codec_enable(codec, 0);
twl4030_write(codec, TWL4030_REG_AUDIO_IF, format);
twl4030_codec_enable(codec, 1);
twl4030_codec_enable(component, 0);
twl4030_write(component, TWL4030_REG_AUDIO_IF, format);
twl4030_codec_enable(component, 1);
} else {
twl4030_write(codec, TWL4030_REG_AUDIO_IF, format);
twl4030_write(component, TWL4030_REG_AUDIO_IF, format);
}
}
......@@ -1900,25 +1900,25 @@ static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
static int twl4030_set_tristate(struct snd_soc_dai *dai, int tristate)
{
struct snd_soc_codec *codec = dai->codec;
u8 reg = twl4030_read(codec, TWL4030_REG_AUDIO_IF);
struct snd_soc_component *component = dai->component;
u8 reg = twl4030_read(component, TWL4030_REG_AUDIO_IF);
if (tristate)
reg |= TWL4030_AIF_TRI_EN;
else
reg &= ~TWL4030_AIF_TRI_EN;
return twl4030_write(codec, TWL4030_REG_AUDIO_IF, reg);
return twl4030_write(component, TWL4030_REG_AUDIO_IF, reg);
}
/* In case of voice mode, the RX1 L(VRX) for downlink and the TX2 L/R
* (VTXL, VTXR) for uplink has to be enabled/disabled. */
static void twl4030_voice_enable(struct snd_soc_codec *codec, int direction,
static void twl4030_voice_enable(struct snd_soc_component *component, int direction,
int enable)
{
u8 reg, mask;
reg = twl4030_read(codec, TWL4030_REG_OPTION);
reg = twl4030_read(component, TWL4030_REG_OPTION);
if (direction == SNDRV_PCM_STREAM_PLAYBACK)
mask = TWL4030_ARXL1_VRX_EN;
......@@ -1930,21 +1930,21 @@ static void twl4030_voice_enable(struct snd_soc_codec *codec, int direction,
else
reg &= ~mask;
twl4030_write(codec, TWL4030_REG_OPTION, reg);
twl4030_write(component, TWL4030_REG_OPTION, reg);
}
static int twl4030_voice_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
struct snd_soc_component *component = dai->component;
struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
u8 mode;
/* If the system master clock is not 26MHz, the voice PCM interface is
* not available.
*/
if (twl4030->sysclk != 26000) {
dev_err(codec->dev,
dev_err(component->dev,
"%s: HFCLKIN is %u KHz, voice interface needs 26MHz\n",
__func__, twl4030->sysclk);
return -EINVAL;
......@@ -1953,11 +1953,11 @@ static int twl4030_voice_startup(struct snd_pcm_substream *substream,
/* If the codec mode is not option2, the voice PCM interface is not
* available.
*/
mode = twl4030_read(codec, TWL4030_REG_CODEC_MODE)
mode = twl4030_read(component, TWL4030_REG_CODEC_MODE)
& TWL4030_OPT_MODE;
if (mode != TWL4030_OPTION_2) {
dev_err(codec->dev, "%s: the codec mode is not option2\n",
dev_err(component->dev, "%s: the codec mode is not option2\n",
__func__);
return -EINVAL;
}
......@@ -1968,25 +1968,25 @@ static int twl4030_voice_startup(struct snd_pcm_substream *substream,
static void twl4030_voice_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
struct snd_soc_component *component = dai->component;
/* Enable voice digital filters */
twl4030_voice_enable(codec, substream->stream, 0);
twl4030_voice_enable(component, substream->stream, 0);
}
static int twl4030_voice_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
struct snd_soc_component *component = dai->component;
struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
u8 old_mode, mode;
/* Enable voice digital filters */
twl4030_voice_enable(codec, substream->stream, 1);
twl4030_voice_enable(component, substream->stream, 1);
/* bit rate */
old_mode = twl4030_read(codec,
old_mode = twl4030_read(component,
TWL4030_REG_CODEC_MODE) & ~TWL4030_CODECPDZ;
mode = old_mode;
......@@ -1998,7 +1998,7 @@ static int twl4030_voice_hw_params(struct snd_pcm_substream *substream,
mode |= TWL4030_SEL_16K;
break;
default:
dev_err(codec->dev, "%s: unknown rate %d\n", __func__,
dev_err(component->dev, "%s: unknown rate %d\n", __func__,
params_rate(params));
return -EINVAL;
}
......@@ -2009,11 +2009,11 @@ static int twl4030_voice_hw_params(struct snd_pcm_substream *substream,
* If the codec is powered, than we need to toggle the
* codec power.
*/
twl4030_codec_enable(codec, 0);
twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode);
twl4030_codec_enable(codec, 1);
twl4030_codec_enable(component, 0);
twl4030_write(component, TWL4030_REG_CODEC_MODE, mode);
twl4030_codec_enable(component, 1);
} else {
twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode);
twl4030_write(component, TWL4030_REG_CODEC_MODE, mode);
}
}
......@@ -2023,17 +2023,17 @@ static int twl4030_voice_hw_params(struct snd_pcm_substream *substream,
static int twl4030_voice_set_dai_sysclk(struct snd_soc_dai *codec_dai,
int clk_id, unsigned int freq, int dir)
{
struct snd_soc_codec *codec = codec_dai->codec;
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
struct snd_soc_component *component = codec_dai->component;
struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
if (freq != 26000000) {
dev_err(codec->dev,
dev_err(component->dev,
"%s: HFCLKIN is %u KHz, voice interface needs 26MHz\n",
__func__, freq / 1000);
return -EINVAL;
}
if ((freq / 1000) != twl4030->sysclk) {
dev_err(codec->dev,
dev_err(component->dev,
"Mismatch in HFCLKIN: %u (configured: %u)\n",
freq, twl4030->sysclk * 1000);
return -EINVAL;
......@@ -2044,12 +2044,12 @@ static int twl4030_voice_set_dai_sysclk(struct snd_soc_dai *codec_dai,
static int twl4030_voice_set_dai_fmt(struct snd_soc_dai *codec_dai,
unsigned int fmt)
{
struct snd_soc_codec *codec = codec_dai->codec;
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
struct snd_soc_component *component = codec_dai->component;
struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
u8 old_format, format;
/* get format */
old_format = twl4030_read(codec, TWL4030_REG_VOICE_IF);
old_format = twl4030_read(component, TWL4030_REG_VOICE_IF);
format = old_format;
/* set master/slave audio interface */
......@@ -2082,11 +2082,11 @@ static int twl4030_voice_set_dai_fmt(struct snd_soc_dai *codec_dai,
* If the codec is powered, than we need to toggle the
* codec power.
*/
twl4030_codec_enable(codec, 0);
twl4030_write(codec, TWL4030_REG_VOICE_IF, format);
twl4030_codec_enable(codec, 1);
twl4030_codec_enable(component, 0);
twl4030_write(component, TWL4030_REG_VOICE_IF, format);
twl4030_codec_enable(component, 1);
} else {
twl4030_write(codec, TWL4030_REG_VOICE_IF, format);
twl4030_write(component, TWL4030_REG_VOICE_IF, format);
}
}
......@@ -2095,15 +2095,15 @@ static int twl4030_voice_set_dai_fmt(struct snd_soc_dai *codec_dai,
static int twl4030_voice_set_tristate(struct snd_soc_dai *dai, int tristate)
{
struct snd_soc_codec *codec = dai->codec;
u8 reg = twl4030_read(codec, TWL4030_REG_VOICE_IF);
struct snd_soc_component *component = dai->component;
u8 reg = twl4030_read(component, TWL4030_REG_VOICE_IF);
if (tristate)
reg |= TWL4030_VIF_TRI_EN;
else
reg &= ~TWL4030_VIF_TRI_EN;
return twl4030_write(codec, TWL4030_REG_VOICE_IF, reg);
return twl4030_write(component, TWL4030_REG_VOICE_IF, reg);
}
#define TWL4030_RATES (SNDRV_PCM_RATE_8000_48000)
......@@ -2164,69 +2164,60 @@ static struct snd_soc_dai_driver twl4030_dai[] = {
},
};
static int twl4030_soc_probe(struct snd_soc_codec *codec)
static int twl4030_soc_probe(struct snd_soc_component *component)
{
struct twl4030_priv *twl4030;
twl4030 = devm_kzalloc(codec->dev, sizeof(struct twl4030_priv),
twl4030 = devm_kzalloc(component->dev, sizeof(struct twl4030_priv),
GFP_KERNEL);
if (!twl4030)
return -ENOMEM;
snd_soc_codec_set_drvdata(codec, twl4030);
snd_soc_component_set_drvdata(component, twl4030);
/* Set the defaults, and power up the codec */
twl4030->sysclk = twl4030_audio_get_mclk() / 1000;
twl4030_init_chip(codec);
twl4030_init_chip(component);
return 0;
}
static int twl4030_soc_remove(struct snd_soc_codec *codec)
static void twl4030_soc_remove(struct snd_soc_component *component)
{
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
struct twl4030_codec_data *pdata = twl4030->pdata;
if (pdata && pdata->hs_extmute && gpio_is_valid(pdata->hs_extmute_gpio))
gpio_free(pdata->hs_extmute_gpio);
return 0;
}
static const struct snd_soc_codec_driver soc_codec_dev_twl4030 = {
.probe = twl4030_soc_probe,
.remove = twl4030_soc_remove,
.read = twl4030_read,
.write = twl4030_write,
.set_bias_level = twl4030_set_bias_level,
.idle_bias_off = true,
.component_driver = {
.controls = twl4030_snd_controls,
.num_controls = ARRAY_SIZE(twl4030_snd_controls),
.dapm_widgets = twl4030_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(twl4030_dapm_widgets),
.dapm_routes = intercon,
.num_dapm_routes = ARRAY_SIZE(intercon),
},
static const struct snd_soc_component_driver soc_component_dev_twl4030 = {
.probe = twl4030_soc_probe,
.remove = twl4030_soc_remove,
.read = twl4030_read,
.write = twl4030_write,
.set_bias_level = twl4030_set_bias_level,
.controls = twl4030_snd_controls,
.num_controls = ARRAY_SIZE(twl4030_snd_controls),
.dapm_widgets = twl4030_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(twl4030_dapm_widgets),
.dapm_routes = intercon,
.num_dapm_routes = ARRAY_SIZE(intercon),
.use_pmdown_time = 1,
.endianness = 1,
.non_legacy_dai_naming = 1,
};
static int twl4030_codec_probe(struct platform_device *pdev)
{
return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_twl4030,
return devm_snd_soc_register_component(&pdev->dev,
&soc_component_dev_twl4030,
twl4030_dai, ARRAY_SIZE(twl4030_dai));
}
static int twl4030_codec_remove(struct platform_device *pdev)
{
snd_soc_unregister_codec(&pdev->dev);
return 0;
}
MODULE_ALIAS("platform:twl4030-codec");
static struct platform_driver twl4030_codec_driver = {
.probe = twl4030_codec_probe,
.remove = twl4030_codec_remove,
.driver = {
.name = "twl4030-codec",
},
......
......@@ -76,7 +76,7 @@ struct twl6040_data {
unsigned int clk_in;
unsigned int sysclk;
struct twl6040_jack_data hs_jack;
struct snd_soc_codec *codec;
struct snd_soc_component *component;
struct mutex mutex;
};
......@@ -106,12 +106,12 @@ static const struct snd_pcm_hw_constraint_list sysclk_constraints[] = {
{ .count = ARRAY_SIZE(hp_rates), .list = hp_rates, },
};
#define to_twl6040(codec) dev_get_drvdata((codec)->dev->parent)
#define to_twl6040(component) dev_get_drvdata((component)->dev->parent)
static unsigned int twl6040_read(struct snd_soc_codec *codec, unsigned int reg)
static unsigned int twl6040_read(struct snd_soc_component *component, unsigned int reg)
{
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
struct twl6040 *twl6040 = to_twl6040(codec);
struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
struct twl6040 *twl6040 = to_twl6040(component);
u8 value;
if (reg >= TWL6040_CACHEREGNUM)
......@@ -133,10 +133,10 @@ static unsigned int twl6040_read(struct snd_soc_codec *codec, unsigned int reg)
return value;
}
static bool twl6040_can_write_to_chip(struct snd_soc_codec *codec,
static bool twl6040_can_write_to_chip(struct snd_soc_component *component,
unsigned int reg)
{
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
switch (reg) {
case TWL6040_REG_HSLCTL:
......@@ -152,10 +152,10 @@ static bool twl6040_can_write_to_chip(struct snd_soc_codec *codec,
}
}
static inline void twl6040_update_dl12_cache(struct snd_soc_codec *codec,
static inline void twl6040_update_dl12_cache(struct snd_soc_component *component,
u8 reg, u8 value)
{
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
switch (reg) {
case TWL6040_REG_HSLCTL:
......@@ -170,54 +170,54 @@ static inline void twl6040_update_dl12_cache(struct snd_soc_codec *codec,
}
}
static int twl6040_write(struct snd_soc_codec *codec,
static int twl6040_write(struct snd_soc_component *component,
unsigned int reg, unsigned int value)
{
struct twl6040 *twl6040 = to_twl6040(codec);
struct twl6040 *twl6040 = to_twl6040(component);
if (reg >= TWL6040_CACHEREGNUM)
return -EIO;
twl6040_update_dl12_cache(codec, reg, value);
if (twl6040_can_write_to_chip(codec, reg))
twl6040_update_dl12_cache(component, reg, value);
if (twl6040_can_write_to_chip(component, reg))
return twl6040_reg_write(twl6040, reg, value);
else
return 0;
}
static void twl6040_init_chip(struct snd_soc_codec *codec)
static void twl6040_init_chip(struct snd_soc_component *component)
{
twl6040_read(codec, TWL6040_REG_TRIM1);
twl6040_read(codec, TWL6040_REG_TRIM2);
twl6040_read(codec, TWL6040_REG_TRIM3);
twl6040_read(codec, TWL6040_REG_HSOTRIM);
twl6040_read(codec, TWL6040_REG_HFOTRIM);
twl6040_read(component, TWL6040_REG_TRIM1);
twl6040_read(component, TWL6040_REG_TRIM2);
twl6040_read(component, TWL6040_REG_TRIM3);
twl6040_read(component, TWL6040_REG_HSOTRIM);
twl6040_read(component, TWL6040_REG_HFOTRIM);
/* Change chip defaults */
/* No imput selected for microphone amplifiers */
twl6040_write(codec, TWL6040_REG_MICLCTL, 0x18);
twl6040_write(codec, TWL6040_REG_MICRCTL, 0x18);
twl6040_write(component, TWL6040_REG_MICLCTL, 0x18);
twl6040_write(component, TWL6040_REG_MICRCTL, 0x18);
/*
* We need to lower the default gain values, so the ramp code
* can work correctly for the first playback.
* This reduces the pop noise heard at the first playback.
*/
twl6040_write(codec, TWL6040_REG_HSGAIN, 0xff);
twl6040_write(codec, TWL6040_REG_EARCTL, 0x1e);
twl6040_write(codec, TWL6040_REG_HFLGAIN, 0x1d);
twl6040_write(codec, TWL6040_REG_HFRGAIN, 0x1d);
twl6040_write(codec, TWL6040_REG_LINEGAIN, 0);
twl6040_write(component, TWL6040_REG_HSGAIN, 0xff);
twl6040_write(component, TWL6040_REG_EARCTL, 0x1e);
twl6040_write(component, TWL6040_REG_HFLGAIN, 0x1d);
twl6040_write(component, TWL6040_REG_HFRGAIN, 0x1d);
twl6040_write(component, TWL6040_REG_LINEGAIN, 0);
}
/* set headset dac and driver power mode */
static int headset_power_mode(struct snd_soc_codec *codec, int high_perf)
static int headset_power_mode(struct snd_soc_component *component, int high_perf)
{
int hslctl, hsrctl;
int mask = TWL6040_HSDRVMODE | TWL6040_HSDACMODE;
hslctl = twl6040_read(codec, TWL6040_REG_HSLCTL);
hsrctl = twl6040_read(codec, TWL6040_REG_HSRCTL);
hslctl = twl6040_read(component, TWL6040_REG_HSLCTL);
hsrctl = twl6040_read(component, TWL6040_REG_HSRCTL);
if (high_perf) {
hslctl &= ~mask;
......@@ -227,8 +227,8 @@ static int headset_power_mode(struct snd_soc_codec *codec, int high_perf)
hsrctl |= mask;
}
twl6040_write(codec, TWL6040_REG_HSLCTL, hslctl);
twl6040_write(codec, TWL6040_REG_HSRCTL, hsrctl);
twl6040_write(component, TWL6040_REG_HSLCTL, hslctl);
twl6040_write(component, TWL6040_REG_HSRCTL, hsrctl);
return 0;
}
......@@ -236,7 +236,7 @@ static int headset_power_mode(struct snd_soc_codec *codec, int high_perf)
static int twl6040_hs_dac_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
u8 hslctl, hsrctl;
/*
......@@ -244,8 +244,8 @@ static int twl6040_hs_dac_event(struct snd_soc_dapm_widget *w,
* Both HS DAC need to be turned on (before the HS driver) and off at
* the same time.
*/
hslctl = twl6040_read(codec, TWL6040_REG_HSLCTL);
hsrctl = twl6040_read(codec, TWL6040_REG_HSRCTL);
hslctl = twl6040_read(component, TWL6040_REG_HSLCTL);
hsrctl = twl6040_read(component, TWL6040_REG_HSRCTL);
if (SND_SOC_DAPM_EVENT_ON(event)) {
hslctl |= TWL6040_HSDACENA;
hsrctl |= TWL6040_HSDACENA;
......@@ -253,8 +253,8 @@ static int twl6040_hs_dac_event(struct snd_soc_dapm_widget *w,
hslctl &= ~TWL6040_HSDACENA;
hsrctl &= ~TWL6040_HSDACENA;
}
twl6040_write(codec, TWL6040_REG_HSLCTL, hslctl);
twl6040_write(codec, TWL6040_REG_HSRCTL, hsrctl);
twl6040_write(component, TWL6040_REG_HSLCTL, hslctl);
twl6040_write(component, TWL6040_REG_HSRCTL, hsrctl);
msleep(1);
return 0;
......@@ -263,17 +263,17 @@ static int twl6040_hs_dac_event(struct snd_soc_dapm_widget *w,
static int twl6040_ep_drv_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
int ret = 0;
if (SND_SOC_DAPM_EVENT_ON(event)) {
/* Earphone doesn't support low power mode */
priv->hs_power_mode_locked = 1;
ret = headset_power_mode(codec, 1);
ret = headset_power_mode(component, 1);
} else {
priv->hs_power_mode_locked = 0;
ret = headset_power_mode(codec, priv->hs_power_mode);
ret = headset_power_mode(component, priv->hs_power_mode);
}
msleep(1);
......@@ -281,16 +281,16 @@ static int twl6040_ep_drv_event(struct snd_soc_dapm_widget *w,
return ret;
}
static void twl6040_hs_jack_report(struct snd_soc_codec *codec,
static void twl6040_hs_jack_report(struct snd_soc_component *component,
struct snd_soc_jack *jack, int report)
{
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
int status;
mutex_lock(&priv->mutex);
/* Sync status */
status = twl6040_read(codec, TWL6040_REG_STATUS);
status = twl6040_read(component, TWL6040_REG_STATUS);
if (status & TWL6040_PLUGCOMP)
snd_soc_jack_report(jack, report, report);
else
......@@ -299,16 +299,16 @@ static void twl6040_hs_jack_report(struct snd_soc_codec *codec,
mutex_unlock(&priv->mutex);
}
void twl6040_hs_jack_detect(struct snd_soc_codec *codec,
void twl6040_hs_jack_detect(struct snd_soc_component *component,
struct snd_soc_jack *jack, int report)
{
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
struct twl6040_jack_data *hs_jack = &priv->hs_jack;
hs_jack->jack = jack;
hs_jack->report = report;
twl6040_hs_jack_report(codec, hs_jack->jack, hs_jack->report);
twl6040_hs_jack_report(component, hs_jack->jack, hs_jack->report);
}
EXPORT_SYMBOL_GPL(twl6040_hs_jack_detect);
......@@ -316,17 +316,17 @@ static void twl6040_accessory_work(struct work_struct *work)
{
struct twl6040_data *priv = container_of(work,
struct twl6040_data, hs_jack.work.work);
struct snd_soc_codec *codec = priv->codec;
struct snd_soc_component *component = priv->component;
struct twl6040_jack_data *hs_jack = &priv->hs_jack;
twl6040_hs_jack_report(codec, hs_jack->jack, hs_jack->report);
twl6040_hs_jack_report(component, hs_jack->jack, hs_jack->report);
}
/* audio interrupt handler */
static irqreturn_t twl6040_audio_handler(int irq, void *data)
{
struct snd_soc_codec *codec = data;
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
struct snd_soc_component *component = data;
struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
queue_delayed_work(system_power_efficient_wq,
&priv->hs_jack.work, msecs_to_jiffies(200));
......@@ -337,12 +337,12 @@ static irqreturn_t twl6040_audio_handler(int irq, void *data)
static int twl6040_soc_dapm_put_vibra_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int val;
/* Do not allow changes while Input/FF efect is running */
val = twl6040_read(codec, e->reg);
val = twl6040_read(component, e->reg);
if (val & TWL6040_VIBENA && !(val & TWL6040_VIBSEL))
return -EBUSY;
......@@ -486,8 +486,8 @@ static SOC_ENUM_SINGLE_EXT_DECL(twl6040_power_mode_enum,
static int twl6040_headset_power_get_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
ucontrol->value.enumerated.item[0] = priv->hs_power_mode;
......@@ -497,13 +497,13 @@ static int twl6040_headset_power_get_enum(struct snd_kcontrol *kcontrol,
static int twl6040_headset_power_put_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
int high_perf = ucontrol->value.enumerated.item[0];
int ret = 0;
if (!priv->hs_power_mode_locked)
ret = headset_power_mode(codec, high_perf);
ret = headset_power_mode(component, high_perf);
if (!ret)
priv->hs_power_mode = high_perf;
......@@ -514,8 +514,8 @@ static int twl6040_headset_power_put_enum(struct snd_kcontrol *kcontrol,
static int twl6040_pll_get_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
ucontrol->value.enumerated.item[0] = priv->pll_power_mode;
......@@ -525,17 +525,17 @@ static int twl6040_pll_get_enum(struct snd_kcontrol *kcontrol,
static int twl6040_pll_put_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
priv->pll_power_mode = ucontrol->value.enumerated.item[0];
return 0;
}
int twl6040_get_dl1_gain(struct snd_soc_codec *codec)
int twl6040_get_dl1_gain(struct snd_soc_component *component)
{
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
if (snd_soc_dapm_get_pin_status(dapm, "EP"))
return -1; /* -1dB */
......@@ -543,7 +543,7 @@ int twl6040_get_dl1_gain(struct snd_soc_codec *codec)
if (snd_soc_dapm_get_pin_status(dapm, "HSOR") ||
snd_soc_dapm_get_pin_status(dapm, "HSOL")) {
u8 val = twl6040_read(codec, TWL6040_REG_HSLCTL);
u8 val = twl6040_read(component, TWL6040_REG_HSLCTL);
if (val & TWL6040_HSDACMODE)
/* HSDACL in LP mode */
return -8; /* -8dB */
......@@ -555,26 +555,26 @@ int twl6040_get_dl1_gain(struct snd_soc_codec *codec)
}
EXPORT_SYMBOL_GPL(twl6040_get_dl1_gain);
int twl6040_get_clk_id(struct snd_soc_codec *codec)
int twl6040_get_clk_id(struct snd_soc_component *component)
{
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
return priv->pll_power_mode;
}
EXPORT_SYMBOL_GPL(twl6040_get_clk_id);
int twl6040_get_trim_value(struct snd_soc_codec *codec, enum twl6040_trim trim)
int twl6040_get_trim_value(struct snd_soc_component *component, enum twl6040_trim trim)
{
if (unlikely(trim >= TWL6040_TRIM_INVAL))
return -EINVAL;
return twl6040_read(codec, TWL6040_REG_TRIM1 + trim);
return twl6040_read(component, TWL6040_REG_TRIM1 + trim);
}
EXPORT_SYMBOL_GPL(twl6040_get_trim_value);
int twl6040_get_hs_step_size(struct snd_soc_codec *codec)
int twl6040_get_hs_step_size(struct snd_soc_component *component)
{
struct twl6040 *twl6040 = to_twl6040(codec);
struct twl6040 *twl6040 = to_twl6040(component);
if (twl6040_get_revid(twl6040) < TWL6040_REV_ES1_3)
/* For ES under ES_1.3 HS step is 2 mV */
......@@ -829,11 +829,11 @@ static const struct snd_soc_dapm_route intercon[] = {
{"VIBRAR", NULL, "Vibra Right Driver"},
};
static int twl6040_set_bias_level(struct snd_soc_codec *codec,
static int twl6040_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct twl6040 *twl6040 = to_twl6040(codec);
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
struct twl6040 *twl6040 = to_twl6040(component);
struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
int ret = 0;
switch (level) {
......@@ -856,7 +856,7 @@ static int twl6040_set_bias_level(struct snd_soc_codec *codec,
priv->codec_powered = 1;
/* Set external boost GPO */
twl6040_write(codec, TWL6040_REG_GPOCTL, 0x02);
twl6040_write(component, TWL6040_REG_GPOCTL, 0x02);
break;
case SND_SOC_BIAS_OFF:
if (!priv->codec_powered)
......@@ -873,8 +873,8 @@ static int twl6040_set_bias_level(struct snd_soc_codec *codec,
static int twl6040_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
struct snd_soc_component *component = dai->component;
struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
snd_pcm_hw_constraint_list(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_RATE,
......@@ -887,8 +887,8 @@ static int twl6040_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
struct snd_soc_component *component = dai->component;
struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
int rate;
rate = params_rate(params);
......@@ -899,7 +899,7 @@ static int twl6040_hw_params(struct snd_pcm_substream *substream,
case 88200:
/* These rates are not supported when HPPLL is in use */
if (unlikely(priv->pll == TWL6040_SYSCLK_SEL_HPPLL)) {
dev_err(codec->dev, "HPPLL does not support rate %d\n",
dev_err(component->dev, "HPPLL does not support rate %d\n",
rate);
return -EINVAL;
}
......@@ -913,7 +913,7 @@ static int twl6040_hw_params(struct snd_pcm_substream *substream,
priv->sysclk = 19200000;
break;
default:
dev_err(codec->dev, "unsupported rate %d\n", rate);
dev_err(component->dev, "unsupported rate %d\n", rate);
return -EINVAL;
}
......@@ -923,20 +923,20 @@ static int twl6040_hw_params(struct snd_pcm_substream *substream,
static int twl6040_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
struct twl6040 *twl6040 = to_twl6040(codec);
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
struct snd_soc_component *component = dai->component;
struct twl6040 *twl6040 = to_twl6040(component);
struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
int ret;
if (!priv->sysclk) {
dev_err(codec->dev,
dev_err(component->dev,
"no mclk configured, call set_sysclk() on init\n");
return -EINVAL;
}
ret = twl6040_set_pll(twl6040, priv->pll, priv->clk_in, priv->sysclk);
if (ret) {
dev_err(codec->dev, "Can not set PLL (%d)\n", ret);
dev_err(component->dev, "Can not set PLL (%d)\n", ret);
return -EPERM;
}
......@@ -946,8 +946,8 @@ static int twl6040_prepare(struct snd_pcm_substream *substream,
static int twl6040_set_dai_sysclk(struct snd_soc_dai *codec_dai,
int clk_id, unsigned int freq, int dir)
{
struct snd_soc_codec *codec = codec_dai->codec;
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
struct snd_soc_component *component = codec_dai->component;
struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
switch (clk_id) {
case TWL6040_SYSCLK_SEL_LPPLL:
......@@ -956,26 +956,26 @@ static int twl6040_set_dai_sysclk(struct snd_soc_dai *codec_dai,
priv->clk_in = freq;
break;
default:
dev_err(codec->dev, "unknown clk_id %d\n", clk_id);
dev_err(component->dev, "unknown clk_id %d\n", clk_id);
return -EINVAL;
}
return 0;
}
static void twl6040_mute_path(struct snd_soc_codec *codec, enum twl6040_dai_id id,
static void twl6040_mute_path(struct snd_soc_component *component, enum twl6040_dai_id id,
int mute)
{
struct twl6040 *twl6040 = to_twl6040(codec);
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
struct twl6040 *twl6040 = to_twl6040(component);
struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
int hslctl, hsrctl, earctl;
int hflctl, hfrctl;
switch (id) {
case TWL6040_DAI_DL1:
hslctl = twl6040_read(codec, TWL6040_REG_HSLCTL);
hsrctl = twl6040_read(codec, TWL6040_REG_HSRCTL);
earctl = twl6040_read(codec, TWL6040_REG_EARCTL);
hslctl = twl6040_read(component, TWL6040_REG_HSLCTL);
hsrctl = twl6040_read(component, TWL6040_REG_HSRCTL);
earctl = twl6040_read(component, TWL6040_REG_EARCTL);
if (mute) {
/* Power down drivers and DACs */
......@@ -991,8 +991,8 @@ static void twl6040_mute_path(struct snd_soc_codec *codec, enum twl6040_dai_id i
priv->dl1_unmuted = !mute;
break;
case TWL6040_DAI_DL2:
hflctl = twl6040_read(codec, TWL6040_REG_HFLCTL);
hfrctl = twl6040_read(codec, TWL6040_REG_HFRCTL);
hflctl = twl6040_read(component, TWL6040_REG_HFLCTL);
hfrctl = twl6040_read(component, TWL6040_REG_HFRCTL);
if (mute) {
/* Power down drivers and DACs */
......@@ -1015,12 +1015,12 @@ static int twl6040_digital_mute(struct snd_soc_dai *dai, int mute)
{
switch (dai->id) {
case TWL6040_DAI_LEGACY:
twl6040_mute_path(dai->codec, TWL6040_DAI_DL1, mute);
twl6040_mute_path(dai->codec, TWL6040_DAI_DL2, mute);
twl6040_mute_path(dai->component, TWL6040_DAI_DL1, mute);
twl6040_mute_path(dai->component, TWL6040_DAI_DL2, mute);
break;
case TWL6040_DAI_DL1:
case TWL6040_DAI_DL2:
twl6040_mute_path(dai->codec, dai->id, mute);
twl6040_mute_path(dai->component, dai->id, mute);
break;
default:
break;
......@@ -1107,23 +1107,23 @@ static struct snd_soc_dai_driver twl6040_dai[] = {
},
};
static int twl6040_probe(struct snd_soc_codec *codec)
static int twl6040_probe(struct snd_soc_component *component)
{
struct twl6040_data *priv;
struct platform_device *pdev = to_platform_device(codec->dev);
struct platform_device *pdev = to_platform_device(component->dev);
int ret = 0;
priv = devm_kzalloc(codec->dev, sizeof(*priv), GFP_KERNEL);
priv = devm_kzalloc(component->dev, sizeof(*priv), GFP_KERNEL);
if (priv == NULL)
return -ENOMEM;
snd_soc_codec_set_drvdata(codec, priv);
snd_soc_component_set_drvdata(component, priv);
priv->codec = codec;
priv->component = component;
priv->plug_irq = platform_get_irq(pdev, 0);
if (priv->plug_irq < 0) {
dev_err(codec->dev, "invalid irq: %d\n", priv->plug_irq);
dev_err(component->dev, "invalid irq: %d\n", priv->plug_irq);
return priv->plug_irq;
}
......@@ -1134,64 +1134,55 @@ static int twl6040_probe(struct snd_soc_codec *codec)
ret = request_threaded_irq(priv->plug_irq, NULL,
twl6040_audio_handler,
IRQF_NO_SUSPEND | IRQF_ONESHOT,
"twl6040_irq_plug", codec);
"twl6040_irq_plug", component);
if (ret) {
dev_err(codec->dev, "PLUG IRQ request failed: %d\n", ret);
dev_err(component->dev, "PLUG IRQ request failed: %d\n", ret);
return ret;
}
snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
twl6040_init_chip(codec);
snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
twl6040_init_chip(component);
return 0;
}
static int twl6040_remove(struct snd_soc_codec *codec)
static void twl6040_remove(struct snd_soc_component *component)
{
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
free_irq(priv->plug_irq, codec);
return 0;
free_irq(priv->plug_irq, component);
}
static const struct snd_soc_codec_driver soc_codec_dev_twl6040 = {
.probe = twl6040_probe,
.remove = twl6040_remove,
.read = twl6040_read,
.write = twl6040_write,
.set_bias_level = twl6040_set_bias_level,
.suspend_bias_off = true,
.ignore_pmdown_time = true,
.component_driver = {
.controls = twl6040_snd_controls,
.num_controls = ARRAY_SIZE(twl6040_snd_controls),
.dapm_widgets = twl6040_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(twl6040_dapm_widgets),
.dapm_routes = intercon,
.num_dapm_routes = ARRAY_SIZE(intercon),
},
static const struct snd_soc_component_driver soc_component_dev_twl6040 = {
.probe = twl6040_probe,
.remove = twl6040_remove,
.read = twl6040_read,
.write = twl6040_write,
.set_bias_level = twl6040_set_bias_level,
.controls = twl6040_snd_controls,
.num_controls = ARRAY_SIZE(twl6040_snd_controls),
.dapm_widgets = twl6040_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(twl6040_dapm_widgets),
.dapm_routes = intercon,
.num_dapm_routes = ARRAY_SIZE(intercon),
.suspend_bias_off = 1,
.idle_bias_on = 1,
.endianness = 1,
.non_legacy_dai_naming = 1,
};
static int twl6040_codec_probe(struct platform_device *pdev)
{
return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_twl6040,
return devm_snd_soc_register_component(&pdev->dev,
&soc_component_dev_twl6040,
twl6040_dai, ARRAY_SIZE(twl6040_dai));
}
static int twl6040_codec_remove(struct platform_device *pdev)
{
snd_soc_unregister_codec(&pdev->dev);
return 0;
}
static struct platform_driver twl6040_codec_driver = {
.driver = {
.name = "twl6040-codec",
},
.probe = twl6040_codec_probe,
.remove = twl6040_codec_remove,
};
module_platform_driver(twl6040_codec_driver);
......
......@@ -34,11 +34,11 @@ enum twl6040_trim {
#define TWL6040_HSF_TRIM_LEFT(x) (x & 0x0f)
#define TWL6040_HSF_TRIM_RIGHT(x) ((x >> 4) & 0x0f)
int twl6040_get_dl1_gain(struct snd_soc_codec *codec);
void twl6040_hs_jack_detect(struct snd_soc_codec *codec,
int twl6040_get_dl1_gain(struct snd_soc_component *component);
void twl6040_hs_jack_detect(struct snd_soc_component *component,
struct snd_soc_jack *jack, int report);
int twl6040_get_clk_id(struct snd_soc_codec *codec);
int twl6040_get_trim_value(struct snd_soc_codec *codec, enum twl6040_trim trim);
int twl6040_get_hs_step_size(struct snd_soc_codec *codec);
int twl6040_get_clk_id(struct snd_soc_component *component);
int twl6040_get_trim_value(struct snd_soc_component *component, enum twl6040_trim trim);
int twl6040_get_hs_step_size(struct snd_soc_component *component);
#endif /* End of __TWL6040_H__ */
......@@ -110,9 +110,9 @@ static int uda134x_regmap_write(void *context, unsigned int reg,
return 0;
}
static inline void uda134x_reset(struct snd_soc_codec *codec)
static inline void uda134x_reset(struct snd_soc_component *component)
{
struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component);
unsigned int mask = 1<<6;
regmap_update_bits(uda134x->regmap, UDA134X_STATUS0, mask, mask);
......@@ -122,7 +122,7 @@ static inline void uda134x_reset(struct snd_soc_codec *codec)
static int uda134x_mute(struct snd_soc_dai *dai, int mute)
{
struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(dai->codec);
struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(dai->component);
unsigned int mask = 1<<2;
unsigned int val;
......@@ -139,8 +139,8 @@ static int uda134x_mute(struct snd_soc_dai *dai, int mute)
static int uda134x_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
struct snd_soc_component *component = dai->component;
struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component);
struct snd_pcm_runtime *master_runtime;
if (uda134x->master_substream) {
......@@ -168,8 +168,8 @@ static int uda134x_startup(struct snd_pcm_substream *substream,
static void uda134x_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
struct snd_soc_component *component = dai->component;
struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component);
if (uda134x->master_substream == substream)
uda134x->master_substream = uda134x->slave_substream;
......@@ -181,8 +181,8 @@ static int uda134x_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
struct snd_soc_component *component = dai->component;
struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component);
unsigned int hw_params = 0;
if (substream == uda134x->slave_substream) {
......@@ -248,8 +248,8 @@ static int uda134x_hw_params(struct snd_pcm_substream *substream,
static int uda134x_set_dai_sysclk(struct snd_soc_dai *codec_dai,
int clk_id, unsigned int freq, int dir)
{
struct snd_soc_codec *codec = codec_dai->codec;
struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
struct snd_soc_component *component = codec_dai->component;
struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component);
pr_debug("%s clk_id: %d, freq: %u, dir: %d\n", __func__,
clk_id, freq, dir);
......@@ -270,8 +270,8 @@ static int uda134x_set_dai_sysclk(struct snd_soc_dai *codec_dai,
static int uda134x_set_dai_fmt(struct snd_soc_dai *codec_dai,
unsigned int fmt)
{
struct snd_soc_codec *codec = codec_dai->codec;
struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
struct snd_soc_component *component = codec_dai->component;
struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component);
pr_debug("%s fmt: %08X\n", __func__, fmt);
......@@ -294,10 +294,10 @@ static int uda134x_set_dai_fmt(struct snd_soc_dai *codec_dai,
return 0;
}
static int uda134x_set_bias_level(struct snd_soc_codec *codec,
static int uda134x_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component);
struct uda134x_platform_data *pd = uda134x->pd;
pr_debug("%s bias level %d\n", __func__, level);
......@@ -446,10 +446,10 @@ static struct snd_soc_dai_driver uda134x_dai = {
.ops = &uda134x_dai_ops,
};
static int uda134x_soc_probe(struct snd_soc_codec *codec)
static int uda134x_soc_probe(struct snd_soc_component *component)
{
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component);
struct uda134x_platform_data *pd = uda134x->pd;
const struct snd_soc_dapm_widget *widgets;
unsigned num_widgets;
......@@ -473,7 +473,7 @@ static int uda134x_soc_probe(struct snd_soc_codec *codec)
if (pd->power)
pd->power(1);
uda134x_reset(codec);
uda134x_reset(component);
if (pd->model == UDA134X_UDA1341) {
widgets = uda1341_dapm_widgets;
......@@ -493,15 +493,15 @@ static int uda134x_soc_probe(struct snd_soc_codec *codec)
switch (pd->model) {
case UDA134X_UDA1340:
case UDA134X_UDA1344:
ret = snd_soc_add_codec_controls(codec, uda1340_snd_controls,
ret = snd_soc_add_component_controls(component, uda1340_snd_controls,
ARRAY_SIZE(uda1340_snd_controls));
break;
case UDA134X_UDA1341:
ret = snd_soc_add_codec_controls(codec, uda1341_snd_controls,
ret = snd_soc_add_component_controls(component, uda1341_snd_controls,
ARRAY_SIZE(uda1341_snd_controls));
break;
case UDA134X_UDA1345:
ret = snd_soc_add_codec_controls(codec, uda1345_snd_controls,
ret = snd_soc_add_component_controls(component, uda1345_snd_controls,
ARRAY_SIZE(uda1345_snd_controls));
break;
default:
......@@ -518,17 +518,18 @@ static int uda134x_soc_probe(struct snd_soc_codec *codec)
return 0;
}
static const struct snd_soc_codec_driver soc_codec_dev_uda134x = {
.probe = uda134x_soc_probe,
.set_bias_level = uda134x_set_bias_level,
.suspend_bias_off = true,
.component_driver = {
.dapm_widgets = uda134x_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(uda134x_dapm_widgets),
.dapm_routes = uda134x_dapm_routes,
.num_dapm_routes = ARRAY_SIZE(uda134x_dapm_routes),
},
static const struct snd_soc_component_driver soc_component_dev_uda134x = {
.probe = uda134x_soc_probe,
.set_bias_level = uda134x_set_bias_level,
.dapm_widgets = uda134x_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(uda134x_dapm_widgets),
.dapm_routes = uda134x_dapm_routes,
.num_dapm_routes = ARRAY_SIZE(uda134x_dapm_routes),
.suspend_bias_off = 1,
.idle_bias_on = 1,
.use_pmdown_time = 1,
.endianness = 1,
.non_legacy_dai_naming = 1,
};
static const struct regmap_config uda134x_regmap_config = {
......@@ -571,14 +572,8 @@ static int uda134x_codec_probe(struct platform_device *pdev)
if (IS_ERR(uda134x->regmap))
return PTR_ERR(uda134x->regmap);
return snd_soc_register_codec(&pdev->dev,
&soc_codec_dev_uda134x, &uda134x_dai, 1);
}
static int uda134x_codec_remove(struct platform_device *pdev)
{
snd_soc_unregister_codec(&pdev->dev);
return 0;
return devm_snd_soc_register_component(&pdev->dev,
&soc_component_dev_uda134x, &uda134x_dai, 1);
}
static struct platform_driver uda134x_codec_driver = {
......@@ -586,7 +581,6 @@ static struct platform_driver uda134x_codec_driver = {
.name = "uda134x-codec",
},
.probe = uda134x_codec_probe,
.remove = uda134x_codec_remove,
};
module_platform_driver(uda134x_codec_driver);
......
......@@ -34,7 +34,7 @@
/* codec private data */
struct uda1380_priv {
struct snd_soc_codec *codec;
struct snd_soc_component *component;
unsigned int dac_clk;
struct work_struct work;
struct i2c_client *i2c;
......@@ -61,10 +61,10 @@ static unsigned long uda1380_cache_dirty;
/*
* read uda1380 register cache
*/
static inline unsigned int uda1380_read_reg_cache(struct snd_soc_codec *codec,
static inline unsigned int uda1380_read_reg_cache(struct snd_soc_component *component,
unsigned int reg)
{
struct uda1380_priv *uda1380 = snd_soc_codec_get_drvdata(codec);
struct uda1380_priv *uda1380 = snd_soc_component_get_drvdata(component);
u16 *cache = uda1380->reg_cache;
if (reg == UDA1380_RESET)
......@@ -77,10 +77,10 @@ static inline unsigned int uda1380_read_reg_cache(struct snd_soc_codec *codec,
/*
* write uda1380 register cache
*/
static inline void uda1380_write_reg_cache(struct snd_soc_codec *codec,
static inline void uda1380_write_reg_cache(struct snd_soc_component *component,
u16 reg, unsigned int value)
{
struct uda1380_priv *uda1380 = snd_soc_codec_get_drvdata(codec);
struct uda1380_priv *uda1380 = snd_soc_component_get_drvdata(component);
u16 *cache = uda1380->reg_cache;
if (reg >= UDA1380_CACHEREGNUM)
......@@ -93,10 +93,10 @@ static inline void uda1380_write_reg_cache(struct snd_soc_codec *codec,
/*
* write to the UDA1380 register space
*/
static int uda1380_write(struct snd_soc_codec *codec, unsigned int reg,
static int uda1380_write(struct snd_soc_component *component, unsigned int reg,
unsigned int value)
{
struct uda1380_priv *uda1380 = snd_soc_codec_get_drvdata(codec);
struct uda1380_priv *uda1380 = snd_soc_component_get_drvdata(component);
u8 data[3];
/* data is
......@@ -108,12 +108,12 @@ static int uda1380_write(struct snd_soc_codec *codec, unsigned int reg,
data[1] = (value & 0xff00) >> 8;
data[2] = value & 0x00ff;
uda1380_write_reg_cache(codec, reg, value);
uda1380_write_reg_cache(component, reg, value);
/* the interpolator & decimator regs must only be written when the
* codec DAI is active.
*/
if (!snd_soc_codec_is_active(codec) && (reg >= UDA1380_MVOL))
if (!snd_soc_component_is_active(component) && (reg >= UDA1380_MVOL))
return 0;
pr_debug("uda1380: hw write %x val %x\n", reg, value);
if (i2c_master_send(uda1380->i2c, data, 3) == 3) {
......@@ -133,9 +133,9 @@ static int uda1380_write(struct snd_soc_codec *codec, unsigned int reg,
return -EIO;
}
static void uda1380_sync_cache(struct snd_soc_codec *codec)
static void uda1380_sync_cache(struct snd_soc_component *component)
{
struct uda1380_priv *uda1380 = snd_soc_codec_get_drvdata(codec);
struct uda1380_priv *uda1380 = snd_soc_component_get_drvdata(component);
int reg;
u8 data[3];
u16 *cache = uda1380->reg_cache;
......@@ -146,15 +146,15 @@ static void uda1380_sync_cache(struct snd_soc_codec *codec)
data[1] = (cache[reg] & 0xff00) >> 8;
data[2] = cache[reg] & 0x00ff;
if (i2c_master_send(uda1380->i2c, data, 3) != 3)
dev_err(codec->dev, "%s: write to reg 0x%x failed\n",
dev_err(component->dev, "%s: write to reg 0x%x failed\n",
__func__, reg);
}
}
static int uda1380_reset(struct snd_soc_codec *codec)
static int uda1380_reset(struct snd_soc_component *component)
{
struct uda1380_platform_data *pdata = codec->dev->platform_data;
struct uda1380_priv *uda1380 = snd_soc_codec_get_drvdata(codec);
struct uda1380_platform_data *pdata = component->dev->platform_data;
struct uda1380_priv *uda1380 = snd_soc_component_get_drvdata(component);
if (gpio_is_valid(pdata->gpio_reset)) {
gpio_set_value(pdata->gpio_reset, 1);
......@@ -168,7 +168,7 @@ static int uda1380_reset(struct snd_soc_codec *codec)
data[2] = 0;
if (i2c_master_send(uda1380->i2c, data, 3) != 3) {
dev_err(codec->dev, "%s: failed\n", __func__);
dev_err(component->dev, "%s: failed\n", __func__);
return -EIO;
}
}
......@@ -179,15 +179,15 @@ static int uda1380_reset(struct snd_soc_codec *codec)
static void uda1380_flush_work(struct work_struct *work)
{
struct uda1380_priv *uda1380 = container_of(work, struct uda1380_priv, work);
struct snd_soc_codec *uda1380_codec = uda1380->codec;
struct snd_soc_component *uda1380_component = uda1380->component;
int bit, reg;
for_each_set_bit(bit, &uda1380_cache_dirty, UDA1380_CACHEREGNUM - 0x10) {
reg = 0x10 + bit;
pr_debug("uda1380: flush reg %x val %x:\n", reg,
uda1380_read_reg_cache(uda1380_codec, reg));
uda1380_write(uda1380_codec, reg,
uda1380_read_reg_cache(uda1380_codec, reg));
uda1380_read_reg_cache(uda1380_component, reg));
uda1380_write(uda1380_component, reg,
uda1380_read_reg_cache(uda1380_component, reg));
clear_bit(bit, &uda1380_cache_dirty);
}
......@@ -420,11 +420,11 @@ static const struct snd_soc_dapm_route uda1380_dapm_routes[] = {
static int uda1380_set_dai_fmt_both(struct snd_soc_dai *codec_dai,
unsigned int fmt)
{
struct snd_soc_codec *codec = codec_dai->codec;
struct snd_soc_component *component = codec_dai->component;
int iface;
/* set up DAI based upon fmt */
iface = uda1380_read_reg_cache(codec, UDA1380_IFACE);
iface = uda1380_read_reg_cache(component, UDA1380_IFACE);
iface &= ~(R01_SFORI_MASK | R01_SIM | R01_SFORO_MASK);
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
......@@ -442,7 +442,7 @@ static int uda1380_set_dai_fmt_both(struct snd_soc_dai *codec_dai,
if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS)
return -EINVAL;
uda1380_write_reg_cache(codec, UDA1380_IFACE, iface);
uda1380_write_reg_cache(component, UDA1380_IFACE, iface);
return 0;
}
......@@ -450,11 +450,11 @@ static int uda1380_set_dai_fmt_both(struct snd_soc_dai *codec_dai,
static int uda1380_set_dai_fmt_playback(struct snd_soc_dai *codec_dai,
unsigned int fmt)
{
struct snd_soc_codec *codec = codec_dai->codec;
struct snd_soc_component *component = codec_dai->component;
int iface;
/* set up DAI based upon fmt */
iface = uda1380_read_reg_cache(codec, UDA1380_IFACE);
iface = uda1380_read_reg_cache(component, UDA1380_IFACE);
iface &= ~R01_SFORI_MASK;
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
......@@ -472,7 +472,7 @@ static int uda1380_set_dai_fmt_playback(struct snd_soc_dai *codec_dai,
if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS)
return -EINVAL;
uda1380_write(codec, UDA1380_IFACE, iface);
uda1380_write(component, UDA1380_IFACE, iface);
return 0;
}
......@@ -480,11 +480,11 @@ static int uda1380_set_dai_fmt_playback(struct snd_soc_dai *codec_dai,
static int uda1380_set_dai_fmt_capture(struct snd_soc_dai *codec_dai,
unsigned int fmt)
{
struct snd_soc_codec *codec = codec_dai->codec;
struct snd_soc_component *component = codec_dai->component;
int iface;
/* set up DAI based upon fmt */
iface = uda1380_read_reg_cache(codec, UDA1380_IFACE);
iface = uda1380_read_reg_cache(component, UDA1380_IFACE);
iface &= ~(R01_SIM | R01_SFORO_MASK);
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
......@@ -501,7 +501,7 @@ static int uda1380_set_dai_fmt_capture(struct snd_soc_dai *codec_dai,
if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFM)
iface |= R01_SIM;
uda1380_write(codec, UDA1380_IFACE, iface);
uda1380_write(component, UDA1380_IFACE, iface);
return 0;
}
......@@ -509,20 +509,20 @@ static int uda1380_set_dai_fmt_capture(struct snd_soc_dai *codec_dai,
static int uda1380_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
struct uda1380_priv *uda1380 = snd_soc_codec_get_drvdata(codec);
int mixer = uda1380_read_reg_cache(codec, UDA1380_MIXER);
struct snd_soc_component *component = dai->component;
struct uda1380_priv *uda1380 = snd_soc_component_get_drvdata(component);
int mixer = uda1380_read_reg_cache(component, UDA1380_MIXER);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
uda1380_write_reg_cache(codec, UDA1380_MIXER,
uda1380_write_reg_cache(component, UDA1380_MIXER,
mixer & ~R14_SILENCE);
schedule_work(&uda1380->work);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
uda1380_write_reg_cache(codec, UDA1380_MIXER,
uda1380_write_reg_cache(component, UDA1380_MIXER,
mixer | R14_SILENCE);
schedule_work(&uda1380->work);
break;
......@@ -534,13 +534,13 @@ static int uda1380_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK);
struct snd_soc_component *component = dai->component;
u16 clk = uda1380_read_reg_cache(component, UDA1380_CLK);
/* set WSPLL power and divider if running from this clock */
if (clk & R00_DAC_CLK) {
int rate = params_rate(params);
u16 pm = uda1380_read_reg_cache(codec, UDA1380_PM);
u16 pm = uda1380_read_reg_cache(component, UDA1380_PM);
clk &= ~0x3; /* clear SEL_LOOP_DIV */
switch (rate) {
case 6250 ... 12500:
......@@ -556,7 +556,7 @@ static int uda1380_pcm_hw_params(struct snd_pcm_substream *substream,
clk |= 0x3;
break;
}
uda1380_write(codec, UDA1380_PM, R02_PON_PLL | pm);
uda1380_write(component, UDA1380_PM, R02_PON_PLL | pm);
}
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
......@@ -564,20 +564,20 @@ static int uda1380_pcm_hw_params(struct snd_pcm_substream *substream,
else
clk |= R00_EN_ADC | R00_EN_DEC;
uda1380_write(codec, UDA1380_CLK, clk);
uda1380_write(component, UDA1380_CLK, clk);
return 0;
}
static void uda1380_pcm_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK);
struct snd_soc_component *component = dai->component;
u16 clk = uda1380_read_reg_cache(component, UDA1380_CLK);
/* shut down WSPLL power if running from this clock */
if (clk & R00_DAC_CLK) {
u16 pm = uda1380_read_reg_cache(codec, UDA1380_PM);
uda1380_write(codec, UDA1380_PM, ~R02_PON_PLL & pm);
u16 pm = uda1380_read_reg_cache(component, UDA1380_PM);
uda1380_write(component, UDA1380_PM, ~R02_PON_PLL & pm);
}
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
......@@ -585,33 +585,33 @@ static void uda1380_pcm_shutdown(struct snd_pcm_substream *substream,
else
clk &= ~(R00_EN_ADC | R00_EN_DEC);
uda1380_write(codec, UDA1380_CLK, clk);
uda1380_write(component, UDA1380_CLK, clk);
}
static int uda1380_set_bias_level(struct snd_soc_codec *codec,
static int uda1380_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
int pm = uda1380_read_reg_cache(codec, UDA1380_PM);
int pm = uda1380_read_reg_cache(component, UDA1380_PM);
int reg;
struct uda1380_platform_data *pdata = codec->dev->platform_data;
struct uda1380_platform_data *pdata = component->dev->platform_data;
switch (level) {
case SND_SOC_BIAS_ON:
case SND_SOC_BIAS_PREPARE:
/* ADC, DAC on */
uda1380_write(codec, UDA1380_PM, R02_PON_BIAS | pm);
uda1380_write(component, UDA1380_PM, R02_PON_BIAS | pm);
break;
case SND_SOC_BIAS_STANDBY:
if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
if (gpio_is_valid(pdata->gpio_power)) {
gpio_set_value(pdata->gpio_power, 1);
mdelay(1);
uda1380_reset(codec);
uda1380_reset(component);
}
uda1380_sync_cache(codec);
uda1380_sync_cache(component);
}
uda1380_write(codec, UDA1380_PM, 0x0);
uda1380_write(component, UDA1380_PM, 0x0);
break;
case SND_SOC_BIAS_OFF:
if (!gpio_is_valid(pdata->gpio_power))
......@@ -694,16 +694,16 @@ static struct snd_soc_dai_driver uda1380_dai[] = {
},
};
static int uda1380_probe(struct snd_soc_codec *codec)
static int uda1380_probe(struct snd_soc_component *component)
{
struct uda1380_platform_data *pdata =codec->dev->platform_data;
struct uda1380_priv *uda1380 = snd_soc_codec_get_drvdata(codec);
struct uda1380_platform_data *pdata =component->dev->platform_data;
struct uda1380_priv *uda1380 = snd_soc_component_get_drvdata(component);
int ret;
uda1380->codec = codec;
uda1380->component = component;
if (!gpio_is_valid(pdata->gpio_power)) {
ret = uda1380_reset(codec);
ret = uda1380_reset(component);
if (ret)
return ret;
}
......@@ -713,10 +713,10 @@ static int uda1380_probe(struct snd_soc_codec *codec)
/* set clock input */
switch (pdata->dac_clk) {
case UDA1380_DAC_CLK_SYSCLK:
uda1380_write_reg_cache(codec, UDA1380_CLK, 0);
uda1380_write_reg_cache(component, UDA1380_CLK, 0);
break;
case UDA1380_DAC_CLK_WSPLL:
uda1380_write_reg_cache(codec, UDA1380_CLK,
uda1380_write_reg_cache(component, UDA1380_CLK,
R00_DAC_CLK);
break;
}
......@@ -724,21 +724,22 @@ static int uda1380_probe(struct snd_soc_codec *codec)
return 0;
}
static const struct snd_soc_codec_driver soc_codec_dev_uda1380 = {
.probe = uda1380_probe,
.read = uda1380_read_reg_cache,
.write = uda1380_write,
.set_bias_level = uda1380_set_bias_level,
.suspend_bias_off = true,
.component_driver = {
.controls = uda1380_snd_controls,
.num_controls = ARRAY_SIZE(uda1380_snd_controls),
.dapm_widgets = uda1380_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(uda1380_dapm_widgets),
.dapm_routes = uda1380_dapm_routes,
.num_dapm_routes = ARRAY_SIZE(uda1380_dapm_routes),
},
static const struct snd_soc_component_driver soc_component_dev_uda1380 = {
.probe = uda1380_probe,
.read = uda1380_read_reg_cache,
.write = uda1380_write,
.set_bias_level = uda1380_set_bias_level,
.controls = uda1380_snd_controls,
.num_controls = ARRAY_SIZE(uda1380_snd_controls),
.dapm_widgets = uda1380_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(uda1380_dapm_widgets),
.dapm_routes = uda1380_dapm_routes,
.num_dapm_routes = ARRAY_SIZE(uda1380_dapm_routes),
.suspend_bias_off = 1,
.idle_bias_on = 1,
.use_pmdown_time = 1,
.endianness = 1,
.non_legacy_dai_naming = 1,
};
static int uda1380_i2c_probe(struct i2c_client *i2c,
......@@ -780,17 +781,11 @@ static int uda1380_i2c_probe(struct i2c_client *i2c,
i2c_set_clientdata(i2c, uda1380);
uda1380->i2c = i2c;
ret = snd_soc_register_codec(&i2c->dev,
&soc_codec_dev_uda1380, uda1380_dai, ARRAY_SIZE(uda1380_dai));
ret = devm_snd_soc_register_component(&i2c->dev,
&soc_component_dev_uda1380, uda1380_dai, ARRAY_SIZE(uda1380_dai));
return ret;
}
static int uda1380_i2c_remove(struct i2c_client *i2c)
{
snd_soc_unregister_codec(&i2c->dev);
return 0;
}
static const struct i2c_device_id uda1380_i2c_id[] = {
{ "uda1380", 0 },
{ }
......@@ -809,7 +804,6 @@ static struct i2c_driver uda1380_i2c_driver = {
.of_match_table = uda1380_of_match,
},
.probe = uda1380_i2c_probe,
.remove = uda1380_i2c_remove,
.id_table = uda1380_i2c_id,
};
......
......@@ -52,7 +52,7 @@ static int omap_abe_hw_params(struct snd_pcm_substream *substream,
int clk_id, freq;
int ret;
clk_id = twl6040_get_clk_id(rtd->codec);
clk_id = twl6040_get_clk_id(codec_dai->component);
if (clk_id == TWL6040_SYSCLK_SEL_HPPLL)
freq = priv->mclk_freq;
else if (clk_id == TWL6040_SYSCLK_SEL_LPPLL)
......@@ -166,7 +166,7 @@ static const struct snd_soc_dapm_route audio_map[] = {
static int omap_abe_twl6040_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_component *component = rtd->codec_dai->component;
struct snd_soc_card *card = rtd->card;
struct abe_twl6040 *priv = snd_soc_card_get_drvdata(card);
int hs_trim;
......@@ -176,7 +176,7 @@ static int omap_abe_twl6040_init(struct snd_soc_pcm_runtime *rtd)
* Configure McPDM offset cancellation based on the HSOTRIM value from
* twl6040.
*/
hs_trim = twl6040_get_trim_value(codec, TWL6040_TRIM_HSOTRIM);
hs_trim = twl6040_get_trim_value(component, TWL6040_TRIM_HSOTRIM);
omap_mcpdm_configure_dn_offsets(rtd, TWL6040_HSF_TRIM_LEFT(hs_trim),
TWL6040_HSF_TRIM_RIGHT(hs_trim));
......@@ -189,7 +189,7 @@ static int omap_abe_twl6040_init(struct snd_soc_pcm_runtime *rtd)
if (ret)
return ret;
twl6040_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADSET);
twl6040_hs_jack_detect(component, &hs_jack, SND_JACK_HEADSET);
}
return 0;
......
......@@ -8,6 +8,39 @@ config SND_SOC_UNIPHIER
audio interfaces to support below.
If unsure select "N".
config SND_SOC_UNIPHIER_AIO
tristate "UniPhier AIO DAI Driver"
select REGMAP_MMIO
select SND_SOC_COMPRESS
depends on SND_SOC_UNIPHIER
help
This adds ASoC driver support for Socionext UniPhier
'AIO' Audio Input/Output subsystem.
Select Y if you use such device.
If unsure select "N".
config SND_SOC_UNIPHIER_LD11
tristate "UniPhier LD11/LD20 Device Driver"
depends on SND_SOC_UNIPHIER
select SND_SOC_UNIPHIER_AIO
select SND_SOC_UNIPHIER_AIO_DMA
help
This adds ASoC driver for Socionext UniPhier LD11/LD20
input and output that can be used with other codecs.
Select Y if you use such device.
If unsure select "N".
config SND_SOC_UNIPHIER_PXS2
tristate "UniPhier PXs2 Device Driver"
depends on SND_SOC_UNIPHIER
select SND_SOC_UNIPHIER_AIO
select SND_SOC_UNIPHIER_AIO_DMA
help
This adds ASoC driver for Socionext UniPhier PXs2
input and output that can be used with other codecs.
Select Y if you use such device.
If unsure select "N".
config SND_SOC_UNIPHIER_EVEA_CODEC
tristate "UniPhier SoC internal audio codec"
depends on SND_SOC_UNIPHIER
......
# SPDX-License-Identifier: GPL-2.0
snd-soc-uniphier-aio-cpu-objs := aio-core.o aio-dma.o aio-cpu.o aio-compress.o
snd-soc-uniphier-aio-ld11-objs := aio-ld11.o
snd-soc-uniphier-aio-pxs2-objs := aio-pxs2.o
obj-$(CONFIG_SND_SOC_UNIPHIER_AIO) += snd-soc-uniphier-aio-cpu.o
obj-$(CONFIG_SND_SOC_UNIPHIER_LD11) += snd-soc-uniphier-aio-ld11.o
obj-$(CONFIG_SND_SOC_UNIPHIER_PXS2) += snd-soc-uniphier-aio-pxs2.o
snd-soc-uniphier-evea-objs := evea.o
obj-$(CONFIG_SND_SOC_UNIPHIER_EVEA_CODEC) += snd-soc-uniphier-evea.o
// SPDX-License-Identifier: GPL-2.0
//
// Socionext UniPhier AIO Compress Audio driver.
//
// Copyright (c) 2017-2018 Socionext Inc.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; version 2
// of the License.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, see <http://www.gnu.org/licenses/>.
#include <linux/bitfield.h>
#include <linux/circ_buf.h>
#include <linux/dma-mapping.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include "aio.h"
static int uniphier_aio_compr_prepare(struct snd_compr_stream *cstream);
static int uniphier_aio_compr_hw_free(struct snd_compr_stream *cstream);
static int uniphier_aio_comprdma_new(struct snd_soc_pcm_runtime *rtd)
{
struct snd_compr *compr = rtd->compr;
struct device *dev = compr->card->dev;
struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
struct uniphier_aio_sub *sub = &aio->sub[compr->direction];
size_t size = AUD_RING_SIZE;
int dma_dir = DMA_FROM_DEVICE, ret;
ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(33));
if (ret)
return ret;
sub->compr_area = kzalloc(size, GFP_KERNEL);
if (!sub->compr_area)
return -ENOMEM;
if (sub->swm->dir == PORT_DIR_OUTPUT)
dma_dir = DMA_TO_DEVICE;
sub->compr_addr = dma_map_single(dev, sub->compr_area, size, dma_dir);
if (dma_mapping_error(dev, sub->compr_addr)) {
kfree(sub->compr_area);
sub->compr_area = NULL;
return -ENOMEM;
}
sub->compr_bytes = size;
return 0;
}
static int uniphier_aio_comprdma_free(struct snd_soc_pcm_runtime *rtd)
{
struct snd_compr *compr = rtd->compr;
struct device *dev = compr->card->dev;
struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
struct uniphier_aio_sub *sub = &aio->sub[compr->direction];
int dma_dir = DMA_FROM_DEVICE;
if (sub->swm->dir == PORT_DIR_OUTPUT)
dma_dir = DMA_TO_DEVICE;
dma_unmap_single(dev, sub->compr_addr, sub->compr_bytes, dma_dir);
kfree(sub->compr_area);
sub->compr_area = NULL;
return 0;
}
static int uniphier_aio_compr_open(struct snd_compr_stream *cstream)
{
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
int ret;
if (sub->cstream)
return -EBUSY;
sub->cstream = cstream;
sub->pass_through = 1;
sub->use_mmap = false;
ret = uniphier_aio_comprdma_new(rtd);
if (ret)
return ret;
ret = aio_init(sub);
if (ret)
return ret;
return 0;
}
static int uniphier_aio_compr_free(struct snd_compr_stream *cstream)
{
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
int ret;
ret = uniphier_aio_compr_hw_free(cstream);
if (ret)
return ret;
ret = uniphier_aio_comprdma_free(rtd);
if (ret)
return ret;
sub->cstream = NULL;
return 0;
}
static int uniphier_aio_compr_get_params(struct snd_compr_stream *cstream,
struct snd_codec *params)
{
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
*params = sub->cparams.codec;
return 0;
}
static int uniphier_aio_compr_set_params(struct snd_compr_stream *cstream,
struct snd_compr_params *params)
{
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
struct device *dev = &aio->chip->pdev->dev;
int ret;
if (params->codec.id != SND_AUDIOCODEC_IEC61937) {
dev_err(dev, "Codec ID is not supported(%d)\n",
params->codec.id);
return -EINVAL;
}
if (params->codec.profile != SND_AUDIOPROFILE_IEC61937_SPDIF) {
dev_err(dev, "Codec profile is not supported(%d)\n",
params->codec.profile);
return -EINVAL;
}
/* IEC frame type will be changed after received valid data */
sub->iec_pc = IEC61937_PC_AAC;
sub->cparams = *params;
sub->setting = 1;
aio_port_reset(sub);
aio_src_reset(sub);
ret = uniphier_aio_compr_prepare(cstream);
if (ret)
return ret;
return 0;
}
static int uniphier_aio_compr_hw_free(struct snd_compr_stream *cstream)
{
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
sub->setting = 0;
return 0;
}
static int uniphier_aio_compr_prepare(struct snd_compr_stream *cstream)
{
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
struct snd_compr_runtime *runtime = cstream->runtime;
struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
int bytes = runtime->fragment_size;
unsigned long flags;
int ret;
ret = aiodma_ch_set_param(sub);
if (ret)
return ret;
spin_lock_irqsave(&sub->lock, flags);
ret = aiodma_rb_set_buffer(sub, sub->compr_addr,
sub->compr_addr + sub->compr_bytes,
bytes);
spin_unlock_irqrestore(&sub->lock, flags);
if (ret)
return ret;
ret = aio_port_set_param(sub, sub->pass_through, &sub->params);
if (ret)
return ret;
ret = aio_oport_set_stream_type(sub, sub->iec_pc);
if (ret)
return ret;
aio_port_set_enable(sub, 1);
ret = aio_if_set_param(sub, sub->pass_through);
if (ret)
return ret;
return 0;
}
static int uniphier_aio_compr_trigger(struct snd_compr_stream *cstream,
int cmd)
{
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
struct snd_compr_runtime *runtime = cstream->runtime;
struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
struct device *dev = &aio->chip->pdev->dev;
int bytes = runtime->fragment_size, ret = 0;
unsigned long flags;
spin_lock_irqsave(&sub->lock, flags);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
aiodma_rb_sync(sub, sub->compr_addr, sub->compr_bytes, bytes);
aiodma_ch_set_enable(sub, 1);
sub->running = 1;
break;
case SNDRV_PCM_TRIGGER_STOP:
sub->running = 0;
aiodma_ch_set_enable(sub, 0);
break;
default:
dev_warn(dev, "Unknown trigger(%d)\n", cmd);
ret = -EINVAL;
}
spin_unlock_irqrestore(&sub->lock, flags);
return ret;
}
static int uniphier_aio_compr_pointer(struct snd_compr_stream *cstream,
struct snd_compr_tstamp *tstamp)
{
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
struct snd_compr_runtime *runtime = cstream->runtime;
struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
int bytes = runtime->fragment_size;
unsigned long flags;
u32 pos;
spin_lock_irqsave(&sub->lock, flags);
aiodma_rb_sync(sub, sub->compr_addr, sub->compr_bytes, bytes);
if (sub->swm->dir == PORT_DIR_OUTPUT) {
pos = sub->rd_offs;
/* Size of AIO output format is double of IEC61937 */
tstamp->copied_total = sub->rd_total / 2;
} else {
pos = sub->wr_offs;
tstamp->copied_total = sub->rd_total;
}
tstamp->byte_offset = pos;
spin_unlock_irqrestore(&sub->lock, flags);
return 0;
}
static int aio_compr_send_to_hw(struct uniphier_aio_sub *sub,
char __user *buf, size_t dstsize)
{
u32 __user *srcbuf = (u32 __user *)buf;
u32 *dstbuf = (u32 *)(sub->compr_area + sub->wr_offs);
int src = 0, dst = 0, ret;
u32 frm, frm_a, frm_b;
while (dstsize > 0) {
ret = get_user(frm, srcbuf + src);
if (ret)
return ret;
src++;
frm_a = frm & 0xffff;
frm_b = (frm >> 16) & 0xffff;
if (frm == IEC61937_HEADER_SIGN) {
frm_a |= 0x01000000;
/* Next data is Pc and Pd */
sub->iec_header = true;
} else {
u16 pc = be16_to_cpu((__be16)frm_a);
if (sub->iec_header && sub->iec_pc != pc) {
/* Force overwrite IEC frame type */
sub->iec_pc = pc;
ret = aio_oport_set_stream_type(sub, pc);
if (ret)
return ret;
}
sub->iec_header = false;
}
dstbuf[dst++] = frm_a;
dstbuf[dst++] = frm_b;
dstsize -= sizeof(u32) * 2;
}
return 0;
}
static int uniphier_aio_compr_copy(struct snd_compr_stream *cstream,
char __user *buf, size_t count)
{
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
struct snd_compr_runtime *runtime = cstream->runtime;
struct device *carddev = rtd->compr->card->dev;
struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
size_t cnt = min_t(size_t, count, aio_rb_space_to_end(sub) / 2);
int bytes = runtime->fragment_size;
unsigned long flags;
size_t s;
int ret;
if (cnt < sizeof(u32))
return 0;
if (sub->swm->dir == PORT_DIR_OUTPUT) {
dma_addr_t dmapos = sub->compr_addr + sub->wr_offs;
/* Size of AIO output format is double of IEC61937 */
s = cnt * 2;
dma_sync_single_for_cpu(carddev, dmapos, s, DMA_TO_DEVICE);
ret = aio_compr_send_to_hw(sub, buf, s);
dma_sync_single_for_device(carddev, dmapos, s, DMA_TO_DEVICE);
} else {
dma_addr_t dmapos = sub->compr_addr + sub->rd_offs;
s = cnt;
dma_sync_single_for_cpu(carddev, dmapos, s, DMA_FROM_DEVICE);
ret = copy_to_user(buf, sub->compr_area + sub->rd_offs, s);
dma_sync_single_for_device(carddev, dmapos, s, DMA_FROM_DEVICE);
}
if (ret)
return -EFAULT;
spin_lock_irqsave(&sub->lock, flags);
sub->threshold = 2 * bytes;
aiodma_rb_set_threshold(sub, sub->compr_bytes, 2 * bytes);
if (sub->swm->dir == PORT_DIR_OUTPUT) {
sub->wr_offs += s;
if (sub->wr_offs >= sub->compr_bytes)
sub->wr_offs -= sub->compr_bytes;
} else {
sub->rd_offs += s;
if (sub->rd_offs >= sub->compr_bytes)
sub->rd_offs -= sub->compr_bytes;
}
aiodma_rb_sync(sub, sub->compr_addr, sub->compr_bytes, bytes);
spin_unlock_irqrestore(&sub->lock, flags);
return cnt;
}
static int uniphier_aio_compr_get_caps(struct snd_compr_stream *cstream,
struct snd_compr_caps *caps)
{
caps->num_codecs = 1;
caps->min_fragment_size = AUD_MIN_FRAGMENT_SIZE;
caps->max_fragment_size = AUD_MAX_FRAGMENT_SIZE;
caps->min_fragments = AUD_MIN_FRAGMENT;
caps->max_fragments = AUD_MAX_FRAGMENT;
caps->codecs[0] = SND_AUDIOCODEC_IEC61937;
return 0;
}
static const struct snd_compr_codec_caps caps_iec = {
.num_descriptors = 1,
.descriptor[0].max_ch = 8,
.descriptor[0].num_sample_rates = 0,
.descriptor[0].num_bitrates = 0,
.descriptor[0].profiles = SND_AUDIOPROFILE_IEC61937_SPDIF,
.descriptor[0].modes = SND_AUDIOMODE_IEC_AC3 |
SND_AUDIOMODE_IEC_MPEG1 |
SND_AUDIOMODE_IEC_MP3 |
SND_AUDIOMODE_IEC_DTS,
.descriptor[0].formats = 0,
};
static int uniphier_aio_compr_get_codec_caps(struct snd_compr_stream *stream,
struct snd_compr_codec_caps *codec)
{
if (codec->codec == SND_AUDIOCODEC_IEC61937)
*codec = caps_iec;
else
return -EINVAL;
return 0;
}
const struct snd_compr_ops uniphier_aio_compr_ops = {
.open = uniphier_aio_compr_open,
.free = uniphier_aio_compr_free,
.get_params = uniphier_aio_compr_get_params,
.set_params = uniphier_aio_compr_set_params,
.trigger = uniphier_aio_compr_trigger,
.pointer = uniphier_aio_compr_pointer,
.copy = uniphier_aio_compr_copy,
.get_caps = uniphier_aio_compr_get_caps,
.get_codec_caps = uniphier_aio_compr_get_codec_caps,
};
// SPDX-License-Identifier: GPL-2.0
//
// Socionext UniPhier AIO ALSA common driver.
//
// Copyright (c) 2016-2018 Socionext Inc.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; version 2
// of the License.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, see <http://www.gnu.org/licenses/>.
#include <linux/bitfield.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include "aio.h"
#include "aio-reg.h"
static u64 rb_cnt(u64 wr, u64 rd, u64 len)
{
if (rd <= wr)
return wr - rd;
else
return len - (rd - wr);
}
static u64 rb_cnt_to_end(u64 wr, u64 rd, u64 len)
{
if (rd <= wr)
return wr - rd;
else
return len - rd;
}
static u64 rb_space(u64 wr, u64 rd, u64 len)
{
if (rd <= wr)
return len - (wr - rd) - 8;
else
return rd - wr - 8;
}
static u64 rb_space_to_end(u64 wr, u64 rd, u64 len)
{
if (rd > wr)
return rd - wr - 8;
else if (rd > 0)
return len - wr;
else
return len - wr - 8;
}
u64 aio_rb_cnt(struct uniphier_aio_sub *sub)
{
return rb_cnt(sub->wr_offs, sub->rd_offs, sub->compr_bytes);
}
u64 aio_rbt_cnt_to_end(struct uniphier_aio_sub *sub)
{
return rb_cnt_to_end(sub->wr_offs, sub->rd_offs, sub->compr_bytes);
}
u64 aio_rb_space(struct uniphier_aio_sub *sub)
{
return rb_space(sub->wr_offs, sub->rd_offs, sub->compr_bytes);
}
u64 aio_rb_space_to_end(struct uniphier_aio_sub *sub)
{
return rb_space_to_end(sub->wr_offs, sub->rd_offs, sub->compr_bytes);
}
/**
* aio_iecout_set_enable - setup IEC output via SoC glue
* @chip: the AIO chip pointer
* @enable: false to stop the output, true to start
*
* Set enabled or disabled S/PDIF signal output to out of SoC via AOnIEC pins.
* This function need to call at driver startup.
*
* The regmap of SoC glue is specified by 'socionext,syscon' optional property
* of DT. This function has no effect if no property.
*/
void aio_iecout_set_enable(struct uniphier_aio_chip *chip, bool enable)
{
struct regmap *r = chip->regmap_sg;
if (!r)
return;
regmap_write(r, SG_AOUTEN, (enable) ? ~0 : 0);
}
/**
* aio_chip_set_pll - set frequency to audio PLL
* @chip : the AIO chip pointer
* @source: PLL
* @freq : frequency in Hz, 0 is ignored
*
* Sets frequency of audio PLL. This function can be called anytime,
* but it takes time till PLL is locked.
*
* Return: Zero if successful, otherwise a negative value on error.
*/
int aio_chip_set_pll(struct uniphier_aio_chip *chip, int pll_id,
unsigned int freq)
{
struct device *dev = &chip->pdev->dev;
struct regmap *r = chip->regmap;
int shift;
u32 v;
/* Not change */
if (freq == 0)
return 0;
switch (pll_id) {
case AUD_PLL_A1:
shift = 0;
break;
case AUD_PLL_F1:
shift = 1;
break;
case AUD_PLL_A2:
shift = 2;
break;
case AUD_PLL_F2:
shift = 3;
break;
default:
dev_err(dev, "PLL(%d) not supported\n", pll_id);
return -EINVAL;
}
switch (freq) {
case 36864000:
v = A2APLLCTR1_APLLX_36MHZ;
break;
case 33868800:
v = A2APLLCTR1_APLLX_33MHZ;
break;
default:
dev_err(dev, "PLL frequency not supported(%d)\n", freq);
return -EINVAL;
}
chip->plls[pll_id].freq = freq;
regmap_update_bits(r, A2APLLCTR1, A2APLLCTR1_APLLX_MASK << shift,
v << shift);
return 0;
}
/**
* aio_chip_init - initialize AIO whole settings
* @chip: the AIO chip pointer
*
* Sets AIO fixed and whole device settings to AIO.
* This function need to call once at driver startup.
*
* The register area that is changed by this function is shared by all
* modules of AIO. But there is not race condition since this function
* has always set the same initialize values.
*/
void aio_chip_init(struct uniphier_aio_chip *chip)
{
struct regmap *r = chip->regmap;
regmap_update_bits(r, A2APLLCTR0,
A2APLLCTR0_APLLXPOW_MASK,
A2APLLCTR0_APLLXPOW_PWON);
regmap_update_bits(r, A2EXMCLKSEL0,
A2EXMCLKSEL0_EXMCLK_MASK,
A2EXMCLKSEL0_EXMCLK_OUTPUT);
regmap_update_bits(r, A2AIOINPUTSEL, A2AIOINPUTSEL_RXSEL_MASK,
A2AIOINPUTSEL_RXSEL_PCMI1_HDMIRX1 |
A2AIOINPUTSEL_RXSEL_PCMI2_SIF |
A2AIOINPUTSEL_RXSEL_PCMI3_EVEA |
A2AIOINPUTSEL_RXSEL_IECI1_HDMIRX1);
if (chip->chip_spec->addr_ext)
regmap_update_bits(r, CDA2D_TEST, CDA2D_TEST_DDR_MODE_MASK,
CDA2D_TEST_DDR_MODE_EXTON0);
else
regmap_update_bits(r, CDA2D_TEST, CDA2D_TEST_DDR_MODE_MASK,
CDA2D_TEST_DDR_MODE_EXTOFF1);
}
/**
* aio_init - initialize AIO substream
* @sub: the AIO substream pointer
*
* Sets fixed settings of each AIO substreams.
* This function need to call once at substream startup.
*
* Return: Zero if successful, otherwise a negative value on error.
*/
int aio_init(struct uniphier_aio_sub *sub)
{
struct device *dev = &sub->aio->chip->pdev->dev;
struct regmap *r = sub->aio->chip->regmap;
regmap_write(r, A2RBNMAPCTR0(sub->swm->rb.hw),
MAPCTR0_EN | sub->swm->rb.map);
regmap_write(r, A2CHNMAPCTR0(sub->swm->ch.hw),
MAPCTR0_EN | sub->swm->ch.map);
switch (sub->swm->type) {
case PORT_TYPE_I2S:
case PORT_TYPE_SPDIF:
case PORT_TYPE_EVE:
if (sub->swm->dir == PORT_DIR_INPUT) {
regmap_write(r, A2IIFNMAPCTR0(sub->swm->iif.hw),
MAPCTR0_EN | sub->swm->iif.map);
regmap_write(r, A2IPORTNMAPCTR0(sub->swm->iport.hw),
MAPCTR0_EN | sub->swm->iport.map);
} else {
regmap_write(r, A2OIFNMAPCTR0(sub->swm->oif.hw),
MAPCTR0_EN | sub->swm->oif.map);
regmap_write(r, A2OPORTNMAPCTR0(sub->swm->oport.hw),
MAPCTR0_EN | sub->swm->oport.map);
}
break;
case PORT_TYPE_CONV:
regmap_write(r, A2OIFNMAPCTR0(sub->swm->oif.hw),
MAPCTR0_EN | sub->swm->oif.map);
regmap_write(r, A2OPORTNMAPCTR0(sub->swm->oport.hw),
MAPCTR0_EN | sub->swm->oport.map);
regmap_write(r, A2CHNMAPCTR0(sub->swm->och.hw),
MAPCTR0_EN | sub->swm->och.map);
regmap_write(r, A2IIFNMAPCTR0(sub->swm->iif.hw),
MAPCTR0_EN | sub->swm->iif.map);
break;
default:
dev_err(dev, "Unknown port type %d.\n", sub->swm->type);
return -EINVAL;
}
return 0;
}
/**
* aio_port_reset - reset AIO port block
* @sub: the AIO substream pointer
*
* Resets the digital signal input/output port block of AIO.
*/
void aio_port_reset(struct uniphier_aio_sub *sub)
{
struct regmap *r = sub->aio->chip->regmap;
if (sub->swm->dir == PORT_DIR_OUTPUT) {
regmap_write(r, AOUTRSTCTR0, BIT(sub->swm->oport.map));
regmap_write(r, AOUTRSTCTR1, BIT(sub->swm->oport.map));
} else {
regmap_update_bits(r, IPORTMXRSTCTR(sub->swm->iport.map),
IPORTMXRSTCTR_RSTPI_MASK,
IPORTMXRSTCTR_RSTPI_RESET);
regmap_update_bits(r, IPORTMXRSTCTR(sub->swm->iport.map),
IPORTMXRSTCTR_RSTPI_MASK,
IPORTMXRSTCTR_RSTPI_RELEASE);
}
}
/**
* aio_port_set_rate - set sampling rate of LPCM
* @sub: the AIO substream pointer, PCM substream only
* @rate: Sampling rate in Hz.
*
* Set suitable I2S format settings to input/output port block of AIO.
* Parameter is specified by hw_params().
*
* This function may return error if non-PCM substream.
*
* Return: Zero if successful, otherwise a negative value on error.
*/
int aio_port_set_rate(struct uniphier_aio_sub *sub, int rate)
{
struct regmap *r = sub->aio->chip->regmap;
struct device *dev = &sub->aio->chip->pdev->dev;
u32 v;
if (sub->swm->dir == PORT_DIR_OUTPUT) {
switch (rate) {
case 8000:
v = OPORTMXCTR1_FSSEL_8;
break;
case 11025:
v = OPORTMXCTR1_FSSEL_11_025;
break;
case 12000:
v = OPORTMXCTR1_FSSEL_12;
break;
case 16000:
v = OPORTMXCTR1_FSSEL_16;
break;
case 22050:
v = OPORTMXCTR1_FSSEL_22_05;
break;
case 24000:
v = OPORTMXCTR1_FSSEL_24;
break;
case 32000:
v = OPORTMXCTR1_FSSEL_32;
break;
case 44100:
v = OPORTMXCTR1_FSSEL_44_1;
break;
case 48000:
v = OPORTMXCTR1_FSSEL_48;
break;
case 88200:
v = OPORTMXCTR1_FSSEL_88_2;
break;
case 96000:
v = OPORTMXCTR1_FSSEL_96;
break;
case 176400:
v = OPORTMXCTR1_FSSEL_176_4;
break;
case 192000:
v = OPORTMXCTR1_FSSEL_192;
break;
default:
dev_err(dev, "Rate not supported(%d)\n", rate);
return -EINVAL;
}
regmap_update_bits(r, OPORTMXCTR1(sub->swm->oport.map),
OPORTMXCTR1_FSSEL_MASK, v);
} else {
switch (rate) {
case 8000:
v = IPORTMXCTR1_FSSEL_8;
break;
case 11025:
v = IPORTMXCTR1_FSSEL_11_025;
break;
case 12000:
v = IPORTMXCTR1_FSSEL_12;
break;
case 16000:
v = IPORTMXCTR1_FSSEL_16;
break;
case 22050:
v = IPORTMXCTR1_FSSEL_22_05;
break;
case 24000:
v = IPORTMXCTR1_FSSEL_24;
break;
case 32000:
v = IPORTMXCTR1_FSSEL_32;
break;
case 44100:
v = IPORTMXCTR1_FSSEL_44_1;
break;
case 48000:
v = IPORTMXCTR1_FSSEL_48;
break;
case 88200:
v = IPORTMXCTR1_FSSEL_88_2;
break;
case 96000:
v = IPORTMXCTR1_FSSEL_96;
break;
case 176400:
v = IPORTMXCTR1_FSSEL_176_4;
break;
case 192000:
v = IPORTMXCTR1_FSSEL_192;
break;
default:
dev_err(dev, "Rate not supported(%d)\n", rate);
return -EINVAL;
}
regmap_update_bits(r, IPORTMXCTR1(sub->swm->iport.map),
IPORTMXCTR1_FSSEL_MASK, v);
}
return 0;
}
/**
* aio_port_set_fmt - set format of I2S data
* @sub: the AIO substream pointer, PCM substream only
* This parameter has no effect if substream is I2S or PCM.
*
* Set suitable I2S format settings to input/output port block of AIO.
* Parameter is specified by set_fmt().
*
* This function may return error if non-PCM substream.
*
* Return: Zero if successful, otherwise a negative value on error.
*/
int aio_port_set_fmt(struct uniphier_aio_sub *sub)
{
struct regmap *r = sub->aio->chip->regmap;
struct device *dev = &sub->aio->chip->pdev->dev;
u32 v;
if (sub->swm->dir == PORT_DIR_OUTPUT) {
switch (sub->aio->fmt) {
case SND_SOC_DAIFMT_LEFT_J:
v = OPORTMXCTR1_I2SLRSEL_LEFT;
break;
case SND_SOC_DAIFMT_RIGHT_J:
v = OPORTMXCTR1_I2SLRSEL_RIGHT;
break;
case SND_SOC_DAIFMT_I2S:
v = OPORTMXCTR1_I2SLRSEL_I2S;
break;
default:
dev_err(dev, "Format is not supported(%d)\n",
sub->aio->fmt);
return -EINVAL;
}
v |= OPORTMXCTR1_OUTBITSEL_24;
regmap_update_bits(r, OPORTMXCTR1(sub->swm->oport.map),
OPORTMXCTR1_I2SLRSEL_MASK |
OPORTMXCTR1_OUTBITSEL_MASK, v);
} else {
switch (sub->aio->fmt) {
case SND_SOC_DAIFMT_LEFT_J:
v = IPORTMXCTR1_LRSEL_LEFT;
break;
case SND_SOC_DAIFMT_RIGHT_J:
v = IPORTMXCTR1_LRSEL_RIGHT;
break;
case SND_SOC_DAIFMT_I2S:
v = IPORTMXCTR1_LRSEL_I2S;
break;
default:
dev_err(dev, "Format is not supported(%d)\n",
sub->aio->fmt);
return -EINVAL;
}
v |= IPORTMXCTR1_OUTBITSEL_24 |
IPORTMXCTR1_CHSEL_ALL;
regmap_update_bits(r, IPORTMXCTR1(sub->swm->iport.map),
IPORTMXCTR1_LRSEL_MASK |
IPORTMXCTR1_OUTBITSEL_MASK |
IPORTMXCTR1_CHSEL_MASK, v);
}
return 0;
}
/**
* aio_port_set_clk - set clock and divider of AIO port block
* @sub: the AIO substream pointer
*
* Set suitable PLL clock divider and relational settings to
* input/output port block of AIO. Parameters are specified by
* set_sysclk() and set_pll().
*
* Return: Zero if successful, otherwise a negative value on error.
*/
int aio_port_set_clk(struct uniphier_aio_sub *sub)
{
struct uniphier_aio_chip *chip = sub->aio->chip;
struct device *dev = &sub->aio->chip->pdev->dev;
struct regmap *r = sub->aio->chip->regmap;
u32 v_pll[] = {
OPORTMXCTR2_ACLKSEL_A1, OPORTMXCTR2_ACLKSEL_F1,
OPORTMXCTR2_ACLKSEL_A2, OPORTMXCTR2_ACLKSEL_F2,
OPORTMXCTR2_ACLKSEL_A2PLL,
OPORTMXCTR2_ACLKSEL_RX1,
};
u32 v_div[] = {
OPORTMXCTR2_DACCKSEL_1_2, OPORTMXCTR2_DACCKSEL_1_3,
OPORTMXCTR2_DACCKSEL_1_1, OPORTMXCTR2_DACCKSEL_2_3,
};
u32 v;
if (sub->swm->dir == PORT_DIR_OUTPUT) {
if (sub->swm->type == PORT_TYPE_I2S) {
if (sub->aio->pll_out >= ARRAY_SIZE(v_pll)) {
dev_err(dev, "PLL(%d) is invalid\n",
sub->aio->pll_out);
return -EINVAL;
}
if (sub->aio->plldiv >= ARRAY_SIZE(v_div)) {
dev_err(dev, "PLL divider(%d) is invalid\n",
sub->aio->plldiv);
return -EINVAL;
}
v = v_pll[sub->aio->pll_out] |
OPORTMXCTR2_MSSEL_MASTER |
v_div[sub->aio->plldiv];
switch (chip->plls[sub->aio->pll_out].freq) {
case 0:
case 36864000:
case 33868800:
v |= OPORTMXCTR2_EXTLSIFSSEL_36;
break;
default:
v |= OPORTMXCTR2_EXTLSIFSSEL_24;
break;
}
} else if (sub->swm->type == PORT_TYPE_EVE) {
v = OPORTMXCTR2_ACLKSEL_A2PLL |
OPORTMXCTR2_MSSEL_MASTER |
OPORTMXCTR2_EXTLSIFSSEL_36 |
OPORTMXCTR2_DACCKSEL_1_2;
} else if (sub->swm->type == PORT_TYPE_SPDIF) {
if (sub->aio->pll_out >= ARRAY_SIZE(v_pll)) {
dev_err(dev, "PLL(%d) is invalid\n",
sub->aio->pll_out);
return -EINVAL;
}
v = v_pll[sub->aio->pll_out] |
OPORTMXCTR2_MSSEL_MASTER |
OPORTMXCTR2_DACCKSEL_1_2;
switch (chip->plls[sub->aio->pll_out].freq) {
case 0:
case 36864000:
case 33868800:
v |= OPORTMXCTR2_EXTLSIFSSEL_36;
break;
default:
v |= OPORTMXCTR2_EXTLSIFSSEL_24;
break;
}
} else {
v = OPORTMXCTR2_ACLKSEL_A1 |
OPORTMXCTR2_MSSEL_MASTER |
OPORTMXCTR2_EXTLSIFSSEL_36 |
OPORTMXCTR2_DACCKSEL_1_2;
}
regmap_write(r, OPORTMXCTR2(sub->swm->oport.map), v);
} else {
v = IPORTMXCTR2_ACLKSEL_A1 |
IPORTMXCTR2_MSSEL_SLAVE |
IPORTMXCTR2_EXTLSIFSSEL_36 |
IPORTMXCTR2_DACCKSEL_1_2;
regmap_write(r, IPORTMXCTR2(sub->swm->iport.map), v);
}
return 0;
}
/**
* aio_port_set_param - set parameters of AIO port block
* @sub: the AIO substream pointer
* @pass_through: Zero if sound data is LPCM, otherwise if data is not LPCM.
* This parameter has no effect if substream is I2S or PCM.
* @params: hardware parameters of ALSA
*
* Set suitable setting to input/output port block of AIO to process the
* specified in params.
*
* Return: Zero if successful, otherwise a negative value on error.
*/
int aio_port_set_param(struct uniphier_aio_sub *sub, int pass_through,
const struct snd_pcm_hw_params *params)
{
struct regmap *r = sub->aio->chip->regmap;
unsigned int rate;
u32 v;
int ret;
if (!pass_through) {
if (sub->swm->type == PORT_TYPE_EVE ||
sub->swm->type == PORT_TYPE_CONV) {
rate = 48000;
} else {
rate = params_rate(params);
}
ret = aio_port_set_rate(sub, rate);
if (ret)
return ret;
ret = aio_port_set_fmt(sub);
if (ret)
return ret;
}
ret = aio_port_set_clk(sub);
if (ret)
return ret;
if (sub->swm->dir == PORT_DIR_OUTPUT) {
if (pass_through)
v = OPORTMXCTR3_SRCSEL_STREAM |
OPORTMXCTR3_VALID_STREAM;
else
v = OPORTMXCTR3_SRCSEL_PCM |
OPORTMXCTR3_VALID_PCM;
v |= OPORTMXCTR3_IECTHUR_IECOUT |
OPORTMXCTR3_PMSEL_PAUSE |
OPORTMXCTR3_PMSW_MUTE_OFF;
regmap_write(r, OPORTMXCTR3(sub->swm->oport.map), v);
} else {
regmap_write(r, IPORTMXACLKSEL0EX(sub->swm->iport.map),
IPORTMXACLKSEL0EX_ACLKSEL0EX_INTERNAL);
regmap_write(r, IPORTMXEXNOE(sub->swm->iport.map),
IPORTMXEXNOE_PCMINOE_INPUT);
}
return 0;
}
/**
* aio_port_set_enable - start or stop of AIO port block
* @sub: the AIO substream pointer
* @enable: zero to stop the block, otherwise to start
*
* Start or stop the signal input/output port block of AIO.
*/
void aio_port_set_enable(struct uniphier_aio_sub *sub, int enable)
{
struct regmap *r = sub->aio->chip->regmap;
if (sub->swm->dir == PORT_DIR_OUTPUT) {
regmap_write(r, OPORTMXPATH(sub->swm->oport.map),
sub->swm->oif.map);
regmap_update_bits(r, OPORTMXMASK(sub->swm->oport.map),
OPORTMXMASK_IUDXMSK_MASK |
OPORTMXMASK_IUXCKMSK_MASK |
OPORTMXMASK_DXMSK_MASK |
OPORTMXMASK_XCKMSK_MASK,
OPORTMXMASK_IUDXMSK_OFF |
OPORTMXMASK_IUXCKMSK_OFF |
OPORTMXMASK_DXMSK_OFF |
OPORTMXMASK_XCKMSK_OFF);
if (enable)
regmap_write(r, AOUTENCTR0, BIT(sub->swm->oport.map));
else
regmap_write(r, AOUTENCTR1, BIT(sub->swm->oport.map));
} else {
regmap_update_bits(r, IPORTMXMASK(sub->swm->iport.map),
IPORTMXMASK_IUXCKMSK_MASK |
IPORTMXMASK_XCKMSK_MASK,
IPORTMXMASK_IUXCKMSK_OFF |
IPORTMXMASK_XCKMSK_OFF);
if (enable)
regmap_update_bits(r,
IPORTMXCTR2(sub->swm->iport.map),
IPORTMXCTR2_REQEN_MASK,
IPORTMXCTR2_REQEN_ENABLE);
else
regmap_update_bits(r,
IPORTMXCTR2(sub->swm->iport.map),
IPORTMXCTR2_REQEN_MASK,
IPORTMXCTR2_REQEN_DISABLE);
}
}
/**
* aio_if_set_param - set parameters of AIO DMA I/F block
* @sub: the AIO substream pointer
* @pass_through: Zero if sound data is LPCM, otherwise if data is not LPCM.
* This parameter has no effect if substream is I2S or PCM.
*
* Set suitable setting to DMA interface block of AIO to process the
* specified in settings.
*
* Return: Zero if successful, otherwise a negative value on error.
*/
int aio_if_set_param(struct uniphier_aio_sub *sub, int pass_through)
{
struct regmap *r = sub->aio->chip->regmap;
u32 v;
if (sub->swm->dir == PORT_DIR_OUTPUT) {
if (pass_through)
v = PBOUTMXCTR0_ENDIAN_0123 |
PBOUTMXCTR0_MEMFMT_STREAM;
else
v = PBOUTMXCTR0_ENDIAN_3210 |
PBOUTMXCTR0_MEMFMT_2CH;
regmap_write(r, PBOUTMXCTR0(sub->swm->oif.map), v);
regmap_write(r, PBOUTMXCTR1(sub->swm->oif.map), 0);
} else {
regmap_write(r, PBINMXCTR(sub->swm->iif.map),
PBINMXCTR_NCONNECT_CONNECT |
PBINMXCTR_INOUTSEL_IN |
(sub->swm->iport.map << PBINMXCTR_PBINSEL_SHIFT) |
PBINMXCTR_ENDIAN_3210 |
PBINMXCTR_MEMFMT_D0);
}
return 0;
}
/**
* aio_oport_set_stream_type - set parameters of AIO playback port block
* @sub: the AIO substream pointer
* @pc: Pc type of IEC61937
*
* Set special setting to output port block of AIO to output the stream
* via S/PDIF.
*
* Return: Zero if successful, otherwise a negative value on error.
*/
int aio_oport_set_stream_type(struct uniphier_aio_sub *sub,
enum IEC61937_PC pc)
{
struct regmap *r = sub->aio->chip->regmap;
u32 repet = 0, pause = OPORTMXPAUDAT_PAUSEPC_CMN;
switch (pc) {
case IEC61937_PC_AC3:
repet = OPORTMXREPET_STRLENGTH_AC3 |
OPORTMXREPET_PMLENGTH_AC3;
pause |= OPORTMXPAUDAT_PAUSEPD_AC3;
break;
case IEC61937_PC_MPA:
repet = OPORTMXREPET_STRLENGTH_MPA |
OPORTMXREPET_PMLENGTH_MPA;
pause |= OPORTMXPAUDAT_PAUSEPD_MPA;
break;
case IEC61937_PC_MP3:
repet = OPORTMXREPET_STRLENGTH_MP3 |
OPORTMXREPET_PMLENGTH_MP3;
pause |= OPORTMXPAUDAT_PAUSEPD_MP3;
break;
case IEC61937_PC_DTS1:
repet = OPORTMXREPET_STRLENGTH_DTS1 |
OPORTMXREPET_PMLENGTH_DTS1;
pause |= OPORTMXPAUDAT_PAUSEPD_DTS1;
break;
case IEC61937_PC_DTS2:
repet = OPORTMXREPET_STRLENGTH_DTS2 |
OPORTMXREPET_PMLENGTH_DTS2;
pause |= OPORTMXPAUDAT_PAUSEPD_DTS2;
break;
case IEC61937_PC_DTS3:
repet = OPORTMXREPET_STRLENGTH_DTS3 |
OPORTMXREPET_PMLENGTH_DTS3;
pause |= OPORTMXPAUDAT_PAUSEPD_DTS3;
break;
case IEC61937_PC_AAC:
repet = OPORTMXREPET_STRLENGTH_AAC |
OPORTMXREPET_PMLENGTH_AAC;
pause |= OPORTMXPAUDAT_PAUSEPD_AAC;
break;
case IEC61937_PC_PAUSE:
/* Do nothing */
break;
}
regmap_write(r, OPORTMXREPET(sub->swm->oport.map), repet);
regmap_write(r, OPORTMXPAUDAT(sub->swm->oport.map), pause);
return 0;
}
/**
* aio_src_reset - reset AIO SRC block
* @sub: the AIO substream pointer
*
* Resets the digital signal input/output port with sampling rate converter
* block of AIO.
* This function has no effect if substream is not supported rate converter.
*/
void aio_src_reset(struct uniphier_aio_sub *sub)
{
struct regmap *r = sub->aio->chip->regmap;
if (sub->swm->dir != PORT_DIR_OUTPUT)
return;
regmap_write(r, AOUTSRCRSTCTR0, BIT(sub->swm->oport.map));
regmap_write(r, AOUTSRCRSTCTR1, BIT(sub->swm->oport.map));
}
/**
* aio_src_set_param - set parameters of AIO SRC block
* @sub: the AIO substream pointer
* @params: hardware parameters of ALSA
*
* Set suitable setting to input/output port with sampling rate converter
* block of AIO to process the specified in params.
* This function has no effect if substream is not supported rate converter.
*
* Return: Zero if successful, otherwise a negative value on error.
*/
int aio_src_set_param(struct uniphier_aio_sub *sub,
const struct snd_pcm_hw_params *params)
{
struct regmap *r = sub->aio->chip->regmap;
u32 v;
if (sub->swm->dir != PORT_DIR_OUTPUT)
return 0;
regmap_write(r, OPORTMXSRC1CTR(sub->swm->oport.map),
OPORTMXSRC1CTR_THMODE_SRC |
OPORTMXSRC1CTR_SRCPATH_CALC |
OPORTMXSRC1CTR_SYNC_ASYNC |
OPORTMXSRC1CTR_FSIIPSEL_INNER |
OPORTMXSRC1CTR_FSISEL_ACLK);
switch (params_rate(params)) {
default:
case 48000:
v = OPORTMXRATE_I_ACLKSEL_APLLA1 |
OPORTMXRATE_I_MCKSEL_36 |
OPORTMXRATE_I_FSSEL_48;
break;
case 44100:
v = OPORTMXRATE_I_ACLKSEL_APLLA2 |
OPORTMXRATE_I_MCKSEL_33 |
OPORTMXRATE_I_FSSEL_44_1;
break;
case 32000:
v = OPORTMXRATE_I_ACLKSEL_APLLA1 |
OPORTMXRATE_I_MCKSEL_36 |
OPORTMXRATE_I_FSSEL_32;
break;
}
regmap_write(r, OPORTMXRATE_I(sub->swm->oport.map),
v | OPORTMXRATE_I_ACLKSRC_APLL |
OPORTMXRATE_I_LRCKSTP_STOP);
regmap_update_bits(r, OPORTMXRATE_I(sub->swm->oport.map),
OPORTMXRATE_I_LRCKSTP_MASK,
OPORTMXRATE_I_LRCKSTP_START);
return 0;
}
int aio_srcif_set_param(struct uniphier_aio_sub *sub)
{
struct regmap *r = sub->aio->chip->regmap;
regmap_write(r, PBINMXCTR(sub->swm->iif.map),
PBINMXCTR_NCONNECT_CONNECT |
PBINMXCTR_INOUTSEL_OUT |
(sub->swm->oport.map << PBINMXCTR_PBINSEL_SHIFT) |
PBINMXCTR_ENDIAN_3210 |
PBINMXCTR_MEMFMT_D0);
return 0;
}
int aio_srcch_set_param(struct uniphier_aio_sub *sub)
{
struct regmap *r = sub->aio->chip->regmap;
regmap_write(r, CDA2D_CHMXCTRL1(sub->swm->och.map),
CDA2D_CHMXCTRL1_INDSIZE_INFINITE);
regmap_write(r, CDA2D_CHMXSRCAMODE(sub->swm->och.map),
CDA2D_CHMXAMODE_ENDIAN_3210 |
CDA2D_CHMXAMODE_AUPDT_FIX |
CDA2D_CHMXAMODE_TYPE_NORMAL);
regmap_write(r, CDA2D_CHMXDSTAMODE(sub->swm->och.map),
CDA2D_CHMXAMODE_ENDIAN_3210 |
CDA2D_CHMXAMODE_AUPDT_INC |
CDA2D_CHMXAMODE_TYPE_RING |
(sub->swm->och.map << CDA2D_CHMXAMODE_RSSEL_SHIFT));
return 0;
}
void aio_srcch_set_enable(struct uniphier_aio_sub *sub, int enable)
{
struct regmap *r = sub->aio->chip->regmap;
u32 v;
if (enable)
v = CDA2D_STRT0_STOP_START;
else
v = CDA2D_STRT0_STOP_STOP;
regmap_write(r, CDA2D_STRT0,
v | BIT(sub->swm->och.map));
}
int aiodma_ch_set_param(struct uniphier_aio_sub *sub)
{
struct regmap *r = sub->aio->chip->regmap;
u32 v;
regmap_write(r, CDA2D_CHMXCTRL1(sub->swm->ch.map),
CDA2D_CHMXCTRL1_INDSIZE_INFINITE);
v = CDA2D_CHMXAMODE_ENDIAN_3210 |
CDA2D_CHMXAMODE_AUPDT_INC |
CDA2D_CHMXAMODE_TYPE_NORMAL |
(sub->swm->rb.map << CDA2D_CHMXAMODE_RSSEL_SHIFT);
if (sub->swm->dir == PORT_DIR_OUTPUT)
regmap_write(r, CDA2D_CHMXSRCAMODE(sub->swm->ch.map), v);
else
regmap_write(r, CDA2D_CHMXDSTAMODE(sub->swm->ch.map), v);
return 0;
}
void aiodma_ch_set_enable(struct uniphier_aio_sub *sub, int enable)
{
struct regmap *r = sub->aio->chip->regmap;
if (enable) {
regmap_write(r, CDA2D_STRT0,
CDA2D_STRT0_STOP_START | BIT(sub->swm->ch.map));
regmap_update_bits(r, INTRBIM(0),
BIT(sub->swm->rb.map),
BIT(sub->swm->rb.map));
} else {
regmap_write(r, CDA2D_STRT0,
CDA2D_STRT0_STOP_STOP | BIT(sub->swm->ch.map));
regmap_update_bits(r, INTRBIM(0),
BIT(sub->swm->rb.map),
0);
}
}
static u64 aiodma_rb_get_rp(struct uniphier_aio_sub *sub)
{
struct regmap *r = sub->aio->chip->regmap;
u32 pos_u, pos_l;
int i;
regmap_write(r, CDA2D_RDPTRLOAD,
CDA2D_RDPTRLOAD_LSFLAG_STORE | BIT(sub->swm->rb.map));
/* Wait for setup */
for (i = 0; i < 6; i++)
regmap_read(r, CDA2D_RBMXRDPTR(sub->swm->rb.map), &pos_l);
regmap_read(r, CDA2D_RBMXRDPTR(sub->swm->rb.map), &pos_l);
regmap_read(r, CDA2D_RBMXRDPTRU(sub->swm->rb.map), &pos_u);
pos_u = FIELD_GET(CDA2D_RBMXPTRU_PTRU_MASK, pos_u);
return ((u64)pos_u << 32) | pos_l;
}
static void aiodma_rb_set_rp(struct uniphier_aio_sub *sub, u64 pos)
{
struct regmap *r = sub->aio->chip->regmap;
u32 tmp;
int i;
regmap_write(r, CDA2D_RBMXRDPTR(sub->swm->rb.map), (u32)pos);
regmap_write(r, CDA2D_RBMXRDPTRU(sub->swm->rb.map), (u32)(pos >> 32));
regmap_write(r, CDA2D_RDPTRLOAD, BIT(sub->swm->rb.map));
/* Wait for setup */
for (i = 0; i < 6; i++)
regmap_read(r, CDA2D_RBMXRDPTR(sub->swm->rb.map), &tmp);
}
static u64 aiodma_rb_get_wp(struct uniphier_aio_sub *sub)
{
struct regmap *r = sub->aio->chip->regmap;
u32 pos_u, pos_l;
int i;
regmap_write(r, CDA2D_WRPTRLOAD,
CDA2D_WRPTRLOAD_LSFLAG_STORE | BIT(sub->swm->rb.map));
/* Wait for setup */
for (i = 0; i < 6; i++)
regmap_read(r, CDA2D_RBMXWRPTR(sub->swm->rb.map), &pos_l);
regmap_read(r, CDA2D_RBMXWRPTR(sub->swm->rb.map), &pos_l);
regmap_read(r, CDA2D_RBMXWRPTRU(sub->swm->rb.map), &pos_u);
pos_u = FIELD_GET(CDA2D_RBMXPTRU_PTRU_MASK, pos_u);
return ((u64)pos_u << 32) | pos_l;
}
static void aiodma_rb_set_wp(struct uniphier_aio_sub *sub, u64 pos)
{
struct regmap *r = sub->aio->chip->regmap;
u32 tmp;
int i;
regmap_write(r, CDA2D_RBMXWRPTR(sub->swm->rb.map),
lower_32_bits(pos));
regmap_write(r, CDA2D_RBMXWRPTRU(sub->swm->rb.map),
upper_32_bits(pos));
regmap_write(r, CDA2D_WRPTRLOAD, BIT(sub->swm->rb.map));
/* Wait for setup */
for (i = 0; i < 6; i++)
regmap_read(r, CDA2D_RBMXWRPTR(sub->swm->rb.map), &tmp);
}
int aiodma_rb_set_threshold(struct uniphier_aio_sub *sub, u64 size, u32 th)
{
struct regmap *r = sub->aio->chip->regmap;
if (size <= th)
return -EINVAL;
regmap_write(r, CDA2D_RBMXBTH(sub->swm->rb.map), th);
regmap_write(r, CDA2D_RBMXRTH(sub->swm->rb.map), th);
return 0;
}
int aiodma_rb_set_buffer(struct uniphier_aio_sub *sub, u64 start, u64 end,
int period)
{
struct regmap *r = sub->aio->chip->regmap;
u64 size = end - start;
int ret;
if (end < start || period < 0)
return -EINVAL;
regmap_write(r, CDA2D_RBMXCNFG(sub->swm->rb.map), 0);
regmap_write(r, CDA2D_RBMXBGNADRS(sub->swm->rb.map),
lower_32_bits(start));
regmap_write(r, CDA2D_RBMXBGNADRSU(sub->swm->rb.map),
upper_32_bits(start));
regmap_write(r, CDA2D_RBMXENDADRS(sub->swm->rb.map),
lower_32_bits(end));
regmap_write(r, CDA2D_RBMXENDADRSU(sub->swm->rb.map),
upper_32_bits(end));
regmap_write(r, CDA2D_RBADRSLOAD, BIT(sub->swm->rb.map));
ret = aiodma_rb_set_threshold(sub, size, 2 * period);
if (ret)
return ret;
if (sub->swm->dir == PORT_DIR_OUTPUT) {
aiodma_rb_set_rp(sub, start);
aiodma_rb_set_wp(sub, end - period);
regmap_update_bits(r, CDA2D_RBMXIE(sub->swm->rb.map),
CDA2D_RBMXIX_SPACE,
CDA2D_RBMXIX_SPACE);
} else {
aiodma_rb_set_rp(sub, end - period);
aiodma_rb_set_wp(sub, start);
regmap_update_bits(r, CDA2D_RBMXIE(sub->swm->rb.map),
CDA2D_RBMXIX_REMAIN,
CDA2D_RBMXIX_REMAIN);
}
sub->threshold = 2 * period;
sub->rd_offs = 0;
sub->wr_offs = 0;
sub->rd_org = 0;
sub->wr_org = 0;
sub->rd_total = 0;
sub->wr_total = 0;
return 0;
}
void aiodma_rb_sync(struct uniphier_aio_sub *sub, u64 start, u64 size,
int period)
{
if (sub->swm->dir == PORT_DIR_OUTPUT) {
sub->rd_offs = aiodma_rb_get_rp(sub) - start;
if (sub->use_mmap) {
sub->threshold = 2 * period;
aiodma_rb_set_threshold(sub, size, 2 * period);
sub->wr_offs = sub->rd_offs - period;
if (sub->rd_offs < period)
sub->wr_offs += size;
}
aiodma_rb_set_wp(sub, sub->wr_offs + start);
} else {
sub->wr_offs = aiodma_rb_get_wp(sub) - start;
if (sub->use_mmap) {
sub->threshold = 2 * period;
aiodma_rb_set_threshold(sub, size, 2 * period);
sub->rd_offs = sub->wr_offs - period;
if (sub->wr_offs < period)
sub->rd_offs += size;
}
aiodma_rb_set_rp(sub, sub->rd_offs + start);
}
sub->rd_total += sub->rd_offs - sub->rd_org;
if (sub->rd_offs < sub->rd_org)
sub->rd_total += size;
sub->wr_total += sub->wr_offs - sub->wr_org;
if (sub->wr_offs < sub->wr_org)
sub->wr_total += size;
sub->rd_org = sub->rd_offs;
sub->wr_org = sub->wr_offs;
}
bool aiodma_rb_is_irq(struct uniphier_aio_sub *sub)
{
struct regmap *r = sub->aio->chip->regmap;
u32 ir;
regmap_read(r, CDA2D_RBMXIR(sub->swm->rb.map), &ir);
if (sub->swm->dir == PORT_DIR_OUTPUT)
return !!(ir & CDA2D_RBMXIX_SPACE);
else
return !!(ir & CDA2D_RBMXIX_REMAIN);
}
void aiodma_rb_clear_irq(struct uniphier_aio_sub *sub)
{
struct regmap *r = sub->aio->chip->regmap;
if (sub->swm->dir == PORT_DIR_OUTPUT)
regmap_write(r, CDA2D_RBMXIR(sub->swm->rb.map),
CDA2D_RBMXIX_SPACE);
else
regmap_write(r, CDA2D_RBMXIR(sub->swm->rb.map),
CDA2D_RBMXIX_REMAIN);
}
// SPDX-License-Identifier: GPL-2.0
//
// Socionext UniPhier AIO ALSA CPU DAI driver.
//
// Copyright (c) 2016-2018 Socionext Inc.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; version 2
// of the License.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, see <http://www.gnu.org/licenses/>.
#include <linux/clk.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/reset.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include "aio.h"
static bool is_valid_pll(struct uniphier_aio_chip *chip, int pll_id)
{
struct device *dev = &chip->pdev->dev;
if (pll_id < 0 || chip->num_plls <= pll_id) {
dev_err(dev, "PLL(%d) is not supported\n", pll_id);
return false;
}
return chip->plls[pll_id].enable;
}
static bool match_spec(const struct uniphier_aio_spec *spec,
const char *name, int dir)
{
if (dir == SNDRV_PCM_STREAM_PLAYBACK &&
spec->swm.dir != PORT_DIR_OUTPUT) {
return false;
}
if (dir == SNDRV_PCM_STREAM_CAPTURE &&
spec->swm.dir != PORT_DIR_INPUT) {
return false;
}
if (spec->name && strcmp(spec->name, name) == 0)
return true;
if (spec->gname && strcmp(spec->gname, name) == 0)
return true;
return false;
}
/**
* find_spec - find HW specification info by name
* @aio: the AIO device pointer
* @name: name of device
* @direction: the direction of substream, SNDRV_PCM_STREAM_*
*
* Find hardware specification information from list by device name. This
* information is used for telling the difference of SoCs to driver.
*
* Specification list is array of 'struct uniphier_aio_spec' which is defined
* in each drivers (see: aio-i2s.c).
*
* Return: The pointer of hardware specification of AIO if successful,
* otherwise NULL on error.
*/
static const struct uniphier_aio_spec *find_spec(struct uniphier_aio *aio,
const char *name,
int direction)
{
const struct uniphier_aio_chip_spec *chip_spec = aio->chip->chip_spec;
int i;
for (i = 0; i < chip_spec->num_specs; i++) {
const struct uniphier_aio_spec *spec = &chip_spec->specs[i];
if (match_spec(spec, name, direction))
return spec;
}
return NULL;
}
/**
* find_divider - find clock divider by frequency
* @aio: the AIO device pointer
* @pll_id: PLL ID, should be AUD_PLL_XX
* @freq: required frequency
*
* Find suitable clock divider by frequency.
*
* Return: The ID of PLL if successful, otherwise negative error value.
*/
static int find_divider(struct uniphier_aio *aio, int pll_id, unsigned int freq)
{
struct uniphier_aio_pll *pll;
int mul[] = { 1, 1, 1, 2, };
int div[] = { 2, 3, 1, 3, };
int i;
if (!is_valid_pll(aio->chip, pll_id))
return -EINVAL;
pll = &aio->chip->plls[pll_id];
for (i = 0; i < ARRAY_SIZE(mul); i++)
if (pll->freq * mul[i] / div[i] == freq)
return i;
return -ENOTSUPP;
}
static int uniphier_aio_set_sysclk(struct snd_soc_dai *dai, int clk_id,
unsigned int freq, int dir)
{
struct uniphier_aio *aio = uniphier_priv(dai);
struct device *dev = &aio->chip->pdev->dev;
bool pll_auto = false;
int pll_id, div_id;
switch (clk_id) {
case AUD_CLK_IO:
return -ENOTSUPP;
case AUD_CLK_A1:
pll_id = AUD_PLL_A1;
break;
case AUD_CLK_F1:
pll_id = AUD_PLL_F1;
break;
case AUD_CLK_A2:
pll_id = AUD_PLL_A2;
break;
case AUD_CLK_F2:
pll_id = AUD_PLL_F2;
break;
case AUD_CLK_A:
pll_id = AUD_PLL_A1;
pll_auto = true;
break;
case AUD_CLK_F:
pll_id = AUD_PLL_F1;
pll_auto = true;
break;
case AUD_CLK_APLL:
pll_id = AUD_PLL_APLL;
break;
case AUD_CLK_RX0:
pll_id = AUD_PLL_RX0;
break;
case AUD_CLK_USB0:
pll_id = AUD_PLL_USB0;
break;
case AUD_CLK_HSC0:
pll_id = AUD_PLL_HSC0;
break;
default:
dev_err(dev, "Sysclk(%d) is not supported\n", clk_id);
return -EINVAL;
}
if (pll_auto) {
for (pll_id = 0; pll_id < aio->chip->num_plls; pll_id++) {
div_id = find_divider(aio, pll_id, freq);
if (div_id >= 0) {
aio->plldiv = div_id;
break;
}
}
if (pll_id == aio->chip->num_plls) {
dev_err(dev, "Sysclk frequency is not supported(%d)\n",
freq);
return -EINVAL;
}
}
if (dir == SND_SOC_CLOCK_OUT)
aio->pll_out = pll_id;
else
aio->pll_in = pll_id;
return 0;
}
static int uniphier_aio_set_pll(struct snd_soc_dai *dai, int pll_id,
int source, unsigned int freq_in,
unsigned int freq_out)
{
struct uniphier_aio *aio = uniphier_priv(dai);
struct device *dev = &aio->chip->pdev->dev;
int ret;
if (!is_valid_pll(aio->chip, pll_id))
return -EINVAL;
if (!aio->chip->plls[pll_id].enable) {
dev_err(dev, "PLL(%d) is not implemented\n", pll_id);
return -ENOTSUPP;
}
ret = aio_chip_set_pll(aio->chip, pll_id, freq_out);
if (ret < 0)
return ret;
return 0;
}
static int uniphier_aio_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
struct uniphier_aio *aio = uniphier_priv(dai);
struct device *dev = &aio->chip->pdev->dev;
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_LEFT_J:
case SND_SOC_DAIFMT_RIGHT_J:
case SND_SOC_DAIFMT_I2S:
aio->fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
break;
default:
dev_err(dev, "Format is not supported(%d)\n",
fmt & SND_SOC_DAIFMT_FORMAT_MASK);
return -EINVAL;
}
return 0;
}
static int uniphier_aio_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct uniphier_aio *aio = uniphier_priv(dai);
struct uniphier_aio_sub *sub = &aio->sub[substream->stream];
int ret;
sub->substream = substream;
sub->pass_through = 0;
sub->use_mmap = true;
ret = aio_init(sub);
if (ret)
return ret;
return 0;
}
static void uniphier_aio_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct uniphier_aio *aio = uniphier_priv(dai);
struct uniphier_aio_sub *sub = &aio->sub[substream->stream];
sub->substream = NULL;
}
static int uniphier_aio_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct uniphier_aio *aio = uniphier_priv(dai);
struct uniphier_aio_sub *sub = &aio->sub[substream->stream];
struct device *dev = &aio->chip->pdev->dev;
int freq, ret;
switch (params_rate(params)) {
case 48000:
case 32000:
case 24000:
freq = 12288000;
break;
case 44100:
case 22050:
freq = 11289600;
break;
default:
dev_err(dev, "Rate is not supported(%d)\n",
params_rate(params));
return -EINVAL;
}
ret = snd_soc_dai_set_sysclk(dai, AUD_CLK_A,
freq, SND_SOC_CLOCK_OUT);
if (ret)
return ret;
sub->params = *params;
sub->setting = 1;
aio_port_reset(sub);
aio_src_reset(sub);
return 0;
}
static int uniphier_aio_hw_free(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct uniphier_aio *aio = uniphier_priv(dai);
struct uniphier_aio_sub *sub = &aio->sub[substream->stream];
sub->setting = 0;
return 0;
}
static int uniphier_aio_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct uniphier_aio *aio = uniphier_priv(dai);
struct uniphier_aio_sub *sub = &aio->sub[substream->stream];
int ret;
ret = aio_port_set_param(sub, sub->pass_through, &sub->params);
if (ret)
return ret;
ret = aio_src_set_param(sub, &sub->params);
if (ret)
return ret;
aio_port_set_enable(sub, 1);
ret = aio_if_set_param(sub, sub->pass_through);
if (ret)
return ret;
if (sub->swm->type == PORT_TYPE_CONV) {
ret = aio_srcif_set_param(sub);
if (ret)
return ret;
ret = aio_srcch_set_param(sub);
if (ret)
return ret;
aio_srcch_set_enable(sub, 1);
}
return 0;
}
const struct snd_soc_dai_ops uniphier_aio_i2s_ops = {
.set_sysclk = uniphier_aio_set_sysclk,
.set_pll = uniphier_aio_set_pll,
.set_fmt = uniphier_aio_set_fmt,
.startup = uniphier_aio_startup,
.shutdown = uniphier_aio_shutdown,
.hw_params = uniphier_aio_hw_params,
.hw_free = uniphier_aio_hw_free,
.prepare = uniphier_aio_prepare,
};
EXPORT_SYMBOL_GPL(uniphier_aio_i2s_ops);
const struct snd_soc_dai_ops uniphier_aio_spdif_ops = {
.set_sysclk = uniphier_aio_set_sysclk,
.set_pll = uniphier_aio_set_pll,
.startup = uniphier_aio_startup,
.shutdown = uniphier_aio_shutdown,
.hw_params = uniphier_aio_hw_params,
.hw_free = uniphier_aio_hw_free,
.prepare = uniphier_aio_prepare,
};
EXPORT_SYMBOL_GPL(uniphier_aio_spdif_ops);
int uniphier_aio_dai_probe(struct snd_soc_dai *dai)
{
struct uniphier_aio *aio = uniphier_priv(dai);
int i;
for (i = 0; i < ARRAY_SIZE(aio->sub); i++) {
struct uniphier_aio_sub *sub = &aio->sub[i];
const struct uniphier_aio_spec *spec;
spec = find_spec(aio, dai->name, i);
if (!spec)
continue;
sub->swm = &spec->swm;
sub->spec = spec;
}
aio_iecout_set_enable(aio->chip, true);
aio_chip_init(aio->chip);
aio->chip->active = 1;
return 0;
}
EXPORT_SYMBOL_GPL(uniphier_aio_dai_probe);
int uniphier_aio_dai_remove(struct snd_soc_dai *dai)
{
struct uniphier_aio *aio = uniphier_priv(dai);
aio->chip->active = 0;
return 0;
}
EXPORT_SYMBOL_GPL(uniphier_aio_dai_remove);
int uniphier_aio_dai_suspend(struct snd_soc_dai *dai)
{
struct uniphier_aio *aio = uniphier_priv(dai);
reset_control_assert(aio->chip->rst);
clk_disable_unprepare(aio->chip->clk);
return 0;
}
EXPORT_SYMBOL_GPL(uniphier_aio_dai_suspend);
int uniphier_aio_dai_resume(struct snd_soc_dai *dai)
{
struct uniphier_aio *aio = uniphier_priv(dai);
int ret, i;
if (!aio->chip->active)
return 0;
ret = clk_prepare_enable(aio->chip->clk);
if (ret)
return ret;
ret = reset_control_deassert(aio->chip->rst);
if (ret)
goto err_out_clock;
aio_iecout_set_enable(aio->chip, true);
aio_chip_init(aio->chip);
for (i = 0; i < ARRAY_SIZE(aio->sub); i++) {
struct uniphier_aio_sub *sub = &aio->sub[i];
if (!sub->spec || !sub->substream)
continue;
ret = aio_init(sub);
if (ret)
goto err_out_clock;
if (!sub->setting)
continue;
aio_port_reset(sub);
aio_src_reset(sub);
}
return 0;
err_out_clock:
clk_disable_unprepare(aio->chip->clk);
return ret;
}
EXPORT_SYMBOL_GPL(uniphier_aio_dai_resume);
static const struct snd_soc_component_driver uniphier_aio_component = {
.name = "uniphier-aio",
};
int uniphier_aio_probe(struct platform_device *pdev)
{
struct uniphier_aio_chip *chip;
struct device *dev = &pdev->dev;
int ret, i, j;
chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
chip->chip_spec = of_device_get_match_data(dev);
if (!chip->chip_spec)
return -EINVAL;
chip->regmap_sg = syscon_regmap_lookup_by_phandle(dev->of_node,
"socionext,syscon");
if (IS_ERR(chip->regmap_sg)) {
if (PTR_ERR(chip->regmap_sg) == -EPROBE_DEFER)
return -EPROBE_DEFER;
chip->regmap_sg = NULL;
}
chip->clk = devm_clk_get(dev, "aio");
if (IS_ERR(chip->clk))
return PTR_ERR(chip->clk);
chip->rst = devm_reset_control_get_shared(dev, "aio");
if (IS_ERR(chip->rst))
return PTR_ERR(chip->rst);
chip->num_aios = chip->chip_spec->num_dais;
chip->aios = devm_kzalloc(dev,
sizeof(struct uniphier_aio) * chip->num_aios,
GFP_KERNEL);
if (!chip->aios)
return -ENOMEM;
chip->num_plls = chip->chip_spec->num_plls;
chip->plls = devm_kzalloc(dev, sizeof(struct uniphier_aio_pll) *
chip->num_plls, GFP_KERNEL);
if (!chip->plls)
return -ENOMEM;
memcpy(chip->plls, chip->chip_spec->plls,
sizeof(struct uniphier_aio_pll) * chip->num_plls);
for (i = 0; i < chip->num_aios; i++) {
struct uniphier_aio *aio = &chip->aios[i];
aio->chip = chip;
aio->fmt = SND_SOC_DAIFMT_I2S;
for (j = 0; j < ARRAY_SIZE(aio->sub); j++) {
struct uniphier_aio_sub *sub = &aio->sub[j];
sub->aio = aio;
spin_lock_init(&sub->lock);
}
}
chip->pdev = pdev;
platform_set_drvdata(pdev, chip);
ret = clk_prepare_enable(chip->clk);
if (ret)
return ret;
ret = reset_control_deassert(chip->rst);
if (ret)
goto err_out_clock;
ret = devm_snd_soc_register_component(dev, &uniphier_aio_component,
chip->chip_spec->dais,
chip->chip_spec->num_dais);
if (ret) {
dev_err(dev, "Register component failed.\n");
goto err_out_reset;
}
ret = uniphier_aiodma_soc_register_platform(pdev);
if (ret) {
dev_err(dev, "Register platform failed.\n");
goto err_out_reset;
}
return 0;
err_out_reset:
reset_control_assert(chip->rst);
err_out_clock:
clk_disable_unprepare(chip->clk);
return ret;
}
EXPORT_SYMBOL_GPL(uniphier_aio_probe);
int uniphier_aio_remove(struct platform_device *pdev)
{
struct uniphier_aio_chip *chip = platform_get_drvdata(pdev);
reset_control_assert(chip->rst);
clk_disable_unprepare(chip->clk);
return 0;
}
EXPORT_SYMBOL_GPL(uniphier_aio_remove);
MODULE_AUTHOR("Katsuhiro Suzuki <suzuki.katsuhiro@socionext.com>");
MODULE_DESCRIPTION("UniPhier AIO CPU DAI driver.");
MODULE_LICENSE("GPL v2");
// SPDX-License-Identifier: GPL-2.0
//
// Socionext UniPhier AIO DMA driver.
//
// Copyright (c) 2016-2018 Socionext Inc.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; version 2
// of the License.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, see <http://www.gnu.org/licenses/>.
#include <linux/dma-mapping.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include "aio.h"
static struct snd_pcm_hardware uniphier_aiodma_hw = {
.info = SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_INTERLEAVED,
.period_bytes_min = 256,
.period_bytes_max = 4096,
.periods_min = 4,
.periods_max = 1024,
.buffer_bytes_max = 128 * 1024,
};
static void aiodma_pcm_irq(struct uniphier_aio_sub *sub)
{
struct snd_pcm_runtime *runtime = sub->substream->runtime;
int bytes = runtime->period_size *
runtime->channels * samples_to_bytes(runtime, 1);
int ret;
spin_lock(&sub->lock);
ret = aiodma_rb_set_threshold(sub, runtime->dma_bytes,
sub->threshold + bytes);
if (!ret)
sub->threshold += bytes;
aiodma_rb_sync(sub, runtime->dma_addr, runtime->dma_bytes, bytes);
aiodma_rb_clear_irq(sub);
spin_unlock(&sub->lock);
snd_pcm_period_elapsed(sub->substream);
}
static void aiodma_compr_irq(struct uniphier_aio_sub *sub)
{
struct snd_compr_runtime *runtime = sub->cstream->runtime;
int bytes = runtime->fragment_size;
int ret;
spin_lock(&sub->lock);
ret = aiodma_rb_set_threshold(sub, sub->compr_bytes,
sub->threshold + bytes);
if (!ret)
sub->threshold += bytes;
aiodma_rb_sync(sub, sub->compr_addr, sub->compr_bytes, bytes);
aiodma_rb_clear_irq(sub);
spin_unlock(&sub->lock);
snd_compr_fragment_elapsed(sub->cstream);
}
static irqreturn_t aiodma_irq(int irq, void *p)
{
struct platform_device *pdev = p;
struct uniphier_aio_chip *chip = platform_get_drvdata(pdev);
irqreturn_t ret = IRQ_NONE;
int i, j;
for (i = 0; i < chip->num_aios; i++) {
struct uniphier_aio *aio = &chip->aios[i];
for (j = 0; j < ARRAY_SIZE(aio->sub); j++) {
struct uniphier_aio_sub *sub = &aio->sub[j];
/* Skip channel that does not trigger */
if (!sub->running || !aiodma_rb_is_irq(sub))
continue;
if (sub->substream)
aiodma_pcm_irq(sub);
if (sub->cstream)
aiodma_compr_irq(sub);
ret = IRQ_HANDLED;
}
}
return ret;
}
static int uniphier_aiodma_open(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
snd_soc_set_runtime_hwparams(substream, &uniphier_aiodma_hw);
return snd_pcm_hw_constraint_step(runtime, 0,
SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 256);
}
static int uniphier_aiodma_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
substream->runtime->dma_bytes = params_buffer_bytes(params);
return 0;
}
static int uniphier_aiodma_hw_free(struct snd_pcm_substream *substream)
{
snd_pcm_set_runtime_buffer(substream, NULL);
substream->runtime->dma_bytes = 0;
return 0;
}
static int uniphier_aiodma_prepare(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
struct uniphier_aio_sub *sub = &aio->sub[substream->stream];
int bytes = runtime->period_size *
runtime->channels * samples_to_bytes(runtime, 1);
unsigned long flags;
int ret;
ret = aiodma_ch_set_param(sub);
if (ret)
return ret;
spin_lock_irqsave(&sub->lock, flags);
ret = aiodma_rb_set_buffer(sub, runtime->dma_addr,
runtime->dma_addr + runtime->dma_bytes,
bytes);
spin_unlock_irqrestore(&sub->lock, flags);
if (ret)
return ret;
return 0;
}
static int uniphier_aiodma_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
struct uniphier_aio_sub *sub = &aio->sub[substream->stream];
struct device *dev = &aio->chip->pdev->dev;
int bytes = runtime->period_size *
runtime->channels * samples_to_bytes(runtime, 1);
unsigned long flags;
spin_lock_irqsave(&sub->lock, flags);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
aiodma_rb_sync(sub, runtime->dma_addr, runtime->dma_bytes,
bytes);
aiodma_ch_set_enable(sub, 1);
sub->running = 1;
break;
case SNDRV_PCM_TRIGGER_STOP:
sub->running = 0;
aiodma_ch_set_enable(sub, 0);
break;
default:
dev_warn(dev, "Unknown trigger(%d) ignored\n", cmd);
break;
}
spin_unlock_irqrestore(&sub->lock, flags);
return 0;
}
static snd_pcm_uframes_t uniphier_aiodma_pointer(
struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
struct uniphier_aio_sub *sub = &aio->sub[substream->stream];
int bytes = runtime->period_size *
runtime->channels * samples_to_bytes(runtime, 1);
unsigned long flags;
snd_pcm_uframes_t pos;
spin_lock_irqsave(&sub->lock, flags);
aiodma_rb_sync(sub, runtime->dma_addr, runtime->dma_bytes, bytes);
if (sub->swm->dir == PORT_DIR_OUTPUT)
pos = bytes_to_frames(runtime, sub->rd_offs);
else
pos = bytes_to_frames(runtime, sub->wr_offs);
spin_unlock_irqrestore(&sub->lock, flags);
return pos;
}
static int uniphier_aiodma_mmap(struct snd_pcm_substream *substream,
struct vm_area_struct *vma)
{
vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
return remap_pfn_range(vma, vma->vm_start,
substream->dma_buffer.addr >> PAGE_SHIFT,
vma->vm_end - vma->vm_start, vma->vm_page_prot);
}
static const struct snd_pcm_ops uniphier_aiodma_ops = {
.open = uniphier_aiodma_open,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = uniphier_aiodma_hw_params,
.hw_free = uniphier_aiodma_hw_free,
.prepare = uniphier_aiodma_prepare,
.trigger = uniphier_aiodma_trigger,
.pointer = uniphier_aiodma_pointer,
.mmap = uniphier_aiodma_mmap,
};
static int uniphier_aiodma_new(struct snd_soc_pcm_runtime *rtd)
{
struct device *dev = rtd->card->snd_card->dev;
struct snd_pcm *pcm = rtd->pcm;
int ret;
ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(33));
if (ret)
return ret;
return snd_pcm_lib_preallocate_pages_for_all(pcm,
SNDRV_DMA_TYPE_DEV, dev,
uniphier_aiodma_hw.buffer_bytes_max,
uniphier_aiodma_hw.buffer_bytes_max);
}
static void uniphier_aiodma_free(struct snd_pcm *pcm)
{
snd_pcm_lib_preallocate_free_for_all(pcm);
}
static const struct snd_soc_component_driver uniphier_soc_platform = {
.pcm_new = uniphier_aiodma_new,
.pcm_free = uniphier_aiodma_free,
.ops = &uniphier_aiodma_ops,
.compr_ops = &uniphier_aio_compr_ops,
};
static const struct regmap_config aiodma_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
.max_register = 0x7fffc,
.cache_type = REGCACHE_NONE,
};
/**
* uniphier_aiodma_soc_register_platform - register the AIO DMA
* @pdev: the platform device
*
* Register and setup the DMA of AIO to transfer the sound data to device.
* This function need to call once at driver startup and need NOT to call
* unregister function.
*
* Return: Zero if successful, otherwise a negative value on error.
*/
int uniphier_aiodma_soc_register_platform(struct platform_device *pdev)
{
struct uniphier_aio_chip *chip = platform_get_drvdata(pdev);
struct device *dev = &pdev->dev;
struct resource *res;
void __iomem *preg;
int irq, ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
preg = devm_ioremap_resource(dev, res);
if (IS_ERR(preg))
return PTR_ERR(preg);
chip->regmap = devm_regmap_init_mmio(dev, preg,
&aiodma_regmap_config);
if (IS_ERR(chip->regmap))
return PTR_ERR(chip->regmap);
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(dev, "Could not get irq.\n");
return irq;
}
ret = devm_request_irq(dev, irq, aiodma_irq,
IRQF_SHARED, dev_name(dev), pdev);
if (ret)
return ret;
return devm_snd_soc_register_component(dev, &uniphier_soc_platform,
NULL, 0);
}
EXPORT_SYMBOL_GPL(uniphier_aiodma_soc_register_platform);
// SPDX-License-Identifier: GPL-2.0
//
// Socionext UniPhier AIO ALSA driver for LD11/LD20.
//
// Copyright (c) 2016-2018 Socionext Inc.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; version 2
// of the License.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, see <http://www.gnu.org/licenses/>.
#include <linux/module.h>
#include "aio.h"
static const struct uniphier_aio_spec uniphier_aio_ld11[] = {
/* for HDMI PCM In, Pin:AI1Dx */
{
.name = AUD_NAME_PCMIN1,
.gname = AUD_GNAME_HDMI,
.swm = {
.type = PORT_TYPE_I2S,
.dir = PORT_DIR_INPUT,
.rb = { 21, 14, },
.ch = { 21, 14, },
.iif = { 5, 3, },
.iport = { 0, AUD_HW_PCMIN1, },
},
},
/* for SIF In, Pin:AI2Dx */
{
.name = AUD_NAME_PCMIN2,
.swm = {
.type = PORT_TYPE_I2S,
.dir = PORT_DIR_INPUT,
.rb = { 22, 15, },
.ch = { 22, 15, },
.iif = { 6, 4, },
.iport = { 1, AUD_HW_PCMIN2, },
},
},
/* for Line In, Pin:AI3Dx */
{
.name = AUD_NAME_PCMIN3,
.gname = AUD_GNAME_LINE,
.swm = {
.type = PORT_TYPE_EVE,
.dir = PORT_DIR_INPUT,
.rb = { 23, 16, },
.ch = { 23, 16, },
.iif = { 7, 5, },
.iport = { 2, AUD_HW_PCMIN3, },
},
},
/* for S/PDIF In, Pin:AI1IEC */
{
.name = AUD_NAME_IECIN1,
.gname = AUD_GNAME_IEC,
.swm = {
.type = PORT_TYPE_SPDIF,
.dir = PORT_DIR_INPUT,
.rb = { 26, 17, },
.ch = { 26, 17, },
.iif = { 10, 6, },
.iport = { 3, AUD_HW_IECIN1, },
},
},
/* for Speaker, Pin:AO1Dx */
{
.name = AUD_NAME_HPCMOUT1,
.swm = {
.type = PORT_TYPE_I2S,
.dir = PORT_DIR_OUTPUT,
.rb = { 0, 0, },
.ch = { 0, 0, },
.oif = { 0, 0, },
.oport = { 0, AUD_HW_HPCMOUT1, },
},
},
/* for HDMI PCM, Pin:AO2Dx */
{
.name = AUD_NAME_PCMOUT1,
.gname = AUD_GNAME_HDMI,
.swm = {
.type = PORT_TYPE_I2S,
.dir = PORT_DIR_OUTPUT,
.rb = { 0, 0, },
.ch = { 0, 0, },
.oif = { 0, 0, },
.oport = { 3, AUD_HW_PCMOUT1, },
},
},
/* for Line Out, Pin:LO2_x */
{
.name = AUD_NAME_PCMOUT2,
.gname = AUD_GNAME_LINE,
.swm = {
.type = PORT_TYPE_EVE,
.dir = PORT_DIR_OUTPUT,
.rb = { 2, 2, },
.ch = { 2, 2, },
.oif = { 2, 2, },
.oport = { 1, AUD_HW_PCMOUT2, },
},
},
/* for Headphone, Pin:HP1_x */
{
.name = AUD_NAME_PCMOUT3,
.swm = {
.type = PORT_TYPE_EVE,
.dir = PORT_DIR_OUTPUT,
.rb = { 3, 3, },
.ch = { 3, 3, },
.oif = { 3, 3, },
.oport = { 2, AUD_HW_PCMOUT3, },
},
},
/* for HW Sampling Rate Converter */
{
.name = AUD_NAME_EPCMOUT2,
.swm = {
.type = PORT_TYPE_CONV,
.dir = PORT_DIR_OUTPUT,
.rb = { 7, 5, },
.ch = { 7, 5, },
.oif = { 7, 5, },
.oport = { 6, AUD_HW_EPCMOUT2, },
.och = { 17, 12, },
.iif = { 1, 1, },
},
},
/* for HW Sampling Rate Converter 2 */
{
.name = AUD_NAME_EPCMOUT3,
.swm = {
.type = PORT_TYPE_CONV,
.dir = PORT_DIR_OUTPUT,
.rb = { 8, 6, },
.ch = { 8, 6, },
.oif = { 8, 6, },
.oport = { 7, AUD_HW_EPCMOUT3, },
.och = { 18, 13, },
.iif = { 2, 2, },
},
},
/* for S/PDIF Out, Pin:AO1IEC */
{
.name = AUD_NAME_HIECOUT1,
.gname = AUD_GNAME_IEC,
.swm = {
.type = PORT_TYPE_SPDIF,
.dir = PORT_DIR_OUTPUT,
.rb = { 1, 1, },
.ch = { 1, 1, },
.oif = { 1, 1, },
.oport = { 12, AUD_HW_HIECOUT1, },
},
},
/* for S/PDIF Out, Pin:AO1IEC, Compress */
{
.name = AUD_NAME_HIECCOMPOUT1,
.gname = AUD_GNAME_IEC,
.swm = {
.type = PORT_TYPE_SPDIF,
.dir = PORT_DIR_OUTPUT,
.rb = { 1, 1, },
.ch = { 1, 1, },
.oif = { 1, 1, },
.oport = { 12, AUD_HW_HIECOUT1, },
},
},
};
static const struct uniphier_aio_pll uniphier_aio_pll_ld11[] = {
[AUD_PLL_A1] = { .enable = true, },
[AUD_PLL_F1] = { .enable = true, },
[AUD_PLL_A2] = { .enable = true, },
[AUD_PLL_F2] = { .enable = true, },
[AUD_PLL_APLL] = { .enable = true, },
[AUD_PLL_RX0] = { .enable = true, },
[AUD_PLL_USB0] = { .enable = true, },
[AUD_PLL_HSC0] = { .enable = true, },
};
static int uniphier_aio_ld11_probe(struct snd_soc_dai *dai)
{
int ret;
ret = uniphier_aio_dai_probe(dai);
if (ret < 0)
return ret;
ret = snd_soc_dai_set_pll(dai, AUD_PLL_A1, 0, 0, 36864000);
if (ret < 0)
return ret;
ret = snd_soc_dai_set_pll(dai, AUD_PLL_F1, 0, 0, 36864000);
if (ret < 0)
return ret;
ret = snd_soc_dai_set_pll(dai, AUD_PLL_A2, 0, 0, 33868800);
if (ret < 0)
return ret;
ret = snd_soc_dai_set_pll(dai, AUD_PLL_F2, 0, 0, 33868800);
if (ret < 0)
return ret;
return 0;
}
static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = {
{
.name = AUD_GNAME_HDMI,
.probe = uniphier_aio_ld11_probe,
.remove = uniphier_aio_dai_remove,
.suspend = uniphier_aio_dai_suspend,
.resume = uniphier_aio_dai_resume,
.playback = {
.stream_name = AUD_NAME_PCMOUT1,
.formats = SNDRV_PCM_FMTBIT_S32_LE,
.rates = SNDRV_PCM_RATE_48000,
.channels_min = 2,
.channels_max = 2,
},
.capture = {
.stream_name = AUD_NAME_PCMIN1,
.formats = SNDRV_PCM_FMTBIT_S32_LE,
.rates = SNDRV_PCM_RATE_48000 |
SNDRV_PCM_RATE_44100 |
SNDRV_PCM_RATE_32000,
.channels_min = 2,
.channels_max = 2,
},
.ops = &uniphier_aio_i2s_ops,
},
{
.name = AUD_NAME_PCMIN2,
.probe = uniphier_aio_ld11_probe,
.remove = uniphier_aio_dai_remove,
.suspend = uniphier_aio_dai_suspend,
.resume = uniphier_aio_dai_resume,
.capture = {
.stream_name = AUD_NAME_PCMIN2,
.formats = SNDRV_PCM_FMTBIT_S32_LE,
.rates = SNDRV_PCM_RATE_48000,
.channels_min = 2,
.channels_max = 2,
},
.ops = &uniphier_aio_i2s_ops,
},
{
.name = AUD_GNAME_LINE,
.probe = uniphier_aio_ld11_probe,
.remove = uniphier_aio_dai_remove,
.suspend = uniphier_aio_dai_suspend,
.resume = uniphier_aio_dai_resume,
.playback = {
.stream_name = AUD_NAME_PCMOUT2,
.formats = SNDRV_PCM_FMTBIT_S32_LE,
.rates = SNDRV_PCM_RATE_48000,
.channels_min = 2,
.channels_max = 2,
},
.capture = {
.stream_name = AUD_NAME_PCMIN3,
.formats = SNDRV_PCM_FMTBIT_S32_LE,
.rates = SNDRV_PCM_RATE_48000,
.channels_min = 2,
.channels_max = 2,
},
.ops = &uniphier_aio_i2s_ops,
},
{
.name = AUD_NAME_HPCMOUT1,
.probe = uniphier_aio_ld11_probe,
.remove = uniphier_aio_dai_remove,
.suspend = uniphier_aio_dai_suspend,
.resume = uniphier_aio_dai_resume,
.playback = {
.stream_name = AUD_NAME_HPCMOUT1,
.formats = SNDRV_PCM_FMTBIT_S32_LE,
.rates = SNDRV_PCM_RATE_48000,
.channels_min = 2,
.channels_max = 2,
},
.ops = &uniphier_aio_i2s_ops,
},
{
.name = AUD_NAME_PCMOUT3,
.probe = uniphier_aio_ld11_probe,
.remove = uniphier_aio_dai_remove,
.suspend = uniphier_aio_dai_suspend,
.resume = uniphier_aio_dai_resume,
.playback = {
.stream_name = AUD_NAME_PCMOUT3,
.formats = SNDRV_PCM_FMTBIT_S32_LE,
.rates = SNDRV_PCM_RATE_48000,
.channels_min = 2,
.channels_max = 2,
},
.ops = &uniphier_aio_i2s_ops,
},
{
.name = AUD_NAME_HIECOUT1,
.probe = uniphier_aio_ld11_probe,
.remove = uniphier_aio_dai_remove,
.suspend = uniphier_aio_dai_suspend,
.resume = uniphier_aio_dai_resume,
.playback = {
.stream_name = AUD_NAME_HIECOUT1,
.formats = SNDRV_PCM_FMTBIT_S32_LE,
.rates = SNDRV_PCM_RATE_48000,
.channels_min = 2,
.channels_max = 2,
},
.ops = &uniphier_aio_spdif_ops,
},
{
.name = AUD_NAME_EPCMOUT2,
.probe = uniphier_aio_ld11_probe,
.remove = uniphier_aio_dai_remove,
.suspend = uniphier_aio_dai_suspend,
.resume = uniphier_aio_dai_resume,
.playback = {
.stream_name = AUD_NAME_EPCMOUT2,
.formats = SNDRV_PCM_FMTBIT_S32_LE,
.rates = SNDRV_PCM_RATE_48000 |
SNDRV_PCM_RATE_44100 |
SNDRV_PCM_RATE_32000,
.channels_min = 2,
.channels_max = 2,
},
.ops = &uniphier_aio_i2s_ops,
},
{
.name = AUD_NAME_EPCMOUT3,
.probe = uniphier_aio_ld11_probe,
.remove = uniphier_aio_dai_remove,
.suspend = uniphier_aio_dai_suspend,
.resume = uniphier_aio_dai_resume,
.playback = {
.stream_name = AUD_NAME_EPCMOUT3,
.formats = SNDRV_PCM_FMTBIT_S32_LE,
.rates = SNDRV_PCM_RATE_48000 |
SNDRV_PCM_RATE_44100 |
SNDRV_PCM_RATE_32000,
.channels_min = 2,
.channels_max = 2,
},
.ops = &uniphier_aio_i2s_ops,
},
{
.name = AUD_NAME_HIECCOMPOUT1,
.probe = uniphier_aio_ld11_probe,
.remove = uniphier_aio_dai_remove,
.suspend = uniphier_aio_dai_suspend,
.resume = uniphier_aio_dai_resume,
.compress_new = snd_soc_new_compress,
.playback = {
.stream_name = AUD_NAME_HIECCOMPOUT1,
.channels_min = 1,
.channels_max = 1,
},
.ops = &uniphier_aio_spdif_ops,
},
};
static const struct uniphier_aio_chip_spec uniphier_aio_ld11_spec = {
.specs = uniphier_aio_ld11,
.num_specs = ARRAY_SIZE(uniphier_aio_ld11),
.dais = uniphier_aio_dai_ld11,
.num_dais = ARRAY_SIZE(uniphier_aio_dai_ld11),
.plls = uniphier_aio_pll_ld11,
.num_plls = ARRAY_SIZE(uniphier_aio_pll_ld11),
.addr_ext = 0,
};
static const struct uniphier_aio_chip_spec uniphier_aio_ld20_spec = {
.specs = uniphier_aio_ld11,
.num_specs = ARRAY_SIZE(uniphier_aio_ld11),
.dais = uniphier_aio_dai_ld11,
.num_dais = ARRAY_SIZE(uniphier_aio_dai_ld11),
.plls = uniphier_aio_pll_ld11,
.num_plls = ARRAY_SIZE(uniphier_aio_pll_ld11),
.addr_ext = 1,
};
static const struct of_device_id uniphier_aio_of_match[] = {
{
.compatible = "socionext,uniphier-ld11-aio",
.data = &uniphier_aio_ld11_spec,
},
{
.compatible = "socionext,uniphier-ld20-aio",
.data = &uniphier_aio_ld20_spec,
},
{},
};
MODULE_DEVICE_TABLE(of, uniphier_aio_of_match);
static struct platform_driver uniphier_aio_driver = {
.driver = {
.name = "snd-uniphier-aio-ld11",
.of_match_table = of_match_ptr(uniphier_aio_of_match),
},
.probe = uniphier_aio_probe,
.remove = uniphier_aio_remove,
};
module_platform_driver(uniphier_aio_driver);
MODULE_AUTHOR("Katsuhiro Suzuki <suzuki.katsuhiro@socionext.com>");
MODULE_DESCRIPTION("UniPhier LD11/LD20 AIO driver.");
MODULE_LICENSE("GPL v2");
// SPDX-License-Identifier: GPL-2.0
//
// Socionext UniPhier AIO ALSA driver for PXs2.
//
// Copyright (c) 2018 Socionext Inc.
#include <linux/module.h>
#include "aio.h"
static const struct uniphier_aio_spec uniphier_aio_pxs2[] = {
/* for Line PCM In, Pin:AI1Dx */
{
.name = AUD_NAME_PCMIN1,
.gname = AUD_GNAME_LINE,
.swm = {
.type = PORT_TYPE_I2S,
.dir = PORT_DIR_INPUT,
.rb = { 16, 11, },
.ch = { 16, 11, },
.iif = { 0, 0, },
.iport = { 0, AUD_HW_PCMIN1, },
},
},
/* for Speaker/Headphone/Mic PCM In, Pin:AI2Dx */
{
.name = AUD_NAME_PCMIN2,
.gname = AUD_GNAME_AUX,
.swm = {
.type = PORT_TYPE_I2S,
.dir = PORT_DIR_INPUT,
.rb = { 17, 12, },
.ch = { 17, 12, },
.iif = { 1, 1, },
.iport = { 1, AUD_HW_PCMIN2, },
},
},
/* for HDMI PCM Out, Pin:AO1Dx (inner) */
{
.name = AUD_NAME_HPCMOUT1,
.gname = AUD_GNAME_HDMI,
.swm = {
.type = PORT_TYPE_I2S,
.dir = PORT_DIR_OUTPUT,
.rb = { 0, 0, },
.ch = { 0, 0, },
.oif = { 0, 0, },
.oport = { 3, AUD_HW_HPCMOUT1, },
},
},
/* for Line PCM Out, Pin:AO2Dx */
{
.name = AUD_NAME_PCMOUT1,
.gname = AUD_GNAME_LINE,
.swm = {
.type = PORT_TYPE_I2S,
.dir = PORT_DIR_OUTPUT,
.rb = { 1, 1, },
.ch = { 1, 1, },
.oif = { 1, 1, },
.oport = { 0, AUD_HW_PCMOUT1, },
},
},
/* for Speaker/Headphone/Mic PCM Out, Pin:AO3Dx */
{
.name = AUD_NAME_PCMOUT2,
.gname = AUD_GNAME_AUX,
.swm = {
.type = PORT_TYPE_I2S,
.dir = PORT_DIR_OUTPUT,
.rb = { 2, 2, },
.ch = { 2, 2, },
.oif = { 2, 2, },
.oport = { 1, AUD_HW_PCMOUT2, },
},
},
/* for HDMI Out, Pin:AO1IEC */
{
.name = AUD_NAME_HIECOUT1,
.swm = {
.type = PORT_TYPE_SPDIF,
.dir = PORT_DIR_OUTPUT,
.rb = { 6, 4, },
.ch = { 6, 4, },
.oif = { 6, 4, },
.oport = { 12, AUD_HW_HIECOUT1, },
},
},
/* for HDMI Out, Pin:AO1IEC, Compress */
{
.name = AUD_NAME_HIECCOMPOUT1,
.swm = {
.type = PORT_TYPE_SPDIF,
.dir = PORT_DIR_OUTPUT,
.rb = { 6, 4, },
.ch = { 6, 4, },
.oif = { 6, 4, },
.oport = { 12, AUD_HW_HIECOUT1, },
},
},
/* for S/PDIF Out, Pin:AO2IEC */
{
.name = AUD_NAME_IECOUT1,
.swm = {
.type = PORT_TYPE_SPDIF,
.dir = PORT_DIR_OUTPUT,
.rb = { 7, 5, },
.ch = { 7, 5, },
.oif = { 7, 5, },
.oport = { 13, AUD_HW_IECOUT1, },
},
},
/* for S/PDIF Out, Pin:AO2IEC */
{
.name = AUD_NAME_IECCOMPOUT1,
.swm = {
.type = PORT_TYPE_SPDIF,
.dir = PORT_DIR_OUTPUT,
.rb = { 7, 5, },
.ch = { 7, 5, },
.oif = { 7, 5, },
.oport = { 13, AUD_HW_IECOUT1, },
},
},
};
static const struct uniphier_aio_pll uniphier_aio_pll_pxs2[] = {
[AUD_PLL_A1] = { .enable = true, },
[AUD_PLL_F1] = { .enable = true, },
[AUD_PLL_A2] = { .enable = true, },
[AUD_PLL_F2] = { .enable = true, },
[AUD_PLL_APLL] = { .enable = true, },
[AUD_PLL_HSC0] = { .enable = true, },
};
static int uniphier_aio_pxs2_probe(struct snd_soc_dai *dai)
{
int ret;
ret = uniphier_aio_dai_probe(dai);
if (ret < 0)
return ret;
ret = snd_soc_dai_set_pll(dai, AUD_PLL_A1, 0, 0, 36864000);
if (ret < 0)
return ret;
ret = snd_soc_dai_set_pll(dai, AUD_PLL_F1, 0, 0, 36864000);
if (ret < 0)
return ret;
ret = snd_soc_dai_set_pll(dai, AUD_PLL_A2, 0, 0, 33868800);
if (ret < 0)
return ret;
ret = snd_soc_dai_set_pll(dai, AUD_PLL_F2, 0, 0, 33868800);
if (ret < 0)
return ret;
return 0;
}
static struct snd_soc_dai_driver uniphier_aio_dai_pxs2[] = {
{
.name = AUD_GNAME_HDMI,
.probe = uniphier_aio_pxs2_probe,
.remove = uniphier_aio_dai_remove,
.suspend = uniphier_aio_dai_suspend,
.resume = uniphier_aio_dai_resume,
.playback = {
.stream_name = AUD_NAME_HPCMOUT1,
.formats = SNDRV_PCM_FMTBIT_S32_LE,
.rates = SNDRV_PCM_RATE_48000,
.channels_min = 2,
.channels_max = 2,
},
.ops = &uniphier_aio_i2s_ops,
},
{
.name = AUD_GNAME_LINE,
.probe = uniphier_aio_pxs2_probe,
.remove = uniphier_aio_dai_remove,
.suspend = uniphier_aio_dai_suspend,
.resume = uniphier_aio_dai_resume,
.playback = {
.stream_name = AUD_NAME_PCMOUT1,
.formats = SNDRV_PCM_FMTBIT_S32_LE,
.rates = SNDRV_PCM_RATE_48000,
.channels_min = 2,
.channels_max = 2,
},
.capture = {
.stream_name = AUD_NAME_PCMIN1,
.formats = SNDRV_PCM_FMTBIT_S32_LE,
.rates = SNDRV_PCM_RATE_48000,
.channels_min = 2,
.channels_max = 2,
},
.ops = &uniphier_aio_i2s_ops,
},
{
.name = AUD_GNAME_AUX,
.probe = uniphier_aio_pxs2_probe,
.remove = uniphier_aio_dai_remove,
.suspend = uniphier_aio_dai_suspend,
.resume = uniphier_aio_dai_resume,
.playback = {
.stream_name = AUD_NAME_PCMOUT2,
.formats = SNDRV_PCM_FMTBIT_S32_LE,
.rates = SNDRV_PCM_RATE_48000,
.channels_min = 2,
.channels_max = 2,
},
.capture = {
.stream_name = AUD_NAME_PCMIN2,
.formats = SNDRV_PCM_FMTBIT_S32_LE,
.rates = SNDRV_PCM_RATE_48000,
.channels_min = 2,
.channels_max = 2,
},
.ops = &uniphier_aio_i2s_ops,
},
{
.name = AUD_NAME_HIECOUT1,
.probe = uniphier_aio_pxs2_probe,
.remove = uniphier_aio_dai_remove,
.suspend = uniphier_aio_dai_suspend,
.resume = uniphier_aio_dai_resume,
.playback = {
.stream_name = AUD_NAME_HIECOUT1,
.formats = SNDRV_PCM_FMTBIT_S32_LE,
.rates = SNDRV_PCM_RATE_48000,
.channels_min = 2,
.channels_max = 2,
},
.ops = &uniphier_aio_spdif_ops,
},
{
.name = AUD_NAME_IECOUT1,
.probe = uniphier_aio_pxs2_probe,
.remove = uniphier_aio_dai_remove,
.suspend = uniphier_aio_dai_suspend,
.resume = uniphier_aio_dai_resume,
.playback = {
.stream_name = AUD_NAME_IECOUT1,
.formats = SNDRV_PCM_FMTBIT_S32_LE,
.rates = SNDRV_PCM_RATE_48000,
.channels_min = 2,
.channels_max = 2,
},
.ops = &uniphier_aio_spdif_ops,
},
{
.name = AUD_NAME_HIECCOMPOUT1,
.probe = uniphier_aio_pxs2_probe,
.remove = uniphier_aio_dai_remove,
.suspend = uniphier_aio_dai_suspend,
.resume = uniphier_aio_dai_resume,
.compress_new = snd_soc_new_compress,
.playback = {
.stream_name = AUD_NAME_HIECCOMPOUT1,
.channels_min = 1,
.channels_max = 1,
},
.ops = &uniphier_aio_spdif_ops,
},
{
.name = AUD_NAME_IECCOMPOUT1,
.probe = uniphier_aio_pxs2_probe,
.remove = uniphier_aio_dai_remove,
.suspend = uniphier_aio_dai_suspend,
.resume = uniphier_aio_dai_resume,
.compress_new = snd_soc_new_compress,
.playback = {
.stream_name = AUD_NAME_IECCOMPOUT1,
.channels_min = 1,
.channels_max = 1,
},
.ops = &uniphier_aio_spdif_ops,
},
};
static const struct uniphier_aio_chip_spec uniphier_aio_pxs2_spec = {
.specs = uniphier_aio_pxs2,
.num_specs = ARRAY_SIZE(uniphier_aio_pxs2),
.dais = uniphier_aio_dai_pxs2,
.num_dais = ARRAY_SIZE(uniphier_aio_dai_pxs2),
.plls = uniphier_aio_pll_pxs2,
.num_plls = ARRAY_SIZE(uniphier_aio_pll_pxs2),
.addr_ext = 0,
};
static const struct of_device_id uniphier_aio_of_match[] = {
{
.compatible = "socionext,uniphier-pxs2-aio",
.data = &uniphier_aio_pxs2_spec,
},
{},
};
MODULE_DEVICE_TABLE(of, uniphier_aio_of_match);
static struct platform_driver uniphier_aio_driver = {
.driver = {
.name = "snd-uniphier-aio-pxs2",
.of_match_table = of_match_ptr(uniphier_aio_of_match),
},
.probe = uniphier_aio_probe,
.remove = uniphier_aio_remove,
};
module_platform_driver(uniphier_aio_driver);
MODULE_AUTHOR("Katsuhiro Suzuki <suzuki.katsuhiro@socionext.com>");
MODULE_DESCRIPTION("UniPhier PXs2 AIO driver.");
MODULE_LICENSE("GPL v2");
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Socionext UniPhier AIO ALSA driver.
*
* Copyright (c) 2016-2018 Socionext Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; version 2
* of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SND_UNIPHIER_AIO_REG_H__
#define SND_UNIPHIER_AIO_REG_H__
#include <linux/bitops.h>
/* soc-glue */
#define SG_AOUTEN 0x1c04
/* SW view */
#define A2CHNMAPCTR0(n) (0x00000 + 0x40 * (n))
#define A2RBNMAPCTR0(n) (0x01000 + 0x40 * (n))
#define A2IPORTNMAPCTR0(n) (0x02000 + 0x40 * (n))
#define A2IPORTNMAPCTR1(n) (0x02004 + 0x40 * (n))
#define A2IIFNMAPCTR0(n) (0x03000 + 0x40 * (n))
#define A2OPORTNMAPCTR0(n) (0x04000 + 0x40 * (n))
#define A2OPORTNMAPCTR1(n) (0x04004 + 0x40 * (n))
#define A2OPORTNMAPCTR2(n) (0x04008 + 0x40 * (n))
#define A2OIFNMAPCTR0(n) (0x05000 + 0x40 * (n))
#define A2ATNMAPCTR0(n) (0x06000 + 0x40 * (n))
#define MAPCTR0_EN 0x80000000
/* CTL */
#define A2APLLCTR0 0x07000
#define A2APLLCTR0_APLLXPOW_MASK GENMASK(3, 0)
#define A2APLLCTR0_APLLXPOW_PWOFF (0x0 << 0)
#define A2APLLCTR0_APLLXPOW_PWON (0xf << 0)
#define A2APLLCTR1 0x07004
#define A2APLLCTR1_APLLX_MASK 0x00010101
#define A2APLLCTR1_APLLX_36MHZ 0x00000000
#define A2APLLCTR1_APLLX_33MHZ 0x00000001
#define A2EXMCLKSEL0 0x07030
#define A2EXMCLKSEL0_EXMCLK_MASK GENMASK(2, 0)
#define A2EXMCLKSEL0_EXMCLK_OUTPUT (0x0 << 0)
#define A2EXMCLKSEL0_EXMCLK_INPUT (0x7 << 0)
#define A2SSIFSW 0x07050
#define A2CH22_2CTR 0x07054
#define A2AIOINPUTSEL 0x070e0
#define A2AIOINPUTSEL_RXSEL_PCMI1_MASK GENMASK(2, 0)
#define A2AIOINPUTSEL_RXSEL_PCMI1_HDMIRX1 (0x2 << 0)
#define A2AIOINPUTSEL_RXSEL_PCMI2_MASK GENMASK(6, 4)
#define A2AIOINPUTSEL_RXSEL_PCMI2_SIF (0x7 << 4)
#define A2AIOINPUTSEL_RXSEL_PCMI3_MASK GENMASK(10, 8)
#define A2AIOINPUTSEL_RXSEL_PCMI3_EVEA (0x1 << 8)
#define A2AIOINPUTSEL_RXSEL_IECI1_MASK GENMASK(14, 12)
#define A2AIOINPUTSEL_RXSEL_IECI1_HDMIRX1 (0x2 << 12)
#define A2AIOINPUTSEL_RXSEL_MASK (A2AIOINPUTSEL_RXSEL_PCMI1_MASK | \
A2AIOINPUTSEL_RXSEL_PCMI2_MASK | \
A2AIOINPUTSEL_RXSEL_PCMI3_MASK | \
A2AIOINPUTSEL_RXSEL_IECI1_HDMIRX1)
/* INTC */
#define INTCHIM(m) (0x9028 + 0x80 * (m))
#define INTRBIM(m) (0x9030 + 0x80 * (m))
#define INTCHID(m) (0xa028 + 0x80 * (m))
#define INTRBID(m) (0xa030 + 0x80 * (m))
/* AIN(PCMINN) */
#define IPORTMXCTR1(n) (0x22000 + 0x400 * (n))
#define IPORTMXCTR1_LRSEL_MASK GENMASK(11, 10)
#define IPORTMXCTR1_LRSEL_RIGHT (0x0 << 10)
#define IPORTMXCTR1_LRSEL_LEFT (0x1 << 10)
#define IPORTMXCTR1_LRSEL_I2S (0x2 << 10)
#define IPORTMXCTR1_OUTBITSEL_MASK (0x800003U << 8)
#define IPORTMXCTR1_OUTBITSEL_32 (0x800000U << 8)
#define IPORTMXCTR1_OUTBITSEL_24 (0x000000U << 8)
#define IPORTMXCTR1_OUTBITSEL_20 (0x000001U << 8)
#define IPORTMXCTR1_OUTBITSEL_16 (0x000002U << 8)
#define IPORTMXCTR1_CHSEL_MASK GENMASK(6, 4)
#define IPORTMXCTR1_CHSEL_ALL (0x0 << 4)
#define IPORTMXCTR1_CHSEL_D0_D2 (0x1 << 4)
#define IPORTMXCTR1_CHSEL_D0 (0x2 << 4)
#define IPORTMXCTR1_CHSEL_D1 (0x3 << 4)
#define IPORTMXCTR1_CHSEL_D2 (0x4 << 4)
#define IPORTMXCTR1_CHSEL_DMIX (0x5 << 4)
#define IPORTMXCTR1_FSSEL_MASK GENMASK(3, 0)
#define IPORTMXCTR1_FSSEL_48 (0x0 << 0)
#define IPORTMXCTR1_FSSEL_96 (0x1 << 0)
#define IPORTMXCTR1_FSSEL_192 (0x2 << 0)
#define IPORTMXCTR1_FSSEL_32 (0x3 << 0)
#define IPORTMXCTR1_FSSEL_44_1 (0x4 << 0)
#define IPORTMXCTR1_FSSEL_88_2 (0x5 << 0)
#define IPORTMXCTR1_FSSEL_176_4 (0x6 << 0)
#define IPORTMXCTR1_FSSEL_16 (0x8 << 0)
#define IPORTMXCTR1_FSSEL_22_05 (0x9 << 0)
#define IPORTMXCTR1_FSSEL_24 (0xa << 0)
#define IPORTMXCTR1_FSSEL_8 (0xb << 0)
#define IPORTMXCTR1_FSSEL_11_025 (0xc << 0)
#define IPORTMXCTR1_FSSEL_12 (0xd << 0)
#define IPORTMXCTR2(n) (0x22004 + 0x400 * (n))
#define IPORTMXCTR2_ACLKSEL_MASK GENMASK(19, 16)
#define IPORTMXCTR2_ACLKSEL_A1 (0x0 << 16)
#define IPORTMXCTR2_ACLKSEL_F1 (0x1 << 16)
#define IPORTMXCTR2_ACLKSEL_A2 (0x2 << 16)
#define IPORTMXCTR2_ACLKSEL_F2 (0x3 << 16)
#define IPORTMXCTR2_ACLKSEL_A2PLL (0x4 << 16)
#define IPORTMXCTR2_ACLKSEL_RX1 (0x5 << 16)
#define IPORTMXCTR2_ACLKSEL_RX2 (0x6 << 16)
#define IPORTMXCTR2_MSSEL_MASK BIT(15)
#define IPORTMXCTR2_MSSEL_SLAVE (0x0 << 15)
#define IPORTMXCTR2_MSSEL_MASTER (0x1 << 15)
#define IPORTMXCTR2_EXTLSIFSSEL_MASK BIT(14)
#define IPORTMXCTR2_EXTLSIFSSEL_36 (0x0 << 14)
#define IPORTMXCTR2_EXTLSIFSSEL_24 (0x1 << 14)
#define IPORTMXCTR2_DACCKSEL_MASK GENMASK(9, 8)
#define IPORTMXCTR2_DACCKSEL_1_2 (0x0 << 8)
#define IPORTMXCTR2_DACCKSEL_1_3 (0x1 << 8)
#define IPORTMXCTR2_DACCKSEL_1_1 (0x2 << 8)
#define IPORTMXCTR2_DACCKSEL_2_3 (0x3 << 8)
#define IPORTMXCTR2_REQEN_MASK BIT(0)
#define IPORTMXCTR2_REQEN_DISABLE (0x0 << 0)
#define IPORTMXCTR2_REQEN_ENABLE (0x1 << 0)
#define IPORTMXCNTCTR(n) (0x22010 + 0x400 * (n))
#define IPORTMXCOUNTER(n) (0x22014 + 0x400 * (n))
#define IPORTMXCNTMONI(n) (0x22018 + 0x400 * (n))
#define IPORTMXACLKSEL0EX(n) (0x22020 + 0x400 * (n))
#define IPORTMXACLKSEL0EX_ACLKSEL0EX_MASK GENMASK(3, 0)
#define IPORTMXACLKSEL0EX_ACLKSEL0EX_INTERNAL (0x0 << 0)
#define IPORTMXACLKSEL0EX_ACLKSEL0EX_EXTERNAL (0xf << 0)
#define IPORTMXEXNOE(n) (0x22070 + 0x400 * (n))
#define IPORTMXEXNOE_PCMINOE_MASK BIT(0)
#define IPORTMXEXNOE_PCMINOE_OUTPUT (0x0 << 0)
#define IPORTMXEXNOE_PCMINOE_INPUT (0x1 << 0)
#define IPORTMXMASK(n) (0x22078 + 0x400 * (n))
#define IPORTMXMASK_IUXCKMSK_MASK GENMASK(18, 16)
#define IPORTMXMASK_IUXCKMSK_ON (0x0 << 16)
#define IPORTMXMASK_IUXCKMSK_OFF (0x7 << 16)
#define IPORTMXMASK_XCKMSK_MASK GENMASK(2, 0)
#define IPORTMXMASK_XCKMSK_ON (0x0 << 0)
#define IPORTMXMASK_XCKMSK_OFF (0x7 << 0)
#define IPORTMXRSTCTR(n) (0x2207c + 0x400 * (n))
#define IPORTMXRSTCTR_RSTPI_MASK BIT(7)
#define IPORTMXRSTCTR_RSTPI_RELEASE (0x0 << 7)
#define IPORTMXRSTCTR_RSTPI_RESET (0x1 << 7)
/* AIN(PBinMX) */
#define PBINMXCTR(n) (0x20200 + 0x40 * (n))
#define PBINMXCTR_NCONNECT_MASK BIT(15)
#define PBINMXCTR_NCONNECT_CONNECT (0x0 << 15)
#define PBINMXCTR_NCONNECT_DISCONNECT (0x1 << 15)
#define PBINMXCTR_INOUTSEL_MASK BIT(14)
#define PBINMXCTR_INOUTSEL_IN (0x0 << 14)
#define PBINMXCTR_INOUTSEL_OUT (0x1 << 14)
#define PBINMXCTR_PBINSEL_SHIFT (8)
#define PBINMXCTR_ENDIAN_MASK GENMASK(5, 4)
#define PBINMXCTR_ENDIAN_3210 (0x0 << 4)
#define PBINMXCTR_ENDIAN_0123 (0x1 << 4)
#define PBINMXCTR_ENDIAN_1032 (0x2 << 4)
#define PBINMXCTR_ENDIAN_2301 (0x3 << 4)
#define PBINMXCTR_MEMFMT_MASK GENMASK(3, 0)
#define PBINMXCTR_MEMFMT_D0 (0x0 << 0)
#define PBINMXCTR_MEMFMT_5_1CH_DMIX (0x1 << 0)
#define PBINMXCTR_MEMFMT_6CH (0x2 << 0)
#define PBINMXCTR_MEMFMT_4CH (0x3 << 0)
#define PBINMXCTR_MEMFMT_DMIX (0x4 << 0)
#define PBINMXCTR_MEMFMT_1CH (0x5 << 0)
#define PBINMXCTR_MEMFMT_16LR (0x6 << 0)
#define PBINMXCTR_MEMFMT_7_1CH (0x7 << 0)
#define PBINMXCTR_MEMFMT_7_1CH_DMIX (0x8 << 0)
#define PBINMXCTR_MEMFMT_STREAM (0xf << 0)
#define PBINMXPAUSECTR0(n) (0x20204 + 0x40 * (n))
#define PBINMXPAUSECTR1(n) (0x20208 + 0x40 * (n))
/* AOUT */
#define AOUTENCTR0 0x40040
#define AOUTENCTR1 0x40044
#define AOUTENCTR2 0x40048
#define AOUTRSTCTR0 0x40060
#define AOUTRSTCTR1 0x40064
#define AOUTRSTCTR2 0x40068
#define AOUTSRCRSTCTR0 0x400c0
#define AOUTSRCRSTCTR1 0x400c4
#define AOUTSRCRSTCTR2 0x400c8
/* AOUT(PCMOUTN) */
#define OPORTMXCTR1(n) (0x42000 + 0x400 * (n))
#define OPORTMXCTR1_I2SLRSEL_MASK (0x11 << 10)
#define OPORTMXCTR1_I2SLRSEL_RIGHT (0x00 << 10)
#define OPORTMXCTR1_I2SLRSEL_LEFT (0x01 << 10)
#define OPORTMXCTR1_I2SLRSEL_I2S (0x11 << 10)
#define OPORTMXCTR1_OUTBITSEL_MASK (0x800003U << 8)
#define OPORTMXCTR1_OUTBITSEL_32 (0x800000U << 8)
#define OPORTMXCTR1_OUTBITSEL_24 (0x000000U << 8)
#define OPORTMXCTR1_OUTBITSEL_20 (0x000001U << 8)
#define OPORTMXCTR1_OUTBITSEL_16 (0x000002U << 8)
#define OPORTMXCTR1_FSSEL_MASK GENMASK(3, 0)
#define OPORTMXCTR1_FSSEL_48 (0x0 << 0)
#define OPORTMXCTR1_FSSEL_96 (0x1 << 0)
#define OPORTMXCTR1_FSSEL_192 (0x2 << 0)
#define OPORTMXCTR1_FSSEL_32 (0x3 << 0)
#define OPORTMXCTR1_FSSEL_44_1 (0x4 << 0)
#define OPORTMXCTR1_FSSEL_88_2 (0x5 << 0)
#define OPORTMXCTR1_FSSEL_176_4 (0x6 << 0)
#define OPORTMXCTR1_FSSEL_16 (0x8 << 0)
#define OPORTMXCTR1_FSSEL_22_05 (0x9 << 0)
#define OPORTMXCTR1_FSSEL_24 (0xa << 0)
#define OPORTMXCTR1_FSSEL_8 (0xb << 0)
#define OPORTMXCTR1_FSSEL_11_025 (0xc << 0)
#define OPORTMXCTR1_FSSEL_12 (0xd << 0)
#define OPORTMXCTR2(n) (0x42004 + 0x400 * (n))
#define OPORTMXCTR2_ACLKSEL_MASK GENMASK(19, 16)
#define OPORTMXCTR2_ACLKSEL_A1 (0x0 << 16)
#define OPORTMXCTR2_ACLKSEL_F1 (0x1 << 16)
#define OPORTMXCTR2_ACLKSEL_A2 (0x2 << 16)
#define OPORTMXCTR2_ACLKSEL_F2 (0x3 << 16)
#define OPORTMXCTR2_ACLKSEL_A2PLL (0x4 << 16)
#define OPORTMXCTR2_ACLKSEL_RX1 (0x5 << 16)
#define OPORTMXCTR2_ACLKSEL_RX2 (0x6 << 16)
#define OPORTMXCTR2_MSSEL_MASK BIT(15)
#define OPORTMXCTR2_MSSEL_SLAVE (0x0 << 15)
#define OPORTMXCTR2_MSSEL_MASTER (0x1 << 15)
#define OPORTMXCTR2_EXTLSIFSSEL_MASK BIT(14)
#define OPORTMXCTR2_EXTLSIFSSEL_36 (0x0 << 14)
#define OPORTMXCTR2_EXTLSIFSSEL_24 (0x1 << 14)
#define OPORTMXCTR2_DACCKSEL_MASK GENMASK(9, 8)
#define OPORTMXCTR2_DACCKSEL_1_2 (0x0 << 8)
#define OPORTMXCTR2_DACCKSEL_1_3 (0x1 << 8)
#define OPORTMXCTR2_DACCKSEL_1_1 (0x2 << 8)
#define OPORTMXCTR2_DACCKSEL_2_3 (0x3 << 8)
#define OPORTMXCTR3(n) (0x42008 + 0x400 * (n))
#define OPORTMXCTR3_IECTHUR_MASK BIT(19)
#define OPORTMXCTR3_IECTHUR_IECOUT (0x0 << 19)
#define OPORTMXCTR3_IECTHUR_IECIN (0x1 << 19)
#define OPORTMXCTR3_SRCSEL_MASK GENMASK(18, 16)
#define OPORTMXCTR3_SRCSEL_PCM (0x0 << 16)
#define OPORTMXCTR3_SRCSEL_STREAM (0x1 << 16)
#define OPORTMXCTR3_SRCSEL_CDDTS (0x2 << 16)
#define OPORTMXCTR3_VALID_MASK BIT(12)
#define OPORTMXCTR3_VALID_PCM (0x0 << 12)
#define OPORTMXCTR3_VALID_STREAM (0x1 << 12)
#define OPORTMXCTR3_PMSEL_MASK BIT(3)
#define OPORTMXCTR3_PMSEL_MUTE (0x0 << 3)
#define OPORTMXCTR3_PMSEL_PAUSE (0x1 << 3)
#define OPORTMXCTR3_PMSW_MASK BIT(2)
#define OPORTMXCTR3_PMSW_MUTE_OFF (0x0 << 2)
#define OPORTMXCTR3_PMSW_MUTE_ON (0x1 << 2)
#define OPORTMXSRC1CTR(n) (0x4200c + 0x400 * (n))
#define OPORTMXSRC1CTR_FSIIPNUM_SHIFT (24)
#define OPORTMXSRC1CTR_THMODE_MASK BIT(23)
#define OPORTMXSRC1CTR_THMODE_SRC (0x0 << 23)
#define OPORTMXSRC1CTR_THMODE_BYPASS (0x1 << 23)
#define OPORTMXSRC1CTR_LOCK_MASK BIT(16)
#define OPORTMXSRC1CTR_LOCK_UNLOCK (0x0 << 16)
#define OPORTMXSRC1CTR_LOCK_LOCK (0x1 << 16)
#define OPORTMXSRC1CTR_SRCPATH_MASK BIT(15)
#define OPORTMXSRC1CTR_SRCPATH_BYPASS (0x0 << 15)
#define OPORTMXSRC1CTR_SRCPATH_CALC (0x1 << 15)
#define OPORTMXSRC1CTR_SYNC_MASK BIT(14)
#define OPORTMXSRC1CTR_SYNC_ASYNC (0x0 << 14)
#define OPORTMXSRC1CTR_SYNC_SYNC (0x1 << 14)
#define OPORTMXSRC1CTR_FSOCK_MASK GENMASK(11, 10)
#define OPORTMXSRC1CTR_FSOCK_44_1 (0x0 << 10)
#define OPORTMXSRC1CTR_FSOCK_48 (0x1 << 10)
#define OPORTMXSRC1CTR_FSOCK_32 (0x2 << 10)
#define OPORTMXSRC1CTR_FSICK_MASK GENMASK(9, 8)
#define OPORTMXSRC1CTR_FSICK_44_1 (0x0 << 8)
#define OPORTMXSRC1CTR_FSICK_48 (0x1 << 8)
#define OPORTMXSRC1CTR_FSICK_32 (0x2 << 8)
#define OPORTMXSRC1CTR_FSIIPSEL_MASK GENMASK(5, 4)
#define OPORTMXSRC1CTR_FSIIPSEL_INNER (0x0 << 4)
#define OPORTMXSRC1CTR_FSIIPSEL_OUTER (0x1 << 4)
#define OPORTMXSRC1CTR_FSISEL_MASK GENMASK(3, 0)
#define OPORTMXSRC1CTR_FSISEL_ACLK (0x0 << 0)
#define OPORTMXSRC1CTR_FSISEL_DD (0x1 << 0)
#define OPORTMXDSDMUTEDAT(n) (0x42020 + 0x400 * (n))
#define OPORTMXDXDFREQMODE(n) (0x42024 + 0x400 * (n))
#define OPORTMXDSDSEL(n) (0x42028 + 0x400 * (n))
#define OPORTMXDSDPORT(n) (0x4202c + 0x400 * (n))
#define OPORTMXACLKSEL0EX(n) (0x42030 + 0x400 * (n))
#define OPORTMXPATH(n) (0x42040 + 0x400 * (n))
#define OPORTMXSYNC(n) (0x42044 + 0x400 * (n))
#define OPORTMXREPET(n) (0x42050 + 0x400 * (n))
#define OPORTMXREPET_STRLENGTH_AC3 SBF_(IEC61937_FRM_STR_AC3, 16)
#define OPORTMXREPET_STRLENGTH_MPA SBF_(IEC61937_FRM_STR_MPA, 16)
#define OPORTMXREPET_STRLENGTH_MP3 SBF_(IEC61937_FRM_STR_MP3, 16)
#define OPORTMXREPET_STRLENGTH_DTS1 SBF_(IEC61937_FRM_STR_DTS1, 16)
#define OPORTMXREPET_STRLENGTH_DTS2 SBF_(IEC61937_FRM_STR_DTS2, 16)
#define OPORTMXREPET_STRLENGTH_DTS3 SBF_(IEC61937_FRM_STR_DTS3, 16)
#define OPORTMXREPET_STRLENGTH_AAC SBF_(IEC61937_FRM_STR_AAC, 16)
#define OPORTMXREPET_PMLENGTH_AC3 SBF_(IEC61937_FRM_PAU_AC3, 0)
#define OPORTMXREPET_PMLENGTH_MPA SBF_(IEC61937_FRM_PAU_MPA, 0)
#define OPORTMXREPET_PMLENGTH_MP3 SBF_(IEC61937_FRM_PAU_MP3, 0)
#define OPORTMXREPET_PMLENGTH_DTS1 SBF_(IEC61937_FRM_PAU_DTS1, 0)
#define OPORTMXREPET_PMLENGTH_DTS2 SBF_(IEC61937_FRM_PAU_DTS2, 0)
#define OPORTMXREPET_PMLENGTH_DTS3 SBF_(IEC61937_FRM_PAU_DTS3, 0)
#define OPORTMXREPET_PMLENGTH_AAC SBF_(IEC61937_FRM_PAU_AAC, 0)
#define OPORTMXPAUDAT(n) (0x42054 + 0x400 * (n))
#define OPORTMXPAUDAT_PAUSEPC_CMN (IEC61937_PC_PAUSE << 16)
#define OPORTMXPAUDAT_PAUSEPD_AC3 (IEC61937_FRM_PAU_AC3 * 4)
#define OPORTMXPAUDAT_PAUSEPD_MPA (IEC61937_FRM_PAU_MPA * 4)
#define OPORTMXPAUDAT_PAUSEPD_MP3 (IEC61937_FRM_PAU_MP3 * 4)
#define OPORTMXPAUDAT_PAUSEPD_DTS1 (IEC61937_FRM_PAU_DTS1 * 4)
#define OPORTMXPAUDAT_PAUSEPD_DTS2 (IEC61937_FRM_PAU_DTS2 * 4)
#define OPORTMXPAUDAT_PAUSEPD_DTS3 (IEC61937_FRM_PAU_DTS3 * 4)
#define OPORTMXPAUDAT_PAUSEPD_AAC (IEC61937_FRM_PAU_AAC * 4)
#define OPORTMXRATE_I(n) (0x420e4 + 0x400 * (n))
#define OPORTMXRATE_I_EQU_MASK BIT(31)
#define OPORTMXRATE_I_EQU_NOTEQUAL (0x0 << 31)
#define OPORTMXRATE_I_EQU_EQUAL (0x1 << 31)
#define OPORTMXRATE_I_SRCBPMD_MASK BIT(29)
#define OPORTMXRATE_I_SRCBPMD_BYPASS (0x0 << 29)
#define OPORTMXRATE_I_SRCBPMD_SRC (0x1 << 29)
#define OPORTMXRATE_I_LRCKSTP_MASK BIT(24)
#define OPORTMXRATE_I_LRCKSTP_START (0x0 << 24)
#define OPORTMXRATE_I_LRCKSTP_STOP (0x1 << 24)
#define OPORTMXRATE_I_ACLKSRC_MASK GENMASK(15, 12)
#define OPORTMXRATE_I_ACLKSRC_APLL (0x0 << 12)
#define OPORTMXRATE_I_ACLKSRC_USB (0x1 << 12)
#define OPORTMXRATE_I_ACLKSRC_HSC (0x3 << 12)
/* if OPORTMXRATE_I_ACLKSRC_APLL */
#define OPORTMXRATE_I_ACLKSEL_MASK GENMASK(11, 8)
#define OPORTMXRATE_I_ACLKSEL_APLLA1 (0x0 << 8)
#define OPORTMXRATE_I_ACLKSEL_APLLF1 (0x1 << 8)
#define OPORTMXRATE_I_ACLKSEL_APLLA2 (0x2 << 8)
#define OPORTMXRATE_I_ACLKSEL_APLLF2 (0x3 << 8)
#define OPORTMXRATE_I_ACLKSEL_APLL (0x4 << 8)
#define OPORTMXRATE_I_ACLKSEL_HDMI1 (0x5 << 8)
#define OPORTMXRATE_I_ACLKSEL_HDMI2 (0x6 << 8)
#define OPORTMXRATE_I_ACLKSEL_AI1ADCCK (0xc << 8)
#define OPORTMXRATE_I_ACLKSEL_AI2ADCCK (0xd << 8)
#define OPORTMXRATE_I_ACLKSEL_AI3ADCCK (0xe << 8)
#define OPORTMXRATE_I_MCKSEL_MASK GENMASK(7, 4)
#define OPORTMXRATE_I_MCKSEL_36 (0x0 << 4)
#define OPORTMXRATE_I_MCKSEL_33 (0x1 << 4)
#define OPORTMXRATE_I_MCKSEL_HSC27 (0xb << 4)
#define OPORTMXRATE_I_FSSEL_MASK GENMASK(3, 0)
#define OPORTMXRATE_I_FSSEL_48 (0x0 << 0)
#define OPORTMXRATE_I_FSSEL_96 (0x1 << 0)
#define OPORTMXRATE_I_FSSEL_192 (0x2 << 0)
#define OPORTMXRATE_I_FSSEL_32 (0x3 << 0)
#define OPORTMXRATE_I_FSSEL_44_1 (0x4 << 0)
#define OPORTMXRATE_I_FSSEL_88_2 (0x5 << 0)
#define OPORTMXRATE_I_FSSEL_176_4 (0x6 << 0)
#define OPORTMXRATE_I_FSSEL_16 (0x8 << 0)
#define OPORTMXRATE_I_FSSEL_22_05 (0x9 << 0)
#define OPORTMXRATE_I_FSSEL_24 (0xa << 0)
#define OPORTMXRATE_I_FSSEL_8 (0xb << 0)
#define OPORTMXRATE_I_FSSEL_11_025 (0xc << 0)
#define OPORTMXRATE_I_FSSEL_12 (0xd << 0)
#define OPORTMXEXNOE(n) (0x420f0 + 0x400 * (n))
#define OPORTMXMASK(n) (0x420f8 + 0x400 * (n))
#define OPORTMXMASK_IUDXMSK_MASK GENMASK(28, 24)
#define OPORTMXMASK_IUDXMSK_ON (0x00 << 24)
#define OPORTMXMASK_IUDXMSK_OFF (0x1f << 24)
#define OPORTMXMASK_IUXCKMSK_MASK GENMASK(18, 16)
#define OPORTMXMASK_IUXCKMSK_ON (0x0 << 16)
#define OPORTMXMASK_IUXCKMSK_OFF (0x7 << 16)
#define OPORTMXMASK_DXMSK_MASK GENMASK(12, 8)
#define OPORTMXMASK_DXMSK_ON (0x00 << 8)
#define OPORTMXMASK_DXMSK_OFF (0x1f << 8)
#define OPORTMXMASK_XCKMSK_MASK GENMASK(2, 0)
#define OPORTMXMASK_XCKMSK_ON (0x0 << 0)
#define OPORTMXMASK_XCKMSK_OFF (0x7 << 0)
#define OPORTMXDEBUG(n) (0x420fc + 0x400 * (n))
#define OPORTMXT0RSTCTR(n) (0x4211c + 0x400 * (n))
#define OPORTMXT1RSTCTR(n) (0x4213c + 0x400 * (n))
#define OPORTMXT2RSTCTR(n) (0x4215c + 0x400 * (n))
#define OPORTMXT3RSTCTR(n) (0x4217c + 0x400 * (n))
#define OPORTMXT4RSTCTR(n) (0x4219c + 0x400 * (n))
#define SBF_(frame, shift) (((frame) * 2 - 1) << shift)
/* AOUT(PBoutMX) */
#define PBOUTMXCTR0(n) (0x40200 + 0x40 * (n))
#define PBOUTMXCTR0_ENDIAN_MASK GENMASK(5, 4)
#define PBOUTMXCTR0_ENDIAN_3210 (0x0 << 4)
#define PBOUTMXCTR0_ENDIAN_0123 (0x1 << 4)
#define PBOUTMXCTR0_ENDIAN_1032 (0x2 << 4)
#define PBOUTMXCTR0_ENDIAN_2301 (0x3 << 4)
#define PBOUTMXCTR0_MEMFMT_MASK GENMASK(3, 0)
#define PBOUTMXCTR0_MEMFMT_10CH (0x0 << 0)
#define PBOUTMXCTR0_MEMFMT_8CH (0x1 << 0)
#define PBOUTMXCTR0_MEMFMT_6CH (0x2 << 0)
#define PBOUTMXCTR0_MEMFMT_4CH (0x3 << 0)
#define PBOUTMXCTR0_MEMFMT_2CH (0x4 << 0)
#define PBOUTMXCTR0_MEMFMT_STREAM (0x5 << 0)
#define PBOUTMXCTR0_MEMFMT_1CH (0x6 << 0)
#define PBOUTMXCTR1(n) (0x40204 + 0x40 * (n))
#define PBOUTMXINTCTR(n) (0x40208 + 0x40 * (n))
/* A2D(subsystem) */
#define CDA2D_STRT0 0x10000
#define CDA2D_STRT0_STOP_MASK BIT(31)
#define CDA2D_STRT0_STOP_START (0x0 << 31)
#define CDA2D_STRT0_STOP_STOP (0x1 << 31)
#define CDA2D_STAT0 0x10020
#define CDA2D_TEST 0x100a0
#define CDA2D_TEST_DDR_MODE_MASK GENMASK(3, 2)
#define CDA2D_TEST_DDR_MODE_EXTON0 (0x0 << 2)
#define CDA2D_TEST_DDR_MODE_EXTOFF1 (0x3 << 2)
#define CDA2D_STRTADRSLOAD 0x100b0
#define CDA2D_CHMXCTRL1(n) (0x12000 + 0x80 * (n))
#define CDA2D_CHMXCTRL1_INDSIZE_MASK BIT(0)
#define CDA2D_CHMXCTRL1_INDSIZE_FINITE (0x0 << 0)
#define CDA2D_CHMXCTRL1_INDSIZE_INFINITE (0x1 << 0)
#define CDA2D_CHMXCTRL2(n) (0x12004 + 0x80 * (n))
#define CDA2D_CHMXSRCAMODE(n) (0x12020 + 0x80 * (n))
#define CDA2D_CHMXDSTAMODE(n) (0x12024 + 0x80 * (n))
#define CDA2D_CHMXAMODE_ENDIAN_MASK GENMASK(17, 16)
#define CDA2D_CHMXAMODE_ENDIAN_3210 (0x0 << 16)
#define CDA2D_CHMXAMODE_ENDIAN_0123 (0x1 << 16)
#define CDA2D_CHMXAMODE_ENDIAN_1032 (0x2 << 16)
#define CDA2D_CHMXAMODE_ENDIAN_2301 (0x3 << 16)
#define CDA2D_CHMXAMODE_RSSEL_SHIFT (8)
#define CDA2D_CHMXAMODE_AUPDT_MASK GENMASK(5, 4)
#define CDA2D_CHMXAMODE_AUPDT_INC (0x0 << 4)
#define CDA2D_CHMXAMODE_AUPDT_FIX (0x2 << 4)
#define CDA2D_CHMXAMODE_TYPE_MASK GENMASK(3, 2)
#define CDA2D_CHMXAMODE_TYPE_NORMAL (0x0 << 2)
#define CDA2D_CHMXAMODE_TYPE_RING (0x1 << 2)
#define CDA2D_CHMXSRCSTRTADRS(n) (0x12030 + 0x80 * (n))
#define CDA2D_CHMXSRCSTRTADRSU(n) (0x12034 + 0x80 * (n))
#define CDA2D_CHMXDSTSTRTADRS(n) (0x12038 + 0x80 * (n))
#define CDA2D_CHMXDSTSTRTADRSU(n) (0x1203c + 0x80 * (n))
/* A2D(ring buffer) */
#define CDA2D_RBFLUSH0 0x10040
#define CDA2D_RBADRSLOAD 0x100b4
#define CDA2D_RDPTRLOAD 0x100b8
#define CDA2D_RDPTRLOAD_LSFLAG_LOAD (0x0 << 31)
#define CDA2D_RDPTRLOAD_LSFLAG_STORE (0x1 << 31)
#define CDA2D_WRPTRLOAD 0x100bc
#define CDA2D_WRPTRLOAD_LSFLAG_LOAD (0x0 << 31)
#define CDA2D_WRPTRLOAD_LSFLAG_STORE (0x1 << 31)
#define CDA2D_RBMXBGNADRS(n) (0x14000 + 0x80 * (n))
#define CDA2D_RBMXBGNADRSU(n) (0x14004 + 0x80 * (n))
#define CDA2D_RBMXENDADRS(n) (0x14008 + 0x80 * (n))
#define CDA2D_RBMXENDADRSU(n) (0x1400c + 0x80 * (n))
#define CDA2D_RBMXBTH(n) (0x14038 + 0x80 * (n))
#define CDA2D_RBMXRTH(n) (0x1403c + 0x80 * (n))
#define CDA2D_RBMXRDPTR(n) (0x14020 + 0x80 * (n))
#define CDA2D_RBMXRDPTRU(n) (0x14024 + 0x80 * (n))
#define CDA2D_RBMXWRPTR(n) (0x14028 + 0x80 * (n))
#define CDA2D_RBMXWRPTRU(n) (0x1402c + 0x80 * (n))
#define CDA2D_RBMXPTRU_PTRU_MASK GENMASK(1, 0)
#define CDA2D_RBMXCNFG(n) (0x14030 + 0x80 * (n))
#define CDA2D_RBMXIR(n) (0x14014 + 0x80 * (n))
#define CDA2D_RBMXIE(n) (0x14018 + 0x80 * (n))
#define CDA2D_RBMXID(n) (0x1401c + 0x80 * (n))
#define CDA2D_RBMXIX_SPACE BIT(3)
#define CDA2D_RBMXIX_REMAIN BIT(4)
#endif /* SND_UNIPHIER_AIO_REG_H__ */
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Socionext UniPhier AIO ALSA driver.
*
* Copyright (c) 2016-2018 Socionext Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; version 2
* of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SND_UNIPHIER_AIO_H__
#define SND_UNIPHIER_AIO_H__
#include <linux/spinlock.h>
#include <linux/types.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/soc-dai.h>
struct platform_device;
enum ID_PORT_TYPE {
PORT_TYPE_UNKNOWN,
PORT_TYPE_I2S,
PORT_TYPE_SPDIF,
PORT_TYPE_EVE,
PORT_TYPE_CONV,
};
enum ID_PORT_DIR {
PORT_DIR_OUTPUT,
PORT_DIR_INPUT,
};
enum IEC61937_PC {
IEC61937_PC_AC3 = 0x0001,
IEC61937_PC_PAUSE = 0x0003,
IEC61937_PC_MPA = 0x0004,
IEC61937_PC_MP3 = 0x0005,
IEC61937_PC_DTS1 = 0x000b,
IEC61937_PC_DTS2 = 0x000c,
IEC61937_PC_DTS3 = 0x000d,
IEC61937_PC_AAC = 0x0007,
};
/* IEC61937 Repetition period of data-burst in IEC60958 frames */
#define IEC61937_FRM_STR_AC3 1536
#define IEC61937_FRM_STR_MPA 1152
#define IEC61937_FRM_STR_MP3 1152
#define IEC61937_FRM_STR_DTS1 512
#define IEC61937_FRM_STR_DTS2 1024
#define IEC61937_FRM_STR_DTS3 2048
#define IEC61937_FRM_STR_AAC 1024
/* IEC61937 Repetition period of Pause data-burst in IEC60958 frames */
#define IEC61937_FRM_PAU_AC3 3
#define IEC61937_FRM_PAU_MPA 32
#define IEC61937_FRM_PAU_MP3 32
#define IEC61937_FRM_PAU_DTS1 3
#define IEC61937_FRM_PAU_DTS2 3
#define IEC61937_FRM_PAU_DTS3 3
#define IEC61937_FRM_PAU_AAC 32
/* IEC61937 Pa and Pb */
#define IEC61937_HEADER_SIGN 0x1f4e72f8
#define AUD_HW_PCMIN1 0
#define AUD_HW_PCMIN2 1
#define AUD_HW_PCMIN3 2
#define AUD_HW_IECIN1 3
#define AUD_HW_DIECIN1 4
#define AUD_NAME_PCMIN1 "aio-pcmin1"
#define AUD_NAME_PCMIN2 "aio-pcmin2"
#define AUD_NAME_PCMIN3 "aio-pcmin3"
#define AUD_NAME_IECIN1 "aio-iecin1"
#define AUD_NAME_DIECIN1 "aio-diecin1"
#define AUD_HW_HPCMOUT1 0
#define AUD_HW_PCMOUT1 1
#define AUD_HW_PCMOUT2 2
#define AUD_HW_PCMOUT3 3
#define AUD_HW_EPCMOUT1 4
#define AUD_HW_EPCMOUT2 5
#define AUD_HW_EPCMOUT3 6
#define AUD_HW_EPCMOUT6 9
#define AUD_HW_HIECOUT1 10
#define AUD_HW_IECOUT1 11
#define AUD_HW_CMASTER 31
#define AUD_NAME_HPCMOUT1 "aio-hpcmout1"
#define AUD_NAME_PCMOUT1 "aio-pcmout1"
#define AUD_NAME_PCMOUT2 "aio-pcmout2"
#define AUD_NAME_PCMOUT3 "aio-pcmout3"
#define AUD_NAME_EPCMOUT1 "aio-epcmout1"
#define AUD_NAME_EPCMOUT2 "aio-epcmout2"
#define AUD_NAME_EPCMOUT3 "aio-epcmout3"
#define AUD_NAME_EPCMOUT6 "aio-epcmout6"
#define AUD_NAME_HIECOUT1 "aio-hiecout1"
#define AUD_NAME_IECOUT1 "aio-iecout1"
#define AUD_NAME_CMASTER "aio-cmaster"
#define AUD_NAME_HIECCOMPOUT1 "aio-hieccompout1"
#define AUD_NAME_IECCOMPOUT1 "aio-ieccompout1"
#define AUD_GNAME_HDMI "aio-hdmi"
#define AUD_GNAME_LINE "aio-line"
#define AUD_GNAME_AUX "aio-aux"
#define AUD_GNAME_IEC "aio-iec"
#define AUD_CLK_IO 0
#define AUD_CLK_A1 1
#define AUD_CLK_F1 2
#define AUD_CLK_A2 3
#define AUD_CLK_F2 4
#define AUD_CLK_A 5
#define AUD_CLK_F 6
#define AUD_CLK_APLL 7
#define AUD_CLK_RX0 8
#define AUD_CLK_USB0 9
#define AUD_CLK_HSC0 10
#define AUD_PLL_A1 0
#define AUD_PLL_F1 1
#define AUD_PLL_A2 2
#define AUD_PLL_F2 3
#define AUD_PLL_APLL 4
#define AUD_PLL_RX0 5
#define AUD_PLL_USB0 6
#define AUD_PLL_HSC0 7
#define AUD_PLLDIV_1_2 0
#define AUD_PLLDIV_1_3 1
#define AUD_PLLDIV_1_1 2
#define AUD_PLLDIV_2_3 3
#define AUD_RING_SIZE (128 * 1024)
#define AUD_MIN_FRAGMENT 4
#define AUD_MAX_FRAGMENT 8
#define AUD_MIN_FRAGMENT_SIZE (4 * 1024)
#define AUD_MAX_FRAGMENT_SIZE (16 * 1024)
/*
* This is a selector for virtual register map of AIO.
*
* map: Specify the index of virtual register map.
* hw : Specify the ID of real register map, selector uses this value.
* A meaning of this value depends specification of SoC.
*/
struct uniphier_aio_selector {
int map;
int hw;
};
/**
* 'SoftWare MAPping' setting of UniPhier AIO registers.
*
* We have to setup 'virtual' register maps to access 'real' registers of AIO.
* This feature is legacy and meaningless but AIO needs this to work.
*
* Each hardware blocks have own virtual register maps as following:
*
* Address Virtual Real
* ------- --------- ---------------
* 0x12000 DMAC map0 --> [selector] --> DMAC hardware 3
* 0x12080 DMAC map1 --> [selector] --> DMAC hardware 1
* ...
* 0x42000 Port map0 --> [selector] --> Port hardware 1
* 0x42400 Port map1 --> [selector] --> Port hardware 2
* ...
*
* ch : Input or output channel of DMAC
* rb : Ring buffer
* iport: PCM input port
* iif : Input interface
* oport: PCM output port
* oif : Output interface
* och : Output channel of DMAC for sampling rate converter
*
* These are examples for sound data paths:
*
* For caputure device:
* (outer of AIO) -> iport -> iif -> ch -> rb -> (CPU)
* For playback device:
* (CPU) -> rb -> ch -> oif -> oport -> (outer of AIO)
* For sampling rate converter device:
* (CPU) -> rb -> ch -> oif -> (HW SRC) -> iif -> och -> orb -> (CPU)
*/
struct uniphier_aio_swmap {
int type;
int dir;
struct uniphier_aio_selector ch;
struct uniphier_aio_selector rb;
struct uniphier_aio_selector iport;
struct uniphier_aio_selector iif;
struct uniphier_aio_selector oport;
struct uniphier_aio_selector oif;
struct uniphier_aio_selector och;
};
struct uniphier_aio_spec {
const char *name;
const char *gname;
struct uniphier_aio_swmap swm;
};
struct uniphier_aio_pll {
bool enable;
unsigned int freq;
};
struct uniphier_aio_chip_spec {
const struct uniphier_aio_spec *specs;
int num_specs;
const struct uniphier_aio_pll *plls;
int num_plls;
struct snd_soc_dai_driver *dais;
int num_dais;
/* DMA access mode, this is workaround for DMA hungup */
int addr_ext;
};
struct uniphier_aio_sub {
struct uniphier_aio *aio;
/* Guard sub->rd_offs and wr_offs from IRQ handler. */
spinlock_t lock;
const struct uniphier_aio_swmap *swm;
const struct uniphier_aio_spec *spec;
/* For PCM audio */
struct snd_pcm_substream *substream;
struct snd_pcm_hw_params params;
/* For compress audio */
struct snd_compr_stream *cstream;
struct snd_compr_params cparams;
unsigned char *compr_area;
dma_addr_t compr_addr;
size_t compr_bytes;
int pass_through;
enum IEC61937_PC iec_pc;
bool iec_header;
/* Both PCM and compress audio */
bool use_mmap;
int setting;
int running;
u64 rd_offs;
u64 wr_offs;
u32 threshold;
u64 rd_org;
u64 wr_org;
u64 rd_total;
u64 wr_total;
};
struct uniphier_aio {
struct uniphier_aio_chip *chip;
struct uniphier_aio_sub sub[2];
unsigned int fmt;
/* Set one of AUD_CLK_X */
int clk_in;
int clk_out;
/* Set one of AUD_PLL_X */
int pll_in;
int pll_out;
/* Set one of AUD_PLLDIV_X */
int plldiv;
};
struct uniphier_aio_chip {
struct platform_device *pdev;
const struct uniphier_aio_chip_spec *chip_spec;
struct uniphier_aio *aios;
int num_aios;
struct uniphier_aio_pll *plls;
int num_plls;
struct clk *clk;
struct reset_control *rst;
struct regmap *regmap;
struct regmap *regmap_sg;
int active;
};
static inline struct uniphier_aio *uniphier_priv(struct snd_soc_dai *dai)
{
struct uniphier_aio_chip *chip = snd_soc_dai_get_drvdata(dai);
return &chip->aios[dai->id];
}
int uniphier_aiodma_soc_register_platform(struct platform_device *pdev);
extern const struct snd_compr_ops uniphier_aio_compr_ops;
int uniphier_aio_dai_probe(struct snd_soc_dai *dai);
int uniphier_aio_dai_remove(struct snd_soc_dai *dai);
int uniphier_aio_dai_suspend(struct snd_soc_dai *dai);
int uniphier_aio_dai_resume(struct snd_soc_dai *dai);
int uniphier_aio_probe(struct platform_device *pdev);
int uniphier_aio_remove(struct platform_device *pdev);
extern const struct snd_soc_dai_ops uniphier_aio_i2s_ops;
extern const struct snd_soc_dai_ops uniphier_aio_spdif_ops;
u64 aio_rb_cnt(struct uniphier_aio_sub *sub);
u64 aio_rbt_cnt_to_end(struct uniphier_aio_sub *sub);
u64 aio_rb_space(struct uniphier_aio_sub *sub);
u64 aio_rb_space_to_end(struct uniphier_aio_sub *sub);
void aio_iecout_set_enable(struct uniphier_aio_chip *chip, bool enable);
int aio_chip_set_pll(struct uniphier_aio_chip *chip, int pll_id,
unsigned int freq);
void aio_chip_init(struct uniphier_aio_chip *chip);
int aio_init(struct uniphier_aio_sub *sub);
void aio_port_reset(struct uniphier_aio_sub *sub);
int aio_port_set_rate(struct uniphier_aio_sub *sub, int rate);
int aio_port_set_fmt(struct uniphier_aio_sub *sub);
int aio_port_set_clk(struct uniphier_aio_sub *sub);
int aio_port_set_param(struct uniphier_aio_sub *sub, int pass_through,
const struct snd_pcm_hw_params *params);
void aio_port_set_enable(struct uniphier_aio_sub *sub, int enable);
int aio_if_set_param(struct uniphier_aio_sub *sub, int pass_through);
int aio_oport_set_stream_type(struct uniphier_aio_sub *sub,
enum IEC61937_PC pc);
void aio_src_reset(struct uniphier_aio_sub *sub);
int aio_src_set_param(struct uniphier_aio_sub *sub,
const struct snd_pcm_hw_params *params);
int aio_srcif_set_param(struct uniphier_aio_sub *sub);
int aio_srcch_set_param(struct uniphier_aio_sub *sub);
void aio_srcch_set_enable(struct uniphier_aio_sub *sub, int enable);
int aiodma_ch_set_param(struct uniphier_aio_sub *sub);
void aiodma_ch_set_enable(struct uniphier_aio_sub *sub, int enable);
int aiodma_rb_set_threshold(struct uniphier_aio_sub *sub, u64 size, u32 th);
int aiodma_rb_set_buffer(struct uniphier_aio_sub *sub, u64 start, u64 end,
int period);
void aiodma_rb_sync(struct uniphier_aio_sub *sub, u64 start, u64 size,
int period);
bool aiodma_rb_is_irq(struct uniphier_aio_sub *sub);
void aiodma_rb_clear_irq(struct uniphier_aio_sub *sub);
#endif /* SND_UNIPHIER_AIO_H__ */
// SPDX-License-Identifier: GPL-2.0
/*
* Socionext UniPhier EVEA ADC/DAC codec driver.
*
* Copyright (c) 2016-2017 Socionext Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; version 2
* of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
//
// Socionext UniPhier EVEA ADC/DAC codec driver.
//
// Copyright (c) 2016-2017 Socionext Inc.
#include <linux/clk.h>
#include <linux/module.h>
......@@ -32,6 +18,8 @@
#define AADCPOW(n) (0x0078 + 0x04 * (n))
#define AADCPOW_AADC_POWD BIT(0)
#define ALINSW1 0x0088
#define ALINSW1_SEL1_SHIFT 3
#define AHPOUTPOW 0x0098
#define AHPOUTPOW_HP_ON BIT(4)
#define ALINEPOW 0x009c
......@@ -220,8 +208,8 @@ static void evea_update_switch_all(struct evea_priv *evea)
static int evea_get_switch_lin(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct evea_priv *evea = snd_soc_codec_get_drvdata(codec);
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct evea_priv *evea = snd_soc_component_get_drvdata(component);
ucontrol->value.integer.value[0] = evea->switch_lin;
......@@ -231,8 +219,8 @@ static int evea_get_switch_lin(struct snd_kcontrol *kcontrol,
static int evea_set_switch_lin(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct evea_priv *evea = snd_soc_codec_get_drvdata(codec);
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct evea_priv *evea = snd_soc_component_get_drvdata(component);
if (evea->switch_lin == ucontrol->value.integer.value[0])
return 0;
......@@ -245,8 +233,8 @@ static int evea_set_switch_lin(struct snd_kcontrol *kcontrol,
static int evea_get_switch_lo(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct evea_priv *evea = snd_soc_codec_get_drvdata(codec);
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct evea_priv *evea = snd_soc_component_get_drvdata(component);
ucontrol->value.integer.value[0] = evea->switch_lo;
......@@ -256,8 +244,8 @@ static int evea_get_switch_lo(struct snd_kcontrol *kcontrol,
static int evea_set_switch_lo(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct evea_priv *evea = snd_soc_codec_get_drvdata(codec);
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct evea_priv *evea = snd_soc_component_get_drvdata(component);
if (evea->switch_lo == ucontrol->value.integer.value[0])
return 0;
......@@ -270,8 +258,8 @@ static int evea_set_switch_lo(struct snd_kcontrol *kcontrol,
static int evea_get_switch_hp(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct evea_priv *evea = snd_soc_codec_get_drvdata(codec);
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct evea_priv *evea = snd_soc_component_get_drvdata(component);
ucontrol->value.integer.value[0] = evea->switch_hp;
......@@ -281,8 +269,8 @@ static int evea_get_switch_hp(struct snd_kcontrol *kcontrol,
static int evea_set_switch_hp(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct evea_priv *evea = snd_soc_codec_get_drvdata(codec);
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct evea_priv *evea = snd_soc_component_get_drvdata(component);
if (evea->switch_hp == ucontrol->value.integer.value[0])
return 0;
......@@ -292,7 +280,16 @@ static int evea_set_switch_hp(struct snd_kcontrol *kcontrol,
return evea_update_switch_hp(evea);
}
static const struct snd_kcontrol_new eva_controls[] = {
static const char * const linsw1_sel1_text[] = {
"LIN1", "LIN2", "LIN3"
};
static SOC_ENUM_SINGLE_DECL(linsw1_sel1_enum,
ALINSW1, ALINSW1_SEL1_SHIFT,
linsw1_sel1_text);
static const struct snd_kcontrol_new evea_controls[] = {
SOC_ENUM("Line Capture Source", linsw1_sel1_enum),
SOC_SINGLE_BOOL_EXT("Line Capture Switch", 0,
evea_get_switch_lin, evea_set_switch_lin),
SOC_SINGLE_BOOL_EXT("Line Playback Switch", 0,
......@@ -301,9 +298,9 @@ static const struct snd_kcontrol_new eva_controls[] = {
evea_get_switch_hp, evea_set_switch_hp),
};
static int evea_codec_probe(struct snd_soc_codec *codec)
static int evea_codec_probe(struct snd_soc_component *component)
{
struct evea_priv *evea = snd_soc_codec_get_drvdata(codec);
struct evea_priv *evea = snd_soc_component_get_drvdata(component);
evea->switch_lin = 1;
evea->switch_lo = 1;
......@@ -315,9 +312,9 @@ static int evea_codec_probe(struct snd_soc_codec *codec)
return 0;
}
static int evea_codec_suspend(struct snd_soc_codec *codec)
static int evea_codec_suspend(struct snd_soc_component *component)
{
struct evea_priv *evea = snd_soc_codec_get_drvdata(codec);
struct evea_priv *evea = snd_soc_component_get_drvdata(component);
evea_set_power_state_off(evea);
......@@ -331,9 +328,9 @@ static int evea_codec_suspend(struct snd_soc_codec *codec)
return 0;
}
static int evea_codec_resume(struct snd_soc_codec *codec)
static int evea_codec_resume(struct snd_soc_component *component)
{
struct evea_priv *evea = snd_soc_codec_get_drvdata(codec);
struct evea_priv *evea = snd_soc_component_get_drvdata(component);
int ret;
ret = clk_prepare_enable(evea->clk);
......@@ -376,19 +373,20 @@ static int evea_codec_resume(struct snd_soc_codec *codec)
return ret;
}
static struct snd_soc_codec_driver soc_codec_evea = {
.probe = evea_codec_probe,
.suspend = evea_codec_suspend,
.resume = evea_codec_resume,
.component_driver = {
.dapm_widgets = evea_widgets,
.num_dapm_widgets = ARRAY_SIZE(evea_widgets),
.dapm_routes = evea_routes,
.num_dapm_routes = ARRAY_SIZE(evea_routes),
.controls = eva_controls,
.num_controls = ARRAY_SIZE(eva_controls),
},
static struct snd_soc_component_driver soc_codec_evea = {
.probe = evea_codec_probe,
.suspend = evea_codec_suspend,
.resume = evea_codec_resume,
.dapm_widgets = evea_widgets,
.num_dapm_widgets = ARRAY_SIZE(evea_widgets),
.dapm_routes = evea_routes,
.num_dapm_routes = ARRAY_SIZE(evea_routes),
.controls = evea_controls,
.num_controls = ARRAY_SIZE(evea_controls),
.idle_bias_on = 1,
.use_pmdown_time = 1,
.endianness = 1,
.non_legacy_dai_naming = 1,
};
static struct snd_soc_dai_driver soc_dai_evea[] = {
......@@ -505,7 +503,7 @@ static int evea_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, evea);
ret = snd_soc_register_codec(&pdev->dev, &soc_codec_evea,
ret = devm_snd_soc_register_component(&pdev->dev, &soc_codec_evea,
soc_dai_evea, ARRAY_SIZE(soc_dai_evea));
if (ret)
goto err_out_reset_adamv;
......@@ -534,8 +532,6 @@ static int evea_remove(struct platform_device *pdev)
{
struct evea_priv *evea = platform_get_drvdata(pdev);
snd_soc_unregister_codec(&pdev->dev);
reset_control_assert(evea->rst_adamv);
reset_control_assert(evea->rst_exiv);
reset_control_assert(evea->rst);
......
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