forked from luck/tmp_suning_uos_patched
Merge remote-tracking branches 'asoc/topic/ab8500', 'asoc/topic/arizona', 'asoc/topic/atmel', 'asoc/topic/bcm' and 'asoc/topic/bitfield' into asoc-next
This commit is contained in:
commit
ffe9c4f330
@ -0,0 +1,88 @@
|
||||
Devicetree bindings for the Axentia TSE-850 audio complex
|
||||
|
||||
Required properties:
|
||||
- compatible: "axentia,tse850-pcm5142"
|
||||
- axentia,ssc-controller: The phandle of the atmel SSC controller used as
|
||||
cpu dai.
|
||||
- axentia,audio-codec: The phandle of the PCM5142 codec.
|
||||
- axentia,add-gpios: gpio specifier that controls the mixer.
|
||||
- axentia,loop1-gpios: gpio specifier that controls loop relays on channel 1.
|
||||
- axentia,loop2-gpios: gpio specifier that controls loop relays on channel 2.
|
||||
- axentia,ana-supply: Regulator that supplies the output amplifier. Must
|
||||
support voltages in the 2V - 20V range, in 1V steps.
|
||||
|
||||
The schematics explaining the gpios are as follows:
|
||||
|
||||
loop1 relays
|
||||
IN1 +---o +------------+ o---+ OUT1
|
||||
\ /
|
||||
+ +
|
||||
| / |
|
||||
+--o +--. |
|
||||
| add | |
|
||||
| V |
|
||||
| .---. |
|
||||
DAC +----------->|Sum|---+
|
||||
| '---' |
|
||||
| |
|
||||
+ +
|
||||
|
||||
IN2 +---o--+------------+--o---+ OUT2
|
||||
loop2 relays
|
||||
|
||||
The 'loop1' gpio pin controlls two relays, which are either in loop position,
|
||||
meaning that input and output are directly connected, or they are in mixer
|
||||
position, meaning that the signal is passed through the 'Sum' mixer. Similarly
|
||||
for 'loop2'.
|
||||
|
||||
In the above, the 'loop1' relays are inactive, thus feeding IN1 to the mixer
|
||||
(if 'add' is active) and feeding the mixer output to OUT1. The 'loop2' relays
|
||||
are active, short-cutting the TSE-850 from channel 2. IN1, IN2, OUT1 and OUT2
|
||||
are TSE-850 connectors and DAC is the PCB name of the (filtered) output from
|
||||
the PCM5142 codec.
|
||||
|
||||
Example:
|
||||
|
||||
&i2c {
|
||||
codec: pcm5142@4c {
|
||||
compatible = "ti,pcm5142";
|
||||
|
||||
reg = <0x4c>;
|
||||
|
||||
AVDD-supply = <®_3v3>;
|
||||
DVDD-supply = <®_3v3>;
|
||||
CPVDD-supply = <®_3v3>;
|
||||
|
||||
clocks = <&sck>;
|
||||
|
||||
pll-in = <3>;
|
||||
pll-out = <6>;
|
||||
};
|
||||
};
|
||||
|
||||
ana: ana-reg {
|
||||
compatible = "pwm-regulator";
|
||||
|
||||
regulator-name = "ANA";
|
||||
|
||||
pwms = <&pwm0 2 1000 PWM_POLARITY_INVERTED>;
|
||||
pwm-dutycycle-unit = <1000>;
|
||||
pwm-dutycycle-range = <100 1000>;
|
||||
|
||||
regulator-min-microvolt = <2000000>;
|
||||
regulator-max-microvolt = <20000000>;
|
||||
regulator-ramp-delay = <1000>;
|
||||
};
|
||||
|
||||
sound {
|
||||
compatible = "axentia,tse850-pcm5142";
|
||||
|
||||
axentia,ssc-controller = <&ssc0>;
|
||||
axentia,audio-codec = <&codec>;
|
||||
|
||||
axentia,add-gpios = <&pioA 8 GPIO_ACTIVE_LOW>;
|
||||
axentia,loop1-gpios = <&pioA 10 GPIO_ACTIVE_LOW>;
|
||||
axentia,loop2-gpios = <&pioA 11 GPIO_ACTIVE_LOW>;
|
||||
|
||||
axentia,ana-supply = <&ana>;
|
||||
};
|
@ -2325,6 +2325,13 @@ F: include/uapi/linux/ax25.h
|
||||
F: include/net/ax25.h
|
||||
F: net/ax25/
|
||||
|
||||
AXENTIA ASOC DRIVERS
|
||||
M: Peter Rosin <peda@axentia.se>
|
||||
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/sound/axentia,*
|
||||
F: sound/soc/atmel/tse850-pcm5142.c
|
||||
|
||||
AZ6007 DVB DRIVER
|
||||
M: Mauro Carvalho Chehab <mchehab@s-opensource.com>
|
||||
M: Mauro Carvalho Chehab <mchehab@kernel.org>
|
||||
|
@ -268,8 +268,9 @@ struct snd_soc_dai {
|
||||
unsigned int symmetric_rates:1;
|
||||
unsigned int symmetric_channels:1;
|
||||
unsigned int symmetric_samplebits:1;
|
||||
unsigned int probed:1;
|
||||
|
||||
unsigned int active;
|
||||
unsigned char probed:1;
|
||||
|
||||
struct snd_soc_dapm_widget *playback_widget;
|
||||
struct snd_soc_dapm_widget *capture_widget;
|
||||
|
@ -1029,13 +1029,13 @@ struct snd_soc_dai_link {
|
||||
const struct snd_soc_ops *ops;
|
||||
const struct snd_soc_compr_ops *compr_ops;
|
||||
|
||||
/* For unidirectional dai links */
|
||||
bool playback_only;
|
||||
bool capture_only;
|
||||
|
||||
/* Mark this pcm with non atomic ops */
|
||||
bool nonatomic;
|
||||
|
||||
/* For unidirectional dai links */
|
||||
unsigned int playback_only:1;
|
||||
unsigned int capture_only:1;
|
||||
|
||||
/* Keep DAI active over suspend */
|
||||
unsigned int ignore_suspend:1;
|
||||
|
||||
@ -1206,14 +1206,11 @@ struct snd_soc_pcm_runtime {
|
||||
enum snd_soc_pcm_subclass pcm_subclass;
|
||||
struct snd_pcm_ops ops;
|
||||
|
||||
unsigned int dev_registered:1;
|
||||
|
||||
/* Dynamic PCM BE runtime data */
|
||||
struct snd_soc_dpcm_runtime dpcm[2];
|
||||
int fe_compr;
|
||||
|
||||
long pmdown_time;
|
||||
unsigned char pop_wait:1;
|
||||
|
||||
/* runtime devices */
|
||||
struct snd_pcm *pcm;
|
||||
@ -1234,6 +1231,10 @@ struct snd_soc_pcm_runtime {
|
||||
|
||||
unsigned int num; /* 0-based and monotonic increasing */
|
||||
struct list_head list; /* rtd list of the soc card */
|
||||
|
||||
/* bit field */
|
||||
unsigned int dev_registered:1;
|
||||
unsigned int pop_wait:1;
|
||||
};
|
||||
|
||||
/* mixer control */
|
||||
|
@ -78,4 +78,14 @@ config SND_ATMEL_SOC_PDMIC
|
||||
help
|
||||
Say Y if you want to add support for Atmel ASoC driver for boards using
|
||||
PDMIC.
|
||||
|
||||
config SND_ATMEL_SOC_TSE850_PCM5142
|
||||
tristate "ASoC driver for the Axentia TSE-850"
|
||||
depends on ARCH_AT91 && OF
|
||||
depends on ATMEL_SSC && I2C
|
||||
select SND_ATMEL_SOC_SSC_DMA
|
||||
select SND_SOC_PCM512x_I2C
|
||||
help
|
||||
Say Y if you want to add support for the ASoC driver for the
|
||||
Axentia TSE-850 with a PCM5142 codec.
|
||||
endif
|
||||
|
@ -13,9 +13,11 @@ snd-atmel-soc-wm8904-objs := atmel_wm8904.o
|
||||
snd-soc-sam9x5-wm8731-objs := sam9x5_wm8731.o
|
||||
snd-atmel-soc-classd-objs := atmel-classd.o
|
||||
snd-atmel-soc-pdmic-objs := atmel-pdmic.o
|
||||
snd-atmel-soc-tse850-pcm5142-objs := tse850-pcm5142.o
|
||||
|
||||
obj-$(CONFIG_SND_AT91_SOC_SAM9G20_WM8731) += snd-soc-sam9g20-wm8731.o
|
||||
obj-$(CONFIG_SND_ATMEL_SOC_WM8904) += snd-atmel-soc-wm8904.o
|
||||
obj-$(CONFIG_SND_AT91_SOC_SAM9X5_WM8731) += snd-soc-sam9x5-wm8731.o
|
||||
obj-$(CONFIG_SND_ATMEL_SOC_CLASSD) += snd-atmel-soc-classd.o
|
||||
obj-$(CONFIG_SND_ATMEL_SOC_PDMIC) += snd-atmel-soc-pdmic.o
|
||||
obj-$(CONFIG_SND_ATMEL_SOC_TSE850_PCM5142) += snd-atmel-soc-tse850-pcm5142.o
|
||||
|
@ -380,6 +380,7 @@ static void atmel_ssc_shutdown(struct snd_pcm_substream *substream,
|
||||
ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST));
|
||||
/* Clear the SSC dividers */
|
||||
ssc_p->cmr_div = ssc_p->tcmr_period = ssc_p->rcmr_period = 0;
|
||||
ssc_p->forced_divider = 0;
|
||||
}
|
||||
spin_unlock_irq(&ssc_p->lock);
|
||||
|
||||
@ -426,14 +427,17 @@ static int atmel_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
|
||||
else
|
||||
if (div != ssc_p->cmr_div)
|
||||
return -EBUSY;
|
||||
ssc_p->forced_divider |= BIT(ATMEL_SSC_CMR_DIV);
|
||||
break;
|
||||
|
||||
case ATMEL_SSC_TCMR_PERIOD:
|
||||
ssc_p->tcmr_period = div;
|
||||
ssc_p->forced_divider |= BIT(ATMEL_SSC_TCMR_PERIOD);
|
||||
break;
|
||||
|
||||
case ATMEL_SSC_RCMR_PERIOD:
|
||||
ssc_p->rcmr_period = div;
|
||||
ssc_p->forced_divider |= BIT(ATMEL_SSC_RCMR_PERIOD);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -443,6 +447,28 @@ static int atmel_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Is the cpu-dai master of the frame clock? */
|
||||
static int atmel_ssc_cfs(struct atmel_ssc_info *ssc_p)
|
||||
{
|
||||
switch (ssc_p->daifmt & SND_SOC_DAIFMT_MASTER_MASK) {
|
||||
case SND_SOC_DAIFMT_CBM_CFS:
|
||||
case SND_SOC_DAIFMT_CBS_CFS:
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Is the cpu-dai master of the bit clock? */
|
||||
static int atmel_ssc_cbs(struct atmel_ssc_info *ssc_p)
|
||||
{
|
||||
switch (ssc_p->daifmt & SND_SOC_DAIFMT_MASTER_MASK) {
|
||||
case SND_SOC_DAIFMT_CBS_CFM:
|
||||
case SND_SOC_DAIFMT_CBS_CFS:
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Configure the SSC.
|
||||
*/
|
||||
@ -459,6 +485,9 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
|
||||
u32 tfmr, rfmr, tcmr, rcmr;
|
||||
int ret;
|
||||
int fslen, fslen_ext;
|
||||
u32 cmr_div;
|
||||
u32 tcmr_period;
|
||||
u32 rcmr_period;
|
||||
|
||||
/*
|
||||
* Currently, there is only one set of dma params for
|
||||
@ -470,6 +499,46 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
|
||||
else
|
||||
dir = 1;
|
||||
|
||||
/*
|
||||
* If the cpu dai should provide BCLK, but noone has provided the
|
||||
* divider needed for that to work, fall back to something sensible.
|
||||
*/
|
||||
cmr_div = ssc_p->cmr_div;
|
||||
if (!(ssc_p->forced_divider & BIT(ATMEL_SSC_CMR_DIV)) &&
|
||||
atmel_ssc_cbs(ssc_p)) {
|
||||
int bclk_rate = snd_soc_params_to_bclk(params);
|
||||
|
||||
if (bclk_rate < 0) {
|
||||
dev_err(dai->dev, "unable to calculate cmr_div: %d\n",
|
||||
bclk_rate);
|
||||
return bclk_rate;
|
||||
}
|
||||
|
||||
cmr_div = DIV_ROUND_CLOSEST(ssc_p->mck_rate, 2 * bclk_rate);
|
||||
}
|
||||
|
||||
/*
|
||||
* If the cpu dai should provide LRCLK, but noone has provided the
|
||||
* dividers needed for that to work, fall back to something sensible.
|
||||
*/
|
||||
tcmr_period = ssc_p->tcmr_period;
|
||||
rcmr_period = ssc_p->rcmr_period;
|
||||
if (atmel_ssc_cfs(ssc_p)) {
|
||||
int frame_size = snd_soc_params_to_frame_size(params);
|
||||
|
||||
if (frame_size < 0) {
|
||||
dev_err(dai->dev,
|
||||
"unable to calculate tx/rx cmr_period: %d\n",
|
||||
frame_size);
|
||||
return frame_size;
|
||||
}
|
||||
|
||||
if (!(ssc_p->forced_divider & BIT(ATMEL_SSC_TCMR_PERIOD)))
|
||||
tcmr_period = frame_size / 2 - 1;
|
||||
if (!(ssc_p->forced_divider & BIT(ATMEL_SSC_RCMR_PERIOD)))
|
||||
rcmr_period = frame_size / 2 - 1;
|
||||
}
|
||||
|
||||
dma_params = ssc_p->dma_params[dir];
|
||||
|
||||
channels = params_channels(params);
|
||||
@ -524,7 +593,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
|
||||
fslen_ext = (bits - 1) / 16;
|
||||
fslen = (bits - 1) % 16;
|
||||
|
||||
rcmr = SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period)
|
||||
rcmr = SSC_BF(RCMR_PERIOD, rcmr_period)
|
||||
| SSC_BF(RCMR_STTDLY, START_DELAY)
|
||||
| SSC_BF(RCMR_START, SSC_START_FALLING_RF)
|
||||
| SSC_BF(RCMR_CKI, SSC_CKI_RISING)
|
||||
@ -540,7 +609,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
|
||||
| SSC_BF(RFMR_LOOP, 0)
|
||||
| SSC_BF(RFMR_DATLEN, (bits - 1));
|
||||
|
||||
tcmr = SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period)
|
||||
tcmr = SSC_BF(TCMR_PERIOD, tcmr_period)
|
||||
| SSC_BF(TCMR_STTDLY, START_DELAY)
|
||||
| SSC_BF(TCMR_START, SSC_START_FALLING_RF)
|
||||
| SSC_BF(TCMR_CKI, SSC_CKI_FALLING)
|
||||
@ -606,7 +675,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
|
||||
fslen_ext = (bits - 1) / 16;
|
||||
fslen = (bits - 1) % 16;
|
||||
|
||||
rcmr = SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period)
|
||||
rcmr = SSC_BF(RCMR_PERIOD, rcmr_period)
|
||||
| SSC_BF(RCMR_STTDLY, START_DELAY)
|
||||
| SSC_BF(RCMR_START, SSC_START_FALLING_RF)
|
||||
| SSC_BF(RCMR_CKI, SSC_CKI_RISING)
|
||||
@ -623,7 +692,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
|
||||
| SSC_BF(RFMR_LOOP, 0)
|
||||
| SSC_BF(RFMR_DATLEN, (bits - 1));
|
||||
|
||||
tcmr = SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period)
|
||||
tcmr = SSC_BF(TCMR_PERIOD, tcmr_period)
|
||||
| SSC_BF(TCMR_STTDLY, START_DELAY)
|
||||
| SSC_BF(TCMR_START, SSC_START_FALLING_RF)
|
||||
| SSC_BF(TCMR_CKI, SSC_CKI_FALLING)
|
||||
@ -650,7 +719,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
|
||||
* MCK divider, and the BCLK signal is output
|
||||
* on the SSC TK line.
|
||||
*/
|
||||
rcmr = SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period)
|
||||
rcmr = SSC_BF(RCMR_PERIOD, rcmr_period)
|
||||
| SSC_BF(RCMR_STTDLY, 1)
|
||||
| SSC_BF(RCMR_START, SSC_START_RISING_RF)
|
||||
| SSC_BF(RCMR_CKI, SSC_CKI_RISING)
|
||||
@ -665,7 +734,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
|
||||
| SSC_BF(RFMR_LOOP, 0)
|
||||
| SSC_BF(RFMR_DATLEN, (bits - 1));
|
||||
|
||||
tcmr = SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period)
|
||||
tcmr = SSC_BF(TCMR_PERIOD, tcmr_period)
|
||||
| SSC_BF(TCMR_STTDLY, 1)
|
||||
| SSC_BF(TCMR_START, SSC_START_RISING_RF)
|
||||
| SSC_BF(TCMR_CKI, SSC_CKI_FALLING)
|
||||
@ -760,7 +829,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
|
||||
}
|
||||
|
||||
/* set SSC clock mode register */
|
||||
ssc_writel(ssc_p->ssc->regs, CMR, ssc_p->cmr_div);
|
||||
ssc_writel(ssc_p->ssc->regs, CMR, cmr_div);
|
||||
|
||||
/* set receive clock mode and format */
|
||||
ssc_writel(ssc_p->ssc->regs, RCMR, rcmr);
|
||||
|
@ -113,6 +113,7 @@ struct atmel_ssc_info {
|
||||
unsigned short cmr_div;
|
||||
unsigned short tcmr_period;
|
||||
unsigned short rcmr_period;
|
||||
unsigned int forced_divider;
|
||||
struct atmel_pcm_dma_params *dma_params[2];
|
||||
struct atmel_ssc_state ssc_state;
|
||||
unsigned long mck_rate;
|
||||
|
@ -53,7 +53,7 @@ static int atmel_asoc_wm8904_hw_params(struct snd_pcm_substream *substream,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_ops atmel_asoc_wm8904_ops = {
|
||||
static const struct snd_soc_ops atmel_asoc_wm8904_ops = {
|
||||
.hw_params = atmel_asoc_wm8904_hw_params,
|
||||
};
|
||||
|
||||
|
472
sound/soc/atmel/tse850-pcm5142.c
Normal file
472
sound/soc/atmel/tse850-pcm5142.c
Normal file
@ -0,0 +1,472 @@
|
||||
/*
|
||||
* TSE-850 audio - ASoC driver for the Axentia TSE-850 with a PCM5142 codec
|
||||
*
|
||||
* Copyright (C) 2016 Axentia Technologies AB
|
||||
*
|
||||
* Author: Peter Rosin <peda@axentia.se>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
/*
|
||||
* loop1 relays
|
||||
* IN1 +---o +------------+ o---+ OUT1
|
||||
* \ /
|
||||
* + +
|
||||
* | / |
|
||||
* +--o +--. |
|
||||
* | add | |
|
||||
* | V |
|
||||
* | .---. |
|
||||
* DAC +----------->|Sum|---+
|
||||
* | '---' |
|
||||
* | |
|
||||
* + +
|
||||
*
|
||||
* IN2 +---o--+------------+--o---+ OUT2
|
||||
* loop2 relays
|
||||
*
|
||||
* The 'loop1' gpio pin controlls two relays, which are either in loop
|
||||
* position, meaning that input and output are directly connected, or
|
||||
* they are in mixer position, meaning that the signal is passed through
|
||||
* the 'Sum' mixer. Similarly for 'loop2'.
|
||||
*
|
||||
* In the above, the 'loop1' relays are inactive, thus feeding IN1 to the
|
||||
* mixer (if 'add' is active) and feeding the mixer output to OUT1. The
|
||||
* 'loop2' relays are active, short-cutting the TSE-850 from channel 2.
|
||||
* IN1, IN2, OUT1 and OUT2 are TSE-850 connectors and DAC is the PCB name
|
||||
* of the (filtered) output from the PCM5142 codec.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
#include <sound/soc.h>
|
||||
#include <sound/pcm_params.h>
|
||||
|
||||
#include "atmel_ssc_dai.h"
|
||||
|
||||
struct tse850_priv {
|
||||
int ssc_id;
|
||||
|
||||
struct gpio_desc *add;
|
||||
struct gpio_desc *loop1;
|
||||
struct gpio_desc *loop2;
|
||||
|
||||
struct regulator *ana;
|
||||
|
||||
int add_cache;
|
||||
int loop1_cache;
|
||||
int loop2_cache;
|
||||
};
|
||||
|
||||
static int tse850_get_mux1(struct snd_kcontrol *kctrl,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctrl);
|
||||
struct snd_soc_card *card = dapm->card;
|
||||
struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card);
|
||||
|
||||
ucontrol->value.enumerated.item[0] = tse850->loop1_cache;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tse850_put_mux1(struct snd_kcontrol *kctrl,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctrl);
|
||||
struct snd_soc_card *card = dapm->card;
|
||||
struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card);
|
||||
struct soc_enum *e = (struct soc_enum *)kctrl->private_value;
|
||||
unsigned int val = ucontrol->value.enumerated.item[0];
|
||||
|
||||
if (val >= e->items)
|
||||
return -EINVAL;
|
||||
|
||||
gpiod_set_value_cansleep(tse850->loop1, val);
|
||||
tse850->loop1_cache = val;
|
||||
|
||||
return snd_soc_dapm_put_enum_double(kctrl, ucontrol);
|
||||
}
|
||||
|
||||
static int tse850_get_mux2(struct snd_kcontrol *kctrl,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctrl);
|
||||
struct snd_soc_card *card = dapm->card;
|
||||
struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card);
|
||||
|
||||
ucontrol->value.enumerated.item[0] = tse850->loop2_cache;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tse850_put_mux2(struct snd_kcontrol *kctrl,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctrl);
|
||||
struct snd_soc_card *card = dapm->card;
|
||||
struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card);
|
||||
struct soc_enum *e = (struct soc_enum *)kctrl->private_value;
|
||||
unsigned int val = ucontrol->value.enumerated.item[0];
|
||||
|
||||
if (val >= e->items)
|
||||
return -EINVAL;
|
||||
|
||||
gpiod_set_value_cansleep(tse850->loop2, val);
|
||||
tse850->loop2_cache = val;
|
||||
|
||||
return snd_soc_dapm_put_enum_double(kctrl, ucontrol);
|
||||
}
|
||||
|
||||
int tse850_get_mix(struct snd_kcontrol *kctrl,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctrl);
|
||||
struct snd_soc_card *card = dapm->card;
|
||||
struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card);
|
||||
|
||||
ucontrol->value.enumerated.item[0] = tse850->add_cache;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tse850_put_mix(struct snd_kcontrol *kctrl,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctrl);
|
||||
struct snd_soc_card *card = dapm->card;
|
||||
struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card);
|
||||
int connect = !!ucontrol->value.integer.value[0];
|
||||
|
||||
if (tse850->add_cache == connect)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Hmmm, this gpiod_set_value_cansleep call should probably happen
|
||||
* inside snd_soc_dapm_mixer_update_power in the loop.
|
||||
*/
|
||||
gpiod_set_value_cansleep(tse850->add, connect);
|
||||
tse850->add_cache = connect;
|
||||
|
||||
snd_soc_dapm_mixer_update_power(dapm, kctrl, connect, NULL);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int tse850_get_ana(struct snd_kcontrol *kctrl,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctrl);
|
||||
struct snd_soc_card *card = dapm->card;
|
||||
struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card);
|
||||
int ret;
|
||||
|
||||
ret = regulator_get_voltage(tse850->ana);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Map regulator output values like so:
|
||||
* -11.5V to "Low" (enum 0)
|
||||
* 11.5V-12.5V to "12V" (enum 1)
|
||||
* 12.5V-13.5V to "13V" (enum 2)
|
||||
* ...
|
||||
* 18.5V-19.5V to "19V" (enum 8)
|
||||
* 19.5V- to "20V" (enum 9)
|
||||
*/
|
||||
if (ret < 11000000)
|
||||
ret = 11000000;
|
||||
else if (ret > 20000000)
|
||||
ret = 20000000;
|
||||
ret -= 11000000;
|
||||
ret = (ret + 500000) / 1000000;
|
||||
|
||||
ucontrol->value.enumerated.item[0] = ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tse850_put_ana(struct snd_kcontrol *kctrl,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctrl);
|
||||
struct snd_soc_card *card = dapm->card;
|
||||
struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card);
|
||||
struct soc_enum *e = (struct soc_enum *)kctrl->private_value;
|
||||
unsigned int uV = ucontrol->value.enumerated.item[0];
|
||||
int ret;
|
||||
|
||||
if (uV >= e->items)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Map enum zero (Low) to 2 volts on the regulator, do this since
|
||||
* the ana regulator is supplied by the system 12V voltage and
|
||||
* requesting anything below the system voltage causes the system
|
||||
* voltage to be passed through the regulator. Also, the ana
|
||||
* regulator induces noise when requesting voltages near the
|
||||
* system voltage. So, by mapping Low to 2V, that noise is
|
||||
* eliminated when all that is needed is 12V (the system voltage).
|
||||
*/
|
||||
if (uV)
|
||||
uV = 11000000 + (1000000 * uV);
|
||||
else
|
||||
uV = 2000000;
|
||||
|
||||
ret = regulator_set_voltage(tse850->ana, uV, uV);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return snd_soc_dapm_put_enum_double(kctrl, ucontrol);
|
||||
}
|
||||
|
||||
static const char * const mux_text[] = { "Mixer", "Loop" };
|
||||
|
||||
static const struct soc_enum mux_enum =
|
||||
SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, 2, mux_text);
|
||||
|
||||
static const struct snd_kcontrol_new mux1 =
|
||||
SOC_DAPM_ENUM_EXT("MUX1", mux_enum, tse850_get_mux1, tse850_put_mux1);
|
||||
|
||||
static const struct snd_kcontrol_new mux2 =
|
||||
SOC_DAPM_ENUM_EXT("MUX2", mux_enum, tse850_get_mux2, tse850_put_mux2);
|
||||
|
||||
#define TSE850_DAPM_SINGLE_EXT(xname, reg, shift, max, invert, xget, xput) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
|
||||
.info = snd_soc_info_volsw, \
|
||||
.get = xget, \
|
||||
.put = xput, \
|
||||
.private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) }
|
||||
|
||||
static const struct snd_kcontrol_new mix[] = {
|
||||
TSE850_DAPM_SINGLE_EXT("IN Switch", SND_SOC_NOPM, 0, 1, 0,
|
||||
tse850_get_mix, tse850_put_mix),
|
||||
};
|
||||
|
||||
static const char * const ana_text[] = {
|
||||
"Low", "12V", "13V", "14V", "15V", "16V", "17V", "18V", "19V", "20V"
|
||||
};
|
||||
|
||||
static const struct soc_enum ana_enum =
|
||||
SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, 9, ana_text);
|
||||
|
||||
static const struct snd_kcontrol_new out =
|
||||
SOC_DAPM_ENUM_EXT("ANA", ana_enum, tse850_get_ana, tse850_put_ana);
|
||||
|
||||
static const struct snd_soc_dapm_widget tse850_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_LINE("OUT1", NULL),
|
||||
SND_SOC_DAPM_LINE("OUT2", NULL),
|
||||
SND_SOC_DAPM_LINE("IN1", NULL),
|
||||
SND_SOC_DAPM_LINE("IN2", NULL),
|
||||
SND_SOC_DAPM_INPUT("DAC"),
|
||||
SND_SOC_DAPM_AIF_IN("AIFINL", "Playback", 0, SND_SOC_NOPM, 0, 0),
|
||||
SND_SOC_DAPM_AIF_IN("AIFINR", "Playback", 1, SND_SOC_NOPM, 0, 0),
|
||||
SOC_MIXER_ARRAY("MIX", SND_SOC_NOPM, 0, 0, mix),
|
||||
SND_SOC_DAPM_MUX("MUX1", SND_SOC_NOPM, 0, 0, &mux1),
|
||||
SND_SOC_DAPM_MUX("MUX2", SND_SOC_NOPM, 0, 0, &mux2),
|
||||
SND_SOC_DAPM_OUT_DRV("OUT", SND_SOC_NOPM, 0, 0, &out, 1),
|
||||
};
|
||||
|
||||
/*
|
||||
* These connections are not entirely correct, since both IN1 and IN2
|
||||
* are always fed to MIX (if the "IN switch" is set so), i.e. without
|
||||
* regard to the loop1 and loop2 relays that according to this only
|
||||
* control MUX1 and MUX2 but in fact also control how the input signals
|
||||
* are routed.
|
||||
* But, 1) I don't know how to do it right, and 2) it doesn't seem to
|
||||
* matter in practice since nothing is powered in those sections anyway.
|
||||
*/
|
||||
static const struct snd_soc_dapm_route tse850_intercon[] = {
|
||||
{ "OUT1", NULL, "MUX1" },
|
||||
{ "OUT2", NULL, "MUX2" },
|
||||
|
||||
{ "MUX1", "Loop", "IN1" },
|
||||
{ "MUX1", "Mixer", "OUT" },
|
||||
|
||||
{ "MUX2", "Loop", "IN2" },
|
||||
{ "MUX2", "Mixer", "OUT" },
|
||||
|
||||
{ "OUT", NULL, "MIX" },
|
||||
|
||||
{ "MIX", NULL, "DAC" },
|
||||
{ "MIX", "IN Switch", "IN1" },
|
||||
{ "MIX", "IN Switch", "IN2" },
|
||||
|
||||
/* connect board input to the codec left channel output pin */
|
||||
{ "DAC", NULL, "OUTL" },
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_link tse850_dailink = {
|
||||
.name = "TSE-850",
|
||||
.stream_name = "TSE-850-PCM",
|
||||
.codec_dai_name = "pcm512x-hifi",
|
||||
.dai_fmt = SND_SOC_DAIFMT_I2S
|
||||
| SND_SOC_DAIFMT_NB_NF
|
||||
| SND_SOC_DAIFMT_CBM_CFS,
|
||||
};
|
||||
|
||||
static struct snd_soc_card tse850_card = {
|
||||
.name = "TSE-850-ASoC",
|
||||
.owner = THIS_MODULE,
|
||||
.dai_link = &tse850_dailink,
|
||||
.num_links = 1,
|
||||
.dapm_widgets = tse850_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(tse850_dapm_widgets),
|
||||
.dapm_routes = tse850_intercon,
|
||||
.num_dapm_routes = ARRAY_SIZE(tse850_intercon),
|
||||
.fully_routed = true,
|
||||
};
|
||||
|
||||
static int tse850_dt_init(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct device_node *codec_np, *cpu_np;
|
||||
struct snd_soc_card *card = &tse850_card;
|
||||
struct snd_soc_dai_link *dailink = &tse850_dailink;
|
||||
struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card);
|
||||
|
||||
if (!np) {
|
||||
dev_err(&pdev->dev, "only device tree supported\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cpu_np = of_parse_phandle(np, "axentia,ssc-controller", 0);
|
||||
if (!cpu_np) {
|
||||
dev_err(&pdev->dev, "failed to get dai and pcm info\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
dailink->cpu_of_node = cpu_np;
|
||||
dailink->platform_of_node = cpu_np;
|
||||
tse850->ssc_id = of_alias_get_id(cpu_np, "ssc");
|
||||
of_node_put(cpu_np);
|
||||
|
||||
codec_np = of_parse_phandle(np, "axentia,audio-codec", 0);
|
||||
if (!codec_np) {
|
||||
dev_err(&pdev->dev, "failed to get codec info\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
dailink->codec_of_node = codec_np;
|
||||
of_node_put(codec_np);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tse850_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_card *card = &tse850_card;
|
||||
struct device *dev = card->dev = &pdev->dev;
|
||||
struct tse850_priv *tse850;
|
||||
int ret;
|
||||
|
||||
tse850 = devm_kzalloc(dev, sizeof(*tse850), GFP_KERNEL);
|
||||
if (!tse850)
|
||||
return -ENOMEM;
|
||||
|
||||
snd_soc_card_set_drvdata(card, tse850);
|
||||
|
||||
ret = tse850_dt_init(pdev);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to init dt info\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
tse850->add = devm_gpiod_get(dev, "axentia,add", GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(tse850->add)) {
|
||||
if (PTR_ERR(tse850->add) != -EPROBE_DEFER)
|
||||
dev_err(dev, "failed to get 'add' gpio\n");
|
||||
return PTR_ERR(tse850->add);
|
||||
}
|
||||
tse850->add_cache = 1;
|
||||
|
||||
tse850->loop1 = devm_gpiod_get(dev, "axentia,loop1", GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(tse850->loop1)) {
|
||||
if (PTR_ERR(tse850->loop1) != -EPROBE_DEFER)
|
||||
dev_err(dev, "failed to get 'loop1' gpio\n");
|
||||
return PTR_ERR(tse850->loop1);
|
||||
}
|
||||
tse850->loop1_cache = 1;
|
||||
|
||||
tse850->loop2 = devm_gpiod_get(dev, "axentia,loop2", GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(tse850->loop2)) {
|
||||
if (PTR_ERR(tse850->loop2) != -EPROBE_DEFER)
|
||||
dev_err(dev, "failed to get 'loop2' gpio\n");
|
||||
return PTR_ERR(tse850->loop2);
|
||||
}
|
||||
tse850->loop2_cache = 1;
|
||||
|
||||
tse850->ana = devm_regulator_get(dev, "axentia,ana");
|
||||
if (IS_ERR(tse850->ana)) {
|
||||
if (PTR_ERR(tse850->ana) != -EPROBE_DEFER)
|
||||
dev_err(dev, "failed to get 'ana' regulator\n");
|
||||
return PTR_ERR(tse850->ana);
|
||||
}
|
||||
|
||||
ret = regulator_enable(tse850->ana);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to enable the 'ana' regulator\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = atmel_ssc_set_audio(tse850->ssc_id);
|
||||
if (ret != 0) {
|
||||
dev_err(dev,
|
||||
"failed to set SSC %d for audio\n", tse850->ssc_id);
|
||||
goto err_disable_ana;
|
||||
}
|
||||
|
||||
ret = snd_soc_register_card(card);
|
||||
if (ret) {
|
||||
dev_err(dev, "snd_soc_register_card failed\n");
|
||||
goto err_put_audio;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_put_audio:
|
||||
atmel_ssc_put_audio(tse850->ssc_id);
|
||||
err_disable_ana:
|
||||
regulator_disable(tse850->ana);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tse850_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_card *card = platform_get_drvdata(pdev);
|
||||
struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card);
|
||||
|
||||
snd_soc_unregister_card(card);
|
||||
atmel_ssc_put_audio(tse850->ssc_id);
|
||||
regulator_disable(tse850->ana);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id tse850_dt_ids[] = {
|
||||
{ .compatible = "axentia,tse850-pcm5142", },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, tse850_dt_ids);
|
||||
|
||||
static struct platform_driver tse850_driver = {
|
||||
.driver = {
|
||||
.name = "axentia-tse850-pcm5142",
|
||||
.of_match_table = of_match_ptr(tse850_dt_ids),
|
||||
},
|
||||
.probe = tse850_probe,
|
||||
.remove = tse850_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(tse850_driver);
|
||||
|
||||
/* Module information */
|
||||
MODULE_AUTHOR("Peter Rosin <peda@axentia.se>");
|
||||
MODULE_DESCRIPTION("ALSA SoC driver for TSE-850 with PCM5142 codec");
|
||||
MODULE_LICENSE("GPL");
|
@ -11,6 +11,7 @@ config SND_BCM2835_SOC_I2S
|
||||
config SND_SOC_CYGNUS
|
||||
tristate "SoC platform audio for Broadcom Cygnus chips"
|
||||
depends on ARCH_BCM_CYGNUS || COMPILE_TEST
|
||||
depends on HAS_DMA
|
||||
help
|
||||
Say Y if you want to add support for ASoC audio on Broadcom
|
||||
Cygnus chips (bcm958300, bcm958305, bcm911360)
|
||||
|
@ -2587,8 +2587,6 @@ static struct platform_driver ab8500_codec_platform_driver = {
|
||||
},
|
||||
.probe = ab8500_codec_driver_probe,
|
||||
.remove = ab8500_codec_driver_remove,
|
||||
.suspend = NULL,
|
||||
.resume = NULL,
|
||||
};
|
||||
module_platform_driver(ab8500_codec_platform_driver);
|
||||
|
||||
|
@ -191,6 +191,14 @@ int arizona_init_spk(struct snd_soc_codec *codec)
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(arizona_init_spk);
|
||||
|
||||
int arizona_init_spk_irqs(struct arizona *arizona)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT_WARN,
|
||||
"Thermal warning", arizona_thermal_warn,
|
||||
arizona);
|
||||
@ -209,19 +217,16 @@ int arizona_init_spk(struct snd_soc_codec *codec)
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(arizona_init_spk);
|
||||
EXPORT_SYMBOL_GPL(arizona_init_spk_irqs);
|
||||
|
||||
int arizona_free_spk(struct snd_soc_codec *codec)
|
||||
int arizona_free_spk_irqs(struct arizona *arizona)
|
||||
{
|
||||
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
|
||||
struct arizona *arizona = priv->arizona;
|
||||
|
||||
arizona_free_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT_WARN, arizona);
|
||||
arizona_free_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT, arizona);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(arizona_free_spk);
|
||||
EXPORT_SYMBOL_GPL(arizona_free_spk_irqs);
|
||||
|
||||
static const struct snd_soc_dapm_route arizona_mono_routes[] = {
|
||||
{ "OUT1R", NULL, "OUT1L" },
|
||||
@ -252,6 +257,7 @@ EXPORT_SYMBOL_GPL(arizona_init_mono);
|
||||
int arizona_init_gpio(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
|
||||
struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
|
||||
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
|
||||
struct arizona *arizona = priv->arizona;
|
||||
int i;
|
||||
@ -259,21 +265,24 @@ int arizona_init_gpio(struct snd_soc_codec *codec)
|
||||
switch (arizona->type) {
|
||||
case WM5110:
|
||||
case WM8280:
|
||||
snd_soc_dapm_disable_pin(dapm, "DRC2 Signal Activity");
|
||||
snd_soc_component_disable_pin(component,
|
||||
"DRC2 Signal Activity");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
snd_soc_dapm_disable_pin(dapm, "DRC1 Signal Activity");
|
||||
snd_soc_component_disable_pin(component, "DRC1 Signal Activity");
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) {
|
||||
switch (arizona->pdata.gpio_defaults[i] & ARIZONA_GPN_FN_MASK) {
|
||||
case ARIZONA_GP_FN_DRC1_SIGNAL_DETECT:
|
||||
snd_soc_dapm_enable_pin(dapm, "DRC1 Signal Activity");
|
||||
snd_soc_component_enable_pin(component,
|
||||
"DRC1 Signal Activity");
|
||||
break;
|
||||
case ARIZONA_GP_FN_DRC2_SIGNAL_DETECT:
|
||||
snd_soc_dapm_enable_pin(dapm, "DRC2 Signal Activity");
|
||||
snd_soc_component_enable_pin(component,
|
||||
"DRC2 Signal Activity");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -1233,6 +1242,46 @@ static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int arizona_clk_ev(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 arizona *arizona = dev_get_drvdata(codec->dev->parent);
|
||||
unsigned int val;
|
||||
int clk_idx;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(arizona->regmap, w->reg, &val);
|
||||
if (ret) {
|
||||
dev_err(codec->dev, "Failed to check clock source: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
val = (val & ARIZONA_SYSCLK_SRC_MASK) >> ARIZONA_SYSCLK_SRC_SHIFT;
|
||||
|
||||
switch (val) {
|
||||
case ARIZONA_CLK_SRC_MCLK1:
|
||||
clk_idx = ARIZONA_MCLK1;
|
||||
break;
|
||||
case ARIZONA_CLK_SRC_MCLK2:
|
||||
clk_idx = ARIZONA_MCLK2;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (event) {
|
||||
case SND_SOC_DAPM_PRE_PMU:
|
||||
return clk_prepare_enable(arizona->mclk[clk_idx]);
|
||||
case SND_SOC_DAPM_POST_PMD:
|
||||
clk_disable_unprepare(arizona->mclk[clk_idx]);
|
||||
return 0;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(arizona_clk_ev);
|
||||
|
||||
int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
|
||||
int source, unsigned int freq, int dir)
|
||||
{
|
||||
@ -2242,6 +2291,42 @@ static int arizona_is_enabled_fll(struct arizona_fll *fll, int base)
|
||||
return reg & ARIZONA_FLL1_ENA;
|
||||
}
|
||||
|
||||
static int arizona_set_fll_clks(struct arizona_fll *fll, int base, bool ena)
|
||||
{
|
||||
struct arizona *arizona = fll->arizona;
|
||||
unsigned int val;
|
||||
struct clk *clk;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(arizona->regmap, base + 6, &val);
|
||||
if (ret != 0) {
|
||||
arizona_fll_err(fll, "Failed to read current source: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
val &= ARIZONA_FLL1_CLK_REF_SRC_MASK;
|
||||
val >>= ARIZONA_FLL1_CLK_REF_SRC_SHIFT;
|
||||
|
||||
switch (val) {
|
||||
case ARIZONA_FLL_SRC_MCLK1:
|
||||
clk = arizona->mclk[ARIZONA_MCLK1];
|
||||
break;
|
||||
case ARIZONA_FLL_SRC_MCLK2:
|
||||
clk = arizona->mclk[ARIZONA_MCLK2];
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ena) {
|
||||
return clk_prepare_enable(clk);
|
||||
} else {
|
||||
clk_disable_unprepare(clk);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int arizona_enable_fll(struct arizona_fll *fll)
|
||||
{
|
||||
struct arizona *arizona = fll->arizona;
|
||||
@ -2264,6 +2349,10 @@ static int arizona_enable_fll(struct arizona_fll *fll)
|
||||
udelay(32);
|
||||
regmap_update_bits_async(fll->arizona->regmap, fll->base + 0x9,
|
||||
ARIZONA_FLL1_GAIN_MASK, 0);
|
||||
|
||||
if (arizona_is_enabled_fll(fll, fll->base + 0x10) > 0)
|
||||
arizona_set_fll_clks(fll, fll->base + 0x10, false);
|
||||
arizona_set_fll_clks(fll, fll->base, false);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2318,10 +2407,13 @@ static int arizona_enable_fll(struct arizona_fll *fll)
|
||||
if (!already_enabled)
|
||||
pm_runtime_get_sync(arizona->dev);
|
||||
|
||||
if (use_sync)
|
||||
if (use_sync) {
|
||||
arizona_set_fll_clks(fll, fll->base + 0x10, true);
|
||||
regmap_update_bits_async(arizona->regmap, fll->base + 0x11,
|
||||
ARIZONA_FLL1_SYNC_ENA,
|
||||
ARIZONA_FLL1_SYNC_ENA);
|
||||
}
|
||||
arizona_set_fll_clks(fll, fll->base, true);
|
||||
regmap_update_bits_async(arizona->regmap, fll->base + 1,
|
||||
ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
|
||||
|
||||
@ -2354,19 +2446,24 @@ static int arizona_enable_fll(struct arizona_fll *fll)
|
||||
static void arizona_disable_fll(struct arizona_fll *fll)
|
||||
{
|
||||
struct arizona *arizona = fll->arizona;
|
||||
bool change;
|
||||
bool ref_change, sync_change;
|
||||
|
||||
regmap_update_bits_async(arizona->regmap, fll->base + 1,
|
||||
ARIZONA_FLL1_FREERUN, ARIZONA_FLL1_FREERUN);
|
||||
regmap_update_bits_check(arizona->regmap, fll->base + 1,
|
||||
ARIZONA_FLL1_ENA, 0, &change);
|
||||
regmap_update_bits(arizona->regmap, fll->base + 0x11,
|
||||
ARIZONA_FLL1_SYNC_ENA, 0);
|
||||
ARIZONA_FLL1_ENA, 0, &ref_change);
|
||||
regmap_update_bits_check(arizona->regmap, fll->base + 0x11,
|
||||
ARIZONA_FLL1_SYNC_ENA, 0, &sync_change);
|
||||
regmap_update_bits_async(arizona->regmap, fll->base + 1,
|
||||
ARIZONA_FLL1_FREERUN, 0);
|
||||
|
||||
if (change)
|
||||
if (sync_change)
|
||||
arizona_set_fll_clks(fll, fll->base + 0x10, false);
|
||||
|
||||
if (ref_change) {
|
||||
arizona_set_fll_clks(fll, fll->base, false);
|
||||
pm_runtime_put_autosuspend(arizona->dev);
|
||||
}
|
||||
}
|
||||
|
||||
int arizona_set_fll_refclk(struct arizona_fll *fll, int source,
|
||||
@ -2598,30 +2695,6 @@ int arizona_lhpf_coeff_put(struct snd_kcontrol *kcontrol,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(arizona_lhpf_coeff_put);
|
||||
|
||||
int arizona_register_notifier(struct snd_soc_codec *codec,
|
||||
struct notifier_block *nb,
|
||||
int (*notify)(struct notifier_block *nb,
|
||||
unsigned long action, void *data))
|
||||
{
|
||||
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
|
||||
struct arizona *arizona = priv->arizona;
|
||||
|
||||
nb->notifier_call = notify;
|
||||
|
||||
return blocking_notifier_chain_register(&arizona->notifier, nb);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(arizona_register_notifier);
|
||||
|
||||
int arizona_unregister_notifier(struct snd_soc_codec *codec,
|
||||
struct notifier_block *nb)
|
||||
{
|
||||
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
|
||||
struct arizona *arizona = priv->arizona;
|
||||
|
||||
return blocking_notifier_chain_unregister(&arizona->notifier, nb);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(arizona_unregister_notifier);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support");
|
||||
MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -14,6 +14,8 @@
|
||||
#define _ASOC_ARIZONA_H
|
||||
|
||||
#include <linux/completion.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/mfd/arizona/core.h>
|
||||
|
||||
#include <sound/soc.h>
|
||||
|
||||
@ -66,7 +68,6 @@
|
||||
/* Notifier events */
|
||||
#define ARIZONA_NOTIFY_VOICE_TRIGGER 0x1
|
||||
|
||||
struct arizona;
|
||||
struct wm_adsp;
|
||||
|
||||
struct arizona_dai_priv {
|
||||
@ -255,26 +256,24 @@ extern const struct soc_enum arizona_output_anc_src[];
|
||||
|
||||
extern const struct snd_kcontrol_new arizona_voice_trigger_switch[];
|
||||
|
||||
extern int arizona_in_ev(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol,
|
||||
int event);
|
||||
extern int arizona_out_ev(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol,
|
||||
int event);
|
||||
extern int arizona_hp_ev(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol,
|
||||
int event);
|
||||
extern int arizona_anc_ev(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol,
|
||||
int event);
|
||||
int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
|
||||
int event);
|
||||
int arizona_out_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
|
||||
int event);
|
||||
int arizona_hp_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
|
||||
int event);
|
||||
int arizona_anc_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
|
||||
int event);
|
||||
|
||||
extern int arizona_eq_coeff_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
extern int arizona_lhpf_coeff_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
int arizona_eq_coeff_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
int arizona_lhpf_coeff_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
|
||||
extern int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
|
||||
int source, unsigned int freq, int dir);
|
||||
int arizona_clk_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
|
||||
int event);
|
||||
int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id, int source,
|
||||
unsigned int freq, int dir);
|
||||
|
||||
extern const struct snd_soc_dai_ops arizona_dai_ops;
|
||||
extern const struct snd_soc_dai_ops arizona_simple_dai_ops;
|
||||
@ -297,41 +296,57 @@ struct arizona_fll {
|
||||
char clock_ok_name[ARIZONA_FLL_NAME_LEN];
|
||||
};
|
||||
|
||||
extern int arizona_dvfs_up(struct snd_soc_codec *codec, unsigned int flags);
|
||||
extern int arizona_dvfs_down(struct snd_soc_codec *codec, unsigned int flags);
|
||||
extern int arizona_dvfs_sysclk_ev(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event);
|
||||
extern void arizona_init_dvfs(struct arizona_priv *priv);
|
||||
int arizona_dvfs_up(struct snd_soc_codec *codec, unsigned int flags);
|
||||
int arizona_dvfs_down(struct snd_soc_codec *codec, unsigned int flags);
|
||||
int arizona_dvfs_sysclk_ev(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event);
|
||||
void arizona_init_dvfs(struct arizona_priv *priv);
|
||||
|
||||
extern int arizona_init_fll(struct arizona *arizona, int id, int base,
|
||||
int lock_irq, int ok_irq, struct arizona_fll *fll);
|
||||
extern int arizona_set_fll_refclk(struct arizona_fll *fll, int source,
|
||||
unsigned int Fref, unsigned int Fout);
|
||||
extern int arizona_set_fll(struct arizona_fll *fll, int source,
|
||||
int arizona_init_fll(struct arizona *arizona, int id, int base,
|
||||
int lock_irq, int ok_irq, struct arizona_fll *fll);
|
||||
int arizona_set_fll_refclk(struct arizona_fll *fll, int source,
|
||||
unsigned int Fref, unsigned int Fout);
|
||||
int arizona_set_fll(struct arizona_fll *fll, int source,
|
||||
unsigned int Fref, unsigned int Fout);
|
||||
|
||||
extern int arizona_init_spk(struct snd_soc_codec *codec);
|
||||
extern int arizona_init_gpio(struct snd_soc_codec *codec);
|
||||
extern int arizona_init_mono(struct snd_soc_codec *codec);
|
||||
extern int arizona_init_notifiers(struct snd_soc_codec *codec);
|
||||
int arizona_init_spk(struct snd_soc_codec *codec);
|
||||
int arizona_init_gpio(struct snd_soc_codec *codec);
|
||||
int arizona_init_mono(struct snd_soc_codec *codec);
|
||||
int arizona_init_notifiers(struct snd_soc_codec *codec);
|
||||
|
||||
extern int arizona_free_spk(struct snd_soc_codec *codec);
|
||||
int arizona_init_spk_irqs(struct arizona *arizona);
|
||||
int arizona_free_spk_irqs(struct arizona *arizona);
|
||||
|
||||
extern int arizona_init_dai(struct arizona_priv *priv, int dai);
|
||||
int arizona_init_dai(struct arizona_priv *priv, int dai);
|
||||
|
||||
int arizona_set_output_mode(struct snd_soc_codec *codec, int output,
|
||||
bool diff);
|
||||
|
||||
extern bool arizona_input_analog(struct snd_soc_codec *codec, int shift);
|
||||
bool arizona_input_analog(struct snd_soc_codec *codec, int shift);
|
||||
|
||||
extern const char *arizona_sample_rate_val_to_name(unsigned int rate_val);
|
||||
const char *arizona_sample_rate_val_to_name(unsigned int rate_val);
|
||||
|
||||
extern int arizona_register_notifier(struct snd_soc_codec *codec,
|
||||
struct notifier_block *nb,
|
||||
int (*notify)(struct notifier_block *nb,
|
||||
unsigned long action,
|
||||
void *data));
|
||||
extern int arizona_unregister_notifier(struct snd_soc_codec *codec,
|
||||
struct notifier_block *nb);
|
||||
static inline int arizona_register_notifier(struct snd_soc_codec *codec,
|
||||
struct notifier_block *nb,
|
||||
int (*notify)
|
||||
(struct notifier_block *nb,
|
||||
unsigned long action, void *data))
|
||||
{
|
||||
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
|
||||
struct arizona *arizona = priv->arizona;
|
||||
|
||||
nb->notifier_call = notify;
|
||||
|
||||
return blocking_notifier_chain_register(&arizona->notifier, nb);
|
||||
}
|
||||
|
||||
static inline int arizona_unregister_notifier(struct snd_soc_codec *codec,
|
||||
struct notifier_block *nb)
|
||||
{
|
||||
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
|
||||
struct arizona *arizona = priv->arizona;
|
||||
|
||||
return blocking_notifier_chain_unregister(&arizona->notifier, nb);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -335,9 +335,11 @@ static const struct snd_kcontrol_new cs47l24_aec_loopback_mux =
|
||||
|
||||
static const struct snd_soc_dapm_widget cs47l24_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1,
|
||||
ARIZONA_SYSCLK_ENA_SHIFT, 0, NULL, 0),
|
||||
ARIZONA_SYSCLK_ENA_SHIFT, 0, arizona_clk_ev,
|
||||
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
|
||||
SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1,
|
||||
ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0),
|
||||
ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, arizona_clk_ev,
|
||||
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
|
||||
SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK,
|
||||
ARIZONA_OPCLK_ENA_SHIFT, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", ARIZONA_OUTPUT_ASYNC_CLOCK,
|
||||
@ -1064,7 +1066,7 @@ static struct snd_soc_dai_driver cs47l24_dai[] = {
|
||||
static int cs47l24_open(struct snd_compr_stream *stream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = stream->private_data;
|
||||
struct cs47l24_priv *priv = snd_soc_codec_get_drvdata(rtd->codec);
|
||||
struct cs47l24_priv *priv = snd_soc_platform_get_drvdata(rtd->platform);
|
||||
struct arizona *arizona = priv->core.arizona;
|
||||
int n_adsp;
|
||||
|
||||
@ -1113,8 +1115,8 @@ static irqreturn_t cs47l24_adsp2_irq(int irq, void *data)
|
||||
static int cs47l24_codec_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
|
||||
struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
|
||||
struct cs47l24_priv *priv = snd_soc_codec_get_drvdata(codec);
|
||||
struct arizona *arizona = priv->core.arizona;
|
||||
int ret;
|
||||
|
||||
priv->core.arizona->dapm = dapm;
|
||||
@ -1124,14 +1126,6 @@ static int cs47l24_codec_probe(struct snd_soc_codec *codec)
|
||||
arizona_init_mono(codec);
|
||||
arizona_init_notifiers(codec);
|
||||
|
||||
ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1,
|
||||
"ADSP2 Compressed IRQ", cs47l24_adsp2_irq,
|
||||
priv);
|
||||
if (ret != 0) {
|
||||
dev_err(codec->dev, "Failed to request DSP IRQ: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = wm_adsp2_codec_probe(&priv->core.adsp[1], codec);
|
||||
if (ret)
|
||||
goto err_adsp2_codec_probe;
|
||||
@ -1145,7 +1139,7 @@ static int cs47l24_codec_probe(struct snd_soc_codec *codec)
|
||||
if (ret)
|
||||
goto err_adsp2_codec_probe;
|
||||
|
||||
snd_soc_dapm_disable_pin(dapm, "HAPTICS");
|
||||
snd_soc_component_disable_pin(component, "HAPTICS");
|
||||
|
||||
return 0;
|
||||
|
||||
@ -1159,17 +1153,12 @@ static int cs47l24_codec_probe(struct snd_soc_codec *codec)
|
||||
static int cs47l24_codec_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct cs47l24_priv *priv = snd_soc_codec_get_drvdata(codec);
|
||||
struct arizona *arizona = priv->core.arizona;
|
||||
|
||||
wm_adsp2_codec_remove(&priv->core.adsp[1], codec);
|
||||
wm_adsp2_codec_remove(&priv->core.adsp[2], codec);
|
||||
|
||||
priv->core.arizona->dapm = NULL;
|
||||
|
||||
arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, priv);
|
||||
|
||||
arizona_free_spk(codec);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1285,25 +1274,47 @@ static int cs47l24_probe(struct platform_device *pdev)
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
pm_runtime_idle(&pdev->dev);
|
||||
|
||||
ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1,
|
||||
"ADSP2 Compressed IRQ", cs47l24_adsp2_irq,
|
||||
cs47l24);
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev, "Failed to request DSP IRQ: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = arizona_init_spk_irqs(arizona);
|
||||
if (ret < 0)
|
||||
goto err_dsp_irq;
|
||||
|
||||
ret = snd_soc_register_platform(&pdev->dev, &cs47l24_compr_platform);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Failed to register platform: %d\n", ret);
|
||||
return ret;
|
||||
goto err_spk_irqs;
|
||||
}
|
||||
|
||||
ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_cs47l24,
|
||||
cs47l24_dai, ARRAY_SIZE(cs47l24_dai));
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Failed to register codec: %d\n", ret);
|
||||
snd_soc_unregister_platform(&pdev->dev);
|
||||
goto err_platform;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
err_platform:
|
||||
snd_soc_unregister_platform(&pdev->dev);
|
||||
err_spk_irqs:
|
||||
arizona_free_spk_irqs(arizona);
|
||||
err_dsp_irq:
|
||||
arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, cs47l24);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cs47l24_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct cs47l24_priv *cs47l24 = platform_get_drvdata(pdev);
|
||||
struct arizona *arizona = cs47l24->core.arizona;
|
||||
|
||||
snd_soc_unregister_platform(&pdev->dev);
|
||||
snd_soc_unregister_codec(&pdev->dev);
|
||||
@ -1312,6 +1323,10 @@ static int cs47l24_remove(struct platform_device *pdev)
|
||||
wm_adsp2_remove(&cs47l24->core.adsp[1]);
|
||||
wm_adsp2_remove(&cs47l24->core.adsp[2]);
|
||||
|
||||
arizona_free_spk_irqs(arizona);
|
||||
|
||||
arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, cs47l24);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -607,6 +607,9 @@ static int wm5102_sysclk_ev(struct snd_soc_dapm_widget *w,
|
||||
break;
|
||||
case SND_SOC_DAPM_PRE_PMD:
|
||||
break;
|
||||
case SND_SOC_DAPM_PRE_PMU:
|
||||
case SND_SOC_DAPM_POST_PMD:
|
||||
return arizona_clk_ev(w, kcontrol, event);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@ -1077,9 +1080,11 @@ static const struct snd_kcontrol_new wm5102_aec_loopback_mux =
|
||||
static const struct snd_soc_dapm_widget wm5102_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT,
|
||||
0, wm5102_sysclk_ev,
|
||||
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
|
||||
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD |
|
||||
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
|
||||
SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1,
|
||||
ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0),
|
||||
ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, arizona_clk_ev,
|
||||
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
|
||||
SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK,
|
||||
ARIZONA_OPCLK_ENA_SHIFT, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", ARIZONA_OUTPUT_ASYNC_CLOCK,
|
||||
@ -1903,7 +1908,7 @@ static struct snd_soc_dai_driver wm5102_dai[] = {
|
||||
static int wm5102_open(struct snd_compr_stream *stream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = stream->private_data;
|
||||
struct wm5102_priv *priv = snd_soc_codec_get_drvdata(rtd->codec);
|
||||
struct wm5102_priv *priv = snd_soc_platform_get_drvdata(rtd->platform);
|
||||
|
||||
return wm_adsp_compr_open(&priv->core.adsp[0], stream);
|
||||
}
|
||||
@ -1926,18 +1931,10 @@ static irqreturn_t wm5102_adsp2_irq(int irq, void *data)
|
||||
static int wm5102_codec_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
|
||||
struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
|
||||
struct wm5102_priv *priv = snd_soc_codec_get_drvdata(codec);
|
||||
struct arizona *arizona = priv->core.arizona;
|
||||
int ret;
|
||||
|
||||
ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1,
|
||||
"ADSP2 Compressed IRQ", wm5102_adsp2_irq,
|
||||
priv);
|
||||
if (ret != 0) {
|
||||
dev_err(codec->dev, "Failed to request DSP IRQ: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = wm_adsp2_codec_probe(&priv->core.adsp[0], codec);
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -1949,8 +1946,9 @@ static int wm5102_codec_probe(struct snd_soc_codec *codec)
|
||||
|
||||
arizona_init_spk(codec);
|
||||
arizona_init_gpio(codec);
|
||||
arizona_init_notifiers(codec);
|
||||
|
||||
snd_soc_dapm_disable_pin(dapm, "HAPTICS");
|
||||
snd_soc_component_disable_pin(component, "HAPTICS");
|
||||
|
||||
priv->core.arizona->dapm = dapm;
|
||||
|
||||
@ -1965,16 +1963,11 @@ static int wm5102_codec_probe(struct snd_soc_codec *codec)
|
||||
static int wm5102_codec_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct wm5102_priv *priv = snd_soc_codec_get_drvdata(codec);
|
||||
struct arizona *arizona = priv->core.arizona;
|
||||
|
||||
wm_adsp2_codec_remove(&priv->core.adsp[0], codec);
|
||||
|
||||
priv->core.arizona->dapm = NULL;
|
||||
|
||||
arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, priv);
|
||||
|
||||
arizona_free_spk(codec);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2092,25 +2085,47 @@ static int wm5102_probe(struct platform_device *pdev)
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
pm_runtime_idle(&pdev->dev);
|
||||
|
||||
ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1,
|
||||
"ADSP2 Compressed IRQ", wm5102_adsp2_irq,
|
||||
wm5102);
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev, "Failed to request DSP IRQ: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = arizona_init_spk_irqs(arizona);
|
||||
if (ret < 0)
|
||||
goto err_dsp_irq;
|
||||
|
||||
ret = snd_soc_register_platform(&pdev->dev, &wm5102_compr_platform);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Failed to register platform: %d\n", ret);
|
||||
return ret;
|
||||
goto err_spk_irqs;
|
||||
}
|
||||
|
||||
ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm5102,
|
||||
wm5102_dai, ARRAY_SIZE(wm5102_dai));
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Failed to register codec: %d\n", ret);
|
||||
snd_soc_unregister_platform(&pdev->dev);
|
||||
goto err_platform;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
err_platform:
|
||||
snd_soc_unregister_platform(&pdev->dev);
|
||||
err_spk_irqs:
|
||||
arizona_free_spk_irqs(arizona);
|
||||
err_dsp_irq:
|
||||
arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, wm5102);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wm5102_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct wm5102_priv *wm5102 = platform_get_drvdata(pdev);
|
||||
struct arizona *arizona = wm5102->core.arizona;
|
||||
|
||||
snd_soc_unregister_platform(&pdev->dev);
|
||||
snd_soc_unregister_codec(&pdev->dev);
|
||||
@ -2118,6 +2133,10 @@ static int wm5102_remove(struct platform_device *pdev)
|
||||
|
||||
wm_adsp2_remove(&wm5102->core.adsp[0]);
|
||||
|
||||
arizona_free_spk_irqs(arizona);
|
||||
|
||||
arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, wm5102);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -183,7 +183,9 @@ static int wm5110_sysclk_ev(struct snd_soc_dapm_widget *w,
|
||||
regmap_write_async(regmap, patch[i].reg,
|
||||
patch[i].def);
|
||||
break;
|
||||
|
||||
case SND_SOC_DAPM_PRE_PMU:
|
||||
case SND_SOC_DAPM_POST_PMD:
|
||||
return arizona_clk_ev(w, kcontrol, event);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -1073,9 +1075,11 @@ static const struct snd_kcontrol_new wm5110_output_anc_src[] = {
|
||||
|
||||
static const struct snd_soc_dapm_widget wm5110_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT,
|
||||
0, wm5110_sysclk_ev, SND_SOC_DAPM_POST_PMU),
|
||||
0, wm5110_sysclk_ev, SND_SOC_DAPM_POST_PMU |
|
||||
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
|
||||
SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1,
|
||||
ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0),
|
||||
ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, arizona_clk_ev,
|
||||
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
|
||||
SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK,
|
||||
ARIZONA_OPCLK_ENA_SHIFT, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", ARIZONA_OUTPUT_ASYNC_CLOCK,
|
||||
@ -2220,7 +2224,7 @@ static struct snd_soc_dai_driver wm5110_dai[] = {
|
||||
static int wm5110_open(struct snd_compr_stream *stream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = stream->private_data;
|
||||
struct wm5110_priv *priv = snd_soc_codec_get_drvdata(rtd->codec);
|
||||
struct wm5110_priv *priv = snd_soc_platform_get_drvdata(rtd->platform);
|
||||
struct arizona *arizona = priv->core.arizona;
|
||||
int n_adsp;
|
||||
|
||||
@ -2269,8 +2273,8 @@ static irqreturn_t wm5110_adsp2_irq(int irq, void *data)
|
||||
static int wm5110_codec_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
|
||||
struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
|
||||
struct wm5110_priv *priv = snd_soc_codec_get_drvdata(codec);
|
||||
struct arizona *arizona = priv->core.arizona;
|
||||
int i, ret;
|
||||
|
||||
priv->core.arizona->dapm = dapm;
|
||||
@ -2280,14 +2284,6 @@ static int wm5110_codec_probe(struct snd_soc_codec *codec)
|
||||
arizona_init_mono(codec);
|
||||
arizona_init_notifiers(codec);
|
||||
|
||||
ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1,
|
||||
"ADSP2 Compressed IRQ", wm5110_adsp2_irq,
|
||||
priv);
|
||||
if (ret != 0) {
|
||||
dev_err(codec->dev, "Failed to request DSP IRQ: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 0; i < WM5110_NUM_ADSP; ++i) {
|
||||
ret = wm_adsp2_codec_probe(&priv->core.adsp[i], codec);
|
||||
if (ret)
|
||||
@ -2300,7 +2296,7 @@ static int wm5110_codec_probe(struct snd_soc_codec *codec)
|
||||
if (ret)
|
||||
goto err_adsp2_codec_probe;
|
||||
|
||||
snd_soc_dapm_disable_pin(dapm, "HAPTICS");
|
||||
snd_soc_component_disable_pin(component, "HAPTICS");
|
||||
|
||||
return 0;
|
||||
|
||||
@ -2308,15 +2304,12 @@ static int wm5110_codec_probe(struct snd_soc_codec *codec)
|
||||
for (--i; i >= 0; --i)
|
||||
wm_adsp2_codec_remove(&priv->core.adsp[i], codec);
|
||||
|
||||
arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, priv);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wm5110_codec_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct wm5110_priv *priv = snd_soc_codec_get_drvdata(codec);
|
||||
struct arizona *arizona = priv->core.arizona;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < WM5110_NUM_ADSP; ++i)
|
||||
@ -2324,10 +2317,6 @@ static int wm5110_codec_remove(struct snd_soc_codec *codec)
|
||||
|
||||
priv->core.arizona->dapm = NULL;
|
||||
|
||||
arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, priv);
|
||||
|
||||
arizona_free_spk(codec);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2449,25 +2438,47 @@ static int wm5110_probe(struct platform_device *pdev)
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
pm_runtime_idle(&pdev->dev);
|
||||
|
||||
ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1,
|
||||
"ADSP2 Compressed IRQ", wm5110_adsp2_irq,
|
||||
wm5110);
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev, "Failed to request DSP IRQ: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = arizona_init_spk_irqs(arizona);
|
||||
if (ret < 0)
|
||||
goto err_dsp_irq;
|
||||
|
||||
ret = snd_soc_register_platform(&pdev->dev, &wm5110_compr_platform);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Failed to register platform: %d\n", ret);
|
||||
return ret;
|
||||
goto err_spk_irqs;
|
||||
}
|
||||
|
||||
ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm5110,
|
||||
wm5110_dai, ARRAY_SIZE(wm5110_dai));
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Failed to register codec: %d\n", ret);
|
||||
snd_soc_unregister_platform(&pdev->dev);
|
||||
goto err_platform;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
err_platform:
|
||||
snd_soc_unregister_platform(&pdev->dev);
|
||||
err_spk_irqs:
|
||||
arizona_free_spk_irqs(arizona);
|
||||
err_dsp_irq:
|
||||
arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, wm5110);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wm5110_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct wm5110_priv *wm5110 = platform_get_drvdata(pdev);
|
||||
struct arizona *arizona = wm5110->core.arizona;
|
||||
int i;
|
||||
|
||||
snd_soc_unregister_platform(&pdev->dev);
|
||||
@ -2477,6 +2488,10 @@ static int wm5110_remove(struct platform_device *pdev)
|
||||
for (i = 0; i < WM5110_NUM_ADSP; i++)
|
||||
wm_adsp2_remove(&wm5110->core.adsp[i]);
|
||||
|
||||
arizona_free_spk_irqs(arizona);
|
||||
|
||||
arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, wm5110);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -108,6 +108,9 @@ static int wm8997_sysclk_ev(struct snd_soc_dapm_widget *w,
|
||||
break;
|
||||
case SND_SOC_DAPM_PRE_PMD:
|
||||
break;
|
||||
case SND_SOC_DAPM_PRE_PMU:
|
||||
case SND_SOC_DAPM_POST_PMD:
|
||||
return arizona_clk_ev(w, kcontrol, event);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@ -408,9 +411,11 @@ static const struct snd_kcontrol_new wm8997_aec_loopback_mux =
|
||||
static const struct snd_soc_dapm_widget wm8997_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT,
|
||||
0, wm8997_sysclk_ev,
|
||||
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
|
||||
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD |
|
||||
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
|
||||
SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1,
|
||||
ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0),
|
||||
ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, arizona_clk_ev,
|
||||
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
|
||||
SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK,
|
||||
ARIZONA_OPCLK_ENA_SHIFT, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", ARIZONA_OUTPUT_ASYNC_CLOCK,
|
||||
@ -1055,11 +1060,13 @@ static struct snd_soc_dai_driver wm8997_dai[] = {
|
||||
static int wm8997_codec_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
|
||||
struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
|
||||
struct wm8997_priv *priv = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
arizona_init_spk(codec);
|
||||
arizona_init_notifiers(codec);
|
||||
|
||||
snd_soc_dapm_disable_pin(dapm, "HAPTICS");
|
||||
snd_soc_component_disable_pin(component, "HAPTICS");
|
||||
|
||||
priv->core.arizona->dapm = dapm;
|
||||
|
||||
@ -1072,8 +1079,6 @@ static int wm8997_codec_remove(struct snd_soc_codec *codec)
|
||||
|
||||
priv->core.arizona->dapm = NULL;
|
||||
|
||||
arizona_free_spk(codec);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1119,7 +1124,7 @@ static int wm8997_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
|
||||
struct wm8997_priv *wm8997;
|
||||
int i;
|
||||
int i, ret;
|
||||
|
||||
wm8997 = devm_kzalloc(&pdev->dev, sizeof(struct wm8997_priv),
|
||||
GFP_KERNEL);
|
||||
@ -1159,15 +1164,33 @@ static int wm8997_probe(struct platform_device *pdev)
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
pm_runtime_idle(&pdev->dev);
|
||||
|
||||
return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8997,
|
||||
wm8997_dai, ARRAY_SIZE(wm8997_dai));
|
||||
ret = arizona_init_spk_irqs(arizona);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8997,
|
||||
wm8997_dai, ARRAY_SIZE(wm8997_dai));
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Failed to register codec: %d\n", ret);
|
||||
goto err_spk_irqs;
|
||||
}
|
||||
|
||||
err_spk_irqs:
|
||||
arizona_free_spk_irqs(arizona);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wm8997_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct wm8997_priv *wm8997 = platform_get_drvdata(pdev);
|
||||
struct arizona *arizona = wm8997->core.arizona;
|
||||
|
||||
snd_soc_unregister_codec(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
arizona_free_spk_irqs(arizona);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -541,9 +541,11 @@ static const struct snd_kcontrol_new wm8998_aec_loopback_mux[] = {
|
||||
|
||||
static const struct snd_soc_dapm_widget wm8998_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1,
|
||||
ARIZONA_SYSCLK_ENA_SHIFT, 0, NULL, 0),
|
||||
ARIZONA_SYSCLK_ENA_SHIFT, 0, arizona_clk_ev,
|
||||
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
|
||||
SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1,
|
||||
ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0),
|
||||
ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, arizona_clk_ev,
|
||||
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
|
||||
SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK,
|
||||
ARIZONA_OPCLK_ENA_SHIFT, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", ARIZONA_OUTPUT_ASYNC_CLOCK,
|
||||
@ -1318,13 +1320,15 @@ static int wm8998_codec_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct wm8998_priv *priv = snd_soc_codec_get_drvdata(codec);
|
||||
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
|
||||
struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
|
||||
|
||||
priv->core.arizona->dapm = dapm;
|
||||
|
||||
arizona_init_spk(codec);
|
||||
arizona_init_gpio(codec);
|
||||
arizona_init_notifiers(codec);
|
||||
|
||||
snd_soc_dapm_disable_pin(dapm, "HAPTICS");
|
||||
snd_soc_component_disable_pin(component, "HAPTICS");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1335,8 +1339,6 @@ static int wm8998_codec_remove(struct snd_soc_codec *codec)
|
||||
|
||||
priv->core.arizona->dapm = NULL;
|
||||
|
||||
arizona_free_spk(codec);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1385,7 +1387,7 @@ static int wm8998_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
|
||||
struct wm8998_priv *wm8998;
|
||||
int i;
|
||||
int i, ret;
|
||||
|
||||
wm8998 = devm_kzalloc(&pdev->dev, sizeof(struct wm8998_priv),
|
||||
GFP_KERNEL);
|
||||
@ -1417,15 +1419,35 @@ static int wm8998_probe(struct platform_device *pdev)
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
pm_runtime_idle(&pdev->dev);
|
||||
|
||||
return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8998,
|
||||
wm8998_dai, ARRAY_SIZE(wm8998_dai));
|
||||
ret = arizona_init_spk_irqs(arizona);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8998,
|
||||
wm8998_dai, ARRAY_SIZE(wm8998_dai));
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Failed to register codec: %d\n", ret);
|
||||
goto err_spk_irqs;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
err_spk_irqs:
|
||||
arizona_free_spk_irqs(arizona);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wm8998_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct wm8998_priv *wm8998 = platform_get_drvdata(pdev);
|
||||
struct arizona *arizona = wm8998->core.arizona;
|
||||
|
||||
snd_soc_unregister_codec(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
arizona_free_spk_irqs(arizona);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -162,6 +162,16 @@
|
||||
|
||||
#define ADSP_MAX_STD_CTRL_SIZE 512
|
||||
|
||||
#define WM_ADSP_ACKED_CTL_TIMEOUT_MS 100
|
||||
#define WM_ADSP_ACKED_CTL_N_QUICKPOLLS 10
|
||||
#define WM_ADSP_ACKED_CTL_MIN_VALUE 0
|
||||
#define WM_ADSP_ACKED_CTL_MAX_VALUE 0xFFFFFF
|
||||
|
||||
/*
|
||||
* Event control messages
|
||||
*/
|
||||
#define WM_ADSP_FW_EVENT_SHUTDOWN 0x000001
|
||||
|
||||
struct wm_adsp_buf {
|
||||
struct list_head list;
|
||||
void *buf;
|
||||
@ -177,7 +187,7 @@ static struct wm_adsp_buf *wm_adsp_buf_alloc(const void *src, size_t len,
|
||||
|
||||
buf->buf = vmalloc(len);
|
||||
if (!buf->buf) {
|
||||
vfree(buf);
|
||||
kfree(buf);
|
||||
return NULL;
|
||||
}
|
||||
memcpy(buf->buf, src, len);
|
||||
@ -441,11 +451,29 @@ struct wm_coeff_ctl {
|
||||
unsigned int offset;
|
||||
size_t len;
|
||||
unsigned int set:1;
|
||||
struct snd_kcontrol *kcontrol;
|
||||
struct soc_bytes_ext bytes_ext;
|
||||
unsigned int flags;
|
||||
unsigned int type;
|
||||
};
|
||||
|
||||
static const char *wm_adsp_mem_region_name(unsigned int type)
|
||||
{
|
||||
switch (type) {
|
||||
case WMFW_ADSP1_PM:
|
||||
return "PM";
|
||||
case WMFW_ADSP1_DM:
|
||||
return "DM";
|
||||
case WMFW_ADSP2_XM:
|
||||
return "XM";
|
||||
case WMFW_ADSP2_YM:
|
||||
return "YM";
|
||||
case WMFW_ADSP1_ZM:
|
||||
return "ZM";
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
static void wm_adsp_debugfs_save_wmfwname(struct wm_adsp *dsp, const char *s)
|
||||
{
|
||||
@ -727,27 +755,11 @@ static inline struct wm_coeff_ctl *bytes_ext_to_ctl(struct soc_bytes_ext *ext)
|
||||
return container_of(ext, struct wm_coeff_ctl, bytes_ext);
|
||||
}
|
||||
|
||||
static int wm_coeff_info(struct snd_kcontrol *kctl,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
static int wm_coeff_base_reg(struct wm_coeff_ctl *ctl, unsigned int *reg)
|
||||
{
|
||||
struct soc_bytes_ext *bytes_ext =
|
||||
(struct soc_bytes_ext *)kctl->private_value;
|
||||
struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
|
||||
|
||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
|
||||
uinfo->count = ctl->len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wm_coeff_write_control(struct wm_coeff_ctl *ctl,
|
||||
const void *buf, size_t len)
|
||||
{
|
||||
struct wm_adsp_alg_region *alg_region = &ctl->alg_region;
|
||||
const struct wm_adsp_region *mem;
|
||||
const struct wm_adsp_alg_region *alg_region = &ctl->alg_region;
|
||||
struct wm_adsp *dsp = ctl->dsp;
|
||||
void *scratch;
|
||||
int ret;
|
||||
unsigned int reg;
|
||||
const struct wm_adsp_region *mem;
|
||||
|
||||
mem = wm_adsp_find_region(dsp, alg_region->type);
|
||||
if (!mem) {
|
||||
@ -756,8 +768,106 @@ static int wm_coeff_write_control(struct wm_coeff_ctl *ctl,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
reg = ctl->alg_region.base + ctl->offset;
|
||||
reg = wm_adsp_region_to_reg(mem, reg);
|
||||
*reg = wm_adsp_region_to_reg(mem, ctl->alg_region.base + ctl->offset);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wm_coeff_info(struct snd_kcontrol *kctl,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
struct soc_bytes_ext *bytes_ext =
|
||||
(struct soc_bytes_ext *)kctl->private_value;
|
||||
struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
|
||||
|
||||
switch (ctl->type) {
|
||||
case WMFW_CTL_TYPE_ACKED:
|
||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
|
||||
uinfo->value.integer.min = WM_ADSP_ACKED_CTL_MIN_VALUE;
|
||||
uinfo->value.integer.max = WM_ADSP_ACKED_CTL_MAX_VALUE;
|
||||
uinfo->value.integer.step = 1;
|
||||
uinfo->count = 1;
|
||||
break;
|
||||
default:
|
||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
|
||||
uinfo->count = ctl->len;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wm_coeff_write_acked_control(struct wm_coeff_ctl *ctl,
|
||||
unsigned int event_id)
|
||||
{
|
||||
struct wm_adsp *dsp = ctl->dsp;
|
||||
u32 val = cpu_to_be32(event_id);
|
||||
unsigned int reg;
|
||||
int i, ret;
|
||||
|
||||
ret = wm_coeff_base_reg(ctl, ®);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
adsp_dbg(dsp, "Sending 0x%x to acked control alg 0x%x %s:0x%x\n",
|
||||
event_id, ctl->alg_region.alg,
|
||||
wm_adsp_mem_region_name(ctl->alg_region.type), ctl->offset);
|
||||
|
||||
ret = regmap_raw_write(dsp->regmap, reg, &val, sizeof(val));
|
||||
if (ret) {
|
||||
adsp_err(dsp, "Failed to write %x: %d\n", reg, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Poll for ack, we initially poll at ~1ms intervals for firmwares
|
||||
* that respond quickly, then go to ~10ms polls. A firmware is unlikely
|
||||
* to ack instantly so we do the first 1ms delay before reading the
|
||||
* control to avoid a pointless bus transaction
|
||||
*/
|
||||
for (i = 0; i < WM_ADSP_ACKED_CTL_TIMEOUT_MS;) {
|
||||
switch (i) {
|
||||
case 0 ... WM_ADSP_ACKED_CTL_N_QUICKPOLLS - 1:
|
||||
usleep_range(1000, 2000);
|
||||
i++;
|
||||
break;
|
||||
default:
|
||||
usleep_range(10000, 20000);
|
||||
i += 10;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = regmap_raw_read(dsp->regmap, reg, &val, sizeof(val));
|
||||
if (ret) {
|
||||
adsp_err(dsp, "Failed to read %x: %d\n", reg, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (val == 0) {
|
||||
adsp_dbg(dsp, "Acked control ACKED at poll %u\n", i);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
adsp_warn(dsp, "Acked control @0x%x alg:0x%x %s:0x%x timed out\n",
|
||||
reg, ctl->alg_region.alg,
|
||||
wm_adsp_mem_region_name(ctl->alg_region.type),
|
||||
ctl->offset);
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static int wm_coeff_write_control(struct wm_coeff_ctl *ctl,
|
||||
const void *buf, size_t len)
|
||||
{
|
||||
struct wm_adsp *dsp = ctl->dsp;
|
||||
void *scratch;
|
||||
int ret;
|
||||
unsigned int reg;
|
||||
|
||||
ret = wm_coeff_base_reg(ctl, ®);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
scratch = kmemdup(buf, len, GFP_KERNEL | GFP_DMA);
|
||||
if (!scratch)
|
||||
@ -823,25 +933,41 @@ static int wm_coeff_tlv_put(struct snd_kcontrol *kctl,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wm_coeff_put_acked(struct snd_kcontrol *kctl,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct soc_bytes_ext *bytes_ext =
|
||||
(struct soc_bytes_ext *)kctl->private_value;
|
||||
struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
|
||||
unsigned int val = ucontrol->value.integer.value[0];
|
||||
int ret;
|
||||
|
||||
if (val == 0)
|
||||
return 0; /* 0 means no event */
|
||||
|
||||
mutex_lock(&ctl->dsp->pwr_lock);
|
||||
|
||||
if (ctl->enabled)
|
||||
ret = wm_coeff_write_acked_control(ctl, val);
|
||||
else
|
||||
ret = -EPERM;
|
||||
|
||||
mutex_unlock(&ctl->dsp->pwr_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wm_coeff_read_control(struct wm_coeff_ctl *ctl,
|
||||
void *buf, size_t len)
|
||||
{
|
||||
struct wm_adsp_alg_region *alg_region = &ctl->alg_region;
|
||||
const struct wm_adsp_region *mem;
|
||||
struct wm_adsp *dsp = ctl->dsp;
|
||||
void *scratch;
|
||||
int ret;
|
||||
unsigned int reg;
|
||||
|
||||
mem = wm_adsp_find_region(dsp, alg_region->type);
|
||||
if (!mem) {
|
||||
adsp_err(dsp, "No base for region %x\n",
|
||||
alg_region->type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
reg = ctl->alg_region.base + ctl->offset;
|
||||
reg = wm_adsp_region_to_reg(mem, reg);
|
||||
ret = wm_coeff_base_reg(ctl, ®);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
scratch = kmalloc(len, GFP_KERNEL | GFP_DMA);
|
||||
if (!scratch)
|
||||
@ -918,6 +1044,21 @@ static int wm_coeff_tlv_get(struct snd_kcontrol *kctl,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wm_coeff_get_acked(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
/*
|
||||
* Although it's not useful to read an acked control, we must satisfy
|
||||
* user-side assumptions that all controls are readable and that a
|
||||
* write of the same value should be filtered out (it's valid to send
|
||||
* the same event number again to the firmware). We therefore return 0,
|
||||
* meaning "no event" so valid event numbers will always be a change
|
||||
*/
|
||||
ucontrol->value.integer.value[0] = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct wmfw_ctl_work {
|
||||
struct wm_adsp *dsp;
|
||||
struct wm_coeff_ctl *ctl;
|
||||
@ -967,30 +1108,35 @@ static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl)
|
||||
kcontrol = kzalloc(sizeof(*kcontrol), GFP_KERNEL);
|
||||
if (!kcontrol)
|
||||
return -ENOMEM;
|
||||
kcontrol->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
|
||||
|
||||
kcontrol->name = ctl->name;
|
||||
kcontrol->info = wm_coeff_info;
|
||||
kcontrol->get = wm_coeff_get;
|
||||
kcontrol->put = wm_coeff_put;
|
||||
kcontrol->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
|
||||
kcontrol->tlv.c = snd_soc_bytes_tlv_callback;
|
||||
kcontrol->private_value = (unsigned long)&ctl->bytes_ext;
|
||||
|
||||
ctl->bytes_ext.max = ctl->len;
|
||||
ctl->bytes_ext.get = wm_coeff_tlv_get;
|
||||
ctl->bytes_ext.put = wm_coeff_tlv_put;
|
||||
|
||||
kcontrol->access = wmfw_convert_flags(ctl->flags, ctl->len);
|
||||
|
||||
ret = snd_soc_add_card_controls(dsp->card, kcontrol, 1);
|
||||
switch (ctl->type) {
|
||||
case WMFW_CTL_TYPE_ACKED:
|
||||
kcontrol->get = wm_coeff_get_acked;
|
||||
kcontrol->put = wm_coeff_put_acked;
|
||||
break;
|
||||
default:
|
||||
kcontrol->get = wm_coeff_get;
|
||||
kcontrol->put = wm_coeff_put;
|
||||
|
||||
ctl->bytes_ext.max = ctl->len;
|
||||
ctl->bytes_ext.get = wm_coeff_tlv_get;
|
||||
ctl->bytes_ext.put = wm_coeff_tlv_put;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = snd_soc_add_codec_controls(dsp->codec, kcontrol, 1);
|
||||
if (ret < 0)
|
||||
goto err_kcontrol;
|
||||
|
||||
kfree(kcontrol);
|
||||
|
||||
ctl->kcontrol = snd_soc_card_get_kcontrol(dsp->card, ctl->name);
|
||||
|
||||
return 0;
|
||||
|
||||
err_kcontrol:
|
||||
@ -1035,6 +1181,27 @@ static int wm_coeff_sync_controls(struct wm_adsp *dsp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void wm_adsp_signal_event_controls(struct wm_adsp *dsp,
|
||||
unsigned int event)
|
||||
{
|
||||
struct wm_coeff_ctl *ctl;
|
||||
int ret;
|
||||
|
||||
list_for_each_entry(ctl, &dsp->ctl_list, list) {
|
||||
if (ctl->type != WMFW_CTL_TYPE_HOSTEVENT)
|
||||
continue;
|
||||
|
||||
if (!ctl->enabled)
|
||||
continue;
|
||||
|
||||
ret = wm_coeff_write_acked_control(ctl, event);
|
||||
if (ret)
|
||||
adsp_warn(dsp,
|
||||
"Failed to send 0x%x event to alg 0x%x (%d)\n",
|
||||
event, ctl->alg_region.alg, ret);
|
||||
}
|
||||
}
|
||||
|
||||
static void wm_adsp_ctl_work(struct work_struct *work)
|
||||
{
|
||||
struct wmfw_ctl_work *ctl_work = container_of(work,
|
||||
@ -1056,34 +1223,16 @@ static int wm_adsp_create_control(struct wm_adsp *dsp,
|
||||
const struct wm_adsp_alg_region *alg_region,
|
||||
unsigned int offset, unsigned int len,
|
||||
const char *subname, unsigned int subname_len,
|
||||
unsigned int flags)
|
||||
unsigned int flags, unsigned int type)
|
||||
{
|
||||
struct wm_coeff_ctl *ctl;
|
||||
struct wmfw_ctl_work *ctl_work;
|
||||
char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
|
||||
char *region_name;
|
||||
const char *region_name;
|
||||
int ret;
|
||||
|
||||
if (flags & WMFW_CTL_FLAG_SYS)
|
||||
return 0;
|
||||
|
||||
switch (alg_region->type) {
|
||||
case WMFW_ADSP1_PM:
|
||||
region_name = "PM";
|
||||
break;
|
||||
case WMFW_ADSP1_DM:
|
||||
region_name = "DM";
|
||||
break;
|
||||
case WMFW_ADSP2_XM:
|
||||
region_name = "XM";
|
||||
break;
|
||||
case WMFW_ADSP2_YM:
|
||||
region_name = "YM";
|
||||
break;
|
||||
case WMFW_ADSP1_ZM:
|
||||
region_name = "ZM";
|
||||
break;
|
||||
default:
|
||||
region_name = wm_adsp_mem_region_name(alg_region->type);
|
||||
if (!region_name) {
|
||||
adsp_err(dsp, "Unknown region type: %d\n", alg_region->type);
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -1139,6 +1288,7 @@ static int wm_adsp_create_control(struct wm_adsp *dsp,
|
||||
ctl->dsp = dsp;
|
||||
|
||||
ctl->flags = flags;
|
||||
ctl->type = type;
|
||||
ctl->offset = offset;
|
||||
ctl->len = len;
|
||||
ctl->cache = kzalloc(ctl->len, GFP_KERNEL);
|
||||
@ -1149,6 +1299,9 @@ static int wm_adsp_create_control(struct wm_adsp *dsp,
|
||||
|
||||
list_add(&ctl->list, &dsp->ctl_list);
|
||||
|
||||
if (flags & WMFW_CTL_FLAG_SYS)
|
||||
return 0;
|
||||
|
||||
ctl_work = kzalloc(sizeof(*ctl_work), GFP_KERNEL);
|
||||
if (!ctl_work) {
|
||||
ret = -ENOMEM;
|
||||
@ -1308,6 +1461,21 @@ static inline void wm_coeff_parse_coeff(struct wm_adsp *dsp, const u8 **data,
|
||||
adsp_dbg(dsp, "\tALSA control len: %#x\n", blk->len);
|
||||
}
|
||||
|
||||
static int wm_adsp_check_coeff_flags(struct wm_adsp *dsp,
|
||||
const struct wm_coeff_parsed_coeff *coeff_blk,
|
||||
unsigned int f_required,
|
||||
unsigned int f_illegal)
|
||||
{
|
||||
if ((coeff_blk->flags & f_illegal) ||
|
||||
((coeff_blk->flags & f_required) != f_required)) {
|
||||
adsp_err(dsp, "Illegal flags 0x%x for control type 0x%x\n",
|
||||
coeff_blk->flags, coeff_blk->ctl_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wm_adsp_parse_coeff(struct wm_adsp *dsp,
|
||||
const struct wmfw_region *region)
|
||||
{
|
||||
@ -1324,6 +1492,28 @@ static int wm_adsp_parse_coeff(struct wm_adsp *dsp,
|
||||
switch (coeff_blk.ctl_type) {
|
||||
case SNDRV_CTL_ELEM_TYPE_BYTES:
|
||||
break;
|
||||
case WMFW_CTL_TYPE_ACKED:
|
||||
if (coeff_blk.flags & WMFW_CTL_FLAG_SYS)
|
||||
continue; /* ignore */
|
||||
|
||||
ret = wm_adsp_check_coeff_flags(dsp, &coeff_blk,
|
||||
WMFW_CTL_FLAG_VOLATILE |
|
||||
WMFW_CTL_FLAG_WRITEABLE |
|
||||
WMFW_CTL_FLAG_READABLE,
|
||||
0);
|
||||
if (ret)
|
||||
return -EINVAL;
|
||||
break;
|
||||
case WMFW_CTL_TYPE_HOSTEVENT:
|
||||
ret = wm_adsp_check_coeff_flags(dsp, &coeff_blk,
|
||||
WMFW_CTL_FLAG_SYS |
|
||||
WMFW_CTL_FLAG_VOLATILE |
|
||||
WMFW_CTL_FLAG_WRITEABLE |
|
||||
WMFW_CTL_FLAG_READABLE,
|
||||
0);
|
||||
if (ret)
|
||||
return -EINVAL;
|
||||
break;
|
||||
default:
|
||||
adsp_err(dsp, "Unknown control type: %d\n",
|
||||
coeff_blk.ctl_type);
|
||||
@ -1338,7 +1528,8 @@ static int wm_adsp_parse_coeff(struct wm_adsp *dsp,
|
||||
coeff_blk.len,
|
||||
coeff_blk.name,
|
||||
coeff_blk.name_len,
|
||||
coeff_blk.flags);
|
||||
coeff_blk.flags,
|
||||
coeff_blk.ctl_type);
|
||||
if (ret < 0)
|
||||
adsp_err(dsp, "Failed to create control: %.*s, %d\n",
|
||||
coeff_blk.name_len, coeff_blk.name, ret);
|
||||
@ -1491,23 +1682,11 @@ static int wm_adsp_load(struct wm_adsp *dsp)
|
||||
reg = offset;
|
||||
break;
|
||||
case WMFW_ADSP1_PM:
|
||||
region_name = "PM";
|
||||
reg = wm_adsp_region_to_reg(mem, offset);
|
||||
break;
|
||||
case WMFW_ADSP1_DM:
|
||||
region_name = "DM";
|
||||
reg = wm_adsp_region_to_reg(mem, offset);
|
||||
break;
|
||||
case WMFW_ADSP2_XM:
|
||||
region_name = "XM";
|
||||
reg = wm_adsp_region_to_reg(mem, offset);
|
||||
break;
|
||||
case WMFW_ADSP2_YM:
|
||||
region_name = "YM";
|
||||
reg = wm_adsp_region_to_reg(mem, offset);
|
||||
break;
|
||||
case WMFW_ADSP1_ZM:
|
||||
region_name = "ZM";
|
||||
region_name = wm_adsp_mem_region_name(type);
|
||||
reg = wm_adsp_region_to_reg(mem, offset);
|
||||
break;
|
||||
default:
|
||||
@ -1750,7 +1929,8 @@ static int wm_adsp1_setup_algs(struct wm_adsp *dsp)
|
||||
len -= be32_to_cpu(adsp1_alg[i].dm);
|
||||
len *= 4;
|
||||
wm_adsp_create_control(dsp, alg_region, 0,
|
||||
len, NULL, 0, 0);
|
||||
len, NULL, 0, 0,
|
||||
SNDRV_CTL_ELEM_TYPE_BYTES);
|
||||
} else {
|
||||
adsp_warn(dsp, "Missing length info for region DM with ID %x\n",
|
||||
be32_to_cpu(adsp1_alg[i].alg.id));
|
||||
@ -1770,7 +1950,8 @@ static int wm_adsp1_setup_algs(struct wm_adsp *dsp)
|
||||
len -= be32_to_cpu(adsp1_alg[i].zm);
|
||||
len *= 4;
|
||||
wm_adsp_create_control(dsp, alg_region, 0,
|
||||
len, NULL, 0, 0);
|
||||
len, NULL, 0, 0,
|
||||
SNDRV_CTL_ELEM_TYPE_BYTES);
|
||||
} else {
|
||||
adsp_warn(dsp, "Missing length info for region ZM with ID %x\n",
|
||||
be32_to_cpu(adsp1_alg[i].alg.id));
|
||||
@ -1861,7 +2042,8 @@ static int wm_adsp2_setup_algs(struct wm_adsp *dsp)
|
||||
len -= be32_to_cpu(adsp2_alg[i].xm);
|
||||
len *= 4;
|
||||
wm_adsp_create_control(dsp, alg_region, 0,
|
||||
len, NULL, 0, 0);
|
||||
len, NULL, 0, 0,
|
||||
SNDRV_CTL_ELEM_TYPE_BYTES);
|
||||
} else {
|
||||
adsp_warn(dsp, "Missing length info for region XM with ID %x\n",
|
||||
be32_to_cpu(adsp2_alg[i].alg.id));
|
||||
@ -1881,7 +2063,8 @@ static int wm_adsp2_setup_algs(struct wm_adsp *dsp)
|
||||
len -= be32_to_cpu(adsp2_alg[i].ym);
|
||||
len *= 4;
|
||||
wm_adsp_create_control(dsp, alg_region, 0,
|
||||
len, NULL, 0, 0);
|
||||
len, NULL, 0, 0,
|
||||
SNDRV_CTL_ELEM_TYPE_BYTES);
|
||||
} else {
|
||||
adsp_warn(dsp, "Missing length info for region YM with ID %x\n",
|
||||
be32_to_cpu(adsp2_alg[i].alg.id));
|
||||
@ -1901,7 +2084,8 @@ static int wm_adsp2_setup_algs(struct wm_adsp *dsp)
|
||||
len -= be32_to_cpu(adsp2_alg[i].zm);
|
||||
len *= 4;
|
||||
wm_adsp_create_control(dsp, alg_region, 0,
|
||||
len, NULL, 0, 0);
|
||||
len, NULL, 0, 0,
|
||||
SNDRV_CTL_ELEM_TYPE_BYTES);
|
||||
} else {
|
||||
adsp_warn(dsp, "Missing length info for region ZM with ID %x\n",
|
||||
be32_to_cpu(adsp2_alg[i].alg.id));
|
||||
@ -2114,7 +2298,7 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,
|
||||
int ret;
|
||||
unsigned int val;
|
||||
|
||||
dsp->card = codec->component.card;
|
||||
dsp->codec = codec;
|
||||
|
||||
mutex_lock(&dsp->pwr_lock);
|
||||
|
||||
@ -2325,8 +2509,6 @@ int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
|
||||
struct wm_adsp *dsp = &dsps[w->shift];
|
||||
struct wm_coeff_ctl *ctl;
|
||||
|
||||
dsp->card = codec->component.card;
|
||||
|
||||
switch (event) {
|
||||
case SND_SOC_DAPM_PRE_PMU:
|
||||
wm_adsp2_set_dspclk(dsp, freq);
|
||||
@ -2393,14 +2575,22 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
|
||||
|
||||
mutex_lock(&dsp->pwr_lock);
|
||||
|
||||
if (wm_adsp_fw[dsp->fw].num_caps != 0)
|
||||
if (wm_adsp_fw[dsp->fw].num_caps != 0) {
|
||||
ret = wm_adsp_buffer_init(dsp);
|
||||
if (ret < 0) {
|
||||
mutex_unlock(&dsp->pwr_lock);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&dsp->pwr_lock);
|
||||
|
||||
break;
|
||||
|
||||
case SND_SOC_DAPM_PRE_PMD:
|
||||
/* Tell the firmware to cleanup */
|
||||
wm_adsp_signal_event_controls(dsp, WM_ADSP_FW_EVENT_SHUTDOWN);
|
||||
|
||||
/* Log firmware state, it can be useful for analysis */
|
||||
wm_adsp2_show_fw_status(dsp);
|
||||
|
||||
@ -2441,6 +2631,8 @@ EXPORT_SYMBOL_GPL(wm_adsp2_event);
|
||||
|
||||
int wm_adsp2_codec_probe(struct wm_adsp *dsp, struct snd_soc_codec *codec)
|
||||
{
|
||||
dsp->codec = codec;
|
||||
|
||||
wm_adsp2_init_debugfs(dsp, codec);
|
||||
|
||||
return snd_soc_add_codec_controls(codec,
|
||||
|
@ -44,7 +44,7 @@ struct wm_adsp {
|
||||
int type;
|
||||
struct device *dev;
|
||||
struct regmap *regmap;
|
||||
struct snd_soc_card *card;
|
||||
struct snd_soc_codec *codec;
|
||||
|
||||
int base;
|
||||
int sysclk_reg;
|
||||
@ -110,18 +110,17 @@ int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
|
||||
int wm_adsp2_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event);
|
||||
|
||||
extern int wm_adsp_compr_open(struct wm_adsp *dsp,
|
||||
struct snd_compr_stream *stream);
|
||||
extern int wm_adsp_compr_free(struct snd_compr_stream *stream);
|
||||
extern int wm_adsp_compr_set_params(struct snd_compr_stream *stream,
|
||||
struct snd_compr_params *params);
|
||||
extern int wm_adsp_compr_get_caps(struct snd_compr_stream *stream,
|
||||
struct snd_compr_caps *caps);
|
||||
extern int wm_adsp_compr_trigger(struct snd_compr_stream *stream, int cmd);
|
||||
extern int wm_adsp_compr_handle_irq(struct wm_adsp *dsp);
|
||||
extern int wm_adsp_compr_pointer(struct snd_compr_stream *stream,
|
||||
struct snd_compr_tstamp *tstamp);
|
||||
extern int wm_adsp_compr_copy(struct snd_compr_stream *stream,
|
||||
char __user *buf, size_t count);
|
||||
int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream);
|
||||
int wm_adsp_compr_free(struct snd_compr_stream *stream);
|
||||
int wm_adsp_compr_set_params(struct snd_compr_stream *stream,
|
||||
struct snd_compr_params *params);
|
||||
int wm_adsp_compr_get_caps(struct snd_compr_stream *stream,
|
||||
struct snd_compr_caps *caps);
|
||||
int wm_adsp_compr_trigger(struct snd_compr_stream *stream, int cmd);
|
||||
int wm_adsp_compr_handle_irq(struct wm_adsp *dsp);
|
||||
int wm_adsp_compr_pointer(struct snd_compr_stream *stream,
|
||||
struct snd_compr_tstamp *tstamp);
|
||||
int wm_adsp_compr_copy(struct snd_compr_stream *stream,
|
||||
char __user *buf, size_t count);
|
||||
|
||||
#endif
|
||||
|
@ -26,6 +26,10 @@
|
||||
#define WMFW_CTL_FLAG_WRITEABLE 0x0002
|
||||
#define WMFW_CTL_FLAG_READABLE 0x0001
|
||||
|
||||
/* Non-ALSA coefficient types start at 0x1000 */
|
||||
#define WMFW_CTL_TYPE_ACKED 0x1000 /* acked control */
|
||||
#define WMFW_CTL_TYPE_HOSTEVENT 0x1001 /* event control */
|
||||
|
||||
struct wmfw_header {
|
||||
char magic[4];
|
||||
__le32 len;
|
||||
|
Loading…
Reference in New Issue
Block a user