Merge tag 'sound-3.9' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound

Pull sound updates from Takashi Iwai:
 "The biggest change in this update is the unification of HD-audio codec
  parsers.  Now the HD-audio codec is parsed in a generic parser code
  which is invoked by each HD-audio codec driver.

  Some background information is found in David Henningsson's blog
  entry:

      http://voices.canonical.com/david.henningsson/2013/01/18/upcoming-changes-to-the-intel-hda-drivers/

  Other than that, some random updates/fixes like USB-audio and a bunch
  of small AoC updates as usual.

  Highlights:

   - Unification of HD-audio parser code (aka generic parser)

   - Support of new Intel HD-audio controller, new IDT codecs

   - Fixes for HD-audio HDMI audio hotplug

   - Haswell HDMI audio fixup

   - Support of Creative CA0132 DSP code

   - A few fixes of HDSP driver

   - USB-audio fix for Roland A-PRO, M-Audio FT C600

   - Support PM for aloop driver (and fixes Oops)

   - Compress API updates for gapless playback support

  For ASoC part:

   - Support for a wider range of hardware in the compressed stream code

   - The ability to mute capture streams as well as playback streams
     while inactive

   - DT support for AK4642, FSI, Samsung I2S and WM8962

   - AC'97 support for Tegra

   - New driver for max98090, replacing the stub which was there

   - A new driver from Dialog

  Note that due to dependencies, DTification of DMA support for Samsung
  platforms (used only by the and I2S driver and SPI) is merged here as
  well."

Fix up trivial conflict in drivers/spi/spi-s3c64xx.c due to removed code
being changed.

* tag 'sound-3.9' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (453 commits)
  ALSA: usb: Fix Processing Unit Descriptor parsers
  ALSA: hda - hdmi: Notify userspace when ELD control changes
  ALSA: hda - hdmi: Protect ELD buffer
  ALSA: hda - hdmi: Refactor hdmi_eld into parsed_hdmi_eld
  ALSA: hda - hdmi: Do not expose eld data when eld is invalid
  ALSA: hda - hdmi: ELD shouldn't be valid after unplug
  ALSA: hda - Fix the silent speaker output on Fujitsu S7020 laptop
  ALSA: hda - add quirks for mute LED on two HP machines
  ALSA: usb/quirks, fix out-of-bounds access
  ASoC: codecs: Add da7213 codec
  ALSA: au88x0 - Define channel map for au88x0
  ALSA: compress: add support for gapless playback
  ALSA: hda - Remove speaker clicks on CX20549
  ALSA: hda - Disable runtime PM for Intel 5 Series/3400
  ALSA: hda - Increase badness for missing multi-io
  ASoC: arizona: Automatically manage input mutes
  ALSA: hda - Fix broken workaround for HDMI/SPDIF conflicts
  ALSA: hda/ca0132 - Add missing \n to debug prints
  ALSA: hda/ca0132 - Fix type of INVALID_CHIP_ADDRESS
  ALSA: hda - update documentation for no-primary-hp fixup
  ...
This commit is contained in:
Linus Torvalds
2013-02-21 11:34:25 -08:00
175 changed files with 25631 additions and 18988 deletions

View File

@@ -34,7 +34,7 @@ static struct clk *ac97_clk;
static struct clk *ac97conf_clk;
static int reset_gpio;
extern void pxa27x_assert_ac97reset(int reset_gpio, int on);
extern void pxa27x_configure_ac97reset(int reset_gpio, bool to_gpio);
/*
* Beware PXA27x bugs:
@@ -140,10 +140,10 @@ static inline void pxa_ac97_warm_pxa27x(void)
gsr_bits = 0;
/* warm reset broken on Bulverde, so manually keep AC97 reset high */
pxa27x_assert_ac97reset(reset_gpio, 1);
pxa27x_configure_ac97reset(reset_gpio, true);
udelay(10);
GCR |= GCR_WARM_RST;
pxa27x_assert_ac97reset(reset_gpio, 0);
pxa27x_configure_ac97reset(reset_gpio, false);
udelay(500);
}
@@ -358,7 +358,7 @@ int pxa2xx_ac97_hw_probe(struct platform_device *dev)
__func__, ret);
goto err_conf;
}
pxa27x_assert_ac97reset(reset_gpio, 0);
pxa27x_configure_ac97reset(reset_gpio, false);
ac97conf_clk = clk_get(&dev->dev, "AC97CONFCLK");
if (IS_ERR(ac97conf_clk)) {

View File

@@ -144,16 +144,17 @@ static int snd_compr_free(struct inode *inode, struct file *f)
return 0;
}
static void snd_compr_update_tstamp(struct snd_compr_stream *stream,
static int snd_compr_update_tstamp(struct snd_compr_stream *stream,
struct snd_compr_tstamp *tstamp)
{
if (!stream->ops->pointer)
return;
return -ENOTSUPP;
stream->ops->pointer(stream, tstamp);
pr_debug("dsp consumed till %d total %d bytes\n",
tstamp->byte_offset, tstamp->copied_total);
stream->runtime->hw_pointer = tstamp->byte_offset;
stream->runtime->total_bytes_transferred = tstamp->copied_total;
return 0;
}
static size_t snd_compr_calc_avail(struct snd_compr_stream *stream,
@@ -161,7 +162,9 @@ static size_t snd_compr_calc_avail(struct snd_compr_stream *stream,
{
long avail_calc; /*this needs to be signed variable */
memset(avail, 0, sizeof(*avail));
snd_compr_update_tstamp(stream, &avail->tstamp);
/* Still need to return avail even if tstamp can't be filled in */
/* FIXME: This needs to be different for capture stream,
available is # of compressed data, for playback it's
@@ -483,6 +486,8 @@ snd_compr_set_params(struct snd_compr_stream *stream, unsigned long arg)
if (retval)
goto out;
stream->runtime->state = SNDRV_PCM_STATE_SETUP;
stream->metadata_set = false;
stream->next_track = false;
} else {
return -EPERM;
}
@@ -514,14 +519,60 @@ out:
return retval;
}
static int
snd_compr_get_metadata(struct snd_compr_stream *stream, unsigned long arg)
{
struct snd_compr_metadata metadata;
int retval;
if (!stream->ops->get_metadata)
return -ENXIO;
if (copy_from_user(&metadata, (void __user *)arg, sizeof(metadata)))
return -EFAULT;
retval = stream->ops->get_metadata(stream, &metadata);
if (retval != 0)
return retval;
if (copy_to_user((void __user *)arg, &metadata, sizeof(metadata)))
return -EFAULT;
return 0;
}
static int
snd_compr_set_metadata(struct snd_compr_stream *stream, unsigned long arg)
{
struct snd_compr_metadata metadata;
int retval;
if (!stream->ops->set_metadata)
return -ENXIO;
/*
* we should allow parameter change only when stream has been
* opened not in other cases
*/
if (copy_from_user(&metadata, (void __user *)arg, sizeof(metadata)))
return -EFAULT;
retval = stream->ops->set_metadata(stream, &metadata);
stream->metadata_set = true;
return retval;
}
static inline int
snd_compr_tstamp(struct snd_compr_stream *stream, unsigned long arg)
{
struct snd_compr_tstamp tstamp;
struct snd_compr_tstamp tstamp = {0};
int ret;
snd_compr_update_tstamp(stream, &tstamp);
return copy_to_user((struct snd_compr_tstamp __user *)arg,
&tstamp, sizeof(tstamp)) ? -EFAULT : 0;
ret = snd_compr_update_tstamp(stream, &tstamp);
if (ret == 0)
ret = copy_to_user((struct snd_compr_tstamp __user *)arg,
&tstamp, sizeof(tstamp)) ? -EFAULT : 0;
return ret;
}
static int snd_compr_pause(struct snd_compr_stream *stream)
@@ -594,6 +645,44 @@ static int snd_compr_drain(struct snd_compr_stream *stream)
return retval;
}
static int snd_compr_next_track(struct snd_compr_stream *stream)
{
int retval;
/* only a running stream can transition to next track */
if (stream->runtime->state != SNDRV_PCM_STATE_RUNNING)
return -EPERM;
/* you can signal next track isf this is intended to be a gapless stream
* and current track metadata is set
*/
if (stream->metadata_set == false)
return -EPERM;
retval = stream->ops->trigger(stream, SND_COMPR_TRIGGER_NEXT_TRACK);
if (retval != 0)
return retval;
stream->metadata_set = false;
stream->next_track = true;
return 0;
}
static int snd_compr_partial_drain(struct snd_compr_stream *stream)
{
int retval;
if (stream->runtime->state == SNDRV_PCM_STATE_PREPARED ||
stream->runtime->state == SNDRV_PCM_STATE_SETUP)
return -EPERM;
/* stream can be drained only when next track has been signalled */
if (stream->next_track == false)
return -EPERM;
retval = stream->ops->trigger(stream, SND_COMPR_TRIGGER_PARTIAL_DRAIN);
stream->next_track = false;
return retval;
}
static long snd_compr_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
{
struct snd_compr_file *data = f->private_data;
@@ -623,6 +712,12 @@ static long snd_compr_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
case _IOC_NR(SNDRV_COMPRESS_GET_PARAMS):
retval = snd_compr_get_params(stream, arg);
break;
case _IOC_NR(SNDRV_COMPRESS_SET_METADATA):
retval = snd_compr_set_metadata(stream, arg);
break;
case _IOC_NR(SNDRV_COMPRESS_GET_METADATA):
retval = snd_compr_get_metadata(stream, arg);
break;
case _IOC_NR(SNDRV_COMPRESS_TSTAMP):
retval = snd_compr_tstamp(stream, arg);
break;
@@ -644,6 +739,13 @@ static long snd_compr_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
case _IOC_NR(SNDRV_COMPRESS_DRAIN):
retval = snd_compr_drain(stream);
break;
case _IOC_NR(SNDRV_COMPRESS_PARTIAL_DRAIN):
retval = snd_compr_partial_drain(stream);
break;
case _IOC_NR(SNDRV_COMPRESS_NEXT_TRACK):
retval = snd_compr_next_track(stream);
break;
}
mutex_unlock(&stream->device->lock);
return retval;

View File

@@ -286,12 +286,14 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd)
loopback_active_notify(dpcm);
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
case SNDRV_PCM_TRIGGER_SUSPEND:
spin_lock(&cable->lock);
cable->pause |= stream;
loopback_timer_stop(dpcm);
spin_unlock(&cable->lock);
break;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
case SNDRV_PCM_TRIGGER_RESUME:
spin_lock(&cable->lock);
dpcm->last_jiffies = jiffies;
cable->pause &= ~stream;
@@ -563,7 +565,8 @@ static snd_pcm_uframes_t loopback_pointer(struct snd_pcm_substream *substream)
static struct snd_pcm_hardware loopback_pcm_hardware =
{
.info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE),
SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE |
SNDRV_PCM_INFO_RESUME),
.formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |
SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE |
SNDRV_PCM_FMTBIT_FLOAT_LE | SNDRV_PCM_FMTBIT_FLOAT_BE),

View File

@@ -52,7 +52,6 @@ MODULE_LICENSE("GPL");
int snd_vx_check_reg_bit(struct vx_core *chip, int reg, int mask, int bit, int time)
{
unsigned long end_time = jiffies + (time * HZ + 999) / 1000;
#ifdef CONFIG_SND_DEBUG
static char *reg_names[VX_REG_MAX] = {
"ICR", "CVR", "ISR", "IVR", "RXH", "RXM", "RXL",
"DMA", "CDSP", "RFREQ", "RUER/V2", "DATA", "MEMIRQ",
@@ -60,7 +59,7 @@ int snd_vx_check_reg_bit(struct vx_core *chip, int reg, int mask, int bit, int t
"MIC3", "INTCSR", "CNTRL", "GPIOC",
"LOFREQ", "HIFREQ", "CSUER", "RUER"
};
#endif
do {
if ((snd_vx_inb(chip, reg) & mask) == bit)
return 0;

View File

@@ -678,6 +678,7 @@ config SND_LOLA
config SND_LX6464ES
tristate "Digigram LX6464ES"
depends on HAS_IOPORT
select SND_PCM
help
Say Y here to include support for Digigram LX6464ES boards.

View File

@@ -1435,7 +1435,7 @@ static snd_pcm_uframes_t snd_ali_pointer(struct snd_pcm_substream *substream)
spin_lock(&codec->reg_lock);
if (!pvoice->running) {
spin_unlock_irq(&codec->reg_lock);
spin_unlock(&codec->reg_lock);
return 0;
}
outb(pvoice->number, ALI_REG(codec, ALI_GC_CIR));

View File

@@ -567,8 +567,9 @@ static int ac97_probing_bugs(struct pci_dev *pci)
q = snd_pci_quirk_lookup(pci, atiixp_quirks);
if (q) {
snd_printdd(KERN_INFO "Atiixp quirk for %s. "
"Forcing codec %d\n", q->name, q->value);
snd_printdd(KERN_INFO
"Atiixp quirk for %s. Forcing codec %d\n",
snd_pci_quirk_name(q), q->value);
return q->value;
}
/* this hardware doesn't need workarounds. Probe for codec */

View File

@@ -650,6 +650,29 @@ static int snd_vortex_new_pcm(vortex_t *chip, int idx, int nr)
snd_dma_pci_data(chip->pci_dev),
0x10000, 0x10000);
switch (VORTEX_PCM_TYPE(pcm)) {
case VORTEX_PCM_ADB:
err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
snd_pcm_std_chmaps,
VORTEX_IS_QUAD(chip) ? 4 : 2,
0, NULL);
if (err < 0)
return err;
err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_CAPTURE,
snd_pcm_std_chmaps, 2, 0, NULL);
if (err < 0)
return err;
break;
#ifdef CHIP_AU8830
case VORTEX_PCM_A3D:
err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
snd_pcm_std_chmaps, 1, 0, NULL);
if (err < 0)
return err;
break;
#endif
};
if (VORTEX_PCM_TYPE(pcm) == VORTEX_PCM_SPDIF) {
for (i = 0; i < ARRAY_SIZE(snd_vortex_mixer_spdif); i++) {
kctl = snd_ctl_new1(&snd_vortex_mixer_spdif[i], chip);

View File

@@ -15,6 +15,9 @@ menuconfig SND_HDA_INTEL
if SND_HDA_INTEL
config SND_HDA_DSP_LOADER
bool
config SND_HDA_PREALLOC_SIZE
int "Pre-allocated buffer size for HD-audio driver"
range 0 32768
@@ -86,6 +89,7 @@ config SND_HDA_PATCH_LOADER
config SND_HDA_CODEC_REALTEK
bool "Build Realtek HD-audio codec support"
default y
select SND_HDA_GENERIC
help
Say Y here to include Realtek HD-audio codec support in
snd-hda-intel driver, such as ALC880.
@@ -98,6 +102,7 @@ config SND_HDA_CODEC_REALTEK
config SND_HDA_CODEC_ANALOG
bool "Build Analog Device HD-audio codec support"
default y
select SND_HDA_GENERIC
help
Say Y here to include Analog Device HD-audio codec support in
snd-hda-intel driver, such as AD1986A.
@@ -110,6 +115,7 @@ config SND_HDA_CODEC_ANALOG
config SND_HDA_CODEC_SIGMATEL
bool "Build IDT/Sigmatel HD-audio codec support"
default y
select SND_HDA_GENERIC
help
Say Y here to include IDT (Sigmatel) HD-audio codec support in
snd-hda-intel driver, such as STAC9200.
@@ -122,6 +128,7 @@ config SND_HDA_CODEC_SIGMATEL
config SND_HDA_CODEC_VIA
bool "Build VIA HD-audio codec support"
default y
select SND_HDA_GENERIC
help
Say Y here to include VIA HD-audio codec support in
snd-hda-intel driver, such as VT1708.
@@ -147,8 +154,8 @@ config SND_HDA_CODEC_HDMI
config SND_HDA_CODEC_CIRRUS
bool "Build Cirrus Logic codec support"
depends on SND_HDA_INTEL
default y
select SND_HDA_GENERIC
help
Say Y here to include Cirrus Logic codec support in
snd-hda-intel driver, such as CS4206.
@@ -161,6 +168,7 @@ config SND_HDA_CODEC_CIRRUS
config SND_HDA_CODEC_CONEXANT
bool "Build Conexant HD-audio codec support"
default y
select SND_HDA_GENERIC
help
Say Y here to include Conexant HD-audio codec support in
snd-hda-intel driver, such as CX20549.
@@ -172,8 +180,8 @@ config SND_HDA_CODEC_CONEXANT
config SND_HDA_CODEC_CA0110
bool "Build Creative CA0110-IBG codec support"
depends on SND_HDA_INTEL
default y
select SND_HDA_GENERIC
help
Say Y here to include Creative CA0110-IBG codec support in
snd-hda-intel driver, found on some Creative X-Fi cards.
@@ -185,7 +193,6 @@ config SND_HDA_CODEC_CA0110
config SND_HDA_CODEC_CA0132
bool "Build Creative CA0132 codec support"
depends on SND_HDA_INTEL
default y
help
Say Y here to include Creative CA0132 codec support in
@@ -196,9 +203,21 @@ config SND_HDA_CODEC_CA0132
snd-hda-codec-ca0132.
This module is automatically loaded at probing.
config SND_HDA_CODEC_CA0132_DSP
bool "Support new DSP code for CA0132 codec"
depends on SND_HDA_CODEC_CA0132 && FW_LOADER
select SND_HDA_DSP_LOADER
help
Say Y here to enable the DSP for Creative CA0132 for extended
features like equalizer or echo cancellation.
Note that this option requires the external firmware file
(ctefx.bin).
config SND_HDA_CODEC_CMEDIA
bool "Build C-Media HD-audio codec support"
default y
select SND_HDA_GENERIC
help
Say Y here to include C-Media HD-audio codec support in
snd-hda-intel driver, such as CMI9880.

409
sound/pci/hda/ca0132_regs.h Normal file
View File

@@ -0,0 +1,409 @@
/*
* HD audio interface patch for Creative CA0132 chip.
* CA0132 registers defines.
*
* Copyright (c) 2011, Creative Technology Ltd.
*
* This driver 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.
*
* This driver is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __CA0132_REGS_H
#define __CA0312_REGS_H
#define DSP_CHIP_OFFSET 0x100000
#define DSP_DBGCNTL_MODULE_OFFSET 0xE30
#define DSP_DBGCNTL_INST_OFFSET \
(DSP_CHIP_OFFSET + DSP_DBGCNTL_MODULE_OFFSET)
#define DSP_DBGCNTL_EXEC_LOBIT 0x0
#define DSP_DBGCNTL_EXEC_HIBIT 0x3
#define DSP_DBGCNTL_EXEC_MASK 0xF
#define DSP_DBGCNTL_SS_LOBIT 0x4
#define DSP_DBGCNTL_SS_HIBIT 0x7
#define DSP_DBGCNTL_SS_MASK 0xF0
#define DSP_DBGCNTL_STATE_LOBIT 0xA
#define DSP_DBGCNTL_STATE_HIBIT 0xD
#define DSP_DBGCNTL_STATE_MASK 0x3C00
#define XRAM_CHIP_OFFSET 0x0
#define XRAM_XRAM_CHANNEL_COUNT 0xE000
#define XRAM_XRAM_MODULE_OFFSET 0x0
#define XRAM_XRAM_CHAN_INCR 4
#define XRAM_XRAM_INST_OFFSET(_chan) \
(XRAM_CHIP_OFFSET + XRAM_XRAM_MODULE_OFFSET + \
(_chan * XRAM_XRAM_CHAN_INCR))
#define YRAM_CHIP_OFFSET 0x40000
#define YRAM_YRAM_CHANNEL_COUNT 0x8000
#define YRAM_YRAM_MODULE_OFFSET 0x0
#define YRAM_YRAM_CHAN_INCR 4
#define YRAM_YRAM_INST_OFFSET(_chan) \
(YRAM_CHIP_OFFSET + YRAM_YRAM_MODULE_OFFSET + \
(_chan * YRAM_YRAM_CHAN_INCR))
#define UC_CHIP_OFFSET 0x80000
#define UC_UC_CHANNEL_COUNT 0x10000
#define UC_UC_MODULE_OFFSET 0x0
#define UC_UC_CHAN_INCR 4
#define UC_UC_INST_OFFSET(_chan) \
(UC_CHIP_OFFSET + UC_UC_MODULE_OFFSET + \
(_chan * UC_UC_CHAN_INCR))
#define AXRAM_CHIP_OFFSET 0x3C000
#define AXRAM_AXRAM_CHANNEL_COUNT 0x1000
#define AXRAM_AXRAM_MODULE_OFFSET 0x0
#define AXRAM_AXRAM_CHAN_INCR 4
#define AXRAM_AXRAM_INST_OFFSET(_chan) \
(AXRAM_CHIP_OFFSET + AXRAM_AXRAM_MODULE_OFFSET + \
(_chan * AXRAM_AXRAM_CHAN_INCR))
#define AYRAM_CHIP_OFFSET 0x78000
#define AYRAM_AYRAM_CHANNEL_COUNT 0x1000
#define AYRAM_AYRAM_MODULE_OFFSET 0x0
#define AYRAM_AYRAM_CHAN_INCR 4
#define AYRAM_AYRAM_INST_OFFSET(_chan) \
(AYRAM_CHIP_OFFSET + AYRAM_AYRAM_MODULE_OFFSET + \
(_chan * AYRAM_AYRAM_CHAN_INCR))
#define DSPDMAC_CHIP_OFFSET 0x110000
#define DSPDMAC_DMA_CFG_CHANNEL_COUNT 12
#define DSPDMAC_DMACFG_MODULE_OFFSET 0xF00
#define DSPDMAC_DMACFG_CHAN_INCR 0x10
#define DSPDMAC_DMACFG_INST_OFFSET(_chan) \
(DSPDMAC_CHIP_OFFSET + DSPDMAC_DMACFG_MODULE_OFFSET + \
(_chan * DSPDMAC_DMACFG_CHAN_INCR))
#define DSPDMAC_DMACFG_DBADR_LOBIT 0x0
#define DSPDMAC_DMACFG_DBADR_HIBIT 0x10
#define DSPDMAC_DMACFG_DBADR_MASK 0x1FFFF
#define DSPDMAC_DMACFG_LP_LOBIT 0x11
#define DSPDMAC_DMACFG_LP_HIBIT 0x11
#define DSPDMAC_DMACFG_LP_MASK 0x20000
#define DSPDMAC_DMACFG_AINCR_LOBIT 0x12
#define DSPDMAC_DMACFG_AINCR_HIBIT 0x12
#define DSPDMAC_DMACFG_AINCR_MASK 0x40000
#define DSPDMAC_DMACFG_DWR_LOBIT 0x13
#define DSPDMAC_DMACFG_DWR_HIBIT 0x13
#define DSPDMAC_DMACFG_DWR_MASK 0x80000
#define DSPDMAC_DMACFG_AJUMP_LOBIT 0x14
#define DSPDMAC_DMACFG_AJUMP_HIBIT 0x17
#define DSPDMAC_DMACFG_AJUMP_MASK 0xF00000
#define DSPDMAC_DMACFG_AMODE_LOBIT 0x18
#define DSPDMAC_DMACFG_AMODE_HIBIT 0x19
#define DSPDMAC_DMACFG_AMODE_MASK 0x3000000
#define DSPDMAC_DMACFG_LK_LOBIT 0x1A
#define DSPDMAC_DMACFG_LK_HIBIT 0x1A
#define DSPDMAC_DMACFG_LK_MASK 0x4000000
#define DSPDMAC_DMACFG_AICS_LOBIT 0x1B
#define DSPDMAC_DMACFG_AICS_HIBIT 0x1F
#define DSPDMAC_DMACFG_AICS_MASK 0xF8000000
#define DSPDMAC_DMACFG_LP_SINGLE 0
#define DSPDMAC_DMACFG_LP_LOOPING 1
#define DSPDMAC_DMACFG_AINCR_XANDY 0
#define DSPDMAC_DMACFG_AINCR_XORY 1
#define DSPDMAC_DMACFG_DWR_DMA_RD 0
#define DSPDMAC_DMACFG_DWR_DMA_WR 1
#define DSPDMAC_DMACFG_AMODE_LINEAR 0
#define DSPDMAC_DMACFG_AMODE_RSV1 1
#define DSPDMAC_DMACFG_AMODE_WINTLV 2
#define DSPDMAC_DMACFG_AMODE_GINTLV 3
#define DSPDMAC_DSP_ADR_OFS_CHANNEL_COUNT 12
#define DSPDMAC_DSPADROFS_MODULE_OFFSET 0xF04
#define DSPDMAC_DSPADROFS_CHAN_INCR 0x10
#define DSPDMAC_DSPADROFS_INST_OFFSET(_chan) \
(DSPDMAC_CHIP_OFFSET + DSPDMAC_DSPADROFS_MODULE_OFFSET + \
(_chan * DSPDMAC_DSPADROFS_CHAN_INCR))
#define DSPDMAC_DSPADROFS_COFS_LOBIT 0x0
#define DSPDMAC_DSPADROFS_COFS_HIBIT 0xF
#define DSPDMAC_DSPADROFS_COFS_MASK 0xFFFF
#define DSPDMAC_DSPADROFS_BOFS_LOBIT 0x10
#define DSPDMAC_DSPADROFS_BOFS_HIBIT 0x1F
#define DSPDMAC_DSPADROFS_BOFS_MASK 0xFFFF0000
#define DSPDMAC_DSP_ADR_WOFS_CHANNEL_COUNT 12
#define DSPDMAC_DSPADRWOFS_MODULE_OFFSET 0xF04
#define DSPDMAC_DSPADRWOFS_CHAN_INCR 0x10
#define DSPDMAC_DSPADRWOFS_INST_OFFSET(_chan) \
(DSPDMAC_CHIP_OFFSET + DSPDMAC_DSPADRWOFS_MODULE_OFFSET + \
(_chan * DSPDMAC_DSPADRWOFS_CHAN_INCR))
#define DSPDMAC_DSPADRWOFS_WCOFS_LOBIT 0x0
#define DSPDMAC_DSPADRWOFS_WCOFS_HIBIT 0xA
#define DSPDMAC_DSPADRWOFS_WCOFS_MASK 0x7FF
#define DSPDMAC_DSPADRWOFS_WCBFR_LOBIT 0xB
#define DSPDMAC_DSPADRWOFS_WCBFR_HIBIT 0xF
#define DSPDMAC_DSPADRWOFS_WCBFR_MASK 0xF800
#define DSPDMAC_DSPADRWOFS_WBOFS_LOBIT 0x10
#define DSPDMAC_DSPADRWOFS_WBOFS_HIBIT 0x1A
#define DSPDMAC_DSPADRWOFS_WBOFS_MASK 0x7FF0000
#define DSPDMAC_DSPADRWOFS_WBBFR_LOBIT 0x1B
#define DSPDMAC_DSPADRWOFS_WBBFR_HIBIT 0x1F
#define DSPDMAC_DSPADRWOFS_WBBFR_MASK 0xF8000000
#define DSPDMAC_DSP_ADR_GOFS_CHANNEL_COUNT 12
#define DSPDMAC_DSPADRGOFS_MODULE_OFFSET 0xF04
#define DSPDMAC_DSPADRGOFS_CHAN_INCR 0x10
#define DSPDMAC_DSPADRGOFS_INST_OFFSET(_chan) \
(DSPDMAC_CHIP_OFFSET + DSPDMAC_DSPADRGOFS_MODULE_OFFSET + \
(_chan * DSPDMAC_DSPADRGOFS_CHAN_INCR))
#define DSPDMAC_DSPADRGOFS_GCOFS_LOBIT 0x0
#define DSPDMAC_DSPADRGOFS_GCOFS_HIBIT 0x9
#define DSPDMAC_DSPADRGOFS_GCOFS_MASK 0x3FF
#define DSPDMAC_DSPADRGOFS_GCS_LOBIT 0xA
#define DSPDMAC_DSPADRGOFS_GCS_HIBIT 0xC
#define DSPDMAC_DSPADRGOFS_GCS_MASK 0x1C00
#define DSPDMAC_DSPADRGOFS_GCBFR_LOBIT 0xD
#define DSPDMAC_DSPADRGOFS_GCBFR_HIBIT 0xF
#define DSPDMAC_DSPADRGOFS_GCBFR_MASK 0xE000
#define DSPDMAC_DSPADRGOFS_GBOFS_LOBIT 0x10
#define DSPDMAC_DSPADRGOFS_GBOFS_HIBIT 0x19
#define DSPDMAC_DSPADRGOFS_GBOFS_MASK 0x3FF0000
#define DSPDMAC_DSPADRGOFS_GBS_LOBIT 0x1A
#define DSPDMAC_DSPADRGOFS_GBS_HIBIT 0x1C
#define DSPDMAC_DSPADRGOFS_GBS_MASK 0x1C000000
#define DSPDMAC_DSPADRGOFS_GBBFR_LOBIT 0x1D
#define DSPDMAC_DSPADRGOFS_GBBFR_HIBIT 0x1F
#define DSPDMAC_DSPADRGOFS_GBBFR_MASK 0xE0000000
#define DSPDMAC_XFR_CNT_CHANNEL_COUNT 12
#define DSPDMAC_XFRCNT_MODULE_OFFSET 0xF08
#define DSPDMAC_XFRCNT_CHAN_INCR 0x10
#define DSPDMAC_XFRCNT_INST_OFFSET(_chan) \
(DSPDMAC_CHIP_OFFSET + DSPDMAC_XFRCNT_MODULE_OFFSET + \
(_chan * DSPDMAC_XFRCNT_CHAN_INCR))
#define DSPDMAC_XFRCNT_CCNT_LOBIT 0x0
#define DSPDMAC_XFRCNT_CCNT_HIBIT 0xF
#define DSPDMAC_XFRCNT_CCNT_MASK 0xFFFF
#define DSPDMAC_XFRCNT_BCNT_LOBIT 0x10
#define DSPDMAC_XFRCNT_BCNT_HIBIT 0x1F
#define DSPDMAC_XFRCNT_BCNT_MASK 0xFFFF0000
#define DSPDMAC_IRQ_CNT_CHANNEL_COUNT 12
#define DSPDMAC_IRQCNT_MODULE_OFFSET 0xF0C
#define DSPDMAC_IRQCNT_CHAN_INCR 0x10
#define DSPDMAC_IRQCNT_INST_OFFSET(_chan) \
(DSPDMAC_CHIP_OFFSET + DSPDMAC_IRQCNT_MODULE_OFFSET + \
(_chan * DSPDMAC_IRQCNT_CHAN_INCR))
#define DSPDMAC_IRQCNT_CICNT_LOBIT 0x0
#define DSPDMAC_IRQCNT_CICNT_HIBIT 0xF
#define DSPDMAC_IRQCNT_CICNT_MASK 0xFFFF
#define DSPDMAC_IRQCNT_BICNT_LOBIT 0x10
#define DSPDMAC_IRQCNT_BICNT_HIBIT 0x1F
#define DSPDMAC_IRQCNT_BICNT_MASK 0xFFFF0000
#define DSPDMAC_AUD_CHSEL_CHANNEL_COUNT 12
#define DSPDMAC_AUDCHSEL_MODULE_OFFSET 0xFC0
#define DSPDMAC_AUDCHSEL_CHAN_INCR 0x4
#define DSPDMAC_AUDCHSEL_INST_OFFSET(_chan) \
(DSPDMAC_CHIP_OFFSET + DSPDMAC_AUDCHSEL_MODULE_OFFSET + \
(_chan * DSPDMAC_AUDCHSEL_CHAN_INCR))
#define DSPDMAC_AUDCHSEL_ACS_LOBIT 0x0
#define DSPDMAC_AUDCHSEL_ACS_HIBIT 0x1F
#define DSPDMAC_AUDCHSEL_ACS_MASK 0xFFFFFFFF
#define DSPDMAC_CHNLSTART_MODULE_OFFSET 0xFF0
#define DSPDMAC_CHNLSTART_INST_OFFSET \
(DSPDMAC_CHIP_OFFSET + DSPDMAC_CHNLSTART_MODULE_OFFSET)
#define DSPDMAC_CHNLSTART_EN_LOBIT 0x0
#define DSPDMAC_CHNLSTART_EN_HIBIT 0xB
#define DSPDMAC_CHNLSTART_EN_MASK 0xFFF
#define DSPDMAC_CHNLSTART_VAI1_LOBIT 0xC
#define DSPDMAC_CHNLSTART_VAI1_HIBIT 0xF
#define DSPDMAC_CHNLSTART_VAI1_MASK 0xF000
#define DSPDMAC_CHNLSTART_DIS_LOBIT 0x10
#define DSPDMAC_CHNLSTART_DIS_HIBIT 0x1B
#define DSPDMAC_CHNLSTART_DIS_MASK 0xFFF0000
#define DSPDMAC_CHNLSTART_VAI2_LOBIT 0x1C
#define DSPDMAC_CHNLSTART_VAI2_HIBIT 0x1F
#define DSPDMAC_CHNLSTART_VAI2_MASK 0xF0000000
#define DSPDMAC_CHNLSTATUS_MODULE_OFFSET 0xFF4
#define DSPDMAC_CHNLSTATUS_INST_OFFSET \
(DSPDMAC_CHIP_OFFSET + DSPDMAC_CHNLSTATUS_MODULE_OFFSET)
#define DSPDMAC_CHNLSTATUS_ISC_LOBIT 0x0
#define DSPDMAC_CHNLSTATUS_ISC_HIBIT 0xB
#define DSPDMAC_CHNLSTATUS_ISC_MASK 0xFFF
#define DSPDMAC_CHNLSTATUS_AOO_LOBIT 0xC
#define DSPDMAC_CHNLSTATUS_AOO_HIBIT 0xC
#define DSPDMAC_CHNLSTATUS_AOO_MASK 0x1000
#define DSPDMAC_CHNLSTATUS_AOU_LOBIT 0xD
#define DSPDMAC_CHNLSTATUS_AOU_HIBIT 0xD
#define DSPDMAC_CHNLSTATUS_AOU_MASK 0x2000
#define DSPDMAC_CHNLSTATUS_AIO_LOBIT 0xE
#define DSPDMAC_CHNLSTATUS_AIO_HIBIT 0xE
#define DSPDMAC_CHNLSTATUS_AIO_MASK 0x4000
#define DSPDMAC_CHNLSTATUS_AIU_LOBIT 0xF
#define DSPDMAC_CHNLSTATUS_AIU_HIBIT 0xF
#define DSPDMAC_CHNLSTATUS_AIU_MASK 0x8000
#define DSPDMAC_CHNLSTATUS_IEN_LOBIT 0x10
#define DSPDMAC_CHNLSTATUS_IEN_HIBIT 0x1B
#define DSPDMAC_CHNLSTATUS_IEN_MASK 0xFFF0000
#define DSPDMAC_CHNLSTATUS_VAI0_LOBIT 0x1C
#define DSPDMAC_CHNLSTATUS_VAI0_HIBIT 0x1F
#define DSPDMAC_CHNLSTATUS_VAI0_MASK 0xF0000000
#define DSPDMAC_CHNLPROP_MODULE_OFFSET 0xFF8
#define DSPDMAC_CHNLPROP_INST_OFFSET \
(DSPDMAC_CHIP_OFFSET + DSPDMAC_CHNLPROP_MODULE_OFFSET)
#define DSPDMAC_CHNLPROP_DCON_LOBIT 0x0
#define DSPDMAC_CHNLPROP_DCON_HIBIT 0xB
#define DSPDMAC_CHNLPROP_DCON_MASK 0xFFF
#define DSPDMAC_CHNLPROP_FFS_LOBIT 0xC
#define DSPDMAC_CHNLPROP_FFS_HIBIT 0xC
#define DSPDMAC_CHNLPROP_FFS_MASK 0x1000
#define DSPDMAC_CHNLPROP_NAJ_LOBIT 0xD
#define DSPDMAC_CHNLPROP_NAJ_HIBIT 0xD
#define DSPDMAC_CHNLPROP_NAJ_MASK 0x2000
#define DSPDMAC_CHNLPROP_ENH_LOBIT 0xE
#define DSPDMAC_CHNLPROP_ENH_HIBIT 0xE
#define DSPDMAC_CHNLPROP_ENH_MASK 0x4000
#define DSPDMAC_CHNLPROP_MSPCE_LOBIT 0x10
#define DSPDMAC_CHNLPROP_MSPCE_HIBIT 0x1B
#define DSPDMAC_CHNLPROP_MSPCE_MASK 0xFFF0000
#define DSPDMAC_CHNLPROP_AC_LOBIT 0x1C
#define DSPDMAC_CHNLPROP_AC_HIBIT 0x1F
#define DSPDMAC_CHNLPROP_AC_MASK 0xF0000000
#define DSPDMAC_ACTIVE_MODULE_OFFSET 0xFFC
#define DSPDMAC_ACTIVE_INST_OFFSET \
(DSPDMAC_CHIP_OFFSET + DSPDMAC_ACTIVE_MODULE_OFFSET)
#define DSPDMAC_ACTIVE_AAR_LOBIT 0x0
#define DSPDMAC_ACTIVE_AAR_HIBIT 0xB
#define DSPDMAC_ACTIVE_AAR_MASK 0xFFF
#define DSPDMAC_ACTIVE_WFR_LOBIT 0xC
#define DSPDMAC_ACTIVE_WFR_HIBIT 0x17
#define DSPDMAC_ACTIVE_WFR_MASK 0xFFF000
#define DSP_AUX_MEM_BASE 0xE000
#define INVALID_CHIP_ADDRESS (~0U)
#define X_SIZE (XRAM_XRAM_CHANNEL_COUNT * XRAM_XRAM_CHAN_INCR)
#define Y_SIZE (YRAM_YRAM_CHANNEL_COUNT * YRAM_YRAM_CHAN_INCR)
#define AX_SIZE (AXRAM_AXRAM_CHANNEL_COUNT * AXRAM_AXRAM_CHAN_INCR)
#define AY_SIZE (AYRAM_AYRAM_CHANNEL_COUNT * AYRAM_AYRAM_CHAN_INCR)
#define UC_SIZE (UC_UC_CHANNEL_COUNT * UC_UC_CHAN_INCR)
#define XEXT_SIZE (X_SIZE + AX_SIZE)
#define YEXT_SIZE (Y_SIZE + AY_SIZE)
#define U64K 0x10000UL
#define X_END (XRAM_CHIP_OFFSET + X_SIZE)
#define X_EXT (XRAM_CHIP_OFFSET + XEXT_SIZE)
#define AX_END (XRAM_CHIP_OFFSET + U64K*4)
#define Y_END (YRAM_CHIP_OFFSET + Y_SIZE)
#define Y_EXT (YRAM_CHIP_OFFSET + YEXT_SIZE)
#define AY_END (YRAM_CHIP_OFFSET + U64K*4)
#define UC_END (UC_CHIP_OFFSET + UC_SIZE)
#define X_RANGE_MAIN(a, s) \
(((a)+((s)-1)*XRAM_XRAM_CHAN_INCR < X_END))
#define X_RANGE_AUX(a, s) \
(((a) >= X_END) && ((a)+((s)-1)*XRAM_XRAM_CHAN_INCR < AX_END))
#define X_RANGE_EXT(a, s) \
(((a)+((s)-1)*XRAM_XRAM_CHAN_INCR < X_EXT))
#define X_RANGE_ALL(a, s) \
(((a)+((s)-1)*XRAM_XRAM_CHAN_INCR < AX_END))
#define Y_RANGE_MAIN(a, s) \
(((a) >= YRAM_CHIP_OFFSET) && \
((a)+((s)-1)*YRAM_YRAM_CHAN_INCR < Y_END))
#define Y_RANGE_AUX(a, s) \
(((a) >= Y_END) && \
((a)+((s)-1)*YRAM_YRAM_CHAN_INCR < AY_END))
#define Y_RANGE_EXT(a, s) \
(((a) >= YRAM_CHIP_OFFSET) && \
((a)+((s)-1)*YRAM_YRAM_CHAN_INCR < Y_EXT))
#define Y_RANGE_ALL(a, s) \
(((a) >= YRAM_CHIP_OFFSET) && \
((a)+((s)-1)*YRAM_YRAM_CHAN_INCR < AY_END))
#define UC_RANGE(a, s) \
(((a) >= UC_CHIP_OFFSET) && \
((a)+((s)-1)*UC_UC_CHAN_INCR < UC_END))
#define X_OFF(a) \
(((a) - XRAM_CHIP_OFFSET) / XRAM_XRAM_CHAN_INCR)
#define AX_OFF(a) \
(((a) % (AXRAM_AXRAM_CHANNEL_COUNT * \
AXRAM_AXRAM_CHAN_INCR)) / AXRAM_AXRAM_CHAN_INCR)
#define Y_OFF(a) \
(((a) - YRAM_CHIP_OFFSET) / YRAM_YRAM_CHAN_INCR)
#define AY_OFF(a) \
(((a) % (AYRAM_AYRAM_CHANNEL_COUNT * \
AYRAM_AYRAM_CHAN_INCR)) / AYRAM_AYRAM_CHAN_INCR)
#define UC_OFF(a) (((a) - UC_CHIP_OFFSET) / UC_UC_CHAN_INCR)
#define X_EXT_MAIN_SIZE(a) (XRAM_XRAM_CHANNEL_COUNT - X_OFF(a))
#define X_EXT_AUX_SIZE(a, s) ((s) - X_EXT_MAIN_SIZE(a))
#define Y_EXT_MAIN_SIZE(a) (YRAM_YRAM_CHANNEL_COUNT - Y_OFF(a))
#define Y_EXT_AUX_SIZE(a, s) ((s) - Y_EXT_MAIN_SIZE(a))
#endif

View File

@@ -97,6 +97,28 @@ static void reorder_outputs(unsigned int nums, hda_nid_t *pins)
}
}
/* check whether the given pin has a proper pin I/O capability bit */
static bool check_pincap_validity(struct hda_codec *codec, hda_nid_t pin,
unsigned int dev)
{
unsigned int pincap = snd_hda_query_pin_caps(codec, pin);
/* some old hardware don't return the proper pincaps */
if (!pincap)
return true;
switch (dev) {
case AC_JACK_LINE_OUT:
case AC_JACK_SPEAKER:
case AC_JACK_HP_OUT:
case AC_JACK_SPDIF_OUT:
case AC_JACK_DIG_OTHER_OUT:
return !!(pincap & AC_PINCAP_OUT);
default:
return !!(pincap & AC_PINCAP_IN);
}
}
/*
* Parse all pin widgets and store the useful pin nids to cfg
*
@@ -126,6 +148,9 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
struct auto_out_pin hp_out[ARRAY_SIZE(cfg->hp_pins)];
int i;
if (!snd_hda_get_int_hint(codec, "parser_flags", &i))
cond_flags = i;
memset(cfg, 0, sizeof(*cfg));
memset(line_out, 0, sizeof(line_out));
@@ -156,10 +181,14 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
/* workaround for buggy BIOS setups */
if (dev == AC_JACK_LINE_OUT) {
if (conn == AC_JACK_PORT_FIXED)
if (conn == AC_JACK_PORT_FIXED ||
conn == AC_JACK_PORT_BOTH)
dev = AC_JACK_SPEAKER;
}
if (!check_pincap_validity(codec, nid, dev))
continue;
switch (dev) {
case AC_JACK_LINE_OUT:
seq = get_defcfg_sequence(def_conf);
@@ -363,7 +392,7 @@ static const char *hda_get_input_pin_label(struct hda_codec *codec,
{
unsigned int def_conf;
static const char * const mic_names[] = {
"Internal Mic", "Dock Mic", "Mic", "Front Mic", "Rear Mic",
"Internal Mic", "Dock Mic", "Mic", "Rear Mic", "Front Mic"
};
int attr;
@@ -394,6 +423,8 @@ static const char *hda_get_input_pin_label(struct hda_codec *codec,
return "SPDIF In";
case AC_JACK_DIG_OTHER_IN:
return "Digital In";
case AC_JACK_HP_OUT:
return "Headphone Mic";
default:
return "Misc";
}
@@ -552,6 +583,9 @@ static int fill_audio_out_name(struct hda_codec *codec, hda_nid_t nid,
return 1;
}
#define is_hdmi_cfg(conf) \
(get_defcfg_location(conf) == AC_JACK_LOC_HDMI)
/**
* snd_hda_get_pin_label - Get a label for the given I/O pin
*
@@ -572,6 +606,7 @@ int snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid,
unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid);
const char *name = NULL;
int i;
bool hdmi;
if (indexp)
*indexp = 0;
@@ -590,16 +625,18 @@ int snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid,
label, maxlen, indexp);
case AC_JACK_SPDIF_OUT:
case AC_JACK_DIG_OTHER_OUT:
if (get_defcfg_location(def_conf) == AC_JACK_LOC_HDMI)
name = "HDMI";
else
name = "SPDIF";
if (cfg && indexp) {
i = find_idx_in_nid_list(nid, cfg->dig_out_pins,
cfg->dig_outs);
if (i >= 0)
*indexp = i;
}
hdmi = is_hdmi_cfg(def_conf);
name = hdmi ? "HDMI" : "SPDIF";
if (cfg && indexp)
for (i = 0; i < cfg->dig_outs; i++) {
hda_nid_t pin = cfg->dig_out_pins[i];
unsigned int c;
if (pin == nid)
break;
c = snd_hda_codec_get_pincfg(codec, pin);
if (hdmi == is_hdmi_cfg(c))
(*indexp)++;
}
break;
default:
if (cfg) {
@@ -622,28 +659,27 @@ int snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid,
}
EXPORT_SYMBOL_HDA(snd_hda_get_pin_label);
int snd_hda_gen_add_verbs(struct hda_gen_spec *spec,
const struct hda_verb *list)
int snd_hda_add_verbs(struct hda_codec *codec,
const struct hda_verb *list)
{
const struct hda_verb **v;
v = snd_array_new(&spec->verbs);
v = snd_array_new(&codec->verbs);
if (!v)
return -ENOMEM;
*v = list;
return 0;
}
EXPORT_SYMBOL_HDA(snd_hda_gen_add_verbs);
EXPORT_SYMBOL_HDA(snd_hda_add_verbs);
void snd_hda_gen_apply_verbs(struct hda_codec *codec)
void snd_hda_apply_verbs(struct hda_codec *codec)
{
struct hda_gen_spec *spec = codec->spec;
int i;
for (i = 0; i < spec->verbs.used; i++) {
struct hda_verb **v = snd_array_elem(&spec->verbs, i);
for (i = 0; i < codec->verbs.used; i++) {
struct hda_verb **v = snd_array_elem(&codec->verbs, i);
snd_hda_sequence_write(codec, *v);
}
}
EXPORT_SYMBOL_HDA(snd_hda_gen_apply_verbs);
EXPORT_SYMBOL_HDA(snd_hda_apply_verbs);
void snd_hda_apply_pincfgs(struct hda_codec *codec,
const struct hda_pintbl *cfg)
@@ -653,20 +689,22 @@ void snd_hda_apply_pincfgs(struct hda_codec *codec,
}
EXPORT_SYMBOL_HDA(snd_hda_apply_pincfgs);
void snd_hda_apply_fixup(struct hda_codec *codec, int action)
static void set_pin_targets(struct hda_codec *codec,
const struct hda_pintbl *cfg)
{
struct hda_gen_spec *spec = codec->spec;
int id = spec->fixup_id;
#ifdef CONFIG_SND_DEBUG_VERBOSE
const char *modelname = spec->fixup_name;
#endif
int depth = 0;
for (; cfg->nid; cfg++)
snd_hda_set_pin_ctl_cache(codec, cfg->nid, cfg->val);
}
if (!spec->fixup_list)
return;
static void apply_fixup(struct hda_codec *codec, int id, int action, int depth)
{
const char *modelname = codec->fixup_name;
while (id >= 0) {
const struct hda_fixup *fix = spec->fixup_list + id;
const struct hda_fixup *fix = codec->fixup_list + id;
if (fix->chained_before)
apply_fixup(codec, fix->chain_id, action, depth + 1);
switch (fix->type) {
case HDA_FIXUP_PINS:
@@ -683,7 +721,7 @@ void snd_hda_apply_fixup(struct hda_codec *codec, int action)
snd_printdd(KERN_INFO SFX
"%s: Apply fix-verbs for %s\n",
codec->chip_name, modelname);
snd_hda_gen_add_verbs(codec->spec, fix->v.verbs);
snd_hda_add_verbs(codec, fix->v.verbs);
break;
case HDA_FIXUP_FUNC:
if (!fix->v.func)
@@ -693,19 +731,33 @@ void snd_hda_apply_fixup(struct hda_codec *codec, int action)
codec->chip_name, modelname);
fix->v.func(codec, fix, action);
break;
case HDA_FIXUP_PINCTLS:
if (action != HDA_FIXUP_ACT_PROBE || !fix->v.pins)
break;
snd_printdd(KERN_INFO SFX
"%s: Apply pinctl for %s\n",
codec->chip_name, modelname);
set_pin_targets(codec, fix->v.pins);
break;
default:
snd_printk(KERN_ERR SFX
"%s: Invalid fixup type %d\n",
codec->chip_name, fix->type);
break;
}
if (!fix->chained)
if (!fix->chained || fix->chained_before)
break;
if (++depth > 10)
break;
id = fix->chain_id;
}
}
void snd_hda_apply_fixup(struct hda_codec *codec, int action)
{
if (codec->fixup_list)
apply_fixup(codec, codec->fixup_id, action, 0);
}
EXPORT_SYMBOL_HDA(snd_hda_apply_fixup);
void snd_hda_pick_fixup(struct hda_codec *codec,
@@ -713,15 +765,14 @@ void snd_hda_pick_fixup(struct hda_codec *codec,
const struct snd_pci_quirk *quirk,
const struct hda_fixup *fixlist)
{
struct hda_gen_spec *spec = codec->spec;
const struct snd_pci_quirk *q;
int id = -1;
const char *name = NULL;
/* when model=nofixup is given, don't pick up any fixups */
if (codec->modelname && !strcmp(codec->modelname, "nofixup")) {
spec->fixup_list = NULL;
spec->fixup_id = -1;
codec->fixup_list = NULL;
codec->fixup_id = -1;
return;
}
@@ -759,10 +810,10 @@ void snd_hda_pick_fixup(struct hda_codec *codec,
}
}
spec->fixup_id = id;
codec->fixup_id = id;
if (id >= 0) {
spec->fixup_list = fixlist;
spec->fixup_name = name;
codec->fixup_list = fixlist;
codec->fixup_name = name;
}
}
EXPORT_SYMBOL_HDA(snd_hda_pick_fixup);

View File

@@ -51,8 +51,9 @@ enum {
INPUT_PIN_ATTR_INT, /* internal mic/line-in */
INPUT_PIN_ATTR_DOCK, /* docking mic/line-in */
INPUT_PIN_ATTR_NORMAL, /* mic/line-in jack */
INPUT_PIN_ATTR_FRONT, /* mic/line-in jack in front */
INPUT_PIN_ATTR_REAR, /* mic/line-in jack in rear */
INPUT_PIN_ATTR_FRONT, /* mic/line-in jack in front */
INPUT_PIN_ATTR_LAST = INPUT_PIN_ATTR_FRONT,
};
int snd_hda_get_input_pin_attr(unsigned int def_conf);
@@ -89,82 +90,4 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
#define snd_hda_parse_pin_def_config(codec, cfg, ignore) \
snd_hda_parse_pin_defcfg(codec, cfg, ignore, 0)
/*
*/
struct hda_gen_spec {
/* fix-up list */
int fixup_id;
const struct hda_fixup *fixup_list;
const char *fixup_name;
/* additional init verbs */
struct snd_array verbs;
};
/*
* Fix-up pin default configurations and add default verbs
*/
struct hda_pintbl {
hda_nid_t nid;
u32 val;
};
struct hda_model_fixup {
const int id;
const char *name;
};
struct hda_fixup {
int type;
bool chained;
int chain_id;
union {
const struct hda_pintbl *pins;
const struct hda_verb *verbs;
void (*func)(struct hda_codec *codec,
const struct hda_fixup *fix,
int action);
} v;
};
/* fixup types */
enum {
HDA_FIXUP_INVALID,
HDA_FIXUP_PINS,
HDA_FIXUP_VERBS,
HDA_FIXUP_FUNC,
};
/* fixup action definitions */
enum {
HDA_FIXUP_ACT_PRE_PROBE,
HDA_FIXUP_ACT_PROBE,
HDA_FIXUP_ACT_INIT,
HDA_FIXUP_ACT_BUILD,
};
int snd_hda_gen_add_verbs(struct hda_gen_spec *spec,
const struct hda_verb *list);
void snd_hda_gen_apply_verbs(struct hda_codec *codec);
void snd_hda_apply_pincfgs(struct hda_codec *codec,
const struct hda_pintbl *cfg);
void snd_hda_apply_fixup(struct hda_codec *codec, int action);
void snd_hda_pick_fixup(struct hda_codec *codec,
const struct hda_model_fixup *models,
const struct snd_pci_quirk *quirk,
const struct hda_fixup *fixlist);
static inline void snd_hda_gen_init(struct hda_gen_spec *spec)
{
snd_array_init(&spec->verbs, sizeof(struct hda_verb *), 8);
}
static inline void snd_hda_gen_free(struct hda_gen_spec *spec)
{
snd_array_free(&spec->verbs);
}
#endif /* __SOUND_HDA_AUTO_PARSER_H */

File diff suppressed because it is too large Load Diff

View File

@@ -551,9 +551,6 @@ enum {
AC_JACK_PORT_BOTH,
};
/* max. connections to a widget */
#define HDA_MAX_CONNECTIONS 32
/* max. codec address */
#define HDA_MAX_CODEC_ADDRESS 0x0f
@@ -618,6 +615,17 @@ struct hda_bus_ops {
/* notify power-up/down from codec to controller */
void (*pm_notify)(struct hda_bus *bus, bool power_up);
#endif
#ifdef CONFIG_SND_HDA_DSP_LOADER
/* prepare DSP transfer */
int (*load_dsp_prepare)(struct hda_bus *bus, unsigned int format,
unsigned int byte_size,
struct snd_dma_buffer *bufp);
/* start/stop DSP transfer */
void (*load_dsp_trigger)(struct hda_bus *bus, bool start);
/* clean up DSP transfer */
void (*load_dsp_cleanup)(struct hda_bus *bus,
struct snd_dma_buffer *dmab);
#endif
};
/* template to pass to the bus constructor */
@@ -671,6 +679,8 @@ struct hda_bus {
unsigned int response_reset:1; /* controller was reset */
unsigned int in_reset:1; /* during reset operation */
unsigned int power_keep_link_on:1; /* don't power off HDA link */
int primary_dig_out_type; /* primary digital out PCM type */
};
/*
@@ -719,9 +729,10 @@ struct hda_codec_ops {
/* record for amp information cache */
struct hda_cache_head {
u32 key; /* hash key */
u32 key:31; /* hash key */
u32 dirty:1;
u16 val; /* assigned value */
u16 next; /* next link; -1 = terminal */
u16 next;
};
struct hda_amp_info {
@@ -830,20 +841,20 @@ struct hda_codec {
struct hda_cache_rec amp_cache; /* cache for amp access */
struct hda_cache_rec cmd_cache; /* cache for other commands */
struct snd_array conn_lists; /* connection-list array */
struct list_head conn_list; /* linked-list of connection-list */
struct mutex spdif_mutex;
struct mutex control_mutex;
struct mutex hash_mutex;
struct snd_array spdif_out;
unsigned int spdif_in_enable; /* SPDIF input enable? */
int primary_dig_out_type; /* primary digital out PCM type */
const hda_nid_t *slave_dig_outs; /* optional digital out slave widgets */
struct snd_array init_pins; /* initial (BIOS) pin configurations */
struct snd_array driver_pins; /* pin configs set by codec parser */
struct snd_array cvt_setups; /* audio convert setups */
#ifdef CONFIG_SND_HDA_HWDEP
struct mutex user_mutex;
struct snd_hwdep *hwdep; /* assigned hwdep device */
struct snd_array init_verbs; /* additional init verbs */
struct snd_array hints; /* additional hints */
@@ -865,8 +876,11 @@ struct hda_codec {
unsigned int pins_shutup:1; /* pins are shut up */
unsigned int no_trigger_sense:1; /* don't trigger at pin-sensing */
unsigned int no_jack_detect:1; /* Machine has no jack-detection */
unsigned int inv_eapd:1; /* broken h/w: inverted EAPD control */
unsigned int inv_jack_detect:1; /* broken h/w: inverted detection bit */
unsigned int pcm_format_first:1; /* PCM format must be set first */
unsigned int epss:1; /* supporting EPSS? */
unsigned int cached_write:1; /* write only to caches */
#ifdef CONFIG_PM
unsigned int power_on :1; /* current (global) power-state */
unsigned int d3_stop_clk:1; /* support D3 operation without BCLK */
@@ -881,6 +895,10 @@ struct hda_codec {
spinlock_t power_lock;
#endif
/* filter the requested power state per nid */
unsigned int (*power_filter)(struct hda_codec *codec, hda_nid_t nid,
unsigned int power_state);
/* codec-specific additional proc output */
void (*proc_widget_hook)(struct snd_info_buffer *buffer,
struct hda_codec *codec, hda_nid_t nid);
@@ -894,6 +912,14 @@ struct hda_codec {
/* jack detection */
struct snd_array jacks;
#endif
/* fix-up list */
int fixup_id;
const struct hda_fixup *fixup_list;
const char *fixup_name;
/* additional init verbs */
struct snd_array verbs;
};
/* direction */
@@ -910,6 +936,7 @@ int snd_hda_bus_new(struct snd_card *card, const struct hda_bus_template *temp,
int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
struct hda_codec **codecp);
int snd_hda_codec_configure(struct hda_codec *codec);
int snd_hda_codec_update_widgets(struct hda_codec *codec);
/*
* low level functions
@@ -930,8 +957,11 @@ snd_hda_get_num_conns(struct hda_codec *codec, hda_nid_t nid)
{
return snd_hda_get_connections(codec, nid, NULL, 0);
}
int snd_hda_get_num_raw_conns(struct hda_codec *codec, hda_nid_t nid);
int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid,
hda_nid_t *conn_list, int max_conns);
int snd_hda_get_conn_list(struct hda_codec *codec, hda_nid_t nid,
const hda_nid_t **listp);
int snd_hda_override_conn_list(struct hda_codec *codec, hda_nid_t nid, int nums,
const hda_nid_t *list);
int snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux,
@@ -952,7 +982,6 @@ void snd_hda_sequence_write(struct hda_codec *codec,
int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex);
/* cached write */
#ifdef CONFIG_PM
int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid,
int direct, unsigned int verb, unsigned int parm);
void snd_hda_sequence_write_cache(struct hda_codec *codec,
@@ -960,17 +989,14 @@ void snd_hda_sequence_write_cache(struct hda_codec *codec,
int snd_hda_codec_update_cache(struct hda_codec *codec, hda_nid_t nid,
int direct, unsigned int verb, unsigned int parm);
void snd_hda_codec_resume_cache(struct hda_codec *codec);
#else
#define snd_hda_codec_write_cache snd_hda_codec_write
#define snd_hda_codec_update_cache snd_hda_codec_write
#define snd_hda_sequence_write_cache snd_hda_sequence_write
#endif
/* both for cmd & amp caches */
void snd_hda_codec_flush_cache(struct hda_codec *codec);
/* the struct for codec->pin_configs */
struct hda_pincfg {
hda_nid_t nid;
unsigned char ctrl; /* current pin control value */
unsigned char pad; /* reserved */
unsigned char ctrl; /* original pin control value */
unsigned char target; /* target pin control value */
unsigned int cfg; /* default configuration */
};
@@ -1036,8 +1062,7 @@ extern const struct snd_pcm_chmap_elem snd_pcm_2_1_chmaps[];
void snd_hda_get_codec_name(struct hda_codec *codec, char *name, int namelen);
void snd_hda_bus_reboot_notify(struct hda_bus *bus);
void snd_hda_codec_set_power_to_all(struct hda_codec *codec, hda_nid_t fg,
unsigned int power_state,
bool eapd_workaround);
unsigned int power_state);
int snd_hda_lock_devices(struct hda_bus *bus);
void snd_hda_unlock_devices(struct hda_bus *bus);
@@ -1136,6 +1161,40 @@ static inline void snd_hda_power_sync(struct hda_codec *codec)
int snd_hda_load_patch(struct hda_bus *bus, size_t size, const void *buf);
#endif
#ifdef CONFIG_SND_HDA_DSP_LOADER
static inline int
snd_hda_codec_load_dsp_prepare(struct hda_codec *codec, unsigned int format,
unsigned int size,
struct snd_dma_buffer *bufp)
{
return codec->bus->ops.load_dsp_prepare(codec->bus, format, size, bufp);
}
static inline void
snd_hda_codec_load_dsp_trigger(struct hda_codec *codec, bool start)
{
return codec->bus->ops.load_dsp_trigger(codec->bus, start);
}
static inline void
snd_hda_codec_load_dsp_cleanup(struct hda_codec *codec,
struct snd_dma_buffer *dmab)
{
return codec->bus->ops.load_dsp_cleanup(codec->bus, dmab);
}
#else
static inline int
snd_hda_codec_load_dsp_prepare(struct hda_codec *codec, unsigned int format,
unsigned int size,
struct snd_dma_buffer *bufp)
{
return -ENOSYS;
}
static inline void
snd_hda_codec_load_dsp_trigger(struct hda_codec *codec, bool start) {}
static inline void
snd_hda_codec_load_dsp_cleanup(struct hda_codec *codec,
struct snd_dma_buffer *dmab) {}
#endif
/*
* Codec modularization
*/

View File

@@ -246,8 +246,8 @@ static void hdmi_update_short_audio_desc(struct cea_sad *a,
/*
* Be careful, ELD buf could be totally rubbish!
*/
static int hdmi_update_eld(struct hdmi_eld *e,
const unsigned char *buf, int size)
int snd_hdmi_parse_eld(struct parsed_hdmi_eld *e,
const unsigned char *buf, int size)
{
int mnl;
int i;
@@ -260,7 +260,6 @@ static int hdmi_update_eld(struct hdmi_eld *e,
goto out_fail;
}
e->eld_size = size;
e->baseline_len = GRAB_BITS(buf, 2, 0, 8);
mnl = GRAB_BITS(buf, 4, 0, 5);
e->cea_edid_ver = GRAB_BITS(buf, 4, 5, 3);
@@ -305,7 +304,6 @@ static int hdmi_update_eld(struct hdmi_eld *e,
if (!e->spk_alloc)
e->spk_alloc = 0xffff;
e->eld_valid = true;
return 0;
out_fail:
@@ -318,17 +316,16 @@ int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid)
AC_DIPSIZE_ELD_BUF);
}
int snd_hdmi_get_eld(struct hdmi_eld *eld,
struct hda_codec *codec, hda_nid_t nid)
int snd_hdmi_get_eld(struct hda_codec *codec, hda_nid_t nid,
unsigned char *buf, int *eld_size)
{
int i;
int ret;
int size;
unsigned char *buf;
/*
* ELD size is initialized to zero in caller function. If no errors and
* ELD is valid, actual eld_size is assigned in hdmi_update_eld()
* ELD is valid, actual eld_size is assigned.
*/
size = snd_hdmi_get_eld_size(codec, nid);
@@ -343,8 +340,6 @@ int snd_hdmi_get_eld(struct hdmi_eld *eld,
}
/* set ELD buffer */
buf = eld->eld_buffer;
for (i = 0; i < size; i++) {
unsigned int val = hdmi_get_eld_data(codec, nid, i);
/*
@@ -372,8 +367,7 @@ int snd_hdmi_get_eld(struct hdmi_eld *eld,
buf[i] = val;
}
ret = hdmi_update_eld(eld, buf, size);
*eld_size = size;
error:
return ret;
}
@@ -438,7 +432,7 @@ void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen)
buf[j] = '\0'; /* necessary when j == 0 */
}
void snd_hdmi_show_eld(struct hdmi_eld *e)
void snd_hdmi_show_eld(struct parsed_hdmi_eld *e)
{
int i;
@@ -487,10 +481,11 @@ static void hdmi_print_sad_info(int i, struct cea_sad *a,
static void hdmi_print_eld_info(struct snd_info_entry *entry,
struct snd_info_buffer *buffer)
{
struct hdmi_eld *e = entry->private_data;
struct hdmi_eld *eld = entry->private_data;
struct parsed_hdmi_eld *e = &eld->info;
char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE];
int i;
static char *eld_versoin_names[32] = {
static char *eld_version_names[32] = {
"reserved",
"reserved",
"CEA-861D or below",
@@ -505,15 +500,18 @@ static void hdmi_print_eld_info(struct snd_info_entry *entry,
[4 ... 7] = "reserved"
};
snd_iprintf(buffer, "monitor_present\t\t%d\n", e->monitor_present);
snd_iprintf(buffer, "eld_valid\t\t%d\n", e->eld_valid);
if (!e->eld_valid)
mutex_lock(&eld->lock);
snd_iprintf(buffer, "monitor_present\t\t%d\n", eld->monitor_present);
snd_iprintf(buffer, "eld_valid\t\t%d\n", eld->eld_valid);
if (!eld->eld_valid) {
mutex_unlock(&eld->lock);
return;
}
snd_iprintf(buffer, "monitor_name\t\t%s\n", e->monitor_name);
snd_iprintf(buffer, "connection_type\t\t%s\n",
eld_connection_type_names[e->conn_type]);
snd_iprintf(buffer, "eld_version\t\t[0x%x] %s\n", e->eld_ver,
eld_versoin_names[e->eld_ver]);
eld_version_names[e->eld_ver]);
snd_iprintf(buffer, "edid_version\t\t[0x%x] %s\n", e->cea_edid_ver,
cea_edid_version_names[e->cea_edid_ver]);
snd_iprintf(buffer, "manufacture_id\t\t0x%x\n", e->manufacture_id);
@@ -530,18 +528,21 @@ static void hdmi_print_eld_info(struct snd_info_entry *entry,
for (i = 0; i < e->sad_count; i++)
hdmi_print_sad_info(i, e->sad + i, buffer);
mutex_unlock(&eld->lock);
}
static void hdmi_write_eld_info(struct snd_info_entry *entry,
struct snd_info_buffer *buffer)
{
struct hdmi_eld *e = entry->private_data;
struct hdmi_eld *eld = entry->private_data;
struct parsed_hdmi_eld *e = &eld->info;
char line[64];
char name[64];
char *sname;
long long val;
unsigned int n;
mutex_lock(&eld->lock);
while (!snd_info_get_line(buffer, line, sizeof(line))) {
if (sscanf(line, "%s %llx", name, &val) != 2)
continue;
@@ -551,9 +552,9 @@ static void hdmi_write_eld_info(struct snd_info_entry *entry,
* eld_version edid_version
*/
if (!strcmp(name, "monitor_present"))
e->monitor_present = val;
eld->monitor_present = val;
else if (!strcmp(name, "eld_valid"))
e->eld_valid = val;
eld->eld_valid = val;
else if (!strcmp(name, "connection_type"))
e->conn_type = val;
else if (!strcmp(name, "port_id"))
@@ -593,6 +594,7 @@ static void hdmi_write_eld_info(struct snd_info_entry *entry,
e->sad_count = n + 1;
}
}
mutex_unlock(&eld->lock);
}
@@ -627,7 +629,7 @@ void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld)
#endif /* CONFIG_PROC_FS */
/* update PCM info based on ELD */
void snd_hdmi_eld_update_pcm_info(struct hdmi_eld *eld,
void snd_hdmi_eld_update_pcm_info(struct parsed_hdmi_eld *e,
struct hda_pcm_stream *hinfo)
{
u32 rates;
@@ -644,8 +646,8 @@ void snd_hdmi_eld_update_pcm_info(struct hdmi_eld *eld,
formats = SNDRV_PCM_FMTBIT_S16_LE;
maxbps = 16;
channels_max = 2;
for (i = 0; i < eld->sad_count; i++) {
struct cea_sad *a = &eld->sad[i];
for (i = 0; i < e->sad_count; i++) {
struct cea_sad *a = &e->sad[i];
rates |= a->rates;
if (a->channels > channels_max)
channels_max = a->channels;

File diff suppressed because it is too large Load Diff

303
sound/pci/hda/hda_generic.h Normal file
View File

@@ -0,0 +1,303 @@
/*
* Generic BIOS auto-parser helper functions for HD-audio
*
* Copyright (c) 2012 Takashi Iwai <tiwai@suse.de>
*
* This driver 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.
*/
#ifndef __SOUND_HDA_GENERIC_H
#define __SOUND_HDA_GENERIC_H
/* unsol event tags */
enum {
HDA_GEN_HP_EVENT = 1, HDA_GEN_FRONT_EVENT, HDA_GEN_MIC_EVENT,
HDA_GEN_LAST_EVENT = HDA_GEN_MIC_EVENT
};
/* table entry for multi-io paths */
struct hda_multi_io {
hda_nid_t pin; /* multi-io widget pin NID */
hda_nid_t dac; /* DAC to be connected */
unsigned int ctl_in; /* cached input-pin control value */
};
/* Widget connection path
*
* For output, stored in the order of DAC -> ... -> pin,
* for input, pin -> ... -> ADC.
*
* idx[i] contains the source index number to select on of the widget path[i];
* e.g. idx[1] is the index of the DAC (path[0]) selected by path[1] widget
* multi[] indicates whether it's a selector widget with multi-connectors
* (i.e. the connection selection is mandatory)
* vol_ctl and mute_ctl contains the NIDs for the assigned mixers
*/
#define MAX_NID_PATH_DEPTH 10
enum {
NID_PATH_VOL_CTL,
NID_PATH_MUTE_CTL,
NID_PATH_BOOST_CTL,
NID_PATH_NUM_CTLS
};
struct nid_path {
int depth;
hda_nid_t path[MAX_NID_PATH_DEPTH];
unsigned char idx[MAX_NID_PATH_DEPTH];
unsigned char multi[MAX_NID_PATH_DEPTH];
unsigned int ctls[NID_PATH_NUM_CTLS]; /* NID_PATH_XXX_CTL */
bool active;
};
/* mic/line-in auto switching entry */
#define MAX_AUTO_MIC_PINS 3
struct automic_entry {
hda_nid_t pin; /* pin */
int idx; /* imux index, -1 = invalid */
unsigned int attr; /* pin attribute (INPUT_PIN_ATTR_*) */
};
/* active stream id */
enum { STREAM_MULTI_OUT, STREAM_INDEP_HP };
/* PCM hook action */
enum {
HDA_GEN_PCM_ACT_OPEN,
HDA_GEN_PCM_ACT_PREPARE,
HDA_GEN_PCM_ACT_CLEANUP,
HDA_GEN_PCM_ACT_CLOSE,
};
struct hda_gen_spec {
char stream_name_analog[32]; /* analog PCM stream */
const struct hda_pcm_stream *stream_analog_playback;
const struct hda_pcm_stream *stream_analog_capture;
char stream_name_alt_analog[32]; /* alternative analog PCM stream */
const struct hda_pcm_stream *stream_analog_alt_playback;
const struct hda_pcm_stream *stream_analog_alt_capture;
char stream_name_digital[32]; /* digital PCM stream */
const struct hda_pcm_stream *stream_digital_playback;
const struct hda_pcm_stream *stream_digital_capture;
/* PCM */
unsigned int active_streams;
struct mutex pcm_mutex;
/* playback */
struct hda_multi_out multiout; /* playback set-up
* max_channels, dacs must be set
* dig_out_nid and hp_nid are optional
*/
hda_nid_t alt_dac_nid;
hda_nid_t slave_dig_outs[3]; /* optional - for auto-parsing */
int dig_out_type;
/* capture */
unsigned int num_adc_nids;
hda_nid_t adc_nids[AUTO_CFG_MAX_INS];
hda_nid_t dig_in_nid; /* digital-in NID; optional */
hda_nid_t mixer_nid; /* analog-mixer NID */
hda_nid_t mixer_merge_nid; /* aamix merge-point NID (optional) */
const char *input_labels[HDA_MAX_NUM_INPUTS];
int input_label_idxs[HDA_MAX_NUM_INPUTS];
/* capture setup for dynamic dual-adc switch */
hda_nid_t cur_adc;
unsigned int cur_adc_stream_tag;
unsigned int cur_adc_format;
/* capture source */
struct hda_input_mux input_mux;
unsigned int cur_mux[3];
/* channel model */
/* min_channel_count contains the minimum channel count for primary
* outputs. When multi_ios is set, the channels can be configured
* between min_channel_count and (min_channel_count + multi_ios * 2).
*
* ext_channel_count contains the current channel count of the primary
* out. This varies in the range above.
*
* Meanwhile, const_channel_count is the channel count for all outputs
* including headphone and speakers. It's a constant value, and the
* PCM is set up as max(ext_channel_count, const_channel_count).
*/
int min_channel_count; /* min. channel count for primary out */
int ext_channel_count; /* current channel count for primary */
int const_channel_count; /* channel count for all */
/* PCM information */
struct hda_pcm pcm_rec[3]; /* used in build_pcms() */
/* dynamic controls, init_verbs and input_mux */
struct auto_pin_cfg autocfg;
struct snd_array kctls;
hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
hda_nid_t imux_pins[HDA_MAX_NUM_INPUTS];
unsigned int dyn_adc_idx[HDA_MAX_NUM_INPUTS];
hda_nid_t shared_mic_vref_pin;
/* DAC/ADC lists */
int num_all_dacs;
hda_nid_t all_dacs[16];
int num_all_adcs;
hda_nid_t all_adcs[AUTO_CFG_MAX_INS];
/* path list */
struct snd_array paths;
/* path indices */
int out_paths[AUTO_CFG_MAX_OUTS];
int hp_paths[AUTO_CFG_MAX_OUTS];
int speaker_paths[AUTO_CFG_MAX_OUTS];
int aamix_out_paths[3];
int digout_paths[AUTO_CFG_MAX_OUTS];
int input_paths[HDA_MAX_NUM_INPUTS][AUTO_CFG_MAX_INS];
int loopback_paths[HDA_MAX_NUM_INPUTS];
int loopback_merge_path;
int digin_path;
/* auto-mic stuff */
int am_num_entries;
struct automic_entry am_entry[MAX_AUTO_MIC_PINS];
/* for pin sensing */
/* current status; set in hda_geneic.c */
unsigned int hp_jack_present:1;
unsigned int line_jack_present:1;
unsigned int speaker_muted:1; /* current status of speaker mute */
unsigned int line_out_muted:1; /* current status of LO mute */
/* internal states of automute / autoswitch behavior */
unsigned int auto_mic:1;
unsigned int automute_speaker:1; /* automute speaker outputs */
unsigned int automute_lo:1; /* automute LO outputs */
/* capabilities detected by parser */
unsigned int detect_hp:1; /* Headphone detection enabled */
unsigned int detect_lo:1; /* Line-out detection enabled */
unsigned int automute_speaker_possible:1; /* there are speakers and either LO or HP */
unsigned int automute_lo_possible:1; /* there are line outs and HP */
/* additional parameters set by codec drivers */
unsigned int master_mute:1; /* master mute over all */
unsigned int keep_vref_in_automute:1; /* Don't clear VREF in automute */
unsigned int line_in_auto_switch:1; /* allow line-in auto switch */
/* parser behavior flags; set before snd_hda_gen_parse_auto_config() */
unsigned int suppress_auto_mute:1; /* suppress input jack auto mute */
unsigned int suppress_auto_mic:1; /* suppress input jack auto switch */
/* other parse behavior flags */
unsigned int need_dac_fix:1; /* need to limit DACs for multi channels */
unsigned int shared_mic_hp:1; /* HP/Mic-in sharing */
unsigned int no_primary_hp:1; /* Don't prefer HP pins to speaker pins */
unsigned int multi_cap_vol:1; /* allow multiple capture xxx volumes */
unsigned int inv_dmic_split:1; /* inverted dmic w/a for conexant */
unsigned int own_eapd_ctl:1; /* set EAPD by own function */
unsigned int vmaster_mute_enum:1; /* add vmaster mute mode enum */
unsigned int indep_hp:1; /* independent HP supported */
unsigned int prefer_hp_amp:1; /* enable HP amp for speaker if any */
unsigned int add_stereo_mix_input:1; /* add aamix as a capture src */
unsigned int add_out_jack_modes:1; /* add output jack mode enum ctls */
unsigned int add_in_jack_modes:1; /* add input jack mode enum ctls */
unsigned int power_down_unused:1; /* power down unused widgets */
/* other internal flags */
unsigned int no_analog:1; /* digital I/O only */
unsigned int dyn_adc_switch:1; /* switch ADCs (for ALC275) */
unsigned int indep_hp_enabled:1; /* independent HP enabled */
unsigned int have_aamix_ctl:1;
/* loopback mixing mode */
bool aamix_mode;
/* for virtual master */
hda_nid_t vmaster_nid;
unsigned int vmaster_tlv[4];
struct hda_vmaster_mute_hook vmaster_mute;
struct hda_loopback_check loopback;
struct snd_array loopback_list;
/* multi-io */
int multi_ios;
struct hda_multi_io multi_io[4];
/* hooks */
void (*init_hook)(struct hda_codec *codec);
void (*automute_hook)(struct hda_codec *codec);
void (*cap_sync_hook)(struct hda_codec *codec,
struct snd_ctl_elem_value *ucontrol);
/* PCM hooks */
void (*pcm_playback_hook)(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
struct snd_pcm_substream *substream,
int action);
void (*pcm_capture_hook)(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
struct snd_pcm_substream *substream,
int action);
/* automute / autoswitch hooks */
void (*hp_automute_hook)(struct hda_codec *codec,
struct hda_jack_tbl *tbl);
void (*line_automute_hook)(struct hda_codec *codec,
struct hda_jack_tbl *tbl);
void (*mic_autoswitch_hook)(struct hda_codec *codec,
struct hda_jack_tbl *tbl);
};
int snd_hda_gen_spec_init(struct hda_gen_spec *spec);
void snd_hda_gen_spec_free(struct hda_gen_spec *spec);
int snd_hda_gen_init(struct hda_codec *codec);
void snd_hda_gen_free(struct hda_codec *codec);
struct nid_path *snd_hda_get_nid_path(struct hda_codec *codec,
hda_nid_t from_nid, hda_nid_t to_nid);
int snd_hda_get_path_idx(struct hda_codec *codec, struct nid_path *path);
struct nid_path *snd_hda_get_path_from_idx(struct hda_codec *codec, int idx);
bool snd_hda_parse_nid_path(struct hda_codec *codec, hda_nid_t from_nid,
hda_nid_t to_nid, int anchor_nid,
struct nid_path *path);
struct nid_path *
snd_hda_add_new_path(struct hda_codec *codec, hda_nid_t from_nid,
hda_nid_t to_nid, int anchor_nid);
void snd_hda_activate_path(struct hda_codec *codec, struct nid_path *path,
bool enable, bool add_aamix);
struct snd_kcontrol_new *
snd_hda_gen_add_kctl(struct hda_gen_spec *spec, const char *name,
const struct snd_kcontrol_new *temp);
int snd_hda_gen_parse_auto_config(struct hda_codec *codec,
struct auto_pin_cfg *cfg);
int snd_hda_gen_build_controls(struct hda_codec *codec);
int snd_hda_gen_build_pcms(struct hda_codec *codec);
/* standard jack event callbacks */
void snd_hda_gen_hp_automute(struct hda_codec *codec,
struct hda_jack_tbl *jack);
void snd_hda_gen_line_automute(struct hda_codec *codec,
struct hda_jack_tbl *jack);
void snd_hda_gen_mic_autoswitch(struct hda_codec *codec,
struct hda_jack_tbl *jack);
void snd_hda_gen_update_outputs(struct hda_codec *codec);
#ifdef CONFIG_PM
int snd_hda_gen_check_power_status(struct hda_codec *codec, hda_nid_t nid);
#endif
#endif /* __SOUND_HDA_GENERIC_H */

View File

@@ -148,6 +148,7 @@ int snd_hda_create_hwdep(struct hda_codec *codec)
hwdep->ops.ioctl_compat = hda_hwdep_ioctl_compat;
#endif
mutex_init(&codec->user_mutex);
snd_array_init(&codec->init_verbs, sizeof(struct hda_verb), 32);
snd_array_init(&codec->hints, sizeof(struct hda_hint), 32);
snd_array_init(&codec->user_pins, sizeof(struct hda_pincfg), 16);
@@ -346,12 +347,14 @@ static ssize_t init_verbs_show(struct device *dev,
struct snd_hwdep *hwdep = dev_get_drvdata(dev);
struct hda_codec *codec = hwdep->private_data;
int i, len = 0;
mutex_lock(&codec->user_mutex);
for (i = 0; i < codec->init_verbs.used; i++) {
struct hda_verb *v = snd_array_elem(&codec->init_verbs, i);
len += snprintf(buf + len, PAGE_SIZE - len,
"0x%02x 0x%03x 0x%04x\n",
v->nid, v->verb, v->param);
}
mutex_unlock(&codec->user_mutex);
return len;
}
@@ -364,12 +367,16 @@ static int parse_init_verbs(struct hda_codec *codec, const char *buf)
return -EINVAL;
if (!nid || !verb)
return -EINVAL;
mutex_lock(&codec->user_mutex);
v = snd_array_new(&codec->init_verbs);
if (!v)
if (!v) {
mutex_unlock(&codec->user_mutex);
return -ENOMEM;
}
v->nid = nid;
v->verb = verb;
v->param = param;
mutex_unlock(&codec->user_mutex);
return 0;
}
@@ -392,11 +399,13 @@ static ssize_t hints_show(struct device *dev,
struct snd_hwdep *hwdep = dev_get_drvdata(dev);
struct hda_codec *codec = hwdep->private_data;
int i, len = 0;
mutex_lock(&codec->user_mutex);
for (i = 0; i < codec->hints.used; i++) {
struct hda_hint *hint = snd_array_elem(&codec->hints, i);
len += snprintf(buf + len, PAGE_SIZE - len,
"%s = %s\n", hint->key, hint->val);
}
mutex_unlock(&codec->user_mutex);
return len;
}
@@ -431,6 +440,7 @@ static int parse_hints(struct hda_codec *codec, const char *buf)
{
char *key, *val;
struct hda_hint *hint;
int err = 0;
buf = skip_spaces(buf);
if (!*buf || *buf == '#' || *buf == '\n')
@@ -450,26 +460,31 @@ static int parse_hints(struct hda_codec *codec, const char *buf)
val = skip_spaces(val);
remove_trail_spaces(key);
remove_trail_spaces(val);
mutex_lock(&codec->user_mutex);
hint = get_hint(codec, key);
if (hint) {
/* replace */
kfree(hint->key);
hint->key = key;
hint->val = val;
return 0;
goto unlock;
}
/* allocate a new hint entry */
if (codec->hints.used >= MAX_HINTS)
hint = NULL;
else
hint = snd_array_new(&codec->hints);
if (!hint) {
kfree(key);
return -ENOMEM;
if (hint) {
hint->key = key;
hint->val = val;
} else {
err = -ENOMEM;
}
hint->key = key;
hint->val = val;
return 0;
unlock:
mutex_unlock(&codec->user_mutex);
if (err)
kfree(key);
return err;
}
static ssize_t hints_store(struct device *dev,
@@ -489,11 +504,13 @@ static ssize_t pin_configs_show(struct hda_codec *codec,
char *buf)
{
int i, len = 0;
mutex_lock(&codec->user_mutex);
for (i = 0; i < list->used; i++) {
struct hda_pincfg *pin = snd_array_elem(list, i);
len += sprintf(buf + len, "0x%02x 0x%08x\n",
pin->nid, pin->cfg);
}
mutex_unlock(&codec->user_mutex);
return len;
}
@@ -528,13 +545,16 @@ static ssize_t driver_pin_configs_show(struct device *dev,
static int parse_user_pin_configs(struct hda_codec *codec, const char *buf)
{
int nid, cfg;
int nid, cfg, err;
if (sscanf(buf, "%i %i", &nid, &cfg) != 2)
return -EINVAL;
if (!nid)
return -EINVAL;
return snd_hda_add_pincfg(codec, &codec->user_pins, nid, cfg);
mutex_lock(&codec->user_mutex);
err = snd_hda_add_pincfg(codec, &codec->user_pins, nid, cfg);
mutex_unlock(&codec->user_mutex);
return err;
}
static ssize_t user_pin_configs_store(struct device *dev,
@@ -600,19 +620,50 @@ EXPORT_SYMBOL_HDA(snd_hda_get_hint);
int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key)
{
const char *p = snd_hda_get_hint(codec, key);
const char *p;
int ret;
mutex_lock(&codec->user_mutex);
p = snd_hda_get_hint(codec, key);
if (!p || !*p)
return -ENOENT;
switch (toupper(*p)) {
case 'T': /* true */
case 'Y': /* yes */
case '1':
return 1;
ret = -ENOENT;
else {
switch (toupper(*p)) {
case 'T': /* true */
case 'Y': /* yes */
case '1':
ret = 1;
break;
default:
ret = 0;
break;
}
}
return 0;
mutex_unlock(&codec->user_mutex);
return ret;
}
EXPORT_SYMBOL_HDA(snd_hda_get_bool_hint);
int snd_hda_get_int_hint(struct hda_codec *codec, const char *key, int *valp)
{
const char *p;
unsigned long val;
int ret;
mutex_lock(&codec->user_mutex);
p = snd_hda_get_hint(codec, key);
if (!p)
ret = -ENOENT;
else if (strict_strtoul(p, 0, &val))
ret = -EINVAL;
else {
*valp = val;
ret = 0;
}
mutex_unlock(&codec->user_mutex);
return ret;
}
EXPORT_SYMBOL_HDA(snd_hda_get_int_hint);
#endif /* CONFIG_SND_HDA_RECONFIG */
#ifdef CONFIG_SND_HDA_PATCH_LOADER

View File

@@ -134,8 +134,8 @@ MODULE_PARM_DESC(power_save, "Automatic power-saving timeout "
* this may give more power-saving, but will take longer time to
* wake up.
*/
static bool power_save_controller = 1;
module_param(power_save_controller, bool, 0644);
static int power_save_controller = -1;
module_param(power_save_controller, bint, 0644);
MODULE_PARM_DESC(power_save_controller, "Reset controller in power save mode.");
#endif /* CONFIG_PM */
@@ -811,7 +811,7 @@ static int azx_corb_send_cmd(struct hda_bus *bus, u32 val)
{
struct azx *chip = bus->private_data;
unsigned int addr = azx_command_addr(val);
unsigned int wp;
unsigned int wp, rp;
spin_lock_irq(&chip->reg_lock);
@@ -820,11 +820,18 @@ static int azx_corb_send_cmd(struct hda_bus *bus, u32 val)
if (wp == 0xffff) {
/* something wrong, controller likely turned to D3 */
spin_unlock_irq(&chip->reg_lock);
return -1;
return -EIO;
}
wp++;
wp %= ICH6_MAX_CORB_ENTRIES;
rp = azx_readw(chip, CORBRP);
if (wp == rp) {
/* oops, it's full */
spin_unlock_irq(&chip->reg_lock);
return -EAGAIN;
}
chip->rirb.cmds[addr]++;
chip->corb.buf[wp] = cpu_to_le32(val);
azx_writel(chip, CORBWP, wp);
@@ -1078,6 +1085,15 @@ static unsigned int azx_get_response(struct hda_bus *bus,
static void azx_power_notify(struct hda_bus *bus, bool power_up);
#endif
#ifdef CONFIG_SND_HDA_DSP_LOADER
static int azx_load_dsp_prepare(struct hda_bus *bus, unsigned int format,
unsigned int byte_size,
struct snd_dma_buffer *bufp);
static void azx_load_dsp_trigger(struct hda_bus *bus, bool start);
static void azx_load_dsp_cleanup(struct hda_bus *bus,
struct snd_dma_buffer *dmab);
#endif
/* reset codec link */
static int azx_reset(struct azx *chip, int full_reset)
{
@@ -1401,7 +1417,7 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
* set up a BDL entry
*/
static int setup_bdle(struct azx *chip,
struct snd_pcm_substream *substream,
struct snd_dma_buffer *dmab,
struct azx_dev *azx_dev, u32 **bdlp,
int ofs, int size, int with_ioc)
{
@@ -1414,12 +1430,12 @@ static int setup_bdle(struct azx *chip,
if (azx_dev->frags >= AZX_MAX_BDL_ENTRIES)
return -EINVAL;
addr = snd_pcm_sgbuf_get_addr(substream, ofs);
addr = snd_sgbuf_get_addr(dmab, ofs);
/* program the address field of the BDL entry */
bdl[0] = cpu_to_le32((u32)addr);
bdl[1] = cpu_to_le32(upper_32_bits(addr));
/* program the size field of the BDL entry */
chunk = snd_pcm_sgbuf_get_chunk_size(substream, ofs, size);
chunk = snd_sgbuf_get_chunk_size(dmab, ofs, size);
/* one BDLE cannot cross 4K boundary on CTHDA chips */
if (chip->driver_caps & AZX_DCAPS_4K_BDLE_BOUNDARY) {
u32 remain = 0x1000 - (ofs & 0xfff);
@@ -1478,7 +1494,8 @@ static int azx_setup_periods(struct azx *chip,
pci_name(chip->pci), bdl_pos_adj[chip->dev_index]);
pos_adj = 0;
} else {
ofs = setup_bdle(chip, substream, azx_dev,
ofs = setup_bdle(chip, snd_pcm_get_dma_buf(substream),
azx_dev,
&bdl, ofs, pos_adj, true);
if (ofs < 0)
goto error;
@@ -1487,10 +1504,12 @@ static int azx_setup_periods(struct azx *chip,
pos_adj = 0;
for (i = 0; i < periods; i++) {
if (i == periods - 1 && pos_adj)
ofs = setup_bdle(chip, substream, azx_dev, &bdl, ofs,
ofs = setup_bdle(chip, snd_pcm_get_dma_buf(substream),
azx_dev, &bdl, ofs,
period_bytes - pos_adj, 0);
else
ofs = setup_bdle(chip, substream, azx_dev, &bdl, ofs,
ofs = setup_bdle(chip, snd_pcm_get_dma_buf(substream),
azx_dev, &bdl, ofs,
period_bytes,
!azx_dev->no_period_wakeup);
if (ofs < 0)
@@ -1668,6 +1687,11 @@ static int azx_codec_create(struct azx *chip, const char *model)
bus_temp.power_save = &power_save;
bus_temp.ops.pm_notify = azx_power_notify;
#endif
#ifdef CONFIG_SND_HDA_DSP_LOADER
bus_temp.ops.load_dsp_prepare = azx_load_dsp_prepare;
bus_temp.ops.load_dsp_trigger = azx_load_dsp_trigger;
bus_temp.ops.load_dsp_cleanup = azx_load_dsp_cleanup;
#endif
err = snd_hda_bus_new(chip->card, &bus_temp, &chip->bus);
if (err < 0)
@@ -2576,6 +2600,102 @@ static void azx_stop_chip(struct azx *chip)
chip->initialized = 0;
}
#ifdef CONFIG_SND_HDA_DSP_LOADER
/*
* DSP loading code (e.g. for CA0132)
*/
/* use the first stream for loading DSP */
static struct azx_dev *
azx_get_dsp_loader_dev(struct azx *chip)
{
return &chip->azx_dev[chip->playback_index_offset];
}
static int azx_load_dsp_prepare(struct hda_bus *bus, unsigned int format,
unsigned int byte_size,
struct snd_dma_buffer *bufp)
{
u32 *bdl;
struct azx *chip = bus->private_data;
struct azx_dev *azx_dev;
int err;
if (snd_hda_lock_devices(bus))
return -EBUSY;
err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG,
snd_dma_pci_data(chip->pci),
byte_size, bufp);
if (err < 0)
goto unlock;
mark_pages_wc(chip, bufp, true);
azx_dev = azx_get_dsp_loader_dev(chip);
azx_dev->bufsize = byte_size;
azx_dev->period_bytes = byte_size;
azx_dev->format_val = format;
azx_stream_reset(chip, azx_dev);
/* reset BDL address */
azx_sd_writel(azx_dev, SD_BDLPL, 0);
azx_sd_writel(azx_dev, SD_BDLPU, 0);
azx_dev->frags = 0;
bdl = (u32 *)azx_dev->bdl.area;
err = setup_bdle(chip, bufp, azx_dev, &bdl, 0, byte_size, 0);
if (err < 0)
goto error;
azx_setup_controller(chip, azx_dev);
return azx_dev->stream_tag;
error:
mark_pages_wc(chip, bufp, false);
snd_dma_free_pages(bufp);
unlock:
snd_hda_unlock_devices(bus);
return err;
}
static void azx_load_dsp_trigger(struct hda_bus *bus, bool start)
{
struct azx *chip = bus->private_data;
struct azx_dev *azx_dev = azx_get_dsp_loader_dev(chip);
if (start)
azx_stream_start(chip, azx_dev);
else
azx_stream_stop(chip, azx_dev);
azx_dev->running = start;
}
static void azx_load_dsp_cleanup(struct hda_bus *bus,
struct snd_dma_buffer *dmab)
{
struct azx *chip = bus->private_data;
struct azx_dev *azx_dev = azx_get_dsp_loader_dev(chip);
if (!dmab->area)
return;
/* reset BDL address */
azx_sd_writel(azx_dev, SD_BDLPL, 0);
azx_sd_writel(azx_dev, SD_BDLPU, 0);
azx_sd_writel(azx_dev, SD_CTL, 0);
azx_dev->bufsize = 0;
azx_dev->period_bytes = 0;
azx_dev->format_val = 0;
mark_pages_wc(chip, dmab, false);
snd_dma_free_pages(dmab);
dmab->area = NULL;
snd_hda_unlock_devices(bus);
}
#endif /* CONFIG_SND_HDA_DSP_LOADER */
#ifdef CONFIG_PM
/* power-up/down the controller */
static void azx_power_notify(struct hda_bus *bus, bool power_up)
@@ -2726,6 +2846,8 @@ static int azx_runtime_idle(struct device *dev)
struct snd_card *card = dev_get_drvdata(dev);
struct azx *chip = card->private_data;
if (power_save_controller > 0)
return 0;
if (!power_save_controller ||
!(chip->driver_caps & AZX_DCAPS_PM_RUNTIME))
return -EBUSY;
@@ -3150,6 +3272,9 @@ static void azx_check_snoop_available(struct azx *chip)
/* new ATI HDMI requires non-snoop */
snoop = false;
break;
case AZX_DRIVER_CTHDA:
snoop = false;
break;
}
if (snoop != chip->snoop) {
@@ -3611,6 +3736,11 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
/* Lynx Point */
{ PCI_DEVICE(0x8086, 0x8c20),
.driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
/* Wellsburg */
{ PCI_DEVICE(0x8086, 0x8d20),
.driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
{ PCI_DEVICE(0x8086, 0x8d21),
.driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
/* Lynx Point-LP */
{ PCI_DEVICE(0x8086, 0x9c20),
.driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
@@ -3618,13 +3748,15 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
{ PCI_DEVICE(0x8086, 0x9c21),
.driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
/* Haswell */
{ PCI_DEVICE(0x8086, 0x0a0c),
.driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH },
{ PCI_DEVICE(0x8086, 0x0c0c),
.driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH },
{ PCI_DEVICE(0x8086, 0x0d0c),
.driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH },
/* 5 Series/3400 */
{ PCI_DEVICE(0x8086, 0x3b56),
.driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH },
.driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM },
/* Poulsbo */
{ PCI_DEVICE(0x8086, 0x811b),
.driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM },

View File

@@ -29,7 +29,8 @@ bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid)
if (get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) &
AC_DEFCFG_MISC_NO_PRESENCE)
return false;
if (!(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP))
if (!(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) &&
!codec->jackpoll_interval)
return false;
return true;
}
@@ -39,6 +40,7 @@ EXPORT_SYMBOL_HDA(is_jack_detectable);
static u32 read_pin_sense(struct hda_codec *codec, hda_nid_t nid)
{
u32 pincap;
u32 val;
if (!codec->no_trigger_sense) {
pincap = snd_hda_query_pin_caps(codec, nid);
@@ -46,8 +48,11 @@ static u32 read_pin_sense(struct hda_codec *codec, hda_nid_t nid)
snd_hda_codec_read(codec, nid, 0,
AC_VERB_SET_PIN_SENSE, 0);
}
return snd_hda_codec_read(codec, nid, 0,
val = snd_hda_codec_read(codec, nid, 0,
AC_VERB_GET_PIN_SENSE, 0);
if (codec->inv_jack_detect)
val ^= AC_PINSENSE_PRESENCE;
return val;
}
/**

View File

@@ -133,9 +133,11 @@ int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch,
int direction, int idx, int mask, int val);
int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid,
int dir, int idx, int mask, int val);
#ifdef CONFIG_PM
int snd_hda_codec_amp_init(struct hda_codec *codec, hda_nid_t nid, int ch,
int direction, int idx, int mask, int val);
int snd_hda_codec_amp_init_stereo(struct hda_codec *codec, hda_nid_t nid,
int dir, int idx, int mask, int val);
void snd_hda_codec_resume_amp(struct hda_codec *codec);
#endif
void snd_hda_set_vmaster_tlv(struct hda_codec *codec, hda_nid_t nid, int dir,
unsigned int *tlv);
@@ -383,6 +385,61 @@ int snd_hda_check_board_codec_sid_config(struct hda_codec *codec,
int snd_hda_add_new_ctls(struct hda_codec *codec,
const struct snd_kcontrol_new *knew);
/*
* Fix-up pin default configurations and add default verbs
*/
struct hda_pintbl {
hda_nid_t nid;
u32 val;
};
struct hda_model_fixup {
const int id;
const char *name;
};
struct hda_fixup {
int type;
bool chained:1; /* call the chained fixup(s) after this */
bool chained_before:1; /* call the chained fixup(s) before this */
int chain_id;
union {
const struct hda_pintbl *pins;
const struct hda_verb *verbs;
void (*func)(struct hda_codec *codec,
const struct hda_fixup *fix,
int action);
} v;
};
/* fixup types */
enum {
HDA_FIXUP_INVALID,
HDA_FIXUP_PINS,
HDA_FIXUP_VERBS,
HDA_FIXUP_FUNC,
HDA_FIXUP_PINCTLS,
};
/* fixup action definitions */
enum {
HDA_FIXUP_ACT_PRE_PROBE,
HDA_FIXUP_ACT_PROBE,
HDA_FIXUP_ACT_INIT,
HDA_FIXUP_ACT_BUILD,
};
int snd_hda_add_verbs(struct hda_codec *codec, const struct hda_verb *list);
void snd_hda_apply_verbs(struct hda_codec *codec);
void snd_hda_apply_pincfgs(struct hda_codec *codec,
const struct hda_pintbl *cfg);
void snd_hda_apply_fixup(struct hda_codec *codec, int action);
void snd_hda_pick_fixup(struct hda_codec *codec,
const struct hda_model_fixup *models,
const struct snd_pci_quirk *quirk,
const struct hda_fixup *fixlist);
/*
* unsolicited event handler
*/
@@ -431,6 +488,8 @@ struct hda_bus_unsolicited {
#define PIN_HP_AMP (AC_PINCTL_HP_EN)
unsigned int snd_hda_get_default_vref(struct hda_codec *codec, hda_nid_t pin);
unsigned int snd_hda_correct_pin_ctl(struct hda_codec *codec,
hda_nid_t pin, unsigned int val);
int _snd_hda_set_pin_ctl(struct hda_codec *codec, hda_nid_t pin,
unsigned int val, bool cached);
@@ -470,6 +529,10 @@ snd_hda_set_pin_ctl_cache(struct hda_codec *codec, hda_nid_t pin,
return _snd_hda_set_pin_ctl(codec, pin, val, true);
}
int snd_hda_codec_get_pin_target(struct hda_codec *codec, hda_nid_t nid);
int snd_hda_codec_set_pin_target(struct hda_codec *codec, hda_nid_t nid,
unsigned int val);
/*
* get widget capabilities
*/
@@ -552,6 +615,7 @@ static inline int snd_hda_hwdep_add_sysfs(struct hda_codec *codec)
#ifdef CONFIG_SND_HDA_RECONFIG
const char *snd_hda_get_hint(struct hda_codec *codec, const char *key);
int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key);
int snd_hda_get_int_hint(struct hda_codec *codec, const char *key, int *valp);
#else
static inline
const char *snd_hda_get_hint(struct hda_codec *codec, const char *key)
@@ -564,6 +628,12 @@ int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key)
{
return -ENOENT;
}
static inline
int snd_hda_get_int_hint(struct hda_codec *codec, const char *key, int *valp)
{
return -ENOENT;
}
#endif
/*
@@ -587,6 +657,19 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec,
struct hda_loopback_check *check,
hda_nid_t nid);
/* check whether the actual power state matches with the target state */
static inline bool
snd_hda_check_power_state(struct hda_codec *codec, hda_nid_t nid,
unsigned int target_state)
{
unsigned int state = snd_hda_codec_read(codec, nid, 0,
AC_VERB_GET_POWER_STATE, 0);
if (state & AC_PWRST_ERROR)
return true;
state = (state >> 4) & 0x0f;
return (state != target_state);
}
/*
* AMP control callbacks
*/
@@ -596,7 +679,8 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec,
#define get_amp_channels(kc) (((kc)->private_value >> 16) & 0x3)
#define get_amp_direction_(pv) (((pv) >> 18) & 0x1)
#define get_amp_direction(kc) get_amp_direction_((kc)->private_value)
#define get_amp_index(kc) (((kc)->private_value >> 19) & 0xf)
#define get_amp_index_(pv) (((pv) >> 19) & 0xf)
#define get_amp_index(kc) get_amp_index_((kc)->private_value)
#define get_amp_offset(kc) (((kc)->private_value >> 23) & 0x3f)
#define get_amp_min_mute(kc) (((kc)->private_value >> 29) & 0x1)
@@ -629,10 +713,10 @@ struct cea_sad {
/*
* ELD: EDID Like Data
*/
struct hdmi_eld {
bool monitor_present;
bool eld_valid;
int eld_size;
struct parsed_hdmi_eld {
/*
* all fields will be cleared before updating ELD
*/
int baseline_len;
int eld_ver;
int cea_edid_ver;
@@ -647,19 +731,27 @@ struct hdmi_eld {
int spk_alloc;
int sad_count;
struct cea_sad sad[ELD_MAX_SAD];
/*
* all fields above eld_buffer will be cleared before updating ELD
*/
};
struct hdmi_eld {
bool monitor_present;
bool eld_valid;
int eld_size;
char eld_buffer[ELD_MAX_SIZE];
struct parsed_hdmi_eld info;
struct mutex lock;
#ifdef CONFIG_PROC_FS
struct snd_info_entry *proc_entry;
#endif
};
int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid);
int snd_hdmi_get_eld(struct hdmi_eld *, struct hda_codec *, hda_nid_t);
void snd_hdmi_show_eld(struct hdmi_eld *eld);
void snd_hdmi_eld_update_pcm_info(struct hdmi_eld *eld,
int snd_hdmi_get_eld(struct hda_codec *codec, hda_nid_t nid,
unsigned char *buf, int *eld_size);
int snd_hdmi_parse_eld(struct parsed_hdmi_eld *e,
const unsigned char *buf, int size);
void snd_hdmi_show_eld(struct parsed_hdmi_eld *e);
void snd_hdmi_eld_update_pcm_info(struct parsed_hdmi_eld *e,
struct hda_pcm_stream *hinfo);
#ifdef CONFIG_PROC_FS

View File

@@ -22,6 +22,7 @@
*/
#include <linux/init.h>
#include <linux/slab.h>
#include <sound/core.h>
#include "hda_codec.h"
#include "hda_local.h"
@@ -138,16 +139,17 @@ static void print_amp_vals(struct snd_info_buffer *buffer,
dir = dir == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT;
for (i = 0; i < indices; i++) {
snd_iprintf(buffer, " [");
val = snd_hda_codec_read(codec, nid, 0,
AC_VERB_GET_AMP_GAIN_MUTE,
AC_AMP_GET_LEFT | dir | i);
snd_iprintf(buffer, "0x%02x", val);
if (stereo) {
val = snd_hda_codec_read(codec, nid, 0,
AC_VERB_GET_AMP_GAIN_MUTE,
AC_AMP_GET_LEFT | dir | i);
snd_iprintf(buffer, "0x%02x ", val);
AC_AMP_GET_RIGHT | dir | i);
snd_iprintf(buffer, " 0x%02x", val);
}
val = snd_hda_codec_read(codec, nid, 0,
AC_VERB_GET_AMP_GAIN_MUTE,
AC_AMP_GET_RIGHT | dir | i);
snd_iprintf(buffer, "0x%02x]", val);
snd_iprintf(buffer, "]");
}
snd_iprintf(buffer, "\n");
}
@@ -603,6 +605,8 @@ static void print_codec_info(struct snd_info_entry *entry,
print_amp_caps(buffer, codec, codec->afg, HDA_INPUT);
snd_iprintf(buffer, "Default Amp-Out caps: ");
print_amp_caps(buffer, codec, codec->afg, HDA_OUTPUT);
snd_iprintf(buffer, "State of AFG node 0x%02x:\n", codec->afg);
print_power_state(buffer, codec, codec->afg);
nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid);
if (! nid || nodes < 0) {
@@ -620,7 +624,7 @@ static void print_codec_info(struct snd_info_entry *entry,
snd_hda_param_read(codec, nid,
AC_PAR_AUDIO_WIDGET_CAP);
unsigned int wid_type = get_wcaps_type(wid_caps);
hda_nid_t conn[HDA_MAX_CONNECTIONS];
hda_nid_t *conn = NULL;
int conn_len = 0;
snd_iprintf(buffer, "Node 0x%02x [%s] wcaps 0x%x:", nid,
@@ -657,9 +661,18 @@ static void print_codec_info(struct snd_info_entry *entry,
if (wid_type == AC_WID_VOL_KNB)
wid_caps |= AC_WCAP_CONN_LIST;
if (wid_caps & AC_WCAP_CONN_LIST)
conn_len = snd_hda_get_raw_connections(codec, nid, conn,
HDA_MAX_CONNECTIONS);
if (wid_caps & AC_WCAP_CONN_LIST) {
conn_len = snd_hda_get_num_raw_conns(codec, nid);
if (conn_len > 0) {
conn = kmalloc(sizeof(hda_nid_t) * conn_len,
GFP_KERNEL);
if (!conn)
return;
if (snd_hda_get_raw_connections(codec, nid, conn,
conn_len) < 0)
conn_len = 0;
}
}
if (wid_caps & AC_WCAP_IN_AMP) {
snd_iprintf(buffer, " Amp-In caps: ");
@@ -732,6 +745,8 @@ static void print_codec_info(struct snd_info_entry *entry,
if (codec->proc_widget_hook)
codec->proc_widget_hook(buffer, codec, nid);
kfree(conn);
}
snd_hda_power_down(codec);
}

File diff suppressed because it is too large Load Diff

View File

@@ -19,7 +19,6 @@
*/
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/pci.h>
#include <linux/module.h>
@@ -27,502 +26,46 @@
#include "hda_codec.h"
#include "hda_local.h"
#include "hda_auto_parser.h"
#include "hda_jack.h"
#include "hda_generic.h"
/*
*/
struct ca0110_spec {
struct auto_pin_cfg autocfg;
struct hda_multi_out multiout;
hda_nid_t out_pins[AUTO_CFG_MAX_OUTS];
hda_nid_t dacs[AUTO_CFG_MAX_OUTS];
hda_nid_t hp_dac;
hda_nid_t input_pins[AUTO_PIN_LAST];
hda_nid_t adcs[AUTO_PIN_LAST];
hda_nid_t dig_out;
hda_nid_t dig_in;
unsigned int num_inputs;
char input_labels[AUTO_PIN_LAST][32];
struct hda_pcm pcm_rec[2]; /* PCM information */
};
/*
* PCM callbacks
*/
static int ca0110_playback_pcm_open(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
struct snd_pcm_substream *substream)
{
struct ca0110_spec *spec = codec->spec;
return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
hinfo);
}
static int ca0110_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
unsigned int stream_tag,
unsigned int format,
struct snd_pcm_substream *substream)
{
struct ca0110_spec *spec = codec->spec;
return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
stream_tag, format, substream);
}
static int ca0110_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
struct snd_pcm_substream *substream)
{
struct ca0110_spec *spec = codec->spec;
return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
}
/*
* Digital out
*/
static int ca0110_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
struct snd_pcm_substream *substream)
{
struct ca0110_spec *spec = codec->spec;
return snd_hda_multi_out_dig_open(codec, &spec->multiout);
}
static int ca0110_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
struct snd_pcm_substream *substream)
{
struct ca0110_spec *spec = codec->spec;
return snd_hda_multi_out_dig_close(codec, &spec->multiout);
}
static int ca0110_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
unsigned int stream_tag,
unsigned int format,
struct snd_pcm_substream *substream)
{
struct ca0110_spec *spec = codec->spec;
return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag,
format, substream);
}
/*
* Analog capture
*/
static int ca0110_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
unsigned int stream_tag,
unsigned int format,
struct snd_pcm_substream *substream)
{
struct ca0110_spec *spec = codec->spec;
snd_hda_codec_setup_stream(codec, spec->adcs[substream->number],
stream_tag, 0, format);
return 0;
}
static int ca0110_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
struct snd_pcm_substream *substream)
{
struct ca0110_spec *spec = codec->spec;
snd_hda_codec_cleanup_stream(codec, spec->adcs[substream->number]);
return 0;
}
/*
*/
static const char * const dirstr[2] = { "Playback", "Capture" };
static int _add_switch(struct hda_codec *codec, hda_nid_t nid, const char *pfx,
int chan, int dir)
{
char namestr[44];
int type = dir ? HDA_INPUT : HDA_OUTPUT;
struct snd_kcontrol_new knew =
HDA_CODEC_MUTE_MONO(namestr, nid, chan, 0, type);
sprintf(namestr, "%s %s Switch", pfx, dirstr[dir]);
return snd_hda_ctl_add(codec, nid, snd_ctl_new1(&knew, codec));
}
static int _add_volume(struct hda_codec *codec, hda_nid_t nid, const char *pfx,
int chan, int dir)
{
char namestr[44];
int type = dir ? HDA_INPUT : HDA_OUTPUT;
struct snd_kcontrol_new knew =
HDA_CODEC_VOLUME_MONO(namestr, nid, chan, 0, type);
sprintf(namestr, "%s %s Volume", pfx, dirstr[dir]);
return snd_hda_ctl_add(codec, nid, snd_ctl_new1(&knew, codec));
}
#define add_out_switch(codec, nid, pfx) _add_switch(codec, nid, pfx, 3, 0)
#define add_out_volume(codec, nid, pfx) _add_volume(codec, nid, pfx, 3, 0)
#define add_in_switch(codec, nid, pfx) _add_switch(codec, nid, pfx, 3, 1)
#define add_in_volume(codec, nid, pfx) _add_volume(codec, nid, pfx, 3, 1)
#define add_mono_switch(codec, nid, pfx, chan) \
_add_switch(codec, nid, pfx, chan, 0)
#define add_mono_volume(codec, nid, pfx, chan) \
_add_volume(codec, nid, pfx, chan, 0)
static int ca0110_build_controls(struct hda_codec *codec)
{
struct ca0110_spec *spec = codec->spec;
struct auto_pin_cfg *cfg = &spec->autocfg;
static const char * const prefix[AUTO_CFG_MAX_OUTS] = {
"Front", "Surround", NULL, "Side", "Multi"
};
hda_nid_t mutenid;
int i, err;
for (i = 0; i < spec->multiout.num_dacs; i++) {
if (get_wcaps(codec, spec->out_pins[i]) & AC_WCAP_OUT_AMP)
mutenid = spec->out_pins[i];
else
mutenid = spec->multiout.dac_nids[i];
if (!prefix[i]) {
err = add_mono_switch(codec, mutenid,
"Center", 1);
if (err < 0)
return err;
err = add_mono_switch(codec, mutenid,
"LFE", 1);
if (err < 0)
return err;
err = add_mono_volume(codec, spec->multiout.dac_nids[i],
"Center", 1);
if (err < 0)
return err;
err = add_mono_volume(codec, spec->multiout.dac_nids[i],
"LFE", 1);
if (err < 0)
return err;
} else {
err = add_out_switch(codec, mutenid,
prefix[i]);
if (err < 0)
return err;
err = add_out_volume(codec, spec->multiout.dac_nids[i],
prefix[i]);
if (err < 0)
return err;
}
}
if (cfg->hp_outs) {
if (get_wcaps(codec, cfg->hp_pins[0]) & AC_WCAP_OUT_AMP)
mutenid = cfg->hp_pins[0];
else
mutenid = spec->multiout.dac_nids[i];
err = add_out_switch(codec, mutenid, "Headphone");
if (err < 0)
return err;
if (spec->hp_dac) {
err = add_out_volume(codec, spec->hp_dac, "Headphone");
if (err < 0)
return err;
}
}
for (i = 0; i < spec->num_inputs; i++) {
const char *label = spec->input_labels[i];
if (get_wcaps(codec, spec->input_pins[i]) & AC_WCAP_IN_AMP)
mutenid = spec->input_pins[i];
else
mutenid = spec->adcs[i];
err = add_in_switch(codec, mutenid, label);
if (err < 0)
return err;
err = add_in_volume(codec, spec->adcs[i], label);
if (err < 0)
return err;
}
if (spec->dig_out) {
err = snd_hda_create_spdif_out_ctls(codec, spec->dig_out,
spec->dig_out);
if (err < 0)
return err;
err = snd_hda_create_spdif_share_sw(codec, &spec->multiout);
if (err < 0)
return err;
spec->multiout.share_spdif = 1;
}
if (spec->dig_in) {
err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in);
if (err < 0)
return err;
err = add_in_volume(codec, spec->dig_in, "IEC958");
}
return 0;
}
/*
*/
static const struct hda_pcm_stream ca0110_pcm_analog_playback = {
.substreams = 1,
.channels_min = 2,
.channels_max = 8,
.ops = {
.open = ca0110_playback_pcm_open,
.prepare = ca0110_playback_pcm_prepare,
.cleanup = ca0110_playback_pcm_cleanup
},
};
static const struct hda_pcm_stream ca0110_pcm_analog_capture = {
.substreams = 1,
.channels_min = 2,
.channels_max = 2,
.ops = {
.prepare = ca0110_capture_pcm_prepare,
.cleanup = ca0110_capture_pcm_cleanup
},
};
static const struct hda_pcm_stream ca0110_pcm_digital_playback = {
.substreams = 1,
.channels_min = 2,
.channels_max = 2,
.ops = {
.open = ca0110_dig_playback_pcm_open,
.close = ca0110_dig_playback_pcm_close,
.prepare = ca0110_dig_playback_pcm_prepare
},
};
static const struct hda_pcm_stream ca0110_pcm_digital_capture = {
.substreams = 1,
.channels_min = 2,
.channels_max = 2,
};
static int ca0110_build_pcms(struct hda_codec *codec)
{
struct ca0110_spec *spec = codec->spec;
struct hda_pcm *info = spec->pcm_rec;
codec->pcm_info = info;
codec->num_pcms = 0;
info->name = "CA0110 Analog";
info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ca0110_pcm_analog_playback;
info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dacs[0];
info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =
spec->multiout.max_channels;
info->stream[SNDRV_PCM_STREAM_CAPTURE] = ca0110_pcm_analog_capture;
info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_inputs;
info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[0];
codec->num_pcms++;
if (!spec->dig_out && !spec->dig_in)
return 0;
info++;
info->name = "CA0110 Digital";
info->pcm_type = HDA_PCM_TYPE_SPDIF;
if (spec->dig_out) {
info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
ca0110_pcm_digital_playback;
info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dig_out;
}
if (spec->dig_in) {
info->stream[SNDRV_PCM_STREAM_CAPTURE] =
ca0110_pcm_digital_capture;
info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in;
}
codec->num_pcms++;
return 0;
}
static void init_output(struct hda_codec *codec, hda_nid_t pin, hda_nid_t dac)
{
if (pin) {
snd_hda_set_pin_ctl(codec, pin, PIN_HP);
if (get_wcaps(codec, pin) & AC_WCAP_OUT_AMP)
snd_hda_codec_write(codec, pin, 0,
AC_VERB_SET_AMP_GAIN_MUTE,
AMP_OUT_UNMUTE);
}
if (dac)
snd_hda_codec_write(codec, dac, 0,
AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO);
}
static void init_input(struct hda_codec *codec, hda_nid_t pin, hda_nid_t adc)
{
if (pin) {
snd_hda_set_pin_ctl(codec, pin, PIN_IN |
snd_hda_get_default_vref(codec, pin));
if (get_wcaps(codec, pin) & AC_WCAP_IN_AMP)
snd_hda_codec_write(codec, pin, 0,
AC_VERB_SET_AMP_GAIN_MUTE,
AMP_IN_UNMUTE(0));
}
if (adc)
snd_hda_codec_write(codec, adc, 0, AC_VERB_SET_AMP_GAIN_MUTE,
AMP_IN_UNMUTE(0));
}
static int ca0110_init(struct hda_codec *codec)
{
struct ca0110_spec *spec = codec->spec;
struct auto_pin_cfg *cfg = &spec->autocfg;
int i;
for (i = 0; i < spec->multiout.num_dacs; i++)
init_output(codec, spec->out_pins[i],
spec->multiout.dac_nids[i]);
init_output(codec, cfg->hp_pins[0], spec->hp_dac);
init_output(codec, cfg->dig_out_pins[0], spec->dig_out);
for (i = 0; i < spec->num_inputs; i++)
init_input(codec, spec->input_pins[i], spec->adcs[i]);
init_input(codec, cfg->dig_in_pin, spec->dig_in);
return 0;
}
static void ca0110_free(struct hda_codec *codec)
{
kfree(codec->spec);
}
static const struct hda_codec_ops ca0110_patch_ops = {
.build_controls = ca0110_build_controls,
.build_pcms = ca0110_build_pcms,
.init = ca0110_init,
.free = ca0110_free,
.build_controls = snd_hda_gen_build_controls,
.build_pcms = snd_hda_gen_build_pcms,
.init = snd_hda_gen_init,
.free = snd_hda_gen_free,
.unsol_event = snd_hda_jack_unsol_event,
};
static void parse_line_outs(struct hda_codec *codec)
{
struct ca0110_spec *spec = codec->spec;
struct auto_pin_cfg *cfg = &spec->autocfg;
int i, n;
unsigned int def_conf;
hda_nid_t nid;
n = 0;
for (i = 0; i < cfg->line_outs; i++) {
nid = cfg->line_out_pins[i];
def_conf = snd_hda_codec_get_pincfg(codec, nid);
if (!def_conf)
continue; /* invalid pin */
if (snd_hda_get_connections(codec, nid, &spec->dacs[i], 1) != 1)
continue;
spec->out_pins[n++] = nid;
}
spec->multiout.dac_nids = spec->dacs;
spec->multiout.num_dacs = n;
spec->multiout.max_channels = n * 2;
}
static void parse_hp_out(struct hda_codec *codec)
{
struct ca0110_spec *spec = codec->spec;
struct auto_pin_cfg *cfg = &spec->autocfg;
int i;
unsigned int def_conf;
hda_nid_t nid, dac;
if (!cfg->hp_outs)
return;
nid = cfg->hp_pins[0];
def_conf = snd_hda_codec_get_pincfg(codec, nid);
if (!def_conf) {
cfg->hp_outs = 0;
return;
}
if (snd_hda_get_connections(codec, nid, &dac, 1) != 1)
return;
for (i = 0; i < cfg->line_outs; i++)
if (dac == spec->dacs[i])
break;
if (i >= cfg->line_outs) {
spec->hp_dac = dac;
spec->multiout.hp_nid = dac;
}
}
static void parse_input(struct hda_codec *codec)
{
struct ca0110_spec *spec = codec->spec;
struct auto_pin_cfg *cfg = &spec->autocfg;
hda_nid_t nid, pin;
int n, i, j;
n = 0;
nid = codec->start_nid;
for (i = 0; i < codec->num_nodes; i++, nid++) {
unsigned int wcaps = get_wcaps(codec, nid);
unsigned int type = get_wcaps_type(wcaps);
if (type != AC_WID_AUD_IN)
continue;
if (snd_hda_get_connections(codec, nid, &pin, 1) != 1)
continue;
if (pin == cfg->dig_in_pin) {
spec->dig_in = nid;
continue;
}
for (j = 0; j < cfg->num_inputs; j++)
if (cfg->inputs[j].pin == pin)
break;
if (j >= cfg->num_inputs)
continue;
spec->input_pins[n] = pin;
snd_hda_get_pin_label(codec, pin, cfg,
spec->input_labels[n],
sizeof(spec->input_labels[n]), NULL);
spec->adcs[n] = nid;
n++;
}
spec->num_inputs = n;
}
static void parse_digital(struct hda_codec *codec)
{
struct ca0110_spec *spec = codec->spec;
struct auto_pin_cfg *cfg = &spec->autocfg;
if (cfg->dig_outs &&
snd_hda_get_connections(codec, cfg->dig_out_pins[0],
&spec->dig_out, 1) == 1)
spec->multiout.dig_out_nid = spec->dig_out;
}
static int ca0110_parse_auto_config(struct hda_codec *codec)
{
struct ca0110_spec *spec = codec->spec;
struct hda_gen_spec *spec = codec->spec;
int err;
err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
err = snd_hda_parse_pin_defcfg(codec, &spec->autocfg, NULL, 0);
if (err < 0)
return err;
err = snd_hda_gen_parse_auto_config(codec, &spec->autocfg);
if (err < 0)
return err;
parse_line_outs(codec);
parse_hp_out(codec);
parse_digital(codec);
parse_input(codec);
return 0;
}
static int patch_ca0110(struct hda_codec *codec)
{
struct ca0110_spec *spec;
struct hda_gen_spec *spec;
int err;
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
if (!spec)
return -ENOMEM;
snd_hda_gen_spec_init(spec);
codec->spec = spec;
spec->multi_cap_vol = 1;
codec->bus->needs_damn_long_delay = 1;
err = ca0110_parse_auto_config(codec);
@@ -534,8 +77,7 @@ static int patch_ca0110(struct hda_codec *codec)
return 0;
error:
kfree(codec->spec);
codec->spec = NULL;
snd_hda_gen_free(codec);
return err;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -22,7 +22,6 @@
*/
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/pci.h>
#include <linux/module.h>
@@ -30,6 +29,9 @@
#include "hda_codec.h"
#include "hda_local.h"
#include "hda_auto_parser.h"
#include "hda_jack.h"
#include "hda_generic.h"
#define NUM_PINS 11
@@ -45,6 +47,10 @@ enum {
};
struct cmi_spec {
struct hda_gen_spec gen;
/* below are only for static models */
int board_config;
unsigned int no_line_in: 1; /* no line-in (5-jack) */
unsigned int front_panel: 1; /* has front-panel 2-jack */
@@ -356,77 +362,6 @@ static int cmi9880_build_controls(struct hda_codec *codec)
return 0;
}
/* fill in the multi_dac_nids table, which will decide
which audio widget to use for each channel */
static int cmi9880_fill_multi_dac_nids(struct hda_codec *codec, const struct auto_pin_cfg *cfg)
{
struct cmi_spec *spec = codec->spec;
hda_nid_t nid;
int assigned[4];
int i, j;
/* clear the table, only one c-media dac assumed here */
memset(spec->dac_nids, 0, sizeof(spec->dac_nids));
memset(assigned, 0, sizeof(assigned));
/* check the pins we found */
for (i = 0; i < cfg->line_outs; i++) {
nid = cfg->line_out_pins[i];
/* nid 0x0b~0x0e is hardwired to audio widget 0x3~0x6 */
if (nid >= 0x0b && nid <= 0x0e) {
spec->dac_nids[i] = (nid - 0x0b) + 0x03;
assigned[nid - 0x0b] = 1;
}
}
/* left pin can be connect to any audio widget */
for (i = 0; i < cfg->line_outs; i++) {
nid = cfg->line_out_pins[i];
if (nid <= 0x0e)
continue;
/* search for an empty channel */
for (j = 0; j < cfg->line_outs; j++) {
if (! assigned[j]) {
spec->dac_nids[i] = j + 0x03;
assigned[j] = 1;
break;
}
}
}
spec->num_dacs = cfg->line_outs;
return 0;
}
/* create multi_init table, which is used for multichannel initialization */
static int cmi9880_fill_multi_init(struct hda_codec *codec, const struct auto_pin_cfg *cfg)
{
struct cmi_spec *spec = codec->spec;
hda_nid_t nid;
int i, j, k;
/* clear the table, only one c-media dac assumed here */
memset(spec->multi_init, 0, sizeof(spec->multi_init));
for (j = 0, i = 0; i < cfg->line_outs; i++) {
nid = cfg->line_out_pins[i];
/* set as output */
spec->multi_init[j].nid = nid;
spec->multi_init[j].verb = AC_VERB_SET_PIN_WIDGET_CONTROL;
spec->multi_init[j].param = PIN_OUT;
j++;
if (nid > 0x0e) {
/* set connection */
spec->multi_init[j].nid = nid;
spec->multi_init[j].verb = AC_VERB_SET_CONNECT_SEL;
spec->multi_init[j].param = 0;
/* find the index in connect list */
k = snd_hda_get_conn_index(codec, nid,
spec->dac_nids[i], 0);
if (k >= 0)
spec->multi_init[j].param = k;
j++;
}
}
return 0;
}
static int cmi9880_init(struct hda_codec *codec)
{
struct cmi_spec *spec = codec->spec;
@@ -632,6 +567,36 @@ static const struct hda_codec_ops cmi9880_patch_ops = {
.free = cmi9880_free,
};
/*
* stuff for auto-parser
*/
static const struct hda_codec_ops cmi_auto_patch_ops = {
.build_controls = snd_hda_gen_build_controls,
.build_pcms = snd_hda_gen_build_pcms,
.init = snd_hda_gen_init,
.free = snd_hda_gen_free,
.unsol_event = snd_hda_jack_unsol_event,
};
static int cmi_parse_auto_config(struct hda_codec *codec)
{
struct cmi_spec *spec = codec->spec;
struct auto_pin_cfg *cfg = &spec->gen.autocfg;
int err;
snd_hda_gen_spec_init(&spec->gen);
err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0);
if (err < 0)
return err;
err = snd_hda_gen_parse_auto_config(codec, cfg);
if (err < 0)
return err;
codec->patch_ops = cmi_auto_patch_ops;
return 0;
}
static int patch_cmi9880(struct hda_codec *codec)
{
struct cmi_spec *spec;
@@ -650,6 +615,15 @@ static int patch_cmi9880(struct hda_codec *codec)
spec->board_config = CMI_AUTO; /* try everything */
}
if (spec->board_config == CMI_AUTO) {
int err = cmi_parse_auto_config(codec);
if (err < 0) {
snd_hda_gen_free(codec);
return err;
}
return 0;
}
/* copy default DAC NIDs */
memcpy(spec->dac_nids, cmi9880_dac_nids, sizeof(spec->dac_nids));
spec->num_dacs = 4;
@@ -678,59 +652,13 @@ static int patch_cmi9880(struct hda_codec *codec)
}
break;
case CMI_ALLOUT:
default:
spec->front_panel = 1;
spec->multiout.max_channels = 8;
spec->no_line_in = 1;
spec->input_mux = &cmi9880_no_line_mux;
spec->multiout.dig_out_nid = CMI_DIG_OUT_NID;
break;
case CMI_AUTO:
{
unsigned int port_e, port_f, port_g, port_h;
unsigned int port_spdifi, port_spdifo;
struct auto_pin_cfg cfg;
/* collect pin default configuration */
port_e = snd_hda_codec_get_pincfg(codec, 0x0f);
port_f = snd_hda_codec_get_pincfg(codec, 0x10);
spec->front_panel = 1;
if (get_defcfg_connect(port_e) == AC_JACK_PORT_NONE ||
get_defcfg_connect(port_f) == AC_JACK_PORT_NONE) {
port_g = snd_hda_codec_get_pincfg(codec, 0x1f);
port_h = snd_hda_codec_get_pincfg(codec, 0x20);
spec->channel_modes = cmi9880_channel_modes;
/* no front panel */
if (get_defcfg_connect(port_g) == AC_JACK_PORT_NONE ||
get_defcfg_connect(port_h) == AC_JACK_PORT_NONE) {
/* no optional rear panel */
spec->board_config = CMI_MINIMAL;
spec->front_panel = 0;
spec->num_channel_modes = 2;
} else {
spec->board_config = CMI_MIN_FP;
spec->num_channel_modes = 3;
}
spec->input_mux = &cmi9880_basic_mux;
spec->multiout.max_channels = cmi9880_channel_modes[0].channels;
} else {
spec->input_mux = &cmi9880_basic_mux;
port_spdifi = snd_hda_codec_get_pincfg(codec, 0x13);
port_spdifo = snd_hda_codec_get_pincfg(codec, 0x12);
if (get_defcfg_connect(port_spdifo) != AC_JACK_PORT_NONE)
spec->multiout.dig_out_nid = CMI_DIG_OUT_NID;
if (get_defcfg_connect(port_spdifi) != AC_JACK_PORT_NONE)
spec->dig_in_nid = CMI_DIG_IN_NID;
spec->multiout.max_channels = 8;
}
snd_hda_parse_pin_def_config(codec, &cfg, NULL);
if (cfg.line_outs) {
spec->multiout.max_channels = cfg.line_outs * 2;
cmi9880_fill_multi_dac_nids(codec, &cfg);
cmi9880_fill_multi_init(codec, &cfg);
} else
snd_printd("patch_cmedia: cannot detect association in defcfg\n");
break;
}
}
spec->multiout.num_dacs = spec->num_dacs;

File diff suppressed because it is too large Load Diff

View File

@@ -64,6 +64,9 @@ struct hdmi_spec_per_cvt {
unsigned int maxbps;
};
/* max. connections to a widget */
#define HDA_MAX_CONNECTIONS 32
struct hdmi_spec_per_pin {
hda_nid_t pin_nid;
int num_mux_nids;
@@ -72,6 +75,7 @@ struct hdmi_spec_per_pin {
struct hda_codec *codec;
struct hdmi_eld sink_eld;
struct delayed_work work;
struct snd_kcontrol *eld_ctl;
int repoll_count;
bool non_pcm;
bool chmap_set; /* channel-map override by ALSA API? */
@@ -81,12 +85,14 @@ struct hdmi_spec_per_pin {
struct hdmi_spec {
int num_cvts;
struct hdmi_spec_per_cvt cvts[MAX_HDMI_CVTS];
hda_nid_t cvt_nids[MAX_HDMI_CVTS];
int num_pins;
struct hdmi_spec_per_pin pins[MAX_HDMI_PINS];
struct hda_pcm pcm_rec[MAX_HDMI_PINS];
unsigned int channels_max; /* max over all cvts */
struct hdmi_eld temp_eld;
/*
* Non-generic ATI/NVIDIA specific
*/
@@ -339,14 +345,18 @@ static int hdmi_eld_ctl_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct hdmi_spec *spec;
struct hdmi_spec *spec = codec->spec;
struct hdmi_eld *eld;
int pin_idx;
spec = codec->spec;
uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
pin_idx = kcontrol->private_value;
uinfo->count = spec->pins[pin_idx].sink_eld.eld_size;
eld = &spec->pins[pin_idx].sink_eld;
mutex_lock(&eld->lock);
uinfo->count = eld->eld_valid ? eld->eld_size : 0;
mutex_unlock(&eld->lock);
return 0;
}
@@ -355,14 +365,26 @@ static int hdmi_eld_ctl_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct hdmi_spec *spec;
struct hdmi_spec *spec = codec->spec;
struct hdmi_eld *eld;
int pin_idx;
spec = codec->spec;
pin_idx = kcontrol->private_value;
eld = &spec->pins[pin_idx].sink_eld;
memcpy(ucontrol->value.bytes.data,
spec->pins[pin_idx].sink_eld.eld_buffer, ELD_MAX_SIZE);
mutex_lock(&eld->lock);
if (eld->eld_size > ARRAY_SIZE(ucontrol->value.bytes.data)) {
mutex_unlock(&eld->lock);
snd_BUG();
return -EINVAL;
}
memset(ucontrol->value.bytes.data, 0,
ARRAY_SIZE(ucontrol->value.bytes.data));
if (eld->eld_valid)
memcpy(ucontrol->value.bytes.data, eld->eld_buffer,
eld->eld_size);
mutex_unlock(&eld->lock);
return 0;
}
@@ -392,6 +414,7 @@ static int hdmi_create_eld_ctl(struct hda_codec *codec, int pin_idx,
if (err < 0)
return err;
spec->pins[pin_idx].eld_ctl = kctl;
return 0;
}
@@ -516,7 +539,7 @@ static int hdmi_channel_allocation(struct hdmi_eld *eld, int channels)
* expand ELD's notions to match the ones used by Audio InfoFrame.
*/
for (i = 0; i < ARRAY_SIZE(eld_speaker_allocation_bits); i++) {
if (eld->spk_alloc & (1 << i))
if (eld->info.spk_alloc & (1 << i))
spk_mask |= eld_speaker_allocation_bits[i];
}
@@ -530,7 +553,7 @@ static int hdmi_channel_allocation(struct hdmi_eld *eld, int channels)
}
}
snd_print_channel_allocation(eld->spk_alloc, buf, sizeof(buf));
snd_print_channel_allocation(eld->info.spk_alloc, buf, sizeof(buf));
snd_printdd("HDMI: select CA 0x%x for %d-channel allocation: %s\n",
ca, channels, buf);
@@ -714,9 +737,10 @@ static void hdmi_setup_fake_chmap(unsigned char *map, int ca)
static void hdmi_setup_channel_mapping(struct hda_codec *codec,
hda_nid_t pin_nid, bool non_pcm, int ca,
int channels, unsigned char *map)
int channels, unsigned char *map,
bool chmap_set)
{
if (!non_pcm && map) {
if (!non_pcm && chmap_set) {
hdmi_manual_setup_channel_mapping(codec, pin_nid,
channels, map);
} else {
@@ -870,7 +894,7 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, int pin_idx,
ca = 0;
memset(&ai, 0, sizeof(ai));
if (eld->conn_type == 0) { /* HDMI */
if (eld->info.conn_type == 0) { /* HDMI */
struct hdmi_audio_infoframe *hdmi_ai = &ai.hdmi;
hdmi_ai->type = 0x84;
@@ -879,7 +903,7 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, int pin_idx,
hdmi_ai->CC02_CT47 = channels - 1;
hdmi_ai->CA = ca;
hdmi_checksum_audio_infoframe(hdmi_ai);
} else if (eld->conn_type == 1) { /* DisplayPort */
} else if (eld->info.conn_type == 1) { /* DisplayPort */
struct dp_audio_infoframe *dp_ai = &ai.dp;
dp_ai->type = 0x84;
@@ -905,7 +929,8 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, int pin_idx,
pin_nid,
channels);
hdmi_setup_channel_mapping(codec, pin_nid, non_pcm, ca,
channels, per_pin->chmap);
channels, per_pin->chmap,
per_pin->chmap_set);
hdmi_stop_infoframe_trans(codec, pin_nid);
hdmi_fill_audio_infoframe(codec, pin_nid,
ai.bytes, sizeof(ai));
@@ -915,7 +940,8 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, int pin_idx,
* accordingly */
if (per_pin->non_pcm != non_pcm)
hdmi_setup_channel_mapping(codec, pin_nid, non_pcm, ca,
channels, per_pin->chmap);
channels, per_pin->chmap,
per_pin->chmap_set);
}
per_pin->non_pcm = non_pcm;
@@ -1098,10 +1124,14 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
/* Restrict capabilities by ELD if this isn't disabled */
if (!static_hdmi_pcm && eld->eld_valid) {
snd_hdmi_eld_update_pcm_info(eld, hinfo);
snd_hdmi_eld_update_pcm_info(&eld->info, hinfo);
if (hinfo->channels_min > hinfo->channels_max ||
!hinfo->rates || !hinfo->formats)
!hinfo->rates || !hinfo->formats) {
per_cvt->assigned = 0;
hinfo->nid = 0;
snd_hda_spdif_ctls_unassign(codec, pin_idx);
return -ENODEV;
}
}
/* Store the updated parameters */
@@ -1142,7 +1172,9 @@ static int hdmi_read_pin_conn(struct hda_codec *codec, int pin_idx)
static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
{
struct hda_codec *codec = per_pin->codec;
struct hdmi_eld *eld = &per_pin->sink_eld;
struct hdmi_spec *spec = codec->spec;
struct hdmi_eld *eld = &spec->temp_eld;
struct hdmi_eld *pin_eld = &per_pin->sink_eld;
hda_nid_t pin_nid = per_pin->pin_nid;
/*
* Always execute a GetPinSense verb here, even when called from
@@ -1153,27 +1185,64 @@ static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
* the unsolicited response to avoid custom WARs.
*/
int present = snd_hda_pin_sense(codec, pin_nid);
bool eld_valid = false;
bool update_eld = false;
bool eld_changed = false;
memset(eld, 0, offsetof(struct hdmi_eld, eld_buffer));
eld->monitor_present = !!(present & AC_PINSENSE_PRESENCE);
if (eld->monitor_present)
eld_valid = !!(present & AC_PINSENSE_ELDV);
pin_eld->monitor_present = !!(present & AC_PINSENSE_PRESENCE);
if (pin_eld->monitor_present)
eld->eld_valid = !!(present & AC_PINSENSE_ELDV);
else
eld->eld_valid = false;
_snd_printd(SND_PR_VERBOSE,
"HDMI status: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n",
codec->addr, pin_nid, eld->monitor_present, eld_valid);
codec->addr, pin_nid, eld->monitor_present, eld->eld_valid);
if (eld_valid) {
if (!snd_hdmi_get_eld(eld, codec, pin_nid))
snd_hdmi_show_eld(eld);
if (eld->eld_valid) {
if (snd_hdmi_get_eld(codec, pin_nid, eld->eld_buffer,
&eld->eld_size) < 0)
eld->eld_valid = false;
else {
memset(&eld->info, 0, sizeof(struct parsed_hdmi_eld));
if (snd_hdmi_parse_eld(&eld->info, eld->eld_buffer,
eld->eld_size) < 0)
eld->eld_valid = false;
}
if (eld->eld_valid) {
snd_hdmi_show_eld(&eld->info);
update_eld = true;
}
else if (repoll) {
queue_delayed_work(codec->bus->workq,
&per_pin->work,
msecs_to_jiffies(300));
return;
}
}
mutex_lock(&pin_eld->lock);
if (pin_eld->eld_valid && !eld->eld_valid) {
update_eld = true;
eld_changed = true;
}
if (update_eld) {
pin_eld->eld_valid = eld->eld_valid;
eld_changed = pin_eld->eld_size != eld->eld_size ||
memcmp(pin_eld->eld_buffer, eld->eld_buffer,
eld->eld_size) != 0;
if (eld_changed)
memcpy(pin_eld->eld_buffer, eld->eld_buffer,
eld->eld_size);
pin_eld->eld_size = eld->eld_size;
pin_eld->info = eld->info;
}
mutex_unlock(&pin_eld->lock);
if (eld_changed)
snd_ctl_notify(codec->bus->card,
SNDRV_CTL_EVENT_MASK_VALUE | SNDRV_CTL_EVENT_MASK_INFO,
&per_pin->eld_ctl->id);
}
static void hdmi_repoll_eld(struct work_struct *work)
@@ -1187,6 +1256,9 @@ static void hdmi_repoll_eld(struct work_struct *work)
hdmi_present_sense(per_pin, per_pin->repoll_count);
}
static void intel_haswell_fixup_connect_list(struct hda_codec *codec,
hda_nid_t nid);
static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)
{
struct hdmi_spec *spec = codec->spec;
@@ -1206,6 +1278,9 @@ static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)
if (snd_BUG_ON(spec->num_pins >= MAX_HDMI_PINS))
return -E2BIG;
if (codec->vendor_id == 0x80862807)
intel_haswell_fixup_connect_list(codec, pin_nid);
pin_idx = spec->num_pins;
per_pin = &spec->pins[pin_idx];
@@ -1253,7 +1328,7 @@ static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t cvt_nid)
if (err < 0)
return err;
spec->num_cvts++;
spec->cvt_nids[spec->num_cvts++] = cvt_nid;
return 0;
}
@@ -1635,6 +1710,7 @@ static int generic_hdmi_init_per_pins(struct hda_codec *codec)
struct hdmi_eld *eld = &per_pin->sink_eld;
per_pin->codec = codec;
mutex_init(&eld->lock);
INIT_DELAYED_WORK(&per_pin->work, hdmi_repoll_eld);
snd_hda_eld_proc_new(codec, eld, pin_idx);
}
@@ -1681,30 +1757,92 @@ static const struct hda_codec_ops generic_hdmi_patch_ops = {
.unsol_event = hdmi_unsol_event,
};
static void intel_haswell_fixup_connect_list(struct hda_codec *codec)
static void intel_haswell_fixup_connect_list(struct hda_codec *codec,
hda_nid_t nid)
{
struct hdmi_spec *spec = codec->spec;
hda_nid_t conns[4];
int nconns;
nconns = snd_hda_get_connections(codec, nid, conns, ARRAY_SIZE(conns));
if (nconns == spec->num_cvts &&
!memcmp(conns, spec->cvt_nids, spec->num_cvts * sizeof(hda_nid_t)))
return;
/* override pins connection list */
snd_printdd("hdmi: haswell: override pin connection 0x%x\n", nid);
snd_hda_override_conn_list(codec, nid, spec->num_cvts, spec->cvt_nids);
}
#define INTEL_VENDOR_NID 0x08
#define INTEL_GET_VENDOR_VERB 0xf81
#define INTEL_SET_VENDOR_VERB 0x781
#define INTEL_EN_DP12 0x02 /* enable DP 1.2 features */
#define INTEL_EN_ALL_PIN_CVTS 0x01 /* enable 2nd & 3rd pins and convertors */
static void intel_haswell_enable_all_pins(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
unsigned int vendor_param;
hda_nid_t list[3] = {0x2, 0x3, 0x4};
vendor_param = snd_hda_codec_read(codec, 0x08, 0, 0xf81, 0);
if (vendor_param == -1 || vendor_param & 0x02)
if (action != HDA_FIXUP_ACT_PRE_PROBE)
return;
vendor_param = snd_hda_codec_read(codec, INTEL_VENDOR_NID, 0,
INTEL_GET_VENDOR_VERB, 0);
if (vendor_param == -1 || vendor_param & INTEL_EN_ALL_PIN_CVTS)
return;
vendor_param |= INTEL_EN_ALL_PIN_CVTS;
vendor_param = snd_hda_codec_read(codec, INTEL_VENDOR_NID, 0,
INTEL_SET_VENDOR_VERB, vendor_param);
if (vendor_param == -1)
return;
snd_hda_codec_update_widgets(codec);
return;
}
static void intel_haswell_fixup_enable_dp12(struct hda_codec *codec)
{
unsigned int vendor_param;
vendor_param = snd_hda_codec_read(codec, INTEL_VENDOR_NID, 0,
INTEL_GET_VENDOR_VERB, 0);
if (vendor_param == -1 || vendor_param & INTEL_EN_DP12)
return;
/* enable DP1.2 mode */
vendor_param |= 0x02;
snd_hda_codec_read(codec, 0x08, 0, 0x781, vendor_param);
vendor_param = snd_hda_codec_read(codec, 0x08, 0, 0xf81, 0);
if (vendor_param == -1 || !(vendor_param & 0x02))
return;
/* override 3 pins connection list */
snd_hda_override_conn_list(codec, 0x05, 3, list);
snd_hda_override_conn_list(codec, 0x06, 3, list);
snd_hda_override_conn_list(codec, 0x07, 3, list);
vendor_param |= INTEL_EN_DP12;
snd_hda_codec_write_cache(codec, INTEL_VENDOR_NID, 0,
INTEL_SET_VENDOR_VERB, vendor_param);
}
/* available models for fixup */
enum {
INTEL_HASWELL,
};
static const struct hda_model_fixup hdmi_models[] = {
{.id = INTEL_HASWELL, .name = "Haswell"},
{}
};
static const struct snd_pci_quirk hdmi_fixup_tbl[] = {
SND_PCI_QUIRK(0x8086, 0x2010, "Haswell", INTEL_HASWELL),
{} /* terminator */
};
static const struct hda_fixup hdmi_fixups[] = {
[INTEL_HASWELL] = {
.type = HDA_FIXUP_FUNC,
.v.func = intel_haswell_enable_all_pins,
},
};
static int patch_generic_hdmi(struct hda_codec *codec)
{
struct hdmi_spec *spec;
@@ -1715,8 +1853,11 @@ static int patch_generic_hdmi(struct hda_codec *codec)
codec->spec = spec;
snd_hda_pick_fixup(codec, hdmi_models, hdmi_fixup_tbl, hdmi_fixups);
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
if (codec->vendor_id == 0x80862807)
intel_haswell_fixup_connect_list(codec);
intel_haswell_fixup_enable_dp12(codec);
if (hdmi_parse_codec(codec) < 0) {
codec->spec = NULL;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -31,7 +31,7 @@
static void snd_wm8766_write(struct snd_wm8766 *wm, u16 addr, u16 data)
{
if (addr < WM8766_REG_RESET)
if (addr < WM8766_REG_COUNT)
wm->regs[addr] = data;
wm->ops.write(wm, addr, data);
}

View File

@@ -3266,11 +3266,13 @@ static int check_default_spdif_aclink(struct pci_dev *pci)
w = snd_pci_quirk_lookup(pci, spdif_aclink_defaults);
if (w) {
if (w->value)
snd_printdd(KERN_INFO "intel8x0: Using SPDIF over "
"AC-Link for %s\n", w->name);
snd_printdd(KERN_INFO
"intel8x0: Using SPDIF over AC-Link for %s\n",
snd_pci_quirk_name(w));
else
snd_printdd(KERN_INFO "intel8x0: Using integrated "
"SPDIF DMA for %s\n", w->name);
snd_printdd(KERN_INFO
"intel8x0: Using integrated SPDIF DMA for %s\n",
snd_pci_quirk_name(w));
return w->value;
}
return 0;

View File

@@ -2586,8 +2586,9 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci,
else {
quirk = snd_pci_quirk_lookup(pci, m3_amp_quirk_list);
if (quirk) {
snd_printdd(KERN_INFO "maestro3: set amp-gpio "
"for '%s'\n", quirk->name);
snd_printdd(KERN_INFO
"maestro3: set amp-gpio for '%s'\n",
snd_pci_quirk_name(quirk));
chip->amp_gpio = quirk->value;
} else if (chip->allegro_flag)
chip->amp_gpio = GPO_EXT_AMP_ALLEGRO;
@@ -2597,8 +2598,9 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci,
quirk = snd_pci_quirk_lookup(pci, m3_irda_quirk_list);
if (quirk) {
snd_printdd(KERN_INFO "maestro3: enabled irda workaround "
"for '%s'\n", quirk->name);
snd_printdd(KERN_INFO
"maestro3: enabled irda workaround for '%s'\n",
snd_pci_quirk_name(quirk));
chip->irda_workaround = 1;
}
quirk = snd_pci_quirk_lookup(pci, m3_hv_quirk_list);

View File

@@ -1660,7 +1660,8 @@ static int snd_nm256_probe(struct pci_dev *pci,
q = snd_pci_quirk_lookup(pci, nm256_quirks);
if (q) {
snd_printdd(KERN_INFO "nm256: Enabled quirk for %s.\n", q->name);
snd_printdd(KERN_INFO "nm256: Enabled quirk for %s.\n",
snd_pci_quirk_name(q));
switch (q->value) {
case NM_BLACKLISTED:
printk(KERN_INFO "nm256: The device is blacklisted. "

View File

@@ -1012,13 +1012,12 @@ static int pcxhr_handle_async_err(struct pcxhr_mgr *mgr, u32 err,
enum pcxhr_async_err_src err_src, int pipe,
int is_capture)
{
#ifdef CONFIG_SND_DEBUG_VERBOSE
static char* err_src_name[] = {
[PCXHR_ERR_PIPE] = "Pipe",
[PCXHR_ERR_STREAM] = "Stream",
[PCXHR_ERR_AUDIO] = "Audio"
};
#endif
if (err & 0xfff)
err &= 0xfff;
else

View File

@@ -1017,7 +1017,7 @@ static int snd_rme32_capture_close(struct snd_pcm_substream *substream)
spin_lock_irq(&rme32->lock);
rme32->capture_substream = NULL;
rme32->capture_periodsize = 0;
spin_unlock(&rme32->lock);
spin_unlock_irq(&rme32->lock);
return 0;
}

View File

@@ -154,10 +154,13 @@ MODULE_FIRMWARE("digiface_firmware_rev11.bin");
#define HDSP_BIGENDIAN_MODE 0x200
#define HDSP_RD_MULTIPLE 0x400
#define HDSP_9652_ENABLE_MIXER 0x800
#define HDSP_S200 0x800
#define HDSP_S300 (0x100 | HDSP_S200) /* dummy, purpose of 0x100 unknown */
#define HDSP_CYCLIC_MODE 0x1000
#define HDSP_TDO 0x10000000
#define HDSP_S_PROGRAM (HDSP_PROGRAM|HDSP_CONFIG_MODE_0)
#define HDSP_S_LOAD (HDSP_PROGRAM|HDSP_CONFIG_MODE_1)
#define HDSP_S_PROGRAM (HDSP_CYCLIC_MODE|HDSP_PROGRAM|HDSP_CONFIG_MODE_0)
#define HDSP_S_LOAD (HDSP_CYCLIC_MODE|HDSP_PROGRAM|HDSP_CONFIG_MODE_1)
/* Control Register bits */
@@ -671,13 +674,23 @@ static unsigned int hdsp_read(struct hdsp *hdsp, int reg)
static int hdsp_check_for_iobox (struct hdsp *hdsp)
{
int i;
if (hdsp->io_type == H9652 || hdsp->io_type == H9632) return 0;
if (hdsp_read (hdsp, HDSP_statusRegister) & HDSP_ConfigError) {
snd_printk("Hammerfall-DSP: no IO box connected!\n");
hdsp->state &= ~HDSP_FirmwareLoaded;
return -EIO;
for (i = 0; i < 500; i++) {
if (0 == (hdsp_read(hdsp, HDSP_statusRegister) &
HDSP_ConfigError)) {
if (i) {
snd_printd("Hammerfall-DSP: IO box found after %d ms\n",
(20 * i));
}
return 0;
}
msleep(20);
}
return 0;
snd_printk(KERN_ERR "Hammerfall-DSP: no IO box connected!\n");
hdsp->state &= ~HDSP_FirmwareLoaded;
return -EIO;
}
static int hdsp_wait_for_iobox(struct hdsp *hdsp, unsigned int loops,
@@ -728,6 +741,7 @@ static int snd_hdsp_load_firmware_from_cache(struct hdsp *hdsp) {
if (hdsp_fifo_wait (hdsp, 0, HDSP_LONG_WAIT)) {
snd_printk ("Hammerfall-DSP: timeout waiting for download preparation\n");
hdsp_write(hdsp, HDSP_control2Reg, HDSP_S200);
return -EIO;
}
@@ -737,17 +751,15 @@ static int snd_hdsp_load_firmware_from_cache(struct hdsp *hdsp) {
hdsp_write(hdsp, HDSP_fifoData, cache[i]);
if (hdsp_fifo_wait (hdsp, 127, HDSP_LONG_WAIT)) {
snd_printk ("Hammerfall-DSP: timeout during firmware loading\n");
hdsp_write(hdsp, HDSP_control2Reg, HDSP_S200);
return -EIO;
}
}
hdsp_fifo_wait(hdsp, 3, HDSP_LONG_WAIT);
hdsp_write(hdsp, HDSP_control2Reg, HDSP_S200);
ssleep(3);
if (hdsp_fifo_wait (hdsp, 0, HDSP_LONG_WAIT)) {
snd_printk ("Hammerfall-DSP: timeout at end of firmware loading\n");
return -EIO;
}
#ifdef SNDRV_BIG_ENDIAN
hdsp->control2_register = HDSP_BIGENDIAN_MODE;
#else
@@ -773,24 +785,51 @@ static int hdsp_get_iobox_version (struct hdsp *hdsp)
{
if ((hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DllError) != 0) {
hdsp_write (hdsp, HDSP_control2Reg, HDSP_PROGRAM);
hdsp_write (hdsp, HDSP_fifoData, 0);
if (hdsp_fifo_wait (hdsp, 0, HDSP_SHORT_WAIT) < 0)
return -EIO;
hdsp_write(hdsp, HDSP_control2Reg, HDSP_S_LOAD);
hdsp_write(hdsp, HDSP_fifoData, 0);
hdsp_write (hdsp, HDSP_control2Reg, HDSP_S_LOAD);
hdsp_write (hdsp, HDSP_fifoData, 0);
if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT)) {
hdsp_write(hdsp, HDSP_control2Reg, HDSP_VERSION_BIT);
if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT) < 0) {
hdsp_write(hdsp, HDSP_control2Reg, HDSP_S300);
hdsp_write(hdsp, HDSP_control2Reg, HDSP_S_LOAD);
if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT))
hdsp->io_type = RPM;
else
hdsp->io_type = Multiface;
} else {
hdsp->io_type = Digiface;
}
hdsp_write(hdsp, HDSP_control2Reg, HDSP_S200 | HDSP_PROGRAM);
hdsp_write (hdsp, HDSP_fifoData, 0);
if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT) < 0) {
hdsp->io_type = Multiface;
snd_printk("Hammerfall-DSP: Multiface found\n");
return 0;
}
hdsp_write(hdsp, HDSP_control2Reg, HDSP_S_LOAD);
hdsp_write(hdsp, HDSP_fifoData, 0);
if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT) == 0) {
hdsp->io_type = Digiface;
snd_printk("Hammerfall-DSP: Digiface found\n");
return 0;
}
hdsp_write(hdsp, HDSP_control2Reg, HDSP_S300);
hdsp_write(hdsp, HDSP_control2Reg, HDSP_S_LOAD);
hdsp_write(hdsp, HDSP_fifoData, 0);
if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT) == 0) {
hdsp->io_type = Multiface;
snd_printk("Hammerfall-DSP: Multiface found\n");
return 0;
}
hdsp_write(hdsp, HDSP_control2Reg, HDSP_S300);
hdsp_write(hdsp, HDSP_control2Reg, HDSP_S_LOAD);
hdsp_write(hdsp, HDSP_fifoData, 0);
if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT) < 0) {
hdsp->io_type = Multiface;
snd_printk("Hammerfall-DSP: Multiface found\n");
return 0;
}
hdsp->io_type = RPM;
snd_printk("Hammerfall-DSP: RPM found\n");
return 0;
} else {
/* firmware was already loaded, get iobox type */
if (hdsp_read(hdsp, HDSP_status2Register) & HDSP_version2)
@@ -1674,83 +1713,50 @@ static int snd_hdsp_put_spdif_in(struct snd_kcontrol *kcontrol, struct snd_ctl_e
return change;
}
#define HDSP_SPDIF_OUT(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
.info = snd_hdsp_info_spdif_bits, \
.get = snd_hdsp_get_spdif_out, .put = snd_hdsp_put_spdif_out }
static int hdsp_spdif_out(struct hdsp *hdsp)
{
return (hdsp->control_register & HDSP_SPDIFOpticalOut) ? 1 : 0;
#define HDSP_TOGGLE_SETTING(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.private_value = xindex, \
.info = snd_hdsp_info_toggle_setting, \
.get = snd_hdsp_get_toggle_setting, \
.put = snd_hdsp_put_toggle_setting \
}
static int hdsp_set_spdif_output(struct hdsp *hdsp, int out)
static int hdsp_toggle_setting(struct hdsp *hdsp, u32 regmask)
{
return (hdsp->control_register & regmask) ? 1 : 0;
}
static int hdsp_set_toggle_setting(struct hdsp *hdsp, u32 regmask, int out)
{
if (out)
hdsp->control_register |= HDSP_SPDIFOpticalOut;
hdsp->control_register |= regmask;
else
hdsp->control_register &= ~HDSP_SPDIFOpticalOut;
hdsp->control_register &= ~regmask;
hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
return 0;
}
#define snd_hdsp_info_spdif_bits snd_ctl_boolean_mono_info
#define snd_hdsp_info_toggle_setting snd_ctl_boolean_mono_info
static int snd_hdsp_get_spdif_out(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
static int snd_hdsp_get_toggle_setting(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
u32 regmask = kcontrol->private_value;
ucontrol->value.integer.value[0] = hdsp_spdif_out(hdsp);
return 0;
}
static int snd_hdsp_put_spdif_out(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
int change;
unsigned int val;
if (!snd_hdsp_use_is_exclusive(hdsp))
return -EBUSY;
val = ucontrol->value.integer.value[0] & 1;
spin_lock_irq(&hdsp->lock);
change = (int)val != hdsp_spdif_out(hdsp);
hdsp_set_spdif_output(hdsp, val);
ucontrol->value.integer.value[0] = hdsp_toggle_setting(hdsp, regmask);
spin_unlock_irq(&hdsp->lock);
return change;
}
#define HDSP_SPDIF_PROFESSIONAL(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
.info = snd_hdsp_info_spdif_bits, \
.get = snd_hdsp_get_spdif_professional, .put = snd_hdsp_put_spdif_professional }
static int hdsp_spdif_professional(struct hdsp *hdsp)
{
return (hdsp->control_register & HDSP_SPDIFProfessional) ? 1 : 0;
}
static int hdsp_set_spdif_professional(struct hdsp *hdsp, int val)
{
if (val)
hdsp->control_register |= HDSP_SPDIFProfessional;
else
hdsp->control_register &= ~HDSP_SPDIFProfessional;
hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
return 0;
}
static int snd_hdsp_get_spdif_professional(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
ucontrol->value.integer.value[0] = hdsp_spdif_professional(hdsp);
return 0;
}
static int snd_hdsp_put_spdif_professional(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
static int snd_hdsp_put_toggle_setting(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
u32 regmask = kcontrol->private_value;
int change;
unsigned int val;
@@ -1758,96 +1764,9 @@ static int snd_hdsp_put_spdif_professional(struct snd_kcontrol *kcontrol, struct
return -EBUSY;
val = ucontrol->value.integer.value[0] & 1;
spin_lock_irq(&hdsp->lock);
change = (int)val != hdsp_spdif_professional(hdsp);
hdsp_set_spdif_professional(hdsp, val);
spin_unlock_irq(&hdsp->lock);
return change;
}
#define HDSP_SPDIF_EMPHASIS(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
.info = snd_hdsp_info_spdif_bits, \
.get = snd_hdsp_get_spdif_emphasis, .put = snd_hdsp_put_spdif_emphasis }
static int hdsp_spdif_emphasis(struct hdsp *hdsp)
{
return (hdsp->control_register & HDSP_SPDIFEmphasis) ? 1 : 0;
}
static int hdsp_set_spdif_emphasis(struct hdsp *hdsp, int val)
{
if (val)
hdsp->control_register |= HDSP_SPDIFEmphasis;
else
hdsp->control_register &= ~HDSP_SPDIFEmphasis;
hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
return 0;
}
static int snd_hdsp_get_spdif_emphasis(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
ucontrol->value.integer.value[0] = hdsp_spdif_emphasis(hdsp);
return 0;
}
static int snd_hdsp_put_spdif_emphasis(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
int change;
unsigned int val;
if (!snd_hdsp_use_is_exclusive(hdsp))
return -EBUSY;
val = ucontrol->value.integer.value[0] & 1;
spin_lock_irq(&hdsp->lock);
change = (int)val != hdsp_spdif_emphasis(hdsp);
hdsp_set_spdif_emphasis(hdsp, val);
spin_unlock_irq(&hdsp->lock);
return change;
}
#define HDSP_SPDIF_NON_AUDIO(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
.info = snd_hdsp_info_spdif_bits, \
.get = snd_hdsp_get_spdif_nonaudio, .put = snd_hdsp_put_spdif_nonaudio }
static int hdsp_spdif_nonaudio(struct hdsp *hdsp)
{
return (hdsp->control_register & HDSP_SPDIFNonAudio) ? 1 : 0;
}
static int hdsp_set_spdif_nonaudio(struct hdsp *hdsp, int val)
{
if (val)
hdsp->control_register |= HDSP_SPDIFNonAudio;
else
hdsp->control_register &= ~HDSP_SPDIFNonAudio;
hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
return 0;
}
static int snd_hdsp_get_spdif_nonaudio(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
ucontrol->value.integer.value[0] = hdsp_spdif_nonaudio(hdsp);
return 0;
}
static int snd_hdsp_put_spdif_nonaudio(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
int change;
unsigned int val;
if (!snd_hdsp_use_is_exclusive(hdsp))
return -EBUSY;
val = ucontrol->value.integer.value[0] & 1;
spin_lock_irq(&hdsp->lock);
change = (int)val != hdsp_spdif_nonaudio(hdsp);
hdsp_set_spdif_nonaudio(hdsp, val);
change = (int) val != hdsp_toggle_setting(hdsp, regmask);
if (change)
hdsp_set_toggle_setting(hdsp, regmask, val);
spin_unlock_irq(&hdsp->lock);
return change;
}
@@ -2451,114 +2370,6 @@ static int snd_hdsp_put_phone_gain(struct snd_kcontrol *kcontrol, struct snd_ctl
return change;
}
#define HDSP_XLR_BREAKOUT_CABLE(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.info = snd_hdsp_info_xlr_breakout_cable, \
.get = snd_hdsp_get_xlr_breakout_cable, \
.put = snd_hdsp_put_xlr_breakout_cable \
}
static int hdsp_xlr_breakout_cable(struct hdsp *hdsp)
{
if (hdsp->control_register & HDSP_XLRBreakoutCable)
return 1;
return 0;
}
static int hdsp_set_xlr_breakout_cable(struct hdsp *hdsp, int mode)
{
if (mode)
hdsp->control_register |= HDSP_XLRBreakoutCable;
else
hdsp->control_register &= ~HDSP_XLRBreakoutCable;
hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
return 0;
}
#define snd_hdsp_info_xlr_breakout_cable snd_ctl_boolean_mono_info
static int snd_hdsp_get_xlr_breakout_cable(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
ucontrol->value.enumerated.item[0] = hdsp_xlr_breakout_cable(hdsp);
return 0;
}
static int snd_hdsp_put_xlr_breakout_cable(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
int change;
int val;
if (!snd_hdsp_use_is_exclusive(hdsp))
return -EBUSY;
val = ucontrol->value.integer.value[0] & 1;
spin_lock_irq(&hdsp->lock);
change = (int)val != hdsp_xlr_breakout_cable(hdsp);
hdsp_set_xlr_breakout_cable(hdsp, val);
spin_unlock_irq(&hdsp->lock);
return change;
}
/* (De)activates old RME Analog Extension Board
These are connected to the internal ADAT connector
Switching this on desactivates external ADAT
*/
#define HDSP_AEB(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.info = snd_hdsp_info_aeb, \
.get = snd_hdsp_get_aeb, \
.put = snd_hdsp_put_aeb \
}
static int hdsp_aeb(struct hdsp *hdsp)
{
if (hdsp->control_register & HDSP_AnalogExtensionBoard)
return 1;
return 0;
}
static int hdsp_set_aeb(struct hdsp *hdsp, int mode)
{
if (mode)
hdsp->control_register |= HDSP_AnalogExtensionBoard;
else
hdsp->control_register &= ~HDSP_AnalogExtensionBoard;
hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
return 0;
}
#define snd_hdsp_info_aeb snd_ctl_boolean_mono_info
static int snd_hdsp_get_aeb(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
ucontrol->value.enumerated.item[0] = hdsp_aeb(hdsp);
return 0;
}
static int snd_hdsp_put_aeb(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
int change;
int val;
if (!snd_hdsp_use_is_exclusive(hdsp))
return -EBUSY;
val = ucontrol->value.integer.value[0] & 1;
spin_lock_irq(&hdsp->lock);
change = (int)val != hdsp_aeb(hdsp);
hdsp_set_aeb(hdsp, val);
spin_unlock_irq(&hdsp->lock);
return change;
}
#define HDSP_PREF_SYNC_REF(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
@@ -2747,58 +2558,6 @@ static int snd_hdsp_get_autosync_ref(struct snd_kcontrol *kcontrol, struct snd_c
return 0;
}
#define HDSP_LINE_OUT(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.info = snd_hdsp_info_line_out, \
.get = snd_hdsp_get_line_out, \
.put = snd_hdsp_put_line_out \
}
static int hdsp_line_out(struct hdsp *hdsp)
{
return (hdsp->control_register & HDSP_LineOut) ? 1 : 0;
}
static int hdsp_set_line_output(struct hdsp *hdsp, int out)
{
if (out)
hdsp->control_register |= HDSP_LineOut;
else
hdsp->control_register &= ~HDSP_LineOut;
hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
return 0;
}
#define snd_hdsp_info_line_out snd_ctl_boolean_mono_info
static int snd_hdsp_get_line_out(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
spin_lock_irq(&hdsp->lock);
ucontrol->value.integer.value[0] = hdsp_line_out(hdsp);
spin_unlock_irq(&hdsp->lock);
return 0;
}
static int snd_hdsp_put_line_out(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
int change;
unsigned int val;
if (!snd_hdsp_use_is_exclusive(hdsp))
return -EBUSY;
val = ucontrol->value.integer.value[0] & 1;
spin_lock_irq(&hdsp->lock);
change = (int)val != hdsp_line_out(hdsp);
hdsp_set_line_output(hdsp, val);
spin_unlock_irq(&hdsp->lock);
return change;
}
#define HDSP_PRECISE_POINTER(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_CARD, \
.name = xname, \
@@ -3190,7 +2949,7 @@ static struct snd_kcontrol_new snd_hdsp_9632_controls[] = {
HDSP_DA_GAIN("DA Gain", 0),
HDSP_AD_GAIN("AD Gain", 0),
HDSP_PHONE_GAIN("Phones Gain", 0),
HDSP_XLR_BREAKOUT_CABLE("XLR Breakout Cable", 0),
HDSP_TOGGLE_SETTING("XLR Breakout Cable", HDSP_XLRBreakoutCable),
HDSP_DDS_OFFSET("DDS Sample Rate Offset", 0)
};
@@ -3232,10 +2991,10 @@ static struct snd_kcontrol_new snd_hdsp_controls[] = {
},
HDSP_MIXER("Mixer", 0),
HDSP_SPDIF_IN("IEC958 Input Connector", 0),
HDSP_SPDIF_OUT("IEC958 Output also on ADAT1", 0),
HDSP_SPDIF_PROFESSIONAL("IEC958 Professional Bit", 0),
HDSP_SPDIF_EMPHASIS("IEC958 Emphasis Bit", 0),
HDSP_SPDIF_NON_AUDIO("IEC958 Non-audio Bit", 0),
HDSP_TOGGLE_SETTING("IEC958 Output also on ADAT1", HDSP_SPDIFOpticalOut),
HDSP_TOGGLE_SETTING("IEC958 Professional Bit", HDSP_SPDIFProfessional),
HDSP_TOGGLE_SETTING("IEC958 Emphasis Bit", HDSP_SPDIFEmphasis),
HDSP_TOGGLE_SETTING("IEC958 Non-audio Bit", HDSP_SPDIFNonAudio),
/* 'Sample Clock Source' complies with the alsa control naming scheme */
HDSP_CLOCK_SOURCE("Sample Clock Source", 0),
{
@@ -3255,7 +3014,7 @@ HDSP_AUTOSYNC_SAMPLE_RATE("External Rate", 0),
HDSP_WC_SYNC_CHECK("Word Clock Lock Status", 0),
HDSP_SPDIF_SYNC_CHECK("SPDIF Lock Status", 0),
HDSP_ADATSYNC_SYNC_CHECK("ADAT Sync Lock Status", 0),
HDSP_LINE_OUT("Line Out", 0),
HDSP_TOGGLE_SETTING("Line Out", HDSP_LineOut),
HDSP_PRECISE_POINTER("Precise Pointer", 0),
HDSP_USE_MIDI_TASKLET("Use Midi Tasklet", 0),
};
@@ -3572,7 +3331,9 @@ static struct snd_kcontrol_new snd_hdsp_rpm_controls[] = {
HDSP_MIXER("Mixer", 0)
};
static struct snd_kcontrol_new snd_hdsp_96xx_aeb = HDSP_AEB("Analog Extension Board", 0);
static struct snd_kcontrol_new snd_hdsp_96xx_aeb =
HDSP_TOGGLE_SETTING("Analog Extension Board",
HDSP_AnalogExtensionBoard);
static struct snd_kcontrol_new snd_hdsp_adat_sync_check = HDSP_ADAT_SYNC_CHECK;
static int snd_hdsp_create_controls(struct snd_card *card, struct hdsp *hdsp)
@@ -3995,7 +3756,9 @@ snd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
}
snd_iprintf(buffer, "Phones Gain : %s\n", tmp);
snd_iprintf(buffer, "XLR Breakout Cable : %s\n", hdsp_xlr_breakout_cable(hdsp) ? "yes" : "no");
snd_iprintf(buffer, "XLR Breakout Cable : %s\n",
hdsp_toggle_setting(hdsp, HDSP_XLRBreakoutCable) ?
"yes" : "no");
if (hdsp->control_register & HDSP_AnalogExtensionBoard)
snd_iprintf(buffer, "AEB : on (ADAT1 internal)\n");
@@ -5026,29 +4789,38 @@ static int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigne
for (i = 0; i < ((hdsp->io_type != Multiface && hdsp->io_type != RPM && hdsp->io_type != H9632) ? 3 : 1); ++i)
info.adat_sync_check[i] = (unsigned char)hdsp_adat_sync_check(hdsp, i);
info.spdif_in = (unsigned char)hdsp_spdif_in(hdsp);
info.spdif_out = (unsigned char)hdsp_spdif_out(hdsp);
info.spdif_professional = (unsigned char)hdsp_spdif_professional(hdsp);
info.spdif_emphasis = (unsigned char)hdsp_spdif_emphasis(hdsp);
info.spdif_nonaudio = (unsigned char)hdsp_spdif_nonaudio(hdsp);
info.spdif_out = (unsigned char)hdsp_toggle_setting(hdsp,
HDSP_SPDIFOpticalOut);
info.spdif_professional = (unsigned char)
hdsp_toggle_setting(hdsp, HDSP_SPDIFProfessional);
info.spdif_emphasis = (unsigned char)
hdsp_toggle_setting(hdsp, HDSP_SPDIFEmphasis);
info.spdif_nonaudio = (unsigned char)
hdsp_toggle_setting(hdsp, HDSP_SPDIFNonAudio);
info.spdif_sample_rate = hdsp_spdif_sample_rate(hdsp);
info.system_sample_rate = hdsp->system_sample_rate;
info.autosync_sample_rate = hdsp_external_sample_rate(hdsp);
info.system_clock_mode = (unsigned char)hdsp_system_clock_mode(hdsp);
info.clock_source = (unsigned char)hdsp_clock_source(hdsp);
info.autosync_ref = (unsigned char)hdsp_autosync_ref(hdsp);
info.line_out = (unsigned char)hdsp_line_out(hdsp);
info.line_out = (unsigned char)
hdsp_toggle_setting(hdsp, HDSP_LineOut);
if (hdsp->io_type == H9632) {
info.da_gain = (unsigned char)hdsp_da_gain(hdsp);
info.ad_gain = (unsigned char)hdsp_ad_gain(hdsp);
info.phone_gain = (unsigned char)hdsp_phone_gain(hdsp);
info.xlr_breakout_cable = (unsigned char)hdsp_xlr_breakout_cable(hdsp);
info.xlr_breakout_cable =
(unsigned char)hdsp_toggle_setting(hdsp,
HDSP_XLRBreakoutCable);
} else if (hdsp->io_type == RPM) {
info.da_gain = (unsigned char) hdsp_rpm_input12(hdsp);
info.ad_gain = (unsigned char) hdsp_rpm_input34(hdsp);
}
if (hdsp->io_type == H9632 || hdsp->io_type == H9652)
info.analog_extension_board = (unsigned char)hdsp_aeb(hdsp);
info.analog_extension_board =
(unsigned char)hdsp_toggle_setting(hdsp,
HDSP_AnalogExtensionBoard);
spin_unlock_irqrestore(&hdsp->lock, flags);
if (copy_to_user(argp, &info, sizeof(info)))
return -EFAULT;

View File

@@ -2517,7 +2517,7 @@ static int check_dxs_list(struct pci_dev *pci, int revision)
w = snd_pci_quirk_lookup(pci, dxs_whitelist);
if (w) {
snd_printdd(KERN_INFO "via82xx: DXS white list for %s found\n",
w->name);
snd_pci_quirk_name(w));
return w->value;
}

View File

@@ -1,6 +1,6 @@
config SND_ATMEL_SOC
tristate "SoC Audio for the Atmel System-on-Chip"
depends on ARCH_AT91
depends on HAS_IOMEM
help
Say Y or M if you want to add support for codecs attached to
the ATMEL SSC interface. You will also need
@@ -24,7 +24,7 @@ config SND_ATMEL_SOC_SSC
config SND_AT91_SOC_SAM9G20_WM8731
tristate "SoC Audio support for WM8731-based At91sam9g20 evaluation board"
depends on ATMEL_SSC && SND_ATMEL_SOC && AT91_PROGRAMMABLE_CLOCKS
depends on ARCH_AT91 && ATMEL_SSC && SND_ATMEL_SOC && AT91_PROGRAMMABLE_CLOCKS
select SND_ATMEL_SOC_PDC
select SND_ATMEL_SOC_SSC
select SND_SOC_WM8731
@@ -34,7 +34,7 @@ config SND_AT91_SOC_SAM9G20_WM8731
config SND_AT91_SOC_AFEB9260
tristate "SoC Audio support for AFEB9260 board"
depends on ATMEL_SSC && ARCH_AT91 && MACH_AFEB9260 && SND_ATMEL_SOC
depends on ARCH_AT91 && ATMEL_SSC && ARCH_AT91 && MACH_AFEB9260 && SND_ATMEL_SOC
select SND_ATMEL_SOC_PDC
select SND_ATMEL_SOC_SSC
select SND_SOC_TLV320AIC23

View File

@@ -159,7 +159,7 @@ static int atmel_pcm_hw_params(struct snd_pcm_substream *substream,
pr_debug("atmel-pcm: "
"hw_params: DMA for %s initialized "
"(dma_bytes=%u, period_size=%u)\n",
"(dma_bytes=%zu, period_size=%zu)\n",
prtd->params->name,
runtime->dma_bytes,
prtd->period_size);
@@ -201,7 +201,7 @@ static int atmel_pcm_trigger(struct snd_pcm_substream *substream,
int ret = 0;
pr_debug("atmel-pcm:buffer_size = %ld,"
"dma_area = %p, dma_bytes = %u\n",
"dma_area = %p, dma_bytes = %zu\n",
rtd->buffer_size, rtd->dma_area, rtd->dma_bytes);
switch (cmd) {

View File

@@ -49,7 +49,7 @@ static int atmel_pcm_preallocate_dma_buffer(struct snd_pcm *pcm,
buf->private_data = NULL;
buf->area = dma_alloc_coherent(pcm->card->dev, size,
&buf->addr, GFP_KERNEL);
pr_debug("atmel-pcm: alloc dma buffer: area=%p, addr=%p, size=%d\n",
pr_debug("atmel-pcm: alloc dma buffer: area=%p, addr=%p, size=%zu\n",
(void *)buf->area, (void *)buf->addr, size);
if (!buf->area)

View File

@@ -88,7 +88,8 @@ void atmel_pcm_free(struct snd_pcm *pcm);
int atmel_pcm_mmap(struct snd_pcm_substream *substream,
struct vm_area_struct *vma);
#ifdef CONFIG_SND_ATMEL_SOC_PDC
#if defined(CONFIG_SND_ATMEL_SOC_PDC) || \
defined(CONFIG_SND_ATMEL_SOC_PDC_MODULE)
int atmel_pcm_pdc_platform_register(struct device *dev);
void atmel_pcm_pdc_platform_unregister(struct device *dev);
#else
@@ -101,7 +102,8 @@ static inline void atmel_pcm_pdc_platform_unregister(struct device *dev)
}
#endif
#ifdef CONFIG_SND_ATMEL_SOC_DMA
#if defined(CONFIG_SND_ATMEL_SOC_DMA) || \
defined(CONFIG_SND_ATMEL_SOC_DMA_MODULE)
int atmel_pcm_dma_platform_register(struct device *dev);
void atmel_pcm_dma_platform_unregister(struct device *dev);
#else

View File

@@ -42,8 +42,6 @@
#include <sound/initval.h>
#include <sound/soc.h>
#include <mach/hardware.h>
#include "atmel-pcm.h"
#include "atmel_ssc_dai.h"
@@ -679,15 +677,6 @@ static int atmel_ssc_resume(struct snd_soc_dai *cpu_dai)
# define atmel_ssc_resume NULL
#endif /* CONFIG_PM */
static int atmel_ssc_probe(struct snd_soc_dai *dai)
{
struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
snd_soc_dai_set_drvdata(dai, ssc_p);
return 0;
}
#define ATMEL_SSC_RATES (SNDRV_PCM_RATE_8000_96000)
#define ATMEL_SSC_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\
@@ -703,7 +692,6 @@ static const struct snd_soc_dai_ops atmel_ssc_dai_ops = {
};
static struct snd_soc_dai_driver atmel_ssc_dai = {
.probe = atmel_ssc_probe,
.suspend = atmel_ssc_suspend,
.resume = atmel_ssc_resume,
.playback = {
@@ -790,8 +778,8 @@ void atmel_ssc_put_audio(int ssc_id)
{
struct ssc_device *ssc = ssc_info[ssc_id].ssc;
ssc_free(ssc);
asoc_ssc_exit(&ssc->pdev->dev);
ssc_free(ssc);
}
EXPORT_SYMBOL_GPL(atmel_ssc_put_audio);

View File

@@ -305,10 +305,10 @@ static int at91sam9g20ek_audio_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
atmel_ssc_put_audio(0);
snd_soc_unregister_card(card);
clk_put(mclk);
clk_disable(mclk);
mclk = NULL;
snd_soc_unregister_card(card);
atmel_ssc_put_audio(0);
return 0;
}

View File

@@ -36,6 +36,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_CS4271 if SND_SOC_I2C_AND_SPI
select SND_SOC_CX20442
select SND_SOC_DA7210 if I2C
select SND_SOC_DA7213 if I2C
select SND_SOC_DA732X if I2C
select SND_SOC_DA9055 if I2C
select SND_SOC_DFBMCS320
@@ -98,7 +99,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_WM8782
select SND_SOC_WM8804 if SND_SOC_I2C_AND_SPI
select SND_SOC_WM8900 if I2C
select SND_SOC_WM8903 if I2C
select SND_SOC_WM8903 if I2C && GENERIC_HARDIRQS
select SND_SOC_WM8904 if I2C
select SND_SOC_WM8940 if I2C
select SND_SOC_WM8955 if I2C
@@ -247,6 +248,9 @@ config SND_SOC_L3
config SND_SOC_DA7210
tristate
config SND_SOC_DA7213
tristate
config SND_SOC_DA732X
tristate

View File

@@ -23,6 +23,7 @@ snd-soc-cs4270-objs := cs4270.o
snd-soc-cs4271-objs := cs4271.o
snd-soc-cx20442-objs := cx20442.o
snd-soc-da7210-objs := da7210.o
snd-soc-da7213-objs := da7213.o
snd-soc-da732x-objs := da732x.o
snd-soc-da9055-objs := da9055.o
snd-soc-dfbmcs320-objs := dfbmcs320.o
@@ -147,6 +148,7 @@ obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o
obj-$(CONFIG_SND_SOC_CS4271) += snd-soc-cs4271.o
obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o
obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o
obj-$(CONFIG_SND_SOC_DA7213) += snd-soc-da7213.o
obj-$(CONFIG_SND_SOC_DA732X) += snd-soc-da732x.o
obj-$(CONFIG_SND_SOC_DA9055) += snd-soc-da9055.o
obj-$(CONFIG_SND_SOC_DFBMCS320) += snd-soc-dfbmcs320.o

View File

@@ -26,6 +26,7 @@
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/of_device.h>
#include <linux/module.h>
#include <sound/soc.h>
#include <sound/initval.h>
@@ -513,12 +514,31 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4648 = {
};
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
static struct of_device_id ak4642_of_match[];
static int ak4642_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct device_node *np = i2c->dev.of_node;
const struct snd_soc_codec_driver *driver;
driver = NULL;
if (np) {
const struct of_device_id *of_id;
of_id = of_match_device(ak4642_of_match, &i2c->dev);
if (of_id)
driver = of_id->data;
} else {
driver = (struct snd_soc_codec_driver *)id->driver_data;
}
if (!driver) {
dev_err(&i2c->dev, "no driver\n");
return -EINVAL;
}
return snd_soc_register_codec(&i2c->dev,
(struct snd_soc_codec_driver *)id->driver_data,
&ak4642_dai, 1);
driver, &ak4642_dai, 1);
}
static int ak4642_i2c_remove(struct i2c_client *client)
@@ -527,6 +547,14 @@ static int ak4642_i2c_remove(struct i2c_client *client)
return 0;
}
static struct of_device_id ak4642_of_match[] = {
{ .compatible = "asahi-kasei,ak4642", .data = &soc_codec_dev_ak4642},
{ .compatible = "asahi-kasei,ak4643", .data = &soc_codec_dev_ak4642},
{ .compatible = "asahi-kasei,ak4648", .data = &soc_codec_dev_ak4648},
{},
};
MODULE_DEVICE_TABLE(of, ak4642_of_match);
static const struct i2c_device_id ak4642_i2c_id[] = {
{ "ak4642", (kernel_ulong_t)&soc_codec_dev_ak4642 },
{ "ak4643", (kernel_ulong_t)&soc_codec_dev_ak4642 },
@@ -539,6 +567,7 @@ static struct i2c_driver ak4642_i2c_driver = {
.driver = {
.name = "ak4642-codec",
.owner = THIS_MODULE,
.of_match_table = ak4642_of_match,
},
.probe = ak4642_i2c_probe,
.remove = ak4642_i2c_remove,

View File

@@ -56,14 +56,14 @@
#define arizona_fll_warn(_fll, fmt, ...) \
dev_warn(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
#define arizona_fll_dbg(_fll, fmt, ...) \
dev_err(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
dev_dbg(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
#define arizona_aif_err(_dai, fmt, ...) \
dev_err(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
#define arizona_aif_warn(_dai, fmt, ...) \
dev_warn(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
#define arizona_aif_dbg(_dai, fmt, ...) \
dev_err(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
dev_dbg(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
"None",
@@ -141,6 +141,30 @@ const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
"ASRC1R",
"ASRC2L",
"ASRC2R",
"ISRC1INT1",
"ISRC1INT2",
"ISRC1INT3",
"ISRC1INT4",
"ISRC1DEC1",
"ISRC1DEC2",
"ISRC1DEC3",
"ISRC1DEC4",
"ISRC2INT1",
"ISRC2INT2",
"ISRC2INT3",
"ISRC2INT4",
"ISRC2DEC1",
"ISRC2DEC2",
"ISRC2DEC3",
"ISRC2DEC4",
"ISRC3INT1",
"ISRC3INT2",
"ISRC3INT3",
"ISRC3INT4",
"ISRC3DEC1",
"ISRC3DEC2",
"ISRC3DEC3",
"ISRC3DEC4",
};
EXPORT_SYMBOL_GPL(arizona_mixer_texts);
@@ -220,6 +244,30 @@ int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS] = {
0x91,
0x92,
0x93,
0xa0, /* ISRC1INT1 */
0xa1,
0xa2,
0xa3,
0xa4, /* ISRC1DEC1 */
0xa5,
0xa6,
0xa7,
0xa8, /* ISRC2DEC1 */
0xa9,
0xaa,
0xab,
0xac, /* ISRC2INT1 */
0xad,
0xae,
0xaf,
0xb0, /* ISRC3DEC1 */
0xb1,
0xb2,
0xb3,
0xb4, /* ISRC3INT1 */
0xb5,
0xb6,
0xb7,
};
EXPORT_SYMBOL_GPL(arizona_mixer_values);
@@ -275,9 +323,35 @@ const struct soc_enum arizona_lhpf4_mode =
arizona_lhpf_mode_text);
EXPORT_SYMBOL_GPL(arizona_lhpf4_mode);
static const char *arizona_ng_hold_text[] = {
"30ms", "120ms", "250ms", "500ms",
};
const struct soc_enum arizona_ng_hold =
SOC_ENUM_SINGLE(ARIZONA_NOISE_GATE_CONTROL, ARIZONA_NGATE_HOLD_SHIFT,
4, arizona_ng_hold_text);
EXPORT_SYMBOL_GPL(arizona_ng_hold);
int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
int event)
{
unsigned int reg;
if (w->shift % 2)
reg = ARIZONA_ADC_DIGITAL_VOLUME_1L + ((w->shift / 2) * 8);
else
reg = ARIZONA_ADC_DIGITAL_VOLUME_1R + ((w->shift / 2) * 8);
switch (event) {
case SND_SOC_DAPM_POST_PMU:
snd_soc_update_bits(w->codec, reg, ARIZONA_IN1L_MUTE, 0);
break;
case SND_SOC_DAPM_PRE_PMD:
snd_soc_update_bits(w->codec, reg, ARIZONA_IN1L_MUTE,
ARIZONA_IN1L_MUTE);
break;
}
return 0;
}
EXPORT_SYMBOL_GPL(arizona_in_ev);
@@ -417,6 +491,10 @@ int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
case 147456000:
val |= 6 << ARIZONA_SYSCLK_FREQ_SHIFT;
break;
case 0:
dev_dbg(arizona->dev, "%s cleared\n", name);
*clk = freq;
return 0;
default:
return -EINVAL;
}
@@ -635,6 +713,9 @@ static int arizona_startup(struct snd_pcm_substream *substream,
return 0;
}
if (base_rate == 0)
return 0;
if (base_rate % 8000)
constraint = &arizona_44k1_constraint;
else
@@ -645,25 +726,81 @@ static int arizona_startup(struct snd_pcm_substream *substream,
constraint);
}
static int arizona_hw_params_rate(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
int base = dai->driver->base;
int i, sr_val;
/*
* We will need to be more flexible than this in future,
* currently we use a single sample rate for SYSCLK.
*/
for (i = 0; i < ARRAY_SIZE(arizona_sr_vals); i++)
if (arizona_sr_vals[i] == params_rate(params))
break;
if (i == ARRAY_SIZE(arizona_sr_vals)) {
arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
params_rate(params));
return -EINVAL;
}
sr_val = i;
switch (dai_priv->clk) {
case ARIZONA_CLK_SYSCLK:
snd_soc_update_bits(codec, ARIZONA_SAMPLE_RATE_1,
ARIZONA_SAMPLE_RATE_1_MASK, sr_val);
if (base)
snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
ARIZONA_AIF1_RATE_MASK, 0);
break;
case ARIZONA_CLK_ASYNCCLK:
snd_soc_update_bits(codec, ARIZONA_ASYNC_SAMPLE_RATE_1,
ARIZONA_ASYNC_SAMPLE_RATE_MASK, sr_val);
if (base)
snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
ARIZONA_AIF1_RATE_MASK,
8 << ARIZONA_AIF1_RATE_SHIFT);
break;
default:
arizona_aif_err(dai, "Invalid clock %d\n", dai_priv->clk);
return -EINVAL;
}
return 0;
}
static int arizona_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
struct arizona *arizona = priv->arizona;
int base = dai->driver->base;
const int *rates;
int i;
int bclk, lrclk, wl, frame, sr_val;
int i, ret;
int chan_limit = arizona->pdata.max_channels_clocked[dai->id - 1];
int bclk, lrclk, wl, frame, bclk_target;
if (params_rate(params) % 8000)
rates = &arizona_44k1_bclk_rates[0];
else
rates = &arizona_48k_bclk_rates[0];
bclk_target = snd_soc_params_to_bclk(params);
if (chan_limit && chan_limit < params_channels(params)) {
arizona_aif_dbg(dai, "Limiting to %d channels\n", chan_limit);
bclk_target /= params_channels(params);
bclk_target *= chan_limit;
}
for (i = 0; i < ARRAY_SIZE(arizona_44k1_bclk_rates); i++) {
if (rates[i] >= snd_soc_params_to_bclk(params) &&
if (rates[i] >= bclk_target &&
rates[i] % params_rate(params) == 0) {
bclk = i;
break;
@@ -675,16 +812,6 @@ static int arizona_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
for (i = 0; i < ARRAY_SIZE(arizona_sr_vals); i++)
if (arizona_sr_vals[i] == params_rate(params))
break;
if (i == ARRAY_SIZE(arizona_sr_vals)) {
arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
params_rate(params));
return -EINVAL;
}
sr_val = i;
lrclk = rates[bclk] / params_rate(params);
arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n",
@@ -693,28 +820,9 @@ static int arizona_hw_params(struct snd_pcm_substream *substream,
wl = snd_pcm_format_width(params_format(params));
frame = wl << ARIZONA_AIF1TX_WL_SHIFT | wl;
/*
* We will need to be more flexible than this in future,
* currently we use a single sample rate for SYSCLK.
*/
switch (dai_priv->clk) {
case ARIZONA_CLK_SYSCLK:
snd_soc_update_bits(codec, ARIZONA_SAMPLE_RATE_1,
ARIZONA_SAMPLE_RATE_1_MASK, sr_val);
snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
ARIZONA_AIF1_RATE_MASK, 0);
break;
case ARIZONA_CLK_ASYNCCLK:
snd_soc_update_bits(codec, ARIZONA_ASYNC_SAMPLE_RATE_1,
ARIZONA_ASYNC_SAMPLE_RATE_MASK, sr_val);
snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
ARIZONA_AIF1_RATE_MASK,
8 << ARIZONA_AIF1_RATE_SHIFT);
break;
default:
arizona_aif_err(dai, "Invalid clock %d\n", dai_priv->clk);
return -EINVAL;
}
ret = arizona_hw_params_rate(substream, params, dai);
if (ret != 0)
return ret;
snd_soc_update_bits(codec, base + ARIZONA_AIF_BCLK_CTRL,
ARIZONA_AIF1_BCLK_FREQ_MASK, bclk);
@@ -789,11 +897,27 @@ static int arizona_dai_set_sysclk(struct snd_soc_dai *dai,
return snd_soc_dapm_sync(&codec->dapm);
}
static int arizona_set_tristate(struct snd_soc_dai *dai, int tristate)
{
struct snd_soc_codec *codec = dai->codec;
int base = dai->driver->base;
unsigned int reg;
if (tristate)
reg = ARIZONA_AIF1_TRI;
else
reg = 0;
return snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
ARIZONA_AIF1_TRI, reg);
}
const struct snd_soc_dai_ops arizona_dai_ops = {
.startup = arizona_startup,
.set_fmt = arizona_set_fmt,
.hw_params = arizona_hw_params,
.set_sysclk = arizona_dai_set_sysclk,
.set_tristate = arizona_set_tristate,
};
EXPORT_SYMBOL_GPL(arizona_dai_ops);
@@ -807,17 +931,6 @@ int arizona_init_dai(struct arizona_priv *priv, int id)
}
EXPORT_SYMBOL_GPL(arizona_init_dai);
static irqreturn_t arizona_fll_lock(int irq, void *data)
{
struct arizona_fll *fll = data;
arizona_fll_dbg(fll, "Lock status changed\n");
complete(&fll->lock);
return IRQ_HANDLED;
}
static irqreturn_t arizona_fll_clock_ok(int irq, void *data)
{
struct arizona_fll *fll = data;
@@ -910,7 +1023,7 @@ static int arizona_calc_fll(struct arizona_fll *fll,
cfg->n = target / (ratio * Fref);
if (target % Fref) {
if (target % (ratio * Fref)) {
gcd_fll = gcd(target, ratio * Fref);
arizona_fll_dbg(fll, "GCD=%u\n", gcd_fll);
@@ -922,6 +1035,15 @@ static int arizona_calc_fll(struct arizona_fll *fll,
cfg->lambda = 0;
}
/* Round down to 16bit range with cost of accuracy lost.
* Denominator must be bigger than numerator so we only
* take care of it.
*/
while (cfg->lambda >= (1 << 16)) {
cfg->theta >>= 1;
cfg->lambda >>= 1;
}
arizona_fll_dbg(fll, "N=%x THETA=%x LAMBDA=%x\n",
cfg->n, cfg->theta, cfg->lambda);
arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n",
@@ -1057,7 +1179,6 @@ int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
{
int ret;
init_completion(&fll->lock);
init_completion(&fll->ok);
fll->id = id;
@@ -1068,13 +1189,6 @@ int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name),
"FLL%d clock OK", id);
ret = arizona_request_irq(arizona, lock_irq, fll->lock_name,
arizona_fll_lock, fll);
if (ret != 0) {
dev_err(arizona->dev, "Failed to get FLL%d lock IRQ: %d\n",
id, ret);
}
ret = arizona_request_irq(arizona, ok_irq, fll->clock_ok_name,
arizona_fll_clock_ok, fll);
if (ret != 0) {
@@ -1089,6 +1203,40 @@ int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
}
EXPORT_SYMBOL_GPL(arizona_init_fll);
/**
* arizona_set_output_mode - Set the mode of the specified output
*
* @codec: Device to configure
* @output: Output number
* @diff: True to set the output to differential mode
*
* Some systems use external analogue switches to connect more
* analogue devices to the CODEC than are supported by the device. In
* some systems this requires changing the switched output from single
* ended to differential mode dynamically at runtime, an operation
* supported using this function.
*
* Most systems have a single static configuration and should use
* platform data instead.
*/
int arizona_set_output_mode(struct snd_soc_codec *codec, int output, bool diff)
{
unsigned int reg, val;
if (output < 1 || output > 6)
return -EINVAL;
reg = ARIZONA_OUTPUT_PATH_CONFIG_1L + (output - 1) * 8;
if (diff)
val = ARIZONA_OUT1_MONO;
else
val = 0;
return snd_soc_update_bits(codec, reg, ARIZONA_OUT1_MONO, val);
}
EXPORT_SYMBOL_GPL(arizona_set_output_mode);
MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support");
MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
MODULE_LICENSE("GPL");

View File

@@ -66,7 +66,7 @@ struct arizona_priv {
struct arizona_dai_priv dai[ARIZONA_MAX_DAI];
};
#define ARIZONA_NUM_MIXER_INPUTS 75
#define ARIZONA_NUM_MIXER_INPUTS 99
extern const unsigned int arizona_mixer_tlv[];
extern const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS];
@@ -176,6 +176,8 @@ extern const struct soc_enum arizona_lhpf2_mode;
extern const struct soc_enum arizona_lhpf3_mode;
extern const struct soc_enum arizona_lhpf4_mode;
extern const struct soc_enum arizona_ng_hold;
extern int arizona_in_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol,
int event);
@@ -195,7 +197,6 @@ struct arizona_fll {
int id;
unsigned int base;
unsigned int vco_mult;
struct completion lock;
struct completion ok;
unsigned int fref;
unsigned int fout;
@@ -211,4 +212,7 @@ extern int arizona_set_fll(struct arizona_fll *fll, int source,
extern int arizona_init_dai(struct arizona_priv *priv, int dai);
int arizona_set_output_mode(struct snd_soc_codec *codec, int output,
bool diff);
#endif

View File

@@ -167,6 +167,8 @@ struct cs4271_private {
int gpio_nreset;
/* GPIO that disable serial bus, if any */
int gpio_disable;
/* enable soft reset workaround */
bool enable_soft_reset;
};
/*
@@ -325,6 +327,33 @@ static int cs4271_hw_params(struct snd_pcm_substream *substream,
int i, ret;
unsigned int ratio, val;
if (cs4271->enable_soft_reset) {
/*
* Put the codec in soft reset and back again in case it's not
* currently streaming data. This way of bringing the codec in
* sync to the current clocks is not explicitly documented in
* the data sheet, but it seems to work fine, and in contrast
* to a read hardware reset, we don't have to sync back all
* registers every time.
*/
if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
!dai->capture_active) ||
(substream->stream == SNDRV_PCM_STREAM_CAPTURE &&
!dai->playback_active)) {
ret = snd_soc_update_bits(codec, CS4271_MODE2,
CS4271_MODE2_PDN,
CS4271_MODE2_PDN);
if (ret < 0)
return ret;
ret = snd_soc_update_bits(codec, CS4271_MODE2,
CS4271_MODE2_PDN, 0);
if (ret < 0)
return ret;
}
}
cs4271->rate = params_rate(params);
/* Configure DAC */
@@ -484,6 +513,10 @@ static int cs4271_probe(struct snd_soc_codec *codec)
if (of_get_property(codec->dev->of_node,
"cirrus,amutec-eq-bmutec", NULL))
amutec_eq_bmutec = true;
if (of_get_property(codec->dev->of_node,
"cirrus,enable-soft-reset", NULL))
cs4271->enable_soft_reset = true;
}
#endif
@@ -492,6 +525,7 @@ static int cs4271_probe(struct snd_soc_codec *codec)
gpio_nreset = cs4271plat->gpio_nreset;
amutec_eq_bmutec = cs4271plat->amutec_eq_bmutec;
cs4271->enable_soft_reset = cs4271plat->enable_soft_reset;
}
if (gpio_nreset >= 0)

View File

@@ -1038,7 +1038,7 @@ static void cs42l52_init_beep(struct snd_soc_codec *codec)
struct cs42l52_private *cs42l52 = snd_soc_codec_get_drvdata(codec);
int ret;
cs42l52->beep = input_allocate_device();
cs42l52->beep = devm_input_allocate_device(codec->dev);
if (!cs42l52->beep) {
dev_err(codec->dev, "Failed to allocate beep device\n");
return;
@@ -1059,7 +1059,6 @@ static void cs42l52_init_beep(struct snd_soc_codec *codec)
ret = input_register_device(cs42l52->beep);
if (ret != 0) {
input_free_device(cs42l52->beep);
cs42l52->beep = NULL;
dev_err(codec->dev, "Failed to register beep device\n");
}
@@ -1076,7 +1075,6 @@ static void cs42l52_free_beep(struct snd_soc_codec *codec)
struct cs42l52_private *cs42l52 = snd_soc_codec_get_drvdata(codec);
device_remove_file(codec->dev, &dev_attr_beep);
input_unregister_device(cs42l52->beep);
cancel_work_sync(&cs42l52->beep_work);
cs42l52->beep = NULL;

1599
sound/soc/codecs/da7213.c Normal file

File diff suppressed because it is too large Load Diff

523
sound/soc/codecs/da7213.h Normal file
View File

@@ -0,0 +1,523 @@
/*
* da7213.h - DA7213 ASoC Codec Driver
*
* Copyright (c) 2013 Dialog Semiconductor
*
* Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _DA7213_H
#define _DA7213_H
#include <linux/regmap.h>
#include <sound/da7213.h>
/*
* Registers
*/
/* Status Registers */
#define DA7213_STATUS1 0x02
#define DA7213_PLL_STATUS 0x03
#define DA7213_AUX_L_GAIN_STATUS 0x04
#define DA7213_AUX_R_GAIN_STATUS 0x05
#define DA7213_MIC_1_GAIN_STATUS 0x06
#define DA7213_MIC_2_GAIN_STATUS 0x07
#define DA7213_MIXIN_L_GAIN_STATUS 0x08
#define DA7213_MIXIN_R_GAIN_STATUS 0x09
#define DA7213_ADC_L_GAIN_STATUS 0x0A
#define DA7213_ADC_R_GAIN_STATUS 0x0B
#define DA7213_DAC_L_GAIN_STATUS 0x0C
#define DA7213_DAC_R_GAIN_STATUS 0x0D
#define DA7213_HP_L_GAIN_STATUS 0x0E
#define DA7213_HP_R_GAIN_STATUS 0x0F
#define DA7213_LINE_GAIN_STATUS 0x10
/* System Initialisation Registers */
#define DA7213_DIG_ROUTING_DAI 0x21
#define DA7213_SR 0x22
#define DA7213_REFERENCES 0x23
#define DA7213_PLL_FRAC_TOP 0x24
#define DA7213_PLL_FRAC_BOT 0x25
#define DA7213_PLL_INTEGER 0x26
#define DA7213_PLL_CTRL 0x27
#define DA7213_DAI_CLK_MODE 0x28
#define DA7213_DAI_CTRL 0x29
#define DA7213_DIG_ROUTING_DAC 0x2A
#define DA7213_ALC_CTRL1 0x2B
/* Input - Gain, Select and Filter Registers */
#define DA7213_AUX_L_GAIN 0x30
#define DA7213_AUX_R_GAIN 0x31
#define DA7213_MIXIN_L_SELECT 0x32
#define DA7213_MIXIN_R_SELECT 0x33
#define DA7213_MIXIN_L_GAIN 0x34
#define DA7213_MIXIN_R_GAIN 0x35
#define DA7213_ADC_L_GAIN 0x36
#define DA7213_ADC_R_GAIN 0x37
#define DA7213_ADC_FILTERS1 0x38
#define DA7213_MIC_1_GAIN 0x39
#define DA7213_MIC_2_GAIN 0x3A
/* Output - Gain, Select and Filter Registers */
#define DA7213_DAC_FILTERS5 0x40
#define DA7213_DAC_FILTERS2 0x41
#define DA7213_DAC_FILTERS3 0x42
#define DA7213_DAC_FILTERS4 0x43
#define DA7213_DAC_FILTERS1 0x44
#define DA7213_DAC_L_GAIN 0x45
#define DA7213_DAC_R_GAIN 0x46
#define DA7213_CP_CTRL 0x47
#define DA7213_HP_L_GAIN 0x48
#define DA7213_HP_R_GAIN 0x49
#define DA7213_LINE_GAIN 0x4A
#define DA7213_MIXOUT_L_SELECT 0x4B
#define DA7213_MIXOUT_R_SELECT 0x4C
/* System Controller Registers */
#define DA7213_SYSTEM_MODES_INPUT 0x50
#define DA7213_SYSTEM_MODES_OUTPUT 0x51
/* Control Registers */
#define DA7213_AUX_L_CTRL 0x60
#define DA7213_AUX_R_CTRL 0x61
#define DA7213_MICBIAS_CTRL 0x62
#define DA7213_MIC_1_CTRL 0x63
#define DA7213_MIC_2_CTRL 0x64
#define DA7213_MIXIN_L_CTRL 0x65
#define DA7213_MIXIN_R_CTRL 0x66
#define DA7213_ADC_L_CTRL 0x67
#define DA7213_ADC_R_CTRL 0x68
#define DA7213_DAC_L_CTRL 0x69
#define DA7213_DAC_R_CTRL 0x6A
#define DA7213_HP_L_CTRL 0x6B
#define DA7213_HP_R_CTRL 0x6C
#define DA7213_LINE_CTRL 0x6D
#define DA7213_MIXOUT_L_CTRL 0x6E
#define DA7213_MIXOUT_R_CTRL 0x6F
/* Configuration Registers */
#define DA7213_LDO_CTRL 0x90
#define DA7213_IO_CTRL 0x91
#define DA7213_GAIN_RAMP_CTRL 0x92
#define DA7213_MIC_CONFIG 0x93
#define DA7213_PC_COUNT 0x94
#define DA7213_CP_VOL_THRESHOLD1 0x95
#define DA7213_CP_DELAY 0x96
#define DA7213_CP_DETECTOR 0x97
#define DA7213_DAI_OFFSET 0x98
#define DA7213_DIG_CTRL 0x99
#define DA7213_ALC_CTRL2 0x9A
#define DA7213_ALC_CTRL3 0x9B
#define DA7213_ALC_NOISE 0x9C
#define DA7213_ALC_TARGET_MIN 0x9D
#define DA7213_ALC_TARGET_MAX 0x9E
#define DA7213_ALC_GAIN_LIMITS 0x9F
#define DA7213_ALC_ANA_GAIN_LIMITS 0xA0
#define DA7213_ALC_ANTICLIP_CTRL 0xA1
#define DA7213_ALC_ANTICLIP_LEVEL 0xA2
#define DA7213_ALC_OFFSET_AUTO_M_L 0xA3
#define DA7213_ALC_OFFSET_AUTO_U_L 0xA4
#define DA7213_ALC_OFFSET_MAN_M_L 0xA6
#define DA7213_ALC_OFFSET_MAN_U_L 0xA7
#define DA7213_ALC_OFFSET_AUTO_M_R 0xA8
#define DA7213_ALC_OFFSET_AUTO_U_R 0xA9
#define DA7213_ALC_OFFSET_MAN_M_R 0xAB
#define DA7213_ALC_OFFSET_MAN_U_R 0xAC
#define DA7213_ALC_CIC_OP_LVL_CTRL 0xAD
#define DA7213_ALC_CIC_OP_LVL_DATA 0xAE
#define DA7213_DAC_NG_SETUP_TIME 0xAF
#define DA7213_DAC_NG_OFF_THRESHOLD 0xB0
#define DA7213_DAC_NG_ON_THRESHOLD 0xB1
#define DA7213_DAC_NG_CTRL 0xB2
/*
* Bit fields
*/
/* DA7213_SR = 0x22 */
#define DA7213_SR_8000 (0x1 << 0)
#define DA7213_SR_11025 (0x2 << 0)
#define DA7213_SR_12000 (0x3 << 0)
#define DA7213_SR_16000 (0x5 << 0)
#define DA7213_SR_22050 (0x6 << 0)
#define DA7213_SR_24000 (0x7 << 0)
#define DA7213_SR_32000 (0x9 << 0)
#define DA7213_SR_44100 (0xA << 0)
#define DA7213_SR_48000 (0xB << 0)
#define DA7213_SR_88200 (0xE << 0)
#define DA7213_SR_96000 (0xF << 0)
/* DA7213_REFERENCES = 0x23 */
#define DA7213_BIAS_EN (0x1 << 3)
#define DA7213_VMID_EN (0x1 << 7)
/* DA7213_PLL_CTRL = 0x27 */
#define DA7213_PLL_INDIV_5_10_MHZ (0x0 << 2)
#define DA7213_PLL_INDIV_10_20_MHZ (0x1 << 2)
#define DA7213_PLL_INDIV_20_40_MHZ (0x2 << 2)
#define DA7213_PLL_INDIV_40_54_MHZ (0x3 << 2)
#define DA7213_PLL_INDIV_MASK (0x3 << 2)
#define DA7213_PLL_MCLK_SQR_EN (0x1 << 4)
#define DA7213_PLL_32K_MODE (0x1 << 5)
#define DA7213_PLL_SRM_EN (0x1 << 6)
#define DA7213_PLL_EN (0x1 << 7)
/* DA7213_DAI_CLK_MODE = 0x28 */
#define DA7213_DAI_BCLKS_PER_WCLK_32 (0x0 << 0)
#define DA7213_DAI_BCLKS_PER_WCLK_64 (0x1 << 0)
#define DA7213_DAI_BCLKS_PER_WCLK_128 (0x2 << 0)
#define DA7213_DAI_BCLKS_PER_WCLK_256 (0x3 << 0)
#define DA7213_DAI_BCLKS_PER_WCLK_MASK (0x3 << 0)
#define DA7213_DAI_CLK_POL_INV (0x1 << 2)
#define DA7213_DAI_WCLK_POL_INV (0x1 << 3)
#define DA7213_DAI_CLK_EN_SLAVE_MODE (0x0 << 7)
#define DA7213_DAI_CLK_EN_MASTER_MODE (0x1 << 7)
#define DA7213_DAI_CLK_EN_MASK (0x1 << 7)
/* DA7213_DAI_CTRL = 0x29 */
#define DA7213_DAI_FORMAT_I2S_MODE (0x0 << 0)
#define DA7213_DAI_FORMAT_LEFT_J (0x1 << 0)
#define DA7213_DAI_FORMAT_RIGHT_J (0x2 << 0)
#define DA7213_DAI_FORMAT_MASK (0x3 << 0)
#define DA7213_DAI_WORD_LENGTH_S16_LE (0x0 << 2)
#define DA7213_DAI_WORD_LENGTH_S20_LE (0x1 << 2)
#define DA7213_DAI_WORD_LENGTH_S24_LE (0x2 << 2)
#define DA7213_DAI_WORD_LENGTH_S32_LE (0x3 << 2)
#define DA7213_DAI_WORD_LENGTH_MASK (0x3 << 2)
#define DA7213_DAI_EN_SHIFT 7
/* DA7213_DIG_ROUTING_DAI = 0x21 */
#define DA7213_DAI_L_SRC_SHIFT 0
#define DA7213_DAI_R_SRC_SHIFT 4
#define DA7213_DAI_SRC_MAX 4
/* DA7213_DIG_ROUTING_DAC = 0x2A */
#define DA7213_DAC_L_SRC_SHIFT 0
#define DA7213_DAC_L_MONO_SHIFT 3
#define DA7213_DAC_R_SRC_SHIFT 4
#define DA7213_DAC_R_MONO_SHIFT 7
#define DA7213_DAC_SRC_MAX 4
#define DA7213_DAC_MONO_MAX 0x1
/* DA7213_ALC_CTRL1 = 0x2B */
#define DA7213_ALC_OFFSET_EN_SHIFT 0
#define DA7213_ALC_OFFSET_EN_MAX 0x1
#define DA7213_ALC_OFFSET_EN (0x1 << 0)
#define DA7213_ALC_SYNC_MODE (0x1 << 1)
#define DA7213_ALC_CALIB_MODE_MAN (0x1 << 2)
#define DA7213_ALC_L_EN_SHIFT 3
#define DA7213_ALC_AUTO_CALIB_EN (0x1 << 4)
#define DA7213_ALC_CALIB_OVERFLOW (0x1 << 5)
#define DA7213_ALC_R_EN_SHIFT 7
#define DA7213_ALC_EN_MAX 0x1
/* DA7213_AUX_L/R_GAIN = 0x30/0x31 */
#define DA7213_AUX_AMP_GAIN_SHIFT 0
#define DA7213_AUX_AMP_GAIN_MAX 0x3F
/* DA7213_MIXIN_L/R_SELECT = 0x32/0x33 */
#define DA7213_DMIC_EN_SHIFT 7
#define DA7213_DMIC_EN_MAX 0x1
/* DA7213_MIXIN_L_SELECT = 0x32 */
#define DA7213_MIXIN_L_MIX_SELECT_AUX_L_SHIFT 0
#define DA7213_MIXIN_L_MIX_SELECT_MIC_1_SHIFT 1
#define DA7213_MIXIN_L_MIX_SELECT_MIC_1 (0x1 << 1)
#define DA7213_MIXIN_L_MIX_SELECT_MIC_2_SHIFT 2
#define DA7213_MIXIN_L_MIX_SELECT_MIC_2 (0x1 << 2)
#define DA7213_MIXIN_L_MIX_SELECT_MIXIN_R_SHIFT 3
#define DA7213_MIXIN_L_MIX_SELECT_MAX 0x1
/* DA7213_MIXIN_R_SELECT = 0x33 */
#define DA7213_MIXIN_R_MIX_SELECT_AUX_R_SHIFT 0
#define DA7213_MIXIN_R_MIX_SELECT_MIC_2_SHIFT 1
#define DA7213_MIXIN_R_MIX_SELECT_MIC_2 (0x1 << 1)
#define DA7213_MIXIN_R_MIX_SELECT_MIC_1_SHIFT 2
#define DA7213_MIXIN_R_MIX_SELECT_MIC_1 (0x1 << 2)
#define DA7213_MIXIN_R_MIX_SELECT_MIXIN_L_SHIFT 3
#define DA7213_MIXIN_R_MIX_SELECT_MAX 0x1
#define DA7213_MIC_BIAS_OUTPUT_SELECT_2 (0x1 << 6)
/* DA7213_MIXIN_L/R_GAIN = 0x34/0x35 */
#define DA7213_MIXIN_AMP_GAIN_SHIFT 0
#define DA7213_MIXIN_AMP_GAIN_MAX 0xF
/* DA7213_ADC_L/R_GAIN = 0x36/0x37 */
#define DA7213_ADC_AMP_GAIN_SHIFT 0
#define DA7213_ADC_AMP_GAIN_MAX 0x7F
/* DA7213_ADC/DAC_FILTERS1 = 0x38/0x44 */
#define DA7213_VOICE_HPF_CORNER_SHIFT 0
#define DA7213_VOICE_HPF_CORNER_MAX 8
#define DA7213_VOICE_EN_SHIFT 3
#define DA7213_VOICE_EN_MAX 0x1
#define DA7213_AUDIO_HPF_CORNER_SHIFT 4
#define DA7213_AUDIO_HPF_CORNER_MAX 4
#define DA7213_HPF_EN_SHIFT 7
#define DA7213_HPF_EN_MAX 0x1
/* DA7213_MIC_1/2_GAIN = 0x39/0x3A */
#define DA7213_MIC_AMP_GAIN_SHIFT 0
#define DA7213_MIC_AMP_GAIN_MAX 0x7
/* DA7213_DAC_FILTERS5 = 0x40 */
#define DA7213_DAC_SOFTMUTE_EN_SHIFT 7
#define DA7213_DAC_SOFTMUTE_EN_MAX 0x1
#define DA7213_DAC_SOFTMUTE_RATE_SHIFT 4
#define DA7213_DAC_SOFTMUTE_RATE_MAX 7
/* DA7213_DAC_FILTERS2/3/4 = 0x41/0x42/0x43 */
#define DA7213_DAC_EQ_BAND_MAX 0xF
/* DA7213_DAC_FILTERS2 = 0x41 */
#define DA7213_DAC_EQ_BAND1_SHIFT 0
#define DA7213_DAC_EQ_BAND2_SHIFT 4
/* DA7213_DAC_FILTERS2 = 0x42 */
#define DA7213_DAC_EQ_BAND3_SHIFT 0
#define DA7213_DAC_EQ_BAND4_SHIFT 4
/* DA7213_DAC_FILTERS4 = 0x43 */
#define DA7213_DAC_EQ_BAND5_SHIFT 0
#define DA7213_DAC_EQ_EN_SHIFT 7
#define DA7213_DAC_EQ_EN_MAX 0x1
/* DA7213_DAC_L/R_GAIN = 0x45/0x46 */
#define DA7213_DAC_AMP_GAIN_SHIFT 0
#define DA7213_DAC_AMP_GAIN_MAX 0x7F
/* DA7213_HP_L/R_GAIN = 0x45/0x46 */
#define DA7213_HP_AMP_GAIN_SHIFT 0
#define DA7213_HP_AMP_GAIN_MAX 0x3F
/* DA7213_CP_CTRL = 0x47 */
#define DA7213_CP_EN_SHIFT 7
/* DA7213_LINE_GAIN = 0x4A */
#define DA7213_LINE_AMP_GAIN_SHIFT 0
#define DA7213_LINE_AMP_GAIN_MAX 0x3F
/* DA7213_MIXOUT_L_SELECT = 0x4B */
#define DA7213_MIXOUT_L_MIX_SELECT_AUX_L_SHIFT 0
#define DA7213_MIXOUT_L_MIX_SELECT_MIXIN_L_SHIFT 1
#define DA7213_MIXOUT_L_MIX_SELECT_MIXIN_R_SHIFT 2
#define DA7213_MIXOUT_L_MIX_SELECT_DAC_L_SHIFT 3
#define DA7213_MIXOUT_L_MIX_SELECT_AUX_L_INVERTED_SHIFT 4
#define DA7213_MIXOUT_L_MIX_SELECT_MIXIN_L_INVERTED_SHIFT 5
#define DA7213_MIXOUT_L_MIX_SELECT_MIXIN_R_INVERTED_SHIFT 6
#define DA7213_MIXOUT_L_MIX_SELECT_MAX 0x1
/* DA7213_MIXOUT_R_SELECT = 0x4C */
#define DA7213_MIXOUT_R_MIX_SELECT_AUX_R_SHIFT 0
#define DA7213_MIXOUT_R_MIX_SELECT_MIXIN_R_SHIFT 1
#define DA7213_MIXOUT_R_MIX_SELECT_MIXIN_L_SHIFT 2
#define DA7213_MIXOUT_R_MIX_SELECT_DAC_R_SHIFT 3
#define DA7213_MIXOUT_R_MIX_SELECT_AUX_R_INVERTED_SHIFT 4
#define DA7213_MIXOUT_R_MIX_SELECT_MIXIN_R_INVERTED_SHIFT 5
#define DA7213_MIXOUT_R_MIX_SELECT_MIXIN_L_INVERTED_SHIFT 6
#define DA7213_MIXOUT_R_MIX_SELECT_MAX 0x1
/*
* DA7213_AUX_L/R_CTRL = 0x60/0x61,
* DA7213_MIC_1/2_CTRL = 0x63/0x64,
* DA7213_MIXIN_L/R_CTRL = 0x65/0x66,
* DA7213_ADC_L/R_CTRL = 0x65/0x66,
* DA7213_DAC_L/R_CTRL = 0x69/0x6A,
* DA7213_HP_L/R_CTRL = 0x6B/0x6C,
* DA7213_LINE_CTRL = 0x6D
*/
#define DA7213_MUTE_EN_SHIFT 6
#define DA7213_MUTE_EN_MAX 0x1
#define DA7213_MUTE_EN (0x1 << 6)
/*
* DA7213_AUX_L/R_CTRL = 0x60/0x61,
* DA7213_MIXIN_L/R_CTRL = 0x65/0x66,
* DA7213_ADC_L/R_CTRL = 0x65/0x66,
* DA7213_DAC_L/R_CTRL = 0x69/0x6A,
* DA7213_HP_L/R_CTRL = 0x6B/0x6C,
* DA7213_LINE_CTRL = 0x6D
*/
#define DA7213_GAIN_RAMP_EN_SHIFT 5
#define DA7213_GAIN_RAMP_EN_MAX 0x1
#define DA7213_GAIN_RAMP_EN (0x1 << 5)
/*
* DA7213_AUX_L/R_CTRL = 0x60/0x61,
* DA7213_MIXIN_L/R_CTRL = 0x65/0x66,
* DA7213_HP_L/R_CTRL = 0x6B/0x6C,
* DA7213_LINE_CTRL = 0x6D
*/
#define DA7213_ZC_EN_SHIFT 4
#define DA7213_ZC_EN_MAX 0x1
/*
* DA7213_AUX_L/R_CTRL = 0x60/0x61,
* DA7213_MIC_1/2_CTRL = 0x63/0x64,
* DA7213_MIXIN_L/R_CTRL = 0x65/0x66,
* DA7213_HP_L/R_CTRL = 0x6B/0x6C,
* DA7213_MIXOUT_L/R_CTRL = 0x6E/0x6F,
* DA7213_LINE_CTRL = 0x6D
*/
#define DA7213_AMP_EN_SHIFT 7
/* DA7213_MIC_1/2_CTRL = 0x63/0x64 */
#define DA7213_MIC_AMP_IN_SEL_SHIFT 2
#define DA7213_MIC_AMP_IN_SEL_MAX 3
/* DA7213_MICBIAS_CTRL = 0x62 */
#define DA7213_MICBIAS1_LEVEL_SHIFT 0
#define DA7213_MICBIAS1_LEVEL_MASK (0x3 << 0)
#define DA7213_MICBIAS1_EN_SHIFT 3
#define DA7213_MICBIAS2_LEVEL_SHIFT 4
#define DA7213_MICBIAS2_LEVEL_MASK (0x3 << 4)
#define DA7213_MICBIAS2_EN_SHIFT 7
/* DA7213_MIXIN_L/R_CTRL = 0x65/0x66 */
#define DA7213_MIXIN_MIX_EN (0x1 << 3)
/* DA7213_ADC_L/R_CTRL = 0x67/0x68 */
#define DA7213_ADC_EN_SHIFT 7
#define DA7213_ADC_EN (0x1 << 7)
/* DA7213_DAC_L/R_CTRL = 0x69/0x6A*/
#define DA7213_DAC_EN_SHIFT 7
/* DA7213_HP_L/R_CTRL = 0x6B/0x6C */
#define DA7213_HP_AMP_OE (0x1 << 3)
/* DA7213_LINE_CTRL = 0x6D */
#define DA7213_LINE_AMP_OE (0x1 << 3)
/* DA7213_MIXOUT_L/R_CTRL = 0x6E/0x6F */
#define DA7213_MIXOUT_MIX_EN (0x1 << 3)
/* DA7213_GAIN_RAMP_CTRL = 0x92 */
#define DA7213_GAIN_RAMP_RATE_SHIFT 0
#define DA7213_GAIN_RAMP_RATE_MAX 4
/* DA7213_MIC_CONFIG = 0x93 */
#define DA7213_DMIC_DATA_SEL_SHIFT 0
#define DA7213_DMIC_DATA_SEL_MASK (0x1 << 0)
#define DA7213_DMIC_SAMPLEPHASE_SHIFT 1
#define DA7213_DMIC_SAMPLEPHASE_MASK (0x1 << 1)
#define DA7213_DMIC_CLK_RATE_SHIFT 2
#define DA7213_DMIC_CLK_RATE_MASK (0x1 << 2)
/* DA7213_DIG_CTRL = 0x99 */
#define DA7213_DAC_L_INV_SHIFT 3
#define DA7213_DAC_R_INV_SHIFT 7
#define DA7213_DAC_INV_MAX 0x1
/* DA7213_ALC_CTRL2 = 0x9A */
#define DA7213_ALC_ATTACK_SHIFT 0
#define DA7213_ALC_ATTACK_MAX 13
#define DA7213_ALC_RELEASE_SHIFT 4
#define DA7213_ALC_RELEASE_MAX 11
/* DA7213_ALC_CTRL3 = 0x9B */
#define DA7213_ALC_HOLD_SHIFT 0
#define DA7213_ALC_HOLD_MAX 16
#define DA7213_ALC_INTEG_ATTACK_SHIFT 4
#define DA7213_ALC_INTEG_RELEASE_SHIFT 6
#define DA7213_ALC_INTEG_MAX 4
/*
* DA7213_ALC_NOISE = 0x9C,
* DA7213_ALC_TARGET_MIN/MAX = 0x9D/0x9E
*/
#define DA7213_ALC_THRESHOLD_SHIFT 0
#define DA7213_ALC_THRESHOLD_MAX 0x3F
/* DA7213_ALC_GAIN_LIMITS = 0x9F */
#define DA7213_ALC_ATTEN_MAX_SHIFT 0
#define DA7213_ALC_GAIN_MAX_SHIFT 4
#define DA7213_ALC_ATTEN_GAIN_MAX_MAX 0xF
/* DA7213_ALC_ANA_GAIN_LIMITS = 0xA0 */
#define DA7213_ALC_ANA_GAIN_MIN_SHIFT 0
#define DA7213_ALC_ANA_GAIN_MAX_SHIFT 4
#define DA7213_ALC_ANA_GAIN_MAX 0x7
/* DA7213_ALC_ANTICLIP_CTRL = 0xA1 */
#define DA7213_ALC_ANTICLIP_EN_SHIFT 7
#define DA7213_ALC_ANTICLIP_EN_MAX 0x1
/* DA7213_ALC_ANTICLIP_LEVEL = 0xA2 */
#define DA7213_ALC_ANTICLIP_LEVEL_SHIFT 0
#define DA7213_ALC_ANTICLIP_LEVEL_MAX 0x7F
/* DA7213_ALC_CIC_OP_LVL_CTRL = 0xAD */
#define DA7213_ALC_DATA_MIDDLE (0x2 << 0)
#define DA7213_ALC_DATA_TOP (0x3 << 0)
#define DA7213_ALC_CIC_OP_CHANNEL_LEFT (0x0 << 7)
#define DA7213_ALC_CIC_OP_CHANNEL_RIGHT (0x1 << 7)
/* DA7213_DAC_NG_SETUP_TIME = 0xAF */
#define DA7213_DAC_NG_SETUP_TIME_SHIFT 0
#define DA7213_DAC_NG_SETUP_TIME_MAX 4
#define DA7213_DAC_NG_RAMPUP_RATE_SHIFT 2
#define DA7213_DAC_NG_RAMPDN_RATE_SHIFT 3
#define DA7213_DAC_NG_RAMP_RATE_MAX 2
/* DA7213_DAC_NG_OFF/ON_THRESH = 0xB0/0xB1 */
#define DA7213_DAC_NG_THRESHOLD_SHIFT 0
#define DA7213_DAC_NG_THRESHOLD_MAX 0x7
/* DA7213_DAC_NG_CTRL = 0xB2 */
#define DA7213_DAC_NG_EN_SHIFT 7
#define DA7213_DAC_NG_EN_MAX 0x1
/*
* General defines
*/
/* Register inversion */
#define DA7213_NO_INVERT 0
#define DA7213_INVERT 1
/* Byte related defines */
#define DA7213_BYTE_SHIFT 8
#define DA7213_BYTE_MASK 0xFF
/* ALC related */
#define DA7213_ALC_OFFSET_15_8 0x00FF00
#define DA7213_ALC_OFFSET_19_16 0x0F0000
#define DA7213_ALC_AVG_ITERATIONS 5
/* PLL related */
#define DA7213_SYSCLK_MCLK 0
#define DA7213_SYSCLK_PLL 1
#define DA7213_PLL_FREQ_OUT_90316800 90316800
#define DA7213_PLL_FREQ_OUT_98304000 98304000
#define DA7213_PLL_FREQ_OUT_94310400 94310400
#define DA7213_PLL_INDIV_5_10_MHZ_VAL 2
#define DA7213_PLL_INDIV_10_20_MHZ_VAL 4
#define DA7213_PLL_INDIV_20_40_MHZ_VAL 8
#define DA7213_PLL_INDIV_40_54_MHZ_VAL 16
enum clk_src {
DA7213_CLKSRC_MCLK
};
/* Codec private data */
struct da7213_priv {
struct regmap *regmap;
unsigned int mclk_rate;
bool master;
bool mclk_squarer_en;
bool srm_en;
bool alc_calib_auto;
bool alc_en;
struct da7213_platform_data *pdata;
};
#endif /* _DA7213_H */

2673
sound/soc/codecs/max98090.c Normal file → Executable file

File diff suppressed because it is too large Load Diff

1549
sound/soc/codecs/max98090.h Executable file

File diff suppressed because it is too large Load Diff

View File

@@ -85,6 +85,9 @@ struct aic3x_priv {
#define AIC3X_MODEL_33 1
#define AIC3X_MODEL_3007 2
u16 model;
/* Selects the micbias voltage */
enum aic3x_micbias_voltage micbias_vg;
};
/*
@@ -195,6 +198,37 @@ static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol,
return ret;
}
/*
* mic bias power on/off share the same register bits with
* output voltage of mic bias. when power on mic bias, we
* need reclaim it to voltage value.
* 0x0 = Powered off
* 0x1 = MICBIAS output is powered to 2.0V,
* 0x2 = MICBIAS output is powered to 2.5V
* 0x3 = MICBIAS output is connected to AVDD
*/
static int mic_bias_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
switch (event) {
case SND_SOC_DAPM_POST_PMU:
/* change mic bias voltage to user defined */
snd_soc_update_bits(codec, MICBIAS_CTRL,
MICBIAS_LEVEL_MASK,
aic3x->micbias_vg << MICBIAS_LEVEL_SHIFT);
break;
case SND_SOC_DAPM_PRE_PMD:
snd_soc_update_bits(codec, MICBIAS_CTRL,
MICBIAS_LEVEL_MASK, 0);
break;
}
return 0;
}
static const char *aic3x_left_dac_mux[] = { "DAC_L1", "DAC_L3", "DAC_L2" };
static const char *aic3x_right_dac_mux[] = { "DAC_R1", "DAC_R3", "DAC_R2" };
static const char *aic3x_left_hpcom_mux[] =
@@ -596,12 +630,9 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
AIC3X_ASD_INTF_CTRLA, 0, 3, 3, 0),
/* Mic Bias */
SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "Mic Bias 2V",
MICBIAS_CTRL, 6, 3, 1, 0),
SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "Mic Bias 2.5V",
MICBIAS_CTRL, 6, 3, 2, 0),
SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "Mic Bias AVDD",
MICBIAS_CTRL, 6, 3, 3, 0),
SND_SOC_DAPM_SUPPLY("Mic Bias", MICBIAS_CTRL, 6, 0,
mic_bias_event,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
/* Output mixers */
SND_SOC_DAPM_MIXER("Left Line Mixer", SND_SOC_NOPM, 0, 0,
@@ -1210,13 +1241,13 @@ static struct snd_soc_dai_driver aic3x_dai = {
.name = "tlv320aic3x-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
.channels_min = 2,
.channels_max = 2,
.rates = AIC3X_RATES,
.formats = AIC3X_FORMATS,},
.capture = {
.stream_name = "Capture",
.channels_min = 1,
.channels_min = 2,
.channels_max = 2,
.rates = AIC3X_RATES,
.formats = AIC3X_FORMATS,},
@@ -1386,6 +1417,24 @@ static int aic3x_probe(struct snd_soc_codec *codec)
if (aic3x->model == AIC3X_MODEL_3007)
snd_soc_add_codec_controls(codec, &aic3x_classd_amp_gain_ctrl, 1);
/* set mic bias voltage */
switch (aic3x->micbias_vg) {
case AIC3X_MICBIAS_2_0V:
case AIC3X_MICBIAS_2_5V:
case AIC3X_MICBIAS_AVDDV:
snd_soc_update_bits(codec, MICBIAS_CTRL,
MICBIAS_LEVEL_MASK,
(aic3x->micbias_vg) << MICBIAS_LEVEL_SHIFT);
break;
case AIC3X_MICBIAS_OFF:
/*
* noting to do. target won't enter here. This is just to avoid
* compile time warning "warning: enumeration value
* 'AIC3X_MICBIAS_OFF' not handled in switch"
*/
break;
}
aic3x_add_widgets(codec);
list_add(&aic3x->list, &reset_list);
@@ -1461,6 +1510,7 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
struct aic3x_setup_data *ai3x_setup;
struct device_node *np = i2c->dev.of_node;
int ret;
u32 value;
aic3x = devm_kzalloc(&i2c->dev, sizeof(struct aic3x_priv), GFP_KERNEL);
if (aic3x == NULL) {
@@ -1474,6 +1524,7 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
if (pdata) {
aic3x->gpio_reset = pdata->gpio_reset;
aic3x->setup = pdata->setup;
aic3x->micbias_vg = pdata->micbias_vg;
} else if (np) {
ai3x_setup = devm_kzalloc(&i2c->dev, sizeof(*ai3x_setup),
GFP_KERNEL);
@@ -1493,6 +1544,26 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
aic3x->setup = ai3x_setup;
}
if (!of_property_read_u32(np, "ai3x-micbias-vg", &value)) {
switch (value) {
case 1 :
aic3x->micbias_vg = AIC3X_MICBIAS_2_0V;
break;
case 2 :
aic3x->micbias_vg = AIC3X_MICBIAS_2_5V;
break;
case 3 :
aic3x->micbias_vg = AIC3X_MICBIAS_AVDDV;
break;
default :
aic3x->micbias_vg = AIC3X_MICBIAS_OFF;
dev_err(&i2c->dev, "Unsuitable MicBias voltage "
"found in DT\n");
}
} else {
aic3x->micbias_vg = AIC3X_MICBIAS_OFF;
}
} else {
aic3x->gpio_reset = -1;
}

View File

@@ -238,6 +238,10 @@
/* Default input volume */
#define DEFAULT_GAIN 0x20
/* MICBIAS Control Register */
#define MICBIAS_LEVEL_SHIFT (6)
#define MICBIAS_LEVEL_MASK (3 << 6)
/* headset detection / button API */
/* The AIC3x supports detection of stereo headsets (GND + left + right signal)

View File

@@ -1452,20 +1452,6 @@ static int dac33_soc_remove(struct snd_soc_codec *codec)
return 0;
}
static int dac33_soc_suspend(struct snd_soc_codec *codec)
{
dac33_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
static int dac33_soc_resume(struct snd_soc_codec *codec)
{
dac33_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
}
static struct snd_soc_codec_driver soc_codec_dev_tlv320dac33 = {
.read = dac33_read_reg_cache,
.write = dac33_write_locked,
@@ -1476,8 +1462,6 @@ static struct snd_soc_codec_driver soc_codec_dev_tlv320dac33 = {
.reg_cache_default = dac33_reg,
.probe = dac33_soc_probe,
.remove = dac33_soc_remove,
.suspend = dac33_soc_suspend,
.resume = dac33_soc_resume,
.controls = dac33_snd_controls,
.num_controls = ARRAY_SIZE(dac33_snd_controls),

View File

@@ -41,6 +41,11 @@
/* Register descriptions are here */
#include <linux/mfd/twl4030-audio.h>
/* TWL4030 PMBR1 Register */
#define TWL4030_PMBR1_REG 0x0D
/* TWL4030 PMBR1 Register GPIO6 mux bits */
#define TWL4030_GPIO6_PWM0_MUTE(value) ((value & 0x03) << 2)
/* Shadow register used by the audio driver */
#define TWL4030_REG_SW_SHADOW 0x4A
#define TWL4030_CACHEREGNUM (TWL4030_REG_SW_SHADOW + 1)
@@ -348,19 +353,32 @@ static void twl4030_init_chip(struct snd_soc_codec *codec)
pdata = twl4030_get_pdata(codec);
if (pdata && pdata->hs_extmute &&
gpio_is_valid(pdata->hs_extmute_gpio)) {
int ret;
if (pdata && pdata->hs_extmute) {
if (gpio_is_valid(pdata->hs_extmute_gpio)) {
int ret;
if (!pdata->hs_extmute_gpio)
dev_warn(codec->dev,
"Extmute GPIO is 0 is this correct?\n");
if (!pdata->hs_extmute_gpio)
dev_warn(codec->dev,
"Extmute GPIO is 0 is this correct?\n");
ret = gpio_request_one(pdata->hs_extmute_gpio,
GPIOF_OUT_INIT_LOW, "hs_extmute");
if (ret) {
dev_err(codec->dev, "Failed to get hs_extmute GPIO\n");
pdata->hs_extmute_gpio = -1;
ret = gpio_request_one(pdata->hs_extmute_gpio,
GPIOF_OUT_INIT_LOW,
"hs_extmute");
if (ret) {
dev_err(codec->dev,
"Failed to get hs_extmute GPIO\n");
pdata->hs_extmute_gpio = -1;
}
} else {
u8 pin_mux;
/* Set TWL4030 GPIO6 as EXTMUTE signal */
twl_i2c_read_u8(TWL4030_MODULE_INTBR, &pin_mux,
TWL4030_PMBR1_REG);
pin_mux &= ~TWL4030_GPIO6_PWM0_MUTE(0x03);
pin_mux |= TWL4030_GPIO6_PWM0_MUTE(0x02);
twl_i2c_write_u8(TWL4030_MODULE_INTBR, pin_mux,
TWL4030_PMBR1_REG);
}
}
@@ -1306,6 +1324,9 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
SND_SOC_DAPM_DAC("DAC Left2", NULL, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_DAC("DAC Voice", NULL, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_IN("VAIFIN", "Voice Playback", 0,
TWL4030_REG_VOICE_IF, 6, 0),
/* Analog bypasses */
SND_SOC_DAPM_SWITCH("Right1 Analog Loopback", SND_SOC_NOPM, 0, 0,
&twl4030_dapm_abypassr1_control),
@@ -1438,6 +1459,9 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
SND_SOC_DAPM_ADC("ADC Virtual Left2", NULL, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_ADC("ADC Virtual Right2", NULL, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_OUT("VAIFOUT", "Voice Capture", 0,
TWL4030_REG_VOICE_IF, 5, 0),
/* Analog/Digital mic path selection.
TX1 Left/Right: either analog Left/Right or Digimic0
TX2 Left/Right: either analog Left/Right or Digimic1 */
@@ -1473,10 +1497,15 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("micbias2 select", TWL4030_REG_MICBIAS_CTL, 6, 0,
NULL, 0),
SND_SOC_DAPM_MICBIAS("Mic Bias 1", TWL4030_REG_MICBIAS_CTL, 0, 0),
SND_SOC_DAPM_MICBIAS("Mic Bias 2", TWL4030_REG_MICBIAS_CTL, 1, 0),
SND_SOC_DAPM_MICBIAS("Headset Mic Bias", TWL4030_REG_MICBIAS_CTL, 2, 0),
/* Microphone bias */
SND_SOC_DAPM_SUPPLY("Mic Bias 1",
TWL4030_REG_MICBIAS_CTL, 0, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("Mic Bias 2",
TWL4030_REG_MICBIAS_CTL, 1, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("Headset Mic Bias",
TWL4030_REG_MICBIAS_CTL, 2, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("VIF Enable", TWL4030_REG_VOICE_IF, 0, 0, NULL, 0),
};
static const struct snd_soc_dapm_route intercon[] = {
@@ -1485,17 +1514,16 @@ static const struct snd_soc_dapm_route intercon[] = {
{"DAC Left1", NULL, "HiFi Playback"},
{"DAC Right2", NULL, "HiFi Playback"},
{"DAC Left2", NULL, "HiFi Playback"},
{"DAC Voice", NULL, "Voice Playback"},
{"DAC Voice", NULL, "VAIFIN"},
/* ADC -> Stream mapping */
{"HiFi Capture", NULL, "ADC Virtual Left1"},
{"HiFi Capture", NULL, "ADC Virtual Right1"},
{"HiFi Capture", NULL, "ADC Virtual Left2"},
{"HiFi Capture", NULL, "ADC Virtual Right2"},
{"Voice Capture", NULL, "ADC Virtual Left1"},
{"Voice Capture", NULL, "ADC Virtual Right1"},
{"Voice Capture", NULL, "ADC Virtual Left2"},
{"Voice Capture", NULL, "ADC Virtual Right2"},
{"VAIFOUT", NULL, "ADC Virtual Left2"},
{"VAIFOUT", NULL, "ADC Virtual Right2"},
{"VAIFOUT", NULL, "VIF Enable"},
{"Digital L1 Playback Mixer", NULL, "DAC Left1"},
{"Digital R1 Playback Mixer", NULL, "DAC Right1"},
@@ -1510,6 +1538,7 @@ static const struct snd_soc_dapm_route intercon[] = {
{"DAC Right1", NULL, "AIF Enable"},
{"DAC Left2", NULL, "AIF Enable"},
{"DAC Right1", NULL, "AIF Enable"},
{"DAC Voice", NULL, "VIF Enable"},
{"Digital R2 Playback Mixer", NULL, "AIF Enable"},
{"Digital L2 Playback Mixer", NULL, "AIF Enable"},
@@ -2267,18 +2296,6 @@ static struct snd_soc_dai_driver twl4030_dai[] = {
},
};
static int twl4030_soc_suspend(struct snd_soc_codec *codec)
{
twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
static int twl4030_soc_resume(struct snd_soc_codec *codec)
{
twl4030_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
}
static int twl4030_soc_probe(struct snd_soc_codec *codec)
{
struct twl4030_priv *twl4030;
@@ -2316,8 +2333,6 @@ static int twl4030_soc_remove(struct snd_soc_codec *codec)
static struct snd_soc_codec_driver soc_codec_dev_twl4030 = {
.probe = twl4030_soc_probe,
.remove = twl4030_soc_remove,
.suspend = twl4030_soc_suspend,
.resume = twl4030_soc_resume,
.read = twl4030_read_reg_cache,
.write = twl4030_write,
.set_bias_level = twl4030_set_bias_level,

View File

@@ -69,13 +69,8 @@ struct twl6040_data {
int hs_power_mode_locked;
unsigned int clk_in;
unsigned int sysclk;
u16 hs_left_step;
u16 hs_right_step;
u16 hf_left_step;
u16 hf_right_step;
struct twl6040_jack_data hs_jack;
struct snd_soc_codec *codec;
struct workqueue_struct *workqueue;
struct mutex mutex;
};
@@ -404,8 +399,7 @@ static irqreturn_t twl6040_audio_handler(int irq, void *data)
struct snd_soc_codec *codec = data;
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
queue_delayed_work(priv->workqueue, &priv->hs_jack.work,
msecs_to_jiffies(200));
schedule_delayed_work(&priv->hs_jack.work, msecs_to_jiffies(200));
return IRQ_HANDLED;
}
@@ -1115,7 +1109,6 @@ static int twl6040_suspend(struct snd_soc_codec *codec)
static int twl6040_resume(struct snd_soc_codec *codec)
{
twl6040_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
twl6040_set_bias_level(codec, codec->dapm.suspend_bias_level);
return 0;
}
@@ -1127,83 +1120,46 @@ static int twl6040_resume(struct snd_soc_codec *codec)
static int twl6040_probe(struct snd_soc_codec *codec)
{
struct twl6040_data *priv;
struct twl6040_codec_data *pdata = dev_get_platdata(codec->dev);
struct platform_device *pdev = container_of(codec->dev,
struct platform_device, dev);
int ret = 0;
priv = kzalloc(sizeof(struct twl6040_data), GFP_KERNEL);
priv = devm_kzalloc(codec->dev, sizeof(*priv), GFP_KERNEL);
if (priv == NULL)
return -ENOMEM;
snd_soc_codec_set_drvdata(codec, priv);
priv->codec = codec;
codec->control_data = dev_get_drvdata(codec->dev->parent);
if (pdata && pdata->hs_left_step && pdata->hs_right_step) {
priv->hs_left_step = pdata->hs_left_step;
priv->hs_right_step = pdata->hs_right_step;
} else {
priv->hs_left_step = 1;
priv->hs_right_step = 1;
}
if (pdata && pdata->hf_left_step && pdata->hf_right_step) {
priv->hf_left_step = pdata->hf_left_step;
priv->hf_right_step = pdata->hf_right_step;
} else {
priv->hf_left_step = 1;
priv->hf_right_step = 1;
}
priv->plug_irq = platform_get_irq(pdev, 0);
if (priv->plug_irq < 0) {
dev_err(codec->dev, "invalid irq\n");
ret = -EINVAL;
goto work_err;
}
priv->workqueue = alloc_workqueue("twl6040-codec", 0, 0);
if (!priv->workqueue) {
ret = -ENOMEM;
goto work_err;
return -EINVAL;
}
INIT_DELAYED_WORK(&priv->hs_jack.work, twl6040_accessory_work);
mutex_init(&priv->mutex);
ret = request_threaded_irq(priv->plug_irq, NULL, twl6040_audio_handler,
0, "twl6040_irq_plug", codec);
ret = devm_request_threaded_irq(codec->dev, priv->plug_irq, NULL,
twl6040_audio_handler, IRQF_NO_SUSPEND,
"twl6040_irq_plug", codec);
if (ret) {
dev_err(codec->dev, "PLUG IRQ request failed: %d\n", ret);
goto plugirq_err;
return ret;
}
twl6040_init_chip(codec);
/* power on device */
ret = twl6040_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
if (!ret)
return 0;
/* Error path */
free_irq(priv->plug_irq, codec);
plugirq_err:
destroy_workqueue(priv->workqueue);
work_err:
kfree(priv);
return ret;
return twl6040_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
}
static int twl6040_remove(struct snd_soc_codec *codec)
{
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
twl6040_set_bias_level(codec, SND_SOC_BIAS_OFF);
free_irq(priv->plug_irq, codec);
destroy_workqueue(priv->workqueue);
kfree(priv);
return 0;
}

View File

@@ -26,6 +26,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/firmware.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/i2c.h>
@@ -62,6 +63,7 @@ enum wm2000_anc_mode {
struct wm2000_priv {
struct i2c_client *i2c;
struct regmap *regmap;
struct clk *mclk;
struct regulator_bulk_data supplies[WM2000_NUM_SUPPLIES];
@@ -71,11 +73,12 @@ struct wm2000_priv {
unsigned int anc_eng_ena:1;
unsigned int spk_ena:1;
unsigned int mclk_div:1;
unsigned int speech_clarity:1;
int anc_download_size;
char *anc_download;
struct mutex lock;
};
static int wm2000_write(struct i2c_client *i2c, unsigned int reg,
@@ -131,6 +134,7 @@ static int wm2000_poll_bit(struct i2c_client *i2c,
static int wm2000_power_up(struct i2c_client *i2c, int analogue)
{
struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev);
unsigned long rate;
int ret;
BUG_ON(wm2000->anc_mode != ANC_OFF);
@@ -143,7 +147,8 @@ static int wm2000_power_up(struct i2c_client *i2c, int analogue)
return ret;
}
if (!wm2000->mclk_div) {
rate = clk_get_rate(wm2000->mclk);
if (rate <= 13500000) {
dev_dbg(&i2c->dev, "Disabling MCLK divider\n");
wm2000_write(i2c, WM2000_REG_SYS_CTL2,
WM2000_MCLK_DIV2_ENA_CLR);
@@ -550,6 +555,15 @@ static int wm2000_anc_transition(struct wm2000_priv *wm2000,
return -EINVAL;
}
/* Maintain clock while active */
if (anc_transitions[i].source == ANC_OFF) {
ret = clk_prepare_enable(wm2000->mclk);
if (ret != 0) {
dev_err(&i2c->dev, "Failed to enable MCLK: %d\n", ret);
return ret;
}
}
for (j = 0; j < ARRAY_SIZE(anc_transitions[j].step); j++) {
if (!anc_transitions[i].step[j])
break;
@@ -559,7 +573,10 @@ static int wm2000_anc_transition(struct wm2000_priv *wm2000,
return ret;
}
return 0;
if (anc_transitions[i].dest == ANC_OFF)
clk_disable_unprepare(wm2000->mclk);
return ret;
}
static int wm2000_anc_set_mode(struct wm2000_priv *wm2000)
@@ -599,13 +616,20 @@ static int wm2000_anc_mode_put(struct snd_kcontrol *kcontrol,
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
int anc_active = ucontrol->value.enumerated.item[0];
int ret;
if (anc_active > 1)
return -EINVAL;
mutex_lock(&wm2000->lock);
wm2000->anc_active = anc_active;
return wm2000_anc_set_mode(wm2000);
ret = wm2000_anc_set_mode(wm2000);
mutex_unlock(&wm2000->lock);
return ret;
}
static int wm2000_speaker_get(struct snd_kcontrol *kcontrol,
@@ -625,16 +649,24 @@ static int wm2000_speaker_put(struct snd_kcontrol *kcontrol,
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
int val = ucontrol->value.enumerated.item[0];
int ret;
if (val > 1)
return -EINVAL;
mutex_lock(&wm2000->lock);
wm2000->spk_ena = val;
return wm2000_anc_set_mode(wm2000);
ret = wm2000_anc_set_mode(wm2000);
mutex_unlock(&wm2000->lock);
return ret;
}
static const struct snd_kcontrol_new wm2000_controls[] = {
SOC_SINGLE("ANC Volume", WM2000_REG_ANC_GAIN_CTRL, 0, 255, 0),
SOC_SINGLE_BOOL_EXT("WM2000 ANC Switch", 0,
wm2000_anc_mode_get,
wm2000_anc_mode_put),
@@ -648,6 +680,9 @@ static int wm2000_anc_power_event(struct snd_soc_dapm_widget *w,
{
struct snd_soc_codec *codec = w->codec;
struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
int ret;
mutex_lock(&wm2000->lock);
if (SND_SOC_DAPM_EVENT_ON(event))
wm2000->anc_eng_ena = 1;
@@ -655,7 +690,11 @@ static int wm2000_anc_power_event(struct snd_soc_dapm_widget *w,
if (SND_SOC_DAPM_EVENT_OFF(event))
wm2000->anc_eng_ena = 0;
return wm2000_anc_set_mode(wm2000);
ret = wm2000_anc_set_mode(wm2000);
mutex_unlock(&wm2000->lock);
return ret;
}
static const struct snd_soc_dapm_widget wm2000_dapm_widgets[] = {
@@ -702,6 +741,9 @@ static bool wm2000_readable_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case WM2000_REG_SYS_START:
case WM2000_REG_ANC_GAIN_CTRL:
case WM2000_REG_MSE_TH1:
case WM2000_REG_MSE_TH2:
case WM2000_REG_SPEECH_CLARITY:
case WM2000_REG_SYS_WATCHDOG:
case WM2000_REG_ANA_VMID_PD_TIME:
@@ -737,6 +779,8 @@ static int wm2000_probe(struct snd_soc_codec *codec)
{
struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
snd_soc_codec_set_cache_io(codec, 16, 8, SND_SOC_REGMAP);
/* This will trigger a transition to standby mode by default */
wm2000_anc_set_mode(wm2000);
@@ -782,6 +826,8 @@ static int wm2000_i2c_probe(struct i2c_client *i2c,
return -ENOMEM;
}
mutex_init(&wm2000->lock);
dev_set_drvdata(&i2c->dev, wm2000);
wm2000->regmap = devm_regmap_init_i2c(i2c, &wm2000_regmap);
@@ -823,10 +869,16 @@ static int wm2000_i2c_probe(struct i2c_client *i2c,
reg = wm2000_read(i2c, WM2000_REG_REVISON);
dev_info(&i2c->dev, "revision %c\n", reg + 'A');
wm2000->mclk = devm_clk_get(&i2c->dev, "MCLK");
if (IS_ERR(wm2000->mclk)) {
ret = PTR_ERR(wm2000->mclk);
dev_err(&i2c->dev, "Failed to get MCLK: %d\n", ret);
goto err_supplies;
}
filename = "wm2000_anc.bin";
pdata = dev_get_platdata(&i2c->dev);
if (pdata) {
wm2000->mclk_div = pdata->mclkdiv2;
wm2000->speech_clarity = !pdata->speech_enh_disable;
if (pdata->download_file)

View File

@@ -10,6 +10,9 @@
#define _WM2000_H
#define WM2000_REG_SYS_START 0x8000
#define WM2000_REG_ANC_GAIN_CTRL 0x8fa2
#define WM2000_REG_MSE_TH2 0x8fdf
#define WM2000_REG_MSE_TH1 0x8fe0
#define WM2000_REG_SPEECH_CLARITY 0x8fef
#define WM2000_REG_SYS_WATCHDOG 0x8ff6
#define WM2000_REG_ANA_VMID_PD_TIME 0x8ff7

View File

@@ -1109,6 +1109,16 @@ static int wm2200_mixer_values[] = {
static WM2200_MUX_CTL_DECL(name##_aux5); \
static WM2200_MUX_CTL_DECL(name##_aux6);
static const char *wm2200_rxanc_input_sel_texts[] = {
"None", "IN1", "IN2", "IN3",
};
static const struct soc_enum wm2200_rxanc_input_sel =
SOC_ENUM_SINGLE(WM2200_RXANC_SRC,
WM2200_IN_RXANC_SEL_SHIFT,
ARRAY_SIZE(wm2200_rxanc_input_sel_texts),
wm2200_rxanc_input_sel_texts);
static const struct snd_kcontrol_new wm2200_snd_controls[] = {
SOC_SINGLE("IN1 High Performance Switch", WM2200_IN1L_CONTROL,
WM2200_IN1_OSR_SHIFT, 1, 0),
@@ -1126,9 +1136,9 @@ SOC_DOUBLE_R_TLV("IN3 Volume", WM2200_IN3L_CONTROL, WM2200_IN3R_CONTROL,
SOC_DOUBLE_R("IN1 Digital Switch", WM2200_ADC_DIGITAL_VOLUME_1L,
WM2200_ADC_DIGITAL_VOLUME_1R, WM2200_IN1L_MUTE_SHIFT, 1, 1),
SOC_DOUBLE_R("IN2 Digital Switch", WM2200_ADC_DIGITAL_VOLUME_1L,
SOC_DOUBLE_R("IN2 Digital Switch", WM2200_ADC_DIGITAL_VOLUME_2L,
WM2200_ADC_DIGITAL_VOLUME_2R, WM2200_IN2L_MUTE_SHIFT, 1, 1),
SOC_DOUBLE_R("IN3 Digital Switch", WM2200_ADC_DIGITAL_VOLUME_1L,
SOC_DOUBLE_R("IN3 Digital Switch", WM2200_ADC_DIGITAL_VOLUME_3L,
WM2200_ADC_DIGITAL_VOLUME_3R, WM2200_IN3L_MUTE_SHIFT, 1, 1),
SOC_DOUBLE_R_TLV("IN1 Digital Volume", WM2200_ADC_DIGITAL_VOLUME_1L,
@@ -1141,6 +1151,12 @@ SOC_DOUBLE_R_TLV("IN3 Digital Volume", WM2200_ADC_DIGITAL_VOLUME_3L,
WM2200_ADC_DIGITAL_VOLUME_3R, WM2200_IN3L_DIG_VOL_SHIFT,
0xbf, 0, digital_tlv),
SND_SOC_BYTES_MASK("EQL Coefficients", WM2200_EQL_1, 20, WM2200_EQL_ENA),
SND_SOC_BYTES_MASK("EQR Coefficients", WM2200_EQR_1, 20, WM2200_EQR_ENA),
SND_SOC_BYTES("LHPF1 Coefficeints", WM2200_HPLPF1_2, 1),
SND_SOC_BYTES("LHPF2 Coefficeints", WM2200_HPLPF2_2, 1),
SOC_SINGLE("OUT1 High Performance Switch", WM2200_DAC_DIGITAL_VOLUME_1L,
WM2200_OUT1_OSR_SHIFT, 1, 0),
SOC_SINGLE("OUT2 High Performance Switch", WM2200_DAC_DIGITAL_VOLUME_2L,
@@ -1162,6 +1178,7 @@ SOC_DOUBLE_R_TLV("OUT2 Digital Volume", WM2200_DAC_DIGITAL_VOLUME_2L,
digital_tlv),
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),
};
WM2200_MIXER_ENUMS(OUT1L, WM2200_OUT1LMIX_INPUT_1_SOURCE);
@@ -1548,6 +1565,10 @@ static int wm2200_probe(struct snd_soc_codec *codec)
return ret;
}
ret = snd_soc_add_codec_controls(codec, wm_adsp_fw_controls, 2);
if (ret != 0)
return ret;
return ret;
}
@@ -2182,6 +2203,7 @@ static int wm2200_i2c_probe(struct i2c_client *i2c,
struct wm2200_priv *wm2200;
unsigned int reg;
int ret, i;
int val;
wm2200 = devm_kzalloc(&i2c->dev, sizeof(struct wm2200_priv),
GFP_KERNEL);
@@ -2205,6 +2227,9 @@ static int wm2200_i2c_probe(struct i2c_client *i2c,
wm2200->dsp[i].num = i + 1;
wm2200->dsp[i].dev = &i2c->dev;
wm2200->dsp[i].regmap = wm2200->regmap;
wm2200->dsp[i].sysclk_reg = WM2200_CLOCKING_3;
wm2200->dsp[i].sysclk_mask = WM2200_SYSCLK_FREQ_MASK;
wm2200->dsp[i].sysclk_shift = WM2200_SYSCLK_FREQ_SHIFT;
}
wm2200->dsp[0].base = WM2200_DSP1_CONTROL_1;
@@ -2215,6 +2240,9 @@ static int wm2200_i2c_probe(struct i2c_client *i2c,
wm2200->dsp[1].mem = wm2200_dsp2_regions;
wm2200->dsp[1].num_mems = ARRAY_SIZE(wm2200_dsp2_regions);
for (i = 0; i < ARRAY_SIZE(wm2200->dsp); i++)
wm_adsp1_init(&wm2200->dsp[i]);
if (pdata)
wm2200->pdata = *pdata;
@@ -2326,6 +2354,36 @@ static int wm2200_i2c_probe(struct i2c_client *i2c,
regmap_write(wm2200->regmap, WM2200_AUDIO_IF_1_16 + i, i);
}
for (i = 0; i < WM2200_MAX_MICBIAS; i++) {
if (!wm2200->pdata.micbias[i].mb_lvl &&
!wm2200->pdata.micbias[i].bypass)
continue;
/* Apply default for bypass mode */
if (!wm2200->pdata.micbias[i].mb_lvl)
wm2200->pdata.micbias[i].mb_lvl
= WM2200_MBIAS_LVL_1V5;
val = (wm2200->pdata.micbias[i].mb_lvl -1)
<< WM2200_MICB1_LVL_SHIFT;
if (wm2200->pdata.micbias[i].discharge)
val |= WM2200_MICB1_DISCH;
if (wm2200->pdata.micbias[i].fast_start)
val |= WM2200_MICB1_RATE;
if (wm2200->pdata.micbias[i].bypass)
val |= WM2200_MICB1_MODE;
regmap_update_bits(wm2200->regmap,
WM2200_MIC_BIAS_CTRL_1 + i,
WM2200_MICB1_LVL_MASK |
WM2200_MICB1_DISCH |
WM2200_MICB1_MODE |
WM2200_MICB1_RATE, val);
}
for (i = 0; i < ARRAY_SIZE(wm2200->pdata.in_mode); i++) {
regmap_update_bits(wm2200->regmap, wm2200_mic_ctrl_reg[i],
WM2200_IN1_MODE_MASK |

View File

@@ -563,6 +563,19 @@ SOC_DOUBLE_R("IN3 Switch", WM5100_ADC_DIGITAL_VOLUME_3L,
SOC_DOUBLE_R("IN4 Switch", WM5100_ADC_DIGITAL_VOLUME_4L,
WM5100_ADC_DIGITAL_VOLUME_4R, WM5100_IN4L_MUTE_SHIFT, 1, 1),
SND_SOC_BYTES_MASK("EQ1 Coefficients", WM5100_EQ1_1, 20, WM5100_EQ1_ENA),
SND_SOC_BYTES_MASK("EQ2 Coefficients", WM5100_EQ2_1, 20, WM5100_EQ2_ENA),
SND_SOC_BYTES_MASK("EQ3 Coefficients", WM5100_EQ3_1, 20, WM5100_EQ3_ENA),
SND_SOC_BYTES_MASK("EQ4 Coefficients", WM5100_EQ4_1, 20, WM5100_EQ4_ENA),
SND_SOC_BYTES_MASK("DRC Coefficients", WM5100_DRC1_CTRL1, 5,
WM5100_DRCL_ENA | WM5100_DRCR_ENA),
SND_SOC_BYTES("LHPF1 Coefficeints", WM5100_HPLPF1_2, 1),
SND_SOC_BYTES("LHPF2 Coefficeints", WM5100_HPLPF2_2, 1),
SND_SOC_BYTES("LHPF3 Coefficeints", WM5100_HPLPF3_2, 1),
SND_SOC_BYTES("LHPF4 Coefficeints", WM5100_HPLPF4_2, 1),
SOC_SINGLE("HPOUT1 High Performance Switch", WM5100_OUT_VOLUME_1L,
WM5100_OUT1_OSR_SHIFT, 1, 0),
SOC_SINGLE("HPOUT2 High Performance Switch", WM5100_OUT_VOLUME_2L,

View File

@@ -45,6 +45,7 @@ static DECLARE_TLV_DB_SCALE(ana_tlv, 0, 100, 0);
static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0);
static DECLARE_TLV_DB_SCALE(noise_tlv, 0, 600, 0);
static DECLARE_TLV_DB_SCALE(ng_tlv, -10200, 600, 0);
static const struct wm_adsp_region wm5102_dsp1_regions[] = {
{ .type = WMFW_ADSP2_PM, .base = 0x100000 },
@@ -603,6 +604,17 @@ static int wm5102_sysclk_ev(struct snd_soc_dapm_widget *w,
return 0;
}
#define WM5102_NG_SRC(name, base) \
SOC_SINGLE(name " NG HPOUT1L Switch", base, 0, 1, 0), \
SOC_SINGLE(name " NG HPOUT1R Switch", base, 1, 1, 0), \
SOC_SINGLE(name " NG HPOUT2L Switch", base, 2, 1, 0), \
SOC_SINGLE(name " NG HPOUT2R Switch", base, 3, 1, 0), \
SOC_SINGLE(name " NG EPOUT Switch", base, 4, 1, 0), \
SOC_SINGLE(name " NG SPKOUTL Switch", base, 6, 1, 0), \
SOC_SINGLE(name " NG SPKOUTR Switch", base, 7, 1, 0), \
SOC_SINGLE(name " NG SPKDAT1L Switch", base, 8, 1, 0), \
SOC_SINGLE(name " NG SPKDAT1R Switch", base, 9, 1, 0)
static const struct snd_kcontrol_new wm5102_snd_controls[] = {
SOC_SINGLE("IN1 High Performance Switch", ARIZONA_IN1L_CONTROL,
ARIZONA_IN1_OSR_SHIFT, 1, 0),
@@ -611,32 +623,31 @@ SOC_SINGLE("IN2 High Performance Switch", ARIZONA_IN2L_CONTROL,
SOC_SINGLE("IN3 High Performance Switch", ARIZONA_IN3L_CONTROL,
ARIZONA_IN3_OSR_SHIFT, 1, 0),
SOC_DOUBLE_R_RANGE_TLV("IN1 Volume", ARIZONA_IN1L_CONTROL,
ARIZONA_IN1R_CONTROL,
ARIZONA_IN1L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
SOC_DOUBLE_R_RANGE_TLV("IN2 Volume", ARIZONA_IN2L_CONTROL,
ARIZONA_IN2R_CONTROL,
ARIZONA_IN2L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
SOC_DOUBLE_R_RANGE_TLV("IN3 Volume", ARIZONA_IN3L_CONTROL,
ARIZONA_IN3R_CONTROL,
ARIZONA_IN3L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
SOC_SINGLE_RANGE_TLV("IN1L Volume", ARIZONA_IN1L_CONTROL,
ARIZONA_IN1L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
SOC_SINGLE_RANGE_TLV("IN1R Volume", ARIZONA_IN1R_CONTROL,
ARIZONA_IN1R_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
SOC_SINGLE_RANGE_TLV("IN2L Volume", ARIZONA_IN2L_CONTROL,
ARIZONA_IN2L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
SOC_SINGLE_RANGE_TLV("IN2R Volume", ARIZONA_IN2R_CONTROL,
ARIZONA_IN2R_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
SOC_SINGLE_RANGE_TLV("IN3L Volume", ARIZONA_IN3L_CONTROL,
ARIZONA_IN3L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
SOC_SINGLE_RANGE_TLV("IN3R Volume", ARIZONA_IN3R_CONTROL,
ARIZONA_IN3R_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
SOC_DOUBLE_R("IN1 Digital Switch", ARIZONA_ADC_DIGITAL_VOLUME_1L,
ARIZONA_ADC_DIGITAL_VOLUME_1R, ARIZONA_IN1L_MUTE_SHIFT, 1, 1),
SOC_DOUBLE_R("IN2 Digital Switch", ARIZONA_ADC_DIGITAL_VOLUME_2L,
ARIZONA_ADC_DIGITAL_VOLUME_2R, ARIZONA_IN2L_MUTE_SHIFT, 1, 1),
SOC_DOUBLE_R("IN3 Digital Switch", ARIZONA_ADC_DIGITAL_VOLUME_3L,
ARIZONA_ADC_DIGITAL_VOLUME_3R, ARIZONA_IN3L_MUTE_SHIFT, 1, 1),
SOC_DOUBLE_R_TLV("IN1 Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1L,
ARIZONA_ADC_DIGITAL_VOLUME_1R, ARIZONA_IN1L_DIG_VOL_SHIFT,
0xbf, 0, digital_tlv),
SOC_DOUBLE_R_TLV("IN2 Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_2L,
ARIZONA_ADC_DIGITAL_VOLUME_2R, ARIZONA_IN2L_DIG_VOL_SHIFT,
0xbf, 0, digital_tlv),
SOC_DOUBLE_R_TLV("IN3 Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_3L,
ARIZONA_ADC_DIGITAL_VOLUME_3R, ARIZONA_IN3L_DIG_VOL_SHIFT,
0xbf, 0, digital_tlv),
SOC_SINGLE_TLV("IN1L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1L,
ARIZONA_IN1L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
SOC_SINGLE_TLV("IN1R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1R,
ARIZONA_IN1R_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
SOC_SINGLE_TLV("IN2L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_2L,
ARIZONA_IN2L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
SOC_SINGLE_TLV("IN2R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_2R,
ARIZONA_IN2R_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
SOC_SINGLE_TLV("IN3L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_3L,
ARIZONA_IN3L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
SOC_SINGLE_TLV("IN3R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_3R,
ARIZONA_IN3R_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
SOC_ENUM("Input Ramp Up", arizona_in_vi_ramp),
SOC_ENUM("Input Ramp Down", arizona_in_vd_ramp),
@@ -774,6 +785,22 @@ SOC_ENUM("Output Ramp Down", arizona_out_vd_ramp),
SOC_DOUBLE("SPKDAT1 Switch", ARIZONA_PDM_SPK1_CTRL_1, ARIZONA_SPK1L_MUTE_SHIFT,
ARIZONA_SPK1R_MUTE_SHIFT, 1, 1),
SOC_SINGLE("Noise Gate Switch", ARIZONA_NOISE_GATE_CONTROL,
ARIZONA_NGATE_ENA_SHIFT, 1, 0),
SOC_SINGLE_TLV("Noise Gate Threshold Volume", ARIZONA_NOISE_GATE_CONTROL,
ARIZONA_NGATE_THR_SHIFT, 7, 1, ng_tlv),
SOC_ENUM("Noise Gate Hold", arizona_ng_hold),
WM5102_NG_SRC("HPOUT1L", ARIZONA_NOISE_GATE_SELECT_1L),
WM5102_NG_SRC("HPOUT1R", ARIZONA_NOISE_GATE_SELECT_1R),
WM5102_NG_SRC("HPOUT2L", ARIZONA_NOISE_GATE_SELECT_2L),
WM5102_NG_SRC("HPOUT2R", ARIZONA_NOISE_GATE_SELECT_2R),
WM5102_NG_SRC("EPOUT", ARIZONA_NOISE_GATE_SELECT_3L),
WM5102_NG_SRC("SPKOUTL", ARIZONA_NOISE_GATE_SELECT_4L),
WM5102_NG_SRC("SPKOUTR", ARIZONA_NOISE_GATE_SELECT_4R),
WM5102_NG_SRC("SPKDAT1L", ARIZONA_NOISE_GATE_SELECT_5L),
WM5102_NG_SRC("SPKDAT1R", ARIZONA_NOISE_GATE_SELECT_5R),
ARIZONA_MIXER_CONTROLS("AIF1TX1", ARIZONA_AIF1TX1MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("AIF1TX2", ARIZONA_AIF1TX2MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("AIF1TX3", ARIZONA_AIF1TX3MIX_INPUT_1_SOURCE),
@@ -880,6 +907,18 @@ ARIZONA_MUX_ENUMS(ASRC1R, ARIZONA_ASRC1RMIX_INPUT_1_SOURCE);
ARIZONA_MUX_ENUMS(ASRC2L, ARIZONA_ASRC2LMIX_INPUT_1_SOURCE);
ARIZONA_MUX_ENUMS(ASRC2R, ARIZONA_ASRC2RMIX_INPUT_1_SOURCE);
ARIZONA_MUX_ENUMS(ISRC1INT1, ARIZONA_ISRC1INT1MIX_INPUT_1_SOURCE);
ARIZONA_MUX_ENUMS(ISRC1INT2, ARIZONA_ISRC1INT2MIX_INPUT_1_SOURCE);
ARIZONA_MUX_ENUMS(ISRC1DEC1, ARIZONA_ISRC1DEC1MIX_INPUT_1_SOURCE);
ARIZONA_MUX_ENUMS(ISRC1DEC2, ARIZONA_ISRC1DEC2MIX_INPUT_1_SOURCE);
ARIZONA_MUX_ENUMS(ISRC2INT1, ARIZONA_ISRC2INT1MIX_INPUT_1_SOURCE);
ARIZONA_MUX_ENUMS(ISRC2INT2, ARIZONA_ISRC2INT2MIX_INPUT_1_SOURCE);
ARIZONA_MUX_ENUMS(ISRC2DEC1, ARIZONA_ISRC2DEC1MIX_INPUT_1_SOURCE);
ARIZONA_MUX_ENUMS(ISRC2DEC2, ARIZONA_ISRC2DEC2MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(DSP1L, ARIZONA_DSP1LMIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(DSP1R, ARIZONA_DSP1RMIX_INPUT_1_SOURCE);
@@ -1002,6 +1041,26 @@ SND_SOC_DAPM_PGA("ASRC2L", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2L_ENA_SHIFT, 0,
SND_SOC_DAPM_PGA("ASRC2R", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2R_ENA_SHIFT, 0,
NULL, 0),
SND_SOC_DAPM_PGA("ISRC1INT1", ARIZONA_ISRC_1_CTRL_3,
ARIZONA_ISRC1_INT0_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("ISRC1INT2", ARIZONA_ISRC_1_CTRL_3,
ARIZONA_ISRC1_INT1_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("ISRC1DEC1", ARIZONA_ISRC_1_CTRL_3,
ARIZONA_ISRC1_DEC0_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("ISRC1DEC2", ARIZONA_ISRC_1_CTRL_3,
ARIZONA_ISRC1_DEC1_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("ISRC2INT1", ARIZONA_ISRC_2_CTRL_3,
ARIZONA_ISRC2_INT0_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("ISRC2INT2", ARIZONA_ISRC_2_CTRL_3,
ARIZONA_ISRC2_INT1_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("ISRC2DEC1", ARIZONA_ISRC_2_CTRL_3,
ARIZONA_ISRC2_DEC0_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("ISRC2DEC2", ARIZONA_ISRC_2_CTRL_3,
ARIZONA_ISRC2_DEC1_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_AIF_OUT("AIF1TX1", NULL, 0,
ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX1_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 0,
@@ -1138,6 +1197,18 @@ ARIZONA_MUX_WIDGETS(ASRC1R, "ASRC1R"),
ARIZONA_MUX_WIDGETS(ASRC2L, "ASRC2L"),
ARIZONA_MUX_WIDGETS(ASRC2R, "ASRC2R"),
ARIZONA_MUX_WIDGETS(ISRC1DEC1, "ISRC1DEC1"),
ARIZONA_MUX_WIDGETS(ISRC1DEC2, "ISRC1DEC2"),
ARIZONA_MUX_WIDGETS(ISRC1INT1, "ISRC1INT1"),
ARIZONA_MUX_WIDGETS(ISRC1INT2, "ISRC1INT2"),
ARIZONA_MUX_WIDGETS(ISRC2DEC1, "ISRC2DEC1"),
ARIZONA_MUX_WIDGETS(ISRC2DEC2, "ISRC2DEC2"),
ARIZONA_MUX_WIDGETS(ISRC2INT1, "ISRC2INT1"),
ARIZONA_MUX_WIDGETS(ISRC2INT2, "ISRC2INT2"),
WM_ADSP2("DSP1", 0),
SND_SOC_DAPM_OUTPUT("HPOUT1L"),
@@ -1195,6 +1266,14 @@ SND_SOC_DAPM_OUTPUT("MICSUPP"),
{ name, "ASRC1R", "ASRC1R" }, \
{ name, "ASRC2L", "ASRC2L" }, \
{ name, "ASRC2R", "ASRC2R" }, \
{ name, "ISRC1DEC1", "ISRC1DEC1" }, \
{ name, "ISRC1DEC2", "ISRC1DEC2" }, \
{ name, "ISRC1INT1", "ISRC1INT1" }, \
{ name, "ISRC1INT2", "ISRC1INT2" }, \
{ name, "ISRC2DEC1", "ISRC2DEC1" }, \
{ name, "ISRC2DEC2", "ISRC2DEC2" }, \
{ name, "ISRC2INT1", "ISRC2INT1" }, \
{ name, "ISRC2INT2", "ISRC2INT2" }, \
{ name, "DSP1.1", "DSP1" }, \
{ name, "DSP1.2", "DSP1" }, \
{ name, "DSP1.3", "DSP1" }, \
@@ -1291,6 +1370,18 @@ static const struct snd_soc_dapm_route wm5102_dapm_routes[] = {
{ "ASRC2L", NULL, "ASRC2L Input" },
{ "ASRC2R", NULL, "ASRC2R Input" },
{ "ISRC1DEC1", NULL, "ISRC1DEC1 Input" },
{ "ISRC1DEC2", NULL, "ISRC1DEC2 Input" },
{ "ISRC1INT1", NULL, "ISRC1INT1 Input" },
{ "ISRC1INT2", NULL, "ISRC1INT2 Input" },
{ "ISRC2DEC1", NULL, "ISRC2DEC1 Input" },
{ "ISRC2DEC2", NULL, "ISRC2DEC2 Input" },
{ "ISRC2INT1", NULL, "ISRC2INT1 Input" },
{ "ISRC2INT2", NULL, "ISRC2INT2 Input" },
ARIZONA_MIXER_ROUTES("OUT1L", "HPOUT1L"),
ARIZONA_MIXER_ROUTES("OUT1R", "HPOUT1R"),
ARIZONA_MIXER_ROUTES("OUT2L", "HPOUT2L"),
@@ -1338,6 +1429,18 @@ static const struct snd_soc_dapm_route wm5102_dapm_routes[] = {
ARIZONA_MUX_ROUTES("ASRC2L"),
ARIZONA_MUX_ROUTES("ASRC2R"),
ARIZONA_MUX_ROUTES("ISRC1INT1"),
ARIZONA_MUX_ROUTES("ISRC1INT2"),
ARIZONA_MUX_ROUTES("ISRC1DEC1"),
ARIZONA_MUX_ROUTES("ISRC1DEC2"),
ARIZONA_MUX_ROUTES("ISRC2INT1"),
ARIZONA_MUX_ROUTES("ISRC2INT2"),
ARIZONA_MUX_ROUTES("ISRC2DEC1"),
ARIZONA_MUX_ROUTES("ISRC2DEC2"),
ARIZONA_DSP_ROUTES("DSP1"),
{ "AEC Loopback", "HPOUT1L", "OUT1L" },
@@ -1467,6 +1570,10 @@ static int wm5102_codec_probe(struct snd_soc_codec *codec)
if (ret != 0)
return ret;
ret = snd_soc_add_codec_controls(codec, wm_adsp_fw_controls, 1);
if (ret != 0)
return ret;
snd_soc_dapm_disable_pin(&codec->dapm, "HAPTICS");
priv->core.arizona->dapm = &codec->dapm;

View File

@@ -41,6 +41,21 @@ static DECLARE_TLV_DB_SCALE(ana_tlv, 0, 100, 0);
static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0);
static DECLARE_TLV_DB_SCALE(noise_tlv, 0, 600, 0);
static DECLARE_TLV_DB_SCALE(ng_tlv, -10200, 600, 0);
#define WM5110_NG_SRC(name, base) \
SOC_SINGLE(name " NG HPOUT1L Switch", base, 0, 1, 0), \
SOC_SINGLE(name " NG HPOUT1R Switch", base, 1, 1, 0), \
SOC_SINGLE(name " NG HPOUT2L Switch", base, 2, 1, 0), \
SOC_SINGLE(name " NG HPOUT2R Switch", base, 3, 1, 0), \
SOC_SINGLE(name " NG HPOUT3L Switch", base, 4, 1, 0), \
SOC_SINGLE(name " NG HPOUT3R Switch", base, 5, 1, 0), \
SOC_SINGLE(name " NG SPKOUTL Switch", base, 6, 1, 0), \
SOC_SINGLE(name " NG SPKOUTR Switch", base, 7, 1, 0), \
SOC_SINGLE(name " NG SPKDAT1L Switch", base, 8, 1, 0), \
SOC_SINGLE(name " NG SPKDAT1R Switch", base, 9, 1, 0), \
SOC_SINGLE(name " NG SPKDAT2L Switch", base, 10, 1, 0), \
SOC_SINGLE(name " NG SPKDAT2R Switch", base, 11, 1, 0)
static const struct snd_kcontrol_new wm5110_snd_controls[] = {
SOC_SINGLE("IN1 High Performance Switch", ARIZONA_IN1L_CONTROL,
@@ -52,37 +67,35 @@ SOC_SINGLE("IN3 High Performance Switch", ARIZONA_IN3L_CONTROL,
SOC_SINGLE("IN4 High Performance Switch", ARIZONA_IN4L_CONTROL,
ARIZONA_IN4_OSR_SHIFT, 1, 0),
SOC_DOUBLE_R_RANGE_TLV("IN1 Volume", ARIZONA_IN1L_CONTROL,
ARIZONA_IN1R_CONTROL,
ARIZONA_IN1L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
SOC_DOUBLE_R_RANGE_TLV("IN2 Volume", ARIZONA_IN2L_CONTROL,
ARIZONA_IN2R_CONTROL,
ARIZONA_IN2L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
SOC_DOUBLE_R_RANGE_TLV("IN3 Volume", ARIZONA_IN3L_CONTROL,
ARIZONA_IN3R_CONTROL,
ARIZONA_IN3L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
SOC_SINGLE_RANGE_TLV("IN1L Volume", ARIZONA_IN1L_CONTROL,
ARIZONA_IN1L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
SOC_SINGLE_RANGE_TLV("IN1R Volume", ARIZONA_IN1R_CONTROL,
ARIZONA_IN1R_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
SOC_SINGLE_RANGE_TLV("IN2L Volume", ARIZONA_IN2L_CONTROL,
ARIZONA_IN2L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
SOC_SINGLE_RANGE_TLV("IN2R Volume", ARIZONA_IN2R_CONTROL,
ARIZONA_IN2R_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
SOC_SINGLE_RANGE_TLV("IN3L Volume", ARIZONA_IN3L_CONTROL,
ARIZONA_IN3L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
SOC_SINGLE_RANGE_TLV("IN3R Volume", ARIZONA_IN3R_CONTROL,
ARIZONA_IN3R_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
SOC_DOUBLE_R("IN1 Digital Switch", ARIZONA_ADC_DIGITAL_VOLUME_1L,
ARIZONA_ADC_DIGITAL_VOLUME_1R, ARIZONA_IN1L_MUTE_SHIFT, 1, 1),
SOC_DOUBLE_R("IN2 Digital Switch", ARIZONA_ADC_DIGITAL_VOLUME_2L,
ARIZONA_ADC_DIGITAL_VOLUME_2R, ARIZONA_IN2L_MUTE_SHIFT, 1, 1),
SOC_DOUBLE_R("IN3 Digital Switch", ARIZONA_ADC_DIGITAL_VOLUME_3L,
ARIZONA_ADC_DIGITAL_VOLUME_3R, ARIZONA_IN3L_MUTE_SHIFT, 1, 1),
SOC_DOUBLE_R("IN4 Digital Switch", ARIZONA_ADC_DIGITAL_VOLUME_4L,
ARIZONA_ADC_DIGITAL_VOLUME_4R, ARIZONA_IN4L_MUTE_SHIFT, 1, 1),
SOC_DOUBLE_R_TLV("IN1 Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1L,
ARIZONA_ADC_DIGITAL_VOLUME_1R, ARIZONA_IN1L_DIG_VOL_SHIFT,
0xbf, 0, digital_tlv),
SOC_DOUBLE_R_TLV("IN2 Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_2L,
ARIZONA_ADC_DIGITAL_VOLUME_2R, ARIZONA_IN2L_DIG_VOL_SHIFT,
0xbf, 0, digital_tlv),
SOC_DOUBLE_R_TLV("IN3 Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_3L,
ARIZONA_ADC_DIGITAL_VOLUME_3R, ARIZONA_IN3L_DIG_VOL_SHIFT,
0xbf, 0, digital_tlv),
SOC_DOUBLE_R_TLV("IN4 Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_4L,
ARIZONA_ADC_DIGITAL_VOLUME_4R, ARIZONA_IN4L_DIG_VOL_SHIFT,
0xbf, 0, digital_tlv),
SOC_SINGLE_TLV("IN1L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1L,
ARIZONA_IN1L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
SOC_SINGLE_TLV("IN1R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1R,
ARIZONA_IN1R_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
SOC_SINGLE_TLV("IN2L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_2L,
ARIZONA_IN2L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
SOC_SINGLE_TLV("IN2R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_2R,
ARIZONA_IN2R_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
SOC_SINGLE_TLV("IN3L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_3L,
ARIZONA_IN3L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
SOC_SINGLE_TLV("IN3R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_3R,
ARIZONA_IN3R_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
SOC_SINGLE_TLV("IN4L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_4L,
ARIZONA_IN4L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
SOC_SINGLE_TLV("IN4R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_4R,
ARIZONA_IN4R_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
SOC_ENUM("Input Ramp Up", arizona_in_vi_ramp),
SOC_ENUM("Input Ramp Down", arizona_in_vd_ramp),
@@ -263,6 +276,25 @@ SOC_DOUBLE("SPKDAT2 Switch", ARIZONA_PDM_SPK2_CTRL_1, ARIZONA_SPK2L_MUTE_SHIFT,
SOC_ENUM("Output Ramp Up", arizona_out_vi_ramp),
SOC_ENUM("Output Ramp Down", arizona_out_vd_ramp),
SOC_SINGLE("Noise Gate Switch", ARIZONA_NOISE_GATE_CONTROL,
ARIZONA_NGATE_ENA_SHIFT, 1, 0),
SOC_SINGLE_TLV("Noise Gate Threshold Volume", ARIZONA_NOISE_GATE_CONTROL,
ARIZONA_NGATE_THR_SHIFT, 7, 1, ng_tlv),
SOC_ENUM("Noise Gate Hold", arizona_ng_hold),
WM5110_NG_SRC("HPOUT1L", ARIZONA_NOISE_GATE_SELECT_1L),
WM5110_NG_SRC("HPOUT1R", ARIZONA_NOISE_GATE_SELECT_1R),
WM5110_NG_SRC("HPOUT2L", ARIZONA_NOISE_GATE_SELECT_2L),
WM5110_NG_SRC("HPOUT2R", ARIZONA_NOISE_GATE_SELECT_2R),
WM5110_NG_SRC("HPOUT3L", ARIZONA_NOISE_GATE_SELECT_3L),
WM5110_NG_SRC("HPOUT3R", ARIZONA_NOISE_GATE_SELECT_3R),
WM5110_NG_SRC("SPKOUTL", ARIZONA_NOISE_GATE_SELECT_4L),
WM5110_NG_SRC("SPKOUTR", ARIZONA_NOISE_GATE_SELECT_4R),
WM5110_NG_SRC("SPKDAT1L", ARIZONA_NOISE_GATE_SELECT_5L),
WM5110_NG_SRC("SPKDAT1R", ARIZONA_NOISE_GATE_SELECT_5R),
WM5110_NG_SRC("SPKDAT2L", ARIZONA_NOISE_GATE_SELECT_6L),
WM5110_NG_SRC("SPKDAT2R", ARIZONA_NOISE_GATE_SELECT_6R),
ARIZONA_MIXER_CONTROLS("AIF1TX1", ARIZONA_AIF1TX1MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("AIF1TX2", ARIZONA_AIF1TX2MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("AIF1TX3", ARIZONA_AIF1TX3MIX_INPUT_1_SOURCE),

View File

@@ -283,18 +283,16 @@ static int pga_event(struct snd_soc_dapm_widget *w,
out->ramp = WM8350_RAMP_UP;
out->active = 1;
if (!delayed_work_pending(&codec->dapm.delayed_work))
schedule_delayed_work(&codec->dapm.delayed_work,
msecs_to_jiffies(1));
schedule_delayed_work(&codec->dapm.delayed_work,
msecs_to_jiffies(1));
break;
case SND_SOC_DAPM_PRE_PMD:
out->ramp = WM8350_RAMP_DOWN;
out->active = 0;
if (!delayed_work_pending(&codec->dapm.delayed_work))
schedule_delayed_work(&codec->dapm.delayed_work,
msecs_to_jiffies(1));
schedule_delayed_work(&codec->dapm.delayed_work,
msecs_to_jiffies(1));
break;
}

View File

@@ -395,9 +395,6 @@ static int wm8804_set_pll(struct snd_soc_dai *dai, int pll_id,
/* power down the PLL before reprogramming it */
snd_soc_update_bits(codec, WM8804_PWRDN, 0x1, 0x1);
if (!freq_in || !freq_out)
return 0;
/* set PLLN and PRESCALE */
snd_soc_update_bits(codec, WM8804_PLL4, 0xf | 0x10,
pll_div.n | (pll_div.prescale << 4));

View File

@@ -2873,22 +2873,20 @@ static int wm8962_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
ret = 0;
if (fll1 & WM8962_FLL_ENA) {
/* This should be a massive overestimate but go even
* higher if we'll error out
*/
if (wm8962->irq)
timeout = msecs_to_jiffies(5);
else
timeout = msecs_to_jiffies(1);
/* This should be a massive overestimate but go even
* higher if we'll error out
*/
if (wm8962->irq)
timeout = msecs_to_jiffies(5);
else
timeout = msecs_to_jiffies(1);
timeout = wait_for_completion_timeout(&wm8962->fll_lock,
timeout);
timeout = wait_for_completion_timeout(&wm8962->fll_lock,
timeout);
if (timeout == 0 && wm8962->irq) {
dev_err(codec->dev, "FLL lock timed out");
ret = -ETIMEDOUT;
}
if (timeout == 0 && wm8962->irq) {
dev_err(codec->dev, "FLL lock timed out");
ret = -ETIMEDOUT;
}
wm8962->fll_fref = Fref;
@@ -3189,7 +3187,7 @@ static void wm8962_init_beep(struct snd_soc_codec *codec)
struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
int ret;
wm8962->beep = input_allocate_device();
wm8962->beep = devm_input_allocate_device(codec->dev);
if (!wm8962->beep) {
dev_err(codec->dev, "Failed to allocate beep device\n");
return;
@@ -3210,7 +3208,6 @@ static void wm8962_init_beep(struct snd_soc_codec *codec)
ret = input_register_device(wm8962->beep);
if (ret != 0) {
input_free_device(wm8962->beep);
wm8962->beep = NULL;
dev_err(codec->dev, "Failed to register beep device\n");
}
@@ -3227,7 +3224,6 @@ static void wm8962_free_beep(struct snd_soc_codec *codec)
struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
device_remove_file(codec->dev, &dev_attr_beep);
input_unregister_device(wm8962->beep);
cancel_work_sync(&wm8962->beep_work);
wm8962->beep = NULL;
@@ -3758,10 +3754,17 @@ static const struct i2c_device_id wm8962_i2c_id[] = {
};
MODULE_DEVICE_TABLE(i2c, wm8962_i2c_id);
static const struct of_device_id wm8962_of_match[] = {
{ .compatible = "wlf,wm8962", },
{ }
};
MODULE_DEVICE_TABLE(of, wm8962_of_match);
static struct i2c_driver wm8962_i2c_driver = {
.driver = {
.name = "wm8962",
.owner = THIS_MODULE,
.of_match_table = wm8962_of_match,
.pm = &wm8962_pm,
},
.probe = wm8962_i2c_probe,

View File

@@ -851,30 +851,33 @@ static int wm8983_set_pll(struct snd_soc_dai *dai, int pll_id,
struct pll_div pll_div;
codec = dai->codec;
if (freq_in && freq_out) {
if (!freq_in || !freq_out) {
/* disable the PLL */
snd_soc_update_bits(codec, WM8983_POWER_MANAGEMENT_1,
WM8983_PLLEN_MASK, 0);
return 0;
} else {
ret = pll_factors(&pll_div, freq_out * 4 * 2, freq_in);
if (ret)
return ret;
/* disable the PLL before re-programming it */
snd_soc_update_bits(codec, WM8983_POWER_MANAGEMENT_1,
WM8983_PLLEN_MASK, 0);
/* set PLLN and PRESCALE */
snd_soc_write(codec, WM8983_PLL_N,
(pll_div.div2 << WM8983_PLL_PRESCALE_SHIFT)
| pll_div.n);
/* set PLLK */
snd_soc_write(codec, WM8983_PLL_K_3, pll_div.k & 0x1ff);
snd_soc_write(codec, WM8983_PLL_K_2, (pll_div.k >> 9) & 0x1ff);
snd_soc_write(codec, WM8983_PLL_K_1, (pll_div.k >> 18));
/* enable the PLL */
snd_soc_update_bits(codec, WM8983_POWER_MANAGEMENT_1,
WM8983_PLLEN_MASK, WM8983_PLLEN);
}
/* disable the PLL before re-programming it */
snd_soc_update_bits(codec, WM8983_POWER_MANAGEMENT_1,
WM8983_PLLEN_MASK, 0);
if (!freq_in || !freq_out)
return 0;
/* set PLLN and PRESCALE */
snd_soc_write(codec, WM8983_PLL_N,
(pll_div.div2 << WM8983_PLL_PRESCALE_SHIFT)
| pll_div.n);
/* set PLLK */
snd_soc_write(codec, WM8983_PLL_K_3, pll_div.k & 0x1ff);
snd_soc_write(codec, WM8983_PLL_K_2, (pll_div.k >> 9) & 0x1ff);
snd_soc_write(codec, WM8983_PLL_K_1, (pll_div.k >> 18));
/* enable the PLL */
snd_soc_update_bits(codec, WM8983_POWER_MANAGEMENT_1,
WM8983_PLLEN_MASK, WM8983_PLLEN);
return 0;
}

View File

@@ -830,33 +830,30 @@ static int wm8985_set_pll(struct snd_soc_dai *dai, int pll_id,
struct pll_div pll_div;
codec = dai->codec;
if (freq_in && freq_out) {
if (!freq_in || !freq_out) {
/* disable the PLL */
snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1,
WM8985_PLLEN_MASK, 0);
} else {
ret = pll_factors(&pll_div, freq_out * 4 * 2, freq_in);
if (ret)
return ret;
/* set PLLN and PRESCALE */
snd_soc_write(codec, WM8985_PLL_N,
(pll_div.div2 << WM8985_PLL_PRESCALE_SHIFT)
| pll_div.n);
/* set PLLK */
snd_soc_write(codec, WM8985_PLL_K_3, pll_div.k & 0x1ff);
snd_soc_write(codec, WM8985_PLL_K_2, (pll_div.k >> 9) & 0x1ff);
snd_soc_write(codec, WM8985_PLL_K_1, (pll_div.k >> 18));
/* set the source of the clock to be the PLL */
snd_soc_update_bits(codec, WM8985_CLOCK_GEN_CONTROL,
WM8985_CLKSEL_MASK, WM8985_CLKSEL);
/* enable the PLL */
snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1,
WM8985_PLLEN_MASK, WM8985_PLLEN);
}
/* disable the PLL before reprogramming it */
snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1,
WM8985_PLLEN_MASK, 0);
if (!freq_in || !freq_out)
return 0;
/* set PLLN and PRESCALE */
snd_soc_write(codec, WM8985_PLL_N,
(pll_div.div2 << WM8985_PLL_PRESCALE_SHIFT)
| pll_div.n);
/* set PLLK */
snd_soc_write(codec, WM8985_PLL_K_3, pll_div.k & 0x1ff);
snd_soc_write(codec, WM8985_PLL_K_2, (pll_div.k >> 9) & 0x1ff);
snd_soc_write(codec, WM8985_PLL_K_1, (pll_div.k >> 18));
/* set the source of the clock to be the PLL */
snd_soc_update_bits(codec, WM8985_CLOCK_GEN_CONTROL,
WM8985_CLKSEL_MASK, WM8985_CLKSEL);
/* enable the PLL */
snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1,
WM8985_PLLEN_MASK, WM8985_PLLEN);
return 0;
}

View File

@@ -3737,7 +3737,7 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data)
{
struct wm8994_priv *wm8994 = data;
struct snd_soc_codec *codec = wm8994->hubs.codec;
int reg, count;
int reg, count, ret;
/*
* Jack detection may have detected a removal simulataneously
@@ -3783,11 +3783,11 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data)
/* Avoid a transient report when the accessory is being removed */
if (wm8994->jackdet) {
reg = snd_soc_read(codec, WM1811_JACKDET_CTRL);
if (reg < 0) {
ret = snd_soc_read(codec, WM1811_JACKDET_CTRL);
if (ret < 0) {
dev_err(codec->dev, "Failed to read jack status: %d\n",
reg);
} else if (!(reg & WM1811_JACKDET_LVL)) {
ret);
} else if (!(ret & WM1811_JACKDET_LVL)) {
dev_dbg(codec->dev, "Ignoring removed jack\n");
return IRQ_HANDLED;
}

View File

@@ -15,6 +15,7 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/firmware.h>
#include <linux/list.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
@@ -103,9 +104,19 @@
#define ADSP1_START_SHIFT 0 /* DSP1_START */
#define ADSP1_START_WIDTH 1 /* DSP1_START */
#define ADSP2_CONTROL 0
#define ADSP2_CLOCKING 1
#define ADSP2_STATUS1 4
/*
* ADSP1 Control 31
*/
#define ADSP1_CLK_SEL_MASK 0x0007 /* CLK_SEL_ENA */
#define ADSP1_CLK_SEL_SHIFT 0 /* CLK_SEL_ENA */
#define ADSP1_CLK_SEL_WIDTH 3 /* CLK_SEL_ENA */
#define ADSP2_CONTROL 0x0
#define ADSP2_CLOCKING 0x1
#define ADSP2_STATUS1 0x4
#define ADSP2_WDMA_CONFIG_1 0x30
#define ADSP2_WDMA_CONFIG_2 0x31
#define ADSP2_RDMA_CONFIG_1 0x34
/*
* ADSP2 Control
@@ -143,6 +154,109 @@
#define ADSP2_RAM_RDY_SHIFT 0
#define ADSP2_RAM_RDY_WIDTH 1
struct wm_adsp_buf {
struct list_head list;
void *buf;
};
static struct wm_adsp_buf *wm_adsp_buf_alloc(const void *src, size_t len,
struct list_head *list)
{
struct wm_adsp_buf *buf = kzalloc(sizeof(*buf), GFP_KERNEL);
if (buf == NULL)
return NULL;
buf->buf = kmemdup(src, len, GFP_KERNEL | GFP_DMA);
if (!buf->buf) {
kfree(buf);
return NULL;
}
if (list)
list_add_tail(&buf->list, list);
return buf;
}
static void wm_adsp_buf_free(struct list_head *list)
{
while (!list_empty(list)) {
struct wm_adsp_buf *buf = list_first_entry(list,
struct wm_adsp_buf,
list);
list_del(&buf->list);
kfree(buf->buf);
kfree(buf);
}
}
#define WM_ADSP_NUM_FW 4
static const char *wm_adsp_fw_text[WM_ADSP_NUM_FW] = {
"MBC/VSS", "Tx", "Tx Speaker", "Rx ANC"
};
static struct {
const char *file;
} wm_adsp_fw[WM_ADSP_NUM_FW] = {
{ .file = "mbc-vss" },
{ .file = "tx" },
{ .file = "tx-spk" },
{ .file = "rx-anc" },
};
static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
struct wm_adsp *adsp = snd_soc_codec_get_drvdata(codec);
ucontrol->value.integer.value[0] = adsp[e->shift_l].fw;
return 0;
}
static int wm_adsp_fw_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
struct wm_adsp *adsp = snd_soc_codec_get_drvdata(codec);
if (ucontrol->value.integer.value[0] == adsp[e->shift_l].fw)
return 0;
if (ucontrol->value.integer.value[0] >= WM_ADSP_NUM_FW)
return -EINVAL;
if (adsp[e->shift_l].running)
return -EBUSY;
adsp[e->shift_l].fw = ucontrol->value.integer.value[0];
return 0;
}
static 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),
SOC_ENUM_SINGLE(0, 3, 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),
};
EXPORT_SYMBOL_GPL(wm_adsp_fw_controls);
static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp,
int type)
@@ -156,8 +270,29 @@ static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp,
return NULL;
}
static unsigned int wm_adsp_region_to_reg(struct wm_adsp_region const *region,
unsigned int offset)
{
switch (region->type) {
case WMFW_ADSP1_PM:
return region->base + (offset * 3);
case WMFW_ADSP1_DM:
return region->base + (offset * 2);
case WMFW_ADSP2_XM:
return region->base + (offset * 2);
case WMFW_ADSP2_YM:
return region->base + (offset * 2);
case WMFW_ADSP1_ZM:
return region->base + (offset * 2);
default:
WARN_ON(NULL != "Unknown memory region type");
return offset;
}
}
static int wm_adsp_load(struct wm_adsp *dsp)
{
LIST_HEAD(buf_list);
const struct firmware *firmware;
struct regmap *regmap = dsp->regmap;
unsigned int pos = 0;
@@ -169,7 +304,7 @@ static int wm_adsp_load(struct wm_adsp *dsp)
const struct wm_adsp_region *mem;
const char *region_name;
char *file, *text;
void *buf;
struct wm_adsp_buf *buf;
unsigned int reg;
int regions = 0;
int ret, offset, type, sizes;
@@ -178,7 +313,8 @@ static int wm_adsp_load(struct wm_adsp *dsp)
if (file == NULL)
return -ENOMEM;
snprintf(file, PAGE_SIZE, "%s-dsp%d.wmfw", dsp->part, dsp->num);
snprintf(file, PAGE_SIZE, "%s-dsp%d-%s.wmfw", dsp->part, dsp->num,
wm_adsp_fw[dsp->fw].file);
file[PAGE_SIZE - 1] = '\0';
ret = request_firmware(&firmware, file, dsp->dev);
@@ -283,27 +419,27 @@ static int wm_adsp_load(struct wm_adsp *dsp)
case WMFW_ADSP1_PM:
BUG_ON(!mem);
region_name = "PM";
reg = mem->base + (offset * 3);
reg = wm_adsp_region_to_reg(mem, offset);
break;
case WMFW_ADSP1_DM:
BUG_ON(!mem);
region_name = "DM";
reg = mem->base + (offset * 2);
reg = wm_adsp_region_to_reg(mem, offset);
break;
case WMFW_ADSP2_XM:
BUG_ON(!mem);
region_name = "XM";
reg = mem->base + (offset * 2);
reg = wm_adsp_region_to_reg(mem, offset);
break;
case WMFW_ADSP2_YM:
BUG_ON(!mem);
region_name = "YM";
reg = mem->base + (offset * 2);
reg = wm_adsp_region_to_reg(mem, offset);
break;
case WMFW_ADSP1_ZM:
BUG_ON(!mem);
region_name = "ZM";
reg = mem->base + (offset * 2);
reg = wm_adsp_region_to_reg(mem, offset);
break;
default:
adsp_warn(dsp,
@@ -323,18 +459,16 @@ static int wm_adsp_load(struct wm_adsp *dsp)
}
if (reg) {
buf = kmemdup(region->data, le32_to_cpu(region->len),
GFP_KERNEL | GFP_DMA);
buf = wm_adsp_buf_alloc(region->data,
le32_to_cpu(region->len),
&buf_list);
if (!buf) {
adsp_err(dsp, "Out of memory\n");
return -ENOMEM;
}
ret = regmap_raw_write(regmap, reg, buf,
le32_to_cpu(region->len));
kfree(buf);
ret = regmap_raw_write_async(regmap, reg, buf->buf,
le32_to_cpu(region->len));
if (ret != 0) {
adsp_err(dsp,
"%s.%d: Failed to write %d bytes at %d in %s: %d\n",
@@ -348,12 +482,20 @@ static int wm_adsp_load(struct wm_adsp *dsp)
pos += le32_to_cpu(region->len) + sizeof(*region);
regions++;
}
ret = regmap_async_complete(regmap);
if (ret != 0) {
adsp_err(dsp, "Failed to complete async write: %d\n", ret);
goto out_fw;
}
if (pos > firmware->size)
adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n",
file, regions, pos - firmware->size);
out_fw:
regmap_async_complete(regmap);
wm_adsp_buf_free(&buf_list);
release_firmware(firmware);
out:
kfree(file);
@@ -361,22 +503,222 @@ out:
return ret;
}
static int wm_adsp_setup_algs(struct wm_adsp *dsp)
{
struct regmap *regmap = dsp->regmap;
struct wmfw_adsp1_id_hdr adsp1_id;
struct wmfw_adsp2_id_hdr adsp2_id;
struct wmfw_adsp1_alg_hdr *adsp1_alg;
struct wmfw_adsp2_alg_hdr *adsp2_alg;
void *alg, *buf;
struct wm_adsp_alg_region *region;
const struct wm_adsp_region *mem;
unsigned int pos, term;
size_t algs, buf_size;
__be32 val;
int i, ret;
switch (dsp->type) {
case WMFW_ADSP1:
mem = wm_adsp_find_region(dsp, WMFW_ADSP1_DM);
break;
case WMFW_ADSP2:
mem = wm_adsp_find_region(dsp, WMFW_ADSP2_XM);
break;
default:
mem = NULL;
break;
}
if (mem == NULL) {
BUG_ON(mem != NULL);
return -EINVAL;
}
switch (dsp->type) {
case WMFW_ADSP1:
ret = regmap_raw_read(regmap, mem->base, &adsp1_id,
sizeof(adsp1_id));
if (ret != 0) {
adsp_err(dsp, "Failed to read algorithm info: %d\n",
ret);
return ret;
}
buf = &adsp1_id;
buf_size = sizeof(adsp1_id);
algs = be32_to_cpu(adsp1_id.algs);
adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
be32_to_cpu(adsp1_id.fw.id),
(be32_to_cpu(adsp1_id.fw.ver) & 0xff0000) >> 16,
(be32_to_cpu(adsp1_id.fw.ver) & 0xff00) >> 8,
be32_to_cpu(adsp1_id.fw.ver) & 0xff,
algs);
pos = sizeof(adsp1_id) / 2;
term = pos + ((sizeof(*adsp1_alg) * algs) / 2);
break;
case WMFW_ADSP2:
ret = regmap_raw_read(regmap, mem->base, &adsp2_id,
sizeof(adsp2_id));
if (ret != 0) {
adsp_err(dsp, "Failed to read algorithm info: %d\n",
ret);
return ret;
}
buf = &adsp2_id;
buf_size = sizeof(adsp2_id);
algs = be32_to_cpu(adsp2_id.algs);
adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
be32_to_cpu(adsp2_id.fw.id),
(be32_to_cpu(adsp2_id.fw.ver) & 0xff0000) >> 16,
(be32_to_cpu(adsp2_id.fw.ver) & 0xff00) >> 8,
be32_to_cpu(adsp2_id.fw.ver) & 0xff,
algs);
pos = sizeof(adsp2_id) / 2;
term = pos + ((sizeof(*adsp2_alg) * algs) / 2);
break;
default:
BUG_ON(NULL == "Unknown DSP type");
return -EINVAL;
}
if (algs == 0) {
adsp_err(dsp, "No algorithms\n");
return -EINVAL;
}
if (algs > 1024) {
adsp_err(dsp, "Algorithm count %zx excessive\n", algs);
print_hex_dump_bytes(dev_name(dsp->dev), DUMP_PREFIX_OFFSET,
buf, buf_size);
return -EINVAL;
}
/* Read the terminator first to validate the length */
ret = regmap_raw_read(regmap, mem->base + term, &val, sizeof(val));
if (ret != 0) {
adsp_err(dsp, "Failed to read algorithm list end: %d\n",
ret);
return ret;
}
if (be32_to_cpu(val) != 0xbedead)
adsp_warn(dsp, "Algorithm list end %x 0x%x != 0xbeadead\n",
term, be32_to_cpu(val));
alg = kzalloc((term - pos) * 2, GFP_KERNEL | GFP_DMA);
if (!alg)
return -ENOMEM;
ret = regmap_raw_read(regmap, mem->base + pos, alg, (term - pos) * 2);
if (ret != 0) {
adsp_err(dsp, "Failed to read algorithm list: %d\n",
ret);
goto out;
}
adsp1_alg = alg;
adsp2_alg = alg;
for (i = 0; i < algs; i++) {
switch (dsp->type) {
case WMFW_ADSP1:
adsp_info(dsp, "%d: ID %x v%d.%d.%d DM@%x ZM@%x\n",
i, be32_to_cpu(adsp1_alg[i].alg.id),
(be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff0000) >> 16,
(be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff00) >> 8,
be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff,
be32_to_cpu(adsp1_alg[i].dm),
be32_to_cpu(adsp1_alg[i].zm));
region = kzalloc(sizeof(*region), GFP_KERNEL);
if (!region)
return -ENOMEM;
region->type = WMFW_ADSP1_DM;
region->alg = be32_to_cpu(adsp1_alg[i].alg.id);
region->base = be32_to_cpu(adsp1_alg[i].dm);
list_add_tail(&region->list, &dsp->alg_regions);
region = kzalloc(sizeof(*region), GFP_KERNEL);
if (!region)
return -ENOMEM;
region->type = WMFW_ADSP1_ZM;
region->alg = be32_to_cpu(adsp1_alg[i].alg.id);
region->base = be32_to_cpu(adsp1_alg[i].zm);
list_add_tail(&region->list, &dsp->alg_regions);
break;
case WMFW_ADSP2:
adsp_info(dsp,
"%d: ID %x v%d.%d.%d XM@%x YM@%x ZM@%x\n",
i, be32_to_cpu(adsp2_alg[i].alg.id),
(be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff0000) >> 16,
(be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff00) >> 8,
be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff,
be32_to_cpu(adsp2_alg[i].xm),
be32_to_cpu(adsp2_alg[i].ym),
be32_to_cpu(adsp2_alg[i].zm));
region = kzalloc(sizeof(*region), GFP_KERNEL);
if (!region)
return -ENOMEM;
region->type = WMFW_ADSP2_XM;
region->alg = be32_to_cpu(adsp2_alg[i].alg.id);
region->base = be32_to_cpu(adsp2_alg[i].xm);
list_add_tail(&region->list, &dsp->alg_regions);
region = kzalloc(sizeof(*region), GFP_KERNEL);
if (!region)
return -ENOMEM;
region->type = WMFW_ADSP2_YM;
region->alg = be32_to_cpu(adsp2_alg[i].alg.id);
region->base = be32_to_cpu(adsp2_alg[i].ym);
list_add_tail(&region->list, &dsp->alg_regions);
region = kzalloc(sizeof(*region), GFP_KERNEL);
if (!region)
return -ENOMEM;
region->type = WMFW_ADSP2_ZM;
region->alg = be32_to_cpu(adsp2_alg[i].alg.id);
region->base = be32_to_cpu(adsp2_alg[i].zm);
list_add_tail(&region->list, &dsp->alg_regions);
break;
}
}
out:
kfree(alg);
return ret;
}
static int wm_adsp_load_coeff(struct wm_adsp *dsp)
{
LIST_HEAD(buf_list);
struct regmap *regmap = dsp->regmap;
struct wmfw_coeff_hdr *hdr;
struct wmfw_coeff_item *blk;
const struct firmware *firmware;
const struct wm_adsp_region *mem;
struct wm_adsp_alg_region *alg_region;
const char *region_name;
int ret, pos, blocks, type, offset, reg;
char *file;
void *buf;
struct wm_adsp_buf *buf;
int tmp;
file = kzalloc(PAGE_SIZE, GFP_KERNEL);
if (file == NULL)
return -ENOMEM;
snprintf(file, PAGE_SIZE, "%s-dsp%d.bin", dsp->part, dsp->num);
snprintf(file, PAGE_SIZE, "%s-dsp%d-%s.bin", dsp->part, dsp->num,
wm_adsp_fw[dsp->fw].file);
file[PAGE_SIZE - 1] = '\0';
ret = request_firmware(&firmware, file, dsp->dev);
@@ -399,6 +741,16 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)
goto out_fw;
}
switch (be32_to_cpu(hdr->rev) & 0xff) {
case 1:
break;
default:
adsp_err(dsp, "%s: Unsupported coefficient file format %d\n",
file, be32_to_cpu(hdr->rev) & 0xff);
ret = -EINVAL;
goto out_fw;
}
adsp_dbg(dsp, "%s: v%d.%d.%d\n", file,
(le32_to_cpu(hdr->ver) >> 16) & 0xff,
(le32_to_cpu(hdr->ver) >> 8) & 0xff,
@@ -411,8 +763,8 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)
pos - firmware->size > sizeof(*blk)) {
blk = (void*)(&firmware->data[pos]);
type = be32_to_cpu(blk->type) & 0xff;
offset = le32_to_cpu(blk->offset) & 0xffffff;
type = le16_to_cpu(blk->type);
offset = le16_to_cpu(blk->offset);
adsp_dbg(dsp, "%s.%d: %x v%d.%d.%d\n",
file, blocks, le32_to_cpu(blk->id),
@@ -425,52 +777,105 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)
reg = 0;
region_name = "Unknown";
switch (type) {
case WMFW_NAME_TEXT:
case WMFW_INFO_TEXT:
case (WMFW_NAME_TEXT << 8):
case (WMFW_INFO_TEXT << 8):
break;
case WMFW_ABSOLUTE:
case (WMFW_ABSOLUTE << 8):
region_name = "register";
reg = offset;
break;
case WMFW_ADSP1_DM:
case WMFW_ADSP1_ZM:
case WMFW_ADSP2_XM:
case WMFW_ADSP2_YM:
adsp_dbg(dsp, "%s.%d: %d bytes in %x for %x\n",
file, blocks, le32_to_cpu(blk->len),
type, le32_to_cpu(blk->id));
mem = wm_adsp_find_region(dsp, type);
if (!mem) {
adsp_err(dsp, "No base for region %x\n", type);
break;
}
reg = 0;
list_for_each_entry(alg_region,
&dsp->alg_regions, list) {
if (le32_to_cpu(blk->id) == alg_region->alg &&
type == alg_region->type) {
reg = alg_region->base;
reg = wm_adsp_region_to_reg(mem,
reg);
reg += offset;
}
}
if (reg == 0)
adsp_err(dsp, "No %x for algorithm %x\n",
type, le32_to_cpu(blk->id));
break;
default:
adsp_err(dsp, "Unknown region type %x\n", type);
adsp_err(dsp, "%s.%d: Unknown region type %x at %d\n",
file, blocks, type, pos);
break;
}
if (reg) {
buf = kmemdup(blk->data, le32_to_cpu(blk->len),
GFP_KERNEL | GFP_DMA);
buf = wm_adsp_buf_alloc(blk->data,
le32_to_cpu(blk->len),
&buf_list);
if (!buf) {
adsp_err(dsp, "Out of memory\n");
return -ENOMEM;
}
ret = regmap_raw_write(regmap, reg, blk->data,
le32_to_cpu(blk->len));
adsp_dbg(dsp, "%s.%d: Writing %d bytes at %x\n",
file, blocks, le32_to_cpu(blk->len),
reg);
ret = regmap_raw_write_async(regmap, reg, buf->buf,
le32_to_cpu(blk->len));
if (ret != 0) {
adsp_err(dsp,
"%s.%d: Failed to write to %x in %s\n",
file, blocks, reg, region_name);
}
kfree(buf);
}
pos += le32_to_cpu(blk->len) + sizeof(*blk);
tmp = le32_to_cpu(blk->len) % 4;
if (tmp)
pos += le32_to_cpu(blk->len) + (4 - tmp) + sizeof(*blk);
else
pos += le32_to_cpu(blk->len) + sizeof(*blk);
blocks++;
}
ret = regmap_async_complete(regmap);
if (ret != 0)
adsp_err(dsp, "Failed to complete async write: %d\n", ret);
if (pos > firmware->size)
adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n",
file, blocks, pos - firmware->size);
out_fw:
release_firmware(firmware);
wm_adsp_buf_free(&buf_list);
out:
kfree(file);
return 0;
}
int wm_adsp1_init(struct wm_adsp *adsp)
{
INIT_LIST_HEAD(&adsp->alg_regions);
return 0;
}
EXPORT_SYMBOL_GPL(wm_adsp1_init);
int wm_adsp1_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol,
int event)
@@ -479,16 +884,46 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,
struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
struct wm_adsp *dsp = &dsps[w->shift];
int ret;
int val;
switch (event) {
case SND_SOC_DAPM_POST_PMU:
regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
ADSP1_SYS_ENA, ADSP1_SYS_ENA);
/*
* For simplicity set the DSP clock rate to be the
* SYSCLK rate rather than making it configurable.
*/
if(dsp->sysclk_reg) {
ret = regmap_read(dsp->regmap, dsp->sysclk_reg, &val);
if (ret != 0) {
adsp_err(dsp, "Failed to read SYSCLK state: %d\n",
ret);
return ret;
}
val = (val & dsp->sysclk_mask)
>> dsp->sysclk_shift;
ret = regmap_update_bits(dsp->regmap,
dsp->base + ADSP1_CONTROL_31,
ADSP1_CLK_SEL_MASK, val);
if (ret != 0) {
adsp_err(dsp, "Failed to set clock rate: %d\n",
ret);
return ret;
}
}
ret = wm_adsp_load(dsp);
if (ret != 0)
goto err;
ret = wm_adsp_setup_algs(dsp);
if (ret != 0)
goto err;
ret = wm_adsp_load_coeff(dsp);
if (ret != 0)
goto err;
@@ -560,6 +995,7 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
struct snd_soc_codec *codec = w->codec;
struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
struct wm_adsp *dsp = &dsps[w->shift];
struct wm_adsp_alg_region *alg_region;
unsigned int val;
int ret;
@@ -625,6 +1061,10 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
if (ret != 0)
goto err;
ret = wm_adsp_setup_algs(dsp);
if (ret != 0)
goto err;
ret = wm_adsp_load_coeff(dsp);
if (ret != 0)
goto err;
@@ -635,13 +1075,22 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
ADSP2_CORE_ENA | ADSP2_START);
if (ret != 0)
goto err;
dsp->running = true;
break;
case SND_SOC_DAPM_PRE_PMD:
dsp->running = false;
regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
ADSP2_SYS_ENA | ADSP2_CORE_ENA |
ADSP2_START, 0);
/* Make sure DMAs are quiesced */
regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_1, 0);
regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_2, 0);
regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0);
if (dsp->dvfs) {
ret = regulator_set_voltage(dsp->dvfs, 1200000,
1800000);
@@ -656,6 +1105,14 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
"Failed to enable supply: %d\n",
ret);
}
while (!list_empty(&dsp->alg_regions)) {
alg_region = list_first_entry(&dsp->alg_regions,
struct wm_adsp_alg_region,
list);
list_del(&alg_region->list);
kfree(alg_region);
}
break;
default:
@@ -685,6 +1142,8 @@ int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs)
return ret;
}
INIT_LIST_HEAD(&adsp->alg_regions);
if (dvfs) {
adsp->dvfs = devm_regulator_get(adsp->dev, "DCVDD");
if (IS_ERR(adsp->dvfs)) {

View File

@@ -25,6 +25,13 @@ struct wm_adsp_region {
unsigned int base;
};
struct wm_adsp_alg_region {
struct list_head list;
unsigned int alg;
int type;
unsigned int base;
};
struct wm_adsp {
const char *part;
int num;
@@ -33,10 +40,18 @@ struct wm_adsp {
struct regmap *regmap;
int base;
int sysclk_reg;
int sysclk_mask;
int sysclk_shift;
struct list_head alg_regions;
const struct wm_adsp_region *mem;
int num_mems;
int fw;
bool running;
struct regulator *dvfs;
};
@@ -50,6 +65,9 @@ struct wm_adsp {
.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[];
int wm_adsp1_init(struct wm_adsp *adsp);
int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs);
int wm_adsp1_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event);

View File

@@ -93,15 +93,20 @@ struct wmfw_adsp2_alg_hdr {
struct wmfw_coeff_hdr {
u8 magic[4];
__le32 len;
__le32 ver;
union {
__be32 rev;
__le32 ver;
};
union {
__be32 core;
__le32 core_ver;
};
u8 data[];
} __packed;
struct wmfw_coeff_item {
union {
__be32 type;
__le32 offset;
};
__le16 offset;
__le16 type;
__le32 id;
__le32 ver;
__le32 sr;

View File

@@ -116,9 +116,9 @@ static const struct snd_soc_dapm_route audio_map[] = {
{"Line Out", NULL, "RLOUT"},
/* Mic connected to (MIC3L | MIC3R) */
{"MIC3L", NULL, "Mic Bias 2V"},
{"MIC3R", NULL, "Mic Bias 2V"},
{"Mic Bias 2V", NULL, "Mic Jack"},
{"MIC3L", NULL, "Mic Bias"},
{"MIC3R", NULL, "Mic Bias"},
{"Mic Bias", NULL, "Mic Jack"},
/* Line In connected to (LINE1L | LINE2L), (LINE1R | LINE2R) */
{"LINE1L", NULL, "Line In"},

View File

@@ -626,7 +626,7 @@ static int davinci_config_channel_size(struct davinci_audio_dev *dev,
int word_length)
{
u32 fmt;
u32 rotate = (32 - word_length) / 4;
u32 rotate = (word_length / 4) & 0x7;
u32 mask = (1ULL << word_length) - 1;
/*

View File

@@ -210,15 +210,19 @@ static int dw_i2s_hw_params(struct snd_pcm_substream *substream,
switch (config->chan_nr) {
case EIGHT_CHANNEL_SUPPORT:
ch_reg = 3;
break;
case SIX_CHANNEL_SUPPORT:
ch_reg = 2;
break;
case FOUR_CHANNEL_SUPPORT:
ch_reg = 1;
break;
case TWO_CHANNEL_SUPPORT:
ch_reg = 0;
break;
default:
dev_err(dev->dev, "channel not supported\n");
return -EINVAL;
}
i2s_disable_channels(dev, substream->stream);

View File

@@ -176,7 +176,7 @@ static inline void audmux_debugfs_remove(void)
}
#endif
enum imx_audmux_type {
static enum imx_audmux_type {
IMX21_AUDMUX,
IMX31_AUDMUX,
} audmux_type;

View File

@@ -16,33 +16,38 @@
#define asoc_simple_get_card_info(p) \
container_of(p->dai_link, struct asoc_simple_card_info, snd_link)
static int __asoc_simple_card_dai_init(struct snd_soc_dai *dai,
struct asoc_simple_dai *set,
unsigned int daifmt)
{
int ret = 0;
daifmt |= set->fmt;
if (!ret && daifmt)
ret = snd_soc_dai_set_fmt(dai, daifmt);
if (!ret && set->sysclk)
ret = snd_soc_dai_set_sysclk(dai, 0, set->sysclk, 0);
return ret;
}
static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
{
struct asoc_simple_card_info *cinfo = asoc_simple_get_card_info(rtd);
struct asoc_simple_dai_init_info *iinfo = cinfo->init;
struct asoc_simple_card_info *info = asoc_simple_get_card_info(rtd);
struct snd_soc_dai *codec = rtd->codec_dai;
struct snd_soc_dai *cpu = rtd->cpu_dai;
unsigned int cpu_daifmt = iinfo->fmt | iinfo->cpu_daifmt;
unsigned int codec_daifmt = iinfo->fmt | iinfo->codec_daifmt;
unsigned int daifmt = info->daifmt;
int ret;
if (codec_daifmt) {
ret = snd_soc_dai_set_fmt(codec, codec_daifmt);
if (ret < 0)
return ret;
}
ret = __asoc_simple_card_dai_init(codec, &info->codec_dai, daifmt);
if (ret < 0)
return ret;
if (iinfo->sysclk) {
ret = snd_soc_dai_set_sysclk(codec, 0, iinfo->sysclk, 0);
if (ret < 0)
return ret;
}
if (cpu_daifmt) {
ret = snd_soc_dai_set_fmt(cpu, cpu_daifmt);
if (ret < 0)
return ret;
}
ret = __asoc_simple_card_dai_init(cpu, &info->cpu_dai, daifmt);
if (ret < 0)
return ret;
return 0;
}
@@ -50,19 +55,20 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
static int asoc_simple_card_probe(struct platform_device *pdev)
{
struct asoc_simple_card_info *cinfo = pdev->dev.platform_data;
struct device *dev = &pdev->dev;
if (!cinfo) {
dev_err(&pdev->dev, "no info for asoc-simple-card\n");
dev_err(dev, "no info for asoc-simple-card\n");
return -EINVAL;
}
if (!cinfo->name ||
!cinfo->card ||
!cinfo->cpu_dai ||
!cinfo->codec ||
!cinfo->platform ||
!cinfo->codec_dai) {
dev_err(&pdev->dev, "insufficient asoc_simple_card_info settings\n");
!cinfo->cpu_dai.name ||
!cinfo->codec_dai.name) {
dev_err(dev, "insufficient asoc_simple_card_info settings\n");
return -EINVAL;
}
@@ -71,14 +77,11 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
*/
cinfo->snd_link.name = cinfo->name;
cinfo->snd_link.stream_name = cinfo->name;
cinfo->snd_link.cpu_dai_name = cinfo->cpu_dai;
cinfo->snd_link.cpu_dai_name = cinfo->cpu_dai.name;
cinfo->snd_link.platform_name = cinfo->platform;
cinfo->snd_link.codec_name = cinfo->codec;
cinfo->snd_link.codec_dai_name = cinfo->codec_dai;
/* enable snd_link.init if cinfo has settings */
if (cinfo->init)
cinfo->snd_link.init = asoc_simple_card_dai_init;
cinfo->snd_link.codec_dai_name = cinfo->codec_dai.name;
cinfo->snd_link.init = asoc_simple_card_dai_init;
/*
* init snd_soc_card

View File

@@ -32,7 +32,6 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/saif.h>
#include <asm/mach-types.h>
#include <mach/hardware.h>
#include <mach/mxs.h>
@@ -662,46 +661,40 @@ static int mxs_saif_probe(struct platform_device *pdev)
struct device_node *np = pdev->dev.of_node;
struct resource *iores, *dmares;
struct mxs_saif *saif;
struct mxs_saif_platform_data *pdata;
struct pinctrl *pinctrl;
int ret = 0;
struct device_node *master;
if (!np && pdev->id >= ARRAY_SIZE(mxs_saif))
if (!np)
return -EINVAL;
saif = devm_kzalloc(&pdev->dev, sizeof(*saif), GFP_KERNEL);
if (!saif)
return -ENOMEM;
if (np) {
struct device_node *master;
saif->id = of_alias_get_id(np, "saif");
if (saif->id < 0)
return saif->id;
/*
* If there is no "fsl,saif-master" phandle, it's a saif
* master. Otherwise, it's a slave and its phandle points
* to the master.
*/
master = of_parse_phandle(np, "fsl,saif-master", 0);
if (!master) {
saif->master_id = saif->id;
} else {
saif->master_id = of_alias_get_id(master, "saif");
if (saif->master_id < 0)
return saif->master_id;
}
ret = of_alias_get_id(np, "saif");
if (ret < 0)
return ret;
else
saif->id = ret;
/*
* If there is no "fsl,saif-master" phandle, it's a saif
* master. Otherwise, it's a slave and its phandle points
* to the master.
*/
master = of_parse_phandle(np, "fsl,saif-master", 0);
if (!master) {
saif->master_id = saif->id;
} else {
saif->id = pdev->id;
pdata = pdev->dev.platform_data;
if (pdata && !pdata->master_mode)
saif->master_id = pdata->master_id;
ret = of_alias_get_id(master, "saif");
if (ret < 0)
return ret;
else
saif->master_id = saif->id;
saif->master_id = ret;
}
if (saif->master_id < 0 || saif->master_id >= ARRAY_SIZE(mxs_saif)) {
if (saif->master_id >= ARRAY_SIZE(mxs_saif)) {
dev_err(&pdev->dev, "get wrong master id\n");
return -EINVAL;
}

View File

@@ -70,15 +70,6 @@ config SND_OMAP_SOC_AM3517EVM
Say Y if you want to add support for SoC audio on the OMAP3517 / AM3517
EVM.
config SND_OMAP_SOC_SDP3430
tristate "SoC Audio support for Texas Instruments SDP3430"
depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP_3430SDP
select SND_OMAP_SOC_MCBSP
select SND_SOC_TWL4030
help
Say Y if you want to add support for SoC audio on Texas Instruments
SDP3430.
config SND_OMAP_SOC_OMAP_TWL4030
tristate "SoC Audio support for TI SoC based boards with twl4030 codec"
depends on TWL4030_CORE && SND_OMAP_SOC
@@ -91,6 +82,8 @@ config SND_OMAP_SOC_OMAP_TWL4030
- Gumstix Overo or CompuLab CM-T35/CM-T3730
- IGEP v2
- OMAP3EVM
- SDP3430
- Zoom2
config SND_OMAP_SOC_OMAP_ABE_TWL6040
tristate "SoC Audio support for OMAP boards using ABE and twl6040 codec"
@@ -123,11 +116,3 @@ config SND_OMAP_SOC_OMAP3_PANDORA
select SND_SOC_TWL4030
help
Say Y if you want to add support for SoC audio on the OMAP3 Pandora.
config SND_OMAP_SOC_ZOOM2
tristate "SoC Audio support for Zoom2"
depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP_ZOOM2
select SND_OMAP_SOC_MCBSP
select SND_SOC_TWL4030
help
Say Y if you want to add support for Soc audio on Zoom2 board.

View File

@@ -17,11 +17,9 @@ snd-soc-rx51-objs := rx51.o
snd-soc-ams-delta-objs := ams-delta.o
snd-soc-osk5912-objs := osk5912.o
snd-soc-am3517evm-objs := am3517evm.o
snd-soc-sdp3430-objs := sdp3430.o
snd-soc-omap-abe-twl6040-objs := omap-abe-twl6040.o
snd-soc-omap-twl4030-objs := omap-twl4030.o
snd-soc-omap3pandora-objs := omap3pandora.o
snd-soc-zoom2-objs := zoom2.o
snd-soc-omap-hdmi-card-objs := omap-hdmi-card.o
obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o
@@ -30,9 +28,7 @@ obj-$(CONFIG_SND_OMAP_SOC_AMS_DELTA) += snd-soc-ams-delta.o
obj-$(CONFIG_SND_OMAP_SOC_OSK5912) += snd-soc-osk5912.o
obj-$(CONFIG_SND_OMAP_SOC_OMAP2EVM) += snd-soc-omap2evm.o
obj-$(CONFIG_SND_OMAP_SOC_AM3517EVM) += snd-soc-am3517evm.o
obj-$(CONFIG_SND_OMAP_SOC_SDP3430) += snd-soc-sdp3430.o
obj-$(CONFIG_SND_OMAP_SOC_OMAP_ABE_TWL6040) += snd-soc-omap-abe-twl6040.o
obj-$(CONFIG_SND_OMAP_SOC_OMAP_TWL4030) += snd-soc-omap-twl4030.o
obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o
obj-$(CONFIG_SND_OMAP_SOC_ZOOM2) += snd-soc-zoom2.o
obj-$(CONFIG_SND_OMAP_SOC_OMAP_HDMI) += snd-soc-omap-hdmi-card.o

View File

@@ -230,8 +230,8 @@ static const struct snd_soc_dapm_route audio_map[] = {
{"Ext Spk", NULL, "LLOUT"},
{"Ext Spk", NULL, "RLOUT"},
{"DMic Rate 64", NULL, "Mic Bias 2V"},
{"Mic Bias 2V", NULL, "DMic"},
{"DMic Rate 64", NULL, "Mic Bias"},
{"Mic Bias", NULL, "DMic"},
};
static const char *spk_function[] = {"Off", "On"};

View File

@@ -110,6 +110,8 @@ static int omap_hdmi_dai_hw_params(struct snd_pcm_substream *substream,
/*
* fill the IEC-60958 channel status word
*/
/* initialize the word bytes */
memset(iec->status, 0, sizeof(iec->status));
/* specify IEC-60958-3 (commercial use) */
iec->status[0] &= ~IEC958_AES0_PROFESSIONAL;

View File

@@ -449,10 +449,6 @@ static int asoc_mcpdm_probe(struct platform_device *pdev)
omap_mcpdm_dai_dma_params[0].port_addr = res->start + MCPDM_REG_DN_DATA;
omap_mcpdm_dai_dma_params[1].port_addr = res->start + MCPDM_REG_UP_DATA;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res == NULL)
return -ENOMEM;
res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "dn_link");
if (!res)
return -ENODEV;

View File

@@ -174,23 +174,15 @@ static snd_pcm_uframes_t omap_pcm_pointer(struct snd_pcm_substream *substream)
static int omap_pcm_open(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct omap_pcm_dma_data *dma_data;
int ret;
snd_soc_set_runtime_hwparams(substream, &omap_pcm_hardware);
/* Ensure that buffer size is a multiple of period size */
ret = snd_pcm_hw_constraint_integer(runtime,
SNDRV_PCM_HW_PARAM_PERIODS);
if (ret < 0)
return ret;
dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
ret = snd_dmaengine_pcm_open(substream, omap_dma_filter_fn,
&dma_data->dma_req);
return ret;
return snd_dmaengine_pcm_open(substream, omap_dma_filter_fn,
&dma_data->dma_req);
}
static int omap_pcm_close(struct snd_pcm_substream *substream)

View File

@@ -11,6 +11,8 @@
* omap3evm (Author: Anuj Aggarwal <anuj.aggarwal@ti.com>)
* overo (Author: Steve Sakoman <steve@sakoman.com>)
* igep0020 (Author: Enric Balletbo i Serra <eballetbo@iseebcn.com>)
* zoom2 (Author: Misael Lopez Cruz <misael.lopez@ti.com>)
* sdp3430 (Author: Misael Lopez Cruz <misael.lopez@ti.com>)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -32,14 +34,22 @@
#include <linux/platform_data/omap-twl4030.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/jack.h>
#include "omap-mcbsp.h"
#include "omap-pcm.h"
struct omap_twl4030 {
int jack_detect; /* board can detect jack events */
struct snd_soc_jack hs_jack;
};
static int omap_twl4030_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
@@ -87,17 +97,164 @@ static struct snd_soc_ops omap_twl4030_ops = {
.hw_params = omap_twl4030_hw_params,
};
static const struct snd_soc_dapm_widget dapm_widgets[] = {
SND_SOC_DAPM_SPK("Earpiece Spk", NULL),
SND_SOC_DAPM_SPK("Handsfree Spk", NULL),
SND_SOC_DAPM_HP("Headset Stereophone", NULL),
SND_SOC_DAPM_SPK("Ext Spk", NULL),
SND_SOC_DAPM_SPK("Carkit Spk", NULL),
SND_SOC_DAPM_MIC("Main Mic", NULL),
SND_SOC_DAPM_MIC("Sub Mic", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
SND_SOC_DAPM_MIC("Carkit Mic", NULL),
SND_SOC_DAPM_MIC("Digital0 Mic", NULL),
SND_SOC_DAPM_MIC("Digital1 Mic", NULL),
SND_SOC_DAPM_LINE("Line In", NULL),
};
static const struct snd_soc_dapm_route audio_map[] = {
/* Headset Stereophone: HSOL, HSOR */
{"Headset Stereophone", NULL, "HSOL"},
{"Headset Stereophone", NULL, "HSOR"},
/* External Speakers: HFL, HFR */
{"Handsfree Spk", NULL, "HFL"},
{"Handsfree Spk", NULL, "HFR"},
/* External Speakers: PredrivL, PredrivR */
{"Ext Spk", NULL, "PREDRIVEL"},
{"Ext Spk", NULL, "PREDRIVER"},
/* Carkit speakers: CARKITL, CARKITR */
{"Carkit Spk", NULL, "CARKITL"},
{"Carkit Spk", NULL, "CARKITR"},
/* Earpiece */
{"Earpiece Spk", NULL, "EARPIECE"},
/* External Mics: MAINMIC, SUBMIC with bias */
{"MAINMIC", NULL, "Main Mic"},
{"Main Mic", NULL, "Mic Bias 1"},
{"SUBMIC", NULL, "Sub Mic"},
{"Sub Mic", NULL, "Mic Bias 2"},
/* Headset Mic: HSMIC with bias */
{"HSMIC", NULL, "Headset Mic"},
{"Headset Mic", NULL, "Headset Mic Bias"},
/* Digital Mics: DIGIMIC0, DIGIMIC1 with bias */
{"DIGIMIC0", NULL, "Digital0 Mic"},
{"Digital0 Mic", NULL, "Mic Bias 1"},
{"DIGIMIC1", NULL, "Digital1 Mic"},
{"Digital1 Mic", NULL, "Mic Bias 2"},
/* Carkit In: CARKITMIC */
{"CARKITMIC", NULL, "Carkit Mic"},
/* Aux In: AUXL, AUXR */
{"AUXL", NULL, "Line In"},
{"AUXR", NULL, "Line In"},
};
/* Headset jack detection DAPM pins */
static struct snd_soc_jack_pin hs_jack_pins[] = {
{
.pin = "Headset Mic",
.mask = SND_JACK_MICROPHONE,
},
{
.pin = "Headset Stereophone",
.mask = SND_JACK_HEADPHONE,
},
};
/* Headset jack detection gpios */
static struct snd_soc_jack_gpio hs_jack_gpios[] = {
{
.name = "hsdet-gpio",
.report = SND_JACK_HEADSET,
.debounce_time = 200,
},
};
static inline void twl4030_disconnect_pin(struct snd_soc_dapm_context *dapm,
int connected, char *pin)
{
if (!connected)
snd_soc_dapm_disable_pin(dapm, pin);
}
static int omap_twl4030_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_card *card = codec->card;
struct snd_soc_dapm_context *dapm = &codec->dapm;
struct omap_tw4030_pdata *pdata = dev_get_platdata(card->dev);
struct omap_twl4030 *priv = snd_soc_card_get_drvdata(card);
int ret = 0;
/* Headset jack detection only if it is supported */
if (priv->jack_detect > 0) {
hs_jack_gpios[0].gpio = priv->jack_detect;
ret = snd_soc_jack_new(codec, "Headset Jack", SND_JACK_HEADSET,
&priv->hs_jack);
if (ret)
return ret;
ret = snd_soc_jack_add_pins(&priv->hs_jack,
ARRAY_SIZE(hs_jack_pins),
hs_jack_pins);
if (ret)
return ret;
ret = snd_soc_jack_add_gpios(&priv->hs_jack,
ARRAY_SIZE(hs_jack_gpios),
hs_jack_gpios);
if (ret)
return ret;
}
/*
* NULL pdata means we booted with DT. In this case the routing is
* provided and the card is fully routed, no need to mark pins.
*/
if (!pdata || !pdata->custom_routing)
return ret;
/* Disable not connected paths if not used */
twl4030_disconnect_pin(dapm, pdata->has_ear, "Earpiece Spk");
twl4030_disconnect_pin(dapm, pdata->has_hf, "Handsfree Spk");
twl4030_disconnect_pin(dapm, pdata->has_hs, "Headset Stereophone");
twl4030_disconnect_pin(dapm, pdata->has_predriv, "Ext Spk");
twl4030_disconnect_pin(dapm, pdata->has_carkit, "Carkit Spk");
twl4030_disconnect_pin(dapm, pdata->has_mainmic, "Main Mic");
twl4030_disconnect_pin(dapm, pdata->has_submic, "Sub Mic");
twl4030_disconnect_pin(dapm, pdata->has_hsmic, "Headset Mic");
twl4030_disconnect_pin(dapm, pdata->has_carkitmic, "Carkit Mic");
twl4030_disconnect_pin(dapm, pdata->has_digimic0, "Digital0 Mic");
twl4030_disconnect_pin(dapm, pdata->has_digimic1, "Digital1 Mic");
twl4030_disconnect_pin(dapm, pdata->has_linein, "Line In");
return ret;
}
/* Digital audio interface glue - connects codec <--> CPU */
static struct snd_soc_dai_link omap_twl4030_dai_links[] = {
{
.name = "TWL4030",
.stream_name = "TWL4030",
.name = "TWL4030 HiFi",
.stream_name = "TWL4030 HiFi",
.cpu_dai_name = "omap-mcbsp.2",
.codec_dai_name = "twl4030-hifi",
.platform_name = "omap-pcm-audio",
.codec_name = "twl4030-codec",
.init = omap_twl4030_init,
.ops = &omap_twl4030_ops,
},
{
.name = "TWL4030 Voice",
.stream_name = "TWL4030 Voice",
.cpu_dai_name = "omap-mcbsp.3",
.codec_dai_name = "twl4030-voice",
.platform_name = "omap-pcm-audio",
.codec_name = "twl4030-codec",
.dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF |
SND_SOC_DAIFMT_CBM_CFM,
},
};
/* Audio machine driver */
@@ -105,6 +262,11 @@ static struct snd_soc_card omap_twl4030_card = {
.owner = THIS_MODULE,
.dai_link = omap_twl4030_dai_links,
.num_links = ARRAY_SIZE(omap_twl4030_dai_links),
.dapm_widgets = dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(dapm_widgets),
.dapm_routes = audio_map,
.num_dapm_routes = ARRAY_SIZE(audio_map),
};
static int omap_twl4030_probe(struct platform_device *pdev)
@@ -112,12 +274,18 @@ static int omap_twl4030_probe(struct platform_device *pdev)
struct omap_tw4030_pdata *pdata = dev_get_platdata(&pdev->dev);
struct device_node *node = pdev->dev.of_node;
struct snd_soc_card *card = &omap_twl4030_card;
struct omap_twl4030 *priv;
int ret = 0;
card->dev = &pdev->dev;
priv = devm_kzalloc(&pdev->dev, sizeof(struct omap_twl4030), GFP_KERNEL);
if (priv == NULL)
return -ENOMEM;
if (node) {
struct device_node *dai_node;
struct property *prop;
if (snd_soc_of_parse_card_name(card, "ti,model")) {
dev_err(&pdev->dev, "Card name is not provided\n");
@@ -132,6 +300,27 @@ static int omap_twl4030_probe(struct platform_device *pdev)
omap_twl4030_dai_links[0].cpu_dai_name = NULL;
omap_twl4030_dai_links[0].cpu_of_node = dai_node;
dai_node = of_parse_phandle(node, "ti,mcbsp-voice", 0);
if (!dai_node) {
card->num_links = 1;
} else {
omap_twl4030_dai_links[1].cpu_dai_name = NULL;
omap_twl4030_dai_links[1].cpu_of_node = dai_node;
}
priv->jack_detect = of_get_named_gpio(node,
"ti,jack-det-gpio", 0);
/* Optional: audio routing can be provided */
prop = of_find_property(node, "ti,audio-routing", NULL);
if (prop) {
ret = snd_soc_of_parse_audio_routing(card,
"ti,audio-routing");
if (ret)
return ret;
card->fully_routed = 1;
}
} else if (pdata) {
if (pdata->card_name) {
card->name = pdata->card_name;
@@ -139,11 +328,17 @@ static int omap_twl4030_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "Card name is not provided\n");
return -ENODEV;
}
if (!pdata->voice_connected)
card->num_links = 1;
priv->jack_detect = pdata->jack_detect;
} else {
dev_err(&pdev->dev, "Missing pdata\n");
return -ENODEV;
}
snd_soc_card_set_drvdata(card, priv);
ret = snd_soc_register_card(card);
if (ret) {
dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
@@ -157,7 +352,12 @@ static int omap_twl4030_probe(struct platform_device *pdev)
static int omap_twl4030_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
struct omap_twl4030 *priv = snd_soc_card_get_drvdata(card);
if (priv->jack_detect > 0)
snd_soc_jack_free_gpios(&priv->hs_jack,
ARRAY_SIZE(hs_jack_gpios),
hs_jack_gpios);
snd_soc_unregister_card(card);
return 0;

View File

@@ -144,11 +144,11 @@ static const struct snd_soc_dapm_route omap3pandora_in_map[] = {
{"AUXL", NULL, "Line In"},
{"AUXR", NULL, "Line In"},
{"MAINMIC", NULL, "Mic Bias 1"},
{"Mic Bias 1", NULL, "Mic (internal)"},
{"MAINMIC", NULL, "Mic (internal)"},
{"Mic (internal)", NULL, "Mic Bias 1"},
{"SUBMIC", NULL, "Mic Bias 2"},
{"Mic Bias 2", NULL, "Mic (external)"},
{"SUBMIC", NULL, "Mic (external)"},
{"Mic (external)", NULL, "Mic Bias 2"},
};
static int omap3pandora_out_init(struct snd_soc_pcm_runtime *rtd)

View File

@@ -248,16 +248,16 @@ static const struct snd_soc_dapm_route audio_map[] = {
{"FM Transmitter", NULL, "LLOUT"},
{"FM Transmitter", NULL, "RLOUT"},
{"DMic Rate 64", NULL, "Mic Bias 2V"},
{"Mic Bias 2V", NULL, "DMic"},
{"DMic Rate 64", NULL, "Mic Bias"},
{"Mic Bias", NULL, "DMic"},
};
static const struct snd_soc_dapm_route audio_mapb[] = {
{"b LINE2R", NULL, "MONO_LOUT"},
{"Earphone", NULL, "b HPLOUT"},
{"LINE1L", NULL, "b Mic Bias 2.5V"},
{"b Mic Bias 2.5V", NULL, "HS Mic"}
{"LINE1L", NULL, "b Mic Bias"},
{"b Mic Bias", NULL, "HS Mic"}
};
static const char *spk_function[] = {"Off", "On"};

View File

@@ -1,278 +0,0 @@
/*
* sdp3430.c -- SoC audio for TI OMAP3430 SDP
*
* Author: Misael Lopez Cruz <x0052729@ti.com>
*
* Based on:
* Author: Steve Sakoman <steve@sakoman.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.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/i2c/twl.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/jack.h>
#include <asm/mach-types.h>
#include <linux/platform_data/gpio-omap.h>
#include <linux/platform_data/asoc-ti-mcbsp.h>
/* Register descriptions for twl4030 codec part */
#include <linux/mfd/twl4030-audio.h>
#include <linux/module.h>
#include "omap-mcbsp.h"
#include "omap-pcm.h"
/* TWL4030 PMBR1 Register */
#define TWL4030_INTBR_PMBR1 0x0D
/* TWL4030 PMBR1 Register GPIO6 mux bit */
#define TWL4030_GPIO6_PWM0_MUTE(value) (value << 2)
static struct snd_soc_card snd_soc_sdp3430;
static int sdp3430_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
int ret;
/* Set the codec system clock for DAC and ADC */
ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000,
SND_SOC_CLOCK_IN);
if (ret < 0) {
printk(KERN_ERR "can't set codec system clock\n");
return ret;
}
return 0;
}
static struct snd_soc_ops sdp3430_ops = {
.hw_params = sdp3430_hw_params,
};
/* Headset jack */
static struct snd_soc_jack hs_jack;
/* Headset jack detection DAPM pins */
static struct snd_soc_jack_pin hs_jack_pins[] = {
{
.pin = "Headset Mic",
.mask = SND_JACK_MICROPHONE,
},
{
.pin = "Headset Stereophone",
.mask = SND_JACK_HEADPHONE,
},
};
/* Headset jack detection gpios */
static struct snd_soc_jack_gpio hs_jack_gpios[] = {
{
.gpio = (OMAP_MAX_GPIO_LINES + 2),
.name = "hsdet-gpio",
.report = SND_JACK_HEADSET,
.debounce_time = 200,
},
};
/* SDP3430 machine DAPM */
static const struct snd_soc_dapm_widget sdp3430_twl4030_dapm_widgets[] = {
SND_SOC_DAPM_MIC("Ext Mic", NULL),
SND_SOC_DAPM_SPK("Ext Spk", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
SND_SOC_DAPM_HP("Headset Stereophone", NULL),
};
static const struct snd_soc_dapm_route audio_map[] = {
/* External Mics: MAINMIC, SUBMIC with bias*/
{"MAINMIC", NULL, "Mic Bias 1"},
{"SUBMIC", NULL, "Mic Bias 2"},
{"Mic Bias 1", NULL, "Ext Mic"},
{"Mic Bias 2", NULL, "Ext Mic"},
/* External Speakers: HFL, HFR */
{"Ext Spk", NULL, "HFL"},
{"Ext Spk", NULL, "HFR"},
/* Headset Mic: HSMIC with bias */
{"HSMIC", NULL, "Headset Mic Bias"},
{"Headset Mic Bias", NULL, "Headset Mic"},
/* Headset Stereophone (Headphone): HSOL, HSOR */
{"Headset Stereophone", NULL, "HSOL"},
{"Headset Stereophone", NULL, "HSOR"},
};
static int sdp3430_twl4030_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
int ret;
/* SDP3430 connected pins */
snd_soc_dapm_enable_pin(dapm, "Ext Mic");
snd_soc_dapm_enable_pin(dapm, "Ext Spk");
snd_soc_dapm_disable_pin(dapm, "Headset Mic");
snd_soc_dapm_disable_pin(dapm, "Headset Stereophone");
/* TWL4030 not connected pins */
snd_soc_dapm_nc_pin(dapm, "AUXL");
snd_soc_dapm_nc_pin(dapm, "AUXR");
snd_soc_dapm_nc_pin(dapm, "CARKITMIC");
snd_soc_dapm_nc_pin(dapm, "DIGIMIC0");
snd_soc_dapm_nc_pin(dapm, "DIGIMIC1");
snd_soc_dapm_nc_pin(dapm, "OUTL");
snd_soc_dapm_nc_pin(dapm, "OUTR");
snd_soc_dapm_nc_pin(dapm, "EARPIECE");
snd_soc_dapm_nc_pin(dapm, "PREDRIVEL");
snd_soc_dapm_nc_pin(dapm, "PREDRIVER");
snd_soc_dapm_nc_pin(dapm, "CARKITL");
snd_soc_dapm_nc_pin(dapm, "CARKITR");
/* Headset jack detection */
ret = snd_soc_jack_new(codec, "Headset Jack",
SND_JACK_HEADSET, &hs_jack);
if (ret)
return ret;
ret = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins),
hs_jack_pins);
if (ret)
return ret;
ret = snd_soc_jack_add_gpios(&hs_jack, ARRAY_SIZE(hs_jack_gpios),
hs_jack_gpios);
return ret;
}
static int sdp3430_twl4030_voice_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
unsigned short reg;
/* Enable voice interface */
reg = codec->driver->read(codec, TWL4030_REG_VOICE_IF);
reg |= TWL4030_VIF_DIN_EN | TWL4030_VIF_DOUT_EN | TWL4030_VIF_EN;
codec->driver->write(codec, TWL4030_REG_VOICE_IF, reg);
return 0;
}
/* Digital audio interface glue - connects codec <--> CPU */
static struct snd_soc_dai_link sdp3430_dai[] = {
{
.name = "TWL4030 I2S",
.stream_name = "TWL4030 Audio",
.cpu_dai_name = "omap-mcbsp.2",
.codec_dai_name = "twl4030-hifi",
.platform_name = "omap-pcm-audio",
.codec_name = "twl4030-codec",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBM_CFM,
.init = sdp3430_twl4030_init,
.ops = &sdp3430_ops,
},
{
.name = "TWL4030 PCM",
.stream_name = "TWL4030 Voice",
.cpu_dai_name = "omap-mcbsp.3",
.codec_dai_name = "twl4030-voice",
.platform_name = "omap-pcm-audio",
.codec_name = "twl4030-codec",
.dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF |
SND_SOC_DAIFMT_CBM_CFM,
.init = sdp3430_twl4030_voice_init,
.ops = &sdp3430_ops,
},
};
/* Audio machine driver */
static struct snd_soc_card snd_soc_sdp3430 = {
.name = "SDP3430",
.owner = THIS_MODULE,
.dai_link = sdp3430_dai,
.num_links = ARRAY_SIZE(sdp3430_dai),
.dapm_widgets = sdp3430_twl4030_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(sdp3430_twl4030_dapm_widgets),
.dapm_routes = audio_map,
.num_dapm_routes = ARRAY_SIZE(audio_map),
};
static struct platform_device *sdp3430_snd_device;
static int __init sdp3430_soc_init(void)
{
int ret;
u8 pin_mux;
if (!machine_is_omap_3430sdp())
return -ENODEV;
printk(KERN_INFO "SDP3430 SoC init\n");
sdp3430_snd_device = platform_device_alloc("soc-audio", -1);
if (!sdp3430_snd_device) {
printk(KERN_ERR "Platform device allocation failed\n");
return -ENOMEM;
}
platform_set_drvdata(sdp3430_snd_device, &snd_soc_sdp3430);
/* Set TWL4030 GPIO6 as EXTMUTE signal */
twl_i2c_read_u8(TWL4030_MODULE_INTBR, &pin_mux,
TWL4030_INTBR_PMBR1);
pin_mux &= ~TWL4030_GPIO6_PWM0_MUTE(0x03);
pin_mux |= TWL4030_GPIO6_PWM0_MUTE(0x02);
twl_i2c_write_u8(TWL4030_MODULE_INTBR, pin_mux,
TWL4030_INTBR_PMBR1);
ret = platform_device_add(sdp3430_snd_device);
if (ret)
goto err1;
return 0;
err1:
printk(KERN_ERR "Unable to add platform device\n");
platform_device_put(sdp3430_snd_device);
return ret;
}
module_init(sdp3430_soc_init);
static void __exit sdp3430_soc_exit(void)
{
snd_soc_jack_free_gpios(&hs_jack, ARRAY_SIZE(hs_jack_gpios),
hs_jack_gpios);
platform_device_unregister(sdp3430_snd_device);
}
module_exit(sdp3430_soc_exit);
MODULE_AUTHOR("Misael Lopez Cruz <x0052729@ti.com>");
MODULE_DESCRIPTION("ALSA SoC SDP3430");
MODULE_LICENSE("GPL");

View File

@@ -1,207 +0,0 @@
/*
* zoom2.c -- SoC audio for Zoom2
*
* Author: Misael Lopez Cruz <x0052729@ti.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.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <asm/mach-types.h>
#include <linux/platform_data/asoc-ti-mcbsp.h>
#include <linux/platform_data/gpio-omap.h>
/* Register descriptions for twl4030 codec part */
#include <linux/mfd/twl4030-audio.h>
#include <linux/module.h>
#include "omap-mcbsp.h"
#include "omap-pcm.h"
static int zoom2_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
int ret;
/* Set the codec system clock for DAC and ADC */
ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000,
SND_SOC_CLOCK_IN);
if (ret < 0) {
printk(KERN_ERR "can't set codec system clock\n");
return ret;
}
return 0;
}
static struct snd_soc_ops zoom2_ops = {
.hw_params = zoom2_hw_params,
};
/* Zoom2 machine DAPM */
static const struct snd_soc_dapm_widget zoom2_twl4030_dapm_widgets[] = {
SND_SOC_DAPM_MIC("Ext Mic", NULL),
SND_SOC_DAPM_SPK("Ext Spk", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
SND_SOC_DAPM_HP("Headset Stereophone", NULL),
SND_SOC_DAPM_LINE("Aux In", NULL),
};
static const struct snd_soc_dapm_route audio_map[] = {
/* External Mics: MAINMIC, SUBMIC with bias*/
{"MAINMIC", NULL, "Mic Bias 1"},
{"SUBMIC", NULL, "Mic Bias 2"},
{"Mic Bias 1", NULL, "Ext Mic"},
{"Mic Bias 2", NULL, "Ext Mic"},
/* External Speakers: HFL, HFR */
{"Ext Spk", NULL, "HFL"},
{"Ext Spk", NULL, "HFR"},
/* Headset Stereophone: HSOL, HSOR */
{"Headset Stereophone", NULL, "HSOL"},
{"Headset Stereophone", NULL, "HSOR"},
/* Headset Mic: HSMIC with bias */
{"HSMIC", NULL, "Headset Mic Bias"},
{"Headset Mic Bias", NULL, "Headset Mic"},
/* Aux In: AUXL, AUXR */
{"Aux In", NULL, "AUXL"},
{"Aux In", NULL, "AUXR"},
};
static int zoom2_twl4030_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
/* TWL4030 not connected pins */
snd_soc_dapm_nc_pin(dapm, "CARKITMIC");
snd_soc_dapm_nc_pin(dapm, "DIGIMIC0");
snd_soc_dapm_nc_pin(dapm, "DIGIMIC1");
snd_soc_dapm_nc_pin(dapm, "EARPIECE");
snd_soc_dapm_nc_pin(dapm, "PREDRIVEL");
snd_soc_dapm_nc_pin(dapm, "PREDRIVER");
snd_soc_dapm_nc_pin(dapm, "CARKITL");
snd_soc_dapm_nc_pin(dapm, "CARKITR");
return 0;
}
static int zoom2_twl4030_voice_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
unsigned short reg;
/* Enable voice interface */
reg = codec->driver->read(codec, TWL4030_REG_VOICE_IF);
reg |= TWL4030_VIF_DIN_EN | TWL4030_VIF_DOUT_EN | TWL4030_VIF_EN;
codec->driver->write(codec, TWL4030_REG_VOICE_IF, reg);
return 0;
}
/* Digital audio interface glue - connects codec <--> CPU */
static struct snd_soc_dai_link zoom2_dai[] = {
{
.name = "TWL4030 I2S",
.stream_name = "TWL4030 Audio",
.cpu_dai_name = "omap-mcbsp.2",
.codec_dai_name = "twl4030-hifi",
.platform_name = "omap-pcm-audio",
.codec_name = "twl4030-codec",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBM_CFM,
.init = zoom2_twl4030_init,
.ops = &zoom2_ops,
},
{
.name = "TWL4030 PCM",
.stream_name = "TWL4030 Voice",
.cpu_dai_name = "omap-mcbsp.3",
.codec_dai_name = "twl4030-voice",
.platform_name = "omap-pcm-audio",
.codec_name = "twl4030-codec",
.dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF |
SND_SOC_DAIFMT_CBM_CFM,
.init = zoom2_twl4030_voice_init,
.ops = &zoom2_ops,
},
};
/* Audio machine driver */
static struct snd_soc_card snd_soc_zoom2 = {
.name = "Zoom2",
.owner = THIS_MODULE,
.dai_link = zoom2_dai,
.num_links = ARRAY_SIZE(zoom2_dai),
.dapm_widgets = zoom2_twl4030_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(zoom2_twl4030_dapm_widgets),
.dapm_routes = audio_map,
.num_dapm_routes = ARRAY_SIZE(audio_map),
};
static struct platform_device *zoom2_snd_device;
static int __init zoom2_soc_init(void)
{
int ret;
if (!machine_is_omap_zoom2())
return -ENODEV;
printk(KERN_INFO "Zoom2 SoC init\n");
zoom2_snd_device = platform_device_alloc("soc-audio", -1);
if (!zoom2_snd_device) {
printk(KERN_ERR "Platform device allocation failed\n");
return -ENOMEM;
}
platform_set_drvdata(zoom2_snd_device, &snd_soc_zoom2);
ret = platform_device_add(zoom2_snd_device);
if (ret)
goto err1;
return 0;
err1:
printk(KERN_ERR "Unable to add platform device\n");
platform_device_put(zoom2_snd_device);
return ret;
}
module_init(zoom2_soc_init);
static void __exit zoom2_soc_exit(void)
{
platform_device_unregister(zoom2_snd_device);
}
module_exit(zoom2_soc_exit);
MODULE_AUTHOR("Misael Lopez Cruz <x0052729@ti.com>");
MODULE_DESCRIPTION("ALSA SoC Zoom2");
MODULE_LICENSE("GPL");

View File

@@ -79,17 +79,6 @@ static int palm27x_ac97_init(struct snd_soc_pcm_runtime *rtd)
struct snd_soc_dapm_context *dapm = &codec->dapm;
int err;
/* add palm27x specific widgets */
err = snd_soc_dapm_new_controls(dapm, palm27x_dapm_widgets,
ARRAY_SIZE(palm27x_dapm_widgets));
if (err)
return err;
/* set up palm27x specific audio path audio_map */
err = snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
if (err)
return err;
/* connected pins */
if (machine_is_palmld())
snd_soc_dapm_enable_pin(dapm, "MIC1");
@@ -149,10 +138,12 @@ static struct snd_soc_card palm27x_asoc = {
.owner = THIS_MODULE,
.dai_link = palm27x_dai,
.num_links = ARRAY_SIZE(palm27x_dai),
.dapm_widgets = palm27x_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(palm27x_dapm_widgets),
.dapm_routes = audio_map,
.num_dapm_routes = ARRAY_SIZE(audio_map)
};
static struct platform_device *palm27x_snd_device;
static int palm27x_asoc_probe(struct platform_device *pdev)
{
int ret;
@@ -169,27 +160,18 @@ static int palm27x_asoc_probe(struct platform_device *pdev)
hs_jack_gpios[0].gpio = ((struct palm27x_asoc_info *)
(pdev->dev.platform_data))->jack_gpio;
palm27x_snd_device = platform_device_alloc("soc-audio", -1);
if (!palm27x_snd_device)
return -ENOMEM;
platform_set_drvdata(palm27x_snd_device, &palm27x_asoc);
ret = platform_device_add(palm27x_snd_device);
if (ret != 0)
goto put_device;
return 0;
put_device:
platform_device_put(palm27x_snd_device);
palm27x_asoc.dev = &pdev->dev;
ret = snd_soc_register_card(&palm27x_asoc);
if (ret)
dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
ret);
return ret;
}
static int palm27x_asoc_remove(struct platform_device *pdev)
{
platform_device_unregister(palm27x_snd_device);
snd_soc_unregister_card(&palm27x_asoc);
return 0;
}

View File

@@ -63,7 +63,7 @@ config SND_SOC_SAMSUNG_SMDK_WM8580
config SND_SOC_SAMSUNG_SMDK_WM8994
tristate "SoC I2S Audio support for WM8994 on SMDK"
depends on SND_SOC_SAMSUNG && (MACH_SMDKV310 || MACH_SMDKC210 || MACH_SMDK4212)
depends on SND_SOC_SAMSUNG
depends on I2C=y && GENERIC_HARDIRQS
select MFD_WM8994
select SND_SOC_WM8994
@@ -162,7 +162,7 @@ config SND_SOC_GONI_AQUILA_WM8994
config SND_SOC_SAMSUNG_SMDK_SPDIF
tristate "SoC S/PDIF Audio support for SMDK"
depends on SND_SOC_SAMSUNG && (MACH_SMDKC100 || MACH_SMDKC110 || MACH_SMDKV210 || MACH_SMDKV310 || MACH_SMDK4212)
depends on SND_SOC_SAMSUNG
select SND_SAMSUNG_SPDIF
help
Say Y if you want to add support for SoC S/PDIF audio on the SMDK.
@@ -177,7 +177,7 @@ config SND_SOC_SMDK_WM8580_PCM
config SND_SOC_SMDK_WM8994_PCM
tristate "SoC PCM Audio support for WM8994 on SMDK"
depends on SND_SOC_SAMSUNG && (MACH_SMDKC210 || MACH_SMDKV310 || MACH_SMDK4212)
depends on SND_SOC_SAMSUNG
depends on I2C=y && GENERIC_HARDIRQS
select MFD_WM8994
select SND_SOC_WM8994

View File

@@ -174,7 +174,8 @@ static int dma_hw_params(struct snd_pcm_substream *substream,
config.width = prtd->params->dma_size;
config.fifo = prtd->params->dma_addr;
prtd->params->ch = prtd->params->ops->request(
prtd->params->channel, &req);
prtd->params->channel, &req, rtd->cpu_dai->dev,
prtd->params->ch_name);
prtd->params->ops->config(prtd->params->ch, &config);
}

View File

@@ -19,6 +19,7 @@ struct s3c_dma_params {
int dma_size; /* Size of the DMA transfer */
unsigned ch;
struct samsung_dma_ops *ops;
char *ch_name;
};
int asoc_dma_platform_register(struct device *dev);

View File

@@ -15,11 +15,15 @@
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/pm_runtime.h>
#include <sound/soc.h>
#include <sound/pcm_params.h>
#include <mach/dma.h>
#include <linux/platform_data/asoc-s3c.h>
#include "dma.h"
@@ -29,6 +33,15 @@
#define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t)
enum samsung_dai_type {
TYPE_PRI,
TYPE_SEC,
};
struct samsung_i2s_dai_data {
int dai_type;
};
struct i2s_dai {
/* Platform device for this DAI */
struct platform_device *pdev;
@@ -66,6 +79,7 @@ struct i2s_dai {
u32 suspend_i2smod;
u32 suspend_i2scon;
u32 suspend_i2spsr;
unsigned long gpios[7]; /* i2s gpio line numbers */
};
/* Lock for cross i/f checks */
@@ -651,6 +665,9 @@ static int i2s_startup(struct snd_pcm_substream *substream,
/* Enforce set_sysclk in Master mode */
i2s->rclk_srcrate = 0;
if (!any_active(i2s) && (i2s->quirks & QUIRK_NEED_RSTCLR))
writel(CON_RSTCLR, i2s->addr + I2SCON);
spin_unlock_irqrestore(&lock, flags);
return 0;
@@ -981,8 +998,7 @@ static struct i2s_dai *i2s_alloc_dai(struct platform_device *pdev, bool sec)
i2s->i2s_dai_drv.capture.formats = SAMSUNG_I2S_FMTS;
} else { /* Create a new platform_device for Secondary */
i2s->pdev = platform_device_register_resndata(NULL,
pdev->name, pdev->id + SAMSUNG_I2S_SECOFF,
NULL, 0, NULL, 0);
"samsung-i2s-sec", -1, NULL, 0, NULL, 0);
if (IS_ERR(i2s->pdev))
return NULL;
}
@@ -993,18 +1009,103 @@ static struct i2s_dai *i2s_alloc_dai(struct platform_device *pdev, bool sec)
return i2s;
}
#ifdef CONFIG_OF
static int samsung_i2s_parse_dt_gpio(struct i2s_dai *i2s)
{
struct device *dev = &i2s->pdev->dev;
int index, gpio, ret;
for (index = 0; index < 7; index++) {
gpio = of_get_gpio(dev->of_node, index);
if (!gpio_is_valid(gpio)) {
dev_err(dev, "invalid gpio[%d]: %d\n", index, gpio);
goto free_gpio;
}
ret = gpio_request(gpio, dev_name(dev));
if (ret) {
dev_err(dev, "gpio [%d] request failed\n", gpio);
goto free_gpio;
}
i2s->gpios[index] = gpio;
}
return 0;
free_gpio:
while (--index >= 0)
gpio_free(i2s->gpios[index]);
return -EINVAL;
}
static void samsung_i2s_dt_gpio_free(struct i2s_dai *i2s)
{
unsigned int index;
for (index = 0; index < 7; index++)
gpio_free(i2s->gpios[index]);
}
#else
static int samsung_i2s_parse_dt_gpio(struct i2s_dai *dai)
{
return -EINVAL;
}
static void samsung_i2s_dt_gpio_free(struct i2s_dai *dai)
{
}
#endif
static const struct of_device_id exynos_i2s_match[];
static inline int samsung_i2s_get_driver_data(struct platform_device *pdev)
{
#ifdef CONFIG_OF
struct samsung_i2s_dai_data *data;
if (pdev->dev.of_node) {
const struct of_device_id *match;
match = of_match_node(exynos_i2s_match, pdev->dev.of_node);
data = (struct samsung_i2s_dai_data *) match->data;
return data->dai_type;
} else
#endif
return platform_get_device_id(pdev)->driver_data;
}
#ifdef CONFIG_PM_RUNTIME
static int i2s_runtime_suspend(struct device *dev)
{
struct i2s_dai *i2s = dev_get_drvdata(dev);
clk_disable_unprepare(i2s->clk);
return 0;
}
static int i2s_runtime_resume(struct device *dev)
{
struct i2s_dai *i2s = dev_get_drvdata(dev);
clk_prepare_enable(i2s->clk);
return 0;
}
#endif /* CONFIG_PM_RUNTIME */
static int samsung_i2s_probe(struct platform_device *pdev)
{
u32 dma_pl_chan, dma_cp_chan, dma_pl_sec_chan;
struct i2s_dai *pri_dai, *sec_dai = NULL;
struct s3c_audio_pdata *i2s_pdata;
struct samsung_i2s *i2s_cfg;
struct s3c_audio_pdata *i2s_pdata = pdev->dev.platform_data;
struct samsung_i2s *i2s_cfg = NULL;
struct resource *res;
u32 regs_base, quirks;
u32 regs_base, quirks = 0, idma_addr = 0;
struct device_node *np = pdev->dev.of_node;
enum samsung_dai_type samsung_dai_type;
int ret = 0;
/* Call during Seconday interface registration */
if (pdev->id >= SAMSUNG_I2S_SECOFF) {
samsung_dai_type = samsung_i2s_get_driver_data(pdev);
if (samsung_dai_type == TYPE_SEC) {
sec_dai = dev_get_drvdata(&pdev->dev);
snd_soc_register_dai(&sec_dai->pdev->dev,
&sec_dai->i2s_dai_drv);
@@ -1012,31 +1113,60 @@ static int samsung_i2s_probe(struct platform_device *pdev)
return 0;
}
i2s_pdata = pdev->dev.platform_data;
if (i2s_pdata == NULL) {
dev_err(&pdev->dev, "Can't work without s3c_audio_pdata\n");
return -EINVAL;
pri_dai = i2s_alloc_dai(pdev, false);
if (!pri_dai) {
dev_err(&pdev->dev, "Unable to alloc I2S_pri\n");
return -ENOMEM;
}
res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
if (!res) {
dev_err(&pdev->dev, "Unable to get I2S-TX dma resource\n");
return -ENXIO;
}
dma_pl_chan = res->start;
if (!np) {
res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
if (!res) {
dev_err(&pdev->dev,
"Unable to get I2S-TX dma resource\n");
return -ENXIO;
}
pri_dai->dma_playback.channel = res->start;
res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
if (!res) {
dev_err(&pdev->dev, "Unable to get I2S-RX dma resource\n");
return -ENXIO;
}
dma_cp_chan = res->start;
res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
if (!res) {
dev_err(&pdev->dev,
"Unable to get I2S-RX dma resource\n");
return -ENXIO;
}
pri_dai->dma_capture.channel = res->start;
res = platform_get_resource(pdev, IORESOURCE_DMA, 2);
if (res)
dma_pl_sec_chan = res->start;
else
dma_pl_sec_chan = 0;
if (i2s_pdata == NULL) {
dev_err(&pdev->dev, "Can't work without s3c_audio_pdata\n");
return -EINVAL;
}
if (&i2s_pdata->type)
i2s_cfg = &i2s_pdata->type.i2s;
if (i2s_cfg) {
quirks = i2s_cfg->quirks;
idma_addr = i2s_cfg->idma_addr;
}
} else {
if (of_find_property(np, "samsung,supports-6ch", NULL))
quirks |= QUIRK_PRI_6CHAN;
if (of_find_property(np, "samsung,supports-secdai", NULL))
quirks |= QUIRK_SEC_DAI;
if (of_find_property(np, "samsung,supports-rstclr", NULL))
quirks |= QUIRK_NEED_RSTCLR;
if (of_property_read_u32(np, "samsung,idma-addr",
&idma_addr)) {
if (quirks & QUIRK_SEC_DAI) {
dev_err(&pdev->dev, "idma address is not"\
"specified");
return -EINVAL;
}
}
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
@@ -1051,24 +1181,14 @@ static int samsung_i2s_probe(struct platform_device *pdev)
}
regs_base = res->start;
i2s_cfg = &i2s_pdata->type.i2s;
quirks = i2s_cfg->quirks;
pri_dai = i2s_alloc_dai(pdev, false);
if (!pri_dai) {
dev_err(&pdev->dev, "Unable to alloc I2S_pri\n");
ret = -ENOMEM;
goto err;
}
pri_dai->dma_playback.dma_addr = regs_base + I2STXD;
pri_dai->dma_capture.dma_addr = regs_base + I2SRXD;
pri_dai->dma_playback.client =
(struct s3c2410_dma_client *)&pri_dai->dma_playback;
pri_dai->dma_playback.ch_name = "tx";
pri_dai->dma_capture.client =
(struct s3c2410_dma_client *)&pri_dai->dma_capture;
pri_dai->dma_playback.channel = dma_pl_chan;
pri_dai->dma_capture.channel = dma_cp_chan;
pri_dai->dma_capture.ch_name = "rx";
pri_dai->dma_playback.dma_size = 4;
pri_dai->dma_capture.dma_size = 4;
pri_dai->base = regs_base;
@@ -1087,20 +1207,34 @@ static int samsung_i2s_probe(struct platform_device *pdev)
sec_dai->dma_playback.dma_addr = regs_base + I2STXDS;
sec_dai->dma_playback.client =
(struct s3c2410_dma_client *)&sec_dai->dma_playback;
/* Use iDMA always if SysDMA not provided */
sec_dai->dma_playback.channel = dma_pl_sec_chan ? : -1;
sec_dai->dma_playback.ch_name = "tx-sec";
if (!np) {
res = platform_get_resource(pdev, IORESOURCE_DMA, 2);
if (res)
sec_dai->dma_playback.channel = res->start;
}
sec_dai->dma_playback.dma_size = 4;
sec_dai->base = regs_base;
sec_dai->quirks = quirks;
sec_dai->idma_playback.dma_addr = i2s_cfg->idma_addr;
sec_dai->idma_playback.dma_addr = idma_addr;
sec_dai->pri_dai = pri_dai;
pri_dai->sec_dai = sec_dai;
}
if (i2s_pdata->cfg_gpio && i2s_pdata->cfg_gpio(pdev)) {
dev_err(&pdev->dev, "Unable to configure gpio\n");
ret = -EINVAL;
goto err;
if (np) {
if (samsung_i2s_parse_dt_gpio(pri_dai)) {
dev_err(&pdev->dev, "Unable to configure gpio\n");
ret = -EINVAL;
goto err;
}
} else {
if (i2s_pdata->cfg_gpio && i2s_pdata->cfg_gpio(pdev)) {
dev_err(&pdev->dev, "Unable to configure gpio\n");
ret = -EINVAL;
goto err;
}
}
snd_soc_register_dai(&pri_dai->pdev->dev, &pri_dai->i2s_dai_drv);
@@ -1120,10 +1254,14 @@ static int samsung_i2s_remove(struct platform_device *pdev)
{
struct i2s_dai *i2s, *other;
struct resource *res;
struct s3c_audio_pdata *i2s_pdata = pdev->dev.platform_data;
i2s = dev_get_drvdata(&pdev->dev);
other = i2s->pri_dai ? : i2s->sec_dai;
if (!i2s_pdata->cfg_gpio && pdev->dev.of_node)
samsung_i2s_dt_gpio_free(i2s->pri_dai);
if (other) {
other->pri_dai = NULL;
other->sec_dai = NULL;
@@ -1143,12 +1281,47 @@ static int samsung_i2s_remove(struct platform_device *pdev)
return 0;
}
static struct platform_device_id samsung_i2s_driver_ids[] = {
{
.name = "samsung-i2s",
.driver_data = TYPE_PRI,
}, {
.name = "samsung-i2s-sec",
.driver_data = TYPE_SEC,
},
{},
};
MODULE_DEVICE_TABLE(platform, samsung-i2s-driver-ids);
#ifdef CONFIG_OF
static struct samsung_i2s_dai_data samsung_i2s_dai_data_array[] = {
[TYPE_PRI] = { TYPE_PRI },
[TYPE_SEC] = { TYPE_SEC },
};
static const struct of_device_id exynos_i2s_match[] = {
{ .compatible = "samsung,i2s-v5",
.data = &samsung_i2s_dai_data_array[TYPE_PRI],
},
{},
};
MODULE_DEVICE_TABLE(of, exynos_i2s_match);
#endif
static const struct dev_pm_ops samsung_i2s_pm = {
SET_RUNTIME_PM_OPS(i2s_runtime_suspend,
i2s_runtime_resume, NULL)
};
static struct platform_driver samsung_i2s_driver = {
.probe = samsung_i2s_probe,
.remove = samsung_i2s_remove,
.id_table = samsung_i2s_driver_ids,
.driver = {
.name = "samsung-i2s",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(exynos_i2s_match),
.pm = &samsung_i2s_pm,
},
};

View File

@@ -13,13 +13,6 @@
#ifndef __SND_SOC_SAMSUNG_I2S_H
#define __SND_SOC_SAMSUNG_I2S_H
/*
* Maximum number of I2S blocks that any SoC can have.
* The secondary interface of a CPU dai(if there exists any),
* is indexed at [cpu-dai's ID + SAMSUNG_I2S_SECOFF]
*/
#define SAMSUNG_I2S_SECOFF 4
#define SAMSUNG_I2S_DIV_BCLK 1
#define SAMSUNG_I2S_RCLKSRC_0 0

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