Merge remote-tracking branch 'asoc/fix/fsl' into asoc-linus

This commit is contained in:
Mark Brown 2013-09-11 11:17:15 +01:00
commit c34c0d7684
63 changed files with 2174 additions and 5017 deletions

View file

@ -0,0 +1,34 @@
Freescale i.MX audio complex with S/PDIF transceiver
Required properties:
- compatible : "fsl,imx-audio-spdif"
- model : The user-visible name of this sound complex
- spdif-controller : The phandle of the i.MX S/PDIF controller
Optional properties:
- spdif-out : This is a boolean property. If present, the transmitting
function of S/PDIF will be enabled, indicating there's a physical
S/PDIF out connector/jack on the board or it's connecting to some
other IP block, such as an HDMI encoder/display-controller.
- spdif-in : This is a boolean property. If present, the receiving
function of S/PDIF will be enabled, indicating there's a physical
S/PDIF in connector/jack on the board.
* Note: At least one of these two properties should be set in the DT binding.
Example:
sound-spdif {
compatible = "fsl,imx-audio-spdif";
model = "imx-spdif";
spdif-controller = <&spdif>;
spdif-out;
spdif-in;
};

View file

@ -0,0 +1,29 @@
* mvebu (Kirkwood, Dove, Armada 370) audio controller
Required properties:
- compatible: "marvell,mvebu-audio"
- reg: physical base address of the controller and length of memory mapped
region.
- interrupts: list of two irq numbers.
The first irq is used for data flow and the second one is used for errors.
- clocks: one or two phandles.
The first one is mandatory and defines the internal clock.
The second one is optional and defines an external clock.
- clock-names: names associated to the clocks:
"internal" for the internal clock
"extclk" for the external clock
Example:
i2s1: audio-controller@b4000 {
compatible = "marvell,mvebu-audio";
reg = <0xb4000 0x2210>;
interrupts = <21>, <22>;
clocks = <&gate_clk 13>;
clock-names = "internal";
};

View file

@ -244,6 +244,7 @@ STAC9227/9228/9229/927x
5stack-no-fp D965 5stack without front panel
dell-3stack Dell Dimension E520
dell-bios Fixes with Dell BIOS setup
dell-bios-amic Fixes with Dell BIOS setup including analog mic
volknob Fixes with volume-knob widget 0x24
auto BIOS setup (default)

View file

@ -454,6 +454,8 @@ The generic parser supports the following hints:
- need_dac_fix (bool): limits the DACs depending on the channel count
- primary_hp (bool): probe headphone jacks as the primary outputs;
default true
- multi_io (bool): try probing multi-I/O config (e.g. shared
line-in/surround, mic/clfe jacks)
- multi_cap_vol (bool): provide multiple capture volumes
- inv_dmic_split (bool): provide split internal mic volume/switch for
phase-inverted digital mics

View file

@ -7676,6 +7676,17 @@ F: include/sound/
F: include/uapi/sound/
F: sound/
SOUND - COMPRESSED AUDIO
M: Vinod Koul <vinod.koul@intel.com>
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
T: git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
S: Supported
F: Documentation/sound/alsa/compress_offload.txt
F: include/sound/compress_driver.h
F: include/uapi/sound/compress_*
F: sound/core/compress_offload.c
F: sound/soc/soc-compress.c
SOUND - SOC LAYER / DYNAMIC AUDIO POWER MANAGEMENT (ASoC)
M: Liam Girdwood <lgirdwood@gmail.com>
M: Mark Brown <broonie@kernel.org>

View file

@ -82,7 +82,8 @@ static int s3c_dma_config(unsigned ch, struct samsung_dma_config *param)
static int s3c_dma_prepare(unsigned ch, struct samsung_dma_prep *param)
{
struct cb_data *data;
int len = (param->cap == DMA_CYCLIC) ? param->period : param->len;
dma_addr_t pos = param->buf;
dma_addr_t end = param->buf + param->len;
list_for_each_entry(data, &dma_list, node)
if (data->ch == ch)
@ -94,7 +95,15 @@ static int s3c_dma_prepare(unsigned ch, struct samsung_dma_prep *param)
data->fp_param = param->fp_param;
}
s3c2410_dma_enqueue(ch, (void *)data, param->buf, len);
if (param->cap != DMA_CYCLIC) {
s3c2410_dma_enqueue(ch, (void *)data, param->buf, param->len);
return 0;
}
while (pos < end) {
s3c2410_dma_enqueue(ch, (void *)data, pos, param->period);
pos += param->period;
}
return 0;
}

View file

@ -27,6 +27,7 @@
#include <linux/rwsem.h> /* struct rw_semaphore */
#include <linux/pm.h> /* pm_message_t */
#include <linux/stringify.h>
#include <linux/printk.h>
/* number of supported soundcards */
#ifdef CONFIG_SND_DYNAMIC_MINORS
@ -375,6 +376,11 @@ void __snd_printk(unsigned int level, const char *file, int line,
*/
#define snd_BUG() WARN(1, "BUG?\n")
/**
* Suppress high rates of output when CONFIG_SND_DEBUG is enabled.
*/
#define snd_printd_ratelimit() printk_ratelimit()
/**
* snd_BUG_ON - debugging check macro
* @cond: condition to evaluate
@ -398,6 +404,8 @@ static inline void _snd_printd(int level, const char *format, ...) {}
unlikely(__ret_warn_on); \
})
static inline bool snd_printd_ratelimit(void) { return false; }
#endif /* CONFIG_SND_DEBUG */
#ifdef CONFIG_SND_DEBUG_VERBOSE

View file

@ -413,7 +413,7 @@ int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
struct snd_soc_dapm_widget *sink);
/* dapm path setup */
int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm);
int snd_soc_dapm_new_widgets(struct snd_soc_card *card);
void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm);
int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
const struct snd_soc_dapm_route *route, int num);

View file

