mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-30 19:51:31 -04:00
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6: (365 commits) ALSA: hda - Disable sticky PCM stream assignment for AD codecs ALSA: usb - Creative USB X-Fi volume knob support ALSA: ca0106: Use card specific dac id for mute controls. ALSA: ca0106: Allow different sound cards to use different SPI channel mappings. ALSA: ca0106: Create a nice spot for mapping channels to dacs. ALSA: ca0106: Move enabling of front dac out of hardcoded setup sequence. ALSA: ca0106: Pull out dac powering routine into separate function. ALSA: ca0106 - add Sound Blaster 5.1vx info. ASoC: tlv320dac33: Use usleep_range for delays ALSA: usb-audio: add Novation Launchpad support ALSA: hda - Add workarounds for CT-IBG controllers ALSA: hda - Fix wrong TLV mute bit for STAC/IDT codecs ASoC: tpa6130a2: Error handling for broken chip ASoC: max98088: Staticise m98088_eq_band ASoC: soc-core: Fix codec->name memory leak ALSA: hda - Apply ideapad quirk to Acer laptops with Cxt5066 ALSA: hda - Add some workarounds for Creative IBG ALSA: hda - Fix wrong SPDIF NID assignment for CA0110 ALSA: hda - Fix codec rename rules for ALC662-compatible codecs ALSA: hda - Add alc_init_jacks() call to other codecs ...
This commit is contained in:
commit
33081adf8b
479 changed files with 37901 additions and 19477 deletions
|
|
@ -604,11 +604,16 @@ card_id_store_attr(struct device *dev, struct device_attribute *attr,
|
|||
return -EEXIST;
|
||||
}
|
||||
for (idx = 0; idx < snd_ecards_limit; idx++) {
|
||||
if (snd_cards[idx] && !strcmp(snd_cards[idx]->id, buf1))
|
||||
goto __exist;
|
||||
if (snd_cards[idx] && !strcmp(snd_cards[idx]->id, buf1)) {
|
||||
if (card == snd_cards[idx])
|
||||
goto __ok;
|
||||
else
|
||||
goto __exist;
|
||||
}
|
||||
}
|
||||
strcpy(card->id, buf1);
|
||||
snd_info_card_id_change(card);
|
||||
__ok:
|
||||
mutex_unlock(&snd_card_mutex);
|
||||
|
||||
return count;
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ static int snd_mixer_oss_release(struct inode *inode, struct file *file)
|
|||
struct snd_mixer_oss_file *fmixer;
|
||||
|
||||
if (file->private_data) {
|
||||
fmixer = (struct snd_mixer_oss_file *) file->private_data;
|
||||
fmixer = file->private_data;
|
||||
module_put(fmixer->card->module);
|
||||
snd_card_file_remove(fmixer->card, file);
|
||||
kfree(fmixer);
|
||||
|
|
@ -368,7 +368,7 @@ static int snd_mixer_oss_ioctl1(struct snd_mixer_oss_file *fmixer, unsigned int
|
|||
|
||||
static long snd_mixer_oss_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
return snd_mixer_oss_ioctl1((struct snd_mixer_oss_file *) file->private_data, cmd, arg);
|
||||
return snd_mixer_oss_ioctl1(file->private_data, cmd, arg);
|
||||
}
|
||||
|
||||
int snd_mixer_oss_ioctl_card(struct snd_card *card, unsigned int cmd, unsigned long arg)
|
||||
|
|
@ -582,7 +582,7 @@ static int snd_mixer_oss_get_volume1(struct snd_mixer_oss_file *fmixer,
|
|||
struct snd_mixer_oss_slot *pslot,
|
||||
int *left, int *right)
|
||||
{
|
||||
struct slot *slot = (struct slot *)pslot->private_data;
|
||||
struct slot *slot = pslot->private_data;
|
||||
|
||||
*left = *right = 100;
|
||||
if (slot->present & SNDRV_MIXER_OSS_PRESENT_PVOLUME) {
|
||||
|
|
@ -618,8 +618,10 @@ static void snd_mixer_oss_put_volume1_vol(struct snd_mixer_oss_file *fmixer,
|
|||
if (numid == ID_UNKNOWN)
|
||||
return;
|
||||
down_read(&card->controls_rwsem);
|
||||
if ((kctl = snd_ctl_find_numid(card, numid)) == NULL)
|
||||
if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) {
|
||||
up_read(&card->controls_rwsem);
|
||||
return;
|
||||
}
|
||||
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
|
||||
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
|
||||
if (uinfo == NULL || uctl == NULL)
|
||||
|
|
@ -658,7 +660,7 @@ static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer,
|
|||
return;
|
||||
down_read(&card->controls_rwsem);
|
||||
if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) {
|
||||
up_read(&fmixer->card->controls_rwsem);
|
||||
up_read(&card->controls_rwsem);
|
||||
return;
|
||||
}
|
||||
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
|
||||
|
|
@ -691,7 +693,7 @@ static int snd_mixer_oss_put_volume1(struct snd_mixer_oss_file *fmixer,
|
|||
struct snd_mixer_oss_slot *pslot,
|
||||
int left, int right)
|
||||
{
|
||||
struct slot *slot = (struct slot *)pslot->private_data;
|
||||
struct slot *slot = pslot->private_data;
|
||||
|
||||
if (slot->present & SNDRV_MIXER_OSS_PRESENT_PVOLUME) {
|
||||
snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PVOLUME], left, right);
|
||||
|
|
@ -740,7 +742,7 @@ static int snd_mixer_oss_get_recsrc1_sw(struct snd_mixer_oss_file *fmixer,
|
|||
struct snd_mixer_oss_slot *pslot,
|
||||
int *active)
|
||||
{
|
||||
struct slot *slot = (struct slot *)pslot->private_data;
|
||||
struct slot *slot = pslot->private_data;
|
||||
int left, right;
|
||||
|
||||
left = right = 1;
|
||||
|
|
@ -753,7 +755,7 @@ static int snd_mixer_oss_get_recsrc1_route(struct snd_mixer_oss_file *fmixer,
|
|||
struct snd_mixer_oss_slot *pslot,
|
||||
int *active)
|
||||
{
|
||||
struct slot *slot = (struct slot *)pslot->private_data;
|
||||
struct slot *slot = pslot->private_data;
|
||||
int left, right;
|
||||
|
||||
left = right = 1;
|
||||
|
|
@ -766,7 +768,7 @@ static int snd_mixer_oss_put_recsrc1_sw(struct snd_mixer_oss_file *fmixer,
|
|||
struct snd_mixer_oss_slot *pslot,
|
||||
int active)
|
||||
{
|
||||
struct slot *slot = (struct slot *)pslot->private_data;
|
||||
struct slot *slot = pslot->private_data;
|
||||
|
||||
snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CSWITCH], active, active, 0);
|
||||
return 0;
|
||||
|
|
@ -776,7 +778,7 @@ static int snd_mixer_oss_put_recsrc1_route(struct snd_mixer_oss_file *fmixer,
|
|||
struct snd_mixer_oss_slot *pslot,
|
||||
int active)
|
||||
{
|
||||
struct slot *slot = (struct slot *)pslot->private_data;
|
||||
struct slot *slot = pslot->private_data;
|
||||
|
||||
snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CROUTE], active, active, 1);
|
||||
return 0;
|
||||
|
|
@ -797,7 +799,7 @@ static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
|
|||
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
|
||||
if (uinfo == NULL || uctl == NULL) {
|
||||
err = -ENOMEM;
|
||||
goto __unlock;
|
||||
goto __free_only;
|
||||
}
|
||||
down_read(&card->controls_rwsem);
|
||||
kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0);
|
||||
|
|
@ -813,7 +815,7 @@ static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
|
|||
if (!(mixer->mask_recsrc & (1 << idx)))
|
||||
continue;
|
||||
pslot = &mixer->slots[idx];
|
||||
slot = (struct slot *)pslot->private_data;
|
||||
slot = pslot->private_data;
|
||||
if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE)
|
||||
continue;
|
||||
if (!(slot->present & SNDRV_MIXER_OSS_PRESENT_CAPTURE))
|
||||
|
|
@ -826,6 +828,7 @@ static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
|
|||
err = 0;
|
||||
__unlock:
|
||||
up_read(&card->controls_rwsem);
|
||||
__free_only:
|
||||
kfree(uctl);
|
||||
kfree(uinfo);
|
||||
return err;
|
||||
|
|
@ -847,7 +850,7 @@ static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
|
|||
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
|
||||
if (uinfo == NULL || uctl == NULL) {
|
||||
err = -ENOMEM;
|
||||
goto __unlock;
|
||||
goto __free_only;
|
||||
}
|
||||
down_read(&card->controls_rwsem);
|
||||
kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0);
|
||||
|
|
@ -861,7 +864,7 @@ static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
|
|||
if (!(mixer->mask_recsrc & (1 << idx)))
|
||||
continue;
|
||||
pslot = &mixer->slots[idx];
|
||||
slot = (struct slot *)pslot->private_data;
|
||||
slot = pslot->private_data;
|
||||
if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE)
|
||||
continue;
|
||||
if (!(slot->present & SNDRV_MIXER_OSS_PRESENT_CAPTURE))
|
||||
|
|
@ -880,6 +883,7 @@ static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
|
|||
err = 0;
|
||||
__unlock:
|
||||
up_read(&card->controls_rwsem);
|
||||
__free_only:
|
||||
kfree(uctl);
|
||||
kfree(uinfo);
|
||||
return err;
|
||||
|
|
@ -925,7 +929,7 @@ static int snd_mixer_oss_build_test(struct snd_mixer_oss *mixer, struct slot *sl
|
|||
|
||||
static void snd_mixer_oss_slot_free(struct snd_mixer_oss_slot *chn)
|
||||
{
|
||||
struct slot *p = (struct slot *)chn->private_data;
|
||||
struct slot *p = chn->private_data;
|
||||
if (p) {
|
||||
if (p->allocated && p->assigned) {
|
||||
kfree(p->assigned->name);
|
||||
|
|
|
|||
|
|
@ -364,8 +364,7 @@ static void snd_pcm_stream_proc_info_read(struct snd_info_entry *entry,
|
|||
static void snd_pcm_substream_proc_info_read(struct snd_info_entry *entry,
|
||||
struct snd_info_buffer *buffer)
|
||||
{
|
||||
snd_pcm_proc_info_read((struct snd_pcm_substream *)entry->private_data,
|
||||
buffer);
|
||||
snd_pcm_proc_info_read(entry->private_data, buffer);
|
||||
}
|
||||
|
||||
static void snd_pcm_substream_proc_hw_params_read(struct snd_info_entry *entry,
|
||||
|
|
|
|||
|
|
@ -334,11 +334,15 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
|
|||
/* delta = "expected next hw_ptr" for in_interrupt != 0 */
|
||||
delta = runtime->hw_ptr_interrupt + runtime->period_size;
|
||||
if (delta > new_hw_ptr) {
|
||||
hw_base += runtime->buffer_size;
|
||||
if (hw_base >= runtime->boundary)
|
||||
hw_base = 0;
|
||||
new_hw_ptr = hw_base + pos;
|
||||
goto __delta;
|
||||
/* check for double acknowledged interrupts */
|
||||
hdelta = jiffies - runtime->hw_ptr_jiffies;
|
||||
if (hdelta > runtime->hw_ptr_buffer_jiffies/2) {
|
||||
hw_base += runtime->buffer_size;
|
||||
if (hw_base >= runtime->boundary)
|
||||
hw_base = 0;
|
||||
new_hw_ptr = hw_base + pos;
|
||||
goto __delta;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* new_hw_ptr might be lower than old_hw_ptr in case when */
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ int snd_pcm_info_user(struct snd_pcm_substream *substream,
|
|||
|
||||
#ifdef RULES_DEBUG
|
||||
#define HW_PARAM(v) [SNDRV_PCM_HW_PARAM_##v] = #v
|
||||
char *snd_pcm_hw_param_names[] = {
|
||||
static const char * const snd_pcm_hw_param_names[] = {
|
||||
HW_PARAM(ACCESS),
|
||||
HW_PARAM(FORMAT),
|
||||
HW_PARAM(SUBFORMAT),
|
||||
|
|
@ -864,6 +864,8 @@ static void snd_pcm_post_start(struct snd_pcm_substream *substream, int state)
|
|||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
snd_pcm_trigger_tstamp(substream);
|
||||
runtime->hw_ptr_jiffies = jiffies;
|
||||
runtime->hw_ptr_buffer_jiffies = (runtime->buffer_size * HZ) /
|
||||
runtime->rate;
|
||||
runtime->status->state = state;
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
|
||||
runtime->silence_size > 0)
|
||||
|
|
|
|||
|
|
@ -74,6 +74,25 @@ config SND_DUMMY
|
|||
To compile this driver as a module, choose M here: the module
|
||||
will be called snd-dummy.
|
||||
|
||||
config SND_ALOOP
|
||||
tristate "Generic loopback driver (PCM)"
|
||||
select SND_PCM
|
||||
help
|
||||
Say 'Y' or 'M' to include support for the PCM loopback device.
|
||||
This module returns played samples back to the user space using
|
||||
the standard ALSA PCM device. The devices are routed 0->1 and
|
||||
1->0, where first number is the playback PCM device and second
|
||||
number is the capture device. Module creates two PCM devices and
|
||||
configured number of substreams (see the pcm_substreams module
|
||||
parameter).
|
||||
|
||||
The looback device allow time sychronization with an external
|
||||
timing source using the time shift universal control (+-20%
|
||||
of system time).
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called snd-aloop.
|
||||
|
||||
config SND_VIRMIDI
|
||||
tristate "Virtual MIDI soundcard"
|
||||
depends on SND_SEQUENCER
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
#
|
||||
|
||||
snd-dummy-objs := dummy.o
|
||||
snd-aloop-objs := aloop.o
|
||||
snd-mtpav-objs := mtpav.o
|
||||
snd-mts64-objs := mts64.o
|
||||
snd-portman2x4-objs := portman2x4.o
|
||||
|
|
@ -13,6 +14,7 @@ snd-ml403-ac97cr-objs := ml403-ac97cr.o pcm-indirect2.o
|
|||
|
||||
# Toplevel Module Dependency
|
||||
obj-$(CONFIG_SND_DUMMY) += snd-dummy.o
|
||||
obj-$(CONFIG_SND_ALOOP) += snd-aloop.o
|
||||
obj-$(CONFIG_SND_VIRMIDI) += snd-virmidi.o
|
||||
obj-$(CONFIG_SND_SERIAL_U16550) += snd-serial-u16550.o
|
||||
obj-$(CONFIG_SND_MTPAV) += snd-mtpav.o
|
||||
|
|
|
|||
1258
sound/drivers/aloop.c
Normal file
1258
sound/drivers/aloop.c
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -94,7 +94,7 @@ static int __devinit snd_virmidi_probe(struct platform_device *devptr)
|
|||
sizeof(struct snd_card_virmidi), &card);
|
||||
if (err < 0)
|
||||
return err;
|
||||
vmidi = (struct snd_card_virmidi *)card->private_data;
|
||||
vmidi = card->private_data;
|
||||
vmidi->card = card;
|
||||
|
||||
if (midi_devs[dev] > MAX_MIDI_DEVICES) {
|
||||
|
|
|
|||
|
|
@ -878,7 +878,7 @@ static int build_deemphasis(struct snd_akm4xxx *ak, int num_emphs)
|
|||
static void proc_regs_read(struct snd_info_entry *entry,
|
||||
struct snd_info_buffer *buffer)
|
||||
{
|
||||
struct snd_akm4xxx *ak = (struct snd_akm4xxx *)entry->private_data;
|
||||
struct snd_akm4xxx *ak = entry->private_data;
|
||||
int reg, val, chip;
|
||||
for (chip = 0; chip < ak->num_chips; chip++) {
|
||||
for (reg = 0; reg < ak->total_regs; reg++) {
|
||||
|
|
|
|||
|
|
@ -77,6 +77,32 @@ config SND_ALS100
|
|||
To compile this driver as a module, choose M here: the module
|
||||
will be called snd-als100.
|
||||
|
||||
config SND_AZT1605
|
||||
tristate "Aztech AZT1605 Driver"
|
||||
depends on SND
|
||||
select SND_WSS_LIB
|
||||
select SND_MPU401_UART
|
||||
select SND_OPL3_LIB
|
||||
help
|
||||
Say Y here to include support for Aztech Sound Galaxy cards
|
||||
based on the AZT1605 chipset.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called snd-azt1605.
|
||||
|
||||
config SND_AZT2316
|
||||
tristate "Aztech AZT2316 Driver"
|
||||
depends on SND
|
||||
select SND_WSS_LIB
|
||||
select SND_MPU401_UART
|
||||
select SND_OPL3_LIB
|
||||
help
|
||||
Say Y here to include support for Aztech Sound Galaxy cards
|
||||
based on the AZT2316 chipset.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called snd-azt2316.
|
||||
|
||||
config SND_AZT2320
|
||||
tristate "Aztech Systems AZT2320"
|
||||
depends on PNP
|
||||
|
|
@ -351,16 +377,6 @@ config SND_SB16_CSP
|
|||
coprocessor can do variable tasks like various compression and
|
||||
decompression algorithms.
|
||||
|
||||
config SND_SGALAXY
|
||||
tristate "Aztech Sound Galaxy"
|
||||
select SND_WSS_LIB
|
||||
help
|
||||
Say Y here to include support for Aztech Sound Galaxy
|
||||
soundcards.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called snd-sgalaxy.
|
||||
|
||||
config SND_SSCAPE
|
||||
tristate "Ensoniq SoundScape driver"
|
||||
select SND_MPU401_UART
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ snd-cmi8330-objs := cmi8330.o
|
|||
snd-es18xx-objs := es18xx.o
|
||||
snd-opl3sa2-objs := opl3sa2.o
|
||||
snd-sc6000-objs := sc6000.o
|
||||
snd-sgalaxy-objs := sgalaxy.o
|
||||
snd-sscape-objs := sscape.o
|
||||
|
||||
# Toplevel Module Dependency
|
||||
|
|
@ -21,8 +20,7 @@ obj-$(CONFIG_SND_CMI8330) += snd-cmi8330.o
|
|||
obj-$(CONFIG_SND_ES18XX) += snd-es18xx.o
|
||||
obj-$(CONFIG_SND_OPL3SA2) += snd-opl3sa2.o
|
||||
obj-$(CONFIG_SND_SC6000) += snd-sc6000.o
|
||||
obj-$(CONFIG_SND_SGALAXY) += snd-sgalaxy.o
|
||||
obj-$(CONFIG_SND_SSCAPE) += snd-sscape.o
|
||||
|
||||
obj-$(CONFIG_SND) += ad1816a/ ad1848/ cs423x/ es1688/ gus/ msnd/ opti9xx/ \
|
||||
obj-$(CONFIG_SND) += ad1816a/ ad1848/ cs423x/ es1688/ galaxy/ gus/ msnd/ opti9xx/ \
|
||||
sb/ wavefront/ wss/
|
||||
|
|
|
|||
|
|
@ -162,7 +162,7 @@ static int __devinit snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard
|
|||
sizeof(struct snd_card_ad1816a), &card);
|
||||
if (error < 0)
|
||||
return error;
|
||||
acard = (struct snd_card_ad1816a *)card->private_data;
|
||||
acard = card->private_data;
|
||||
|
||||
if ((error = snd_card_ad1816a_pnp(dev, acard, pcard, pid))) {
|
||||
snd_card_free(card);
|
||||
|
|
|
|||
|
|
@ -188,7 +188,7 @@ static int __devinit snd_card_azt2320_probe(int dev,
|
|||
sizeof(struct snd_card_azt2320), &card);
|
||||
if (error < 0)
|
||||
return error;
|
||||
acard = (struct snd_card_azt2320 *)card->private_data;
|
||||
acard = card->private_data;
|
||||
|
||||
if ((error = snd_card_azt2320_pnp(dev, acard, pcard, pid))) {
|
||||
snd_card_free(card);
|
||||
|
|
|
|||
10
sound/isa/galaxy/Makefile
Normal file
10
sound/isa/galaxy/Makefile
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
#
|
||||
# Makefile for ALSA
|
||||
# Copyright (c) 2001 by Jaroslav Kysela <[email protected]>
|
||||
#
|
||||
|
||||
snd-azt1605-objs := azt1605.o
|
||||
snd-azt2316-objs := azt2316.o
|
||||
|
||||
obj-$(CONFIG_SND_AZT1605) += snd-azt1605.o
|
||||
obj-$(CONFIG_SND_AZT2316) += snd-azt2316.o
|
||||
91
sound/isa/galaxy/azt1605.c
Normal file
91
sound/isa/galaxy/azt1605.c
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* Aztech AZT1605 Driver
|
||||
* Copyright (C) 2007,2010 Rene Herman
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#define AZT1605
|
||||
|
||||
#define CRD_NAME "Aztech AZT1605"
|
||||
#define DRV_NAME "AZT1605"
|
||||
#define DEV_NAME "azt1605"
|
||||
|
||||
#define GALAXY_DSP_MAJOR 2
|
||||
#define GALAXY_DSP_MINOR 1
|
||||
|
||||
#define GALAXY_CONFIG_SIZE 3
|
||||
|
||||
/*
|
||||
* 24-bit config register
|
||||
*/
|
||||
|
||||
#define GALAXY_CONFIG_SBA_220 (0 << 0)
|
||||
#define GALAXY_CONFIG_SBA_240 (1 << 0)
|
||||
#define GALAXY_CONFIG_SBA_260 (2 << 0)
|
||||
#define GALAXY_CONFIG_SBA_280 (3 << 0)
|
||||
#define GALAXY_CONFIG_SBA_MASK GALAXY_CONFIG_SBA_280
|
||||
|
||||
#define GALAXY_CONFIG_MPUA_300 (0 << 2)
|
||||
#define GALAXY_CONFIG_MPUA_330 (1 << 2)
|
||||
|
||||
#define GALAXY_CONFIG_MPU_ENABLE (1 << 3)
|
||||
|
||||
#define GALAXY_CONFIG_GAME_ENABLE (1 << 4)
|
||||
|
||||
#define GALAXY_CONFIG_CD_PANASONIC (1 << 5)
|
||||
#define GALAXY_CONFIG_CD_MITSUMI (1 << 6)
|
||||
#define GALAXY_CONFIG_CD_MASK (\
|
||||
GALAXY_CONFIG_CD_PANASONIC | GALAXY_CONFIG_CD_MITSUMI)
|
||||
|
||||
#define GALAXY_CONFIG_UNUSED (1 << 7)
|
||||
#define GALAXY_CONFIG_UNUSED_MASK GALAXY_CONFIG_UNUSED
|
||||
|
||||
#define GALAXY_CONFIG_SBIRQ_2 (1 << 8)
|
||||
#define GALAXY_CONFIG_SBIRQ_3 (1 << 9)
|
||||
#define GALAXY_CONFIG_SBIRQ_5 (1 << 10)
|
||||
#define GALAXY_CONFIG_SBIRQ_7 (1 << 11)
|
||||
|
||||
#define GALAXY_CONFIG_MPUIRQ_2 (1 << 12)
|
||||
#define GALAXY_CONFIG_MPUIRQ_3 (1 << 13)
|
||||
#define GALAXY_CONFIG_MPUIRQ_5 (1 << 14)
|
||||
#define GALAXY_CONFIG_MPUIRQ_7 (1 << 15)
|
||||
|
||||
#define GALAXY_CONFIG_WSSA_530 (0 << 16)
|
||||
#define GALAXY_CONFIG_WSSA_604 (1 << 16)
|
||||
#define GALAXY_CONFIG_WSSA_E80 (2 << 16)
|
||||
#define GALAXY_CONFIG_WSSA_F40 (3 << 16)
|
||||
|
||||
#define GALAXY_CONFIG_WSS_ENABLE (1 << 18)
|
||||
|
||||
#define GALAXY_CONFIG_CDIRQ_11 (1 << 19)
|
||||
#define GALAXY_CONFIG_CDIRQ_12 (1 << 20)
|
||||
#define GALAXY_CONFIG_CDIRQ_15 (1 << 21)
|
||||
#define GALAXY_CONFIG_CDIRQ_MASK (\
|
||||
GALAXY_CONFIG_CDIRQ_11 | GALAXY_CONFIG_CDIRQ_12 |\
|
||||
GALAXY_CONFIG_CDIRQ_15)
|
||||
|
||||
#define GALAXY_CONFIG_CDDMA_DISABLE (0 << 22)
|
||||
#define GALAXY_CONFIG_CDDMA_0 (1 << 22)
|
||||
#define GALAXY_CONFIG_CDDMA_1 (2 << 22)
|
||||
#define GALAXY_CONFIG_CDDMA_3 (3 << 22)
|
||||
#define GALAXY_CONFIG_CDDMA_MASK GALAXY_CONFIG_CDDMA_3
|
||||
|
||||
#define GALAXY_CONFIG_MASK (\
|
||||
GALAXY_CONFIG_SBA_MASK | GALAXY_CONFIG_CD_MASK |\
|
||||
GALAXY_CONFIG_UNUSED_MASK | GALAXY_CONFIG_CDIRQ_MASK |\
|
||||
GALAXY_CONFIG_CDDMA_MASK)
|
||||
|
||||
#include "galaxy.c"
|
||||
111
sound/isa/galaxy/azt2316.c
Normal file
111
sound/isa/galaxy/azt2316.c
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
* Aztech AZT2316 Driver
|
||||
* Copyright (C) 2007,2010 Rene Herman
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#define AZT2316
|
||||
|
||||
#define CRD_NAME "Aztech AZT2316"
|
||||
#define DRV_NAME "AZT2316"
|
||||
#define DEV_NAME "azt2316"
|
||||
|
||||
#define GALAXY_DSP_MAJOR 3
|
||||
#define GALAXY_DSP_MINOR 1
|
||||
|
||||
#define GALAXY_CONFIG_SIZE 4
|
||||
|
||||
/*
|
||||
* 32-bit config register
|
||||
*/
|
||||
|
||||
#define GALAXY_CONFIG_SBA_220 (0 << 0)
|
||||
#define GALAXY_CONFIG_SBA_240 (1 << 0)
|
||||
#define GALAXY_CONFIG_SBA_260 (2 << 0)
|
||||
#define GALAXY_CONFIG_SBA_280 (3 << 0)
|
||||
#define GALAXY_CONFIG_SBA_MASK GALAXY_CONFIG_SBA_280
|
||||
|
||||
#define GALAXY_CONFIG_SBIRQ_2 (1 << 2)
|
||||
#define GALAXY_CONFIG_SBIRQ_5 (1 << 3)
|
||||
#define GALAXY_CONFIG_SBIRQ_7 (1 << 4)
|
||||
#define GALAXY_CONFIG_SBIRQ_10 (1 << 5)
|
||||
|
||||
#define GALAXY_CONFIG_SBDMA_DISABLE (0 << 6)
|
||||
#define GALAXY_CONFIG_SBDMA_0 (1 << 6)
|
||||
#define GALAXY_CONFIG_SBDMA_1 (2 << 6)
|
||||
#define GALAXY_CONFIG_SBDMA_3 (3 << 6)
|
||||
|
||||
#define GALAXY_CONFIG_WSSA_530 (0 << 8)
|
||||
#define GALAXY_CONFIG_WSSA_604 (1 << 8)
|
||||
#define GALAXY_CONFIG_WSSA_E80 (2 << 8)
|
||||
#define GALAXY_CONFIG_WSSA_F40 (3 << 8)
|
||||
|
||||
#define GALAXY_CONFIG_WSS_ENABLE (1 << 10)
|
||||
|
||||
#define GALAXY_CONFIG_GAME_ENABLE (1 << 11)
|
||||
|
||||
#define GALAXY_CONFIG_MPUA_300 (0 << 12)
|
||||
#define GALAXY_CONFIG_MPUA_330 (1 << 12)
|
||||
|
||||
#define GALAXY_CONFIG_MPU_ENABLE (1 << 13)
|
||||
|
||||
#define GALAXY_CONFIG_CDA_310 (0 << 14)
|
||||
#define GALAXY_CONFIG_CDA_320 (1 << 14)
|
||||
#define GALAXY_CONFIG_CDA_340 (2 << 14)
|
||||
#define GALAXY_CONFIG_CDA_350 (3 << 14)
|
||||
#define GALAXY_CONFIG_CDA_MASK GALAXY_CONFIG_CDA_350
|
||||
|
||||
#define GALAXY_CONFIG_CD_DISABLE (0 << 16)
|
||||
#define GALAXY_CONFIG_CD_PANASONIC (1 << 16)
|
||||
#define GALAXY_CONFIG_CD_SONY (2 << 16)
|
||||
#define GALAXY_CONFIG_CD_MITSUMI (3 << 16)
|
||||
#define GALAXY_CONFIG_CD_AZTECH (4 << 16)
|
||||
#define GALAXY_CONFIG_CD_UNUSED_5 (5 << 16)
|
||||
#define GALAXY_CONFIG_CD_UNUSED_6 (6 << 16)
|
||||
#define GALAXY_CONFIG_CD_UNUSED_7 (7 << 16)
|
||||
#define GALAXY_CONFIG_CD_MASK GALAXY_CONFIG_CD_UNUSED_7
|
||||
|
||||
#define GALAXY_CONFIG_CDDMA8_DISABLE (0 << 20)
|
||||
#define GALAXY_CONFIG_CDDMA8_0 (1 << 20)
|
||||
#define GALAXY_CONFIG_CDDMA8_1 (2 << 20)
|
||||
#define GALAXY_CONFIG_CDDMA8_3 (3 << 20)
|
||||
#define GALAXY_CONFIG_CDDMA8_MASK GALAXY_CONFIG_CDDMA8_3
|
||||
|
||||
#define GALAXY_CONFIG_CDDMA16_DISABLE (0 << 22)
|
||||
#define GALAXY_CONFIG_CDDMA16_5 (1 << 22)
|
||||
#define GALAXY_CONFIG_CDDMA16_6 (2 << 22)
|
||||
#define GALAXY_CONFIG_CDDMA16_7 (3 << 22)
|
||||
#define GALAXY_CONFIG_CDDMA16_MASK GALAXY_CONFIG_CDDMA16_7
|
||||
|
||||
#define GALAXY_CONFIG_MPUIRQ_2 (1 << 24)
|
||||
#define GALAXY_CONFIG_MPUIRQ_5 (1 << 25)
|
||||
#define GALAXY_CONFIG_MPUIRQ_7 (1 << 26)
|
||||
#define GALAXY_CONFIG_MPUIRQ_10 (1 << 27)
|
||||
|
||||
#define GALAXY_CONFIG_CDIRQ_5 (1 << 28)
|
||||
#define GALAXY_CONFIG_CDIRQ_11 (1 << 29)
|
||||
#define GALAXY_CONFIG_CDIRQ_12 (1 << 30)
|
||||
#define GALAXY_CONFIG_CDIRQ_15 (1 << 31)
|
||||
#define GALAXY_CONFIG_CDIRQ_MASK (\
|
||||
GALAXY_CONFIG_CDIRQ_5 | GALAXY_CONFIG_CDIRQ_11 |\
|
||||
GALAXY_CONFIG_CDIRQ_12 | GALAXY_CONFIG_CDIRQ_15)
|
||||
|
||||
#define GALAXY_CONFIG_MASK (\
|
||||
GALAXY_CONFIG_SBA_MASK | GALAXY_CONFIG_CDA_MASK |\
|
||||
GALAXY_CONFIG_CD_MASK | GALAXY_CONFIG_CDDMA16_MASK |\
|
||||
GALAXY_CONFIG_CDDMA8_MASK | GALAXY_CONFIG_CDIRQ_MASK)
|
||||
|
||||
#include "galaxy.c"
|
||||
652
sound/isa/galaxy/galaxy.c
Normal file
652
sound/isa/galaxy/galaxy.c
Normal file
|
|
@ -0,0 +1,652 @@
|
|||
/*
|
||||
* Aztech AZT1605/AZT2316 Driver
|
||||
* Copyright (C) 2007,2010 Rene Herman
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/isa.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/io.h>
|
||||
#include <asm/processor.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/wss.h>
|
||||
#include <sound/mpu401.h>
|
||||
#include <sound/opl3.h>
|
||||
|
||||
MODULE_DESCRIPTION(CRD_NAME);
|
||||
MODULE_AUTHOR("Rene Herman");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
|
||||
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
|
||||
static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;
|
||||
|
||||
module_param_array(index, int, NULL, 0444);
|
||||
MODULE_PARM_DESC(index, "Index value for " CRD_NAME " soundcard.");
|
||||
module_param_array(id, charp, NULL, 0444);
|
||||
MODULE_PARM_DESC(id, "ID string for " CRD_NAME " soundcard.");
|
||||
module_param_array(enable, bool, NULL, 0444);
|
||||
MODULE_PARM_DESC(enable, "Enable " CRD_NAME " soundcard.");
|
||||
|
||||
static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
|
||||
static long wss_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
|
||||
static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
|
||||
static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
|
||||
static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
|
||||
static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
|
||||
static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;
|
||||
static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;
|
||||
|
||||
module_param_array(port, long, NULL, 0444);
|
||||
MODULE_PARM_DESC(port, "Port # for " CRD_NAME " driver.");
|
||||
module_param_array(wss_port, long, NULL, 0444);
|
||||
MODULE_PARM_DESC(wss_port, "WSS port # for " CRD_NAME " driver.");
|
||||
module_param_array(mpu_port, long, NULL, 0444);
|
||||
MODULE_PARM_DESC(mpu_port, "MPU-401 port # for " CRD_NAME " driver.");
|
||||
module_param_array(fm_port, long, NULL, 0444);
|
||||
MODULE_PARM_DESC(fm_port, "FM port # for " CRD_NAME " driver.");
|
||||
module_param_array(irq, int, NULL, 0444);
|
||||
MODULE_PARM_DESC(irq, "IRQ # for " CRD_NAME " driver.");
|
||||
module_param_array(mpu_irq, int, NULL, 0444);
|
||||
MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for " CRD_NAME " driver.");
|
||||
module_param_array(dma1, int, NULL, 0444);
|
||||
MODULE_PARM_DESC(dma1, "Playback DMA # for " CRD_NAME " driver.");
|
||||
module_param_array(dma2, int, NULL, 0444);
|
||||
MODULE_PARM_DESC(dma2, "Capture DMA # for " CRD_NAME " driver.");
|
||||
|
||||
/*
|
||||
* Generic SB DSP support routines
|
||||
*/
|
||||
|
||||
#define DSP_PORT_RESET 0x6
|
||||
#define DSP_PORT_READ 0xa
|
||||
#define DSP_PORT_COMMAND 0xc
|
||||
#define DSP_PORT_STATUS 0xc
|
||||
#define DSP_PORT_DATA_AVAIL 0xe
|
||||
|
||||
#define DSP_SIGNATURE 0xaa
|
||||
|
||||
#define DSP_COMMAND_GET_VERSION 0xe1
|
||||
|
||||
static int __devinit dsp_get_byte(void __iomem *port, u8 *val)
|
||||
{
|
||||
int loops = 1000;
|
||||
|
||||
while (!(ioread8(port + DSP_PORT_DATA_AVAIL) & 0x80)) {
|
||||
if (!loops--)
|
||||
return -EIO;
|
||||
cpu_relax();
|
||||
}
|
||||
*val = ioread8(port + DSP_PORT_READ);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit dsp_reset(void __iomem *port)
|
||||
{
|
||||
u8 val;
|
||||
|
||||
iowrite8(1, port + DSP_PORT_RESET);
|
||||
udelay(10);
|
||||
iowrite8(0, port + DSP_PORT_RESET);
|
||||
|
||||
if (dsp_get_byte(port, &val) < 0 || val != DSP_SIGNATURE)
|
||||
return -ENODEV;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit dsp_command(void __iomem *port, u8 cmd)
|
||||
{
|
||||
int loops = 1000;
|
||||
|
||||
while (ioread8(port + DSP_PORT_STATUS) & 0x80) {
|
||||
if (!loops--)
|
||||
return -EIO;
|
||||
cpu_relax();
|
||||
}
|
||||
iowrite8(cmd, port + DSP_PORT_COMMAND);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit dsp_get_version(void __iomem *port, u8 *major, u8 *minor)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = dsp_command(port, DSP_COMMAND_GET_VERSION);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = dsp_get_byte(port, major);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = dsp_get_byte(port, minor);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generic WSS support routines
|
||||
*/
|
||||
|
||||
#define WSS_CONFIG_DMA_0 (1 << 0)
|
||||
#define WSS_CONFIG_DMA_1 (2 << 0)
|
||||
#define WSS_CONFIG_DMA_3 (3 << 0)
|
||||
#define WSS_CONFIG_DUPLEX (1 << 2)
|
||||
#define WSS_CONFIG_IRQ_7 (1 << 3)
|
||||
#define WSS_CONFIG_IRQ_9 (2 << 3)
|
||||
#define WSS_CONFIG_IRQ_10 (3 << 3)
|
||||
#define WSS_CONFIG_IRQ_11 (4 << 3)
|
||||
|
||||
#define WSS_PORT_CONFIG 0
|
||||
#define WSS_PORT_SIGNATURE 3
|
||||
|
||||
#define WSS_SIGNATURE 4
|
||||
|
||||
static int __devinit wss_detect(void __iomem *wss_port)
|
||||
{
|
||||
if ((ioread8(wss_port + WSS_PORT_SIGNATURE) & 0x3f) != WSS_SIGNATURE)
|
||||
return -ENODEV;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void wss_set_config(void __iomem *wss_port, u8 wss_config)
|
||||
{
|
||||
iowrite8(wss_config, wss_port + WSS_PORT_CONFIG);
|
||||
}
|
||||
|
||||
/*
|
||||
* Aztech Sound Galaxy specifics
|
||||
*/
|
||||
|
||||
#define GALAXY_PORT_CONFIG 1024
|
||||
#define CONFIG_PORT_SET 4
|
||||
|
||||
#define DSP_COMMAND_GALAXY_8 8
|
||||
#define GALAXY_COMMAND_GET_TYPE 5
|
||||
|
||||
#define DSP_COMMAND_GALAXY_9 9
|
||||
#define GALAXY_COMMAND_WSSMODE 0
|
||||
#define GALAXY_COMMAND_SB8MODE 1
|
||||
|
||||
#define GALAXY_MODE_WSS GALAXY_COMMAND_WSSMODE
|
||||
#define GALAXY_MODE_SB8 GALAXY_COMMAND_SB8MODE
|
||||
|
||||
struct snd_galaxy {
|
||||
void __iomem *port;
|
||||
void __iomem *config_port;
|
||||
void __iomem *wss_port;
|
||||
u32 config;
|
||||
struct resource *res_port;
|
||||
struct resource *res_config_port;
|
||||
struct resource *res_wss_port;
|
||||
};
|
||||
|
||||
static u32 config[SNDRV_CARDS];
|
||||
static u8 wss_config[SNDRV_CARDS];
|
||||
|
||||
static int __devinit snd_galaxy_match(struct device *dev, unsigned int n)
|
||||
{
|
||||
if (!enable[n])
|
||||
return 0;
|
||||
|
||||
switch (port[n]) {
|
||||
case SNDRV_AUTO_PORT:
|
||||
dev_err(dev, "please specify port\n");
|
||||
return 0;
|
||||
case 0x220:
|
||||
config[n] |= GALAXY_CONFIG_SBA_220;
|
||||
break;
|
||||
case 0x240:
|
||||
config[n] |= GALAXY_CONFIG_SBA_240;
|
||||
break;
|
||||
case 0x260:
|
||||
config[n] |= GALAXY_CONFIG_SBA_260;
|
||||
break;
|
||||
case 0x280:
|
||||
config[n] |= GALAXY_CONFIG_SBA_280;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "invalid port %#lx\n", port[n]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (wss_port[n]) {
|
||||
case SNDRV_AUTO_PORT:
|
||||
dev_err(dev, "please specify wss_port\n");
|
||||
return 0;
|
||||
case 0x530:
|
||||
config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_530;
|
||||
break;
|
||||
case 0x604:
|
||||
config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_604;
|
||||
break;
|
||||
case 0xe80:
|
||||
config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_E80;
|
||||
break;
|
||||
case 0xf40:
|
||||
config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_F40;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "invalid WSS port %#lx\n", wss_port[n]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (irq[n]) {
|
||||
case SNDRV_AUTO_IRQ:
|
||||
dev_err(dev, "please specify irq\n");
|
||||
return 0;
|
||||
case 7:
|
||||
wss_config[n] |= WSS_CONFIG_IRQ_7;
|
||||
break;
|
||||
case 2:
|
||||
irq[n] = 9;
|
||||
case 9:
|
||||
wss_config[n] |= WSS_CONFIG_IRQ_9;
|
||||
break;
|
||||
case 10:
|
||||
wss_config[n] |= WSS_CONFIG_IRQ_10;
|
||||
break;
|
||||
case 11:
|
||||
wss_config[n] |= WSS_CONFIG_IRQ_11;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "invalid IRQ %d\n", irq[n]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (dma1[n]) {
|
||||
case SNDRV_AUTO_DMA:
|
||||
dev_err(dev, "please specify dma1\n");
|
||||
return 0;
|
||||
case 0:
|
||||
wss_config[n] |= WSS_CONFIG_DMA_0;
|
||||
break;
|
||||
case 1:
|
||||
wss_config[n] |= WSS_CONFIG_DMA_1;
|
||||
break;
|
||||
case 3:
|
||||
wss_config[n] |= WSS_CONFIG_DMA_3;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "invalid playback DMA %d\n", dma1[n]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dma2[n] == SNDRV_AUTO_DMA || dma2[n] == dma1[n]) {
|
||||
dma2[n] = -1;
|
||||
goto mpu;
|
||||
}
|
||||
|
||||
wss_config[n] |= WSS_CONFIG_DUPLEX;
|
||||
switch (dma2[n]) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
if (dma1[n] == 0)
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "invalid capture DMA %d\n", dma2[n]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
mpu:
|
||||
switch (mpu_port[n]) {
|
||||
case SNDRV_AUTO_PORT:
|
||||
dev_warn(dev, "mpu_port not specified; not using MPU-401\n");
|
||||
mpu_port[n] = -1;
|
||||
goto fm;
|
||||
case 0x300:
|
||||
config[n] |= GALAXY_CONFIG_MPU_ENABLE | GALAXY_CONFIG_MPUA_300;
|
||||
break;
|
||||
case 0x330:
|
||||
config[n] |= GALAXY_CONFIG_MPU_ENABLE | GALAXY_CONFIG_MPUA_330;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "invalid MPU port %#lx\n", mpu_port[n]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (mpu_irq[n]) {
|
||||
case SNDRV_AUTO_IRQ:
|
||||
dev_warn(dev, "mpu_irq not specified: using polling mode\n");
|
||||
mpu_irq[n] = -1;
|
||||
break;
|
||||
case 2:
|
||||
mpu_irq[n] = 9;
|
||||
case 9:
|
||||
config[n] |= GALAXY_CONFIG_MPUIRQ_2;
|
||||
break;
|
||||
#ifdef AZT1605
|
||||
case 3:
|
||||
config[n] |= GALAXY_CONFIG_MPUIRQ_3;
|
||||
break;
|
||||
#endif
|
||||
case 5:
|
||||
config[n] |= GALAXY_CONFIG_MPUIRQ_5;
|
||||
break;
|
||||
case 7:
|
||||
config[n] |= GALAXY_CONFIG_MPUIRQ_7;
|
||||
break;
|
||||
#ifdef AZT2316
|
||||
case 10:
|
||||
config[n] |= GALAXY_CONFIG_MPUIRQ_10;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
dev_err(dev, "invalid MPU IRQ %d\n", mpu_irq[n]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mpu_irq[n] == irq[n]) {
|
||||
dev_err(dev, "cannot share IRQ between WSS and MPU-401\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
fm:
|
||||
switch (fm_port[n]) {
|
||||
case SNDRV_AUTO_PORT:
|
||||
dev_warn(dev, "fm_port not specified: not using OPL3\n");
|
||||
fm_port[n] = -1;
|
||||
break;
|
||||
case 0x388:
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "illegal FM port %#lx\n", fm_port[n]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
config[n] |= GALAXY_CONFIG_GAME_ENABLE;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int __devinit galaxy_init(struct snd_galaxy *galaxy, u8 *type)
|
||||
{
|
||||
u8 major;
|
||||
u8 minor;
|
||||
int err;
|
||||
|
||||
err = dsp_reset(galaxy->port);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = dsp_get_version(galaxy->port, &major, &minor);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (major != GALAXY_DSP_MAJOR || minor != GALAXY_DSP_MINOR)
|
||||
return -ENODEV;
|
||||
|
||||
err = dsp_command(galaxy->port, DSP_COMMAND_GALAXY_8);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = dsp_command(galaxy->port, GALAXY_COMMAND_GET_TYPE);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = dsp_get_byte(galaxy->port, type);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit galaxy_set_mode(struct snd_galaxy *galaxy, u8 mode)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = dsp_command(galaxy->port, DSP_COMMAND_GALAXY_9);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = dsp_command(galaxy->port, mode);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
#ifdef AZT1605
|
||||
/*
|
||||
* Needed for MPU IRQ on AZT1605, but AZT2316 loses WSS again
|
||||
*/
|
||||
err = dsp_reset(galaxy->port);
|
||||
if (err < 0)
|
||||
return err;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void galaxy_set_config(struct snd_galaxy *galaxy, u32 config)
|
||||
{
|
||||
u8 tmp = ioread8(galaxy->config_port + CONFIG_PORT_SET);
|
||||
int i;
|
||||
|
||||
iowrite8(tmp | 0x80, galaxy->config_port + CONFIG_PORT_SET);
|
||||
for (i = 0; i < GALAXY_CONFIG_SIZE; i++) {
|
||||
iowrite8(config, galaxy->config_port + i);
|
||||
config >>= 8;
|
||||
}
|
||||
iowrite8(tmp & 0x7f, galaxy->config_port + CONFIG_PORT_SET);
|
||||
msleep(10);
|
||||
}
|
||||
|
||||
static void __devinit galaxy_config(struct snd_galaxy *galaxy, u32 config)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = GALAXY_CONFIG_SIZE; i; i--) {
|
||||
u8 tmp = ioread8(galaxy->config_port + i - 1);
|
||||
galaxy->config = (galaxy->config << 8) | tmp;
|
||||
}
|
||||
config |= galaxy->config & GALAXY_CONFIG_MASK;
|
||||
galaxy_set_config(galaxy, config);
|
||||
}
|
||||
|
||||
static int __devinit galaxy_wss_config(struct snd_galaxy *galaxy, u8 wss_config)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = wss_detect(galaxy->wss_port);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
wss_set_config(galaxy->wss_port, wss_config);
|
||||
|
||||
err = galaxy_set_mode(galaxy, GALAXY_MODE_WSS);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void snd_galaxy_free(struct snd_card *card)
|
||||
{
|
||||
struct snd_galaxy *galaxy = card->private_data;
|
||||
|
||||
if (galaxy->wss_port) {
|
||||
wss_set_config(galaxy->wss_port, 0);
|
||||
ioport_unmap(galaxy->wss_port);
|
||||
release_and_free_resource(galaxy->res_wss_port);
|
||||
}
|
||||
if (galaxy->config_port) {
|
||||
galaxy_set_config(galaxy, galaxy->config);
|
||||
ioport_unmap(galaxy->config_port);
|
||||
release_and_free_resource(galaxy->res_config_port);
|
||||
}
|
||||
if (galaxy->port) {
|
||||
ioport_unmap(galaxy->port);
|
||||
release_and_free_resource(galaxy->res_port);
|
||||
}
|
||||
}
|
||||
|
||||
static int __devinit snd_galaxy_probe(struct device *dev, unsigned int n)
|
||||
{
|
||||
struct snd_galaxy *galaxy;
|
||||
struct snd_wss *chip;
|
||||
struct snd_card *card;
|
||||
u8 type;
|
||||
int err;
|
||||
|
||||
err = snd_card_create(index[n], id[n], THIS_MODULE, sizeof *galaxy,
|
||||
&card);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
snd_card_set_dev(card, dev);
|
||||
|
||||
card->private_free = snd_galaxy_free;
|
||||
galaxy = card->private_data;
|
||||
|
||||
galaxy->res_port = request_region(port[n], 16, DRV_NAME);
|
||||
if (!galaxy->res_port) {
|
||||
dev_err(dev, "could not grab ports %#lx-%#lx\n", port[n],
|
||||
port[n] + 15);
|
||||
err = -EBUSY;
|
||||
goto error;
|
||||
}
|
||||
galaxy->port = ioport_map(port[n], 16);
|
||||
|
||||
err = galaxy_init(galaxy, &type);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "did not find a Sound Galaxy at %#lx\n", port[n]);
|
||||
goto error;
|
||||
}
|
||||
dev_info(dev, "Sound Galaxy (type %d) found at %#lx\n", type, port[n]);
|
||||
|
||||
galaxy->res_config_port = request_region(port[n] + GALAXY_PORT_CONFIG,
|
||||
16, DRV_NAME);
|
||||
if (!galaxy->res_config_port) {
|
||||
dev_err(dev, "could not grab ports %#lx-%#lx\n",
|
||||
port[n] + GALAXY_PORT_CONFIG,
|
||||
port[n] + GALAXY_PORT_CONFIG + 15);
|
||||
err = -EBUSY;
|
||||
goto error;
|
||||
}
|
||||
galaxy->config_port = ioport_map(port[n] + GALAXY_PORT_CONFIG, 16);
|
||||
|
||||
galaxy_config(galaxy, config[n]);
|
||||
|
||||
galaxy->res_wss_port = request_region(wss_port[n], 4, DRV_NAME);
|
||||
if (!galaxy->res_wss_port) {
|
||||
dev_err(dev, "could not grab ports %#lx-%#lx\n", wss_port[n],
|
||||
wss_port[n] + 3);
|
||||
err = -EBUSY;
|
||||
goto error;
|
||||
}
|
||||
galaxy->wss_port = ioport_map(wss_port[n], 4);
|
||||
|
||||
err = galaxy_wss_config(galaxy, wss_config[n]);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "could not configure WSS\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
strcpy(card->driver, DRV_NAME);
|
||||
strcpy(card->shortname, DRV_NAME);
|
||||
sprintf(card->longname, "%s at %#lx/%#lx, irq %d, dma %d/%d",
|
||||
card->shortname, port[n], wss_port[n], irq[n], dma1[n],
|
||||
dma2[n]);
|
||||
|
||||
err = snd_wss_create(card, wss_port[n] + 4, -1, irq[n], dma1[n],
|
||||
dma2[n], WSS_HW_DETECT, 0, &chip);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
err = snd_wss_pcm(chip, 0, NULL);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
err = snd_wss_mixer(chip);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
err = snd_wss_timer(chip, 0, NULL);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
if (mpu_port[n] >= 0) {
|
||||
err = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
|
||||
mpu_port[n], 0, mpu_irq[n],
|
||||
IRQF_DISABLED, NULL);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (fm_port[n] >= 0) {
|
||||
struct snd_opl3 *opl3;
|
||||
|
||||
err = snd_opl3_create(card, fm_port[n], fm_port[n] + 2,
|
||||
OPL3_HW_AUTO, 0, &opl3);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "no OPL device at %#lx\n", fm_port[n]);
|
||||
goto error;
|
||||
}
|
||||
err = snd_opl3_timer_new(opl3, 1, 2);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
err = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
}
|
||||
|
||||
err = snd_card_register(card);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
dev_set_drvdata(dev, card);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
snd_card_free(card);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __devexit snd_galaxy_remove(struct device *dev, unsigned int n)
|
||||
{
|
||||
snd_card_free(dev_get_drvdata(dev));
|
||||
dev_set_drvdata(dev, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct isa_driver snd_galaxy_driver = {
|
||||
.match = snd_galaxy_match,
|
||||
.probe = snd_galaxy_probe,
|
||||
.remove = __devexit_p(snd_galaxy_remove),
|
||||
|
||||
.driver = {
|
||||
.name = DEV_NAME
|
||||
}
|
||||
};
|
||||
|
||||
static int __init alsa_card_galaxy_init(void)
|
||||
{
|
||||
return isa_register_driver(&snd_galaxy_driver, SNDRV_CARDS);
|
||||
}
|
||||
|
||||
static void __exit alsa_card_galaxy_exit(void)
|
||||
{
|
||||
isa_unregister_driver(&snd_galaxy_driver);
|
||||
}
|
||||
|
||||
module_init(alsa_card_galaxy_init);
|
||||
module_exit(alsa_card_galaxy_exit);
|
||||
|
|
@ -191,7 +191,7 @@ static int __devinit snd_gusmax_mixer(struct snd_wss *chip)
|
|||
|
||||
static void snd_gusmax_free(struct snd_card *card)
|
||||
{
|
||||
struct snd_gusmax *maxcard = (struct snd_gusmax *)card->private_data;
|
||||
struct snd_gusmax *maxcard = card->private_data;
|
||||
|
||||
if (maxcard == NULL)
|
||||
return;
|
||||
|
|
@ -219,7 +219,7 @@ static int __devinit snd_gusmax_probe(struct device *pdev, unsigned int dev)
|
|||
if (err < 0)
|
||||
return err;
|
||||
card->private_free = snd_gusmax_free;
|
||||
maxcard = (struct snd_gusmax *)card->private_data;
|
||||
maxcard = card->private_data;
|
||||
maxcard->card = card;
|
||||
maxcard->irq = -1;
|
||||
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ static irqreturn_t snd_sb8_interrupt(int irq, void *dev_id)
|
|||
|
||||
static void snd_sb8_free(struct snd_card *card)
|
||||
{
|
||||
struct snd_sb8 *acard = (struct snd_sb8 *)card->private_data;
|
||||
struct snd_sb8 *acard = card->private_data;
|
||||
|
||||
if (acard == NULL)
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -1,369 +0,0 @@
|
|||
/*
|
||||
* Driver for Aztech Sound Galaxy cards
|
||||
* Copyright (c) by Christopher Butler <chrisb@sandy.force9.co.uk.
|
||||
*
|
||||
* I don't have documentation for this card, I based this driver on the
|
||||
* driver for OSS/Free included in the kernel source (drivers/sound/sgalaxy.c)
|
||||
*
|
||||
* 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/err.h>
|
||||
#include <linux/isa.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <asm/dma.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/sb.h>
|
||||
#include <sound/wss.h>
|
||||
#include <sound/control.h>
|
||||
#define SNDRV_LEGACY_FIND_FREE_IRQ
|
||||
#define SNDRV_LEGACY_FIND_FREE_DMA
|
||||
#include <sound/initval.h>
|
||||
|
||||
MODULE_AUTHOR("Christopher Butler <[email protected]>");
|
||||
MODULE_DESCRIPTION("Aztech Sound Galaxy");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_SUPPORTED_DEVICE("{{Aztech Systems,Sound Galaxy}}");
|
||||
|
||||
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
|
||||
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
|
||||
static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */
|
||||
static long sbport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x220,0x240 */
|
||||
static long wssport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x530,0xe80,0xf40,0x604 */
|
||||
static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 7,9,10,11 */
|
||||
static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0,1,3 */
|
||||
|
||||
module_param_array(index, int, NULL, 0444);
|
||||
MODULE_PARM_DESC(index, "Index value for Sound Galaxy soundcard.");
|
||||
module_param_array(id, charp, NULL, 0444);
|
||||
MODULE_PARM_DESC(id, "ID string for Sound Galaxy soundcard.");
|
||||
module_param_array(sbport, long, NULL, 0444);
|
||||
MODULE_PARM_DESC(sbport, "Port # for Sound Galaxy SB driver.");
|
||||
module_param_array(wssport, long, NULL, 0444);
|
||||
MODULE_PARM_DESC(wssport, "Port # for Sound Galaxy WSS driver.");
|
||||
module_param_array(irq, int, NULL, 0444);
|
||||
MODULE_PARM_DESC(irq, "IRQ # for Sound Galaxy driver.");
|
||||
module_param_array(dma1, int, NULL, 0444);
|
||||
MODULE_PARM_DESC(dma1, "DMA1 # for Sound Galaxy driver.");
|
||||
|
||||
#define SGALAXY_AUXC_LEFT 18
|
||||
#define SGALAXY_AUXC_RIGHT 19
|
||||
|
||||
#define PFX "sgalaxy: "
|
||||
|
||||
/*
|
||||
|
||||
*/
|
||||
|
||||
#define AD1848P1( port, x ) ( port + c_d_c_AD1848##x )
|
||||
|
||||
/* from lowlevel/sb/sb.c - to avoid having to allocate a struct snd_sb for the */
|
||||
/* short time we actually need it.. */
|
||||
|
||||
static int snd_sgalaxy_sbdsp_reset(unsigned long port)
|
||||
{
|
||||
int i;
|
||||
|
||||
outb(1, SBP1(port, RESET));
|
||||
udelay(10);
|
||||
outb(0, SBP1(port, RESET));
|
||||
udelay(30);
|
||||
for (i = 0; i < 1000 && !(inb(SBP1(port, DATA_AVAIL)) & 0x80); i++);
|
||||
if (inb(SBP1(port, READ)) != 0xaa) {
|
||||
snd_printd("sb_reset: failed at 0x%lx!!!\n", port);
|
||||
return -ENODEV;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit snd_sgalaxy_sbdsp_command(unsigned long port,
|
||||
unsigned char val)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 10000; i; i--)
|
||||
if ((inb(SBP1(port, STATUS)) & 0x80) == 0) {
|
||||
outb(val, SBP1(port, COMMAND));
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t snd_sgalaxy_dummy_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
static int __devinit snd_sgalaxy_setup_wss(unsigned long port, int irq, int dma)
|
||||
{
|
||||
static int interrupt_bits[] = {-1, -1, -1, -1, -1, -1, -1, 0x08, -1,
|
||||
0x10, 0x18, 0x20, -1, -1, -1, -1};
|
||||
static int dma_bits[] = {1, 2, 0, 3};
|
||||
int tmp, tmp1;
|
||||
|
||||
if ((tmp = inb(port + 3)) == 0xff)
|
||||
{
|
||||
snd_printdd("I/O address dead (0x%lx)\n", port);
|
||||
return 0;
|
||||
}
|
||||
#if 0
|
||||
snd_printdd("WSS signature = 0x%x\n", tmp);
|
||||
#endif
|
||||
|
||||
if ((tmp & 0x3f) != 0x04 &&
|
||||
(tmp & 0x3f) != 0x0f &&
|
||||
(tmp & 0x3f) != 0x00) {
|
||||
snd_printdd("No WSS signature detected on port 0x%lx\n",
|
||||
port + 3);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
snd_printdd(PFX "setting up IRQ/DMA for WSS\n");
|
||||
#endif
|
||||
|
||||
/* initialize IRQ for WSS codec */
|
||||
tmp = interrupt_bits[irq % 16];
|
||||
if (tmp < 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (request_irq(irq, snd_sgalaxy_dummy_interrupt, IRQF_DISABLED, "sgalaxy", NULL)) {
|
||||
snd_printk(KERN_ERR "sgalaxy: can't grab irq %d\n", irq);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
outb(tmp | 0x40, port);
|
||||
tmp1 = dma_bits[dma % 4];
|
||||
outb(tmp | tmp1, port);
|
||||
|
||||
free_irq(irq, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit snd_sgalaxy_detect(int dev, int irq, int dma)
|
||||
{
|
||||
#if 0
|
||||
snd_printdd(PFX "switching to WSS mode\n");
|
||||
#endif
|
||||
|
||||
/* switch to WSS mode */
|
||||
snd_sgalaxy_sbdsp_reset(sbport[dev]);
|
||||
|
||||
snd_sgalaxy_sbdsp_command(sbport[dev], 9);
|
||||
snd_sgalaxy_sbdsp_command(sbport[dev], 0);
|
||||
|
||||
udelay(400);
|
||||
return snd_sgalaxy_setup_wss(wssport[dev], irq, dma);
|
||||
}
|
||||
|
||||
static struct snd_kcontrol_new snd_sgalaxy_controls[] = {
|
||||
WSS_DOUBLE("Aux Playback Switch", 0,
|
||||
SGALAXY_AUXC_LEFT, SGALAXY_AUXC_RIGHT, 7, 7, 1, 1),
|
||||
WSS_DOUBLE("Aux Playback Volume", 0,
|
||||
SGALAXY_AUXC_LEFT, SGALAXY_AUXC_RIGHT, 0, 0, 31, 0)
|
||||
};
|
||||
|
||||
static int __devinit snd_sgalaxy_mixer(struct snd_wss *chip)
|
||||
{
|
||||
struct snd_card *card = chip->card;
|
||||
struct snd_ctl_elem_id id1, id2;
|
||||
unsigned int idx;
|
||||
int err;
|
||||
|
||||
memset(&id1, 0, sizeof(id1));
|
||||
memset(&id2, 0, sizeof(id2));
|
||||
id1.iface = id2.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
|
||||
/* reassign AUX0 to LINE */
|
||||
strcpy(id1.name, "Aux Playback Switch");
|
||||
strcpy(id2.name, "Line Playback Switch");
|
||||
if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0)
|
||||
return err;
|
||||
strcpy(id1.name, "Aux Playback Volume");
|
||||
strcpy(id2.name, "Line Playback Volume");
|
||||
if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0)
|
||||
return err;
|
||||
/* reassign AUX1 to FM */
|
||||
strcpy(id1.name, "Aux Playback Switch"); id1.index = 1;
|
||||
strcpy(id2.name, "FM Playback Switch");
|
||||
if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0)
|
||||
return err;
|
||||
strcpy(id1.name, "Aux Playback Volume");
|
||||
strcpy(id2.name, "FM Playback Volume");
|
||||
if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0)
|
||||
return err;
|
||||
/* build AUX2 input */
|
||||
for (idx = 0; idx < ARRAY_SIZE(snd_sgalaxy_controls); idx++) {
|
||||
err = snd_ctl_add(card,
|
||||
snd_ctl_new1(&snd_sgalaxy_controls[idx], chip));
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit snd_sgalaxy_match(struct device *devptr, unsigned int dev)
|
||||
{
|
||||
if (!enable[dev])
|
||||
return 0;
|
||||
if (sbport[dev] == SNDRV_AUTO_PORT) {
|
||||
snd_printk(KERN_ERR PFX "specify SB port\n");
|
||||
return 0;
|
||||
}
|
||||
if (wssport[dev] == SNDRV_AUTO_PORT) {
|
||||
snd_printk(KERN_ERR PFX "specify WSS port\n");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int __devinit snd_sgalaxy_probe(struct device *devptr, unsigned int dev)
|
||||
{
|
||||
static int possible_irqs[] = {7, 9, 10, 11, -1};
|
||||
static int possible_dmas[] = {1, 3, 0, -1};
|
||||
int err, xirq, xdma1;
|
||||
struct snd_card *card;
|
||||
struct snd_wss *chip;
|
||||
|
||||
err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
xirq = irq[dev];
|
||||
if (xirq == SNDRV_AUTO_IRQ) {
|
||||
if ((xirq = snd_legacy_find_free_irq(possible_irqs)) < 0) {
|
||||
snd_printk(KERN_ERR PFX "unable to find a free IRQ\n");
|
||||
err = -EBUSY;
|
||||
goto _err;
|
||||
}
|
||||
}
|
||||
xdma1 = dma1[dev];
|
||||
if (xdma1 == SNDRV_AUTO_DMA) {
|
||||
if ((xdma1 = snd_legacy_find_free_dma(possible_dmas)) < 0) {
|
||||
snd_printk(KERN_ERR PFX "unable to find a free DMA\n");
|
||||
err = -EBUSY;
|
||||
goto _err;
|
||||
}
|
||||
}
|
||||
|
||||
if ((err = snd_sgalaxy_detect(dev, xirq, xdma1)) < 0)
|
||||
goto _err;
|
||||
|
||||
err = snd_wss_create(card, wssport[dev] + 4, -1,
|
||||
xirq, xdma1, -1,
|
||||
WSS_HW_DETECT, 0, &chip);
|
||||
if (err < 0)
|
||||
goto _err;
|
||||
card->private_data = chip;
|
||||
|
||||
err = snd_wss_pcm(chip, 0, NULL);
|
||||
if (err < 0) {
|
||||
snd_printdd(PFX "error creating new WSS PCM device\n");
|
||||
goto _err;
|
||||
}
|
||||
err = snd_wss_mixer(chip);
|
||||
if (err < 0) {
|
||||
snd_printdd(PFX "error creating new WSS mixer\n");
|
||||
goto _err;
|
||||
}
|
||||
if ((err = snd_sgalaxy_mixer(chip)) < 0) {
|
||||
snd_printdd(PFX "the mixer rewrite failed\n");
|
||||
goto _err;
|
||||
}
|
||||
|
||||
strcpy(card->driver, "Sound Galaxy");
|
||||
strcpy(card->shortname, "Sound Galaxy");
|
||||
sprintf(card->longname, "Sound Galaxy at 0x%lx, irq %d, dma %d",
|
||||
wssport[dev], xirq, xdma1);
|
||||
|
||||
snd_card_set_dev(card, devptr);
|
||||
|
||||
if ((err = snd_card_register(card)) < 0)
|
||||
goto _err;
|
||||
|
||||
dev_set_drvdata(devptr, card);
|
||||
return 0;
|
||||
|
||||
_err:
|
||||
snd_card_free(card);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __devexit snd_sgalaxy_remove(struct device *devptr, unsigned int dev)
|
||||
{
|
||||
snd_card_free(dev_get_drvdata(devptr));
|
||||
dev_set_drvdata(devptr, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int snd_sgalaxy_suspend(struct device *pdev, unsigned int n,
|
||||
pm_message_t state)
|
||||
{
|
||||
struct snd_card *card = dev_get_drvdata(pdev);
|
||||
struct snd_wss *chip = card->private_data;
|
||||
|
||||
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
|
||||
chip->suspend(chip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_sgalaxy_resume(struct device *pdev, unsigned int n)
|
||||
{
|
||||
struct snd_card *card = dev_get_drvdata(pdev);
|
||||
struct snd_wss *chip = card->private_data;
|
||||
|
||||
chip->resume(chip);
|
||||
snd_wss_out(chip, SGALAXY_AUXC_LEFT, chip->image[SGALAXY_AUXC_LEFT]);
|
||||
snd_wss_out(chip, SGALAXY_AUXC_RIGHT, chip->image[SGALAXY_AUXC_RIGHT]);
|
||||
|
||||
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define DEV_NAME "sgalaxy"
|
||||
|
||||
static struct isa_driver snd_sgalaxy_driver = {
|
||||
.match = snd_sgalaxy_match,
|
||||
.probe = snd_sgalaxy_probe,
|
||||
.remove = __devexit_p(snd_sgalaxy_remove),
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = snd_sgalaxy_suspend,
|
||||
.resume = snd_sgalaxy_resume,
|
||||
#endif
|
||||
.driver = {
|
||||
.name = DEV_NAME
|
||||
},
|
||||
};
|
||||
|
||||
static int __init alsa_card_sgalaxy_init(void)
|
||||
{
|
||||
return isa_register_driver(&snd_sgalaxy_driver, SNDRV_CARDS);
|
||||
}
|
||||
|
||||
static void __exit alsa_card_sgalaxy_exit(void)
|
||||
{
|
||||
isa_unregister_driver(&snd_sgalaxy_driver);
|
||||
}
|
||||
|
||||
module_init(alsa_card_sgalaxy_init)
|
||||
module_exit(alsa_card_sgalaxy_exit)
|
||||
|
|
@ -545,11 +545,3 @@ config SOUND_KAHLUA
|
|||
|
||||
endif # SOUND_OSS
|
||||
|
||||
config SOUND_SH_DAC_AUDIO
|
||||
tristate "SuperH DAC audio support"
|
||||
depends on CPU_SH3 && HIGH_RES_TIMERS
|
||||
|
||||
config SOUND_SH_DAC_AUDIO_CHANNEL
|
||||
int "DAC channel"
|
||||
default "1"
|
||||
depends on SOUND_SH_DAC_AUDIO
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ obj-$(CONFIG_SOUND_OSS) += sound.o
|
|||
|
||||
# Please leave it as is, cause the link order is significant !
|
||||
|
||||
obj-$(CONFIG_SOUND_SH_DAC_AUDIO) += sh_dac_audio.o
|
||||
obj-$(CONFIG_SOUND_AEDSP16) += aedsp16.o
|
||||
obj-$(CONFIG_SOUND_PSS) += pss.o ad1848.o mpu401.o
|
||||
obj-$(CONFIG_SOUND_TRIX) += trix.o ad1848.o sb_lib.o uart401.o
|
||||
|
|
|
|||
|
|
@ -43,7 +43,6 @@
|
|||
#include <linux/sound.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/soundcard.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
|
|
@ -77,6 +76,7 @@
|
|||
/* Boot options
|
||||
* 0 = no VRA, 1 = use VRA if codec supports it
|
||||
*/
|
||||
static DEFINE_MUTEX(au1550_ac97_mutex);
|
||||
static int vra = 1;
|
||||
module_param(vra, bool, 0);
|
||||
MODULE_PARM_DESC(vra, "if 1 use VRA if codec supports it");
|
||||
|
|
@ -171,7 +171,7 @@ au1550_delay(int msec)
|
|||
static u16
|
||||
rdcodec(struct ac97_codec *codec, u8 addr)
|
||||
{
|
||||
struct au1550_state *s = (struct au1550_state *)codec->private_data;
|
||||
struct au1550_state *s = codec->private_data;
|
||||
unsigned long flags;
|
||||
u32 cmd, val;
|
||||
u16 data;
|
||||
|
|
@ -239,7 +239,7 @@ rdcodec(struct ac97_codec *codec, u8 addr)
|
|||
static void
|
||||
wrcodec(struct ac97_codec *codec, u8 addr, u16 data)
|
||||
{
|
||||
struct au1550_state *s = (struct au1550_state *)codec->private_data;
|
||||
struct au1550_state *s = codec->private_data;
|
||||
unsigned long flags;
|
||||
u32 cmd, val;
|
||||
int i;
|
||||
|
|
@ -798,9 +798,9 @@ au1550_llseek(struct file *file, loff_t offset, int origin)
|
|||
static int
|
||||
au1550_open_mixdev(struct inode *inode, struct file *file)
|
||||
{
|
||||
lock_kernel();
|
||||
mutex_lock(&au1550_ac97_mutex);
|
||||
file->private_data = &au1550_state;
|
||||
unlock_kernel();
|
||||
mutex_unlock(&au1550_ac97_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -820,13 +820,13 @@ mixdev_ioctl(struct ac97_codec *codec, unsigned int cmd,
|
|||
static long
|
||||
au1550_ioctl_mixdev(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct au1550_state *s = (struct au1550_state *)file->private_data;
|
||||
struct au1550_state *s = file->private_data;
|
||||
struct ac97_codec *codec = s->codec;
|
||||
int ret;
|
||||
|
||||
lock_kernel();
|
||||
mutex_lock(&au1550_ac97_mutex);
|
||||
ret = mixdev_ioctl(codec, cmd, arg);
|
||||
unlock_kernel();
|
||||
mutex_unlock(&au1550_ac97_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -1031,7 +1031,7 @@ copy_dmabuf_user(struct dmabuf *db, char* userbuf, int count, int to_user)
|
|||
static ssize_t
|
||||
au1550_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
|
||||
{
|
||||
struct au1550_state *s = (struct au1550_state *)file->private_data;
|
||||
struct au1550_state *s = file->private_data;
|
||||
struct dmabuf *db = &s->dma_adc;
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
ssize_t ret;
|
||||
|
|
@ -1111,7 +1111,7 @@ out2:
|
|||
static ssize_t
|
||||
au1550_write(struct file *file, const char *buffer, size_t count, loff_t * ppos)
|
||||
{
|
||||
struct au1550_state *s = (struct au1550_state *)file->private_data;
|
||||
struct au1550_state *s = file->private_data;
|
||||
struct dmabuf *db = &s->dma_dac;
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
ssize_t ret = 0;
|
||||
|
|
@ -1211,7 +1211,7 @@ out2:
|
|||
static unsigned int
|
||||
au1550_poll(struct file *file, struct poll_table_struct *wait)
|
||||
{
|
||||
struct au1550_state *s = (struct au1550_state *)file->private_data;
|
||||
struct au1550_state *s = file->private_data;
|
||||
unsigned long flags;
|
||||
unsigned int mask = 0;
|
||||
|
||||
|
|
@ -1250,12 +1250,12 @@ au1550_poll(struct file *file, struct poll_table_struct *wait)
|
|||
static int
|
||||
au1550_mmap(struct file *file, struct vm_area_struct *vma)
|
||||
{
|
||||
struct au1550_state *s = (struct au1550_state *)file->private_data;
|
||||
struct au1550_state *s = file->private_data;
|
||||
struct dmabuf *db;
|
||||
unsigned long size;
|
||||
int ret = 0;
|
||||
|
||||
lock_kernel();
|
||||
mutex_lock(&au1550_ac97_mutex);
|
||||
mutex_lock(&s->sem);
|
||||
if (vma->vm_flags & VM_WRITE)
|
||||
db = &s->dma_dac;
|
||||
|
|
@ -1283,7 +1283,7 @@ au1550_mmap(struct file *file, struct vm_area_struct *vma)
|
|||
db->mapped = 1;
|
||||
out:
|
||||
mutex_unlock(&s->sem);
|
||||
unlock_kernel();
|
||||
mutex_unlock(&au1550_ac97_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -1342,7 +1342,7 @@ dma_count_done(struct dmabuf *db)
|
|||
static int
|
||||
au1550_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct au1550_state *s = (struct au1550_state *)file->private_data;
|
||||
struct au1550_state *s = file->private_data;
|
||||
unsigned long flags;
|
||||
audio_buf_info abinfo;
|
||||
count_info cinfo;
|
||||
|
|
@ -1781,9 +1781,9 @@ au1550_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|||
{
|
||||
int ret;
|
||||
|
||||
lock_kernel();
|
||||
mutex_lock(&au1550_ac97_mutex);
|
||||
ret = au1550_ioctl(file, cmd, arg);
|
||||
unlock_kernel();
|
||||
mutex_unlock(&au1550_ac97_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -1804,7 +1804,7 @@ au1550_open(struct inode *inode, struct file *file)
|
|||
#endif
|
||||
|
||||
file->private_data = s;
|
||||
lock_kernel();
|
||||
mutex_lock(&au1550_ac97_mutex);
|
||||
/* wait for device to become free */
|
||||
mutex_lock(&s->open_mutex);
|
||||
while (s->open_mode & file->f_mode) {
|
||||
|
|
@ -1861,21 +1861,21 @@ au1550_open(struct inode *inode, struct file *file)
|
|||
out:
|
||||
mutex_unlock(&s->open_mutex);
|
||||
out2:
|
||||
unlock_kernel();
|
||||
mutex_unlock(&au1550_ac97_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
au1550_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct au1550_state *s = (struct au1550_state *)file->private_data;
|
||||
struct au1550_state *s = file->private_data;
|
||||
|
||||
lock_kernel();
|
||||
mutex_lock(&au1550_ac97_mutex);
|
||||
|
||||
if (file->f_mode & FMODE_WRITE) {
|
||||
unlock_kernel();
|
||||
mutex_unlock(&au1550_ac97_mutex);
|
||||
drain_dac(s, file->f_flags & O_NONBLOCK);
|
||||
lock_kernel();
|
||||
mutex_lock(&au1550_ac97_mutex);
|
||||
}
|
||||
|
||||
mutex_lock(&s->open_mutex);
|
||||
|
|
@ -1892,7 +1892,7 @@ au1550_release(struct inode *inode, struct file *file)
|
|||
s->open_mode &= ((~file->f_mode) & (FMODE_READ|FMODE_WRITE));
|
||||
mutex_unlock(&s->open_mutex);
|
||||
wake_up(&s->open_wait);
|
||||
unlock_kernel();
|
||||
mutex_unlock(&au1550_ac97_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/soundcard.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
|
|
@ -194,6 +194,7 @@
|
|||
* Declarations
|
||||
*/
|
||||
|
||||
static DEFINE_MUTEX(dmasound_core_mutex);
|
||||
int dmasound_catchRadius = 0;
|
||||
module_param(dmasound_catchRadius, int, 0);
|
||||
|
||||
|
|
@ -323,22 +324,22 @@ static struct {
|
|||
|
||||
static int mixer_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
lock_kernel();
|
||||
mutex_lock(&dmasound_core_mutex);
|
||||
if (!try_module_get(dmasound.mach.owner)) {
|
||||
unlock_kernel();
|
||||
mutex_unlock(&dmasound_core_mutex);
|
||||
return -ENODEV;
|
||||
}
|
||||
mixer.busy = 1;
|
||||
unlock_kernel();
|
||||
mutex_unlock(&dmasound_core_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mixer_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
lock_kernel();
|
||||
mutex_lock(&dmasound_core_mutex);
|
||||
mixer.busy = 0;
|
||||
module_put(dmasound.mach.owner);
|
||||
unlock_kernel();
|
||||
mutex_unlock(&dmasound_core_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -370,9 +371,9 @@ static long mixer_unlocked_ioctl(struct file *file, u_int cmd, u_long arg)
|
|||
{
|
||||
int ret;
|
||||
|
||||
lock_kernel();
|
||||
mutex_lock(&dmasound_core_mutex);
|
||||
ret = mixer_ioctl(file, cmd, arg);
|
||||
unlock_kernel();
|
||||
mutex_unlock(&dmasound_core_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -752,9 +753,9 @@ static int sq_open(struct inode *inode, struct file *file)
|
|||
{
|
||||
int rc;
|
||||
|
||||
lock_kernel();
|
||||
mutex_lock(&dmasound_core_mutex);
|
||||
if (!try_module_get(dmasound.mach.owner)) {
|
||||
unlock_kernel();
|
||||
mutex_unlock(&dmasound_core_mutex);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
|
@ -799,11 +800,11 @@ static int sq_open(struct inode *inode, struct file *file)
|
|||
sound_set_format(AFMT_MU_LAW);
|
||||
}
|
||||
#endif
|
||||
unlock_kernel();
|
||||
mutex_unlock(&dmasound_core_mutex);
|
||||
return 0;
|
||||
out:
|
||||
module_put(dmasound.mach.owner);
|
||||
unlock_kernel();
|
||||
mutex_unlock(&dmasound_core_mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
@ -869,7 +870,7 @@ static int sq_release(struct inode *inode, struct file *file)
|
|||
{
|
||||
int rc = 0;
|
||||
|
||||
lock_kernel();
|
||||
mutex_lock(&dmasound_core_mutex);
|
||||
|
||||
if (file->f_mode & FMODE_WRITE) {
|
||||
if (write_sq.busy)
|
||||
|
|
@ -900,7 +901,7 @@ static int sq_release(struct inode *inode, struct file *file)
|
|||
write_sq_wake_up(file); /* checks f_mode */
|
||||
#endif /* blocking open() */
|
||||
|
||||
unlock_kernel();
|
||||
mutex_unlock(&dmasound_core_mutex);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
|
@ -1141,9 +1142,9 @@ static long sq_unlocked_ioctl(struct file *file, u_int cmd, u_long arg)
|
|||
{
|
||||
int ret;
|
||||
|
||||
lock_kernel();
|
||||
mutex_lock(&dmasound_core_mutex);
|
||||
ret = sq_ioctl(file, cmd, arg);
|
||||
unlock_kernel();
|
||||
mutex_unlock(&dmasound_core_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -1257,7 +1258,7 @@ static int state_open(struct inode *inode, struct file *file)
|
|||
int len = 0;
|
||||
int ret;
|
||||
|
||||
lock_kernel();
|
||||
mutex_lock(&dmasound_core_mutex);
|
||||
ret = -EBUSY;
|
||||
if (state.busy)
|
||||
goto out;
|
||||
|
|
@ -1329,16 +1330,16 @@ printk("dmasound: stat buffer used %d bytes\n", len) ;
|
|||
state.len = len;
|
||||
ret = 0;
|
||||
out:
|
||||
unlock_kernel();
|
||||
mutex_unlock(&dmasound_core_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int state_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
lock_kernel();
|
||||
mutex_lock(&dmasound_core_mutex);
|
||||
state.busy = 0;
|
||||
module_put(dmasound.mach.owner);
|
||||
unlock_kernel();
|
||||
mutex_unlock(&dmasound_core_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/gfp.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/io.h>
|
||||
|
|
@ -79,6 +79,7 @@
|
|||
dev.rec_sample_rate / \
|
||||
dev.rec_channels)
|
||||
|
||||
static DEFINE_MUTEX(msnd_pinnacle_mutex);
|
||||
static multisound_dev_t dev;
|
||||
|
||||
#ifndef HAVE_DSPCODEH
|
||||
|
|
@ -651,12 +652,12 @@ static long dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|||
|
||||
ret = -EINVAL;
|
||||
|
||||
lock_kernel();
|
||||
mutex_lock(&msnd_pinnacle_mutex);
|
||||
if (minor == dev.dsp_minor)
|
||||
ret = dsp_ioctl(file, cmd, arg);
|
||||
else if (minor == dev.mixer_minor)
|
||||
ret = mixer_ioctl(cmd, arg);
|
||||
unlock_kernel();
|
||||
mutex_unlock(&msnd_pinnacle_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -761,7 +762,7 @@ static int dev_open(struct inode *inode, struct file *file)
|
|||
int minor = iminor(inode);
|
||||
int err = 0;
|
||||
|
||||
lock_kernel();
|
||||
mutex_lock(&msnd_pinnacle_mutex);
|
||||
if (minor == dev.dsp_minor) {
|
||||
if ((file->f_mode & FMODE_WRITE &&
|
||||
test_bit(F_AUDIO_WRITE_INUSE, &dev.flags)) ||
|
||||
|
|
@ -791,7 +792,7 @@ static int dev_open(struct inode *inode, struct file *file)
|
|||
} else
|
||||
err = -EINVAL;
|
||||
out:
|
||||
unlock_kernel();
|
||||
mutex_unlock(&msnd_pinnacle_mutex);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
@ -800,14 +801,14 @@ static int dev_release(struct inode *inode, struct file *file)
|
|||
int minor = iminor(inode);
|
||||
int err = 0;
|
||||
|
||||
lock_kernel();
|
||||
mutex_lock(&msnd_pinnacle_mutex);
|
||||
if (minor == dev.dsp_minor)
|
||||
err = dsp_release(file);
|
||||
else if (minor == dev.mixer_minor) {
|
||||
/* nothing */
|
||||
} else
|
||||
err = -EINVAL;
|
||||
unlock_kernel();
|
||||
mutex_unlock(&msnd_pinnacle_mutex);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,325 +0,0 @@
|
|||
/*
|
||||
* sound/oss/sh_dac_audio.c
|
||||
*
|
||||
* SH DAC based sound :(
|
||||
*
|
||||
* Copyright (C) 2004,2005 Andriy Skulysh
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file "COPYING" in the main directory of this archive
|
||||
* for more details.
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/sound.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/soundcard.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/hrtimer.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/delay.h>
|
||||
#include <asm/clock.h>
|
||||
#include <cpu/dac.h>
|
||||
#include <asm/machvec.h>
|
||||
#include <mach/hp6xx.h>
|
||||
#include <asm/hd64461.h>
|
||||
|
||||
#define MODNAME "sh_dac_audio"
|
||||
|
||||
#define BUFFER_SIZE 48000
|
||||
|
||||
static int rate;
|
||||
static int empty;
|
||||
static char *data_buffer, *buffer_begin, *buffer_end;
|
||||
static int in_use, device_major;
|
||||
static struct hrtimer hrtimer;
|
||||
static ktime_t wakeups_per_second;
|
||||
|
||||
static void dac_audio_start_timer(void)
|
||||
{
|
||||
hrtimer_start(&hrtimer, wakeups_per_second, HRTIMER_MODE_REL);
|
||||
}
|
||||
|
||||
static void dac_audio_stop_timer(void)
|
||||
{
|
||||
hrtimer_cancel(&hrtimer);
|
||||
}
|
||||
|
||||
static void dac_audio_reset(void)
|
||||
{
|
||||
dac_audio_stop_timer();
|
||||
buffer_begin = buffer_end = data_buffer;
|
||||
empty = 1;
|
||||
}
|
||||
|
||||
static void dac_audio_sync(void)
|
||||
{
|
||||
while (!empty)
|
||||
schedule();
|
||||
}
|
||||
|
||||
static void dac_audio_start(void)
|
||||
{
|
||||
if (mach_is_hp6xx()) {
|
||||
u16 v = __raw_readw(HD64461_GPADR);
|
||||
v &= ~HD64461_GPADR_SPEAKER;
|
||||
__raw_writew(v, HD64461_GPADR);
|
||||
}
|
||||
|
||||
sh_dac_enable(CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL);
|
||||
}
|
||||
static void dac_audio_stop(void)
|
||||
{
|
||||
dac_audio_stop_timer();
|
||||
|
||||
if (mach_is_hp6xx()) {
|
||||
u16 v = __raw_readw(HD64461_GPADR);
|
||||
v |= HD64461_GPADR_SPEAKER;
|
||||
__raw_writew(v, HD64461_GPADR);
|
||||
}
|
||||
|
||||
sh_dac_output(0, CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL);
|
||||
sh_dac_disable(CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL);
|
||||
}
|
||||
|
||||
static void dac_audio_set_rate(void)
|
||||
{
|
||||
wakeups_per_second = ktime_set(0, 1000000000 / rate);
|
||||
}
|
||||
|
||||
static int dac_audio_ioctl(struct file *file,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
int val;
|
||||
|
||||
switch (cmd) {
|
||||
case OSS_GETVERSION:
|
||||
return put_user(SOUND_VERSION, (int *)arg);
|
||||
|
||||
case SNDCTL_DSP_SYNC:
|
||||
dac_audio_sync();
|
||||
return 0;
|
||||
|
||||
case SNDCTL_DSP_RESET:
|
||||
dac_audio_reset();
|
||||
return 0;
|
||||
|
||||
case SNDCTL_DSP_GETFMTS:
|
||||
return put_user(AFMT_U8, (int *)arg);
|
||||
|
||||
case SNDCTL_DSP_SETFMT:
|
||||
return put_user(AFMT_U8, (int *)arg);
|
||||
|
||||
case SNDCTL_DSP_NONBLOCK:
|
||||
spin_lock(&file->f_lock);
|
||||
file->f_flags |= O_NONBLOCK;
|
||||
spin_unlock(&file->f_lock);
|
||||
return 0;
|
||||
|
||||
case SNDCTL_DSP_GETCAPS:
|
||||
return 0;
|
||||
|
||||
case SOUND_PCM_WRITE_RATE:
|
||||
val = *(int *)arg;
|
||||
if (val > 0) {
|
||||
rate = val;
|
||||
dac_audio_set_rate();
|
||||
}
|
||||
return put_user(rate, (int *)arg);
|
||||
|
||||
case SNDCTL_DSP_STEREO:
|
||||
return put_user(0, (int *)arg);
|
||||
|
||||
case SOUND_PCM_WRITE_CHANNELS:
|
||||
return put_user(1, (int *)arg);
|
||||
|
||||
case SNDCTL_DSP_SETDUPLEX:
|
||||
return -EINVAL;
|
||||
|
||||
case SNDCTL_DSP_PROFILE:
|
||||
return -EINVAL;
|
||||
|
||||
case SNDCTL_DSP_GETBLKSIZE:
|
||||
return put_user(BUFFER_SIZE, (int *)arg);
|
||||
|
||||
case SNDCTL_DSP_SETFRAGMENT:
|
||||
return 0;
|
||||
|
||||
default:
|
||||
printk(KERN_ERR "sh_dac_audio: unimplemented ioctl=0x%x\n",
|
||||
cmd);
|
||||
return -EINVAL;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static long dac_audio_unlocked_ioctl(struct file *file, u_int cmd, u_long arg)
|
||||
{
|
||||
int ret;
|
||||
|
||||
lock_kernel();
|
||||
ret = dac_audio_ioctl(file, cmd, arg);
|
||||
unlock_kernel();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t dac_audio_write(struct file *file, const char *buf, size_t count,
|
||||
loff_t * ppos)
|
||||
{
|
||||
int free;
|
||||
int nbytes;
|
||||
|
||||
if (!count) {
|
||||
dac_audio_sync();
|
||||
return 0;
|
||||
}
|
||||
|
||||
free = buffer_begin - buffer_end;
|
||||
|
||||
if (free < 0)
|
||||
free += BUFFER_SIZE;
|
||||
if ((free == 0) && (empty))
|
||||
free = BUFFER_SIZE;
|
||||
if (count > free)
|
||||
count = free;
|
||||
if (buffer_begin > buffer_end) {
|
||||
if (copy_from_user((void *)buffer_end, buf, count))
|
||||
return -EFAULT;
|
||||
|
||||
buffer_end += count;
|
||||
} else {
|
||||
nbytes = data_buffer + BUFFER_SIZE - buffer_end;
|
||||
if (nbytes > count) {
|
||||
if (copy_from_user((void *)buffer_end, buf, count))
|
||||
return -EFAULT;
|
||||
buffer_end += count;
|
||||
} else {
|
||||
if (copy_from_user((void *)buffer_end, buf, nbytes))
|
||||
return -EFAULT;
|
||||
if (copy_from_user
|
||||
((void *)data_buffer, buf + nbytes, count - nbytes))
|
||||
return -EFAULT;
|
||||
buffer_end = data_buffer + count - nbytes;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty) {
|
||||
empty = 0;
|
||||
dac_audio_start_timer();
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t dac_audio_read(struct file *file, char *buf, size_t count,
|
||||
loff_t * ppos)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int dac_audio_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
if (file->f_mode & FMODE_READ)
|
||||
return -ENODEV;
|
||||
|
||||
lock_kernel();
|
||||
if (in_use) {
|
||||
unlock_kernel();
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
in_use = 1;
|
||||
|
||||
dac_audio_start();
|
||||
unlock_kernel();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dac_audio_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
dac_audio_sync();
|
||||
dac_audio_stop();
|
||||
in_use = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct file_operations dac_audio_fops = {
|
||||
.read = dac_audio_read,
|
||||
.write = dac_audio_write,
|
||||
.unlocked_ioctl = dac_audio_unlocked_ioctl,
|
||||
.open = dac_audio_open,
|
||||
.release = dac_audio_release,
|
||||
};
|
||||
|
||||
static enum hrtimer_restart sh_dac_audio_timer(struct hrtimer *handle)
|
||||
{
|
||||
if (!empty) {
|
||||
sh_dac_output(*buffer_begin, CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL);
|
||||
buffer_begin++;
|
||||
|
||||
if (buffer_begin == data_buffer + BUFFER_SIZE)
|
||||
buffer_begin = data_buffer;
|
||||
if (buffer_begin == buffer_end)
|
||||
empty = 1;
|
||||
}
|
||||
|
||||
if (!empty)
|
||||
hrtimer_start(&hrtimer, wakeups_per_second, HRTIMER_MODE_REL);
|
||||
|
||||
return HRTIMER_NORESTART;
|
||||
}
|
||||
|
||||
static int __init dac_audio_init(void)
|
||||
{
|
||||
if ((device_major = register_sound_dsp(&dac_audio_fops, -1)) < 0) {
|
||||
printk(KERN_ERR "Cannot register dsp device");
|
||||
return device_major;
|
||||
}
|
||||
|
||||
in_use = 0;
|
||||
|
||||
data_buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL);
|
||||
if (data_buffer == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
dac_audio_reset();
|
||||
rate = 8000;
|
||||
dac_audio_set_rate();
|
||||
|
||||
/* Today: High Resolution Timer driven DAC playback.
|
||||
* The timer callback gets called once per sample. Ouch.
|
||||
*
|
||||
* Future: A much better approach would be to use the
|
||||
* SH7720 CMT+DMAC+DAC hardware combination like this:
|
||||
* - Program sample rate using CMT0 or CMT1
|
||||
* - Program DMAC to use CMT for timing and output to DAC
|
||||
* - Play sound using DMAC, let CPU sleep.
|
||||
* - While at it, rewrite this driver to use ALSA.
|
||||
*/
|
||||
|
||||
hrtimer_init(&hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
|
||||
hrtimer.function = sh_dac_audio_timer;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit dac_audio_exit(void)
|
||||
{
|
||||
unregister_sound_dsp(device_major);
|
||||
kfree((void *)data_buffer);
|
||||
}
|
||||
|
||||
module_init(dac_audio_init);
|
||||
module_exit(dac_audio_exit);
|
||||
|
||||
MODULE_AUTHOR("Andriy Skulysh, [email protected]");
|
||||
MODULE_DESCRIPTION("SH DAC sound driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
@ -40,7 +40,7 @@
|
|||
#include <linux/major.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/device.h>
|
||||
|
|
@ -56,6 +56,7 @@
|
|||
* Table for permanently allocated memory (used when unloading the module)
|
||||
*/
|
||||
void * sound_mem_blocks[MAX_MEM_BLOCKS];
|
||||
static DEFINE_MUTEX(soundcard_mutex);
|
||||
int sound_nblocks = 0;
|
||||
|
||||
/* Persistent DMA buffers */
|
||||
|
|
@ -151,7 +152,7 @@ static ssize_t sound_read(struct file *file, char __user *buf, size_t count, lof
|
|||
* big one anyway, we might as well bandage here..
|
||||
*/
|
||||
|
||||
lock_kernel();
|
||||
mutex_lock(&soundcard_mutex);
|
||||
|
||||
DEB(printk("sound_read(dev=%d, count=%d)\n", dev, count));
|
||||
switch (dev & 0x0f) {
|
||||
|
|
@ -169,7 +170,7 @@ static ssize_t sound_read(struct file *file, char __user *buf, size_t count, lof
|
|||
case SND_DEV_MIDIN:
|
||||
ret = MIDIbuf_read(dev, file, buf, count);
|
||||
}
|
||||
unlock_kernel();
|
||||
mutex_unlock(&soundcard_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -178,7 +179,7 @@ static ssize_t sound_write(struct file *file, const char __user *buf, size_t cou
|
|||
int dev = iminor(file->f_path.dentry->d_inode);
|
||||
int ret = -EINVAL;
|
||||
|
||||
lock_kernel();
|
||||
mutex_lock(&soundcard_mutex);
|
||||
DEB(printk("sound_write(dev=%d, count=%d)\n", dev, count));
|
||||
switch (dev & 0x0f) {
|
||||
case SND_DEV_SEQ:
|
||||
|
|
@ -196,7 +197,7 @@ static ssize_t sound_write(struct file *file, const char __user *buf, size_t cou
|
|||
ret = MIDIbuf_write(dev, file, buf, count);
|
||||
break;
|
||||
}
|
||||
unlock_kernel();
|
||||
mutex_unlock(&soundcard_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -210,7 +211,7 @@ static int sound_open(struct inode *inode, struct file *file)
|
|||
printk(KERN_ERR "Invalid minor device %d\n", dev);
|
||||
return -ENXIO;
|
||||
}
|
||||
lock_kernel();
|
||||
mutex_lock(&soundcard_mutex);
|
||||
switch (dev & 0x0f) {
|
||||
case SND_DEV_CTL:
|
||||
dev >>= 4;
|
||||
|
|
@ -247,15 +248,15 @@ static int sound_open(struct inode *inode, struct file *file)
|
|||
retval = -ENXIO;
|
||||
}
|
||||
|
||||
unlock_kernel();
|
||||
return 0;
|
||||
mutex_unlock(&soundcard_mutex);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int sound_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
int dev = iminor(inode);
|
||||
|
||||
lock_kernel();
|
||||
mutex_lock(&soundcard_mutex);
|
||||
DEB(printk("sound_release(dev=%d)\n", dev));
|
||||
switch (dev & 0x0f) {
|
||||
case SND_DEV_CTL:
|
||||
|
|
@ -280,7 +281,7 @@ static int sound_release(struct inode *inode, struct file *file)
|
|||
default:
|
||||
printk(KERN_ERR "Sound error: Releasing unknown device 0x%02x\n", dev);
|
||||
}
|
||||
unlock_kernel();
|
||||
mutex_unlock(&soundcard_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -354,7 +355,7 @@ static long sound_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|||
if (cmd == OSS_GETVERSION)
|
||||
return __put_user(SOUND_VERSION, (int __user *)p);
|
||||
|
||||
lock_kernel();
|
||||
mutex_lock(&soundcard_mutex);
|
||||
if (_IOC_TYPE(cmd) == 'M' && num_mixers > 0 && /* Mixer ioctl */
|
||||
(dev & 0x0f) != SND_DEV_CTL) {
|
||||
dtype = dev & 0x0f;
|
||||
|
|
@ -369,7 +370,7 @@ static long sound_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|||
ret = sound_mixer_ioctl(dev >> 4, cmd, p);
|
||||
break;
|
||||
}
|
||||
unlock_kernel();
|
||||
mutex_unlock(&soundcard_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -399,7 +400,7 @@ static long sound_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|||
break;
|
||||
|
||||
}
|
||||
unlock_kernel();
|
||||
mutex_unlock(&soundcard_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -439,35 +440,35 @@ static int sound_mmap(struct file *file, struct vm_area_struct *vma)
|
|||
printk(KERN_ERR "Sound: mmap() not supported for other than audio devices\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
lock_kernel();
|
||||
mutex_lock(&soundcard_mutex);
|
||||
if (vma->vm_flags & VM_WRITE) /* Map write and read/write to the output buf */
|
||||
dmap = audio_devs[dev]->dmap_out;
|
||||
else if (vma->vm_flags & VM_READ)
|
||||
dmap = audio_devs[dev]->dmap_in;
|
||||
else {
|
||||
printk(KERN_ERR "Sound: Undefined mmap() access\n");
|
||||
unlock_kernel();
|
||||
mutex_unlock(&soundcard_mutex);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (dmap == NULL) {
|
||||
printk(KERN_ERR "Sound: mmap() error. dmap == NULL\n");
|
||||
unlock_kernel();
|
||||
mutex_unlock(&soundcard_mutex);
|
||||
return -EIO;
|
||||
}
|
||||
if (dmap->raw_buf == NULL) {
|
||||
printk(KERN_ERR "Sound: mmap() called when raw_buf == NULL\n");
|
||||
unlock_kernel();
|
||||
mutex_unlock(&soundcard_mutex);
|
||||
return -EIO;
|
||||
}
|
||||
if (dmap->mapping_flags) {
|
||||
printk(KERN_ERR "Sound: mmap() called twice for the same DMA buffer\n");
|
||||
unlock_kernel();
|
||||
mutex_unlock(&soundcard_mutex);
|
||||
return -EIO;
|
||||
}
|
||||
if (vma->vm_pgoff != 0) {
|
||||
printk(KERN_ERR "Sound: mmap() offset must be 0.\n");
|
||||
unlock_kernel();
|
||||
mutex_unlock(&soundcard_mutex);
|
||||
return -EINVAL;
|
||||
}
|
||||
size = vma->vm_end - vma->vm_start;
|
||||
|
|
@ -478,7 +479,7 @@ static int sound_mmap(struct file *file, struct vm_area_struct *vma)
|
|||
if (remap_pfn_range(vma, vma->vm_start,
|
||||
virt_to_phys(dmap->raw_buf) >> PAGE_SHIFT,
|
||||
vma->vm_end - vma->vm_start, vma->vm_page_prot)) {
|
||||
unlock_kernel();
|
||||
mutex_unlock(&soundcard_mutex);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
|
|
@ -490,7 +491,7 @@ static int sound_mmap(struct file *file, struct vm_area_struct *vma)
|
|||
memset(dmap->raw_buf,
|
||||
dmap->neutral_byte,
|
||||
dmap->bytes_in_use);
|
||||
unlock_kernel();
|
||||
mutex_unlock(&soundcard_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -68,7 +68,6 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/sound.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/soundcard.h>
|
||||
#include <linux/ac97_codec.h>
|
||||
#include <linux/pci.h>
|
||||
|
|
@ -94,6 +93,7 @@
|
|||
|
||||
struct cs4297a_state;
|
||||
|
||||
static DEFINE_MUTEX(swarm_cs4297a_mutex);
|
||||
static void stop_dac(struct cs4297a_state *s);
|
||||
static void stop_adc(struct cs4297a_state *s);
|
||||
static void start_dac(struct cs4297a_state *s);
|
||||
|
|
@ -1535,7 +1535,7 @@ static int cs4297a_open_mixdev(struct inode *inode, struct file *file)
|
|||
CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4,
|
||||
printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()+\n"));
|
||||
|
||||
lock_kernel();
|
||||
mutex_lock(&swarm_cs4297a_mutex);
|
||||
list_for_each(entry, &cs4297a_devs)
|
||||
{
|
||||
s = list_entry(entry, struct cs4297a_state, list);
|
||||
|
|
@ -1547,7 +1547,7 @@ static int cs4297a_open_mixdev(struct inode *inode, struct file *file)
|
|||
CS_DBGOUT(CS_FUNCTION | CS_OPEN | CS_ERROR, 2,
|
||||
printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()- -ENODEV\n"));
|
||||
|
||||
unlock_kernel();
|
||||
mutex_unlock(&swarm_cs4297a_mutex);
|
||||
return -ENODEV;
|
||||
}
|
||||
VALIDATE_STATE(s);
|
||||
|
|
@ -1555,7 +1555,7 @@ static int cs4297a_open_mixdev(struct inode *inode, struct file *file)
|
|||
|
||||
CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4,
|
||||
printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()- 0\n"));
|
||||
unlock_kernel();
|
||||
mutex_unlock(&swarm_cs4297a_mutex);
|
||||
|
||||
return nonseekable_open(inode, file);
|
||||
}
|
||||
|
|
@ -1575,10 +1575,10 @@ static int cs4297a_ioctl_mixdev(struct file *file,
|
|||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
int ret;
|
||||
lock_kernel();
|
||||
mutex_lock(&swarm_cs4297a_mutex);
|
||||
ret = mixer_ioctl((struct cs4297a_state *) file->private_data, cmd,
|
||||
arg);
|
||||
unlock_kernel();
|
||||
mutex_unlock(&swarm_cs4297a_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -2350,9 +2350,9 @@ static long cs4297a_unlocked_ioctl(struct file *file, u_int cmd, u_long arg)
|
|||
{
|
||||
int ret;
|
||||
|
||||
lock_kernel();
|
||||
mutex_lock(&swarm_cs4297a_mutex);
|
||||
ret = cs4297a_ioctl(file, cmd, arg);
|
||||
unlock_kernel();
|
||||
mutex_unlock(&swarm_cs4297a_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -2509,9 +2509,9 @@ static int cs4297a_open(struct inode *inode, struct file *file)
|
|||
{
|
||||
int ret;
|
||||
|
||||
lock_kernel();
|
||||
mutex_lock(&swarm_cs4297a_mutex);
|
||||
ret = cs4297a_open(inode, file);
|
||||
unlock_kernel();
|
||||
mutex_unlock(&swarm_cs4297a_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -145,7 +145,6 @@
|
|||
#include <linux/init.h>
|
||||
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/mutex.h>
|
||||
|
|
@ -160,6 +159,7 @@
|
|||
|
||||
#ifdef VWSND_DEBUG
|
||||
|
||||
static DEFINE_MUTEX(vwsnd_mutex);
|
||||
static int shut_up = 1;
|
||||
|
||||
/*
|
||||
|
|
@ -2891,11 +2891,11 @@ static long vwsnd_audio_ioctl(struct file *file,
|
|||
vwsnd_dev_t *devc = (vwsnd_dev_t *) file->private_data;
|
||||
int ret;
|
||||
|
||||
lock_kernel();
|
||||
mutex_lock(&vwsnd_mutex);
|
||||
mutex_lock(&devc->io_mutex);
|
||||
ret = vwsnd_audio_do_ioctl(file, cmd, arg);
|
||||
mutex_unlock(&devc->io_mutex);
|
||||
unlock_kernel();
|
||||
mutex_unlock(&vwsnd_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -2922,7 +2922,7 @@ static int vwsnd_audio_open(struct inode *inode, struct file *file)
|
|||
|
||||
DBGE("(inode=0x%p, file=0x%p)\n", inode, file);
|
||||
|
||||
lock_kernel();
|
||||
mutex_lock(&vwsnd_mutex);
|
||||
INC_USE_COUNT;
|
||||
for (devc = vwsnd_dev_list; devc; devc = devc->next_dev)
|
||||
if ((devc->audio_minor & ~0x0F) == (minor & ~0x0F))
|
||||
|
|
@ -2930,7 +2930,7 @@ static int vwsnd_audio_open(struct inode *inode, struct file *file)
|
|||
|
||||
if (devc == NULL) {
|
||||
DEC_USE_COUNT;
|
||||
unlock_kernel();
|
||||
mutex_unlock(&vwsnd_mutex);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
|
@ -2939,13 +2939,13 @@ static int vwsnd_audio_open(struct inode *inode, struct file *file)
|
|||
mutex_unlock(&devc->open_mutex);
|
||||
if (file->f_flags & O_NONBLOCK) {
|
||||
DEC_USE_COUNT;
|
||||
unlock_kernel();
|
||||
mutex_unlock(&vwsnd_mutex);
|
||||
return -EBUSY;
|
||||
}
|
||||
interruptible_sleep_on(&devc->open_wait);
|
||||
if (signal_pending(current)) {
|
||||
DEC_USE_COUNT;
|
||||
unlock_kernel();
|
||||
mutex_unlock(&vwsnd_mutex);
|
||||
return -ERESTARTSYS;
|
||||
}
|
||||
mutex_lock(&devc->open_mutex);
|
||||
|
|
@ -2998,7 +2998,7 @@ static int vwsnd_audio_open(struct inode *inode, struct file *file)
|
|||
|
||||
file->private_data = devc;
|
||||
DBGRV();
|
||||
unlock_kernel();
|
||||
mutex_unlock(&vwsnd_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -3012,7 +3012,7 @@ static int vwsnd_audio_release(struct inode *inode, struct file *file)
|
|||
vwsnd_port_t *wport = NULL, *rport = NULL;
|
||||
int err = 0;
|
||||
|
||||
lock_kernel();
|
||||
mutex_lock(&vwsnd_mutex);
|
||||
mutex_lock(&devc->io_mutex);
|
||||
{
|
||||
DBGEV("(inode=0x%p, file=0x%p)\n", inode, file);
|
||||
|
|
@ -3040,7 +3040,7 @@ static int vwsnd_audio_release(struct inode *inode, struct file *file)
|
|||
wake_up(&devc->open_wait);
|
||||
DEC_USE_COUNT;
|
||||
DBGR();
|
||||
unlock_kernel();
|
||||
mutex_unlock(&vwsnd_mutex);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
@ -3068,18 +3068,18 @@ static int vwsnd_mixer_open(struct inode *inode, struct file *file)
|
|||
DBGEV("(inode=0x%p, file=0x%p)\n", inode, file);
|
||||
|
||||
INC_USE_COUNT;
|
||||
lock_kernel();
|
||||
mutex_lock(&vwsnd_mutex);
|
||||
for (devc = vwsnd_dev_list; devc; devc = devc->next_dev)
|
||||
if (devc->mixer_minor == iminor(inode))
|
||||
break;
|
||||
|
||||
if (devc == NULL) {
|
||||
DEC_USE_COUNT;
|
||||
unlock_kernel();
|
||||
mutex_unlock(&vwsnd_mutex);
|
||||
return -ENODEV;
|
||||
}
|
||||
file->private_data = devc;
|
||||
unlock_kernel();
|
||||
mutex_unlock(&vwsnd_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -3223,7 +3223,7 @@ static long vwsnd_mixer_ioctl(struct file *file,
|
|||
|
||||
DBGEV("(devc=0x%p, cmd=0x%x, arg=0x%lx)\n", devc, cmd, arg);
|
||||
|
||||
lock_kernel();
|
||||
mutex_lock(&vwsnd_mutex);
|
||||
mutex_lock(&devc->mix_mutex);
|
||||
{
|
||||
if ((cmd & ~nrmask) == MIXER_READ(0))
|
||||
|
|
@ -3234,7 +3234,7 @@ static long vwsnd_mixer_ioctl(struct file *file,
|
|||
retval = -EINVAL;
|
||||
}
|
||||
mutex_unlock(&devc->mix_mutex);
|
||||
unlock_kernel();
|
||||
mutex_unlock(&vwsnd_mutex);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -207,12 +207,12 @@ config SND_CMIPCI
|
|||
|
||||
config SND_OXYGEN_LIB
|
||||
tristate
|
||||
select SND_PCM
|
||||
select SND_MPU401_UART
|
||||
|
||||
config SND_OXYGEN
|
||||
tristate "C-Media 8788 (Oxygen)"
|
||||
select SND_OXYGEN_LIB
|
||||
select SND_PCM
|
||||
select SND_MPU401_UART
|
||||
help
|
||||
Say Y here to include support for sound cards based on the
|
||||
C-Media CMI8788 (Oxygen HD Audio) chip:
|
||||
|
|
@ -581,6 +581,8 @@ config SND_HDSPM
|
|||
config SND_HIFIER
|
||||
tristate "TempoTec HiFier Fantasia"
|
||||
select SND_OXYGEN_LIB
|
||||
select SND_PCM
|
||||
select SND_MPU401_UART
|
||||
help
|
||||
Say Y here to include support for the MediaTek/TempoTec HiFier
|
||||
Fantasia sound card.
|
||||
|
|
@ -815,14 +817,17 @@ config SND_VIA82XX_MODEM
|
|||
will be called snd-via82xx-modem.
|
||||
|
||||
config SND_VIRTUOSO
|
||||
tristate "Asus Virtuoso 100/200 (Xonar)"
|
||||
tristate "Asus Virtuoso 66/100/200 (Xonar)"
|
||||
select SND_OXYGEN_LIB
|
||||
select SND_PCM
|
||||
select SND_MPU401_UART
|
||||
select SND_JACK if INPUT=y || INPUT=SND
|
||||
help
|
||||
Say Y here to include support for sound cards based on the
|
||||
Asus AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X,
|
||||
Asus AV66/AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X, DS,
|
||||
Essence ST (Deluxe), and Essence STX.
|
||||
Support for the DS is experimental.
|
||||
Support for the HDAV1.3 (Deluxe) is very experimental.
|
||||
Support for the HDAV1.3 (Deluxe) is incomplete; for the
|
||||
HDAV1.3 Slim and Xense, missing.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called snd-virtuoso.
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ static int __devinit snd_vortex_mixer(vortex_t * vortex)
|
|||
if ((err = snd_ac97_bus(vortex->card, 0, &ops, NULL, &pbus)) < 0)
|
||||
return err;
|
||||
memset(&ac97, 0, sizeof(ac97));
|
||||
// Intialize AC97 codec stuff.
|
||||
// Initialize AC97 codec stuff.
|
||||
ac97.private_data = vortex;
|
||||
ac97.scaps = AC97_SCAP_NO_SPDIF;
|
||||
err = snd_ac97_mixer(pbus, &ac97, &vortex->codec);
|
||||
|
|
|
|||
|
|
@ -670,8 +670,9 @@ struct snd_ca0106_details {
|
|||
gpio_type = 2 -> shared side-out/line-in. */
|
||||
int i2c_adc; /* with i2c_adc=1, the driver adds some capture volume
|
||||
controls, phone, mic, line-in and aux. */
|
||||
int spi_dac; /* spi_dac=1 adds the mute switch for each analog
|
||||
output, front, rear, etc. */
|
||||
u16 spi_dac; /* spi_dac = 0 -> no spi interface for DACs
|
||||
spi_dac = 0x<front><rear><center-lfe><side>
|
||||
-> specifies DAC id for each channel pair. */
|
||||
};
|
||||
|
||||
// definition of the chip-specific record
|
||||
|
|
|
|||
|
|
@ -227,7 +227,7 @@ static struct snd_ca0106_details ca0106_chip_details[] = {
|
|||
.name = "Audigy SE [SB0570]",
|
||||
.gpio_type = 1,
|
||||
.i2c_adc = 1,
|
||||
.spi_dac = 1 } ,
|
||||
.spi_dac = 0x4021 } ,
|
||||
/* New Audigy LS. Has a different DAC. */
|
||||
/* SB0570:
|
||||
* CTRL:CA0106-DAT
|
||||
|
|
@ -238,7 +238,17 @@ static struct snd_ca0106_details ca0106_chip_details[] = {
|
|||
.name = "Audigy SE OEM [SB0570a]",
|
||||
.gpio_type = 1,
|
||||
.i2c_adc = 1,
|
||||
.spi_dac = 1 } ,
|
||||
.spi_dac = 0x4021 } ,
|
||||
/* Sound Blaster 5.1vx
|
||||
* Tested: Playback on front, rear, center/lfe speakers
|
||||
* Not-Tested: Capture
|
||||
*/
|
||||
{ .serial = 0x10041102,
|
||||
.name = "Sound Blaster 5.1vx [SB1070]",
|
||||
.gpio_type = 1,
|
||||
.i2c_adc = 0,
|
||||
.spi_dac = 0x0124
|
||||
} ,
|
||||
/* MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97 */
|
||||
/* SB0438
|
||||
* CTRL:CA0106-DAT
|
||||
|
|
@ -254,7 +264,7 @@ static struct snd_ca0106_details ca0106_chip_details[] = {
|
|||
.name = "MSI K8N Diamond MB",
|
||||
.gpio_type = 2,
|
||||
.i2c_adc = 1,
|
||||
.spi_dac = 1 } ,
|
||||
.spi_dac = 0x4021 } ,
|
||||
/* Giga-byte GA-G1975X mobo
|
||||
* Novell bnc#395807
|
||||
*/
|
||||
|
|
@ -483,16 +493,18 @@ static void snd_ca0106_pcm_free_substream(struct snd_pcm_runtime *runtime)
|
|||
}
|
||||
|
||||
static const int spi_dacd_reg[] = {
|
||||
[PCM_FRONT_CHANNEL] = SPI_DACD4_REG,
|
||||
[PCM_REAR_CHANNEL] = SPI_DACD0_REG,
|
||||
[PCM_CENTER_LFE_CHANNEL]= SPI_DACD2_REG,
|
||||
[PCM_UNKNOWN_CHANNEL] = SPI_DACD1_REG,
|
||||
SPI_DACD0_REG,
|
||||
SPI_DACD1_REG,
|
||||
SPI_DACD2_REG,
|
||||
0,
|
||||
SPI_DACD4_REG,
|
||||
};
|
||||
static const int spi_dacd_bit[] = {
|
||||
[PCM_FRONT_CHANNEL] = SPI_DACD4_BIT,
|
||||
[PCM_REAR_CHANNEL] = SPI_DACD0_BIT,
|
||||
[PCM_CENTER_LFE_CHANNEL]= SPI_DACD2_BIT,
|
||||
[PCM_UNKNOWN_CHANNEL] = SPI_DACD1_BIT,
|
||||
SPI_DACD0_BIT,
|
||||
SPI_DACD1_BIT,
|
||||
SPI_DACD2_BIT,
|
||||
0,
|
||||
SPI_DACD4_BIT,
|
||||
};
|
||||
|
||||
static void restore_spdif_bits(struct snd_ca0106 *chip, int idx)
|
||||
|
|
@ -504,6 +516,45 @@ static void restore_spdif_bits(struct snd_ca0106 *chip, int idx)
|
|||
}
|
||||
}
|
||||
|
||||
static int snd_ca0106_channel_dac(struct snd_ca0106_details *details,
|
||||
int channel_id)
|
||||
{
|
||||
switch (channel_id) {
|
||||
case PCM_FRONT_CHANNEL:
|
||||
return (details->spi_dac & 0xf000) >> (4 * 3);
|
||||
case PCM_REAR_CHANNEL:
|
||||
return (details->spi_dac & 0x0f00) >> (4 * 2);
|
||||
case PCM_CENTER_LFE_CHANNEL:
|
||||
return (details->spi_dac & 0x00f0) >> (4 * 1);
|
||||
case PCM_UNKNOWN_CHANNEL:
|
||||
return (details->spi_dac & 0x000f) >> (4 * 0);
|
||||
default:
|
||||
snd_printk(KERN_DEBUG "ca0106: unknown channel_id %d\n",
|
||||
channel_id);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_ca0106_pcm_power_dac(struct snd_ca0106 *chip, int channel_id,
|
||||
int power)
|
||||
{
|
||||
if (chip->details->spi_dac) {
|
||||
const int dac = snd_ca0106_channel_dac(chip->details,
|
||||
channel_id);
|
||||
const int reg = spi_dacd_reg[dac];
|
||||
const int bit = spi_dacd_bit[dac];
|
||||
|
||||
if (power)
|
||||
/* Power up */
|
||||
chip->spi_dac_reg[reg] &= ~bit;
|
||||
else
|
||||
/* Power down */
|
||||
chip->spi_dac_reg[reg] |= bit;
|
||||
return snd_ca0106_spi_write(chip, chip->spi_dac_reg[reg]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* open_playback callback */
|
||||
static int snd_ca0106_pcm_open_playback_channel(struct snd_pcm_substream *substream,
|
||||
int channel_id)
|
||||
|
|
@ -543,12 +594,9 @@ static int snd_ca0106_pcm_open_playback_channel(struct snd_pcm_substream *substr
|
|||
return err;
|
||||
snd_pcm_set_sync(substream);
|
||||
|
||||
if (chip->details->spi_dac && channel_id != PCM_FRONT_CHANNEL) {
|
||||
const int reg = spi_dacd_reg[channel_id];
|
||||
|
||||
/* Power up dac */
|
||||
chip->spi_dac_reg[reg] &= ~spi_dacd_bit[channel_id];
|
||||
err = snd_ca0106_spi_write(chip, chip->spi_dac_reg[reg]);
|
||||
/* Front channel dac should already be on */
|
||||
if (channel_id != PCM_FRONT_CHANNEL) {
|
||||
err = snd_ca0106_pcm_power_dac(chip, channel_id, 1);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
|
@ -568,13 +616,14 @@ static int snd_ca0106_pcm_close_playback(struct snd_pcm_substream *substream)
|
|||
|
||||
restore_spdif_bits(chip, epcm->channel_id);
|
||||
|
||||
if (chip->details->spi_dac && epcm->channel_id != PCM_FRONT_CHANNEL) {
|
||||
const int reg = spi_dacd_reg[epcm->channel_id];
|
||||
|
||||
/* Power down DAC */
|
||||
chip->spi_dac_reg[reg] |= spi_dacd_bit[epcm->channel_id];
|
||||
snd_ca0106_spi_write(chip, chip->spi_dac_reg[reg]);
|
||||
/* Front channel dac should stay on */
|
||||
if (epcm->channel_id != PCM_FRONT_CHANNEL) {
|
||||
int err;
|
||||
err = snd_ca0106_pcm_power_dac(chip, epcm->channel_id, 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* FIXME: maybe zero others */
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1002,29 +1051,27 @@ snd_ca0106_pcm_pointer_playback(struct snd_pcm_substream *substream)
|
|||
struct snd_ca0106 *emu = snd_pcm_substream_chip(substream);
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct snd_ca0106_pcm *epcm = runtime->private_data;
|
||||
snd_pcm_uframes_t ptr, ptr1, ptr2,ptr3,ptr4 = 0;
|
||||
unsigned int ptr, prev_ptr;
|
||||
int channel = epcm->channel_id;
|
||||
int timeout = 10;
|
||||
|
||||
if (!epcm->running)
|
||||
return 0;
|
||||
|
||||
ptr3 = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel);
|
||||
ptr1 = snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel);
|
||||
ptr4 = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel);
|
||||
if (ptr3 != ptr4) ptr1 = snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel);
|
||||
ptr2 = bytes_to_frames(runtime, ptr1);
|
||||
ptr2+= (ptr4 >> 3) * runtime->period_size;
|
||||
ptr=ptr2;
|
||||
if (ptr >= runtime->buffer_size)
|
||||
ptr -= runtime->buffer_size;
|
||||
/*
|
||||
printk(KERN_DEBUG "ptr1 = 0x%lx, ptr2=0x%lx, ptr=0x%lx, "
|
||||
"buffer_size = 0x%x, period_size = 0x%x, bits=%d, rate=%d\n",
|
||||
ptr1, ptr2, ptr, (int)runtime->buffer_size,
|
||||
(int)runtime->period_size, (int)runtime->frame_bits,
|
||||
(int)runtime->rate);
|
||||
*/
|
||||
return ptr;
|
||||
prev_ptr = -1;
|
||||
do {
|
||||
ptr = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel);
|
||||
ptr = (ptr >> 3) * runtime->period_size;
|
||||
ptr += bytes_to_frames(runtime,
|
||||
snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel));
|
||||
if (ptr >= runtime->buffer_size)
|
||||
ptr -= runtime->buffer_size;
|
||||
if (prev_ptr == ptr)
|
||||
return ptr;
|
||||
prev_ptr = ptr;
|
||||
} while (--timeout);
|
||||
snd_printk(KERN_WARNING "ca0106: unstable DMA pointer!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* pointer_capture callback */
|
||||
|
|
@ -1362,7 +1409,7 @@ static unsigned int spi_dac_init[] = {
|
|||
SPI_REG(12, 0x00),
|
||||
SPI_REG(SPI_LDA4_REG, SPI_DA_BIT_0dB),
|
||||
SPI_REG(SPI_RDA4_REG, SPI_DA_BIT_0dB | SPI_DA_BIT_UPDATE),
|
||||
SPI_REG(SPI_DACD4_REG, 0x00),
|
||||
SPI_REG(SPI_DACD4_REG, SPI_DACD4_BIT),
|
||||
};
|
||||
|
||||
static unsigned int i2c_adc_init[][2] = {
|
||||
|
|
@ -1541,7 +1588,7 @@ static void ca0106_init_chip(struct snd_ca0106 *chip, int resume)
|
|||
/* snd_ca0106_i2c_write(chip, ADC_MUX, ADC_MUX_LINEIN); */
|
||||
}
|
||||
|
||||
if (chip->details->spi_dac == 1) {
|
||||
if (chip->details->spi_dac) {
|
||||
/* The SB0570 use SPI to control DAC. */
|
||||
int size, n;
|
||||
|
||||
|
|
@ -1553,6 +1600,9 @@ static void ca0106_init_chip(struct snd_ca0106 *chip, int resume)
|
|||
if (reg < ARRAY_SIZE(chip->spi_dac_reg))
|
||||
chip->spi_dac_reg[reg] = spi_dac_init[n];
|
||||
}
|
||||
|
||||
/* Enable front dac only */
|
||||
snd_ca0106_pcm_power_dac(chip, PCM_FRONT_CHANNEL, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -676,27 +676,64 @@ static struct snd_kcontrol_new snd_ca0106_volume_i2c_adc_ctls[] __devinitdata =
|
|||
I2C_VOLUME("Aux Capture Volume", 3),
|
||||
};
|
||||
|
||||
#define SPI_SWITCH(xname,reg,bit) \
|
||||
{ \
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
|
||||
.info = spi_mute_info, \
|
||||
.get = spi_mute_get, \
|
||||
.put = spi_mute_put, \
|
||||
.private_value = (reg<<SPI_REG_SHIFT) | (bit) \
|
||||
}
|
||||
|
||||
static struct snd_kcontrol_new snd_ca0106_volume_spi_dac_ctls[]
|
||||
__devinitdata = {
|
||||
SPI_SWITCH("Analog Front Playback Switch",
|
||||
SPI_DMUTE4_REG, SPI_DMUTE4_BIT),
|
||||
SPI_SWITCH("Analog Rear Playback Switch",
|
||||
SPI_DMUTE0_REG, SPI_DMUTE0_BIT),
|
||||
SPI_SWITCH("Analog Center/LFE Playback Switch",
|
||||
SPI_DMUTE2_REG, SPI_DMUTE2_BIT),
|
||||
SPI_SWITCH("Analog Side Playback Switch",
|
||||
SPI_DMUTE1_REG, SPI_DMUTE1_BIT),
|
||||
static const int spi_dmute_reg[] = {
|
||||
SPI_DMUTE0_REG,
|
||||
SPI_DMUTE1_REG,
|
||||
SPI_DMUTE2_REG,
|
||||
0,
|
||||
SPI_DMUTE4_REG,
|
||||
};
|
||||
static const int spi_dmute_bit[] = {
|
||||
SPI_DMUTE0_BIT,
|
||||
SPI_DMUTE1_BIT,
|
||||
SPI_DMUTE2_BIT,
|
||||
0,
|
||||
SPI_DMUTE4_BIT,
|
||||
};
|
||||
|
||||
static struct snd_kcontrol_new __devinit
|
||||
snd_ca0106_volume_spi_dac_ctl(struct snd_ca0106_details *details,
|
||||
int channel_id)
|
||||
{
|
||||
struct snd_kcontrol_new spi_switch = {0};
|
||||
int reg, bit;
|
||||
int dac_id;
|
||||
|
||||
spi_switch.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
|
||||
spi_switch.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
|
||||
spi_switch.info = spi_mute_info;
|
||||
spi_switch.get = spi_mute_get;
|
||||
spi_switch.put = spi_mute_put;
|
||||
|
||||
switch (channel_id) {
|
||||
case PCM_FRONT_CHANNEL:
|
||||
spi_switch.name = "Analog Front Playback Switch";
|
||||
dac_id = (details->spi_dac & 0xf000) >> (4 * 3);
|
||||
break;
|
||||
case PCM_REAR_CHANNEL:
|
||||
spi_switch.name = "Analog Rear Playback Switch";
|
||||
dac_id = (details->spi_dac & 0x0f00) >> (4 * 2);
|
||||
break;
|
||||
case PCM_CENTER_LFE_CHANNEL:
|
||||
spi_switch.name = "Analog Center/LFE Playback Switch";
|
||||
dac_id = (details->spi_dac & 0x00f0) >> (4 * 1);
|
||||
break;
|
||||
case PCM_UNKNOWN_CHANNEL:
|
||||
spi_switch.name = "Analog Side Playback Switch";
|
||||
dac_id = (details->spi_dac & 0x000f) >> (4 * 0);
|
||||
break;
|
||||
default:
|
||||
/* Unused channel */
|
||||
spi_switch.name = NULL;
|
||||
dac_id = 0;
|
||||
}
|
||||
reg = spi_dmute_reg[dac_id];
|
||||
bit = spi_dmute_bit[dac_id];
|
||||
|
||||
spi_switch.private_value = (reg << SPI_REG_SHIFT) | bit;
|
||||
|
||||
return spi_switch;
|
||||
}
|
||||
|
||||
static int __devinit remove_ctl(struct snd_card *card, const char *name)
|
||||
{
|
||||
|
|
@ -832,8 +869,18 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu)
|
|||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
if (emu->details->spi_dac == 1)
|
||||
ADD_CTLS(emu, snd_ca0106_volume_spi_dac_ctls);
|
||||
if (emu->details->spi_dac) {
|
||||
int i;
|
||||
for (i = 0;; i++) {
|
||||
struct snd_kcontrol_new ctl;
|
||||
ctl = snd_ca0106_volume_spi_dac_ctl(emu->details, i);
|
||||
if (!ctl.name)
|
||||
break;
|
||||
err = snd_ctl_add(card, snd_ctl_new1(&ctl, emu));
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
/* Create virtual master controls */
|
||||
vmaster = snd_ctl_make_virtual_master("Master Playback Volume",
|
||||
|
|
@ -845,7 +892,7 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu)
|
|||
return err;
|
||||
add_slaves(card, vmaster, slave_vols);
|
||||
|
||||
if (emu->details->spi_dac == 1) {
|
||||
if (emu->details->spi_dac) {
|
||||
vmaster = snd_ctl_make_virtual_master("Master Playback Switch",
|
||||
NULL);
|
||||
if (!vmaster)
|
||||
|
|
|
|||
|
|
@ -321,7 +321,7 @@ static struct snd_rawmidi_ops snd_emu10k1_midi_input =
|
|||
|
||||
static void snd_emu10k1_midi_free(struct snd_rawmidi *rmidi)
|
||||
{
|
||||
struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)rmidi->private_data;
|
||||
struct snd_emu10k1_midi *midi = rmidi->private_data;
|
||||
midi->interrupt = NULL;
|
||||
midi->rmidi = NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -119,47 +119,20 @@ config SND_HDA_CODEC_VIA
|
|||
snd-hda-codec-via.
|
||||
This module is automatically loaded at probing.
|
||||
|
||||
config SND_HDA_CODEC_ATIHDMI
|
||||
bool "Build ATI HDMI HD-audio codec support"
|
||||
default y
|
||||
help
|
||||
Say Y here to include ATI HDMI HD-audio codec support in
|
||||
snd-hda-intel driver, such as ATI RS600 HDMI.
|
||||
|
||||
When the HD-audio driver is built as a module, the codec
|
||||
support code is also built as another module,
|
||||
snd-hda-codec-atihdmi.
|
||||
This module is automatically loaded at probing.
|
||||
|
||||
config SND_HDA_CODEC_NVHDMI
|
||||
bool "Build NVIDIA HDMI HD-audio codec support"
|
||||
default y
|
||||
help
|
||||
Say Y here to include NVIDIA HDMI HD-audio codec support in
|
||||
snd-hda-intel driver, such as NVIDIA MCP78 HDMI.
|
||||
|
||||
When the HD-audio driver is built as a module, the codec
|
||||
support code is also built as another module,
|
||||
snd-hda-codec-nvhdmi.
|
||||
This module is automatically loaded at probing.
|
||||
|
||||
config SND_HDA_CODEC_INTELHDMI
|
||||
bool "Build INTEL HDMI HD-audio codec support"
|
||||
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 INTEL HDMI HD-audio codec support in
|
||||
snd-hda-intel driver, such as Eaglelake integrated HDMI.
|
||||
Say Y here to include HDMI and DisplayPort HD-audio codec
|
||||
support in snd-hda-intel driver. This includes all AMD/ATI,
|
||||
Intel and Nvidia HDMI/DisplayPort codecs.
|
||||
|
||||
When the HD-audio driver is built as a module, the codec
|
||||
support code is also built as another module,
|
||||
snd-hda-codec-intelhdmi.
|
||||
snd-hda-codec-hdmi.
|
||||
This module is automatically loaded at probing.
|
||||
|
||||
config SND_HDA_ELD
|
||||
def_bool y
|
||||
depends on SND_HDA_CODEC_INTELHDMI || SND_HDA_CODEC_NVHDMI
|
||||
|
||||
config SND_HDA_CODEC_CIRRUS
|
||||
bool "Build Cirrus Logic codec support"
|
||||
depends on SND_HDA_INTEL
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ snd-hda-intel-objs := hda_intel.o
|
|||
snd-hda-codec-y := hda_codec.o
|
||||
snd-hda-codec-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o
|
||||
snd-hda-codec-$(CONFIG_PROC_FS) += hda_proc.o
|
||||
snd-hda-codec-$(CONFIG_SND_HDA_ELD) += hda_eld.o
|
||||
snd-hda-codec-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o
|
||||
snd-hda-codec-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o
|
||||
|
||||
|
|
@ -12,13 +11,11 @@ snd-hda-codec-cmedia-objs := patch_cmedia.o
|
|||
snd-hda-codec-analog-objs := patch_analog.o
|
||||
snd-hda-codec-idt-objs := patch_sigmatel.o
|
||||
snd-hda-codec-si3054-objs := patch_si3054.o
|
||||
snd-hda-codec-atihdmi-objs := patch_atihdmi.o
|
||||
snd-hda-codec-cirrus-objs := patch_cirrus.o
|
||||
snd-hda-codec-ca0110-objs := patch_ca0110.o
|
||||
snd-hda-codec-conexant-objs := patch_conexant.o
|
||||
snd-hda-codec-via-objs := patch_via.o
|
||||
snd-hda-codec-nvhdmi-objs := patch_nvhdmi.o
|
||||
snd-hda-codec-intelhdmi-objs := patch_intelhdmi.o
|
||||
snd-hda-codec-hdmi-objs := patch_hdmi.o hda_eld.o
|
||||
|
||||
# common driver
|
||||
obj-$(CONFIG_SND_HDA_INTEL) := snd-hda-codec.o
|
||||
|
|
@ -39,9 +36,6 @@ endif
|
|||
ifdef CONFIG_SND_HDA_CODEC_SI3054
|
||||
obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-si3054.o
|
||||
endif
|
||||
ifdef CONFIG_SND_HDA_CODEC_ATIHDMI
|
||||
obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-atihdmi.o
|
||||
endif
|
||||
ifdef CONFIG_SND_HDA_CODEC_CIRRUS
|
||||
obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-cirrus.o
|
||||
endif
|
||||
|
|
@ -54,11 +48,8 @@ endif
|
|||
ifdef CONFIG_SND_HDA_CODEC_VIA
|
||||
obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-via.o
|
||||
endif
|
||||
ifdef CONFIG_SND_HDA_CODEC_NVHDMI
|
||||
obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-nvhdmi.o
|
||||
endif
|
||||
ifdef CONFIG_SND_HDA_CODEC_INTELHDMI
|
||||
obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-intelhdmi.o
|
||||
ifdef CONFIG_SND_HDA_CODEC_HDMI
|
||||
obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-hdmi.o
|
||||
endif
|
||||
|
||||
# this must be the last entry after codec drivers;
|
||||
|
|
|
|||
|
|
@ -1216,6 +1216,7 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid,
|
|||
struct hda_codec *c;
|
||||
struct hda_cvt_setup *p;
|
||||
unsigned int oldval, newval;
|
||||
int type;
|
||||
int i;
|
||||
|
||||
if (!nid)
|
||||
|
|
@ -1254,10 +1255,12 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid,
|
|||
p->dirty = 0;
|
||||
|
||||
/* make other inactive cvts with the same stream-tag dirty */
|
||||
type = get_wcaps_type(get_wcaps(codec, nid));
|
||||
list_for_each_entry(c, &codec->bus->codec_list, list) {
|
||||
for (i = 0; i < c->cvt_setups.used; i++) {
|
||||
p = snd_array_elem(&c->cvt_setups, i);
|
||||
if (!p->active && p->stream_tag == stream_tag)
|
||||
if (!p->active && p->stream_tag == stream_tag &&
|
||||
get_wcaps_type(get_wcaps(codec, p->nid)) == type)
|
||||
p->dirty = 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -1281,6 +1284,9 @@ void __snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid,
|
|||
if (!nid)
|
||||
return;
|
||||
|
||||
if (codec->no_sticky_stream)
|
||||
do_now = 1;
|
||||
|
||||
snd_printdd("hda_codec_cleanup_stream: NID=0x%x\n", nid);
|
||||
p = get_hda_cvt_setup(codec, nid);
|
||||
if (p) {
|
||||
|
|
@ -1831,6 +1837,7 @@ int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag,
|
|||
hda_nid_t nid = get_amp_nid(kcontrol);
|
||||
int dir = get_amp_direction(kcontrol);
|
||||
unsigned int ofs = get_amp_offset(kcontrol);
|
||||
bool min_mute = get_amp_min_mute(kcontrol);
|
||||
u32 caps, val1, val2;
|
||||
|
||||
if (size < 4 * sizeof(unsigned int))
|
||||
|
|
@ -1841,6 +1848,8 @@ int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag,
|
|||
val1 = -((caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT);
|
||||
val1 += ofs;
|
||||
val1 = ((int)val1) * ((int)val2);
|
||||
if (min_mute)
|
||||
val2 |= TLV_DB_SCALE_MUTE;
|
||||
if (put_user(SNDRV_CTL_TLVT_DB_SCALE, _tlv))
|
||||
return -EFAULT;
|
||||
if (put_user(2 * sizeof(unsigned int), _tlv + 1))
|
||||
|
|
@ -2228,10 +2237,7 @@ int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol,
|
|||
change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx,
|
||||
HDA_AMP_MUTE,
|
||||
*valp ? 0 : HDA_AMP_MUTE);
|
||||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
if (codec->patch_ops.check_power_status)
|
||||
codec->patch_ops.check_power_status(codec, nid);
|
||||
#endif
|
||||
hda_call_check_power_status(codec, nid);
|
||||
snd_hda_power_down(codec);
|
||||
return change;
|
||||
}
|
||||
|
|
@ -4372,6 +4378,34 @@ static void sort_pins_by_sequence(hda_nid_t *pins, short *sequences,
|
|||
}
|
||||
|
||||
|
||||
/* add the found input-pin to the cfg->inputs[] table */
|
||||
static void add_auto_cfg_input_pin(struct auto_pin_cfg *cfg, hda_nid_t nid,
|
||||
int type)
|
||||
{
|
||||
if (cfg->num_inputs < AUTO_CFG_MAX_INS) {
|
||||
cfg->inputs[cfg->num_inputs].pin = nid;
|
||||
cfg->inputs[cfg->num_inputs].type = type;
|
||||
cfg->num_inputs++;
|
||||
}
|
||||
}
|
||||
|
||||
/* sort inputs in the order of AUTO_PIN_* type */
|
||||
static void sort_autocfg_input_pins(struct auto_pin_cfg *cfg)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < cfg->num_inputs; i++) {
|
||||
for (j = i + 1; j < cfg->num_inputs; j++) {
|
||||
if (cfg->inputs[i].type > cfg->inputs[j].type) {
|
||||
struct auto_pin_cfg_item tmp;
|
||||
tmp = cfg->inputs[i];
|
||||
cfg->inputs[i] = cfg->inputs[j];
|
||||
cfg->inputs[j] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse all pin widgets and store the useful pin nids to cfg
|
||||
*
|
||||
|
|
@ -4385,7 +4419,7 @@ static void sort_pins_by_sequence(hda_nid_t *pins, short *sequences,
|
|||
* output, i.e. to line_out_pins[0]. So, line_outs is always positive
|
||||
* if any analog output exists.
|
||||
*
|
||||
* The analog input pins are assigned to input_pins array.
|
||||
* The analog input pins are assigned to inputs array.
|
||||
* The digital input/output pins are assigned to dig_in_pin and dig_out_pin,
|
||||
* respectively.
|
||||
*/
|
||||
|
|
@ -4398,6 +4432,7 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
|
|||
short sequences_line_out[ARRAY_SIZE(cfg->line_out_pins)];
|
||||
short sequences_speaker[ARRAY_SIZE(cfg->speaker_pins)];
|
||||
short sequences_hp[ARRAY_SIZE(cfg->hp_pins)];
|
||||
int i;
|
||||
|
||||
memset(cfg, 0, sizeof(*cfg));
|
||||
|
||||
|
|
@ -4468,33 +4503,17 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
|
|||
sequences_hp[cfg->hp_outs] = (assoc << 4) | seq;
|
||||
cfg->hp_outs++;
|
||||
break;
|
||||
case AC_JACK_MIC_IN: {
|
||||
int preferred, alt;
|
||||
if (loc == AC_JACK_LOC_FRONT ||
|
||||
(loc & 0x30) == AC_JACK_LOC_INTERNAL) {
|
||||
preferred = AUTO_PIN_FRONT_MIC;
|
||||
alt = AUTO_PIN_MIC;
|
||||
} else {
|
||||
preferred = AUTO_PIN_MIC;
|
||||
alt = AUTO_PIN_FRONT_MIC;
|
||||
}
|
||||
if (!cfg->input_pins[preferred])
|
||||
cfg->input_pins[preferred] = nid;
|
||||
else if (!cfg->input_pins[alt])
|
||||
cfg->input_pins[alt] = nid;
|
||||
case AC_JACK_MIC_IN:
|
||||
add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_MIC);
|
||||
break;
|
||||
}
|
||||
case AC_JACK_LINE_IN:
|
||||
if (loc == AC_JACK_LOC_FRONT)
|
||||
cfg->input_pins[AUTO_PIN_FRONT_LINE] = nid;
|
||||
else
|
||||
cfg->input_pins[AUTO_PIN_LINE] = nid;
|
||||
add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_LINE_IN);
|
||||
break;
|
||||
case AC_JACK_CD:
|
||||
cfg->input_pins[AUTO_PIN_CD] = nid;
|
||||
add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_CD);
|
||||
break;
|
||||
case AC_JACK_AUX:
|
||||
cfg->input_pins[AUTO_PIN_AUX] = nid;
|
||||
add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_AUX);
|
||||
break;
|
||||
case AC_JACK_SPDIF_OUT:
|
||||
case AC_JACK_DIG_OTHER_OUT:
|
||||
|
|
@ -4539,6 +4558,8 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
|
|||
memmove(sequences_hp + i, sequences_hp + i + 1,
|
||||
sizeof(sequences_hp[0]) * (cfg->hp_outs - i));
|
||||
}
|
||||
memset(cfg->hp_pins + cfg->hp_outs, 0,
|
||||
sizeof(hda_nid_t) * (AUTO_CFG_MAX_OUTS - cfg->hp_outs));
|
||||
}
|
||||
|
||||
/* sort by sequence */
|
||||
|
|
@ -4549,21 +4570,6 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
|
|||
sort_pins_by_sequence(cfg->hp_pins, sequences_hp,
|
||||
cfg->hp_outs);
|
||||
|
||||
/* if we have only one mic, make it AUTO_PIN_MIC */
|
||||
if (!cfg->input_pins[AUTO_PIN_MIC] &&
|
||||
cfg->input_pins[AUTO_PIN_FRONT_MIC]) {
|
||||
cfg->input_pins[AUTO_PIN_MIC] =
|
||||
cfg->input_pins[AUTO_PIN_FRONT_MIC];
|
||||
cfg->input_pins[AUTO_PIN_FRONT_MIC] = 0;
|
||||
}
|
||||
/* ditto for line-in */
|
||||
if (!cfg->input_pins[AUTO_PIN_LINE] &&
|
||||
cfg->input_pins[AUTO_PIN_FRONT_LINE]) {
|
||||
cfg->input_pins[AUTO_PIN_LINE] =
|
||||
cfg->input_pins[AUTO_PIN_FRONT_LINE];
|
||||
cfg->input_pins[AUTO_PIN_FRONT_LINE] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* FIX-UP: if no line-outs are detected, try to use speaker or HP pin
|
||||
* as a primary output
|
||||
|
|
@ -4602,6 +4608,8 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
|
|||
break;
|
||||
}
|
||||
|
||||
sort_autocfg_input_pins(cfg);
|
||||
|
||||
/*
|
||||
* debug prints of the parsed results
|
||||
*/
|
||||
|
|
@ -4621,14 +4629,13 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
|
|||
if (cfg->dig_outs)
|
||||
snd_printd(" dig-out=0x%x/0x%x\n",
|
||||
cfg->dig_out_pins[0], cfg->dig_out_pins[1]);
|
||||
snd_printd(" inputs: mic=0x%x, fmic=0x%x, line=0x%x, fline=0x%x,"
|
||||
" cd=0x%x, aux=0x%x\n",
|
||||
cfg->input_pins[AUTO_PIN_MIC],
|
||||
cfg->input_pins[AUTO_PIN_FRONT_MIC],
|
||||
cfg->input_pins[AUTO_PIN_LINE],
|
||||
cfg->input_pins[AUTO_PIN_FRONT_LINE],
|
||||
cfg->input_pins[AUTO_PIN_CD],
|
||||
cfg->input_pins[AUTO_PIN_AUX]);
|
||||
snd_printd(" inputs:");
|
||||
for (i = 0; i < cfg->num_inputs; i++) {
|
||||
snd_printdd(" %s=0x%x",
|
||||
hda_get_autocfg_input_label(codec, cfg, i),
|
||||
cfg->inputs[i].pin);
|
||||
}
|
||||
snd_printd("\n");
|
||||
if (cfg->dig_in_pin)
|
||||
snd_printd(" dig-in=0x%x\n", cfg->dig_in_pin);
|
||||
|
||||
|
|
@ -4636,11 +4643,165 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
|
|||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_parse_pin_def_config);
|
||||
|
||||
/* labels for input pins */
|
||||
const char *auto_pin_cfg_labels[AUTO_PIN_LAST] = {
|
||||
"Mic", "Front Mic", "Line", "Front Line", "CD", "Aux"
|
||||
};
|
||||
EXPORT_SYMBOL_HDA(auto_pin_cfg_labels);
|
||||
int snd_hda_get_input_pin_attr(unsigned int def_conf)
|
||||
{
|
||||
unsigned int loc = get_defcfg_location(def_conf);
|
||||
unsigned int conn = get_defcfg_connect(def_conf);
|
||||
if (conn == AC_JACK_PORT_NONE)
|
||||
return INPUT_PIN_ATTR_UNUSED;
|
||||
/* Windows may claim the internal mic to be BOTH, too */
|
||||
if (conn == AC_JACK_PORT_FIXED || conn == AC_JACK_PORT_BOTH)
|
||||
return INPUT_PIN_ATTR_INT;
|
||||
if ((loc & 0x30) == AC_JACK_LOC_INTERNAL)
|
||||
return INPUT_PIN_ATTR_INT;
|
||||
if ((loc & 0x30) == AC_JACK_LOC_SEPARATE)
|
||||
return INPUT_PIN_ATTR_DOCK;
|
||||
if (loc == AC_JACK_LOC_REAR)
|
||||
return INPUT_PIN_ATTR_REAR;
|
||||
if (loc == AC_JACK_LOC_FRONT)
|
||||
return INPUT_PIN_ATTR_FRONT;
|
||||
return INPUT_PIN_ATTR_NORMAL;
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_get_input_pin_attr);
|
||||
|
||||
/**
|
||||
* hda_get_input_pin_label - Give a label for the given input pin
|
||||
*
|
||||
* When check_location is true, the function checks the pin location
|
||||
* for mic and line-in pins, and set an appropriate prefix like "Front",
|
||||
* "Rear", "Internal".
|
||||
*/
|
||||
|
||||
const char *hda_get_input_pin_label(struct hda_codec *codec, hda_nid_t pin,
|
||||
int check_location)
|
||||
{
|
||||
unsigned int def_conf;
|
||||
static const char *mic_names[] = {
|
||||
"Internal Mic", "Dock Mic", "Mic", "Front Mic", "Rear Mic",
|
||||
};
|
||||
int attr;
|
||||
|
||||
def_conf = snd_hda_codec_get_pincfg(codec, pin);
|
||||
|
||||
switch (get_defcfg_device(def_conf)) {
|
||||
case AC_JACK_MIC_IN:
|
||||
if (!check_location)
|
||||
return "Mic";
|
||||
attr = snd_hda_get_input_pin_attr(def_conf);
|
||||
if (!attr)
|
||||
return "None";
|
||||
return mic_names[attr - 1];
|
||||
case AC_JACK_LINE_IN:
|
||||
if (!check_location)
|
||||
return "Line";
|
||||
attr = snd_hda_get_input_pin_attr(def_conf);
|
||||
if (!attr)
|
||||
return "None";
|
||||
if (attr == INPUT_PIN_ATTR_DOCK)
|
||||
return "Dock Line";
|
||||
return "Line";
|
||||
case AC_JACK_AUX:
|
||||
return "Aux";
|
||||
case AC_JACK_CD:
|
||||
return "CD";
|
||||
case AC_JACK_SPDIF_IN:
|
||||
return "SPDIF In";
|
||||
case AC_JACK_DIG_OTHER_IN:
|
||||
return "Digital In";
|
||||
default:
|
||||
return "Misc";
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(hda_get_input_pin_label);
|
||||
|
||||
/* Check whether the location prefix needs to be added to the label.
|
||||
* If all mic-jacks are in the same location (e.g. rear panel), we don't
|
||||
* have to put "Front" prefix to each label. In such a case, returns false.
|
||||
*/
|
||||
static int check_mic_location_need(struct hda_codec *codec,
|
||||
const struct auto_pin_cfg *cfg,
|
||||
int input)
|
||||
{
|
||||
unsigned int defc;
|
||||
int i, attr, attr2;
|
||||
|
||||
defc = snd_hda_codec_get_pincfg(codec, cfg->inputs[input].pin);
|
||||
attr = snd_hda_get_input_pin_attr(defc);
|
||||
/* for internal or docking mics, we need locations */
|
||||
if (attr <= INPUT_PIN_ATTR_NORMAL)
|
||||
return 1;
|
||||
|
||||
attr = 0;
|
||||
for (i = 0; i < cfg->num_inputs; i++) {
|
||||
defc = snd_hda_codec_get_pincfg(codec, cfg->inputs[i].pin);
|
||||
attr2 = snd_hda_get_input_pin_attr(defc);
|
||||
if (attr2 >= INPUT_PIN_ATTR_NORMAL) {
|
||||
if (attr && attr != attr2)
|
||||
return 1; /* different locations found */
|
||||
attr = attr2;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* hda_get_autocfg_input_label - Get a label for the given input
|
||||
*
|
||||
* Get a label for the given input pin defined by the autocfg item.
|
||||
* Unlike hda_get_input_pin_label(), this function checks all inputs
|
||||
* defined in autocfg and avoids the redundant mic/line prefix as much as
|
||||
* possible.
|
||||
*/
|
||||
const char *hda_get_autocfg_input_label(struct hda_codec *codec,
|
||||
const struct auto_pin_cfg *cfg,
|
||||
int input)
|
||||
{
|
||||
int type = cfg->inputs[input].type;
|
||||
int has_multiple_pins = 0;
|
||||
|
||||
if ((input > 0 && cfg->inputs[input - 1].type == type) ||
|
||||
(input < cfg->num_inputs - 1 && cfg->inputs[input + 1].type == type))
|
||||
has_multiple_pins = 1;
|
||||
if (has_multiple_pins && type == AUTO_PIN_MIC)
|
||||
has_multiple_pins &= check_mic_location_need(codec, cfg, input);
|
||||
return hda_get_input_pin_label(codec, cfg->inputs[input].pin,
|
||||
has_multiple_pins);
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(hda_get_autocfg_input_label);
|
||||
|
||||
/**
|
||||
* snd_hda_add_imux_item - Add an item to input_mux
|
||||
*
|
||||
* When the same label is used already in the existing items, the number
|
||||
* suffix is appended to the label. This label index number is stored
|
||||
* to type_idx when non-NULL pointer is given.
|
||||
*/
|
||||
int snd_hda_add_imux_item(struct hda_input_mux *imux, const char *label,
|
||||
int index, int *type_idx)
|
||||
{
|
||||
int i, label_idx = 0;
|
||||
if (imux->num_items >= HDA_MAX_NUM_INPUTS) {
|
||||
snd_printd(KERN_ERR "hda_codec: Too many imux items!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
for (i = 0; i < imux->num_items; i++) {
|
||||
if (!strncmp(label, imux->items[i].label, strlen(label)))
|
||||
label_idx++;
|
||||
}
|
||||
if (type_idx)
|
||||
*type_idx = label_idx;
|
||||
if (label_idx > 0)
|
||||
snprintf(imux->items[imux->num_items].label,
|
||||
sizeof(imux->items[imux->num_items].label),
|
||||
"%s %d", label, label_idx);
|
||||
else
|
||||
strlcpy(imux->items[imux->num_items].label, label,
|
||||
sizeof(imux->items[imux->num_items].label));
|
||||
imux->items[imux->num_items].index = index;
|
||||
imux->num_items++;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_add_imux_item);
|
||||
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
|
|
|||
|
|
@ -850,6 +850,7 @@ struct hda_codec {
|
|||
unsigned int pin_amp_workaround:1; /* pin out-amp takes index
|
||||
* (e.g. Conexant codecs)
|
||||
*/
|
||||
unsigned int no_sticky_stream:1; /* no sticky-PCM stream assignment */
|
||||
unsigned int pins_shutup:1; /* pins are shut up */
|
||||
unsigned int no_trigger_sense:1; /* don't trigger at pin-sensing */
|
||||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
|
|
@ -989,6 +990,18 @@ int snd_hda_suspend(struct hda_bus *bus);
|
|||
int snd_hda_resume(struct hda_bus *bus);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
static inline
|
||||
int hda_call_check_power_status(struct hda_codec *codec, hda_nid_t nid)
|
||||
{
|
||||
if (codec->patch_ops.check_power_status)
|
||||
return codec->patch_ops.check_power_status(codec, nid);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define hda_call_check_power_status(codec, nid) 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* get widget information
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -332,7 +332,6 @@ int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid)
|
|||
return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE,
|
||||
AC_DIPSIZE_ELD_BUF);
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hdmi_get_eld_size);
|
||||
|
||||
int snd_hdmi_get_eld(struct hdmi_eld *eld,
|
||||
struct hda_codec *codec, hda_nid_t nid)
|
||||
|
|
@ -368,7 +367,6 @@ int snd_hdmi_get_eld(struct hdmi_eld *eld,
|
|||
kfree(buf);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hdmi_get_eld);
|
||||
|
||||
static void hdmi_show_short_audio_desc(struct cea_sad *a)
|
||||
{
|
||||
|
|
@ -407,7 +405,6 @@ void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen)
|
|||
}
|
||||
buf[j] = '\0'; /* necessary when j == 0 */
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_print_channel_allocation);
|
||||
|
||||
void snd_hdmi_show_eld(struct hdmi_eld *e)
|
||||
{
|
||||
|
|
@ -426,7 +423,6 @@ void snd_hdmi_show_eld(struct hdmi_eld *e)
|
|||
for (i = 0; i < e->sad_count; i++)
|
||||
hdmi_show_short_audio_desc(e->sad + i);
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hdmi_show_eld);
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
|
||||
|
|
@ -585,7 +581,6 @@ int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld,
|
|||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_eld_proc_new);
|
||||
|
||||
void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld)
|
||||
{
|
||||
|
|
@ -594,7 +589,6 @@ void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld)
|
|||
eld->proc_entry = NULL;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_eld_proc_free);
|
||||
|
||||
#endif /* CONFIG_PROC_FS */
|
||||
|
||||
|
|
@ -645,4 +639,3 @@ void hdmi_eld_update_pcm_info(struct hdmi_eld *eld, struct hda_pcm_stream *pcm,
|
|||
pcm->channels_max = min(pcm->channels_max, codec_pars->channels_max);
|
||||
pcm->maxbps = min(pcm->maxbps, codec_pars->maxbps);
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(hdmi_eld_update_pcm_info);
|
||||
|
|
|
|||
|
|
@ -61,7 +61,6 @@ struct hda_gspec {
|
|||
struct hda_gnode *cap_vol_node; /* Node for capture volume */
|
||||
unsigned int cur_cap_src; /* current capture source */
|
||||
struct hda_input_mux input_mux;
|
||||
char cap_labels[HDA_MAX_NUM_INPUTS][16];
|
||||
|
||||
unsigned int def_amp_in_caps;
|
||||
unsigned int def_amp_out_caps;
|
||||
|
|
@ -506,11 +505,10 @@ static const char *get_input_type(struct hda_gnode *node, unsigned int *pinctl)
|
|||
* returns 0 if not found, 1 if found, or a negative error code.
|
||||
*/
|
||||
static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec,
|
||||
struct hda_gnode *node)
|
||||
struct hda_gnode *node, int idx)
|
||||
{
|
||||
int i, err;
|
||||
unsigned int pinctl;
|
||||
char *label;
|
||||
const char *type;
|
||||
|
||||
if (node->checked)
|
||||
|
|
@ -523,7 +521,7 @@ static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec,
|
|||
child = hda_get_node(spec, node->conn_list[i]);
|
||||
if (! child)
|
||||
continue;
|
||||
err = parse_adc_sub_nodes(codec, spec, child);
|
||||
err = parse_adc_sub_nodes(codec, spec, child, idx);
|
||||
if (err < 0)
|
||||
return err;
|
||||
if (err > 0) {
|
||||
|
|
@ -564,9 +562,7 @@ static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec,
|
|||
return 0;
|
||||
type = "Input";
|
||||
}
|
||||
label = spec->cap_labels[spec->input_mux.num_items];
|
||||
strcpy(label, type);
|
||||
spec->input_mux.items[spec->input_mux.num_items].label = label;
|
||||
snd_hda_add_imux_item(&spec->input_mux, type, idx, NULL);
|
||||
|
||||
/* unmute the PIN external input */
|
||||
unmute_input(codec, node, 0); /* index = 0? */
|
||||
|
|
@ -577,29 +573,6 @@ static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec,
|
|||
return 1; /* found */
|
||||
}
|
||||
|
||||
/* add a capture source element */
|
||||
static void add_cap_src(struct hda_gspec *spec, int idx)
|
||||
{
|
||||
struct hda_input_mux_item *csrc;
|
||||
char *buf;
|
||||
int num, ocap;
|
||||
|
||||
num = spec->input_mux.num_items;
|
||||
csrc = &spec->input_mux.items[num];
|
||||
buf = spec->cap_labels[num];
|
||||
for (ocap = 0; ocap < num; ocap++) {
|
||||
if (! strcmp(buf, spec->cap_labels[ocap])) {
|
||||
/* same label already exists,
|
||||
* put the index number to be unique
|
||||
*/
|
||||
sprintf(buf, "%s %d", spec->cap_labels[ocap], num);
|
||||
break;
|
||||
}
|
||||
}
|
||||
csrc->index = idx;
|
||||
spec->input_mux.num_items++;
|
||||
}
|
||||
|
||||
/*
|
||||
* parse input
|
||||
*/
|
||||
|
|
@ -624,22 +597,18 @@ static int parse_input_path(struct hda_codec *codec, struct hda_gnode *adc_node)
|
|||
for (i = 0; i < adc_node->nconns; i++) {
|
||||
node = hda_get_node(spec, adc_node->conn_list[i]);
|
||||
if (node && node->type == AC_WID_PIN) {
|
||||
err = parse_adc_sub_nodes(codec, spec, node);
|
||||
err = parse_adc_sub_nodes(codec, spec, node, i);
|
||||
if (err < 0)
|
||||
return err;
|
||||
else if (err > 0)
|
||||
add_cap_src(spec, i);
|
||||
}
|
||||
}
|
||||
/* ... then check the rests, more complicated connections */
|
||||
for (i = 0; i < adc_node->nconns; i++) {
|
||||
node = hda_get_node(spec, adc_node->conn_list[i]);
|
||||
if (node && node->type != AC_WID_PIN) {
|
||||
err = parse_adc_sub_nodes(codec, spec, node);
|
||||
err = parse_adc_sub_nodes(codec, spec, node, i);
|
||||
if (err < 0)
|
||||
return err;
|
||||
else if (err > 0)
|
||||
add_cap_src(spec, i);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -78,8 +78,8 @@ MODULE_PARM_DESC(enable, "Enable Intel HD audio interface.");
|
|||
module_param_array(model, charp, NULL, 0444);
|
||||
MODULE_PARM_DESC(model, "Use the given board model.");
|
||||
module_param_array(position_fix, int, NULL, 0444);
|
||||
MODULE_PARM_DESC(position_fix, "Fix DMA pointer "
|
||||
"(0 = auto, 1 = none, 2 = POSBUF).");
|
||||
MODULE_PARM_DESC(position_fix, "DMA pointer read method."
|
||||
"(0 = auto, 1 = LPIB, 2 = POSBUF, 3 = VIACOMBO).");
|
||||
module_param_array(bdl_pos_adj, int, NULL, 0644);
|
||||
MODULE_PARM_DESC(bdl_pos_adj, "BDL position adjustment offset.");
|
||||
module_param_array(probe_mask, int, NULL, 0444);
|
||||
|
|
@ -305,6 +305,7 @@ enum {
|
|||
POS_FIX_AUTO,
|
||||
POS_FIX_LPIB,
|
||||
POS_FIX_POSBUF,
|
||||
POS_FIX_VIACOMBO,
|
||||
};
|
||||
|
||||
/* Defines for ATI HD Audio support in SB450 south bridge */
|
||||
|
|
@ -433,7 +434,6 @@ struct azx {
|
|||
unsigned int polling_mode :1;
|
||||
unsigned int msi :1;
|
||||
unsigned int irq_pending_warned :1;
|
||||
unsigned int via_dmapos_patch :1; /* enable DMA-position fix for VIA */
|
||||
unsigned int probing :1; /* codec probing phase */
|
||||
|
||||
/* for debugging */
|
||||
|
|
@ -458,6 +458,7 @@ enum {
|
|||
AZX_DRIVER_ULI,
|
||||
AZX_DRIVER_NVIDIA,
|
||||
AZX_DRIVER_TERA,
|
||||
AZX_DRIVER_CTX,
|
||||
AZX_DRIVER_GENERIC,
|
||||
AZX_NUM_DRIVERS, /* keep this as last entry */
|
||||
};
|
||||
|
|
@ -473,6 +474,7 @@ static char *driver_short_names[] __devinitdata = {
|
|||
[AZX_DRIVER_ULI] = "HDA ULI M5461",
|
||||
[AZX_DRIVER_NVIDIA] = "HDA NVidia",
|
||||
[AZX_DRIVER_TERA] = "HDA Teradici",
|
||||
[AZX_DRIVER_CTX] = "HDA Creative",
|
||||
[AZX_DRIVER_GENERIC] = "HD-Audio Generic",
|
||||
};
|
||||
|
||||
|
|
@ -563,7 +565,10 @@ static void azx_init_cmd_io(struct azx *chip)
|
|||
/* reset the rirb hw write pointer */
|
||||
azx_writew(chip, RIRBWP, ICH6_RIRBWP_RST);
|
||||
/* set N=1, get RIRB response interrupt for new entry */
|
||||
azx_writew(chip, RINTCNT, 1);
|
||||
if (chip->driver_type == AZX_DRIVER_CTX)
|
||||
azx_writew(chip, RINTCNT, 0xc0);
|
||||
else
|
||||
azx_writew(chip, RINTCNT, 1);
|
||||
/* enable rirb dma and response irq */
|
||||
azx_writeb(chip, RIRBCTL, ICH6_RBCTL_DMA_EN | ICH6_RBCTL_IRQ_EN);
|
||||
spin_unlock_irq(&chip->reg_lock);
|
||||
|
|
@ -1136,8 +1141,11 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
|
|||
/* clear rirb int */
|
||||
status = azx_readb(chip, RIRBSTS);
|
||||
if (status & RIRB_INT_MASK) {
|
||||
if (status & RIRB_INT_RESPONSE)
|
||||
if (status & RIRB_INT_RESPONSE) {
|
||||
if (chip->driver_type == AZX_DRIVER_CTX)
|
||||
udelay(80);
|
||||
azx_update_rirb(chip);
|
||||
}
|
||||
azx_writeb(chip, RIRBSTS, RIRB_INT_MASK);
|
||||
}
|
||||
|
||||
|
|
@ -1309,11 +1317,8 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev)
|
|||
azx_sd_writel(azx_dev, SD_BDLPU, upper_32_bits(azx_dev->bdl.addr));
|
||||
|
||||
/* enable the position buffer */
|
||||
if (chip->position_fix[0] == POS_FIX_POSBUF ||
|
||||
chip->position_fix[0] == POS_FIX_AUTO ||
|
||||
chip->position_fix[1] == POS_FIX_POSBUF ||
|
||||
chip->position_fix[1] == POS_FIX_AUTO ||
|
||||
chip->via_dmapos_patch) {
|
||||
if (chip->position_fix[0] != POS_FIX_LPIB ||
|
||||
chip->position_fix[1] != POS_FIX_LPIB) {
|
||||
if (!(azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE))
|
||||
azx_writel(chip, DPLBASE,
|
||||
(u32)chip->posbuf.addr | ICH6_DPLBASE_ENABLE);
|
||||
|
|
@ -1647,7 +1652,7 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
|
|||
struct azx_dev *azx_dev = get_azx_dev(substream);
|
||||
struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
unsigned int bufsize, period_bytes, format_val;
|
||||
unsigned int bufsize, period_bytes, format_val, stream_tag;
|
||||
int err;
|
||||
|
||||
azx_stream_reset(chip, azx_dev);
|
||||
|
|
@ -1689,7 +1694,12 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
|
|||
else
|
||||
azx_dev->fifo_size = 0;
|
||||
|
||||
return snd_hda_codec_prepare(apcm->codec, hinfo, azx_dev->stream_tag,
|
||||
stream_tag = azx_dev->stream_tag;
|
||||
/* CA-IBG chips need the playback stream starting from 1 */
|
||||
if (chip->driver_type == AZX_DRIVER_CTX &&
|
||||
stream_tag > chip->capture_streams)
|
||||
stream_tag -= chip->capture_streams;
|
||||
return snd_hda_codec_prepare(apcm->codec, hinfo, stream_tag,
|
||||
azx_dev->format_val, substream);
|
||||
}
|
||||
|
||||
|
|
@ -1852,20 +1862,21 @@ static unsigned int azx_get_position(struct azx *chip,
|
|||
struct azx_dev *azx_dev)
|
||||
{
|
||||
unsigned int pos;
|
||||
int stream = azx_dev->substream->stream;
|
||||
|
||||
if (chip->via_dmapos_patch)
|
||||
switch (chip->position_fix[stream]) {
|
||||
case POS_FIX_LPIB:
|
||||
/* read LPIB */
|
||||
pos = azx_sd_readl(azx_dev, SD_LPIB);
|
||||
break;
|
||||
case POS_FIX_VIACOMBO:
|
||||
pos = azx_via_get_position(chip, azx_dev);
|
||||
else {
|
||||
int stream = azx_dev->substream->stream;
|
||||
if (chip->position_fix[stream] == POS_FIX_POSBUF ||
|
||||
chip->position_fix[stream] == POS_FIX_AUTO) {
|
||||
/* use the position buffer */
|
||||
pos = le32_to_cpu(*azx_dev->posbuf);
|
||||
} else {
|
||||
/* read LPIB */
|
||||
pos = azx_sd_readl(azx_dev, SD_LPIB);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* use the position buffer */
|
||||
pos = le32_to_cpu(*azx_dev->posbuf);
|
||||
}
|
||||
|
||||
if (pos >= azx_dev->bufsize)
|
||||
pos = 0;
|
||||
return pos;
|
||||
|
|
@ -2313,19 +2324,10 @@ static int __devinit check_position_fix(struct azx *chip, int fix)
|
|||
switch (fix) {
|
||||
case POS_FIX_LPIB:
|
||||
case POS_FIX_POSBUF:
|
||||
case POS_FIX_VIACOMBO:
|
||||
return fix;
|
||||
}
|
||||
|
||||
/* Check VIA/ATI HD Audio Controller exist */
|
||||
switch (chip->driver_type) {
|
||||
case AZX_DRIVER_VIA:
|
||||
case AZX_DRIVER_ATI:
|
||||
chip->via_dmapos_patch = 1;
|
||||
/* Use link position directly, avoid any transfer problem. */
|
||||
return POS_FIX_LPIB;
|
||||
}
|
||||
chip->via_dmapos_patch = 0;
|
||||
|
||||
q = snd_pci_quirk_lookup(chip->pci, position_fix_list);
|
||||
if (q) {
|
||||
printk(KERN_INFO
|
||||
|
|
@ -2334,6 +2336,15 @@ static int __devinit check_position_fix(struct azx *chip, int fix)
|
|||
q->value, q->subvendor, q->subdevice);
|
||||
return q->value;
|
||||
}
|
||||
|
||||
/* Check VIA/ATI HD Audio Controller exist */
|
||||
switch (chip->driver_type) {
|
||||
case AZX_DRIVER_VIA:
|
||||
case AZX_DRIVER_ATI:
|
||||
/* Use link position directly, avoid any transfer problem. */
|
||||
return POS_FIX_VIACOMBO;
|
||||
}
|
||||
|
||||
return POS_FIX_AUTO;
|
||||
}
|
||||
|
||||
|
|
@ -2735,25 +2746,17 @@ static void __devexit azx_remove(struct pci_dev *pci)
|
|||
|
||||
/* PCI IDs */
|
||||
static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
|
||||
/* ICH 6..10 */
|
||||
{ PCI_DEVICE(0x8086, 0x2668), .driver_data = AZX_DRIVER_ICH },
|
||||
{ PCI_DEVICE(0x8086, 0x27d8), .driver_data = AZX_DRIVER_ICH },
|
||||
{ PCI_DEVICE(0x8086, 0x269a), .driver_data = AZX_DRIVER_ICH },
|
||||
{ PCI_DEVICE(0x8086, 0x284b), .driver_data = AZX_DRIVER_ICH },
|
||||
{ PCI_DEVICE(0x8086, 0x2911), .driver_data = AZX_DRIVER_ICH },
|
||||
{ PCI_DEVICE(0x8086, 0x293e), .driver_data = AZX_DRIVER_ICH },
|
||||
{ PCI_DEVICE(0x8086, 0x293f), .driver_data = AZX_DRIVER_ICH },
|
||||
{ PCI_DEVICE(0x8086, 0x3a3e), .driver_data = AZX_DRIVER_ICH },
|
||||
{ PCI_DEVICE(0x8086, 0x3a6e), .driver_data = AZX_DRIVER_ICH },
|
||||
/* PCH */
|
||||
{ PCI_DEVICE(0x8086, 0x3b56), .driver_data = AZX_DRIVER_ICH },
|
||||
{ PCI_DEVICE(0x8086, 0x3b57), .driver_data = AZX_DRIVER_ICH },
|
||||
/* CPT */
|
||||
{ PCI_DEVICE(0x8086, 0x1c20), .driver_data = AZX_DRIVER_PCH },
|
||||
/* PBG */
|
||||
{ PCI_DEVICE(0x8086, 0x1d20), .driver_data = AZX_DRIVER_PCH },
|
||||
/* SCH */
|
||||
{ PCI_DEVICE(0x8086, 0x811b), .driver_data = AZX_DRIVER_SCH },
|
||||
/* Generic Intel */
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_ANY_ID),
|
||||
.class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
|
||||
.class_mask = 0xffffff,
|
||||
.driver_data = AZX_DRIVER_ICH },
|
||||
/* ATI SB 450/600 */
|
||||
{ PCI_DEVICE(0x1002, 0x437b), .driver_data = AZX_DRIVER_ATI },
|
||||
{ PCI_DEVICE(0x1002, 0x4383), .driver_data = AZX_DRIVER_ATI },
|
||||
|
|
@ -2794,11 +2797,13 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
|
|||
{ PCI_DEVICE(PCI_VENDOR_ID_CREATIVE, PCI_ANY_ID),
|
||||
.class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
|
||||
.class_mask = 0xffffff,
|
||||
.driver_data = AZX_DRIVER_GENERIC },
|
||||
.driver_data = AZX_DRIVER_CTX },
|
||||
#else
|
||||
/* this entry seems still valid -- i.e. without emu20kx chip */
|
||||
{ PCI_DEVICE(0x1102, 0x0009), .driver_data = AZX_DRIVER_GENERIC },
|
||||
{ PCI_DEVICE(0x1102, 0x0009), .driver_data = AZX_DRIVER_CTX },
|
||||
#endif
|
||||
/* Vortex86MX */
|
||||
{ PCI_DEVICE(0x17f3, 0x3010), .driver_data = AZX_DRIVER_GENERIC },
|
||||
/* AMD/ATI Generic, PCI class code and Vendor ID for HD Audio */
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_ANY_ID),
|
||||
.class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
|
||||
|
|
|
|||
|
|
@ -38,10 +38,11 @@
|
|||
*/
|
||||
#define HDA_COMPOSE_AMP_VAL_OFS(nid,chs,idx,dir,ofs) \
|
||||
((nid) | ((chs)<<16) | ((dir)<<18) | ((idx)<<19) | ((ofs)<<23))
|
||||
#define HDA_AMP_VAL_MIN_MUTE (1<<29)
|
||||
#define HDA_COMPOSE_AMP_VAL(nid,chs,idx,dir) \
|
||||
HDA_COMPOSE_AMP_VAL_OFS(nid, chs, idx, dir, 0)
|
||||
/* mono volume with index (index=0,1,...) (channel=1,2) */
|
||||
#define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \
|
||||
#define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, dir, flags) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \
|
||||
.subdevice = HDA_SUBDEV_AMP_FLAG, \
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
|
||||
|
|
@ -51,16 +52,20 @@
|
|||
.get = snd_hda_mixer_amp_volume_get, \
|
||||
.put = snd_hda_mixer_amp_volume_put, \
|
||||
.tlv = { .c = snd_hda_mixer_amp_tlv }, \
|
||||
.private_value = HDA_COMPOSE_AMP_VAL(nid, channel, xindex, direction) }
|
||||
.private_value = HDA_COMPOSE_AMP_VAL(nid, channel, xindex, dir) | flags }
|
||||
/* stereo volume with index */
|
||||
#define HDA_CODEC_VOLUME_IDX(xname, xcidx, nid, xindex, direction) \
|
||||
HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, 3, xindex, direction)
|
||||
HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, 3, xindex, direction, 0)
|
||||
/* mono volume */
|
||||
#define HDA_CODEC_VOLUME_MONO(xname, nid, channel, xindex, direction) \
|
||||
HDA_CODEC_VOLUME_MONO_IDX(xname, 0, nid, channel, xindex, direction)
|
||||
HDA_CODEC_VOLUME_MONO_IDX(xname, 0, nid, channel, xindex, direction, 0)
|
||||
/* stereo volume */
|
||||
#define HDA_CODEC_VOLUME(xname, nid, xindex, direction) \
|
||||
HDA_CODEC_VOLUME_MONO(xname, nid, 3, xindex, direction)
|
||||
/* stereo volume with min=mute */
|
||||
#define HDA_CODEC_VOLUME_MIN_MUTE(xname, nid, xindex, direction) \
|
||||
HDA_CODEC_VOLUME_MONO_IDX(xname, 0, nid, 3, xindex, direction, \
|
||||
HDA_AMP_VAL_MIN_MUTE)
|
||||
/* mono mute switch with index (index=0,1,...) (channel=1,2) */
|
||||
#define HDA_CODEC_MUTE_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \
|
||||
|
|
@ -215,7 +220,7 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid);
|
|||
*/
|
||||
#define HDA_MAX_NUM_INPUTS 16
|
||||
struct hda_input_mux_item {
|
||||
const char *label;
|
||||
char label[32];
|
||||
unsigned int index;
|
||||
};
|
||||
struct hda_input_mux {
|
||||
|
|
@ -366,9 +371,7 @@ struct hda_bus_unsolicited {
|
|||
|
||||
enum {
|
||||
AUTO_PIN_MIC,
|
||||
AUTO_PIN_FRONT_MIC,
|
||||
AUTO_PIN_LINE,
|
||||
AUTO_PIN_FRONT_LINE,
|
||||
AUTO_PIN_LINE_IN,
|
||||
AUTO_PIN_CD,
|
||||
AUTO_PIN_AUX,
|
||||
AUTO_PIN_LAST
|
||||
|
|
@ -380,9 +383,33 @@ enum {
|
|||
AUTO_PIN_HP_OUT
|
||||
};
|
||||
|
||||
extern const char *auto_pin_cfg_labels[AUTO_PIN_LAST];
|
||||
|
||||
#define AUTO_CFG_MAX_OUTS 5
|
||||
#define AUTO_CFG_MAX_INS 8
|
||||
|
||||
struct auto_pin_cfg_item {
|
||||
hda_nid_t pin;
|
||||
int type;
|
||||
};
|
||||
|
||||
struct auto_pin_cfg;
|
||||
const char *hda_get_input_pin_label(struct hda_codec *codec, hda_nid_t pin,
|
||||
int check_location);
|
||||
const char *hda_get_autocfg_input_label(struct hda_codec *codec,
|
||||
const struct auto_pin_cfg *cfg,
|
||||
int input);
|
||||
int snd_hda_add_imux_item(struct hda_input_mux *imux, const char *label,
|
||||
int index, int *type_index_ret);
|
||||
|
||||
enum {
|
||||
INPUT_PIN_ATTR_UNUSED, /* pin not connected */
|
||||
INPUT_PIN_ATTR_INT, /* internal mic/line-in */
|
||||
INPUT_PIN_ATTR_DOCK, /* docking mic/line-in */
|
||||
INPUT_PIN_ATTR_NORMAL, /* mic/line-in jack */
|
||||
INPUT_PIN_ATTR_FRONT, /* mic/line-in jack in front */
|
||||
INPUT_PIN_ATTR_REAR, /* mic/line-in jack in rear */
|
||||
};
|
||||
|
||||
int snd_hda_get_input_pin_attr(unsigned int def_conf);
|
||||
|
||||
struct auto_pin_cfg {
|
||||
int line_outs;
|
||||
|
|
@ -393,7 +420,8 @@ struct auto_pin_cfg {
|
|||
int hp_outs;
|
||||
int line_out_type; /* AUTO_PIN_XXX_OUT */
|
||||
hda_nid_t hp_pins[AUTO_CFG_MAX_OUTS];
|
||||
hda_nid_t input_pins[AUTO_PIN_LAST];
|
||||
int num_inputs;
|
||||
struct auto_pin_cfg_item inputs[AUTO_CFG_MAX_INS];
|
||||
int dig_outs;
|
||||
hda_nid_t dig_out_pins[2];
|
||||
hda_nid_t dig_in_pin;
|
||||
|
|
@ -558,6 +586,7 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec,
|
|||
#define get_amp_direction(kc) (((kc)->private_value >> 18) & 0x1)
|
||||
#define get_amp_index(kc) (((kc)->private_value >> 19) & 0xf)
|
||||
#define get_amp_offset(kc) (((kc)->private_value >> 23) & 0x3f)
|
||||
#define get_amp_min_mute(kc) (((kc)->private_value >> 29) & 0x1)
|
||||
|
||||
/*
|
||||
* CEA Short Audio Descriptor data
|
||||
|
|
|
|||
|
|
@ -1276,6 +1276,7 @@ static int patch_ad1986a(struct hda_codec *codec)
|
|||
spec->multiout.no_share_stream = 1;
|
||||
|
||||
codec->no_trigger_sense = 1;
|
||||
codec->no_sticky_stream = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1463,6 +1464,7 @@ static int patch_ad1983(struct hda_codec *codec)
|
|||
codec->patch_ops = ad198x_patch_ops;
|
||||
|
||||
codec->no_trigger_sense = 1;
|
||||
codec->no_sticky_stream = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1917,6 +1919,7 @@ static int patch_ad1981(struct hda_codec *codec)
|
|||
}
|
||||
|
||||
codec->no_trigger_sense = 1;
|
||||
codec->no_sticky_stream = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -2880,7 +2883,7 @@ static int ad1988_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
|
|||
|
||||
/* create input playback/capture controls for the given pin */
|
||||
static int new_analog_input(struct ad198x_spec *spec, hda_nid_t pin,
|
||||
const char *ctlname, int boost)
|
||||
const char *ctlname, int ctlidx, int boost)
|
||||
{
|
||||
char name[32];
|
||||
int err, idx;
|
||||
|
|
@ -2909,25 +2912,27 @@ static int new_analog_input(struct ad198x_spec *spec, hda_nid_t pin,
|
|||
}
|
||||
|
||||
/* create playback/capture controls for input pins */
|
||||
static int ad1988_auto_create_analog_input_ctls(struct ad198x_spec *spec,
|
||||
static int ad1988_auto_create_analog_input_ctls(struct hda_codec *codec,
|
||||
const struct auto_pin_cfg *cfg)
|
||||
{
|
||||
struct ad198x_spec *spec = codec->spec;
|
||||
struct hda_input_mux *imux = &spec->private_imux;
|
||||
int i, err;
|
||||
int i, err, type, type_idx;
|
||||
|
||||
for (i = 0; i < AUTO_PIN_LAST; i++) {
|
||||
err = new_analog_input(spec, cfg->input_pins[i],
|
||||
auto_pin_cfg_labels[i],
|
||||
i <= AUTO_PIN_FRONT_MIC);
|
||||
for (i = 0; i < cfg->num_inputs; i++) {
|
||||
const char *label;
|
||||
type = cfg->inputs[i].type;
|
||||
label = hda_get_autocfg_input_label(codec, cfg, i);
|
||||
snd_hda_add_imux_item(imux, label,
|
||||
ad1988_pin_to_adc_idx(cfg->inputs[i].pin),
|
||||
&type_idx);
|
||||
err = new_analog_input(spec, cfg->inputs[i].pin,
|
||||
label, type_idx,
|
||||
type == AUTO_PIN_MIC);
|
||||
if (err < 0)
|
||||
return err;
|
||||
imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
|
||||
imux->items[imux->num_items].index = ad1988_pin_to_adc_idx(cfg->input_pins[i]);
|
||||
imux->num_items++;
|
||||
}
|
||||
imux->items[imux->num_items].label = "Mix";
|
||||
imux->items[imux->num_items].index = 9;
|
||||
imux->num_items++;
|
||||
snd_hda_add_imux_item(imux, "Mix", 9, NULL);
|
||||
|
||||
if ((err = add_control(spec, AD_CTL_WIDGET_VOL,
|
||||
"Analog Mix Playback Volume",
|
||||
|
|
@ -2994,12 +2999,11 @@ static void ad1988_auto_init_extra_out(struct hda_codec *codec)
|
|||
static void ad1988_auto_init_analog_input(struct hda_codec *codec)
|
||||
{
|
||||
struct ad198x_spec *spec = codec->spec;
|
||||
const struct auto_pin_cfg *cfg = &spec->autocfg;
|
||||
int i, idx;
|
||||
|
||||
for (i = 0; i < AUTO_PIN_LAST; i++) {
|
||||
hda_nid_t nid = spec->autocfg.input_pins[i];
|
||||
if (! nid)
|
||||
continue;
|
||||
for (i = 0; i < cfg->num_inputs; i++) {
|
||||
hda_nid_t nid = cfg->inputs[i].pin;
|
||||
switch (nid) {
|
||||
case 0x15: /* port-C */
|
||||
snd_hda_codec_write(codec, 0x33, 0, AC_VERB_SET_CONNECT_SEL, 0x0);
|
||||
|
|
@ -3009,7 +3013,7 @@ static void ad1988_auto_init_analog_input(struct hda_codec *codec)
|
|||
break;
|
||||
}
|
||||
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||
i <= AUTO_PIN_FRONT_MIC ? PIN_VREF80 : PIN_IN);
|
||||
i == AUTO_PIN_MIC ? PIN_VREF80 : PIN_IN);
|
||||
if (nid != AD1988_PIN_CD_NID)
|
||||
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
|
||||
AMP_OUT_MUTE);
|
||||
|
|
@ -3040,7 +3044,7 @@ static int ad1988_parse_auto_config(struct hda_codec *codec)
|
|||
"Speaker")) < 0 ||
|
||||
(err = ad1988_auto_create_extra_out(codec, spec->autocfg.hp_pins[0],
|
||||
"Headphone")) < 0 ||
|
||||
(err = ad1988_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0)
|
||||
(err = ad1988_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0)
|
||||
return err;
|
||||
|
||||
spec->multiout.max_channels = spec->multiout.num_dacs * 2;
|
||||
|
|
@ -3235,6 +3239,7 @@ static int patch_ad1988(struct hda_codec *codec)
|
|||
spec->vmaster_nid = 0x04;
|
||||
|
||||
codec->no_trigger_sense = 1;
|
||||
codec->no_sticky_stream = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -3449,6 +3454,7 @@ static int patch_ad1884(struct hda_codec *codec)
|
|||
codec->patch_ops = ad198x_patch_ops;
|
||||
|
||||
codec->no_trigger_sense = 1;
|
||||
codec->no_sticky_stream = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -4422,6 +4428,7 @@ static int patch_ad1884a(struct hda_codec *codec)
|
|||
}
|
||||
|
||||
codec->no_trigger_sense = 1;
|
||||
codec->no_sticky_stream = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -4761,6 +4768,7 @@ static int patch_ad1882(struct hda_codec *codec)
|
|||
}
|
||||
|
||||
codec->no_trigger_sense = 1;
|
||||
codec->no_sticky_stream = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,224 +0,0 @@
|
|||
/*
|
||||
* Universal Interface for Intel High Definition Audio Codec
|
||||
*
|
||||
* HD audio interface patch for ATI HDMI codecs
|
||||
*
|
||||
* Copyright (c) 2006 ATI Technologies Inc.
|
||||
*
|
||||
*
|
||||
* This driver is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This driver is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <sound/core.h>
|
||||
#include "hda_codec.h"
|
||||
#include "hda_local.h"
|
||||
|
||||
struct atihdmi_spec {
|
||||
struct hda_multi_out multiout;
|
||||
|
||||
struct hda_pcm pcm_rec;
|
||||
};
|
||||
|
||||
#define CVT_NID 0x02 /* audio converter */
|
||||
#define PIN_NID 0x03 /* HDMI output pin */
|
||||
|
||||
static struct hda_verb atihdmi_basic_init[] = {
|
||||
/* enable digital output on pin widget */
|
||||
{ 0x03, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
|
||||
{} /* terminator */
|
||||
};
|
||||
|
||||
/*
|
||||
* Controls
|
||||
*/
|
||||
static int atihdmi_build_controls(struct hda_codec *codec)
|
||||
{
|
||||
struct atihdmi_spec *spec = codec->spec;
|
||||
int err;
|
||||
|
||||
err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atihdmi_init(struct hda_codec *codec)
|
||||
{
|
||||
snd_hda_sequence_write(codec, atihdmi_basic_init);
|
||||
/* SI codec requires to unmute the pin */
|
||||
if (get_wcaps(codec, PIN_NID) & AC_WCAP_OUT_AMP)
|
||||
snd_hda_codec_write(codec, PIN_NID, 0,
|
||||
AC_VERB_SET_AMP_GAIN_MUTE,
|
||||
AMP_OUT_UNMUTE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Digital out
|
||||
*/
|
||||
static int atihdmi_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
|
||||
struct hda_codec *codec,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct atihdmi_spec *spec = codec->spec;
|
||||
return snd_hda_multi_out_dig_open(codec, &spec->multiout);
|
||||
}
|
||||
|
||||
static int atihdmi_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
|
||||
struct hda_codec *codec,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct atihdmi_spec *spec = codec->spec;
|
||||
return snd_hda_multi_out_dig_close(codec, &spec->multiout);
|
||||
}
|
||||
|
||||
static int atihdmi_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
|
||||
struct hda_codec *codec,
|
||||
unsigned int stream_tag,
|
||||
unsigned int format,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct atihdmi_spec *spec = codec->spec;
|
||||
int chans = substream->runtime->channels;
|
||||
int i, err;
|
||||
|
||||
err = snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag,
|
||||
format, substream);
|
||||
if (err < 0)
|
||||
return err;
|
||||
snd_hda_codec_write(codec, CVT_NID, 0, AC_VERB_SET_CVT_CHAN_COUNT,
|
||||
chans - 1);
|
||||
/* FIXME: XXX */
|
||||
for (i = 0; i < chans; i++) {
|
||||
snd_hda_codec_write(codec, CVT_NID, 0,
|
||||
AC_VERB_SET_HDMI_CHAN_SLOT,
|
||||
(i << 4) | i);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct hda_pcm_stream atihdmi_pcm_digital_playback = {
|
||||
.substreams = 1,
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.nid = CVT_NID, /* NID to query formats and rates and setup streams */
|
||||
.ops = {
|
||||
.open = atihdmi_dig_playback_pcm_open,
|
||||
.close = atihdmi_dig_playback_pcm_close,
|
||||
.prepare = atihdmi_dig_playback_pcm_prepare
|
||||
},
|
||||
};
|
||||
|
||||
static int atihdmi_build_pcms(struct hda_codec *codec)
|
||||
{
|
||||
struct atihdmi_spec *spec = codec->spec;
|
||||
struct hda_pcm *info = &spec->pcm_rec;
|
||||
unsigned int chans;
|
||||
|
||||
codec->num_pcms = 1;
|
||||
codec->pcm_info = info;
|
||||
|
||||
info->name = "ATI HDMI";
|
||||
info->pcm_type = HDA_PCM_TYPE_HDMI;
|
||||
info->stream[SNDRV_PCM_STREAM_PLAYBACK] = atihdmi_pcm_digital_playback;
|
||||
|
||||
/* FIXME: we must check ELD and change the PCM parameters dynamically
|
||||
*/
|
||||
chans = get_wcaps(codec, CVT_NID);
|
||||
chans = get_wcaps_channels(chans);
|
||||
info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = chans;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void atihdmi_free(struct hda_codec *codec)
|
||||
{
|
||||
kfree(codec->spec);
|
||||
}
|
||||
|
||||
static struct hda_codec_ops atihdmi_patch_ops = {
|
||||
.build_controls = atihdmi_build_controls,
|
||||
.build_pcms = atihdmi_build_pcms,
|
||||
.init = atihdmi_init,
|
||||
.free = atihdmi_free,
|
||||
};
|
||||
|
||||
static int patch_atihdmi(struct hda_codec *codec)
|
||||
{
|
||||
struct atihdmi_spec *spec;
|
||||
|
||||
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
|
||||
if (spec == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
codec->spec = spec;
|
||||
|
||||
spec->multiout.num_dacs = 0; /* no analog */
|
||||
spec->multiout.max_channels = 2;
|
||||
/* NID for copying analog to digital,
|
||||
* seems to be unused in pure-digital
|
||||
* case.
|
||||
*/
|
||||
spec->multiout.dig_out_nid = CVT_NID;
|
||||
|
||||
codec->patch_ops = atihdmi_patch_ops;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* patch entries
|
||||
*/
|
||||
static struct hda_codec_preset snd_hda_preset_atihdmi[] = {
|
||||
{ .id = 0x1002793c, .name = "RS600 HDMI", .patch = patch_atihdmi },
|
||||
{ .id = 0x10027919, .name = "RS600 HDMI", .patch = patch_atihdmi },
|
||||
{ .id = 0x1002791a, .name = "RS690/780 HDMI", .patch = patch_atihdmi },
|
||||
{ .id = 0x1002aa01, .name = "R6xx HDMI", .patch = patch_atihdmi },
|
||||
{ .id = 0x10951390, .name = "SiI1390 HDMI", .patch = patch_atihdmi },
|
||||
{ .id = 0x17e80047, .name = "Chrontel HDMI", .patch = patch_atihdmi },
|
||||
{} /* terminator */
|
||||
};
|
||||
|
||||
MODULE_ALIAS("snd-hda-codec-id:1002793c");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10027919");
|
||||
MODULE_ALIAS("snd-hda-codec-id:1002791a");
|
||||
MODULE_ALIAS("snd-hda-codec-id:1002aa01");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10951390");
|
||||
MODULE_ALIAS("snd-hda-codec-id:17e80047");
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("ATI HDMI HD-audio codec");
|
||||
|
||||
static struct hda_codec_preset_list atihdmi_list = {
|
||||
.preset = snd_hda_preset_atihdmi,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init patch_atihdmi_init(void)
|
||||
{
|
||||
return snd_hda_add_codec_preset(&atihdmi_list);
|
||||
}
|
||||
|
||||
static void __exit patch_atihdmi_exit(void)
|
||||
{
|
||||
snd_hda_delete_codec_preset(&atihdmi_list);
|
||||
}
|
||||
|
||||
module_init(patch_atihdmi_init)
|
||||
module_exit(patch_atihdmi_exit)
|
||||
|
|
@ -468,13 +468,13 @@ static void parse_input(struct hda_codec *codec)
|
|||
spec->dig_in = nid;
|
||||
continue;
|
||||
}
|
||||
for (j = 0; j < AUTO_PIN_LAST; j++)
|
||||
if (cfg->input_pins[j] == pin)
|
||||
for (j = 0; j < cfg->num_inputs; j++)
|
||||
if (cfg->inputs[j].pin == pin)
|
||||
break;
|
||||
if (j >= AUTO_PIN_LAST)
|
||||
if (j >= cfg->num_inputs)
|
||||
continue;
|
||||
spec->input_pins[n] = pin;
|
||||
spec->input_labels[n] = auto_pin_cfg_labels[j];
|
||||
spec->input_labels[n] = hda_get_input_pin_label(codec, pin, 1);
|
||||
spec->adcs[n] = nid;
|
||||
n++;
|
||||
}
|
||||
|
|
@ -489,7 +489,7 @@ static void parse_digital(struct hda_codec *codec)
|
|||
if (cfg->dig_outs &&
|
||||
snd_hda_get_connections(codec, cfg->dig_out_pins[0],
|
||||
&spec->dig_out, 1) == 1)
|
||||
spec->multiout.dig_out_nid = cfg->dig_out_pins[0];
|
||||
spec->multiout.dig_out_nid = spec->dig_out;
|
||||
}
|
||||
|
||||
static int ca0110_parse_auto_config(struct hda_codec *codec)
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ struct cs_spec {
|
|||
|
||||
/* available models */
|
||||
enum {
|
||||
CS420X_MBP53,
|
||||
CS420X_MBP55,
|
||||
CS420X_IMAC27,
|
||||
CS420X_AUTO,
|
||||
|
|
@ -329,12 +330,12 @@ static int is_ext_mic(struct hda_codec *codec, unsigned int idx)
|
|||
{
|
||||
struct cs_spec *spec = codec->spec;
|
||||
struct auto_pin_cfg *cfg = &spec->autocfg;
|
||||
hda_nid_t pin = cfg->input_pins[idx];
|
||||
hda_nid_t pin = cfg->inputs[idx].pin;
|
||||
unsigned int val = snd_hda_query_pin_caps(codec, pin);
|
||||
if (!(val & AC_PINCAP_PRES_DETECT))
|
||||
return 0;
|
||||
val = snd_hda_codec_get_pincfg(codec, pin);
|
||||
return (get_defcfg_connect(val) == AC_JACK_PORT_COMPLEX);
|
||||
return (snd_hda_get_input_pin_attr(val) != INPUT_PIN_ATTR_INT);
|
||||
}
|
||||
|
||||
static hda_nid_t get_adc(struct hda_codec *codec, hda_nid_t pin,
|
||||
|
|
@ -424,10 +425,8 @@ static int parse_input(struct hda_codec *codec)
|
|||
struct auto_pin_cfg *cfg = &spec->autocfg;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < AUTO_PIN_LAST; i++) {
|
||||
hda_nid_t pin = cfg->input_pins[i];
|
||||
if (!pin)
|
||||
continue;
|
||||
for (i = 0; i < cfg->num_inputs; i++) {
|
||||
hda_nid_t pin = cfg->inputs[i].pin;
|
||||
spec->input_idx[spec->num_inputs] = i;
|
||||
spec->capsrc_idx[i] = spec->num_inputs++;
|
||||
spec->cur_input = i;
|
||||
|
|
@ -438,16 +437,17 @@ static int parse_input(struct hda_codec *codec)
|
|||
|
||||
/* check whether the automatic mic switch is available */
|
||||
if (spec->num_inputs == 2 &&
|
||||
spec->adc_nid[AUTO_PIN_MIC] && spec->adc_nid[AUTO_PIN_FRONT_MIC]) {
|
||||
if (is_ext_mic(codec, cfg->input_pins[AUTO_PIN_FRONT_MIC])) {
|
||||
if (!is_ext_mic(codec, cfg->input_pins[AUTO_PIN_MIC])) {
|
||||
cfg->inputs[0].type == AUTO_PIN_MIC &&
|
||||
cfg->inputs[1].type == AUTO_PIN_MIC) {
|
||||
if (is_ext_mic(codec, cfg->inputs[0].pin)) {
|
||||
if (!is_ext_mic(codec, cfg->inputs[1].pin)) {
|
||||
spec->mic_detect = 1;
|
||||
spec->automic_idx = AUTO_PIN_FRONT_MIC;
|
||||
spec->automic_idx = 0;
|
||||
}
|
||||
} else {
|
||||
if (is_ext_mic(codec, cfg->input_pins[AUTO_PIN_MIC])) {
|
||||
if (is_ext_mic(codec, cfg->inputs[1].pin)) {
|
||||
spec->mic_detect = 1;
|
||||
spec->automic_idx = AUTO_PIN_MIC;
|
||||
spec->automic_idx = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -674,6 +674,7 @@ static int cs_capture_source_info(struct snd_kcontrol *kcontrol,
|
|||
{
|
||||
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct cs_spec *spec = codec->spec;
|
||||
struct auto_pin_cfg *cfg = &spec->autocfg;
|
||||
unsigned int idx;
|
||||
|
||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
|
||||
|
|
@ -682,7 +683,8 @@ static int cs_capture_source_info(struct snd_kcontrol *kcontrol,
|
|||
if (uinfo->value.enumerated.item >= spec->num_inputs)
|
||||
uinfo->value.enumerated.item = spec->num_inputs - 1;
|
||||
idx = spec->input_idx[uinfo->value.enumerated.item];
|
||||
strcpy(uinfo->value.enumerated.name, auto_pin_cfg_labels[idx]);
|
||||
strcpy(uinfo->value.enumerated.name,
|
||||
hda_get_input_pin_label(codec, cfg->inputs[idx].pin, 1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -740,6 +742,27 @@ static struct hda_bind_ctls *make_bind_capture(struct hda_codec *codec,
|
|||
return bind;
|
||||
}
|
||||
|
||||
/* add a (input-boost) volume control to the given input pin */
|
||||
static int add_input_volume_control(struct hda_codec *codec,
|
||||
struct auto_pin_cfg *cfg,
|
||||
int item)
|
||||
{
|
||||
hda_nid_t pin = cfg->inputs[item].pin;
|
||||
u32 caps;
|
||||
const char *label;
|
||||
struct snd_kcontrol *kctl;
|
||||
|
||||
if (!(get_wcaps(codec, pin) & AC_WCAP_IN_AMP))
|
||||
return 0;
|
||||
caps = query_amp_caps(codec, pin, HDA_INPUT);
|
||||
caps = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT;
|
||||
if (caps <= 1)
|
||||
return 0;
|
||||
label = hda_get_autocfg_input_label(codec, cfg, item);
|
||||
return add_volume(codec, label, 0,
|
||||
HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_INPUT), 1, &kctl);
|
||||
}
|
||||
|
||||
static int build_input(struct hda_codec *codec)
|
||||
{
|
||||
struct cs_spec *spec = codec->spec;
|
||||
|
|
@ -779,6 +802,12 @@ static int build_input(struct hda_codec *codec)
|
|||
return err;
|
||||
}
|
||||
|
||||
for (i = 0; i < spec->num_inputs; i++) {
|
||||
err = add_input_volume_control(codec, &spec->autocfg, i);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -838,7 +867,8 @@ static void cs_automute(struct hda_codec *codec)
|
|||
AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||
hp_present ? 0 : PIN_OUT);
|
||||
}
|
||||
if (spec->board_config == CS420X_MBP55 ||
|
||||
if (spec->board_config == CS420X_MBP53 ||
|
||||
spec->board_config == CS420X_MBP55 ||
|
||||
spec->board_config == CS420X_IMAC27) {
|
||||
unsigned int gpio = hp_present ? 0x02 : 0x08;
|
||||
snd_hda_codec_write(codec, 0x01, 0,
|
||||
|
|
@ -853,15 +883,12 @@ static void cs_automic(struct hda_codec *codec)
|
|||
hda_nid_t nid;
|
||||
unsigned int present;
|
||||
|
||||
nid = cfg->input_pins[spec->automic_idx];
|
||||
nid = cfg->inputs[spec->automic_idx].pin;
|
||||
present = snd_hda_jack_detect(codec, nid);
|
||||
if (present)
|
||||
change_cur_input(codec, spec->automic_idx, 0);
|
||||
else {
|
||||
unsigned int imic = (spec->automic_idx == AUTO_PIN_MIC) ?
|
||||
AUTO_PIN_FRONT_MIC : AUTO_PIN_MIC;
|
||||
change_cur_input(codec, imic, 0);
|
||||
}
|
||||
else
|
||||
change_cur_input(codec, !spec->automic_idx, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -918,14 +945,14 @@ static void init_input(struct hda_codec *codec)
|
|||
unsigned int coef;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < AUTO_PIN_LAST; i++) {
|
||||
for (i = 0; i < cfg->num_inputs; i++) {
|
||||
unsigned int ctl;
|
||||
hda_nid_t pin = cfg->input_pins[i];
|
||||
if (!pin || !spec->adc_nid[i])
|
||||
hda_nid_t pin = cfg->inputs[i].pin;
|
||||
if (!spec->adc_nid[i])
|
||||
continue;
|
||||
/* set appropriate pin control and mute first */
|
||||
ctl = PIN_IN;
|
||||
if (i <= AUTO_PIN_FRONT_MIC) {
|
||||
if (cfg->inputs[i].type == AUTO_PIN_MIC) {
|
||||
unsigned int caps = snd_hda_query_pin_caps(codec, pin);
|
||||
caps >>= AC_PINCAP_VREF_SHIFT;
|
||||
if (caps & AC_PINCAP_VREF_80)
|
||||
|
|
@ -1130,6 +1157,7 @@ static int cs_parse_auto_config(struct hda_codec *codec)
|
|||
}
|
||||
|
||||
static const char *cs420x_models[CS420X_MODELS] = {
|
||||
[CS420X_MBP53] = "mbp53",
|
||||
[CS420X_MBP55] = "mbp55",
|
||||
[CS420X_IMAC27] = "imac27",
|
||||
[CS420X_AUTO] = "auto",
|
||||
|
|
@ -1137,7 +1165,9 @@ static const char *cs420x_models[CS420X_MODELS] = {
|
|||
|
||||
|
||||
static struct snd_pci_quirk cs420x_cfg_tbl[] = {
|
||||
SND_PCI_QUIRK(0x10de, 0x0ac0, "MacBookPro 5,3", CS420X_MBP53),
|
||||
SND_PCI_QUIRK(0x10de, 0xcb79, "MacBookPro 5,5", CS420X_MBP55),
|
||||
SND_PCI_QUIRK(0x10de, 0xcb89, "MacBookPro 7,1", CS420X_MBP55),
|
||||
SND_PCI_QUIRK(0x8086, 0x7270, "IMac 27 Inch", CS420X_IMAC27),
|
||||
{} /* terminator */
|
||||
};
|
||||
|
|
@ -1147,6 +1177,20 @@ struct cs_pincfg {
|
|||
u32 val;
|
||||
};
|
||||
|
||||
static struct cs_pincfg mbp53_pincfgs[] = {
|
||||
{ 0x09, 0x012b4050 },
|
||||
{ 0x0a, 0x90100141 },
|
||||
{ 0x0b, 0x90100140 },
|
||||
{ 0x0c, 0x018b3020 },
|
||||
{ 0x0d, 0x90a00110 },
|
||||
{ 0x0e, 0x400000f0 },
|
||||
{ 0x0f, 0x01cbe030 },
|
||||
{ 0x10, 0x014be060 },
|
||||
{ 0x12, 0x400000f0 },
|
||||
{ 0x15, 0x400000f0 },
|
||||
{} /* terminator */
|
||||
};
|
||||
|
||||
static struct cs_pincfg mbp55_pincfgs[] = {
|
||||
{ 0x09, 0x012b4030 },
|
||||
{ 0x0a, 0x90100121 },
|
||||
|
|
@ -1176,6 +1220,7 @@ static struct cs_pincfg imac27_pincfgs[] = {
|
|||
};
|
||||
|
||||
static struct cs_pincfg *cs_pincfgs[CS420X_MODELS] = {
|
||||
[CS420X_MBP53] = mbp53_pincfgs,
|
||||
[CS420X_MBP55] = mbp55_pincfgs,
|
||||
[CS420X_IMAC27] = imac27_pincfgs,
|
||||
};
|
||||
|
|
@ -1208,6 +1253,7 @@ static int patch_cs420x(struct hda_codec *codec)
|
|||
|
||||
switch (spec->board_config) {
|
||||
case CS420X_IMAC27:
|
||||
case CS420X_MBP53:
|
||||
case CS420X_MBP55:
|
||||
/* GPIO1 = headphones */
|
||||
/* GPIO3 = speakers */
|
||||
|
|
|
|||
|
|
@ -57,6 +57,12 @@ struct conexant_jack {
|
|||
|
||||
};
|
||||
|
||||
struct pin_dac_pair {
|
||||
hda_nid_t pin;
|
||||
hda_nid_t dac;
|
||||
int type;
|
||||
};
|
||||
|
||||
struct conexant_spec {
|
||||
|
||||
struct snd_kcontrol_new *mixers[5];
|
||||
|
|
@ -77,6 +83,7 @@ struct conexant_spec {
|
|||
unsigned int cur_eapd;
|
||||
unsigned int hp_present;
|
||||
unsigned int auto_mic;
|
||||
int auto_mic_ext; /* autocfg.inputs[] index for ext mic */
|
||||
unsigned int need_dac_fix;
|
||||
|
||||
/* capture */
|
||||
|
|
@ -110,9 +117,12 @@ struct conexant_spec {
|
|||
struct auto_pin_cfg autocfg;
|
||||
struct hda_input_mux private_imux;
|
||||
hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
|
||||
struct pin_dac_pair dac_info[8];
|
||||
int dac_info_filled;
|
||||
|
||||
unsigned int dell_automute;
|
||||
unsigned int port_d_mode;
|
||||
unsigned int auto_mute:1; /* used in auto-parser */
|
||||
unsigned int dell_automute:1;
|
||||
unsigned int dell_vostro:1;
|
||||
unsigned int ideapad:1;
|
||||
unsigned int thinkpad:1;
|
||||
|
|
@ -3065,7 +3075,7 @@ enum {
|
|||
CXT5066_LAPTOP, /* Laptops w/ EAPD support */
|
||||
CXT5066_DELL_LAPTOP, /* Dell Laptop */
|
||||
CXT5066_OLPC_XO_1_5, /* OLPC XO 1.5 */
|
||||
CXT5066_DELL_VOSTO, /* Dell Vostro 1015i */
|
||||
CXT5066_DELL_VOSTRO, /* Dell Vostro 1015i */
|
||||
CXT5066_IDEAPAD, /* Lenovo IdeaPad U150 */
|
||||
CXT5066_THINKPAD, /* Lenovo ThinkPad T410s, others? */
|
||||
CXT5066_HP_LAPTOP, /* HP Laptop */
|
||||
|
|
@ -3076,25 +3086,26 @@ static const char *cxt5066_models[CXT5066_MODELS] = {
|
|||
[CXT5066_LAPTOP] = "laptop",
|
||||
[CXT5066_DELL_LAPTOP] = "dell-laptop",
|
||||
[CXT5066_OLPC_XO_1_5] = "olpc-xo-1_5",
|
||||
[CXT5066_DELL_VOSTO] = "dell-vostro",
|
||||
[CXT5066_DELL_VOSTRO] = "dell-vostro",
|
||||
[CXT5066_IDEAPAD] = "ideapad",
|
||||
[CXT5066_THINKPAD] = "thinkpad",
|
||||
[CXT5066_HP_LAPTOP] = "hp-laptop",
|
||||
};
|
||||
|
||||
static struct snd_pci_quirk cxt5066_cfg_tbl[] = {
|
||||
SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board",
|
||||
CXT5066_LAPTOP),
|
||||
SND_PCI_QUIRK_MASK(0x1025, 0xff00, 0x0400, "Acer", CXT5066_IDEAPAD),
|
||||
SND_PCI_QUIRK(0x1028, 0x02d8, "Dell Vostro", CXT5066_DELL_VOSTRO),
|
||||
SND_PCI_QUIRK(0x1028, 0x02f5, "Dell",
|
||||
CXT5066_DELL_LAPTOP),
|
||||
SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5),
|
||||
SND_PCI_QUIRK(0x1028, 0x02d8, "Dell Vostro", CXT5066_DELL_VOSTO),
|
||||
SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTO),
|
||||
SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTRO),
|
||||
SND_PCI_QUIRK(0x1028, 0x0408, "Dell Inspiron One 19T", CXT5066_IDEAPAD),
|
||||
SND_PCI_QUIRK(0x103c, 0x360b, "HP G60", CXT5066_HP_LAPTOP),
|
||||
SND_PCI_QUIRK(0x1179, 0xff1e, "Toshiba Satellite C650D", CXT5066_IDEAPAD),
|
||||
SND_PCI_QUIRK(0x1179, 0xff50, "Toshiba Satellite P500-PSPGSC-01800T", CXT5066_OLPC_XO_1_5),
|
||||
SND_PCI_QUIRK(0x1179, 0xffe0, "Toshiba Satellite Pro T130-15F", CXT5066_OLPC_XO_1_5),
|
||||
SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board",
|
||||
CXT5066_LAPTOP),
|
||||
SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5),
|
||||
SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400s", CXT5066_THINKPAD),
|
||||
SND_PCI_QUIRK(0x17aa, 0x21b2, "Thinkpad X100e", CXT5066_IDEAPAD),
|
||||
SND_PCI_QUIRK(0x17aa, 0x21b3, "Thinkpad Edge 13 (197)", CXT5066_IDEAPAD),
|
||||
|
|
@ -3196,7 +3207,7 @@ static int patch_cxt5066(struct hda_codec *codec)
|
|||
spec->capture_prepare = cxt5066_olpc_capture_prepare;
|
||||
spec->capture_cleanup = cxt5066_olpc_capture_cleanup;
|
||||
break;
|
||||
case CXT5066_DELL_VOSTO:
|
||||
case CXT5066_DELL_VOSTRO:
|
||||
codec->patch_ops.init = cxt5066_init;
|
||||
codec->patch_ops.unsol_event = cxt5066_vostro_event;
|
||||
spec->init_verbs[0] = cxt5066_init_verbs_vostro;
|
||||
|
|
@ -3253,6 +3264,604 @@ static int patch_cxt5066(struct hda_codec *codec)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Automatic parser for CX20641 & co
|
||||
*/
|
||||
|
||||
static hda_nid_t cx_auto_adc_nids[] = { 0x14 };
|
||||
|
||||
/* get the connection index of @nid in the widget @mux */
|
||||
static int get_connection_index(struct hda_codec *codec, hda_nid_t mux,
|
||||
hda_nid_t nid)
|
||||
{
|
||||
hda_nid_t conn[HDA_MAX_NUM_INPUTS];
|
||||
int i, nums;
|
||||
|
||||
nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn));
|
||||
for (i = 0; i < nums; i++)
|
||||
if (conn[i] == nid)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* get an unassigned DAC from the given list.
|
||||
* Return the nid if found and reduce the DAC list, or return zero if
|
||||
* not found
|
||||
*/
|
||||
static hda_nid_t get_unassigned_dac(struct hda_codec *codec, hda_nid_t pin,
|
||||
hda_nid_t *dacs, int *num_dacs)
|
||||
{
|
||||
int i, nums = *num_dacs;
|
||||
hda_nid_t ret = 0;
|
||||
|
||||
for (i = 0; i < nums; i++) {
|
||||
if (get_connection_index(codec, pin, dacs[i]) >= 0) {
|
||||
ret = dacs[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!ret)
|
||||
return 0;
|
||||
if (--nums > 0)
|
||||
memmove(dacs, dacs + 1, nums * sizeof(hda_nid_t));
|
||||
*num_dacs = nums;
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define MAX_AUTO_DACS 5
|
||||
|
||||
/* fill analog DAC list from the widget tree */
|
||||
static int fill_cx_auto_dacs(struct hda_codec *codec, hda_nid_t *dacs)
|
||||
{
|
||||
hda_nid_t nid, end_nid;
|
||||
int nums = 0;
|
||||
|
||||
end_nid = codec->start_nid + codec->num_nodes;
|
||||
for (nid = codec->start_nid; nid < end_nid; nid++) {
|
||||
unsigned int wcaps = get_wcaps(codec, nid);
|
||||
unsigned int type = get_wcaps_type(wcaps);
|
||||
if (type == AC_WID_AUD_OUT && !(wcaps & AC_WCAP_DIGITAL)) {
|
||||
dacs[nums++] = nid;
|
||||
if (nums >= MAX_AUTO_DACS)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return nums;
|
||||
}
|
||||
|
||||
/* fill pin_dac_pair list from the pin and dac list */
|
||||
static int fill_dacs_for_pins(struct hda_codec *codec, hda_nid_t *pins,
|
||||
int num_pins, hda_nid_t *dacs, int *rest,
|
||||
struct pin_dac_pair *filled, int type)
|
||||
{
|
||||
int i, nums;
|
||||
|
||||
nums = 0;
|
||||
for (i = 0; i < num_pins; i++) {
|
||||
filled[nums].pin = pins[i];
|
||||
filled[nums].type = type;
|
||||
filled[nums].dac = get_unassigned_dac(codec, pins[i], dacs, rest);
|
||||
nums++;
|
||||
}
|
||||
return nums;
|
||||
}
|
||||
|
||||
/* parse analog output paths */
|
||||
static void cx_auto_parse_output(struct hda_codec *codec)
|
||||
{
|
||||
struct conexant_spec *spec = codec->spec;
|
||||
struct auto_pin_cfg *cfg = &spec->autocfg;
|
||||
hda_nid_t dacs[MAX_AUTO_DACS];
|
||||
int i, j, nums, rest;
|
||||
|
||||
rest = fill_cx_auto_dacs(codec, dacs);
|
||||
/* parse all analog output pins */
|
||||
nums = fill_dacs_for_pins(codec, cfg->line_out_pins, cfg->line_outs,
|
||||
dacs, &rest, spec->dac_info,
|
||||
AUTO_PIN_LINE_OUT);
|
||||
nums += fill_dacs_for_pins(codec, cfg->hp_pins, cfg->hp_outs,
|
||||
dacs, &rest, spec->dac_info + nums,
|
||||
AUTO_PIN_HP_OUT);
|
||||
nums += fill_dacs_for_pins(codec, cfg->speaker_pins, cfg->speaker_outs,
|
||||
dacs, &rest, spec->dac_info + nums,
|
||||
AUTO_PIN_SPEAKER_OUT);
|
||||
spec->dac_info_filled = nums;
|
||||
/* fill multiout struct */
|
||||
for (i = 0; i < nums; i++) {
|
||||
hda_nid_t dac = spec->dac_info[i].dac;
|
||||
if (!dac)
|
||||
continue;
|
||||
switch (spec->dac_info[i].type) {
|
||||
case AUTO_PIN_LINE_OUT:
|
||||
spec->private_dac_nids[spec->multiout.num_dacs] = dac;
|
||||
spec->multiout.num_dacs++;
|
||||
break;
|
||||
case AUTO_PIN_HP_OUT:
|
||||
case AUTO_PIN_SPEAKER_OUT:
|
||||
if (!spec->multiout.hp_nid) {
|
||||
spec->multiout.hp_nid = dac;
|
||||
break;
|
||||
}
|
||||
for (j = 0; j < ARRAY_SIZE(spec->multiout.extra_out_nid); j++)
|
||||
if (!spec->multiout.extra_out_nid[j]) {
|
||||
spec->multiout.extra_out_nid[j] = dac;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
spec->multiout.dac_nids = spec->private_dac_nids;
|
||||
spec->multiout.max_channels = nums * 2;
|
||||
|
||||
if (cfg->hp_outs > 0)
|
||||
spec->auto_mute = 1;
|
||||
spec->vmaster_nid = spec->private_dac_nids[0];
|
||||
}
|
||||
|
||||
/* auto-mute/unmute speaker and line outs according to headphone jack */
|
||||
static void cx_auto_hp_automute(struct hda_codec *codec)
|
||||
{
|
||||
struct conexant_spec *spec = codec->spec;
|
||||
struct auto_pin_cfg *cfg = &spec->autocfg;
|
||||
int i, present;
|
||||
|
||||
if (!spec->auto_mute)
|
||||
return;
|
||||
present = 0;
|
||||
for (i = 0; i < cfg->hp_outs; i++) {
|
||||
if (snd_hda_jack_detect(codec, cfg->hp_pins[i])) {
|
||||
present = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < cfg->line_outs; i++) {
|
||||
snd_hda_codec_write(codec, cfg->line_out_pins[i], 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||
present ? 0 : PIN_OUT);
|
||||
}
|
||||
for (i = 0; i < cfg->speaker_outs; i++) {
|
||||
snd_hda_codec_write(codec, cfg->speaker_pins[i], 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||
present ? 0 : PIN_OUT);
|
||||
}
|
||||
}
|
||||
|
||||
/* automatic switch internal and external mic */
|
||||
static void cx_auto_automic(struct hda_codec *codec)
|
||||
{
|
||||
struct conexant_spec *spec = codec->spec;
|
||||
struct auto_pin_cfg *cfg = &spec->autocfg;
|
||||
struct hda_input_mux *imux = &spec->private_imux;
|
||||
int ext_idx = spec->auto_mic_ext;
|
||||
|
||||
if (!spec->auto_mic)
|
||||
return;
|
||||
if (snd_hda_jack_detect(codec, cfg->inputs[ext_idx].pin)) {
|
||||
snd_hda_codec_write(codec, spec->adc_nids[0], 0,
|
||||
AC_VERB_SET_CONNECT_SEL,
|
||||
imux->items[ext_idx].index);
|
||||
} else {
|
||||
snd_hda_codec_write(codec, spec->adc_nids[0], 0,
|
||||
AC_VERB_SET_CONNECT_SEL,
|
||||
imux->items[!ext_idx].index);
|
||||
}
|
||||
}
|
||||
|
||||
static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res)
|
||||
{
|
||||
int nid = (res & AC_UNSOL_RES_SUBTAG) >> 20;
|
||||
switch (res >> 26) {
|
||||
case CONEXANT_HP_EVENT:
|
||||
cx_auto_hp_automute(codec);
|
||||
conexant_report_jack(codec, nid);
|
||||
break;
|
||||
case CONEXANT_MIC_EVENT:
|
||||
cx_auto_automic(codec);
|
||||
conexant_report_jack(codec, nid);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* return true if it's an internal-mic pin */
|
||||
static int is_int_mic(struct hda_codec *codec, hda_nid_t pin)
|
||||
{
|
||||
unsigned int def_conf = snd_hda_codec_get_pincfg(codec, pin);
|
||||
return get_defcfg_device(def_conf) == AC_JACK_MIC_IN &&
|
||||
snd_hda_get_input_pin_attr(def_conf) == INPUT_PIN_ATTR_INT;
|
||||
}
|
||||
|
||||
/* return true if it's an external-mic pin */
|
||||
static int is_ext_mic(struct hda_codec *codec, hda_nid_t pin)
|
||||
{
|
||||
unsigned int def_conf = snd_hda_codec_get_pincfg(codec, pin);
|
||||
return get_defcfg_device(def_conf) == AC_JACK_MIC_IN &&
|
||||
snd_hda_get_input_pin_attr(def_conf) >= INPUT_PIN_ATTR_NORMAL &&
|
||||
(snd_hda_query_pin_caps(codec, pin) & AC_PINCAP_PRES_DETECT);
|
||||
}
|
||||
|
||||
/* check whether the pin config is suitable for auto-mic switching;
|
||||
* auto-mic is enabled only when one int-mic and one-ext mic exist
|
||||
*/
|
||||
static void cx_auto_check_auto_mic(struct hda_codec *codec)
|
||||
{
|
||||
struct conexant_spec *spec = codec->spec;
|
||||
struct auto_pin_cfg *cfg = &spec->autocfg;
|
||||
|
||||
if (is_ext_mic(codec, cfg->inputs[0].pin) &&
|
||||
is_int_mic(codec, cfg->inputs[1].pin)) {
|
||||
spec->auto_mic = 1;
|
||||
spec->auto_mic_ext = 1;
|
||||
return;
|
||||
}
|
||||
if (is_int_mic(codec, cfg->inputs[1].pin) &&
|
||||
is_ext_mic(codec, cfg->inputs[0].pin)) {
|
||||
spec->auto_mic = 1;
|
||||
spec->auto_mic_ext = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void cx_auto_parse_input(struct hda_codec *codec)
|
||||
{
|
||||
struct conexant_spec *spec = codec->spec;
|
||||
struct auto_pin_cfg *cfg = &spec->autocfg;
|
||||
struct hda_input_mux *imux;
|
||||
int i;
|
||||
|
||||
imux = &spec->private_imux;
|
||||
for (i = 0; i < cfg->num_inputs; i++) {
|
||||
int idx = get_connection_index(codec, spec->adc_nids[0],
|
||||
cfg->inputs[i].pin);
|
||||
if (idx >= 0) {
|
||||
const char *label;
|
||||
label = hda_get_autocfg_input_label(codec, cfg, i);
|
||||
snd_hda_add_imux_item(imux, label, idx, NULL);
|
||||
}
|
||||
}
|
||||
if (imux->num_items == 2 && cfg->num_inputs == 2)
|
||||
cx_auto_check_auto_mic(codec);
|
||||
if (imux->num_items > 1 && !spec->auto_mic)
|
||||
spec->input_mux = imux;
|
||||
}
|
||||
|
||||
/* get digital-input audio widget corresponding to the given pin */
|
||||
static hda_nid_t cx_auto_get_dig_in(struct hda_codec *codec, hda_nid_t pin)
|
||||
{
|
||||
hda_nid_t nid, end_nid;
|
||||
|
||||
end_nid = codec->start_nid + codec->num_nodes;
|
||||
for (nid = codec->start_nid; nid < end_nid; nid++) {
|
||||
unsigned int wcaps = get_wcaps(codec, nid);
|
||||
unsigned int type = get_wcaps_type(wcaps);
|
||||
if (type == AC_WID_AUD_IN && (wcaps & AC_WCAP_DIGITAL)) {
|
||||
if (get_connection_index(codec, nid, pin) >= 0)
|
||||
return nid;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cx_auto_parse_digital(struct hda_codec *codec)
|
||||
{
|
||||
struct conexant_spec *spec = codec->spec;
|
||||
struct auto_pin_cfg *cfg = &spec->autocfg;
|
||||
hda_nid_t nid;
|
||||
|
||||
if (cfg->dig_outs &&
|
||||
snd_hda_get_connections(codec, cfg->dig_out_pins[0], &nid, 1) == 1)
|
||||
spec->multiout.dig_out_nid = nid;
|
||||
if (cfg->dig_in_pin)
|
||||
spec->dig_in_nid = cx_auto_get_dig_in(codec, cfg->dig_in_pin);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SND_HDA_INPUT_BEEP
|
||||
static void cx_auto_parse_beep(struct hda_codec *codec)
|
||||
{
|
||||
struct conexant_spec *spec = codec->spec;
|
||||
hda_nid_t nid, end_nid;
|
||||
|
||||
end_nid = codec->start_nid + codec->num_nodes;
|
||||
for (nid = codec->start_nid; nid < end_nid; nid++)
|
||||
if (get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_BEEP) {
|
||||
set_beep_amp(spec, nid, 0, HDA_OUTPUT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define cx_auto_parse_beep(codec)
|
||||
#endif
|
||||
|
||||
static int cx_auto_parse_auto_config(struct hda_codec *codec)
|
||||
{
|
||||
struct conexant_spec *spec = codec->spec;
|
||||
int err;
|
||||
|
||||
err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
cx_auto_parse_output(codec);
|
||||
cx_auto_parse_input(codec);
|
||||
cx_auto_parse_digital(codec);
|
||||
cx_auto_parse_beep(codec);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cx_auto_turn_on_eapd(struct hda_codec *codec, int num_pins,
|
||||
hda_nid_t *pins)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < num_pins; i++) {
|
||||
if (snd_hda_query_pin_caps(codec, pins[i]) & AC_PINCAP_EAPD)
|
||||
snd_hda_codec_write(codec, pins[i], 0,
|
||||
AC_VERB_SET_EAPD_BTLENABLE, 0x02);
|
||||
}
|
||||
}
|
||||
|
||||
static void select_connection(struct hda_codec *codec, hda_nid_t pin,
|
||||
hda_nid_t src)
|
||||
{
|
||||
int idx = get_connection_index(codec, pin, src);
|
||||
if (idx >= 0)
|
||||
snd_hda_codec_write(codec, pin, 0,
|
||||
AC_VERB_SET_CONNECT_SEL, idx);
|
||||
}
|
||||
|
||||
static void cx_auto_init_output(struct hda_codec *codec)
|
||||
{
|
||||
struct conexant_spec *spec = codec->spec;
|
||||
struct auto_pin_cfg *cfg = &spec->autocfg;
|
||||
hda_nid_t nid;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < spec->multiout.num_dacs; i++)
|
||||
snd_hda_codec_write(codec, spec->multiout.dac_nids[i], 0,
|
||||
AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
|
||||
|
||||
for (i = 0; i < cfg->hp_outs; i++)
|
||||
snd_hda_codec_write(codec, cfg->hp_pins[i], 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP);
|
||||
if (spec->auto_mute) {
|
||||
for (i = 0; i < cfg->hp_outs; i++) {
|
||||
snd_hda_codec_write(codec, cfg->hp_pins[i], 0,
|
||||
AC_VERB_SET_UNSOLICITED_ENABLE,
|
||||
AC_USRSP_EN | CONEXANT_HP_EVENT);
|
||||
}
|
||||
cx_auto_hp_automute(codec);
|
||||
} else {
|
||||
for (i = 0; i < cfg->line_outs; i++)
|
||||
snd_hda_codec_write(codec, cfg->line_out_pins[i], 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
|
||||
for (i = 0; i < cfg->speaker_outs; i++)
|
||||
snd_hda_codec_write(codec, cfg->speaker_pins[i], 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
|
||||
}
|
||||
|
||||
for (i = 0; i < spec->dac_info_filled; i++) {
|
||||
nid = spec->dac_info[i].dac;
|
||||
if (!nid)
|
||||
nid = spec->multiout.dac_nids[0];
|
||||
select_connection(codec, spec->dac_info[i].pin, nid);
|
||||
}
|
||||
|
||||
/* turn on EAPD */
|
||||
cx_auto_turn_on_eapd(codec, cfg->line_outs, cfg->line_out_pins);
|
||||
cx_auto_turn_on_eapd(codec, cfg->hp_outs, cfg->hp_pins);
|
||||
cx_auto_turn_on_eapd(codec, cfg->speaker_outs, cfg->speaker_pins);
|
||||
}
|
||||
|
||||
static void cx_auto_init_input(struct hda_codec *codec)
|
||||
{
|
||||
struct conexant_spec *spec = codec->spec;
|
||||
struct auto_pin_cfg *cfg = &spec->autocfg;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < spec->num_adc_nids; i++)
|
||||
snd_hda_codec_write(codec, spec->adc_nids[i], 0,
|
||||
AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0));
|
||||
|
||||
for (i = 0; i < cfg->num_inputs; i++) {
|
||||
unsigned int type;
|
||||
if (cfg->inputs[i].type == AUTO_PIN_MIC)
|
||||
type = PIN_VREF80;
|
||||
else
|
||||
type = PIN_IN;
|
||||
snd_hda_codec_write(codec, cfg->inputs[i].pin, 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL, type);
|
||||
}
|
||||
|
||||
if (spec->auto_mic) {
|
||||
int ext_idx = spec->auto_mic_ext;
|
||||
snd_hda_codec_write(codec, cfg->inputs[ext_idx].pin, 0,
|
||||
AC_VERB_SET_UNSOLICITED_ENABLE,
|
||||
AC_USRSP_EN | CONEXANT_MIC_EVENT);
|
||||
cx_auto_automic(codec);
|
||||
} else {
|
||||
for (i = 0; i < spec->num_adc_nids; i++) {
|
||||
snd_hda_codec_write(codec, spec->adc_nids[i], 0,
|
||||
AC_VERB_SET_CONNECT_SEL,
|
||||
spec->private_imux.items[0].index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void cx_auto_init_digital(struct hda_codec *codec)
|
||||
{
|
||||
struct conexant_spec *spec = codec->spec;
|
||||
struct auto_pin_cfg *cfg = &spec->autocfg;
|
||||
|
||||
if (spec->multiout.dig_out_nid)
|
||||
snd_hda_codec_write(codec, cfg->dig_out_pins[0], 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
|
||||
if (spec->dig_in_nid)
|
||||
snd_hda_codec_write(codec, cfg->dig_in_pin, 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN);
|
||||
}
|
||||
|
||||
static int cx_auto_init(struct hda_codec *codec)
|
||||
{
|
||||
/*snd_hda_sequence_write(codec, cx_auto_init_verbs);*/
|
||||
cx_auto_init_output(codec);
|
||||
cx_auto_init_input(codec);
|
||||
cx_auto_init_digital(codec);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cx_auto_add_volume(struct hda_codec *codec, const char *basename,
|
||||
const char *dir, int cidx,
|
||||
hda_nid_t nid, int hda_dir)
|
||||
{
|
||||
static char name[32];
|
||||
static struct snd_kcontrol_new knew[] = {
|
||||
HDA_CODEC_VOLUME(name, 0, 0, 0),
|
||||
HDA_CODEC_MUTE(name, 0, 0, 0),
|
||||
};
|
||||
static char *sfx[2] = { "Volume", "Switch" };
|
||||
int i, err;
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
struct snd_kcontrol *kctl;
|
||||
knew[i].private_value = HDA_COMPOSE_AMP_VAL(nid, 3, 0, hda_dir);
|
||||
knew[i].subdevice = HDA_SUBDEV_AMP_FLAG;
|
||||
knew[i].index = cidx;
|
||||
snprintf(name, sizeof(name), "%s%s %s", basename, dir, sfx[i]);
|
||||
kctl = snd_ctl_new1(&knew[i], codec);
|
||||
if (!kctl)
|
||||
return -ENOMEM;
|
||||
err = snd_hda_ctl_add(codec, nid, kctl);
|
||||
if (err < 0)
|
||||
return err;
|
||||
if (!(query_amp_caps(codec, nid, hda_dir) & AC_AMPCAP_MUTE))
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define cx_auto_add_pb_volume(codec, nid, str, idx) \
|
||||
cx_auto_add_volume(codec, str, " Playback", idx, nid, HDA_OUTPUT)
|
||||
|
||||
static int cx_auto_build_output_controls(struct hda_codec *codec)
|
||||
{
|
||||
struct conexant_spec *spec = codec->spec;
|
||||
int i, err;
|
||||
int num_line = 0, num_hp = 0, num_spk = 0;
|
||||
static const char *texts[3] = { "Front", "Surround", "CLFE" };
|
||||
|
||||
if (spec->dac_info_filled == 1)
|
||||
return cx_auto_add_pb_volume(codec, spec->dac_info[0].dac,
|
||||
"Master", 0);
|
||||
for (i = 0; i < spec->dac_info_filled; i++) {
|
||||
const char *label;
|
||||
int idx, type;
|
||||
if (!spec->dac_info[i].dac)
|
||||
continue;
|
||||
type = spec->dac_info[i].type;
|
||||
if (type == AUTO_PIN_LINE_OUT)
|
||||
type = spec->autocfg.line_out_type;
|
||||
switch (type) {
|
||||
case AUTO_PIN_LINE_OUT:
|
||||
default:
|
||||
label = texts[num_line++];
|
||||
idx = 0;
|
||||
break;
|
||||
case AUTO_PIN_HP_OUT:
|
||||
label = "Headphone";
|
||||
idx = num_hp++;
|
||||
break;
|
||||
case AUTO_PIN_SPEAKER_OUT:
|
||||
label = "Speaker";
|
||||
idx = num_spk++;
|
||||
break;
|
||||
}
|
||||
err = cx_auto_add_pb_volume(codec, spec->dac_info[i].dac,
|
||||
label, idx);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cx_auto_build_input_controls(struct hda_codec *codec)
|
||||
{
|
||||
struct conexant_spec *spec = codec->spec;
|
||||
struct auto_pin_cfg *cfg = &spec->autocfg;
|
||||
static const char *prev_label;
|
||||
int i, err, cidx;
|
||||
|
||||
err = cx_auto_add_volume(codec, "Capture", "", 0, spec->adc_nids[0],
|
||||
HDA_INPUT);
|
||||
if (err < 0)
|
||||
return err;
|
||||
prev_label = NULL;
|
||||
cidx = 0;
|
||||
for (i = 0; i < cfg->num_inputs; i++) {
|
||||
hda_nid_t nid = cfg->inputs[i].pin;
|
||||
const char *label;
|
||||
if (!(get_wcaps(codec, nid) & AC_WCAP_IN_AMP))
|
||||
continue;
|
||||
label = hda_get_autocfg_input_label(codec, cfg, i);
|
||||
if (label == prev_label)
|
||||
cidx++;
|
||||
else
|
||||
cidx = 0;
|
||||
prev_label = label;
|
||||
err = cx_auto_add_volume(codec, label, " Capture", cidx,
|
||||
nid, HDA_INPUT);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cx_auto_build_controls(struct hda_codec *codec)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = cx_auto_build_output_controls(codec);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = cx_auto_build_input_controls(codec);
|
||||
if (err < 0)
|
||||
return err;
|
||||
return conexant_build_controls(codec);
|
||||
}
|
||||
|
||||
static struct hda_codec_ops cx_auto_patch_ops = {
|
||||
.build_controls = cx_auto_build_controls,
|
||||
.build_pcms = conexant_build_pcms,
|
||||
.init = cx_auto_init,
|
||||
.free = conexant_free,
|
||||
.unsol_event = cx_auto_unsol_event,
|
||||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
.suspend = conexant_suspend,
|
||||
#endif
|
||||
.reboot_notify = snd_hda_shutup_pins,
|
||||
};
|
||||
|
||||
static int patch_conexant_auto(struct hda_codec *codec)
|
||||
{
|
||||
struct conexant_spec *spec;
|
||||
int err;
|
||||
|
||||
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
|
||||
if (!spec)
|
||||
return -ENOMEM;
|
||||
codec->spec = spec;
|
||||
spec->adc_nids = cx_auto_adc_nids;
|
||||
spec->num_adc_nids = ARRAY_SIZE(cx_auto_adc_nids);
|
||||
spec->capsrc_nids = spec->adc_nids;
|
||||
err = cx_auto_parse_auto_config(codec);
|
||||
if (err < 0) {
|
||||
kfree(codec->spec);
|
||||
codec->spec = NULL;
|
||||
return err;
|
||||
}
|
||||
codec->patch_ops = cx_auto_patch_ops;
|
||||
if (spec->beep_amp)
|
||||
snd_hda_attach_beep_device(codec, spec->beep_amp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
*/
|
||||
|
||||
|
|
@ -3271,6 +3880,22 @@ static struct hda_codec_preset snd_hda_preset_conexant[] = {
|
|||
.patch = patch_cxt5066 },
|
||||
{ .id = 0x14f15069, .name = "CX20585",
|
||||
.patch = patch_cxt5066 },
|
||||
{ .id = 0x14f15097, .name = "CX20631",
|
||||
.patch = patch_conexant_auto },
|
||||
{ .id = 0x14f15098, .name = "CX20632",
|
||||
.patch = patch_conexant_auto },
|
||||
{ .id = 0x14f150a1, .name = "CX20641",
|
||||
.patch = patch_conexant_auto },
|
||||
{ .id = 0x14f150a2, .name = "CX20642",
|
||||
.patch = patch_conexant_auto },
|
||||
{ .id = 0x14f150ab, .name = "CX20651",
|
||||
.patch = patch_conexant_auto },
|
||||
{ .id = 0x14f150ac, .name = "CX20652",
|
||||
.patch = patch_conexant_auto },
|
||||
{ .id = 0x14f150b8, .name = "CX20664",
|
||||
.patch = patch_conexant_auto },
|
||||
{ .id = 0x14f150b9, .name = "CX20665",
|
||||
.patch = patch_conexant_auto },
|
||||
{} /* terminator */
|
||||
};
|
||||
|
||||
|
|
@ -3281,6 +3906,14 @@ MODULE_ALIAS("snd-hda-codec-id:14f15066");
|
|||
MODULE_ALIAS("snd-hda-codec-id:14f15067");
|
||||
MODULE_ALIAS("snd-hda-codec-id:14f15068");
|
||||
MODULE_ALIAS("snd-hda-codec-id:14f15069");
|
||||
MODULE_ALIAS("snd-hda-codec-id:14f15097");
|
||||
MODULE_ALIAS("snd-hda-codec-id:14f15098");
|
||||
MODULE_ALIAS("snd-hda-codec-id:14f150a1");
|
||||
MODULE_ALIAS("snd-hda-codec-id:14f150a2");
|
||||
MODULE_ALIAS("snd-hda-codec-id:14f150ab");
|
||||
MODULE_ALIAS("snd-hda-codec-id:14f150ac");
|
||||
MODULE_ALIAS("snd-hda-codec-id:14f150b8");
|
||||
MODULE_ALIAS("snd-hda-codec-id:14f150b9");
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("Conexant HD-audio codec");
|
||||
|
|
|
|||
|
|
@ -3,6 +3,9 @@
|
|||
* patch_hdmi.c - routines for HDMI/DisplayPort codecs
|
||||
*
|
||||
* Copyright(c) 2008-2010 Intel Corporation. All rights reserved.
|
||||
* Copyright (c) 2006 ATI Technologies Inc.
|
||||
* Copyright (c) 2008 NVIDIA Corp. All rights reserved.
|
||||
* Copyright (c) 2008 Wei Ni <wni@nvidia.com>
|
||||
*
|
||||
* Authors:
|
||||
* Wu Fengguang <wfg@linux.intel.com>
|
||||
|
|
@ -25,6 +28,22 @@
|
|||
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <sound/core.h>
|
||||
#include "hda_codec.h"
|
||||
#include "hda_local.h"
|
||||
|
||||
/*
|
||||
* The HDMI/DisplayPort configuration can be highly dynamic. A graphics device
|
||||
* could support two independent pipes, each of them can be connected to one or
|
||||
* more ports (DVI, HDMI or DisplayPort).
|
||||
*
|
||||
* The HDA correspondence of pipes/ports are converter/pin nodes.
|
||||
*/
|
||||
#define MAX_HDMI_CVTS 3
|
||||
#define MAX_HDMI_PINS 3
|
||||
|
||||
struct hdmi_spec {
|
||||
int num_cvts;
|
||||
|
|
@ -49,10 +68,10 @@ struct hdmi_spec {
|
|||
struct hda_pcm_stream codec_pcm_pars[MAX_HDMI_CVTS];
|
||||
|
||||
/*
|
||||
* nvhdmi specific
|
||||
* ati/nvhdmi specific
|
||||
*/
|
||||
struct hda_multi_out multiout;
|
||||
unsigned int codec_type;
|
||||
struct hda_pcm_stream *pcm_playback;
|
||||
|
||||
/* misc flags */
|
||||
/* PD bit indicates only the update, not the current state */
|
||||
|
|
@ -65,13 +84,25 @@ struct hdmi_audio_infoframe {
|
|||
u8 ver; /* 0x01 */
|
||||
u8 len; /* 0x0a */
|
||||
|
||||
u8 checksum; /* PB0 */
|
||||
u8 checksum;
|
||||
|
||||
u8 CC02_CT47; /* CC in bits 0:2, CT in 4:7 */
|
||||
u8 SS01_SF24;
|
||||
u8 CXT04;
|
||||
u8 CA;
|
||||
u8 LFEPBL01_LSV36_DM_INH7;
|
||||
u8 reserved[5]; /* PB6 - PB10 */
|
||||
};
|
||||
|
||||
struct dp_audio_infoframe {
|
||||
u8 type; /* 0x84 */
|
||||
u8 len; /* 0x1b */
|
||||
u8 ver; /* 0x11 << 2 */
|
||||
|
||||
u8 CC02_CT47; /* match with HDMI infoframe from this on */
|
||||
u8 SS01_SF24;
|
||||
u8 CXT04;
|
||||
u8 CA;
|
||||
u8 LFEPBL01_LSV36_DM_INH7;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -162,7 +193,7 @@ static int hdmi_channel_mapping[0x32][8] = {
|
|||
/* 4ch */
|
||||
[0x03] = { 0x00, 0x11, 0x23, 0x32, 0x44, 0xf5, 0xf6, 0xf7 },
|
||||
/* surround41 */
|
||||
[0x09] = { 0x00, 0x11, 0x24, 0x34, 0x43, 0xf2, 0xf6, 0xf7 },
|
||||
[0x09] = { 0x00, 0x11, 0x24, 0x35, 0x42, 0xf3, 0xf6, 0xf7 },
|
||||
/* surround50 */
|
||||
[0x0a] = { 0x00, 0x11, 0x24, 0x35, 0x43, 0xf2, 0xf6, 0xf7 },
|
||||
/* surround51 */
|
||||
|
|
@ -175,7 +206,7 @@ static int hdmi_channel_mapping[0x32][8] = {
|
|||
* This is an ordered list!
|
||||
*
|
||||
* The preceding ones have better chances to be selected by
|
||||
* hdmi_setup_channel_allocation().
|
||||
* hdmi_channel_allocation().
|
||||
*/
|
||||
static struct cea_channel_speaker_allocation channel_allocations[] = {
|
||||
/* channel: 7 6 5 4 3 2 1 0 */
|
||||
|
|
@ -352,14 +383,14 @@ static void init_channel_allocations(void)
|
|||
*
|
||||
* TODO: it could select the wrong CA from multiple candidates.
|
||||
*/
|
||||
static int hdmi_setup_channel_allocation(struct hda_codec *codec, hda_nid_t nid,
|
||||
struct hdmi_audio_infoframe *ai)
|
||||
static int hdmi_channel_allocation(struct hda_codec *codec, hda_nid_t nid,
|
||||
int channels)
|
||||
{
|
||||
struct hdmi_spec *spec = codec->spec;
|
||||
struct hdmi_eld *eld;
|
||||
int i;
|
||||
int ca = 0;
|
||||
int spk_mask = 0;
|
||||
int channels = 1 + (ai->CC02_CT47 & 0x7);
|
||||
char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE];
|
||||
|
||||
/*
|
||||
|
|
@ -397,16 +428,16 @@ static int hdmi_setup_channel_allocation(struct hda_codec *codec, hda_nid_t nid,
|
|||
if (channels == channel_allocations[i].channels &&
|
||||
(spk_mask & channel_allocations[i].spk_mask) ==
|
||||
channel_allocations[i].spk_mask) {
|
||||
ai->CA = channel_allocations[i].ca_index;
|
||||
ca = channel_allocations[i].ca_index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
snd_print_channel_allocation(eld->spk_alloc, buf, sizeof(buf));
|
||||
snd_printdd("HDMI: select CA 0x%x for %d-channel allocation: %s\n",
|
||||
ai->CA, channels, buf);
|
||||
ca, channels, buf);
|
||||
|
||||
return ai->CA;
|
||||
return ca;
|
||||
}
|
||||
|
||||
static void hdmi_debug_channel_mapping(struct hda_codec *codec,
|
||||
|
|
@ -428,10 +459,9 @@ static void hdmi_debug_channel_mapping(struct hda_codec *codec,
|
|||
|
||||
static void hdmi_setup_channel_mapping(struct hda_codec *codec,
|
||||
hda_nid_t pin_nid,
|
||||
struct hdmi_audio_infoframe *ai)
|
||||
int ca)
|
||||
{
|
||||
int i;
|
||||
int ca = ai->CA;
|
||||
int err;
|
||||
|
||||
if (hdmi_channel_mapping[ca][1] == 0) {
|
||||
|
|
@ -528,41 +558,37 @@ static void hdmi_clear_dip_buffers(struct hda_codec *codec, hda_nid_t pin_nid)
|
|||
#endif
|
||||
}
|
||||
|
||||
static void hdmi_checksum_audio_infoframe(struct hdmi_audio_infoframe *ai)
|
||||
static void hdmi_checksum_audio_infoframe(struct hdmi_audio_infoframe *hdmi_ai)
|
||||
{
|
||||
u8 *bytes = (u8 *)ai;
|
||||
u8 *bytes = (u8 *)hdmi_ai;
|
||||
u8 sum = 0;
|
||||
int i;
|
||||
|
||||
ai->checksum = 0;
|
||||
hdmi_ai->checksum = 0;
|
||||
|
||||
for (i = 0; i < sizeof(*ai); i++)
|
||||
for (i = 0; i < sizeof(*hdmi_ai); i++)
|
||||
sum += bytes[i];
|
||||
|
||||
ai->checksum = -sum;
|
||||
hdmi_ai->checksum = -sum;
|
||||
}
|
||||
|
||||
static void hdmi_fill_audio_infoframe(struct hda_codec *codec,
|
||||
hda_nid_t pin_nid,
|
||||
struct hdmi_audio_infoframe *ai)
|
||||
u8 *dip, int size)
|
||||
{
|
||||
u8 *bytes = (u8 *)ai;
|
||||
int i;
|
||||
|
||||
hdmi_debug_dip_size(codec, pin_nid);
|
||||
hdmi_clear_dip_buffers(codec, pin_nid); /* be paranoid */
|
||||
|
||||
hdmi_checksum_audio_infoframe(ai);
|
||||
|
||||
hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0);
|
||||
for (i = 0; i < sizeof(*ai); i++)
|
||||
hdmi_write_dip_byte(codec, pin_nid, bytes[i]);
|
||||
for (i = 0; i < size; i++)
|
||||
hdmi_write_dip_byte(codec, pin_nid, dip[i]);
|
||||
}
|
||||
|
||||
static bool hdmi_infoframe_uptodate(struct hda_codec *codec, hda_nid_t pin_nid,
|
||||
struct hdmi_audio_infoframe *ai)
|
||||
u8 *dip, int size)
|
||||
{
|
||||
u8 *bytes = (u8 *)ai;
|
||||
u8 val;
|
||||
int i;
|
||||
|
||||
|
|
@ -571,10 +597,10 @@ static bool hdmi_infoframe_uptodate(struct hda_codec *codec, hda_nid_t pin_nid,
|
|||
return false;
|
||||
|
||||
hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0);
|
||||
for (i = 0; i < sizeof(*ai); i++) {
|
||||
for (i = 0; i < size; i++) {
|
||||
val = snd_hda_codec_read(codec, pin_nid, 0,
|
||||
AC_VERB_GET_HDMI_DIP_DATA, 0);
|
||||
if (val != bytes[i])
|
||||
if (val != dip[i])
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -586,15 +612,13 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid,
|
|||
{
|
||||
struct hdmi_spec *spec = codec->spec;
|
||||
hda_nid_t pin_nid;
|
||||
int channels = substream->runtime->channels;
|
||||
int ca;
|
||||
int i;
|
||||
struct hdmi_audio_infoframe ai = {
|
||||
.type = 0x84,
|
||||
.ver = 0x01,
|
||||
.len = 0x0a,
|
||||
.CC02_CT47 = substream->runtime->channels - 1,
|
||||
};
|
||||
u8 ai[max(sizeof(struct hdmi_audio_infoframe),
|
||||
sizeof(struct dp_audio_infoframe))];
|
||||
|
||||
hdmi_setup_channel_allocation(codec, nid, &ai);
|
||||
ca = hdmi_channel_allocation(codec, nid, channels);
|
||||
|
||||
for (i = 0; i < spec->num_pins; i++) {
|
||||
if (spec->pin_cvt[i] != nid)
|
||||
|
|
@ -603,14 +627,45 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid,
|
|||
continue;
|
||||
|
||||
pin_nid = spec->pin[i];
|
||||
if (!hdmi_infoframe_uptodate(codec, pin_nid, &ai)) {
|
||||
|
||||
memset(ai, 0, sizeof(ai));
|
||||
if (spec->sink_eld[i].conn_type == 0) { /* HDMI */
|
||||
struct hdmi_audio_infoframe *hdmi_ai;
|
||||
|
||||
hdmi_ai = (struct hdmi_audio_infoframe *)ai;
|
||||
hdmi_ai->type = 0x84;
|
||||
hdmi_ai->ver = 0x01;
|
||||
hdmi_ai->len = 0x0a;
|
||||
hdmi_ai->CC02_CT47 = channels - 1;
|
||||
hdmi_checksum_audio_infoframe(hdmi_ai);
|
||||
} else if (spec->sink_eld[i].conn_type == 1) { /* DisplayPort */
|
||||
struct dp_audio_infoframe *dp_ai;
|
||||
|
||||
dp_ai = (struct dp_audio_infoframe *)ai;
|
||||
dp_ai->type = 0x84;
|
||||
dp_ai->len = 0x1b;
|
||||
dp_ai->ver = 0x11 << 2;
|
||||
dp_ai->CC02_CT47 = channels - 1;
|
||||
} else {
|
||||
snd_printd("HDMI: unknown connection type at pin %d\n",
|
||||
pin_nid);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* sizeof(ai) is used instead of sizeof(*hdmi_ai) or
|
||||
* sizeof(*dp_ai) to avoid partial match/update problems when
|
||||
* the user switches between HDMI/DP monitors.
|
||||
*/
|
||||
if (!hdmi_infoframe_uptodate(codec, pin_nid, ai, sizeof(ai))) {
|
||||
snd_printdd("hdmi_setup_audio_infoframe: "
|
||||
"cvt=%d pin=%d channels=%d\n",
|
||||
nid, pin_nid,
|
||||
substream->runtime->channels);
|
||||
hdmi_setup_channel_mapping(codec, pin_nid, &ai);
|
||||
channels);
|
||||
hdmi_setup_channel_mapping(codec, pin_nid, ca);
|
||||
hdmi_stop_infoframe_trans(codec, pin_nid);
|
||||
hdmi_fill_audio_infoframe(codec, pin_nid, &ai);
|
||||
hdmi_fill_audio_infoframe(codec, pin_nid,
|
||||
ai, sizeof(ai));
|
||||
hdmi_start_infoframe_trans(codec, pin_nid);
|
||||
}
|
||||
}
|
||||
|
|
@ -791,7 +846,6 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
|
|||
/*
|
||||
* HDA/HDMI auto parsing
|
||||
*/
|
||||
|
||||
static int hdmi_read_pin_conn(struct hda_codec *codec, hda_nid_t pin_nid)
|
||||
{
|
||||
struct hdmi_spec *spec = codec->spec;
|
||||
|
|
@ -922,3 +976,664 @@ static int hdmi_parse_codec(struct hda_codec *codec)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
*/
|
||||
static char *generic_hdmi_pcm_names[MAX_HDMI_CVTS] = {
|
||||
"HDMI 0",
|
||||
"HDMI 1",
|
||||
"HDMI 2",
|
||||
};
|
||||
|
||||
/*
|
||||
* HDMI callbacks
|
||||
*/
|
||||
|
||||
static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
|
||||
struct hda_codec *codec,
|
||||
unsigned int stream_tag,
|
||||
unsigned int format,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
hdmi_set_channel_count(codec, hinfo->nid,
|
||||
substream->runtime->channels);
|
||||
|
||||
hdmi_setup_audio_infoframe(codec, hinfo->nid, substream);
|
||||
|
||||
return hdmi_setup_stream(codec, hinfo->nid, stream_tag, format);
|
||||
}
|
||||
|
||||
static struct hda_pcm_stream generic_hdmi_pcm_playback = {
|
||||
.substreams = 1,
|
||||
.channels_min = 2,
|
||||
.ops = {
|
||||
.open = hdmi_pcm_open,
|
||||
.prepare = generic_hdmi_playback_pcm_prepare,
|
||||
},
|
||||
};
|
||||
|
||||
static int generic_hdmi_build_pcms(struct hda_codec *codec)
|
||||
{
|
||||
struct hdmi_spec *spec = codec->spec;
|
||||
struct hda_pcm *info = spec->pcm_rec;
|
||||
int i;
|
||||
|
||||
codec->num_pcms = spec->num_cvts;
|
||||
codec->pcm_info = info;
|
||||
|
||||
for (i = 0; i < codec->num_pcms; i++, info++) {
|
||||
unsigned int chans;
|
||||
struct hda_pcm_stream *pstr;
|
||||
|
||||
chans = get_wcaps(codec, spec->cvt[i]);
|
||||
chans = get_wcaps_channels(chans);
|
||||
|
||||
info->name = generic_hdmi_pcm_names[i];
|
||||
info->pcm_type = HDA_PCM_TYPE_HDMI;
|
||||
pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK];
|
||||
if (spec->pcm_playback)
|
||||
*pstr = *spec->pcm_playback;
|
||||
else
|
||||
*pstr = generic_hdmi_pcm_playback;
|
||||
pstr->nid = spec->cvt[i];
|
||||
if (pstr->channels_max <= 2 && chans && chans <= 16)
|
||||
pstr->channels_max = chans;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int generic_hdmi_build_controls(struct hda_codec *codec)
|
||||
{
|
||||
struct hdmi_spec *spec = codec->spec;
|
||||
int err;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < codec->num_pcms; i++) {
|
||||
err = snd_hda_create_spdif_out_ctls(codec, spec->cvt[i]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int generic_hdmi_init(struct hda_codec *codec)
|
||||
{
|
||||
struct hdmi_spec *spec = codec->spec;
|
||||
int i;
|
||||
|
||||
for (i = 0; spec->pin[i]; i++) {
|
||||
hdmi_enable_output(codec, spec->pin[i]);
|
||||
snd_hda_codec_write(codec, spec->pin[i], 0,
|
||||
AC_VERB_SET_UNSOLICITED_ENABLE,
|
||||
AC_USRSP_EN | spec->pin[i]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void generic_hdmi_free(struct hda_codec *codec)
|
||||
{
|
||||
struct hdmi_spec *spec = codec->spec;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < spec->num_pins; i++)
|
||||
snd_hda_eld_proc_free(codec, &spec->sink_eld[i]);
|
||||
|
||||
kfree(spec);
|
||||
}
|
||||
|
||||
static 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,
|
||||
};
|
||||
|
||||
static int patch_generic_hdmi(struct hda_codec *codec)
|
||||
{
|
||||
struct hdmi_spec *spec;
|
||||
int i;
|
||||
|
||||
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
|
||||
if (spec == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
codec->spec = spec;
|
||||
if (hdmi_parse_codec(codec) < 0) {
|
||||
codec->spec = NULL;
|
||||
kfree(spec);
|
||||
return -EINVAL;
|
||||
}
|
||||
codec->patch_ops = generic_hdmi_patch_ops;
|
||||
|
||||
for (i = 0; i < spec->num_pins; i++)
|
||||
snd_hda_eld_proc_new(codec, &spec->sink_eld[i], i);
|
||||
|
||||
init_channel_allocations();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Nvidia specific implementations
|
||||
*/
|
||||
|
||||
#define Nv_VERB_SET_Channel_Allocation 0xF79
|
||||
#define Nv_VERB_SET_Info_Frame_Checksum 0xF7A
|
||||
#define Nv_VERB_SET_Audio_Protection_On 0xF98
|
||||
#define Nv_VERB_SET_Audio_Protection_Off 0xF99
|
||||
|
||||
#define nvhdmi_master_con_nid_7x 0x04
|
||||
#define nvhdmi_master_pin_nid_7x 0x05
|
||||
|
||||
static hda_nid_t nvhdmi_con_nids_7x[4] = {
|
||||
/*front, rear, clfe, rear_surr */
|
||||
0x6, 0x8, 0xa, 0xc,
|
||||
};
|
||||
|
||||
static struct hda_verb nvhdmi_basic_init_7x[] = {
|
||||
/* set audio protect on */
|
||||
{ 0x1, Nv_VERB_SET_Audio_Protection_On, 0x1},
|
||||
/* enable digital output on pin widget */
|
||||
{ 0x5, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
|
||||
{ 0x7, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
|
||||
{ 0x9, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
|
||||
{ 0xb, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
|
||||
{ 0xd, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
|
||||
{} /* terminator */
|
||||
};
|
||||
|
||||
#ifdef LIMITED_RATE_FMT_SUPPORT
|
||||
/* support only the safe format and rate */
|
||||
#define SUPPORTED_RATES SNDRV_PCM_RATE_48000
|
||||
#define SUPPORTED_MAXBPS 16
|
||||
#define SUPPORTED_FORMATS SNDRV_PCM_FMTBIT_S16_LE
|
||||
#else
|
||||
/* support all rates and formats */
|
||||
#define SUPPORTED_RATES \
|
||||
(SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
|
||||
SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |\
|
||||
SNDRV_PCM_RATE_192000)
|
||||
#define SUPPORTED_MAXBPS 24
|
||||
#define SUPPORTED_FORMATS \
|
||||
(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE)
|
||||
#endif
|
||||
|
||||
static int nvhdmi_7x_init(struct hda_codec *codec)
|
||||
{
|
||||
snd_hda_sequence_write(codec, nvhdmi_basic_init_7x);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int simple_playback_pcm_open(struct hda_pcm_stream *hinfo,
|
||||
struct hda_codec *codec,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct hdmi_spec *spec = codec->spec;
|
||||
return snd_hda_multi_out_dig_open(codec, &spec->multiout);
|
||||
}
|
||||
|
||||
static int simple_playback_pcm_close(struct hda_pcm_stream *hinfo,
|
||||
struct hda_codec *codec,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct hdmi_spec *spec = codec->spec;
|
||||
return snd_hda_multi_out_dig_close(codec, &spec->multiout);
|
||||
}
|
||||
|
||||
static int simple_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
|
||||
struct hda_codec *codec,
|
||||
unsigned int stream_tag,
|
||||
unsigned int format,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct hdmi_spec *spec = codec->spec;
|
||||
return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
|
||||
stream_tag, format, substream);
|
||||
}
|
||||
|
||||
static int nvhdmi_8ch_7x_pcm_close(struct hda_pcm_stream *hinfo,
|
||||
struct hda_codec *codec,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct hdmi_spec *spec = codec->spec;
|
||||
int i;
|
||||
|
||||
snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x,
|
||||
0, AC_VERB_SET_CHANNEL_STREAMID, 0);
|
||||
for (i = 0; i < 4; i++) {
|
||||
/* set the stream id */
|
||||
snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0,
|
||||
AC_VERB_SET_CHANNEL_STREAMID, 0);
|
||||
/* set the stream format */
|
||||
snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0,
|
||||
AC_VERB_SET_STREAM_FORMAT, 0);
|
||||
}
|
||||
|
||||
return snd_hda_multi_out_dig_close(codec, &spec->multiout);
|
||||
}
|
||||
|
||||
static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo,
|
||||
struct hda_codec *codec,
|
||||
unsigned int stream_tag,
|
||||
unsigned int format,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
int chs;
|
||||
unsigned int dataDCC1, dataDCC2, chan, chanmask, channel_id;
|
||||
int i;
|
||||
|
||||
mutex_lock(&codec->spdif_mutex);
|
||||
|
||||
chs = substream->runtime->channels;
|
||||
chan = chs ? (chs - 1) : 1;
|
||||
|
||||
switch (chs) {
|
||||
default:
|
||||
case 0:
|
||||
case 2:
|
||||
chanmask = 0x00;
|
||||
break;
|
||||
case 4:
|
||||
chanmask = 0x08;
|
||||
break;
|
||||
case 6:
|
||||
chanmask = 0x0b;
|
||||
break;
|
||||
case 8:
|
||||
chanmask = 0x13;
|
||||
break;
|
||||
}
|
||||
dataDCC1 = AC_DIG1_ENABLE | AC_DIG1_COPYRIGHT;
|
||||
dataDCC2 = 0x2;
|
||||
|
||||
/* set the Audio InforFrame Channel Allocation */
|
||||
snd_hda_codec_write(codec, 0x1, 0,
|
||||
Nv_VERB_SET_Channel_Allocation, chanmask);
|
||||
|
||||
/* turn off SPDIF once; otherwise the IEC958 bits won't be updated */
|
||||
if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE))
|
||||
snd_hda_codec_write(codec,
|
||||
nvhdmi_master_con_nid_7x,
|
||||
0,
|
||||
AC_VERB_SET_DIGI_CONVERT_1,
|
||||
codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff);
|
||||
|
||||
/* set the stream id */
|
||||
snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0,
|
||||
AC_VERB_SET_CHANNEL_STREAMID, (stream_tag << 4) | 0x0);
|
||||
|
||||
/* set the stream format */
|
||||
snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0,
|
||||
AC_VERB_SET_STREAM_FORMAT, format);
|
||||
|
||||
/* turn on again (if needed) */
|
||||
/* enable and set the channel status audio/data flag */
|
||||
if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) {
|
||||
snd_hda_codec_write(codec,
|
||||
nvhdmi_master_con_nid_7x,
|
||||
0,
|
||||
AC_VERB_SET_DIGI_CONVERT_1,
|
||||
codec->spdif_ctls & 0xff);
|
||||
snd_hda_codec_write(codec,
|
||||
nvhdmi_master_con_nid_7x,
|
||||
0,
|
||||
AC_VERB_SET_DIGI_CONVERT_2, dataDCC2);
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (chs == 2)
|
||||
channel_id = 0;
|
||||
else
|
||||
channel_id = i * 2;
|
||||
|
||||
/* turn off SPDIF once;
|
||||
*otherwise the IEC958 bits won't be updated
|
||||
*/
|
||||
if (codec->spdif_status_reset &&
|
||||
(codec->spdif_ctls & AC_DIG1_ENABLE))
|
||||
snd_hda_codec_write(codec,
|
||||
nvhdmi_con_nids_7x[i],
|
||||
0,
|
||||
AC_VERB_SET_DIGI_CONVERT_1,
|
||||
codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff);
|
||||
/* set the stream id */
|
||||
snd_hda_codec_write(codec,
|
||||
nvhdmi_con_nids_7x[i],
|
||||
0,
|
||||
AC_VERB_SET_CHANNEL_STREAMID,
|
||||
(stream_tag << 4) | channel_id);
|
||||
/* set the stream format */
|
||||
snd_hda_codec_write(codec,
|
||||
nvhdmi_con_nids_7x[i],
|
||||
0,
|
||||
AC_VERB_SET_STREAM_FORMAT,
|
||||
format);
|
||||
/* turn on again (if needed) */
|
||||
/* enable and set the channel status audio/data flag */
|
||||
if (codec->spdif_status_reset &&
|
||||
(codec->spdif_ctls & AC_DIG1_ENABLE)) {
|
||||
snd_hda_codec_write(codec,
|
||||
nvhdmi_con_nids_7x[i],
|
||||
0,
|
||||
AC_VERB_SET_DIGI_CONVERT_1,
|
||||
codec->spdif_ctls & 0xff);
|
||||
snd_hda_codec_write(codec,
|
||||
nvhdmi_con_nids_7x[i],
|
||||
0,
|
||||
AC_VERB_SET_DIGI_CONVERT_2, dataDCC2);
|
||||
}
|
||||
}
|
||||
|
||||
/* set the Audio Info Frame Checksum */
|
||||
snd_hda_codec_write(codec, 0x1, 0,
|
||||
Nv_VERB_SET_Info_Frame_Checksum,
|
||||
(0x71 - chan - chanmask));
|
||||
|
||||
mutex_unlock(&codec->spdif_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct hda_pcm_stream nvhdmi_pcm_playback_8ch_7x = {
|
||||
.substreams = 1,
|
||||
.channels_min = 2,
|
||||
.channels_max = 8,
|
||||
.nid = nvhdmi_master_con_nid_7x,
|
||||
.rates = SUPPORTED_RATES,
|
||||
.maxbps = SUPPORTED_MAXBPS,
|
||||
.formats = SUPPORTED_FORMATS,
|
||||
.ops = {
|
||||
.open = simple_playback_pcm_open,
|
||||
.close = nvhdmi_8ch_7x_pcm_close,
|
||||
.prepare = nvhdmi_8ch_7x_pcm_prepare
|
||||
},
|
||||
};
|
||||
|
||||
static struct hda_pcm_stream nvhdmi_pcm_playback_2ch = {
|
||||
.substreams = 1,
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.nid = nvhdmi_master_con_nid_7x,
|
||||
.rates = SUPPORTED_RATES,
|
||||
.maxbps = SUPPORTED_MAXBPS,
|
||||
.formats = SUPPORTED_FORMATS,
|
||||
.ops = {
|
||||
.open = simple_playback_pcm_open,
|
||||
.close = simple_playback_pcm_close,
|
||||
.prepare = simple_playback_pcm_prepare
|
||||
},
|
||||
};
|
||||
|
||||
static struct hda_codec_ops nvhdmi_patch_ops_8ch_7x = {
|
||||
.build_controls = generic_hdmi_build_controls,
|
||||
.build_pcms = generic_hdmi_build_pcms,
|
||||
.init = nvhdmi_7x_init,
|
||||
.free = generic_hdmi_free,
|
||||
};
|
||||
|
||||
static struct hda_codec_ops nvhdmi_patch_ops_2ch = {
|
||||
.build_controls = generic_hdmi_build_controls,
|
||||
.build_pcms = generic_hdmi_build_pcms,
|
||||
.init = nvhdmi_7x_init,
|
||||
.free = generic_hdmi_free,
|
||||
};
|
||||
|
||||
static int patch_nvhdmi_8ch_89(struct hda_codec *codec)
|
||||
{
|
||||
struct hdmi_spec *spec;
|
||||
int err = patch_generic_hdmi(codec);
|
||||
|
||||
if (err < 0)
|
||||
return err;
|
||||
spec = codec->spec;
|
||||
spec->old_pin_detect = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int patch_nvhdmi_2ch(struct hda_codec *codec)
|
||||
{
|
||||
struct hdmi_spec *spec;
|
||||
|
||||
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
|
||||
if (spec == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
codec->spec = spec;
|
||||
|
||||
spec->multiout.num_dacs = 0; /* no analog */
|
||||
spec->multiout.max_channels = 2;
|
||||
spec->multiout.dig_out_nid = nvhdmi_master_con_nid_7x;
|
||||
spec->old_pin_detect = 1;
|
||||
spec->num_cvts = 1;
|
||||
spec->cvt[0] = nvhdmi_master_con_nid_7x;
|
||||
spec->pcm_playback = &nvhdmi_pcm_playback_2ch;
|
||||
|
||||
codec->patch_ops = nvhdmi_patch_ops_2ch;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int patch_nvhdmi_8ch_7x(struct hda_codec *codec)
|
||||
{
|
||||
struct hdmi_spec *spec;
|
||||
int err = patch_nvhdmi_2ch(codec);
|
||||
|
||||
if (err < 0)
|
||||
return err;
|
||||
spec = codec->spec;
|
||||
spec->multiout.max_channels = 8;
|
||||
spec->pcm_playback = &nvhdmi_pcm_playback_8ch_7x;
|
||||
codec->patch_ops = nvhdmi_patch_ops_8ch_7x;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ATI-specific implementations
|
||||
*
|
||||
* FIXME: we may omit the whole this and use the generic code once after
|
||||
* it's confirmed to work.
|
||||
*/
|
||||
|
||||
#define ATIHDMI_CVT_NID 0x02 /* audio converter */
|
||||
#define ATIHDMI_PIN_NID 0x03 /* HDMI output pin */
|
||||
|
||||
static int atihdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
|
||||
struct hda_codec *codec,
|
||||
unsigned int stream_tag,
|
||||
unsigned int format,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct hdmi_spec *spec = codec->spec;
|
||||
int chans = substream->runtime->channels;
|
||||
int i, err;
|
||||
|
||||
err = simple_playback_pcm_prepare(hinfo, codec, stream_tag, format,
|
||||
substream);
|
||||
if (err < 0)
|
||||
return err;
|
||||
snd_hda_codec_write(codec, spec->cvt[0], 0, AC_VERB_SET_CVT_CHAN_COUNT,
|
||||
chans - 1);
|
||||
/* FIXME: XXX */
|
||||
for (i = 0; i < chans; i++) {
|
||||
snd_hda_codec_write(codec, spec->cvt[0], 0,
|
||||
AC_VERB_SET_HDMI_CHAN_SLOT,
|
||||
(i << 4) | i);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct hda_pcm_stream atihdmi_pcm_digital_playback = {
|
||||
.substreams = 1,
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.nid = ATIHDMI_CVT_NID,
|
||||
.ops = {
|
||||
.open = simple_playback_pcm_open,
|
||||
.close = simple_playback_pcm_close,
|
||||
.prepare = atihdmi_playback_pcm_prepare
|
||||
},
|
||||
};
|
||||
|
||||
static struct hda_verb atihdmi_basic_init[] = {
|
||||
/* enable digital output on pin widget */
|
||||
{ 0x03, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
|
||||
{} /* terminator */
|
||||
};
|
||||
|
||||
static int atihdmi_init(struct hda_codec *codec)
|
||||
{
|
||||
struct hdmi_spec *spec = codec->spec;
|
||||
|
||||
snd_hda_sequence_write(codec, atihdmi_basic_init);
|
||||
/* SI codec requires to unmute the pin */
|
||||
if (get_wcaps(codec, spec->pin[0]) & AC_WCAP_OUT_AMP)
|
||||
snd_hda_codec_write(codec, spec->pin[0], 0,
|
||||
AC_VERB_SET_AMP_GAIN_MUTE,
|
||||
AMP_OUT_UNMUTE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct hda_codec_ops atihdmi_patch_ops = {
|
||||
.build_controls = generic_hdmi_build_controls,
|
||||
.build_pcms = generic_hdmi_build_pcms,
|
||||
.init = atihdmi_init,
|
||||
.free = generic_hdmi_free,
|
||||
};
|
||||
|
||||
|
||||
static int patch_atihdmi(struct hda_codec *codec)
|
||||
{
|
||||
struct hdmi_spec *spec;
|
||||
|
||||
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
|
||||
if (spec == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
codec->spec = spec;
|
||||
|
||||
spec->multiout.num_dacs = 0; /* no analog */
|
||||
spec->multiout.max_channels = 2;
|
||||
spec->multiout.dig_out_nid = ATIHDMI_CVT_NID;
|
||||
spec->num_cvts = 1;
|
||||
spec->cvt[0] = ATIHDMI_CVT_NID;
|
||||
spec->pin[0] = ATIHDMI_PIN_NID;
|
||||
spec->pcm_playback = &atihdmi_pcm_digital_playback;
|
||||
|
||||
codec->patch_ops = atihdmi_patch_ops;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* patch entries
|
||||
*/
|
||||
static struct hda_codec_preset snd_hda_preset_hdmi[] = {
|
||||
{ .id = 0x1002793c, .name = "RS600 HDMI", .patch = patch_atihdmi },
|
||||
{ .id = 0x10027919, .name = "RS600 HDMI", .patch = patch_atihdmi },
|
||||
{ .id = 0x1002791a, .name = "RS690/780 HDMI", .patch = patch_atihdmi },
|
||||
{ .id = 0x1002aa01, .name = "R6xx HDMI", .patch = patch_atihdmi },
|
||||
{ .id = 0x10951390, .name = "SiI1390 HDMI", .patch = patch_generic_hdmi },
|
||||
{ .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_generic_hdmi },
|
||||
{ .id = 0x17e80047, .name = "Chrontel HDMI", .patch = patch_generic_hdmi },
|
||||
{ .id = 0x10de0002, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x },
|
||||
{ .id = 0x10de0003, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x },
|
||||
{ .id = 0x10de0005, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x },
|
||||
{ .id = 0x10de0006, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x },
|
||||
{ .id = 0x10de0007, .name = "MCP79/7A HDMI", .patch = patch_nvhdmi_8ch_7x },
|
||||
{ .id = 0x10de000a, .name = "GPU 0a HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
|
||||
{ .id = 0x10de000b, .name = "GPU 0b HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
|
||||
{ .id = 0x10de000c, .name = "MCP89 HDMI", .patch = patch_nvhdmi_8ch_89 },
|
||||
{ .id = 0x10de000d, .name = "GPU 0d HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
|
||||
{ .id = 0x10de0010, .name = "GPU 10 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
|
||||
{ .id = 0x10de0011, .name = "GPU 11 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
|
||||
{ .id = 0x10de0012, .name = "GPU 12 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
|
||||
{ .id = 0x10de0013, .name = "GPU 13 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
|
||||
{ .id = 0x10de0014, .name = "GPU 14 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
|
||||
{ .id = 0x10de0018, .name = "GPU 18 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
|
||||
{ .id = 0x10de0019, .name = "GPU 19 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
|
||||
{ .id = 0x10de001a, .name = "GPU 1a HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
|
||||
{ .id = 0x10de001b, .name = "GPU 1b HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
|
||||
{ .id = 0x10de001c, .name = "GPU 1c HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
|
||||
{ .id = 0x10de0040, .name = "GPU 40 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
|
||||
{ .id = 0x10de0041, .name = "GPU 41 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
|
||||
{ .id = 0x10de0042, .name = "GPU 42 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
|
||||
{ .id = 0x10de0043, .name = "GPU 43 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
|
||||
{ .id = 0x10de0044, .name = "GPU 44 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
|
||||
{ .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi_2ch },
|
||||
{ .id = 0x10de8001, .name = "MCP73 HDMI", .patch = patch_nvhdmi_2ch },
|
||||
{ .id = 0x80860054, .name = "IbexPeak HDMI", .patch = patch_generic_hdmi },
|
||||
{ .id = 0x80862801, .name = "Bearlake HDMI", .patch = patch_generic_hdmi },
|
||||
{ .id = 0x80862802, .name = "Cantiga HDMI", .patch = patch_generic_hdmi },
|
||||
{ .id = 0x80862803, .name = "Eaglelake HDMI", .patch = patch_generic_hdmi },
|
||||
{ .id = 0x80862804, .name = "IbexPeak HDMI", .patch = patch_generic_hdmi },
|
||||
{ .id = 0x80862805, .name = "CougarPoint HDMI", .patch = patch_generic_hdmi },
|
||||
{ .id = 0x808629fb, .name = "Crestline HDMI", .patch = patch_generic_hdmi },
|
||||
{} /* terminator */
|
||||
};
|
||||
|
||||
MODULE_ALIAS("snd-hda-codec-id:1002793c");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10027919");
|
||||
MODULE_ALIAS("snd-hda-codec-id:1002791a");
|
||||
MODULE_ALIAS("snd-hda-codec-id:1002aa01");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10951390");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10951392");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de0002");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de0003");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de0005");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de0006");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de0007");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de000a");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de000b");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de000c");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de000d");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de0010");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de0011");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de0012");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de0013");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de0014");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de0018");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de0019");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de001a");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de001b");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de001c");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de0040");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de0041");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de0042");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de0043");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de0044");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de0067");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de8001");
|
||||
MODULE_ALIAS("snd-hda-codec-id:17e80047");
|
||||
MODULE_ALIAS("snd-hda-codec-id:80860054");
|
||||
MODULE_ALIAS("snd-hda-codec-id:80862801");
|
||||
MODULE_ALIAS("snd-hda-codec-id:80862802");
|
||||
MODULE_ALIAS("snd-hda-codec-id:80862803");
|
||||
MODULE_ALIAS("snd-hda-codec-id:80862804");
|
||||
MODULE_ALIAS("snd-hda-codec-id:80862805");
|
||||
MODULE_ALIAS("snd-hda-codec-id:808629fb");
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("HDMI HD-audio codec");
|
||||
MODULE_ALIAS("snd-hda-codec-intelhdmi");
|
||||
MODULE_ALIAS("snd-hda-codec-nvhdmi");
|
||||
MODULE_ALIAS("snd-hda-codec-atihdmi");
|
||||
|
||||
static struct hda_codec_preset_list intel_list = {
|
||||
.preset = snd_hda_preset_hdmi,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init patch_hdmi_init(void)
|
||||
{
|
||||
return snd_hda_add_codec_preset(&intel_list);
|
||||
}
|
||||
|
||||
static void __exit patch_hdmi_exit(void)
|
||||
{
|
||||
snd_hda_delete_codec_preset(&intel_list);
|
||||
}
|
||||
|
||||
module_init(patch_hdmi_init)
|
||||
module_exit(patch_hdmi_exit)
|
||||
|
|
|
|||
|
|
@ -1,220 +0,0 @@
|
|||
/*
|
||||
*
|
||||
* patch_intelhdmi.c - Patch for Intel HDMI codecs
|
||||
*
|
||||
* Copyright(c) 2008 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* Authors:
|
||||
* Jiang Zhe <zhe.jiang@intel.com>
|
||||
* Wu Fengguang <wfg@linux.intel.com>
|
||||
*
|
||||
* Maintained by:
|
||||
* Wu Fengguang <wfg@linux.intel.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (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/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <sound/core.h>
|
||||
#include "hda_codec.h"
|
||||
#include "hda_local.h"
|
||||
|
||||
/*
|
||||
* The HDMI/DisplayPort configuration can be highly dynamic. A graphics device
|
||||
* could support two independent pipes, each of them can be connected to one or
|
||||
* more ports (DVI, HDMI or DisplayPort).
|
||||
*
|
||||
* The HDA correspondence of pipes/ports are converter/pin nodes.
|
||||
*/
|
||||
#define MAX_HDMI_CVTS 3
|
||||
#define MAX_HDMI_PINS 3
|
||||
|
||||
#include "patch_hdmi.c"
|
||||
|
||||
static char *intel_hdmi_pcm_names[MAX_HDMI_CVTS] = {
|
||||
"INTEL HDMI 0",
|
||||
"INTEL HDMI 1",
|
||||
"INTEL HDMI 2",
|
||||
};
|
||||
|
||||
/*
|
||||
* HDMI callbacks
|
||||
*/
|
||||
|
||||
static int intel_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
|
||||
struct hda_codec *codec,
|
||||
unsigned int stream_tag,
|
||||
unsigned int format,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
hdmi_set_channel_count(codec, hinfo->nid,
|
||||
substream->runtime->channels);
|
||||
|
||||
hdmi_setup_audio_infoframe(codec, hinfo->nid, substream);
|
||||
|
||||
return hdmi_setup_stream(codec, hinfo->nid, stream_tag, format);
|
||||
}
|
||||
|
||||
static struct hda_pcm_stream intel_hdmi_pcm_playback = {
|
||||
.substreams = 1,
|
||||
.channels_min = 2,
|
||||
.ops = {
|
||||
.open = hdmi_pcm_open,
|
||||
.prepare = intel_hdmi_playback_pcm_prepare,
|
||||
},
|
||||
};
|
||||
|
||||
static int intel_hdmi_build_pcms(struct hda_codec *codec)
|
||||
{
|
||||
struct hdmi_spec *spec = codec->spec;
|
||||
struct hda_pcm *info = spec->pcm_rec;
|
||||
int i;
|
||||
|
||||
codec->num_pcms = spec->num_cvts;
|
||||
codec->pcm_info = info;
|
||||
|
||||
for (i = 0; i < codec->num_pcms; i++, info++) {
|
||||
unsigned int chans;
|
||||
|
||||
chans = get_wcaps(codec, spec->cvt[i]);
|
||||
chans = get_wcaps_channels(chans);
|
||||
|
||||
info->name = intel_hdmi_pcm_names[i];
|
||||
info->pcm_type = HDA_PCM_TYPE_HDMI;
|
||||
info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
|
||||
intel_hdmi_pcm_playback;
|
||||
info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->cvt[i];
|
||||
info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = chans;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int intel_hdmi_build_controls(struct hda_codec *codec)
|
||||
{
|
||||
struct hdmi_spec *spec = codec->spec;
|
||||
int err;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < codec->num_pcms; i++) {
|
||||
err = snd_hda_create_spdif_out_ctls(codec, spec->cvt[i]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int intel_hdmi_init(struct hda_codec *codec)
|
||||
{
|
||||
struct hdmi_spec *spec = codec->spec;
|
||||
int i;
|
||||
|
||||
for (i = 0; spec->pin[i]; i++) {
|
||||
hdmi_enable_output(codec, spec->pin[i]);
|
||||
snd_hda_codec_write(codec, spec->pin[i], 0,
|
||||
AC_VERB_SET_UNSOLICITED_ENABLE,
|
||||
AC_USRSP_EN | spec->pin[i]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void intel_hdmi_free(struct hda_codec *codec)
|
||||
{
|
||||
struct hdmi_spec *spec = codec->spec;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < spec->num_pins; i++)
|
||||
snd_hda_eld_proc_free(codec, &spec->sink_eld[i]);
|
||||
|
||||
kfree(spec);
|
||||
}
|
||||
|
||||
static struct hda_codec_ops intel_hdmi_patch_ops = {
|
||||
.init = intel_hdmi_init,
|
||||
.free = intel_hdmi_free,
|
||||
.build_pcms = intel_hdmi_build_pcms,
|
||||
.build_controls = intel_hdmi_build_controls,
|
||||
.unsol_event = hdmi_unsol_event,
|
||||
};
|
||||
|
||||
static int patch_intel_hdmi(struct hda_codec *codec)
|
||||
{
|
||||
struct hdmi_spec *spec;
|
||||
int i;
|
||||
|
||||
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
|
||||
if (spec == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
codec->spec = spec;
|
||||
if (hdmi_parse_codec(codec) < 0) {
|
||||
codec->spec = NULL;
|
||||
kfree(spec);
|
||||
return -EINVAL;
|
||||
}
|
||||
codec->patch_ops = intel_hdmi_patch_ops;
|
||||
|
||||
for (i = 0; i < spec->num_pins; i++)
|
||||
snd_hda_eld_proc_new(codec, &spec->sink_eld[i], i);
|
||||
|
||||
init_channel_allocations();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct hda_codec_preset snd_hda_preset_intelhdmi[] = {
|
||||
{ .id = 0x808629fb, .name = "Crestline HDMI", .patch = patch_intel_hdmi },
|
||||
{ .id = 0x80862801, .name = "Bearlake HDMI", .patch = patch_intel_hdmi },
|
||||
{ .id = 0x80862802, .name = "Cantiga HDMI", .patch = patch_intel_hdmi },
|
||||
{ .id = 0x80862803, .name = "Eaglelake HDMI", .patch = patch_intel_hdmi },
|
||||
{ .id = 0x80862804, .name = "IbexPeak HDMI", .patch = patch_intel_hdmi },
|
||||
{ .id = 0x80860054, .name = "IbexPeak HDMI", .patch = patch_intel_hdmi },
|
||||
{ .id = 0x80862805, .name = "CougarPoint HDMI", .patch = patch_intel_hdmi },
|
||||
{ .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_intel_hdmi },
|
||||
{} /* terminator */
|
||||
};
|
||||
|
||||
MODULE_ALIAS("snd-hda-codec-id:808629fb");
|
||||
MODULE_ALIAS("snd-hda-codec-id:80862801");
|
||||
MODULE_ALIAS("snd-hda-codec-id:80862802");
|
||||
MODULE_ALIAS("snd-hda-codec-id:80862803");
|
||||
MODULE_ALIAS("snd-hda-codec-id:80862804");
|
||||
MODULE_ALIAS("snd-hda-codec-id:80862805");
|
||||
MODULE_ALIAS("snd-hda-codec-id:80860054");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10951392");
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("Intel HDMI HD-audio codec");
|
||||
|
||||
static struct hda_codec_preset_list intel_list = {
|
||||
.preset = snd_hda_preset_intelhdmi,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init patch_intelhdmi_init(void)
|
||||
{
|
||||
return snd_hda_add_codec_preset(&intel_list);
|
||||
}
|
||||
|
||||
static void __exit patch_intelhdmi_exit(void)
|
||||
{
|
||||
snd_hda_delete_codec_preset(&intel_list);
|
||||
}
|
||||
|
||||
module_init(patch_intelhdmi_init)
|
||||
module_exit(patch_intelhdmi_exit)
|
||||
|
|
@ -1,608 +0,0 @@
|
|||
/*
|
||||
* Universal Interface for Intel High Definition Audio Codec
|
||||
*
|
||||
* HD audio interface patch for NVIDIA HDMI codecs
|
||||
*
|
||||
* Copyright (c) 2008 NVIDIA Corp. All rights reserved.
|
||||
* Copyright (c) 2008 Wei Ni <wni@nvidia.com>
|
||||
*
|
||||
*
|
||||
* This driver is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This driver is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <sound/core.h>
|
||||
#include "hda_codec.h"
|
||||
#include "hda_local.h"
|
||||
|
||||
#define MAX_HDMI_CVTS 1
|
||||
#define MAX_HDMI_PINS 1
|
||||
|
||||
#include "patch_hdmi.c"
|
||||
|
||||
static char *nvhdmi_pcm_names[MAX_HDMI_CVTS] = {
|
||||
"NVIDIA HDMI",
|
||||
};
|
||||
|
||||
/* define below to restrict the supported rates and formats */
|
||||
/* #define LIMITED_RATE_FMT_SUPPORT */
|
||||
|
||||
enum HDACodec {
|
||||
HDA_CODEC_NVIDIA_MCP7X,
|
||||
HDA_CODEC_NVIDIA_MCP89,
|
||||
HDA_CODEC_NVIDIA_GT21X,
|
||||
HDA_CODEC_INVALID
|
||||
};
|
||||
|
||||
#define Nv_VERB_SET_Channel_Allocation 0xF79
|
||||
#define Nv_VERB_SET_Info_Frame_Checksum 0xF7A
|
||||
#define Nv_VERB_SET_Audio_Protection_On 0xF98
|
||||
#define Nv_VERB_SET_Audio_Protection_Off 0xF99
|
||||
|
||||
#define nvhdmi_master_con_nid_7x 0x04
|
||||
#define nvhdmi_master_pin_nid_7x 0x05
|
||||
|
||||
#define nvhdmi_master_con_nid_89 0x04
|
||||
#define nvhdmi_master_pin_nid_89 0x05
|
||||
|
||||
static hda_nid_t nvhdmi_con_nids_7x[4] = {
|
||||
/*front, rear, clfe, rear_surr */
|
||||
0x6, 0x8, 0xa, 0xc,
|
||||
};
|
||||
|
||||
static struct hda_verb nvhdmi_basic_init_7x[] = {
|
||||
/* set audio protect on */
|
||||
{ 0x1, Nv_VERB_SET_Audio_Protection_On, 0x1},
|
||||
/* enable digital output on pin widget */
|
||||
{ 0x5, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
|
||||
{ 0x7, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
|
||||
{ 0x9, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
|
||||
{ 0xb, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
|
||||
{ 0xd, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
|
||||
{} /* terminator */
|
||||
};
|
||||
|
||||
#ifdef LIMITED_RATE_FMT_SUPPORT
|
||||
/* support only the safe format and rate */
|
||||
#define SUPPORTED_RATES SNDRV_PCM_RATE_48000
|
||||
#define SUPPORTED_MAXBPS 16
|
||||
#define SUPPORTED_FORMATS SNDRV_PCM_FMTBIT_S16_LE
|
||||
#else
|
||||
/* support all rates and formats */
|
||||
#define SUPPORTED_RATES \
|
||||
(SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
|
||||
SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |\
|
||||
SNDRV_PCM_RATE_192000)
|
||||
#define SUPPORTED_MAXBPS 24
|
||||
#define SUPPORTED_FORMATS \
|
||||
(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Controls
|
||||
*/
|
||||
static int nvhdmi_build_controls(struct hda_codec *codec)
|
||||
{
|
||||
struct hdmi_spec *spec = codec->spec;
|
||||
int err;
|
||||
int i;
|
||||
|
||||
if ((spec->codec_type == HDA_CODEC_NVIDIA_MCP89)
|
||||
|| (spec->codec_type == HDA_CODEC_NVIDIA_GT21X)) {
|
||||
for (i = 0; i < codec->num_pcms; i++) {
|
||||
err = snd_hda_create_spdif_out_ctls(codec,
|
||||
spec->cvt[i]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
} else {
|
||||
err = snd_hda_create_spdif_out_ctls(codec,
|
||||
spec->multiout.dig_out_nid);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nvhdmi_init(struct hda_codec *codec)
|
||||
{
|
||||
struct hdmi_spec *spec = codec->spec;
|
||||
int i;
|
||||
if ((spec->codec_type == HDA_CODEC_NVIDIA_MCP89)
|
||||
|| (spec->codec_type == HDA_CODEC_NVIDIA_GT21X)) {
|
||||
for (i = 0; spec->pin[i]; i++) {
|
||||
hdmi_enable_output(codec, spec->pin[i]);
|
||||
snd_hda_codec_write(codec, spec->pin[i], 0,
|
||||
AC_VERB_SET_UNSOLICITED_ENABLE,
|
||||
AC_USRSP_EN | spec->pin[i]);
|
||||
}
|
||||
} else {
|
||||
snd_hda_sequence_write(codec, nvhdmi_basic_init_7x);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void nvhdmi_free(struct hda_codec *codec)
|
||||
{
|
||||
struct hdmi_spec *spec = codec->spec;
|
||||
int i;
|
||||
|
||||
if ((spec->codec_type == HDA_CODEC_NVIDIA_MCP89)
|
||||
|| (spec->codec_type == HDA_CODEC_NVIDIA_GT21X)) {
|
||||
for (i = 0; i < spec->num_pins; i++)
|
||||
snd_hda_eld_proc_free(codec, &spec->sink_eld[i]);
|
||||
}
|
||||
|
||||
kfree(spec);
|
||||
}
|
||||
|
||||
/*
|
||||
* Digital out
|
||||
*/
|
||||
static int nvhdmi_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
|
||||
struct hda_codec *codec,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct hdmi_spec *spec = codec->spec;
|
||||
return snd_hda_multi_out_dig_open(codec, &spec->multiout);
|
||||
}
|
||||
|
||||
static int nvhdmi_dig_playback_pcm_close_8ch_7x(struct hda_pcm_stream *hinfo,
|
||||
struct hda_codec *codec,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct hdmi_spec *spec = codec->spec;
|
||||
int i;
|
||||
|
||||
snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x,
|
||||
0, AC_VERB_SET_CHANNEL_STREAMID, 0);
|
||||
for (i = 0; i < 4; i++) {
|
||||
/* set the stream id */
|
||||
snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0,
|
||||
AC_VERB_SET_CHANNEL_STREAMID, 0);
|
||||
/* set the stream format */
|
||||
snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0,
|
||||
AC_VERB_SET_STREAM_FORMAT, 0);
|
||||
}
|
||||
|
||||
return snd_hda_multi_out_dig_close(codec, &spec->multiout);
|
||||
}
|
||||
|
||||
static int nvhdmi_dig_playback_pcm_close_2ch(struct hda_pcm_stream *hinfo,
|
||||
struct hda_codec *codec,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct hdmi_spec *spec = codec->spec;
|
||||
return snd_hda_multi_out_dig_close(codec, &spec->multiout);
|
||||
}
|
||||
|
||||
static int nvhdmi_dig_playback_pcm_prepare_8ch_89(struct hda_pcm_stream *hinfo,
|
||||
struct hda_codec *codec,
|
||||
unsigned int stream_tag,
|
||||
unsigned int format,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
hdmi_set_channel_count(codec, hinfo->nid,
|
||||
substream->runtime->channels);
|
||||
|
||||
hdmi_setup_audio_infoframe(codec, hinfo->nid, substream);
|
||||
|
||||
return hdmi_setup_stream(codec, hinfo->nid, stream_tag, format);
|
||||
}
|
||||
|
||||
static int nvhdmi_dig_playback_pcm_prepare_8ch(struct hda_pcm_stream *hinfo,
|
||||
struct hda_codec *codec,
|
||||
unsigned int stream_tag,
|
||||
unsigned int format,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
int chs;
|
||||
unsigned int dataDCC1, dataDCC2, chan, chanmask, channel_id;
|
||||
int i;
|
||||
|
||||
mutex_lock(&codec->spdif_mutex);
|
||||
|
||||
chs = substream->runtime->channels;
|
||||
chan = chs ? (chs - 1) : 1;
|
||||
|
||||
switch (chs) {
|
||||
default:
|
||||
case 0:
|
||||
case 2:
|
||||
chanmask = 0x00;
|
||||
break;
|
||||
case 4:
|
||||
chanmask = 0x08;
|
||||
break;
|
||||
case 6:
|
||||
chanmask = 0x0b;
|
||||
break;
|
||||
case 8:
|
||||
chanmask = 0x13;
|
||||
break;
|
||||
}
|
||||
dataDCC1 = AC_DIG1_ENABLE | AC_DIG1_COPYRIGHT;
|
||||
dataDCC2 = 0x2;
|
||||
|
||||
/* set the Audio InforFrame Channel Allocation */
|
||||
snd_hda_codec_write(codec, 0x1, 0,
|
||||
Nv_VERB_SET_Channel_Allocation, chanmask);
|
||||
|
||||
/* turn off SPDIF once; otherwise the IEC958 bits won't be updated */
|
||||
if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE))
|
||||
snd_hda_codec_write(codec,
|
||||
nvhdmi_master_con_nid_7x,
|
||||
0,
|
||||
AC_VERB_SET_DIGI_CONVERT_1,
|
||||
codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff);
|
||||
|
||||
/* set the stream id */
|
||||
snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0,
|
||||
AC_VERB_SET_CHANNEL_STREAMID, (stream_tag << 4) | 0x0);
|
||||
|
||||
/* set the stream format */
|
||||
snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0,
|
||||
AC_VERB_SET_STREAM_FORMAT, format);
|
||||
|
||||
/* turn on again (if needed) */
|
||||
/* enable and set the channel status audio/data flag */
|
||||
if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) {
|
||||
snd_hda_codec_write(codec,
|
||||
nvhdmi_master_con_nid_7x,
|
||||
0,
|
||||
AC_VERB_SET_DIGI_CONVERT_1,
|
||||
codec->spdif_ctls & 0xff);
|
||||
snd_hda_codec_write(codec,
|
||||
nvhdmi_master_con_nid_7x,
|
||||
0,
|
||||
AC_VERB_SET_DIGI_CONVERT_2, dataDCC2);
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (chs == 2)
|
||||
channel_id = 0;
|
||||
else
|
||||
channel_id = i * 2;
|
||||
|
||||
/* turn off SPDIF once;
|
||||
*otherwise the IEC958 bits won't be updated
|
||||
*/
|
||||
if (codec->spdif_status_reset &&
|
||||
(codec->spdif_ctls & AC_DIG1_ENABLE))
|
||||
snd_hda_codec_write(codec,
|
||||
nvhdmi_con_nids_7x[i],
|
||||
0,
|
||||
AC_VERB_SET_DIGI_CONVERT_1,
|
||||
codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff);
|
||||
/* set the stream id */
|
||||
snd_hda_codec_write(codec,
|
||||
nvhdmi_con_nids_7x[i],
|
||||
0,
|
||||
AC_VERB_SET_CHANNEL_STREAMID,
|
||||
(stream_tag << 4) | channel_id);
|
||||
/* set the stream format */
|
||||
snd_hda_codec_write(codec,
|
||||
nvhdmi_con_nids_7x[i],
|
||||
0,
|
||||
AC_VERB_SET_STREAM_FORMAT,
|
||||
format);
|
||||
/* turn on again (if needed) */
|
||||
/* enable and set the channel status audio/data flag */
|
||||
if (codec->spdif_status_reset &&
|
||||
(codec->spdif_ctls & AC_DIG1_ENABLE)) {
|
||||
snd_hda_codec_write(codec,
|
||||
nvhdmi_con_nids_7x[i],
|
||||
0,
|
||||
AC_VERB_SET_DIGI_CONVERT_1,
|
||||
codec->spdif_ctls & 0xff);
|
||||
snd_hda_codec_write(codec,
|
||||
nvhdmi_con_nids_7x[i],
|
||||
0,
|
||||
AC_VERB_SET_DIGI_CONVERT_2, dataDCC2);
|
||||
}
|
||||
}
|
||||
|
||||
/* set the Audio Info Frame Checksum */
|
||||
snd_hda_codec_write(codec, 0x1, 0,
|
||||
Nv_VERB_SET_Info_Frame_Checksum,
|
||||
(0x71 - chan - chanmask));
|
||||
|
||||
mutex_unlock(&codec->spdif_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nvhdmi_dig_playback_pcm_prepare_2ch(struct hda_pcm_stream *hinfo,
|
||||
struct hda_codec *codec,
|
||||
unsigned int stream_tag,
|
||||
unsigned int format,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct hdmi_spec *spec = codec->spec;
|
||||
return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag,
|
||||
format, substream);
|
||||
}
|
||||
|
||||
static struct hda_pcm_stream nvhdmi_pcm_digital_playback_8ch_89 = {
|
||||
.substreams = 1,
|
||||
.channels_min = 2,
|
||||
.ops = {
|
||||
.open = hdmi_pcm_open,
|
||||
.prepare = nvhdmi_dig_playback_pcm_prepare_8ch_89,
|
||||
},
|
||||
};
|
||||
|
||||
static struct hda_pcm_stream nvhdmi_pcm_digital_playback_8ch_7x = {
|
||||
.substreams = 1,
|
||||
.channels_min = 2,
|
||||
.channels_max = 8,
|
||||
.nid = nvhdmi_master_con_nid_7x,
|
||||
.rates = SUPPORTED_RATES,
|
||||
.maxbps = SUPPORTED_MAXBPS,
|
||||
.formats = SUPPORTED_FORMATS,
|
||||
.ops = {
|
||||
.open = nvhdmi_dig_playback_pcm_open,
|
||||
.close = nvhdmi_dig_playback_pcm_close_8ch_7x,
|
||||
.prepare = nvhdmi_dig_playback_pcm_prepare_8ch
|
||||
},
|
||||
};
|
||||
|
||||
static struct hda_pcm_stream nvhdmi_pcm_digital_playback_2ch = {
|
||||
.substreams = 1,
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.nid = nvhdmi_master_con_nid_7x,
|
||||
.rates = SUPPORTED_RATES,
|
||||
.maxbps = SUPPORTED_MAXBPS,
|
||||
.formats = SUPPORTED_FORMATS,
|
||||
.ops = {
|
||||
.open = nvhdmi_dig_playback_pcm_open,
|
||||
.close = nvhdmi_dig_playback_pcm_close_2ch,
|
||||
.prepare = nvhdmi_dig_playback_pcm_prepare_2ch
|
||||
},
|
||||
};
|
||||
|
||||
static int nvhdmi_build_pcms_8ch_89(struct hda_codec *codec)
|
||||
{
|
||||
struct hdmi_spec *spec = codec->spec;
|
||||
struct hda_pcm *info = spec->pcm_rec;
|
||||
int i;
|
||||
|
||||
codec->num_pcms = spec->num_cvts;
|
||||
codec->pcm_info = info;
|
||||
|
||||
for (i = 0; i < codec->num_pcms; i++, info++) {
|
||||
unsigned int chans;
|
||||
|
||||
chans = get_wcaps(codec, spec->cvt[i]);
|
||||
chans = get_wcaps_channels(chans);
|
||||
|
||||
info->name = nvhdmi_pcm_names[i];
|
||||
info->pcm_type = HDA_PCM_TYPE_HDMI;
|
||||
info->stream[SNDRV_PCM_STREAM_PLAYBACK]
|
||||
= nvhdmi_pcm_digital_playback_8ch_89;
|
||||
info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->cvt[i];
|
||||
info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = chans;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nvhdmi_build_pcms_8ch_7x(struct hda_codec *codec)
|
||||
{
|
||||
struct hdmi_spec *spec = codec->spec;
|
||||
struct hda_pcm *info = spec->pcm_rec;
|
||||
|
||||
codec->num_pcms = 1;
|
||||
codec->pcm_info = info;
|
||||
|
||||
info->name = "NVIDIA HDMI";
|
||||
info->pcm_type = HDA_PCM_TYPE_HDMI;
|
||||
info->stream[SNDRV_PCM_STREAM_PLAYBACK]
|
||||
= nvhdmi_pcm_digital_playback_8ch_7x;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nvhdmi_build_pcms_2ch(struct hda_codec *codec)
|
||||
{
|
||||
struct hdmi_spec *spec = codec->spec;
|
||||
struct hda_pcm *info = spec->pcm_rec;
|
||||
|
||||
codec->num_pcms = 1;
|
||||
codec->pcm_info = info;
|
||||
|
||||
info->name = "NVIDIA HDMI";
|
||||
info->pcm_type = HDA_PCM_TYPE_HDMI;
|
||||
info->stream[SNDRV_PCM_STREAM_PLAYBACK]
|
||||
= nvhdmi_pcm_digital_playback_2ch;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct hda_codec_ops nvhdmi_patch_ops_8ch_89 = {
|
||||
.build_controls = nvhdmi_build_controls,
|
||||
.build_pcms = nvhdmi_build_pcms_8ch_89,
|
||||
.init = nvhdmi_init,
|
||||
.free = nvhdmi_free,
|
||||
.unsol_event = hdmi_unsol_event,
|
||||
};
|
||||
|
||||
static struct hda_codec_ops nvhdmi_patch_ops_8ch_7x = {
|
||||
.build_controls = nvhdmi_build_controls,
|
||||
.build_pcms = nvhdmi_build_pcms_8ch_7x,
|
||||
.init = nvhdmi_init,
|
||||
.free = nvhdmi_free,
|
||||
};
|
||||
|
||||
static struct hda_codec_ops nvhdmi_patch_ops_2ch = {
|
||||
.build_controls = nvhdmi_build_controls,
|
||||
.build_pcms = nvhdmi_build_pcms_2ch,
|
||||
.init = nvhdmi_init,
|
||||
.free = nvhdmi_free,
|
||||
};
|
||||
|
||||
static int patch_nvhdmi_8ch_89(struct hda_codec *codec)
|
||||
{
|
||||
struct hdmi_spec *spec;
|
||||
int i;
|
||||
|
||||
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
|
||||
if (spec == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
codec->spec = spec;
|
||||
spec->codec_type = HDA_CODEC_NVIDIA_MCP89;
|
||||
spec->old_pin_detect = 1;
|
||||
|
||||
if (hdmi_parse_codec(codec) < 0) {
|
||||
codec->spec = NULL;
|
||||
kfree(spec);
|
||||
return -EINVAL;
|
||||
}
|
||||
codec->patch_ops = nvhdmi_patch_ops_8ch_89;
|
||||
|
||||
for (i = 0; i < spec->num_pins; i++)
|
||||
snd_hda_eld_proc_new(codec, &spec->sink_eld[i], i);
|
||||
|
||||
init_channel_allocations();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int patch_nvhdmi_8ch_7x(struct hda_codec *codec)
|
||||
{
|
||||
struct hdmi_spec *spec;
|
||||
|
||||
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
|
||||
if (spec == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
codec->spec = spec;
|
||||
|
||||
spec->multiout.num_dacs = 0; /* no analog */
|
||||
spec->multiout.max_channels = 8;
|
||||
spec->multiout.dig_out_nid = nvhdmi_master_con_nid_7x;
|
||||
spec->codec_type = HDA_CODEC_NVIDIA_MCP7X;
|
||||
spec->old_pin_detect = 1;
|
||||
|
||||
codec->patch_ops = nvhdmi_patch_ops_8ch_7x;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int patch_nvhdmi_2ch(struct hda_codec *codec)
|
||||
{
|
||||
struct hdmi_spec *spec;
|
||||
|
||||
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
|
||||
if (spec == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
codec->spec = spec;
|
||||
|
||||
spec->multiout.num_dacs = 0; /* no analog */
|
||||
spec->multiout.max_channels = 2;
|
||||
spec->multiout.dig_out_nid = nvhdmi_master_con_nid_7x;
|
||||
spec->codec_type = HDA_CODEC_NVIDIA_MCP7X;
|
||||
spec->old_pin_detect = 1;
|
||||
|
||||
codec->patch_ops = nvhdmi_patch_ops_2ch;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* patch entries
|
||||
*/
|
||||
static struct hda_codec_preset snd_hda_preset_nvhdmi[] = {
|
||||
{ .id = 0x10de0002, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x },
|
||||
{ .id = 0x10de0003, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x },
|
||||
{ .id = 0x10de0005, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x },
|
||||
{ .id = 0x10de0006, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x },
|
||||
{ .id = 0x10de0007, .name = "MCP79/7A HDMI", .patch = patch_nvhdmi_8ch_7x },
|
||||
{ .id = 0x10de000a, .name = "GPU 0a HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
|
||||
{ .id = 0x10de000b, .name = "GPU 0b HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
|
||||
{ .id = 0x10de000c, .name = "MCP89 HDMI", .patch = patch_nvhdmi_8ch_89 },
|
||||
{ .id = 0x10de000d, .name = "GPU 0d HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
|
||||
{ .id = 0x10de0010, .name = "GPU 10 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
|
||||
{ .id = 0x10de0011, .name = "GPU 11 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
|
||||
{ .id = 0x10de0012, .name = "GPU 12 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
|
||||
{ .id = 0x10de0013, .name = "GPU 13 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
|
||||
{ .id = 0x10de0014, .name = "GPU 14 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
|
||||
{ .id = 0x10de0018, .name = "GPU 18 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
|
||||
{ .id = 0x10de0019, .name = "GPU 19 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
|
||||
{ .id = 0x10de001a, .name = "GPU 1a HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
|
||||
{ .id = 0x10de001b, .name = "GPU 1b HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
|
||||
{ .id = 0x10de001c, .name = "GPU 1c HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
|
||||
{ .id = 0x10de0040, .name = "GPU 40 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
|
||||
{ .id = 0x10de0041, .name = "GPU 41 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
|
||||
{ .id = 0x10de0042, .name = "GPU 42 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
|
||||
{ .id = 0x10de0043, .name = "GPU 43 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
|
||||
{ .id = 0x10de0044, .name = "GPU 44 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
|
||||
{ .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi_2ch },
|
||||
{ .id = 0x10de8001, .name = "MCP73 HDMI", .patch = patch_nvhdmi_2ch },
|
||||
{} /* terminator */
|
||||
};
|
||||
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de0002");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de0003");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de0005");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de0006");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de0007");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de000a");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de000b");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de000c");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de000d");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de0010");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de0011");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de0012");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de0013");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de0014");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de0018");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de0019");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de001a");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de001b");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de001c");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de0040");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de0041");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de0042");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de0043");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de0044");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de0067");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de8001");
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("NVIDIA HDMI HD-audio codec");
|
||||
|
||||
static struct hda_codec_preset_list nvhdmi_list = {
|
||||
.preset = snd_hda_preset_nvhdmi,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init patch_nvhdmi_init(void)
|
||||
{
|
||||
return snd_hda_add_codec_preset(&nvhdmi_list);
|
||||
}
|
||||
|
||||
static void __exit patch_nvhdmi_exit(void)
|
||||
{
|
||||
snd_hda_delete_codec_preset(&nvhdmi_list);
|
||||
}
|
||||
|
||||
module_init(patch_nvhdmi_init)
|
||||
module_exit(patch_nvhdmi_exit)
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -32,6 +32,7 @@
|
|||
#include <sound/core.h>
|
||||
#include <sound/asoundef.h>
|
||||
#include <sound/jack.h>
|
||||
#include <sound/tlv.h>
|
||||
#include "hda_codec.h"
|
||||
#include "hda_local.h"
|
||||
#include "hda_beep.h"
|
||||
|
|
@ -263,6 +264,7 @@ struct sigmatel_spec {
|
|||
|
||||
struct sigmatel_mic_route ext_mic;
|
||||
struct sigmatel_mic_route int_mic;
|
||||
struct sigmatel_mic_route dock_mic;
|
||||
|
||||
const char **spdif_labels;
|
||||
|
||||
|
|
@ -382,6 +384,11 @@ static unsigned int stac92hd83xxx_pwr_mapping[4] = {
|
|||
0x03, 0x0c, 0x20, 0x40,
|
||||
};
|
||||
|
||||
#define STAC92HD83XXX_NUM_DMICS 2
|
||||
static hda_nid_t stac92hd83xxx_dmic_nids[STAC92HD83XXX_NUM_DMICS + 1] = {
|
||||
0x11, 0x20, 0
|
||||
};
|
||||
|
||||
#define STAC92HD83XXX_NUM_CAPS 2
|
||||
static unsigned long stac92hd83xxx_capvols[] = {
|
||||
HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT),
|
||||
|
|
@ -986,7 +993,7 @@ static struct hda_verb stac9205_core_init[] = {
|
|||
}
|
||||
|
||||
static struct snd_kcontrol_new stac9200_mixer[] = {
|
||||
HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME_MIN_MUTE("Master Playback Volume", 0xb, 0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT),
|
||||
|
|
@ -1014,7 +1021,7 @@ static struct snd_kcontrol_new stac92hd71bxx_loopback[] = {
|
|||
};
|
||||
|
||||
static struct snd_kcontrol_new stac925x_mixer[] = {
|
||||
HDA_CODEC_VOLUME("Master Playback Volume", 0x0e, 0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME_MIN_MUTE("Master Playback Volume", 0xe, 0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Master Playback Switch", 0x0e, 0, HDA_OUTPUT),
|
||||
{ } /* end */
|
||||
};
|
||||
|
|
@ -1105,9 +1112,7 @@ static int stac92xx_build_controls(struct hda_codec *codec)
|
|||
struct hda_input_mux *smux = &spec->private_smux;
|
||||
/* check for mute support on SPDIF out */
|
||||
if (wcaps & AC_WCAP_OUT_AMP) {
|
||||
smux->items[smux->num_items].label = "Off";
|
||||
smux->items[smux->num_items].index = 0;
|
||||
smux->num_items++;
|
||||
snd_hda_add_imux_item(smux, "Off", 0, NULL);
|
||||
spec->spdif_mute = 1;
|
||||
}
|
||||
stac_smux_mixer.count = spec->num_smuxes;
|
||||
|
|
@ -1140,6 +1145,8 @@ static int stac92xx_build_controls(struct hda_codec *codec)
|
|||
HDA_OUTPUT, vmaster_tlv);
|
||||
/* correct volume offset */
|
||||
vmaster_tlv[2] += vmaster_tlv[3] * spec->volume_offset;
|
||||
/* minimum value is actually mute */
|
||||
vmaster_tlv[3] |= TLV_DB_SCALE_MUTE;
|
||||
err = snd_hda_add_vmaster(codec, "Master Playback Volume",
|
||||
vmaster_tlv, slave_vols);
|
||||
if (err < 0)
|
||||
|
|
@ -1180,14 +1187,11 @@ static int stac92xx_build_controls(struct hda_codec *codec)
|
|||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
for (i = 0; i < AUTO_PIN_LAST; i++) {
|
||||
nid = cfg->input_pins[i];
|
||||
if (nid) {
|
||||
err = stac92xx_add_jack(codec, nid,
|
||||
SND_JACK_MICROPHONE);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
for (i = 0; i < cfg->num_inputs; i++) {
|
||||
nid = cfg->inputs[i].pin;
|
||||
err = stac92xx_add_jack(codec, nid, SND_JACK_MICROPHONE);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -2779,7 +2783,7 @@ static inline int stac92xx_add_jack_mode_control(struct hda_codec *codec,
|
|||
struct sigmatel_spec *spec = codec->spec;
|
||||
char name[22];
|
||||
|
||||
if (!((get_defcfg_connect(def_conf)) & AC_JACK_PORT_FIXED)) {
|
||||
if (snd_hda_get_input_pin_attr(def_conf) != INPUT_PIN_ATTR_INT) {
|
||||
if (stac92xx_get_default_vref(codec, nid) == AC_PINCTL_VREF_GRD
|
||||
&& nid == spec->line_switch)
|
||||
control = STAC_CTL_WIDGET_IO_SWITCH;
|
||||
|
|
@ -2791,7 +2795,7 @@ static inline int stac92xx_add_jack_mode_control(struct hda_codec *codec,
|
|||
}
|
||||
|
||||
if (control) {
|
||||
strcpy(name, auto_pin_cfg_labels[idx]);
|
||||
strcpy(name, hda_get_input_pin_label(codec, nid, 1));
|
||||
return stac92xx_add_control(codec->spec, control,
|
||||
strcat(name, " Jack Mode"), nid);
|
||||
}
|
||||
|
|
@ -2823,41 +2827,49 @@ static hda_nid_t check_line_out_switch(struct hda_codec *codec)
|
|||
struct auto_pin_cfg *cfg = &spec->autocfg;
|
||||
hda_nid_t nid;
|
||||
unsigned int pincap;
|
||||
int i;
|
||||
|
||||
if (cfg->line_out_type != AUTO_PIN_LINE_OUT)
|
||||
return 0;
|
||||
nid = cfg->input_pins[AUTO_PIN_LINE];
|
||||
pincap = snd_hda_query_pin_caps(codec, nid);
|
||||
if (pincap & AC_PINCAP_OUT)
|
||||
return nid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* check whether the mic-input can be used as line-out */
|
||||
static hda_nid_t check_mic_out_switch(struct hda_codec *codec)
|
||||
{
|
||||
struct sigmatel_spec *spec = codec->spec;
|
||||
struct auto_pin_cfg *cfg = &spec->autocfg;
|
||||
unsigned int def_conf, pincap;
|
||||
unsigned int mic_pin;
|
||||
|
||||
if (cfg->line_out_type != AUTO_PIN_LINE_OUT)
|
||||
return 0;
|
||||
mic_pin = AUTO_PIN_MIC;
|
||||
for (;;) {
|
||||
hda_nid_t nid = cfg->input_pins[mic_pin];
|
||||
def_conf = snd_hda_codec_get_pincfg(codec, nid);
|
||||
/* some laptops have an internal analog microphone
|
||||
* which can't be used as a output */
|
||||
if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED) {
|
||||
for (i = 0; i < cfg->num_inputs; i++) {
|
||||
if (cfg->inputs[i].type == AUTO_PIN_LINE_IN) {
|
||||
nid = cfg->inputs[i].pin;
|
||||
pincap = snd_hda_query_pin_caps(codec, nid);
|
||||
if (pincap & AC_PINCAP_OUT)
|
||||
return nid;
|
||||
}
|
||||
if (mic_pin == AUTO_PIN_MIC)
|
||||
mic_pin = AUTO_PIN_FRONT_MIC;
|
||||
else
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static hda_nid_t get_unassigned_dac(struct hda_codec *codec, hda_nid_t nid);
|
||||
|
||||
/* check whether the mic-input can be used as line-out */
|
||||
static hda_nid_t check_mic_out_switch(struct hda_codec *codec, hda_nid_t *dac)
|
||||
{
|
||||
struct sigmatel_spec *spec = codec->spec;
|
||||
struct auto_pin_cfg *cfg = &spec->autocfg;
|
||||
unsigned int def_conf, pincap;
|
||||
int i;
|
||||
|
||||
*dac = 0;
|
||||
if (cfg->line_out_type != AUTO_PIN_LINE_OUT)
|
||||
return 0;
|
||||
for (i = 0; i < cfg->num_inputs; i++) {
|
||||
hda_nid_t nid = cfg->inputs[i].pin;
|
||||
if (cfg->inputs[i].type != AUTO_PIN_MIC)
|
||||
continue;
|
||||
def_conf = snd_hda_codec_get_pincfg(codec, nid);
|
||||
/* some laptops have an internal analog microphone
|
||||
* which can't be used as a output */
|
||||
if (snd_hda_get_input_pin_attr(def_conf) != INPUT_PIN_ATTR_INT) {
|
||||
pincap = snd_hda_query_pin_caps(codec, nid);
|
||||
if (pincap & AC_PINCAP_OUT) {
|
||||
*dac = get_unassigned_dac(codec, nid);
|
||||
if (*dac)
|
||||
return nid;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -3004,17 +3016,14 @@ static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec)
|
|||
}
|
||||
}
|
||||
/* add mic as output */
|
||||
nid = check_mic_out_switch(codec);
|
||||
if (nid) {
|
||||
dac = get_unassigned_dac(codec, nid);
|
||||
if (dac) {
|
||||
snd_printdd("STAC: Add mic-in 0x%x as output %d\n",
|
||||
nid, cfg->line_outs);
|
||||
cfg->line_out_pins[cfg->line_outs] = nid;
|
||||
cfg->line_outs++;
|
||||
spec->mic_switch = nid;
|
||||
add_spec_dacs(spec, dac);
|
||||
}
|
||||
nid = check_mic_out_switch(codec, &dac);
|
||||
if (nid && dac) {
|
||||
snd_printdd("STAC: Add mic-in 0x%x as output %d\n",
|
||||
nid, cfg->line_outs);
|
||||
cfg->line_out_pins[cfg->line_outs] = nid;
|
||||
cfg->line_outs++;
|
||||
spec->mic_switch = nid;
|
||||
add_spec_dacs(spec, dac);
|
||||
}
|
||||
|
||||
snd_printd("stac92xx: dac_nids=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
|
||||
|
|
@ -3204,13 +3213,13 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
|
|||
return err;
|
||||
}
|
||||
|
||||
for (idx = AUTO_PIN_MIC; idx <= AUTO_PIN_FRONT_LINE; idx++) {
|
||||
nid = cfg->input_pins[idx];
|
||||
if (nid) {
|
||||
err = stac92xx_add_jack_mode_control(codec, nid, idx);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
for (idx = 0; idx < cfg->num_inputs; idx++) {
|
||||
if (cfg->inputs[idx].type > AUTO_PIN_LINE_IN)
|
||||
break;
|
||||
nid = cfg->inputs[idx].pin;
|
||||
err = stac92xx_add_jack_mode_control(codec, nid, idx);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -3256,12 +3265,9 @@ static int stac92xx_auto_create_mono_output_ctls(struct hda_codec *codec)
|
|||
if (num_cons <= 0 || num_cons > ARRAY_SIZE(stac92xx_mono_labels))
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < num_cons; i++) {
|
||||
mono_mux->items[mono_mux->num_items].label =
|
||||
stac92xx_mono_labels[i];
|
||||
mono_mux->items[mono_mux->num_items].index = i;
|
||||
mono_mux->num_items++;
|
||||
}
|
||||
for (i = 0; i < num_cons; i++)
|
||||
snd_hda_add_imux_item(mono_mux, stac92xx_mono_labels[i], i,
|
||||
NULL);
|
||||
|
||||
return stac92xx_add_control(spec, STAC_CTL_WIDGET_MONO_MUX,
|
||||
"Mono Mux", spec->mono_nid);
|
||||
|
|
@ -3386,11 +3392,8 @@ static int stac92xx_auto_create_spdif_mux_ctls(struct hda_codec *codec)
|
|||
if (!labels)
|
||||
labels = stac92xx_spdif_labels;
|
||||
|
||||
for (i = 0; i < num_cons; i++) {
|
||||
spdif_mux->items[spdif_mux->num_items].label = labels[i];
|
||||
spdif_mux->items[spdif_mux->num_items].index = i;
|
||||
spdif_mux->num_items++;
|
||||
}
|
||||
for (i = 0; i < num_cons; i++)
|
||||
snd_hda_add_imux_item(spdif_mux, labels[i], i, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -3417,7 +3420,7 @@ static int get_connection_index(struct hda_codec *codec, hda_nid_t mux,
|
|||
/* create a volume assigned to the given pin (only if supported) */
|
||||
/* return 1 if the volume control is created */
|
||||
static int create_elem_capture_vol(struct hda_codec *codec, hda_nid_t nid,
|
||||
const char *label, int direction)
|
||||
const char *label, int idx, int direction)
|
||||
{
|
||||
unsigned int caps, nums;
|
||||
char name[32];
|
||||
|
|
@ -3434,8 +3437,8 @@ static int create_elem_capture_vol(struct hda_codec *codec, hda_nid_t nid,
|
|||
if (!nums)
|
||||
return 0;
|
||||
snprintf(name, sizeof(name), "%s Capture Volume", label);
|
||||
err = stac92xx_add_control(codec->spec, STAC_CTL_WIDGET_VOL, name,
|
||||
HDA_COMPOSE_AMP_VAL(nid, 3, 0, direction));
|
||||
err = stac92xx_add_control_idx(codec->spec, STAC_CTL_WIDGET_VOL, idx, name,
|
||||
HDA_COMPOSE_AMP_VAL(nid, 3, 0, direction));
|
||||
if (err < 0)
|
||||
return err;
|
||||
return 1;
|
||||
|
|
@ -3448,27 +3451,14 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
|
|||
struct sigmatel_spec *spec = codec->spec;
|
||||
struct hda_input_mux *imux = &spec->private_imux;
|
||||
struct hda_input_mux *dimux = &spec->private_dimux;
|
||||
int err, i, active_mics;
|
||||
int err, i;
|
||||
unsigned int def_conf;
|
||||
|
||||
dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0];
|
||||
dimux->items[dimux->num_items].index = 0;
|
||||
dimux->num_items++;
|
||||
|
||||
active_mics = 0;
|
||||
for (i = 0; i < spec->num_dmics; i++) {
|
||||
/* check the validity: sometimes it's a dead vendor-spec node */
|
||||
if (get_wcaps_type(get_wcaps(codec, spec->dmic_nids[i]))
|
||||
!= AC_WID_PIN)
|
||||
continue;
|
||||
def_conf = snd_hda_codec_get_pincfg(codec, spec->dmic_nids[i]);
|
||||
if (get_defcfg_connect(def_conf) != AC_JACK_PORT_NONE)
|
||||
active_mics++;
|
||||
}
|
||||
snd_hda_add_imux_item(dimux, stac92xx_dmic_labels[0], 0, NULL);
|
||||
|
||||
for (i = 0; i < spec->num_dmics; i++) {
|
||||
hda_nid_t nid;
|
||||
int index;
|
||||
int index, type_idx;
|
||||
const char *label;
|
||||
|
||||
nid = spec->dmic_nids[i];
|
||||
|
|
@ -3482,28 +3472,23 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
|
|||
if (index < 0)
|
||||
continue;
|
||||
|
||||
if (active_mics == 1)
|
||||
label = "Digital Mic";
|
||||
else
|
||||
label = stac92xx_dmic_labels[dimux->num_items];
|
||||
label = hda_get_input_pin_label(codec, nid, 1);
|
||||
snd_hda_add_imux_item(dimux, label, index, &type_idx);
|
||||
|
||||
err = create_elem_capture_vol(codec, nid, label, HDA_INPUT);
|
||||
err = create_elem_capture_vol(codec, nid, label, type_idx,
|
||||
HDA_INPUT);
|
||||
if (err < 0)
|
||||
return err;
|
||||
if (!err) {
|
||||
err = create_elem_capture_vol(codec, nid, label,
|
||||
HDA_OUTPUT);
|
||||
type_idx, HDA_OUTPUT);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
dimux->items[dimux->num_items].label = label;
|
||||
dimux->items[dimux->num_items].index = index;
|
||||
dimux->num_items++;
|
||||
if (snd_hda_get_bool_hint(codec, "separate_dmux") != 1) {
|
||||
imux->items[imux->num_items].label = label;
|
||||
imux->items[imux->num_items].index = index;
|
||||
imux->num_items++;
|
||||
snd_hda_add_imux_item(imux, label, index, NULL);
|
||||
spec->num_analog_muxes++;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3511,20 +3496,27 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
|
|||
}
|
||||
|
||||
static int check_mic_pin(struct hda_codec *codec, hda_nid_t nid,
|
||||
hda_nid_t *fixed, hda_nid_t *ext)
|
||||
hda_nid_t *fixed, hda_nid_t *ext, hda_nid_t *dock)
|
||||
{
|
||||
unsigned int cfg;
|
||||
|
||||
if (!nid)
|
||||
return 0;
|
||||
cfg = snd_hda_codec_get_pincfg(codec, nid);
|
||||
switch (get_defcfg_connect(cfg)) {
|
||||
case AC_JACK_PORT_FIXED:
|
||||
switch (snd_hda_get_input_pin_attr(cfg)) {
|
||||
case INPUT_PIN_ATTR_INT:
|
||||
if (*fixed)
|
||||
return 1; /* already occupied */
|
||||
*fixed = nid;
|
||||
break;
|
||||
case AC_JACK_PORT_COMPLEX:
|
||||
case INPUT_PIN_ATTR_UNUSED:
|
||||
break;
|
||||
case INPUT_PIN_ATTR_DOCK:
|
||||
if (*dock)
|
||||
return 1; /* already occupied */
|
||||
*dock = nid;
|
||||
break;
|
||||
default:
|
||||
if (*ext)
|
||||
return 1; /* already occupied */
|
||||
*ext = nid;
|
||||
|
|
@ -3542,10 +3534,13 @@ static int set_mic_route(struct hda_codec *codec,
|
|||
int i;
|
||||
|
||||
mic->pin = pin;
|
||||
for (i = AUTO_PIN_MIC; i <= AUTO_PIN_FRONT_MIC; i++)
|
||||
if (pin == cfg->input_pins[i])
|
||||
if (pin == 0)
|
||||
return 0;
|
||||
for (i = 0; i < cfg->num_inputs; i++) {
|
||||
if (pin == cfg->inputs[i].pin)
|
||||
break;
|
||||
if (i <= AUTO_PIN_FRONT_MIC) {
|
||||
}
|
||||
if (i < cfg->num_inputs && cfg->inputs[i].type == AUTO_PIN_MIC) {
|
||||
/* analog pin */
|
||||
i = get_connection_index(codec, spec->mux_nids[0], pin);
|
||||
if (i < 0)
|
||||
|
|
@ -3576,26 +3571,29 @@ static int stac_check_auto_mic(struct hda_codec *codec)
|
|||
{
|
||||
struct sigmatel_spec *spec = codec->spec;
|
||||
struct auto_pin_cfg *cfg = &spec->autocfg;
|
||||
hda_nid_t fixed, ext;
|
||||
hda_nid_t fixed, ext, dock;
|
||||
int i;
|
||||
|
||||
for (i = AUTO_PIN_LINE; i < AUTO_PIN_LAST; i++) {
|
||||
if (cfg->input_pins[i])
|
||||
for (i = 0; i < cfg->num_inputs; i++) {
|
||||
if (cfg->inputs[i].type >= AUTO_PIN_LINE_IN)
|
||||
return 0; /* must be exclusively mics */
|
||||
}
|
||||
fixed = ext = 0;
|
||||
for (i = AUTO_PIN_MIC; i <= AUTO_PIN_FRONT_MIC; i++)
|
||||
if (check_mic_pin(codec, cfg->input_pins[i], &fixed, &ext))
|
||||
fixed = ext = dock = 0;
|
||||
for (i = 0; i < cfg->num_inputs; i++)
|
||||
if (check_mic_pin(codec, cfg->inputs[i].pin,
|
||||
&fixed, &ext, &dock))
|
||||
return 0;
|
||||
for (i = 0; i < spec->num_dmics; i++)
|
||||
if (check_mic_pin(codec, spec->dmic_nids[i], &fixed, &ext))
|
||||
if (check_mic_pin(codec, spec->dmic_nids[i],
|
||||
&fixed, &ext, &dock))
|
||||
return 0;
|
||||
if (!fixed || !ext)
|
||||
return 0;
|
||||
if (!fixed && !ext && !dock)
|
||||
return 0; /* no input to switch */
|
||||
if (!(get_wcaps(codec, ext) & AC_WCAP_UNSOL_CAP))
|
||||
return 0; /* no unsol support */
|
||||
if (set_mic_route(codec, &spec->ext_mic, ext) ||
|
||||
set_mic_route(codec, &spec->int_mic, fixed))
|
||||
set_mic_route(codec, &spec->int_mic, fixed) ||
|
||||
set_mic_route(codec, &spec->dock_mic, dock))
|
||||
return 0; /* something is wrong */
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -3606,13 +3604,12 @@ static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const
|
|||
struct sigmatel_spec *spec = codec->spec;
|
||||
struct hda_input_mux *imux = &spec->private_imux;
|
||||
int i, j;
|
||||
const char *label;
|
||||
|
||||
for (i = 0; i < AUTO_PIN_LAST; i++) {
|
||||
hda_nid_t nid = cfg->input_pins[i];
|
||||
int index, err;
|
||||
for (i = 0; i < cfg->num_inputs; i++) {
|
||||
hda_nid_t nid = cfg->inputs[i].pin;
|
||||
int index, err, type_idx;
|
||||
|
||||
if (!nid)
|
||||
continue;
|
||||
index = -1;
|
||||
for (j = 0; j < spec->num_muxes; j++) {
|
||||
index = get_connection_index(codec, spec->mux_nids[j],
|
||||
|
|
@ -3623,15 +3620,14 @@ static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const
|
|||
if (index < 0)
|
||||
continue;
|
||||
|
||||
label = hda_get_autocfg_input_label(codec, cfg, i);
|
||||
snd_hda_add_imux_item(imux, label, index, &type_idx);
|
||||
|
||||
err = create_elem_capture_vol(codec, nid,
|
||||
auto_pin_cfg_labels[i],
|
||||
label, type_idx,
|
||||
HDA_INPUT);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
|
||||
imux->items[imux->num_items].index = index;
|
||||
imux->num_items++;
|
||||
}
|
||||
spec->num_analog_muxes = imux->num_items;
|
||||
|
||||
|
|
@ -4305,38 +4301,38 @@ static int stac92xx_init(struct hda_codec *codec)
|
|||
AC_VERB_SET_CONNECT_SEL, 0);
|
||||
if (enable_pin_detect(codec, spec->ext_mic.pin, STAC_MIC_EVENT))
|
||||
stac_issue_unsol_event(codec, spec->ext_mic.pin);
|
||||
if (enable_pin_detect(codec, spec->dock_mic.pin,
|
||||
STAC_MIC_EVENT))
|
||||
stac_issue_unsol_event(codec, spec->dock_mic.pin);
|
||||
}
|
||||
for (i = 0; i < AUTO_PIN_LAST; i++) {
|
||||
hda_nid_t nid = cfg->input_pins[i];
|
||||
if (nid) {
|
||||
unsigned int pinctl, conf;
|
||||
if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC) {
|
||||
/* for mic pins, force to initialize */
|
||||
pinctl = stac92xx_get_default_vref(codec, nid);
|
||||
for (i = 0; i < cfg->num_inputs; i++) {
|
||||
hda_nid_t nid = cfg->inputs[i].pin;
|
||||
int type = cfg->inputs[i].type;
|
||||
unsigned int pinctl, conf;
|
||||
if (type == AUTO_PIN_MIC) {
|
||||
/* for mic pins, force to initialize */
|
||||
pinctl = stac92xx_get_default_vref(codec, nid);
|
||||
pinctl |= AC_PINCTL_IN_EN;
|
||||
stac92xx_auto_set_pinctl(codec, nid, pinctl);
|
||||
} else {
|
||||
pinctl = snd_hda_codec_read(codec, nid, 0,
|
||||
AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
|
||||
/* if PINCTL already set then skip */
|
||||
/* Also, if both INPUT and OUTPUT are set,
|
||||
* it must be a BIOS bug; need to override, too
|
||||
*/
|
||||
if (!(pinctl & AC_PINCTL_IN_EN) ||
|
||||
(pinctl & AC_PINCTL_OUT_EN)) {
|
||||
pinctl &= ~AC_PINCTL_OUT_EN;
|
||||
pinctl |= AC_PINCTL_IN_EN;
|
||||
stac92xx_auto_set_pinctl(codec, nid, pinctl);
|
||||
} else {
|
||||
pinctl = snd_hda_codec_read(codec, nid, 0,
|
||||
AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
|
||||
/* if PINCTL already set then skip */
|
||||
/* Also, if both INPUT and OUTPUT are set,
|
||||
* it must be a BIOS bug; need to override, too
|
||||
*/
|
||||
if (!(pinctl & AC_PINCTL_IN_EN) ||
|
||||
(pinctl & AC_PINCTL_OUT_EN)) {
|
||||
pinctl &= ~AC_PINCTL_OUT_EN;
|
||||
pinctl |= AC_PINCTL_IN_EN;
|
||||
stac92xx_auto_set_pinctl(codec, nid,
|
||||
pinctl);
|
||||
}
|
||||
}
|
||||
conf = snd_hda_codec_get_pincfg(codec, nid);
|
||||
if (get_defcfg_connect(conf) != AC_JACK_PORT_FIXED) {
|
||||
if (enable_pin_detect(codec, nid,
|
||||
STAC_INSERT_EVENT))
|
||||
stac_issue_unsol_event(codec, nid);
|
||||
}
|
||||
}
|
||||
conf = snd_hda_codec_get_pincfg(codec, nid);
|
||||
if (get_defcfg_connect(conf) != AC_JACK_PORT_FIXED) {
|
||||
if (enable_pin_detect(codec, nid, STAC_INSERT_EVENT))
|
||||
stac_issue_unsol_event(codec, nid);
|
||||
}
|
||||
}
|
||||
for (i = 0; i < spec->num_dmics; i++)
|
||||
stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i],
|
||||
|
|
@ -4383,11 +4379,9 @@ static int stac92xx_init(struct hda_codec *codec)
|
|||
stac_issue_unsol_event(codec, nid);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
/* sync mute LED */
|
||||
if (spec->gpio_led && codec->patch_ops.check_power_status)
|
||||
codec->patch_ops.check_power_status(codec, 0x01);
|
||||
#endif
|
||||
if (spec->gpio_led)
|
||||
hda_call_check_power_status(codec, 0x01);
|
||||
if (spec->dac_list)
|
||||
stac92xx_power_down(codec);
|
||||
return 0;
|
||||
|
|
@ -4688,6 +4682,36 @@ static void stac92xx_report_jack(struct hda_codec *codec, hda_nid_t nid)
|
|||
}
|
||||
}
|
||||
|
||||
/* get the pin connection (fixed, none, etc) */
|
||||
static unsigned int stac_get_defcfg_connect(struct hda_codec *codec, int idx)
|
||||
{
|
||||
struct sigmatel_spec *spec = codec->spec;
|
||||
unsigned int cfg;
|
||||
|
||||
cfg = snd_hda_codec_get_pincfg(codec, spec->pin_nids[idx]);
|
||||
return get_defcfg_connect(cfg);
|
||||
}
|
||||
|
||||
static int stac92xx_connected_ports(struct hda_codec *codec,
|
||||
hda_nid_t *nids, int num_nids)
|
||||
{
|
||||
struct sigmatel_spec *spec = codec->spec;
|
||||
int idx, num;
|
||||
unsigned int def_conf;
|
||||
|
||||
for (num = 0; num < num_nids; num++) {
|
||||
for (idx = 0; idx < spec->num_pins; idx++)
|
||||
if (spec->pin_nids[idx] == nids[num])
|
||||
break;
|
||||
if (idx >= spec->num_pins)
|
||||
break;
|
||||
def_conf = stac_get_defcfg_connect(codec, idx);
|
||||
if (def_conf == AC_JACK_PORT_NONE)
|
||||
break;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
static void stac92xx_mic_detect(struct hda_codec *codec)
|
||||
{
|
||||
struct sigmatel_spec *spec = codec->spec;
|
||||
|
|
@ -4695,6 +4719,8 @@ static void stac92xx_mic_detect(struct hda_codec *codec)
|
|||
|
||||
if (get_pin_presence(codec, spec->ext_mic.pin))
|
||||
mic = &spec->ext_mic;
|
||||
else if (get_pin_presence(codec, spec->dock_mic.pin))
|
||||
mic = &spec->dock_mic;
|
||||
else
|
||||
mic = &spec->int_mic;
|
||||
if (mic->dmux_idx >= 0)
|
||||
|
|
@ -4937,11 +4963,9 @@ static int stac92xx_resume(struct hda_codec *codec)
|
|||
stac_issue_unsol_event(codec,
|
||||
spec->autocfg.line_out_pins[0]);
|
||||
}
|
||||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
/* sync mute LED */
|
||||
if (spec->gpio_led && codec->patch_ops.check_power_status)
|
||||
codec->patch_ops.check_power_status(codec, 0x01);
|
||||
#endif
|
||||
if (spec->gpio_led)
|
||||
hda_call_check_power_status(codec, 0x01);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -5313,11 +5337,16 @@ static int patch_stac92hd83xxx(struct hda_codec *codec)
|
|||
if (spec == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
/* reset pin power-down; Windows may leave these bits after reboot */
|
||||
snd_hda_codec_write_cache(codec, codec->afg, 0, 0x7EC, 0);
|
||||
snd_hda_codec_write_cache(codec, codec->afg, 0, 0x7ED, 0);
|
||||
codec->no_trigger_sense = 1;
|
||||
codec->spec = spec;
|
||||
spec->linear_tone_beep = 1;
|
||||
codec->slave_dig_outs = stac92hd83xxx_slave_dig_outs;
|
||||
spec->digbeep_nid = 0x21;
|
||||
spec->dmic_nids = stac92hd83xxx_dmic_nids;
|
||||
spec->dmux_nids = stac92hd83xxx_mux_nids;
|
||||
spec->mux_nids = stac92hd83xxx_mux_nids;
|
||||
spec->num_muxes = ARRAY_SIZE(stac92hd83xxx_mux_nids);
|
||||
spec->adc_nids = stac92hd83xxx_adc_nids;
|
||||
|
|
@ -5363,9 +5392,13 @@ again:
|
|||
case 0x111d76d4:
|
||||
case 0x111d7605:
|
||||
case 0x111d76d5:
|
||||
case 0x111d76e7:
|
||||
if (spec->board_config == STAC_92HD83XXX_PWR_REF)
|
||||
break;
|
||||
spec->num_pwrs = 0;
|
||||
spec->num_dmics = stac92xx_connected_ports(codec,
|
||||
stac92hd83xxx_dmic_nids,
|
||||
STAC92HD83XXX_NUM_DMICS);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -5424,36 +5457,6 @@ again:
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* get the pin connection (fixed, none, etc) */
|
||||
static unsigned int stac_get_defcfg_connect(struct hda_codec *codec, int idx)
|
||||
{
|
||||
struct sigmatel_spec *spec = codec->spec;
|
||||
unsigned int cfg;
|
||||
|
||||
cfg = snd_hda_codec_get_pincfg(codec, spec->pin_nids[idx]);
|
||||
return get_defcfg_connect(cfg);
|
||||
}
|
||||
|
||||
static int stac92hd71bxx_connected_ports(struct hda_codec *codec,
|
||||
hda_nid_t *nids, int num_nids)
|
||||
{
|
||||
struct sigmatel_spec *spec = codec->spec;
|
||||
int idx, num;
|
||||
unsigned int def_conf;
|
||||
|
||||
for (num = 0; num < num_nids; num++) {
|
||||
for (idx = 0; idx < spec->num_pins; idx++)
|
||||
if (spec->pin_nids[idx] == nids[num])
|
||||
break;
|
||||
if (idx >= spec->num_pins)
|
||||
break;
|
||||
def_conf = stac_get_defcfg_connect(codec, idx);
|
||||
if (def_conf == AC_JACK_PORT_NONE)
|
||||
break;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
static int stac92hd71bxx_connected_smuxes(struct hda_codec *codec,
|
||||
hda_nid_t dig0pin)
|
||||
{
|
||||
|
|
@ -5592,7 +5595,7 @@ again:
|
|||
case 0x111d76b5:
|
||||
spec->init = stac92hd71bxx_core_init;
|
||||
codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
|
||||
spec->num_dmics = stac92hd71bxx_connected_ports(codec,
|
||||
spec->num_dmics = stac92xx_connected_ports(codec,
|
||||
stac92hd71bxx_dmic_nids,
|
||||
STAC92HD71BXX_NUM_DMICS);
|
||||
break;
|
||||
|
|
@ -5624,7 +5627,7 @@ again:
|
|||
snd_hda_codec_set_pincfg(codec, 0x0f, 0x40f000f0);
|
||||
snd_hda_codec_set_pincfg(codec, 0x19, 0x40f000f3);
|
||||
stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS - 1] = 0;
|
||||
spec->num_dmics = stac92hd71bxx_connected_ports(codec,
|
||||
spec->num_dmics = stac92xx_connected_ports(codec,
|
||||
stac92hd71bxx_dmic_nids,
|
||||
STAC92HD71BXX_NUM_DMICS - 1);
|
||||
break;
|
||||
|
|
@ -5638,7 +5641,7 @@ again:
|
|||
default:
|
||||
spec->init = stac92hd71bxx_core_init;
|
||||
codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
|
||||
spec->num_dmics = stac92hd71bxx_connected_ports(codec,
|
||||
spec->num_dmics = stac92xx_connected_ports(codec,
|
||||
stac92hd71bxx_dmic_nids,
|
||||
STAC92HD71BXX_NUM_DMICS);
|
||||
break;
|
||||
|
|
@ -6320,6 +6323,8 @@ static struct hda_codec_preset snd_hda_preset_sigmatel[] = {
|
|||
{ .id = 0x111d76cc, .name = "92HD89F3", .patch = patch_stac92hd73xx },
|
||||
{ .id = 0x111d76cd, .name = "92HD89F2", .patch = patch_stac92hd73xx },
|
||||
{ .id = 0x111d76ce, .name = "92HD89F1", .patch = patch_stac92hd73xx },
|
||||
{ .id = 0x111d76e0, .name = "92HD91BXX", .patch = patch_stac92hd83xxx},
|
||||
{ .id = 0x111d76e7, .name = "92HD90BXX", .patch = patch_stac92hd83xxx},
|
||||
{} /* terminator */
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -444,8 +444,8 @@ static hda_nid_t vt1812_adc_nids[2] = {
|
|||
|
||||
|
||||
/* add dynamic controls */
|
||||
static int via_add_control(struct via_spec *spec, int type, const char *name,
|
||||
unsigned long val)
|
||||
static int __via_add_control(struct via_spec *spec, int type, const char *name,
|
||||
int idx, unsigned long val)
|
||||
{
|
||||
struct snd_kcontrol_new *knew;
|
||||
|
||||
|
|
@ -463,6 +463,9 @@ static int via_add_control(struct via_spec *spec, int type, const char *name,
|
|||
return 0;
|
||||
}
|
||||
|
||||
#define via_add_control(spec, type, name, val) \
|
||||
__via_add_control(spec, type, name, 0, val)
|
||||
|
||||
static struct snd_kcontrol_new *via_clone_control(struct via_spec *spec,
|
||||
struct snd_kcontrol_new *tmpl)
|
||||
{
|
||||
|
|
@ -494,18 +497,18 @@ static void via_free_kctls(struct hda_codec *codec)
|
|||
|
||||
/* create input playback/capture controls for the given pin */
|
||||
static int via_new_analog_input(struct via_spec *spec, const char *ctlname,
|
||||
int idx, int mix_nid)
|
||||
int type_idx, int idx, int mix_nid)
|
||||
{
|
||||
char name[32];
|
||||
int err;
|
||||
|
||||
sprintf(name, "%s Playback Volume", ctlname);
|
||||
err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
|
||||
err = __via_add_control(spec, VIA_CTL_WIDGET_VOL, name, type_idx,
|
||||
HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
|
||||
if (err < 0)
|
||||
return err;
|
||||
sprintf(name, "%s Playback Switch", ctlname);
|
||||
err = via_add_control(spec, VIA_CTL_WIDGET_ANALOG_MUTE, name,
|
||||
err = __via_add_control(spec, VIA_CTL_WIDGET_ANALOG_MUTE, name, type_idx,
|
||||
HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
|
@ -557,17 +560,15 @@ static int is_smart51_pins(struct via_spec *spec, hda_nid_t pin);
|
|||
static void via_auto_init_analog_input(struct hda_codec *codec)
|
||||
{
|
||||
struct via_spec *spec = codec->spec;
|
||||
const struct auto_pin_cfg *cfg = &spec->autocfg;
|
||||
unsigned int ctl;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < AUTO_PIN_LAST; i++) {
|
||||
hda_nid_t nid = spec->autocfg.input_pins[i];
|
||||
if (!nid)
|
||||
continue;
|
||||
|
||||
for (i = 0; i < cfg->num_inputs; i++) {
|
||||
hda_nid_t nid = cfg->inputs[i].pin;
|
||||
if (spec->smart51_enabled && is_smart51_pins(spec, nid))
|
||||
ctl = PIN_OUT;
|
||||
else if (i <= AUTO_PIN_FRONT_MIC)
|
||||
else if (i == AUTO_PIN_MIC)
|
||||
ctl = PIN_VREF50;
|
||||
else
|
||||
ctl = PIN_IN;
|
||||
|
|
@ -1322,15 +1323,14 @@ static void mute_aa_path(struct hda_codec *codec, int mute)
|
|||
}
|
||||
static int is_smart51_pins(struct via_spec *spec, hda_nid_t pin)
|
||||
{
|
||||
int res = 0;
|
||||
int index;
|
||||
for (index = AUTO_PIN_MIC; index < AUTO_PIN_FRONT_LINE; index++) {
|
||||
if (pin == spec->autocfg.input_pins[index]) {
|
||||
res = 1;
|
||||
break;
|
||||
}
|
||||
const struct auto_pin_cfg *cfg = &spec->autocfg;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < cfg->num_inputs; i++) {
|
||||
if (pin == cfg->inputs[i].pin)
|
||||
return cfg->inputs[i].type <= AUTO_PIN_LINE_IN;
|
||||
}
|
||||
return res;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int via_smart51_info(struct snd_kcontrol *kcontrol,
|
||||
|
|
@ -1348,25 +1348,21 @@ static int via_smart51_get(struct snd_kcontrol *kcontrol,
|
|||
{
|
||||
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct via_spec *spec = codec->spec;
|
||||
int index[] = { AUTO_PIN_MIC, AUTO_PIN_FRONT_MIC, AUTO_PIN_LINE };
|
||||
const struct auto_pin_cfg *cfg = &spec->autocfg;
|
||||
int on = 1;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(index); i++) {
|
||||
hda_nid_t nid = spec->autocfg.input_pins[index[i]];
|
||||
if (nid) {
|
||||
int ctl =
|
||||
snd_hda_codec_read(codec, nid, 0,
|
||||
AC_VERB_GET_PIN_WIDGET_CONTROL,
|
||||
0);
|
||||
if (i == AUTO_PIN_FRONT_MIC
|
||||
&& spec->hp_independent_mode
|
||||
&& spec->codec_type != VT1718S)
|
||||
continue; /* ignore FMic for independent HP */
|
||||
if (ctl & AC_PINCTL_IN_EN
|
||||
&& !(ctl & AC_PINCTL_OUT_EN))
|
||||
on = 0;
|
||||
}
|
||||
for (i = 0; i < cfg->num_inputs; i++) {
|
||||
hda_nid_t nid = cfg->inputs[i].pin;
|
||||
int ctl = snd_hda_codec_read(codec, nid, 0,
|
||||
AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
|
||||
if (cfg->inputs[i].type > AUTO_PIN_LINE_IN)
|
||||
continue;
|
||||
if (cfg->inputs[i].type == AUTO_PIN_MIC &&
|
||||
spec->hp_independent_mode && spec->codec_type != VT1718S)
|
||||
continue; /* ignore FMic for independent HP */
|
||||
if ((ctl & AC_PINCTL_IN_EN) && !(ctl & AC_PINCTL_OUT_EN))
|
||||
on = 0;
|
||||
}
|
||||
*ucontrol->value.integer.value = on;
|
||||
return 0;
|
||||
|
|
@ -1377,36 +1373,38 @@ static int via_smart51_put(struct snd_kcontrol *kcontrol,
|
|||
{
|
||||
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct via_spec *spec = codec->spec;
|
||||
const struct auto_pin_cfg *cfg = &spec->autocfg;
|
||||
int out_in = *ucontrol->value.integer.value
|
||||
? AC_PINCTL_OUT_EN : AC_PINCTL_IN_EN;
|
||||
int index[] = { AUTO_PIN_MIC, AUTO_PIN_FRONT_MIC, AUTO_PIN_LINE };
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(index); i++) {
|
||||
hda_nid_t nid = spec->autocfg.input_pins[index[i]];
|
||||
if (i == AUTO_PIN_FRONT_MIC
|
||||
&& spec->hp_independent_mode
|
||||
&& spec->codec_type != VT1718S)
|
||||
for (i = 0; i < cfg->num_inputs; i++) {
|
||||
hda_nid_t nid = cfg->inputs[i].pin;
|
||||
unsigned int parm;
|
||||
|
||||
if (cfg->inputs[i].type > AUTO_PIN_LINE_IN)
|
||||
continue;
|
||||
if (cfg->inputs[i].type == AUTO_PIN_MIC &&
|
||||
spec->hp_independent_mode && spec->codec_type != VT1718S)
|
||||
continue; /* don't retask FMic for independent HP */
|
||||
if (nid) {
|
||||
unsigned int parm = snd_hda_codec_read(
|
||||
codec, nid, 0,
|
||||
AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
|
||||
parm &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
|
||||
parm |= out_in;
|
||||
snd_hda_codec_write(codec, nid, 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||
parm);
|
||||
if (out_in == AC_PINCTL_OUT_EN) {
|
||||
mute_aa_path(codec, 1);
|
||||
notify_aa_path_ctls(codec);
|
||||
}
|
||||
if (spec->codec_type == VT1718S)
|
||||
snd_hda_codec_amp_stereo(
|
||||
|
||||
parm = snd_hda_codec_read(codec, nid, 0,
|
||||
AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
|
||||
parm &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
|
||||
parm |= out_in;
|
||||
snd_hda_codec_write(codec, nid, 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||
parm);
|
||||
if (out_in == AC_PINCTL_OUT_EN) {
|
||||
mute_aa_path(codec, 1);
|
||||
notify_aa_path_ctls(codec);
|
||||
}
|
||||
if (spec->codec_type == VT1718S) {
|
||||
snd_hda_codec_amp_stereo(
|
||||
codec, nid, HDA_OUTPUT, 0, HDA_AMP_MUTE,
|
||||
HDA_AMP_UNMUTE);
|
||||
}
|
||||
if (i == AUTO_PIN_FRONT_MIC) {
|
||||
if (cfg->inputs[i].type == AUTO_PIN_MIC) {
|
||||
if (spec->codec_type == VT1708S
|
||||
|| spec->codec_type == VT1716S) {
|
||||
/* input = index 1 (AOW3) */
|
||||
|
|
@ -1442,7 +1440,7 @@ static struct snd_kcontrol_new via_smart51_mixer[2] = {
|
|||
static int via_smart51_build(struct via_spec *spec)
|
||||
{
|
||||
struct snd_kcontrol_new *knew;
|
||||
int index[] = { AUTO_PIN_MIC, AUTO_PIN_FRONT_MIC, AUTO_PIN_LINE };
|
||||
const struct auto_pin_cfg *cfg = &spec->autocfg;
|
||||
hda_nid_t nid;
|
||||
int i;
|
||||
|
||||
|
|
@ -1450,13 +1448,14 @@ static int via_smart51_build(struct via_spec *spec)
|
|||
if (knew == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(index); i++) {
|
||||
nid = spec->autocfg.input_pins[index[i]];
|
||||
if (nid) {
|
||||
for (i = 0; i < cfg->num_inputs; i++) {
|
||||
nid = cfg->inputs[i].pin;
|
||||
if (cfg->inputs[i].type <= AUTO_PIN_LINE_IN) {
|
||||
knew = via_clone_control(spec, &via_smart51_mixer[1]);
|
||||
if (knew == NULL)
|
||||
return -ENOMEM;
|
||||
knew->subdevice = nid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2375,13 +2374,8 @@ static void create_hp_imux(struct via_spec *spec)
|
|||
static const char *texts[] = { "OFF", "ON", NULL};
|
||||
|
||||
/* for hp mode select */
|
||||
i = 0;
|
||||
while (texts[i] != NULL) {
|
||||
imux->items[imux->num_items].label = texts[i];
|
||||
imux->items[imux->num_items].index = i;
|
||||
imux->num_items++;
|
||||
i++;
|
||||
}
|
||||
for (i = 0; texts[i]; i++)
|
||||
snd_hda_add_imux_item(imux, texts[i], i, NULL);
|
||||
|
||||
spec->hp_mux = &spec->private_imux[1];
|
||||
}
|
||||
|
|
@ -2413,51 +2407,53 @@ static int vt1708_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
|
|||
}
|
||||
|
||||
/* create playback/capture controls for input pins */
|
||||
static int vt1708_auto_create_analog_input_ctls(struct via_spec *spec,
|
||||
const struct auto_pin_cfg *cfg)
|
||||
static int vt_auto_create_analog_input_ctls(struct hda_codec *codec,
|
||||
const struct auto_pin_cfg *cfg,
|
||||
hda_nid_t cap_nid,
|
||||
hda_nid_t pin_idxs[], int num_idxs)
|
||||
{
|
||||
static char *labels[] = {
|
||||
"Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
|
||||
};
|
||||
struct via_spec *spec = codec->spec;
|
||||
struct hda_input_mux *imux = &spec->private_imux[0];
|
||||
int i, err, idx = 0;
|
||||
int i, err, idx, type, type_idx = 0;
|
||||
|
||||
/* for internal loopback recording select */
|
||||
imux->items[imux->num_items].label = "Stereo Mixer";
|
||||
imux->items[imux->num_items].index = idx;
|
||||
imux->num_items++;
|
||||
|
||||
for (i = 0; i < AUTO_PIN_LAST; i++) {
|
||||
if (!cfg->input_pins[i])
|
||||
continue;
|
||||
|
||||
switch (cfg->input_pins[i]) {
|
||||
case 0x1d: /* Mic */
|
||||
idx = 2;
|
||||
break;
|
||||
|
||||
case 0x1e: /* Line In */
|
||||
idx = 3;
|
||||
break;
|
||||
|
||||
case 0x21: /* Front Mic */
|
||||
idx = 4;
|
||||
break;
|
||||
|
||||
case 0x24: /* CD */
|
||||
idx = 1;
|
||||
for (idx = 0; idx < num_idxs; idx++) {
|
||||
if (pin_idxs[idx] == 0xff) {
|
||||
snd_hda_add_imux_item(imux, "Stereo Mixer", idx, NULL);
|
||||
break;
|
||||
}
|
||||
err = via_new_analog_input(spec, labels[i], idx, 0x17);
|
||||
}
|
||||
|
||||
for (i = 0; i < cfg->num_inputs; i++) {
|
||||
const char *label;
|
||||
type = cfg->inputs[i].type;
|
||||
for (idx = 0; idx < num_idxs; idx++)
|
||||
if (pin_idxs[idx] == cfg->inputs[i].pin)
|
||||
break;
|
||||
if (idx >= num_idxs)
|
||||
continue;
|
||||
if (i > 0 && type == cfg->inputs[i - 1].type)
|
||||
type_idx++;
|
||||
else
|
||||
type_idx = 0;
|
||||
label = hda_get_autocfg_input_label(codec, cfg, i);
|
||||
err = via_new_analog_input(spec, label, type_idx, idx, cap_nid);
|
||||
if (err < 0)
|
||||
return err;
|
||||
imux->items[imux->num_items].label = labels[i];
|
||||
imux->items[imux->num_items].index = idx;
|
||||
imux->num_items++;
|
||||
snd_hda_add_imux_item(imux, label, idx, NULL);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* create playback/capture controls for input pins */
|
||||
static int vt1708_auto_create_analog_input_ctls(struct hda_codec *codec,
|
||||
const struct auto_pin_cfg *cfg)
|
||||
{
|
||||
static hda_nid_t pin_idxs[] = { 0xff, 0x24, 0x1d, 0x1e, 0x21 };
|
||||
return vt_auto_create_analog_input_ctls(codec, cfg, 0x17, pin_idxs,
|
||||
ARRAY_SIZE(pin_idxs));
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
static struct hda_amp_list vt1708_loopbacks[] = {
|
||||
{ 0x17, HDA_INPUT, 1 },
|
||||
|
|
@ -2554,7 +2550,7 @@ static int vt1708_parse_auto_config(struct hda_codec *codec)
|
|||
err = vt1708_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = vt1708_auto_create_analog_input_ctls(spec, &spec->autocfg);
|
||||
err = vt1708_auto_create_analog_input_ctls(codec, &spec->autocfg);
|
||||
if (err < 0)
|
||||
return err;
|
||||
/* add jack detect on/off control */
|
||||
|
|
@ -3021,49 +3017,12 @@ static int vt1709_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
|
|||
}
|
||||
|
||||
/* create playback/capture controls for input pins */
|
||||
static int vt1709_auto_create_analog_input_ctls(struct via_spec *spec,
|
||||
static int vt1709_auto_create_analog_input_ctls(struct hda_codec *codec,
|
||||
const struct auto_pin_cfg *cfg)
|
||||
{
|
||||
static char *labels[] = {
|
||||
"Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
|
||||
};
|
||||
struct hda_input_mux *imux = &spec->private_imux[0];
|
||||
int i, err, idx = 0;
|
||||
|
||||
/* for internal loopback recording select */
|
||||
imux->items[imux->num_items].label = "Stereo Mixer";
|
||||
imux->items[imux->num_items].index = idx;
|
||||
imux->num_items++;
|
||||
|
||||
for (i = 0; i < AUTO_PIN_LAST; i++) {
|
||||
if (!cfg->input_pins[i])
|
||||
continue;
|
||||
|
||||
switch (cfg->input_pins[i]) {
|
||||
case 0x1d: /* Mic */
|
||||
idx = 2;
|
||||
break;
|
||||
|
||||
case 0x1e: /* Line In */
|
||||
idx = 3;
|
||||
break;
|
||||
|
||||
case 0x21: /* Front Mic */
|
||||
idx = 4;
|
||||
break;
|
||||
|
||||
case 0x23: /* CD */
|
||||
idx = 1;
|
||||
break;
|
||||
}
|
||||
err = via_new_analog_input(spec, labels[i], idx, 0x18);
|
||||
if (err < 0)
|
||||
return err;
|
||||
imux->items[imux->num_items].label = labels[i];
|
||||
imux->items[imux->num_items].index = idx;
|
||||
imux->num_items++;
|
||||
}
|
||||
return 0;
|
||||
static hda_nid_t pin_idxs[] = { 0xff, 0x23, 0x1d, 0x1e, 0x21 };
|
||||
return vt_auto_create_analog_input_ctls(codec, cfg, 0x18, pin_idxs,
|
||||
ARRAY_SIZE(pin_idxs));
|
||||
}
|
||||
|
||||
static int vt1709_parse_auto_config(struct hda_codec *codec)
|
||||
|
|
@ -3086,7 +3045,7 @@ static int vt1709_parse_auto_config(struct hda_codec *codec)
|
|||
err = vt1709_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = vt1709_auto_create_analog_input_ctls(spec, &spec->autocfg);
|
||||
err = vt1709_auto_create_analog_input_ctls(codec, &spec->autocfg);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
|
|
@ -3588,49 +3547,12 @@ static int vt1708B_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
|
|||
}
|
||||
|
||||
/* create playback/capture controls for input pins */
|
||||
static int vt1708B_auto_create_analog_input_ctls(struct via_spec *spec,
|
||||
static int vt1708B_auto_create_analog_input_ctls(struct hda_codec *codec,
|
||||
const struct auto_pin_cfg *cfg)
|
||||
{
|
||||
static char *labels[] = {
|
||||
"Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
|
||||
};
|
||||
struct hda_input_mux *imux = &spec->private_imux[0];
|
||||
int i, err, idx = 0;
|
||||
|
||||
/* for internal loopback recording select */
|
||||
imux->items[imux->num_items].label = "Stereo Mixer";
|
||||
imux->items[imux->num_items].index = idx;
|
||||
imux->num_items++;
|
||||
|
||||
for (i = 0; i < AUTO_PIN_LAST; i++) {
|
||||
if (!cfg->input_pins[i])
|
||||
continue;
|
||||
|
||||
switch (cfg->input_pins[i]) {
|
||||
case 0x1a: /* Mic */
|
||||
idx = 2;
|
||||
break;
|
||||
|
||||
case 0x1b: /* Line In */
|
||||
idx = 3;
|
||||
break;
|
||||
|
||||
case 0x1e: /* Front Mic */
|
||||
idx = 4;
|
||||
break;
|
||||
|
||||
case 0x1f: /* CD */
|
||||
idx = 1;
|
||||
break;
|
||||
}
|
||||
err = via_new_analog_input(spec, labels[i], idx, 0x16);
|
||||
if (err < 0)
|
||||
return err;
|
||||
imux->items[imux->num_items].label = labels[i];
|
||||
imux->items[imux->num_items].index = idx;
|
||||
imux->num_items++;
|
||||
}
|
||||
return 0;
|
||||
static hda_nid_t pin_idxs[] = { 0xff, 0x1f, 0x1a, 0x1b, 0x1e };
|
||||
return vt_auto_create_analog_input_ctls(codec, cfg, 0x16, pin_idxs,
|
||||
ARRAY_SIZE(pin_idxs));
|
||||
}
|
||||
|
||||
static int vt1708B_parse_auto_config(struct hda_codec *codec)
|
||||
|
|
@ -3653,7 +3575,7 @@ static int vt1708B_parse_auto_config(struct hda_codec *codec)
|
|||
err = vt1708B_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = vt1708B_auto_create_analog_input_ctls(spec, &spec->autocfg);
|
||||
err = vt1708B_auto_create_analog_input_ctls(codec, &spec->autocfg);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
|
|
@ -4061,49 +3983,12 @@ static int vt1708S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
|
|||
}
|
||||
|
||||
/* create playback/capture controls for input pins */
|
||||
static int vt1708S_auto_create_analog_input_ctls(struct via_spec *spec,
|
||||
static int vt1708S_auto_create_analog_input_ctls(struct hda_codec *codec,
|
||||
const struct auto_pin_cfg *cfg)
|
||||
{
|
||||
static char *labels[] = {
|
||||
"Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
|
||||
};
|
||||
struct hda_input_mux *imux = &spec->private_imux[0];
|
||||
int i, err, idx = 0;
|
||||
|
||||
/* for internal loopback recording select */
|
||||
imux->items[imux->num_items].label = "Stereo Mixer";
|
||||
imux->items[imux->num_items].index = 5;
|
||||
imux->num_items++;
|
||||
|
||||
for (i = 0; i < AUTO_PIN_LAST; i++) {
|
||||
if (!cfg->input_pins[i])
|
||||
continue;
|
||||
|
||||
switch (cfg->input_pins[i]) {
|
||||
case 0x1a: /* Mic */
|
||||
idx = 2;
|
||||
break;
|
||||
|
||||
case 0x1b: /* Line In */
|
||||
idx = 3;
|
||||
break;
|
||||
|
||||
case 0x1e: /* Front Mic */
|
||||
idx = 4;
|
||||
break;
|
||||
|
||||
case 0x1f: /* CD */
|
||||
idx = 1;
|
||||
break;
|
||||
}
|
||||
err = via_new_analog_input(spec, labels[i], idx, 0x16);
|
||||
if (err < 0)
|
||||
return err;
|
||||
imux->items[imux->num_items].label = labels[i];
|
||||
imux->items[imux->num_items].index = idx-1;
|
||||
imux->num_items++;
|
||||
}
|
||||
return 0;
|
||||
static hda_nid_t pin_idxs[] = { 0x1f, 0x1a, 0x1b, 0x1e, 0, 0xff };
|
||||
return vt_auto_create_analog_input_ctls(codec, cfg, 0x16, pin_idxs,
|
||||
ARRAY_SIZE(pin_idxs));
|
||||
}
|
||||
|
||||
/* fill out digital output widgets; one for master and one for slave outputs */
|
||||
|
|
@ -4151,7 +4036,7 @@ static int vt1708S_parse_auto_config(struct hda_codec *codec)
|
|||
err = vt1708S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = vt1708S_auto_create_analog_input_ctls(spec, &spec->autocfg);
|
||||
err = vt1708S_auto_create_analog_input_ctls(codec, &spec->autocfg);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
|
|
@ -4441,58 +4326,20 @@ static int vt1702_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
|
|||
imux = &spec->private_imux[1];
|
||||
|
||||
/* for hp mode select */
|
||||
i = 0;
|
||||
while (texts[i] != NULL) {
|
||||
imux->items[imux->num_items].label = texts[i];
|
||||
imux->items[imux->num_items].index = i;
|
||||
imux->num_items++;
|
||||
i++;
|
||||
}
|
||||
for (i = 0; texts[i]; i++)
|
||||
snd_hda_add_imux_item(imux, texts[i], i, NULL);
|
||||
|
||||
spec->hp_mux = &spec->private_imux[1];
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* create playback/capture controls for input pins */
|
||||
static int vt1702_auto_create_analog_input_ctls(struct via_spec *spec,
|
||||
static int vt1702_auto_create_analog_input_ctls(struct hda_codec *codec,
|
||||
const struct auto_pin_cfg *cfg)
|
||||
{
|
||||
static char *labels[] = {
|
||||
"Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
|
||||
};
|
||||
struct hda_input_mux *imux = &spec->private_imux[0];
|
||||
int i, err, idx = 0;
|
||||
|
||||
/* for internal loopback recording select */
|
||||
imux->items[imux->num_items].label = "Stereo Mixer";
|
||||
imux->items[imux->num_items].index = 3;
|
||||
imux->num_items++;
|
||||
|
||||
for (i = 0; i < AUTO_PIN_LAST; i++) {
|
||||
if (!cfg->input_pins[i])
|
||||
continue;
|
||||
|
||||
switch (cfg->input_pins[i]) {
|
||||
case 0x14: /* Mic */
|
||||
idx = 1;
|
||||
break;
|
||||
|
||||
case 0x15: /* Line In */
|
||||
idx = 2;
|
||||
break;
|
||||
|
||||
case 0x18: /* Front Mic */
|
||||
idx = 3;
|
||||
break;
|
||||
}
|
||||
err = via_new_analog_input(spec, labels[i], idx, 0x1A);
|
||||
if (err < 0)
|
||||
return err;
|
||||
imux->items[imux->num_items].label = labels[i];
|
||||
imux->items[imux->num_items].index = idx-1;
|
||||
imux->num_items++;
|
||||
}
|
||||
return 0;
|
||||
static hda_nid_t pin_idxs[] = { 0x14, 0x15, 0x18, 0xff };
|
||||
return vt_auto_create_analog_input_ctls(codec, cfg, 0x1a, pin_idxs,
|
||||
ARRAY_SIZE(pin_idxs));
|
||||
}
|
||||
|
||||
static int vt1702_parse_auto_config(struct hda_codec *codec)
|
||||
|
|
@ -4521,7 +4368,7 @@ static int vt1702_parse_auto_config(struct hda_codec *codec)
|
|||
(0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
|
||||
(0x5 << AC_AMPCAP_STEP_SIZE_SHIFT) |
|
||||
(1 << AC_AMPCAP_MUTE_SHIFT));
|
||||
err = vt1702_auto_create_analog_input_ctls(spec, &spec->autocfg);
|
||||
err = vt1702_auto_create_analog_input_ctls(codec, &spec->autocfg);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
|
|
@ -4872,49 +4719,12 @@ static int vt1718S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
|
|||
}
|
||||
|
||||
/* create playback/capture controls for input pins */
|
||||
static int vt1718S_auto_create_analog_input_ctls(struct via_spec *spec,
|
||||
static int vt1718S_auto_create_analog_input_ctls(struct hda_codec *codec,
|
||||
const struct auto_pin_cfg *cfg)
|
||||
{
|
||||
static char *labels[] = {
|
||||
"Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
|
||||
};
|
||||
struct hda_input_mux *imux = &spec->private_imux[0];
|
||||
int i, err, idx = 0;
|
||||
|
||||
/* for internal loopback recording select */
|
||||
imux->items[imux->num_items].label = "Stereo Mixer";
|
||||
imux->items[imux->num_items].index = 5;
|
||||
imux->num_items++;
|
||||
|
||||
for (i = 0; i < AUTO_PIN_LAST; i++) {
|
||||
if (!cfg->input_pins[i])
|
||||
continue;
|
||||
|
||||
switch (cfg->input_pins[i]) {
|
||||
case 0x2b: /* Mic */
|
||||
idx = 1;
|
||||
break;
|
||||
|
||||
case 0x2a: /* Line In */
|
||||
idx = 2;
|
||||
break;
|
||||
|
||||
case 0x29: /* Front Mic */
|
||||
idx = 3;
|
||||
break;
|
||||
|
||||
case 0x2c: /* CD */
|
||||
idx = 0;
|
||||
break;
|
||||
}
|
||||
err = via_new_analog_input(spec, labels[i], idx, 0x21);
|
||||
if (err < 0)
|
||||
return err;
|
||||
imux->items[imux->num_items].label = labels[i];
|
||||
imux->items[imux->num_items].index = idx;
|
||||
imux->num_items++;
|
||||
}
|
||||
return 0;
|
||||
static hda_nid_t pin_idxs[] = { 0x2c, 0x2b, 0x2a, 0x29, 0, 0xff };
|
||||
return vt_auto_create_analog_input_ctls(codec, cfg, 0x21, pin_idxs,
|
||||
ARRAY_SIZE(pin_idxs));
|
||||
}
|
||||
|
||||
static int vt1718S_parse_auto_config(struct hda_codec *codec)
|
||||
|
|
@ -4938,7 +4748,7 @@ static int vt1718S_parse_auto_config(struct hda_codec *codec)
|
|||
err = vt1718S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = vt1718S_auto_create_analog_input_ctls(spec, &spec->autocfg);
|
||||
err = vt1718S_auto_create_analog_input_ctls(codec, &spec->autocfg);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
|
|
@ -5371,49 +5181,12 @@ static int vt1716S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
|
|||
}
|
||||
|
||||
/* create playback/capture controls for input pins */
|
||||
static int vt1716S_auto_create_analog_input_ctls(struct via_spec *spec,
|
||||
static int vt1716S_auto_create_analog_input_ctls(struct hda_codec *codec,
|
||||
const struct auto_pin_cfg *cfg)
|
||||
{
|
||||
static char *labels[] = {
|
||||
"Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
|
||||
};
|
||||
struct hda_input_mux *imux = &spec->private_imux[0];
|
||||
int i, err, idx = 0;
|
||||
|
||||
/* for internal loopback recording select */
|
||||
imux->items[imux->num_items].label = "Stereo Mixer";
|
||||
imux->items[imux->num_items].index = 5;
|
||||
imux->num_items++;
|
||||
|
||||
for (i = 0; i < AUTO_PIN_LAST; i++) {
|
||||
if (!cfg->input_pins[i])
|
||||
continue;
|
||||
|
||||
switch (cfg->input_pins[i]) {
|
||||
case 0x1a: /* Mic */
|
||||
idx = 2;
|
||||
break;
|
||||
|
||||
case 0x1b: /* Line In */
|
||||
idx = 3;
|
||||
break;
|
||||
|
||||
case 0x1e: /* Front Mic */
|
||||
idx = 4;
|
||||
break;
|
||||
|
||||
case 0x1f: /* CD */
|
||||
idx = 1;
|
||||
break;
|
||||
}
|
||||
err = via_new_analog_input(spec, labels[i], idx, 0x16);
|
||||
if (err < 0)
|
||||
return err;
|
||||
imux->items[imux->num_items].label = labels[i];
|
||||
imux->items[imux->num_items].index = idx-1;
|
||||
imux->num_items++;
|
||||
}
|
||||
return 0;
|
||||
static hda_nid_t pin_idxs[] = { 0x1f, 0x1a, 0x1b, 0x1e, 0, 0xff };
|
||||
return vt_auto_create_analog_input_ctls(codec, cfg, 0x16, pin_idxs,
|
||||
ARRAY_SIZE(pin_idxs));
|
||||
}
|
||||
|
||||
static int vt1716S_parse_auto_config(struct hda_codec *codec)
|
||||
|
|
@ -5436,7 +5209,7 @@ static int vt1716S_parse_auto_config(struct hda_codec *codec)
|
|||
err = vt1716S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = vt1716S_auto_create_analog_input_ctls(spec, &spec->autocfg);
|
||||
err = vt1716S_auto_create_analog_input_ctls(codec, &spec->autocfg);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
|
|
@ -5717,54 +5490,25 @@ static int vt2002P_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
|
|||
}
|
||||
|
||||
/* create playback/capture controls for input pins */
|
||||
static int vt2002P_auto_create_analog_input_ctls(struct via_spec *spec,
|
||||
static int vt2002P_auto_create_analog_input_ctls(struct hda_codec *codec,
|
||||
const struct auto_pin_cfg *cfg)
|
||||
{
|
||||
static char *labels[] = {
|
||||
"Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
|
||||
};
|
||||
struct via_spec *spec = codec->spec;
|
||||
struct hda_input_mux *imux = &spec->private_imux[0];
|
||||
int i, err, idx = 0;
|
||||
|
||||
for (i = 0; i < AUTO_PIN_LAST; i++) {
|
||||
if (!cfg->input_pins[i])
|
||||
continue;
|
||||
|
||||
switch (cfg->input_pins[i]) {
|
||||
case 0x2b: /* Mic */
|
||||
idx = 0;
|
||||
break;
|
||||
|
||||
case 0x2a: /* Line In */
|
||||
idx = 1;
|
||||
break;
|
||||
|
||||
case 0x29: /* Front Mic */
|
||||
idx = 2;
|
||||
break;
|
||||
}
|
||||
err = via_new_analog_input(spec, labels[i], idx, 0x21);
|
||||
if (err < 0)
|
||||
return err;
|
||||
imux->items[imux->num_items].label = labels[i];
|
||||
imux->items[imux->num_items].index = idx;
|
||||
imux->num_items++;
|
||||
}
|
||||
static hda_nid_t pin_idxs[] = { 0x2b, 0x2a, 0x29, 0xff };
|
||||
int err;
|
||||
|
||||
err = vt_auto_create_analog_input_ctls(codec, cfg, 0x21, pin_idxs,
|
||||
ARRAY_SIZE(pin_idxs));
|
||||
if (err < 0)
|
||||
return err;
|
||||
/* build volume/mute control of loopback */
|
||||
err = via_new_analog_input(spec, "Stereo Mixer", 3, 0x21);
|
||||
err = via_new_analog_input(spec, "Stereo Mixer", 0, 3, 0x21);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* for internal loopback recording select */
|
||||
imux->items[imux->num_items].label = "Stereo Mixer";
|
||||
imux->items[imux->num_items].index = 3;
|
||||
imux->num_items++;
|
||||
|
||||
/* for digital mic select */
|
||||
imux->items[imux->num_items].label = "Digital Mic";
|
||||
imux->items[imux->num_items].index = 4;
|
||||
imux->num_items++;
|
||||
snd_hda_add_imux_item(imux, "Digital Mic", 4, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -5792,7 +5536,7 @@ static int vt2002P_parse_auto_config(struct hda_codec *codec)
|
|||
err = vt2002P_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = vt2002P_auto_create_analog_input_ctls(spec, &spec->autocfg);
|
||||
err = vt2002P_auto_create_analog_input_ctls(codec, &spec->autocfg);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
|
|
@ -6067,53 +5811,26 @@ static int vt1812_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
|
|||
}
|
||||
|
||||
/* create playback/capture controls for input pins */
|
||||
static int vt1812_auto_create_analog_input_ctls(struct via_spec *spec,
|
||||
static int vt1812_auto_create_analog_input_ctls(struct hda_codec *codec,
|
||||
const struct auto_pin_cfg *cfg)
|
||||
{
|
||||
static char *labels[] = {
|
||||
"Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
|
||||
};
|
||||
struct via_spec *spec = codec->spec;
|
||||
struct hda_input_mux *imux = &spec->private_imux[0];
|
||||
int i, err, idx = 0;
|
||||
static hda_nid_t pin_idxs[] = { 0x2b, 0x2a, 0x29, 0, 0, 0xff };
|
||||
int err;
|
||||
|
||||
for (i = 0; i < AUTO_PIN_LAST; i++) {
|
||||
if (!cfg->input_pins[i])
|
||||
continue;
|
||||
|
||||
switch (cfg->input_pins[i]) {
|
||||
case 0x2b: /* Mic */
|
||||
idx = 0;
|
||||
break;
|
||||
|
||||
case 0x2a: /* Line In */
|
||||
idx = 1;
|
||||
break;
|
||||
|
||||
case 0x29: /* Front Mic */
|
||||
idx = 2;
|
||||
break;
|
||||
}
|
||||
err = via_new_analog_input(spec, labels[i], idx, 0x21);
|
||||
if (err < 0)
|
||||
return err;
|
||||
imux->items[imux->num_items].label = labels[i];
|
||||
imux->items[imux->num_items].index = idx;
|
||||
imux->num_items++;
|
||||
}
|
||||
/* build volume/mute control of loopback */
|
||||
err = via_new_analog_input(spec, "Stereo Mixer", 5, 0x21);
|
||||
err = vt_auto_create_analog_input_ctls(codec, cfg, 0x21, pin_idxs,
|
||||
ARRAY_SIZE(pin_idxs));
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* for internal loopback recording select */
|
||||
imux->items[imux->num_items].label = "Stereo Mixer";
|
||||
imux->items[imux->num_items].index = 5;
|
||||
imux->num_items++;
|
||||
/* build volume/mute control of loopback */
|
||||
err = via_new_analog_input(spec, "Stereo Mixer", 0, 5, 0x21);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* for digital mic select */
|
||||
imux->items[imux->num_items].label = "Digital Mic";
|
||||
imux->items[imux->num_items].index = 6;
|
||||
imux->num_items++;
|
||||
snd_hda_add_imux_item(imux, "Digital Mic", 6, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -6141,7 +5858,7 @@ static int vt1812_parse_auto_config(struct hda_codec *codec)
|
|||
err = vt1812_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = vt1812_auto_create_analog_input_ctls(spec, &spec->autocfg);
|
||||
err = vt1812_auto_create_analog_input_ctls(codec, &spec->autocfg);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
|
|
|
|||
|
|
@ -563,6 +563,7 @@ static int __devinit snd_ice1712_delta_init(struct snd_ice1712 *ice)
|
|||
case ICE1712_SUBDEVICE_DELTA1010E:
|
||||
case ICE1712_SUBDEVICE_DELTA1010LT:
|
||||
case ICE1712_SUBDEVICE_MEDIASTATION:
|
||||
case ICE1712_SUBDEVICE_EDIROLDA2496:
|
||||
ice->num_total_dacs = 8;
|
||||
ice->num_total_adcs = 8;
|
||||
break;
|
||||
|
|
@ -635,6 +636,7 @@ static int __devinit snd_ice1712_delta_init(struct snd_ice1712 *ice)
|
|||
err = snd_ice1712_akm4xxx_init(ak, &akm_delta410, &akm_delta410_priv, ice);
|
||||
break;
|
||||
case ICE1712_SUBDEVICE_DELTA1010LT:
|
||||
case ICE1712_SUBDEVICE_EDIROLDA2496:
|
||||
err = snd_ice1712_akm4xxx_init(ak, &akm_delta1010lt, &akm_delta1010lt_priv, ice);
|
||||
break;
|
||||
case ICE1712_SUBDEVICE_DELTA66:
|
||||
|
|
@ -734,6 +736,7 @@ static int __devinit snd_ice1712_delta_add_controls(struct snd_ice1712 *ice)
|
|||
case ICE1712_SUBDEVICE_DELTA66:
|
||||
case ICE1712_SUBDEVICE_VX442:
|
||||
case ICE1712_SUBDEVICE_DELTA66E:
|
||||
case ICE1712_SUBDEVICE_EDIROLDA2496:
|
||||
err = snd_ice1712_akm4xxx_build_controls(ice);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
|
@ -813,5 +816,12 @@ struct snd_ice1712_card_info snd_ice1712_delta_cards[] __devinitdata = {
|
|||
.chip_init = snd_ice1712_delta_init,
|
||||
.build_controls = snd_ice1712_delta_add_controls,
|
||||
},
|
||||
{
|
||||
.subvendor = ICE1712_SUBDEVICE_EDIROLDA2496,
|
||||
.name = "Edirol DA2496",
|
||||
.model = "da2496",
|
||||
.chip_init = snd_ice1712_delta_init,
|
||||
.build_controls = snd_ice1712_delta_add_controls,
|
||||
},
|
||||
{ } /* terminator */
|
||||
};
|
||||
|
|
|
|||
|
|
@ -34,7 +34,8 @@
|
|||
"{MidiMan M Audio,Delta 410},"\
|
||||
"{MidiMan M Audio,Audiophile 24/96},"\
|
||||
"{Digigram,VX442},"\
|
||||
"{Lionstracs,Mediastation},"
|
||||
"{Lionstracs,Mediastation},"\
|
||||
"{Edirol,DA2496},"
|
||||
|
||||
#define ICE1712_SUBDEVICE_DELTA1010 0x121430d6
|
||||
#define ICE1712_SUBDEVICE_DELTA1010E 0xff1430d6
|
||||
|
|
@ -47,6 +48,7 @@
|
|||
#define ICE1712_SUBDEVICE_DELTA1010LT 0x12143bd6
|
||||
#define ICE1712_SUBDEVICE_VX442 0x12143cd6
|
||||
#define ICE1712_SUBDEVICE_MEDIASTATION 0x694c0100
|
||||
#define ICE1712_SUBDEVICE_EDIROLDA2496 0xce164010
|
||||
|
||||
/* entry point */
|
||||
extern struct snd_ice1712_card_info snd_ice1712_delta_cards[];
|
||||
|
|
|
|||
|
|
@ -638,7 +638,7 @@ static struct snd_kcontrol_new pontis_controls[] __devinitdata = {
|
|||
*/
|
||||
static void wm_proc_regs_write(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
|
||||
{
|
||||
struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data;
|
||||
struct snd_ice1712 *ice = entry->private_data;
|
||||
char line[64];
|
||||
unsigned int reg, val;
|
||||
mutex_lock(&ice->gpio_mutex);
|
||||
|
|
@ -653,7 +653,7 @@ static void wm_proc_regs_write(struct snd_info_entry *entry, struct snd_info_buf
|
|||
|
||||
static void wm_proc_regs_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
|
||||
{
|
||||
struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data;
|
||||
struct snd_ice1712 *ice = entry->private_data;
|
||||
int reg, val;
|
||||
|
||||
mutex_lock(&ice->gpio_mutex);
|
||||
|
|
@ -676,7 +676,7 @@ static void wm_proc_init(struct snd_ice1712 *ice)
|
|||
|
||||
static void cs_proc_regs_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
|
||||
{
|
||||
struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data;
|
||||
struct snd_ice1712 *ice = entry->private_data;
|
||||
int reg, val;
|
||||
|
||||
mutex_lock(&ice->gpio_mutex);
|
||||
|
|
|
|||
|
|
@ -654,7 +654,7 @@ static int prodigy192_ak4114_init(struct snd_ice1712 *ice)
|
|||
static void stac9460_proc_regs_read(struct snd_info_entry *entry,
|
||||
struct snd_info_buffer *buffer)
|
||||
{
|
||||
struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data;
|
||||
struct snd_ice1712 *ice = entry->private_data;
|
||||
int reg, val;
|
||||
/* registers 0x0 - 0x14 */
|
||||
for (reg = 0; reg <= 0x15; reg++) {
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@ static DEFINE_PCI_DEVICE_TABLE(oxygen_ids) = {
|
|||
{ OXYGEN_PCI_SUBID(0x13f6, 0x0001), .driver_data = MODEL_CMEDIA_REF },
|
||||
{ OXYGEN_PCI_SUBID(0x13f6, 0x0010), .driver_data = MODEL_CMEDIA_REF },
|
||||
{ OXYGEN_PCI_SUBID(0x13f6, 0x8788), .driver_data = MODEL_CMEDIA_REF },
|
||||
{ OXYGEN_PCI_SUBID(0x13f6, 0xffff), .driver_data = MODEL_CMEDIA_REF },
|
||||
{ OXYGEN_PCI_SUBID(0x147a, 0xa017), .driver_data = MODEL_CMEDIA_REF },
|
||||
{ OXYGEN_PCI_SUBID(0x1a58, 0x0910), .driver_data = MODEL_CMEDIA_REF },
|
||||
{ OXYGEN_PCI_SUBID(0x415a, 0x5431), .driver_data = MODEL_MERIDIAN },
|
||||
|
|
@ -505,7 +506,8 @@ static const struct oxygen_model model_generic = {
|
|||
PLAYBACK_2_TO_AC97_1 |
|
||||
CAPTURE_0_FROM_I2S_1 |
|
||||
CAPTURE_1_FROM_SPDIF |
|
||||
CAPTURE_2_FROM_AC97_1,
|
||||
CAPTURE_2_FROM_AC97_1 |
|
||||
AC97_CD_INPUT,
|
||||
.dac_channels = 8,
|
||||
.dac_volume_min = 0,
|
||||
.dac_volume_max = 255,
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
/* CAPTURE_3_FROM_I2S_3 not implemented */
|
||||
#define MIDI_OUTPUT 0x0800
|
||||
#define MIDI_INPUT 0x1000
|
||||
#define AC97_CD_INPUT 0x2000
|
||||
|
||||
enum {
|
||||
CONTROL_SPDIF_PCM,
|
||||
|
|
|
|||
|
|
@ -308,25 +308,46 @@ static void oxygen_restore_eeprom(struct oxygen *chip,
|
|||
}
|
||||
}
|
||||
|
||||
static void pci_bridge_magic(void)
|
||||
static void configure_pcie_bridge(struct pci_dev *pci)
|
||||
{
|
||||
struct pci_dev *pci = NULL;
|
||||
enum { PEX811X, PI7C9X110 };
|
||||
static const struct pci_device_id bridge_ids[] = {
|
||||
{ PCI_VDEVICE(PLX, 0x8111), .driver_data = PEX811X },
|
||||
{ PCI_VDEVICE(PLX, 0x8112), .driver_data = PEX811X },
|
||||
{ PCI_DEVICE(0x12d8, 0xe110), .driver_data = PI7C9X110 },
|
||||
{ }
|
||||
};
|
||||
struct pci_dev *bridge;
|
||||
const struct pci_device_id *id;
|
||||
u32 tmp;
|
||||
|
||||
for (;;) {
|
||||
/* If there is any Pericom PI7C9X110 PCI-E/PCI bridge ... */
|
||||
pci = pci_get_device(0x12d8, 0xe110, pci);
|
||||
if (!pci)
|
||||
break;
|
||||
/*
|
||||
* ... configure its secondary internal arbiter to park to
|
||||
* the secondary port, instead of to the last master.
|
||||
*/
|
||||
if (!pci_read_config_dword(pci, 0x40, &tmp)) {
|
||||
tmp |= 1;
|
||||
pci_write_config_dword(pci, 0x40, tmp);
|
||||
}
|
||||
/* Why? Try asking C-Media. */
|
||||
if (!pci->bus || !pci->bus->self)
|
||||
return;
|
||||
bridge = pci->bus->self;
|
||||
|
||||
id = pci_match_id(bridge_ids, bridge);
|
||||
if (!id)
|
||||
return;
|
||||
|
||||
switch (id->driver_data) {
|
||||
case PEX811X: /* PLX PEX8111/PEX8112 PCIe/PCI bridge */
|
||||
pci_read_config_dword(bridge, 0x48, &tmp);
|
||||
tmp |= 1; /* enable blind prefetching */
|
||||
tmp |= 1 << 11; /* enable beacon generation */
|
||||
pci_write_config_dword(bridge, 0x48, tmp);
|
||||
|
||||
pci_write_config_dword(bridge, 0x84, 0x0c);
|
||||
pci_read_config_dword(bridge, 0x88, &tmp);
|
||||
tmp &= ~(7 << 27);
|
||||
tmp |= 2 << 27; /* set prefetch size to 128 bytes */
|
||||
pci_write_config_dword(bridge, 0x88, tmp);
|
||||
break;
|
||||
|
||||
case PI7C9X110: /* Pericom PI7C9X110 PCIe/PCI bridge */
|
||||
pci_read_config_dword(bridge, 0x40, &tmp);
|
||||
tmp |= 1; /* park the PCI arbiter to the sound chip */
|
||||
pci_write_config_dword(bridge, 0x40, tmp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -613,7 +634,7 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
|
|||
snd_card_set_dev(card, &pci->dev);
|
||||
card->private_free = oxygen_card_free;
|
||||
|
||||
pci_bridge_magic();
|
||||
configure_pcie_bridge(pci);
|
||||
oxygen_init(chip);
|
||||
chip->model.init(chip);
|
||||
|
||||
|
|
|
|||
|
|
@ -708,7 +708,7 @@ static int ac97_fp_rec_volume_put(struct snd_kcontrol *ctl,
|
|||
.private_value = ((codec) << 24) | ((stereo) << 16) | (index), \
|
||||
}
|
||||
|
||||
static DECLARE_TLV_DB_SCALE(monitor_db_scale, -1000, 1000, 0);
|
||||
static DECLARE_TLV_DB_SCALE(monitor_db_scale, -600, 600, 0);
|
||||
static DECLARE_TLV_DB_SCALE(ac97_db_scale, -3450, 150, 0);
|
||||
static DECLARE_TLV_DB_SCALE(ac97_rec_db_scale, 0, 150, 0);
|
||||
|
||||
|
|
@ -972,6 +972,9 @@ static int add_controls(struct oxygen *chip,
|
|||
if (!strcmp(template.name, "Stereo Upmixing") &&
|
||||
chip->model.dac_channels == 2)
|
||||
continue;
|
||||
if (!strncmp(template.name, "CD Capture ", 11) &&
|
||||
!(chip->model.device_config & AC97_CD_INPUT))
|
||||
continue;
|
||||
if (!strcmp(template.name, "Master Playback Volume") &&
|
||||
chip->model.dac_tlv) {
|
||||
template.tlv.p = chip->model.dac_tlv;
|
||||
|
|
|
|||
|
|
@ -56,8 +56,8 @@ static const struct snd_pcm_hardware oxygen_stereo_hardware = {
|
|||
.channels_max = 2,
|
||||
.buffer_bytes_max = BUFFER_BYTES_MAX,
|
||||
.period_bytes_min = PERIOD_BYTES_MIN,
|
||||
.period_bytes_max = BUFFER_BYTES_MAX / 2,
|
||||
.periods_min = 2,
|
||||
.period_bytes_max = BUFFER_BYTES_MAX,
|
||||
.periods_min = 1,
|
||||
.periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN,
|
||||
};
|
||||
static const struct snd_pcm_hardware oxygen_multichannel_hardware = {
|
||||
|
|
@ -82,8 +82,8 @@ static const struct snd_pcm_hardware oxygen_multichannel_hardware = {
|
|||
.channels_max = 8,
|
||||
.buffer_bytes_max = BUFFER_BYTES_MAX_MULTICH,
|
||||
.period_bytes_min = PERIOD_BYTES_MIN,
|
||||
.period_bytes_max = BUFFER_BYTES_MAX_MULTICH / 2,
|
||||
.periods_min = 2,
|
||||
.period_bytes_max = BUFFER_BYTES_MAX_MULTICH,
|
||||
.periods_min = 1,
|
||||
.periods_max = BUFFER_BYTES_MAX_MULTICH / PERIOD_BYTES_MIN,
|
||||
};
|
||||
static const struct snd_pcm_hardware oxygen_ac97_hardware = {
|
||||
|
|
@ -100,8 +100,8 @@ static const struct snd_pcm_hardware oxygen_ac97_hardware = {
|
|||
.channels_max = 2,
|
||||
.buffer_bytes_max = BUFFER_BYTES_MAX,
|
||||
.period_bytes_min = PERIOD_BYTES_MIN,
|
||||
.period_bytes_max = BUFFER_BYTES_MAX / 2,
|
||||
.periods_min = 2,
|
||||
.period_bytes_max = BUFFER_BYTES_MAX,
|
||||
.periods_min = 1,
|
||||
.periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -436,13 +436,15 @@
|
|||
/* OXYGEN_CHANNEL_* */
|
||||
|
||||
#define OXYGEN_CODEC_VERSION 0xe4
|
||||
#define OXYGEN_XCID_MASK 0x07
|
||||
#define OXYGEN_CODEC_ID_MASK 0x07
|
||||
|
||||
#define OXYGEN_REVISION 0xe6
|
||||
#define OXYGEN_REVISION_XPKGID_MASK 0x0007
|
||||
#define OXYGEN_PACKAGE_ID_MASK 0x0007
|
||||
#define OXYGEN_PACKAGE_ID_8786 0x0004
|
||||
#define OXYGEN_PACKAGE_ID_8787 0x0006
|
||||
#define OXYGEN_PACKAGE_ID_8788 0x0007
|
||||
#define OXYGEN_REVISION_MASK 0xfff8
|
||||
#define OXYGEN_REVISION_2 0x0008 /* bit flag */
|
||||
#define OXYGEN_REVISION_8787 0x0014 /* 8 bits */
|
||||
#define OXYGEN_REVISION_2 0x0008
|
||||
|
||||
#define OXYGEN_OFFSIN_48K 0xe8
|
||||
#define OXYGEN_OFFSBASE_48K 0xe9
|
||||
|
|
|
|||
|
|
@ -25,9 +25,9 @@
|
|||
#include "xonar.h"
|
||||
|
||||
MODULE_AUTHOR("Clemens Ladisch <[email protected]>");
|
||||
MODULE_DESCRIPTION("Asus AVx00 driver");
|
||||
MODULE_DESCRIPTION("Asus Virtuoso driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_SUPPORTED_DEVICE("{{Asus,AV100},{Asus,AV200}}");
|
||||
MODULE_SUPPORTED_DEVICE("{{Asus,AV66},{Asus,AV100},{Asus,AV200}}");
|
||||
|
||||
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
|
||||
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
|
||||
|
|
@ -49,6 +49,7 @@ static DEFINE_PCI_DEVICE_TABLE(xonar_ids) = {
|
|||
{ OXYGEN_PCI_SUBID(0x1043, 0x834f) },
|
||||
{ OXYGEN_PCI_SUBID(0x1043, 0x835c) },
|
||||
{ OXYGEN_PCI_SUBID(0x1043, 0x835d) },
|
||||
{ OXYGEN_PCI_SUBID(0x1043, 0x835e) },
|
||||
{ OXYGEN_PCI_SUBID(0x1043, 0x838e) },
|
||||
{ OXYGEN_PCI_SUBID_BROKEN_EEPROM },
|
||||
{ }
|
||||
|
|
|
|||
|
|
@ -367,13 +367,6 @@ static void xonar_d1_line_mic_ac97_switch(struct oxygen *chip,
|
|||
|
||||
static const DECLARE_TLV_DB_SCALE(cs4362a_db_scale, -6000, 100, 0);
|
||||
|
||||
static int xonar_d1_control_filter(struct snd_kcontrol_new *template)
|
||||
{
|
||||
if (!strncmp(template->name, "CD Capture ", 11))
|
||||
return 1; /* no CD input */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xonar_d1_mixer_init(struct oxygen *chip)
|
||||
{
|
||||
int err;
|
||||
|
|
@ -391,7 +384,6 @@ static const struct oxygen_model model_xonar_d1 = {
|
|||
.longname = "Asus Virtuoso 100",
|
||||
.chip = "AV200",
|
||||
.init = xonar_d1_init,
|
||||
.control_filter = xonar_d1_control_filter,
|
||||
.mixer_init = xonar_d1_mixer_init,
|
||||
.cleanup = xonar_d1_cleanup,
|
||||
.suspend = xonar_d1_suspend,
|
||||
|
|
|
|||
|
|
@ -132,6 +132,18 @@
|
|||
* GPIO 5 <- 0
|
||||
*/
|
||||
|
||||
/*
|
||||
* Xonar HDAV1.3 Slim
|
||||
* ------------------
|
||||
*
|
||||
* CMI8788:
|
||||
*
|
||||
* GPIO 1 -> enable output
|
||||
*
|
||||
* TXD -> HDMI controller
|
||||
* RXD <- HDMI controller
|
||||
*/
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/mutex.h>
|
||||
|
|
@ -362,7 +374,6 @@ static void xonar_st_init_common(struct oxygen *chip)
|
|||
{
|
||||
struct xonar_pcm179x *data = chip->model_data;
|
||||
|
||||
data->generic.anti_pop_delay = 100;
|
||||
data->generic.output_enable_bit = GPIO_ST_OUTPUT_ENABLE;
|
||||
data->dacs = chip->model.private_data ? 4 : 1;
|
||||
data->hp_gain_offset = 2*-18;
|
||||
|
|
@ -408,6 +419,7 @@ static void xonar_st_init(struct oxygen *chip)
|
|||
{
|
||||
struct xonar_pcm179x *data = chip->model_data;
|
||||
|
||||
data->generic.anti_pop_delay = 100;
|
||||
data->has_cs2000 = 1;
|
||||
data->cs2000_fun_cfg_1 = CS2000_REF_CLK_DIV_1;
|
||||
|
||||
|
|
@ -428,6 +440,7 @@ static void xonar_stx_init(struct oxygen *chip)
|
|||
struct xonar_pcm179x *data = chip->model_data;
|
||||
|
||||
xonar_st_init_i2c(chip);
|
||||
data->generic.anti_pop_delay = 800;
|
||||
data->generic.ext_power_reg = OXYGEN_GPI_DATA;
|
||||
data->generic.ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK;
|
||||
data->generic.ext_power_bit = GPI_EXT_POWER;
|
||||
|
|
@ -915,13 +928,6 @@ static int xonar_d2_control_filter(struct snd_kcontrol_new *template)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int xonar_st_control_filter(struct snd_kcontrol_new *template)
|
||||
{
|
||||
if (!strncmp(template->name, "CD Capture ", 11))
|
||||
return 1; /* no CD input */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int add_pcm1796_controls(struct oxygen *chip)
|
||||
{
|
||||
int err;
|
||||
|
|
@ -991,7 +997,8 @@ static const struct oxygen_model model_xonar_d2 = {
|
|||
CAPTURE_0_FROM_I2S_2 |
|
||||
CAPTURE_1_FROM_SPDIF |
|
||||
MIDI_OUTPUT |
|
||||
MIDI_INPUT,
|
||||
MIDI_INPUT |
|
||||
AC97_CD_INPUT,
|
||||
.dac_channels = 8,
|
||||
.dac_volume_min = 255 - 2*60,
|
||||
.dac_volume_max = 255,
|
||||
|
|
@ -1037,7 +1044,6 @@ static const struct oxygen_model model_xonar_st = {
|
|||
.longname = "Asus Virtuoso 100",
|
||||
.chip = "AV200",
|
||||
.init = xonar_st_init,
|
||||
.control_filter = xonar_st_control_filter,
|
||||
.mixer_init = xonar_st_mixer_init,
|
||||
.cleanup = xonar_st_cleanup,
|
||||
.suspend = xonar_st_suspend,
|
||||
|
|
@ -1108,6 +1114,9 @@ int __devinit get_xonar_pcm179x_model(struct oxygen *chip,
|
|||
chip->model.resume = xonar_stx_resume;
|
||||
chip->model.set_dac_params = set_pcm1796_params;
|
||||
break;
|
||||
case 0x835e:
|
||||
snd_printk(KERN_ERR "the HDAV1.3 Slim is not supported\n");
|
||||
return -ENODEV;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,16 +25,24 @@
|
|||
* SPI 0 -> WM8766 (surround, center/LFE, back)
|
||||
* SPI 1 -> WM8776 (front, input)
|
||||
*
|
||||
* GPIO 4 <- headphone detect
|
||||
* GPIO 6 -> route input jack to input 1/2 (1/0)
|
||||
* GPIO 7 -> enable output to speakers
|
||||
* GPIO 8 -> enable output to speakers
|
||||
* GPIO 4 <- headphone detect, 0 = plugged
|
||||
* GPIO 6 -> route input jack to mic-in (0) or line-in (1)
|
||||
* GPIO 7 -> enable output to front L/R speaker channels
|
||||
* GPIO 8 -> enable output to other speaker channels and front panel headphone
|
||||
*
|
||||
* WM8766:
|
||||
*
|
||||
* input 1 <- line
|
||||
* input 2 <- mic
|
||||
* input 3 <- front mic
|
||||
* input 4 <- aux
|
||||
*/
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include <linux/delay.h>
|
||||
#include <sound/control.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/jack.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/tlv.h>
|
||||
|
|
@ -44,7 +52,8 @@
|
|||
|
||||
#define GPIO_DS_HP_DETECT 0x0010
|
||||
#define GPIO_DS_INPUT_ROUTE 0x0040
|
||||
#define GPIO_DS_OUTPUT_ENABLE 0x0180
|
||||
#define GPIO_DS_OUTPUT_FRONTLR 0x0080
|
||||
#define GPIO_DS_OUTPUT_ENABLE 0x0100
|
||||
|
||||
#define LC_CONTROL_LIMITER 0x40000000
|
||||
#define LC_CONTROL_ALC 0x20000000
|
||||
|
|
@ -56,6 +65,7 @@ struct xonar_wm87x6 {
|
|||
struct snd_kcontrol *line_adcmux_control;
|
||||
struct snd_kcontrol *mic_adcmux_control;
|
||||
struct snd_kcontrol *lc_controls[13];
|
||||
struct snd_jack *hp_jack;
|
||||
};
|
||||
|
||||
static void wm8776_write(struct oxygen *chip,
|
||||
|
|
@ -97,8 +107,12 @@ static void wm8766_write(struct oxygen *chip,
|
|||
(0 << OXYGEN_SPI_CODEC_SHIFT) |
|
||||
OXYGEN_SPI_CEN_LATCH_CLOCK_LO,
|
||||
(reg << 9) | value);
|
||||
if (reg < ARRAY_SIZE(data->wm8766_regs))
|
||||
if (reg < ARRAY_SIZE(data->wm8766_regs)) {
|
||||
if ((reg >= WM8766_LDA1 && reg <= WM8766_RDA1) ||
|
||||
(reg >= WM8766_LDA2 && reg <= WM8766_MASTDA))
|
||||
value &= ~WM8766_UPDATE;
|
||||
data->wm8766_regs[reg] = value;
|
||||
}
|
||||
}
|
||||
|
||||
static void wm8766_write_cached(struct oxygen *chip,
|
||||
|
|
@ -107,12 +121,8 @@ static void wm8766_write_cached(struct oxygen *chip,
|
|||
struct xonar_wm87x6 *data = chip->model_data;
|
||||
|
||||
if (reg >= ARRAY_SIZE(data->wm8766_regs) ||
|
||||
value != data->wm8766_regs[reg]) {
|
||||
if ((reg >= WM8766_LDA1 && reg <= WM8766_RDA1) ||
|
||||
(reg >= WM8766_LDA2 && reg <= WM8766_MASTDA))
|
||||
value &= ~WM8766_UPDATE;
|
||||
value != data->wm8766_regs[reg])
|
||||
wm8766_write(chip, reg, value);
|
||||
}
|
||||
}
|
||||
|
||||
static void wm8776_registers_init(struct oxygen *chip)
|
||||
|
|
@ -141,7 +151,10 @@ static void wm8776_registers_init(struct oxygen *chip)
|
|||
|
||||
static void wm8766_registers_init(struct oxygen *chip)
|
||||
{
|
||||
struct xonar_wm87x6 *data = chip->model_data;
|
||||
|
||||
wm8766_write(chip, WM8766_RESET, 0);
|
||||
wm8766_write(chip, WM8766_DAC_CTRL, data->wm8766_regs[WM8766_DAC_CTRL]);
|
||||
wm8766_write(chip, WM8766_INT_CTRL, WM8766_FMT_LJUST | WM8766_IWL_24);
|
||||
wm8766_write(chip, WM8766_DAC_CTRL2,
|
||||
WM8766_ZCD | (chip->dac_mute ? WM8766_DMUTE_MASK : 0));
|
||||
|
|
@ -170,6 +183,40 @@ static void wm8776_init(struct oxygen *chip)
|
|||
wm8776_registers_init(chip);
|
||||
}
|
||||
|
||||
static void wm8766_init(struct oxygen *chip)
|
||||
{
|
||||
struct xonar_wm87x6 *data = chip->model_data;
|
||||
|
||||
data->wm8766_regs[WM8766_DAC_CTRL] =
|
||||
WM8766_PL_LEFT_LEFT | WM8766_PL_RIGHT_RIGHT;
|
||||
wm8766_registers_init(chip);
|
||||
}
|
||||
|
||||
static void xonar_ds_handle_hp_jack(struct oxygen *chip)
|
||||
{
|
||||
struct xonar_wm87x6 *data = chip->model_data;
|
||||
bool hp_plugged;
|
||||
unsigned int reg;
|
||||
|
||||
mutex_lock(&chip->mutex);
|
||||
|
||||
hp_plugged = !(oxygen_read16(chip, OXYGEN_GPIO_DATA) &
|
||||
GPIO_DS_HP_DETECT);
|
||||
|
||||
oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
|
||||
hp_plugged ? 0 : GPIO_DS_OUTPUT_FRONTLR,
|
||||
GPIO_DS_OUTPUT_FRONTLR);
|
||||
|
||||
reg = data->wm8766_regs[WM8766_DAC_CTRL] & ~WM8766_MUTEALL;
|
||||
if (hp_plugged)
|
||||
reg |= WM8766_MUTEALL;
|
||||
wm8766_write_cached(chip, WM8766_DAC_CTRL, reg);
|
||||
|
||||
snd_jack_report(data->hp_jack, hp_plugged ? SND_JACK_HEADPHONE : 0);
|
||||
|
||||
mutex_unlock(&chip->mutex);
|
||||
}
|
||||
|
||||
static void xonar_ds_init(struct oxygen *chip)
|
||||
{
|
||||
struct xonar_wm87x6 *data = chip->model_data;
|
||||
|
|
@ -178,16 +225,22 @@ static void xonar_ds_init(struct oxygen *chip)
|
|||
data->generic.output_enable_bit = GPIO_DS_OUTPUT_ENABLE;
|
||||
|
||||
wm8776_init(chip);
|
||||
wm8766_registers_init(chip);
|
||||
wm8766_init(chip);
|
||||
|
||||
oxygen_write16_masked(chip, OXYGEN_GPIO_CONTROL, GPIO_DS_INPUT_ROUTE,
|
||||
GPIO_DS_HP_DETECT | GPIO_DS_INPUT_ROUTE);
|
||||
oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
|
||||
GPIO_DS_INPUT_ROUTE | GPIO_DS_OUTPUT_FRONTLR);
|
||||
oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL,
|
||||
GPIO_DS_HP_DETECT);
|
||||
oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_DS_INPUT_ROUTE);
|
||||
oxygen_set_bits16(chip, OXYGEN_GPIO_INTERRUPT_MASK, GPIO_DS_HP_DETECT);
|
||||
chip->interrupt_mask |= OXYGEN_INT_GPIO;
|
||||
|
||||
xonar_enable_output(chip);
|
||||
|
||||
snd_jack_new(chip->card, "Headphone",
|
||||
SND_JACK_HEADPHONE, &data->hp_jack);
|
||||
xonar_ds_handle_hp_jack(chip);
|
||||
|
||||
snd_component_add(chip->card, "WM8776");
|
||||
snd_component_add(chip->card, "WM8766");
|
||||
}
|
||||
|
|
@ -208,6 +261,7 @@ static void xonar_ds_resume(struct oxygen *chip)
|
|||
wm8776_registers_init(chip);
|
||||
wm8766_registers_init(chip);
|
||||
xonar_enable_output(chip);
|
||||
xonar_ds_handle_hp_jack(chip);
|
||||
}
|
||||
|
||||
static void wm8776_adc_hardware_filter(unsigned int channel,
|
||||
|
|
@ -323,12 +377,27 @@ static void update_wm87x6_mute(struct oxygen *chip)
|
|||
(chip->dac_mute ? WM8766_DMUTE_MASK : 0));
|
||||
}
|
||||
|
||||
static void update_wm8766_center_lfe_mix(struct oxygen *chip, bool mixed)
|
||||
{
|
||||
struct xonar_wm87x6 *data = chip->model_data;
|
||||
unsigned int reg;
|
||||
|
||||
/*
|
||||
* The WM8766 can mix left and right channels, but this setting
|
||||
* applies to all three stereo pairs.
|
||||
*/
|
||||
reg = data->wm8766_regs[WM8766_DAC_CTRL] &
|
||||
~(WM8766_PL_LEFT_MASK | WM8766_PL_RIGHT_MASK);
|
||||
if (mixed)
|
||||
reg |= WM8766_PL_LEFT_LRMIX | WM8766_PL_RIGHT_LRMIX;
|
||||
else
|
||||
reg |= WM8766_PL_LEFT_LEFT | WM8766_PL_RIGHT_RIGHT;
|
||||
wm8766_write_cached(chip, WM8766_DAC_CTRL, reg);
|
||||
}
|
||||
|
||||
static void xonar_ds_gpio_changed(struct oxygen *chip)
|
||||
{
|
||||
u16 bits;
|
||||
|
||||
bits = oxygen_read16(chip, OXYGEN_GPIO_DATA);
|
||||
snd_printk(KERN_INFO "HP detect: %d\n", !!(bits & GPIO_DS_HP_DETECT));
|
||||
xonar_ds_handle_hp_jack(chip);
|
||||
}
|
||||
|
||||
static int wm8776_bit_switch_get(struct snd_kcontrol *ctl,
|
||||
|
|
@ -896,7 +965,10 @@ static const struct snd_kcontrol_new ds_controls[] = {
|
|||
.put = wm8776_input_mux_put,
|
||||
.private_value = 1 << 1,
|
||||
},
|
||||
WM8776_BIT_SWITCH("Aux", WM8776_ADCMUX, 1 << 2, 0, 0),
|
||||
WM8776_BIT_SWITCH("Front Mic Capture Switch",
|
||||
WM8776_ADCMUX, 1 << 2, 0, 0),
|
||||
WM8776_BIT_SWITCH("Aux Capture Switch",
|
||||
WM8776_ADCMUX, 1 << 3, 0, 0),
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "ADC Filter Capture Enum",
|
||||
|
|
@ -956,13 +1028,6 @@ static const struct snd_kcontrol_new lc_controls[] = {
|
|||
LC_CONTROL_ALC, wm8776_ngth_db_scale),
|
||||
};
|
||||
|
||||
static int xonar_ds_control_filter(struct snd_kcontrol_new *template)
|
||||
{
|
||||
if (!strncmp(template->name, "CD Capture ", 11))
|
||||
return 1; /* no CD input */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xonar_ds_mixer_init(struct oxygen *chip)
|
||||
{
|
||||
struct xonar_wm87x6 *data = chip->model_data;
|
||||
|
|
@ -999,10 +1064,9 @@ static int xonar_ds_mixer_init(struct oxygen *chip)
|
|||
|
||||
static const struct oxygen_model model_xonar_ds = {
|
||||
.shortname = "Xonar DS",
|
||||
.longname = "Asus Virtuoso 200",
|
||||
.longname = "Asus Virtuoso 66",
|
||||
.chip = "AV200",
|
||||
.init = xonar_ds_init,
|
||||
.control_filter = xonar_ds_control_filter,
|
||||
.mixer_init = xonar_ds_mixer_init,
|
||||
.cleanup = xonar_ds_cleanup,
|
||||
.suspend = xonar_ds_suspend,
|
||||
|
|
@ -1013,6 +1077,7 @@ static const struct oxygen_model model_xonar_ds = {
|
|||
.set_adc_params = set_wm8776_adc_params,
|
||||
.update_dac_volume = update_wm87x6_volume,
|
||||
.update_dac_mute = update_wm87x6_mute,
|
||||
.update_center_lfe_mix = update_wm8766_center_lfe_mix,
|
||||
.gpio_changed = xonar_ds_gpio_changed,
|
||||
.dac_tlv = wm87x6_dac_db_scale,
|
||||
.model_data_size = sizeof(struct xonar_wm87x6),
|
||||
|
|
|
|||
|
|
@ -1527,14 +1527,14 @@ snd_rme96_free(void *private_data)
|
|||
static void
|
||||
snd_rme96_free_spdif_pcm(struct snd_pcm *pcm)
|
||||
{
|
||||
struct rme96 *rme96 = (struct rme96 *) pcm->private_data;
|
||||
struct rme96 *rme96 = pcm->private_data;
|
||||
rme96->spdif_pcm = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
snd_rme96_free_adat_pcm(struct snd_pcm *pcm)
|
||||
{
|
||||
struct rme96 *rme96 = (struct rme96 *) pcm->private_data;
|
||||
struct rme96 *rme96 = pcm->private_data;
|
||||
rme96->adat_pcm = NULL;
|
||||
}
|
||||
|
||||
|
|
@ -1661,7 +1661,7 @@ static void
|
|||
snd_rme96_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
|
||||
{
|
||||
int n;
|
||||
struct rme96 *rme96 = (struct rme96 *)entry->private_data;
|
||||
struct rme96 *rme96 = entry->private_data;
|
||||
|
||||
rme96->rcreg = readl(rme96->iobase + RME96_IO_CONTROL_REGISTER);
|
||||
|
||||
|
|
@ -2348,7 +2348,7 @@ snd_rme96_probe(struct pci_dev *pci,
|
|||
if (err < 0)
|
||||
return err;
|
||||
card->private_free = snd_rme96_card_free;
|
||||
rme96 = (struct rme96 *)card->private_data;
|
||||
rme96 = card->private_data;
|
||||
rme96->card = card;
|
||||
rme96->pci = pci;
|
||||
snd_card_set_dev(card, &pci->dev);
|
||||
|
|
|
|||
|
|
@ -3284,7 +3284,7 @@ static int snd_hdsp_create_controls(struct snd_card *card, struct hdsp *hdsp)
|
|||
static void
|
||||
snd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
|
||||
{
|
||||
struct hdsp *hdsp = (struct hdsp *) entry->private_data;
|
||||
struct hdsp *hdsp = entry->private_data;
|
||||
unsigned int status;
|
||||
unsigned int status2;
|
||||
char *pref_sync_ref;
|
||||
|
|
@ -4566,7 +4566,7 @@ static int hdsp_get_peak(struct hdsp *hdsp, struct hdsp_peak_rms __user *peak_rm
|
|||
|
||||
static int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct hdsp *hdsp = (struct hdsp *)hw->private_data;
|
||||
struct hdsp *hdsp = hw->private_data;
|
||||
void __user *argp = (void __user *)arg;
|
||||
int err;
|
||||
|
||||
|
|
@ -5156,7 +5156,7 @@ static int snd_hdsp_free(struct hdsp *hdsp)
|
|||
|
||||
static void snd_hdsp_card_free(struct snd_card *card)
|
||||
{
|
||||
struct hdsp *hdsp = (struct hdsp *) card->private_data;
|
||||
struct hdsp *hdsp = card->private_data;
|
||||
|
||||
if (hdsp)
|
||||
snd_hdsp_free(hdsp);
|
||||
|
|
@ -5182,7 +5182,7 @@ static int __devinit snd_hdsp_probe(struct pci_dev *pci,
|
|||
if (err < 0)
|
||||
return err;
|
||||
|
||||
hdsp = (struct hdsp *) card->private_data;
|
||||
hdsp = card->private_data;
|
||||
card->private_free = snd_hdsp_card_free;
|
||||
hdsp->dev = dev;
|
||||
hdsp->pci = pci;
|
||||
|
|
|
|||
|
|
@ -785,7 +785,7 @@ static int snapper_set_capture_source(struct pmac_tumbler *mix)
|
|||
if (! mix->i2c.client)
|
||||
return -ENODEV;
|
||||
if (mix->capture_source)
|
||||
mix->acs = mix->acs |= 2;
|
||||
mix->acs |= 2;
|
||||
else
|
||||
mix->acs &= ~2;
|
||||
return i2c_smbus_write_byte_data(mix->i2c.client, TAS_REG_ACS, mix->acs);
|
||||
|
|
|
|||
|
|
@ -179,7 +179,7 @@ static int atmel_pcm_hw_params(struct snd_pcm_substream *substream,
|
|||
snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
|
||||
runtime->dma_bytes = params_buffer_bytes(params);
|
||||
|
||||
prtd->params = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
|
||||
prtd->params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
|
||||
prtd->params->dma_intr_handler = atmel_pcm_dma_irq;
|
||||
|
||||
prtd->dma_buffer = runtime->dma_addr;
|
||||
|
|
@ -374,14 +374,14 @@ static int atmel_pcm_new(struct snd_card *card,
|
|||
if (!card->dev->coherent_dma_mask)
|
||||
card->dev->coherent_dma_mask = 0xffffffff;
|
||||
|
||||
if (dai->playback.channels_min) {
|
||||
if (dai->driver->playback.channels_min) {
|
||||
ret = atmel_pcm_preallocate_dma_buffer(pcm,
|
||||
SNDRV_PCM_STREAM_PLAYBACK);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (dai->capture.channels_min) {
|
||||
if (dai->driver->capture.channels_min) {
|
||||
pr_debug("at32-pcm:"
|
||||
"Allocating PCM capture DMA buffer\n");
|
||||
ret = atmel_pcm_preallocate_dma_buffer(pcm,
|
||||
|
|
@ -414,12 +414,9 @@ static void atmel_pcm_free_dma_buffers(struct snd_pcm *pcm)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int atmel_pcm_suspend(struct snd_soc_dai_link *dai_link)
|
||||
static int atmel_pcm_suspend(struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_pcm *pcm = dai_link->pcm;
|
||||
struct snd_pcm_str *stream = &pcm->streams[0];
|
||||
struct snd_pcm_substream *substream = stream->substream;
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct snd_pcm_runtime *runtime = dai->runtime;
|
||||
struct atmel_runtime_data *prtd;
|
||||
struct atmel_pcm_dma_params *params;
|
||||
|
||||
|
|
@ -441,12 +438,9 @@ static int atmel_pcm_suspend(struct snd_soc_dai_link *dai_link)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int atmel_pcm_resume(struct snd_soc_dai_link *dai_link)
|
||||
static int atmel_pcm_resume(struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_pcm *pcm = dai_link->pcm;
|
||||
struct snd_pcm_str *stream = &pcm->streams[0];
|
||||
struct snd_pcm_substream *substream = stream->substream;
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct snd_pcm_runtime *runtime = dai->runtime;
|
||||
struct atmel_runtime_data *prtd;
|
||||
struct atmel_pcm_dma_params *params;
|
||||
|
||||
|
|
@ -470,27 +464,46 @@ static int atmel_pcm_resume(struct snd_soc_dai_link *dai_link)
|
|||
#define atmel_pcm_resume NULL
|
||||
#endif
|
||||
|
||||
struct snd_soc_platform atmel_soc_platform = {
|
||||
.name = "atmel-audio",
|
||||
.pcm_ops = &atmel_pcm_ops,
|
||||
static struct snd_soc_platform_driver atmel_soc_platform = {
|
||||
.ops = &atmel_pcm_ops,
|
||||
.pcm_new = atmel_pcm_new,
|
||||
.pcm_free = atmel_pcm_free_dma_buffers,
|
||||
.suspend = atmel_pcm_suspend,
|
||||
.resume = atmel_pcm_resume,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(atmel_soc_platform);
|
||||
|
||||
static int __init atmel_pcm_modinit(void)
|
||||
static int __devinit atmel_soc_platform_probe(struct platform_device *pdev)
|
||||
{
|
||||
return snd_soc_register_platform(&atmel_soc_platform);
|
||||
return snd_soc_register_platform(&pdev->dev, &atmel_soc_platform);
|
||||
}
|
||||
module_init(atmel_pcm_modinit);
|
||||
|
||||
static void __exit atmel_pcm_modexit(void)
|
||||
static int __devexit atmel_soc_platform_remove(struct platform_device *pdev)
|
||||
{
|
||||
snd_soc_unregister_platform(&atmel_soc_platform);
|
||||
snd_soc_unregister_platform(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
module_exit(atmel_pcm_modexit);
|
||||
|
||||
static struct platform_driver atmel_pcm_driver = {
|
||||
.driver = {
|
||||
.name = "atmel-pcm-audio",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
|
||||
.probe = atmel_soc_platform_probe,
|
||||
.remove = __devexit_p(atmel_soc_platform_remove),
|
||||
};
|
||||
|
||||
static int __init snd_atmel_pcm_init(void)
|
||||
{
|
||||
return platform_driver_register(&atmel_pcm_driver);
|
||||
}
|
||||
module_init(snd_atmel_pcm_init);
|
||||
|
||||
static void __exit snd_atmel_pcm_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&atmel_pcm_driver);
|
||||
}
|
||||
module_exit(snd_atmel_pcm_exit);
|
||||
|
||||
MODULE_AUTHOR("Sedji Gaouaou <[email protected]>");
|
||||
MODULE_DESCRIPTION("Atmel PCM module");
|
||||
|
|
|
|||
|
|
@ -74,9 +74,6 @@ struct atmel_pcm_dma_params {
|
|||
void (*dma_intr_handler)(u32, struct snd_pcm_substream *);
|
||||
};
|
||||
|
||||
extern struct snd_soc_platform atmel_soc_platform;
|
||||
|
||||
|
||||
/*
|
||||
* SSC register access (since ssc_writel() / ssc_readl() require literal name)
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -205,8 +205,7 @@ static irqreturn_t atmel_ssc_interrupt(int irq, void *dev_id)
|
|||
static int atmel_ssc_startup(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
|
||||
struct atmel_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];
|
||||
struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
|
||||
int dir_mask;
|
||||
|
||||
pr_debug("atmel_ssc_startup: SSC_SR=0x%u\n",
|
||||
|
|
@ -235,8 +234,7 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream,
|
|||
static void atmel_ssc_shutdown(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
|
||||
struct atmel_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];
|
||||
struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
|
||||
struct atmel_pcm_dma_params *dma_params;
|
||||
int dir, dir_mask;
|
||||
|
||||
|
|
@ -338,7 +336,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
|
||||
int id = rtd->dai->cpu_dai->id;
|
||||
int id = dai->id;
|
||||
struct atmel_ssc_info *ssc_p = &ssc_info[id];
|
||||
struct atmel_pcm_dma_params *dma_params;
|
||||
int dir, channels, bits;
|
||||
|
|
@ -368,7 +366,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
|
|||
* function. It should not be used for other purposes
|
||||
* as it is common to all substreams.
|
||||
*/
|
||||
snd_soc_dai_set_dma_data(rtd->dai->cpu_dai, substream, dma_params);
|
||||
snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_params);
|
||||
|
||||
channels = params_channels(params);
|
||||
|
||||
|
|
@ -605,8 +603,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
|
|||
static int atmel_ssc_prepare(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
|
||||
struct atmel_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];
|
||||
struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
|
||||
struct atmel_pcm_dma_params *dma_params;
|
||||
int dir;
|
||||
|
||||
|
|
@ -690,6 +687,32 @@ static int atmel_ssc_resume(struct snd_soc_dai *cpu_dai)
|
|||
# define atmel_ssc_resume NULL
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
static int atmel_ssc_probe(struct snd_soc_dai *dai)
|
||||
{
|
||||
struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
|
||||
int ret = 0;
|
||||
|
||||
snd_soc_dai_set_drvdata(dai, ssc_p);
|
||||
|
||||
/*
|
||||
* Request SSC device
|
||||
*/
|
||||
ssc_p->ssc = ssc_request(dai->id);
|
||||
if (IS_ERR(ssc_p->ssc)) {
|
||||
printk(KERN_ERR "ASoC: Failed to request SSC %d\n", dai->id);
|
||||
ret = PTR_ERR(ssc_p->ssc);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int atmel_ssc_remove(struct snd_soc_dai *dai)
|
||||
{
|
||||
struct atmel_ssc_info *ssc_p = snd_soc_dai_get_drvdata(dai);
|
||||
|
||||
ssc_free(ssc_p->ssc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define ATMEL_SSC_RATES (SNDRV_PCM_RATE_8000_96000)
|
||||
|
||||
|
|
@ -705,9 +728,11 @@ static struct snd_soc_dai_ops atmel_ssc_dai_ops = {
|
|||
.set_clkdiv = atmel_ssc_set_dai_clkdiv,
|
||||
};
|
||||
|
||||
struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = {
|
||||
{ .name = "atmel-ssc0",
|
||||
.id = 0,
|
||||
static struct snd_soc_dai_driver atmel_ssc_dai[NUM_SSC_DEVICES] = {
|
||||
{
|
||||
.name = "atmel-ssc-dai.0",
|
||||
.probe = atmel_ssc_probe,
|
||||
.remove = atmel_ssc_remove,
|
||||
.suspend = atmel_ssc_suspend,
|
||||
.resume = atmel_ssc_resume,
|
||||
.playback = {
|
||||
|
|
@ -721,11 +746,12 @@ struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = {
|
|||
.rates = ATMEL_SSC_RATES,
|
||||
.formats = ATMEL_SSC_FORMATS,},
|
||||
.ops = &atmel_ssc_dai_ops,
|
||||
.private_data = &ssc_info[0],
|
||||
},
|
||||
#if NUM_SSC_DEVICES == 3
|
||||
{ .name = "atmel-ssc1",
|
||||
.id = 1,
|
||||
{
|
||||
.name = "atmel-ssc-dai.1",
|
||||
.probe = atmel_ssc_probe,
|
||||
.remove = atmel_ssc_remove,
|
||||
.suspend = atmel_ssc_suspend,
|
||||
.resume = atmel_ssc_resume,
|
||||
.playback = {
|
||||
|
|
@ -739,10 +765,11 @@ struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = {
|
|||
.rates = ATMEL_SSC_RATES,
|
||||
.formats = ATMEL_SSC_FORMATS,},
|
||||
.ops = &atmel_ssc_dai_ops,
|
||||
.private_data = &ssc_info[1],
|
||||
},
|
||||
{ .name = "atmel-ssc2",
|
||||
.id = 2,
|
||||
{
|
||||
.name = "atmel-ssc-dai.2",
|
||||
.probe = atmel_ssc_probe,
|
||||
.remove = atmel_ssc_remove,
|
||||
.suspend = atmel_ssc_suspend,
|
||||
.resume = atmel_ssc_resume,
|
||||
.playback = {
|
||||
|
|
@ -756,23 +783,94 @@ struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = {
|
|||
.rates = ATMEL_SSC_RATES,
|
||||
.formats = ATMEL_SSC_FORMATS,},
|
||||
.ops = &atmel_ssc_dai_ops,
|
||||
.private_data = &ssc_info[2],
|
||||
},
|
||||
#endif
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(atmel_ssc_dai);
|
||||
|
||||
static int __init atmel_ssc_modinit(void)
|
||||
static __devinit int asoc_ssc_probe(struct platform_device *pdev)
|
||||
{
|
||||
return snd_soc_register_dais(atmel_ssc_dai, ARRAY_SIZE(atmel_ssc_dai));
|
||||
BUG_ON(pdev->id < 0);
|
||||
BUG_ON(pdev->id >= ARRAY_SIZE(atmel_ssc_dai));
|
||||
return snd_soc_register_dai(&pdev->dev, &atmel_ssc_dai[pdev->id]);
|
||||
}
|
||||
module_init(atmel_ssc_modinit);
|
||||
|
||||
static void __exit atmel_ssc_modexit(void)
|
||||
static int __devexit asoc_ssc_remove(struct platform_device *pdev)
|
||||
{
|
||||
snd_soc_unregister_dais(atmel_ssc_dai, ARRAY_SIZE(atmel_ssc_dai));
|
||||
snd_soc_unregister_dai(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
module_exit(atmel_ssc_modexit);
|
||||
|
||||
static struct platform_driver asoc_ssc_driver = {
|
||||
.driver = {
|
||||
.name = "atmel-ssc-dai",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
|
||||
.probe = asoc_ssc_probe,
|
||||
.remove = __devexit_p(asoc_ssc_remove),
|
||||
};
|
||||
|
||||
/**
|
||||
* atmel_ssc_set_audio - Allocate the specified SSC for audio use.
|
||||
*/
|
||||
int atmel_ssc_set_audio(int ssc_id)
|
||||
{
|
||||
struct ssc_device *ssc;
|
||||
static struct platform_device *dma_pdev;
|
||||
struct platform_device *ssc_pdev;
|
||||
int ret;
|
||||
|
||||
if (ssc_id < 0 || ssc_id >= ARRAY_SIZE(atmel_ssc_dai))
|
||||
return -EINVAL;
|
||||
|
||||
/* Allocate a dummy device for DMA if we don't have one already */
|
||||
if (!dma_pdev) {
|
||||
dma_pdev = platform_device_alloc("atmel-pcm-audio", -1);
|
||||
if (!dma_pdev)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = platform_device_add(dma_pdev);
|
||||
if (ret < 0) {
|
||||
platform_device_put(dma_pdev);
|
||||
dma_pdev = NULL;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ssc_pdev = platform_device_alloc("atmel-ssc-dai", ssc_id);
|
||||
if (!ssc_pdev) {
|
||||
ssc_free(ssc);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* If we can grab the SSC briefly to parent the DAI device off it */
|
||||
ssc = ssc_request(ssc_id);
|
||||
if (IS_ERR(ssc))
|
||||
pr_warn("Unable to parent ASoC SSC DAI on SSC: %ld\n",
|
||||
PTR_ERR(ssc));
|
||||
else
|
||||
ssc_pdev->dev.parent = &(ssc->pdev->dev);
|
||||
ssc_free(ssc);
|
||||
|
||||
ret = platform_device_add(ssc_pdev);
|
||||
if (ret < 0)
|
||||
platform_device_put(ssc_pdev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(atmel_ssc_set_audio);
|
||||
|
||||
static int __init snd_atmel_ssc_init(void)
|
||||
{
|
||||
return platform_driver_register(&asoc_ssc_driver);
|
||||
}
|
||||
module_init(snd_atmel_ssc_init);
|
||||
|
||||
static void __exit snd_atmel_ssc_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&asoc_ssc_driver);
|
||||
}
|
||||
module_exit(snd_atmel_ssc_exit);
|
||||
|
||||
/* Module information */
|
||||
MODULE_AUTHOR("Sedji Gaouaou, [email protected], www.atmel.com");
|
||||
|
|
|
|||
|
|
@ -116,6 +116,7 @@ struct atmel_ssc_info {
|
|||
struct atmel_pcm_dma_params *dma_params[2];
|
||||
struct atmel_ssc_state ssc_state;
|
||||
};
|
||||
extern struct snd_soc_dai atmel_ssc_dai[];
|
||||
|
||||
int atmel_ssc_set_audio(int ssc);
|
||||
|
||||
#endif /* _AT91_SSC_DAI_H */
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ static struct ssc_clock_data playpaq_wm8510_calc_ssc_clock(
|
|||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *cpu_dai)
|
||||
{
|
||||
struct at32_ssc_info *ssc_p = cpu_dai->private_data;
|
||||
struct at32_ssc_info *ssc_p = snd_soc_dai_get_drvdata(cpu_dai);
|
||||
struct ssc_device *ssc = ssc_p->ssc;
|
||||
struct ssc_clock_data cd;
|
||||
unsigned int rate, width_bits, channels;
|
||||
|
|
@ -131,9 +131,9 @@ static int playpaq_wm8510_hw_params(struct snd_pcm_substream *substream,
|
|||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
|
||||
struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
|
||||
struct at32_ssc_info *ssc_p = cpu_dai->private_data;
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
struct at32_ssc_info *ssc_p = snd_soc_dai_get_drvdata(cpu_dai);
|
||||
struct ssc_device *ssc = ssc_p->ssc;
|
||||
unsigned int pll_out = 0, bclk = 0, mclk_div = 0;
|
||||
int ret;
|
||||
|
|
@ -315,8 +315,9 @@ static const struct snd_soc_dapm_route intercon[] = {
|
|||
|
||||
|
||||
|
||||
static int playpaq_wm8510_init(struct snd_soc_codec *codec)
|
||||
static int playpaq_wm8510_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
int i;
|
||||
|
||||
/*
|
||||
|
|
@ -342,7 +343,7 @@ static int playpaq_wm8510_init(struct snd_soc_codec *codec)
|
|||
|
||||
|
||||
/* Make CSB show PLL rate */
|
||||
snd_soc_dai_set_clkdiv(codec->dai, WM8510_OPCLKDIV,
|
||||
snd_soc_dai_set_clkdiv(rtd->codec_dai, WM8510_OPCLKDIV,
|
||||
WM8510_OPCLKDIV_1 | 4);
|
||||
|
||||
return 0;
|
||||
|
|
@ -353,8 +354,10 @@ static int playpaq_wm8510_init(struct snd_soc_codec *codec)
|
|||
static struct snd_soc_dai_link playpaq_wm8510_dai = {
|
||||
.name = "WM8510",
|
||||
.stream_name = "WM8510 PCM",
|
||||
.cpu_dai = &at32_ssc_dai[0],
|
||||
.codec_dai = &wm8510_dai,
|
||||
.cpu_dai_name= "atmel-ssc-dai.0",
|
||||
.platform_name = "atmel-pcm-audio",
|
||||
.codec_name = "wm8510-codec.0-0x1a",
|
||||
.codec_dai_name = "wm8510-hifi",
|
||||
.init = playpaq_wm8510_init,
|
||||
.ops = &playpaq_wm8510_ops,
|
||||
};
|
||||
|
|
@ -363,46 +366,16 @@ static struct snd_soc_dai_link playpaq_wm8510_dai = {
|
|||
|
||||
static struct snd_soc_card snd_soc_playpaq = {
|
||||
.name = "LRS_PlayPaq_WM8510",
|
||||
.platform = &at32_soc_platform,
|
||||
.dai_link = &playpaq_wm8510_dai,
|
||||
.num_links = 1,
|
||||
};
|
||||
|
||||
|
||||
|
||||
static struct wm8510_setup_data playpaq_wm8510_setup = {
|
||||
.i2c_bus = 0,
|
||||
.i2c_address = 0x1a,
|
||||
};
|
||||
|
||||
|
||||
|
||||
static struct snd_soc_device playpaq_wm8510_snd_devdata = {
|
||||
.card = &snd_soc_playpaq,
|
||||
.codec_dev = &soc_codec_dev_wm8510,
|
||||
.codec_data = &playpaq_wm8510_setup,
|
||||
};
|
||||
|
||||
static struct platform_device *playpaq_snd_device;
|
||||
|
||||
|
||||
static int __init playpaq_asoc_init(void)
|
||||
{
|
||||
int ret = 0;
|
||||
struct at32_ssc_info *ssc_p = playpaq_wm8510_dai.cpu_dai->private_data;
|
||||
struct ssc_device *ssc = NULL;
|
||||
|
||||
|
||||
/*
|
||||
* Request SSC device
|
||||
*/
|
||||
ssc = ssc_request(0);
|
||||
if (IS_ERR(ssc)) {
|
||||
ret = PTR_ERR(ssc);
|
||||
goto err_ssc;
|
||||
}
|
||||
ssc_p->ssc = ssc;
|
||||
|
||||
|
||||
/*
|
||||
* Configure MCLK for WM8510
|
||||
|
|
@ -439,8 +412,7 @@ static int __init playpaq_asoc_init(void)
|
|||
goto err_device_alloc;
|
||||
}
|
||||
|
||||
platform_set_drvdata(playpaq_snd_device, &playpaq_wm8510_snd_devdata);
|
||||
playpaq_wm8510_snd_devdata.dev = &playpaq_snd_device->dev;
|
||||
platform_set_drvdata(playpaq_snd_device, &snd_soc_playpaq);
|
||||
|
||||
ret = platform_device_add(playpaq_snd_device);
|
||||
if (ret) {
|
||||
|
|
@ -468,25 +440,12 @@ err_pll0:
|
|||
clk_put(_gclk0);
|
||||
_gclk0 = NULL;
|
||||
}
|
||||
err_gclk0:
|
||||
ssc_free(ssc);
|
||||
err_ssc:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void __exit playpaq_asoc_exit(void)
|
||||
{
|
||||
struct at32_ssc_info *ssc_p = playpaq_wm8510_dai.cpu_dai->private_data;
|
||||
struct ssc_device *ssc;
|
||||
|
||||
if (ssc_p != NULL) {
|
||||
ssc = ssc_p->ssc;
|
||||
if (ssc != NULL)
|
||||
ssc_free(ssc);
|
||||
ssc_p->ssc = NULL;
|
||||
}
|
||||
|
||||
if (_gclk0 != NULL) {
|
||||
clk_put(_gclk0);
|
||||
_gclk0 = NULL;
|
||||
|
|
|
|||
|
|
@ -69,8 +69,8 @@ static int at91sam9g20ek_hw_params(struct snd_pcm_substream *substream,
|
|||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
|
||||
struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
int ret;
|
||||
|
||||
/* set codec DAI configuration */
|
||||
|
|
@ -136,16 +136,17 @@ static const struct snd_soc_dapm_route intercon[] = {
|
|||
/*
|
||||
* Logic for a wm8731 as connected on a at91sam9g20ek board.
|
||||
*/
|
||||
static int at91sam9g20ek_wm8731_init(struct snd_soc_codec *codec)
|
||||
static int at91sam9g20ek_wm8731_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_soc_dai *codec_dai = &codec->dai[0];
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
int ret;
|
||||
|
||||
printk(KERN_DEBUG
|
||||
"at91sam9g20ek_wm8731 "
|
||||
": at91sam9g20ek_wm8731_init() called\n");
|
||||
|
||||
ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK,
|
||||
ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL,
|
||||
MCLK_RATE, SND_SOC_CLOCK_IN);
|
||||
if (ret < 0) {
|
||||
printk(KERN_ERR "Failed to set WM8731 SYSCLK: %d\n", ret);
|
||||
|
|
@ -179,37 +180,37 @@ static int at91sam9g20ek_wm8731_init(struct snd_soc_codec *codec)
|
|||
static struct snd_soc_dai_link at91sam9g20ek_dai = {
|
||||
.name = "WM8731",
|
||||
.stream_name = "WM8731 PCM",
|
||||
.cpu_dai = &atmel_ssc_dai[0],
|
||||
.codec_dai = &wm8731_dai,
|
||||
.cpu_dai_name = "atmel-ssc-dai.0",
|
||||
.codec_dai_name = "wm8731-hifi",
|
||||
.init = at91sam9g20ek_wm8731_init,
|
||||
.platform_name = "atmel-pcm-audio",
|
||||
.codec_name = "wm8731-codec.0-001b",
|
||||
.ops = &at91sam9g20ek_ops,
|
||||
};
|
||||
|
||||
static struct snd_soc_card snd_soc_at91sam9g20ek = {
|
||||
.name = "AT91SAMG20-EK",
|
||||
.platform = &atmel_soc_platform,
|
||||
.dai_link = &at91sam9g20ek_dai,
|
||||
.num_links = 1,
|
||||
.set_bias_level = at91sam9g20ek_set_bias_level,
|
||||
};
|
||||
|
||||
static struct snd_soc_device at91sam9g20ek_snd_devdata = {
|
||||
.card = &snd_soc_at91sam9g20ek,
|
||||
.codec_dev = &soc_codec_dev_wm8731,
|
||||
};
|
||||
|
||||
static struct platform_device *at91sam9g20ek_snd_device;
|
||||
|
||||
static int __init at91sam9g20ek_init(void)
|
||||
{
|
||||
struct atmel_ssc_info *ssc_p = at91sam9g20ek_dai.cpu_dai->private_data;
|
||||
struct ssc_device *ssc = NULL;
|
||||
struct clk *pllb;
|
||||
int ret;
|
||||
|
||||
if (!(machine_is_at91sam9g20ek() || machine_is_at91sam9g20ek_2mmc()))
|
||||
return -ENODEV;
|
||||
|
||||
ret = atmel_ssc_set_audio(0);
|
||||
if (ret != 0) {
|
||||
pr_err("Failed to set SSC 0 for audio: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Codec MCLK is supplied by PCK0 - set it up.
|
||||
*/
|
||||
|
|
@ -235,18 +236,6 @@ static int __init at91sam9g20ek_init(void)
|
|||
|
||||
clk_set_rate(mclk, MCLK_RATE);
|
||||
|
||||
/*
|
||||
* Request SSC device
|
||||
*/
|
||||
ssc = ssc_request(0);
|
||||
if (IS_ERR(ssc)) {
|
||||
printk(KERN_ERR "ASoC: Failed to request SSC 0\n");
|
||||
ret = PTR_ERR(ssc);
|
||||
ssc = NULL;
|
||||
goto err_ssc;
|
||||
}
|
||||
ssc_p->ssc = ssc;
|
||||
|
||||
at91sam9g20ek_snd_device = platform_device_alloc("soc-audio", -1);
|
||||
if (!at91sam9g20ek_snd_device) {
|
||||
printk(KERN_ERR "ASoC: Platform device allocation failed\n");
|
||||
|
|
@ -254,8 +243,7 @@ static int __init at91sam9g20ek_init(void)
|
|||
}
|
||||
|
||||
platform_set_drvdata(at91sam9g20ek_snd_device,
|
||||
&at91sam9g20ek_snd_devdata);
|
||||
at91sam9g20ek_snd_devdata.dev = &at91sam9g20ek_snd_device->dev;
|
||||
&snd_soc_at91sam9g20ek);
|
||||
|
||||
ret = platform_device_add(at91sam9g20ek_snd_device);
|
||||
if (ret) {
|
||||
|
|
@ -265,9 +253,6 @@ static int __init at91sam9g20ek_init(void)
|
|||
|
||||
return ret;
|
||||
|
||||
err_ssc:
|
||||
ssc_free(ssc);
|
||||
ssc_p->ssc = NULL;
|
||||
err_mclk:
|
||||
clk_put(mclk);
|
||||
mclk = NULL;
|
||||
|
|
@ -277,16 +262,6 @@ err:
|
|||
|
||||
static void __exit at91sam9g20ek_exit(void)
|
||||
{
|
||||
struct atmel_ssc_info *ssc_p = at91sam9g20ek_dai.cpu_dai->private_data;
|
||||
struct ssc_device *ssc;
|
||||
|
||||
if (ssc_p != NULL) {
|
||||
ssc = ssc_p->ssc;
|
||||
if (ssc != NULL)
|
||||
ssc_free(ssc);
|
||||
ssc_p->ssc = NULL;
|
||||
}
|
||||
|
||||
platform_device_unregister(at91sam9g20ek_snd_device);
|
||||
at91sam9g20ek_snd_device = NULL;
|
||||
clk_put(mclk);
|
||||
|
|
|
|||
|
|
@ -46,8 +46,8 @@ static int afeb9260_hw_params(struct snd_pcm_substream *substream,
|
|||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
|
||||
struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
int err;
|
||||
|
||||
/* Set codec DAI configuration */
|
||||
|
|
@ -102,8 +102,9 @@ static const struct snd_soc_dapm_route audio_map[] = {
|
|||
{"MICIN", NULL, "Mic Jack"},
|
||||
};
|
||||
|
||||
static int afeb9260_tlv320aic23_init(struct snd_soc_codec *codec)
|
||||
static int afeb9260_tlv320aic23_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
|
||||
/* Add afeb9260 specific widgets */
|
||||
snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets,
|
||||
|
|
@ -125,8 +126,10 @@ static int afeb9260_tlv320aic23_init(struct snd_soc_codec *codec)
|
|||
static struct snd_soc_dai_link afeb9260_dai = {
|
||||
.name = "TLV320AIC23",
|
||||
.stream_name = "AIC23",
|
||||
.cpu_dai = &atmel_ssc_dai[0],
|
||||
.codec_dai = &tlv320aic23_dai,
|
||||
.cpu_dai_name = "atmel-ssc-dai.0",
|
||||
.codec_dai_name = "tlv320aic23-hifi",
|
||||
.platform_name = "atmel_pcm-audio",
|
||||
.codec_name = "tlv320aic23-codec.0-0x1a",
|
||||
.init = afeb9260_tlv320aic23_init,
|
||||
.ops = &afeb9260_ops,
|
||||
};
|
||||
|
|
@ -134,37 +137,20 @@ static struct snd_soc_dai_link afeb9260_dai = {
|
|||
/* Audio machine driver */
|
||||
static struct snd_soc_card snd_soc_machine_afeb9260 = {
|
||||
.name = "AFEB9260",
|
||||
.platform = &atmel_soc_platform,
|
||||
.dai_link = &afeb9260_dai,
|
||||
.num_links = 1,
|
||||
};
|
||||
|
||||
/* Audio subsystem */
|
||||
static struct snd_soc_device afeb9260_snd_devdata = {
|
||||
.card = &snd_soc_machine_afeb9260,
|
||||
.codec_dev = &soc_codec_dev_tlv320aic23,
|
||||
};
|
||||
|
||||
static struct platform_device *afeb9260_snd_device;
|
||||
|
||||
static int __init afeb9260_soc_init(void)
|
||||
{
|
||||
int err;
|
||||
struct device *dev;
|
||||
struct atmel_ssc_info *ssc_p = afeb9260_dai.cpu_dai->private_data;
|
||||
struct ssc_device *ssc = NULL;
|
||||
|
||||
if (!(machine_is_afeb9260()))
|
||||
return -ENODEV;
|
||||
|
||||
ssc = ssc_request(0);
|
||||
if (IS_ERR(ssc)) {
|
||||
printk(KERN_ERR "ASoC: Failed to request SSC 0\n");
|
||||
err = PTR_ERR(ssc);
|
||||
ssc = NULL;
|
||||
goto err_ssc;
|
||||
}
|
||||
ssc_p->ssc = ssc;
|
||||
|
||||
afeb9260_snd_device = platform_device_alloc("soc-audio", -1);
|
||||
if (!afeb9260_snd_device) {
|
||||
|
|
@ -172,8 +158,7 @@ static int __init afeb9260_soc_init(void)
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
platform_set_drvdata(afeb9260_snd_device, &afeb9260_snd_devdata);
|
||||
afeb9260_snd_devdata.dev = &afeb9260_snd_device->dev;
|
||||
platform_set_drvdata(afeb9260_snd_device, &snd_soc_machine_afeb9260);
|
||||
err = platform_device_add(afeb9260_snd_device);
|
||||
if (err)
|
||||
goto err1;
|
||||
|
|
@ -184,9 +169,7 @@ static int __init afeb9260_soc_init(void)
|
|||
err1:
|
||||
platform_device_del(afeb9260_snd_device);
|
||||
platform_device_put(afeb9260_snd_device);
|
||||
err_ssc:
|
||||
return err;
|
||||
|
||||
}
|
||||
|
||||
static void __exit afeb9260_soc_exit(void)
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@
|
|||
#include <asm/mach-au1x00/au1xxx_dbdma.h>
|
||||
#include <asm/mach-db1x00/bcsr.h>
|
||||
|
||||
#include "../codecs/ac97.h"
|
||||
#include "../codecs/wm8731.h"
|
||||
#include "psc.h"
|
||||
|
||||
|
|
@ -28,20 +27,16 @@
|
|||
static struct snd_soc_dai_link db1200_ac97_dai = {
|
||||
.name = "AC97",
|
||||
.stream_name = "AC97 HiFi",
|
||||
.cpu_dai = &au1xpsc_ac97_dai,
|
||||
.codec_dai = &ac97_dai,
|
||||
.codec_dai_name = "ac97-hifi",
|
||||
.cpu_dai_name = "au1xpsc_ac97.1",
|
||||
.platform_name = "au1xpsc-pcm.1",
|
||||
.codec_name = "ac97-codec.1",
|
||||
};
|
||||
|
||||
static struct snd_soc_card db1200_ac97_machine = {
|
||||
.name = "DB1200_AC97",
|
||||
.dai_link = &db1200_ac97_dai,
|
||||
.num_links = 1,
|
||||
.platform = &au1xpsc_soc_platform,
|
||||
};
|
||||
|
||||
static struct snd_soc_device db1200_ac97_devdata = {
|
||||
.card = &db1200_ac97_machine,
|
||||
.codec_dev = &soc_codec_dev_ac97,
|
||||
};
|
||||
|
||||
/*------------------------- I2S PART ---------------------------*/
|
||||
|
|
@ -49,12 +44,12 @@ static struct snd_soc_device db1200_ac97_devdata = {
|
|||
static int db1200_i2s_startup(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
|
||||
struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
int ret;
|
||||
|
||||
/* WM8731 has its own 12MHz crystal */
|
||||
snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK,
|
||||
snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL,
|
||||
12000000, SND_SOC_CLOCK_IN);
|
||||
|
||||
/* codec is bitclock and lrclk master */
|
||||
|
|
@ -80,8 +75,10 @@ static struct snd_soc_ops db1200_i2s_wm8731_ops = {
|
|||
static struct snd_soc_dai_link db1200_i2s_dai = {
|
||||
.name = "WM8731",
|
||||
.stream_name = "WM8731 PCM",
|
||||
.cpu_dai = &au1xpsc_i2s_dai,
|
||||
.codec_dai = &wm8731_dai,
|
||||
.codec_dai_name = "wm8731-hifi",
|
||||
.cpu_dai_name = "au1xpsc_i2s.1",
|
||||
.platform_name = "au1xpsc-pcm.1",
|
||||
.codec_name = "wm8731-codec.0-001b",
|
||||
.ops = &db1200_i2s_wm8731_ops,
|
||||
};
|
||||
|
||||
|
|
@ -89,12 +86,6 @@ static struct snd_soc_card db1200_i2s_machine = {
|
|||
.name = "DB1200_I2S",
|
||||
.dai_link = &db1200_i2s_dai,
|
||||
.num_links = 1,
|
||||
.platform = &au1xpsc_soc_platform,
|
||||
};
|
||||
|
||||
static struct snd_soc_device db1200_i2s_devdata = {
|
||||
.card = &db1200_i2s_machine,
|
||||
.codec_dev = &soc_codec_dev_wm8731,
|
||||
};
|
||||
|
||||
/*------------------------- COMMON PART ---------------------------*/
|
||||
|
|
@ -106,18 +97,16 @@ static int __init db1200_audio_load(void)
|
|||
int ret;
|
||||
|
||||
ret = -ENOMEM;
|
||||
db1200_asoc_dev = platform_device_alloc("soc-audio", -1);
|
||||
db1200_asoc_dev = platform_device_alloc("soc-audio", 1); /* PSC1 */
|
||||
if (!db1200_asoc_dev)
|
||||
goto out;
|
||||
|
||||
/* DB1200 board setup set PSC1MUX to preferred audio device */
|
||||
if (bcsr_read(BCSR_RESETS) & BCSR_RESETS_PSC1MUX)
|
||||
platform_set_drvdata(db1200_asoc_dev, &db1200_i2s_devdata);
|
||||
platform_set_drvdata(db1200_asoc_dev, &db1200_i2s_machine);
|
||||
else
|
||||
platform_set_drvdata(db1200_asoc_dev, &db1200_ac97_devdata);
|
||||
platform_set_drvdata(db1200_asoc_dev, &db1200_ac97_machine);
|
||||
|
||||
db1200_ac97_devdata.dev = &db1200_asoc_dev->dev;
|
||||
db1200_i2s_devdata.dev = &db1200_asoc_dev->dev;
|
||||
ret = platform_device_add(db1200_asoc_dev);
|
||||
|
||||
if (ret) {
|
||||
|
|
|
|||
|
|
@ -10,9 +10,6 @@
|
|||
*
|
||||
* DMA glue for Au1x-PSC audio.
|
||||
*
|
||||
* NOTE: all of these drivers can only work with a SINGLE instance
|
||||
* of a PSC. Multiple independent audio devices are impossible
|
||||
* with ASoC v1.
|
||||
*/
|
||||
|
||||
|
||||
|
|
@ -61,9 +58,6 @@ struct au1xpsc_audio_dmadata {
|
|||
int msbits;
|
||||
};
|
||||
|
||||
/* instance data. There can be only one, MacLeod!!!! */
|
||||
static struct au1xpsc_audio_dmadata *au1xpsc_audio_pcmdma[2];
|
||||
|
||||
/*
|
||||
* These settings are somewhat okay, at least on my machine audio plays
|
||||
* almost skip-free. Especially the 64kB buffer seems to help a LOT.
|
||||
|
|
@ -199,6 +193,14 @@ out:
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline struct au1xpsc_audio_dmadata *to_dmadata(struct snd_pcm_substream *ss)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = ss->private_data;
|
||||
struct au1xpsc_audio_dmadata *pcd =
|
||||
snd_soc_platform_get_drvdata(rtd->platform);
|
||||
return &pcd[SUBSTREAM_TYPE(ss)];
|
||||
}
|
||||
|
||||
static int au1xpsc_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
|
|
@ -211,7 +213,7 @@ static int au1xpsc_pcm_hw_params(struct snd_pcm_substream *substream,
|
|||
goto out;
|
||||
|
||||
stype = SUBSTREAM_TYPE(substream);
|
||||
pcd = au1xpsc_audio_pcmdma[stype];
|
||||
pcd = to_dmadata(substream);
|
||||
|
||||
DBG("runtime->dma_area = 0x%08lx dma_addr_t = 0x%08lx dma_size = %d "
|
||||
"runtime->min_align %d\n",
|
||||
|
|
@ -249,8 +251,7 @@ static int au1xpsc_pcm_hw_free(struct snd_pcm_substream *substream)
|
|||
|
||||
static int au1xpsc_pcm_prepare(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct au1xpsc_audio_dmadata *pcd =
|
||||
au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)];
|
||||
struct au1xpsc_audio_dmadata *pcd = to_dmadata(substream);
|
||||
|
||||
au1xxx_dbdma_reset(pcd->ddma_chan);
|
||||
|
||||
|
|
@ -267,7 +268,7 @@ static int au1xpsc_pcm_prepare(struct snd_pcm_substream *substream)
|
|||
|
||||
static int au1xpsc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
{
|
||||
u32 c = au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)]->ddma_chan;
|
||||
u32 c = to_dmadata(substream)->ddma_chan;
|
||||
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
|
|
@ -287,8 +288,7 @@ static int au1xpsc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
|||
static snd_pcm_uframes_t
|
||||
au1xpsc_pcm_pointer(struct snd_pcm_substream *substream)
|
||||
{
|
||||
return bytes_to_frames(substream->runtime,
|
||||
au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)]->pos);
|
||||
return bytes_to_frames(substream->runtime, to_dmadata(substream)->pos);
|
||||
}
|
||||
|
||||
static int au1xpsc_pcm_open(struct snd_pcm_substream *substream)
|
||||
|
|
@ -299,7 +299,7 @@ static int au1xpsc_pcm_open(struct snd_pcm_substream *substream)
|
|||
|
||||
static int au1xpsc_pcm_close(struct snd_pcm_substream *substream)
|
||||
{
|
||||
au1x_pcm_dbdma_free(au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)]);
|
||||
au1x_pcm_dbdma_free(to_dmadata(substream));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -329,42 +329,21 @@ static int au1xpsc_pcm_new(struct snd_card *card,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int au1xpsc_pcm_probe(struct platform_device *pdev)
|
||||
{
|
||||
if (!au1xpsc_audio_pcmdma[PCM_TX] || !au1xpsc_audio_pcmdma[PCM_RX])
|
||||
return -ENODEV;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int au1xpsc_pcm_remove(struct platform_device *pdev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* au1xpsc audio platform */
|
||||
struct snd_soc_platform au1xpsc_soc_platform = {
|
||||
.name = "au1xpsc-pcm-dbdma",
|
||||
.probe = au1xpsc_pcm_probe,
|
||||
.remove = au1xpsc_pcm_remove,
|
||||
.pcm_ops = &au1xpsc_pcm_ops,
|
||||
struct snd_soc_platform_driver au1xpsc_soc_platform = {
|
||||
.ops = &au1xpsc_pcm_ops,
|
||||
.pcm_new = au1xpsc_pcm_new,
|
||||
.pcm_free = au1xpsc_pcm_free_dma_buffers,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(au1xpsc_soc_platform);
|
||||
|
||||
static int __devinit au1xpsc_pcm_drvprobe(struct platform_device *pdev)
|
||||
{
|
||||
struct au1xpsc_audio_dmadata *dmadata;
|
||||
struct resource *r;
|
||||
int ret;
|
||||
|
||||
if (au1xpsc_audio_pcmdma[PCM_TX] || au1xpsc_audio_pcmdma[PCM_RX])
|
||||
return -EBUSY;
|
||||
|
||||
/* TX DMA */
|
||||
au1xpsc_audio_pcmdma[PCM_TX]
|
||||
= kzalloc(sizeof(struct au1xpsc_audio_dmadata), GFP_KERNEL);
|
||||
if (!au1xpsc_audio_pcmdma[PCM_TX])
|
||||
dmadata = kzalloc(2 * sizeof(struct au1xpsc_audio_dmadata), GFP_KERNEL);
|
||||
if (!dmadata)
|
||||
return -ENOMEM;
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
|
||||
|
|
@ -372,47 +351,33 @@ static int __devinit au1xpsc_pcm_drvprobe(struct platform_device *pdev)
|
|||
ret = -ENODEV;
|
||||
goto out1;
|
||||
}
|
||||
(au1xpsc_audio_pcmdma[PCM_TX])->ddma_id = r->start;
|
||||
dmadata[PCM_TX].ddma_id = r->start;
|
||||
|
||||
/* RX DMA */
|
||||
au1xpsc_audio_pcmdma[PCM_RX]
|
||||
= kzalloc(sizeof(struct au1xpsc_audio_dmadata), GFP_KERNEL);
|
||||
if (!au1xpsc_audio_pcmdma[PCM_RX])
|
||||
return -ENOMEM;
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
|
||||
if (!r) {
|
||||
ret = -ENODEV;
|
||||
goto out2;
|
||||
goto out1;
|
||||
}
|
||||
(au1xpsc_audio_pcmdma[PCM_RX])->ddma_id = r->start;
|
||||
dmadata[PCM_RX].ddma_id = r->start;
|
||||
|
||||
ret = snd_soc_register_platform(&au1xpsc_soc_platform);
|
||||
platform_set_drvdata(pdev, dmadata);
|
||||
|
||||
ret = snd_soc_register_platform(&pdev->dev, &au1xpsc_soc_platform);
|
||||
if (!ret)
|
||||
return ret;
|
||||
|
||||
out2:
|
||||
kfree(au1xpsc_audio_pcmdma[PCM_RX]);
|
||||
au1xpsc_audio_pcmdma[PCM_RX] = NULL;
|
||||
out1:
|
||||
kfree(au1xpsc_audio_pcmdma[PCM_TX]);
|
||||
au1xpsc_audio_pcmdma[PCM_TX] = NULL;
|
||||
kfree(dmadata);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit au1xpsc_pcm_drvremove(struct platform_device *pdev)
|
||||
{
|
||||
int i;
|
||||
struct au1xpsc_audio_dmadata *dmadata = platform_get_drvdata(pdev);
|
||||
|
||||
snd_soc_unregister_platform(&au1xpsc_soc_platform);
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
if (au1xpsc_audio_pcmdma[i]) {
|
||||
au1x_pcm_dbdma_free(au1xpsc_audio_pcmdma[i]);
|
||||
kfree(au1xpsc_audio_pcmdma[i]);
|
||||
au1xpsc_audio_pcmdma[i] = NULL;
|
||||
}
|
||||
}
|
||||
snd_soc_unregister_platform(&pdev->dev);
|
||||
kfree(dmadata);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -428,8 +393,6 @@ static struct platform_driver au1xpsc_pcm_driver = {
|
|||
|
||||
static int __init au1xpsc_audio_dbdma_load(void)
|
||||
{
|
||||
au1xpsc_audio_pcmdma[PCM_TX] = NULL;
|
||||
au1xpsc_audio_pcmdma[PCM_RX] = NULL;
|
||||
return platform_driver_register(&au1xpsc_pcm_driver);
|
||||
}
|
||||
|
||||
|
|
@ -467,7 +430,7 @@ struct platform_device *au1xpsc_pcm_add(struct platform_device *pdev)
|
|||
res[1].start = res[1].end = id[1];
|
||||
res[0].flags = res[1].flags = IORESOURCE_DMA;
|
||||
|
||||
pd = platform_device_alloc("au1xpsc-pcm", -1);
|
||||
pd = platform_device_alloc("au1xpsc-pcm", pdev->id);
|
||||
if (!pd)
|
||||
goto out;
|
||||
|
||||
|
|
|
|||
|
|
@ -10,9 +10,6 @@
|
|||
*
|
||||
* Au1xxx-PSC AC97 glue.
|
||||
*
|
||||
* NOTE: all of these drivers can only work with a SINGLE instance
|
||||
* of a PSC. Multiple independent audio devices are impossible
|
||||
* with ASoC v1.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
|
|
@ -56,12 +53,29 @@
|
|||
/* instance data. There can be only one, MacLeod!!!! */
|
||||
static struct au1xpsc_audio_data *au1xpsc_ac97_workdata;
|
||||
|
||||
#if 0
|
||||
|
||||
/* this could theoretically work, but ac97->bus->card->private_data can be NULL
|
||||
* when snd_ac97_mixer() is called; I don't know if the rest further down the
|
||||
* chain are always valid either.
|
||||
*/
|
||||
static inline struct au1xpsc_audio_data *ac97_to_pscdata(struct snd_ac97 *x)
|
||||
{
|
||||
struct snd_soc_card *c = x->bus->card->private_data;
|
||||
return snd_soc_dai_get_drvdata(c->rtd->cpu_dai);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define ac97_to_pscdata(x) au1xpsc_ac97_workdata
|
||||
|
||||
#endif
|
||||
|
||||
/* AC97 controller reads codec register */
|
||||
static unsigned short au1xpsc_ac97_read(struct snd_ac97 *ac97,
|
||||
unsigned short reg)
|
||||
{
|
||||
/* FIXME */
|
||||
struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
|
||||
struct au1xpsc_audio_data *pscdata = ac97_to_pscdata(ac97);
|
||||
unsigned short retry, tmo;
|
||||
unsigned long data;
|
||||
|
||||
|
|
@ -102,8 +116,7 @@ static unsigned short au1xpsc_ac97_read(struct snd_ac97 *ac97,
|
|||
static void au1xpsc_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
|
||||
unsigned short val)
|
||||
{
|
||||
/* FIXME */
|
||||
struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
|
||||
struct au1xpsc_audio_data *pscdata = ac97_to_pscdata(ac97);
|
||||
unsigned int tmo, retry;
|
||||
|
||||
au_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata));
|
||||
|
|
@ -134,8 +147,7 @@ static void au1xpsc_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
|
|||
/* AC97 controller asserts a warm reset */
|
||||
static void au1xpsc_ac97_warm_reset(struct snd_ac97 *ac97)
|
||||
{
|
||||
/* FIXME */
|
||||
struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
|
||||
struct au1xpsc_audio_data *pscdata = ac97_to_pscdata(ac97);
|
||||
|
||||
au_writel(PSC_AC97RST_SNC, AC97_RST(pscdata));
|
||||
au_sync();
|
||||
|
|
@ -146,8 +158,7 @@ static void au1xpsc_ac97_warm_reset(struct snd_ac97 *ac97)
|
|||
|
||||
static void au1xpsc_ac97_cold_reset(struct snd_ac97 *ac97)
|
||||
{
|
||||
/* FIXME */
|
||||
struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
|
||||
struct au1xpsc_audio_data *pscdata = ac97_to_pscdata(ac97);
|
||||
int i;
|
||||
|
||||
/* disable PSC during cold reset */
|
||||
|
|
@ -202,8 +213,7 @@ static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream,
|
|||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
/* FIXME */
|
||||
struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
|
||||
struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
|
||||
unsigned long r, ro, stat;
|
||||
int chans, t, stype = SUBSTREAM_TYPE(substream);
|
||||
|
||||
|
|
@ -283,8 +293,7 @@ out:
|
|||
static int au1xpsc_ac97_trigger(struct snd_pcm_substream *substream,
|
||||
int cmd, struct snd_soc_dai *dai)
|
||||
{
|
||||
/* FIXME */
|
||||
struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
|
||||
struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
|
||||
int ret, stype = SUBSTREAM_TYPE(substream);
|
||||
|
||||
ret = 0;
|
||||
|
|
@ -315,27 +324,19 @@ static int au1xpsc_ac97_trigger(struct snd_pcm_substream *substream,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int au1xpsc_ac97_probe(struct platform_device *pdev,
|
||||
struct snd_soc_dai *dai)
|
||||
static int au1xpsc_ac97_probe(struct snd_soc_dai *dai)
|
||||
{
|
||||
return au1xpsc_ac97_workdata ? 0 : -ENODEV;
|
||||
}
|
||||
|
||||
static void au1xpsc_ac97_remove(struct platform_device *pdev,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
}
|
||||
|
||||
static struct snd_soc_dai_ops au1xpsc_ac97_dai_ops = {
|
||||
.trigger = au1xpsc_ac97_trigger,
|
||||
.hw_params = au1xpsc_ac97_hw_params,
|
||||
};
|
||||
|
||||
struct snd_soc_dai au1xpsc_ac97_dai = {
|
||||
.name = "au1xpsc_ac97",
|
||||
static const struct snd_soc_dai_driver au1xpsc_ac97_dai_template = {
|
||||
.ac97_control = 1,
|
||||
.probe = au1xpsc_ac97_probe,
|
||||
.remove = au1xpsc_ac97_remove,
|
||||
.playback = {
|
||||
.rates = AC97_RATES,
|
||||
.formats = AC97_FMTS,
|
||||
|
|
@ -350,7 +351,6 @@ struct snd_soc_dai au1xpsc_ac97_dai = {
|
|||
},
|
||||
.ops = &au1xpsc_ac97_dai_ops,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(au1xpsc_ac97_dai);
|
||||
|
||||
static int __devinit au1xpsc_ac97_drvprobe(struct platform_device *pdev)
|
||||
{
|
||||
|
|
@ -359,9 +359,6 @@ static int __devinit au1xpsc_ac97_drvprobe(struct platform_device *pdev)
|
|||
unsigned long sel;
|
||||
struct au1xpsc_audio_data *wd;
|
||||
|
||||
if (au1xpsc_ac97_workdata)
|
||||
return -EBUSY;
|
||||
|
||||
wd = kzalloc(sizeof(struct au1xpsc_audio_data), GFP_KERNEL);
|
||||
if (!wd)
|
||||
return -ENOMEM;
|
||||
|
|
@ -395,18 +392,24 @@ static int __devinit au1xpsc_ac97_drvprobe(struct platform_device *pdev)
|
|||
au_writel(PSC_SEL_PS_AC97MODE | sel, PSC_SEL(wd));
|
||||
au_sync();
|
||||
|
||||
ret = snd_soc_register_dai(&au1xpsc_ac97_dai);
|
||||
/* name the DAI like this device instance ("au1xpsc-ac97.PSCINDEX") */
|
||||
memcpy(&wd->dai_drv, &au1xpsc_ac97_dai_template,
|
||||
sizeof(struct snd_soc_dai_driver));
|
||||
wd->dai_drv.name = dev_name(&pdev->dev);
|
||||
|
||||
platform_set_drvdata(pdev, wd);
|
||||
|
||||
ret = snd_soc_register_dai(&pdev->dev, &wd->dai_drv);
|
||||
if (ret)
|
||||
goto out1;
|
||||
|
||||
wd->dmapd = au1xpsc_pcm_add(pdev);
|
||||
if (wd->dmapd) {
|
||||
platform_set_drvdata(pdev, wd);
|
||||
au1xpsc_ac97_workdata = wd; /* MDEV */
|
||||
au1xpsc_ac97_workdata = wd;
|
||||
return 0;
|
||||
}
|
||||
|
||||
snd_soc_unregister_dai(&au1xpsc_ac97_dai);
|
||||
snd_soc_unregister_dai(&pdev->dev);
|
||||
out1:
|
||||
release_mem_region(r->start, resource_size(r));
|
||||
out0:
|
||||
|
|
@ -422,7 +425,7 @@ static int __devexit au1xpsc_ac97_drvremove(struct platform_device *pdev)
|
|||
if (wd->dmapd)
|
||||
au1xpsc_pcm_destroy(wd->dmapd);
|
||||
|
||||
snd_soc_unregister_dai(&au1xpsc_ac97_dai);
|
||||
snd_soc_unregister_dai(&pdev->dev);
|
||||
|
||||
/* disable PSC completely */
|
||||
au_writel(0, AC97_CFG(wd));
|
||||
|
|
|
|||
|
|
@ -10,9 +10,6 @@
|
|||
*
|
||||
* Au1xxx-PSC I2S glue.
|
||||
*
|
||||
* NOTE: all of these drivers can only work with a SINGLE instance
|
||||
* of a PSC. Multiple independent audio devices are impossible
|
||||
* with ASoC v1.
|
||||
* NOTE: so far only PSC slave mode (bit- and frameclock) is supported.
|
||||
*/
|
||||
|
||||
|
|
@ -54,13 +51,10 @@
|
|||
((stype) == PCM_TX ? PSC_I2SPCR_TC : PSC_I2SPCR_RC)
|
||||
|
||||
|
||||
/* instance data. There can be only one, MacLeod!!!! */
|
||||
static struct au1xpsc_audio_data *au1xpsc_i2s_workdata;
|
||||
|
||||
static int au1xpsc_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
|
||||
unsigned int fmt)
|
||||
{
|
||||
struct au1xpsc_audio_data *pscdata = au1xpsc_i2s_workdata;
|
||||
struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(cpu_dai);
|
||||
unsigned long ct;
|
||||
int ret;
|
||||
|
||||
|
|
@ -120,7 +114,7 @@ static int au1xpsc_i2s_hw_params(struct snd_pcm_substream *substream,
|
|||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct au1xpsc_audio_data *pscdata = au1xpsc_i2s_workdata;
|
||||
struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
|
||||
|
||||
int cfgbits;
|
||||
unsigned long stat;
|
||||
|
|
@ -245,7 +239,7 @@ static int au1xpsc_i2s_stop(struct au1xpsc_audio_data *pscdata, int stype)
|
|||
static int au1xpsc_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct au1xpsc_audio_data *pscdata = au1xpsc_i2s_workdata;
|
||||
struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
|
||||
int ret, stype = SUBSTREAM_TYPE(substream);
|
||||
|
||||
switch (cmd) {
|
||||
|
|
@ -263,27 +257,13 @@ static int au1xpsc_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int au1xpsc_i2s_probe(struct platform_device *pdev,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
return au1xpsc_i2s_workdata ? 0 : -ENODEV;
|
||||
}
|
||||
|
||||
static void au1xpsc_i2s_remove(struct platform_device *pdev,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
}
|
||||
|
||||
static struct snd_soc_dai_ops au1xpsc_i2s_dai_ops = {
|
||||
.trigger = au1xpsc_i2s_trigger,
|
||||
.hw_params = au1xpsc_i2s_hw_params,
|
||||
.set_fmt = au1xpsc_i2s_set_fmt,
|
||||
};
|
||||
|
||||
struct snd_soc_dai au1xpsc_i2s_dai = {
|
||||
.name = "au1xpsc_i2s",
|
||||
.probe = au1xpsc_i2s_probe,
|
||||
.remove = au1xpsc_i2s_remove,
|
||||
static const struct snd_soc_dai_driver au1xpsc_i2s_dai_template = {
|
||||
.playback = {
|
||||
.rates = AU1XPSC_I2S_RATES,
|
||||
.formats = AU1XPSC_I2S_FMTS,
|
||||
|
|
@ -298,7 +278,6 @@ struct snd_soc_dai au1xpsc_i2s_dai = {
|
|||
},
|
||||
.ops = &au1xpsc_i2s_dai_ops,
|
||||
};
|
||||
EXPORT_SYMBOL(au1xpsc_i2s_dai);
|
||||
|
||||
static int __devinit au1xpsc_i2s_drvprobe(struct platform_device *pdev)
|
||||
{
|
||||
|
|
@ -307,9 +286,6 @@ static int __devinit au1xpsc_i2s_drvprobe(struct platform_device *pdev)
|
|||
int ret;
|
||||
struct au1xpsc_audio_data *wd;
|
||||
|
||||
if (au1xpsc_i2s_workdata)
|
||||
return -EBUSY;
|
||||
|
||||
wd = kzalloc(sizeof(struct au1xpsc_audio_data), GFP_KERNEL);
|
||||
if (!wd)
|
||||
return -ENOMEM;
|
||||
|
|
@ -346,19 +322,23 @@ static int __devinit au1xpsc_i2s_drvprobe(struct platform_device *pdev)
|
|||
* time out.
|
||||
*/
|
||||
|
||||
ret = snd_soc_register_dai(&au1xpsc_i2s_dai);
|
||||
/* name the DAI like this device instance ("au1xpsc-i2s.PSCINDEX") */
|
||||
memcpy(&wd->dai_drv, &au1xpsc_i2s_dai_template,
|
||||
sizeof(struct snd_soc_dai_driver));
|
||||
wd->dai_drv.name = dev_name(&pdev->dev);
|
||||
|
||||
platform_set_drvdata(pdev, wd);
|
||||
|
||||
ret = snd_soc_register_dai(&pdev->dev, &wd->dai_drv);
|
||||
if (ret)
|
||||
goto out1;
|
||||
|
||||
/* finally add the DMA device for this PSC */
|
||||
wd->dmapd = au1xpsc_pcm_add(pdev);
|
||||
if (wd->dmapd) {
|
||||
platform_set_drvdata(pdev, wd);
|
||||
au1xpsc_i2s_workdata = wd;
|
||||
if (wd->dmapd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
snd_soc_unregister_dai(&au1xpsc_i2s_dai);
|
||||
snd_soc_unregister_dai(&pdev->dev);
|
||||
out1:
|
||||
release_mem_region(r->start, resource_size(r));
|
||||
out0:
|
||||
|
|
@ -374,7 +354,7 @@ static int __devexit au1xpsc_i2s_drvremove(struct platform_device *pdev)
|
|||
if (wd->dmapd)
|
||||
au1xpsc_pcm_destroy(wd->dmapd);
|
||||
|
||||
snd_soc_unregister_dai(&au1xpsc_i2s_dai);
|
||||
snd_soc_unregister_dai(&pdev->dev);
|
||||
|
||||
au_writel(0, I2S_CFG(wd));
|
||||
au_sync();
|
||||
|
|
@ -385,8 +365,6 @@ static int __devexit au1xpsc_i2s_drvremove(struct platform_device *pdev)
|
|||
release_mem_region(r->start, resource_size(r));
|
||||
kfree(wd);
|
||||
|
||||
au1xpsc_i2s_workdata = NULL; /* MDEV */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -446,7 +424,6 @@ static struct platform_driver au1xpsc_i2s_driver = {
|
|||
|
||||
static int __init au1xpsc_i2s_load(void)
|
||||
{
|
||||
au1xpsc_i2s_workdata = NULL;
|
||||
return platform_driver_register(&au1xpsc_i2s_driver);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,19 +8,11 @@
|
|||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* NOTE: all of these drivers can only work with a SINGLE instance
|
||||
* of a PSC. Multiple independent audio devices are impossible
|
||||
* with ASoC v1.
|
||||
*/
|
||||
|
||||
#ifndef _AU1X_PCM_H
|
||||
#define _AU1X_PCM_H
|
||||
|
||||
extern struct snd_soc_dai au1xpsc_ac97_dai;
|
||||
extern struct snd_soc_dai au1xpsc_i2s_dai;
|
||||
extern struct snd_soc_platform au1xpsc_soc_platform;
|
||||
extern struct snd_ac97_bus_ops soc_ac97_ops;
|
||||
|
||||
/* DBDMA helpers */
|
||||
extern struct platform_device *au1xpsc_pcm_add(struct platform_device *pdev);
|
||||
extern void au1xpsc_pcm_destroy(struct platform_device *dmapd);
|
||||
|
|
@ -31,6 +23,8 @@ struct au1xpsc_audio_data {
|
|||
unsigned long cfg;
|
||||
unsigned long rate;
|
||||
|
||||
struct snd_soc_dai_driver dai_drv;
|
||||
|
||||
unsigned long pm[2];
|
||||
struct mutex lock;
|
||||
struct platform_device *dmapd;
|
||||
|
|
|
|||
|
|
@ -422,14 +422,14 @@ int bf5xx_pcm_ac97_new(struct snd_card *card, struct snd_soc_dai *dai,
|
|||
if (!card->dev->coherent_dma_mask)
|
||||
card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
|
||||
|
||||
if (dai->playback.channels_min) {
|
||||
if (dai->driver->playback.channels_min) {
|
||||
ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
|
||||
SNDRV_PCM_STREAM_PLAYBACK);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (dai->capture.channels_min) {
|
||||
if (dai->driver->capture.channels_min) {
|
||||
ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
|
||||
SNDRV_PCM_STREAM_CAPTURE);
|
||||
if (ret)
|
||||
|
|
@ -439,25 +439,44 @@ int bf5xx_pcm_ac97_new(struct snd_card *card, struct snd_soc_dai *dai,
|
|||
return ret;
|
||||
}
|
||||
|
||||
struct snd_soc_platform bf5xx_ac97_soc_platform = {
|
||||
.name = "bf5xx-audio",
|
||||
.pcm_ops = &bf5xx_pcm_ac97_ops,
|
||||
static struct snd_soc_platform_driver bf5xx_ac97_soc_platform = {
|
||||
.ops = &bf5xx_pcm_ac97_ops,
|
||||
.pcm_new = bf5xx_pcm_ac97_new,
|
||||
.pcm_free = bf5xx_pcm_free_dma_buffers,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(bf5xx_ac97_soc_platform);
|
||||
|
||||
static int __init bfin_ac97_init(void)
|
||||
static int __devinit bf5xx_soc_platform_probe(struct platform_device *pdev)
|
||||
{
|
||||
return snd_soc_register_platform(&bf5xx_ac97_soc_platform);
|
||||
return snd_soc_register_platform(&pdev->dev, &bf5xx_ac97_soc_platform);
|
||||
}
|
||||
module_init(bfin_ac97_init);
|
||||
|
||||
static void __exit bfin_ac97_exit(void)
|
||||
static int __devexit bf5xx_soc_platform_remove(struct platform_device *pdev)
|
||||
{
|
||||
snd_soc_unregister_platform(&bf5xx_ac97_soc_platform);
|
||||
snd_soc_unregister_platform(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
module_exit(bfin_ac97_exit);
|
||||
|
||||
static struct platform_driver bf5xx_pcm_driver = {
|
||||
.driver = {
|
||||
.name = "bf5xx-pcm-audio",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
|
||||
.probe = bf5xx_soc_platform_probe,
|
||||
.remove = __devexit_p(bf5xx_soc_platform_remove),
|
||||
};
|
||||
|
||||
static int __init snd_bf5xx_pcm_init(void)
|
||||
{
|
||||
return platform_driver_register(&bf5xx_pcm_driver);
|
||||
}
|
||||
module_init(snd_bf5xx_pcm_init);
|
||||
|
||||
static void __exit snd_bf5xx_pcm_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&bf5xx_pcm_driver);
|
||||
}
|
||||
module_exit(snd_bf5xx_pcm_exit);
|
||||
|
||||
MODULE_AUTHOR("Cliff Cai");
|
||||
MODULE_DESCRIPTION("ADI Blackfin AC97 PCM DMA module");
|
||||
|
|
|
|||
|
|
@ -23,7 +23,4 @@ struct bf5xx_gpio {
|
|||
u32 frm;
|
||||
};
|
||||
|
||||
/* platform data */
|
||||
extern struct snd_soc_platform bf5xx_ac97_soc_platform;
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -255,7 +255,7 @@ EXPORT_SYMBOL_GPL(soc_ac97_ops);
|
|||
#ifdef CONFIG_PM
|
||||
static int bf5xx_ac97_suspend(struct snd_soc_dai *dai)
|
||||
{
|
||||
struct sport_device *sport = dai->private_data;
|
||||
struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
|
||||
|
||||
pr_debug("%s : sport %d\n", __func__, dai->id);
|
||||
if (!dai->active)
|
||||
|
|
@ -270,7 +270,7 @@ static int bf5xx_ac97_suspend(struct snd_soc_dai *dai)
|
|||
static int bf5xx_ac97_resume(struct snd_soc_dai *dai)
|
||||
{
|
||||
int ret;
|
||||
struct sport_device *sport = dai->private_data;
|
||||
struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
|
||||
|
||||
pr_debug("%s : sport %d\n", __func__, dai->id);
|
||||
if (!dai->active)
|
||||
|
|
@ -306,8 +306,7 @@ static int bf5xx_ac97_resume(struct snd_soc_dai *dai)
|
|||
#define bf5xx_ac97_resume NULL
|
||||
#endif
|
||||
|
||||
static int bf5xx_ac97_probe(struct platform_device *pdev,
|
||||
struct snd_soc_dai *dai)
|
||||
static int bf5xx_ac97_probe(struct snd_soc_dai *dai)
|
||||
{
|
||||
int ret = 0;
|
||||
cmd_count = (int *)get_zeroed_page(GFP_KERNEL);
|
||||
|
|
@ -379,8 +378,7 @@ peripheral_err:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void bf5xx_ac97_remove(struct platform_device *pdev,
|
||||
struct snd_soc_dai *dai)
|
||||
static int bf5xx_ac97_remove(struct snd_soc_dai *dai)
|
||||
{
|
||||
free_page((unsigned long)cmd_count);
|
||||
cmd_count = NULL;
|
||||
|
|
@ -388,11 +386,10 @@ static void bf5xx_ac97_remove(struct platform_device *pdev,
|
|||
#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
|
||||
gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct snd_soc_dai bfin_ac97_dai = {
|
||||
.name = "bf5xx-ac97",
|
||||
.id = 0,
|
||||
struct snd_soc_dai_driver bfin_ac97_dai = {
|
||||
.ac97_control = 1,
|
||||
.probe = bf5xx_ac97_probe,
|
||||
.remove = bf5xx_ac97_remove,
|
||||
|
|
@ -417,18 +414,40 @@ struct snd_soc_dai bfin_ac97_dai = {
|
|||
};
|
||||
EXPORT_SYMBOL_GPL(bfin_ac97_dai);
|
||||
|
||||
static __devinit int asoc_bfin_ac97_probe(struct platform_device *pdev)
|
||||
{
|
||||
return snd_soc_register_dai(&pdev->dev, &bfin_ac97_dai);
|
||||
}
|
||||
|
||||
static int __devexit asoc_bfin_ac97_remove(struct platform_device *pdev)
|
||||
{
|
||||
snd_soc_unregister_dai(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver asoc_bfin_ac97_driver = {
|
||||
.driver = {
|
||||
.name = "bfin-ac97",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
|
||||
.probe = asoc_bfin_ac97_probe,
|
||||
.remove = __devexit_p(asoc_bfin_ac97_remove),
|
||||
};
|
||||
|
||||
static int __init bfin_ac97_init(void)
|
||||
{
|
||||
return snd_soc_register_dai(&bfin_ac97_dai);
|
||||
return platform_driver_register(&asoc_bfin_ac97_driver);
|
||||
}
|
||||
module_init(bfin_ac97_init);
|
||||
|
||||
static void __exit bfin_ac97_exit(void)
|
||||
{
|
||||
snd_soc_unregister_dai(&bfin_ac97_dai);
|
||||
platform_driver_unregister(&asoc_bfin_ac97_driver);
|
||||
}
|
||||
module_exit(bfin_ac97_exit);
|
||||
|
||||
|
||||
MODULE_AUTHOR("Roy Huang");
|
||||
MODULE_DESCRIPTION("AC97 driver for ADI Blackfin");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
|||
|
|
@ -50,8 +50,6 @@ struct ac97_frame {
|
|||
#define TAG_PCM_SR 0x0080
|
||||
#define TAG_PCM_LFE 0x0040
|
||||
|
||||
extern struct snd_soc_dai bfin_ac97_dai;
|
||||
|
||||
void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u16 *src, \
|
||||
size_t count, unsigned int chan_mask);
|
||||
|
||||
|
|
|
|||
|
|
@ -40,9 +40,9 @@ static struct snd_soc_card bf5xx_ad1836;
|
|||
static int bf5xx_ad1836_startup(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
|
||||
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
|
||||
cpu_dai->private_data = sport_handle;
|
||||
snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -50,8 +50,8 @@ static int bf5xx_ad1836_hw_params(struct snd_pcm_substream *substream,
|
|||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
|
||||
struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
|
||||
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
unsigned int channel_map[] = {0, 4, 1, 5, 2, 6, 3, 7};
|
||||
int ret = 0;
|
||||
/* set cpu DAI configuration */
|
||||
|
|
@ -83,23 +83,19 @@ static struct snd_soc_ops bf5xx_ad1836_ops = {
|
|||
static struct snd_soc_dai_link bf5xx_ad1836_dai = {
|
||||
.name = "ad1836",
|
||||
.stream_name = "AD1836",
|
||||
.cpu_dai = &bf5xx_tdm_dai,
|
||||
.codec_dai = &ad1836_dai,
|
||||
.cpu_dai_name = "bf5xx-tdm",
|
||||
.codec_dai_name = "ad1836-hifi",
|
||||
.platform_name = "bf5xx-tdm-pcm-audio",
|
||||
.codec_name = "ad1836-codec.0",
|
||||
.ops = &bf5xx_ad1836_ops,
|
||||
};
|
||||
|
||||
static struct snd_soc_card bf5xx_ad1836 = {
|
||||
.name = "bf5xx_ad1836",
|
||||
.platform = &bf5xx_tdm_soc_platform,
|
||||
.dai_link = &bf5xx_ad1836_dai,
|
||||
.num_links = 1,
|
||||
};
|
||||
|
||||
static struct snd_soc_device bf5xx_ad1836_snd_devdata = {
|
||||
.card = &bf5xx_ad1836,
|
||||
.codec_dev = &soc_codec_dev_ad1836,
|
||||
};
|
||||
|
||||
static struct platform_device *bfxx_ad1836_snd_device;
|
||||
|
||||
static int __init bf5xx_ad1836_init(void)
|
||||
|
|
@ -110,8 +106,7 @@ static int __init bf5xx_ad1836_init(void)
|
|||
if (!bfxx_ad1836_snd_device)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(bfxx_ad1836_snd_device, &bf5xx_ad1836_snd_devdata);
|
||||
bf5xx_ad1836_snd_devdata.dev = &bfxx_ad1836_snd_device->dev;
|
||||
platform_set_drvdata(bfxx_ad1836_snd_device, &bf5xx_ad1836);
|
||||
ret = platform_device_add(bfxx_ad1836_snd_device);
|
||||
|
||||
if (ret)
|
||||
|
|
|
|||
|
|
@ -49,9 +49,9 @@ static struct snd_soc_card bf5xx_ad193x;
|
|||
static int bf5xx_ad193x_startup(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
|
||||
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
|
||||
cpu_dai->private_data = sport_handle;
|
||||
snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -59,8 +59,8 @@ static int bf5xx_ad193x_hw_params(struct snd_pcm_substream *substream,
|
|||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
|
||||
struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
|
||||
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
unsigned int channel_map[] = {0, 1, 2, 3, 4, 5, 6, 7};
|
||||
int ret = 0;
|
||||
/* set cpu DAI configuration */
|
||||
|
|
@ -97,23 +97,19 @@ static struct snd_soc_ops bf5xx_ad193x_ops = {
|
|||
static struct snd_soc_dai_link bf5xx_ad193x_dai = {
|
||||
.name = "ad193x",
|
||||
.stream_name = "AD193X",
|
||||
.cpu_dai = &bf5xx_tdm_dai,
|
||||
.codec_dai = &ad193x_dai,
|
||||
.cpu_dai_name = "bf5xx-tdm",
|
||||
.codec_dai_name ="ad193x-hifi",
|
||||
.platform_name = "bf5xx-tdm-pcm-audio",
|
||||
.codec_name = "ad193x-codec.5",
|
||||
.ops = &bf5xx_ad193x_ops,
|
||||
};
|
||||
|
||||
static struct snd_soc_card bf5xx_ad193x = {
|
||||
.name = "bf5xx_ad193x",
|
||||
.platform = &bf5xx_tdm_soc_platform,
|
||||
.dai_link = &bf5xx_ad193x_dai,
|
||||
.num_links = 1,
|
||||
};
|
||||
|
||||
static struct snd_soc_device bf5xx_ad193x_snd_devdata = {
|
||||
.card = &bf5xx_ad193x,
|
||||
.codec_dev = &soc_codec_dev_ad193x,
|
||||
};
|
||||
|
||||
static struct platform_device *bfxx_ad193x_snd_device;
|
||||
|
||||
static int __init bf5xx_ad193x_init(void)
|
||||
|
|
@ -124,8 +120,7 @@ static int __init bf5xx_ad193x_init(void)
|
|||
if (!bfxx_ad193x_snd_device)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(bfxx_ad193x_snd_device, &bf5xx_ad193x_snd_devdata);
|
||||
bf5xx_ad193x_snd_devdata.dev = &bfxx_ad193x_snd_device->dev;
|
||||
platform_set_drvdata(bfxx_ad193x_snd_device, &bf5xx_ad193x);
|
||||
ret = platform_device_add(bfxx_ad193x_snd_device);
|
||||
|
||||
if (ret)
|
||||
|
|
|
|||
|
|
@ -56,10 +56,10 @@ static struct snd_soc_card bf5xx_board;
|
|||
static int bf5xx_board_startup(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
|
||||
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
|
||||
pr_debug("%s enter\n", __func__);
|
||||
cpu_dai->private_data = sport_handle;
|
||||
snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -70,23 +70,19 @@ static struct snd_soc_ops bf5xx_board_ops = {
|
|||
static struct snd_soc_dai_link bf5xx_board_dai = {
|
||||
.name = "AC97",
|
||||
.stream_name = "AC97 HiFi",
|
||||
.cpu_dai = &bfin_ac97_dai,
|
||||
.codec_dai = &ad1980_dai,
|
||||
.cpu_dai_name = "bfin-ac97",
|
||||
.codec_dai_name = "ad1980-hifi",
|
||||
.platform_name = "bfin-pcm-audio",
|
||||
.codec_name = "ad1980-codec",
|
||||
.ops = &bf5xx_board_ops,
|
||||
};
|
||||
|
||||
static struct snd_soc_card bf5xx_board = {
|
||||
.name = "bf5xx-board",
|
||||
.platform = &bf5xx_ac97_soc_platform,
|
||||
.dai_link = &bf5xx_board_dai,
|
||||
.num_links = 1,
|
||||
};
|
||||
|
||||
static struct snd_soc_device bf5xx_board_snd_devdata = {
|
||||
.card = &bf5xx_board,
|
||||
.codec_dev = &soc_codec_dev_ad1980,
|
||||
};
|
||||
|
||||
static struct platform_device *bf5xx_board_snd_device;
|
||||
|
||||
static int __init bf5xx_board_init(void)
|
||||
|
|
@ -97,8 +93,7 @@ static int __init bf5xx_board_init(void)
|
|||
if (!bf5xx_board_snd_device)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(bf5xx_board_snd_device, &bf5xx_board_snd_devdata);
|
||||
bf5xx_board_snd_devdata.dev = &bf5xx_board_snd_device->dev;
|
||||
platform_set_drvdata(bf5xx_board_snd_device, &bf5xx_board);
|
||||
ret = platform_device_add(bf5xx_board_snd_device);
|
||||
|
||||
if (ret)
|
||||
|
|
|
|||
|
|
@ -47,7 +47,6 @@
|
|||
#include "../codecs/ad73311.h"
|
||||
#include "bf5xx-sport.h"
|
||||
#include "bf5xx-i2s-pcm.h"
|
||||
#include "bf5xx-i2s.h"
|
||||
|
||||
#if CONFIG_SND_BF5XX_SPORT_NUM == 0
|
||||
#define bfin_write_SPORT_TCR1 bfin_write_SPORT0_TCR1
|
||||
|
|
@ -150,10 +149,10 @@ static int bf5xx_probe(struct platform_device *pdev)
|
|||
static int bf5xx_ad73311_startup(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
|
||||
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
|
||||
pr_debug("%s enter\n", __func__);
|
||||
cpu_dai->private_data = sport_handle;
|
||||
snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -161,7 +160,7 @@ static int bf5xx_ad73311_hw_params(struct snd_pcm_substream *substream,
|
|||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
|
||||
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
int ret = 0;
|
||||
|
||||
pr_debug("%s rate %d format %x\n", __func__, params_rate(params),
|
||||
|
|
@ -185,24 +184,20 @@ static struct snd_soc_ops bf5xx_ad73311_ops = {
|
|||
static struct snd_soc_dai_link bf5xx_ad73311_dai = {
|
||||
.name = "ad73311",
|
||||
.stream_name = "AD73311",
|
||||
.cpu_dai = &bf5xx_i2s_dai,
|
||||
.codec_dai = &ad73311_dai,
|
||||
.cpu_dai_name = "bf5xx-i2s",
|
||||
.codec_dai_name = "ad73311-hifi",
|
||||
.platform_name = "bfin-pcm-audio",
|
||||
.codec_name = "ad73311-codec",
|
||||
.ops = &bf5xx_ad73311_ops,
|
||||
};
|
||||
|
||||
static struct snd_soc_card bf5xx_ad73311 = {
|
||||
.name = "bf5xx_ad73311",
|
||||
.platform = &bf5xx_i2s_soc_platform,
|
||||
.probe = bf5xx_probe,
|
||||
.dai_link = &bf5xx_ad73311_dai,
|
||||
.num_links = 1,
|
||||
};
|
||||
|
||||
static struct snd_soc_device bf5xx_ad73311_snd_devdata = {
|
||||
.card = &bf5xx_ad73311,
|
||||
.codec_dev = &soc_codec_dev_ad73311,
|
||||
};
|
||||
|
||||
static struct platform_device *bf5xx_ad73311_snd_device;
|
||||
|
||||
static int __init bf5xx_ad73311_init(void)
|
||||
|
|
@ -214,8 +209,7 @@ static int __init bf5xx_ad73311_init(void)
|
|||
if (!bf5xx_ad73311_snd_device)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(bf5xx_ad73311_snd_device, &bf5xx_ad73311_snd_devdata);
|
||||
bf5xx_ad73311_snd_devdata.dev = &bf5xx_ad73311_snd_device->dev;
|
||||
platform_set_drvdata(bf5xx_ad73311_snd_device, &bf5xx_ad73311);
|
||||
ret = platform_device_add(bf5xx_ad73311_snd_device);
|
||||
|
||||
if (ret)
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@
|
|||
#include <asm/dma.h>
|
||||
|
||||
#include "bf5xx-i2s-pcm.h"
|
||||
#include "bf5xx-i2s.h"
|
||||
#include "bf5xx-sport.h"
|
||||
|
||||
static void bf5xx_dma_irq(void *data)
|
||||
|
|
@ -257,14 +256,14 @@ int bf5xx_pcm_i2s_new(struct snd_card *card, struct snd_soc_dai *dai,
|
|||
if (!card->dev->coherent_dma_mask)
|
||||
card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
|
||||
|
||||
if (dai->playback.channels_min) {
|
||||
if (dai->driver->playback.channels_min) {
|
||||
ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
|
||||
SNDRV_PCM_STREAM_PLAYBACK);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (dai->capture.channels_min) {
|
||||
if (dai->driver->capture.channels_min) {
|
||||
ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
|
||||
SNDRV_PCM_STREAM_CAPTURE);
|
||||
if (ret)
|
||||
|
|
@ -274,25 +273,44 @@ int bf5xx_pcm_i2s_new(struct snd_card *card, struct snd_soc_dai *dai,
|
|||
return ret;
|
||||
}
|
||||
|
||||
struct snd_soc_platform bf5xx_i2s_soc_platform = {
|
||||
.name = "bf5xx-audio",
|
||||
.pcm_ops = &bf5xx_pcm_i2s_ops,
|
||||
static struct snd_soc_platform_driver bf5xx_i2s_soc_platform = {
|
||||
.ops = &bf5xx_pcm_i2s_ops,
|
||||
.pcm_new = bf5xx_pcm_i2s_new,
|
||||
.pcm_free = bf5xx_pcm_free_dma_buffers,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(bf5xx_i2s_soc_platform);
|
||||
|
||||
static int __init bfin_i2s_init(void)
|
||||
static int __devinit bfin_i2s_soc_platform_probe(struct platform_device *pdev)
|
||||
{
|
||||
return snd_soc_register_platform(&bf5xx_i2s_soc_platform);
|
||||
return snd_soc_register_platform(&pdev->dev, &bf5xx_i2s_soc_platform);
|
||||
}
|
||||
module_init(bfin_i2s_init);
|
||||
|
||||
static void __exit bfin_i2s_exit(void)
|
||||
static int __devexit bfin_i2s_soc_platform_remove(struct platform_device *pdev)
|
||||
{
|
||||
snd_soc_unregister_platform(&bf5xx_i2s_soc_platform);
|
||||
snd_soc_unregister_platform(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
module_exit(bfin_i2s_exit);
|
||||
|
||||
static struct platform_driver bfin_i2s_pcm_driver = {
|
||||
.driver = {
|
||||
.name = "bfin-pcm-audio",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
|
||||
.probe = bfin_i2s_soc_platform_probe,
|
||||
.remove = __devexit_p(bfin_i2s_soc_platform_remove),
|
||||
};
|
||||
|
||||
static int __init snd_bfin_i2s_pcm_init(void)
|
||||
{
|
||||
return platform_driver_register(&bfin_i2s_pcm_driver);
|
||||
}
|
||||
module_init(snd_bfin_i2s_pcm_init);
|
||||
|
||||
static void __exit snd_bfin_i2s_pcm_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&bfin_i2s_pcm_driver);
|
||||
}
|
||||
module_exit(snd_bfin_i2s_pcm_exit);
|
||||
|
||||
MODULE_AUTHOR("Cliff Cai");
|
||||
MODULE_DESCRIPTION("ADI Blackfin I2S PCM DMA module");
|
||||
|
|
|
|||
|
|
@ -23,7 +23,4 @@ struct bf5xx_gpio {
|
|||
u32 frm;
|
||||
};
|
||||
|
||||
/* platform data */
|
||||
extern struct snd_soc_platform bf5xx_i2s_soc_platform;
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -42,7 +42,6 @@
|
|||
#include <linux/gpio.h>
|
||||
|
||||
#include "bf5xx-sport.h"
|
||||
#include "bf5xx-i2s.h"
|
||||
|
||||
struct bf5xx_i2s_port {
|
||||
u16 tcr1;
|
||||
|
|
@ -195,8 +194,7 @@ static void bf5xx_i2s_shutdown(struct snd_pcm_substream *substream,
|
|||
bf5xx_i2s.configured = 0;
|
||||
}
|
||||
|
||||
static int bf5xx_i2s_probe(struct platform_device *pdev,
|
||||
struct snd_soc_dai *dai)
|
||||
static int bf5xx_i2s_probe(struct snd_soc_dai *dai)
|
||||
{
|
||||
pr_debug("%s enter\n", __func__);
|
||||
if (peripheral_request_list(&sport_req[sport_num][0], "soc-audio")) {
|
||||
|
|
@ -215,11 +213,11 @@ static int bf5xx_i2s_probe(struct platform_device *pdev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void bf5xx_i2s_remove(struct platform_device *pdev,
|
||||
struct snd_soc_dai *dai)
|
||||
static int bf5xx_i2s_remove(struct snd_soc_dai *dai)
|
||||
{
|
||||
pr_debug("%s enter\n", __func__);
|
||||
peripheral_free_list(&sport_req[sport_num][0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
|
@ -228,9 +226,9 @@ static int bf5xx_i2s_suspend(struct snd_soc_dai *dai)
|
|||
|
||||
pr_debug("%s : sport %d\n", __func__, dai->id);
|
||||
|
||||
if (dai->capture.active)
|
||||
if (dai->capture_active)
|
||||
sport_rx_stop(sport_handle);
|
||||
if (dai->playback.active)
|
||||
if (dai->playback_active)
|
||||
sport_tx_stop(sport_handle);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -277,9 +275,7 @@ static struct snd_soc_dai_ops bf5xx_i2s_dai_ops = {
|
|||
.set_fmt = bf5xx_i2s_set_dai_fmt,
|
||||
};
|
||||
|
||||
struct snd_soc_dai bf5xx_i2s_dai = {
|
||||
.name = "bf5xx-i2s",
|
||||
.id = 0,
|
||||
static struct snd_soc_dai_driver bf5xx_i2s_dai = {
|
||||
.probe = bf5xx_i2s_probe,
|
||||
.remove = bf5xx_i2s_remove,
|
||||
.suspend = bf5xx_i2s_suspend,
|
||||
|
|
@ -296,18 +292,39 @@ struct snd_soc_dai bf5xx_i2s_dai = {
|
|||
.formats = BF5XX_I2S_FORMATS,},
|
||||
.ops = &bf5xx_i2s_dai_ops,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(bf5xx_i2s_dai);
|
||||
|
||||
static int bfin_i2s_drv_probe(struct platform_device *pdev)
|
||||
{
|
||||
return snd_soc_register_dai(&pdev->dev, &bf5xx_i2s_dai);
|
||||
}
|
||||
|
||||
static int __devexit bfin_i2s_drv_remove(struct platform_device *pdev)
|
||||
{
|
||||
snd_soc_unregister_dai(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver bfin_i2s_driver = {
|
||||
.probe = bfin_i2s_drv_probe,
|
||||
.remove = __devexit_p(bfin_i2s_drv_remove),
|
||||
|
||||
.driver = {
|
||||
.name = "bf5xx-i2s",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init bfin_i2s_init(void)
|
||||
{
|
||||
return snd_soc_register_dai(&bf5xx_i2s_dai);
|
||||
return platform_driver_register(&bfin_i2s_driver);
|
||||
}
|
||||
module_init(bfin_i2s_init);
|
||||
|
||||
static void __exit bfin_i2s_exit(void)
|
||||
{
|
||||
snd_soc_unregister_dai(&bf5xx_i2s_dai);
|
||||
platform_driver_unregister(&bfin_i2s_driver);
|
||||
}
|
||||
|
||||
module_init(bfin_i2s_init);
|
||||
module_exit(bfin_i2s_exit);
|
||||
|
||||
/* Module information */
|
||||
|
|
|
|||
|
|
@ -1,14 +0,0 @@
|
|||
/*
|
||||
* sound/soc/blackfin/bf5xx-i2s.h
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _BF5XX_I2S_H
|
||||
#define _BF5XX_I2S_H
|
||||
|
||||
extern struct snd_soc_dai bf5xx_i2s_dai;
|
||||
|
||||
#endif
|
||||
|
|
@ -42,17 +42,16 @@
|
|||
#include "../codecs/ssm2602.h"
|
||||
#include "bf5xx-sport.h"
|
||||
#include "bf5xx-i2s-pcm.h"
|
||||
#include "bf5xx-i2s.h"
|
||||
|
||||
static struct snd_soc_card bf5xx_ssm2602;
|
||||
|
||||
static int bf5xx_ssm2602_startup(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
|
||||
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
|
||||
pr_debug("%s enter\n", __func__);
|
||||
cpu_dai->private_data = sport_handle;
|
||||
snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -60,8 +59,8 @@ static int bf5xx_ssm2602_hw_params(struct snd_pcm_substream *substream,
|
|||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
|
||||
struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
unsigned int clk = 0;
|
||||
int ret = 0;
|
||||
|
||||
|
|
@ -118,36 +117,19 @@ static struct snd_soc_ops bf5xx_ssm2602_ops = {
|
|||
static struct snd_soc_dai_link bf5xx_ssm2602_dai = {
|
||||
.name = "ssm2602",
|
||||
.stream_name = "SSM2602",
|
||||
.cpu_dai = &bf5xx_i2s_dai,
|
||||
.codec_dai = &ssm2602_dai,
|
||||
.cpu_dai_name = "bf5xx-i2s",
|
||||
.codec_dai_name = "ssm2602-hifi",
|
||||
.platform_name = "bf5xx-pcm-audio",
|
||||
.codec_name = "ssm2602-codec.0-0x1b",
|
||||
.ops = &bf5xx_ssm2602_ops,
|
||||
};
|
||||
|
||||
/*
|
||||
* SSM2602 2 wire address is determined by CSB
|
||||
* state during powerup.
|
||||
* low = 0x1a
|
||||
* high = 0x1b
|
||||
*/
|
||||
|
||||
static struct ssm2602_setup_data bf5xx_ssm2602_setup = {
|
||||
.i2c_bus = 0,
|
||||
.i2c_address = 0x1b,
|
||||
};
|
||||
|
||||
static struct snd_soc_card bf5xx_ssm2602 = {
|
||||
.name = "bf5xx_ssm2602",
|
||||
.platform = &bf5xx_i2s_soc_platform,
|
||||
.dai_link = &bf5xx_ssm2602_dai,
|
||||
.num_links = 1,
|
||||
};
|
||||
|
||||
static struct snd_soc_device bf5xx_ssm2602_snd_devdata = {
|
||||
.card = &bf5xx_ssm2602,
|
||||
.codec_dev = &soc_codec_dev_ssm2602,
|
||||
.codec_data = &bf5xx_ssm2602_setup,
|
||||
};
|
||||
|
||||
static struct platform_device *bf5xx_ssm2602_snd_device;
|
||||
|
||||
static int __init bf5xx_ssm2602_init(void)
|
||||
|
|
@ -159,9 +141,7 @@ static int __init bf5xx_ssm2602_init(void)
|
|||
if (!bf5xx_ssm2602_snd_device)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(bf5xx_ssm2602_snd_device,
|
||||
&bf5xx_ssm2602_snd_devdata);
|
||||
bf5xx_ssm2602_snd_devdata.dev = &bf5xx_ssm2602_snd_device->dev;
|
||||
platform_set_drvdata(bf5xx_ssm2602_snd_device, &bf5xx_ssm2602);
|
||||
ret = platform_device_add(bf5xx_ssm2602_snd_device);
|
||||
|
||||
if (ret)
|
||||
|
|
|
|||
|
|
@ -290,14 +290,14 @@ static int bf5xx_pcm_tdm_new(struct snd_card *card, struct snd_soc_dai *dai,
|
|||
if (!card->dev->coherent_dma_mask)
|
||||
card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
|
||||
|
||||
if (dai->playback.channels_min) {
|
||||
if (dai->driver->playback.channels_min) {
|
||||
ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
|
||||
SNDRV_PCM_STREAM_PLAYBACK);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (dai->capture.channels_min) {
|
||||
if (dai->driver->capture.channels_min) {
|
||||
ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
|
||||
SNDRV_PCM_STREAM_CAPTURE);
|
||||
if (ret)
|
||||
|
|
@ -307,25 +307,44 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
struct snd_soc_platform bf5xx_tdm_soc_platform = {
|
||||
.name = "bf5xx-audio",
|
||||
.pcm_ops = &bf5xx_pcm_tdm_ops,
|
||||
static struct snd_soc_platform_driver bf5xx_tdm_soc_platform = {
|
||||
.ops = &bf5xx_pcm_tdm_ops,
|
||||
.pcm_new = bf5xx_pcm_tdm_new,
|
||||
.pcm_free = bf5xx_pcm_free_dma_buffers,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(bf5xx_tdm_soc_platform);
|
||||
|
||||
static int __init bfin_pcm_tdm_init(void)
|
||||
static int __devinit bf5xx_soc_platform_probe(struct platform_device *pdev)
|
||||
{
|
||||
return snd_soc_register_platform(&bf5xx_tdm_soc_platform);
|
||||
return snd_soc_register_platform(&pdev->dev, &bf5xx_tdm_soc_platform);
|
||||
}
|
||||
module_init(bfin_pcm_tdm_init);
|
||||
|
||||
static void __exit bfin_pcm_tdm_exit(void)
|
||||
static int __devexit bf5xx_soc_platform_remove(struct platform_device *pdev)
|
||||
{
|
||||
snd_soc_unregister_platform(&bf5xx_tdm_soc_platform);
|
||||
snd_soc_unregister_platform(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
module_exit(bfin_pcm_tdm_exit);
|
||||
|
||||
static struct platform_driver bfin_tdm_driver = {
|
||||
.driver = {
|
||||
.name = "bf5xx-tdm-pcm-audio",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
|
||||
.probe = bf5xx_soc_platform_probe,
|
||||
.remove = __devexit_p(bf5xx_soc_platform_remove),
|
||||
};
|
||||
|
||||
static int __init snd_bfin_tdm_init(void)
|
||||
{
|
||||
return platform_driver_register(&bfin_tdm_driver);
|
||||
}
|
||||
module_init(snd_bfin_tdm_init);
|
||||
|
||||
static void __exit snd_bfin_tdm_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&bfin_tdm_driver);
|
||||
}
|
||||
module_exit(snd_bfin_tdm_exit);
|
||||
|
||||
MODULE_AUTHOR("Barry Song");
|
||||
MODULE_DESCRIPTION("ADI Blackfin TDM PCM DMA module");
|
||||
|
|
|
|||
|
|
@ -15,7 +15,4 @@ struct bf5xx_pcm_dma_params {
|
|||
char *name; /* stream identifier */
|
||||
};
|
||||
|
||||
/* platform data */
|
||||
extern struct snd_soc_platform bf5xx_tdm_soc_platform;
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -214,9 +214,9 @@ static int bf5xx_tdm_suspend(struct snd_soc_dai *dai)
|
|||
|
||||
if (!dai->active)
|
||||
return 0;
|
||||
if (dai->capture.active)
|
||||
if (dai->capture_active)
|
||||
sport_rx_stop(sport);
|
||||
if (dai->playback.active)
|
||||
if (dai->playback_active)
|
||||
sport_tx_stop(sport);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -224,7 +224,7 @@ static int bf5xx_tdm_suspend(struct snd_soc_dai *dai)
|
|||
static int bf5xx_tdm_resume(struct snd_soc_dai *dai)
|
||||
{
|
||||
int ret;
|
||||
struct sport_device *sport = dai->private_data;
|
||||
struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
|
||||
|
||||
if (!dai->active)
|
||||
return 0;
|
||||
|
|
@ -262,9 +262,7 @@ static struct snd_soc_dai_ops bf5xx_tdm_dai_ops = {
|
|||
.set_channel_map = bf5xx_tdm_set_channel_map,
|
||||
};
|
||||
|
||||
struct snd_soc_dai bf5xx_tdm_dai = {
|
||||
.name = "bf5xx-tdm",
|
||||
.id = 0,
|
||||
static struct snd_soc_dai_driver bf5xx_tdm_dai = {
|
||||
.suspend = bf5xx_tdm_suspend,
|
||||
.resume = bf5xx_tdm_resume,
|
||||
.playback = {
|
||||
|
|
@ -279,7 +277,6 @@ struct snd_soc_dai bf5xx_tdm_dai = {
|
|||
.formats = SNDRV_PCM_FMTBIT_S32_LE,},
|
||||
.ops = &bf5xx_tdm_dai_ops,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(bf5xx_tdm_dai);
|
||||
|
||||
static int __devinit bfin_tdm_probe(struct platform_device *pdev)
|
||||
{
|
||||
|
|
@ -320,7 +317,7 @@ static int __devinit bfin_tdm_probe(struct platform_device *pdev)
|
|||
goto sport_config_err;
|
||||
}
|
||||
|
||||
ret = snd_soc_register_dai(&bf5xx_tdm_dai);
|
||||
ret = snd_soc_register_dai(&pdev->dev, &bf5xx_tdm_dai);
|
||||
if (ret) {
|
||||
pr_err("Failed to register DAI: %d\n", ret);
|
||||
goto sport_config_err;
|
||||
|
|
@ -337,7 +334,7 @@ sport_config_err:
|
|||
static int __devexit bfin_tdm_remove(struct platform_device *pdev)
|
||||
{
|
||||
peripheral_free_list(&sport_req[sport_num][0]);
|
||||
snd_soc_unregister_dai(&bf5xx_tdm_dai);
|
||||
snd_soc_unregister_dai(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue