Merge branch 'fix/misc' into topic/misc
This commit is contained in:
commit
b1ac29620b
53 changed files with 728 additions and 869 deletions
|
@ -349,6 +349,7 @@ STAC92HD83*
|
|||
ref Reference board
|
||||
mic-ref Reference board with power management for ports
|
||||
dell-s14 Dell laptop
|
||||
dell-vostro-3500 Dell Vostro 3500 laptop
|
||||
hp HP laptops with (inverted) mute-LED
|
||||
hp-dv7-4000 HP dv-7 4000
|
||||
auto BIOS setup (default)
|
||||
|
|
|
@ -579,7 +579,7 @@ Development Tree
|
|||
~~~~~~~~~~~~~~~~
|
||||
The latest development codes for HD-audio are found on sound git tree:
|
||||
|
||||
- git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6.git
|
||||
- git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
|
||||
|
||||
The master branch or for-next branches can be used as the main
|
||||
development branches in general while the HD-audio specific patches
|
||||
|
@ -594,7 +594,7 @@ is, installed via the usual spells: configure, make and make
|
|||
install(-modules). See INSTALL in the package. The snapshot tarballs
|
||||
are found at:
|
||||
|
||||
- ftp://ftp.kernel.org/pub/linux/kernel/people/tiwai/snapshot/
|
||||
- ftp://ftp.suse.com/pub/people/tiwai/snapshot/
|
||||
|
||||
|
||||
Sending a Bug Report
|
||||
|
@ -696,7 +696,7 @@ via hda-verb won't change the mixer value.
|
|||
|
||||
The hda-verb program is found in the ftp directory:
|
||||
|
||||
- ftp://ftp.kernel.org/pub/linux/kernel/people/tiwai/misc/
|
||||
- ftp://ftp.suse.com/pub/people/tiwai/misc/
|
||||
|
||||
Also a git repository is available:
|
||||
|
||||
|
@ -764,7 +764,7 @@ operation, the jack plugging simulation, etc.
|
|||
|
||||
The package is found in:
|
||||
|
||||
- ftp://ftp.kernel.org/pub/linux/kernel/people/tiwai/misc/
|
||||
- ftp://ftp.suse.com/pub/people/tiwai/misc/
|
||||
|
||||
A git repository is available:
|
||||
|
||||
|
|
|
@ -5648,7 +5648,6 @@ F: drivers/media/video/*7146*
|
|||
F: include/media/*7146*
|
||||
|
||||
SAMSUNG AUDIO (ASoC) DRIVERS
|
||||
M: Jassi Brar <jassisinghbrar@gmail.com>
|
||||
M: Sangbeom Kim <sbkim73@samsung.com>
|
||||
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
|
||||
S: Supported
|
||||
|
@ -6122,7 +6121,7 @@ F: sound/
|
|||
SOUND - SOC LAYER / DYNAMIC AUDIO POWER MANAGEMENT (ASoC)
|
||||
M: Liam Girdwood <lrg@ti.com>
|
||||
M: Mark Brown <broonie@opensource.wolfsonmicro.com>
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound-2.6.git
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
|
||||
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
|
||||
W: http://alsa-project.org/main/index.php/ASoC
|
||||
S: Supported
|
||||
|
|
|
@ -14,13 +14,34 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/sigma.h>
|
||||
|
||||
/* Return: 0==OK, <0==error, =1 ==no more actions */
|
||||
static int
|
||||
process_sigma_action(struct i2c_client *client, struct sigma_firmware *ssfw)
|
||||
static size_t sigma_action_size(struct sigma_action *sa)
|
||||
{
|
||||
size_t payload = 0;
|
||||
|
||||
switch (sa->instr) {
|
||||
case SIGMA_ACTION_WRITEXBYTES:
|
||||
case SIGMA_ACTION_WRITESINGLE:
|
||||
case SIGMA_ACTION_WRITESAFELOAD:
|
||||
payload = sigma_action_len(sa);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
payload = ALIGN(payload, 2);
|
||||
|
||||
return payload + sizeof(struct sigma_action);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns a negative error value in case of an error, 0 if processing of
|
||||
* the firmware should be stopped after this action, 1 otherwise.
|
||||
*/
|
||||
static int
|
||||
process_sigma_action(struct i2c_client *client, struct sigma_action *sa)
|
||||
{
|
||||
struct sigma_action *sa = (void *)(ssfw->fw->data + ssfw->pos);
|
||||
size_t len = sigma_action_len(sa);
|
||||
int ret = 0;
|
||||
int ret;
|
||||
|
||||
pr_debug("%s: instr:%i addr:%#x len:%zu\n", __func__,
|
||||
sa->instr, sa->addr, len);
|
||||
|
@ -29,44 +50,50 @@ process_sigma_action(struct i2c_client *client, struct sigma_firmware *ssfw)
|
|||
case SIGMA_ACTION_WRITEXBYTES:
|
||||
case SIGMA_ACTION_WRITESINGLE:
|
||||
case SIGMA_ACTION_WRITESAFELOAD:
|
||||
if (ssfw->fw->size < ssfw->pos + len)
|
||||
return -EINVAL;
|
||||
ret = i2c_master_send(client, (void *)&sa->addr, len);
|
||||
if (ret < 0)
|
||||
return -EINVAL;
|
||||
break;
|
||||
|
||||
case SIGMA_ACTION_DELAY:
|
||||
ret = 0;
|
||||
udelay(len);
|
||||
len = 0;
|
||||
break;
|
||||
|
||||
case SIGMA_ACTION_END:
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* when arrive here ret=0 or sent data */
|
||||
ssfw->pos += sigma_action_size(sa, len);
|
||||
return ssfw->pos == ssfw->fw->size;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
process_sigma_actions(struct i2c_client *client, struct sigma_firmware *ssfw)
|
||||
{
|
||||
pr_debug("%s: processing %p\n", __func__, ssfw);
|
||||
struct sigma_action *sa;
|
||||
size_t size;
|
||||
int ret;
|
||||
|
||||
while (ssfw->pos + sizeof(*sa) <= ssfw->fw->size) {
|
||||
sa = (struct sigma_action *)(ssfw->fw->data + ssfw->pos);
|
||||
|
||||
size = sigma_action_size(sa);
|
||||
ssfw->pos += size;
|
||||
if (ssfw->pos > ssfw->fw->size || size == 0)
|
||||
break;
|
||||
|
||||
ret = process_sigma_action(client, sa);
|
||||
|
||||
while (1) {
|
||||
int ret = process_sigma_action(client, ssfw);
|
||||
pr_debug("%s: action returned %i\n", __func__, ret);
|
||||
if (ret == 1)
|
||||
return 0;
|
||||
else if (ret)
|
||||
|
||||
if (ret <= 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ssfw->pos != ssfw->fw->size)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int process_sigma_firmware(struct i2c_client *client, const char *name)
|
||||
|
@ -89,16 +116,24 @@ int process_sigma_firmware(struct i2c_client *client, const char *name)
|
|||
|
||||
/* then verify the header */
|
||||
ret = -EINVAL;
|
||||
if (fw->size < sizeof(*ssfw_head))
|
||||
|
||||
/*
|
||||
* Reject too small or unreasonable large files. The upper limit has been
|
||||
* chosen a bit arbitrarily, but it should be enough for all practical
|
||||
* purposes and having the limit makes it easier to avoid integer
|
||||
* overflows later in the loading process.
|
||||
*/
|
||||
if (fw->size < sizeof(*ssfw_head) || fw->size >= 0x4000000)
|
||||
goto done;
|
||||
|
||||
ssfw_head = (void *)fw->data;
|
||||
if (memcmp(ssfw_head->magic, SIGMA_MAGIC, ARRAY_SIZE(ssfw_head->magic)))
|
||||
goto done;
|
||||
|
||||
crc = crc32(0, fw->data, fw->size);
|
||||
crc = crc32(0, fw->data + sizeof(*ssfw_head),
|
||||
fw->size - sizeof(*ssfw_head));
|
||||
pr_debug("%s: crc=%x\n", __func__, crc);
|
||||
if (crc != ssfw_head->crc)
|
||||
if (crc != le32_to_cpu(ssfw_head->crc))
|
||||
goto done;
|
||||
|
||||
ssfw.pos = sizeof(*ssfw_head);
|
||||
|
|
|
@ -1962,6 +1962,21 @@
|
|||
#define WM8958_MICB2_DISCH_SHIFT 0 /* MICB2_DISCH */
|
||||
#define WM8958_MICB2_DISCH_WIDTH 1 /* MICB2_DISCH */
|
||||
|
||||
/*
|
||||
* R210 (0xD2) - Mic Detect 3
|
||||
*/
|
||||
#define WM8958_MICD_LVL_MASK 0x07FC /* MICD_LVL - [10:2] */
|
||||
#define WM8958_MICD_LVL_SHIFT 2 /* MICD_LVL - [10:2] */
|
||||
#define WM8958_MICD_LVL_WIDTH 9 /* MICD_LVL - [10:2] */
|
||||
#define WM8958_MICD_VALID 0x0002 /* MICD_VALID */
|
||||
#define WM8958_MICD_VALID_MASK 0x0002 /* MICD_VALID */
|
||||
#define WM8958_MICD_VALID_SHIFT 1 /* MICD_VALID */
|
||||
#define WM8958_MICD_VALID_WIDTH 1 /* MICD_VALID */
|
||||
#define WM8958_MICD_STS 0x0001 /* MICD_STS */
|
||||
#define WM8958_MICD_STS_MASK 0x0001 /* MICD_STS */
|
||||
#define WM8958_MICD_STS_SHIFT 0 /* MICD_STS */
|
||||
#define WM8958_MICD_STS_WIDTH 1 /* MICD_STS */
|
||||
|
||||
/*
|
||||
* R76 (0x4C) - Charge Pump (1)
|
||||
*/
|
||||
|
|
|
@ -24,7 +24,7 @@ struct sigma_firmware {
|
|||
struct sigma_firmware_header {
|
||||
unsigned char magic[7];
|
||||
u8 version;
|
||||
u32 crc;
|
||||
__le32 crc;
|
||||
};
|
||||
|
||||
enum {
|
||||
|
@ -40,19 +40,14 @@ enum {
|
|||
struct sigma_action {
|
||||
u8 instr;
|
||||
u8 len_hi;
|
||||
u16 len;
|
||||
u16 addr;
|
||||
__le16 len;
|
||||
__be16 addr;
|
||||
unsigned char payload[];
|
||||
};
|
||||
|
||||
static inline u32 sigma_action_len(struct sigma_action *sa)
|
||||
{
|
||||
return (sa->len_hi << 16) | sa->len;
|
||||
}
|
||||
|
||||
static inline size_t sigma_action_size(struct sigma_action *sa, u32 payload_len)
|
||||
{
|
||||
return sizeof(*sa) + payload_len + (payload_len % 2);
|
||||
return (sa->len_hi << 16) | le16_to_cpu(sa->len);
|
||||
}
|
||||
|
||||
extern int process_sigma_firmware(struct i2c_client *client, const char *name);
|
||||
|
|
|
@ -52,6 +52,7 @@ struct link_slave {
|
|||
struct link_ctl_info info;
|
||||
int vals[2]; /* current values */
|
||||
unsigned int flags;
|
||||
struct snd_kcontrol *kctl; /* original kcontrol pointer */
|
||||
struct snd_kcontrol slave; /* the copy of original control entry */
|
||||
};
|
||||
|
||||
|
@ -252,6 +253,7 @@ int _snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave,
|
|||
slave->count * sizeof(*slave->vd), GFP_KERNEL);
|
||||
if (!srec)
|
||||
return -ENOMEM;
|
||||
srec->kctl = slave;
|
||||
srec->slave = *slave;
|
||||
memcpy(srec->slave.vd, slave->vd, slave->count * sizeof(*slave->vd));
|
||||
srec->master = master_link;
|
||||
|
@ -333,10 +335,18 @@ static int master_put(struct snd_kcontrol *kcontrol,
|
|||
static void master_free(struct snd_kcontrol *kcontrol)
|
||||
{
|
||||
struct link_master *master = snd_kcontrol_chip(kcontrol);
|
||||
struct link_slave *slave;
|
||||
struct link_slave *slave, *n;
|
||||
|
||||
list_for_each_entry(slave, &master->slaves, list)
|
||||
slave->master = NULL;
|
||||
/* free all slave links and retore the original slave kctls */
|
||||
list_for_each_entry_safe(slave, n, &master->slaves, list) {
|
||||
struct snd_kcontrol *sctl = slave->kctl;
|
||||
struct list_head olist = sctl->list;
|
||||
memcpy(sctl, &slave->slave, sizeof(*sctl));
|
||||
memcpy(sctl->vd, slave->slave.vd,
|
||||
sctl->count * sizeof(*sctl->vd));
|
||||
sctl->list = olist; /* keep the current linked-list */
|
||||
kfree(slave);
|
||||
}
|
||||
kfree(master);
|
||||
}
|
||||
|
||||
|
|
|
@ -148,7 +148,7 @@ static int cs5535audio_build_dma_packets(struct cs5535audio *cs5535au,
|
|||
struct cs5535audio_dma_desc *desc =
|
||||
&((struct cs5535audio_dma_desc *) dma->desc_buf.area)[i];
|
||||
desc->addr = cpu_to_le32(addr);
|
||||
desc->size = cpu_to_le32(period_bytes);
|
||||
desc->size = cpu_to_le16(period_bytes);
|
||||
desc->ctlreserved = cpu_to_le16(PRD_EOP);
|
||||
desc_addr += sizeof(struct cs5535audio_dma_desc);
|
||||
addr += period_bytes;
|
||||
|
|
|
@ -2331,6 +2331,39 @@ int snd_hda_codec_reset(struct hda_codec *codec)
|
|||
return 0;
|
||||
}
|
||||
|
||||
typedef int (*map_slave_func_t)(void *, struct snd_kcontrol *);
|
||||
|
||||
/* apply the function to all matching slave ctls in the mixer list */
|
||||
static int map_slaves(struct hda_codec *codec, const char * const *slaves,
|
||||
map_slave_func_t func, void *data)
|
||||
{
|
||||
struct hda_nid_item *items;
|
||||
const char * const *s;
|
||||
int i, err;
|
||||
|
||||
items = codec->mixers.list;
|
||||
for (i = 0; i < codec->mixers.used; i++) {
|
||||
struct snd_kcontrol *sctl = items[i].kctl;
|
||||
if (!sctl || !sctl->id.name ||
|
||||
sctl->id.iface != SNDRV_CTL_ELEM_IFACE_MIXER)
|
||||
continue;
|
||||
for (s = slaves; *s; s++) {
|
||||
if (!strcmp(sctl->id.name, *s)) {
|
||||
err = func(data, sctl);
|
||||
if (err)
|
||||
return err;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int check_slave_present(void *data, struct snd_kcontrol *sctl)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_hda_add_vmaster - create a virtual master control and add slaves
|
||||
* @codec: HD-audio codec
|
||||
|
@ -2351,12 +2384,10 @@ int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
|
|||
unsigned int *tlv, const char * const *slaves)
|
||||
{
|
||||
struct snd_kcontrol *kctl;
|
||||
const char * const *s;
|
||||
int err;
|
||||
|
||||
for (s = slaves; *s && !snd_hda_find_mixer_ctl(codec, *s); s++)
|
||||
;
|
||||
if (!*s) {
|
||||
err = map_slaves(codec, slaves, check_slave_present, NULL);
|
||||
if (err != 1) {
|
||||
snd_printdd("No slave found for %s\n", name);
|
||||
return 0;
|
||||
}
|
||||
|
@ -2367,23 +2398,10 @@ int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
|
|||
if (err < 0)
|
||||
return err;
|
||||
|
||||
for (s = slaves; *s; s++) {
|
||||
struct snd_kcontrol *sctl;
|
||||
int i = 0;
|
||||
for (;;) {
|
||||
sctl = _snd_hda_find_mixer_ctl(codec, *s, i);
|
||||
if (!sctl) {
|
||||
if (!i)
|
||||
snd_printdd("Cannot find slave %s, "
|
||||
"skipped\n", *s);
|
||||
break;
|
||||
}
|
||||
err = snd_ctl_add_slave(kctl, sctl);
|
||||
if (err < 0)
|
||||
return err;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
err = map_slaves(codec, slaves, (map_slave_func_t)snd_ctl_add_slave,
|
||||
kctl);
|
||||
if (err < 0)
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_add_vmaster);
|
||||
|
@ -4028,9 +4046,9 @@ int snd_hda_check_board_codec_sid_config(struct hda_codec *codec,
|
|||
|
||||
/* Search for codec ID */
|
||||
for (q = tbl; q->subvendor; q++) {
|
||||
unsigned long vendorid = (q->subdevice) | (q->subvendor << 16);
|
||||
|
||||
if (vendorid == codec->subsystem_id)
|
||||
unsigned int mask = 0xffff0000 | q->subdevice_mask;
|
||||
unsigned int id = (q->subdevice | (q->subvendor << 16)) & mask;
|
||||
if ((codec->subsystem_id & mask) == id)
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -4752,6 +4770,7 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
|
|||
memset(sequences_hp, 0, sizeof(sequences_hp));
|
||||
assoc_line_out = 0;
|
||||
|
||||
codec->ignore_misc_bit = true;
|
||||
end_nid = codec->start_nid + codec->num_nodes;
|
||||
for (nid = codec->start_nid; nid < end_nid; nid++) {
|
||||
unsigned int wid_caps = get_wcaps(codec, nid);
|
||||
|
@ -4767,6 +4786,9 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
|
|||
continue;
|
||||
|
||||
def_conf = snd_hda_codec_get_pincfg(codec, nid);
|
||||
if (!(get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) &
|
||||
AC_DEFCFG_MISC_NO_PRESENCE))
|
||||
codec->ignore_misc_bit = false;
|
||||
conn = get_defcfg_connect(def_conf);
|
||||
if (conn == AC_JACK_PORT_NONE)
|
||||
continue;
|
||||
|
|
|
@ -854,6 +854,7 @@ struct hda_codec {
|
|||
unsigned int no_sticky_stream:1; /* no sticky-PCM stream assignment */
|
||||
unsigned int pins_shutup:1; /* pins are shut up */
|
||||
unsigned int no_trigger_sense:1; /* don't trigger at pin-sensing */
|
||||
unsigned int ignore_misc_bit:1; /* ignore MISC_NO_PRESENCE bit */
|
||||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
unsigned int power_on :1; /* current (global) power-state */
|
||||
unsigned int power_transition :1; /* power-state in transition */
|
||||
|
|
|
@ -297,10 +297,18 @@ static int hdmi_update_eld(struct hdmi_eld *e,
|
|||
buf + ELD_FIXED_BYTES + mnl + 3 * i);
|
||||
}
|
||||
|
||||
/*
|
||||
* HDMI sink's ELD info cannot always be retrieved for now, e.g.
|
||||
* in console or for audio devices. Assume the highest speakers
|
||||
* configuration, to _not_ prohibit multi-channel audio playback.
|
||||
*/
|
||||
if (!e->spk_alloc)
|
||||
e->spk_alloc = 0xffff;
|
||||
|
||||
e->eld_valid = true;
|
||||
return 0;
|
||||
|
||||
out_fail:
|
||||
e->eld_ver = 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -323,9 +331,6 @@ int snd_hdmi_get_eld(struct hdmi_eld *eld,
|
|||
* ELD is valid, actual eld_size is assigned in hdmi_update_eld()
|
||||
*/
|
||||
|
||||
if (!eld->eld_valid)
|
||||
return -ENOENT;
|
||||
|
||||
size = snd_hdmi_get_eld_size(codec, nid);
|
||||
if (size == 0) {
|
||||
/* wfg: workaround for ASUS P5E-VM HDMI board */
|
||||
|
@ -342,18 +347,28 @@ int snd_hdmi_get_eld(struct hdmi_eld *eld,
|
|||
|
||||
for (i = 0; i < size; i++) {
|
||||
unsigned int val = hdmi_get_eld_data(codec, nid, i);
|
||||
/*
|
||||
* Graphics driver might be writing to ELD buffer right now.
|
||||
* Just abort. The caller will repoll after a while.
|
||||
*/
|
||||
if (!(val & AC_ELDD_ELD_VALID)) {
|
||||
if (!i) {
|
||||
snd_printd(KERN_INFO
|
||||
"HDMI: invalid ELD data\n");
|
||||
ret = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
snd_printd(KERN_INFO
|
||||
"HDMI: invalid ELD data byte %d\n", i);
|
||||
val = 0;
|
||||
} else
|
||||
val &= AC_ELDD_ELD_DATA;
|
||||
ret = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
val &= AC_ELDD_ELD_DATA;
|
||||
/*
|
||||
* The first byte cannot be zero. This can happen on some DVI
|
||||
* connections. Some Intel chips may also need some 250ms delay
|
||||
* to return non-zero ELD data, even when the graphics driver
|
||||
* correctly writes ELD content before setting ELD_valid bit.
|
||||
*/
|
||||
if (!val && !i) {
|
||||
snd_printdd(KERN_INFO "HDMI: 0 ELD data\n");
|
||||
ret = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
buf[i] = val;
|
||||
}
|
||||
|
||||
|
|
|
@ -2508,7 +2508,6 @@ static struct snd_pci_quirk position_fix_list[] __devinitdata = {
|
|||
SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS", POS_FIX_LPIB),
|
||||
SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS M2V", POS_FIX_LPIB),
|
||||
SND_PCI_QUIRK(0x104d, 0x9069, "Sony VPCS11V9E", POS_FIX_LPIB),
|
||||
SND_PCI_QUIRK(0x1106, 0x3288, "ASUS M2V-MX SE", POS_FIX_LPIB),
|
||||
SND_PCI_QUIRK(0x1297, 0x3166, "Shuttle", POS_FIX_LPIB),
|
||||
SND_PCI_QUIRK(0x1458, 0xa022, "ga-ma770-ud3", POS_FIX_LPIB),
|
||||
SND_PCI_QUIRK(0x1462, 0x1002, "MSI Wind U115", POS_FIX_LPIB),
|
||||
|
|
|
@ -510,13 +510,15 @@ int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid);
|
|||
|
||||
static inline bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid)
|
||||
{
|
||||
return (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_PRES_DETECT) &&
|
||||
/* disable MISC_NO_PRESENCE check because it may break too
|
||||
* many devices
|
||||
*/
|
||||
/*(get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid) &
|
||||
AC_DEFCFG_MISC_NO_PRESENCE)) &&*/
|
||||
(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP);
|
||||
if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_PRES_DETECT))
|
||||
return false;
|
||||
if (!codec->ignore_misc_bit &&
|
||||
(get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) &
|
||||
AC_DEFCFG_MISC_NO_PRESENCE))
|
||||
return false;
|
||||
if (!(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* flags for hda_nid_item */
|
||||
|
@ -651,6 +653,9 @@ struct hdmi_eld {
|
|||
int spk_alloc;
|
||||
int sad_count;
|
||||
struct cea_sad sad[ELD_MAX_SAD];
|
||||
/*
|
||||
* all fields above eld_buffer will be cleared before updating ELD
|
||||
*/
|
||||
char eld_buffer[ELD_MAX_SIZE];
|
||||
#ifdef CONFIG_PROC_FS
|
||||
struct snd_info_entry *proc_entry;
|
||||
|
|
|
@ -58,6 +58,8 @@ struct cs_spec {
|
|||
unsigned int gpio_mask;
|
||||
unsigned int gpio_dir;
|
||||
unsigned int gpio_data;
|
||||
unsigned int gpio_eapd_hp; /* EAPD GPIO bit for headphones */
|
||||
unsigned int gpio_eapd_speaker; /* EAPD GPIO bit for speakers */
|
||||
|
||||
struct hda_pcm pcm_rec[2]; /* PCM information */
|
||||
|
||||
|
@ -76,6 +78,7 @@ enum {
|
|||
CS420X_MBP53,
|
||||
CS420X_MBP55,
|
||||
CS420X_IMAC27,
|
||||
CS420X_APPLE,
|
||||
CS420X_AUTO,
|
||||
CS420X_MODELS
|
||||
};
|
||||
|
@ -237,6 +240,15 @@ static int cs_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
|
|||
return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
|
||||
}
|
||||
|
||||
static void cs_update_input_select(struct hda_codec *codec)
|
||||
{
|
||||
struct cs_spec *spec = codec->spec;
|
||||
if (spec->cur_adc)
|
||||
snd_hda_codec_write(codec, spec->cur_adc, 0,
|
||||
AC_VERB_SET_CONNECT_SEL,
|
||||
spec->adc_idx[spec->cur_input]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Analog capture
|
||||
*/
|
||||
|
@ -250,6 +262,7 @@ static int cs_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
|
|||
spec->cur_adc = spec->adc_nid[spec->cur_input];
|
||||
spec->cur_adc_stream_tag = stream_tag;
|
||||
spec->cur_adc_format = format;
|
||||
cs_update_input_select(codec);
|
||||
snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format);
|
||||
return 0;
|
||||
}
|
||||
|
@ -689,10 +702,8 @@ static int change_cur_input(struct hda_codec *codec, unsigned int idx,
|
|||
spec->cur_adc_stream_tag, 0,
|
||||
spec->cur_adc_format);
|
||||
}
|
||||
snd_hda_codec_write(codec, spec->cur_adc, 0,
|
||||
AC_VERB_SET_CONNECT_SEL,
|
||||
spec->adc_idx[idx]);
|
||||
spec->cur_input = idx;
|
||||
cs_update_input_select(codec);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -920,10 +931,9 @@ static void cs_automute(struct hda_codec *codec)
|
|||
spdif_present ? 0 : PIN_OUT);
|
||||
}
|
||||
}
|
||||
if (spec->board_config == CS420X_MBP53 ||
|
||||
spec->board_config == CS420X_MBP55 ||
|
||||
spec->board_config == CS420X_IMAC27) {
|
||||
unsigned int gpio = hp_present ? 0x02 : 0x08;
|
||||
if (spec->gpio_eapd_hp) {
|
||||
unsigned int gpio = hp_present ?
|
||||
spec->gpio_eapd_hp : spec->gpio_eapd_speaker;
|
||||
snd_hda_codec_write(codec, 0x01, 0,
|
||||
AC_VERB_SET_GPIO_DATA, gpio);
|
||||
}
|
||||
|
@ -973,10 +983,7 @@ static void cs_automic(struct hda_codec *codec)
|
|||
} else {
|
||||
spec->cur_input = spec->last_input;
|
||||
}
|
||||
|
||||
snd_hda_codec_write_cache(codec, spec->cur_adc, 0,
|
||||
AC_VERB_SET_CONNECT_SEL,
|
||||
spec->adc_idx[spec->cur_input]);
|
||||
cs_update_input_select(codec);
|
||||
} else {
|
||||
if (present)
|
||||
change_cur_input(codec, spec->automic_idx, 0);
|
||||
|
@ -1073,9 +1080,7 @@ static void init_input(struct hda_codec *codec)
|
|||
cs_automic(codec);
|
||||
else {
|
||||
spec->cur_adc = spec->adc_nid[spec->cur_input];
|
||||
snd_hda_codec_write(codec, spec->cur_adc, 0,
|
||||
AC_VERB_SET_CONNECT_SEL,
|
||||
spec->adc_idx[spec->cur_input]);
|
||||
cs_update_input_select(codec);
|
||||
}
|
||||
} else {
|
||||
change_cur_input(codec, spec->cur_input, 1);
|
||||
|
@ -1273,6 +1278,7 @@ static const char * const cs420x_models[CS420X_MODELS] = {
|
|||
[CS420X_MBP53] = "mbp53",
|
||||
[CS420X_MBP55] = "mbp55",
|
||||
[CS420X_IMAC27] = "imac27",
|
||||
[CS420X_APPLE] = "apple",
|
||||
[CS420X_AUTO] = "auto",
|
||||
};
|
||||
|
||||
|
@ -1282,7 +1288,13 @@ static const struct snd_pci_quirk cs420x_cfg_tbl[] = {
|
|||
SND_PCI_QUIRK(0x10de, 0x0d94, "MacBookAir 3,1(2)", CS420X_MBP55),
|
||||
SND_PCI_QUIRK(0x10de, 0xcb79, "MacBookPro 5,5", CS420X_MBP55),
|
||||
SND_PCI_QUIRK(0x10de, 0xcb89, "MacBookPro 7,1", CS420X_MBP55),
|
||||
SND_PCI_QUIRK(0x8086, 0x7270, "IMac 27 Inch", CS420X_IMAC27),
|
||||
/* this conflicts with too many other models */
|
||||
/*SND_PCI_QUIRK(0x8086, 0x7270, "IMac 27 Inch", CS420X_IMAC27),*/
|
||||
{} /* terminator */
|
||||
};
|
||||
|
||||
static const struct snd_pci_quirk cs420x_codec_cfg_tbl[] = {
|
||||
SND_PCI_QUIRK_VENDOR(0x106b, "Apple", CS420X_APPLE),
|
||||
{} /* terminator */
|
||||
};
|
||||
|
||||
|
@ -1364,6 +1376,10 @@ static int patch_cs420x(struct hda_codec *codec)
|
|||
spec->board_config =
|
||||
snd_hda_check_board_config(codec, CS420X_MODELS,
|
||||
cs420x_models, cs420x_cfg_tbl);
|
||||
if (spec->board_config < 0)
|
||||
spec->board_config =
|
||||
snd_hda_check_board_codec_sid_config(codec,
|
||||
CS420X_MODELS, NULL, cs420x_codec_cfg_tbl);
|
||||
if (spec->board_config >= 0)
|
||||
fix_pincfg(codec, spec->board_config, cs_pincfgs);
|
||||
|
||||
|
@ -1371,10 +1387,11 @@ static int patch_cs420x(struct hda_codec *codec)
|
|||
case CS420X_IMAC27:
|
||||
case CS420X_MBP53:
|
||||
case CS420X_MBP55:
|
||||
/* GPIO1 = headphones */
|
||||
/* GPIO3 = speakers */
|
||||
spec->gpio_mask = 0x0a;
|
||||
spec->gpio_dir = 0x0a;
|
||||
case CS420X_APPLE:
|
||||
spec->gpio_eapd_hp = 2; /* GPIO1 = headphones */
|
||||
spec->gpio_eapd_speaker = 8; /* GPIO3 = speakers */
|
||||
spec->gpio_mask = spec->gpio_dir =
|
||||
spec->gpio_eapd_hp | spec->gpio_eapd_speaker;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -3062,7 +3062,6 @@ static const struct snd_pci_quirk cxt5066_cfg_tbl[] = {
|
|||
SND_PCI_QUIRK(0x1043, 0x1993, "Asus U50F", CXT5066_ASUS),
|
||||
SND_PCI_QUIRK(0x1179, 0xff1e, "Toshiba Satellite C650D", CXT5066_IDEAPAD),
|
||||
SND_PCI_QUIRK(0x1179, 0xff50, "Toshiba Satellite P500-PSPGSC-01800T", CXT5066_OLPC_XO_1_5),
|
||||
SND_PCI_QUIRK(0x1179, 0xffe0, "Toshiba Satellite Pro T130-15F", CXT5066_OLPC_XO_1_5),
|
||||
SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board",
|
||||
CXT5066_LAPTOP),
|
||||
SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5),
|
||||
|
|
|
@ -65,7 +65,11 @@ struct hdmi_spec_per_pin {
|
|||
hda_nid_t pin_nid;
|
||||
int num_mux_nids;
|
||||
hda_nid_t mux_nids[HDA_MAX_CONNECTIONS];
|
||||
|
||||
struct hda_codec *codec;
|
||||
struct hdmi_eld sink_eld;
|
||||
struct delayed_work work;
|
||||
int repoll_count;
|
||||
};
|
||||
|
||||
struct hdmi_spec {
|
||||
|
@ -745,8 +749,7 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, int pin_idx,
|
|||
* Unsolicited events
|
||||
*/
|
||||
|
||||
static void hdmi_present_sense(struct hda_codec *codec, hda_nid_t pin_nid,
|
||||
struct hdmi_eld *eld);
|
||||
static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll);
|
||||
|
||||
static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
|
||||
{
|
||||
|
@ -755,7 +758,6 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
|
|||
int pd = !!(res & AC_UNSOL_RES_PD);
|
||||
int eldv = !!(res & AC_UNSOL_RES_ELDV);
|
||||
int pin_idx;
|
||||
struct hdmi_eld *eld;
|
||||
|
||||
printk(KERN_INFO
|
||||
"HDMI hot plug event: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n",
|
||||
|
@ -764,17 +766,8 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
|
|||
pin_idx = pin_nid_to_pin_index(spec, pin_nid);
|
||||
if (pin_idx < 0)
|
||||
return;
|
||||
eld = &spec->pins[pin_idx].sink_eld;
|
||||
|
||||
hdmi_present_sense(codec, pin_nid, eld);
|
||||
|
||||
/*
|
||||
* HDMI sink's ELD info cannot always be retrieved for now, e.g.
|
||||
* in console or for audio devices. Assume the highest speakers
|
||||
* configuration, to _not_ prohibit multi-channel audio playback.
|
||||
*/
|
||||
if (!eld->spk_alloc)
|
||||
eld->spk_alloc = 0xffff;
|
||||
hdmi_present_sense(&spec->pins[pin_idx], 1);
|
||||
}
|
||||
|
||||
static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res)
|
||||
|
@ -968,9 +961,11 @@ static int hdmi_read_pin_conn(struct hda_codec *codec, int pin_idx)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void hdmi_present_sense(struct hda_codec *codec, hda_nid_t pin_nid,
|
||||
struct hdmi_eld *eld)
|
||||
static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
|
||||
{
|
||||
struct hda_codec *codec = per_pin->codec;
|
||||
struct hdmi_eld *eld = &per_pin->sink_eld;
|
||||
hda_nid_t pin_nid = per_pin->pin_nid;
|
||||
/*
|
||||
* Always execute a GetPinSense verb here, even when called from
|
||||
* hdmi_intrinsic_event; for some NVIDIA HW, the unsolicited
|
||||
|
@ -980,26 +975,42 @@ static void hdmi_present_sense(struct hda_codec *codec, hda_nid_t pin_nid,
|
|||
* the unsolicited response to avoid custom WARs.
|
||||
*/
|
||||
int present = snd_hda_pin_sense(codec, pin_nid);
|
||||
bool eld_valid = false;
|
||||
|
||||
memset(eld, 0, sizeof(*eld));
|
||||
memset(eld, 0, offsetof(struct hdmi_eld, eld_buffer));
|
||||
|
||||
eld->monitor_present = !!(present & AC_PINSENSE_PRESENCE);
|
||||
if (eld->monitor_present)
|
||||
eld->eld_valid = !!(present & AC_PINSENSE_ELDV);
|
||||
else
|
||||
eld->eld_valid = 0;
|
||||
eld_valid = !!(present & AC_PINSENSE_ELDV);
|
||||
|
||||
printk(KERN_INFO
|
||||
"HDMI status: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n",
|
||||
codec->addr, pin_nid, eld->monitor_present, eld->eld_valid);
|
||||
codec->addr, pin_nid, eld->monitor_present, eld_valid);
|
||||
|
||||
if (eld->eld_valid)
|
||||
if (eld_valid) {
|
||||
if (!snd_hdmi_get_eld(eld, codec, pin_nid))
|
||||
snd_hdmi_show_eld(eld);
|
||||
else if (repoll) {
|
||||
queue_delayed_work(codec->bus->workq,
|
||||
&per_pin->work,
|
||||
msecs_to_jiffies(300));
|
||||
}
|
||||
}
|
||||
|
||||
snd_hda_input_jack_report(codec, pin_nid);
|
||||
}
|
||||
|
||||
static void hdmi_repoll_eld(struct work_struct *work)
|
||||
{
|
||||
struct hdmi_spec_per_pin *per_pin =
|
||||
container_of(to_delayed_work(work), struct hdmi_spec_per_pin, work);
|
||||
|
||||
if (per_pin->repoll_count++ > 6)
|
||||
per_pin->repoll_count = 0;
|
||||
|
||||
hdmi_present_sense(per_pin, per_pin->repoll_count);
|
||||
}
|
||||
|
||||
static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)
|
||||
{
|
||||
struct hdmi_spec *spec = codec->spec;
|
||||
|
@ -1228,7 +1239,7 @@ static int generic_hdmi_build_jack(struct hda_codec *codec, int pin_idx)
|
|||
if (err < 0)
|
||||
return err;
|
||||
|
||||
hdmi_present_sense(codec, per_pin->pin_nid, &per_pin->sink_eld);
|
||||
hdmi_present_sense(per_pin, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1279,6 +1290,8 @@ static int generic_hdmi_init(struct hda_codec *codec)
|
|||
AC_VERB_SET_UNSOLICITED_ENABLE,
|
||||
AC_USRSP_EN | pin_nid);
|
||||
|
||||
per_pin->codec = codec;
|
||||
INIT_DELAYED_WORK(&per_pin->work, hdmi_repoll_eld);
|
||||
snd_hda_eld_proc_new(codec, eld, pin_idx);
|
||||
}
|
||||
return 0;
|
||||
|
@ -1293,10 +1306,12 @@ static void generic_hdmi_free(struct hda_codec *codec)
|
|||
struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
|
||||
struct hdmi_eld *eld = &per_pin->sink_eld;
|
||||
|
||||
cancel_delayed_work(&per_pin->work);
|
||||
snd_hda_eld_proc_free(codec, eld);
|
||||
}
|
||||
snd_hda_input_jack_free(codec);
|
||||
|
||||
flush_workqueue(codec->bus->workq);
|
||||
kfree(spec);
|
||||
}
|
||||
|
||||
|
|
|
@ -277,6 +277,12 @@ static bool alc_dyn_adc_pcm_resetup(struct hda_codec *codec, int cur)
|
|||
return false;
|
||||
}
|
||||
|
||||
static inline hda_nid_t get_capsrc(struct alc_spec *spec, int idx)
|
||||
{
|
||||
return spec->capsrc_nids ?
|
||||
spec->capsrc_nids[idx] : spec->adc_nids[idx];
|
||||
}
|
||||
|
||||
/* select the given imux item; either unmute exclusively or select the route */
|
||||
static int alc_mux_select(struct hda_codec *codec, unsigned int adc_idx,
|
||||
unsigned int idx, bool force)
|
||||
|
@ -284,7 +290,7 @@ static int alc_mux_select(struct hda_codec *codec, unsigned int adc_idx,
|
|||
struct alc_spec *spec = codec->spec;
|
||||
const struct hda_input_mux *imux;
|
||||
unsigned int mux_idx;
|
||||
int i, type;
|
||||
int i, type, num_conns;
|
||||
hda_nid_t nid;
|
||||
|
||||
mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx;
|
||||
|
@ -303,20 +309,20 @@ static int alc_mux_select(struct hda_codec *codec, unsigned int adc_idx,
|
|||
adc_idx = spec->dyn_adc_idx[idx];
|
||||
}
|
||||
|
||||
nid = spec->capsrc_nids ?
|
||||
spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx];
|
||||
nid = get_capsrc(spec, adc_idx);
|
||||
|
||||
/* no selection? */
|
||||
if (snd_hda_get_conn_list(codec, nid, NULL) <= 1)
|
||||
num_conns = snd_hda_get_conn_list(codec, nid, NULL);
|
||||
if (num_conns <= 1)
|
||||
return 1;
|
||||
|
||||
type = get_wcaps_type(get_wcaps(codec, nid));
|
||||
if (type == AC_WID_AUD_MIX) {
|
||||
/* Matrix-mixer style (e.g. ALC882) */
|
||||
for (i = 0; i < imux->num_items; i++) {
|
||||
unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE;
|
||||
snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT,
|
||||
imux->items[i].index,
|
||||
int active = imux->items[idx].index;
|
||||
for (i = 0; i < num_conns; i++) {
|
||||
unsigned int v = (i == active) ? 0 : HDA_AMP_MUTE;
|
||||
snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, i,
|
||||
HDA_AMP_MUTE, v);
|
||||
}
|
||||
} else {
|
||||
|
@ -1053,8 +1059,19 @@ static bool alc_rebuild_imux_for_auto_mic(struct hda_codec *codec)
|
|||
spec->imux_pins[2] = spec->dock_mic_pin;
|
||||
for (i = 0; i < 3; i++) {
|
||||
strcpy(imux->items[i].label, texts[i]);
|
||||
if (spec->imux_pins[i])
|
||||
if (spec->imux_pins[i]) {
|
||||
hda_nid_t pin = spec->imux_pins[i];
|
||||
int c;
|
||||
for (c = 0; c < spec->num_adc_nids; c++) {
|
||||
hda_nid_t cap = get_capsrc(spec, c);
|
||||
int idx = get_connection_index(codec, cap, pin);
|
||||
if (idx >= 0) {
|
||||
imux->items[i].index = idx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
imux->num_items = i + 1;
|
||||
}
|
||||
}
|
||||
spec->num_mux_defs = 1;
|
||||
spec->input_mux = imux;
|
||||
|
@ -1451,7 +1468,7 @@ static void alc_apply_fixup(struct hda_codec *codec, int action)
|
|||
switch (fix->type) {
|
||||
case ALC_FIXUP_SKU:
|
||||
if (action != ALC_FIXUP_ACT_PRE_PROBE || !fix->v.sku)
|
||||
break;;
|
||||
break;
|
||||
snd_printdd(KERN_INFO "hda_codec: %s: "
|
||||
"Apply sku override for %s\n",
|
||||
codec->chip_name, modelname);
|
||||
|
@ -1956,10 +1973,8 @@ static int alc_build_controls(struct hda_codec *codec)
|
|||
if (!kctl)
|
||||
kctl = snd_hda_find_mixer_ctl(codec, "Input Source");
|
||||
for (i = 0; kctl && i < kctl->count; i++) {
|
||||
const hda_nid_t *nids = spec->capsrc_nids;
|
||||
if (!nids)
|
||||
nids = spec->adc_nids;
|
||||
err = snd_hda_add_nid(codec, kctl, i, nids[i]);
|
||||
err = snd_hda_add_nid(codec, kctl, i,
|
||||
get_capsrc(spec, i));
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
@ -2746,8 +2761,7 @@ static int alc_auto_create_input_ctls(struct hda_codec *codec)
|
|||
}
|
||||
|
||||
for (c = 0; c < num_adcs; c++) {
|
||||
hda_nid_t cap = spec->capsrc_nids ?
|
||||
spec->capsrc_nids[c] : spec->adc_nids[c];
|
||||
hda_nid_t cap = get_capsrc(spec, c);
|
||||
idx = get_connection_index(codec, cap, pin);
|
||||
if (idx >= 0) {
|
||||
spec->imux_pins[imux->num_items] = pin;
|
||||
|
@ -3693,8 +3707,7 @@ static int init_capsrc_for_pin(struct hda_codec *codec, hda_nid_t pin)
|
|||
if (!pin)
|
||||
return 0;
|
||||
for (i = 0; i < spec->num_adc_nids; i++) {
|
||||
hda_nid_t cap = spec->capsrc_nids ?
|
||||
spec->capsrc_nids[i] : spec->adc_nids[i];
|
||||
hda_nid_t cap = get_capsrc(spec, i);
|
||||
int idx;
|
||||
|
||||
idx = get_connection_index(codec, cap, pin);
|
||||
|
|
|
@ -95,6 +95,7 @@ enum {
|
|||
STAC_92HD83XXX_REF,
|
||||
STAC_92HD83XXX_PWR_REF,
|
||||
STAC_DELL_S14,
|
||||
STAC_DELL_VOSTRO_3500,
|
||||
STAC_92HD83XXX_HP,
|
||||
STAC_92HD83XXX_HP_cNB11_INTQUAD,
|
||||
STAC_HP_DV7_4000,
|
||||
|
@ -226,7 +227,6 @@ struct sigmatel_spec {
|
|||
|
||||
/* power management */
|
||||
unsigned int num_pwrs;
|
||||
const unsigned int *pwr_mapping;
|
||||
const hda_nid_t *pwr_nids;
|
||||
const hda_nid_t *dac_list;
|
||||
|
||||
|
@ -373,18 +373,15 @@ static const unsigned long stac92hd73xx_capvols[] = {
|
|||
|
||||
#define STAC92HD83_DAC_COUNT 3
|
||||
|
||||
static const hda_nid_t stac92hd83xxx_pwr_nids[4] = {
|
||||
0xa, 0xb, 0xd, 0xe,
|
||||
static const hda_nid_t stac92hd83xxx_pwr_nids[7] = {
|
||||
0x0a, 0x0b, 0x0c, 0xd, 0x0e,
|
||||
0x0f, 0x10
|
||||
};
|
||||
|
||||
static const hda_nid_t stac92hd83xxx_slave_dig_outs[2] = {
|
||||
0x1e, 0,
|
||||
};
|
||||
|
||||
static const unsigned int stac92hd83xxx_pwr_mapping[4] = {
|
||||
0x03, 0x0c, 0x20, 0x40,
|
||||
};
|
||||
|
||||
static const hda_nid_t stac92hd83xxx_dmic_nids[] = {
|
||||
0x11, 0x20,
|
||||
};
|
||||
|
@ -1644,6 +1641,8 @@ static const struct snd_pci_quirk stac92hd73xx_codec_id_cfg_tbl[] = {
|
|||
"Alienware M17x", STAC_ALIENWARE_M17X),
|
||||
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x043a,
|
||||
"Alienware M17x", STAC_ALIENWARE_M17X),
|
||||
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0490,
|
||||
"Alienware M17x", STAC_ALIENWARE_M17X),
|
||||
{} /* terminator */
|
||||
};
|
||||
|
||||
|
@ -1659,6 +1658,12 @@ static const unsigned int dell_s14_pin_configs[10] = {
|
|||
0x40f000f0, 0x40f000f0,
|
||||
};
|
||||
|
||||
static const unsigned int dell_vostro_3500_pin_configs[10] = {
|
||||
0x02a11020, 0x0221101f, 0x400000f0, 0x90170110,
|
||||
0x400000f1, 0x400000f2, 0x400000f3, 0x90a60160,
|
||||
0x400000f4, 0x400000f5,
|
||||
};
|
||||
|
||||
static const unsigned int hp_dv7_4000_pin_configs[10] = {
|
||||
0x03a12050, 0x0321201f, 0x40f000f0, 0x90170110,
|
||||
0x40f000f0, 0x40f000f0, 0x90170110, 0xd5a30140,
|
||||
|
@ -1675,6 +1680,7 @@ static const unsigned int *stac92hd83xxx_brd_tbl[STAC_92HD83XXX_MODELS] = {
|
|||
[STAC_92HD83XXX_REF] = ref92hd83xxx_pin_configs,
|
||||
[STAC_92HD83XXX_PWR_REF] = ref92hd83xxx_pin_configs,
|
||||
[STAC_DELL_S14] = dell_s14_pin_configs,
|
||||
[STAC_DELL_VOSTRO_3500] = dell_vostro_3500_pin_configs,
|
||||
[STAC_92HD83XXX_HP_cNB11_INTQUAD] = hp_cNB11_intquad_pin_configs,
|
||||
[STAC_HP_DV7_4000] = hp_dv7_4000_pin_configs,
|
||||
};
|
||||
|
@ -1684,6 +1690,7 @@ static const char * const stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = {
|
|||
[STAC_92HD83XXX_REF] = "ref",
|
||||
[STAC_92HD83XXX_PWR_REF] = "mic-ref",
|
||||
[STAC_DELL_S14] = "dell-s14",
|
||||
[STAC_DELL_VOSTRO_3500] = "dell-vostro-3500",
|
||||
[STAC_92HD83XXX_HP] = "hp",
|
||||
[STAC_92HD83XXX_HP_cNB11_INTQUAD] = "hp_cNB11_intquad",
|
||||
[STAC_HP_DV7_4000] = "hp-dv7-4000",
|
||||
|
@ -1697,6 +1704,8 @@ static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = {
|
|||
"DFI LanParty", STAC_92HD83XXX_REF),
|
||||
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02ba,
|
||||
"unknown Dell", STAC_DELL_S14),
|
||||
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x1028,
|
||||
"Dell Vostro 3500", STAC_DELL_VOSTRO_3500),
|
||||
SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xff00, 0x3600,
|
||||
"HP", STAC_92HD83XXX_HP),
|
||||
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1656,
|
||||
|
@ -4432,7 +4441,9 @@ static int stac92xx_init(struct hda_codec *codec)
|
|||
int pinctl, def_conf;
|
||||
|
||||
/* power on when no jack detection is available */
|
||||
if (!spec->hp_detect) {
|
||||
/* or when the VREF is used for controlling LED */
|
||||
if (!spec->hp_detect ||
|
||||
(spec->gpio_led > 8 && spec->gpio_led == nid)) {
|
||||
stac_toggle_power_map(codec, nid, 1);
|
||||
continue;
|
||||
}
|
||||
|
@ -4459,8 +4470,12 @@ static int stac92xx_init(struct hda_codec *codec)
|
|||
stac_toggle_power_map(codec, nid, 1);
|
||||
continue;
|
||||
}
|
||||
if (enable_pin_detect(codec, nid, STAC_PWR_EVENT))
|
||||
if (enable_pin_detect(codec, nid, STAC_PWR_EVENT)) {
|
||||
stac_issue_unsol_event(codec, nid);
|
||||
continue;
|
||||
}
|
||||
/* none of the above, turn the port OFF */
|
||||
stac_toggle_power_map(codec, nid, 0);
|
||||
}
|
||||
|
||||
/* sync mute LED */
|
||||
|
@ -4716,11 +4731,7 @@ static void stac_toggle_power_map(struct hda_codec *codec, hda_nid_t nid,
|
|||
if (idx >= spec->num_pwrs)
|
||||
return;
|
||||
|
||||
/* several codecs have two power down bits */
|
||||
if (spec->pwr_mapping)
|
||||
idx = spec->pwr_mapping[idx];
|
||||
else
|
||||
idx = 1 << idx;
|
||||
idx = 1 << idx;
|
||||
|
||||
val = snd_hda_codec_read(codec, codec->afg, 0, 0x0fec, 0x0) & 0xff;
|
||||
if (enable)
|
||||
|
@ -5046,20 +5057,6 @@ static int stac92xx_pre_resume(struct hda_codec *codec)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int stac92xx_post_suspend(struct hda_codec *codec)
|
||||
{
|
||||
struct sigmatel_spec *spec = codec->spec;
|
||||
if (spec->gpio_led > 8) {
|
||||
/* with vref-out pin used for mute led control
|
||||
* codec AFG is prevented from D3 state, but on
|
||||
* system suspend it can (and should) be used
|
||||
*/
|
||||
snd_hda_codec_read(codec, codec->afg, 0,
|
||||
AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void stac92xx_set_power_state(struct hda_codec *codec, hda_nid_t fg,
|
||||
unsigned int power_state)
|
||||
{
|
||||
|
@ -5618,9 +5615,6 @@ static int patch_stac92hd83xxx(struct hda_codec *codec)
|
|||
snd_hda_codec_set_pincfg(codec, 0xf, 0x2181205e);
|
||||
}
|
||||
|
||||
/* reset pin power-down; Windows may leave these bits after reboot */
|
||||
snd_hda_codec_write_cache(codec, codec->afg, 0, 0x7EC, 0);
|
||||
snd_hda_codec_write_cache(codec, codec->afg, 0, 0x7ED, 0);
|
||||
codec->no_trigger_sense = 1;
|
||||
codec->spec = spec;
|
||||
|
||||
|
@ -5630,7 +5624,6 @@ static int patch_stac92hd83xxx(struct hda_codec *codec)
|
|||
codec->slave_dig_outs = stac92hd83xxx_slave_dig_outs;
|
||||
spec->digbeep_nid = 0x21;
|
||||
spec->pwr_nids = stac92hd83xxx_pwr_nids;
|
||||
spec->pwr_mapping = stac92hd83xxx_pwr_mapping;
|
||||
spec->num_pwrs = ARRAY_SIZE(stac92hd83xxx_pwr_nids);
|
||||
spec->multiout.dac_nids = spec->dac_nids;
|
||||
spec->init = stac92hd83xxx_core_init;
|
||||
|
@ -5647,9 +5640,6 @@ again:
|
|||
stac92xx_set_config_regs(codec,
|
||||
stac92hd83xxx_brd_tbl[spec->board_config]);
|
||||
|
||||
if (spec->board_config != STAC_92HD83XXX_PWR_REF)
|
||||
spec->num_pwrs = 0;
|
||||
|
||||
codec->patch_ops = stac92xx_patch_ops;
|
||||
|
||||
if (find_mute_led_gpio(codec, 0))
|
||||
|
@ -5666,8 +5656,6 @@ again:
|
|||
} else {
|
||||
codec->patch_ops.set_power_state =
|
||||
stac92xx_set_power_state;
|
||||
codec->patch_ops.post_suspend =
|
||||
stac92xx_post_suspend;
|
||||
}
|
||||
codec->patch_ops.pre_resume = stac92xx_pre_resume;
|
||||
codec->patch_ops.check_power_status =
|
||||
|
@ -5858,8 +5846,6 @@ again:
|
|||
(codec->revision_id & 0xf) == 1)
|
||||
spec->stream_delay = 40; /* 40 milliseconds */
|
||||
|
||||
/* no output amps */
|
||||
spec->num_pwrs = 0;
|
||||
/* disable VSW */
|
||||
spec->init = stac92hd71bxx_core_init;
|
||||
unmute_init++;
|
||||
|
@ -5874,8 +5860,6 @@ again:
|
|||
if ((codec->revision_id & 0xf) == 1)
|
||||
spec->stream_delay = 40; /* 40 milliseconds */
|
||||
|
||||
/* no output amps */
|
||||
spec->num_pwrs = 0;
|
||||
/* fallthru */
|
||||
default:
|
||||
spec->init = stac92hd71bxx_core_init;
|
||||
|
@ -5985,8 +5969,6 @@ again:
|
|||
} else {
|
||||
codec->patch_ops.set_power_state =
|
||||
stac92xx_set_power_state;
|
||||
codec->patch_ops.post_suspend =
|
||||
stac92xx_post_suspend;
|
||||
}
|
||||
codec->patch_ops.pre_resume = stac92xx_pre_resume;
|
||||
codec->patch_ops.check_power_status =
|
||||
|
|
|
@ -208,6 +208,7 @@ struct via_spec {
|
|||
/* work to check hp jack state */
|
||||
struct hda_codec *codec;
|
||||
struct delayed_work vt1708_hp_work;
|
||||
int hp_work_active;
|
||||
int vt1708_jack_detect;
|
||||
int vt1708_hp_present;
|
||||
|
||||
|
@ -305,27 +306,35 @@ enum {
|
|||
static void analog_low_current_mode(struct hda_codec *codec);
|
||||
static bool is_aa_path_mute(struct hda_codec *codec);
|
||||
|
||||
static void vt1708_start_hp_work(struct via_spec *spec)
|
||||
{
|
||||
if (spec->codec_type != VT1708 || spec->autocfg.hp_pins[0] == 0)
|
||||
return;
|
||||
snd_hda_codec_write(spec->codec, 0x1, 0, 0xf81,
|
||||
!spec->vt1708_jack_detect);
|
||||
if (!delayed_work_pending(&spec->vt1708_hp_work))
|
||||
schedule_delayed_work(&spec->vt1708_hp_work,
|
||||
msecs_to_jiffies(100));
|
||||
}
|
||||
#define hp_detect_with_aa(codec) \
|
||||
(snd_hda_get_bool_hint(codec, "analog_loopback_hp_detect") == 1 && \
|
||||
!is_aa_path_mute(codec))
|
||||
|
||||
static void vt1708_stop_hp_work(struct via_spec *spec)
|
||||
{
|
||||
if (spec->codec_type != VT1708 || spec->autocfg.hp_pins[0] == 0)
|
||||
return;
|
||||
if (snd_hda_get_bool_hint(spec->codec, "analog_loopback_hp_detect") == 1
|
||||
&& !is_aa_path_mute(spec->codec))
|
||||
if (spec->hp_work_active) {
|
||||
snd_hda_codec_write(spec->codec, 0x1, 0, 0xf81, 1);
|
||||
cancel_delayed_work_sync(&spec->vt1708_hp_work);
|
||||
spec->hp_work_active = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void vt1708_update_hp_work(struct via_spec *spec)
|
||||
{
|
||||
if (spec->codec_type != VT1708 || spec->autocfg.hp_pins[0] == 0)
|
||||
return;
|
||||
snd_hda_codec_write(spec->codec, 0x1, 0, 0xf81,
|
||||
!spec->vt1708_jack_detect);
|
||||
cancel_delayed_work_sync(&spec->vt1708_hp_work);
|
||||
if (spec->vt1708_jack_detect &&
|
||||
(spec->active_streams || hp_detect_with_aa(spec->codec))) {
|
||||
if (!spec->hp_work_active) {
|
||||
snd_hda_codec_write(spec->codec, 0x1, 0, 0xf81, 0);
|
||||
schedule_delayed_work(&spec->vt1708_hp_work,
|
||||
msecs_to_jiffies(100));
|
||||
spec->hp_work_active = 1;
|
||||
}
|
||||
} else if (!hp_detect_with_aa(spec->codec))
|
||||
vt1708_stop_hp_work(spec);
|
||||
}
|
||||
|
||||
static void set_widgets_power_state(struct hda_codec *codec)
|
||||
|
@ -343,12 +352,7 @@ static int analog_input_switch_put(struct snd_kcontrol *kcontrol,
|
|||
|
||||
set_widgets_power_state(codec);
|
||||
analog_low_current_mode(snd_kcontrol_chip(kcontrol));
|
||||
if (snd_hda_get_bool_hint(codec, "analog_loopback_hp_detect") == 1) {
|
||||
if (is_aa_path_mute(codec))
|
||||
vt1708_start_hp_work(codec->spec);
|
||||
else
|
||||
vt1708_stop_hp_work(codec->spec);
|
||||
}
|
||||
vt1708_update_hp_work(codec->spec);
|
||||
return change;
|
||||
}
|
||||
|
||||
|
@ -1154,7 +1158,7 @@ static int via_playback_multi_pcm_prepare(struct hda_pcm_stream *hinfo,
|
|||
spec->cur_dac_stream_tag = stream_tag;
|
||||
spec->cur_dac_format = format;
|
||||
mutex_unlock(&spec->config_mutex);
|
||||
vt1708_start_hp_work(spec);
|
||||
vt1708_update_hp_work(spec);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1174,7 +1178,7 @@ static int via_playback_hp_pcm_prepare(struct hda_pcm_stream *hinfo,
|
|||
spec->cur_hp_stream_tag = stream_tag;
|
||||
spec->cur_hp_format = format;
|
||||
mutex_unlock(&spec->config_mutex);
|
||||
vt1708_start_hp_work(spec);
|
||||
vt1708_update_hp_work(spec);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1188,7 +1192,7 @@ static int via_playback_multi_pcm_cleanup(struct hda_pcm_stream *hinfo,
|
|||
snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
|
||||
spec->active_streams &= ~STREAM_MULTI_OUT;
|
||||
mutex_unlock(&spec->config_mutex);
|
||||
vt1708_stop_hp_work(spec);
|
||||
vt1708_update_hp_work(spec);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1203,7 +1207,7 @@ static int via_playback_hp_pcm_cleanup(struct hda_pcm_stream *hinfo,
|
|||
snd_hda_codec_setup_stream(codec, spec->hp_dac_nid, 0, 0, 0);
|
||||
spec->active_streams &= ~STREAM_INDEP_HP;
|
||||
mutex_unlock(&spec->config_mutex);
|
||||
vt1708_stop_hp_work(spec);
|
||||
vt1708_update_hp_work(spec);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1645,7 +1649,8 @@ static void via_hp_automute(struct hda_codec *codec)
|
|||
int nums;
|
||||
struct via_spec *spec = codec->spec;
|
||||
|
||||
if (!spec->hp_independent_mode && spec->autocfg.hp_pins[0])
|
||||
if (!spec->hp_independent_mode && spec->autocfg.hp_pins[0] &&
|
||||
(spec->codec_type != VT1708 || spec->vt1708_jack_detect))
|
||||
present = snd_hda_jack_detect(codec, spec->autocfg.hp_pins[0]);
|
||||
|
||||
if (spec->smart51_enabled)
|
||||
|
@ -2612,8 +2617,6 @@ static int vt1708_jack_detect_get(struct snd_kcontrol *kcontrol,
|
|||
|
||||
if (spec->codec_type != VT1708)
|
||||
return 0;
|
||||
spec->vt1708_jack_detect =
|
||||
!((snd_hda_codec_read(codec, 0x1, 0, 0xf84, 0) >> 8) & 0x1);
|
||||
ucontrol->value.integer.value[0] = spec->vt1708_jack_detect;
|
||||
return 0;
|
||||
}
|
||||
|
@ -2623,18 +2626,22 @@ static int vt1708_jack_detect_put(struct snd_kcontrol *kcontrol,
|
|||
{
|
||||
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct via_spec *spec = codec->spec;
|
||||
int change;
|
||||
int val;
|
||||
|
||||
if (spec->codec_type != VT1708)
|
||||
return 0;
|
||||
spec->vt1708_jack_detect = ucontrol->value.integer.value[0];
|
||||
change = (0x1 & (snd_hda_codec_read(codec, 0x1, 0, 0xf84, 0) >> 8))
|
||||
== !spec->vt1708_jack_detect;
|
||||
if (spec->vt1708_jack_detect) {
|
||||
val = !!ucontrol->value.integer.value[0];
|
||||
if (spec->vt1708_jack_detect == val)
|
||||
return 0;
|
||||
spec->vt1708_jack_detect = val;
|
||||
if (spec->vt1708_jack_detect &&
|
||||
snd_hda_get_bool_hint(codec, "analog_loopback_hp_detect") != 1) {
|
||||
mute_aa_path(codec, 1);
|
||||
notify_aa_path_ctls(codec);
|
||||
}
|
||||
return change;
|
||||
via_hp_automute(codec);
|
||||
vt1708_update_hp_work(spec);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const struct snd_kcontrol_new vt1708_jack_detect_ctl = {
|
||||
|
@ -2771,6 +2778,7 @@ static int via_init(struct hda_codec *codec)
|
|||
via_auto_init_unsol_event(codec);
|
||||
|
||||
via_hp_automute(codec);
|
||||
vt1708_update_hp_work(spec);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -2787,7 +2795,9 @@ static void vt1708_update_hp_jack_state(struct work_struct *work)
|
|||
spec->vt1708_hp_present ^= 1;
|
||||
via_hp_automute(spec->codec);
|
||||
}
|
||||
vt1708_start_hp_work(spec);
|
||||
if (spec->vt1708_jack_detect)
|
||||
schedule_delayed_work(&spec->vt1708_hp_work,
|
||||
msecs_to_jiffies(100));
|
||||
}
|
||||
|
||||
static int get_mux_nids(struct hda_codec *codec)
|
||||
|
|
|
@ -1077,6 +1077,13 @@ static snd_pcm_uframes_t snd_intel8x0_pcm_pointer(struct snd_pcm_substream *subs
|
|||
}
|
||||
if (civ != igetbyte(chip, ichdev->reg_offset + ICH_REG_OFF_CIV))
|
||||
continue;
|
||||
|
||||
/* IO read operation is very expensive inside virtual machine
|
||||
* as it is emulated. The probability that subsequent PICB read
|
||||
* will return different result is high enough to loop till
|
||||
* timeout here.
|
||||
* Same CIV is strict enough condition to be sure that PICB
|
||||
* is valid inside VM on emulated card. */
|
||||
if (chip->inside_vm)
|
||||
break;
|
||||
if (ptr1 == igetword(chip, ichdev->reg_offset + ichdev->roff_picb))
|
||||
|
@ -2930,6 +2937,45 @@ static unsigned int sis_codec_bits[3] = {
|
|||
ICH_PCR, ICH_SCR, ICH_SIS_TCR
|
||||
};
|
||||
|
||||
static int __devinit snd_intel8x0_inside_vm(struct pci_dev *pci)
|
||||
{
|
||||
int result = inside_vm;
|
||||
char *msg = NULL;
|
||||
|
||||
/* check module parameter first (override detection) */
|
||||
if (result >= 0) {
|
||||
msg = result ? "enable (forced) VM" : "disable (forced) VM";
|
||||
goto fini;
|
||||
}
|
||||
|
||||
/* detect KVM and Parallels virtual environments */
|
||||
result = kvm_para_available();
|
||||
#ifdef X86_FEATURE_HYPERVISOR
|
||||
result = result || boot_cpu_has(X86_FEATURE_HYPERVISOR);
|
||||
#endif
|
||||
if (!result)
|
||||
goto fini;
|
||||
|
||||
/* check for known (emulated) devices */
|
||||
if (pci->subsystem_vendor == 0x1af4 &&
|
||||
pci->subsystem_device == 0x1100) {
|
||||
/* KVM emulated sound, PCI SSID: 1af4:1100 */
|
||||
msg = "enable KVM";
|
||||
} else if (pci->subsystem_vendor == 0x1ab8) {
|
||||
/* Parallels VM emulated sound, PCI SSID: 1ab8:xxxx */
|
||||
msg = "enable Parallels VM";
|
||||
} else {
|
||||
msg = "disable (unknown or VT-d) VM";
|
||||
result = 0;
|
||||
}
|
||||
|
||||
fini:
|
||||
if (msg != NULL)
|
||||
printk(KERN_INFO "intel8x0: %s optimization\n", msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int __devinit snd_intel8x0_create(struct snd_card *card,
|
||||
struct pci_dev *pci,
|
||||
unsigned long device_type,
|
||||
|
@ -2997,9 +3043,7 @@ static int __devinit snd_intel8x0_create(struct snd_card *card,
|
|||
if (xbox)
|
||||
chip->xbox = 1;
|
||||
|
||||
chip->inside_vm = inside_vm;
|
||||
if (inside_vm)
|
||||
printk(KERN_INFO "intel8x0: enable KVM optimization\n");
|
||||
chip->inside_vm = snd_intel8x0_inside_vm(pci);
|
||||
|
||||
if (pci->vendor == PCI_VENDOR_ID_INTEL &&
|
||||
pci->device == PCI_DEVICE_ID_INTEL_440MX)
|
||||
|
@ -3243,14 +3287,6 @@ static int __devinit snd_intel8x0_probe(struct pci_dev *pci,
|
|||
buggy_irq = 0;
|
||||
}
|
||||
|
||||
if (inside_vm < 0) {
|
||||
/* detect KVM and Parallels virtual environments */
|
||||
inside_vm = kvm_para_available();
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
inside_vm = inside_vm || boot_cpu_has(X86_FEATURE_HYPERVISOR);
|
||||
#endif
|
||||
}
|
||||
|
||||
if ((err = snd_intel8x0_create(card, pci, pci_id->driver_data,
|
||||
&chip)) < 0) {
|
||||
snd_card_free(card);
|
||||
|
|
|
@ -78,10 +78,15 @@ unsigned long lx_dsp_reg_read(struct lx6464es *chip, int port)
|
|||
return ioread32(address);
|
||||
}
|
||||
|
||||
void lx_dsp_reg_readbuf(struct lx6464es *chip, int port, u32 *data, u32 len)
|
||||
static void lx_dsp_reg_readbuf(struct lx6464es *chip, int port, u32 *data,
|
||||
u32 len)
|
||||
{
|
||||
void __iomem *address = lx_dsp_register(chip, port);
|
||||
memcpy_fromio(data, address, len*sizeof(u32));
|
||||
u32 __iomem *address = lx_dsp_register(chip, port);
|
||||
int i;
|
||||
|
||||
/* we cannot use memcpy_fromio */
|
||||
for (i = 0; i != len; ++i)
|
||||
data[i] = ioread32(address + i);
|
||||
}
|
||||
|
||||
|
||||
|
@ -91,11 +96,15 @@ void lx_dsp_reg_write(struct lx6464es *chip, int port, unsigned data)
|
|||
iowrite32(data, address);
|
||||
}
|
||||
|
||||
void lx_dsp_reg_writebuf(struct lx6464es *chip, int port, const u32 *data,
|
||||
u32 len)
|
||||
static void lx_dsp_reg_writebuf(struct lx6464es *chip, int port,
|
||||
const u32 *data, u32 len)
|
||||
{
|
||||
void __iomem *address = lx_dsp_register(chip, port);
|
||||
memcpy_toio(address, data, len*sizeof(u32));
|
||||
u32 __iomem *address = lx_dsp_register(chip, port);
|
||||
int i;
|
||||
|
||||
/* we cannot use memcpy_to */
|
||||
for (i = 0; i != len; ++i)
|
||||
iowrite32(data[i], address + i);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -72,10 +72,7 @@ enum {
|
|||
};
|
||||
|
||||
unsigned long lx_dsp_reg_read(struct lx6464es *chip, int port);
|
||||
void lx_dsp_reg_readbuf(struct lx6464es *chip, int port, u32 *data, u32 len);
|
||||
void lx_dsp_reg_write(struct lx6464es *chip, int port, unsigned data);
|
||||
void lx_dsp_reg_writebuf(struct lx6464es *chip, int port, const u32 *data,
|
||||
u32 len);
|
||||
|
||||
/* plx register access */
|
||||
enum {
|
||||
|
|
|
@ -6518,7 +6518,7 @@ static int __devinit snd_hdspm_create(struct snd_card *card,
|
|||
hdspm->io_type = AES32;
|
||||
hdspm->card_name = "RME AES32";
|
||||
hdspm->midiPorts = 2;
|
||||
} else if ((hdspm->firmware_rev == 0xd5) ||
|
||||
} else if ((hdspm->firmware_rev == 0xd2) ||
|
||||
((hdspm->firmware_rev >= 0xc8) &&
|
||||
(hdspm->firmware_rev <= 0xcf))) {
|
||||
hdspm->io_type = MADI;
|
||||
|
|
|
@ -41,6 +41,7 @@ MODULE_SUPPORTED_DEVICE("{{SiS,SiS7019 Audio Accelerator}}");
|
|||
static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */
|
||||
static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */
|
||||
static int enable = 1;
|
||||
static int codecs = 1;
|
||||
|
||||
module_param(index, int, 0444);
|
||||
MODULE_PARM_DESC(index, "Index value for SiS7019 Audio Accelerator.");
|
||||
|
@ -48,6 +49,8 @@ module_param(id, charp, 0444);
|
|||
MODULE_PARM_DESC(id, "ID string for SiS7019 Audio Accelerator.");
|
||||
module_param(enable, bool, 0444);
|
||||
MODULE_PARM_DESC(enable, "Enable SiS7019 Audio Accelerator.");
|
||||
module_param(codecs, int, 0444);
|
||||
MODULE_PARM_DESC(codecs, "Set bit to indicate that codec number is expected to be present (default 1)");
|
||||
|
||||
static DEFINE_PCI_DEVICE_TABLE(snd_sis7019_ids) = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_SI, 0x7019) },
|
||||
|
@ -140,6 +143,9 @@ struct sis7019 {
|
|||
dma_addr_t silence_dma_addr;
|
||||
};
|
||||
|
||||
/* These values are also used by the module param 'codecs' to indicate
|
||||
* which codecs should be present.
|
||||
*/
|
||||
#define SIS_PRIMARY_CODEC_PRESENT 0x0001
|
||||
#define SIS_SECONDARY_CODEC_PRESENT 0x0002
|
||||
#define SIS_TERTIARY_CODEC_PRESENT 0x0004
|
||||
|
@ -1078,6 +1084,7 @@ static int sis_chip_init(struct sis7019 *sis)
|
|||
{
|
||||
unsigned long io = sis->ioport;
|
||||
void __iomem *ioaddr = sis->ioaddr;
|
||||
unsigned long timeout;
|
||||
u16 status;
|
||||
int count;
|
||||
int i;
|
||||
|
@ -1104,22 +1111,46 @@ static int sis_chip_init(struct sis7019 *sis)
|
|||
while ((inw(io + SIS_AC97_STATUS) & SIS_AC97_STATUS_BUSY) && --count)
|
||||
udelay(1);
|
||||
|
||||
/* Now that we've finished the reset, find out what's attached.
|
||||
*/
|
||||
status = inl(io + SIS_AC97_STATUS);
|
||||
if (status & SIS_AC97_STATUS_CODEC_READY)
|
||||
sis->codecs_present |= SIS_PRIMARY_CODEC_PRESENT;
|
||||
if (status & SIS_AC97_STATUS_CODEC2_READY)
|
||||
sis->codecs_present |= SIS_SECONDARY_CODEC_PRESENT;
|
||||
if (status & SIS_AC97_STATUS_CODEC3_READY)
|
||||
sis->codecs_present |= SIS_TERTIARY_CODEC_PRESENT;
|
||||
|
||||
/* All done, let go of the semaphore, and check for errors
|
||||
/* Command complete, we can let go of the semaphore now.
|
||||
*/
|
||||
outl(SIS_AC97_SEMA_RELEASE, io + SIS_AC97_SEMA);
|
||||
if (!sis->codecs_present || !count)
|
||||
if (!count)
|
||||
return -EIO;
|
||||
|
||||
/* Now that we've finished the reset, find out what's attached.
|
||||
* There are some codec/board combinations that take an extremely
|
||||
* long time to come up. 350+ ms has been observed in the field,
|
||||
* so we'll give them up to 500ms.
|
||||
*/
|
||||
sis->codecs_present = 0;
|
||||
timeout = msecs_to_jiffies(500) + jiffies;
|
||||
while (time_before_eq(jiffies, timeout)) {
|
||||
status = inl(io + SIS_AC97_STATUS);
|
||||
if (status & SIS_AC97_STATUS_CODEC_READY)
|
||||
sis->codecs_present |= SIS_PRIMARY_CODEC_PRESENT;
|
||||
if (status & SIS_AC97_STATUS_CODEC2_READY)
|
||||
sis->codecs_present |= SIS_SECONDARY_CODEC_PRESENT;
|
||||
if (status & SIS_AC97_STATUS_CODEC3_READY)
|
||||
sis->codecs_present |= SIS_TERTIARY_CODEC_PRESENT;
|
||||
|
||||
if (sis->codecs_present == codecs)
|
||||
break;
|
||||
|
||||
msleep(1);
|
||||
}
|
||||
|
||||
/* All done, check for errors.
|
||||
*/
|
||||
if (!sis->codecs_present) {
|
||||
printk(KERN_ERR "sis7019: could not find any codecs\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (sis->codecs_present != codecs) {
|
||||
printk(KERN_WARNING "sis7019: missing codecs, found %0x, expected %0x\n",
|
||||
sis->codecs_present, codecs);
|
||||
}
|
||||
|
||||
/* Let the hardware know that the audio driver is alive,
|
||||
* and enable PCM slots on the AC-link for L/R playback (3 & 4) and
|
||||
* record channels. We're going to want to use Variable Rate Audio
|
||||
|
@ -1390,6 +1421,17 @@ static int __devinit snd_sis7019_probe(struct pci_dev *pci,
|
|||
if (!enable)
|
||||
goto error_out;
|
||||
|
||||
/* The user can specify which codecs should be present so that we
|
||||
* can wait for them to show up if they are slow to recover from
|
||||
* the AC97 cold reset. We default to a single codec, the primary.
|
||||
*
|
||||
* We assume that SIS_PRIMARY_*_PRESENT matches bits 0-2.
|
||||
*/
|
||||
codecs &= SIS_PRIMARY_CODEC_PRESENT | SIS_SECONDARY_CODEC_PRESENT |
|
||||
SIS_TERTIARY_CODEC_PRESENT;
|
||||
if (!codecs)
|
||||
codecs = SIS_PRIMARY_CODEC_PRESENT;
|
||||
|
||||
rc = snd_card_create(index, id, THIS_MODULE, sizeof(*sis), &card);
|
||||
if (rc < 0)
|
||||
goto error_out;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
config SND_ATMEL_SOC
|
||||
tristate "SoC Audio for the Atmel System-on-Chip"
|
||||
depends on ARCH_AT91 || AVR32
|
||||
depends on ARCH_AT91
|
||||
help
|
||||
Say Y or M if you want to add support for codecs attached to
|
||||
the ATMEL SSC interface. You will also need
|
||||
|
@ -24,25 +24,6 @@ config SND_AT91_SOC_SAM9G20_WM8731
|
|||
Say Y if you want to add support for SoC audio on WM8731-based
|
||||
AT91sam9g20 evaluation board.
|
||||
|
||||
config SND_AT32_SOC_PLAYPAQ
|
||||
tristate "SoC Audio support for PlayPaq with WM8510"
|
||||
depends on SND_ATMEL_SOC && BOARD_PLAYPAQ && AT91_PROGRAMMABLE_CLOCKS
|
||||
select SND_ATMEL_SOC_SSC
|
||||
select SND_SOC_WM8510
|
||||
help
|
||||
Say Y or M here if you want to add support for SoC audio
|
||||
on the LRS PlayPaq.
|
||||
|
||||
config SND_AT32_SOC_PLAYPAQ_SLAVE
|
||||
bool "Run CODEC on PlayPaq in slave mode"
|
||||
depends on SND_AT32_SOC_PLAYPAQ
|
||||
default n
|
||||
help
|
||||
Say Y if you want to run with the AT32 SSC generating the BCLK
|
||||
and FRAME signals on the PlayPaq. Unless you want to play
|
||||
with the AT32 as the SSC master, you probably want to say N here,
|
||||
as this will give you better sound quality.
|
||||
|
||||
config SND_AT91_SOC_AFEB9260
|
||||
tristate "SoC Audio support for AFEB9260 board"
|
||||
depends on ARCH_AT91 && MACH_AFEB9260 && SND_ATMEL_SOC
|
||||
|
|
|
@ -8,9 +8,5 @@ obj-$(CONFIG_SND_ATMEL_SOC_SSC) += snd-soc-atmel_ssc_dai.o
|
|||
# AT91 Machine Support
|
||||
snd-soc-sam9g20-wm8731-objs := sam9g20_wm8731.o
|
||||
|
||||
# AT32 Machine Support
|
||||
snd-soc-playpaq-objs := playpaq_wm8510.o
|
||||
|
||||
obj-$(CONFIG_SND_AT91_SOC_SAM9G20_WM8731) += snd-soc-sam9g20-wm8731.o
|
||||
obj-$(CONFIG_SND_AT32_SOC_PLAYPAQ) += snd-soc-playpaq.o
|
||||
obj-$(CONFIG_SND_AT91_SOC_AFEB9260) += snd-soc-afeb9260.o
|
||||
|
|
|
@ -1,473 +0,0 @@
|
|||
/* sound/soc/at32/playpaq_wm8510.c
|
||||
* ASoC machine driver for PlayPaq using WM8510 codec
|
||||
*
|
||||
* Copyright (C) 2008 Long Range Systems
|
||||
* Geoffrey Wossum <gwossum@acm.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is largely inspired by sound/soc/at91/eti_b1_wm8731.c
|
||||
*
|
||||
* NOTE: If you don't have the AT32 enhanced portmux configured (which
|
||||
* isn't currently in the mainline or Atmel patched kernel), you will
|
||||
* need to set the MCLK pin (PA30) to peripheral A in your board initialization
|
||||
* code. Something like:
|
||||
* at32_select_periph(GPIO_PIN_PA(30), GPIO_PERIPH_A, 0);
|
||||
*
|
||||
*/
|
||||
|
||||
/* #define DEBUG */
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include <mach/at32ap700x.h>
|
||||
#include <mach/portmux.h>
|
||||
|
||||
#include "../codecs/wm8510.h"
|
||||
#include "atmel-pcm.h"
|
||||
#include "atmel_ssc_dai.h"
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* constants
|
||||
\*-------------------------------------------------------------------------*/
|
||||
#define MCLK_PIN GPIO_PIN_PA(30)
|
||||
#define MCLK_PERIPH GPIO_PERIPH_A
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* data types
|
||||
\*-------------------------------------------------------------------------*/
|
||||
/* SSC clocking data */
|
||||
struct ssc_clock_data {
|
||||
/* CMR div */
|
||||
unsigned int cmr_div;
|
||||
|
||||
/* Frame period (as needed by xCMR.PERIOD) */
|
||||
unsigned int period;
|
||||
|
||||
/* The SSC clock rate these settings where calculated for */
|
||||
unsigned long ssc_rate;
|
||||
};
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* module data
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static struct clk *_gclk0;
|
||||
static struct clk *_pll0;
|
||||
|
||||
#define CODEC_CLK (_gclk0)
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Sound SOC operations
|
||||
\*-------------------------------------------------------------------------*/
|
||||
#if defined CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE
|
||||
static struct ssc_clock_data playpaq_wm8510_calc_ssc_clock(
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *cpu_dai)
|
||||
{
|
||||
struct at32_ssc_info *ssc_p = snd_soc_dai_get_drvdata(cpu_dai);
|
||||
struct ssc_device *ssc = ssc_p->ssc;
|
||||
struct ssc_clock_data cd;
|
||||
unsigned int rate, width_bits, channels;
|
||||
unsigned int bitrate, ssc_div;
|
||||
unsigned actual_rate;
|
||||
|
||||
|
||||
/*
|
||||
* Figure out required bitrate
|
||||
*/
|
||||
rate = params_rate(params);
|
||||
channels = params_channels(params);
|
||||
width_bits = snd_pcm_format_physical_width(params_format(params));
|
||||
bitrate = rate * width_bits * channels;
|
||||
|
||||
|
||||
/*
|
||||
* Figure out required SSC divider and period for required bitrate
|
||||
*/
|
||||
cd.ssc_rate = clk_get_rate(ssc->clk);
|
||||
ssc_div = cd.ssc_rate / bitrate;
|
||||
cd.cmr_div = ssc_div / 2;
|
||||
if (ssc_div & 1) {
|
||||
/* round cmr_div up */
|
||||
cd.cmr_div++;
|
||||
}
|
||||
cd.period = width_bits - 1;
|
||||
|
||||
|
||||
/*
|
||||
* Find actual rate, compare to requested rate
|
||||
*/
|
||||
actual_rate = (cd.ssc_rate / (cd.cmr_div * 2)) / (2 * (cd.period + 1));
|
||||
pr_debug("playpaq_wm8510: Request rate = %u, actual rate = %u\n",
|
||||
rate, actual_rate);
|
||||
|
||||
|
||||
return cd;
|
||||
}
|
||||
#endif /* CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE */
|
||||
|
||||
|
||||
|
||||
static int playpaq_wm8510_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
struct at32_ssc_info *ssc_p = snd_soc_dai_get_drvdata(cpu_dai);
|
||||
struct ssc_device *ssc = ssc_p->ssc;
|
||||
unsigned int pll_out = 0, bclk = 0, mclk_div = 0;
|
||||
int ret;
|
||||
|
||||
|
||||
/* Due to difficulties with getting the correct clocks from the AT32's
|
||||
* PLL0, we're going to let the CODEC be in charge of all the clocks
|
||||
*/
|
||||
#if !defined CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE
|
||||
const unsigned int fmt = (SND_SOC_DAIFMT_I2S |
|
||||
SND_SOC_DAIFMT_NB_NF |
|
||||
SND_SOC_DAIFMT_CBM_CFM);
|
||||
#else
|
||||
struct ssc_clock_data cd;
|
||||
const unsigned int fmt = (SND_SOC_DAIFMT_I2S |
|
||||
SND_SOC_DAIFMT_NB_NF |
|
||||
SND_SOC_DAIFMT_CBS_CFS);
|
||||
#endif
|
||||
|
||||
if (ssc == NULL) {
|
||||
pr_warning("playpaq_wm8510_hw_params: ssc is NULL!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Figure out PLL and BCLK dividers for WM8510
|
||||
*/
|
||||
switch (params_rate(params)) {
|
||||
case 48000:
|
||||
pll_out = 24576000;
|
||||
mclk_div = WM8510_MCLKDIV_2;
|
||||
bclk = WM8510_BCLKDIV_8;
|
||||
break;
|
||||
|
||||
case 44100:
|
||||
pll_out = 22579200;
|
||||
mclk_div = WM8510_MCLKDIV_2;
|
||||
bclk = WM8510_BCLKDIV_8;
|
||||
break;
|
||||
|
||||
case 22050:
|
||||
pll_out = 22579200;
|
||||
mclk_div = WM8510_MCLKDIV_4;
|
||||
bclk = WM8510_BCLKDIV_8;
|
||||
break;
|
||||
|
||||
case 16000:
|
||||
pll_out = 24576000;
|
||||
mclk_div = WM8510_MCLKDIV_6;
|
||||
bclk = WM8510_BCLKDIV_8;
|
||||
break;
|
||||
|
||||
case 11025:
|
||||
pll_out = 22579200;
|
||||
mclk_div = WM8510_MCLKDIV_8;
|
||||
bclk = WM8510_BCLKDIV_8;
|
||||
break;
|
||||
|
||||
case 8000:
|
||||
pll_out = 24576000;
|
||||
mclk_div = WM8510_MCLKDIV_12;
|
||||
bclk = WM8510_BCLKDIV_8;
|
||||
break;
|
||||
|
||||
default:
|
||||
pr_warning("playpaq_wm8510: Unsupported sample rate %d\n",
|
||||
params_rate(params));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* set CPU and CODEC DAI configuration
|
||||
*/
|
||||
ret = snd_soc_dai_set_fmt(codec_dai, fmt);
|
||||
if (ret < 0) {
|
||||
pr_warning("playpaq_wm8510: "
|
||||
"Failed to set CODEC DAI format (%d)\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
|
||||
if (ret < 0) {
|
||||
pr_warning("playpaq_wm8510: "
|
||||
"Failed to set CPU DAI format (%d)\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Set CPU clock configuration
|
||||
*/
|
||||
#if defined CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE
|
||||
cd = playpaq_wm8510_calc_ssc_clock(params, cpu_dai);
|
||||
pr_debug("playpaq_wm8510: cmr_div = %d, period = %d\n",
|
||||
cd.cmr_div, cd.period);
|
||||
ret = snd_soc_dai_set_clkdiv(cpu_dai, AT32_SSC_CMR_DIV, cd.cmr_div);
|
||||
if (ret < 0) {
|
||||
pr_warning("playpaq_wm8510: Failed to set CPU CMR_DIV (%d)\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
ret = snd_soc_dai_set_clkdiv(cpu_dai, AT32_SSC_TCMR_PERIOD,
|
||||
cd.period);
|
||||
if (ret < 0) {
|
||||
pr_warning("playpaq_wm8510: "
|
||||
"Failed to set CPU transmit period (%d)\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
#endif /* CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE */
|
||||
|
||||
|
||||
/*
|
||||
* Set CODEC clock configuration
|
||||
*/
|
||||
pr_debug("playpaq_wm8510: "
|
||||
"pll_in = %ld, pll_out = %u, bclk = %x, mclk = %x\n",
|
||||
clk_get_rate(CODEC_CLK), pll_out, bclk, mclk_div);
|
||||
|
||||
|
||||
#if !defined CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE
|
||||
ret = snd_soc_dai_set_clkdiv(codec_dai, WM8510_BCLKDIV, bclk);
|
||||
if (ret < 0) {
|
||||
pr_warning
|
||||
("playpaq_wm8510: Failed to set CODEC DAI BCLKDIV (%d)\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
#endif /* CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE */
|
||||
|
||||
|
||||
ret = snd_soc_dai_set_pll(codec_dai, 0, 0,
|
||||
clk_get_rate(CODEC_CLK), pll_out);
|
||||
if (ret < 0) {
|
||||
pr_warning("playpaq_wm8510: Failed to set CODEC DAI PLL (%d)\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
ret = snd_soc_dai_set_clkdiv(codec_dai, WM8510_MCLKDIV, mclk_div);
|
||||
if (ret < 0) {
|
||||
pr_warning("playpaq_wm8510: Failed to set CODEC MCLKDIV (%d)\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static struct snd_soc_ops playpaq_wm8510_ops = {
|
||||
.hw_params = playpaq_wm8510_hw_params,
|
||||
};
|
||||
|
||||
|
||||
|
||||
static const struct snd_soc_dapm_widget playpaq_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_MIC("Int Mic", NULL),
|
||||
SND_SOC_DAPM_SPK("Ext Spk", NULL),
|
||||
};
|
||||
|
||||
|
||||
|
||||
static const struct snd_soc_dapm_route intercon[] = {
|
||||
/* speaker connected to SPKOUT */
|
||||
{"Ext Spk", NULL, "SPKOUTP"},
|
||||
{"Ext Spk", NULL, "SPKOUTN"},
|
||||
|
||||
{"Mic Bias", NULL, "Int Mic"},
|
||||
{"MICN", NULL, "Mic Bias"},
|
||||
{"MICP", NULL, "Mic Bias"},
|
||||
};
|
||||
|
||||
|
||||
|
||||
static int playpaq_wm8510_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
struct snd_soc_dapm_context *dapm = &codec->dapm;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Add DAPM widgets
|
||||
*/
|
||||
for (i = 0; i < ARRAY_SIZE(playpaq_dapm_widgets); i++)
|
||||
snd_soc_dapm_new_control(dapm, &playpaq_dapm_widgets[i]);
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Setup audio path interconnects
|
||||
*/
|
||||
snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
|
||||
|
||||
|
||||
|
||||
/* always connected pins */
|
||||
snd_soc_dapm_enable_pin(dapm, "Int Mic");
|
||||
snd_soc_dapm_enable_pin(dapm, "Ext Spk");
|
||||
|
||||
|
||||
|
||||
/* Make CSB show PLL rate */
|
||||
snd_soc_dai_set_clkdiv(rtd->codec_dai, WM8510_OPCLKDIV,
|
||||
WM8510_OPCLKDIV_1 | 4);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static struct snd_soc_dai_link playpaq_wm8510_dai = {
|
||||
.name = "WM8510",
|
||||
.stream_name = "WM8510 PCM",
|
||||
.cpu_dai_name= "atmel-ssc-dai.0",
|
||||
.platform_name = "atmel-pcm-audio",
|
||||
.codec_name = "wm8510-codec.0-0x1a",
|
||||
.codec_dai_name = "wm8510-hifi",
|
||||
.init = playpaq_wm8510_init,
|
||||
.ops = &playpaq_wm8510_ops,
|
||||
};
|
||||
|
||||
|
||||
|
||||
static struct snd_soc_card snd_soc_playpaq = {
|
||||
.name = "LRS_PlayPaq_WM8510",
|
||||
.dai_link = &playpaq_wm8510_dai,
|
||||
.num_links = 1,
|
||||
};
|
||||
|
||||
static struct platform_device *playpaq_snd_device;
|
||||
|
||||
|
||||
static int __init playpaq_asoc_init(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
/*
|
||||
* Configure MCLK for WM8510
|
||||
*/
|
||||
_gclk0 = clk_get(NULL, "gclk0");
|
||||
if (IS_ERR(_gclk0)) {
|
||||
_gclk0 = NULL;
|
||||
ret = PTR_ERR(_gclk0);
|
||||
goto err_gclk0;
|
||||
}
|
||||
_pll0 = clk_get(NULL, "pll0");
|
||||
if (IS_ERR(_pll0)) {
|
||||
_pll0 = NULL;
|
||||
ret = PTR_ERR(_pll0);
|
||||
goto err_pll0;
|
||||
}
|
||||
ret = clk_set_parent(_gclk0, _pll0);
|
||||
if (ret) {
|
||||
pr_warning("snd-soc-playpaq: "
|
||||
"Failed to set PLL0 as parent for DAC clock\n");
|
||||
goto err_set_clk;
|
||||
}
|
||||
clk_set_rate(CODEC_CLK, 12000000);
|
||||
clk_enable(CODEC_CLK);
|
||||
|
||||
#if defined CONFIG_AT32_ENHANCED_PORTMUX
|
||||
at32_select_periph(MCLK_PIN, MCLK_PERIPH, 0);
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Create and register platform device
|
||||
*/
|
||||
playpaq_snd_device = platform_device_alloc("soc-audio", 0);
|
||||
if (playpaq_snd_device == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto err_device_alloc;
|
||||
}
|
||||
|
||||
platform_set_drvdata(playpaq_snd_device, &snd_soc_playpaq);
|
||||
|
||||
ret = platform_device_add(playpaq_snd_device);
|
||||
if (ret) {
|
||||
pr_warning("playpaq_wm8510: platform_device_add failed (%d)\n",
|
||||
ret);
|
||||
goto err_device_add;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
|
||||
err_device_add:
|
||||
if (playpaq_snd_device != NULL) {
|
||||
platform_device_put(playpaq_snd_device);
|
||||
playpaq_snd_device = NULL;
|
||||
}
|
||||
err_device_alloc:
|
||||
err_set_clk:
|
||||
if (_pll0 != NULL) {
|
||||
clk_put(_pll0);
|
||||
_pll0 = NULL;
|
||||
}
|
||||
err_pll0:
|
||||
if (_gclk0 != NULL) {
|
||||
clk_put(_gclk0);
|
||||
_gclk0 = NULL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void __exit playpaq_asoc_exit(void)
|
||||
{
|
||||
if (_gclk0 != NULL) {
|
||||
clk_put(_gclk0);
|
||||
_gclk0 = NULL;
|
||||
}
|
||||
if (_pll0 != NULL) {
|
||||
clk_put(_pll0);
|
||||
_pll0 = NULL;
|
||||
}
|
||||
|
||||
#if defined CONFIG_AT32_ENHANCED_PORTMUX
|
||||
at32_free_pin(MCLK_PIN);
|
||||
#endif
|
||||
|
||||
platform_device_unregister(playpaq_snd_device);
|
||||
playpaq_snd_device = NULL;
|
||||
}
|
||||
|
||||
module_init(playpaq_asoc_init);
|
||||
module_exit(playpaq_asoc_exit);
|
||||
|
||||
MODULE_AUTHOR("Geoffrey Wossum <gwossum@acm.org>");
|
||||
MODULE_DESCRIPTION("ASoC machine driver for LRS PlayPaq");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -34,7 +34,7 @@
|
|||
|
||||
#define AD1836_ADC_CTRL2 13
|
||||
#define AD1836_ADC_WORD_LEN_MASK 0x30
|
||||
#define AD1836_ADC_WORD_OFFSET 5
|
||||
#define AD1836_ADC_WORD_OFFSET 4
|
||||
#define AD1836_ADC_SERFMT_MASK (7 << 6)
|
||||
#define AD1836_ADC_SERFMT_PCK256 (0x4 << 6)
|
||||
#define AD1836_ADC_SERFMT_PCK128 (0x5 << 6)
|
||||
|
|
|
@ -245,7 +245,7 @@ static const char *adau1373_bass_hpf_cutoff_text[] = {
|
|||
};
|
||||
|
||||
static const unsigned int adau1373_bass_tlv[] = {
|
||||
TLV_DB_RANGE_HEAD(4),
|
||||
TLV_DB_RANGE_HEAD(3),
|
||||
0, 2, TLV_DB_SCALE_ITEM(-600, 600, 1),
|
||||
3, 4, TLV_DB_SCALE_ITEM(950, 250, 0),
|
||||
5, 7, TLV_DB_SCALE_ITEM(1400, 150, 0),
|
||||
|
|
|
@ -601,7 +601,6 @@ static int cs4270_soc_suspend(struct snd_soc_codec *codec, pm_message_t mesg)
|
|||
static int cs4270_soc_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
|
||||
struct i2c_client *i2c_client = to_i2c_client(codec->dev);
|
||||
int reg;
|
||||
|
||||
regulator_bulk_enable(ARRAY_SIZE(cs4270->supplies),
|
||||
|
@ -612,14 +611,7 @@ static int cs4270_soc_resume(struct snd_soc_codec *codec)
|
|||
ndelay(500);
|
||||
|
||||
/* first restore the entire register cache ... */
|
||||
for (reg = CS4270_FIRSTREG; reg <= CS4270_LASTREG; reg++) {
|
||||
u8 val = snd_soc_read(codec, reg);
|
||||
|
||||
if (i2c_smbus_write_byte_data(i2c_client, reg, val)) {
|
||||
dev_err(codec->dev, "i2c write failed\n");
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
snd_soc_cache_sync(codec);
|
||||
|
||||
/* ... then disable the power-down bits */
|
||||
reg = snd_soc_read(codec, CS4270_PWRCTL);
|
||||
|
|
|
@ -434,7 +434,8 @@ static int cs4271_soc_suspend(struct snd_soc_codec *codec, pm_message_t mesg)
|
|||
{
|
||||
int ret;
|
||||
/* Set power-down bit */
|
||||
ret = snd_soc_update_bits(codec, CS4271_MODE2, 0, CS4271_MODE2_PDN);
|
||||
ret = snd_soc_update_bits(codec, CS4271_MODE2, CS4271_MODE2_PDN,
|
||||
CS4271_MODE2_PDN);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return 0;
|
||||
|
@ -501,8 +502,9 @@ static int cs4271_probe(struct snd_soc_codec *codec)
|
|||
return ret;
|
||||
}
|
||||
|
||||
ret = snd_soc_update_bits(codec, CS4271_MODE2, 0,
|
||||
CS4271_MODE2_PDN | CS4271_MODE2_CPEN);
|
||||
ret = snd_soc_update_bits(codec, CS4271_MODE2,
|
||||
CS4271_MODE2_PDN | CS4271_MODE2_CPEN,
|
||||
CS4271_MODE2_PDN | CS4271_MODE2_CPEN);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = snd_soc_update_bits(codec, CS4271_MODE2, CS4271_MODE2_PDN, 0);
|
||||
|
|
|
@ -555,7 +555,7 @@ static int cs42l51_probe(struct snd_soc_codec *codec)
|
|||
|
||||
static struct snd_soc_codec_driver soc_codec_device_cs42l51 = {
|
||||
.probe = cs42l51_probe,
|
||||
.reg_cache_size = CS42L51_NUMREGS,
|
||||
.reg_cache_size = CS42L51_NUMREGS + 1,
|
||||
.reg_word_size = sizeof(u8),
|
||||
};
|
||||
|
||||
|
|
|
@ -106,13 +106,13 @@ static int max9877_set_2reg(struct snd_kcontrol *kcontrol,
|
|||
unsigned int mask = mc->max;
|
||||
unsigned int val = (ucontrol->value.integer.value[0] & mask);
|
||||
unsigned int val2 = (ucontrol->value.integer.value[1] & mask);
|
||||
unsigned int change = 1;
|
||||
unsigned int change = 0;
|
||||
|
||||
if (((max9877_regs[reg] >> shift) & mask) == val)
|
||||
change = 0;
|
||||
if (((max9877_regs[reg] >> shift) & mask) != val)
|
||||
change = 1;
|
||||
|
||||
if (((max9877_regs[reg2] >> shift) & mask) == val2)
|
||||
change = 0;
|
||||
if (((max9877_regs[reg2] >> shift) & mask) != val2)
|
||||
change = 1;
|
||||
|
||||
if (change) {
|
||||
max9877_regs[reg] &= ~(mask << shift);
|
||||
|
|
|
@ -177,7 +177,7 @@ static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -95625, 375, 0);
|
|||
static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0);
|
||||
/* {0, +20, +24, +30, +35, +40, +44, +50, +52}dB */
|
||||
static unsigned int mic_bst_tlv[] = {
|
||||
TLV_DB_RANGE_HEAD(6),
|
||||
TLV_DB_RANGE_HEAD(7),
|
||||
0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
|
||||
1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0),
|
||||
2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0),
|
||||
|
|
|
@ -365,7 +365,7 @@ static const DECLARE_TLV_DB_SCALE(capture_6db_attenuate, -600, 600, 0);
|
|||
|
||||
/* tlv for mic gain, 0db 20db 30db 40db */
|
||||
static const unsigned int mic_gain_tlv[] = {
|
||||
TLV_DB_RANGE_HEAD(4),
|
||||
TLV_DB_RANGE_HEAD(2),
|
||||
0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
|
||||
1, 3, TLV_DB_SCALE_ITEM(2000, 1000, 0),
|
||||
};
|
||||
|
|
|
@ -76,6 +76,8 @@ struct sta32x_priv {
|
|||
|
||||
unsigned int mclk;
|
||||
unsigned int format;
|
||||
|
||||
u32 coef_shadow[STA32X_COEF_COUNT];
|
||||
};
|
||||
|
||||
static const DECLARE_TLV_DB_SCALE(mvol_tlv, -12700, 50, 1);
|
||||
|
@ -227,6 +229,7 @@ static int sta32x_coefficient_put(struct snd_kcontrol *kcontrol,
|
|||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
|
||||
int numcoef = kcontrol->private_value >> 16;
|
||||
int index = kcontrol->private_value & 0xffff;
|
||||
unsigned int cfud;
|
||||
|
@ -239,6 +242,11 @@ static int sta32x_coefficient_put(struct snd_kcontrol *kcontrol,
|
|||
snd_soc_write(codec, STA32X_CFUD, cfud);
|
||||
|
||||
snd_soc_write(codec, STA32X_CFADDR2, index);
|
||||
for (i = 0; i < numcoef && (index + i < STA32X_COEF_COUNT); i++)
|
||||
sta32x->coef_shadow[index + i] =
|
||||
(ucontrol->value.bytes.data[3 * i] << 16)
|
||||
| (ucontrol->value.bytes.data[3 * i + 1] << 8)
|
||||
| (ucontrol->value.bytes.data[3 * i + 2]);
|
||||
for (i = 0; i < 3 * numcoef; i++)
|
||||
snd_soc_write(codec, STA32X_B1CF1 + i,
|
||||
ucontrol->value.bytes.data[i]);
|
||||
|
@ -252,6 +260,48 @@ static int sta32x_coefficient_put(struct snd_kcontrol *kcontrol,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int sta32x_sync_coef_shadow(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int cfud;
|
||||
int i;
|
||||
|
||||
/* preserve reserved bits in STA32X_CFUD */
|
||||
cfud = snd_soc_read(codec, STA32X_CFUD) & 0xf0;
|
||||
|
||||
for (i = 0; i < STA32X_COEF_COUNT; i++) {
|
||||
snd_soc_write(codec, STA32X_CFADDR2, i);
|
||||
snd_soc_write(codec, STA32X_B1CF1,
|
||||
(sta32x->coef_shadow[i] >> 16) & 0xff);
|
||||
snd_soc_write(codec, STA32X_B1CF2,
|
||||
(sta32x->coef_shadow[i] >> 8) & 0xff);
|
||||
snd_soc_write(codec, STA32X_B1CF3,
|
||||
(sta32x->coef_shadow[i]) & 0xff);
|
||||
/* chip documentation does not say if the bits are
|
||||
* self-clearing, so do it explicitly */
|
||||
snd_soc_write(codec, STA32X_CFUD, cfud);
|
||||
snd_soc_write(codec, STA32X_CFUD, cfud | 0x01);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sta32x_cache_sync(struct snd_soc_codec *codec)
|
||||
{
|
||||
unsigned int mute;
|
||||
int rc;
|
||||
|
||||
if (!codec->cache_sync)
|
||||
return 0;
|
||||
|
||||
/* mute during register sync */
|
||||
mute = snd_soc_read(codec, STA32X_MMUTE);
|
||||
snd_soc_write(codec, STA32X_MMUTE, mute | STA32X_MMUTE_MMUTE);
|
||||
sta32x_sync_coef_shadow(codec);
|
||||
rc = snd_soc_cache_sync(codec);
|
||||
snd_soc_write(codec, STA32X_MMUTE, mute);
|
||||
return rc;
|
||||
}
|
||||
|
||||
#define SINGLE_COEF(xname, index) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
|
||||
.info = sta32x_coefficient_info, \
|
||||
|
@ -661,7 +711,7 @@ static int sta32x_set_bias_level(struct snd_soc_codec *codec,
|
|||
return ret;
|
||||
}
|
||||
|
||||
snd_soc_cache_sync(codec);
|
||||
sta32x_cache_sync(codec);
|
||||
}
|
||||
|
||||
/* Power up to mute */
|
||||
|
@ -790,6 +840,17 @@ static int sta32x_probe(struct snd_soc_codec *codec)
|
|||
STA32X_CxCFG_OM_MASK,
|
||||
2 << STA32X_CxCFG_OM_SHIFT);
|
||||
|
||||
/* initialize coefficient shadow RAM with reset values */
|
||||
for (i = 4; i <= 49; i += 5)
|
||||
sta32x->coef_shadow[i] = 0x400000;
|
||||
for (i = 50; i <= 54; i++)
|
||||
sta32x->coef_shadow[i] = 0x7fffff;
|
||||
sta32x->coef_shadow[55] = 0x5a9df7;
|
||||
sta32x->coef_shadow[56] = 0x7fffff;
|
||||
sta32x->coef_shadow[59] = 0x7fffff;
|
||||
sta32x->coef_shadow[60] = 0x400000;
|
||||
sta32x->coef_shadow[61] = 0x400000;
|
||||
|
||||
sta32x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
/* Bias level configuration will have done an extra enable */
|
||||
regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
/* STA326 register addresses */
|
||||
|
||||
#define STA32X_REGISTER_COUNT 0x2d
|
||||
#define STA32X_COEF_COUNT 62
|
||||
|
||||
#define STA32X_CONFA 0x00
|
||||
#define STA32X_CONFB 0x01
|
||||
|
|
|
@ -453,6 +453,7 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec,
|
|||
snd_soc_write(codec, WM8731_PWR, 0xffff);
|
||||
regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies),
|
||||
wm8731->supplies);
|
||||
codec->cache_sync = 1;
|
||||
break;
|
||||
}
|
||||
codec->dapm.bias_level = level;
|
||||
|
|
|
@ -190,6 +190,9 @@ static int wm8753_set_dai(struct snd_kcontrol *kcontrol,
|
|||
struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
|
||||
u16 ioctl;
|
||||
|
||||
if (wm8753->dai_func == ucontrol->value.integer.value[0])
|
||||
return 0;
|
||||
|
||||
if (codec->active)
|
||||
return -EBUSY;
|
||||
|
||||
|
|
|
@ -1973,7 +1973,7 @@ static int wm8962_reset(struct snd_soc_codec *codec)
|
|||
static const DECLARE_TLV_DB_SCALE(inpga_tlv, -2325, 75, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(mixin_tlv, -1500, 300, 0);
|
||||
static const unsigned int mixinpga_tlv[] = {
|
||||
TLV_DB_RANGE_HEAD(7),
|
||||
TLV_DB_RANGE_HEAD(5),
|
||||
0, 1, TLV_DB_SCALE_ITEM(0, 600, 0),
|
||||
2, 2, TLV_DB_SCALE_ITEM(1300, 1300, 0),
|
||||
3, 4, TLV_DB_SCALE_ITEM(1800, 200, 0),
|
||||
|
@ -1988,7 +1988,7 @@ static const DECLARE_TLV_DB_SCALE(bypass_tlv, -1500, 300, 0);
|
|||
static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1);
|
||||
static const DECLARE_TLV_DB_SCALE(hp_tlv, -700, 100, 0);
|
||||
static const unsigned int classd_tlv[] = {
|
||||
TLV_DB_RANGE_HEAD(7),
|
||||
TLV_DB_RANGE_HEAD(2),
|
||||
0, 6, TLV_DB_SCALE_ITEM(0, 150, 0),
|
||||
7, 7, TLV_DB_SCALE_ITEM(1200, 0, 0),
|
||||
};
|
||||
|
|
|
@ -512,7 +512,7 @@ static const DECLARE_TLV_DB_SCALE(drc_comp_threash, -4500, 75, 0);
|
|||
static const DECLARE_TLV_DB_SCALE(drc_comp_amp, -2250, 75, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(drc_min_tlv, -1800, 600, 0);
|
||||
static const unsigned int drc_max_tlv[] = {
|
||||
TLV_DB_RANGE_HEAD(4),
|
||||
TLV_DB_RANGE_HEAD(2),
|
||||
0, 2, TLV_DB_SCALE_ITEM(1200, 600, 0),
|
||||
3, 3, TLV_DB_SCALE_ITEM(3600, 0, 0),
|
||||
};
|
||||
|
|
|
@ -56,7 +56,7 @@ static int wm8994_retune_mobile_base[] = {
|
|||
static int wm8994_readable(struct snd_soc_codec *codec, unsigned int reg)
|
||||
{
|
||||
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
|
||||
struct wm8994 *control = wm8994->control_data;
|
||||
struct wm8994 *control = codec->control_data;
|
||||
|
||||
switch (reg) {
|
||||
case WM8994_GPIO_1:
|
||||
|
@ -2357,6 +2357,11 @@ static int wm8994_hw_params(struct snd_pcm_substream *substream,
|
|||
bclk |= best << WM8994_AIF1_BCLK_DIV_SHIFT;
|
||||
|
||||
lrclk = bclk_rate / params_rate(params);
|
||||
if (!lrclk) {
|
||||
dev_err(dai->dev, "Unable to generate LRCLK from %dHz BCLK\n",
|
||||
bclk_rate);
|
||||
return -EINVAL;
|
||||
}
|
||||
dev_dbg(dai->dev, "Using LRCLK rate %d for actual LRCLK %dHz\n",
|
||||
lrclk, bclk_rate / lrclk);
|
||||
|
||||
|
@ -3030,19 +3035,34 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data)
|
|||
{
|
||||
struct wm8994_priv *wm8994 = data;
|
||||
struct snd_soc_codec *codec = wm8994->codec;
|
||||
int reg;
|
||||
int reg, count;
|
||||
|
||||
reg = snd_soc_read(codec, WM8958_MIC_DETECT_3);
|
||||
if (reg < 0) {
|
||||
dev_err(codec->dev, "Failed to read mic detect status: %d\n",
|
||||
reg);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
/* We may occasionally read a detection without an impedence
|
||||
* range being provided - if that happens loop again.
|
||||
*/
|
||||
count = 10;
|
||||
do {
|
||||
reg = snd_soc_read(codec, WM8958_MIC_DETECT_3);
|
||||
if (reg < 0) {
|
||||
dev_err(codec->dev,
|
||||
"Failed to read mic detect status: %d\n",
|
||||
reg);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
if (!(reg & WM8958_MICD_VALID)) {
|
||||
dev_dbg(codec->dev, "Mic detect data not valid\n");
|
||||
goto out;
|
||||
}
|
||||
if (!(reg & WM8958_MICD_VALID)) {
|
||||
dev_dbg(codec->dev, "Mic detect data not valid\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(reg & WM8958_MICD_STS) || (reg & WM8958_MICD_LVL_MASK))
|
||||
break;
|
||||
|
||||
msleep(1);
|
||||
} while (count--);
|
||||
|
||||
if (count == 0)
|
||||
dev_warn(codec->dev, "No impedence range reported for jack\n");
|
||||
|
||||
#ifndef CONFIG_SND_SOC_WM8994_MODULE
|
||||
trace_snd_soc_jack_irq(dev_name(codec->dev));
|
||||
|
@ -3163,6 +3183,8 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
|
|||
switch (wm8994->revision) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
wm8994->hubs.dcs_codes_l = -9;
|
||||
wm8994->hubs.dcs_codes_r = -5;
|
||||
break;
|
||||
|
@ -3180,9 +3202,9 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
|
|||
|
||||
wm8994_request_irq(codec->control_data, WM8994_IRQ_FIFOS_ERR,
|
||||
wm8994_fifo_error, "FIFO error", codec);
|
||||
wm8994_request_irq(wm8994->control_data, WM8994_IRQ_TEMP_WARN,
|
||||
wm8994_request_irq(codec->control_data, WM8994_IRQ_TEMP_WARN,
|
||||
wm8994_temp_warn, "Thermal warning", codec);
|
||||
wm8994_request_irq(wm8994->control_data, WM8994_IRQ_TEMP_SHUT,
|
||||
wm8994_request_irq(codec->control_data, WM8994_IRQ_TEMP_SHUT,
|
||||
wm8994_temp_shut, "Thermal shutdown", codec);
|
||||
|
||||
ret = wm8994_request_irq(codec->control_data, WM8994_IRQ_DCS_DONE,
|
||||
|
|
|
@ -807,7 +807,6 @@ static int wm9081_set_bias_level(struct snd_soc_codec *codec,
|
|||
mdelay(100);
|
||||
|
||||
/* Normal bias enable & soft start off */
|
||||
reg |= WM9081_BIAS_ENA;
|
||||
reg &= ~WM9081_VMID_RAMP;
|
||||
snd_soc_write(codec, WM9081_VMID_CONTROL, reg);
|
||||
|
||||
|
@ -818,7 +817,7 @@ static int wm9081_set_bias_level(struct snd_soc_codec *codec,
|
|||
}
|
||||
|
||||
/* VMID 2*240k */
|
||||
reg = snd_soc_read(codec, WM9081_BIAS_CONTROL_1);
|
||||
reg = snd_soc_read(codec, WM9081_VMID_CONTROL);
|
||||
reg &= ~WM9081_VMID_SEL_MASK;
|
||||
reg |= 0x04;
|
||||
snd_soc_write(codec, WM9081_VMID_CONTROL, reg);
|
||||
|
@ -830,14 +829,15 @@ static int wm9081_set_bias_level(struct snd_soc_codec *codec,
|
|||
break;
|
||||
|
||||
case SND_SOC_BIAS_OFF:
|
||||
/* Startup bias source */
|
||||
/* Startup bias source and disable bias */
|
||||
reg = snd_soc_read(codec, WM9081_BIAS_CONTROL_1);
|
||||
reg |= WM9081_BIAS_SRC;
|
||||
reg &= ~WM9081_BIAS_ENA;
|
||||
snd_soc_write(codec, WM9081_BIAS_CONTROL_1, reg);
|
||||
|
||||
/* Disable VMID and biases with soft ramping */
|
||||
/* Disable VMID with soft ramping */
|
||||
reg = snd_soc_read(codec, WM9081_VMID_CONTROL);
|
||||
reg &= ~(WM9081_VMID_SEL_MASK | WM9081_BIAS_ENA);
|
||||
reg &= ~WM9081_VMID_SEL_MASK;
|
||||
reg |= WM9081_VMID_RAMP;
|
||||
snd_soc_write(codec, WM9081_VMID_CONTROL, reg);
|
||||
|
||||
|
|
|
@ -177,19 +177,19 @@ static void wait_for_dc_servo(struct snd_soc_codec *codec)
|
|||
}
|
||||
|
||||
static const unsigned int in_tlv[] = {
|
||||
TLV_DB_RANGE_HEAD(6),
|
||||
TLV_DB_RANGE_HEAD(3),
|
||||
0, 0, TLV_DB_SCALE_ITEM(-600, 0, 0),
|
||||
1, 3, TLV_DB_SCALE_ITEM(-350, 350, 0),
|
||||
4, 6, TLV_DB_SCALE_ITEM(600, 600, 0),
|
||||
};
|
||||
static const unsigned int mix_tlv[] = {
|
||||
TLV_DB_RANGE_HEAD(4),
|
||||
TLV_DB_RANGE_HEAD(2),
|
||||
0, 2, TLV_DB_SCALE_ITEM(-1200, 300, 0),
|
||||
3, 3, TLV_DB_SCALE_ITEM(0, 0, 0),
|
||||
};
|
||||
static const DECLARE_TLV_DB_SCALE(out_tlv, -5700, 100, 0);
|
||||
static const unsigned int spkboost_tlv[] = {
|
||||
TLV_DB_RANGE_HEAD(7),
|
||||
TLV_DB_RANGE_HEAD(2),
|
||||
0, 6, TLV_DB_SCALE_ITEM(0, 150, 0),
|
||||
7, 7, TLV_DB_SCALE_ITEM(1200, 0, 0),
|
||||
};
|
||||
|
|
|
@ -40,7 +40,7 @@ static const DECLARE_TLV_DB_SCALE(outmix_tlv, -2100, 300, 0);
|
|||
static const DECLARE_TLV_DB_SCALE(spkmixout_tlv, -1800, 600, 1);
|
||||
static const DECLARE_TLV_DB_SCALE(outpga_tlv, -5700, 100, 0);
|
||||
static const unsigned int spkboost_tlv[] = {
|
||||
TLV_DB_RANGE_HEAD(7),
|
||||
TLV_DB_RANGE_HEAD(2),
|
||||
0, 6, TLV_DB_SCALE_ITEM(0, 150, 0),
|
||||
7, 7, TLV_DB_SCALE_ITEM(1200, 0, 0),
|
||||
};
|
||||
|
|
|
@ -694,6 +694,7 @@ static int __devinit fsl_ssi_probe(struct platform_device *pdev)
|
|||
|
||||
/* Initialize the the device_attribute structure */
|
||||
dev_attr = &ssi_private->dev_attr;
|
||||
sysfs_attr_init(&dev_attr->attr);
|
||||
dev_attr->attr.name = "statistics";
|
||||
dev_attr->attr.mode = S_IRUGO;
|
||||
dev_attr->show = fsl_sysfs_ssi_show;
|
||||
|
|
|
@ -392,7 +392,8 @@ static int mpc8610_hpcd_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
if (strcasecmp(sprop, "i2s-slave") == 0) {
|
||||
machine_data->dai_format = SND_SOC_DAIFMT_I2S;
|
||||
machine_data->dai_format =
|
||||
SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM;
|
||||
machine_data->codec_clk_direction = SND_SOC_CLOCK_OUT;
|
||||
machine_data->cpu_clk_direction = SND_SOC_CLOCK_IN;
|
||||
|
||||
|
@ -409,31 +410,38 @@ static int mpc8610_hpcd_probe(struct platform_device *pdev)
|
|||
}
|
||||
machine_data->clk_frequency = be32_to_cpup(iprop);
|
||||
} else if (strcasecmp(sprop, "i2s-master") == 0) {
|
||||
machine_data->dai_format = SND_SOC_DAIFMT_I2S;
|
||||
machine_data->dai_format =
|
||||
SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS;
|
||||
machine_data->codec_clk_direction = SND_SOC_CLOCK_IN;
|
||||
machine_data->cpu_clk_direction = SND_SOC_CLOCK_OUT;
|
||||
} else if (strcasecmp(sprop, "lj-slave") == 0) {
|
||||
machine_data->dai_format = SND_SOC_DAIFMT_LEFT_J;
|
||||
machine_data->dai_format =
|
||||
SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_CBM_CFM;
|
||||
machine_data->codec_clk_direction = SND_SOC_CLOCK_OUT;
|
||||
machine_data->cpu_clk_direction = SND_SOC_CLOCK_IN;
|
||||
} else if (strcasecmp(sprop, "lj-master") == 0) {
|
||||
machine_data->dai_format = SND_SOC_DAIFMT_LEFT_J;
|
||||
machine_data->dai_format =
|
||||
SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_CBS_CFS;
|
||||
machine_data->codec_clk_direction = SND_SOC_CLOCK_IN;
|
||||
machine_data->cpu_clk_direction = SND_SOC_CLOCK_OUT;
|
||||
} else if (strcasecmp(sprop, "rj-slave") == 0) {
|
||||
machine_data->dai_format = SND_SOC_DAIFMT_RIGHT_J;
|
||||
machine_data->dai_format =
|
||||
SND_SOC_DAIFMT_RIGHT_J | SND_SOC_DAIFMT_CBM_CFM;
|
||||
machine_data->codec_clk_direction = SND_SOC_CLOCK_OUT;
|
||||
machine_data->cpu_clk_direction = SND_SOC_CLOCK_IN;
|
||||
} else if (strcasecmp(sprop, "rj-master") == 0) {
|
||||
machine_data->dai_format = SND_SOC_DAIFMT_RIGHT_J;
|
||||
machine_data->dai_format =
|
||||
SND_SOC_DAIFMT_RIGHT_J | SND_SOC_DAIFMT_CBS_CFS;
|
||||
machine_data->codec_clk_direction = SND_SOC_CLOCK_IN;
|
||||
machine_data->cpu_clk_direction = SND_SOC_CLOCK_OUT;
|
||||
} else if (strcasecmp(sprop, "ac97-slave") == 0) {
|
||||
machine_data->dai_format = SND_SOC_DAIFMT_AC97;
|
||||
machine_data->dai_format =
|
||||
SND_SOC_DAIFMT_AC97 | SND_SOC_DAIFMT_CBM_CFM;
|
||||
machine_data->codec_clk_direction = SND_SOC_CLOCK_OUT;
|
||||
machine_data->cpu_clk_direction = SND_SOC_CLOCK_IN;
|
||||
} else if (strcasecmp(sprop, "ac97-master") == 0) {
|
||||
machine_data->dai_format = SND_SOC_DAIFMT_AC97;
|
||||
machine_data->dai_format =
|
||||
SND_SOC_DAIFMT_AC97 | SND_SOC_DAIFMT_CBS_CFS;
|
||||
machine_data->codec_clk_direction = SND_SOC_CLOCK_IN;
|
||||
machine_data->cpu_clk_direction = SND_SOC_CLOCK_OUT;
|
||||
} else {
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include "../codecs/wm8994.h"
|
||||
#include <sound/pcm_params.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
/*
|
||||
* Default CFG switch settings to use this driver:
|
||||
|
|
|
@ -191,7 +191,7 @@ static int speyside_late_probe(struct snd_soc_card *card)
|
|||
snd_soc_dapm_ignore_suspend(&card->dapm, "Headset Mic");
|
||||
snd_soc_dapm_ignore_suspend(&card->dapm, "Main AMIC");
|
||||
snd_soc_dapm_ignore_suspend(&card->dapm, "Main DMIC");
|
||||
snd_soc_dapm_ignore_suspend(&card->dapm, "Speaker");
|
||||
snd_soc_dapm_ignore_suspend(&card->dapm, "Main Speaker");
|
||||
snd_soc_dapm_ignore_suspend(&card->dapm, "WM1250 Output");
|
||||
snd_soc_dapm_ignore_suspend(&card->dapm, "WM1250 Input");
|
||||
|
||||
|
|
|
@ -709,6 +709,12 @@ int snd_soc_resume(struct device *dev)
|
|||
struct snd_soc_card *card = dev_get_drvdata(dev);
|
||||
int i, ac97_control = 0;
|
||||
|
||||
/* If the initialization of this soc device failed, there is no codec
|
||||
* associated with it. Just bail out in this case.
|
||||
*/
|
||||
if (list_empty(&card->codec_dev_list))
|
||||
return 0;
|
||||
|
||||
/* AC97 devices might have other drivers hanging off them so
|
||||
* need to resume immediately. Other drivers don't have that
|
||||
* problem and may take a substantial amount of time to resume
|
||||
|
|
|
@ -765,10 +765,61 @@ static void usb_mixer_elem_free(struct snd_kcontrol *kctl)
|
|||
* interface to ALSA control for feature/mixer units
|
||||
*/
|
||||
|
||||
/* volume control quirks */
|
||||
static void volume_control_quirks(struct usb_mixer_elem_info *cval,
|
||||
struct snd_kcontrol *kctl)
|
||||
{
|
||||
switch (cval->mixer->chip->usb_id) {
|
||||
case USB_ID(0x0471, 0x0101):
|
||||
case USB_ID(0x0471, 0x0104):
|
||||
case USB_ID(0x0471, 0x0105):
|
||||
case USB_ID(0x0672, 0x1041):
|
||||
/* quirk for UDA1321/N101.
|
||||
* note that detection between firmware 2.1.1.7 (N101)
|
||||
* and later 2.1.1.21 is not very clear from datasheets.
|
||||
* I hope that the min value is -15360 for newer firmware --jk
|
||||
*/
|
||||
if (!strcmp(kctl->id.name, "PCM Playback Volume") &&
|
||||
cval->min == -15616) {
|
||||
snd_printk(KERN_INFO
|
||||
"set volume quirk for UDA1321/N101 chip\n");
|
||||
cval->max = -256;
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_ID(0x046d, 0x09a4):
|
||||
if (!strcmp(kctl->id.name, "Mic Capture Volume")) {
|
||||
snd_printk(KERN_INFO
|
||||
"set volume quirk for QuickCam E3500\n");
|
||||
cval->min = 6080;
|
||||
cval->max = 8768;
|
||||
cval->res = 192;
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_ID(0x046d, 0x0808):
|
||||
case USB_ID(0x046d, 0x0809):
|
||||
case USB_ID(0x046d, 0x081d): /* HD Webcam c510 */
|
||||
case USB_ID(0x046d, 0x0991):
|
||||
/* Most audio usb devices lie about volume resolution.
|
||||
* Most Logitech webcams have res = 384.
|
||||
* Proboly there is some logitech magic behind this number --fishor
|
||||
*/
|
||||
if (!strcmp(kctl->id.name, "Mic Capture Volume")) {
|
||||
snd_printk(KERN_INFO
|
||||
"set resolution quirk: cval->res = 384\n");
|
||||
cval->res = 384;
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* retrieve the minimum and maximum values for the specified control
|
||||
*/
|
||||
static int get_min_max(struct usb_mixer_elem_info *cval, int default_min)
|
||||
static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval,
|
||||
int default_min, struct snd_kcontrol *kctl)
|
||||
{
|
||||
/* for failsafe */
|
||||
cval->min = default_min;
|
||||
|
@ -844,6 +895,9 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min)
|
|||
cval->initialized = 1;
|
||||
}
|
||||
|
||||
if (kctl)
|
||||
volume_control_quirks(cval, kctl);
|
||||
|
||||
/* USB descriptions contain the dB scale in 1/256 dB unit
|
||||
* while ALSA TLV contains in 1/100 dB unit
|
||||
*/
|
||||
|
@ -864,6 +918,7 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#define get_min_max(cval, def) get_min_max_with_quirks(cval, def, NULL)
|
||||
|
||||
/* get a feature/mixer unit info */
|
||||
static int mixer_ctl_feature_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
|
||||
|
@ -882,7 +937,7 @@ static int mixer_ctl_feature_info(struct snd_kcontrol *kcontrol, struct snd_ctl_
|
|||
uinfo->value.integer.max = 1;
|
||||
} else {
|
||||
if (!cval->initialized) {
|
||||
get_min_max(cval, 0);
|
||||
get_min_max_with_quirks(cval, 0, kcontrol);
|
||||
if (cval->initialized && cval->dBmin >= cval->dBmax) {
|
||||
kcontrol->vd[0].access &=
|
||||
~(SNDRV_CTL_ELEM_ACCESS_TLV_READ |
|
||||
|
@ -1045,9 +1100,6 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
|
|||
cval->ch_readonly = readonly_mask;
|
||||
}
|
||||
|
||||
/* get min/max values */
|
||||
get_min_max(cval, 0);
|
||||
|
||||
/* if all channels in the mask are marked read-only, make the control
|
||||
* read-only. set_cur_mix_value() will check the mask again and won't
|
||||
* issue write commands to read-only channels. */
|
||||
|
@ -1069,6 +1121,9 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
|
|||
len = snd_usb_copy_string_desc(state, nameid,
|
||||
kctl->id.name, sizeof(kctl->id.name));
|
||||
|
||||
/* get min/max values */
|
||||
get_min_max_with_quirks(cval, 0, kctl);
|
||||
|
||||
switch (control) {
|
||||
case UAC_FU_MUTE:
|
||||
case UAC_FU_VOLUME:
|
||||
|
@ -1118,51 +1173,6 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
|
|||
break;
|
||||
}
|
||||
|
||||
/* volume control quirks */
|
||||
switch (state->chip->usb_id) {
|
||||
case USB_ID(0x0471, 0x0101):
|
||||
case USB_ID(0x0471, 0x0104):
|
||||
case USB_ID(0x0471, 0x0105):
|
||||
case USB_ID(0x0672, 0x1041):
|
||||
/* quirk for UDA1321/N101.
|
||||
* note that detection between firmware 2.1.1.7 (N101)
|
||||
* and later 2.1.1.21 is not very clear from datasheets.
|
||||
* I hope that the min value is -15360 for newer firmware --jk
|
||||
*/
|
||||
if (!strcmp(kctl->id.name, "PCM Playback Volume") &&
|
||||
cval->min == -15616) {
|
||||
snd_printk(KERN_INFO
|
||||
"set volume quirk for UDA1321/N101 chip\n");
|
||||
cval->max = -256;
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_ID(0x046d, 0x09a4):
|
||||
if (!strcmp(kctl->id.name, "Mic Capture Volume")) {
|
||||
snd_printk(KERN_INFO
|
||||
"set volume quirk for QuickCam E3500\n");
|
||||
cval->min = 6080;
|
||||
cval->max = 8768;
|
||||
cval->res = 192;
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_ID(0x046d, 0x0808):
|
||||
case USB_ID(0x046d, 0x0809):
|
||||
case USB_ID(0x046d, 0x0991):
|
||||
/* Most audio usb devices lie about volume resolution.
|
||||
* Most Logitech webcams have res = 384.
|
||||
* Proboly there is some logitech magic behind this number --fishor
|
||||
*/
|
||||
if (!strcmp(kctl->id.name, "Mic Capture Volume")) {
|
||||
snd_printk(KERN_INFO
|
||||
"set resolution quirk: cval->res = 384\n");
|
||||
cval->res = 384;
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
range = (cval->max - cval->min) / cval->res;
|
||||
/* Are there devices with volume range more than 255? I use a bit more
|
||||
* to be sure. 384 is a resolution magic number found on Logitech
|
||||
|
|
|
@ -1632,6 +1632,37 @@ YAMAHA_DEVICE(0x7010, "UB99"),
|
|||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
/* Roland GAIA SH-01 */
|
||||
USB_DEVICE(0x0582, 0x0111),
|
||||
.driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
|
||||
.vendor_name = "Roland",
|
||||
.product_name = "GAIA",
|
||||
.ifnum = QUIRK_ANY_INTERFACE,
|
||||
.type = QUIRK_COMPOSITE,
|
||||
.data = (const struct snd_usb_audio_quirk[]) {
|
||||
{
|
||||
.ifnum = 0,
|
||||
.type = QUIRK_AUDIO_STANDARD_INTERFACE
|
||||
},
|
||||
{
|
||||
.ifnum = 1,
|
||||
.type = QUIRK_AUDIO_STANDARD_INTERFACE
|
||||
},
|
||||
{
|
||||
.ifnum = 2,
|
||||
.type = QUIRK_MIDI_FIXED_ENDPOINT,
|
||||
.data = &(const struct snd_usb_midi_endpoint_info) {
|
||||
.out_cables = 0x0003,
|
||||
.in_cables = 0x0003
|
||||
}
|
||||
},
|
||||
{
|
||||
.ifnum = -1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
USB_DEVICE(0x0582, 0x0113),
|
||||
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
|
||||
|
|
|
@ -137,12 +137,12 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip,
|
|||
return -ENOMEM;
|
||||
}
|
||||
if (fp->nr_rates > 0) {
|
||||
rate_table = kmalloc(sizeof(int) * fp->nr_rates, GFP_KERNEL);
|
||||
rate_table = kmemdup(fp->rate_table,
|
||||
sizeof(int) * fp->nr_rates, GFP_KERNEL);
|
||||
if (!rate_table) {
|
||||
kfree(fp);
|
||||
return -ENOMEM;
|
||||
}
|
||||
memcpy(rate_table, fp->rate_table, sizeof(int) * fp->nr_rates);
|
||||
fp->rate_table = rate_table;
|
||||
}
|
||||
|
||||
|
@ -224,10 +224,9 @@ static int create_uaxx_quirk(struct snd_usb_audio *chip,
|
|||
if (altsd->bNumEndpoints != 1)
|
||||
return -ENXIO;
|
||||
|
||||
fp = kmalloc(sizeof(*fp), GFP_KERNEL);
|
||||
fp = kmemdup(&ua_format, sizeof(*fp), GFP_KERNEL);
|
||||
if (!fp)
|
||||
return -ENOMEM;
|
||||
memcpy(fp, &ua_format, sizeof(*fp));
|
||||
|
||||
fp->iface = altsd->bInterfaceNumber;
|
||||
fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress;
|
||||
|
|
Reference in a new issue