@ -697,7 +697,6 @@ struct snd_soc_codec {
unsigned int probed:1; /* Codec has been probed */
unsigned int ac97_registered:1; /* Codec has been AC97 registered */
unsigned int ac97_created:1; /* Codec has been created by SoC */
unsigned int sysfs_registered:1; /* codec has been sysfs registered */
unsigned int cache_init:1; /* codec cache has been initialized */
unsigned int using_regmap:1; /* using regmap access */
u32 cache_only; /* Suppress writes to hardware */
@ -705,7 +704,6 @@ struct snd_soc_codec {
/* codec IO */
void *control_data; /* codec control (i2c/3wire) data */
enum snd_soc_control_type control_type;
hw_write_t hw_write;
unsigned int (*hw_read)(struct snd_soc_codec *, unsigned int);
unsigned int (*read)(struct snd_soc_codec *, unsigned int);
@ -724,7 +722,6 @@ struct snd_soc_codec {
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs_codec_root;
struct dentry *debugfs_reg;
struct dentry *debugfs_dapm;
#endif
};
@ -849,7 +846,6 @@ struct snd_soc_platform {
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs_platform_root;
struct dentry *debugfs_dapm;
#endif
};
@ -934,6 +930,10 @@ struct snd_soc_dai_link {
/* machine stream operations */
const struct snd_soc_ops *ops;
const struct snd_soc_compr_ops *compr_ops;
/* For unidirectional dai links */
bool playback_only;
bool capture_only;
};
struct snd_soc_codec_conf {

View file

@ -111,7 +111,7 @@ struct hdspm_ltc {
enum hdspm_ltc_input_format input_format;
};
#define SNDRV_HDSPM_IOCTL_GET_LTC _IOR('H', 0x46, struct hdspm_mixer_ioctl)
#define SNDRV_HDSPM_IOCTL_GET_LTC _IOR('H', 0x46, struct hdspm_ltc)
/**
* The status data reflects the device's current state

View file

@ -184,7 +184,7 @@ static void xrun(struct snd_pcm_substream *substream)
do { \
if (xrun_debug(substream, XRUN_DEBUG_BASIC)) { \
xrun_log_show(substream); \
if (printk_ratelimit()) { \
if (snd_printd_ratelimit()) { \
snd_printd("PCM: " fmt, ##args); \
} \
dump_stack_on_xrun(substream); \
@ -342,7 +342,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
return -EPIPE;
}
if (pos >= runtime->buffer_size) {
if (printk_ratelimit()) {
if (snd_printd_ratelimit()) {
char name[16];
snd_pcm_debug_name(substream, name, sizeof(name));
xrun_log_show(substream);

View file

@ -1022,7 +1022,7 @@ static void dummy_proc_write(struct snd_info_entry *entry,
if (i >= ARRAY_SIZE(fields))
continue;
snd_info_get_str(item, ptr, sizeof(item));
if (strict_strtoull(item, 0, &val))
if (kstrtoull(item, 0, &val))
continue;
if (fields[i].size == sizeof(int))
*get_dummy_int_ptr(dummy, fields[i].offset) = val;

View file

@ -49,7 +49,6 @@ struct fwspk {
struct snd_card *card;
struct fw_unit *unit;
const struct device_info *device_info;
struct snd_pcm_substream *pcm;
struct mutex mutex;
struct cmp_connection connection;
struct amdtp_out_stream stream;
@ -363,8 +362,7 @@ static int fwspk_create_pcm(struct fwspk *fwspk)
return err;
pcm->private_data = fwspk;
strcpy(pcm->name, fwspk->device_info->short_name);
fwspk->pcm = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
fwspk->pcm->ops = &ops;
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &ops);
return 0;
}

View file

@ -443,8 +443,7 @@ static void snd_interwave_detect_memory(struct snd_gus_card *gus)
for (i = 0; i < 8; ++i)
iwave[i] = snd_gf1_peek(gus, bank_pos + i);
#ifdef CONFIG_SND_DEBUG_ROM
printk(KERN_DEBUG "ROM at 0x%06x = %*phC\n", bank_pos,
8, iwave);
printk(KERN_DEBUG "ROM at 0x%06x = %8phC\n", bank_pos, iwave);
#endif
if (strncmp(iwave, "INTRWAVE", 8))
continue; /* first check */

View file

@ -557,7 +557,6 @@ int DMAbuf_getrdbuffer(int dev, char **buf, int *len, int dontblock)
unsigned long flags;
int err = 0, n = 0;
struct dma_buffparms *dmap = adev->dmap_in;
int go;
if (!(adev->open_mode & OPEN_READ))
return -EIO;
@ -584,7 +583,7 @@ int DMAbuf_getrdbuffer(int dev, char **buf, int *len, int dontblock)
spin_unlock_irqrestore(&dmap->lock,flags);
return -EAGAIN;
}
if ((go = adev->go))
if (adev->go)
timeout = dmabuf_timeout(dmap);
spin_unlock_irqrestore(&dmap->lock,flags);

View file

@ -152,14 +152,9 @@ config SND_HDA_CODEC_HDMI
This module is automatically loaded at probing.
config SND_HDA_I915
bool "Build Display HD-audio controller/codec power well support for i915 cards"
bool
default y
depends on DRM_I915
help
Say Y here to include full HDMI and DisplayPort HD-audio controller/codec
power-well support for Intel Haswell graphics cards based on the i915 driver.
Note that this option must be enabled for Intel Haswell C+ stepping machines, otherwise
the GPU audio controller/codecs will not be initialized or damaged when exit from S3 mode.
config SND_HDA_CODEC_CIRRUS
bool "Build Cirrus Logic codec support"

View file

@ -666,6 +666,64 @@ int snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux,
}
EXPORT_SYMBOL_HDA(snd_hda_get_conn_index);
/* return DEVLIST_LEN parameter of the given widget */
static unsigned int get_num_devices(struct hda_codec *codec, hda_nid_t nid)
{
unsigned int wcaps = get_wcaps(codec, nid);
unsigned int parm;
if (!codec->dp_mst || !(wcaps & AC_WCAP_DIGITAL) ||
get_wcaps_type(wcaps) != AC_WID_PIN)
return 0;
parm = snd_hda_param_read(codec, nid, AC_PAR_DEVLIST_LEN);
if (parm == -1 && codec->bus->rirb_error)
parm = 0;
return parm & AC_DEV_LIST_LEN_MASK;
}
/**
* snd_hda_get_devices - copy device list without cache
* @codec: the HDA codec
* @nid: NID of the pin to parse
* @dev_list: device list array
* @max_devices: max. number of devices to store
*
* Copy the device list. This info is dynamic and so not cached.
* Currently called only from hda_proc.c, so not exported.
*/
int snd_hda_get_devices(struct hda_codec *codec, hda_nid_t nid,
u8 *dev_list, int max_devices)
{
unsigned int parm;
int i, dev_len, devices;
parm = get_num_devices(codec, nid);
if (!parm) /* not multi-stream capable */
return 0;
dev_len = parm + 1;
dev_len = dev_len < max_devices ? dev_len : max_devices;
devices = 0;
while (devices < dev_len) {
parm = snd_hda_codec_read(codec, nid, 0,
AC_VERB_GET_DEVICE_LIST, devices);
if (parm == -1 && codec->bus->rirb_error)
break;
for (i = 0; i < 8; i++) {
dev_list[devices] = (u8)parm;
parm >>= 4;
devices++;
if (devices >= dev_len)
break;
}
}
return devices;
}
/**
* snd_hda_queue_unsol_event - add an unsolicited event to queue
* @bus: the BUS
@ -1216,11 +1274,13 @@ static void hda_jackpoll_work(struct work_struct *work)
{
struct hda_codec *codec =
container_of(work, struct hda_codec, jackpoll_work.work);
if (!codec->jackpoll_interval)
return;
snd_hda_jack_set_dirty_all(codec);
snd_hda_jack_poll_all(codec);
if (!codec->jackpoll_interval)
return;
queue_delayed_work(codec->bus->workq, &codec->jackpoll_work,
codec->jackpoll_interval);
}

View file

@ -94,6 +94,8 @@ enum {
#define AC_VERB_GET_HDMI_DIP_XMIT 0x0f32
#define AC_VERB_GET_HDMI_CP_CTRL 0x0f33
#define AC_VERB_GET_HDMI_CHAN_SLOT 0x0f34
#define AC_VERB_GET_DEVICE_SEL 0xf35
#define AC_VERB_GET_DEVICE_LIST 0xf36
/*
* SET verbs
@ -133,6 +135,7 @@ enum {
#define AC_VERB_SET_HDMI_DIP_XMIT 0x732
#define AC_VERB_SET_HDMI_CP_CTRL 0x733
#define AC_VERB_SET_HDMI_CHAN_SLOT 0x734
#define AC_VERB_SET_DEVICE_SEL 0x735
/*
* Parameter IDs
@ -154,6 +157,7 @@ enum {
#define AC_PAR_GPIO_CAP 0x11
#define AC_PAR_AMP_OUT_CAP 0x12
#define AC_PAR_VOL_KNB_CAP 0x13
#define AC_PAR_DEVLIST_LEN 0x15
#define AC_PAR_HDMI_LPCM_CAP 0x20
/*
@ -251,6 +255,11 @@ enum {
#define AC_UNSOL_RES_TAG_SHIFT 26
#define AC_UNSOL_RES_SUBTAG (0x1f<<21)
#define AC_UNSOL_RES_SUBTAG_SHIFT 21
#define AC_UNSOL_RES_DE (0x3f<<15) /* Device Entry
* (for DP1.2 MST)
*/
#define AC_UNSOL_RES_DE_SHIFT 15
#define AC_UNSOL_RES_IA (1<<2) /* Inactive (for DP1.2 MST) */
#define AC_UNSOL_RES_ELDV (1<<1) /* ELD Data valid (for HDMI) */
#define AC_UNSOL_RES_PD (1<<0) /* pinsense detect */
#define AC_UNSOL_RES_CP_STATE (1<<1) /* content protection */
@ -352,6 +361,10 @@ enum {
#define AC_LPCMCAP_44K (1<<30) /* 44.1kHz support */
#define AC_LPCMCAP_44K_MS (1<<31) /* 44.1kHz-multiplies support */
/* Display pin's device list length */
#define AC_DEV_LIST_LEN_MASK 0x3f
#define AC_MAX_DEV_LIST_LEN 64
/*
* Control Parameters
*/
@ -460,6 +473,11 @@ enum {
#define AC_DEFCFG_PORT_CONN (0x3<<30)
#define AC_DEFCFG_PORT_CONN_SHIFT 30
/* Display pin's device list entry */
#define AC_DE_PD (1<<0)
#define AC_DE_ELDV (1<<1)
#define AC_DE_IA (1<<2)
/* device device types (0x0-0xf) */
enum {
AC_JACK_LINE_OUT,
@ -885,6 +903,7 @@ struct hda_codec {
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 */
unsigned int dp_mst:1; /* support DP1.2 Multi-stream transport */
#ifdef CONFIG_PM
unsigned int power_on :1; /* current (global) power-state */
unsigned int d3_stop_clk:1; /* support D3 operation without BCLK */
@ -972,6 +991,8 @@ 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,
hda_nid_t nid, int recursive);
int snd_hda_get_devices(struct hda_codec *codec, hda_nid_t nid,
u8 *dev_list, int max_devices);
int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
u32 *ratesp, u64 *formatsp, unsigned int *bpsp);

View file

@ -142,6 +142,9 @@ static void parse_user_hints(struct hda_codec *codec)
val = snd_hda_get_bool_hint(codec, "primary_hp");
if (val >= 0)
spec->no_primary_hp = !val;
val = snd_hda_get_bool_hint(codec, "multi_io");
if (val >= 0)
spec->no_multi_io = !val;
val = snd_hda_get_bool_hint(codec, "multi_cap_vol");
if (val >= 0)
spec->multi_cap_vol = !!val;
@ -813,6 +816,8 @@ static void resume_path_from_idx(struct hda_codec *codec, int path_idx)
static int hda_gen_mixer_mute_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
static int hda_gen_bind_mute_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
enum {
HDA_CTL_WIDGET_VOL,
@ -830,7 +835,13 @@ static const struct snd_kcontrol_new control_templates[] = {
.put = hda_gen_mixer_mute_put, /* replaced */
.private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0),
},
HDA_BIND_MUTE(NULL, 0, 0, 0),
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.info = snd_hda_mixer_amp_switch_info,
.get = snd_hda_mixer_bind_switch_get,
.put = hda_gen_bind_mute_put, /* replaced */
.private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0),
},
};
/* add dynamic controls from template */
@ -937,8 +948,8 @@ static int add_stereo_sw(struct hda_codec *codec, const char *pfx,
}
/* playback mute control with the software mute bit check */
static int hda_gen_mixer_mute_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
static void sync_auto_mute_bits(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct hda_gen_spec *spec = codec->spec;
@ -949,10 +960,22 @@ static int hda_gen_mixer_mute_put(struct snd_kcontrol *kcontrol,
ucontrol->value.integer.value[0] &= enabled;
ucontrol->value.integer.value[1] &= enabled;
}
}
static int hda_gen_mixer_mute_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
sync_auto_mute_bits(kcontrol, ucontrol);
return snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
}
static int hda_gen_bind_mute_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
sync_auto_mute_bits(kcontrol, ucontrol);
return snd_hda_mixer_bind_switch_put(kcontrol, ucontrol);
}
/* any ctl assigned to the path with the given index? */
static bool path_has_mixer(struct hda_codec *codec, int path_idx, int ctl_type)
{
@ -1541,7 +1564,8 @@ static int fill_and_eval_dacs(struct hda_codec *codec,
cfg->speaker_pins,
spec->multiout.extra_out_nid,
spec->speaker_paths);
if (fill_mio_first && cfg->line_outs == 1 &&
if (!spec->no_multi_io &&
fill_mio_first && cfg->line_outs == 1 &&
cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
err = fill_multi_ios(codec, cfg->line_out_pins[0], true);
if (!err)
@ -1554,7 +1578,7 @@ static int fill_and_eval_dacs(struct hda_codec *codec,
spec->private_dac_nids, spec->out_paths,
spec->main_out_badness);
if (fill_mio_first &&
if (!spec->no_multi_io && fill_mio_first &&
cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
/* try to fill multi-io first */
err = fill_multi_ios(codec, cfg->line_out_pins[0], false);
@ -1582,7 +1606,8 @@ static int fill_and_eval_dacs(struct hda_codec *codec,
return err;
badness += err;
}
if (cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
if (!spec->no_multi_io &&
cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
err = fill_multi_ios(codec, cfg->line_out_pins[0], false);
if (err < 0)
return err;
@ -1600,7 +1625,8 @@ static int fill_and_eval_dacs(struct hda_codec *codec,
check_aamix_out_path(codec, spec->speaker_paths[0]);
}
if (cfg->hp_outs && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
if (!spec->no_multi_io &&
cfg->hp_outs && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
if (count_multiio_pins(codec, cfg->hp_pins[0]) >= 2)
spec->multi_ios = 1; /* give badness */
@ -3724,7 +3750,8 @@ static int mux_select(struct hda_codec *codec, unsigned int adc_idx,
/* check each pin in the given array; returns true if any of them is plugged */
static bool detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins)
{
int i, present = 0;
int i;
bool present = false;
for (i = 0; i < num_pins; i++) {
hda_nid_t nid = pins[i];
@ -3733,14 +3760,15 @@ static bool detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins)
/* don't detect pins retasked as inputs */
if (snd_hda_codec_get_pin_target(codec, nid) & AC_PINCTL_IN_EN)
continue;
present |= snd_hda_jack_detect(codec, nid);
if (snd_hda_jack_detect_state(codec, nid) == HDA_JACK_PRESENT)
present = true;
}
return present;
}
/* standard HP/line-out auto-mute helper */
static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins,
bool mute)
int *paths, bool mute)
{
struct hda_gen_spec *spec = codec->spec;
int i;
@ -3752,10 +3780,19 @@ static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins,
break;
if (spec->auto_mute_via_amp) {
struct nid_path *path;
hda_nid_t mute_nid;
path = snd_hda_get_path_from_idx(codec, paths[i]);
if (!path)
continue;
mute_nid = get_amp_nid_(path->ctls[NID_PATH_MUTE_CTL]);
if (!mute_nid)
continue;
if (mute)
spec->mute_bits |= (1ULL << nid);
spec->mute_bits |= (1ULL << mute_nid);
else
spec->mute_bits &= ~(1ULL << nid);
spec->mute_bits &= ~(1ULL << mute_nid);
set_pin_eapd(codec, nid, !mute);
continue;
}
@ -3786,14 +3823,19 @@ static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins,
void snd_hda_gen_update_outputs(struct hda_codec *codec)
{
struct hda_gen_spec *spec = codec->spec;
int *paths;
int on;
/* Control HP pins/amps depending on master_mute state;
* in general, HP pins/amps control should be enabled in all cases,
* but currently set only for master_mute, just to be safe
*/
if (spec->autocfg.line_out_type == AUTO_PIN_HP_OUT)
paths = spec->out_paths;
else
paths = spec->hp_paths;
do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins),
spec->autocfg.hp_pins, spec->master_mute);
spec->autocfg.hp_pins, paths, spec->master_mute);
if (!spec->automute_speaker)
on = 0;
@ -3801,8 +3843,12 @@ void snd_hda_gen_update_outputs(struct hda_codec *codec)
on = spec->hp_jack_present | spec->line_jack_present;
on |= spec->master_mute;
spec->speaker_muted = on;
if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT)
paths = spec->out_paths;
else
paths = spec->speaker_paths;
do_automute(codec, ARRAY_SIZE(spec->autocfg.speaker_pins),
spec->autocfg.speaker_pins, on);
spec->autocfg.speaker_pins, paths, on);
/* toggle line-out mutes if needed, too */
/* if LO is a copy of either HP or Speaker, don't need to handle it */
@ -3815,8 +3861,9 @@ void snd_hda_gen_update_outputs(struct hda_codec *codec)
on = spec->hp_jack_present;
on |= spec->master_mute;
spec->line_out_muted = on;
paths = spec->out_paths;
do_automute(codec, ARRAY_SIZE(spec->autocfg.line_out_pins),
spec->autocfg.line_out_pins, on);
spec->autocfg.line_out_pins, paths, on);
}
EXPORT_SYMBOL_HDA(snd_hda_gen_update_outputs);
@ -3887,7 +3934,7 @@ void snd_hda_gen_mic_autoswitch(struct hda_codec *codec, struct hda_jack_tbl *ja
/* don't detect pins retasked as outputs */
if (snd_hda_codec_get_pin_target(codec, pin) & AC_PINCTL_OUT_EN)
continue;
if (snd_hda_jack_detect(codec, pin)) {
if (snd_hda_jack_detect_state(codec, pin) == HDA_JACK_PRESENT) {
mux_select(codec, 0, spec->am_entry[i].idx);
return;
}

View file

@ -220,6 +220,7 @@ struct hda_gen_spec {
unsigned int hp_mic:1; /* Allow HP as a mic-in */
unsigned int suppress_hp_mic_detect:1; /* Don't detect HP/mic */
unsigned int no_primary_hp:1; /* Don't prefer HP pins to speaker pins */
unsigned int no_multi_io:1; /* Don't try multi I/O config */
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 */

View file

@ -295,7 +295,7 @@ static ssize_t type##_store(struct device *dev, \
struct snd_hwdep *hwdep = dev_get_drvdata(dev); \
struct hda_codec *codec = hwdep->private_data; \
unsigned long val; \
int err = strict_strtoul(buf, 0, &val); \
int err = kstrtoul(buf, 0, &val); \
if (err < 0) \
return err; \
codec->type = val; \
@ -654,7 +654,7 @@ int snd_hda_get_int_hint(struct hda_codec *codec, const char *key, int *valp)
p = snd_hda_get_hint(codec, key);
if (!p)
ret = -ENOENT;
else if (strict_strtoul(p, 0, &val))
else if (kstrtoul(p, 0, &val))
ret = -EINVAL;
else {
*valp = val;
@ -751,7 +751,7 @@ static void parse_##name##_mode(char *buf, struct hda_bus *bus, \
struct hda_codec **codecp) \
{ \
unsigned long val; \
if (!strict_strtoul(buf, 0, &val)) \
if (!kstrtoul(buf, 0, &val)) \
(*codecp)->name = val; \
}

View file

@ -1160,7 +1160,7 @@ static int azx_reset(struct azx *chip, int full_reset)
goto __skip;
/* clear STATESTS */
azx_writeb(chip, STATESTS, STATESTS_INT_MASK);
azx_writew(chip, STATESTS, STATESTS_INT_MASK);
/* reset controller */
azx_enter_link_reset(chip);
@ -1242,7 +1242,7 @@ static void azx_int_clear(struct azx *chip)
}
/* clear STATESTS */
azx_writeb(chip, STATESTS, STATESTS_INT_MASK);
azx_writew(chip, STATESTS, STATESTS_INT_MASK);
/* clear rirb status */
azx_writeb(chip, RIRBSTS, RIRB_INT_MASK);
@ -1451,8 +1451,8 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
#if 0
/* clear state status int */
if (azx_readb(chip, STATESTS) & 0x04)
azx_writeb(chip, STATESTS, 0x04);
if (azx_readw(chip, STATESTS) & 0x04)
azx_writew(chip, STATESTS, 0x04);
#endif
spin_unlock(&chip->reg_lock);
@ -2971,6 +2971,10 @@ static int azx_runtime_suspend(struct device *dev)
struct snd_card *card = dev_get_drvdata(dev);
struct azx *chip = card->private_data;
/* enable controller wake up event */
azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) |
STATESTS_INT_MASK);
azx_stop_chip(chip);
azx_enter_link_reset(chip);
azx_clear_irq_pending(chip);
@ -2983,11 +2987,31 @@ static int azx_runtime_resume(struct device *dev)
{
struct snd_card *card = dev_get_drvdata(dev);
struct azx *chip = card->private_data;
struct hda_bus *bus;
struct hda_codec *codec;
int status;
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
hda_display_power(true);
/* Read STATESTS before controller reset */
status = azx_readw(chip, STATESTS);
azx_init_pci(chip);
azx_init_chip(chip, 1);
bus = chip->bus;
if (status && bus) {
list_for_each_entry(codec, &bus->codec_list, list)
if (status & (1 << codec->addr))
queue_delayed_work(codec->bus->workq,
&codec->jackpoll_work, codec->jackpoll_interval);
}
/* disable controller Wake Up event*/
azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) &
~STATESTS_INT_MASK);
return 0;
}
@ -3831,11 +3855,13 @@ static int azx_probe_continue(struct azx *chip)
/* Request power well for Haswell HDA controller and codec */
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
#ifdef CONFIG_SND_HDA_I915
err = hda_i915_init();
if (err < 0) {
snd_printk(KERN_ERR SFX "Error request power-well from i915\n");
goto out_free;
}
#endif
hda_display_power(true);
}

View file

@ -194,18 +194,24 @@ u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid)
EXPORT_SYMBOL_HDA(snd_hda_pin_sense);
/**
* snd_hda_jack_detect - query pin Presence Detect status
* snd_hda_jack_detect_state - query pin Presence Detect status
* @codec: the CODEC to sense
* @nid: the pin NID to sense
*
* Query and return the pin's Presence Detect status.
* Query and return the pin's Presence Detect status, as either
* HDA_JACK_NOT_PRESENT, HDA_JACK_PRESENT or HDA_JACK_PHANTOM.
*/
int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid)
int snd_hda_jack_detect_state(struct hda_codec *codec, hda_nid_t nid)
{
u32 sense = snd_hda_pin_sense(codec, nid);
return get_jack_plug_state(sense);
struct hda_jack_tbl *jack = snd_hda_jack_tbl_get(codec, nid);
if (jack && jack->phantom_jack)
return HDA_JACK_PHANTOM;
else if (snd_hda_pin_sense(codec, nid) & AC_PINSENSE_PRESENCE)
return HDA_JACK_PRESENT;
else
return HDA_JACK_NOT_PRESENT;
}
EXPORT_SYMBOL_HDA(snd_hda_jack_detect);
EXPORT_SYMBOL_HDA(snd_hda_jack_detect_state);
/**
* snd_hda_jack_detect_enable - enable the jack-detection
@ -247,8 +253,8 @@ EXPORT_SYMBOL_HDA(snd_hda_jack_detect_enable);
int snd_hda_jack_set_gating_jack(struct hda_codec *codec, hda_nid_t gated_nid,
hda_nid_t gating_nid)
{
struct hda_jack_tbl *gated = snd_hda_jack_tbl_get(codec, gated_nid);
struct hda_jack_tbl *gating = snd_hda_jack_tbl_get(codec, gating_nid);
struct hda_jack_tbl *gated = snd_hda_jack_tbl_new(codec, gated_nid);
struct hda_jack_tbl *gating = snd_hda_jack_tbl_new(codec, gating_nid);
if (!gated || !gating)
return -EINVAL;

View file

@ -75,7 +75,18 @@ int snd_hda_jack_set_gating_jack(struct hda_codec *codec, hda_nid_t gated_nid,
hda_nid_t gating_nid);
u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid);
int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid);
/* the jack state returned from snd_hda_jack_detect_state() */
enum {
HDA_JACK_NOT_PRESENT, HDA_JACK_PRESENT, HDA_JACK_PHANTOM,
};
int snd_hda_jack_detect_state(struct hda_codec *codec, hda_nid_t nid);
static inline bool snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid)
{
return snd_hda_jack_detect_state(codec, nid) != HDA_JACK_NOT_PRESENT;
}
bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid);

View file

