Merge remote-tracking branches 'asoc/topic/adau', 'asoc/topic/adau7002', 'asoc/topic/adsp', 'asoc/topic/ak4613' and 'asoc/topic/ak4642' into asoc-next
This commit is contained in:
Коммит
72a04d6b60
|
@ -13,6 +13,11 @@ Required properties:
|
|||
- reg: The i2c address. Value depends on the state of ADDR0
|
||||
and ADDR1, as wired in hardware.
|
||||
|
||||
Optional properties:
|
||||
- clock-names: If provided must be "mclk".
|
||||
- clocks: phandle + clock-specifiers for the clock that provides
|
||||
the audio master clock for the device.
|
||||
|
||||
Examples:
|
||||
#include <dt-bindings/sound/adau17x1.h>
|
||||
|
||||
|
@ -20,5 +25,8 @@ Examples:
|
|||
adau1361@38 {
|
||||
compatible = "adi,adau1761";
|
||||
reg = <0x38>;
|
||||
|
||||
clock-names = "mclk";
|
||||
clocks = <&audio_clock>;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
Analog Devices ADAU7002 Stereo PDM-to-I2S/TDM Converter
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: Must be "adi,adau7002"
|
||||
|
||||
Optional properties:
|
||||
|
||||
- IOVDD-supply: Phandle and specifier for the power supply providing the IOVDD
|
||||
supply as covered in Documentation/devicetree/bindings/regulator/regulator.txt
|
||||
|
||||
If this property is not present it is assumed that the supply pin is
|
||||
hardwired to always on.
|
||||
|
||||
Example:
|
||||
adau7002: pdm-to-i2s {
|
||||
compatible = "adi,adau7002";
|
||||
IOVDD-supply = <&supply>;
|
||||
};
|
|
@ -14,6 +14,7 @@
|
|||
#define _WM_ARIZONA_CORE_H
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/mfd/arizona/pdata.h>
|
||||
|
@ -148,8 +149,17 @@ struct arizona {
|
|||
uint16_t dac_comp_coeff;
|
||||
uint8_t dac_comp_enabled;
|
||||
struct mutex dac_comp_lock;
|
||||
|
||||
struct blocking_notifier_head notifier;
|
||||
};
|
||||
|
||||
static inline int arizona_call_notifiers(struct arizona *arizona,
|
||||
unsigned long event,
|
||||
void *data)
|
||||
{
|
||||
return blocking_notifier_call_chain(&arizona->notifier, event, data);
|
||||
}
|
||||
|
||||
int arizona_clk32k_enable(struct arizona *arizona);
|
||||
int arizona_clk32k_disable(struct arizona *arizona);
|
||||
|
||||
|
|
|
@ -68,6 +68,7 @@ struct snd_compr_runtime {
|
|||
* @ops: pointer to DSP callbacks
|
||||
* @runtime: pointer to runtime structure
|
||||
* @device: device pointer
|
||||
* @error_work: delayed work used when closing the stream due to an error
|
||||
* @direction: stream direction, playback/recording
|
||||
* @metadata_set: metadata set flag, true when set
|
||||
* @next_track: has userspace signal next track transition, true when set
|
||||
|
@ -78,6 +79,7 @@ struct snd_compr_stream {
|
|||
struct snd_compr_ops *ops;
|
||||
struct snd_compr_runtime *runtime;
|
||||
struct snd_compr *device;
|
||||
struct delayed_work error_work;
|
||||
enum snd_compr_direction direction;
|
||||
bool metadata_set;
|
||||
bool next_track;
|
||||
|
@ -187,4 +189,7 @@ static inline void snd_compr_drain_notify(struct snd_compr_stream *stream)
|
|||
wake_up(&stream->runtime->sleep);
|
||||
}
|
||||
|
||||
int snd_compr_stop_error(struct snd_compr_stream *stream,
|
||||
snd_pcm_state_t state);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -67,6 +67,8 @@ struct snd_compr_file {
|
|||
struct snd_compr_stream stream;
|
||||
};
|
||||
|
||||
static void error_delayed_work(struct work_struct *work);
|
||||
|
||||
/*
|
||||
* a note on stream states used:
|
||||
* we use following states in the compressed core
|
||||
|
@ -123,6 +125,9 @@ static int snd_compr_open(struct inode *inode, struct file *f)
|
|||
snd_card_unref(compr->card);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
INIT_DELAYED_WORK(&data->stream.error_work, error_delayed_work);
|
||||
|
||||
data->stream.ops = compr->ops;
|
||||
data->stream.direction = dirn;
|
||||
data->stream.private_data = compr->private_data;
|
||||
|
@ -153,6 +158,8 @@ static int snd_compr_free(struct inode *inode, struct file *f)
|
|||
struct snd_compr_file *data = f->private_data;
|
||||
struct snd_compr_runtime *runtime = data->stream.runtime;
|
||||
|
||||
cancel_delayed_work_sync(&data->stream.error_work);
|
||||
|
||||
switch (runtime->state) {
|
||||
case SNDRV_PCM_STATE_RUNNING:
|
||||
case SNDRV_PCM_STATE_DRAINING:
|
||||
|
@ -237,6 +244,15 @@ snd_compr_ioctl_avail(struct snd_compr_stream *stream, unsigned long arg)
|
|||
avail = snd_compr_calc_avail(stream, &ioctl_avail);
|
||||
ioctl_avail.avail = avail;
|
||||
|
||||
switch (stream->runtime->state) {
|
||||
case SNDRV_PCM_STATE_OPEN:
|
||||
return -EBADFD;
|
||||
case SNDRV_PCM_STATE_XRUN:
|
||||
return -EPIPE;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (copy_to_user((__u64 __user *)arg,
|
||||
&ioctl_avail, sizeof(ioctl_avail)))
|
||||
return -EFAULT;
|
||||
|
@ -346,11 +362,13 @@ static ssize_t snd_compr_read(struct file *f, char __user *buf,
|
|||
switch (stream->runtime->state) {
|
||||
case SNDRV_PCM_STATE_OPEN:
|
||||
case SNDRV_PCM_STATE_PREPARED:
|
||||
case SNDRV_PCM_STATE_XRUN:
|
||||
case SNDRV_PCM_STATE_SUSPENDED:
|
||||
case SNDRV_PCM_STATE_DISCONNECTED:
|
||||
retval = -EBADFD;
|
||||
goto out;
|
||||
case SNDRV_PCM_STATE_XRUN:
|
||||
retval = -EPIPE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
avail = snd_compr_get_avail(stream);
|
||||
|
@ -399,10 +417,16 @@ static unsigned int snd_compr_poll(struct file *f, poll_table *wait)
|
|||
stream = &data->stream;
|
||||
|
||||
mutex_lock(&stream->device->lock);
|
||||
if (stream->runtime->state == SNDRV_PCM_STATE_OPEN) {
|
||||
|
||||
switch (stream->runtime->state) {
|
||||
case SNDRV_PCM_STATE_OPEN:
|
||||
case SNDRV_PCM_STATE_XRUN:
|
||||
retval = snd_compr_get_poll(stream) | POLLERR;
|
||||
goto out;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
poll_wait(f, &stream->runtime->sleep, wait);
|
||||
|
||||
avail = snd_compr_get_avail(stream);
|
||||
|
@ -697,6 +721,45 @@ static int snd_compr_stop(struct snd_compr_stream *stream)
|
|||
return retval;
|
||||
}
|
||||
|
||||
static void error_delayed_work(struct work_struct *work)
|
||||
{
|
||||
struct snd_compr_stream *stream;
|
||||
|
||||
stream = container_of(work, struct snd_compr_stream, error_work.work);
|
||||
|
||||
mutex_lock(&stream->device->lock);
|
||||
|
||||
stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_STOP);
|
||||
wake_up(&stream->runtime->sleep);
|
||||
|
||||
mutex_unlock(&stream->device->lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* snd_compr_stop_error: Report a fatal error on a stream
|
||||
* @stream: pointer to stream
|
||||
* @state: state to transition the stream to
|
||||
*
|
||||
* Stop the stream and set its state.
|
||||
*
|
||||
* Should be called with compressed device lock held.
|
||||
*/
|
||||
int snd_compr_stop_error(struct snd_compr_stream *stream,
|
||||
snd_pcm_state_t state)
|
||||
{
|
||||
if (stream->runtime->state == state)
|
||||
return 0;
|
||||
|
||||
stream->runtime->state = state;
|
||||
|
||||
pr_debug("Changing state to: %d\n", state);
|
||||
|
||||
queue_delayed_work(system_power_efficient_wq, &stream->error_work, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_compr_stop_error);
|
||||
|
||||
static int snd_compress_wait_for_drain(struct snd_compr_stream *stream)
|
||||
{
|
||||
int ret;
|
||||
|
|
|
@ -32,6 +32,7 @@ config SND_SOC_ALL_CODECS
|
|||
select SND_SOC_ADAU1977_SPI if SPI_MASTER
|
||||
select SND_SOC_ADAU1977_I2C if I2C
|
||||
select SND_SOC_ADAU1701 if I2C
|
||||
select SND_SOC_ADAU7002
|
||||
select SND_SOC_ADS117X
|
||||
select SND_SOC_AK4104 if SPI_MASTER
|
||||
select SND_SOC_AK4535 if I2C
|
||||
|
@ -269,8 +270,12 @@ config SND_SOC_AD1980
|
|||
config SND_SOC_AD73311
|
||||
tristate
|
||||
|
||||
config SND_SOC_ADAU_UTILS
|
||||
tristate
|
||||
|
||||
config SND_SOC_ADAU1373
|
||||
tristate
|
||||
select SND_SOC_ADAU_UTILS
|
||||
|
||||
config SND_SOC_ADAU1701
|
||||
tristate "Analog Devices ADAU1701 CODEC"
|
||||
|
@ -280,6 +285,7 @@ config SND_SOC_ADAU1701
|
|||
config SND_SOC_ADAU17X1
|
||||
tristate
|
||||
select SND_SOC_SIGMADSP_REGMAP
|
||||
select SND_SOC_ADAU_UTILS
|
||||
|
||||
config SND_SOC_ADAU1761
|
||||
tristate
|
||||
|
@ -322,6 +328,9 @@ config SND_SOC_ADAU1977_I2C
|
|||
select SND_SOC_ADAU1977
|
||||
select REGMAP_I2C
|
||||
|
||||
config SND_SOC_ADAU7002
|
||||
tristate "Analog Devices ADAU7002 Stereo PDM-to-I2S/TDM Converter"
|
||||
|
||||
config SND_SOC_ADAV80X
|
||||
tristate
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ snd-soc-ad193x-spi-objs := ad193x-spi.o
|
|||
snd-soc-ad193x-i2c-objs := ad193x-i2c.o
|
||||
snd-soc-ad1980-objs := ad1980.o
|
||||
snd-soc-ad73311-objs := ad73311.o
|
||||
snd-soc-adau-utils-objs := adau-utils.o
|
||||
snd-soc-adau1373-objs := adau1373.o
|
||||
snd-soc-adau1701-objs := adau1701.o
|
||||
snd-soc-adau17x1-objs := adau17x1.o
|
||||
|
@ -19,6 +20,7 @@ snd-soc-adau1781-spi-objs := adau1781-spi.o
|
|||
snd-soc-adau1977-objs := adau1977.o
|
||||
snd-soc-adau1977-spi-objs := adau1977-spi.o
|
||||
snd-soc-adau1977-i2c-objs := adau1977-i2c.o
|
||||
snd-soc-adau7002-objs := adau7002.o
|
||||
snd-soc-adav80x-objs := adav80x.o
|
||||
snd-soc-adav801-objs := adav801.o
|
||||
snd-soc-adav803-objs := adav803.o
|
||||
|
@ -220,6 +222,7 @@ obj-$(CONFIG_SND_SOC_AD193X_SPI) += snd-soc-ad193x-spi.o
|
|||
obj-$(CONFIG_SND_SOC_AD193X_I2C) += snd-soc-ad193x-i2c.o
|
||||
obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o
|
||||
obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o
|
||||
obj-$(CONFIG_SND_SOC_ADAU_UTILS) += snd-soc-adau-utils.o
|
||||
obj-$(CONFIG_SND_SOC_ADAU1373) += snd-soc-adau1373.o
|
||||
obj-$(CONFIG_SND_SOC_ADAU1701) += snd-soc-adau1701.o
|
||||
obj-$(CONFIG_SND_SOC_ADAU17X1) += snd-soc-adau17x1.o
|
||||
|
@ -232,6 +235,7 @@ obj-$(CONFIG_SND_SOC_ADAU1781_SPI) += snd-soc-adau1781-spi.o
|
|||
obj-$(CONFIG_SND_SOC_ADAU1977) += snd-soc-adau1977.o
|
||||
obj-$(CONFIG_SND_SOC_ADAU1977_SPI) += snd-soc-adau1977-spi.o
|
||||
obj-$(CONFIG_SND_SOC_ADAU1977_I2C) += snd-soc-adau1977-i2c.o
|
||||
obj-$(CONFIG_SND_SOC_ADAU7002) += snd-soc-adau7002.o
|
||||
obj-$(CONFIG_SND_SOC_ADAV80X) += snd-soc-adav80x.o
|
||||
obj-$(CONFIG_SND_SOC_ADAV801) += snd-soc-adav801.o
|
||||
obj-$(CONFIG_SND_SOC_ADAV803) += snd-soc-adav803.o
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Shared helper functions for devices from the ADAU family
|
||||
*
|
||||
* Copyright 2011-2016 Analog Devices Inc.
|
||||
* Author: Lars-Peter Clausen <lars@metafoo.de>
|
||||
*
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#include <linux/gcd.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "adau-utils.h"
|
||||
|
||||
int adau_calc_pll_cfg(unsigned int freq_in, unsigned int freq_out,
|
||||
uint8_t regs[5])
|
||||
{
|
||||
unsigned int r, n, m, i, j;
|
||||
unsigned int div;
|
||||
|
||||
if (!freq_out) {
|
||||
r = 0;
|
||||
n = 0;
|
||||
m = 0;
|
||||
div = 0;
|
||||
} else {
|
||||
if (freq_out % freq_in != 0) {
|
||||
div = DIV_ROUND_UP(freq_in, 13500000);
|
||||
freq_in /= div;
|
||||
r = freq_out / freq_in;
|
||||
i = freq_out % freq_in;
|
||||
j = gcd(i, freq_in);
|
||||
n = i / j;
|
||||
m = freq_in / j;
|
||||
div--;
|
||||
} else {
|
||||
r = freq_out / freq_in;
|
||||
n = 0;
|
||||
m = 0;
|
||||
div = 0;
|
||||
}
|
||||
if (n > 0xffff || m > 0xffff || div > 3 || r > 8 || r < 2)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
regs[0] = m >> 8;
|
||||
regs[1] = m & 0xff;
|
||||
regs[2] = n >> 8;
|
||||
regs[3] = n & 0xff;
|
||||
regs[4] = (r << 3) | (div << 1);
|
||||
if (m != 0)
|
||||
regs[4] |= 1; /* Fractional mode */
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(adau_calc_pll_cfg);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC ADAU audio CODECs shared helper functions");
|
||||
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef SOUND_SOC_CODECS_ADAU_PLL_H
|
||||
#define SOUND_SOC_CODECS_ADAU_PLL_H
|
||||
|
||||
int adau_calc_pll_cfg(unsigned int freq_in, unsigned int freq_out,
|
||||
uint8_t regs[5]);
|
||||
|
||||
#endif
|
|
@ -23,6 +23,7 @@
|
|||
#include <sound/adau1373.h>
|
||||
|
||||
#include "adau1373.h"
|
||||
#include "adau-utils.h"
|
||||
|
||||
struct adau1373_dai {
|
||||
unsigned int clk_src;
|
||||
|
@ -1254,7 +1255,8 @@ static int adau1373_set_pll(struct snd_soc_codec *codec, int pll_id,
|
|||
{
|
||||
struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int dpll_div = 0;
|
||||
unsigned int x, r, n, m, i, j, mode;
|
||||
uint8_t pll_regs[5];
|
||||
int ret;
|
||||
|
||||
switch (pll_id) {
|
||||
case ADAU1373_PLL1:
|
||||
|
@ -1295,27 +1297,8 @@ static int adau1373_set_pll(struct snd_soc_codec *codec, int pll_id,
|
|||
dpll_div++;
|
||||
}
|
||||
|
||||
if (freq_out % freq_in != 0) {
|
||||
/* fout = fin * (r + (n/m)) / x */
|
||||
x = DIV_ROUND_UP(freq_in, 13500000);
|
||||
freq_in /= x;
|
||||
r = freq_out / freq_in;
|
||||
i = freq_out % freq_in;
|
||||
j = gcd(i, freq_in);
|
||||
n = i / j;
|
||||
m = freq_in / j;
|
||||
x--;
|
||||
mode = 1;
|
||||
} else {
|
||||
/* fout = fin / r */
|
||||
r = freq_out / freq_in;
|
||||
n = 0;
|
||||
m = 0;
|
||||
x = 0;
|
||||
mode = 0;
|
||||
}
|
||||
|
||||
if (r < 2 || r > 8 || x > 3 || m > 0xffff || n > 0xffff)
|
||||
ret = adau_calc_pll_cfg(freq_in, freq_out, pll_regs);
|
||||
if (ret)
|
||||
return -EINVAL;
|
||||
|
||||
if (dpll_div) {
|
||||
|
@ -1330,12 +1313,11 @@ static int adau1373_set_pll(struct snd_soc_codec *codec, int pll_id,
|
|||
|
||||
regmap_write(adau1373->regmap, ADAU1373_DPLL_CTRL(pll_id),
|
||||
(source << 4) | dpll_div);
|
||||
regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL1(pll_id), (m >> 8) & 0xff);
|
||||
regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL2(pll_id), m & 0xff);
|
||||
regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL3(pll_id), (n >> 8) & 0xff);
|
||||
regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL4(pll_id), n & 0xff);
|
||||
regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL5(pll_id),
|
||||
(r << 3) | (x << 1) | mode);
|
||||
regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL1(pll_id), pll_regs[0]);
|
||||
regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL2(pll_id), pll_regs[1]);
|
||||
regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL3(pll_id), pll_regs[2]);
|
||||
regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL4(pll_id), pll_regs[3]);
|
||||
regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL5(pll_id), pll_regs[4]);
|
||||
|
||||
/* Set sysclk to pll_rate / 4 */
|
||||
regmap_update_bits(adau1373->regmap, ADAU1373_CLK_SRC_DIV(pll_id), 0x3f, 0x09);
|
||||
|
|
|
@ -31,7 +31,7 @@ static int adau1761_i2c_probe(struct i2c_client *client,
|
|||
|
||||
static int adau1761_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
snd_soc_unregister_codec(&client->dev);
|
||||
adau17x1_remove(&client->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ static int adau1761_spi_probe(struct spi_device *spi)
|
|||
|
||||
static int adau1761_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
snd_soc_unregister_codec(&spi->dev);
|
||||
adau17x1_remove(&spi->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ static int adau1781_i2c_probe(struct i2c_client *client,
|
|||
|
||||
static int adau1781_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
snd_soc_unregister_codec(&client->dev);
|
||||
adau17x1_remove(&client->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ static int adau1781_spi_probe(struct spi_device *spi)
|
|||
|
||||
static int adau1781_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
snd_soc_unregister_codec(&spi->dev);
|
||||
adau17x1_remove(&spi->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <sound/core.h>
|
||||
|
@ -23,6 +24,7 @@
|
|||
|
||||
#include "sigmadsp.h"
|
||||
#include "adau17x1.h"
|
||||
#include "adau-utils.h"
|
||||
|
||||
static const char * const adau17x1_capture_mixer_boost_text[] = {
|
||||
"Normal operation", "Boost Level 1", "Boost Level 2", "Boost Level 3",
|
||||
|
@ -302,6 +304,116 @@ bool adau17x1_has_dsp(struct adau *adau)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(adau17x1_has_dsp);
|
||||
|
||||
static int adau17x1_set_dai_pll(struct snd_soc_dai *dai, int pll_id,
|
||||
int source, unsigned int freq_in, unsigned int freq_out)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct adau *adau = snd_soc_codec_get_drvdata(codec);
|
||||
int ret;
|
||||
|
||||
if (freq_in < 8000000 || freq_in > 27000000)
|
||||
return -EINVAL;
|
||||
|
||||
ret = adau_calc_pll_cfg(freq_in, freq_out, adau->pll_regs);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* The PLL register is 6 bytes long and can only be written at once. */
|
||||
ret = regmap_raw_write(adau->regmap, ADAU17X1_PLL_CONTROL,
|
||||
adau->pll_regs, ARRAY_SIZE(adau->pll_regs));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
adau->pll_freq = freq_out;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adau17x1_set_dai_sysclk(struct snd_soc_dai *dai,
|
||||
int clk_id, unsigned int freq, int dir)
|
||||
{
|
||||
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(dai->codec);
|
||||
struct adau *adau = snd_soc_codec_get_drvdata(dai->codec);
|
||||
bool is_pll;
|
||||
bool was_pll;
|
||||
|
||||
switch (clk_id) {
|
||||
case ADAU17X1_CLK_SRC_MCLK:
|
||||
is_pll = false;
|
||||
break;
|
||||
case ADAU17X1_CLK_SRC_PLL_AUTO:
|
||||
if (!adau->mclk)
|
||||
return -EINVAL;
|
||||
/* Fall-through */
|
||||
case ADAU17X1_CLK_SRC_PLL:
|
||||
is_pll = true;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (adau->clk_src) {
|
||||
case ADAU17X1_CLK_SRC_MCLK:
|
||||
was_pll = false;
|
||||
break;
|
||||
case ADAU17X1_CLK_SRC_PLL:
|
||||
case ADAU17X1_CLK_SRC_PLL_AUTO:
|
||||
was_pll = true;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
adau->sysclk = freq;
|
||||
|
||||
if (is_pll != was_pll) {
|
||||
if (is_pll) {
|
||||
snd_soc_dapm_add_routes(dapm,
|
||||
&adau17x1_dapm_pll_route, 1);
|
||||
} else {
|
||||
snd_soc_dapm_del_routes(dapm,
|
||||
&adau17x1_dapm_pll_route, 1);
|
||||
}
|
||||
}
|
||||
|
||||
adau->clk_src = clk_id;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adau17x1_auto_pll(struct snd_soc_dai *dai,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct adau *adau = snd_soc_dai_get_drvdata(dai);
|
||||
unsigned int pll_rate;
|
||||
|
||||
switch (params_rate(params)) {
|
||||
case 48000:
|
||||
case 8000:
|
||||
case 12000:
|
||||
case 16000:
|
||||
case 24000:
|
||||
case 32000:
|
||||
case 96000:
|
||||
pll_rate = 48000 * 1024;
|
||||
break;
|
||||
case 44100:
|
||||
case 7350:
|
||||
case 11025:
|
||||
case 14700:
|
||||
case 22050:
|
||||
case 29400:
|
||||
case 88200:
|
||||
pll_rate = 44100 * 1024;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return adau17x1_set_dai_pll(dai, ADAU17X1_PLL, ADAU17X1_PLL_SRC_MCLK,
|
||||
clk_get_rate(adau->mclk), pll_rate);
|
||||
}
|
||||
|
||||
static int adau17x1_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
|
||||
{
|
||||
|
@ -311,10 +423,19 @@ static int adau17x1_hw_params(struct snd_pcm_substream *substream,
|
|||
unsigned int freq;
|
||||
int ret;
|
||||
|
||||
if (adau->clk_src == ADAU17X1_CLK_SRC_PLL)
|
||||
switch (adau->clk_src) {
|
||||
case ADAU17X1_CLK_SRC_PLL_AUTO:
|
||||
ret = adau17x1_auto_pll(dai, params);
|
||||
if (ret)
|
||||
return ret;
|
||||
/* Fall-through */
|
||||
case ADAU17X1_CLK_SRC_PLL:
|
||||
freq = adau->pll_freq;
|
||||
else
|
||||
break;
|
||||
default:
|
||||
freq = adau->sysclk;
|
||||
break;
|
||||
}
|
||||
|
||||
if (freq % params_rate(params) != 0)
|
||||
return -EINVAL;
|
||||
|
@ -386,93 +507,6 @@ static int adau17x1_hw_params(struct snd_pcm_substream *substream,
|
|||
ADAU17X1_SERIAL_PORT1_DELAY_MASK, val);
|
||||
}
|
||||
|
||||
static int adau17x1_set_dai_pll(struct snd_soc_dai *dai, int pll_id,
|
||||
int source, unsigned int freq_in, unsigned int freq_out)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct adau *adau = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int r, n, m, i, j;
|
||||
unsigned int div;
|
||||
int ret;
|
||||
|
||||
if (freq_in < 8000000 || freq_in > 27000000)
|
||||
return -EINVAL;
|
||||
|
||||
if (!freq_out) {
|
||||
r = 0;
|
||||
n = 0;
|
||||
m = 0;
|
||||
div = 0;
|
||||
} else {
|
||||
if (freq_out % freq_in != 0) {
|
||||
div = DIV_ROUND_UP(freq_in, 13500000);
|
||||
freq_in /= div;
|
||||
r = freq_out / freq_in;
|
||||
i = freq_out % freq_in;
|
||||
j = gcd(i, freq_in);
|
||||
n = i / j;
|
||||
m = freq_in / j;
|
||||
div--;
|
||||
} else {
|
||||
r = freq_out / freq_in;
|
||||
n = 0;
|
||||
m = 0;
|
||||
div = 0;
|
||||
}
|
||||
if (n > 0xffff || m > 0xffff || div > 3 || r > 8 || r < 2)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
adau->pll_regs[0] = m >> 8;
|
||||
adau->pll_regs[1] = m & 0xff;
|
||||
adau->pll_regs[2] = n >> 8;
|
||||
adau->pll_regs[3] = n & 0xff;
|
||||
adau->pll_regs[4] = (r << 3) | (div << 1);
|
||||
if (m != 0)
|
||||
adau->pll_regs[4] |= 1; /* Fractional mode */
|
||||
|
||||
/* The PLL register is 6 bytes long and can only be written at once. */
|
||||
ret = regmap_raw_write(adau->regmap, ADAU17X1_PLL_CONTROL,
|
||||
adau->pll_regs, ARRAY_SIZE(adau->pll_regs));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
adau->pll_freq = freq_out;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adau17x1_set_dai_sysclk(struct snd_soc_dai *dai,
|
||||
int clk_id, unsigned int freq, int dir)
|
||||
{
|
||||
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(dai->codec);
|
||||
struct adau *adau = snd_soc_codec_get_drvdata(dai->codec);
|
||||
|
||||
switch (clk_id) {
|
||||
case ADAU17X1_CLK_SRC_MCLK:
|
||||
case ADAU17X1_CLK_SRC_PLL:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
adau->sysclk = freq;
|
||||
|
||||
if (adau->clk_src != clk_id) {
|
||||
if (clk_id == ADAU17X1_CLK_SRC_PLL) {
|
||||
snd_soc_dapm_add_routes(dapm,
|
||||
&adau17x1_dapm_pll_route, 1);
|
||||
} else {
|
||||
snd_soc_dapm_del_routes(dapm,
|
||||
&adau17x1_dapm_pll_route, 1);
|
||||
}
|
||||
}
|
||||
|
||||
adau->clk_src = clk_id;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adau17x1_set_dai_fmt(struct snd_soc_dai *dai,
|
||||
unsigned int fmt)
|
||||
{
|
||||
|
@ -857,6 +891,10 @@ int adau17x1_add_routes(struct snd_soc_codec *codec)
|
|||
ret = snd_soc_dapm_add_routes(dapm, adau17x1_no_dsp_dapm_routes,
|
||||
ARRAY_SIZE(adau17x1_no_dsp_dapm_routes));
|
||||
}
|
||||
|
||||
if (adau->clk_src != ADAU17X1_CLK_SRC_MCLK)
|
||||
snd_soc_dapm_add_routes(dapm, &adau17x1_dapm_pll_route, 1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(adau17x1_add_routes);
|
||||
|
@ -879,6 +917,7 @@ int adau17x1_probe(struct device *dev, struct regmap *regmap,
|
|||
const char *firmware_name)
|
||||
{
|
||||
struct adau *adau;
|
||||
int ret;
|
||||
|
||||
if (IS_ERR(regmap))
|
||||
return PTR_ERR(regmap);
|
||||
|
@ -887,6 +926,30 @@ int adau17x1_probe(struct device *dev, struct regmap *regmap,
|
|||
if (!adau)
|
||||
return -ENOMEM;
|
||||
|
||||
adau->mclk = devm_clk_get(dev, "mclk");
|
||||
if (IS_ERR(adau->mclk)) {
|
||||
if (PTR_ERR(adau->mclk) != -ENOENT)
|
||||
return PTR_ERR(adau->mclk);
|
||||
/* Clock is optional (for the driver) */
|
||||
adau->mclk = NULL;
|
||||
} else if (adau->mclk) {
|
||||
adau->clk_src = ADAU17X1_CLK_SRC_PLL_AUTO;
|
||||
|
||||
/*
|
||||
* Any valid PLL output rate will work at this point, use one
|
||||
* that is likely to be chosen later as well. The register will
|
||||
* be written when the PLL is powered up for the first time.
|
||||
*/
|
||||
ret = adau_calc_pll_cfg(clk_get_rate(adau->mclk), 48000 * 1024,
|
||||
adau->pll_regs);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = clk_prepare_enable(adau->mclk);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
adau->regmap = regmap;
|
||||
adau->switch_mode = switch_mode;
|
||||
adau->type = type;
|
||||
|
@ -910,6 +973,16 @@ int adau17x1_probe(struct device *dev, struct regmap *regmap,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(adau17x1_probe);
|
||||
|
||||
void adau17x1_remove(struct device *dev)
|
||||
{
|
||||
struct adau *adau = dev_get_drvdata(dev);
|
||||
|
||||
snd_soc_unregister_codec(dev);
|
||||
if (adau->mclk)
|
||||
clk_disable_unprepare(adau->mclk);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(adau17x1_remove);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC ADAU1X61/ADAU1X81 common code");
|
||||
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -22,13 +22,18 @@ enum adau17x1_pll_src {
|
|||
};
|
||||
|
||||
enum adau17x1_clk_src {
|
||||
/* Automatically configure PLL based on the sample rate */
|
||||
ADAU17X1_CLK_SRC_PLL_AUTO,
|
||||
ADAU17X1_CLK_SRC_MCLK,
|
||||
ADAU17X1_CLK_SRC_PLL,
|
||||
};
|
||||
|
||||
struct clk;
|
||||
|
||||
struct adau {
|
||||
unsigned int sysclk;
|
||||
unsigned int pll_freq;
|
||||
struct clk *mclk;
|
||||
|
||||
enum adau17x1_clk_src clk_src;
|
||||
enum adau17x1_type type;
|
||||
|
@ -52,6 +57,7 @@ int adau17x1_add_routes(struct snd_soc_codec *codec);
|
|||
int adau17x1_probe(struct device *dev, struct regmap *regmap,
|
||||
enum adau17x1_type type, void (*switch_mode)(struct device *dev),
|
||||
const char *firmware_name);
|
||||
void adau17x1_remove(struct device *dev);
|
||||
int adau17x1_set_micbias_voltage(struct snd_soc_codec *codec,
|
||||
enum adau17x1_micbias_voltage micbias);
|
||||
bool adau17x1_readable_register(struct device *dev, unsigned int reg);
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* ADAU7002 Stereo PDM-to-I2S/TDM converter driver
|
||||
*
|
||||
* Copyright 2014-2016 Analog Devices
|
||||
* Author: Lars-Peter Clausen <lars@metafoo.de>
|
||||
*
|
||||
* Licensed under the GPL-2.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <sound/soc.h>
|
||||
|
||||
static const struct snd_soc_dapm_widget adau7002_widgets[] = {
|
||||
SND_SOC_DAPM_INPUT("PDM_DAT"),
|
||||
SND_SOC_DAPM_REGULATOR_SUPPLY("IOVDD", 0, 0),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route adau7002_routes[] = {
|
||||
{ "Capture", NULL, "PDM_DAT" },
|
||||
{ "Capture", NULL, "IOVDD" },
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver adau7002_dai = {
|
||||
.name = "adau7002-hifi",
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.rates = SNDRV_PCM_RATE_8000_96000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE |
|
||||
SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE |
|
||||
SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE,
|
||||
.sig_bits = 20,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct snd_soc_codec_driver adau7002_codec_driver = {
|
||||
.dapm_widgets = adau7002_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(adau7002_widgets),
|
||||
.dapm_routes = adau7002_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(adau7002_routes),
|
||||
};
|
||||
|
||||
static int adau7002_probe(struct platform_device *pdev)
|
||||
{
|
||||
return snd_soc_register_codec(&pdev->dev, &adau7002_codec_driver,
|
||||
&adau7002_dai, 1);
|
||||
}
|
||||
|
||||
static int adau7002_remove(struct platform_device *pdev)
|
||||
{
|
||||
snd_soc_unregister_codec(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id adau7002_dt_ids[] = {
|
||||
{ .compatible = "adi,adau7002", },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, adau7002_dt_ids);
|
||||
#endif
|
||||
|
||||
static struct platform_driver adau7002_driver = {
|
||||
.driver = {
|
||||
.name = "adau7002",
|
||||
.of_match_table = of_match_ptr(adau7002_dt_ids),
|
||||
},
|
||||
.probe = adau7002_probe,
|
||||
.remove = adau7002_remove,
|
||||
};
|
||||
module_platform_driver(adau7002_driver);
|
||||
|
||||
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
|
||||
MODULE_DESCRIPTION("ADAU7002 Stereo PDM-to-I2S/TDM Converter driver");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -437,15 +437,25 @@ static struct snd_soc_dai_driver ak4613_dai = {
|
|||
.symmetric_rates = 1,
|
||||
};
|
||||
|
||||
static int ak4613_suspend(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct regmap *regmap = dev_get_regmap(codec->dev, NULL);
|
||||
|
||||
regcache_cache_only(regmap, true);
|
||||
regcache_mark_dirty(regmap);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ak4613_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct regmap *regmap = dev_get_regmap(codec->dev, NULL);
|
||||
|
||||
regcache_mark_dirty(regmap);
|
||||
regcache_cache_only(regmap, false);
|
||||
return regcache_sync(regmap);
|
||||
}
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_ak4613 = {
|
||||
.suspend = ak4613_suspend,
|
||||
.resume = ak4613_resume,
|
||||
.set_bias_level = ak4613_set_bias_level,
|
||||
.controls = ak4613_snd_controls,
|
||||
|
|
|
@ -523,15 +523,23 @@ static struct snd_soc_dai_driver ak4642_dai = {
|
|||
.symmetric_rates = 1,
|
||||
};
|
||||
|
||||
static int ak4642_suspend(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct regmap *regmap = dev_get_regmap(codec->dev, NULL);
|
||||
|
||||
regcache_cache_only(regmap, true);
|
||||
regcache_mark_dirty(regmap);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ak4642_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct regmap *regmap = dev_get_regmap(codec->dev, NULL);
|
||||
|
||||
regcache_mark_dirty(regmap);
|
||||
regcache_cache_only(regmap, false);
|
||||
regcache_sync(regmap);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ak4642_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct ak4642_priv *priv = snd_soc_codec_get_drvdata(codec);
|
||||
|
@ -544,6 +552,7 @@ static int ak4642_probe(struct snd_soc_codec *codec)
|
|||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_ak4642 = {
|
||||
.probe = ak4642_probe,
|
||||
.suspend = ak4642_suspend,
|
||||
.resume = ak4642_resume,
|
||||
.set_bias_level = ak4642_set_bias_level,
|
||||
.controls = ak4642_snd_controls,
|
||||
|
|
|
@ -324,6 +324,17 @@ int arizona_init_gpio(struct snd_soc_codec *codec)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(arizona_init_gpio);
|
||||
|
||||
int arizona_init_notifiers(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
|
||||
struct arizona *arizona = priv->arizona;
|
||||
|
||||
BLOCKING_INIT_NOTIFIER_HEAD(&arizona->notifier);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(arizona_init_notifiers);
|
||||
|
||||
const char * const arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
|
||||
"None",
|
||||
"Tone Generator 1",
|
||||
|
@ -2573,6 +2584,30 @@ 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");
|
||||
|
|
|
@ -63,6 +63,9 @@
|
|||
#define ARIZONA_DVFS_SR1_RQ 0x001
|
||||
#define ARIZONA_DVFS_ADSP1_RQ 0x100
|
||||
|
||||
/* Notifier events */
|
||||
#define ARIZONA_NOTIFY_VOICE_TRIGGER 0x1
|
||||
|
||||
struct arizona;
|
||||
struct wm_adsp;
|
||||
|
||||
|
@ -95,6 +98,10 @@ struct arizona_priv {
|
|||
bool dvfs_cached;
|
||||
};
|
||||
|
||||
struct arizona_voice_trigger_info {
|
||||
int core;
|
||||
};
|
||||
|
||||
#define ARIZONA_NUM_MIXER_INPUTS 104
|
||||
|
||||
extern const unsigned int arizona_mixer_tlv[];
|
||||
|
@ -306,6 +313,7 @@ extern int arizona_set_fll(struct arizona_fll *fll, int source,
|
|||
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);
|
||||
|
||||
extern int arizona_free_spk(struct snd_soc_codec *codec);
|
||||
|
||||
|
@ -317,4 +325,13 @@ int arizona_set_output_mode(struct snd_soc_codec *codec, int output,
|
|||
extern bool arizona_input_analog(struct snd_soc_codec *codec, int shift);
|
||||
|
||||
extern 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);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1067,6 +1067,7 @@ static irqreturn_t cs47l24_adsp2_irq(int irq, void *data)
|
|||
{
|
||||
struct cs47l24_priv *priv = data;
|
||||
struct arizona *arizona = priv->core.arizona;
|
||||
struct arizona_voice_trigger_info info;
|
||||
int serviced = 0;
|
||||
int i, ret;
|
||||
|
||||
|
@ -1074,6 +1075,12 @@ static irqreturn_t cs47l24_adsp2_irq(int irq, void *data)
|
|||
ret = wm_adsp_compr_handle_irq(&priv->core.adsp[i]);
|
||||
if (ret != -ENODEV)
|
||||
serviced++;
|
||||
if (ret == WM_ADSP_COMPR_VOICE_TRIGGER) {
|
||||
info.core = i;
|
||||
arizona_call_notifiers(arizona,
|
||||
ARIZONA_NOTIFY_VOICE_TRIGGER,
|
||||
&info);
|
||||
}
|
||||
}
|
||||
|
||||
if (!serviced) {
|
||||
|
@ -1096,6 +1103,7 @@ static int cs47l24_codec_probe(struct snd_soc_codec *codec)
|
|||
arizona_init_spk(codec);
|
||||
arizona_init_gpio(codec);
|
||||
arizona_init_mono(codec);
|
||||
arizona_init_notifiers(codec);
|
||||
|
||||
ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1,
|
||||
"ADSP2 Compressed IRQ", cs47l24_adsp2_irq,
|
||||
|
|
|
@ -2223,6 +2223,7 @@ static irqreturn_t wm5110_adsp2_irq(int irq, void *data)
|
|||
{
|
||||
struct wm5110_priv *priv = data;
|
||||
struct arizona *arizona = priv->core.arizona;
|
||||
struct arizona_voice_trigger_info info;
|
||||
int serviced = 0;
|
||||
int i, ret;
|
||||
|
||||
|
@ -2230,6 +2231,12 @@ static irqreturn_t wm5110_adsp2_irq(int irq, void *data)
|
|||
ret = wm_adsp_compr_handle_irq(&priv->core.adsp[i]);
|
||||
if (ret != -ENODEV)
|
||||
serviced++;
|
||||
if (ret == WM_ADSP_COMPR_VOICE_TRIGGER) {
|
||||
info.core = i;
|
||||
arizona_call_notifiers(arizona,
|
||||
ARIZONA_NOTIFY_VOICE_TRIGGER,
|
||||
&info);
|
||||
}
|
||||
}
|
||||
|
||||
if (!serviced) {
|
||||
|
@ -2252,6 +2259,7 @@ static int wm5110_codec_probe(struct snd_soc_codec *codec)
|
|||
arizona_init_spk(codec);
|
||||
arizona_init_gpio(codec);
|
||||
arizona_init_mono(codec);
|
||||
arizona_init_notifiers(codec);
|
||||
|
||||
ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1,
|
||||
"ADSP2 Compressed IRQ", wm5110_adsp2_irq,
|
||||
|
|
|
@ -2366,13 +2366,15 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
|
|||
dsp->running = false;
|
||||
|
||||
regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
|
||||
ADSP2_SYS_ENA | ADSP2_CORE_ENA |
|
||||
ADSP2_START, 0);
|
||||
ADSP2_CORE_ENA | ADSP2_START, 0);
|
||||
|
||||
/* Make sure DMAs are quiesced */
|
||||
regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0);
|
||||
regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_1, 0);
|
||||
regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_2, 0);
|
||||
regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0);
|
||||
|
||||
regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
|
||||
ADSP2_SYS_ENA, 0);
|
||||
|
||||
list_for_each_entry(ctl, &dsp->ctl_list, list)
|
||||
ctl->enabled = 0;
|
||||
|
@ -3037,12 +3039,8 @@ int wm_adsp_compr_pointer(struct snd_compr_stream *stream,
|
|||
|
||||
buf = compr->buf;
|
||||
|
||||
if (!compr->buf) {
|
||||
ret = -ENXIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (compr->buf->error) {
|
||||
if (!compr->buf || compr->buf->error) {
|
||||
snd_compr_stop_error(stream, SNDRV_PCM_STATE_XRUN);
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
@ -3060,8 +3058,12 @@ int wm_adsp_compr_pointer(struct snd_compr_stream *stream,
|
|||
*/
|
||||
if (buf->avail < wm_adsp_compr_frag_words(compr)) {
|
||||
ret = wm_adsp_buffer_get_error(buf);
|
||||
if (ret < 0)
|
||||
if (ret < 0) {
|
||||
if (compr->buf->error)
|
||||
snd_compr_stop_error(stream,
|
||||
SNDRV_PCM_STATE_XRUN);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = wm_adsp_buffer_reenable_irq(buf);
|
||||
if (ret < 0) {
|
||||
|
@ -3156,11 +3158,10 @@ static int wm_adsp_compr_read(struct wm_adsp_compr *compr,
|
|||
|
||||
adsp_dbg(dsp, "Requested read of %zu bytes\n", count);
|
||||
|
||||
if (!compr->buf)
|
||||
return -ENXIO;
|
||||
|
||||
if (compr->buf->error)
|
||||
if (!compr->buf || compr->buf->error) {
|
||||
snd_compr_stop_error(compr->stream, SNDRV_PCM_STATE_XRUN);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
count /= WM_ADSP_DATA_WORD_SIZE;
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче