summaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
Diffstat (limited to 'sound')
-rw-r--r--sound/arm/aaci.c2
-rw-r--r--sound/arm/pxa2xx-ac97.c1
-rw-r--r--sound/core/Kconfig9
-rw-r--r--sound/core/init.c55
-rw-r--r--sound/core/pcm_lib.c3
-rw-r--r--sound/core/pcm_native.c40
-rw-r--r--sound/core/vmaster.c65
-rw-r--r--sound/drivers/aloop.c1
-rw-r--r--sound/drivers/dummy.c1
-rw-r--r--sound/drivers/ml403-ac97cr.c1
-rw-r--r--sound/drivers/mpu401/mpu401.c1
-rw-r--r--sound/drivers/mtpav.c1
-rw-r--r--sound/drivers/pcsp/pcsp.c1
-rw-r--r--sound/drivers/serial-u16550.c1
-rw-r--r--sound/drivers/virmidi.c1
-rw-r--r--sound/drivers/vx/vx_core.c2
-rw-r--r--sound/firewire/amdtp.h1
-rw-r--r--sound/firewire/isight.c44
-rw-r--r--sound/firewire/scs1x.c43
-rw-r--r--sound/firewire/speakers.c106
-rw-r--r--sound/i2c/other/ak4xxx-adda.c2
-rw-r--r--sound/isa/ad1848/ad1848.c1
-rw-r--r--sound/isa/adlib.c1
-rw-r--r--sound/isa/cmi8328.c1
-rw-r--r--sound/isa/cmi8330.c1
-rw-r--r--sound/isa/cs423x/cs4231.c1
-rw-r--r--sound/isa/cs423x/cs4236.c2
-rw-r--r--sound/isa/es1688/es1688.c1
-rw-r--r--sound/isa/es18xx.c2
-rw-r--r--sound/isa/galaxy/galaxy.c1
-rw-r--r--sound/isa/gus/gusclassic.c1
-rw-r--r--sound/isa/gus/gusextreme.c1
-rw-r--r--sound/isa/gus/gusmax.c1
-rw-r--r--sound/isa/gus/interwave.c1
-rw-r--r--sound/isa/msnd/msnd_pinnacle.c1
-rw-r--r--sound/isa/opl3sa2.c2
-rw-r--r--sound/isa/opti9xx/miro.c1
-rw-r--r--sound/isa/opti9xx/opti92x-ad1848.c1
-rw-r--r--sound/isa/sb/jazz16.c1
-rw-r--r--sound/isa/sb/sb16.c1
-rw-r--r--sound/isa/sb/sb8.c1
-rw-r--r--sound/isa/sc6000.c1
-rw-r--r--sound/isa/sscape.c1
-rw-r--r--sound/isa/wavefront/wavefront.c1
-rw-r--r--sound/oss/kahlua.c2
-rw-r--r--sound/parisc/harmony.c3
-rw-r--r--sound/pci/ac97/ac97_codec.c2
-rw-r--r--sound/pci/ad1889.c1
-rw-r--r--sound/pci/ali5451/ali5451.c1
-rw-r--r--sound/pci/als300.c1
-rw-r--r--sound/pci/als4000.c1
-rw-r--r--sound/pci/asihpi/asihpi.c2
-rw-r--r--sound/pci/asihpi/hpioctl.c1
-rw-r--r--sound/pci/atiixp.c1
-rw-r--r--sound/pci/atiixp_modem.c1
-rw-r--r--sound/pci/au88x0/au88x0.c1
-rw-r--r--sound/pci/aw2/aw2-alsa.c1
-rw-r--r--sound/pci/azt3328.c1
-rw-r--r--sound/pci/bt87x.c1
-rw-r--r--sound/pci/ca0106/ca0106_main.c1
-rw-r--r--sound/pci/cmipci.c1
-rw-r--r--sound/pci/cs4281.c3
-rw-r--r--sound/pci/cs46xx/cs46xx.c1
-rw-r--r--sound/pci/cs5530.c1
-rw-r--r--sound/pci/cs5535audio/cs5535audio.c1
-rw-r--r--sound/pci/ctxfi/xfi.c1
-rw-r--r--sound/pci/echoaudio/echoaudio.c1
-rw-r--r--sound/pci/emu10k1/emu10k1.c1
-rw-r--r--sound/pci/emu10k1/emu10k1x.c1
-rw-r--r--sound/pci/ens1370.c3
-rw-r--r--sound/pci/es1938.c1
-rw-r--r--sound/pci/es1968.c74
-rw-r--r--sound/pci/fm801.c1
-rw-r--r--sound/pci/hda/Kconfig11
-rw-r--r--sound/pci/hda/Makefile2
-rw-r--r--sound/pci/hda/hda_codec.c69
-rw-r--r--sound/pci/hda/hda_codec.h11
-rw-r--r--sound/pci/hda/hda_generic.c59
-rw-r--r--sound/pci/hda/hda_generic.h4
-rw-r--r--sound/pci/hda/hda_i915.c75
-rw-r--r--sound/pci/hda/hda_i915.h35
-rw-r--r--sound/pci/hda/hda_intel.c140
-rw-r--r--sound/pci/hda/hda_jack.c2
-rw-r--r--sound/pci/hda/hda_local.h10
-rw-r--r--sound/pci/hda/hda_proc.c15
-rw-r--r--sound/pci/hda/patch_analog.c12
-rw-r--r--sound/pci/hda/patch_ca0132.c8
-rw-r--r--sound/pci/hda/patch_cirrus.c23
-rw-r--r--sound/pci/hda/patch_conexant.c2
-rw-r--r--sound/pci/hda/patch_hdmi.c128
-rw-r--r--sound/pci/hda/patch_realtek.c138
-rw-r--r--sound/pci/hda/patch_sigmatel.c14
-rw-r--r--sound/pci/hda/patch_via.c15
-rw-r--r--sound/pci/ice1712/ice1712.c1
-rw-r--r--sound/pci/ice1712/ice1724.c1
-rw-r--r--sound/pci/intel8x0.c1
-rw-r--r--sound/pci/intel8x0m.c1
-rw-r--r--sound/pci/korg1212/korg1212.c1
-rw-r--r--sound/pci/lola/lola.c1
-rw-r--r--sound/pci/lx6464es/lx6464es.c1
-rw-r--r--sound/pci/maestro3.c1
-rw-r--r--sound/pci/mixart/mixart.c1
-rw-r--r--sound/pci/nm256/nm256.c1
-rw-r--r--sound/pci/oxygen/oxygen_lib.c1
-rw-r--r--sound/pci/pcxhr/pcxhr.c1
-rw-r--r--sound/pci/riptide/riptide.c2
-rw-r--r--sound/pci/rme32.c1
-rw-r--r--sound/pci/rme96.c1
-rw-r--r--sound/pci/rme9652/hdsp.c1
-rw-r--r--sound/pci/rme9652/hdspm.c59
-rw-r--r--sound/pci/rme9652/rme9652.c1
-rw-r--r--sound/pci/sis7019.c1
-rw-r--r--sound/pci/sonicvibes.c1
-rw-r--r--sound/pci/trident/trident.c1
-rw-r--r--sound/pci/via82xx.c1
-rw-r--r--sound/pci/via82xx_modem.c1
-rw-r--r--sound/pci/vx222/vx222.c1
-rw-r--r--sound/pci/ymfpci/ymfpci.c1
-rw-r--r--sound/pci/ymfpci/ymfpci_main.c2
-rw-r--r--sound/ppc/powermac.c1
-rw-r--r--sound/sh/aica.c1
-rw-r--r--sound/sh/sh_dac_audio.c2
-rw-r--r--sound/soc/au1x/ac97c.c21
-rw-r--r--sound/soc/au1x/psc-ac97.c33
-rw-r--r--sound/soc/blackfin/bf5xx-ac97.c29
-rw-r--r--sound/soc/cirrus/ep93xx-ac97.c12
-rw-r--r--sound/soc/codecs/88pm860x-codec.c6
-rw-r--r--sound/soc/codecs/ac97.c7
-rw-r--r--sound/soc/codecs/ad1980.c12
-rw-r--r--sound/soc/codecs/adau1701.c298
-rw-r--r--sound/soc/codecs/sgtl5000.c2
-rw-r--r--sound/soc/codecs/sgtl5000.h2
-rw-r--r--sound/soc/codecs/si476x.c6
-rw-r--r--sound/soc/codecs/stac9766.c26
-rw-r--r--sound/soc/codecs/tas5086.c330
-rw-r--r--sound/soc/codecs/tlv320aic3x.c6
-rw-r--r--sound/soc/codecs/twl6040.c109
-rw-r--r--sound/soc/codecs/wm8400.c9
-rw-r--r--sound/soc/codecs/wm8903.c6
-rw-r--r--sound/soc/codecs/wm8904.c9
-rw-r--r--sound/soc/codecs/wm8962.c2
-rw-r--r--sound/soc/codecs/wm8978.c1
-rw-r--r--sound/soc/codecs/wm8990.c11
-rw-r--r--sound/soc/codecs/wm8991.h9
-rw-r--r--sound/soc/codecs/wm8994.c12
-rw-r--r--sound/soc/codecs/wm8995.h7
-rw-r--r--sound/soc/codecs/wm9705.c16
-rw-r--r--sound/soc/codecs/wm9712.c18
-rw-r--r--sound/soc/codecs/wm9713.c18
-rw-r--r--sound/soc/codecs/wm_adsp.h10
-rw-r--r--sound/soc/codecs/wm_hubs.c6
-rw-r--r--sound/soc/davinci/davinci-evm.c1
-rw-r--r--sound/soc/davinci/davinci-pcm.c1
-rw-r--r--sound/soc/davinci/davinci-pcm.h2
-rw-r--r--sound/soc/fsl/imx-sgtl5000.c4
-rw-r--r--sound/soc/fsl/imx-ssi.c11
-rw-r--r--sound/soc/fsl/mpc5200_psc_ac97.c10
-rw-r--r--sound/soc/mid-x86/mfld_machine.c31
-rw-r--r--sound/soc/mxs/mxs-saif.c35
-rw-r--r--sound/soc/nuc900/nuc900-ac97.c60
-rw-r--r--sound/soc/omap/Kconfig2
-rw-r--r--sound/soc/omap/mcbsp.c39
-rw-r--r--sound/soc/omap/omap-dmic.c11
-rw-r--r--sound/soc/omap/omap-mcpdm.c16
-rw-r--r--sound/soc/omap/omap-pcm.c17
-rw-r--r--sound/soc/omap/rx51.c2
-rw-r--r--sound/soc/pxa/pxa2xx-ac97.c10
-rw-r--r--sound/soc/pxa/pxa2xx-ac97.h3
-rw-r--r--sound/soc/samsung/Kconfig2
-rw-r--r--sound/soc/samsung/ac97.c42
-rw-r--r--sound/soc/samsung/i2s.c74
-rw-r--r--sound/soc/samsung/idma.c1
-rw-r--r--sound/soc/samsung/s3c-i2s-v2.c4
-rw-r--r--sound/soc/sh/hac.c8
-rw-r--r--sound/soc/soc-core.c17
-rw-r--r--sound/soc/tegra/tegra20_ac97.c67
-rw-r--r--sound/soc/txx9/txx9aclc-ac97.c17
-rw-r--r--sound/soc/ux500/ux500_pcm.c10
-rw-r--r--sound/sound_core.c2
-rw-r--r--sound/sparc/dbri.c2
-rw-r--r--sound/spi/at73c213.c1
-rw-r--r--sound/usb/6fire/chip.c2
-rw-r--r--sound/usb/6fire/pcm.c12
-rw-r--r--sound/usb/Kconfig31
-rw-r--r--sound/usb/Makefile2
-rw-r--r--sound/usb/caiaq/audio.c14
-rw-r--r--sound/usb/caiaq/device.c31
-rw-r--r--sound/usb/card.c22
-rw-r--r--sound/usb/card.h1
-rw-r--r--sound/usb/clock.c4
-rw-r--r--sound/usb/format.c34
-rw-r--r--sound/usb/format.h2
-rw-r--r--sound/usb/hiface/Makefile2
-rw-r--r--sound/usb/hiface/chip.c297
-rw-r--r--sound/usb/hiface/chip.h30
-rw-r--r--sound/usb/hiface/pcm.c621
-rw-r--r--sound/usb/hiface/pcm.h24
-rw-r--r--sound/usb/midi.c74
-rw-r--r--sound/usb/misc/ua101.c2
-rw-r--r--sound/usb/mixer.c1
-rw-r--r--sound/usb/mixer_quirks.c212
-rw-r--r--sound/usb/pcm.c45
-rw-r--r--sound/usb/quirks-table.h509
-rw-r--r--sound/usb/quirks.c213
-rw-r--r--sound/usb/stream.c18
-rw-r--r--sound/usb/usbaudio.h2
-rw-r--r--sound/usb/usx2y/usbusx2y.c2
-rw-r--r--sound/usb/usx2y/usbusx2yaudio.c3
208 files changed, 3676 insertions, 1450 deletions
diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c
index aa5d803..1ca8dc2 100644
--- a/sound/arm/aaci.c
+++ b/sound/arm/aaci.c
@@ -1076,8 +1076,6 @@ static int aaci_remove(struct amba_device *dev)
{
struct snd_card *card = amba_get_drvdata(dev);
- amba_set_drvdata(dev, NULL);
-
if (card) {
struct aaci *aaci = card->private_data;
writel(0, aaci->base + AACI_MAINCR);
diff --git a/sound/arm/pxa2xx-ac97.c b/sound/arm/pxa2xx-ac97.c
index ec54be4..ce431e6 100644
--- a/sound/arm/pxa2xx-ac97.c
+++ b/sound/arm/pxa2xx-ac97.c
@@ -230,7 +230,6 @@ static int pxa2xx_ac97_remove(struct platform_device *dev)
if (card) {
snd_card_free(card);
- platform_set_drvdata(dev, NULL);
pxa2xx_ac97_hw_remove(dev);
}
diff --git a/sound/core/Kconfig b/sound/core/Kconfig
index b413ed0..c0c2f57 100644
--- a/sound/core/Kconfig
+++ b/sound/core/Kconfig
@@ -157,6 +157,15 @@ config SND_DYNAMIC_MINORS
If you are unsure about this, say N here.
+config SND_MAX_CARDS
+ int "Max number of sound cards"
+ range 4 256
+ default 32
+ depends on SND_DYNAMIC_MINORS
+ help
+ Specify the max number of sound cards that can be assigned
+ on a single machine.
+
config SND_SUPPORT_OLD_API
bool "Support old ALSA API"
default y
diff --git a/sound/core/init.c b/sound/core/init.c
index 6ef0640..6b90871 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -46,7 +46,8 @@ static LIST_HEAD(shutdown_files);
static const struct file_operations snd_shutdown_f_ops;
-static unsigned int snd_cards_lock; /* locked for registering/using */
+/* locked for registering/using */
+static DECLARE_BITMAP(snd_cards_lock, SNDRV_CARDS);
struct snd_card *snd_cards[SNDRV_CARDS];
EXPORT_SYMBOL(snd_cards);
@@ -167,29 +168,35 @@ int snd_card_create(int idx, const char *xid,
err = 0;
mutex_lock(&snd_card_mutex);
if (idx < 0) {
- for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++)
+ for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++) {
/* idx == -1 == 0xffff means: take any free slot */
- if (~snd_cards_lock & idx & 1<<idx2) {
+ if (idx2 < sizeof(int) && !(idx & (1U << idx2)))
+ continue;
+ if (!test_bit(idx2, snd_cards_lock)) {
if (module_slot_match(module, idx2)) {
idx = idx2;
break;
}
}
+ }
}
if (idx < 0) {
- for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++)
+ for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++) {
/* idx == -1 == 0xffff means: take any free slot */
- if (~snd_cards_lock & idx & 1<<idx2) {
+ if (idx2 < sizeof(int) && !(idx & (1U << idx2)))
+ continue;
+ if (!test_bit(idx2, snd_cards_lock)) {
if (!slots[idx2] || !*slots[idx2]) {
idx = idx2;
break;
}
}
+ }
}
if (idx < 0)
err = -ENODEV;
else if (idx < snd_ecards_limit) {
- if (snd_cards_lock & (1 << idx))
+ if (test_bit(idx, snd_cards_lock))
err = -EBUSY; /* invalid */
} else if (idx >= SNDRV_CARDS)
err = -ENODEV;
@@ -199,7 +206,7 @@ int snd_card_create(int idx, const char *xid,
idx, snd_ecards_limit - 1, err);
goto __error;
}
- snd_cards_lock |= 1 << idx; /* lock it */
+ set_bit(idx, snd_cards_lock); /* lock it */
if (idx >= snd_ecards_limit)
snd_ecards_limit = idx + 1; /* increase the limit */
mutex_unlock(&snd_card_mutex);
@@ -249,7 +256,7 @@ int snd_card_locked(int card)
int locked;
mutex_lock(&snd_card_mutex);
- locked = snd_cards_lock & (1 << card);
+ locked = test_bit(card, snd_cards_lock);
mutex_unlock(&snd_card_mutex);
return locked;
}
@@ -361,7 +368,7 @@ int snd_card_disconnect(struct snd_card *card)
/* phase 1: disable fops (user space) operations for ALSA API */
mutex_lock(&snd_card_mutex);
snd_cards[card->number] = NULL;
- snd_cards_lock &= ~(1 << card->number);
+ clear_bit(card->number, snd_cards_lock);
mutex_unlock(&snd_card_mutex);
/* phase 2: replace file->f_op with special dummy operations */
@@ -549,7 +556,6 @@ static void snd_card_set_id_no_lock(struct snd_card *card, const char *src,
const char *nid)
{
int len, loops;
- bool with_suffix;
bool is_default = false;
char *id;
@@ -565,26 +571,23 @@ static void snd_card_set_id_no_lock(struct snd_card *card, const char *src,
is_default = true;
}
- with_suffix = false;
+ len = strlen(id);
for (loops = 0; loops < SNDRV_CARDS; loops++) {
+ char *spos;
+ char sfxstr[5]; /* "_012" */
+ int sfxlen;
+
if (card_id_ok(card, id))
return; /* OK */
- len = strlen(id);
- if (!with_suffix) {
- /* add the "_X" suffix */
- char *spos = id + len;
- if (len > sizeof(card->id) - 3)
- spos = id + sizeof(card->id) - 3;
- strcpy(spos, "_1");
- with_suffix = true;
- } else {
- /* modify the existing suffix */
- if (id[len - 1] != '9')
- id[len - 1]++;
- else
- id[len - 1] = 'A';
- }
+ /* Add _XYZ suffix */
+ sprintf(sfxstr, "_%X", loops + 1);
+ sfxlen = strlen(sfxstr);
+ if (len + sfxlen >= sizeof(card->id))
+ spos = id + sizeof(card->id) - sfxlen - 1;
+ else
+ spos = id + len;
+ strcpy(spos, sfxstr);
}
/* fallback to the default id */
if (!is_default) {
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index 41b3dfe..82bb029 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -568,7 +568,8 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream)
*
* Sets the given PCM operators to the pcm instance.
*/
-void snd_pcm_set_ops(struct snd_pcm *pcm, int direction, struct snd_pcm_ops *ops)
+void snd_pcm_set_ops(struct snd_pcm *pcm, int direction,
+ const struct snd_pcm_ops *ops)
{
struct snd_pcm_str *stream = &pcm->streams[direction];
struct snd_pcm_substream *substream;
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index f928181..a68d4c6 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -1589,29 +1589,16 @@ static int snd_pcm_drop(struct snd_pcm_substream *substream)
}
-/* WARNING: Don't forget to fput back the file */
-static struct file *snd_pcm_file_fd(int fd, int *fput_needed)
+static bool is_pcm_file(struct file *file)
{
- struct file *file;
- struct inode *inode;
+ struct inode *inode = file_inode(file);
unsigned int minor;
- file = fget_light(fd, fput_needed);
- if (!file)
- return NULL;
- inode = file_inode(file);
- if (!S_ISCHR(inode->i_mode) ||
- imajor(inode) != snd_major) {
- fput_light(file, *fput_needed);
- return NULL;
- }
+ if (!S_ISCHR(inode->i_mode) || imajor(inode) != snd_major)
+ return false;
minor = iminor(inode);
- if (!snd_lookup_minor_data(minor, SNDRV_DEVICE_TYPE_PCM_PLAYBACK) &&
- !snd_lookup_minor_data(minor, SNDRV_DEVICE_TYPE_PCM_CAPTURE)) {
- fput_light(file, *fput_needed);
- return NULL;
- }
- return file;
+ return snd_lookup_minor_data(minor, SNDRV_DEVICE_TYPE_PCM_PLAYBACK) ||
+ snd_lookup_minor_data(minor, SNDRV_DEVICE_TYPE_PCM_CAPTURE);
}
/*
@@ -1620,16 +1607,18 @@ static struct file *snd_pcm_file_fd(int fd, int *fput_needed)
static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
{
int res = 0;
- struct file *file;
struct snd_pcm_file *pcm_file;
struct snd_pcm_substream *substream1;
struct snd_pcm_group *group;
- int fput_needed;
+ struct fd f = fdget(fd);
- file = snd_pcm_file_fd(fd, &fput_needed);
- if (!file)
+ if (!f.file)
return -EBADFD;
- pcm_file = file->private_data;
+ if (!is_pcm_file(f.file)) {
+ res = -EBADFD;
+ goto _badf;
+ }
+ pcm_file = f.file->private_data;
substream1 = pcm_file->substream;
group = kmalloc(sizeof(*group), GFP_KERNEL);
if (!group) {
@@ -1663,8 +1652,9 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
up_write(&snd_pcm_link_rwsem);
_nolock:
snd_card_unref(substream1->pcm->card);
- fput_light(file, fput_needed);
kfree(group);
+ _badf:
+ fdput(f);
return res;
}
diff --git a/sound/core/vmaster.c b/sound/core/vmaster.c
index 02f90b4..842a97d 100644
--- a/sound/core/vmaster.c
+++ b/sound/core/vmaster.c
@@ -310,20 +310,10 @@ static int master_get(struct snd_kcontrol *kcontrol,
return 0;
}
-static int master_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static int sync_slaves(struct link_master *master, int old_val, int new_val)
{
- struct link_master *master = snd_kcontrol_chip(kcontrol);
struct link_slave *slave;
struct snd_ctl_elem_value *uval;
- int err, old_val;
-
- err = master_init(master);
- if (err < 0)
- return err;
- old_val = master->val;
- if (ucontrol->value.integer.value[0] == old_val)
- return 0;
uval = kmalloc(sizeof(*uval), GFP_KERNEL);
if (!uval)
@@ -332,11 +322,33 @@ static int master_put(struct snd_kcontrol *kcontrol,
master->val = old_val;
uval->id = slave->slave.id;
slave_get_val(slave, uval);
- master->val = ucontrol->value.integer.value[0];
+ master->val = new_val;
slave_put_val(slave, uval);
}
kfree(uval);
- if (master->hook && !err)
+ return 0;
+}
+
+static int master_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct link_master *master = snd_kcontrol_chip(kcontrol);
+ int err, new_val, old_val;
+ bool first_init;
+
+ err = master_init(master);
+ if (err < 0)
+ return err;
+ first_init = err;
+ old_val = master->val;
+ new_val = ucontrol->value.integer.value[0];
+ if (new_val == old_val)
+ return 0;
+
+ err = sync_slaves(master, old_val, new_val);
+ if (err < 0)
+ return err;
+ if (master->hook && !first_init)
master->hook(master->hook_private_data, master->val);
return 1;
}
@@ -442,20 +454,33 @@ int snd_ctl_add_vmaster_hook(struct snd_kcontrol *kcontrol,
EXPORT_SYMBOL_GPL(snd_ctl_add_vmaster_hook);
/**
- * snd_ctl_sync_vmaster_hook - Sync the vmaster hook
+ * snd_ctl_sync_vmaster - Sync the vmaster slaves and hook
* @kcontrol: vmaster kctl element
+ * @hook_only: sync only the hook
*
- * Call the hook function to synchronize with the current value of the given
- * vmaster element. NOP when NULL is passed to @kcontrol or the hook doesn't
- * exist.
+ * Forcibly call the put callback of each slave and call the hook function
+ * to synchronize with the current value of the given vmaster element.
+ * NOP when NULL is passed to @kcontrol.
*/
-void snd_ctl_sync_vmaster_hook(struct snd_kcontrol *kcontrol)
+void snd_ctl_sync_vmaster(struct snd_kcontrol *kcontrol, bool hook_only)
{
struct link_master *master;
+ bool first_init = false;
+
if (!kcontrol)
return;
master = snd_kcontrol_chip(kcontrol);
- if (master->hook)
+ if (!hook_only) {
+ int err = master_init(master);
+ if (err < 0)
+ return;
+ first_init = err;
+ err = sync_slaves(master, master->val, master->val);
+ if (err < 0)
+ return;
+ }
+
+ if (master->hook && !first_init)
master->hook(master->hook_private_data, master->val);
}
-EXPORT_SYMBOL_GPL(snd_ctl_sync_vmaster_hook);
+EXPORT_SYMBOL_GPL(snd_ctl_sync_vmaster);
diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c
index 6f78de9..f758992 100644
--- a/sound/drivers/aloop.c
+++ b/sound/drivers/aloop.c
@@ -1183,7 +1183,6 @@ static int loopback_probe(struct platform_device *devptr)
static int loopback_remove(struct platform_device *devptr)
{
snd_card_free(platform_get_drvdata(devptr));
- platform_set_drvdata(devptr, NULL);
return 0;
}
diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c
index fd798f7..11048cc 100644
--- a/sound/drivers/dummy.c
+++ b/sound/drivers/dummy.c
@@ -1129,7 +1129,6 @@ static int snd_dummy_probe(struct platform_device *devptr)
static int snd_dummy_remove(struct platform_device *devptr)
{
snd_card_free(platform_get_drvdata(devptr));
- platform_set_drvdata(devptr, NULL);
return 0;
}
diff --git a/sound/drivers/ml403-ac97cr.c b/sound/drivers/ml403-ac97cr.c
index 8125a7e..95ea4a1 100644
--- a/sound/drivers/ml403-ac97cr.c
+++ b/sound/drivers/ml403-ac97cr.c
@@ -1325,7 +1325,6 @@ static int snd_ml403_ac97cr_probe(struct platform_device *pfdev)
static int snd_ml403_ac97cr_remove(struct platform_device *pfdev)
{
snd_card_free(platform_get_drvdata(pfdev));
- platform_set_drvdata(pfdev, NULL);
return 0;
}
diff --git a/sound/drivers/mpu401/mpu401.c b/sound/drivers/mpu401/mpu401.c
index da1a29b..90a3a7b 100644
--- a/sound/drivers/mpu401/mpu401.c
+++ b/sound/drivers/mpu401/mpu401.c
@@ -129,7 +129,6 @@ static int snd_mpu401_probe(struct platform_device *devptr)
static int snd_mpu401_remove(struct platform_device *devptr)
{
snd_card_free(platform_get_drvdata(devptr));
- platform_set_drvdata(devptr, NULL);
return 0;
}
diff --git a/sound/drivers/mtpav.c b/sound/drivers/mtpav.c
index 9f1815b..e5ec7eb 100644
--- a/sound/drivers/mtpav.c
+++ b/sound/drivers/mtpav.c
@@ -749,7 +749,6 @@ static int snd_mtpav_probe(struct platform_device *dev)
static int snd_mtpav_remove(struct platform_device *devptr)
{
snd_card_free(platform_get_drvdata(devptr));
- platform_set_drvdata(devptr, NULL);
return 0;
}
diff --git a/sound/drivers/pcsp/pcsp.c b/sound/drivers/pcsp/pcsp.c
index 7a5fdb9..1c19cd7 100644
--- a/sound/drivers/pcsp/pcsp.c
+++ b/sound/drivers/pcsp/pcsp.c
@@ -189,7 +189,6 @@ static int pcsp_remove(struct platform_device *dev)
struct snd_pcsp *chip = platform_get_drvdata(dev);
alsa_card_pcsp_exit(chip);
pcspkr_input_remove(chip->input_dev);
- platform_set_drvdata(dev, NULL);
return 0;
}
diff --git a/sound/drivers/serial-u16550.c b/sound/drivers/serial-u16550.c
index 7425dd8..e0bf5e7 100644
--- a/sound/drivers/serial-u16550.c
+++ b/sound/drivers/serial-u16550.c
@@ -985,7 +985,6 @@ static int snd_serial_probe(struct platform_device *devptr)
static int snd_serial_remove(struct platform_device *devptr)
{
snd_card_free(platform_get_drvdata(devptr));
- platform_set_drvdata(devptr, NULL);
return 0;
}
diff --git a/sound/drivers/virmidi.c b/sound/drivers/virmidi.c
index cc4be88..ace3879 100644
--- a/sound/drivers/virmidi.c
+++ b/sound/drivers/virmidi.c
@@ -132,7 +132,6 @@ static int snd_virmidi_probe(struct platform_device *devptr)
static int snd_virmidi_remove(struct platform_device *devptr)
{
snd_card_free(platform_get_drvdata(devptr));
- platform_set_drvdata(devptr, NULL);
return 0;
}
diff --git a/sound/drivers/vx/vx_core.c b/sound/drivers/vx/vx_core.c
index c39961c..8359689 100644
--- a/sound/drivers/vx/vx_core.c
+++ b/sound/drivers/vx/vx_core.c
@@ -205,7 +205,7 @@ static int vx_read_status(struct vx_core *chip, struct vx_rmh *rmh)
if (size < 1)
return 0;
- if (snd_BUG_ON(size > SIZE_MAX_STATUS))
+ if (snd_BUG_ON(size >= SIZE_MAX_STATUS))
return -EINVAL;
for (i = 1; i <= size; i++) {
diff --git a/sound/firewire/amdtp.h b/sound/firewire/amdtp.h
index b680c5e..f6103d6 100644
--- a/sound/firewire/amdtp.h
+++ b/sound/firewire/amdtp.h
@@ -3,7 +3,6 @@
#include <linux/interrupt.h>
#include <linux/mutex.h>
-#include <linux/spinlock.h>
#include "packets-buffer.h"
/**
diff --git a/sound/firewire/isight.c b/sound/firewire/isight.c
index d428ffe..58a5afe 100644
--- a/sound/firewire/isight.c
+++ b/sound/firewire/isight.c
@@ -626,9 +626,9 @@ static u64 get_unit_base(struct fw_unit *unit)
return 0;
}
-static int isight_probe(struct device *unit_dev)
+static int isight_probe(struct fw_unit *unit,
+ const struct ieee1394_device_id *id)
{
- struct fw_unit *unit = fw_unit(unit_dev);
struct fw_device *fw_dev = fw_parent_device(unit);
struct snd_card *card;
struct isight *isight;
@@ -637,7 +637,7 @@ static int isight_probe(struct device *unit_dev)
err = snd_card_create(-1, NULL, THIS_MODULE, sizeof(*isight), &card);
if (err < 0)
return err;
- snd_card_set_dev(card, unit_dev);
+ snd_card_set_dev(card, &unit->device);
isight = card->private_data;
isight->card = card;
@@ -674,7 +674,7 @@ static int isight_probe(struct device *unit_dev)
if (err < 0)
goto error;
- dev_set_drvdata(unit_dev, isight);
+ dev_set_drvdata(&unit->device, isight);
return 0;
@@ -686,23 +686,6 @@ error:
return err;
}
-static int isight_remove(struct device *dev)
-{
- struct isight *isight = dev_get_drvdata(dev);
-
- isight_pcm_abort(isight);
-
- snd_card_disconnect(isight->card);
-
- mutex_lock(&isight->mutex);
- isight_stop_streaming(isight);
- mutex_unlock(&isight->mutex);
-
- snd_card_free_when_closed(isight->card);
-
- return 0;
-}
-
static void isight_bus_reset(struct fw_unit *unit)
{
struct isight *isight = dev_get_drvdata(&unit->device);
@@ -716,6 +699,21 @@ static void isight_bus_reset(struct fw_unit *unit)
}
}
+static void isight_remove(struct fw_unit *unit)
+{
+ struct isight *isight = dev_get_drvdata(&unit->device);
+
+ isight_pcm_abort(isight);
+
+ snd_card_disconnect(isight->card);
+
+ mutex_lock(&isight->mutex);
+ isight_stop_streaming(isight);
+ mutex_unlock(&isight->mutex);
+
+ snd_card_free_when_closed(isight->card);
+}
+
static const struct ieee1394_device_id isight_id_table[] = {
{
.match_flags = IEEE1394_MATCH_SPECIFIER_ID |
@@ -732,10 +730,10 @@ static struct fw_driver isight_driver = {
.owner = THIS_MODULE,
.name = KBUILD_MODNAME,
.bus = &fw_bus_type,
- .probe = isight_probe,
- .remove = isight_remove,
},
+ .probe = isight_probe,
.update = isight_bus_reset,
+ .remove = isight_remove,
.id_table = isight_id_table,
};
diff --git a/sound/firewire/scs1x.c b/sound/firewire/scs1x.c
index 844a555..505fc81 100644
--- a/sound/firewire/scs1x.c
+++ b/sound/firewire/scs1x.c
@@ -384,9 +384,8 @@ static void scs_card_free(struct snd_card *card)
kfree(scs->buffer);
}
-static int scs_probe(struct device *unit_dev)
+static int scs_probe(struct fw_unit *unit, const struct ieee1394_device_id *id)
{
- struct fw_unit *unit = fw_unit(unit_dev);
struct fw_device *fw_dev = fw_parent_device(unit);
struct snd_card *card;
struct scs *scs;
@@ -395,7 +394,7 @@ static int scs_probe(struct device *unit_dev)
err = snd_card_create(-16, NULL, THIS_MODULE, sizeof(*scs), &card);
if (err < 0)
return err;
- snd_card_set_dev(card, unit_dev);
+ snd_card_set_dev(card, &unit->device);
scs = card->private_data;
scs->card = card;
@@ -405,8 +404,10 @@ static int scs_probe(struct device *unit_dev)
scs->output_idle = true;
scs->buffer = kmalloc(HSS1394_MAX_PACKET_SIZE, GFP_KERNEL);
- if (!scs->buffer)
+ if (!scs->buffer) {
+ err = -ENOMEM;
goto err_card;
+ }
scs->hss_handler.length = HSS1394_MAX_PACKET_SIZE;
scs->hss_handler.address_callback = handle_hss;
@@ -440,7 +441,7 @@ static int scs_probe(struct device *unit_dev)
if (err < 0)
goto err_card;
- dev_set_drvdata(unit_dev, scs);
+ dev_set_drvdata(&unit->device, scs);
return 0;
@@ -451,9 +452,20 @@ err_card:
return err;
}
-static int scs_remove(struct device *dev)
+static void scs_update(struct fw_unit *unit)
{
- struct scs *scs = dev_get_drvdata(dev);
+ struct scs *scs = dev_get_drvdata(&unit->device);
+ __be64 data;
+
+ data = cpu_to_be64(((u64)HSS1394_TAG_CHANGE_ADDRESS << 56) |
+ scs->hss_handler.offset);
+ snd_fw_transaction(scs->unit, TCODE_WRITE_BLOCK_REQUEST,
+ HSS1394_ADDRESS, &data, 8);
+}
+
+static void scs_remove(struct fw_unit *unit)
+{
+ struct scs *scs = dev_get_drvdata(&unit->device);
snd_card_disconnect(scs->card);
@@ -465,19 +477,6 @@ static int scs_remove(struct device *dev)
tasklet_kill(&scs->tasklet);
snd_card_free_when_closed(scs->card);
-
- return 0;
-}
-
-static void scs_update(struct fw_unit *unit)
-{
- struct scs *scs = dev_get_drvdata(&unit->device);
- __be64 data;
-
- data = cpu_to_be64(((u64)HSS1394_TAG_CHANGE_ADDRESS << 56) |
- scs->hss_handler.offset);
- snd_fw_transaction(scs->unit, TCODE_WRITE_BLOCK_REQUEST,
- HSS1394_ADDRESS, &data, 8);
}
static const struct ieee1394_device_id scs_id_table[] = {
@@ -506,10 +505,10 @@ static struct fw_driver scs_driver = {
.owner = THIS_MODULE,
.name = KBUILD_MODNAME,
.bus = &fw_bus_type,
- .probe = scs_probe,
- .remove = scs_remove,
},
+ .probe = scs_probe,
.update = scs_update,
+ .remove = scs_remove,
.id_table = scs_id_table,
};
diff --git a/sound/firewire/speakers.c b/sound/firewire/speakers.c
index d684655..2c63865 100644
--- a/sound/firewire/speakers.c
+++ b/sound/firewire/speakers.c
@@ -663,45 +663,9 @@ static void fwspk_card_free(struct snd_card *card)
mutex_destroy(&fwspk->mutex);
}
-static const struct device_info *fwspk_detect(struct fw_device *dev)
+static int fwspk_probe(struct fw_unit *unit,
+ const struct ieee1394_device_id *id)
{
- static const struct device_info griffin_firewave = {
- .driver_name = "FireWave",
- .short_name = "FireWave",
- .long_name = "Griffin FireWave Surround",
- .pcm_constraints = firewave_constraints,
- .mixer_channels = 6,
- .mute_fb_id = 0x01,
- .volume_fb_id = 0x02,
- };
- static const struct device_info lacie_speakers = {
- .driver_name = "FWSpeakers",
- .short_name = "FireWire Speakers",
- .long_name = "LaCie FireWire Speakers",
- .pcm_constraints = lacie_speakers_constraints,
- .mixer_channels = 1,
- .mute_fb_id = 0x01,
- .volume_fb_id = 0x01,
- };
- struct fw_csr_iterator i;
- int key, value;
-
- fw_csr_iterator_init(&i, dev->config_rom);
- while (fw_csr_iterator_next(&i, &key, &value))
- if (key == CSR_VENDOR)
- switch (value) {
- case VENDOR_GRIFFIN:
- return &griffin_firewave;
- case VENDOR_LACIE:
- return &lacie_speakers;
- }
-
- return NULL;
-}
-
-static int fwspk_probe(struct device *unit_dev)
-{
- struct fw_unit *unit = fw_unit(unit_dev);
struct fw_device *fw_dev = fw_parent_device(unit);
struct snd_card *card;
struct fwspk *fwspk;
@@ -711,17 +675,13 @@ static int fwspk_probe(struct device *unit_dev)
err = snd_card_create(-1, NULL, THIS_MODULE, sizeof(*fwspk), &card);
if (err < 0)
return err;
- snd_card_set_dev(card, unit_dev);
+ snd_card_set_dev(card, &unit->device);
fwspk = card->private_data;
fwspk->card = card;
mutex_init(&fwspk->mutex);
fwspk->unit = fw_unit_get(unit);
- fwspk->device_info = fwspk_detect(fw_dev);
- if (!fwspk->device_info) {
- err = -ENODEV;
- goto err_unit;
- }
+ fwspk->device_info = (const struct device_info *)id->driver_data;
err = cmp_connection_init(&fwspk->connection, unit, 0);
if (err < 0)
@@ -756,7 +716,7 @@ static int fwspk_probe(struct device *unit_dev)
if (err < 0)
goto error;
- dev_set_drvdata(unit_dev, fwspk);
+ dev_set_drvdata(&unit->device, fwspk);
return 0;
@@ -770,22 +730,6 @@ error:
return err;
}
-static int fwspk_remove(struct device *dev)
-{
- struct fwspk *fwspk = dev_get_drvdata(dev);
-
- amdtp_out_stream_pcm_abort(&fwspk->stream);
- snd_card_disconnect(fwspk->card);
-
- mutex_lock(&fwspk->mutex);
- fwspk_stop_stream(fwspk);
- mutex_unlock(&fwspk->mutex);
-
- snd_card_free_when_closed(fwspk->card);
-
- return 0;
-}
-
static void fwspk_bus_reset(struct fw_unit *unit)
{
struct fwspk *fwspk = dev_get_drvdata(&unit->device);
@@ -803,6 +747,40 @@ static void fwspk_bus_reset(struct fw_unit *unit)
amdtp_out_stream_update(&fwspk->stream);
}
+static void fwspk_remove(struct fw_unit *unit)
+{
+ struct fwspk *fwspk = dev_get_drvdata(&unit->device);
+
+ amdtp_out_stream_pcm_abort(&fwspk->stream);
+ snd_card_disconnect(fwspk->card);
+
+ mutex_lock(&fwspk->mutex);
+ fwspk_stop_stream(fwspk);
+ mutex_unlock(&fwspk->mutex);
+
+ snd_card_free_when_closed(fwspk->card);
+}
+
+static const struct device_info griffin_firewave = {
+ .driver_name = "FireWave",
+ .short_name = "FireWave",
+ .long_name = "Griffin FireWave Surround",
+ .pcm_constraints = firewave_constraints,
+ .mixer_channels = 6,
+ .mute_fb_id = 0x01,
+ .volume_fb_id = 0x02,
+};
+
+static const struct device_info lacie_speakers = {
+ .driver_name = "FWSpeakers",
+ .short_name = "FireWire Speakers",
+ .long_name = "LaCie FireWire Speakers",
+ .pcm_constraints = lacie_speakers_constraints,
+ .mixer_channels = 1,
+ .mute_fb_id = 0x01,
+ .volume_fb_id = 0x01,
+};
+
static const struct ieee1394_device_id fwspk_id_table[] = {
{
.match_flags = IEEE1394_MATCH_VENDOR_ID |
@@ -813,6 +791,7 @@ static const struct ieee1394_device_id fwspk_id_table[] = {
.model_id = 0x00f970,
.specifier_id = SPECIFIER_1394TA,
.version = VERSION_AVC,
+ .driver_data = (kernel_ulong_t)&griffin_firewave,
},
{
.match_flags = IEEE1394_MATCH_VENDOR_ID |
@@ -823,6 +802,7 @@ static const struct ieee1394_device_id fwspk_id_table[] = {
.model_id = 0x00f970,
.specifier_id = SPECIFIER_1394TA,
.version = VERSION_AVC,
+ .driver_data = (kernel_ulong_t)&lacie_speakers,
},
{ }
};
@@ -833,10 +813,10 @@ static struct fw_driver fwspk_driver = {
.owner = THIS_MODULE,
.name = KBUILD_MODNAME,
.bus = &fw_bus_type,
- .probe = fwspk_probe,
- .remove = fwspk_remove,
},
+ .probe = fwspk_probe,
.update = fwspk_bus_reset,
+ .remove = fwspk_remove,
.id_table = fwspk_id_table,
};
diff --git a/sound/i2c/other/ak4xxx-adda.c b/sound/i2c/other/ak4xxx-adda.c
index cef813d..ed726d1 100644
--- a/sound/i2c/other/ak4xxx-adda.c
+++ b/sound/i2c/other/ak4xxx-adda.c
@@ -571,7 +571,7 @@ static int ak4xxx_capture_source_info(struct snd_kcontrol *kcontrol,
struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
int mixer_ch = AK_GET_SHIFT(kcontrol->private_value);
const char **input_names;
- int num_names, idx;
+ unsigned int num_names, idx;
num_names = ak4xxx_capture_num_inputs(ak, mixer_ch);
if (!num_names)
diff --git a/sound/isa/ad1848/ad1848.c b/sound/isa/ad1848/ad1848.c
index c214ecf..e3f455bd 100644
--- a/sound/isa/ad1848/ad1848.c
+++ b/sound/isa/ad1848/ad1848.c
@@ -135,7 +135,6 @@ out: snd_card_free(card);
static int snd_ad1848_remove(struct device *dev, unsigned int n)
{
snd_card_free(dev_get_drvdata(dev));
- dev_set_drvdata(dev, NULL);
return 0;
}
diff --git a/sound/isa/adlib.c b/sound/isa/adlib.c
index d265455..3565921 100644
--- a/sound/isa/adlib.c
+++ b/sound/isa/adlib.c
@@ -101,7 +101,6 @@ out: snd_card_free(card);
static int snd_adlib_remove(struct device *dev, unsigned int n)
{
snd_card_free(dev_get_drvdata(dev));
- dev_set_drvdata(dev, NULL);
return 0;
}
diff --git a/sound/isa/cmi8328.c b/sound/isa/cmi8328.c
index a7369fe..f84f073 100644
--- a/sound/isa/cmi8328.c
+++ b/sound/isa/cmi8328.c
@@ -418,7 +418,6 @@ static int snd_cmi8328_remove(struct device *pdev, unsigned int dev)
snd_cmi8328_cfg_write(cmi->port, CFG2, 0);
snd_cmi8328_cfg_write(cmi->port, CFG3, 0);
snd_card_free(card);
- dev_set_drvdata(pdev, NULL);
return 0;
}
diff --git a/sound/isa/cmi8330.c b/sound/isa/cmi8330.c
index c707c52..270b965 100644
--- a/sound/isa/cmi8330.c
+++ b/sound/isa/cmi8330.c
@@ -651,7 +651,6 @@ static int snd_cmi8330_isa_remove(struct device *devptr,
unsigned int dev)
{
snd_card_free(dev_get_drvdata(devptr));
- dev_set_drvdata(devptr, NULL);
return 0;
}
diff --git a/sound/isa/cs423x/cs4231.c b/sound/isa/cs423x/cs4231.c
index aa7a5d8..ba9a74e 100644
--- a/sound/isa/cs423x/cs4231.c
+++ b/sound/isa/cs423x/cs4231.c
@@ -151,7 +151,6 @@ out: snd_card_free(card);
static int snd_cs4231_remove(struct device *dev, unsigned int n)
{
snd_card_free(dev_get_drvdata(dev));
- dev_set_drvdata(dev, NULL);
return 0;
}
diff --git a/sound/isa/cs423x/cs4236.c b/sound/isa/cs423x/cs4236.c
index 252e9fb..69614ac 100644
--- a/sound/isa/cs423x/cs4236.c
+++ b/sound/isa/cs423x/cs4236.c
@@ -504,7 +504,6 @@ static int snd_cs423x_isa_remove(struct device *pdev,
unsigned int dev)
{
snd_card_free(dev_get_drvdata(pdev));
- dev_set_drvdata(pdev, NULL);
return 0;
}
@@ -600,7 +599,6 @@ static int snd_cs423x_pnpbios_detect(struct pnp_dev *pdev,
static void snd_cs423x_pnp_remove(struct pnp_dev *pdev)
{
snd_card_free(pnp_get_drvdata(pdev));
- pnp_set_drvdata(pdev, NULL);
}
#ifdef CONFIG_PM
diff --git a/sound/isa/es1688/es1688.c b/sound/isa/es1688/es1688.c
index 102874a..cdcfb57 100644
--- a/sound/isa/es1688/es1688.c
+++ b/sound/isa/es1688/es1688.c
@@ -213,7 +213,6 @@ out:
static int snd_es1688_isa_remove(struct device *dev, unsigned int n)
{
snd_card_free(dev_get_drvdata(dev));
- dev_set_drvdata(dev, NULL);
return 0;
}
diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c
index 24380ef..12978b8 100644
--- a/sound/isa/es18xx.c
+++ b/sound/isa/es18xx.c
@@ -2235,7 +2235,6 @@ static int snd_es18xx_isa_remove(struct device *devptr,
unsigned int dev)
{
snd_card_free(dev_get_drvdata(devptr));
- dev_set_drvdata(devptr, NULL);
return 0;
}
@@ -2305,7 +2304,6 @@ static int snd_audiodrive_pnp_detect(struct pnp_dev *pdev,
static void snd_audiodrive_pnp_remove(struct pnp_dev *pdev)
{
snd_card_free(pnp_get_drvdata(pdev));
- pnp_set_drvdata(pdev, NULL);
}
#ifdef CONFIG_PM
diff --git a/sound/isa/galaxy/galaxy.c b/sound/isa/galaxy/galaxy.c
index 672184e..81244e7 100644
--- a/sound/isa/galaxy/galaxy.c
+++ b/sound/isa/galaxy/galaxy.c
@@ -623,7 +623,6 @@ error:
static int snd_galaxy_remove(struct device *dev, unsigned int n)
{
snd_card_free(dev_get_drvdata(dev));
- dev_set_drvdata(dev, NULL);
return 0;
}
diff --git a/sound/isa/gus/gusclassic.c b/sound/isa/gus/gusclassic.c
index 16bca4e..1adc1b9 100644
--- a/sound/isa/gus/gusclassic.c
+++ b/sound/isa/gus/gusclassic.c
@@ -215,7 +215,6 @@ out: snd_card_free(card);
static int snd_gusclassic_remove(struct device *dev, unsigned int n)
{
snd_card_free(dev_get_drvdata(dev));
- dev_set_drvdata(dev, NULL);
return 0;
}
diff --git a/sound/isa/gus/gusextreme.c b/sound/isa/gus/gusextreme.c
index 0b9c242..38e1e32 100644
--- a/sound/isa/gus/gusextreme.c
+++ b/sound/isa/gus/gusextreme.c
@@ -344,7 +344,6 @@ out: snd_card_free(card);
static int snd_gusextreme_remove(struct device *dev, unsigned int n)
{
snd_card_free(dev_get_drvdata(dev));
- dev_set_drvdata(dev, NULL);
return 0;
}
diff --git a/sound/isa/gus/gusmax.c b/sound/isa/gus/gusmax.c
index c309a5d..652d5d8 100644
--- a/sound/isa/gus/gusmax.c
+++ b/sound/isa/gus/gusmax.c
@@ -357,7 +357,6 @@ static int snd_gusmax_probe(struct device *pdev, unsigned int dev)
static int snd_gusmax_remove(struct device *devptr, unsigned int dev)
{
snd_card_free(dev_get_drvdata(devptr));
- dev_set_drvdata(devptr, NULL);
return 0;
}
diff --git a/sound/isa/gus/interwave.c b/sound/isa/gus/interwave.c
index 78bc574..9942691 100644
--- a/sound/isa/gus/interwave.c
+++ b/sound/isa/gus/interwave.c
@@ -849,7 +849,6 @@ static int snd_interwave_isa_probe(struct device *pdev,
static int snd_interwave_isa_remove(struct device *devptr, unsigned int dev)
{
snd_card_free(dev_get_drvdata(devptr));
- dev_set_drvdata(devptr, NULL);
return 0;
}
diff --git a/sound/isa/msnd/msnd_pinnacle.c b/sound/isa/msnd/msnd_pinnacle.c
index ddabb40..81aeb93 100644
--- a/sound/isa/msnd/msnd_pinnacle.c
+++ b/sound/isa/msnd/msnd_pinnacle.c
@@ -1064,7 +1064,6 @@ cfg_error:
static int snd_msnd_isa_remove(struct device *pdev, unsigned int dev)
{
snd_msnd_unload(dev_get_drvdata(pdev));
- dev_set_drvdata(pdev, NULL);
return 0;
}
diff --git a/sound/isa/opl3sa2.c b/sound/isa/opl3sa2.c
index 075777a..cc01c41 100644
--- a/sound/isa/opl3sa2.c
+++ b/sound/isa/opl3sa2.c
@@ -757,7 +757,6 @@ static int snd_opl3sa2_pnp_detect(struct pnp_dev *pdev,
static void snd_opl3sa2_pnp_remove(struct pnp_dev *pdev)
{
snd_card_free(pnp_get_drvdata(pdev));
- pnp_set_drvdata(pdev, NULL);
}
#ifdef CONFIG_PM
@@ -900,7 +899,6 @@ static int snd_opl3sa2_isa_remove(struct device *devptr,
unsigned int dev)
{
snd_card_free(dev_get_drvdata(devptr));
- dev_set_drvdata(devptr, NULL);
return 0;
}
diff --git a/sound/isa/opti9xx/miro.c b/sound/isa/opti9xx/miro.c
index c3da1df..619753d 100644
--- a/sound/isa/opti9xx/miro.c
+++ b/sound/isa/opti9xx/miro.c
@@ -1495,7 +1495,6 @@ static int snd_miro_isa_remove(struct device *devptr,
unsigned int dev)
{
snd_card_free(dev_get_drvdata(devptr));
- dev_set_drvdata(devptr, NULL);
return 0;
}
diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c
index b41ed86..103b333 100644
--- a/sound/isa/opti9xx/opti92x-ad1848.c
+++ b/sound/isa/opti9xx/opti92x-ad1848.c
@@ -1035,7 +1035,6 @@ static int snd_opti9xx_isa_remove(struct device *devptr,
unsigned int dev)
{
snd_card_free(dev_get_drvdata(devptr));
- dev_set_drvdata(devptr, NULL);
return 0;
}
diff --git a/sound/isa/sb/jazz16.c b/sound/isa/sb/jazz16.c
index 4961da4..356a630 100644
--- a/sound/isa/sb/jazz16.c
+++ b/sound/isa/sb/jazz16.c
@@ -345,7 +345,6 @@ static int snd_jazz16_remove(struct device *devptr, unsigned int dev)
{
struct snd_card *card = dev_get_drvdata(devptr);
- dev_set_drvdata(devptr, NULL);
snd_card_free(card);
return 0;
}
diff --git a/sound/isa/sb/sb16.c b/sound/isa/sb/sb16.c
index 50dbec4..a413099 100644
--- a/sound/isa/sb/sb16.c
+++ b/sound/isa/sb/sb16.c
@@ -566,7 +566,6 @@ static int snd_sb16_isa_probe(struct device *pdev, unsigned int dev)
static int snd_sb16_isa_remove(struct device *pdev, unsigned int dev)
{
snd_card_free(dev_get_drvdata(pdev));
- dev_set_drvdata(pdev, NULL);
return 0;
}
diff --git a/sound/isa/sb/sb8.c b/sound/isa/sb/sb8.c
index 237d964..a806ae9 100644
--- a/sound/isa/sb/sb8.c
+++ b/sound/isa/sb/sb8.c
@@ -208,7 +208,6 @@ static int snd_sb8_probe(struct device *pdev, unsigned int dev)
static int snd_sb8_remove(struct device *pdev, unsigned int dev)
{
snd_card_free(dev_get_drvdata(pdev));
- dev_set_drvdata(pdev, NULL);
return 0;
}
diff --git a/sound/isa/sc6000.c b/sound/isa/sc6000.c
index 5376ebf..09d481b 100644
--- a/sound/isa/sc6000.c
+++ b/sound/isa/sc6000.c
@@ -698,7 +698,6 @@ static int snd_sc6000_remove(struct device *devptr, unsigned int dev)
release_region(port[dev], 0x10);
release_region(mss_port[dev], 4);
- dev_set_drvdata(devptr, NULL);
snd_card_free(card);
return 0;
}
diff --git a/sound/isa/sscape.c b/sound/isa/sscape.c
index 42a0097..57b3389 100644
--- a/sound/isa/sscape.c
+++ b/sound/isa/sscape.c
@@ -1200,7 +1200,6 @@ _release_card:
static int snd_sscape_remove(struct device *devptr, unsigned int dev)
{
snd_card_free(dev_get_drvdata(devptr));
- dev_set_drvdata(devptr, NULL);
return 0;
}
diff --git a/sound/isa/wavefront/wavefront.c b/sound/isa/wavefront/wavefront.c
index fe5dd98..82dd769 100644
--- a/sound/isa/wavefront/wavefront.c
+++ b/sound/isa/wavefront/wavefront.c
@@ -581,7 +581,6 @@ static int snd_wavefront_isa_remove(struct device *devptr,
unsigned int dev)
{
snd_card_free(dev_get_drvdata(devptr));
- dev_set_drvdata(devptr, NULL);
return 0;
}
diff --git a/sound/oss/kahlua.c b/sound/oss/kahlua.c
index 2a44cc1..12be1fb 100644
--- a/sound/oss/kahlua.c
+++ b/sound/oss/kahlua.c
@@ -178,7 +178,6 @@ static int probe_one(struct pci_dev *pdev, const struct pci_device_id *ent)
return 0;
err_out_free:
- pci_set_drvdata(pdev, NULL);
kfree(hw_config);
return 1;
}
@@ -187,7 +186,6 @@ static void remove_one(struct pci_dev *pdev)
{
struct address_info *hw_config = pci_get_drvdata(pdev);
sb_dsp_unload(hw_config, 0);
- pci_set_drvdata(pdev, NULL);
kfree(hw_config);
}
diff --git a/sound/parisc/harmony.c b/sound/parisc/harmony.c
index 0e66ba4..67f56a2 100644
--- a/sound/parisc/harmony.c
+++ b/sound/parisc/harmony.c
@@ -902,8 +902,6 @@ snd_harmony_free(struct snd_harmony *h)
if (h->iobase)
iounmap(h->iobase);
- parisc_set_drvdata(h->dev, NULL);
-
kfree(h);
return 0;
}
@@ -1016,7 +1014,6 @@ static int
snd_harmony_remove(struct parisc_device *padev)
{
snd_card_free(parisc_get_drvdata(padev));
- parisc_set_drvdata(padev, NULL);
return 0;
}
diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c
index d37c683..445ca48 100644
--- a/sound/pci/ac97/ac97_codec.c
+++ b/sound/pci/ac97/ac97_codec.c
@@ -1296,7 +1296,7 @@ static int snd_ac97_cmix_new_stereo(struct snd_card *card, const char *pfx,
struct snd_ac97 *ac97)
{
int err;
- char name[44];
+ char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
unsigned char lo_max, hi_max;
if (! snd_ac97_valid_reg(ac97, reg))
diff --git a/sound/pci/ad1889.c b/sound/pci/ad1889.c
index ad8a311..d2b9d61 100644
--- a/sound/pci/ad1889.c
+++ b/sound/pci/ad1889.c
@@ -1046,7 +1046,6 @@ static void
snd_ad1889_remove(struct pci_dev *pci)
{
snd_card_free(pci_get_drvdata(pci));
- pci_set_drvdata(pci, NULL);
}
static DEFINE_PCI_DEVICE_TABLE(snd_ad1889_ids) = {
diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c
index 53754f5..3dfa12b 100644
--- a/sound/pci/ali5451/ali5451.c
+++ b/sound/pci/ali5451/ali5451.c
@@ -2298,7 +2298,6 @@ static int snd_ali_probe(struct pci_dev *pci,
static void snd_ali_remove(struct pci_dev *pci)
{
snd_card_free(pci_get_drvdata(pci));
- pci_set_drvdata(pci, NULL);
}
static struct pci_driver ali5451_driver = {
diff --git a/sound/pci/als300.c b/sound/pci/als300.c
index 864c431..591efb6 100644
--- a/sound/pci/als300.c
+++ b/sound/pci/als300.c
@@ -282,7 +282,6 @@ static void snd_als300_remove(struct pci_dev *pci)
{
snd_als300_dbgcallenter();
snd_card_free(pci_get_drvdata(pci));
- pci_set_drvdata(pci, NULL);
snd_als300_dbgcallleave();
}
diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c
index 61efda2..ffc821b 100644
--- a/sound/pci/als4000.c
+++ b/sound/pci/als4000.c
@@ -984,7 +984,6 @@ out:
static void snd_card_als4000_remove(struct pci_dev *pci)
{
snd_card_free(pci_get_drvdata(pci));
- pci_set_drvdata(pci, NULL);
}
#ifdef CONFIG_PM_SLEEP
diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c
index fbc1720..185d54a 100644
--- a/sound/pci/asihpi/asihpi.c
+++ b/sound/pci/asihpi/asihpi.c
@@ -1278,7 +1278,7 @@ struct hpi_control {
u16 dst_node_type;
u16 dst_node_index;
u16 band;
- char name[44]; /* copied to snd_ctl_elem_id.name[44]; */
+ char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; /* copied to snd_ctl_elem_id.name[44]; */
};
static const char * const asihpi_tuner_band_names[] = {
diff --git a/sound/pci/asihpi/hpioctl.c b/sound/pci/asihpi/hpioctl.c
index ef5019f..7f02720 100644
--- a/sound/pci/asihpi/hpioctl.c
+++ b/sound/pci/asihpi/hpioctl.c
@@ -445,7 +445,6 @@ void asihpi_adapter_remove(struct pci_dev *pci_dev)
if (pa->p_buffer)
vfree(pa->p_buffer);
- pci_set_drvdata(pci_dev, NULL);
if (1)
dev_info(&pci_dev->dev,
"remove %04x:%04x,%04x:%04x,%04x, HPI index %d\n",
diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c
index 6e78c67..fe4c61b 100644
--- a/sound/pci/atiixp.c
+++ b/sound/pci/atiixp.c
@@ -1714,7 +1714,6 @@ static int snd_atiixp_probe(struct pci_dev *pci,
static void snd_atiixp_remove(struct pci_dev *pci)
{
snd_card_free(pci_get_drvdata(pci));
- pci_set_drvdata(pci, NULL);
}
static struct pci_driver atiixp_driver = {
diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c
index d0bec7b..cf29b9a 100644
--- a/sound/pci/atiixp_modem.c
+++ b/sound/pci/atiixp_modem.c
@@ -1334,7 +1334,6 @@ static int snd_atiixp_probe(struct pci_dev *pci,
static void snd_atiixp_remove(struct pci_dev *pci)
{
snd_card_free(pci_get_drvdata(pci));
- pci_set_drvdata(pci, NULL);
}
static struct pci_driver atiixp_modem_driver = {
diff --git a/sound/pci/au88x0/au88x0.c b/sound/pci/au88x0/au88x0.c
index b157e1f..7059dd6 100644
--- a/sound/pci/au88x0/au88x0.c
+++ b/sound/pci/au88x0/au88x0.c
@@ -371,7 +371,6 @@ snd_vortex_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
static void snd_vortex_remove(struct pci_dev *pci)
{
snd_card_free(pci_get_drvdata(pci));
- pci_set_drvdata(pci, NULL);
}
// pci_driver definition
diff --git a/sound/pci/aw2/aw2-alsa.c b/sound/pci/aw2/aw2-alsa.c
index 08e9a47..2925220 100644
--- a/sound/pci/aw2/aw2-alsa.c
+++ b/sound/pci/aw2/aw2-alsa.c
@@ -392,7 +392,6 @@ static int snd_aw2_probe(struct pci_dev *pci,
static void snd_aw2_remove(struct pci_dev *pci)
{
snd_card_free(pci_get_drvdata(pci));
- pci_set_drvdata(pci, NULL);
}
/* open callback */
diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c
index 1204a0f..c8e1216 100644
--- a/sound/pci/azt3328.c
+++ b/sound/pci/azt3328.c
@@ -2725,7 +2725,6 @@ snd_azf3328_remove(struct pci_dev *pci)
{
snd_azf3328_dbgcallenter();
snd_card_free(pci_get_drvdata(pci));
- pci_set_drvdata(pci, NULL);
snd_azf3328_dbgcallleave();
}
diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c
index 9febe55..1880203 100644
--- a/sound/pci/bt87x.c
+++ b/sound/pci/bt87x.c
@@ -953,7 +953,6 @@ _error:
static void snd_bt87x_remove(struct pci_dev *pci)
{
snd_card_free(pci_get_drvdata(pci));
- pci_set_drvdata(pci, NULL);
}
/* default entries for all Bt87x cards - it's not exported */
diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c
index 1610a57..f4db558 100644
--- a/sound/pci/ca0106/ca0106_main.c
+++ b/sound/pci/ca0106/ca0106_main.c
@@ -1896,7 +1896,6 @@ static int snd_ca0106_probe(struct pci_dev *pci,
static void snd_ca0106_remove(struct pci_dev *pci)
{
snd_card_free(pci_get_drvdata(pci));
- pci_set_drvdata(pci, NULL);
}
#ifdef CONFIG_PM_SLEEP
diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c
index c617435..2755ec5 100644
--- a/sound/pci/cmipci.c
+++ b/sound/pci/cmipci.c
@@ -3317,7 +3317,6 @@ static int snd_cmipci_probe(struct pci_dev *pci,
static void snd_cmipci_remove(struct pci_dev *pci)
{
snd_card_free(pci_get_drvdata(pci));
- pci_set_drvdata(pci, NULL);
}
diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c
index 6a86950..1dc793e 100644
--- a/sound/pci/cs4281.c
+++ b/sound/pci/cs4281.c
@@ -1312,7 +1312,7 @@ static int snd_cs4281_free(struct cs4281 *chip)
/* Sound System Power Management - Turn Everything OFF */
snd_cs4281_pokeBA0(chip, BA0_SSPM, 0);
/* PCI interface - D3 state */
- pci_set_power_state(chip->pci, 3);
+ pci_set_power_state(chip->pci, PCI_D3hot);
if (chip->irq >= 0)
free_irq(chip->irq, chip);
@@ -1971,7 +1971,6 @@ static int snd_cs4281_probe(struct pci_dev *pci,
static void snd_cs4281_remove(struct pci_dev *pci)
{
snd_card_free(pci_get_drvdata(pci));
- pci_set_drvdata(pci, NULL);
}
/*
diff --git a/sound/pci/cs46xx/cs46xx.c b/sound/pci/cs46xx/cs46xx.c
index 6b0d8b5..b034983 100644
--- a/sound/pci/cs46xx/cs46xx.c
+++ b/sound/pci/cs46xx/cs46xx.c
@@ -158,7 +158,6 @@ static int snd_card_cs46xx_probe(struct pci_dev *pci,
static void snd_card_cs46xx_remove(struct pci_dev *pci)
{
snd_card_free(pci_get_drvdata(pci));
- pci_set_drvdata(pci, NULL);
}
static struct pci_driver cs46xx_driver = {
diff --git a/sound/pci/cs5530.c b/sound/pci/cs5530.c
index dace827..c6b82c8 100644
--- a/sound/pci/cs5530.c
+++ b/sound/pci/cs5530.c
@@ -91,7 +91,6 @@ static int snd_cs5530_dev_free(struct snd_device *device)
static void snd_cs5530_remove(struct pci_dev *pci)
{
snd_card_free(pci_get_drvdata(pci));
- pci_set_drvdata(pci, NULL);
}
static u8 snd_cs5530_mixer_read(unsigned long io, u8 reg)
diff --git a/sound/pci/cs5535audio/cs5535audio.c b/sound/pci/cs5535audio/cs5535audio.c
index 7e4b13e..902bebd 100644
--- a/sound/pci/cs5535audio/cs5535audio.c
+++ b/sound/pci/cs5535audio/cs5535audio.c
@@ -391,7 +391,6 @@ static void snd_cs5535audio_remove(struct pci_dev *pci)
{
olpc_quirks_cleanup();
snd_card_free(pci_get_drvdata(pci));
- pci_set_drvdata(pci, NULL);
}
static struct pci_driver cs5535audio_driver = {
diff --git a/sound/pci/ctxfi/xfi.c b/sound/pci/ctxfi/xfi.c
index d01ffcb..d464ad2 100644
--- a/sound/pci/ctxfi/xfi.c
+++ b/sound/pci/ctxfi/xfi.c
@@ -122,7 +122,6 @@ error:
static void ct_card_remove(struct pci_dev *pci)
{
snd_card_free(pci_get_drvdata(pci));
- pci_set_drvdata(pci, NULL);
}
#ifdef CONFIG_PM_SLEEP
diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c
index 760cbff..05cfe55 100644
--- a/sound/pci/echoaudio/echoaudio.c
+++ b/sound/pci/echoaudio/echoaudio.c
@@ -2323,7 +2323,6 @@ static void snd_echo_remove(struct pci_dev *pci)
chip = pci_get_drvdata(pci);
if (chip)
snd_card_free(chip->card);
- pci_set_drvdata(pci, NULL);
}
diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c
index 8c5010f..9e1bd0c 100644
--- a/sound/pci/emu10k1/emu10k1.c
+++ b/sound/pci/emu10k1/emu10k1.c
@@ -202,7 +202,6 @@ static int snd_card_emu10k1_probe(struct pci_dev *pci,
static void snd_card_emu10k1_remove(struct pci_dev *pci)
{
snd_card_free(pci_get_drvdata(pci));
- pci_set_drvdata(pci, NULL);
}
diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c
index cdff11d..56ad9d6 100644
--- a/sound/pci/emu10k1/emu10k1x.c
+++ b/sound/pci/emu10k1/emu10k1x.c
@@ -1623,7 +1623,6 @@ static int snd_emu10k1x_probe(struct pci_dev *pci,
static void snd_emu10k1x_remove(struct pci_dev *pci)
{
snd_card_free(pci_get_drvdata(pci));
- pci_set_drvdata(pci, NULL);
}
// PCI IDs
diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c
index db2dc83..ca8929b 100644
--- a/sound/pci/ens1370.c
+++ b/sound/pci/ens1370.c
@@ -1939,7 +1939,7 @@ static int snd_ensoniq_free(struct ensoniq *ensoniq)
#endif
if (ensoniq->irq >= 0)
synchronize_irq(ensoniq->irq);
- pci_set_power_state(ensoniq->pci, 3);
+ pci_set_power_state(ensoniq->pci, PCI_D3hot);
__hw_end:
#ifdef CHIP1370
if (ensoniq->dma_bug.area)
@@ -2497,7 +2497,6 @@ static int snd_audiopci_probe(struct pci_dev *pci,
static void snd_audiopci_remove(struct pci_dev *pci)
{
snd_card_free(pci_get_drvdata(pci));
- pci_set_drvdata(pci, NULL);
}
static struct pci_driver ens137x_driver = {
diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c
index 8423403..9213fb3 100644
--- a/sound/pci/es1938.c
+++ b/sound/pci/es1938.c
@@ -1881,7 +1881,6 @@ static int snd_es1938_probe(struct pci_dev *pci,
static void snd_es1938_remove(struct pci_dev *pci)
{
snd_card_free(pci_get_drvdata(pci));
- pci_set_drvdata(pci, NULL);
}
static struct pci_driver es1938_driver = {
diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c
index a1f32b5..5e2ec96 100644
--- a/sound/pci/es1968.c
+++ b/sound/pci/es1968.c
@@ -564,6 +564,7 @@ struct es1968 {
#ifdef CONFIG_SND_ES1968_RADIO
struct v4l2_device v4l2_dev;
struct snd_tea575x tea;
+ unsigned int tea575x_tuner;
#endif
};
@@ -2557,37 +2558,47 @@ static int snd_es1968_input_register(struct es1968 *chip)
bits 1=unmask write to given bit */
#define IO_DIR 8 /* direction register offset from GPIO_DATA
bits 0/1=read/write direction */
-/* mask bits for GPIO lines */
-#define STR_DATA 0x0040 /* GPIO6 */
-#define STR_CLK 0x0080 /* GPIO7 */
-#define STR_WREN 0x0100 /* GPIO8 */
-#define STR_MOST 0x0200 /* GPIO9 */
+
+/* GPIO to TEA575x maps */
+struct snd_es1968_tea575x_gpio {
+ u8 data, clk, wren, most;
+ char *name;
+};
+
+static struct snd_es1968_tea575x_gpio snd_es1968_tea575x_gpios[] = {
+ { .data = 6, .clk = 7, .wren = 8, .most = 9, .name = "SF64-PCE2" },
+ { .data = 7, .clk = 8, .wren = 6, .most = 10, .name = "M56VAP" },
+};
+
+#define get_tea575x_gpio(chip) \
+ (&snd_es1968_tea575x_gpios[(chip)->tea575x_tuner])
+
static void snd_es1968_tea575x_set_pins(struct snd_tea575x *tea, u8 pins)
{
struct es1968 *chip = tea->private_data;
- unsigned long io = chip->io_port + GPIO_DATA;
+ struct snd_es1968_tea575x_gpio gpio = *get_tea575x_gpio(chip);
u16 val = 0;
- val |= (pins & TEA575X_DATA) ? STR_DATA : 0;
- val |= (pins & TEA575X_CLK) ? STR_CLK : 0;
- val |= (pins & TEA575X_WREN) ? STR_WREN : 0;
+ val |= (pins & TEA575X_DATA) ? (1 << gpio.data) : 0;
+ val |= (pins & TEA575X_CLK) ? (1 << gpio.clk) : 0;
+ val |= (pins & TEA575X_WREN) ? (1 << gpio.wren) : 0;
- outw(val, io);
+ outw(val, chip->io_port + GPIO_DATA);
}
static u8 snd_es1968_tea575x_get_pins(struct snd_tea575x *tea)
{
struct es1968 *chip = tea->private_data;
- unsigned long io = chip->io_port + GPIO_DATA;
- u16 val = inw(io);
- u8 ret;
+ struct snd_es1968_tea575x_gpio gpio = *get_tea575x_gpio(chip);
+ u16 val = inw(chip->io_port + GPIO_DATA);
+ u8 ret = 0;
- ret = 0;
- if (val & STR_DATA)
+ if (val & (1 << gpio.data))
ret |= TEA575X_DATA;
- if (val & STR_MOST)
+ if (val & (1 << gpio.most))
ret |= TEA575X_MOST;
+
return ret;
}
@@ -2596,13 +2607,18 @@ static void snd_es1968_tea575x_set_direction(struct snd_tea575x *tea, bool outpu
struct es1968 *chip = tea->private_data;
unsigned long io = chip->io_port + GPIO_DATA;
u16 odir = inw(io + IO_DIR);
+ struct snd_es1968_tea575x_gpio gpio = *get_tea575x_gpio(chip);
if (output) {
- outw(~(STR_DATA | STR_CLK | STR_WREN), io + IO_MASK);
- outw(odir | STR_DATA | STR_CLK | STR_WREN, io + IO_DIR);
+ outw(~((1 << gpio.data) | (1 << gpio.clk) | (1 << gpio.wren)),
+ io + IO_MASK);
+ outw(odir | (1 << gpio.data) | (1 << gpio.clk) | (1 << gpio.wren),
+ io + IO_DIR);
} else {
- outw(~(STR_CLK | STR_WREN | STR_DATA | STR_MOST), io + IO_MASK);
- outw((odir & ~(STR_DATA | STR_MOST)) | STR_CLK | STR_WREN, io + IO_DIR);
+ outw(~((1 << gpio.clk) | (1 << gpio.wren) | (1 << gpio.data) | (1 << gpio.most)),
+ io + IO_MASK);
+ outw((odir & ~((1 << gpio.data) | (1 << gpio.most)))
+ | (1 << gpio.clk) | (1 << gpio.wren), io + IO_DIR);
}
}
@@ -2772,6 +2788,9 @@ static int snd_es1968_create(struct snd_card *card,
snd_card_set_dev(card, &pci->dev);
#ifdef CONFIG_SND_ES1968_RADIO
+ /* don't play with GPIOs on laptops */
+ if (chip->pci->subsystem_vendor != 0x125d)
+ goto no_radio;
err = v4l2_device_register(&pci->dev, &chip->v4l2_dev);
if (err < 0) {
snd_es1968_free(chip);
@@ -2781,10 +2800,18 @@ static int snd_es1968_create(struct snd_card *card,
chip->tea.private_data = chip;
chip->tea.radio_nr = radio_nr;
chip->tea.ops = &snd_es1968_tea_ops;
- strlcpy(chip->tea.card, "SF64-PCE2", sizeof(chip->tea.card));
sprintf(chip->tea.bus_info, "PCI:%s", pci_name(pci));
- if (!snd_tea575x_init(&chip->tea, THIS_MODULE))
- printk(KERN_INFO "es1968: detected TEA575x radio\n");
+ for (i = 0; i < ARRAY_SIZE(snd_es1968_tea575x_gpios); i++) {
+ chip->tea575x_tuner = i;
+ if (!snd_tea575x_init(&chip->tea, THIS_MODULE)) {
+ snd_printk(KERN_INFO "es1968: detected TEA575x radio type %s\n",
+ get_tea575x_gpio(chip)->name);
+ strlcpy(chip->tea.card, get_tea575x_gpio(chip)->name,
+ sizeof(chip->tea.card));
+ break;
+ }
+ }
+no_radio:
#endif
*chip_ret = chip;
@@ -2909,7 +2936,6 @@ static int snd_es1968_probe(struct pci_dev *pci,
static void snd_es1968_remove(struct pci_dev *pci)
{
snd_card_free(pci_get_drvdata(pci));
- pci_set_drvdata(pci, NULL);
}
static struct pci_driver es1968_driver = {
diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c
index 4f07fda..706c5b6 100644
--- a/sound/pci/fm801.c
+++ b/sound/pci/fm801.c
@@ -1370,7 +1370,6 @@ static int snd_card_fm801_probe(struct pci_dev *pci,
static void snd_card_fm801_remove(struct pci_dev *pci)
{
snd_card_free(pci_get_drvdata(pci));
- pci_set_drvdata(pci, NULL);
}
#ifdef CONFIG_PM_SLEEP
diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig
index 80a7d44..59c5e9c 100644
--- a/sound/pci/hda/Kconfig
+++ b/sound/pci/hda/Kconfig
@@ -140,7 +140,6 @@ config SND_HDA_CODEC_VIA
config SND_HDA_CODEC_HDMI
bool "Build HDMI/DisplayPort HD-audio codec support"
- select SND_DYNAMIC_MINORS
default y
help
Say Y here to include HDMI and DisplayPort HD-audio codec
@@ -152,6 +151,16 @@ config SND_HDA_CODEC_HDMI
snd-hda-codec-hdmi.
This module is automatically loaded at probing.
+config SND_HDA_I915
+ bool "Build Display HD-audio controller/codec power well support for i915 cards"
+ depends on DRM_I915
+ help
+ Say Y here to include full HDMI and DisplayPort HD-audio controller/codec
+ power-well support for Intel Haswell graphics cards based on the i915 driver.
+
+ Note that this option must be enabled for Intel Haswell C+ stepping machines, otherwise
+ the GPU audio controller/codecs will not be initialized or damaged when exit from S3 mode.
+
config SND_HDA_CODEC_CIRRUS
bool "Build Cirrus Logic codec support"
default y
diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile
index 24a2514..c091438 100644
--- a/sound/pci/hda/Makefile
+++ b/sound/pci/hda/Makefile
@@ -1,4 +1,6 @@
snd-hda-intel-objs := hda_intel.o
+# for haswell power well
+snd-hda-intel-$(CONFIG_SND_HDA_I915) += hda_i915.o
snd-hda-codec-y := hda_codec.o hda_jack.o hda_auto_parser.o
snd-hda-codec-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 55108b5..8a005f0 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -185,20 +185,19 @@ EXPORT_SYMBOL_HDA(snd_hda_get_jack_type);
* Compose a 32bit command word to be sent to the HD-audio controller
*/
static inline unsigned int
-make_codec_cmd(struct hda_codec *codec, hda_nid_t nid, int direct,
+make_codec_cmd(struct hda_codec *codec, hda_nid_t nid, int flags,
unsigned int verb, unsigned int parm)
{
u32 val;
- if ((codec->addr & ~0xf) || (direct & ~1) || (nid & ~0x7f) ||
+ if ((codec->addr & ~0xf) || (nid & ~0x7f) ||
(verb & ~0xfff) || (parm & ~0xffff)) {
- printk(KERN_ERR "hda-codec: out of range cmd %x:%x:%x:%x:%x\n",
- codec->addr, direct, nid, verb, parm);
+ printk(KERN_ERR "hda-codec: out of range cmd %x:%x:%x:%x\n",
+ codec->addr, nid, verb, parm);
return ~0;
}
val = (u32)codec->addr << 28;
- val |= (u32)direct << 27;
val |= (u32)nid << 20;
val |= verb << 8;
val |= parm;
@@ -209,7 +208,7 @@ make_codec_cmd(struct hda_codec *codec, hda_nid_t nid, int direct,
* Send and receive a verb
*/
static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd,
- unsigned int *res)
+ int flags, unsigned int *res)
{
struct hda_bus *bus = codec->bus;
int err;
@@ -222,6 +221,8 @@ static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd,
again:
snd_hda_power_up(codec);
mutex_lock(&bus->cmd_mutex);
+ if (flags & HDA_RW_NO_RESPONSE_FALLBACK)
+ bus->no_response_fallback = 1;
for (;;) {
trace_hda_send_cmd(codec, cmd);
err = bus->ops.command(bus, cmd);
@@ -234,6 +235,7 @@ static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd,
*res = bus->ops.get_response(bus, codec->addr);
trace_hda_get_response(codec, *res);
}
+ bus->no_response_fallback = 0;
mutex_unlock(&bus->cmd_mutex);
snd_hda_power_down(codec);
if (!codec_in_pm(codec) && res && *res == -1 && bus->rirb_error) {
@@ -255,7 +257,7 @@ static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd,
* snd_hda_codec_read - send a command and get the response
* @codec: the HDA codec
* @nid: NID to send the command
- * @direct: direct flag
+ * @flags: optional bit flags
* @verb: the verb to send
* @parm: the parameter for the verb
*
@@ -264,12 +266,12 @@ static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd,
* Returns the obtained response value, or -1 for an error.
*/
unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid,
- int direct,
+ int flags,
unsigned int verb, unsigned int parm)
{
- unsigned cmd = make_codec_cmd(codec, nid, direct, verb, parm);
+ unsigned cmd = make_codec_cmd(codec, nid, flags, verb, parm);
unsigned int res;
- if (codec_exec_verb(codec, cmd, &res))
+ if (codec_exec_verb(codec, cmd, flags, &res))
return -1;
return res;
}
@@ -279,7 +281,7 @@ EXPORT_SYMBOL_HDA(snd_hda_codec_read);
* snd_hda_codec_write - send a single command without waiting for response
* @codec: the HDA codec
* @nid: NID to send the command
- * @direct: direct flag
+ * @flags: optional bit flags
* @verb: the verb to send
* @parm: the parameter for the verb
*
@@ -287,12 +289,12 @@ EXPORT_SYMBOL_HDA(snd_hda_codec_read);
*
* Returns 0 if successful, or a negative error code.
*/
-int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int direct,
- unsigned int verb, unsigned int parm)
+int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int flags,
+ unsigned int verb, unsigned int parm)
{
- unsigned int cmd = make_codec_cmd(codec, nid, direct, verb, parm);
+ unsigned int cmd = make_codec_cmd(codec, nid, flags, verb, parm);
unsigned int res;
- return codec_exec_verb(codec, cmd,
+ return codec_exec_verb(codec, cmd, flags,
codec->bus->sync_write ? &res : NULL);
}
EXPORT_SYMBOL_HDA(snd_hda_codec_write);
@@ -2523,7 +2525,7 @@ int snd_hda_codec_reset(struct hda_codec *codec)
flush_workqueue(bus->workq);
#endif
snd_hda_ctls_clear(codec);
- /* relase PCMs */
+ /* release PCMs */
for (i = 0; i < codec->num_pcms; i++) {
if (codec->pcm_info[i].pcm) {
snd_device_free(card, codec->pcm_info[i].pcm);
@@ -3582,7 +3584,7 @@ EXPORT_SYMBOL_HDA(snd_hda_create_spdif_in_ctls);
* snd_hda_codec_write_cache - send a single command with caching
* @codec: the HDA codec
* @nid: NID to send the command
- * @direct: direct flag
+ * @flags: optional bit flags
* @verb: the verb to send
* @parm: the parameter for the verb
*
@@ -3591,7 +3593,7 @@ EXPORT_SYMBOL_HDA(snd_hda_create_spdif_in_ctls);
* Returns 0 if successful, or a negative error code.
*/
int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid,
- int direct, unsigned int verb, unsigned int parm)
+ int flags, unsigned int verb, unsigned int parm)
{
int err;
struct hda_cache_head *c;
@@ -3600,7 +3602,7 @@ int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid,
cache_only = codec->cached_write;
if (!cache_only) {
- err = snd_hda_codec_write(codec, nid, direct, verb, parm);
+ err = snd_hda_codec_write(codec, nid, flags, verb, parm);
if (err < 0)
return err;
}
@@ -3624,7 +3626,7 @@ EXPORT_SYMBOL_HDA(snd_hda_codec_write_cache);
* snd_hda_codec_update_cache - check cache and write the cmd only when needed
* @codec: the HDA codec
* @nid: NID to send the command
- * @direct: direct flag
+ * @flags: optional bit flags
* @verb: the verb to send
* @parm: the parameter for the verb
*
@@ -3635,7 +3637,7 @@ EXPORT_SYMBOL_HDA(snd_hda_codec_write_cache);
* Returns 0 if successful, or a negative error code.
*/
int snd_hda_codec_update_cache(struct hda_codec *codec, hda_nid_t nid,
- int direct, unsigned int verb, unsigned int parm)
+ int flags, unsigned int verb, unsigned int parm)
{
struct hda_cache_head *c;
u32 key;
@@ -3651,7 +3653,7 @@ int snd_hda_codec_update_cache(struct hda_codec *codec, hda_nid_t nid,
return 0;
}
mutex_unlock(&codec->bus->cmd_mutex);
- return snd_hda_codec_write_cache(codec, nid, direct, verb, parm);
+ return snd_hda_codec_write_cache(codec, nid, flags, verb, parm);
}
EXPORT_SYMBOL_HDA(snd_hda_codec_update_cache);
@@ -3806,11 +3808,13 @@ static unsigned int hda_set_power_state(struct hda_codec *codec,
hda_nid_t fg = codec->afg ? codec->afg : codec->mfg;
int count;
unsigned int state;
+ int flags = 0;
/* this delay seems necessary to avoid click noise at power-down */
if (power_state == AC_PWRST_D3) {
/* transition time less than 10ms for power down */
msleep(codec->epss ? 10 : 100);
+ flags = HDA_RW_NO_RESPONSE_FALLBACK;
}
/* repeat power states setting at most 10 times*/
@@ -3819,7 +3823,7 @@ static unsigned int hda_set_power_state(struct hda_codec *codec,
codec->patch_ops.set_power_state(codec, fg,
power_state);
else {
- snd_hda_codec_read(codec, fg, 0,
+ snd_hda_codec_read(codec, fg, flags,
AC_VERB_SET_POWER_STATE,
power_state);
snd_hda_codec_set_power_to_all(codec, fg, power_state);
@@ -4461,12 +4465,13 @@ const char *snd_hda_pcm_type_name[HDA_PCM_NTYPES] = {
/*
* get the empty PCM device number to assign
- *
- * note the max device number is limited by HDA_MAX_PCMS, currently 10
*/
-static int get_empty_pcm_device(struct hda_bus *bus, int type)
+static int get_empty_pcm_device(struct hda_bus *bus, unsigned int type)
{
/* audio device indices; not linear to keep compatibility */
+ /* assigned to static slots up to dev#10; if more needed, assign
+ * the later slot dynamically (when CONFIG_SND_DYNAMIC_MINORS=y)
+ */
static int audio_idx[HDA_PCM_NTYPES][5] = {
[HDA_PCM_TYPE_AUDIO] = { 0, 2, 4, 5, -1 },
[HDA_PCM_TYPE_SPDIF] = { 1, -1 },
@@ -4480,18 +4485,28 @@ static int get_empty_pcm_device(struct hda_bus *bus, int type)
return -EINVAL;
}
- for (i = 0; audio_idx[type][i] >= 0 ; i++)
+ for (i = 0; audio_idx[type][i] >= 0; i++) {
+#ifndef CONFIG_SND_DYNAMIC_MINORS
+ if (audio_idx[type][i] >= 8)
+ break;
+#endif
if (!test_and_set_bit(audio_idx[type][i], bus->pcm_dev_bits))
return audio_idx[type][i];
+ }
+#ifdef CONFIG_SND_DYNAMIC_MINORS
/* non-fixed slots starting from 10 */
for (i = 10; i < 32; i++) {
if (!test_and_set_bit(i, bus->pcm_dev_bits))
return i;
}
+#endif
snd_printk(KERN_WARNING "Too many %s devices\n",
snd_hda_pcm_type_name[type]);
+#ifndef CONFIG_SND_DYNAMIC_MINORS
+ snd_printk(KERN_WARNING "Consider building the kernel with CONFIG_SND_DYNAMIC_MINORS=y\n");
+#endif
return -EAGAIN;
}
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index c93f902..701c2e0 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -679,6 +679,7 @@ struct hda_bus {
unsigned int response_reset:1; /* controller was reset */
unsigned int in_reset:1; /* during reset operation */
unsigned int power_keep_link_on:1; /* don't power off HDA link */
+ unsigned int no_response_fallback:1; /* don't fallback at RIRB error */
int primary_dig_out_type; /* primary digital out PCM type */
};
@@ -930,6 +931,8 @@ enum {
HDA_INPUT, HDA_OUTPUT
};
+/* snd_hda_codec_read/write optional flags */
+#define HDA_RW_NO_RESPONSE_FALLBACK (1 << 0)
/*
* constructors
@@ -945,9 +948,9 @@ int snd_hda_codec_update_widgets(struct hda_codec *codec);
* low level functions
*/
unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid,
- int direct,
+ int flags,
unsigned int verb, unsigned int parm);
-int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int direct,
+int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int flags,
unsigned int verb, unsigned int parm);
#define snd_hda_param_read(codec, nid, param) \
snd_hda_codec_read(codec, nid, 0, AC_VERB_PARAMETERS, param)
@@ -986,11 +989,11 @@ int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex);
/* cached write */
int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid,
- int direct, unsigned int verb, unsigned int parm);
+ int flags, unsigned int verb, unsigned int parm);
void snd_hda_sequence_write_cache(struct hda_codec *codec,
const struct hda_verb *seq);
int snd_hda_codec_update_cache(struct hda_codec *codec, hda_nid_t nid,
- int direct, unsigned int verb, unsigned int parm);
+ int flags, unsigned int verb, unsigned int parm);
void snd_hda_codec_resume_cache(struct hda_codec *codec);
/* both for cmd & amp caches */
void snd_hda_codec_flush_cache(struct hda_codec *codec);
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
index 4b1524a..8e77cbb 100644
--- a/sound/pci/hda/hda_generic.c
+++ b/sound/pci/hda/hda_generic.c
@@ -133,6 +133,9 @@ static void parse_user_hints(struct hda_codec *codec)
val = snd_hda_get_bool_hint(codec, "line_in_auto_switch");
if (val >= 0)
spec->line_in_auto_switch = !!val;
+ val = snd_hda_get_bool_hint(codec, "auto_mute_via_amp");
+ if (val >= 0)
+ spec->auto_mute_via_amp = !!val;
val = snd_hda_get_bool_hint(codec, "need_dac_fix");
if (val >= 0)
spec->need_dac_fix = !!val;
@@ -808,6 +811,9 @@ static void resume_path_from_idx(struct hda_codec *codec, int path_idx)
* Helper functions for creating mixer ctl elements
*/
+static int hda_gen_mixer_mute_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+
enum {
HDA_CTL_WIDGET_VOL,
HDA_CTL_WIDGET_MUTE,
@@ -815,7 +821,15 @@ enum {
};
static const struct snd_kcontrol_new control_templates[] = {
HDA_CODEC_VOLUME(NULL, 0, 0, 0),
- HDA_CODEC_MUTE(NULL, 0, 0, 0),
+ /* only the put callback is replaced for handling the special mute */
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .subdevice = HDA_SUBDEV_AMP_FLAG,
+ .info = snd_hda_mixer_amp_switch_info,
+ .get = snd_hda_mixer_amp_switch_get,
+ .put = hda_gen_mixer_mute_put, /* replaced */
+ .private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0),
+ },
HDA_BIND_MUTE(NULL, 0, 0, 0),
};
@@ -840,7 +854,7 @@ static int add_control_with_pfx(struct hda_gen_spec *spec, int type,
const char *pfx, const char *dir,
const char *sfx, int cidx, unsigned long val)
{
- char name[32];
+ char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx);
if (!add_control(spec, type, name, cidx, val))
return -ENOMEM;
@@ -922,6 +936,23 @@ static int add_stereo_sw(struct hda_codec *codec, const char *pfx,
return add_sw_ctl(codec, pfx, cidx, chs, path);
}
+/* playback mute control with the software mute bit check */
+static int hda_gen_mixer_mute_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct hda_gen_spec *spec = codec->spec;
+
+ if (spec->auto_mute_via_amp) {
+ hda_nid_t nid = get_amp_nid(kcontrol);
+ bool enabled = !((spec->mute_bits >> nid) & 1);
+ ucontrol->value.integer.value[0] &= enabled;
+ ucontrol->value.integer.value[1] &= enabled;
+ }
+
+ return snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
+}
+
/* any ctl assigned to the path with the given index? */
static bool path_has_mixer(struct hda_codec *codec, int path_idx, int ctl_type)
{
@@ -1900,7 +1931,7 @@ static int create_extra_outs(struct hda_codec *codec, int num_pins,
for (i = 0; i < num_pins; i++) {
const char *name;
- char tmp[44];
+ char tmp[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
int err, idx = 0;
if (num_pins == 2 && i == 1 && !strcmp(pfx, "Speaker"))
@@ -2453,7 +2484,7 @@ static int create_out_jack_modes(struct hda_codec *codec, int num_pins,
}
if (get_out_jack_num_items(codec, pin) > 1) {
struct snd_kcontrol_new *knew;
- char name[44];
+ char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
get_jack_mode_name(codec, pin, name, sizeof(name));
knew = snd_hda_gen_add_kctl(spec, name,
&out_jack_mode_enum);
@@ -2585,7 +2616,7 @@ static int create_in_jack_mode(struct hda_codec *codec, hda_nid_t pin)
{
struct hda_gen_spec *spec = codec->spec;
struct snd_kcontrol_new *knew;
- char name[44];
+ char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
unsigned int defcfg;
if (pin == spec->hp_mic_pin)
@@ -3285,7 +3316,7 @@ static int add_single_cap_ctl(struct hda_codec *codec, const char *label,
bool inv_dmic)
{
struct hda_gen_spec *spec = codec->spec;
- char tmpname[44];
+ char tmpname[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
int type = is_switch ? HDA_CTL_WIDGET_MUTE : HDA_CTL_WIDGET_VOL;
const char *sfx = is_switch ? "Switch" : "Volume";
unsigned int chs = inv_dmic ? 1 : 3;
@@ -3547,7 +3578,7 @@ static int parse_mic_boost(struct hda_codec *codec)
struct nid_path *path;
unsigned int val;
int idx;
- char boost_label[44];
+ char boost_label[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
idx = imux->items[i].index;
if (idx >= imux->num_items)
@@ -3719,6 +3750,16 @@ static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins,
unsigned int val, oldval;
if (!nid)
break;
+
+ if (spec->auto_mute_via_amp) {
+ if (mute)
+ spec->mute_bits |= (1ULL << nid);
+ else
+ spec->mute_bits &= ~(1ULL << nid);
+ set_pin_eapd(codec, nid, !mute);
+ continue;
+ }
+
oldval = snd_hda_codec_get_pin_target(codec, nid);
if (oldval & PIN_IN)
continue; /* no mute for inputs */
@@ -3786,6 +3827,10 @@ static void call_update_outputs(struct hda_codec *codec)
spec->automute_hook(codec);
else
snd_hda_gen_update_outputs(codec);
+
+ /* sync the whole vmaster slaves to reflect the new auto-mute status */
+ if (spec->auto_mute_via_amp && !codec->bus->shutdown)
+ snd_ctl_sync_vmaster(spec->vmaster_mute.sw_kctl, false);
}
/* standard HP-automute helper */
diff --git a/sound/pci/hda/hda_generic.h b/sound/pci/hda/hda_generic.h
index 7620031..e199a85 100644
--- a/sound/pci/hda/hda_generic.h
+++ b/sound/pci/hda/hda_generic.h
@@ -209,6 +209,7 @@ struct hda_gen_spec {
unsigned int master_mute:1; /* master mute over all */
unsigned int keep_vref_in_automute:1; /* Don't clear VREF in automute */
unsigned int line_in_auto_switch:1; /* allow line-in auto switch */
+ unsigned int auto_mute_via_amp:1; /* auto-mute via amp instead of pinctl */
/* parser behavior flags; set before snd_hda_gen_parse_auto_config() */
unsigned int suppress_auto_mute:1; /* suppress input jack auto mute */
@@ -237,6 +238,9 @@ struct hda_gen_spec {
unsigned int have_aamix_ctl:1;
unsigned int hp_mic_jack_modes:1;
+ /* additional mute flags (only effective with auto_mute_via_amp=1) */
+ u64 mute_bits;
+
/* badness tables for output path evaluations */
const struct badness_table *main_out_badness;
const struct badness_table *extra_out_badness;
diff --git a/sound/pci/hda/hda_i915.c b/sound/pci/hda/hda_i915.c
new file mode 100644
index 0000000..76c13d5
--- /dev/null
+++ b/sound/pci/hda/hda_i915.c
@@ -0,0 +1,75 @@
+/*
+ * hda_i915.c - routines for Haswell HDA controller power well support
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <drm/i915_powerwell.h>
+#include "hda_i915.h"
+
+static void (*get_power)(void);
+static void (*put_power)(void);
+
+void hda_display_power(bool enable)
+{
+ if (!get_power || !put_power)
+ return;
+
+ snd_printdd("HDA display power %s \n",
+ enable ? "Enable" : "Disable");
+ if (enable)
+ get_power();
+ else
+ put_power();
+}
+
+int hda_i915_init(void)
+{
+ int err = 0;
+
+ get_power = symbol_request(i915_request_power_well);
+ if (!get_power) {
+ snd_printk(KERN_WARNING "hda-i915: get_power symbol get fail\n");
+ return -ENODEV;
+ }
+
+ put_power = symbol_request(i915_release_power_well);
+ if (!put_power) {
+ symbol_put(i915_request_power_well);
+ get_power = NULL;
+ return -ENODEV;
+ }
+
+ snd_printd("HDA driver get symbol successfully from i915 module\n");
+
+ return err;
+}
+
+int hda_i915_exit(void)
+{
+ if (get_power) {
+ symbol_put(i915_request_power_well);
+ get_power = NULL;
+ }
+ if (put_power) {
+ symbol_put(i915_release_power_well);
+ put_power = NULL;
+ }
+
+ return 0;
+}
diff --git a/sound/pci/hda/hda_i915.h b/sound/pci/hda/hda_i915.h
new file mode 100644
index 0000000..5a63da2
--- /dev/null
+++ b/sound/pci/hda/hda_i915.h
@@ -0,0 +1,35 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#ifndef __SOUND_HDA_I915_H
+#define __SOUND_HDA_I915_H
+
+#ifdef CONFIG_SND_HDA_I915
+void hda_display_power(bool enable);
+int hda_i915_init(void);
+int hda_i915_exit(void);
+#else
+static inline void hda_display_power(bool enable) {}
+static inline int hda_i915_init(void)
+{
+ return -ENODEV;
+}
+static inline int hda_i915_exit(void)
+{
+ return 0;
+}
+#endif
+
+#endif
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index de18722..8860dd52 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -62,6 +62,7 @@
#include <linux/vga_switcheroo.h>
#include <linux/firmware.h>
#include "hda_codec.h"
+#include "hda_i915.h"
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
@@ -541,6 +542,10 @@ struct azx {
/* for pending irqs */
struct work_struct irq_pending_work;
+#ifdef CONFIG_SND_HDA_I915
+ struct work_struct probe_work;
+#endif
+
/* reboot notifier (for mysterious hangup problem at power-down) */
struct notifier_block reboot_notifier;
@@ -594,6 +599,7 @@ enum {
#define AZX_DCAPS_4K_BDLE_BOUNDARY (1 << 23) /* BDLE in 4k boundary */
#define AZX_DCAPS_COUNT_LPIB_DELAY (1 << 25) /* Take LPIB as delay */
#define AZX_DCAPS_PM_RUNTIME (1 << 26) /* runtime PM support */
+#define AZX_DCAPS_I915_POWERWELL (1 << 27) /* HSW i915 power well support */
/* quirks for Intel PCH */
#define AZX_DCAPS_INTEL_PCH_NOPM \
@@ -942,6 +948,9 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus,
}
}
+ if (!bus->no_response_fallback)
+ return -1;
+
if (!chip->polling_mode && chip->poll_count < 2) {
snd_printdd(SFX "%s: azx_get_response timeout, "
"polling the codec once: last cmd=0x%08x\n",
@@ -1117,37 +1126,52 @@ static void azx_load_dsp_cleanup(struct hda_bus *bus,
struct snd_dma_buffer *dmab);
#endif
-/* reset codec link */
-static int azx_reset(struct azx *chip, int full_reset)
+/* enter link reset */
+static void azx_enter_link_reset(struct azx *chip)
{
unsigned long timeout;
- if (!full_reset)
- goto __skip;
-
- /* clear STATESTS */
- azx_writeb(chip, STATESTS, STATESTS_INT_MASK);
-
/* reset controller */
azx_writel(chip, GCTL, azx_readl(chip, GCTL) & ~ICH6_GCTL_RESET);
timeout = jiffies + msecs_to_jiffies(100);
- while (azx_readb(chip, GCTL) &&
+ while ((azx_readb(chip, GCTL) & ICH6_GCTL_RESET) &&
time_before(jiffies, timeout))
usleep_range(500, 1000);
+}
- /* delay for >= 100us for codec PLL to settle per spec
- * Rev 0.9 section 5.5.1
- */
- usleep_range(500, 1000);
+/* exit link reset */
+static void azx_exit_link_reset(struct azx *chip)
+{
+ unsigned long timeout;
- /* Bring controller out of reset */
azx_writeb(chip, GCTL, azx_readb(chip, GCTL) | ICH6_GCTL_RESET);
timeout = jiffies + msecs_to_jiffies(100);
while (!azx_readb(chip, GCTL) &&
time_before(jiffies, timeout))
usleep_range(500, 1000);
+}
+
+/* reset codec link */
+static int azx_reset(struct azx *chip, int full_reset)
+{
+ if (!full_reset)
+ goto __skip;
+
+ /* clear STATESTS */
+ azx_writeb(chip, STATESTS, STATESTS_INT_MASK);
+
+ /* reset controller */
+ azx_enter_link_reset(chip);
+
+ /* delay for >= 100us for codec PLL to settle per spec
+ * Rev 0.9 section 5.5.1
+ */
+ usleep_range(500, 1000);
+
+ /* Bring controller out of reset */
+ azx_exit_link_reset(chip);
/* Brent Chartrand said to wait >= 540us for codecs to initialize */
usleep_range(1000, 1200);
@@ -2891,6 +2915,7 @@ static int azx_suspend(struct device *dev)
if (chip->initialized)
snd_hda_suspend(chip->bus);
azx_stop_chip(chip);
+ azx_enter_link_reset(chip);
if (chip->irq >= 0) {
free_irq(chip->irq, chip);
chip->irq = -1;
@@ -2900,6 +2925,8 @@ static int azx_suspend(struct device *dev)
pci_disable_device(pci);
pci_save_state(pci);
pci_set_power_state(pci, PCI_D3hot);
+ if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
+ hda_display_power(false);
return 0;
}
@@ -2912,6 +2939,8 @@ static int azx_resume(struct device *dev)
if (chip->disabled)
return 0;
+ if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
+ hda_display_power(true);
pci_set_power_state(pci, PCI_D0);
pci_restore_state(pci);
if (pci_enable_device(pci) < 0) {
@@ -2943,7 +2972,10 @@ static int azx_runtime_suspend(struct device *dev)
struct azx *chip = card->private_data;
azx_stop_chip(chip);
+ azx_enter_link_reset(chip);
azx_clear_irq_pending(chip);
+ if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
+ hda_display_power(false);
return 0;
}
@@ -2952,6 +2984,8 @@ static int azx_runtime_resume(struct device *dev)
struct snd_card *card = dev_get_drvdata(dev);
struct azx *chip = card->private_data;
+ if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
+ hda_display_power(true);
azx_init_pci(chip);
azx_init_chip(chip, 1);
return 0;
@@ -3006,7 +3040,6 @@ static void azx_notifier_unregister(struct azx *chip)
unregister_reboot_notifier(&chip->reboot_notifier);
}
-static int azx_first_init(struct azx *chip);
static int azx_probe_continue(struct azx *chip);
#ifdef SUPPORT_VGA_SWITCHEROO
@@ -3033,8 +3066,7 @@ static void azx_vs_set_state(struct pci_dev *pci,
snd_printk(KERN_INFO SFX
"%s: Start delayed initialization\n",
pci_name(chip->pci));
- if (azx_first_init(chip) < 0 ||
- azx_probe_continue(chip) < 0) {
+ if (azx_probe_continue(chip) < 0) {
snd_printk(KERN_ERR SFX
"%s: initialization error\n",
pci_name(chip->pci));
@@ -3120,8 +3152,13 @@ static int register_vga_switcheroo(struct azx *chip)
*/
static int azx_free(struct azx *chip)
{
+ struct pci_dev *pci = chip->pci;
int i;
+ if ((chip->driver_caps & AZX_DCAPS_PM_RUNTIME)
+ && chip->running)
+ pm_runtime_get_noresume(&pci->dev);
+
azx_del_card_list(chip);
azx_notifier_unregister(chip);
@@ -3173,6 +3210,10 @@ static int azx_free(struct azx *chip)
if (chip->fw)
release_firmware(chip->fw);
#endif
+ if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
+ hda_display_power(false);
+ hda_i915_exit();
+ }
kfree(chip);
return 0;
@@ -3398,6 +3439,13 @@ static void azx_check_snoop_available(struct azx *chip)
}
}
+#ifdef CONFIG_SND_HDA_I915
+static void azx_probe_work(struct work_struct *work)
+{
+ azx_probe_continue(container_of(work, struct azx, probe_work));
+}
+#endif
+
/*
* constructor
*/
@@ -3473,7 +3521,13 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci,
return err;
}
+#ifdef CONFIG_SND_HDA_I915
+ /* continue probing in work context as may trigger request module */
+ INIT_WORK(&chip->probe_work, azx_probe_work);
+#endif
+
*rchip = chip;
+
return 0;
}
@@ -3730,11 +3784,6 @@ static int azx_probe(struct pci_dev *pci,
}
probe_now = !chip->disabled;
- if (probe_now) {
- err = azx_first_init(chip);
- if (err < 0)
- goto out_free;
- }
#ifdef CONFIG_SND_HDA_PATCH_LOADER
if (patch[dev] && *patch[dev]) {
@@ -3749,30 +3798,51 @@ static int azx_probe(struct pci_dev *pci,
}
#endif /* CONFIG_SND_HDA_PATCH_LOADER */
+ /* continue probing in work context, avoid request_module deadlock */
+ if (probe_now && (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)) {
+#ifdef CONFIG_SND_HDA_I915
+ probe_now = false;
+ schedule_work(&chip->probe_work);
+#else
+ snd_printk(KERN_ERR SFX "Haswell must build in CONFIG_SND_HDA_I915\n");
+#endif
+ }
+
if (probe_now) {
err = azx_probe_continue(chip);
if (err < 0)
goto out_free;
}
- if (pci_dev_run_wake(pci))
- pm_runtime_put_noidle(&pci->dev);
-
dev++;
complete_all(&chip->probe_wait);
return 0;
out_free:
snd_card_free(card);
- pci_set_drvdata(pci, NULL);
return err;
}
static int azx_probe_continue(struct azx *chip)
{
+ struct pci_dev *pci = chip->pci;
int dev = chip->dev_index;
int err;
+ /* Request power well for Haswell HDA controller and codec */
+ if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
+ err = hda_i915_init();
+ if (err < 0) {
+ snd_printk(KERN_ERR SFX "Error request power-well from i915\n");
+ goto out_free;
+ }
+ hda_display_power(true);
+ }
+
+ err = azx_first_init(chip);
+ if (err < 0)
+ goto out_free;
+
#ifdef CONFIG_SND_HDA_INPUT_BEEP
chip->beep_mode = beep_mode[dev];
#endif
@@ -3817,6 +3887,8 @@ static int azx_probe_continue(struct azx *chip)
power_down_all_codecs(chip);
azx_notifier_register(chip);
azx_add_card_list(chip);
+ if (chip->driver_caps & AZX_DCAPS_PM_RUNTIME)
+ pm_runtime_put_noidle(&pci->dev);
return 0;
@@ -3829,12 +3901,8 @@ static void azx_remove(struct pci_dev *pci)
{
struct snd_card *card = pci_get_drvdata(pci);
- if (pci_dev_run_wake(pci))
- pm_runtime_get_noresume(&pci->dev);
-
if (card)
snd_card_free(card);
- pci_set_drvdata(pci, NULL);
}
/* PCI IDs */
@@ -3864,11 +3932,14 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
.driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
/* Haswell */
{ PCI_DEVICE(0x8086, 0x0a0c),
- .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH },
+ .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH |
+ AZX_DCAPS_I915_POWERWELL },
{ PCI_DEVICE(0x8086, 0x0c0c),
- .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH },
+ .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH |
+ AZX_DCAPS_I915_POWERWELL },
{ PCI_DEVICE(0x8086, 0x0d0c),
- .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH },
+ .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH |
+ AZX_DCAPS_I915_POWERWELL },
/* 5 Series/3400 */
{ PCI_DEVICE(0x8086, 0x3b56),
.driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM },
@@ -3878,6 +3949,9 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
/* Oaktrail */
{ PCI_DEVICE(0x8086, 0x080a),
.driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM },
+ /* BayTrail */
+ { PCI_DEVICE(0x8086, 0x0f04),
+ .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM },
/* ICH */
{ PCI_DEVICE(0x8086, 0x2668),
.driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC |
diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c
index 9e0a952..3fd2973 100644
--- a/sound/pci/hda/hda_jack.c
+++ b/sound/pci/hda/hda_jack.c
@@ -398,7 +398,7 @@ static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid,
const char *base_name)
{
unsigned int def_conf, conn;
- char name[44];
+ char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
int idx, err;
bool phantom_jack;
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index e0bf753..2e7493e 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -562,6 +562,14 @@ static inline unsigned int get_wcaps_channels(u32 wcaps)
return chans;
}
+static inline void snd_hda_override_wcaps(struct hda_codec *codec,
+ hda_nid_t nid, u32 val)
+{
+ if (nid >= codec->start_nid &&
+ nid < codec->start_nid + codec->num_nodes)
+ codec->wcaps[nid - codec->start_nid] = val;
+}
+
u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction);
int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir,
unsigned int caps);
@@ -667,7 +675,7 @@ snd_hda_check_power_state(struct hda_codec *codec, hda_nid_t nid,
if (state & AC_PWRST_ERROR)
return true;
state = (state >> 4) & 0x0f;
- return (state != target_state);
+ return (state == target_state);
}
unsigned int snd_hda_codec_eapd_power_filter(struct hda_codec *codec,
diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c
index 0fee8fa..9760f00 100644
--- a/sound/pci/hda/hda_proc.c
+++ b/sound/pci/hda/hda_proc.c
@@ -504,6 +504,8 @@ static void print_conn_list(struct snd_info_buffer *buffer,
int conn_len)
{
int c, curr = -1;
+ const hda_nid_t *list;
+ int cache_len;
if (conn_len > 1 &&
wid_type != AC_WID_AUD_MIX &&
@@ -521,6 +523,19 @@ static void print_conn_list(struct snd_info_buffer *buffer,
}
snd_iprintf(buffer, "\n");
}
+
+ /* Get Cache connections info */
+ cache_len = snd_hda_get_conn_list(codec, nid, &list);
+ if (cache_len != conn_len
+ || memcmp(list, conn, conn_len)) {
+ snd_iprintf(buffer, " In-driver Connection: %d\n", cache_len);
+ if (cache_len > 0) {
+ snd_iprintf(buffer, " ");
+ for (c = 0; c < cache_len; c++)
+ snd_iprintf(buffer, " 0x%02x", list[c]);
+ snd_iprintf(buffer, "\n");
+ }
+ }
}
static void print_gpio(struct snd_info_buffer *buffer,
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index 977b0d8..d97f0d6 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -2112,6 +2112,9 @@ static void ad_vmaster_eapd_hook(void *private_data, int enabled)
{
struct hda_codec *codec = private_data;
struct ad198x_spec *spec = codec->spec;
+
+ if (!spec->eapd_nid)
+ return;
snd_hda_codec_update_cache(codec, spec->eapd_nid, 0,
AC_VERB_SET_EAPD_BTLENABLE,
enabled ? 0x02 : 0x00);
@@ -3601,13 +3604,16 @@ static void ad1884_fixup_hp_eapd(struct hda_codec *codec,
{
struct ad198x_spec *spec = codec->spec;
- if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+ switch (action) {
+ case HDA_FIXUP_ACT_PRE_PROBE:
+ spec->gen.vmaster_mute.hook = ad_vmaster_eapd_hook;
+ break;
+ case HDA_FIXUP_ACT_PROBE:
if (spec->gen.autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT)
spec->eapd_nid = spec->gen.autocfg.line_out_pins[0];
else
spec->eapd_nid = spec->gen.autocfg.speaker_pins[0];
- if (spec->eapd_nid)
- spec->gen.vmaster_mute.hook = ad_vmaster_eapd_hook;
+ break;
}
}
diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c
index 90ff7a3..6e9876f 100644
--- a/sound/pci/hda/patch_ca0132.c
+++ b/sound/pci/hda/patch_ca0132.c
@@ -139,7 +139,7 @@ enum {
#define DSP_SPEAKER_OUT_LATENCY 7
struct ct_effect {
- char name[44];
+ char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
hda_nid_t nid;
int mid; /*effect module ID*/
int reqs[EFFECT_VALS_MAX_COUNT]; /*effect module request*/
@@ -270,7 +270,7 @@ enum {
};
struct ct_tuning_ctl {
- char name[44];
+ char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
hda_nid_t parent_nid;
hda_nid_t nid;
int mid; /*effect module ID*/
@@ -3103,7 +3103,7 @@ static int add_tuning_control(struct hda_codec *codec,
hda_nid_t pnid, hda_nid_t nid,
const char *name, int dir)
{
- char namestr[44];
+ char namestr[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
int type = dir ? HDA_INPUT : HDA_OUTPUT;
struct snd_kcontrol_new knew =
HDA_CODEC_VOLUME_MONO(namestr, nid, 1, 0, type);
@@ -3935,7 +3935,7 @@ static int ca0132_volume_tlv(struct snd_kcontrol *kcontrol, int op_flag,
static int add_fx_switch(struct hda_codec *codec, hda_nid_t nid,
const char *pfx, int dir)
{
- char namestr[44];
+ char namestr[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
int type = dir ? HDA_INPUT : HDA_OUTPUT;
struct snd_kcontrol_new knew =
CA0132_CODEC_MUTE_MONO(namestr, nid, 1, type);
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index bd8d46c..cccaf9c 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -58,6 +58,7 @@ enum {
CS420X_GPIO_23,
CS420X_MBP101,
CS420X_MBP81,
+ CS420X_MBA42,
CS420X_AUTO,
/* aliases */
CS420X_IMAC27_122 = CS420X_GPIO_23,
@@ -346,6 +347,7 @@ static const struct hda_model_fixup cs420x_models[] = {
{ .id = CS420X_APPLE, .name = "apple" },
{ .id = CS420X_MBP101, .name = "mbp101" },
{ .id = CS420X_MBP81, .name = "mbp81" },
+ { .id = CS420X_MBA42, .name = "mba42" },
{}
};
@@ -361,6 +363,7 @@ static const struct snd_pci_quirk cs420x_fixup_tbl[] = {
SND_PCI_QUIRK(0x106b, 0x1c00, "MacBookPro 8,1", CS420X_MBP81),
SND_PCI_QUIRK(0x106b, 0x2000, "iMac 12,2", CS420X_IMAC27_122),
SND_PCI_QUIRK(0x106b, 0x2800, "MacBookPro 10,1", CS420X_MBP101),
+ SND_PCI_QUIRK(0x106b, 0x5b00, "MacBookAir 4,2", CS420X_MBA42),
SND_PCI_QUIRK_VENDOR(0x106b, "Apple", CS420X_APPLE),
{} /* terminator */
};
@@ -414,6 +417,20 @@ static const struct hda_pintbl mbp101_pincfgs[] = {
{} /* terminator */
};
+static const struct hda_pintbl mba42_pincfgs[] = {
+ { 0x09, 0x012b4030 }, /* HP */
+ { 0x0a, 0x400000f0 },
+ { 0x0b, 0x90100120 }, /* speaker */
+ { 0x0c, 0x400000f0 },
+ { 0x0d, 0x90a00110 }, /* mic */
+ { 0x0e, 0x400000f0 },
+ { 0x0f, 0x400000f0 },
+ { 0x10, 0x400000f0 },
+ { 0x12, 0x400000f0 },
+ { 0x15, 0x400000f0 },
+ {} /* terminator */
+};
+
static void cs420x_fixup_gpio_13(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
@@ -482,6 +499,12 @@ static const struct hda_fixup cs420x_fixups[] = {
.chained = true,
.chain_id = CS420X_GPIO_13,
},
+ [CS420X_MBA42] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = mba42_pincfgs,
+ .chained = true,
+ .chain_id = CS420X_GPIO_13,
+ },
};
static struct cs_spec *cs_alloc_spec(struct hda_codec *codec, int vendor_nid)
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index b314d3e..de00ce1 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -2947,7 +2947,6 @@ static const struct snd_pci_quirk cxt5066_cfg_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400s", CXT5066_THINKPAD),
SND_PCI_QUIRK(0x17aa, 0x21c5, "Thinkpad Edge 13", CXT5066_THINKPAD),
SND_PCI_QUIRK(0x17aa, 0x21c6, "Thinkpad Edge 13", CXT5066_ASUS),
- SND_PCI_QUIRK(0x17aa, 0x21db, "Lenovo X220-tablet", CXT5066_THINKPAD),
SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo U350", CXT5066_ASUS),
SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo G560", CXT5066_ASUS),
{}
@@ -3318,6 +3317,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = {
SND_PCI_QUIRK(0x17aa, 0x21ce, "Lenovo T420", CXT_PINCFG_LENOVO_TP410),
SND_PCI_QUIRK(0x17aa, 0x21cf, "Lenovo T520", CXT_PINCFG_LENOVO_TP410),
SND_PCI_QUIRK(0x17aa, 0x21da, "Lenovo X220", CXT_PINCFG_LENOVO_TP410),
+ SND_PCI_QUIRK(0x17aa, 0x21db, "Lenovo X220-tablet", CXT_PINCFG_LENOVO_TP410),
SND_PCI_QUIRK(0x17aa, 0x3975, "Lenovo U300s", CXT_FIXUP_STEREO_DMIC),
SND_PCI_QUIRK(0x17aa, 0x3977, "Lenovo IdeaPad U310", CXT_FIXUP_STEREO_DMIC),
SND_PCI_QUIRK(0x17aa, 0x397b, "Lenovo S205", CXT_FIXUP_STEREO_DMIC),
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index e12f7a0..540bdef 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -1018,13 +1018,18 @@ static void hdmi_unsol_event(struct hda_codec *codec, unsigned int res)
hdmi_non_intrinsic_event(codec, res);
}
-static void haswell_verify_pin_D0(struct hda_codec *codec, hda_nid_t nid)
+static void haswell_verify_pin_D0(struct hda_codec *codec,
+ hda_nid_t cvt_nid, hda_nid_t nid)
{
int pwr, lamp, ramp;
- pwr = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_POWER_STATE, 0);
- pwr = (pwr & AC_PWRST_ACTUAL) >> AC_PWRST_ACTUAL_SHIFT;
- if (pwr != AC_PWRST_D0) {
+ /* For Haswell, the converter 1/2 may keep in D3 state after bootup,
+ * thus pins could only choose converter 0 for use. Make sure the
+ * converters are in correct power state */
+ if (!snd_hda_check_power_state(codec, cvt_nid, AC_PWRST_D0))
+ snd_hda_codec_write(codec, cvt_nid, 0, AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+
+ if (!snd_hda_check_power_state(codec, nid, AC_PWRST_D0)) {
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE,
AC_PWRST_D0);
msleep(40);
@@ -1068,7 +1073,7 @@ static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid,
int new_pinctl = 0;
if (codec->vendor_id == 0x80862807)
- haswell_verify_pin_D0(codec, pin_nid);
+ haswell_verify_pin_D0(codec, cvt_nid, pin_nid);
if (snd_hda_query_pin_caps(codec, pin_nid) & AC_PINCAP_HBR) {
pinctl = snd_hda_codec_read(codec, pin_nid, 0,
@@ -1101,26 +1106,15 @@ static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid,
return 0;
}
-/*
- * HDA PCM callbacks
- */
-static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
- struct hda_codec *codec,
- struct snd_pcm_substream *substream)
+static int hdmi_choose_cvt(struct hda_codec *codec,
+ int pin_idx, int *cvt_id, int *mux_id)
{
struct hdmi_spec *spec = codec->spec;
- struct snd_pcm_runtime *runtime = substream->runtime;
- int pin_idx, cvt_idx, mux_idx = 0;
struct hdmi_spec_per_pin *per_pin;
- struct hdmi_eld *eld;
struct hdmi_spec_per_cvt *per_cvt = NULL;
+ int cvt_idx, mux_idx = 0;
- /* Validate hinfo */
- pin_idx = hinfo_to_pin_index(spec, hinfo);
- if (snd_BUG_ON(pin_idx < 0))
- return -EINVAL;
per_pin = get_pin(spec, pin_idx);
- eld = &per_pin->sink_eld;
/* Dynamically assign converter to stream */
for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) {
@@ -1138,17 +1132,89 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
continue;
break;
}
+
/* No free converters */
if (cvt_idx == spec->num_cvts)
return -ENODEV;
+ if (cvt_id)
+ *cvt_id = cvt_idx;
+ if (mux_id)
+ *mux_id = mux_idx;
+
+ return 0;
+}
+
+static void haswell_config_cvts(struct hda_codec *codec,
+ int pin_id, int mux_id)
+{
+ struct hdmi_spec *spec = codec->spec;
+ struct hdmi_spec_per_pin *per_pin;
+ int pin_idx, mux_idx;
+ int curr;
+ int err;
+
+ for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+ per_pin = get_pin(spec, pin_idx);
+
+ if (pin_idx == pin_id)
+ continue;
+
+ curr = snd_hda_codec_read(codec, per_pin->pin_nid, 0,
+ AC_VERB_GET_CONNECT_SEL, 0);
+
+ /* Choose another unused converter */
+ if (curr == mux_id) {
+ err = hdmi_choose_cvt(codec, pin_idx, NULL, &mux_idx);
+ if (err < 0)
+ return;
+ snd_printdd("HDMI: choose converter %d for pin %d\n", mux_idx, pin_idx);
+ snd_hda_codec_write_cache(codec, per_pin->pin_nid, 0,
+ AC_VERB_SET_CONNECT_SEL,
+ mux_idx);
+ }
+ }
+}
+
+/*
+ * HDA PCM callbacks
+ */
+static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ struct hdmi_spec *spec = codec->spec;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ int pin_idx, cvt_idx, mux_idx = 0;
+ struct hdmi_spec_per_pin *per_pin;
+ struct hdmi_eld *eld;
+ struct hdmi_spec_per_cvt *per_cvt = NULL;
+ int err;
+
+ /* Validate hinfo */
+ pin_idx = hinfo_to_pin_index(spec, hinfo);
+ if (snd_BUG_ON(pin_idx < 0))
+ return -EINVAL;
+ per_pin = get_pin(spec, pin_idx);
+ eld = &per_pin->sink_eld;
+
+ err = hdmi_choose_cvt(codec, pin_idx, &cvt_idx, &mux_idx);
+ if (err < 0)
+ return err;
+
+ per_cvt = get_cvt(spec, cvt_idx);
/* Claim converter */
per_cvt->assigned = 1;
hinfo->nid = per_cvt->cvt_nid;
- snd_hda_codec_write(codec, per_pin->pin_nid, 0,
+ snd_hda_codec_write_cache(codec, per_pin->pin_nid, 0,
AC_VERB_SET_CONNECT_SEL,
mux_idx);
+
+ /* configure unused pins to choose other converters */
+ if (codec->vendor_id == 0x80862807)
+ haswell_config_cvts(codec, pin_idx, mux_idx);
+
snd_hda_spdif_ctls_assign(codec, pin_idx, per_cvt->cvt_nid);
/* Initially set the converter's capabilities */
@@ -1798,12 +1864,33 @@ static void generic_hdmi_free(struct hda_codec *codec)
kfree(spec);
}
+#ifdef CONFIG_PM
+static int generic_hdmi_resume(struct hda_codec *codec)
+{
+ struct hdmi_spec *spec = codec->spec;
+ int pin_idx;
+
+ generic_hdmi_init(codec);
+ snd_hda_codec_resume_amp(codec);
+ snd_hda_codec_resume_cache(codec);
+
+ for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+ struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
+ hdmi_present_sense(per_pin, 1);
+ }
+ return 0;
+}
+#endif
+
static const struct hda_codec_ops generic_hdmi_patch_ops = {
.init = generic_hdmi_init,
.free = generic_hdmi_free,
.build_pcms = generic_hdmi_build_pcms,
.build_controls = generic_hdmi_build_controls,
.unsol_event = hdmi_unsol_event,
+#ifdef CONFIG_PM
+ .resume = generic_hdmi_resume,
+#endif
};
@@ -1821,7 +1908,6 @@ static void intel_haswell_fixup_connect_list(struct hda_codec *codec,
/* override pins connection list */
snd_printdd("hdmi: haswell: override pin connection 0x%x\n", nid);
- nconns = max(spec->num_cvts, 4);
snd_hda_override_conn_list(codec, nid, spec->num_cvts, spec->cvt_nids);
}
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 02e22b4..8bd2261 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -37,6 +37,9 @@
#include "hda_jack.h"
#include "hda_generic.h"
+/* keep halting ALC5505 DSP, for power saving */
+#define HALT_REALTEK_ALC5505
+
/* unsol event tags */
#define ALC_DCVOL_EVENT 0x08
@@ -115,6 +118,7 @@ struct alc_spec {
int init_amp;
int codec_variant; /* flag for other variants */
+ bool has_alc5505_dsp;
/* for PLL fix */
hda_nid_t pll_nid;
@@ -2580,7 +2584,108 @@ static void alc269_shutup(struct hda_codec *codec)
}
}
+static void alc5505_coef_set(struct hda_codec *codec, unsigned int index_reg,
+ unsigned int val)
+{
+ snd_hda_codec_write(codec, 0x51, 0, AC_VERB_SET_COEF_INDEX, index_reg >> 1);
+ snd_hda_codec_write(codec, 0x51, 0, AC_VERB_SET_PROC_COEF, val & 0xffff); /* LSB */
+ snd_hda_codec_write(codec, 0x51, 0, AC_VERB_SET_PROC_COEF, val >> 16); /* MSB */
+}
+
+static int alc5505_coef_get(struct hda_codec *codec, unsigned int index_reg)
+{
+ unsigned int val;
+
+ snd_hda_codec_write(codec, 0x51, 0, AC_VERB_SET_COEF_INDEX, index_reg >> 1);
+ val = snd_hda_codec_read(codec, 0x51, 0, AC_VERB_GET_PROC_COEF, 0)
+ & 0xffff;
+ val |= snd_hda_codec_read(codec, 0x51, 0, AC_VERB_GET_PROC_COEF, 0)
+ << 16;
+ return val;
+}
+
+static void alc5505_dsp_halt(struct hda_codec *codec)
+{
+ unsigned int val;
+
+ alc5505_coef_set(codec, 0x3000, 0x000c); /* DSP CPU stop */
+ alc5505_coef_set(codec, 0x880c, 0x0008); /* DDR enter self refresh */
+ alc5505_coef_set(codec, 0x61c0, 0x11110080); /* Clock control for PLL and CPU */
+ alc5505_coef_set(codec, 0x6230, 0xfc0d4011); /* Disable Input OP */
+ alc5505_coef_set(codec, 0x61b4, 0x040a2b03); /* Stop PLL2 */
+ alc5505_coef_set(codec, 0x61b0, 0x00005b17); /* Stop PLL1 */
+ alc5505_coef_set(codec, 0x61b8, 0x04133303); /* Stop PLL3 */
+ val = alc5505_coef_get(codec, 0x6220);
+ alc5505_coef_set(codec, 0x6220, (val | 0x3000)); /* switch Ringbuffer clock to DBUS clock */
+}
+
+static void alc5505_dsp_back_from_halt(struct hda_codec *codec)
+{
+ alc5505_coef_set(codec, 0x61b8, 0x04133302);
+ alc5505_coef_set(codec, 0x61b0, 0x00005b16);
+ alc5505_coef_set(codec, 0x61b4, 0x040a2b02);
+ alc5505_coef_set(codec, 0x6230, 0xf80d4011);
+ alc5505_coef_set(codec, 0x6220, 0x2002010f);
+ alc5505_coef_set(codec, 0x880c, 0x00000004);
+}
+
+static void alc5505_dsp_init(struct hda_codec *codec)
+{
+ unsigned int val;
+
+ alc5505_dsp_halt(codec);
+ alc5505_dsp_back_from_halt(codec);
+ alc5505_coef_set(codec, 0x61b0, 0x5b14); /* PLL1 control */
+ alc5505_coef_set(codec, 0x61b0, 0x5b16);
+ alc5505_coef_set(codec, 0x61b4, 0x04132b00); /* PLL2 control */
+ alc5505_coef_set(codec, 0x61b4, 0x04132b02);
+ alc5505_coef_set(codec, 0x61b8, 0x041f3300); /* PLL3 control*/
+ alc5505_coef_set(codec, 0x61b8, 0x041f3302);
+ snd_hda_codec_write(codec, 0x51, 0, AC_VERB_SET_CODEC_RESET, 0); /* Function reset */
+ alc5505_coef_set(codec, 0x61b8, 0x041b3302);
+ alc5505_coef_set(codec, 0x61b8, 0x04173302);
+ alc5505_coef_set(codec, 0x61b8, 0x04163302);
+ alc5505_coef_set(codec, 0x8800, 0x348b328b); /* DRAM control */
+ alc5505_coef_set(codec, 0x8808, 0x00020022); /* DRAM control */
+ alc5505_coef_set(codec, 0x8818, 0x00000400); /* DRAM control */
+
+ val = alc5505_coef_get(codec, 0x6200) >> 16; /* Read revision ID */
+ if (val <= 3)
+ alc5505_coef_set(codec, 0x6220, 0x2002010f); /* I/O PAD Configuration */
+ else
+ alc5505_coef_set(codec, 0x6220, 0x6002018f);
+
+ alc5505_coef_set(codec, 0x61ac, 0x055525f0); /**/
+ alc5505_coef_set(codec, 0x61c0, 0x12230080); /* Clock control */
+ alc5505_coef_set(codec, 0x61b4, 0x040e2b02); /* PLL2 control */
+ alc5505_coef_set(codec, 0x61bc, 0x010234f8); /* OSC Control */
+ alc5505_coef_set(codec, 0x880c, 0x00000004); /* DRAM Function control */
+ alc5505_coef_set(codec, 0x880c, 0x00000003);
+ alc5505_coef_set(codec, 0x880c, 0x00000010);
+
+#ifdef HALT_REALTEK_ALC5505
+ alc5505_dsp_halt(codec);
+#endif
+}
+
+#ifdef HALT_REALTEK_ALC5505
+#define alc5505_dsp_suspend(codec) /* NOP */
+#define alc5505_dsp_resume(codec) /* NOP */
+#else
+#define alc5505_dsp_suspend(codec) alc5505_dsp_halt(codec)
+#define alc5505_dsp_resume(codec) alc5505_dsp_back_from_halt(codec)
+#endif
+
#ifdef CONFIG_PM
+static int alc269_suspend(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+
+ if (spec->has_alc5505_dsp)
+ alc5505_dsp_suspend(codec);
+ return alc_suspend(codec);
+}
+
static int alc269_resume(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
@@ -2603,7 +2708,10 @@ static int alc269_resume(struct hda_codec *codec)
snd_hda_codec_resume_amp(codec);
snd_hda_codec_resume_cache(codec);
+ alc_inv_dmic_sync(codec, true);
hda_call_check_power_status(codec, 0x01);
+ if (spec->has_alc5505_dsp)
+ alc5505_dsp_resume(codec);
return 0;
}
#endif /* CONFIG_PM */
@@ -3225,6 +3333,7 @@ enum {
ALC271_FIXUP_HP_GATE_MIC_JACK,
ALC269_FIXUP_ACER_AC700,
ALC269_FIXUP_LIMIT_INT_MIC_BOOST,
+ ALC269VB_FIXUP_ORDISSIMO_EVE2,
};
static const struct hda_fixup alc269_fixups[] = {
@@ -3467,6 +3576,15 @@ static const struct hda_fixup alc269_fixups[] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc269_fixup_limit_int_mic_boost,
},
+ [ALC269VB_FIXUP_ORDISSIMO_EVE2] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x12, 0x99a3092f }, /* int-mic */
+ { 0x18, 0x03a11d20 }, /* mic */
+ { 0x19, 0x411111f0 }, /* Unused bogus pin */
+ { }
+ },
+ },
};
static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -3482,7 +3600,10 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1028, 0x05c9, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x05ca, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x05cb, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x05cc, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x05cd, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x05de, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x05e0, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x05e9, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x05ea, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x05eb, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
@@ -3494,7 +3615,14 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1028, 0x05f5, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x05f6, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x05f8, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x05f9, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x05fb, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x0606, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x0608, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x0609, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x0613, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x15cc, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x15cd, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2),
SND_PCI_QUIRK(0x103c, 0x18e6, "HP", ALC269_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x1973, "HP Pavilion", ALC269_FIXUP_HP_MUTE_LED_MIC1),
@@ -3536,6 +3664,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x2203, "Thinkpad X230 Tablet", ALC269_FIXUP_LENOVO_DOCK),
SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K),
SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
+ SND_PCI_QUIRK(0x1b7d, 0xa831, "Ordissimo EVE2 ", ALC269VB_FIXUP_ORDISSIMO_EVE2), /* Also known as Malata PC-B1303 */
#if 0
/* Below is a quirk table taken from the old code.
@@ -3596,6 +3725,8 @@ static const struct hda_model_fixup alc269_fixup_models[] = {
{.id = ALC269_FIXUP_INV_DMIC, .name = "inv-dmic"},
{.id = ALC269_FIXUP_LENOVO_DOCK, .name = "lenovo-dock"},
{.id = ALC269_FIXUP_HP_GPIO_LED, .name = "hp-gpio-led"},
+ {.id = ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, .name = "dell-headset-multi"},
+ {.id = ALC269_FIXUP_DELL2_MIC_NO_PRESENCE, .name = "dell-headset-dock"},
{}
};
@@ -3713,6 +3844,11 @@ static int patch_alc269(struct hda_codec *codec)
break;
}
+ if (snd_hda_codec_read(codec, 0x51, 0, AC_VERB_PARAMETERS, 0) == 0x10ec5505) {
+ spec->has_alc5505_dsp = true;
+ spec->init_hook = alc5505_dsp_init;
+ }
+
/* automatic parse from the BIOS config */
err = alc269_parse_auto_config(codec);
if (err < 0)
@@ -3723,6 +3859,7 @@ static int patch_alc269(struct hda_codec *codec)
codec->patch_ops = alc_patch_ops;
#ifdef CONFIG_PM
+ codec->patch_ops.suspend = alc269_suspend;
codec->patch_ops.resume = alc269_resume;
#endif
spec->shutup = alc269_shutup;
@@ -4275,6 +4412,7 @@ static const struct hda_model_fixup alc662_fixup_models[] = {
{.id = ALC662_FIXUP_ASUS_MODE7, .name = "asus-mode7"},
{.id = ALC662_FIXUP_ASUS_MODE8, .name = "asus-mode8"},
{.id = ALC662_FIXUP_INV_DMIC, .name = "inv-dmic"},
+ {.id = ALC668_FIXUP_DELL_MIC_NO_PRESENCE, .name = "dell-headset-multi"},
{}
};
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index 1d9d642..e2f8359 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -2233,6 +2233,10 @@ static const struct snd_pci_quirk stac92hd83xxx_fixup_tbl[] = {
"HP Folio", STAC_92HD83XXX_HP_MIC_LED),
SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xff00, 0x1900,
"HP", STAC_92HD83XXX_HP_MIC_LED),
+ SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xff00, 0x2000,
+ "HP", STAC_92HD83XXX_HP_MIC_LED),
+ SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xff00, 0x2100,
+ "HP", STAC_92HD83XXX_HP_MIC_LED),
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3388,
"HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3389,
@@ -3707,14 +3711,6 @@ static void stac927x_proc_hook(struct snd_info_buffer *buffer,
#endif
#ifdef CONFIG_PM
-static int stac_resume(struct hda_codec *codec)
-{
- codec->patch_ops.init(codec);
- snd_hda_codec_resume_amp(codec);
- snd_hda_codec_resume_cache(codec);
- return 0;
-}
-
static int stac_suspend(struct hda_codec *codec)
{
stac_shutup(codec);
@@ -3743,7 +3739,6 @@ static void stac_set_power_state(struct hda_codec *codec, hda_nid_t fg,
}
#else
#define stac_suspend NULL
-#define stac_resume NULL
#define stac_set_power_state NULL
#endif /* CONFIG_PM */
@@ -3755,7 +3750,6 @@ static const struct hda_codec_ops stac_patch_ops = {
.unsol_event = snd_hda_jack_unsol_event,
#ifdef CONFIG_PM
.suspend = stac_suspend,
- .resume = stac_resume,
#endif
.reboot_notify = stac_shutup,
};
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
index e524554..e2481ba 100644
--- a/sound/pci/hda/patch_via.c
+++ b/sound/pci/hda/patch_via.c
@@ -480,14 +480,9 @@ static int via_suspend(struct hda_codec *codec)
struct via_spec *spec = codec->spec;
vt1708_stop_hp_work(codec);
- if (spec->codec_type == VT1802) {
- /* Fix pop noise on headphones */
- int i;
- for (i = 0; i < spec->gen.autocfg.hp_outs; i++)
- snd_hda_codec_write(codec, spec->gen.autocfg.hp_pins[i],
- 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
- 0x00);
- }
+ /* Fix pop noise on headphones */
+ if (spec->codec_type == VT1802)
+ snd_hda_shutup_pins(codec);
return 0;
}
@@ -746,6 +741,8 @@ static int patch_vt1708(struct hda_codec *codec)
/* don't support the input jack switching due to lack of unsol event */
/* (it may work with polling, though, but it needs testing) */
spec->gen.suppress_auto_mic = 1;
+ /* Some machines show the broken speaker mute */
+ spec->gen.auto_mute_via_amp = 1;
/* Add HP and CD pin config connect bit re-config action */
vt1708_set_pinconfig_connect(codec, VT1708_HP_PIN_NID);
@@ -910,6 +907,8 @@ static const struct hda_verb vt1708S_init_verbs[] = {
static void override_mic_boost(struct hda_codec *codec, hda_nid_t pin,
int offset, int num_steps, int step_size)
{
+ snd_hda_override_wcaps(codec, pin,
+ get_wcaps(codec, pin) | AC_WCAP_IN_AMP);
snd_hda_override_amp_caps(codec, pin, HDA_INPUT,
(offset << AC_AMPCAP_OFFSET_SHIFT) |
(num_steps << AC_AMPCAP_NUM_STEPS_SHIFT) |
diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c
index 806407a..28ec872 100644
--- a/sound/pci/ice1712/ice1712.c
+++ b/sound/pci/ice1712/ice1712.c
@@ -2807,7 +2807,6 @@ static void snd_ice1712_remove(struct pci_dev *pci)
if (ice->card_info && ice->card_info->chip_exit)
ice->card_info->chip_exit(ice);
snd_card_free(card);
- pci_set_drvdata(pci, NULL);
}
static struct pci_driver ice1712_driver = {
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c
index ce70e7f..5004717 100644
--- a/sound/pci/ice1712/ice1724.c
+++ b/sound/pci/ice1712/ice1724.c
@@ -2800,7 +2800,6 @@ static void snd_vt1724_remove(struct pci_dev *pci)
if (ice->card_info && ice->card_info->chip_exit)
ice->card_info->chip_exit(ice);
snd_card_free(card);
- pci_set_drvdata(pci, NULL);
}
#ifdef CONFIG_PM_SLEEP
diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c
index b8fe405..59c8aae 100644
--- a/sound/pci/intel8x0.c
+++ b/sound/pci/intel8x0.c
@@ -3364,7 +3364,6 @@ static int snd_intel8x0_probe(struct pci_dev *pci,
static void snd_intel8x0_remove(struct pci_dev *pci)
{
snd_card_free(pci_get_drvdata(pci));
- pci_set_drvdata(pci, NULL);
}
static struct pci_driver intel8x0_driver = {
diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c
index fea09e8..3573c11 100644
--- a/sound/pci/intel8x0m.c
+++ b/sound/pci/intel8x0m.c
@@ -1328,7 +1328,6 @@ static int snd_intel8x0m_probe(struct pci_dev *pci,
static void snd_intel8x0m_remove(struct pci_dev *pci)
{
snd_card_free(pci_get_drvdata(pci));
- pci_set_drvdata(pci, NULL);
}
static struct pci_driver intel8x0m_driver = {
diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c
index 43b4228..9cf9829 100644
--- a/sound/pci/korg1212/korg1212.c
+++ b/sound/pci/korg1212/korg1212.c
@@ -2473,7 +2473,6 @@ snd_korg1212_probe(struct pci_dev *pci,
static void snd_korg1212_remove(struct pci_dev *pci)
{
snd_card_free(pci_get_drvdata(pci));
- pci_set_drvdata(pci, NULL);
}
static struct pci_driver korg1212_driver = {
diff --git a/sound/pci/lola/lola.c b/sound/pci/lola/lola.c
index 322b638..7307d97 100644
--- a/sound/pci/lola/lola.c
+++ b/sound/pci/lola/lola.c
@@ -759,7 +759,6 @@ out_free:
static void lola_remove(struct pci_dev *pci)
{
snd_card_free(pci_get_drvdata(pci));
- pci_set_drvdata(pci, NULL);
}
/* PCI IDs */
diff --git a/sound/pci/lx6464es/lx6464es.c b/sound/pci/lx6464es/lx6464es.c
index 298bc9b..3230e57 100644
--- a/sound/pci/lx6464es/lx6464es.c
+++ b/sound/pci/lx6464es/lx6464es.c
@@ -1139,7 +1139,6 @@ out_free:
static void snd_lx6464es_remove(struct pci_dev *pci)
{
snd_card_free(pci_get_drvdata(pci));
- pci_set_drvdata(pci, NULL);
}
diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c
index c76ac14..d541736 100644
--- a/sound/pci/maestro3.c
+++ b/sound/pci/maestro3.c
@@ -2775,7 +2775,6 @@ snd_m3_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
static void snd_m3_remove(struct pci_dev *pci)
{
snd_card_free(pci_get_drvdata(pci));
- pci_set_drvdata(pci, NULL);
}
static struct pci_driver m3_driver = {
diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c
index 934dec9..1e0f6ee 100644
--- a/sound/pci/mixart/mixart.c
+++ b/sound/pci/mixart/mixart.c
@@ -1377,7 +1377,6 @@ static int snd_mixart_probe(struct pci_dev *pci,
static void snd_mixart_remove(struct pci_dev *pci)
{
snd_mixart_free(pci_get_drvdata(pci));
- pci_set_drvdata(pci, NULL);
}
static struct pci_driver mixart_driver = {
diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c
index 6febedb..fe79fff 100644
--- a/sound/pci/nm256/nm256.c
+++ b/sound/pci/nm256/nm256.c
@@ -1746,7 +1746,6 @@ static int snd_nm256_probe(struct pci_dev *pci,
static void snd_nm256_remove(struct pci_dev *pci)
{
snd_card_free(pci_get_drvdata(pci));
- pci_set_drvdata(pci, NULL);
}
diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c
index 9562dc6..b0cb48a 100644
--- a/sound/pci/oxygen/oxygen_lib.c
+++ b/sound/pci/oxygen/oxygen_lib.c
@@ -722,7 +722,6 @@ EXPORT_SYMBOL(oxygen_pci_probe);
void oxygen_pci_remove(struct pci_dev *pci)
{
snd_card_free(pci_get_drvdata(pci));
- pci_set_drvdata(pci, NULL);
}
EXPORT_SYMBOL(oxygen_pci_remove);
diff --git a/sound/pci/pcxhr/pcxhr.c b/sound/pci/pcxhr/pcxhr.c
index b97384a..d379b28 100644
--- a/sound/pci/pcxhr/pcxhr.c
+++ b/sound/pci/pcxhr/pcxhr.c
@@ -1691,7 +1691,6 @@ static int pcxhr_probe(struct pci_dev *pci,
static void pcxhr_remove(struct pci_dev *pci)
{
pcxhr_free(pci_get_drvdata(pci));
- pci_set_drvdata(pci, NULL);
}
static struct pci_driver pcxhr_driver = {
diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c
index 63c1c80..56cc891 100644
--- a/sound/pci/riptide/riptide.c
+++ b/sound/pci/riptide/riptide.c
@@ -2066,7 +2066,6 @@ static void snd_riptide_joystick_remove(struct pci_dev *pci)
if (gameport) {
release_region(gameport->io, 8);
gameport_unregister_port(gameport);
- pci_set_drvdata(pci, NULL);
}
}
#endif
@@ -2179,7 +2178,6 @@ snd_card_riptide_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
static void snd_card_riptide_remove(struct pci_dev *pci)
{
snd_card_free(pci_get_drvdata(pci));
- pci_set_drvdata(pci, NULL);
}
static struct pci_driver driver = {
diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c
index 0ecd410..cc26346 100644
--- a/sound/pci/rme32.c
+++ b/sound/pci/rme32.c
@@ -1981,7 +1981,6 @@ snd_rme32_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
static void snd_rme32_remove(struct pci_dev *pci)
{
snd_card_free(pci_get_drvdata(pci));
- pci_set_drvdata(pci, NULL);
}
static struct pci_driver rme32_driver = {
diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c
index 5fb88ac..2a8ad9d 100644
--- a/sound/pci/rme96.c
+++ b/sound/pci/rme96.c
@@ -2390,7 +2390,6 @@ snd_rme96_probe(struct pci_dev *pci,
static void snd_rme96_remove(struct pci_dev *pci)
{
snd_card_free(pci_get_drvdata(pci));
- pci_set_drvdata(pci, NULL);
}
static struct pci_driver rme96_driver = {
diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c
index 94084cd..4f255df 100644
--- a/sound/pci/rme9652/hdsp.c
+++ b/sound/pci/rme9652/hdsp.c
@@ -5412,7 +5412,6 @@ static int snd_hdsp_probe(struct pci_dev *pci,
static void snd_hdsp_remove(struct pci_dev *pci)
{
snd_card_free(pci_get_drvdata(pci));
- pci_set_drvdata(pci, NULL);
}
static struct pci_driver hdsp_driver = {
diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c
index 9ea05e9..bd50193 100644
--- a/sound/pci/rme9652/hdspm.c
+++ b/sound/pci/rme9652/hdspm.c
@@ -400,8 +400,8 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
#define HDSPM_wc_freq0 (1<<5) /* input freq detected via autosync */
#define HDSPM_wc_freq1 (1<<6) /* 001=32, 010==44.1, 011=48, */
-#define HDSPM_wc_freq2 (1<<7) /* 100=64, 101=88.2, 110=96, */
-/* missing Bit for 111=128, 1000=176.4, 1001=192 */
+#define HDSPM_wc_freq2 (1<<7) /* 100=64, 101=88.2, 110=96, 111=128 */
+#define HDSPM_wc_freq3 0x800 /* 1000=176.4, 1001=192 */
#define HDSPM_SyncRef0 0x10000 /* Sync Reference */
#define HDSPM_SyncRef1 0x20000
@@ -412,13 +412,17 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
#define HDSPM_wc_valid (HDSPM_wcLock|HDSPM_wcSync)
-#define HDSPM_wcFreqMask (HDSPM_wc_freq0|HDSPM_wc_freq1|HDSPM_wc_freq2)
+#define HDSPM_wcFreqMask (HDSPM_wc_freq0|HDSPM_wc_freq1|HDSPM_wc_freq2|\
+ HDSPM_wc_freq3)
#define HDSPM_wcFreq32 (HDSPM_wc_freq0)
#define HDSPM_wcFreq44_1 (HDSPM_wc_freq1)
#define HDSPM_wcFreq48 (HDSPM_wc_freq0|HDSPM_wc_freq1)
#define HDSPM_wcFreq64 (HDSPM_wc_freq2)
#define HDSPM_wcFreq88_2 (HDSPM_wc_freq0|HDSPM_wc_freq2)
#define HDSPM_wcFreq96 (HDSPM_wc_freq1|HDSPM_wc_freq2)
+#define HDSPM_wcFreq128 (HDSPM_wc_freq0|HDSPM_wc_freq1|HDSPM_wc_freq2)
+#define HDSPM_wcFreq176_4 (HDSPM_wc_freq3)
+#define HDSPM_wcFreq192 (HDSPM_wc_freq0|HDSPM_wc_freq3)
#define HDSPM_status1_F_0 0x0400000
#define HDSPM_status1_F_1 0x0800000
@@ -1087,6 +1091,26 @@ static int hdspm_round_frequency(int rate)
return 48000;
}
+/* QS and DS rates normally can not be detected
+ * automatically by the card. Only exception is MADI
+ * in 96k frame mode.
+ *
+ * So if we read SS values (32 .. 48k), check for
+ * user-provided DS/QS bits in the control register
+ * and multiply the base frequency accordingly.
+ */
+static int hdspm_rate_multiplier(struct hdspm *hdspm, int rate)
+{
+ if (rate <= 48000) {
+ if (hdspm->control_register & HDSPM_QuadSpeed)
+ return rate * 4;
+ else if (hdspm->control_register &
+ HDSPM_DoubleSpeed)
+ return rate * 2;
+ };
+ return rate;
+}
+
static int hdspm_tco_sync_check(struct hdspm *hdspm);
static int hdspm_sync_in_sync_check(struct hdspm *hdspm);
@@ -1181,6 +1205,15 @@ static int hdspm_external_sample_rate(struct hdspm *hdspm)
case HDSPM_wcFreq96:
rate = 96000;
break;
+ case HDSPM_wcFreq128:
+ rate = 128000;
+ break;
+ case HDSPM_wcFreq176_4:
+ rate = 176400;
+ break;
+ case HDSPM_wcFreq192:
+ rate = 192000;
+ break;
default:
rate = 0;
break;
@@ -1192,7 +1225,7 @@ static int hdspm_external_sample_rate(struct hdspm *hdspm)
*/
if (rate != 0 &&
(status2 & HDSPM_SelSyncRefMask) == HDSPM_SelSyncRef_WORD)
- return rate;
+ return hdspm_rate_multiplier(hdspm, rate);
/* maybe a madi input (which is taken if sel sync is madi) */
if (status & HDSPM_madiLock) {
@@ -1255,21 +1288,8 @@ static int hdspm_external_sample_rate(struct hdspm *hdspm)
}
}
- /* QS and DS rates normally can not be detected
- * automatically by the card. Only exception is MADI
- * in 96k frame mode.
- *
- * So if we read SS values (32 .. 48k), check for
- * user-provided DS/QS bits in the control register
- * and multiply the base frequency accordingly.
- */
- if (rate <= 48000) {
- if (hdspm->control_register & HDSPM_QuadSpeed)
- rate *= 4;
- else if (hdspm->control_register &
- HDSPM_DoubleSpeed)
- rate *= 2;
- }
+ rate = hdspm_rate_multiplier(hdspm, rate);
+
break;
}
@@ -6737,7 +6757,6 @@ static int snd_hdspm_probe(struct pci_dev *pci,
static void snd_hdspm_remove(struct pci_dev *pci)
{
snd_card_free(pci_get_drvdata(pci));
- pci_set_drvdata(pci, NULL);
}
static struct pci_driver hdspm_driver = {
diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c
index 773a67f..b96d9e1 100644
--- a/sound/pci/rme9652/rme9652.c
+++ b/sound/pci/rme9652/rme9652.c
@@ -2628,7 +2628,6 @@ static int snd_rme9652_probe(struct pci_dev *pci,
static void snd_rme9652_remove(struct pci_dev *pci)
{
snd_card_free(pci_get_drvdata(pci));
- pci_set_drvdata(pci, NULL);
}
static struct pci_driver rme9652_driver = {
diff --git a/sound/pci/sis7019.c b/sound/pci/sis7019.c
index 748e82d..e413b4e 100644
--- a/sound/pci/sis7019.c
+++ b/sound/pci/sis7019.c
@@ -1482,7 +1482,6 @@ error_out:
static void snd_sis7019_remove(struct pci_dev *pci)
{
snd_card_free(pci_get_drvdata(pci));
- pci_set_drvdata(pci, NULL);
}
static struct pci_driver sis7019_driver = {
diff --git a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c
index a2e7686..2a46bf9 100644
--- a/sound/pci/sonicvibes.c
+++ b/sound/pci/sonicvibes.c
@@ -1528,7 +1528,6 @@ static int snd_sonic_probe(struct pci_dev *pci,
static void snd_sonic_remove(struct pci_dev *pci)
{
snd_card_free(pci_get_drvdata(pci));
- pci_set_drvdata(pci, NULL);
}
static struct pci_driver sonicvibes_driver = {
diff --git a/sound/pci/trident/trident.c b/sound/pci/trident/trident.c
index 1aefd62..b3b588b 100644
--- a/sound/pci/trident/trident.c
+++ b/sound/pci/trident/trident.c
@@ -169,7 +169,6 @@ static int snd_trident_probe(struct pci_dev *pci,
static void snd_trident_remove(struct pci_dev *pci)
{
snd_card_free(pci_get_drvdata(pci));
- pci_set_drvdata(pci, NULL);
}
static struct pci_driver trident_driver = {
diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c
index d756a35..3c511d0 100644
--- a/sound/pci/via82xx.c
+++ b/sound/pci/via82xx.c
@@ -2646,7 +2646,6 @@ static int snd_via82xx_probe(struct pci_dev *pci,
static void snd_via82xx_remove(struct pci_dev *pci)
{
snd_card_free(pci_get_drvdata(pci));
- pci_set_drvdata(pci, NULL);
}
static struct pci_driver via82xx_driver = {
diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c
index 4f5fd80..ca19028 100644
--- a/sound/pci/via82xx_modem.c
+++ b/sound/pci/via82xx_modem.c
@@ -1227,7 +1227,6 @@ static int snd_via82xx_probe(struct pci_dev *pci,
static void snd_via82xx_remove(struct pci_dev *pci)
{
snd_card_free(pci_get_drvdata(pci));
- pci_set_drvdata(pci, NULL);
}
static struct pci_driver via82xx_modem_driver = {
diff --git a/sound/pci/vx222/vx222.c b/sound/pci/vx222/vx222.c
index e2f1ab3..ab8a9b1 100644
--- a/sound/pci/vx222/vx222.c
+++ b/sound/pci/vx222/vx222.c
@@ -254,7 +254,6 @@ static int snd_vx222_probe(struct pci_dev *pci,
static void snd_vx222_remove(struct pci_dev *pci)
{
snd_card_free(pci_get_drvdata(pci));
- pci_set_drvdata(pci, NULL);
}
#ifdef CONFIG_PM_SLEEP
diff --git a/sound/pci/ymfpci/ymfpci.c b/sound/pci/ymfpci/ymfpci.c
index 01c4965..e8932b2 100644
--- a/sound/pci/ymfpci/ymfpci.c
+++ b/sound/pci/ymfpci/ymfpci.c
@@ -347,7 +347,6 @@ static int snd_card_ymfpci_probe(struct pci_dev *pci,
static void snd_card_ymfpci_remove(struct pci_dev *pci)
{
snd_card_free(pci_get_drvdata(pci));
- pci_set_drvdata(pci, NULL);
}
static struct pci_driver ymfpci_driver = {
diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c
index 22056c5..d591c15 100644
--- a/sound/pci/ymfpci/ymfpci_main.c
+++ b/sound/pci/ymfpci/ymfpci_main.c
@@ -2258,7 +2258,7 @@ static int snd_ymfpci_free(struct snd_ymfpci *chip)
/* FIXME: temporarily disabled, otherwise we cannot fire up
* the chip again unless reboot. ACPI bug?
*/
- pci_set_power_state(chip->pci, 3);
+ pci_set_power_state(chip->pci, PCI_D3hot);
#endif
#ifdef CONFIG_PM_SLEEP
diff --git a/sound/ppc/powermac.c b/sound/ppc/powermac.c
index 09fc848..8abb521 100644
--- a/sound/ppc/powermac.c
+++ b/sound/ppc/powermac.c
@@ -139,7 +139,6 @@ __error:
static int snd_pmac_remove(struct platform_device *devptr)
{
snd_card_free(platform_get_drvdata(devptr));
- platform_set_drvdata(devptr, NULL);
return 0;
}
diff --git a/sound/sh/aica.c b/sound/sh/aica.c
index e59a73a..78a3697 100644
--- a/sound/sh/aica.c
+++ b/sound/sh/aica.c
@@ -598,7 +598,6 @@ static int snd_aica_remove(struct platform_device *devptr)
return -ENODEV;
snd_card_free(dreamcastcard->card);
kfree(dreamcastcard);
- platform_set_drvdata(devptr, NULL);
return 0;
}
diff --git a/sound/sh/sh_dac_audio.c b/sound/sh/sh_dac_audio.c
index e68c4fc..7c9422c 100644
--- a/sound/sh/sh_dac_audio.c
+++ b/sound/sh/sh_dac_audio.c
@@ -290,8 +290,6 @@ static int snd_sh_dac_pcm(struct snd_sh_dac *chip, int device)
static int snd_sh_dac_remove(struct platform_device *devptr)
{
snd_card_free(platform_get_drvdata(devptr));
- platform_set_drvdata(devptr, NULL);
-
return 0;
}
diff --git a/sound/soc/au1x/ac97c.c b/sound/soc/au1x/ac97c.c
index 44b8dce..d6f7694 100644
--- a/sound/soc/au1x/ac97c.c
+++ b/sound/soc/au1x/ac97c.c
@@ -179,13 +179,12 @@ static void au1xac97c_ac97_cold_reset(struct snd_ac97 *ac97)
}
/* AC97 controller operations */
-struct snd_ac97_bus_ops soc_ac97_ops = {
+static struct snd_ac97_bus_ops ac97c_bus_ops = {
.read = au1xac97c_ac97_read,
.write = au1xac97c_ac97_write,
.reset = au1xac97c_ac97_cold_reset,
.warm_reset = au1xac97c_ac97_warm_reset,
};
-EXPORT_SYMBOL_GPL(soc_ac97_ops); /* globals be gone! */
static int alchemy_ac97c_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
@@ -272,6 +271,10 @@ static int au1xac97c_drvprobe(struct platform_device *pdev)
platform_set_drvdata(pdev, ctx);
+ ret = snd_soc_set_ac97_ops(&ac97c_bus_ops);
+ if (ret)
+ return ret;
+
ret = snd_soc_register_component(&pdev->dev, &au1xac97c_component,
&au1xac97c_dai_driver, 1);
if (ret)
@@ -338,19 +341,7 @@ static struct platform_driver au1xac97c_driver = {
.remove = au1xac97c_drvremove,
};
-static int __init au1xac97c_load(void)
-{
- ac97c_workdata = NULL;
- return platform_driver_register(&au1xac97c_driver);
-}
-
-static void __exit au1xac97c_unload(void)
-{
- platform_driver_unregister(&au1xac97c_driver);
-}
-
-module_init(au1xac97c_load);
-module_exit(au1xac97c_unload);
+module_platform_driver(&au1xac97c_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Au1000/1500/1100 AC97C ASoC driver");
diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c
index 8f1862a..a822ab8 100644
--- a/sound/soc/au1x/psc-ac97.c
+++ b/sound/soc/au1x/psc-ac97.c
@@ -201,13 +201,12 @@ static void au1xpsc_ac97_cold_reset(struct snd_ac97 *ac97)
}
/* AC97 controller operations */
-struct snd_ac97_bus_ops soc_ac97_ops = {
+static struct snd_ac97_bus_ops psc_ac97_ops = {
.read = au1xpsc_ac97_read,
.write = au1xpsc_ac97_write,
.reset = au1xpsc_ac97_cold_reset,
.warm_reset = au1xpsc_ac97_warm_reset,
};
-EXPORT_SYMBOL_GPL(soc_ac97_ops);
static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
@@ -383,15 +382,9 @@ static int au1xpsc_ac97_drvprobe(struct platform_device *pdev)
if (!iores)
return -ENODEV;
- if (!devm_request_mem_region(&pdev->dev, iores->start,
- resource_size(iores),
- pdev->name))
- return -EBUSY;
-
- wd->mmio = devm_ioremap(&pdev->dev, iores->start,
- resource_size(iores));
- if (!wd->mmio)
- return -EBUSY;
+ wd->mmio = devm_ioremap_resource(&pdev->dev, iores);
+ if (IS_ERR(wd->mmio))
+ return PTR_ERR(wd->mmio);
dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0);
if (!dmares)
@@ -423,6 +416,10 @@ static int au1xpsc_ac97_drvprobe(struct platform_device *pdev)
platform_set_drvdata(pdev, wd);
+ ret = snd_soc_set_ac97_ops(&psc_ac97_ops);
+ if (ret)
+ return ret;
+
ret = snd_soc_register_component(&pdev->dev, &au1xpsc_ac97_component,
&wd->dai_drv, 1);
if (ret)
@@ -503,19 +500,7 @@ static struct platform_driver au1xpsc_ac97_driver = {
.remove = au1xpsc_ac97_drvremove,
};
-static int __init au1xpsc_ac97_load(void)
-{
- au1xpsc_ac97_workdata = NULL;
- return platform_driver_register(&au1xpsc_ac97_driver);
-}
-
-static void __exit au1xpsc_ac97_unload(void)
-{
- platform_driver_unregister(&au1xpsc_ac97_driver);
-}
-
-module_init(au1xpsc_ac97_load);
-module_exit(au1xpsc_ac97_unload);
+module_platform_driver(au1xpsc_ac97_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Au12x0/Au1550 PSC AC97 ALSA ASoC audio driver");
diff --git a/sound/soc/blackfin/bf5xx-ac97.c b/sound/soc/blackfin/bf5xx-ac97.c
index c66bef8..efb1dae 100644
--- a/sound/soc/blackfin/bf5xx-ac97.c
+++ b/sound/soc/blackfin/bf5xx-ac97.c
@@ -198,13 +198,12 @@ static void bf5xx_ac97_cold_reset(struct snd_ac97 *ac97)
#endif
}
-struct snd_ac97_bus_ops soc_ac97_ops = {
+static struct snd_ac97_bus_ops bf5xx_ac97_ops = {
.read = bf5xx_ac97_read,
.write = bf5xx_ac97_write,
.warm_reset = bf5xx_ac97_warm_reset,
.reset = bf5xx_ac97_cold_reset,
};
-EXPORT_SYMBOL_GPL(soc_ac97_ops);
#ifdef CONFIG_PM
static int bf5xx_ac97_suspend(struct snd_soc_dai *dai)
@@ -293,13 +292,14 @@ static int asoc_bfin_ac97_probe(struct platform_device *pdev)
#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
/* Request PB3 as reset pin */
- if (gpio_request(CONFIG_SND_BF5XX_RESET_GPIO_NUM, "SND_AD198x RESET")) {
- pr_err("Failed to request GPIO_%d for reset\n",
- CONFIG_SND_BF5XX_RESET_GPIO_NUM);
- ret = -1;
+ ret = devm_gpio_request_one(&pdev->dev,
+ CONFIG_SND_BF5XX_RESET_GPIO_NUM,
+ GPIOF_OUT_INIT_HIGH, "SND_AD198x RESET") {
+ dev_err(&pdev->dev,
+ "Failed to request GPIO_%d for reset: %d\n",
+ CONFIG_SND_BF5XX_RESET_GPIO_NUM, ret);
goto gpio_err;
}
- gpio_direction_output(CONFIG_SND_BF5XX_RESET_GPIO_NUM, 1);
#endif
sport_handle = sport_init(pdev, 2, sizeof(struct ac97_frame),
@@ -335,6 +335,12 @@ static int asoc_bfin_ac97_probe(struct platform_device *pdev)
goto sport_config_err;
}
+ ret = snd_soc_set_ac97_ops(&bf5xx_ac97_ops);
+ if (ret != 0) {
+ dev_err(&pdev->dev, "Failed to set AC'97 ops: %d\n", ret);
+ goto sport_config_err;
+ }
+
ret = snd_soc_register_component(&pdev->dev, &bfin_ac97_component,
&bfin_ac97_dai, 1);
if (ret) {
@@ -349,10 +355,7 @@ static int asoc_bfin_ac97_probe(struct platform_device *pdev)
sport_config_err:
sport_done(sport_handle);
sport_err:
-#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
- gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
-gpio_err:
-#endif
+ snd_soc_set_ac97_ops(NULL);
return ret;
}
@@ -363,9 +366,7 @@ static int asoc_bfin_ac97_remove(struct platform_device *pdev)
snd_soc_unregister_component(&pdev->dev);
sport_done(sport_handle);
-#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
- gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
-#endif
+ snd_soc_set_ac97_ops(NULL);
return 0;
}
diff --git a/sound/soc/cirrus/ep93xx-ac97.c b/sound/soc/cirrus/ep93xx-ac97.c
index 3f4f888..ac73c60 100644
--- a/sound/soc/cirrus/ep93xx-ac97.c
+++ b/sound/soc/cirrus/ep93xx-ac97.c
@@ -237,13 +237,12 @@ static irqreturn_t ep93xx_ac97_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
-struct snd_ac97_bus_ops soc_ac97_ops = {
+static struct snd_ac97_bus_ops ep93xx_ac97_ops = {
.read = ep93xx_ac97_read,
.write = ep93xx_ac97_write,
.reset = ep93xx_ac97_cold_reset,
.warm_reset = ep93xx_ac97_warm_reset,
};
-EXPORT_SYMBOL_GPL(soc_ac97_ops);
static int ep93xx_ac97_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai)
@@ -389,6 +388,10 @@ static int ep93xx_ac97_probe(struct platform_device *pdev)
ep93xx_ac97_info = info;
platform_set_drvdata(pdev, info);
+ ret = snd_soc_set_ac97_ops(&ep93xx_ac97_ops);
+ if (ret)
+ goto fail;
+
ret = snd_soc_register_component(&pdev->dev, &ep93xx_ac97_component,
&ep93xx_ac97_dai, 1);
if (ret)
@@ -398,7 +401,7 @@ static int ep93xx_ac97_probe(struct platform_device *pdev)
fail:
ep93xx_ac97_info = NULL;
- dev_set_drvdata(&pdev->dev, NULL);
+ snd_soc_set_ac97_ops(NULL);
return ret;
}
@@ -412,7 +415,8 @@ static int ep93xx_ac97_remove(struct platform_device *pdev)
ep93xx_ac97_write_reg(info, AC97GCR, 0);
ep93xx_ac97_info = NULL;
- dev_set_drvdata(&pdev->dev, NULL);
+
+ snd_soc_set_ac97_ops(NULL);
return 0;
}
diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c
index 1382f3f..8af0434 100644
--- a/sound/soc/codecs/88pm860x-codec.c
+++ b/sound/soc/codecs/88pm860x-codec.c
@@ -120,10 +120,8 @@
* before DAC & PGA in DAPM power-off sequence.
*/
#define PM860X_DAPM_OUTPUT(wname, wevent) \
-{ .id = snd_soc_dapm_pga, .name = wname, .reg = SND_SOC_NOPM, \
- .shift = 0, .invert = 0, .kcontrol_news = NULL, \
- .num_kcontrols = 0, .event = wevent, \
- .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD, }
+ SND_SOC_DAPM_PGA_E(wname, SND_SOC_NOPM, 0, 0, NULL, 0, wevent, \
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD)
struct pm860x_det {
struct snd_soc_jack *hp_jack;
diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c
index ef2ae32..ec73518 100644
--- a/sound/soc/codecs/ac97.c
+++ b/sound/soc/codecs/ac97.c
@@ -62,13 +62,13 @@ static struct snd_soc_dai_driver ac97_dai = {
static unsigned int ac97_read(struct snd_soc_codec *codec,
unsigned int reg)
{
- return soc_ac97_ops.read(codec->ac97, reg);
+ return soc_ac97_ops->read(codec->ac97, reg);
}
static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int val)
{
- soc_ac97_ops.write(codec->ac97, reg, val);
+ soc_ac97_ops->write(codec->ac97, reg, val);
return 0;
}
@@ -79,7 +79,8 @@ static int ac97_soc_probe(struct snd_soc_codec *codec)
int ret;
/* add codec as bus device for standard ac97 */
- ret = snd_ac97_bus(codec->card->snd_card, 0, &soc_ac97_ops, NULL, &ac97_bus);
+ ret = snd_ac97_bus(codec->card->snd_card, 0, soc_ac97_ops, NULL,
+ &ac97_bus);
if (ret < 0)
return ret;
diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c
index f385342..89fcf7d 100644
--- a/sound/soc/codecs/ad1980.c
+++ b/sound/soc/codecs/ad1980.c
@@ -108,7 +108,7 @@ static unsigned int ac97_read(struct snd_soc_codec *codec,
case AC97_EXTENDED_STATUS:
case AC97_VENDOR_ID1:
case AC97_VENDOR_ID2:
- return soc_ac97_ops.read(codec->ac97, reg);
+ return soc_ac97_ops->read(codec->ac97, reg);
default:
reg = reg >> 1;
@@ -124,7 +124,7 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
{
u16 *cache = codec->reg_cache;
- soc_ac97_ops.write(codec->ac97, reg, val);
+ soc_ac97_ops->write(codec->ac97, reg, val);
reg = reg >> 1;
if (reg < ARRAY_SIZE(ad1980_reg))
cache[reg] = val;
@@ -154,13 +154,13 @@ static int ad1980_reset(struct snd_soc_codec *codec, int try_warm)
u16 retry_cnt = 0;
retry:
- if (try_warm && soc_ac97_ops.warm_reset) {
- soc_ac97_ops.warm_reset(codec->ac97);
+ if (try_warm && soc_ac97_ops->warm_reset) {
+ soc_ac97_ops->warm_reset(codec->ac97);
if (ac97_read(codec, AC97_RESET) == 0x0090)
return 1;
}
- soc_ac97_ops.reset(codec->ac97);
+ soc_ac97_ops->reset(codec->ac97);
/* Set bit 16slot in register 74h, then every slot will has only 16
* bits. This command is sent out in 20bit mode, in which case the
* first nibble of data is eaten by the addr. (Tag is always 16 bit)*/
@@ -186,7 +186,7 @@ static int ad1980_soc_probe(struct snd_soc_codec *codec)
printk(KERN_INFO "AD1980 SoC Audio Codec\n");
- ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
+ ret = snd_soc_new_ac97_codec(codec, soc_ac97_ops, 0);
if (ret < 0) {
printk(KERN_ERR "ad1980: failed to register AC97 codec\n");
return ret;
diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c
index b6b1a77..d1124a5 100644
--- a/sound/soc/codecs/adau1701.c
+++ b/sound/soc/codecs/adau1701.c
@@ -16,6 +16,7 @@
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/of_device.h>
+#include <linux/regmap.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -24,16 +25,19 @@
#include "sigmadsp.h"
#include "adau1701.h"
-#define ADAU1701_DSPCTRL 0x1c
-#define ADAU1701_SEROCTL 0x1e
-#define ADAU1701_SERICTL 0x1f
+#define ADAU1701_DSPCTRL 0x081c
+#define ADAU1701_SEROCTL 0x081e
+#define ADAU1701_SERICTL 0x081f
-#define ADAU1701_AUXNPOW 0x22
+#define ADAU1701_AUXNPOW 0x0822
+#define ADAU1701_PINCONF_0 0x0820
+#define ADAU1701_PINCONF_1 0x0821
+#define ADAU1701_AUXNPOW 0x0822
-#define ADAU1701_OSCIPOW 0x26
-#define ADAU1701_DACSET 0x27
+#define ADAU1701_OSCIPOW 0x0826
+#define ADAU1701_DACSET 0x0827
-#define ADAU1701_NUM_REGS 0x28
+#define ADAU1701_MAX_REGISTER 0x0828
#define ADAU1701_DSPCTRL_CR (1 << 2)
#define ADAU1701_DSPCTRL_DAM (1 << 3)
@@ -87,11 +91,18 @@
#define ADAU1701_OSCIPOW_OPD 0x04
#define ADAU1701_DACSET_DACINIT 1
+#define ADAU1707_CLKDIV_UNSET (-1UL)
+
#define ADAU1701_FIRMWARE "adau1701.bin"
struct adau1701 {
int gpio_nreset;
+ int gpio_pll_mode[2];
unsigned int dai_fmt;
+ unsigned int pll_clkdiv;
+ unsigned int sysclk;
+ struct regmap *regmap;
+ u8 pin_config[12];
};
static const struct snd_kcontrol_new adau1701_controls[] = {
@@ -123,10 +134,13 @@ static const struct snd_soc_dapm_route adau1701_dapm_routes[] = {
{ "ADC", NULL, "IN1" },
};
-static unsigned int adau1701_register_size(struct snd_soc_codec *codec,
+static unsigned int adau1701_register_size(struct device *dev,
unsigned int reg)
{
switch (reg) {
+ case ADAU1701_PINCONF_0:
+ case ADAU1701_PINCONF_1:
+ return 3;
case ADAU1701_DSPCTRL:
case ADAU1701_SEROCTL:
case ADAU1701_AUXNPOW:
@@ -137,33 +151,42 @@ static unsigned int adau1701_register_size(struct snd_soc_codec *codec,
return 1;
}
- dev_err(codec->dev, "Unsupported register address: %d\n", reg);
+ dev_err(dev, "Unsupported register address: %d\n", reg);
return 0;
}
-static int adau1701_write(struct snd_soc_codec *codec, unsigned int reg,
- unsigned int value)
+static bool adau1701_volatile_reg(struct device *dev, unsigned int reg)
{
+ switch (reg) {
+ case ADAU1701_DACSET:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static int adau1701_reg_write(void *context, unsigned int reg,
+ unsigned int value)
+{
+ struct i2c_client *client = context;
unsigned int i;
unsigned int size;
- uint8_t buf[4];
+ uint8_t buf[5];
int ret;
- size = adau1701_register_size(codec, reg);
+ size = adau1701_register_size(&client->dev, reg);
if (size == 0)
return -EINVAL;
- snd_soc_cache_write(codec, reg, value);
-
- buf[0] = 0x08;
- buf[1] = reg;
+ buf[0] = reg >> 8;
+ buf[1] = reg & 0xff;
for (i = size + 1; i >= 2; --i) {
buf[i] = value;
value >>= 8;
}
- ret = i2c_master_send(to_i2c_client(codec->dev), buf, size + 2);
+ ret = i2c_master_send(client, buf, size + 2);
if (ret == size + 2)
return 0;
else if (ret < 0)
@@ -172,47 +195,105 @@ static int adau1701_write(struct snd_soc_codec *codec, unsigned int reg,
return -EIO;
}
-static unsigned int adau1701_read(struct snd_soc_codec *codec, unsigned int reg)
+static int adau1701_reg_read(void *context, unsigned int reg,
+ unsigned int *value)
{
- unsigned int value;
- unsigned int ret;
+ int ret;
+ unsigned int i;
+ unsigned int size;
+ uint8_t send_buf[2], recv_buf[3];
+ struct i2c_client *client = context;
+ struct i2c_msg msgs[2];
- ret = snd_soc_cache_read(codec, reg, &value);
- if (ret)
- return ret;
+ size = adau1701_register_size(&client->dev, reg);
+ if (size == 0)
+ return -EINVAL;
- return value;
-}
+ send_buf[0] = reg >> 8;
+ send_buf[1] = reg & 0xff;
-static void adau1701_reset(struct snd_soc_codec *codec)
-{
- struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
+ msgs[0].addr = client->addr;
+ msgs[0].len = sizeof(send_buf);
+ msgs[0].buf = send_buf;
+ msgs[0].flags = 0;
- if (!gpio_is_valid(adau1701->gpio_nreset))
- return;
+ msgs[1].addr = client->addr;
+ msgs[1].len = size;
+ msgs[1].buf = recv_buf;
+ msgs[1].flags = I2C_M_RD;
- gpio_set_value(adau1701->gpio_nreset, 0);
- /* minimum reset time is 20ns */
- udelay(1);
- gpio_set_value(adau1701->gpio_nreset, 1);
- /* power-up time may be as long as 85ms */
- mdelay(85);
+ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+ if (ret < 0)
+ return ret;
+ else if (ret != ARRAY_SIZE(msgs))
+ return -EIO;
+
+ *value = 0;
+
+ for (i = 0; i < size; i++)
+ *value |= recv_buf[i] << (i * 8);
+
+ return 0;
}
-static int adau1701_init(struct snd_soc_codec *codec)
+static int adau1701_reset(struct snd_soc_codec *codec, unsigned int clkdiv)
{
- int ret;
+ struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
struct i2c_client *client = to_i2c_client(codec->dev);
+ int ret;
- adau1701_reset(codec);
+ if (clkdiv != ADAU1707_CLKDIV_UNSET &&
+ gpio_is_valid(adau1701->gpio_pll_mode[0]) &&
+ gpio_is_valid(adau1701->gpio_pll_mode[1])) {
+ switch (clkdiv) {
+ case 64:
+ gpio_set_value(adau1701->gpio_pll_mode[0], 0);
+ gpio_set_value(adau1701->gpio_pll_mode[1], 0);
+ break;
+ case 256:
+ gpio_set_value(adau1701->gpio_pll_mode[0], 0);
+ gpio_set_value(adau1701->gpio_pll_mode[1], 1);
+ break;
+ case 384:
+ gpio_set_value(adau1701->gpio_pll_mode[0], 1);
+ gpio_set_value(adau1701->gpio_pll_mode[1], 0);
+ break;
+ case 0: /* fallback */
+ case 512:
+ gpio_set_value(adau1701->gpio_pll_mode[0], 1);
+ gpio_set_value(adau1701->gpio_pll_mode[1], 1);
+ break;
+ }
+ }
- ret = process_sigma_firmware(client, ADAU1701_FIRMWARE);
- if (ret) {
- dev_warn(codec->dev, "Failed to load firmware\n");
- return ret;
+ adau1701->pll_clkdiv = clkdiv;
+
+ if (gpio_is_valid(adau1701->gpio_nreset)) {
+ gpio_set_value(adau1701->gpio_nreset, 0);
+ /* minimum reset time is 20ns */
+ udelay(1);
+ gpio_set_value(adau1701->gpio_nreset, 1);
+ /* power-up time may be as long as 85ms */
+ mdelay(85);
+ }
+
+ /*
+ * Postpone the firmware download to a point in time when we
+ * know the correct PLL setup
+ */
+ if (clkdiv != ADAU1707_CLKDIV_UNSET) {
+ ret = process_sigma_firmware(client, ADAU1701_FIRMWARE);
+ if (ret) {
+ dev_warn(codec->dev, "Failed to load firmware\n");
+ return ret;
+ }
}
- snd_soc_write(codec, ADAU1701_DACSET, ADAU1701_DACSET_DACINIT);
+ regmap_write(adau1701->regmap, ADAU1701_DACSET, ADAU1701_DACSET_DACINIT);
+ regmap_write(adau1701->regmap, ADAU1701_DSPCTRL, ADAU1701_DSPCTRL_CR);
+
+ regcache_mark_dirty(adau1701->regmap);
+ regcache_sync(adau1701->regmap);
return 0;
}
@@ -253,7 +334,7 @@ static int adau1701_set_capture_pcm_format(struct snd_soc_codec *codec,
mask |= ADAU1701_SEROCTL_MSB_DEALY_MASK;
}
- snd_soc_update_bits(codec, ADAU1701_SEROCTL, mask, val);
+ regmap_update_bits(adau1701->regmap, ADAU1701_SEROCTL, mask, val);
return 0;
}
@@ -281,7 +362,7 @@ static int adau1701_set_playback_pcm_format(struct snd_soc_codec *codec,
return -EINVAL;
}
- snd_soc_update_bits(codec, ADAU1701_SERICTL,
+ regmap_update_bits(adau1701->regmap, ADAU1701_SERICTL,
ADAU1701_SERICTL_MODE_MASK, val);
return 0;
@@ -291,8 +372,22 @@ static int adau1701_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
+ struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
+ unsigned int clkdiv = adau1701->sysclk / params_rate(params);
snd_pcm_format_t format;
unsigned int val;
+ int ret;
+
+ /*
+ * If the mclk/lrclk ratio changes, the chip needs updated PLL
+ * mode GPIO settings, and a full reset cycle, including a new
+ * firmware upload.
+ */
+ if (clkdiv != adau1701->pll_clkdiv) {
+ ret = adau1701_reset(codec, clkdiv);
+ if (ret < 0)
+ return ret;
+ }
switch (params_rate(params)) {
case 192000:
@@ -308,7 +403,7 @@ static int adau1701_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
- snd_soc_update_bits(codec, ADAU1701_DSPCTRL,
+ regmap_update_bits(adau1701->regmap, ADAU1701_DSPCTRL,
ADAU1701_DSPCTRL_SR_MASK, val);
format = params_format(params);
@@ -384,8 +479,8 @@ static int adau1701_set_dai_fmt(struct snd_soc_dai *codec_dai,
adau1701->dai_fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
- snd_soc_write(codec, ADAU1701_SERICTL, serictl);
- snd_soc_update_bits(codec, ADAU1701_SEROCTL,
+ regmap_write(adau1701->regmap, ADAU1701_SERICTL, serictl);
+ regmap_update_bits(adau1701->regmap, ADAU1701_SEROCTL,
~ADAU1701_SEROCTL_WORD_LEN_MASK, seroctl);
return 0;
@@ -395,6 +490,7 @@ static int adau1701_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
unsigned int mask = ADAU1701_AUXNPOW_VBPD | ADAU1701_AUXNPOW_VRPD;
+ struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
switch (level) {
case SND_SOC_BIAS_ON:
@@ -403,11 +499,13 @@ static int adau1701_set_bias_level(struct snd_soc_codec *codec,
break;
case SND_SOC_BIAS_STANDBY:
/* Enable VREF and VREF buffer */
- snd_soc_update_bits(codec, ADAU1701_AUXNPOW, mask, 0x00);
+ regmap_update_bits(adau1701->regmap,
+ ADAU1701_AUXNPOW, mask, 0x00);
break;
case SND_SOC_BIAS_OFF:
/* Disable VREF and VREF buffer */
- snd_soc_update_bits(codec, ADAU1701_AUXNPOW, mask, mask);
+ regmap_update_bits(adau1701->regmap,
+ ADAU1701_AUXNPOW, mask, mask);
break;
}
@@ -419,6 +517,7 @@ static int adau1701_digital_mute(struct snd_soc_dai *dai, int mute)
{
struct snd_soc_codec *codec = dai->codec;
unsigned int mask = ADAU1701_DSPCTRL_DAM;
+ struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
unsigned int val;
if (mute)
@@ -426,7 +525,7 @@ static int adau1701_digital_mute(struct snd_soc_dai *dai, int mute)
else
val = mask;
- snd_soc_update_bits(codec, ADAU1701_DSPCTRL, mask, val);
+ regmap_update_bits(adau1701->regmap, ADAU1701_DSPCTRL, mask, val);
return 0;
}
@@ -435,6 +534,7 @@ static int adau1701_set_sysclk(struct snd_soc_codec *codec, int clk_id,
int source, unsigned int freq, int dir)
{
unsigned int val;
+ struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
switch (clk_id) {
case ADAU1701_CLK_SRC_OSC:
@@ -447,7 +547,9 @@ static int adau1701_set_sysclk(struct snd_soc_codec *codec, int clk_id,
return -EINVAL;
}
- snd_soc_update_bits(codec, ADAU1701_OSCIPOW, ADAU1701_OSCIPOW_OPD, val);
+ regmap_update_bits(adau1701->regmap, ADAU1701_OSCIPOW,
+ ADAU1701_OSCIPOW_OPD, val);
+ adau1701->sysclk = freq;
return 0;
}
@@ -494,15 +596,35 @@ MODULE_DEVICE_TABLE(of, adau1701_dt_ids);
static int adau1701_probe(struct snd_soc_codec *codec)
{
- int ret;
-
- codec->control_data = to_i2c_client(codec->dev);
+ int i, ret;
+ unsigned int val;
+ struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
- ret = adau1701_init(codec);
- if (ret)
+ /*
+ * Let the pll_clkdiv variable default to something that won't happen
+ * at runtime. That way, we can postpone the firmware download from
+ * adau1701_reset() to a point in time when we know the correct PLL
+ * mode parameters.
+ */
+ adau1701->pll_clkdiv = ADAU1707_CLKDIV_UNSET;
+
+ /* initalize with pre-configured pll mode settings */
+ ret = adau1701_reset(codec, adau1701->pll_clkdiv);
+ if (ret < 0)
return ret;
- snd_soc_write(codec, ADAU1701_DSPCTRL, ADAU1701_DSPCTRL_CR);
+ /* set up pin config */
+ val = 0;
+ for (i = 0; i < 6; i++)
+ val |= adau1701->pin_config[i] << (i * 4);
+
+ regmap_write(adau1701->regmap, ADAU1701_PINCONF_0, val);
+
+ val = 0;
+ for (i = 0; i < 6; i++)
+ val |= adau1701->pin_config[i + 6] << (i * 4);
+
+ regmap_write(adau1701->regmap, ADAU1701_PINCONF_1, val);
return 0;
}
@@ -512,9 +634,6 @@ static struct snd_soc_codec_driver adau1701_codec_drv = {
.set_bias_level = adau1701_set_bias_level,
.idle_bias_off = true,
- .reg_cache_size = ADAU1701_NUM_REGS,
- .reg_word_size = sizeof(u16),
-
.controls = adau1701_controls,
.num_controls = ARRAY_SIZE(adau1701_controls),
.dapm_widgets = adau1701_dapm_widgets,
@@ -522,28 +641,58 @@ static struct snd_soc_codec_driver adau1701_codec_drv = {
.dapm_routes = adau1701_dapm_routes,
.num_dapm_routes = ARRAY_SIZE(adau1701_dapm_routes),
- .write = adau1701_write,
- .read = adau1701_read,
-
.set_sysclk = adau1701_set_sysclk,
};
+static const struct regmap_config adau1701_regmap = {
+ .reg_bits = 16,
+ .val_bits = 32,
+ .max_register = ADAU1701_MAX_REGISTER,
+ .cache_type = REGCACHE_RBTREE,
+ .volatile_reg = adau1701_volatile_reg,
+ .reg_write = adau1701_reg_write,
+ .reg_read = adau1701_reg_read,
+};
+
static int adau1701_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct adau1701 *adau1701;
struct device *dev = &client->dev;
int gpio_nreset = -EINVAL;
+ int gpio_pll_mode[2] = { -EINVAL, -EINVAL };
int ret;
adau1701 = devm_kzalloc(dev, sizeof(*adau1701), GFP_KERNEL);
if (!adau1701)
return -ENOMEM;
+ adau1701->regmap = devm_regmap_init(dev, NULL, client,
+ &adau1701_regmap);
+ if (IS_ERR(adau1701->regmap))
+ return PTR_ERR(adau1701->regmap);
+
if (dev->of_node) {
gpio_nreset = of_get_named_gpio(dev->of_node, "reset-gpio", 0);
if (gpio_nreset < 0 && gpio_nreset != -ENOENT)
return gpio_nreset;
+
+ gpio_pll_mode[0] = of_get_named_gpio(dev->of_node,
+ "adi,pll-mode-gpios", 0);
+ if (gpio_pll_mode[0] < 0 && gpio_pll_mode[0] != -ENOENT)
+ return gpio_pll_mode[0];
+
+ gpio_pll_mode[1] = of_get_named_gpio(dev->of_node,
+ "adi,pll-mode-gpios", 1);
+ if (gpio_pll_mode[1] < 0 && gpio_pll_mode[1] != -ENOENT)
+ return gpio_pll_mode[1];
+
+ of_property_read_u32(dev->of_node, "adi,pll-clkdiv",
+ &adau1701->pll_clkdiv);
+
+ of_property_read_u8_array(dev->of_node, "adi,pin-config",
+ adau1701->pin_config,
+ ARRAY_SIZE(adau1701->pin_config));
}
if (gpio_is_valid(gpio_nreset)) {
@@ -553,7 +702,24 @@ static int adau1701_i2c_probe(struct i2c_client *client,
return ret;
}
+ if (gpio_is_valid(gpio_pll_mode[0]) &&
+ gpio_is_valid(gpio_pll_mode[1])) {
+ ret = devm_gpio_request_one(dev, gpio_pll_mode[0],
+ GPIOF_OUT_INIT_LOW,
+ "ADAU1701 PLL mode 0");
+ if (ret < 0)
+ return ret;
+
+ ret = devm_gpio_request_one(dev, gpio_pll_mode[1],
+ GPIOF_OUT_INIT_LOW,
+ "ADAU1701 PLL mode 1");
+ if (ret < 0)
+ return ret;
+ }
+
adau1701->gpio_nreset = gpio_nreset;
+ adau1701->gpio_pll_mode[0] = gpio_pll_mode[0];
+ adau1701->gpio_pll_mode[1] = gpio_pll_mode[1];
i2c_set_clientdata(client, adau1701);
ret = snd_soc_register_codec(&client->dev, &adau1701_codec_drv,
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c
index d441559..d659d3a 100644
--- a/sound/soc/codecs/sgtl5000.c
+++ b/sound/soc/codecs/sgtl5000.c
@@ -38,7 +38,7 @@
static const struct reg_default sgtl5000_reg_defaults[] = {
{ SGTL5000_CHIP_CLK_CTRL, 0x0008 },
{ SGTL5000_CHIP_I2S_CTRL, 0x0010 },
- { SGTL5000_CHIP_SSS_CTRL, 0x0008 },
+ { SGTL5000_CHIP_SSS_CTRL, 0x0010 },
{ SGTL5000_CHIP_DAC_VOL, 0x3c3c },
{ SGTL5000_CHIP_PAD_STRENGTH, 0x015f },
{ SGTL5000_CHIP_ANA_HP_CTRL, 0x1818 },
diff --git a/sound/soc/codecs/sgtl5000.h b/sound/soc/codecs/sgtl5000.h
index 4b69229..2f8c889 100644
--- a/sound/soc/codecs/sgtl5000.h
+++ b/sound/soc/codecs/sgtl5000.h
@@ -347,7 +347,7 @@
#define SGTL5000_PLL_INT_DIV_MASK 0xf800
#define SGTL5000_PLL_INT_DIV_SHIFT 11
#define SGTL5000_PLL_INT_DIV_WIDTH 5
-#define SGTL5000_PLL_FRAC_DIV_MASK 0x0700
+#define SGTL5000_PLL_FRAC_DIV_MASK 0x07ff
#define SGTL5000_PLL_FRAC_DIV_SHIFT 0
#define SGTL5000_PLL_FRAC_DIV_WIDTH 11
diff --git a/sound/soc/codecs/si476x.c b/sound/soc/codecs/si476x.c
index 721587c..73e205c 100644
--- a/sound/soc/codecs/si476x.c
+++ b/sound/soc/codecs/si476x.c
@@ -38,9 +38,9 @@ enum si476x_digital_io_output_format {
SI476X_DIGITAL_IO_SAMPLE_SIZE_SHIFT = 8,
};
-#define SI476X_DIGITAL_IO_OUTPUT_WIDTH_MASK ((0b111 << SI476X_DIGITAL_IO_SLOT_SIZE_SHIFT) | \
- (0b111 << SI476X_DIGITAL_IO_SAMPLE_SIZE_SHIFT))
-#define SI476X_DIGITAL_IO_OUTPUT_FORMAT_MASK (0b1111110)
+#define SI476X_DIGITAL_IO_OUTPUT_WIDTH_MASK ((0x7 << SI476X_DIGITAL_IO_SLOT_SIZE_SHIFT) | \
+ (0x7 << SI476X_DIGITAL_IO_SAMPLE_SIZE_SHIFT))
+#define SI476X_DIGITAL_IO_OUTPUT_FORMAT_MASK (0x7e)
enum si476x_daudio_formats {
SI476X_DAUDIO_MODE_I2S = (0x0 << 1),
diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c
index 2eda85ba..a5455c1 100644
--- a/sound/soc/codecs/stac9766.c
+++ b/sound/soc/codecs/stac9766.c
@@ -28,8 +28,6 @@
#include "stac9766.h"
-#define STAC9766_VERSION "0.10"
-
/*
* STAC9766 register cache
*/
@@ -145,14 +143,14 @@ static int stac9766_ac97_write(struct snd_soc_codec *codec, unsigned int reg,
if (reg > AC97_STAC_PAGE0) {
stac9766_ac97_write(codec, AC97_INT_PAGING, 0);
- soc_ac97_ops.write(codec->ac97, reg, val);
+ soc_ac97_ops->write(codec->ac97, reg, val);
stac9766_ac97_write(codec, AC97_INT_PAGING, 1);
return 0;
}
if (reg / 2 >= ARRAY_SIZE(stac9766_reg))
return -EIO;
- soc_ac97_ops.write(codec->ac97, reg, val);
+ soc_ac97_ops->write(codec->ac97, reg, val);
cache[reg / 2] = val;
return 0;
}
@@ -164,7 +162,7 @@ static unsigned int stac9766_ac97_read(struct snd_soc_codec *codec,
if (reg > AC97_STAC_PAGE0) {
stac9766_ac97_write(codec, AC97_INT_PAGING, 0);
- val = soc_ac97_ops.read(codec->ac97, reg - AC97_STAC_PAGE0);
+ val = soc_ac97_ops->read(codec->ac97, reg - AC97_STAC_PAGE0);
stac9766_ac97_write(codec, AC97_INT_PAGING, 1);
return val;
}
@@ -175,7 +173,7 @@ static unsigned int stac9766_ac97_read(struct snd_soc_codec *codec,
reg == AC97_INT_PAGING || reg == AC97_VENDOR_ID1 ||
reg == AC97_VENDOR_ID2) {
- val = soc_ac97_ops.read(codec->ac97, reg);
+ val = soc_ac97_ops->read(codec->ac97, reg);
return val;
}
return cache[reg / 2];
@@ -242,15 +240,15 @@ static int stac9766_set_bias_level(struct snd_soc_codec *codec,
static int stac9766_reset(struct snd_soc_codec *codec, int try_warm)
{
- if (try_warm && soc_ac97_ops.warm_reset) {
- soc_ac97_ops.warm_reset(codec->ac97);
+ if (try_warm && soc_ac97_ops->warm_reset) {
+ soc_ac97_ops->warm_reset(codec->ac97);
if (stac9766_ac97_read(codec, 0) == stac9766_reg[0])
return 1;
}
- soc_ac97_ops.reset(codec->ac97);
- if (soc_ac97_ops.warm_reset)
- soc_ac97_ops.warm_reset(codec->ac97);
+ soc_ac97_ops->reset(codec->ac97);
+ if (soc_ac97_ops->warm_reset)
+ soc_ac97_ops->warm_reset(codec->ac97);
if (stac9766_ac97_read(codec, 0) != stac9766_reg[0])
return -EIO;
return 0;
@@ -274,7 +272,7 @@ reset:
return -EIO;
}
codec->ac97->bus->ops->warm_reset(codec->ac97);
- id = soc_ac97_ops.read(codec->ac97, AC97_VENDOR_ID2);
+ id = soc_ac97_ops->read(codec->ac97, AC97_VENDOR_ID2);
if (id != 0x4c13) {
stac9766_reset(codec, 0);
reset++;
@@ -338,9 +336,7 @@ static int stac9766_codec_probe(struct snd_soc_codec *codec)
{
int ret = 0;
- printk(KERN_INFO "STAC9766 SoC Audio Codec %s\n", STAC9766_VERSION);
-
- ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
+ ret = snd_soc_new_ac97_codec(codec, soc_ac97_ops, 0);
if (ret < 0)
goto codec_err;
diff --git a/sound/soc/codecs/tas5086.c b/sound/soc/codecs/tas5086.c
index d447c4a..6d31d88 100644
--- a/sound/soc/codecs/tas5086.c
+++ b/sound/soc/codecs/tas5086.c
@@ -83,6 +83,14 @@
#define TAS5086_SPLIT_CAP_CHARGE 0x1a /* Split cap charge period register */
#define TAS5086_OSC_TRIM 0x1b /* Oscillator trim register */
#define TAS5086_BKNDERR 0x1c
+#define TAS5086_INPUT_MUX 0x20
+#define TAS5086_PWM_OUTPUT_MUX 0x25
+
+#define TAS5086_MAX_REGISTER TAS5086_PWM_OUTPUT_MUX
+
+#define TAS5086_PWM_START_MIDZ_FOR_START_1 (1 << 7)
+#define TAS5086_PWM_START_MIDZ_FOR_START_2 (1 << 6)
+#define TAS5086_PWM_START_CHANNEL_MASK (0x3f)
/*
* Default TAS5086 power-up configuration
@@ -119,9 +127,30 @@ static const struct reg_default tas5086_reg_defaults[] = {
{ 0x1c, 0x05 },
};
+static int tas5086_register_size(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case TAS5086_CLOCK_CONTROL ... TAS5086_BKNDERR:
+ return 1;
+ case TAS5086_INPUT_MUX:
+ case TAS5086_PWM_OUTPUT_MUX:
+ return 4;
+ }
+
+ dev_err(dev, "Unsupported register address: %d\n", reg);
+ return 0;
+}
+
static bool tas5086_accessible_reg(struct device *dev, unsigned int reg)
{
- return !((reg == 0x0f) || (reg >= 0x11 && reg <= 0x17));
+ switch (reg) {
+ case 0x0f:
+ case 0x11 ... 0x17:
+ case 0x1d ... 0x1f:
+ return false;
+ default:
+ return true;
+ }
}
static bool tas5086_volatile_reg(struct device *dev, unsigned int reg)
@@ -140,6 +169,76 @@ static bool tas5086_writeable_reg(struct device *dev, unsigned int reg)
return tas5086_accessible_reg(dev, reg) && (reg != TAS5086_DEV_ID);
}
+static int tas5086_reg_write(void *context, unsigned int reg,
+ unsigned int value)
+{
+ struct i2c_client *client = context;
+ unsigned int i, size;
+ uint8_t buf[5];
+ int ret;
+
+ size = tas5086_register_size(&client->dev, reg);
+ if (size == 0)
+ return -EINVAL;
+
+ buf[0] = reg;
+
+ for (i = size; i >= 1; --i) {
+ buf[i] = value;
+ value >>= 8;
+ }
+
+ ret = i2c_master_send(client, buf, size + 1);
+ if (ret == size + 1)
+ return 0;
+ else if (ret < 0)
+ return ret;
+ else
+ return -EIO;
+}
+
+static int tas5086_reg_read(void *context, unsigned int reg,
+ unsigned int *value)
+{
+ struct i2c_client *client = context;
+ uint8_t send_buf, recv_buf[4];
+ struct i2c_msg msgs[2];
+ unsigned int size;
+ unsigned int i;
+ int ret;
+
+ size = tas5086_register_size(&client->dev, reg);
+ if (size == 0)
+ return -EINVAL;
+
+ send_buf = reg;
+
+ msgs[0].addr = client->addr;
+ msgs[0].len = sizeof(send_buf);
+ msgs[0].buf = &send_buf;
+ msgs[0].flags = 0;
+
+ msgs[1].addr = client->addr;
+ msgs[1].len = size;
+ msgs[1].buf = recv_buf;
+ msgs[1].flags = I2C_M_RD;
+
+ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+ if (ret < 0)
+ return ret;
+ else if (ret != ARRAY_SIZE(msgs))
+ return -EIO;
+
+ *value = 0;
+
+ for (i = 0; i < size; i++) {
+ *value <<= 8;
+ *value |= recv_buf[i];
+ }
+
+ return 0;
+}
+
struct tas5086_private {
struct regmap *regmap;
unsigned int mclk, sclk;
@@ -376,6 +475,202 @@ static const struct snd_kcontrol_new tas5086_controls[] = {
tas5086_get_deemph, tas5086_put_deemph),
};
+/* Input mux controls */
+static const char *tas5086_dapm_sdin_texts[] =
+{
+ "SDIN1-L", "SDIN1-R", "SDIN2-L", "SDIN2-R",
+ "SDIN3-L", "SDIN3-R", "Ground (0)", "nc"
+};
+
+static const struct soc_enum tas5086_dapm_input_mux_enum[] = {
+ SOC_ENUM_SINGLE(TAS5086_INPUT_MUX, 20, 8, tas5086_dapm_sdin_texts),
+ SOC_ENUM_SINGLE(TAS5086_INPUT_MUX, 16, 8, tas5086_dapm_sdin_texts),
+ SOC_ENUM_SINGLE(TAS5086_INPUT_MUX, 12, 8, tas5086_dapm_sdin_texts),
+ SOC_ENUM_SINGLE(TAS5086_INPUT_MUX, 8, 8, tas5086_dapm_sdin_texts),
+ SOC_ENUM_SINGLE(TAS5086_INPUT_MUX, 4, 8, tas5086_dapm_sdin_texts),
+ SOC_ENUM_SINGLE(TAS5086_INPUT_MUX, 0, 8, tas5086_dapm_sdin_texts),
+};
+
+static const struct snd_kcontrol_new tas5086_dapm_input_mux_controls[] = {
+ SOC_DAPM_ENUM("Channel 1 input", tas5086_dapm_input_mux_enum[0]),
+ SOC_DAPM_ENUM("Channel 2 input", tas5086_dapm_input_mux_enum[1]),
+ SOC_DAPM_ENUM("Channel 3 input", tas5086_dapm_input_mux_enum[2]),
+ SOC_DAPM_ENUM("Channel 4 input", tas5086_dapm_input_mux_enum[3]),
+ SOC_DAPM_ENUM("Channel 5 input", tas5086_dapm_input_mux_enum[4]),
+ SOC_DAPM_ENUM("Channel 6 input", tas5086_dapm_input_mux_enum[5]),
+};
+
+/* Output mux controls */
+static const char *tas5086_dapm_channel_texts[] =
+ { "Channel 1 Mux", "Channel 2 Mux", "Channel 3 Mux",
+ "Channel 4 Mux", "Channel 5 Mux", "Channel 6 Mux" };
+
+static const struct soc_enum tas5086_dapm_output_mux_enum[] = {
+ SOC_ENUM_SINGLE(TAS5086_PWM_OUTPUT_MUX, 20, 6, tas5086_dapm_channel_texts),
+ SOC_ENUM_SINGLE(TAS5086_PWM_OUTPUT_MUX, 16, 6, tas5086_dapm_channel_texts),
+ SOC_ENUM_SINGLE(TAS5086_PWM_OUTPUT_MUX, 12, 6, tas5086_dapm_channel_texts),
+ SOC_ENUM_SINGLE(TAS5086_PWM_OUTPUT_MUX, 8, 6, tas5086_dapm_channel_texts),
+ SOC_ENUM_SINGLE(TAS5086_PWM_OUTPUT_MUX, 4, 6, tas5086_dapm_channel_texts),
+ SOC_ENUM_SINGLE(TAS5086_PWM_OUTPUT_MUX, 0, 6, tas5086_dapm_channel_texts),
+};
+
+static const struct snd_kcontrol_new tas5086_dapm_output_mux_controls[] = {
+ SOC_DAPM_ENUM("PWM1 Output", tas5086_dapm_output_mux_enum[0]),
+ SOC_DAPM_ENUM("PWM2 Output", tas5086_dapm_output_mux_enum[1]),
+ SOC_DAPM_ENUM("PWM3 Output", tas5086_dapm_output_mux_enum[2]),
+ SOC_DAPM_ENUM("PWM4 Output", tas5086_dapm_output_mux_enum[3]),
+ SOC_DAPM_ENUM("PWM5 Output", tas5086_dapm_output_mux_enum[4]),
+ SOC_DAPM_ENUM("PWM6 Output", tas5086_dapm_output_mux_enum[5]),
+};
+
+static const struct snd_soc_dapm_widget tas5086_dapm_widgets[] = {
+ SND_SOC_DAPM_INPUT("SDIN1-L"),
+ SND_SOC_DAPM_INPUT("SDIN1-R"),
+ SND_SOC_DAPM_INPUT("SDIN2-L"),
+ SND_SOC_DAPM_INPUT("SDIN2-R"),
+ SND_SOC_DAPM_INPUT("SDIN3-L"),
+ SND_SOC_DAPM_INPUT("SDIN3-R"),
+ SND_SOC_DAPM_INPUT("SDIN4-L"),
+ SND_SOC_DAPM_INPUT("SDIN4-R"),
+
+ SND_SOC_DAPM_OUTPUT("PWM1"),
+ SND_SOC_DAPM_OUTPUT("PWM2"),
+ SND_SOC_DAPM_OUTPUT("PWM3"),
+ SND_SOC_DAPM_OUTPUT("PWM4"),
+ SND_SOC_DAPM_OUTPUT("PWM5"),
+ SND_SOC_DAPM_OUTPUT("PWM6"),
+
+ SND_SOC_DAPM_MUX("Channel 1 Mux", SND_SOC_NOPM, 0, 0,
+ &tas5086_dapm_input_mux_controls[0]),
+ SND_SOC_DAPM_MUX("Channel 2 Mux", SND_SOC_NOPM, 0, 0,
+ &tas5086_dapm_input_mux_controls[1]),
+ SND_SOC_DAPM_MUX("Channel 3 Mux", SND_SOC_NOPM, 0, 0,
+ &tas5086_dapm_input_mux_controls[2]),
+ SND_SOC_DAPM_MUX("Channel 4 Mux", SND_SOC_NOPM, 0, 0,
+ &tas5086_dapm_input_mux_controls[3]),
+ SND_SOC_DAPM_MUX("Channel 5 Mux", SND_SOC_NOPM, 0, 0,
+ &tas5086_dapm_input_mux_controls[4]),
+ SND_SOC_DAPM_MUX("Channel 6 Mux", SND_SOC_NOPM, 0, 0,
+ &tas5086_dapm_input_mux_controls[5]),
+
+ SND_SOC_DAPM_MUX("PWM1 Mux", SND_SOC_NOPM, 0, 0,
+ &tas5086_dapm_output_mux_controls[0]),
+ SND_SOC_DAPM_MUX("PWM2 Mux", SND_SOC_NOPM, 0, 0,
+ &tas5086_dapm_output_mux_controls[1]),
+ SND_SOC_DAPM_MUX("PWM3 Mux", SND_SOC_NOPM, 0, 0,
+ &tas5086_dapm_output_mux_controls[2]),
+ SND_SOC_DAPM_MUX("PWM4 Mux", SND_SOC_NOPM, 0, 0,
+ &tas5086_dapm_output_mux_controls[3]),
+ SND_SOC_DAPM_MUX("PWM5 Mux", SND_SOC_NOPM, 0, 0,
+ &tas5086_dapm_output_mux_controls[4]),
+ SND_SOC_DAPM_MUX("PWM6 Mux", SND_SOC_NOPM, 0, 0,
+ &tas5086_dapm_output_mux_controls[5]),
+};
+
+static const struct snd_soc_dapm_route tas5086_dapm_routes[] = {
+ /* SDIN inputs -> channel muxes */
+ { "Channel 1 Mux", "SDIN1-L", "SDIN1-L" },
+ { "Channel 1 Mux", "SDIN1-R", "SDIN1-R" },
+ { "Channel 1 Mux", "SDIN2-L", "SDIN2-L" },
+ { "Channel 1 Mux", "SDIN2-R", "SDIN2-R" },
+ { "Channel 1 Mux", "SDIN3-L", "SDIN3-L" },
+ { "Channel 1 Mux", "SDIN3-R", "SDIN3-R" },
+
+ { "Channel 2 Mux", "SDIN1-L", "SDIN1-L" },
+ { "Channel 2 Mux", "SDIN1-R", "SDIN1-R" },
+ { "Channel 2 Mux", "SDIN2-L", "SDIN2-L" },
+ { "Channel 2 Mux", "SDIN2-R", "SDIN2-R" },
+ { "Channel 2 Mux", "SDIN3-L", "SDIN3-L" },
+ { "Channel 2 Mux", "SDIN3-R", "SDIN3-R" },
+
+ { "Channel 2 Mux", "SDIN1-L", "SDIN1-L" },
+ { "Channel 2 Mux", "SDIN1-R", "SDIN1-R" },
+ { "Channel 2 Mux", "SDIN2-L", "SDIN2-L" },
+ { "Channel 2 Mux", "SDIN2-R", "SDIN2-R" },
+ { "Channel 2 Mux", "SDIN3-L", "SDIN3-L" },
+ { "Channel 2 Mux", "SDIN3-R", "SDIN3-R" },
+
+ { "Channel 3 Mux", "SDIN1-L", "SDIN1-L" },
+ { "Channel 3 Mux", "SDIN1-R", "SDIN1-R" },
+ { "Channel 3 Mux", "SDIN2-L", "SDIN2-L" },
+ { "Channel 3 Mux", "SDIN2-R", "SDIN2-R" },
+ { "Channel 3 Mux", "SDIN3-L", "SDIN3-L" },
+ { "Channel 3 Mux", "SDIN3-R", "SDIN3-R" },
+
+ { "Channel 4 Mux", "SDIN1-L", "SDIN1-L" },
+ { "Channel 4 Mux", "SDIN1-R", "SDIN1-R" },
+ { "Channel 4 Mux", "SDIN2-L", "SDIN2-L" },
+ { "Channel 4 Mux", "SDIN2-R", "SDIN2-R" },
+ { "Channel 4 Mux", "SDIN3-L", "SDIN3-L" },
+ { "Channel 4 Mux", "SDIN3-R", "SDIN3-R" },
+
+ { "Channel 5 Mux", "SDIN1-L", "SDIN1-L" },
+ { "Channel 5 Mux", "SDIN1-R", "SDIN1-R" },
+ { "Channel 5 Mux", "SDIN2-L", "SDIN2-L" },
+ { "Channel 5 Mux", "SDIN2-R", "SDIN2-R" },
+ { "Channel 5 Mux", "SDIN3-L", "SDIN3-L" },
+ { "Channel 5 Mux", "SDIN3-R", "SDIN3-R" },
+
+ { "Channel 6 Mux", "SDIN1-L", "SDIN1-L" },
+ { "Channel 6 Mux", "SDIN1-R", "SDIN1-R" },
+ { "Channel 6 Mux", "SDIN2-L", "SDIN2-L" },
+ { "Channel 6 Mux", "SDIN2-R", "SDIN2-R" },
+ { "Channel 6 Mux", "SDIN3-L", "SDIN3-L" },
+ { "Channel 6 Mux", "SDIN3-R", "SDIN3-R" },
+
+ /* Channel muxes -> PWM muxes */
+ { "PWM1 Mux", "Channel 1 Mux", "Channel 1 Mux" },
+ { "PWM2 Mux", "Channel 1 Mux", "Channel 1 Mux" },
+ { "PWM3 Mux", "Channel 1 Mux", "Channel 1 Mux" },
+ { "PWM4 Mux", "Channel 1 Mux", "Channel 1 Mux" },
+ { "PWM5 Mux", "Channel 1 Mux", "Channel 1 Mux" },
+ { "PWM6 Mux", "Channel 1 Mux", "Channel 1 Mux" },
+
+ { "PWM1 Mux", "Channel 2 Mux", "Channel 2 Mux" },
+ { "PWM2 Mux", "Channel 2 Mux", "Channel 2 Mux" },
+ { "PWM3 Mux", "Channel 2 Mux", "Channel 2 Mux" },
+ { "PWM4 Mux", "Channel 2 Mux", "Channel 2 Mux" },
+ { "PWM5 Mux", "Channel 2 Mux", "Channel 2 Mux" },
+ { "PWM6 Mux", "Channel 2 Mux", "Channel 2 Mux" },
+
+ { "PWM1 Mux", "Channel 3 Mux", "Channel 3 Mux" },
+ { "PWM2 Mux", "Channel 3 Mux", "Channel 3 Mux" },
+ { "PWM3 Mux", "Channel 3 Mux", "Channel 3 Mux" },
+ { "PWM4 Mux", "Channel 3 Mux", "Channel 3 Mux" },
+ { "PWM5 Mux", "Channel 3 Mux", "Channel 3 Mux" },
+ { "PWM6 Mux", "Channel 3 Mux", "Channel 3 Mux" },
+
+ { "PWM1 Mux", "Channel 4 Mux", "Channel 4 Mux" },
+ { "PWM2 Mux", "Channel 4 Mux", "Channel 4 Mux" },
+ { "PWM3 Mux", "Channel 4 Mux", "Channel 4 Mux" },
+ { "PWM4 Mux", "Channel 4 Mux", "Channel 4 Mux" },
+ { "PWM5 Mux", "Channel 4 Mux", "Channel 4 Mux" },
+ { "PWM6 Mux", "Channel 4 Mux", "Channel 4 Mux" },
+
+ { "PWM1 Mux", "Channel 5 Mux", "Channel 5 Mux" },
+ { "PWM2 Mux", "Channel 5 Mux", "Channel 5 Mux" },
+ { "PWM3 Mux", "Channel 5 Mux", "Channel 5 Mux" },
+ { "PWM4 Mux", "Channel 5 Mux", "Channel 5 Mux" },
+ { "PWM5 Mux", "Channel 5 Mux", "Channel 5 Mux" },
+ { "PWM6 Mux", "Channel 5 Mux", "Channel 5 Mux" },
+
+ { "PWM1 Mux", "Channel 6 Mux", "Channel 6 Mux" },
+ { "PWM2 Mux", "Channel 6 Mux", "Channel 6 Mux" },
+ { "PWM3 Mux", "Channel 6 Mux", "Channel 6 Mux" },
+ { "PWM4 Mux", "Channel 6 Mux", "Channel 6 Mux" },
+ { "PWM5 Mux", "Channel 6 Mux", "Channel 6 Mux" },
+ { "PWM6 Mux", "Channel 6 Mux", "Channel 6 Mux" },
+
+ /* The PWM muxes are directly connected to the PWM outputs */
+ { "PWM1", NULL, "PWM1 Mux" },
+ { "PWM2", NULL, "PWM2 Mux" },
+ { "PWM3", NULL, "PWM3 Mux" },
+ { "PWM4", NULL, "PWM4 Mux" },
+ { "PWM5", NULL, "PWM5 Mux" },
+ { "PWM6", NULL, "PWM6 Mux" },
+
+};
+
static const struct snd_soc_dai_ops tas5086_dai_ops = {
.hw_params = tas5086_hw_params,
.set_sysclk = tas5086_set_dai_sysclk,
@@ -426,13 +721,34 @@ static int tas5086_probe(struct snd_soc_codec *codec)
{
struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
int charge_period = 1300000; /* hardware default is 1300 ms */
+ u8 pwm_start_mid_z = 0;
int i, ret;
if (of_match_device(of_match_ptr(tas5086_dt_ids), codec->dev)) {
struct device_node *of_node = codec->dev->of_node;
of_property_read_u32(of_node, "ti,charge-period", &charge_period);
+
+ for (i = 0; i < 6; i++) {
+ char name[25];
+
+ snprintf(name, sizeof(name),
+ "ti,mid-z-channel-%d", i + 1);
+
+ if (of_get_property(of_node, name, NULL) != NULL)
+ pwm_start_mid_z |= 1 << i;
+ }
}
+ /*
+ * If any of the channels is configured to start in Mid-Z mode,
+ * configure 'part 1' of the PWM starts to use Mid-Z, and tell
+ * all configured mid-z channels to start start under 'part 1'.
+ */
+ if (pwm_start_mid_z)
+ regmap_write(priv->regmap, TAS5086_PWM_START,
+ TAS5086_PWM_START_MIDZ_FOR_START_1 |
+ pwm_start_mid_z);
+
/* lookup and set split-capacitor charge period */
if (charge_period == 0) {
regmap_write(priv->regmap, TAS5086_SPLIT_CAP_CHARGE, 0);
@@ -490,6 +806,10 @@ static struct snd_soc_codec_driver soc_codec_dev_tas5086 = {
.resume = tas5086_soc_resume,
.controls = tas5086_controls,
.num_controls = ARRAY_SIZE(tas5086_controls),
+ .dapm_widgets = tas5086_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(tas5086_dapm_widgets),
+ .dapm_routes = tas5086_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(tas5086_dapm_routes),
};
static const struct i2c_device_id tas5086_i2c_id[] = {
@@ -500,14 +820,16 @@ MODULE_DEVICE_TABLE(i2c, tas5086_i2c_id);
static const struct regmap_config tas5086_regmap = {
.reg_bits = 8,
- .val_bits = 8,
- .max_register = ARRAY_SIZE(tas5086_reg_defaults),
+ .val_bits = 32,
+ .max_register = TAS5086_MAX_REGISTER,
.reg_defaults = tas5086_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(tas5086_reg_defaults),
.cache_type = REGCACHE_RBTREE,
.volatile_reg = tas5086_volatile_reg,
.writeable_reg = tas5086_writeable_reg,
.readable_reg = tas5086_accessible_reg,
+ .reg_read = tas5086_reg_read,
+ .reg_write = tas5086_reg_write,
};
static int tas5086_i2c_probe(struct i2c_client *i2c,
@@ -522,7 +844,7 @@ static int tas5086_i2c_probe(struct i2c_client *i2c,
if (!priv)
return -ENOMEM;
- priv->regmap = devm_regmap_init_i2c(i2c, &tas5086_regmap);
+ priv->regmap = devm_regmap_init(dev, NULL, i2c, &tas5086_regmap);
if (IS_ERR(priv->regmap)) {
ret = PTR_ERR(priv->regmap);
dev_err(&i2c->dev, "Failed to create regmap: %d\n", ret);
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index 1514bf84..e5b9268 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -128,10 +128,8 @@ static const u8 aic3x_reg[AIC3X_CACHEREGNUM] = {
};
#define SOC_DAPM_SINGLE_AIC3X(xname, reg, shift, mask, invert) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
- .info = snd_soc_info_volsw, \
- .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw_aic3x, \
- .private_value = SOC_SINGLE_VALUE(reg, shift, mask, invert) }
+ SOC_SINGLE_EXT(xname, reg, shift, mask, invert, \
+ snd_soc_dapm_get_volsw, snd_soc_dapm_put_volsw_aic3x)
/*
* All input lines are connected when !0xf and disconnected with 0xf bit field,
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c
index 9b9a6e5..44621dd 100644
--- a/sound/soc/codecs/twl6040.c
+++ b/sound/soc/codecs/twl6040.c
@@ -38,6 +38,14 @@
#include "twl6040.h"
+enum twl6040_dai_id {
+ TWL6040_DAI_LEGACY = 0,
+ TWL6040_DAI_UL,
+ TWL6040_DAI_DL1,
+ TWL6040_DAI_DL2,
+ TWL6040_DAI_VIB,
+};
+
#define TWL6040_RATES SNDRV_PCM_RATE_8000_96000
#define TWL6040_FORMATS (SNDRV_PCM_FMTBIT_S32_LE)
@@ -67,6 +75,8 @@ struct twl6040_data {
int pll_power_mode;
int hs_power_mode;
int hs_power_mode_locked;
+ bool dl1_unmuted;
+ bool dl2_unmuted;
unsigned int clk_in;
unsigned int sysclk;
struct twl6040_jack_data hs_jack;
@@ -220,6 +230,25 @@ static int twl6040_read_reg_volatile(struct snd_soc_codec *codec,
return value;
}
+static bool twl6040_is_path_unmuted(struct snd_soc_codec *codec,
+ unsigned int reg)
+{
+ struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
+
+ switch (reg) {
+ case TWL6040_REG_HSLCTL:
+ case TWL6040_REG_HSRCTL:
+ case TWL6040_REG_EARCTL:
+ /* DL1 path */
+ return priv->dl1_unmuted;
+ case TWL6040_REG_HFLCTL:
+ case TWL6040_REG_HFRCTL:
+ return priv->dl2_unmuted;
+ default:
+ return 1;
+ };
+}
+
/*
* write to the twl6040 register space
*/
@@ -232,7 +261,8 @@ static int twl6040_write(struct snd_soc_codec *codec,
return -EIO;
twl6040_write_reg_cache(codec, reg, value);
- if (likely(reg < TWL6040_REG_SW_SHADOW))
+ if (likely(reg < TWL6040_REG_SW_SHADOW) &&
+ twl6040_is_path_unmuted(codec, reg))
return twl6040_reg_write(twl6040, reg, value);
else
return 0;
@@ -1026,16 +1056,84 @@ static int twl6040_set_dai_sysclk(struct snd_soc_dai *codec_dai,
return 0;
}
+static void twl6040_mute_path(struct snd_soc_codec *codec, enum twl6040_dai_id id,
+ int mute)
+{
+ struct twl6040 *twl6040 = codec->control_data;
+ struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
+ int hslctl, hsrctl, earctl;
+ int hflctl, hfrctl;
+
+ switch (id) {
+ case TWL6040_DAI_DL1:
+ hslctl = twl6040_read_reg_cache(codec, TWL6040_REG_HSLCTL);
+ hsrctl = twl6040_read_reg_cache(codec, TWL6040_REG_HSRCTL);
+ earctl = twl6040_read_reg_cache(codec, TWL6040_REG_EARCTL);
+
+ if (mute) {
+ /* Power down drivers and DACs */
+ earctl &= ~0x01;
+ hslctl &= ~(TWL6040_HSDRVENA | TWL6040_HSDACENA);
+ hsrctl &= ~(TWL6040_HSDRVENA | TWL6040_HSDACENA);
+
+ }
+
+ twl6040_reg_write(twl6040, TWL6040_REG_EARCTL, earctl);
+ twl6040_reg_write(twl6040, TWL6040_REG_HSLCTL, hslctl);
+ twl6040_reg_write(twl6040, TWL6040_REG_HSRCTL, hsrctl);
+ priv->dl1_unmuted = !mute;
+ break;
+ case TWL6040_DAI_DL2:
+ hflctl = twl6040_read_reg_cache(codec, TWL6040_REG_HFLCTL);
+ hfrctl = twl6040_read_reg_cache(codec, TWL6040_REG_HFRCTL);
+
+ if (mute) {
+ /* Power down drivers and DACs */
+ hflctl &= ~(TWL6040_HFDACENA | TWL6040_HFPGAENA |
+ TWL6040_HFDRVENA);
+ hfrctl &= ~(TWL6040_HFDACENA | TWL6040_HFPGAENA |
+ TWL6040_HFDRVENA);
+ }
+
+ twl6040_reg_write(twl6040, TWL6040_REG_HFLCTL, hflctl);
+ twl6040_reg_write(twl6040, TWL6040_REG_HFRCTL, hfrctl);
+ priv->dl2_unmuted = !mute;
+ break;
+ default:
+ break;
+ };
+}
+
+static int twl6040_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+ switch (dai->id) {
+ case TWL6040_DAI_LEGACY:
+ twl6040_mute_path(dai->codec, TWL6040_DAI_DL1, mute);
+ twl6040_mute_path(dai->codec, TWL6040_DAI_DL2, mute);
+ break;
+ case TWL6040_DAI_DL1:
+ case TWL6040_DAI_DL2:
+ twl6040_mute_path(dai->codec, dai->id, mute);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
static const struct snd_soc_dai_ops twl6040_dai_ops = {
.startup = twl6040_startup,
.hw_params = twl6040_hw_params,
.prepare = twl6040_prepare,
.set_sysclk = twl6040_set_dai_sysclk,
+ .digital_mute = twl6040_digital_mute,
};
static struct snd_soc_dai_driver twl6040_dai[] = {
{
.name = "twl6040-legacy",
+ .id = TWL6040_DAI_LEGACY,
.playback = {
.stream_name = "Legacy Playback",
.channels_min = 1,
@@ -1054,6 +1152,7 @@ static struct snd_soc_dai_driver twl6040_dai[] = {
},
{
.name = "twl6040-ul",
+ .id = TWL6040_DAI_UL,
.capture = {
.stream_name = "Capture",
.channels_min = 1,
@@ -1065,6 +1164,7 @@ static struct snd_soc_dai_driver twl6040_dai[] = {
},
{
.name = "twl6040-dl1",
+ .id = TWL6040_DAI_DL1,
.playback = {
.stream_name = "Headset Playback",
.channels_min = 1,
@@ -1076,6 +1176,7 @@ static struct snd_soc_dai_driver twl6040_dai[] = {
},
{
.name = "twl6040-dl2",
+ .id = TWL6040_DAI_DL2,
.playback = {
.stream_name = "Handsfree Playback",
.channels_min = 1,
@@ -1087,6 +1188,7 @@ static struct snd_soc_dai_driver twl6040_dai[] = {
},
{
.name = "twl6040-vib",
+ .id = TWL6040_DAI_VIB,
.playback = {
.stream_name = "Vibra Playback",
.channels_min = 1,
@@ -1143,7 +1245,7 @@ static int twl6040_probe(struct snd_soc_codec *codec)
mutex_init(&priv->mutex);
- ret = devm_request_threaded_irq(codec->dev, priv->plug_irq, NULL,
+ ret = request_threaded_irq(priv->plug_irq, NULL,
twl6040_audio_handler, IRQF_NO_SUSPEND,
"twl6040_irq_plug", codec);
if (ret) {
@@ -1159,6 +1261,9 @@ static int twl6040_probe(struct snd_soc_codec *codec)
static int twl6040_remove(struct snd_soc_codec *codec)
{
+ struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
+
+ free_irq(priv->plug_irq, codec);
twl6040_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c
index af6d227..d2a0928 100644
--- a/sound/soc/codecs/wm8400.c
+++ b/sound/soc/codecs/wm8400.c
@@ -143,13 +143,8 @@ static int wm8400_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol,
}
#define WM8400_OUTPGA_SINGLE_R_TLV(xname, reg, shift, max, invert, tlv_array) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
- .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
- SNDRV_CTL_ELEM_ACCESS_READWRITE,\
- .tlv.p = (tlv_array), \
- .info = snd_soc_info_volsw, \
- .get = snd_soc_get_volsw, .put = wm8400_outpga_put_volsw_vu, \
- .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) }
+ SOC_SINGLE_EXT_TLV(xname, reg, shift, max, invert, \
+ snd_soc_get_volsw, wm8400_outpga_put_volsw_vu, tlv_array)
static const char *wm8400_digital_sidetone[] =
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c
index 9d88437..fa24ced 100644
--- a/sound/soc/codecs/wm8903.c
+++ b/sound/soc/codecs/wm8903.c
@@ -403,10 +403,8 @@ static int wm8903_class_w_put(struct snd_kcontrol *kcontrol,
}
#define SOC_DAPM_SINGLE_W(xname, reg, shift, max, invert) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
- .info = snd_soc_info_volsw, \
- .get = snd_soc_dapm_get_volsw, .put = wm8903_class_w_put, \
- .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) }
+ SOC_SINGLE_EXT(xname, reg, shift, max, invert, \
+ snd_soc_dapm_get_volsw, wm8903_class_w_put)
static int wm8903_deemph[] = { 0, 32000, 44100, 48000 };
diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c
index 3ff195c..4c9fb14 100644
--- a/sound/soc/codecs/wm8904.c
+++ b/sound/soc/codecs/wm8904.c
@@ -603,13 +603,8 @@ SOC_DOUBLE_R("Capture Switch", WM8904_ANALOGUE_LEFT_INPUT_0,
SOC_SINGLE("High Pass Filter Switch", WM8904_ADC_DIGITAL_0, 4, 1, 0),
SOC_ENUM("High Pass Filter Mode", hpf_mode),
-
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "ADC 128x OSR Switch",
- .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,
- .put = wm8904_adc_osr_put,
- .private_value = SOC_SINGLE_VALUE(WM8904_ANALOGUE_ADC_0, 0, 1, 0),
-},
+SOC_SINGLE_EXT("ADC 128x OSR Switch", WM8904_ANALOGUE_ADC_0, 0, 1, 0,
+ snd_soc_get_volsw, wm8904_adc_osr_put),
};
static const char *drc_path_text[] = {
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
index b1dc7d4..e2de9ec 100644
--- a/sound/soc/codecs/wm8962.c
+++ b/sound/soc/codecs/wm8962.c
@@ -3377,7 +3377,7 @@ static int wm8962_probe(struct snd_soc_codec *codec)
{
int ret;
struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
- struct wm8962_pdata *pdata = dev_get_platdata(codec->dev);
+ struct wm8962_pdata *pdata = &wm8962->pdata;
int i, trigger, irq_pol;
bool dmicclk, dmicdat;
diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c
index 029f31c..d8fc531 100644
--- a/sound/soc/codecs/wm8978.c
+++ b/sound/soc/codecs/wm8978.c
@@ -921,6 +921,7 @@ static struct snd_soc_dai_driver wm8978_dai = {
.formats = WM8978_FORMATS,
},
.ops = &wm8978_dai_ops,
+ .symmetric_rates = 1,
};
static int wm8978_suspend(struct snd_soc_codec *codec)
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c
index 837978e..253c88b 100644
--- a/sound/soc/codecs/wm8990.c
+++ b/sound/soc/codecs/wm8990.c
@@ -151,14 +151,9 @@ static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol,
}
#define SOC_WM899X_OUTPGA_SINGLE_R_TLV(xname, reg, shift, max, invert,\
- tlv_array) {\
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
- .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
- SNDRV_CTL_ELEM_ACCESS_READWRITE,\
- .tlv.p = (tlv_array), \
- .info = snd_soc_info_volsw, \
- .get = snd_soc_get_volsw, .put = wm899x_outpga_put_volsw_vu, \
- .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) }
+ tlv_array) \
+ SOC_SINGLE_EXT_TLV(xname, reg, shift, max, invert, \
+ snd_soc_get_volsw, wm899x_outpga_put_volsw_vu, tlv_array)
static const char *wm8990_digital_sidetone[] =
diff --git a/sound/soc/codecs/wm8991.h b/sound/soc/codecs/wm8991.h
index 8a942ef..07707d8 100644
--- a/sound/soc/codecs/wm8991.h
+++ b/sound/soc/codecs/wm8991.h
@@ -822,12 +822,7 @@
#define SOC_WM899X_OUTPGA_SINGLE_R_TLV(xname, reg, shift, max, invert,\
tlv_array) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
- .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
- SNDRV_CTL_ELEM_ACCESS_READWRITE,\
- .tlv.p = (tlv_array), \
- .info = snd_soc_info_volsw, \
- .get = snd_soc_get_volsw, .put = wm899x_outpga_put_volsw_vu, \
- .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) }
+ SOC_SINGLE_EXT_TLV(xname, reg, shift, max, invert, \
+ snd_soc_get_volsw, wm899x_outpga_put_volsw_vu, tlv_array)
#endif /* _WM8991_H */
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index 1b89aa9..ba832b7 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -290,10 +290,8 @@ static const DECLARE_TLV_DB_SCALE(ng_tlv, -10200, 600, 0);
static const DECLARE_TLV_DB_SCALE(mixin_boost_tlv, 0, 900, 0);
#define WM8994_DRC_SWITCH(xname, reg, shift) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
- .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
- .put = wm8994_put_drc_sw, \
- .private_value = SOC_SINGLE_VALUE(reg, shift, 1, 0) }
+ SOC_SINGLE_EXT(xname, reg, shift, 1, 0, \
+ snd_soc_get_volsw, wm8994_put_drc_sw)
static int wm8994_put_drc_sw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
@@ -1433,10 +1431,8 @@ SOC_DAPM_SINGLE("AIF1.1 Switch", WM8994_DAC2_RIGHT_MIXER_ROUTING,
};
#define WM8994_CLASS_W_SWITCH(xname, reg, shift, max, invert) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
- .info = snd_soc_info_volsw, \
- .get = snd_soc_dapm_get_volsw, .put = wm8994_put_class_w, \
- .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) }
+ SOC_SINGLE_EXT(xname, reg, shift, max, invert, \
+ snd_soc_get_volsw, wm8994_put_class_w)
static int wm8994_put_class_w(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
diff --git a/sound/soc/codecs/wm8995.h b/sound/soc/codecs/wm8995.h
index 5642121..508ad27 100644
--- a/sound/soc/codecs/wm8995.h
+++ b/sound/soc/codecs/wm8995.h
@@ -4237,11 +4237,8 @@
#define WM8995_SPK2_MUTE_SEQ1_WIDTH 8 /* SPK2_MUTE_SEQ1 - [7:0] */
#define WM8995_CLASS_W_SWITCH(xname, reg, shift, max, invert) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
- .info = snd_soc_info_volsw, \
- .get = snd_soc_dapm_get_volsw, .put = wm8995_put_class_w, \
- .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) \
-}
+ SOC_SINGLE_EXT(xname, reg, shift, max, invert, \
+ snd_soc_dapm_get_volsw, wm8995_put_class_w)
struct wm8995_reg_access {
u16 read;
diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c
index 05b1f34..70ce6793 100644
--- a/sound/soc/codecs/wm9705.c
+++ b/sound/soc/codecs/wm9705.c
@@ -209,7 +209,7 @@ static unsigned int ac97_read(struct snd_soc_codec *codec, unsigned int reg)
case AC97_RESET:
case AC97_VENDOR_ID1:
case AC97_VENDOR_ID2:
- return soc_ac97_ops.read(codec->ac97, reg);
+ return soc_ac97_ops->read(codec->ac97, reg);
default:
reg = reg >> 1;
@@ -225,7 +225,7 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
{
u16 *cache = codec->reg_cache;
- soc_ac97_ops.write(codec->ac97, reg, val);
+ soc_ac97_ops->write(codec->ac97, reg, val);
reg = reg >> 1;
if (reg < (ARRAY_SIZE(wm9705_reg)))
cache[reg] = val;
@@ -294,8 +294,8 @@ static struct snd_soc_dai_driver wm9705_dai[] = {
static int wm9705_reset(struct snd_soc_codec *codec)
{
- if (soc_ac97_ops.reset) {
- soc_ac97_ops.reset(codec->ac97);
+ if (soc_ac97_ops->reset) {
+ soc_ac97_ops->reset(codec->ac97);
if (ac97_read(codec, 0) == wm9705_reg[0])
return 0; /* Success */
}
@@ -306,7 +306,7 @@ static int wm9705_reset(struct snd_soc_codec *codec)
#ifdef CONFIG_PM
static int wm9705_soc_suspend(struct snd_soc_codec *codec)
{
- soc_ac97_ops.write(codec->ac97, AC97_POWERDOWN, 0xffff);
+ soc_ac97_ops->write(codec->ac97, AC97_POWERDOWN, 0xffff);
return 0;
}
@@ -323,7 +323,7 @@ static int wm9705_soc_resume(struct snd_soc_codec *codec)
}
for (i = 2; i < ARRAY_SIZE(wm9705_reg) << 1; i += 2) {
- soc_ac97_ops.write(codec->ac97, i, cache[i>>1]);
+ soc_ac97_ops->write(codec->ac97, i, cache[i>>1]);
}
return 0;
@@ -337,9 +337,7 @@ static int wm9705_soc_probe(struct snd_soc_codec *codec)
{
int ret = 0;
- printk(KERN_INFO "WM9705 SoC Audio Codec\n");
-
- ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
+ ret = snd_soc_new_ac97_codec(codec, soc_ac97_ops, 0);
if (ret < 0) {
printk(KERN_ERR "wm9705: failed to register AC97 codec\n");
return ret;
diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c
index 8e9a6a3..c5eb746 100644
--- a/sound/soc/codecs/wm9712.c
+++ b/sound/soc/codecs/wm9712.c
@@ -455,7 +455,7 @@ static unsigned int ac97_read(struct snd_soc_codec *codec,
if (reg == AC97_RESET || reg == AC97_GPIO_STATUS ||
reg == AC97_VENDOR_ID1 || reg == AC97_VENDOR_ID2 ||
reg == AC97_REC_GAIN)
- return soc_ac97_ops.read(codec->ac97, reg);
+ return soc_ac97_ops->read(codec->ac97, reg);
else {
reg = reg >> 1;
@@ -472,7 +472,7 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
u16 *cache = codec->reg_cache;
if (reg < 0x7c)
- soc_ac97_ops.write(codec->ac97, reg, val);
+ soc_ac97_ops->write(codec->ac97, reg, val);
reg = reg >> 1;
if (reg < (ARRAY_SIZE(wm9712_reg)))
cache[reg] = val;
@@ -581,15 +581,15 @@ static int wm9712_set_bias_level(struct snd_soc_codec *codec,
static int wm9712_reset(struct snd_soc_codec *codec, int try_warm)
{
- if (try_warm && soc_ac97_ops.warm_reset) {
- soc_ac97_ops.warm_reset(codec->ac97);
+ if (try_warm && soc_ac97_ops->warm_reset) {
+ soc_ac97_ops->warm_reset(codec->ac97);
if (ac97_read(codec, 0) == wm9712_reg[0])
return 1;
}
- soc_ac97_ops.reset(codec->ac97);
- if (soc_ac97_ops.warm_reset)
- soc_ac97_ops.warm_reset(codec->ac97);
+ soc_ac97_ops->reset(codec->ac97);
+ if (soc_ac97_ops->warm_reset)
+ soc_ac97_ops->warm_reset(codec->ac97);
if (ac97_read(codec, 0) != wm9712_reg[0])
goto err;
return 0;
@@ -624,7 +624,7 @@ static int wm9712_soc_resume(struct snd_soc_codec *codec)
if (i == AC97_INT_PAGING || i == AC97_POWERDOWN ||
(i > 0x58 && i != 0x5c))
continue;
- soc_ac97_ops.write(codec->ac97, i, cache[i>>1]);
+ soc_ac97_ops->write(codec->ac97, i, cache[i>>1]);
}
}
@@ -635,7 +635,7 @@ static int wm9712_soc_probe(struct snd_soc_codec *codec)
{
int ret = 0;
- ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
+ ret = snd_soc_new_ac97_codec(codec, soc_ac97_ops, 0);
if (ret < 0) {
printk(KERN_ERR "wm9712: failed to register AC97 codec\n");
return ret;
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c
index f7afa68..a53e175 100644
--- a/sound/soc/codecs/wm9713.c
+++ b/sound/soc/codecs/wm9713.c
@@ -652,7 +652,7 @@ static unsigned int ac97_read(struct snd_soc_codec *codec,
if (reg == AC97_RESET || reg == AC97_GPIO_STATUS ||
reg == AC97_VENDOR_ID1 || reg == AC97_VENDOR_ID2 ||
reg == AC97_CD)
- return soc_ac97_ops.read(codec->ac97, reg);
+ return soc_ac97_ops->read(codec->ac97, reg);
else {
reg = reg >> 1;
@@ -668,7 +668,7 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
{
u16 *cache = codec->reg_cache;
if (reg < 0x7c)
- soc_ac97_ops.write(codec->ac97, reg, val);
+ soc_ac97_ops->write(codec->ac97, reg, val);
reg = reg >> 1;
if (reg < (ARRAY_SIZE(wm9713_reg)))
cache[reg] = val;
@@ -1095,15 +1095,15 @@ static struct snd_soc_dai_driver wm9713_dai[] = {
int wm9713_reset(struct snd_soc_codec *codec, int try_warm)
{
- if (try_warm && soc_ac97_ops.warm_reset) {
- soc_ac97_ops.warm_reset(codec->ac97);
+ if (try_warm && soc_ac97_ops->warm_reset) {
+ soc_ac97_ops->warm_reset(codec->ac97);
if (ac97_read(codec, 0) == wm9713_reg[0])
return 1;
}
- soc_ac97_ops.reset(codec->ac97);
- if (soc_ac97_ops.warm_reset)
- soc_ac97_ops.warm_reset(codec->ac97);
+ soc_ac97_ops->reset(codec->ac97);
+ if (soc_ac97_ops->warm_reset)
+ soc_ac97_ops->warm_reset(codec->ac97);
if (ac97_read(codec, 0) != wm9713_reg[0])
return -EIO;
return 0;
@@ -1180,7 +1180,7 @@ static int wm9713_soc_resume(struct snd_soc_codec *codec)
if (i == AC97_POWERDOWN || i == AC97_EXTENDED_MID ||
i == AC97_EXTENDED_MSTATUS || i > 0x66)
continue;
- soc_ac97_ops.write(codec->ac97, i, cache[i>>1]);
+ soc_ac97_ops->write(codec->ac97, i, cache[i>>1]);
}
}
@@ -1197,7 +1197,7 @@ static int wm9713_soc_probe(struct snd_soc_codec *codec)
return -ENOMEM;
snd_soc_codec_set_drvdata(codec, wm9713);
- ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
+ ret = snd_soc_new_ac97_codec(codec, soc_ac97_ops, 0);
if (ret < 0)
goto codec_err;
diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h
index 6e890b9..9f922c8 100644
--- a/sound/soc/codecs/wm_adsp.h
+++ b/sound/soc/codecs/wm_adsp.h
@@ -61,14 +61,12 @@ struct wm_adsp {
};
#define WM_ADSP1(wname, num) \
- { .id = snd_soc_dapm_pga, .name = wname, .reg = SND_SOC_NOPM, \
- .shift = num, .event = wm_adsp1_event, \
- .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD }
+ SND_SOC_DAPM_PGA_E(wname, SND_SOC_NOPM, num, 0, NULL, 0, \
+ wm_adsp1_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD)
#define WM_ADSP2(wname, num) \
-{ .id = snd_soc_dapm_pga, .name = wname, .reg = SND_SOC_NOPM, \
- .shift = num, .event = wm_adsp2_event, \
- .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD }
+ SND_SOC_DAPM_PGA_E(wname, SND_SOC_NOPM, num, 0, NULL, 0, \
+ wm_adsp2_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD)
extern const struct snd_kcontrol_new wm_adsp1_fw_controls[];
extern const struct snd_kcontrol_new wm_adsp2_fw_controls[];
diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c
index f5d81b9..2d9e099 100644
--- a/sound/soc/codecs/wm_hubs.c
+++ b/sound/soc/codecs/wm_hubs.c
@@ -693,10 +693,8 @@ void wm_hubs_update_class_w(struct snd_soc_codec *codec)
EXPORT_SYMBOL_GPL(wm_hubs_update_class_w);
#define WM_HUBS_SINGLE_W(xname, reg, shift, max, invert) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
- .info = snd_soc_info_volsw, \
- .get = snd_soc_dapm_get_volsw, .put = class_w_put_volsw, \
- .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) }
+ SOC_SINGLE_EXT(xname, reg, shift, max, invert, \
+ snd_soc_dapm_get_volsw, class_w_put_volsw)
static int class_w_put_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c
index 484b22c..fd7c45b 100644
--- a/sound/soc/davinci/davinci-evm.c
+++ b/sound/soc/davinci/davinci-evm.c
@@ -14,6 +14,7 @@
#include <linux/timer.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
+#include <linux/platform_data/edma.h>
#include <linux/i2c.h>
#include <sound/core.h>
#include <sound/pcm.h>
diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c
index b2f27c2..8460edc 100644
--- a/sound/soc/davinci/davinci-pcm.c
+++ b/sound/soc/davinci/davinci-pcm.c
@@ -17,6 +17,7 @@
#include <linux/dma-mapping.h>
#include <linux/kernel.h>
#include <linux/genalloc.h>
+#include <linux/platform_data/edma.h>
#include <sound/core.h>
#include <sound/pcm.h>
diff --git a/sound/soc/davinci/davinci-pcm.h b/sound/soc/davinci/davinci-pcm.h
index b6ef703..fbb710c 100644
--- a/sound/soc/davinci/davinci-pcm.h
+++ b/sound/soc/davinci/davinci-pcm.h
@@ -14,7 +14,7 @@
#include <linux/genalloc.h>
#include <linux/platform_data/davinci_asp.h>
-#include <mach/edma.h>
+#include <linux/platform_data/edma.h>
struct davinci_pcm_dma_params {
int channel; /* sync dma channel ID */
diff --git a/sound/soc/fsl/imx-sgtl5000.c b/sound/soc/fsl/imx-sgtl5000.c
index 7a8bc12..3f726e4 100644
--- a/sound/soc/fsl/imx-sgtl5000.c
+++ b/sound/soc/fsl/imx-sgtl5000.c
@@ -113,13 +113,13 @@ static int imx_sgtl5000_probe(struct platform_device *pdev)
ssi_pdev = of_find_device_by_node(ssi_np);
if (!ssi_pdev) {
dev_err(&pdev->dev, "failed to find SSI platform device\n");
- ret = -EINVAL;
+ ret = -EPROBE_DEFER;
goto fail;
}
codec_dev = of_find_i2c_device_by_node(codec_np);
if (!codec_dev) {
dev_err(&pdev->dev, "failed to find codec platform device\n");
- return -EINVAL;
+ return -EPROBE_DEFER;
}
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
diff --git a/sound/soc/fsl/imx-ssi.c b/sound/soc/fsl/imx-ssi.c
index a8362be..51be377 100644
--- a/sound/soc/fsl/imx-ssi.c
+++ b/sound/soc/fsl/imx-ssi.c
@@ -501,13 +501,12 @@ static void imx_ssi_ac97_warm_reset(struct snd_ac97 *ac97)
imx_ssi_ac97_read(ac97, 0);
}
-struct snd_ac97_bus_ops soc_ac97_ops = {
+static struct snd_ac97_bus_ops imx_ssi_ac97_ops = {
.read = imx_ssi_ac97_read,
.write = imx_ssi_ac97_write,
.reset = imx_ssi_ac97_reset,
.warm_reset = imx_ssi_ac97_warm_reset
};
-EXPORT_SYMBOL_GPL(soc_ac97_ops);
static int imx_ssi_probe(struct platform_device *pdev)
{
@@ -583,6 +582,12 @@ static int imx_ssi_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, ssi);
+ ret = snd_soc_set_ac97_ops(&imx_ssi_ac97_ops);
+ if (ret != 0) {
+ dev_err(&pdev->dev, "Failed to set AC'97 ops: %d\n", ret);
+ goto failed_register;
+ }
+
ret = snd_soc_register_component(&pdev->dev, &imx_component,
dai, 1);
if (ret) {
@@ -608,6 +613,7 @@ failed_register:
release_mem_region(res->start, resource_size(res));
clk_disable_unprepare(ssi->clk);
failed_clk:
+ snd_soc_set_ac97_ops(NULL);
return ret;
}
@@ -627,6 +633,7 @@ static int imx_ssi_remove(struct platform_device *pdev)
release_mem_region(res->start, resource_size(res));
clk_disable_unprepare(ssi->clk);
+ snd_soc_set_ac97_ops(NULL);
return 0;
}
diff --git a/sound/soc/fsl/mpc5200_psc_ac97.c b/sound/soc/fsl/mpc5200_psc_ac97.c
index 4141b35..3ef7a0c 100644
--- a/sound/soc/fsl/mpc5200_psc_ac97.c
+++ b/sound/soc/fsl/mpc5200_psc_ac97.c
@@ -131,13 +131,12 @@ static void psc_ac97_cold_reset(struct snd_ac97 *ac97)
psc_ac97_warm_reset(ac97);
}
-struct snd_ac97_bus_ops soc_ac97_ops = {
+static struct snd_ac97_bus_ops psc_ac97_ops = {
.read = psc_ac97_read,
.write = psc_ac97_write,
.reset = psc_ac97_cold_reset,
.warm_reset = psc_ac97_warm_reset,
};
-EXPORT_SYMBOL_GPL(soc_ac97_ops);
static int psc_ac97_hw_analog_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
@@ -290,6 +289,12 @@ static int psc_ac97_of_probe(struct platform_device *op)
if (rc != 0)
return rc;
+ rc = snd_soc_set_ac97_ops(&psc_ac97_ops);
+ if (rc != 0) {
+ dev_err(&op->dev, "Failed to set AC'97 ops: %d\n", ret);
+ return rc;
+ }
+
rc = snd_soc_register_component(&op->dev, &psc_ac97_component,
psc_ac97_dai, ARRAY_SIZE(psc_ac97_dai));
if (rc != 0) {
@@ -318,6 +323,7 @@ static int psc_ac97_of_remove(struct platform_device *op)
{
mpc5200_audio_dma_destroy(op);
snd_soc_unregister_component(&op->dev);
+ snd_soc_set_ac97_ops(NULL);
return 0;
}
diff --git a/sound/soc/mid-x86/mfld_machine.c b/sound/soc/mid-x86/mfld_machine.c
index 78d5825..ee36384 100644
--- a/sound/soc/mid-x86/mfld_machine.c
+++ b/sound/soc/mid-x86/mfld_machine.c
@@ -371,7 +371,7 @@ static int snd_mfld_mc_probe(struct platform_device *pdev)
/* audio interrupt base of SRAM location where
* interrupts are stored by System FW */
- mc_drv_ctx = kzalloc(sizeof(*mc_drv_ctx), GFP_ATOMIC);
+ mc_drv_ctx = devm_kzalloc(&pdev->dev, sizeof(*mc_drv_ctx), GFP_ATOMIC);
if (!mc_drv_ctx) {
pr_err("allocation failed\n");
return -ENOMEM;
@@ -381,50 +381,39 @@ static int snd_mfld_mc_probe(struct platform_device *pdev)
pdev, IORESOURCE_MEM, "IRQ_BASE");
if (!irq_mem) {
pr_err("no mem resource given\n");
- ret_val = -ENODEV;
- goto unalloc;
+ return -ENODEV;
}
- mc_drv_ctx->int_base = ioremap_nocache(irq_mem->start,
- resource_size(irq_mem));
+ mc_drv_ctx->int_base = devm_ioremap_nocache(&pdev->dev, irq_mem->start,
+ resource_size(irq_mem));
if (!mc_drv_ctx->int_base) {
pr_err("Mapping of cache failed\n");
- ret_val = -ENOMEM;
- goto unalloc;
+ return -ENOMEM;
}
/* register for interrupt */
- ret_val = request_threaded_irq(irq, snd_mfld_jack_intr_handler,
+ ret_val = devm_request_threaded_irq(&pdev->dev, irq,
+ snd_mfld_jack_intr_handler,
snd_mfld_jack_detection,
IRQF_SHARED, pdev->dev.driver->name, mc_drv_ctx);
if (ret_val) {
pr_err("cannot register IRQ\n");
- goto unalloc;
+ return ret_val;
}
/* register the soc card */
snd_soc_card_mfld.dev = &pdev->dev;
ret_val = snd_soc_register_card(&snd_soc_card_mfld);
if (ret_val) {
pr_debug("snd_soc_register_card failed %d\n", ret_val);
- goto freeirq;
+ return ret_val;
}
platform_set_drvdata(pdev, mc_drv_ctx);
pr_debug("successfully exited probe\n");
- return ret_val;
-
-freeirq:
- free_irq(irq, mc_drv_ctx);
-unalloc:
- kfree(mc_drv_ctx);
- return ret_val;
+ return 0;
}
static int snd_mfld_mc_remove(struct platform_device *pdev)
{
- struct mfld_mc_private *mc_drv_ctx = platform_get_drvdata(pdev);
-
pr_debug("snd_mfld_mc_remove called\n");
- free_irq(platform_get_irq(pdev, 0), mc_drv_ctx);
snd_soc_unregister_card(&snd_soc_card_mfld);
- kfree(mc_drv_ctx);
return 0;
}
diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c
index 49d8700..54511c5 100644
--- a/sound/soc/mxs/mxs-saif.c
+++ b/sound/soc/mxs/mxs-saif.c
@@ -24,6 +24,7 @@
#include <linux/slab.h>
#include <linux/dma-mapping.h>
#include <linux/clk.h>
+#include <linux/clk-provider.h>
#include <linux/delay.h>
#include <linux/time.h>
#include <sound/core.h>
@@ -658,6 +659,33 @@ static irqreturn_t mxs_saif_irq(int irq, void *dev_id)
return IRQ_HANDLED;
}
+static int mxs_saif_mclk_init(struct platform_device *pdev)
+{
+ struct mxs_saif *saif = platform_get_drvdata(pdev);
+ struct device_node *np = pdev->dev.of_node;
+ struct clk *clk;
+ int ret;
+
+ clk = clk_register_divider(&pdev->dev, "mxs_saif_mclk",
+ __clk_get_name(saif->clk), 0,
+ saif->base + SAIF_CTRL,
+ BP_SAIF_CTRL_BITCLK_MULT_RATE, 3,
+ 0, NULL);
+ if (IS_ERR(clk)) {
+ ret = PTR_ERR(clk);
+ if (ret == -EEXIST)
+ return 0;
+ dev_err(&pdev->dev, "failed to register mclk: %d\n", ret);
+ return PTR_ERR(clk);
+ }
+
+ ret = of_clk_add_provider(np, of_clk_src_simple_get, clk);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
static int mxs_saif_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
@@ -734,6 +762,13 @@ static int mxs_saif_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, saif);
+ /* We only support saif0 being tx and clock master */
+ if (saif->id == 0) {
+ ret = mxs_saif_mclk_init(pdev);
+ if (ret)
+ dev_warn(&pdev->dev, "failed to init clocks\n");
+ }
+
ret = snd_soc_register_component(&pdev->dev, &mxs_saif_component,
&mxs_saif_dai, 1);
if (ret) {
diff --git a/sound/soc/nuc900/nuc900-ac97.c b/sound/soc/nuc900/nuc900-ac97.c
index fe3285c..f4c2417 100644
--- a/sound/soc/nuc900/nuc900-ac97.c
+++ b/sound/soc/nuc900/nuc900-ac97.c
@@ -197,13 +197,12 @@ static void nuc900_ac97_cold_reset(struct snd_ac97 *ac97)
}
/* AC97 controller operations */
-struct snd_ac97_bus_ops soc_ac97_ops = {
+static struct snd_ac97_bus_ops nuc900_ac97_ops = {
.read = nuc900_ac97_read,
.write = nuc900_ac97_write,
.reset = nuc900_ac97_cold_reset,
.warm_reset = nuc900_ac97_warm_reset,
-}
-EXPORT_SYMBOL_GPL(soc_ac97_ops);
+};
static int nuc900_ac97_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai)
@@ -326,64 +325,52 @@ static int nuc900_ac97_drvprobe(struct platform_device *pdev)
if (nuc900_ac97_data)
return -EBUSY;
- nuc900_audio = kzalloc(sizeof(struct nuc900_audio), GFP_KERNEL);
+ nuc900_audio = devm_kzalloc(&pdev->dev, sizeof(struct nuc900_audio),
+ GFP_KERNEL);
if (!nuc900_audio)
return -ENOMEM;
spin_lock_init(&nuc900_audio->lock);
nuc900_audio->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!nuc900_audio->res) {
- ret = -ENODEV;
- goto out0;
- }
-
- if (!request_mem_region(nuc900_audio->res->start,
- resource_size(nuc900_audio->res), pdev->name)) {
- ret = -EBUSY;
- goto out0;
- }
+ if (!nuc900_audio->res)
+ return ret;
- nuc900_audio->mmio = ioremap(nuc900_audio->res->start,
- resource_size(nuc900_audio->res));
- if (!nuc900_audio->mmio) {
- ret = -ENOMEM;
- goto out1;
- }
+ nuc900_audio->mmio = devm_ioremap_resource(&pdev->dev,
+ nuc900_audio->res);
+ if (IS_ERR(nuc900_audio->mmio))
+ return PTR_ERR(nuc900_audio->mmio);
- nuc900_audio->clk = clk_get(&pdev->dev, NULL);
+ nuc900_audio->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(nuc900_audio->clk)) {
ret = PTR_ERR(nuc900_audio->clk);
- goto out2;
+ goto out;
}
nuc900_audio->irq_num = platform_get_irq(pdev, 0);
if (!nuc900_audio->irq_num) {
ret = -EBUSY;
- goto out3;
+ goto out;
}
nuc900_ac97_data = nuc900_audio;
+ ret = snd_soc_set_ac97_ops(&nuc900_ac97_ops);
+ if (ret)
+ goto out;
+
ret = snd_soc_register_component(&pdev->dev, &nuc900_ac97_component,
&nuc900_ac97_dai, 1);
if (ret)
- goto out3;
+ goto out;
/* enbale ac97 multifunction pin */
mfp_set_groupg(nuc900_audio->dev, NULL);
return 0;
-out3:
- clk_put(nuc900_audio->clk);
-out2:
- iounmap(nuc900_audio->mmio);
-out1:
- release_mem_region(nuc900_audio->res->start,
- resource_size(nuc900_audio->res));
-out0:
- kfree(nuc900_audio);
+out:
+ snd_soc_set_ac97_ops(NULL);
return ret;
}
@@ -391,13 +378,8 @@ static int nuc900_ac97_drvremove(struct platform_device *pdev)
{
snd_soc_unregister_component(&pdev->dev);
- clk_put(nuc900_ac97_data->clk);
- iounmap(nuc900_ac97_data->mmio);
- release_mem_region(nuc900_ac97_data->res->start,
- resource_size(nuc900_ac97_data->res));
-
- kfree(nuc900_ac97_data);
nuc900_ac97_data = NULL;
+ snd_soc_set_ac97_ops(NULL);
return 0;
}
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig
index 60259f2..9f5d55e 100644
--- a/sound/soc/omap/Kconfig
+++ b/sound/soc/omap/Kconfig
@@ -103,7 +103,7 @@ config SND_OMAP_SOC_OMAP_HDMI
tristate "SoC Audio support for Texas Instruments OMAP HDMI"
depends on SND_OMAP_SOC && OMAP4_DSS_HDMI && OMAP2_DSS
select SND_OMAP_SOC_HDMI
- select SND_SOC_OMAP_HDMI_CODEC
+ select SND_SOC_HDMI_CODEC
select OMAP4_DSS_HDMI_AUDIO
help
Say Y if you want to add support for SoC HDMI audio on Texas Instruments
diff --git a/sound/soc/omap/mcbsp.c b/sound/soc/omap/mcbsp.c
index eb68c7d..361e4c0 100644
--- a/sound/soc/omap/mcbsp.c
+++ b/sound/soc/omap/mcbsp.c
@@ -1012,28 +1012,33 @@ int omap_mcbsp_init(struct platform_device *pdev)
}
}
- res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx");
- if (!res) {
- dev_err(&pdev->dev, "invalid rx DMA channel\n");
- return -ENODEV;
- }
- /* RX DMA request number, and port address configuration */
- mcbsp->dma_req[1] = res->start;
- mcbsp->dma_data[1].filter_data = &mcbsp->dma_req[1];
- mcbsp->dma_data[1].addr = omap_mcbsp_dma_reg_params(mcbsp, 1);
- mcbsp->dma_data[1].maxburst = 4;
+ if (!pdev->dev.of_node) {
+ res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx");
+ if (!res) {
+ dev_err(&pdev->dev, "invalid tx DMA channel\n");
+ return -ENODEV;
+ }
+ mcbsp->dma_req[0] = res->start;
+ mcbsp->dma_data[0].filter_data = &mcbsp->dma_req[0];
- res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx");
- if (!res) {
- dev_err(&pdev->dev, "invalid tx DMA channel\n");
- return -ENODEV;
+ res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx");
+ if (!res) {
+ dev_err(&pdev->dev, "invalid rx DMA channel\n");
+ return -ENODEV;
+ }
+ mcbsp->dma_req[1] = res->start;
+ mcbsp->dma_data[1].filter_data = &mcbsp->dma_req[1];
+ } else {
+ mcbsp->dma_data[0].filter_data = "tx";
+ mcbsp->dma_data[1].filter_data = "rx";
}
- /* TX DMA request number, and port address configuration */
- mcbsp->dma_req[0] = res->start;
- mcbsp->dma_data[0].filter_data = &mcbsp->dma_req[0];
+
mcbsp->dma_data[0].addr = omap_mcbsp_dma_reg_params(mcbsp, 0);
mcbsp->dma_data[0].maxburst = 4;
+ mcbsp->dma_data[1].addr = omap_mcbsp_dma_reg_params(mcbsp, 1);
+ mcbsp->dma_data[1].maxburst = 4;
+
mcbsp->fclk = clk_get(&pdev->dev, "fck");
if (IS_ERR(mcbsp->fclk)) {
ret = PTR_ERR(mcbsp->fclk);
diff --git a/sound/soc/omap/omap-dmic.c b/sound/soc/omap/omap-dmic.c
index 2ad0370..4db1f8e 100644
--- a/sound/soc/omap/omap-dmic.c
+++ b/sound/soc/omap/omap-dmic.c
@@ -57,7 +57,6 @@ struct omap_dmic {
struct mutex mutex;
struct snd_dmaengine_dai_dma_data dma_data;
- unsigned int dma_req;
};
static inline void omap_dmic_write(struct omap_dmic *dmic, u16 reg, u32 val)
@@ -478,15 +477,7 @@ static int asoc_dmic_probe(struct platform_device *pdev)
}
dmic->dma_data.addr = res->start + OMAP_DMIC_DATA_REG;
- res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
- if (!res) {
- dev_err(dmic->dev, "invalid dma resource\n");
- ret = -ENODEV;
- goto err_put_clk;
- }
-
- dmic->dma_req = res->start;
- dmic->dma_data.filter_data = &dmic->dma_req;
+ dmic->dma_data.filter_data = "up_link";
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
if (!res) {
diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/omap/omap-mcpdm.c
index eb05c7e..a49dc52 100644
--- a/sound/soc/omap/omap-mcpdm.c
+++ b/sound/soc/omap/omap-mcpdm.c
@@ -66,7 +66,6 @@ struct omap_mcpdm {
bool restart;
struct snd_dmaengine_dai_dma_data dma_data[2];
- unsigned int dma_req[2];
};
/*
@@ -477,19 +476,8 @@ static int asoc_mcpdm_probe(struct platform_device *pdev)
mcpdm->dma_data[0].addr = res->start + MCPDM_REG_DN_DATA;
mcpdm->dma_data[1].addr = res->start + MCPDM_REG_UP_DATA;
- res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "dn_link");
- if (!res)
- return -ENODEV;
-
- mcpdm->dma_req[0] = res->start;
- mcpdm->dma_data[0].filter_data = &mcpdm->dma_req[0];
-
- res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "up_link");
- if (!res)
- return -ENODEV;
-
- mcpdm->dma_req[1] = res->start;
- mcpdm->dma_data[1].filter_data = &mcpdm->dma_req[1];
+ mcpdm->dma_data[0].filter_data = "dn_link";
+ mcpdm->dma_data[1].filter_data = "up_link";
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
if (res == NULL)
diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c
index c28e042..a11405d 100644
--- a/sound/soc/omap/omap-pcm.c
+++ b/sound/soc/omap/omap-pcm.c
@@ -113,14 +113,25 @@ static int omap_pcm_open(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_dmaengine_dai_dma_data *dma_data;
+ int ret;
snd_soc_set_runtime_hwparams(substream, &omap_pcm_hardware);
dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
- return snd_dmaengine_pcm_open_request_chan(substream,
- omap_dma_filter_fn,
- dma_data->filter_data);
+ /* DT boot: filter_data is the DMA name */
+ if (rtd->cpu_dai->dev->of_node) {
+ struct dma_chan *chan;
+
+ chan = dma_request_slave_channel(rtd->cpu_dai->dev,
+ dma_data->filter_data);
+ ret = snd_dmaengine_pcm_open(substream, chan);
+ } else {
+ ret = snd_dmaengine_pcm_open_request_chan(substream,
+ omap_dma_filter_fn,
+ dma_data->filter_data);
+ }
+ return ret;
}
static int omap_pcm_mmap(struct snd_pcm_substream *substream,
diff --git a/sound/soc/omap/rx51.c b/sound/soc/omap/rx51.c
index 249cd23..611179c 100644
--- a/sound/soc/omap/rx51.c
+++ b/sound/soc/omap/rx51.c
@@ -396,7 +396,7 @@ static int __init rx51_soc_init(void)
{
int err;
- if (!machine_is_nokia_rx51())
+ if (!machine_is_nokia_rx51() && !of_machine_is_compatible("nokia,omap3-n900"))
return -ENODEV;
err = gpio_request_one(RX51_TVOUT_SEL_GPIO,
diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c
index 57ea8e6..1475515 100644
--- a/sound/soc/pxa/pxa2xx-ac97.c
+++ b/sound/soc/pxa/pxa2xx-ac97.c
@@ -41,13 +41,12 @@ static void pxa2xx_ac97_cold_reset(struct snd_ac97 *ac97)
pxa2xx_ac97_finish_reset(ac97);
}
-struct snd_ac97_bus_ops soc_ac97_ops = {
+static struct snd_ac97_bus_ops pxa2xx_ac97_ops = {
.read = pxa2xx_ac97_read,
.write = pxa2xx_ac97_write,
.warm_reset = pxa2xx_ac97_warm_reset,
.reset = pxa2xx_ac97_cold_reset,
};
-EXPORT_SYMBOL_GPL(soc_ac97_ops);
static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_stereo_out = {
.name = "AC97 PCM Stereo out",
@@ -239,11 +238,17 @@ static const struct snd_soc_component_driver pxa_ac97_component = {
static int pxa2xx_ac97_dev_probe(struct platform_device *pdev)
{
+ int ret;
+
if (pdev->id != -1) {
dev_err(&pdev->dev, "PXA2xx has only one AC97 port.\n");
return -ENXIO;
}
+ ret = snd_soc_set_ac97_ops(&pxa2xx_ac97_ops);
+ if (ret != 0)
+ return ret;
+
/* Punt most of the init to the SoC probe; we may need the machine
* driver to do interesting things with the clocking to get us up
* and running.
@@ -255,6 +260,7 @@ static int pxa2xx_ac97_dev_probe(struct platform_device *pdev)
static int pxa2xx_ac97_dev_remove(struct platform_device *pdev)
{
snd_soc_unregister_component(&pdev->dev);
+ snd_soc_set_ac97_ops(NULL);
return 0;
}
diff --git a/sound/soc/pxa/pxa2xx-ac97.h b/sound/soc/pxa/pxa2xx-ac97.h
index eda891e..a49c21b 100644
--- a/sound/soc/pxa/pxa2xx-ac97.h
+++ b/sound/soc/pxa/pxa2xx-ac97.h
@@ -14,7 +14,4 @@
#define PXA2XX_DAI_AC97_AUX 1
#define PXA2XX_DAI_AC97_MIC 2
-/* platform data */
-extern struct snd_ac97_bus_ops pxa2xx_ac97_ops;
-
#endif
diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig
index ae0ea87..9855dfc 100644
--- a/sound/soc/samsung/Kconfig
+++ b/sound/soc/samsung/Kconfig
@@ -39,7 +39,7 @@ config SND_SOC_SAMSUNG_NEO1973_WM8753
depends on SND_SOC_SAMSUNG && MACH_NEO1973_GTA02
select SND_S3C24XX_I2S
select SND_SOC_WM8753
- select SND_SOC_SCO
+ select SND_SOC_BT_SCO
help
Say Y here to enable audio support for the Openmoko Neo1973
Smartphones.
diff --git a/sound/soc/samsung/ac97.c b/sound/soc/samsung/ac97.c
index cb88ead..2dd623f 100644
--- a/sound/soc/samsung/ac97.c
+++ b/sound/soc/samsung/ac97.c
@@ -214,13 +214,12 @@ static irqreturn_t s3c_ac97_irq(int irq, void *dev_id)
return IRQ_HANDLED;
}
-struct snd_ac97_bus_ops soc_ac97_ops = {
+static struct snd_ac97_bus_ops s3c_ac97_ops = {
.read = s3c_ac97_read,
.write = s3c_ac97_write,
.warm_reset = s3c_ac97_warm_reset,
.reset = s3c_ac97_cold_reset,
};
-EXPORT_SYMBOL_GPL(soc_ac97_ops);
static int s3c_ac97_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
@@ -417,11 +416,9 @@ static int s3c_ac97_probe(struct platform_device *pdev)
return -ENXIO;
}
- if (!request_mem_region(mem_res->start,
- resource_size(mem_res), "ac97")) {
- dev_err(&pdev->dev, "Unable to request register region\n");
- return -EBUSY;
- }
+ s3c_ac97.regs = devm_ioremap_resource(&pdev->dev, mem_res);
+ if (IS_ERR(s3c_ac97.regs))
+ return PTR_ERR(s3c_ac97.regs);
s3c_ac97_pcm_out.channel = dmatx_res->start;
s3c_ac97_pcm_out.dma_addr = mem_res->start + S3C_AC97_PCM_DATA;
@@ -433,14 +430,7 @@ static int s3c_ac97_probe(struct platform_device *pdev)
init_completion(&s3c_ac97.done);
mutex_init(&s3c_ac97.lock);
- s3c_ac97.regs = ioremap(mem_res->start, resource_size(mem_res));
- if (s3c_ac97.regs == NULL) {
- dev_err(&pdev->dev, "Unable to ioremap register region\n");
- ret = -ENXIO;
- goto err1;
- }
-
- s3c_ac97.ac97_clk = clk_get(&pdev->dev, "ac97");
+ s3c_ac97.ac97_clk = devm_clk_get(&pdev->dev, "ac97");
if (IS_ERR(s3c_ac97.ac97_clk)) {
dev_err(&pdev->dev, "ac97 failed to get ac97_clock\n");
ret = -ENODEV;
@@ -461,6 +451,12 @@ static int s3c_ac97_probe(struct platform_device *pdev)
goto err4;
}
+ ret = snd_soc_set_ac97_ops(&s3c_ac97_ops);
+ if (ret != 0) {
+ dev_err(&pdev->dev, "Failed to set AC'97 ops: %d\n", ret);
+ goto err4;
+ }
+
ret = snd_soc_register_component(&pdev->dev, &s3c_ac97_component,
s3c_ac97_dai, ARRAY_SIZE(s3c_ac97_dai));
if (ret)
@@ -480,18 +476,14 @@ err5:
err4:
err3:
clk_disable_unprepare(s3c_ac97.ac97_clk);
- clk_put(s3c_ac97.ac97_clk);
err2:
- iounmap(s3c_ac97.regs);
-err1:
- release_mem_region(mem_res->start, resource_size(mem_res));
-
+ snd_soc_set_ac97_ops(NULL);
return ret;
}
static int s3c_ac97_remove(struct platform_device *pdev)
{
- struct resource *mem_res, *irq_res;
+ struct resource *irq_res;
asoc_dma_platform_unregister(&pdev->dev);
snd_soc_unregister_component(&pdev->dev);
@@ -501,13 +493,7 @@ static int s3c_ac97_remove(struct platform_device *pdev)
free_irq(irq_res->start, NULL);
clk_disable_unprepare(s3c_ac97.ac97_clk);
- clk_put(s3c_ac97.ac97_clk);
-
- iounmap(s3c_ac97.regs);
-
- mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (mem_res)
- release_mem_region(mem_res->start, resource_size(mem_res));
+ snd_soc_set_ac97_ops(NULL);
return 0;
}
diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c
index 82ebb1a..959c702 100644
--- a/sound/soc/samsung/i2s.c
+++ b/sound/soc/samsung/i2s.c
@@ -742,13 +742,13 @@ static int config_setup(struct i2s_dai *i2s)
return -EAGAIN;
}
- /* Don't bother RFS, BFS & PSR in Slave mode */
- if (is_slave(i2s))
- return 0;
-
set_bfs(i2s, bfs);
set_rfs(i2s, rfs);
+ /* Don't bother with PSR in Slave mode */
+ if (is_slave(i2s))
+ return 0;
+
if (!(i2s->quirks & QUIRK_NO_MUXPSR)) {
psr = i2s->rclk_srcrate / i2s->frmclk / rfs;
writel(((psr - 1) << 8) | PSR_PSREN, i2s->addr + I2SPSR);
@@ -1016,52 +1016,6 @@ static struct i2s_dai *i2s_alloc_dai(struct platform_device *pdev, bool sec)
return i2s;
}
-#ifdef CONFIG_OF
-static int samsung_i2s_parse_dt_gpio(struct i2s_dai *i2s)
-{
- struct device *dev = &i2s->pdev->dev;
- int index, gpio, ret;
-
- for (index = 0; index < 7; index++) {
- gpio = of_get_gpio(dev->of_node, index);
- if (!gpio_is_valid(gpio)) {
- dev_err(dev, "invalid gpio[%d]: %d\n", index, gpio);
- goto free_gpio;
- }
-
- ret = gpio_request(gpio, dev_name(dev));
- if (ret) {
- dev_err(dev, "gpio [%d] request failed\n", gpio);
- goto free_gpio;
- }
- i2s->gpios[index] = gpio;
- }
- return 0;
-
-free_gpio:
- while (--index >= 0)
- gpio_free(i2s->gpios[index]);
- return -EINVAL;
-}
-
-static void samsung_i2s_dt_gpio_free(struct i2s_dai *i2s)
-{
- unsigned int index;
- for (index = 0; index < 7; index++)
- gpio_free(i2s->gpios[index]);
-}
-#else
-static int samsung_i2s_parse_dt_gpio(struct i2s_dai *dai)
-{
- return -EINVAL;
-}
-
-static void samsung_i2s_dt_gpio_free(struct i2s_dai *dai)
-{
-}
-
-#endif
-
static const struct of_device_id exynos_i2s_match[];
static inline int samsung_i2s_get_driver_data(struct platform_device *pdev)
@@ -1235,18 +1189,10 @@ static int samsung_i2s_probe(struct platform_device *pdev)
pri_dai->sec_dai = sec_dai;
}
- if (np) {
- if (samsung_i2s_parse_dt_gpio(pri_dai)) {
- dev_err(&pdev->dev, "Unable to configure gpio\n");
- ret = -EINVAL;
- goto err;
- }
- } else {
- if (i2s_pdata->cfg_gpio && i2s_pdata->cfg_gpio(pdev)) {
- dev_err(&pdev->dev, "Unable to configure gpio\n");
- ret = -EINVAL;
- goto err;
- }
+ if (i2s_pdata && i2s_pdata->cfg_gpio && i2s_pdata->cfg_gpio(pdev)) {
+ dev_err(&pdev->dev, "Unable to configure gpio\n");
+ ret = -EINVAL;
+ goto err;
}
snd_soc_register_component(&pri_dai->pdev->dev, &samsung_i2s_component,
@@ -1267,14 +1213,10 @@ static int samsung_i2s_remove(struct platform_device *pdev)
{
struct i2s_dai *i2s, *other;
struct resource *res;
- struct s3c_audio_pdata *i2s_pdata = pdev->dev.platform_data;
i2s = dev_get_drvdata(&pdev->dev);
other = i2s->pri_dai ? : i2s->sec_dai;
- if (!i2s_pdata->cfg_gpio && pdev->dev.of_node)
- samsung_i2s_dt_gpio_free(i2s->pri_dai);
-
if (other) {
other->pri_dai = NULL;
other->sec_dai = NULL;
diff --git a/sound/soc/samsung/idma.c b/sound/soc/samsung/idma.c
index 6e5fed3..ce1e1e1 100644
--- a/sound/soc/samsung/idma.c
+++ b/sound/soc/samsung/idma.c
@@ -257,7 +257,6 @@ static int idma_mmap(struct snd_pcm_substream *substream,
/* From snd_pcm_lib_mmap_iomem */
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
- vma->vm_flags |= VM_IO;
size = vma->vm_end - vma->vm_start;
offset = vma->vm_pgoff << PAGE_SHIFT;
ret = io_remap_pfn_range(vma, vma->vm_start,
diff --git a/sound/soc/samsung/s3c-i2s-v2.c b/sound/soc/samsung/s3c-i2s-v2.c
index 20e98d1..e5e81b1 100644
--- a/sound/soc/samsung/s3c-i2s-v2.c
+++ b/sound/soc/samsung/s3c-i2s-v2.c
@@ -1,6 +1,4 @@
-/* sound/soc/samsung/s3c-i2c-v2.c
- *
- * ALSA Soc Audio Layer - I2S core for newer Samsung SoCs.
+/* ALSA Soc Audio Layer - I2S core for newer Samsung SoCs.
*
* Copyright (c) 2006 Wolfson Microelectronics PLC.
* Graeme Gregory graeme.gregory@wolfsonmicro.com
diff --git a/sound/soc/sh/hac.c b/sound/soc/sh/hac.c
index af19f77..0af2e4d 100644
--- a/sound/soc/sh/hac.c
+++ b/sound/soc/sh/hac.c
@@ -227,13 +227,12 @@ static void hac_ac97_coldrst(struct snd_ac97 *ac97)
hac_ac97_warmrst(ac97);
}
-struct snd_ac97_bus_ops soc_ac97_ops = {
+static struct snd_ac97_bus_ops hac_ac97_ops = {
.read = hac_ac97_read,
.write = hac_ac97_write,
.reset = hac_ac97_coldrst,
.warm_reset = hac_ac97_warmrst,
};
-EXPORT_SYMBOL_GPL(soc_ac97_ops);
static int hac_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
@@ -316,6 +315,10 @@ static const struct snd_soc_component_driver sh4_hac_component = {
static int hac_soc_platform_probe(struct platform_device *pdev)
{
+ ret = snd_soc_set_ac97_ops(&hac_ac97_ops);
+ if (ret != 0)
+ return ret;
+
return snd_soc_register_component(&pdev->dev, &sh4_hac_component,
sh4_hac_dai, ARRAY_SIZE(sh4_hac_dai));
}
@@ -323,6 +326,7 @@ static int hac_soc_platform_probe(struct platform_device *pdev)
static int hac_soc_platform_remove(struct platform_device *pdev)
{
snd_soc_unregister_component(&pdev->dev);
+ snd_soc_set_ac97_ops(NULL);
return 0;
}
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 4489c5b..0ec070c 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -2080,6 +2080,23 @@ int snd_soc_new_ac97_codec(struct snd_soc_codec *codec,
}
EXPORT_SYMBOL_GPL(snd_soc_new_ac97_codec);
+struct snd_ac97_bus_ops *soc_ac97_ops;
+EXPORT_SYMBOL_GPL(soc_ac97_ops);
+
+int snd_soc_set_ac97_ops(struct snd_ac97_bus_ops *ops)
+{
+ if (ops == soc_ac97_ops)
+ return 0;
+
+ if (soc_ac97_ops && ops)
+ return -EBUSY;
+
+ soc_ac97_ops = ops;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_set_ac97_ops);
+
/**
* snd_soc_free_ac97_codec - free AC97 codec device
* @codec: audio codec
diff --git a/sound/soc/tegra/tegra20_ac97.c b/sound/soc/tegra/tegra20_ac97.c
index 2f70ea7..e58233f 100644
--- a/sound/soc/tegra/tegra20_ac97.c
+++ b/sound/soc/tegra/tegra20_ac97.c
@@ -142,13 +142,12 @@ static void tegra20_ac97_codec_write(struct snd_ac97 *ac97_snd,
} while (!time_after(jiffies, timeout));
}
-struct snd_ac97_bus_ops soc_ac97_ops = {
+static struct snd_ac97_bus_ops tegra20_ac97_ops = {
.read = tegra20_ac97_codec_read,
.write = tegra20_ac97_codec_write,
.reset = tegra20_ac97_codec_reset,
.warm_reset = tegra20_ac97_codec_warm_reset,
};
-EXPORT_SYMBOL_GPL(soc_ac97_ops);
static inline void tegra20_ac97_start_playback(struct tegra20_ac97 *ac97)
{
@@ -313,7 +312,7 @@ static const struct regmap_config tegra20_ac97_regmap_config = {
static int tegra20_ac97_platform_probe(struct platform_device *pdev)
{
struct tegra20_ac97 *ac97;
- struct resource *mem, *memregion;
+ struct resource *mem;
u32 of_dma[2];
void __iomem *regs;
int ret = 0;
@@ -327,7 +326,7 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev)
}
dev_set_drvdata(&pdev->dev, ac97);
- ac97->clk_ac97 = clk_get(&pdev->dev, NULL);
+ ac97->clk_ac97 = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(ac97->clk_ac97)) {
dev_err(&pdev->dev, "Can't retrieve ac97 clock\n");
ret = PTR_ERR(ac97->clk_ac97);
@@ -341,18 +340,9 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev)
goto err_clk_put;
}
- memregion = devm_request_mem_region(&pdev->dev, mem->start,
- resource_size(mem), DRV_NAME);
- if (!memregion) {
- dev_err(&pdev->dev, "Memory region already claimed\n");
- ret = -EBUSY;
- goto err_clk_put;
- }
-
- regs = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
- if (!regs) {
- dev_err(&pdev->dev, "ioremap failed\n");
- ret = -ENOMEM;
+ regs = devm_ioremap_resource(&pdev->dev, mem);
+ if (IS_ERR(regs)) {
+ ret = PTR_ERR(regs);
goto err_clk_put;
}
@@ -403,23 +393,9 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev)
ac97->capture_dma_data.maxburst = 4;
ac97->capture_dma_data.slave_id = of_dma[0];
- ret = snd_soc_register_component(&pdev->dev, &tegra20_ac97_component,
- &tegra20_ac97_dai, 1);
- if (ret) {
- dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
- ret = -ENOMEM;
- goto err_clk_put;
- }
-
- ret = tegra_pcm_platform_register(&pdev->dev);
- if (ret) {
- dev_err(&pdev->dev, "Could not register PCM: %d\n", ret);
- goto err_unregister_component;
- }
-
ret = tegra_asoc_utils_init(&ac97->util_data, &pdev->dev);
if (ret)
- goto err_unregister_pcm;
+ goto err_clk_put;
ret = tegra_asoc_utils_set_ac97_rate(&ac97->util_data);
if (ret)
@@ -431,20 +407,40 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev)
goto err_asoc_utils_fini;
}
+ ret = snd_soc_set_ac97_ops(&tegra20_ac97_ops);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to set AC'97 ops: %d\n", ret);
+ goto err_asoc_utils_fini;
+ }
+
+ ret = snd_soc_register_component(&pdev->dev, &tegra20_ac97_component,
+ &tegra20_ac97_dai, 1);
+ if (ret) {
+ dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
+ ret = -ENOMEM;
+ goto err_asoc_utils_fini;
+ }
+
+ ret = tegra_pcm_platform_register(&pdev->dev);
+ if (ret) {
+ dev_err(&pdev->dev, "Could not register PCM: %d\n", ret);
+ goto err_unregister_component;
+ }
+
/* XXX: crufty ASoC AC97 API - only one AC97 codec allowed */
workdata = ac97;
return 0;
-err_asoc_utils_fini:
- tegra_asoc_utils_fini(&ac97->util_data);
err_unregister_pcm:
tegra_pcm_platform_unregister(&pdev->dev);
err_unregister_component:
snd_soc_unregister_component(&pdev->dev);
+err_asoc_utils_fini:
+ tegra_asoc_utils_fini(&ac97->util_data);
err_clk_put:
- clk_put(ac97->clk_ac97);
err:
+ snd_soc_set_ac97_ops(NULL);
return ret;
}
@@ -458,7 +454,8 @@ static int tegra20_ac97_platform_remove(struct platform_device *pdev)
tegra_asoc_utils_fini(&ac97->util_data);
clk_disable_unprepare(ac97->clk_ac97);
- clk_put(ac97->clk_ac97);
+
+ snd_soc_set_ac97_ops(NULL);
return 0;
}
diff --git a/sound/soc/txx9/txx9aclc-ac97.c b/sound/soc/txx9/txx9aclc-ac97.c
index 8a28403..4bcce8a 100644
--- a/sound/soc/txx9/txx9aclc-ac97.c
+++ b/sound/soc/txx9/txx9aclc-ac97.c
@@ -119,12 +119,11 @@ static void txx9aclc_ac97_cold_reset(struct snd_ac97 *ac97)
}
/* AC97 controller operations */
-struct snd_ac97_bus_ops soc_ac97_ops = {
+static struct snd_ac97_bus_ops txx9aclc_ac97_ops = {
.read = txx9aclc_ac97_read,
.write = txx9aclc_ac97_write,
.reset = txx9aclc_ac97_cold_reset,
};
-EXPORT_SYMBOL_GPL(soc_ac97_ops);
static irqreturn_t txx9aclc_ac97_irq(int irq, void *dev_id)
{
@@ -188,9 +187,9 @@ static int txx9aclc_ac97_dev_probe(struct platform_device *pdev)
if (!r)
return -EBUSY;
- if (!devm_request_mem_region(&pdev->dev, r->start, resource_size(r),
- dev_name(&pdev->dev)))
- return -EBUSY;
+ drvdata->base = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(drvdata->base))
+ return PTR_ERR(drvdata->base);
drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
if (!drvdata)
@@ -201,14 +200,15 @@ static int txx9aclc_ac97_dev_probe(struct platform_device *pdev)
r->start >= TXX9_DIRECTMAP_BASE &&
r->start < TXX9_DIRECTMAP_BASE + 0x400000)
drvdata->physbase |= 0xf00000000ull;
- drvdata->base = devm_ioremap(&pdev->dev, r->start, resource_size(r));
- if (!drvdata->base)
- return -EBUSY;
err = devm_request_irq(&pdev->dev, irq, txx9aclc_ac97_irq,
0, dev_name(&pdev->dev), drvdata);
if (err < 0)
return err;
+ err = snd_soc_set_ac97_ops(&txx9aclc_ac97_ops);
+ if (err < 0)
+ return err;
+
return snd_soc_register_component(&pdev->dev, &txx9aclc_ac97_component,
&txx9aclc_ac97_dai, 1);
}
@@ -216,6 +216,7 @@ static int txx9aclc_ac97_dev_probe(struct platform_device *pdev)
static int txx9aclc_ac97_dev_remove(struct platform_device *pdev)
{
snd_soc_unregister_component(&pdev->dev);
+ snd_soc_set_ac97_ops(NULL);
return 0;
}
diff --git a/sound/soc/ux500/ux500_pcm.c b/sound/soc/ux500/ux500_pcm.c
index 5f01c19..ce554de 100644
--- a/sound/soc/ux500/ux500_pcm.c
+++ b/sound/soc/ux500/ux500_pcm.c
@@ -76,20 +76,20 @@ static struct dma_chan *ux500_pcm_request_chan(struct snd_soc_pcm_runtime *rtd,
dma_params = snd_soc_dai_get_dma_data(dai, substream);
dma_cfg = dma_params->dma_cfg;
- mem_data_width = STEDMA40_HALFWORD_WIDTH;
+ mem_data_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
switch (dma_params->data_size) {
case 32:
- per_data_width = STEDMA40_WORD_WIDTH;
+ per_data_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
break;
case 16:
- per_data_width = STEDMA40_HALFWORD_WIDTH;
+ per_data_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
break;
case 8:
- per_data_width = STEDMA40_BYTE_WIDTH;
+ per_data_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
break;
default:
- per_data_width = STEDMA40_WORD_WIDTH;
+ per_data_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
}
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
diff --git a/sound/sound_core.c b/sound/sound_core.c
index 359753f..45759f4 100644
--- a/sound/sound_core.c
+++ b/sound/sound_core.c
@@ -292,7 +292,7 @@ retry:
}
device_create(sound_class, dev, MKDEV(SOUND_MAJOR, s->unit_minor),
- NULL, s->name+6);
+ NULL, "%s", s->name+6);
return s->unit_minor;
fail:
diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c
index 75e6016..eee7afc 100644
--- a/sound/sparc/dbri.c
+++ b/sound/sparc/dbri.c
@@ -2670,8 +2670,6 @@ static int dbri_remove(struct platform_device *op)
snd_dbri_free(card->private_data);
snd_card_free(card);
- dev_set_drvdata(&op->dev, NULL);
-
return 0;
}
diff --git a/sound/spi/at73c213.c b/sound/spi/at73c213.c
index a1a24b9..8e3d9a6 100644
--- a/sound/spi/at73c213.c
+++ b/sound/spi/at73c213.c
@@ -1070,7 +1070,6 @@ out:
ssc_free(chip->ssc);
snd_card_free(card);
- dev_set_drvdata(&spi->dev, NULL);
return 0;
}
diff --git a/sound/usb/6fire/chip.c b/sound/usb/6fire/chip.c
index 4394ae7..c39c779 100644
--- a/sound/usb/6fire/chip.c
+++ b/sound/usb/6fire/chip.c
@@ -30,7 +30,7 @@
MODULE_AUTHOR("Torsten Schenk <torsten.schenk@zoho.com>");
MODULE_DESCRIPTION("TerraTec DMX 6Fire USB audio driver");
MODULE_LICENSE("GPL v2");
-MODULE_SUPPORTED_DEVICE("{{TerraTec, DMX 6Fire USB}}");
+MODULE_SUPPORTED_DEVICE("{{TerraTec,DMX 6Fire USB}}");
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for card */
diff --git a/sound/usb/6fire/pcm.c b/sound/usb/6fire/pcm.c
index 40dd50a..c5b9cac 100644
--- a/sound/usb/6fire/pcm.c
+++ b/sound/usb/6fire/pcm.c
@@ -450,13 +450,13 @@ static int usb6fire_pcm_close(struct snd_pcm_substream *alsa_sub)
static int usb6fire_pcm_hw_params(struct snd_pcm_substream *alsa_sub,
struct snd_pcm_hw_params *hw_params)
{
- return snd_pcm_lib_malloc_pages(alsa_sub,
- params_buffer_bytes(hw_params));
+ return snd_pcm_lib_alloc_vmalloc_buffer(alsa_sub,
+ params_buffer_bytes(hw_params));
}
static int usb6fire_pcm_hw_free(struct snd_pcm_substream *alsa_sub)
{
- return snd_pcm_lib_free_pages(alsa_sub);
+ return snd_pcm_lib_free_vmalloc_buffer(alsa_sub);
}
static int usb6fire_pcm_prepare(struct snd_pcm_substream *alsa_sub)
@@ -560,6 +560,8 @@ static struct snd_pcm_ops pcm_ops = {
.prepare = usb6fire_pcm_prepare,
.trigger = usb6fire_pcm_trigger,
.pointer = usb6fire_pcm_pointer,
+ .page = snd_pcm_lib_get_vmalloc_page,
+ .mmap = snd_pcm_lib_mmap_vmalloc,
};
static void usb6fire_pcm_init_urb(struct pcm_urb *urb,
@@ -622,10 +624,6 @@ int usb6fire_pcm_init(struct sfire_chip *chip)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pcm_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcm_ops);
- ret = snd_pcm_lib_preallocate_pages_for_all(pcm,
- SNDRV_DMA_TYPE_CONTINUOUS,
- snd_dma_continuous_data(GFP_KERNEL),
- MAX_BUFSIZE, MAX_BUFSIZE);
if (ret) {
kfree(rt);
snd_printk(KERN_ERR PREFIX
diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig
index 225dfd7..de9408b 100644
--- a/sound/usb/Kconfig
+++ b/sound/usb/Kconfig
@@ -115,5 +115,36 @@ config SND_USB_6FIRE
and further help can be found at
http://sixfireusb.sourceforge.net
+config SND_USB_HIFACE
+ tristate "M2Tech hiFace USB-SPDIF driver"
+ select SND_PCM
+ help
+ Select this option to include support for M2Tech hiFace USB-SPDIF
+ interface.
+
+ This driver supports the original M2Tech hiFace and some other
+ compatible devices. The supported products are:
+
+ * M2Tech Young
+ * M2Tech hiFace
+ * M2Tech North Star
+ * M2Tech W4S Young
+ * M2Tech Corrson
+ * M2Tech AUDIA
+ * M2Tech SL Audio
+ * M2Tech Empirical
+ * M2Tech Rockna
+ * M2Tech Pathos
+ * M2Tech Metronome
+ * M2Tech CAD
+ * M2Tech Audio Esclusive
+ * M2Tech Rotel
+ * M2Tech Eeaudio
+ * The Chord Company CHORD
+ * AVA Group A/S Vitus
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-usb-hiface.
+
endif # SND_USB
diff --git a/sound/usb/Makefile b/sound/usb/Makefile
index ac256dc..abe668f 100644
--- a/sound/usb/Makefile
+++ b/sound/usb/Makefile
@@ -23,4 +23,4 @@ obj-$(CONFIG_SND_USB_UA101) += snd-usbmidi-lib.o
obj-$(CONFIG_SND_USB_USX2Y) += snd-usbmidi-lib.o
obj-$(CONFIG_SND_USB_US122L) += snd-usbmidi-lib.o
-obj-$(CONFIG_SND) += misc/ usx2y/ caiaq/ 6fire/
+obj-$(CONFIG_SND) += misc/ usx2y/ caiaq/ 6fire/ hiface/
diff --git a/sound/usb/caiaq/audio.c b/sound/usb/caiaq/audio.c
index c191618..7103b09 100644
--- a/sound/usb/caiaq/audio.c
+++ b/sound/usb/caiaq/audio.c
@@ -183,14 +183,15 @@ static int snd_usb_caiaq_substream_close(struct snd_pcm_substream *substream)
static int snd_usb_caiaq_pcm_hw_params(struct snd_pcm_substream *sub,
struct snd_pcm_hw_params *hw_params)
{
- return snd_pcm_lib_malloc_pages(sub, params_buffer_bytes(hw_params));
+ return snd_pcm_lib_alloc_vmalloc_buffer(sub,
+ params_buffer_bytes(hw_params));
}
static int snd_usb_caiaq_pcm_hw_free(struct snd_pcm_substream *sub)
{
struct snd_usb_caiaqdev *cdev = snd_pcm_substream_chip(sub);
deactivate_substream(cdev, sub);
- return snd_pcm_lib_free_pages(sub);
+ return snd_pcm_lib_free_vmalloc_buffer(sub);
}
/* this should probably go upstream */
@@ -345,7 +346,9 @@ static struct snd_pcm_ops snd_usb_caiaq_ops = {
.hw_free = snd_usb_caiaq_pcm_hw_free,
.prepare = snd_usb_caiaq_pcm_prepare,
.trigger = snd_usb_caiaq_pcm_trigger,
- .pointer = snd_usb_caiaq_pcm_pointer
+ .pointer = snd_usb_caiaq_pcm_pointer,
+ .page = snd_pcm_lib_get_vmalloc_page,
+ .mmap = snd_pcm_lib_mmap_vmalloc,
};
static void check_for_elapsed_periods(struct snd_usb_caiaqdev *cdev,
@@ -852,11 +855,6 @@ int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *cdev)
snd_pcm_set_ops(cdev->pcm, SNDRV_PCM_STREAM_CAPTURE,
&snd_usb_caiaq_ops);
- snd_pcm_lib_preallocate_pages_for_all(cdev->pcm,
- SNDRV_DMA_TYPE_CONTINUOUS,
- snd_dma_continuous_data(GFP_KERNEL),
- MAX_BUFFER_SIZE, MAX_BUFFER_SIZE);
-
cdev->data_cb_info =
kmalloc(sizeof(struct snd_usb_caiaq_cb_info) * N_URBS,
GFP_KERNEL);
diff --git a/sound/usb/caiaq/device.c b/sound/usb/caiaq/device.c
index 48b63cc..1a61dd1 100644
--- a/sound/usb/caiaq/device.c
+++ b/sound/usb/caiaq/device.c
@@ -39,25 +39,24 @@
MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
MODULE_DESCRIPTION("caiaq USB audio");
MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2},"
- "{Native Instruments, RigKontrol3},"
- "{Native Instruments, Kore Controller},"
- "{Native Instruments, Kore Controller 2},"
- "{Native Instruments, Audio Kontrol 1},"
- "{Native Instruments, Audio 2 DJ},"
- "{Native Instruments, Audio 4 DJ},"
- "{Native Instruments, Audio 8 DJ},"
- "{Native Instruments, Traktor Audio 2},"
- "{Native Instruments, Session I/O},"
- "{Native Instruments, GuitarRig mobile},"
- "{Native Instruments, Traktor Kontrol X1},"
- "{Native Instruments, Traktor Kontrol S4},"
- "{Native Instruments, Maschine Controller}}");
+MODULE_SUPPORTED_DEVICE("{{Native Instruments,RigKontrol2},"
+ "{Native Instruments,RigKontrol3},"
+ "{Native Instruments,Kore Controller},"
+ "{Native Instruments,Kore Controller 2},"
+ "{Native Instruments,Audio Kontrol 1},"
+ "{Native Instruments,Audio 2 DJ},"
+ "{Native Instruments,Audio 4 DJ},"
+ "{Native Instruments,Audio 8 DJ},"
+ "{Native Instruments,Traktor Audio 2},"
+ "{Native Instruments,Session I/O},"
+ "{Native Instruments,GuitarRig mobile},"
+ "{Native Instruments,Traktor Kontrol X1},"
+ "{Native Instruments,Traktor Kontrol S4},"
+ "{Native Instruments,Maschine Controller}}");
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */
static char* id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for this card */
static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */
-static int snd_card_used[SNDRV_CARDS];
module_param_array(index, int, NULL, 0444);
MODULE_PARM_DESC(index, "Index value for the caiaq sound device");
@@ -388,7 +387,7 @@ static int create_card(struct usb_device *usb_dev,
struct snd_usb_caiaqdev *cdev;
for (devnum = 0; devnum < SNDRV_CARDS; devnum++)
- if (enable[devnum] && !snd_card_used[devnum])
+ if (enable[devnum])
break;
if (devnum >= SNDRV_CARDS)
diff --git a/sound/usb/card.c b/sound/usb/card.c
index 1a03317..64952e2 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -147,14 +147,32 @@ static int snd_usb_create_stream(struct snd_usb_audio *chip, int ctrlif, int int
return -EINVAL;
}
+ alts = &iface->altsetting[0];
+ altsd = get_iface_desc(alts);
+
+ /*
+ * Android with both accessory and audio interfaces enabled gets the
+ * interface numbers wrong.
+ */
+ if ((chip->usb_id == USB_ID(0x18d1, 0x2d04) ||
+ chip->usb_id == USB_ID(0x18d1, 0x2d05)) &&
+ interface == 0 &&
+ altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC &&
+ altsd->bInterfaceSubClass == USB_SUBCLASS_VENDOR_SPEC) {
+ interface = 2;
+ iface = usb_ifnum_to_if(dev, interface);
+ if (!iface)
+ return -EINVAL;
+ alts = &iface->altsetting[0];
+ altsd = get_iface_desc(alts);
+ }
+
if (usb_interface_claimed(iface)) {
snd_printdd(KERN_INFO "%d:%d:%d: skipping, already claimed\n",
dev->devnum, ctrlif, interface);
return -EINVAL;
}
- alts = &iface->altsetting[0];
- altsd = get_iface_desc(alts);
if ((altsd->bInterfaceClass == USB_CLASS_AUDIO ||
altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC) &&
altsd->bInterfaceSubClass == USB_SUBCLASS_MIDISTREAMING) {
diff --git a/sound/usb/card.h b/sound/usb/card.h
index bf2889a..5ecacaa 100644
--- a/sound/usb/card.h
+++ b/sound/usb/card.h
@@ -21,6 +21,7 @@ struct audioformat {
unsigned char endpoint; /* endpoint */
unsigned char ep_attr; /* endpoint attributes */
unsigned char datainterval; /* log_2 of data packet interval */
+ unsigned char protocol; /* UAC_VERSION_1/2 */
unsigned int maxpacksize; /* max. packet size */
unsigned int rates; /* rate bitmasks */
unsigned int rate_min, rate_max; /* min/max rates */
diff --git a/sound/usb/clock.c b/sound/usb/clock.c
index 3a2ce39..86f80c6 100644
--- a/sound/usb/clock.c
+++ b/sound/usb/clock.c
@@ -407,9 +407,7 @@ int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface,
struct usb_host_interface *alts,
struct audioformat *fmt, int rate)
{
- struct usb_interface_descriptor *altsd = get_iface_desc(alts);
-
- switch (altsd->bInterfaceProtocol) {
+ switch (fmt->protocol) {
case UAC_VERSION_1:
default:
return set_sample_rate_v1(chip, iface, alts, fmt, rate);
diff --git a/sound/usb/format.c b/sound/usb/format.c
index 99299ff..3525231 100644
--- a/sound/usb/format.c
+++ b/sound/usb/format.c
@@ -43,13 +43,12 @@
*/
static u64 parse_audio_format_i_type(struct snd_usb_audio *chip,
struct audioformat *fp,
- unsigned int format, void *_fmt,
- int protocol)
+ unsigned int format, void *_fmt)
{
int sample_width, sample_bytes;
u64 pcm_formats = 0;
- switch (protocol) {
+ switch (fp->protocol) {
case UAC_VERSION_1:
default: {
struct uac_format_type_i_discrete_descriptor *fmt = _fmt;
@@ -360,11 +359,8 @@ err:
*/
static int parse_audio_format_i(struct snd_usb_audio *chip,
struct audioformat *fp, unsigned int format,
- struct uac_format_type_i_continuous_descriptor *fmt,
- struct usb_host_interface *iface)
+ struct uac_format_type_i_continuous_descriptor *fmt)
{
- struct usb_interface_descriptor *altsd = get_iface_desc(iface);
- int protocol = altsd->bInterfaceProtocol;
snd_pcm_format_t pcm_format;
int ret;
@@ -387,8 +383,7 @@ static int parse_audio_format_i(struct snd_usb_audio *chip,
}
fp->formats = pcm_format_to_bits(pcm_format);
} else {
- fp->formats = parse_audio_format_i_type(chip, fp, format,
- fmt, protocol);
+ fp->formats = parse_audio_format_i_type(chip, fp, format, fmt);
if (!fp->formats)
return -EINVAL;
}
@@ -398,11 +393,8 @@ static int parse_audio_format_i(struct snd_usb_audio *chip,
* proprietary class specific descriptor.
* audio class v2 uses class specific EP0 range requests for that.
*/
- switch (protocol) {
+ switch (fp->protocol) {
default:
- snd_printdd(KERN_WARNING "%d:%u:%d : invalid protocol version %d, assuming v1\n",
- chip->dev->devnum, fp->iface, fp->altsetting, protocol);
- /* fall through */
case UAC_VERSION_1:
fp->channels = fmt->bNrChannels;
ret = parse_audio_format_rates_v1(chip, fp, (unsigned char *) fmt, 7);
@@ -427,12 +419,9 @@ static int parse_audio_format_i(struct snd_usb_audio *chip,
*/
static int parse_audio_format_ii(struct snd_usb_audio *chip,
struct audioformat *fp,
- int format, void *_fmt,
- struct usb_host_interface *iface)
+ int format, void *_fmt)
{
int brate, framesize, ret;
- struct usb_interface_descriptor *altsd = get_iface_desc(iface);
- int protocol = altsd->bInterfaceProtocol;
switch (format) {
case UAC_FORMAT_TYPE_II_AC3:
@@ -452,11 +441,8 @@ static int parse_audio_format_ii(struct snd_usb_audio *chip,
fp->channels = 1;
- switch (protocol) {
+ switch (fp->protocol) {
default:
- snd_printdd(KERN_WARNING "%d:%u:%d : invalid protocol version %d, assuming v1\n",
- chip->dev->devnum, fp->iface, fp->altsetting, protocol);
- /* fall through */
case UAC_VERSION_1: {
struct uac_format_type_ii_discrete_descriptor *fmt = _fmt;
brate = le16_to_cpu(fmt->wMaxBitRate);
@@ -483,17 +469,17 @@ static int parse_audio_format_ii(struct snd_usb_audio *chip,
int snd_usb_parse_audio_format(struct snd_usb_audio *chip,
struct audioformat *fp, unsigned int format,
struct uac_format_type_i_continuous_descriptor *fmt,
- int stream, struct usb_host_interface *iface)
+ int stream)
{
int err;
switch (fmt->bFormatType) {
case UAC_FORMAT_TYPE_I:
case UAC_FORMAT_TYPE_III:
- err = parse_audio_format_i(chip, fp, format, fmt, iface);
+ err = parse_audio_format_i(chip, fp, format, fmt);
break;
case UAC_FORMAT_TYPE_II:
- err = parse_audio_format_ii(chip, fp, format, fmt, iface);
+ err = parse_audio_format_ii(chip, fp, format, fmt);
break;
default:
snd_printd(KERN_INFO "%d:%u:%d : format type %d is not supported yet\n",
diff --git a/sound/usb/format.h b/sound/usb/format.h
index 6f31522..4b8a011 100644
--- a/sound/usb/format.h
+++ b/sound/usb/format.h
@@ -4,6 +4,6 @@
int snd_usb_parse_audio_format(struct snd_usb_audio *chip,
struct audioformat *fp, unsigned int format,
struct uac_format_type_i_continuous_descriptor *fmt,
- int stream, struct usb_host_interface *iface);
+ int stream);
#endif /* __USBAUDIO_FORMAT_H */
diff --git a/sound/usb/hiface/Makefile b/sound/usb/hiface/Makefile
new file mode 100644
index 0000000..463b136
--- /dev/null
+++ b/sound/usb/hiface/Makefile
@@ -0,0 +1,2 @@
+snd-usb-hiface-objs := chip.o pcm.o
+obj-$(CONFIG_SND_USB_HIFACE) += snd-usb-hiface.o
diff --git a/sound/usb/hiface/chip.c b/sound/usb/hiface/chip.c
new file mode 100644
index 0000000..b0dcb39
--- /dev/null
+++ b/sound/usb/hiface/chip.c
@@ -0,0 +1,297 @@
+/*
+ * Linux driver for M2Tech hiFace compatible devices
+ *
+ * Copyright 2012-2013 (C) M2TECH S.r.l and Amarula Solutions B.V.
+ *
+ * Authors: Michael Trimarchi <michael@amarulasolutions.com>
+ * Antonio Ospite <ao2@amarulasolutions.com>
+ *
+ * The driver is based on the work done in TerraTec DMX 6Fire USB
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <sound/initval.h>
+
+#include "chip.h"
+#include "pcm.h"
+
+MODULE_AUTHOR("Michael Trimarchi <michael@amarulasolutions.com>");
+MODULE_AUTHOR("Antonio Ospite <ao2@amarulasolutions.com>");
+MODULE_DESCRIPTION("M2Tech hiFace USB-SPDIF audio driver");
+MODULE_LICENSE("GPL v2");
+MODULE_SUPPORTED_DEVICE("{{M2Tech,Young},"
+ "{M2Tech,hiFace},"
+ "{M2Tech,North Star},"
+ "{M2Tech,W4S Young},"
+ "{M2Tech,Corrson},"
+ "{M2Tech,AUDIA},"
+ "{M2Tech,SL Audio},"
+ "{M2Tech,Empirical},"
+ "{M2Tech,Rockna},"
+ "{M2Tech,Pathos},"
+ "{M2Tech,Metronome},"
+ "{M2Tech,CAD},"
+ "{M2Tech,Audio Esclusive},"
+ "{M2Tech,Rotel},"
+ "{M2Tech,Eeaudio},"
+ "{The Chord Company,CHORD},"
+ "{AVA Group A/S,Vitus}}");
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for card */
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */
+
+#define DRIVER_NAME "snd-usb-hiface"
+#define CARD_NAME "hiFace"
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard.");
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard.");
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard.");
+
+static DEFINE_MUTEX(register_mutex);
+
+struct hiface_vendor_quirk {
+ const char *device_name;
+ u8 extra_freq;
+};
+
+static int hiface_chip_create(struct usb_device *device, int idx,
+ const struct hiface_vendor_quirk *quirk,
+ struct hiface_chip **rchip)
+{
+ struct snd_card *card = NULL;
+ struct hiface_chip *chip;
+ int ret;
+ int len;
+
+ *rchip = NULL;
+
+ /* if we are here, card can be registered in alsa. */
+ ret = snd_card_create(index[idx], id[idx], THIS_MODULE, sizeof(*chip), &card);
+ if (ret < 0) {
+ dev_err(&device->dev, "cannot create alsa card.\n");
+ return ret;
+ }
+
+ strlcpy(card->driver, DRIVER_NAME, sizeof(card->driver));
+
+ if (quirk && quirk->device_name)
+ strlcpy(card->shortname, quirk->device_name, sizeof(card->shortname));
+ else
+ strlcpy(card->shortname, "M2Tech generic audio", sizeof(card->shortname));
+
+ strlcat(card->longname, card->shortname, sizeof(card->longname));
+ len = strlcat(card->longname, " at ", sizeof(card->longname));
+ if (len < sizeof(card->longname))
+ usb_make_path(device, card->longname + len,
+ sizeof(card->longname) - len);
+
+ chip = card->private_data;
+ chip->dev = device;
+ chip->card = card;
+
+ *rchip = chip;
+ return 0;
+}
+
+static int hiface_chip_probe(struct usb_interface *intf,
+ const struct usb_device_id *usb_id)
+{
+ const struct hiface_vendor_quirk *quirk = (struct hiface_vendor_quirk *)usb_id->driver_info;
+ int ret;
+ int i;
+ struct hiface_chip *chip;
+ struct usb_device *device = interface_to_usbdev(intf);
+
+ ret = usb_set_interface(device, 0, 0);
+ if (ret != 0) {
+ dev_err(&device->dev, "can't set first interface for " CARD_NAME " device.\n");
+ return -EIO;
+ }
+
+ /* check whether the card is already registered */
+ chip = NULL;
+ mutex_lock(&register_mutex);
+
+ for (i = 0; i < SNDRV_CARDS; i++)
+ if (enable[i])
+ break;
+
+ if (i >= SNDRV_CARDS) {
+ dev_err(&device->dev, "no available " CARD_NAME " audio device\n");
+ ret = -ENODEV;
+ goto err;
+ }
+
+ ret = hiface_chip_create(device, i, quirk, &chip);
+ if (ret < 0)
+ goto err;
+
+ snd_card_set_dev(chip->card, &intf->dev);
+
+ ret = hiface_pcm_init(chip, quirk ? quirk->extra_freq : 0);
+ if (ret < 0)
+ goto err_chip_destroy;
+
+ ret = snd_card_register(chip->card);
+ if (ret < 0) {
+ dev_err(&device->dev, "cannot register " CARD_NAME " card\n");
+ goto err_chip_destroy;
+ }
+
+ mutex_unlock(&register_mutex);
+
+ usb_set_intfdata(intf, chip);
+ return 0;
+
+err_chip_destroy:
+ snd_card_free(chip->card);
+err:
+ mutex_unlock(&register_mutex);
+ return ret;
+}
+
+static void hiface_chip_disconnect(struct usb_interface *intf)
+{
+ struct hiface_chip *chip;
+ struct snd_card *card;
+
+ chip = usb_get_intfdata(intf);
+ if (!chip)
+ return;
+
+ card = chip->card;
+
+ /* Make sure that the userspace cannot create new request */
+ snd_card_disconnect(card);
+
+ hiface_pcm_abort(chip);
+ snd_card_free_when_closed(card);
+}
+
+static const struct usb_device_id device_table[] = {
+ {
+ USB_DEVICE(0x04b4, 0x0384),
+ .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
+ .device_name = "Young",
+ .extra_freq = 1,
+ }
+ },
+ {
+ USB_DEVICE(0x04b4, 0x930b),
+ .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
+ .device_name = "hiFace",
+ }
+ },
+ {
+ USB_DEVICE(0x04b4, 0x931b),
+ .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
+ .device_name = "North Star",
+ }
+ },
+ {
+ USB_DEVICE(0x04b4, 0x931c),
+ .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
+ .device_name = "W4S Young",
+ }
+ },
+ {
+ USB_DEVICE(0x04b4, 0x931d),
+ .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
+ .device_name = "Corrson",
+ }
+ },
+ {
+ USB_DEVICE(0x04b4, 0x931e),
+ .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
+ .device_name = "AUDIA",
+ }
+ },
+ {
+ USB_DEVICE(0x04b4, 0x931f),
+ .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
+ .device_name = "SL Audio",
+ }
+ },
+ {
+ USB_DEVICE(0x04b4, 0x9320),
+ .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
+ .device_name = "Empirical",
+ }
+ },
+ {
+ USB_DEVICE(0x04b4, 0x9321),
+ .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
+ .device_name = "Rockna",
+ }
+ },
+ {
+ USB_DEVICE(0x249c, 0x9001),
+ .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
+ .device_name = "Pathos",
+ }
+ },
+ {
+ USB_DEVICE(0x249c, 0x9002),
+ .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
+ .device_name = "Metronome",
+ }
+ },
+ {
+ USB_DEVICE(0x249c, 0x9006),
+ .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
+ .device_name = "CAD",
+ }
+ },
+ {
+ USB_DEVICE(0x249c, 0x9008),
+ .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
+ .device_name = "Audio Esclusive",
+ }
+ },
+ {
+ USB_DEVICE(0x249c, 0x931c),
+ .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
+ .device_name = "Rotel",
+ }
+ },
+ {
+ USB_DEVICE(0x249c, 0x932c),
+ .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
+ .device_name = "Eeaudio",
+ }
+ },
+ {
+ USB_DEVICE(0x245f, 0x931c),
+ .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
+ .device_name = "CHORD",
+ }
+ },
+ {
+ USB_DEVICE(0x25c6, 0x9002),
+ .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
+ .device_name = "Vitus",
+ }
+ },
+ {}
+};
+
+MODULE_DEVICE_TABLE(usb, device_table);
+
+static struct usb_driver hiface_usb_driver = {
+ .name = DRIVER_NAME,
+ .probe = hiface_chip_probe,
+ .disconnect = hiface_chip_disconnect,
+ .id_table = device_table,
+};
+
+module_usb_driver(hiface_usb_driver);
diff --git a/sound/usb/hiface/chip.h b/sound/usb/hiface/chip.h
new file mode 100644
index 0000000..189a137
--- /dev/null
+++ b/sound/usb/hiface/chip.h
@@ -0,0 +1,30 @@
+/*
+ * Linux driver for M2Tech hiFace compatible devices
+ *
+ * Copyright 2012-2013 (C) M2TECH S.r.l and Amarula Solutions B.V.
+ *
+ * Authors: Michael Trimarchi <michael@amarulasolutions.com>
+ * Antonio Ospite <ao2@amarulasolutions.com>
+ *
+ * The driver is based on the work done in TerraTec DMX 6Fire USB
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef HIFACE_CHIP_H
+#define HIFACE_CHIP_H
+
+#include <linux/usb.h>
+#include <sound/core.h>
+
+struct pcm_runtime;
+
+struct hiface_chip {
+ struct usb_device *dev;
+ struct snd_card *card;
+ struct pcm_runtime *pcm;
+};
+#endif /* HIFACE_CHIP_H */
diff --git a/sound/usb/hiface/pcm.c b/sound/usb/hiface/pcm.c
new file mode 100644
index 0000000..6430ed2
--- /dev/null
+++ b/sound/usb/hiface/pcm.c
@@ -0,0 +1,621 @@
+/*
+ * Linux driver for M2Tech hiFace compatible devices
+ *
+ * Copyright 2012-2013 (C) M2TECH S.r.l and Amarula Solutions B.V.
+ *
+ * Authors: Michael Trimarchi <michael@amarulasolutions.com>
+ * Antonio Ospite <ao2@amarulasolutions.com>
+ *
+ * The driver is based on the work done in TerraTec DMX 6Fire USB
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/slab.h>
+#include <sound/pcm.h>
+
+#include "pcm.h"
+#include "chip.h"
+
+#define OUT_EP 0x2
+#define PCM_N_URBS 8
+#define PCM_PACKET_SIZE 4096
+#define PCM_BUFFER_SIZE (2 * PCM_N_URBS * PCM_PACKET_SIZE)
+
+struct pcm_urb {
+ struct hiface_chip *chip;
+
+ struct urb instance;
+ struct usb_anchor submitted;
+ u8 *buffer;
+};
+
+struct pcm_substream {
+ spinlock_t lock;
+ struct snd_pcm_substream *instance;
+
+ bool active;
+ snd_pcm_uframes_t dma_off; /* current position in alsa dma_area */
+ snd_pcm_uframes_t period_off; /* current position in current period */
+};
+
+enum { /* pcm streaming states */
+ STREAM_DISABLED, /* no pcm streaming */
+ STREAM_STARTING, /* pcm streaming requested, waiting to become ready */
+ STREAM_RUNNING, /* pcm streaming running */
+ STREAM_STOPPING
+};
+
+struct pcm_runtime {
+ struct hiface_chip *chip;
+ struct snd_pcm *instance;
+
+ struct pcm_substream playback;
+ bool panic; /* if set driver won't do anymore pcm on device */
+
+ struct pcm_urb out_urbs[PCM_N_URBS];
+
+ struct mutex stream_mutex;
+ u8 stream_state; /* one of STREAM_XXX */
+ u8 extra_freq;
+ wait_queue_head_t stream_wait_queue;
+ bool stream_wait_cond;
+};
+
+static const unsigned int rates[] = { 44100, 48000, 88200, 96000, 176400, 192000,
+ 352800, 384000 };
+static const struct snd_pcm_hw_constraint_list constraints_extra_rates = {
+ .count = ARRAY_SIZE(rates),
+ .list = rates,
+ .mask = 0,
+};
+
+static const struct snd_pcm_hardware pcm_hw = {
+ .info = SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_PAUSE |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_BATCH,
+
+ .formats = SNDRV_PCM_FMTBIT_S32_LE,
+
+ .rates = SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_88200 |
+ SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_176400 |
+ SNDRV_PCM_RATE_192000,
+
+ .rate_min = 44100,
+ .rate_max = 192000, /* changes in hiface_pcm_open to support extra rates */
+ .channels_min = 2,
+ .channels_max = 2,
+ .buffer_bytes_max = PCM_BUFFER_SIZE,
+ .period_bytes_min = PCM_PACKET_SIZE,
+ .period_bytes_max = PCM_BUFFER_SIZE,
+ .periods_min = 2,
+ .periods_max = 1024
+};
+
+/* message values used to change the sample rate */
+#define HIFACE_SET_RATE_REQUEST 0xb0
+
+#define HIFACE_RATE_44100 0x43
+#define HIFACE_RATE_48000 0x4b
+#define HIFACE_RATE_88200 0x42
+#define HIFACE_RATE_96000 0x4a
+#define HIFACE_RATE_176400 0x40
+#define HIFACE_RATE_192000 0x48
+#define HIFACE_RATE_352000 0x58
+#define HIFACE_RATE_384000 0x68
+
+static int hiface_pcm_set_rate(struct pcm_runtime *rt, unsigned int rate)
+{
+ struct usb_device *device = rt->chip->dev;
+ u16 rate_value;
+ int ret;
+
+ /* We are already sure that the rate is supported here thanks to
+ * ALSA constraints
+ */
+ switch (rate) {
+ case 44100:
+ rate_value = HIFACE_RATE_44100;
+ break;
+ case 48000:
+ rate_value = HIFACE_RATE_48000;
+ break;
+ case 88200:
+ rate_value = HIFACE_RATE_88200;
+ break;
+ case 96000:
+ rate_value = HIFACE_RATE_96000;
+ break;
+ case 176400:
+ rate_value = HIFACE_RATE_176400;
+ break;
+ case 192000:
+ rate_value = HIFACE_RATE_192000;
+ break;
+ case 352000:
+ rate_value = HIFACE_RATE_352000;
+ break;
+ case 384000:
+ rate_value = HIFACE_RATE_384000;
+ break;
+ default:
+ dev_err(&device->dev, "Unsupported rate %d\n", rate);
+ return -EINVAL;
+ }
+
+ /*
+ * USBIO: Vendor 0xb0(wValue=0x0043, wIndex=0x0000)
+ * 43 b0 43 00 00 00 00 00
+ * USBIO: Vendor 0xb0(wValue=0x004b, wIndex=0x0000)
+ * 43 b0 4b 00 00 00 00 00
+ * This control message doesn't have any ack from the
+ * other side
+ */
+ ret = usb_control_msg(device, usb_sndctrlpipe(device, 0),
+ HIFACE_SET_RATE_REQUEST,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
+ rate_value, 0, NULL, 0, 100);
+ if (ret < 0) {
+ dev_err(&device->dev, "Error setting samplerate %d.\n", rate);
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct pcm_substream *hiface_pcm_get_substream(struct snd_pcm_substream
+ *alsa_sub)
+{
+ struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub);
+ struct device *device = &rt->chip->dev->dev;
+
+ if (alsa_sub->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ return &rt->playback;
+
+ dev_err(device, "Error getting pcm substream slot.\n");
+ return NULL;
+}
+
+/* call with stream_mutex locked */
+static void hiface_pcm_stream_stop(struct pcm_runtime *rt)
+{
+ int i, time;
+
+ if (rt->stream_state != STREAM_DISABLED) {
+ rt->stream_state = STREAM_STOPPING;
+
+ for (i = 0; i < PCM_N_URBS; i++) {
+ time = usb_wait_anchor_empty_timeout(
+ &rt->out_urbs[i].submitted, 100);
+ if (!time)
+ usb_kill_anchored_urbs(
+ &rt->out_urbs[i].submitted);
+ usb_kill_urb(&rt->out_urbs[i].instance);
+ }
+
+ rt->stream_state = STREAM_DISABLED;
+ }
+}
+
+/* call with stream_mutex locked */
+static int hiface_pcm_stream_start(struct pcm_runtime *rt)
+{
+ int ret = 0;
+ int i;
+
+ if (rt->stream_state == STREAM_DISABLED) {
+
+ /* reset panic state when starting a new stream */
+ rt->panic = false;
+
+ /* submit our out urbs zero init */
+ rt->stream_state = STREAM_STARTING;
+ for (i = 0; i < PCM_N_URBS; i++) {
+ memset(rt->out_urbs[i].buffer, 0, PCM_PACKET_SIZE);
+ usb_anchor_urb(&rt->out_urbs[i].instance,
+ &rt->out_urbs[i].submitted);
+ ret = usb_submit_urb(&rt->out_urbs[i].instance,
+ GFP_ATOMIC);
+ if (ret) {
+ hiface_pcm_stream_stop(rt);
+ return ret;
+ }
+ }
+
+ /* wait for first out urb to return (sent in in urb handler) */
+ wait_event_timeout(rt->stream_wait_queue, rt->stream_wait_cond,
+ HZ);
+ if (rt->stream_wait_cond) {
+ struct device *device = &rt->chip->dev->dev;
+ dev_dbg(device, "%s: Stream is running wakeup event\n",
+ __func__);
+ rt->stream_state = STREAM_RUNNING;
+ } else {
+ hiface_pcm_stream_stop(rt);
+ return -EIO;
+ }
+ }
+ return ret;
+}
+
+/* The hardware wants word-swapped 32-bit values */
+static void memcpy_swahw32(u8 *dest, u8 *src, unsigned int n)
+{
+ unsigned int i;
+
+ for (i = 0; i < n / 4; i++)
+ ((u32 *)dest)[i] = swahw32(((u32 *)src)[i]);
+}
+
+/* call with substream locked */
+/* returns true if a period elapsed */
+static bool hiface_pcm_playback(struct pcm_substream *sub, struct pcm_urb *urb)
+{
+ struct snd_pcm_runtime *alsa_rt = sub->instance->runtime;
+ struct device *device = &urb->chip->dev->dev;
+ u8 *source;
+ unsigned int pcm_buffer_size;
+
+ WARN_ON(alsa_rt->format != SNDRV_PCM_FORMAT_S32_LE);
+
+ pcm_buffer_size = snd_pcm_lib_buffer_bytes(sub->instance);
+
+ if (sub->dma_off + PCM_PACKET_SIZE <= pcm_buffer_size) {
+ dev_dbg(device, "%s: (1) buffer_size %#x dma_offset %#x\n", __func__,
+ (unsigned int) pcm_buffer_size,
+ (unsigned int) sub->dma_off);
+
+ source = alsa_rt->dma_area + sub->dma_off;
+ memcpy_swahw32(urb->buffer, source, PCM_PACKET_SIZE);
+ } else {
+ /* wrap around at end of ring buffer */
+ unsigned int len;
+
+ dev_dbg(device, "%s: (2) buffer_size %#x dma_offset %#x\n", __func__,
+ (unsigned int) pcm_buffer_size,
+ (unsigned int) sub->dma_off);
+
+ len = pcm_buffer_size - sub->dma_off;
+
+ source = alsa_rt->dma_area + sub->dma_off;
+ memcpy_swahw32(urb->buffer, source, len);
+
+ source = alsa_rt->dma_area;
+ memcpy_swahw32(urb->buffer + len, source,
+ PCM_PACKET_SIZE - len);
+ }
+ sub->dma_off += PCM_PACKET_SIZE;
+ if (sub->dma_off >= pcm_buffer_size)
+ sub->dma_off -= pcm_buffer_size;
+
+ sub->period_off += PCM_PACKET_SIZE;
+ if (sub->period_off >= alsa_rt->period_size) {
+ sub->period_off %= alsa_rt->period_size;
+ return true;
+ }
+ return false;
+}
+
+static void hiface_pcm_out_urb_handler(struct urb *usb_urb)
+{
+ struct pcm_urb *out_urb = usb_urb->context;
+ struct pcm_runtime *rt = out_urb->chip->pcm;
+ struct pcm_substream *sub;
+ bool do_period_elapsed = false;
+ unsigned long flags;
+ int ret;
+
+ if (rt->panic || rt->stream_state == STREAM_STOPPING)
+ return;
+
+ if (unlikely(usb_urb->status == -ENOENT || /* unlinked */
+ usb_urb->status == -ENODEV || /* device removed */
+ usb_urb->status == -ECONNRESET || /* unlinked */
+ usb_urb->status == -ESHUTDOWN)) { /* device disabled */
+ goto out_fail;
+ }
+
+ if (rt->stream_state == STREAM_STARTING) {
+ rt->stream_wait_cond = true;
+ wake_up(&rt->stream_wait_queue);
+ }
+
+ /* now send our playback data (if a free out urb was found) */
+ sub = &rt->playback;
+ spin_lock_irqsave(&sub->lock, flags);
+ if (sub->active)
+ do_period_elapsed = hiface_pcm_playback(sub, out_urb);
+ else
+ memset(out_urb->buffer, 0, PCM_PACKET_SIZE);
+
+ spin_unlock_irqrestore(&sub->lock, flags);
+
+ if (do_period_elapsed)
+ snd_pcm_period_elapsed(sub->instance);
+
+ ret = usb_submit_urb(&out_urb->instance, GFP_ATOMIC);
+ if (ret < 0)
+ goto out_fail;
+
+ return;
+
+out_fail:
+ rt->panic = true;
+}
+
+static int hiface_pcm_open(struct snd_pcm_substream *alsa_sub)
+{
+ struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub);
+ struct pcm_substream *sub = NULL;
+ struct snd_pcm_runtime *alsa_rt = alsa_sub->runtime;
+ int ret;
+
+ if (rt->panic)
+ return -EPIPE;
+
+ mutex_lock(&rt->stream_mutex);
+ alsa_rt->hw = pcm_hw;
+
+ if (alsa_sub->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ sub = &rt->playback;
+
+ if (!sub) {
+ struct device *device = &rt->chip->dev->dev;
+ mutex_unlock(&rt->stream_mutex);
+ dev_err(device, "Invalid stream type\n");
+ return -EINVAL;
+ }
+
+ if (rt->extra_freq) {
+ alsa_rt->hw.rates |= SNDRV_PCM_RATE_KNOT;
+ alsa_rt->hw.rate_max = 384000;
+
+ /* explicit constraints needed as we added SNDRV_PCM_RATE_KNOT */
+ ret = snd_pcm_hw_constraint_list(alsa_sub->runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ &constraints_extra_rates);
+ if (ret < 0) {
+ mutex_unlock(&rt->stream_mutex);
+ return ret;
+ }
+ }
+
+ sub->instance = alsa_sub;
+ sub->active = false;
+ mutex_unlock(&rt->stream_mutex);
+ return 0;
+}
+
+static int hiface_pcm_close(struct snd_pcm_substream *alsa_sub)
+{
+ struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub);
+ struct pcm_substream *sub = hiface_pcm_get_substream(alsa_sub);
+ unsigned long flags;
+
+ if (rt->panic)
+ return 0;
+
+ mutex_lock(&rt->stream_mutex);
+ if (sub) {
+ hiface_pcm_stream_stop(rt);
+
+ /* deactivate substream */
+ spin_lock_irqsave(&sub->lock, flags);
+ sub->instance = NULL;
+ sub->active = false;
+ spin_unlock_irqrestore(&sub->lock, flags);
+
+ }
+ mutex_unlock(&rt->stream_mutex);
+ return 0;
+}
+
+static int hiface_pcm_hw_params(struct snd_pcm_substream *alsa_sub,
+ struct snd_pcm_hw_params *hw_params)
+{
+ return snd_pcm_lib_alloc_vmalloc_buffer(alsa_sub,
+ params_buffer_bytes(hw_params));
+}
+
+static int hiface_pcm_hw_free(struct snd_pcm_substream *alsa_sub)
+{
+ return snd_pcm_lib_free_vmalloc_buffer(alsa_sub);
+}
+
+static int hiface_pcm_prepare(struct snd_pcm_substream *alsa_sub)
+{
+ struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub);
+ struct pcm_substream *sub = hiface_pcm_get_substream(alsa_sub);
+ struct snd_pcm_runtime *alsa_rt = alsa_sub->runtime;
+ int ret;
+
+ if (rt->panic)
+ return -EPIPE;
+ if (!sub)
+ return -ENODEV;
+
+ mutex_lock(&rt->stream_mutex);
+
+ sub->dma_off = 0;
+ sub->period_off = 0;
+
+ if (rt->stream_state == STREAM_DISABLED) {
+
+ ret = hiface_pcm_set_rate(rt, alsa_rt->rate);
+ if (ret) {
+ mutex_unlock(&rt->stream_mutex);
+ return ret;
+ }
+ ret = hiface_pcm_stream_start(rt);
+ if (ret) {
+ mutex_unlock(&rt->stream_mutex);
+ return ret;
+ }
+ }
+ mutex_unlock(&rt->stream_mutex);
+ return 0;
+}
+
+static int hiface_pcm_trigger(struct snd_pcm_substream *alsa_sub, int cmd)
+{
+ struct pcm_substream *sub = hiface_pcm_get_substream(alsa_sub);
+ struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub);
+
+ if (rt->panic)
+ return -EPIPE;
+ if (!sub)
+ return -ENODEV;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ spin_lock_irq(&sub->lock);
+ sub->active = true;
+ spin_unlock_irq(&sub->lock);
+ return 0;
+
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ spin_lock_irq(&sub->lock);
+ sub->active = false;
+ spin_unlock_irq(&sub->lock);
+ return 0;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static snd_pcm_uframes_t hiface_pcm_pointer(struct snd_pcm_substream *alsa_sub)
+{
+ struct pcm_substream *sub = hiface_pcm_get_substream(alsa_sub);
+ struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub);
+ unsigned long flags;
+ snd_pcm_uframes_t dma_offset;
+
+ if (rt->panic || !sub)
+ return SNDRV_PCM_STATE_XRUN;
+
+ spin_lock_irqsave(&sub->lock, flags);
+ dma_offset = sub->dma_off;
+ spin_unlock_irqrestore(&sub->lock, flags);
+ return bytes_to_frames(alsa_sub->runtime, dma_offset);
+}
+
+static struct snd_pcm_ops pcm_ops = {
+ .open = hiface_pcm_open,
+ .close = hiface_pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = hiface_pcm_hw_params,
+ .hw_free = hiface_pcm_hw_free,
+ .prepare = hiface_pcm_prepare,
+ .trigger = hiface_pcm_trigger,
+ .pointer = hiface_pcm_pointer,
+ .page = snd_pcm_lib_get_vmalloc_page,
+ .mmap = snd_pcm_lib_mmap_vmalloc,
+};
+
+static int hiface_pcm_init_urb(struct pcm_urb *urb,
+ struct hiface_chip *chip,
+ unsigned int ep,
+ void (*handler)(struct urb *))
+{
+ urb->chip = chip;
+ usb_init_urb(&urb->instance);
+
+ urb->buffer = kzalloc(PCM_PACKET_SIZE, GFP_KERNEL);
+ if (!urb->buffer)
+ return -ENOMEM;
+
+ usb_fill_bulk_urb(&urb->instance, chip->dev,
+ usb_sndbulkpipe(chip->dev, ep), (void *)urb->buffer,
+ PCM_PACKET_SIZE, handler, urb);
+ init_usb_anchor(&urb->submitted);
+
+ return 0;
+}
+
+void hiface_pcm_abort(struct hiface_chip *chip)
+{
+ struct pcm_runtime *rt = chip->pcm;
+
+ if (rt) {
+ rt->panic = true;
+
+ mutex_lock(&rt->stream_mutex);
+ hiface_pcm_stream_stop(rt);
+ mutex_unlock(&rt->stream_mutex);
+ }
+}
+
+static void hiface_pcm_destroy(struct hiface_chip *chip)
+{
+ struct pcm_runtime *rt = chip->pcm;
+ int i;
+
+ for (i = 0; i < PCM_N_URBS; i++)
+ kfree(rt->out_urbs[i].buffer);
+
+ kfree(chip->pcm);
+ chip->pcm = NULL;
+}
+
+static void hiface_pcm_free(struct snd_pcm *pcm)
+{
+ struct pcm_runtime *rt = pcm->private_data;
+
+ if (rt)
+ hiface_pcm_destroy(rt->chip);
+}
+
+int hiface_pcm_init(struct hiface_chip *chip, u8 extra_freq)
+{
+ int i;
+ int ret;
+ struct snd_pcm *pcm;
+ struct pcm_runtime *rt;
+
+ rt = kzalloc(sizeof(*rt), GFP_KERNEL);
+ if (!rt)
+ return -ENOMEM;
+
+ rt->chip = chip;
+ rt->stream_state = STREAM_DISABLED;
+ if (extra_freq)
+ rt->extra_freq = 1;
+
+ init_waitqueue_head(&rt->stream_wait_queue);
+ mutex_init(&rt->stream_mutex);
+ spin_lock_init(&rt->playback.lock);
+
+ for (i = 0; i < PCM_N_URBS; i++)
+ hiface_pcm_init_urb(&rt->out_urbs[i], chip, OUT_EP,
+ hiface_pcm_out_urb_handler);
+
+ ret = snd_pcm_new(chip->card, "USB-SPDIF Audio", 0, 1, 0, &pcm);
+ if (ret < 0) {
+ kfree(rt);
+ dev_err(&chip->dev->dev, "Cannot create pcm instance\n");
+ return ret;
+ }
+
+ pcm->private_data = rt;
+ pcm->private_free = hiface_pcm_free;
+
+ strlcpy(pcm->name, "USB-SPDIF Audio", sizeof(pcm->name));
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pcm_ops);
+
+ rt->instance = pcm;
+
+ chip->pcm = rt;
+ return 0;
+}
diff --git a/sound/usb/hiface/pcm.h b/sound/usb/hiface/pcm.h
new file mode 100644
index 0000000..77edd7c
--- /dev/null
+++ b/sound/usb/hiface/pcm.h
@@ -0,0 +1,24 @@
+/*
+ * Linux driver for M2Tech hiFace compatible devices
+ *
+ * Copyright 2012-2013 (C) M2TECH S.r.l and Amarula Solutions B.V.
+ *
+ * Authors: Michael Trimarchi <michael@amarulasolutions.com>
+ * Antonio Ospite <ao2@amarulasolutions.com>
+ *
+ * The driver is based on the work done in TerraTec DMX 6Fire USB
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef HIFACE_PCM_H
+#define HIFACE_PCM_H
+
+struct hiface_chip;
+
+int hiface_pcm_init(struct hiface_chip *chip, u8 extra_freq);
+void hiface_pcm_abort(struct hiface_chip *chip);
+#endif /* HIFACE_PCM_H */
diff --git a/sound/usb/midi.c b/sound/usb/midi.c
index 8e01fa4..b901f46 100644
--- a/sound/usb/midi.c
+++ b/sound/usb/midi.c
@@ -1575,8 +1575,41 @@ static struct port_info {
EXTERNAL_PORT(0x0582, 0x004d, 0, "%s MIDI"),
EXTERNAL_PORT(0x0582, 0x004d, 1, "%s 1"),
EXTERNAL_PORT(0x0582, 0x004d, 2, "%s 2"),
+ /* BOSS GT-PRO */
+ CONTROL_PORT(0x0582, 0x0089, 0, "%s Control"),
/* Edirol UM-3EX */
CONTROL_PORT(0x0582, 0x009a, 3, "%s Control"),
+ /* Roland VG-99 */
+ CONTROL_PORT(0x0582, 0x00b2, 0, "%s Control"),
+ EXTERNAL_PORT(0x0582, 0x00b2, 1, "%s MIDI"),
+ /* Cakewalk Sonar V-Studio 100 */
+ EXTERNAL_PORT(0x0582, 0x00eb, 0, "%s MIDI"),
+ CONTROL_PORT(0x0582, 0x00eb, 1, "%s Control"),
+ /* Roland VB-99 */
+ CONTROL_PORT(0x0582, 0x0102, 0, "%s Control"),
+ EXTERNAL_PORT(0x0582, 0x0102, 1, "%s MIDI"),
+ /* Roland A-PRO */
+ EXTERNAL_PORT(0x0582, 0x010f, 0, "%s MIDI"),
+ CONTROL_PORT(0x0582, 0x010f, 1, "%s 1"),
+ CONTROL_PORT(0x0582, 0x010f, 2, "%s 2"),
+ /* Roland SD-50 */
+ ROLAND_SYNTH_PORT(0x0582, 0x0114, 0, "%s Synth", 128),
+ EXTERNAL_PORT(0x0582, 0x0114, 1, "%s MIDI"),
+ CONTROL_PORT(0x0582, 0x0114, 2, "%s Control"),
+ /* Roland OCTA-CAPTURE */
+ EXTERNAL_PORT(0x0582, 0x0120, 0, "%s MIDI"),
+ CONTROL_PORT(0x0582, 0x0120, 1, "%s Control"),
+ EXTERNAL_PORT(0x0582, 0x0121, 0, "%s MIDI"),
+ CONTROL_PORT(0x0582, 0x0121, 1, "%s Control"),
+ /* Roland SPD-SX */
+ CONTROL_PORT(0x0582, 0x0145, 0, "%s Control"),
+ EXTERNAL_PORT(0x0582, 0x0145, 1, "%s MIDI"),
+ /* Roland A-Series */
+ CONTROL_PORT(0x0582, 0x0156, 0, "%s Keyboard"),
+ EXTERNAL_PORT(0x0582, 0x0156, 1, "%s MIDI"),
+ /* Roland INTEGRA-7 */
+ ROLAND_SYNTH_PORT(0x0582, 0x015b, 0, "%s Synth", 128),
+ CONTROL_PORT(0x0582, 0x015b, 1, "%s Control"),
/* M-Audio MidiSport 8x8 */
CONTROL_PORT(0x0763, 0x1031, 8, "%s Control"),
CONTROL_PORT(0x0763, 0x1033, 8, "%s Control"),
@@ -1948,6 +1981,44 @@ static int snd_usbmidi_detect_yamaha(struct snd_usb_midi* umidi,
}
/*
+ * Detects the endpoints and ports of Roland devices.
+ */
+static int snd_usbmidi_detect_roland(struct snd_usb_midi* umidi,
+ struct snd_usb_midi_endpoint_info* endpoint)
+{
+ struct usb_interface* intf;
+ struct usb_host_interface *hostif;
+ u8* cs_desc;
+
+ intf = umidi->iface;
+ if (!intf)
+ return -ENOENT;
+ hostif = intf->altsetting;
+ /*
+ * Some devices have a descriptor <06 24 F1 02 <inputs> <outputs>>,
+ * some have standard class descriptors, or both kinds, or neither.
+ */
+ for (cs_desc = hostif->extra;
+ cs_desc < hostif->extra + hostif->extralen && cs_desc[0] >= 2;
+ cs_desc += cs_desc[0]) {
+ if (cs_desc[0] >= 6 &&
+ cs_desc[1] == USB_DT_CS_INTERFACE &&
+ cs_desc[2] == 0xf1 &&
+ cs_desc[3] == 0x02) {
+ endpoint->in_cables = (1 << cs_desc[4]) - 1;
+ endpoint->out_cables = (1 << cs_desc[5]) - 1;
+ return snd_usbmidi_detect_endpoints(umidi, endpoint, 1);
+ } else if (cs_desc[0] >= 7 &&
+ cs_desc[1] == USB_DT_CS_INTERFACE &&
+ cs_desc[2] == UAC_HEADER) {
+ return snd_usbmidi_get_ms_info(umidi, endpoint);
+ }
+ }
+
+ return -ENODEV;
+}
+
+/*
* Creates the endpoints and their ports for Midiman devices.
*/
static int snd_usbmidi_create_endpoints_midiman(struct snd_usb_midi* umidi,
@@ -2162,6 +2233,9 @@ int snd_usbmidi_create(struct snd_card *card,
case QUIRK_MIDI_YAMAHA:
err = snd_usbmidi_detect_yamaha(umidi, &endpoints[0]);
break;
+ case QUIRK_MIDI_ROLAND:
+ err = snd_usbmidi_detect_roland(umidi, &endpoints[0]);
+ break;
case QUIRK_MIDI_MIDIMAN:
umidi->usb_protocol_ops = &snd_usbmidi_midiman_ops;
memcpy(&endpoints[0], quirk->data,
diff --git a/sound/usb/misc/ua101.c b/sound/usb/misc/ua101.c
index 6ad617b..8b5d2c5 100644
--- a/sound/usb/misc/ua101.c
+++ b/sound/usb/misc/ua101.c
@@ -1349,7 +1349,7 @@ static void ua101_disconnect(struct usb_interface *interface)
snd_card_disconnect(ua->card);
/* make sure that there are no pending USB requests */
- __list_for_each(midi, &ua->midi_list)
+ list_for_each(midi, &ua->midi_list)
snd_usbmidi_disconnect(midi);
abort_alsa_playback(ua);
abort_alsa_capture(ua);
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index e5c7f9f..d543808 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -885,6 +885,7 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval,
case USB_ID(0x046d, 0x0808):
case USB_ID(0x046d, 0x0809):
+ case USB_ID(0x046d, 0x081b): /* HD Webcam c310 */
case USB_ID(0x046d, 0x081d): /* HD Webcam c510 */
case USB_ID(0x046d, 0x0825): /* HD Webcam c270 */
case USB_ID(0x046d, 0x0991):
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
index ebe9144..d42a584 100644
--- a/sound/usb/mixer_quirks.c
+++ b/sound/usb/mixer_quirks.c
@@ -9,6 +9,8 @@
* Alan Cox (alan@lxorguk.ukuu.org.uk)
* Thomas Sailer (sailer@ife.ee.ethz.ch)
*
+ * Audio Advantage Micro II support added by:
+ * Przemek Rudy (prudy1@o2.pl)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -30,6 +32,7 @@
#include <linux/usb.h>
#include <linux/usb/audio.h>
+#include <sound/asoundef.h>
#include <sound/core.h>
#include <sound/control.h>
#include <sound/hwdep.h>
@@ -1315,6 +1318,211 @@ static struct std_mono_table ebox44_table[] = {
{}
};
+/* Audio Advantage Micro II findings:
+ *
+ * Mapping spdif AES bits to vendor register.bit:
+ * AES0: [0 0 0 0 2.3 2.2 2.1 2.0] - default 0x00
+ * AES1: [3.3 3.2.3.1.3.0 2.7 2.6 2.5 2.4] - default: 0x01
+ * AES2: [0 0 0 0 0 0 0 0]
+ * AES3: [0 0 0 0 0 0 x 0] - 'x' bit is set basing on standard usb request
+ * (UAC_EP_CS_ATTR_SAMPLE_RATE) for Audio Devices
+ *
+ * power on values:
+ * r2: 0x10
+ * r3: 0x20 (b7 is zeroed just before playback (except IEC61937) and set
+ * just after it to 0xa0, presumably it disables/mutes some analog
+ * parts when there is no audio.)
+ * r9: 0x28
+ *
+ * Optical transmitter on/off:
+ * vendor register.bit: 9.1
+ * 0 - on (0x28 register value)
+ * 1 - off (0x2a register value)
+ *
+ */
+static int snd_microii_spdif_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
+ uinfo->count = 1;
+ return 0;
+}
+
+static int snd_microii_spdif_default_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
+ int err;
+ struct usb_interface *iface;
+ struct usb_host_interface *alts;
+ unsigned int ep;
+ unsigned char data[3];
+ int rate;
+
+ ucontrol->value.iec958.status[0] = kcontrol->private_value & 0xff;
+ ucontrol->value.iec958.status[1] = (kcontrol->private_value >> 8) & 0xff;
+ ucontrol->value.iec958.status[2] = 0x00;
+
+ /* use known values for that card: interface#1 altsetting#1 */
+ iface = usb_ifnum_to_if(mixer->chip->dev, 1);
+ alts = &iface->altsetting[1];
+ ep = get_endpoint(alts, 0)->bEndpointAddress;
+
+ err = snd_usb_ctl_msg(mixer->chip->dev,
+ usb_rcvctrlpipe(mixer->chip->dev, 0),
+ UAC_GET_CUR,
+ USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_IN,
+ UAC_EP_CS_ATTR_SAMPLE_RATE << 8,
+ ep,
+ data,
+ sizeof(data));
+ if (err < 0)
+ goto end;
+
+ rate = data[0] | (data[1] << 8) | (data[2] << 16);
+ ucontrol->value.iec958.status[3] = (rate == 48000) ?
+ IEC958_AES3_CON_FS_48000 : IEC958_AES3_CON_FS_44100;
+
+ err = 0;
+end:
+ return err;
+}
+
+static int snd_microii_spdif_default_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
+ int err;
+ u8 reg;
+ unsigned long priv_backup = kcontrol->private_value;
+
+ reg = ((ucontrol->value.iec958.status[1] & 0x0f) << 4) |
+ (ucontrol->value.iec958.status[0] & 0x0f);
+ err = snd_usb_ctl_msg(mixer->chip->dev,
+ usb_sndctrlpipe(mixer->chip->dev, 0),
+ UAC_SET_CUR,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
+ reg,
+ 2,
+ NULL,
+ 0);
+ if (err < 0)
+ goto end;
+
+ kcontrol->private_value &= 0xfffff0f0;
+ kcontrol->private_value |= (ucontrol->value.iec958.status[1] & 0x0f) << 8;
+ kcontrol->private_value |= (ucontrol->value.iec958.status[0] & 0x0f);
+
+ reg = (ucontrol->value.iec958.status[0] & IEC958_AES0_NONAUDIO) ?
+ 0xa0 : 0x20;
+ reg |= (ucontrol->value.iec958.status[1] >> 4) & 0x0f;
+ err = snd_usb_ctl_msg(mixer->chip->dev,
+ usb_sndctrlpipe(mixer->chip->dev, 0),
+ UAC_SET_CUR,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
+ reg,
+ 3,
+ NULL,
+ 0);
+ if (err < 0)
+ goto end;
+
+ kcontrol->private_value &= 0xffff0fff;
+ kcontrol->private_value |= (ucontrol->value.iec958.status[1] & 0xf0) << 8;
+
+ /* The frequency bits in AES3 cannot be set via register access. */
+
+ /* Silently ignore any bits from the request that cannot be set. */
+
+ err = (priv_backup != kcontrol->private_value);
+end:
+ return err;
+}
+
+static int snd_microii_spdif_mask_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.iec958.status[0] = 0x0f;
+ ucontrol->value.iec958.status[1] = 0xff;
+ ucontrol->value.iec958.status[2] = 0x00;
+ ucontrol->value.iec958.status[3] = 0x00;
+
+ return 0;
+}
+
+static int snd_microii_spdif_switch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = !(kcontrol->private_value & 0x02);
+
+ return 0;
+}
+
+static int snd_microii_spdif_switch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
+ int err;
+ u8 reg = ucontrol->value.integer.value[0] ? 0x28 : 0x2a;
+
+ err = snd_usb_ctl_msg(mixer->chip->dev,
+ usb_sndctrlpipe(mixer->chip->dev, 0),
+ UAC_SET_CUR,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
+ reg,
+ 9,
+ NULL,
+ 0);
+
+ if (!err) {
+ err = (reg != (kcontrol->private_value & 0x0ff));
+ if (err)
+ kcontrol->private_value = reg;
+ }
+
+ return err;
+}
+
+static struct snd_kcontrol_new snd_microii_mixer_spdif[] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
+ .info = snd_microii_spdif_info,
+ .get = snd_microii_spdif_default_get,
+ .put = snd_microii_spdif_default_put,
+ .private_value = 0x00000100UL,/* reset value */
+ },
+ {
+ .access = SNDRV_CTL_ELEM_ACCESS_READ,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, MASK),
+ .info = snd_microii_spdif_info,
+ .get = snd_microii_spdif_mask_get,
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, SWITCH),
+ .info = snd_ctl_boolean_mono_info,
+ .get = snd_microii_spdif_switch_get,
+ .put = snd_microii_spdif_switch_put,
+ .private_value = 0x00000028UL,/* reset value */
+ }
+};
+
+static int snd_microii_controls_create(struct usb_mixer_interface *mixer)
+{
+ int err, i;
+
+ for (i = 0; i < ARRAY_SIZE(snd_microii_mixer_spdif); ++i) {
+ err = snd_ctl_add(mixer->chip->card,
+ snd_ctl_new1(&snd_microii_mixer_spdif[i], mixer));
+ if (err < 0)
+ return err;
+ }
+
+ return err;
+}
+
int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
{
int err = 0;
@@ -1353,6 +1561,10 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
err = snd_xonar_u1_controls_create(mixer);
break;
+ case USB_ID(0x0d8c, 0x0103): /* Audio Advantage Micro II */
+ err = snd_microii_controls_create(mixer);
+ break;
+
case USB_ID(0x17cc, 0x1011): /* Traktor Audio 6 */
err = snd_nativeinstruments_create_mixer(mixer,
snd_nativeinstruments_ta6_mixers,
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index 93b6e32..15b151e 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -202,13 +202,11 @@ int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface,
struct usb_host_interface *alts,
struct audioformat *fmt)
{
- struct usb_interface_descriptor *altsd = get_iface_desc(alts);
-
/* if endpoint doesn't have pitch control, bail out */
if (!(fmt->attributes & UAC_EP_CS_ATTR_PITCH_CONTROL))
return 0;
- switch (altsd->bInterfaceProtocol) {
+ switch (fmt->protocol) {
case UAC_VERSION_1:
default:
return init_pitch_v1(chip, iface, alts, fmt);
@@ -300,6 +298,35 @@ static int deactivate_endpoints(struct snd_usb_substream *subs)
return 0;
}
+static int search_roland_implicit_fb(struct usb_device *dev, int ifnum,
+ unsigned int altsetting,
+ struct usb_host_interface **alts,
+ unsigned int *ep)
+{
+ struct usb_interface *iface;
+ struct usb_interface_descriptor *altsd;
+ struct usb_endpoint_descriptor *epd;
+
+ iface = usb_ifnum_to_if(dev, ifnum);
+ if (!iface || iface->num_altsetting < altsetting + 1)
+ return -ENOENT;
+ *alts = &iface->altsetting[altsetting];
+ altsd = get_iface_desc(*alts);
+ if (altsd->bAlternateSetting != altsetting ||
+ altsd->bInterfaceClass != USB_CLASS_VENDOR_SPEC ||
+ (altsd->bInterfaceSubClass != 2 &&
+ altsd->bInterfaceProtocol != 2 ) ||
+ altsd->bNumEndpoints < 1)
+ return -ENOENT;
+ epd = get_endpoint(*alts, 0);
+ if (!usb_endpoint_is_isoc_in(epd) ||
+ (epd->bmAttributes & USB_ENDPOINT_USAGE_MASK) !=
+ USB_ENDPOINT_USAGE_IMPLICIT_FB)
+ return -ENOENT;
+ *ep = epd->bEndpointAddress;
+ return 0;
+}
+
/*
* find a matching format and set up the interface
*/
@@ -395,6 +422,18 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
goto add_sync_ep;
}
}
+ if (is_playback &&
+ attr == USB_ENDPOINT_SYNC_ASYNC &&
+ altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC &&
+ altsd->bInterfaceProtocol == 2 &&
+ altsd->bNumEndpoints == 1 &&
+ USB_ID_VENDOR(subs->stream->chip->usb_id) == 0x0582 /* Roland */ &&
+ search_roland_implicit_fb(dev, altsd->bInterfaceNumber + 1,
+ altsd->bAlternateSetting,
+ &alts, &ep) >= 0) {
+ implicit_fb = 1;
+ goto add_sync_ep;
+ }
if (((is_playback && attr == USB_ENDPOINT_SYNC_ASYNC) ||
(!is_playback && attr == USB_ENDPOINT_SYNC_ADAPTIVE)) &&
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
index 8b75bcf..f5f0595 100644
--- a/sound/usb/quirks-table.h
+++ b/sound/usb/quirks-table.h
@@ -461,6 +461,17 @@ YAMAHA_DEVICE(0x7000, "DTX"),
YAMAHA_DEVICE(0x7010, "UB99"),
#undef YAMAHA_DEVICE
#undef YAMAHA_INTERFACE
+/* this catches most recent vendor-specific Yamaha devices */
+{
+ .match_flags = USB_DEVICE_ID_MATCH_VENDOR |
+ USB_DEVICE_ID_MATCH_INT_CLASS,
+ .idVendor = 0x0499,
+ .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
+ .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+ .ifnum = QUIRK_ANY_INTERFACE,
+ .type = QUIRK_AUTODETECT
+ }
+},
/*
* Roland/RolandED/Edirol/BOSS devices
@@ -1136,7 +1147,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
}
},
- /* TODO: add Roland M-1000 support */
{
/*
* Has ID 0x0038 when not in "Advanced Driver" mode;
@@ -1251,7 +1261,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
}
},
- /* TODO: add Edirol M-100FX support */
{
/* has ID 0x004e when not in "Advanced Driver" mode */
USB_DEVICE(0x0582, 0x004c),
@@ -1371,20 +1380,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
},
{
- /* has ID 0x006b when not in "Advanced Driver" mode */
- USB_DEVICE_VENDOR_SPEC(0x0582, 0x006a),
- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
- .vendor_name = "Roland",
- .product_name = "SP-606",
- .ifnum = 3,
- .type = QUIRK_MIDI_FIXED_ENDPOINT,
- .data = & (const struct snd_usb_midi_endpoint_info) {
- .out_cables = 0x0001,
- .in_cables = 0x0001
- }
- }
-},
-{
/* has ID 0x006e when not in "Advanced Driver" mode */
USB_DEVICE(0x0582, 0x006d),
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
@@ -1471,8 +1466,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
}
},
- /* TODO: add Roland V-SYNTH XT support */
- /* TODO: add BOSS GT-PRO support */
{
/* has ID 0x008c when not in "Advanced Driver" mode */
USB_DEVICE(0x0582, 0x008b),
@@ -1487,42 +1480,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
}
},
- /* TODO: add Edirol PC-80 support */
-{
- USB_DEVICE(0x0582, 0x0096),
- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
- .vendor_name = "EDIROL",
- .product_name = "UA-1EX",
- .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 = -1
- }
- }
- }
-},
-{
- USB_DEVICE(0x0582, 0x009a),
- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
- .vendor_name = "EDIROL",
- .product_name = "UM-3EX",
- .ifnum = 0,
- .type = QUIRK_MIDI_FIXED_ENDPOINT,
- .data = & (const struct snd_usb_midi_endpoint_info) {
- .out_cables = 0x000f,
- .in_cables = 0x000f
- }
- }
-},
{
/*
* This quirk is for the "Advanced Driver" mode. If off, the UA-4FX
@@ -1553,124 +1510,8 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
}
},
- /* TODO: add Edirol MD-P1 support */
-{
- USB_DEVICE(0x582, 0x00a6),
- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
- .vendor_name = "Roland",
- .product_name = "Juno-G",
- .ifnum = 0,
- .type = QUIRK_MIDI_FIXED_ENDPOINT,
- .data = & (const struct snd_usb_midi_endpoint_info) {
- .out_cables = 0x0001,
- .in_cables = 0x0001
- }
- }
-},
-{
- /* Roland SH-201 */
- USB_DEVICE(0x0582, 0x00ad),
- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
- .vendor_name = "Roland",
- .product_name = "SH-201",
- .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 = 0x0001,
- .in_cables = 0x0001
- }
- },
- {
- .ifnum = -1
- }
- }
- }
-},
-{
- /* Advanced mode of the Roland VG-99, with MIDI and 24-bit PCM at 44.1
- * kHz. In standard mode, the device has ID 0582:00b3, and offers
- * 16-bit PCM at 44.1 kHz with no MIDI.
- */
- USB_DEVICE(0x0582, 0x00b2),
- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
- .vendor_name = "Roland",
- .product_name = "VG-99",
- .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
- }
- }
- }
-},
-{
- /* Roland SonicCell */
- USB_DEVICE(0x0582, 0x00c2),
- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
- .vendor_name = "Roland",
- .product_name = "SonicCell",
- .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 = 0x0001,
- .in_cables = 0x0001
- }
- },
- {
- .ifnum = -1
- }
- }
- }
-},
{
/* Edirol M-16DX */
- /* FIXME: This quirk gives a good-working capture stream but the
- * playback seems problematic because of lacking of sync
- * with capture stream. It needs to sync with the capture
- * clock. As now, you'll get frequent sound distortions
- * via the playback.
- */
USB_DEVICE(0x0582, 0x00c4),
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
.ifnum = QUIRK_ANY_INTERFACE,
@@ -1699,35 +1540,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
},
{
- /* BOSS GT-10 */
- USB_DEVICE(0x0582, 0x00da),
- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
- .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 = 0x0001,
- .in_cables = 0x0001
- }
- },
- {
- .ifnum = -1
- }
- }
- }
-},
-{
/* Advanced modes of the Edirol UA-25EX.
* For the standard mode, UA-25EX has ID 0582:00e7, which
* offers only 16-bit PCM at 44.1 kHz and no MIDI.
@@ -1758,42 +1570,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
},
{
- /* has ID 0x00ea when not in Advanced Driver mode */
- USB_DEVICE_VENDOR_SPEC(0x0582, 0x00e9),
- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
- /* .vendor_name = "Roland", */
- /* .product_name = "UA-1G", */
- .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 = -1
- }
- }
- }
-},
-{
- USB_DEVICE_VENDOR_SPEC(0x0582, 0x0104),
- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
- /* .vendor_name = "Roland", */
- /* .product_name = "UM-1G", */
- .ifnum = 0,
- .type = QUIRK_MIDI_FIXED_ENDPOINT,
- .data = & (const struct snd_usb_midi_endpoint_info) {
- .out_cables = 0x0001,
- .in_cables = 0x0001
- }
- }
-},
-{
/* Edirol UM-3G */
USB_DEVICE_VENDOR_SPEC(0x0582, 0x0108),
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
@@ -1806,92 +1582,49 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
},
{
- /* Boss JS-8 Jam Station */
- USB_DEVICE(0x0582, 0x0109),
- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
- /* .vendor_name = "BOSS", */
- /* .product_name = "JS-8", */
- .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_STANDARD_INTERFACE
- },
- {
- .ifnum = -1
- }
- }
- }
-},
-{
- /* has ID 0x0110 when not in Advanced Driver mode */
- USB_DEVICE_VENDOR_SPEC(0x0582, 0x010f),
+ /* only 44.1 kHz works at the moment */
+ USB_DEVICE(0x0582, 0x0120),
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
/* .vendor_name = "Roland", */
- /* .product_name = "A-PRO", */
- .ifnum = 0,
- .type = QUIRK_MIDI_FIXED_ENDPOINT,
- .data = & (const struct snd_usb_midi_endpoint_info) {
- .out_cables = 0x0003,
- .in_cables = 0x0007
- }
- }
-},
-{
- /* Roland GAIA SH-01 */
- USB_DEVICE(0x0582, 0x0111),
- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
- .vendor_name = "Roland",
- .product_name = "GAIA",
+ /* .product_name = "OCTO-CAPTURE", */
.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
+ .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+ .data = & (const struct audioformat) {
+ .formats = SNDRV_PCM_FMTBIT_S32_LE,
+ .channels = 10,
+ .iface = 0,
+ .altsetting = 1,
+ .altset_idx = 1,
+ .endpoint = 0x05,
+ .ep_attr = 0x05,
+ .rates = SNDRV_PCM_RATE_44100,
+ .rate_min = 44100,
+ .rate_max = 44100,
+ .nr_rates = 1,
+ .rate_table = (unsigned int[]) { 44100 }
}
},
{
- .ifnum = -1
- }
- }
- }
-},
-{
- USB_DEVICE(0x0582, 0x0113),
- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
- /* .vendor_name = "BOSS", */
- /* .product_name = "ME-25", */
- .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
+ .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+ .data = & (const struct audioformat) {
+ .formats = SNDRV_PCM_FMTBIT_S32_LE,
+ .channels = 12,
+ .iface = 1,
+ .altsetting = 1,
+ .altset_idx = 1,
+ .endpoint = 0x85,
+ .ep_attr = 0x25,
+ .rates = SNDRV_PCM_RATE_44100,
+ .rate_min = 44100,
+ .rate_max = 44100,
+ .nr_rates = 1,
+ .rate_table = (unsigned int[]) { 44100 }
+ }
},
{
.ifnum = 2,
@@ -1902,30 +1635,12 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
},
{
- .ifnum = -1
- }
- }
- }
-},
-{
- USB_DEVICE(0x0582, 0x0127),
- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
- /* .vendor_name = "Roland", */
- /* .product_name = "GR-55", */
- .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 = 3,
+ .type = QUIRK_IGNORE_INTERFACE
},
{
- .ifnum = 2,
- .type = QUIRK_MIDI_STANDARD_INTERFACE
+ .ifnum = 4,
+ .type = QUIRK_IGNORE_INTERFACE
},
{
.ifnum = -1
@@ -1934,34 +1649,49 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
},
{
- /* Added support for Roland UM-ONE which differs from UM-1 */
- USB_DEVICE(0x0582, 0x012a),
- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
- /* .vendor_name = "ROLAND", */
- /* .product_name = "UM-ONE", */
- .ifnum = 0,
- .type = QUIRK_MIDI_FIXED_ENDPOINT,
- .data = & (const struct snd_usb_midi_endpoint_info) {
- .out_cables = 0x0001,
- .in_cables = 0x0003
- }
- }
-},
-{
- USB_DEVICE(0x0582, 0x011e),
+ /* only 44.1 kHz works at the moment */
+ USB_DEVICE(0x0582, 0x012f),
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
- /* .vendor_name = "BOSS", */
- /* .product_name = "BR-800", */
+ /* .vendor_name = "Roland", */
+ /* .product_name = "QUAD-CAPTURE", */
.ifnum = QUIRK_ANY_INTERFACE,
.type = QUIRK_COMPOSITE,
.data = (const struct snd_usb_audio_quirk[]) {
{
.ifnum = 0,
- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+ .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+ .data = & (const struct audioformat) {
+ .formats = SNDRV_PCM_FMTBIT_S32_LE,
+ .channels = 4,
+ .iface = 0,
+ .altsetting = 1,
+ .altset_idx = 1,
+ .endpoint = 0x05,
+ .ep_attr = 0x05,
+ .rates = SNDRV_PCM_RATE_44100,
+ .rate_min = 44100,
+ .rate_max = 44100,
+ .nr_rates = 1,
+ .rate_table = (unsigned int[]) { 44100 }
+ }
},
{
.ifnum = 1,
- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+ .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+ .data = & (const struct audioformat) {
+ .formats = SNDRV_PCM_FMTBIT_S32_LE,
+ .channels = 6,
+ .iface = 1,
+ .altsetting = 1,
+ .altset_idx = 1,
+ .endpoint = 0x85,
+ .ep_attr = 0x25,
+ .rates = SNDRV_PCM_RATE_44100,
+ .rate_min = 44100,
+ .rate_max = 44100,
+ .nr_rates = 1,
+ .rate_table = (unsigned int[]) { 44100 }
+ }
},
{
.ifnum = 2,
@@ -1972,38 +1702,12 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
},
{
- .ifnum = -1
- }
- }
- }
-},
-{
- USB_DEVICE(0x0582, 0x0130),
- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
- /* .vendor_name = "BOSS", */
- /* .product_name = "MICRO BR-80", */
- .ifnum = QUIRK_ANY_INTERFACE,
- .type = QUIRK_COMPOSITE,
- .data = (const struct snd_usb_audio_quirk[]) {
- {
- .ifnum = 0,
+ .ifnum = 3,
.type = QUIRK_IGNORE_INTERFACE
},
{
- .ifnum = 1,
- .type = QUIRK_AUDIO_STANDARD_INTERFACE
- },
- {
- .ifnum = 2,
- .type = QUIRK_AUDIO_STANDARD_INTERFACE
- },
- {
- .ifnum = 3,
- .type = QUIRK_MIDI_FIXED_ENDPOINT,
- .data = & (const struct snd_usb_midi_endpoint_info) {
- .out_cables = 0x0001,
- .in_cables = 0x0001
- }
+ .ifnum = 4,
+ .type = QUIRK_IGNORE_INTERFACE
},
{
.ifnum = -1
@@ -2011,34 +1715,15 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
}
},
+/* this catches most recent vendor-specific Roland devices */
{
- USB_DEVICE(0x0582, 0x014d),
- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
- /* .vendor_name = "BOSS", */
- /* .product_name = "GT-100", */
+ .match_flags = USB_DEVICE_ID_MATCH_VENDOR |
+ USB_DEVICE_ID_MATCH_INT_CLASS,
+ .idVendor = 0x0582,
+ .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
+ .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
.ifnum = QUIRK_ANY_INTERFACE,
- .type = QUIRK_COMPOSITE,
- .data = (const struct snd_usb_audio_quirk[]) {
- {
- .ifnum = 1,
- .type = QUIRK_AUDIO_STANDARD_INTERFACE
- },
- {
- .ifnum = 2,
- .type = QUIRK_AUDIO_STANDARD_INTERFACE
- },
- {
- .ifnum = 3,
- .type = QUIRK_MIDI_FIXED_ENDPOINT,
- .data = & (const struct snd_usb_midi_endpoint_info) {
- .out_cables = 0x0001,
- .in_cables = 0x0001
- }
- },
- {
- .ifnum = -1
- }
- }
+ .type = QUIRK_AUTODETECT
}
},
@@ -3434,4 +3119,16 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
},
+{
+ /*
+ * The original product_name is "USB Sound Device", however this name
+ * is also used by the CM106 based cards, so make it unique.
+ */
+ USB_DEVICE(0x0d8c, 0x0103),
+ .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+ .product_name = "Audio Advantage MicroII",
+ .ifnum = QUIRK_NO_INTERFACE
+ }
+},
+
#undef USB_DEVICE_VENDOR_SPEC
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index 3879eae..1bc45e7 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -18,6 +18,7 @@
#include <linux/slab.h>
#include <linux/usb.h>
#include <linux/usb/audio.h>
+#include <linux/usb/midi.h>
#include <sound/control.h>
#include <sound/core.h>
@@ -128,6 +129,7 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip,
{
struct audioformat *fp;
struct usb_host_interface *alts;
+ struct usb_interface_descriptor *altsd;
int stream, err;
unsigned *rate_table = NULL;
@@ -165,6 +167,9 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip,
return -EINVAL;
}
alts = &iface->altsetting[fp->altset_idx];
+ altsd = get_iface_desc(alts);
+ fp->protocol = altsd->bInterfaceProtocol;
+
if (fp->datainterval == 0)
fp->datainterval = snd_usb_parse_datainterval(chip, alts);
if (fp->maxpacksize == 0)
@@ -175,6 +180,212 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip,
return 0;
}
+static int create_auto_pcm_quirk(struct snd_usb_audio *chip,
+ struct usb_interface *iface,
+ struct usb_driver *driver)
+{
+ struct usb_host_interface *alts;
+ struct usb_interface_descriptor *altsd;
+ struct usb_endpoint_descriptor *epd;
+ struct uac1_as_header_descriptor *ashd;
+ struct uac_format_type_i_discrete_descriptor *fmtd;
+
+ /*
+ * Most Roland/Yamaha audio streaming interfaces have more or less
+ * standard descriptors, but older devices might lack descriptors, and
+ * future ones might change, so ensure that we fail silently if the
+ * interface doesn't look exactly right.
+ */
+
+ /* must have a non-zero altsetting for streaming */
+ if (iface->num_altsetting < 2)
+ return -ENODEV;
+ alts = &iface->altsetting[1];
+ altsd = get_iface_desc(alts);
+
+ /* must have an isochronous endpoint for streaming */
+ if (altsd->bNumEndpoints < 1)
+ return -ENODEV;
+ epd = get_endpoint(alts, 0);
+ if (!usb_endpoint_xfer_isoc(epd))
+ return -ENODEV;
+
+ /* must have format descriptors */
+ ashd = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL,
+ UAC_AS_GENERAL);
+ fmtd = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL,
+ UAC_FORMAT_TYPE);
+ if (!ashd || ashd->bLength < 7 ||
+ !fmtd || fmtd->bLength < 8)
+ return -ENODEV;
+
+ return create_standard_audio_quirk(chip, iface, driver, NULL);
+}
+
+static int create_yamaha_midi_quirk(struct snd_usb_audio *chip,
+ struct usb_interface *iface,
+ struct usb_driver *driver,
+ struct usb_host_interface *alts)
+{
+ static const struct snd_usb_audio_quirk yamaha_midi_quirk = {
+ .type = QUIRK_MIDI_YAMAHA
+ };
+ struct usb_midi_in_jack_descriptor *injd;
+ struct usb_midi_out_jack_descriptor *outjd;
+
+ /* must have some valid jack descriptors */
+ injd = snd_usb_find_csint_desc(alts->extra, alts->extralen,
+ NULL, USB_MS_MIDI_IN_JACK);
+ outjd = snd_usb_find_csint_desc(alts->extra, alts->extralen,
+ NULL, USB_MS_MIDI_OUT_JACK);
+ if (!injd && !outjd)
+ return -ENODEV;
+ if (injd && (injd->bLength < 5 ||
+ (injd->bJackType != USB_MS_EMBEDDED &&
+ injd->bJackType != USB_MS_EXTERNAL)))
+ return -ENODEV;
+ if (outjd && (outjd->bLength < 6 ||
+ (outjd->bJackType != USB_MS_EMBEDDED &&
+ outjd->bJackType != USB_MS_EXTERNAL)))
+ return -ENODEV;
+ return create_any_midi_quirk(chip, iface, driver, &yamaha_midi_quirk);
+}
+
+static int create_roland_midi_quirk(struct snd_usb_audio *chip,
+ struct usb_interface *iface,
+ struct usb_driver *driver,
+ struct usb_host_interface *alts)
+{
+ static const struct snd_usb_audio_quirk roland_midi_quirk = {
+ .type = QUIRK_MIDI_ROLAND
+ };
+ u8 *roland_desc = NULL;
+
+ /* might have a vendor-specific descriptor <06 24 F1 02 ...> */
+ for (;;) {
+ roland_desc = snd_usb_find_csint_desc(alts->extra,
+ alts->extralen,
+ roland_desc, 0xf1);
+ if (!roland_desc)
+ return -ENODEV;
+ if (roland_desc[0] < 6 || roland_desc[3] != 2)
+ continue;
+ return create_any_midi_quirk(chip, iface, driver,
+ &roland_midi_quirk);
+ }
+}
+
+static int create_std_midi_quirk(struct snd_usb_audio *chip,
+ struct usb_interface *iface,
+ struct usb_driver *driver,
+ struct usb_host_interface *alts)
+{
+ struct usb_ms_header_descriptor *mshd;
+ struct usb_ms_endpoint_descriptor *msepd;
+
+ /* must have the MIDIStreaming interface header descriptor*/
+ mshd = (struct usb_ms_header_descriptor *)alts->extra;
+ if (alts->extralen < 7 ||
+ mshd->bLength < 7 ||
+ mshd->bDescriptorType != USB_DT_CS_INTERFACE ||
+ mshd->bDescriptorSubtype != USB_MS_HEADER)
+ return -ENODEV;
+ /* must have the MIDIStreaming endpoint descriptor*/
+ msepd = (struct usb_ms_endpoint_descriptor *)alts->endpoint[0].extra;
+ if (alts->endpoint[0].extralen < 4 ||
+ msepd->bLength < 4 ||
+ msepd->bDescriptorType != USB_DT_CS_ENDPOINT ||
+ msepd->bDescriptorSubtype != UAC_MS_GENERAL ||
+ msepd->bNumEmbMIDIJack < 1 ||
+ msepd->bNumEmbMIDIJack > 16)
+ return -ENODEV;
+
+ return create_any_midi_quirk(chip, iface, driver, NULL);
+}
+
+static int create_auto_midi_quirk(struct snd_usb_audio *chip,
+ struct usb_interface *iface,
+ struct usb_driver *driver)
+{
+ struct usb_host_interface *alts;
+ struct usb_interface_descriptor *altsd;
+ struct usb_endpoint_descriptor *epd;
+ int err;
+
+ alts = &iface->altsetting[0];
+ altsd = get_iface_desc(alts);
+
+ /* must have at least one bulk/interrupt endpoint for streaming */
+ if (altsd->bNumEndpoints < 1)
+ return -ENODEV;
+ epd = get_endpoint(alts, 0);
+ if (!usb_endpoint_xfer_bulk(epd) ||
+ !usb_endpoint_xfer_int(epd))
+ return -ENODEV;
+
+ switch (USB_ID_VENDOR(chip->usb_id)) {
+ case 0x0499: /* Yamaha */
+ err = create_yamaha_midi_quirk(chip, iface, driver, alts);
+ if (err < 0 && err != -ENODEV)
+ return err;
+ break;
+ case 0x0582: /* Roland */
+ err = create_roland_midi_quirk(chip, iface, driver, alts);
+ if (err < 0 && err != -ENODEV)
+ return err;
+ break;
+ }
+
+ return create_std_midi_quirk(chip, iface, driver, alts);
+}
+
+static int create_autodetect_quirk(struct snd_usb_audio *chip,
+ struct usb_interface *iface,
+ struct usb_driver *driver)
+{
+ int err;
+
+ err = create_auto_pcm_quirk(chip, iface, driver);
+ if (err == -ENODEV)
+ err = create_auto_midi_quirk(chip, iface, driver);
+ return err;
+}
+
+static int create_autodetect_quirks(struct snd_usb_audio *chip,
+ struct usb_interface *iface,
+ struct usb_driver *driver,
+ const struct snd_usb_audio_quirk *quirk)
+{
+ int probed_ifnum = get_iface_desc(iface->altsetting)->bInterfaceNumber;
+ int ifcount, ifnum, err;
+
+ err = create_autodetect_quirk(chip, iface, driver);
+ if (err < 0)
+ return err;
+
+ /*
+ * ALSA PCM playback/capture devices cannot be registered in two steps,
+ * so we have to claim the other corresponding interface here.
+ */
+ ifcount = chip->dev->actconfig->desc.bNumInterfaces;
+ for (ifnum = 0; ifnum < ifcount; ifnum++) {
+ if (ifnum == probed_ifnum || quirk->ifnum >= 0)
+ continue;
+ iface = usb_ifnum_to_if(chip->dev, ifnum);
+ if (!iface ||
+ usb_interface_claimed(iface) ||
+ get_iface_desc(iface->altsetting)->bInterfaceClass !=
+ USB_CLASS_VENDOR_SPEC)
+ continue;
+
+ err = create_autodetect_quirk(chip, iface, driver);
+ if (err >= 0)
+ usb_driver_claim_interface(driver, iface, (void *)-1L);
+ }
+
+ return 0;
+}
+
/*
* Create a stream for an Edirol UA-700/UA-25/UA-4FX interface.
* The only way to detect the sample rate is by looking at wMaxPacketSize.
@@ -303,9 +514,11 @@ int snd_usb_create_quirk(struct snd_usb_audio *chip,
static const quirk_func_t quirk_funcs[] = {
[QUIRK_IGNORE_INTERFACE] = ignore_interface_quirk,
[QUIRK_COMPOSITE] = create_composite_quirk,
+ [QUIRK_AUTODETECT] = create_autodetect_quirks,
[QUIRK_MIDI_STANDARD_INTERFACE] = create_any_midi_quirk,
[QUIRK_MIDI_FIXED_ENDPOINT] = create_any_midi_quirk,
[QUIRK_MIDI_YAMAHA] = create_any_midi_quirk,
+ [QUIRK_MIDI_ROLAND] = create_any_midi_quirk,
[QUIRK_MIDI_MIDIMAN] = create_any_midi_quirk,
[QUIRK_MIDI_NOVATION] = create_any_midi_quirk,
[QUIRK_MIDI_RAW_BYTES] = create_any_midi_quirk,
diff --git a/sound/usb/stream.c b/sound/usb/stream.c
index 7db2f89..c4339f9 100644
--- a/sound/usb/stream.c
+++ b/sound/usb/stream.c
@@ -493,10 +493,10 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
altsd = get_iface_desc(alts);
protocol = altsd->bInterfaceProtocol;
/* skip invalid one */
- if ((altsd->bInterfaceClass != USB_CLASS_AUDIO &&
+ if (((altsd->bInterfaceClass != USB_CLASS_AUDIO ||
+ (altsd->bInterfaceSubClass != USB_SUBCLASS_AUDIOSTREAMING &&
+ altsd->bInterfaceSubClass != USB_SUBCLASS_VENDOR_SPEC)) &&
altsd->bInterfaceClass != USB_CLASS_VENDOR_SPEC) ||
- (altsd->bInterfaceSubClass != USB_SUBCLASS_AUDIOSTREAMING &&
- altsd->bInterfaceSubClass != USB_SUBCLASS_VENDOR_SPEC) ||
altsd->bNumEndpoints < 1 ||
le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize) == 0)
continue;
@@ -512,6 +512,15 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
if (snd_usb_apply_interface_quirk(chip, iface_no, altno))
continue;
+ /*
+ * Roland audio streaming interfaces are marked with protocols
+ * 0/1/2, but are UAC 1 compatible.
+ */
+ if (USB_ID_VENDOR(chip->usb_id) == 0x0582 &&
+ altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC &&
+ protocol <= 2)
+ protocol = UAC_VERSION_1;
+
chconfig = 0;
/* get audio formats */
switch (protocol) {
@@ -635,6 +644,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress;
fp->ep_attr = get_endpoint(alts, 0)->bmAttributes;
fp->datainterval = snd_usb_parse_datainterval(chip, alts);
+ fp->protocol = protocol;
fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize);
fp->channels = num_channels;
if (snd_usb_get_speed(dev) == USB_SPEED_HIGH)
@@ -676,7 +686,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
}
/* ok, let's parse further... */
- if (snd_usb_parse_audio_format(chip, fp, format, fmt, stream, alts) < 0) {
+ if (snd_usb_parse_audio_format(chip, fp, format, fmt, stream) < 0) {
kfree(fp->rate_table);
kfree(fp->chmap);
kfree(fp);
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
index bc43bca..caabe9b 100644
--- a/sound/usb/usbaudio.h
+++ b/sound/usb/usbaudio.h
@@ -72,9 +72,11 @@ struct snd_usb_audio {
enum quirk_type {
QUIRK_IGNORE_INTERFACE,
QUIRK_COMPOSITE,
+ QUIRK_AUTODETECT,
QUIRK_MIDI_STANDARD_INTERFACE,
QUIRK_MIDI_FIXED_ENDPOINT,
QUIRK_MIDI_YAMAHA,
+ QUIRK_MIDI_ROLAND,
QUIRK_MIDI_MIDIMAN,
QUIRK_MIDI_NOVATION,
QUIRK_MIDI_RAW_BYTES,
diff --git a/sound/usb/usx2y/usbusx2y.c b/sound/usb/usx2y/usbusx2y.c
index 9af7c1f..1f9bbd5 100644
--- a/sound/usb/usx2y/usbusx2y.c
+++ b/sound/usb/usx2y/usbusx2y.c
@@ -150,7 +150,7 @@
MODULE_AUTHOR("Karsten Wiese <annabellesgarden@yahoo.de>");
MODULE_DESCRIPTION("TASCAM "NAME_ALLCAPS" Version 0.8.7.2");
MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{TASCAM(0x1604), "NAME_ALLCAPS"(0x8001)(0x8005)(0x8007) }}");
+MODULE_SUPPORTED_DEVICE("{{TASCAM(0x1604),"NAME_ALLCAPS"(0x8001)(0x8005)(0x8007)}}");
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */
static char* id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for this card */
diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c
index b376532..4967fe9 100644
--- a/sound/usb/usx2y/usbusx2yaudio.c
+++ b/sound/usb/usx2y/usbusx2yaudio.c
@@ -695,9 +695,6 @@ static int usX2Y_rate_set(struct usX2Ydev *usX2Y, int rate)
((char*)(usbdata + i))[1] = ra[i].c2;
usb_fill_bulk_urb(us->urb[i], usX2Y->dev, usb_sndbulkpipe(usX2Y->dev, 4),
usbdata + i, 2, i_usX2Y_04Int, usX2Y);
-#ifdef OLD_USB
- us->urb[i]->transfer_flags = USB_QUEUE_BULK;
-#endif
}
us->submitted = 0;
us->len = NOOF_SETRATE_URBS;
OpenPOWER on IntegriCloud