@ -582,6 +582,36 @@ static void print_gpio(struct snd_info_buffer *buffer,
print_nid_array(buffer, codec, nid, &codec->nids);
}
static void print_device_list(struct snd_info_buffer *buffer,
struct hda_codec *codec, hda_nid_t nid)
{
int i, curr = -1;
u8 dev_list[AC_MAX_DEV_LIST_LEN];
int devlist_len;
devlist_len = snd_hda_get_devices(codec, nid, dev_list,
AC_MAX_DEV_LIST_LEN);
snd_iprintf(buffer, " Devices: %d\n", devlist_len);
if (devlist_len <= 0)
return;
curr = snd_hda_codec_read(codec, nid, 0,
AC_VERB_GET_DEVICE_SEL, 0);
for (i = 0; i < devlist_len; i++) {
if (i == curr)
snd_iprintf(buffer, " *");
else
snd_iprintf(buffer, " ");
snd_iprintf(buffer,
"Dev %02d: PD = %d, ELDV = %d, IA = %d\n", i,
!!(dev_list[i] & AC_DE_PD),
!!(dev_list[i] & AC_DE_ELDV),
!!(dev_list[i] & AC_DE_IA));
}
}
static void print_codec_info(struct snd_info_entry *entry,
struct snd_info_buffer *buffer)
{
@ -751,6 +781,9 @@ static void print_codec_info(struct snd_info_entry *entry,
(wid_caps & AC_WCAP_DELAY) >>
AC_WCAP_DELAY_SHIFT);
if (wid_type == AC_WID_PIN && codec->dp_mst)
print_device_list(buffer, codec, nid);
if (wid_caps & AC_WCAP_CONN_LIST)
print_conn_list(buffer, codec, nid, wid_type,
conn, conn_len);

File diff suppressed because it is too large Load diff

View file

@ -66,6 +66,8 @@ struct conexant_spec {
hda_nid_t eapds[4];
bool dynamic_eapd;
unsigned int parse_flags; /* flag for snd_hda_parse_pin_defcfg() */
#ifdef ENABLE_CXT_STATIC_QUIRKS
const struct snd_kcontrol_new *mixers[5];
int num_mixers;
@ -3200,6 +3202,9 @@ static int cx_auto_init(struct hda_codec *codec)
snd_hda_gen_init(codec);
if (!spec->dynamic_eapd)
cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, true);
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT);
return 0;
}
@ -3224,6 +3229,8 @@ enum {
CXT_PINCFG_LEMOTE_A1205,
CXT_FIXUP_STEREO_DMIC,
CXT_FIXUP_INC_MIC_BOOST,
CXT_FIXUP_HEADPHONE_MIC_PIN,
CXT_FIXUP_HEADPHONE_MIC,
};
static void cxt_fixup_stereo_dmic(struct hda_codec *codec,
@ -3246,6 +3253,59 @@ static void cxt5066_increase_mic_boost(struct hda_codec *codec,
(0 << AC_AMPCAP_MUTE_SHIFT));
}
static void cxt_update_headset_mode(struct hda_codec *codec)
{
/* The verbs used in this function were tested on a Conexant CX20751/2 codec. */
int i;
bool mic_mode = false;
struct conexant_spec *spec = codec->spec;
struct auto_pin_cfg *cfg = &spec->gen.autocfg;
hda_nid_t mux_pin = spec->gen.imux_pins[spec->gen.cur_mux[0]];
for (i = 0; i < cfg->num_inputs; i++)
if (cfg->inputs[i].pin == mux_pin) {
mic_mode = !!cfg->inputs[i].is_headphone_mic;
break;
}
if (mic_mode) {
snd_hda_codec_write_cache(codec, 0x1c, 0, 0x410, 0x7c); /* enable merged mode for analog int-mic */
spec->gen.hp_jack_present = false;
} else {
snd_hda_codec_write_cache(codec, 0x1c, 0, 0x410, 0x54); /* disable merged mode for analog int-mic */
spec->gen.hp_jack_present = snd_hda_jack_detect(codec, spec->gen.autocfg.hp_pins[0]);
}
snd_hda_gen_update_outputs(codec);
}
static void cxt_update_headset_mode_hook(struct hda_codec *codec,
struct snd_ctl_elem_value *ucontrol)
{
cxt_update_headset_mode(codec);
}
static void cxt_fixup_headphone_mic(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
struct conexant_spec *spec = codec->spec;
switch (action) {
case HDA_FIXUP_ACT_PRE_PROBE:
spec->parse_flags |= HDA_PINCFG_HEADPHONE_MIC;
break;
case HDA_FIXUP_ACT_PROBE:
spec->gen.cap_sync_hook = cxt_update_headset_mode_hook;
spec->gen.automute_hook = cxt_update_headset_mode;
break;
case HDA_FIXUP_ACT_INIT:
cxt_update_headset_mode(codec);
break;
}
}
/* ThinkPad X200 & co with cxt5051 */
static const struct hda_pintbl cxt_pincfg_lenovo_x200[] = {
{ 0x16, 0x042140ff }, /* HP (seq# overridden) */
@ -3302,6 +3362,19 @@ static const struct hda_fixup cxt_fixups[] = {
.type = HDA_FIXUP_FUNC,
.v.func = cxt5066_increase_mic_boost,
},
[CXT_FIXUP_HEADPHONE_MIC_PIN] = {
.type = HDA_FIXUP_PINS,
.chained = true,
.chain_id = CXT_FIXUP_HEADPHONE_MIC,
.v.pins = (const struct hda_pintbl[]) {
{ 0x18, 0x03a1913d }, /* use as headphone mic, without its own jack detect */
{ }
}
},
[CXT_FIXUP_HEADPHONE_MIC] = {
.type = HDA_FIXUP_FUNC,
.v.func = cxt_fixup_headphone_mic,
},
};
static const struct snd_pci_quirk cxt5051_fixups[] = {
@ -3311,6 +3384,7 @@ static const struct snd_pci_quirk cxt5051_fixups[] = {
static const struct snd_pci_quirk cxt5066_fixups[] = {
SND_PCI_QUIRK(0x1025, 0x0543, "Acer Aspire One 522", CXT_FIXUP_STEREO_DMIC),
SND_PCI_QUIRK(0x1043, 0x138d, "Asus", CXT_FIXUP_HEADPHONE_MIC_PIN),
SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410),
SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo T410", CXT_PINCFG_LENOVO_TP410),
SND_PCI_QUIRK(0x17aa, 0x215f, "Lenovo T510", CXT_PINCFG_LENOVO_TP410),
@ -3395,7 +3469,8 @@ static int patch_conexant_auto(struct hda_codec *codec)
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, 0);
err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL,
spec->parse_flags);
if (err < 0)
goto error;
@ -3416,6 +3491,8 @@ static int patch_conexant_auto(struct hda_codec *codec)
codec->bus->allow_bus_reset = 1;
}
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
return 0;
error:

View file

@ -959,6 +959,7 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
int pin_nid;
int pin_idx;
struct hda_jack_tbl *jack;
int dev_entry = (res & AC_UNSOL_RES_DE) >> AC_UNSOL_RES_DE_SHIFT;
jack = snd_hda_jack_tbl_get_from_tag(codec, tag);
if (!jack)
@ -967,8 +968,8 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
jack->jack_dirty = 1;
_snd_printd(SND_PR_VERBOSE,
"HDMI hot plug event: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n",
codec->addr, pin_nid,
"HDMI hot plug event: Codec=%d Pin=%d Device=%d Inactive=%d Presence_Detect=%d ELD_Valid=%d\n",
codec->addr, pin_nid, dev_entry, !!(res & AC_UNSOL_RES_IA),
!!(res & AC_UNSOL_RES_PD), !!(res & AC_UNSOL_RES_ELDV));
pin_idx = pin_nid_to_pin_index(spec, pin_nid);
@ -1992,8 +1993,10 @@ static int patch_generic_hdmi(struct hda_codec *codec)
return -EINVAL;
}
codec->patch_ops = generic_hdmi_patch_ops;
if (codec->vendor_id == 0x80862807)
if (codec->vendor_id == 0x80862807) {
codec->patch_ops.set_power_state = haswell_set_power_state;
codec->dp_mst = true;
}
generic_hdmi_init_per_pins(codec);

View file

@ -282,6 +282,7 @@ static void alc_eapd_shutup(struct hda_codec *codec)
{
alc_auto_setup_eapd(codec, false);
msleep(200);
snd_hda_shutup_pins(codec);
}
/* generic EAPD initialization */
@ -826,7 +827,8 @@ static inline void alc_shutup(struct hda_codec *codec)
if (spec && spec->shutup)
spec->shutup(codec);
snd_hda_shutup_pins(codec);
else
snd_hda_shutup_pins(codec);
}
#define alc_free snd_hda_gen_free
@ -1853,8 +1855,10 @@ static void alc882_fixup_no_primary_hp(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
struct alc_spec *spec = codec->spec;
if (action == HDA_FIXUP_ACT_PRE_PROBE)
if (action == HDA_FIXUP_ACT_PRE_PROBE) {
spec->gen.no_primary_hp = 1;
spec->gen.no_multi_io = 1;
}
}
static const struct hda_fixup alc882_fixups[] = {
@ -2533,6 +2537,7 @@ enum {
ALC269_TYPE_ALC269VD,
ALC269_TYPE_ALC280,
ALC269_TYPE_ALC282,
ALC269_TYPE_ALC283,
ALC269_TYPE_ALC284,
ALC269_TYPE_ALC286,
};
@ -2558,6 +2563,7 @@ static int alc269_parse_auto_config(struct hda_codec *codec)
case ALC269_TYPE_ALC269VB:
case ALC269_TYPE_ALC269VD:
case ALC269_TYPE_ALC282:
case ALC269_TYPE_ALC283:
case ALC269_TYPE_ALC286:
ssids = alc269_ssids;
break;
@ -2583,15 +2589,81 @@ static void alc269_shutup(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
if (spec->codec_variant != ALC269_TYPE_ALC269VB)
return;
if (spec->codec_variant == ALC269_TYPE_ALC269VB)
alc269vb_toggle_power_output(codec, 0);
if (spec->codec_variant == ALC269_TYPE_ALC269VB &&
(alc_get_coef0(codec) & 0x00ff) == 0x018) {
msleep(150);
}
snd_hda_shutup_pins(codec);
}
static void alc283_init(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0];
bool hp_pin_sense;
int val;
if (!hp_pin)
return;
hp_pin_sense = snd_hda_jack_detect(codec, hp_pin);
/* Index 0x43 Direct Drive HP AMP LPM Control 1 */
/* Headphone capless set to high power mode */
alc_write_coef_idx(codec, 0x43, 0x9004);
snd_hda_codec_write(codec, hp_pin, 0,
AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
if (hp_pin_sense)
msleep(85);
snd_hda_codec_write(codec, hp_pin, 0,
AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
if (hp_pin_sense)
msleep(85);
/* Index 0x46 Combo jack auto switch control 2 */
/* 3k pull low control for Headset jack. */
val = alc_read_coef_idx(codec, 0x46);
alc_write_coef_idx(codec, 0x46, val & ~(3 << 12));
/* Headphone capless set to normal mode */
alc_write_coef_idx(codec, 0x43, 0x9614);
}
static void alc283_shutup(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0];
bool hp_pin_sense;
int val;
if (!hp_pin) {
alc269_shutup(codec);
return;
}
hp_pin_sense = snd_hda_jack_detect(codec, hp_pin);
alc_write_coef_idx(codec, 0x43, 0x9004);
snd_hda_codec_write(codec, hp_pin, 0,
AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
if (hp_pin_sense)
msleep(85);
snd_hda_codec_write(codec, hp_pin, 0,
AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
val = alc_read_coef_idx(codec, 0x46);
alc_write_coef_idx(codec, 0x46, val | (3 << 12));
if (hp_pin_sense)
msleep(85);
snd_hda_shutup_pins(codec);
alc_write_coef_idx(codec, 0x43, 0x9614);
}
static void alc5505_coef_set(struct hda_codec *codec, unsigned int index_reg,
@ -2722,6 +2794,7 @@ static int alc269_resume(struct hda_codec *codec)
hda_call_check_power_status(codec, 0x01);
if (spec->has_alc5505_dsp)
alc5505_dsp_resume(codec);
return 0;
}
#endif /* CONFIG_PM */
@ -3261,6 +3334,28 @@ static void alc_fixup_headset_mode_alc668(struct hda_codec *codec,
alc_fixup_headset_mode(codec, fix, action);
}
/* Returns the nid of the external mic input pin, or 0 if it cannot be found. */
static int find_ext_mic_pin(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
struct auto_pin_cfg *cfg = &spec->gen.autocfg;
hda_nid_t nid;
unsigned int defcfg;
int i;
for (i = 0; i < cfg->num_inputs; i++) {
if (cfg->inputs[i].type != AUTO_PIN_MIC)
continue;
nid = cfg->inputs[i].pin;
defcfg = snd_hda_codec_get_pincfg(codec, nid);
if (snd_hda_get_input_pin_attr(defcfg) == INPUT_PIN_ATTR_INT)
continue;
return nid;
}
return 0;
}
static void alc271_hp_gate_mic_jack(struct hda_codec *codec,
const struct hda_fixup *fix,
int action)
@ -3268,11 +3363,12 @@ static void alc271_hp_gate_mic_jack(struct hda_codec *codec,
struct alc_spec *spec = codec->spec;
if (action == HDA_FIXUP_ACT_PROBE) {
if (snd_BUG_ON(!spec->gen.am_entry[1].pin ||
!spec->gen.autocfg.hp_pins[0]))
int mic_pin = find_ext_mic_pin(codec);
int hp_pin = spec->gen.autocfg.hp_pins[0];
if (snd_BUG_ON(!mic_pin || !hp_pin))
return;
snd_hda_jack_set_gating_jack(codec, spec->gen.am_entry[1].pin,
spec->gen.autocfg.hp_pins[0]);
snd_hda_jack_set_gating_jack(codec, mic_pin, hp_pin);
}
}
@ -3308,6 +3404,45 @@ static void alc269_fixup_limit_int_mic_boost(struct hda_codec *codec,
}
}
static void alc283_hp_automute_hook(struct hda_codec *codec,
struct hda_jack_tbl *jack)
{
struct alc_spec *spec = codec->spec;
int vref;
msleep(200);
snd_hda_gen_hp_automute(codec, jack);
vref = spec->gen.hp_jack_present ? PIN_VREF80 : 0;
msleep(600);
snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
vref);
}
static void alc283_chromebook_caps(struct hda_codec *codec)
{
snd_hda_override_wcaps(codec, 0x03, 0);
}
static void alc283_fixup_chromebook(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
struct alc_spec *spec = codec->spec;
int val;
switch (action) {
case HDA_FIXUP_ACT_PRE_PROBE:
alc283_chromebook_caps(codec);
spec->gen.hp_automute_hook = alc283_hp_automute_hook;
/* MIC2-VREF control */
/* Set to manual mode */
val = alc_read_coef_idx(codec, 0x06);
alc_write_coef_idx(codec, 0x06, val & ~0x000c);
break;
}
}
enum {
ALC269_FIXUP_SONY_VAIO,
ALC275_FIXUP_SONY_VAIO_GPIO2,
@ -3344,6 +3479,7 @@ enum {
ALC269_FIXUP_ACER_AC700,
ALC269_FIXUP_LIMIT_INT_MIC_BOOST,
ALC269VB_FIXUP_ORDISSIMO_EVE2,
ALC283_FIXUP_CHROME_BOOK,
};
static const struct hda_fixup alc269_fixups[] = {
@ -3595,11 +3731,20 @@ static const struct hda_fixup alc269_fixups[] = {
{ }
},
},
[ALC283_FIXUP_CHROME_BOOK] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc283_fixup_chromebook,
},
};
static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1025, 0x029b, "Acer 1810TZ", ALC269_FIXUP_INV_DMIC),
SND_PCI_QUIRK(0x1025, 0x0349, "Acer AOD260", ALC269_FIXUP_INV_DMIC),
SND_PCI_QUIRK(0x1025, 0x047c, "Acer AC700", ALC269_FIXUP_ACER_AC700),
SND_PCI_QUIRK(0x1025, 0x0740, "Acer AO725", ALC271_FIXUP_HP_GATE_MIC_JACK),
SND_PCI_QUIRK(0x1025, 0x0742, "Acer AO756", ALC271_FIXUP_HP_GATE_MIC_JACK),
SND_PCI_QUIRK_VENDOR(0x1025, "Acer Aspire", ALC271_FIXUP_DMIC),
SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z),
SND_PCI_QUIRK(0x1028, 0x05bd, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x05be, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x05c4, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
@ -3637,6 +3782,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x18e6, "HP", ALC269_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x1973, "HP Pavilion", ALC269_FIXUP_HP_MUTE_LED_MIC1),
SND_PCI_QUIRK(0x103c, 0x1983, "HP Pavilion", ALC269_FIXUP_HP_MUTE_LED_MIC1),
SND_PCI_QUIRK(0x103c, 0x21ed, "HP Falco Chromebook", ALC283_FIXUP_CHROME_BOOK),
SND_PCI_QUIRK_VENDOR(0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED),
SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x1043, 0x115d, "Asus 1015E", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
@ -3655,11 +3801,6 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO),
SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z),
SND_PCI_QUIRK(0x1025, 0x047c, "Acer AC700", ALC269_FIXUP_ACER_AC700),
SND_PCI_QUIRK(0x1025, 0x0740, "Acer AO725", ALC271_FIXUP_HP_GATE_MIC_JACK),
SND_PCI_QUIRK(0x1025, 0x0742, "Acer AO756", ALC271_FIXUP_HP_GATE_MIC_JACK),
SND_PCI_QUIRK_VENDOR(0x1025, "Acer Aspire", ALC271_FIXUP_DMIC),
SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook", ALC269_FIXUP_LIFEBOOK),
SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE),
SND_PCI_QUIRK(0x17aa, 0x215e, "Thinkpad L512", ALC269_FIXUP_SKU_IGNORE),
@ -3670,8 +3811,16 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x21fa, "Thinkpad X230", ALC269_FIXUP_LENOVO_DOCK),
SND_PCI_QUIRK(0x17aa, 0x21f3, "Thinkpad T430", ALC269_FIXUP_LENOVO_DOCK),
SND_PCI_QUIRK(0x17aa, 0x21fb, "Thinkpad T430s", ALC269_FIXUP_LENOVO_DOCK),
SND_PCI_QUIRK(0x17aa, 0x2208, "Thinkpad T431s", ALC269_FIXUP_LENOVO_DOCK),
SND_PCI_QUIRK(0x17aa, 0x2203, "Thinkpad X230 Tablet", ALC269_FIXUP_LENOVO_DOCK),
SND_PCI_QUIRK(0x17aa, 0x2208, "Thinkpad T431s", ALC269_FIXUP_LENOVO_DOCK),
SND_PCI_QUIRK(0x17aa, 0x220c, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x17aa, 0x2212, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x17aa, 0x2214, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x17aa, 0x2215, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x17aa, 0x5013, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x17aa, 0x501a, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x17aa, 0x5026, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x17aa, 0x5109, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K),
SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
SND_PCI_QUIRK(0x1b7d, 0xa831, "Ordissimo EVE2 ", ALC269VB_FIXUP_ORDISSIMO_EVE2), /* Also known as Malata PC-B1303 */
@ -3840,11 +3989,15 @@ static int patch_alc269(struct hda_codec *codec)
case 0x10ec0290:
spec->codec_variant = ALC269_TYPE_ALC280;
break;
case 0x10ec0233:
case 0x10ec0282:
case 0x10ec0283:
spec->codec_variant = ALC269_TYPE_ALC282;
break;
case 0x10ec0233:
case 0x10ec0283:
spec->codec_variant = ALC269_TYPE_ALC283;
spec->shutup = alc283_shutup;
spec->init_hook = alc283_init;
break;
case 0x10ec0284:
case 0x10ec0292:
spec->codec_variant = ALC269_TYPE_ALC284;
@ -3872,7 +4025,8 @@ static int patch_alc269(struct hda_codec *codec)
codec->patch_ops.suspend = alc269_suspend;
codec->patch_ops.resume = alc269_resume;
#endif
spec->shutup = alc269_shutup;
if (!spec->shutup)
spec->shutup = alc269_shutup;
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);

