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:
commit
72a04d6b60
|
@ -13,6 +13,11 @@ Required properties:
|
||||||
- reg: The i2c address. Value depends on the state of ADDR0
|
- reg: The i2c address. Value depends on the state of ADDR0
|
||||||
and ADDR1, as wired in hardware.
|
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:
|
Examples:
|
||||||
#include <dt-bindings/sound/adau17x1.h>
|
#include <dt-bindings/sound/adau17x1.h>
|
||||||
|
|
||||||
|
@ -20,5 +25,8 @@ Examples:
|
||||||
adau1361@38 {
|
adau1361@38 {
|
||||||
compatible = "adi,adau1761";
|
compatible = "adi,adau1761";
|
||||||
reg = <0x38>;
|
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
|
#define _WM_ARIZONA_CORE_H
|
||||||
|
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/notifier.h>
|
||||||
#include <linux/regmap.h>
|
#include <linux/regmap.h>
|
||||||
#include <linux/regulator/consumer.h>
|
#include <linux/regulator/consumer.h>
|
||||||
#include <linux/mfd/arizona/pdata.h>
|
#include <linux/mfd/arizona/pdata.h>
|
||||||
|
@ -148,8 +149,17 @@ struct arizona {
|
||||||
uint16_t dac_comp_coeff;
|
uint16_t dac_comp_coeff;
|
||||||
uint8_t dac_comp_enabled;
|
uint8_t dac_comp_enabled;
|
||||||
struct mutex dac_comp_lock;
|
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_enable(struct arizona *arizona);
|
||||||
int arizona_clk32k_disable(struct arizona *arizona);
|
int arizona_clk32k_disable(struct arizona *arizona);
|
||||||
|
|
||||||
|
|
|
@ -68,6 +68,7 @@ struct snd_compr_runtime {
|
||||||
* @ops: pointer to DSP callbacks
|
* @ops: pointer to DSP callbacks
|
||||||
* @runtime: pointer to runtime structure
|
* @runtime: pointer to runtime structure
|
||||||
* @device: device pointer
|
* @device: device pointer
|
||||||
|
* @error_work: delayed work used when closing the stream due to an error
|
||||||
* @direction: stream direction, playback/recording
|
* @direction: stream direction, playback/recording
|
||||||
* @metadata_set: metadata set flag, true when set
|
* @metadata_set: metadata set flag, true when set
|
||||||
* @next_track: has userspace signal next track transition, 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_ops *ops;
|
||||||
struct snd_compr_runtime *runtime;
|
struct snd_compr_runtime *runtime;
|
||||||
struct snd_compr *device;
|
struct snd_compr *device;
|
||||||
|
struct delayed_work error_work;
|
||||||
enum snd_compr_direction direction;
|
enum snd_compr_direction direction;
|
||||||
bool metadata_set;
|
bool metadata_set;
|
||||||
bool next_track;
|
bool next_track;
|
||||||
|
@ -187,4 +189,7 @@ static inline void snd_compr_drain_notify(struct snd_compr_stream *stream)
|
||||||
wake_up(&stream->runtime->sleep);
|
wake_up(&stream->runtime->sleep);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int snd_compr_stop_error(struct snd_compr_stream *stream,
|
||||||
|
snd_pcm_state_t state);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -67,6 +67,8 @@ struct snd_compr_file {
|
||||||
struct snd_compr_stream stream;
|
struct snd_compr_stream stream;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void error_delayed_work(struct work_struct *work);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* a note on stream states used:
|
* a note on stream states used:
|
||||||
* we use following states in the compressed core
|
* 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);
|
snd_card_unref(compr->card);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
INIT_DELAYED_WORK(&data->stream.error_work, error_delayed_work);
|
||||||
|
|
||||||
data->stream.ops = compr->ops;
|
data->stream.ops = compr->ops;
|
||||||
data->stream.direction = dirn;
|
data->stream.direction = dirn;
|
||||||
data->stream.private_data = compr->private_data;
|
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_file *data = f->private_data;
|
||||||
struct snd_compr_runtime *runtime = data->stream.runtime;
|
struct snd_compr_runtime *runtime = data->stream.runtime;
|
||||||
|
|
||||||
|
cancel_delayed_work_sync(&data->stream.error_work);
|
||||||
|
|
||||||
switch (runtime->state) {
|
switch (runtime->state) {
|
||||||
case SNDRV_PCM_STATE_RUNNING:
|
case SNDRV_PCM_STATE_RUNNING:
|
||||||
case SNDRV_PCM_STATE_DRAINING:
|
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);
|
avail = snd_compr_calc_avail(stream, &ioctl_avail);
|
||||||
ioctl_avail.avail = 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,
|
if (copy_to_user((__u64 __user *)arg,
|
||||||
&ioctl_avail, sizeof(ioctl_avail)))
|
&ioctl_avail, sizeof(ioctl_avail)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
@ -346,11 +362,13 @@ static ssize_t snd_compr_read(struct file *f, char __user *buf,
|
||||||
switch (stream->runtime->state) {
|
switch (stream->runtime->state) {
|
||||||
case SNDRV_PCM_STATE_OPEN:
|
case SNDRV_PCM_STATE_OPEN:
|
||||||
case SNDRV_PCM_STATE_PREPARED:
|
case SNDRV_PCM_STATE_PREPARED:
|
||||||
case SNDRV_PCM_STATE_XRUN:
|
|
||||||
case SNDRV_PCM_STATE_SUSPENDED:
|
case SNDRV_PCM_STATE_SUSPENDED:
|
||||||
case SNDRV_PCM_STATE_DISCONNECTED:
|
case SNDRV_PCM_STATE_DISCONNECTED:
|
||||||
retval = -EBADFD;
|
retval = -EBADFD;
|
||||||
goto out;
|
goto out;
|
||||||
|
case SNDRV_PCM_STATE_XRUN:
|
||||||
|
retval = -EPIPE;
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
avail = snd_compr_get_avail(stream);
|
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;
|
stream = &data->stream;
|
||||||
|
|
||||||
mutex_lock(&stream->device->lock);
|
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;
|
retval = snd_compr_get_poll(stream) | POLLERR;
|
||||||
goto out;
|
goto out;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
poll_wait(f, &stream->runtime->sleep, wait);
|
poll_wait(f, &stream->runtime->sleep, wait);
|
||||||
|
|
||||||
avail = snd_compr_get_avail(stream);
|
avail = snd_compr_get_avail(stream);
|
||||||
|
@ -697,6 +721,45 @@ static int snd_compr_stop(struct snd_compr_stream *stream)
|
||||||
return retval;
|
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)
|
static int snd_compress_wait_for_drain(struct snd_compr_stream *stream)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
|
@ -32,6 +32,7 @@ config SND_SOC_ALL_CODECS
|
||||||
select SND_SOC_ADAU1977_SPI if SPI_MASTER
|
select SND_SOC_ADAU1977_SPI if SPI_MASTER
|
||||||
select SND_SOC_ADAU1977_I2C if I2C
|
select SND_SOC_ADAU1977_I2C if I2C
|
||||||
select SND_SOC_ADAU1701 if I2C
|
select SND_SOC_ADAU1701 if I2C
|
||||||
|
select SND_SOC_ADAU7002
|
||||||
select SND_SOC_ADS117X
|
select SND_SOC_ADS117X
|
||||||
select SND_SOC_AK4104 if SPI_MASTER
|
select SND_SOC_AK4104 if SPI_MASTER
|
||||||
select SND_SOC_AK4535 if I2C
|
select SND_SOC_AK4535 if I2C
|
||||||
|
@ -269,8 +270,12 @@ config SND_SOC_AD1980
|
||||||
config SND_SOC_AD73311
|
config SND_SOC_AD73311
|
||||||
tristate
|
tristate
|
||||||
|
|
||||||
|
config SND_SOC_ADAU_UTILS
|
||||||
|
tristate
|
||||||
|
|
||||||
config SND_SOC_ADAU1373
|
config SND_SOC_ADAU1373
|
||||||
tristate
|
tristate
|
||||||
|
select SND_SOC_ADAU_UTILS
|
||||||
|
|
||||||
config SND_SOC_ADAU1701
|
config SND_SOC_ADAU1701
|
||||||
tristate "Analog Devices ADAU1701 CODEC"
|
tristate "Analog Devices ADAU1701 CODEC"
|
||||||
|
@ -280,6 +285,7 @@ config SND_SOC_ADAU1701
|
||||||
config SND_SOC_ADAU17X1
|
config SND_SOC_ADAU17X1
|
||||||
tristate
|
tristate
|
||||||
select SND_SOC_SIGMADSP_REGMAP
|
select SND_SOC_SIGMADSP_REGMAP
|
||||||
|
select SND_SOC_ADAU_UTILS
|
||||||
|
|
||||||
config SND_SOC_ADAU1761
|
config SND_SOC_ADAU1761
|
||||||
tristate
|
tristate
|
||||||
|
@ -322,6 +328,9 @@ config SND_SOC_ADAU1977_I2C
|
||||||
select SND_SOC_ADAU1977
|
select SND_SOC_ADAU1977
|
||||||
select REGMAP_I2C
|
select REGMAP_I2C
|
||||||
|
|
||||||
|
config SND_SOC_ADAU7002
|
||||||
|
tristate "Analog Devices ADAU7002 Stereo PDM-to-I2S/TDM Converter"
|
||||||
|
|
||||||
config SND_SOC_ADAV80X
|
config SND_SOC_ADAV80X
|
||||||
tristate
|
tristate
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ snd-soc-ad193x-spi-objs := ad193x-spi.o
|
||||||
snd-soc-ad193x-i2c-objs := ad193x-i2c.o
|
snd-soc-ad193x-i2c-objs := ad193x-i2c.o
|
||||||
snd-soc-ad1980-objs := ad1980.o
|
snd-soc-ad1980-objs := ad1980.o
|
||||||
snd-soc-ad73311-objs := ad73311.o
|
snd-soc-ad73311-objs := ad73311.o
|
||||||
|
snd-soc-adau-utils-objs := adau-utils.o
|
||||||
snd-soc-adau1373-objs := adau1373.o
|
snd-soc-adau1373-objs := adau1373.o
|
||||||
snd-soc-adau1701-objs := adau1701.o
|
snd-soc-adau1701-objs := adau1701.o
|
||||||
snd-soc-adau17x1-objs := adau17x1.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-objs := adau1977.o
|
||||||
snd-soc-adau1977-spi-objs := adau1977-spi.o
|
snd-soc-adau1977-spi-objs := adau1977-spi.o
|
||||||
snd-soc-adau1977-i2c-objs := adau1977-i2c.o
|
snd-soc-adau1977-i2c-objs := adau1977-i2c.o
|
||||||
|
snd-soc-adau7002-objs := adau7002.o
|
||||||
snd-soc-adav80x-objs := adav80x.o
|
snd-soc-adav80x-objs := adav80x.o
|
||||||
snd-soc-adav801-objs := adav801.o
|
snd-soc-adav801-objs := adav801.o
|
||||||
snd-soc-adav803-objs := adav803.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_AD193X_I2C) += snd-soc-ad193x-i2c.o
|
||||||
obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o
|
obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o
|
||||||
obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.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_ADAU1373) += snd-soc-adau1373.o
|
||||||
obj-$(CONFIG_SND_SOC_ADAU1701) += snd-soc-adau1701.o
|
obj-$(CONFIG_SND_SOC_ADAU1701) += snd-soc-adau1701.o
|
||||||
obj-$(CONFIG_SND_SOC_ADAU17X1) += snd-soc-adau17x1.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) += snd-soc-adau1977.o
|
||||||
obj-$(CONFIG_SND_SOC_ADAU1977_SPI) += snd-soc-adau1977-spi.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_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_ADAV80X) += snd-soc-adav80x.o
|
||||||
obj-$(CONFIG_SND_SOC_ADAV801) += snd-soc-adav801.o
|
obj-$(CONFIG_SND_SOC_ADAV801) += snd-soc-adav801.o
|
||||||
obj-$(CONFIG_SND_SOC_ADAV803) += snd-soc-adav803.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 <sound/adau1373.h>
|
||||||
|
|
||||||
#include "adau1373.h"
|
#include "adau1373.h"
|
||||||
|
#include "adau-utils.h"
|
||||||
|
|
||||||
struct adau1373_dai {
|
struct adau1373_dai {
|
||||||
unsigned int clk_src;
|
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);
|
struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec);
|
||||||
unsigned int dpll_div = 0;
|
unsigned int dpll_div = 0;
|
||||||
unsigned int x, r, n, m, i, j, mode;
|
uint8_t pll_regs[5];
|
||||||
|
int ret;
|
||||||
|
|
||||||
switch (pll_id) {
|
switch (pll_id) {
|
||||||
case ADAU1373_PLL1:
|
case ADAU1373_PLL1:
|
||||||
|
@ -1295,27 +1297,8 @@ static int adau1373_set_pll(struct snd_soc_codec *codec, int pll_id,
|
||||||
dpll_div++;
|
dpll_div++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (freq_out % freq_in != 0) {
|
ret = adau_calc_pll_cfg(freq_in, freq_out, pll_regs);
|
||||||
/* fout = fin * (r + (n/m)) / x */
|
if (ret)
|
||||||
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)
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (dpll_div) {
|
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),
|
regmap_write(adau1373->regmap, ADAU1373_DPLL_CTRL(pll_id),
|
||||||
(source << 4) | dpll_div);
|
(source << 4) | dpll_div);
|
||||||
regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL1(pll_id), (m >> 8) & 0xff);
|
regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL1(pll_id), pll_regs[0]);
|
||||||
regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL2(pll_id), m & 0xff);
|
regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL2(pll_id), pll_regs[1]);
|
||||||
regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL3(pll_id), (n >> 8) & 0xff);
|
regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL3(pll_id), pll_regs[2]);
|
||||||
regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL4(pll_id), n & 0xff);
|
regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL4(pll_id), pll_regs[3]);
|
||||||
regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL5(pll_id),
|
regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL5(pll_id), pll_regs[4]);
|
||||||
(r << 3) | (x << 1) | mode);
|
|
||||||
|
|
||||||
/* Set sysclk to pll_rate / 4 */
|
/* Set sysclk to pll_rate / 4 */
|
||||||
regmap_update_bits(adau1373->regmap, ADAU1373_CLK_SRC_DIV(pll_id), 0x3f, 0x09);
|
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)
|
static int adau1761_i2c_remove(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
snd_soc_unregister_codec(&client->dev);
|
adau17x1_remove(&client->dev);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,7 @@ static int adau1761_spi_probe(struct spi_device *spi)
|
||||||
|
|
||||||
static int adau1761_spi_remove(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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ static int adau1781_i2c_probe(struct i2c_client *client,
|
||||||
|
|
||||||
static int adau1781_i2c_remove(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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,7 @@ static int adau1781_spi_probe(struct spi_device *spi)
|
||||||
|
|
||||||
static int adau1781_spi_remove(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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
|
#include <linux/clk.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <sound/core.h>
|
#include <sound/core.h>
|
||||||
|
@ -23,6 +24,7 @@
|
||||||
|
|
||||||
#include "sigmadsp.h"
|
#include "sigmadsp.h"
|
||||||
#include "adau17x1.h"
|
#include "adau17x1.h"
|
||||||
|
#include "adau-utils.h"
|
||||||
|
|
||||||
static const char * const adau17x1_capture_mixer_boost_text[] = {
|
static const char * const adau17x1_capture_mixer_boost_text[] = {
|
||||||
"Normal operation", "Boost Level 1", "Boost Level 2", "Boost Level 3",
|
"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);
|
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,
|
static int adau17x1_hw_params(struct snd_pcm_substream *substream,
|
||||||
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
|
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;
|
unsigned int freq;
|
||||||
int ret;
|
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;
|
freq = adau->pll_freq;
|
||||||
else
|
break;
|
||||||
|
default:
|
||||||
freq = adau->sysclk;
|
freq = adau->sysclk;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (freq % params_rate(params) != 0)
|
if (freq % params_rate(params) != 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -386,93 +507,6 @@ static int adau17x1_hw_params(struct snd_pcm_substream *substream,
|
||||||
ADAU17X1_SERIAL_PORT1_DELAY_MASK, val);
|
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,
|
static int adau17x1_set_dai_fmt(struct snd_soc_dai *dai,
|
||||||
unsigned int fmt)
|
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,
|
ret = snd_soc_dapm_add_routes(dapm, adau17x1_no_dsp_dapm_routes,
|
||||||
ARRAY_SIZE(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;
|
return ret;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(adau17x1_add_routes);
|
EXPORT_SYMBOL_GPL(adau17x1_add_routes);
|
||||||
|
@ -879,6 +917,7 @@ int adau17x1_probe(struct device *dev, struct regmap *regmap,
|
||||||
const char *firmware_name)
|
const char *firmware_name)
|
||||||
{
|
{
|
||||||
struct adau *adau;
|
struct adau *adau;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (IS_ERR(regmap))
|
if (IS_ERR(regmap))
|
||||||
return PTR_ERR(regmap);
|
return PTR_ERR(regmap);
|
||||||
|
@ -887,6 +926,30 @@ int adau17x1_probe(struct device *dev, struct regmap *regmap,
|
||||||
if (!adau)
|
if (!adau)
|
||||||
return -ENOMEM;
|
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->regmap = regmap;
|
||||||
adau->switch_mode = switch_mode;
|
adau->switch_mode = switch_mode;
|
||||||
adau->type = type;
|
adau->type = type;
|
||||||
|
@ -910,6 +973,16 @@ int adau17x1_probe(struct device *dev, struct regmap *regmap,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(adau17x1_probe);
|
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_DESCRIPTION("ASoC ADAU1X61/ADAU1X81 common code");
|
||||||
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
|
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
|
|
@ -22,13 +22,18 @@ enum adau17x1_pll_src {
|
||||||
};
|
};
|
||||||
|
|
||||||
enum adau17x1_clk_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_MCLK,
|
||||||
ADAU17X1_CLK_SRC_PLL,
|
ADAU17X1_CLK_SRC_PLL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct clk;
|
||||||
|
|
||||||
struct adau {
|
struct adau {
|
||||||
unsigned int sysclk;
|
unsigned int sysclk;
|
||||||
unsigned int pll_freq;
|
unsigned int pll_freq;
|
||||||
|
struct clk *mclk;
|
||||||
|
|
||||||
enum adau17x1_clk_src clk_src;
|
enum adau17x1_clk_src clk_src;
|
||||||
enum adau17x1_type type;
|
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,
|
int adau17x1_probe(struct device *dev, struct regmap *regmap,
|
||||||
enum adau17x1_type type, void (*switch_mode)(struct device *dev),
|
enum adau17x1_type type, void (*switch_mode)(struct device *dev),
|
||||||
const char *firmware_name);
|
const char *firmware_name);
|
||||||
|
void adau17x1_remove(struct device *dev);
|
||||||
int adau17x1_set_micbias_voltage(struct snd_soc_codec *codec,
|
int adau17x1_set_micbias_voltage(struct snd_soc_codec *codec,
|
||||||
enum adau17x1_micbias_voltage micbias);
|
enum adau17x1_micbias_voltage micbias);
|
||||||
bool adau17x1_readable_register(struct device *dev, unsigned int reg);
|
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,
|
.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)
|
static int ak4613_resume(struct snd_soc_codec *codec)
|
||||||
{
|
{
|
||||||
struct regmap *regmap = dev_get_regmap(codec->dev, NULL);
|
struct regmap *regmap = dev_get_regmap(codec->dev, NULL);
|
||||||
|
|
||||||
regcache_mark_dirty(regmap);
|
regcache_cache_only(regmap, false);
|
||||||
return regcache_sync(regmap);
|
return regcache_sync(regmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct snd_soc_codec_driver soc_codec_dev_ak4613 = {
|
static struct snd_soc_codec_driver soc_codec_dev_ak4613 = {
|
||||||
|
.suspend = ak4613_suspend,
|
||||||
.resume = ak4613_resume,
|
.resume = ak4613_resume,
|
||||||
.set_bias_level = ak4613_set_bias_level,
|
.set_bias_level = ak4613_set_bias_level,
|
||||||
.controls = ak4613_snd_controls,
|
.controls = ak4613_snd_controls,
|
||||||
|
|
|
@ -523,15 +523,23 @@ static struct snd_soc_dai_driver ak4642_dai = {
|
||||||
.symmetric_rates = 1,
|
.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)
|
static int ak4642_resume(struct snd_soc_codec *codec)
|
||||||
{
|
{
|
||||||
struct regmap *regmap = dev_get_regmap(codec->dev, NULL);
|
struct regmap *regmap = dev_get_regmap(codec->dev, NULL);
|
||||||
|
|
||||||
regcache_mark_dirty(regmap);
|
regcache_cache_only(regmap, false);
|
||||||
regcache_sync(regmap);
|
regcache_sync(regmap);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ak4642_probe(struct snd_soc_codec *codec)
|
static int ak4642_probe(struct snd_soc_codec *codec)
|
||||||
{
|
{
|
||||||
struct ak4642_priv *priv = snd_soc_codec_get_drvdata(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 = {
|
static struct snd_soc_codec_driver soc_codec_dev_ak4642 = {
|
||||||
.probe = ak4642_probe,
|
.probe = ak4642_probe,
|
||||||
|
.suspend = ak4642_suspend,
|
||||||
.resume = ak4642_resume,
|
.resume = ak4642_resume,
|
||||||
.set_bias_level = ak4642_set_bias_level,
|
.set_bias_level = ak4642_set_bias_level,
|
||||||
.controls = ak4642_snd_controls,
|
.controls = ak4642_snd_controls,
|
||||||
|
|
|
@ -324,6 +324,17 @@ int arizona_init_gpio(struct snd_soc_codec *codec)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(arizona_init_gpio);
|
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] = {
|
const char * const arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
|
||||||
"None",
|
"None",
|
||||||
"Tone Generator 1",
|
"Tone Generator 1",
|
||||||
|
@ -2573,6 +2584,30 @@ int arizona_lhpf_coeff_put(struct snd_kcontrol *kcontrol,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(arizona_lhpf_coeff_put);
|
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_DESCRIPTION("ASoC Wolfson Arizona class device support");
|
||||||
MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
|
MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
|
|
@ -63,6 +63,9 @@
|
||||||
#define ARIZONA_DVFS_SR1_RQ 0x001
|
#define ARIZONA_DVFS_SR1_RQ 0x001
|
||||||
#define ARIZONA_DVFS_ADSP1_RQ 0x100
|
#define ARIZONA_DVFS_ADSP1_RQ 0x100
|
||||||
|
|
||||||
|
/* Notifier events */
|
||||||
|
#define ARIZONA_NOTIFY_VOICE_TRIGGER 0x1
|
||||||
|
|
||||||
struct arizona;
|
struct arizona;
|
||||||
struct wm_adsp;
|
struct wm_adsp;
|
||||||
|
|
||||||
|
@ -95,6 +98,10 @@ struct arizona_priv {
|
||||||
bool dvfs_cached;
|
bool dvfs_cached;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct arizona_voice_trigger_info {
|
||||||
|
int core;
|
||||||
|
};
|
||||||
|
|
||||||
#define ARIZONA_NUM_MIXER_INPUTS 104
|
#define ARIZONA_NUM_MIXER_INPUTS 104
|
||||||
|
|
||||||
extern const unsigned int arizona_mixer_tlv[];
|
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_spk(struct snd_soc_codec *codec);
|
||||||
extern int arizona_init_gpio(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_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);
|
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 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 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
|
#endif
|
||||||
|
|
|
@ -1067,6 +1067,7 @@ static irqreturn_t cs47l24_adsp2_irq(int irq, void *data)
|
||||||
{
|
{
|
||||||
struct cs47l24_priv *priv = data;
|
struct cs47l24_priv *priv = data;
|
||||||
struct arizona *arizona = priv->core.arizona;
|
struct arizona *arizona = priv->core.arizona;
|
||||||
|
struct arizona_voice_trigger_info info;
|
||||||
int serviced = 0;
|
int serviced = 0;
|
||||||
int i, ret;
|
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]);
|
ret = wm_adsp_compr_handle_irq(&priv->core.adsp[i]);
|
||||||
if (ret != -ENODEV)
|
if (ret != -ENODEV)
|
||||||
serviced++;
|
serviced++;
|
||||||
|
if (ret == WM_ADSP_COMPR_VOICE_TRIGGER) {
|
||||||
|
info.core = i;
|
||||||
|
arizona_call_notifiers(arizona,
|
||||||
|
ARIZONA_NOTIFY_VOICE_TRIGGER,
|
||||||
|
&info);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!serviced) {
|
if (!serviced) {
|
||||||
|
@ -1096,6 +1103,7 @@ static int cs47l24_codec_probe(struct snd_soc_codec *codec)
|
||||||
arizona_init_spk(codec);
|
arizona_init_spk(codec);
|
||||||
arizona_init_gpio(codec);
|
arizona_init_gpio(codec);
|
||||||
arizona_init_mono(codec);
|
arizona_init_mono(codec);
|
||||||
|
arizona_init_notifiers(codec);
|
||||||
|
|
||||||
ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1,
|
ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1,
|
||||||
"ADSP2 Compressed IRQ", cs47l24_adsp2_irq,
|
"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 wm5110_priv *priv = data;
|
||||||
struct arizona *arizona = priv->core.arizona;
|
struct arizona *arizona = priv->core.arizona;
|
||||||
|
struct arizona_voice_trigger_info info;
|
||||||
int serviced = 0;
|
int serviced = 0;
|
||||||
int i, ret;
|
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]);
|
ret = wm_adsp_compr_handle_irq(&priv->core.adsp[i]);
|
||||||
if (ret != -ENODEV)
|
if (ret != -ENODEV)
|
||||||
serviced++;
|
serviced++;
|
||||||
|
if (ret == WM_ADSP_COMPR_VOICE_TRIGGER) {
|
||||||
|
info.core = i;
|
||||||
|
arizona_call_notifiers(arizona,
|
||||||
|
ARIZONA_NOTIFY_VOICE_TRIGGER,
|
||||||
|
&info);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!serviced) {
|
if (!serviced) {
|
||||||
|
@ -2252,6 +2259,7 @@ static int wm5110_codec_probe(struct snd_soc_codec *codec)
|
||||||
arizona_init_spk(codec);
|
arizona_init_spk(codec);
|
||||||
arizona_init_gpio(codec);
|
arizona_init_gpio(codec);
|
||||||
arizona_init_mono(codec);
|
arizona_init_mono(codec);
|
||||||
|
arizona_init_notifiers(codec);
|
||||||
|
|
||||||
ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1,
|
ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1,
|
||||||
"ADSP2 Compressed IRQ", wm5110_adsp2_irq,
|
"ADSP2 Compressed IRQ", wm5110_adsp2_irq,
|
||||||
|
|
|
@ -2366,13 +2366,15 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
|
||||||
dsp->running = false;
|
dsp->running = false;
|
||||||
|
|
||||||
regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
|
regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
|
||||||
ADSP2_SYS_ENA | ADSP2_CORE_ENA |
|
ADSP2_CORE_ENA | ADSP2_START, 0);
|
||||||
ADSP2_START, 0);
|
|
||||||
|
|
||||||
/* Make sure DMAs are quiesced */
|
/* 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_1, 0);
|
||||||
regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_2, 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)
|
list_for_each_entry(ctl, &dsp->ctl_list, list)
|
||||||
ctl->enabled = 0;
|
ctl->enabled = 0;
|
||||||
|
@ -3037,12 +3039,8 @@ int wm_adsp_compr_pointer(struct snd_compr_stream *stream,
|
||||||
|
|
||||||
buf = compr->buf;
|
buf = compr->buf;
|
||||||
|
|
||||||
if (!compr->buf) {
|
if (!compr->buf || compr->buf->error) {
|
||||||
ret = -ENXIO;
|
snd_compr_stop_error(stream, SNDRV_PCM_STATE_XRUN);
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (compr->buf->error) {
|
|
||||||
ret = -EIO;
|
ret = -EIO;
|
||||||
goto out;
|
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)) {
|
if (buf->avail < wm_adsp_compr_frag_words(compr)) {
|
||||||
ret = wm_adsp_buffer_get_error(buf);
|
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;
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
ret = wm_adsp_buffer_reenable_irq(buf);
|
ret = wm_adsp_buffer_reenable_irq(buf);
|
||||||
if (ret < 0) {
|
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);
|
adsp_dbg(dsp, "Requested read of %zu bytes\n", count);
|
||||||
|
|
||||||
if (!compr->buf)
|
if (!compr->buf || compr->buf->error) {
|
||||||
return -ENXIO;
|
snd_compr_stop_error(compr->stream, SNDRV_PCM_STATE_XRUN);
|
||||||
|
|
||||||
if (compr->buf->error)
|
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
count /= WM_ADSP_DATA_WORD_SIZE;
|
count /= WM_ADSP_DATA_WORD_SIZE;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue