mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-11-17 23:25:46 +08: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: (348 commits) ALSA: hda - Fix NULL-derefence with a single mic in STAC auto-mic detection ALSA: hda - Add missing NID 0x19 fixup for Sony VAIO ALSA: hda - Fix ALC275 enable hardware EQ for SONY VAIO ALSA: oxygen: fix Xonar DG input ALSA: hda - Fix EAPD on Lenovo NB ALC269 to low ALSA: hda - Fix missing EAPD for Acer 4930G ALSA: hda: Disable 4/6 channels on some NVIDIA GPUs. ALSA: hda - Add static_hdmi_pcm option to HDMI codec parser ALSA: hda - Don't refer ELD when unplugged ASoC: tpa6130a2: Fix compiler warning ASoC: tlv320dac33: Add DAPM selection for LOM invert ASoC: DMIC codec: Adding a generic DMIC codec ALSA: snd-usb-us122l: Fix missing NULL checks ALSA: snd-usb-us122l: Fix MIDI output ASoC: soc-cache: Fix invalid memory access during snd_soc_lzo_cache_sync() ASoC: Fix section mismatch in wm8995.c ALSA: oxygen: add S/PDIF source selection for Claro cards ALSA: oxygen: fix CD/MIDI for X-Meridian (2G) ASoC: fix migor audio build ALSA: include delay.h for msleep in Xonar DG support ...
This commit is contained in:
commit
66dc918d42
@ -974,13 +974,6 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
|
||||
|
||||
See hdspm.txt for details.
|
||||
|
||||
Module snd-hifier
|
||||
-----------------
|
||||
|
||||
Module for the MediaTek/TempoTec HiFier Fantasia sound card.
|
||||
|
||||
This module supports autoprobe and multiple cards.
|
||||
|
||||
Module snd-ice1712
|
||||
------------------
|
||||
|
||||
@ -1531,15 +1524,20 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
|
||||
Module snd-oxygen
|
||||
-----------------
|
||||
|
||||
Module for sound cards based on the C-Media CMI8788 chip:
|
||||
Module for sound cards based on the C-Media CMI8786/8787/8788 chip:
|
||||
* Asound A-8788
|
||||
* Asus Xonar DG
|
||||
* AuzenTech X-Meridian
|
||||
* AuzenTech X-Meridian 2G
|
||||
* Bgears b-Enspirer
|
||||
* Club3D Theatron DTS
|
||||
* HT-Omega Claro (plus)
|
||||
* HT-Omega Claro halo (XT)
|
||||
* Kuroutoshikou CMI8787-HG2PCI
|
||||
* Razer Barracuda AC-1
|
||||
* Sondigo Inferno
|
||||
* TempoTec HiFier Fantasia
|
||||
* TempoTec HiFier Serenade
|
||||
|
||||
This module supports autoprobe and multiple cards.
|
||||
|
||||
@ -2006,9 +2004,9 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
|
||||
Module snd-virtuoso
|
||||
-------------------
|
||||
|
||||
Module for sound cards based on the Asus AV100/AV200 chips,
|
||||
i.e., Xonar D1, DX, D2, D2X, DS, HDAV1.3 (Deluxe), Essence ST
|
||||
(Deluxe) and Essence STX.
|
||||
Module for sound cards based on the Asus AV66/AV100/AV200 chips,
|
||||
i.e., Xonar D1, DX, D2, D2X, DS, Essence ST (Deluxe), Essence STX,
|
||||
HDAV1.3 (Deluxe), and HDAV1.3 Slim.
|
||||
|
||||
This module supports autoprobe and multiple cards.
|
||||
|
||||
|
@ -149,7 +149,6 @@ ALC882/883/885/888/889
|
||||
acer-aspire-7730g Acer Aspire 7730G
|
||||
acer-aspire-8930g Acer Aspire 8930G
|
||||
medion Medion Laptops
|
||||
medion-md2 Medion MD2
|
||||
targa-dig Targa/MSI
|
||||
targa-2ch-dig Targa/MSI with 2-channel
|
||||
targa-8ch-dig Targa/MSI with 8-channel (MSI GX620)
|
||||
|
45
MAINTAINERS
45
MAINTAINERS
@ -1523,6 +1523,14 @@ S: Supported
|
||||
F: block/bsg.c
|
||||
F: include/linux/bsg.h
|
||||
|
||||
BT87X AUDIO DRIVER
|
||||
M: Clemens Ladisch <clemens@ladisch.de>
|
||||
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
|
||||
T: git git://git.alsa-project.org/alsa-kernel.git
|
||||
S: Maintained
|
||||
F: Documentation/sound/alsa/Bt87x.txt
|
||||
F: sound/pci/bt87x.c
|
||||
|
||||
BT8XXGPIO DRIVER
|
||||
M: Michael Buesch <mb@bu3sch.de>
|
||||
W: http://bu3sch.de/btgpio.php
|
||||
@ -1548,6 +1556,13 @@ S: Maintained
|
||||
F: Documentation/video4linux/bttv/
|
||||
F: drivers/media/video/bt8xx/bttv*
|
||||
|
||||
C-MEDIA CMI8788 DRIVER
|
||||
M: Clemens Ladisch <clemens@ladisch.de>
|
||||
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
|
||||
T: git git://git.alsa-project.org/alsa-kernel.git
|
||||
S: Maintained
|
||||
F: sound/pci/oxygen/
|
||||
|
||||
CACHEFILES: FS-CACHE BACKEND FOR CACHING ON MOUNTED FILESYSTEMS
|
||||
M: David Howells <dhowells@redhat.com>
|
||||
L: linux-cachefs@redhat.com
|
||||
@ -2339,6 +2354,13 @@ W: bluesmoke.sourceforge.net
|
||||
S: Maintained
|
||||
F: drivers/edac/r82600_edac.c
|
||||
|
||||
EDIROL UA-101/UA-1000 DRIVER
|
||||
M: Clemens Ladisch <clemens@ladisch.de>
|
||||
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
|
||||
T: git git://git.alsa-project.org/alsa-kernel.git
|
||||
S: Maintained
|
||||
F: sound/usb/misc/ua101.c
|
||||
|
||||
EEEPC LAPTOP EXTRAS DRIVER
|
||||
M: Corentin Chary <corentincj@iksaif.net>
|
||||
L: acpi4asus-user@lists.sourceforge.net
|
||||
@ -3507,6 +3529,13 @@ L: linux-serial@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/serial/jsm/
|
||||
|
||||
K10TEMP HARDWARE MONITORING DRIVER
|
||||
M: Clemens Ladisch <clemens@ladisch.de>
|
||||
L: lm-sensors@lm-sensors.org
|
||||
S: Maintained
|
||||
F: Documentation/hwmon/k10temp
|
||||
F: drivers/hwmon/k10temp.c
|
||||
|
||||
K8TEMP HARDWARE MONITORING DRIVER
|
||||
M: Rudolf Marek <r.marek@assembler.cz>
|
||||
L: lm-sensors@lm-sensors.org
|
||||
@ -4537,6 +4566,13 @@ F: drivers/of
|
||||
F: include/linux/of*.h
|
||||
K: of_get_property
|
||||
|
||||
OPL4 DRIVER
|
||||
M: Clemens Ladisch <clemens@ladisch.de>
|
||||
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
|
||||
T: git git://git.alsa-project.org/alsa-kernel.git
|
||||
S: Maintained
|
||||
F: sound/drivers/opl4/
|
||||
|
||||
OPROFILE
|
||||
M: Robert Richter <robert.richter@amd.com>
|
||||
L: oprofile-list@lists.sf.net
|
||||
@ -5283,7 +5319,7 @@ SAMSUNG AUDIO (ASoC) DRIVERS
|
||||
M: Jassi Brar <jassi.brar@samsung.com>
|
||||
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
|
||||
S: Supported
|
||||
F: sound/soc/s3c24xx
|
||||
F: sound/soc/samsung
|
||||
|
||||
TIMEKEEPING, NTP
|
||||
M: John Stultz <johnstul@us.ibm.com>
|
||||
@ -6291,6 +6327,13 @@ S: Maintained
|
||||
W: http://www.one-eyed-alien.net/~mdharm/linux-usb/
|
||||
F: drivers/usb/storage/
|
||||
|
||||
USB MIDI DRIVER
|
||||
M: Clemens Ladisch <clemens@ladisch.de>
|
||||
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
|
||||
T: git git://git.alsa-project.org/alsa-kernel.git
|
||||
S: Maintained
|
||||
F: sound/usb/midi.*
|
||||
|
||||
USB OHCI DRIVER
|
||||
M: David Brownell <dbrownell@users.sourceforge.net>
|
||||
L: linux-usb@vger.kernel.org
|
||||
|
@ -171,7 +171,7 @@ static void __init openrd_init(void)
|
||||
|
||||
kirkwood_i2c_init();
|
||||
|
||||
if (machine_is_openrd_client()) {
|
||||
if (machine_is_openrd_client() || machine_is_openrd_ultimate()) {
|
||||
i2c_register_board_info(0, i2c_board_info,
|
||||
ARRAY_SIZE(i2c_board_info));
|
||||
kirkwood_audio_init();
|
||||
|
@ -387,7 +387,7 @@ static struct platform_device *h1940_devices[] __initdata = {
|
||||
&s3c_device_wdt,
|
||||
&s3c_device_i2c0,
|
||||
&s3c_device_iis,
|
||||
&s3c_device_pcm,
|
||||
&samsung_asoc_dma,
|
||||
&s3c_device_usbgadget,
|
||||
&h1940_device_leds,
|
||||
&h1940_device_bluetooth,
|
||||
|
@ -692,7 +692,7 @@ static struct platform_device *rx1950_devices[] __initdata = {
|
||||
&s3c_device_wdt,
|
||||
&s3c_device_i2c0,
|
||||
&s3c_device_iis,
|
||||
&s3c_device_pcm,
|
||||
&samsung_asoc_dma,
|
||||
&s3c_device_usbgadget,
|
||||
&s3c_device_rtc,
|
||||
&s3c_device_nand,
|
||||
|
@ -695,7 +695,7 @@ static struct clksrc_clk clksrcs[] = {
|
||||
}, {
|
||||
.clk = {
|
||||
.name = "audio-bus",
|
||||
.id = -1, /* There's only one IISv4 port */
|
||||
.id = 2,
|
||||
.ctrlbit = S3C6410_CLKCON_SCLK_AUDIO2,
|
||||
.enable = s3c64xx_sclk_ctrl,
|
||||
},
|
||||
|
@ -22,7 +22,12 @@
|
||||
#include <plat/audio.h>
|
||||
#include <plat/gpio-cfg.h>
|
||||
|
||||
static int s3c64xx_i2sv3_cfg_gpio(struct platform_device *pdev)
|
||||
static const char *rclksrc[] = {
|
||||
[0] = "iis",
|
||||
[1] = "audio-bus",
|
||||
};
|
||||
|
||||
static int s3c64xx_i2s_cfg_gpio(struct platform_device *pdev)
|
||||
{
|
||||
unsigned int base;
|
||||
|
||||
@ -33,6 +38,12 @@ static int s3c64xx_i2sv3_cfg_gpio(struct platform_device *pdev)
|
||||
case 1:
|
||||
base = S3C64XX_GPE(0);
|
||||
break;
|
||||
case 2:
|
||||
s3c_gpio_cfgpin(S3C64XX_GPC(4), S3C_GPIO_SFN(5));
|
||||
s3c_gpio_cfgpin(S3C64XX_GPC(5), S3C_GPIO_SFN(5));
|
||||
s3c_gpio_cfgpin(S3C64XX_GPC(7), S3C_GPIO_SFN(5));
|
||||
s3c_gpio_cfgpin_range(S3C64XX_GPH(6), 4, S3C_GPIO_SFN(5));
|
||||
return 0;
|
||||
default:
|
||||
printk(KERN_DEBUG "Invalid I2S Controller number: %d\n",
|
||||
pdev->id);
|
||||
@ -44,16 +55,6 @@ static int s3c64xx_i2sv3_cfg_gpio(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int s3c64xx_i2sv4_cfg_gpio(struct platform_device *pdev)
|
||||
{
|
||||
s3c_gpio_cfgpin(S3C64XX_GPC(4), S3C_GPIO_SFN(5));
|
||||
s3c_gpio_cfgpin(S3C64XX_GPC(5), S3C_GPIO_SFN(5));
|
||||
s3c_gpio_cfgpin(S3C64XX_GPC(7), S3C_GPIO_SFN(5));
|
||||
s3c_gpio_cfgpin_range(S3C64XX_GPH(6), 4, S3C_GPIO_SFN(5));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct resource s3c64xx_iis0_resource[] = {
|
||||
[0] = {
|
||||
.start = S3C64XX_PA_IIS0,
|
||||
@ -72,17 +73,22 @@ static struct resource s3c64xx_iis0_resource[] = {
|
||||
},
|
||||
};
|
||||
|
||||
static struct s3c_audio_pdata s3c_i2s0_pdata = {
|
||||
.cfg_gpio = s3c64xx_i2sv3_cfg_gpio,
|
||||
static struct s3c_audio_pdata i2sv3_pdata = {
|
||||
.cfg_gpio = s3c64xx_i2s_cfg_gpio,
|
||||
.type = {
|
||||
.i2s = {
|
||||
.src_clk = rclksrc,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
struct platform_device s3c64xx_device_iis0 = {
|
||||
.name = "s3c64xx-iis",
|
||||
.name = "samsung-i2s",
|
||||
.id = 0,
|
||||
.num_resources = ARRAY_SIZE(s3c64xx_iis0_resource),
|
||||
.resource = s3c64xx_iis0_resource,
|
||||
.dev = {
|
||||
.platform_data = &s3c_i2s0_pdata,
|
||||
.platform_data = &i2sv3_pdata,
|
||||
},
|
||||
};
|
||||
EXPORT_SYMBOL(s3c64xx_device_iis0);
|
||||
@ -105,17 +111,13 @@ static struct resource s3c64xx_iis1_resource[] = {
|
||||
},
|
||||
};
|
||||
|
||||
static struct s3c_audio_pdata s3c_i2s1_pdata = {
|
||||
.cfg_gpio = s3c64xx_i2sv3_cfg_gpio,
|
||||
};
|
||||
|
||||
struct platform_device s3c64xx_device_iis1 = {
|
||||
.name = "s3c64xx-iis",
|
||||
.name = "samsung-i2s",
|
||||
.id = 1,
|
||||
.num_resources = ARRAY_SIZE(s3c64xx_iis1_resource),
|
||||
.resource = s3c64xx_iis1_resource,
|
||||
.dev = {
|
||||
.platform_data = &s3c_i2s1_pdata,
|
||||
.platform_data = &i2sv3_pdata,
|
||||
},
|
||||
};
|
||||
EXPORT_SYMBOL(s3c64xx_device_iis1);
|
||||
@ -138,17 +140,23 @@ static struct resource s3c64xx_iisv4_resource[] = {
|
||||
},
|
||||
};
|
||||
|
||||
static struct s3c_audio_pdata s3c_i2sv4_pdata = {
|
||||
.cfg_gpio = s3c64xx_i2sv4_cfg_gpio,
|
||||
static struct s3c_audio_pdata i2sv4_pdata = {
|
||||
.cfg_gpio = s3c64xx_i2s_cfg_gpio,
|
||||
.type = {
|
||||
.i2s = {
|
||||
.quirks = QUIRK_PRI_6CHAN,
|
||||
.src_clk = rclksrc,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
struct platform_device s3c64xx_device_iisv4 = {
|
||||
.name = "s3c64xx-iis-v4",
|
||||
.id = -1,
|
||||
.name = "samsung-i2s",
|
||||
.id = 2,
|
||||
.num_resources = ARRAY_SIZE(s3c64xx_iisv4_resource),
|
||||
.resource = s3c64xx_iisv4_resource,
|
||||
.dev = {
|
||||
.platform_data = &s3c_i2sv4_pdata,
|
||||
.platform_data = &i2sv4_pdata,
|
||||
},
|
||||
};
|
||||
EXPORT_SYMBOL(s3c64xx_device_iisv4);
|
||||
@ -288,7 +296,7 @@ static struct s3c_audio_pdata s3c_ac97_pdata;
|
||||
static u64 s3c64xx_ac97_dmamask = DMA_BIT_MASK(32);
|
||||
|
||||
struct platform_device s3c64xx_device_ac97 = {
|
||||
.name = "s3c-ac97",
|
||||
.name = "samsung-ac97",
|
||||
.id = -1,
|
||||
.num_resources = ARRAY_SIZE(s3c64xx_ac97_resource),
|
||||
.resource = s3c64xx_ac97_resource,
|
||||
@ -307,16 +315,3 @@ void __init s3c64xx_ac97_setup_gpio(int num)
|
||||
else
|
||||
s3c_ac97_pdata.cfg_gpio = s3c64xx_ac97_cfg_gpe;
|
||||
}
|
||||
|
||||
static u64 s3c_device_audio_dmamask = 0xffffffffUL;
|
||||
|
||||
struct platform_device s3c_device_pcm = {
|
||||
.name = "s3c24xx-pcm-audio",
|
||||
.id = -1,
|
||||
.dev = {
|
||||
.dma_mask = &s3c_device_audio_dmamask,
|
||||
.coherent_dma_mask = 0xffffffffUL
|
||||
}
|
||||
};
|
||||
EXPORT_SYMBOL(s3c_device_pcm);
|
||||
|
||||
|
@ -283,7 +283,7 @@ static struct platform_device *smdk6410_devices[] __initdata = {
|
||||
&s3c_device_fb,
|
||||
&s3c_device_ohci,
|
||||
&s3c_device_usb_hsotg,
|
||||
&s3c_device_pcm,
|
||||
&samsung_asoc_dma,
|
||||
&s3c64xx_device_iisv4,
|
||||
&samsung_device_keypad,
|
||||
|
||||
|
@ -29,7 +29,7 @@ static int s5p6442_cfg_i2s(struct platform_device *pdev)
|
||||
base = S5P6442_GPC1(0);
|
||||
break;
|
||||
|
||||
case -1:
|
||||
case 0:
|
||||
base = S5P6442_GPC0(0);
|
||||
break;
|
||||
|
||||
@ -42,8 +42,19 @@ static int s5p6442_cfg_i2s(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct s3c_audio_pdata s3c_i2s_pdata = {
|
||||
static const char *rclksrc_v35[] = {
|
||||
[0] = "busclk",
|
||||
[1] = "i2sclk",
|
||||
};
|
||||
|
||||
static struct s3c_audio_pdata i2sv35_pdata = {
|
||||
.cfg_gpio = s5p6442_cfg_i2s,
|
||||
.type = {
|
||||
.i2s = {
|
||||
.quirks = QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR,
|
||||
.src_clk = rclksrc_v35,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static struct resource s5p6442_iis0_resource[] = {
|
||||
@ -62,15 +73,34 @@ static struct resource s5p6442_iis0_resource[] = {
|
||||
.end = DMACH_I2S0_RX,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
[3] = {
|
||||
.start = DMACH_I2S0S_TX,
|
||||
.end = DMACH_I2S0S_TX,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
};
|
||||
|
||||
struct platform_device s5p6442_device_iis0 = {
|
||||
.name = "s3c64xx-iis-v4",
|
||||
.id = -1,
|
||||
.name = "samsung-i2s",
|
||||
.id = 0,
|
||||
.num_resources = ARRAY_SIZE(s5p6442_iis0_resource),
|
||||
.resource = s5p6442_iis0_resource,
|
||||
.dev = {
|
||||
.platform_data = &s3c_i2s_pdata,
|
||||
.platform_data = &i2sv35_pdata,
|
||||
},
|
||||
};
|
||||
|
||||
static const char *rclksrc_v3[] = {
|
||||
[0] = "iis",
|
||||
[1] = "sclk_audio",
|
||||
};
|
||||
|
||||
static struct s3c_audio_pdata i2sv3_pdata = {
|
||||
.cfg_gpio = s5p6442_cfg_i2s,
|
||||
.type = {
|
||||
.i2s = {
|
||||
.src_clk = rclksrc_v3,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@ -93,12 +123,12 @@ static struct resource s5p6442_iis1_resource[] = {
|
||||
};
|
||||
|
||||
struct platform_device s5p6442_device_iis1 = {
|
||||
.name = "s3c64xx-iis",
|
||||
.name = "samsung-i2s",
|
||||
.id = 1,
|
||||
.num_resources = ARRAY_SIZE(s5p6442_iis1_resource),
|
||||
.resource = s5p6442_iis1_resource,
|
||||
.dev = {
|
||||
.platform_data = &s3c_i2s_pdata,
|
||||
.platform_data = &i2sv3_pdata,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -261,7 +261,7 @@ static struct clk init_clocks_disable[] = {
|
||||
.enable = s5p64x0_pclk_ctrl,
|
||||
.ctrlbit = (1 << 25),
|
||||
}, {
|
||||
.name = "i2s_v40",
|
||||
.name = "iis",
|
||||
.id = 0,
|
||||
.parent = &clk_pclk_low.clk,
|
||||
.enable = s5p64x0_pclk_ctrl,
|
||||
|
@ -256,7 +256,7 @@ static struct clk init_clocks_disable[] = {
|
||||
.ctrlbit = (1 << 22),
|
||||
}, {
|
||||
.name = "iis",
|
||||
.id = -1,
|
||||
.id = 0,
|
||||
.parent = &clk_pclk_low.clk,
|
||||
.enable = s5p64x0_pclk_ctrl,
|
||||
.ctrlbit = (1 << 26),
|
||||
|
@ -19,15 +19,19 @@
|
||||
#include <mach/dma.h>
|
||||
#include <mach/irqs.h>
|
||||
|
||||
static int s5p6440_cfg_i2s(struct platform_device *pdev)
|
||||
static const char *rclksrc[] = {
|
||||
[0] = "iis",
|
||||
[1] = "sclk_audio2",
|
||||
};
|
||||
|
||||
static int s5p64x0_cfg_i2s(struct platform_device *pdev)
|
||||
{
|
||||
/* configure GPIO for i2s port */
|
||||
switch (pdev->id) {
|
||||
case -1:
|
||||
case 0:
|
||||
s3c_gpio_cfgpin_range(S5P6440_GPR(4), 5, S3C_GPIO_SFN(5));
|
||||
s3c_gpio_cfgpin_range(S5P6440_GPR(13), 2, S3C_GPIO_SFN(5));
|
||||
break;
|
||||
|
||||
default:
|
||||
printk(KERN_ERR "Invalid Device %d\n", pdev->id);
|
||||
return -EINVAL;
|
||||
@ -36,31 +40,14 @@ static int s5p6440_cfg_i2s(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int s5p6450_cfg_i2s(struct platform_device *pdev)
|
||||
{
|
||||
/* configure GPIO for i2s port */
|
||||
switch (pdev->id) {
|
||||
case -1:
|
||||
s3c_gpio_cfgpin(S5P6450_GPB(4), S3C_GPIO_SFN(5));
|
||||
s3c_gpio_cfgpin_range(S5P6450_GPR(4), 5, S3C_GPIO_SFN(5));
|
||||
s3c_gpio_cfgpin_range(S5P6450_GPR(13), 2, S3C_GPIO_SFN(5));
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
printk(KERN_ERR "Invalid Device %d\n", pdev->id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct s3c_audio_pdata s5p6440_i2s_pdata = {
|
||||
.cfg_gpio = s5p6440_cfg_i2s,
|
||||
};
|
||||
|
||||
static struct s3c_audio_pdata s5p6450_i2s_pdata = {
|
||||
.cfg_gpio = s5p6450_cfg_i2s,
|
||||
static struct s3c_audio_pdata s5p64x0_i2s_pdata = {
|
||||
.cfg_gpio = s5p64x0_cfg_i2s,
|
||||
.type = {
|
||||
.i2s = {
|
||||
.quirks = QUIRK_PRI_6CHAN,
|
||||
.src_clk = rclksrc,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static struct resource s5p64x0_iis0_resource[] = {
|
||||
@ -82,22 +69,22 @@ static struct resource s5p64x0_iis0_resource[] = {
|
||||
};
|
||||
|
||||
struct platform_device s5p6440_device_iis = {
|
||||
.name = "s3c64xx-iis-v4",
|
||||
.id = -1,
|
||||
.name = "samsung-i2s",
|
||||
.id = 0,
|
||||
.num_resources = ARRAY_SIZE(s5p64x0_iis0_resource),
|
||||
.resource = s5p64x0_iis0_resource,
|
||||
.dev = {
|
||||
.platform_data = &s5p6440_i2s_pdata,
|
||||
.platform_data = &s5p64x0_i2s_pdata,
|
||||
},
|
||||
};
|
||||
|
||||
struct platform_device s5p6450_device_iis0 = {
|
||||
.name = "s3c64xx-iis-v4",
|
||||
.id = -1,
|
||||
.name = "samsung-i2s",
|
||||
.id = 0,
|
||||
.num_resources = ARRAY_SIZE(s5p64x0_iis0_resource),
|
||||
.resource = s5p64x0_iis0_resource,
|
||||
.dev = {
|
||||
.platform_data = &s5p6450_i2s_pdata,
|
||||
.platform_data = &s5p64x0_i2s_pdata,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -23,17 +23,14 @@ static int s5pc100_cfg_i2s(struct platform_device *pdev)
|
||||
{
|
||||
/* configure GPIO for i2s port */
|
||||
switch (pdev->id) {
|
||||
case 0: /* Dedicated pins */
|
||||
break;
|
||||
case 1:
|
||||
s3c_gpio_cfgpin_range(S5PC100_GPC(0), 5, S3C_GPIO_SFN(2));
|
||||
break;
|
||||
|
||||
case 2:
|
||||
s3c_gpio_cfgpin_range(S5PC100_GPG3(0), 5, S3C_GPIO_SFN(4));
|
||||
break;
|
||||
|
||||
case -1: /* Dedicated pins */
|
||||
break;
|
||||
|
||||
default:
|
||||
printk(KERN_ERR "Invalid Device %d\n", pdev->id);
|
||||
return -EINVAL;
|
||||
@ -42,8 +39,20 @@ static int s5pc100_cfg_i2s(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct s3c_audio_pdata s3c_i2s_pdata = {
|
||||
static const char *rclksrc_v5[] = {
|
||||
[0] = "iis",
|
||||
[1] = "i2sclkd2",
|
||||
};
|
||||
|
||||
static struct s3c_audio_pdata i2sv5_pdata = {
|
||||
.cfg_gpio = s5pc100_cfg_i2s,
|
||||
.type = {
|
||||
.i2s = {
|
||||
.quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI
|
||||
| QUIRK_NEED_RSTCLR,
|
||||
.src_clk = rclksrc_v5,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static struct resource s5pc100_iis0_resource[] = {
|
||||
@ -62,15 +71,34 @@ static struct resource s5pc100_iis0_resource[] = {
|
||||
.end = DMACH_I2S0_RX,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
[3] = {
|
||||
.start = DMACH_I2S0S_TX,
|
||||
.end = DMACH_I2S0S_TX,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
};
|
||||
|
||||
struct platform_device s5pc100_device_iis0 = {
|
||||
.name = "s3c64xx-iis-v4",
|
||||
.id = -1,
|
||||
.name = "samsung-i2s",
|
||||
.id = 0,
|
||||
.num_resources = ARRAY_SIZE(s5pc100_iis0_resource),
|
||||
.resource = s5pc100_iis0_resource,
|
||||
.dev = {
|
||||
.platform_data = &s3c_i2s_pdata,
|
||||
.platform_data = &i2sv5_pdata,
|
||||
},
|
||||
};
|
||||
|
||||
static const char *rclksrc_v3[] = {
|
||||
[0] = "iis",
|
||||
[1] = "sclk_audio",
|
||||
};
|
||||
|
||||
static struct s3c_audio_pdata i2sv3_pdata = {
|
||||
.cfg_gpio = s5pc100_cfg_i2s,
|
||||
.type = {
|
||||
.i2s = {
|
||||
.src_clk = rclksrc_v3,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@ -93,12 +121,12 @@ static struct resource s5pc100_iis1_resource[] = {
|
||||
};
|
||||
|
||||
struct platform_device s5pc100_device_iis1 = {
|
||||
.name = "s3c64xx-iis",
|
||||
.name = "samsung-i2s",
|
||||
.id = 1,
|
||||
.num_resources = ARRAY_SIZE(s5pc100_iis1_resource),
|
||||
.resource = s5pc100_iis1_resource,
|
||||
.dev = {
|
||||
.platform_data = &s3c_i2s_pdata,
|
||||
.platform_data = &i2sv3_pdata,
|
||||
},
|
||||
};
|
||||
|
||||
@ -121,12 +149,12 @@ static struct resource s5pc100_iis2_resource[] = {
|
||||
};
|
||||
|
||||
struct platform_device s5pc100_device_iis2 = {
|
||||
.name = "s3c64xx-iis",
|
||||
.name = "samsung-i2s",
|
||||
.id = 2,
|
||||
.num_resources = ARRAY_SIZE(s5pc100_iis2_resource),
|
||||
.resource = s5pc100_iis2_resource,
|
||||
.dev = {
|
||||
.platform_data = &s3c_i2s_pdata,
|
||||
.platform_data = &i2sv3_pdata,
|
||||
},
|
||||
};
|
||||
|
||||
@ -253,7 +281,7 @@ static struct s3c_audio_pdata s3c_ac97_pdata = {
|
||||
static u64 s5pc100_ac97_dmamask = DMA_BIT_MASK(32);
|
||||
|
||||
struct platform_device s5pc100_device_ac97 = {
|
||||
.name = "s3c-ac97",
|
||||
.name = "samsung-ac97",
|
||||
.id = -1,
|
||||
.num_resources = ARRAY_SIZE(s5pc100_ac97_resource),
|
||||
.resource = s5pc100_ac97_resource,
|
||||
|
@ -96,6 +96,7 @@ static struct s3c2410_uartcfg smdkc100_uartcfgs[] __initdata = {
|
||||
|
||||
/* I2C0 */
|
||||
static struct i2c_board_info i2c_devs0[] __initdata = {
|
||||
{I2C_BOARD_INFO("wm8580", 0x1b),},
|
||||
};
|
||||
|
||||
/* I2C1 */
|
||||
@ -190,6 +191,7 @@ static struct platform_device *smdkc100_devices[] __initdata = {
|
||||
&s3c_device_ts,
|
||||
&s3c_device_wdt,
|
||||
&smdkc100_lcd_powerdev,
|
||||
&samsung_asoc_dma,
|
||||
&s5pc100_device_iis0,
|
||||
&samsung_device_keypad,
|
||||
&s5pc100_device_ac97,
|
||||
|
@ -467,20 +467,20 @@ static struct clk init_clocks_disable[] = {
|
||||
.enable = s5pv210_clk_ip3_ctrl,
|
||||
.ctrlbit = (1<<21),
|
||||
}, {
|
||||
.name = "i2s_v50",
|
||||
.name = "iis",
|
||||
.id = 0,
|
||||
.parent = &clk_p,
|
||||
.enable = s5pv210_clk_ip3_ctrl,
|
||||
.ctrlbit = (1<<4),
|
||||
}, {
|
||||
.name = "i2s_v32",
|
||||
.id = 0,
|
||||
.name = "iis",
|
||||
.id = 1,
|
||||
.parent = &clk_p,
|
||||
.enable = s5pv210_clk_ip3_ctrl,
|
||||
.ctrlbit = (1 << 5),
|
||||
}, {
|
||||
.name = "i2s_v32",
|
||||
.id = 1,
|
||||
.name = "iis",
|
||||
.id = 2,
|
||||
.parent = &clk_p,
|
||||
.enable = s5pv210_clk_ip3_ctrl,
|
||||
.ctrlbit = (1 << 6),
|
||||
|
@ -19,22 +19,24 @@
|
||||
#include <mach/dma.h>
|
||||
#include <mach/irqs.h>
|
||||
|
||||
static const char *rclksrc[] = {
|
||||
[0] = "busclk",
|
||||
[1] = "i2sclk",
|
||||
};
|
||||
|
||||
static int s5pv210_cfg_i2s(struct platform_device *pdev)
|
||||
{
|
||||
/* configure GPIO for i2s port */
|
||||
switch (pdev->id) {
|
||||
case 0:
|
||||
s3c_gpio_cfgpin_range(S5PV210_GPI(0), 7, S3C_GPIO_SFN(2));
|
||||
break;
|
||||
case 1:
|
||||
s3c_gpio_cfgpin_range(S5PV210_GPC0(0), 5, S3C_GPIO_SFN(2));
|
||||
break;
|
||||
|
||||
case 2:
|
||||
s3c_gpio_cfgpin_range(S5PV210_GPC1(0), 5, S3C_GPIO_SFN(4));
|
||||
break;
|
||||
|
||||
case -1:
|
||||
s3c_gpio_cfgpin_range(S5PV210_GPI(0), 7, S3C_GPIO_SFN(2));
|
||||
break;
|
||||
|
||||
default:
|
||||
printk(KERN_ERR "Invalid Device %d\n", pdev->id);
|
||||
return -EINVAL;
|
||||
@ -43,8 +45,15 @@ static int s5pv210_cfg_i2s(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct s3c_audio_pdata s3c_i2s_pdata = {
|
||||
static struct s3c_audio_pdata i2sv5_pdata = {
|
||||
.cfg_gpio = s5pv210_cfg_i2s,
|
||||
.type = {
|
||||
.i2s = {
|
||||
.quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI
|
||||
| QUIRK_NEED_RSTCLR,
|
||||
.src_clk = rclksrc,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static struct resource s5pv210_iis0_resource[] = {
|
||||
@ -63,15 +72,34 @@ static struct resource s5pv210_iis0_resource[] = {
|
||||
.end = DMACH_I2S0_RX,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
[3] = {
|
||||
.start = DMACH_I2S0S_TX,
|
||||
.end = DMACH_I2S0S_TX,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
};
|
||||
|
||||
struct platform_device s5pv210_device_iis0 = {
|
||||
.name = "s3c64xx-iis-v4",
|
||||
.id = -1,
|
||||
.name = "samsung-i2s",
|
||||
.id = 0,
|
||||
.num_resources = ARRAY_SIZE(s5pv210_iis0_resource),
|
||||
.resource = s5pv210_iis0_resource,
|
||||
.dev = {
|
||||
.platform_data = &s3c_i2s_pdata,
|
||||
.platform_data = &i2sv5_pdata,
|
||||
},
|
||||
};
|
||||
|
||||
static const char *rclksrc_v3[] = {
|
||||
[0] = "iis",
|
||||
[1] = "audio-bus",
|
||||
};
|
||||
|
||||
static struct s3c_audio_pdata i2sv3_pdata = {
|
||||
.cfg_gpio = s5pv210_cfg_i2s,
|
||||
.type = {
|
||||
.i2s = {
|
||||
.src_clk = rclksrc_v3,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@ -94,12 +122,12 @@ static struct resource s5pv210_iis1_resource[] = {
|
||||
};
|
||||
|
||||
struct platform_device s5pv210_device_iis1 = {
|
||||
.name = "s3c64xx-iis",
|
||||
.name = "samsung-i2s",
|
||||
.id = 1,
|
||||
.num_resources = ARRAY_SIZE(s5pv210_iis1_resource),
|
||||
.resource = s5pv210_iis1_resource,
|
||||
.dev = {
|
||||
.platform_data = &s3c_i2s_pdata,
|
||||
.platform_data = &i2sv3_pdata,
|
||||
},
|
||||
};
|
||||
|
||||
@ -122,12 +150,12 @@ static struct resource s5pv210_iis2_resource[] = {
|
||||
};
|
||||
|
||||
struct platform_device s5pv210_device_iis2 = {
|
||||
.name = "s3c64xx-iis",
|
||||
.name = "samsung-i2s",
|
||||
.id = 2,
|
||||
.num_resources = ARRAY_SIZE(s5pv210_iis2_resource),
|
||||
.resource = s5pv210_iis2_resource,
|
||||
.dev = {
|
||||
.platform_data = &s3c_i2s_pdata,
|
||||
.platform_data = &i2sv3_pdata,
|
||||
},
|
||||
};
|
||||
|
||||
@ -283,7 +311,7 @@ static struct s3c_audio_pdata s3c_ac97_pdata = {
|
||||
static u64 s5pv210_ac97_dmamask = DMA_BIT_MASK(32);
|
||||
|
||||
struct platform_device s5pv210_device_ac97 = {
|
||||
.name = "s3c-ac97",
|
||||
.name = "samsung-ac97",
|
||||
.id = -1,
|
||||
.num_resources = ARRAY_SIZE(s5pv210_ac97_resource),
|
||||
.resource = s5pv210_ac97_resource,
|
||||
|
@ -11,6 +11,7 @@ if ARCH_S5PV310
|
||||
|
||||
config CPU_S5PV310
|
||||
bool
|
||||
select S3C_PL330_DMA
|
||||
help
|
||||
Enable S5PV310 CPU support
|
||||
|
||||
|
@ -13,7 +13,7 @@ obj- :=
|
||||
# Core support for S5PV310 system
|
||||
|
||||
obj-$(CONFIG_CPU_S5PV310) += cpu.o init.o clock.o irq-combiner.o
|
||||
obj-$(CONFIG_CPU_S5PV310) += setup-i2c0.o time.o gpiolib.o irq-eint.o
|
||||
obj-$(CONFIG_CPU_S5PV310) += setup-i2c0.o time.o gpiolib.o irq-eint.o dma.o
|
||||
|
||||
obj-$(CONFIG_SMP) += platsmp.o headsmp.o
|
||||
obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o
|
||||
@ -27,6 +27,7 @@ obj-$(CONFIG_MACH_UNIVERSAL_C210) += mach-universal_c210.o
|
||||
|
||||
# device support
|
||||
|
||||
obj-y += dev-audio.o
|
||||
obj-$(CONFIG_S5PV310_SETUP_I2C1) += setup-i2c1.o
|
||||
obj-$(CONFIG_S5PV310_SETUP_I2C2) += setup-i2c2.o
|
||||
obj-$(CONFIG_S5PV310_SETUP_I2C3) += setup-i2c3.o
|
||||
|
364
arch/arm/mach-s5pv310/dev-audio.c
Normal file
364
arch/arm/mach-s5pv310/dev-audio.c
Normal file
@ -0,0 +1,364 @@
|
||||
/* linux/arch/arm/mach-s5pv310/dev-audio.c
|
||||
*
|
||||
* Copyright (c) 2010 Samsung Electronics Co. Ltd
|
||||
* Jaswinder Singh <jassi.brar@samsung.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include <plat/gpio-cfg.h>
|
||||
#include <plat/audio.h>
|
||||
|
||||
#include <mach/map.h>
|
||||
#include <mach/dma.h>
|
||||
#include <mach/irqs.h>
|
||||
|
||||
static const char *rclksrc[] = {
|
||||
[0] = "busclk",
|
||||
[1] = "i2sclk",
|
||||
};
|
||||
|
||||
static int s5pv310_cfg_i2s(struct platform_device *pdev)
|
||||
{
|
||||
/* configure GPIO for i2s port */
|
||||
switch (pdev->id) {
|
||||
case 0:
|
||||
s3c_gpio_cfgpin_range(S5PV310_GPZ(0), 7, S3C_GPIO_SFN(2));
|
||||
break;
|
||||
case 1:
|
||||
s3c_gpio_cfgpin_range(S5PV310_GPC0(0), 5, S3C_GPIO_SFN(2));
|
||||
break;
|
||||
case 2:
|
||||
s3c_gpio_cfgpin_range(S5PV310_GPC1(0), 5, S3C_GPIO_SFN(4));
|
||||
break;
|
||||
default:
|
||||
printk(KERN_ERR "Invalid Device %d\n", pdev->id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct s3c_audio_pdata i2sv5_pdata = {
|
||||
.cfg_gpio = s5pv310_cfg_i2s,
|
||||
.type = {
|
||||
.i2s = {
|
||||
.quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI
|
||||
| QUIRK_NEED_RSTCLR,
|
||||
.src_clk = rclksrc,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static struct resource s5pv310_i2s0_resource[] = {
|
||||
[0] = {
|
||||
.start = S5PV310_PA_I2S0,
|
||||
.end = S5PV310_PA_I2S0 + 0x100 - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = DMACH_I2S0_TX,
|
||||
.end = DMACH_I2S0_TX,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
[2] = {
|
||||
.start = DMACH_I2S0_RX,
|
||||
.end = DMACH_I2S0_RX,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
[3] = {
|
||||
.start = DMACH_I2S0S_TX,
|
||||
.end = DMACH_I2S0S_TX,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
};
|
||||
|
||||
struct platform_device s5pv310_device_i2s0 = {
|
||||
.name = "samsung-i2s",
|
||||
.id = 0,
|
||||
.num_resources = ARRAY_SIZE(s5pv310_i2s0_resource),
|
||||
.resource = s5pv310_i2s0_resource,
|
||||
.dev = {
|
||||
.platform_data = &i2sv5_pdata,
|
||||
},
|
||||
};
|
||||
|
||||
static const char *rclksrc_v3[] = {
|
||||
[0] = "sclk_i2s",
|
||||
[1] = "no_such_clock",
|
||||
};
|
||||
|
||||
static struct s3c_audio_pdata i2sv3_pdata = {
|
||||
.cfg_gpio = s5pv310_cfg_i2s,
|
||||
.type = {
|
||||
.i2s = {
|
||||
.quirks = QUIRK_NO_MUXPSR,
|
||||
.src_clk = rclksrc_v3,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static struct resource s5pv310_i2s1_resource[] = {
|
||||
[0] = {
|
||||
.start = S5PV310_PA_I2S1,
|
||||
.end = S5PV310_PA_I2S1 + 0x100 - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = DMACH_I2S1_TX,
|
||||
.end = DMACH_I2S1_TX,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
[2] = {
|
||||
.start = DMACH_I2S1_RX,
|
||||
.end = DMACH_I2S1_RX,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
};
|
||||
|
||||
struct platform_device s5pv310_device_i2s1 = {
|
||||
.name = "samsung-i2s",
|
||||
.id = 1,
|
||||
.num_resources = ARRAY_SIZE(s5pv310_i2s1_resource),
|
||||
.resource = s5pv310_i2s1_resource,
|
||||
.dev = {
|
||||
.platform_data = &i2sv3_pdata,
|
||||
},
|
||||
};
|
||||
|
||||
static struct resource s5pv310_i2s2_resource[] = {
|
||||
[0] = {
|
||||
.start = S5PV310_PA_I2S2,
|
||||
.end = S5PV310_PA_I2S2 + 0x100 - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = DMACH_I2S2_TX,
|
||||
.end = DMACH_I2S2_TX,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
[2] = {
|
||||
.start = DMACH_I2S2_RX,
|
||||
.end = DMACH_I2S2_RX,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
};
|
||||
|
||||
struct platform_device s5pv310_device_i2s2 = {
|
||||
.name = "samsung-i2s",
|
||||
.id = 2,
|
||||
.num_resources = ARRAY_SIZE(s5pv310_i2s2_resource),
|
||||
.resource = s5pv310_i2s2_resource,
|
||||
.dev = {
|
||||
.platform_data = &i2sv3_pdata,
|
||||
},
|
||||
};
|
||||
|
||||
/* PCM Controller platform_devices */
|
||||
|
||||
static int s5pv310_pcm_cfg_gpio(struct platform_device *pdev)
|
||||
{
|
||||
switch (pdev->id) {
|
||||
case 0:
|
||||
s3c_gpio_cfgpin_range(S5PV310_GPZ(0), 5, S3C_GPIO_SFN(3));
|
||||
break;
|
||||
case 1:
|
||||
s3c_gpio_cfgpin_range(S5PV310_GPC0(0), 5, S3C_GPIO_SFN(3));
|
||||
break;
|
||||
case 2:
|
||||
s3c_gpio_cfgpin_range(S5PV310_GPC1(0), 5, S3C_GPIO_SFN(3));
|
||||
break;
|
||||
default:
|
||||
printk(KERN_DEBUG "Invalid PCM Controller number!");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct s3c_audio_pdata s3c_pcm_pdata = {
|
||||
.cfg_gpio = s5pv310_pcm_cfg_gpio,
|
||||
};
|
||||
|
||||
static struct resource s5pv310_pcm0_resource[] = {
|
||||
[0] = {
|
||||
.start = S5PV310_PA_PCM0,
|
||||
.end = S5PV310_PA_PCM0 + 0x100 - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = DMACH_PCM0_TX,
|
||||
.end = DMACH_PCM0_TX,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
[2] = {
|
||||
.start = DMACH_PCM0_RX,
|
||||
.end = DMACH_PCM0_RX,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
};
|
||||
|
||||
struct platform_device s5pv310_device_pcm0 = {
|
||||
.name = "samsung-pcm",
|
||||
.id = 0,
|
||||
.num_resources = ARRAY_SIZE(s5pv310_pcm0_resource),
|
||||
.resource = s5pv310_pcm0_resource,
|
||||
.dev = {
|
||||
.platform_data = &s3c_pcm_pdata,
|
||||
},
|
||||
};
|
||||
|
||||
static struct resource s5pv310_pcm1_resource[] = {
|
||||
[0] = {
|
||||
.start = S5PV310_PA_PCM1,
|
||||
.end = S5PV310_PA_PCM1 + 0x100 - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = DMACH_PCM1_TX,
|
||||
.end = DMACH_PCM1_TX,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
[2] = {
|
||||
.start = DMACH_PCM1_RX,
|
||||
.end = DMACH_PCM1_RX,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
};
|
||||
|
||||
struct platform_device s5pv310_device_pcm1 = {
|
||||
.name = "samsung-pcm",
|
||||
.id = 1,
|
||||
.num_resources = ARRAY_SIZE(s5pv310_pcm1_resource),
|
||||
.resource = s5pv310_pcm1_resource,
|
||||
.dev = {
|
||||
.platform_data = &s3c_pcm_pdata,
|
||||
},
|
||||
};
|
||||
|
||||
static struct resource s5pv310_pcm2_resource[] = {
|
||||
[0] = {
|
||||
.start = S5PV310_PA_PCM2,
|
||||
.end = S5PV310_PA_PCM2 + 0x100 - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = DMACH_PCM2_TX,
|
||||
.end = DMACH_PCM2_TX,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
[2] = {
|
||||
.start = DMACH_PCM2_RX,
|
||||
.end = DMACH_PCM2_RX,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
};
|
||||
|
||||
struct platform_device s5pv310_device_pcm2 = {
|
||||
.name = "samsung-pcm",
|
||||
.id = 2,
|
||||
.num_resources = ARRAY_SIZE(s5pv310_pcm2_resource),
|
||||
.resource = s5pv310_pcm2_resource,
|
||||
.dev = {
|
||||
.platform_data = &s3c_pcm_pdata,
|
||||
},
|
||||
};
|
||||
|
||||
/* AC97 Controller platform devices */
|
||||
|
||||
static int s5pv310_ac97_cfg_gpio(struct platform_device *pdev)
|
||||
{
|
||||
return s3c_gpio_cfgpin_range(S5PV310_GPC0(0), 5, S3C_GPIO_SFN(4));
|
||||
}
|
||||
|
||||
static struct resource s5pv310_ac97_resource[] = {
|
||||
[0] = {
|
||||
.start = S5PV310_PA_AC97,
|
||||
.end = S5PV310_PA_AC97 + 0x100 - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = DMACH_AC97_PCMOUT,
|
||||
.end = DMACH_AC97_PCMOUT,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
[2] = {
|
||||
.start = DMACH_AC97_PCMIN,
|
||||
.end = DMACH_AC97_PCMIN,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
[3] = {
|
||||
.start = DMACH_AC97_MICIN,
|
||||
.end = DMACH_AC97_MICIN,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
[4] = {
|
||||
.start = IRQ_AC97,
|
||||
.end = IRQ_AC97,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static struct s3c_audio_pdata s3c_ac97_pdata = {
|
||||
.cfg_gpio = s5pv310_ac97_cfg_gpio,
|
||||
};
|
||||
|
||||
static u64 s5pv310_ac97_dmamask = DMA_BIT_MASK(32);
|
||||
|
||||
struct platform_device s5pv310_device_ac97 = {
|
||||
.name = "samsung-ac97",
|
||||
.id = -1,
|
||||
.num_resources = ARRAY_SIZE(s5pv310_ac97_resource),
|
||||
.resource = s5pv310_ac97_resource,
|
||||
.dev = {
|
||||
.platform_data = &s3c_ac97_pdata,
|
||||
.dma_mask = &s5pv310_ac97_dmamask,
|
||||
.coherent_dma_mask = DMA_BIT_MASK(32),
|
||||
},
|
||||
};
|
||||
|
||||
/* S/PDIF Controller platform_device */
|
||||
|
||||
static int s5pv310_spdif_cfg_gpio(struct platform_device *pdev)
|
||||
{
|
||||
s3c_gpio_cfgpin_range(S5PV310_GPC1(0), 2, S3C_GPIO_SFN(3));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct resource s5pv310_spdif_resource[] = {
|
||||
[0] = {
|
||||
.start = S5PV310_PA_SPDIF,
|
||||
.end = S5PV310_PA_SPDIF + 0x100 - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = DMACH_SPDIF,
|
||||
.end = DMACH_SPDIF,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
};
|
||||
|
||||
static struct s3c_audio_pdata samsung_spdif_pdata = {
|
||||
.cfg_gpio = s5pv310_spdif_cfg_gpio,
|
||||
};
|
||||
|
||||
static u64 s5pv310_spdif_dmamask = DMA_BIT_MASK(32);
|
||||
|
||||
struct platform_device s5pv310_device_spdif = {
|
||||
.name = "samsung-spdif",
|
||||
.id = -1,
|
||||
.num_resources = ARRAY_SIZE(s5pv310_spdif_resource),
|
||||
.resource = s5pv310_spdif_resource,
|
||||
.dev = {
|
||||
.platform_data = &samsung_spdif_pdata,
|
||||
.dma_mask = &s5pv310_spdif_dmamask,
|
||||
.coherent_dma_mask = DMA_BIT_MASK(32),
|
||||
},
|
||||
};
|
168
arch/arm/mach-s5pv310/dma.c
Normal file
168
arch/arm/mach-s5pv310/dma.c
Normal file
@ -0,0 +1,168 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Samsung Electronics Co. Ltd.
|
||||
* Jaswinder Singh <jassi.brar@samsung.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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
|
||||
#include <plat/devs.h>
|
||||
#include <plat/irqs.h>
|
||||
|
||||
#include <mach/map.h>
|
||||
#include <mach/irqs.h>
|
||||
|
||||
#include <plat/s3c-pl330-pdata.h>
|
||||
|
||||
static u64 dma_dmamask = DMA_BIT_MASK(32);
|
||||
|
||||
static struct resource s5pv310_pdma0_resource[] = {
|
||||
[0] = {
|
||||
.start = S5PV310_PA_PDMA0,
|
||||
.end = S5PV310_PA_PDMA0 + SZ_4K,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = IRQ_PDMA0,
|
||||
.end = IRQ_PDMA0,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static struct s3c_pl330_platdata s5pv310_pdma0_pdata = {
|
||||
.peri = {
|
||||
[0] = DMACH_PCM0_RX,
|
||||
[1] = DMACH_PCM0_TX,
|
||||
[2] = DMACH_PCM2_RX,
|
||||
[3] = DMACH_PCM2_TX,
|
||||
[4] = DMACH_MSM_REQ0,
|
||||
[5] = DMACH_MSM_REQ2,
|
||||
[6] = DMACH_SPI0_RX,
|
||||
[7] = DMACH_SPI0_TX,
|
||||
[8] = DMACH_SPI2_RX,
|
||||
[9] = DMACH_SPI2_TX,
|
||||
[10] = DMACH_I2S0S_TX,
|
||||
[11] = DMACH_I2S0_RX,
|
||||
[12] = DMACH_I2S0_TX,
|
||||
[13] = DMACH_I2S2_RX,
|
||||
[14] = DMACH_I2S2_TX,
|
||||
[15] = DMACH_UART0_RX,
|
||||
[16] = DMACH_UART0_TX,
|
||||
[17] = DMACH_UART2_RX,
|
||||
[18] = DMACH_UART2_TX,
|
||||
[19] = DMACH_UART4_RX,
|
||||
[20] = DMACH_UART4_TX,
|
||||
[21] = DMACH_SLIMBUS0_RX,
|
||||
[22] = DMACH_SLIMBUS0_TX,
|
||||
[23] = DMACH_SLIMBUS2_RX,
|
||||
[24] = DMACH_SLIMBUS2_TX,
|
||||
[25] = DMACH_SLIMBUS4_RX,
|
||||
[26] = DMACH_SLIMBUS4_TX,
|
||||
[27] = DMACH_AC97_MICIN,
|
||||
[28] = DMACH_AC97_PCMIN,
|
||||
[29] = DMACH_AC97_PCMOUT,
|
||||
[30] = DMACH_MAX,
|
||||
[31] = DMACH_MAX,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device s5pv310_device_pdma0 = {
|
||||
.name = "s3c-pl330",
|
||||
.id = 0,
|
||||
.num_resources = ARRAY_SIZE(s5pv310_pdma0_resource),
|
||||
.resource = s5pv310_pdma0_resource,
|
||||
.dev = {
|
||||
.dma_mask = &dma_dmamask,
|
||||
.coherent_dma_mask = DMA_BIT_MASK(32),
|
||||
.platform_data = &s5pv310_pdma0_pdata,
|
||||
},
|
||||
};
|
||||
|
||||
static struct resource s5pv310_pdma1_resource[] = {
|
||||
[0] = {
|
||||
.start = S5PV310_PA_PDMA1,
|
||||
.end = S5PV310_PA_PDMA1 + SZ_4K,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = IRQ_PDMA1,
|
||||
.end = IRQ_PDMA1,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static struct s3c_pl330_platdata s5pv310_pdma1_pdata = {
|
||||
.peri = {
|
||||
[0] = DMACH_PCM0_RX,
|
||||
[1] = DMACH_PCM0_TX,
|
||||
[2] = DMACH_PCM1_RX,
|
||||
[3] = DMACH_PCM1_TX,
|
||||
[4] = DMACH_MSM_REQ1,
|
||||
[5] = DMACH_MSM_REQ3,
|
||||
[6] = DMACH_SPI1_RX,
|
||||
[7] = DMACH_SPI1_TX,
|
||||
[8] = DMACH_I2S0S_TX,
|
||||
[9] = DMACH_I2S0_RX,
|
||||
[10] = DMACH_I2S0_TX,
|
||||
[11] = DMACH_I2S1_RX,
|
||||
[12] = DMACH_I2S1_TX,
|
||||
[13] = DMACH_UART0_RX,
|
||||
[14] = DMACH_UART0_TX,
|
||||
[15] = DMACH_UART1_RX,
|
||||
[16] = DMACH_UART1_TX,
|
||||
[17] = DMACH_UART3_RX,
|
||||
[18] = DMACH_UART3_TX,
|
||||
[19] = DMACH_SLIMBUS1_RX,
|
||||
[20] = DMACH_SLIMBUS1_TX,
|
||||
[21] = DMACH_SLIMBUS3_RX,
|
||||
[22] = DMACH_SLIMBUS3_TX,
|
||||
[23] = DMACH_SLIMBUS5_RX,
|
||||
[24] = DMACH_SLIMBUS5_TX,
|
||||
[25] = DMACH_SLIMBUS0AUX_RX,
|
||||
[26] = DMACH_SLIMBUS0AUX_TX,
|
||||
[27] = DMACH_SPDIF,
|
||||
[28] = DMACH_MAX,
|
||||
[29] = DMACH_MAX,
|
||||
[30] = DMACH_MAX,
|
||||
[31] = DMACH_MAX,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device s5pv310_device_pdma1 = {
|
||||
.name = "s3c-pl330",
|
||||
.id = 1,
|
||||
.num_resources = ARRAY_SIZE(s5pv310_pdma1_resource),
|
||||
.resource = s5pv310_pdma1_resource,
|
||||
.dev = {
|
||||
.dma_mask = &dma_dmamask,
|
||||
.coherent_dma_mask = DMA_BIT_MASK(32),
|
||||
.platform_data = &s5pv310_pdma1_pdata,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device *s5pv310_dmacs[] __initdata = {
|
||||
&s5pv310_device_pdma0,
|
||||
&s5pv310_device_pdma1,
|
||||
};
|
||||
|
||||
static int __init s5pv310_dma_init(void)
|
||||
{
|
||||
platform_add_devices(s5pv310_dmacs, ARRAY_SIZE(s5pv310_dmacs));
|
||||
|
||||
return 0;
|
||||
}
|
||||
arch_initcall(s5pv310_dma_init);
|
26
arch/arm/mach-s5pv310/include/mach/dma.h
Normal file
26
arch/arm/mach-s5pv310/include/mach/dma.h
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Samsung Electronics Co. Ltd.
|
||||
* Jaswinder Singh <jassi.brar@samsung.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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef __MACH_DMA_H
|
||||
#define __MACH_DMA_H
|
||||
|
||||
/* This platform uses the common S3C DMA API driver for PL330 */
|
||||
#include <plat/s3c-dma-pl330.h>
|
||||
|
||||
#endif /* __MACH_DMA_H */
|
@ -54,6 +54,9 @@
|
||||
#define COMBINER_GROUP(x) ((x) * MAX_IRQ_IN_COMBINER + IRQ_SPI(64))
|
||||
#define COMBINER_IRQ(x, y) (COMBINER_GROUP(x) + y)
|
||||
|
||||
#define IRQ_PDMA0 COMBINER_IRQ(21, 0)
|
||||
#define IRQ_PDMA1 COMBINER_IRQ(21, 1)
|
||||
|
||||
#define IRQ_TIMER0_VIC COMBINER_IRQ(22, 0)
|
||||
#define IRQ_TIMER1_VIC COMBINER_IRQ(22, 1)
|
||||
#define IRQ_TIMER2_VIC COMBINER_IRQ(22, 2)
|
||||
|
@ -52,6 +52,11 @@
|
||||
#define S5PV310_PA_GIC_DIST (0x10501000)
|
||||
#define S5PV310_PA_L2CC (0x10502000)
|
||||
|
||||
/* DMA */
|
||||
#define S5PV310_PA_MDMA 0x10810000
|
||||
#define S5PV310_PA_PDMA0 0x12680000
|
||||
#define S5PV310_PA_PDMA1 0x12690000
|
||||
|
||||
#define S5PV310_PA_GPIO1 (0x11400000)
|
||||
#define S5PV310_PA_GPIO2 (0x11000000)
|
||||
#define S5PV310_PA_GPIO3 (0x03860000)
|
||||
@ -60,6 +65,22 @@
|
||||
|
||||
#define S5PV310_PA_SROMC (0x12570000)
|
||||
|
||||
/* S/PDIF */
|
||||
#define S5PV310_PA_SPDIF 0xE1100000
|
||||
|
||||
/* I2S */
|
||||
#define S5PV310_PA_I2S0 0x03830000
|
||||
#define S5PV310_PA_I2S1 0xE3100000
|
||||
#define S5PV310_PA_I2S2 0xE2A00000
|
||||
|
||||
/* PCM */
|
||||
#define S5PV310_PA_PCM0 0x03840000
|
||||
#define S5PV310_PA_PCM1 0x13980000
|
||||
#define S5PV310_PA_PCM2 0x13990000
|
||||
|
||||
/* AC97 */
|
||||
#define S5PV310_PA_AC97 0x139A0000
|
||||
|
||||
#define S5PV310_PA_UART (0x13800000)
|
||||
|
||||
#define S5P_PA_UART(x) (S5PV310_PA_UART + ((x) * S3C_UART_OFFSET))
|
||||
|
@ -711,6 +711,10 @@ static struct platform_device fsi_device = {
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device fsi_ak4643_device = {
|
||||
.name = "sh_fsi2_a_ak4643",
|
||||
};
|
||||
|
||||
static struct sh_mobile_lcdc_info sh_mobile_lcdc1_info = {
|
||||
.clock_source = LCDC_CLK_EXTERNAL,
|
||||
.ch[0] = {
|
||||
@ -933,6 +937,7 @@ static struct platform_device *ap4evb_devices[] __initdata = {
|
||||
&sdhi1_device,
|
||||
&usb1_host_device,
|
||||
&fsi_device,
|
||||
&fsi_ak4643_device,
|
||||
&sh_mmcif_device,
|
||||
&lcdc1_device,
|
||||
&lcdc_device,
|
||||
|
@ -259,21 +259,6 @@ struct platform_device s3c_device_iis = {
|
||||
|
||||
EXPORT_SYMBOL(s3c_device_iis);
|
||||
|
||||
/* ASoC PCM DMA */
|
||||
|
||||
static u64 s3c_device_audio_dmamask = 0xffffffffUL;
|
||||
|
||||
struct platform_device s3c_device_pcm = {
|
||||
.name = "s3c24xx-pcm-audio",
|
||||
.id = -1,
|
||||
.dev = {
|
||||
.dma_mask = &s3c_device_audio_dmamask,
|
||||
.coherent_dma_mask = 0xffffffffUL
|
||||
}
|
||||
};
|
||||
|
||||
EXPORT_SYMBOL(s3c_device_pcm);
|
||||
|
||||
/* RTC */
|
||||
|
||||
static struct resource s3c_rtc_resource[] = {
|
||||
@ -496,8 +481,10 @@ static struct resource s3c_ac97_resource[] = {
|
||||
},
|
||||
};
|
||||
|
||||
static u64 s3c_device_audio_dmamask = 0xffffffffUL;
|
||||
|
||||
struct platform_device s3c_device_ac97 = {
|
||||
.name = "s3c-ac97",
|
||||
.name = "samsung-ac97",
|
||||
.id = -1,
|
||||
.num_resources = ARRAY_SIZE(s3c_ac97_resource),
|
||||
.resource = s3c_ac97_resource,
|
||||
|
@ -17,6 +17,7 @@ obj-y += clock.o
|
||||
obj-y += pwm-clock.o
|
||||
obj-y += gpio.o
|
||||
obj-y += gpio-config.o
|
||||
obj-y += dev-asocdma.o
|
||||
|
||||
obj-$(CONFIG_SAMSUNG_GPIOLIB_4BIT) += gpiolib.o
|
||||
obj-$(CONFIG_SAMSUNG_CLKSRC) += clock-clksrc.o
|
||||
|
25
arch/arm/plat-samsung/dev-asocdma.c
Normal file
25
arch/arm/plat-samsung/dev-asocdma.c
Normal file
@ -0,0 +1,25 @@
|
||||
/* linux/arch/arm/plat-samsung/dev-asocdma.c
|
||||
*
|
||||
* Copyright (c) 2010 Samsung Electronics Co. Ltd
|
||||
* Jaswinder Singh <jassi.brar@samsung.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <plat/devs.h>
|
||||
|
||||
static u64 audio_dmamask = DMA_BIT_MASK(32);
|
||||
|
||||
struct platform_device samsung_asoc_dma = {
|
||||
.name = "samsung-audio",
|
||||
.id = -1,
|
||||
.dev = {
|
||||
.dma_mask = &audio_dmamask,
|
||||
.coherent_dma_mask = DMA_BIT_MASK(32),
|
||||
}
|
||||
};
|
||||
EXPORT_SYMBOL(samsung_asoc_dma);
|
@ -25,10 +25,34 @@ extern void s3c64xx_ac97_setup_gpio(int);
|
||||
#define S5PC100_SPDIF_GPG3 1
|
||||
extern void s5pc100_spdif_setup_gpio(int);
|
||||
|
||||
struct samsung_i2s {
|
||||
/* If the Primary DAI has 5.1 Channels */
|
||||
#define QUIRK_PRI_6CHAN (1 << 0)
|
||||
/* If the I2S block has a Stereo Overlay Channel */
|
||||
#define QUIRK_SEC_DAI (1 << 1)
|
||||
/*
|
||||
* If the I2S block has no internal prescalar or MUX (I2SMOD[10] bit)
|
||||
* The Machine driver must provide suitably set clock to the I2S block.
|
||||
*/
|
||||
#define QUIRK_NO_MUXPSR (1 << 2)
|
||||
#define QUIRK_NEED_RSTCLR (1 << 3)
|
||||
/* Quirks of the I2S controller */
|
||||
u32 quirks;
|
||||
|
||||
/*
|
||||
* Array of clock names that can be used to generate I2S signals.
|
||||
* Also corresponds to clocks of I2SMOD[10]
|
||||
*/
|
||||
const char **src_clk;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct s3c_audio_pdata - common platform data for audio device drivers
|
||||
* @cfg_gpio: Callback function to setup mux'ed pins in I2S/PCM/AC97 mode
|
||||
*/
|
||||
struct s3c_audio_pdata {
|
||||
int (*cfg_gpio)(struct platform_device *);
|
||||
union {
|
||||
struct samsung_i2s i2s;
|
||||
} type;
|
||||
};
|
||||
|
@ -32,7 +32,7 @@ extern struct platform_device s3c64xx_device_iisv4;
|
||||
extern struct platform_device s3c64xx_device_spi0;
|
||||
extern struct platform_device s3c64xx_device_spi1;
|
||||
|
||||
extern struct platform_device s3c_device_pcm;
|
||||
extern struct platform_device samsung_asoc_dma;
|
||||
|
||||
extern struct platform_device s3c64xx_device_pcm0;
|
||||
extern struct platform_device s3c64xx_device_pcm1;
|
||||
@ -96,6 +96,15 @@ extern struct platform_device s5pv210_device_iis1;
|
||||
extern struct platform_device s5pv210_device_iis2;
|
||||
extern struct platform_device s5pv210_device_spdif;
|
||||
|
||||
extern struct platform_device s5pv310_device_ac97;
|
||||
extern struct platform_device s5pv310_device_pcm0;
|
||||
extern struct platform_device s5pv310_device_pcm1;
|
||||
extern struct platform_device s5pv310_device_pcm2;
|
||||
extern struct platform_device s5pv310_device_i2s0;
|
||||
extern struct platform_device s5pv310_device_i2s1;
|
||||
extern struct platform_device s5pv310_device_i2s2;
|
||||
extern struct platform_device s5pv310_device_spdif;
|
||||
|
||||
extern struct platform_device s5p6442_device_pcm0;
|
||||
extern struct platform_device s5p6442_device_pcm1;
|
||||
extern struct platform_device s5p6442_device_iis0;
|
||||
|
@ -318,6 +318,10 @@ static struct platform_device fsi_device = {
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device fsi_ak4642_device = {
|
||||
.name = "sh_fsi_a_ak4642",
|
||||
};
|
||||
|
||||
/* KEYSC in SoC (Needs SW33-2 set to ON) */
|
||||
static struct sh_keysc_info keysc_info = {
|
||||
.mode = SH_KEYSC_MODE_1,
|
||||
@ -590,6 +594,7 @@ static struct platform_device *ms7724se_devices[] __initdata = {
|
||||
&sh7724_usb0_host_device,
|
||||
&sh7724_usb1_gadget_device,
|
||||
&fsi_device,
|
||||
&fsi_ak4642_device,
|
||||
&sdhi0_cn7_device,
|
||||
&sdhi1_cn8_device,
|
||||
&irda_device,
|
||||
|
@ -35,6 +35,29 @@ static inline struct wm8994_gpio *to_wm8994_gpio(struct gpio_chip *chip)
|
||||
return container_of(chip, struct wm8994_gpio, gpio_chip);
|
||||
}
|
||||
|
||||
static int wm8994_gpio_request(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct wm8994_gpio *wm8994_gpio = to_wm8994_gpio(chip);
|
||||
struct wm8994 *wm8994 = wm8994_gpio->wm8994;
|
||||
|
||||
switch (wm8994->type) {
|
||||
case WM8958:
|
||||
switch (offset) {
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 6:
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wm8994_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct wm8994_gpio *wm8994_gpio = to_wm8994_gpio(chip);
|
||||
@ -136,6 +159,7 @@ static void wm8994_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
|
||||
static struct gpio_chip template_chip = {
|
||||
.label = "wm8994",
|
||||
.owner = THIS_MODULE,
|
||||
.request = wm8994_gpio_request,
|
||||
.direction_input = wm8994_gpio_direction_in,
|
||||
.get = wm8994_gpio_get,
|
||||
.direction_output = wm8994_gpio_direction_out,
|
||||
|
@ -218,6 +218,18 @@ static const char *wm8994_main_supplies[] = {
|
||||
"SPKVDD2",
|
||||
};
|
||||
|
||||
static const char *wm8958_main_supplies[] = {
|
||||
"DBVDD1",
|
||||
"DBVDD2",
|
||||
"DBVDD3",
|
||||
"DCVDD",
|
||||
"AVDD1",
|
||||
"AVDD2",
|
||||
"CPVDD",
|
||||
"SPKVDD1",
|
||||
"SPKVDD2",
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int wm8994_device_suspend(struct device *dev)
|
||||
{
|
||||
@ -239,7 +251,7 @@ static int wm8994_device_suspend(struct device *dev)
|
||||
if (ret < 0)
|
||||
dev_err(dev, "Failed to save LDO registers: %d\n", ret);
|
||||
|
||||
ret = regulator_bulk_disable(ARRAY_SIZE(wm8994_main_supplies),
|
||||
ret = regulator_bulk_disable(wm8994->num_supplies,
|
||||
wm8994->supplies);
|
||||
if (ret != 0) {
|
||||
dev_err(dev, "Failed to disable supplies: %d\n", ret);
|
||||
@ -254,7 +266,7 @@ static int wm8994_device_resume(struct device *dev)
|
||||
struct wm8994 *wm8994 = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(wm8994_main_supplies),
|
||||
ret = regulator_bulk_enable(wm8994->num_supplies,
|
||||
wm8994->supplies);
|
||||
if (ret != 0) {
|
||||
dev_err(dev, "Failed to enable supplies: %d\n", ret);
|
||||
@ -305,9 +317,10 @@ static int wm8994_ldo_in_use(struct wm8994_pdata *pdata, int ldo)
|
||||
/*
|
||||
* Instantiate the generic non-control parts of the device.
|
||||
*/
|
||||
static int wm8994_device_init(struct wm8994 *wm8994, unsigned long id, int irq)
|
||||
static int wm8994_device_init(struct wm8994 *wm8994, int irq)
|
||||
{
|
||||
struct wm8994_pdata *pdata = wm8994->dev->platform_data;
|
||||
const char *devname;
|
||||
int ret, i;
|
||||
|
||||
mutex_init(&wm8994->io_lock);
|
||||
@ -323,25 +336,48 @@ static int wm8994_device_init(struct wm8994 *wm8994, unsigned long id, int irq)
|
||||
goto err;
|
||||
}
|
||||
|
||||
switch (wm8994->type) {
|
||||
case WM8994:
|
||||
wm8994->num_supplies = ARRAY_SIZE(wm8994_main_supplies);
|
||||
break;
|
||||
case WM8958:
|
||||
wm8994->num_supplies = ARRAY_SIZE(wm8958_main_supplies);
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
wm8994->supplies = kzalloc(sizeof(struct regulator_bulk_data) *
|
||||
ARRAY_SIZE(wm8994_main_supplies),
|
||||
wm8994->num_supplies,
|
||||
GFP_KERNEL);
|
||||
if (!wm8994->supplies) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(wm8994_main_supplies); i++)
|
||||
wm8994->supplies[i].supply = wm8994_main_supplies[i];
|
||||
|
||||
ret = regulator_bulk_get(wm8994->dev, ARRAY_SIZE(wm8994_main_supplies),
|
||||
switch (wm8994->type) {
|
||||
case WM8994:
|
||||
for (i = 0; i < ARRAY_SIZE(wm8994_main_supplies); i++)
|
||||
wm8994->supplies[i].supply = wm8994_main_supplies[i];
|
||||
break;
|
||||
case WM8958:
|
||||
for (i = 0; i < ARRAY_SIZE(wm8958_main_supplies); i++)
|
||||
wm8994->supplies[i].supply = wm8958_main_supplies[i];
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = regulator_bulk_get(wm8994->dev, wm8994->num_supplies,
|
||||
wm8994->supplies);
|
||||
if (ret != 0) {
|
||||
dev_err(wm8994->dev, "Failed to get supplies: %d\n", ret);
|
||||
goto err_supplies;
|
||||
}
|
||||
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(wm8994_main_supplies),
|
||||
ret = regulator_bulk_enable(wm8994->num_supplies,
|
||||
wm8994->supplies);
|
||||
if (ret != 0) {
|
||||
dev_err(wm8994->dev, "Failed to enable supplies: %d\n", ret);
|
||||
@ -353,7 +389,22 @@ static int wm8994_device_init(struct wm8994 *wm8994, unsigned long id, int irq)
|
||||
dev_err(wm8994->dev, "Failed to read ID register\n");
|
||||
goto err_enable;
|
||||
}
|
||||
if (ret != 0x8994) {
|
||||
switch (ret) {
|
||||
case 0x8994:
|
||||
devname = "WM8994";
|
||||
if (wm8994->type != WM8994)
|
||||
dev_warn(wm8994->dev, "Device registered as type %d\n",
|
||||
wm8994->type);
|
||||
wm8994->type = WM8994;
|
||||
break;
|
||||
case 0x8958:
|
||||
devname = "WM8958";
|
||||
if (wm8994->type != WM8958)
|
||||
dev_warn(wm8994->dev, "Device registered as type %d\n",
|
||||
wm8994->type);
|
||||
wm8994->type = WM8958;
|
||||
break;
|
||||
default:
|
||||
dev_err(wm8994->dev, "Device is not a WM8994, ID is %x\n",
|
||||
ret);
|
||||
ret = -EINVAL;
|
||||
@ -370,14 +421,16 @@ static int wm8994_device_init(struct wm8994 *wm8994, unsigned long id, int irq)
|
||||
switch (ret) {
|
||||
case 0:
|
||||
case 1:
|
||||
dev_warn(wm8994->dev, "revision %c not fully supported\n",
|
||||
'A' + ret);
|
||||
if (wm8994->type == WM8994)
|
||||
dev_warn(wm8994->dev,
|
||||
"revision %c not fully supported\n",
|
||||
'A' + ret);
|
||||
break;
|
||||
default:
|
||||
dev_info(wm8994->dev, "revision %c\n", 'A' + ret);
|
||||
break;
|
||||
}
|
||||
|
||||
dev_info(wm8994->dev, "%s revision %c\n", devname, 'A' + ret);
|
||||
|
||||
if (pdata) {
|
||||
wm8994->irq_base = pdata->irq_base;
|
||||
@ -423,10 +476,10 @@ static int wm8994_device_init(struct wm8994 *wm8994, unsigned long id, int irq)
|
||||
err_irq:
|
||||
wm8994_irq_exit(wm8994);
|
||||
err_enable:
|
||||
regulator_bulk_disable(ARRAY_SIZE(wm8994_main_supplies),
|
||||
regulator_bulk_disable(wm8994->num_supplies,
|
||||
wm8994->supplies);
|
||||
err_get:
|
||||
regulator_bulk_free(ARRAY_SIZE(wm8994_main_supplies), wm8994->supplies);
|
||||
regulator_bulk_free(wm8994->num_supplies, wm8994->supplies);
|
||||
err_supplies:
|
||||
kfree(wm8994->supplies);
|
||||
err:
|
||||
@ -439,9 +492,9 @@ static void wm8994_device_exit(struct wm8994 *wm8994)
|
||||
{
|
||||
mfd_remove_devices(wm8994->dev);
|
||||
wm8994_irq_exit(wm8994);
|
||||
regulator_bulk_disable(ARRAY_SIZE(wm8994_main_supplies),
|
||||
regulator_bulk_disable(wm8994->num_supplies,
|
||||
wm8994->supplies);
|
||||
regulator_bulk_free(ARRAY_SIZE(wm8994_main_supplies), wm8994->supplies);
|
||||
regulator_bulk_free(wm8994->num_supplies, wm8994->supplies);
|
||||
kfree(wm8994->supplies);
|
||||
kfree(wm8994);
|
||||
}
|
||||
@ -506,8 +559,9 @@ static int wm8994_i2c_probe(struct i2c_client *i2c,
|
||||
wm8994->read_dev = wm8994_i2c_read_device;
|
||||
wm8994->write_dev = wm8994_i2c_write_device;
|
||||
wm8994->irq = i2c->irq;
|
||||
wm8994->type = id->driver_data;
|
||||
|
||||
return wm8994_device_init(wm8994, id->driver_data, i2c->irq);
|
||||
return wm8994_device_init(wm8994, i2c->irq);
|
||||
}
|
||||
|
||||
static int wm8994_i2c_remove(struct i2c_client *i2c)
|
||||
@ -535,7 +589,8 @@ static int wm8994_i2c_resume(struct i2c_client *i2c)
|
||||
#endif
|
||||
|
||||
static const struct i2c_device_id wm8994_i2c_id[] = {
|
||||
{ "wm8994", 0 },
|
||||
{ "wm8994", WM8994 },
|
||||
{ "wm8958", WM8958 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, wm8994_i2c_id);
|
||||
|
@ -130,10 +130,19 @@ static struct regulator_ops wm8994_ldo1_ops = {
|
||||
static int wm8994_ldo2_list_voltage(struct regulator_dev *rdev,
|
||||
unsigned int selector)
|
||||
{
|
||||
struct wm8994_ldo *ldo = rdev_get_drvdata(rdev);
|
||||
|
||||
if (selector > WM8994_LDO2_MAX_SELECTOR)
|
||||
return -EINVAL;
|
||||
|
||||
return (selector * 100000) + 900000;
|
||||
switch (ldo->wm8994->type) {
|
||||
case WM8994:
|
||||
return (selector * 100000) + 900000;
|
||||
case WM8958:
|
||||
return (selector * 100000) + 1000000;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int wm8994_ldo2_get_voltage_sel(struct regulator_dev *rdev)
|
||||
@ -154,7 +163,17 @@ static int wm8994_ldo2_set_voltage(struct regulator_dev *rdev,
|
||||
struct wm8994_ldo *ldo = rdev_get_drvdata(rdev);
|
||||
int selector, v;
|
||||
|
||||
selector = (min_uV - 900000) / 100000;
|
||||
switch (ldo->wm8994->type) {
|
||||
case WM8994:
|
||||
selector = (min_uV - 900000) / 100000;
|
||||
break;
|
||||
case WM8958:
|
||||
selector = (min_uV - 1000000) / 100000;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
v = wm8994_ldo2_list_voltage(rdev, selector);
|
||||
if (v < 0 || v > max_uV)
|
||||
return -EINVAL;
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/soc-dapm.h>
|
||||
#include <sound/initval.h>
|
||||
|
||||
|
@ -17,6 +17,11 @@
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
enum wm8994_type {
|
||||
WM8994 = 0,
|
||||
WM8958 = 1,
|
||||
};
|
||||
|
||||
struct regulator_dev;
|
||||
struct regulator_bulk_data;
|
||||
|
||||
@ -48,6 +53,8 @@ struct wm8994 {
|
||||
struct mutex io_lock;
|
||||
struct mutex irq_lock;
|
||||
|
||||
enum wm8994_type type;
|
||||
|
||||
struct device *dev;
|
||||
int (*read_dev)(struct wm8994 *wm8994, unsigned short reg,
|
||||
int bytes, void *dest);
|
||||
@ -68,6 +75,7 @@ struct wm8994 {
|
||||
u16 gpio_regs[WM8994_NUM_GPIO_REGS];
|
||||
|
||||
struct regulator_dev *dbvdd;
|
||||
int num_supplies;
|
||||
struct regulator_bulk_data *supplies;
|
||||
};
|
||||
|
||||
|
@ -30,6 +30,8 @@ struct wm8994_ldo_pdata {
|
||||
|
||||
#define WM8994_DRC_REGS 5
|
||||
#define WM8994_EQ_REGS 20
|
||||
#define WM8958_MBC_CUTOFF_REGS 20
|
||||
#define WM8958_MBC_COEFF_REGS 48
|
||||
|
||||
/**
|
||||
* DRC configurations are specified with a label and a set of register
|
||||
@ -59,6 +61,18 @@ struct wm8994_retune_mobile_cfg {
|
||||
u16 regs[WM8994_EQ_REGS];
|
||||
};
|
||||
|
||||
/**
|
||||
* Multiband compressor configurations are specified with a label and
|
||||
* two sets of values to write. Configurations are expected to be
|
||||
* generated using the multiband compressor configuration panel in
|
||||
* WISCE - see http://www.wolfsonmicro.com/wisce/
|
||||
*/
|
||||
struct wm8958_mbc_cfg {
|
||||
const char *name;
|
||||
u16 cutoff_regs[WM8958_MBC_CUTOFF_REGS];
|
||||
u16 coeff_regs[WM8958_MBC_COEFF_REGS];
|
||||
};
|
||||
|
||||
struct wm8994_pdata {
|
||||
int gpio_base;
|
||||
|
||||
@ -78,6 +92,9 @@ struct wm8994_pdata {
|
||||
int num_retune_mobile_cfgs;
|
||||
struct wm8994_retune_mobile_cfg *retune_mobile_cfgs;
|
||||
|
||||
int num_mbc_cfgs;
|
||||
struct wm8958_mbc_cfg *mbc_cfgs;
|
||||
|
||||
/* LINEOUT can be differential or single ended */
|
||||
unsigned int lineout1_diff:1;
|
||||
unsigned int lineout2_diff:1;
|
||||
|
@ -64,12 +64,16 @@
|
||||
#define WM8994_LDO_1 0x3B
|
||||
#define WM8994_LDO_2 0x3C
|
||||
#define WM8994_CHARGE_PUMP_1 0x4C
|
||||
#define WM8958_CHARGE_PUMP_2 0x4D
|
||||
#define WM8994_CLASS_W_1 0x51
|
||||
#define WM8994_DC_SERVO_1 0x54
|
||||
#define WM8994_DC_SERVO_2 0x55
|
||||
#define WM8994_DC_SERVO_4 0x57
|
||||
#define WM8994_DC_SERVO_READBACK 0x58
|
||||
#define WM8994_ANALOGUE_HP_1 0x60
|
||||
#define WM8958_MIC_DETECT_1 0xD0
|
||||
#define WM8958_MIC_DETECT_2 0xD1
|
||||
#define WM8958_MIC_DETECT_3 0xD2
|
||||
#define WM8994_CHIP_REVISION 0x100
|
||||
#define WM8994_CONTROL_INTERFACE 0x101
|
||||
#define WM8994_WRITE_SEQUENCER_CTRL_1 0x110
|
||||
@ -109,6 +113,10 @@
|
||||
#define WM8994_AIF2DAC_LRCLK 0x315
|
||||
#define WM8994_AIF2DAC_DATA 0x316
|
||||
#define WM8994_AIF2ADC_DATA 0x317
|
||||
#define WM8958_AIF3_CONTROL_1 0x320
|
||||
#define WM8958_AIF3_CONTROL_2 0x321
|
||||
#define WM8958_AIF3DAC_DATA 0x322
|
||||
#define WM8958_AIF3ADC_DATA 0x323
|
||||
#define WM8994_AIF1_ADC1_LEFT_VOLUME 0x400
|
||||
#define WM8994_AIF1_ADC1_RIGHT_VOLUME 0x401
|
||||
#define WM8994_AIF1_DAC1_LEFT_VOLUME 0x402
|
||||
@ -242,6 +250,83 @@
|
||||
#define WM8994_INTERRUPT_STATUS_2_MASK 0x739
|
||||
#define WM8994_INTERRUPT_CONTROL 0x740
|
||||
#define WM8994_IRQ_DEBOUNCE 0x748
|
||||
#define WM8958_DSP2_PROGRAM 0x900
|
||||
#define WM8958_DSP2_CONFIG 0x901
|
||||
#define WM8958_DSP2_MAGICNUM 0xA00
|
||||
#define WM8958_DSP2_RELEASEYEAR 0xA01
|
||||
#define WM8958_DSP2_RELEASEMONTHDAY 0xA02
|
||||
#define WM8958_DSP2_RELEASETIME 0xA03
|
||||
#define WM8958_DSP2_VERMAJMIN 0xA04
|
||||
#define WM8958_DSP2_VERBUILD 0xA05
|
||||
#define WM8958_DSP2_EXECCONTROL 0xA0D
|
||||
#define WM8958_MBC_BAND_2_LOWER_CUTOFF_C1_1 0x2200
|
||||
#define WM8958_MBC_BAND_2_LOWER_CUTOFF_C1_2 0x2201
|
||||
#define WM8958_MBC_BAND_2_LOWER_CUTOFF_C2_1 0x2202
|
||||
#define WM8958_MBC_BAND_2_LOWER_CUTOFF_C2_2 0x2203
|
||||
#define WM8958_MBC_BAND_2_LOWER_CUTOFF_C3_1 0x2204
|
||||
#define WM8958_MBC_BAND_2_LOWER_CUTOFF_C3_2 0x2205
|
||||
#define WM8958_MBC_BAND_2_UPPER_CUTOFF_C2_1 0x2206
|
||||
#define WM8958_MBC_BAND_2_UPPER_CUTOFF_C2_2 0x2207
|
||||
#define WM8958_MBC_BAND_2_UPPER_CUTOFF_C3_1 0x2208
|
||||
#define WM8958_MBC_BAND_2_UPPER_CUTOFF_C3_2 0x2209
|
||||
#define WM8958_MBC_BAND_2_UPPER_CUTOFF_C1_1 0x220A
|
||||
#define WM8958_MBC_BAND_2_UPPER_CUTOFF_C1_2 0x220B
|
||||
#define WM8958_MBC_BAND_1_UPPER_CUTOFF_C1_1 0x220C
|
||||
#define WM8958_MBC_BAND_1_UPPER_CUTOFF_C1_2 0x220D
|
||||
#define WM8958_MBC_BAND_1_UPPER_CUTOFF_C2_1 0x220E
|
||||
#define WM8958_MBC_BAND_1_UPPER_CUTOFF_C2_2 0x220F
|
||||
#define WM8958_MBC_BAND_1_UPPER_CUTOFF_C3_1 0x2210
|
||||
#define WM8958_MBC_BAND_1_UPPER_CUTOFF_C3_2 0x2211
|
||||
#define WM8958_MBC_BAND_1_LOWER_CUTOFF_1 0x2212
|
||||
#define WM8958_MBC_BAND_1_LOWER_CUTOFF_2 0x2213
|
||||
#define WM8958_MBC_BAND_1_K_1 0x2400
|
||||
#define WM8958_MBC_BAND_1_K_2 0x2401
|
||||
#define WM8958_MBC_BAND_1_N1_1 0x2402
|
||||
#define WM8958_MBC_BAND_1_N1_2 0x2403
|
||||
#define WM8958_MBC_BAND_1_N2_1 0x2404
|
||||
#define WM8958_MBC_BAND_1_N2_2 0x2405
|
||||
#define WM8958_MBC_BAND_1_N3_1 0x2406
|
||||
#define WM8958_MBC_BAND_1_N3_2 0x2407
|
||||
#define WM8958_MBC_BAND_1_N4_1 0x2408
|
||||
#define WM8958_MBC_BAND_1_N4_2 0x2409
|
||||
#define WM8958_MBC_BAND_1_N5_1 0x240A
|
||||
#define WM8958_MBC_BAND_1_N5_2 0x240B
|
||||
#define WM8958_MBC_BAND_1_X1_1 0x240C
|
||||
#define WM8958_MBC_BAND_1_X1_2 0x240D
|
||||
#define WM8958_MBC_BAND_1_X2_1 0x240E
|
||||
#define WM8958_MBC_BAND_1_X2_2 0x240F
|
||||
#define WM8958_MBC_BAND_1_X3_1 0x2410
|
||||
#define WM8958_MBC_BAND_1_X3_2 0x2411
|
||||
#define WM8958_MBC_BAND_1_ATTACK_1 0x2412
|
||||
#define WM8958_MBC_BAND_1_ATTACK_2 0x2413
|
||||
#define WM8958_MBC_BAND_1_DECAY_1 0x2414
|
||||
#define WM8958_MBC_BAND_1_DECAY_2 0x2415
|
||||
#define WM8958_MBC_BAND_2_K_1 0x2416
|
||||
#define WM8958_MBC_BAND_2_K_2 0x2417
|
||||
#define WM8958_MBC_BAND_2_N1_1 0x2418
|
||||
#define WM8958_MBC_BAND_2_N1_2 0x2419
|
||||
#define WM8958_MBC_BAND_2_N2_1 0x241A
|
||||
#define WM8958_MBC_BAND_2_N2_2 0x241B
|
||||
#define WM8958_MBC_BAND_2_N3_1 0x241C
|
||||
#define WM8958_MBC_BAND_2_N3_2 0x241D
|
||||
#define WM8958_MBC_BAND_2_N4_1 0x241E
|
||||
#define WM8958_MBC_BAND_2_N4_2 0x241F
|
||||
#define WM8958_MBC_BAND_2_N5_1 0x2420
|
||||
#define WM8958_MBC_BAND_2_N5_2 0x2421
|
||||
#define WM8958_MBC_BAND_2_X1_1 0x2422
|
||||
#define WM8958_MBC_BAND_2_X1_2 0x2423
|
||||
#define WM8958_MBC_BAND_2_X2_1 0x2424
|
||||
#define WM8958_MBC_BAND_2_X2_2 0x2425
|
||||
#define WM8958_MBC_BAND_2_X3_1 0x2426
|
||||
#define WM8958_MBC_BAND_2_X3_2 0x2427
|
||||
#define WM8958_MBC_BAND_2_ATTACK_1 0x2428
|
||||
#define WM8958_MBC_BAND_2_ATTACK_2 0x2429
|
||||
#define WM8958_MBC_BAND_2_DECAY_1 0x242A
|
||||
#define WM8958_MBC_BAND_2_DECAY_2 0x242B
|
||||
#define WM8958_MBC_B2_PG2_1 0x242C
|
||||
#define WM8958_MBC_B2_PG2_2 0x242D
|
||||
#define WM8958_MBC_B1_PG2_1 0x242E
|
||||
#define WM8958_MBC_B1_PG2_2 0x242F
|
||||
#define WM8994_WRITE_SEQUENCER_0 0x3000
|
||||
#define WM8994_WRITE_SEQUENCER_1 0x3001
|
||||
#define WM8994_WRITE_SEQUENCER_2 0x3002
|
||||
@ -992,6 +1077,12 @@
|
||||
/*
|
||||
* R6 (0x06) - Power Management (6)
|
||||
*/
|
||||
#define WM8958_AIF3ADC_SRC_MASK 0x0600 /* AIF3ADC_SRC - [10:9] */
|
||||
#define WM8958_AIF3ADC_SRC_SHIFT 9 /* AIF3ADC_SRC - [10:9] */
|
||||
#define WM8958_AIF3ADC_SRC_WIDTH 2 /* AIF3ADC_SRC - [10:9] */
|
||||
#define WM8958_AIF2DAC_SRC_MASK 0x0180 /* AIF2DAC_SRC - [8:7] */
|
||||
#define WM8958_AIF2DAC_SRC_SHIFT 7 /* AIF2DAC_SRC - [8:7] */
|
||||
#define WM8958_AIF2DAC_SRC_WIDTH 2 /* AIF2DAC_SRC - [8:7] */
|
||||
#define WM8994_AIF3_TRI 0x0020 /* AIF3_TRI */
|
||||
#define WM8994_AIF3_TRI_MASK 0x0020 /* AIF3_TRI */
|
||||
#define WM8994_AIF3_TRI_SHIFT 5 /* AIF3_TRI */
|
||||
@ -1835,6 +1926,14 @@
|
||||
#define WM8994_CP_ENA_SHIFT 15 /* CP_ENA */
|
||||
#define WM8994_CP_ENA_WIDTH 1 /* CP_ENA */
|
||||
|
||||
/*
|
||||
* R77 (0x4D) - Charge Pump (2)
|
||||
*/
|
||||
#define WM8958_CP_DISCH 0x8000 /* CP_DISCH */
|
||||
#define WM8958_CP_DISCH_MASK 0x8000 /* CP_DISCH */
|
||||
#define WM8958_CP_DISCH_SHIFT 15 /* CP_DISCH */
|
||||
#define WM8958_CP_DISCH_WIDTH 1 /* CP_DISCH */
|
||||
|
||||
/*
|
||||
* R81 (0x51) - Class W (1)
|
||||
*/
|
||||
@ -1951,6 +2050,46 @@
|
||||
#define WM8994_HPOUT1R_DLY_SHIFT 1 /* HPOUT1R_DLY */
|
||||
#define WM8994_HPOUT1R_DLY_WIDTH 1 /* HPOUT1R_DLY */
|
||||
|
||||
/*
|
||||
* R208 (0xD0) - Mic Detect 1
|
||||
*/
|
||||
#define WM8958_MICD_BIAS_STARTTIME_MASK 0xF000 /* MICD_BIAS_STARTTIME - [15:12] */
|
||||
#define WM8958_MICD_BIAS_STARTTIME_SHIFT 12 /* MICD_BIAS_STARTTIME - [15:12] */
|
||||
#define WM8958_MICD_BIAS_STARTTIME_WIDTH 4 /* MICD_BIAS_STARTTIME - [15:12] */
|
||||
#define WM8958_MICD_RATE_MASK 0x0F00 /* MICD_RATE - [11:8] */
|
||||
#define WM8958_MICD_RATE_SHIFT 8 /* MICD_RATE - [11:8] */
|
||||
#define WM8958_MICD_RATE_WIDTH 4 /* MICD_RATE - [11:8] */
|
||||
#define WM8958_MICD_DBTIME 0x0002 /* MICD_DBTIME */
|
||||
#define WM8958_MICD_DBTIME_MASK 0x0002 /* MICD_DBTIME */
|
||||
#define WM8958_MICD_DBTIME_SHIFT 1 /* MICD_DBTIME */
|
||||
#define WM8958_MICD_DBTIME_WIDTH 1 /* MICD_DBTIME */
|
||||
#define WM8958_MICD_ENA 0x0001 /* MICD_ENA */
|
||||
#define WM8958_MICD_ENA_MASK 0x0001 /* MICD_ENA */
|
||||
#define WM8958_MICD_ENA_SHIFT 0 /* MICD_ENA */
|
||||
#define WM8958_MICD_ENA_WIDTH 1 /* MICD_ENA */
|
||||
|
||||
/*
|
||||
* R209 (0xD1) - Mic Detect 2
|
||||
*/
|
||||
#define WM8958_MICD_LVL_SEL_MASK 0x00FF /* MICD_LVL_SEL - [7:0] */
|
||||
#define WM8958_MICD_LVL_SEL_SHIFT 0 /* MICD_LVL_SEL - [7:0] */
|
||||
#define WM8958_MICD_LVL_SEL_WIDTH 8 /* MICD_LVL_SEL - [7:0] */
|
||||
|
||||
/*
|
||||
* R210 (0xD2) - Mic Detect 3
|
||||
*/
|
||||
#define WM8958_MICD_LVL_MASK 0x07FC /* MICD_LVL - [10:2] */
|
||||
#define WM8958_MICD_LVL_SHIFT 2 /* MICD_LVL - [10:2] */
|
||||
#define WM8958_MICD_LVL_WIDTH 9 /* MICD_LVL - [10:2] */
|
||||
#define WM8958_MICD_VALID 0x0002 /* MICD_VALID */
|
||||
#define WM8958_MICD_VALID_MASK 0x0002 /* MICD_VALID */
|
||||
#define WM8958_MICD_VALID_SHIFT 1 /* MICD_VALID */
|
||||
#define WM8958_MICD_VALID_WIDTH 1 /* MICD_VALID */
|
||||
#define WM8958_MICD_STS 0x0001 /* MICD_STS */
|
||||
#define WM8958_MICD_STS_MASK 0x0001 /* MICD_STS */
|
||||
#define WM8958_MICD_STS_SHIFT 0 /* MICD_STS */
|
||||
#define WM8958_MICD_STS_WIDTH 1 /* MICD_STS */
|
||||
|
||||
/*
|
||||
* R256 (0x100) - Chip Revision
|
||||
*/
|
||||
@ -2069,6 +2208,14 @@
|
||||
/*
|
||||
* R520 (0x208) - Clocking (1)
|
||||
*/
|
||||
#define WM8958_DSP2CLK_ENA 0x4000 /* DSP2CLK_ENA */
|
||||
#define WM8958_DSP2CLK_ENA_MASK 0x4000 /* DSP2CLK_ENA */
|
||||
#define WM8958_DSP2CLK_ENA_SHIFT 14 /* DSP2CLK_ENA */
|
||||
#define WM8958_DSP2CLK_ENA_WIDTH 1 /* DSP2CLK_ENA */
|
||||
#define WM8958_DSP2CLK_SRC 0x1000 /* DSP2CLK_SRC */
|
||||
#define WM8958_DSP2CLK_SRC_MASK 0x1000 /* DSP2CLK_SRC */
|
||||
#define WM8958_DSP2CLK_SRC_SHIFT 12 /* DSP2CLK_SRC */
|
||||
#define WM8958_DSP2CLK_SRC_WIDTH 1 /* DSP2CLK_SRC */
|
||||
#define WM8994_TOCLK_ENA 0x0010 /* TOCLK_ENA */
|
||||
#define WM8994_TOCLK_ENA_MASK 0x0010 /* TOCLK_ENA */
|
||||
#define WM8994_TOCLK_ENA_SHIFT 4 /* TOCLK_ENA */
|
||||
@ -2552,6 +2699,63 @@
|
||||
#define WM8994_AIF2ADCR_DAT_INV_SHIFT 0 /* AIF2ADCR_DAT_INV */
|
||||
#define WM8994_AIF2ADCR_DAT_INV_WIDTH 1 /* AIF2ADCR_DAT_INV */
|
||||
|
||||
/*
|
||||
* R800 (0x320) - AIF3 Control (1)
|
||||
*/
|
||||
#define WM8958_AIF3_LRCLK_INV 0x0080 /* AIF3_LRCLK_INV */
|
||||
#define WM8958_AIF3_LRCLK_INV_MASK 0x0080 /* AIF3_LRCLK_INV */
|
||||
#define WM8958_AIF3_LRCLK_INV_SHIFT 7 /* AIF3_LRCLK_INV */
|
||||
#define WM8958_AIF3_LRCLK_INV_WIDTH 1 /* AIF3_LRCLK_INV */
|
||||
#define WM8958_AIF3_WL_MASK 0x0060 /* AIF3_WL - [6:5] */
|
||||
#define WM8958_AIF3_WL_SHIFT 5 /* AIF3_WL - [6:5] */
|
||||
#define WM8958_AIF3_WL_WIDTH 2 /* AIF3_WL - [6:5] */
|
||||
#define WM8958_AIF3_FMT_MASK 0x0018 /* AIF3_FMT - [4:3] */
|
||||
#define WM8958_AIF3_FMT_SHIFT 3 /* AIF3_FMT - [4:3] */
|
||||
#define WM8958_AIF3_FMT_WIDTH 2 /* AIF3_FMT - [4:3] */
|
||||
|
||||
/*
|
||||
* R801 (0x321) - AIF3 Control (2)
|
||||
*/
|
||||
#define WM8958_AIF3DAC_BOOST_MASK 0x0C00 /* AIF3DAC_BOOST - [11:10] */
|
||||
#define WM8958_AIF3DAC_BOOST_SHIFT 10 /* AIF3DAC_BOOST - [11:10] */
|
||||
#define WM8958_AIF3DAC_BOOST_WIDTH 2 /* AIF3DAC_BOOST - [11:10] */
|
||||
#define WM8958_AIF3DAC_COMP 0x0010 /* AIF3DAC_COMP */
|
||||
#define WM8958_AIF3DAC_COMP_MASK 0x0010 /* AIF3DAC_COMP */
|
||||
#define WM8958_AIF3DAC_COMP_SHIFT 4 /* AIF3DAC_COMP */
|
||||
#define WM8958_AIF3DAC_COMP_WIDTH 1 /* AIF3DAC_COMP */
|
||||
#define WM8958_AIF3DAC_COMPMODE 0x0008 /* AIF3DAC_COMPMODE */
|
||||
#define WM8958_AIF3DAC_COMPMODE_MASK 0x0008 /* AIF3DAC_COMPMODE */
|
||||
#define WM8958_AIF3DAC_COMPMODE_SHIFT 3 /* AIF3DAC_COMPMODE */
|
||||
#define WM8958_AIF3DAC_COMPMODE_WIDTH 1 /* AIF3DAC_COMPMODE */
|
||||
#define WM8958_AIF3ADC_COMP 0x0004 /* AIF3ADC_COMP */
|
||||
#define WM8958_AIF3ADC_COMP_MASK 0x0004 /* AIF3ADC_COMP */
|
||||
#define WM8958_AIF3ADC_COMP_SHIFT 2 /* AIF3ADC_COMP */
|
||||
#define WM8958_AIF3ADC_COMP_WIDTH 1 /* AIF3ADC_COMP */
|
||||
#define WM8958_AIF3ADC_COMPMODE 0x0002 /* AIF3ADC_COMPMODE */
|
||||
#define WM8958_AIF3ADC_COMPMODE_MASK 0x0002 /* AIF3ADC_COMPMODE */
|
||||
#define WM8958_AIF3ADC_COMPMODE_SHIFT 1 /* AIF3ADC_COMPMODE */
|
||||
#define WM8958_AIF3ADC_COMPMODE_WIDTH 1 /* AIF3ADC_COMPMODE */
|
||||
#define WM8958_AIF3_LOOPBACK 0x0001 /* AIF3_LOOPBACK */
|
||||
#define WM8958_AIF3_LOOPBACK_MASK 0x0001 /* AIF3_LOOPBACK */
|
||||
#define WM8958_AIF3_LOOPBACK_SHIFT 0 /* AIF3_LOOPBACK */
|
||||
#define WM8958_AIF3_LOOPBACK_WIDTH 1 /* AIF3_LOOPBACK */
|
||||
|
||||
/*
|
||||
* R802 (0x322) - AIF3DAC Data
|
||||
*/
|
||||
#define WM8958_AIF3DAC_DAT_INV 0x0001 /* AIF3DAC_DAT_INV */
|
||||
#define WM8958_AIF3DAC_DAT_INV_MASK 0x0001 /* AIF3DAC_DAT_INV */
|
||||
#define WM8958_AIF3DAC_DAT_INV_SHIFT 0 /* AIF3DAC_DAT_INV */
|
||||
#define WM8958_AIF3DAC_DAT_INV_WIDTH 1 /* AIF3DAC_DAT_INV */
|
||||
|
||||
/*
|
||||
* R803 (0x323) - AIF3ADC Data
|
||||
*/
|
||||
#define WM8958_AIF3ADC_DAT_INV 0x0001 /* AIF3ADC_DAT_INV */
|
||||
#define WM8958_AIF3ADC_DAT_INV_MASK 0x0001 /* AIF3ADC_DAT_INV */
|
||||
#define WM8958_AIF3ADC_DAT_INV_SHIFT 0 /* AIF3ADC_DAT_INV */
|
||||
#define WM8958_AIF3ADC_DAT_INV_WIDTH 1 /* AIF3ADC_DAT_INV */
|
||||
|
||||
/*
|
||||
* R1024 (0x400) - AIF1 ADC1 Left Volume
|
||||
*/
|
||||
@ -4289,4 +4493,102 @@
|
||||
#define WM8994_TEMP_SHUT_DB_SHIFT 0 /* TEMP_SHUT_DB */
|
||||
#define WM8994_TEMP_SHUT_DB_WIDTH 1 /* TEMP_SHUT_DB */
|
||||
|
||||
/*
|
||||
* R2304 (0x900) - DSP2_Program
|
||||
*/
|
||||
#define WM8958_DSP2_ENA 0x0001 /* DSP2_ENA */
|
||||
#define WM8958_DSP2_ENA_MASK 0x0001 /* DSP2_ENA */
|
||||
#define WM8958_DSP2_ENA_SHIFT 0 /* DSP2_ENA */
|
||||
#define WM8958_DSP2_ENA_WIDTH 1 /* DSP2_ENA */
|
||||
|
||||
/*
|
||||
* R2305 (0x901) - DSP2_Config
|
||||
*/
|
||||
#define WM8958_MBC_SEL_MASK 0x0030 /* MBC_SEL - [5:4] */
|
||||
#define WM8958_MBC_SEL_SHIFT 4 /* MBC_SEL - [5:4] */
|
||||
#define WM8958_MBC_SEL_WIDTH 2 /* MBC_SEL - [5:4] */
|
||||
#define WM8958_MBC_ENA 0x0001 /* MBC_ENA */
|
||||
#define WM8958_MBC_ENA_MASK 0x0001 /* MBC_ENA */
|
||||
#define WM8958_MBC_ENA_SHIFT 0 /* MBC_ENA */
|
||||
#define WM8958_MBC_ENA_WIDTH 1 /* MBC_ENA */
|
||||
|
||||
/*
|
||||
* R2560 (0xA00) - DSP2_MagicNum
|
||||
*/
|
||||
#define WM8958_DSP2_MAGIC_NUM_MASK 0xFFFF /* DSP2_MAGIC_NUM - [15:0] */
|
||||
#define WM8958_DSP2_MAGIC_NUM_SHIFT 0 /* DSP2_MAGIC_NUM - [15:0] */
|
||||
#define WM8958_DSP2_MAGIC_NUM_WIDTH 16 /* DSP2_MAGIC_NUM - [15:0] */
|
||||
|
||||
/*
|
||||
* R2561 (0xA01) - DSP2_ReleaseYear
|
||||
*/
|
||||
#define WM8958_DSP2_RELEASE_YEAR_MASK 0xFFFF /* DSP2_RELEASE_YEAR - [15:0] */
|
||||
#define WM8958_DSP2_RELEASE_YEAR_SHIFT 0 /* DSP2_RELEASE_YEAR - [15:0] */
|
||||
#define WM8958_DSP2_RELEASE_YEAR_WIDTH 16 /* DSP2_RELEASE_YEAR - [15:0] */
|
||||
|
||||
/*
|
||||
* R2562 (0xA02) - DSP2_ReleaseMonthDay
|
||||
*/
|
||||
#define WM8958_DSP2_RELEASE_MONTH_MASK 0xFF00 /* DSP2_RELEASE_MONTH - [15:8] */
|
||||
#define WM8958_DSP2_RELEASE_MONTH_SHIFT 8 /* DSP2_RELEASE_MONTH - [15:8] */
|
||||
#define WM8958_DSP2_RELEASE_MONTH_WIDTH 8 /* DSP2_RELEASE_MONTH - [15:8] */
|
||||
#define WM8958_DSP2_RELEASE_DAY_MASK 0x00FF /* DSP2_RELEASE_DAY - [7:0] */
|
||||
#define WM8958_DSP2_RELEASE_DAY_SHIFT 0 /* DSP2_RELEASE_DAY - [7:0] */
|
||||
#define WM8958_DSP2_RELEASE_DAY_WIDTH 8 /* DSP2_RELEASE_DAY - [7:0] */
|
||||
|
||||
/*
|
||||
* R2563 (0xA03) - DSP2_ReleaseTime
|
||||
*/
|
||||
#define WM8958_DSP2_RELEASE_HOURS_MASK 0xFF00 /* DSP2_RELEASE_HOURS - [15:8] */
|
||||
#define WM8958_DSP2_RELEASE_HOURS_SHIFT 8 /* DSP2_RELEASE_HOURS - [15:8] */
|
||||
#define WM8958_DSP2_RELEASE_HOURS_WIDTH 8 /* DSP2_RELEASE_HOURS - [15:8] */
|
||||
#define WM8958_DSP2_RELEASE_MINS_MASK 0x00FF /* DSP2_RELEASE_MINS - [7:0] */
|
||||
#define WM8958_DSP2_RELEASE_MINS_SHIFT 0 /* DSP2_RELEASE_MINS - [7:0] */
|
||||
#define WM8958_DSP2_RELEASE_MINS_WIDTH 8 /* DSP2_RELEASE_MINS - [7:0] */
|
||||
|
||||
/*
|
||||
* R2564 (0xA04) - DSP2_VerMajMin
|
||||
*/
|
||||
#define WM8958_DSP2_MAJOR_VER_MASK 0xFF00 /* DSP2_MAJOR_VER - [15:8] */
|
||||
#define WM8958_DSP2_MAJOR_VER_SHIFT 8 /* DSP2_MAJOR_VER - [15:8] */
|
||||
#define WM8958_DSP2_MAJOR_VER_WIDTH 8 /* DSP2_MAJOR_VER - [15:8] */
|
||||
#define WM8958_DSP2_MINOR_VER_MASK 0x00FF /* DSP2_MINOR_VER - [7:0] */
|
||||
#define WM8958_DSP2_MINOR_VER_SHIFT 0 /* DSP2_MINOR_VER - [7:0] */
|
||||
#define WM8958_DSP2_MINOR_VER_WIDTH 8 /* DSP2_MINOR_VER - [7:0] */
|
||||
|
||||
/*
|
||||
* R2565 (0xA05) - DSP2_VerBuild
|
||||
*/
|
||||
#define WM8958_DSP2_BUILD_VER_MASK 0xFFFF /* DSP2_BUILD_VER - [15:0] */
|
||||
#define WM8958_DSP2_BUILD_VER_SHIFT 0 /* DSP2_BUILD_VER - [15:0] */
|
||||
#define WM8958_DSP2_BUILD_VER_WIDTH 16 /* DSP2_BUILD_VER - [15:0] */
|
||||
|
||||
/*
|
||||
* R2573 (0xA0D) - DSP2_ExecControl
|
||||
*/
|
||||
#define WM8958_DSP2_STOPC 0x0020 /* DSP2_STOPC */
|
||||
#define WM8958_DSP2_STOPC_MASK 0x0020 /* DSP2_STOPC */
|
||||
#define WM8958_DSP2_STOPC_SHIFT 5 /* DSP2_STOPC */
|
||||
#define WM8958_DSP2_STOPC_WIDTH 1 /* DSP2_STOPC */
|
||||
#define WM8958_DSP2_STOPS 0x0010 /* DSP2_STOPS */
|
||||
#define WM8958_DSP2_STOPS_MASK 0x0010 /* DSP2_STOPS */
|
||||
#define WM8958_DSP2_STOPS_SHIFT 4 /* DSP2_STOPS */
|
||||
#define WM8958_DSP2_STOPS_WIDTH 1 /* DSP2_STOPS */
|
||||
#define WM8958_DSP2_STOPI 0x0008 /* DSP2_STOPI */
|
||||
#define WM8958_DSP2_STOPI_MASK 0x0008 /* DSP2_STOPI */
|
||||
#define WM8958_DSP2_STOPI_SHIFT 3 /* DSP2_STOPI */
|
||||
#define WM8958_DSP2_STOPI_WIDTH 1 /* DSP2_STOPI */
|
||||
#define WM8958_DSP2_STOP 0x0004 /* DSP2_STOP */
|
||||
#define WM8958_DSP2_STOP_MASK 0x0004 /* DSP2_STOP */
|
||||
#define WM8958_DSP2_STOP_SHIFT 2 /* DSP2_STOP */
|
||||
#define WM8958_DSP2_STOP_WIDTH 1 /* DSP2_STOP */
|
||||
#define WM8958_DSP2_RUNR 0x0002 /* DSP2_RUNR */
|
||||
#define WM8958_DSP2_RUNR_MASK 0x0002 /* DSP2_RUNR */
|
||||
#define WM8958_DSP2_RUNR_SHIFT 1 /* DSP2_RUNR */
|
||||
#define WM8958_DSP2_RUNR_WIDTH 1 /* DSP2_RUNR */
|
||||
#define WM8958_DSP2_RUN 0x0001 /* DSP2_RUN */
|
||||
#define WM8958_DSP2_RUN_MASK 0x0001 /* DSP2_RUN */
|
||||
#define WM8958_DSP2_RUN_SHIFT 0 /* DSP2_RUN */
|
||||
#define WM8958_DSP2_RUN_WIDTH 1 /* DSP2_RUN */
|
||||
|
||||
#endif
|
||||
|
15
include/sound/alc5623.h
Normal file
15
include/sound/alc5623.h
Normal file
@ -0,0 +1,15 @@
|
||||
#ifndef _INCLUDE_SOUND_ALC5623_H
|
||||
#define _INCLUDE_SOUND_ALC5623_H
|
||||
struct alc5623_platform_data {
|
||||
/* configure : */
|
||||
/* Lineout/Speaker Amps Vmid ratio control */
|
||||
/* enable/disable adc/dac high pass filters */
|
||||
unsigned int add_ctrl;
|
||||
/* configure : */
|
||||
/* output to enable when jack is low */
|
||||
/* output to enable when jack is high */
|
||||
/* jack detect (gpio/nc/jack detect [12] */
|
||||
unsigned int jack_det_ctrl;
|
||||
};
|
||||
#endif
|
||||
|
@ -259,6 +259,7 @@ typedef int __bitwise snd_pcm_subformat_t;
|
||||
#define SNDRV_PCM_INFO_HALF_DUPLEX 0x00100000 /* only half duplex */
|
||||
#define SNDRV_PCM_INFO_JOINT_DUPLEX 0x00200000 /* playback and capture stream are somewhat correlated */
|
||||
#define SNDRV_PCM_INFO_SYNC_START 0x00400000 /* pcm support some kind of sync go */
|
||||
#define SNDRV_PCM_INFO_NO_PERIOD_WAKEUP 0x00800000 /* period wakeup can be disabled */
|
||||
#define SNDRV_PCM_INFO_FIFO_IN_FRAMES 0x80000000 /* internal kernel flag - FIFO size is in frames */
|
||||
|
||||
typedef int __bitwise snd_pcm_state_t;
|
||||
@ -334,6 +335,8 @@ typedef int snd_pcm_hw_param_t;
|
||||
#define SNDRV_PCM_HW_PARAM_LAST_INTERVAL SNDRV_PCM_HW_PARAM_TICK_TIME
|
||||
|
||||
#define SNDRV_PCM_HW_PARAMS_NORESAMPLE (1<<0) /* avoid rate resampling */
|
||||
#define SNDRV_PCM_HW_PARAMS_EXPORT_BUFFER (1<<1) /* export buffer */
|
||||
#define SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP (1<<2) /* disable period wakeups */
|
||||
|
||||
struct snd_interval {
|
||||
unsigned int min, max;
|
||||
|
@ -160,12 +160,14 @@ static inline struct snd_ctl_elem_id *snd_ctl_build_ioff(struct snd_ctl_elem_id
|
||||
}
|
||||
|
||||
/*
|
||||
* Frequently used control callbacks
|
||||
* Frequently used control callbacks/helpers
|
||||
*/
|
||||
int snd_ctl_boolean_mono_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo);
|
||||
int snd_ctl_boolean_stereo_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo);
|
||||
int snd_ctl_enum_info(struct snd_ctl_elem_info *info, unsigned int channels,
|
||||
unsigned int items, const char *const names[]);
|
||||
|
||||
/*
|
||||
* virtual master control
|
||||
|
@ -28,6 +28,7 @@ enum HDSP_IO_Type {
|
||||
Multiface,
|
||||
H9652,
|
||||
H9632,
|
||||
RPM,
|
||||
Undefined,
|
||||
};
|
||||
|
||||
|
@ -31,8 +31,8 @@
|
||||
/* these minors can still be used for autoloading devices (/dev/aload*) */
|
||||
#define SNDRV_MINOR_CONTROL 0 /* 0 */
|
||||
#define SNDRV_MINOR_GLOBAL 1 /* 1 */
|
||||
#define SNDRV_MINOR_SEQUENCER (SNDRV_MINOR_GLOBAL + 0 * 32)
|
||||
#define SNDRV_MINOR_TIMER (SNDRV_MINOR_GLOBAL + 1 * 32)
|
||||
#define SNDRV_MINOR_SEQUENCER 1 /* SNDRV_MINOR_GLOBAL + 0 * 32 */
|
||||
#define SNDRV_MINOR_TIMER 33 /* SNDRV_MINOR_GLOBAL + 1 * 32 */
|
||||
|
||||
#ifndef CONFIG_SND_DYNAMIC_MINORS
|
||||
/* 2 - 3 (reserved) */
|
||||
|
@ -297,6 +297,7 @@ struct snd_pcm_runtime {
|
||||
unsigned int info;
|
||||
unsigned int rate_num;
|
||||
unsigned int rate_den;
|
||||
unsigned int no_period_wakeup: 1;
|
||||
|
||||
/* -- SW params -- */
|
||||
int tstamp_mode; /* mmap timestamp is updated */
|
||||
|
@ -16,8 +16,6 @@
|
||||
|
||||
#include <linux/list.h>
|
||||
|
||||
#include <sound/soc.h>
|
||||
|
||||
struct snd_pcm_substream;
|
||||
|
||||
/*
|
||||
@ -205,7 +203,7 @@ struct snd_soc_dai_driver {
|
||||
int (*resume)(struct snd_soc_dai *dai);
|
||||
|
||||
/* ops */
|
||||
struct snd_soc_dai_ops *ops;
|
||||
const struct snd_soc_dai_ops *ops;
|
||||
|
||||
/* DAI capabilities */
|
||||
struct snd_soc_pcm_stream capture;
|
||||
|
@ -16,7 +16,6 @@
|
||||
#include <linux/device.h>
|
||||
#include <linux/types.h>
|
||||
#include <sound/control.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
/* widget has no PM register bit */
|
||||
#define SND_SOC_NOPM -1
|
||||
@ -72,6 +71,10 @@
|
||||
wcontrols, wncontrols) \
|
||||
{ .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
|
||||
.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols}
|
||||
#define SND_SOC_DAPM_OUT_DRV(wname, wreg, wshift, winvert,\
|
||||
wcontrols, wncontrols) \
|
||||
{ .id = snd_soc_dapm_out_drv, .name = wname, .reg = wreg, .shift = wshift, \
|
||||
.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols}
|
||||
#define SND_SOC_DAPM_MIXER(wname, wreg, wshift, winvert, \
|
||||
wcontrols, wncontrols)\
|
||||
{ .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
|
||||
@ -90,6 +93,9 @@
|
||||
#define SND_SOC_DAPM_MUX(wname, wreg, wshift, winvert, wcontrols) \
|
||||
{ .id = snd_soc_dapm_mux, .name = wname, .reg = wreg, .shift = wshift, \
|
||||
.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1}
|
||||
#define SND_SOC_DAPM_VIRT_MUX(wname, wreg, wshift, winvert, wcontrols) \
|
||||
{ .id = snd_soc_dapm_virt_mux, .name = wname, .reg = wreg, .shift = wshift, \
|
||||
.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1}
|
||||
#define SND_SOC_DAPM_VALUE_MUX(wname, wreg, wshift, winvert, wcontrols) \
|
||||
{ .id = snd_soc_dapm_value_mux, .name = wname, .reg = wreg, \
|
||||
.shift = wshift, .invert = winvert, .kcontrols = wcontrols, \
|
||||
@ -116,6 +122,11 @@
|
||||
{ .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
|
||||
.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols, \
|
||||
.event = wevent, .event_flags = wflags}
|
||||
#define SND_SOC_DAPM_OUT_DRV_E(wname, wreg, wshift, winvert, wcontrols, \
|
||||
wncontrols, wevent, wflags) \
|
||||
{ .id = snd_soc_dapm_out_drv, .name = wname, .reg = wreg, .shift = wshift, \
|
||||
.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols, \
|
||||
.event = wevent, .event_flags = wflags}
|
||||
#define SND_SOC_DAPM_MIXER_E(wname, wreg, wshift, winvert, wcontrols, \
|
||||
wncontrols, wevent, wflags) \
|
||||
{ .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
|
||||
@ -140,6 +151,11 @@
|
||||
{ .id = snd_soc_dapm_mux, .name = wname, .reg = wreg, .shift = wshift, \
|
||||
.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1, \
|
||||
.event = wevent, .event_flags = wflags}
|
||||
#define SND_SOC_DAPM_VIRT_MUX_E(wname, wreg, wshift, winvert, wcontrols, \
|
||||
wevent, wflags) \
|
||||
{ .id = snd_soc_dapm_virt_mux, .name = wname, .reg = wreg, .shift = wshift, \
|
||||
.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1, \
|
||||
.event = wevent, .event_flags = wflags}
|
||||
|
||||
/* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */
|
||||
#define SOC_PGA_E_ARRAY(wname, wreg, wshift, winvert, wcontrols, \
|
||||
@ -219,13 +235,6 @@
|
||||
.info = snd_soc_info_volsw, \
|
||||
.get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
|
||||
.private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) }
|
||||
#define SOC_DAPM_DOUBLE(xname, reg, shift_left, shift_right, max, invert, \
|
||||
power) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
|
||||
.info = snd_soc_info_volsw, \
|
||||
.get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
|
||||
.private_value = (reg) | ((shift_left) << 8) | ((shift_right) << 12) |\
|
||||
((max) << 16) | ((invert) << 24) }
|
||||
#define SOC_DAPM_SINGLE_TLV(xname, reg, shift, max, invert, tlv_array) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
|
||||
.info = snd_soc_info_volsw, \
|
||||
@ -233,15 +242,6 @@
|
||||
.tlv.p = (tlv_array), \
|
||||
.get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
|
||||
.private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) }
|
||||
#define SOC_DAPM_DOUBLE_TLV(xname, reg, shift_left, shift_right, max, invert, \
|
||||
power, tlv_array) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | SNDRV_CTL_ELEM_ACCESS_READWRITE,\
|
||||
.tlv.p = (tlv_array), \
|
||||
.info = snd_soc_info_volsw, \
|
||||
.get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
|
||||
.private_value = (reg) | ((shift_left) << 8) | ((shift_right) << 12) |\
|
||||
((max) << 16) | ((invert) << 24) }
|
||||
#define SOC_DAPM_ENUM(xname, xenum) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
|
||||
.info = snd_soc_info_enum_double, \
|
||||
@ -297,6 +297,7 @@ enum snd_soc_dapm_type;
|
||||
struct snd_soc_dapm_path;
|
||||
struct snd_soc_dapm_pin;
|
||||
struct snd_soc_dapm_route;
|
||||
struct snd_soc_dapm_context;
|
||||
|
||||
int dapm_reg_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event);
|
||||
@ -324,16 +325,16 @@ int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *uncontrol);
|
||||
int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *uncontrol);
|
||||
int snd_soc_dapm_new_control(struct snd_soc_codec *codec,
|
||||
int snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
|
||||
const struct snd_soc_dapm_widget *widget);
|
||||
int snd_soc_dapm_new_controls(struct snd_soc_codec *codec,
|
||||
int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm,
|
||||
const struct snd_soc_dapm_widget *widget,
|
||||
int num);
|
||||
|
||||
/* dapm path setup */
|
||||
int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec);
|
||||
void snd_soc_dapm_free(struct snd_soc_codec *codec);
|
||||
int snd_soc_dapm_add_routes(struct snd_soc_codec *codec,
|
||||
int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm);
|
||||
void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm);
|
||||
int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
|
||||
const struct snd_soc_dapm_route *route, int num);
|
||||
|
||||
/* dapm events */
|
||||
@ -343,27 +344,33 @@ void snd_soc_dapm_shutdown(struct snd_soc_card *card);
|
||||
|
||||
/* dapm sys fs - used by the core */
|
||||
int snd_soc_dapm_sys_add(struct device *dev);
|
||||
void snd_soc_dapm_debugfs_init(struct snd_soc_codec *codec);
|
||||
void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm);
|
||||
|
||||
/* dapm audio pin control and status */
|
||||
int snd_soc_dapm_enable_pin(struct snd_soc_codec *codec, const char *pin);
|
||||
int snd_soc_dapm_disable_pin(struct snd_soc_codec *codec, const char *pin);
|
||||
int snd_soc_dapm_nc_pin(struct snd_soc_codec *codec, const char *pin);
|
||||
int snd_soc_dapm_get_pin_status(struct snd_soc_codec *codec, const char *pin);
|
||||
int snd_soc_dapm_sync(struct snd_soc_codec *codec);
|
||||
int snd_soc_dapm_force_enable_pin(struct snd_soc_codec *codec,
|
||||
int snd_soc_dapm_enable_pin(struct snd_soc_dapm_context *dapm,
|
||||
const char *pin);
|
||||
int snd_soc_dapm_disable_pin(struct snd_soc_dapm_context *dapm,
|
||||
const char *pin);
|
||||
int snd_soc_dapm_nc_pin(struct snd_soc_dapm_context *dapm, const char *pin);
|
||||
int snd_soc_dapm_get_pin_status(struct snd_soc_dapm_context *dapm,
|
||||
const char *pin);
|
||||
int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm);
|
||||
int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm,
|
||||
const char *pin);
|
||||
int snd_soc_dapm_ignore_suspend(struct snd_soc_codec *codec, const char *pin);
|
||||
int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm,
|
||||
const char *pin);
|
||||
|
||||
/* dapm widget types */
|
||||
enum snd_soc_dapm_type {
|
||||
snd_soc_dapm_input = 0, /* input pin */
|
||||
snd_soc_dapm_output, /* output pin */
|
||||
snd_soc_dapm_mux, /* selects 1 analog signal from many inputs */
|
||||
snd_soc_dapm_virt_mux, /* virtual version of snd_soc_dapm_mux */
|
||||
snd_soc_dapm_value_mux, /* selects 1 analog signal from many inputs */
|
||||
snd_soc_dapm_mixer, /* mixes several analog signals together */
|
||||
snd_soc_dapm_mixer_named_ctl, /* mixer with named controls */
|
||||
snd_soc_dapm_pga, /* programmable gain/attenuation (volume) */
|
||||
snd_soc_dapm_out_drv, /* output driver */
|
||||
snd_soc_dapm_adc, /* analog to digital converter */
|
||||
snd_soc_dapm_dac, /* digital to analog converter */
|
||||
snd_soc_dapm_micbias, /* microphone bias (power) */
|
||||
@ -425,6 +432,7 @@ struct snd_soc_dapm_widget {
|
||||
char *sname; /* stream name */
|
||||
struct snd_soc_codec *codec;
|
||||
struct list_head list;
|
||||
struct snd_soc_dapm_context *dapm;
|
||||
|
||||
/* dapm control */
|
||||
short reg; /* negative reg = no direct dapm */
|
||||
@ -461,4 +469,35 @@ struct snd_soc_dapm_widget {
|
||||
struct list_head power_list;
|
||||
};
|
||||
|
||||
struct snd_soc_dapm_update {
|
||||
struct snd_soc_dapm_widget *widget;
|
||||
struct snd_kcontrol *kcontrol;
|
||||
int reg;
|
||||
int mask;
|
||||
int val;
|
||||
};
|
||||
|
||||
/* DAPM context */
|
||||
struct snd_soc_dapm_context {
|
||||
int n_widgets; /* number of widgets in this context */
|
||||
enum snd_soc_bias_level bias_level;
|
||||
enum snd_soc_bias_level suspend_bias_level;
|
||||
struct delayed_work delayed_work;
|
||||
unsigned int idle_bias_off:1; /* Use BIAS_OFF instead of STANDBY */
|
||||
|
||||
struct snd_soc_dapm_update *update;
|
||||
|
||||
struct device *dev; /* from parent - for debug */
|
||||
struct snd_soc_codec *codec; /* parent codec */
|
||||
struct snd_soc_card *card; /* parent card */
|
||||
|
||||
/* used during DAPM updates */
|
||||
int dev_power;
|
||||
struct list_head list;
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
struct dentry *debugfs_dapm;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -222,10 +222,8 @@ enum snd_soc_bias_level {
|
||||
|
||||
struct snd_jack;
|
||||
struct snd_soc_card;
|
||||
struct snd_soc_device;
|
||||
struct snd_soc_pcm_stream;
|
||||
struct snd_soc_ops;
|
||||
struct snd_soc_dai_mode;
|
||||
struct snd_soc_pcm_runtime;
|
||||
struct snd_soc_dai;
|
||||
struct snd_soc_dai_driver;
|
||||
@ -235,9 +233,10 @@ struct snd_soc_platform_driver;
|
||||
struct snd_soc_codec;
|
||||
struct snd_soc_codec_driver;
|
||||
struct soc_enum;
|
||||
struct snd_soc_ac97_ops;
|
||||
struct snd_soc_jack;
|
||||
struct snd_soc_jack_pin;
|
||||
struct snd_soc_cache_ops;
|
||||
#include <sound/soc-dapm.h>
|
||||
|
||||
#ifdef CONFIG_GPIOLIB
|
||||
struct snd_soc_jack_gpio;
|
||||
@ -253,17 +252,30 @@ enum snd_soc_control_type {
|
||||
SND_SOC_SPI,
|
||||
};
|
||||
|
||||
enum snd_soc_compress_type {
|
||||
SND_SOC_FLAT_COMPRESSION = 1,
|
||||
SND_SOC_LZO_COMPRESSION,
|
||||
SND_SOC_RBTREE_COMPRESSION
|
||||
};
|
||||
|
||||
int snd_soc_register_platform(struct device *dev,
|
||||
struct snd_soc_platform_driver *platform_drv);
|
||||
void snd_soc_unregister_platform(struct device *dev);
|
||||
int snd_soc_register_codec(struct device *dev,
|
||||
struct snd_soc_codec_driver *codec_drv,
|
||||
const struct snd_soc_codec_driver *codec_drv,
|
||||
struct snd_soc_dai_driver *dai_drv, int num_dai);
|
||||
void snd_soc_unregister_codec(struct device *dev);
|
||||
int snd_soc_codec_volatile_register(struct snd_soc_codec *codec, int reg);
|
||||
int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
|
||||
int addr_bits, int data_bits,
|
||||
enum snd_soc_control_type control);
|
||||
int snd_soc_cache_sync(struct snd_soc_codec *codec);
|
||||
int snd_soc_cache_init(struct snd_soc_codec *codec);
|
||||
int snd_soc_cache_exit(struct snd_soc_codec *codec);
|
||||
int snd_soc_cache_write(struct snd_soc_codec *codec,
|
||||
unsigned int reg, unsigned int value);
|
||||
int snd_soc_cache_read(struct snd_soc_codec *codec,
|
||||
unsigned int reg, unsigned int *value);
|
||||
|
||||
/* Utility functions to get clock rates from various things */
|
||||
int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots);
|
||||
@ -420,23 +432,37 @@ struct snd_soc_ops {
|
||||
int (*trigger)(struct snd_pcm_substream *, int);
|
||||
};
|
||||
|
||||
/* SoC cache ops */
|
||||
struct snd_soc_cache_ops {
|
||||
const char *name;
|
||||
enum snd_soc_compress_type id;
|
||||
int (*init)(struct snd_soc_codec *codec);
|
||||
int (*exit)(struct snd_soc_codec *codec);
|
||||
int (*read)(struct snd_soc_codec *codec, unsigned int reg,
|
||||
unsigned int *value);
|
||||
int (*write)(struct snd_soc_codec *codec, unsigned int reg,
|
||||
unsigned int value);
|
||||
int (*sync)(struct snd_soc_codec *codec);
|
||||
};
|
||||
|
||||
/* SoC Audio Codec device */
|
||||
struct snd_soc_codec {
|
||||
const char *name;
|
||||
const char *name_prefix;
|
||||
int id;
|
||||
struct device *dev;
|
||||
struct snd_soc_codec_driver *driver;
|
||||
const struct snd_soc_codec_driver *driver;
|
||||
|
||||
struct mutex mutex;
|
||||
struct snd_soc_card *card;
|
||||
struct list_head list;
|
||||
struct list_head card_list;
|
||||
int num_dai;
|
||||
enum snd_soc_compress_type compress_type;
|
||||
|
||||
/* runtime */
|
||||
struct snd_ac97 *ac97; /* for ad-hoc ac97 devices */
|
||||
unsigned int active;
|
||||
unsigned int idle_bias_off:1; /* Use BIAS_OFF instead of STANDBY */
|
||||
unsigned int cache_only:1; /* Suppress writes to hardware */
|
||||
unsigned int cache_sync:1; /* Cache needs to be synced to hardware */
|
||||
unsigned int suspended:1; /* Codec is in suspend PM state */
|
||||
@ -444,25 +470,25 @@ struct snd_soc_codec {
|
||||
unsigned int ac97_registered:1; /* Codec has been AC97 registered */
|
||||
unsigned int ac97_created:1; /* Codec has been created by SoC */
|
||||
unsigned int sysfs_registered:1; /* codec has been sysfs registered */
|
||||
unsigned int cache_init:1; /* codec cache has been initialized */
|
||||
|
||||
/* codec IO */
|
||||
void *control_data; /* codec control (i2c/3wire) data */
|
||||
hw_write_t hw_write;
|
||||
unsigned int (*hw_read)(struct snd_soc_codec *, unsigned int);
|
||||
unsigned int (*read)(struct snd_soc_codec *, unsigned int);
|
||||
int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
|
||||
void *reg_cache;
|
||||
const void *reg_def_copy;
|
||||
const struct snd_soc_cache_ops *cache_ops;
|
||||
struct mutex cache_rw_mutex;
|
||||
|
||||
/* dapm */
|
||||
u32 pop_time;
|
||||
struct list_head dapm_widgets;
|
||||
struct list_head dapm_paths;
|
||||
enum snd_soc_bias_level bias_level;
|
||||
enum snd_soc_bias_level suspend_bias_level;
|
||||
struct delayed_work delayed_work;
|
||||
struct snd_soc_dapm_context dapm;
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
struct dentry *debugfs_codec_root;
|
||||
struct dentry *debugfs_reg;
|
||||
struct dentry *debugfs_pop_time;
|
||||
struct dentry *debugfs_dapm;
|
||||
#endif
|
||||
};
|
||||
@ -488,6 +514,7 @@ struct snd_soc_codec_driver {
|
||||
short reg_cache_step;
|
||||
short reg_word_size;
|
||||
const void *reg_cache_default;
|
||||
enum snd_soc_compress_type compress_type;
|
||||
|
||||
/* codec bias level */
|
||||
int (*set_bias_level)(struct snd_soc_codec *,
|
||||
@ -554,6 +581,30 @@ struct snd_soc_dai_link {
|
||||
struct snd_soc_ops *ops;
|
||||
};
|
||||
|
||||
struct snd_soc_codec_conf {
|
||||
const char *dev_name;
|
||||
|
||||
/*
|
||||
* optional map of kcontrol, widget and path name prefixes that are
|
||||
* associated per device
|
||||
*/
|
||||
const char *name_prefix;
|
||||
|
||||
/*
|
||||
* set this to the desired compression type if you want to
|
||||
* override the one supplied in codec->driver->compress_type
|
||||
*/
|
||||
enum snd_soc_compress_type compress_type;
|
||||
};
|
||||
|
||||
struct snd_soc_aux_dev {
|
||||
const char *name; /* Codec name */
|
||||
const char *codec_name; /* for multi-codec */
|
||||
|
||||
/* codec/machine specific init - e.g. add machine controls */
|
||||
int (*init)(struct snd_soc_dapm_context *dapm);
|
||||
};
|
||||
|
||||
/* SoC card */
|
||||
struct snd_soc_card {
|
||||
const char *name;
|
||||
@ -579,6 +630,8 @@ struct snd_soc_card {
|
||||
/* callbacks */
|
||||
int (*set_bias_level)(struct snd_soc_card *,
|
||||
enum snd_soc_bias_level level);
|
||||
int (*set_bias_level_post)(struct snd_soc_card *,
|
||||
enum snd_soc_bias_level level);
|
||||
|
||||
long pmdown_time;
|
||||
|
||||
@ -588,12 +641,35 @@ struct snd_soc_card {
|
||||
struct snd_soc_pcm_runtime *rtd;
|
||||
int num_rtd;
|
||||
|
||||
/* optional codec specific configuration */
|
||||
struct snd_soc_codec_conf *codec_conf;
|
||||
int num_configs;
|
||||
|
||||
/*
|
||||
* optional auxiliary devices such as amplifiers or codecs with DAI
|
||||
* link unused
|
||||
*/
|
||||
struct snd_soc_aux_dev *aux_dev;
|
||||
int num_aux_devs;
|
||||
struct snd_soc_pcm_runtime *rtd_aux;
|
||||
int num_aux_rtd;
|
||||
|
||||
struct work_struct deferred_resume_work;
|
||||
|
||||
/* lists of probed devices belonging to this card */
|
||||
struct list_head codec_dev_list;
|
||||
struct list_head platform_dev_list;
|
||||
struct list_head dai_dev_list;
|
||||
|
||||
struct list_head widgets;
|
||||
struct list_head paths;
|
||||
struct list_head dapm_list;
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
struct dentry *debugfs_card_root;
|
||||
struct dentry *debugfs_pop_time;
|
||||
#endif
|
||||
u32 pop_time;
|
||||
};
|
||||
|
||||
/* SoC machine DAI configuration, glues a codec and cpu DAI together */
|
||||
@ -639,17 +715,9 @@ struct soc_enum {
|
||||
};
|
||||
|
||||
/* codec IO */
|
||||
static inline unsigned int snd_soc_read(struct snd_soc_codec *codec,
|
||||
unsigned int reg)
|
||||
{
|
||||
return codec->driver->read(codec, reg);
|
||||
}
|
||||
|
||||
static inline unsigned int snd_soc_write(struct snd_soc_codec *codec,
|
||||
unsigned int reg, unsigned int val)
|
||||
{
|
||||
return codec->driver->write(codec, reg, val);
|
||||
}
|
||||
unsigned int snd_soc_read(struct snd_soc_codec *codec, unsigned int reg);
|
||||
unsigned int snd_soc_write(struct snd_soc_codec *codec,
|
||||
unsigned int reg, unsigned int val);
|
||||
|
||||
/* device driver data */
|
||||
|
||||
|
235
include/trace/events/asoc.h
Normal file
235
include/trace/events/asoc.h
Normal file
@ -0,0 +1,235 @@
|
||||
#undef TRACE_SYSTEM
|
||||
#define TRACE_SYSTEM asoc
|
||||
|
||||
#if !defined(_TRACE_ASOC_H) || defined(TRACE_HEADER_MULTI_READ)
|
||||
#define _TRACE_ASOC_H
|
||||
|
||||
#include <linux/ktime.h>
|
||||
#include <linux/tracepoint.h>
|
||||
|
||||
struct snd_soc_jack;
|
||||
struct snd_soc_codec;
|
||||
struct snd_soc_card;
|
||||
struct snd_soc_dapm_widget;
|
||||
|
||||
/*
|
||||
* Log register events
|
||||
*/
|
||||
DECLARE_EVENT_CLASS(snd_soc_reg,
|
||||
|
||||
TP_PROTO(struct snd_soc_codec *codec, unsigned int reg,
|
||||
unsigned int val),
|
||||
|
||||
TP_ARGS(codec, reg, val),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__string( name, codec->name )
|
||||
__field( int, id )
|
||||
__field( unsigned int, reg )
|
||||
__field( unsigned int, val )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__assign_str(name, codec->name);
|
||||
__entry->id = codec->id;
|
||||
__entry->reg = reg;
|
||||
__entry->val = val;
|
||||
),
|
||||
|
||||
TP_printk("codec=%s.%d reg=%x val=%x", __get_str(name),
|
||||
(int)__entry->id, (unsigned int)__entry->reg,
|
||||
(unsigned int)__entry->val)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(snd_soc_reg, snd_soc_reg_write,
|
||||
|
||||
TP_PROTO(struct snd_soc_codec *codec, unsigned int reg,
|
||||
unsigned int val),
|
||||
|
||||
TP_ARGS(codec, reg, val)
|
||||
|
||||
);
|
||||
|
||||
DEFINE_EVENT(snd_soc_reg, snd_soc_reg_read,
|
||||
|
||||
TP_PROTO(struct snd_soc_codec *codec, unsigned int reg,
|
||||
unsigned int val),
|
||||
|
||||
TP_ARGS(codec, reg, val)
|
||||
|
||||
);
|
||||
|
||||
DECLARE_EVENT_CLASS(snd_soc_card,
|
||||
|
||||
TP_PROTO(struct snd_soc_card *card, int val),
|
||||
|
||||
TP_ARGS(card, val),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__string( name, card->name )
|
||||
__field( int, val )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__assign_str(name, card->name);
|
||||
__entry->val = val;
|
||||
),
|
||||
|
||||
TP_printk("card=%s val=%d", __get_str(name), (int)__entry->val)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(snd_soc_card, snd_soc_bias_level_start,
|
||||
|
||||
TP_PROTO(struct snd_soc_card *card, int val),
|
||||
|
||||
TP_ARGS(card, val)
|
||||
|
||||
);
|
||||
|
||||
DEFINE_EVENT(snd_soc_card, snd_soc_bias_level_done,
|
||||
|
||||
TP_PROTO(struct snd_soc_card *card, int val),
|
||||
|
||||
TP_ARGS(card, val)
|
||||
|
||||
);
|
||||
|
||||
DECLARE_EVENT_CLASS(snd_soc_dapm_basic,
|
||||
|
||||
TP_PROTO(struct snd_soc_card *card),
|
||||
|
||||
TP_ARGS(card),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__string( name, card->name )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__assign_str(name, card->name);
|
||||
),
|
||||
|
||||
TP_printk("card=%s", __get_str(name))
|
||||
);
|
||||
|
||||
DEFINE_EVENT(snd_soc_dapm_basic, snd_soc_dapm_start,
|
||||
|
||||
TP_PROTO(struct snd_soc_card *card),
|
||||
|
||||
TP_ARGS(card)
|
||||
|
||||
);
|
||||
|
||||
DEFINE_EVENT(snd_soc_dapm_basic, snd_soc_dapm_done,
|
||||
|
||||
TP_PROTO(struct snd_soc_card *card),
|
||||
|
||||
TP_ARGS(card)
|
||||
|
||||
);
|
||||
|
||||
DECLARE_EVENT_CLASS(snd_soc_dapm_widget,
|
||||
|
||||
TP_PROTO(struct snd_soc_dapm_widget *w, int val),
|
||||
|
||||
TP_ARGS(w, val),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__string( name, w->name )
|
||||
__field( int, val )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__assign_str(name, w->name);
|
||||
__entry->val = val;
|
||||
),
|
||||
|
||||
TP_printk("widget=%s val=%d", __get_str(name),
|
||||
(int)__entry->val)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(snd_soc_dapm_widget, snd_soc_dapm_widget_power,
|
||||
|
||||
TP_PROTO(struct snd_soc_dapm_widget *w, int val),
|
||||
|
||||
TP_ARGS(w, val)
|
||||
|
||||
);
|
||||
|
||||
DEFINE_EVENT(snd_soc_dapm_widget, snd_soc_dapm_widget_event_start,
|
||||
|
||||
TP_PROTO(struct snd_soc_dapm_widget *w, int val),
|
||||
|
||||
TP_ARGS(w, val)
|
||||
|
||||
);
|
||||
|
||||
DEFINE_EVENT(snd_soc_dapm_widget, snd_soc_dapm_widget_event_done,
|
||||
|
||||
TP_PROTO(struct snd_soc_dapm_widget *w, int val),
|
||||
|
||||
TP_ARGS(w, val)
|
||||
|
||||
);
|
||||
|
||||
TRACE_EVENT(snd_soc_jack_irq,
|
||||
|
||||
TP_PROTO(const char *name),
|
||||
|
||||
TP_ARGS(name),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__string( name, name )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__assign_str(name, name);
|
||||
),
|
||||
|
||||
TP_printk("%s", __get_str(name))
|
||||
);
|
||||
|
||||
TRACE_EVENT(snd_soc_jack_report,
|
||||
|
||||
TP_PROTO(struct snd_soc_jack *jack, int mask, int val),
|
||||
|
||||
TP_ARGS(jack, mask, val),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__string( name, jack->jack->name )
|
||||
__field( int, mask )
|
||||
__field( int, val )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__assign_str(name, jack->jack->name);
|
||||
__entry->mask = mask;
|
||||
__entry->val = val;
|
||||
),
|
||||
|
||||
TP_printk("jack=%s %x/%x", __get_str(name), (int)__entry->val,
|
||||
(int)__entry->mask)
|
||||
);
|
||||
|
||||
TRACE_EVENT(snd_soc_jack_notify,
|
||||
|
||||
TP_PROTO(struct snd_soc_jack *jack, int val),
|
||||
|
||||
TP_ARGS(jack, val),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__string( name, jack->jack->name )
|
||||
__field( int, val )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__assign_str(name, jack->jack->name);
|
||||
__entry->val = val;
|
||||
),
|
||||
|
||||
TP_printk("jack=%s %x", __get_str(name), (int)__entry->val)
|
||||
);
|
||||
|
||||
#endif /* _TRACE_ASOC_H */
|
||||
|
||||
/* This part must be outside protection */
|
||||
#include <trace/define_trace.h>
|
@ -19,8 +19,8 @@
|
||||
|
||||
/*
|
||||
* Let drivers decide whether they want to support given codec from their
|
||||
* probe method. Drivers have direct access to the struct snd_ac97 structure and may
|
||||
* decide based on the id field amongst other things.
|
||||
* probe method. Drivers have direct access to the struct snd_ac97
|
||||
* structure and may decide based on the id field amongst other things.
|
||||
*/
|
||||
static int ac97_bus_match(struct device *dev, struct device_driver *drv)
|
||||
{
|
||||
|
@ -1114,7 +1114,6 @@ static int onyx_i2c_remove(struct i2c_client *client)
|
||||
of_node_put(onyx->codec.node);
|
||||
if (onyx->codec_info)
|
||||
kfree(onyx->codec_info);
|
||||
i2c_set_clientdata(client, onyx);
|
||||
kfree(onyx);
|
||||
return 0;
|
||||
}
|
||||
|
@ -287,10 +287,9 @@ static void ftr_gpio_exit(struct gpio_runtime *rt)
|
||||
free_irq(linein_detect_irq, &rt->line_in_notify);
|
||||
if (rt->line_out_notify.gpio_private)
|
||||
free_irq(lineout_detect_irq, &rt->line_out_notify);
|
||||
cancel_delayed_work(&rt->headphone_notify.work);
|
||||
cancel_delayed_work(&rt->line_in_notify.work);
|
||||
cancel_delayed_work(&rt->line_out_notify.work);
|
||||
flush_scheduled_work();
|
||||
cancel_delayed_work_sync(&rt->headphone_notify.work);
|
||||
cancel_delayed_work_sync(&rt->line_in_notify.work);
|
||||
cancel_delayed_work_sync(&rt->line_out_notify.work);
|
||||
mutex_destroy(&rt->headphone_notify.mutex);
|
||||
mutex_destroy(&rt->line_in_notify.mutex);
|
||||
mutex_destroy(&rt->line_out_notify.mutex);
|
||||
|
@ -107,10 +107,9 @@ static void pmf_gpio_exit(struct gpio_runtime *rt)
|
||||
|
||||
/* make sure no work is pending before freeing
|
||||
* all things */
|
||||
cancel_delayed_work(&rt->headphone_notify.work);
|
||||
cancel_delayed_work(&rt->line_in_notify.work);
|
||||
cancel_delayed_work(&rt->line_out_notify.work);
|
||||
flush_scheduled_work();
|
||||
cancel_delayed_work_sync(&rt->headphone_notify.work);
|
||||
cancel_delayed_work_sync(&rt->line_in_notify.work);
|
||||
cancel_delayed_work_sync(&rt->line_out_notify.work);
|
||||
|
||||
mutex_destroy(&rt->headphone_notify.mutex);
|
||||
mutex_destroy(&rt->line_in_notify.mutex);
|
||||
|
@ -1488,7 +1488,7 @@ int snd_ctl_create(struct snd_card *card)
|
||||
}
|
||||
|
||||
/*
|
||||
* Frequently used control callbacks
|
||||
* Frequently used control callbacks/helpers
|
||||
*/
|
||||
int snd_ctl_boolean_mono_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
@ -1513,3 +1513,29 @@ int snd_ctl_boolean_stereo_info(struct snd_kcontrol *kcontrol,
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(snd_ctl_boolean_stereo_info);
|
||||
|
||||
/**
|
||||
* snd_ctl_enum_info - fills the info structure for an enumerated control
|
||||
* @info: the structure to be filled
|
||||
* @channels: the number of the control's channels; often one
|
||||
* @items: the number of control values; also the size of @names
|
||||
* @names: an array containing the names of all control values
|
||||
*
|
||||
* Sets all required fields in @info to their appropriate values.
|
||||
* If the control's accessibility is not the default (readable and writable),
|
||||
* the caller has to fill @info->access.
|
||||
*/
|
||||
int snd_ctl_enum_info(struct snd_ctl_elem_info *info, unsigned int channels,
|
||||
unsigned int items, const char *const names[])
|
||||
{
|
||||
info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
|
||||
info->count = channels;
|
||||
info->value.enumerated.items = items;
|
||||
if (info->value.enumerated.item >= items)
|
||||
info->value.enumerated.item = items - 1;
|
||||
strlcpy(info->value.enumerated.name,
|
||||
names[info->value.enumerated.item],
|
||||
sizeof(info->value.enumerated.name));
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(snd_ctl_enum_info);
|
||||
|
@ -453,8 +453,10 @@ static int snd_pcm_hw_param_near(struct snd_pcm_substream *pcm,
|
||||
} else {
|
||||
*params = *save;
|
||||
max = snd_pcm_hw_param_max(pcm, params, var, max, &maxdir);
|
||||
if (max < 0)
|
||||
if (max < 0) {
|
||||
kfree(save);
|
||||
return max;
|
||||
}
|
||||
last = 1;
|
||||
}
|
||||
_end:
|
||||
|
@ -373,6 +373,27 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
|
||||
(unsigned long)new_hw_ptr,
|
||||
(unsigned long)runtime->hw_ptr_base);
|
||||
}
|
||||
|
||||
if (runtime->no_period_wakeup) {
|
||||
/*
|
||||
* Without regular period interrupts, we have to check
|
||||
* the elapsed time to detect xruns.
|
||||
*/
|
||||
jdelta = jiffies - runtime->hw_ptr_jiffies;
|
||||
if (jdelta < runtime->hw_ptr_buffer_jiffies / 2)
|
||||
goto no_delta_check;
|
||||
hdelta = jdelta - delta * HZ / runtime->rate;
|
||||
while (hdelta > runtime->hw_ptr_buffer_jiffies / 2 + 1) {
|
||||
delta += runtime->buffer_size;
|
||||
hw_base += runtime->buffer_size;
|
||||
if (hw_base >= runtime->boundary)
|
||||
hw_base = 0;
|
||||
new_hw_ptr = hw_base + pos;
|
||||
hdelta -= runtime->hw_ptr_buffer_jiffies;
|
||||
}
|
||||
goto no_delta_check;
|
||||
}
|
||||
|
||||
/* something must be really wrong */
|
||||
if (delta >= runtime->buffer_size + runtime->period_size) {
|
||||
hw_ptr_error(substream,
|
||||
@ -442,6 +463,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
|
||||
(long)old_hw_ptr);
|
||||
}
|
||||
|
||||
no_delta_check:
|
||||
if (runtime->status->hw_ptr == new_hw_ptr)
|
||||
return 0;
|
||||
|
||||
|
@ -422,6 +422,9 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
runtime->info = params->info;
|
||||
runtime->rate_num = params->rate_num;
|
||||
runtime->rate_den = params->rate_den;
|
||||
runtime->no_period_wakeup =
|
||||
(params->info & SNDRV_PCM_INFO_NO_PERIOD_WAKEUP) &&
|
||||
(params->flags & SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP);
|
||||
|
||||
bits = snd_pcm_format_physical_width(runtime->format);
|
||||
runtime->sample_bits = bits;
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "seq_timer.h"
|
||||
#include "seq_system.h"
|
||||
#include "seq_info.h"
|
||||
#include <sound/minors.h>
|
||||
#include <sound/seq_device.h>
|
||||
|
||||
#if defined(CONFIG_SND_SEQ_DUMMY_MODULE)
|
||||
@ -73,6 +74,9 @@ MODULE_PARM_DESC(seq_default_timer_subdevice, "The default timer subdevice numbe
|
||||
module_param(seq_default_timer_resolution, int, 0644);
|
||||
MODULE_PARM_DESC(seq_default_timer_resolution, "The default timer resolution in Hz.");
|
||||
|
||||
MODULE_ALIAS_CHARDEV(CONFIG_SND_MAJOR, SNDRV_MINOR_SEQUENCER);
|
||||
MODULE_ALIAS("devname:snd/seq");
|
||||
|
||||
/*
|
||||
* INIT PART
|
||||
*/
|
||||
|
@ -188,14 +188,22 @@ static const struct file_operations snd_fops =
|
||||
};
|
||||
|
||||
#ifdef CONFIG_SND_DYNAMIC_MINORS
|
||||
static int snd_find_free_minor(void)
|
||||
static int snd_find_free_minor(int type)
|
||||
{
|
||||
int minor;
|
||||
|
||||
/* static minors for module auto loading */
|
||||
if (type == SNDRV_DEVICE_TYPE_SEQUENCER)
|
||||
return SNDRV_MINOR_SEQUENCER;
|
||||
if (type == SNDRV_DEVICE_TYPE_TIMER)
|
||||
return SNDRV_MINOR_TIMER;
|
||||
|
||||
for (minor = 0; minor < ARRAY_SIZE(snd_minors); ++minor) {
|
||||
/* skip minors still used statically for autoloading devices */
|
||||
if (SNDRV_MINOR_DEVICE(minor) == SNDRV_MINOR_CONTROL ||
|
||||
minor == SNDRV_MINOR_SEQUENCER)
|
||||
/* skip static minors still used for module auto loading */
|
||||
if (SNDRV_MINOR_DEVICE(minor) == SNDRV_MINOR_CONTROL)
|
||||
continue;
|
||||
if (minor == SNDRV_MINOR_SEQUENCER ||
|
||||
minor == SNDRV_MINOR_TIMER)
|
||||
continue;
|
||||
if (!snd_minors[minor])
|
||||
return minor;
|
||||
@ -269,7 +277,7 @@ int snd_register_device_for_dev(int type, struct snd_card *card, int dev,
|
||||
preg->private_data = private_data;
|
||||
mutex_lock(&sound_mutex);
|
||||
#ifdef CONFIG_SND_DYNAMIC_MINORS
|
||||
minor = snd_find_free_minor();
|
||||
minor = snd_find_free_minor(type);
|
||||
#else
|
||||
minor = snd_kernel_minor(type, card, dev);
|
||||
if (minor >= 0 && snd_minors[minor])
|
||||
|
@ -34,8 +34,8 @@
|
||||
#include <sound/initval.h>
|
||||
#include <linux/kmod.h>
|
||||
|
||||
#if defined(CONFIG_SND_HPET) || defined(CONFIG_SND_HPET_MODULE)
|
||||
#define DEFAULT_TIMER_LIMIT 3
|
||||
#if defined(CONFIG_SND_HRTIMER) || defined(CONFIG_SND_HRTIMER_MODULE)
|
||||
#define DEFAULT_TIMER_LIMIT 4
|
||||
#elif defined(CONFIG_SND_RTCTIMER) || defined(CONFIG_SND_RTCTIMER_MODULE)
|
||||
#define DEFAULT_TIMER_LIMIT 2
|
||||
#else
|
||||
@ -52,6 +52,9 @@ MODULE_PARM_DESC(timer_limit, "Maximum global timers in system.");
|
||||
module_param(timer_tstamp_monotonic, int, 0444);
|
||||
MODULE_PARM_DESC(timer_tstamp_monotonic, "Use posix monotonic clock source for timestamps (default).");
|
||||
|
||||
MODULE_ALIAS_CHARDEV(CONFIG_SND_MAJOR, SNDRV_MINOR_TIMER);
|
||||
MODULE_ALIAS("devname:snd/timer");
|
||||
|
||||
struct snd_timer_user {
|
||||
struct snd_timer_instance *timeri;
|
||||
int tread; /* enhanced read with timestamps and events */
|
||||
|
@ -1143,8 +1143,8 @@ snd_ml403_ac97cr_create(struct snd_card *card, struct platform_device *pfdev,
|
||||
(resource->start) + 1);
|
||||
if (ml403_ac97cr->port == NULL) {
|
||||
snd_printk(KERN_ERR SND_ML403_AC97CR_DRIVER ": "
|
||||
"unable to remap memory region (%x to %x)\n",
|
||||
resource->start, resource->end);
|
||||
"unable to remap memory region (%pR)\n",
|
||||
resource);
|
||||
snd_ml403_ac97cr_free(ml403_ac97cr);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
@ -57,8 +57,7 @@ static void snd_ak4113_free(struct ak4113 *chip)
|
||||
{
|
||||
chip->init = 1; /* don't schedule new work */
|
||||
mb();
|
||||
cancel_delayed_work(&chip->work);
|
||||
flush_scheduled_work();
|
||||
cancel_delayed_work_sync(&chip->work);
|
||||
kfree(chip);
|
||||
}
|
||||
|
||||
@ -141,7 +140,7 @@ void snd_ak4113_reinit(struct ak4113 *chip)
|
||||
{
|
||||
chip->init = 1;
|
||||
mb();
|
||||
flush_scheduled_work();
|
||||
flush_delayed_work_sync(&chip->work);
|
||||
ak4113_init_regs(chip);
|
||||
/* bring up statistics / event queing */
|
||||
chip->init = 0;
|
||||
|
@ -67,8 +67,7 @@ static void snd_ak4114_free(struct ak4114 *chip)
|
||||
{
|
||||
chip->init = 1; /* don't schedule new work */
|
||||
mb();
|
||||
cancel_delayed_work(&chip->work);
|
||||
flush_scheduled_work();
|
||||
cancel_delayed_work_sync(&chip->work);
|
||||
kfree(chip);
|
||||
}
|
||||
|
||||
@ -154,7 +153,7 @@ void snd_ak4114_reinit(struct ak4114 *chip)
|
||||
{
|
||||
chip->init = 1;
|
||||
mb();
|
||||
flush_scheduled_work();
|
||||
flush_delayed_work_sync(&chip->work);
|
||||
ak4114_init_regs(chip);
|
||||
/* bring up statistics / event queing */
|
||||
chip->init = 0;
|
||||
|
@ -209,7 +209,7 @@ config SND_OXYGEN_LIB
|
||||
tristate
|
||||
|
||||
config SND_OXYGEN
|
||||
tristate "C-Media 8788 (Oxygen)"
|
||||
tristate "C-Media 8786, 8787, 8788 (Oxygen)"
|
||||
select SND_OXYGEN_LIB
|
||||
select SND_PCM
|
||||
select SND_MPU401_UART
|
||||
@ -217,13 +217,18 @@ config SND_OXYGEN
|
||||
Say Y here to include support for sound cards based on the
|
||||
C-Media CMI8788 (Oxygen HD Audio) chip:
|
||||
* Asound A-8788
|
||||
* Asus Xonar DG
|
||||
* AuzenTech X-Meridian
|
||||
* AuzenTech X-Meridian 2G
|
||||
* Bgears b-Enspirer
|
||||
* Club3D Theatron DTS
|
||||
* HT-Omega Claro (plus)
|
||||
* HT-Omega Claro halo (XT)
|
||||
* Kuroutoshikou CMI8787-HG2PCI
|
||||
* Razer Barracuda AC-1
|
||||
* Sondigo Inferno
|
||||
* TempoTec/MediaTek HiFier Fantasia
|
||||
* TempoTec/MediaTek HiFier Serenade
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called snd-oxygen.
|
||||
@ -578,18 +583,6 @@ config SND_HDSPM
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called 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.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called snd-hifier.
|
||||
|
||||
config SND_ICE1712
|
||||
tristate "ICEnsemble ICE1712 (Envy24)"
|
||||
select SND_MPU401_UART
|
||||
@ -826,8 +819,8 @@ config SND_VIRTUOSO
|
||||
Say Y here to include support for sound cards based on the
|
||||
Asus AV66/AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X, DS,
|
||||
Essence ST (Deluxe), and Essence STX.
|
||||
Support for the HDAV1.3 (Deluxe) is incomplete; for the
|
||||
HDAV1.3 Slim and Xense, missing.
|
||||
Support for the HDAV1.3 (Deluxe) and HDAV1.3 Slim is experimental;
|
||||
for the Xense, missing.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called snd-virtuoso.
|
||||
|
@ -1014,8 +1014,7 @@ static int snd_ac97_free(struct snd_ac97 *ac97)
|
||||
{
|
||||
if (ac97) {
|
||||
#ifdef CONFIG_SND_AC97_POWER_SAVE
|
||||
cancel_delayed_work(&ac97->power_work);
|
||||
flush_scheduled_work();
|
||||
cancel_delayed_work_sync(&ac97->power_work);
|
||||
#endif
|
||||
snd_ac97_proc_done(ac97);
|
||||
if (ac97->bus)
|
||||
@ -2456,8 +2455,7 @@ void snd_ac97_suspend(struct snd_ac97 *ac97)
|
||||
if (ac97->build_ops->suspend)
|
||||
ac97->build_ops->suspend(ac97);
|
||||
#ifdef CONFIG_SND_AC97_POWER_SAVE
|
||||
cancel_delayed_work(&ac97->power_work);
|
||||
flush_scheduled_work();
|
||||
cancel_delayed_work_sync(&ac97->power_work);
|
||||
#endif
|
||||
snd_ac97_powerdown(ac97);
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* azt3328.c - driver for Aztech AZF3328 based soundcards (e.g. PCI168).
|
||||
* Copyright (C) 2002, 2005 - 2009 by Andreas Mohr <andi AT lisas.de>
|
||||
* Copyright (C) 2002, 2005 - 2010 by Andreas Mohr <andi AT lisas.de>
|
||||
*
|
||||
* Framework borrowed from Bart Hartgers's als4000.c.
|
||||
* Driver developed on PCI168 AP(W) version (PCI rev. 10, subsystem ID 1801),
|
||||
@ -175,6 +175,7 @@
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/bug.h> /* WARN_ONCE */
|
||||
#include <linux/pci.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
@ -201,14 +202,15 @@ MODULE_SUPPORTED_DEVICE("{{Aztech,AZF3328}}");
|
||||
|
||||
/* === Debug settings ===
|
||||
Further diagnostic functionality than the settings below
|
||||
does not need to be provided, since one can easily write a bash script
|
||||
does not need to be provided, since one can easily write a POSIX shell script
|
||||
to dump the card's I/O ports (those listed in lspci -v -v):
|
||||
function dump()
|
||||
dump()
|
||||
{
|
||||
local descr=$1; local addr=$2; local count=$3
|
||||
|
||||
echo "${descr}: ${count} @ ${addr}:"
|
||||
dd if=/dev/port skip=$[${addr}] count=${count} bs=1 2>/dev/null| hexdump -C
|
||||
dd if=/dev/port skip=`printf %d ${addr}` count=${count} bs=1 \
|
||||
2>/dev/null| hexdump -C
|
||||
}
|
||||
and then use something like
|
||||
"dump joy200 0x200 8", "dump mpu388 0x388 4", "dump joy 0xb400 8",
|
||||
@ -216,14 +218,14 @@ MODULE_SUPPORTED_DEVICE("{{Aztech,AZF3328}}");
|
||||
possibly within a "while true; do ... sleep 1; done" loop.
|
||||
Tweaking ports could be done using
|
||||
VALSTRING="`printf "%02x" $value`"
|
||||
printf "\x""$VALSTRING"|dd of=/dev/port seek=$[${addr}] bs=1 2>/dev/null
|
||||
printf "\x""$VALSTRING"|dd of=/dev/port seek=`printf %d ${addr}` bs=1 \
|
||||
2>/dev/null
|
||||
*/
|
||||
|
||||
#define DEBUG_MISC 0
|
||||
#define DEBUG_CALLS 0
|
||||
#define DEBUG_MIXER 0
|
||||
#define DEBUG_CODEC 0
|
||||
#define DEBUG_IO 0
|
||||
#define DEBUG_TIMER 0
|
||||
#define DEBUG_GAME 0
|
||||
#define DEBUG_PM 0
|
||||
@ -291,19 +293,23 @@ static int seqtimer_scaling = 128;
|
||||
module_param(seqtimer_scaling, int, 0444);
|
||||
MODULE_PARM_DESC(seqtimer_scaling, "Set 1024000Hz sequencer timer scale factor (lockup danger!). Default 128.");
|
||||
|
||||
struct snd_azf3328_codec_data {
|
||||
unsigned long io_base;
|
||||
struct snd_pcm_substream *substream;
|
||||
bool running;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
enum snd_azf3328_codec_type {
|
||||
/* warning: fixed indices (also used for bitmask checks!) */
|
||||
AZF_CODEC_PLAYBACK = 0,
|
||||
AZF_CODEC_CAPTURE = 1,
|
||||
AZF_CODEC_I2S_OUT = 2,
|
||||
};
|
||||
|
||||
struct snd_azf3328_codec_data {
|
||||
unsigned long io_base; /* keep first! (avoid offset calc) */
|
||||
unsigned int dma_base; /* helper to avoid an indirection in hotpath */
|
||||
spinlock_t *lock; /* TODO: convert to our own per-codec lock member */
|
||||
struct snd_pcm_substream *substream;
|
||||
bool running;
|
||||
enum snd_azf3328_codec_type type;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
struct snd_azf3328 {
|
||||
/* often-used fields towards beginning, then grouped */
|
||||
|
||||
@ -362,6 +368,9 @@ MODULE_DEVICE_TABLE(pci, snd_azf3328_ids);
|
||||
static int
|
||||
snd_azf3328_io_reg_setb(unsigned reg, u8 mask, bool do_set)
|
||||
{
|
||||
/* Well, strictly spoken, the inb/outb sequence isn't atomic
|
||||
and would need locking. However we currently don't care
|
||||
since it potentially complicates matters. */
|
||||
u8 prev = inb(reg), new;
|
||||
|
||||
new = (do_set) ? (prev|mask) : (prev & ~mask);
|
||||
@ -413,6 +422,21 @@ snd_azf3328_codec_outl(const struct snd_azf3328_codec_data *codec,
|
||||
outl(value, codec->io_base + reg);
|
||||
}
|
||||
|
||||
static inline void
|
||||
snd_azf3328_codec_outl_multi(const struct snd_azf3328_codec_data *codec,
|
||||
unsigned reg, const void *buffer, int count
|
||||
)
|
||||
{
|
||||
unsigned long addr = codec->io_base + reg;
|
||||
if (count) {
|
||||
const u32 *buf = buffer;
|
||||
do {
|
||||
outl(*buf++, addr);
|
||||
addr += 4;
|
||||
} while (--count);
|
||||
}
|
||||
}
|
||||
|
||||
static inline u32
|
||||
snd_azf3328_codec_inl(const struct snd_azf3328_codec_data *codec, unsigned reg)
|
||||
{
|
||||
@ -943,38 +967,43 @@ snd_azf3328_hw_free(struct snd_pcm_substream *substream)
|
||||
}
|
||||
|
||||
static void
|
||||
snd_azf3328_codec_setfmt(struct snd_azf3328 *chip,
|
||||
enum snd_azf3328_codec_type codec_type,
|
||||
snd_azf3328_codec_setfmt(struct snd_azf3328_codec_data *codec,
|
||||
enum azf_freq_t bitrate,
|
||||
unsigned int format_width,
|
||||
unsigned int channels
|
||||
)
|
||||
{
|
||||
unsigned long flags;
|
||||
const struct snd_azf3328_codec_data *codec = &chip->codecs[codec_type];
|
||||
u16 val = 0xff00;
|
||||
u8 freq = 0;
|
||||
|
||||
snd_azf3328_dbgcallenter();
|
||||
switch (bitrate) {
|
||||
case AZF_FREQ_4000: val |= SOUNDFORMAT_FREQ_SUSPECTED_4000; break;
|
||||
case AZF_FREQ_4800: val |= SOUNDFORMAT_FREQ_SUSPECTED_4800; break;
|
||||
case AZF_FREQ_5512:
|
||||
/* the AZF3328 names it "5510" for some strange reason */
|
||||
val |= SOUNDFORMAT_FREQ_5510; break;
|
||||
case AZF_FREQ_6620: val |= SOUNDFORMAT_FREQ_6620; break;
|
||||
case AZF_FREQ_8000: val |= SOUNDFORMAT_FREQ_8000; break;
|
||||
case AZF_FREQ_9600: val |= SOUNDFORMAT_FREQ_9600; break;
|
||||
case AZF_FREQ_11025: val |= SOUNDFORMAT_FREQ_11025; break;
|
||||
case AZF_FREQ_13240: val |= SOUNDFORMAT_FREQ_SUSPECTED_13240; break;
|
||||
case AZF_FREQ_16000: val |= SOUNDFORMAT_FREQ_16000; break;
|
||||
case AZF_FREQ_22050: val |= SOUNDFORMAT_FREQ_22050; break;
|
||||
case AZF_FREQ_32000: val |= SOUNDFORMAT_FREQ_32000; break;
|
||||
#define AZF_FMT_XLATE(in_freq, out_bits) \
|
||||
do { \
|
||||
case AZF_FREQ_ ## in_freq: \
|
||||
freq = SOUNDFORMAT_FREQ_ ## out_bits; \
|
||||
break; \
|
||||
} while (0);
|
||||
AZF_FMT_XLATE(4000, SUSPECTED_4000)
|
||||
AZF_FMT_XLATE(4800, SUSPECTED_4800)
|
||||
/* the AZF3328 names it "5510" for some strange reason: */
|
||||
AZF_FMT_XLATE(5512, 5510)
|
||||
AZF_FMT_XLATE(6620, 6620)
|
||||
AZF_FMT_XLATE(8000, 8000)
|
||||
AZF_FMT_XLATE(9600, 9600)
|
||||
AZF_FMT_XLATE(11025, 11025)
|
||||
AZF_FMT_XLATE(13240, SUSPECTED_13240)
|
||||
AZF_FMT_XLATE(16000, 16000)
|
||||
AZF_FMT_XLATE(22050, 22050)
|
||||
AZF_FMT_XLATE(32000, 32000)
|
||||
default:
|
||||
snd_printk(KERN_WARNING "unknown bitrate %d, assuming 44.1kHz!\n", bitrate);
|
||||
/* fall-through */
|
||||
case AZF_FREQ_44100: val |= SOUNDFORMAT_FREQ_44100; break;
|
||||
case AZF_FREQ_48000: val |= SOUNDFORMAT_FREQ_48000; break;
|
||||
case AZF_FREQ_66200: val |= SOUNDFORMAT_FREQ_SUSPECTED_66200; break;
|
||||
AZF_FMT_XLATE(44100, 44100)
|
||||
AZF_FMT_XLATE(48000, 48000)
|
||||
AZF_FMT_XLATE(66200, SUSPECTED_66200)
|
||||
#undef AZF_FMT_XLATE
|
||||
}
|
||||
/* val = 0xff07; 3m27.993s (65301Hz; -> 64000Hz???) hmm, 66120, 65967, 66123 */
|
||||
/* val = 0xff09; 17m15.098s (13123,478Hz; -> 12000Hz???) hmm, 13237.2Hz? */
|
||||
@ -986,13 +1015,15 @@ snd_azf3328_codec_setfmt(struct snd_azf3328 *chip,
|
||||
/* val = 0xff0d; 41m23.135s (5523,600Hz; -> 5512Hz???) */
|
||||
/* val = 0xff0e; 28m30.777s (8017Hz; -> 8000Hz???) */
|
||||
|
||||
val |= freq;
|
||||
|
||||
if (channels == 2)
|
||||
val |= SOUNDFORMAT_FLAG_2CHANNELS;
|
||||
|
||||
if (format_width == 16)
|
||||
val |= SOUNDFORMAT_FLAG_16BIT;
|
||||
|
||||
spin_lock_irqsave(&chip->reg_lock, flags);
|
||||
spin_lock_irqsave(codec->lock, flags);
|
||||
|
||||
/* set bitrate/format */
|
||||
snd_azf3328_codec_outw(codec, IDX_IO_CODEC_SOUNDFORMAT, val);
|
||||
@ -1004,7 +1035,8 @@ snd_azf3328_codec_setfmt(struct snd_azf3328 *chip,
|
||||
* (FIXME: yes, it works, but what exactly am I doing here?? :)
|
||||
* FIXME: does this have some side effects for full-duplex
|
||||
* or other dramatic side effects? */
|
||||
if (codec_type == AZF_CODEC_PLAYBACK) /* only do it for playback */
|
||||
/* do it for non-capture codecs only */
|
||||
if (codec->type != AZF_CODEC_CAPTURE)
|
||||
snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS,
|
||||
snd_azf3328_codec_inw(codec, IDX_IO_CODEC_DMA_FLAGS) |
|
||||
DMA_RUN_SOMETHING1 |
|
||||
@ -1014,20 +1046,19 @@ snd_azf3328_codec_setfmt(struct snd_azf3328 *chip,
|
||||
DMA_SOMETHING_ELSE
|
||||
);
|
||||
|
||||
spin_unlock_irqrestore(&chip->reg_lock, flags);
|
||||
spin_unlock_irqrestore(codec->lock, flags);
|
||||
snd_azf3328_dbgcallleave();
|
||||
}
|
||||
|
||||
static inline void
|
||||
snd_azf3328_codec_setfmt_lowpower(struct snd_azf3328 *chip,
|
||||
enum snd_azf3328_codec_type codec_type
|
||||
snd_azf3328_codec_setfmt_lowpower(struct snd_azf3328_codec_data *codec
|
||||
)
|
||||
{
|
||||
/* choose lowest frequency for low power consumption.
|
||||
* While this will cause louder noise due to rather coarse frequency,
|
||||
* it should never matter since output should always
|
||||
* get disabled properly when idle anyway. */
|
||||
snd_azf3328_codec_setfmt(chip, codec_type, AZF_FREQ_4000, 8, 1);
|
||||
snd_azf3328_codec_setfmt(codec, AZF_FREQ_4000, 8, 1);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1101,69 +1132,87 @@ snd_azf3328_ctrl_codec_activity(struct snd_azf3328 *chip,
|
||||
/* ...and adjust clock, too
|
||||
* (reduce noise and power consumption) */
|
||||
if (!enable)
|
||||
snd_azf3328_codec_setfmt_lowpower(
|
||||
chip,
|
||||
codec_type
|
||||
);
|
||||
snd_azf3328_codec_setfmt_lowpower(codec);
|
||||
codec->running = enable;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
snd_azf3328_codec_setdmaa(struct snd_azf3328 *chip,
|
||||
enum snd_azf3328_codec_type codec_type,
|
||||
snd_azf3328_codec_setdmaa(struct snd_azf3328_codec_data *codec,
|
||||
unsigned long addr,
|
||||
unsigned int count,
|
||||
unsigned int size
|
||||
unsigned int period_bytes,
|
||||
unsigned int buffer_bytes
|
||||
)
|
||||
{
|
||||
const struct snd_azf3328_codec_data *codec = &chip->codecs[codec_type];
|
||||
snd_azf3328_dbgcallenter();
|
||||
WARN_ONCE(period_bytes & 1, "odd period length!?\n");
|
||||
WARN_ONCE(buffer_bytes != 2 * period_bytes,
|
||||
"missed our input expectations! %u vs. %u\n",
|
||||
buffer_bytes, period_bytes);
|
||||
if (!codec->running) {
|
||||
/* AZF3328 uses a two buffer pointer DMA transfer approach */
|
||||
|
||||
unsigned long flags, addr_area2;
|
||||
unsigned long flags;
|
||||
|
||||
/* width 32bit (prevent overflow): */
|
||||
u32 count_areas, lengths;
|
||||
u32 area_length;
|
||||
struct codec_setup_io {
|
||||
u32 dma_start_1;
|
||||
u32 dma_start_2;
|
||||
u32 dma_lengths;
|
||||
} __attribute__((packed)) setup_io;
|
||||
|
||||
count_areas = size/2;
|
||||
addr_area2 = addr+count_areas;
|
||||
snd_azf3328_dbgcodec("setdma: buffers %08lx[%u] / %08lx[%u]\n",
|
||||
addr, count_areas, addr_area2, count_areas);
|
||||
area_length = buffer_bytes/2;
|
||||
|
||||
count_areas--; /* max. index */
|
||||
setup_io.dma_start_1 = addr;
|
||||
setup_io.dma_start_2 = addr+area_length;
|
||||
|
||||
snd_azf3328_dbgcodec(
|
||||
"setdma: buffers %08x[%u] / %08x[%u], %u, %u\n",
|
||||
setup_io.dma_start_1, area_length,
|
||||
setup_io.dma_start_2, area_length,
|
||||
period_bytes, buffer_bytes);
|
||||
|
||||
/* Hmm, are we really supposed to decrement this by 1??
|
||||
Most definitely certainly not: configuring full length does
|
||||
work properly (i.e. likely better), and BTW we
|
||||
violated possibly differing frame sizes with this...
|
||||
|
||||
area_length--; |* max. index *|
|
||||
*/
|
||||
|
||||
/* build combined I/O buffer length word */
|
||||
lengths = (count_areas << 16) | (count_areas);
|
||||
spin_lock_irqsave(&chip->reg_lock, flags);
|
||||
snd_azf3328_codec_outl(codec, IDX_IO_CODEC_DMA_START_1, addr);
|
||||
snd_azf3328_codec_outl(codec, IDX_IO_CODEC_DMA_START_2,
|
||||
addr_area2);
|
||||
snd_azf3328_codec_outl(codec, IDX_IO_CODEC_DMA_LENGTHS,
|
||||
lengths);
|
||||
spin_unlock_irqrestore(&chip->reg_lock, flags);
|
||||
setup_io.dma_lengths = (area_length << 16) | (area_length);
|
||||
|
||||
spin_lock_irqsave(codec->lock, flags);
|
||||
snd_azf3328_codec_outl_multi(
|
||||
codec, IDX_IO_CODEC_DMA_START_1, &setup_io, 3
|
||||
);
|
||||
spin_unlock_irqrestore(codec->lock, flags);
|
||||
}
|
||||
snd_azf3328_dbgcallleave();
|
||||
}
|
||||
|
||||
static int
|
||||
snd_azf3328_codec_prepare(struct snd_pcm_substream *substream)
|
||||
snd_azf3328_pcm_prepare(struct snd_pcm_substream *substream)
|
||||
{
|
||||
#if 0
|
||||
struct snd_azf3328 *chip = snd_pcm_substream_chip(substream);
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct snd_azf3328_codec_data *codec = runtime->private_data;
|
||||
#if 0
|
||||
unsigned int size = snd_pcm_lib_buffer_bytes(substream);
|
||||
unsigned int count = snd_pcm_lib_period_bytes(substream);
|
||||
#endif
|
||||
|
||||
snd_azf3328_dbgcallenter();
|
||||
|
||||
codec->dma_base = runtime->dma_addr;
|
||||
|
||||
#if 0
|
||||
snd_azf3328_codec_setfmt(chip, AZF_CODEC_...,
|
||||
snd_azf3328_codec_setfmt(codec,
|
||||
runtime->rate,
|
||||
snd_pcm_format_width(runtime->format),
|
||||
runtime->channels);
|
||||
snd_azf3328_codec_setdmaa(chip, AZF_CODEC_...,
|
||||
snd_azf3328_codec_setdmaa(codec,
|
||||
runtime->dma_addr, count, size);
|
||||
#endif
|
||||
snd_azf3328_dbgcallleave();
|
||||
@ -1171,24 +1220,23 @@ snd_azf3328_codec_prepare(struct snd_pcm_substream *substream)
|
||||
}
|
||||
|
||||
static int
|
||||
snd_azf3328_codec_trigger(enum snd_azf3328_codec_type codec_type,
|
||||
struct snd_pcm_substream *substream, int cmd)
|
||||
snd_azf3328_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
{
|
||||
struct snd_azf3328 *chip = snd_pcm_substream_chip(substream);
|
||||
const struct snd_azf3328_codec_data *codec = &chip->codecs[codec_type];
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct snd_azf3328_codec_data *codec = runtime->private_data;
|
||||
int result = 0;
|
||||
u16 flags1;
|
||||
bool previously_muted = 0;
|
||||
bool is_playback_codec = (AZF_CODEC_PLAYBACK == codec_type);
|
||||
bool is_main_mixer_playback_codec = (AZF_CODEC_PLAYBACK == codec->type);
|
||||
|
||||
snd_azf3328_dbgcalls("snd_azf3328_codec_trigger cmd %d\n", cmd);
|
||||
snd_azf3328_dbgcalls("snd_azf3328_pcm_trigger cmd %d\n", cmd);
|
||||
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
snd_azf3328_dbgcodec("START %s\n", codec->name);
|
||||
|
||||
if (is_playback_codec) {
|
||||
if (is_main_mixer_playback_codec) {
|
||||
/* mute WaveOut (avoid clicking during setup) */
|
||||
previously_muted =
|
||||
snd_azf3328_mixer_set_mute(
|
||||
@ -1196,12 +1244,12 @@ snd_azf3328_codec_trigger(enum snd_azf3328_codec_type codec_type,
|
||||
);
|
||||
}
|
||||
|
||||
snd_azf3328_codec_setfmt(chip, codec_type,
|
||||
snd_azf3328_codec_setfmt(codec,
|
||||
runtime->rate,
|
||||
snd_pcm_format_width(runtime->format),
|
||||
runtime->channels);
|
||||
|
||||
spin_lock(&chip->reg_lock);
|
||||
spin_lock(codec->lock);
|
||||
/* first, remember current value: */
|
||||
flags1 = snd_azf3328_codec_inw(codec, IDX_IO_CODEC_DMA_FLAGS);
|
||||
|
||||
@ -1211,14 +1259,14 @@ snd_azf3328_codec_trigger(enum snd_azf3328_codec_type codec_type,
|
||||
|
||||
/* FIXME: clear interrupts or what??? */
|
||||
snd_azf3328_codec_outw(codec, IDX_IO_CODEC_IRQTYPE, 0xffff);
|
||||
spin_unlock(&chip->reg_lock);
|
||||
spin_unlock(codec->lock);
|
||||
|
||||
snd_azf3328_codec_setdmaa(chip, codec_type, runtime->dma_addr,
|
||||
snd_azf3328_codec_setdmaa(codec, runtime->dma_addr,
|
||||
snd_pcm_lib_period_bytes(substream),
|
||||
snd_pcm_lib_buffer_bytes(substream)
|
||||
);
|
||||
|
||||
spin_lock(&chip->reg_lock);
|
||||
spin_lock(codec->lock);
|
||||
#ifdef WIN9X
|
||||
/* FIXME: enable playback/recording??? */
|
||||
flags1 |= DMA_RUN_SOMETHING1 | DMA_RUN_SOMETHING2;
|
||||
@ -1242,10 +1290,10 @@ snd_azf3328_codec_trigger(enum snd_azf3328_codec_type codec_type,
|
||||
DMA_EPILOGUE_SOMETHING |
|
||||
DMA_SOMETHING_ELSE);
|
||||
#endif
|
||||
spin_unlock(&chip->reg_lock);
|
||||
snd_azf3328_ctrl_codec_activity(chip, codec_type, 1);
|
||||
spin_unlock(codec->lock);
|
||||
snd_azf3328_ctrl_codec_activity(chip, codec->type, 1);
|
||||
|
||||
if (is_playback_codec) {
|
||||
if (is_main_mixer_playback_codec) {
|
||||
/* now unmute WaveOut */
|
||||
if (!previously_muted)
|
||||
snd_azf3328_mixer_set_mute(
|
||||
@ -1258,19 +1306,19 @@ snd_azf3328_codec_trigger(enum snd_azf3328_codec_type codec_type,
|
||||
case SNDRV_PCM_TRIGGER_RESUME:
|
||||
snd_azf3328_dbgcodec("RESUME %s\n", codec->name);
|
||||
/* resume codec if we were active */
|
||||
spin_lock(&chip->reg_lock);
|
||||
spin_lock(codec->lock);
|
||||
if (codec->running)
|
||||
snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS,
|
||||
snd_azf3328_codec_inw(
|
||||
codec, IDX_IO_CODEC_DMA_FLAGS
|
||||
) | DMA_RESUME
|
||||
);
|
||||
spin_unlock(&chip->reg_lock);
|
||||
spin_unlock(codec->lock);
|
||||
break;
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
snd_azf3328_dbgcodec("STOP %s\n", codec->name);
|
||||
|
||||
if (is_playback_codec) {
|
||||
if (is_main_mixer_playback_codec) {
|
||||
/* mute WaveOut (avoid clicking during setup) */
|
||||
previously_muted =
|
||||
snd_azf3328_mixer_set_mute(
|
||||
@ -1278,7 +1326,7 @@ snd_azf3328_codec_trigger(enum snd_azf3328_codec_type codec_type,
|
||||
);
|
||||
}
|
||||
|
||||
spin_lock(&chip->reg_lock);
|
||||
spin_lock(codec->lock);
|
||||
/* first, remember current value: */
|
||||
flags1 = snd_azf3328_codec_inw(codec, IDX_IO_CODEC_DMA_FLAGS);
|
||||
|
||||
@ -1293,10 +1341,10 @@ snd_azf3328_codec_trigger(enum snd_azf3328_codec_type codec_type,
|
||||
|
||||
flags1 &= ~DMA_RUN_SOMETHING1;
|
||||
snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, flags1);
|
||||
spin_unlock(&chip->reg_lock);
|
||||
snd_azf3328_ctrl_codec_activity(chip, codec_type, 0);
|
||||
spin_unlock(codec->lock);
|
||||
snd_azf3328_ctrl_codec_activity(chip, codec->type, 0);
|
||||
|
||||
if (is_playback_codec) {
|
||||
if (is_main_mixer_playback_codec) {
|
||||
/* now unmute WaveOut */
|
||||
if (!previously_muted)
|
||||
snd_azf3328_mixer_set_mute(
|
||||
@ -1330,67 +1378,29 @@ snd_azf3328_codec_trigger(enum snd_azf3328_codec_type codec_type,
|
||||
return result;
|
||||
}
|
||||
|
||||
static int
|
||||
snd_azf3328_codec_playback_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
{
|
||||
return snd_azf3328_codec_trigger(AZF_CODEC_PLAYBACK, substream, cmd);
|
||||
}
|
||||
|
||||
static int
|
||||
snd_azf3328_codec_capture_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
{
|
||||
return snd_azf3328_codec_trigger(AZF_CODEC_CAPTURE, substream, cmd);
|
||||
}
|
||||
|
||||
static int
|
||||
snd_azf3328_codec_i2s_out_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
{
|
||||
return snd_azf3328_codec_trigger(AZF_CODEC_I2S_OUT, substream, cmd);
|
||||
}
|
||||
|
||||
static snd_pcm_uframes_t
|
||||
snd_azf3328_codec_pointer(struct snd_pcm_substream *substream,
|
||||
enum snd_azf3328_codec_type codec_type
|
||||
snd_azf3328_pcm_pointer(struct snd_pcm_substream *substream
|
||||
)
|
||||
{
|
||||
const struct snd_azf3328 *chip = snd_pcm_substream_chip(substream);
|
||||
const struct snd_azf3328_codec_data *codec = &chip->codecs[codec_type];
|
||||
unsigned long bufptr, result;
|
||||
const struct snd_azf3328_codec_data *codec =
|
||||
substream->runtime->private_data;
|
||||
unsigned long result;
|
||||
snd_pcm_uframes_t frmres;
|
||||
|
||||
#ifdef QUERY_HARDWARE
|
||||
bufptr = snd_azf3328_codec_inl(codec, IDX_IO_CODEC_DMA_START_1);
|
||||
#else
|
||||
bufptr = substream->runtime->dma_addr;
|
||||
#endif
|
||||
result = snd_azf3328_codec_inl(codec, IDX_IO_CODEC_DMA_CURRPOS);
|
||||
|
||||
/* calculate offset */
|
||||
result -= bufptr;
|
||||
#ifdef QUERY_HARDWARE
|
||||
result -= snd_azf3328_codec_inl(codec, IDX_IO_CODEC_DMA_START_1);
|
||||
#else
|
||||
result -= codec->dma_base;
|
||||
#endif
|
||||
frmres = bytes_to_frames( substream->runtime, result);
|
||||
snd_azf3328_dbgcodec("%s @ 0x%8lx, frames %8ld\n",
|
||||
codec->name, result, frmres);
|
||||
snd_azf3328_dbgcodec("%08li %s @ 0x%8lx, frames %8ld\n",
|
||||
jiffies, codec->name, result, frmres);
|
||||
return frmres;
|
||||
}
|
||||
|
||||
static snd_pcm_uframes_t
|
||||
snd_azf3328_codec_playback_pointer(struct snd_pcm_substream *substream)
|
||||
{
|
||||
return snd_azf3328_codec_pointer(substream, AZF_CODEC_PLAYBACK);
|
||||
}
|
||||
|
||||
static snd_pcm_uframes_t
|
||||
snd_azf3328_codec_capture_pointer(struct snd_pcm_substream *substream)
|
||||
{
|
||||
return snd_azf3328_codec_pointer(substream, AZF_CODEC_CAPTURE);
|
||||
}
|
||||
|
||||
static snd_pcm_uframes_t
|
||||
snd_azf3328_codec_i2s_out_pointer(struct snd_pcm_substream *substream)
|
||||
{
|
||||
return snd_azf3328_codec_pointer(substream, AZF_CODEC_I2S_OUT);
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
#ifdef SUPPORT_GAMEPORT
|
||||
@ -1532,7 +1542,7 @@ snd_azf3328_gameport_cooked_read(struct gameport *gameport,
|
||||
}
|
||||
}
|
||||
|
||||
/* trigger next axes sampling, to be evaluated the next time we
|
||||
/* trigger next sampling of axes, to be evaluated the next time we
|
||||
* enter this function */
|
||||
|
||||
/* for some very, very strange reason we cannot enable
|
||||
@ -1624,29 +1634,29 @@ snd_azf3328_irq_log_unknown_type(u8 which)
|
||||
}
|
||||
|
||||
static inline void
|
||||
snd_azf3328_codec_interrupt(struct snd_azf3328 *chip, u8 status)
|
||||
snd_azf3328_pcm_interrupt(const struct snd_azf3328_codec_data *first_codec,
|
||||
u8 status
|
||||
)
|
||||
{
|
||||
u8 which;
|
||||
enum snd_azf3328_codec_type codec_type;
|
||||
const struct snd_azf3328_codec_data *codec;
|
||||
const struct snd_azf3328_codec_data *codec = first_codec;
|
||||
|
||||
for (codec_type = AZF_CODEC_PLAYBACK;
|
||||
codec_type <= AZF_CODEC_I2S_OUT;
|
||||
++codec_type) {
|
||||
++codec_type, ++codec) {
|
||||
|
||||
/* skip codec if there's no interrupt for it */
|
||||
if (!(status & (1 << codec_type)))
|
||||
continue;
|
||||
|
||||
codec = &chip->codecs[codec_type];
|
||||
|
||||
spin_lock(&chip->reg_lock);
|
||||
spin_lock(codec->lock);
|
||||
which = snd_azf3328_codec_inb(codec, IDX_IO_CODEC_IRQTYPE);
|
||||
/* ack all IRQ types immediately */
|
||||
snd_azf3328_codec_outb(codec, IDX_IO_CODEC_IRQTYPE, which);
|
||||
spin_unlock(&chip->reg_lock);
|
||||
spin_unlock(codec->lock);
|
||||
|
||||
if ((chip->pcm[codec_type]) && (codec->substream)) {
|
||||
if (codec->substream) {
|
||||
snd_pcm_period_elapsed(codec->substream);
|
||||
snd_azf3328_dbgcodec("%s period done (#%x), @ %x\n",
|
||||
codec->name,
|
||||
@ -1701,7 +1711,7 @@ snd_azf3328_interrupt(int irq, void *dev_id)
|
||||
}
|
||||
|
||||
if (status & (IRQ_PLAYBACK|IRQ_RECORDING|IRQ_I2S_OUT))
|
||||
snd_azf3328_codec_interrupt(chip, status);
|
||||
snd_azf3328_pcm_interrupt(chip->codecs, status);
|
||||
|
||||
if (status & IRQ_GAMEPORT)
|
||||
snd_azf3328_gameport_interrupt(chip);
|
||||
@ -1789,101 +1799,85 @@ snd_azf3328_pcm_open(struct snd_pcm_substream *substream,
|
||||
{
|
||||
struct snd_azf3328 *chip = snd_pcm_substream_chip(substream);
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct snd_azf3328_codec_data *codec = &chip->codecs[codec_type];
|
||||
|
||||
snd_azf3328_dbgcallenter();
|
||||
chip->codecs[codec_type].substream = substream;
|
||||
codec->substream = substream;
|
||||
|
||||
/* same parameters for all our codecs - at least we think so... */
|
||||
runtime->hw = snd_azf3328_hardware;
|
||||
|
||||
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
|
||||
&snd_azf3328_hw_constraints_rates);
|
||||
runtime->private_data = codec;
|
||||
snd_azf3328_dbgcallleave();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
snd_azf3328_playback_open(struct snd_pcm_substream *substream)
|
||||
snd_azf3328_pcm_playback_open(struct snd_pcm_substream *substream)
|
||||
{
|
||||
return snd_azf3328_pcm_open(substream, AZF_CODEC_PLAYBACK);
|
||||
}
|
||||
|
||||
static int
|
||||
snd_azf3328_capture_open(struct snd_pcm_substream *substream)
|
||||
snd_azf3328_pcm_capture_open(struct snd_pcm_substream *substream)
|
||||
{
|
||||
return snd_azf3328_pcm_open(substream, AZF_CODEC_CAPTURE);
|
||||
}
|
||||
|
||||
static int
|
||||
snd_azf3328_i2s_out_open(struct snd_pcm_substream *substream)
|
||||
snd_azf3328_pcm_i2s_out_open(struct snd_pcm_substream *substream)
|
||||
{
|
||||
return snd_azf3328_pcm_open(substream, AZF_CODEC_I2S_OUT);
|
||||
}
|
||||
|
||||
static int
|
||||
snd_azf3328_pcm_close(struct snd_pcm_substream *substream,
|
||||
enum snd_azf3328_codec_type codec_type
|
||||
snd_azf3328_pcm_close(struct snd_pcm_substream *substream
|
||||
)
|
||||
{
|
||||
struct snd_azf3328 *chip = snd_pcm_substream_chip(substream);
|
||||
struct snd_azf3328_codec_data *codec =
|
||||
substream->runtime->private_data;
|
||||
|
||||
snd_azf3328_dbgcallenter();
|
||||
chip->codecs[codec_type].substream = NULL;
|
||||
codec->substream = NULL;
|
||||
snd_azf3328_dbgcallleave();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
snd_azf3328_playback_close(struct snd_pcm_substream *substream)
|
||||
{
|
||||
return snd_azf3328_pcm_close(substream, AZF_CODEC_PLAYBACK);
|
||||
}
|
||||
|
||||
static int
|
||||
snd_azf3328_capture_close(struct snd_pcm_substream *substream)
|
||||
{
|
||||
return snd_azf3328_pcm_close(substream, AZF_CODEC_CAPTURE);
|
||||
}
|
||||
|
||||
static int
|
||||
snd_azf3328_i2s_out_close(struct snd_pcm_substream *substream)
|
||||
{
|
||||
return snd_azf3328_pcm_close(substream, AZF_CODEC_I2S_OUT);
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
static struct snd_pcm_ops snd_azf3328_playback_ops = {
|
||||
.open = snd_azf3328_playback_open,
|
||||
.close = snd_azf3328_playback_close,
|
||||
.open = snd_azf3328_pcm_playback_open,
|
||||
.close = snd_azf3328_pcm_close,
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.hw_params = snd_azf3328_hw_params,
|
||||
.hw_free = snd_azf3328_hw_free,
|
||||
.prepare = snd_azf3328_codec_prepare,
|
||||
.trigger = snd_azf3328_codec_playback_trigger,
|
||||
.pointer = snd_azf3328_codec_playback_pointer
|
||||
.prepare = snd_azf3328_pcm_prepare,
|
||||
.trigger = snd_azf3328_pcm_trigger,
|
||||
.pointer = snd_azf3328_pcm_pointer
|
||||
};
|
||||
|
||||
static struct snd_pcm_ops snd_azf3328_capture_ops = {
|
||||
.open = snd_azf3328_capture_open,
|
||||
.close = snd_azf3328_capture_close,
|
||||
.open = snd_azf3328_pcm_capture_open,
|
||||
.close = snd_azf3328_pcm_close,
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.hw_params = snd_azf3328_hw_params,
|
||||
.hw_free = snd_azf3328_hw_free,
|
||||
.prepare = snd_azf3328_codec_prepare,
|
||||
.trigger = snd_azf3328_codec_capture_trigger,
|
||||
.pointer = snd_azf3328_codec_capture_pointer
|
||||
.prepare = snd_azf3328_pcm_prepare,
|
||||
.trigger = snd_azf3328_pcm_trigger,
|
||||
.pointer = snd_azf3328_pcm_pointer
|
||||
};
|
||||
|
||||
static struct snd_pcm_ops snd_azf3328_i2s_out_ops = {
|
||||
.open = snd_azf3328_i2s_out_open,
|
||||
.close = snd_azf3328_i2s_out_close,
|
||||
.open = snd_azf3328_pcm_i2s_out_open,
|
||||
.close = snd_azf3328_pcm_close,
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.hw_params = snd_azf3328_hw_params,
|
||||
.hw_free = snd_azf3328_hw_free,
|
||||
.prepare = snd_azf3328_codec_prepare,
|
||||
.trigger = snd_azf3328_codec_i2s_out_trigger,
|
||||
.pointer = snd_azf3328_codec_i2s_out_pointer
|
||||
.prepare = snd_azf3328_pcm_prepare,
|
||||
.trigger = snd_azf3328_pcm_trigger,
|
||||
.pointer = snd_azf3328_pcm_pointer
|
||||
};
|
||||
|
||||
static int __devinit
|
||||
@ -1966,7 +1960,7 @@ snd_azf3328_timer_start(struct snd_timer *timer)
|
||||
snd_azf3328_dbgtimer("delay was too low (%d)!\n", delay);
|
||||
delay = 49; /* minimum time is 49 ticks */
|
||||
}
|
||||
snd_azf3328_dbgtimer("setting timer countdown value %d, add COUNTDOWN|IRQ\n", delay);
|
||||
snd_azf3328_dbgtimer("setting timer countdown value %d\n", delay);
|
||||
delay |= TIMER_COUNTDOWN_ENABLE | TIMER_IRQ_ENABLE;
|
||||
spin_lock_irqsave(&chip->reg_lock, flags);
|
||||
snd_azf3328_ctrl_outl(chip, IDX_IO_TIMER_VALUE, delay);
|
||||
@ -2180,6 +2174,7 @@ snd_azf3328_create(struct snd_card *card,
|
||||
};
|
||||
u8 dma_init;
|
||||
enum snd_azf3328_codec_type codec_type;
|
||||
struct snd_azf3328_codec_data *codec_setup;
|
||||
|
||||
*rchip = NULL;
|
||||
|
||||
@ -2217,15 +2212,23 @@ snd_azf3328_create(struct snd_card *card,
|
||||
chip->opl3_io = pci_resource_start(pci, 3);
|
||||
chip->mixer_io = pci_resource_start(pci, 4);
|
||||
|
||||
chip->codecs[AZF_CODEC_PLAYBACK].io_base =
|
||||
chip->ctrl_io + AZF_IO_OFFS_CODEC_PLAYBACK;
|
||||
chip->codecs[AZF_CODEC_PLAYBACK].name = "PLAYBACK";
|
||||
chip->codecs[AZF_CODEC_CAPTURE].io_base =
|
||||
chip->ctrl_io + AZF_IO_OFFS_CODEC_CAPTURE;
|
||||
chip->codecs[AZF_CODEC_CAPTURE].name = "CAPTURE";
|
||||
chip->codecs[AZF_CODEC_I2S_OUT].io_base =
|
||||
chip->ctrl_io + AZF_IO_OFFS_CODEC_I2S_OUT;
|
||||
chip->codecs[AZF_CODEC_I2S_OUT].name = "I2S_OUT";
|
||||
codec_setup = &chip->codecs[AZF_CODEC_PLAYBACK];
|
||||
codec_setup->io_base = chip->ctrl_io + AZF_IO_OFFS_CODEC_PLAYBACK;
|
||||
codec_setup->lock = &chip->reg_lock;
|
||||
codec_setup->type = AZF_CODEC_PLAYBACK;
|
||||
codec_setup->name = "PLAYBACK";
|
||||
|
||||
codec_setup = &chip->codecs[AZF_CODEC_CAPTURE];
|
||||
codec_setup->io_base = chip->ctrl_io + AZF_IO_OFFS_CODEC_CAPTURE;
|
||||
codec_setup->lock = &chip->reg_lock;
|
||||
codec_setup->type = AZF_CODEC_CAPTURE;
|
||||
codec_setup->name = "CAPTURE";
|
||||
|
||||
codec_setup = &chip->codecs[AZF_CODEC_I2S_OUT];
|
||||
codec_setup->io_base = chip->ctrl_io + AZF_IO_OFFS_CODEC_I2S_OUT;
|
||||
codec_setup->lock = &chip->reg_lock;
|
||||
codec_setup->type = AZF_CODEC_I2S_OUT;
|
||||
codec_setup->name = "I2S_OUT";
|
||||
|
||||
if (request_irq(pci->irq, snd_azf3328_interrupt,
|
||||
IRQF_SHARED, card->shortname, chip)) {
|
||||
@ -2257,15 +2260,15 @@ snd_azf3328_create(struct snd_card *card,
|
||||
struct snd_azf3328_codec_data *codec =
|
||||
&chip->codecs[codec_type];
|
||||
|
||||
/* shutdown codecs to save power */
|
||||
/* shutdown codecs to reduce power / noise */
|
||||
/* have ...ctrl_codec_activity() act properly */
|
||||
codec->running = 1;
|
||||
snd_azf3328_ctrl_codec_activity(chip, codec_type, 0);
|
||||
|
||||
spin_lock_irq(&chip->reg_lock);
|
||||
spin_lock_irq(codec->lock);
|
||||
snd_azf3328_codec_outb(codec, IDX_IO_CODEC_DMA_FLAGS,
|
||||
dma_init);
|
||||
spin_unlock_irq(&chip->reg_lock);
|
||||
spin_unlock_irq(codec->lock);
|
||||
}
|
||||
|
||||
snd_card_set_dev(card, &pci->dev);
|
||||
@ -2419,6 +2422,7 @@ snd_azf3328_suspend(struct pci_dev *pci, pm_message_t state)
|
||||
|
||||
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
|
||||
|
||||
/* same pcm object for playback/capture */
|
||||
snd_pcm_suspend_all(chip->pcm[AZF_CODEC_PLAYBACK]);
|
||||
snd_pcm_suspend_all(chip->pcm[AZF_CODEC_I2S_OUT]);
|
||||
|
||||
|
@ -637,15 +637,9 @@ static struct snd_kcontrol_new snd_bt87x_capture_boost = {
|
||||
static int snd_bt87x_capture_source_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *info)
|
||||
{
|
||||
static char *texts[3] = {"TV Tuner", "FM", "Mic/Line"};
|
||||
static const char *const texts[3] = {"TV Tuner", "FM", "Mic/Line"};
|
||||
|
||||
info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
|
||||
info->count = 1;
|
||||
info->value.enumerated.items = 3;
|
||||
if (info->value.enumerated.item > 2)
|
||||
info->value.enumerated.item = 2;
|
||||
strcpy(info->value.enumerated.name, texts[info->value.enumerated.item]);
|
||||
return 0;
|
||||
return snd_ctl_enum_info(info, 1, 3, texts);
|
||||
}
|
||||
|
||||
static int snd_bt87x_capture_source_get(struct snd_kcontrol *kcontrol,
|
||||
|
@ -2507,14 +2507,12 @@ static int snd_cmipci_line_in_mode_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
struct cmipci *cm = snd_kcontrol_chip(kcontrol);
|
||||
static char *texts[3] = { "Line-In", "Rear Output", "Bass Output" };
|
||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
|
||||
uinfo->count = 1;
|
||||
uinfo->value.enumerated.items = cm->chip_version >= 39 ? 3 : 2;
|
||||
if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
|
||||
uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
|
||||
strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
|
||||
return 0;
|
||||
static const char *const texts[3] = {
|
||||
"Line-In", "Rear Output", "Bass Output"
|
||||
};
|
||||
|
||||
return snd_ctl_enum_info(uinfo, 1,
|
||||
cm->chip_version >= 39 ? 3 : 2, texts);
|
||||
}
|
||||
|
||||
static inline unsigned int get_line_in_mode(struct cmipci *cm)
|
||||
@ -2564,14 +2562,9 @@ static int snd_cmipci_line_in_mode_put(struct snd_kcontrol *kcontrol,
|
||||
static int snd_cmipci_mic_in_mode_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
static char *texts[2] = { "Mic-In", "Center/LFE Output" };
|
||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
|
||||
uinfo->count = 1;
|
||||
uinfo->value.enumerated.items = 2;
|
||||
if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
|
||||
uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
|
||||
strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
|
||||
return 0;
|
||||
static const char *const texts[2] = { "Mic-In", "Center/LFE Output" };
|
||||
|
||||
return snd_ctl_enum_info(uinfo, 1, 2, texts);
|
||||
}
|
||||
|
||||
static int snd_cmipci_mic_in_mode_get(struct snd_kcontrol *kcontrol,
|
||||
|
@ -4571,6 +4571,9 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
|
||||
}
|
||||
memset(cfg->hp_pins + cfg->hp_outs, 0,
|
||||
sizeof(hda_nid_t) * (AUTO_CFG_MAX_OUTS - cfg->hp_outs));
|
||||
if (!cfg->hp_outs)
|
||||
cfg->line_out_type = AUTO_PIN_HP_OUT;
|
||||
|
||||
}
|
||||
|
||||
/* sort by sequence */
|
||||
|
@ -1235,7 +1235,8 @@ static int azx_setup_periods(struct azx *chip,
|
||||
pos_adj = 0;
|
||||
} else {
|
||||
ofs = setup_bdle(substream, azx_dev,
|
||||
&bdl, ofs, pos_adj, 1);
|
||||
&bdl, ofs, pos_adj,
|
||||
!substream->runtime->no_period_wakeup);
|
||||
if (ofs < 0)
|
||||
goto error;
|
||||
}
|
||||
@ -1247,7 +1248,8 @@ static int azx_setup_periods(struct azx *chip,
|
||||
period_bytes - pos_adj, 0);
|
||||
else
|
||||
ofs = setup_bdle(substream, azx_dev, &bdl, ofs,
|
||||
period_bytes, 1);
|
||||
period_bytes,
|
||||
!substream->runtime->no_period_wakeup);
|
||||
if (ofs < 0)
|
||||
goto error;
|
||||
}
|
||||
@ -1515,7 +1517,8 @@ static struct snd_pcm_hardware azx_pcm_hw = {
|
||||
/* No full-resume yet implemented */
|
||||
/* SNDRV_PCM_INFO_RESUME |*/
|
||||
SNDRV_PCM_INFO_PAUSE |
|
||||
SNDRV_PCM_INFO_SYNC_START),
|
||||
SNDRV_PCM_INFO_SYNC_START |
|
||||
SNDRV_PCM_INFO_NO_PERIOD_WAKEUP),
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
.rate_min = 48000,
|
||||
|
@ -666,7 +666,7 @@ static struct snd_kcontrol_new ad1986a_mixers[] = {
|
||||
HDA_CODEC_MUTE("Aux Playback Switch", 0x16, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Mic Boost Volume", 0x0f, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
|
||||
@ -729,7 +729,7 @@ static struct snd_kcontrol_new ad1986a_laptop_mixers[] = {
|
||||
HDA_CODEC_MUTE("Aux Playback Switch", 0x16, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Mic Boost Volume", 0x0f, 0x0, HDA_OUTPUT),
|
||||
/*
|
||||
HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT), */
|
||||
@ -775,7 +775,7 @@ static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = {
|
||||
HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Mic Boost Volume", 0x0f, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
|
||||
{
|
||||
@ -1358,7 +1358,7 @@ static struct snd_kcontrol_new ad1983_mixers[] = {
|
||||
HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Line Playback Volume", 0x13, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Line Playback Switch", 0x13, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Mic Boost", 0x0c, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Mic Boost Volume", 0x0c, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
|
||||
{
|
||||
@ -1515,8 +1515,8 @@ static struct snd_kcontrol_new ad1981_mixers[] = {
|
||||
HDA_CODEC_MUTE("Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Front Mic Boost", 0x08, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x08, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
|
||||
{
|
||||
@ -1726,8 +1726,8 @@ static struct snd_kcontrol_new ad1981_hp_mixers[] = {
|
||||
HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
|
||||
#endif
|
||||
HDA_CODEC_VOLUME("Mic Boost", 0x08, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Internal Mic Boost", 0x18, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Mic Boost Volume", 0x08, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x18, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
|
||||
{
|
||||
@ -1774,7 +1774,7 @@ static struct snd_kcontrol_new ad1981_thinkpad_mixers[] = {
|
||||
HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Mic Boost", 0x08, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Mic Boost Volume", 0x08, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
|
||||
{
|
||||
@ -2160,8 +2160,8 @@ static struct snd_kcontrol_new ad1988_6stack_mixers2[] = {
|
||||
HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
|
||||
|
||||
HDA_CODEC_VOLUME("Front Mic Boost", 0x39, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Mic Boost", 0x3c, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT),
|
||||
|
||||
{ } /* end */
|
||||
};
|
||||
@ -2203,8 +2203,8 @@ static struct snd_kcontrol_new ad1988_3stack_mixers2[] = {
|
||||
HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
|
||||
|
||||
HDA_CODEC_VOLUME("Front Mic Boost", 0x39, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Mic Boost", 0x3c, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT),
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Channel Mode",
|
||||
@ -2232,7 +2232,7 @@ static struct snd_kcontrol_new ad1988_laptop_mixers[] = {
|
||||
HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
|
||||
|
||||
HDA_CODEC_VOLUME("Mic Boost", 0x39, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT),
|
||||
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
@ -2902,7 +2902,7 @@ static int new_analog_input(struct ad198x_spec *spec, hda_nid_t pin,
|
||||
idx = ad1988_pin_idx(pin);
|
||||
bnid = ad1988_boost_nids[idx];
|
||||
if (bnid) {
|
||||
sprintf(name, "%s Boost", ctlname);
|
||||
sprintf(name, "%s Boost Volume", ctlname);
|
||||
return add_control(spec, AD_CTL_WIDGET_VOL, name,
|
||||
HDA_COMPOSE_AMP_VAL(bnid, 3, idx, HDA_OUTPUT));
|
||||
|
||||
@ -3300,8 +3300,8 @@ static struct snd_kcontrol_new ad1884_base_mixers[] = {
|
||||
HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Mic Boost", 0x15, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Front Mic Boost", 0x14, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Mic Boost Volume", 0x15, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
|
||||
@ -3499,9 +3499,9 @@ static struct snd_kcontrol_new ad1984_thinkpad_mixers[] = {
|
||||
HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Docking Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Docking Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Mic Boost", 0x14, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Internal Mic Boost", 0x15, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Docking Mic Boost", 0x25, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x15, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
|
||||
@ -3560,8 +3560,8 @@ static struct snd_kcontrol_new ad1984_dell_desktop_mixers[] = {
|
||||
HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Line-In Playback Volume", 0x20, 0x01, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Line-In Playback Switch", 0x20, 0x01, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Line-In Boost", 0x15, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Front Mic Boost", 0x14, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Line-In Boost Volume", 0x15, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
|
||||
@ -3745,9 +3745,9 @@ static struct snd_kcontrol_new ad1884a_base_mixers[] = {
|
||||
HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Front Mic Boost", 0x14, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Line Boost", 0x15, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Mic Boost", 0x25, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
|
||||
@ -3888,9 +3888,9 @@ static struct snd_kcontrol_new ad1884a_laptop_mixers[] = {
|
||||
HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Mic Boost", 0x14, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Internal Mic Boost", 0x15, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Dock Mic Boost", 0x25, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x15, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
|
||||
{ } /* end */
|
||||
@ -4126,8 +4126,8 @@ static struct snd_kcontrol_new ad1984a_thinkpad_mixers[] = {
|
||||
HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Mic Boost", 0x14, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Internal Mic Boost", 0x17, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x17, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
|
||||
{
|
||||
@ -4255,8 +4255,8 @@ static struct snd_kcontrol_new ad1984a_touchsmart_mixers[] = {
|
||||
HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Mic Boost", 0x25, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Internal Mic Boost", 0x17, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x17, 0x0, HDA_INPUT),
|
||||
{ } /* end */
|
||||
};
|
||||
|
||||
@ -4494,9 +4494,9 @@ static struct snd_kcontrol_new ad1882_base_mixers[] = {
|
||||
HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
|
||||
|
||||
HDA_CODEC_VOLUME("Mic Boost", 0x3c, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Front Mic Boost", 0x39, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Line-In Boost", 0x3a, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Line-In Boost Volume", 0x3a, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
|
||||
@ -4547,7 +4547,7 @@ static struct snd_kcontrol_new ad1882a_loopback_mixers[] = {
|
||||
HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x01, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Digital Mic Boost", 0x1f, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Digital Mic Boost Volume", 0x1f, 0x0, HDA_INPUT),
|
||||
{ } /* end */
|
||||
};
|
||||
|
||||
|
@ -869,16 +869,16 @@ static void cxt5045_hp_unsol_event(struct hda_codec *codec,
|
||||
}
|
||||
|
||||
static struct snd_kcontrol_new cxt5045_mixers[] = {
|
||||
HDA_CODEC_VOLUME("Int Mic Capture Volume", 0x1a, 0x01, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Int Mic Capture Switch", 0x1a, 0x01, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Ext Mic Capture Volume", 0x1a, 0x02, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Ext Mic Capture Switch", 0x1a, 0x02, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Internal Mic Capture Volume", 0x1a, 0x01, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Internal Mic Capture Switch", 0x1a, 0x01, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Mic Capture Volume", 0x1a, 0x02, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Mic Capture Switch", 0x1a, 0x02, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("PCM Playback Volume", 0x17, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("PCM Playback Switch", 0x17, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x17, 0x1, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Int Mic Playback Switch", 0x17, 0x1, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x17, 0x2, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x17, 0x2, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0x1, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0x1, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Mic Playback Volume", 0x17, 0x2, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Mic Playback Switch", 0x17, 0x2, HDA_INPUT),
|
||||
HDA_BIND_VOL("Master Playback Volume", &cxt5045_hp_bind_master_vol),
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
@ -910,16 +910,16 @@ static struct snd_kcontrol_new cxt5045_benq_mixers[] = {
|
||||
};
|
||||
|
||||
static struct snd_kcontrol_new cxt5045_mixers_hp530[] = {
|
||||
HDA_CODEC_VOLUME("Int Mic Capture Volume", 0x1a, 0x02, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Int Mic Capture Switch", 0x1a, 0x02, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Ext Mic Capture Volume", 0x1a, 0x01, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Ext Mic Capture Switch", 0x1a, 0x01, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Internal Mic Capture Volume", 0x1a, 0x02, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Internal Mic Capture Switch", 0x1a, 0x02, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Mic Capture Volume", 0x1a, 0x01, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Mic Capture Switch", 0x1a, 0x01, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("PCM Playback Volume", 0x17, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("PCM Playback Switch", 0x17, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x17, 0x2, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Int Mic Playback Switch", 0x17, 0x2, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x17, 0x1, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x17, 0x1, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0x2, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0x2, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Mic Playback Volume", 0x17, 0x1, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Mic Playback Switch", 0x17, 0x1, HDA_INPUT),
|
||||
HDA_BIND_VOL("Master Playback Volume", &cxt5045_hp_bind_master_vol),
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
@ -947,7 +947,7 @@ static struct hda_verb cxt5045_init_verbs[] = {
|
||||
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
|
||||
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
|
||||
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
|
||||
/* Record selector: Int mic */
|
||||
/* Record selector: Internal mic */
|
||||
{0x1a, AC_VERB_SET_CONNECT_SEL,0x1},
|
||||
{0x1a, AC_VERB_SET_AMP_GAIN_MUTE,
|
||||
AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17},
|
||||
@ -960,7 +960,7 @@ static struct hda_verb cxt5045_init_verbs[] = {
|
||||
};
|
||||
|
||||
static struct hda_verb cxt5045_benq_init_verbs[] = {
|
||||
/* Int Mic, Mic */
|
||||
/* Internal Mic, Mic */
|
||||
{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 },
|
||||
{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 },
|
||||
/* Line In,HP, Amp */
|
||||
@ -973,7 +973,7 @@ static struct hda_verb cxt5045_benq_init_verbs[] = {
|
||||
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
|
||||
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
|
||||
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
|
||||
/* Record selector: Int mic */
|
||||
/* Record selector: Internal mic */
|
||||
{0x1a, AC_VERB_SET_CONNECT_SEL, 0x1},
|
||||
{0x1a, AC_VERB_SET_AMP_GAIN_MUTE,
|
||||
AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17},
|
||||
@ -1376,7 +1376,7 @@ static void cxt5047_hp_unsol_event(struct hda_codec *codec,
|
||||
static struct snd_kcontrol_new cxt5047_base_mixers[] = {
|
||||
HDA_CODEC_VOLUME("Mic Playback Volume", 0x19, 0x02, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Mic Playback Switch", 0x19, 0x02, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Mic Boost", 0x1a, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Mic Boost Volume", 0x1a, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x03, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Capture Switch", 0x12, 0x03, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("PCM Volume", 0x10, 0x00, HDA_OUTPUT),
|
||||
@ -1796,8 +1796,8 @@ static struct snd_kcontrol_new cxt5051_playback_mixers[] = {
|
||||
static struct snd_kcontrol_new cxt5051_capture_mixers[] = {
|
||||
HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("External Mic Volume", 0x14, 0x01, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("External Mic Switch", 0x14, 0x01, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Mic Volume", 0x14, 0x01, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Mic Switch", 0x14, 0x01, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Docking Mic Volume", 0x15, 0x00, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Docking Mic Switch", 0x15, 0x00, HDA_INPUT),
|
||||
{}
|
||||
@ -1806,8 +1806,8 @@ static struct snd_kcontrol_new cxt5051_capture_mixers[] = {
|
||||
static struct snd_kcontrol_new cxt5051_hp_mixers[] = {
|
||||
HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("External Mic Volume", 0x15, 0x00, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("External Mic Switch", 0x15, 0x00, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Mic Volume", 0x15, 0x00, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Mic Switch", 0x15, 0x00, HDA_INPUT),
|
||||
{}
|
||||
};
|
||||
|
||||
@ -1826,8 +1826,8 @@ static struct snd_kcontrol_new cxt5051_f700_mixers[] = {
|
||||
static struct snd_kcontrol_new cxt5051_toshiba_mixers[] = {
|
||||
HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("External Mic Volume", 0x14, 0x01, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("External Mic Switch", 0x14, 0x01, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Mic Volume", 0x14, 0x01, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Mic Switch", 0x14, 0x01, HDA_INPUT),
|
||||
{}
|
||||
};
|
||||
|
||||
@ -1847,7 +1847,7 @@ static struct hda_verb cxt5051_init_verbs[] = {
|
||||
{0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
|
||||
/* DAC1 */
|
||||
{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
|
||||
/* Record selector: Int mic */
|
||||
/* Record selector: Internal mic */
|
||||
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44},
|
||||
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44},
|
||||
{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44},
|
||||
@ -1874,7 +1874,7 @@ static struct hda_verb cxt5051_hp_dv6736_init_verbs[] = {
|
||||
{0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
|
||||
/* DAC1 */
|
||||
{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
|
||||
/* Record selector: Int mic */
|
||||
/* Record selector: Internal mic */
|
||||
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44},
|
||||
{0x14, AC_VERB_SET_CONNECT_SEL, 0x1},
|
||||
/* SPDIF route: PCM */
|
||||
@ -1904,7 +1904,7 @@ static struct hda_verb cxt5051_lenovo_x200_init_verbs[] = {
|
||||
{0x19, AC_VERB_SET_CONNECT_SEL, 0x00},
|
||||
/* DAC1 */
|
||||
{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
|
||||
/* Record selector: Int mic */
|
||||
/* Record selector: Internal mic */
|
||||
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44},
|
||||
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44},
|
||||
{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44},
|
||||
@ -1932,7 +1932,7 @@ static struct hda_verb cxt5051_f700_init_verbs[] = {
|
||||
{0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
|
||||
/* DAC1 */
|
||||
{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
|
||||
/* Record selector: Int mic */
|
||||
/* Record selector: Internal mic */
|
||||
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44},
|
||||
{0x14, AC_VERB_SET_CONNECT_SEL, 0x1},
|
||||
/* SPDIF route: PCM */
|
||||
@ -2111,6 +2111,11 @@ static struct hda_channel_mode cxt5066_modes[1] = {
|
||||
{ 2, NULL },
|
||||
};
|
||||
|
||||
#define HP_PRESENT_PORT_A (1 << 0)
|
||||
#define HP_PRESENT_PORT_D (1 << 1)
|
||||
#define hp_port_a_present(spec) ((spec)->hp_present & HP_PRESENT_PORT_A)
|
||||
#define hp_port_d_present(spec) ((spec)->hp_present & HP_PRESENT_PORT_D)
|
||||
|
||||
static void cxt5066_update_speaker(struct hda_codec *codec)
|
||||
{
|
||||
struct conexant_spec *spec = codec->spec;
|
||||
@ -2120,24 +2125,20 @@ static void cxt5066_update_speaker(struct hda_codec *codec)
|
||||
spec->hp_present, spec->cur_eapd);
|
||||
|
||||
/* Port A (HP) */
|
||||
pinctl = ((spec->hp_present & 1) && spec->cur_eapd) ? PIN_HP : 0;
|
||||
pinctl = (hp_port_a_present(spec) && spec->cur_eapd) ? PIN_HP : 0;
|
||||
snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||
pinctl);
|
||||
|
||||
/* Port D (HP/LO) */
|
||||
if (spec->dell_automute) {
|
||||
/* DELL AIO Port Rule: PortA> PortD> IntSpk */
|
||||
pinctl = (!(spec->hp_present & 1) && spec->cur_eapd)
|
||||
? PIN_OUT : 0;
|
||||
} else if (spec->thinkpad) {
|
||||
if (spec->cur_eapd)
|
||||
pinctl = spec->port_d_mode;
|
||||
/* Mute dock line-out if Port A (laptop HP) is present */
|
||||
if (spec->hp_present& 1)
|
||||
pinctl = spec->cur_eapd ? spec->port_d_mode : 0;
|
||||
if (spec->dell_automute || spec->thinkpad) {
|
||||
/* Mute if Port A is connected */
|
||||
if (hp_port_a_present(spec))
|
||||
pinctl = 0;
|
||||
} else {
|
||||
pinctl = ((spec->hp_present & 2) && spec->cur_eapd)
|
||||
? spec->port_d_mode : 0;
|
||||
/* Thinkpad/Dell doesn't give pin-D status */
|
||||
if (!hp_port_d_present(spec))
|
||||
pinctl = 0;
|
||||
}
|
||||
snd_hda_codec_write(codec, 0x1c, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||
pinctl);
|
||||
@ -2379,8 +2380,8 @@ static void cxt5066_hp_automute(struct hda_codec *codec)
|
||||
/* Port D */
|
||||
portD = snd_hda_jack_detect(codec, 0x1c);
|
||||
|
||||
spec->hp_present = !!(portA);
|
||||
spec->hp_present |= portD ? 2 : 0;
|
||||
spec->hp_present = portA ? HP_PRESENT_PORT_A : 0;
|
||||
spec->hp_present |= portD ? HP_PRESENT_PORT_D : 0;
|
||||
snd_printdd("CXT5066: hp automute portA=%x portD=%x present=%d\n",
|
||||
portA, portD, spec->hp_present);
|
||||
cxt5066_update_speaker(codec);
|
||||
@ -2728,7 +2729,7 @@ static struct snd_kcontrol_new cxt5066_mixers[] = {
|
||||
static struct snd_kcontrol_new cxt5066_vostro_mixers[] = {
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Int Mic Boost Capture Enum",
|
||||
.name = "Internal Mic Boost Capture Enum",
|
||||
.info = cxt5066_mic_boost_mux_enum_info,
|
||||
.get = cxt5066_mic_boost_mux_enum_get,
|
||||
.put = cxt5066_mic_boost_mux_enum_put,
|
||||
@ -2954,7 +2955,7 @@ static struct hda_verb cxt5066_init_verbs_ideapad[] = {
|
||||
{0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
|
||||
|
||||
/* internal microphone */
|
||||
{0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* enable int mic */
|
||||
{0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* enable internal mic */
|
||||
|
||||
/* EAPD */
|
||||
{0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
|
||||
@ -3009,7 +3010,7 @@ static struct hda_verb cxt5066_init_verbs_thinkpad[] = {
|
||||
{0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
|
||||
|
||||
/* internal microphone */
|
||||
{0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* enable int mic */
|
||||
{0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* enable internal mic */
|
||||
|
||||
/* EAPD */
|
||||
{0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
|
||||
@ -3097,6 +3098,7 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = {
|
||||
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 Vostro 320", CXT5066_IDEAPAD),
|
||||
SND_PCI_QUIRK(0x1028, 0x0401, "Dell Vostro 1014", CXT5066_DELL_VOSTRO),
|
||||
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),
|
||||
@ -3108,16 +3110,9 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = {
|
||||
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, 0x21c5, "Thinkpad Edge 13", CXT5066_THINKPAD),
|
||||
SND_PCI_QUIRK(0x17aa, 0x21b3, "Thinkpad Edge 13 (197)", CXT5066_IDEAPAD),
|
||||
SND_PCI_QUIRK(0x17aa, 0x21b4, "Thinkpad Edge", CXT5066_IDEAPAD),
|
||||
SND_PCI_QUIRK(0x17aa, 0x21c8, "Thinkpad Edge 11", CXT5066_IDEAPAD),
|
||||
SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo Thinkpad", CXT5066_THINKPAD),
|
||||
SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo G series", CXT5066_IDEAPAD),
|
||||
SND_PCI_QUIRK(0x17aa, 0x390a, "Lenovo S10-3t", CXT5066_IDEAPAD),
|
||||
SND_PCI_QUIRK(0x17aa, 0x3938, "Lenovo G series (AMD)", CXT5066_IDEAPAD),
|
||||
SND_PCI_QUIRK(0x17aa, 0x3a0d, "ideapad", CXT5066_IDEAPAD),
|
||||
SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", CXT5066_IDEAPAD), /* Fallback for Lenovos without dock mic */
|
||||
{}
|
||||
};
|
||||
|
||||
@ -3422,6 +3417,9 @@ static void cx_auto_hp_automute(struct hda_codec *codec)
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||
present ? 0 : PIN_OUT);
|
||||
}
|
||||
for (i = 0; !present && i < cfg->line_outs; i++)
|
||||
if (snd_hda_jack_detect(codec, cfg->line_out_pins[i]))
|
||||
present = 1;
|
||||
for (i = 0; i < cfg->speaker_outs; i++) {
|
||||
snd_hda_codec_write(codec, cfg->speaker_pins[i], 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||
|
@ -31,10 +31,15 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <sound/core.h>
|
||||
#include "hda_codec.h"
|
||||
#include "hda_local.h"
|
||||
|
||||
static bool static_hdmi_pcm;
|
||||
module_param(static_hdmi_pcm, bool, 0644);
|
||||
MODULE_PARM_DESC(static_hdmi_pcm, "Don't restrict PCM parameters per ELD info");
|
||||
|
||||
/*
|
||||
* 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
|
||||
@ -827,7 +832,7 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
|
||||
*codec_pars = *hinfo;
|
||||
|
||||
eld = &spec->sink_eld[idx];
|
||||
if (eld->sad_count > 0) {
|
||||
if (!static_hdmi_pcm && eld->eld_valid && eld->sad_count > 0) {
|
||||
hdmi_eld_update_pcm_info(eld, hinfo, codec_pars);
|
||||
if (hinfo->channels_min > hinfo->channels_max ||
|
||||
!hinfo->rates || !hinfo->formats)
|
||||
@ -904,23 +909,28 @@ static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)
|
||||
spec->pin[spec->num_pins] = pin_nid;
|
||||
spec->num_pins++;
|
||||
|
||||
/*
|
||||
* It is assumed that converter nodes come first in the node list and
|
||||
* hence have been registered and usable now.
|
||||
*/
|
||||
return hdmi_read_pin_conn(codec, pin_nid);
|
||||
}
|
||||
|
||||
static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t nid)
|
||||
{
|
||||
int i, found_pin = 0;
|
||||
struct hdmi_spec *spec = codec->spec;
|
||||
|
||||
if (spec->num_cvts >= MAX_HDMI_CVTS) {
|
||||
snd_printk(KERN_WARNING
|
||||
"HDMI: no space for converter %d\n", nid);
|
||||
return -E2BIG;
|
||||
for (i = 0; i < spec->num_pins; i++)
|
||||
if (nid == spec->pin_cvt[i]) {
|
||||
found_pin = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!found_pin) {
|
||||
snd_printdd("HDMI: Skipping node %d (no connection)\n", nid);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (snd_BUG_ON(spec->num_cvts >= MAX_HDMI_CVTS))
|
||||
return -E2BIG;
|
||||
|
||||
spec->cvt[spec->num_cvts] = nid;
|
||||
spec->num_cvts++;
|
||||
|
||||
@ -931,6 +941,8 @@ static int hdmi_parse_codec(struct hda_codec *codec)
|
||||
{
|
||||
hda_nid_t nid;
|
||||
int i, nodes;
|
||||
int num_tmp_cvts = 0;
|
||||
hda_nid_t tmp_cvt[MAX_HDMI_CVTS];
|
||||
|
||||
nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid);
|
||||
if (!nid || nodes < 0) {
|
||||
@ -941,6 +953,7 @@ static int hdmi_parse_codec(struct hda_codec *codec)
|
||||
for (i = 0; i < nodes; i++, nid++) {
|
||||
unsigned int caps;
|
||||
unsigned int type;
|
||||
unsigned int config;
|
||||
|
||||
caps = snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP);
|
||||
type = get_wcaps_type(caps);
|
||||
@ -950,17 +963,32 @@ static int hdmi_parse_codec(struct hda_codec *codec)
|
||||
|
||||
switch (type) {
|
||||
case AC_WID_AUD_OUT:
|
||||
hdmi_add_cvt(codec, nid);
|
||||
if (num_tmp_cvts >= MAX_HDMI_CVTS) {
|
||||
snd_printk(KERN_WARNING
|
||||
"HDMI: no space for converter %d\n", nid);
|
||||
continue;
|
||||
}
|
||||
tmp_cvt[num_tmp_cvts] = nid;
|
||||
num_tmp_cvts++;
|
||||
break;
|
||||
case AC_WID_PIN:
|
||||
caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
|
||||
if (!(caps & (AC_PINCAP_HDMI | AC_PINCAP_DP)))
|
||||
continue;
|
||||
|
||||
config = snd_hda_codec_read(codec, nid, 0,
|
||||
AC_VERB_GET_CONFIG_DEFAULT, 0);
|
||||
if (get_defcfg_connect(config) == AC_JACK_PORT_NONE)
|
||||
continue;
|
||||
|
||||
hdmi_add_pin(codec, nid);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < num_tmp_cvts; i++)
|
||||
hdmi_add_cvt(codec, tmp_cvt[i]);
|
||||
|
||||
/*
|
||||
* G45/IbexPeak don't support EPSS: the unsolicited pin hot plug event
|
||||
* can be lost and presence sense verb will become inaccurate if the
|
||||
@ -1165,11 +1193,53 @@ static int nvhdmi_7x_init(struct hda_codec *codec)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int channels_2_6_8[] = {
|
||||
2, 6, 8
|
||||
};
|
||||
|
||||
static unsigned int channels_2_8[] = {
|
||||
2, 8
|
||||
};
|
||||
|
||||
static struct snd_pcm_hw_constraint_list hw_constraints_2_6_8_channels = {
|
||||
.count = ARRAY_SIZE(channels_2_6_8),
|
||||
.list = channels_2_6_8,
|
||||
.mask = 0,
|
||||
};
|
||||
|
||||
static struct snd_pcm_hw_constraint_list hw_constraints_2_8_channels = {
|
||||
.count = ARRAY_SIZE(channels_2_8),
|
||||
.list = channels_2_8,
|
||||
.mask = 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;
|
||||
struct snd_pcm_hw_constraint_list *hw_constraints_channels = NULL;
|
||||
|
||||
switch (codec->preset->id) {
|
||||
case 0x10de0002:
|
||||
case 0x10de0003:
|
||||
case 0x10de0005:
|
||||
case 0x10de0006:
|
||||
hw_constraints_channels = &hw_constraints_2_8_channels;
|
||||
break;
|
||||
case 0x10de0007:
|
||||
hw_constraints_channels = &hw_constraints_2_6_8_channels;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (hw_constraints_channels != NULL) {
|
||||
snd_pcm_hw_constraint_list(substream->runtime, 0,
|
||||
SNDRV_PCM_HW_PARAM_CHANNELS,
|
||||
hw_constraints_channels);
|
||||
}
|
||||
|
||||
return snd_hda_multi_out_dig_open(codec, &spec->multiout);
|
||||
}
|
||||
|
||||
@ -1532,7 +1602,7 @@ 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 = 0x1002aa01, .name = "R6xx HDMI", .patch = patch_generic_hdmi },
|
||||
{ .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 },
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -389,6 +389,9 @@ static hda_nid_t stac92hd83xxx_dmic_nids[STAC92HD83XXX_NUM_DMICS + 1] = {
|
||||
0x11, 0x20, 0
|
||||
};
|
||||
|
||||
#define STAC92HD88XXX_NUM_DMICS STAC92HD83XXX_NUM_DMICS
|
||||
#define stac92hd88xxx_dmic_nids stac92hd83xxx_dmic_nids
|
||||
|
||||
#define STAC92HD87B_NUM_DMICS 1
|
||||
static hda_nid_t stac92hd87b_dmic_nids[STAC92HD87B_NUM_DMICS + 1] = {
|
||||
0x11, 0
|
||||
@ -3591,7 +3594,7 @@ static int stac_check_auto_mic(struct hda_codec *codec)
|
||||
if (check_mic_pin(codec, spec->dmic_nids[i],
|
||||
&fixed, &ext, &dock))
|
||||
return 0;
|
||||
if (!fixed && !ext && !dock)
|
||||
if (!fixed || (!ext && !dock))
|
||||
return 0; /* no input to switch */
|
||||
if (!(get_wcaps(codec, ext) & AC_WCAP_UNSOL_CAP))
|
||||
return 0; /* no unsol support */
|
||||
@ -5422,7 +5425,7 @@ static int patch_stac92hd83xxx(struct hda_codec *codec)
|
||||
snd_hda_codec_write_cache(codec, codec->afg, 0, 0x7ED, 0);
|
||||
codec->no_trigger_sense = 1;
|
||||
codec->spec = spec;
|
||||
spec->linear_tone_beep = 1;
|
||||
spec->linear_tone_beep = 0;
|
||||
codec->slave_dig_outs = stac92hd83xxx_slave_dig_outs;
|
||||
spec->digbeep_nid = 0x21;
|
||||
spec->dmic_nids = stac92hd83xxx_dmic_nids;
|
||||
@ -5462,15 +5465,21 @@ again:
|
||||
spec->num_dmics = stac92xx_connected_ports(codec,
|
||||
stac92hd87b_dmic_nids,
|
||||
STAC92HD87B_NUM_DMICS);
|
||||
/* Fall through */
|
||||
spec->num_pins = ARRAY_SIZE(stac92hd88xxx_pin_nids);
|
||||
spec->pin_nids = stac92hd88xxx_pin_nids;
|
||||
spec->mono_nid = 0;
|
||||
spec->num_pwrs = 0;
|
||||
break;
|
||||
case 0x111d7666:
|
||||
case 0x111d7667:
|
||||
case 0x111d7668:
|
||||
case 0x111d7669:
|
||||
spec->num_dmics = stac92xx_connected_ports(codec,
|
||||
stac92hd88xxx_dmic_nids,
|
||||
STAC92HD88XXX_NUM_DMICS);
|
||||
spec->num_pins = ARRAY_SIZE(stac92hd88xxx_pin_nids);
|
||||
spec->pin_nids = stac92hd88xxx_pin_nids;
|
||||
spec->mono_nid = 0;
|
||||
spec->digbeep_nid = 0;
|
||||
spec->num_pwrs = 0;
|
||||
break;
|
||||
case 0x111d7604:
|
||||
|
@ -263,8 +263,7 @@ static void vt1708_stop_hp_work(struct via_spec *spec)
|
||||
return;
|
||||
snd_hda_codec_write(spec->codec, 0x1, 0, 0xf81,
|
||||
!spec->vt1708_jack_detectect);
|
||||
cancel_delayed_work(&spec->vt1708_hp_work);
|
||||
flush_scheduled_work();
|
||||
cancel_delayed_work_sync(&spec->vt1708_hp_work);
|
||||
}
|
||||
|
||||
|
||||
|
@ -96,6 +96,11 @@ static unsigned char ap_cs8427_codec_select(struct snd_ice1712 *ice)
|
||||
tmp |= ICE1712_DELTA_AP_CCLK | ICE1712_DELTA_AP_CS_CODEC;
|
||||
tmp &= ~ICE1712_DELTA_AP_CS_DIGITAL;
|
||||
break;
|
||||
case ICE1712_SUBDEVICE_DELTA66E:
|
||||
tmp |= ICE1712_DELTA_66E_CCLK | ICE1712_DELTA_66E_CS_CHIP_A |
|
||||
ICE1712_DELTA_66E_CS_CHIP_B;
|
||||
tmp &= ~ICE1712_DELTA_66E_CS_CS8427;
|
||||
break;
|
||||
case ICE1712_SUBDEVICE_VX442:
|
||||
tmp |= ICE1712_VX442_CCLK | ICE1712_VX442_CODEC_CHIP_A | ICE1712_VX442_CODEC_CHIP_B;
|
||||
tmp &= ~ICE1712_VX442_CS_DIGITAL;
|
||||
@ -119,6 +124,9 @@ static void ap_cs8427_codec_deassert(struct snd_ice1712 *ice, unsigned char tmp)
|
||||
case ICE1712_SUBDEVICE_DELTA410:
|
||||
tmp |= ICE1712_DELTA_AP_CS_DIGITAL;
|
||||
break;
|
||||
case ICE1712_SUBDEVICE_DELTA66E:
|
||||
tmp |= ICE1712_DELTA_66E_CS_CS8427;
|
||||
break;
|
||||
case ICE1712_SUBDEVICE_VX442:
|
||||
tmp |= ICE1712_VX442_CS_DIGITAL;
|
||||
break;
|
||||
@ -275,6 +283,20 @@ static void delta1010lt_ak4524_lock(struct snd_akm4xxx *ak, int chip)
|
||||
priv->cs_addr = chip << 4;
|
||||
}
|
||||
|
||||
/*
|
||||
* AK4524 on Delta66 rev E to choose the chip address
|
||||
*/
|
||||
static void delta66e_ak4524_lock(struct snd_akm4xxx *ak, int chip)
|
||||
{
|
||||
struct snd_ak4xxx_private *priv = (void *)ak->private_value[0];
|
||||
struct snd_ice1712 *ice = ak->private_data[0];
|
||||
|
||||
snd_ice1712_save_gpio_status(ice);
|
||||
priv->cs_mask =
|
||||
priv->cs_addr = chip == 0 ? ICE1712_DELTA_66E_CS_CHIP_A :
|
||||
ICE1712_DELTA_66E_CS_CHIP_B;
|
||||
}
|
||||
|
||||
/*
|
||||
* AK4528 on VX442 to choose the chip mask
|
||||
*/
|
||||
@ -487,6 +509,29 @@ static struct snd_ak4xxx_private akm_delta1010lt_priv __devinitdata = {
|
||||
.mask_flags = 0,
|
||||
};
|
||||
|
||||
static struct snd_akm4xxx akm_delta66e __devinitdata = {
|
||||
.type = SND_AK4524,
|
||||
.num_adcs = 4,
|
||||
.num_dacs = 4,
|
||||
.ops = {
|
||||
.lock = delta66e_ak4524_lock,
|
||||
.set_rate_val = delta_ak4524_set_rate_val
|
||||
}
|
||||
};
|
||||
|
||||
static struct snd_ak4xxx_private akm_delta66e_priv __devinitdata = {
|
||||
.caddr = 2,
|
||||
.cif = 0, /* the default level of the CIF pin from AK4524 */
|
||||
.data_mask = ICE1712_DELTA_66E_DOUT,
|
||||
.clk_mask = ICE1712_DELTA_66E_CCLK,
|
||||
.cs_mask = 0,
|
||||
.cs_addr = 0, /* set later */
|
||||
.cs_none = 0,
|
||||
.add_flags = 0,
|
||||
.mask_flags = 0,
|
||||
};
|
||||
|
||||
|
||||
static struct snd_akm4xxx akm_delta44 __devinitdata = {
|
||||
.type = SND_AK4524,
|
||||
.num_adcs = 4,
|
||||
@ -644,9 +689,11 @@ static int __devinit snd_ice1712_delta_init(struct snd_ice1712 *ice)
|
||||
err = snd_ice1712_akm4xxx_init(ak, &akm_delta44, &akm_delta44_priv, ice);
|
||||
break;
|
||||
case ICE1712_SUBDEVICE_VX442:
|
||||
case ICE1712_SUBDEVICE_DELTA66E:
|
||||
err = snd_ice1712_akm4xxx_init(ak, &akm_vx442, &akm_vx442_priv, ice);
|
||||
break;
|
||||
case ICE1712_SUBDEVICE_DELTA66E:
|
||||
err = snd_ice1712_akm4xxx_init(ak, &akm_delta66e, &akm_delta66e_priv, ice);
|
||||
break;
|
||||
default:
|
||||
snd_BUG();
|
||||
return -EINVAL;
|
||||
|
@ -144,6 +144,17 @@ extern struct snd_ice1712_card_info snd_ice1712_delta_cards[];
|
||||
#define ICE1712_DELTA_1010LT_CS_NONE 0x50 /* nothing */
|
||||
#define ICE1712_DELTA_1010LT_WORDCLOCK 0x80 /* sample clock source: 0 = Word Clock Input, 1 = S/PDIF Input ??? */
|
||||
|
||||
/* M-Audio Delta 66 rev. E definitions.
|
||||
* Newer revisions of Delta 66 have CS8427 over SPI for
|
||||
* S/PDIF transceiver instead of CS8404/CS8414. */
|
||||
/* 0x01 = DFS */
|
||||
#define ICE1712_DELTA_66E_CCLK 0x02 /* SPI clock */
|
||||
#define ICE1712_DELTA_66E_DIN 0x04 /* data input */
|
||||
#define ICE1712_DELTA_66E_DOUT 0x08 /* data output */
|
||||
#define ICE1712_DELTA_66E_CS_CS8427 0x10 /* chip select, low = CS8427 */
|
||||
#define ICE1712_DELTA_66E_CS_CHIP_A 0x20 /* AK4524 #0 */
|
||||
#define ICE1712_DELTA_66E_CS_CHIP_B 0x40 /* AK4524 #1 */
|
||||
|
||||
/* Digigram VX442 definitions */
|
||||
#define ICE1712_VX442_CCLK 0x02 /* SPI clock */
|
||||
#define ICE1712_VX442_DIN 0x04 /* data input */
|
||||
|
@ -1,10 +1,8 @@
|
||||
snd-oxygen-lib-objs := oxygen_io.o oxygen_lib.o oxygen_mixer.o oxygen_pcm.o
|
||||
snd-hifier-objs := hifier.o
|
||||
snd-oxygen-objs := oxygen.o
|
||||
snd-oxygen-objs := oxygen.o xonar_dg.o
|
||||
snd-virtuoso-objs := virtuoso.o xonar_lib.o \
|
||||
xonar_pcm179x.o xonar_cs43xx.o xonar_wm87x6.o xonar_hdmi.o
|
||||
|
||||
obj-$(CONFIG_SND_OXYGEN_LIB) += snd-oxygen-lib.o
|
||||
obj-$(CONFIG_SND_HIFIER) += snd-hifier.o
|
||||
obj-$(CONFIG_SND_OXYGEN) += snd-oxygen.o
|
||||
obj-$(CONFIG_SND_VIRTUOSO) += snd-virtuoso.o
|
||||
|
107
sound/pci/oxygen/cs4245.h
Normal file
107
sound/pci/oxygen/cs4245.h
Normal file
@ -0,0 +1,107 @@
|
||||
#define CS4245_CHIP_ID 0x01
|
||||
#define CS4245_POWER_CTRL 0x02
|
||||
#define CS4245_DAC_CTRL_1 0x03
|
||||
#define CS4245_ADC_CTRL 0x04
|
||||
#define CS4245_MCLK_FREQ 0x05
|
||||
#define CS4245_SIGNAL_SEL 0x06
|
||||
#define CS4245_PGA_B_CTRL 0x07
|
||||
#define CS4245_PGA_A_CTRL 0x08
|
||||
#define CS4245_ANALOG_IN 0x09
|
||||
#define CS4245_DAC_A_CTRL 0x0a
|
||||
#define CS4245_DAC_B_CTRL 0x0b
|
||||
#define CS4245_DAC_CTRL_2 0x0c
|
||||
#define CS4245_INT_STATUS 0x0d
|
||||
#define CS4245_INT_MASK 0x0e
|
||||
#define CS4245_INT_MODE_MSB 0x0f
|
||||
#define CS4245_INT_MODE_LSB 0x10
|
||||
|
||||
/* Chip ID */
|
||||
#define CS4245_CHIP_PART_MASK 0xf0
|
||||
#define CS4245_CHIP_REV_MASK 0x0f
|
||||
|
||||
/* Power Control */
|
||||
#define CS4245_FREEZE 0x80
|
||||
#define CS4245_PDN_MIC 0x08
|
||||
#define CS4245_PDN_ADC 0x04
|
||||
#define CS4245_PDN_DAC 0x02
|
||||
#define CS4245_PDN 0x01
|
||||
|
||||
/* DAC Control */
|
||||
#define CS4245_DAC_FM_MASK 0xc0
|
||||
#define CS4245_DAC_FM_SINGLE 0x00
|
||||
#define CS4245_DAC_FM_DOUBLE 0x40
|
||||
#define CS4245_DAC_FM_QUAD 0x80
|
||||
#define CS4245_DAC_DIF_MASK 0x30
|
||||
#define CS4245_DAC_DIF_LJUST 0x00
|
||||
#define CS4245_DAC_DIF_I2S 0x10
|
||||
#define CS4245_DAC_DIF_RJUST_16 0x20
|
||||
#define CS4245_DAC_DIF_RJUST_24 0x30
|
||||
#define CS4245_RESERVED_1 0x08
|
||||
#define CS4245_MUTE_DAC 0x04
|
||||
#define CS4245_DEEMPH 0x02
|
||||
#define CS4245_DAC_MASTER 0x01
|
||||
|
||||
/* ADC Control */
|
||||
#define CS4245_ADC_FM_MASK 0xc0
|
||||
#define CS4245_ADC_FM_SINGLE 0x00
|
||||
#define CS4245_ADC_FM_DOUBLE 0x40
|
||||
#define CS4245_ADC_FM_QUAD 0x80
|
||||
#define CS4245_ADC_DIF_MASK 0x10
|
||||
#define CS4245_ADC_DIF_LJUST 0x00
|
||||
#define CS4245_ADC_DIF_I2S 0x10
|
||||
#define CS4245_MUTE_ADC 0x04
|
||||
#define CS4245_HPF_FREEZE 0x02
|
||||
#define CS4245_ADC_MASTER 0x01
|
||||
|
||||
/* MCLK Frequency */
|
||||
#define CS4245_MCLK1_MASK 0x70
|
||||
#define CS4245_MCLK1_SHIFT 4
|
||||
#define CS4245_MCLK2_MASK 0x07
|
||||
#define CS4245_MCLK2_SHIFT 0
|
||||
#define CS4245_MCLK_1 0
|
||||
#define CS4245_MCLK_1_5 1
|
||||
#define CS4245_MCLK_2 2
|
||||
#define CS4245_MCLK_3 3
|
||||
#define CS4245_MCLK_4 4
|
||||
|
||||
/* Signal Selection */
|
||||
#define CS4245_A_OUT_SEL_MASK 0x60
|
||||
#define CS4245_A_OUT_SEL_HIZ 0x00
|
||||
#define CS4245_A_OUT_SEL_DAC 0x20
|
||||
#define CS4245_A_OUT_SEL_PGA 0x40
|
||||
#define CS4245_LOOP 0x02
|
||||
#define CS4245_ASYNCH 0x01
|
||||
|
||||
/* Channel B/A PGA Control */
|
||||
#define CS4245_PGA_GAIN_MASK 0x3f
|
||||
|
||||
/* ADC Input Control */
|
||||
#define CS4245_PGA_SOFT 0x10
|
||||
#define CS4245_PGA_ZERO 0x08
|
||||
#define CS4245_SEL_MASK 0x07
|
||||
#define CS4245_SEL_MIC 0x00
|
||||
#define CS4245_SEL_INPUT_1 0x01
|
||||
#define CS4245_SEL_INPUT_2 0x02
|
||||
#define CS4245_SEL_INPUT_3 0x03
|
||||
#define CS4245_SEL_INPUT_4 0x04
|
||||
#define CS4245_SEL_INPUT_5 0x05
|
||||
#define CS4245_SEL_INPUT_6 0x06
|
||||
|
||||
/* DAC Channel A/B Volume Control */
|
||||
#define CS4245_VOL_MASK 0xff
|
||||
|
||||
/* DAC Control 2 */
|
||||
#define CS4245_DAC_SOFT 0x80
|
||||
#define CS4245_DAC_ZERO 0x40
|
||||
#define CS4245_INVERT_DAC 0x20
|
||||
#define CS4245_INT_ACTIVE_HIGH 0x01
|
||||
|
||||
/* Interrupt Status/Mask/Mode */
|
||||
#define CS4245_ADC_CLK_ERR 0x08
|
||||
#define CS4245_DAC_CLK_ERR 0x04
|
||||
#define CS4245_ADC_OVFL 0x02
|
||||
#define CS4245_ADC_UNDRFL 0x01
|
||||
|
||||
|
||||
#define CS4245_SPI_ADDRESS (0x9e << 16)
|
||||
#define CS4245_SPI_WRITE (0 << 16)
|
@ -1,239 +0,0 @@
|
||||
/*
|
||||
* C-Media CMI8788 driver for the MediaTek/TempoTec HiFier Fantasia
|
||||
*
|
||||
* Copyright (c) Clemens Ladisch <clemens@ladisch.de>
|
||||
*
|
||||
*
|
||||
* This driver is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License, version 2.
|
||||
*
|
||||
* 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 driver; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* CMI8788:
|
||||
*
|
||||
* SPI 0 -> AK4396
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/pci.h>
|
||||
#include <sound/control.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/tlv.h>
|
||||
#include "oxygen.h"
|
||||
#include "ak4396.h"
|
||||
|
||||
MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
|
||||
MODULE_DESCRIPTION("TempoTec HiFier driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
|
||||
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
|
||||
static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
|
||||
|
||||
module_param_array(index, int, NULL, 0444);
|
||||
MODULE_PARM_DESC(index, "card index");
|
||||
module_param_array(id, charp, NULL, 0444);
|
||||
MODULE_PARM_DESC(id, "ID string");
|
||||
module_param_array(enable, bool, NULL, 0444);
|
||||
MODULE_PARM_DESC(enable, "enable card");
|
||||
|
||||
static DEFINE_PCI_DEVICE_TABLE(hifier_ids) = {
|
||||
{ OXYGEN_PCI_SUBID(0x14c3, 0x1710) },
|
||||
{ OXYGEN_PCI_SUBID(0x14c3, 0x1711) },
|
||||
{ OXYGEN_PCI_SUBID_BROKEN_EEPROM },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, hifier_ids);
|
||||
|
||||
struct hifier_data {
|
||||
u8 ak4396_regs[5];
|
||||
};
|
||||
|
||||
static void ak4396_write(struct oxygen *chip, u8 reg, u8 value)
|
||||
{
|
||||
struct hifier_data *data = chip->model_data;
|
||||
|
||||
oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
|
||||
OXYGEN_SPI_DATA_LENGTH_2 |
|
||||
OXYGEN_SPI_CLOCK_160 |
|
||||
(0 << OXYGEN_SPI_CODEC_SHIFT) |
|
||||
OXYGEN_SPI_CEN_LATCH_CLOCK_HI,
|
||||
AK4396_WRITE | (reg << 8) | value);
|
||||
data->ak4396_regs[reg] = value;
|
||||
}
|
||||
|
||||
static void ak4396_write_cached(struct oxygen *chip, u8 reg, u8 value)
|
||||
{
|
||||
struct hifier_data *data = chip->model_data;
|
||||
|
||||
if (value != data->ak4396_regs[reg])
|
||||
ak4396_write(chip, reg, value);
|
||||
}
|
||||
|
||||
static void hifier_registers_init(struct oxygen *chip)
|
||||
{
|
||||
struct hifier_data *data = chip->model_data;
|
||||
|
||||
ak4396_write(chip, AK4396_CONTROL_1, AK4396_DIF_24_MSB | AK4396_RSTN);
|
||||
ak4396_write(chip, AK4396_CONTROL_2,
|
||||
data->ak4396_regs[AK4396_CONTROL_2]);
|
||||
ak4396_write(chip, AK4396_CONTROL_3, AK4396_PCM);
|
||||
ak4396_write(chip, AK4396_LCH_ATT, chip->dac_volume[0]);
|
||||
ak4396_write(chip, AK4396_RCH_ATT, chip->dac_volume[1]);
|
||||
}
|
||||
|
||||
static void hifier_init(struct oxygen *chip)
|
||||
{
|
||||
struct hifier_data *data = chip->model_data;
|
||||
|
||||
data->ak4396_regs[AK4396_CONTROL_2] =
|
||||
AK4396_SMUTE | AK4396_DEM_OFF | AK4396_DFS_NORMAL;
|
||||
hifier_registers_init(chip);
|
||||
|
||||
snd_component_add(chip->card, "AK4396");
|
||||
snd_component_add(chip->card, "CS5340");
|
||||
}
|
||||
|
||||
static void hifier_cleanup(struct oxygen *chip)
|
||||
{
|
||||
}
|
||||
|
||||
static void hifier_resume(struct oxygen *chip)
|
||||
{
|
||||
hifier_registers_init(chip);
|
||||
}
|
||||
|
||||
static void set_ak4396_params(struct oxygen *chip,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct hifier_data *data = chip->model_data;
|
||||
u8 value;
|
||||
|
||||
value = data->ak4396_regs[AK4396_CONTROL_2] & ~AK4396_DFS_MASK;
|
||||
if (params_rate(params) <= 54000)
|
||||
value |= AK4396_DFS_NORMAL;
|
||||
else if (params_rate(params) <= 108000)
|
||||
value |= AK4396_DFS_DOUBLE;
|
||||
else
|
||||
value |= AK4396_DFS_QUAD;
|
||||
|
||||
msleep(1); /* wait for the new MCLK to become stable */
|
||||
|
||||
if (value != data->ak4396_regs[AK4396_CONTROL_2]) {
|
||||
ak4396_write(chip, AK4396_CONTROL_1,
|
||||
AK4396_DIF_24_MSB);
|
||||
ak4396_write(chip, AK4396_CONTROL_2, value);
|
||||
ak4396_write(chip, AK4396_CONTROL_1,
|
||||
AK4396_DIF_24_MSB | AK4396_RSTN);
|
||||
}
|
||||
}
|
||||
|
||||
static void update_ak4396_volume(struct oxygen *chip)
|
||||
{
|
||||
ak4396_write_cached(chip, AK4396_LCH_ATT, chip->dac_volume[0]);
|
||||
ak4396_write_cached(chip, AK4396_RCH_ATT, chip->dac_volume[1]);
|
||||
}
|
||||
|
||||
static void update_ak4396_mute(struct oxygen *chip)
|
||||
{
|
||||
struct hifier_data *data = chip->model_data;
|
||||
u8 value;
|
||||
|
||||
value = data->ak4396_regs[AK4396_CONTROL_2] & ~AK4396_SMUTE;
|
||||
if (chip->dac_mute)
|
||||
value |= AK4396_SMUTE;
|
||||
ak4396_write_cached(chip, AK4396_CONTROL_2, value);
|
||||
}
|
||||
|
||||
static void set_cs5340_params(struct oxygen *chip,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
}
|
||||
|
||||
static const DECLARE_TLV_DB_LINEAR(ak4396_db_scale, TLV_DB_GAIN_MUTE, 0);
|
||||
|
||||
static const struct oxygen_model model_hifier = {
|
||||
.shortname = "C-Media CMI8787",
|
||||
.longname = "C-Media Oxygen HD Audio",
|
||||
.chip = "CMI8788",
|
||||
.init = hifier_init,
|
||||
.cleanup = hifier_cleanup,
|
||||
.resume = hifier_resume,
|
||||
.get_i2s_mclk = oxygen_default_i2s_mclk,
|
||||
.set_dac_params = set_ak4396_params,
|
||||
.set_adc_params = set_cs5340_params,
|
||||
.update_dac_volume = update_ak4396_volume,
|
||||
.update_dac_mute = update_ak4396_mute,
|
||||
.dac_tlv = ak4396_db_scale,
|
||||
.model_data_size = sizeof(struct hifier_data),
|
||||
.device_config = PLAYBACK_0_TO_I2S |
|
||||
PLAYBACK_1_TO_SPDIF |
|
||||
CAPTURE_0_FROM_I2S_1,
|
||||
.dac_channels = 2,
|
||||
.dac_volume_min = 0,
|
||||
.dac_volume_max = 255,
|
||||
.function_flags = OXYGEN_FUNCTION_SPI,
|
||||
.dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
|
||||
.adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
|
||||
};
|
||||
|
||||
static int __devinit get_hifier_model(struct oxygen *chip,
|
||||
const struct pci_device_id *id)
|
||||
{
|
||||
chip->model = model_hifier;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit hifier_probe(struct pci_dev *pci,
|
||||
const struct pci_device_id *pci_id)
|
||||
{
|
||||
static int dev;
|
||||
int err;
|
||||
|
||||
if (dev >= SNDRV_CARDS)
|
||||
return -ENODEV;
|
||||
if (!enable[dev]) {
|
||||
++dev;
|
||||
return -ENOENT;
|
||||
}
|
||||
err = oxygen_pci_probe(pci, index[dev], id[dev], THIS_MODULE,
|
||||
hifier_ids, get_hifier_model);
|
||||
if (err >= 0)
|
||||
++dev;
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct pci_driver hifier_driver = {
|
||||
.name = "CMI8787HiFier",
|
||||
.id_table = hifier_ids,
|
||||
.probe = hifier_probe,
|
||||
.remove = __devexit_p(oxygen_pci_remove),
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = oxygen_pci_suspend,
|
||||
.resume = oxygen_pci_resume,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int __init alsa_card_hifier_init(void)
|
||||
{
|
||||
return pci_register_driver(&hifier_driver);
|
||||
}
|
||||
|
||||
static void __exit alsa_card_hifier_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&hifier_driver);
|
||||
}
|
||||
|
||||
module_init(alsa_card_hifier_init)
|
||||
module_exit(alsa_card_hifier_exit)
|
@ -20,19 +20,32 @@
|
||||
/*
|
||||
* CMI8788:
|
||||
*
|
||||
* SPI 0 -> 1st AK4396 (front)
|
||||
* SPI 1 -> 2nd AK4396 (surround)
|
||||
* SPI 2 -> 3rd AK4396 (center/LFE)
|
||||
* SPI 3 -> WM8785
|
||||
* SPI 4 -> 4th AK4396 (back)
|
||||
* SPI 0 -> 1st AK4396 (front)
|
||||
* SPI 1 -> 2nd AK4396 (surround)
|
||||
* SPI 2 -> 3rd AK4396 (center/LFE)
|
||||
* SPI 3 -> WM8785
|
||||
* SPI 4 -> 4th AK4396 (back)
|
||||
*
|
||||
* GPIO 0 -> DFS0 of AK5385
|
||||
* GPIO 1 -> DFS1 of AK5385
|
||||
* GPIO 8 -> enable headphone amplifier on HT-Omega models
|
||||
* GPIO 0 -> DFS0 of AK5385
|
||||
* GPIO 1 -> DFS1 of AK5385
|
||||
*
|
||||
* X-Meridian models:
|
||||
* GPIO 4 -> enable extension S/PDIF input
|
||||
* GPIO 6 -> enable on-board S/PDIF input
|
||||
*
|
||||
* Claro models:
|
||||
* GPIO 6 -> S/PDIF from optical (0) or coaxial (1) input
|
||||
* GPIO 8 -> enable headphone amplifier
|
||||
*
|
||||
* CM9780:
|
||||
*
|
||||
* GPO 0 -> route line-in (0) or AC97 output (1) to ADC input
|
||||
* LINE_OUT -> input of ADC
|
||||
*
|
||||
* AUX_IN <- aux
|
||||
* CD_IN <- CD
|
||||
* MIC_IN <- mic
|
||||
*
|
||||
* GPO 0 -> route line-in (0) or AC97 output (1) to ADC input
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
@ -41,18 +54,22 @@
|
||||
#include <sound/ac97_codec.h>
|
||||
#include <sound/control.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/info.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/tlv.h>
|
||||
#include "oxygen.h"
|
||||
#include "xonar_dg.h"
|
||||
#include "ak4396.h"
|
||||
#include "wm8785.h"
|
||||
|
||||
MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
|
||||
MODULE_DESCRIPTION("C-Media CMI8788 driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_SUPPORTED_DEVICE("{{C-Media,CMI8788}}");
|
||||
MODULE_SUPPORTED_DEVICE("{{C-Media,CMI8786}"
|
||||
",{C-Media,CMI8787}"
|
||||
",{C-Media,CMI8788}}");
|
||||
|
||||
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
|
||||
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
|
||||
@ -66,24 +83,46 @@ module_param_array(enable, bool, NULL, 0444);
|
||||
MODULE_PARM_DESC(enable, "enable card");
|
||||
|
||||
enum {
|
||||
MODEL_CMEDIA_REF, /* C-Media's reference design */
|
||||
MODEL_MERIDIAN, /* AuzenTech X-Meridian */
|
||||
MODEL_CLARO, /* HT-Omega Claro */
|
||||
MODEL_CLARO_HALO, /* HT-Omega Claro halo */
|
||||
MODEL_CMEDIA_REF,
|
||||
MODEL_MERIDIAN,
|
||||
MODEL_MERIDIAN_2G,
|
||||
MODEL_CLARO,
|
||||
MODEL_CLARO_HALO,
|
||||
MODEL_FANTASIA,
|
||||
MODEL_SERENADE,
|
||||
MODEL_2CH_OUTPUT,
|
||||
MODEL_HG2PCI,
|
||||
MODEL_XONAR_DG,
|
||||
};
|
||||
|
||||
static DEFINE_PCI_DEVICE_TABLE(oxygen_ids) = {
|
||||
/* C-Media's reference design */
|
||||
{ OXYGEN_PCI_SUBID(0x10b0, 0x0216), .driver_data = MODEL_CMEDIA_REF },
|
||||
{ OXYGEN_PCI_SUBID(0x10b0, 0x0217), .driver_data = MODEL_CMEDIA_REF },
|
||||
{ OXYGEN_PCI_SUBID(0x10b0, 0x0218), .driver_data = MODEL_CMEDIA_REF },
|
||||
{ OXYGEN_PCI_SUBID(0x10b0, 0x0219), .driver_data = MODEL_CMEDIA_REF },
|
||||
{ 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 },
|
||||
/* Asus Xonar DG */
|
||||
{ OXYGEN_PCI_SUBID(0x1043, 0x8467), .driver_data = MODEL_XONAR_DG },
|
||||
/* PCI 2.0 HD Audio */
|
||||
{ OXYGEN_PCI_SUBID(0x13f6, 0x8782), .driver_data = MODEL_2CH_OUTPUT },
|
||||
/* Kuroutoshikou CMI8787-HG2PCI */
|
||||
{ OXYGEN_PCI_SUBID(0x13f6, 0xffff), .driver_data = MODEL_HG2PCI },
|
||||
/* TempoTec HiFier Fantasia */
|
||||
{ OXYGEN_PCI_SUBID(0x14c3, 0x1710), .driver_data = MODEL_FANTASIA },
|
||||
/* TempoTec HiFier Serenade */
|
||||
{ OXYGEN_PCI_SUBID(0x14c3, 0x1711), .driver_data = MODEL_SERENADE },
|
||||
/* AuzenTech X-Meridian */
|
||||
{ OXYGEN_PCI_SUBID(0x415a, 0x5431), .driver_data = MODEL_MERIDIAN },
|
||||
/* AuzenTech X-Meridian 2G */
|
||||
{ OXYGEN_PCI_SUBID(0x5431, 0x017a), .driver_data = MODEL_MERIDIAN_2G },
|
||||
/* HT-Omega Claro */
|
||||
{ OXYGEN_PCI_SUBID(0x7284, 0x9761), .driver_data = MODEL_CLARO },
|
||||
/* HT-Omega Claro halo */
|
||||
{ OXYGEN_PCI_SUBID(0x7284, 0x9781), .driver_data = MODEL_CLARO_HALO },
|
||||
{ }
|
||||
};
|
||||
@ -95,9 +134,15 @@ MODULE_DEVICE_TABLE(pci, oxygen_ids);
|
||||
#define GPIO_AK5385_DFS_DOUBLE 0x0001
|
||||
#define GPIO_AK5385_DFS_QUAD 0x0002
|
||||
|
||||
#define GPIO_MERIDIAN_DIG_MASK 0x0050
|
||||
#define GPIO_MERIDIAN_DIG_EXT 0x0010
|
||||
#define GPIO_MERIDIAN_DIG_BOARD 0x0040
|
||||
|
||||
#define GPIO_CLARO_DIG_COAX 0x0040
|
||||
#define GPIO_CLARO_HP 0x0100
|
||||
|
||||
struct generic_data {
|
||||
unsigned int dacs;
|
||||
u8 ak4396_regs[4][5];
|
||||
u16 wm8785_regs[3];
|
||||
};
|
||||
@ -148,7 +193,7 @@ static void ak4396_registers_init(struct oxygen *chip)
|
||||
struct generic_data *data = chip->model_data;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < 4; ++i) {
|
||||
for (i = 0; i < data->dacs; ++i) {
|
||||
ak4396_write(chip, i, AK4396_CONTROL_1,
|
||||
AK4396_DIF_24_MSB | AK4396_RSTN);
|
||||
ak4396_write(chip, i, AK4396_CONTROL_2,
|
||||
@ -166,6 +211,7 @@ static void ak4396_init(struct oxygen *chip)
|
||||
{
|
||||
struct generic_data *data = chip->model_data;
|
||||
|
||||
data->dacs = chip->model.dac_channels_pcm / 2;
|
||||
data->ak4396_regs[0][AK4396_CONTROL_2] =
|
||||
AK4396_SMUTE | AK4396_DEM_OFF | AK4396_DFS_NORMAL;
|
||||
ak4396_registers_init(chip);
|
||||
@ -207,6 +253,10 @@ static void generic_init(struct oxygen *chip)
|
||||
|
||||
static void meridian_init(struct oxygen *chip)
|
||||
{
|
||||
oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
|
||||
GPIO_MERIDIAN_DIG_MASK);
|
||||
oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
|
||||
GPIO_MERIDIAN_DIG_BOARD, GPIO_MERIDIAN_DIG_MASK);
|
||||
ak4396_init(chip);
|
||||
ak5385_init(chip);
|
||||
}
|
||||
@ -220,6 +270,8 @@ static void claro_enable_hp(struct oxygen *chip)
|
||||
|
||||
static void claro_init(struct oxygen *chip)
|
||||
{
|
||||
oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_CLARO_DIG_COAX);
|
||||
oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_CLARO_DIG_COAX);
|
||||
ak4396_init(chip);
|
||||
wm8785_init(chip);
|
||||
claro_enable_hp(chip);
|
||||
@ -227,11 +279,24 @@ static void claro_init(struct oxygen *chip)
|
||||
|
||||
static void claro_halo_init(struct oxygen *chip)
|
||||
{
|
||||
oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_CLARO_DIG_COAX);
|
||||
oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_CLARO_DIG_COAX);
|
||||
ak4396_init(chip);
|
||||
ak5385_init(chip);
|
||||
claro_enable_hp(chip);
|
||||
}
|
||||
|
||||
static void fantasia_init(struct oxygen *chip)
|
||||
{
|
||||
ak4396_init(chip);
|
||||
snd_component_add(chip->card, "CS5340");
|
||||
}
|
||||
|
||||
static void stereo_output_init(struct oxygen *chip)
|
||||
{
|
||||
ak4396_init(chip);
|
||||
}
|
||||
|
||||
static void generic_cleanup(struct oxygen *chip)
|
||||
{
|
||||
}
|
||||
@ -268,6 +333,11 @@ static void claro_resume(struct oxygen *chip)
|
||||
claro_enable_hp(chip);
|
||||
}
|
||||
|
||||
static void stereo_resume(struct oxygen *chip)
|
||||
{
|
||||
ak4396_registers_init(chip);
|
||||
}
|
||||
|
||||
static void set_ak4396_params(struct oxygen *chip,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
@ -286,7 +356,7 @@ static void set_ak4396_params(struct oxygen *chip,
|
||||
msleep(1); /* wait for the new MCLK to become stable */
|
||||
|
||||
if (value != data->ak4396_regs[0][AK4396_CONTROL_2]) {
|
||||
for (i = 0; i < 4; ++i) {
|
||||
for (i = 0; i < data->dacs; ++i) {
|
||||
ak4396_write(chip, i, AK4396_CONTROL_1,
|
||||
AK4396_DIF_24_MSB);
|
||||
ak4396_write(chip, i, AK4396_CONTROL_2, value);
|
||||
@ -298,9 +368,10 @@ static void set_ak4396_params(struct oxygen *chip,
|
||||
|
||||
static void update_ak4396_volume(struct oxygen *chip)
|
||||
{
|
||||
struct generic_data *data = chip->model_data;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < 4; ++i) {
|
||||
for (i = 0; i < data->dacs; ++i) {
|
||||
ak4396_write_cached(chip, i, AK4396_LCH_ATT,
|
||||
chip->dac_volume[i * 2]);
|
||||
ak4396_write_cached(chip, i, AK4396_RCH_ATT,
|
||||
@ -317,7 +388,7 @@ static void update_ak4396_mute(struct oxygen *chip)
|
||||
value = data->ak4396_regs[0][AK4396_CONTROL_2] & ~AK4396_SMUTE;
|
||||
if (chip->dac_mute)
|
||||
value |= AK4396_SMUTE;
|
||||
for (i = 0; i < 4; ++i)
|
||||
for (i = 0; i < data->dacs; ++i)
|
||||
ak4396_write_cached(chip, i, AK4396_CONTROL_2, value);
|
||||
}
|
||||
|
||||
@ -356,6 +427,10 @@ static void set_ak5385_params(struct oxygen *chip,
|
||||
value, GPIO_AK5385_DFS_MASK);
|
||||
}
|
||||
|
||||
static void set_no_params(struct oxygen *chip, struct snd_pcm_hw_params *params)
|
||||
{
|
||||
}
|
||||
|
||||
static int rolloff_info(struct snd_kcontrol *ctl,
|
||||
struct snd_ctl_elem_info *info)
|
||||
{
|
||||
@ -363,13 +438,7 @@ static int rolloff_info(struct snd_kcontrol *ctl,
|
||||
"Sharp Roll-off", "Slow Roll-off"
|
||||
};
|
||||
|
||||
info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
|
||||
info->count = 1;
|
||||
info->value.enumerated.items = 2;
|
||||
if (info->value.enumerated.item >= 2)
|
||||
info->value.enumerated.item = 1;
|
||||
strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
|
||||
return 0;
|
||||
return snd_ctl_enum_info(info, 1, 2, names);
|
||||
}
|
||||
|
||||
static int rolloff_get(struct snd_kcontrol *ctl,
|
||||
@ -400,7 +469,7 @@ static int rolloff_put(struct snd_kcontrol *ctl,
|
||||
reg &= ~AK4396_SLOW;
|
||||
changed = reg != data->ak4396_regs[0][AK4396_CONTROL_2];
|
||||
if (changed) {
|
||||
for (i = 0; i < 4; ++i)
|
||||
for (i = 0; i < data->dacs; ++i)
|
||||
ak4396_write(chip, i, AK4396_CONTROL_2, reg);
|
||||
}
|
||||
mutex_unlock(&chip->mutex);
|
||||
@ -421,13 +490,7 @@ static int hpf_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info)
|
||||
"None", "High-pass Filter"
|
||||
};
|
||||
|
||||
info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
|
||||
info->count = 1;
|
||||
info->value.enumerated.items = 2;
|
||||
if (info->value.enumerated.item >= 2)
|
||||
info->value.enumerated.item = 1;
|
||||
strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
|
||||
return 0;
|
||||
return snd_ctl_enum_info(info, 1, 2, names);
|
||||
}
|
||||
|
||||
static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
|
||||
@ -466,6 +529,100 @@ static const struct snd_kcontrol_new hpf_control = {
|
||||
.put = hpf_put,
|
||||
};
|
||||
|
||||
static int meridian_dig_source_info(struct snd_kcontrol *ctl,
|
||||
struct snd_ctl_elem_info *info)
|
||||
{
|
||||
static const char *const names[2] = { "On-board", "Extension" };
|
||||
|
||||
return snd_ctl_enum_info(info, 1, 2, names);
|
||||
}
|
||||
|
||||
static int claro_dig_source_info(struct snd_kcontrol *ctl,
|
||||
struct snd_ctl_elem_info *info)
|
||||
{
|
||||
static const char *const names[2] = { "Optical", "Coaxial" };
|
||||
|
||||
return snd_ctl_enum_info(info, 1, 2, names);
|
||||
}
|
||||
|
||||
static int meridian_dig_source_get(struct snd_kcontrol *ctl,
|
||||
struct snd_ctl_elem_value *value)
|
||||
{
|
||||
struct oxygen *chip = ctl->private_data;
|
||||
|
||||
value->value.enumerated.item[0] =
|
||||
!!(oxygen_read16(chip, OXYGEN_GPIO_DATA) &
|
||||
GPIO_MERIDIAN_DIG_EXT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int claro_dig_source_get(struct snd_kcontrol *ctl,
|
||||
struct snd_ctl_elem_value *value)
|
||||
{
|
||||
struct oxygen *chip = ctl->private_data;
|
||||
|
||||
value->value.enumerated.item[0] =
|
||||
!!(oxygen_read16(chip, OXYGEN_GPIO_DATA) &
|
||||
GPIO_CLARO_DIG_COAX);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int meridian_dig_source_put(struct snd_kcontrol *ctl,
|
||||
struct snd_ctl_elem_value *value)
|
||||
{
|
||||
struct oxygen *chip = ctl->private_data;
|
||||
u16 old_reg, new_reg;
|
||||
int changed;
|
||||
|
||||
mutex_lock(&chip->mutex);
|
||||
old_reg = oxygen_read16(chip, OXYGEN_GPIO_DATA);
|
||||
new_reg = old_reg & ~GPIO_MERIDIAN_DIG_MASK;
|
||||
if (value->value.enumerated.item[0] == 0)
|
||||
new_reg |= GPIO_MERIDIAN_DIG_BOARD;
|
||||
else
|
||||
new_reg |= GPIO_MERIDIAN_DIG_EXT;
|
||||
changed = new_reg != old_reg;
|
||||
if (changed)
|
||||
oxygen_write16(chip, OXYGEN_GPIO_DATA, new_reg);
|
||||
mutex_unlock(&chip->mutex);
|
||||
return changed;
|
||||
}
|
||||
|
||||
static int claro_dig_source_put(struct snd_kcontrol *ctl,
|
||||
struct snd_ctl_elem_value *value)
|
||||
{
|
||||
struct oxygen *chip = ctl->private_data;
|
||||
u16 old_reg, new_reg;
|
||||
int changed;
|
||||
|
||||
mutex_lock(&chip->mutex);
|
||||
old_reg = oxygen_read16(chip, OXYGEN_GPIO_DATA);
|
||||
new_reg = old_reg & ~GPIO_CLARO_DIG_COAX;
|
||||
if (value->value.enumerated.item[0])
|
||||
new_reg |= GPIO_CLARO_DIG_COAX;
|
||||
changed = new_reg != old_reg;
|
||||
if (changed)
|
||||
oxygen_write16(chip, OXYGEN_GPIO_DATA, new_reg);
|
||||
mutex_unlock(&chip->mutex);
|
||||
return changed;
|
||||
}
|
||||
|
||||
static const struct snd_kcontrol_new meridian_dig_source_control = {
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "IEC958 Source Capture Enum",
|
||||
.info = meridian_dig_source_info,
|
||||
.get = meridian_dig_source_get,
|
||||
.put = meridian_dig_source_put,
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new claro_dig_source_control = {
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "IEC958 Source Capture Enum",
|
||||
.info = claro_dig_source_info,
|
||||
.get = claro_dig_source_get,
|
||||
.put = claro_dig_source_put,
|
||||
};
|
||||
|
||||
static int generic_mixer_init(struct oxygen *chip)
|
||||
{
|
||||
return snd_ctl_add(chip->card, snd_ctl_new1(&rolloff_control, chip));
|
||||
@ -484,6 +641,81 @@ static int generic_wm8785_mixer_init(struct oxygen *chip)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int meridian_mixer_init(struct oxygen *chip)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = generic_mixer_init(chip);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = snd_ctl_add(chip->card,
|
||||
snd_ctl_new1(&meridian_dig_source_control, chip));
|
||||
if (err < 0)
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int claro_mixer_init(struct oxygen *chip)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = generic_wm8785_mixer_init(chip);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = snd_ctl_add(chip->card,
|
||||
snd_ctl_new1(&claro_dig_source_control, chip));
|
||||
if (err < 0)
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int claro_halo_mixer_init(struct oxygen *chip)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = generic_mixer_init(chip);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = snd_ctl_add(chip->card,
|
||||
snd_ctl_new1(&claro_dig_source_control, chip));
|
||||
if (err < 0)
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dump_ak4396_registers(struct oxygen *chip,
|
||||
struct snd_info_buffer *buffer)
|
||||
{
|
||||
struct generic_data *data = chip->model_data;
|
||||
unsigned int dac, i;
|
||||
|
||||
for (dac = 0; dac < data->dacs; ++dac) {
|
||||
snd_iprintf(buffer, "\nAK4396 %u:", dac + 1);
|
||||
for (i = 0; i < 5; ++i)
|
||||
snd_iprintf(buffer, " %02x", data->ak4396_regs[dac][i]);
|
||||
}
|
||||
snd_iprintf(buffer, "\n");
|
||||
}
|
||||
|
||||
static void dump_wm8785_registers(struct oxygen *chip,
|
||||
struct snd_info_buffer *buffer)
|
||||
{
|
||||
struct generic_data *data = chip->model_data;
|
||||
unsigned int i;
|
||||
|
||||
snd_iprintf(buffer, "\nWM8785:");
|
||||
for (i = 0; i < 3; ++i)
|
||||
snd_iprintf(buffer, " %03x", data->wm8785_regs[i]);
|
||||
snd_iprintf(buffer, "\n");
|
||||
}
|
||||
|
||||
static void dump_oxygen_registers(struct oxygen *chip,
|
||||
struct snd_info_buffer *buffer)
|
||||
{
|
||||
dump_ak4396_registers(chip, buffer);
|
||||
dump_wm8785_registers(chip, buffer);
|
||||
}
|
||||
|
||||
static const DECLARE_TLV_DB_LINEAR(ak4396_db_scale, TLV_DB_GAIN_MUTE, 0);
|
||||
|
||||
static const struct oxygen_model model_generic = {
|
||||
@ -494,11 +726,11 @@ static const struct oxygen_model model_generic = {
|
||||
.mixer_init = generic_wm8785_mixer_init,
|
||||
.cleanup = generic_cleanup,
|
||||
.resume = generic_resume,
|
||||
.get_i2s_mclk = oxygen_default_i2s_mclk,
|
||||
.set_dac_params = set_ak4396_params,
|
||||
.set_adc_params = set_wm8785_params,
|
||||
.update_dac_volume = update_ak4396_volume,
|
||||
.update_dac_mute = update_ak4396_mute,
|
||||
.dump_registers = dump_oxygen_registers,
|
||||
.dac_tlv = ak4396_db_scale,
|
||||
.model_data_size = sizeof(struct generic_data),
|
||||
.device_config = PLAYBACK_0_TO_I2S |
|
||||
@ -508,11 +740,14 @@ static const struct oxygen_model model_generic = {
|
||||
CAPTURE_1_FROM_SPDIF |
|
||||
CAPTURE_2_FROM_AC97_1 |
|
||||
AC97_CD_INPUT,
|
||||
.dac_channels = 8,
|
||||
.dac_channels_pcm = 8,
|
||||
.dac_channels_mixer = 8,
|
||||
.dac_volume_min = 0,
|
||||
.dac_volume_max = 255,
|
||||
.function_flags = OXYGEN_FUNCTION_SPI |
|
||||
OXYGEN_FUNCTION_ENABLE_SPI_4_5,
|
||||
.dac_mclks = OXYGEN_MCLKS(256, 128, 128),
|
||||
.adc_mclks = OXYGEN_MCLKS(256, 256, 128),
|
||||
.dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
|
||||
.adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
|
||||
};
|
||||
@ -520,42 +755,87 @@ static const struct oxygen_model model_generic = {
|
||||
static int __devinit get_oxygen_model(struct oxygen *chip,
|
||||
const struct pci_device_id *id)
|
||||
{
|
||||
static const char *const names[] = {
|
||||
[MODEL_MERIDIAN] = "AuzenTech X-Meridian",
|
||||
[MODEL_MERIDIAN_2G] = "AuzenTech X-Meridian 2G",
|
||||
[MODEL_CLARO] = "HT-Omega Claro",
|
||||
[MODEL_CLARO_HALO] = "HT-Omega Claro halo",
|
||||
[MODEL_FANTASIA] = "TempoTec HiFier Fantasia",
|
||||
[MODEL_SERENADE] = "TempoTec HiFier Serenade",
|
||||
[MODEL_HG2PCI] = "CMI8787-HG2PCI",
|
||||
};
|
||||
|
||||
chip->model = model_generic;
|
||||
switch (id->driver_data) {
|
||||
case MODEL_MERIDIAN:
|
||||
case MODEL_MERIDIAN_2G:
|
||||
chip->model.init = meridian_init;
|
||||
chip->model.mixer_init = generic_mixer_init;
|
||||
chip->model.mixer_init = meridian_mixer_init;
|
||||
chip->model.resume = meridian_resume;
|
||||
chip->model.set_adc_params = set_ak5385_params;
|
||||
chip->model.dump_registers = dump_ak4396_registers;
|
||||
chip->model.device_config = PLAYBACK_0_TO_I2S |
|
||||
PLAYBACK_1_TO_SPDIF |
|
||||
CAPTURE_0_FROM_I2S_2 |
|
||||
CAPTURE_1_FROM_SPDIF;
|
||||
if (id->driver_data == MODEL_MERIDIAN)
|
||||
chip->model.device_config |= AC97_CD_INPUT;
|
||||
break;
|
||||
case MODEL_CLARO:
|
||||
chip->model.init = claro_init;
|
||||
chip->model.mixer_init = claro_mixer_init;
|
||||
chip->model.cleanup = claro_cleanup;
|
||||
chip->model.suspend = claro_suspend;
|
||||
chip->model.resume = claro_resume;
|
||||
break;
|
||||
case MODEL_CLARO_HALO:
|
||||
chip->model.init = claro_halo_init;
|
||||
chip->model.mixer_init = generic_mixer_init;
|
||||
chip->model.mixer_init = claro_halo_mixer_init;
|
||||
chip->model.cleanup = claro_cleanup;
|
||||
chip->model.suspend = claro_suspend;
|
||||
chip->model.resume = claro_resume;
|
||||
chip->model.set_adc_params = set_ak5385_params;
|
||||
chip->model.dump_registers = dump_ak4396_registers;
|
||||
chip->model.device_config = PLAYBACK_0_TO_I2S |
|
||||
PLAYBACK_1_TO_SPDIF |
|
||||
CAPTURE_0_FROM_I2S_2 |
|
||||
CAPTURE_1_FROM_SPDIF;
|
||||
break;
|
||||
case MODEL_FANTASIA:
|
||||
case MODEL_SERENADE:
|
||||
case MODEL_2CH_OUTPUT:
|
||||
case MODEL_HG2PCI:
|
||||
chip->model.shortname = "C-Media CMI8787";
|
||||
chip->model.chip = "CMI8787";
|
||||
if (id->driver_data == MODEL_FANTASIA)
|
||||
chip->model.init = fantasia_init;
|
||||
else
|
||||
chip->model.init = stereo_output_init;
|
||||
chip->model.resume = stereo_resume;
|
||||
chip->model.mixer_init = generic_mixer_init;
|
||||
chip->model.set_adc_params = set_no_params;
|
||||
chip->model.dump_registers = dump_ak4396_registers;
|
||||
chip->model.device_config = PLAYBACK_0_TO_I2S |
|
||||
PLAYBACK_1_TO_SPDIF;
|
||||
if (id->driver_data == MODEL_FANTASIA) {
|
||||
chip->model.device_config |= CAPTURE_0_FROM_I2S_1;
|
||||
chip->model.adc_mclks = OXYGEN_MCLKS(256, 128, 128);
|
||||
}
|
||||
chip->model.dac_channels_pcm = 2;
|
||||
chip->model.dac_channels_mixer = 2;
|
||||
break;
|
||||
case MODEL_XONAR_DG:
|
||||
chip->model = model_xonar_dg;
|
||||
break;
|
||||
}
|
||||
if (id->driver_data == MODEL_MERIDIAN ||
|
||||
id->driver_data == MODEL_MERIDIAN_2G ||
|
||||
id->driver_data == MODEL_CLARO_HALO) {
|
||||
chip->model.misc_flags = OXYGEN_MISC_MIDI;
|
||||
chip->model.device_config |= MIDI_OUTPUT | MIDI_INPUT;
|
||||
}
|
||||
if (id->driver_data < ARRAY_SIZE(names) && names[id->driver_data])
|
||||
chip->model.shortname = names[id->driver_data];
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,10 @@
|
||||
#define PCM_AC97 5
|
||||
#define PCM_COUNT 6
|
||||
|
||||
#define OXYGEN_MCLKS(f_single, f_double, f_quad) ((MCLK_##f_single << 0) | \
|
||||
(MCLK_##f_double << 2) | \
|
||||
(MCLK_##f_quad << 4))
|
||||
|
||||
#define OXYGEN_IO_SIZE 0x100
|
||||
|
||||
#define OXYGEN_EEPROM_ID 0x434d /* "CM" */
|
||||
@ -35,6 +39,7 @@
|
||||
#define MIDI_OUTPUT 0x0800
|
||||
#define MIDI_INPUT 0x1000
|
||||
#define AC97_CD_INPUT 0x2000
|
||||
#define AC97_FMIC_SWITCH 0x4000
|
||||
|
||||
enum {
|
||||
CONTROL_SPDIF_PCM,
|
||||
@ -65,6 +70,7 @@ struct snd_pcm_hardware;
|
||||
struct snd_pcm_hw_params;
|
||||
struct snd_kcontrol_new;
|
||||
struct snd_rawmidi;
|
||||
struct snd_info_buffer;
|
||||
struct oxygen;
|
||||
|
||||
struct oxygen_model {
|
||||
@ -79,8 +85,6 @@ struct oxygen_model {
|
||||
void (*resume)(struct oxygen *chip);
|
||||
void (*pcm_hardware_filter)(unsigned int channel,
|
||||
struct snd_pcm_hardware *hardware);
|
||||
unsigned int (*get_i2s_mclk)(struct oxygen *chip, unsigned int channel,
|
||||
struct snd_pcm_hw_params *hw_params);
|
||||
void (*set_dac_params)(struct oxygen *chip,
|
||||
struct snd_pcm_hw_params *params);
|
||||
void (*set_adc_params)(struct oxygen *chip,
|
||||
@ -92,15 +96,19 @@ struct oxygen_model {
|
||||
void (*uart_input)(struct oxygen *chip);
|
||||
void (*ac97_switch)(struct oxygen *chip,
|
||||
unsigned int reg, unsigned int mute);
|
||||
void (*dump_registers)(struct oxygen *chip,
|
||||
struct snd_info_buffer *buffer);
|
||||
const unsigned int *dac_tlv;
|
||||
unsigned long private_data;
|
||||
size_t model_data_size;
|
||||
unsigned int device_config;
|
||||
u8 dac_channels;
|
||||
u8 dac_channels_pcm;
|
||||
u8 dac_channels_mixer;
|
||||
u8 dac_volume_min;
|
||||
u8 dac_volume_max;
|
||||
u8 misc_flags;
|
||||
u8 function_flags;
|
||||
u8 dac_mclks;
|
||||
u8 adc_mclks;
|
||||
u16 dac_i2s_format;
|
||||
u16 adc_i2s_format;
|
||||
};
|
||||
@ -121,7 +129,6 @@ struct oxygen {
|
||||
u8 pcm_running;
|
||||
u8 dac_routing;
|
||||
u8 spdif_playback_enable;
|
||||
u8 revision;
|
||||
u8 has_ac97_0;
|
||||
u8 has_ac97_1;
|
||||
u32 spdif_bits;
|
||||
@ -167,8 +174,6 @@ void oxygen_update_spdif_source(struct oxygen *chip);
|
||||
/* oxygen_pcm.c */
|
||||
|
||||
int oxygen_pcm_init(struct oxygen *chip);
|
||||
unsigned int oxygen_default_i2s_mclk(struct oxygen *chip, unsigned int channel,
|
||||
struct snd_pcm_hw_params *hw_params);
|
||||
|
||||
/* oxygen_io.c */
|
||||
|
||||
|
@ -197,11 +197,11 @@ void oxygen_write_spi(struct oxygen *chip, u8 control, unsigned int data)
|
||||
{
|
||||
unsigned int count;
|
||||
|
||||
/* should not need more than 7.68 us (24 * 320 ns) */
|
||||
/* should not need more than 30.72 us (24 * 1.28 us) */
|
||||
count = 10;
|
||||
while ((oxygen_read8(chip, OXYGEN_SPI_CONTROL) & OXYGEN_SPI_BUSY)
|
||||
&& count > 0) {
|
||||
udelay(1);
|
||||
udelay(4);
|
||||
--count;
|
||||
}
|
||||
|
||||
|
@ -202,7 +202,13 @@ static void oxygen_proc_read(struct snd_info_entry *entry,
|
||||
struct oxygen *chip = entry->private_data;
|
||||
int i, j;
|
||||
|
||||
snd_iprintf(buffer, "CMI8788\n\n");
|
||||
switch (oxygen_read8(chip, OXYGEN_REVISION) & OXYGEN_PACKAGE_ID_MASK) {
|
||||
case OXYGEN_PACKAGE_ID_8786: i = '6'; break;
|
||||
case OXYGEN_PACKAGE_ID_8787: i = '7'; break;
|
||||
case OXYGEN_PACKAGE_ID_8788: i = '8'; break;
|
||||
default: i = '?'; break;
|
||||
}
|
||||
snd_iprintf(buffer, "CMI878%c:\n", i);
|
||||
for (i = 0; i < OXYGEN_IO_SIZE; i += 0x10) {
|
||||
snd_iprintf(buffer, "%02x:", i);
|
||||
for (j = 0; j < 0x10; ++j)
|
||||
@ -212,7 +218,7 @@ static void oxygen_proc_read(struct snd_info_entry *entry,
|
||||
if (mutex_lock_interruptible(&chip->mutex) < 0)
|
||||
return;
|
||||
if (chip->has_ac97_0) {
|
||||
snd_iprintf(buffer, "\nAC97\n");
|
||||
snd_iprintf(buffer, "\nAC97:\n");
|
||||
for (i = 0; i < 0x80; i += 0x10) {
|
||||
snd_iprintf(buffer, "%02x:", i);
|
||||
for (j = 0; j < 0x10; j += 2)
|
||||
@ -222,7 +228,7 @@ static void oxygen_proc_read(struct snd_info_entry *entry,
|
||||
}
|
||||
}
|
||||
if (chip->has_ac97_1) {
|
||||
snd_iprintf(buffer, "\nAC97 2\n");
|
||||
snd_iprintf(buffer, "\nAC97 2:\n");
|
||||
for (i = 0; i < 0x80; i += 0x10) {
|
||||
snd_iprintf(buffer, "%02x:", i);
|
||||
for (j = 0; j < 0x10; j += 2)
|
||||
@ -232,13 +238,15 @@ static void oxygen_proc_read(struct snd_info_entry *entry,
|
||||
}
|
||||
}
|
||||
mutex_unlock(&chip->mutex);
|
||||
if (chip->model.dump_registers)
|
||||
chip->model.dump_registers(chip, buffer);
|
||||
}
|
||||
|
||||
static void oxygen_proc_init(struct oxygen *chip)
|
||||
{
|
||||
struct snd_info_entry *entry;
|
||||
|
||||
if (!snd_card_proc_new(chip->card, "cmi8788", &entry))
|
||||
if (!snd_card_proc_new(chip->card, "oxygen", &entry))
|
||||
snd_info_set_text_ops(entry, chip, oxygen_proc_read);
|
||||
}
|
||||
#else
|
||||
@ -262,7 +270,7 @@ oxygen_search_pci_id(struct oxygen *chip, const struct pci_device_id ids[])
|
||||
*/
|
||||
subdevice = oxygen_read_eeprom(chip, 2);
|
||||
/* use default ID if EEPROM is missing */
|
||||
if (subdevice == 0xffff)
|
||||
if (subdevice == 0xffff && oxygen_read_eeprom(chip, 1) == 0xffff)
|
||||
subdevice = 0x8788;
|
||||
/*
|
||||
* We use only the subsystem device ID for searching because it is
|
||||
@ -364,12 +372,7 @@ static void oxygen_init(struct oxygen *chip)
|
||||
(IEC958_AES1_CON_PCM_CODER << OXYGEN_SPDIF_CATEGORY_SHIFT);
|
||||
chip->spdif_pcm_bits = chip->spdif_bits;
|
||||
|
||||
if (oxygen_read8(chip, OXYGEN_REVISION) & OXYGEN_REVISION_2)
|
||||
chip->revision = 2;
|
||||
else
|
||||
chip->revision = 1;
|
||||
|
||||
if (chip->revision == 1)
|
||||
if (!(oxygen_read8(chip, OXYGEN_REVISION) & OXYGEN_REVISION_2))
|
||||
oxygen_set_bits8(chip, OXYGEN_MISC,
|
||||
OXYGEN_MISC_PCI_MEM_W_1_CLOCK);
|
||||
|
||||
@ -406,28 +409,40 @@ static void oxygen_init(struct oxygen *chip)
|
||||
(OXYGEN_FORMAT_16 << OXYGEN_MULTICH_FORMAT_SHIFT));
|
||||
oxygen_write8(chip, OXYGEN_REC_CHANNELS, OXYGEN_REC_CHANNELS_2_2_2);
|
||||
oxygen_write16(chip, OXYGEN_I2S_MULTICH_FORMAT,
|
||||
OXYGEN_RATE_48000 | chip->model.dac_i2s_format |
|
||||
OXYGEN_I2S_MCLK_256 | OXYGEN_I2S_BITS_16 |
|
||||
OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64);
|
||||
OXYGEN_RATE_48000 |
|
||||
chip->model.dac_i2s_format |
|
||||
OXYGEN_I2S_MCLK(chip->model.dac_mclks) |
|
||||
OXYGEN_I2S_BITS_16 |
|
||||
OXYGEN_I2S_MASTER |
|
||||
OXYGEN_I2S_BCLK_64);
|
||||
if (chip->model.device_config & CAPTURE_0_FROM_I2S_1)
|
||||
oxygen_write16(chip, OXYGEN_I2S_A_FORMAT,
|
||||
OXYGEN_RATE_48000 | chip->model.adc_i2s_format |
|
||||
OXYGEN_I2S_MCLK_256 | OXYGEN_I2S_BITS_16 |
|
||||
OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64);
|
||||
OXYGEN_RATE_48000 |
|
||||
chip->model.adc_i2s_format |
|
||||
OXYGEN_I2S_MCLK(chip->model.adc_mclks) |
|
||||
OXYGEN_I2S_BITS_16 |
|
||||
OXYGEN_I2S_MASTER |
|
||||
OXYGEN_I2S_BCLK_64);
|
||||
else
|
||||
oxygen_write16(chip, OXYGEN_I2S_A_FORMAT,
|
||||
OXYGEN_I2S_MASTER | OXYGEN_I2S_MUTE_MCLK);
|
||||
OXYGEN_I2S_MASTER |
|
||||
OXYGEN_I2S_MUTE_MCLK);
|
||||
if (chip->model.device_config & (CAPTURE_0_FROM_I2S_2 |
|
||||
CAPTURE_2_FROM_I2S_2))
|
||||
oxygen_write16(chip, OXYGEN_I2S_B_FORMAT,
|
||||
OXYGEN_RATE_48000 | chip->model.adc_i2s_format |
|
||||
OXYGEN_I2S_MCLK_256 | OXYGEN_I2S_BITS_16 |
|
||||
OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64);
|
||||
OXYGEN_RATE_48000 |
|
||||
chip->model.adc_i2s_format |
|
||||
OXYGEN_I2S_MCLK(chip->model.adc_mclks) |
|
||||
OXYGEN_I2S_BITS_16 |
|
||||
OXYGEN_I2S_MASTER |
|
||||
OXYGEN_I2S_BCLK_64);
|
||||
else
|
||||
oxygen_write16(chip, OXYGEN_I2S_B_FORMAT,
|
||||
OXYGEN_I2S_MASTER | OXYGEN_I2S_MUTE_MCLK);
|
||||
OXYGEN_I2S_MASTER |
|
||||
OXYGEN_I2S_MUTE_MCLK);
|
||||
oxygen_write16(chip, OXYGEN_I2S_C_FORMAT,
|
||||
OXYGEN_I2S_MASTER | OXYGEN_I2S_MUTE_MCLK);
|
||||
OXYGEN_I2S_MASTER |
|
||||
OXYGEN_I2S_MUTE_MCLK);
|
||||
oxygen_clear_bits32(chip, OXYGEN_SPDIF_CONTROL,
|
||||
OXYGEN_SPDIF_OUT_ENABLE |
|
||||
OXYGEN_SPDIF_LOOPBACK);
|
||||
@ -557,7 +572,8 @@ static void oxygen_card_free(struct snd_card *card)
|
||||
oxygen_shutdown(chip);
|
||||
if (chip->irq >= 0)
|
||||
free_irq(chip->irq, chip);
|
||||
flush_scheduled_work();
|
||||
flush_work_sync(&chip->spdif_input_bits_work);
|
||||
flush_work_sync(&chip->gpio_work);
|
||||
chip->model.cleanup(chip);
|
||||
kfree(chip->model_data);
|
||||
mutex_destroy(&chip->mutex);
|
||||
@ -648,8 +664,8 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
|
||||
|
||||
strcpy(card->driver, chip->model.chip);
|
||||
strcpy(card->shortname, chip->model.shortname);
|
||||
sprintf(card->longname, "%s (rev %u) at %#lx, irq %i",
|
||||
chip->model.longname, chip->revision, chip->addr, chip->irq);
|
||||
sprintf(card->longname, "%s at %#lx, irq %i",
|
||||
chip->model.longname, chip->addr, chip->irq);
|
||||
strcpy(card->mixername, chip->model.chip);
|
||||
snd_component_add(card, chip->model.chip);
|
||||
|
||||
@ -733,7 +749,8 @@ int oxygen_pci_suspend(struct pci_dev *pci, pm_message_t state)
|
||||
spin_unlock_irq(&chip->reg_lock);
|
||||
|
||||
synchronize_irq(chip->irq);
|
||||
flush_scheduled_work();
|
||||
flush_work_sync(&chip->spdif_input_bits_work);
|
||||
flush_work_sync(&chip->gpio_work);
|
||||
chip->interrupt_mask = saved_interrupt_mask;
|
||||
|
||||
pci_disable_device(pci);
|
||||
|
@ -31,7 +31,7 @@ static int dac_volume_info(struct snd_kcontrol *ctl,
|
||||
struct oxygen *chip = ctl->private_data;
|
||||
|
||||
info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
|
||||
info->count = chip->model.dac_channels;
|
||||
info->count = chip->model.dac_channels_mixer;
|
||||
info->value.integer.min = chip->model.dac_volume_min;
|
||||
info->value.integer.max = chip->model.dac_volume_max;
|
||||
return 0;
|
||||
@ -44,7 +44,7 @@ static int dac_volume_get(struct snd_kcontrol *ctl,
|
||||
unsigned int i;
|
||||
|
||||
mutex_lock(&chip->mutex);
|
||||
for (i = 0; i < chip->model.dac_channels; ++i)
|
||||
for (i = 0; i < chip->model.dac_channels_mixer; ++i)
|
||||
value->value.integer.value[i] = chip->dac_volume[i];
|
||||
mutex_unlock(&chip->mutex);
|
||||
return 0;
|
||||
@ -59,7 +59,7 @@ static int dac_volume_put(struct snd_kcontrol *ctl,
|
||||
|
||||
changed = 0;
|
||||
mutex_lock(&chip->mutex);
|
||||
for (i = 0; i < chip->model.dac_channels; ++i)
|
||||
for (i = 0; i < chip->model.dac_channels_mixer; ++i)
|
||||
if (value->value.integer.value[i] != chip->dac_volume[i]) {
|
||||
chip->dac_volume[i] = value->value.integer.value[i];
|
||||
changed = 1;
|
||||
@ -97,6 +97,16 @@ static int dac_mute_put(struct snd_kcontrol *ctl,
|
||||
return changed;
|
||||
}
|
||||
|
||||
static unsigned int upmix_item_count(struct oxygen *chip)
|
||||
{
|
||||
if (chip->model.dac_channels_pcm < 8)
|
||||
return 2;
|
||||
else if (chip->model.update_center_lfe_mix)
|
||||
return 5;
|
||||
else
|
||||
return 3;
|
||||
}
|
||||
|
||||
static int upmix_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info)
|
||||
{
|
||||
static const char *const names[5] = {
|
||||
@ -107,15 +117,9 @@ static int upmix_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info)
|
||||
"Front+Surround+Center/LFE+Back",
|
||||
};
|
||||
struct oxygen *chip = ctl->private_data;
|
||||
unsigned int count = chip->model.update_center_lfe_mix ? 5 : 3;
|
||||
unsigned int count = upmix_item_count(chip);
|
||||
|
||||
info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
|
||||
info->count = 1;
|
||||
info->value.enumerated.items = count;
|
||||
if (info->value.enumerated.item >= count)
|
||||
info->value.enumerated.item = count - 1;
|
||||
strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
|
||||
return 0;
|
||||
return snd_ctl_enum_info(info, 1, count, names);
|
||||
}
|
||||
|
||||
static int upmix_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
|
||||
@ -188,7 +192,7 @@ void oxygen_update_dac_routing(struct oxygen *chip)
|
||||
static int upmix_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
|
||||
{
|
||||
struct oxygen *chip = ctl->private_data;
|
||||
unsigned int count = chip->model.update_center_lfe_mix ? 5 : 3;
|
||||
unsigned int count = upmix_item_count(chip);
|
||||
int changed;
|
||||
|
||||
if (value->value.enumerated.item[0] >= count)
|
||||
@ -430,30 +434,31 @@ static int spdif_input_default_get(struct snd_kcontrol *ctl,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int spdif_loopback_get(struct snd_kcontrol *ctl,
|
||||
struct snd_ctl_elem_value *value)
|
||||
static int spdif_bit_switch_get(struct snd_kcontrol *ctl,
|
||||
struct snd_ctl_elem_value *value)
|
||||
{
|
||||
struct oxygen *chip = ctl->private_data;
|
||||
u32 bit = ctl->private_value;
|
||||
|
||||
value->value.integer.value[0] =
|
||||
!!(oxygen_read32(chip, OXYGEN_SPDIF_CONTROL)
|
||||
& OXYGEN_SPDIF_LOOPBACK);
|
||||
!!(oxygen_read32(chip, OXYGEN_SPDIF_CONTROL) & bit);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int spdif_loopback_put(struct snd_kcontrol *ctl,
|
||||
struct snd_ctl_elem_value *value)
|
||||
static int spdif_bit_switch_put(struct snd_kcontrol *ctl,
|
||||
struct snd_ctl_elem_value *value)
|
||||
{
|
||||
struct oxygen *chip = ctl->private_data;
|
||||
u32 bit = ctl->private_value;
|
||||
u32 oldreg, newreg;
|
||||
int changed;
|
||||
|
||||
spin_lock_irq(&chip->reg_lock);
|
||||
oldreg = oxygen_read32(chip, OXYGEN_SPDIF_CONTROL);
|
||||
if (value->value.integer.value[0])
|
||||
newreg = oldreg | OXYGEN_SPDIF_LOOPBACK;
|
||||
newreg = oldreg | bit;
|
||||
else
|
||||
newreg = oldreg & ~OXYGEN_SPDIF_LOOPBACK;
|
||||
newreg = oldreg & ~bit;
|
||||
changed = newreg != oldreg;
|
||||
if (changed)
|
||||
oxygen_write32(chip, OXYGEN_SPDIF_CONTROL, newreg);
|
||||
@ -644,6 +649,46 @@ static int ac97_volume_put(struct snd_kcontrol *ctl,
|
||||
return change;
|
||||
}
|
||||
|
||||
static int mic_fmic_source_info(struct snd_kcontrol *ctl,
|
||||
struct snd_ctl_elem_info *info)
|
||||
{
|
||||
static const char *const names[] = { "Mic Jack", "Front Panel" };
|
||||
|
||||
return snd_ctl_enum_info(info, 1, 2, names);
|
||||
}
|
||||
|
||||
static int mic_fmic_source_get(struct snd_kcontrol *ctl,
|
||||
struct snd_ctl_elem_value *value)
|
||||
{
|
||||
struct oxygen *chip = ctl->private_data;
|
||||
|
||||
mutex_lock(&chip->mutex);
|
||||
value->value.enumerated.item[0] =
|
||||
!!(oxygen_read_ac97(chip, 0, CM9780_JACK) & CM9780_FMIC2MIC);
|
||||
mutex_unlock(&chip->mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mic_fmic_source_put(struct snd_kcontrol *ctl,
|
||||
struct snd_ctl_elem_value *value)
|
||||
{
|
||||
struct oxygen *chip = ctl->private_data;
|
||||
u16 oldreg, newreg;
|
||||
int change;
|
||||
|
||||
mutex_lock(&chip->mutex);
|
||||
oldreg = oxygen_read_ac97(chip, 0, CM9780_JACK);
|
||||
if (value->value.enumerated.item[0])
|
||||
newreg = oldreg | CM9780_FMIC2MIC;
|
||||
else
|
||||
newreg = oldreg & ~CM9780_FMIC2MIC;
|
||||
change = newreg != oldreg;
|
||||
if (change)
|
||||
oxygen_write_ac97(chip, 0, CM9780_JACK, newreg);
|
||||
mutex_unlock(&chip->mutex);
|
||||
return change;
|
||||
}
|
||||
|
||||
static int ac97_fp_rec_volume_info(struct snd_kcontrol *ctl,
|
||||
struct snd_ctl_elem_info *info)
|
||||
{
|
||||
@ -791,8 +836,17 @@ static const struct snd_kcontrol_new spdif_input_controls[] = {
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = SNDRV_CTL_NAME_IEC958("Loopback ", NONE, SWITCH),
|
||||
.info = snd_ctl_boolean_mono_info,
|
||||
.get = spdif_loopback_get,
|
||||
.put = spdif_loopback_put,
|
||||
.get = spdif_bit_switch_get,
|
||||
.put = spdif_bit_switch_put,
|
||||
.private_value = OXYGEN_SPDIF_LOOPBACK,
|
||||
},
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = SNDRV_CTL_NAME_IEC958("Validity Check ",CAPTURE,SWITCH),
|
||||
.info = snd_ctl_boolean_mono_info,
|
||||
.get = spdif_bit_switch_get,
|
||||
.put = spdif_bit_switch_put,
|
||||
.private_value = OXYGEN_SPDIF_SPDVALID,
|
||||
},
|
||||
};
|
||||
|
||||
@ -908,6 +962,13 @@ static const struct snd_kcontrol_new ac97_controls[] = {
|
||||
AC97_VOLUME("Mic Capture Volume", 0, AC97_MIC, 0),
|
||||
AC97_SWITCH("Mic Capture Switch", 0, AC97_MIC, 15, 1),
|
||||
AC97_SWITCH("Mic Boost (+20dB)", 0, AC97_MIC, 6, 0),
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Mic Source Capture Enum",
|
||||
.info = mic_fmic_source_info,
|
||||
.get = mic_fmic_source_get,
|
||||
.put = mic_fmic_source_put,
|
||||
},
|
||||
AC97_SWITCH("Line Capture Switch", 0, AC97_LINE, 15, 1),
|
||||
AC97_VOLUME("CD Capture Volume", 0, AC97_CD, 1),
|
||||
AC97_SWITCH("CD Capture Switch", 0, AC97_CD, 15, 1),
|
||||
@ -970,7 +1031,10 @@ static int add_controls(struct oxygen *chip,
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(template.name, "Stereo Upmixing") &&
|
||||
chip->model.dac_channels == 2)
|
||||
chip->model.dac_channels_pcm == 2)
|
||||
continue;
|
||||
if (!strcmp(template.name, "Mic Source Capture Enum") &&
|
||||
!(chip->model.device_config & AC97_FMIC_SWITCH))
|
||||
continue;
|
||||
if (!strncmp(template.name, "CD Capture ", 11) &&
|
||||
!(chip->model.device_config & AC97_CD_INPUT))
|
||||
|
@ -39,7 +39,8 @@ static const struct snd_pcm_hardware oxygen_stereo_hardware = {
|
||||
SNDRV_PCM_INFO_MMAP_VALID |
|
||||
SNDRV_PCM_INFO_INTERLEAVED |
|
||||
SNDRV_PCM_INFO_PAUSE |
|
||||
SNDRV_PCM_INFO_SYNC_START,
|
||||
SNDRV_PCM_INFO_SYNC_START |
|
||||
SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S32_LE,
|
||||
.rates = SNDRV_PCM_RATE_32000 |
|
||||
@ -65,7 +66,8 @@ static const struct snd_pcm_hardware oxygen_multichannel_hardware = {
|
||||
SNDRV_PCM_INFO_MMAP_VALID |
|
||||
SNDRV_PCM_INFO_INTERLEAVED |
|
||||
SNDRV_PCM_INFO_PAUSE |
|
||||
SNDRV_PCM_INFO_SYNC_START,
|
||||
SNDRV_PCM_INFO_SYNC_START |
|
||||
SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S32_LE,
|
||||
.rates = SNDRV_PCM_RATE_32000 |
|
||||
@ -91,7 +93,8 @@ static const struct snd_pcm_hardware oxygen_ac97_hardware = {
|
||||
SNDRV_PCM_INFO_MMAP_VALID |
|
||||
SNDRV_PCM_INFO_INTERLEAVED |
|
||||
SNDRV_PCM_INFO_PAUSE |
|
||||
SNDRV_PCM_INFO_SYNC_START,
|
||||
SNDRV_PCM_INFO_SYNC_START |
|
||||
SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
.rate_min = 48000,
|
||||
@ -140,7 +143,7 @@ static int oxygen_open(struct snd_pcm_substream *substream,
|
||||
runtime->hw.rate_min = 44100;
|
||||
break;
|
||||
case PCM_MULTICH:
|
||||
runtime->hw.channels_max = chip->model.dac_channels;
|
||||
runtime->hw.channels_max = chip->model.dac_channels_pcm;
|
||||
break;
|
||||
}
|
||||
if (chip->model.pcm_hardware_filter)
|
||||
@ -271,17 +274,6 @@ static unsigned int oxygen_rate(struct snd_pcm_hw_params *hw_params)
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int oxygen_default_i2s_mclk(struct oxygen *chip,
|
||||
unsigned int channel,
|
||||
struct snd_pcm_hw_params *hw_params)
|
||||
{
|
||||
if (params_rate(hw_params) <= 96000)
|
||||
return OXYGEN_I2S_MCLK_256;
|
||||
else
|
||||
return OXYGEN_I2S_MCLK_128;
|
||||
}
|
||||
EXPORT_SYMBOL(oxygen_default_i2s_mclk);
|
||||
|
||||
static unsigned int oxygen_i2s_bits(struct snd_pcm_hw_params *hw_params)
|
||||
{
|
||||
if (params_format(hw_params) == SNDRV_PCM_FORMAT_S32_LE)
|
||||
@ -341,6 +333,26 @@ static int oxygen_hw_params(struct snd_pcm_substream *substream,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u16 get_mclk(struct oxygen *chip, unsigned int channel,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
unsigned int mclks, shift;
|
||||
|
||||
if (channel == PCM_MULTICH)
|
||||
mclks = chip->model.dac_mclks;
|
||||
else
|
||||
mclks = chip->model.adc_mclks;
|
||||
|
||||
if (params_rate(params) <= 48000)
|
||||
shift = 0;
|
||||
else if (params_rate(params) <= 96000)
|
||||
shift = 2;
|
||||
else
|
||||
shift = 4;
|
||||
|
||||
return OXYGEN_I2S_MCLK(mclks >> shift);
|
||||
}
|
||||
|
||||
static int oxygen_rec_a_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *hw_params)
|
||||
{
|
||||
@ -357,8 +369,8 @@ static int oxygen_rec_a_hw_params(struct snd_pcm_substream *substream,
|
||||
OXYGEN_REC_FORMAT_A_MASK);
|
||||
oxygen_write16_masked(chip, OXYGEN_I2S_A_FORMAT,
|
||||
oxygen_rate(hw_params) |
|
||||
chip->model.get_i2s_mclk(chip, PCM_A, hw_params) |
|
||||
chip->model.adc_i2s_format |
|
||||
get_mclk(chip, PCM_A, hw_params) |
|
||||
oxygen_i2s_bits(hw_params),
|
||||
OXYGEN_I2S_RATE_MASK |
|
||||
OXYGEN_I2S_FORMAT_MASK |
|
||||
@ -393,9 +405,8 @@ static int oxygen_rec_b_hw_params(struct snd_pcm_substream *substream,
|
||||
if (!is_ac97)
|
||||
oxygen_write16_masked(chip, OXYGEN_I2S_B_FORMAT,
|
||||
oxygen_rate(hw_params) |
|
||||
chip->model.get_i2s_mclk(chip, PCM_B,
|
||||
hw_params) |
|
||||
chip->model.adc_i2s_format |
|
||||
get_mclk(chip, PCM_B, hw_params) |
|
||||
oxygen_i2s_bits(hw_params),
|
||||
OXYGEN_I2S_RATE_MASK |
|
||||
OXYGEN_I2S_FORMAT_MASK |
|
||||
@ -476,8 +487,7 @@ static int oxygen_multich_hw_params(struct snd_pcm_substream *substream,
|
||||
oxygen_write16_masked(chip, OXYGEN_I2S_MULTICH_FORMAT,
|
||||
oxygen_rate(hw_params) |
|
||||
chip->model.dac_i2s_format |
|
||||
chip->model.get_i2s_mclk(chip, PCM_MULTICH,
|
||||
hw_params) |
|
||||
get_mclk(chip, PCM_MULTICH, hw_params) |
|
||||
oxygen_i2s_bits(hw_params),
|
||||
OXYGEN_I2S_RATE_MASK |
|
||||
OXYGEN_I2S_FORMAT_MASK |
|
||||
@ -530,7 +540,10 @@ static int oxygen_prepare(struct snd_pcm_substream *substream)
|
||||
oxygen_set_bits8(chip, OXYGEN_DMA_FLUSH, channel_mask);
|
||||
oxygen_clear_bits8(chip, OXYGEN_DMA_FLUSH, channel_mask);
|
||||
|
||||
chip->interrupt_mask |= channel_mask;
|
||||
if (substream->runtime->no_period_wakeup)
|
||||
chip->interrupt_mask &= ~channel_mask;
|
||||
else
|
||||
chip->interrupt_mask |= channel_mask;
|
||||
oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, chip->interrupt_mask);
|
||||
spin_unlock_irq(&chip->reg_lock);
|
||||
return 0;
|
||||
|
@ -139,9 +139,11 @@
|
||||
#define OXYGEN_I2S_FORMAT_I2S 0x0000
|
||||
#define OXYGEN_I2S_FORMAT_LJUST 0x0008
|
||||
#define OXYGEN_I2S_MCLK_MASK 0x0030 /* MCLK/LRCK */
|
||||
#define OXYGEN_I2S_MCLK_128 0x0000
|
||||
#define OXYGEN_I2S_MCLK_256 0x0010
|
||||
#define OXYGEN_I2S_MCLK_512 0x0020
|
||||
#define OXYGEN_I2S_MCLK_SHIFT 4
|
||||
#define MCLK_128 0
|
||||
#define MCLK_256 1
|
||||
#define MCLK_512 2
|
||||
#define OXYGEN_I2S_MCLK(f) (((f) & 3) << OXYGEN_I2S_MCLK_SHIFT)
|
||||
#define OXYGEN_I2S_BITS_MASK 0x00c0
|
||||
#define OXYGEN_I2S_BITS_16 0x0000
|
||||
#define OXYGEN_I2S_BITS_20 0x0040
|
||||
@ -238,11 +240,11 @@
|
||||
#define OXYGEN_SPI_DATA_LENGTH_MASK 0x02
|
||||
#define OXYGEN_SPI_DATA_LENGTH_2 0x00
|
||||
#define OXYGEN_SPI_DATA_LENGTH_3 0x02
|
||||
#define OXYGEN_SPI_CLOCK_MASK 0xc0
|
||||
#define OXYGEN_SPI_CLOCK_MASK 0x0c
|
||||
#define OXYGEN_SPI_CLOCK_160 0x00 /* ns */
|
||||
#define OXYGEN_SPI_CLOCK_320 0x40
|
||||
#define OXYGEN_SPI_CLOCK_640 0x80
|
||||
#define OXYGEN_SPI_CLOCK_1280 0xc0
|
||||
#define OXYGEN_SPI_CLOCK_320 0x04
|
||||
#define OXYGEN_SPI_CLOCK_640 0x08
|
||||
#define OXYGEN_SPI_CLOCK_1280 0x0c
|
||||
#define OXYGEN_SPI_CODEC_MASK 0x70 /* 0..5 */
|
||||
#define OXYGEN_SPI_CODEC_SHIFT 4
|
||||
#define OXYGEN_SPI_CEN_MASK 0x80
|
||||
|
@ -24,6 +24,8 @@ void xonar_init_ext_power(struct oxygen *chip);
|
||||
void xonar_init_cs53x1(struct oxygen *chip);
|
||||
void xonar_set_cs53x1_params(struct oxygen *chip,
|
||||
struct snd_pcm_hw_params *params);
|
||||
|
||||
#define XONAR_GPIO_BIT_INVERT (1 << 16)
|
||||
int xonar_gpio_bit_switch_get(struct snd_kcontrol *ctl,
|
||||
struct snd_ctl_elem_value *value);
|
||||
int xonar_gpio_bit_switch_put(struct snd_kcontrol *ctl,
|
||||
|
@ -22,29 +22,28 @@
|
||||
*
|
||||
* CMI8788:
|
||||
*
|
||||
* I²C <-> CS4398 (front)
|
||||
* <-> CS4362A (surround, center/LFE, back)
|
||||
* I²C <-> CS4398 (addr 1001111) (front)
|
||||
* <-> CS4362A (addr 0011000) (surround, center/LFE, back)
|
||||
*
|
||||
* GPI 0 <- external power present (DX only)
|
||||
* GPI 0 <- external power present (DX only)
|
||||
*
|
||||
* GPIO 0 -> enable output to speakers
|
||||
* GPIO 1 -> enable front panel I/O
|
||||
* GPIO 2 -> M0 of CS5361
|
||||
* GPIO 3 -> M1 of CS5361
|
||||
* GPIO 8 -> route input jack to line-in (0) or mic-in (1)
|
||||
*
|
||||
* CS4398:
|
||||
*
|
||||
* AD0 <- 1
|
||||
* AD1 <- 1
|
||||
*
|
||||
* CS4362A:
|
||||
*
|
||||
* AD0 <- 0
|
||||
* GPIO 0 -> enable output to speakers
|
||||
* GPIO 1 -> route output to front panel
|
||||
* GPIO 2 -> M0 of CS5361
|
||||
* GPIO 3 -> M1 of CS5361
|
||||
* GPIO 6 -> ?
|
||||
* GPIO 7 -> ?
|
||||
* GPIO 8 -> route input jack to line-in (0) or mic-in (1)
|
||||
*
|
||||
* CM9780:
|
||||
*
|
||||
* GPO 0 -> route line-in (0) or AC97 output (1) to CS5361 input
|
||||
* LINE_OUT -> input of ADC
|
||||
*
|
||||
* AUX_IN <- aux
|
||||
* MIC_IN <- mic
|
||||
* FMIC_IN <- front mic
|
||||
*
|
||||
* GPO 0 -> route line-in (0) or AC97 output (1) to CS5361 input
|
||||
*/
|
||||
|
||||
#include <linux/pci.h>
|
||||
@ -63,6 +62,7 @@
|
||||
#define GPI_EXT_POWER 0x01
|
||||
#define GPIO_D1_OUTPUT_ENABLE 0x0001
|
||||
#define GPIO_D1_FRONT_PANEL 0x0002
|
||||
#define GPIO_D1_MAGIC 0x00c0
|
||||
#define GPIO_D1_INPUT_ROUTE 0x0100
|
||||
|
||||
#define I2C_DEVICE_CS4398 0x9e /* 10011, AD1=1, AD0=1, /W=0 */
|
||||
@ -169,12 +169,12 @@ static void xonar_d1_init(struct oxygen *chip)
|
||||
cs43xx_registers_init(chip);
|
||||
|
||||
oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
|
||||
GPIO_D1_FRONT_PANEL | GPIO_D1_INPUT_ROUTE);
|
||||
GPIO_D1_FRONT_PANEL |
|
||||
GPIO_D1_MAGIC |
|
||||
GPIO_D1_INPUT_ROUTE);
|
||||
oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA,
|
||||
GPIO_D1_FRONT_PANEL | GPIO_D1_INPUT_ROUTE);
|
||||
|
||||
oxygen_ac97_set_bits(chip, 0, CM9780_JACK, CM9780_FMIC2MIC);
|
||||
|
||||
xonar_init_cs53x1(chip);
|
||||
xonar_enable_output(chip);
|
||||
|
||||
@ -284,7 +284,7 @@ static void update_cs43xx_center_lfe_mix(struct oxygen *chip, bool mixed)
|
||||
|
||||
static const struct snd_kcontrol_new front_panel_switch = {
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Front Panel Switch",
|
||||
.name = "Front Panel Playback Switch",
|
||||
.info = snd_ctl_boolean_mono_info,
|
||||
.get = xonar_gpio_bit_switch_get,
|
||||
.put = xonar_gpio_bit_switch_put,
|
||||
@ -298,13 +298,7 @@ static int rolloff_info(struct snd_kcontrol *ctl,
|
||||
"Fast Roll-off", "Slow Roll-off"
|
||||
};
|
||||
|
||||
info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
|
||||
info->count = 1;
|
||||
info->value.enumerated.items = 2;
|
||||
if (info->value.enumerated.item >= 2)
|
||||
info->value.enumerated.item = 1;
|
||||
strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
|
||||
return 0;
|
||||
return snd_ctl_enum_info(info, 1, 2, names);
|
||||
}
|
||||
|
||||
static int rolloff_get(struct snd_kcontrol *ctl,
|
||||
@ -380,6 +374,30 @@ static int xonar_d1_mixer_init(struct oxygen *chip)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dump_cs4362a_registers(struct xonar_cs43xx *data,
|
||||
struct snd_info_buffer *buffer)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
snd_iprintf(buffer, "\nCS4362A:");
|
||||
for (i = 1; i <= 14; ++i)
|
||||
snd_iprintf(buffer, " %02x", data->cs4362a_regs[i]);
|
||||
snd_iprintf(buffer, "\n");
|
||||
}
|
||||
|
||||
static void dump_d1_registers(struct oxygen *chip,
|
||||
struct snd_info_buffer *buffer)
|
||||
{
|
||||
struct xonar_cs43xx *data = chip->model_data;
|
||||
unsigned int i;
|
||||
|
||||
snd_iprintf(buffer, "\nCS4398: 7?");
|
||||
for (i = 2; i <= 8; ++i)
|
||||
snd_iprintf(buffer, " %02x", data->cs4398_regs[i]);
|
||||
snd_iprintf(buffer, "\n");
|
||||
dump_cs4362a_registers(data, buffer);
|
||||
}
|
||||
|
||||
static const struct oxygen_model model_xonar_d1 = {
|
||||
.longname = "Asus Virtuoso 100",
|
||||
.chip = "AV200",
|
||||
@ -388,22 +406,26 @@ static const struct oxygen_model model_xonar_d1 = {
|
||||
.cleanup = xonar_d1_cleanup,
|
||||
.suspend = xonar_d1_suspend,
|
||||
.resume = xonar_d1_resume,
|
||||
.get_i2s_mclk = oxygen_default_i2s_mclk,
|
||||
.set_dac_params = set_cs43xx_params,
|
||||
.set_adc_params = xonar_set_cs53x1_params,
|
||||
.update_dac_volume = update_cs43xx_volume,
|
||||
.update_dac_mute = update_cs43xx_mute,
|
||||
.update_center_lfe_mix = update_cs43xx_center_lfe_mix,
|
||||
.ac97_switch = xonar_d1_line_mic_ac97_switch,
|
||||
.dump_registers = dump_d1_registers,
|
||||
.dac_tlv = cs4362a_db_scale,
|
||||
.model_data_size = sizeof(struct xonar_cs43xx),
|
||||
.device_config = PLAYBACK_0_TO_I2S |
|
||||
PLAYBACK_1_TO_SPDIF |
|
||||
CAPTURE_0_FROM_I2S_2,
|
||||
.dac_channels = 8,
|
||||
CAPTURE_0_FROM_I2S_2 |
|
||||
AC97_FMIC_SWITCH,
|
||||
.dac_channels_pcm = 8,
|
||||
.dac_channels_mixer = 8,
|
||||
.dac_volume_min = 127 - 60,
|
||||
.dac_volume_max = 127,
|
||||
.function_flags = OXYGEN_FUNCTION_2WIRE,
|
||||
.dac_mclks = OXYGEN_MCLKS(256, 128, 128),
|
||||
.adc_mclks = OXYGEN_MCLKS(256, 128, 128),
|
||||
.dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
|
||||
.adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
|
||||
};
|
||||
|
572
sound/pci/oxygen/xonar_dg.c
Normal file
572
sound/pci/oxygen/xonar_dg.c
Normal file
@ -0,0 +1,572 @@
|
||||
/*
|
||||
* card driver for the Xonar DG
|
||||
*
|
||||
* Copyright (c) Clemens Ladisch <clemens@ladisch.de>
|
||||
*
|
||||
*
|
||||
* This driver is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License, version 2.
|
||||
*
|
||||
* 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 driver; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Xonar DG
|
||||
* --------
|
||||
*
|
||||
* CMI8788:
|
||||
*
|
||||
* SPI 0 -> CS4245
|
||||
*
|
||||
* GPIO 3 <- ?
|
||||
* GPIO 4 <- headphone detect
|
||||
* GPIO 5 -> route input jack to line-in (0) or mic-in (1)
|
||||
* GPIO 6 -> route input jack to line-in (0) or mic-in (1)
|
||||
* GPIO 7 -> enable rear headphone amp
|
||||
* GPIO 8 -> enable output to speakers
|
||||
*
|
||||
* CS4245:
|
||||
*
|
||||
* input 1 <- aux
|
||||
* input 2 <- front mic
|
||||
* input 4 <- line/mic
|
||||
* aux out -> front panel headphones
|
||||
*/
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include <linux/delay.h>
|
||||
#include <sound/control.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/info.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/tlv.h>
|
||||
#include "oxygen.h"
|
||||
#include "xonar_dg.h"
|
||||
#include "cs4245.h"
|
||||
|
||||
#define GPIO_MAGIC 0x0008
|
||||
#define GPIO_HP_DETECT 0x0010
|
||||
#define GPIO_INPUT_ROUTE 0x0060
|
||||
#define GPIO_HP_REAR 0x0080
|
||||
#define GPIO_OUTPUT_ENABLE 0x0100
|
||||
|
||||
struct dg {
|
||||
unsigned int output_sel;
|
||||
s8 input_vol[4][2];
|
||||
unsigned int input_sel;
|
||||
u8 hp_vol_att;
|
||||
u8 cs4245_regs[0x11];
|
||||
};
|
||||
|
||||
static void cs4245_write(struct oxygen *chip, unsigned int reg, u8 value)
|
||||
{
|
||||
struct dg *data = chip->model_data;
|
||||
|
||||
oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
|
||||
OXYGEN_SPI_DATA_LENGTH_3 |
|
||||
OXYGEN_SPI_CLOCK_1280 |
|
||||
(0 << OXYGEN_SPI_CODEC_SHIFT) |
|
||||
OXYGEN_SPI_CEN_LATCH_CLOCK_HI,
|
||||
CS4245_SPI_ADDRESS |
|
||||
CS4245_SPI_WRITE |
|
||||
(value << 8) | reg);
|
||||
data->cs4245_regs[reg] = value;
|
||||
}
|
||||
|
||||
static void cs4245_write_cached(struct oxygen *chip, unsigned int reg, u8 value)
|
||||
{
|
||||
struct dg *data = chip->model_data;
|
||||
|
||||
if (value != data->cs4245_regs[reg])
|
||||
cs4245_write(chip, reg, value);
|
||||
}
|
||||
|
||||
static void cs4245_registers_init(struct oxygen *chip)
|
||||
{
|
||||
struct dg *data = chip->model_data;
|
||||
|
||||
cs4245_write(chip, CS4245_POWER_CTRL, CS4245_PDN);
|
||||
cs4245_write(chip, CS4245_DAC_CTRL_1,
|
||||
data->cs4245_regs[CS4245_DAC_CTRL_1]);
|
||||
cs4245_write(chip, CS4245_ADC_CTRL,
|
||||
data->cs4245_regs[CS4245_ADC_CTRL]);
|
||||
cs4245_write(chip, CS4245_SIGNAL_SEL,
|
||||
data->cs4245_regs[CS4245_SIGNAL_SEL]);
|
||||
cs4245_write(chip, CS4245_PGA_B_CTRL,
|
||||
data->cs4245_regs[CS4245_PGA_B_CTRL]);
|
||||
cs4245_write(chip, CS4245_PGA_A_CTRL,
|
||||
data->cs4245_regs[CS4245_PGA_A_CTRL]);
|
||||
cs4245_write(chip, CS4245_ANALOG_IN,
|
||||
data->cs4245_regs[CS4245_ANALOG_IN]);
|
||||
cs4245_write(chip, CS4245_DAC_A_CTRL,
|
||||
data->cs4245_regs[CS4245_DAC_A_CTRL]);
|
||||
cs4245_write(chip, CS4245_DAC_B_CTRL,
|
||||
data->cs4245_regs[CS4245_DAC_B_CTRL]);
|
||||
cs4245_write(chip, CS4245_DAC_CTRL_2,
|
||||
CS4245_DAC_SOFT | CS4245_DAC_ZERO | CS4245_INVERT_DAC);
|
||||
cs4245_write(chip, CS4245_INT_MASK, 0);
|
||||
cs4245_write(chip, CS4245_POWER_CTRL, 0);
|
||||
}
|
||||
|
||||
static void cs4245_init(struct oxygen *chip)
|
||||
{
|
||||
struct dg *data = chip->model_data;
|
||||
|
||||
data->cs4245_regs[CS4245_DAC_CTRL_1] =
|
||||
CS4245_DAC_FM_SINGLE | CS4245_DAC_DIF_LJUST;
|
||||
data->cs4245_regs[CS4245_ADC_CTRL] =
|
||||
CS4245_ADC_FM_SINGLE | CS4245_ADC_DIF_LJUST;
|
||||
data->cs4245_regs[CS4245_SIGNAL_SEL] =
|
||||
CS4245_A_OUT_SEL_HIZ | CS4245_ASYNCH;
|
||||
data->cs4245_regs[CS4245_PGA_B_CTRL] = 0;
|
||||
data->cs4245_regs[CS4245_PGA_A_CTRL] = 0;
|
||||
data->cs4245_regs[CS4245_ANALOG_IN] =
|
||||
CS4245_PGA_SOFT | CS4245_PGA_ZERO | CS4245_SEL_INPUT_4;
|
||||
data->cs4245_regs[CS4245_DAC_A_CTRL] = 0;
|
||||
data->cs4245_regs[CS4245_DAC_B_CTRL] = 0;
|
||||
cs4245_registers_init(chip);
|
||||
snd_component_add(chip->card, "CS4245");
|
||||
}
|
||||
|
||||
static void dg_output_enable(struct oxygen *chip)
|
||||
{
|
||||
msleep(2500);
|
||||
oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE);
|
||||
}
|
||||
|
||||
static void dg_init(struct oxygen *chip)
|
||||
{
|
||||
struct dg *data = chip->model_data;
|
||||
|
||||
data->output_sel = 0;
|
||||
data->input_sel = 3;
|
||||
data->hp_vol_att = 2 * 16;
|
||||
|
||||
cs4245_init(chip);
|
||||
|
||||
oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL,
|
||||
GPIO_MAGIC | GPIO_HP_DETECT);
|
||||
oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
|
||||
GPIO_INPUT_ROUTE | GPIO_HP_REAR | GPIO_OUTPUT_ENABLE);
|
||||
oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA,
|
||||
GPIO_INPUT_ROUTE | GPIO_HP_REAR);
|
||||
dg_output_enable(chip);
|
||||
}
|
||||
|
||||
static void dg_cleanup(struct oxygen *chip)
|
||||
{
|
||||
oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE);
|
||||
}
|
||||
|
||||
static void dg_suspend(struct oxygen *chip)
|
||||
{
|
||||
dg_cleanup(chip);
|
||||
}
|
||||
|
||||
static void dg_resume(struct oxygen *chip)
|
||||
{
|
||||
cs4245_registers_init(chip);
|
||||
dg_output_enable(chip);
|
||||
}
|
||||
|
||||
static void set_cs4245_dac_params(struct oxygen *chip,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct dg *data = chip->model_data;
|
||||
u8 value;
|
||||
|
||||
value = data->cs4245_regs[CS4245_DAC_CTRL_1] & ~CS4245_DAC_FM_MASK;
|
||||
if (params_rate(params) <= 50000)
|
||||
value |= CS4245_DAC_FM_SINGLE;
|
||||
else if (params_rate(params) <= 100000)
|
||||
value |= CS4245_DAC_FM_DOUBLE;
|
||||
else
|
||||
value |= CS4245_DAC_FM_QUAD;
|
||||
cs4245_write_cached(chip, CS4245_DAC_CTRL_1, value);
|
||||
}
|
||||
|
||||
static void set_cs4245_adc_params(struct oxygen *chip,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct dg *data = chip->model_data;
|
||||
u8 value;
|
||||
|
||||
value = data->cs4245_regs[CS4245_ADC_CTRL] & ~CS4245_ADC_FM_MASK;
|
||||
if (params_rate(params) <= 50000)
|
||||
value |= CS4245_ADC_FM_SINGLE;
|
||||
else if (params_rate(params) <= 100000)
|
||||
value |= CS4245_ADC_FM_DOUBLE;
|
||||
else
|
||||
value |= CS4245_ADC_FM_QUAD;
|
||||
cs4245_write_cached(chip, CS4245_ADC_CTRL, value);
|
||||
}
|
||||
|
||||
static int output_switch_info(struct snd_kcontrol *ctl,
|
||||
struct snd_ctl_elem_info *info)
|
||||
{
|
||||
static const char *const names[3] = {
|
||||
"Speakers", "Headphones", "FP Headphones"
|
||||
};
|
||||
|
||||
return snd_ctl_enum_info(info, 1, 3, names);
|
||||
}
|
||||
|
||||
static int output_switch_get(struct snd_kcontrol *ctl,
|
||||
struct snd_ctl_elem_value *value)
|
||||
{
|
||||
struct oxygen *chip = ctl->private_data;
|
||||
struct dg *data = chip->model_data;
|
||||
|
||||
mutex_lock(&chip->mutex);
|
||||
value->value.enumerated.item[0] = data->output_sel;
|
||||
mutex_unlock(&chip->mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int output_switch_put(struct snd_kcontrol *ctl,
|
||||
struct snd_ctl_elem_value *value)
|
||||
{
|
||||
struct oxygen *chip = ctl->private_data;
|
||||
struct dg *data = chip->model_data;
|
||||
u8 reg;
|
||||
int changed;
|
||||
|
||||
if (value->value.enumerated.item[0] > 2)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&chip->mutex);
|
||||
changed = value->value.enumerated.item[0] != data->output_sel;
|
||||
if (changed) {
|
||||
data->output_sel = value->value.enumerated.item[0];
|
||||
|
||||
reg = data->cs4245_regs[CS4245_SIGNAL_SEL] &
|
||||
~CS4245_A_OUT_SEL_MASK;
|
||||
reg |= data->output_sel == 2 ?
|
||||
CS4245_A_OUT_SEL_DAC : CS4245_A_OUT_SEL_HIZ;
|
||||
cs4245_write_cached(chip, CS4245_SIGNAL_SEL, reg);
|
||||
|
||||
cs4245_write_cached(chip, CS4245_DAC_A_CTRL,
|
||||
data->output_sel ? data->hp_vol_att : 0);
|
||||
cs4245_write_cached(chip, CS4245_DAC_B_CTRL,
|
||||
data->output_sel ? data->hp_vol_att : 0);
|
||||
|
||||
oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
|
||||
data->output_sel == 1 ? GPIO_HP_REAR : 0,
|
||||
GPIO_HP_REAR);
|
||||
}
|
||||
mutex_unlock(&chip->mutex);
|
||||
return changed;
|
||||
}
|
||||
|
||||
static int hp_volume_offset_info(struct snd_kcontrol *ctl,
|
||||
struct snd_ctl_elem_info *info)
|
||||
{
|
||||
static const char *const names[3] = {
|
||||
"< 64 ohms", "64-150 ohms", "150-300 ohms"
|
||||
};
|
||||
|
||||
return snd_ctl_enum_info(info, 1, 3, names);
|
||||
}
|
||||
|
||||
static int hp_volume_offset_get(struct snd_kcontrol *ctl,
|
||||
struct snd_ctl_elem_value *value)
|
||||
{
|
||||
struct oxygen *chip = ctl->private_data;
|
||||
struct dg *data = chip->model_data;
|
||||
|
||||
mutex_lock(&chip->mutex);
|
||||
if (data->hp_vol_att > 2 * 7)
|
||||
value->value.enumerated.item[0] = 0;
|
||||
else if (data->hp_vol_att > 0)
|
||||
value->value.enumerated.item[0] = 1;
|
||||
else
|
||||
value->value.enumerated.item[0] = 2;
|
||||
mutex_unlock(&chip->mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hp_volume_offset_put(struct snd_kcontrol *ctl,
|
||||
struct snd_ctl_elem_value *value)
|
||||
{
|
||||
static const s8 atts[3] = { 2 * 16, 2 * 7, 0 };
|
||||
struct oxygen *chip = ctl->private_data;
|
||||
struct dg *data = chip->model_data;
|
||||
s8 att;
|
||||
int changed;
|
||||
|
||||
if (value->value.enumerated.item[0] > 2)
|
||||
return -EINVAL;
|
||||
att = atts[value->value.enumerated.item[0]];
|
||||
mutex_lock(&chip->mutex);
|
||||
changed = att != data->hp_vol_att;
|
||||
if (changed) {
|
||||
data->hp_vol_att = att;
|
||||
if (data->output_sel) {
|
||||
cs4245_write_cached(chip, CS4245_DAC_A_CTRL, att);
|
||||
cs4245_write_cached(chip, CS4245_DAC_B_CTRL, att);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&chip->mutex);
|
||||
return changed;
|
||||
}
|
||||
|
||||
static int input_vol_info(struct snd_kcontrol *ctl,
|
||||
struct snd_ctl_elem_info *info)
|
||||
{
|
||||
info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
|
||||
info->count = 2;
|
||||
info->value.integer.min = 2 * -12;
|
||||
info->value.integer.max = 2 * 12;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int input_vol_get(struct snd_kcontrol *ctl,
|
||||
struct snd_ctl_elem_value *value)
|
||||
{
|
||||
struct oxygen *chip = ctl->private_data;
|
||||
struct dg *data = chip->model_data;
|
||||
unsigned int idx = ctl->private_value;
|
||||
|
||||
mutex_lock(&chip->mutex);
|
||||
value->value.integer.value[0] = data->input_vol[idx][0];
|
||||
value->value.integer.value[1] = data->input_vol[idx][1];
|
||||
mutex_unlock(&chip->mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int input_vol_put(struct snd_kcontrol *ctl,
|
||||
struct snd_ctl_elem_value *value)
|
||||
{
|
||||
struct oxygen *chip = ctl->private_data;
|
||||
struct dg *data = chip->model_data;
|
||||
unsigned int idx = ctl->private_value;
|
||||
int changed = 0;
|
||||
|
||||
if (value->value.integer.value[0] < 2 * -12 ||
|
||||
value->value.integer.value[0] > 2 * 12 ||
|
||||
value->value.integer.value[1] < 2 * -12 ||
|
||||
value->value.integer.value[1] > 2 * 12)
|
||||
return -EINVAL;
|
||||
mutex_lock(&chip->mutex);
|
||||
changed = data->input_vol[idx][0] != value->value.integer.value[0] ||
|
||||
data->input_vol[idx][1] != value->value.integer.value[1];
|
||||
if (changed) {
|
||||
data->input_vol[idx][0] = value->value.integer.value[0];
|
||||
data->input_vol[idx][1] = value->value.integer.value[1];
|
||||
if (idx == data->input_sel) {
|
||||
cs4245_write_cached(chip, CS4245_PGA_A_CTRL,
|
||||
data->input_vol[idx][0]);
|
||||
cs4245_write_cached(chip, CS4245_PGA_B_CTRL,
|
||||
data->input_vol[idx][1]);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&chip->mutex);
|
||||
return changed;
|
||||
}
|
||||
|
||||
static DECLARE_TLV_DB_SCALE(cs4245_pga_db_scale, -1200, 50, 0);
|
||||
|
||||
static int input_sel_info(struct snd_kcontrol *ctl,
|
||||
struct snd_ctl_elem_info *info)
|
||||
{
|
||||
static const char *const names[4] = {
|
||||
"Mic", "Aux", "Front Mic", "Line"
|
||||
};
|
||||
|
||||
return snd_ctl_enum_info(info, 1, 4, names);
|
||||
}
|
||||
|
||||
static int input_sel_get(struct snd_kcontrol *ctl,
|
||||
struct snd_ctl_elem_value *value)
|
||||
{
|
||||
struct oxygen *chip = ctl->private_data;
|
||||
struct dg *data = chip->model_data;
|
||||
|
||||
mutex_lock(&chip->mutex);
|
||||
value->value.enumerated.item[0] = data->input_sel;
|
||||
mutex_unlock(&chip->mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int input_sel_put(struct snd_kcontrol *ctl,
|
||||
struct snd_ctl_elem_value *value)
|
||||
{
|
||||
static const u8 sel_values[4] = {
|
||||
CS4245_SEL_MIC,
|
||||
CS4245_SEL_INPUT_1,
|
||||
CS4245_SEL_INPUT_2,
|
||||
CS4245_SEL_INPUT_4
|
||||
};
|
||||
struct oxygen *chip = ctl->private_data;
|
||||
struct dg *data = chip->model_data;
|
||||
int changed;
|
||||
|
||||
if (value->value.enumerated.item[0] > 3)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&chip->mutex);
|
||||
changed = value->value.enumerated.item[0] != data->input_sel;
|
||||
if (changed) {
|
||||
data->input_sel = value->value.enumerated.item[0];
|
||||
|
||||
cs4245_write(chip, CS4245_ANALOG_IN,
|
||||
(data->cs4245_regs[CS4245_ANALOG_IN] &
|
||||
~CS4245_SEL_MASK) |
|
||||
sel_values[data->input_sel]);
|
||||
|
||||
cs4245_write_cached(chip, CS4245_PGA_A_CTRL,
|
||||
data->input_vol[data->input_sel][0]);
|
||||
cs4245_write_cached(chip, CS4245_PGA_B_CTRL,
|
||||
data->input_vol[data->input_sel][1]);
|
||||
|
||||
oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
|
||||
data->input_sel ? 0 : GPIO_INPUT_ROUTE,
|
||||
GPIO_INPUT_ROUTE);
|
||||
}
|
||||
mutex_unlock(&chip->mutex);
|
||||
return changed;
|
||||
}
|
||||
|
||||
static int hpf_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info)
|
||||
{
|
||||
static const char *const names[2] = { "Active", "Frozen" };
|
||||
|
||||
return snd_ctl_enum_info(info, 1, 2, names);
|
||||
}
|
||||
|
||||
static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
|
||||
{
|
||||
struct oxygen *chip = ctl->private_data;
|
||||
struct dg *data = chip->model_data;
|
||||
|
||||
value->value.enumerated.item[0] =
|
||||
!!(data->cs4245_regs[CS4245_ADC_CTRL] & CS4245_HPF_FREEZE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hpf_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
|
||||
{
|
||||
struct oxygen *chip = ctl->private_data;
|
||||
struct dg *data = chip->model_data;
|
||||
u8 reg;
|
||||
int changed;
|
||||
|
||||
mutex_lock(&chip->mutex);
|
||||
reg = data->cs4245_regs[CS4245_ADC_CTRL] & ~CS4245_HPF_FREEZE;
|
||||
if (value->value.enumerated.item[0])
|
||||
reg |= CS4245_HPF_FREEZE;
|
||||
changed = reg != data->cs4245_regs[CS4245_ADC_CTRL];
|
||||
if (changed)
|
||||
cs4245_write(chip, CS4245_ADC_CTRL, reg);
|
||||
mutex_unlock(&chip->mutex);
|
||||
return changed;
|
||||
}
|
||||
|
||||
#define INPUT_VOLUME(xname, index) { \
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
|
||||
.name = xname, \
|
||||
.info = input_vol_info, \
|
||||
.get = input_vol_get, \
|
||||
.put = input_vol_put, \
|
||||
.tlv = { .p = cs4245_pga_db_scale }, \
|
||||
.private_value = index, \
|
||||
}
|
||||
static const struct snd_kcontrol_new dg_controls[] = {
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Analog Output Playback Enum",
|
||||
.info = output_switch_info,
|
||||
.get = output_switch_get,
|
||||
.put = output_switch_put,
|
||||
},
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Headphones Impedance Playback Enum",
|
||||
.info = hp_volume_offset_info,
|
||||
.get = hp_volume_offset_get,
|
||||
.put = hp_volume_offset_put,
|
||||
},
|
||||
INPUT_VOLUME("Mic Capture Volume", 0),
|
||||
INPUT_VOLUME("Aux Capture Volume", 1),
|
||||
INPUT_VOLUME("Front Mic Capture Volume", 2),
|
||||
INPUT_VOLUME("Line Capture Volume", 3),
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Capture Source",
|
||||
.info = input_sel_info,
|
||||
.get = input_sel_get,
|
||||
.put = input_sel_put,
|
||||
},
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "ADC High-pass Filter Capture Enum",
|
||||
.info = hpf_info,
|
||||
.get = hpf_get,
|
||||
.put = hpf_put,
|
||||
},
|
||||
};
|
||||
|
||||
static int dg_control_filter(struct snd_kcontrol_new *template)
|
||||
{
|
||||
if (!strncmp(template->name, "Master Playback ", 16))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dg_mixer_init(struct oxygen *chip)
|
||||
{
|
||||
unsigned int i;
|
||||
int err;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(dg_controls); ++i) {
|
||||
err = snd_ctl_add(chip->card,
|
||||
snd_ctl_new1(&dg_controls[i], chip));
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dump_cs4245_registers(struct oxygen *chip,
|
||||
struct snd_info_buffer *buffer)
|
||||
{
|
||||
struct dg *data = chip->model_data;
|
||||
unsigned int i;
|
||||
|
||||
snd_iprintf(buffer, "\nCS4245:");
|
||||
for (i = 1; i <= 0x10; ++i)
|
||||
snd_iprintf(buffer, " %02x", data->cs4245_regs[i]);
|
||||
snd_iprintf(buffer, "\n");
|
||||
}
|
||||
|
||||
struct oxygen_model model_xonar_dg = {
|
||||
.shortname = "Xonar DG",
|
||||
.longname = "C-Media Oxygen HD Audio",
|
||||
.chip = "CMI8786",
|
||||
.init = dg_init,
|
||||
.control_filter = dg_control_filter,
|
||||
.mixer_init = dg_mixer_init,
|
||||
.cleanup = dg_cleanup,
|
||||
.suspend = dg_suspend,
|
||||
.resume = dg_resume,
|
||||
.set_dac_params = set_cs4245_dac_params,
|
||||
.set_adc_params = set_cs4245_adc_params,
|
||||
.dump_registers = dump_cs4245_registers,
|
||||
.model_data_size = sizeof(struct dg),
|
||||
.device_config = PLAYBACK_0_TO_I2S |
|
||||
PLAYBACK_1_TO_SPDIF |
|
||||
CAPTURE_0_FROM_I2S_2,
|
||||
.dac_channels_pcm = 6,
|
||||
.dac_channels_mixer = 0,
|
||||
.function_flags = OXYGEN_FUNCTION_SPI,
|
||||
.dac_mclks = OXYGEN_MCLKS(256, 128, 128),
|
||||
.adc_mclks = OXYGEN_MCLKS(256, 128, 128),
|
||||
.dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
|
||||
.adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
|
||||
};
|
8
sound/pci/oxygen/xonar_dg.h
Normal file
8
sound/pci/oxygen/xonar_dg.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef XONAR_DG_H_INCLUDED
|
||||
#define XONAR_DG_H_INCLUDED
|
||||
|
||||
#include "oxygen.h"
|
||||
|
||||
extern struct oxygen_model model_xonar_dg;
|
||||
|
||||
#endif
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* helper functions for HDMI models (Xonar HDAV1.3)
|
||||
* helper functions for HDMI models (Xonar HDAV1.3/HDAV1.3 Slim)
|
||||
*
|
||||
* Copyright (c) Clemens Ladisch <clemens@ladisch.de>
|
||||
*
|
||||
|
@ -104,9 +104,10 @@ int xonar_gpio_bit_switch_get(struct snd_kcontrol *ctl,
|
||||
{
|
||||
struct oxygen *chip = ctl->private_data;
|
||||
u16 bit = ctl->private_value;
|
||||
bool invert = ctl->private_value & XONAR_GPIO_BIT_INVERT;
|
||||
|
||||
value->value.integer.value[0] =
|
||||
!!(oxygen_read16(chip, OXYGEN_GPIO_DATA) & bit);
|
||||
!!(oxygen_read16(chip, OXYGEN_GPIO_DATA) & bit) ^ invert;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -115,12 +116,13 @@ int xonar_gpio_bit_switch_put(struct snd_kcontrol *ctl,
|
||||
{
|
||||
struct oxygen *chip = ctl->private_data;
|
||||
u16 bit = ctl->private_value;
|
||||
bool invert = ctl->private_value & XONAR_GPIO_BIT_INVERT;
|
||||
u16 old_bits, new_bits;
|
||||
int changed;
|
||||
|
||||
spin_lock_irq(&chip->reg_lock);
|
||||
old_bits = oxygen_read16(chip, OXYGEN_GPIO_DATA);
|
||||
if (value->value.integer.value[0])
|
||||
if (!!value->value.integer.value[0] ^ invert)
|
||||
new_bits = old_bits | bit;
|
||||
else
|
||||
new_bits = old_bits & ~bit;
|
||||
|
@ -22,20 +22,26 @@
|
||||
*
|
||||
* CMI8788:
|
||||
*
|
||||
* SPI 0 -> 1st PCM1796 (front)
|
||||
* SPI 1 -> 2nd PCM1796 (surround)
|
||||
* SPI 2 -> 3rd PCM1796 (center/LFE)
|
||||
* SPI 4 -> 4th PCM1796 (back)
|
||||
* SPI 0 -> 1st PCM1796 (front)
|
||||
* SPI 1 -> 2nd PCM1796 (surround)
|
||||
* SPI 2 -> 3rd PCM1796 (center/LFE)
|
||||
* SPI 4 -> 4th PCM1796 (back)
|
||||
*
|
||||
* GPIO 2 -> M0 of CS5381
|
||||
* GPIO 3 -> M1 of CS5381
|
||||
* GPIO 5 <- external power present (D2X only)
|
||||
* GPIO 7 -> ALT
|
||||
* GPIO 8 -> enable output to speakers
|
||||
* GPIO 2 -> M0 of CS5381
|
||||
* GPIO 3 -> M1 of CS5381
|
||||
* GPIO 5 <- external power present (D2X only)
|
||||
* GPIO 7 -> ALT
|
||||
* GPIO 8 -> enable output to speakers
|
||||
*
|
||||
* CM9780:
|
||||
*
|
||||
* GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input
|
||||
* LINE_OUT -> input of ADC
|
||||
*
|
||||
* AUX_IN <- aux
|
||||
* VIDEO_IN <- CD
|
||||
* FMIC_IN <- mic
|
||||
*
|
||||
* GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -44,52 +50,53 @@
|
||||
*
|
||||
* CMI8788:
|
||||
*
|
||||
* I²C <-> PCM1796 (front)
|
||||
* I²C <-> PCM1796 (addr 1001100) (front)
|
||||
*
|
||||
* GPI 0 <- external power present
|
||||
* GPI 0 <- external power present
|
||||
*
|
||||
* GPIO 0 -> enable output to speakers
|
||||
* GPIO 2 -> M0 of CS5381
|
||||
* GPIO 3 -> M1 of CS5381
|
||||
* GPIO 8 -> route input jack to line-in (0) or mic-in (1)
|
||||
* GPIO 0 -> enable HDMI (0) or speaker (1) output
|
||||
* GPIO 2 -> M0 of CS5381
|
||||
* GPIO 3 -> M1 of CS5381
|
||||
* GPIO 4 <- daughterboard detection
|
||||
* GPIO 5 <- daughterboard detection
|
||||
* GPIO 6 -> ?
|
||||
* GPIO 7 -> ?
|
||||
* GPIO 8 -> route input jack to line-in (0) or mic-in (1)
|
||||
*
|
||||
* TXD -> HDMI controller
|
||||
* RXD <- HDMI controller
|
||||
*
|
||||
* PCM1796 front: AD1,0 <- 0,0
|
||||
* UART <-> HDMI controller
|
||||
*
|
||||
* CM9780:
|
||||
*
|
||||
* GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input
|
||||
* LINE_OUT -> input of ADC
|
||||
*
|
||||
* AUX_IN <- aux
|
||||
* CD_IN <- CD
|
||||
* MIC_IN <- mic
|
||||
*
|
||||
* GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input
|
||||
*
|
||||
* no daughterboard
|
||||
* ----------------
|
||||
*
|
||||
* GPIO 4 <- 1
|
||||
* GPIO 4 <- 1
|
||||
*
|
||||
* H6 daughterboard
|
||||
* ----------------
|
||||
*
|
||||
* GPIO 4 <- 0
|
||||
* GPIO 5 <- 0
|
||||
* GPIO 4 <- 0
|
||||
* GPIO 5 <- 0
|
||||
*
|
||||
* I²C <-> PCM1796 (surround)
|
||||
* <-> PCM1796 (center/LFE)
|
||||
* <-> PCM1796 (back)
|
||||
*
|
||||
* PCM1796 surround: AD1,0 <- 0,1
|
||||
* PCM1796 center/LFE: AD1,0 <- 1,0
|
||||
* PCM1796 back: AD1,0 <- 1,1
|
||||
* I²C <-> PCM1796 (addr 1001101) (surround)
|
||||
* <-> PCM1796 (addr 1001110) (center/LFE)
|
||||
* <-> PCM1796 (addr 1001111) (back)
|
||||
*
|
||||
* unknown daughterboard
|
||||
* ---------------------
|
||||
*
|
||||
* GPIO 4 <- 0
|
||||
* GPIO 5 <- 1
|
||||
* GPIO 4 <- 0
|
||||
* GPIO 5 <- 1
|
||||
*
|
||||
* I²C <-> CS4362A (surround, center/LFE, back)
|
||||
*
|
||||
* CS4362A: AD0 <- 0
|
||||
* I²C <-> CS4362A (addr 0011000) (surround, center/LFE, back)
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -98,32 +105,35 @@
|
||||
*
|
||||
* CMI8788:
|
||||
*
|
||||
* I²C <-> PCM1792A
|
||||
* <-> CS2000 (ST only)
|
||||
* I²C <-> PCM1792A (addr 1001100)
|
||||
* <-> CS2000 (addr 1001110) (ST only)
|
||||
*
|
||||
* ADC1 MCLK -> REF_CLK of CS2000 (ST only)
|
||||
* ADC1 MCLK -> REF_CLK of CS2000 (ST only)
|
||||
*
|
||||
* GPI 0 <- external power present (STX only)
|
||||
* GPI 0 <- external power present (STX only)
|
||||
*
|
||||
* GPIO 0 -> enable output to speakers
|
||||
* GPIO 1 -> route HP to front panel (0) or rear jack (1)
|
||||
* GPIO 2 -> M0 of CS5381
|
||||
* GPIO 3 -> M1 of CS5381
|
||||
* GPIO 7 -> route output to speaker jacks (0) or HP (1)
|
||||
* GPIO 8 -> route input jack to line-in (0) or mic-in (1)
|
||||
* GPIO 0 -> enable output to speakers
|
||||
* GPIO 1 -> route HP to front panel (0) or rear jack (1)
|
||||
* GPIO 2 -> M0 of CS5381
|
||||
* GPIO 3 -> M1 of CS5381
|
||||
* GPIO 4 <- daughterboard detection
|
||||
* GPIO 5 <- daughterboard detection
|
||||
* GPIO 6 -> ?
|
||||
* GPIO 7 -> route output to speaker jacks (0) or HP (1)
|
||||
* GPIO 8 -> route input jack to line-in (0) or mic-in (1)
|
||||
*
|
||||
* PCM1792A:
|
||||
*
|
||||
* AD1,0 <- 0,0
|
||||
* SCK <- CLK_OUT of CS2000 (ST only)
|
||||
*
|
||||
* CS2000:
|
||||
*
|
||||
* AD0 <- 0
|
||||
* SCK <- CLK_OUT of CS2000 (ST only)
|
||||
*
|
||||
* CM9780:
|
||||
*
|
||||
* GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input
|
||||
* LINE_OUT -> input of ADC
|
||||
*
|
||||
* AUX_IN <- aux
|
||||
* MIC_IN <- mic
|
||||
*
|
||||
* GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input
|
||||
*
|
||||
* H6 daughterboard
|
||||
* ----------------
|
||||
@ -133,15 +143,39 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Xonar HDAV1.3 Slim
|
||||
* ------------------
|
||||
* Xonar Xense
|
||||
* -----------
|
||||
*
|
||||
* CMI8788:
|
||||
*
|
||||
* GPIO 1 -> enable output
|
||||
* I²C <-> PCM1796 (addr 1001100) (front)
|
||||
* <-> CS4362A (addr 0011000) (surround, center/LFE, back)
|
||||
* <-> CS2000 (addr 1001110)
|
||||
*
|
||||
* TXD -> HDMI controller
|
||||
* RXD <- HDMI controller
|
||||
* ADC1 MCLK -> REF_CLK of CS2000
|
||||
*
|
||||
* GPI 0 <- external power present
|
||||
*
|
||||
* GPIO 0 -> enable output
|
||||
* GPIO 1 -> route HP to front panel (0) or rear jack (1)
|
||||
* GPIO 2 -> M0 of CS5381
|
||||
* GPIO 3 -> M1 of CS5381
|
||||
* GPIO 4 -> enable output
|
||||
* GPIO 5 -> enable output
|
||||
* GPIO 6 -> ?
|
||||
* GPIO 7 -> route output to HP (0) or speaker (1)
|
||||
* GPIO 8 -> route input jack to mic-in (0) or line-in (1)
|
||||
*
|
||||
* CM9780:
|
||||
*
|
||||
* LINE_OUT -> input of ADC
|
||||
*
|
||||
* AUX_IN <- aux
|
||||
* VIDEO_IN <- ?
|
||||
* FMIC_IN <- mic
|
||||
*
|
||||
* GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input
|
||||
* GPO 1 -> route mic-in from input jack (0) or front panel header (1)
|
||||
*/
|
||||
|
||||
#include <linux/pci.h>
|
||||
@ -150,6 +184,7 @@
|
||||
#include <sound/ac97_codec.h>
|
||||
#include <sound/control.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/info.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/tlv.h>
|
||||
@ -167,12 +202,14 @@
|
||||
#define GPIO_INPUT_ROUTE 0x0100
|
||||
|
||||
#define GPIO_HDAV_OUTPUT_ENABLE 0x0001
|
||||
#define GPIO_HDAV_MAGIC 0x00c0
|
||||
|
||||
#define GPIO_DB_MASK 0x0030
|
||||
#define GPIO_DB_H6 0x0000
|
||||
|
||||
#define GPIO_ST_OUTPUT_ENABLE 0x0001
|
||||
#define GPIO_ST_HP_REAR 0x0002
|
||||
#define GPIO_ST_MAGIC 0x0040
|
||||
#define GPIO_ST_HP 0x0080
|
||||
|
||||
#define I2C_DEVICE_PCM1796(i) (0x98 + ((i) << 1)) /* 10011, ii, /W=0 */
|
||||
@ -186,11 +223,12 @@ struct xonar_pcm179x {
|
||||
unsigned int dacs;
|
||||
u8 pcm1796_regs[4][5];
|
||||
unsigned int current_rate;
|
||||
bool os_128;
|
||||
bool h6;
|
||||
bool hp_active;
|
||||
s8 hp_gain_offset;
|
||||
bool has_cs2000;
|
||||
u8 cs2000_fun_cfg_1;
|
||||
u8 cs2000_regs[0x1f];
|
||||
bool broken_i2c;
|
||||
};
|
||||
|
||||
struct xonar_hdav {
|
||||
@ -249,16 +287,14 @@ static void cs2000_write(struct oxygen *chip, u8 reg, u8 value)
|
||||
struct xonar_pcm179x *data = chip->model_data;
|
||||
|
||||
oxygen_write_i2c(chip, I2C_DEVICE_CS2000, reg, value);
|
||||
if (reg == CS2000_FUN_CFG_1)
|
||||
data->cs2000_fun_cfg_1 = value;
|
||||
data->cs2000_regs[reg] = value;
|
||||
}
|
||||
|
||||
static void cs2000_write_cached(struct oxygen *chip, u8 reg, u8 value)
|
||||
{
|
||||
struct xonar_pcm179x *data = chip->model_data;
|
||||
|
||||
if (reg != CS2000_FUN_CFG_1 ||
|
||||
value != data->cs2000_fun_cfg_1)
|
||||
if (value != data->cs2000_regs[reg])
|
||||
cs2000_write(chip, reg, value);
|
||||
}
|
||||
|
||||
@ -268,6 +304,7 @@ static void pcm1796_registers_init(struct oxygen *chip)
|
||||
unsigned int i;
|
||||
s8 gain_offset;
|
||||
|
||||
msleep(1);
|
||||
gain_offset = data->hp_active ? data->hp_gain_offset : 0;
|
||||
for (i = 0; i < data->dacs; ++i) {
|
||||
/* set ATLD before ATL/ATR */
|
||||
@ -282,6 +319,7 @@ static void pcm1796_registers_init(struct oxygen *chip)
|
||||
pcm1796_write(chip, i, 20,
|
||||
data->pcm1796_regs[0][20 - PCM1796_REG_BASE]);
|
||||
pcm1796_write(chip, i, 21, 0);
|
||||
gain_offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -290,10 +328,11 @@ static void pcm1796_init(struct oxygen *chip)
|
||||
struct xonar_pcm179x *data = chip->model_data;
|
||||
|
||||
data->pcm1796_regs[0][18 - PCM1796_REG_BASE] = PCM1796_MUTE |
|
||||
PCM1796_DMF_DISABLED | PCM1796_FMT_24_LJUST | PCM1796_ATLD;
|
||||
PCM1796_DMF_DISABLED | PCM1796_FMT_24_I2S | PCM1796_ATLD;
|
||||
data->pcm1796_regs[0][19 - PCM1796_REG_BASE] =
|
||||
PCM1796_FLT_SHARP | PCM1796_ATS_1;
|
||||
data->pcm1796_regs[0][20 - PCM1796_REG_BASE] = PCM1796_OS_64;
|
||||
data->pcm1796_regs[0][20 - PCM1796_REG_BASE] =
|
||||
data->h6 ? PCM1796_OS_64 : PCM1796_OS_128;
|
||||
pcm1796_registers_init(chip);
|
||||
data->current_rate = 48000;
|
||||
}
|
||||
@ -339,18 +378,20 @@ static void xonar_hdav_init(struct oxygen *chip)
|
||||
oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS,
|
||||
OXYGEN_2WIRE_LENGTH_8 |
|
||||
OXYGEN_2WIRE_INTERRUPT_MASK |
|
||||
OXYGEN_2WIRE_SPEED_FAST);
|
||||
OXYGEN_2WIRE_SPEED_STANDARD);
|
||||
|
||||
data->pcm179x.generic.anti_pop_delay = 100;
|
||||
data->pcm179x.generic.output_enable_bit = GPIO_HDAV_OUTPUT_ENABLE;
|
||||
data->pcm179x.generic.ext_power_reg = OXYGEN_GPI_DATA;
|
||||
data->pcm179x.generic.ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK;
|
||||
data->pcm179x.generic.ext_power_bit = GPI_EXT_POWER;
|
||||
data->pcm179x.dacs = chip->model.private_data ? 4 : 1;
|
||||
data->pcm179x.dacs = chip->model.dac_channels_mixer / 2;
|
||||
data->pcm179x.h6 = chip->model.dac_channels_mixer > 2;
|
||||
|
||||
pcm1796_init(chip);
|
||||
|
||||
oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_INPUT_ROUTE);
|
||||
oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
|
||||
GPIO_HDAV_MAGIC | GPIO_INPUT_ROUTE);
|
||||
oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_INPUT_ROUTE);
|
||||
|
||||
xonar_init_cs53x1(chip);
|
||||
@ -367,7 +408,7 @@ static void xonar_st_init_i2c(struct oxygen *chip)
|
||||
oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS,
|
||||
OXYGEN_2WIRE_LENGTH_8 |
|
||||
OXYGEN_2WIRE_INTERRUPT_MASK |
|
||||
OXYGEN_2WIRE_SPEED_FAST);
|
||||
OXYGEN_2WIRE_SPEED_STANDARD);
|
||||
}
|
||||
|
||||
static void xonar_st_init_common(struct oxygen *chip)
|
||||
@ -375,13 +416,14 @@ static void xonar_st_init_common(struct oxygen *chip)
|
||||
struct xonar_pcm179x *data = chip->model_data;
|
||||
|
||||
data->generic.output_enable_bit = GPIO_ST_OUTPUT_ENABLE;
|
||||
data->dacs = chip->model.private_data ? 4 : 1;
|
||||
data->dacs = chip->model.dac_channels_mixer / 2;
|
||||
data->hp_gain_offset = 2*-18;
|
||||
|
||||
pcm1796_init(chip);
|
||||
|
||||
oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
|
||||
GPIO_INPUT_ROUTE | GPIO_ST_HP_REAR | GPIO_ST_HP);
|
||||
GPIO_INPUT_ROUTE | GPIO_ST_HP_REAR |
|
||||
GPIO_ST_MAGIC | GPIO_ST_HP);
|
||||
oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA,
|
||||
GPIO_INPUT_ROUTE | GPIO_ST_HP_REAR | GPIO_ST_HP);
|
||||
|
||||
@ -410,9 +452,11 @@ static void cs2000_registers_init(struct oxygen *chip)
|
||||
cs2000_write(chip, CS2000_RATIO_0 + 1, 0x10);
|
||||
cs2000_write(chip, CS2000_RATIO_0 + 2, 0x00);
|
||||
cs2000_write(chip, CS2000_RATIO_0 + 3, 0x00);
|
||||
cs2000_write(chip, CS2000_FUN_CFG_1, data->cs2000_fun_cfg_1);
|
||||
cs2000_write(chip, CS2000_FUN_CFG_1,
|
||||
data->cs2000_regs[CS2000_FUN_CFG_1]);
|
||||
cs2000_write(chip, CS2000_FUN_CFG_2, 0);
|
||||
cs2000_write(chip, CS2000_GLOBAL_CFG, CS2000_EN_DEV_CFG_2);
|
||||
msleep(3); /* PLL lock delay */
|
||||
}
|
||||
|
||||
static void xonar_st_init(struct oxygen *chip)
|
||||
@ -420,13 +464,18 @@ static void xonar_st_init(struct oxygen *chip)
|
||||
struct xonar_pcm179x *data = chip->model_data;
|
||||
|
||||
data->generic.anti_pop_delay = 100;
|
||||
data->h6 = chip->model.dac_channels_mixer > 2;
|
||||
data->has_cs2000 = 1;
|
||||
data->cs2000_fun_cfg_1 = CS2000_REF_CLK_DIV_1;
|
||||
data->cs2000_regs[CS2000_FUN_CFG_1] = CS2000_REF_CLK_DIV_1;
|
||||
data->broken_i2c = true;
|
||||
|
||||
oxygen_write16(chip, OXYGEN_I2S_A_FORMAT,
|
||||
OXYGEN_RATE_48000 | OXYGEN_I2S_FORMAT_I2S |
|
||||
OXYGEN_I2S_MCLK_128 | OXYGEN_I2S_BITS_16 |
|
||||
OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64);
|
||||
OXYGEN_RATE_48000 |
|
||||
OXYGEN_I2S_FORMAT_I2S |
|
||||
OXYGEN_I2S_MCLK(data->h6 ? MCLK_256 : MCLK_512) |
|
||||
OXYGEN_I2S_BITS_16 |
|
||||
OXYGEN_I2S_MASTER |
|
||||
OXYGEN_I2S_BCLK_64);
|
||||
|
||||
xonar_st_init_i2c(chip);
|
||||
cs2000_registers_init(chip);
|
||||
@ -507,44 +556,16 @@ static void xonar_st_resume(struct oxygen *chip)
|
||||
xonar_stx_resume(chip);
|
||||
}
|
||||
|
||||
static unsigned int mclk_from_rate(struct oxygen *chip, unsigned int rate)
|
||||
{
|
||||
struct xonar_pcm179x *data = chip->model_data;
|
||||
|
||||
if (rate <= 32000)
|
||||
return OXYGEN_I2S_MCLK_512;
|
||||
else if (rate <= 48000 && data->os_128)
|
||||
return OXYGEN_I2S_MCLK_512;
|
||||
else if (rate <= 96000)
|
||||
return OXYGEN_I2S_MCLK_256;
|
||||
else
|
||||
return OXYGEN_I2S_MCLK_128;
|
||||
}
|
||||
|
||||
static unsigned int get_pcm1796_i2s_mclk(struct oxygen *chip,
|
||||
unsigned int channel,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
if (channel == PCM_MULTICH)
|
||||
return mclk_from_rate(chip, params_rate(params));
|
||||
else
|
||||
return oxygen_default_i2s_mclk(chip, channel, params);
|
||||
}
|
||||
|
||||
static void update_pcm1796_oversampling(struct oxygen *chip)
|
||||
{
|
||||
struct xonar_pcm179x *data = chip->model_data;
|
||||
unsigned int i;
|
||||
u8 reg;
|
||||
|
||||
if (data->current_rate <= 32000)
|
||||
if (data->current_rate <= 48000 && !data->h6)
|
||||
reg = PCM1796_OS_128;
|
||||
else if (data->current_rate <= 48000 && data->os_128)
|
||||
reg = PCM1796_OS_128;
|
||||
else if (data->current_rate <= 96000 || data->os_128)
|
||||
reg = PCM1796_OS_64;
|
||||
else
|
||||
reg = PCM1796_OS_32;
|
||||
reg = PCM1796_OS_64;
|
||||
for (i = 0; i < data->dacs; ++i)
|
||||
pcm1796_write_cached(chip, i, 20, reg);
|
||||
}
|
||||
@ -554,6 +575,7 @@ static void set_pcm1796_params(struct oxygen *chip,
|
||||
{
|
||||
struct xonar_pcm179x *data = chip->model_data;
|
||||
|
||||
msleep(1);
|
||||
data->current_rate = params_rate(params);
|
||||
update_pcm1796_oversampling(chip);
|
||||
}
|
||||
@ -570,6 +592,7 @@ static void update_pcm1796_volume(struct oxygen *chip)
|
||||
+ gain_offset);
|
||||
pcm1796_write_cached(chip, i, 17, chip->dac_volume[i * 2 + 1]
|
||||
+ gain_offset);
|
||||
gain_offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -579,7 +602,7 @@ static void update_pcm1796_mute(struct oxygen *chip)
|
||||
unsigned int i;
|
||||
u8 value;
|
||||
|
||||
value = PCM1796_DMF_DISABLED | PCM1796_FMT_24_LJUST | PCM1796_ATLD;
|
||||
value = PCM1796_DMF_DISABLED | PCM1796_FMT_24_I2S | PCM1796_ATLD;
|
||||
if (chip->dac_mute)
|
||||
value |= PCM1796_MUTE;
|
||||
for (i = 0; i < data->dacs; ++i)
|
||||
@ -592,45 +615,35 @@ static void update_cs2000_rate(struct oxygen *chip, unsigned int rate)
|
||||
u8 rate_mclk, reg;
|
||||
|
||||
switch (rate) {
|
||||
/* XXX Why is the I2S A MCLK half the actual I2S MCLK? */
|
||||
case 32000:
|
||||
rate_mclk = OXYGEN_RATE_32000 | OXYGEN_I2S_MCLK_256;
|
||||
case 64000:
|
||||
rate_mclk = OXYGEN_RATE_32000;
|
||||
break;
|
||||
case 44100:
|
||||
if (data->os_128)
|
||||
rate_mclk = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_256;
|
||||
else
|
||||
rate_mclk = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_128;
|
||||
break;
|
||||
default: /* 48000 */
|
||||
if (data->os_128)
|
||||
rate_mclk = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_256;
|
||||
else
|
||||
rate_mclk = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_128;
|
||||
break;
|
||||
case 64000:
|
||||
rate_mclk = OXYGEN_RATE_32000 | OXYGEN_I2S_MCLK_256;
|
||||
break;
|
||||
case 88200:
|
||||
rate_mclk = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_256;
|
||||
break;
|
||||
case 96000:
|
||||
rate_mclk = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_256;
|
||||
break;
|
||||
case 176400:
|
||||
rate_mclk = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_256;
|
||||
rate_mclk = OXYGEN_RATE_44100;
|
||||
break;
|
||||
default:
|
||||
case 48000:
|
||||
case 96000:
|
||||
case 192000:
|
||||
rate_mclk = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_256;
|
||||
rate_mclk = OXYGEN_RATE_48000;
|
||||
break;
|
||||
}
|
||||
|
||||
if (rate <= 96000 && (rate > 48000 || data->h6)) {
|
||||
rate_mclk |= OXYGEN_I2S_MCLK(MCLK_256);
|
||||
reg = CS2000_REF_CLK_DIV_1;
|
||||
} else {
|
||||
rate_mclk |= OXYGEN_I2S_MCLK(MCLK_512);
|
||||
reg = CS2000_REF_CLK_DIV_2;
|
||||
}
|
||||
|
||||
oxygen_write16_masked(chip, OXYGEN_I2S_A_FORMAT, rate_mclk,
|
||||
OXYGEN_I2S_RATE_MASK | OXYGEN_I2S_MCLK_MASK);
|
||||
if ((rate_mclk & OXYGEN_I2S_MCLK_MASK) <= OXYGEN_I2S_MCLK_128)
|
||||
reg = CS2000_REF_CLK_DIV_1;
|
||||
else
|
||||
reg = CS2000_REF_CLK_DIV_2;
|
||||
cs2000_write_cached(chip, CS2000_FUN_CFG_1, reg);
|
||||
msleep(3); /* PLL lock delay */
|
||||
}
|
||||
|
||||
static void set_st_params(struct oxygen *chip,
|
||||
@ -665,13 +678,7 @@ static int rolloff_info(struct snd_kcontrol *ctl,
|
||||
"Sharp Roll-off", "Slow Roll-off"
|
||||
};
|
||||
|
||||
info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
|
||||
info->count = 1;
|
||||
info->value.enumerated.items = 2;
|
||||
if (info->value.enumerated.item >= 2)
|
||||
info->value.enumerated.item = 1;
|
||||
strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
|
||||
return 0;
|
||||
return snd_ctl_enum_info(info, 1, 2, names);
|
||||
}
|
||||
|
||||
static int rolloff_get(struct snd_kcontrol *ctl,
|
||||
@ -719,57 +726,13 @@ static const struct snd_kcontrol_new rolloff_control = {
|
||||
.put = rolloff_put,
|
||||
};
|
||||
|
||||
static int os_128_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info)
|
||||
{
|
||||
static const char *const names[2] = { "64x", "128x" };
|
||||
|
||||
info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
|
||||
info->count = 1;
|
||||
info->value.enumerated.items = 2;
|
||||
if (info->value.enumerated.item >= 2)
|
||||
info->value.enumerated.item = 1;
|
||||
strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int os_128_get(struct snd_kcontrol *ctl,
|
||||
struct snd_ctl_elem_value *value)
|
||||
{
|
||||
struct oxygen *chip = ctl->private_data;
|
||||
struct xonar_pcm179x *data = chip->model_data;
|
||||
|
||||
value->value.enumerated.item[0] = data->os_128;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int os_128_put(struct snd_kcontrol *ctl,
|
||||
struct snd_ctl_elem_value *value)
|
||||
{
|
||||
struct oxygen *chip = ctl->private_data;
|
||||
struct xonar_pcm179x *data = chip->model_data;
|
||||
int changed;
|
||||
|
||||
mutex_lock(&chip->mutex);
|
||||
changed = value->value.enumerated.item[0] != data->os_128;
|
||||
if (changed) {
|
||||
data->os_128 = value->value.enumerated.item[0];
|
||||
if (data->has_cs2000)
|
||||
update_cs2000_rate(chip, data->current_rate);
|
||||
oxygen_write16_masked(chip, OXYGEN_I2S_MULTICH_FORMAT,
|
||||
mclk_from_rate(chip, data->current_rate),
|
||||
OXYGEN_I2S_MCLK_MASK);
|
||||
update_pcm1796_oversampling(chip);
|
||||
}
|
||||
mutex_unlock(&chip->mutex);
|
||||
return changed;
|
||||
}
|
||||
|
||||
static const struct snd_kcontrol_new os_128_control = {
|
||||
static const struct snd_kcontrol_new hdav_hdmi_control = {
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "DAC Oversampling Playback Enum",
|
||||
.info = os_128_info,
|
||||
.get = os_128_get,
|
||||
.put = os_128_put,
|
||||
.name = "HDMI Playback Switch",
|
||||
.info = snd_ctl_boolean_mono_info,
|
||||
.get = xonar_gpio_bit_switch_get,
|
||||
.put = xonar_gpio_bit_switch_put,
|
||||
.private_value = GPIO_HDAV_OUTPUT_ENABLE | XONAR_GPIO_BIT_INVERT,
|
||||
};
|
||||
|
||||
static int st_output_switch_info(struct snd_kcontrol *ctl,
|
||||
@ -779,13 +742,7 @@ static int st_output_switch_info(struct snd_kcontrol *ctl,
|
||||
"Speakers", "Headphones", "FP Headphones"
|
||||
};
|
||||
|
||||
info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
|
||||
info->count = 1;
|
||||
info->value.enumerated.items = 3;
|
||||
if (info->value.enumerated.item >= 3)
|
||||
info->value.enumerated.item = 2;
|
||||
strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
|
||||
return 0;
|
||||
return snd_ctl_enum_info(info, 1, 3, names);
|
||||
}
|
||||
|
||||
static int st_output_switch_get(struct snd_kcontrol *ctl,
|
||||
@ -840,13 +797,7 @@ static int st_hp_volume_offset_info(struct snd_kcontrol *ctl,
|
||||
"< 64 ohms", "64-300 ohms", "300-600 ohms"
|
||||
};
|
||||
|
||||
info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
|
||||
info->count = 1;
|
||||
info->value.enumerated.items = 3;
|
||||
if (info->value.enumerated.item > 2)
|
||||
info->value.enumerated.item = 2;
|
||||
strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
|
||||
return 0;
|
||||
return snd_ctl_enum_info(info, 1, 3, names);
|
||||
}
|
||||
|
||||
static int st_hp_volume_offset_get(struct snd_kcontrol *ctl,
|
||||
@ -928,16 +879,25 @@ static int xonar_d2_control_filter(struct snd_kcontrol_new *template)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xonar_st_h6_control_filter(struct snd_kcontrol_new *template)
|
||||
{
|
||||
if (!strncmp(template->name, "Master Playback ", 16))
|
||||
/* no volume/mute, as I²C to the third DAC does not work */
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int add_pcm1796_controls(struct oxygen *chip)
|
||||
{
|
||||
struct xonar_pcm179x *data = chip->model_data;
|
||||
int err;
|
||||
|
||||
err = snd_ctl_add(chip->card, snd_ctl_new1(&rolloff_control, chip));
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = snd_ctl_add(chip->card, snd_ctl_new1(&os_128_control, chip));
|
||||
if (err < 0)
|
||||
return err;
|
||||
if (!data->broken_i2c) {
|
||||
err = snd_ctl_add(chip->card,
|
||||
snd_ctl_new1(&rolloff_control, chip));
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -956,7 +916,15 @@ static int xonar_d2_mixer_init(struct oxygen *chip)
|
||||
|
||||
static int xonar_hdav_mixer_init(struct oxygen *chip)
|
||||
{
|
||||
return add_pcm1796_controls(chip);
|
||||
int err;
|
||||
|
||||
err = snd_ctl_add(chip->card, snd_ctl_new1(&hdav_hdmi_control, chip));
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = add_pcm1796_controls(chip);
|
||||
if (err < 0)
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xonar_st_mixer_init(struct oxygen *chip)
|
||||
@ -976,6 +944,45 @@ static int xonar_st_mixer_init(struct oxygen *chip)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dump_pcm1796_registers(struct oxygen *chip,
|
||||
struct snd_info_buffer *buffer)
|
||||
{
|
||||
struct xonar_pcm179x *data = chip->model_data;
|
||||
unsigned int dac, i;
|
||||
|
||||
for (dac = 0; dac < data->dacs; ++dac) {
|
||||
snd_iprintf(buffer, "\nPCM1796 %u:", dac + 1);
|
||||
for (i = 0; i < 5; ++i)
|
||||
snd_iprintf(buffer, " %02x",
|
||||
data->pcm1796_regs[dac][i]);
|
||||
}
|
||||
snd_iprintf(buffer, "\n");
|
||||
}
|
||||
|
||||
static void dump_cs2000_registers(struct oxygen *chip,
|
||||
struct snd_info_buffer *buffer)
|
||||
{
|
||||
struct xonar_pcm179x *data = chip->model_data;
|
||||
unsigned int i;
|
||||
|
||||
if (data->has_cs2000) {
|
||||
snd_iprintf(buffer, "\nCS2000:\n00: ");
|
||||
for (i = 1; i < 0x10; ++i)
|
||||
snd_iprintf(buffer, " %02x", data->cs2000_regs[i]);
|
||||
snd_iprintf(buffer, "\n10:");
|
||||
for (i = 0x10; i < 0x1f; ++i)
|
||||
snd_iprintf(buffer, " %02x", data->cs2000_regs[i]);
|
||||
snd_iprintf(buffer, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void dump_st_registers(struct oxygen *chip,
|
||||
struct snd_info_buffer *buffer)
|
||||
{
|
||||
dump_pcm1796_registers(chip, buffer);
|
||||
dump_cs2000_registers(chip, buffer);
|
||||
}
|
||||
|
||||
static const struct oxygen_model model_xonar_d2 = {
|
||||
.longname = "Asus Virtuoso 200",
|
||||
.chip = "AV200",
|
||||
@ -985,11 +992,11 @@ static const struct oxygen_model model_xonar_d2 = {
|
||||
.cleanup = xonar_d2_cleanup,
|
||||
.suspend = xonar_d2_suspend,
|
||||
.resume = xonar_d2_resume,
|
||||
.get_i2s_mclk = get_pcm1796_i2s_mclk,
|
||||
.set_dac_params = set_pcm1796_params,
|
||||
.set_adc_params = xonar_set_cs53x1_params,
|
||||
.update_dac_volume = update_pcm1796_volume,
|
||||
.update_dac_mute = update_pcm1796_mute,
|
||||
.dump_registers = dump_pcm1796_registers,
|
||||
.dac_tlv = pcm1796_db_scale,
|
||||
.model_data_size = sizeof(struct xonar_pcm179x),
|
||||
.device_config = PLAYBACK_0_TO_I2S |
|
||||
@ -999,13 +1006,16 @@ static const struct oxygen_model model_xonar_d2 = {
|
||||
MIDI_OUTPUT |
|
||||
MIDI_INPUT |
|
||||
AC97_CD_INPUT,
|
||||
.dac_channels = 8,
|
||||
.dac_channels_pcm = 8,
|
||||
.dac_channels_mixer = 8,
|
||||
.dac_volume_min = 255 - 2*60,
|
||||
.dac_volume_max = 255,
|
||||
.misc_flags = OXYGEN_MISC_MIDI,
|
||||
.function_flags = OXYGEN_FUNCTION_SPI |
|
||||
OXYGEN_FUNCTION_ENABLE_SPI_4_5,
|
||||
.dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
|
||||
.dac_mclks = OXYGEN_MCLKS(512, 128, 128),
|
||||
.adc_mclks = OXYGEN_MCLKS(256, 128, 128),
|
||||
.dac_i2s_format = OXYGEN_I2S_FORMAT_I2S,
|
||||
.adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
|
||||
};
|
||||
|
||||
@ -1018,25 +1028,28 @@ static const struct oxygen_model model_xonar_hdav = {
|
||||
.suspend = xonar_hdav_suspend,
|
||||
.resume = xonar_hdav_resume,
|
||||
.pcm_hardware_filter = xonar_hdmi_pcm_hardware_filter,
|
||||
.get_i2s_mclk = get_pcm1796_i2s_mclk,
|
||||
.set_dac_params = set_hdav_params,
|
||||
.set_adc_params = xonar_set_cs53x1_params,
|
||||
.update_dac_volume = update_pcm1796_volume,
|
||||
.update_dac_mute = update_pcm1796_mute,
|
||||
.uart_input = xonar_hdmi_uart_input,
|
||||
.ac97_switch = xonar_line_mic_ac97_switch,
|
||||
.dump_registers = dump_pcm1796_registers,
|
||||
.dac_tlv = pcm1796_db_scale,
|
||||
.model_data_size = sizeof(struct xonar_hdav),
|
||||
.device_config = PLAYBACK_0_TO_I2S |
|
||||
PLAYBACK_1_TO_SPDIF |
|
||||
CAPTURE_0_FROM_I2S_2 |
|
||||
CAPTURE_1_FROM_SPDIF,
|
||||
.dac_channels = 8,
|
||||
.dac_channels_pcm = 8,
|
||||
.dac_channels_mixer = 2,
|
||||
.dac_volume_min = 255 - 2*60,
|
||||
.dac_volume_max = 255,
|
||||
.misc_flags = OXYGEN_MISC_MIDI,
|
||||
.function_flags = OXYGEN_FUNCTION_2WIRE,
|
||||
.dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
|
||||
.dac_mclks = OXYGEN_MCLKS(512, 128, 128),
|
||||
.adc_mclks = OXYGEN_MCLKS(256, 128, 128),
|
||||
.dac_i2s_format = OXYGEN_I2S_FORMAT_I2S,
|
||||
.adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
|
||||
};
|
||||
|
||||
@ -1048,22 +1061,26 @@ static const struct oxygen_model model_xonar_st = {
|
||||
.cleanup = xonar_st_cleanup,
|
||||
.suspend = xonar_st_suspend,
|
||||
.resume = xonar_st_resume,
|
||||
.get_i2s_mclk = get_pcm1796_i2s_mclk,
|
||||
.set_dac_params = set_st_params,
|
||||
.set_adc_params = xonar_set_cs53x1_params,
|
||||
.update_dac_volume = update_pcm1796_volume,
|
||||
.update_dac_mute = update_pcm1796_mute,
|
||||
.ac97_switch = xonar_line_mic_ac97_switch,
|
||||
.dump_registers = dump_st_registers,
|
||||
.dac_tlv = pcm1796_db_scale,
|
||||
.model_data_size = sizeof(struct xonar_pcm179x),
|
||||
.device_config = PLAYBACK_0_TO_I2S |
|
||||
PLAYBACK_1_TO_SPDIF |
|
||||
CAPTURE_0_FROM_I2S_2,
|
||||
.dac_channels = 2,
|
||||
CAPTURE_0_FROM_I2S_2 |
|
||||
AC97_FMIC_SWITCH,
|
||||
.dac_channels_pcm = 2,
|
||||
.dac_channels_mixer = 2,
|
||||
.dac_volume_min = 255 - 2*60,
|
||||
.dac_volume_max = 255,
|
||||
.function_flags = OXYGEN_FUNCTION_2WIRE,
|
||||
.dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
|
||||
.dac_mclks = OXYGEN_MCLKS(512, 128, 128),
|
||||
.adc_mclks = OXYGEN_MCLKS(256, 128, 128),
|
||||
.dac_i2s_format = OXYGEN_I2S_FORMAT_I2S,
|
||||
.adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
|
||||
};
|
||||
|
||||
@ -1089,7 +1106,8 @@ int __devinit get_xonar_pcm179x_model(struct oxygen *chip,
|
||||
break;
|
||||
case GPIO_DB_H6:
|
||||
chip->model.shortname = "Xonar HDAV1.3+H6";
|
||||
chip->model.private_data = 1;
|
||||
chip->model.dac_channels_mixer = 8;
|
||||
chip->model.dac_mclks = OXYGEN_MCLKS(256, 128, 128);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@ -1102,8 +1120,10 @@ int __devinit get_xonar_pcm179x_model(struct oxygen *chip,
|
||||
break;
|
||||
case GPIO_DB_H6:
|
||||
chip->model.shortname = "Xonar ST+H6";
|
||||
chip->model.dac_channels = 8;
|
||||
chip->model.private_data = 1;
|
||||
chip->model.control_filter = xonar_st_h6_control_filter;
|
||||
chip->model.dac_channels_pcm = 8;
|
||||
chip->model.dac_channels_mixer = 8;
|
||||
chip->model.dac_mclks = OXYGEN_MCLKS(256, 128, 128);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@ -1114,9 +1134,6 @@ 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;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* card driver for models with WM8776/WM8766 DACs (Xonar DS)
|
||||
* card driver for models with WM8776/WM8766 DACs (Xonar DS/HDAV1.3 Slim)
|
||||
*
|
||||
* Copyright (c) Clemens Ladisch <clemens@ladisch.de>
|
||||
*
|
||||
@ -22,26 +22,48 @@
|
||||
*
|
||||
* CMI8788:
|
||||
*
|
||||
* SPI 0 -> WM8766 (surround, center/LFE, back)
|
||||
* SPI 1 -> WM8776 (front, input)
|
||||
* SPI 0 -> WM8766 (surround, center/LFE, back)
|
||||
* SPI 1 -> WM8776 (front, input)
|
||||
*
|
||||
* 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
|
||||
* 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:
|
||||
* WM8776:
|
||||
*
|
||||
* input 1 <- line
|
||||
* input 2 <- mic
|
||||
* input 3 <- front mic
|
||||
* input 4 <- aux
|
||||
* input 1 <- line
|
||||
* input 2 <- mic
|
||||
* input 3 <- front mic
|
||||
* input 4 <- aux
|
||||
*/
|
||||
|
||||
/*
|
||||
* Xonar HDAV1.3 Slim
|
||||
* ------------------
|
||||
*
|
||||
* CMI8788:
|
||||
*
|
||||
* I²C <-> WM8776 (addr 0011010)
|
||||
*
|
||||
* GPIO 0 -> disable HDMI output
|
||||
* GPIO 1 -> enable HP output
|
||||
* GPIO 6 -> firmware EEPROM I²C clock
|
||||
* GPIO 7 <-> firmware EEPROM I²C data
|
||||
*
|
||||
* UART <-> HDMI controller
|
||||
*
|
||||
* WM8776:
|
||||
*
|
||||
* input 1 <- mic
|
||||
* input 2 <- aux
|
||||
*/
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include <linux/delay.h>
|
||||
#include <sound/control.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/info.h>
|
||||
#include <sound/jack.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
@ -55,6 +77,13 @@
|
||||
#define GPIO_DS_OUTPUT_FRONTLR 0x0080
|
||||
#define GPIO_DS_OUTPUT_ENABLE 0x0100
|
||||
|
||||
#define GPIO_SLIM_HDMI_DISABLE 0x0001
|
||||
#define GPIO_SLIM_OUTPUT_ENABLE 0x0002
|
||||
#define GPIO_SLIM_FIRMWARE_CLK 0x0040
|
||||
#define GPIO_SLIM_FIRMWARE_DATA 0x0080
|
||||
|
||||
#define I2C_DEVICE_WM8776 0x34 /* 001101, 0, /W=0 */
|
||||
|
||||
#define LC_CONTROL_LIMITER 0x40000000
|
||||
#define LC_CONTROL_ALC 0x20000000
|
||||
|
||||
@ -66,19 +95,37 @@ struct xonar_wm87x6 {
|
||||
struct snd_kcontrol *mic_adcmux_control;
|
||||
struct snd_kcontrol *lc_controls[13];
|
||||
struct snd_jack *hp_jack;
|
||||
struct xonar_hdmi hdmi;
|
||||
};
|
||||
|
||||
static void wm8776_write(struct oxygen *chip,
|
||||
unsigned int reg, unsigned int value)
|
||||
static void wm8776_write_spi(struct oxygen *chip,
|
||||
unsigned int reg, unsigned int value)
|
||||
{
|
||||
struct xonar_wm87x6 *data = chip->model_data;
|
||||
|
||||
oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
|
||||
OXYGEN_SPI_DATA_LENGTH_2 |
|
||||
OXYGEN_SPI_CLOCK_160 |
|
||||
(1 << OXYGEN_SPI_CODEC_SHIFT) |
|
||||
OXYGEN_SPI_CEN_LATCH_CLOCK_LO,
|
||||
(reg << 9) | value);
|
||||
}
|
||||
|
||||
static void wm8776_write_i2c(struct oxygen *chip,
|
||||
unsigned int reg, unsigned int value)
|
||||
{
|
||||
oxygen_write_i2c(chip, I2C_DEVICE_WM8776,
|
||||
(reg << 1) | (value >> 8), value);
|
||||
}
|
||||
|
||||
static void wm8776_write(struct oxygen *chip,
|
||||
unsigned int reg, unsigned int value)
|
||||
{
|
||||
struct xonar_wm87x6 *data = chip->model_data;
|
||||
|
||||
if ((chip->model.function_flags & OXYGEN_FUNCTION_2WIRE_SPI_MASK) ==
|
||||
OXYGEN_FUNCTION_SPI)
|
||||
wm8776_write_spi(chip, reg, value);
|
||||
else
|
||||
wm8776_write_i2c(chip, reg, value);
|
||||
if (reg < ARRAY_SIZE(data->wm8776_regs)) {
|
||||
if (reg >= WM8776_HPLVOL && reg <= WM8776_DACMASTER)
|
||||
value &= ~WM8776_UPDATE;
|
||||
@ -245,17 +292,50 @@ static void xonar_ds_init(struct oxygen *chip)
|
||||
snd_component_add(chip->card, "WM8766");
|
||||
}
|
||||
|
||||
static void xonar_hdav_slim_init(struct oxygen *chip)
|
||||
{
|
||||
struct xonar_wm87x6 *data = chip->model_data;
|
||||
|
||||
data->generic.anti_pop_delay = 300;
|
||||
data->generic.output_enable_bit = GPIO_SLIM_OUTPUT_ENABLE;
|
||||
|
||||
wm8776_init(chip);
|
||||
|
||||
oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
|
||||
GPIO_SLIM_HDMI_DISABLE |
|
||||
GPIO_SLIM_FIRMWARE_CLK |
|
||||
GPIO_SLIM_FIRMWARE_DATA);
|
||||
|
||||
xonar_hdmi_init(chip, &data->hdmi);
|
||||
xonar_enable_output(chip);
|
||||
|
||||
snd_component_add(chip->card, "WM8776");
|
||||
}
|
||||
|
||||
static void xonar_ds_cleanup(struct oxygen *chip)
|
||||
{
|
||||
xonar_disable_output(chip);
|
||||
wm8776_write(chip, WM8776_RESET, 0);
|
||||
}
|
||||
|
||||
static void xonar_hdav_slim_cleanup(struct oxygen *chip)
|
||||
{
|
||||
xonar_hdmi_cleanup(chip);
|
||||
xonar_disable_output(chip);
|
||||
wm8776_write(chip, WM8776_RESET, 0);
|
||||
msleep(2);
|
||||
}
|
||||
|
||||
static void xonar_ds_suspend(struct oxygen *chip)
|
||||
{
|
||||
xonar_ds_cleanup(chip);
|
||||
}
|
||||
|
||||
static void xonar_hdav_slim_suspend(struct oxygen *chip)
|
||||
{
|
||||
xonar_hdav_slim_cleanup(chip);
|
||||
}
|
||||
|
||||
static void xonar_ds_resume(struct oxygen *chip)
|
||||
{
|
||||
wm8776_registers_init(chip);
|
||||
@ -264,6 +344,15 @@ static void xonar_ds_resume(struct oxygen *chip)
|
||||
xonar_ds_handle_hp_jack(chip);
|
||||
}
|
||||
|
||||
static void xonar_hdav_slim_resume(struct oxygen *chip)
|
||||
{
|
||||
struct xonar_wm87x6 *data = chip->model_data;
|
||||
|
||||
wm8776_registers_init(chip);
|
||||
xonar_hdmi_resume(chip, &data->hdmi);
|
||||
xonar_enable_output(chip);
|
||||
}
|
||||
|
||||
static void wm8776_adc_hardware_filter(unsigned int channel,
|
||||
struct snd_pcm_hardware *hardware)
|
||||
{
|
||||
@ -278,6 +367,13 @@ static void wm8776_adc_hardware_filter(unsigned int channel,
|
||||
}
|
||||
}
|
||||
|
||||
static void xonar_hdav_slim_hardware_filter(unsigned int channel,
|
||||
struct snd_pcm_hardware *hardware)
|
||||
{
|
||||
wm8776_adc_hardware_filter(channel, hardware);
|
||||
xonar_hdmi_pcm_hardware_filter(channel, hardware);
|
||||
}
|
||||
|
||||
static void set_wm87x6_dac_params(struct oxygen *chip,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
@ -294,6 +390,14 @@ static void set_wm8776_adc_params(struct oxygen *chip,
|
||||
wm8776_write_cached(chip, WM8776_MSTRCTRL, reg);
|
||||
}
|
||||
|
||||
static void set_hdav_slim_dac_params(struct oxygen *chip,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct xonar_wm87x6 *data = chip->model_data;
|
||||
|
||||
xonar_set_hdmi_params(chip, &data->hdmi, params);
|
||||
}
|
||||
|
||||
static void update_wm8776_volume(struct oxygen *chip)
|
||||
{
|
||||
struct xonar_wm87x6 *data = chip->model_data;
|
||||
@ -473,11 +577,6 @@ static int wm8776_field_enum_info(struct snd_kcontrol *ctl,
|
||||
const char *const *names;
|
||||
|
||||
max = (ctl->private_value >> 12) & 0xf;
|
||||
info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
|
||||
info->count = 1;
|
||||
info->value.enumerated.items = max + 1;
|
||||
if (info->value.enumerated.item > max)
|
||||
info->value.enumerated.item = max;
|
||||
switch ((ctl->private_value >> 24) & 0x1f) {
|
||||
case WM8776_ALCCTRL2:
|
||||
names = hld;
|
||||
@ -501,8 +600,7 @@ static int wm8776_field_enum_info(struct snd_kcontrol *ctl,
|
||||
default:
|
||||
return -ENXIO;
|
||||
}
|
||||
strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
|
||||
return 0;
|
||||
return snd_ctl_enum_info(info, 1, max + 1, names);
|
||||
}
|
||||
|
||||
static int wm8776_field_volume_info(struct snd_kcontrol *ctl,
|
||||
@ -759,13 +857,8 @@ static int wm8776_level_control_info(struct snd_kcontrol *ctl,
|
||||
static const char *const names[3] = {
|
||||
"None", "Peak Limiter", "Automatic Level Control"
|
||||
};
|
||||
info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
|
||||
info->count = 1;
|
||||
info->value.enumerated.items = 3;
|
||||
if (info->value.enumerated.item >= 3)
|
||||
info->value.enumerated.item = 2;
|
||||
strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
|
||||
return 0;
|
||||
|
||||
return snd_ctl_enum_info(info, 1, 3, names);
|
||||
}
|
||||
|
||||
static int wm8776_level_control_get(struct snd_kcontrol *ctl,
|
||||
@ -851,13 +944,7 @@ static int hpf_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info)
|
||||
"None", "High-pass Filter"
|
||||
};
|
||||
|
||||
info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
|
||||
info->count = 1;
|
||||
info->value.enumerated.items = 2;
|
||||
if (info->value.enumerated.item >= 2)
|
||||
info->value.enumerated.item = 1;
|
||||
strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
|
||||
return 0;
|
||||
return snd_ctl_enum_info(info, 1, 2, names);
|
||||
}
|
||||
|
||||
static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
|
||||
@ -985,6 +1072,53 @@ static const struct snd_kcontrol_new ds_controls[] = {
|
||||
.private_value = 0,
|
||||
},
|
||||
};
|
||||
static const struct snd_kcontrol_new hdav_slim_controls[] = {
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "HDMI Playback Switch",
|
||||
.info = snd_ctl_boolean_mono_info,
|
||||
.get = xonar_gpio_bit_switch_get,
|
||||
.put = xonar_gpio_bit_switch_put,
|
||||
.private_value = GPIO_SLIM_HDMI_DISABLE | XONAR_GPIO_BIT_INVERT,
|
||||
},
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Headphone Playback Volume",
|
||||
.info = wm8776_hp_vol_info,
|
||||
.get = wm8776_hp_vol_get,
|
||||
.put = wm8776_hp_vol_put,
|
||||
.tlv = { .p = wm8776_hp_db_scale },
|
||||
},
|
||||
WM8776_BIT_SWITCH("Headphone Playback Switch",
|
||||
WM8776_PWRDOWN, WM8776_HPPD, 1, 0),
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Input Capture Volume",
|
||||
.info = wm8776_input_vol_info,
|
||||
.get = wm8776_input_vol_get,
|
||||
.put = wm8776_input_vol_put,
|
||||
.tlv = { .p = wm8776_adc_db_scale },
|
||||
},
|
||||
WM8776_BIT_SWITCH("Mic Capture Switch",
|
||||
WM8776_ADCMUX, 1 << 0, 0, 0),
|
||||
WM8776_BIT_SWITCH("Aux Capture Switch",
|
||||
WM8776_ADCMUX, 1 << 1, 0, 0),
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "ADC Filter Capture Enum",
|
||||
.info = hpf_info,
|
||||
.get = hpf_get,
|
||||
.put = hpf_put,
|
||||
},
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Level Control Capture Enum",
|
||||
.info = wm8776_level_control_info,
|
||||
.get = wm8776_level_control_get,
|
||||
.put = wm8776_level_control_put,
|
||||
.private_value = 0,
|
||||
},
|
||||
};
|
||||
static const struct snd_kcontrol_new lc_controls[] = {
|
||||
WM8776_FIELD_CTL_VOLUME("Limiter Threshold",
|
||||
WM8776_ALCCTRL1, 0, 11, 0, 15, 0xf,
|
||||
@ -1028,6 +1162,26 @@ static const struct snd_kcontrol_new lc_controls[] = {
|
||||
LC_CONTROL_ALC, wm8776_ngth_db_scale),
|
||||
};
|
||||
|
||||
static int add_lc_controls(struct oxygen *chip)
|
||||
{
|
||||
struct xonar_wm87x6 *data = chip->model_data;
|
||||
unsigned int i;
|
||||
struct snd_kcontrol *ctl;
|
||||
int err;
|
||||
|
||||
BUILD_BUG_ON(ARRAY_SIZE(lc_controls) != ARRAY_SIZE(data->lc_controls));
|
||||
for (i = 0; i < ARRAY_SIZE(lc_controls); ++i) {
|
||||
ctl = snd_ctl_new1(&lc_controls[i], chip);
|
||||
if (!ctl)
|
||||
return -ENOMEM;
|
||||
err = snd_ctl_add(chip->card, ctl);
|
||||
if (err < 0)
|
||||
return err;
|
||||
data->lc_controls[i] = ctl;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xonar_ds_mixer_init(struct oxygen *chip)
|
||||
{
|
||||
struct xonar_wm87x6 *data = chip->model_data;
|
||||
@ -1049,17 +1203,54 @@ static int xonar_ds_mixer_init(struct oxygen *chip)
|
||||
}
|
||||
if (!data->line_adcmux_control || !data->mic_adcmux_control)
|
||||
return -ENXIO;
|
||||
BUILD_BUG_ON(ARRAY_SIZE(lc_controls) != ARRAY_SIZE(data->lc_controls));
|
||||
for (i = 0; i < ARRAY_SIZE(lc_controls); ++i) {
|
||||
ctl = snd_ctl_new1(&lc_controls[i], chip);
|
||||
|
||||
return add_lc_controls(chip);
|
||||
}
|
||||
|
||||
static int xonar_hdav_slim_mixer_init(struct oxygen *chip)
|
||||
{
|
||||
unsigned int i;
|
||||
struct snd_kcontrol *ctl;
|
||||
int err;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(hdav_slim_controls); ++i) {
|
||||
ctl = snd_ctl_new1(&hdav_slim_controls[i], chip);
|
||||
if (!ctl)
|
||||
return -ENOMEM;
|
||||
err = snd_ctl_add(chip->card, ctl);
|
||||
if (err < 0)
|
||||
return err;
|
||||
data->lc_controls[i] = ctl;
|
||||
}
|
||||
return 0;
|
||||
|
||||
return add_lc_controls(chip);
|
||||
}
|
||||
|
||||
static void dump_wm8776_registers(struct oxygen *chip,
|
||||
struct snd_info_buffer *buffer)
|
||||
{
|
||||
struct xonar_wm87x6 *data = chip->model_data;
|
||||
unsigned int i;
|
||||
|
||||
snd_iprintf(buffer, "\nWM8776:\n00:");
|
||||
for (i = 0; i < 0x10; ++i)
|
||||
snd_iprintf(buffer, " %03x", data->wm8776_regs[i]);
|
||||
snd_iprintf(buffer, "\n10:");
|
||||
for (i = 0x10; i < 0x17; ++i)
|
||||
snd_iprintf(buffer, " %03x", data->wm8776_regs[i]);
|
||||
snd_iprintf(buffer, "\n");
|
||||
}
|
||||
|
||||
static void dump_wm87x6_registers(struct oxygen *chip,
|
||||
struct snd_info_buffer *buffer)
|
||||
{
|
||||
struct xonar_wm87x6 *data = chip->model_data;
|
||||
unsigned int i;
|
||||
|
||||
dump_wm8776_registers(chip, buffer);
|
||||
snd_iprintf(buffer, "\nWM8766:\n00:");
|
||||
for (i = 0; i < 0x10; ++i)
|
||||
snd_iprintf(buffer, " %03x", data->wm8766_regs[i]);
|
||||
snd_iprintf(buffer, "\n");
|
||||
}
|
||||
|
||||
static const struct oxygen_model model_xonar_ds = {
|
||||
@ -1072,22 +1263,57 @@ static const struct oxygen_model model_xonar_ds = {
|
||||
.suspend = xonar_ds_suspend,
|
||||
.resume = xonar_ds_resume,
|
||||
.pcm_hardware_filter = wm8776_adc_hardware_filter,
|
||||
.get_i2s_mclk = oxygen_default_i2s_mclk,
|
||||
.set_dac_params = set_wm87x6_dac_params,
|
||||
.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,
|
||||
.dump_registers = dump_wm87x6_registers,
|
||||
.dac_tlv = wm87x6_dac_db_scale,
|
||||
.model_data_size = sizeof(struct xonar_wm87x6),
|
||||
.device_config = PLAYBACK_0_TO_I2S |
|
||||
PLAYBACK_1_TO_SPDIF |
|
||||
CAPTURE_0_FROM_I2S_1,
|
||||
.dac_channels = 8,
|
||||
.dac_channels_pcm = 8,
|
||||
.dac_channels_mixer = 8,
|
||||
.dac_volume_min = 255 - 2*60,
|
||||
.dac_volume_max = 255,
|
||||
.function_flags = OXYGEN_FUNCTION_SPI,
|
||||
.dac_mclks = OXYGEN_MCLKS(256, 256, 128),
|
||||
.adc_mclks = OXYGEN_MCLKS(256, 256, 128),
|
||||
.dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
|
||||
.adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
|
||||
};
|
||||
|
||||
static const struct oxygen_model model_xonar_hdav_slim = {
|
||||
.shortname = "Xonar HDAV1.3 Slim",
|
||||
.longname = "Asus Virtuoso 200",
|
||||
.chip = "AV200",
|
||||
.init = xonar_hdav_slim_init,
|
||||
.mixer_init = xonar_hdav_slim_mixer_init,
|
||||
.cleanup = xonar_hdav_slim_cleanup,
|
||||
.suspend = xonar_hdav_slim_suspend,
|
||||
.resume = xonar_hdav_slim_resume,
|
||||
.pcm_hardware_filter = xonar_hdav_slim_hardware_filter,
|
||||
.set_dac_params = set_hdav_slim_dac_params,
|
||||
.set_adc_params = set_wm8776_adc_params,
|
||||
.update_dac_volume = update_wm8776_volume,
|
||||
.update_dac_mute = update_wm8776_mute,
|
||||
.uart_input = xonar_hdmi_uart_input,
|
||||
.dump_registers = dump_wm8776_registers,
|
||||
.dac_tlv = wm87x6_dac_db_scale,
|
||||
.model_data_size = sizeof(struct xonar_wm87x6),
|
||||
.device_config = PLAYBACK_0_TO_I2S |
|
||||
PLAYBACK_1_TO_SPDIF |
|
||||
CAPTURE_0_FROM_I2S_1,
|
||||
.dac_channels_pcm = 8,
|
||||
.dac_channels_mixer = 2,
|
||||
.dac_volume_min = 255 - 2*60,
|
||||
.dac_volume_max = 255,
|
||||
.function_flags = OXYGEN_FUNCTION_2WIRE,
|
||||
.dac_mclks = OXYGEN_MCLKS(256, 256, 128),
|
||||
.adc_mclks = OXYGEN_MCLKS(256, 256, 128),
|
||||
.dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
|
||||
.adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
|
||||
};
|
||||
@ -1099,6 +1325,9 @@ int __devinit get_xonar_wm87x6_model(struct oxygen *chip,
|
||||
case 0x838e:
|
||||
chip->model = model_xonar_ds;
|
||||
break;
|
||||
case 0x835e:
|
||||
chip->model = model_xonar_hdav_slim;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -60,6 +60,7 @@ MODULE_SUPPORTED_DEVICE("{{RME Hammerfall-DSP},"
|
||||
"{RME HDSP-9652},"
|
||||
"{RME HDSP-9632}}");
|
||||
#ifdef HDSP_FW_LOADER
|
||||
MODULE_FIRMWARE("rpm_firmware.bin");
|
||||
MODULE_FIRMWARE("multiface_firmware.bin");
|
||||
MODULE_FIRMWARE("multiface_firmware_rev11.bin");
|
||||
MODULE_FIRMWARE("digiface_firmware.bin");
|
||||
@ -81,6 +82,7 @@ MODULE_FIRMWARE("digiface_firmware_rev11.bin");
|
||||
#define H9632_SS_CHANNELS 12
|
||||
#define H9632_DS_CHANNELS 8
|
||||
#define H9632_QS_CHANNELS 4
|
||||
#define RPM_CHANNELS 6
|
||||
|
||||
/* Write registers. These are defined as byte-offsets from the iobase value.
|
||||
*/
|
||||
@ -191,6 +193,25 @@ MODULE_FIRMWARE("digiface_firmware_rev11.bin");
|
||||
#define HDSP_PhoneGain1 (1<<30)
|
||||
#define HDSP_QuadSpeed (1<<31)
|
||||
|
||||
/* RPM uses some of the registers for special purposes */
|
||||
#define HDSP_RPM_Inp12 0x04A00
|
||||
#define HDSP_RPM_Inp12_Phon_6dB 0x00800 /* Dolby */
|
||||
#define HDSP_RPM_Inp12_Phon_0dB 0x00000 /* .. */
|
||||
#define HDSP_RPM_Inp12_Phon_n6dB 0x04000 /* inp_0 */
|
||||
#define HDSP_RPM_Inp12_Line_0dB 0x04200 /* Dolby+PRO */
|
||||
#define HDSP_RPM_Inp12_Line_n6dB 0x00200 /* PRO */
|
||||
|
||||
#define HDSP_RPM_Inp34 0x32000
|
||||
#define HDSP_RPM_Inp34_Phon_6dB 0x20000 /* SyncRef1 */
|
||||
#define HDSP_RPM_Inp34_Phon_0dB 0x00000 /* .. */
|
||||
#define HDSP_RPM_Inp34_Phon_n6dB 0x02000 /* SyncRef2 */
|
||||
#define HDSP_RPM_Inp34_Line_0dB 0x30000 /* SyncRef1+SyncRef0 */
|
||||
#define HDSP_RPM_Inp34_Line_n6dB 0x10000 /* SyncRef0 */
|
||||
|
||||
#define HDSP_RPM_Bypass 0x01000
|
||||
|
||||
#define HDSP_RPM_Disconnect 0x00001
|
||||
|
||||
#define HDSP_ADGainMask (HDSP_ADGain0|HDSP_ADGain1)
|
||||
#define HDSP_ADGainMinus10dBV HDSP_ADGainMask
|
||||
#define HDSP_ADGainPlus4dBu (HDSP_ADGain0)
|
||||
@ -450,7 +471,7 @@ struct hdsp {
|
||||
u32 creg_spdif;
|
||||
u32 creg_spdif_stream;
|
||||
int clock_source_locked;
|
||||
char *card_name; /* digiface/multiface */
|
||||
char *card_name; /* digiface/multiface/rpm */
|
||||
enum HDSP_IO_Type io_type; /* ditto, but for code use */
|
||||
unsigned short firmware_rev;
|
||||
unsigned short state; /* stores state bits */
|
||||
@ -612,6 +633,7 @@ static int hdsp_playback_to_output_key (struct hdsp *hdsp, int in, int out)
|
||||
switch (hdsp->io_type) {
|
||||
case Multiface:
|
||||
case Digiface:
|
||||
case RPM:
|
||||
default:
|
||||
if (hdsp->firmware_rev == 0xa)
|
||||
return (64 * out) + (32 + (in));
|
||||
@ -629,6 +651,7 @@ static int hdsp_input_to_output_key (struct hdsp *hdsp, int in, int out)
|
||||
switch (hdsp->io_type) {
|
||||
case Multiface:
|
||||
case Digiface:
|
||||
case RPM:
|
||||
default:
|
||||
if (hdsp->firmware_rev == 0xa)
|
||||
return (64 * out) + in;
|
||||
@ -655,7 +678,7 @@ static int hdsp_check_for_iobox (struct hdsp *hdsp)
|
||||
{
|
||||
if (hdsp->io_type == H9652 || hdsp->io_type == H9632) return 0;
|
||||
if (hdsp_read (hdsp, HDSP_statusRegister) & HDSP_ConfigError) {
|
||||
snd_printk ("Hammerfall-DSP: no Digiface or Multiface connected!\n");
|
||||
snd_printk("Hammerfall-DSP: no IO box connected!\n");
|
||||
hdsp->state &= ~HDSP_FirmwareLoaded;
|
||||
return -EIO;
|
||||
}
|
||||
@ -680,7 +703,7 @@ static int hdsp_wait_for_iobox(struct hdsp *hdsp, unsigned int loops,
|
||||
}
|
||||
}
|
||||
|
||||
snd_printk("Hammerfall-DSP: no Digiface or Multiface connected!\n");
|
||||
snd_printk("Hammerfall-DSP: no IO box connected!\n");
|
||||
hdsp->state &= ~HDSP_FirmwareLoaded;
|
||||
return -EIO;
|
||||
}
|
||||
@ -752,17 +775,21 @@ static int hdsp_get_iobox_version (struct hdsp *hdsp)
|
||||
hdsp_write (hdsp, HDSP_control2Reg, HDSP_S_LOAD);
|
||||
hdsp_write (hdsp, HDSP_fifoData, 0);
|
||||
|
||||
if (hdsp_fifo_wait (hdsp, 0, HDSP_SHORT_WAIT)) {
|
||||
hdsp->io_type = Multiface;
|
||||
hdsp_write (hdsp, HDSP_control2Reg, HDSP_VERSION_BIT);
|
||||
hdsp_write (hdsp, HDSP_control2Reg, HDSP_S_LOAD);
|
||||
hdsp_fifo_wait (hdsp, 0, HDSP_SHORT_WAIT);
|
||||
if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT)) {
|
||||
hdsp_write(hdsp, HDSP_control2Reg, HDSP_VERSION_BIT);
|
||||
hdsp_write(hdsp, HDSP_control2Reg, HDSP_S_LOAD);
|
||||
if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT))
|
||||
hdsp->io_type = RPM;
|
||||
else
|
||||
hdsp->io_type = Multiface;
|
||||
} else {
|
||||
hdsp->io_type = Digiface;
|
||||
}
|
||||
} else {
|
||||
/* firmware was already loaded, get iobox type */
|
||||
if (hdsp_read(hdsp, HDSP_status2Register) & HDSP_version1)
|
||||
if (hdsp_read(hdsp, HDSP_status2Register) & HDSP_version2)
|
||||
hdsp->io_type = RPM;
|
||||
else if (hdsp_read(hdsp, HDSP_status2Register) & HDSP_version1)
|
||||
hdsp->io_type = Multiface;
|
||||
else
|
||||
hdsp->io_type = Digiface;
|
||||
@ -1184,6 +1211,7 @@ static int hdsp_set_rate(struct hdsp *hdsp, int rate, int called_internally)
|
||||
hdsp->channel_map = channel_map_ds;
|
||||
} else {
|
||||
switch (hdsp->io_type) {
|
||||
case RPM:
|
||||
case Multiface:
|
||||
hdsp->channel_map = channel_map_mf_ss;
|
||||
break;
|
||||
@ -3231,6 +3259,318 @@ HDSP_PRECISE_POINTER("Precise Pointer", 0),
|
||||
HDSP_USE_MIDI_TASKLET("Use Midi Tasklet", 0),
|
||||
};
|
||||
|
||||
|
||||
static int hdsp_rpm_input12(struct hdsp *hdsp)
|
||||
{
|
||||
switch (hdsp->control_register & HDSP_RPM_Inp12) {
|
||||
case HDSP_RPM_Inp12_Phon_6dB:
|
||||
return 0;
|
||||
case HDSP_RPM_Inp12_Phon_n6dB:
|
||||
return 2;
|
||||
case HDSP_RPM_Inp12_Line_0dB:
|
||||
return 3;
|
||||
case HDSP_RPM_Inp12_Line_n6dB:
|
||||
return 4;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int snd_hdsp_get_rpm_input12(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
|
||||
|
||||
ucontrol->value.enumerated.item[0] = hdsp_rpm_input12(hdsp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int hdsp_set_rpm_input12(struct hdsp *hdsp, int mode)
|
||||
{
|
||||
hdsp->control_register &= ~HDSP_RPM_Inp12;
|
||||
switch (mode) {
|
||||
case 0:
|
||||
hdsp->control_register |= HDSP_RPM_Inp12_Phon_6dB;
|
||||
break;
|
||||
case 1:
|
||||
break;
|
||||
case 2:
|
||||
hdsp->control_register |= HDSP_RPM_Inp12_Phon_n6dB;
|
||||
break;
|
||||
case 3:
|
||||
hdsp->control_register |= HDSP_RPM_Inp12_Line_0dB;
|
||||
break;
|
||||
case 4:
|
||||
hdsp->control_register |= HDSP_RPM_Inp12_Line_n6dB;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int snd_hdsp_put_rpm_input12(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
|
||||
int change;
|
||||
int val;
|
||||
|
||||
if (!snd_hdsp_use_is_exclusive(hdsp))
|
||||
return -EBUSY;
|
||||
val = ucontrol->value.enumerated.item[0];
|
||||
if (val < 0)
|
||||
val = 0;
|
||||
if (val > 4)
|
||||
val = 4;
|
||||
spin_lock_irq(&hdsp->lock);
|
||||
if (val != hdsp_rpm_input12(hdsp))
|
||||
change = (hdsp_set_rpm_input12(hdsp, val) == 0) ? 1 : 0;
|
||||
else
|
||||
change = 0;
|
||||
spin_unlock_irq(&hdsp->lock);
|
||||
return change;
|
||||
}
|
||||
|
||||
|
||||
static int snd_hdsp_info_rpm_input(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
static char *texts[] = {"Phono +6dB", "Phono 0dB", "Phono -6dB", "Line 0dB", "Line -6dB"};
|
||||
|
||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
|
||||
uinfo->count = 1;
|
||||
uinfo->value.enumerated.items = 5;
|
||||
if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
|
||||
uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
|
||||
strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int hdsp_rpm_input34(struct hdsp *hdsp)
|
||||
{
|
||||
switch (hdsp->control_register & HDSP_RPM_Inp34) {
|
||||
case HDSP_RPM_Inp34_Phon_6dB:
|
||||
return 0;
|
||||
case HDSP_RPM_Inp34_Phon_n6dB:
|
||||
return 2;
|
||||
case HDSP_RPM_Inp34_Line_0dB:
|
||||
return 3;
|
||||
case HDSP_RPM_Inp34_Line_n6dB:
|
||||
return 4;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int snd_hdsp_get_rpm_input34(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
|
||||
|
||||
ucontrol->value.enumerated.item[0] = hdsp_rpm_input34(hdsp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int hdsp_set_rpm_input34(struct hdsp *hdsp, int mode)
|
||||
{
|
||||
hdsp->control_register &= ~HDSP_RPM_Inp34;
|
||||
switch (mode) {
|
||||
case 0:
|
||||
hdsp->control_register |= HDSP_RPM_Inp34_Phon_6dB;
|
||||
break;
|
||||
case 1:
|
||||
break;
|
||||
case 2:
|
||||
hdsp->control_register |= HDSP_RPM_Inp34_Phon_n6dB;
|
||||
break;
|
||||
case 3:
|
||||
hdsp->control_register |= HDSP_RPM_Inp34_Line_0dB;
|
||||
break;
|
||||
case 4:
|
||||
hdsp->control_register |= HDSP_RPM_Inp34_Line_n6dB;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int snd_hdsp_put_rpm_input34(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
|
||||
int change;
|
||||
int val;
|
||||
|
||||
if (!snd_hdsp_use_is_exclusive(hdsp))
|
||||
return -EBUSY;
|
||||
val = ucontrol->value.enumerated.item[0];
|
||||
if (val < 0)
|
||||
val = 0;
|
||||
if (val > 4)
|
||||
val = 4;
|
||||
spin_lock_irq(&hdsp->lock);
|
||||
if (val != hdsp_rpm_input34(hdsp))
|
||||
change = (hdsp_set_rpm_input34(hdsp, val) == 0) ? 1 : 0;
|
||||
else
|
||||
change = 0;
|
||||
spin_unlock_irq(&hdsp->lock);
|
||||
return change;
|
||||
}
|
||||
|
||||
|
||||
/* RPM Bypass switch */
|
||||
static int hdsp_rpm_bypass(struct hdsp *hdsp)
|
||||
{
|
||||
return (hdsp->control_register & HDSP_RPM_Bypass) ? 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
static int snd_hdsp_get_rpm_bypass(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
|
||||
|
||||
ucontrol->value.integer.value[0] = hdsp_rpm_bypass(hdsp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int hdsp_set_rpm_bypass(struct hdsp *hdsp, int on)
|
||||
{
|
||||
if (on)
|
||||
hdsp->control_register |= HDSP_RPM_Bypass;
|
||||
else
|
||||
hdsp->control_register &= ~HDSP_RPM_Bypass;
|
||||
hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int snd_hdsp_put_rpm_bypass(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
|
||||
int change;
|
||||
unsigned int val;
|
||||
|
||||
if (!snd_hdsp_use_is_exclusive(hdsp))
|
||||
return -EBUSY;
|
||||
val = ucontrol->value.integer.value[0] & 1;
|
||||
spin_lock_irq(&hdsp->lock);
|
||||
change = (int)val != hdsp_rpm_bypass(hdsp);
|
||||
hdsp_set_rpm_bypass(hdsp, val);
|
||||
spin_unlock_irq(&hdsp->lock);
|
||||
return change;
|
||||
}
|
||||
|
||||
|
||||
static int snd_hdsp_info_rpm_bypass(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
static char *texts[] = {"On", "Off"};
|
||||
|
||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
|
||||
uinfo->count = 1;
|
||||
uinfo->value.enumerated.items = 2;
|
||||
if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
|
||||
uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
|
||||
strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* RPM Disconnect switch */
|
||||
static int hdsp_rpm_disconnect(struct hdsp *hdsp)
|
||||
{
|
||||
return (hdsp->control_register & HDSP_RPM_Disconnect) ? 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
static int snd_hdsp_get_rpm_disconnect(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
|
||||
|
||||
ucontrol->value.integer.value[0] = hdsp_rpm_disconnect(hdsp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int hdsp_set_rpm_disconnect(struct hdsp *hdsp, int on)
|
||||
{
|
||||
if (on)
|
||||
hdsp->control_register |= HDSP_RPM_Disconnect;
|
||||
else
|
||||
hdsp->control_register &= ~HDSP_RPM_Disconnect;
|
||||
hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int snd_hdsp_put_rpm_disconnect(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
|
||||
int change;
|
||||
unsigned int val;
|
||||
|
||||
if (!snd_hdsp_use_is_exclusive(hdsp))
|
||||
return -EBUSY;
|
||||
val = ucontrol->value.integer.value[0] & 1;
|
||||
spin_lock_irq(&hdsp->lock);
|
||||
change = (int)val != hdsp_rpm_disconnect(hdsp);
|
||||
hdsp_set_rpm_disconnect(hdsp, val);
|
||||
spin_unlock_irq(&hdsp->lock);
|
||||
return change;
|
||||
}
|
||||
|
||||
static int snd_hdsp_info_rpm_disconnect(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
static char *texts[] = {"On", "Off"};
|
||||
|
||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
|
||||
uinfo->count = 1;
|
||||
uinfo->value.enumerated.items = 2;
|
||||
if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
|
||||
uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
|
||||
strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_kcontrol_new snd_hdsp_rpm_controls[] = {
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "RPM Bypass",
|
||||
.get = snd_hdsp_get_rpm_bypass,
|
||||
.put = snd_hdsp_put_rpm_bypass,
|
||||
.info = snd_hdsp_info_rpm_bypass
|
||||
},
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "RPM Disconnect",
|
||||
.get = snd_hdsp_get_rpm_disconnect,
|
||||
.put = snd_hdsp_put_rpm_disconnect,
|
||||
.info = snd_hdsp_info_rpm_disconnect
|
||||
},
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Input 1/2",
|
||||
.get = snd_hdsp_get_rpm_input12,
|
||||
.put = snd_hdsp_put_rpm_input12,
|
||||
.info = snd_hdsp_info_rpm_input
|
||||
},
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Input 3/4",
|
||||
.get = snd_hdsp_get_rpm_input34,
|
||||
.put = snd_hdsp_put_rpm_input34,
|
||||
.info = snd_hdsp_info_rpm_input
|
||||
},
|
||||
HDSP_SYSTEM_SAMPLE_RATE("System Sample Rate", 0),
|
||||
HDSP_MIXER("Mixer", 0)
|
||||
};
|
||||
|
||||
static struct snd_kcontrol_new snd_hdsp_96xx_aeb = HDSP_AEB("Analog Extension Board", 0);
|
||||
static struct snd_kcontrol_new snd_hdsp_adat_sync_check = HDSP_ADAT_SYNC_CHECK;
|
||||
|
||||
@ -3240,6 +3580,16 @@ static int snd_hdsp_create_controls(struct snd_card *card, struct hdsp *hdsp)
|
||||
int err;
|
||||
struct snd_kcontrol *kctl;
|
||||
|
||||
if (hdsp->io_type == RPM) {
|
||||
/* RPM Bypass, Disconnect and Input switches */
|
||||
for (idx = 0; idx < ARRAY_SIZE(snd_hdsp_rpm_controls); idx++) {
|
||||
err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_hdsp_rpm_controls[idx], hdsp));
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (idx = 0; idx < ARRAY_SIZE(snd_hdsp_controls); idx++) {
|
||||
if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_hdsp_controls[idx], hdsp))) < 0)
|
||||
return err;
|
||||
@ -3459,48 +3809,102 @@ snd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
|
||||
|
||||
snd_iprintf(buffer, "\n");
|
||||
|
||||
switch (hdsp_spdif_in(hdsp)) {
|
||||
case HDSP_SPDIFIN_OPTICAL:
|
||||
snd_iprintf(buffer, "IEC958 input: Optical\n");
|
||||
break;
|
||||
case HDSP_SPDIFIN_COAXIAL:
|
||||
snd_iprintf(buffer, "IEC958 input: Coaxial\n");
|
||||
break;
|
||||
case HDSP_SPDIFIN_INTERNAL:
|
||||
snd_iprintf(buffer, "IEC958 input: Internal\n");
|
||||
break;
|
||||
case HDSP_SPDIFIN_AES:
|
||||
snd_iprintf(buffer, "IEC958 input: AES\n");
|
||||
break;
|
||||
default:
|
||||
snd_iprintf(buffer, "IEC958 input: ???\n");
|
||||
break;
|
||||
if (hdsp->io_type != RPM) {
|
||||
switch (hdsp_spdif_in(hdsp)) {
|
||||
case HDSP_SPDIFIN_OPTICAL:
|
||||
snd_iprintf(buffer, "IEC958 input: Optical\n");
|
||||
break;
|
||||
case HDSP_SPDIFIN_COAXIAL:
|
||||
snd_iprintf(buffer, "IEC958 input: Coaxial\n");
|
||||
break;
|
||||
case HDSP_SPDIFIN_INTERNAL:
|
||||
snd_iprintf(buffer, "IEC958 input: Internal\n");
|
||||
break;
|
||||
case HDSP_SPDIFIN_AES:
|
||||
snd_iprintf(buffer, "IEC958 input: AES\n");
|
||||
break;
|
||||
default:
|
||||
snd_iprintf(buffer, "IEC958 input: ???\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (hdsp->control_register & HDSP_SPDIFOpticalOut)
|
||||
snd_iprintf(buffer, "IEC958 output: Coaxial & ADAT1\n");
|
||||
else
|
||||
snd_iprintf(buffer, "IEC958 output: Coaxial only\n");
|
||||
if (RPM == hdsp->io_type) {
|
||||
if (hdsp->control_register & HDSP_RPM_Bypass)
|
||||
snd_iprintf(buffer, "RPM Bypass: disabled\n");
|
||||
else
|
||||
snd_iprintf(buffer, "RPM Bypass: enabled\n");
|
||||
if (hdsp->control_register & HDSP_RPM_Disconnect)
|
||||
snd_iprintf(buffer, "RPM disconnected\n");
|
||||
else
|
||||
snd_iprintf(buffer, "RPM connected\n");
|
||||
|
||||
if (hdsp->control_register & HDSP_SPDIFProfessional)
|
||||
snd_iprintf(buffer, "IEC958 quality: Professional\n");
|
||||
else
|
||||
snd_iprintf(buffer, "IEC958 quality: Consumer\n");
|
||||
switch (hdsp->control_register & HDSP_RPM_Inp12) {
|
||||
case HDSP_RPM_Inp12_Phon_6dB:
|
||||
snd_iprintf(buffer, "Input 1/2: Phono, 6dB\n");
|
||||
break;
|
||||
case HDSP_RPM_Inp12_Phon_0dB:
|
||||
snd_iprintf(buffer, "Input 1/2: Phono, 0dB\n");
|
||||
break;
|
||||
case HDSP_RPM_Inp12_Phon_n6dB:
|
||||
snd_iprintf(buffer, "Input 1/2: Phono, -6dB\n");
|
||||
break;
|
||||
case HDSP_RPM_Inp12_Line_0dB:
|
||||
snd_iprintf(buffer, "Input 1/2: Line, 0dB\n");
|
||||
break;
|
||||
case HDSP_RPM_Inp12_Line_n6dB:
|
||||
snd_iprintf(buffer, "Input 1/2: Line, -6dB\n");
|
||||
break;
|
||||
default:
|
||||
snd_iprintf(buffer, "Input 1/2: ???\n");
|
||||
}
|
||||
|
||||
if (hdsp->control_register & HDSP_SPDIFEmphasis)
|
||||
snd_iprintf(buffer, "IEC958 emphasis: on\n");
|
||||
else
|
||||
snd_iprintf(buffer, "IEC958 emphasis: off\n");
|
||||
switch (hdsp->control_register & HDSP_RPM_Inp34) {
|
||||
case HDSP_RPM_Inp34_Phon_6dB:
|
||||
snd_iprintf(buffer, "Input 3/4: Phono, 6dB\n");
|
||||
break;
|
||||
case HDSP_RPM_Inp34_Phon_0dB:
|
||||
snd_iprintf(buffer, "Input 3/4: Phono, 0dB\n");
|
||||
break;
|
||||
case HDSP_RPM_Inp34_Phon_n6dB:
|
||||
snd_iprintf(buffer, "Input 3/4: Phono, -6dB\n");
|
||||
break;
|
||||
case HDSP_RPM_Inp34_Line_0dB:
|
||||
snd_iprintf(buffer, "Input 3/4: Line, 0dB\n");
|
||||
break;
|
||||
case HDSP_RPM_Inp34_Line_n6dB:
|
||||
snd_iprintf(buffer, "Input 3/4: Line, -6dB\n");
|
||||
break;
|
||||
default:
|
||||
snd_iprintf(buffer, "Input 3/4: ???\n");
|
||||
}
|
||||
|
||||
if (hdsp->control_register & HDSP_SPDIFNonAudio)
|
||||
snd_iprintf(buffer, "IEC958 NonAudio: on\n");
|
||||
else
|
||||
snd_iprintf(buffer, "IEC958 NonAudio: off\n");
|
||||
if ((x = hdsp_spdif_sample_rate (hdsp)) != 0)
|
||||
snd_iprintf (buffer, "IEC958 sample rate: %d\n", x);
|
||||
else
|
||||
snd_iprintf (buffer, "IEC958 sample rate: Error flag set\n");
|
||||
} else {
|
||||
if (hdsp->control_register & HDSP_SPDIFOpticalOut)
|
||||
snd_iprintf(buffer, "IEC958 output: Coaxial & ADAT1\n");
|
||||
else
|
||||
snd_iprintf(buffer, "IEC958 output: Coaxial only\n");
|
||||
|
||||
if (hdsp->control_register & HDSP_SPDIFProfessional)
|
||||
snd_iprintf(buffer, "IEC958 quality: Professional\n");
|
||||
else
|
||||
snd_iprintf(buffer, "IEC958 quality: Consumer\n");
|
||||
|
||||
if (hdsp->control_register & HDSP_SPDIFEmphasis)
|
||||
snd_iprintf(buffer, "IEC958 emphasis: on\n");
|
||||
else
|
||||
snd_iprintf(buffer, "IEC958 emphasis: off\n");
|
||||
|
||||
if (hdsp->control_register & HDSP_SPDIFNonAudio)
|
||||
snd_iprintf(buffer, "IEC958 NonAudio: on\n");
|
||||
else
|
||||
snd_iprintf(buffer, "IEC958 NonAudio: off\n");
|
||||
x = hdsp_spdif_sample_rate(hdsp);
|
||||
if (x != 0)
|
||||
snd_iprintf(buffer, "IEC958 sample rate: %d\n", x);
|
||||
else
|
||||
snd_iprintf(buffer, "IEC958 sample rate: Error flag set\n");
|
||||
}
|
||||
snd_iprintf(buffer, "\n");
|
||||
|
||||
/* Sync Check */
|
||||
@ -3765,7 +4169,7 @@ static irqreturn_t snd_hdsp_interrupt(int irq, void *dev_id)
|
||||
snd_hdsp_midi_input_read (&hdsp->midi[0]);
|
||||
}
|
||||
}
|
||||
if (hdsp->io_type != Multiface && hdsp->io_type != H9632 && midi1 && midi1status) {
|
||||
if (hdsp->io_type != Multiface && hdsp->io_type != RPM && hdsp->io_type != H9632 && midi1 && midi1status) {
|
||||
if (hdsp->use_midi_tasklet) {
|
||||
/* we disable interrupts for this input until processing is done */
|
||||
hdsp->control_register &= ~HDSP_Midi1InterruptEnable;
|
||||
@ -4093,7 +4497,7 @@ static struct snd_pcm_hardware snd_hdsp_playback_subinfo =
|
||||
SNDRV_PCM_RATE_96000),
|
||||
.rate_min = 32000,
|
||||
.rate_max = 96000,
|
||||
.channels_min = 14,
|
||||
.channels_min = 6,
|
||||
.channels_max = HDSP_MAX_CHANNELS,
|
||||
.buffer_bytes_max = HDSP_CHANNEL_BUFFER_BYTES * HDSP_MAX_CHANNELS,
|
||||
.period_bytes_min = (64 * 4) * 10,
|
||||
@ -4122,7 +4526,7 @@ static struct snd_pcm_hardware snd_hdsp_capture_subinfo =
|
||||
SNDRV_PCM_RATE_96000),
|
||||
.rate_min = 32000,
|
||||
.rate_max = 96000,
|
||||
.channels_min = 14,
|
||||
.channels_min = 5,
|
||||
.channels_max = HDSP_MAX_CHANNELS,
|
||||
.buffer_bytes_max = HDSP_CHANNEL_BUFFER_BYTES * HDSP_MAX_CHANNELS,
|
||||
.period_bytes_min = (64 * 4) * 10,
|
||||
@ -4357,10 +4761,12 @@ static int snd_hdsp_playback_open(struct snd_pcm_substream *substream)
|
||||
snd_hdsp_hw_rule_rate_out_channels, hdsp,
|
||||
SNDRV_PCM_HW_PARAM_CHANNELS, -1);
|
||||
|
||||
hdsp->creg_spdif_stream = hdsp->creg_spdif;
|
||||
hdsp->spdif_ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
|
||||
snd_ctl_notify(hdsp->card, SNDRV_CTL_EVENT_MASK_VALUE |
|
||||
SNDRV_CTL_EVENT_MASK_INFO, &hdsp->spdif_ctl->id);
|
||||
if (RPM != hdsp->io_type) {
|
||||
hdsp->creg_spdif_stream = hdsp->creg_spdif;
|
||||
hdsp->spdif_ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
|
||||
snd_ctl_notify(hdsp->card, SNDRV_CTL_EVENT_MASK_VALUE |
|
||||
SNDRV_CTL_EVENT_MASK_INFO, &hdsp->spdif_ctl->id);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -4375,9 +4781,11 @@ static int snd_hdsp_playback_release(struct snd_pcm_substream *substream)
|
||||
|
||||
spin_unlock_irq(&hdsp->lock);
|
||||
|
||||
hdsp->spdif_ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
|
||||
snd_ctl_notify(hdsp->card, SNDRV_CTL_EVENT_MASK_VALUE |
|
||||
SNDRV_CTL_EVENT_MASK_INFO, &hdsp->spdif_ctl->id);
|
||||
if (RPM != hdsp->io_type) {
|
||||
hdsp->spdif_ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
|
||||
snd_ctl_notify(hdsp->card, SNDRV_CTL_EVENT_MASK_VALUE |
|
||||
SNDRV_CTL_EVENT_MASK_INFO, &hdsp->spdif_ctl->id);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -4616,7 +5024,7 @@ static int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigne
|
||||
if (hdsp->io_type != H9632)
|
||||
info.adatsync_sync_check = (unsigned char)hdsp_adatsync_sync_check(hdsp);
|
||||
info.spdif_sync_check = (unsigned char)hdsp_spdif_sync_check(hdsp);
|
||||
for (i = 0; i < ((hdsp->io_type != Multiface && hdsp->io_type != H9632) ? 3 : 1); ++i)
|
||||
for (i = 0; i < ((hdsp->io_type != Multiface && hdsp->io_type != RPM && hdsp->io_type != H9632) ? 3 : 1); ++i)
|
||||
info.adat_sync_check[i] = (unsigned char)hdsp_adat_sync_check(hdsp, i);
|
||||
info.spdif_in = (unsigned char)hdsp_spdif_in(hdsp);
|
||||
info.spdif_out = (unsigned char)hdsp_spdif_out(hdsp);
|
||||
@ -4636,6 +5044,9 @@ static int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigne
|
||||
info.phone_gain = (unsigned char)hdsp_phone_gain(hdsp);
|
||||
info.xlr_breakout_cable = (unsigned char)hdsp_xlr_breakout_cable(hdsp);
|
||||
|
||||
} else if (hdsp->io_type == RPM) {
|
||||
info.da_gain = (unsigned char) hdsp_rpm_input12(hdsp);
|
||||
info.ad_gain = (unsigned char) hdsp_rpm_input34(hdsp);
|
||||
}
|
||||
if (hdsp->io_type == H9632 || hdsp->io_type == H9652)
|
||||
info.analog_extension_board = (unsigned char)hdsp_aeb(hdsp);
|
||||
@ -4844,6 +5255,14 @@ static void snd_hdsp_initialize_channels(struct hdsp *hdsp)
|
||||
hdsp->ds_in_channels = hdsp->ds_out_channels = MULTIFACE_DS_CHANNELS;
|
||||
break;
|
||||
|
||||
case RPM:
|
||||
hdsp->card_name = "RME Hammerfall DSP + RPM";
|
||||
hdsp->ss_in_channels = RPM_CHANNELS-1;
|
||||
hdsp->ss_out_channels = RPM_CHANNELS;
|
||||
hdsp->ds_in_channels = RPM_CHANNELS-1;
|
||||
hdsp->ds_out_channels = RPM_CHANNELS;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* should never get here */
|
||||
break;
|
||||
@ -4930,6 +5349,9 @@ static int hdsp_request_fw_loader(struct hdsp *hdsp)
|
||||
|
||||
/* caution: max length of firmware filename is 30! */
|
||||
switch (hdsp->io_type) {
|
||||
case RPM:
|
||||
fwfile = "rpm_firmware.bin";
|
||||
break;
|
||||
case Multiface:
|
||||
if (hdsp->firmware_rev == 0xa)
|
||||
fwfile = "multiface_firmware.bin";
|
||||
@ -5100,7 +5522,9 @@ static int __devinit snd_hdsp_create(struct snd_card *card,
|
||||
return 0;
|
||||
} else {
|
||||
snd_printk(KERN_INFO "Hammerfall-DSP: Firmware already present, initializing card.\n");
|
||||
if (hdsp_read(hdsp, HDSP_status2Register) & HDSP_version1)
|
||||
if (hdsp_read(hdsp, HDSP_status2Register) & HDSP_version2)
|
||||
hdsp->io_type = RPM;
|
||||
else if (hdsp_read(hdsp, HDSP_status2Register) & HDSP_version1)
|
||||
hdsp->io_type = Multiface;
|
||||
else
|
||||
hdsp->io_type = Digiface;
|
||||
|
@ -1389,15 +1389,9 @@ static struct snd_kcontrol_new snd_ymfpci_spdif_stream __devinitdata =
|
||||
|
||||
static int snd_ymfpci_drec_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *info)
|
||||
{
|
||||
static char *texts[3] = {"AC'97", "IEC958", "ZV Port"};
|
||||
static const char *const texts[3] = {"AC'97", "IEC958", "ZV Port"};
|
||||
|
||||
info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
|
||||
info->count = 1;
|
||||
info->value.enumerated.items = 3;
|
||||
if (info->value.enumerated.item > 2)
|
||||
info->value.enumerated.item = 2;
|
||||
strcpy(info->value.enumerated.name, texts[info->value.enumerated.item]);
|
||||
return 0;
|
||||
return snd_ctl_enum_info(info, 1, 3, texts);
|
||||
}
|
||||
|
||||
static int snd_ymfpci_drec_source_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *value)
|
||||
|
@ -20,6 +20,21 @@ menuconfig SND_SOC
|
||||
|
||||
if SND_SOC
|
||||
|
||||
config SND_SOC_CACHE_LZO
|
||||
bool "Support LZO compression for register caches"
|
||||
select LZO_COMPRESS
|
||||
select LZO_DECOMPRESS
|
||||
---help---
|
||||
Select this to enable LZO compression for register caches.
|
||||
This will allow machine or CODEC drivers to compress register
|
||||
caches in memory, reducing the memory consumption at the
|
||||
expense of performance. If this is not present and is used
|
||||
the system will fall back to uncompressed caches.
|
||||
|
||||
Usually it is safe to disable this option, where cache
|
||||
compression in used the rbtree option will typically perform
|
||||
better.
|
||||
|
||||
config SND_SOC_AC97_BUS
|
||||
bool
|
||||
|
||||
@ -36,7 +51,7 @@ source "sound/soc/nuc900/Kconfig"
|
||||
source "sound/soc/omap/Kconfig"
|
||||
source "sound/soc/kirkwood/Kconfig"
|
||||
source "sound/soc/pxa/Kconfig"
|
||||
source "sound/soc/s3c24xx/Kconfig"
|
||||
source "sound/soc/samsung/Kconfig"
|
||||
source "sound/soc/s6000/Kconfig"
|
||||
source "sound/soc/sh/Kconfig"
|
||||
source "sound/soc/txx9/Kconfig"
|
||||
|
@ -14,7 +14,7 @@ obj-$(CONFIG_SND_SOC) += nuc900/
|
||||
obj-$(CONFIG_SND_SOC) += omap/
|
||||
obj-$(CONFIG_SND_SOC) += kirkwood/
|
||||
obj-$(CONFIG_SND_SOC) += pxa/
|
||||
obj-$(CONFIG_SND_SOC) += s3c24xx/
|
||||
obj-$(CONFIG_SND_SOC) += samsung/
|
||||
obj-$(CONFIG_SND_SOC) += s6000/
|
||||
obj-$(CONFIG_SND_SOC) += sh/
|
||||
obj-$(CONFIG_SND_SOC) += txx9/
|
||||
|
@ -33,7 +33,6 @@
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/soc-dapm.h>
|
||||
|
||||
#include <mach/at32ap700x.h>
|
||||
#include <mach/portmux.h>
|
||||
@ -318,27 +317,28 @@ static const struct snd_soc_dapm_route intercon[] = {
|
||||
static int playpaq_wm8510_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
struct snd_soc_dapm_context *dapm = &codec->dapm;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Add DAPM widgets
|
||||
*/
|
||||
for (i = 0; i < ARRAY_SIZE(playpaq_dapm_widgets); i++)
|
||||
snd_soc_dapm_new_control(codec, &playpaq_dapm_widgets[i]);
|
||||
snd_soc_dapm_new_control(dapm, &playpaq_dapm_widgets[i]);
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Setup audio path interconnects
|
||||
*/
|
||||
snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
|
||||
snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
|
||||
|
||||
|
||||
|
||||
/* always connected pins */
|
||||
snd_soc_dapm_enable_pin(codec, "Int Mic");
|
||||
snd_soc_dapm_enable_pin(codec, "Ext Spk");
|
||||
snd_soc_dapm_sync(codec);
|
||||
snd_soc_dapm_enable_pin(dapm, "Int Mic");
|
||||
snd_soc_dapm_enable_pin(dapm, "Ext Spk");
|
||||
snd_soc_dapm_sync(dapm);
|
||||
|
||||
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user