View file

@ -158,6 +158,7 @@ enum {
STAC_D965_VERBS,
STAC_DELL_3ST,
STAC_DELL_BIOS,
STAC_DELL_BIOS_AMIC,
STAC_DELL_BIOS_SPDIF,
STAC_927X_DELL_DMIC,
STAC_927X_VOLKNOB,
@ -3231,8 +3232,6 @@ static const struct hda_fixup stac927x_fixups[] = {
[STAC_DELL_BIOS] = {
.type = HDA_FIXUP_PINS,
.v.pins = (const struct hda_pintbl[]) {
/* configure the analog microphone on some laptops */
{ 0x0c, 0x90a79130 },
/* correct the front output jack as a hp out */
{ 0x0f, 0x0221101f },
/* correct the front input jack as a mic */
@ -3242,6 +3241,16 @@ static const struct hda_fixup stac927x_fixups[] = {
.chained = true,
.chain_id = STAC_927X_DELL_DMIC,
},
[STAC_DELL_BIOS_AMIC] = {
.type = HDA_FIXUP_PINS,
.v.pins = (const struct hda_pintbl[]) {
/* configure the analog microphone on some laptops */
{ 0x0c, 0x90a79130 },
{}
},
.chained = true,
.chain_id = STAC_DELL_BIOS,
},
[STAC_DELL_BIOS_SPDIF] = {
.type = HDA_FIXUP_PINS,
.v.pins = (const struct hda_pintbl[]) {
@ -3270,6 +3279,7 @@ static const struct hda_model_fixup stac927x_models[] = {
{ .id = STAC_D965_5ST_NO_FP, .name = "5stack-no-fp" },
{ .id = STAC_DELL_3ST, .name = "dell-3stack" },
{ .id = STAC_DELL_BIOS, .name = "dell-bios" },
{ .id = STAC_DELL_BIOS_AMIC, .name = "dell-bios-amic" },
{ .id = STAC_927X_VOLKNOB, .name = "volknob" },
{}
};

View file

@ -207,9 +207,9 @@ static void vt1708_stop_hp_work(struct hda_codec *codec)
return;
if (spec->hp_work_active) {
snd_hda_codec_write(codec, 0x1, 0, 0xf81, 1);
codec->jackpoll_interval = 0;
cancel_delayed_work_sync(&codec->jackpoll_work);
spec->hp_work_active = false;
codec->jackpoll_interval = 0;
}
}

View file

@ -28,6 +28,7 @@
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/module.h>
#include <linux/vmalloc.h>
#include <sound/core.h>
#include <sound/info.h>
@ -198,6 +199,31 @@ MODULE_PARM_DESC(enable, "Enable RME Digi96 soundcard.");
#define RME96_AD1852_VOL_BITS 14
#define RME96_AD1855_VOL_BITS 10
/* Defines for snd_rme96_trigger */
#define RME96_TB_START_PLAYBACK 1
#define RME96_TB_START_CAPTURE 2
#define RME96_TB_STOP_PLAYBACK 4
#define RME96_TB_STOP_CAPTURE 8
#define RME96_TB_RESET_PLAYPOS 16
#define RME96_TB_RESET_CAPTUREPOS 32
#define RME96_TB_CLEAR_PLAYBACK_IRQ 64
#define RME96_TB_CLEAR_CAPTURE_IRQ 128
#define RME96_RESUME_PLAYBACK (RME96_TB_START_PLAYBACK)
#define RME96_RESUME_CAPTURE (RME96_TB_START_CAPTURE)
#define RME96_RESUME_BOTH (RME96_RESUME_PLAYBACK \
| RME96_RESUME_CAPTURE)
#define RME96_START_PLAYBACK (RME96_TB_START_PLAYBACK \
| RME96_TB_RESET_PLAYPOS)
#define RME96_START_CAPTURE (RME96_TB_START_CAPTURE \
| RME96_TB_RESET_CAPTUREPOS)
#define RME96_START_BOTH (RME96_START_PLAYBACK \
| RME96_START_CAPTURE)
#define RME96_STOP_PLAYBACK (RME96_TB_STOP_PLAYBACK \
| RME96_TB_CLEAR_PLAYBACK_IRQ)
#define RME96_STOP_CAPTURE (RME96_TB_STOP_CAPTURE \
| RME96_TB_CLEAR_CAPTURE_IRQ)
#define RME96_STOP_BOTH (RME96_STOP_PLAYBACK \
| RME96_STOP_CAPTURE)
struct rme96 {
spinlock_t lock;
@ -214,6 +240,13 @@ struct rme96 {
u8 rev; /* card revision number */
#ifdef CONFIG_PM
u32 playback_pointer;
u32 capture_pointer;
void *playback_suspend_buffer;
void *capture_suspend_buffer;
#endif
struct snd_pcm_substream *playback_substream;
struct snd_pcm_substream *capture_substream;
@ -344,6 +377,8 @@ static struct snd_pcm_hardware snd_rme96_playback_spdif_info =
{
.info = (SNDRV_PCM_INFO_MMAP_IOMEM |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_SYNC_START |
SNDRV_PCM_INFO_RESUME |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE),
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
@ -373,6 +408,8 @@ static struct snd_pcm_hardware snd_rme96_capture_spdif_info =
{
.info = (SNDRV_PCM_INFO_MMAP_IOMEM |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_SYNC_START |
SNDRV_PCM_INFO_RESUME |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE),
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
@ -402,6 +439,8 @@ static struct snd_pcm_hardware snd_rme96_playback_adat_info =
{
.info = (SNDRV_PCM_INFO_MMAP_IOMEM |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_SYNC_START |
SNDRV_PCM_INFO_RESUME |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE),
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
@ -427,6 +466,8 @@ static struct snd_pcm_hardware snd_rme96_capture_adat_info =
{
.info = (SNDRV_PCM_INFO_MMAP_IOMEM |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_SYNC_START |
SNDRV_PCM_INFO_RESUME |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE),
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
@ -1045,54 +1086,35 @@ snd_rme96_capture_hw_params(struct snd_pcm_substream *substream,
}
static void
snd_rme96_playback_start(struct rme96 *rme96,
int from_pause)
snd_rme96_trigger(struct rme96 *rme96,
int op)
{
if (!from_pause) {
if (op & RME96_TB_RESET_PLAYPOS)
writel(0, rme96->iobase + RME96_IO_RESET_PLAY_POS);
}
rme96->wcreg |= RME96_WCR_START;
writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER);
}
static void
snd_rme96_capture_start(struct rme96 *rme96,
int from_pause)
{
if (!from_pause) {
if (op & RME96_TB_RESET_CAPTUREPOS)
writel(0, rme96->iobase + RME96_IO_RESET_REC_POS);
if (op & RME96_TB_CLEAR_PLAYBACK_IRQ) {
rme96->rcreg = readl(rme96->iobase + RME96_IO_CONTROL_REGISTER);
if (rme96->rcreg & RME96_RCR_IRQ)
writel(0, rme96->iobase + RME96_IO_CONFIRM_PLAY_IRQ);
}
rme96->wcreg |= RME96_WCR_START_2;
if (op & RME96_TB_CLEAR_CAPTURE_IRQ) {
rme96->rcreg = readl(rme96->iobase + RME96_IO_CONTROL_REGISTER);
if (rme96->rcreg & RME96_RCR_IRQ_2)
writel(0, rme96->iobase + RME96_IO_CONFIRM_REC_IRQ);
}
if (op & RME96_TB_START_PLAYBACK)
rme96->wcreg |= RME96_WCR_START;
if (op & RME96_TB_STOP_PLAYBACK)
rme96->wcreg &= ~RME96_WCR_START;
if (op & RME96_TB_START_CAPTURE)
rme96->wcreg |= RME96_WCR_START_2;
if (op & RME96_TB_STOP_CAPTURE)
rme96->wcreg &= ~RME96_WCR_START_2;
writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER);
}
static void
snd_rme96_playback_stop(struct rme96 *rme96)
{
/*
* Check if there is an unconfirmed IRQ, if so confirm it, or else
* the hardware will not stop generating interrupts
*/
rme96->rcreg = readl(rme96->iobase + RME96_IO_CONTROL_REGISTER);
if (rme96->rcreg & RME96_RCR_IRQ) {
writel(0, rme96->iobase + RME96_IO_CONFIRM_PLAY_IRQ);
}
rme96->wcreg &= ~RME96_WCR_START;
writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER);
}
static void
snd_rme96_capture_stop(struct rme96 *rme96)
{
rme96->rcreg = readl(rme96->iobase + RME96_IO_CONTROL_REGISTER);
if (rme96->rcreg & RME96_RCR_IRQ_2) {
writel(0, rme96->iobase + RME96_IO_CONFIRM_REC_IRQ);
}
rme96->wcreg &= ~RME96_WCR_START_2;
writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER);
}
static irqreturn_t
snd_rme96_interrupt(int irq,
@ -1155,6 +1177,7 @@ snd_rme96_playback_spdif_open(struct snd_pcm_substream *substream)
struct rme96 *rme96 = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_set_sync(substream);
spin_lock_irq(&rme96->lock);
if (rme96->playback_substream != NULL) {
spin_unlock_irq(&rme96->lock);
@ -1191,6 +1214,7 @@ snd_rme96_capture_spdif_open(struct snd_pcm_substream *substream)
struct rme96 *rme96 = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_set_sync(substream);
runtime->hw = snd_rme96_capture_spdif_info;
if (snd_rme96_getinputtype(rme96) != RME96_INPUT_ANALOG &&
(rate = snd_rme96_capture_getrate(rme96, &isadat)) > 0)
@ -1222,6 +1246,7 @@ snd_rme96_playback_adat_open(struct snd_pcm_substream *substream)
struct rme96 *rme96 = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_set_sync(substream);
spin_lock_irq(&rme96->lock);
if (rme96->playback_substream != NULL) {
spin_unlock_irq(&rme96->lock);
@ -1253,6 +1278,7 @@ snd_rme96_capture_adat_open(struct snd_pcm_substream *substream)
struct rme96 *rme96 = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_set_sync(substream);
runtime->hw = snd_rme96_capture_adat_info;
if (snd_rme96_getinputtype(rme96) == RME96_INPUT_ANALOG) {
/* makes no sense to use analog input. Note that analog
@ -1288,7 +1314,7 @@ snd_rme96_playback_close(struct snd_pcm_substream *substream)
spin_lock_irq(&rme96->lock);
if (RME96_ISPLAYING(rme96)) {
snd_rme96_playback_stop(rme96);
snd_rme96_trigger(rme96, RME96_STOP_PLAYBACK);
}
rme96->playback_substream = NULL;
rme96->playback_periodsize = 0;
@ -1309,7 +1335,7 @@ snd_rme96_capture_close(struct snd_pcm_substream *substream)
spin_lock_irq(&rme96->lock);
if (RME96_ISRECORDING(rme96)) {
snd_rme96_capture_stop(rme96);
snd_rme96_trigger(rme96, RME96_STOP_CAPTURE);
}
rme96->capture_substream = NULL;
rme96->capture_periodsize = 0;
@ -1324,7 +1350,7 @@ snd_rme96_playback_prepare(struct snd_pcm_substream *substream)
spin_lock_irq(&rme96->lock);
if (RME96_ISPLAYING(rme96)) {
snd_rme96_playback_stop(rme96);
snd_rme96_trigger(rme96, RME96_STOP_PLAYBACK);
}
writel(0, rme96->iobase + RME96_IO_RESET_PLAY_POS);
spin_unlock_irq(&rme96->lock);
@ -1338,7 +1364,7 @@ snd_rme96_capture_prepare(struct snd_pcm_substream *substream)
spin_lock_irq(&rme96->lock);
if (RME96_ISRECORDING(rme96)) {
snd_rme96_capture_stop(rme96);
snd_rme96_trigger(rme96, RME96_STOP_CAPTURE);
}
writel(0, rme96->iobase + RME96_IO_RESET_REC_POS);
spin_unlock_irq(&rme96->lock);
@ -1350,41 +1376,55 @@ snd_rme96_playback_trigger(struct snd_pcm_substream *substream,
int cmd)
{
struct rme96 *rme96 = snd_pcm_substream_chip(substream);
struct snd_pcm_substream *s;
bool sync;
snd_pcm_group_for_each_entry(s, substream) {
if (snd_pcm_substream_chip(s) == rme96)
snd_pcm_trigger_done(s, substream);
}
sync = (rme96->playback_substream && rme96->capture_substream) &&
(rme96->playback_substream->group ==
rme96->capture_substream->group);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
if (!RME96_ISPLAYING(rme96)) {
if (substream != rme96->playback_substream) {
if (substream != rme96->playback_substream)
return -EBUSY;
}
snd_rme96_playback_start(rme96, 0);
snd_rme96_trigger(rme96, sync ? RME96_START_BOTH
: RME96_START_PLAYBACK);
}
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_STOP:
if (RME96_ISPLAYING(rme96)) {
if (substream != rme96->playback_substream) {
if (substream != rme96->playback_substream)
return -EBUSY;
}
snd_rme96_playback_stop(rme96);
snd_rme96_trigger(rme96, sync ? RME96_STOP_BOTH
: RME96_STOP_PLAYBACK);
}
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
if (RME96_ISPLAYING(rme96)) {
snd_rme96_playback_stop(rme96);
}
if (RME96_ISPLAYING(rme96))
snd_rme96_trigger(rme96, sync ? RME96_STOP_BOTH
: RME96_STOP_PLAYBACK);
break;
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
if (!RME96_ISPLAYING(rme96)) {
snd_rme96_playback_start(rme96, 1);
}
if (!RME96_ISPLAYING(rme96))
snd_rme96_trigger(rme96, sync ? RME96_RESUME_BOTH
: RME96_RESUME_PLAYBACK);
break;
default:
return -EINVAL;
}
return 0;
}
@ -1393,38 +1433,51 @@ snd_rme96_capture_trigger(struct snd_pcm_substream *substream,
int cmd)
{
struct rme96 *rme96 = snd_pcm_substream_chip(substream);
struct snd_pcm_substream *s;
bool sync;
snd_pcm_group_for_each_entry(s, substream) {
if (snd_pcm_substream_chip(s) == rme96)
snd_pcm_trigger_done(s, substream);
}
sync = (rme96->playback_substream && rme96->capture_substream) &&
(rme96->playback_substream->group ==
rme96->capture_substream->group);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
if (!RME96_ISRECORDING(rme96)) {
if (substream != rme96->capture_substream) {
if (substream != rme96->capture_substream)
return -EBUSY;
}
snd_rme96_capture_start(rme96, 0);
snd_rme96_trigger(rme96, sync ? RME96_START_BOTH
: RME96_START_CAPTURE);
}
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_STOP:
if (RME96_ISRECORDING(rme96)) {
if (substream != rme96->capture_substream) {
if (substream != rme96->capture_substream)
return -EBUSY;
}
snd_rme96_capture_stop(rme96);
snd_rme96_trigger(rme96, sync ? RME96_STOP_BOTH
: RME96_STOP_CAPTURE);
}
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
if (RME96_ISRECORDING(rme96)) {
snd_rme96_capture_stop(rme96);
}
if (RME96_ISRECORDING(rme96))
snd_rme96_trigger(rme96, sync ? RME96_STOP_BOTH
: RME96_STOP_CAPTURE);
break;
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
if (!RME96_ISRECORDING(rme96)) {
snd_rme96_capture_start(rme96, 1);
}
if (!RME96_ISRECORDING(rme96))
snd_rme96_trigger(rme96, sync ? RME96_RESUME_BOTH
: RME96_RESUME_CAPTURE);
break;
default:
return -EINVAL;
}
@ -1505,8 +1558,7 @@ snd_rme96_free(void *private_data)
return;
}
if (rme96->irq >= 0) {
snd_rme96_playback_stop(rme96);
snd_rme96_capture_stop(rme96);
snd_rme96_trigger(rme96, RME96_STOP_BOTH);
rme96->areg &= ~RME96_AR_DAC_EN;
writel(rme96->areg, rme96->iobase + RME96_IO_ADDITIONAL_REG);
free_irq(rme96->irq, (void *)rme96);
@ -1520,6 +1572,10 @@ snd_rme96_free(void *private_data)
pci_release_regions(rme96->pci);
rme96->port = 0;
}
#ifdef CONFIG_PM
vfree(rme96->playback_suspend_buffer);
vfree(rme96->capture_suspend_buffer);
#endif
pci_disable_device(rme96->pci);
}
@ -1606,8 +1662,7 @@ snd_rme96_create(struct rme96 *rme96)
rme96->capture_periodsize = 0;
/* make sure playback/capture is stopped, if by some reason active */
snd_rme96_playback_stop(rme96);
snd_rme96_capture_stop(rme96);
snd_rme96_trigger(rme96, RME96_STOP_BOTH);
/* set default values in registers */
rme96->wcreg =
@ -2319,6 +2374,87 @@ snd_rme96_create_switches(struct snd_card *card,
* Card initialisation
*/
#ifdef CONFIG_PM
static int
snd_rme96_suspend(struct pci_dev *pci,
pm_message_t state)
{
struct snd_card *card = pci_get_drvdata(pci);
struct rme96 *rme96 = card->private_data;
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
snd_pcm_suspend(rme96->playback_substream);
snd_pcm_suspend(rme96->capture_substream);
/* save capture & playback pointers */
rme96->playback_pointer = readl(rme96->iobase + RME96_IO_GET_PLAY_POS)
& RME96_RCR_AUDIO_ADDR_MASK;
rme96->capture_pointer = readl(rme96->iobase + RME96_IO_GET_REC_POS)
& RME96_RCR_AUDIO_ADDR_MASK;
/* save playback and capture buffers */
memcpy_fromio(rme96->playback_suspend_buffer,
rme96->iobase + RME96_IO_PLAY_BUFFER, RME96_BUFFER_SIZE);
memcpy_fromio(rme96->capture_suspend_buffer,
rme96->iobase + RME96_IO_REC_BUFFER, RME96_BUFFER_SIZE);
/* disable the DAC */
rme96->areg &= ~RME96_AR_DAC_EN;
writel(rme96->areg, rme96->iobase + RME96_IO_ADDITIONAL_REG);
pci_disable_device(pci);
pci_save_state(pci);
return 0;
}
static int
snd_rme96_resume(struct pci_dev *pci)
{
struct snd_card *card = pci_get_drvdata(pci);
struct rme96 *rme96 = card->private_data;
pci_restore_state(pci);
if (pci_enable_device(pci) < 0) {
printk(KERN_ERR "rme96: pci_enable_device failed, disabling device\n");
snd_card_disconnect(card);
return -EIO;
}
/* reset playback and record buffer pointers */
writel(0, rme96->iobase + RME96_IO_SET_PLAY_POS
+ rme96->playback_pointer);
writel(0, rme96->iobase + RME96_IO_SET_REC_POS
+ rme96->capture_pointer);
/* restore playback and capture buffers */
memcpy_toio(rme96->iobase + RME96_IO_PLAY_BUFFER,
rme96->playback_suspend_buffer, RME96_BUFFER_SIZE);
memcpy_toio(rme96->iobase + RME96_IO_REC_BUFFER,
rme96->capture_suspend_buffer, RME96_BUFFER_SIZE);
/* reset the ADC */
writel(rme96->areg | RME96_AR_PD2,
rme96->iobase + RME96_IO_ADDITIONAL_REG);
writel(rme96->areg, rme96->iobase + RME96_IO_ADDITIONAL_REG);
/* reset and enable DAC, restore analog volume */
snd_rme96_reset_dac(rme96);
rme96->areg |= RME96_AR_DAC_EN;
writel(rme96->areg, rme96->iobase + RME96_IO_ADDITIONAL_REG);
if (RME96_HAS_ANALOG_OUT(rme96)) {
usleep_range(3000, 10000);
snd_rme96_apply_dac_volume(rme96);
}
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
return 0;
}
#endif
static void snd_rme96_card_free(struct snd_card *card)
{
snd_rme96_free(card->private_data);
@ -2355,6 +2491,23 @@ snd_rme96_probe(struct pci_dev *pci,
return err;
}
#ifdef CONFIG_PM
rme96->playback_suspend_buffer = vmalloc(RME96_BUFFER_SIZE);
if (!rme96->playback_suspend_buffer) {
snd_printk(KERN_ERR
"Failed to allocate playback suspend buffer!\n");
snd_card_free(card);
return -ENOMEM;
}
rme96->capture_suspend_buffer = vmalloc(RME96_BUFFER_SIZE);
if (!rme96->capture_suspend_buffer) {
snd_printk(KERN_ERR
"Failed to allocate capture suspend buffer!\n");
snd_card_free(card);
return -ENOMEM;
}
#endif
strcpy(card->driver, "Digi96");
switch (rme96->pci->device) {
case PCI_DEVICE_ID_RME_DIGI96:
@ -2397,6 +2550,10 @@ static struct pci_driver rme96_driver = {
.id_table = snd_rme96_ids,
.probe = snd_rme96_probe,
.remove = snd_rme96_remove,
#ifdef CONFIG_PM
.suspend = snd_rme96_suspend,
.resume = snd_rme96_resume,
#endif
};
module_pci_driver(rme96_driver);

File diff suppressed because it is too large Load diff

View file

@ -408,7 +408,6 @@ static int ep93xx_i2s_probe(struct platform_device *pdev)
return 0;
fail_put_lrclk:
dev_set_drvdata(&pdev->dev, NULL);
clk_put(info->lrclk);
fail_put_sclk:
clk_put(info->sclk);
@ -423,7 +422,6 @@ static int ep93xx_i2s_remove(struct platform_device *pdev)
struct ep93xx_i2s_info *info = dev_get_drvdata(&pdev->dev);
snd_soc_unregister_component(&pdev->dev);
dev_set_drvdata(&pdev->dev, NULL);
clk_put(info->lrclk);
clk_put(info->sclk);
clk_put(info->mclk);

View file

@ -50,20 +50,11 @@ static const struct snd_soc_dapm_route intercon[] = {
{"DMIC AIF", NULL, "DMic"},
};
static int dmic_probe(struct snd_soc_codec *codec)
{
struct snd_soc_dapm_context *dapm = &codec->dapm;
snd_soc_dapm_new_controls(dapm, dmic_dapm_widgets,
ARRAY_SIZE(dmic_dapm_widgets));
snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
snd_soc_dapm_new_widgets(dapm);
return 0;
}
static struct snd_soc_codec_driver soc_dmic = {
.probe = dmic_probe,
.dapm_widgets = dmic_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(dmic_dapm_widgets),
.dapm_routes = intercon,
.num_dapm_routes = ARRAY_SIZE(intercon),
};
static int dmic_dev_probe(struct platform_device *pdev)

View file

@ -50,8 +50,6 @@ static const struct regmap_range_cfg rt5640_ranges[] = {
static struct reg_default init_list[] = {
{RT5640_PR_BASE + 0x3d, 0x3600},
{RT5640_PR_BASE + 0x1c, 0x0D21},
{RT5640_PR_BASE + 0x1b, 0x0000},
{RT5640_PR_BASE + 0x12, 0x0aa8},
{RT5640_PR_BASE + 0x14, 0x0aaa},
{RT5640_PR_BASE + 0x20, 0x6110},
@ -384,15 +382,11 @@ static const SOC_ENUM_SINGLE_DECL(
static const struct snd_kcontrol_new rt5640_snd_controls[] = {
/* Speaker Output Volume */
SOC_DOUBLE("Speaker Playback Switch", RT5640_SPK_VOL,
RT5640_L_MUTE_SFT, RT5640_R_MUTE_SFT, 1, 1),
SOC_DOUBLE("Speaker Channel Switch", RT5640_SPK_VOL,
RT5640_VOL_L_SFT, RT5640_VOL_R_SFT, 1, 1),
SOC_DOUBLE_TLV("Speaker Playback Volume", RT5640_SPK_VOL,
RT5640_L_VOL_SFT, RT5640_R_VOL_SFT, 39, 1, out_vol_tlv),
/* Headphone Output Volume */
SOC_DOUBLE("HP Playback Switch", RT5640_HP_VOL,
RT5640_L_MUTE_SFT, RT5640_R_MUTE_SFT, 1, 1),
SOC_DOUBLE("HP Channel Switch", RT5640_HP_VOL,
RT5640_VOL_L_SFT, RT5640_VOL_R_SFT, 1, 1),
SOC_DOUBLE_TLV("HP Playback Volume", RT5640_HP_VOL,
@ -737,6 +731,22 @@ static const struct snd_kcontrol_new rt5640_mono_mix[] = {
RT5640_M_BST1_MM_SFT, 1, 1),
};
static const struct snd_kcontrol_new spk_l_enable_control =
SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5640_SPK_VOL,
RT5640_L_MUTE_SFT, 1, 1);
static const struct snd_kcontrol_new spk_r_enable_control =
SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5640_SPK_VOL,
RT5640_R_MUTE_SFT, 1, 1);
static const struct snd_kcontrol_new hp_l_enable_control =
SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5640_HP_VOL,
RT5640_L_MUTE_SFT, 1, 1);
static const struct snd_kcontrol_new hp_r_enable_control =
SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5640_HP_VOL,
RT5640_R_MUTE_SFT, 1, 1);
/* Stereo ADC source */
static const char * const rt5640_stereo_adc1_src[] = {
"DIG MIX", "ADC"
@ -868,33 +878,6 @@ static const SOC_ENUM_SINGLE_DECL(
static const struct snd_kcontrol_new rt5640_sdi_mux =
SOC_DAPM_ENUM("SDI select", rt5640_sdi_sel_enum);
static int spk_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
switch (event) {
case SND_SOC_DAPM_POST_PMU:
regmap_update_bits(rt5640->regmap, RT5640_PWR_DIG1,
0x0001, 0x0001);
regmap_update_bits(rt5640->regmap, RT5640_PR_BASE + 0x1c,
0xf000, 0xf000);
break;
case SND_SOC_DAPM_PRE_PMD:
regmap_update_bits(rt5640->regmap, RT5640_PR_BASE + 0x1c,
0xf000, 0x0000);
regmap_update_bits(rt5640->regmap, RT5640_PWR_DIG1,
0x0001, 0x0000);
break;
default:
return 0;
}
return 0;
}
static int rt5640_set_dmic1_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@ -943,6 +926,117 @@ static int rt5640_set_dmic2_event(struct snd_soc_dapm_widget *w,
return 0;
}
void hp_amp_power_on(struct snd_soc_codec *codec)
{
struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
/* depop parameters */
regmap_update_bits(rt5640->regmap, RT5640_PR_BASE +
RT5640_CHPUMP_INT_REG1, 0x0700, 0x0200);
regmap_update_bits(rt5640->regmap, RT5640_DEPOP_M2,
RT5640_DEPOP_MASK, RT5640_DEPOP_MAN);
regmap_update_bits(rt5640->regmap, RT5640_DEPOP_M1,
RT5640_HP_CP_MASK | RT5640_HP_SG_MASK | RT5640_HP_CB_MASK,
RT5640_HP_CP_PU | RT5640_HP_SG_DIS | RT5640_HP_CB_PU);
regmap_write(rt5640->regmap, RT5640_PR_BASE + RT5640_HP_DCC_INT1,
0x9f00);
/* headphone amp power on */
regmap_update_bits(rt5640->regmap, RT5640_PWR_ANLG1,
RT5640_PWR_FV1 | RT5640_PWR_FV2, 0);
regmap_update_bits(rt5640->regmap, RT5640_PWR_ANLG1,
RT5640_PWR_HA,
RT5640_PWR_HA);
usleep_range(10000, 15000);
regmap_update_bits(rt5640->regmap, RT5640_PWR_ANLG1,
RT5640_PWR_FV1 | RT5640_PWR_FV2 ,
RT5640_PWR_FV1 | RT5640_PWR_FV2);
}
static void rt5640_pmu_depop(struct snd_soc_codec *codec)
{
struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
regmap_update_bits(rt5640->regmap, RT5640_DEPOP_M2,
RT5640_DEPOP_MASK | RT5640_DIG_DP_MASK,
RT5640_DEPOP_AUTO | RT5640_DIG_DP_EN);
regmap_update_bits(rt5640->regmap, RT5640_CHARGE_PUMP,
RT5640_PM_HP_MASK, RT5640_PM_HP_HV);
regmap_update_bits(rt5640->regmap, RT5640_DEPOP_M3,
RT5640_CP_FQ1_MASK | RT5640_CP_FQ2_MASK | RT5640_CP_FQ3_MASK,
(RT5640_CP_FQ_192_KHZ << RT5640_CP_FQ1_SFT) |
(RT5640_CP_FQ_12_KHZ << RT5640_CP_FQ2_SFT) |
(RT5640_CP_FQ_192_KHZ << RT5640_CP_FQ3_SFT));
regmap_write(rt5640->regmap, RT5640_PR_BASE +
RT5640_MAMP_INT_REG2, 0x1c00);
regmap_update_bits(rt5640->regmap, RT5640_DEPOP_M1,
RT5640_HP_CP_MASK | RT5640_HP_SG_MASK,
RT5640_HP_CP_PD | RT5640_HP_SG_EN);
regmap_update_bits(rt5640->regmap, RT5640_PR_BASE +
RT5640_CHPUMP_INT_REG1, 0x0700, 0x0400);
}
static int rt5640_hp_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
switch (event) {
case SND_SOC_DAPM_POST_PMU:
rt5640_pmu_depop(codec);
rt5640->hp_mute = 0;
break;
case SND_SOC_DAPM_PRE_PMD:
rt5640->hp_mute = 1;
usleep_range(70000, 75000);
break;
default:
return 0;
}
return 0;
}
static int rt5640_hp_power_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
switch (event) {
case SND_SOC_DAPM_POST_PMU:
hp_amp_power_on(codec);
break;
default:
return 0;
}
return 0;
}
static int rt5640_hp_post_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
switch (event) {
case SND_SOC_DAPM_POST_PMU:
if (!rt5640->hp_mute)
usleep_range(80000, 85000);
break;
default:
return 0;
}
return 0;
}
static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("PLL1", RT5640_PWR_ANLG2,
RT5640_PWR_PLL_BIT, 0, NULL, 0),
@ -1132,15 +1226,28 @@ static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = {
rt5640_mono_mix, ARRAY_SIZE(rt5640_mono_mix)),
SND_SOC_DAPM_SUPPLY("Improve MONO Amp Drv", RT5640_PWR_ANLG1,
RT5640_PWR_MA_BIT, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("Improve HP Amp Drv", RT5640_PWR_ANLG1,
SND_SOC_NOPM, 0, NULL, 0),
SND_SOC_DAPM_PGA("HP L Amp", RT5640_PWR_ANLG1,
SND_SOC_DAPM_SUPPLY_S("Improve HP Amp Drv", 1, SND_SOC_NOPM,
0, 0, rt5640_hp_power_event, SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_S("HP Amp", 1, SND_SOC_NOPM, 0, 0,
rt5640_hp_event,
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_SUPPLY("HP L Amp", RT5640_PWR_ANLG1,
RT5640_PWR_HP_L_BIT, 0, NULL, 0),
SND_SOC_DAPM_PGA("HP R Amp", RT5640_PWR_ANLG1,
SND_SOC_DAPM_SUPPLY("HP R Amp", RT5640_PWR_ANLG1,
RT5640_PWR_HP_R_BIT, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("Improve SPK Amp Drv", RT5640_PWR_DIG1,
SND_SOC_NOPM, 0, spk_event,
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
RT5640_PWR_CLS_D_BIT, 0, NULL, 0),
/* Output Switch */
SND_SOC_DAPM_SWITCH("Speaker L Playback", SND_SOC_NOPM, 0, 0,
&spk_l_enable_control),
SND_SOC_DAPM_SWITCH("Speaker R Playback", SND_SOC_NOPM, 0, 0,
&spk_r_enable_control),
SND_SOC_DAPM_SWITCH("HP L Playback", SND_SOC_NOPM, 0, 0,
&hp_l_enable_control),
SND_SOC_DAPM_SWITCH("HP R Playback", SND_SOC_NOPM, 0, 0,
&hp_r_enable_control),
SND_SOC_DAPM_POST("HP Post", rt5640_hp_post_event),
/* Output Lines */
SND_SOC_DAPM_OUTPUT("SPOLP"),
SND_SOC_DAPM_OUTPUT("SPOLN"),
@ -1381,9 +1488,11 @@ static const struct snd_soc_dapm_route rt5640_dapm_routes[] = {
{"HPO MIX L", "HPO MIX DAC2 Switch", "DAC L2"},
{"HPO MIX L", "HPO MIX DAC1 Switch", "DAC L1"},
{"HPO MIX L", "HPO MIX HPVOL Switch", "HPOVOL L"},
{"HPO MIX L", NULL, "HP L Amp"},
{"HPO MIX R", "HPO MIX DAC2 Switch", "DAC R2"},
{"HPO MIX R", "HPO MIX DAC1 Switch", "DAC R1"},
{"HPO MIX R", "HPO MIX HPVOL Switch", "HPOVOL R"},
{"HPO MIX R", NULL, "HP R Amp"},
{"LOUT MIX", "DAC L1 Switch", "DAC L1"},
{"LOUT MIX", "DAC R1 Switch", "DAC R1"},
@ -1396,13 +1505,15 @@ static const struct snd_soc_dapm_route rt5640_dapm_routes[] = {
{"Mono MIX", "OUTVOL L Switch", "OUTVOL L"},
{"Mono MIX", "BST1 Switch", "BST1"},
{"HP L Amp", NULL, "HPO MIX L"},
{"HP R Amp", NULL, "HPO MIX R"},
{"HP Amp", NULL, "HPO MIX L"},
{"HP Amp", NULL, "HPO MIX R"},
{"SPOLP", NULL, "SPOL MIX"},
{"SPOLN", NULL, "SPOL MIX"},
{"SPORP", NULL, "SPOR MIX"},
{"SPORN", NULL, "SPOR MIX"},
{"Speaker L Playback", "Switch", "SPOL MIX"},
{"Speaker R Playback", "Switch", "SPOR MIX"},
{"SPOLP", NULL, "Speaker L Playback"},
{"SPOLN", NULL, "Speaker L Playback"},
{"SPORP", NULL, "Speaker R Playback"},
{"SPORN", NULL, "Speaker R Playback"},
{"SPOLP", NULL, "Improve SPK Amp Drv"},
{"SPOLN", NULL, "Improve SPK Amp Drv"},
@ -1412,8 +1523,10 @@ static const struct snd_soc_dapm_route rt5640_dapm_routes[] = {
{"HPOL", NULL, "Improve HP Amp Drv"},
{"HPOR", NULL, "Improve HP Amp Drv"},
{"HPOL", NULL, "HP L Amp"},
{"HPOR", NULL, "HP R Amp"},
{"HP L Playback", "Switch", "HP Amp"},
{"HP R Playback", "Switch", "HP Amp"},
{"HPOL", NULL, "HP L Playback"},
{"HPOR", NULL, "HP R Playback"},
{"LOUTL", NULL, "LOUT MIX"},
{"LOUTR", NULL, "LOUT MIX"},
{"MONOP", NULL, "Mono MIX"},
@ -1792,17 +1905,13 @@ static int rt5640_set_bias_level(struct snd_soc_codec *codec,
RT5640_PWR_BG | RT5640_PWR_VREF2,
RT5640_PWR_VREF1 | RT5640_PWR_MB |
RT5640_PWR_BG | RT5640_PWR_VREF2);
mdelay(10);
usleep_range(10000, 15000);
snd_soc_update_bits(codec, RT5640_PWR_ANLG1,
RT5640_PWR_FV1 | RT5640_PWR_FV2,
RT5640_PWR_FV1 | RT5640_PWR_FV2);
regcache_sync(rt5640->regmap);
snd_soc_update_bits(codec, RT5640_DUMMY1,
0x0301, 0x0301);
snd_soc_update_bits(codec, RT5640_DEPOP_M1,
0x001d, 0x0019);
snd_soc_update_bits(codec, RT5640_DEPOP_M2,
0x2000, 0x2000);
snd_soc_update_bits(codec, RT5640_MICBIAS,
0x0030, 0x0030);
}
@ -1846,8 +1955,6 @@ static int rt5640_probe(struct snd_soc_codec *codec)
rt5640_set_bias_level(codec, SND_SOC_BIAS_OFF);
snd_soc_update_bits(codec, RT5640_DUMMY1, 0x0301, 0x0301);
snd_soc_update_bits(codec, RT5640_DEPOP_M1, 0x001d, 0x0019);
snd_soc_update_bits(codec, RT5640_DEPOP_M2, 0x2000, 0x2000);
snd_soc_update_bits(codec, RT5640_MICBIAS, 0x0030, 0x0030);
snd_soc_update_bits(codec, RT5640_DSP_PATH2, 0xfc00, 0x0c00);
@ -2069,6 +2176,8 @@ static int rt5640_i2c_probe(struct i2c_client *i2c,
regmap_update_bits(rt5640->regmap, RT5640_IN3_IN4,
RT5640_IN_DF2, RT5640_IN_DF2);
rt5640->hp_mute = 1;
ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5640,
rt5640_dai, ARRAY_SIZE(rt5640_dai));
if (ret < 0)

View file

@ -145,6 +145,8 @@
/* Index of Codec Private Register definition */
#define RT5640_CHPUMP_INT_REG1 0x24
#define RT5640_MAMP_INT_REG2 0x37
#define RT5640_3D_SPK 0x63
#define RT5640_WND_1 0x6c
#define RT5640_WND_2 0x6d
@ -153,6 +155,7 @@
#define RT5640_WND_5 0x70
#define RT5640_WND_8 0x73
#define RT5640_DIP_SPK_INF 0x75
#define RT5640_HP_DCC_INT1 0x77
#define RT5640_EQ_BW_LOP 0xa0
#define RT5640_EQ_GN_LOP 0xa1
#define RT5640_EQ_FC_BP1 0xa2
@ -1201,6 +1204,14 @@
#define RT5640_CP_FQ2_SFT 4
#define RT5640_CP_FQ3_MASK (0x7)
#define RT5640_CP_FQ3_SFT 0
#define RT5640_CP_FQ_1_5_KHZ 0
#define RT5640_CP_FQ_3_KHZ 1
#define RT5640_CP_FQ_6_KHZ 2
#define RT5640_CP_FQ_12_KHZ 3
#define RT5640_CP_FQ_24_KHZ 4
#define RT5640_CP_FQ_48_KHZ 5
#define RT5640_CP_FQ_96_KHZ 6
#define RT5640_CP_FQ_192_KHZ 7
/* HPOUT charge pump (0x91) */
#define RT5640_OSW_L_MASK (0x1 << 11)
@ -2087,6 +2098,7 @@ struct rt5640_priv {
int pll_out;
int dmic_en;
bool hp_mute;
};
#endif

View file

@ -561,8 +561,9 @@ static int ssm2602_suspend(struct snd_soc_codec *codec)
static int ssm2602_resume(struct snd_soc_codec *codec)
{
snd_soc_cache_sync(codec);
struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
regcache_sync(ssm2602->regmap);
ssm2602_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;

View file

@ -338,18 +338,6 @@ static inline int aic32x4_get_divs(int mclk, int rate)
return -EINVAL;
}
static int aic32x4_add_widgets(struct snd_soc_codec *codec)
{
snd_soc_dapm_new_controls(&codec->dapm, aic32x4_dapm_widgets,
ARRAY_SIZE(aic32x4_dapm_widgets));
snd_soc_dapm_add_routes(&codec->dapm, aic32x4_dapm_routes,
ARRAY_SIZE(aic32x4_dapm_routes));
snd_soc_dapm_new_widgets(&codec->dapm);
return 0;
}
static int aic32x4_set_dai_sysclk(struct snd_soc_dai *codec_dai,
int clk_id, unsigned int freq, int dir)
{
@ -683,9 +671,6 @@ static int aic32x4_probe(struct snd_soc_codec *codec)
}
aic32x4_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
snd_soc_add_codec_controls(codec, aic32x4_snd_controls,
ARRAY_SIZE(aic32x4_snd_controls));
aic32x4_add_widgets(codec);
/*
* Workaround: for an unknown reason, the ADC needs to be powered up
@ -714,6 +699,13 @@ static struct snd_soc_codec_driver soc_codec_dev_aic32x4 = {
.suspend = aic32x4_suspend,
.resume = aic32x4_resume,
.set_bias_level = aic32x4_set_bias_level,
.controls = aic32x4_snd_controls,
.num_controls = ARRAY_SIZE(aic32x4_snd_controls),
.dapm_widgets = aic32x4_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(aic32x4_dapm_widgets),
.dapm_routes = aic32x4_dapm_routes,
.num_dapm_routes = ARRAY_SIZE(aic32x4_dapm_routes),
};
static int aic32x4_i2c_probe(struct i2c_client *i2c,

View file

@ -1202,7 +1202,6 @@ static int wm8904_add_widgets(struct snd_soc_codec *codec)
break;
}
snd_soc_dapm_new_widgets(dapm);
return 0;
}

View file

@ -3174,7 +3174,7 @@ static ssize_t wm8962_beep_set(struct device *dev,
long int time;
int ret;
ret = strict_strtol(buf, 10, &time);
ret = kstrtol(buf, 10, &time);
if (ret != 0)
return ret;

View file

@ -421,13 +421,11 @@ static int dw_i2s_probe(struct platform_device *pdev)
dw_i2s_dai, 1);
if (ret != 0) {
dev_err(&pdev->dev, "not able to register dai\n");
goto err_set_drvdata;
goto err_clk_disable;
}
return 0;
err_set_drvdata:
dev_set_drvdata(&pdev->dev, NULL);
err_clk_disable:
clk_disable(dev->clk);
err_clk_put:
@ -440,7 +438,6 @@ static int dw_i2s_remove(struct platform_device *pdev)
struct dw_i2s_dev *dev = dev_get_drvdata(&pdev->dev);
snd_soc_unregister_component(&pdev->dev);
dev_set_drvdata(&pdev->dev, NULL);
clk_put(dev->clk);

View file

@ -193,6 +193,17 @@ config SND_SOC_IMX_SGTL5000
Say Y if you want to add support for SoC audio on an i.MX board with
a sgtl5000 codec.
config SND_SOC_IMX_SPDIF
tristate "SoC Audio support for i.MX boards with S/PDIF"
select SND_SOC_IMX_PCM_DMA
select SND_SOC_FSL_SPDIF
select SND_SOC_SPDIF
select REGMAP_MMIO
help
SoC Audio support for i.MX boards with S/PDIF
Say Y if you want to add support for SoC audio on an i.MX board with
a S/DPDIF.
config SND_SOC_IMX_MC13783
tristate "SoC Audio support for I.MX boards with mc13783"
depends on MFD_MC13783 && ARM

View file

@ -45,6 +45,7 @@ snd-soc-mx27vis-aic32x4-objs := mx27vis-aic32x4.o
snd-soc-wm1133-ev1-objs := wm1133-ev1.o
snd-soc-imx-sgtl5000-objs := imx-sgtl5000.o
snd-soc-imx-wm8962-objs := imx-wm8962.o
snd-soc-imx-spdif-objs := imx-spdif.o
snd-soc-imx-mc13783-objs := imx-mc13783.o
obj-$(CONFIG_SND_SOC_EUKREA_TLV320) += snd-soc-eukrea-tlv320.o
@ -53,4 +54,5 @@ obj-$(CONFIG_SND_SOC_MX27VIS_AIC32X4) += snd-soc-mx27vis-aic32x4.o
obj-$(CONFIG_SND_MXC_SOC_WM1133_EV1) += snd-soc-wm1133-ev1.o
obj-$(CONFIG_SND_SOC_IMX_SGTL5000) += snd-soc-imx-sgtl5000.o
obj-$(CONFIG_SND_SOC_IMX_WM8962) += snd-soc-imx-wm8962.o
obj-$(CONFIG_SND_SOC_IMX_SPDIF) += snd-soc-imx-spdif.o
obj-$(CONFIG_SND_SOC_IMX_MC13783) += snd-soc-imx-mc13783.o

View file

@ -411,8 +411,8 @@ static int spdif_set_sample_rate(struct snd_pcm_substream *substream,
return 0;
}
int fsl_spdif_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai)
static int fsl_spdif_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(rtd->cpu_dai);
@ -546,7 +546,7 @@ static int fsl_spdif_trigger(struct snd_pcm_substream *substream,
return 0;
}
struct snd_soc_dai_ops fsl_spdif_dai_ops = {
static struct snd_soc_dai_ops fsl_spdif_dai_ops = {
.startup = fsl_spdif_startup,
.hw_params = fsl_spdif_hw_params,
.trigger = fsl_spdif_trigger,
@ -555,7 +555,6 @@ struct snd_soc_dai_ops fsl_spdif_dai_ops = {
/*
* ============================================
* FSL SPDIF IEC958 controller(mixer) functions
*
* Channel status get/put control
@ -563,7 +562,6 @@ struct snd_soc_dai_ops fsl_spdif_dai_ops = {
* Valid bit value get control
* DPLL lock status get control
* User bit sync mode selection control
* ============================================
*/
static int fsl_spdif_info(struct snd_kcontrol *kcontrol,
@ -921,7 +919,7 @@ static int fsl_spdif_dai_probe(struct snd_soc_dai *dai)
return 0;
}
struct snd_soc_dai_driver fsl_spdif_dai = {
static struct snd_soc_dai_driver fsl_spdif_dai = {
.probe = &fsl_spdif_dai_probe,
.playback = {
.channels_min = 2,
@ -942,11 +940,7 @@ static const struct snd_soc_component_driver fsl_spdif_component = {
.name = "fsl-spdif",
};
/*
* ================
* FSL SPDIF REGMAP
* ================
*/
/* FSL SPDIF REGMAP */
static bool fsl_spdif_readable_reg(struct device *dev, unsigned int reg)
{
@ -1077,9 +1071,9 @@ static int fsl_spdif_probe_txclk(struct fsl_spdif_priv *spdif_priv,
break;
}
dev_dbg(&pdev->dev, "use rxtx%d as tx clock source for %dHz sample rate",
dev_dbg(&pdev->dev, "use rxtx%d as tx clock source for %dHz sample rate\n",
spdif_priv->txclk_src[index], rate[index]);
dev_dbg(&pdev->dev, "use divisor %d for %dHz sample rate",
dev_dbg(&pdev->dev, "use divisor %d for %dHz sample rate\n",
spdif_priv->txclk_div[index], rate[index]);
return 0;
@ -1119,10 +1113,8 @@ static int fsl_spdif_probe(struct platform_device *pdev)
}
regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(regs)) {
dev_err(&pdev->dev, "could not map device resources\n");
if (IS_ERR(regs))
return PTR_ERR(regs);
}
spdif_priv->regmap = devm_regmap_init_mmio_clk(&pdev->dev,
"core", regs, &fsl_spdif_regmap_config);
@ -1184,7 +1176,7 @@ static int fsl_spdif_probe(struct platform_device *pdev)
&spdif_priv->cpu_dai_drv, 1);
if (ret) {
dev_err(&pdev->dev, "failed to register DAI: %d\n", ret);
goto error_dev;
return ret;
}
ret = imx_pcm_dma_init(pdev);
@ -1197,8 +1189,6 @@ static int fsl_spdif_probe(struct platform_device *pdev)
error_component:
snd_soc_unregister_component(&pdev->dev);
error_dev:
dev_set_drvdata(&pdev->dev, NULL);
return ret;
}
@ -1207,7 +1197,6 @@ static int fsl_spdif_remove(struct platform_device *pdev)
{
imx_pcm_dma_exit(pdev);
snd_soc_unregister_component(&pdev->dev);
dev_set_drvdata(&pdev->dev, NULL);
return 0;
}

View file

@ -1114,7 +1114,6 @@ static int fsl_ssi_probe(struct platform_device *pdev)
snd_soc_unregister_component(&pdev->dev);
error_dev:
dev_set_drvdata(&pdev->dev, NULL);
device_remove_file(&pdev->dev, dev_attr);
error_clk:

View file

@ -335,7 +335,8 @@ static int imx_audmux_probe(struct platform_device *pdev)
if (audmux_type == IMX31_AUDMUX)
audmux_debugfs_init();
imx_audmux_parse_dt_defaults(pdev, pdev->dev.of_node);
if (of_id)
imx_audmux_parse_dt_defaults(pdev, pdev->dev.of_node);
return 0;
}

148
sound/soc/fsl/imx-spdif.c Normal file
View file

@ -0,0 +1,148 @@
/*
* Copyright (C) 2013 Freescale Semiconductor, Inc.
*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations:
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
#include <linux/module.h>
#include <linux/of_platform.h>
#include <sound/soc.h>
struct imx_spdif_data {
struct snd_soc_dai_link dai[2];
struct snd_soc_card card;
struct platform_device *txdev;
struct platform_device *rxdev;
};
static int imx_spdif_audio_probe(struct platform_device *pdev)
{
struct device_node *spdif_np, *np = pdev->dev.of_node;
struct imx_spdif_data *data;
int ret = 0, num_links = 0;
spdif_np = of_parse_phandle(np, "spdif-controller", 0);
if (!spdif_np) {
dev_err(&pdev->dev, "failed to find spdif-controller\n");
ret = -EINVAL;
goto end;
}
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
if (!data) {
dev_err(&pdev->dev, "failed to allocate memory\n");
ret = -ENOMEM;
goto end;
}
if (of_property_read_bool(np, "spdif-out")) {
data->dai[num_links].name = "S/PDIF TX";
data->dai[num_links].stream_name = "S/PDIF PCM Playback";
data->dai[num_links].codec_dai_name = "dit-hifi";
data->dai[num_links].codec_name = "spdif-dit";
data->dai[num_links].cpu_of_node = spdif_np;
data->dai[num_links].platform_of_node = spdif_np;
num_links++;
data->txdev = platform_device_register_simple("spdif-dit", -1, NULL, 0);
if (IS_ERR(data->txdev)) {
ret = PTR_ERR(data->txdev);
dev_err(&pdev->dev, "register dit failed: %d\n", ret);
goto end;
}
}
if (of_property_read_bool(np, "spdif-in")) {
data->dai[num_links].name = "S/PDIF RX";
data->dai[num_links].stream_name = "S/PDIF PCM Capture";
data->dai[num_links].codec_dai_name = "dir-hifi";
data->dai[num_links].codec_name = "spdif-dir";
data->dai[num_links].cpu_of_node = spdif_np;
data->dai[num_links].platform_of_node = spdif_np;
num_links++;
data->rxdev = platform_device_register_simple("spdif-dir", -1, NULL, 0);
if (IS_ERR(data->rxdev)) {
ret = PTR_ERR(data->rxdev);
dev_err(&pdev->dev, "register dir failed: %d\n", ret);
goto error_dit;
}
}
if (!num_links) {
dev_err(&pdev->dev, "no enabled S/PDIF DAI link\n");
goto error_dir;
}
data->card.dev = &pdev->dev;
data->card.num_links = num_links;
data->card.dai_link = data->dai;
ret = snd_soc_of_parse_card_name(&data->card, "model");
if (ret)
goto error_dir;
ret = snd_soc_register_card(&data->card);
if (ret) {
dev_err(&pdev->dev, "snd_soc_register_card failed: %d\n", ret);
goto error_dir;
}
platform_set_drvdata(pdev, data);
goto end;
error_dir:
if (data->rxdev)
platform_device_unregister(data->rxdev);
error_dit:
if (data->txdev)
platform_device_unregister(data->txdev);
end:
if (spdif_np)
of_node_put(spdif_np);
return ret;
}
static int imx_spdif_audio_remove(struct platform_device *pdev)
{
struct imx_spdif_data *data = platform_get_drvdata(pdev);
if (data->rxdev)
platform_device_unregister(data->rxdev);
if (data->txdev)
platform_device_unregister(data->txdev);
snd_soc_unregister_card(&data->card);
return 0;
}
static const struct of_device_id imx_spdif_dt_ids[] = {
{ .compatible = "fsl,imx-audio-spdif", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, imx_spdif_dt_ids);
static struct platform_driver imx_spdif_driver = {
.driver = {
.name = "imx-spdif",
.owner = THIS_MODULE,
.of_match_table = imx_spdif_dt_ids,
},
.probe = imx_spdif_audio_probe,
.remove = imx_spdif_audio_remove,
};
module_platform_driver(imx_spdif_driver);
MODULE_AUTHOR("Freescale Semiconductor, Inc.");
MODULE_DESCRIPTION("Freescale i.MX S/PDIF machine driver");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:imx-spdif");

View file

@ -105,6 +105,7 @@ static int asoc_simple_card_remove(struct platform_device *pdev)
static struct platform_driver asoc_simple_card = {
.driver = {
.name = "asoc-simple-card",
.owner = THIS_MODULE,
},
.probe = asoc_simple_card_probe,
.remove = asoc_simple_card_remove,
@ -112,6 +113,7 @@ static struct platform_driver asoc_simple_card = {
module_platform_driver(asoc_simple_card);
MODULE_ALIAS("platform:asoc-simple-card");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("ASoC Simple Sound Card");
MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");

View file

@ -1,6 +1,6 @@
config SND_KIRKWOOD_SOC
tristate "SoC Audio for the Marvell Kirkwood chip"
depends on ARCH_KIRKWOOD || COMPILE_TEST
tristate "SoC Audio for the Marvell Kirkwood and Dove chips"
depends on ARCH_KIRKWOOD || ARCH_DOVE || COMPILE_TEST
help
Say Y or M if you want to add support for codecs attached to
the Kirkwood I2S interface. You will also need to select the

View file

@ -22,6 +22,8 @@
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <linux/platform_data/asoc-kirkwood.h>
#include <linux/of.h>
#include "kirkwood.h"
#define DRV_NAME "mvebu-audio"
@ -453,6 +455,7 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev)
struct snd_soc_dai_driver *soc_dai = &kirkwood_i2s_dai;
struct kirkwood_dma_data *priv;
struct resource *mem;
struct device_node *np = pdev->dev.of_node;
int err;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
@ -473,14 +476,16 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev)
return -ENXIO;
}
if (!data) {
dev_err(&pdev->dev, "no platform data ?!\n");
if (np) {
priv->burst = 128; /* might be 32 or 128 */
} else if (data) {
priv->burst = data->burst;
} else {
dev_err(&pdev->dev, "no DT nor platform data ?!\n");
return -EINVAL;
}
priv->burst = data->burst;
priv->clk = devm_clk_get(&pdev->dev, NULL);
priv->clk = devm_clk_get(&pdev->dev, np ? "internal" : NULL);
if (IS_ERR(priv->clk)) {
dev_err(&pdev->dev, "no clock\n");
return PTR_ERR(priv->clk);
@ -507,7 +512,7 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev)
priv->ctl_rec = KIRKWOOD_RECCTL_SIZE_24;
/* Select the burst size */
if (data->burst == 32) {
if (priv->burst == 32) {
priv->ctl_play |= KIRKWOOD_PLAYCTL_BURST_32;
priv->ctl_rec |= KIRKWOOD_RECCTL_BURST_32;
} else {
@ -552,12 +557,21 @@ static int kirkwood_i2s_dev_remove(struct platform_device *pdev)
return 0;
}
#ifdef CONFIG_OF
static struct of_device_id mvebu_audio_of_match[] = {
{ .compatible = "marvell,mvebu-audio" },
{ }
};
MODULE_DEVICE_TABLE(of, mvebu_audio_of_match);
#endif
static struct platform_driver kirkwood_i2s_driver = {
.probe = kirkwood_i2s_dev_probe,
.remove = kirkwood_i2s_dev_remove,
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(mvebu_audio_of_match),
},
};

View file

@ -105,11 +105,13 @@ static struct snd_soc_dai_link mxs_sgtl5000_dai[] = {
.stream_name = "HiFi Playback",
.codec_dai_name = "sgtl5000",
.ops = &mxs_sgtl5000_hifi_ops,
.playback_only = true,
}, {
.name = "HiFi Rx",
.stream_name = "HiFi Capture",
.codec_dai_name = "sgtl5000",
.ops = &mxs_sgtl5000_hifi_ops,
.capture_only = true,
},
};

View file

@ -781,7 +781,7 @@ static ssize_t prop##_store(struct device *dev, \
unsigned long val; \
int status; \
\
status = strict_strtoul(buf, 0, &val); \
status = kstrtoul(buf, 0, &val); \
if (status) \
return status; \
\

View file

@ -90,6 +90,13 @@ static void dma_enqueue(struct snd_pcm_substream *substream)
dma_info.period = prtd->dma_period;
dma_info.len = prtd->dma_period*limit;
if (dma_info.cap == DMA_CYCLIC) {
dma_info.buf = pos;
prtd->params->ops->prepare(prtd->params->ch, &dma_info);
prtd->dma_loaded += limit;
return;
}
while (prtd->dma_loaded < limit) {
pr_debug("dma_loaded: %d\n", prtd->dma_loaded);

View file

@ -235,6 +235,8 @@ struct fsi_stream {
struct sh_dmae_slave slave; /* see fsi_handler_init() */
struct work_struct work;
dma_addr_t dma;
int loop_cnt;
int additional_pos;
};
struct fsi_clk {
@ -1289,6 +1291,8 @@ static int fsi_dma_init(struct fsi_priv *fsi, struct fsi_stream *io)
io->bus_option = BUSOP_SET(24, PACKAGE_24BITBUS_BACK) |
BUSOP_SET(16, PACKAGE_16BITBUS_STREAM);
io->loop_cnt = 2; /* push 1st, 2nd period first, then 3rd, 4th... */
io->additional_pos = 0;
io->dma = dma_map_single(dai->dev, runtime->dma_area,
snd_pcm_lib_buffer_bytes(io->substream), dir);
return 0;
@ -1305,11 +1309,15 @@ static int fsi_dma_quit(struct fsi_priv *fsi, struct fsi_stream *io)
return 0;
}
static dma_addr_t fsi_dma_get_area(struct fsi_stream *io)
static dma_addr_t fsi_dma_get_area(struct fsi_stream *io, int additional)
{
struct snd_pcm_runtime *runtime = io->substream->runtime;
int period = io->period_pos + additional;
return io->dma + samples_to_bytes(runtime, io->buff_sample_pos);
if (period >= runtime->periods)
period = 0;
return io->dma + samples_to_bytes(runtime, period * io->period_samples);
}
static void fsi_dma_complete(void *data)
@ -1321,7 +1329,7 @@ static void fsi_dma_complete(void *data)
enum dma_data_direction dir = fsi_stream_is_play(fsi, io) ?
DMA_TO_DEVICE : DMA_FROM_DEVICE;
dma_sync_single_for_cpu(dai->dev, fsi_dma_get_area(io),
dma_sync_single_for_cpu(dai->dev, fsi_dma_get_area(io, 0),
samples_to_bytes(runtime, io->period_samples), dir);
io->buff_sample_pos += io->period_samples;
@ -1347,7 +1355,7 @@ static void fsi_dma_do_work(struct work_struct *work)
struct snd_pcm_runtime *runtime;
enum dma_data_direction dir;
int is_play = fsi_stream_is_play(fsi, io);
int len;
int len, i;
dma_addr_t buf;
if (!fsi_stream_is_working(fsi, io))
@ -1357,26 +1365,33 @@ static void fsi_dma_do_work(struct work_struct *work)
runtime = io->substream->runtime;
dir = is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
len = samples_to_bytes(runtime, io->period_samples);
buf = fsi_dma_get_area(io);
dma_sync_single_for_device(dai->dev, buf, len, dir);
for (i = 0; i < io->loop_cnt; i++) {
buf = fsi_dma_get_area(io, io->additional_pos);
desc = dmaengine_prep_slave_single(io->chan, buf, len, dir,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc) {
dev_err(dai->dev, "dmaengine_prep_slave_sg() fail\n");
return;
dma_sync_single_for_device(dai->dev, buf, len, dir);
desc = dmaengine_prep_slave_single(io->chan, buf, len, dir,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc) {
dev_err(dai->dev, "dmaengine_prep_slave_sg() fail\n");
return;
}
desc->callback = fsi_dma_complete;
desc->callback_param = io;
if (dmaengine_submit(desc) < 0) {
dev_err(dai->dev, "tx_submit() fail\n");
return;
}
dma_async_issue_pending(io->chan);
io->additional_pos = 1;
}
desc->callback = fsi_dma_complete;
desc->callback_param = io;
if (dmaengine_submit(desc) < 0) {
dev_err(dai->dev, "tx_submit() fail\n");
return;
}
dma_async_issue_pending(io->chan);
io->loop_cnt = 1;
/*
* FIXME

View file

@ -203,7 +203,7 @@ static ssize_t pmdown_time_set(struct device *dev,
struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev);
int ret;
ret = strict_strtol(buf, 10, &rtd->pmdown_time);
ret = kstrtol(buf, 10, &rtd->pmdown_time);
if (ret)
return ret;
@ -248,6 +248,7 @@ static ssize_t codec_reg_write_file(struct file *file,
char *start = buf;
unsigned long reg, value;
struct snd_soc_codec *codec = file->private_data;
int ret;
buf_size = min(count, (sizeof(buf)-1));
if (copy_from_user(buf, user_buf, buf_size))
@ -259,8 +260,9 @@ static ssize_t codec_reg_write_file(struct file *file,
reg = simple_strtoul(start, &start, 16);
while (*start == ' ')
start++;
if (strict_strtoul(start, 16, &value))
return -EINVAL;
ret = kstrtoul(start, 16, &value);
if (ret)
return ret;
/* Userspace has been fiddling around behind the kernel's back */
add_taint(TAINT_USER, LOCKDEP_NOW_UNRELIABLE);
@ -1243,9 +1245,6 @@ static int soc_post_component_init(struct snd_soc_card *card,
}
rtd->card = card;
/* Make sure all DAPM widgets are instantiated */
snd_soc_dapm_new_widgets(&codec->dapm);
/* machine controls, routes and widgets are not prefixed */
temp = codec->name_prefix;
codec->name_prefix = NULL;
@ -1741,8 +1740,6 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
snd_soc_dapm_add_routes(&card->dapm, card->dapm_routes,
card->num_dapm_routes);
snd_soc_dapm_new_widgets(&card->dapm);
for (i = 0; i < card->num_links; i++) {
dai_link = &card->dai_link[i];
dai_fmt = dai_link->dai_fmt;
@ -1821,12 +1818,12 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
}
}
snd_soc_dapm_new_widgets(&card->dapm);
if (card->fully_routed)
list_for_each_entry(codec, &card->codec_dev_list, card_list)
snd_soc_dapm_auto_nc_codec_pins(codec);
snd_soc_dapm_new_widgets(card);
ret = snd_card_register(card->snd_card);
if (ret < 0) {
dev_err(card->dev, "ASoC: failed to register soundcard %d\n",

View file

@ -229,6 +229,8 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget,
template.id = snd_soc_dapm_kcontrol;
template.name = kcontrol->id.name;
data->value = template.on_val;
data->widget = snd_soc_dapm_new_control(widget->dapm,
&template);
if (!data->widget) {
@ -2374,6 +2376,9 @@ static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
wsource->ext = 1;
}
dapm_mark_dirty(wsource, "Route added");
dapm_mark_dirty(wsink, "Route added");
/* connect static paths */
if (control == NULL) {
list_add(&path->list, &dapm->card->paths);
@ -2436,9 +2441,6 @@ static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
return 0;
}
dapm_mark_dirty(wsource, "Route added");
dapm_mark_dirty(wsink, "Route added");
return 0;
err:
kfree(path);
@ -2712,9 +2714,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_weak_routes);
*
* Returns 0 for success.
*/
int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm)
int snd_soc_dapm_new_widgets(struct snd_soc_card *card)
{
struct snd_soc_card *card = dapm->card;
struct snd_soc_dapm_widget *w;
unsigned int val;

View file

@ -183,8 +183,6 @@ int snd_soc_jack_add_pins(struct snd_soc_jack *jack, int count,
list_add(&(pins[i].list), &jack->pins);
}
snd_soc_dapm_new_widgets(&jack->codec->card->dapm);
/* Update to reflect the last reported status; canned jack
* implementations are likely to set their state before the
* card has an opportunity to associate pins.

View file

@ -2020,6 +2020,16 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
capture = 1;
}
if (rtd->dai_link->playback_only) {
playback = 1;
capture = 0;
}
if (rtd->dai_link->capture_only) {
playback = 0;
capture = 1;
}
/* create the PCM */
if (rtd->dai_link->no_pcm) {
snprintf(new_name, sizeof(new_name), "(%s)",

View file

@ -346,10 +346,10 @@ static int usb6fire_fw_check(u8 *version)
if (!memcmp(version, known_fw_versions + i, 2))
return 0;
snd_printk(KERN_ERR PREFIX "invalid fimware version in device: %*ph. "
snd_printk(KERN_ERR PREFIX "invalid fimware version in device: %4ph. "
"please reconnect to power. if this failure "
"still happens, check your firmware installation.",
4, version);
version);
return -EINVAL;
}

View file

@ -418,6 +418,9 @@ struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip,
struct snd_usb_endpoint *ep;
int is_playback = direction == SNDRV_PCM_STREAM_PLAYBACK;
if (WARN_ON(!alts))
return NULL;
mutex_lock(&chip->mutex);
list_for_each_entry(ep, &chip->ep_list, list) {

View file

@ -327,6 +327,137 @@ static int search_roland_implicit_fb(struct usb_device *dev, int ifnum,
return 0;
}
static int set_sync_ep_implicit_fb_quirk(struct snd_usb_substream *subs,
struct usb_device *dev,
struct usb_interface_descriptor *altsd,
unsigned int attr)
{
struct usb_host_interface *alts;
struct usb_interface *iface;
unsigned int ep;
/* Implicit feedback sync EPs consumers are always playback EPs */
if (subs->direction != SNDRV_PCM_STREAM_PLAYBACK)
return 0;
switch (subs->stream->chip->usb_id) {
case USB_ID(0x0763, 0x2030): /* M-Audio Fast Track C400 */
case USB_ID(0x0763, 0x2031): /* M-Audio Fast Track C600 */
ep = 0x81;
iface = usb_ifnum_to_if(dev, 3);
if (!iface || iface->num_altsetting == 0)
return -EINVAL;
alts = &iface->altsetting[1];
goto add_sync_ep;
break;
case USB_ID(0x0763, 0x2080): /* M-Audio FastTrack Ultra */
case USB_ID(0x0763, 0x2081):
ep = 0x81;
iface = usb_ifnum_to_if(dev, 2);
if (!iface || iface->num_altsetting == 0)
return -EINVAL;
alts = &iface->altsetting[1];
goto add_sync_ep;
}
if (attr == USB_ENDPOINT_SYNC_ASYNC &&
altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC &&
altsd->bInterfaceProtocol == 2 &&
altsd->bNumEndpoints == 1 &&
USB_ID_VENDOR(subs->stream->chip->usb_id) == 0x0582 /* Roland */ &&
search_roland_implicit_fb(dev, altsd->bInterfaceNumber + 1,
altsd->bAlternateSetting,
&alts, &ep) >= 0) {
goto add_sync_ep;
}
/* No quirk */
return 0;
add_sync_ep:
subs->sync_endpoint = snd_usb_add_endpoint(subs->stream->chip,
alts, ep, !subs->direction,
SND_USB_ENDPOINT_TYPE_DATA);
if (!subs->sync_endpoint)
return -EINVAL;
subs->data_endpoint->sync_master = subs->sync_endpoint;
return 0;
}
static int set_sync_endpoint(struct snd_usb_substream *subs,
struct audioformat *fmt,
struct usb_device *dev,
struct usb_host_interface *alts,
struct usb_interface_descriptor *altsd)
{
int is_playback = subs->direction == SNDRV_PCM_STREAM_PLAYBACK;
unsigned int ep, attr;
bool implicit_fb;
int err;
/* we need a sync pipe in async OUT or adaptive IN mode */
/* check the number of EP, since some devices have broken
* descriptors which fool us. if it has only one EP,
* assume it as adaptive-out or sync-in.
*/
attr = fmt->ep_attr & USB_ENDPOINT_SYNCTYPE;
err = set_sync_ep_implicit_fb_quirk(subs, dev, altsd, attr);
if (err < 0)
return err;
if (altsd->bNumEndpoints < 2)
return 0;
if ((is_playback && attr != USB_ENDPOINT_SYNC_ASYNC) ||
(!is_playback && attr != USB_ENDPOINT_SYNC_ADAPTIVE))
return 0;
/* check sync-pipe endpoint */
/* ... and check descriptor size before accessing bSynchAddress
because there is a version of the SB Audigy 2 NX firmware lacking
the audio fields in the endpoint descriptors */
if ((get_endpoint(alts, 1)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_ISOC ||
(get_endpoint(alts, 1)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE &&
get_endpoint(alts, 1)->bSynchAddress != 0)) {
snd_printk(KERN_ERR "%d:%d:%d : invalid sync pipe. bmAttributes %02x, bLength %d, bSynchAddress %02x\n",
dev->devnum, fmt->iface, fmt->altsetting,
get_endpoint(alts, 1)->bmAttributes,
get_endpoint(alts, 1)->bLength,
get_endpoint(alts, 1)->bSynchAddress);
return -EINVAL;
}
ep = get_endpoint(alts, 1)->bEndpointAddress;
if (get_endpoint(alts, 0)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE &&
((is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress | USB_DIR_IN)) ||
(!is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress & ~USB_DIR_IN)))) {
snd_printk(KERN_ERR "%d:%d:%d : invalid sync pipe. is_playback %d, ep %02x, bSynchAddress %02x\n",
dev->devnum, fmt->iface, fmt->altsetting,
is_playback, ep, get_endpoint(alts, 0)->bSynchAddress);
return -EINVAL;
}
implicit_fb = (get_endpoint(alts, 1)->bmAttributes & USB_ENDPOINT_USAGE_MASK)
== USB_ENDPOINT_USAGE_IMPLICIT_FB;
subs->sync_endpoint = snd_usb_add_endpoint(subs->stream->chip,
alts, ep, !subs->direction,
implicit_fb ?
SND_USB_ENDPOINT_TYPE_DATA :
SND_USB_ENDPOINT_TYPE_SYNC);
if (!subs->sync_endpoint)
return -EINVAL;
subs->data_endpoint->sync_master = subs->sync_endpoint;
return 0;
}
/*
* find a matching format and set up the interface
*/
@ -336,9 +467,7 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
struct usb_host_interface *alts;
struct usb_interface_descriptor *altsd;
struct usb_interface *iface;
unsigned int ep, attr;
int is_playback = subs->direction == SNDRV_PCM_STREAM_PLAYBACK;
int err, implicit_fb = 0;
int err;
iface = usb_ifnum_to_if(dev, fmt->iface);
if (WARN_ON(!iface))
@ -383,118 +512,22 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
subs->data_endpoint = snd_usb_add_endpoint(subs->stream->chip,
alts, fmt->endpoint, subs->direction,
SND_USB_ENDPOINT_TYPE_DATA);
if (!subs->data_endpoint)
return -EINVAL;
/* we need a sync pipe in async OUT or adaptive IN mode */
/* check the number of EP, since some devices have broken
* descriptors which fool us. if it has only one EP,
* assume it as adaptive-out or sync-in.
*/
attr = fmt->ep_attr & USB_ENDPOINT_SYNCTYPE;
err = set_sync_endpoint(subs, fmt, dev, alts, altsd);
if (err < 0)
return err;
switch (subs->stream->chip->usb_id) {
case USB_ID(0x0763, 0x2030): /* M-Audio Fast Track C400 */
case USB_ID(0x0763, 0x2031): /* M-Audio Fast Track C600 */
if (is_playback) {
implicit_fb = 1;
ep = 0x81;
iface = usb_ifnum_to_if(dev, 3);
if (!iface || iface->num_altsetting == 0)
return -EINVAL;
alts = &iface->altsetting[1];
goto add_sync_ep;
}
break;
case USB_ID(0x0763, 0x2080): /* M-Audio FastTrack Ultra */
case USB_ID(0x0763, 0x2081):
if (is_playback) {
implicit_fb = 1;
ep = 0x81;
iface = usb_ifnum_to_if(dev, 2);
if (!iface || iface->num_altsetting == 0)
return -EINVAL;
alts = &iface->altsetting[1];
goto add_sync_ep;
}
}
if (is_playback &&
attr == USB_ENDPOINT_SYNC_ASYNC &&
altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC &&
altsd->bInterfaceProtocol == 2 &&
altsd->bNumEndpoints == 1 &&
USB_ID_VENDOR(subs->stream->chip->usb_id) == 0x0582 /* Roland */ &&
search_roland_implicit_fb(dev, altsd->bInterfaceNumber + 1,
altsd->bAlternateSetting,
&alts, &ep) >= 0) {
implicit_fb = 1;
goto add_sync_ep;
}
if (((is_playback && attr == USB_ENDPOINT_SYNC_ASYNC) ||
(!is_playback && attr == USB_ENDPOINT_SYNC_ADAPTIVE)) &&
altsd->bNumEndpoints >= 2) {
/* check sync-pipe endpoint */
/* ... and check descriptor size before accessing bSynchAddress
because there is a version of the SB Audigy 2 NX firmware lacking
the audio fields in the endpoint descriptors */
if ((get_endpoint(alts, 1)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_ISOC ||
(get_endpoint(alts, 1)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE &&
get_endpoint(alts, 1)->bSynchAddress != 0 &&
!implicit_fb)) {
snd_printk(KERN_ERR "%d:%d:%d : invalid sync pipe. bmAttributes %02x, bLength %d, bSynchAddress %02x\n",
dev->devnum, fmt->iface, fmt->altsetting,
get_endpoint(alts, 1)->bmAttributes,
get_endpoint(alts, 1)->bLength,
get_endpoint(alts, 1)->bSynchAddress);
return -EINVAL;
}
ep = get_endpoint(alts, 1)->bEndpointAddress;
if (!implicit_fb &&
get_endpoint(alts, 0)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE &&
(( is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress | USB_DIR_IN)) ||
(!is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress & ~USB_DIR_IN)))) {
snd_printk(KERN_ERR "%d:%d:%d : invalid sync pipe. is_playback %d, ep %02x, bSynchAddress %02x\n",
dev->devnum, fmt->iface, fmt->altsetting,
is_playback, ep, get_endpoint(alts, 0)->bSynchAddress);
return -EINVAL;
}
implicit_fb = (get_endpoint(alts, 1)->bmAttributes & USB_ENDPOINT_USAGE_MASK)
== USB_ENDPOINT_USAGE_IMPLICIT_FB;
add_sync_ep:
subs->sync_endpoint = snd_usb_add_endpoint(subs->stream->chip,
alts, ep, !subs->direction,
implicit_fb ?
SND_USB_ENDPOINT_TYPE_DATA :
SND_USB_ENDPOINT_TYPE_SYNC);
if (!subs->sync_endpoint)
return -EINVAL;
subs->data_endpoint->sync_master = subs->sync_endpoint;
}
if ((err = snd_usb_init_pitch(subs->stream->chip, fmt->iface, alts, fmt)) < 0)
err = snd_usb_init_pitch(subs->stream->chip, fmt->iface, alts, fmt);
if (err < 0)
return err;
subs->cur_audiofmt = fmt;
snd_usb_set_format_quirk(subs, fmt);
#if 0
printk(KERN_DEBUG
"setting done: format = %d, rate = %d..%d, channels = %d\n",
fmt->format, fmt->rate_min, fmt->rate_max, fmt->channels);
printk(KERN_DEBUG
" datapipe = 0x%0x, syncpipe = 0x%0x\n",
subs->datapipe, subs->syncpipe);
#endif
return 0;
}

View file

@ -305,11 +305,9 @@ static void usX2Y_unlinkSeq(struct snd_usX2Y_AsyncSeq *S)
{
int i;
for (i = 0; i < URBS_AsyncSeq; ++i) {
if (S[i].urb) {
usb_kill_urb(S->urb[i]);
usb_free_urb(S->urb[i]);
S->urb[i] = NULL;
}
usb_kill_urb(S->urb[i]);
usb_free_urb(S->urb[i]);
S->urb[i] = NULL;
}
kfree(S->buffer);
}