Merge branch 'asoc-4.19' into asoc-next
This commit is contained in:
@@ -17,14 +17,9 @@ config SND_ARMAACI
|
||||
select SND_PCM
|
||||
select SND_AC97_CODEC
|
||||
|
||||
config SND_PXA2XX_PCM
|
||||
tristate
|
||||
select SND_PCM
|
||||
|
||||
config SND_PXA2XX_AC97
|
||||
tristate "AC97 driver for the Intel PXA2xx chip"
|
||||
depends on ARCH_PXA
|
||||
select SND_PXA2XX_PCM
|
||||
select SND_AC97_CODEC
|
||||
select SND_PXA2XX_LIB
|
||||
select SND_PXA2XX_LIB_AC97
|
||||
|
@@ -6,9 +6,6 @@
|
||||
obj-$(CONFIG_SND_ARMAACI) += snd-aaci.o
|
||||
snd-aaci-objs := aaci.o
|
||||
|
||||
obj-$(CONFIG_SND_PXA2XX_PCM) += snd-pxa2xx-pcm.o
|
||||
snd-pxa2xx-pcm-objs := pxa2xx-pcm.o
|
||||
|
||||
obj-$(CONFIG_SND_PXA2XX_LIB) += snd-pxa2xx-lib.o
|
||||
snd-pxa2xx-lib-y := pxa2xx-pcm-lib.o
|
||||
snd-pxa2xx-lib-$(CONFIG_SND_PXA2XX_LIB_AC97) += pxa2xx-ac97-lib.o
|
||||
|
@@ -19,6 +19,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/of_gpio.h>
|
||||
|
||||
#include <sound/pxa2xx-lib.h>
|
||||
|
||||
@@ -337,6 +338,17 @@ int pxa2xx_ac97_hw_probe(struct platform_device *dev)
|
||||
dev_err(&dev->dev, "Invalid reset GPIO %d\n",
|
||||
pdata->reset_gpio);
|
||||
}
|
||||
} else if (!pdata && dev->dev.of_node) {
|
||||
pdata = devm_kzalloc(&dev->dev, sizeof(*pdata), GFP_KERNEL);
|
||||
if (!pdata)
|
||||
return -ENOMEM;
|
||||
pdata->reset_gpio = of_get_named_gpio(dev->dev.of_node,
|
||||
"reset-gpios", 0);
|
||||
if (pdata->reset_gpio == -ENOENT)
|
||||
pdata->reset_gpio = -1;
|
||||
else if (pdata->reset_gpio < 0)
|
||||
return pdata->reset_gpio;
|
||||
reset_gpio = pdata->reset_gpio;
|
||||
} else {
|
||||
if (cpu_is_pxa27x())
|
||||
reset_gpio = 113;
|
||||
|
@@ -15,7 +15,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/dma/pxa-dma.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
@@ -27,8 +27,6 @@
|
||||
#include <mach/regs-ac97.h>
|
||||
#include <mach/audio.h>
|
||||
|
||||
#include "pxa2xx-pcm.h"
|
||||
|
||||
static void pxa2xx_ac97_legacy_reset(struct snd_ac97 *ac97)
|
||||
{
|
||||
if (!pxa2xx_ac97_try_cold_reset())
|
||||
@@ -63,61 +61,46 @@ static struct snd_ac97_bus_ops pxa2xx_ac97_ops = {
|
||||
.reset = pxa2xx_ac97_legacy_reset,
|
||||
};
|
||||
|
||||
static struct pxad_param pxa2xx_ac97_pcm_out_req = {
|
||||
.prio = PXAD_PRIO_LOWEST,
|
||||
.drcmr = 12,
|
||||
};
|
||||
|
||||
static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_out = {
|
||||
.addr = __PREG(PCDR),
|
||||
.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
|
||||
.maxburst = 32,
|
||||
.filter_data = &pxa2xx_ac97_pcm_out_req,
|
||||
};
|
||||
|
||||
static struct pxad_param pxa2xx_ac97_pcm_in_req = {
|
||||
.prio = PXAD_PRIO_LOWEST,
|
||||
.drcmr = 11,
|
||||
};
|
||||
|
||||
static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_in = {
|
||||
.addr = __PREG(PCDR),
|
||||
.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
|
||||
.maxburst = 32,
|
||||
.filter_data = &pxa2xx_ac97_pcm_in_req,
|
||||
};
|
||||
|
||||
static struct snd_pcm *pxa2xx_ac97_pcm;
|
||||
static struct snd_ac97 *pxa2xx_ac97_ac97;
|
||||
|
||||
static int pxa2xx_ac97_pcm_startup(struct snd_pcm_substream *substream)
|
||||
static int pxa2xx_ac97_pcm_open(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
pxa2xx_audio_ops_t *platform_ops;
|
||||
int r;
|
||||
int ret, i;
|
||||
|
||||
ret = pxa2xx_pcm_open(substream);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
runtime->hw.channels_min = 2;
|
||||
runtime->hw.channels_max = 2;
|
||||
|
||||
r = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
|
||||
AC97_RATES_FRONT_DAC : AC97_RATES_ADC;
|
||||
runtime->hw.rates = pxa2xx_ac97_ac97->rates[r];
|
||||
i = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
|
||||
AC97_RATES_FRONT_DAC : AC97_RATES_ADC;
|
||||
runtime->hw.rates = pxa2xx_ac97_ac97->rates[i];
|
||||
snd_pcm_limit_hw_rates(runtime);
|
||||
|
||||
platform_ops = substream->pcm->card->dev->platform_data;
|
||||
if (platform_ops && platform_ops->startup)
|
||||
return platform_ops->startup(substream, platform_ops->priv);
|
||||
else
|
||||
return 0;
|
||||
platform_ops = substream->pcm->card->dev->platform_data;
|
||||
if (platform_ops && platform_ops->startup) {
|
||||
ret = platform_ops->startup(substream, platform_ops->priv);
|
||||
if (ret < 0)
|
||||
pxa2xx_pcm_close(substream);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void pxa2xx_ac97_pcm_shutdown(struct snd_pcm_substream *substream)
|
||||
static int pxa2xx_ac97_pcm_close(struct snd_pcm_substream *substream)
|
||||
{
|
||||
pxa2xx_audio_ops_t *platform_ops;
|
||||
|
||||
platform_ops = substream->pcm->card->dev->platform_data;
|
||||
platform_ops = substream->pcm->card->dev->platform_data;
|
||||
if (platform_ops && platform_ops->shutdown)
|
||||
platform_ops->shutdown(substream, platform_ops->priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pxa2xx_ac97_pcm_prepare(struct snd_pcm_substream *substream)
|
||||
@@ -125,17 +108,15 @@ static int pxa2xx_ac97_pcm_prepare(struct snd_pcm_substream *substream)
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
int reg = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
|
||||
AC97_PCM_FRONT_DAC_RATE : AC97_PCM_LR_ADC_RATE;
|
||||
int ret;
|
||||
|
||||
ret = pxa2xx_pcm_prepare(substream);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return snd_ac97_set_rate(pxa2xx_ac97_ac97, reg, runtime->rate);
|
||||
}
|
||||
|
||||
static struct pxa2xx_pcm_client pxa2xx_ac97_pcm_client = {
|
||||
.playback_params = &pxa2xx_ac97_pcm_out,
|
||||
.capture_params = &pxa2xx_ac97_pcm_in,
|
||||
.startup = pxa2xx_ac97_pcm_startup,
|
||||
.shutdown = pxa2xx_ac97_pcm_shutdown,
|
||||
.prepare = pxa2xx_ac97_pcm_prepare,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
||||
static int pxa2xx_ac97_do_suspend(struct snd_card *card)
|
||||
@@ -193,6 +174,53 @@ static int pxa2xx_ac97_resume(struct device *dev)
|
||||
static SIMPLE_DEV_PM_OPS(pxa2xx_ac97_pm_ops, pxa2xx_ac97_suspend, pxa2xx_ac97_resume);
|
||||
#endif
|
||||
|
||||
static const struct snd_pcm_ops pxa2xx_ac97_pcm_ops = {
|
||||
.open = pxa2xx_ac97_pcm_open,
|
||||
.close = pxa2xx_ac97_pcm_close,
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.hw_params = pxa2xx_pcm_hw_params,
|
||||
.hw_free = pxa2xx_pcm_hw_free,
|
||||
.prepare = pxa2xx_ac97_pcm_prepare,
|
||||
.trigger = pxa2xx_pcm_trigger,
|
||||
.pointer = pxa2xx_pcm_pointer,
|
||||
.mmap = pxa2xx_pcm_mmap,
|
||||
};
|
||||
|
||||
|
||||
static int pxa2xx_ac97_pcm_new(struct snd_card *card)
|
||||
{
|
||||
struct snd_pcm *pcm;
|
||||
int stream, ret;
|
||||
|
||||
ret = snd_pcm_new(card, "PXA2xx-PCM", 0, 1, 1, &pcm);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
pcm->private_free = pxa2xx_pcm_free_dma_buffers;
|
||||
|
||||
ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
stream = SNDRV_PCM_STREAM_PLAYBACK;
|
||||
snd_pcm_set_ops(pcm, stream, &pxa2xx_ac97_pcm_ops);
|
||||
ret = pxa2xx_pcm_preallocate_dma_buffer(pcm, stream);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
stream = SNDRV_PCM_STREAM_CAPTURE;
|
||||
snd_pcm_set_ops(pcm, stream, &pxa2xx_ac97_pcm_ops);
|
||||
ret = pxa2xx_pcm_preallocate_dma_buffer(pcm, stream);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
pxa2xx_ac97_pcm = pcm;
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pxa2xx_ac97_probe(struct platform_device *dev)
|
||||
{
|
||||
struct snd_card *card;
|
||||
@@ -214,7 +242,7 @@ static int pxa2xx_ac97_probe(struct platform_device *dev)
|
||||
|
||||
strlcpy(card->driver, dev->dev.driver->name, sizeof(card->driver));
|
||||
|
||||
ret = pxa2xx_pcm_new(card, &pxa2xx_ac97_pcm_client, &pxa2xx_ac97_pcm);
|
||||
ret = pxa2xx_ac97_pcm_new(card);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
|
@@ -16,8 +16,6 @@
|
||||
#include <sound/pxa2xx-lib.h>
|
||||
#include <sound/dmaengine_pcm.h>
|
||||
|
||||
#include "pxa2xx-pcm.h"
|
||||
|
||||
static const struct snd_pcm_hardware pxa2xx_pcm_hardware = {
|
||||
.info = SNDRV_PCM_INFO_MMAP |
|
||||
SNDRV_PCM_INFO_MMAP_VALID |
|
||||
@@ -25,8 +23,8 @@ static const struct snd_pcm_hardware pxa2xx_pcm_hardware = {
|
||||
SNDRV_PCM_INFO_PAUSE |
|
||||
SNDRV_PCM_INFO_RESUME,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S24_LE |
|
||||
SNDRV_PCM_FMTBIT_S32_LE,
|
||||
SNDRV_PCM_FMTBIT_S24_LE |
|
||||
SNDRV_PCM_FMTBIT_S32_LE,
|
||||
.period_bytes_min = 32,
|
||||
.period_bytes_max = 8192 - 32,
|
||||
.periods_min = 1,
|
||||
@@ -35,8 +33,8 @@ static const struct snd_pcm_hardware pxa2xx_pcm_hardware = {
|
||||
.fifo_size = 32,
|
||||
};
|
||||
|
||||
int __pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream);
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
@@ -64,14 +62,14 @@ int __pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(__pxa2xx_pcm_hw_params);
|
||||
EXPORT_SYMBOL(pxa2xx_pcm_hw_params);
|
||||
|
||||
int __pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream)
|
||||
int pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream)
|
||||
{
|
||||
snd_pcm_set_runtime_buffer(substream, NULL);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(__pxa2xx_pcm_hw_free);
|
||||
EXPORT_SYMBOL(pxa2xx_pcm_hw_free);
|
||||
|
||||
int pxa2xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
{
|
||||
@@ -86,13 +84,13 @@ pxa2xx_pcm_pointer(struct snd_pcm_substream *substream)
|
||||
}
|
||||
EXPORT_SYMBOL(pxa2xx_pcm_pointer);
|
||||
|
||||
int __pxa2xx_pcm_prepare(struct snd_pcm_substream *substream)
|
||||
int pxa2xx_pcm_prepare(struct snd_pcm_substream *substream)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(__pxa2xx_pcm_prepare);
|
||||
EXPORT_SYMBOL(pxa2xx_pcm_prepare);
|
||||
|
||||
int __pxa2xx_pcm_open(struct snd_pcm_substream *substream)
|
||||
int pxa2xx_pcm_open(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
@@ -125,17 +123,17 @@ int __pxa2xx_pcm_open(struct snd_pcm_substream *substream)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return snd_dmaengine_pcm_open_request_chan(substream,
|
||||
pxad_filter_fn,
|
||||
dma_params->filter_data);
|
||||
return snd_dmaengine_pcm_open(
|
||||
substream, dma_request_slave_channel(rtd->cpu_dai->dev,
|
||||
dma_params->chan_name));
|
||||
}
|
||||
EXPORT_SYMBOL(__pxa2xx_pcm_open);
|
||||
EXPORT_SYMBOL(pxa2xx_pcm_open);
|
||||
|
||||
int __pxa2xx_pcm_close(struct snd_pcm_substream *substream)
|
||||
int pxa2xx_pcm_close(struct snd_pcm_substream *substream)
|
||||
{
|
||||
return snd_dmaengine_pcm_close_release_chan(substream);
|
||||
}
|
||||
EXPORT_SYMBOL(__pxa2xx_pcm_close);
|
||||
EXPORT_SYMBOL(pxa2xx_pcm_close);
|
||||
|
||||
int pxa2xx_pcm_mmap(struct snd_pcm_substream *substream,
|
||||
struct vm_area_struct *vma)
|
||||
@@ -181,6 +179,47 @@ void pxa2xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
|
||||
}
|
||||
EXPORT_SYMBOL(pxa2xx_pcm_free_dma_buffers);
|
||||
|
||||
int pxa2xx_soc_pcm_new(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_card *card = rtd->card->snd_card;
|
||||
struct snd_pcm *pcm = rtd->pcm;
|
||||
int ret;
|
||||
|
||||
ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
|
||||
ret = pxa2xx_pcm_preallocate_dma_buffer(pcm,
|
||||
SNDRV_PCM_STREAM_PLAYBACK);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
|
||||
ret = pxa2xx_pcm_preallocate_dma_buffer(pcm,
|
||||
SNDRV_PCM_STREAM_CAPTURE);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(pxa2xx_soc_pcm_new);
|
||||
|
||||
const struct snd_pcm_ops pxa2xx_pcm_ops = {
|
||||
.open = pxa2xx_pcm_open,
|
||||
.close = pxa2xx_pcm_close,
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.hw_params = pxa2xx_pcm_hw_params,
|
||||
.hw_free = pxa2xx_pcm_hw_free,
|
||||
.prepare = pxa2xx_pcm_prepare,
|
||||
.trigger = pxa2xx_pcm_trigger,
|
||||
.pointer = pxa2xx_pcm_pointer,
|
||||
.mmap = pxa2xx_pcm_mmap,
|
||||
};
|
||||
EXPORT_SYMBOL(pxa2xx_pcm_ops);
|
||||
|
||||
MODULE_AUTHOR("Nicolas Pitre");
|
||||
MODULE_DESCRIPTION("Intel PXA2xx sound library");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@@ -1,129 +0,0 @@
|
||||
/*
|
||||
* linux/sound/arm/pxa2xx-pcm.c -- ALSA PCM interface for the Intel PXA2xx chip
|
||||
*
|
||||
* Author: Nicolas Pitre
|
||||
* Created: Nov 30, 2004
|
||||
* Copyright: (C) 2004 MontaVista Software, Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/dmaengine.h>
|
||||
|
||||
#include <mach/dma.h>
|
||||
|
||||
#include <sound/core.h>
|
||||
#include <sound/pxa2xx-lib.h>
|
||||
#include <sound/dmaengine_pcm.h>
|
||||
|
||||
#include "pxa2xx-pcm.h"
|
||||
|
||||
static int pxa2xx_pcm_prepare(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct pxa2xx_pcm_client *client = substream->private_data;
|
||||
|
||||
__pxa2xx_pcm_prepare(substream);
|
||||
|
||||
return client->prepare(substream);
|
||||
}
|
||||
|
||||
static int pxa2xx_pcm_open(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct pxa2xx_pcm_client *client = substream->private_data;
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct pxa2xx_runtime_data *rtd;
|
||||
int ret;
|
||||
|
||||
ret = __pxa2xx_pcm_open(substream);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
rtd = runtime->private_data;
|
||||
|
||||
rtd->params = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
|
||||
client->playback_params : client->capture_params;
|
||||
|
||||
ret = client->startup(substream);
|
||||
if (!ret)
|
||||
goto err2;
|
||||
|
||||
return 0;
|
||||
|
||||
err2:
|
||||
__pxa2xx_pcm_close(substream);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pxa2xx_pcm_close(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct pxa2xx_pcm_client *client = substream->private_data;
|
||||
|
||||
client->shutdown(substream);
|
||||
|
||||
return __pxa2xx_pcm_close(substream);
|
||||
}
|
||||
|
||||
static const struct snd_pcm_ops pxa2xx_pcm_ops = {
|
||||
.open = pxa2xx_pcm_open,
|
||||
.close = pxa2xx_pcm_close,
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.hw_params = __pxa2xx_pcm_hw_params,
|
||||
.hw_free = __pxa2xx_pcm_hw_free,
|
||||
.prepare = pxa2xx_pcm_prepare,
|
||||
.trigger = pxa2xx_pcm_trigger,
|
||||
.pointer = pxa2xx_pcm_pointer,
|
||||
.mmap = pxa2xx_pcm_mmap,
|
||||
};
|
||||
|
||||
int pxa2xx_pcm_new(struct snd_card *card, struct pxa2xx_pcm_client *client,
|
||||
struct snd_pcm **rpcm)
|
||||
{
|
||||
struct snd_pcm *pcm;
|
||||
int play = client->playback_params ? 1 : 0;
|
||||
int capt = client->capture_params ? 1 : 0;
|
||||
int ret;
|
||||
|
||||
ret = snd_pcm_new(card, "PXA2xx-PCM", 0, play, capt, &pcm);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
pcm->private_data = client;
|
||||
pcm->private_free = pxa2xx_pcm_free_dma_buffers;
|
||||
|
||||
ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
if (play) {
|
||||
int stream = SNDRV_PCM_STREAM_PLAYBACK;
|
||||
snd_pcm_set_ops(pcm, stream, &pxa2xx_pcm_ops);
|
||||
ret = pxa2xx_pcm_preallocate_dma_buffer(pcm, stream);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
if (capt) {
|
||||
int stream = SNDRV_PCM_STREAM_CAPTURE;
|
||||
snd_pcm_set_ops(pcm, stream, &pxa2xx_pcm_ops);
|
||||
ret = pxa2xx_pcm_preallocate_dma_buffer(pcm, stream);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (rpcm)
|
||||
*rpcm = pcm;
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(pxa2xx_pcm_new);
|
||||
|
||||
MODULE_AUTHOR("Nicolas Pitre");
|
||||
MODULE_DESCRIPTION("Intel PXA2xx PCM DMA module");
|
||||
MODULE_LICENSE("GPL");
|
@@ -1,27 +0,0 @@
|
||||
/*
|
||||
* linux/sound/arm/pxa2xx-pcm.h -- ALSA PCM interface for the Intel PXA2xx chip
|
||||
*
|
||||
* Author: Nicolas Pitre
|
||||
* Created: Nov 30, 2004
|
||||
* Copyright: MontaVista Software, Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
struct pxa2xx_runtime_data {
|
||||
int dma_ch;
|
||||
struct snd_dmaengine_dai_dma_data *params;
|
||||
};
|
||||
|
||||
struct pxa2xx_pcm_client {
|
||||
struct snd_dmaengine_dai_dma_data *playback_params;
|
||||
struct snd_dmaengine_dai_dma_data *capture_params;
|
||||
int (*startup)(struct snd_pcm_substream *);
|
||||
void (*shutdown)(struct snd_pcm_substream *);
|
||||
int (*prepare)(struct snd_pcm_substream *);
|
||||
};
|
||||
|
||||
extern int pxa2xx_pcm_new(struct snd_card *, struct pxa2xx_pcm_client *, struct snd_pcm **);
|
||||
|
@@ -5,11 +5,12 @@ config SND_HDA_CORE
|
||||
config SND_HDA_DSP_LOADER
|
||||
bool
|
||||
|
||||
config SND_HDA_COMPONENT
|
||||
bool
|
||||
|
||||
config SND_HDA_I915
|
||||
bool
|
||||
default y
|
||||
depends on DRM_I915
|
||||
depends on SND_HDA_CORE
|
||||
select SND_HDA_COMPONENT
|
||||
|
||||
config SND_HDA_EXT_CORE
|
||||
tristate
|
||||
|
@@ -6,6 +6,7 @@ snd-hda-core-objs += trace.o
|
||||
CFLAGS_trace.o := -I$(src)
|
||||
|
||||
# for sync with i915 gfx driver
|
||||
snd-hda-core-$(CONFIG_SND_HDA_COMPONENT) += hdac_component.o
|
||||
snd-hda-core-$(CONFIG_SND_HDA_I915) += hdac_i915.o
|
||||
|
||||
obj-$(CONFIG_SND_HDA_CORE) += snd-hda-core.o
|
||||
|
@@ -87,9 +87,10 @@ static const struct hdac_io_ops hdac_ext_default_io = {
|
||||
*
|
||||
* Returns 0 if successful, or a negative error code.
|
||||
*/
|
||||
int snd_hdac_ext_bus_init(struct hdac_ext_bus *ebus, struct device *dev,
|
||||
int snd_hdac_ext_bus_init(struct hdac_bus *bus, struct device *dev,
|
||||
const struct hdac_bus_ops *ops,
|
||||
const struct hdac_io_ops *io_ops)
|
||||
const struct hdac_io_ops *io_ops,
|
||||
const struct hdac_ext_bus_ops *ext_ops)
|
||||
{
|
||||
int ret;
|
||||
static int idx;
|
||||
@@ -98,15 +99,16 @@ int snd_hdac_ext_bus_init(struct hdac_ext_bus *ebus, struct device *dev,
|
||||
if (io_ops == NULL)
|
||||
io_ops = &hdac_ext_default_io;
|
||||
|
||||
ret = snd_hdac_bus_init(&ebus->bus, dev, ops, io_ops);
|
||||
ret = snd_hdac_bus_init(bus, dev, ops, io_ops);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
INIT_LIST_HEAD(&ebus->hlink_list);
|
||||
ebus->idx = idx++;
|
||||
bus->ext_ops = ext_ops;
|
||||
INIT_LIST_HEAD(&bus->hlink_list);
|
||||
bus->idx = idx++;
|
||||
|
||||
mutex_init(&ebus->lock);
|
||||
ebus->cmd_dma_state = true;
|
||||
mutex_init(&bus->lock);
|
||||
bus->cmd_dma_state = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -116,10 +118,10 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_init);
|
||||
* snd_hdac_ext_bus_exit - clean up a HD-audio extended bus
|
||||
* @ebus: the pointer to extended bus object
|
||||
*/
|
||||
void snd_hdac_ext_bus_exit(struct hdac_ext_bus *ebus)
|
||||
void snd_hdac_ext_bus_exit(struct hdac_bus *bus)
|
||||
{
|
||||
snd_hdac_bus_exit(&ebus->bus);
|
||||
WARN_ON(!list_empty(&ebus->hlink_list));
|
||||
snd_hdac_bus_exit(bus);
|
||||
WARN_ON(!list_empty(&bus->hlink_list));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_exit);
|
||||
|
||||
@@ -135,21 +137,15 @@ static void default_release(struct device *dev)
|
||||
*
|
||||
* Returns zero for success or a negative error code.
|
||||
*/
|
||||
int snd_hdac_ext_bus_device_init(struct hdac_ext_bus *ebus, int addr)
|
||||
int snd_hdac_ext_bus_device_init(struct hdac_bus *bus, int addr,
|
||||
struct hdac_device *hdev)
|
||||
{
|
||||
struct hdac_ext_device *edev;
|
||||
struct hdac_device *hdev = NULL;
|
||||
struct hdac_bus *bus = ebus_to_hbus(ebus);
|
||||
char name[15];
|
||||
int ret;
|
||||
|
||||
edev = kzalloc(sizeof(*edev), GFP_KERNEL);
|
||||
if (!edev)
|
||||
return -ENOMEM;
|
||||
hdev = &edev->hdev;
|
||||
edev->ebus = ebus;
|
||||
hdev->bus = bus;
|
||||
|
||||
snprintf(name, sizeof(name), "ehdaudio%dD%d", ebus->idx, addr);
|
||||
snprintf(name, sizeof(name), "ehdaudio%dD%d", bus->idx, addr);
|
||||
|
||||
ret = snd_hdac_device_init(hdev, bus, name, addr);
|
||||
if (ret < 0) {
|
||||
@@ -176,10 +172,8 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_device_init);
|
||||
*/
|
||||
void snd_hdac_ext_bus_device_exit(struct hdac_device *hdev)
|
||||
{
|
||||
struct hdac_ext_device *edev = to_ehdac_device(hdev);
|
||||
|
||||
snd_hdac_device_exit(hdev);
|
||||
kfree(edev);
|
||||
kfree(hdev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_device_exit);
|
||||
|
||||
@@ -188,14 +182,14 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_device_exit);
|
||||
*
|
||||
* @ebus: HD-audio extended bus
|
||||
*/
|
||||
void snd_hdac_ext_bus_device_remove(struct hdac_ext_bus *ebus)
|
||||
void snd_hdac_ext_bus_device_remove(struct hdac_bus *bus)
|
||||
{
|
||||
struct hdac_device *codec, *__codec;
|
||||
/*
|
||||
* we need to remove all the codec devices objects created in the
|
||||
* snd_hdac_ext_bus_device_init
|
||||
*/
|
||||
list_for_each_entry_safe(codec, __codec, &ebus->bus.codec_list, list) {
|
||||
list_for_each_entry_safe(codec, __codec, &bus->codec_list, list) {
|
||||
snd_hdac_device_unregister(codec);
|
||||
put_device(&codec->dev);
|
||||
}
|
||||
@@ -204,35 +198,31 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_device_remove);
|
||||
#define dev_to_hdac(dev) (container_of((dev), \
|
||||
struct hdac_device, dev))
|
||||
|
||||
static inline struct hdac_ext_driver *get_edrv(struct device *dev)
|
||||
static inline struct hdac_driver *get_hdrv(struct device *dev)
|
||||
{
|
||||
struct hdac_driver *hdrv = drv_to_hdac_driver(dev->driver);
|
||||
struct hdac_ext_driver *edrv = to_ehdac_driver(hdrv);
|
||||
|
||||
return edrv;
|
||||
return hdrv;
|
||||
}
|
||||
|
||||
static inline struct hdac_ext_device *get_edev(struct device *dev)
|
||||
static inline struct hdac_device *get_hdev(struct device *dev)
|
||||
{
|
||||
struct hdac_device *hdev = dev_to_hdac_dev(dev);
|
||||
struct hdac_ext_device *edev = to_ehdac_device(hdev);
|
||||
|
||||
return edev;
|
||||
return hdev;
|
||||
}
|
||||
|
||||
static int hda_ext_drv_probe(struct device *dev)
|
||||
{
|
||||
return (get_edrv(dev))->probe(get_edev(dev));
|
||||
return (get_hdrv(dev))->probe(get_hdev(dev));
|
||||
}
|
||||
|
||||
static int hdac_ext_drv_remove(struct device *dev)
|
||||
{
|
||||
return (get_edrv(dev))->remove(get_edev(dev));
|
||||
return (get_hdrv(dev))->remove(get_hdev(dev));
|
||||
}
|
||||
|
||||
static void hdac_ext_drv_shutdown(struct device *dev)
|
||||
{
|
||||
return (get_edrv(dev))->shutdown(get_edev(dev));
|
||||
return (get_hdrv(dev))->shutdown(get_hdev(dev));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -240,20 +230,20 @@ static void hdac_ext_drv_shutdown(struct device *dev)
|
||||
*
|
||||
* @drv: ext hda driver structure
|
||||
*/
|
||||
int snd_hda_ext_driver_register(struct hdac_ext_driver *drv)
|
||||
int snd_hda_ext_driver_register(struct hdac_driver *drv)
|
||||
{
|
||||
drv->hdac.type = HDA_DEV_ASOC;
|
||||
drv->hdac.driver.bus = &snd_hda_bus_type;
|
||||
drv->type = HDA_DEV_ASOC;
|
||||
drv->driver.bus = &snd_hda_bus_type;
|
||||
/* we use default match */
|
||||
|
||||
if (drv->probe)
|
||||
drv->hdac.driver.probe = hda_ext_drv_probe;
|
||||
drv->driver.probe = hda_ext_drv_probe;
|
||||
if (drv->remove)
|
||||
drv->hdac.driver.remove = hdac_ext_drv_remove;
|
||||
drv->driver.remove = hdac_ext_drv_remove;
|
||||
if (drv->shutdown)
|
||||
drv->hdac.driver.shutdown = hdac_ext_drv_shutdown;
|
||||
drv->driver.shutdown = hdac_ext_drv_shutdown;
|
||||
|
||||
return driver_register(&drv->hdac.driver);
|
||||
return driver_register(&drv->driver);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hda_ext_driver_register);
|
||||
|
||||
@@ -262,8 +252,8 @@ EXPORT_SYMBOL_GPL(snd_hda_ext_driver_register);
|
||||
*
|
||||
* @drv: ext hda driver structure
|
||||
*/
|
||||
void snd_hda_ext_driver_unregister(struct hdac_ext_driver *drv)
|
||||
void snd_hda_ext_driver_unregister(struct hdac_driver *drv)
|
||||
{
|
||||
driver_unregister(&drv->hdac.driver);
|
||||
driver_unregister(&drv->driver);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hda_ext_driver_unregister);
|
||||
|
@@ -39,9 +39,8 @@
|
||||
* @ebus: HD-audio extended core bus
|
||||
* @enable: flag to turn on/off the capability
|
||||
*/
|
||||
void snd_hdac_ext_bus_ppcap_enable(struct hdac_ext_bus *ebus, bool enable)
|
||||
void snd_hdac_ext_bus_ppcap_enable(struct hdac_bus *bus, bool enable)
|
||||
{
|
||||
struct hdac_bus *bus = &ebus->bus;
|
||||
|
||||
if (!bus->ppcap) {
|
||||
dev_err(bus->dev, "Address of PP capability is NULL");
|
||||
@@ -60,9 +59,8 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_ppcap_enable);
|
||||
* @ebus: HD-audio extended core bus
|
||||
* @enable: flag to enable/disable interrupt
|
||||
*/
|
||||
void snd_hdac_ext_bus_ppcap_int_enable(struct hdac_ext_bus *ebus, bool enable)
|
||||
void snd_hdac_ext_bus_ppcap_int_enable(struct hdac_bus *bus, bool enable)
|
||||
{
|
||||
struct hdac_bus *bus = &ebus->bus;
|
||||
|
||||
if (!bus->ppcap) {
|
||||
dev_err(bus->dev, "Address of PP capability is NULL\n");
|
||||
@@ -89,12 +87,11 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_ppcap_int_enable);
|
||||
* in hlink_list of extended hdac bus
|
||||
* Note: this will be freed on bus exit by driver
|
||||
*/
|
||||
int snd_hdac_ext_bus_get_ml_capabilities(struct hdac_ext_bus *ebus)
|
||||
int snd_hdac_ext_bus_get_ml_capabilities(struct hdac_bus *bus)
|
||||
{
|
||||
int idx;
|
||||
u32 link_count;
|
||||
struct hdac_ext_link *hlink;
|
||||
struct hdac_bus *bus = &ebus->bus;
|
||||
|
||||
link_count = readl(bus->mlcap + AZX_REG_ML_MLCD) + 1;
|
||||
|
||||
@@ -114,7 +111,7 @@ int snd_hdac_ext_bus_get_ml_capabilities(struct hdac_ext_bus *ebus)
|
||||
/* since link in On, update the ref */
|
||||
hlink->ref_count = 1;
|
||||
|
||||
list_add_tail(&hlink->list, &ebus->hlink_list);
|
||||
list_add_tail(&hlink->list, &bus->hlink_list);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -127,12 +124,12 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_get_ml_capabilities);
|
||||
* @ebus: HD-audio ext core bus
|
||||
*/
|
||||
|
||||
void snd_hdac_link_free_all(struct hdac_ext_bus *ebus)
|
||||
void snd_hdac_link_free_all(struct hdac_bus *bus)
|
||||
{
|
||||
struct hdac_ext_link *l;
|
||||
|
||||
while (!list_empty(&ebus->hlink_list)) {
|
||||
l = list_first_entry(&ebus->hlink_list, struct hdac_ext_link, list);
|
||||
while (!list_empty(&bus->hlink_list)) {
|
||||
l = list_first_entry(&bus->hlink_list, struct hdac_ext_link, list);
|
||||
list_del(&l->list);
|
||||
kfree(l);
|
||||
}
|
||||
@@ -144,7 +141,7 @@ EXPORT_SYMBOL_GPL(snd_hdac_link_free_all);
|
||||
* @ebus: HD-audio extended core bus
|
||||
* @codec_name: codec name
|
||||
*/
|
||||
struct hdac_ext_link *snd_hdac_ext_bus_get_link(struct hdac_ext_bus *ebus,
|
||||
struct hdac_ext_link *snd_hdac_ext_bus_get_link(struct hdac_bus *bus,
|
||||
const char *codec_name)
|
||||
{
|
||||
int i;
|
||||
@@ -153,10 +150,10 @@ struct hdac_ext_link *snd_hdac_ext_bus_get_link(struct hdac_ext_bus *ebus,
|
||||
|
||||
if (sscanf(codec_name, "ehdaudio%dD%d", &bus_idx, &addr) != 2)
|
||||
return NULL;
|
||||
if (ebus->idx != bus_idx)
|
||||
if (bus->idx != bus_idx)
|
||||
return NULL;
|
||||
|
||||
list_for_each_entry(hlink, &ebus->hlink_list, list) {
|
||||
list_for_each_entry(hlink, &bus->hlink_list, list) {
|
||||
for (i = 0; i < HDA_MAX_CODECS; i++) {
|
||||
if (hlink->lsdiid & (0x1 << addr))
|
||||
return hlink;
|
||||
@@ -219,12 +216,12 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_down);
|
||||
* snd_hdac_ext_bus_link_power_up_all -power up all hda link
|
||||
* @ebus: HD-audio extended bus
|
||||
*/
|
||||
int snd_hdac_ext_bus_link_power_up_all(struct hdac_ext_bus *ebus)
|
||||
int snd_hdac_ext_bus_link_power_up_all(struct hdac_bus *bus)
|
||||
{
|
||||
struct hdac_ext_link *hlink = NULL;
|
||||
int ret;
|
||||
|
||||
list_for_each_entry(hlink, &ebus->hlink_list, list) {
|
||||
list_for_each_entry(hlink, &bus->hlink_list, list) {
|
||||
snd_hdac_updatel(hlink->ml_addr,
|
||||
AZX_REG_ML_LCTL, 0, AZX_MLCTL_SPA);
|
||||
ret = check_hdac_link_power_active(hlink, true);
|
||||
@@ -240,12 +237,12 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_up_all);
|
||||
* snd_hdac_ext_bus_link_power_down_all -power down all hda link
|
||||
* @ebus: HD-audio extended bus
|
||||
*/
|
||||
int snd_hdac_ext_bus_link_power_down_all(struct hdac_ext_bus *ebus)
|
||||
int snd_hdac_ext_bus_link_power_down_all(struct hdac_bus *bus)
|
||||
{
|
||||
struct hdac_ext_link *hlink = NULL;
|
||||
int ret;
|
||||
|
||||
list_for_each_entry(hlink, &ebus->hlink_list, list) {
|
||||
list_for_each_entry(hlink, &bus->hlink_list, list) {
|
||||
snd_hdac_updatel(hlink->ml_addr, AZX_REG_ML_LCTL, AZX_MLCTL_SPA, 0);
|
||||
ret = check_hdac_link_power_active(hlink, false);
|
||||
if (ret < 0)
|
||||
@@ -256,39 +253,48 @@ int snd_hdac_ext_bus_link_power_down_all(struct hdac_ext_bus *ebus)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_down_all);
|
||||
|
||||
int snd_hdac_ext_bus_link_get(struct hdac_ext_bus *ebus,
|
||||
int snd_hdac_ext_bus_link_get(struct hdac_bus *bus,
|
||||
struct hdac_ext_link *link)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&ebus->lock);
|
||||
mutex_lock(&bus->lock);
|
||||
|
||||
/*
|
||||
* if we move from 0 to 1, count will be 1 so power up this link
|
||||
* as well, also check the dma status and trigger that
|
||||
*/
|
||||
if (++link->ref_count == 1) {
|
||||
if (!ebus->cmd_dma_state) {
|
||||
snd_hdac_bus_init_cmd_io(&ebus->bus);
|
||||
ebus->cmd_dma_state = true;
|
||||
if (!bus->cmd_dma_state) {
|
||||
snd_hdac_bus_init_cmd_io(bus);
|
||||
bus->cmd_dma_state = true;
|
||||
}
|
||||
|
||||
ret = snd_hdac_ext_bus_link_power_up(link);
|
||||
|
||||
/*
|
||||
* wait for 521usec for codec to report status
|
||||
* HDA spec section 4.3 - Codec Discovery
|
||||
*/
|
||||
udelay(521);
|
||||
bus->codec_mask = snd_hdac_chip_readw(bus, STATESTS);
|
||||
dev_dbg(bus->dev, "codec_mask = 0x%lx\n", bus->codec_mask);
|
||||
snd_hdac_chip_writew(bus, STATESTS, bus->codec_mask);
|
||||
}
|
||||
|
||||
mutex_unlock(&ebus->lock);
|
||||
mutex_unlock(&bus->lock);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_get);
|
||||
|
||||
int snd_hdac_ext_bus_link_put(struct hdac_ext_bus *ebus,
|
||||
int snd_hdac_ext_bus_link_put(struct hdac_bus *bus,
|
||||
struct hdac_ext_link *link)
|
||||
{
|
||||
int ret = 0;
|
||||
struct hdac_ext_link *hlink;
|
||||
bool link_up = false;
|
||||
|
||||
mutex_lock(&ebus->lock);
|
||||
mutex_lock(&bus->lock);
|
||||
|
||||
/*
|
||||
* if we move from 1 to 0, count will be 0
|
||||
@@ -301,7 +307,7 @@ int snd_hdac_ext_bus_link_put(struct hdac_ext_bus *ebus,
|
||||
* now check if all links are off, if so turn off
|
||||
* cmd dma as well
|
||||
*/
|
||||
list_for_each_entry(hlink, &ebus->hlink_list, list) {
|
||||
list_for_each_entry(hlink, &bus->hlink_list, list) {
|
||||
if (hlink->ref_count) {
|
||||
link_up = true;
|
||||
break;
|
||||
@@ -309,12 +315,12 @@ int snd_hdac_ext_bus_link_put(struct hdac_ext_bus *ebus,
|
||||
}
|
||||
|
||||
if (!link_up) {
|
||||
snd_hdac_bus_stop_cmd_io(&ebus->bus);
|
||||
ebus->cmd_dma_state = false;
|
||||
snd_hdac_bus_stop_cmd_io(bus);
|
||||
bus->cmd_dma_state = false;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&ebus->lock);
|
||||
mutex_unlock(&bus->lock);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_put);
|
||||
|
@@ -25,7 +25,7 @@
|
||||
|
||||
/**
|
||||
* snd_hdac_ext_stream_init - initialize each stream (aka device)
|
||||
* @ebus: HD-audio ext core bus
|
||||
* @bus: HD-audio core bus
|
||||
* @stream: HD-audio ext core stream object to initialize
|
||||
* @idx: stream index number
|
||||
* @direction: stream direction (SNDRV_PCM_STREAM_PLAYBACK or SNDRV_PCM_STREAM_CAPTURE)
|
||||
@@ -34,18 +34,16 @@
|
||||
* initialize the stream, if ppcap is enabled then init those and then
|
||||
* invoke hdac stream initialization routine
|
||||
*/
|
||||
void snd_hdac_ext_stream_init(struct hdac_ext_bus *ebus,
|
||||
void snd_hdac_ext_stream_init(struct hdac_bus *bus,
|
||||
struct hdac_ext_stream *stream,
|
||||
int idx, int direction, int tag)
|
||||
{
|
||||
struct hdac_bus *bus = &ebus->bus;
|
||||
|
||||
if (bus->ppcap) {
|
||||
stream->pphc_addr = bus->ppcap + AZX_PPHC_BASE +
|
||||
AZX_PPHC_INTERVAL * idx;
|
||||
|
||||
stream->pplc_addr = bus->ppcap + AZX_PPLC_BASE +
|
||||
AZX_PPLC_MULTI * ebus->num_streams +
|
||||
AZX_PPLC_MULTI * bus->num_streams +
|
||||
AZX_PPLC_INTERVAL * idx;
|
||||
}
|
||||
|
||||
@@ -71,12 +69,12 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_init);
|
||||
/**
|
||||
* snd_hdac_ext_stream_init_all - create and initialize the stream objects
|
||||
* for an extended hda bus
|
||||
* @ebus: HD-audio ext core bus
|
||||
* @bus: HD-audio core bus
|
||||
* @start_idx: start index for streams
|
||||
* @num_stream: number of streams to initialize
|
||||
* @dir: direction of streams
|
||||
*/
|
||||
int snd_hdac_ext_stream_init_all(struct hdac_ext_bus *ebus, int start_idx,
|
||||
int snd_hdac_ext_stream_init_all(struct hdac_bus *bus, int start_idx,
|
||||
int num_stream, int dir)
|
||||
{
|
||||
int stream_tag = 0;
|
||||
@@ -88,7 +86,7 @@ int snd_hdac_ext_stream_init_all(struct hdac_ext_bus *ebus, int start_idx,
|
||||
if (!stream)
|
||||
return -ENOMEM;
|
||||
tag = ++stream_tag;
|
||||
snd_hdac_ext_stream_init(ebus, stream, idx, dir, tag);
|
||||
snd_hdac_ext_stream_init(bus, stream, idx, dir, tag);
|
||||
idx++;
|
||||
}
|
||||
|
||||
@@ -100,17 +98,16 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_init_all);
|
||||
/**
|
||||
* snd_hdac_stream_free_all - free hdac extended stream objects
|
||||
*
|
||||
* @ebus: HD-audio ext core bus
|
||||
* @bus: HD-audio core bus
|
||||
*/
|
||||
void snd_hdac_stream_free_all(struct hdac_ext_bus *ebus)
|
||||
void snd_hdac_stream_free_all(struct hdac_bus *bus)
|
||||
{
|
||||
struct hdac_stream *s, *_s;
|
||||
struct hdac_ext_stream *stream;
|
||||
struct hdac_bus *bus = ebus_to_hbus(ebus);
|
||||
|
||||
list_for_each_entry_safe(s, _s, &bus->stream_list, list) {
|
||||
stream = stream_to_hdac_ext_stream(s);
|
||||
snd_hdac_ext_stream_decouple(ebus, stream, false);
|
||||
snd_hdac_ext_stream_decouple(bus, stream, false);
|
||||
list_del(&s->list);
|
||||
kfree(stream);
|
||||
}
|
||||
@@ -119,15 +116,14 @@ EXPORT_SYMBOL_GPL(snd_hdac_stream_free_all);
|
||||
|
||||
/**
|
||||
* snd_hdac_ext_stream_decouple - decouple the hdac stream
|
||||
* @ebus: HD-audio ext core bus
|
||||
* @bus: HD-audio core bus
|
||||
* @stream: HD-audio ext core stream object to initialize
|
||||
* @decouple: flag to decouple
|
||||
*/
|
||||
void snd_hdac_ext_stream_decouple(struct hdac_ext_bus *ebus,
|
||||
void snd_hdac_ext_stream_decouple(struct hdac_bus *bus,
|
||||
struct hdac_ext_stream *stream, bool decouple)
|
||||
{
|
||||
struct hdac_stream *hstream = &stream->hstream;
|
||||
struct hdac_bus *bus = &ebus->bus;
|
||||
u32 val;
|
||||
int mask = AZX_PPCTL_PROCEN(hstream->index);
|
||||
|
||||
@@ -251,19 +247,18 @@ void snd_hdac_ext_link_clear_stream_id(struct hdac_ext_link *link,
|
||||
EXPORT_SYMBOL_GPL(snd_hdac_ext_link_clear_stream_id);
|
||||
|
||||
static struct hdac_ext_stream *
|
||||
hdac_ext_link_stream_assign(struct hdac_ext_bus *ebus,
|
||||
hdac_ext_link_stream_assign(struct hdac_bus *bus,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct hdac_ext_stream *res = NULL;
|
||||
struct hdac_stream *stream = NULL;
|
||||
struct hdac_bus *hbus = &ebus->bus;
|
||||
|
||||
if (!hbus->ppcap) {
|
||||
dev_err(hbus->dev, "stream type not supported\n");
|
||||
if (!bus->ppcap) {
|
||||
dev_err(bus->dev, "stream type not supported\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list_for_each_entry(stream, &hbus->stream_list, list) {
|
||||
list_for_each_entry(stream, &bus->stream_list, list) {
|
||||
struct hdac_ext_stream *hstream = container_of(stream,
|
||||
struct hdac_ext_stream,
|
||||
hstream);
|
||||
@@ -277,34 +272,33 @@ hdac_ext_link_stream_assign(struct hdac_ext_bus *ebus,
|
||||
}
|
||||
|
||||
if (!hstream->link_locked) {
|
||||
snd_hdac_ext_stream_decouple(ebus, hstream, true);
|
||||
snd_hdac_ext_stream_decouple(bus, hstream, true);
|
||||
res = hstream;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (res) {
|
||||
spin_lock_irq(&hbus->reg_lock);
|
||||
spin_lock_irq(&bus->reg_lock);
|
||||
res->link_locked = 1;
|
||||
res->link_substream = substream;
|
||||
spin_unlock_irq(&hbus->reg_lock);
|
||||
spin_unlock_irq(&bus->reg_lock);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static struct hdac_ext_stream *
|
||||
hdac_ext_host_stream_assign(struct hdac_ext_bus *ebus,
|
||||
hdac_ext_host_stream_assign(struct hdac_bus *bus,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct hdac_ext_stream *res = NULL;
|
||||
struct hdac_stream *stream = NULL;
|
||||
struct hdac_bus *hbus = &ebus->bus;
|
||||
|
||||
if (!hbus->ppcap) {
|
||||
dev_err(hbus->dev, "stream type not supported\n");
|
||||
if (!bus->ppcap) {
|
||||
dev_err(bus->dev, "stream type not supported\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list_for_each_entry(stream, &hbus->stream_list, list) {
|
||||
list_for_each_entry(stream, &bus->stream_list, list) {
|
||||
struct hdac_ext_stream *hstream = container_of(stream,
|
||||
struct hdac_ext_stream,
|
||||
hstream);
|
||||
@@ -313,17 +307,17 @@ hdac_ext_host_stream_assign(struct hdac_ext_bus *ebus,
|
||||
|
||||
if (!stream->opened) {
|
||||
if (!hstream->decoupled)
|
||||
snd_hdac_ext_stream_decouple(ebus, hstream, true);
|
||||
snd_hdac_ext_stream_decouple(bus, hstream, true);
|
||||
res = hstream;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (res) {
|
||||
spin_lock_irq(&hbus->reg_lock);
|
||||
spin_lock_irq(&bus->reg_lock);
|
||||
res->hstream.opened = 1;
|
||||
res->hstream.running = 0;
|
||||
res->hstream.substream = substream;
|
||||
spin_unlock_irq(&hbus->reg_lock);
|
||||
spin_unlock_irq(&bus->reg_lock);
|
||||
}
|
||||
|
||||
return res;
|
||||
@@ -331,7 +325,7 @@ hdac_ext_host_stream_assign(struct hdac_ext_bus *ebus,
|
||||
|
||||
/**
|
||||
* snd_hdac_ext_stream_assign - assign a stream for the PCM
|
||||
* @ebus: HD-audio ext core bus
|
||||
* @bus: HD-audio core bus
|
||||
* @substream: PCM substream to assign
|
||||
* @type: type of stream (coupled, host or link stream)
|
||||
*
|
||||
@@ -346,27 +340,26 @@ hdac_ext_host_stream_assign(struct hdac_ext_bus *ebus,
|
||||
* the same stream object when it's used beforehand. when a stream is
|
||||
* decoupled, it becomes a host stream and link stream.
|
||||
*/
|
||||
struct hdac_ext_stream *snd_hdac_ext_stream_assign(struct hdac_ext_bus *ebus,
|
||||
struct hdac_ext_stream *snd_hdac_ext_stream_assign(struct hdac_bus *bus,
|
||||
struct snd_pcm_substream *substream,
|
||||
int type)
|
||||
{
|
||||
struct hdac_ext_stream *hstream = NULL;
|
||||
struct hdac_stream *stream = NULL;
|
||||
struct hdac_bus *hbus = &ebus->bus;
|
||||
|
||||
switch (type) {
|
||||
case HDAC_EXT_STREAM_TYPE_COUPLED:
|
||||
stream = snd_hdac_stream_assign(hbus, substream);
|
||||
stream = snd_hdac_stream_assign(bus, substream);
|
||||
if (stream)
|
||||
hstream = container_of(stream,
|
||||
struct hdac_ext_stream, hstream);
|
||||
return hstream;
|
||||
|
||||
case HDAC_EXT_STREAM_TYPE_HOST:
|
||||
return hdac_ext_host_stream_assign(ebus, substream);
|
||||
return hdac_ext_host_stream_assign(bus, substream);
|
||||
|
||||
case HDAC_EXT_STREAM_TYPE_LINK:
|
||||
return hdac_ext_link_stream_assign(ebus, substream);
|
||||
return hdac_ext_link_stream_assign(bus, substream);
|
||||
|
||||
default:
|
||||
return NULL;
|
||||
@@ -384,7 +377,6 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_assign);
|
||||
void snd_hdac_ext_stream_release(struct hdac_ext_stream *stream, int type)
|
||||
{
|
||||
struct hdac_bus *bus = stream->hstream.bus;
|
||||
struct hdac_ext_bus *ebus = hbus_to_ebus(bus);
|
||||
|
||||
switch (type) {
|
||||
case HDAC_EXT_STREAM_TYPE_COUPLED:
|
||||
@@ -393,13 +385,13 @@ void snd_hdac_ext_stream_release(struct hdac_ext_stream *stream, int type)
|
||||
|
||||
case HDAC_EXT_STREAM_TYPE_HOST:
|
||||
if (stream->decoupled && !stream->link_locked)
|
||||
snd_hdac_ext_stream_decouple(ebus, stream, false);
|
||||
snd_hdac_ext_stream_decouple(bus, stream, false);
|
||||
snd_hdac_stream_release(&stream->hstream);
|
||||
break;
|
||||
|
||||
case HDAC_EXT_STREAM_TYPE_LINK:
|
||||
if (stream->decoupled && !stream->hstream.opened)
|
||||
snd_hdac_ext_stream_decouple(ebus, stream, false);
|
||||
snd_hdac_ext_stream_decouple(bus, stream, false);
|
||||
spin_lock_irq(&bus->reg_lock);
|
||||
stream->link_locked = 0;
|
||||
stream->link_substream = NULL;
|
||||
@@ -415,16 +407,15 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_release);
|
||||
|
||||
/**
|
||||
* snd_hdac_ext_stream_spbcap_enable - enable SPIB for a stream
|
||||
* @ebus: HD-audio ext core bus
|
||||
* @bus: HD-audio core bus
|
||||
* @enable: flag to enable/disable SPIB
|
||||
* @index: stream index for which SPIB need to be enabled
|
||||
*/
|
||||
void snd_hdac_ext_stream_spbcap_enable(struct hdac_ext_bus *ebus,
|
||||
void snd_hdac_ext_stream_spbcap_enable(struct hdac_bus *bus,
|
||||
bool enable, int index)
|
||||
{
|
||||
u32 mask = 0;
|
||||
u32 register_mask = 0;
|
||||
struct hdac_bus *bus = &ebus->bus;
|
||||
|
||||
if (!bus->spbcap) {
|
||||
dev_err(bus->dev, "Address of SPB capability is NULL\n");
|
||||
@@ -446,14 +437,13 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_spbcap_enable);
|
||||
|
||||
/**
|
||||
* snd_hdac_ext_stream_set_spib - sets the spib value of a stream
|
||||
* @ebus: HD-audio ext core bus
|
||||
* @bus: HD-audio core bus
|
||||
* @stream: hdac_ext_stream
|
||||
* @value: spib value to set
|
||||
*/
|
||||
int snd_hdac_ext_stream_set_spib(struct hdac_ext_bus *ebus,
|
||||
int snd_hdac_ext_stream_set_spib(struct hdac_bus *bus,
|
||||
struct hdac_ext_stream *stream, u32 value)
|
||||
{
|
||||
struct hdac_bus *bus = &ebus->bus;
|
||||
|
||||
if (!bus->spbcap) {
|
||||
dev_err(bus->dev, "Address of SPB capability is NULL\n");
|
||||
@@ -468,15 +458,14 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_set_spib);
|
||||
|
||||
/**
|
||||
* snd_hdac_ext_stream_get_spbmaxfifo - gets the spib value of a stream
|
||||
* @ebus: HD-audio ext core bus
|
||||
* @bus: HD-audio core bus
|
||||
* @stream: hdac_ext_stream
|
||||
*
|
||||
* Return maxfifo for the stream
|
||||
*/
|
||||
int snd_hdac_ext_stream_get_spbmaxfifo(struct hdac_ext_bus *ebus,
|
||||
int snd_hdac_ext_stream_get_spbmaxfifo(struct hdac_bus *bus,
|
||||
struct hdac_ext_stream *stream)
|
||||
{
|
||||
struct hdac_bus *bus = &ebus->bus;
|
||||
|
||||
if (!bus->spbcap) {
|
||||
dev_err(bus->dev, "Address of SPB capability is NULL\n");
|
||||
@@ -490,11 +479,10 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_get_spbmaxfifo);
|
||||
|
||||
/**
|
||||
* snd_hdac_ext_stop_streams - stop all stream if running
|
||||
* @ebus: HD-audio ext core bus
|
||||
* @bus: HD-audio core bus
|
||||
*/
|
||||
void snd_hdac_ext_stop_streams(struct hdac_ext_bus *ebus)
|
||||
void snd_hdac_ext_stop_streams(struct hdac_bus *bus)
|
||||
{
|
||||
struct hdac_bus *bus = ebus_to_hbus(ebus);
|
||||
struct hdac_stream *stream;
|
||||
|
||||
if (bus->chip_init) {
|
||||
@@ -507,16 +495,15 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_stop_streams);
|
||||
|
||||
/**
|
||||
* snd_hdac_ext_stream_drsm_enable - enable DMA resume for a stream
|
||||
* @ebus: HD-audio ext core bus
|
||||
* @bus: HD-audio core bus
|
||||
* @enable: flag to enable/disable DRSM
|
||||
* @index: stream index for which DRSM need to be enabled
|
||||
*/
|
||||
void snd_hdac_ext_stream_drsm_enable(struct hdac_ext_bus *ebus,
|
||||
void snd_hdac_ext_stream_drsm_enable(struct hdac_bus *bus,
|
||||
bool enable, int index)
|
||||
{
|
||||
u32 mask = 0;
|
||||
u32 register_mask = 0;
|
||||
struct hdac_bus *bus = &ebus->bus;
|
||||
|
||||
if (!bus->drsmcap) {
|
||||
dev_err(bus->dev, "Address of DRSM capability is NULL\n");
|
||||
@@ -538,14 +525,13 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_drsm_enable);
|
||||
|
||||
/**
|
||||
* snd_hdac_ext_stream_set_dpibr - sets the dpibr value of a stream
|
||||
* @ebus: HD-audio ext core bus
|
||||
* @bus: HD-audio core bus
|
||||
* @stream: hdac_ext_stream
|
||||
* @value: dpib value to set
|
||||
*/
|
||||
int snd_hdac_ext_stream_set_dpibr(struct hdac_ext_bus *ebus,
|
||||
int snd_hdac_ext_stream_set_dpibr(struct hdac_bus *bus,
|
||||
struct hdac_ext_stream *stream, u32 value)
|
||||
{
|
||||
struct hdac_bus *bus = &ebus->bus;
|
||||
|
||||
if (!bus->drsmcap) {
|
||||
dev_err(bus->dev, "Address of DRSM capability is NULL\n");
|
||||
@@ -560,7 +546,7 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_set_dpibr);
|
||||
|
||||
/**
|
||||
* snd_hdac_ext_stream_set_lpib - sets the lpib value of a stream
|
||||
* @ebus: HD-audio ext core bus
|
||||
* @bus: HD-audio core bus
|
||||
* @stream: hdac_ext_stream
|
||||
* @value: lpib value to set
|
||||
*/
|
||||
|
335
sound/hda/hdac_component.c
Normal file
335
sound/hda/hdac_component.c
Normal file
@@ -0,0 +1,335 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// hdac_component.c - routines for sync between HD-A core and DRM driver
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/component.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/hdaudio.h>
|
||||
#include <sound/hda_component.h>
|
||||
#include <sound/hda_register.h>
|
||||
|
||||
static void hdac_acomp_release(struct device *dev, void *res)
|
||||
{
|
||||
}
|
||||
|
||||
static struct drm_audio_component *hdac_get_acomp(struct device *dev)
|
||||
{
|
||||
return devres_find(dev, hdac_acomp_release, NULL, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_hdac_set_codec_wakeup - Enable / disable HDMI/DP codec wakeup
|
||||
* @bus: HDA core bus
|
||||
* @enable: enable or disable the wakeup
|
||||
*
|
||||
* This function is supposed to be used only by a HD-audio controller
|
||||
* driver that needs the interaction with graphics driver.
|
||||
*
|
||||
* This function should be called during the chip reset, also called at
|
||||
* resume for updating STATESTS register read.
|
||||
*
|
||||
* Returns zero for success or a negative error code.
|
||||
*/
|
||||
int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable)
|
||||
{
|
||||
struct drm_audio_component *acomp = bus->audio_component;
|
||||
|
||||
if (!acomp || !acomp->ops)
|
||||
return -ENODEV;
|
||||
|
||||
if (!acomp->ops->codec_wake_override)
|
||||
return 0;
|
||||
|
||||
dev_dbg(bus->dev, "%s codec wakeup\n",
|
||||
enable ? "enable" : "disable");
|
||||
|
||||
acomp->ops->codec_wake_override(acomp->dev, enable);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hdac_set_codec_wakeup);
|
||||
|
||||
/**
|
||||
* snd_hdac_display_power - Power up / down the power refcount
|
||||
* @bus: HDA core bus
|
||||
* @enable: power up or down
|
||||
*
|
||||
* This function is supposed to be used only by a HD-audio controller
|
||||
* driver that needs the interaction with graphics driver.
|
||||
*
|
||||
* This function manages a refcount and calls the get_power() and
|
||||
* put_power() ops accordingly, toggling the codec wakeup, too.
|
||||
*
|
||||
* Returns zero for success or a negative error code.
|
||||
*/
|
||||
int snd_hdac_display_power(struct hdac_bus *bus, bool enable)
|
||||
{
|
||||
struct drm_audio_component *acomp = bus->audio_component;
|
||||
|
||||
if (!acomp || !acomp->ops)
|
||||
return -ENODEV;
|
||||
|
||||
dev_dbg(bus->dev, "display power %s\n",
|
||||
enable ? "enable" : "disable");
|
||||
|
||||
if (enable) {
|
||||
if (!bus->drm_power_refcount++) {
|
||||
if (acomp->ops->get_power)
|
||||
acomp->ops->get_power(acomp->dev);
|
||||
snd_hdac_set_codec_wakeup(bus, true);
|
||||
snd_hdac_set_codec_wakeup(bus, false);
|
||||
}
|
||||
} else {
|
||||
WARN_ON(!bus->drm_power_refcount);
|
||||
if (!--bus->drm_power_refcount)
|
||||
if (acomp->ops->put_power)
|
||||
acomp->ops->put_power(acomp->dev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hdac_display_power);
|
||||
|
||||
/**
|
||||
* snd_hdac_sync_audio_rate - Set N/CTS based on the sample rate
|
||||
* @codec: HDA codec
|
||||
* @nid: the pin widget NID
|
||||
* @dev_id: device identifier
|
||||
* @rate: the sample rate to set
|
||||
*
|
||||
* This function is supposed to be used only by a HD-audio controller
|
||||
* driver that needs the interaction with graphics driver.
|
||||
*
|
||||
* This function sets N/CTS value based on the given sample rate.
|
||||
* Returns zero for success, or a negative error code.
|
||||
*/
|
||||
int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid,
|
||||
int dev_id, int rate)
|
||||
{
|
||||
struct hdac_bus *bus = codec->bus;
|
||||
struct drm_audio_component *acomp = bus->audio_component;
|
||||
int port, pipe;
|
||||
|
||||
if (!acomp || !acomp->ops || !acomp->ops->sync_audio_rate)
|
||||
return -ENODEV;
|
||||
port = nid;
|
||||
if (acomp->audio_ops && acomp->audio_ops->pin2port) {
|
||||
port = acomp->audio_ops->pin2port(codec, nid);
|
||||
if (port < 0)
|
||||
return -EINVAL;
|
||||
}
|
||||
pipe = dev_id;
|
||||
return acomp->ops->sync_audio_rate(acomp->dev, port, pipe, rate);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hdac_sync_audio_rate);
|
||||
|
||||
/**
|
||||
* snd_hdac_acomp_get_eld - Get the audio state and ELD via component
|
||||
* @codec: HDA codec
|
||||
* @nid: the pin widget NID
|
||||
* @dev_id: device identifier
|
||||
* @audio_enabled: the pointer to store the current audio state
|
||||
* @buffer: the buffer pointer to store ELD bytes
|
||||
* @max_bytes: the max bytes to be stored on @buffer
|
||||
*
|
||||
* This function is supposed to be used only by a HD-audio controller
|
||||
* driver that needs the interaction with graphics driver.
|
||||
*
|
||||
* This function queries the current state of the audio on the given
|
||||
* digital port and fetches the ELD bytes onto the given buffer.
|
||||
* It returns the number of bytes for the total ELD data, zero for
|
||||
* invalid ELD, or a negative error code.
|
||||
*
|
||||
* The return size is the total bytes required for the whole ELD bytes,
|
||||
* thus it may be over @max_bytes. If it's over @max_bytes, it implies
|
||||
* that only a part of ELD bytes have been fetched.
|
||||
*/
|
||||
int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid, int dev_id,
|
||||
bool *audio_enabled, char *buffer, int max_bytes)
|
||||
{
|
||||
struct hdac_bus *bus = codec->bus;
|
||||
struct drm_audio_component *acomp = bus->audio_component;
|
||||
int port, pipe;
|
||||
|
||||
if (!acomp || !acomp->ops || !acomp->ops->get_eld)
|
||||
return -ENODEV;
|
||||
|
||||
port = nid;
|
||||
if (acomp->audio_ops && acomp->audio_ops->pin2port) {
|
||||
port = acomp->audio_ops->pin2port(codec, nid);
|
||||
if (port < 0)
|
||||
return -EINVAL;
|
||||
}
|
||||
pipe = dev_id;
|
||||
return acomp->ops->get_eld(acomp->dev, port, pipe, audio_enabled,
|
||||
buffer, max_bytes);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hdac_acomp_get_eld);
|
||||
|
||||
static int hdac_component_master_bind(struct device *dev)
|
||||
{
|
||||
struct drm_audio_component *acomp = hdac_get_acomp(dev);
|
||||
int ret;
|
||||
|
||||
if (WARN_ON(!acomp))
|
||||
return -EINVAL;
|
||||
|
||||
ret = component_bind_all(dev, acomp);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (WARN_ON(!(acomp->dev && acomp->ops))) {
|
||||
ret = -EINVAL;
|
||||
goto out_unbind;
|
||||
}
|
||||
|
||||
/* pin the module to avoid dynamic unbinding, but only if given */
|
||||
if (!try_module_get(acomp->ops->owner)) {
|
||||
ret = -ENODEV;
|
||||
goto out_unbind;
|
||||
}
|
||||
|
||||
if (acomp->audio_ops && acomp->audio_ops->master_bind) {
|
||||
ret = acomp->audio_ops->master_bind(dev, acomp);
|
||||
if (ret < 0)
|
||||
goto module_put;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
module_put:
|
||||
module_put(acomp->ops->owner);
|
||||
out_unbind:
|
||||
component_unbind_all(dev, acomp);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void hdac_component_master_unbind(struct device *dev)
|
||||
{
|
||||
struct drm_audio_component *acomp = hdac_get_acomp(dev);
|
||||
|
||||
if (acomp->audio_ops && acomp->audio_ops->master_unbind)
|
||||
acomp->audio_ops->master_unbind(dev, acomp);
|
||||
module_put(acomp->ops->owner);
|
||||
component_unbind_all(dev, acomp);
|
||||
WARN_ON(acomp->ops || acomp->dev);
|
||||
}
|
||||
|
||||
static const struct component_master_ops hdac_component_master_ops = {
|
||||
.bind = hdac_component_master_bind,
|
||||
.unbind = hdac_component_master_unbind,
|
||||
};
|
||||
|
||||
/**
|
||||
* snd_hdac_acomp_register_notifier - Register audio component ops
|
||||
* @bus: HDA core bus
|
||||
* @aops: audio component ops
|
||||
*
|
||||
* This function is supposed to be used only by a HD-audio controller
|
||||
* driver that needs the interaction with graphics driver.
|
||||
*
|
||||
* This function sets the given ops to be called by the graphics driver.
|
||||
*
|
||||
* Returns zero for success or a negative error code.
|
||||
*/
|
||||
int snd_hdac_acomp_register_notifier(struct hdac_bus *bus,
|
||||
const struct drm_audio_component_audio_ops *aops)
|
||||
{
|
||||
if (!bus->audio_component)
|
||||
return -ENODEV;
|
||||
|
||||
bus->audio_component->audio_ops = aops;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hdac_acomp_register_notifier);
|
||||
|
||||
/**
|
||||
* snd_hdac_acomp_init - Initialize audio component
|
||||
* @bus: HDA core bus
|
||||
* @match_master: match function for finding components
|
||||
* @extra_size: Extra bytes to allocate
|
||||
*
|
||||
* This function is supposed to be used only by a HD-audio controller
|
||||
* driver that needs the interaction with graphics driver.
|
||||
*
|
||||
* This function initializes and sets up the audio component to communicate
|
||||
* with graphics driver.
|
||||
*
|
||||
* Unlike snd_hdac_i915_init(), this function doesn't synchronize with the
|
||||
* binding with the DRM component. Each caller needs to sync via master_bind
|
||||
* audio_ops.
|
||||
*
|
||||
* Returns zero for success or a negative error code.
|
||||
*/
|
||||
int snd_hdac_acomp_init(struct hdac_bus *bus,
|
||||
const struct drm_audio_component_audio_ops *aops,
|
||||
int (*match_master)(struct device *, void *),
|
||||
size_t extra_size)
|
||||
{
|
||||
struct component_match *match = NULL;
|
||||
struct device *dev = bus->dev;
|
||||
struct drm_audio_component *acomp;
|
||||
int ret;
|
||||
|
||||
if (WARN_ON(hdac_get_acomp(dev)))
|
||||
return -EBUSY;
|
||||
|
||||
acomp = devres_alloc(hdac_acomp_release, sizeof(*acomp) + extra_size,
|
||||
GFP_KERNEL);
|
||||
if (!acomp)
|
||||
return -ENOMEM;
|
||||
acomp->audio_ops = aops;
|
||||
bus->audio_component = acomp;
|
||||
devres_add(dev, acomp);
|
||||
|
||||
component_match_add(dev, &match, match_master, bus);
|
||||
ret = component_master_add_with_match(dev, &hdac_component_master_ops,
|
||||
match);
|
||||
if (ret < 0)
|
||||
goto out_err;
|
||||
|
||||
return 0;
|
||||
|
||||
out_err:
|
||||
bus->audio_component = NULL;
|
||||
devres_destroy(dev, hdac_acomp_release, NULL, NULL);
|
||||
dev_info(dev, "failed to add audio component master (%d)\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hdac_acomp_init);
|
||||
|
||||
/**
|
||||
* snd_hdac_acomp_exit - Finalize audio component
|
||||
* @bus: HDA core bus
|
||||
*
|
||||
* This function is supposed to be used only by a HD-audio controller
|
||||
* driver that needs the interaction with graphics driver.
|
||||
*
|
||||
* This function releases the audio component that has been used.
|
||||
*
|
||||
* Returns zero for success or a negative error code.
|
||||
*/
|
||||
int snd_hdac_acomp_exit(struct hdac_bus *bus)
|
||||
{
|
||||
struct device *dev = bus->dev;
|
||||
struct drm_audio_component *acomp = bus->audio_component;
|
||||
|
||||
if (!acomp)
|
||||
return 0;
|
||||
|
||||
WARN_ON(bus->drm_power_refcount);
|
||||
if (bus->drm_power_refcount > 0 && acomp->ops)
|
||||
acomp->ops->put_power(acomp->dev);
|
||||
|
||||
component_master_del(dev, &hdac_component_master_ops);
|
||||
|
||||
bus->audio_component = NULL;
|
||||
devres_destroy(dev, hdac_acomp_release, NULL, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hdac_acomp_exit);
|
@@ -15,89 +15,11 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/component.h>
|
||||
#include <drm/i915_component.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/hdaudio.h>
|
||||
#include <sound/hda_i915.h>
|
||||
#include <sound/hda_register.h>
|
||||
|
||||
static struct i915_audio_component *hdac_acomp;
|
||||
|
||||
/**
|
||||
* snd_hdac_set_codec_wakeup - Enable / disable HDMI/DP codec wakeup
|
||||
* @bus: HDA core bus
|
||||
* @enable: enable or disable the wakeup
|
||||
*
|
||||
* This function is supposed to be used only by a HD-audio controller
|
||||
* driver that needs the interaction with i915 graphics.
|
||||
*
|
||||
* This function should be called during the chip reset, also called at
|
||||
* resume for updating STATESTS register read.
|
||||
*
|
||||
* Returns zero for success or a negative error code.
|
||||
*/
|
||||
int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable)
|
||||
{
|
||||
struct i915_audio_component *acomp = bus->audio_component;
|
||||
|
||||
if (!acomp || !acomp->ops)
|
||||
return -ENODEV;
|
||||
|
||||
if (!acomp->ops->codec_wake_override) {
|
||||
dev_warn(bus->dev,
|
||||
"Invalid codec wake callback\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev_dbg(bus->dev, "%s codec wakeup\n",
|
||||
enable ? "enable" : "disable");
|
||||
|
||||
acomp->ops->codec_wake_override(acomp->dev, enable);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hdac_set_codec_wakeup);
|
||||
|
||||
/**
|
||||
* snd_hdac_display_power - Power up / down the power refcount
|
||||
* @bus: HDA core bus
|
||||
* @enable: power up or down
|
||||
*
|
||||
* This function is supposed to be used only by a HD-audio controller
|
||||
* driver that needs the interaction with i915 graphics.
|
||||
*
|
||||
* This function manages a refcount and calls the i915 get_power() and
|
||||
* put_power() ops accordingly, toggling the codec wakeup, too.
|
||||
*
|
||||
* Returns zero for success or a negative error code.
|
||||
*/
|
||||
int snd_hdac_display_power(struct hdac_bus *bus, bool enable)
|
||||
{
|
||||
struct i915_audio_component *acomp = bus->audio_component;
|
||||
|
||||
if (!acomp || !acomp->ops)
|
||||
return -ENODEV;
|
||||
|
||||
dev_dbg(bus->dev, "display power %s\n",
|
||||
enable ? "enable" : "disable");
|
||||
|
||||
if (enable) {
|
||||
if (!bus->i915_power_refcount++) {
|
||||
acomp->ops->get_power(acomp->dev);
|
||||
snd_hdac_set_codec_wakeup(bus, true);
|
||||
snd_hdac_set_codec_wakeup(bus, false);
|
||||
}
|
||||
} else {
|
||||
WARN_ON(!bus->i915_power_refcount);
|
||||
if (!--bus->i915_power_refcount)
|
||||
acomp->ops->put_power(acomp->dev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hdac_display_power);
|
||||
|
||||
#define CONTROLLER_IN_GPU(pci) (((pci)->device == 0x0a0c) || \
|
||||
((pci)->device == 0x0c0c) || \
|
||||
((pci)->device == 0x0d0c) || \
|
||||
@@ -119,7 +41,7 @@ EXPORT_SYMBOL_GPL(snd_hdac_display_power);
|
||||
*/
|
||||
void snd_hdac_i915_set_bclk(struct hdac_bus *bus)
|
||||
{
|
||||
struct i915_audio_component *acomp = bus->audio_component;
|
||||
struct drm_audio_component *acomp = bus->audio_component;
|
||||
struct pci_dev *pci = to_pci_dev(bus->dev);
|
||||
int cdclk_freq;
|
||||
unsigned int bclk_m, bclk_n;
|
||||
@@ -158,181 +80,11 @@ void snd_hdac_i915_set_bclk(struct hdac_bus *bus)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hdac_i915_set_bclk);
|
||||
|
||||
/* There is a fixed mapping between audio pin node and display port.
|
||||
* on SNB, IVY, HSW, BSW, SKL, BXT, KBL:
|
||||
* Pin Widget 5 - PORT B (port = 1 in i915 driver)
|
||||
* Pin Widget 6 - PORT C (port = 2 in i915 driver)
|
||||
* Pin Widget 7 - PORT D (port = 3 in i915 driver)
|
||||
*
|
||||
* on VLV, ILK:
|
||||
* Pin Widget 4 - PORT B (port = 1 in i915 driver)
|
||||
* Pin Widget 5 - PORT C (port = 2 in i915 driver)
|
||||
* Pin Widget 6 - PORT D (port = 3 in i915 driver)
|
||||
*/
|
||||
static int pin2port(struct hdac_device *codec, hda_nid_t pin_nid)
|
||||
static int i915_component_master_match(struct device *dev, void *data)
|
||||
{
|
||||
int base_nid;
|
||||
|
||||
switch (codec->vendor_id) {
|
||||
case 0x80860054: /* ILK */
|
||||
case 0x80862804: /* ILK */
|
||||
case 0x80862882: /* VLV */
|
||||
base_nid = 3;
|
||||
break;
|
||||
default:
|
||||
base_nid = 4;
|
||||
break;
|
||||
}
|
||||
|
||||
if (WARN_ON(pin_nid <= base_nid || pin_nid > base_nid + 3))
|
||||
return -1;
|
||||
return pin_nid - base_nid;
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_hdac_sync_audio_rate - Set N/CTS based on the sample rate
|
||||
* @codec: HDA codec
|
||||
* @nid: the pin widget NID
|
||||
* @dev_id: device identifier
|
||||
* @rate: the sample rate to set
|
||||
*
|
||||
* This function is supposed to be used only by a HD-audio controller
|
||||
* driver that needs the interaction with i915 graphics.
|
||||
*
|
||||
* This function sets N/CTS value based on the given sample rate.
|
||||
* Returns zero for success, or a negative error code.
|
||||
*/
|
||||
int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid,
|
||||
int dev_id, int rate)
|
||||
{
|
||||
struct hdac_bus *bus = codec->bus;
|
||||
struct i915_audio_component *acomp = bus->audio_component;
|
||||
int port, pipe;
|
||||
|
||||
if (!acomp || !acomp->ops || !acomp->ops->sync_audio_rate)
|
||||
return -ENODEV;
|
||||
port = pin2port(codec, nid);
|
||||
if (port < 0)
|
||||
return -EINVAL;
|
||||
pipe = dev_id;
|
||||
return acomp->ops->sync_audio_rate(acomp->dev, port, pipe, rate);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hdac_sync_audio_rate);
|
||||
|
||||
/**
|
||||
* snd_hdac_acomp_get_eld - Get the audio state and ELD via component
|
||||
* @codec: HDA codec
|
||||
* @nid: the pin widget NID
|
||||
* @dev_id: device identifier
|
||||
* @audio_enabled: the pointer to store the current audio state
|
||||
* @buffer: the buffer pointer to store ELD bytes
|
||||
* @max_bytes: the max bytes to be stored on @buffer
|
||||
*
|
||||
* This function is supposed to be used only by a HD-audio controller
|
||||
* driver that needs the interaction with i915 graphics.
|
||||
*
|
||||
* This function queries the current state of the audio on the given
|
||||
* digital port and fetches the ELD bytes onto the given buffer.
|
||||
* It returns the number of bytes for the total ELD data, zero for
|
||||
* invalid ELD, or a negative error code.
|
||||
*
|
||||
* The return size is the total bytes required for the whole ELD bytes,
|
||||
* thus it may be over @max_bytes. If it's over @max_bytes, it implies
|
||||
* that only a part of ELD bytes have been fetched.
|
||||
*/
|
||||
int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid, int dev_id,
|
||||
bool *audio_enabled, char *buffer, int max_bytes)
|
||||
{
|
||||
struct hdac_bus *bus = codec->bus;
|
||||
struct i915_audio_component *acomp = bus->audio_component;
|
||||
int port, pipe;
|
||||
|
||||
if (!acomp || !acomp->ops || !acomp->ops->get_eld)
|
||||
return -ENODEV;
|
||||
|
||||
port = pin2port(codec, nid);
|
||||
if (port < 0)
|
||||
return -EINVAL;
|
||||
|
||||
pipe = dev_id;
|
||||
return acomp->ops->get_eld(acomp->dev, port, pipe, audio_enabled,
|
||||
buffer, max_bytes);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hdac_acomp_get_eld);
|
||||
|
||||
static int hdac_component_master_bind(struct device *dev)
|
||||
{
|
||||
struct i915_audio_component *acomp = hdac_acomp;
|
||||
int ret;
|
||||
|
||||
ret = component_bind_all(dev, acomp);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (WARN_ON(!(acomp->dev && acomp->ops && acomp->ops->get_power &&
|
||||
acomp->ops->put_power && acomp->ops->get_cdclk_freq))) {
|
||||
ret = -EINVAL;
|
||||
goto out_unbind;
|
||||
}
|
||||
|
||||
/*
|
||||
* Atm, we don't support dynamic unbinding initiated by the child
|
||||
* component, so pin its containing module until we unbind.
|
||||
*/
|
||||
if (!try_module_get(acomp->ops->owner)) {
|
||||
ret = -ENODEV;
|
||||
goto out_unbind;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
out_unbind:
|
||||
component_unbind_all(dev, acomp);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void hdac_component_master_unbind(struct device *dev)
|
||||
{
|
||||
struct i915_audio_component *acomp = hdac_acomp;
|
||||
|
||||
module_put(acomp->ops->owner);
|
||||
component_unbind_all(dev, acomp);
|
||||
WARN_ON(acomp->ops || acomp->dev);
|
||||
}
|
||||
|
||||
static const struct component_master_ops hdac_component_master_ops = {
|
||||
.bind = hdac_component_master_bind,
|
||||
.unbind = hdac_component_master_unbind,
|
||||
};
|
||||
|
||||
static int hdac_component_master_match(struct device *dev, void *data)
|
||||
{
|
||||
/* i915 is the only supported component */
|
||||
return !strcmp(dev->driver->name, "i915");
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_hdac_i915_register_notifier - Register i915 audio component ops
|
||||
* @aops: i915 audio component ops
|
||||
*
|
||||
* This function is supposed to be used only by a HD-audio controller
|
||||
* driver that needs the interaction with i915 graphics.
|
||||
*
|
||||
* This function sets the given ops to be called by the i915 graphics driver.
|
||||
*
|
||||
* Returns zero for success or a negative error code.
|
||||
*/
|
||||
int snd_hdac_i915_register_notifier(const struct i915_audio_component_audio_ops *aops)
|
||||
{
|
||||
if (!hdac_acomp)
|
||||
return -ENODEV;
|
||||
|
||||
hdac_acomp->audio_ops = aops;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hdac_i915_register_notifier);
|
||||
|
||||
/* check whether intel graphics is present */
|
||||
static bool i915_gfx_present(void)
|
||||
{
|
||||
@@ -359,83 +111,26 @@ static bool i915_gfx_present(void)
|
||||
*/
|
||||
int snd_hdac_i915_init(struct hdac_bus *bus)
|
||||
{
|
||||
struct component_match *match = NULL;
|
||||
struct device *dev = bus->dev;
|
||||
struct i915_audio_component *acomp;
|
||||
int ret;
|
||||
|
||||
if (WARN_ON(hdac_acomp))
|
||||
return -EBUSY;
|
||||
struct drm_audio_component *acomp;
|
||||
int err;
|
||||
|
||||
if (!i915_gfx_present())
|
||||
return -ENODEV;
|
||||
|
||||
acomp = kzalloc(sizeof(*acomp), GFP_KERNEL);
|
||||
err = snd_hdac_acomp_init(bus, NULL,
|
||||
i915_component_master_match,
|
||||
sizeof(struct i915_audio_component) - sizeof(*acomp));
|
||||
if (err < 0)
|
||||
return err;
|
||||
acomp = bus->audio_component;
|
||||
if (!acomp)
|
||||
return -ENOMEM;
|
||||
bus->audio_component = acomp;
|
||||
hdac_acomp = acomp;
|
||||
|
||||
component_match_add(dev, &match, hdac_component_master_match, bus);
|
||||
ret = component_master_add_with_match(dev, &hdac_component_master_ops,
|
||||
match);
|
||||
if (ret < 0)
|
||||
goto out_err;
|
||||
|
||||
/*
|
||||
* Atm, we don't support deferring the component binding, so make sure
|
||||
* i915 is loaded and that the binding successfully completes.
|
||||
*/
|
||||
request_module("i915");
|
||||
|
||||
return -ENODEV;
|
||||
if (!acomp->ops)
|
||||
request_module("i915");
|
||||
if (!acomp->ops) {
|
||||
ret = -ENODEV;
|
||||
goto out_master_del;
|
||||
snd_hdac_acomp_exit(bus);
|
||||
return -ENODEV;
|
||||
}
|
||||
dev_dbg(dev, "bound to i915 component master\n");
|
||||
|
||||
return 0;
|
||||
out_master_del:
|
||||
component_master_del(dev, &hdac_component_master_ops);
|
||||
out_err:
|
||||
kfree(acomp);
|
||||
bus->audio_component = NULL;
|
||||
hdac_acomp = NULL;
|
||||
dev_info(dev, "failed to add i915 component master (%d)\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hdac_i915_init);
|
||||
|
||||
/**
|
||||
* snd_hdac_i915_exit - Finalize i915 audio component
|
||||
* @bus: HDA core bus
|
||||
*
|
||||
* This function is supposed to be used only by a HD-audio controller
|
||||
* driver that needs the interaction with i915 graphics.
|
||||
*
|
||||
* This function releases the i915 audio component that has been used.
|
||||
*
|
||||
* Returns zero for success or a negative error code.
|
||||
*/
|
||||
int snd_hdac_i915_exit(struct hdac_bus *bus)
|
||||
{
|
||||
struct device *dev = bus->dev;
|
||||
struct i915_audio_component *acomp = bus->audio_component;
|
||||
|
||||
if (!acomp)
|
||||
return 0;
|
||||
|
||||
WARN_ON(bus->i915_power_refcount);
|
||||
if (bus->i915_power_refcount > 0 && acomp->ops)
|
||||
acomp->ops->put_power(acomp->dev);
|
||||
|
||||
component_master_del(dev, &hdac_component_master_ops);
|
||||
|
||||
kfree(acomp);
|
||||
bus->audio_component = NULL;
|
||||
hdac_acomp = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hdac_i915_exit);
|
||||
|
@@ -858,6 +858,39 @@ static void snd_hda_codec_dev_release(struct device *dev)
|
||||
kfree(codec);
|
||||
}
|
||||
|
||||
#define DEV_NAME_LEN 31
|
||||
|
||||
static int snd_hda_codec_device_init(struct hda_bus *bus, struct snd_card *card,
|
||||
unsigned int codec_addr, struct hda_codec **codecp)
|
||||
{
|
||||
char name[DEV_NAME_LEN];
|
||||
struct hda_codec *codec;
|
||||
int err;
|
||||
|
||||
dev_dbg(card->dev, "%s: entry\n", __func__);
|
||||
|
||||
if (snd_BUG_ON(!bus))
|
||||
return -EINVAL;
|
||||
if (snd_BUG_ON(codec_addr > HDA_MAX_CODEC_ADDRESS))
|
||||
return -EINVAL;
|
||||
|
||||
codec = kzalloc(sizeof(*codec), GFP_KERNEL);
|
||||
if (!codec)
|
||||
return -ENOMEM;
|
||||
|
||||
sprintf(name, "hdaudioC%dD%d", card->number, codec_addr);
|
||||
err = snd_hdac_device_init(&codec->core, &bus->core, name, codec_addr);
|
||||
if (err < 0) {
|
||||
kfree(codec);
|
||||
return err;
|
||||
}
|
||||
|
||||
codec->core.type = HDA_DEV_LEGACY;
|
||||
*codecp = codec;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_hda_codec_new - create a HDA codec
|
||||
* @bus: the bus to assign
|
||||
@@ -869,7 +902,19 @@ static void snd_hda_codec_dev_release(struct device *dev)
|
||||
int snd_hda_codec_new(struct hda_bus *bus, struct snd_card *card,
|
||||
unsigned int codec_addr, struct hda_codec **codecp)
|
||||
{
|
||||
struct hda_codec *codec;
|
||||
int ret;
|
||||
|
||||
ret = snd_hda_codec_device_init(bus, card, codec_addr, codecp);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return snd_hda_codec_device_new(bus, card, codec_addr, *codecp);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hda_codec_new);
|
||||
|
||||
int snd_hda_codec_device_new(struct hda_bus *bus, struct snd_card *card,
|
||||
unsigned int codec_addr, struct hda_codec *codec)
|
||||
{
|
||||
char component[31];
|
||||
hda_nid_t fg;
|
||||
int err;
|
||||
@@ -879,25 +924,14 @@ int snd_hda_codec_new(struct hda_bus *bus, struct snd_card *card,
|
||||
.dev_free = snd_hda_codec_dev_free,
|
||||
};
|
||||
|
||||
dev_dbg(card->dev, "%s: entry\n", __func__);
|
||||
|
||||
if (snd_BUG_ON(!bus))
|
||||
return -EINVAL;
|
||||
if (snd_BUG_ON(codec_addr > HDA_MAX_CODEC_ADDRESS))
|
||||
return -EINVAL;
|
||||
|
||||
codec = kzalloc(sizeof(*codec), GFP_KERNEL);
|
||||
if (!codec)
|
||||
return -ENOMEM;
|
||||
|
||||
sprintf(component, "hdaudioC%dD%d", card->number, codec_addr);
|
||||
err = snd_hdac_device_init(&codec->core, &bus->core, component,
|
||||
codec_addr);
|
||||
if (err < 0) {
|
||||
kfree(codec);
|
||||
return err;
|
||||
}
|
||||
|
||||
codec->core.dev.release = snd_hda_codec_dev_release;
|
||||
codec->core.type = HDA_DEV_LEGACY;
|
||||
codec->core.exec_verb = codec_exec_verb;
|
||||
|
||||
codec->bus = bus;
|
||||
@@ -957,15 +991,13 @@ int snd_hda_codec_new(struct hda_bus *bus, struct snd_card *card,
|
||||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
if (codecp)
|
||||
*codecp = codec;
|
||||
return 0;
|
||||
|
||||
error:
|
||||
put_device(hda_codec_dev(codec));
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hda_codec_new);
|
||||
EXPORT_SYMBOL_GPL(snd_hda_codec_device_new);
|
||||
|
||||
/**
|
||||
* snd_hda_codec_update_widgets - Refresh widget caps and pin defaults
|
||||
@@ -2992,6 +3024,7 @@ int snd_hda_codec_build_controls(struct hda_codec *codec)
|
||||
sync_power_up_states(codec);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hda_codec_build_controls);
|
||||
|
||||
/*
|
||||
* PCM stuff
|
||||
@@ -3197,6 +3230,7 @@ int snd_hda_codec_parse_pcms(struct hda_codec *codec)
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hda_codec_parse_pcms);
|
||||
|
||||
/* assign all PCMs of the given codec */
|
||||
int snd_hda_codec_build_pcms(struct hda_codec *codec)
|
||||
|
@@ -308,6 +308,8 @@ struct hda_codec {
|
||||
*/
|
||||
int snd_hda_codec_new(struct hda_bus *bus, struct snd_card *card,
|
||||
unsigned int codec_addr, struct hda_codec **codecp);
|
||||
int snd_hda_codec_device_new(struct hda_bus *bus, struct snd_card *card,
|
||||
unsigned int codec_addr, struct hda_codec *codec);
|
||||
int snd_hda_codec_configure(struct hda_codec *codec);
|
||||
int snd_hda_codec_update_widgets(struct hda_codec *codec);
|
||||
|
||||
|
@@ -177,13 +177,13 @@ struct hdmi_spec {
|
||||
|
||||
/* i915/powerwell (Haswell+/Valleyview+) specific */
|
||||
bool use_acomp_notifier; /* use i915 eld_notify callback for hotplug */
|
||||
struct i915_audio_component_audio_ops i915_audio_ops;
|
||||
struct drm_audio_component_audio_ops drm_audio_ops;
|
||||
|
||||
struct hdac_chmap chmap;
|
||||
hda_nid_t vendor_nid;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_SND_HDA_I915
|
||||
#ifdef CONFIG_SND_HDA_COMPONENT
|
||||
static inline bool codec_has_acomp(struct hda_codec *codec)
|
||||
{
|
||||
struct hdmi_spec *spec = codec->spec;
|
||||
@@ -2288,7 +2288,7 @@ static void generic_hdmi_free(struct hda_codec *codec)
|
||||
int pin_idx, pcm_idx;
|
||||
|
||||
if (codec_has_acomp(codec))
|
||||
snd_hdac_i915_register_notifier(NULL);
|
||||
snd_hdac_acomp_register_notifier(&codec->bus->core, NULL);
|
||||
|
||||
for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
|
||||
struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
|
||||
@@ -2471,6 +2471,38 @@ static void haswell_set_power_state(struct hda_codec *codec, hda_nid_t fg,
|
||||
snd_hda_codec_set_power_to_all(codec, fg, power_state);
|
||||
}
|
||||
|
||||
/* There is a fixed mapping between audio pin node and display port.
|
||||
* on SNB, IVY, HSW, BSW, SKL, BXT, KBL:
|
||||
* Pin Widget 5 - PORT B (port = 1 in i915 driver)
|
||||
* Pin Widget 6 - PORT C (port = 2 in i915 driver)
|
||||
* Pin Widget 7 - PORT D (port = 3 in i915 driver)
|
||||
*
|
||||
* on VLV, ILK:
|
||||
* Pin Widget 4 - PORT B (port = 1 in i915 driver)
|
||||
* Pin Widget 5 - PORT C (port = 2 in i915 driver)
|
||||
* Pin Widget 6 - PORT D (port = 3 in i915 driver)
|
||||
*/
|
||||
static int intel_base_nid(struct hda_codec *codec)
|
||||
{
|
||||
switch (codec->core.vendor_id) {
|
||||
case 0x80860054: /* ILK */
|
||||
case 0x80862804: /* ILK */
|
||||
case 0x80862882: /* VLV */
|
||||
return 4;
|
||||
default:
|
||||
return 5;
|
||||
}
|
||||
}
|
||||
|
||||
static int intel_pin2port(void *audio_ptr, int pin_nid)
|
||||
{
|
||||
int base_nid = intel_base_nid(audio_ptr);
|
||||
|
||||
if (WARN_ON(pin_nid < base_nid || pin_nid >= base_nid + 3))
|
||||
return -1;
|
||||
return pin_nid - base_nid + 1; /* intel port is 1-based */
|
||||
}
|
||||
|
||||
static void intel_pin_eld_notify(void *audio_ptr, int port, int pipe)
|
||||
{
|
||||
struct hda_codec *codec = audio_ptr;
|
||||
@@ -2481,16 +2513,7 @@ static void intel_pin_eld_notify(void *audio_ptr, int port, int pipe)
|
||||
if (port < 1 || port > 3)
|
||||
return;
|
||||
|
||||
switch (codec->core.vendor_id) {
|
||||
case 0x80860054: /* ILK */
|
||||
case 0x80862804: /* ILK */
|
||||
case 0x80862882: /* VLV */
|
||||
pin_nid = port + 0x03;
|
||||
break;
|
||||
default:
|
||||
pin_nid = port + 0x04;
|
||||
break;
|
||||
}
|
||||
pin_nid = port + intel_base_nid(codec) - 1; /* intel port is 1-based */
|
||||
|
||||
/* skip notification during system suspend (but not in runtime PM);
|
||||
* the state will be updated at resume
|
||||
@@ -2511,14 +2534,16 @@ static void register_i915_notifier(struct hda_codec *codec)
|
||||
struct hdmi_spec *spec = codec->spec;
|
||||
|
||||
spec->use_acomp_notifier = true;
|
||||
spec->i915_audio_ops.audio_ptr = codec;
|
||||
spec->drm_audio_ops.audio_ptr = codec;
|
||||
/* intel_audio_codec_enable() or intel_audio_codec_disable()
|
||||
* will call pin_eld_notify with using audio_ptr pointer
|
||||
* We need make sure audio_ptr is really setup
|
||||
*/
|
||||
wmb();
|
||||
spec->i915_audio_ops.pin_eld_notify = intel_pin_eld_notify;
|
||||
snd_hdac_i915_register_notifier(&spec->i915_audio_ops);
|
||||
spec->drm_audio_ops.pin2port = intel_pin2port;
|
||||
spec->drm_audio_ops.pin_eld_notify = intel_pin_eld_notify;
|
||||
snd_hdac_acomp_register_notifier(&codec->bus->core,
|
||||
&spec->drm_audio_ops);
|
||||
}
|
||||
|
||||
/* setup_stream ops override for HSW+ */
|
||||
|
@@ -57,6 +57,7 @@ source "sound/soc/kirkwood/Kconfig"
|
||||
source "sound/soc/img/Kconfig"
|
||||
source "sound/soc/intel/Kconfig"
|
||||
source "sound/soc/mediatek/Kconfig"
|
||||
source "sound/soc/meson/Kconfig"
|
||||
source "sound/soc/mxs/Kconfig"
|
||||
source "sound/soc/pxa/Kconfig"
|
||||
source "sound/soc/qcom/Kconfig"
|
||||
|
@@ -38,6 +38,7 @@ obj-$(CONFIG_SND_SOC) += jz4740/
|
||||
obj-$(CONFIG_SND_SOC) += img/
|
||||
obj-$(CONFIG_SND_SOC) += intel/
|
||||
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/
|
||||
|
@@ -8,6 +8,7 @@ config SND_SOC_AMD_CZ_DA7219MX98357_MACH
|
||||
select SND_SOC_DA7219
|
||||
select SND_SOC_MAX98357A
|
||||
select SND_SOC_ADAU7002
|
||||
select REGULATOR
|
||||
depends on SND_SOC_AMD_ACP && I2C
|
||||
help
|
||||
This option enables machine driver for DA7219 and MAX9835.
|
||||
|
@@ -32,6 +32,8 @@
|
||||
#include <linux/clk.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
#include <linux/regulator/driver.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/acpi.h>
|
||||
@@ -148,7 +150,8 @@ static int cz_da7219_startup(struct snd_pcm_substream *substream)
|
||||
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
|
||||
&constraints_rates);
|
||||
|
||||
machine->i2s_instance = I2S_BT_INSTANCE;
|
||||
machine->i2s_instance = I2S_SP_INSTANCE;
|
||||
machine->capture_channel = CAP_CHANNEL1;
|
||||
return da7219_clk_enable(substream);
|
||||
}
|
||||
|
||||
@@ -163,7 +166,7 @@ static int cz_max_startup(struct snd_pcm_substream *substream)
|
||||
struct snd_soc_card *card = rtd->card;
|
||||
struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
|
||||
|
||||
machine->i2s_instance = I2S_SP_INSTANCE;
|
||||
machine->i2s_instance = I2S_BT_INSTANCE;
|
||||
return da7219_clk_enable(substream);
|
||||
}
|
||||
|
||||
@@ -172,13 +175,24 @@ static void cz_max_shutdown(struct snd_pcm_substream *substream)
|
||||
da7219_clk_disable();
|
||||
}
|
||||
|
||||
static int cz_dmic_startup(struct snd_pcm_substream *substream)
|
||||
static int cz_dmic0_startup(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_card *card = rtd->card;
|
||||
struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
|
||||
|
||||
machine->i2s_instance = I2S_BT_INSTANCE;
|
||||
return da7219_clk_enable(substream);
|
||||
}
|
||||
|
||||
static int cz_dmic1_startup(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_card *card = rtd->card;
|
||||
struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
|
||||
|
||||
machine->i2s_instance = I2S_SP_INSTANCE;
|
||||
machine->capture_channel = CAP_CHANNEL0;
|
||||
return da7219_clk_enable(substream);
|
||||
}
|
||||
|
||||
@@ -197,23 +211,39 @@ static const struct snd_soc_ops cz_max_play_ops = {
|
||||
.shutdown = cz_max_shutdown,
|
||||
};
|
||||
|
||||
static const struct snd_soc_ops cz_dmic_cap_ops = {
|
||||
.startup = cz_dmic_startup,
|
||||
static const struct snd_soc_ops cz_dmic0_cap_ops = {
|
||||
.startup = cz_dmic0_startup,
|
||||
.shutdown = cz_dmic_shutdown,
|
||||
};
|
||||
|
||||
static const struct snd_soc_ops cz_dmic1_cap_ops = {
|
||||
.startup = cz_dmic1_startup,
|
||||
.shutdown = cz_dmic_shutdown,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_link cz_dai_7219_98357[] = {
|
||||
{
|
||||
.name = "amd-da7219-play-cap",
|
||||
.stream_name = "Playback and Capture",
|
||||
.name = "amd-da7219-play",
|
||||
.stream_name = "Playback",
|
||||
.platform_name = "acp_audio_dma.0.auto",
|
||||
.cpu_dai_name = "designware-i2s.3.auto",
|
||||
.cpu_dai_name = "designware-i2s.1.auto",
|
||||
.codec_dai_name = "da7219-hifi",
|
||||
.codec_name = "i2c-DLGS7219:00",
|
||||
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
|
||||
| SND_SOC_DAIFMT_CBM_CFM,
|
||||
.init = cz_da7219_init,
|
||||
.dpcm_playback = 1,
|
||||
.ops = &cz_da7219_cap_ops,
|
||||
},
|
||||
{
|
||||
.name = "amd-da7219-cap",
|
||||
.stream_name = "Capture",
|
||||
.platform_name = "acp_audio_dma.0.auto",
|
||||
.cpu_dai_name = "designware-i2s.2.auto",
|
||||
.codec_dai_name = "da7219-hifi",
|
||||
.codec_name = "i2c-DLGS7219:00",
|
||||
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
|
||||
| SND_SOC_DAIFMT_CBM_CFM,
|
||||
.dpcm_capture = 1,
|
||||
.ops = &cz_da7219_cap_ops,
|
||||
},
|
||||
@@ -221,7 +251,7 @@ static struct snd_soc_dai_link cz_dai_7219_98357[] = {
|
||||
.name = "amd-max98357-play",
|
||||
.stream_name = "HiFi Playback",
|
||||
.platform_name = "acp_audio_dma.0.auto",
|
||||
.cpu_dai_name = "designware-i2s.1.auto",
|
||||
.cpu_dai_name = "designware-i2s.3.auto",
|
||||
.codec_dai_name = "HiFi",
|
||||
.codec_name = "MX98357A:00",
|
||||
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
|
||||
@@ -230,8 +260,22 @@ static struct snd_soc_dai_link cz_dai_7219_98357[] = {
|
||||
.ops = &cz_max_play_ops,
|
||||
},
|
||||
{
|
||||
.name = "dmic",
|
||||
.stream_name = "DMIC Capture",
|
||||
/* C panel DMIC */
|
||||
.name = "dmic0",
|
||||
.stream_name = "DMIC0 Capture",
|
||||
.platform_name = "acp_audio_dma.0.auto",
|
||||
.cpu_dai_name = "designware-i2s.3.auto",
|
||||
.codec_dai_name = "adau7002-hifi",
|
||||
.codec_name = "ADAU7002:00",
|
||||
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
|
||||
| SND_SOC_DAIFMT_CBM_CFM,
|
||||
.dpcm_capture = 1,
|
||||
.ops = &cz_dmic0_cap_ops,
|
||||
},
|
||||
{
|
||||
/* A/B panel DMIC */
|
||||
.name = "dmic1",
|
||||
.stream_name = "DMIC1 Capture",
|
||||
.platform_name = "acp_audio_dma.0.auto",
|
||||
.cpu_dai_name = "designware-i2s.2.auto",
|
||||
.codec_dai_name = "adau7002-hifi",
|
||||
@@ -239,7 +283,7 @@ static struct snd_soc_dai_link cz_dai_7219_98357[] = {
|
||||
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
|
||||
| SND_SOC_DAIFMT_CBM_CFM,
|
||||
.dpcm_capture = 1,
|
||||
.ops = &cz_dmic_cap_ops,
|
||||
.ops = &cz_dmic1_cap_ops,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -278,11 +322,52 @@ static struct snd_soc_card cz_card = {
|
||||
.num_controls = ARRAY_SIZE(cz_mc_controls),
|
||||
};
|
||||
|
||||
static struct regulator_consumer_supply acp_da7219_supplies[] = {
|
||||
REGULATOR_SUPPLY("VDD", "i2c-DLGS7219:00"),
|
||||
REGULATOR_SUPPLY("VDDMIC", "i2c-DLGS7219:00"),
|
||||
REGULATOR_SUPPLY("VDDIO", "i2c-DLGS7219:00"),
|
||||
REGULATOR_SUPPLY("IOVDD", "ADAU7002:00"),
|
||||
};
|
||||
|
||||
static struct regulator_init_data acp_da7219_data = {
|
||||
.constraints = {
|
||||
.always_on = 1,
|
||||
},
|
||||
.num_consumer_supplies = ARRAY_SIZE(acp_da7219_supplies),
|
||||
.consumer_supplies = acp_da7219_supplies,
|
||||
};
|
||||
|
||||
static struct regulator_config acp_da7219_cfg = {
|
||||
.init_data = &acp_da7219_data,
|
||||
};
|
||||
|
||||
static struct regulator_ops acp_da7219_ops = {
|
||||
};
|
||||
|
||||
static struct regulator_desc acp_da7219_desc = {
|
||||
.name = "reg-fixed-1.8V",
|
||||
.type = REGULATOR_VOLTAGE,
|
||||
.owner = THIS_MODULE,
|
||||
.ops = &acp_da7219_ops,
|
||||
.fixed_uV = 1800000, /* 1.8V */
|
||||
.n_voltages = 1,
|
||||
};
|
||||
|
||||
static int cz_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
struct snd_soc_card *card;
|
||||
struct acp_platform_info *machine;
|
||||
struct regulator_dev *rdev;
|
||||
|
||||
acp_da7219_cfg.dev = &pdev->dev;
|
||||
rdev = devm_regulator_register(&pdev->dev, &acp_da7219_desc,
|
||||
&acp_da7219_cfg);
|
||||
if (IS_ERR(rdev)) {
|
||||
dev_err(&pdev->dev, "Failed to register regulator: %d\n",
|
||||
(int)PTR_ERR(rdev));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
machine = devm_kzalloc(&pdev->dev, sizeof(struct acp_platform_info),
|
||||
GFP_KERNEL);
|
||||
|
@@ -224,13 +224,11 @@ static void set_acp_sysmem_dma_descriptors(void __iomem *acp_mmio,
|
||||
switch (asic_type) {
|
||||
case CHIP_STONEY:
|
||||
dmadscr[i].xfer_val |=
|
||||
BIT(22) |
|
||||
(ACP_DMA_ATTR_SHARED_MEM_TO_DAGB_GARLIC << 16) |
|
||||
(size / 2);
|
||||
break;
|
||||
default:
|
||||
dmadscr[i].xfer_val |=
|
||||
BIT(22) |
|
||||
(ACP_DMA_ATTR_SHAREDMEM_TO_DAGB_ONION << 16) |
|
||||
(size / 2);
|
||||
}
|
||||
@@ -322,22 +320,87 @@ static void config_acp_dma(void __iomem *acp_mmio,
|
||||
struct audio_substream_data *rtd,
|
||||
u32 asic_type)
|
||||
{
|
||||
u16 ch_acp_sysmem, ch_acp_i2s;
|
||||
|
||||
acp_pte_config(acp_mmio, rtd->pg, rtd->num_of_pages,
|
||||
rtd->pte_offset);
|
||||
|
||||
if (rtd->direction == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
ch_acp_sysmem = rtd->ch1;
|
||||
ch_acp_i2s = rtd->ch2;
|
||||
} else {
|
||||
ch_acp_i2s = rtd->ch1;
|
||||
ch_acp_sysmem = rtd->ch2;
|
||||
}
|
||||
/* Configure System memory <-> ACP SRAM DMA descriptors */
|
||||
set_acp_sysmem_dma_descriptors(acp_mmio, rtd->size,
|
||||
rtd->direction, rtd->pte_offset,
|
||||
rtd->ch1, rtd->sram_bank,
|
||||
ch_acp_sysmem, rtd->sram_bank,
|
||||
rtd->dma_dscr_idx_1, asic_type);
|
||||
/* Configure ACP SRAM <-> I2S DMA descriptors */
|
||||
set_acp_to_i2s_dma_descriptors(acp_mmio, rtd->size,
|
||||
rtd->direction, rtd->sram_bank,
|
||||
rtd->destination, rtd->ch2,
|
||||
rtd->destination, ch_acp_i2s,
|
||||
rtd->dma_dscr_idx_2, asic_type);
|
||||
}
|
||||
|
||||
static void acp_dma_cap_channel_enable(void __iomem *acp_mmio,
|
||||
u16 cap_channel)
|
||||
{
|
||||
u32 val, ch_reg, imr_reg, res_reg;
|
||||
|
||||
switch (cap_channel) {
|
||||
case CAP_CHANNEL1:
|
||||
ch_reg = mmACP_I2SMICSP_RER1;
|
||||
res_reg = mmACP_I2SMICSP_RCR1;
|
||||
imr_reg = mmACP_I2SMICSP_IMR1;
|
||||
break;
|
||||
case CAP_CHANNEL0:
|
||||
default:
|
||||
ch_reg = mmACP_I2SMICSP_RER0;
|
||||
res_reg = mmACP_I2SMICSP_RCR0;
|
||||
imr_reg = mmACP_I2SMICSP_IMR0;
|
||||
break;
|
||||
}
|
||||
val = acp_reg_read(acp_mmio,
|
||||
mmACP_I2S_16BIT_RESOLUTION_EN);
|
||||
if (val & ACP_I2S_MIC_16BIT_RESOLUTION_EN) {
|
||||
acp_reg_write(0x0, acp_mmio, ch_reg);
|
||||
/* Set 16bit resolution on capture */
|
||||
acp_reg_write(0x2, acp_mmio, res_reg);
|
||||
}
|
||||
val = acp_reg_read(acp_mmio, imr_reg);
|
||||
val &= ~ACP_I2SMICSP_IMR1__I2SMICSP_RXDAM_MASK;
|
||||
val &= ~ACP_I2SMICSP_IMR1__I2SMICSP_RXFOM_MASK;
|
||||
acp_reg_write(val, acp_mmio, imr_reg);
|
||||
acp_reg_write(0x1, acp_mmio, ch_reg);
|
||||
}
|
||||
|
||||
static void acp_dma_cap_channel_disable(void __iomem *acp_mmio,
|
||||
u16 cap_channel)
|
||||
{
|
||||
u32 val, ch_reg, imr_reg;
|
||||
|
||||
switch (cap_channel) {
|
||||
case CAP_CHANNEL1:
|
||||
imr_reg = mmACP_I2SMICSP_IMR1;
|
||||
ch_reg = mmACP_I2SMICSP_RER1;
|
||||
break;
|
||||
case CAP_CHANNEL0:
|
||||
default:
|
||||
imr_reg = mmACP_I2SMICSP_IMR0;
|
||||
ch_reg = mmACP_I2SMICSP_RER0;
|
||||
break;
|
||||
}
|
||||
val = acp_reg_read(acp_mmio, imr_reg);
|
||||
val |= ACP_I2SMICSP_IMR1__I2SMICSP_RXDAM_MASK;
|
||||
val |= ACP_I2SMICSP_IMR1__I2SMICSP_RXFOM_MASK;
|
||||
acp_reg_write(val, acp_mmio, imr_reg);
|
||||
acp_reg_write(0x0, acp_mmio, ch_reg);
|
||||
}
|
||||
|
||||
/* Start a given DMA channel transfer */
|
||||
static void acp_dma_start(void __iomem *acp_mmio, u16 ch_num)
|
||||
static void acp_dma_start(void __iomem *acp_mmio, u16 ch_num, bool is_circular)
|
||||
{
|
||||
u32 dma_ctrl;
|
||||
|
||||
@@ -356,10 +419,8 @@ static void acp_dma_start(void __iomem *acp_mmio, u16 ch_num)
|
||||
|
||||
switch (ch_num) {
|
||||
case ACP_TO_I2S_DMA_CH_NUM:
|
||||
case ACP_TO_SYSRAM_CH_NUM:
|
||||
case I2S_TO_ACP_DMA_CH_NUM:
|
||||
case ACP_TO_I2S_DMA_BT_INSTANCE_CH_NUM:
|
||||
case ACP_TO_SYSRAM_BT_INSTANCE_CH_NUM:
|
||||
case I2S_TO_ACP_DMA_BT_INSTANCE_CH_NUM:
|
||||
dma_ctrl |= ACP_DMA_CNTL_0__DMAChIOCEn_MASK;
|
||||
break;
|
||||
@@ -368,8 +429,11 @@ static void acp_dma_start(void __iomem *acp_mmio, u16 ch_num)
|
||||
break;
|
||||
}
|
||||
|
||||
/* circular for both DMA channel */
|
||||
dma_ctrl |= ACP_DMA_CNTL_0__Circular_DMA_En_MASK;
|
||||
/* enable for ACP to SRAM DMA channel */
|
||||
if (is_circular == true)
|
||||
dma_ctrl |= ACP_DMA_CNTL_0__Circular_DMA_En_MASK;
|
||||
else
|
||||
dma_ctrl &= ~ACP_DMA_CNTL_0__Circular_DMA_En_MASK;
|
||||
|
||||
acp_reg_write(dma_ctrl, acp_mmio, mmACP_DMA_CNTL_0 + ch_num);
|
||||
}
|
||||
@@ -613,6 +677,7 @@ static int acp_deinit(void __iomem *acp_mmio)
|
||||
/* ACP DMA irq handler routine for playback, capture usecases */
|
||||
static irqreturn_t dma_irq_handler(int irq, void *arg)
|
||||
{
|
||||
u16 dscr_idx;
|
||||
u32 intr_flag, ext_intr_status;
|
||||
struct audio_drv_data *irq_data;
|
||||
void __iomem *acp_mmio;
|
||||
@@ -644,32 +709,39 @@ static irqreturn_t dma_irq_handler(int irq, void *arg)
|
||||
|
||||
if ((intr_flag & BIT(I2S_TO_ACP_DMA_CH_NUM)) != 0) {
|
||||
valid_irq = true;
|
||||
if (acp_reg_read(acp_mmio, mmACP_DMA_CUR_DSCR_14) ==
|
||||
CAPTURE_START_DMA_DESCR_CH15)
|
||||
dscr_idx = CAPTURE_END_DMA_DESCR_CH14;
|
||||
else
|
||||
dscr_idx = CAPTURE_START_DMA_DESCR_CH14;
|
||||
config_acp_dma_channel(acp_mmio, ACP_TO_SYSRAM_CH_NUM, dscr_idx,
|
||||
1, 0);
|
||||
acp_dma_start(acp_mmio, ACP_TO_SYSRAM_CH_NUM, false);
|
||||
|
||||
snd_pcm_period_elapsed(irq_data->capture_i2ssp_stream);
|
||||
acp_reg_write((intr_flag & BIT(I2S_TO_ACP_DMA_CH_NUM)) << 16,
|
||||
acp_mmio, mmACP_EXTERNAL_INTR_STAT);
|
||||
}
|
||||
|
||||
if ((intr_flag & BIT(ACP_TO_SYSRAM_CH_NUM)) != 0) {
|
||||
valid_irq = true;
|
||||
acp_reg_write((intr_flag & BIT(ACP_TO_SYSRAM_CH_NUM)) << 16,
|
||||
acp_mmio, mmACP_EXTERNAL_INTR_STAT);
|
||||
}
|
||||
|
||||
if ((intr_flag & BIT(I2S_TO_ACP_DMA_BT_INSTANCE_CH_NUM)) != 0) {
|
||||
valid_irq = true;
|
||||
if (acp_reg_read(acp_mmio, mmACP_DMA_CUR_DSCR_10) ==
|
||||
CAPTURE_START_DMA_DESCR_CH11)
|
||||
dscr_idx = CAPTURE_END_DMA_DESCR_CH10;
|
||||
else
|
||||
dscr_idx = CAPTURE_START_DMA_DESCR_CH10;
|
||||
config_acp_dma_channel(acp_mmio,
|
||||
ACP_TO_SYSRAM_BT_INSTANCE_CH_NUM,
|
||||
dscr_idx, 1, 0);
|
||||
acp_dma_start(acp_mmio, ACP_TO_SYSRAM_BT_INSTANCE_CH_NUM,
|
||||
false);
|
||||
|
||||
snd_pcm_period_elapsed(irq_data->capture_i2sbt_stream);
|
||||
acp_reg_write((intr_flag &
|
||||
BIT(I2S_TO_ACP_DMA_BT_INSTANCE_CH_NUM)) << 16,
|
||||
acp_mmio, mmACP_EXTERNAL_INTR_STAT);
|
||||
}
|
||||
|
||||
if ((intr_flag & BIT(ACP_TO_SYSRAM_BT_INSTANCE_CH_NUM)) != 0) {
|
||||
valid_irq = true;
|
||||
acp_reg_write((intr_flag &
|
||||
BIT(ACP_TO_SYSRAM_BT_INSTANCE_CH_NUM)) << 16,
|
||||
acp_mmio, mmACP_EXTERNAL_INTR_STAT);
|
||||
}
|
||||
|
||||
if (valid_irq)
|
||||
return IRQ_HANDLED;
|
||||
else
|
||||
@@ -773,8 +845,10 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream,
|
||||
if (WARN_ON(!rtd))
|
||||
return -EINVAL;
|
||||
|
||||
if (pinfo)
|
||||
if (pinfo) {
|
||||
rtd->i2s_instance = pinfo->i2s_instance;
|
||||
rtd->capture_channel = pinfo->capture_channel;
|
||||
}
|
||||
if (adata->asic_type == CHIP_STONEY) {
|
||||
val = acp_reg_read(adata->acp_mmio,
|
||||
mmACP_I2S_16BIT_RESOLUTION_EN);
|
||||
@@ -842,8 +916,8 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream,
|
||||
switch (rtd->i2s_instance) {
|
||||
case I2S_BT_INSTANCE:
|
||||
rtd->pte_offset = ACP_ST_BT_CAPTURE_PTE_OFFSET;
|
||||
rtd->ch1 = ACP_TO_SYSRAM_BT_INSTANCE_CH_NUM;
|
||||
rtd->ch2 = I2S_TO_ACP_DMA_BT_INSTANCE_CH_NUM;
|
||||
rtd->ch1 = I2S_TO_ACP_DMA_BT_INSTANCE_CH_NUM;
|
||||
rtd->ch2 = ACP_TO_SYSRAM_BT_INSTANCE_CH_NUM;
|
||||
rtd->sram_bank = ACP_SRAM_BANK_4_ADDRESS;
|
||||
rtd->destination = FROM_BLUETOOTH;
|
||||
rtd->dma_dscr_idx_1 = CAPTURE_START_DMA_DESCR_CH10;
|
||||
@@ -852,13 +926,14 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream,
|
||||
mmACP_I2S_BT_RECEIVE_BYTE_CNT_HIGH;
|
||||
rtd->byte_cnt_low_reg_offset =
|
||||
mmACP_I2S_BT_RECEIVE_BYTE_CNT_LOW;
|
||||
rtd->dma_curr_dscr = mmACP_DMA_CUR_DSCR_11;
|
||||
adata->capture_i2sbt_stream = substream;
|
||||
break;
|
||||
case I2S_SP_INSTANCE:
|
||||
default:
|
||||
rtd->pte_offset = ACP_CAPTURE_PTE_OFFSET;
|
||||
rtd->ch1 = ACP_TO_SYSRAM_CH_NUM;
|
||||
rtd->ch2 = I2S_TO_ACP_DMA_CH_NUM;
|
||||
rtd->ch1 = I2S_TO_ACP_DMA_CH_NUM;
|
||||
rtd->ch2 = ACP_TO_SYSRAM_CH_NUM;
|
||||
switch (adata->asic_type) {
|
||||
case CHIP_STONEY:
|
||||
rtd->pte_offset = ACP_ST_CAPTURE_PTE_OFFSET;
|
||||
@@ -875,6 +950,7 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream,
|
||||
mmACP_I2S_RECEIVED_BYTE_CNT_HIGH;
|
||||
rtd->byte_cnt_low_reg_offset =
|
||||
mmACP_I2S_RECEIVED_BYTE_CNT_LOW;
|
||||
rtd->dma_curr_dscr = mmACP_DMA_CUR_DSCR_15;
|
||||
adata->capture_i2ssp_stream = substream;
|
||||
}
|
||||
}
|
||||
@@ -928,6 +1004,8 @@ static snd_pcm_uframes_t acp_dma_pointer(struct snd_pcm_substream *substream)
|
||||
u32 buffersize;
|
||||
u32 pos = 0;
|
||||
u64 bytescount = 0;
|
||||
u16 dscr;
|
||||
u32 period_bytes, delay;
|
||||
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct audio_substream_data *rtd = runtime->private_data;
|
||||
@@ -935,12 +1013,25 @@ static snd_pcm_uframes_t acp_dma_pointer(struct snd_pcm_substream *substream)
|
||||
if (!rtd)
|
||||
return -EINVAL;
|
||||
|
||||
buffersize = frames_to_bytes(runtime, runtime->buffer_size);
|
||||
bytescount = acp_get_byte_count(rtd);
|
||||
|
||||
if (bytescount > rtd->bytescount)
|
||||
bytescount -= rtd->bytescount;
|
||||
pos = do_div(bytescount, buffersize);
|
||||
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
|
||||
period_bytes = frames_to_bytes(runtime, runtime->period_size);
|
||||
dscr = acp_reg_read(rtd->acp_mmio, rtd->dma_curr_dscr);
|
||||
if (dscr == rtd->dma_dscr_idx_1)
|
||||
pos = period_bytes;
|
||||
else
|
||||
pos = 0;
|
||||
bytescount = acp_get_byte_count(rtd);
|
||||
if (bytescount > rtd->bytescount)
|
||||
bytescount -= rtd->bytescount;
|
||||
delay = do_div(bytescount, period_bytes);
|
||||
runtime->delay = bytes_to_frames(runtime, delay);
|
||||
} else {
|
||||
buffersize = frames_to_bytes(runtime, runtime->buffer_size);
|
||||
bytescount = acp_get_byte_count(rtd);
|
||||
if (bytescount > rtd->bytescount)
|
||||
bytescount -= rtd->bytescount;
|
||||
pos = do_div(bytescount, buffersize);
|
||||
}
|
||||
return bytes_to_frames(runtime, pos);
|
||||
}
|
||||
|
||||
@@ -954,16 +1045,24 @@ static int acp_dma_prepare(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct audio_substream_data *rtd = runtime->private_data;
|
||||
u16 ch_acp_sysmem, ch_acp_i2s;
|
||||
|
||||
if (!rtd)
|
||||
return -EINVAL;
|
||||
|
||||
if (rtd->direction == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
ch_acp_sysmem = rtd->ch1;
|
||||
ch_acp_i2s = rtd->ch2;
|
||||
} else {
|
||||
ch_acp_i2s = rtd->ch1;
|
||||
ch_acp_sysmem = rtd->ch2;
|
||||
}
|
||||
config_acp_dma_channel(rtd->acp_mmio,
|
||||
rtd->ch1,
|
||||
ch_acp_sysmem,
|
||||
rtd->dma_dscr_idx_1,
|
||||
NUM_DSCRS_PER_CHANNEL, 0);
|
||||
config_acp_dma_channel(rtd->acp_mmio,
|
||||
rtd->ch2,
|
||||
ch_acp_i2s,
|
||||
rtd->dma_dscr_idx_2,
|
||||
NUM_DSCRS_PER_CHANNEL, 0);
|
||||
return 0;
|
||||
@@ -972,7 +1071,6 @@ static int acp_dma_prepare(struct snd_pcm_substream *substream)
|
||||
static int acp_dma_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
{
|
||||
int ret;
|
||||
u64 bytescount = 0;
|
||||
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct audio_substream_data *rtd = runtime->private_data;
|
||||
@@ -983,37 +1081,32 @@ static int acp_dma_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||
case SNDRV_PCM_TRIGGER_RESUME:
|
||||
bytescount = acp_get_byte_count(rtd);
|
||||
if (rtd->bytescount == 0)
|
||||
rtd->bytescount = bytescount;
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
acp_dma_start(rtd->acp_mmio, rtd->ch1);
|
||||
acp_dma_start(rtd->acp_mmio, rtd->ch2);
|
||||
rtd->bytescount = acp_get_byte_count(rtd);
|
||||
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
|
||||
if (rtd->capture_channel == CAP_CHANNEL0) {
|
||||
acp_dma_cap_channel_disable(rtd->acp_mmio,
|
||||
CAP_CHANNEL1);
|
||||
acp_dma_cap_channel_enable(rtd->acp_mmio,
|
||||
CAP_CHANNEL0);
|
||||
}
|
||||
if (rtd->capture_channel == CAP_CHANNEL1) {
|
||||
acp_dma_cap_channel_disable(rtd->acp_mmio,
|
||||
CAP_CHANNEL0);
|
||||
acp_dma_cap_channel_enable(rtd->acp_mmio,
|
||||
CAP_CHANNEL1);
|
||||
}
|
||||
acp_dma_start(rtd->acp_mmio, rtd->ch1, true);
|
||||
} else {
|
||||
acp_dma_start(rtd->acp_mmio, rtd->ch2);
|
||||
acp_dma_start(rtd->acp_mmio, rtd->ch1);
|
||||
acp_dma_start(rtd->acp_mmio, rtd->ch1, true);
|
||||
acp_dma_start(rtd->acp_mmio, rtd->ch2, true);
|
||||
}
|
||||
ret = 0;
|
||||
break;
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
/* For playback, non circular dma should be stopped first
|
||||
* i.e Sysram to acp dma transfer channel(rtd->ch1) should be
|
||||
* stopped before stopping cirular dma which is acp sram to i2s
|
||||
* fifo dma transfer channel(rtd->ch2). Where as in Capture
|
||||
* scenario, i2s fifo to acp sram dma channel(rtd->ch2) stopped
|
||||
* first before stopping acp sram to sysram which is circular
|
||||
* dma(rtd->ch1).
|
||||
*/
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
acp_dma_stop(rtd->acp_mmio, rtd->ch1);
|
||||
ret = acp_dma_stop(rtd->acp_mmio, rtd->ch2);
|
||||
} else {
|
||||
acp_dma_stop(rtd->acp_mmio, rtd->ch2);
|
||||
ret = acp_dma_stop(rtd->acp_mmio, rtd->ch1);
|
||||
}
|
||||
rtd->bytescount = 0;
|
||||
acp_dma_stop(rtd->acp_mmio, rtd->ch2);
|
||||
ret = acp_dma_stop(rtd->acp_mmio, rtd->ch1);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
|
@@ -55,6 +55,8 @@
|
||||
|
||||
#define I2S_SP_INSTANCE 0x01
|
||||
#define I2S_BT_INSTANCE 0x02
|
||||
#define CAP_CHANNEL0 0x00
|
||||
#define CAP_CHANNEL1 0x01
|
||||
|
||||
#define ACP_TILE_ON_MASK 0x03
|
||||
#define ACP_TILE_OFF_MASK 0x02
|
||||
@@ -72,16 +74,16 @@
|
||||
#define ACP_TO_I2S_DMA_CH_NUM 13
|
||||
|
||||
/* Capture DMA channels */
|
||||
#define ACP_TO_SYSRAM_CH_NUM 14
|
||||
#define I2S_TO_ACP_DMA_CH_NUM 15
|
||||
#define I2S_TO_ACP_DMA_CH_NUM 14
|
||||
#define ACP_TO_SYSRAM_CH_NUM 15
|
||||
|
||||
/* Playback DMA Channels for I2S BT instance */
|
||||
#define SYSRAM_TO_ACP_BT_INSTANCE_CH_NUM 8
|
||||
#define ACP_TO_I2S_DMA_BT_INSTANCE_CH_NUM 9
|
||||
|
||||
/* Capture DMA Channels for I2S BT Instance */
|
||||
#define ACP_TO_SYSRAM_BT_INSTANCE_CH_NUM 10
|
||||
#define I2S_TO_ACP_DMA_BT_INSTANCE_CH_NUM 11
|
||||
#define I2S_TO_ACP_DMA_BT_INSTANCE_CH_NUM 10
|
||||
#define ACP_TO_SYSRAM_BT_INSTANCE_CH_NUM 11
|
||||
|
||||
#define NUM_DSCRS_PER_CHANNEL 2
|
||||
|
||||
@@ -125,6 +127,7 @@ struct audio_substream_data {
|
||||
unsigned int order;
|
||||
u16 num_of_pages;
|
||||
u16 i2s_instance;
|
||||
u16 capture_channel;
|
||||
u16 direction;
|
||||
u16 ch1;
|
||||
u16 ch2;
|
||||
@@ -135,6 +138,7 @@ struct audio_substream_data {
|
||||
u32 sram_bank;
|
||||
u32 byte_cnt_high_reg_offset;
|
||||
u32 byte_cnt_low_reg_offset;
|
||||
u32 dma_curr_dscr;
|
||||
uint64_t size;
|
||||
u64 bytescount;
|
||||
void __iomem *acp_mmio;
|
||||
@@ -155,6 +159,7 @@ struct audio_drv_data {
|
||||
*/
|
||||
struct acp_platform_info {
|
||||
u16 i2s_instance;
|
||||
u16 capture_channel;
|
||||
};
|
||||
|
||||
union acp_dma_count {
|
||||
|
@@ -206,7 +206,6 @@ struct atmel_i2s_dev {
|
||||
struct regmap *regmap;
|
||||
struct clk *pclk;
|
||||
struct clk *gclk;
|
||||
struct clk *aclk;
|
||||
struct snd_dmaengine_dai_dma_data playback;
|
||||
struct snd_dmaengine_dai_dma_data capture;
|
||||
unsigned int fmt;
|
||||
@@ -303,7 +302,7 @@ static int atmel_i2s_get_gck_param(struct atmel_i2s_dev *dev, int fs)
|
||||
{
|
||||
int i, best;
|
||||
|
||||
if (!dev->gclk || !dev->aclk) {
|
||||
if (!dev->gclk) {
|
||||
dev_err(dev->dev, "cannot generate the I2S Master Clock\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -421,7 +420,7 @@ static int atmel_i2s_switch_mck_generator(struct atmel_i2s_dev *dev,
|
||||
bool enabled)
|
||||
{
|
||||
unsigned int mr, mr_mask;
|
||||
unsigned long aclk_rate;
|
||||
unsigned long gclk_rate;
|
||||
int ret;
|
||||
|
||||
mr = 0;
|
||||
@@ -445,35 +444,18 @@ static int atmel_i2s_switch_mck_generator(struct atmel_i2s_dev *dev,
|
||||
/* Disable/unprepare the PMC generated clock. */
|
||||
clk_disable_unprepare(dev->gclk);
|
||||
|
||||
/* Disable/unprepare the PLL audio clock. */
|
||||
clk_disable_unprepare(dev->aclk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!dev->gck_param)
|
||||
return -EINVAL;
|
||||
|
||||
aclk_rate = dev->gck_param->mck * (dev->gck_param->imckdiv + 1);
|
||||
gclk_rate = dev->gck_param->mck * (dev->gck_param->imckdiv + 1);
|
||||
|
||||
/* Fist change the PLL audio clock frequency ... */
|
||||
ret = clk_set_rate(dev->aclk, aclk_rate);
|
||||
ret = clk_set_rate(dev->gclk, gclk_rate);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* ... then set the PMC generated clock rate to the very same frequency
|
||||
* to set the gclk parent to aclk.
|
||||
*/
|
||||
ret = clk_set_rate(dev->gclk, aclk_rate);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Prepare and enable the PLL audio clock first ... */
|
||||
ret = clk_prepare_enable(dev->aclk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* ... then prepare and enable the PMC generated clock. */
|
||||
ret = clk_prepare_enable(dev->gclk);
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -668,28 +650,14 @@ static int atmel_i2s_probe(struct platform_device *pdev)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Get audio clocks to generate the I2S Master Clock (I2S_MCK) */
|
||||
dev->aclk = devm_clk_get(&pdev->dev, "aclk");
|
||||
/* Get audio clock to generate the I2S Master Clock (I2S_MCK) */
|
||||
dev->gclk = devm_clk_get(&pdev->dev, "gclk");
|
||||
if (IS_ERR(dev->aclk) && IS_ERR(dev->gclk)) {
|
||||
if (PTR_ERR(dev->aclk) == -EPROBE_DEFER ||
|
||||
PTR_ERR(dev->gclk) == -EPROBE_DEFER)
|
||||
if (IS_ERR(dev->gclk)) {
|
||||
if (PTR_ERR(dev->gclk) == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
/* Master Mode not supported */
|
||||
dev->aclk = NULL;
|
||||
dev->gclk = NULL;
|
||||
} else if (IS_ERR(dev->gclk)) {
|
||||
err = PTR_ERR(dev->gclk);
|
||||
dev_err(&pdev->dev,
|
||||
"failed to get the PMC generated clock: %d\n", err);
|
||||
return err;
|
||||
} else if (IS_ERR(dev->aclk)) {
|
||||
err = PTR_ERR(dev->aclk);
|
||||
dev_err(&pdev->dev,
|
||||
"failed to get the PLL audio clock: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
dev->dev = &pdev->dev;
|
||||
dev->regmap = regmap;
|
||||
platform_set_drvdata(pdev, dev);
|
||||
|
@@ -74,12 +74,12 @@ config SND_SOC_ALL_CODECS
|
||||
select SND_SOC_DA7219 if I2C
|
||||
select SND_SOC_DA732X if I2C
|
||||
select SND_SOC_DA9055 if I2C
|
||||
select SND_SOC_DIO2125
|
||||
select SND_SOC_DMIC if GPIOLIB
|
||||
select SND_SOC_ES8316 if I2C
|
||||
select SND_SOC_ES8328_SPI if SPI_MASTER
|
||||
select SND_SOC_ES8328_I2C if I2C
|
||||
select SND_SOC_ES7134
|
||||
select SND_SOC_ES7241
|
||||
select SND_SOC_GTM601
|
||||
select SND_SOC_HDAC_HDMI
|
||||
select SND_SOC_ICS43432
|
||||
@@ -141,8 +141,10 @@ config SND_SOC_ALL_CODECS
|
||||
select SND_SOC_RT5668 if I2C
|
||||
select SND_SOC_RT5670 if I2C
|
||||
select SND_SOC_RT5677 if I2C && SPI_MASTER
|
||||
select SND_SOC_RT5682 if I2C
|
||||
select SND_SOC_SGTL5000 if I2C
|
||||
select SND_SOC_SI476X if MFD_SI476X_CORE
|
||||
select SND_SOC_SIMPLE_AMPLIFIER
|
||||
select SND_SOC_SIRF_AUDIO_CODEC
|
||||
select SND_SOC_SPDIF
|
||||
select SND_SOC_SSM2305
|
||||
@@ -572,10 +574,6 @@ config SND_SOC_DA732X
|
||||
config SND_SOC_DA9055
|
||||
tristate
|
||||
|
||||
config SND_SOC_DIO2125
|
||||
tristate "Dioo DIO2125 Amplifier"
|
||||
select GPIOLIB
|
||||
|
||||
config SND_SOC_DMIC
|
||||
tristate
|
||||
|
||||
@@ -588,6 +586,9 @@ config SND_SOC_HDMI_CODEC
|
||||
config SND_SOC_ES7134
|
||||
tristate "Everest Semi ES7134 CODEC"
|
||||
|
||||
config SND_SOC_ES7241
|
||||
tristate "Everest Semi ES7241 CODEC"
|
||||
|
||||
config SND_SOC_ES8316
|
||||
tristate "Everest Semi ES8316 CODEC"
|
||||
depends on I2C
|
||||
@@ -778,6 +779,7 @@ config SND_SOC_RL6231
|
||||
default y if SND_SOC_RT5668=y
|
||||
default y if SND_SOC_RT5670=y
|
||||
default y if SND_SOC_RT5677=y
|
||||
default y if SND_SOC_RT5682=y
|
||||
default y if SND_SOC_RT1305=y
|
||||
default m if SND_SOC_RT5514=m
|
||||
default m if SND_SOC_RT5616=m
|
||||
@@ -791,6 +793,7 @@ config SND_SOC_RL6231
|
||||
default m if SND_SOC_RT5668=m
|
||||
default m if SND_SOC_RT5670=m
|
||||
default m if SND_SOC_RT5677=m
|
||||
default m if SND_SOC_RT5682=m
|
||||
default m if SND_SOC_RT1305=m
|
||||
|
||||
config SND_SOC_RL6347A
|
||||
@@ -871,6 +874,9 @@ config SND_SOC_RT5677_SPI
|
||||
tristate
|
||||
default SND_SOC_RT5677 && SPI
|
||||
|
||||
config SND_SOC_RT5682
|
||||
tristate
|
||||
|
||||
#Freescale sgtl5000 codec
|
||||
config SND_SOC_SGTL5000
|
||||
tristate "Freescale SGTL5000 CODEC"
|
||||
@@ -891,6 +897,10 @@ config SND_SOC_SIGMADSP_REGMAP
|
||||
tristate
|
||||
select SND_SOC_SIGMADSP
|
||||
|
||||
config SND_SOC_SIMPLE_AMPLIFIER
|
||||
tristate "Simple Audio Amplifier"
|
||||
select GPIOLIB
|
||||
|
||||
config SND_SOC_SIRF_AUDIO_CODEC
|
||||
tristate "SiRF SoC internal audio codec"
|
||||
select REGMAP_MMIO
|
||||
@@ -953,8 +963,11 @@ config SND_SOC_TAS5086
|
||||
depends on I2C
|
||||
|
||||
config SND_SOC_TAS571X
|
||||
tristate "Texas Instruments TAS5711/TAS5717/TAS5719/TAS5721 power amplifiers"
|
||||
tristate "Texas Instruments TAS571x power amplifiers"
|
||||
depends on I2C
|
||||
help
|
||||
Enable support for Texas Instruments TAS5707, TAS5711, TAS5717,
|
||||
TAS5719 and TAS5721 power amplifiers
|
||||
|
||||
config SND_SOC_TAS5720
|
||||
tristate "Texas Instruments TAS5720 Mono Audio amplifier"
|
||||
|
@@ -71,6 +71,7 @@ snd-soc-da732x-objs := da732x.o
|
||||
snd-soc-da9055-objs := da9055.o
|
||||
snd-soc-dmic-objs := dmic.o
|
||||
snd-soc-es7134-objs := es7134.o
|
||||
snd-soc-es7241-objs := es7241.o
|
||||
snd-soc-es8316-objs := es8316.o
|
||||
snd-soc-es8328-objs := es8328.o
|
||||
snd-soc-es8328-i2c-objs := es8328-i2c.o
|
||||
@@ -146,6 +147,7 @@ snd-soc-rt5668-objs := rt5668.o
|
||||
snd-soc-rt5670-objs := rt5670.o
|
||||
snd-soc-rt5677-objs := rt5677.o
|
||||
snd-soc-rt5677-spi-objs := rt5677-spi.o
|
||||
snd-soc-rt5682-objs := rt5682.o
|
||||
snd-soc-sgtl5000-objs := sgtl5000.o
|
||||
snd-soc-alc5623-objs := alc5623.o
|
||||
snd-soc-alc5632-objs := alc5632.o
|
||||
@@ -249,9 +251,9 @@ snd-soc-wm9713-objs := wm9713.o
|
||||
snd-soc-wm-hubs-objs := wm_hubs.o
|
||||
snd-soc-zx-aud96p22-objs := zx_aud96p22.o
|
||||
# Amp
|
||||
snd-soc-dio2125-objs := dio2125.o
|
||||
snd-soc-max9877-objs := max9877.o
|
||||
snd-soc-max98504-objs := max98504.o
|
||||
snd-soc-simple-amplifier-objs := simple-amplifier.o
|
||||
snd-soc-tpa6130a2-objs := tpa6130a2.o
|
||||
snd-soc-tas2552-objs := tas2552.o
|
||||
|
||||
@@ -329,6 +331,7 @@ obj-$(CONFIG_SND_SOC_DA732X) += snd-soc-da732x.o
|
||||
obj-$(CONFIG_SND_SOC_DA9055) += snd-soc-da9055.o
|
||||
obj-$(CONFIG_SND_SOC_DMIC) += snd-soc-dmic.o
|
||||
obj-$(CONFIG_SND_SOC_ES7134) += snd-soc-es7134.o
|
||||
obj-$(CONFIG_SND_SOC_ES7241) += snd-soc-es7241.o
|
||||
obj-$(CONFIG_SND_SOC_ES8316) += snd-soc-es8316.o
|
||||
obj-$(CONFIG_SND_SOC_ES8328) += snd-soc-es8328.o
|
||||
obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.o
|
||||
@@ -405,6 +408,7 @@ obj-$(CONFIG_SND_SOC_RT5668) += snd-soc-rt5668.o
|
||||
obj-$(CONFIG_SND_SOC_RT5670) += snd-soc-rt5670.o
|
||||
obj-$(CONFIG_SND_SOC_RT5677) += snd-soc-rt5677.o
|
||||
obj-$(CONFIG_SND_SOC_RT5677_SPI) += snd-soc-rt5677-spi.o
|
||||
obj-$(CONFIG_SND_SOC_RT5682) += snd-soc-rt5682.o
|
||||
obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o
|
||||
obj-$(CONFIG_SND_SOC_SIGMADSP) += snd-soc-sigmadsp.o
|
||||
obj-$(CONFIG_SND_SOC_SIGMADSP_I2C) += snd-soc-sigmadsp-i2c.o
|
||||
@@ -507,7 +511,7 @@ obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o
|
||||
obj-$(CONFIG_SND_SOC_ZX_AUD96P22) += snd-soc-zx-aud96p22.o
|
||||
|
||||
# Amp
|
||||
obj-$(CONFIG_SND_SOC_DIO2125) += snd-soc-dio2125.o
|
||||
obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o
|
||||
obj-$(CONFIG_SND_SOC_MAX98504) += snd-soc-max98504.o
|
||||
obj-$(CONFIG_SND_SOC_SIMPLE_AMPLIFIER) += snd-soc-simple-amplifier.o
|
||||
obj-$(CONFIG_SND_SOC_TPA6130A2) += snd-soc-tpa6130a2.o
|
||||
|
@@ -299,6 +299,7 @@ static const struct snd_soc_dapm_route adau17x1_dsp_dapm_routes[] = {
|
||||
|
||||
{ "DSP", NULL, "Left Decimator" },
|
||||
{ "DSP", NULL, "Right Decimator" },
|
||||
{ "DSP", NULL, "Playback" },
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route adau17x1_no_dsp_dapm_routes[] = {
|
||||
|
@@ -648,6 +648,7 @@ static int adav80x_set_pll(struct snd_soc_component *component, int pll_id,
|
||||
pll_ctrl1 |= ADAV80X_PLL_CTRL1_PLLDIV;
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@@ -558,7 +558,7 @@ static int __maybe_unused ak4458_runtime_resume(struct device *dev)
|
||||
}
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
struct snd_soc_component_driver soc_codec_dev_ak4458 = {
|
||||
static const struct snd_soc_component_driver soc_codec_dev_ak4458 = {
|
||||
.probe = ak4458_probe,
|
||||
.remove = ak4458_remove,
|
||||
.controls = ak4458_snd_controls,
|
||||
|
@@ -1,13 +1,8 @@
|
||||
/*
|
||||
* ak4554.c
|
||||
*
|
||||
* Copyright (C) 2013 Renesas Solutions Corp.
|
||||
* Kuninori Morimoto <kuninori.morimoto.gx@renesas.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.
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// ak4554.c
|
||||
//
|
||||
// Copyright (C) 2013 Renesas Solutions Corp.
|
||||
// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <sound/soc.h>
|
||||
@@ -97,6 +92,6 @@ static struct platform_driver ak4554_driver = {
|
||||
};
|
||||
module_platform_driver(ak4554_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DESCRIPTION("SoC AK4554 driver");
|
||||
MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
|
||||
|
@@ -1,18 +1,14 @@
|
||||
/*
|
||||
* ak4613.c -- Asahi Kasei ALSA Soc Audio driver
|
||||
*
|
||||
* Copyright (C) 2015 Renesas Electronics Corporation
|
||||
* Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
|
||||
*
|
||||
* Based on ak4642.c by Kuninori Morimoto
|
||||
* Based on wm8731.c by Richard Purdie
|
||||
* Based on ak4535.c by Richard Purdie
|
||||
* Based on wm8753.c by Liam Girdwood
|
||||
*
|
||||
* 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
|
||||
//
|
||||
// ak4613.c -- Asahi Kasei ALSA Soc Audio driver
|
||||
//
|
||||
// Copyright (C) 2015 Renesas Electronics Corporation
|
||||
// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
|
||||
//
|
||||
// Based on ak4642.c by Kuninori Morimoto
|
||||
// Based on wm8731.c by Richard Purdie
|
||||
// Based on ak4535.c by Richard Purdie
|
||||
// Based on wm8753.c by Liam Girdwood
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
|
@@ -1,17 +1,13 @@
|
||||
/*
|
||||
* ak4642.c -- AK4642/AK4643 ALSA Soc Audio driver
|
||||
*
|
||||
* Copyright (C) 2009 Renesas Solutions Corp.
|
||||
* Kuninori Morimoto <morimoto.kuninori@renesas.com>
|
||||
*
|
||||
* Based on wm8731.c by Richard Purdie
|
||||
* Based on ak4535.c by Richard Purdie
|
||||
* Based on wm8753.c by Liam Girdwood
|
||||
*
|
||||
* 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
|
||||
//
|
||||
// ak4642.c -- AK4642/AK4643 ALSA Soc Audio driver
|
||||
//
|
||||
// Copyright (C) 2009 Renesas Solutions Corp.
|
||||
// Kuninori Morimoto <morimoto.kuninori@renesas.com>
|
||||
//
|
||||
// Based on wm8731.c by Richard Purdie
|
||||
// Based on ak4535.c by Richard Purdie
|
||||
// Based on wm8753.c by Liam Girdwood
|
||||
|
||||
/* ** CAUTION **
|
||||
*
|
||||
@@ -709,4 +705,4 @@ module_i2c_driver(ak4642_i2c_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Soc AK4642 driver");
|
||||
MODULE_AUTHOR("Kuninori Morimoto <morimoto.kuninori@renesas.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
@@ -322,13 +322,13 @@ static int __maybe_unused ak5558_runtime_resume(struct device *dev)
|
||||
return regcache_sync(ak5558->regmap);
|
||||
}
|
||||
|
||||
const struct dev_pm_ops ak5558_pm = {
|
||||
static const struct dev_pm_ops ak5558_pm = {
|
||||
SET_RUNTIME_PM_OPS(ak5558_runtime_suspend, ak5558_runtime_resume, NULL)
|
||||
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
|
||||
pm_runtime_force_resume)
|
||||
};
|
||||
|
||||
struct snd_soc_component_driver soc_codec_dev_ak5558 = {
|
||||
static const struct snd_soc_component_driver soc_codec_dev_ak5558 = {
|
||||
.probe = ak5558_probe,
|
||||
.remove = ak5558_remove,
|
||||
.controls = ak5558_snd_controls,
|
||||
|
@@ -219,7 +219,7 @@ static bool cs4270_reg_is_volatile(struct device *dev, unsigned int reg)
|
||||
{
|
||||
/* Unreadable registers are considered volatile */
|
||||
if ((reg < CS4270_FIRSTREG) || (reg > CS4270_LASTREG))
|
||||
return 1;
|
||||
return true;
|
||||
|
||||
return reg == CS4270_CHIPID;
|
||||
}
|
||||
|
@@ -235,6 +235,9 @@ ARIZONA_MIXER_CONTROLS("AIF2TX6", ARIZONA_AIF2TX6MIX_INPUT_1_SOURCE),
|
||||
|
||||
ARIZONA_MIXER_CONTROLS("AIF3TX1", ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE),
|
||||
ARIZONA_MIXER_CONTROLS("AIF3TX2", ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE),
|
||||
|
||||
WM_ADSP_FW_CONTROL("DSP2", 1),
|
||||
WM_ADSP_FW_CONTROL("DSP3", 2),
|
||||
};
|
||||
|
||||
ARIZONA_MIXER_ENUMS(EQ1, ARIZONA_EQ1MIX_INPUT_1_SOURCE);
|
||||
|
@@ -362,8 +362,27 @@ static int cx20442_component_probe(struct snd_soc_component *component)
|
||||
return -ENOMEM;
|
||||
|
||||
cx20442->por = regulator_get(component->dev, "POR");
|
||||
if (IS_ERR(cx20442->por))
|
||||
dev_warn(component->dev, "failed to get the regulator");
|
||||
if (IS_ERR(cx20442->por)) {
|
||||
int err = PTR_ERR(cx20442->por);
|
||||
|
||||
dev_warn(component->dev, "failed to get POR supply (%d)", err);
|
||||
/*
|
||||
* When running on a non-dt platform and requested regulator
|
||||
* is not available, regulator_get() never returns
|
||||
* -EPROBE_DEFER as it is not able to justify if the regulator
|
||||
* may still appear later. On the other hand, the board can
|
||||
* still set full constraints flag at late_initcall in order
|
||||
* to instruct regulator_get() to return a dummy one if
|
||||
* sufficient. Hence, if we get -ENODEV here, let's convert
|
||||
* it to -EPROBE_DEFER and wait for the board to decide or
|
||||
* let Deferred Probe infrastructure handle this error.
|
||||
*/
|
||||
if (err == -ENODEV)
|
||||
err = -EPROBE_DEFER;
|
||||
kfree(cx20442);
|
||||
return err;
|
||||
}
|
||||
|
||||
cx20442->tty = NULL;
|
||||
|
||||
snd_soc_component_set_drvdata(component, cx20442);
|
||||
|
@@ -1,19 +1,14 @@
|
||||
/*
|
||||
* DA7210 ALSA Soc codec driver
|
||||
*
|
||||
* Copyright (c) 2009 Dialog Semiconductor
|
||||
* Written by David Chen <Dajun.chen@diasemi.com>
|
||||
*
|
||||
* Copyright (C) 2009 Renesas Solutions Corp.
|
||||
* Cleanups by Kuninori Morimoto <morimoto.kuninori@renesas.com>
|
||||
*
|
||||
* Tested on SuperH Ecovec24 board with S16/S24 LE in 48KHz using I2S
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
//
|
||||
// DA7210 ALSA Soc codec driver
|
||||
//
|
||||
// Copyright (c) 2009 Dialog Semiconductor
|
||||
// Written by David Chen <Dajun.chen@diasemi.com>
|
||||
//
|
||||
// Copyright (C) 2009 Renesas Solutions Corp.
|
||||
// Cleanups by Kuninori Morimoto <morimoto.kuninori@renesas.com>
|
||||
//
|
||||
// Tested on SuperH Ecovec24 board with S16/S24 LE in 48KHz using I2S
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/i2c.h>
|
||||
|
@@ -1140,9 +1140,9 @@ static bool da7213_volatile_register(struct device *dev, unsigned int reg)
|
||||
case DA7213_ALC_OFFSET_AUTO_M_R:
|
||||
case DA7213_ALC_OFFSET_AUTO_U_R:
|
||||
case DA7213_ALC_CIC_OP_LVL_DATA:
|
||||
return 1;
|
||||
return true;
|
||||
default:
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -59,6 +59,7 @@ static void da7219_aad_btn_det_work(struct work_struct *work)
|
||||
container_of(work, struct da7219_aad_priv, btn_det_work);
|
||||
struct snd_soc_component *component = da7219_aad->component;
|
||||
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
|
||||
struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
|
||||
u8 statusa, micbias_ctrl;
|
||||
bool micbias_up = false;
|
||||
int retries = 0;
|
||||
@@ -86,6 +87,8 @@ static void da7219_aad_btn_det_work(struct work_struct *work)
|
||||
if (retries >= DA7219_AAD_MICBIAS_CHK_RETRIES)
|
||||
dev_warn(component->dev, "Mic bias status check timed out");
|
||||
|
||||
da7219->micbias_on_event = true;
|
||||
|
||||
/*
|
||||
* Mic bias pulse required to enable mic, must be done before enabling
|
||||
* button detection to prevent erroneous button readings.
|
||||
@@ -439,6 +442,8 @@ static irqreturn_t da7219_aad_irq_thread(int irq, void *data)
|
||||
snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_1,
|
||||
DA7219_BUTTON_CONFIG_MASK, 0);
|
||||
|
||||
da7219->micbias_on_event = false;
|
||||
|
||||
/* Disable mic bias */
|
||||
snd_soc_dapm_disable_pin(dapm, "Mic Bias");
|
||||
snd_soc_dapm_sync(dapm);
|
||||
|
@@ -768,6 +768,30 @@ static const struct snd_kcontrol_new da7219_st_out_filtr_mix_controls[] = {
|
||||
* DAPM Events
|
||||
*/
|
||||
|
||||
static int da7219_mic_pga_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
|
||||
struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
|
||||
|
||||
switch (event) {
|
||||
case SND_SOC_DAPM_POST_PMU:
|
||||
if (da7219->micbias_on_event) {
|
||||
/*
|
||||
* Delay only for first capture after bias enabled to
|
||||
* avoid possible DC offset related noise.
|
||||
*/
|
||||
da7219->micbias_on_event = false;
|
||||
msleep(da7219->mic_pga_delay);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int da7219_dai_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
@@ -937,12 +961,12 @@ static const struct snd_soc_dapm_widget da7219_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_INPUT("MIC"),
|
||||
|
||||
/* Input PGAs */
|
||||
SND_SOC_DAPM_PGA("Mic PGA", DA7219_MIC_1_CTRL,
|
||||
DA7219_MIC_1_AMP_EN_SHIFT, DA7219_NO_INVERT,
|
||||
NULL, 0),
|
||||
SND_SOC_DAPM_PGA("Mixin PGA", DA7219_MIXIN_L_CTRL,
|
||||
DA7219_MIXIN_L_AMP_EN_SHIFT, DA7219_NO_INVERT,
|
||||
NULL, 0),
|
||||
SND_SOC_DAPM_PGA_E("Mic PGA", DA7219_MIC_1_CTRL,
|
||||
DA7219_MIC_1_AMP_EN_SHIFT, DA7219_NO_INVERT,
|
||||
NULL, 0, da7219_mic_pga_event, SND_SOC_DAPM_POST_PMU),
|
||||
SND_SOC_DAPM_PGA_E("Mixin PGA", DA7219_MIXIN_L_CTRL,
|
||||
DA7219_MIXIN_L_AMP_EN_SHIFT, DA7219_NO_INVERT,
|
||||
NULL, 0, da7219_settling_event, SND_SOC_DAPM_POST_PMU),
|
||||
|
||||
/* Input Filters */
|
||||
SND_SOC_DAPM_ADC("ADC", NULL, DA7219_ADC_L_CTRL, DA7219_ADC_L_EN_SHIFT,
|
||||
@@ -1847,6 +1871,14 @@ static void da7219_handle_pdata(struct snd_soc_component *component)
|
||||
|
||||
snd_soc_component_write(component, DA7219_MICBIAS_CTRL, micbias_lvl);
|
||||
|
||||
/*
|
||||
* Calculate delay required to compensate for DC offset in
|
||||
* Mic PGA, based on Mic Bias voltage.
|
||||
*/
|
||||
da7219->mic_pga_delay = DA7219_MIC_PGA_BASE_DELAY +
|
||||
(pdata->micbias_lvl *
|
||||
DA7219_MIC_PGA_OFFSET_DELAY);
|
||||
|
||||
/* Mic */
|
||||
switch (pdata->mic_amp_in_sel) {
|
||||
case DA7219_MIC_AMP_IN_SEL_DIFF:
|
||||
@@ -2143,9 +2175,9 @@ static bool da7219_volatile_register(struct device *dev, unsigned int reg)
|
||||
case DA7219_ACCDET_IRQ_EVENT_B:
|
||||
case DA7219_ACCDET_CONFIG_8:
|
||||
case DA7219_SYSTEM_STATUS:
|
||||
return 1;
|
||||
return true;
|
||||
default:
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -781,8 +781,10 @@
|
||||
#define DA7219_SYS_STAT_CHECK_DELAY 50
|
||||
|
||||
/* Power up/down Delays */
|
||||
#define DA7219_SETTLING_DELAY 40
|
||||
#define DA7219_MIN_GAIN_DELAY 30
|
||||
#define DA7219_SETTLING_DELAY 40
|
||||
#define DA7219_MIN_GAIN_DELAY 30
|
||||
#define DA7219_MIC_PGA_BASE_DELAY 100
|
||||
#define DA7219_MIC_PGA_OFFSET_DELAY 40
|
||||
|
||||
enum da7219_clk_src {
|
||||
DA7219_CLKSRC_MCLK = 0,
|
||||
@@ -828,6 +830,8 @@ struct da7219_priv {
|
||||
|
||||
bool master;
|
||||
bool alc_en;
|
||||
bool micbias_on_event;
|
||||
unsigned int mic_pga_delay;
|
||||
u8 gain_ramp_ctrl;
|
||||
};
|
||||
|
||||
|
@@ -1041,9 +1041,9 @@ static bool da9055_volatile_register(struct device *dev,
|
||||
case DA9055_HP_R_GAIN_STATUS:
|
||||
case DA9055_LINE_GAIN_STATUS:
|
||||
case DA9055_ALC_CIC_OP_LVL_DATA:
|
||||
return 1;
|
||||
return true;
|
||||
default:
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -17,6 +17,7 @@
|
||||
* in the file called COPYING.
|
||||
*/
|
||||
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/module.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
@@ -24,6 +25,82 @@
|
||||
* The everest 7134 is a very simple DA converter with no register
|
||||
*/
|
||||
|
||||
struct es7134_clock_mode {
|
||||
unsigned int rate_min;
|
||||
unsigned int rate_max;
|
||||
unsigned int *mclk_fs;
|
||||
unsigned int mclk_fs_num;
|
||||
};
|
||||
|
||||
struct es7134_chip {
|
||||
struct snd_soc_dai_driver *dai_drv;
|
||||
const struct es7134_clock_mode *modes;
|
||||
unsigned int mode_num;
|
||||
const struct snd_soc_dapm_widget *extra_widgets;
|
||||
unsigned int extra_widget_num;
|
||||
const struct snd_soc_dapm_route *extra_routes;
|
||||
unsigned int extra_route_num;
|
||||
};
|
||||
|
||||
struct es7134_data {
|
||||
unsigned int mclk;
|
||||
const struct es7134_chip *chip;
|
||||
};
|
||||
|
||||
static int es7134_check_mclk(struct snd_soc_dai *dai,
|
||||
struct es7134_data *priv,
|
||||
unsigned int rate)
|
||||
{
|
||||
unsigned int mfs = priv->mclk / rate;
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < priv->chip->mode_num; i++) {
|
||||
const struct es7134_clock_mode *mode = &priv->chip->modes[i];
|
||||
|
||||
if (rate < mode->rate_min || rate > mode->rate_max)
|
||||
continue;
|
||||
|
||||
for (j = 0; j < mode->mclk_fs_num; j++) {
|
||||
if (mode->mclk_fs[j] == mfs)
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev_err(dai->dev, "unsupported mclk_fs %u for rate %u\n",
|
||||
mfs, rate);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* should not happen */
|
||||
dev_err(dai->dev, "unsupported rate: %u\n", rate);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int es7134_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct es7134_data *priv = snd_soc_dai_get_drvdata(dai);
|
||||
|
||||
/* mclk has not been provided, assume it is OK */
|
||||
if (!priv->mclk)
|
||||
return 0;
|
||||
|
||||
return es7134_check_mclk(dai, priv, params_rate(params));
|
||||
}
|
||||
|
||||
static int es7134_set_sysclk(struct snd_soc_dai *dai, int clk_id,
|
||||
unsigned int freq, int dir)
|
||||
{
|
||||
struct es7134_data *priv = snd_soc_dai_get_drvdata(dai);
|
||||
|
||||
if (dir == SND_SOC_CLOCK_IN && clk_id == 0) {
|
||||
priv->mclk = freq;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
static int es7134_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
|
||||
{
|
||||
fmt &= (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_INV_MASK |
|
||||
@@ -38,8 +115,38 @@ static int es7134_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int es7134_component_probe(struct snd_soc_component *c)
|
||||
{
|
||||
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(c);
|
||||
struct es7134_data *priv = snd_soc_component_get_drvdata(c);
|
||||
const struct es7134_chip *chip = priv->chip;
|
||||
int ret;
|
||||
|
||||
if (chip->extra_widget_num) {
|
||||
ret = snd_soc_dapm_new_controls(dapm, chip->extra_widgets,
|
||||
chip->extra_widget_num);
|
||||
if (ret) {
|
||||
dev_err(c->dev, "failed to add extra widgets\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (chip->extra_route_num) {
|
||||
ret = snd_soc_dapm_add_routes(dapm, chip->extra_routes,
|
||||
chip->extra_route_num);
|
||||
if (ret) {
|
||||
dev_err(c->dev, "failed to add extra routes\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_soc_dai_ops es7134_dai_ops = {
|
||||
.set_fmt = es7134_set_fmt,
|
||||
.hw_params = es7134_hw_params,
|
||||
.set_sysclk = es7134_set_sysclk,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver es7134_dai = {
|
||||
@@ -48,7 +155,11 @@ static struct snd_soc_dai_driver es7134_dai = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.rates = SNDRV_PCM_RATE_8000_192000,
|
||||
.rates = (SNDRV_PCM_RATE_8000_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_S18_3LE |
|
||||
SNDRV_PCM_FMTBIT_S20_3LE |
|
||||
@@ -58,18 +169,56 @@ static struct snd_soc_dai_driver es7134_dai = {
|
||||
.ops = &es7134_dai_ops,
|
||||
};
|
||||
|
||||
static const struct es7134_clock_mode es7134_modes[] = {
|
||||
{
|
||||
/* Single speed mode */
|
||||
.rate_min = 8000,
|
||||
.rate_max = 50000,
|
||||
.mclk_fs = (unsigned int[]) { 256, 384, 512, 768, 1024 },
|
||||
.mclk_fs_num = 5,
|
||||
}, {
|
||||
/* Double speed mode */
|
||||
.rate_min = 84000,
|
||||
.rate_max = 100000,
|
||||
.mclk_fs = (unsigned int[]) { 128, 192, 256, 384, 512 },
|
||||
.mclk_fs_num = 5,
|
||||
}, {
|
||||
/* Quad speed mode */
|
||||
.rate_min = 167000,
|
||||
.rate_max = 192000,
|
||||
.mclk_fs = (unsigned int[]) { 128, 192, 256 },
|
||||
.mclk_fs_num = 3,
|
||||
},
|
||||
};
|
||||
|
||||
/* Digital I/O are also supplied by VDD on the es7134 */
|
||||
static const struct snd_soc_dapm_route es7134_extra_routes[] = {
|
||||
{ "Playback", NULL, "VDD", }
|
||||
};
|
||||
|
||||
static const struct es7134_chip es7134_chip = {
|
||||
.dai_drv = &es7134_dai,
|
||||
.modes = es7134_modes,
|
||||
.mode_num = ARRAY_SIZE(es7134_modes),
|
||||
.extra_routes = es7134_extra_routes,
|
||||
.extra_route_num = ARRAY_SIZE(es7134_extra_routes),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget es7134_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_OUTPUT("AOUTL"),
|
||||
SND_SOC_DAPM_OUTPUT("AOUTR"),
|
||||
SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0),
|
||||
SND_SOC_DAPM_REGULATOR_SUPPLY("VDD", 0, 0),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route es7134_dapm_routes[] = {
|
||||
{ "AOUTL", NULL, "DAC" },
|
||||
{ "AOUTR", NULL, "DAC" },
|
||||
{ "DAC", NULL, "VDD" },
|
||||
};
|
||||
|
||||
static const struct snd_soc_component_driver es7134_component_driver = {
|
||||
.probe = es7134_component_probe,
|
||||
.dapm_widgets = es7134_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(es7134_dapm_widgets),
|
||||
.dapm_routes = es7134_dapm_routes,
|
||||
@@ -80,17 +229,87 @@ static const struct snd_soc_component_driver es7134_component_driver = {
|
||||
.non_legacy_dai_naming = 1,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver es7154_dai = {
|
||||
.name = "es7154-hifi",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.rates = (SNDRV_PCM_RATE_8000_48000 |
|
||||
SNDRV_PCM_RATE_88200 |
|
||||
SNDRV_PCM_RATE_96000),
|
||||
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S18_3LE |
|
||||
SNDRV_PCM_FMTBIT_S20_3LE |
|
||||
SNDRV_PCM_FMTBIT_S24_3LE |
|
||||
SNDRV_PCM_FMTBIT_S24_LE),
|
||||
},
|
||||
.ops = &es7134_dai_ops,
|
||||
};
|
||||
|
||||
static const struct es7134_clock_mode es7154_modes[] = {
|
||||
{
|
||||
/* Single speed mode */
|
||||
.rate_min = 8000,
|
||||
.rate_max = 50000,
|
||||
.mclk_fs = (unsigned int[]) { 32, 64, 128, 192, 256,
|
||||
384, 512, 768, 1024 },
|
||||
.mclk_fs_num = 9,
|
||||
}, {
|
||||
/* Double speed mode */
|
||||
.rate_min = 84000,
|
||||
.rate_max = 100000,
|
||||
.mclk_fs = (unsigned int[]) { 128, 192, 256, 384, 512,
|
||||
768, 1024},
|
||||
.mclk_fs_num = 7,
|
||||
}
|
||||
};
|
||||
|
||||
/* Es7154 has a separate supply for digital I/O */
|
||||
static const struct snd_soc_dapm_widget es7154_extra_widgets[] = {
|
||||
SND_SOC_DAPM_REGULATOR_SUPPLY("PVDD", 0, 0),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route es7154_extra_routes[] = {
|
||||
{ "Playback", NULL, "PVDD", }
|
||||
};
|
||||
|
||||
static const struct es7134_chip es7154_chip = {
|
||||
.dai_drv = &es7154_dai,
|
||||
.modes = es7154_modes,
|
||||
.mode_num = ARRAY_SIZE(es7154_modes),
|
||||
.extra_routes = es7154_extra_routes,
|
||||
.extra_route_num = ARRAY_SIZE(es7154_extra_routes),
|
||||
.extra_widgets = es7154_extra_widgets,
|
||||
.extra_widget_num = ARRAY_SIZE(es7154_extra_widgets),
|
||||
};
|
||||
|
||||
static int es7134_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct es7134_data *priv;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
priv->chip = of_device_get_match_data(dev);
|
||||
if (!priv->chip) {
|
||||
dev_err(dev, "failed to match device\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return devm_snd_soc_register_component(&pdev->dev,
|
||||
&es7134_component_driver,
|
||||
&es7134_dai, 1);
|
||||
priv->chip->dai_drv, 1);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id es7134_ids[] = {
|
||||
{ .compatible = "everest,es7134", },
|
||||
{ .compatible = "everest,es7144", },
|
||||
{ .compatible = "everest,es7134", .data = &es7134_chip },
|
||||
{ .compatible = "everest,es7144", .data = &es7134_chip },
|
||||
{ .compatible = "everest,es7154", .data = &es7154_chip },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, es7134_ids);
|
||||
|
322
sound/soc/codecs/es7241.c
Normal file
322
sound/soc/codecs/es7241.c
Normal file
@@ -0,0 +1,322 @@
|
||||
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
||||
//
|
||||
// Copyright (c) 2018 BayLibre, SAS.
|
||||
// Author: Jerome Brunet <jbrunet@baylibre.com>
|
||||
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/module.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
struct es7241_clock_mode {
|
||||
unsigned int rate_min;
|
||||
unsigned int rate_max;
|
||||
unsigned int *slv_mfs;
|
||||
unsigned int slv_mfs_num;
|
||||
unsigned int mst_mfs;
|
||||
unsigned int mst_m0:1;
|
||||
unsigned int mst_m1:1;
|
||||
};
|
||||
|
||||
struct es7241_chip {
|
||||
const struct es7241_clock_mode *modes;
|
||||
unsigned int mode_num;
|
||||
};
|
||||
|
||||
struct es7241_data {
|
||||
struct gpio_desc *reset;
|
||||
struct gpio_desc *m0;
|
||||
struct gpio_desc *m1;
|
||||
unsigned int fmt;
|
||||
unsigned int mclk;
|
||||
bool is_slave;
|
||||
const struct es7241_chip *chip;
|
||||
};
|
||||
|
||||
static void es7241_set_mode(struct es7241_data *priv, int m0, int m1)
|
||||
{
|
||||
/* put the device in reset */
|
||||
gpiod_set_value_cansleep(priv->reset, 0);
|
||||
|
||||
/* set the mode */
|
||||
gpiod_set_value_cansleep(priv->m0, m0);
|
||||
gpiod_set_value_cansleep(priv->m1, m1);
|
||||
|
||||
/* take the device out of reset - datasheet does not specify a delay */
|
||||
gpiod_set_value_cansleep(priv->reset, 1);
|
||||
}
|
||||
|
||||
static int es7241_set_slave_mode(struct es7241_data *priv,
|
||||
const struct es7241_clock_mode *mode,
|
||||
unsigned int mfs)
|
||||
{
|
||||
int j;
|
||||
|
||||
if (!mfs)
|
||||
goto out_ok;
|
||||
|
||||
for (j = 0; j < mode->slv_mfs_num; j++) {
|
||||
if (mode->slv_mfs[j] == mfs)
|
||||
goto out_ok;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
|
||||
out_ok:
|
||||
es7241_set_mode(priv, 1, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int es7241_set_master_mode(struct es7241_data *priv,
|
||||
const struct es7241_clock_mode *mode,
|
||||
unsigned int mfs)
|
||||
{
|
||||
/*
|
||||
* We can't really set clock ratio, if the mclk/lrclk is different
|
||||
* from what we provide, then error out
|
||||
*/
|
||||
if (mfs && mfs != mode->mst_mfs)
|
||||
return -EINVAL;
|
||||
|
||||
es7241_set_mode(priv, mode->mst_m0, mode->mst_m1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int es7241_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct es7241_data *priv = snd_soc_dai_get_drvdata(dai);
|
||||
unsigned int rate = params_rate(params);
|
||||
unsigned int mfs = priv->mclk / rate;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < priv->chip->mode_num; i++) {
|
||||
const struct es7241_clock_mode *mode = &priv->chip->modes[i];
|
||||
|
||||
if (rate < mode->rate_min || rate >= mode->rate_max)
|
||||
continue;
|
||||
|
||||
if (priv->is_slave)
|
||||
return es7241_set_slave_mode(priv, mode, mfs);
|
||||
else
|
||||
return es7241_set_master_mode(priv, mode, mfs);
|
||||
}
|
||||
|
||||
/* should not happen */
|
||||
dev_err(dai->dev, "unsupported rate: %u\n", rate);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int es7241_set_sysclk(struct snd_soc_dai *dai, int clk_id,
|
||||
unsigned int freq, int dir)
|
||||
{
|
||||
struct es7241_data *priv = snd_soc_dai_get_drvdata(dai);
|
||||
|
||||
if (dir == SND_SOC_CLOCK_IN && clk_id == 0) {
|
||||
priv->mclk = freq;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
static int es7241_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
|
||||
{
|
||||
struct es7241_data *priv = snd_soc_dai_get_drvdata(dai);
|
||||
|
||||
if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF) {
|
||||
dev_err(dai->dev, "Unsupported dai clock inversion\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) != priv->fmt) {
|
||||
dev_err(dai->dev, "Invalid dai format\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
|
||||
case SND_SOC_DAIFMT_CBS_CFS:
|
||||
priv->is_slave = true;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_CBM_CFM:
|
||||
priv->is_slave = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_err(dai->dev, "Unsupported clock configuration\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_soc_dai_ops es7241_dai_ops = {
|
||||
.set_fmt = es7241_set_fmt,
|
||||
.hw_params = es7241_hw_params,
|
||||
.set_sysclk = es7241_set_sysclk,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver es7241_dai = {
|
||||
.name = "es7241-hifi",
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.rates = SNDRV_PCM_RATE_8000_192000,
|
||||
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S24_3LE |
|
||||
SNDRV_PCM_FMTBIT_S24_LE),
|
||||
},
|
||||
.ops = &es7241_dai_ops,
|
||||
};
|
||||
|
||||
static const struct es7241_clock_mode es7241_modes[] = {
|
||||
{
|
||||
/* Single speed mode */
|
||||
.rate_min = 8000,
|
||||
.rate_max = 50000,
|
||||
.slv_mfs = (unsigned int[]) { 256, 384, 512, 768, 1024 },
|
||||
.slv_mfs_num = 5,
|
||||
.mst_mfs = 256,
|
||||
.mst_m0 = 0,
|
||||
.mst_m1 = 0,
|
||||
}, {
|
||||
/* Double speed mode */
|
||||
.rate_min = 50000,
|
||||
.rate_max = 100000,
|
||||
.slv_mfs = (unsigned int[]) { 128, 192 },
|
||||
.slv_mfs_num = 2,
|
||||
.mst_mfs = 128,
|
||||
.mst_m0 = 1,
|
||||
.mst_m1 = 0,
|
||||
}, {
|
||||
/* Quad speed mode */
|
||||
.rate_min = 100000,
|
||||
.rate_max = 200000,
|
||||
.slv_mfs = (unsigned int[]) { 64 },
|
||||
.slv_mfs_num = 1,
|
||||
.mst_mfs = 64,
|
||||
.mst_m0 = 0,
|
||||
.mst_m1 = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct es7241_chip es7241_chip = {
|
||||
.modes = es7241_modes,
|
||||
.mode_num = ARRAY_SIZE(es7241_modes),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget es7241_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_INPUT("AINL"),
|
||||
SND_SOC_DAPM_INPUT("AINR"),
|
||||
SND_SOC_DAPM_DAC("ADC", "Capture", SND_SOC_NOPM, 0, 0),
|
||||
SND_SOC_DAPM_REGULATOR_SUPPLY("VDDP", 0, 0),
|
||||
SND_SOC_DAPM_REGULATOR_SUPPLY("VDDD", 0, 0),
|
||||
SND_SOC_DAPM_REGULATOR_SUPPLY("VDDA", 0, 0),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route es7241_dapm_routes[] = {
|
||||
{ "ADC", NULL, "AINL", },
|
||||
{ "ADC", NULL, "AINR", },
|
||||
{ "ADC", NULL, "VDDA", },
|
||||
{ "Capture", NULL, "VDDP", },
|
||||
{ "Capture", NULL, "VDDD", },
|
||||
};
|
||||
|
||||
static const struct snd_soc_component_driver es7241_component_driver = {
|
||||
.dapm_widgets = es7241_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(es7241_dapm_widgets),
|
||||
.dapm_routes = es7241_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(es7241_dapm_routes),
|
||||
.idle_bias_on = 1,
|
||||
.endianness = 1,
|
||||
.non_legacy_dai_naming = 1,
|
||||
};
|
||||
|
||||
static void es7241_parse_fmt(struct device *dev, struct es7241_data *priv)
|
||||
{
|
||||
bool is_leftj;
|
||||
|
||||
/*
|
||||
* The format is given by a pull resistor on the SDOUT pin:
|
||||
* pull-up for i2s, pull-down for left justified.
|
||||
*/
|
||||
is_leftj = of_property_read_bool(dev->of_node,
|
||||
"everest,sdout-pull-down");
|
||||
if (is_leftj)
|
||||
priv->fmt = SND_SOC_DAIFMT_LEFT_J;
|
||||
else
|
||||
priv->fmt = SND_SOC_DAIFMT_I2S;
|
||||
}
|
||||
|
||||
static int es7241_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct es7241_data *priv;
|
||||
int err;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
priv->chip = of_device_get_match_data(dev);
|
||||
if (!priv->chip) {
|
||||
dev_err(dev, "failed to match device\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
es7241_parse_fmt(dev, priv);
|
||||
|
||||
priv->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(priv->reset)) {
|
||||
err = PTR_ERR(priv->reset);
|
||||
if (err != -EPROBE_DEFER)
|
||||
dev_err(dev, "Failed to get 'reset' gpio: %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
priv->m0 = devm_gpiod_get_optional(dev, "m0", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(priv->m0)) {
|
||||
err = PTR_ERR(priv->m0);
|
||||
if (err != -EPROBE_DEFER)
|
||||
dev_err(dev, "Failed to get 'm0' gpio: %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
priv->m1 = devm_gpiod_get_optional(dev, "m1", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(priv->m1)) {
|
||||
err = PTR_ERR(priv->m1);
|
||||
if (err != -EPROBE_DEFER)
|
||||
dev_err(dev, "Failed to get 'm1' gpio: %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return devm_snd_soc_register_component(&pdev->dev,
|
||||
&es7241_component_driver,
|
||||
&es7241_dai, 1);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id es7241_ids[] = {
|
||||
{ .compatible = "everest,es7241", .data = &es7241_chip },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, es7241_ids);
|
||||
#endif
|
||||
|
||||
static struct platform_driver es7241_driver = {
|
||||
.driver = {
|
||||
.name = "es7241",
|
||||
.of_match_table = of_match_ptr(es7241_ids),
|
||||
},
|
||||
.probe = es7241_probe,
|
||||
};
|
||||
|
||||
module_platform_driver(es7241_driver);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC ES7241 audio codec driver");
|
||||
MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
|
||||
MODULE_LICENSE("GPL");
|
File diff suppressed because it is too large
Load Diff
@@ -52,9 +52,9 @@ static bool max9850_volatile_register(struct device *dev, unsigned int reg)
|
||||
switch (reg) {
|
||||
case MAX9850_STATUSA:
|
||||
case MAX9850_STATUSB:
|
||||
return 1;
|
||||
return true;
|
||||
default:
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -362,11 +362,8 @@ static const struct snd_soc_dapm_route nau8540_dapm_routes[] = {
|
||||
|
||||
static int nau8540_clock_check(struct nau8540 *nau8540, int rate, int osr)
|
||||
{
|
||||
int osrate;
|
||||
|
||||
if (osr >= ARRAY_SIZE(osr_adc_sel))
|
||||
return -EINVAL;
|
||||
osrate = osr_adc_sel[osr].osr;
|
||||
|
||||
if (rate * osr > CLK_ADC_MAX) {
|
||||
dev_err(nau8540->dev, "exceed the maximum frequency of CLK_ADC\n");
|
||||
|
@@ -1274,7 +1274,7 @@ static int nau8824_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;
|
||||
|
@@ -2016,7 +2016,7 @@ static int nau8825_calc_fll_param(unsigned int fll_in, unsigned int fs,
|
||||
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;
|
||||
|
@@ -262,8 +262,7 @@ int pcm1789_common_exit(struct device *dev)
|
||||
{
|
||||
struct pcm1789_private *priv = dev_get_drvdata(dev);
|
||||
|
||||
if (&priv->work)
|
||||
flush_work(&priv->work);
|
||||
flush_work(&priv->work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -265,7 +265,7 @@ static int pcm186x_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_component *component = dai->component;
|
||||
struct pcm186x_priv *priv = snd_soc_component_get_drvdata(component);
|
||||
unsigned int rate = params_rate(params);
|
||||
unsigned int format = params_format(params);
|
||||
snd_pcm_format_t format = params_format(params);
|
||||
unsigned int width = params_width(params);
|
||||
unsigned int channels = params_channels(params);
|
||||
unsigned int div_lrck;
|
||||
|
@@ -1066,7 +1066,7 @@ static void rt1305_calibrate(struct rt1305_priv *rt1305)
|
||||
pr_debug("Left_rhl = 0x%x rh=0x%x rl=0x%x\n", rhl, rh, rl);
|
||||
pr_info("Left channel %d.%dohm\n", (r0ohm/10), (r0ohm%10));
|
||||
|
||||
r0l = 562949953421312;
|
||||
r0l = 562949953421312ULL;
|
||||
if (rhl != 0)
|
||||
do_div(r0l, rhl);
|
||||
pr_debug("Left_r0 = 0x%llx\n", r0l);
|
||||
@@ -1083,7 +1083,7 @@ static void rt1305_calibrate(struct rt1305_priv *rt1305)
|
||||
pr_debug("Right_rhl = 0x%x rh=0x%x rl=0x%x\n", rhl, rh, rl);
|
||||
pr_info("Right channel %d.%dohm\n", (r0ohm/10), (r0ohm%10));
|
||||
|
||||
r0r = 562949953421312;
|
||||
r0r = 562949953421312ULL;
|
||||
if (rhl != 0)
|
||||
do_div(r0r, rhl);
|
||||
pr_debug("Right_r0 = 0x%llx\n", r0r);
|
||||
@@ -1150,17 +1150,11 @@ static int rt1305_i2c_probe(struct i2c_client *i2c,
|
||||
rt1305_reset(rt1305->regmap);
|
||||
rt1305_calibrate(rt1305);
|
||||
|
||||
return snd_soc_register_component(&i2c->dev, &soc_component_dev_rt1305,
|
||||
return devm_snd_soc_register_component(&i2c->dev,
|
||||
&soc_component_dev_rt1305,
|
||||
rt1305_dai, ARRAY_SIZE(rt1305_dai));
|
||||
}
|
||||
|
||||
static int rt1305_i2c_remove(struct i2c_client *i2c)
|
||||
{
|
||||
snd_soc_unregister_component(&i2c->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rt1305_i2c_shutdown(struct i2c_client *client)
|
||||
{
|
||||
struct rt1305_priv *rt1305 = i2c_get_clientdata(client);
|
||||
@@ -1180,7 +1174,6 @@ static struct i2c_driver rt1305_i2c_driver = {
|
||||
#endif
|
||||
},
|
||||
.probe = rt1305_i2c_probe,
|
||||
.remove = rt1305_i2c_remove,
|
||||
.shutdown = rt1305_i2c_shutdown,
|
||||
.id_table = rt1305_i2c_id,
|
||||
};
|
||||
|
@@ -105,9 +105,9 @@ static bool rt5631_volatile_register(struct device *dev, unsigned int reg)
|
||||
case RT5631_INDEX_ADD:
|
||||
case RT5631_INDEX_DATA:
|
||||
case RT5631_EQ_CTRL:
|
||||
return 1;
|
||||
return true;
|
||||
default:
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,9 +164,9 @@ static bool rt5631_readable_register(struct device *dev, unsigned int reg)
|
||||
case RT5631_VENDOR_ID:
|
||||
case RT5631_VENDOR_ID1:
|
||||
case RT5631_VENDOR_ID2:
|
||||
return 1;
|
||||
return true;
|
||||
default:
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -229,10 +229,10 @@ static SOC_ENUM_SINGLE_DECL(rt5631_spk_ratio_enum, RT5631_GEN_PUR_CTRL_REG,
|
||||
static const struct snd_kcontrol_new rt5631_snd_controls[] = {
|
||||
/* MIC */
|
||||
SOC_ENUM("MIC1 Mode Control", rt5631_mic1_mode_enum),
|
||||
SOC_SINGLE_TLV("MIC1 Boost", RT5631_MIC_CTRL_2,
|
||||
SOC_SINGLE_TLV("MIC1 Boost Volume", RT5631_MIC_CTRL_2,
|
||||
RT5631_MIC1_BOOST_SHIFT, 8, 0, mic_bst_tlv),
|
||||
SOC_ENUM("MIC2 Mode Control", rt5631_mic2_mode_enum),
|
||||
SOC_SINGLE_TLV("MIC2 Boost", RT5631_MIC_CTRL_2,
|
||||
SOC_SINGLE_TLV("MIC2 Boost Volume", RT5631_MIC_CTRL_2,
|
||||
RT5631_MIC2_BOOST_SHIFT, 8, 0, mic_bst_tlv),
|
||||
/* MONO IN */
|
||||
SOC_ENUM("MONOIN Mode Control", rt5631_monoin_mode_enum),
|
||||
|
@@ -1665,6 +1665,7 @@ static int get_sdp_info(struct snd_soc_component *component, int dai_id)
|
||||
break;
|
||||
case RT5640_IF_113:
|
||||
ret |= RT5640_U_IF1;
|
||||
/* fall through */
|
||||
case RT5640_IF_312:
|
||||
case RT5640_IF_213:
|
||||
ret |= RT5640_U_IF2;
|
||||
@@ -1680,6 +1681,7 @@ static int get_sdp_info(struct snd_soc_component *component, int dai_id)
|
||||
break;
|
||||
case RT5640_IF_223:
|
||||
ret |= RT5640_U_IF1;
|
||||
/* fall through */
|
||||
case RT5640_IF_123:
|
||||
case RT5640_IF_321:
|
||||
ret |= RT5640_U_IF2;
|
||||
|
@@ -331,11 +331,13 @@ static const struct snd_kcontrol_new rt5651_snd_controls[] = {
|
||||
SOC_DOUBLE_TLV("Mono DAC Playback Volume", RT5651_DAC2_DIG_VOL,
|
||||
RT5651_L_VOL_SFT, RT5651_R_VOL_SFT,
|
||||
175, 0, dac_vol_tlv),
|
||||
/* IN1/IN2 Control */
|
||||
/* IN1/IN2/IN3 Control */
|
||||
SOC_SINGLE_TLV("IN1 Boost", RT5651_IN1_IN2,
|
||||
RT5651_BST_SFT1, 8, 0, bst_tlv),
|
||||
SOC_SINGLE_TLV("IN2 Boost", RT5651_IN1_IN2,
|
||||
RT5651_BST_SFT2, 8, 0, bst_tlv),
|
||||
SOC_SINGLE_TLV("IN3 Boost", RT5651_IN3,
|
||||
RT5651_BST_SFT1, 8, 0, bst_tlv),
|
||||
/* INL/INR Volume Control */
|
||||
SOC_DOUBLE_TLV("IN Capture Volume", RT5651_INL1_INR1_VOL,
|
||||
RT5651_INL_VOL_SFT, RT5651_INR_VOL_SFT,
|
||||
@@ -1581,6 +1583,24 @@ static void rt5651_disable_micbias1_for_ovcd(struct snd_soc_component *component
|
||||
snd_soc_dapm_mutex_unlock(dapm);
|
||||
}
|
||||
|
||||
static void rt5651_enable_micbias1_ovcd_irq(struct snd_soc_component *component)
|
||||
{
|
||||
struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
|
||||
|
||||
snd_soc_component_update_bits(component, RT5651_IRQ_CTRL2,
|
||||
RT5651_IRQ_MB1_OC_MASK, RT5651_IRQ_MB1_OC_NOR);
|
||||
rt5651->ovcd_irq_enabled = true;
|
||||
}
|
||||
|
||||
static void rt5651_disable_micbias1_ovcd_irq(struct snd_soc_component *component)
|
||||
{
|
||||
struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
|
||||
|
||||
snd_soc_component_update_bits(component, RT5651_IRQ_CTRL2,
|
||||
RT5651_IRQ_MB1_OC_MASK, RT5651_IRQ_MB1_OC_BP);
|
||||
rt5651->ovcd_irq_enabled = false;
|
||||
}
|
||||
|
||||
static void rt5651_clear_micbias1_ovcd(struct snd_soc_component *component)
|
||||
{
|
||||
snd_soc_component_update_bits(component, RT5651_IRQ_CTRL2,
|
||||
@@ -1622,10 +1642,80 @@ static bool rt5651_jack_inserted(struct snd_soc_component *component)
|
||||
return val == 0;
|
||||
}
|
||||
|
||||
/* Jack detect timings */
|
||||
/* Jack detect and button-press timings */
|
||||
#define JACK_SETTLE_TIME 100 /* milli seconds */
|
||||
#define JACK_DETECT_COUNT 5
|
||||
#define JACK_DETECT_MAXCOUNT 20 /* Aprox. 2 seconds worth of tries */
|
||||
#define JACK_UNPLUG_TIME 80 /* milli seconds */
|
||||
#define BP_POLL_TIME 10 /* milli seconds */
|
||||
#define BP_POLL_MAXCOUNT 200 /* assume something is wrong after this */
|
||||
#define BP_THRESHOLD 3
|
||||
|
||||
static void rt5651_start_button_press_work(struct snd_soc_component *component)
|
||||
{
|
||||
struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
|
||||
|
||||
rt5651->poll_count = 0;
|
||||
rt5651->press_count = 0;
|
||||
rt5651->release_count = 0;
|
||||
rt5651->pressed = false;
|
||||
rt5651->press_reported = false;
|
||||
rt5651_clear_micbias1_ovcd(component);
|
||||
schedule_delayed_work(&rt5651->bp_work, msecs_to_jiffies(BP_POLL_TIME));
|
||||
}
|
||||
|
||||
static void rt5651_button_press_work(struct work_struct *work)
|
||||
{
|
||||
struct rt5651_priv *rt5651 =
|
||||
container_of(work, struct rt5651_priv, bp_work.work);
|
||||
struct snd_soc_component *component = rt5651->component;
|
||||
|
||||
/* Check the jack was not removed underneath us */
|
||||
if (!rt5651_jack_inserted(component))
|
||||
return;
|
||||
|
||||
if (rt5651_micbias1_ovcd(component)) {
|
||||
rt5651->release_count = 0;
|
||||
rt5651->press_count++;
|
||||
/* Remember till after JACK_UNPLUG_TIME wait */
|
||||
if (rt5651->press_count >= BP_THRESHOLD)
|
||||
rt5651->pressed = true;
|
||||
rt5651_clear_micbias1_ovcd(component);
|
||||
} else {
|
||||
rt5651->press_count = 0;
|
||||
rt5651->release_count++;
|
||||
}
|
||||
|
||||
/*
|
||||
* The pins get temporarily shorted on jack unplug, so we poll for
|
||||
* at least JACK_UNPLUG_TIME milli-seconds before reporting a press.
|
||||
*/
|
||||
rt5651->poll_count++;
|
||||
if (rt5651->poll_count < (JACK_UNPLUG_TIME / BP_POLL_TIME)) {
|
||||
schedule_delayed_work(&rt5651->bp_work,
|
||||
msecs_to_jiffies(BP_POLL_TIME));
|
||||
return;
|
||||
}
|
||||
|
||||
if (rt5651->pressed && !rt5651->press_reported) {
|
||||
dev_dbg(component->dev, "headset button press\n");
|
||||
snd_soc_jack_report(rt5651->hp_jack, SND_JACK_BTN_0,
|
||||
SND_JACK_BTN_0);
|
||||
rt5651->press_reported = true;
|
||||
}
|
||||
|
||||
if (rt5651->release_count >= BP_THRESHOLD) {
|
||||
if (rt5651->press_reported) {
|
||||
dev_dbg(component->dev, "headset button release\n");
|
||||
snd_soc_jack_report(rt5651->hp_jack, 0, SND_JACK_BTN_0);
|
||||
}
|
||||
/* Re-enable OVCD IRQ to detect next press */
|
||||
rt5651_enable_micbias1_ovcd_irq(component);
|
||||
return; /* Stop polling */
|
||||
}
|
||||
|
||||
schedule_delayed_work(&rt5651->bp_work, msecs_to_jiffies(BP_POLL_TIME));
|
||||
}
|
||||
|
||||
static int rt5651_detect_headset(struct snd_soc_component *component)
|
||||
{
|
||||
@@ -1676,15 +1766,58 @@ static void rt5651_jack_detect_work(struct work_struct *work)
|
||||
{
|
||||
struct rt5651_priv *rt5651 =
|
||||
container_of(work, struct rt5651_priv, jack_detect_work);
|
||||
struct snd_soc_component *component = rt5651->component;
|
||||
int report = 0;
|
||||
|
||||
if (rt5651_jack_inserted(rt5651->component)) {
|
||||
rt5651_enable_micbias1_for_ovcd(rt5651->component);
|
||||
report = rt5651_detect_headset(rt5651->component);
|
||||
rt5651_disable_micbias1_for_ovcd(rt5651->component);
|
||||
}
|
||||
if (!rt5651_jack_inserted(component)) {
|
||||
/* Jack removed, or spurious IRQ? */
|
||||
if (rt5651->hp_jack->status & SND_JACK_HEADPHONE) {
|
||||
if (rt5651->hp_jack->status & SND_JACK_MICROPHONE) {
|
||||
cancel_delayed_work_sync(&rt5651->bp_work);
|
||||
rt5651_disable_micbias1_ovcd_irq(component);
|
||||
rt5651_disable_micbias1_for_ovcd(component);
|
||||
}
|
||||
snd_soc_jack_report(rt5651->hp_jack, 0,
|
||||
SND_JACK_HEADSET | SND_JACK_BTN_0);
|
||||
dev_dbg(component->dev, "jack unplugged\n");
|
||||
}
|
||||
} else if (!(rt5651->hp_jack->status & SND_JACK_HEADPHONE)) {
|
||||
/* Jack inserted */
|
||||
WARN_ON(rt5651->ovcd_irq_enabled);
|
||||
rt5651_enable_micbias1_for_ovcd(component);
|
||||
report = rt5651_detect_headset(component);
|
||||
if (report == SND_JACK_HEADSET) {
|
||||
/* Enable ovcd IRQ for button press detect. */
|
||||
rt5651_enable_micbias1_ovcd_irq(component);
|
||||
} else {
|
||||
/* No more need for overcurrent detect. */
|
||||
rt5651_disable_micbias1_for_ovcd(component);
|
||||
}
|
||||
dev_dbg(component->dev, "detect report %#02x\n", report);
|
||||
snd_soc_jack_report(rt5651->hp_jack, report, SND_JACK_HEADSET);
|
||||
} else if (rt5651->ovcd_irq_enabled && rt5651_micbias1_ovcd(component)) {
|
||||
dev_dbg(component->dev, "OVCD IRQ\n");
|
||||
|
||||
snd_soc_jack_report(rt5651->hp_jack, report, SND_JACK_HEADSET);
|
||||
/*
|
||||
* The ovcd IRQ keeps firing while the button is pressed, so
|
||||
* we disable it and start polling the button until released.
|
||||
*
|
||||
* The disable will make the IRQ pin 0 again and since we get
|
||||
* IRQs on both edges (so as to detect both jack plugin and
|
||||
* unplug) this means we will immediately get another IRQ.
|
||||
* The ovcd_irq_enabled check above makes the 2ND IRQ a NOP.
|
||||
*/
|
||||
rt5651_disable_micbias1_ovcd_irq(component);
|
||||
rt5651_start_button_press_work(component);
|
||||
|
||||
/*
|
||||
* If the jack-detect IRQ flag goes high (unplug) after our
|
||||
* above rt5651_jack_inserted() check and before we have
|
||||
* disabled the OVCD IRQ, the IRQ pin will stay high and as
|
||||
* we react to edges, we miss the unplug event -> recheck.
|
||||
*/
|
||||
queue_work(system_long_wq, &rt5651->jack_detect_work);
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t rt5651_irq(int irq, void *data)
|
||||
@@ -1696,14 +1829,18 @@ static irqreturn_t rt5651_irq(int irq, void *data)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int rt5651_set_jack(struct snd_soc_component *component,
|
||||
struct snd_soc_jack *hp_jack, void *data)
|
||||
static void rt5651_cancel_work(void *data)
|
||||
{
|
||||
struct rt5651_priv *rt5651 = data;
|
||||
|
||||
cancel_work_sync(&rt5651->jack_detect_work);
|
||||
cancel_delayed_work_sync(&rt5651->bp_work);
|
||||
}
|
||||
|
||||
static void rt5651_enable_jack_detect(struct snd_soc_component *component,
|
||||
struct snd_soc_jack *hp_jack)
|
||||
{
|
||||
struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
|
||||
int ret;
|
||||
|
||||
if (!rt5651->irq)
|
||||
return -EINVAL;
|
||||
|
||||
/* IRQ output on GPIO1 */
|
||||
snd_soc_component_update_bits(component, RT5651_GPIO_CTRL1,
|
||||
@@ -1730,10 +1867,10 @@ static int rt5651_set_jack(struct snd_soc_component *component,
|
||||
RT5651_JD2_IRQ_EN, RT5651_JD2_IRQ_EN);
|
||||
break;
|
||||
case RT5651_JD_NULL:
|
||||
return 0;
|
||||
return;
|
||||
default:
|
||||
dev_err(component->dev, "Currently only JD1_1 / JD1_2 / JD2 are supported\n");
|
||||
return -EINVAL;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Enable jack detect power */
|
||||
@@ -1767,19 +1904,39 @@ static int rt5651_set_jack(struct snd_soc_component *component,
|
||||
RT5651_MB1_OC_STKY_MASK, RT5651_MB1_OC_STKY_EN);
|
||||
|
||||
rt5651->hp_jack = hp_jack;
|
||||
|
||||
ret = devm_request_threaded_irq(component->dev, rt5651->irq, NULL,
|
||||
rt5651_irq,
|
||||
IRQF_TRIGGER_RISING |
|
||||
IRQF_TRIGGER_FALLING |
|
||||
IRQF_ONESHOT, "rt5651", rt5651);
|
||||
if (ret) {
|
||||
dev_err(component->dev, "Failed to reguest IRQ: %d\n", ret);
|
||||
return ret;
|
||||
if (rt5651->hp_jack->status & SND_JACK_MICROPHONE) {
|
||||
rt5651_enable_micbias1_for_ovcd(component);
|
||||
rt5651_enable_micbias1_ovcd_irq(component);
|
||||
}
|
||||
|
||||
enable_irq(rt5651->irq);
|
||||
/* sync initial jack state */
|
||||
queue_work(system_power_efficient_wq, &rt5651->jack_detect_work);
|
||||
}
|
||||
|
||||
static void rt5651_disable_jack_detect(struct snd_soc_component *component)
|
||||
{
|
||||
struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
|
||||
|
||||
disable_irq(rt5651->irq);
|
||||
rt5651_cancel_work(rt5651);
|
||||
|
||||
if (rt5651->hp_jack->status & SND_JACK_MICROPHONE) {
|
||||
rt5651_disable_micbias1_ovcd_irq(component);
|
||||
rt5651_disable_micbias1_for_ovcd(component);
|
||||
snd_soc_jack_report(rt5651->hp_jack, 0, SND_JACK_BTN_0);
|
||||
}
|
||||
|
||||
rt5651->hp_jack = NULL;
|
||||
}
|
||||
|
||||
static int rt5651_set_jack(struct snd_soc_component *component,
|
||||
struct snd_soc_jack *jack, void *data)
|
||||
{
|
||||
if (jack)
|
||||
rt5651_enable_jack_detect(component, jack);
|
||||
else
|
||||
rt5651_disable_jack_detect(component);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -2034,8 +2191,26 @@ static int rt5651_i2c_probe(struct i2c_client *i2c,
|
||||
rt5651->irq = i2c->irq;
|
||||
rt5651->hp_mute = 1;
|
||||
|
||||
INIT_DELAYED_WORK(&rt5651->bp_work, rt5651_button_press_work);
|
||||
INIT_WORK(&rt5651->jack_detect_work, rt5651_jack_detect_work);
|
||||
|
||||
/* Make sure work is stopped on probe-error / remove */
|
||||
ret = devm_add_action_or_reset(&i2c->dev, rt5651_cancel_work, rt5651);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_request_irq(&i2c->dev, rt5651->irq, rt5651_irq,
|
||||
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
|
||||
| IRQF_ONESHOT, "rt5651", rt5651);
|
||||
if (ret == 0) {
|
||||
/* Gets re-enabled by rt5651_set_jack() */
|
||||
disable_irq(rt5651->irq);
|
||||
} else {
|
||||
dev_warn(&i2c->dev, "Failed to reguest IRQ %d: %d\n",
|
||||
rt5651->irq, ret);
|
||||
rt5651->irq = -ENXIO;
|
||||
}
|
||||
|
||||
ret = devm_snd_soc_register_component(&i2c->dev,
|
||||
&soc_component_dev_rt5651,
|
||||
rt5651_dai, ARRAY_SIZE(rt5651_dai));
|
||||
@@ -2043,15 +2218,6 @@ static int rt5651_i2c_probe(struct i2c_client *i2c,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rt5651_i2c_remove(struct i2c_client *i2c)
|
||||
{
|
||||
struct rt5651_priv *rt5651 = i2c_get_clientdata(i2c);
|
||||
|
||||
cancel_work_sync(&rt5651->jack_detect_work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct i2c_driver rt5651_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "rt5651",
|
||||
@@ -2059,7 +2225,6 @@ static struct i2c_driver rt5651_i2c_driver = {
|
||||
.of_match_table = of_match_ptr(rt5651_of_match),
|
||||
},
|
||||
.probe = rt5651_i2c_probe,
|
||||
.remove = rt5651_i2c_remove,
|
||||
.id_table = rt5651_i2c_id,
|
||||
};
|
||||
module_i2c_driver(rt5651_i2c_driver);
|
||||
|
@@ -2071,8 +2071,16 @@ struct rt5651_pll_code {
|
||||
struct rt5651_priv {
|
||||
struct snd_soc_component *component;
|
||||
struct regmap *regmap;
|
||||
/* Jack and button detect data */
|
||||
struct snd_soc_jack *hp_jack;
|
||||
struct work_struct jack_detect_work;
|
||||
struct delayed_work bp_work;
|
||||
bool ovcd_irq_enabled;
|
||||
bool pressed;
|
||||
bool press_reported;
|
||||
int press_count;
|
||||
int release_count;
|
||||
int poll_count;
|
||||
unsigned int jd_src;
|
||||
unsigned int ovcd_th;
|
||||
unsigned int ovcd_sf;
|
||||
|
@@ -4417,6 +4417,7 @@ static int rt5677_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
|
||||
break;
|
||||
case 25:
|
||||
slot_width_25 = 0x8080;
|
||||
/* fall through */
|
||||
case 24:
|
||||
val |= (2 << 8);
|
||||
break;
|
||||
@@ -5007,7 +5008,7 @@ static const struct regmap_config rt5677_regmap = {
|
||||
};
|
||||
|
||||
static const struct of_device_id rt5677_of_match[] = {
|
||||
{ .compatible = "realtek,rt5677", RT5677 },
|
||||
{ .compatible = "realtek,rt5677", .data = (const void *)RT5677 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, rt5677_of_match);
|
||||
|
2681
sound/soc/codecs/rt5682.c
Normal file
2681
sound/soc/codecs/rt5682.c
Normal file
File diff suppressed because it is too large
Load Diff
1324
sound/soc/codecs/rt5682.h
Normal file
1324
sound/soc/codecs/rt5682.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -21,9 +21,9 @@
|
||||
#include <linux/module.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#define DRV_NAME "dio2125"
|
||||
#define DRV_NAME "simple-amplifier"
|
||||
|
||||
struct dio2125 {
|
||||
struct simple_amp {
|
||||
struct gpio_desc *gpiod_enable;
|
||||
};
|
||||
|
||||
@@ -31,7 +31,7 @@ static int drv_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *control, int event)
|
||||
{
|
||||
struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm);
|
||||
struct dio2125 *priv = snd_soc_component_get_drvdata(c);
|
||||
struct simple_amp *priv = snd_soc_component_get_drvdata(c);
|
||||
int val;
|
||||
|
||||
switch (event) {
|
||||
@@ -51,7 +51,7 @@ static int drv_event(struct snd_soc_dapm_widget *w,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_soc_dapm_widget dio2125_dapm_widgets[] = {
|
||||
static const struct snd_soc_dapm_widget simple_amp_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_INPUT("INL"),
|
||||
SND_SOC_DAPM_INPUT("INR"),
|
||||
SND_SOC_DAPM_OUT_DRV_E("DRV", SND_SOC_NOPM, 0, 0, NULL, 0, drv_event,
|
||||
@@ -60,24 +60,24 @@ static const struct snd_soc_dapm_widget dio2125_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_OUTPUT("OUTR"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route dio2125_dapm_routes[] = {
|
||||
static const struct snd_soc_dapm_route simple_amp_dapm_routes[] = {
|
||||
{ "DRV", NULL, "INL" },
|
||||
{ "DRV", NULL, "INR" },
|
||||
{ "OUTL", NULL, "DRV" },
|
||||
{ "OUTR", NULL, "DRV" },
|
||||
};
|
||||
|
||||
static const struct snd_soc_component_driver dio2125_component_driver = {
|
||||
.dapm_widgets = dio2125_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(dio2125_dapm_widgets),
|
||||
.dapm_routes = dio2125_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(dio2125_dapm_routes),
|
||||
static const struct snd_soc_component_driver simple_amp_component_driver = {
|
||||
.dapm_widgets = simple_amp_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(simple_amp_dapm_widgets),
|
||||
.dapm_routes = simple_amp_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(simple_amp_dapm_routes),
|
||||
};
|
||||
|
||||
static int dio2125_probe(struct platform_device *pdev)
|
||||
static int simple_amp_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct dio2125 *priv;
|
||||
struct simple_amp *priv;
|
||||
int err;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
@@ -93,28 +93,30 @@ static int dio2125_probe(struct platform_device *pdev)
|
||||
return err;
|
||||
}
|
||||
|
||||
return devm_snd_soc_register_component(dev, &dio2125_component_driver,
|
||||
return devm_snd_soc_register_component(dev,
|
||||
&simple_amp_component_driver,
|
||||
NULL, 0);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id dio2125_ids[] = {
|
||||
static const struct of_device_id simple_amp_ids[] = {
|
||||
{ .compatible = "dioo,dio2125", },
|
||||
{ .compatible = "simple-audio-amplifier", },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, dio2125_ids);
|
||||
MODULE_DEVICE_TABLE(of, simple_amp_ids);
|
||||
#endif
|
||||
|
||||
static struct platform_driver dio2125_driver = {
|
||||
static struct platform_driver simple_amp_driver = {
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
.of_match_table = of_match_ptr(dio2125_ids),
|
||||
.of_match_table = of_match_ptr(simple_amp_ids),
|
||||
},
|
||||
.probe = dio2125_probe,
|
||||
.probe = simple_amp_probe,
|
||||
};
|
||||
|
||||
module_platform_driver(dio2125_driver);
|
||||
module_platform_driver(simple_amp_driver);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC DIO2125 output driver");
|
||||
MODULE_DESCRIPTION("ASoC Simple Audio Amplifier driver");
|
||||
MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
|
||||
MODULE_LICENSE("GPL");
|
@@ -7,6 +7,9 @@
|
||||
* TAS5721 support:
|
||||
* Copyright (C) 2016 Petr Kulhavy, Barix AG <petr@barix.com>
|
||||
*
|
||||
* TAS5707 support:
|
||||
* Copyright (C) 2018 Jerome Brunet, Baylibre SAS <jbrunet@baylibre.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
|
||||
@@ -444,6 +447,111 @@ static const struct tas571x_chip tas5711_chip = {
|
||||
.vol_reg_size = 1,
|
||||
};
|
||||
|
||||
static const struct regmap_range tas5707_volatile_regs_range[] = {
|
||||
regmap_reg_range(TAS571X_CLK_CTRL_REG, TAS571X_ERR_STATUS_REG),
|
||||
regmap_reg_range(TAS571X_OSC_TRIM_REG, TAS571X_OSC_TRIM_REG),
|
||||
regmap_reg_range(TAS5707_CH1_BQ0_REG, TAS5707_CH2_BQ6_REG),
|
||||
};
|
||||
|
||||
static const struct regmap_access_table tas5707_volatile_regs = {
|
||||
.yes_ranges = tas5707_volatile_regs_range,
|
||||
.n_yes_ranges = ARRAY_SIZE(tas5707_volatile_regs_range),
|
||||
|
||||
};
|
||||
|
||||
static const DECLARE_TLV_DB_SCALE(tas5707_volume_tlv, -7900, 50, 1);
|
||||
|
||||
static const char * const tas5707_volume_slew_step_txt[] = {
|
||||
"256", "512", "1024", "2048",
|
||||
};
|
||||
|
||||
static const unsigned int tas5707_volume_slew_step_values[] = {
|
||||
3, 0, 1, 2,
|
||||
};
|
||||
|
||||
static SOC_VALUE_ENUM_SINGLE_DECL(tas5707_volume_slew_step_enum,
|
||||
TAS571X_VOL_CFG_REG, 0, 0x3,
|
||||
tas5707_volume_slew_step_txt,
|
||||
tas5707_volume_slew_step_values);
|
||||
|
||||
static const struct snd_kcontrol_new tas5707_controls[] = {
|
||||
SOC_SINGLE_TLV("Master Volume",
|
||||
TAS571X_MVOL_REG,
|
||||
0, 0xff, 1, tas5707_volume_tlv),
|
||||
SOC_DOUBLE_R_TLV("Speaker Volume",
|
||||
TAS571X_CH1_VOL_REG,
|
||||
TAS571X_CH2_VOL_REG,
|
||||
0, 0xff, 1, tas5707_volume_tlv),
|
||||
SOC_DOUBLE("Speaker Switch",
|
||||
TAS571X_SOFT_MUTE_REG,
|
||||
TAS571X_SOFT_MUTE_CH1_SHIFT, TAS571X_SOFT_MUTE_CH2_SHIFT,
|
||||
1, 1),
|
||||
|
||||
SOC_ENUM("Slew Rate Steps", tas5707_volume_slew_step_enum),
|
||||
|
||||
BIQUAD_COEFS("CH1 - Biquad 0", TAS5707_CH1_BQ0_REG),
|
||||
BIQUAD_COEFS("CH1 - Biquad 1", TAS5707_CH1_BQ1_REG),
|
||||
BIQUAD_COEFS("CH1 - Biquad 2", TAS5707_CH1_BQ2_REG),
|
||||
BIQUAD_COEFS("CH1 - Biquad 3", TAS5707_CH1_BQ3_REG),
|
||||
BIQUAD_COEFS("CH1 - Biquad 4", TAS5707_CH1_BQ4_REG),
|
||||
BIQUAD_COEFS("CH1 - Biquad 5", TAS5707_CH1_BQ5_REG),
|
||||
BIQUAD_COEFS("CH1 - Biquad 6", TAS5707_CH1_BQ6_REG),
|
||||
|
||||
BIQUAD_COEFS("CH2 - Biquad 0", TAS5707_CH2_BQ0_REG),
|
||||
BIQUAD_COEFS("CH2 - Biquad 1", TAS5707_CH2_BQ1_REG),
|
||||
BIQUAD_COEFS("CH2 - Biquad 2", TAS5707_CH2_BQ2_REG),
|
||||
BIQUAD_COEFS("CH2 - Biquad 3", TAS5707_CH2_BQ3_REG),
|
||||
BIQUAD_COEFS("CH2 - Biquad 4", TAS5707_CH2_BQ4_REG),
|
||||
BIQUAD_COEFS("CH2 - Biquad 5", TAS5707_CH2_BQ5_REG),
|
||||
BIQUAD_COEFS("CH2 - Biquad 6", TAS5707_CH2_BQ6_REG),
|
||||
};
|
||||
|
||||
static const struct reg_default tas5707_reg_defaults[] = {
|
||||
{TAS571X_CLK_CTRL_REG, 0x6c},
|
||||
{TAS571X_DEV_ID_REG, 0x70},
|
||||
{TAS571X_ERR_STATUS_REG, 0x00},
|
||||
{TAS571X_SYS_CTRL_1_REG, 0xa0},
|
||||
{TAS571X_SDI_REG, 0x05},
|
||||
{TAS571X_SYS_CTRL_2_REG, 0x40},
|
||||
{TAS571X_SOFT_MUTE_REG, 0x00},
|
||||
{TAS571X_MVOL_REG, 0xff},
|
||||
{TAS571X_CH1_VOL_REG, 0x30},
|
||||
{TAS571X_CH2_VOL_REG, 0x30},
|
||||
{TAS571X_VOL_CFG_REG, 0x91},
|
||||
{TAS571X_MODULATION_LIMIT_REG, 0x02},
|
||||
{TAS571X_IC_DELAY_CH1_REG, 0xac},
|
||||
{TAS571X_IC_DELAY_CH2_REG, 0x54},
|
||||
{TAS571X_IC_DELAY_CH3_REG, 0xac},
|
||||
{TAS571X_IC_DELAY_CH4_REG, 0x54},
|
||||
{TAS571X_START_STOP_PERIOD_REG, 0x0f},
|
||||
{TAS571X_OSC_TRIM_REG, 0x82},
|
||||
{TAS571X_BKND_ERR_REG, 0x02},
|
||||
{TAS571X_INPUT_MUX_REG, 0x17772},
|
||||
{TAS571X_PWM_MUX_REG, 0x1021345},
|
||||
};
|
||||
|
||||
static const struct regmap_config tas5707_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 32,
|
||||
.max_register = 0xff,
|
||||
.reg_read = tas571x_reg_read,
|
||||
.reg_write = tas571x_reg_write,
|
||||
.reg_defaults = tas5707_reg_defaults,
|
||||
.num_reg_defaults = ARRAY_SIZE(tas5707_reg_defaults),
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
.wr_table = &tas571x_write_regs,
|
||||
.volatile_table = &tas5707_volatile_regs,
|
||||
};
|
||||
|
||||
static const struct tas571x_chip tas5707_chip = {
|
||||
.supply_names = tas5711_supply_names,
|
||||
.num_supply_names = ARRAY_SIZE(tas5711_supply_names),
|
||||
.controls = tas5707_controls,
|
||||
.num_controls = ARRAY_SIZE(tas5707_controls),
|
||||
.regmap_config = &tas5707_regmap_config,
|
||||
.vol_reg_size = 1,
|
||||
};
|
||||
|
||||
static const char *const tas5717_supply_names[] = {
|
||||
"AVDD",
|
||||
"DVDD",
|
||||
@@ -775,6 +883,7 @@ static int tas571x_i2c_remove(struct i2c_client *client)
|
||||
}
|
||||
|
||||
static const struct of_device_id tas571x_of_match[] = {
|
||||
{ .compatible = "ti,tas5707", .data = &tas5707_chip, },
|
||||
{ .compatible = "ti,tas5711", .data = &tas5711_chip, },
|
||||
{ .compatible = "ti,tas5717", .data = &tas5717_chip, },
|
||||
{ .compatible = "ti,tas5719", .data = &tas5717_chip, },
|
||||
@@ -784,6 +893,7 @@ static const struct of_device_id tas571x_of_match[] = {
|
||||
MODULE_DEVICE_TABLE(of, tas571x_of_match);
|
||||
|
||||
static const struct i2c_device_id tas571x_i2c_id[] = {
|
||||
{ "tas5707", (kernel_ulong_t) &tas5707_chip },
|
||||
{ "tas5711", (kernel_ulong_t) &tas5711_chip },
|
||||
{ "tas5717", (kernel_ulong_t) &tas5717_chip },
|
||||
{ "tas5719", (kernel_ulong_t) &tas5717_chip },
|
||||
|
@@ -53,6 +53,22 @@
|
||||
#define TAS571X_PWM_MUX_REG 0x25
|
||||
|
||||
/* 20-byte biquad registers */
|
||||
#define TAS5707_CH1_BQ0_REG 0x29
|
||||
#define TAS5707_CH1_BQ1_REG 0x2a
|
||||
#define TAS5707_CH1_BQ2_REG 0x2b
|
||||
#define TAS5707_CH1_BQ3_REG 0x2c
|
||||
#define TAS5707_CH1_BQ4_REG 0x2d
|
||||
#define TAS5707_CH1_BQ5_REG 0x2e
|
||||
#define TAS5707_CH1_BQ6_REG 0x2f
|
||||
|
||||
#define TAS5707_CH2_BQ0_REG 0x30
|
||||
#define TAS5707_CH2_BQ1_REG 0x31
|
||||
#define TAS5707_CH2_BQ2_REG 0x32
|
||||
#define TAS5707_CH2_BQ3_REG 0x33
|
||||
#define TAS5707_CH2_BQ4_REG 0x34
|
||||
#define TAS5707_CH2_BQ5_REG 0x35
|
||||
#define TAS5707_CH2_BQ6_REG 0x36
|
||||
|
||||
#define TAS5717_CH1_BQ0_REG 0x26
|
||||
#define TAS5717_CH1_BQ1_REG 0x27
|
||||
#define TAS5717_CH1_BQ2_REG 0x28
|
||||
|
@@ -142,9 +142,9 @@ struct tda7419_vol_control {
|
||||
static inline bool tda7419_vol_is_stereo(struct tda7419_vol_control *tvc)
|
||||
{
|
||||
if (tvc->reg == tvc->rreg)
|
||||
return 0;
|
||||
return false;
|
||||
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int tda7419_vol_info(struct snd_kcontrol *kcontrol,
|
||||
|
@@ -625,25 +625,34 @@ static int bytes_info_ext(struct snd_kcontrol *kcontrol,
|
||||
|
||||
static const struct snd_kcontrol_new tscs42xx_snd_controls[] = {
|
||||
/* Volumes */
|
||||
SOC_DOUBLE_R_TLV("Headphone Playback Volume", R_HPVOLL, R_HPVOLR,
|
||||
SOC_DOUBLE_R_TLV("Headphone Volume", R_HPVOLL, R_HPVOLR,
|
||||
FB_HPVOLL, 0x7F, 0, hpvol_scale),
|
||||
SOC_DOUBLE_R_TLV("Speaker Playback Volume", R_SPKVOLL, R_SPKVOLR,
|
||||
SOC_DOUBLE_R_TLV("Speaker Volume", R_SPKVOLL, R_SPKVOLR,
|
||||
FB_SPKVOLL, 0x7F, 0, spkvol_scale),
|
||||
SOC_DOUBLE_R_TLV("Master Playback Volume", R_DACVOLL, R_DACVOLR,
|
||||
SOC_DOUBLE_R_TLV("Master Volume", R_DACVOLL, R_DACVOLR,
|
||||
FB_DACVOLL, 0xFF, 0, dacvol_scale),
|
||||
SOC_DOUBLE_R_TLV("PCM Capture Volume", R_ADCVOLL, R_ADCVOLR,
|
||||
SOC_DOUBLE_R_TLV("PCM Volume", R_ADCVOLL, R_ADCVOLR,
|
||||
FB_ADCVOLL, 0xFF, 0, adcvol_scale),
|
||||
SOC_DOUBLE_R_TLV("Master Capture Volume", R_INVOLL, R_INVOLR,
|
||||
SOC_DOUBLE_R_TLV("Input Volume", R_INVOLL, R_INVOLR,
|
||||
FB_INVOLL, 0x3F, 0, invol_scale),
|
||||
|
||||
/* INSEL */
|
||||
SOC_DOUBLE_R_TLV("Mic Boost Capture Volume", R_INSELL, R_INSELR,
|
||||
SOC_DOUBLE_R_TLV("Mic Boost Volume", R_INSELL, R_INSELR,
|
||||
FB_INSELL_MICBSTL, FV_INSELL_MICBSTL_30DB,
|
||||
0, mic_boost_scale),
|
||||
|
||||
/* Input Channel Map */
|
||||
SOC_ENUM("Input Channel Map", ch_map_select_enum),
|
||||
|
||||
/* Mic Bias */
|
||||
SOC_SINGLE("Mic Bias Boost Switch", 0x71, 0x07, 1, 0),
|
||||
|
||||
/* Headphone Auto Switching */
|
||||
SOC_SINGLE("Headphone Auto Switching Switch",
|
||||
R_CTL, FB_CTL_HPSWEN, 1, 0),
|
||||
SOC_SINGLE("Headphone Detect Polarity Toggle Switch",
|
||||
R_CTL, FB_CTL_HPSWPOL, 1, 0),
|
||||
|
||||
/* Coefficient Ram */
|
||||
COEFF_RAM_CTL("Cascade1L BiQuad1", BIQUAD_SIZE, 0x00),
|
||||
COEFF_RAM_CTL("Cascade1L BiQuad2", BIQUAD_SIZE, 0x05),
|
||||
@@ -733,9 +742,9 @@ static const struct snd_kcontrol_new tscs42xx_snd_controls[] = {
|
||||
R_CLECTL, FB_CLECTL_LIMIT_EN, 1, 0),
|
||||
SOC_SINGLE("Comp Switch",
|
||||
R_CLECTL, FB_CLECTL_COMP_EN, 1, 0),
|
||||
SOC_SINGLE_TLV("CLE Make-Up Gain Playback Volume",
|
||||
SOC_SINGLE_TLV("CLE Make-Up Gain Volume",
|
||||
R_MUGAIN, FB_MUGAIN_CLEMUG, 0x1f, 0, mugain_scale),
|
||||
SOC_SINGLE_TLV("Comp Thresh Playback Volume",
|
||||
SOC_SINGLE_TLV("Comp Thresh Volume",
|
||||
R_COMPTH, FB_COMPTH, 0xff, 0, compth_scale),
|
||||
SOC_ENUM("Comp Ratio", compressor_ratio_enum),
|
||||
SND_SOC_BYTES("Comp Atk Time", R_CATKTCL, 2),
|
||||
@@ -766,9 +775,9 @@ static const struct snd_kcontrol_new tscs42xx_snd_controls[] = {
|
||||
|
||||
SOC_SINGLE("MBC1 Phase Invert Switch",
|
||||
R_DACMBCMUG1, FB_DACMBCMUG1_PHASE, 1, 0),
|
||||
SOC_SINGLE_TLV("DAC MBC1 Make-Up Gain Playback Volume",
|
||||
SOC_SINGLE_TLV("DAC MBC1 Make-Up Gain Volume",
|
||||
R_DACMBCMUG1, FB_DACMBCMUG1_MUGAIN, 0x1f, 0, mugain_scale),
|
||||
SOC_SINGLE_TLV("DAC MBC1 Comp Thresh Playback Volume",
|
||||
SOC_SINGLE_TLV("DAC MBC1 Comp Thresh Volume",
|
||||
R_DACMBCTHR1, FB_DACMBCTHR1_THRESH, 0xff, 0, compth_scale),
|
||||
SOC_ENUM("DAC MBC1 Comp Ratio",
|
||||
dac_mbc1_compressor_ratio_enum),
|
||||
@@ -778,9 +787,9 @@ static const struct snd_kcontrol_new tscs42xx_snd_controls[] = {
|
||||
|
||||
SOC_SINGLE("MBC2 Phase Invert Switch",
|
||||
R_DACMBCMUG2, FB_DACMBCMUG2_PHASE, 1, 0),
|
||||
SOC_SINGLE_TLV("DAC MBC2 Make-Up Gain Playback Volume",
|
||||
SOC_SINGLE_TLV("DAC MBC2 Make-Up Gain Volume",
|
||||
R_DACMBCMUG2, FB_DACMBCMUG2_MUGAIN, 0x1f, 0, mugain_scale),
|
||||
SOC_SINGLE_TLV("DAC MBC2 Comp Thresh Playback Volume",
|
||||
SOC_SINGLE_TLV("DAC MBC2 Comp Thresh Volume",
|
||||
R_DACMBCTHR2, FB_DACMBCTHR2_THRESH, 0xff, 0, compth_scale),
|
||||
SOC_ENUM("DAC MBC2 Comp Ratio",
|
||||
dac_mbc2_compressor_ratio_enum),
|
||||
@@ -790,9 +799,9 @@ static const struct snd_kcontrol_new tscs42xx_snd_controls[] = {
|
||||
|
||||
SOC_SINGLE("MBC3 Phase Invert Switch",
|
||||
R_DACMBCMUG3, FB_DACMBCMUG3_PHASE, 1, 0),
|
||||
SOC_SINGLE_TLV("DAC MBC3 Make-Up Gain Playback Volume",
|
||||
SOC_SINGLE_TLV("DAC MBC3 Make-Up Gain Volume",
|
||||
R_DACMBCMUG3, FB_DACMBCMUG3_MUGAIN, 0x1f, 0, mugain_scale),
|
||||
SOC_SINGLE_TLV("DAC MBC3 Comp Thresh Playback Volume",
|
||||
SOC_SINGLE_TLV("DAC MBC3 Comp Thresh Volume",
|
||||
R_DACMBCTHR3, FB_DACMBCTHR3_THRESH, 0xff, 0, compth_scale),
|
||||
SOC_ENUM("DAC MBC3 Comp Ratio",
|
||||
dac_mbc3_compressor_ratio_enum),
|
||||
|
@@ -34,6 +34,7 @@ enum {
|
||||
#define R_DACSR 0x19
|
||||
#define R_PWRM1 0x1A
|
||||
#define R_PWRM2 0x1B
|
||||
#define R_CTL 0x1C
|
||||
#define R_CONFIG0 0x1F
|
||||
#define R_CONFIG1 0x20
|
||||
#define R_DMICCTL 0x24
|
||||
@@ -1110,6 +1111,13 @@ enum {
|
||||
#define RV_PWRM2_VREF_DISABLE \
|
||||
RV(FV_PWRM2_VREF_DISABLE, FB_PWRM2_VREF)
|
||||
|
||||
/******************************
|
||||
* R_CTL (0x1C) *
|
||||
******************************/
|
||||
|
||||
/* Fiel Offsets */
|
||||
#define FB_CTL_HPSWEN 7
|
||||
#define FB_CTL_HPSWPOL 6
|
||||
|
||||
/******************************
|
||||
* R_CONFIG0 (0x1F) *
|
||||
|
@@ -148,7 +148,7 @@ static bool twl6040_can_write_to_chip(struct snd_soc_component *component,
|
||||
case TWL6040_REG_HFRCTL:
|
||||
return priv->dl2_unmuted;
|
||||
default:
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1180,6 +1180,9 @@ SOC_DOUBLE_R_TLV("OUT2 Digital Volume", WM2200_DAC_DIGITAL_VOLUME_2L,
|
||||
SOC_DOUBLE("OUT2 Switch", WM2200_PDM_1, WM2200_SPK1L_MUTE_SHIFT,
|
||||
WM2200_SPK1R_MUTE_SHIFT, 1, 1),
|
||||
SOC_ENUM("RxANC Src", wm2200_rxanc_input_sel),
|
||||
|
||||
WM_ADSP_FW_CONTROL("DSP1", 0),
|
||||
WM_ADSP_FW_CONTROL("DSP2", 1),
|
||||
};
|
||||
|
||||
WM2200_MIXER_ENUMS(OUT1L, WM2200_OUT1LMIX_INPUT_1_SOURCE);
|
||||
@@ -1553,15 +1556,10 @@ static const struct snd_soc_dapm_route wm2200_dapm_routes[] = {
|
||||
static int wm2200_probe(struct snd_soc_component *component)
|
||||
{
|
||||
struct wm2200_priv *wm2200 = snd_soc_component_get_drvdata(component);
|
||||
int ret;
|
||||
|
||||
wm2200->component = component;
|
||||
|
||||
ret = snd_soc_add_component_controls(component, wm_adsp_fw_controls, 2);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wm2200_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
|
||||
|
@@ -30,7 +30,7 @@ bool wm5100_volatile_register(struct device *dev, unsigned int reg)
|
||||
case WM5100_OUTPUT_STATUS_2:
|
||||
case WM5100_INPUT_ENABLES_STATUS:
|
||||
case WM5100_MIC_DETECT_3:
|
||||
return 1;
|
||||
return true;
|
||||
default:
|
||||
if ((reg >= WM5100_DSP1_PM_0 && reg <= WM5100_DSP1_PM_1535) ||
|
||||
(reg >= WM5100_DSP1_ZM_0 && reg <= WM5100_DSP1_ZM_2047) ||
|
||||
@@ -41,9 +41,9 @@ bool wm5100_volatile_register(struct device *dev, unsigned int reg)
|
||||
(reg >= WM5100_DSP3_PM_0 && reg <= WM5100_DSP3_PM_1535) ||
|
||||
(reg >= WM5100_DSP3_ZM_0 && reg <= WM5100_DSP3_ZM_2047) ||
|
||||
(reg >= WM5100_DSP3_DM_0 && reg <= WM5100_DSP3_DM_511))
|
||||
return 1;
|
||||
return true;
|
||||
else
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -798,7 +798,7 @@ bool wm5100_readable_register(struct device *dev, unsigned int reg)
|
||||
case WM5100_DSP3_CONTROL_28:
|
||||
case WM5100_DSP3_CONTROL_29:
|
||||
case WM5100_DSP3_CONTROL_30:
|
||||
return 1;
|
||||
return true;
|
||||
default:
|
||||
if ((reg >= WM5100_DSP1_PM_0 && reg <= WM5100_DSP1_PM_1535) ||
|
||||
(reg >= WM5100_DSP1_ZM_0 && reg <= WM5100_DSP1_ZM_2047) ||
|
||||
@@ -809,9 +809,9 @@ bool wm5100_readable_register(struct device *dev, unsigned int reg)
|
||||
(reg >= WM5100_DSP3_PM_0 && reg <= WM5100_DSP3_PM_1535) ||
|
||||
(reg >= WM5100_DSP3_ZM_0 && reg <= WM5100_DSP3_ZM_2047) ||
|
||||
(reg >= WM5100_DSP3_DM_0 && reg <= WM5100_DSP3_DM_511))
|
||||
return 1;
|
||||
return true;
|
||||
else
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -985,6 +985,8 @@ ARIZONA_MIXER_CONTROLS("SLIMTX5", ARIZONA_SLIMTX5MIX_INPUT_1_SOURCE),
|
||||
ARIZONA_MIXER_CONTROLS("SLIMTX6", ARIZONA_SLIMTX6MIX_INPUT_1_SOURCE),
|
||||
ARIZONA_MIXER_CONTROLS("SLIMTX7", ARIZONA_SLIMTX7MIX_INPUT_1_SOURCE),
|
||||
ARIZONA_MIXER_CONTROLS("SLIMTX8", ARIZONA_SLIMTX8MIX_INPUT_1_SOURCE),
|
||||
|
||||
WM_ADSP_FW_CONTROL("DSP1", 0),
|
||||
};
|
||||
|
||||
ARIZONA_MIXER_ENUMS(EQ1, ARIZONA_EQ1MIX_INPUT_1_SOURCE);
|
||||
|
@@ -927,6 +927,11 @@ ARIZONA_MIXER_CONTROLS("SLIMTX5", ARIZONA_SLIMTX5MIX_INPUT_1_SOURCE),
|
||||
ARIZONA_MIXER_CONTROLS("SLIMTX6", ARIZONA_SLIMTX6MIX_INPUT_1_SOURCE),
|
||||
ARIZONA_MIXER_CONTROLS("SLIMTX7", ARIZONA_SLIMTX7MIX_INPUT_1_SOURCE),
|
||||
ARIZONA_MIXER_CONTROLS("SLIMTX8", ARIZONA_SLIMTX8MIX_INPUT_1_SOURCE),
|
||||
|
||||
WM_ADSP_FW_CONTROL("DSP1", 0),
|
||||
WM_ADSP_FW_CONTROL("DSP2", 1),
|
||||
WM_ADSP_FW_CONTROL("DSP3", 2),
|
||||
WM_ADSP_FW_CONTROL("DSP4", 3),
|
||||
};
|
||||
|
||||
ARIZONA_MIXER_ENUMS(EQ1, ARIZONA_EQ1MIX_INPUT_1_SOURCE);
|
||||
|
@@ -251,10 +251,10 @@ static bool wm8903_volatile_register(struct device *dev, unsigned int reg)
|
||||
case WM8903_DC_SERVO_READBACK_2:
|
||||
case WM8903_DC_SERVO_READBACK_3:
|
||||
case WM8903_DC_SERVO_READBACK_4:
|
||||
return 1;
|
||||
return true;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1455,6 +1455,7 @@ static int wm8904_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
|
||||
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
case SND_SOC_DAIFMT_DSP_B:
|
||||
aif1 |= 0x3 | WM8904_AIF_LRCLK_INV;
|
||||
/* fall through */
|
||||
case SND_SOC_DAIFMT_DSP_A:
|
||||
aif1 |= 0x3;
|
||||
break;
|
||||
|
@@ -686,6 +686,7 @@ static int wm8955_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
|
||||
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
case SND_SOC_DAIFMT_DSP_B:
|
||||
aif |= WM8955_LRP;
|
||||
/* fall through */
|
||||
case SND_SOC_DAIFMT_DSP_A:
|
||||
aif |= 0x3;
|
||||
break;
|
||||
|
@@ -839,6 +839,7 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream,
|
||||
iface |= 0x000c;
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
default:
|
||||
dev_err(component->dev, "unsupported width %d\n",
|
||||
params_width(params));
|
||||
|
@@ -653,6 +653,7 @@ static int wm8961_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
|
||||
|
||||
case SND_SOC_DAIFMT_DSP_B:
|
||||
aif |= WM8961_LRP;
|
||||
/* fall through */
|
||||
case SND_SOC_DAIFMT_DSP_A:
|
||||
aif |= 3;
|
||||
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
|
||||
|
@@ -2649,6 +2649,7 @@ static int wm8962_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
|
||||
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
case SND_SOC_DAIFMT_DSP_B:
|
||||
aif0 |= WM8962_LRCLK_INV | 3;
|
||||
/* fall through */
|
||||
case SND_SOC_DAIFMT_DSP_A:
|
||||
aif0 |= 3;
|
||||
|
||||
|
@@ -40,9 +40,9 @@ static bool wm8990_volatile_register(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case WM8990_RESET:
|
||||
return 1;
|
||||
return true;
|
||||
default:
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -2432,6 +2432,7 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai,
|
||||
snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_2,
|
||||
WM8994_OPCLK_ENA, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
@@ -1465,6 +1465,7 @@ static int wm8995_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
|
||||
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
case SND_SOC_DAIFMT_DSP_B:
|
||||
aif |= WM8995_AIF1_LRCLK_INV;
|
||||
/* fall through */
|
||||
case SND_SOC_DAIFMT_DSP_A:
|
||||
aif |= (0x3 << WM8995_AIF1_FMT_SHIFT);
|
||||
break;
|
||||
|
@@ -1498,9 +1498,9 @@ static bool wm8996_readable_register(struct device *dev, unsigned int reg)
|
||||
case WM8996_RIGHT_PDM_SPEAKER:
|
||||
case WM8996_PDM_SPEAKER_MUTE_SEQUENCE:
|
||||
case WM8996_PDM_SPEAKER_VOLUME:
|
||||
return 1;
|
||||
return true;
|
||||
default:
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1522,9 +1522,9 @@ static bool wm8996_volatile_register(struct device *dev, unsigned int reg)
|
||||
case WM8996_MIC_DETECT_3:
|
||||
case WM8996_HEADPHONE_DETECT_1:
|
||||
case WM8996_HEADPHONE_DETECT_2:
|
||||
return 1;
|
||||
return true;
|
||||
default:
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1858,6 +1858,7 @@ static int wm8996_set_sysclk(struct snd_soc_dai *dai,
|
||||
case 24576000:
|
||||
ratediv = WM8996_SYSCLK_DIV;
|
||||
wm8996->sysclk /= 2;
|
||||
/* fall through */
|
||||
case 11289600:
|
||||
case 12288000:
|
||||
snd_soc_component_update_bits(component, WM8996_AIF_RATE,
|
||||
|
@@ -933,6 +933,7 @@ static int wm9081_set_dai_fmt(struct snd_soc_dai *dai,
|
||||
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
case SND_SOC_DAIFMT_DSP_B:
|
||||
aif2 |= WM9081_AIF_LRCLK_INV;
|
||||
/* fall through */
|
||||
case SND_SOC_DAIFMT_DSP_A:
|
||||
aif2 |= 0x3;
|
||||
break;
|
||||
|
@@ -10,6 +10,7 @@
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/init.h>
|
||||
@@ -35,15 +36,15 @@
|
||||
#include "wm_adsp.h"
|
||||
|
||||
#define adsp_crit(_dsp, fmt, ...) \
|
||||
dev_crit(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__)
|
||||
dev_crit(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
|
||||
#define adsp_err(_dsp, fmt, ...) \
|
||||
dev_err(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__)
|
||||
dev_err(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
|
||||
#define adsp_warn(_dsp, fmt, ...) \
|
||||
dev_warn(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__)
|
||||
dev_warn(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
|
||||
#define adsp_info(_dsp, fmt, ...) \
|
||||
dev_info(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__)
|
||||
dev_info(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
|
||||
#define adsp_dbg(_dsp, fmt, ...) \
|
||||
dev_dbg(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__)
|
||||
dev_dbg(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
|
||||
|
||||
#define ADSP1_CONTROL_1 0x00
|
||||
#define ADSP1_CONTROL_2 0x02
|
||||
@@ -418,7 +419,7 @@ static const struct wm_adsp_fw_caps ctrl_caps[] = {
|
||||
{
|
||||
.id = SND_AUDIOCODEC_BESPOKE,
|
||||
.desc = {
|
||||
.max_ch = 1,
|
||||
.max_ch = 8,
|
||||
.sample_rates = { 16000 },
|
||||
.num_sample_rates = 1,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
@@ -608,7 +609,6 @@ static void wm_adsp2_init_debugfs(struct wm_adsp *dsp,
|
||||
struct snd_soc_component *component)
|
||||
{
|
||||
struct dentry *root = NULL;
|
||||
char *root_name;
|
||||
int i;
|
||||
|
||||
if (!component->debugfs_root) {
|
||||
@@ -616,13 +616,7 @@ static void wm_adsp2_init_debugfs(struct wm_adsp *dsp,
|
||||
goto err;
|
||||
}
|
||||
|
||||
root_name = kmalloc(PAGE_SIZE, GFP_KERNEL);
|
||||
if (!root_name)
|
||||
goto err;
|
||||
|
||||
snprintf(root_name, PAGE_SIZE, "dsp%d", dsp->num);
|
||||
root = debugfs_create_dir(root_name, component->debugfs_root);
|
||||
kfree(root_name);
|
||||
root = debugfs_create_dir(dsp->name, component->debugfs_root);
|
||||
|
||||
if (!root)
|
||||
goto err;
|
||||
@@ -684,8 +678,8 @@ static inline void wm_adsp_debugfs_clear(struct wm_adsp *dsp)
|
||||
}
|
||||
#endif
|
||||
|
||||
static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
|
||||
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
|
||||
@@ -695,9 +689,10 @@ static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wm_adsp_fw_get);
|
||||
|
||||
static int wm_adsp_fw_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
int wm_adsp_fw_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
|
||||
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
|
||||
@@ -721,8 +716,9 @@ static int wm_adsp_fw_put(struct snd_kcontrol *kcontrol,
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wm_adsp_fw_put);
|
||||
|
||||
static const struct soc_enum wm_adsp_fw_enum[] = {
|
||||
const struct soc_enum wm_adsp_fw_enum[] = {
|
||||
SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
|
||||
SOC_ENUM_SINGLE(0, 1, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
|
||||
SOC_ENUM_SINGLE(0, 2, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
|
||||
@@ -731,24 +727,7 @@ static const struct soc_enum wm_adsp_fw_enum[] = {
|
||||
SOC_ENUM_SINGLE(0, 5, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
|
||||
SOC_ENUM_SINGLE(0, 6, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
|
||||
};
|
||||
|
||||
const struct snd_kcontrol_new wm_adsp_fw_controls[] = {
|
||||
SOC_ENUM_EXT("DSP1 Firmware", wm_adsp_fw_enum[0],
|
||||
wm_adsp_fw_get, wm_adsp_fw_put),
|
||||
SOC_ENUM_EXT("DSP2 Firmware", wm_adsp_fw_enum[1],
|
||||
wm_adsp_fw_get, wm_adsp_fw_put),
|
||||
SOC_ENUM_EXT("DSP3 Firmware", wm_adsp_fw_enum[2],
|
||||
wm_adsp_fw_get, wm_adsp_fw_put),
|
||||
SOC_ENUM_EXT("DSP4 Firmware", wm_adsp_fw_enum[3],
|
||||
wm_adsp_fw_get, wm_adsp_fw_put),
|
||||
SOC_ENUM_EXT("DSP5 Firmware", wm_adsp_fw_enum[4],
|
||||
wm_adsp_fw_get, wm_adsp_fw_put),
|
||||
SOC_ENUM_EXT("DSP6 Firmware", wm_adsp_fw_enum[5],
|
||||
wm_adsp_fw_get, wm_adsp_fw_put),
|
||||
SOC_ENUM_EXT("DSP7 Firmware", wm_adsp_fw_enum[6],
|
||||
wm_adsp_fw_get, wm_adsp_fw_put),
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(wm_adsp_fw_controls);
|
||||
EXPORT_SYMBOL_GPL(wm_adsp_fw_enum);
|
||||
|
||||
static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp,
|
||||
int type)
|
||||
@@ -1330,12 +1309,12 @@ static int wm_adsp_create_control(struct wm_adsp *dsp,
|
||||
switch (dsp->fw_ver) {
|
||||
case 0:
|
||||
case 1:
|
||||
snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "DSP%d %s %x",
|
||||
dsp->num, region_name, alg_region->alg);
|
||||
snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s %s %x",
|
||||
dsp->name, region_name, alg_region->alg);
|
||||
break;
|
||||
default:
|
||||
ret = snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
|
||||
"DSP%d%c %.12s %x", dsp->num, *region_name,
|
||||
"%s%c %.12s %x", dsp->name, *region_name,
|
||||
wm_adsp_fw_text[dsp->fw], alg_region->alg);
|
||||
|
||||
/* Truncate the subname from the start if it is too long */
|
||||
@@ -1343,6 +1322,9 @@ static int wm_adsp_create_control(struct wm_adsp *dsp,
|
||||
int avail = SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret - 2;
|
||||
int skip = 0;
|
||||
|
||||
if (dsp->component->name_prefix)
|
||||
avail -= strlen(dsp->component->name_prefix) + 1;
|
||||
|
||||
if (subname_len > avail)
|
||||
skip = subname_len - avail;
|
||||
|
||||
@@ -1604,6 +1586,15 @@ static int wm_adsp_parse_coeff(struct wm_adsp *dsp,
|
||||
if (ret)
|
||||
return -EINVAL;
|
||||
break;
|
||||
case WMFW_CTL_TYPE_HOST_BUFFER:
|
||||
ret = wm_adsp_check_coeff_flags(dsp, &coeff_blk,
|
||||
WMFW_CTL_FLAG_SYS |
|
||||
WMFW_CTL_FLAG_VOLATILE |
|
||||
WMFW_CTL_FLAG_READABLE,
|
||||
0);
|
||||
if (ret)
|
||||
return -EINVAL;
|
||||
break;
|
||||
default:
|
||||
adsp_err(dsp, "Unknown control type: %d\n",
|
||||
coeff_blk.ctl_type);
|
||||
@@ -1651,7 +1642,7 @@ static int wm_adsp_load(struct wm_adsp *dsp)
|
||||
if (file == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
snprintf(file, PAGE_SIZE, "%s-dsp%d-%s.wmfw", dsp->part, dsp->num,
|
||||
snprintf(file, PAGE_SIZE, "%s-%s-%s.wmfw", dsp->part, dsp->fwf_name,
|
||||
wm_adsp_fw[dsp->fw].file);
|
||||
file[PAGE_SIZE - 1] = '\0';
|
||||
|
||||
@@ -1871,9 +1862,11 @@ static void wm_adsp_ctl_fixup_base(struct wm_adsp *dsp,
|
||||
}
|
||||
|
||||
static void *wm_adsp_read_algs(struct wm_adsp *dsp, size_t n_algs,
|
||||
const struct wm_adsp_region *mem,
|
||||
unsigned int pos, unsigned int len)
|
||||
{
|
||||
void *alg;
|
||||
unsigned int reg;
|
||||
int ret;
|
||||
__be32 val;
|
||||
|
||||
@@ -1888,7 +1881,9 @@ static void *wm_adsp_read_algs(struct wm_adsp *dsp, size_t n_algs,
|
||||
}
|
||||
|
||||
/* Read the terminator first to validate the length */
|
||||
ret = regmap_raw_read(dsp->regmap, pos + len, &val, sizeof(val));
|
||||
reg = wm_adsp_region_to_reg(mem, pos + len);
|
||||
|
||||
ret = regmap_raw_read(dsp->regmap, reg, &val, sizeof(val));
|
||||
if (ret != 0) {
|
||||
adsp_err(dsp, "Failed to read algorithm list end: %d\n",
|
||||
ret);
|
||||
@@ -1897,13 +1892,18 @@ static void *wm_adsp_read_algs(struct wm_adsp *dsp, size_t n_algs,
|
||||
|
||||
if (be32_to_cpu(val) != 0xbedead)
|
||||
adsp_warn(dsp, "Algorithm list end %x 0x%x != 0xbedead\n",
|
||||
pos + len, be32_to_cpu(val));
|
||||
reg, be32_to_cpu(val));
|
||||
|
||||
alg = kcalloc(len, 2, GFP_KERNEL | GFP_DMA);
|
||||
/* Convert length from DSP words to bytes */
|
||||
len *= sizeof(u32);
|
||||
|
||||
alg = kzalloc(len, GFP_KERNEL | GFP_DMA);
|
||||
if (!alg)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
ret = regmap_raw_read(dsp->regmap, pos, alg, len * 2);
|
||||
reg = wm_adsp_region_to_reg(mem, pos);
|
||||
|
||||
ret = regmap_raw_read(dsp->regmap, reg, alg, len);
|
||||
if (ret != 0) {
|
||||
adsp_err(dsp, "Failed to read algorithm list: %d\n", ret);
|
||||
kfree(alg);
|
||||
@@ -2002,10 +2002,11 @@ static int wm_adsp1_setup_algs(struct wm_adsp *dsp)
|
||||
if (IS_ERR(alg_region))
|
||||
return PTR_ERR(alg_region);
|
||||
|
||||
pos = sizeof(adsp1_id) / 2;
|
||||
len = (sizeof(*adsp1_alg) * n_algs) / 2;
|
||||
/* Calculate offset and length in DSP words */
|
||||
pos = sizeof(adsp1_id) / sizeof(u32);
|
||||
len = (sizeof(*adsp1_alg) * n_algs) / sizeof(u32);
|
||||
|
||||
adsp1_alg = wm_adsp_read_algs(dsp, n_algs, mem->base + pos, len);
|
||||
adsp1_alg = wm_adsp_read_algs(dsp, n_algs, mem, pos, len);
|
||||
if (IS_ERR(adsp1_alg))
|
||||
return PTR_ERR(adsp1_alg);
|
||||
|
||||
@@ -2113,10 +2114,11 @@ static int wm_adsp2_setup_algs(struct wm_adsp *dsp)
|
||||
if (IS_ERR(alg_region))
|
||||
return PTR_ERR(alg_region);
|
||||
|
||||
pos = sizeof(adsp2_id) / 2;
|
||||
len = (sizeof(*adsp2_alg) * n_algs) / 2;
|
||||
/* Calculate offset and length in DSP words */
|
||||
pos = sizeof(adsp2_id) / sizeof(u32);
|
||||
len = (sizeof(*adsp2_alg) * n_algs) / sizeof(u32);
|
||||
|
||||
adsp2_alg = wm_adsp_read_algs(dsp, n_algs, mem->base + pos, len);
|
||||
adsp2_alg = wm_adsp_read_algs(dsp, n_algs, mem, pos, len);
|
||||
if (IS_ERR(adsp2_alg))
|
||||
return PTR_ERR(adsp2_alg);
|
||||
|
||||
@@ -2218,7 +2220,7 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)
|
||||
if (file == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
snprintf(file, PAGE_SIZE, "%s-dsp%d-%s.bin", dsp->part, dsp->num,
|
||||
snprintf(file, PAGE_SIZE, "%s-%s-%s.bin", dsp->part, dsp->fwf_name,
|
||||
wm_adsp_fw[dsp->fw].file);
|
||||
file[PAGE_SIZE - 1] = '\0';
|
||||
|
||||
@@ -2390,8 +2392,38 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wm_adsp_create_name(struct wm_adsp *dsp)
|
||||
{
|
||||
char *p;
|
||||
|
||||
if (!dsp->name) {
|
||||
dsp->name = devm_kasprintf(dsp->dev, GFP_KERNEL, "DSP%d",
|
||||
dsp->num);
|
||||
if (!dsp->name)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (!dsp->fwf_name) {
|
||||
p = devm_kstrdup(dsp->dev, dsp->name, GFP_KERNEL);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
dsp->fwf_name = p;
|
||||
for (; *p != 0; ++p)
|
||||
*p = tolower(*p);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wm_adsp1_init(struct wm_adsp *dsp)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = wm_adsp_create_name(dsp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
INIT_LIST_HEAD(&dsp->alg_regions);
|
||||
|
||||
mutex_init(&dsp->pwr_lock);
|
||||
@@ -2664,7 +2696,7 @@ int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol,
|
||||
struct wm_adsp *dsp = &dsps[mc->shift - 1];
|
||||
char preload[32];
|
||||
|
||||
snprintf(preload, ARRAY_SIZE(preload), "DSP%u Preload", mc->shift);
|
||||
snprintf(preload, ARRAY_SIZE(preload), "%s Preload", dsp->name);
|
||||
|
||||
dsp->preloaded = ucontrol->value.integer.value[0];
|
||||
|
||||
@@ -2859,17 +2891,14 @@ int wm_adsp2_component_probe(struct wm_adsp *dsp, struct snd_soc_component *comp
|
||||
{
|
||||
char preload[32];
|
||||
|
||||
snprintf(preload, ARRAY_SIZE(preload), "DSP%d Preload", dsp->num);
|
||||
|
||||
snprintf(preload, ARRAY_SIZE(preload), "%s Preload", dsp->name);
|
||||
snd_soc_component_disable_pin(component, preload);
|
||||
|
||||
wm_adsp2_init_debugfs(dsp, component);
|
||||
|
||||
dsp->component = component;
|
||||
|
||||
return snd_soc_add_component_controls(component,
|
||||
&wm_adsp_fw_controls[dsp->num - 1],
|
||||
1);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wm_adsp2_component_probe);
|
||||
|
||||
@@ -2885,6 +2914,10 @@ int wm_adsp2_init(struct wm_adsp *dsp)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = wm_adsp_create_name(dsp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch (dsp->rev) {
|
||||
case 0:
|
||||
/*
|
||||
@@ -3192,7 +3225,7 @@ static inline int wm_adsp_buffer_write(struct wm_adsp_compr_buf *buf,
|
||||
buf->host_buf_ptr + field_offset, data);
|
||||
}
|
||||
|
||||
static int wm_adsp_buffer_locate(struct wm_adsp_compr_buf *buf)
|
||||
static int wm_adsp_legacy_host_buf_addr(struct wm_adsp_compr_buf *buf)
|
||||
{
|
||||
struct wm_adsp_alg_region *alg_region;
|
||||
struct wm_adsp *dsp = buf->dsp;
|
||||
@@ -3231,6 +3264,61 @@ static int wm_adsp_buffer_locate(struct wm_adsp_compr_buf *buf)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct wm_coeff_ctl *
|
||||
wm_adsp_find_host_buffer_ctrl(struct wm_adsp_compr_buf *buf)
|
||||
{
|
||||
struct wm_adsp *dsp = buf->dsp;
|
||||
struct wm_coeff_ctl *ctl;
|
||||
|
||||
list_for_each_entry(ctl, &dsp->ctl_list, list) {
|
||||
if (ctl->type != WMFW_CTL_TYPE_HOST_BUFFER)
|
||||
continue;
|
||||
|
||||
if (!ctl->enabled)
|
||||
continue;
|
||||
|
||||
return ctl;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int wm_adsp_buffer_locate(struct wm_adsp_compr_buf *buf)
|
||||
{
|
||||
struct wm_adsp *dsp = buf->dsp;
|
||||
struct wm_coeff_ctl *ctl;
|
||||
unsigned int reg;
|
||||
u32 val;
|
||||
int i, ret;
|
||||
|
||||
ctl = wm_adsp_find_host_buffer_ctrl(buf);
|
||||
if (!ctl)
|
||||
return wm_adsp_legacy_host_buf_addr(buf);
|
||||
|
||||
ret = wm_coeff_base_reg(ctl, ®);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < 5; ++i) {
|
||||
ret = regmap_raw_read(dsp->regmap, reg, &val, sizeof(val));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (val)
|
||||
break;
|
||||
|
||||
usleep_range(1000, 2000);
|
||||
}
|
||||
|
||||
if (!val)
|
||||
return -EIO;
|
||||
|
||||
buf->host_buf_ptr = be32_to_cpu(val);
|
||||
adsp_dbg(dsp, "host_buf_ptr=%x\n", buf->host_buf_ptr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wm_adsp_buffer_populate(struct wm_adsp_compr_buf *buf)
|
||||
{
|
||||
const struct wm_adsp_fw_caps *caps = wm_adsp_fw[buf->dsp->fw].caps;
|
||||
|
@@ -57,6 +57,8 @@ struct wm_adsp_compr_buf;
|
||||
|
||||
struct wm_adsp {
|
||||
const char *part;
|
||||
const char *name;
|
||||
const char *fwf_name;
|
||||
int rev;
|
||||
int num;
|
||||
int type;
|
||||
@@ -121,7 +123,11 @@ struct wm_adsp {
|
||||
.reg = SND_SOC_NOPM, .shift = num, .event = wm_adsp2_event, \
|
||||
.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD }
|
||||
|
||||
extern const struct snd_kcontrol_new wm_adsp_fw_controls[];
|
||||
#define WM_ADSP_FW_CONTROL(dspname, num) \
|
||||
SOC_ENUM_EXT(dspname " Firmware", wm_adsp_fw_enum[num], \
|
||||
wm_adsp_fw_get, wm_adsp_fw_put)
|
||||
|
||||
extern const struct soc_enum wm_adsp_fw_enum[];
|
||||
|
||||
int wm_adsp1_init(struct wm_adsp *dsp);
|
||||
int wm_adsp2_init(struct wm_adsp *dsp);
|
||||
@@ -144,6 +150,10 @@ int wm_adsp2_preloader_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
int wm_adsp_fw_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
|
||||
int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream);
|
||||
int wm_adsp_compr_free(struct snd_compr_stream *stream);
|
||||
|
@@ -29,6 +29,7 @@
|
||||
/* Non-ALSA coefficient types start at 0x1000 */
|
||||
#define WMFW_CTL_TYPE_ACKED 0x1000 /* acked control */
|
||||
#define WMFW_CTL_TYPE_HOSTEVENT 0x1001 /* event control */
|
||||
#define WMFW_CTL_TYPE_HOST_BUFFER 0x1002 /* host buffer pointer */
|
||||
|
||||
struct wmfw_header {
|
||||
char magic[4];
|
||||
|
@@ -340,6 +340,7 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
|
||||
* rate is lowered.
|
||||
*/
|
||||
inv_fs = true;
|
||||
/* fall through */
|
||||
case SND_SOC_DAIFMT_DSP_A:
|
||||
dev->mode = MOD_DSP_A;
|
||||
break;
|
||||
|
@@ -320,12 +320,8 @@ static irqreturn_t davinci_mcasp_tx_irq_handler(int irq, void *data)
|
||||
handled_mask |= XUNDRN;
|
||||
|
||||
substream = mcasp->substreams[SNDRV_PCM_STREAM_PLAYBACK];
|
||||
if (substream) {
|
||||
snd_pcm_stream_lock_irq(substream);
|
||||
if (snd_pcm_running(substream))
|
||||
snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
|
||||
snd_pcm_stream_unlock_irq(substream);
|
||||
}
|
||||
if (substream)
|
||||
snd_pcm_stop_xrun(substream);
|
||||
}
|
||||
|
||||
if (!handled_mask)
|
||||
@@ -355,12 +351,8 @@ static irqreturn_t davinci_mcasp_rx_irq_handler(int irq, void *data)
|
||||
handled_mask |= ROVRN;
|
||||
|
||||
substream = mcasp->substreams[SNDRV_PCM_STREAM_CAPTURE];
|
||||
if (substream) {
|
||||
snd_pcm_stream_lock_irq(substream);
|
||||
if (snd_pcm_running(substream))
|
||||
snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
|
||||
snd_pcm_stream_unlock_irq(substream);
|
||||
}
|
||||
if (substream)
|
||||
snd_pcm_stop_xrun(substream);
|
||||
}
|
||||
|
||||
if (!handled_mask)
|
||||
|
@@ -1,14 +1,10 @@
|
||||
/*
|
||||
* Freescale Generic ASoC Sound Card driver with ASRC
|
||||
*
|
||||
* Copyright (C) 2014 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* Author: Nicolin Chen <nicoleotsuka@gmail.com>
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public License
|
||||
* version 2. This program is licensed "as is" without any warranty of any
|
||||
* kind, whether express or implied.
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
//
|
||||
// Freescale Generic ASoC Sound Card driver with ASRC
|
||||
//
|
||||
// Copyright (C) 2014 Freescale Semiconductor, Inc.
|
||||
//
|
||||
// Author: Nicolin Chen <nicoleotsuka@gmail.com>
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/i2c.h>
|
||||
@@ -199,7 +195,7 @@ static int be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
|
||||
|
||||
mask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
|
||||
snd_mask_none(mask);
|
||||
snd_mask_set(mask, (__force int)priv->asrc_format);
|
||||
snd_mask_set_format(mask, priv->asrc_format);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -1,14 +1,10 @@
|
||||
/*
|
||||
* Freescale ASRC ALSA SoC Digital Audio Interface (DAI) driver
|
||||
*
|
||||
* Copyright (C) 2014 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* Author: Nicolin Chen <nicoleotsuka@gmail.com>
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public License
|
||||
* version 2. This program is licensed "as is" without any warranty of any
|
||||
* kind, whether express or implied.
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
//
|
||||
// Freescale ASRC ALSA SoC Digital Audio Interface (DAI) driver
|
||||
//
|
||||
// Copyright (C) 2014 Freescale Semiconductor, Inc.
|
||||
//
|
||||
// Author: Nicolin Chen <nicoleotsuka@gmail.com>
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
|
@@ -1,13 +1,10 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* fsl_asrc.h - Freescale ASRC ALSA SoC header file
|
||||
*
|
||||
* Copyright (C) 2014 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* Author: Nicolin Chen <nicoleotsuka@gmail.com>
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public License
|
||||
* version 2. This program is licensed "as is" without any warranty of any
|
||||
* kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#ifndef _FSL_ASRC_H
|
||||
|
@@ -1,14 +1,10 @@
|
||||
/*
|
||||
* Freescale ASRC ALSA SoC Platform (DMA) driver
|
||||
*
|
||||
* Copyright (C) 2014 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* Author: Nicolin Chen <nicoleotsuka@gmail.com>
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public License
|
||||
* version 2. This program is licensed "as is" without any warranty of any
|
||||
* kind, whether express or implied.
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
//
|
||||
// Freescale ASRC ALSA SoC Platform (DMA) driver
|
||||
//
|
||||
// Copyright (C) 2014 Freescale Semiconductor, Inc.
|
||||
//
|
||||
// Author: Nicolin Chen <nicoleotsuka@gmail.com>
|
||||
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/module.h>
|
||||
|
@@ -249,6 +249,7 @@ static int fsl_esai_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
|
||||
break;
|
||||
case ESAI_HCKT_EXTAL:
|
||||
ecr |= ESAI_ECR_ETI;
|
||||
/* fall through */
|
||||
case ESAI_HCKR_EXTAL:
|
||||
ecr |= ESAI_ECR_ERI;
|
||||
break;
|
||||
|
@@ -1118,7 +1118,7 @@ static u32 fsl_spdif_txclk_caldiv(struct fsl_spdif_priv *spdif_priv,
|
||||
|
||||
for (sysclk_df = sysclk_dfmin; sysclk_df <= sysclk_dfmax; sysclk_df++) {
|
||||
for (txclk_df = 1; txclk_df <= 128; txclk_df++) {
|
||||
rate_ideal = rate[index] * txclk_df * 64;
|
||||
rate_ideal = rate[index] * txclk_df * 64ULL;
|
||||
if (round)
|
||||
rate_actual = clk_round_rate(clk, rate_ideal);
|
||||
else
|
||||
|
@@ -1,14 +1,10 @@
|
||||
/**
|
||||
* Freescale ALSA SoC Machine driver utility
|
||||
*
|
||||
* Author: Timur Tabi <timur@freescale.com>
|
||||
*
|
||||
* Copyright 2010 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public License
|
||||
* version 2. This program is licensed "as is" without any warranty of any
|
||||
* kind, whether express or implied.
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
//
|
||||
// Freescale ALSA SoC Machine driver utility
|
||||
//
|
||||
// Author: Timur Tabi <timur@freescale.com>
|
||||
//
|
||||
// Copyright 2010 Freescale Semiconductor, Inc.
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_address.h>
|
||||
|
@@ -1,13 +1,10 @@
|
||||
/**
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Freescale ALSA SoC Machine driver utility
|
||||
*
|
||||
* Author: Timur Tabi <timur@freescale.com>
|
||||
*
|
||||
* Copyright 2010 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public License
|
||||
* version 2. This program is licensed "as is" without any warranty of any
|
||||
* kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#ifndef _FSL_UTILS_H
|
||||
|
@@ -1,14 +1,7 @@
|
||||
/*
|
||||
* Copyright 2012 Freescale Semiconductor, Inc.
|
||||
* Copyright 2012 Linaro Ltd.
|
||||
*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
//
|
||||
// Copyright 2012 Freescale Semiconductor, Inc.
|
||||
// Copyright 2012 Linaro Ltd.
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
|
@@ -1,15 +1,12 @@
|
||||
/*
|
||||
* ASoC audio graph sound card support
|
||||
*
|
||||
* Copyright (C) 2016 Renesas Solutions Corp.
|
||||
* Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
|
||||
*
|
||||
* based on ${LINUX}/sound/soc/generic/simple-card.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
|
||||
//
|
||||
// ASoC audio graph sound card support
|
||||
//
|
||||
// Copyright (C) 2016 Renesas Solutions Corp.
|
||||
// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
|
||||
//
|
||||
// based on ${LINUX}/sound/soc/generic/simple-card.c
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/gpio.h>
|
||||
@@ -21,7 +18,6 @@
|
||||
#include <linux/of_graph.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/string.h>
|
||||
#include <sound/jack.h>
|
||||
#include <sound/simple_card_utils.h>
|
||||
|
||||
struct graph_card_data {
|
||||
@@ -32,6 +28,8 @@ struct graph_card_data {
|
||||
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 gpio_desc *pa_gpio;
|
||||
};
|
||||
@@ -278,6 +276,22 @@ static int asoc_graph_get_dais_count(struct device *dev)
|
||||
return count;
|
||||
}
|
||||
|
||||
static int asoc_graph_soc_card_probe(struct snd_soc_card *card)
|
||||
{
|
||||
struct graph_card_data *priv = snd_soc_card_get_drvdata(card);
|
||||
int ret;
|
||||
|
||||
ret = asoc_simple_card_init_hp(card, &priv->hp_jack, NULL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = asoc_simple_card_init_mic(card, &priv->mic_jack, NULL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int asoc_graph_card_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct graph_card_data *priv;
|
||||
@@ -319,6 +333,7 @@ static int asoc_graph_card_probe(struct platform_device *pdev)
|
||||
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;
|
||||
|
||||
ret = asoc_graph_card_parse_of(priv);
|
||||
if (ret < 0) {
|
||||
|
@@ -1,17 +1,14 @@
|
||||
/*
|
||||
* ASoC audio graph SCU sound card support
|
||||
*
|
||||
* Copyright (C) 2017 Renesas Solutions Corp.
|
||||
* Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
|
||||
*
|
||||
* based on
|
||||
* ${LINUX}/sound/soc/generic/simple-scu-card.c
|
||||
* ${LINUX}/sound/soc/generic/audio-graph-card.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
|
||||
//
|
||||
// ASoC audio graph SCU sound card support
|
||||
//
|
||||
// Copyright (C) 2017 Renesas Solutions Corp.
|
||||
// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
|
||||
//
|
||||
// based on
|
||||
// ${LINUX}/sound/soc/generic/simple-scu-card.c
|
||||
// ${LINUX}/sound/soc/generic/audio-graph-card.c
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/gpio.h>
|
||||
|
@@ -1,16 +1,17 @@
|
||||
/*
|
||||
* simple-card-utils.c
|
||||
*
|
||||
* Copyright (c) 2016 Kuninori Morimoto <kuninori.morimoto.gx@renesas.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.
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
//
|
||||
// simple-card-utils.c
|
||||
//
|
||||
// Copyright (c) 2016 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/of_graph.h>
|
||||
#include <sound/jack.h>
|
||||
#include <sound/simple_card_utils.h>
|
||||
|
||||
void asoc_simple_card_convert_fixup(struct asoc_simple_card_data *data,
|
||||
@@ -419,6 +420,61 @@ int asoc_simple_card_of_parse_widgets(struct snd_soc_card *card,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(asoc_simple_card_of_parse_widgets);
|
||||
|
||||
int asoc_simple_card_init_jack(struct snd_soc_card *card,
|
||||
struct asoc_simple_jack *sjack,
|
||||
int is_hp, char *prefix)
|
||||
{
|
||||
struct device *dev = card->dev;
|
||||
enum of_gpio_flags flags;
|
||||
char prop[128];
|
||||
char *pin_name;
|
||||
char *gpio_name;
|
||||
int mask;
|
||||
int det;
|
||||
|
||||
if (!prefix)
|
||||
prefix = "";
|
||||
|
||||
sjack->gpio.gpio = -ENOENT;
|
||||
|
||||
if (is_hp) {
|
||||
snprintf(prop, sizeof(prop), "%shp-det-gpio", prefix);
|
||||
pin_name = "Headphones";
|
||||
gpio_name = "Headphone detection";
|
||||
mask = SND_JACK_HEADPHONE;
|
||||
} else {
|
||||
snprintf(prop, sizeof(prop), "%smic-det-gpio", prefix);
|
||||
pin_name = "Mic Jack";
|
||||
gpio_name = "Mic detection";
|
||||
mask = SND_JACK_MICROPHONE;
|
||||
}
|
||||
|
||||
det = of_get_named_gpio_flags(dev->of_node, prop, 0, &flags);
|
||||
if (det == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
if (gpio_is_valid(det)) {
|
||||
sjack->pin.pin = pin_name;
|
||||
sjack->pin.mask = mask;
|
||||
|
||||
sjack->gpio.name = gpio_name;
|
||||
sjack->gpio.report = mask;
|
||||
sjack->gpio.gpio = det;
|
||||
sjack->gpio.invert = !!(flags & OF_GPIO_ACTIVE_LOW);
|
||||
sjack->gpio.debounce_time = 150;
|
||||
|
||||
snd_soc_card_jack_new(card, pin_name, mask,
|
||||
&sjack->jack,
|
||||
&sjack->pin, 1);
|
||||
|
||||
snd_soc_jack_add_gpios(&sjack->jack, 1,
|
||||
&sjack->gpio);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(asoc_simple_card_init_jack);
|
||||
|
||||
/* Module information */
|
||||
MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
|
||||
MODULE_DESCRIPTION("ALSA SoC Simple Card Utils");
|
||||
|
@@ -1,32 +1,20 @@
|
||||
/*
|
||||
* ASoC simple sound card support
|
||||
*
|
||||
* Copyright (C) 2012 Renesas Solutions Corp.
|
||||
* Kuninori Morimoto <kuninori.morimoto.gx@renesas.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.
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
//
|
||||
// ASoC simple sound card support
|
||||
//
|
||||
// Copyright (C) 2012 Renesas Solutions Corp.
|
||||
// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/string.h>
|
||||
#include <sound/jack.h>
|
||||
#include <sound/simple_card.h>
|
||||
#include <sound/soc-dai.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
struct asoc_simple_jack {
|
||||
struct snd_soc_jack jack;
|
||||
struct snd_soc_jack_pin pin;
|
||||
struct snd_soc_jack_gpio gpio;
|
||||
};
|
||||
|
||||
struct simple_card_data {
|
||||
struct snd_soc_card snd_card;
|
||||
struct simple_dai_props {
|
||||
@@ -49,61 +37,6 @@ struct simple_card_data {
|
||||
#define CELL "#sound-dai-cells"
|
||||
#define PREFIX "simple-audio-card,"
|
||||
|
||||
#define asoc_simple_card_init_hp(card, sjack, prefix)\
|
||||
asoc_simple_card_init_jack(card, sjack, 1, prefix)
|
||||
#define asoc_simple_card_init_mic(card, sjack, prefix)\
|
||||
asoc_simple_card_init_jack(card, sjack, 0, prefix)
|
||||
static int asoc_simple_card_init_jack(struct snd_soc_card *card,
|
||||
struct asoc_simple_jack *sjack,
|
||||
int is_hp, char *prefix)
|
||||
{
|
||||
struct device *dev = card->dev;
|
||||
enum of_gpio_flags flags;
|
||||
char prop[128];
|
||||
char *pin_name;
|
||||
char *gpio_name;
|
||||
int mask;
|
||||
int det;
|
||||
|
||||
sjack->gpio.gpio = -ENOENT;
|
||||
|
||||
if (is_hp) {
|
||||
snprintf(prop, sizeof(prop), "%shp-det-gpio", prefix);
|
||||
pin_name = "Headphones";
|
||||
gpio_name = "Headphone detection";
|
||||
mask = SND_JACK_HEADPHONE;
|
||||
} else {
|
||||
snprintf(prop, sizeof(prop), "%smic-det-gpio", prefix);
|
||||
pin_name = "Mic Jack";
|
||||
gpio_name = "Mic detection";
|
||||
mask = SND_JACK_MICROPHONE;
|
||||
}
|
||||
|
||||
det = of_get_named_gpio_flags(dev->of_node, prop, 0, &flags);
|
||||
if (det == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
if (gpio_is_valid(det)) {
|
||||
sjack->pin.pin = pin_name;
|
||||
sjack->pin.mask = mask;
|
||||
|
||||
sjack->gpio.name = gpio_name;
|
||||
sjack->gpio.report = mask;
|
||||
sjack->gpio.gpio = det;
|
||||
sjack->gpio.invert = !!(flags & OF_GPIO_ACTIVE_LOW);
|
||||
sjack->gpio.debounce_time = 150;
|
||||
|
||||
snd_soc_card_jack_new(card, pin_name, mask,
|
||||
&sjack->jack,
|
||||
&sjack->pin, 1);
|
||||
|
||||
snd_soc_jack_add_gpios(&sjack->jack, 1,
|
||||
&sjack->gpio);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int asoc_simple_card_startup(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
@@ -213,14 +146,6 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = asoc_simple_card_init_hp(rtd->card, &priv->hp_jack, PREFIX);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = asoc_simple_card_init_mic(rtd->card, &priv->mic_jack, PREFIX);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -414,6 +339,22 @@ card_parse_end:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int asoc_simple_soc_card_probe(struct snd_soc_card *card)
|
||||
{
|
||||
struct simple_card_data *priv = snd_soc_card_get_drvdata(card);
|
||||
int ret;
|
||||
|
||||
ret = asoc_simple_card_init_hp(card, &priv->hp_jack, PREFIX);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = asoc_simple_card_init_mic(card, &priv->mic_jack, PREFIX);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int asoc_simple_card_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct simple_card_data *priv;
|
||||
@@ -449,6 +390,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
|
||||
card->dev = dev;
|
||||
card->dai_link = priv->dai_link;
|
||||
card->num_links = num;
|
||||
card->probe = asoc_simple_soc_card_probe;
|
||||
|
||||
if (np && of_device_is_available(np)) {
|
||||
|
||||
|
@@ -1,15 +1,12 @@
|
||||
/*
|
||||
* ASoC simple SCU sound card support
|
||||
*
|
||||
* Copyright (C) 2015 Renesas Solutions Corp.
|
||||
* Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
|
||||
*
|
||||
* based on ${LINUX}/sound/soc/generic/simple-card.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
|
||||
//
|
||||
// ASoC simple SCU sound card support
|
||||
//
|
||||
// Copyright (C) 2015 Renesas Solutions Corp.
|
||||
// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
|
||||
//
|
||||
// based on ${LINUX}/sound/soc/generic/simple-card.c
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/module.h>
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user