1
0

Merge branch 'asoc-4.21' into asoc-next

This commit is contained in:
Mark Brown
2018-12-18 12:23:59 +00:00
188 changed files with 9580 additions and 4005 deletions

View File

@@ -171,7 +171,8 @@ static int snd_compr_free(struct inode *inode, struct file *f)
}
data->stream.ops->free(&data->stream);
kfree(data->stream.runtime->buffer);
if (!data->stream.runtime->dma_buffer_p)
kfree(data->stream.runtime->buffer);
kfree(data->stream.runtime);
kfree(data);
return 0;
@@ -505,7 +506,7 @@ static int snd_compr_allocate_buffer(struct snd_compr_stream *stream,
struct snd_compr_params *params)
{
unsigned int buffer_size;
void *buffer;
void *buffer = NULL;
buffer_size = params->buffer.fragment_size * params->buffer.fragments;
if (stream->ops->copy) {
@@ -514,7 +515,18 @@ static int snd_compr_allocate_buffer(struct snd_compr_stream *stream,
* the data from core
*/
} else {
buffer = kmalloc(buffer_size, GFP_KERNEL);
if (stream->runtime->dma_buffer_p) {
if (buffer_size > stream->runtime->dma_buffer_p->bytes)
dev_err(&stream->device->dev,
"Not enough DMA buffer");
else
buffer = stream->runtime->dma_buffer_p->area;
} else {
buffer = kmalloc(buffer_size, GFP_KERNEL);
}
if (!buffer)
return -ENOMEM;
}

View File

@@ -46,13 +46,11 @@ source "sound/soc/atmel/Kconfig"
source "sound/soc/au1x/Kconfig"
source "sound/soc/bcm/Kconfig"
source "sound/soc/cirrus/Kconfig"
source "sound/soc/davinci/Kconfig"
source "sound/soc/dwc/Kconfig"
source "sound/soc/fsl/Kconfig"
source "sound/soc/hisilicon/Kconfig"
source "sound/soc/jz4740/Kconfig"
source "sound/soc/nuc900/Kconfig"
source "sound/soc/omap/Kconfig"
source "sound/soc/kirkwood/Kconfig"
source "sound/soc/img/Kconfig"
source "sound/soc/intel/Kconfig"
@@ -70,9 +68,11 @@ source "sound/soc/sti/Kconfig"
source "sound/soc/stm/Kconfig"
source "sound/soc/sunxi/Kconfig"
source "sound/soc/tegra/Kconfig"
source "sound/soc/ti/Kconfig"
source "sound/soc/txx9/Kconfig"
source "sound/soc/uniphier/Kconfig"
source "sound/soc/ux500/Kconfig"
source "sound/soc/xilinx/Kconfig"
source "sound/soc/xtensa/Kconfig"
source "sound/soc/zte/Kconfig"

View File

@@ -30,7 +30,6 @@ obj-$(CONFIG_SND_SOC) += atmel/
obj-$(CONFIG_SND_SOC) += au1x/
obj-$(CONFIG_SND_SOC) += bcm/
obj-$(CONFIG_SND_SOC) += cirrus/
obj-$(CONFIG_SND_SOC) += davinci/
obj-$(CONFIG_SND_SOC) += dwc/
obj-$(CONFIG_SND_SOC) += fsl/
obj-$(CONFIG_SND_SOC) += hisilicon/
@@ -41,7 +40,6 @@ obj-$(CONFIG_SND_SOC) += mediatek/
obj-$(CONFIG_SND_SOC) += meson/
obj-$(CONFIG_SND_SOC) += mxs/
obj-$(CONFIG_SND_SOC) += nuc900/
obj-$(CONFIG_SND_SOC) += omap/
obj-$(CONFIG_SND_SOC) += kirkwood/
obj-$(CONFIG_SND_SOC) += pxa/
obj-$(CONFIG_SND_SOC) += qcom/
@@ -54,8 +52,10 @@ obj-$(CONFIG_SND_SOC) += sti/
obj-$(CONFIG_SND_SOC) += stm/
obj-$(CONFIG_SND_SOC) += sunxi/
obj-$(CONFIG_SND_SOC) += tegra/
obj-$(CONFIG_SND_SOC) += ti/
obj-$(CONFIG_SND_SOC) += txx9/
obj-$(CONFIG_SND_SOC) += uniphier/
obj-$(CONFIG_SND_SOC) += ux500/
obj-$(CONFIG_SND_SOC) += xilinx/
obj-$(CONFIG_SND_SOC) += xtensa/
obj-$(CONFIG_SND_SOC) += zte/

View File

@@ -19,3 +19,9 @@ config SND_SOC_AMD_CZ_RT5645_MACH
depends on SND_SOC_AMD_ACP && I2C
help
This option enables machine driver for rt5645.
config SND_SOC_AMD_ACP3x
tristate "AMD Audio Coprocessor-v3.x support"
depends on X86 && PCI
help
This option enables ACP v3.x I2S support on AMD platform

View File

@@ -5,3 +5,4 @@ snd-soc-acp-rt5645-mach-objs := acp-rt5645.o
obj-$(CONFIG_SND_SOC_AMD_ACP) += acp_audio_dma.o
obj-$(CONFIG_SND_SOC_AMD_CZ_DA7219MX98357_MACH) += snd-soc-acp-da7219mx98357-mach.o
obj-$(CONFIG_SND_SOC_AMD_CZ_RT5645_MACH) += snd-soc-acp-rt5645-mach.o
obj-$(CONFIG_SND_SOC_AMD_ACP3x) += raven/

View File

@@ -403,7 +403,7 @@ static struct regulator_config acp_da7219_cfg = {
static struct regulator_ops acp_da7219_ops = {
};
static struct regulator_desc acp_da7219_desc = {
static const struct regulator_desc acp_da7219_desc = {
.name = "reg-fixed-1.8V",
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,

View File

@@ -303,11 +303,10 @@ static void set_acp_to_i2s_dma_descriptors(void __iomem *acp_mmio, u32 size,
}
/* Create page table entries in ACP SRAM for the allocated memory */
static void acp_pte_config(void __iomem *acp_mmio, struct page *pg,
static void acp_pte_config(void __iomem *acp_mmio, dma_addr_t addr,
u16 num_of_pages, u32 pte_offset)
{
u16 page_idx;
u64 addr;
u32 low;
u32 high;
u32 offset;
@@ -317,7 +316,6 @@ static void acp_pte_config(void __iomem *acp_mmio, struct page *pg,
/* Load the low address of page int ACP SRAM through SRBM */
acp_reg_write((offset + (page_idx * 8)),
acp_mmio, mmACP_SRBM_Targ_Idx_Addr);
addr = page_to_phys(pg);
low = lower_32_bits(addr);
high = upper_32_bits(addr);
@@ -333,7 +331,7 @@ static void acp_pte_config(void __iomem *acp_mmio, struct page *pg,
acp_reg_write(high, acp_mmio, mmACP_SRBM_Targ_Idx_Data);
/* Move to next physically contiguos page */
pg++;
addr += PAGE_SIZE;
}
}
@@ -343,7 +341,7 @@ static void config_acp_dma(void __iomem *acp_mmio,
{
u16 ch_acp_sysmem, ch_acp_i2s;
acp_pte_config(acp_mmio, rtd->pg, rtd->num_of_pages,
acp_pte_config(acp_mmio, rtd->dma_addr, rtd->num_of_pages,
rtd->pte_offset);
if (rtd->direction == SNDRV_PCM_STREAM_PLAYBACK) {
@@ -850,7 +848,6 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream,
int status;
uint64_t size;
u32 val = 0;
struct page *pg;
struct snd_pcm_runtime *runtime;
struct audio_substream_data *rtd;
struct snd_soc_pcm_runtime *prtd = substream->private_data;
@@ -986,16 +983,14 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream,
return status;
memset(substream->runtime->dma_area, 0, params_buffer_bytes(params));
pg = virt_to_page(substream->dma_buffer.area);
if (pg) {
if (substream->dma_buffer.area) {
acp_set_sram_bank_state(rtd->acp_mmio, 0, true);
/* Save for runtime private data */
rtd->pg = pg;
rtd->dma_addr = substream->dma_buffer.addr;
rtd->order = get_order(size);
/* Fill the page table entries in ACP SRAM */
rtd->pg = pg;
rtd->size = size;
rtd->num_of_pages = PAGE_ALIGN(size) >> PAGE_SHIFT;
rtd->direction = substream->stream;
@@ -1151,18 +1146,21 @@ static int acp_dma_new(struct snd_soc_pcm_runtime *rtd)
struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd,
DRV_NAME);
struct audio_drv_data *adata = dev_get_drvdata(component->dev);
struct device *parent = component->dev->parent;
switch (adata->asic_type) {
case CHIP_STONEY:
ret = snd_pcm_lib_preallocate_pages_for_all(rtd->pcm,
SNDRV_DMA_TYPE_DEV,
NULL, ST_MIN_BUFFER,
parent,
ST_MIN_BUFFER,
ST_MAX_BUFFER);
break;
default:
ret = snd_pcm_lib_preallocate_pages_for_all(rtd->pcm,
SNDRV_DMA_TYPE_DEV,
NULL, MIN_BUFFER,
parent,
MIN_BUFFER,
MAX_BUFFER);
break;
}

View File

@@ -123,7 +123,7 @@ enum acp_dma_priority_level {
};
struct audio_substream_data {
struct page *pg;
dma_addr_t dma_addr;
unsigned int order;
u16 num_of_pages;
u16 i2s_instance;

View File

@@ -0,0 +1,6 @@
# SPDX-License-Identifier: GPL-2.0+
# Raven Ridge platform Support
snd-pci-acp3x-objs := pci-acp3x.o
snd-acp3x-pcm-dma-objs := acp3x-pcm-dma.o
obj-$(CONFIG_SND_SOC_AMD_ACP3x) += snd-pci-acp3x.o
obj-$(CONFIG_SND_SOC_AMD_ACP3x) += snd-acp3x-pcm-dma.o

View File

@@ -0,0 +1,777 @@
// SPDX-License-Identifier: GPL-2.0+
//
// AMD ALSA SoC PCM Driver
//
//Copyright 2016 Advanced Micro Devices, Inc.
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/pm_runtime.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dai.h>
#include "acp3x.h"
#define DRV_NAME "acp3x-i2s-audio"
struct i2s_dev_data {
bool tdm_mode;
unsigned int i2s_irq;
u32 tdm_fmt;
void __iomem *acp3x_base;
struct snd_pcm_substream *play_stream;
struct snd_pcm_substream *capture_stream;
};
struct i2s_stream_instance {
u16 num_pages;
u16 channels;
u32 xfer_resolution;
struct page *pg;
void __iomem *acp3x_base;
};
static const struct snd_pcm_hardware acp3x_pcm_hardware_playback = {
.info = SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_BATCH |
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME,
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 2,
.channels_max = 8,
.rates = SNDRV_PCM_RATE_8000_96000,
.rate_min = 8000,
.rate_max = 96000,
.buffer_bytes_max = PLAYBACK_MAX_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE,
.period_bytes_min = PLAYBACK_MIN_PERIOD_SIZE,
.period_bytes_max = PLAYBACK_MAX_PERIOD_SIZE,
.periods_min = PLAYBACK_MIN_NUM_PERIODS,
.periods_max = PLAYBACK_MAX_NUM_PERIODS,
};
static const struct snd_pcm_hardware acp3x_pcm_hardware_capture = {
.info = SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_BATCH |
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME,
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 2,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_8000_48000,
.rate_min = 8000,
.rate_max = 48000,
.buffer_bytes_max = CAPTURE_MAX_NUM_PERIODS * CAPTURE_MAX_PERIOD_SIZE,
.period_bytes_min = CAPTURE_MIN_PERIOD_SIZE,
.period_bytes_max = CAPTURE_MAX_PERIOD_SIZE,
.periods_min = CAPTURE_MIN_NUM_PERIODS,
.periods_max = CAPTURE_MAX_NUM_PERIODS,
};
static int acp3x_power_on(void __iomem *acp3x_base, bool on)
{
u16 val, mask;
u32 timeout;
if (on == true) {
val = 1;
mask = ACP3x_POWER_ON;
} else {
val = 0;
mask = ACP3x_POWER_OFF;
}
rv_writel(val, acp3x_base + mmACP_PGFSM_CONTROL);
timeout = 0;
while (true) {
val = rv_readl(acp3x_base + mmACP_PGFSM_STATUS);
if ((val & ACP3x_POWER_OFF_IN_PROGRESS) == mask)
break;
if (timeout > 100) {
pr_err("ACP3x power state change failure\n");
return -ENODEV;
}
timeout++;
cpu_relax();
}
return 0;
}
static int acp3x_reset(void __iomem *acp3x_base)
{
u32 val, timeout;
rv_writel(1, acp3x_base + mmACP_SOFT_RESET);
timeout = 0;
while (true) {
val = rv_readl(acp3x_base + mmACP_SOFT_RESET);
if ((val & ACP3x_SOFT_RESET__SoftResetAudDone_MASK) ||
timeout > 100) {
if (val & ACP3x_SOFT_RESET__SoftResetAudDone_MASK)
break;
return -ENODEV;
}
timeout++;
cpu_relax();
}
rv_writel(0, acp3x_base + mmACP_SOFT_RESET);
timeout = 0;
while (true) {
val = rv_readl(acp3x_base + mmACP_SOFT_RESET);
if (!val || timeout > 100) {
if (!val)
break;
return -ENODEV;
}
timeout++;
cpu_relax();
}
return 0;
}
static int acp3x_init(void __iomem *acp3x_base)
{
int ret;
/* power on */
ret = acp3x_power_on(acp3x_base, true);
if (ret) {
pr_err("ACP3x power on failed\n");
return ret;
}
/* Reset */
ret = acp3x_reset(acp3x_base);
if (ret) {
pr_err("ACP3x reset failed\n");
return ret;
}
return 0;
}
static int acp3x_deinit(void __iomem *acp3x_base)
{
int ret;
/* Reset */
ret = acp3x_reset(acp3x_base);
if (ret) {
pr_err("ACP3x reset failed\n");
return ret;
}
/* power off */
ret = acp3x_power_on(acp3x_base, false);
if (ret) {
pr_err("ACP3x power off failed\n");
return ret;
}
return 0;
}
static irqreturn_t i2s_irq_handler(int irq, void *dev_id)
{
u16 play_flag, cap_flag;
u32 val;
struct i2s_dev_data *rv_i2s_data = dev_id;
if (!rv_i2s_data)
return IRQ_NONE;
play_flag = 0;
cap_flag = 0;
val = rv_readl(rv_i2s_data->acp3x_base + mmACP_EXTERNAL_INTR_STAT);
if ((val & BIT(BT_TX_THRESHOLD)) && rv_i2s_data->play_stream) {
rv_writel(BIT(BT_TX_THRESHOLD), rv_i2s_data->acp3x_base +
mmACP_EXTERNAL_INTR_STAT);
snd_pcm_period_elapsed(rv_i2s_data->play_stream);
play_flag = 1;
}
if ((val & BIT(BT_RX_THRESHOLD)) && rv_i2s_data->capture_stream) {
rv_writel(BIT(BT_RX_THRESHOLD), rv_i2s_data->acp3x_base +
mmACP_EXTERNAL_INTR_STAT);
snd_pcm_period_elapsed(rv_i2s_data->capture_stream);
cap_flag = 1;
}
if (play_flag | cap_flag)
return IRQ_HANDLED;
else
return IRQ_NONE;
}
static void config_acp3x_dma(struct i2s_stream_instance *rtd, int direction)
{
u16 page_idx;
u64 addr;
u32 low, high, val, acp_fifo_addr;
struct page *pg = rtd->pg;
/* 8 scratch registers used to map one 64 bit address */
if (direction == SNDRV_PCM_STREAM_PLAYBACK)
val = 0;
else
val = rtd->num_pages * 8;
/* Group Enable */
rv_writel(ACP_SRAM_PTE_OFFSET | BIT(31), rtd->acp3x_base +
mmACPAXI2AXI_ATU_BASE_ADDR_GRP_1);
rv_writel(PAGE_SIZE_4K_ENABLE, rtd->acp3x_base +
mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_1);
for (page_idx = 0; page_idx < rtd->num_pages; page_idx++) {
/* Load the low address of page int ACP SRAM through SRBM */
addr = page_to_phys(pg);
low = lower_32_bits(addr);
high = upper_32_bits(addr);
rv_writel(low, rtd->acp3x_base + mmACP_SCRATCH_REG_0 + val);
high |= BIT(31);
rv_writel(high, rtd->acp3x_base + mmACP_SCRATCH_REG_0 + val
+ 4);
/* Move to next physically contiguos page */
val += 8;
pg++;
}
if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
/* Config ringbuffer */
rv_writel(MEM_WINDOW_START, rtd->acp3x_base +
mmACP_BT_TX_RINGBUFADDR);
rv_writel(MAX_BUFFER, rtd->acp3x_base +
mmACP_BT_TX_RINGBUFSIZE);
rv_writel(DMA_SIZE, rtd->acp3x_base + mmACP_BT_TX_DMA_SIZE);
/* Config audio fifo */
acp_fifo_addr = ACP_SRAM_PTE_OFFSET + (rtd->num_pages * 8)
+ PLAYBACK_FIFO_ADDR_OFFSET;
rv_writel(acp_fifo_addr, rtd->acp3x_base +
mmACP_BT_TX_FIFOADDR);
rv_writel(FIFO_SIZE, rtd->acp3x_base + mmACP_BT_TX_FIFOSIZE);
} else {
/* Config ringbuffer */
rv_writel(MEM_WINDOW_START + MAX_BUFFER, rtd->acp3x_base +
mmACP_BT_RX_RINGBUFADDR);
rv_writel(MAX_BUFFER, rtd->acp3x_base +
mmACP_BT_RX_RINGBUFSIZE);
rv_writel(DMA_SIZE, rtd->acp3x_base + mmACP_BT_RX_DMA_SIZE);
/* Config audio fifo */
acp_fifo_addr = ACP_SRAM_PTE_OFFSET +
(rtd->num_pages * 8) + CAPTURE_FIFO_ADDR_OFFSET;
rv_writel(acp_fifo_addr, rtd->acp3x_base +
mmACP_BT_RX_FIFOADDR);
rv_writel(FIFO_SIZE, rtd->acp3x_base + mmACP_BT_RX_FIFOSIZE);
}
/* Enable watermark/period interrupt to host */
rv_writel(BIT(BT_TX_THRESHOLD) | BIT(BT_RX_THRESHOLD),
rtd->acp3x_base + mmACP_EXTERNAL_INTR_CNTL);
}
static int acp3x_dma_open(struct snd_pcm_substream *substream)
{
int ret = 0;
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *prtd = substream->private_data;
struct snd_soc_component *component = snd_soc_rtdcom_lookup(prtd,
DRV_NAME);
struct i2s_dev_data *adata = dev_get_drvdata(component->dev);
struct i2s_stream_instance *i2s_data = kzalloc(sizeof(struct i2s_stream_instance),
GFP_KERNEL);
if (!i2s_data)
return -EINVAL;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
runtime->hw = acp3x_pcm_hardware_playback;
else
runtime->hw = acp3x_pcm_hardware_capture;
ret = snd_pcm_hw_constraint_integer(runtime,
SNDRV_PCM_HW_PARAM_PERIODS);
if (ret < 0) {
dev_err(component->dev, "set integer constraint failed\n");
kfree(i2s_data);
return ret;
}
if (!adata->play_stream && !adata->capture_stream)
rv_writel(1, adata->acp3x_base + mmACP_EXTERNAL_INTR_ENB);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
adata->play_stream = substream;
else
adata->capture_stream = substream;
i2s_data->acp3x_base = adata->acp3x_base;
runtime->private_data = i2s_data;
return 0;
}
static int acp3x_dma_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
int status;
u64 size;
struct page *pg;
struct snd_pcm_runtime *runtime = substream->runtime;
struct i2s_stream_instance *rtd = runtime->private_data;
if (!rtd)
return -EINVAL;
size = params_buffer_bytes(params);
status = snd_pcm_lib_malloc_pages(substream, size);
if (status < 0)
return status;
memset(substream->runtime->dma_area, 0, params_buffer_bytes(params));
pg = virt_to_page(substream->dma_buffer.area);
if (pg) {
rtd->pg = pg;
rtd->num_pages = (PAGE_ALIGN(size) >> PAGE_SHIFT);
config_acp3x_dma(rtd, substream->stream);
status = 0;
} else {
status = -ENOMEM;
}
return status;
}
static snd_pcm_uframes_t acp3x_dma_pointer(struct snd_pcm_substream *substream)
{
u32 pos = 0;
struct i2s_stream_instance *rtd = substream->runtime->private_data;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
pos = rv_readl(rtd->acp3x_base +
mmACP_BT_TX_LINKPOSITIONCNTR);
else
pos = rv_readl(rtd->acp3x_base +
mmACP_BT_RX_LINKPOSITIONCNTR);
if (pos >= MAX_BUFFER)
pos = 0;
return bytes_to_frames(substream->runtime, pos);
}
static int acp3x_dma_new(struct snd_soc_pcm_runtime *rtd)
{
return snd_pcm_lib_preallocate_pages_for_all(rtd->pcm,
SNDRV_DMA_TYPE_DEV,
NULL, MIN_BUFFER,
MAX_BUFFER);
}
static int acp3x_dma_hw_free(struct snd_pcm_substream *substream)
{
return snd_pcm_lib_free_pages(substream);
}
static int acp3x_dma_mmap(struct snd_pcm_substream *substream,
struct vm_area_struct *vma)
{
return snd_pcm_lib_default_mmap(substream, vma);
}
static int acp3x_dma_close(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *prtd = substream->private_data;
struct i2s_stream_instance *rtd = substream->runtime->private_data;
struct snd_soc_component *component = snd_soc_rtdcom_lookup(prtd,
DRV_NAME);
struct i2s_dev_data *adata = dev_get_drvdata(component->dev);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
adata->play_stream = NULL;
else
adata->capture_stream = NULL;
/* Disable ACP irq, when the current stream is being closed and
* another stream is also not active.
*/
if (!adata->play_stream && !adata->capture_stream)
rv_writel(0, adata->acp3x_base + mmACP_EXTERNAL_INTR_ENB);
kfree(rtd);
return 0;
}
static struct snd_pcm_ops acp3x_dma_ops = {
.open = acp3x_dma_open,
.close = acp3x_dma_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = acp3x_dma_hw_params,
.hw_free = acp3x_dma_hw_free,
.pointer = acp3x_dma_pointer,
.mmap = acp3x_dma_mmap,
};
static int acp3x_dai_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
{
struct i2s_dev_data *adata = snd_soc_dai_get_drvdata(cpu_dai);
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
adata->tdm_mode = false;
break;
case SND_SOC_DAIFMT_DSP_A:
adata->tdm_mode = true;
break;
default:
return -EINVAL;
}
return 0;
}
static int acp3x_dai_set_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask,
u32 rx_mask, int slots, int slot_width)
{
u32 val = 0;
u16 slot_len;
struct i2s_dev_data *adata = snd_soc_dai_get_drvdata(cpu_dai);
switch (slot_width) {
case SLOT_WIDTH_8:
slot_len = 8;
break;
case SLOT_WIDTH_16:
slot_len = 16;
break;
case SLOT_WIDTH_24:
slot_len = 24;
break;
case SLOT_WIDTH_32:
slot_len = 0;
break;
default:
return -EINVAL;
}
val = rv_readl(adata->acp3x_base + mmACP_BTTDM_ITER);
rv_writel((val | 0x2), adata->acp3x_base + mmACP_BTTDM_ITER);
val = rv_readl(adata->acp3x_base + mmACP_BTTDM_IRER);
rv_writel((val | 0x2), adata->acp3x_base + mmACP_BTTDM_IRER);
val = (FRM_LEN | (slots << 15) | (slot_len << 18));
rv_writel(val, adata->acp3x_base + mmACP_BTTDM_TXFRMT);
rv_writel(val, adata->acp3x_base + mmACP_BTTDM_RXFRMT);
adata->tdm_fmt = val;
return 0;
}
static int acp3x_dai_i2s_hwparams(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
u32 val = 0;
struct i2s_stream_instance *rtd = substream->runtime->private_data;
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_U8:
case SNDRV_PCM_FORMAT_S8:
rtd->xfer_resolution = 0x0;
break;
case SNDRV_PCM_FORMAT_S16_LE:
rtd->xfer_resolution = 0x02;
break;
case SNDRV_PCM_FORMAT_S24_LE:
rtd->xfer_resolution = 0x04;
break;
case SNDRV_PCM_FORMAT_S32_LE:
rtd->xfer_resolution = 0x05;
break;
default:
return -EINVAL;
}
val = rv_readl(rtd->acp3x_base + mmACP_BTTDM_ITER);
val = val | (rtd->xfer_resolution << 3);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
rv_writel(val, rtd->acp3x_base + mmACP_BTTDM_ITER);
else
rv_writel(val, rtd->acp3x_base + mmACP_BTTDM_IRER);
return 0;
}
static int acp3x_dai_i2s_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai)
{
int ret = 0;
struct i2s_stream_instance *rtd = substream->runtime->private_data;
u32 val, period_bytes;
period_bytes = frames_to_bytes(substream->runtime,
substream->runtime->period_size);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
rv_writel(period_bytes, rtd->acp3x_base +
mmACP_BT_TX_INTR_WATERMARK_SIZE);
val = rv_readl(rtd->acp3x_base + mmACP_BTTDM_ITER);
val = val | BIT(0);
rv_writel(val, rtd->acp3x_base + mmACP_BTTDM_ITER);
} else {
rv_writel(period_bytes, rtd->acp3x_base +
mmACP_BT_RX_INTR_WATERMARK_SIZE);
val = rv_readl(rtd->acp3x_base + mmACP_BTTDM_IRER);
val = val | BIT(0);
rv_writel(val, rtd->acp3x_base + mmACP_BTTDM_IRER);
}
rv_writel(1, rtd->acp3x_base + mmACP_BTTDM_IER);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
val = rv_readl(rtd->acp3x_base + mmACP_BTTDM_ITER);
val = val & ~BIT(0);
rv_writel(val, rtd->acp3x_base + mmACP_BTTDM_ITER);
} else {
val = rv_readl(rtd->acp3x_base + mmACP_BTTDM_IRER);
val = val & ~BIT(0);
rv_writel(val, rtd->acp3x_base + mmACP_BTTDM_IRER);
}
rv_writel(0, rtd->acp3x_base + mmACP_BTTDM_IER);
break;
default:
ret = -EINVAL;
break;
}
return ret;
}
struct snd_soc_dai_ops acp3x_dai_i2s_ops = {
.hw_params = acp3x_dai_i2s_hwparams,
.trigger = acp3x_dai_i2s_trigger,
.set_fmt = acp3x_dai_i2s_set_fmt,
.set_tdm_slot = acp3x_dai_set_tdm_slot,
};
static struct snd_soc_dai_driver acp3x_i2s_dai_driver = {
.playback = {
.rates = SNDRV_PCM_RATE_8000_96000,
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
SNDRV_PCM_FMTBIT_U8 |
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 2,
.channels_max = 8,
.rate_min = 8000,
.rate_max = 96000,
},
.capture = {
.rates = SNDRV_PCM_RATE_8000_48000,
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
SNDRV_PCM_FMTBIT_U8 |
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 2,
.channels_max = 2,
.rate_min = 8000,
.rate_max = 48000,
},
.ops = &acp3x_dai_i2s_ops,
};
static const struct snd_soc_component_driver acp3x_i2s_component = {
.name = DRV_NAME,
.ops = &acp3x_dma_ops,
.pcm_new = acp3x_dma_new,
};
static int acp3x_audio_probe(struct platform_device *pdev)
{
int status;
struct resource *res;
struct i2s_dev_data *adata;
unsigned int irqflags;
if (!pdev->dev.platform_data) {
dev_err(&pdev->dev, "platform_data not retrieved\n");
return -ENODEV;
}
irqflags = *((unsigned int *)(pdev->dev.platform_data));
adata = devm_kzalloc(&pdev->dev, sizeof(struct i2s_dev_data),
GFP_KERNEL);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "IORESOURCE_IRQ FAILED\n");
return -ENODEV;
}
adata->acp3x_base = devm_ioremap(&pdev->dev, res->start,
resource_size(res));
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res) {
dev_err(&pdev->dev, "IORESOURCE_IRQ FAILED\n");
return -ENODEV;
}
adata->i2s_irq = res->start;
adata->play_stream = NULL;
adata->capture_stream = NULL;
dev_set_drvdata(&pdev->dev, adata);
/* Initialize ACP */
status = acp3x_init(adata->acp3x_base);
if (status)
return -ENODEV;
status = devm_snd_soc_register_component(&pdev->dev,
&acp3x_i2s_component,
&acp3x_i2s_dai_driver, 1);
if (status) {
dev_err(&pdev->dev, "Fail to register acp i2s dai\n");
goto dev_err;
}
status = devm_request_irq(&pdev->dev, adata->i2s_irq, i2s_irq_handler,
irqflags, "ACP3x_I2S_IRQ", adata);
if (status) {
dev_err(&pdev->dev, "ACP3x I2S IRQ request failed\n");
goto dev_err;
}
pm_runtime_set_autosuspend_delay(&pdev->dev, 10000);
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_enable(&pdev->dev);
return 0;
dev_err:
status = acp3x_deinit(adata->acp3x_base);
if (status)
dev_err(&pdev->dev, "ACP de-init failed\n");
else
dev_info(&pdev->dev, "ACP de-initialized\n");
/*ignore device status and return driver probe error*/
return -ENODEV;
}
static int acp3x_audio_remove(struct platform_device *pdev)
{
int ret;
struct i2s_dev_data *adata = dev_get_drvdata(&pdev->dev);
ret = acp3x_deinit(adata->acp3x_base);
if (ret)
dev_err(&pdev->dev, "ACP de-init failed\n");
else
dev_info(&pdev->dev, "ACP de-initialized\n");
pm_runtime_disable(&pdev->dev);
return 0;
}
static int acp3x_resume(struct device *dev)
{
int status;
u32 val;
struct i2s_dev_data *adata = dev_get_drvdata(dev);
status = acp3x_init(adata->acp3x_base);
if (status)
return -ENODEV;
if (adata->play_stream && adata->play_stream->runtime) {
struct i2s_stream_instance *rtd =
adata->play_stream->runtime->private_data;
config_acp3x_dma(rtd, SNDRV_PCM_STREAM_PLAYBACK);
rv_writel((rtd->xfer_resolution << 3),
rtd->acp3x_base + mmACP_BTTDM_ITER);
if (adata->tdm_mode == true) {
rv_writel(adata->tdm_fmt, adata->acp3x_base +
mmACP_BTTDM_TXFRMT);
val = rv_readl(adata->acp3x_base + mmACP_BTTDM_ITER);
rv_writel((val | 0x2), adata->acp3x_base +
mmACP_BTTDM_ITER);
}
}
if (adata->capture_stream && adata->capture_stream->runtime) {
struct i2s_stream_instance *rtd =
adata->capture_stream->runtime->private_data;
config_acp3x_dma(rtd, SNDRV_PCM_STREAM_CAPTURE);
rv_writel((rtd->xfer_resolution << 3),
rtd->acp3x_base + mmACP_BTTDM_IRER);
if (adata->tdm_mode == true) {
rv_writel(adata->tdm_fmt, adata->acp3x_base +
mmACP_BTTDM_RXFRMT);
val = rv_readl(adata->acp3x_base + mmACP_BTTDM_IRER);
rv_writel((val | 0x2), adata->acp3x_base +
mmACP_BTTDM_IRER);
}
}
rv_writel(1, adata->acp3x_base + mmACP_EXTERNAL_INTR_ENB);
return 0;
}
static int acp3x_pcm_runtime_suspend(struct device *dev)
{
int status;
struct i2s_dev_data *adata = dev_get_drvdata(dev);
status = acp3x_deinit(adata->acp3x_base);
if (status)
dev_err(dev, "ACP de-init failed\n");
else
dev_info(dev, "ACP de-initialized\n");
rv_writel(0, adata->acp3x_base + mmACP_EXTERNAL_INTR_ENB);
return 0;
}
static int acp3x_pcm_runtime_resume(struct device *dev)
{
int status;
struct i2s_dev_data *adata = dev_get_drvdata(dev);
status = acp3x_init(adata->acp3x_base);
if (status)
return -ENODEV;
rv_writel(1, adata->acp3x_base + mmACP_EXTERNAL_INTR_ENB);
return 0;
}
static const struct dev_pm_ops acp3x_pm_ops = {
.runtime_suspend = acp3x_pcm_runtime_suspend,
.runtime_resume = acp3x_pcm_runtime_resume,
.resume = acp3x_resume,
};
static struct platform_driver acp3x_dma_driver = {
.probe = acp3x_audio_probe,
.remove = acp3x_audio_remove,
.driver = {
.name = "acp3x_rv_i2s",
.pm = &acp3x_pm_ops,
},
};
module_platform_driver(acp3x_dma_driver);
MODULE_AUTHOR("Maruthi.Bayyavarapu@amd.com");
MODULE_AUTHOR("Vijendar.Mukunda@amd.com");
MODULE_DESCRIPTION("AMD ACP 3.x PCM Driver");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:" DRV_NAME);

View File

@@ -0,0 +1,58 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* AMD ALSA SoC PCM Driver
*
* Copyright 2016 Advanced Micro Devices, Inc.
*/
#include "chip_offset_byte.h"
#define ACP3x_PHY_BASE_ADDRESS 0x1240000
#define ACP3x_I2S_MODE 0
#define ACP3x_REG_START 0x1240000
#define ACP3x_REG_END 0x1250200
#define I2S_MODE 0x04
#define BT_TX_THRESHOLD 26
#define BT_RX_THRESHOLD 25
#define ACP3x_POWER_ON 0x00
#define ACP3x_POWER_ON_IN_PROGRESS 0x01
#define ACP3x_POWER_OFF 0x02
#define ACP3x_POWER_OFF_IN_PROGRESS 0x03
#define ACP3x_SOFT_RESET__SoftResetAudDone_MASK 0x00010001
#define ACP_SRAM_PTE_OFFSET 0x02050000
#define PAGE_SIZE_4K_ENABLE 0x2
#define MEM_WINDOW_START 0x4000000
#define PLAYBACK_FIFO_ADDR_OFFSET 0x400
#define CAPTURE_FIFO_ADDR_OFFSET 0x500
#define PLAYBACK_MIN_NUM_PERIODS 2
#define PLAYBACK_MAX_NUM_PERIODS 8
#define PLAYBACK_MAX_PERIOD_SIZE 16384
#define PLAYBACK_MIN_PERIOD_SIZE 4096
#define CAPTURE_MIN_NUM_PERIODS 2
#define CAPTURE_MAX_NUM_PERIODS 8
#define CAPTURE_MAX_PERIOD_SIZE 16384
#define CAPTURE_MIN_PERIOD_SIZE 4096
#define MAX_BUFFER (PLAYBACK_MAX_PERIOD_SIZE * PLAYBACK_MAX_NUM_PERIODS)
#define MIN_BUFFER MAX_BUFFER
#define FIFO_SIZE 0x100
#define DMA_SIZE 0x40
#define FRM_LEN 0x100
#define SLOT_WIDTH_8 0x08
#define SLOT_WIDTH_16 0x10
#define SLOT_WIDTH_24 0x18
#define SLOT_WIDTH_32 0x20
static inline u32 rv_readl(void __iomem *base_addr)
{
return readl(base_addr - ACP3x_PHY_BASE_ADDRESS);
}
static inline void rv_writel(u32 val, void __iomem *base_addr)
{
writel(val, base_addr - ACP3x_PHY_BASE_ADDRESS);
}

View File

@@ -0,0 +1,639 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* AMD ACP 3.0 Register Documentation
*
* Copyright 2016 Advanced Micro Devices, Inc.
*/
#ifndef _acp_ip_OFFSET_HEADER
#define _acp_ip_OFFSET_HEADER
// Registers from ACP_DMA block
#define mmACP_DMA_CNTL_0 0x1240000
#define mmACP_DMA_CNTL_1 0x1240004
#define mmACP_DMA_CNTL_2 0x1240008
#define mmACP_DMA_CNTL_3 0x124000C
#define mmACP_DMA_CNTL_4 0x1240010
#define mmACP_DMA_CNTL_5 0x1240014
#define mmACP_DMA_CNTL_6 0x1240018
#define mmACP_DMA_CNTL_7 0x124001C
#define mmACP_DMA_DSCR_STRT_IDX_0 0x1240020
#define mmACP_DMA_DSCR_STRT_IDX_1 0x1240024
#define mmACP_DMA_DSCR_STRT_IDX_2 0x1240028
#define mmACP_DMA_DSCR_STRT_IDX_3 0x124002C
#define mmACP_DMA_DSCR_STRT_IDX_4 0x1240030
#define mmACP_DMA_DSCR_STRT_IDX_5 0x1240034
#define mmACP_DMA_DSCR_STRT_IDX_6 0x1240038
#define mmACP_DMA_DSCR_STRT_IDX_7 0x124003C
#define mmACP_DMA_DSCR_CNT_0 0x1240040
#define mmACP_DMA_DSCR_CNT_1 0x1240044
#define mmACP_DMA_DSCR_CNT_2 0x1240048
#define mmACP_DMA_DSCR_CNT_3 0x124004C
#define mmACP_DMA_DSCR_CNT_4 0x1240050
#define mmACP_DMA_DSCR_CNT_5 0x1240054
#define mmACP_DMA_DSCR_CNT_6 0x1240058
#define mmACP_DMA_DSCR_CNT_7 0x124005C
#define mmACP_DMA_PRIO_0 0x1240060
#define mmACP_DMA_PRIO_1 0x1240064
#define mmACP_DMA_PRIO_2 0x1240068
#define mmACP_DMA_PRIO_3 0x124006C
#define mmACP_DMA_PRIO_4 0x1240070
#define mmACP_DMA_PRIO_5 0x1240074
#define mmACP_DMA_PRIO_6 0x1240078
#define mmACP_DMA_PRIO_7 0x124007C
#define mmACP_DMA_CUR_DSCR_0 0x1240080
#define mmACP_DMA_CUR_DSCR_1 0x1240084
#define mmACP_DMA_CUR_DSCR_2 0x1240088
#define mmACP_DMA_CUR_DSCR_3 0x124008C
#define mmACP_DMA_CUR_DSCR_4 0x1240090
#define mmACP_DMA_CUR_DSCR_5 0x1240094
#define mmACP_DMA_CUR_DSCR_6 0x1240098
#define mmACP_DMA_CUR_DSCR_7 0x124009C
#define mmACP_DMA_CUR_TRANS_CNT_0 0x12400A0
#define mmACP_DMA_CUR_TRANS_CNT_1 0x12400A4
#define mmACP_DMA_CUR_TRANS_CNT_2 0x12400A8
#define mmACP_DMA_CUR_TRANS_CNT_3 0x12400AC
#define mmACP_DMA_CUR_TRANS_CNT_4 0x12400B0
#define mmACP_DMA_CUR_TRANS_CNT_5 0x12400B4
#define mmACP_DMA_CUR_TRANS_CNT_6 0x12400B8
#define mmACP_DMA_CUR_TRANS_CNT_7 0x12400BC
#define mmACP_DMA_ERR_STS_0 0x12400C0
#define mmACP_DMA_ERR_STS_1 0x12400C4
#define mmACP_DMA_ERR_STS_2 0x12400C8
#define mmACP_DMA_ERR_STS_3 0x12400CC
#define mmACP_DMA_ERR_STS_4 0x12400D0
#define mmACP_DMA_ERR_STS_5 0x12400D4
#define mmACP_DMA_ERR_STS_6 0x12400D8
#define mmACP_DMA_ERR_STS_7 0x12400DC
#define mmACP_DMA_DESC_BASE_ADDR 0x12400E0
#define mmACP_DMA_DESC_MAX_NUM_DSCR 0x12400E4
#define mmACP_DMA_CH_STS 0x12400E8
#define mmACP_DMA_CH_GROUP 0x12400EC
#define mmACP_DMA_CH_RST_STS 0x12400F0
// Registers from ACP_AXI2AXIATU block
#define mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_1 0x1240C00
#define mmACPAXI2AXI_ATU_BASE_ADDR_GRP_1 0x1240C04
#define mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_2 0x1240C08
#define mmACPAXI2AXI_ATU_BASE_ADDR_GRP_2 0x1240C0C
#define mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_3 0x1240C10
#define mmACPAXI2AXI_ATU_BASE_ADDR_GRP_3 0x1240C14
#define mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_4 0x1240C18
#define mmACPAXI2AXI_ATU_BASE_ADDR_GRP_4 0x1240C1C
#define mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_5 0x1240C20
#define mmACPAXI2AXI_ATU_BASE_ADDR_GRP_5 0x1240C24
#define mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_6 0x1240C28
#define mmACPAXI2AXI_ATU_BASE_ADDR_GRP_6 0x1240C2C
#define mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_7 0x1240C30
#define mmACPAXI2AXI_ATU_BASE_ADDR_GRP_7 0x1240C34
#define mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_8 0x1240C38
#define mmACPAXI2AXI_ATU_BASE_ADDR_GRP_8 0x1240C3C
#define mmACPAXI2AXI_ATU_CTRL 0x1240C40
// Registers from ACP_CLKRST block
#define mmACP_SOFT_RESET 0x1241000
#define mmACP_CONTROL 0x1241004
#define mmACP_STATUS 0x1241008
#define mmACP_DSP0_OCD_HALT_ON_RST 0x124100C
#define mmACP_DYNAMIC_CG_MASTER_CONTROL 0x1241010
// Registers from ACP_MISC block
#define mmACP_EXTERNAL_INTR_ENB 0x1241800
#define mmACP_EXTERNAL_INTR_CNTL 0x1241804
#define mmACP_EXTERNAL_INTR_STAT 0x1241808
#define mmACP_DSP0_INTR_CNTL 0x124180C
#define mmACP_DSP0_INTR_STAT 0x1241810
#define mmACP_DSP_SW_INTR_CNTL 0x1241814
#define mmACP_DSP_SW_INTR_STAT 0x1241818
#define mmACP_SW_INTR_TRIG 0x124181C
#define mmACP_SMU_MAILBOX 0x1241820
#define mmDSP_INTERRUPT_ROUTING_CTRL 0x1241824
#define mmACP_DSP0_WATCHDOG_TIMER_CNTL 0x1241828
#define mmACP_DSP0_EXT_TIMER1_CNTL 0x124182C
#define mmACP_DSP0_EXT_TIMER2_CNTL 0x1241830
#define mmACP_DSP0_EXT_TIMER3_CNTL 0x1241834
#define mmACP_DSP0_EXT_TIMER4_CNTL 0x1241838
#define mmACP_DSP0_EXT_TIMER5_CNTL 0x124183C
#define mmACP_DSP0_EXT_TIMER6_CNTL 0x1241840
#define mmACP_DSP0_EXT_TIMER1_CURR_VALUE 0x1241844
#define mmACP_DSP0_EXT_TIMER2_CURR_VALUE 0x1241848
#define mmACP_DSP0_EXT_TIMER3_CURR_VALUE 0x124184C
#define mmACP_DSP0_EXT_TIMER4_CURR_VALUE 0x1241850
#define mmACP_DSP0_EXT_TIMER5_CURR_VALUE 0x1241854
#define mmACP_DSP0_EXT_TIMER6_CURR_VALUE 0x1241858
#define mmACP_FW_STATUS 0x124185C
#define mmACP_TIMER 0x1241874
#define mmACP_TIMER_CNTL 0x1241878
#define mmACP_PGMEM_CTRL 0x12418C0
#define mmACP_ERROR_STATUS 0x12418C4
#define mmACP_SW_I2S_ERROR_REASON 0x12418C8
#define mmACP_MEM_PG_STS 0x12418CC
// Registers from ACP_PGFSM block
#define mmACP_I2S_PIN_CONFIG 0x1241400
#define mmACP_PAD_PULLUP_PULLDOWN_CTRL 0x1241404
#define mmACP_PAD_DRIVE_STRENGTH_CTRL 0x1241408
#define mmACP_SW_PAD_KEEPER_EN 0x124140C
#define mmACP_SW_WAKE_EN 0x1241410
#define mmACP_I2S_WAKE_EN 0x1241414
#define mmACP_PME_EN 0x1241418
#define mmACP_PGFSM_CONTROL 0x124141C
#define mmACP_PGFSM_STATUS 0x1241420
// Registers from ACP_SCRATCH block
#define mmACP_SCRATCH_REG_0 0x1250000
#define mmACP_SCRATCH_REG_1 0x1250004
#define mmACP_SCRATCH_REG_2 0x1250008
#define mmACP_SCRATCH_REG_3 0x125000C
#define mmACP_SCRATCH_REG_4 0x1250010
#define mmACP_SCRATCH_REG_5 0x1250014
#define mmACP_SCRATCH_REG_6 0x1250018
#define mmACP_SCRATCH_REG_7 0x125001C
#define mmACP_SCRATCH_REG_8 0x1250020
#define mmACP_SCRATCH_REG_9 0x1250024
#define mmACP_SCRATCH_REG_10 0x1250028
#define mmACP_SCRATCH_REG_11 0x125002C
#define mmACP_SCRATCH_REG_12 0x1250030
#define mmACP_SCRATCH_REG_13 0x1250034
#define mmACP_SCRATCH_REG_14 0x1250038
#define mmACP_SCRATCH_REG_15 0x125003C
#define mmACP_SCRATCH_REG_16 0x1250040
#define mmACP_SCRATCH_REG_17 0x1250044
#define mmACP_SCRATCH_REG_18 0x1250048
#define mmACP_SCRATCH_REG_19 0x125004C
#define mmACP_SCRATCH_REG_20 0x1250050
#define mmACP_SCRATCH_REG_21 0x1250054
#define mmACP_SCRATCH_REG_22 0x1250058
#define mmACP_SCRATCH_REG_23 0x125005C
#define mmACP_SCRATCH_REG_24 0x1250060
#define mmACP_SCRATCH_REG_25 0x1250064
#define mmACP_SCRATCH_REG_26 0x1250068
#define mmACP_SCRATCH_REG_27 0x125006C
#define mmACP_SCRATCH_REG_28 0x1250070
#define mmACP_SCRATCH_REG_29 0x1250074
#define mmACP_SCRATCH_REG_30 0x1250078
#define mmACP_SCRATCH_REG_31 0x125007C
#define mmACP_SCRATCH_REG_32 0x1250080
#define mmACP_SCRATCH_REG_33 0x1250084
#define mmACP_SCRATCH_REG_34 0x1250088
#define mmACP_SCRATCH_REG_35 0x125008C
#define mmACP_SCRATCH_REG_36 0x1250090
#define mmACP_SCRATCH_REG_37 0x1250094
#define mmACP_SCRATCH_REG_38 0x1250098
#define mmACP_SCRATCH_REG_39 0x125009C
#define mmACP_SCRATCH_REG_40 0x12500A0
#define mmACP_SCRATCH_REG_41 0x12500A4
#define mmACP_SCRATCH_REG_42 0x12500A8
#define mmACP_SCRATCH_REG_43 0x12500AC
#define mmACP_SCRATCH_REG_44 0x12500B0
#define mmACP_SCRATCH_REG_45 0x12500B4
#define mmACP_SCRATCH_REG_46 0x12500B8
#define mmACP_SCRATCH_REG_47 0x12500BC
#define mmACP_SCRATCH_REG_48 0x12500C0
#define mmACP_SCRATCH_REG_49 0x12500C4
#define mmACP_SCRATCH_REG_50 0x12500C8
#define mmACP_SCRATCH_REG_51 0x12500CC
#define mmACP_SCRATCH_REG_52 0x12500D0
#define mmACP_SCRATCH_REG_53 0x12500D4
#define mmACP_SCRATCH_REG_54 0x12500D8
#define mmACP_SCRATCH_REG_55 0x12500DC
#define mmACP_SCRATCH_REG_56 0x12500E0
#define mmACP_SCRATCH_REG_57 0x12500E4
#define mmACP_SCRATCH_REG_58 0x12500E8
#define mmACP_SCRATCH_REG_59 0x12500EC
#define mmACP_SCRATCH_REG_60 0x12500F0
#define mmACP_SCRATCH_REG_61 0x12500F4
#define mmACP_SCRATCH_REG_62 0x12500F8
#define mmACP_SCRATCH_REG_63 0x12500FC
#define mmACP_SCRATCH_REG_64 0x1250100
#define mmACP_SCRATCH_REG_65 0x1250104
#define mmACP_SCRATCH_REG_66 0x1250108
#define mmACP_SCRATCH_REG_67 0x125010C
#define mmACP_SCRATCH_REG_68 0x1250110
#define mmACP_SCRATCH_REG_69 0x1250114
#define mmACP_SCRATCH_REG_70 0x1250118
#define mmACP_SCRATCH_REG_71 0x125011C
#define mmACP_SCRATCH_REG_72 0x1250120
#define mmACP_SCRATCH_REG_73 0x1250124
#define mmACP_SCRATCH_REG_74 0x1250128
#define mmACP_SCRATCH_REG_75 0x125012C
#define mmACP_SCRATCH_REG_76 0x1250130
#define mmACP_SCRATCH_REG_77 0x1250134
#define mmACP_SCRATCH_REG_78 0x1250138
#define mmACP_SCRATCH_REG_79 0x125013C
#define mmACP_SCRATCH_REG_80 0x1250140
#define mmACP_SCRATCH_REG_81 0x1250144
#define mmACP_SCRATCH_REG_82 0x1250148
#define mmACP_SCRATCH_REG_83 0x125014C
#define mmACP_SCRATCH_REG_84 0x1250150
#define mmACP_SCRATCH_REG_85 0x1250154
#define mmACP_SCRATCH_REG_86 0x1250158
#define mmACP_SCRATCH_REG_87 0x125015C
#define mmACP_SCRATCH_REG_88 0x1250160
#define mmACP_SCRATCH_REG_89 0x1250164
#define mmACP_SCRATCH_REG_90 0x1250168
#define mmACP_SCRATCH_REG_91 0x125016C
#define mmACP_SCRATCH_REG_92 0x1250170
#define mmACP_SCRATCH_REG_93 0x1250174
#define mmACP_SCRATCH_REG_94 0x1250178
#define mmACP_SCRATCH_REG_95 0x125017C
#define mmACP_SCRATCH_REG_96 0x1250180
#define mmACP_SCRATCH_REG_97 0x1250184
#define mmACP_SCRATCH_REG_98 0x1250188
#define mmACP_SCRATCH_REG_99 0x125018C
#define mmACP_SCRATCH_REG_100 0x1250190
#define mmACP_SCRATCH_REG_101 0x1250194
#define mmACP_SCRATCH_REG_102 0x1250198
#define mmACP_SCRATCH_REG_103 0x125019C
#define mmACP_SCRATCH_REG_104 0x12501A0
#define mmACP_SCRATCH_REG_105 0x12501A4
#define mmACP_SCRATCH_REG_106 0x12501A8
#define mmACP_SCRATCH_REG_107 0x12501AC
#define mmACP_SCRATCH_REG_108 0x12501B0
#define mmACP_SCRATCH_REG_109 0x12501B4
#define mmACP_SCRATCH_REG_110 0x12501B8
#define mmACP_SCRATCH_REG_111 0x12501BC
#define mmACP_SCRATCH_REG_112 0x12501C0
#define mmACP_SCRATCH_REG_113 0x12501C4
#define mmACP_SCRATCH_REG_114 0x12501C8
#define mmACP_SCRATCH_REG_115 0x12501CC
#define mmACP_SCRATCH_REG_116 0x12501D0
#define mmACP_SCRATCH_REG_117 0x12501D4
#define mmACP_SCRATCH_REG_118 0x12501D8
#define mmACP_SCRATCH_REG_119 0x12501DC
#define mmACP_SCRATCH_REG_120 0x12501E0
#define mmACP_SCRATCH_REG_121 0x12501E4
#define mmACP_SCRATCH_REG_122 0x12501E8
#define mmACP_SCRATCH_REG_123 0x12501EC
#define mmACP_SCRATCH_REG_124 0x12501F0
#define mmACP_SCRATCH_REG_125 0x12501F4
#define mmACP_SCRATCH_REG_126 0x12501F8
#define mmACP_SCRATCH_REG_127 0x12501FC
#define mmACP_SCRATCH_REG_128 0x1250200
// Registers from ACP_SW_ACLK block
#define mmSW_CORB_Base_Address 0x1243200
#define mmSW_CORB_Write_Pointer 0x1243204
#define mmSW_CORB_Read_Pointer 0x1243208
#define mmSW_CORB_Control 0x124320C
#define mmSW_CORB_Size 0x1243214
#define mmSW_RIRB_Base_Address 0x1243218
#define mmSW_RIRB_Write_Pointer 0x124321C
#define mmSW_RIRB_Response_Interrupt_Count 0x1243220
#define mmSW_RIRB_Control 0x1243224
#define mmSW_RIRB_Size 0x1243228
#define mmSW_RIRB_FIFO_MIN_THDL 0x124322C
#define mmSW_imm_cmd_UPPER_WORD 0x1243230
#define mmSW_imm_cmd_LOWER_QWORD 0x1243234
#define mmSW_imm_resp_UPPER_WORD 0x1243238
#define mmSW_imm_resp_LOWER_QWORD 0x124323C
#define mmSW_imm_cmd_sts 0x1243240
#define mmSW_BRA_BASE_ADDRESS 0x1243244
#define mmSW_BRA_TRANSFER_SIZE 0x1243248
#define mmSW_BRA_DMA_BUSY 0x124324C
#define mmSW_BRA_RESP 0x1243250
#define mmSW_BRA_RESP_FRAME_ADDR 0x1243254
#define mmSW_BRA_CURRENT_TRANSFER_SIZE 0x1243258
#define mmSW_STATE_CHANGE_STATUS_0TO7 0x124325C
#define mmSW_STATE_CHANGE_STATUS_8TO11 0x1243260
#define mmSW_STATE_CHANGE_STATUS_MASK_0to7 0x1243264
#define mmSW_STATE_CHANGE_STATUS_MASK_8to11 0x1243268
#define mmSW_CLK_FREQUENCY_CTRL 0x124326C
#define mmSW_ERROR_INTR_MASK 0x1243270
#define mmSW_PHY_TEST_MODE_DATA_OFF 0x1243274
// Registers from ACP_SW_SWCLK block
#define mmACP_SW_EN 0x1243000
#define mmACP_SW_EN_STATUS 0x1243004
#define mmACP_SW_FRAMESIZE 0x1243008
#define mmACP_SW_SSP_Counter 0x124300C
#define mmACP_SW_Audio_TX_EN 0x1243010
#define mmACP_SW_Audio_TX_EN_STATUS 0x1243014
#define mmACP_SW_Audio_TX_Frame_Format 0x1243018
#define mmACP_SW_Audio_TX_SampleInterval 0x124301C
#define mmACP_SW_Audio_TX_Hctrl_DP0 0x1243020
#define mmACP_SW_Audio_TX_Hctrl_DP1 0x1243024
#define mmACP_SW_Audio_TX_Hctrl_DP2 0x1243028
#define mmACP_SW_Audio_TX_Hctrl_DP3 0x124302C
#define mmACP_SW_Audio_TX_offset_DP0 0x1243030
#define mmACP_SW_Audio_TX_offset_DP1 0x1243034
#define mmACP_SW_Audio_TX_offset_DP2 0x1243038
#define mmACP_SW_Audio_TX_offset_DP3 0x124303C
#define mmACP_SW_Audio_TX_Channel_Enable_DP0 0x1243040
#define mmACP_SW_Audio_TX_Channel_Enable_DP1 0x1243044
#define mmACP_SW_Audio_TX_Channel_Enable_DP2 0x1243048
#define mmACP_SW_Audio_TX_Channel_Enable_DP3 0x124304C
#define mmACP_SW_BT_TX_EN 0x1243050
#define mmACP_SW_BT_TX_EN_STATUS 0x1243054
#define mmACP_SW_BT_TX_Frame_Format 0x1243058
#define mmACP_SW_BT_TX_SampleInterval 0x124305C
#define mmACP_SW_BT_TX_Hctrl 0x1243060
#define mmACP_SW_BT_TX_offset 0x1243064
#define mmACP_SW_BT_TX_Channel_Enable_DP0 0x1243068
#define mmACP_SW_Headset_TX_EN 0x124306C
#define mmACP_SW_Headset_TX_EN_STATUS 0x1243070
#define mmACP_SW_Headset_TX_Frame_Format 0x1243074
#define mmACP_SW_Headset_TX_SampleInterval 0x1243078
#define mmACP_SW_Headset_TX_Hctrl 0x124307C
#define mmACP_SW_Headset_TX_offset 0x1243080
#define mmACP_SW_Headset_TX_Channel_Enable_DP0 0x1243084
#define mmACP_SW_Audio_RX_EN 0x1243088
#define mmACP_SW_Audio_RX_EN_STATUS 0x124308C
#define mmACP_SW_Audio_RX_Frame_Format 0x1243090
#define mmACP_SW_Audio_RX_SampleInterval 0x1243094
#define mmACP_SW_Audio_RX_Hctrl_DP0 0x1243098
#define mmACP_SW_Audio_RX_Hctrl_DP1 0x124309C
#define mmACP_SW_Audio_RX_Hctrl_DP2 0x1243100
#define mmACP_SW_Audio_RX_Hctrl_DP3 0x1243104
#define mmACP_SW_Audio_RX_offset_DP0 0x1243108
#define mmACP_SW_Audio_RX_offset_DP1 0x124310C
#define mmACP_SW_Audio_RX_offset_DP2 0x1243110
#define mmACP_SW_Audio_RX_offset_DP3 0x1243114
#define mmACP_SW_Audio_RX_Channel_Enable_DP0 0x1243118
#define mmACP_SW_Audio_RX_Channel_Enable_DP1 0x124311C
#define mmACP_SW_Audio_RX_Channel_Enable_DP2 0x1243120
#define mmACP_SW_Audio_RX_Channel_Enable_DP3 0x1243124
#define mmACP_SW_BT_RX_EN 0x1243128
#define mmACP_SW_BT_RX_EN_STATUS 0x124312C
#define mmACP_SW_BT_RX_Frame_Format 0x1243130
#define mmACP_SW_BT_RX_SampleInterval 0x1243134
#define mmACP_SW_BT_RX_Hctrl 0x1243138
#define mmACP_SW_BT_RX_offset 0x124313C
#define mmACP_SW_BT_RX_Channel_Enable_DP0 0x1243140
#define mmACP_SW_Headset_RX_EN 0x1243144
#define mmACP_SW_Headset_RX_EN_STATUS 0x1243148
#define mmACP_SW_Headset_RX_Frame_Format 0x124314C
#define mmACP_SW_Headset_RX_SampleInterval 0x1243150
#define mmACP_SW_Headset_RX_Hctrl 0x1243154
#define mmACP_SW_Headset_RX_offset 0x1243158
#define mmACP_SW_Headset_RX_Channel_Enable_DP0 0x124315C
#define mmACP_SW_BPT_PORT_EN 0x1243160
#define mmACP_SW_BPT_PORT_EN_STATUS 0x1243164
#define mmACP_SW_BPT_PORT_Frame_Format 0x1243168
#define mmACP_SW_BPT_PORT_SampleInterval 0x124316C
#define mmACP_SW_BPT_PORT_Hctrl 0x1243170
#define mmACP_SW_BPT_PORT_offset 0x1243174
#define mmACP_SW_BPT_PORT_Channel_Enable 0x1243178
#define mmACP_SW_BPT_PORT_First_byte_addr 0x124317C
#define mmACP_SW_CLK_RESUME_CTRL 0x1243180
#define mmACP_SW_CLK_RESUME_Delay_Cntr 0x1243184
#define mmACP_SW_BUS_RESET_CTRL 0x1243188
#define mmACP_SW_PRBS_ERR_STATUS 0x124318C
// Registers from ACP_AUDIO_BUFFERS block
#define mmACP_I2S_RX_RINGBUFADDR 0x1242000
#define mmACP_I2S_RX_RINGBUFSIZE 0x1242004
#define mmACP_I2S_RX_LINKPOSITIONCNTR 0x1242008
#define mmACP_I2S_RX_FIFOADDR 0x124200C
#define mmACP_I2S_RX_FIFOSIZE 0x1242010
#define mmACP_I2S_RX_DMA_SIZE 0x1242014
#define mmACP_I2S_RX_LINEARPOSITIONCNTR_HIGH 0x1242018
#define mmACP_I2S_RX_LINEARPOSITIONCNTR_LOW 0x124201C
#define mmACP_I2S_RX_INTR_WATERMARK_SIZE 0x1242020
#define mmACP_I2S_TX_RINGBUFADDR 0x1242024
#define mmACP_I2S_TX_RINGBUFSIZE 0x1242028
#define mmACP_I2S_TX_LINKPOSITIONCNTR 0x124202C
#define mmACP_I2S_TX_FIFOADDR 0x1242030
#define mmACP_I2S_TX_FIFOSIZE 0x1242034
#define mmACP_I2S_TX_DMA_SIZE 0x1242038
#define mmACP_I2S_TX_LINEARPOSITIONCNTR_HIGH 0x124203C
#define mmACP_I2S_TX_LINEARPOSITIONCNTR_LOW 0x1242040
#define mmACP_I2S_TX_INTR_WATERMARK_SIZE 0x1242044
#define mmACP_BT_RX_RINGBUFADDR 0x1242048
#define mmACP_BT_RX_RINGBUFSIZE 0x124204C
#define mmACP_BT_RX_LINKPOSITIONCNTR 0x1242050
#define mmACP_BT_RX_FIFOADDR 0x1242054
#define mmACP_BT_RX_FIFOSIZE 0x1242058
#define mmACP_BT_RX_DMA_SIZE 0x124205C
#define mmACP_BT_RX_LINEARPOSITIONCNTR_HIGH 0x1242060
#define mmACP_BT_RX_LINEARPOSITIONCNTR_LOW 0x1242064
#define mmACP_BT_RX_INTR_WATERMARK_SIZE 0x1242068
#define mmACP_BT_TX_RINGBUFADDR 0x124206C
#define mmACP_BT_TX_RINGBUFSIZE 0x1242070
#define mmACP_BT_TX_LINKPOSITIONCNTR 0x1242074
#define mmACP_BT_TX_FIFOADDR 0x1242078
#define mmACP_BT_TX_FIFOSIZE 0x124207C
#define mmACP_BT_TX_DMA_SIZE 0x1242080
#define mmACP_BT_TX_LINEARPOSITIONCNTR_HIGH 0x1242084
#define mmACP_BT_TX_LINEARPOSITIONCNTR_LOW 0x1242088
#define mmACP_BT_TX_INTR_WATERMARK_SIZE 0x124208C
#define mmACP_HS_RX_RINGBUFADDR 0x1242090
#define mmACP_HS_RX_RINGBUFSIZE 0x1242094
#define mmACP_HS_RX_LINKPOSITIONCNTR 0x1242098
#define mmACP_HS_RX_FIFOADDR 0x124209C
#define mmACP_HS_RX_FIFOSIZE 0x12420A0
#define mmACP_HS_RX_DMA_SIZE 0x12420A4
#define mmACP_HS_RX_LINEARPOSITIONCNTR_HIGH 0x12420A8
#define mmACP_HS_RX_LINEARPOSITIONCNTR_LOW 0x12420AC
#define mmACP_HS_RX_INTR_WATERMARK_SIZE 0x12420B0
#define mmACP_HS_TX_RINGBUFADDR 0x12420B4
#define mmACP_HS_TX_RINGBUFSIZE 0x12420B8
#define mmACP_HS_TX_LINKPOSITIONCNTR 0x12420BC
#define mmACP_HS_TX_FIFOADDR 0x12420C0
#define mmACP_HS_TX_FIFOSIZE 0x12420C4
#define mmACP_HS_TX_DMA_SIZE 0x12420C8
#define mmACP_HS_TX_LINEARPOSITIONCNTR_HIGH 0x12420CC
#define mmACP_HS_TX_LINEARPOSITIONCNTR_LOW 0x12420D0
#define mmACP_HS_TX_INTR_WATERMARK_SIZE 0x12420D4
// Registers from ACP_I2S_TDM block
#define mmACP_I2STDM_IER 0x1242400
#define mmACP_I2STDM_IRER 0x1242404
#define mmACP_I2STDM_RXFRMT 0x1242408
#define mmACP_I2STDM_ITER 0x124240C
#define mmACP_I2STDM_TXFRMT 0x1242410
// Registers from ACP_BT_TDM block
#define mmACP_BTTDM_IER 0x1242800
#define mmACP_BTTDM_IRER 0x1242804
#define mmACP_BTTDM_RXFRMT 0x1242808
#define mmACP_BTTDM_ITER 0x124280C
#define mmACP_BTTDM_TXFRMT 0x1242810
// Registers from AZALIA_IP block
#define mmAudio_Az_Global_Capabilities 0x1200000
#define mmAudio_Az_Minor_Version 0x1200002
#define mmAudio_Az_Major_Version 0x1200003
#define mmAudio_Az_Output_Payload_Capability 0x1200004
#define mmAudio_Az_Input_Payload_Capability 0x1200006
#define mmAudio_Az_Global_Control 0x1200008
#define mmAudio_Az_Wake_Enable 0x120000C
#define mmAudio_Az_State_Change_Status 0x120000E
#define mmAudio_Az_Global_Status 0x1200010
#define mmAudio_Az_Linked_List_Capability_Header 0x1200014
#define mmAudio_Az_Output_Stream_Payload_Capability 0x1200018
#define mmAudio_Az_Input_Stream_Payload_Capability 0x120001A
#define mmAudio_Az_Interrupt_Control 0x1200020
#define mmAudio_Az_Interrupt_Status 0x1200024
#define mmAudio_Az_Wall_Clock_Counter 0x1200030
#define mmAudio_Az_Stream_Synchronization 0x1200038
#define mmAudio_Az_CORB_Lower_Base_Address 0x1200040
#define mmAudio_Az_CORB_Upper_Base_Address 0x1200044
#define mmAudio_Az_CORB_Write_Pointer 0x1200048
#define mmAudio_Az_CORB_Read_Pointer 0x120004A
#define mmAudio_Az_CORB_Control 0x120004C
#define mmAudio_Az_CORB_Status 0x120004D
#define mmAudio_Az_CORB_Size 0x120004E
#define mmAudio_Az_RIRB_Lower_Base_Address 0x1200050
#define mmAudio_Az_RIRB_Upper_Base_Address 0x1200054
#define mmAudio_Az_RIRB_Write_Pointer 0x1200058
#define mmAudio_Az_RIRB_Response_Interrupt_Count 0x120005A
#define mmAudio_Az_RIRB_Control 0x120005C
#define mmAudio_Az_RIRB_Status 0x120005D
#define mmAudio_Az_RIRB_Size 0x120005E
#define mmAudio_Az_Immediate_Command_Output_Interface 0x1200060
#define mmAudio_Az_Immediate_Response_Input_Interface 0x1200064
#define mmAudio_Az_Immediate_Command_Status 0x1200068
#define mmAudio_Az_DPLBASE 0x1200070
#define mmAudio_Az_DPUBASE 0x1200074
#define mmAudio_Az_Input_SD0CTL_and_STS 0x1200080
#define mmAudio_Az_Input_SD0LPIB 0x1200084
#define mmAudio_Az_Input_SD0CBL 0x1200088
#define mmAudio_Az_Input_SD0LVI 0x120008C
#define mmAudio_Az_Input_SD0FIFOS 0x1200090
#define mmAudio_Az_Input_SD0FMT 0x1200092
#define mmAudio_Az_Input_SD0BDPL 0x1200098
#define mmAudio_Az_Input_SD0BDPU 0x120009C
#define mmAudio_Az_Input_SD1CTL_and_STS 0x12000A0
#define mmAudio_Az_Input_SD1LPIB 0x12000A4
#define mmAudio_Az_Input_SD1CBL 0x12000A8
#define mmAudio_Az_Input_SD1LVI 0x12000AC
#define mmAudio_Az_Input_SD1FIFOS 0x12000B0
#define mmAudio_Az_Input_SD1FMT 0x12000B2
#define mmAudio_Az_Input_SD1BDPL 0x12000B8
#define mmAudio_Az_Input_SD1BDPU 0x12000BC
#define mmAudio_Az_Input_SD2CTL_and_STS 0x12000C0
#define mmAudio_Az_Input_SD2LPIB 0x12000C4
#define mmAudio_Az_Input_SD2CBL 0x12000C8
#define mmAudio_Az_Input_SD2LVI 0x12000CC
#define mmAudio_Az_Input_SD2FIFOS 0x12000D0
#define mmAudio_Az_Input_SD2FMT 0x12000D2
#define mmAudio_Az_Input_SD2BDPL 0x12000D8
#define mmAudio_Az_Input_SD2BDPU 0x12000DC
#define mmAudio_Az_Input_SD3CTL_and_STS 0x12000E0
#define mmAudio_Az_Input_SD3LPIB 0x12000E4
#define mmAudio_Az_Input_SD3CBL 0x12000E8
#define mmAudio_Az_Input_SD3LVI 0x12000EC
#define mmAudio_Az_Input_SD3FIFOS 0x12000F0
#define mmAudio_Az_Input_SD3FMT 0x12000F2
#define mmAudio_Az_Input_SD3BDPL 0x12000F8
#define mmAudio_Az_Input_SD3BDPU 0x12000FC
#define mmAudio_Az_Output_SD0CTL_and_STS 0x1200100
#define mmAudio_Az_Output_SD0LPIB 0x1200104
#define mmAudio_Az_Output_SD0CBL 0x1200108
#define mmAudio_Az_Output_SD0LVI 0x120010C
#define mmAudio_Az_Output_SD0FIFOS 0x1200110
#define mmAudio_Az_Output_SD0FMT 0x1200112
#define mmAudio_Az_Output_SD0BDPL 0x1200118
#define mmAudio_Az_Output_SD0BDPU 0x120011C
#define mmAudio_Az_Output_SD1CTL_and_STS 0x1200120
#define mmAudio_Az_Output_SD1LPIB 0x1200124
#define mmAudio_Az_Output_SD1CBL 0x1200128
#define mmAudio_Az_Output_SD1LVI 0x120012C
#define mmAudio_Az_Output_SD1FIFOS 0x1200130
#define mmAudio_Az_Output_SD1FMT 0x1200132
#define mmAudio_Az_Output_SD1BDPL 0x1200138
#define mmAudio_Az_Output_SD1BDPU 0x120013C
#define mmAudio_Az_Output_SD2CTL_and_STS 0x1200140
#define mmAudio_Az_Output_SD2LPIB 0x1200144
#define mmAudio_Az_Output_SD2CBL 0x1200148
#define mmAudio_Az_Output_SD2LVI 0x120014C
#define mmAudio_Az_Output_SD2FIFOS 0x1200150
#define mmAudio_Az_Output_SD2FMT 0x1200152
#define mmAudio_Az_Output_SD2BDPL 0x1200158
#define mmAudio_Az_Output_SD2BDPU 0x120015C
#define mmAudio_Az_Output_SD3CTL_and_STS 0x1200160
#define mmAudio_Az_Output_SD3LPIB 0x1200164
#define mmAudio_Az_Output_SD3CBL 0x1200168
#define mmAudio_Az_Output_SD3LVI 0x120016C
#define mmAudio_Az_Output_SD3FIFOS 0x1200170
#define mmAudio_Az_Output_SD3FMT 0x1200172
#define mmAudio_Az_Output_SD3BDPL 0x1200178
#define mmAudio_Az_Output_SD3BDPU 0x120017C
#define mmAudioAZ_Misc_Control_Register_1 0x1200180
#define mmAudioAZ_Misc_Control_Register_2 0x1200182
#define mmAudioAZ_Misc_Control_Register_3 0x1200183
#define mmAudio_AZ_Multiple_Links_Capability_Header 0x1200200
#define mmAudio_AZ_Multiple_Links_Capability_Declaration 0x1200204
#define mmAudio_AZ_Link0_Capabilities 0x1200240
#define mmAudio_AZ_Link0_Control 0x1200244
#define mmAudio_AZ_Link0_Output_Stream_ID 0x1200248
#define mmAudio_AZ_Link0_SDI_Identifier 0x120024C
#define mmAudio_AZ_Link0_Per_Stream_Overhead 0x1200250
#define mmAudio_AZ_Link0_Wall_Frame_Counter 0x1200258
#define mmAudio_AZ_Link0_Output_Payload_Capability_L 0x1200260
#define mmAudio_AZ_Link0_Output_Payload_Capability_U 0x1200264
#define mmAudio_AZ_Link0_Input_Payload_Capability_L 0x1200270
#define mmAudio_AZ_Link0_Input_Payload_Capability_U 0x1200274
#define mmAudio_Az_Input_SD0LICBA 0x1202084
#define mmAudio_Az_Input_SD1LICBA 0x12020A4
#define mmAudio_Az_Input_SD2LICBA 0x12020C4
#define mmAudio_Az_Input_SD3LICBA 0x12020E4
#define mmAudio_Az_Output_SD0LICBA 0x1202104
#define mmAudio_Az_Output_SD1LICBA 0x1202124
#define mmAudio_Az_Output_SD2LICBA 0x1202144
#define mmAudio_Az_Output_SD3LICBA 0x1202164
#define mmAUDIO_AZ_POWER_MANAGEMENT_CONTROL 0x1204000
#define mmAUDIO_AZ_IOC_SOFTRST_CONTROL 0x1204004
#define mmAUDIO_AZ_IOC_CLKGATE_CONTROL 0x1204008
// Registers from ACP_AZALIA block
#define mmACP_AZ_PAGE0_LBASE_ADDR 0x1243800
#define mmACP_AZ_PAGE0_UBASE_ADDR 0x1243804
#define mmACP_AZ_PAGE0_PGEN_SIZE 0x1243808
#define mmACP_AZ_PAGE0_OFFSET 0x124380C
#define mmACP_AZ_PAGE1_LBASE_ADDR 0x1243810
#define mmACP_AZ_PAGE1_UBASE_ADDR 0x1243814
#define mmACP_AZ_PAGE1_PGEN_SIZE 0x1243818
#define mmACP_AZ_PAGE1_OFFSET 0x124381C
#define mmACP_AZ_PAGE2_LBASE_ADDR 0x1243820
#define mmACP_AZ_PAGE2_UBASE_ADDR 0x1243824
#define mmACP_AZ_PAGE2_PGEN_SIZE 0x1243828
#define mmACP_AZ_PAGE2_OFFSET 0x124382C
#define mmACP_AZ_PAGE3_LBASE_ADDR 0x1243830
#define mmACP_AZ_PAGE3_UBASE_ADDR 0x1243834
#define mmACP_AZ_PAGE3_PGEN_SIZE 0x1243838
#define mmACP_AZ_PAGE3_OFFSET 0x124383C
#define mmACP_AZ_PAGE4_LBASE_ADDR 0x1243840
#define mmACP_AZ_PAGE4_UBASE_ADDR 0x1243844
#define mmACP_AZ_PAGE4_PGEN_SIZE 0x1243848
#define mmACP_AZ_PAGE4_OFFSET 0x124384C
#define mmACP_AZ_PAGE5_LBASE_ADDR 0x1243850
#define mmACP_AZ_PAGE5_UBASE_ADDR 0x1243854
#define mmACP_AZ_PAGE5_PGEN_SIZE 0x1243858
#define mmACP_AZ_PAGE5_OFFSET 0x124385C
#define mmACP_AZ_PAGE6_LBASE_ADDR 0x1243860
#define mmACP_AZ_PAGE6_UBASE_ADDR 0x1243864
#define mmACP_AZ_PAGE6_PGEN_SIZE 0x1243868
#define mmACP_AZ_PAGE6_OFFSET 0x124386C
#define mmACP_AZ_PAGE7_LBASE_ADDR 0x1243870
#define mmACP_AZ_PAGE7_UBASE_ADDR 0x1243874
#define mmACP_AZ_PAGE7_PGEN_SIZE 0x1243878
#define mmACP_AZ_PAGE7_OFFSET 0x124387C
#endif

View File

@@ -0,0 +1,156 @@
// SPDX-License-Identifier: GPL-2.0+
//
// AMD ACP PCI Driver
//
//Copyright 2016 Advanced Micro Devices, Inc.
#include <linux/pci.h>
#include <linux/module.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include "acp3x.h"
struct acp3x_dev_data {
void __iomem *acp3x_base;
bool acp3x_audio_mode;
struct resource *res;
struct platform_device *pdev;
};
static int snd_acp3x_probe(struct pci_dev *pci,
const struct pci_device_id *pci_id)
{
int ret;
u32 addr, val;
struct acp3x_dev_data *adata;
struct platform_device_info pdevinfo;
unsigned int irqflags;
if (pci_enable_device(pci)) {
dev_err(&pci->dev, "pci_enable_device failed\n");
return -ENODEV;
}
ret = pci_request_regions(pci, "AMD ACP3x audio");
if (ret < 0) {
dev_err(&pci->dev, "pci_request_regions failed\n");
goto disable_pci;
}
adata = devm_kzalloc(&pci->dev, sizeof(struct acp3x_dev_data),
GFP_KERNEL);
if (!adata) {
ret = -ENOMEM;
goto release_regions;
}
/* check for msi interrupt support */
ret = pci_enable_msi(pci);
if (ret)
/* msi is not enabled */
irqflags = IRQF_SHARED;
else
/* msi is enabled */
irqflags = 0;
addr = pci_resource_start(pci, 0);
adata->acp3x_base = ioremap(addr, pci_resource_len(pci, 0));
if (!adata->acp3x_base) {
ret = -ENOMEM;
goto release_regions;
}
pci_set_master(pci);
pci_set_drvdata(pci, adata);
val = rv_readl(adata->acp3x_base + mmACP_I2S_PIN_CONFIG);
switch (val) {
case I2S_MODE:
adata->res = devm_kzalloc(&pci->dev,
sizeof(struct resource) * 2,
GFP_KERNEL);
if (!adata->res) {
ret = -ENOMEM;
goto unmap_mmio;
}
adata->res[0].name = "acp3x_i2s_iomem";
adata->res[0].flags = IORESOURCE_MEM;
adata->res[0].start = addr;
adata->res[0].end = addr + (ACP3x_REG_END - ACP3x_REG_START);
adata->res[1].name = "acp3x_i2s_irq";
adata->res[1].flags = IORESOURCE_IRQ;
adata->res[1].start = pci->irq;
adata->res[1].end = pci->irq;
adata->acp3x_audio_mode = ACP3x_I2S_MODE;
memset(&pdevinfo, 0, sizeof(pdevinfo));
pdevinfo.name = "acp3x_rv_i2s";
pdevinfo.id = 0;
pdevinfo.parent = &pci->dev;
pdevinfo.num_res = 2;
pdevinfo.res = adata->res;
pdevinfo.data = &irqflags;
pdevinfo.size_data = sizeof(irqflags);
adata->pdev = platform_device_register_full(&pdevinfo);
if (IS_ERR(adata->pdev)) {
dev_err(&pci->dev, "cannot register %s device\n",
pdevinfo.name);
ret = PTR_ERR(adata->pdev);
goto unmap_mmio;
}
break;
default:
dev_err(&pci->dev, "Invalid ACP audio mode : %d\n", val);
ret = -ENODEV;
goto unmap_mmio;
}
return 0;
unmap_mmio:
pci_disable_msi(pci);
iounmap(adata->acp3x_base);
release_regions:
pci_release_regions(pci);
disable_pci:
pci_disable_device(pci);
return ret;
}
static void snd_acp3x_remove(struct pci_dev *pci)
{
struct acp3x_dev_data *adata = pci_get_drvdata(pci);
platform_device_unregister(adata->pdev);
iounmap(adata->acp3x_base);
pci_disable_msi(pci);
pci_release_regions(pci);
pci_disable_device(pci);
}
static const struct pci_device_id snd_acp3x_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x15e2),
.class = PCI_CLASS_MULTIMEDIA_OTHER << 8,
.class_mask = 0xffffff },
{ 0, },
};
MODULE_DEVICE_TABLE(pci, snd_acp3x_ids);
static struct pci_driver acp3x_driver = {
.name = KBUILD_MODNAME,
.id_table = snd_acp3x_ids,
.probe = snd_acp3x_probe,
.remove = snd_acp3x_remove,
};
module_pci_driver(acp3x_driver);
MODULE_AUTHOR("Maruthi.Bayyavarapu@amd.com");
MODULE_DESCRIPTION("AMD ACP3x PCI driver");
MODULE_LICENSE("GPL v2");

View File

@@ -35,6 +35,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_ADAU7002
select SND_SOC_ADS117X
select SND_SOC_AK4104 if SPI_MASTER
select SND_SOC_AK4118 if I2C
select SND_SOC_AK4458 if I2C
select SND_SOC_AK4535 if I2C
select SND_SOC_AK4554
@@ -392,6 +393,11 @@ config SND_SOC_AK4104
tristate "AKM AK4104 CODEC"
depends on SPI_MASTER
config SND_SOC_AK4118
tristate "AKM AK4118 CODEC"
depends on I2C
select REGMAP_I2C
config SND_SOC_AK4458
tristate "AKM AK4458 CODEC"
depends on I2C

View File

@@ -27,6 +27,7 @@ snd-soc-adav801-objs := adav801.o
snd-soc-adav803-objs := adav803.o
snd-soc-ads117x-objs := ads117x.o
snd-soc-ak4104-objs := ak4104.o
snd-soc-ak4118-objs := ak4118.o
snd-soc-ak4458-objs := ak4458.o
snd-soc-ak4535-objs := ak4535.o
snd-soc-ak4554-objs := ak4554.o
@@ -290,6 +291,7 @@ obj-$(CONFIG_SND_SOC_ADAV801) += snd-soc-adav801.o
obj-$(CONFIG_SND_SOC_ADAV803) += snd-soc-adav803.o
obj-$(CONFIG_SND_SOC_ADS117X) += snd-soc-ads117x.o
obj-$(CONFIG_SND_SOC_AK4104) += snd-soc-ak4104.o
obj-$(CONFIG_SND_SOC_AK4118) += snd-soc-ak4118.o
obj-$(CONFIG_SND_SOC_AK4458) += snd-soc-ak4458.o
obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o
obj-$(CONFIG_SND_SOC_AK4554) += snd-soc-ak4554.o

View File

@@ -13,7 +13,7 @@
#include <linux/slab.h>
#include <linux/spi/spi.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/regulator/consumer.h>
#include <sound/asoundef.h>
#include <sound/core.h>
@@ -268,8 +268,8 @@ static const struct regmap_config ak4104_regmap = {
static int ak4104_spi_probe(struct spi_device *spi)
{
struct device_node *np = spi->dev.of_node;
struct ak4104_private *ak4104;
struct gpio_desc *reset_gpiod;
unsigned int val;
int ret;
@@ -297,19 +297,11 @@ static int ak4104_spi_probe(struct spi_device *spi)
return ret;
}
if (np) {
enum of_gpio_flags flags;
int gpio = of_get_named_gpio_flags(np, "reset-gpio", 0, &flags);
if (gpio_is_valid(gpio)) {
ret = devm_gpio_request_one(&spi->dev, gpio,
flags & OF_GPIO_ACTIVE_LOW ?
GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH,
"ak4104 reset");
if (ret < 0)
return ret;
}
}
reset_gpiod = devm_gpiod_get_optional(&spi->dev, "reset",
GPIOD_OUT_HIGH);
if (IS_ERR(reset_gpiod) &&
PTR_ERR(reset_gpiod) == -EPROBE_DEFER)
return -EPROBE_DEFER;
/* read the 'reserved' register - according to the datasheet, it
* should contain 0x5b. Not a good way to verify the presence of

438
sound/soc/codecs/ak4118.c Normal file
View File

@@ -0,0 +1,438 @@
// SPDX-License-Identifier: GPL-2.0
/*
* ak4118.c -- Asahi Kasei ALSA Soc Audio driver
*
* Copyright 2018 DEVIALET
*/
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <sound/asoundef.h>
#include <sound/core.h>
#include <sound/initval.h>
#include <sound/soc.h>
#define AK4118_REG_CLK_PWR_CTL 0x00
#define AK4118_REG_FORMAT_CTL 0x01
#define AK4118_REG_IO_CTL0 0x02
#define AK4118_REG_IO_CTL1 0x03
#define AK4118_REG_INT0_MASK 0x04
#define AK4118_REG_INT1_MASK 0x05
#define AK4118_REG_RCV_STATUS0 0x06
#define AK4118_REG_RCV_STATUS1 0x07
#define AK4118_REG_RXCHAN_STATUS0 0x08
#define AK4118_REG_RXCHAN_STATUS1 0x09
#define AK4118_REG_RXCHAN_STATUS2 0x0a
#define AK4118_REG_RXCHAN_STATUS3 0x0b
#define AK4118_REG_RXCHAN_STATUS4 0x0c
#define AK4118_REG_TXCHAN_STATUS0 0x0d
#define AK4118_REG_TXCHAN_STATUS1 0x0e
#define AK4118_REG_TXCHAN_STATUS2 0x0f
#define AK4118_REG_TXCHAN_STATUS3 0x10
#define AK4118_REG_TXCHAN_STATUS4 0x11
#define AK4118_REG_BURST_PREAMB_PC0 0x12
#define AK4118_REG_BURST_PREAMB_PC1 0x13
#define AK4118_REG_BURST_PREAMB_PD0 0x14
#define AK4118_REG_BURST_PREAMB_PD1 0x15
#define AK4118_REG_QSUB_CTL 0x16
#define AK4118_REG_QSUB_TRACK 0x17
#define AK4118_REG_QSUB_INDEX 0x18
#define AK4118_REG_QSUB_MIN 0x19
#define AK4118_REG_QSUB_SEC 0x1a
#define AK4118_REG_QSUB_FRAME 0x1b
#define AK4118_REG_QSUB_ZERO 0x1c
#define AK4118_REG_QSUB_ABS_MIN 0x1d
#define AK4118_REG_QSUB_ABS_SEC 0x1e
#define AK4118_REG_QSUB_ABS_FRAME 0x1f
#define AK4118_REG_GPE 0x20
#define AK4118_REG_GPDR 0x21
#define AK4118_REG_GPSCR 0x22
#define AK4118_REG_GPLR 0x23
#define AK4118_REG_DAT_MASK_DTS 0x24
#define AK4118_REG_RX_DETECT 0x25
#define AK4118_REG_STC_DAT_DETECT 0x26
#define AK4118_REG_RXCHAN_STATUS5 0x27
#define AK4118_REG_TXCHAN_STATUS5 0x28
#define AK4118_REG_MAX 0x29
#define AK4118_REG_FORMAT_CTL_DIF0 (1 << 4)
#define AK4118_REG_FORMAT_CTL_DIF1 (1 << 5)
#define AK4118_REG_FORMAT_CTL_DIF2 (1 << 6)
struct ak4118_priv {
struct regmap *regmap;
struct gpio_desc *reset;
struct gpio_desc *irq;
struct snd_soc_component *component;
};
static const struct reg_default ak4118_reg_defaults[] = {
{AK4118_REG_CLK_PWR_CTL, 0x43},
{AK4118_REG_FORMAT_CTL, 0x6a},
{AK4118_REG_IO_CTL0, 0x88},
{AK4118_REG_IO_CTL1, 0x48},
{AK4118_REG_INT0_MASK, 0xee},
{AK4118_REG_INT1_MASK, 0xb5},
{AK4118_REG_RCV_STATUS0, 0x00},
{AK4118_REG_RCV_STATUS1, 0x10},
{AK4118_REG_TXCHAN_STATUS0, 0x00},
{AK4118_REG_TXCHAN_STATUS1, 0x00},
{AK4118_REG_TXCHAN_STATUS2, 0x00},
{AK4118_REG_TXCHAN_STATUS3, 0x00},
{AK4118_REG_TXCHAN_STATUS4, 0x00},
{AK4118_REG_GPE, 0x77},
{AK4118_REG_GPDR, 0x00},
{AK4118_REG_GPSCR, 0x00},
{AK4118_REG_GPLR, 0x00},
{AK4118_REG_DAT_MASK_DTS, 0x3f},
{AK4118_REG_RX_DETECT, 0x00},
{AK4118_REG_STC_DAT_DETECT, 0x00},
{AK4118_REG_TXCHAN_STATUS5, 0x00},
};
static const char * const ak4118_input_select_txt[] = {
"RX0", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7",
};
static SOC_ENUM_SINGLE_DECL(ak4118_insel_enum, AK4118_REG_IO_CTL1, 0x0,
ak4118_input_select_txt);
static const struct snd_kcontrol_new ak4118_input_mux_controls =
SOC_DAPM_ENUM("Input Select", ak4118_insel_enum);
static const char * const ak4118_iec958_fs_txt[] = {
"44100", "48000", "32000", "22050", "11025", "24000", "16000", "88200",
"8000", "96000", "64000", "176400", "192000",
};
static const int ak4118_iec958_fs_val[] = {
0x0, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xE,
};
static SOC_VALUE_ENUM_SINGLE_DECL(ak4118_iec958_fs_enum, AK4118_REG_RCV_STATUS1,
0x4, 0x4, ak4118_iec958_fs_txt,
ak4118_iec958_fs_val);
static struct snd_kcontrol_new ak4118_iec958_controls[] = {
SOC_SINGLE("IEC958 Parity Errors", AK4118_REG_RCV_STATUS0, 0, 1, 0),
SOC_SINGLE("IEC958 No Audio", AK4118_REG_RCV_STATUS0, 1, 1, 0),
SOC_SINGLE("IEC958 PLL Lock", AK4118_REG_RCV_STATUS0, 4, 1, 1),
SOC_SINGLE("IEC958 Non PCM", AK4118_REG_RCV_STATUS0, 6, 1, 0),
SOC_ENUM("IEC958 Sampling Freq", ak4118_iec958_fs_enum),
};
static const struct snd_soc_dapm_widget ak4118_dapm_widgets[] = {
SND_SOC_DAPM_INPUT("INRX0"),
SND_SOC_DAPM_INPUT("INRX1"),
SND_SOC_DAPM_INPUT("INRX2"),
SND_SOC_DAPM_INPUT("INRX3"),
SND_SOC_DAPM_INPUT("INRX4"),
SND_SOC_DAPM_INPUT("INRX5"),
SND_SOC_DAPM_INPUT("INRX6"),
SND_SOC_DAPM_INPUT("INRX7"),
SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0,
&ak4118_input_mux_controls),
};
static const struct snd_soc_dapm_route ak4118_dapm_routes[] = {
{"Input Mux", "RX0", "INRX0"},
{"Input Mux", "RX1", "INRX1"},
{"Input Mux", "RX2", "INRX2"},
{"Input Mux", "RX3", "INRX3"},
{"Input Mux", "RX4", "INRX4"},
{"Input Mux", "RX5", "INRX5"},
{"Input Mux", "RX6", "INRX6"},
{"Input Mux", "RX7", "INRX7"},
};
static int ak4118_set_dai_fmt_master(struct ak4118_priv *ak4118,
unsigned int format)
{
int dif;
switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
dif = AK4118_REG_FORMAT_CTL_DIF0 | AK4118_REG_FORMAT_CTL_DIF2;
break;
case SND_SOC_DAIFMT_RIGHT_J:
dif = AK4118_REG_FORMAT_CTL_DIF0 | AK4118_REG_FORMAT_CTL_DIF1;
break;
case SND_SOC_DAIFMT_LEFT_J:
dif = AK4118_REG_FORMAT_CTL_DIF2;
break;
default:
return -ENOTSUPP;
}
return dif;
}
static int ak4118_set_dai_fmt_slave(struct ak4118_priv *ak4118,
unsigned int format)
{
int dif;
switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
dif = AK4118_REG_FORMAT_CTL_DIF0 | AK4118_REG_FORMAT_CTL_DIF1 |
AK4118_REG_FORMAT_CTL_DIF2;
break;
case SND_SOC_DAIFMT_LEFT_J:
dif = AK4118_REG_FORMAT_CTL_DIF1 | AK4118_REG_FORMAT_CTL_DIF2;
break;
default:
return -ENOTSUPP;
}
return dif;
}
static int ak4118_set_dai_fmt(struct snd_soc_dai *dai,
unsigned int format)
{
struct snd_soc_component *component = dai->component;
struct ak4118_priv *ak4118 = snd_soc_component_get_drvdata(component);
int dif;
int ret = 0;
switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM:
/* component is master */
dif = ak4118_set_dai_fmt_master(ak4118, format);
break;
case SND_SOC_DAIFMT_CBS_CFS:
/*component is slave */
dif = ak4118_set_dai_fmt_slave(ak4118, format);
break;
default:
ret = -ENOTSUPP;
goto exit;
}
/* format not supported */
if (dif < 0) {
ret = dif;
goto exit;
}
ret = regmap_update_bits(ak4118->regmap, AK4118_REG_FORMAT_CTL,
AK4118_REG_FORMAT_CTL_DIF0 |
AK4118_REG_FORMAT_CTL_DIF1 |
AK4118_REG_FORMAT_CTL_DIF2, dif);
if (ret < 0)
goto exit;
exit:
return ret;
}
static int ak4118_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
return 0;
}
static const struct snd_soc_dai_ops ak4118_dai_ops = {
.hw_params = ak4118_hw_params,
.set_fmt = ak4118_set_dai_fmt,
};
static struct snd_soc_dai_driver ak4118_dai = {
.name = "ak4118-hifi",
.capture = {
.stream_name = "Capture",
.channels_min = 2,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_3LE |
SNDRV_PCM_FMTBIT_S24_LE
},
.ops = &ak4118_dai_ops,
};
static irqreturn_t ak4118_irq_handler(int irq, void *data)
{
struct ak4118_priv *ak4118 = data;
struct snd_soc_component *component = ak4118->component;
struct snd_kcontrol_new *kctl_new;
struct snd_kcontrol *kctl;
struct snd_ctl_elem_id *id;
unsigned int i;
if (!component)
return IRQ_NONE;
for (i = 0; i < ARRAY_SIZE(ak4118_iec958_controls); i++) {
kctl_new = &ak4118_iec958_controls[i];
kctl = snd_soc_card_get_kcontrol(component->card,
kctl_new->name);
if (!kctl)
continue;
id = &kctl->id;
snd_ctl_notify(component->card->snd_card,
SNDRV_CTL_EVENT_MASK_VALUE, id);
}
return IRQ_HANDLED;
}
static int ak4118_probe(struct snd_soc_component *component)
{
struct ak4118_priv *ak4118 = snd_soc_component_get_drvdata(component);
int ret = 0;
ak4118->component = component;
/* release reset */
gpiod_set_value(ak4118->reset, 0);
/* unmask all int1 sources */
ret = regmap_write(ak4118->regmap, AK4118_REG_INT1_MASK, 0x00);
if (ret < 0) {
dev_err(component->dev,
"failed to write regmap 0x%x 0x%x: %d\n",
AK4118_REG_INT1_MASK, 0x00, ret);
return ret;
}
/* rx detect enable on all channels */
ret = regmap_write(ak4118->regmap, AK4118_REG_RX_DETECT, 0xff);
if (ret < 0) {
dev_err(component->dev,
"failed to write regmap 0x%x 0x%x: %d\n",
AK4118_REG_RX_DETECT, 0xff, ret);
return ret;
}
ret = snd_soc_add_component_controls(component, ak4118_iec958_controls,
ARRAY_SIZE(ak4118_iec958_controls));
if (ret) {
dev_err(component->dev,
"failed to add component kcontrols: %d\n", ret);
return ret;
}
return 0;
}
static void ak4118_remove(struct snd_soc_component *component)
{
struct ak4118_priv *ak4118 = snd_soc_component_get_drvdata(component);
/* hold reset */
gpiod_set_value(ak4118->reset, 1);
}
static const struct snd_soc_component_driver soc_component_drv_ak4118 = {
.probe = ak4118_probe,
.remove = ak4118_remove,
.dapm_widgets = ak4118_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(ak4118_dapm_widgets),
.dapm_routes = ak4118_dapm_routes,
.num_dapm_routes = ARRAY_SIZE(ak4118_dapm_routes),
.idle_bias_on = 1,
.use_pmdown_time = 1,
.endianness = 1,
.non_legacy_dai_naming = 1,
};
static const struct regmap_config ak4118_regmap = {
.reg_bits = 8,
.val_bits = 8,
.reg_defaults = ak4118_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(ak4118_reg_defaults),
.cache_type = REGCACHE_NONE,
.max_register = AK4118_REG_MAX - 1,
};
static int ak4118_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct ak4118_priv *ak4118;
int ret;
ak4118 = devm_kzalloc(&i2c->dev, sizeof(struct ak4118_priv),
GFP_KERNEL);
if (ak4118 == NULL)
return -ENOMEM;
ak4118->regmap = devm_regmap_init_i2c(i2c, &ak4118_regmap);
if (IS_ERR(ak4118->regmap))
return PTR_ERR(ak4118->regmap);
i2c_set_clientdata(i2c, ak4118);
ak4118->reset = devm_gpiod_get(&i2c->dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(ak4118->reset)) {
ret = PTR_ERR(ak4118->reset);
if (ret != -EPROBE_DEFER)
dev_err(&i2c->dev, "Failed to get reset: %d\n", ret);
return ret;
}
ak4118->irq = devm_gpiod_get(&i2c->dev, "irq", GPIOD_IN);
if (IS_ERR(ak4118->irq)) {
ret = PTR_ERR(ak4118->irq);
if (ret != -EPROBE_DEFER)
dev_err(&i2c->dev, "Failed to get IRQ: %d\n", ret);
return ret;
}
ret = devm_request_threaded_irq(&i2c->dev, gpiod_to_irq(ak4118->irq),
NULL, ak4118_irq_handler,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
"ak4118-irq", ak4118);
if (ret < 0) {
dev_err(&i2c->dev, "Fail to request_irq: %d\n", ret);
return ret;
}
return snd_soc_register_component(&i2c->dev, &soc_component_drv_ak4118,
&ak4118_dai, 1);
}
static int ak4118_i2c_remove(struct i2c_client *i2c)
{
snd_soc_unregister_component(&i2c->dev);
return 0;
}
static const struct of_device_id ak4118_of_match[] = {
{ .compatible = "asahi-kasei,ak4118", },
{}
};
MODULE_DEVICE_TABLE(of, ak4118_of_match);
static const struct i2c_device_id ak4118_id_table[] = {
{ "ak4118", 0 },
{}
};
MODULE_DEVICE_TABLE(i2c, ak4118_id_table);
static struct i2c_driver ak4118_i2c_driver = {
.driver = {
.name = "ak4118",
.of_match_table = of_match_ptr(ak4118_of_match),
},
.id_table = ak4118_id_table,
.probe = ak4118_i2c_probe,
.remove = ak4118_i2c_remove,
};
module_i2c_driver(ak4118_i2c_driver);
MODULE_DESCRIPTION("Asahi Kasei AK4118 ALSA SoC driver");
MODULE_AUTHOR("Adrien Charruel <adrien.charruel@devialet.com>");
MODULE_LICENSE("GPL");

View File

@@ -456,7 +456,7 @@ static int ak4458_startup(struct snd_pcm_substream *substream,
return ret;
}
static struct snd_soc_dai_ops ak4458_dai_ops = {
static const struct snd_soc_dai_ops ak4458_dai_ops = {
.startup = ak4458_startup,
.hw_params = ak4458_hw_params,
.set_fmt = ak4458_set_dai_fmt,

View File

@@ -130,16 +130,12 @@ static int ak5558_hw_params(struct snd_pcm_substream *substream,
u8 bits;
int pcm_width = max(params_physical_width(params), ak5558->slot_width);
/* set master/slave audio interface */
bits = snd_soc_component_read32(component, AK5558_02_CONTROL1);
bits &= ~AK5558_BITS;
switch (pcm_width) {
case 16:
bits |= AK5558_DIF_24BIT_MODE;
bits = AK5558_DIF_24BIT_MODE;
break;
case 32:
bits |= AK5558_DIF_32BIT_MODE;
bits = AK5558_DIF_32BIT_MODE;
break;
default:
return -EINVAL;
@@ -168,18 +164,15 @@ static int ak5558_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
}
/* set master/slave audio interface */
format = snd_soc_component_read32(component, AK5558_02_CONTROL1);
format &= ~AK5558_DIF;
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
format |= AK5558_DIF_I2S_MODE;
format = AK5558_DIF_I2S_MODE;
break;
case SND_SOC_DAIFMT_LEFT_J:
format |= AK5558_DIF_MSB_MODE;
format = AK5558_DIF_MSB_MODE;
break;
case SND_SOC_DAIFMT_DSP_B:
format |= AK5558_DIF_MSB_MODE;
format = AK5558_DIF_MSB_MODE;
break;
default:
return -EINVAL;
@@ -246,7 +239,7 @@ static int ak5558_startup(struct snd_pcm_substream *substream,
&ak5558_rate_constraints);
}
static struct snd_soc_dai_ops ak5558_dai_ops = {
static const struct snd_soc_dai_ops ak5558_dai_ops = {
.startup = ak5558_startup,
.hw_params = ak5558_hw_params,

View File

@@ -29,8 +29,8 @@
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/regulator/consumer.h>
#include <linux/gpio/consumer.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
/*
* The codec isn't really big-endian or little-endian, since the I2S
@@ -658,8 +658,8 @@ static const struct regmap_config cs4270_regmap = {
static int cs4270_i2c_probe(struct i2c_client *i2c_client,
const struct i2c_device_id *id)
{
struct device_node *np = i2c_client->dev.of_node;
struct cs4270_private *cs4270;
struct gpio_desc *reset_gpiod;
unsigned int val;
int ret, i;
@@ -678,20 +678,11 @@ static int cs4270_i2c_probe(struct i2c_client *i2c_client,
if (ret < 0)
return ret;
/* See if we have a way to bring the codec out of reset */
if (np) {
enum of_gpio_flags flags;
int gpio = of_get_named_gpio_flags(np, "reset-gpio", 0, &flags);
if (gpio_is_valid(gpio)) {
ret = devm_gpio_request_one(&i2c_client->dev, gpio,
flags & OF_GPIO_ACTIVE_LOW ?
GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH,
"cs4270 reset");
if (ret < 0)
return ret;
}
}
reset_gpiod = devm_gpiod_get_optional(&i2c_client->dev, "reset",
GPIOD_OUT_HIGH);
if (IS_ERR(reset_gpiod) &&
PTR_ERR(reset_gpiod) == -EPROBE_DEFER)
return -EPROBE_DEFER;
cs4270->regmap = devm_regmap_init_i2c(i2c_client, &cs4270_regmap);
if (IS_ERR(cs4270->regmap))

View File

@@ -30,9 +30,39 @@
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#define MAX_MODESWITCH_DELAY 70
static int modeswitch_delay;
module_param(modeswitch_delay, uint, 0644);
static int wakeup_delay;
module_param(wakeup_delay, uint, 0644);
struct dmic {
struct gpio_desc *gpio_en;
int wakeup_delay;
/* Delay after DMIC mode switch */
int modeswitch_delay;
};
int dmic_daiops_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai)
{
struct snd_soc_component *component = dai->component;
struct dmic *dmic = snd_soc_component_get_drvdata(component);
switch (cmd) {
case SNDRV_PCM_TRIGGER_STOP:
if (dmic->modeswitch_delay)
mdelay(dmic->modeswitch_delay);
break;
}
return 0;
}
static const struct snd_soc_dai_ops dmic_dai_ops = {
.trigger = dmic_daiops_trigger,
};
static int dmic_aif_event(struct snd_soc_dapm_widget *w,
@@ -68,6 +98,7 @@ static struct snd_soc_dai_driver dmic_dai = {
| SNDRV_PCM_FMTBIT_S24_LE
| SNDRV_PCM_FMTBIT_S16_LE,
},
.ops = &dmic_dai_ops,
};
static int dmic_component_probe(struct snd_soc_component *component)
@@ -85,6 +116,15 @@ static int dmic_component_probe(struct snd_soc_component *component)
device_property_read_u32(component->dev, "wakeup-delay-ms",
&dmic->wakeup_delay);
device_property_read_u32(component->dev, "modeswitch-delay-ms",
&dmic->modeswitch_delay);
if (wakeup_delay)
dmic->wakeup_delay = wakeup_delay;
if (modeswitch_delay)
dmic->modeswitch_delay = modeswitch_delay;
if (dmic->modeswitch_delay > MAX_MODESWITCH_DELAY)
dmic->modeswitch_delay = MAX_MODESWITCH_DELAY;
snd_soc_component_set_drvdata(component, dmic);

View File

@@ -46,7 +46,7 @@ static int hdac_hda_dai_set_tdm_slot(struct snd_soc_dai *dai,
static struct hda_pcm *snd_soc_find_pcm_from_dai(struct hdac_hda_priv *hda_pvt,
struct snd_soc_dai *dai);
static struct snd_soc_dai_ops hdac_hda_dai_ops = {
static const struct snd_soc_dai_ops hdac_hda_dai_ops = {
.startup = hdac_hda_dai_open,
.shutdown = hdac_hda_dai_close,
.prepare = hdac_hda_dai_prepare,

View File

@@ -121,8 +121,16 @@ struct hdac_hdmi_dai_port_map {
struct hdac_hdmi_cvt *cvt;
};
/*
* pin to port mapping table where the value indicate the pin number and
* the index indicate the port number with 1 base.
*/
static const int icl_pin2port_map[] = {0x4, 0x6, 0x8, 0xa, 0xb};
struct hdac_hdmi_drv_data {
unsigned int vendor_nid;
const int *port_map; /* pin to port mapping table */
int port_num;
};
struct hdac_hdmi_priv {
@@ -1329,11 +1337,12 @@ static int hdac_hdmi_add_pin(struct hdac_device *hdev, hda_nid_t nid)
return 0;
}
#define INTEL_VENDOR_NID 0x08
#define INTEL_GLK_VENDOR_NID 0x0b
#define INTEL_VENDOR_NID_0x2 0x02
#define INTEL_VENDOR_NID_0x8 0x08
#define INTEL_VENDOR_NID_0xb 0x0b
#define INTEL_GET_VENDOR_VERB 0xf81
#define INTEL_SET_VENDOR_VERB 0x781
#define INTEL_EN_DP12 0x02 /* enable DP 1.2 features */
#define INTEL_EN_DP12 0x02 /* enable DP 1.2 features */
#define INTEL_EN_ALL_PIN_CVTS 0x01 /* enable 2nd & 3rd pins and convertors */
static void hdac_hdmi_skl_enable_all_pins(struct hdac_device *hdev)
@@ -1538,7 +1547,26 @@ free_widgets:
static int hdac_hdmi_pin2port(void *aptr, int pin)
{
return pin - 4; /* map NID 0x05 -> port #1 */
struct hdac_device *hdev = aptr;
struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
const int *map = hdmi->drv_data->port_map;
int i;
if (!hdmi->drv_data->port_num)
return pin - 4; /* map NID 0x05 -> port #1 */
/*
* looking for the pin number in the mapping table and return
* the index which indicate the port number
*/
for (i = 0; i < hdmi->drv_data->port_num; i++) {
if (pin == map[i])
return i + 1;
}
/* return -1 if pin number exceeds our expectation */
dev_err(&hdev->dev, "Can't find the port for pin %d\n", pin);
return -1;
}
static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe)
@@ -1549,9 +1577,18 @@ static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe)
struct hdac_hdmi_port *hport = NULL;
struct snd_soc_component *component = hdmi->component;
int i;
hda_nid_t pin_nid;
/* Don't know how this mapping is derived */
hda_nid_t pin_nid = port + 0x04;
if (!hdmi->drv_data->port_num) {
/* for legacy platforms */
pin_nid = port + 0x04;
} else if (port < hdmi->drv_data->port_num) {
/* get pin number from the pin2port mapping table */
pin_nid = hdmi->drv_data->port_map[port - 1];
} else {
dev_err(&hdev->dev, "Can't find the pin for port %d\n", port);
return;
}
dev_dbg(&hdev->dev, "%s: for pin:%d port=%d\n", __func__,
pin_nid, pipe);
@@ -1973,12 +2010,18 @@ static int hdac_hdmi_get_spk_alloc(struct hdac_device *hdev, int pcm_idx)
return port->eld.info.spk_alloc;
}
static struct hdac_hdmi_drv_data intel_icl_drv_data = {
.vendor_nid = INTEL_VENDOR_NID_0x2,
.port_map = icl_pin2port_map,
.port_num = ARRAY_SIZE(icl_pin2port_map),
};
static struct hdac_hdmi_drv_data intel_glk_drv_data = {
.vendor_nid = INTEL_GLK_VENDOR_NID,
.vendor_nid = INTEL_VENDOR_NID_0xb,
};
static struct hdac_hdmi_drv_data intel_drv_data = {
.vendor_nid = INTEL_VENDOR_NID,
.vendor_nid = INTEL_VENDOR_NID_0x8,
};
static int hdac_hdmi_dev_probe(struct hdac_device *hdev)
@@ -2258,6 +2301,8 @@ static const struct hda_device_id hdmi_list[] = {
&intel_glk_drv_data),
HDA_CODEC_EXT_ENTRY(0x8086280d, 0x100000, "Geminilake HDMI",
&intel_glk_drv_data),
HDA_CODEC_EXT_ENTRY(0x8086280f, 0x100000, "Icelake HDMI",
&intel_icl_drv_data),
{}
};

View File

@@ -724,14 +724,39 @@ static struct snd_soc_dai_driver max98373_dai[] = {
}
};
static void max98373_reset(struct max98373_priv *max98373, struct device *dev)
{
int ret, reg, count;
/* Software Reset */
ret = regmap_update_bits(max98373->regmap,
MAX98373_R2000_SW_RESET,
MAX98373_SOFT_RESET,
MAX98373_SOFT_RESET);
if (ret)
dev_err(dev, "Reset command failed. (ret:%d)\n", ret);
count = 0;
while (count < 3) {
usleep_range(10000, 11000);
/* Software Reset Verification */
ret = regmap_read(max98373->regmap,
MAX98373_R21FF_REV_ID, &reg);
if (!ret) {
dev_info(dev, "Reset completed (retry:%d)\n", count);
return;
}
count++;
}
dev_err(dev, "Reset failed. (ret:%d)\n", ret);
}
static int max98373_probe(struct snd_soc_component *component)
{
struct max98373_priv *max98373 = snd_soc_component_get_drvdata(component);
/* Software Reset */
regmap_write(max98373->regmap,
MAX98373_R2000_SW_RESET, MAX98373_SOFT_RESET);
usleep_range(10000, 11000);
max98373_reset(max98373, component->dev);
/* IV default slot configuration */
regmap_write(max98373->regmap,
@@ -818,9 +843,7 @@ static int max98373_resume(struct device *dev)
{
struct max98373_priv *max98373 = dev_get_drvdata(dev);
regmap_write(max98373->regmap,
MAX98373_R2000_SW_RESET, MAX98373_SOFT_RESET);
usleep_range(10000, 11000);
max98373_reset(max98373, dev);
regcache_cache_only(max98373->regmap, false);
regcache_sync(max98373->regmap);
return 0;

View File

@@ -1,12 +1,10 @@
/*
* max9867.c -- max9867 ALSA SoC Audio driver
*
* Copyright 2013-15 Maxim Integrated Products
*
* 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.
*/
// SPDX-License-Identifier: GPL-2.0
//
// MAX9867 ALSA SoC codec driver
//
// Copyright 2013-2015 Maxim Integrated Products
// Copyright 2018 Ladislav Michl <ladis@linux-mips.org>
//
#include <linux/delay.h>
#include <linux/i2c.h>
@@ -23,179 +21,218 @@ static const char *const max9867_spmode[] = {
"Stereo Single", "Mono Single",
"Stereo Single Fast", "Mono Single Fast"
};
static const char *const max9867_sidetone_text[] = {
"None", "Left", "Right", "LeftRight", "LeftRightDiv2",
};
static const char *const max9867_filter_text[] = {"IIR", "FIR"};
static SOC_ENUM_SINGLE_DECL(max9867_filter, MAX9867_CODECFLTR, 7,
max9867_filter_text);
static SOC_ENUM_SINGLE_DECL(max9867_spkmode, MAX9867_MODECONFIG, 0,
max9867_spmode);
static SOC_ENUM_SINGLE_DECL(max9867_sidetone, MAX9867_DACGAIN, 6,
max9867_sidetone_text);
static DECLARE_TLV_DB_SCALE(max9860_capture_tlv, -600, 200, 0);
static DECLARE_TLV_DB_SCALE(max9860_mic_tlv, 2000, 100, 1);
static DECLARE_TLV_DB_SCALE(max9860_adc_left_tlv, -1200, 100, 1);
static DECLARE_TLV_DB_SCALE(max9860_adc_right_tlv, -1200, 100, 1);
static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(max98088_micboost_tlv,
0, 1, TLV_DB_SCALE_ITEM(0, 2000, 0),
2, 2, TLV_DB_SCALE_ITEM(3000, 0, 0),
static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(max9867_master_tlv,
0, 2, TLV_DB_SCALE_ITEM(-8600, 200, 1),
3, 17, TLV_DB_SCALE_ITEM(-7800, 400, 0),
18, 25, TLV_DB_SCALE_ITEM(-2000, 200, 0),
26, 34, TLV_DB_SCALE_ITEM( -500, 100, 0),
35, 40, TLV_DB_SCALE_ITEM( 350, 50, 0),
);
static DECLARE_TLV_DB_SCALE(max9867_mic_tlv, 0, 100, 0);
static DECLARE_TLV_DB_SCALE(max9867_line_tlv, -600, 200, 0);
static DECLARE_TLV_DB_SCALE(max9867_adc_tlv, -1200, 100, 0);
static DECLARE_TLV_DB_SCALE(max9867_dac_tlv, -1500, 100, 0);
static DECLARE_TLV_DB_SCALE(max9867_dacboost_tlv, 0, 600, 0);
static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(max9867_micboost_tlv,
0, 2, TLV_DB_SCALE_ITEM(-2000, 2000, 1),
3, 3, TLV_DB_SCALE_ITEM(3000, 0, 0),
);
static const struct snd_kcontrol_new max9867_snd_controls[] = {
SOC_DOUBLE_R("Master Playback Volume", MAX9867_LEFTVOL,
MAX9867_RIGHTVOL, 0, 63, 1),
SOC_DOUBLE_R_TLV("Capture Volume", MAX9867_LEFTMICGAIN,
MAX9867_RIGHTMICGAIN,
0, 15, 1, max9860_capture_tlv),
SOC_DOUBLE_R_TLV("Mic Volume", MAX9867_LEFTMICGAIN,
MAX9867_RIGHTMICGAIN, 0, 31, 1, max9860_mic_tlv),
SOC_DOUBLE_R_TLV("Mic Boost Volume", MAX9867_LEFTMICGAIN,
MAX9867_RIGHTMICGAIN, 5, 3, 0, max98088_micboost_tlv),
SOC_ENUM("Digital Sidetone Src", max9867_sidetone),
SOC_SINGLE("Sidetone Volume", MAX9867_DACGAIN, 0, 31, 1),
SOC_SINGLE("DAC Volume", MAX9867_DACLEVEL, 4, 3, 0),
SOC_SINGLE("DAC Attenuation", MAX9867_DACLEVEL, 0, 15, 1),
SOC_SINGLE_TLV("ADC Left Volume", MAX9867_ADCLEVEL,
4, 15, 1, max9860_adc_left_tlv),
SOC_SINGLE_TLV("ADC Right Volume", MAX9867_ADCLEVEL,
0, 15, 1, max9860_adc_right_tlv),
SOC_DOUBLE_R_TLV("Master Playback Volume", MAX9867_LEFTVOL,
MAX9867_RIGHTVOL, 0, 41, 1, max9867_master_tlv),
SOC_DOUBLE_R_TLV("Line Capture Volume", MAX9867_LEFTLINELVL,
MAX9867_RIGHTLINELVL, 0, 15, 1, max9867_line_tlv),
SOC_DOUBLE_R_TLV("Mic Capture Volume", MAX9867_LEFTMICGAIN,
MAX9867_RIGHTMICGAIN, 0, 20, 1, max9867_mic_tlv),
SOC_DOUBLE_R_TLV("Mic Boost Capture Volume", MAX9867_LEFTMICGAIN,
MAX9867_RIGHTMICGAIN, 5, 4, 0, max9867_micboost_tlv),
SOC_SINGLE("Digital Sidetone Volume", MAX9867_SIDETONE, 0, 31, 1),
SOC_SINGLE_TLV("Digital Playback Volume", MAX9867_DACLEVEL, 0, 15, 1,
max9867_dac_tlv),
SOC_SINGLE_TLV("Digital Boost Playback Volume", MAX9867_DACLEVEL, 4, 3, 0,
max9867_dacboost_tlv),
SOC_DOUBLE_TLV("Digital Capture Volume", MAX9867_ADCLEVEL, 0, 4, 15, 1,
max9867_adc_tlv),
SOC_ENUM("Speaker Mode", max9867_spkmode),
SOC_SINGLE("Volume Smoothing Switch", MAX9867_MODECONFIG, 6, 1, 0),
SOC_SINGLE("ZCD Switch", MAX9867_MODECONFIG, 5, 1, 0),
SOC_SINGLE("Line ZC Switch", MAX9867_MODECONFIG, 5, 1, 0),
SOC_ENUM("DSP Filter", max9867_filter),
};
static const char *const max9867_mux[] = {"None", "Mic", "Line", "Mic_Line"};
/* Input mixer */
static const struct snd_kcontrol_new max9867_input_mixer_controls[] = {
SOC_DAPM_DOUBLE("Line Capture Switch", MAX9867_INPUTCONFIG, 7, 5, 1, 0),
SOC_DAPM_DOUBLE("Mic Capture Switch", MAX9867_INPUTCONFIG, 6, 4, 1, 0),
};
static SOC_ENUM_SINGLE_DECL(max9867_mux_enum,
MAX9867_INPUTCONFIG, MAX9867_INPUT_SHIFT,
max9867_mux);
/* Output mixer */
static const struct snd_kcontrol_new max9867_output_mixer_controls[] = {
SOC_DAPM_DOUBLE_R("Line Bypass Switch",
MAX9867_LEFTLINELVL, MAX9867_RIGHTLINELVL, 6, 1, 1),
};
static const struct snd_kcontrol_new max9867_dapm_mux_controls =
SOC_DAPM_ENUM("Route", max9867_mux_enum);
/* Sidetone mixer */
static const struct snd_kcontrol_new max9867_sidetone_mixer_controls[] = {
SOC_DAPM_DOUBLE("Sidetone Switch", MAX9867_SIDETONE, 6, 7, 1, 0),
};
/* Line out switch */
static const struct snd_kcontrol_new max9867_line_out_control =
SOC_DAPM_DOUBLE_R("Switch",
MAX9867_LEFTVOL, MAX9867_RIGHTVOL, 6, 1, 1);
static const struct snd_kcontrol_new max9867_left_dapm_control =
SOC_DAPM_SINGLE("Switch", MAX9867_PWRMAN, 6, 1, 0);
static const struct snd_kcontrol_new max9867_right_dapm_control =
SOC_DAPM_SINGLE("Switch", MAX9867_PWRMAN, 5, 1, 0);
static const struct snd_kcontrol_new max9867_line_dapm_control =
SOC_DAPM_SINGLE("Switch", MAX9867_LEFTLINELVL, 6, 1, 1);
static const struct snd_soc_dapm_widget max9867_dapm_widgets[] = {
SND_SOC_DAPM_AIF_IN("DAI_OUT", "HiFi Playback", 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_DAC("Left DAC", NULL, MAX9867_PWRMAN, 3, 0),
SND_SOC_DAPM_DAC("Right DAC", NULL, MAX9867_PWRMAN, 2, 0),
SND_SOC_DAPM_MIXER("Output Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_OUTPUT("HPOUT"),
SND_SOC_DAPM_INPUT("MICL"),
SND_SOC_DAPM_INPUT("MICR"),
SND_SOC_DAPM_INPUT("LINL"),
SND_SOC_DAPM_INPUT("LINR"),
SND_SOC_DAPM_AIF_IN("DAI_IN", "HiFi Capture", 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_ADC("Left ADC", "HiFi Capture", MAX9867_PWRMAN, 1, 0),
SND_SOC_DAPM_ADC("Right ADC", "HiFi Capture", MAX9867_PWRMAN, 0, 0),
SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0,
&max9867_dapm_mux_controls),
SND_SOC_DAPM_PGA("Left Line Input", MAX9867_PWRMAN, 6, 0, NULL, 0),
SND_SOC_DAPM_PGA("Right Line Input", MAX9867_PWRMAN, 5, 0, NULL, 0),
SND_SOC_DAPM_MIXER_NAMED_CTL("Input Mixer", SND_SOC_NOPM, 0, 0,
max9867_input_mixer_controls,
ARRAY_SIZE(max9867_input_mixer_controls)),
SND_SOC_DAPM_ADC("ADCL", "HiFi Capture", MAX9867_PWRMAN, 1, 0),
SND_SOC_DAPM_ADC("ADCR", "HiFi Capture", MAX9867_PWRMAN, 0, 0),
SND_SOC_DAPM_MIXER("Input Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_SWITCH("Left Line", MAX9867_LEFTLINELVL, 6, 1,
&max9867_left_dapm_control),
SND_SOC_DAPM_SWITCH("Right Line", MAX9867_RIGTHLINELVL, 6, 1,
&max9867_right_dapm_control),
SND_SOC_DAPM_SWITCH("Line Mixer", SND_SOC_NOPM, 0, 0,
&max9867_line_dapm_control),
SND_SOC_DAPM_INPUT("LINE_IN"),
SND_SOC_DAPM_MIXER("Digital", SND_SOC_NOPM, 0, 0,
max9867_sidetone_mixer_controls,
ARRAY_SIZE(max9867_sidetone_mixer_controls)),
SND_SOC_DAPM_MIXER_NAMED_CTL("Output Mixer", SND_SOC_NOPM, 0, 0,
max9867_output_mixer_controls,
ARRAY_SIZE(max9867_output_mixer_controls)),
SND_SOC_DAPM_DAC("DACL", "HiFi Playback", MAX9867_PWRMAN, 3, 0),
SND_SOC_DAPM_DAC("DACR", "HiFi Playback", MAX9867_PWRMAN, 2, 0),
SND_SOC_DAPM_SWITCH("Master Playback", SND_SOC_NOPM, 0, 0,
&max9867_line_out_control),
SND_SOC_DAPM_OUTPUT("LOUT"),
SND_SOC_DAPM_OUTPUT("ROUT"),
};
static const struct snd_soc_dapm_route max9867_audio_map[] = {
{"Left DAC", NULL, "DAI_OUT"},
{"Right DAC", NULL, "DAI_OUT"},
{"Output Mixer", NULL, "Left DAC"},
{"Output Mixer", NULL, "Right DAC"},
{"HPOUT", NULL, "Output Mixer"},
{"Left Line Input", NULL, "LINL"},
{"Right Line Input", NULL, "LINR"},
{"Input Mixer", "Mic Capture Switch", "MICL"},
{"Input Mixer", "Mic Capture Switch", "MICR"},
{"Input Mixer", "Line Capture Switch", "Left Line Input"},
{"Input Mixer", "Line Capture Switch", "Right Line Input"},
{"ADCL", NULL, "Input Mixer"},
{"ADCR", NULL, "Input Mixer"},
{"Left ADC", NULL, "DAI_IN"},
{"Right ADC", NULL, "DAI_IN"},
{"Input Mixer", NULL, "Left ADC"},
{"Input Mixer", NULL, "Right ADC"},
{"Input Mux", "Line", "Input Mixer"},
{"Input Mux", "Mic", "Input Mixer"},
{"Input Mux", "Mic_Line", "Input Mixer"},
{"Right Line", "Switch", "Input Mux"},
{"Left Line", "Switch", "Input Mux"},
{"LINE_IN", NULL, "Left Line"},
{"LINE_IN", NULL, "Right Line"},
{"Digital", "Sidetone Switch", "ADCL"},
{"Digital", "Sidetone Switch", "ADCR"},
{"DACL", NULL, "Digital"},
{"DACR", NULL, "Digital"},
{"Output Mixer", "Line Bypass Switch", "Left Line Input"},
{"Output Mixer", "Line Bypass Switch", "Right Line Input"},
{"Output Mixer", NULL, "DACL"},
{"Output Mixer", NULL, "DACR"},
{"Master Playback", "Switch", "Output Mixer"},
{"LOUT", NULL, "Master Playback"},
{"ROUT", NULL, "Master Playback"},
};
enum rates {
pcm_rate_8, pcm_rate_16, pcm_rate_24,
pcm_rate_32, pcm_rate_44,
pcm_rate_48, max_pcm_rate,
static const unsigned int max9867_rates_44k1[] = {
11025, 22050, 44100,
};
static const struct ni_div_rates {
u32 mclk;
u16 ni[max_pcm_rate];
} ni_div[] = {
{11289600, {0x116A, 0x22D4, 0x343F, 0x45A9, 0x6000, 0x687D} },
{12000000, {0x1062, 0x20C5, 0x3127, 0x4189, 0x5A51, 0x624E} },
{12288000, {0x1000, 0x2000, 0x3000, 0x4000, 0x5833, 0x6000} },
{13000000, {0x0F20, 0x1E3F, 0x2D5F, 0x3C7F, 0x535F, 0x5ABE} },
{19200000, {0x0A3D, 0x147B, 0x1EB8, 0x28F6, 0x3873, 0x3D71} },
{24000000, {0x1062, 0x20C5, 0x1893, 0x4189, 0x5A51, 0x624E} },
{26000000, {0x0F20, 0x1E3F, 0x16AF, 0x3C7F, 0x535F, 0x5ABE} },
{27000000, {0x0E90, 0x1D21, 0x15D8, 0x3A41, 0x5048, 0x5762} },
static const struct snd_pcm_hw_constraint_list max9867_constraints_44k1 = {
.list = max9867_rates_44k1,
.count = ARRAY_SIZE(max9867_rates_44k1),
};
static inline int get_ni_value(int mclk, int rate)
static const unsigned int max9867_rates_48k[] = {
8000, 16000, 32000, 48000,
};
static const struct snd_pcm_hw_constraint_list max9867_constraints_48k = {
.list = max9867_rates_48k,
.count = ARRAY_SIZE(max9867_rates_48k),
};
struct max9867_priv {
struct regmap *regmap;
const struct snd_pcm_hw_constraint_list *constraints;
unsigned int sysclk, pclk;
bool master, dsp_a;
};
static int max9867_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
int i, ret = 0;
struct max9867_priv *max9867 =
snd_soc_component_get_drvdata(dai->component);
/* find the closest rate index*/
for (i = 0; i < ARRAY_SIZE(ni_div); i++) {
if (ni_div[i].mclk >= mclk)
break;
}
if (i == ARRAY_SIZE(ni_div))
return -EINVAL;
if (max9867->constraints)
snd_pcm_hw_constraint_list(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_RATE, max9867->constraints);
switch (rate) {
case 8000:
return ni_div[i].ni[pcm_rate_8];
case 16000:
return ni_div[i].ni[pcm_rate_16];
case 32000:
return ni_div[i].ni[pcm_rate_32];
case 44100:
return ni_div[i].ni[pcm_rate_44];
case 48000:
return ni_div[i].ni[pcm_rate_48];
default:
pr_err("%s wrong rate %d\n", __func__, rate);
ret = -EINVAL;
}
return ret;
return 0;
}
static int max9867_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
{
int value;
unsigned long int rate, ratio;
struct snd_soc_component *component = dai->component;
struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component);
unsigned int ni_h, ni_l;
int value;
unsigned int ni = DIV_ROUND_CLOSEST_ULL(96ULL * 0x10000 * params_rate(params),
max9867->pclk);
value = get_ni_value(max9867->sysclk, params_rate(params));
if (value < 0)
return value;
ni_h = (0xFF00 & value) >> 8;
ni_l = 0x00FF & value;
/* set up the ni value */
regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKHIGH,
MAX9867_NI_HIGH_MASK, ni_h);
MAX9867_NI_HIGH_MASK, (0xFF00 & ni) >> 8);
regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKLOW,
MAX9867_NI_LOW_MASK, ni_l);
if (!max9867->master) {
MAX9867_NI_LOW_MASK, 0x00FF & ni);
if (max9867->master) {
if (max9867->dsp_a) {
value = MAX9867_IFC1B_48X;
} else {
rate = params_rate(params) * 2 * params_width(params);
ratio = max9867->pclk / rate;
switch (params_width(params)) {
case 8:
case 16:
switch (ratio) {
case 2:
value = MAX9867_IFC1B_PCLK_2;
break;
case 4:
value = MAX9867_IFC1B_PCLK_4;
break;
case 8:
value = MAX9867_IFC1B_PCLK_8;
break;
case 16:
value = MAX9867_IFC1B_PCLK_16;
break;
default:
return -EINVAL;
}
break;
case 24:
value = MAX9867_IFC1B_48X;
break;
case 32:
value = MAX9867_IFC1B_64X;
break;
default:
return -EINVAL;
}
}
regmap_update_bits(max9867->regmap, MAX9867_IFC1B,
MAX9867_IFC1B_BCLK_MASK, value);
} else {
/*
* digital pll locks on to any externally supplied LRCLK signal
* and also enable rapid lock mode.
@@ -204,73 +241,17 @@ static int max9867_dai_hw_params(struct snd_pcm_substream *substream,
MAX9867_RAPID_LOCK, MAX9867_RAPID_LOCK);
regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKHIGH,
MAX9867_PLL, MAX9867_PLL);
} else {
unsigned long int bclk_rate, pclk_bclk_ratio;
int bclk_value;
bclk_rate = params_rate(params) * 2 * params_width(params);
pclk_bclk_ratio = max9867->pclk/bclk_rate;
switch (params_width(params)) {
case 8:
case 16:
switch (pclk_bclk_ratio) {
case 2:
bclk_value = MAX9867_IFC1B_PCLK_2;
break;
case 4:
bclk_value = MAX9867_IFC1B_PCLK_4;
break;
case 8:
bclk_value = MAX9867_IFC1B_PCLK_8;
break;
case 16:
bclk_value = MAX9867_IFC1B_PCLK_16;
break;
default:
dev_err(component->dev,
"unsupported sampling rate\n");
return -EINVAL;
}
break;
case 24:
bclk_value = MAX9867_IFC1B_24BIT;
break;
case 32:
bclk_value = MAX9867_IFC1B_32BIT;
break;
default:
dev_err(component->dev, "unsupported sampling rate\n");
return -EINVAL;
}
regmap_update_bits(max9867->regmap, MAX9867_IFC1B,
MAX9867_IFC1B_BCLK_MASK, bclk_value);
}
return 0;
}
static int max9867_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_component *component = dai->component;
struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component);
regmap_update_bits(max9867->regmap, MAX9867_PWRMAN,
MAX9867_SHTDOWN_MASK, MAX9867_SHTDOWN_MASK);
return 0;
}
static int max9867_mute(struct snd_soc_dai *dai, int mute)
{
struct snd_soc_component *component = dai->component;
struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component);
if (mute)
regmap_update_bits(max9867->regmap, MAX9867_DACLEVEL,
MAX9867_DAC_MUTE_MASK, MAX9867_DAC_MUTE_MASK);
else
regmap_update_bits(max9867->regmap, MAX9867_DACLEVEL,
MAX9867_DAC_MUTE_MASK, 0);
return 0;
return regmap_update_bits(max9867->regmap, MAX9867_DACLEVEL,
1 << 6, !!mute << 6);
}
static int max9867_set_dai_sysclk(struct snd_soc_dai *codec_dai,
@@ -283,21 +264,29 @@ static int max9867_set_dai_sysclk(struct snd_soc_dai *codec_dai,
/* Set the prescaler based on the master clock frequency*/
if (freq >= 10000000 && freq <= 20000000) {
value |= MAX9867_PSCLK_10_20;
max9867->pclk = freq;
max9867->pclk = freq;
} else if (freq >= 20000000 && freq <= 40000000) {
value |= MAX9867_PSCLK_20_40;
max9867->pclk = freq/2;
max9867->pclk = freq / 2;
} else if (freq >= 40000000 && freq <= 60000000) {
value |= MAX9867_PSCLK_40_60;
max9867->pclk = freq/4;
max9867->pclk = freq / 4;
} else {
dev_err(component->dev,
"Invalid clock frequency %uHz (required 10-60MHz)\n",
freq);
return -EINVAL;
}
value = value << MAX9867_PSCLK_SHIFT;
if (freq % 48000 == 0)
max9867->constraints = &max9867_constraints_48k;
else if (freq % 44100 == 0)
max9867->constraints = &max9867_constraints_44k1;
else
dev_warn(component->dev,
"Unable to set exact rate with %uHz clock frequency\n",
freq);
max9867->sysclk = freq;
value = value << MAX9867_PSCLK_SHIFT;
/* exact integer mode is not supported */
value &= ~MAX9867_FREQ_MASK;
regmap_update_bits(max9867->regmap, MAX9867_SYSCLK,
@@ -310,16 +299,17 @@ static int max9867_dai_set_fmt(struct snd_soc_dai *codec_dai,
{
struct snd_soc_component *component = codec_dai->component;
struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component);
u8 iface1A = 0, iface1B = 0;
u8 iface1A, iface1B;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM:
max9867->master = 1;
iface1A |= MAX9867_MASTER;
max9867->master = true;
iface1A = MAX9867_MASTER;
iface1B = MAX9867_IFC1B_48X;
break;
case SND_SOC_DAIFMT_CBS_CFS:
max9867->master = 0;
iface1A &= ~MAX9867_MASTER;
max9867->master = false;
iface1A = iface1B = 0;
break;
default:
return -EINVAL;
@@ -327,9 +317,11 @@ static int max9867_dai_set_fmt(struct snd_soc_dai *codec_dai,
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
max9867->dsp_a = false;
iface1A |= MAX9867_I2S_DLY;
break;
case SND_SOC_DAIFMT_DSP_A:
max9867->dsp_a = true;
iface1A |= MAX9867_TDM_MODE | MAX9867_SDOUT_HIZ;
break;
default:
@@ -355,21 +347,18 @@ static int max9867_dai_set_fmt(struct snd_soc_dai *codec_dai,
regmap_write(max9867->regmap, MAX9867_IFC1A, iface1A);
regmap_write(max9867->regmap, MAX9867_IFC1B, iface1B);
return 0;
}
static const struct snd_soc_dai_ops max9867_dai_ops = {
.set_fmt = max9867_dai_set_fmt,
.set_sysclk = max9867_set_dai_sysclk,
.prepare = max9867_prepare,
.set_fmt = max9867_dai_set_fmt,
.digital_mute = max9867_mute,
.hw_params = max9867_dai_hw_params,
.startup = max9867_startup,
.hw_params = max9867_dai_hw_params,
};
#define MAX9867_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
#define MAX9867_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
static struct snd_soc_dai_driver max9867_dai[] = {
{
.name = "max9867-aif1",
@@ -377,42 +366,74 @@ static struct snd_soc_dai_driver max9867_dai[] = {
.stream_name = "HiFi Playback",
.channels_min = 2,
.channels_max = 2,
.rates = MAX9867_RATES,
.formats = MAX9867_FORMATS,
.rates = SNDRV_PCM_RATE_8000_48000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
},
.capture = {
.stream_name = "HiFi Capture",
.channels_min = 2,
.channels_max = 2,
.rates = MAX9867_RATES,
.formats = MAX9867_FORMATS,
.rates = SNDRV_PCM_RATE_8000_48000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
},
.ops = &max9867_dai_ops,
.symmetric_rates = 1,
}
};
#ifdef CONFIG_PM_SLEEP
static int max9867_suspend(struct device *dev)
#ifdef CONFIG_PM
static int max9867_suspend(struct snd_soc_component *component)
{
struct max9867_priv *max9867 = dev_get_drvdata(dev);
snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF);
/* Drop down to power saving mode when system is suspended */
regmap_update_bits(max9867->regmap, MAX9867_PWRMAN,
MAX9867_SHTDOWN_MASK, ~MAX9867_SHTDOWN_MASK);
return 0;
}
static int max9867_resume(struct device *dev)
static int max9867_resume(struct snd_soc_component *component)
{
struct max9867_priv *max9867 = dev_get_drvdata(dev);
snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
regmap_update_bits(max9867->regmap, MAX9867_PWRMAN,
MAX9867_SHTDOWN_MASK, MAX9867_SHTDOWN_MASK);
return 0;
}
#else
#define max9867_suspend NULL
#define max9867_resume NULL
#endif
static int max9867_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
int err;
struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component);
switch (level) {
case SND_SOC_BIAS_STANDBY:
if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
err = regcache_sync(max9867->regmap);
if (err)
return err;
err = regmap_update_bits(max9867->regmap, MAX9867_PWRMAN,
MAX9867_SHTDOWN, MAX9867_SHTDOWN);
if (err)
return err;
}
break;
case SND_SOC_BIAS_OFF:
err = regmap_update_bits(max9867->regmap, MAX9867_PWRMAN,
MAX9867_SHTDOWN, 0);
if (err)
return err;
regcache_mark_dirty(max9867->regmap);
break;
default:
break;
}
return 0;
}
static const struct snd_soc_component_driver max9867_component = {
.controls = max9867_snd_controls,
.num_controls = ARRAY_SIZE(max9867_snd_controls),
@@ -420,6 +441,9 @@ static const struct snd_soc_component_driver max9867_component = {
.num_dapm_routes = ARRAY_SIZE(max9867_audio_map),
.dapm_widgets = max9867_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(max9867_dapm_widgets),
.suspend = max9867_suspend,
.resume = max9867_resume,
.set_bias_level = max9867_set_bias_level,
.idle_bias_on = 1,
.use_pmdown_time = 1,
.endianness = 1,
@@ -450,8 +474,8 @@ static const struct reg_default max9867_reg[] = {
{ 0x0B, 0x00 },
{ 0x0C, 0x00 },
{ 0x0D, 0x00 },
{ 0x0E, 0x00 },
{ 0x0F, 0x00 },
{ 0x0E, 0x40 },
{ 0x0F, 0x40 },
{ 0x10, 0x00 },
{ 0x11, 0x00 },
{ 0x12, 0x00 },
@@ -476,10 +500,9 @@ static int max9867_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct max9867_priv *max9867;
int ret = 0, reg;
int ret, reg;
max9867 = devm_kzalloc(&i2c->dev,
sizeof(*max9867), GFP_KERNEL);
max9867 = devm_kzalloc(&i2c->dev, sizeof(*max9867), GFP_KERNEL);
if (!max9867)
return -ENOMEM;
@@ -490,8 +513,7 @@ static int max9867_i2c_probe(struct i2c_client *i2c,
dev_err(&i2c->dev, "Failed to allocate regmap: %d\n", ret);
return ret;
}
ret = regmap_read(max9867->regmap,
MAX9867_REVISION, &reg);
ret = regmap_read(max9867->regmap, MAX9867_REVISION, &reg);
if (ret < 0) {
dev_err(&i2c->dev, "Failed to read: %d\n", ret);
return ret;
@@ -499,10 +521,8 @@ static int max9867_i2c_probe(struct i2c_client *i2c,
dev_info(&i2c->dev, "device revision: %x\n", reg);
ret = devm_snd_soc_register_component(&i2c->dev, &max9867_component,
max9867_dai, ARRAY_SIZE(max9867_dai));
if (ret < 0) {
if (ret < 0)
dev_err(&i2c->dev, "Failed to register component: %d\n", ret);
return ret;
}
return ret;
}
@@ -518,15 +538,10 @@ static const struct of_device_id max9867_of_match[] = {
};
MODULE_DEVICE_TABLE(of, max9867_of_match);
static const struct dev_pm_ops max9867_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(max9867_suspend, max9867_resume)
};
static struct i2c_driver max9867_i2c_driver = {
.driver = {
.name = "max9867",
.of_match_table = of_match_ptr(max9867_of_match),
.pm = &max9867_pm_ops,
},
.probe = max9867_i2c_probe,
.id_table = max9867_i2c_id,
@@ -534,6 +549,6 @@ static struct i2c_driver max9867_i2c_driver = {
module_i2c_driver(max9867_i2c_driver);
MODULE_AUTHOR("anish kumar <yesanishhere@gmail.com>");
MODULE_DESCRIPTION("ALSA SoC MAX9867 driver");
MODULE_AUTHOR("Ladislav Michl <ladis@linux-mips.org>");
MODULE_DESCRIPTION("ASoC MAX9867 driver");
MODULE_LICENSE("GPL");

View File

@@ -26,13 +26,11 @@
#define MAX9867_PSCLK_10_20 0x1
#define MAX9867_PSCLK_20_40 0x2
#define MAX9867_PSCLK_40_60 0x3
#define MAX9867_AUDIOCLKHIGH 0x06
#define MAX9867_NI_HIGH_WIDTH 0x7
#define MAX9867_NI_HIGH_MASK 0x7F
#define MAX9867_NI_LOW_MASK 0x7F
#define MAX9867_NI_LOW_SHIFT 0x1
#define MAX9867_PLL (1<<7)
#define MAX9867_AUDIOCLKLOW 0x07
#define MAX9867_AUDIOCLKHIGH 0x06
#define MAX9867_NI_HIGH_MASK 0x7F
#define MAX9867_NI_LOW_MASK 0xFE
#define MAX9867_PLL (1<<7)
#define MAX9867_AUDIOCLKLOW 0x07
#define MAX9867_RAPID_LOCK 0x01
#define MAX9867_IFC1A 0x08
#define MAX9867_MASTER (1<<7)
@@ -43,40 +41,29 @@
#define MAX9867_BCI_MODE (1<<5)
#define MAX9867_IFC1B 0x09
#define MAX9867_IFC1B_BCLK_MASK 7
#define MAX9867_IFC1B_32BIT 0x01
#define MAX9867_IFC1B_24BIT 0x02
#define MAX9867_IFC1B_PCLK_2 4
#define MAX9867_IFC1B_PCLK_4 5
#define MAX9867_IFC1B_PCLK_8 6
#define MAX9867_IFC1B_PCLK_16 7
#define MAX9867_IFC1B_64X 0x01
#define MAX9867_IFC1B_48X 0x02
#define MAX9867_IFC1B_PCLK_2 0x04
#define MAX9867_IFC1B_PCLK_4 0x05
#define MAX9867_IFC1B_PCLK_8 0x06
#define MAX9867_IFC1B_PCLK_16 0x07
#define MAX9867_CODECFLTR 0x0a
#define MAX9867_DACGAIN 0x0b
#define MAX9867_SIDETONE 0x0b
#define MAX9867_DACLEVEL 0x0c
#define MAX9867_DAC_MUTE_SHIFT 0x6
#define MAX9867_DAC_MUTE_WIDTH 0x1
#define MAX9867_DAC_MUTE_MASK (0x1<<MAX9867_DAC_MUTE_SHIFT)
#define MAX9867_ADCLEVEL 0x0d
#define MAX9867_LEFTLINELVL 0x0e
#define MAX9867_RIGTHLINELVL 0x0f
#define MAX9867_RIGHTLINELVL 0x0f
#define MAX9867_LEFTVOL 0x10
#define MAX9867_RIGHTVOL 0x11
#define MAX9867_LEFTMICGAIN 0x12
#define MAX9867_RIGHTMICGAIN 0x13
#define MAX9867_INPUTCONFIG 0x14
#define MAX9867_INPUT_SHIFT 0x6
#define MAX9867_MICCONFIG 0x15
#define MAX9867_MODECONFIG 0x16
#define MAX9867_PWRMAN 0x17
#define MAX9867_SHTDOWN_MASK (1<<7)
#define MAX9867_SHTDOWN 0x80
#define MAX9867_REVISION 0xff
#define MAX9867_CACHEREGNUM 10
/* codec private data */
struct max9867_priv {
struct regmap *regmap;
unsigned int sysclk;
unsigned int pclk;
unsigned int master;
};
#endif

View File

@@ -585,7 +585,7 @@ static int nau8540_calc_fll_param(unsigned int fll_in,
fvco_max = 0;
fvco_sel = ARRAY_SIZE(mclk_src_scaling);
for (i = 0; i < ARRAY_SIZE(mclk_src_scaling); i++) {
fvco = 256 * fs * 2 * mclk_src_scaling[i].param;
fvco = 256ULL * fs * 2 * mclk_src_scaling[i].param;
if (fvco > NAU_FVCO_MIN && fvco < NAU_FVCO_MAX &&
fvco_max < fvco) {
fvco_max = fvco;

View File

@@ -1,18 +1,14 @@
/*
* nau8822.c -- NAU8822 ALSA Soc Audio Codec driver
*
* Copyright 2017 Nuvoton Technology Corp.
*
* Author: David Lin <ctlin0@nuvoton.com>
* Co-author: John Hsu <kchsu0@nuvoton.com>
* Co-author: Seven Li <wtli@nuvoton.com>
*
* Based on WM8974.c
*
* 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.
*/
// SPDX-License-Identifier: GPL-2.0
//
// nau8822.c -- NAU8822 ALSA Soc Audio driver
//
// Copyright 2017 Nuvoton Technology Crop.
//
// Author: David Lin <ctlin0@nuvoton.com>
// Co-author: John Hsu <kchsu0@nuvoton.com>
// Co-author: Seven Li <wtli@nuvoton.com>
//
// Based on WM8974.c
#include <linux/module.h>
#include <linux/moduleparam.h>

View File

@@ -1,13 +1,12 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* nau8822.h -- NAU8822 Soc Audio Codec driver
* nau8822.h -- NAU8822 ALSA SoC Audio driver
*
* Copyright 2017 Nuvoton Technology Crop.
*
* Author: David Lin <ctlin0@nuvoton.com>
* Co-author: John Hsu <kchsu0@nuvoton.com>
* Co-author: Seven Li <wtli@nuvoton.com>
*
* 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.
*/
#ifndef __NAU8822_H__

View File

@@ -424,10 +424,8 @@ static u32 nau8825_xtalk_sidetone(u32 sig_org, u32 sig_cros)
{
u32 gain, sidetone;
if (unlikely(sig_org == 0) || unlikely(sig_cros == 0)) {
WARN_ON(1);
if (WARN_ON(sig_org == 0 || sig_cros == 0))
return 0;
}
sig_org = nau8825_intlog10_dec3(sig_org);
sig_cros = nau8825_intlog10_dec3(sig_cros);

View File

@@ -198,19 +198,25 @@ static const struct snd_kcontrol_new pcm3060_dapm_controls[] = {
};
static const struct snd_soc_dapm_widget pcm3060_dapm_widgets[] = {
SND_SOC_DAPM_DAC("DAC", "Playback", PCM3060_REG64,
PCM3060_REG_SHIFT_DAPSV, 1),
SND_SOC_DAPM_OUTPUT("OUTL"),
SND_SOC_DAPM_OUTPUT("OUTR"),
SND_SOC_DAPM_INPUT("INL"),
SND_SOC_DAPM_INPUT("INR"),
SND_SOC_DAPM_ADC("ADC", "Capture", PCM3060_REG64,
PCM3060_REG_SHIFT_ADPSV, 1),
};
static const struct snd_soc_dapm_route pcm3060_dapm_map[] = {
{ "OUTL", NULL, "Playback" },
{ "OUTR", NULL, "Playback" },
{ "OUTL", NULL, "DAC" },
{ "OUTR", NULL, "DAC" },
{ "Capture", NULL, "INL" },
{ "Capture", NULL, "INR" },
{ "ADC", NULL, "INL" },
{ "ADC", NULL, "INR" },
};
/* soc component */
@@ -270,9 +276,23 @@ EXPORT_SYMBOL(pcm3060_regmap);
/* device */
static void pcm3060_parse_dt(const struct device_node *np,
struct pcm3060_priv *priv)
{
priv->out_se = of_property_read_bool(np, "ti,out-single-ended");
}
int pcm3060_probe(struct device *dev)
{
int rc;
struct pcm3060_priv *priv = dev_get_drvdata(dev);
if (dev->of_node)
pcm3060_parse_dt(dev->of_node, priv);
if (priv->out_se)
regmap_update_bits(priv->regmap, PCM3060_REG64,
PCM3060_REG_SE, PCM3060_REG_SE);
rc = devm_snd_soc_register_component(dev, &pcm3060_soc_comp_driver,
pcm3060_dai,

View File

@@ -25,6 +25,7 @@ struct pcm3060_priv_dai {
struct pcm3060_priv {
struct regmap *regmap;
struct pcm3060_priv_dai dai[PCM3060_DAI_IDS_NUM];
u8 out_se: 1;
};
int pcm3060_probe(struct device *dev);
@@ -36,7 +37,9 @@ int pcm3060_remove(struct device *dev);
#define PCM3060_REG_MRST 0x80
#define PCM3060_REG_SRST 0x40
#define PCM3060_REG_ADPSV 0x20
#define PCM3060_REG_SHIFT_ADPSV 0x05
#define PCM3060_REG_DAPSV 0x10
#define PCM3060_REG_SHIFT_DAPSV 0x04
#define PCM3060_REG_SE 0x01
#define PCM3060_REG65 0x41

View File

@@ -133,10 +133,6 @@ static const struct snd_kcontrol_new pcm3168a_snd_controls[] = {
SOC_DOUBLE("DAC2 Invert Switch", PCM3168A_DAC_INV, 2, 3, 1, 0),
SOC_DOUBLE("DAC3 Invert Switch", PCM3168A_DAC_INV, 4, 5, 1, 0),
SOC_DOUBLE("DAC4 Invert Switch", PCM3168A_DAC_INV, 6, 7, 1, 0),
SOC_DOUBLE_STS("DAC1 Zero Flag", PCM3168A_DAC_ZERO, 0, 1, 1, 0),
SOC_DOUBLE_STS("DAC2 Zero Flag", PCM3168A_DAC_ZERO, 2, 3, 1, 0),
SOC_DOUBLE_STS("DAC3 Zero Flag", PCM3168A_DAC_ZERO, 4, 5, 1, 0),
SOC_DOUBLE_STS("DAC4 Zero Flag", PCM3168A_DAC_ZERO, 6, 7, 1, 0),
SOC_ENUM("DAC Volume Control Type", pcm3168a_dac_volume_type),
SOC_ENUM("DAC Volume Rate Multiplier", pcm3168a_dac_att_mult),
SOC_ENUM("DAC De-Emphasis", pcm3168a_dac_demp),
@@ -176,9 +172,6 @@ static const struct snd_kcontrol_new pcm3168a_snd_controls[] = {
SOC_DOUBLE("ADC1 Mute Switch", PCM3168A_ADC_MUTE, 0, 1, 1, 0),
SOC_DOUBLE("ADC2 Mute Switch", PCM3168A_ADC_MUTE, 2, 3, 1, 0),
SOC_DOUBLE("ADC3 Mute Switch", PCM3168A_ADC_MUTE, 4, 5, 1, 0),
SOC_DOUBLE_STS("ADC1 Overflow Flag", PCM3168A_ADC_OV, 0, 1, 1, 0),
SOC_DOUBLE_STS("ADC2 Overflow Flag", PCM3168A_ADC_OV, 2, 3, 1, 0),
SOC_DOUBLE_STS("ADC3 Overflow Flag", PCM3168A_ADC_OV, 4, 5, 1, 0),
SOC_ENUM("ADC Volume Control Type", pcm3168a_adc_volume_type),
SOC_ENUM("ADC Volume Rate Multiplier", pcm3168a_adc_att_mult),
SOC_ENUM("ADC Overflow Flag Polarity", pcm3168a_adc_ov_pol),
@@ -504,6 +497,10 @@ static int pcm3168a_startup(struct snd_pcm_substream *substream,
unsigned int fmt;
unsigned int sample_min;
unsigned int channel_max;
unsigned int channel_maxs[] = {
6, /* rx */
8 /* tx */
};
if (tx)
fmt = pcm3168a->dac_fmt;
@@ -528,18 +525,9 @@ static int pcm3168a_startup(struct snd_pcm_substream *substream,
channel_max = 2;
break;
case PCM3168A_FMT_LEFT_J:
sample_min = 24;
if (tx)
channel_max = 8;
else
channel_max = 6;
break;
case PCM3168A_FMT_I2S:
sample_min = 24;
if (tx)
channel_max = 8;
else
channel_max = 6;
channel_max = channel_maxs[tx];
break;
default:
sample_min = 24;

View File

@@ -53,6 +53,8 @@ struct pcm512x_priv {
unsigned long overclock_pll;
unsigned long overclock_dac;
unsigned long overclock_dsp;
int mute;
struct mutex mutex;
};
/*
@@ -384,6 +386,61 @@ static const struct soc_enum pcm512x_veds =
SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_2, PCM512x_VEDS_SHIFT, 4,
pcm512x_ramp_step_text);
static int pcm512x_update_mute(struct pcm512x_priv *pcm512x)
{
return regmap_update_bits(
pcm512x->regmap, PCM512x_MUTE, PCM512x_RQML | PCM512x_RQMR,
(!!(pcm512x->mute & 0x5) << PCM512x_RQML_SHIFT)
| (!!(pcm512x->mute & 0x3) << PCM512x_RQMR_SHIFT));
}
static int pcm512x_digital_playback_switch_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
mutex_lock(&pcm512x->mutex);
ucontrol->value.integer.value[0] = !(pcm512x->mute & 0x4);
ucontrol->value.integer.value[1] = !(pcm512x->mute & 0x2);
mutex_unlock(&pcm512x->mutex);
return 0;
}
static int pcm512x_digital_playback_switch_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
int ret, changed = 0;
mutex_lock(&pcm512x->mutex);
if ((pcm512x->mute & 0x4) == (ucontrol->value.integer.value[0] << 2)) {
pcm512x->mute ^= 0x4;
changed = 1;
}
if ((pcm512x->mute & 0x2) == (ucontrol->value.integer.value[1] << 1)) {
pcm512x->mute ^= 0x2;
changed = 1;
}
if (changed) {
ret = pcm512x_update_mute(pcm512x);
if (ret != 0) {
dev_err(component->dev,
"Failed to update digital mute: %d\n", ret);
mutex_unlock(&pcm512x->mutex);
return ret;
}
}
mutex_unlock(&pcm512x->mutex);
return changed;
}
static const struct snd_kcontrol_new pcm512x_controls[] = {
SOC_DOUBLE_R_TLV("Digital Playback Volume", PCM512x_DIGITAL_VOLUME_2,
PCM512x_DIGITAL_VOLUME_3, 0, 255, 1, digital_tlv),
@@ -391,8 +448,15 @@ SOC_DOUBLE_TLV("Analogue Playback Volume", PCM512x_ANALOG_GAIN_CTRL,
PCM512x_LAGN_SHIFT, PCM512x_RAGN_SHIFT, 1, 1, analog_tlv),
SOC_DOUBLE_TLV("Analogue Playback Boost Volume", PCM512x_ANALOG_GAIN_BOOST,
PCM512x_AGBL_SHIFT, PCM512x_AGBR_SHIFT, 1, 0, boost_tlv),
SOC_DOUBLE("Digital Playback Switch", PCM512x_MUTE, PCM512x_RQML_SHIFT,
PCM512x_RQMR_SHIFT, 1, 1),
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Digital Playback Switch",
.index = 0,
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
.info = snd_ctl_boolean_stereo_info,
.get = pcm512x_digital_playback_switch_get,
.put = pcm512x_digital_playback_switch_put
},
SOC_SINGLE("Deemphasis Switch", PCM512x_DSP, PCM512x_DEMP_SHIFT, 1, 1),
SOC_ENUM("DSP Program", pcm512x_dsp_program),
@@ -1319,10 +1383,61 @@ static int pcm512x_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return 0;
}
static int pcm512x_digital_mute(struct snd_soc_dai *dai, int mute)
{
struct snd_soc_component *component = dai->component;
struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
int ret;
unsigned int mute_det;
mutex_lock(&pcm512x->mutex);
if (mute) {
pcm512x->mute |= 0x1;
ret = regmap_update_bits(pcm512x->regmap, PCM512x_MUTE,
PCM512x_RQML | PCM512x_RQMR,
PCM512x_RQML | PCM512x_RQMR);
if (ret != 0) {
dev_err(component->dev,
"Failed to set digital mute: %d\n", ret);
mutex_unlock(&pcm512x->mutex);
return ret;
}
regmap_read_poll_timeout(pcm512x->regmap,
PCM512x_ANALOG_MUTE_DET,
mute_det, (mute_det & 0x3) == 0,
200, 10000);
mutex_unlock(&pcm512x->mutex);
} else {
pcm512x->mute &= ~0x1;
ret = pcm512x_update_mute(pcm512x);
if (ret != 0) {
dev_err(component->dev,
"Failed to update digital mute: %d\n", ret);
mutex_unlock(&pcm512x->mutex);
return ret;
}
regmap_read_poll_timeout(pcm512x->regmap,
PCM512x_ANALOG_MUTE_DET,
mute_det,
(mute_det & 0x3)
== ((~pcm512x->mute >> 1) & 0x3),
200, 10000);
}
mutex_unlock(&pcm512x->mutex);
return 0;
}
static const struct snd_soc_dai_ops pcm512x_dai_ops = {
.startup = pcm512x_dai_startup,
.hw_params = pcm512x_hw_params,
.set_fmt = pcm512x_set_fmt,
.digital_mute = pcm512x_digital_mute,
};
static struct snd_soc_dai_driver pcm512x_dai = {
@@ -1388,6 +1503,8 @@ int pcm512x_probe(struct device *dev, struct regmap *regmap)
if (!pcm512x)
return -ENOMEM;
mutex_init(&pcm512x->mutex);
dev_set_drvdata(dev, pcm512x);
pcm512x->regmap = regmap;

View File

@@ -112,7 +112,9 @@
#define PCM512x_RQST_SHIFT 4
/* Page 0, Register 3 - mute */
#define PCM512x_RQMR (1 << 0)
#define PCM512x_RQMR_SHIFT 0
#define PCM512x_RQML (1 << 4)
#define PCM512x_RQML_SHIFT 4
/* Page 0, Register 4 - PLL */

View File

@@ -17,6 +17,7 @@
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/acpi.h>
#include <linux/regulator/consumer.h>
#include <linux/workqueue.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -33,6 +34,9 @@
#define RT5663_DEVICE_ID_2 0x6451
#define RT5663_DEVICE_ID_1 0x6406
#define RT5663_POWER_ON_DELAY_MS 300
#define RT5663_SUPPLY_CURRENT_UA 500000
enum {
CODEC_VER_1,
CODEC_VER_0,
@@ -48,6 +52,11 @@ struct impedance_mapping_table {
unsigned int dc_offset_r_manual_mic;
};
static const char *const rt5663_supply_names[] = {
"avdd",
"cpvdd",
};
struct rt5663_priv {
struct snd_soc_component *component;
struct rt5663_platform_data pdata;
@@ -56,6 +65,7 @@ struct rt5663_priv {
struct snd_soc_jack *hs_jack;
struct timer_list btn_check_timer;
struct impedance_mapping_table *imp_table;
struct regulator_bulk_data supplies[ARRAY_SIZE(rt5663_supply_names)];
int codec_ver;
int sysclk;
@@ -3483,7 +3493,7 @@ static int rt5663_i2c_probe(struct i2c_client *i2c,
{
struct rt5663_platform_data *pdata = dev_get_platdata(&i2c->dev);
struct rt5663_priv *rt5663;
int ret;
int ret, i;
unsigned int val;
struct regmap *regmap;
@@ -3500,12 +3510,44 @@ static int rt5663_i2c_probe(struct i2c_client *i2c,
else
rt5663_parse_dp(rt5663, &i2c->dev);
for (i = 0; i < ARRAY_SIZE(rt5663->supplies); i++)
rt5663->supplies[i].supply = rt5663_supply_names[i];
ret = devm_regulator_bulk_get(&i2c->dev,
ARRAY_SIZE(rt5663->supplies),
rt5663->supplies);
if (ret) {
dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
return ret;
}
/* Set load for regulator. */
for (i = 0; i < ARRAY_SIZE(rt5663->supplies); i++) {
ret = regulator_set_load(rt5663->supplies[i].consumer,
RT5663_SUPPLY_CURRENT_UA);
if (ret < 0) {
dev_err(&i2c->dev,
"Failed to set regulator load on %s, ret: %d\n",
rt5663->supplies[i].supply, ret);
return ret;
}
}
ret = regulator_bulk_enable(ARRAY_SIZE(rt5663->supplies),
rt5663->supplies);
if (ret) {
dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret);
return ret;
}
msleep(RT5663_POWER_ON_DELAY_MS);
regmap = devm_regmap_init_i2c(i2c, &temp_regmap);
if (IS_ERR(regmap)) {
ret = PTR_ERR(regmap);
dev_err(&i2c->dev, "Failed to allocate temp register map: %d\n",
ret);
return ret;
goto err_enable;
}
ret = regmap_read(regmap, RT5663_VENDOR_ID_2, &val);
@@ -3530,14 +3572,15 @@ static int rt5663_i2c_probe(struct i2c_client *i2c,
dev_err(&i2c->dev,
"Device with ID register %#x is not rt5663\n",
val);
return -ENODEV;
ret = -ENODEV;
goto err_enable;
}
if (IS_ERR(rt5663->regmap)) {
ret = PTR_ERR(rt5663->regmap);
dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
ret);
return ret;
goto err_enable;
}
/* reset and calibrate */
@@ -3635,20 +3678,32 @@ static int rt5663_i2c_probe(struct i2c_client *i2c,
ret = request_irq(i2c->irq, rt5663_irq,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
| IRQF_ONESHOT, "rt5663", rt5663);
if (ret)
if (ret) {
dev_err(&i2c->dev, "%s Failed to reguest IRQ: %d\n",
__func__, ret);
goto err_enable;
}
}
ret = devm_snd_soc_register_component(&i2c->dev,
&soc_component_dev_rt5663,
rt5663_dai, ARRAY_SIZE(rt5663_dai));
if (ret) {
if (i2c->irq)
free_irq(i2c->irq, rt5663);
}
if (ret)
goto err_enable;
return 0;
/*
* Error after enabling regulators should goto err_enable
* to disable regulators.
*/
err_enable:
if (i2c->irq)
free_irq(i2c->irq, rt5663);
regulator_bulk_disable(ARRAY_SIZE(rt5663->supplies), rt5663->supplies);
return ret;
}
@@ -3659,6 +3714,8 @@ static int rt5663_i2c_remove(struct i2c_client *i2c)
if (i2c->irq)
free_irq(i2c->irq, rt5663);
regulator_bulk_disable(ARRAY_SIZE(rt5663->supplies), rt5663->supplies);
return 0;
}

View File

@@ -19,6 +19,7 @@
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/regulator/consumer.h>
#include <sound/soc.h>
#define DRV_NAME "simple-amplifier"
@@ -58,11 +59,14 @@ static const struct snd_soc_dapm_widget simple_amp_dapm_widgets[] = {
(SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD)),
SND_SOC_DAPM_OUTPUT("OUTL"),
SND_SOC_DAPM_OUTPUT("OUTR"),
SND_SOC_DAPM_REGULATOR_SUPPLY("VCC", 20, 0),
};
static const struct snd_soc_dapm_route simple_amp_dapm_routes[] = {
{ "DRV", NULL, "INL" },
{ "DRV", NULL, "INR" },
{ "OUTL", NULL, "VCC" },
{ "OUTR", NULL, "VCC" },
{ "OUTL", NULL, "DRV" },
{ "OUTR", NULL, "DRV" },
};

View File

@@ -378,7 +378,7 @@ static struct snd_soc_component_driver soc_codec_dev_tas6424 = {
.non_legacy_dai_naming = 1,
};
static struct snd_soc_dai_ops tas6424_speaker_dai_ops = {
static const struct snd_soc_dai_ops tas6424_speaker_dai_ops = {
.hw_params = tas6424_hw_params,
.set_fmt = tas6424_set_dai_fmt,
.set_tdm_slot = tas6424_set_dai_tdm_slot,

View File

@@ -1095,7 +1095,7 @@ static int aic31xx_set_dai_sysclk(struct snd_soc_dai *codec_dai,
if (freq/i > 20000000) {
dev_err(aic31xx->dev, "%s: Too high mclk frequency %u\n",
__func__, freq);
return -EINVAL;
return -EINVAL;
}
aic31xx->p_div = i;

View File

@@ -1260,6 +1260,16 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai,
aic3x->master = 0;
iface_areg &= ~(BIT_CLK_MASTER | WORD_CLK_MASTER);
break;
case SND_SOC_DAIFMT_CBM_CFS:
aic3x->master = 1;
iface_areg |= BIT_CLK_MASTER;
iface_areg &= ~WORD_CLK_MASTER;
break;
case SND_SOC_DAIFMT_CBS_CFM:
aic3x->master = 1;
iface_areg |= WORD_CLK_MASTER;
iface_areg &= ~BIT_CLK_MASTER;
break;
default:
return -EINVAL;
}

View File

@@ -394,7 +394,7 @@ static int dac33_hard_power(struct snd_soc_component *component, int power)
if (ret != 0) {
dev_err(component->dev,
"Failed to enable supplies: %d\n", ret);
goto exit;
goto exit;
}
if (dac33->power_gpio >= 0)

View File

@@ -60,7 +60,7 @@ static int wm8998_asrc_ev(struct snd_soc_dapm_widget *w,
dev_warn(component->dev,
"Unsupported ASRC rate1 (%s)\n",
arizona_sample_rate_val_to_name(val));
return -EINVAL;
return -EINVAL;
}
break;
default:

View File

@@ -325,8 +325,7 @@ static int wm9705_soc_probe(struct snd_soc_component *component)
if (wm9705->mfd_pdata) {
wm9705->ac97 = wm9705->mfd_pdata->ac97;
regmap = wm9705->mfd_pdata->regmap;
} else {
#ifdef CONFIG_SND_SOC_AC97_BUS
} else if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS)) {
wm9705->ac97 = snd_soc_new_ac97_component(component, WM9705_VENDOR_ID,
WM9705_VENDOR_ID_MASK);
if (IS_ERR(wm9705->ac97)) {
@@ -339,7 +338,8 @@ static int wm9705_soc_probe(struct snd_soc_component *component)
snd_soc_free_ac97_component(wm9705->ac97);
return PTR_ERR(regmap);
}
#endif
} else {
return -ENXIO;
}
snd_soc_component_set_drvdata(component, wm9705->ac97);
@@ -350,14 +350,12 @@ static int wm9705_soc_probe(struct snd_soc_component *component)
static void wm9705_soc_remove(struct snd_soc_component *component)
{
#ifdef CONFIG_SND_SOC_AC97_BUS
struct wm9705_priv *wm9705 = snd_soc_component_get_drvdata(component);
if (!wm9705->mfd_pdata) {
if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS) && !wm9705->mfd_pdata) {
snd_soc_component_exit_regmap(component);
snd_soc_free_ac97_component(wm9705->ac97);
}
#endif
}
static const struct snd_soc_component_driver soc_component_dev_wm9705 = {

View File

@@ -642,8 +642,7 @@ static int wm9712_soc_probe(struct snd_soc_component *component)
if (wm9712->mfd_pdata) {
wm9712->ac97 = wm9712->mfd_pdata->ac97;
regmap = wm9712->mfd_pdata->regmap;
} else {
#ifdef CONFIG_SND_SOC_AC97_BUS
} else if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS)) {
int ret;
wm9712->ac97 = snd_soc_new_ac97_component(component, WM9712_VENDOR_ID,
@@ -660,7 +659,8 @@ static int wm9712_soc_probe(struct snd_soc_component *component)
snd_soc_free_ac97_component(wm9712->ac97);
return PTR_ERR(regmap);
}
#endif
} else {
return -ENXIO;
}
snd_soc_component_init_regmap(component, regmap);
@@ -673,14 +673,12 @@ static int wm9712_soc_probe(struct snd_soc_component *component)
static void wm9712_soc_remove(struct snd_soc_component *component)
{
#ifdef CONFIG_SND_SOC_AC97_BUS
struct wm9712_priv *wm9712 = snd_soc_component_get_drvdata(component);
if (!wm9712->mfd_pdata) {
if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS) && !wm9712->mfd_pdata) {
snd_soc_component_exit_regmap(component);
snd_soc_free_ac97_component(wm9712->ac97);
}
#endif
}
static const struct snd_soc_component_driver soc_component_dev_wm9712 = {

View File

@@ -1214,8 +1214,7 @@ static int wm9713_soc_probe(struct snd_soc_component *component)
if (wm9713->mfd_pdata) {
wm9713->ac97 = wm9713->mfd_pdata->ac97;
regmap = wm9713->mfd_pdata->regmap;
} else {
#ifdef CONFIG_SND_SOC_AC97_BUS
} else if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS)) {
wm9713->ac97 = snd_soc_new_ac97_component(component, WM9713_VENDOR_ID,
WM9713_VENDOR_ID_MASK);
if (IS_ERR(wm9713->ac97))
@@ -1225,7 +1224,8 @@ static int wm9713_soc_probe(struct snd_soc_component *component)
snd_soc_free_ac97_component(wm9713->ac97);
return PTR_ERR(regmap);
}
#endif
} else {
return -ENXIO;
}
snd_soc_component_init_regmap(component, regmap);
@@ -1238,14 +1238,12 @@ static int wm9713_soc_probe(struct snd_soc_component *component)
static void wm9713_soc_remove(struct snd_soc_component *component)
{
#ifdef CONFIG_SND_SOC_AC97_BUS
struct wm9713_priv *wm9713 = snd_soc_component_get_drvdata(component);
if (!wm9713->mfd_pdata) {
if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS) && !wm9713->mfd_pdata) {
snd_soc_component_exit_regmap(component);
snd_soc_free_ac97_component(wm9713->ac97);
}
#endif
}
static const struct snd_soc_component_driver soc_component_dev_wm9713 = {

View File

@@ -2419,7 +2419,7 @@ static int wm_adsp_create_name(struct wm_adsp *dsp)
return 0;
}
int wm_adsp1_init(struct wm_adsp *dsp)
static int wm_adsp_common_init(struct wm_adsp *dsp)
{
int ret;
@@ -2428,11 +2428,17 @@ int wm_adsp1_init(struct wm_adsp *dsp)
return ret;
INIT_LIST_HEAD(&dsp->alg_regions);
INIT_LIST_HEAD(&dsp->ctl_list);
mutex_init(&dsp->pwr_lock);
return 0;
}
int wm_adsp1_init(struct wm_adsp *dsp)
{
return wm_adsp_common_init(dsp);
}
EXPORT_SYMBOL_GPL(wm_adsp1_init);
int wm_adsp1_event(struct snd_soc_dapm_widget *w,
@@ -2917,7 +2923,7 @@ int wm_adsp2_init(struct wm_adsp *dsp)
{
int ret;
ret = wm_adsp_create_name(dsp);
ret = wm_adsp_common_init(dsp);
if (ret)
return ret;
@@ -2939,12 +2945,8 @@ int wm_adsp2_init(struct wm_adsp *dsp)
break;
}
INIT_LIST_HEAD(&dsp->alg_regions);
INIT_LIST_HEAD(&dsp->ctl_list);
INIT_WORK(&dsp->boot_work, wm_adsp2_boot_work);
mutex_init(&dsp->pwr_lock);
return 0;
}
EXPORT_SYMBOL_GPL(wm_adsp2_init);

View File

@@ -1,106 +0,0 @@
config SND_DAVINCI_SOC
tristate
depends on ARCH_DAVINCI
select SND_EDMA_SOC
config SND_EDMA_SOC
tristate "SoC Audio for Texas Instruments chips using eDMA"
depends on TI_EDMA
select SND_SOC_GENERIC_DMAENGINE_PCM
help
Say Y or M here if you want audio support for TI SoC which uses eDMA.
The following line of SoCs are supported by this platform driver:
- daVinci devices
- AM335x
- AM437x/AM438x
- DRA7xx family
config SND_DAVINCI_SOC_I2S
tristate "DaVinci Multichannel Buffered Serial Port (McBSP) support"
depends on SND_EDMA_SOC
help
Say Y or M here if you want to have support for McBSP IP found in
Texas Instruments DaVinci DA850 SoCs.
config SND_DAVINCI_SOC_MCASP
tristate "Multichannel Audio Serial Port (McASP) support"
depends on SND_SDMA_SOC || SND_EDMA_SOC
help
Say Y or M here if you want to have support for McASP IP found in
various Texas Instruments SoCs like:
- daVinci devices
- Sitara line of SoCs (AM335x, AM438x, etc)
- DRA7x devices
config SND_DAVINCI_SOC_VCIF
tristate
config SND_DAVINCI_SOC_GENERIC_EVM
tristate
select SND_SOC_TLV320AIC3X
select SND_DAVINCI_SOC_MCASP
config SND_AM33XX_SOC_EVM
tristate "SoC Audio for the AM33XX chip based boards"
depends on SND_EDMA_SOC && SOC_AM33XX && I2C
select SND_DAVINCI_SOC_GENERIC_EVM
help
Say Y or M if you want to add support for SoC audio on AM33XX
boards using McASP and TLV320AIC3X codec. For example AM335X-EVM,
AM335X-EVMSK, and BeagelBone with AudioCape boards have this
setup.
config SND_DAVINCI_SOC_EVM
tristate "SoC Audio support for DaVinci DM6446, DM355 or DM365 EVM"
depends on SND_EDMA_SOC && I2C
depends on MACH_DAVINCI_EVM || MACH_DAVINCI_DM355_EVM || MACH_DAVINCI_DM365_EVM
select SND_DAVINCI_SOC_GENERIC_EVM
help
Say Y if you want to add support for SoC audio on TI
DaVinci DM6446, DM355 or DM365 EVM platforms.
choice
prompt "DM365 codec select"
depends on SND_DAVINCI_SOC_EVM
depends on MACH_DAVINCI_DM365_EVM
config SND_DM365_AIC3X_CODEC
tristate "Audio Codec - AIC3101"
help
Say Y if you want to add support for AIC3101 audio codec
config SND_DM365_VOICE_CODEC
tristate "Voice Codec - CQ93VC"
select MFD_DAVINCI_VOICECODEC
select SND_DAVINCI_SOC_VCIF
select SND_SOC_CQ0093VC
help
Say Y if you want to add support for SoC On-chip voice codec
endchoice
config SND_DM6467_SOC_EVM
tristate "SoC Audio support for DaVinci DM6467 EVM"
depends on SND_EDMA_SOC && MACH_DAVINCI_DM6467_EVM && I2C
select SND_DAVINCI_SOC_GENERIC_EVM
select SND_SOC_SPDIF
help
Say Y if you want to add support for SoC audio on TI
config SND_DA830_SOC_EVM
tristate "SoC Audio support for DA830/OMAP-L137 EVM"
depends on SND_EDMA_SOC && MACH_DAVINCI_DA830_EVM && I2C
select SND_DAVINCI_SOC_GENERIC_EVM
help
Say Y if you want to add support for SoC audio on TI
DA830/OMAP-L137 EVM
config SND_DA850_SOC_EVM
tristate "SoC Audio support for DA850/OMAP-L138 EVM"
depends on SND_EDMA_SOC && MACH_DAVINCI_DA850_EVM && I2C
select SND_DAVINCI_SOC_GENERIC_EVM
help
Say Y if you want to add support for SoC audio on TI
DA850/OMAP-L138 EVM

View File

@@ -1,16 +0,0 @@
# SPDX-License-Identifier: GPL-2.0
# DAVINCI Platform Support
snd-soc-edma-objs := edma-pcm.o
snd-soc-davinci-i2s-objs := davinci-i2s.o
snd-soc-davinci-mcasp-objs:= davinci-mcasp.o
snd-soc-davinci-vcif-objs:= davinci-vcif.o
obj-$(CONFIG_SND_EDMA_SOC) += snd-soc-edma.o
obj-$(CONFIG_SND_DAVINCI_SOC_I2S) += snd-soc-davinci-i2s.o
obj-$(CONFIG_SND_DAVINCI_SOC_MCASP) += snd-soc-davinci-mcasp.o
obj-$(CONFIG_SND_DAVINCI_SOC_VCIF) += snd-soc-davinci-vcif.o
# Generic DAVINCI/AM33xx Machine Support
snd-soc-evm-objs := davinci-evm.o
obj-$(CONFIG_SND_DAVINCI_SOC_GENERIC_EVM) += snd-soc-evm.o

View File

@@ -221,7 +221,7 @@ config SND_SOC_PHYCORE_AC97
config SND_SOC_EUKREA_TLV320
tristate "Eukrea TLV320"
depends on ARCH_MXC && I2C
depends on ARCH_MXC && !ARM64 && I2C
select SND_SOC_TLV320AIC23_I2C
select SND_SOC_IMX_AUDMUX
select SND_SOC_IMX_SSI

View File

@@ -571,17 +571,17 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
}
/* Common settings for corresponding Freescale CPU DAI driver */
if (strstr(cpu_np->name, "ssi")) {
if (of_node_name_eq(cpu_np, "ssi")) {
/* Only SSI needs to configure AUDMUX */
ret = fsl_asoc_card_audmux_init(np, priv);
if (ret) {
dev_err(&pdev->dev, "failed to init audmux\n");
goto asrc_fail;
}
} else if (strstr(cpu_np->name, "esai")) {
} else if (of_node_name_eq(cpu_np, "esai")) {
priv->cpu_priv.sysclk_id[1] = ESAI_HCKT_EXTAL;
priv->cpu_priv.sysclk_id[0] = ESAI_HCKR_EXTAL;
} else if (strstr(cpu_np->name, "sai")) {
} else if (of_node_name_eq(cpu_np, "sai")) {
priv->cpu_priv.sysclk_id[1] = FSL_SAI_CLK_MAST1;
priv->cpu_priv.sysclk_id[0] = FSL_SAI_CLK_MAST1;
}

View File

@@ -124,17 +124,7 @@ static int fsl_ssi_stats_show(struct seq_file *s, void *unused)
return 0;
}
static int fsl_ssi_stats_open(struct inode *inode, struct file *file)
{
return single_open(file, fsl_ssi_stats_show, inode->i_private);
}
static const struct file_operations fsl_ssi_stats_ops = {
.open = fsl_ssi_stats_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
DEFINE_SHOW_ATTRIBUTE(fsl_ssi_stats);
int fsl_ssi_debugfs_create(struct fsl_ssi_dbg *ssi_dbg, struct device *dev)
{
@@ -144,7 +134,7 @@ int fsl_ssi_debugfs_create(struct fsl_ssi_dbg *ssi_dbg, struct device *dev)
ssi_dbg->dbg_stats = debugfs_create_file("stats", 0444,
ssi_dbg->dbg_dir, ssi_dbg,
&fsl_ssi_stats_ops);
&fsl_ssi_stats_fops);
if (!ssi_dbg->dbg_stats) {
debugfs_remove(ssi_dbg->dbg_dir);
return -ENOMEM;

View File

@@ -6,6 +6,7 @@ config SND_SIMPLE_CARD
select SND_SIMPLE_CARD_UTILS
help
This option enables generic simple sound card support
It also support DPCM of multi CPU single Codec ststem.
config SND_SIMPLE_SCU_CARD
tristate "ASoC Simple SCU sound card support"
@@ -20,8 +21,9 @@ config SND_AUDIO_GRAPH_CARD
depends on OF
select SND_SIMPLE_CARD_UTILS
help
This option enables generic simple simple sound card support
This option enables generic simple sound card support
with OF-graph DT bindings.
It also support DPCM of multi CPU single Codec ststem.
config SND_AUDIO_GRAPH_SCU_CARD
tristate "ASoC Audio Graph SCU sound card support"

View File

@@ -23,19 +23,29 @@
struct graph_card_data {
struct snd_soc_card snd_card;
struct graph_dai_props {
struct asoc_simple_dai cpu_dai;
struct asoc_simple_dai codec_dai;
struct asoc_simple_dai *cpu_dai;
struct asoc_simple_dai *codec_dai;
struct snd_soc_dai_link_component codecs; /* single codec */
struct snd_soc_dai_link_component platform;
struct asoc_simple_card_data adata;
struct snd_soc_codec_conf *codec_conf;
unsigned int mclk_fs;
} *dai_props;
unsigned int mclk_fs;
struct asoc_simple_jack hp_jack;
struct asoc_simple_jack mic_jack;
struct snd_soc_dai_link *dai_link;
struct asoc_simple_dai *dais;
struct snd_soc_codec_conf *codec_conf;
struct gpio_desc *pa_gpio;
};
#define graph_priv_to_card(priv) (&(priv)->snd_card)
#define graph_priv_to_props(priv, i) ((priv)->dai_props + (i))
#define graph_priv_to_dev(priv) (graph_priv_to_card(priv)->dev)
#define graph_priv_to_link(priv, i) (graph_priv_to_card(priv)->dai_link + (i))
#define PREFIX "audio-graph-card,"
static int asoc_graph_card_outdrv_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol,
int event)
@@ -63,11 +73,6 @@ static const struct snd_soc_dapm_widget asoc_graph_card_dapm_widgets[] = {
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
};
#define graph_priv_to_card(priv) (&(priv)->snd_card)
#define graph_priv_to_props(priv, i) ((priv)->dai_props + (i))
#define graph_priv_to_dev(priv) (graph_priv_to_card(priv)->dev)
#define graph_priv_to_link(priv, i) (graph_priv_to_card(priv)->dai_link + (i))
static int asoc_graph_card_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
@@ -75,13 +80,13 @@ static int asoc_graph_card_startup(struct snd_pcm_substream *substream)
struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
int ret;
ret = asoc_simple_card_clk_enable(&dai_props->cpu_dai);
ret = asoc_simple_card_clk_enable(dai_props->cpu_dai);
if (ret)
return ret;
ret = asoc_simple_card_clk_enable(&dai_props->codec_dai);
ret = asoc_simple_card_clk_enable(dai_props->codec_dai);
if (ret)
asoc_simple_card_clk_disable(&dai_props->cpu_dai);
asoc_simple_card_clk_disable(dai_props->cpu_dai);
return ret;
}
@@ -92,9 +97,9 @@ static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream)
struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
asoc_simple_card_clk_disable(&dai_props->cpu_dai);
asoc_simple_card_clk_disable(dai_props->cpu_dai);
asoc_simple_card_clk_disable(&dai_props->codec_dai);
asoc_simple_card_clk_disable(dai_props->codec_dai);
}
static int asoc_graph_card_hw_params(struct snd_pcm_substream *substream,
@@ -108,9 +113,7 @@ static int asoc_graph_card_hw_params(struct snd_pcm_substream *substream,
unsigned int mclk, mclk_fs = 0;
int ret = 0;
if (priv->mclk_fs)
mclk_fs = priv->mclk_fs;
else if (dai_props->mclk_fs)
if (dai_props->mclk_fs)
mclk_fs = dai_props->mclk_fs;
if (mclk_fs) {
@@ -139,86 +142,238 @@ static const struct snd_soc_ops asoc_graph_card_ops = {
static int asoc_graph_card_dai_init(struct snd_soc_pcm_runtime *rtd)
{
struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
struct snd_soc_dai *codec = rtd->codec_dai;
struct snd_soc_dai *cpu = rtd->cpu_dai;
struct graph_dai_props *dai_props =
graph_priv_to_props(priv, rtd->num);
int ret;
struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
int ret = 0;
ret = asoc_simple_card_init_dai(codec, &dai_props->codec_dai);
ret = asoc_simple_card_init_dai(rtd->codec_dai,
dai_props->codec_dai);
if (ret < 0)
return ret;
ret = asoc_simple_card_init_dai(cpu, &dai_props->cpu_dai);
ret = asoc_simple_card_init_dai(rtd->cpu_dai,
dai_props->cpu_dai);
if (ret < 0)
return ret;
return 0;
}
static int asoc_graph_card_dai_link_of(struct device_node *cpu_port,
struct graph_card_data *priv,
int idx)
static int asoc_graph_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
asoc_simple_card_convert_fixup(&dai_props->adata, params);
return 0;
}
static int asoc_graph_card_dai_link_of_dpcm(struct device_node *top,
struct device_node *cpu_ep,
struct device_node *codec_ep,
struct graph_card_data *priv,
int *dai_idx, int link_idx,
int *conf_idx, int is_cpu)
{
struct device *dev = graph_priv_to_dev(priv);
struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, idx);
struct graph_dai_props *dai_props = graph_priv_to_props(priv, idx);
struct asoc_simple_dai *cpu_dai = &dai_props->cpu_dai;
struct asoc_simple_dai *codec_dai = &dai_props->codec_dai;
struct device_node *cpu_ep = of_get_next_child(cpu_port, NULL);
struct device_node *codec_ep = of_graph_get_remote_endpoint(cpu_ep);
struct device_node *rcpu_ep = of_graph_get_remote_endpoint(codec_ep);
struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, link_idx);
struct graph_dai_props *dai_props = graph_priv_to_props(priv, link_idx);
struct device_node *ep = is_cpu ? cpu_ep : codec_ep;
struct device_node *port = of_get_parent(ep);
struct device_node *ports = of_get_parent(port);
struct device_node *node = of_graph_get_port_parent(ep);
struct asoc_simple_dai *dai;
struct snd_soc_dai_link_component *codecs = dai_link->codecs;
int ret;
if (rcpu_ep != cpu_ep) {
dev_err(dev, "remote-endpoint mismatch (%s/%s/%s)\n",
cpu_ep->name, codec_ep->name, rcpu_ep->name);
ret = -EINVAL;
goto dai_link_of_err;
dev_dbg(dev, "link_of DPCM (for %s)\n", is_cpu ? "CPU" : "Codec");
of_property_read_u32(top, "mclk-fs", &dai_props->mclk_fs);
of_property_read_u32(ports, "mclk-fs", &dai_props->mclk_fs);
of_property_read_u32(port, "mclk-fs", &dai_props->mclk_fs);
of_property_read_u32(ep, "mclk-fs", &dai_props->mclk_fs);
asoc_simple_card_parse_convert(dev, top, NULL, &dai_props->adata);
asoc_simple_card_parse_convert(dev, node, PREFIX, &dai_props->adata);
asoc_simple_card_parse_convert(dev, ports, NULL, &dai_props->adata);
asoc_simple_card_parse_convert(dev, port, NULL, &dai_props->adata);
asoc_simple_card_parse_convert(dev, ep, NULL, &dai_props->adata);
of_node_put(ports);
of_node_put(port);
if (is_cpu) {
/* BE is dummy */
codecs->of_node = NULL;
codecs->dai_name = "snd-soc-dummy-dai";
codecs->name = "snd-soc-dummy";
/* FE settings */
dai_link->dynamic = 1;
dai_link->dpcm_merged_format = 1;
dai =
dai_props->cpu_dai = &priv->dais[(*dai_idx)++];
ret = asoc_simple_card_parse_graph_cpu(ep, dai_link);
if (ret)
return ret;
ret = asoc_simple_card_parse_clk_cpu(dev, ep, dai_link, dai);
if (ret < 0)
return ret;
ret = asoc_simple_card_set_dailink_name(dev, dai_link,
"fe.%s",
dai_link->cpu_dai_name);
if (ret < 0)
return ret;
/* card->num_links includes Codec */
asoc_simple_card_canonicalize_cpu(dai_link,
of_graph_get_endpoint_count(dai_link->cpu_of_node) == 1);
} else {
struct snd_soc_codec_conf *cconf;
/* FE is dummy */
dai_link->cpu_of_node = NULL;
dai_link->cpu_dai_name = "snd-soc-dummy-dai";
dai_link->cpu_name = "snd-soc-dummy";
/* BE settings */
dai_link->no_pcm = 1;
dai_link->be_hw_params_fixup = asoc_graph_card_be_hw_params_fixup;
dai =
dai_props->codec_dai = &priv->dais[(*dai_idx)++];
cconf =
dai_props->codec_conf = &priv->codec_conf[(*conf_idx)++];
ret = asoc_simple_card_parse_graph_codec(ep, dai_link);
if (ret < 0)
return ret;
ret = asoc_simple_card_parse_clk_codec(dev, ep, dai_link, dai);
if (ret < 0)
return ret;
ret = asoc_simple_card_set_dailink_name(dev, dai_link,
"be.%s",
codecs->dai_name);
if (ret < 0)
return ret;
/* check "prefix" from top node */
snd_soc_of_parse_node_prefix(top, cconf, codecs->of_node,
"prefix");
snd_soc_of_parse_node_prefix(node, cconf, codecs->of_node,
PREFIX "prefix");
snd_soc_of_parse_node_prefix(ports, cconf, codecs->of_node,
"prefix");
snd_soc_of_parse_node_prefix(port, cconf, codecs->of_node,
"prefix");
}
ret = asoc_simple_card_of_parse_tdm(ep, dai);
if (ret)
return ret;
ret = asoc_simple_card_canonicalize_dailink(dai_link);
if (ret < 0)
return ret;
ret = asoc_simple_card_parse_daifmt(dev, cpu_ep, codec_ep,
NULL, &dai_link->dai_fmt);
if (ret < 0)
goto dai_link_of_err;
return ret;
of_property_read_u32(cpu_ep, "mclk-fs", &dai_props->mclk_fs);
of_property_read_u32(codec_ep, "mclk-fs", &dai_props->mclk_fs);
dai_link->dpcm_playback = 1;
dai_link->dpcm_capture = 1;
dai_link->ops = &asoc_graph_card_ops;
dai_link->init = asoc_graph_card_dai_init;
return 0;
}
static int asoc_graph_card_dai_link_of(struct device_node *top,
struct device_node *cpu_ep,
struct device_node *codec_ep,
struct graph_card_data *priv,
int *dai_idx, int link_idx)
{
struct device *dev = graph_priv_to_dev(priv);
struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, link_idx);
struct graph_dai_props *dai_props = graph_priv_to_props(priv, link_idx);
struct device_node *cpu_port = of_get_parent(cpu_ep);
struct device_node *codec_port = of_get_parent(codec_ep);
struct device_node *cpu_ports = of_get_parent(cpu_port);
struct device_node *codec_ports = of_get_parent(codec_port);
struct asoc_simple_dai *cpu_dai;
struct asoc_simple_dai *codec_dai;
int ret;
dev_dbg(dev, "link_of\n");
cpu_dai =
dai_props->cpu_dai = &priv->dais[(*dai_idx)++];
codec_dai =
dai_props->codec_dai = &priv->dais[(*dai_idx)++];
/* Factor to mclk, used in hw_params() */
of_property_read_u32(top, "mclk-fs", &dai_props->mclk_fs);
of_property_read_u32(cpu_ports, "mclk-fs", &dai_props->mclk_fs);
of_property_read_u32(codec_ports, "mclk-fs", &dai_props->mclk_fs);
of_property_read_u32(cpu_port, "mclk-fs", &dai_props->mclk_fs);
of_property_read_u32(codec_port, "mclk-fs", &dai_props->mclk_fs);
of_property_read_u32(cpu_ep, "mclk-fs", &dai_props->mclk_fs);
of_property_read_u32(codec_ep, "mclk-fs", &dai_props->mclk_fs);
of_node_put(cpu_port);
of_node_put(cpu_ports);
of_node_put(codec_port);
of_node_put(codec_ports);
ret = asoc_simple_card_parse_daifmt(dev, cpu_ep, codec_ep,
NULL, &dai_link->dai_fmt);
if (ret < 0)
return ret;
ret = asoc_simple_card_parse_graph_cpu(cpu_ep, dai_link);
if (ret < 0)
goto dai_link_of_err;
return ret;
ret = asoc_simple_card_parse_graph_codec(codec_ep, dai_link);
if (ret < 0)
goto dai_link_of_err;
return ret;
ret = asoc_simple_card_of_parse_tdm(cpu_ep, cpu_dai);
if (ret < 0)
goto dai_link_of_err;
return ret;
ret = asoc_simple_card_of_parse_tdm(codec_ep, codec_dai);
if (ret < 0)
goto dai_link_of_err;
return ret;
ret = asoc_simple_card_parse_clk_cpu(dev, cpu_ep, dai_link, cpu_dai);
if (ret < 0)
goto dai_link_of_err;
return ret;
ret = asoc_simple_card_parse_clk_codec(dev, codec_ep, dai_link, codec_dai);
if (ret < 0)
goto dai_link_of_err;
return ret;
ret = asoc_simple_card_canonicalize_dailink(dai_link);
if (ret < 0)
goto dai_link_of_err;
return ret;
ret = asoc_simple_card_set_dailink_name(dev, dai_link,
"%s-%s",
dai_link->cpu_dai_name,
dai_link->codecs->dai_name);
if (ret < 0)
goto dai_link_of_err;
return ret;
dai_link->ops = &asoc_graph_card_ops;
dai_link->init = asoc_graph_card_dai_init;
@@ -226,12 +381,7 @@ static int asoc_graph_card_dai_link_of(struct device_node *cpu_port,
asoc_simple_card_canonicalize_cpu(dai_link,
of_graph_get_endpoint_count(dai_link->cpu_of_node) == 1);
dai_link_of_err:
of_node_put(cpu_ep);
of_node_put(rcpu_ep);
of_node_put(codec_ep);
return ret;
return 0;
}
static int asoc_graph_card_parse_of(struct graph_card_data *priv)
@@ -239,44 +389,173 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv)
struct of_phandle_iterator it;
struct device *dev = graph_priv_to_dev(priv);
struct snd_soc_card *card = graph_priv_to_card(priv);
struct device_node *node = dev->of_node;
int rc, idx = 0;
int ret;
struct device_node *top = dev->of_node;
struct device_node *node = top;
struct device_node *cpu_port;
struct device_node *cpu_ep = NULL;
struct device_node *codec_ep = NULL;
struct device_node *codec_port = NULL;
struct device_node *codec_port_old = NULL;
int rc, ret;
int link_idx, dai_idx, conf_idx;
int cpu;
ret = asoc_simple_card_of_parse_widgets(card, NULL);
if (ret < 0)
return ret;
ret = asoc_simple_card_of_parse_routing(card, NULL, 1);
ret = asoc_simple_card_of_parse_routing(card, NULL);
if (ret < 0)
return ret;
/* Factor to mclk, used in hw_params() */
of_property_read_u32(node, "mclk-fs", &priv->mclk_fs);
link_idx = 0;
dai_idx = 0;
conf_idx = 0;
codec_port_old = NULL;
for (cpu = 1; cpu >= 0; cpu--) {
/*
* Detect all CPU first, and Detect all Codec 2nd.
*
* In Normal sound case, all DAIs are detected
* as "CPU-Codec".
*
* In DPCM sound case,
* all CPUs are detected as "CPU-dummy", and
* all Codecs are detected as "dummy-Codec".
* To avoid random sub-device numbering,
* detect "dummy-Codec" in last;
*/
of_for_each_phandle(&it, rc, node, "dais", NULL, 0) {
cpu_port = it.node;
cpu_ep = NULL;
while (1) {
cpu_ep = of_get_next_child(cpu_port, cpu_ep);
if (!cpu_ep)
break;
of_for_each_phandle(&it, rc, node, "dais", NULL, 0) {
ret = asoc_graph_card_dai_link_of(it.node, priv, idx++);
if (ret < 0) {
of_node_put(it.node);
codec_ep = of_graph_get_remote_endpoint(cpu_ep);
codec_port = of_get_parent(codec_ep);
return ret;
of_node_put(codec_ep);
of_node_put(codec_port);
dev_dbg(dev, "%pOFf <-> %pOFf\n", cpu_ep, codec_ep);
if (of_get_child_count(codec_port) > 1) {
/*
* for DPCM sound
*/
if (!cpu) {
if (codec_port_old == codec_port)
continue;
codec_port_old = codec_port;
}
ret = asoc_graph_card_dai_link_of_dpcm(
top, cpu_ep, codec_ep, priv,
&dai_idx, link_idx++,
&conf_idx, cpu);
} else if (cpu) {
/*
* for Normal sound
*/
ret = asoc_graph_card_dai_link_of(
top, cpu_ep, codec_ep, priv,
&dai_idx, link_idx++);
}
if (ret < 0)
return ret;
}
}
}
return asoc_simple_card_parse_card_name(card, NULL);
}
static int asoc_graph_get_dais_count(struct device *dev)
static void asoc_graph_get_dais_count(struct device *dev,
int *link_num,
int *dais_num,
int *ccnf_num)
{
struct of_phandle_iterator it;
struct device_node *node = dev->of_node;
int count = 0;
struct device_node *cpu_port;
struct device_node *cpu_ep;
struct device_node *codec_ep;
struct device_node *codec_port;
struct device_node *codec_port_old;
struct device_node *codec_port_old2;
int rc;
of_for_each_phandle(&it, rc, node, "dais", NULL, 0)
count++;
/*
* link_num : number of links.
* CPU-Codec / CPU-dummy / dummy-Codec
* dais_num : number of DAIs
* ccnf_num : number of codec_conf
* same number for "dummy-Codec"
*
* ex1)
* CPU0 --- Codec0 link : 5
* CPU1 --- Codec1 dais : 7
* CPU2 -/ ccnf : 1
* CPU3 --- Codec2
*
* => 5 links = 2xCPU-Codec + 2xCPU-dummy + 1xdummy-Codec
* => 7 DAIs = 4xCPU + 3xCodec
* => 1 ccnf = 1xdummy-Codec
*
* ex2)
* CPU0 --- Codec0 link : 5
* CPU1 --- Codec1 dais : 6
* CPU2 -/ ccnf : 1
* CPU3 -/
*
* => 5 links = 1xCPU-Codec + 3xCPU-dummy + 1xdummy-Codec
* => 6 DAIs = 4xCPU + 2xCodec
* => 1 ccnf = 1xdummy-Codec
*
* ex3)
* CPU0 --- Codec0 link : 6
* CPU1 -/ dais : 6
* CPU2 --- Codec1 ccnf : 2
* CPU3 -/
*
* => 6 links = 0xCPU-Codec + 4xCPU-dummy + 2xdummy-Codec
* => 6 DAIs = 4xCPU + 2xCodec
* => 2 ccnf = 2xdummy-Codec
*/
codec_port_old = NULL;
codec_port_old2 = NULL;
of_for_each_phandle(&it, rc, node, "dais", NULL, 0) {
cpu_port = it.node;
cpu_ep = NULL;
while (1) {
cpu_ep = of_get_next_child(cpu_port, cpu_ep);
if (!cpu_ep)
break;
return count;
codec_ep = of_graph_get_remote_endpoint(cpu_ep);
codec_port = of_get_parent(codec_ep);
of_node_put(codec_ep);
of_node_put(codec_port);
(*link_num)++;
(*dais_num)++;
if (codec_port_old == codec_port) {
if (codec_port_old2 != codec_port_old) {
(*link_num)++;
(*ccnf_num)++;
}
codec_port_old2 = codec_port_old;
continue;
}
(*dais_num)++;
codec_port_old = codec_port;
}
}
}
static int asoc_graph_soc_card_probe(struct snd_soc_card *card)
@@ -300,22 +579,27 @@ static int asoc_graph_card_probe(struct platform_device *pdev)
struct graph_card_data *priv;
struct snd_soc_dai_link *dai_link;
struct graph_dai_props *dai_props;
struct asoc_simple_dai *dais;
struct device *dev = &pdev->dev;
struct snd_soc_card *card;
int num, ret, i;
struct snd_soc_codec_conf *cconf;
int lnum = 0, dnum = 0, cnum = 0;
int ret, i;
/* Allocate the private data and the DAI link array */
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
num = asoc_graph_get_dais_count(dev);
if (num == 0)
asoc_graph_get_dais_count(dev, &lnum, &dnum, &cnum);
if (!lnum || !dnum)
return -EINVAL;
dai_props = devm_kcalloc(dev, num, sizeof(*dai_props), GFP_KERNEL);
dai_link = devm_kcalloc(dev, num, sizeof(*dai_link), GFP_KERNEL);
if (!dai_props || !dai_link)
dai_props = devm_kcalloc(dev, lnum, sizeof(*dai_props), GFP_KERNEL);
dai_link = devm_kcalloc(dev, lnum, sizeof(*dai_link), GFP_KERNEL);
dais = devm_kcalloc(dev, dnum, sizeof(*dais), GFP_KERNEL);
cconf = devm_kcalloc(dev, cnum, sizeof(*cconf), GFP_KERNEL);
if (!dai_props || !dai_link || !dais)
return -ENOMEM;
/*
@@ -324,7 +608,7 @@ static int asoc_graph_card_probe(struct platform_device *pdev)
* see
* soc-core.c :: snd_soc_init_multicodec()
*/
for (i = 0; i < num; i++) {
for (i = 0; i < lnum; i++) {
dai_link[i].codecs = &dai_props[i].codecs;
dai_link[i].num_codecs = 1;
dai_link[i].platform = &dai_props[i].platform;
@@ -339,16 +623,20 @@ static int asoc_graph_card_probe(struct platform_device *pdev)
priv->dai_props = dai_props;
priv->dai_link = dai_link;
priv->dais = dais;
priv->codec_conf = cconf;
/* Init snd_soc_card */
card = graph_priv_to_card(priv);
card->owner = THIS_MODULE;
card->dev = dev;
card->dai_link = dai_link;
card->num_links = num;
card->dapm_widgets = asoc_graph_card_dapm_widgets;
card->num_dapm_widgets = ARRAY_SIZE(asoc_graph_card_dapm_widgets);
card->probe = asoc_graph_soc_card_probe;
card->owner = THIS_MODULE;
card->dev = dev;
card->dai_link = dai_link;
card->num_links = lnum;
card->dapm_widgets = asoc_graph_card_dapm_widgets;
card->num_dapm_widgets = ARRAY_SIZE(asoc_graph_card_dapm_widgets);
card->probe = asoc_graph_soc_card_probe;
card->codec_conf = cconf;
card->num_configs = cnum;
ret = asoc_graph_card_parse_of(priv);
if (ret < 0) {
@@ -379,6 +667,7 @@ static int asoc_graph_card_remove(struct platform_device *pdev)
static const struct of_device_id asoc_graph_of_match[] = {
{ .compatible = "audio-graph-card", },
{ .compatible = "audio-graph-scu-card", },
{},
};
MODULE_DEVICE_TABLE(of, asoc_graph_of_match);

View File

@@ -24,14 +24,18 @@
struct graph_card_data {
struct snd_soc_card snd_card;
struct snd_soc_codec_conf codec_conf;
struct graph_dai_props {
struct asoc_simple_dai dai;
struct asoc_simple_dai *cpu_dai;
struct asoc_simple_dai *codec_dai;
struct snd_soc_dai_link_component codecs;
struct snd_soc_dai_link_component platform;
struct asoc_simple_card_data adata;
struct snd_soc_codec_conf *codec_conf;
} *dai_props;
struct snd_soc_dai_link *dai_link;
struct asoc_simple_dai *dais;
struct asoc_simple_card_data adata;
struct snd_soc_codec_conf *codec_conf;
};
#define graph_priv_to_card(priv) (&(priv)->snd_card)
@@ -39,13 +43,24 @@ struct graph_card_data {
#define graph_priv_to_dev(priv) (graph_priv_to_card(priv)->dev)
#define graph_priv_to_link(priv, i) (graph_priv_to_card(priv)->dai_link + (i))
#define PREFIX "audio-graph-card,"
static int asoc_graph_card_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
int ret = 0;
return asoc_simple_card_clk_enable(&dai_props->dai);
ret = asoc_simple_card_clk_enable(dai_props->cpu_dai);
if (ret)
return ret;
ret = asoc_simple_card_clk_enable(dai_props->codec_dai);
if (ret)
asoc_simple_card_clk_disable(dai_props->cpu_dai);
return ret;
}
static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream)
@@ -54,7 +69,9 @@ static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream)
struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
asoc_simple_card_clk_disable(&dai_props->dai);
asoc_simple_card_clk_disable(dai_props->cpu_dai);
asoc_simple_card_clk_disable(dai_props->codec_dai);
}
static const struct snd_soc_ops asoc_graph_card_ops = {
@@ -65,39 +82,49 @@ static const struct snd_soc_ops asoc_graph_card_ops = {
static int asoc_graph_card_dai_init(struct snd_soc_pcm_runtime *rtd)
{
struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
struct snd_soc_dai *dai;
struct snd_soc_dai_link *dai_link;
struct graph_dai_props *dai_props;
int num = rtd->num;
struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
int ret = 0;
dai_link = graph_priv_to_link(priv, num);
dai_props = graph_priv_to_props(priv, num);
dai = dai_link->dynamic ?
rtd->cpu_dai :
rtd->codec_dai;
ret = asoc_simple_card_init_dai(rtd->codec_dai,
dai_props->codec_dai);
if (ret < 0)
return ret;
return asoc_simple_card_init_dai(dai, &dai_props->dai);
ret = asoc_simple_card_init_dai(rtd->cpu_dai,
dai_props->cpu_dai);
if (ret < 0)
return ret;
return 0;
}
static int asoc_graph_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
asoc_simple_card_convert_fixup(&dai_props->adata, params);
/* overwrite by top level adata if exist */
asoc_simple_card_convert_fixup(&priv->adata, params);
return 0;
}
static int asoc_graph_card_dai_link_of(struct device_node *ep,
static int asoc_graph_card_dai_link_of(struct device_node *cpu_ep,
struct device_node *codec_ep,
struct graph_card_data *priv,
unsigned int daifmt,
int idx, int is_fe)
int *dai_idx, int link_idx,
int *conf_idx, int is_fe)
{
struct device *dev = graph_priv_to_dev(priv);
struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, idx);
struct graph_dai_props *dai_props = graph_priv_to_props(priv, idx);
struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, link_idx);
struct graph_dai_props *dai_props = graph_priv_to_props(priv, link_idx);
struct snd_soc_card *card = graph_priv_to_card(priv);
struct device_node *ep = is_fe ? cpu_ep : codec_ep;
struct device_node *node = of_graph_get_port_parent(ep);
struct asoc_simple_dai *dai;
int ret;
if (is_fe) {
@@ -113,11 +140,14 @@ static int asoc_graph_card_dai_link_of(struct device_node *ep,
dai_link->dynamic = 1;
dai_link->dpcm_merged_format = 1;
dai =
dai_props->cpu_dai = &priv->dais[(*dai_idx)++];
ret = asoc_simple_card_parse_graph_cpu(ep, dai_link);
if (ret)
return ret;
ret = asoc_simple_card_parse_clk_cpu(dev, ep, dai_link, &dai_props->dai);
ret = asoc_simple_card_parse_clk_cpu(dev, ep, dai_link, dai);
if (ret < 0)
return ret;
@@ -131,6 +161,8 @@ static int asoc_graph_card_dai_link_of(struct device_node *ep,
asoc_simple_card_canonicalize_cpu(dai_link,
of_graph_get_endpoint_count(dai_link->cpu_of_node) == 1);
} else {
struct snd_soc_codec_conf *cconf;
/* FE is dummy */
dai_link->cpu_of_node = NULL;
dai_link->cpu_dai_name = "snd-soc-dummy-dai";
@@ -140,11 +172,17 @@ static int asoc_graph_card_dai_link_of(struct device_node *ep,
dai_link->no_pcm = 1;
dai_link->be_hw_params_fixup = asoc_graph_card_be_hw_params_fixup;
dai =
dai_props->codec_dai = &priv->dais[(*dai_idx)++];
cconf =
dai_props->codec_conf = &priv->codec_conf[(*conf_idx)++];
ret = asoc_simple_card_parse_graph_codec(ep, dai_link);
if (ret < 0)
return ret;
ret = asoc_simple_card_parse_clk_codec(dev, ep, dai_link, &dai_props->dai);
ret = asoc_simple_card_parse_clk_codec(dev, ep, dai_link, dai);
if (ret < 0)
return ret;
@@ -154,13 +192,20 @@ static int asoc_graph_card_dai_link_of(struct device_node *ep,
if (ret < 0)
return ret;
snd_soc_of_parse_audio_prefix(card,
&priv->codec_conf,
/* check "prefix" from top node */
snd_soc_of_parse_audio_prefix(card, cconf,
dai_link->codecs->of_node,
"prefix");
/* check "prefix" from each node if top doesn't have */
if (!cconf->of_node)
snd_soc_of_parse_node_prefix(node, cconf,
dai_link->codecs->of_node,
PREFIX "prefix");
}
ret = asoc_simple_card_of_parse_tdm(ep, &dai_props->dai);
asoc_simple_card_parse_convert(dev, node, PREFIX, &dai_props->adata);
ret = asoc_simple_card_of_parse_tdm(ep, dai);
if (ret)
return ret;
@@ -168,7 +213,11 @@ static int asoc_graph_card_dai_link_of(struct device_node *ep,
if (ret < 0)
return ret;
dai_link->dai_fmt = daifmt;
ret = asoc_simple_card_parse_daifmt(dev, cpu_ep, codec_ep,
NULL, &dai_link->dai_fmt);
if (ret < 0)
return ret;
dai_link->dpcm_playback = 1;
dai_link->dpcm_capture = 1;
dai_link->ops = &asoc_graph_card_ops;
@@ -186,11 +235,9 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv)
struct device_node *cpu_port;
struct device_node *cpu_ep;
struct device_node *codec_ep;
struct device_node *rcpu_ep;
struct device_node *codec_port;
struct device_node *codec_port_old;
unsigned int daifmt = 0;
int dai_idx, ret;
int dai_idx, link_idx, conf_idx, ret;
int rc, codec;
if (!node)
@@ -201,47 +248,20 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv)
* see simple-card
*/
ret = asoc_simple_card_of_parse_routing(card, NULL, 0);
ret = asoc_simple_card_of_parse_routing(card, NULL);
if (ret < 0)
return ret;
asoc_simple_card_parse_convert(dev, NULL, &priv->adata);
asoc_simple_card_parse_convert(dev, node, NULL, &priv->adata);
/*
* it supports multi CPU, single CODEC only here
* see asoc_graph_get_dais_count
*/
/* find 1st codec */
of_for_each_phandle(&it, rc, node, "dais", NULL, 0) {
cpu_port = it.node;
cpu_ep = of_get_next_child(cpu_port, NULL);
codec_ep = of_graph_get_remote_endpoint(cpu_ep);
rcpu_ep = of_graph_get_remote_endpoint(codec_ep);
of_node_put(cpu_ep);
of_node_put(codec_ep);
of_node_put(rcpu_ep);
if (!codec_ep)
continue;
if (rcpu_ep != cpu_ep) {
dev_err(dev, "remote-endpoint missmatch (%s/%s/%s)\n",
cpu_ep->name, codec_ep->name, rcpu_ep->name);
ret = -EINVAL;
goto parse_of_err;
}
ret = asoc_simple_card_parse_daifmt(dev, cpu_ep, codec_ep,
NULL, &daifmt);
if (ret < 0) {
of_node_put(cpu_port);
goto parse_of_err;
}
}
link_idx = 0;
dai_idx = 0;
conf_idx = 0;
codec_port_old = NULL;
for (codec = 0; codec < 2; codec++) {
/*
@@ -257,31 +277,23 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv)
of_node_put(cpu_ep);
of_node_put(codec_ep);
of_node_put(cpu_port);
of_node_put(codec_port);
it.node = NULL;
if (codec) {
if (!codec_port)
continue;
if (codec_port_old == codec_port)
continue;
codec_port_old = codec_port;
/* Back-End (= Codec) */
ret = asoc_graph_card_dai_link_of(codec_ep, priv, daifmt, dai_idx++, 0);
if (ret < 0) {
of_node_put(cpu_port);
goto parse_of_err;
}
} else {
/* Front-End (= CPU) */
ret = asoc_graph_card_dai_link_of(cpu_ep, priv, daifmt, dai_idx++, 1);
if (ret < 0) {
of_node_put(cpu_port);
goto parse_of_err;
}
}
ret = asoc_graph_card_dai_link_of(cpu_ep, codec_ep,
priv, &dai_idx,
link_idx++, &conf_idx,
!codec);
if (ret < 0)
goto parse_of_err;
}
}
@@ -289,13 +301,24 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv)
if (ret)
goto parse_of_err;
if ((card->num_links != link_idx) ||
(card->num_configs != conf_idx)) {
dev_err(dev, "dai_link or codec_config wrong (%d/%d, %d/%d)\n",
card->num_links, link_idx, card->num_configs, conf_idx);
ret = -EINVAL;
goto parse_of_err;
}
ret = 0;
parse_of_err:
return ret;
}
static int asoc_graph_get_dais_count(struct device *dev)
static void asoc_graph_get_dais_count(struct device *dev,
int *link_num,
int *dais_num,
int *ccnf_num)
{
struct of_phandle_iterator it;
struct device_node *node = dev->of_node;
@@ -304,10 +327,48 @@ static int asoc_graph_get_dais_count(struct device *dev)
struct device_node *codec_ep;
struct device_node *codec_port;
struct device_node *codec_port_old;
int count = 0;
struct device_node *codec_port_old2;
int rc;
/*
* link_num : number of links.
* CPU-Codec / CPU-dummy / dummy-Codec
* dais_num : number of DAIs
* ccnf_num : number of codec_conf
* same number for dummy-Codec
*
* ex1)
* CPU0 --- Codec0 link : 5
* CPU1 --- Codec1 dais : 7
* CPU2 -/ ccnf : 1
* CPU3 --- Codec2
*
* => 5 links = 2xCPU-Codec + 2xCPU-dummy + 1xdummy-Codec
* => 7 DAIs = 4xCPU + 3xCodec
* => 1 ccnf = 1xdummy-Codec
*
* ex2)
* CPU0 --- Codec0 link : 5
* CPU1 --- Codec1 dais : 6
* CPU2 -/ ccnf : 1
* CPU3 -/
*
* => 5 links = 1xCPU-Codec + 3xCPU-dummy + 1xdummy-Codec
* => 6 DAIs = 4xCPU + 2xCodec
* => 1 ccnf = 1xdummy-Codec
*
* ex3)
* CPU0 --- Codec0 link : 6
* CPU1 -/ dais : 6
* CPU2 --- Codec1 ccnf : 2
* CPU3 -/
*
* => 6 links = 0xCPU-Codec + 4xCPU-dummy + 2xdummy-Codec
* => 6 DAIs = 4xCPU + 2xCodec
* => 2 ccnf = 2xdummy-Codec
*/
codec_port_old = NULL;
codec_port_old2 = NULL;
of_for_each_phandle(&it, rc, node, "dais", NULL, 0) {
cpu_port = it.node;
cpu_ep = of_get_next_child(cpu_port, NULL);
@@ -318,20 +379,22 @@ static int asoc_graph_get_dais_count(struct device *dev)
of_node_put(codec_ep);
of_node_put(codec_port);
if (cpu_ep)
count++;
(*link_num)++;
(*dais_num)++;
if (!codec_port)
if (codec_port_old == codec_port) {
if (codec_port_old2 != codec_port_old) {
(*link_num)++;
(*ccnf_num)++;
}
codec_port_old2 = codec_port_old;
continue;
}
if (codec_port_old == codec_port)
continue;
count++;
(*dais_num)++;
codec_port_old = codec_port;
}
return count;
}
static int asoc_graph_card_probe(struct platform_device *pdev)
@@ -339,22 +402,27 @@ static int asoc_graph_card_probe(struct platform_device *pdev)
struct graph_card_data *priv;
struct snd_soc_dai_link *dai_link;
struct graph_dai_props *dai_props;
struct asoc_simple_dai *dais;
struct device *dev = &pdev->dev;
struct snd_soc_card *card;
int num, ret, i;
struct snd_soc_codec_conf *cconf;
int lnum = 0, dnum = 0, cnum = 0;
int ret, i;
/* Allocate the private data and the DAI link array */
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
num = asoc_graph_get_dais_count(dev);
if (num == 0)
asoc_graph_get_dais_count(dev, &lnum, &dnum, &cnum);
if (!lnum || !dnum)
return -EINVAL;
dai_props = devm_kcalloc(dev, num, sizeof(*dai_props), GFP_KERNEL);
dai_link = devm_kcalloc(dev, num, sizeof(*dai_link), GFP_KERNEL);
if (!dai_props || !dai_link)
dai_props = devm_kcalloc(dev, lnum, sizeof(*dai_props), GFP_KERNEL);
dai_link = devm_kcalloc(dev, lnum, sizeof(*dai_link), GFP_KERNEL);
dais = devm_kcalloc(dev, dnum, sizeof(*dais), GFP_KERNEL);
cconf = devm_kcalloc(dev, cnum, sizeof(*cconf), GFP_KERNEL);
if (!dai_props || !dai_link || !dais)
return -ENOMEM;
/*
@@ -363,7 +431,7 @@ static int asoc_graph_card_probe(struct platform_device *pdev)
* see
* soc-core.c :: snd_soc_init_multicodec()
*/
for (i = 0; i < num; i++) {
for (i = 0; i < lnum; i++) {
dai_link[i].codecs = &dai_props[i].codecs;
dai_link[i].num_codecs = 1;
dai_link[i].platform = &dai_props[i].platform;
@@ -371,15 +439,17 @@ static int asoc_graph_card_probe(struct platform_device *pdev)
priv->dai_props = dai_props;
priv->dai_link = dai_link;
priv->dais = dais;
priv->codec_conf = cconf;
/* Init snd_soc_card */
card = graph_priv_to_card(priv);
card->owner = THIS_MODULE;
card->dev = dev;
card->dai_link = priv->dai_link;
card->num_links = num;
card->codec_conf = &priv->codec_conf;
card->num_configs = 1;
card->num_links = lnum;
card->codec_conf = cconf;
card->num_configs = cnum;
ret = asoc_graph_card_parse_of(priv);
if (ret < 0) {

View File

@@ -32,10 +32,11 @@ void asoc_simple_card_convert_fixup(struct asoc_simple_card_data *data,
}
EXPORT_SYMBOL_GPL(asoc_simple_card_convert_fixup);
void asoc_simple_card_parse_convert(struct device *dev, char *prefix,
void asoc_simple_card_parse_convert(struct device *dev,
struct device_node *np,
char *prefix,
struct asoc_simple_card_data *data)
{
struct device_node *np = dev->of_node;
char prop[128];
if (!prefix)
@@ -151,21 +152,19 @@ int asoc_simple_card_parse_card_name(struct snd_soc_card *card,
}
EXPORT_SYMBOL_GPL(asoc_simple_card_parse_card_name);
static void asoc_simple_card_clk_register(struct asoc_simple_dai *dai,
struct clk *clk)
{
dai->clk = clk;
}
int asoc_simple_card_clk_enable(struct asoc_simple_dai *dai)
{
return clk_prepare_enable(dai->clk);
if (dai)
return clk_prepare_enable(dai->clk);
return 0;
}
EXPORT_SYMBOL_GPL(asoc_simple_card_clk_enable);
void asoc_simple_card_clk_disable(struct asoc_simple_dai *dai)
{
clk_disable_unprepare(dai->clk);
if (dai)
clk_disable_unprepare(dai->clk);
}
EXPORT_SYMBOL_GPL(asoc_simple_card_clk_disable);
@@ -200,7 +199,7 @@ int asoc_simple_card_parse_clk(struct device *dev,
if (!IS_ERR(clk)) {
simple_dai->sysclk = clk_get_rate(clk);
asoc_simple_card_clk_register(simple_dai, clk);
simple_dai->clk = clk;
} else if (!of_property_read_u32(node, "system-clock-frequency", &val)) {
simple_dai->sysclk = val;
} else {
@@ -272,13 +271,24 @@ static int asoc_simple_card_get_dai_id(struct device_node *ep)
{
struct device_node *node;
struct device_node *endpoint;
struct of_endpoint info;
int i, id;
int ret;
/* use driver specified DAI ID if exist */
ret = snd_soc_get_dai_id(ep);
if (ret != -ENOTSUPP)
return ret;
/* use endpoint/port reg if exist */
ret = of_graph_parse_endpoint(ep, &info);
if (ret == 0) {
if (info.id)
return info.id;
if (info.port)
return info.port;
}
node = of_graph_get_port_parent(ep);
/*
@@ -348,6 +358,9 @@ int asoc_simple_card_init_dai(struct snd_soc_dai *dai,
{
int ret;
if (!simple_dai)
return 0;
if (simple_dai->sysclk) {
ret = snd_soc_dai_set_sysclk(dai, 0, simple_dai->sysclk,
simple_dai->clk_direction);
@@ -415,8 +428,7 @@ int asoc_simple_card_clean_reference(struct snd_soc_card *card)
EXPORT_SYMBOL_GPL(asoc_simple_card_clean_reference);
int asoc_simple_card_of_parse_routing(struct snd_soc_card *card,
char *prefix,
int optional)
char *prefix)
{
struct device_node *node = card->dev->of_node;
char prop[128];
@@ -426,11 +438,8 @@ int asoc_simple_card_of_parse_routing(struct snd_soc_card *card,
snprintf(prop, sizeof(prop), "%s%s", prefix, "routing");
if (!of_property_read_bool(node, prop)) {
if (optional)
return 0;
return -EINVAL;
}
if (!of_property_read_bool(node, prop))
return 0;
return snd_soc_of_parse_audio_routing(card, prop);
}

View File

@@ -18,16 +18,19 @@
struct simple_card_data {
struct snd_soc_card snd_card;
struct simple_dai_props {
struct asoc_simple_dai cpu_dai;
struct asoc_simple_dai codec_dai;
struct asoc_simple_dai *cpu_dai;
struct asoc_simple_dai *codec_dai;
struct snd_soc_dai_link_component codecs; /* single codec */
struct snd_soc_dai_link_component platform;
struct asoc_simple_card_data adata;
struct snd_soc_codec_conf *codec_conf;
unsigned int mclk_fs;
} *dai_props;
unsigned int mclk_fs;
struct asoc_simple_jack hp_jack;
struct asoc_simple_jack mic_jack;
struct snd_soc_dai_link *dai_link;
struct asoc_simple_dai *dais;
struct snd_soc_codec_conf *codec_conf;
};
#define simple_priv_to_card(priv) (&(priv)->snd_card)
@@ -47,13 +50,13 @@ static int asoc_simple_card_startup(struct snd_pcm_substream *substream)
simple_priv_to_props(priv, rtd->num);
int ret;
ret = asoc_simple_card_clk_enable(&dai_props->cpu_dai);
ret = asoc_simple_card_clk_enable(dai_props->cpu_dai);
if (ret)
return ret;
ret = asoc_simple_card_clk_enable(&dai_props->codec_dai);
ret = asoc_simple_card_clk_enable(dai_props->codec_dai);
if (ret)
asoc_simple_card_clk_disable(&dai_props->cpu_dai);
asoc_simple_card_clk_disable(dai_props->cpu_dai);
return ret;
}
@@ -65,14 +68,17 @@ static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream)
struct simple_dai_props *dai_props =
simple_priv_to_props(priv, rtd->num);
asoc_simple_card_clk_disable(&dai_props->cpu_dai);
asoc_simple_card_clk_disable(dai_props->cpu_dai);
asoc_simple_card_clk_disable(&dai_props->codec_dai);
asoc_simple_card_clk_disable(dai_props->codec_dai);
}
static int asoc_simple_set_clk_rate(struct asoc_simple_dai *simple_dai,
unsigned long rate)
{
if (!simple_dai)
return 0;
if (!simple_dai->clk)
return 0;
@@ -94,19 +100,17 @@ static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream,
unsigned int mclk, mclk_fs = 0;
int ret = 0;
if (priv->mclk_fs)
mclk_fs = priv->mclk_fs;
else if (dai_props->mclk_fs)
if (dai_props->mclk_fs)
mclk_fs = dai_props->mclk_fs;
if (mclk_fs) {
mclk = params_rate(params) * mclk_fs;
ret = asoc_simple_set_clk_rate(&dai_props->codec_dai, mclk);
ret = asoc_simple_set_clk_rate(dai_props->codec_dai, mclk);
if (ret < 0)
return ret;
ret = asoc_simple_set_clk_rate(&dai_props->cpu_dai, mclk);
ret = asoc_simple_set_clk_rate(dai_props->cpu_dai, mclk);
if (ret < 0)
return ret;
@@ -134,33 +138,169 @@ static const struct snd_soc_ops asoc_simple_card_ops = {
static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
{
struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
struct snd_soc_dai *codec = rtd->codec_dai;
struct snd_soc_dai *cpu = rtd->cpu_dai;
struct simple_dai_props *dai_props =
simple_priv_to_props(priv, rtd->num);
struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num);
int ret;
ret = asoc_simple_card_init_dai(codec, &dai_props->codec_dai);
ret = asoc_simple_card_init_dai(rtd->codec_dai,
dai_props->codec_dai);
if (ret < 0)
return ret;
ret = asoc_simple_card_init_dai(cpu, &dai_props->cpu_dai);
ret = asoc_simple_card_init_dai(rtd->cpu_dai,
dai_props->cpu_dai);
if (ret < 0)
return ret;
return 0;
}
static int asoc_simple_card_dai_link_of(struct device_node *node,
static int asoc_simple_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num);
asoc_simple_card_convert_fixup(&dai_props->adata, params);
return 0;
}
static int asoc_simple_card_dai_link_of_dpcm(struct device_node *top,
struct device_node *node,
struct device_node *np,
struct device_node *codec,
struct simple_card_data *priv,
int *dai_idx, int link_idx,
int *conf_idx, int is_fe,
bool is_top_level_node)
{
struct device *dev = simple_priv_to_dev(priv);
struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, link_idx);
struct simple_dai_props *dai_props = simple_priv_to_props(priv, link_idx);
struct asoc_simple_dai *dai;
struct snd_soc_dai_link_component *codecs = dai_link->codecs;
char prop[128];
char *prefix = "";
int ret;
/* For single DAI link & old style of DT node */
if (is_top_level_node)
prefix = PREFIX;
if (is_fe) {
int is_single_links = 0;
/* BE is dummy */
codecs->of_node = NULL;
codecs->dai_name = "snd-soc-dummy-dai";
codecs->name = "snd-soc-dummy";
/* FE settings */
dai_link->dynamic = 1;
dai_link->dpcm_merged_format = 1;
dai =
dai_props->cpu_dai = &priv->dais[(*dai_idx)++];
ret = asoc_simple_card_parse_cpu(np, dai_link, DAI, CELL,
&is_single_links);
if (ret)
return ret;
ret = asoc_simple_card_parse_clk_cpu(dev, np, dai_link, dai);
if (ret < 0)
return ret;
ret = asoc_simple_card_set_dailink_name(dev, dai_link,
"fe.%s",
dai_link->cpu_dai_name);
if (ret < 0)
return ret;
asoc_simple_card_canonicalize_cpu(dai_link, is_single_links);
} else {
struct snd_soc_codec_conf *cconf;
/* FE is dummy */
dai_link->cpu_of_node = NULL;
dai_link->cpu_dai_name = "snd-soc-dummy-dai";
dai_link->cpu_name = "snd-soc-dummy";
/* BE settings */
dai_link->no_pcm = 1;
dai_link->be_hw_params_fixup = asoc_simple_card_be_hw_params_fixup;
dai =
dai_props->codec_dai = &priv->dais[(*dai_idx)++];
cconf =
dai_props->codec_conf = &priv->codec_conf[(*conf_idx)++];
ret = asoc_simple_card_parse_codec(np, dai_link, DAI, CELL);
if (ret < 0)
return ret;
ret = asoc_simple_card_parse_clk_codec(dev, np, dai_link, dai);
if (ret < 0)
return ret;
ret = asoc_simple_card_set_dailink_name(dev, dai_link,
"be.%s",
codecs->dai_name);
if (ret < 0)
return ret;
/* check "prefix" from top node */
snd_soc_of_parse_node_prefix(top, cconf, codecs->of_node,
PREFIX "prefix");
snd_soc_of_parse_node_prefix(node, cconf, codecs->of_node,
"prefix");
snd_soc_of_parse_node_prefix(np, cconf, codecs->of_node,
"prefix");
}
asoc_simple_card_parse_convert(dev, top, PREFIX, &dai_props->adata);
asoc_simple_card_parse_convert(dev, node, prefix, &dai_props->adata);
asoc_simple_card_parse_convert(dev, np, NULL, &dai_props->adata);
ret = asoc_simple_card_of_parse_tdm(np, dai);
if (ret)
return ret;
ret = asoc_simple_card_canonicalize_dailink(dai_link);
if (ret < 0)
return ret;
snprintf(prop, sizeof(prop), "%smclk-fs", prefix);
of_property_read_u32(top, PREFIX "mclk-fs", &dai_props->mclk_fs);
of_property_read_u32(node, prop, &dai_props->mclk_fs);
of_property_read_u32(np, prop, &dai_props->mclk_fs);
ret = asoc_simple_card_parse_daifmt(dev, node, codec,
prefix, &dai_link->dai_fmt);
if (ret < 0)
return ret;
dai_link->dpcm_playback = 1;
dai_link->dpcm_capture = 1;
dai_link->ops = &asoc_simple_card_ops;
dai_link->init = asoc_simple_card_dai_init;
return 0;
}
static int asoc_simple_card_dai_link_of(struct device_node *top,
struct device_node *node,
struct simple_card_data *priv,
int idx,
int *dai_idx, int link_idx,
bool is_top_level_node)
{
struct device *dev = simple_priv_to_dev(priv);
struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx);
struct simple_dai_props *dai_props = simple_priv_to_props(priv, idx);
struct asoc_simple_dai *cpu_dai = &dai_props->cpu_dai;
struct asoc_simple_dai *codec_dai = &dai_props->codec_dai;
struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, link_idx);
struct simple_dai_props *dai_props = simple_priv_to_props(priv, link_idx);
struct asoc_simple_dai *cpu_dai;
struct asoc_simple_dai *codec_dai;
struct device_node *cpu = NULL;
struct device_node *plat = NULL;
struct device_node *codec = NULL;
@@ -193,12 +333,21 @@ static int asoc_simple_card_dai_link_of(struct device_node *node,
goto dai_link_of_err;
}
cpu_dai =
dai_props->cpu_dai = &priv->dais[(*dai_idx)++];
codec_dai =
dai_props->codec_dai = &priv->dais[(*dai_idx)++];
ret = asoc_simple_card_parse_daifmt(dev, node, codec,
prefix, &dai_link->dai_fmt);
if (ret < 0)
goto dai_link_of_err;
of_property_read_u32(node, "mclk-fs", &dai_props->mclk_fs);
snprintf(prop, sizeof(prop), "%smclk-fs", prefix);
of_property_read_u32(top, PREFIX "mclk-fs", &dai_props->mclk_fs);
of_property_read_u32(node, prop, &dai_props->mclk_fs);
of_property_read_u32(cpu, prop, &dai_props->mclk_fs);
of_property_read_u32(codec, prop, &dai_props->mclk_fs);
ret = asoc_simple_card_parse_cpu(cpu, dai_link,
DAI, CELL, &single_cpu);
@@ -286,61 +435,148 @@ static int asoc_simple_card_parse_aux_devs(struct device_node *node,
static int asoc_simple_card_parse_of(struct simple_card_data *priv)
{
struct device *dev = simple_priv_to_dev(priv);
struct device_node *top = dev->of_node;
struct snd_soc_card *card = simple_priv_to_card(priv);
struct device_node *dai_link;
struct device_node *node = dev->of_node;
int ret;
struct device_node *node;
struct device_node *np;
struct device_node *codec;
bool is_fe;
int ret, loop;
int dai_idx, link_idx, conf_idx;
if (!node)
if (!top)
return -EINVAL;
dai_link = of_get_child_by_name(node, PREFIX "dai-link");
ret = asoc_simple_card_of_parse_widgets(card, PREFIX);
if (ret < 0)
goto card_parse_end;
return ret;
ret = asoc_simple_card_of_parse_routing(card, PREFIX, 1);
ret = asoc_simple_card_of_parse_routing(card, PREFIX);
if (ret < 0)
goto card_parse_end;
/* Factor to mclk, used in hw_params() */
of_property_read_u32(node, PREFIX "mclk-fs", &priv->mclk_fs);
return ret;
/* Single/Muti DAI link(s) & New style of DT node */
if (dai_link) {
struct device_node *np = NULL;
int i = 0;
for_each_child_of_node(node, np) {
dev_dbg(dev, "\tlink %d:\n", i);
ret = asoc_simple_card_dai_link_of(np, priv,
i, false);
if (ret < 0) {
of_node_put(np);
goto card_parse_end;
}
i++;
}
} else {
/* For single DAI link & old style of DT node */
ret = asoc_simple_card_dai_link_of(node, priv, 0, true);
if (ret < 0)
goto card_parse_end;
loop = 1;
link_idx = 0;
dai_idx = 0;
conf_idx = 0;
node = of_get_child_by_name(top, PREFIX "dai-link");
if (!node) {
node = dev->of_node;
loop = 0;
}
do {
/* DPCM */
if (of_get_child_count(node) > 2) {
for_each_child_of_node(node, np) {
codec = of_get_child_by_name(node,
loop ? "codec" :
PREFIX "codec");
if (!codec)
return -ENODEV;
is_fe = (np != codec);
ret = asoc_simple_card_dai_link_of_dpcm(
top, node, np, codec, priv,
&dai_idx, link_idx++, &conf_idx,
is_fe, !loop);
}
} else {
ret = asoc_simple_card_dai_link_of(
top, node, priv,
&dai_idx, link_idx++, !loop);
}
if (ret < 0)
return ret;
node = of_get_next_child(top, node);
} while (loop && node);
ret = asoc_simple_card_parse_card_name(card, PREFIX);
if (ret < 0)
goto card_parse_end;
return ret;
ret = asoc_simple_card_parse_aux_devs(node, priv);
card_parse_end:
of_node_put(dai_link);
ret = asoc_simple_card_parse_aux_devs(top, priv);
return ret;
}
static void asoc_simple_card_get_dais_count(struct device *dev,
int *link_num,
int *dais_num,
int *ccnf_num)
{
struct device_node *top = dev->of_node;
struct device_node *node;
int loop;
int num;
/*
* link_num : number of links.
* CPU-Codec / CPU-dummy / dummy-Codec
* dais_num : number of DAIs
* ccnf_num : number of codec_conf
* same number for "dummy-Codec"
*
* ex1)
* CPU0 --- Codec0 link : 5
* CPU1 --- Codec1 dais : 7
* CPU2 -/ ccnf : 1
* CPU3 --- Codec2
*
* => 5 links = 2xCPU-Codec + 2xCPU-dummy + 1xdummy-Codec
* => 7 DAIs = 4xCPU + 3xCodec
* => 1 ccnf = 1xdummy-Codec
*
* ex2)
* CPU0 --- Codec0 link : 5
* CPU1 --- Codec1 dais : 6
* CPU2 -/ ccnf : 1
* CPU3 -/
*
* => 5 links = 1xCPU-Codec + 3xCPU-dummy + 1xdummy-Codec
* => 6 DAIs = 4xCPU + 2xCodec
* => 1 ccnf = 1xdummy-Codec
*
* ex3)
* CPU0 --- Codec0 link : 6
* CPU1 -/ dais : 6
* CPU2 --- Codec1 ccnf : 2
* CPU3 -/
*
* => 6 links = 0xCPU-Codec + 4xCPU-dummy + 2xdummy-Codec
* => 6 DAIs = 4xCPU + 2xCodec
* => 2 ccnf = 2xdummy-Codec
*/
if (!top) {
(*link_num) = 1;
(*dais_num) = 2;
(*ccnf_num) = 0;
return;
}
loop = 1;
node = of_get_child_by_name(top, PREFIX "dai-link");
if (!node) {
node = top;
loop = 0;
}
do {
num = of_get_child_count(node);
(*dais_num) += num;
if (num > 2) {
(*link_num) += num;
(*ccnf_num)++;
} else {
(*link_num)++;
}
node = of_get_next_child(top, node);
} while (loop && node);
}
static int asoc_simple_soc_card_probe(struct snd_soc_card *card)
{
struct simple_card_data *priv = snd_soc_card_get_drvdata(card);
@@ -362,25 +598,28 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
struct simple_card_data *priv;
struct snd_soc_dai_link *dai_link;
struct simple_dai_props *dai_props;
struct asoc_simple_dai *dais;
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct snd_soc_card *card;
int num, ret, i;
/* Get the number of DAI links */
if (np && of_get_child_by_name(np, PREFIX "dai-link"))
num = of_get_child_count(np);
else
num = 1;
struct snd_soc_codec_conf *cconf;
int lnum = 0, dnum = 0, cnum = 0;
int ret, i;
/* Allocate the private data and the DAI link array */
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
dai_props = devm_kcalloc(dev, num, sizeof(*dai_props), GFP_KERNEL);
dai_link = devm_kcalloc(dev, num, sizeof(*dai_link), GFP_KERNEL);
if (!dai_props || !dai_link)
asoc_simple_card_get_dais_count(dev, &lnum, &dnum, &cnum);
if (!lnum || !dnum)
return -EINVAL;
dai_props = devm_kcalloc(dev, lnum, sizeof(*dai_props), GFP_KERNEL);
dai_link = devm_kcalloc(dev, lnum, sizeof(*dai_link), GFP_KERNEL);
dais = devm_kcalloc(dev, dnum, sizeof(*dais), GFP_KERNEL);
cconf = devm_kcalloc(dev, cnum, sizeof(*cconf), GFP_KERNEL);
if (!dai_props || !dai_link || !dais)
return -ENOMEM;
/*
@@ -389,7 +628,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
* see
* soc-core.c :: snd_soc_init_multicodec()
*/
for (i = 0; i < num; i++) {
for (i = 0; i < lnum; i++) {
dai_link[i].codecs = &dai_props[i].codecs;
dai_link[i].num_codecs = 1;
dai_link[i].platform = &dai_props[i].platform;
@@ -397,13 +636,17 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
priv->dai_props = dai_props;
priv->dai_link = dai_link;
priv->dais = dais;
priv->codec_conf = cconf;
/* Init snd_soc_card */
card = simple_priv_to_card(priv);
card->owner = THIS_MODULE;
card->dev = dev;
card->dai_link = priv->dai_link;
card->num_links = num;
card->num_links = lnum;
card->codec_conf = cconf;
card->num_configs = cnum;
card->probe = asoc_simple_soc_card_probe;
if (np && of_device_is_available(np)) {
@@ -419,6 +662,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
struct asoc_simple_card_info *cinfo;
struct snd_soc_dai_link_component *codecs;
struct snd_soc_dai_link_component *platform;
int dai_idx = 0;
cinfo = dev->platform_data;
if (!cinfo) {
@@ -435,6 +679,9 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
return -EINVAL;
}
dai_props->cpu_dai = &priv->dais[dai_idx++];
dai_props->codec_dai = &priv->dais[dai_idx++];
codecs = dai_link->codecs;
codecs->name = cinfo->codec;
codecs->dai_name = cinfo->codec_dai.name;
@@ -448,10 +695,10 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
dai_link->cpu_dai_name = cinfo->cpu_dai.name;
dai_link->dai_fmt = cinfo->daifmt;
dai_link->init = asoc_simple_card_dai_init;
memcpy(&priv->dai_props->cpu_dai, &cinfo->cpu_dai,
sizeof(priv->dai_props->cpu_dai));
memcpy(&priv->dai_props->codec_dai, &cinfo->codec_dai,
sizeof(priv->dai_props->codec_dai));
memcpy(priv->dai_props->cpu_dai, &cinfo->cpu_dai,
sizeof(*priv->dai_props->cpu_dai));
memcpy(priv->dai_props->codec_dai, &cinfo->codec_dai,
sizeof(*priv->dai_props->codec_dai));
}
snd_soc_card_set_drvdata(card, priv);
@@ -476,6 +723,7 @@ static int asoc_simple_card_remove(struct platform_device *pdev)
static const struct of_device_id asoc_simple_of_match[] = {
{ .compatible = "simple-audio-card", },
{ .compatible = "simple-scu-audio-card", },
{},
};
MODULE_DEVICE_TABLE(of, asoc_simple_of_match);

View File

@@ -21,14 +21,18 @@
struct simple_card_data {
struct snd_soc_card snd_card;
struct snd_soc_codec_conf codec_conf;
struct simple_dai_props {
struct asoc_simple_dai dai;
struct asoc_simple_dai *cpu_dai;
struct asoc_simple_dai *codec_dai;
struct snd_soc_dai_link_component codecs;
struct snd_soc_dai_link_component platform;
struct asoc_simple_card_data adata;
struct snd_soc_codec_conf *codec_conf;
} *dai_props;
struct snd_soc_dai_link *dai_link;
struct asoc_simple_dai *dais;
struct asoc_simple_card_data adata;
struct snd_soc_codec_conf *codec_conf;
};
#define simple_priv_to_card(priv) (&(priv)->snd_card)
@@ -46,8 +50,17 @@ static int asoc_simple_card_startup(struct snd_pcm_substream *substream)
struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
struct simple_dai_props *dai_props =
simple_priv_to_props(priv, rtd->num);
int ret;
return asoc_simple_card_clk_enable(&dai_props->dai);
ret = asoc_simple_card_clk_enable(dai_props->cpu_dai);
if (ret)
return ret;
ret = asoc_simple_card_clk_enable(dai_props->codec_dai);
if (ret)
asoc_simple_card_clk_disable(dai_props->cpu_dai);
return ret;
}
static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream)
@@ -57,7 +70,9 @@ static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream)
struct simple_dai_props *dai_props =
simple_priv_to_props(priv, rtd->num);
asoc_simple_card_clk_disable(&dai_props->dai);
asoc_simple_card_clk_disable(dai_props->cpu_dai);
asoc_simple_card_clk_disable(dai_props->codec_dai);
}
static const struct snd_soc_ops asoc_simple_card_ops = {
@@ -67,42 +82,57 @@ static const struct snd_soc_ops asoc_simple_card_ops = {
static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
{
struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
struct snd_soc_dai *dai;
struct snd_soc_dai_link *dai_link;
struct simple_dai_props *dai_props;
int num = rtd->num;
struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num);
int ret;
dai_link = simple_priv_to_link(priv, num);
dai_props = simple_priv_to_props(priv, num);
dai = dai_link->dynamic ?
rtd->cpu_dai :
rtd->codec_dai;
ret = asoc_simple_card_init_dai(rtd->codec_dai,
dai_props->codec_dai);
if (ret < 0)
return ret;
return asoc_simple_card_init_dai(dai, &dai_props->dai);
ret = asoc_simple_card_init_dai(rtd->cpu_dai,
dai_props->cpu_dai);
if (ret < 0)
return ret;
return 0;
}
static int asoc_simple_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num);
asoc_simple_card_convert_fixup(&dai_props->adata, params);
/* overwrite by top level adata if exist */
asoc_simple_card_convert_fixup(&priv->adata, params);
return 0;
}
static int asoc_simple_card_dai_link_of(struct device_node *np,
static int asoc_simple_card_dai_link_of(struct device_node *link,
struct device_node *np,
struct device_node *codec,
struct simple_card_data *priv,
unsigned int daifmt,
int idx, bool is_fe)
int *dai_idx, int link_idx,
int *conf_idx, int is_fe,
bool is_top_level_node)
{
struct device *dev = simple_priv_to_dev(priv);
struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx);
struct simple_dai_props *dai_props = simple_priv_to_props(priv, idx);
struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, link_idx);
struct simple_dai_props *dai_props = simple_priv_to_props(priv, link_idx);
struct snd_soc_card *card = simple_priv_to_card(priv);
struct asoc_simple_dai *dai;
char *prefix = "";
int ret;
/* For single DAI link & old style of DT node */
if (is_top_level_node)
prefix = PREFIX;
if (is_fe) {
int is_single_links = 0;
struct snd_soc_dai_link_component *codecs;
@@ -117,12 +147,15 @@ static int asoc_simple_card_dai_link_of(struct device_node *np,
dai_link->dynamic = 1;
dai_link->dpcm_merged_format = 1;
dai =
dai_props->cpu_dai = &priv->dais[(*dai_idx)++];
ret = asoc_simple_card_parse_cpu(np, dai_link, DAI, CELL,
&is_single_links);
if (ret)
return ret;
ret = asoc_simple_card_parse_clk_cpu(dev, np, dai_link, &dai_props->dai);
ret = asoc_simple_card_parse_clk_cpu(dev, np, dai_link, dai);
if (ret < 0)
return ret;
@@ -134,6 +167,8 @@ static int asoc_simple_card_dai_link_of(struct device_node *np,
asoc_simple_card_canonicalize_cpu(dai_link, is_single_links);
} else {
struct snd_soc_codec_conf *cconf;
/* FE is dummy */
dai_link->cpu_of_node = NULL;
dai_link->cpu_dai_name = "snd-soc-dummy-dai";
@@ -143,11 +178,17 @@ static int asoc_simple_card_dai_link_of(struct device_node *np,
dai_link->no_pcm = 1;
dai_link->be_hw_params_fixup = asoc_simple_card_be_hw_params_fixup;
dai =
dai_props->codec_dai = &priv->dais[(*dai_idx)++];
cconf =
dai_props->codec_conf = &priv->codec_conf[(*conf_idx)++];
ret = asoc_simple_card_parse_codec(np, dai_link, DAI, CELL);
if (ret < 0)
return ret;
ret = asoc_simple_card_parse_clk_codec(dev, np, dai_link, &dai_props->dai);
ret = asoc_simple_card_parse_clk_codec(dev, np, dai_link, dai);
if (ret < 0)
return ret;
@@ -157,13 +198,20 @@ static int asoc_simple_card_dai_link_of(struct device_node *np,
if (ret < 0)
return ret;
snd_soc_of_parse_audio_prefix(card,
&priv->codec_conf,
/* check "prefix" from top node */
snd_soc_of_parse_audio_prefix(card, cconf,
dai_link->codecs->of_node,
PREFIX "prefix");
/* check "prefix" from each node if top doesn't have */
if (!cconf->of_node)
snd_soc_of_parse_node_prefix(np, cconf,
dai_link->codecs->of_node,
"prefix");
}
ret = asoc_simple_card_of_parse_tdm(np, &dai_props->dai);
asoc_simple_card_parse_convert(dev, link, prefix, &dai_props->adata);
ret = asoc_simple_card_of_parse_tdm(np, dai);
if (ret)
return ret;
@@ -171,7 +219,11 @@ static int asoc_simple_card_dai_link_of(struct device_node *np,
if (ret < 0)
return ret;
dai_link->dai_fmt = daifmt;
ret = asoc_simple_card_parse_daifmt(dev, link, codec,
prefix, &dai_link->dai_fmt);
if (ret < 0)
return ret;
dai_link->dpcm_playback = 1;
dai_link->dpcm_capture = 1;
dai_link->ops = &asoc_simple_card_ops;
@@ -184,47 +236,57 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv)
{
struct device *dev = simple_priv_to_dev(priv);
struct device_node *top = dev->of_node;
struct device_node *node;
struct device_node *np;
struct device_node *codec;
struct snd_soc_card *card = simple_priv_to_card(priv);
struct device_node *node = dev->of_node;
unsigned int daifmt = 0;
bool is_fe;
int ret, i;
int ret, loop;
int dai_idx, link_idx, conf_idx;
if (!node)
if (!top)
return -EINVAL;
ret = asoc_simple_card_of_parse_widgets(card, PREFIX);
if (ret < 0)
return ret;
ret = asoc_simple_card_of_parse_routing(card, PREFIX, 0);
ret = asoc_simple_card_of_parse_routing(card, PREFIX);
if (ret < 0)
return ret;
asoc_simple_card_parse_convert(dev, PREFIX, &priv->adata);
asoc_simple_card_parse_convert(dev, top, PREFIX, &priv->adata);
/* find 1st codec */
np = of_get_child_by_name(node, PREFIX "codec");
if (!np)
return -ENODEV;
ret = asoc_simple_card_parse_daifmt(dev, node, np, PREFIX, &daifmt);
if (ret < 0)
return ret;
i = 0;
for_each_child_of_node(node, np) {
is_fe = false;
if (strcmp(np->name, PREFIX "cpu") == 0)
is_fe = true;
ret = asoc_simple_card_dai_link_of(np, priv, daifmt, i, is_fe);
if (ret < 0)
return ret;
i++;
loop = 1;
link_idx = 0;
dai_idx = 0;
conf_idx = 0;
node = of_get_child_by_name(top, PREFIX "dai-link");
if (!node) {
node = dev->of_node;
loop = 0;
}
do {
codec = of_get_child_by_name(node,
loop ? "codec" : PREFIX "codec");
if (!codec)
return -ENODEV;
for_each_child_of_node(node, np) {
is_fe = (np != codec);
ret = asoc_simple_card_dai_link_of(node, np, codec, priv,
&dai_idx, link_idx++,
&conf_idx,
is_fe, !loop);
if (ret < 0)
return ret;
}
node = of_get_next_child(top, node);
} while (loop && node);
ret = asoc_simple_card_parse_card_name(card, PREFIX);
if (ret < 0)
return ret;
@@ -232,26 +294,106 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv)
return 0;
}
static void asoc_simple_card_get_dais_count(struct device *dev,
int *link_num,
int *dais_num,
int *ccnf_num)
{
struct device_node *top = dev->of_node;
struct device_node *node;
int loop;
int num;
/*
* link_num : number of links.
* CPU-Codec / CPU-dummy / dummy-Codec
* dais_num : number of DAIs
* ccnf_num : number of codec_conf
* same number for "dummy-Codec"
*
* ex1)
* CPU0 --- Codec0 link : 5
* CPU1 --- Codec1 dais : 7
* CPU2 -/ ccnf : 1
* CPU3 --- Codec2
*
* => 5 links = 2xCPU-Codec + 2xCPU-dummy + 1xdummy-Codec
* => 7 DAIs = 4xCPU + 3xCodec
* => 1 ccnf = 1xdummy-Codec
*
* ex2)
* CPU0 --- Codec0 link : 5
* CPU1 --- Codec1 dais : 6
* CPU2 -/ ccnf : 1
* CPU3 -/
*
* => 5 links = 1xCPU-Codec + 3xCPU-dummy + 1xdummy-Codec
* => 6 DAIs = 4xCPU + 2xCodec
* => 1 ccnf = 1xdummy-Codec
*
* ex3)
* CPU0 --- Codec0 link : 6
* CPU1 -/ dais : 6
* CPU2 --- Codec1 ccnf : 2
* CPU3 -/
*
* => 6 links = 0xCPU-Codec + 4xCPU-dummy + 2xdummy-Codec
* => 6 DAIs = 4xCPU + 2xCodec
* => 2 ccnf = 2xdummy-Codec
*/
if (!top) {
(*link_num) = 1;
(*dais_num) = 2;
(*ccnf_num) = 0;
return;
}
loop = 1;
node = of_get_child_by_name(top, PREFIX "dai-link");
if (!node) {
node = top;
loop = 0;
}
do {
num = of_get_child_count(node);
(*dais_num) += num;
if (num > 2) {
(*link_num) += num;
(*ccnf_num)++;
} else {
(*link_num)++;
}
node = of_get_next_child(top, node);
} while (loop && node);
}
static int asoc_simple_card_probe(struct platform_device *pdev)
{
struct simple_card_data *priv;
struct snd_soc_dai_link *dai_link;
struct simple_dai_props *dai_props;
struct asoc_simple_dai *dais;
struct snd_soc_card *card;
struct snd_soc_codec_conf *cconf;
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
int num, ret, i;
int ret, i;
int lnum = 0, dnum = 0, cnum = 0;
/* Allocate the private data */
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
num = of_get_child_count(np);
asoc_simple_card_get_dais_count(dev, &lnum, &dnum, &cnum);
if (!lnum || !dnum)
return -EINVAL;
dai_props = devm_kcalloc(dev, num, sizeof(*dai_props), GFP_KERNEL);
dai_link = devm_kcalloc(dev, num, sizeof(*dai_link), GFP_KERNEL);
if (!dai_props || !dai_link)
dai_props = devm_kcalloc(dev, lnum, sizeof(*dai_props), GFP_KERNEL);
dai_link = devm_kcalloc(dev, lnum, sizeof(*dai_link), GFP_KERNEL);
dais = devm_kcalloc(dev, dnum, sizeof(*dais), GFP_KERNEL);
cconf = devm_kcalloc(dev, cnum, sizeof(*cconf), GFP_KERNEL);
if (!dai_props || !dai_link || !dais)
return -ENOMEM;
/*
@@ -260,7 +402,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
* see
* soc-core.c :: snd_soc_init_multicodec()
*/
for (i = 0; i < num; i++) {
for (i = 0; i < lnum; i++) {
dai_link[i].codecs = &dai_props[i].codecs;
dai_link[i].num_codecs = 1;
dai_link[i].platform = &dai_props[i].platform;
@@ -268,15 +410,17 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
priv->dai_props = dai_props;
priv->dai_link = dai_link;
priv->dais = dais;
priv->codec_conf = cconf;
/* Init snd_soc_card */
card = simple_priv_to_card(priv);
card->owner = THIS_MODULE;
card->dev = dev;
card->dai_link = priv->dai_link;
card->num_links = num;
card->codec_conf = &priv->codec_conf;
card->num_configs = 1;
card->num_links = lnum;
card->codec_conf = cconf;
card->num_configs = cnum;
ret = asoc_simple_card_parse_of(priv);
if (ret < 0) {

View File

@@ -102,15 +102,74 @@ config SND_SST_ATOM_HIFI2_PLATFORM_ACPI
recommended option
config SND_SOC_INTEL_SKYLAKE
tristate "SKL/BXT/KBL/GLK/CNL... Platforms"
tristate "All Skylake/SST Platforms"
depends on PCI && ACPI
select SND_SOC_INTEL_SKYLAKE_COMMON
select SND_SOC_INTEL_SKL
select SND_SOC_INTEL_APL
select SND_SOC_INTEL_KBL
select SND_SOC_INTEL_GLK
select SND_SOC_INTEL_CNL
select SND_SOC_INTEL_CFL
help
If you have a Intel Skylake/Broxton/ApolloLake/KabyLake/
GeminiLake or CannonLake platform with the DSP enabled in the BIOS
then enable this option by saying Y or m.
This is a backwards-compatible option to select all devices
supported by the Intel SST/Skylake driver. This option is no
longer recommended and will be deprecated when the SOF
driver is introduced. Distributions should explicitly
select which platform uses this driver.
if SND_SOC_INTEL_SKYLAKE
config SND_SOC_INTEL_SKL
tristate "Skylake Platforms"
depends on PCI && ACPI
select SND_SOC_INTEL_SKYLAKE_FAMILY
help
If you have a Intel Skylake platform with the DSP enabled
in the BIOS then enable this option by saying Y or m.
config SND_SOC_INTEL_APL
tristate "Broxton/ApolloLake Platforms"
depends on PCI && ACPI
select SND_SOC_INTEL_SKYLAKE_FAMILY
help
If you have a Intel Broxton/ApolloLake platform with the DSP
enabled in the BIOS then enable this option by saying Y or m.
config SND_SOC_INTEL_KBL
tristate "Kabylake Platforms"
depends on PCI && ACPI
select SND_SOC_INTEL_SKYLAKE_FAMILY
help
If you have a Intel Kabylake platform with the DSP
enabled in the BIOS then enable this option by saying Y or m.
config SND_SOC_INTEL_GLK
tristate "GeminiLake Platforms"
depends on PCI && ACPI
select SND_SOC_INTEL_SKYLAKE_FAMILY
help
If you have a Intel GeminiLake platform with the DSP
enabled in the BIOS then enable this option by saying Y or m.
config SND_SOC_INTEL_CNL
tristate "CannonLake/WhiskyLake Platforms"
depends on PCI && ACPI
select SND_SOC_INTEL_SKYLAKE_FAMILY
help
If you have a Intel CNL/WHL platform with the DSP
enabled in the BIOS then enable this option by saying Y or m.
config SND_SOC_INTEL_CFL
tristate "CoffeeLake Platforms"
depends on PCI && ACPI
select SND_SOC_INTEL_SKYLAKE_FAMILY
help
If you have a Intel CoffeeLake platform with the DSP
enabled in the BIOS then enable this option by saying Y or m.
config SND_SOC_INTEL_SKYLAKE_FAMILY
tristate
select SND_SOC_INTEL_SKYLAKE_COMMON
if SND_SOC_INTEL_SKYLAKE_FAMILY
config SND_SOC_INTEL_SKYLAKE_SSP_CLK
tristate
@@ -135,7 +194,7 @@ config SND_SOC_INTEL_SKYLAKE_COMMON
GeminiLake or CannonLake platform with the DSP enabled in the BIOS
then enable this option by saying Y or m.
endif ## SND_SOC_INTEL_SKYLAKE
endif ## SND_SOC_INTEL_SKYLAKE_FAMILY
config SND_SOC_ACPI_INTEL_MATCH
tristate

View File

@@ -341,6 +341,10 @@ static int sst_acpi_probe(struct platform_device *pdev)
byt_rvp_platform_data.res_info = &bytcr_res_info;
}
/* update machine parameters */
mach->mach_params.acpi_ipc_irq_index =
pdata->res_info->acpi_ipc_irq_index;
plat_dev = platform_device_register_data(dev, pdata->platform, -1,
NULL, 0);
if (IS_ERR(plat_dev)) {

View File

@@ -354,14 +354,14 @@ static int sst_request_fw(struct intel_sst_drv *sst)
const struct firmware *fw;
retval = request_firmware(&fw, sst->firmware_name, sst->dev);
if (fw == NULL) {
dev_err(sst->dev, "fw is returning as null\n");
return -EINVAL;
}
if (retval) {
dev_err(sst->dev, "request fw failed %d\n", retval);
return retval;
}
if (fw == NULL) {
dev_err(sst->dev, "fw is returning as null\n");
return -EINVAL;
}
mutex_lock(&sst->sst_lock);
retval = sst_cache_and_parse_fw(sst, fw);
mutex_unlock(&sst->sst_lock);

View File

@@ -166,11 +166,11 @@ int sst_create_ipc_msg(struct ipc_post **arg, bool large)
{
struct ipc_post *msg;
msg = kzalloc(sizeof(struct ipc_post), GFP_ATOMIC);
msg = kzalloc(sizeof(*msg), GFP_KERNEL);
if (!msg)
return -ENOMEM;
if (large) {
msg->mailbox_data = kzalloc(SST_MAILBOX_SIZE, GFP_ATOMIC);
msg->mailbox_data = kzalloc(SST_MAILBOX_SIZE, GFP_KERNEL);
if (!msg->mailbox_data) {
kfree(msg);
return -ENOMEM;

View File

@@ -172,7 +172,7 @@ config SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH
endif ## SND_SST_ATOM_HIFI2_PLATFORM
if SND_SOC_INTEL_SKYLAKE
if SND_SOC_INTEL_SKL
config SND_SOC_INTEL_SKL_RT286_MACH
tristate "SKL with RT286 I2S mode"
@@ -212,6 +212,10 @@ config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH
Say Y or m if you have such a device. This is a recommended option.
If unsure select "N".
endif ## SND_SOC_INTEL_SKL
if SND_SOC_INTEL_APL
config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH
tristate "Broxton with DA7219 and MAX98357A in I2S Mode"
depends on MFD_INTEL_LPSS && I2C && ACPI
@@ -239,6 +243,10 @@ config SND_SOC_INTEL_BXT_RT298_MACH
Say Y or m if you have such a device. This is a recommended option.
If unsure select "N".
endif ## SND_SOC_INTEL_APL
if SND_SOC_INTEL_KBL
config SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH
tristate "KBL with RT5663 and MAX98927 in I2S Mode"
depends on MFD_INTEL_LPSS && I2C && ACPI
@@ -293,6 +301,20 @@ config SND_SOC_INTEL_KBL_DA7219_MAX98927_MACH
Say Y if you have such a device.
If unsure select "N".
config SND_SOC_INTEL_KBL_RT5660_MACH
tristate "KBL with RT5660 in I2S Mode"
depends on MFD_INTEL_LPSS && I2C && ACPI
select SND_SOC_RT5660
select SND_SOC_HDAC_HDMI
help
This adds support for ASoC Onboard Codec I2S machine driver. This will
create an alsa sound card for RT5660 I2S audio codec.
Say Y if you have such a device.
endif ## SND_SOC_INTEL_KBL
if SND_SOC_INTEL_GLK
config SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH
tristate "GLK with RT5682 and MAX98357A in I2S Mode"
depends on MFD_INTEL_LPSS && I2C && ACPI
@@ -307,7 +329,7 @@ config SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH
Say Y if you have such a device.
If unsure select "N".
endif ## SND_SOC_INTEL_SKYLAKE
endif ## SND_SOC_INTEL_GLK
if SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC

View File

@@ -20,6 +20,7 @@ snd-soc-kbl_da7219_max98357a-objs := kbl_da7219_max98357a.o
snd-soc-kbl_da7219_max98927-objs := kbl_da7219_max98927.o
snd-soc-kbl_rt5663_max98927-objs := kbl_rt5663_max98927.o
snd-soc-kbl_rt5663_rt5514_max98927-objs := kbl_rt5663_rt5514_max98927.o
snd-soc-kbl_rt5660-objs := kbl_rt5660.o
snd-soc-skl_rt286-objs := skl_rt286.o
snd-soc-skl_hda_dsp-objs := skl_hda_dsp_generic.o skl_hda_dsp_common.o
snd-skl_nau88l25_max98357a-objs := skl_nau88l25_max98357a.o
@@ -46,6 +47,7 @@ obj-$(CONFIG_SND_SOC_INTEL_KBL_DA7219_MAX98357A_MACH) += snd-soc-kbl_da7219_max9
obj-$(CONFIG_SND_SOC_INTEL_KBL_DA7219_MAX98927_MACH) += snd-soc-kbl_da7219_max98927.o
obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH) += snd-soc-kbl_rt5663_max98927.o
obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH) += snd-soc-kbl_rt5663_rt5514_max98927.o
obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5660_MACH) += snd-soc-kbl_rt5660.o
obj-$(CONFIG_SND_SOC_INTEL_SKL_RT286_MACH) += snd-soc-skl_rt286.o
obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH) += snd-skl_nau88l25_max98357a.o
obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH) += snd-soc-skl_nau88l25_ssm4567.o

View File

@@ -29,7 +29,6 @@
#include <linux/input.h>
#include <linux/slab.h>
#include <asm/cpu_device_id.h>
#include <asm/platform_sst_audio.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
@@ -674,6 +673,33 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
BYT_RT5640_SSP0_AIF2 |
BYT_RT5640_MCLK_EN),
},
{ /* Point of View Mobii TAB-P1005W-232 (V2.0) */
.matches = {
DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "POV"),
DMI_EXACT_MATCH(DMI_BOARD_NAME, "I102A"),
},
.driver_data = (void *)(BYT_RT5640_IN1_MAP |
BYT_RT5640_JD_SRC_JD2_IN4N |
BYT_RT5640_OVCD_TH_2000UA |
BYT_RT5640_OVCD_SF_0P75 |
BYT_RT5640_DIFF_MIC |
BYT_RT5640_SSP0_AIF1 |
BYT_RT5640_MCLK_EN),
},
{
/* Prowise PT301 */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Prowise"),
DMI_MATCH(DMI_PRODUCT_NAME, "PT301"),
},
.driver_data = (void *)(BYT_RT5640_IN1_MAP |
BYT_RT5640_JD_SRC_JD2_IN4N |
BYT_RT5640_OVCD_TH_2000UA |
BYT_RT5640_OVCD_SF_0P75 |
BYT_RT5640_DIFF_MIC |
BYT_RT5640_SSP0_AIF1 |
BYT_RT5640_MCLK_EN),
},
{
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "TECLAST"),
@@ -1152,10 +1178,7 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
* (will be overridden if DMI quirk is detected)
*/
if (is_valleyview()) {
struct sst_platform_info *p_info = mach->pdata;
const struct sst_res_info *res_info = p_info->res_info;
if (res_info->acpi_ipc_irq_index == 0)
if (mach->mach_params.acpi_ipc_irq_index == 0)
is_bytcr = true;
}

View File

@@ -32,7 +32,6 @@
#include <linux/slab.h>
#include <asm/cpu_device_id.h>
#include <asm/intel-family.h>
#include <asm/platform_sst_audio.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
@@ -920,10 +919,7 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
* (will be overridden if DMI quirk is detected)
*/
if (x86_match_cpu(baytrail_cpu_ids)) {
struct sst_platform_info *p_info = mach->pdata;
const struct sst_res_info *res_info = p_info->res_info;
if (res_info->acpi_ipc_irq_index == 0)
if (mach->mach_params.acpi_ipc_irq_index == 0)
is_bytcr = true;
}

View File

@@ -27,7 +27,6 @@
#include <linux/dmi.h>
#include <linux/slab.h>
#include <asm/cpu_device_id.h>
#include <asm/platform_sst_audio.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
@@ -585,10 +584,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
* (will be overridden if DMI quirk is detected)
*/
if (is_valleyview()) {
struct sst_platform_info *p_info = mach->pdata;
const struct sst_res_info *res_info = p_info->res_info;
if (res_info->acpi_ipc_irq_index == 0)
if (mach->mach_params.acpi_ipc_irq_index == 0)
is_bytcr = true;
}

View File

@@ -403,7 +403,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
const char *i2c_name;
int i;
drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC);
drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
if (!drv)
return -ENOMEM;

View File

@@ -603,7 +603,7 @@ static int geminilake_audio_probe(struct platform_device *pdev)
{
struct glk_card_private *ctx;
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;

View File

@@ -262,9 +262,9 @@ static int kabylake_da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
jack = &ctx->kabylake_headset;
snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
da7219_aad_jack_det(component, &ctx->kabylake_headset);
@@ -441,7 +441,7 @@ static int kabylake_refcap_startup(struct snd_pcm_substream *substream)
}
static struct snd_soc_ops skylaye_refcap_ops = {
static struct snd_soc_ops skylake_refcap_ops = {
.startup = kabylake_refcap_startup,
};
@@ -525,7 +525,7 @@ static struct snd_soc_dai_link kabylake_dais[] = {
.dpcm_capture = 1,
.nonatomic = 1,
.dynamic = 1,
.ops = &skylaye_refcap_ops,
.ops = &skylake_refcap_ops,
},
[KBL_DPCM_AUDIO_DMIC_CP] = {
.name = "Kbl Audio DMIC cap",
@@ -736,7 +736,7 @@ static struct snd_soc_dai_link kabylake_max98927_dais[] = {
.dpcm_capture = 1,
.nonatomic = 1,
.dynamic = 1,
.ops = &skylaye_refcap_ops,
.ops = &skylake_refcap_ops,
},
[KBL_DPCM_AUDIO_DMIC_CP] = {
.name = "Kbl Audio DMIC cap",
@@ -935,7 +935,7 @@ static int kabylake_audio_probe(struct platform_device *pdev)
{
struct kbl_codec_private *ctx;
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;

View File

@@ -0,0 +1,543 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright(c) 2018-19 Canonical Corporation.
/*
* Intel Kabylake I2S Machine Driver with RT5660 Codec
*
* Modified from:
* Intel Kabylake I2S Machine driver supporting MAXIM98357a and
* DA7219 codecs
* Also referred to:
* Intel Broadwell I2S Machine driver supporting RT5677 codec
*/
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/gpio/consumer.h>
#include <linux/acpi.h>
#include <sound/core.h>
#include <sound/jack.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include "../../codecs/hdac_hdmi.h"
#include "../../codecs/rt5660.h"
#define KBL_RT5660_CODEC_DAI "rt5660-aif1"
#define DUAL_CHANNEL 2
static struct snd_soc_card *kabylake_audio_card;
static struct snd_soc_jack skylake_hdmi[3];
static struct snd_soc_jack lineout_jack;
static struct snd_soc_jack mic_jack;
struct kbl_hdmi_pcm {
struct list_head head;
struct snd_soc_dai *codec_dai;
int device;
};
struct kbl_codec_private {
struct gpio_desc *gpio_lo_mute;
struct list_head hdmi_pcm_list;
};
enum {
KBL_DPCM_AUDIO_PB = 0,
KBL_DPCM_AUDIO_CP,
KBL_DPCM_AUDIO_HDMI1_PB,
KBL_DPCM_AUDIO_HDMI2_PB,
KBL_DPCM_AUDIO_HDMI3_PB,
};
#define GPIO_LINEOUT_MUTE_INDEX 0
#define GPIO_LINEOUT_DET_INDEX 3
#define GPIO_LINEIN_DET_INDEX 4
static const struct acpi_gpio_params lineout_mute_gpio = { GPIO_LINEOUT_MUTE_INDEX, 0, true };
static const struct acpi_gpio_params lineout_det_gpio = { GPIO_LINEOUT_DET_INDEX, 0, false };
static const struct acpi_gpio_params mic_det_gpio = { GPIO_LINEIN_DET_INDEX, 0, false };
static const struct acpi_gpio_mapping acpi_rt5660_gpios[] = {
{ "lineout-mute-gpios", &lineout_mute_gpio, 1 },
{ "lineout-det-gpios", &lineout_det_gpio, 1 },
{ "mic-det-gpios", &mic_det_gpio, 1 },
{ NULL },
};
static struct snd_soc_jack_pin lineout_jack_pin = {
.pin = "Line Out",
.mask = SND_JACK_LINEOUT,
};
static struct snd_soc_jack_pin mic_jack_pin = {
.pin = "Line In",
.mask = SND_JACK_MICROPHONE,
};
static struct snd_soc_jack_gpio lineout_jack_gpio = {
.name = "lineout-det",
.report = SND_JACK_LINEOUT,
.debounce_time = 200,
};
static struct snd_soc_jack_gpio mic_jack_gpio = {
.name = "mic-det",
.report = SND_JACK_MICROPHONE,
.debounce_time = 200,
};
static int kabylake_5660_event_lineout(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *k, int event)
{
struct snd_soc_dapm_context *dapm = w->dapm;
struct kbl_codec_private *priv = snd_soc_card_get_drvdata(dapm->card);
gpiod_set_value_cansleep(priv->gpio_lo_mute,
!(SND_SOC_DAPM_EVENT_ON(event)));
return 0;
}
static const struct snd_kcontrol_new kabylake_rt5660_controls[] = {
SOC_DAPM_PIN_SWITCH("Line In"),
SOC_DAPM_PIN_SWITCH("Line Out"),
};
static const struct snd_soc_dapm_widget kabylake_rt5660_widgets[] = {
SND_SOC_DAPM_MIC("Line In", NULL),
SND_SOC_DAPM_LINE("Line Out", kabylake_5660_event_lineout),
};
static const struct snd_soc_dapm_route kabylake_rt5660_map[] = {
/* other jacks */
{"IN1P", NULL, "Line In"},
{"IN2P", NULL, "Line In"},
{"Line Out", NULL, "LOUTR"},
{"Line Out", NULL, "LOUTL"},
/* CODEC BE connections */
{ "AIF1 Playback", NULL, "ssp0 Tx"},
{ "ssp0 Tx", NULL, "codec0_out"},
{ "codec0_in", NULL, "ssp0 Rx" },
{ "ssp0 Rx", NULL, "AIF1 Capture" },
{ "hifi1", NULL, "iDisp1 Tx"},
{ "iDisp1 Tx", NULL, "iDisp1_out"},
{ "hifi2", NULL, "iDisp2 Tx"},
{ "iDisp2 Tx", NULL, "iDisp2_out"},
{ "hifi3", NULL, "iDisp3 Tx"},
{ "iDisp3 Tx", NULL, "iDisp3_out"},
};
static int kabylake_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
struct snd_interval *rate = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_RATE);
struct snd_interval *channels = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_CHANNELS);
struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
/* The ADSP will convert the FE rate to 48k, stereo */
rate->min = rate->max = 48000;
channels->min = channels->max = DUAL_CHANNEL;
/* set SSP0 to 24 bit */
snd_mask_none(fmt);
snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
return 0;
}
static int kabylake_rt5660_codec_init(struct snd_soc_pcm_runtime *rtd)
{
int ret;
struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card);
struct snd_soc_component *component = rtd->codec_dai->component;
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
ret = devm_acpi_dev_add_driver_gpios(component->dev, acpi_rt5660_gpios);
if (ret)
dev_warn(component->dev, "Failed to add driver gpios\n");
/* Request rt5660 GPIO for lineout mute control, return if fails */
ctx->gpio_lo_mute = devm_gpiod_get(component->dev, "lineout-mute",
GPIOD_OUT_HIGH);
if (IS_ERR(ctx->gpio_lo_mute)) {
dev_err(component->dev, "Can't find GPIO_MUTE# gpio\n");
return PTR_ERR(ctx->gpio_lo_mute);
}
/* Create and initialize headphone jack, this jack is not mandatory, don't return if fails */
ret = snd_soc_card_jack_new(rtd->card, "Lineout Jack",
SND_JACK_LINEOUT, &lineout_jack,
&lineout_jack_pin, 1);
if (ret)
dev_warn(component->dev, "Can't create Lineout jack\n");
else {
lineout_jack_gpio.gpiod_dev = component->dev;
ret = snd_soc_jack_add_gpios(&lineout_jack, 1,
&lineout_jack_gpio);
if (ret)
dev_warn(component->dev, "Can't add Lineout jack gpio\n");
}
/* Create and initialize mic jack, this jack is not mandatory, don't return if fails */
ret = snd_soc_card_jack_new(rtd->card, "Mic Jack",
SND_JACK_MICROPHONE, &mic_jack,
&mic_jack_pin, 1);
if (ret)
dev_warn(component->dev, "Can't create mic jack\n");
else {
mic_jack_gpio.gpiod_dev = component->dev;
ret = snd_soc_jack_add_gpios(&mic_jack, 1, &mic_jack_gpio);
if (ret)
dev_warn(component->dev, "Can't add mic jack gpio\n");
}
/* Here we enable some dapms in advance to reduce the pop noise for recording via line-in */
snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1");
snd_soc_dapm_force_enable_pin(dapm, "BST1");
snd_soc_dapm_force_enable_pin(dapm, "BST2");
return 0;
}
static int kabylake_hdmi_init(struct snd_soc_pcm_runtime *rtd, int device)
{
struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card);
struct snd_soc_dai *dai = rtd->codec_dai;
struct kbl_hdmi_pcm *pcm;
pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
if (!pcm)
return -ENOMEM;
pcm->device = device;
pcm->codec_dai = dai;
list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
return 0;
}
static int kabylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd)
{
return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI1_PB);
}
static int kabylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd)
{
return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI2_PB);
}
static int kabylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd)
{
return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI3_PB);
}
static int kabylake_rt5660_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
int ret;
ret = snd_soc_dai_set_sysclk(codec_dai,
RT5660_SCLK_S_PLL1, params_rate(params) * 512,
SND_SOC_CLOCK_IN);
if (ret < 0) {
dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret);
return ret;
}
ret = snd_soc_dai_set_pll(codec_dai, 0,
RT5660_PLL1_S_BCLK,
params_rate(params) * 50,
params_rate(params) * 512);
if (ret < 0)
dev_err(codec_dai->dev, "can't set codec pll: %d\n", ret);
return ret;
}
static struct snd_soc_ops kabylake_rt5660_ops = {
.hw_params = kabylake_rt5660_hw_params,
};
static const unsigned int rates[] = {
48000,
};
static const struct snd_pcm_hw_constraint_list constraints_rates = {
.count = ARRAY_SIZE(rates),
.list = rates,
.mask = 0,
};
static const unsigned int channels[] = {
DUAL_CHANNEL,
};
static const struct snd_pcm_hw_constraint_list constraints_channels = {
.count = ARRAY_SIZE(channels),
.list = channels,
.mask = 0,
};
static int kbl_fe_startup(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
/*
* On this platform for PCM device we support,
* 48Khz
* stereo
* 16 bit audio
*/
runtime->hw.channels_max = DUAL_CHANNEL;
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
&constraints_channels);
runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE;
snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16);
snd_pcm_hw_constraint_list(runtime, 0,
SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
return 0;
}
static const struct snd_soc_ops kabylake_rt5660_fe_ops = {
.startup = kbl_fe_startup,
};
/* kabylake digital audio interface glue - connects rt5660 codec <--> CPU */
static struct snd_soc_dai_link kabylake_rt5660_dais[] = {
/* Front End DAI links */
[KBL_DPCM_AUDIO_PB] = {
.name = "Kbl Audio Port",
.stream_name = "Audio",
.cpu_dai_name = "System Pin",
.platform_name = "0000:00:1f.3",
.dynamic = 1,
.codec_name = "snd-soc-dummy",
.codec_dai_name = "snd-soc-dummy-dai",
.nonatomic = 1,
.trigger = {
SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
.dpcm_playback = 1,
.ops = &kabylake_rt5660_fe_ops,
},
[KBL_DPCM_AUDIO_CP] = {
.name = "Kbl Audio Capture Port",
.stream_name = "Audio Record",
.cpu_dai_name = "System Pin",
.platform_name = "0000:00:1f.3",
.dynamic = 1,
.codec_name = "snd-soc-dummy",
.codec_dai_name = "snd-soc-dummy-dai",
.nonatomic = 1,
.trigger = {
SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
.dpcm_capture = 1,
.ops = &kabylake_rt5660_fe_ops,
},
[KBL_DPCM_AUDIO_HDMI1_PB] = {
.name = "Kbl HDMI Port1",
.stream_name = "Hdmi1",
.cpu_dai_name = "HDMI1 Pin",
.codec_name = "snd-soc-dummy",
.codec_dai_name = "snd-soc-dummy-dai",
.platform_name = "0000:00:1f.3",
.dpcm_playback = 1,
.init = NULL,
.trigger = {
SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
.nonatomic = 1,
.dynamic = 1,
},
[KBL_DPCM_AUDIO_HDMI2_PB] = {
.name = "Kbl HDMI Port2",
.stream_name = "Hdmi2",
.cpu_dai_name = "HDMI2 Pin",
.codec_name = "snd-soc-dummy",
.codec_dai_name = "snd-soc-dummy-dai",
.platform_name = "0000:00:1f.3",
.dpcm_playback = 1,
.init = NULL,
.trigger = {
SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
.nonatomic = 1,
.dynamic = 1,
},
[KBL_DPCM_AUDIO_HDMI3_PB] = {
.name = "Kbl HDMI Port3",
.stream_name = "Hdmi3",
.cpu_dai_name = "HDMI3 Pin",
.codec_name = "snd-soc-dummy",
.codec_dai_name = "snd-soc-dummy-dai",
.platform_name = "0000:00:1f.3",
.trigger = {
SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
.dpcm_playback = 1,
.init = NULL,
.nonatomic = 1,
.dynamic = 1,
},
/* Back End DAI links */
{
/* SSP0 - Codec */
.name = "SSP0-Codec",
.id = 0,
.cpu_dai_name = "SSP0 Pin",
.platform_name = "0000:00:1f.3",
.no_pcm = 1,
.codec_name = "i2c-10EC3277:00",
.codec_dai_name = KBL_RT5660_CODEC_DAI,
.init = kabylake_rt5660_codec_init,
.dai_fmt = SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBS_CFS,
.ignore_pmdown_time = 1,
.be_hw_params_fixup = kabylake_ssp0_fixup,
.ops = &kabylake_rt5660_ops,
.dpcm_playback = 1,
.dpcm_capture = 1,
},
{
.name = "iDisp1",
.id = 1,
.cpu_dai_name = "iDisp1 Pin",
.codec_name = "ehdaudio0D2",
.codec_dai_name = "intel-hdmi-hifi1",
.platform_name = "0000:00:1f.3",
.dpcm_playback = 1,
.init = kabylake_hdmi1_init,
.no_pcm = 1,
},
{
.name = "iDisp2",
.id = 2,
.cpu_dai_name = "iDisp2 Pin",
.codec_name = "ehdaudio0D2",
.codec_dai_name = "intel-hdmi-hifi2",
.platform_name = "0000:00:1f.3",
.init = kabylake_hdmi2_init,
.dpcm_playback = 1,
.no_pcm = 1,
},
{
.name = "iDisp3",
.id = 3,
.cpu_dai_name = "iDisp3 Pin",
.codec_name = "ehdaudio0D2",
.codec_dai_name = "intel-hdmi-hifi3",
.platform_name = "0000:00:1f.3",
.init = kabylake_hdmi3_init,
.dpcm_playback = 1,
.no_pcm = 1,
},
};
#define NAME_SIZE 32
static int kabylake_card_late_probe(struct snd_soc_card *card)
{
struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(card);
struct kbl_hdmi_pcm *pcm;
struct snd_soc_component *component = NULL;
int err, i = 0;
char jack_name[NAME_SIZE];
list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
component = pcm->codec_dai->component;
snprintf(jack_name, sizeof(jack_name),
"HDMI/DP, pcm=%d Jack", pcm->device);
err = snd_soc_card_jack_new(card, jack_name,
SND_JACK_AVOUT, &skylake_hdmi[i],
NULL, 0);
if (err)
return err;
err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
&skylake_hdmi[i]);
if (err < 0)
return err;
i++;
}
if (!component)
return -EINVAL;
return hdac_hdmi_jack_port_init(component, &card->dapm);
}
/* kabylake audio machine driver for rt5660 */
static struct snd_soc_card kabylake_audio_card_rt5660 = {
.name = "kblrt5660",
.owner = THIS_MODULE,
.dai_link = kabylake_rt5660_dais,
.num_links = ARRAY_SIZE(kabylake_rt5660_dais),
.controls = kabylake_rt5660_controls,
.num_controls = ARRAY_SIZE(kabylake_rt5660_controls),
.dapm_widgets = kabylake_rt5660_widgets,
.num_dapm_widgets = ARRAY_SIZE(kabylake_rt5660_widgets),
.dapm_routes = kabylake_rt5660_map,
.num_dapm_routes = ARRAY_SIZE(kabylake_rt5660_map),
.fully_routed = true,
.late_probe = kabylake_card_late_probe,
};
static int kabylake_audio_probe(struct platform_device *pdev)
{
struct kbl_codec_private *ctx;
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
kabylake_audio_card =
(struct snd_soc_card *)pdev->id_entry->driver_data;
kabylake_audio_card->dev = &pdev->dev;
snd_soc_card_set_drvdata(kabylake_audio_card, ctx);
return devm_snd_soc_register_card(&pdev->dev, kabylake_audio_card);
}
static const struct platform_device_id kbl_board_ids[] = {
{
.name = "kbl_rt5660",
.driver_data =
(kernel_ulong_t)&kabylake_audio_card_rt5660,
},
{ }
};
static struct platform_driver kabylake_audio = {
.probe = kabylake_audio_probe,
.driver = {
.name = "kbl_rt5660",
.pm = &snd_soc_pm_ops,
},
.id_table = kbl_board_ids,
};
module_platform_driver(kabylake_audio)
/* Module information */
MODULE_DESCRIPTION("Audio Machine driver-RT5660 in I2S mode");
MODULE_AUTHOR("Hui Wang <hui.wang@canonical.com>");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:kbl_rt5660");

View File

@@ -25,9 +25,9 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-acpi.h>
#include "../../codecs/rt5663.h"
#include "../../codecs/hdac_hdmi.h"
#include "../skylake/skl.h"
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
@@ -586,7 +586,7 @@ static int kabylake_refcap_startup(struct snd_pcm_substream *substream)
&constraints_16000);
}
static struct snd_soc_ops skylaye_refcap_ops = {
static struct snd_soc_ops skylake_refcap_ops = {
.startup = kabylake_refcap_startup,
};
@@ -655,7 +655,7 @@ static struct snd_soc_dai_link kabylake_dais[] = {
.dpcm_capture = 1,
.nonatomic = 1,
.dynamic = 1,
.ops = &skylaye_refcap_ops,
.ops = &skylake_refcap_ops,
},
[KBL_DPCM_AUDIO_DMIC_CP] = {
.name = "Kbl Audio DMIC cap",
@@ -969,7 +969,7 @@ static struct snd_soc_card kabylake_audio_card_rt5663 = {
static int kabylake_audio_probe(struct platform_device *pdev)
{
struct kbl_rt5663_private *ctx;
struct skl_machine_pdata *pdata;
struct snd_soc_acpi_mach *mach;
int ret;
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
@@ -984,9 +984,9 @@ static int kabylake_audio_probe(struct platform_device *pdev)
kabylake_audio_card->dev = &pdev->dev;
snd_soc_card_set_drvdata(kabylake_audio_card, ctx);
pdata = dev_get_drvdata(&pdev->dev);
if (pdata)
dmic_constraints = pdata->dmic_num == 2 ?
mach = (&pdev->dev)->platform_data;
if (mach)
dmic_constraints = mach->mach_params.dmic_num == 2 ?
&constraints_dmic_2ch : &constraints_dmic_channels;
ctx->mclk = devm_clk_get(&pdev->dev, "ssp1_mclk");

View File

@@ -26,10 +26,10 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-acpi.h>
#include "../../codecs/rt5514.h"
#include "../../codecs/rt5663.h"
#include "../../codecs/hdac_hdmi.h"
#include "../skylake/skl.h"
#define KBL_REALTEK_CODEC_DAI "rt5663-aif"
#define KBL_REALTEK_DMIC_CODEC_DAI "rt5514-aif1"
@@ -648,7 +648,7 @@ static struct snd_soc_card kabylake_audio_card = {
static int kabylake_audio_probe(struct platform_device *pdev)
{
struct kbl_codec_private *ctx;
struct skl_machine_pdata *pdata;
struct snd_soc_acpi_mach *mach;
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
@@ -659,9 +659,9 @@ static int kabylake_audio_probe(struct platform_device *pdev)
kabylake_audio_card.dev = &pdev->dev;
snd_soc_card_set_drvdata(&kabylake_audio_card, ctx);
pdata = dev_get_drvdata(&pdev->dev);
if (pdata)
dmic_constraints = pdata->dmic_num == 2 ?
mach = (&pdev->dev)->platform_data;
if (mach)
dmic_constraints = mach->mach_params.dmic_num == 2 ?
&constraints_dmic_2ch : &constraints_dmic_channels;
return devm_snd_soc_register_card(&pdev->dev, &kabylake_audio_card);

View File

@@ -12,8 +12,8 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-acpi.h>
#include "../../codecs/hdac_hdmi.h"
#include "../skylake/skl.h"
#include "skl_hda_dsp_common.h"
static const struct snd_soc_dapm_widget skl_hda_widgets[] = {
@@ -101,17 +101,17 @@ static struct snd_soc_card hda_soc_card = {
#define IDISP_ROUTE_COUNT (IDISP_DAI_COUNT * 2)
#define IDISP_CODEC_MASK 0x4
static int skl_hda_fill_card_info(struct skl_machine_pdata *pdata)
static int skl_hda_fill_card_info(struct snd_soc_acpi_mach_params *mach_params)
{
struct snd_soc_card *card = &hda_soc_card;
struct snd_soc_dai_link *dai_link;
u32 codec_count, codec_mask;
int i, num_links, num_route;
codec_mask = pdata->codec_mask;
codec_mask = mach_params->codec_mask;
codec_count = hweight_long(codec_mask);
if (codec_count == 1 && pdata->codec_mask & IDISP_CODEC_MASK) {
if (codec_count == 1 && codec_mask & IDISP_CODEC_MASK) {
num_links = IDISP_DAI_COUNT;
num_route = IDISP_ROUTE_COUNT;
} else if (codec_count == 2 && codec_mask & IDISP_CODEC_MASK) {
@@ -127,30 +127,30 @@ static int skl_hda_fill_card_info(struct skl_machine_pdata *pdata)
card->num_dapm_routes = num_route;
for_each_card_prelinks(card, i, dai_link)
dai_link->platform_name = pdata->platform;
dai_link->platform_name = mach_params->platform;
return 0;
}
static int skl_hda_audio_probe(struct platform_device *pdev)
{
struct skl_machine_pdata *pdata;
struct snd_soc_acpi_mach *mach;
struct skl_hda_private *ctx;
int ret;
dev_dbg(&pdev->dev, "%s: entry\n", __func__);
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
pdata = dev_get_drvdata(&pdev->dev);
if (!pdata)
mach = (&pdev->dev)->platform_data;
if (!mach)
return -EINVAL;
ret = skl_hda_fill_card_info(pdata);
ret = skl_hda_fill_card_info(&mach->mach_params);
if (ret < 0) {
dev_err(&pdev->dev, "Unsupported HDAudio/iDisp configuration found\n");
return ret;
@@ -158,7 +158,7 @@ static int skl_hda_audio_probe(struct platform_device *pdev)
ctx->pcm_count = hda_soc_card.num_links;
ctx->dai_index = 1; /* hdmi codec dai name starts from index 1 */
ctx->platform_name = pdata->platform;
ctx->platform_name = mach->mach_params.platform;
hda_soc_card.dev = &pdev->dev;
snd_soc_card_set_drvdata(&hda_soc_card, ctx);

View File

@@ -21,9 +21,9 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-acpi.h>
#include "../../codecs/nau8825.h"
#include "../../codecs/hdac_hdmi.h"
#include "../skylake/skl.h"
#define SKL_NUVOTON_CODEC_DAI "nau8825-hifi"
#define SKL_MAXIM_CODEC_DAI "HiFi"
@@ -400,7 +400,7 @@ static int skylake_refcap_startup(struct snd_pcm_substream *substream)
&constraints_16000);
}
static const struct snd_soc_ops skylaye_refcap_ops = {
static const struct snd_soc_ops skylake_refcap_ops = {
.startup = skylake_refcap_startup,
};
@@ -447,7 +447,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
.dpcm_capture = 1,
.nonatomic = 1,
.dynamic = 1,
.ops = &skylaye_refcap_ops,
.ops = &skylake_refcap_ops,
},
[SKL_DPCM_AUDIO_DMIC_CP] = {
.name = "Skl Audio DMIC cap",
@@ -641,7 +641,7 @@ static struct snd_soc_card skylake_audio_card = {
static int skylake_audio_probe(struct platform_device *pdev)
{
struct skl_nau8825_private *ctx;
struct skl_machine_pdata *pdata;
struct snd_soc_acpi_mach *mach;
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
@@ -652,9 +652,9 @@ static int skylake_audio_probe(struct platform_device *pdev)
skylake_audio_card.dev = &pdev->dev;
snd_soc_card_set_drvdata(&skylake_audio_card, ctx);
pdata = dev_get_drvdata(&pdev->dev);
if (pdata)
dmic_constraints = pdata->dmic_num == 2 ?
mach = (&pdev->dev)->platform_data;
if (mach)
dmic_constraints = mach->mach_params.dmic_num == 2 ?
&constraints_dmic_2ch : &constraints_dmic_channels;
return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card);

View File

@@ -23,11 +23,11 @@
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/soc-acpi.h>
#include <sound/jack.h>
#include <sound/pcm_params.h>
#include "../../codecs/nau8825.h"
#include "../../codecs/hdac_hdmi.h"
#include "../skylake/skl.h"
#define SKL_NUVOTON_CODEC_DAI "nau8825-hifi"
#define SKL_SSM_CODEC_DAI "ssm4567-hifi"
@@ -449,7 +449,7 @@ static int skylake_refcap_startup(struct snd_pcm_substream *substream)
&constraints_16000);
}
static const struct snd_soc_ops skylaye_refcap_ops = {
static const struct snd_soc_ops skylake_refcap_ops = {
.startup = skylake_refcap_startup,
};
@@ -496,7 +496,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
.dpcm_capture = 1,
.nonatomic = 1,
.dynamic = 1,
.ops = &skylaye_refcap_ops,
.ops = &skylake_refcap_ops,
},
[SKL_DPCM_AUDIO_DMIC_CP] = {
.name = "Skl Audio DMIC cap",
@@ -694,7 +694,7 @@ static struct snd_soc_card skylake_audio_card = {
static int skylake_audio_probe(struct platform_device *pdev)
{
struct skl_nau88125_private *ctx;
struct skl_machine_pdata *pdata;
struct snd_soc_acpi_mach *mach;
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
@@ -705,9 +705,9 @@ static int skylake_audio_probe(struct platform_device *pdev)
skylake_audio_card.dev = &pdev->dev;
snd_soc_card_set_drvdata(&skylake_audio_card, ctx);
pdata = dev_get_drvdata(&pdev->dev);
if (pdata)
dmic_constraints = pdata->dmic_num == 2 ?
mach = (&pdev->dev)->platform_data;
if (mach)
dmic_constraints = mach->mach_params.dmic_num == 2 ?
&constraints_dmic_2ch : &constraints_dmic_channels;
return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card);

View File

@@ -7,7 +7,7 @@ snd-soc-acpi-intel-match-objs := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-m
soc-acpi-intel-hsw-bdw-match.o \
soc-acpi-intel-skl-match.o soc-acpi-intel-kbl-match.o \
soc-acpi-intel-bxt-match.o soc-acpi-intel-glk-match.o \
soc-acpi-intel-cnl-match.o \
soc-acpi-intel-cnl-match.o soc-acpi-intel-icl-match.o \
soc-acpi-intel-hda-match.o
obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o snd-soc-sst-ipc.o

View File

@@ -6,9 +6,41 @@
*
*/
#include <linux/dmi.h>
#include <sound/soc-acpi.h>
#include <sound/soc-acpi-intel-match.h>
enum {
APL_RVP,
};
static const struct dmi_system_id apl_table[] = {
{
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Intel Corp."),
DMI_MATCH(DMI_BOARD_NAME, "Apollolake RVP1A"),
},
.driver_data = (void *)(APL_RVP),
},
{}
};
static struct snd_soc_acpi_mach *apl_quirk(void *arg)
{
struct snd_soc_acpi_mach *mach = arg;
const struct dmi_system_id *dmi_id;
unsigned long apl_machine_id;
dmi_id = dmi_first_match(apl_table);
if (dmi_id) {
apl_machine_id = (unsigned long)dmi_id->driver_data;
if (apl_machine_id == APL_RVP)
return NULL;
}
return mach;
}
static struct snd_soc_acpi_codecs bxt_codecs = {
.num_codecs = 1,
.codecs = {"MX98357A"}
@@ -19,6 +51,9 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[] = {
.id = "INT343A",
.drv_name = "bxt_alc298s_i2s",
.fw_filename = "intel/dsp_fw_bxtn.bin",
.sof_fw_filename = "intel/sof-apl.ri",
.sof_tplg_filename = "intel/sof-apl-rt298.tplg",
.asoc_plat_name = "0000:00:0e.0",
},
{
.id = "DLGS7219",
@@ -47,6 +82,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[] = {
{
.id = "INT34C3",
.drv_name = "bxt_tdf8532",
.machine_quirk = apl_quirk,
.sof_fw_filename = "intel/sof-apl.ri",
.sof_tplg_filename = "intel/sof-apl-tdf8532.tplg",
.asoc_plat_name = "0000:00:0e.0",

View File

@@ -0,0 +1,32 @@
// SPDX-License-Identifier: GPL-2.0
/*
* soc-apci-intel-icl-match.c - tables and support for ICL ACPI enumeration.
*
* Copyright (c) 2018, Intel Corporation.
*
*/
#include <sound/soc-acpi.h>
#include <sound/soc-acpi-intel-match.h>
#include "../skylake/skl.h"
static struct skl_machine_pdata icl_pdata = {
.use_tplg_pcm = true,
};
struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_machines[] = {
{
.id = "INT34C2",
.drv_name = "icl_rt274",
.fw_filename = "intel/dsp_fw_icl.bin",
.pdata = &icl_pdata,
.sof_fw_filename = "intel/sof-icl.ri",
.sof_tplg_filename = "intel/sof-icl-rt274.tplg",
.asoc_plat_name = "0000:00:1f.3",
},
{},
};
EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_icl_machines);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Intel Common ACPI Match module");

View File

@@ -96,6 +96,16 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_kbl_machines[] = {
.quirk_data = &kbl_7219_98927_codecs,
.pdata = &skl_dmic_data
},
{
.id = "10EC5660",
.drv_name = "kbl_rt5660",
.fw_filename = "intel/dsp_fw_kbl.bin",
},
{
.id = "10EC3277",
.drv_name = "kbl_rt5660",
.fw_filename = "intel/dsp_fw_kbl.bin",
},
{},
};
EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_kbl_machines);

View File

@@ -247,6 +247,14 @@ static const struct skl_dsp_ops dsp_ops[] = {
.init_fw = cnl_sst_init_fw,
.cleanup = cnl_sst_dsp_cleanup
},
{
.id = 0xa348,
.num_cores = 4,
.loader_ops = bxt_get_loader_ops,
.init = cnl_sst_dsp_init,
.init_fw = cnl_sst_init_fw,
.cleanup = cnl_sst_dsp_cleanup
},
};
const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id)

View File

@@ -180,6 +180,9 @@ int skl_get_dmic_geo(struct skl *skl)
unsigned int dmic_geo = 0;
u8 j;
if (!nhlt)
return 0;
epnt = (struct nhlt_endpoint *)nhlt->desc;
for (j = 0; j < nhlt->endpoint_count; j++) {

View File

@@ -249,6 +249,8 @@ enum skl_ipc_glb_reply {
IPC_GLB_REPLY_INVALID_CONFIG_DATA_LEN = 121,
IPC_GLB_REPLY_GATEWAY_NOT_INITIALIZED = 140,
IPC_GLB_REPLY_GATEWAY_NOT_EXIST = 141,
IPC_GLB_REPLY_SCLK_ALREADY_RUNNING = 150,
IPC_GLB_REPLY_MCLK_ALREADY_RUNNING = 151,
IPC_GLB_REPLY_PPL_NOT_INITIALIZED = 160,
IPC_GLB_REPLY_PPL_NOT_EXIST = 161,
@@ -392,18 +394,47 @@ int skl_ipc_process_notification(struct sst_generic_ipc *ipc,
return 0;
}
static int skl_ipc_set_reply_error_code(u32 reply)
struct skl_ipc_err_map {
const char *msg;
enum skl_ipc_glb_reply reply;
int err;
};
static struct skl_ipc_err_map skl_err_map[] = {
{"DSP out of memory", IPC_GLB_REPLY_OUT_OF_MEMORY, -ENOMEM},
{"DSP busy", IPC_GLB_REPLY_BUSY, -EBUSY},
{"SCLK already running", IPC_GLB_REPLY_SCLK_ALREADY_RUNNING,
IPC_GLB_REPLY_SCLK_ALREADY_RUNNING},
{"MCLK already running", IPC_GLB_REPLY_MCLK_ALREADY_RUNNING,
IPC_GLB_REPLY_MCLK_ALREADY_RUNNING},
};
static int skl_ipc_set_reply_error_code(struct sst_generic_ipc *ipc, u32 reply)
{
switch (reply) {
case IPC_GLB_REPLY_OUT_OF_MEMORY:
return -ENOMEM;
int i;
case IPC_GLB_REPLY_BUSY:
return -EBUSY;
for (i = 0; i < ARRAY_SIZE(skl_err_map); i++) {
if (skl_err_map[i].reply == reply)
break;
}
default:
if (i == ARRAY_SIZE(skl_err_map)) {
dev_err(ipc->dev, "ipc FW reply: %d FW Error Code: %u\n",
reply,
ipc->dsp->fw_ops.get_fw_errcode(ipc->dsp));
return -EINVAL;
}
if (skl_err_map[i].err < 0)
dev_err(ipc->dev, "ipc FW reply: %s FW Error Code: %u\n",
skl_err_map[i].msg,
ipc->dsp->fw_ops.get_fw_errcode(ipc->dsp));
else
dev_info(ipc->dev, "ipc FW reply: %s FW Error Code: %u\n",
skl_err_map[i].msg,
ipc->dsp->fw_ops.get_fw_errcode(ipc->dsp));
return skl_err_map[i].err;
}
void skl_ipc_process_reply(struct sst_generic_ipc *ipc,
@@ -441,10 +472,7 @@ void skl_ipc_process_reply(struct sst_generic_ipc *ipc,
}
} else {
msg->errno = skl_ipc_set_reply_error_code(reply);
dev_err(ipc->dev, "ipc FW reply: reply=%d\n", reply);
dev_err(ipc->dev, "FW Error Code: %u\n",
ipc->dsp->fw_ops.get_fw_errcode(ipc->dsp));
msg->errno = skl_ipc_set_reply_error_code(ipc, reply);
switch (IPC_GLB_NOTIFY_MSG_TYPE(header.primary)) {
case IPC_GLB_LOAD_MULTIPLE_MODS:
case IPC_GLB_LOAD_LIBRARY:

View File

@@ -517,7 +517,7 @@ static int skl_find_machine(struct skl *skl, void *driver_data)
if (pdata) {
skl->use_tplg_pcm = pdata->use_tplg_pcm;
pdata->dmic_num = skl_get_dmic_geo(skl);
mach->mach_params.dmic_num = skl_get_dmic_geo(skl);
}
return 0;
@@ -527,7 +527,6 @@ static int skl_machine_device_register(struct skl *skl)
{
struct snd_soc_acpi_mach *mach = skl->mach;
struct hdac_bus *bus = skl_to_bus(skl);
struct skl_machine_pdata *pdata;
struct platform_device *pdev;
int ret;
@@ -537,6 +536,16 @@ static int skl_machine_device_register(struct skl *skl)
return -EIO;
}
mach->mach_params.platform = dev_name(bus->dev);
mach->mach_params.codec_mask = bus->codec_mask;
ret = platform_device_add_data(pdev, (const void *)mach, sizeof(*mach));
if (ret) {
dev_err(bus->dev, "failed to add machine device platform data\n");
platform_device_put(pdev);
return ret;
}
ret = platform_device_add(pdev);
if (ret) {
dev_err(bus->dev, "failed to add machine device\n");
@@ -544,12 +553,6 @@ static int skl_machine_device_register(struct skl *skl)
return -EIO;
}
if (mach->pdata) {
pdata = (struct skl_machine_pdata *)mach->pdata;
pdata->platform = dev_name(bus->dev);
pdata->codec_mask = bus->codec_mask;
dev_set_drvdata(&pdev->dev, mach->pdata);
}
skl->i2s_dev = pdev;
@@ -823,12 +826,10 @@ static void skl_probe_work(struct work_struct *work)
return;
}
if (bus->ppcap) {
err = skl_machine_device_register(skl);
if (err < 0) {
dev_err(bus->dev, "machine register failed: %d\n", err);
goto out_err;
}
err = skl_machine_device_register(skl);
if (err < 0) {
dev_err(bus->dev, "machine register failed: %d\n", err);
goto out_err;
}
/*
@@ -913,6 +914,21 @@ static int skl_first_init(struct hdac_bus *bus)
unsigned short gcap;
int cp_streams, pb_streams, start_idx;
/*
* detect DSP by checking class/subclass/prog-id information
* class=04 subclass 03 prog-if 00: no DSP, legacy driver needs to be used
* class=04 subclass 01 prog-if 00: DSP is present (and may be required e.g. for DMIC or SSP support)
* class=04 subclass 03 prog-if 80: either of DSP or legacy mode can be used
*/
if (pci->class == 0x040300) {
dev_err(bus->dev, "The DSP is not enabled on this platform, aborting probe\n");
return -ENODEV;
} else if (pci->class != 0x040100 && pci->class != 0x040380) {
dev_err(bus->dev, "Unknown PCI class/subclass/prog-if information (0x%06x) found, aborting probe\n", pci->class);
return -ENODEV;
}
dev_info(bus->dev, "DSP detected with PCI class/subclass/prog-if info 0x%06x\n", pci->class);
err = pci_request_regions(pci, "Skylake HD audio");
if (err < 0)
return err;
@@ -928,6 +944,12 @@ static int skl_first_init(struct hdac_bus *bus)
snd_hdac_bus_parse_capabilities(bus);
/* check if PPCAP exists */
if (!bus->ppcap) {
dev_err(bus->dev, "bus ppcap not set, HDaudio or DSP not present?\n");
return -ENODEV;
}
if (skl_acquire_irq(bus, 0) < 0)
return -EBUSY;
@@ -937,6 +959,17 @@ static int skl_first_init(struct hdac_bus *bus)
gcap = snd_hdac_chip_readw(bus, GCAP);
dev_dbg(bus->dev, "chipset global capabilities = 0x%x\n", gcap);
/* read number of streams from GCAP register */
cp_streams = (gcap >> 8) & 0x0f;
pb_streams = (gcap >> 12) & 0x0f;
if (!pb_streams && !cp_streams) {
dev_err(bus->dev, "no streams found in GCAP definitions?\n");
return -EIO;
}
bus->num_streams = cp_streams + pb_streams;
/* allow 64bit DMA address if supported by H/W */
if (!dma_set_mask(bus->dev, DMA_BIT_MASK(64))) {
dma_set_coherent_mask(bus->dev, DMA_BIT_MASK(64));
@@ -945,15 +978,6 @@ static int skl_first_init(struct hdac_bus *bus)
dma_set_coherent_mask(bus->dev, DMA_BIT_MASK(32));
}
/* read number of streams from GCAP register */
cp_streams = (gcap >> 8) & 0x0f;
pb_streams = (gcap >> 12) & 0x0f;
if (!pb_streams && !cp_streams)
return -EIO;
bus->num_streams = cp_streams + pb_streams;
/* initialize streams */
snd_hdac_ext_stream_init_all
(bus, 0, cp_streams, SNDRV_PCM_STREAM_CAPTURE);
@@ -986,8 +1010,10 @@ static int skl_probe(struct pci_dev *pci,
bus = skl_to_bus(skl);
err = skl_first_init(bus);
if (err < 0)
if (err < 0) {
dev_err(bus->dev, "skl_first_init failed with err: %d\n", err);
goto out_free;
}
skl->pci_id = pci->device;
@@ -996,37 +1022,48 @@ static int skl_probe(struct pci_dev *pci,
skl->nhlt = skl_nhlt_init(bus->dev);
if (skl->nhlt == NULL) {
#if !IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC)
dev_err(bus->dev, "no nhlt info found\n");
err = -ENODEV;
goto out_free;
#else
dev_warn(bus->dev, "no nhlt info found, continuing to try to enable HDaudio codec\n");
#endif
} else {
err = skl_nhlt_create_sysfs(skl);
if (err < 0) {
dev_err(bus->dev, "skl_nhlt_create_sysfs failed with err: %d\n", err);
goto out_nhlt_free;
}
skl_nhlt_update_topology_bin(skl);
/* create device for dsp clk */
err = skl_clock_device_register(skl);
if (err < 0) {
dev_err(bus->dev, "skl_clock_device_register failed with err: %d\n", err);
goto out_clk_free;
}
}
err = skl_nhlt_create_sysfs(skl);
if (err < 0)
goto out_nhlt_free;
skl_nhlt_update_topology_bin(skl);
pci_set_drvdata(skl->pci, bus);
/* check if dsp is there */
if (bus->ppcap) {
/* create device for dsp clk */
err = skl_clock_device_register(skl);
if (err < 0)
goto out_clk_free;
err = skl_find_machine(skl, (void *)pci_id->driver_data);
if (err < 0)
goto out_nhlt_free;
err = skl_init_dsp(skl);
if (err < 0) {
dev_dbg(bus->dev, "error failed to register dsp\n");
goto out_nhlt_free;
}
skl->skl_sst->enable_miscbdcge = skl_enable_miscbdcge;
skl->skl_sst->clock_power_gating = skl_clock_power_gating;
err = skl_find_machine(skl, (void *)pci_id->driver_data);
if (err < 0) {
dev_err(bus->dev, "skl_find_machine failed with err: %d\n", err);
goto out_nhlt_free;
}
err = skl_init_dsp(skl);
if (err < 0) {
dev_dbg(bus->dev, "error failed to register dsp\n");
goto out_nhlt_free;
}
skl->skl_sst->enable_miscbdcge = skl_enable_miscbdcge;
skl->skl_sst->clock_power_gating = skl_clock_power_gating;
if (bus->mlcap)
snd_hdac_ext_bus_get_ml_capabilities(bus);
@@ -1034,8 +1071,10 @@ static int skl_probe(struct pci_dev *pci,
/* create device for soc dmic */
err = skl_dmic_device_register(skl);
if (err < 0)
if (err < 0) {
dev_err(bus->dev, "skl_dmic_device_register failed with err: %d\n", err);
goto out_dsp_free;
}
schedule_work(&skl->probe_work);
@@ -1103,21 +1142,36 @@ static void skl_remove(struct pci_dev *pci)
/* PCI IDs */
static const struct pci_device_id skl_ids[] = {
#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKL)
/* Sunrise Point-LP */
{ PCI_DEVICE(0x8086, 0x9d70),
.driver_data = (unsigned long)&snd_soc_acpi_intel_skl_machines},
#endif
#if IS_ENABLED(CONFIG_SND_SOC_INTEL_APL)
/* BXT-P */
{ PCI_DEVICE(0x8086, 0x5a98),
.driver_data = (unsigned long)&snd_soc_acpi_intel_bxt_machines},
#endif
#if IS_ENABLED(CONFIG_SND_SOC_INTEL_KBL)
/* KBL */
{ PCI_DEVICE(0x8086, 0x9D71),
.driver_data = (unsigned long)&snd_soc_acpi_intel_kbl_machines},
#endif
#if IS_ENABLED(CONFIG_SND_SOC_INTEL_GLK)
/* GLK */
{ PCI_DEVICE(0x8086, 0x3198),
.driver_data = (unsigned long)&snd_soc_acpi_intel_glk_machines},
#endif
#if IS_ENABLED(CONFIG_SND_SOC_INTEL_CNL)
/* CNL */
{ PCI_DEVICE(0x8086, 0x9dc8),
.driver_data = (unsigned long)&snd_soc_acpi_intel_cnl_machines},
#endif
#if IS_ENABLED(CONFIG_SND_SOC_INTEL_CFL)
/* CFL */
{ PCI_DEVICE(0x8086, 0xa348),
.driver_data = (unsigned long)&snd_soc_acpi_intel_cnl_machines},
#endif
{ 0, }
};
MODULE_DEVICE_TABLE(pci, skl_ids);

View File

@@ -119,10 +119,7 @@ struct skl_dma_params {
};
struct skl_machine_pdata {
u32 dmic_num;
bool use_tplg_pcm; /* use dais and dai links from topology */
const char *platform;
u32 codec_mask;
};
struct skl_dsp_ops {

View File

@@ -828,7 +828,7 @@ static int mt6797_afe_pcm_dev_probe(struct platform_device *pdev)
/* request irq */
irq_id = platform_get_irq(pdev, 0);
if (!irq_id) {
dev_err(dev, "%s no irq found\n", dev->of_node->name);
dev_err(dev, "%pOFn no irq found\n", dev->of_node);
return -ENXIO;
}
ret = devm_request_irq(dev, irq_id, mt6797_afe_irq_handler,

View File

@@ -1092,7 +1092,7 @@ static int mt8173_afe_pcm_dev_probe(struct platform_device *pdev)
irq_id = platform_get_irq(pdev, 0);
if (irq_id <= 0) {
dev_err(afe->dev, "np %s no irq\n", afe->dev->of_node->name);
dev_err(afe->dev, "np %pOFn no irq\n", afe->dev->of_node);
return irq_id < 0 ? irq_id : -ENXIO;
}
ret = devm_request_irq(afe->dev, irq_id, mt8173_afe_irq_handler,

View File

@@ -54,6 +54,7 @@ config SND_MESON_AXG_SOUND_CARD
imply SND_MESON_AXG_TDMIN
imply SND_MESON_AXG_TDMOUT
imply SND_MESON_AXG_SPDIFOUT
imply SND_MESON_AXG_SPDIFIN
imply SND_MESON_AXG_PDM
help
Select Y or M to add support for the AXG SoC sound card
@@ -67,6 +68,13 @@ config SND_MESON_AXG_SPDIFOUT
Select Y or M to add support for SPDIF output serializer embedded
in the Amlogic AXG SoC family
config SND_MESON_AXG_SPDIFIN
tristate "Amlogic AXG SPDIF Input Support"
imply SND_SOC_SPDIF
help
Select Y or M to add support for SPDIF input embedded
in the Amlogic AXG SoC family
config SND_MESON_AXG_PDM
tristate "Amlogic AXG PDM Input Support"
imply SND_SOC_DMIC
@@ -74,5 +82,4 @@ config SND_MESON_AXG_PDM
help
Select Y or M to add support for PDM input embedded
in the Amlogic AXG SoC family
endmenu

View File

@@ -8,6 +8,7 @@ snd-soc-meson-axg-tdm-interface-objs := axg-tdm-interface.o
snd-soc-meson-axg-tdmin-objs := axg-tdmin.o
snd-soc-meson-axg-tdmout-objs := axg-tdmout.o
snd-soc-meson-axg-sound-card-objs := axg-card.o
snd-soc-meson-axg-spdifin-objs := axg-spdifin.o
snd-soc-meson-axg-spdifout-objs := axg-spdifout.o
snd-soc-meson-axg-pdm-objs := axg-pdm.o
@@ -19,5 +20,6 @@ obj-$(CONFIG_SND_MESON_AXG_TDM_INTERFACE) += snd-soc-meson-axg-tdm-interface.o
obj-$(CONFIG_SND_MESON_AXG_TDMIN) += snd-soc-meson-axg-tdmin.o
obj-$(CONFIG_SND_MESON_AXG_TDMOUT) += snd-soc-meson-axg-tdmout.o
obj-$(CONFIG_SND_MESON_AXG_SOUND_CARD) += snd-soc-meson-axg-sound-card.o
obj-$(CONFIG_SND_MESON_AXG_SPDIFIN) += snd-soc-meson-axg-spdifin.o
obj-$(CONFIG_SND_MESON_AXG_SPDIFOUT) += snd-soc-meson-axg-spdifout.o
obj-$(CONFIG_SND_MESON_AXG_PDM) += snd-soc-meson-axg-pdm.o

View File

@@ -25,7 +25,8 @@ struct snd_soc_pcm_runtime;
SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S20_LE | \
SNDRV_PCM_FMTBIT_S24_LE | \
SNDRV_PCM_FMTBIT_S32_LE)
SNDRV_PCM_FMTBIT_S32_LE | \
SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE)
#define AXG_FIFO_BURST 8
#define AXG_FIFO_MIN_CNT 64

View File

@@ -0,0 +1,521 @@
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
//
// Copyright (c) 2018 BayLibre, SAS.
// Author: Jerome Brunet <jbrunet@baylibre.com>
#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/regmap.h>
#include <sound/soc.h>
#include <sound/soc-dai.h>
#include <sound/pcm_params.h>
#define SPDIFIN_CTRL0 0x00
#define SPDIFIN_CTRL0_EN BIT(31)
#define SPDIFIN_CTRL0_RST_OUT BIT(29)
#define SPDIFIN_CTRL0_RST_IN BIT(28)
#define SPDIFIN_CTRL0_WIDTH_SEL BIT(24)
#define SPDIFIN_CTRL0_STATUS_CH_SHIFT 11
#define SPDIFIN_CTRL0_STATUS_SEL GENMASK(10, 8)
#define SPDIFIN_CTRL0_SRC_SEL GENMASK(5, 4)
#define SPDIFIN_CTRL0_CHK_VALID BIT(3)
#define SPDIFIN_CTRL1 0x04
#define SPDIFIN_CTRL1_BASE_TIMER GENMASK(19, 0)
#define SPDIFIN_CTRL1_IRQ_MASK GENMASK(27, 20)
#define SPDIFIN_CTRL2 0x08
#define SPDIFIN_THRES_PER_REG 3
#define SPDIFIN_THRES_WIDTH 10
#define SPDIFIN_CTRL3 0x0c
#define SPDIFIN_CTRL4 0x10
#define SPDIFIN_TIMER_PER_REG 4
#define SPDIFIN_TIMER_WIDTH 8
#define SPDIFIN_CTRL5 0x14
#define SPDIFIN_CTRL6 0x18
#define SPDIFIN_STAT0 0x1c
#define SPDIFIN_STAT0_MODE GENMASK(30, 28)
#define SPDIFIN_STAT0_MAXW GENMASK(17, 8)
#define SPDIFIN_STAT0_IRQ GENMASK(7, 0)
#define SPDIFIN_IRQ_MODE_CHANGED BIT(2)
#define SPDIFIN_STAT1 0x20
#define SPDIFIN_STAT2 0x24
#define SPDIFIN_MUTE_VAL 0x28
#define SPDIFIN_MODE_NUM 7
struct axg_spdifin_cfg {
const unsigned int *mode_rates;
unsigned int ref_rate;
};
struct axg_spdifin {
const struct axg_spdifin_cfg *conf;
struct regmap *map;
struct clk *refclk;
struct clk *pclk;
};
/*
* TODO:
* It would have been nice to check the actual rate against the sample rate
* requested in hw_params(). Unfortunately, I was not able to make the mode
* detection and IRQ work reliably:
*
* 1. IRQs are generated on mode change only, so there is no notification
* on transition between no signal and mode 0 (32kHz).
* 2. Mode detection very often has glitches, and may detects the
* lowest or the highest mode before zeroing in on the actual mode.
*
* This makes calling snd_pcm_stop() difficult to get right. Even notifying
* the kcontrol would be very unreliable at this point.
* Let's keep things simple until the magic spell that makes this work is
* found.
*/
static unsigned int axg_spdifin_get_rate(struct axg_spdifin *priv)
{
unsigned int stat, mode, rate = 0;
regmap_read(priv->map, SPDIFIN_STAT0, &stat);
mode = FIELD_GET(SPDIFIN_STAT0_MODE, stat);
/*
* If max width is zero, we are not capturing anything.
* Also Sometimes, when the capture is on but there is no data,
* mode is SPDIFIN_MODE_NUM, but not always ...
*/
if (FIELD_GET(SPDIFIN_STAT0_MAXW, stat) &&
mode < SPDIFIN_MODE_NUM)
rate = priv->conf->mode_rates[mode];
return rate;
}
static int axg_spdifin_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct axg_spdifin *priv = snd_soc_dai_get_drvdata(dai);
/* Apply both reset */
regmap_update_bits(priv->map, SPDIFIN_CTRL0,
SPDIFIN_CTRL0_RST_OUT |
SPDIFIN_CTRL0_RST_IN,
0);
/* Clear out reset before in reset */
regmap_update_bits(priv->map, SPDIFIN_CTRL0,
SPDIFIN_CTRL0_RST_OUT, SPDIFIN_CTRL0_RST_OUT);
regmap_update_bits(priv->map, SPDIFIN_CTRL0,
SPDIFIN_CTRL0_RST_IN, SPDIFIN_CTRL0_RST_IN);
return 0;
}
static int axg_spdifin_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct axg_spdifin *priv = snd_soc_dai_get_drvdata(dai);
int ret;
ret = clk_prepare_enable(priv->refclk);
if (ret) {
dev_err(dai->dev,
"failed to enable spdifin reference clock\n");
return ret;
}
regmap_update_bits(priv->map, SPDIFIN_CTRL0, SPDIFIN_CTRL0_EN,
SPDIFIN_CTRL0_EN);
return 0;
}
static void axg_spdifin_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct axg_spdifin *priv = snd_soc_dai_get_drvdata(dai);
regmap_update_bits(priv->map, SPDIFIN_CTRL0, SPDIFIN_CTRL0_EN, 0);
clk_disable_unprepare(priv->refclk);
}
static void axg_spdifin_write_mode_param(struct regmap *map, int mode,
unsigned int val,
unsigned int num_per_reg,
unsigned int base_reg,
unsigned int width)
{
uint64_t offset = mode;
unsigned int reg, shift, rem;
rem = do_div(offset, num_per_reg);
reg = offset * regmap_get_reg_stride(map) + base_reg;
shift = width * (num_per_reg - 1 - rem);
regmap_update_bits(map, reg, GENMASK(width - 1, 0) << shift,
val << shift);
}
static void axg_spdifin_write_timer(struct regmap *map, int mode,
unsigned int val)
{
axg_spdifin_write_mode_param(map, mode, val, SPDIFIN_TIMER_PER_REG,
SPDIFIN_CTRL4, SPDIFIN_TIMER_WIDTH);
}
static void axg_spdifin_write_threshold(struct regmap *map, int mode,
unsigned int val)
{
axg_spdifin_write_mode_param(map, mode, val, SPDIFIN_THRES_PER_REG,
SPDIFIN_CTRL2, SPDIFIN_THRES_WIDTH);
}
static unsigned int axg_spdifin_mode_timer(struct axg_spdifin *priv,
int mode,
unsigned int rate)
{
/*
* Number of period of the reference clock during a period of the
* input signal reference clock
*/
return rate / (128 * priv->conf->mode_rates[mode]);
}
static int axg_spdifin_sample_mode_config(struct snd_soc_dai *dai,
struct axg_spdifin *priv)
{
unsigned int rate, t_next;
int ret, i = SPDIFIN_MODE_NUM - 1;
/* Set spdif input reference clock */
ret = clk_set_rate(priv->refclk, priv->conf->ref_rate);
if (ret) {
dev_err(dai->dev, "reference clock rate set failed\n");
return ret;
}
/*
* The rate actually set might be slightly different, get
* the actual rate for the following mode calculation
*/
rate = clk_get_rate(priv->refclk);
/* HW will update mode every 1ms */
regmap_update_bits(priv->map, SPDIFIN_CTRL1,
SPDIFIN_CTRL1_BASE_TIMER,
FIELD_PREP(SPDIFIN_CTRL1_BASE_TIMER, rate / 1000));
/* Threshold based on the minimum width between two edges */
regmap_update_bits(priv->map, SPDIFIN_CTRL0,
SPDIFIN_CTRL0_WIDTH_SEL, SPDIFIN_CTRL0_WIDTH_SEL);
/* Calculate the last timer which has no threshold */
t_next = axg_spdifin_mode_timer(priv, i, rate);
axg_spdifin_write_timer(priv->map, i, t_next);
do {
unsigned int t;
i -= 1;
/* Calculate the timer */
t = axg_spdifin_mode_timer(priv, i, rate);
/* Set the timer value */
axg_spdifin_write_timer(priv->map, i, t);
/* Set the threshold value */
axg_spdifin_write_threshold(priv->map, i, t + t_next);
/* Save the current timer for the next threshold calculation */
t_next = t;
} while (i > 0);
return 0;
}
static int axg_spdifin_dai_probe(struct snd_soc_dai *dai)
{
struct axg_spdifin *priv = snd_soc_dai_get_drvdata(dai);
int ret;
ret = clk_prepare_enable(priv->pclk);
if (ret) {
dev_err(dai->dev, "failed to enable pclk\n");
return ret;
}
ret = axg_spdifin_sample_mode_config(dai, priv);
if (ret) {
dev_err(dai->dev, "mode configuration failed\n");
clk_disable_unprepare(priv->pclk);
return ret;
}
return 0;
}
static int axg_spdifin_dai_remove(struct snd_soc_dai *dai)
{
struct axg_spdifin *priv = snd_soc_dai_get_drvdata(dai);
clk_disable_unprepare(priv->pclk);
return 0;
}
static const struct snd_soc_dai_ops axg_spdifin_ops = {
.prepare = axg_spdifin_prepare,
.startup = axg_spdifin_startup,
.shutdown = axg_spdifin_shutdown,
};
static int axg_spdifin_iec958_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
uinfo->count = 1;
return 0;
}
static int axg_spdifin_get_status_mask(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
int i;
for (i = 0; i < 24; i++)
ucontrol->value.iec958.status[i] = 0xff;
return 0;
}
static int axg_spdifin_get_status(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *c = snd_kcontrol_chip(kcontrol);
struct axg_spdifin *priv = snd_soc_component_get_drvdata(c);
int i, j;
for (i = 0; i < 6; i++) {
unsigned int val;
regmap_update_bits(priv->map, SPDIFIN_CTRL0,
SPDIFIN_CTRL0_STATUS_SEL,
FIELD_PREP(SPDIFIN_CTRL0_STATUS_SEL, i));
regmap_read(priv->map, SPDIFIN_STAT1, &val);
for (j = 0; j < 4; j++) {
unsigned int offset = i * 4 + j;
ucontrol->value.iec958.status[offset] =
(val >> (j * 8)) & 0xff;
}
}
return 0;
}
#define AXG_SPDIFIN_IEC958_MASK \
{ \
.access = SNDRV_CTL_ELEM_ACCESS_READ, \
.iface = SNDRV_CTL_ELEM_IFACE_PCM, \
.name = SNDRV_CTL_NAME_IEC958("", CAPTURE, MASK), \
.info = axg_spdifin_iec958_info, \
.get = axg_spdifin_get_status_mask, \
}
#define AXG_SPDIFIN_IEC958_STATUS \
{ \
.access = (SNDRV_CTL_ELEM_ACCESS_READ | \
SNDRV_CTL_ELEM_ACCESS_VOLATILE), \
.iface = SNDRV_CTL_ELEM_IFACE_PCM, \
.name = SNDRV_CTL_NAME_IEC958("", CAPTURE, NONE), \
.info = axg_spdifin_iec958_info, \
.get = axg_spdifin_get_status, \
}
static const char * const spdifin_chsts_src_texts[] = {
"A", "B",
};
static SOC_ENUM_SINGLE_DECL(axg_spdifin_chsts_src_enum, SPDIFIN_CTRL0,
SPDIFIN_CTRL0_STATUS_CH_SHIFT,
spdifin_chsts_src_texts);
static int axg_spdifin_rate_lock_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 1;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = 192000;
return 0;
}
static int axg_spdifin_rate_lock_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *c = snd_kcontrol_chip(kcontrol);
struct axg_spdifin *priv = snd_soc_component_get_drvdata(c);
ucontrol->value.integer.value[0] = axg_spdifin_get_rate(priv);
return 0;
}
#define AXG_SPDIFIN_LOCK_RATE(xname) \
{ \
.iface = SNDRV_CTL_ELEM_IFACE_PCM, \
.access = (SNDRV_CTL_ELEM_ACCESS_READ | \
SNDRV_CTL_ELEM_ACCESS_VOLATILE), \
.get = axg_spdifin_rate_lock_get, \
.info = axg_spdifin_rate_lock_info, \
.name = xname, \
}
static const struct snd_kcontrol_new axg_spdifin_controls[] = {
AXG_SPDIFIN_LOCK_RATE("Capture Rate Lock"),
SOC_DOUBLE("Capture Switch", SPDIFIN_CTRL0, 7, 6, 1, 1),
SOC_ENUM(SNDRV_CTL_NAME_IEC958("", CAPTURE, NONE) "Src",
axg_spdifin_chsts_src_enum),
AXG_SPDIFIN_IEC958_MASK,
AXG_SPDIFIN_IEC958_STATUS,
};
static const struct snd_soc_component_driver axg_spdifin_component_drv = {
.controls = axg_spdifin_controls,
.num_controls = ARRAY_SIZE(axg_spdifin_controls),
};
static const struct regmap_config axg_spdifin_regmap_cfg = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
.max_register = SPDIFIN_MUTE_VAL,
};
static const unsigned int axg_spdifin_mode_rates[SPDIFIN_MODE_NUM] = {
32000, 44100, 48000, 88200, 96000, 176400, 192000,
};
static const struct axg_spdifin_cfg axg_cfg = {
.mode_rates = axg_spdifin_mode_rates,
.ref_rate = 333333333,
};
static const struct of_device_id axg_spdifin_of_match[] = {
{
.compatible = "amlogic,axg-spdifin",
.data = &axg_cfg,
}, {}
};
MODULE_DEVICE_TABLE(of, axg_spdifin_of_match);
static struct snd_soc_dai_driver *
axg_spdifin_get_dai_drv(struct device *dev, struct axg_spdifin *priv)
{
struct snd_soc_dai_driver *drv;
int i;
drv = devm_kzalloc(dev, sizeof(*drv), GFP_KERNEL);
if (!drv)
return ERR_PTR(-ENOMEM);
drv->name = "SPDIF Input";
drv->ops = &axg_spdifin_ops;
drv->probe = axg_spdifin_dai_probe;
drv->remove = axg_spdifin_dai_remove;
drv->capture.stream_name = "Capture";
drv->capture.channels_min = 1;
drv->capture.channels_max = 2;
drv->capture.formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE;
for (i = 0; i < SPDIFIN_MODE_NUM; i++) {
unsigned int rb =
snd_pcm_rate_to_rate_bit(priv->conf->mode_rates[i]);
if (rb == SNDRV_PCM_RATE_KNOT)
return ERR_PTR(-EINVAL);
drv->capture.rates |= rb;
}
return drv;
}
static int axg_spdifin_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct axg_spdifin *priv;
struct snd_soc_dai_driver *dai_drv;
struct resource *res;
void __iomem *regs;
int ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
platform_set_drvdata(pdev, priv);
priv->conf = of_device_get_match_data(dev);
if (!priv->conf) {
dev_err(dev, "failed to match device\n");
return -ENODEV;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
regs = devm_ioremap_resource(dev, res);
if (IS_ERR(regs))
return PTR_ERR(regs);
priv->map = devm_regmap_init_mmio(dev, regs, &axg_spdifin_regmap_cfg);
if (IS_ERR(priv->map)) {
dev_err(dev, "failed to init regmap: %ld\n",
PTR_ERR(priv->map));
return PTR_ERR(priv->map);
}
priv->pclk = devm_clk_get(dev, "pclk");
if (IS_ERR(priv->pclk)) {
ret = PTR_ERR(priv->pclk);
if (ret != -EPROBE_DEFER)
dev_err(dev, "failed to get pclk: %d\n", ret);
return ret;
}
priv->refclk = devm_clk_get(dev, "refclk");
if (IS_ERR(priv->refclk)) {
ret = PTR_ERR(priv->refclk);
if (ret != -EPROBE_DEFER)
dev_err(dev, "failed to get mclk: %d\n", ret);
return ret;
}
dai_drv = axg_spdifin_get_dai_drv(dev, priv);
if (IS_ERR(dai_drv)) {
dev_err(dev, "failed to get dai driver: %ld\n",
PTR_ERR(dai_drv));
return PTR_ERR(dai_drv);
}
return devm_snd_soc_register_component(dev, &axg_spdifin_component_drv,
dai_drv, 1);
}
static struct platform_driver axg_spdifin_pdrv = {
.probe = axg_spdifin_probe,
.driver = {
.name = "axg-spdifin",
.of_match_table = axg_spdifin_of_match,
},
};
module_platform_driver(axg_spdifin_pdrv);
MODULE_DESCRIPTION("Amlogic AXG SPDIF Input driver");
MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
MODULE_LICENSE("GPL v2");

View File

@@ -25,6 +25,8 @@
#define CTRL0_TODDR_LSB_POS_MASK GENMASK(7, 3)
#define CTRL0_TODDR_LSB_POS(x) ((x) << 3)
#define TODDR_MSB_POS 31
static int axg_toddr_pcm_new(struct snd_soc_pcm_runtime *rtd,
struct snd_soc_dai *dai)
{
@@ -36,14 +38,7 @@ static int axg_toddr_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct axg_fifo *fifo = snd_soc_dai_get_drvdata(dai);
unsigned int type, width, msb = 31;
/*
* NOTE:
* Almost all backend will place the MSB at bit 31, except SPDIF Input
* which will put it at index 28. When adding support for the SPDIF
* Input, we'll need to find which type of backend we are connected to.
*/
unsigned int type, width;
switch (params_physical_width(params)) {
case 8:
@@ -66,8 +61,8 @@ static int axg_toddr_dai_hw_params(struct snd_pcm_substream *substream,
CTRL0_TODDR_MSB_POS_MASK |
CTRL0_TODDR_LSB_POS_MASK,
CTRL0_TODDR_TYPE(type) |
CTRL0_TODDR_MSB_POS(msb) |
CTRL0_TODDR_LSB_POS(msb - (width - 1)));
CTRL0_TODDR_MSB_POS(TODDR_MSB_POS) |
CTRL0_TODDR_LSB_POS(TODDR_MSB_POS - (width - 1)));
return 0;
}

View File

@@ -1,129 +0,0 @@
config SND_OMAP_SOC
tristate "SoC Audio for Texas Instruments OMAP chips (deprecated)"
depends on (ARCH_OMAP && DMA_OMAP) || (ARM && COMPILE_TEST)
select SND_SDMA_SOC
config SND_SDMA_SOC
tristate "SoC Audio for Texas Instruments chips using sDMA"
depends on DMA_OMAP || COMPILE_TEST
select SND_SOC_GENERIC_DMAENGINE_PCM
config SND_OMAP_SOC_DMIC
tristate
config SND_OMAP_SOC_MCBSP
tristate
config SND_OMAP_SOC_MCPDM
tristate
config SND_OMAP_SOC_HDMI_AUDIO
tristate "HDMI audio support for OMAP4+ based SoCs"
depends on SND_SDMA_SOC
help
For HDMI audio to work OMAPDSS HDMI support should be
enabled.
The hdmi audio driver implements cpu-dai component using the
callbacks provided by OMAPDSS and registers the component
under DSS HDMI device. Omap-pcm is registered for platform
component also under DSS HDMI device. Dummy codec is used as
as codec component. The hdmi audio driver implements also
the card and registers it under its own platform device.
The device for the driver is registered by OMAPDSS hdmi
driver.
config SND_OMAP_SOC_N810
tristate "SoC Audio support for Nokia N810"
depends on SND_SDMA_SOC && MACH_NOKIA_N810 && I2C
select SND_OMAP_SOC_MCBSP
select SND_SOC_TLV320AIC3X
help
Say Y if you want to add support for SoC audio on Nokia N810.
config SND_OMAP_SOC_RX51
tristate "SoC Audio support for Nokia N900 (RX-51)"
depends on SND_SDMA_SOC && ARM && I2C
select SND_OMAP_SOC_MCBSP
select SND_SOC_TLV320AIC3X
select SND_SOC_TPA6130A2
depends on GPIOLIB
help
Say Y if you want to add support for SoC audio on Nokia N900
cellphone.
config SND_OMAP_SOC_AMS_DELTA
tristate "SoC Audio support for Amstrad E3 (Delta) videophone"
depends on SND_SDMA_SOC && MACH_AMS_DELTA && TTY
select SND_OMAP_SOC_MCBSP
select SND_SOC_CX20442
help
Say Y if you want to add support for SoC audio device connected to
a handset and a speakerphone found on Amstrad E3 (Delta) videophone.
Note that in order to get those devices fully supported, you have to
build the kernel with standard serial port driver included and
configured for at least 4 ports. Then, from userspace, you must load
a line discipline #19 on the modem (ttyS3) serial line. The simplest
way to achieve this is to install util-linux-ng and use the included
ldattach utility. This can be started automatically from udev,
a simple rule like this one should do the trick (it does for me):
ACTION=="add", KERNEL=="controlC0", \
RUN+="/usr/sbin/ldattach 19 /dev/ttyS3"
config SND_OMAP_SOC_OSK5912
tristate "SoC Audio support for omap osk5912"
depends on SND_SDMA_SOC && MACH_OMAP_OSK && I2C
select SND_OMAP_SOC_MCBSP
select SND_SOC_TLV320AIC23_I2C
help
Say Y if you want to add support for SoC audio on osk5912.
config SND_OMAP_SOC_AM3517EVM
tristate "SoC Audio support for OMAP3517 / AM3517 EVM"
depends on SND_SDMA_SOC && MACH_OMAP3517EVM && I2C
select SND_OMAP_SOC_MCBSP
select SND_SOC_TLV320AIC23_I2C
help
Say Y if you want to add support for SoC audio on the OMAP3517 / AM3517
EVM.
config SND_OMAP_SOC_OMAP_TWL4030
tristate "SoC Audio support for TI SoC based boards with twl4030 codec"
depends on TWL4030_CORE && SND_SDMA_SOC
select SND_OMAP_SOC_MCBSP
select SND_SOC_TWL4030
help
Say Y if you want to add support for SoC audio on TI SoC based boards
using twl4030 as c codec. This driver currently supports:
- Beagleboard or Devkit8000
- Gumstix Overo or CompuLab CM-T35/CM-T3730
- IGEP v2
- OMAP3EVM
- SDP3430
- Zoom2
config SND_OMAP_SOC_OMAP_ABE_TWL6040
tristate "SoC Audio support for OMAP boards using ABE and twl6040 codec"
depends on TWL6040_CORE && SND_SDMA_SOC && COMMON_CLK
depends on ARCH_OMAP4 || (SOC_OMAP5 && MFD_PALMAS) || COMPILE_TEST
select SND_OMAP_SOC_DMIC
select SND_OMAP_SOC_MCPDM
select SND_SOC_TWL6040
select SND_SOC_DMIC
select COMMON_CLK_PALMAS if (SOC_OMAP5 && MFD_PALMAS)
select CLK_TWL6040
help
Say Y if you want to add support for SoC audio on OMAP boards using
ABE and twl6040 codec. This driver currently supports:
- SDP4430/Blaze boards
- PandaBoard (4430)
- PandaBoardES (4460)
- omap5-uevm (5432)
config SND_OMAP_SOC_OMAP3_PANDORA
tristate "SoC Audio support for OMAP3 Pandora"
depends on TWL4030_CORE && SND_SDMA_SOC && MACH_OMAP3_PANDORA
select SND_OMAP_SOC_MCBSP
select SND_SOC_TWL4030
help
Say Y if you want to add support for SoC audio on the OMAP3 Pandora.

View File

@@ -1,32 +0,0 @@
# SPDX-License-Identifier: GPL-2.0
# OMAP Platform Support
snd-soc-sdma-objs := sdma-pcm.o
snd-soc-omap-dmic-objs := omap-dmic.o
snd-soc-omap-mcbsp-objs := omap-mcbsp.o mcbsp.o
snd-soc-omap-mcpdm-objs := omap-mcpdm.o
snd-soc-omap-hdmi-audio-objs := omap-hdmi-audio.o
obj-$(CONFIG_SND_SDMA_SOC) += snd-soc-sdma.o
obj-$(CONFIG_SND_OMAP_SOC_DMIC) += snd-soc-omap-dmic.o
obj-$(CONFIG_SND_OMAP_SOC_MCBSP) += snd-soc-omap-mcbsp.o
obj-$(CONFIG_SND_OMAP_SOC_MCPDM) += snd-soc-omap-mcpdm.o
obj-$(CONFIG_SND_OMAP_SOC_HDMI_AUDIO) += snd-soc-omap-hdmi-audio.o
# OMAP Machine Support
snd-soc-n810-objs := n810.o
snd-soc-rx51-objs := rx51.o
snd-soc-ams-delta-objs := ams-delta.o
snd-soc-osk5912-objs := osk5912.o
snd-soc-am3517evm-objs := am3517evm.o
snd-soc-omap-abe-twl6040-objs := omap-abe-twl6040.o
snd-soc-omap-twl4030-objs := omap-twl4030.o
snd-soc-omap3pandora-objs := omap3pandora.o
obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o
obj-$(CONFIG_SND_OMAP_SOC_RX51) += snd-soc-rx51.o
obj-$(CONFIG_SND_OMAP_SOC_AMS_DELTA) += snd-soc-ams-delta.o
obj-$(CONFIG_SND_OMAP_SOC_OSK5912) += snd-soc-osk5912.o
obj-$(CONFIG_SND_OMAP_SOC_AM3517EVM) += snd-soc-am3517evm.o
obj-$(CONFIG_SND_OMAP_SOC_OMAP_ABE_TWL6040) += snd-soc-omap-abe-twl6040.o
obj-$(CONFIG_SND_OMAP_SOC_OMAP_TWL4030) += snd-soc-omap-twl4030.o
obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o

View File

@@ -1,141 +0,0 @@
/*
* am3517evm.c -- ALSA SoC support for OMAP3517 / AM3517 EVM
*
* Author: Anuj Aggarwal <anuj.aggarwal@ti.com>
*
* Based on sound/soc/omap/beagle.c by Steve Sakoman
*
* Copyright (C) 2009 Texas Instruments Incorporated
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation version 2.
*
* This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
* whether express or implied; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/module.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <asm/mach-types.h>
#include <linux/platform_data/asoc-ti-mcbsp.h>
#include "omap-mcbsp.h"
#include "../codecs/tlv320aic23.h"
#define CODEC_CLOCK 12000000
static int am3517evm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
int ret;
/* Set the codec system clock for DAC and ADC */
ret = snd_soc_dai_set_sysclk(codec_dai, 0,
CODEC_CLOCK, SND_SOC_CLOCK_IN);
if (ret < 0)
printk(KERN_ERR "can't set codec system clock\n");
return ret;
}
static const struct snd_soc_ops am3517evm_ops = {
.hw_params = am3517evm_hw_params,
};
/* am3517evm machine dapm widgets */
static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = {
SND_SOC_DAPM_HP("Line Out", NULL),
SND_SOC_DAPM_LINE("Line In", NULL),
SND_SOC_DAPM_MIC("Mic In", NULL),
};
static const struct snd_soc_dapm_route audio_map[] = {
/* Line Out connected to LLOUT, RLOUT */
{"Line Out", NULL, "LOUT"},
{"Line Out", NULL, "ROUT"},
{"LLINEIN", NULL, "Line In"},
{"RLINEIN", NULL, "Line In"},
{"MICIN", NULL, "Mic In"},
};
/* Digital audio interface glue - connects codec <--> CPU */
static struct snd_soc_dai_link am3517evm_dai = {
.name = "TLV320AIC23",
.stream_name = "AIC23",
.cpu_dai_name = "omap-mcbsp.1",
.codec_dai_name = "tlv320aic23-hifi",
.platform_name = "omap-mcbsp.1",
.codec_name = "tlv320aic23-codec.2-001a",
.dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBM_CFM,
.ops = &am3517evm_ops,
};
/* Audio machine driver */
static struct snd_soc_card snd_soc_am3517evm = {
.name = "am3517evm",
.owner = THIS_MODULE,
.dai_link = &am3517evm_dai,
.num_links = 1,
.dapm_widgets = tlv320aic23_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(tlv320aic23_dapm_widgets),
.dapm_routes = audio_map,
.num_dapm_routes = ARRAY_SIZE(audio_map),
};
static struct platform_device *am3517evm_snd_device;
static int __init am3517evm_soc_init(void)
{
int ret;
if (!machine_is_omap3517evm())
return -ENODEV;
pr_info("OMAP3517 / AM3517 EVM SoC init\n");
am3517evm_snd_device = platform_device_alloc("soc-audio", -1);
if (!am3517evm_snd_device) {
printk(KERN_ERR "Platform device allocation failed\n");
return -ENOMEM;
}
platform_set_drvdata(am3517evm_snd_device, &snd_soc_am3517evm);
ret = platform_device_add(am3517evm_snd_device);
if (ret)
goto err1;
return 0;
err1:
printk(KERN_ERR "Unable to add platform device\n");
platform_device_put(am3517evm_snd_device);
return ret;
}
static void __exit am3517evm_soc_exit(void)
{
platform_device_unregister(am3517evm_snd_device);
}
module_init(am3517evm_soc_init);
module_exit(am3517evm_soc_exit);
MODULE_AUTHOR("Anuj Aggarwal <anuj.aggarwal@ti.com>");
MODULE_DESCRIPTION("ALSA SoC OMAP3517 / AM3517 EVM");
MODULE_LICENSE("GPL v2");

File diff suppressed because it is too large Load Diff

View File

@@ -79,7 +79,7 @@ config SND_PXA2XX_SOC_TOSA
tristate "SoC AC97 Audio support for Tosa"
depends on SND_PXA2XX_SOC && MACH_TOSA
depends on MFD_TC6393XB
depends on !AC97_BUS
depends on AC97_BUS=n
select SND_PXA2XX_SOC_AC97
select SND_SOC_WM9712
help
@@ -89,7 +89,7 @@ config SND_PXA2XX_SOC_TOSA
config SND_PXA2XX_SOC_E740
tristate "SoC AC97 Audio support for e740"
depends on SND_PXA2XX_SOC && MACH_E740
depends on !AC97_BUS
depends on AC97_BUS=n
select SND_SOC_WM9705
select SND_PXA2XX_SOC_AC97
help
@@ -99,7 +99,7 @@ config SND_PXA2XX_SOC_E740
config SND_PXA2XX_SOC_E750
tristate "SoC AC97 Audio support for e750"
depends on SND_PXA2XX_SOC && MACH_E750
depends on !AC97_BUS
depends on AC97_BUS=n
select SND_SOC_WM9705
select SND_PXA2XX_SOC_AC97
help
@@ -109,7 +109,7 @@ config SND_PXA2XX_SOC_E750
config SND_PXA2XX_SOC_E800
tristate "SoC AC97 Audio support for e800"
depends on SND_PXA2XX_SOC && MACH_E800
depends on !AC97_BUS
depends on AC97_BUS=n
select SND_SOC_WM9712
select SND_PXA2XX_SOC_AC97
help
@@ -120,7 +120,7 @@ config SND_PXA2XX_SOC_EM_X270
tristate "SoC Audio support for CompuLab EM-x270, eXeda and CM-X300"
depends on SND_PXA2XX_SOC && (MACH_EM_X270 || MACH_EXEDA || \
MACH_CM_X300)
depends on !AC97_BUS
depends on AC97_BUS=n
select SND_PXA2XX_SOC_AC97
select SND_SOC_WM9712
help
@@ -131,7 +131,7 @@ config SND_PXA2XX_SOC_PALM27X
bool "SoC Audio support for Palm T|X, T5, E2 and LifeDrive"
depends on SND_PXA2XX_SOC && (MACH_PALMLD || MACH_PALMTX || \
MACH_PALMT5 || MACH_PALMTE2)
depends on !AC97_BUS
depends on AC97_BUS=n
select SND_PXA2XX_SOC_AC97
select SND_SOC_WM9712
help
@@ -161,7 +161,7 @@ config SND_SOC_TTC_DKB
config SND_SOC_ZYLONITE
tristate "SoC Audio support for Marvell Zylonite"
depends on SND_PXA2XX_SOC && MACH_ZYLONITE
depends on !AC97_BUS
depends on AC97_BUS=n
select SND_PXA2XX_SOC_AC97
select SND_PXA_SOC_SSP
select SND_SOC_WM9713
@@ -169,16 +169,6 @@ config SND_SOC_ZYLONITE
Say Y if you want to add support for SoC audio on the
Marvell Zylonite reference platform.
config SND_SOC_RAUMFELD
tristate "SoC Audio support Raumfeld audio adapter"
depends on SND_PXA2XX_SOC && (MACH_RAUMFELD_SPEAKER || MACH_RAUMFELD_CONNECTOR)
depends on I2C && SPI_MASTER
select SND_PXA_SOC_SSP
select SND_SOC_CS4270
select SND_SOC_AK4104
help
Say Y if you want to add support for SoC audio on Raumfeld devices
config SND_PXA2XX_SOC_HX4700
tristate "SoC Audio support for HP iPAQ hx4700"
depends on SND_PXA2XX_SOC && MACH_H4700 && I2C
@@ -201,7 +191,7 @@ config SND_PXA2XX_SOC_MAGICIAN
config SND_PXA2XX_SOC_MIOA701
tristate "SoC Audio support for MIO A701"
depends on SND_PXA2XX_SOC && MACH_MIOA701
depends on !AC97_BUS
depends on AC97_BUS=n
select SND_PXA2XX_SOC_AC97
select SND_SOC_WM9713
help

View File

@@ -49,6 +49,5 @@ obj-$(CONFIG_SND_PXA2XX_SOC_MIOA701) += snd-soc-mioa701.o
obj-$(CONFIG_SND_PXA2XX_SOC_Z2) += snd-soc-z2.o
obj-$(CONFIG_SND_SOC_ZYLONITE) += snd-soc-zylonite.o
obj-$(CONFIG_SND_PXA2XX_SOC_IMOTE2) += snd-soc-imote2.o
obj-$(CONFIG_SND_SOC_RAUMFELD) += snd-soc-raumfeld.o
obj-$(CONFIG_SND_MMP_SOC_BROWNSTONE) += snd-soc-brownstone.o
obj-$(CONFIG_SND_SOC_TTC_DKB) += snd-soc-ttc-dkb.o

View File

@@ -1,318 +0,0 @@
/*
* raumfeld_audio.c -- SoC audio for Raumfeld audio devices
*
* Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
*
* based on code from:
*
* Wolfson Microelectronics PLC.
* Openedhand Ltd.
* Liam Girdwood <lrg@slimlogic.co.uk>
* Richard Purdie <richard@openedhand.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <asm/mach-types.h>
#include "pxa-ssp.h"
#define GPIO_SPDIF_RESET (38)
#define GPIO_MCLK_RESET (111)
#define GPIO_CODEC_RESET (120)
static struct i2c_client *max9486_client;
static struct i2c_board_info max9486_hwmon_info = {
I2C_BOARD_INFO("max9485", 0x63),
};
#define MAX9485_MCLK_FREQ_112896 0x22
#define MAX9485_MCLK_FREQ_122880 0x23
#define MAX9485_MCLK_FREQ_225792 0x32
#define MAX9485_MCLK_FREQ_245760 0x33
static void set_max9485_clk(char clk)
{
i2c_master_send(max9486_client, &clk, 1);
}
static void raumfeld_enable_audio(bool en)
{
if (en) {
gpio_set_value(GPIO_MCLK_RESET, 1);
/* wait some time to let the clocks become stable */
msleep(100);
gpio_set_value(GPIO_SPDIF_RESET, 1);
gpio_set_value(GPIO_CODEC_RESET, 1);
} else {
gpio_set_value(GPIO_MCLK_RESET, 0);
gpio_set_value(GPIO_SPDIF_RESET, 0);
gpio_set_value(GPIO_CODEC_RESET, 0);
}
}
/* CS4270 */
static int raumfeld_cs4270_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
/* set freq to 0 to enable all possible codec sample rates */
return snd_soc_dai_set_sysclk(codec_dai, 0, 0, 0);
}
static void raumfeld_cs4270_shutdown(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
/* set freq to 0 to enable all possible codec sample rates */
snd_soc_dai_set_sysclk(codec_dai, 0, 0, 0);
}
static int raumfeld_cs4270_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int clk = 0;
int ret = 0;
switch (params_rate(params)) {
case 44100:
set_max9485_clk(MAX9485_MCLK_FREQ_112896);
clk = 11289600;
break;
case 48000:
set_max9485_clk(MAX9485_MCLK_FREQ_122880);
clk = 12288000;
break;
case 88200:
set_max9485_clk(MAX9485_MCLK_FREQ_225792);
clk = 22579200;
break;
case 96000:
set_max9485_clk(MAX9485_MCLK_FREQ_245760);
clk = 24576000;
break;
default:
return -EINVAL;
}
ret = snd_soc_dai_set_sysclk(codec_dai, 0, clk, 0);
if (ret < 0)
return ret;
/* setup the CPU DAI */
ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, 0, clk);
if (ret < 0)
return ret;
ret = snd_soc_dai_set_clkdiv(cpu_dai, PXA_SSP_DIV_SCR, 4);
if (ret < 0)
return ret;
ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_EXT, clk, 1);
if (ret < 0)
return ret;
return 0;
}
static const struct snd_soc_ops raumfeld_cs4270_ops = {
.startup = raumfeld_cs4270_startup,
.shutdown = raumfeld_cs4270_shutdown,
.hw_params = raumfeld_cs4270_hw_params,
};
static int raumfeld_analog_suspend(struct snd_soc_card *card)
{
raumfeld_enable_audio(false);
return 0;
}
static int raumfeld_analog_resume(struct snd_soc_card *card)
{
raumfeld_enable_audio(true);
return 0;
}
/* AK4104 */
static int raumfeld_ak4104_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret = 0, clk = 0;
switch (params_rate(params)) {
case 44100:
set_max9485_clk(MAX9485_MCLK_FREQ_112896);
clk = 11289600;
break;
case 48000:
set_max9485_clk(MAX9485_MCLK_FREQ_122880);
clk = 12288000;
break;
case 88200:
set_max9485_clk(MAX9485_MCLK_FREQ_225792);
clk = 22579200;
break;
case 96000:
set_max9485_clk(MAX9485_MCLK_FREQ_245760);
clk = 24576000;
break;
default:
return -EINVAL;
}
/* setup the CPU DAI */
ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, 0, clk);
if (ret < 0)
return ret;
ret = snd_soc_dai_set_clkdiv(cpu_dai, PXA_SSP_DIV_SCR, 4);
if (ret < 0)
return ret;
ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_EXT, clk, 1);
if (ret < 0)
return ret;
return 0;
}
static struct snd_soc_ops raumfeld_ak4104_ops = {
.hw_params = raumfeld_ak4104_hw_params,
};
#define DAI_LINK_CS4270 \
{ \
.name = "CS4270", \
.stream_name = "CS4270", \
.cpu_dai_name = "pxa-ssp-dai.0", \
.platform_name = "pxa-pcm-audio", \
.codec_dai_name = "cs4270-hifi", \
.codec_name = "cs4270.0-0048", \
.dai_fmt = SND_SOC_DAIFMT_I2S | \
SND_SOC_DAIFMT_NB_NF | \
SND_SOC_DAIFMT_CBS_CFS, \
.ops = &raumfeld_cs4270_ops, \
}
#define DAI_LINK_AK4104 \
{ \
.name = "ak4104", \
.stream_name = "Playback", \
.cpu_dai_name = "pxa-ssp-dai.1", \
.codec_dai_name = "ak4104-hifi", \
.platform_name = "pxa-pcm-audio", \
.dai_fmt = SND_SOC_DAIFMT_I2S | \
SND_SOC_DAIFMT_NB_NF | \
SND_SOC_DAIFMT_CBS_CFS, \
.ops = &raumfeld_ak4104_ops, \
.codec_name = "spi0.0", \
}
static struct snd_soc_dai_link snd_soc_raumfeld_connector_dai[] = {
DAI_LINK_CS4270,
DAI_LINK_AK4104,
};
static struct snd_soc_dai_link snd_soc_raumfeld_speaker_dai[] = {
DAI_LINK_CS4270,
};
static struct snd_soc_card snd_soc_raumfeld_connector = {
.name = "Raumfeld Connector",
.owner = THIS_MODULE,
.dai_link = snd_soc_raumfeld_connector_dai,
.num_links = ARRAY_SIZE(snd_soc_raumfeld_connector_dai),
.suspend_post = raumfeld_analog_suspend,
.resume_pre = raumfeld_analog_resume,
};
static struct snd_soc_card snd_soc_raumfeld_speaker = {
.name = "Raumfeld Speaker",
.owner = THIS_MODULE,
.dai_link = snd_soc_raumfeld_speaker_dai,
.num_links = ARRAY_SIZE(snd_soc_raumfeld_speaker_dai),
.suspend_post = raumfeld_analog_suspend,
.resume_pre = raumfeld_analog_resume,
};
static struct platform_device *raumfeld_audio_device;
static int __init raumfeld_audio_init(void)
{
int ret;
if (!machine_is_raumfeld_speaker() &&
!machine_is_raumfeld_connector())
return 0;
max9486_client = i2c_new_device(i2c_get_adapter(0),
&max9486_hwmon_info);
if (!max9486_client)
return -ENOMEM;
set_max9485_clk(MAX9485_MCLK_FREQ_122880);
/* Register analog device */
raumfeld_audio_device = platform_device_alloc("soc-audio", 0);
if (!raumfeld_audio_device)
return -ENOMEM;
if (machine_is_raumfeld_speaker())
platform_set_drvdata(raumfeld_audio_device,
&snd_soc_raumfeld_speaker);
if (machine_is_raumfeld_connector())
platform_set_drvdata(raumfeld_audio_device,
&snd_soc_raumfeld_connector);
ret = platform_device_add(raumfeld_audio_device);
if (ret < 0) {
platform_device_put(raumfeld_audio_device);
return ret;
}
raumfeld_enable_audio(true);
return 0;
}
static void __exit raumfeld_audio_exit(void)
{
raumfeld_enable_audio(false);
platform_device_unregister(raumfeld_audio_device);
i2c_unregister_device(max9486_client);
gpio_free(GPIO_MCLK_RESET);
gpio_free(GPIO_CODEC_RESET);
gpio_free(GPIO_SPDIF_RESET);
}
module_init(raumfeld_audio_init);
module_exit(raumfeld_audio_exit);
/* Module information */
MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
MODULE_DESCRIPTION("Raumfeld audio SoC");
MODULE_LICENSE("GPL");

View File

@@ -66,6 +66,7 @@ config SND_SOC_QDSP6_ASM
tristate
config SND_SOC_QDSP6_ASM_DAI
select SND_SOC_COMPRESS
tristate
config SND_SOC_QDSP6
@@ -100,6 +101,7 @@ config SND_SOC_SDM845
depends on QCOM_APR
select SND_SOC_QDSP6
select SND_SOC_QCOM_COMMON
select SND_SOC_RT5663
help
To add support for audio on Qualcomm Technologies Inc.
SDM845 SoC-based systems.

View File

@@ -91,7 +91,7 @@ static int lpass_platform_pcmops_open(struct snd_pcm_substream *substream)
if (ret) {
dev_err(soc_runtime->dev,
"error writing to rdmactl reg: %d\n", ret);
return ret;
return ret;
}
data->dma_ch = dma_ch;

Some files were not shown because too many files have changed in this diff Show More