Merge branch 'asoc-4.19' into asoc-next

This commit is contained in:
Mark Brown
2018-08-09 14:47:05 +01:00
312 changed files with 15510 additions and 4310 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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;

View File

@@ -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");

View File

@@ -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");

View File

@@ -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 **);

View File

@@ -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

View File

@@ -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

View File

@@ -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);

View File

@@ -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);

View File

@@ -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
View 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);

View File

@@ -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);

View File

@@ -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)

View File

@@ -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);

View File

@@ -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+ */

View File

@@ -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"

View File

@@ -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/

View File

@@ -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.

View File

@@ -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);

View File

@@ -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;

View File

@@ -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 {

View File

@@ -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);

View File

@@ -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"

View File

@@ -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

View File

@@ -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[] = {

View File

@@ -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;
}

View File

@@ -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,

View File

@@ -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>");

View File

@@ -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>

View File

@@ -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");

View File

@@ -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,

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -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>

View File

@@ -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;
}
}

View File

@@ -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);

View File

@@ -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;
}
}

View File

@@ -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;
};

View File

@@ -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;
}
}

View File

@@ -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
View 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

View File

@@ -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;
}
}

View File

@@ -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");

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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,
};

View File

@@ -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),

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;

View File

@@ -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

File diff suppressed because it is too large Load Diff

1324
sound/soc/codecs/rt5682.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -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");

View File

@@ -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 },

View File

@@ -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

View File

@@ -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,

View File

@@ -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),

View File

@@ -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) *

View File

@@ -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;
}
}

View File

@@ -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)

View File

@@ -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;
}
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -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;
}
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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));

View File

@@ -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) {

View File

@@ -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;

View File

@@ -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;
}
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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,

View File

@@ -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;

View File

@@ -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, &reg);
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;

View File

@@ -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);

View File

@@ -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];

View File

@@ -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;

View File

@@ -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)

View File

@@ -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;
}

View File

@@ -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>

View File

@@ -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

View File

@@ -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>

View File

@@ -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;

View File

@@ -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

View File

@@ -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>

View File

@@ -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

View File

@@ -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>

View File

@@ -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) {

View File

@@ -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>

View File

@@ -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");

View File

@@ -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)) {

View File

@@ -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