diff options
| -rw-r--r-- | Documentation/sound/alsa/ALSA-Configuration.txt | 5 | ||||
| -rw-r--r-- | sound/pci/ice1712/Makefile | 2 | ||||
| -rw-r--r-- | sound/pci/ice1712/ice1712.h | 6 | ||||
| -rw-r--r-- | sound/pci/ice1712/ice1724.c | 3 | ||||
| -rw-r--r-- | sound/pci/ice1712/se.c | 700 | ||||
| -rw-r--r-- | sound/pci/ice1712/se.h | 15 |
6 files changed, 729 insertions, 2 deletions
diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 7b064f2c2a63..69ab91c991a6 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt | |||
| @@ -1157,11 +1157,14 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. | |||
| 1157 | * Chaintech 9CJS | 1157 | * Chaintech 9CJS |
| 1158 | * Chaintech AV-710 | 1158 | * Chaintech AV-710 |
| 1159 | * Shuttle SN25P | 1159 | * Shuttle SN25P |
| 1160 | * Onkyo SE-90PCI | ||
| 1161 | * Onkyo SE-200PCI | ||
| 1160 | 1162 | ||
| 1161 | model - Use the given board model, one of the following: | 1163 | model - Use the given board model, one of the following: |
| 1162 | revo51, revo71, amp2000, prodigy71, prodigy71lt, | 1164 | revo51, revo71, amp2000, prodigy71, prodigy71lt, |
| 1163 | prodigy192, aureon51, aureon71, universe, ap192, | 1165 | prodigy192, aureon51, aureon71, universe, ap192, |
| 1164 | k8x800, phase22, phase28, ms300, av710 | 1166 | k8x800, phase22, phase28, ms300, av710, se200pci, |
| 1167 | se90pci | ||
| 1165 | 1168 | ||
| 1166 | This module supports multiple cards and autoprobe. | 1169 | This module supports multiple cards and autoprobe. |
| 1167 | 1170 | ||
diff --git a/sound/pci/ice1712/Makefile b/sound/pci/ice1712/Makefile index 65ce66adba5a..ee86a1de72f8 100644 --- a/sound/pci/ice1712/Makefile +++ b/sound/pci/ice1712/Makefile | |||
| @@ -5,7 +5,7 @@ | |||
| 5 | 5 | ||
| 6 | snd-ice17xx-ak4xxx-objs := ak4xxx.o | 6 | snd-ice17xx-ak4xxx-objs := ak4xxx.o |
| 7 | snd-ice1712-objs := ice1712.o delta.o hoontech.o ews.o | 7 | snd-ice1712-objs := ice1712.o delta.o hoontech.o ews.o |
| 8 | snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o vt1720_mobo.o pontis.o prodigy192.o juli.o phase.o wtm.o | 8 | snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o vt1720_mobo.o pontis.o prodigy192.o juli.o phase.o wtm.o se.o |
| 9 | 9 | ||
| 10 | # Toplevel Module Dependency | 10 | # Toplevel Module Dependency |
| 11 | obj-$(CONFIG_SND_ICE1712) += snd-ice1712.o snd-ice17xx-ak4xxx.o | 11 | obj-$(CONFIG_SND_ICE1712) += snd-ice1712.o snd-ice17xx-ak4xxx.o |
diff --git a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h index 58640afa5404..3c3cac3dc08b 100644 --- a/sound/pci/ice1712/ice1712.h +++ b/sound/pci/ice1712/ice1712.h | |||
| @@ -400,6 +400,12 @@ struct snd_ice1712 { | |||
| 400 | struct { | 400 | struct { |
| 401 | struct ak4114 *ak4114; | 401 | struct ak4114 *ak4114; |
| 402 | } prodigy192; | 402 | } prodigy192; |
| 403 | struct { | ||
| 404 | struct { | ||
| 405 | unsigned char ch1, ch2; | ||
| 406 | } vol[8]; | ||
| 407 | } se; | ||
| 408 | |||
| 403 | } spec; | 409 | } spec; |
| 404 | 410 | ||
| 405 | }; | 411 | }; |
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index 0b0bbb0d96b9..357bdbe21c8f 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c | |||
| @@ -51,6 +51,7 @@ | |||
| 51 | #include "juli.h" | 51 | #include "juli.h" |
| 52 | #include "phase.h" | 52 | #include "phase.h" |
| 53 | #include "wtm.h" | 53 | #include "wtm.h" |
| 54 | #include "se.h" | ||
| 54 | 55 | ||
| 55 | MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); | 56 | MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); |
| 56 | MODULE_DESCRIPTION("VIA ICEnsemble ICE1724/1720 (Envy24HT/PT)"); | 57 | MODULE_DESCRIPTION("VIA ICEnsemble ICE1724/1720 (Envy24HT/PT)"); |
| @@ -65,6 +66,7 @@ MODULE_SUPPORTED_DEVICE("{" | |||
| 65 | JULI_DEVICE_DESC | 66 | JULI_DEVICE_DESC |
| 66 | PHASE_DEVICE_DESC | 67 | PHASE_DEVICE_DESC |
| 67 | WTM_DEVICE_DESC | 68 | WTM_DEVICE_DESC |
| 69 | SE_DEVICE_DESC | ||
| 68 | "{VIA,VT1720}," | 70 | "{VIA,VT1720}," |
| 69 | "{VIA,VT1724}," | 71 | "{VIA,VT1724}," |
| 70 | "{ICEnsemble,Generic ICE1724}," | 72 | "{ICEnsemble,Generic ICE1724}," |
| @@ -1933,6 +1935,7 @@ static struct snd_ice1712_card_info *card_tables[] __devinitdata = { | |||
| 1933 | snd_vt1724_juli_cards, | 1935 | snd_vt1724_juli_cards, |
| 1934 | snd_vt1724_phase_cards, | 1936 | snd_vt1724_phase_cards, |
| 1935 | snd_vt1724_wtm_cards, | 1937 | snd_vt1724_wtm_cards, |
| 1938 | snd_vt1724_se_cards, | ||
| 1936 | NULL, | 1939 | NULL, |
| 1937 | }; | 1940 | }; |
| 1938 | 1941 | ||
diff --git a/sound/pci/ice1712/se.c b/sound/pci/ice1712/se.c new file mode 100644 index 000000000000..ebfe2454a08b --- /dev/null +++ b/sound/pci/ice1712/se.c | |||
| @@ -0,0 +1,700 @@ | |||
| 1 | /* | ||
| 2 | * ALSA driver for ICEnsemble VT1724 (Envy24HT) | ||
| 3 | * | ||
| 4 | * Lowlevel functions for ONKYO WAVIO SE-90PCI and SE-200PCI | ||
| 5 | * | ||
| 6 | * Copyright (c) 2007 Shin-ya Okada sh_okada(at)d4.dion.ne.jp | ||
| 7 | * (at) -> @ | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or modify | ||
| 10 | * it under the terms of the GNU General Public License as published by | ||
| 11 | * the Free Software Foundation; either version 2 of the License, or | ||
| 12 | * (at your option) any later version. | ||
| 13 | * | ||
| 14 | * This program is distributed in the hope that it will be useful, | ||
| 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 17 | * GNU General Public License for more details. | ||
| 18 | * | ||
| 19 | * You should have received a copy of the GNU General Public License | ||
| 20 | * along with this program; if not, write to the Free Software | ||
| 21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 22 | * | ||
| 23 | */ | ||
| 24 | |||
| 25 | #include <sound/driver.h> | ||
| 26 | #include <asm/io.h> | ||
| 27 | #include <linux/delay.h> | ||
| 28 | #include <linux/interrupt.h> | ||
| 29 | #include <linux/init.h> | ||
| 30 | #include <linux/slab.h> | ||
| 31 | #include <sound/core.h> | ||
| 32 | #include <sound/tlv.h> | ||
| 33 | |||
| 34 | #include "ice1712.h" | ||
| 35 | #include "envy24ht.h" | ||
| 36 | #include "se.h" | ||
| 37 | |||
| 38 | |||
| 39 | /****************************************************************************/ | ||
| 40 | /* ONKYO WAVIO SE-200PCI */ | ||
| 41 | /****************************************************************************/ | ||
| 42 | /* | ||
| 43 | * system configuration ICE_EEP2_SYSCONF=0x4b | ||
| 44 | * XIN1 49.152MHz | ||
| 45 | * not have UART | ||
| 46 | * one stereo ADC and a S/PDIF receiver connected | ||
| 47 | * four stereo DACs connected | ||
| 48 | * | ||
| 49 | * AC-Link configuration ICE_EEP2_ACLINK=0x80 | ||
| 50 | * use I2C, not use AC97 | ||
| 51 | * | ||
| 52 | * I2S converters feature ICE_EEP2_I2S=0x78 | ||
| 53 | * I2S codec has no volume/mute control feature | ||
| 54 | * I2S codec supports 96KHz and 192KHz | ||
| 55 | * I2S codec 24bits | ||
| 56 | * | ||
| 57 | * S/PDIF configuration ICE_EEP2_SPDIF=0xc3 | ||
| 58 | * Enable integrated S/PDIF transmitter | ||
| 59 | * internal S/PDIF out implemented | ||
| 60 | * S/PDIF is stereo | ||
| 61 | * External S/PDIF out implemented | ||
| 62 | * | ||
| 63 | * | ||
| 64 | * ** connected chips ** | ||
| 65 | * | ||
| 66 | * WM8740 | ||
| 67 | * A 2ch-DAC of main outputs. | ||
| 68 | * It setuped as I2S mode by wire, so no way to setup from software. | ||
| 69 | * The sample-rate are automatically changed. | ||
| 70 | * ML/I2S (28pin) --------+ | ||
| 71 | * MC/DM1 (27pin) -- 5V | | ||
| 72 | * MD/DM0 (26pin) -- GND | | ||
| 73 | * MUTEB (25pin) -- NC | | ||
| 74 | * MODE (24pin) -- GND | | ||
| 75 | * CSBIW (23pin) --------+ | ||
| 76 | * | | ||
| 77 | * RSTB (22pin) --R(1K)-+ | ||
| 78 | * Probably it reduce the noise from the control line. | ||
| 79 | * | ||
| 80 | * WM8766 | ||
| 81 | * A 6ch-DAC for surrounds. | ||
| 82 | * It's control wire was connected to GPIOxx (3-wire serial interface) | ||
| 83 | * ML/I2S (11pin) -- GPIO18 | ||
| 84 | * MC/IWL (12pin) -- GPIO17 | ||
| 85 | * MD/DM (13pin) -- GPIO16 | ||
| 86 | * MUTE (14pin) -- GPIO01 | ||
| 87 | * | ||
| 88 | * WM8776 | ||
| 89 | * A 2ch-ADC(with 10ch-selector) plus 2ch-DAC. | ||
| 90 | * It's control wire was connected to SDA/SCLK (2-wire serial interface) | ||
| 91 | * MODE (16pin) -- R(1K) -- GND | ||
| 92 | * CE (17pin) -- R(1K) -- GND 2-wire mode (address=0x34) | ||
| 93 | * DI (18pin) -- SDA | ||
| 94 | * CL (19pin) -- SCLK | ||
| 95 | * | ||
| 96 | * | ||
| 97 | * ** output pins and device names ** | ||
| 98 | * | ||
| 99 | * 7.1ch name -- output connector color -- device (-D option) | ||
| 100 | * | ||
| 101 | * FRONT 2ch -- green -- plughw:0,0 | ||
| 102 | * CENTER(Lch) SUBWOOFER(Rch) -- black -- plughw:0,2,0 | ||
| 103 | * SURROUND 2ch -- orange -- plughw:0,2,1 | ||
| 104 | * SURROUND BACK 2ch -- white -- plughw:0,2,2 | ||
| 105 | * | ||
| 106 | */ | ||
| 107 | |||
| 108 | |||
| 109 | /****************************************************************************/ | ||
| 110 | /* WM8740 interface */ | ||
| 111 | /****************************************************************************/ | ||
| 112 | |||
| 113 | static void __devinit se200pci_WM8740_init(struct snd_ice1712 *ice) | ||
| 114 | { | ||
| 115 | /* nothing to do */ | ||
| 116 | } | ||
| 117 | |||
| 118 | |||
| 119 | static void se200pci_WM8740_set_pro_rate(struct snd_ice1712 *ice, | ||
| 120 | unsigned int rate) | ||
| 121 | { | ||
| 122 | /* nothing to do */ | ||
| 123 | } | ||
| 124 | |||
| 125 | |||
| 126 | /****************************************************************************/ | ||
| 127 | /* WM8766 interface */ | ||
| 128 | /****************************************************************************/ | ||
| 129 | |||
| 130 | static void se200pci_WM8766_write(struct snd_ice1712 *ice, | ||
| 131 | unsigned int addr, unsigned int data) | ||
| 132 | { | ||
| 133 | unsigned int st; | ||
| 134 | unsigned int bits; | ||
| 135 | int i; | ||
| 136 | const unsigned int DATA = 0x010000; | ||
| 137 | const unsigned int CLOCK = 0x020000; | ||
| 138 | const unsigned int LOAD = 0x040000; | ||
| 139 | const unsigned int ALL_MASK = (DATA | CLOCK | LOAD); | ||
| 140 | |||
| 141 | snd_ice1712_save_gpio_status(ice); | ||
| 142 | |||
| 143 | st = ((addr & 0x7f) << 9) | (data & 0x1ff); | ||
| 144 | snd_ice1712_gpio_set_dir(ice, ice->gpio.direction | ALL_MASK); | ||
| 145 | snd_ice1712_gpio_set_mask(ice, ice->gpio.write_mask & ~ALL_MASK); | ||
| 146 | bits = snd_ice1712_gpio_read(ice) & ~ALL_MASK; | ||
| 147 | |||
| 148 | snd_ice1712_gpio_write(ice, bits); | ||
| 149 | for (i = 0; i < 16; i++) { | ||
| 150 | udelay(1); | ||
| 151 | bits &= ~CLOCK; | ||
| 152 | st = (st << 1); | ||
| 153 | if (st & 0x10000) | ||
| 154 | bits |= DATA; | ||
| 155 | else | ||
| 156 | bits &= ~DATA; | ||
| 157 | |||
| 158 | snd_ice1712_gpio_write(ice, bits); | ||
| 159 | |||
| 160 | udelay(1); | ||
| 161 | bits |= CLOCK; | ||
| 162 | snd_ice1712_gpio_write(ice, bits); | ||
| 163 | } | ||
| 164 | |||
| 165 | udelay(1); | ||
| 166 | bits |= LOAD; | ||
| 167 | snd_ice1712_gpio_write(ice, bits); | ||
| 168 | |||
| 169 | udelay(1); | ||
| 170 | bits |= (DATA | CLOCK); | ||
| 171 | snd_ice1712_gpio_write(ice, bits); | ||
| 172 | |||
| 173 | snd_ice1712_restore_gpio_status(ice); | ||
| 174 | } | ||
| 175 | |||
| 176 | static void se200pci_WM8766_set_volume(struct snd_ice1712 *ice, int ch, | ||
| 177 | unsigned int vol1, unsigned int vol2) | ||
| 178 | { | ||
| 179 | switch (ch) { | ||
| 180 | case 0: | ||
| 181 | se200pci_WM8766_write(ice, 0x000, vol1); | ||
| 182 | se200pci_WM8766_write(ice, 0x001, vol2 | 0x100); | ||
| 183 | break; | ||
| 184 | case 1: | ||
| 185 | se200pci_WM8766_write(ice, 0x004, vol1); | ||
| 186 | se200pci_WM8766_write(ice, 0x005, vol2 | 0x100); | ||
| 187 | break; | ||
| 188 | case 2: | ||
| 189 | se200pci_WM8766_write(ice, 0x006, vol1); | ||
| 190 | se200pci_WM8766_write(ice, 0x007, vol2 | 0x100); | ||
| 191 | break; | ||
| 192 | } | ||
| 193 | } | ||
| 194 | |||
| 195 | static void __devinit se200pci_WM8766_init(struct snd_ice1712 *ice) | ||
| 196 | { | ||
| 197 | se200pci_WM8766_write(ice, 0x1f, 0x000); /* RESET ALL */ | ||
| 198 | udelay(10); | ||
| 199 | |||
| 200 | se200pci_WM8766_set_volume(ice, 0, 0, 0); /* volume L=0 R=0 */ | ||
| 201 | se200pci_WM8766_set_volume(ice, 1, 0, 0); /* volume L=0 R=0 */ | ||
| 202 | se200pci_WM8766_set_volume(ice, 2, 0, 0); /* volume L=0 R=0 */ | ||
| 203 | |||
| 204 | se200pci_WM8766_write(ice, 0x03, 0x022); /* serial mode I2S-24bits */ | ||
| 205 | se200pci_WM8766_write(ice, 0x0a, 0x080); /* MCLK=256fs */ | ||
| 206 | se200pci_WM8766_write(ice, 0x12, 0x000); /* MDP=0 */ | ||
| 207 | se200pci_WM8766_write(ice, 0x15, 0x000); /* MDP=0 */ | ||
| 208 | se200pci_WM8766_write(ice, 0x09, 0x000); /* demp=off mute=off */ | ||
| 209 | |||
| 210 | se200pci_WM8766_write(ice, 0x02, 0x124); /* ch-assign L=L R=R RESET */ | ||
| 211 | se200pci_WM8766_write(ice, 0x02, 0x120); /* ch-assign L=L R=R */ | ||
| 212 | } | ||
| 213 | |||
| 214 | static void se200pci_WM8766_set_pro_rate(struct snd_ice1712 *ice, | ||
| 215 | unsigned int rate) | ||
| 216 | { | ||
| 217 | if (rate > 96000) | ||
| 218 | se200pci_WM8766_write(ice, 0x0a, 0x000); /* MCLK=128fs */ | ||
| 219 | else | ||
| 220 | se200pci_WM8766_write(ice, 0x0a, 0x080); /* MCLK=256fs */ | ||
| 221 | } | ||
| 222 | |||
| 223 | |||
| 224 | /****************************************************************************/ | ||
| 225 | /* WM8776 interface */ | ||
| 226 | /****************************************************************************/ | ||
| 227 | |||
| 228 | static void se200pci_WM8776_write(struct snd_ice1712 *ice, | ||
| 229 | unsigned int addr, unsigned int data) | ||
| 230 | { | ||
| 231 | unsigned int val; | ||
| 232 | |||
| 233 | val = (addr << 9) | data; | ||
| 234 | snd_vt1724_write_i2c(ice, 0x34, val >> 8, val & 0xff); | ||
| 235 | } | ||
| 236 | |||
| 237 | |||
| 238 | static void se200pci_WM8776_set_output_volume(struct snd_ice1712 *ice, | ||
| 239 | unsigned int vol1, unsigned int vol2) | ||
| 240 | { | ||
| 241 | se200pci_WM8776_write(ice, 0x03, vol1); | ||
| 242 | se200pci_WM8776_write(ice, 0x04, vol2 | 0x100); | ||
| 243 | } | ||
| 244 | |||
| 245 | static void se200pci_WM8776_set_input_volume(struct snd_ice1712 *ice, | ||
| 246 | unsigned int vol1, unsigned int vol2) | ||
| 247 | { | ||
| 248 | se200pci_WM8776_write(ice, 0x0e, vol1); | ||
| 249 | se200pci_WM8776_write(ice, 0x0f, vol2 | 0x100); | ||
| 250 | } | ||
| 251 | |||
| 252 | static const char *se200pci_sel[] = { | ||
| 253 | "LINE-IN", "CD-IN", "MIC-IN", "ALL-MIX", NULL | ||
| 254 | }; | ||
| 255 | |||
| 256 | static void se200pci_WM8776_set_input_selector(struct snd_ice1712 *ice, | ||
| 257 | unsigned int sel) | ||
| 258 | { | ||
| 259 | static unsigned char vals[] = { | ||
| 260 | /* LINE, CD, MIC, ALL, GND */ | ||
| 261 | 0x10, 0x04, 0x08, 0x1c, 0x03 | ||
| 262 | }; | ||
| 263 | if (sel > 4) | ||
| 264 | sel = 4; | ||
| 265 | se200pci_WM8776_write(ice, 0x15, vals[sel]); | ||
| 266 | } | ||
| 267 | |||
| 268 | static void se200pci_WM8776_set_afl(struct snd_ice1712 *ice, unsigned int afl) | ||
| 269 | { | ||
| 270 | /* AFL -- After Fader Listening */ | ||
| 271 | if (afl) | ||
| 272 | se200pci_WM8776_write(ice, 0x16, 0x005); | ||
| 273 | else | ||
| 274 | se200pci_WM8776_write(ice, 0x16, 0x001); | ||
| 275 | } | ||
| 276 | |||
| 277 | static const char *se200pci_agc[] = { | ||
| 278 | "Off", "LimiterMode", "ALCMode", NULL | ||
| 279 | }; | ||
| 280 | |||
| 281 | static void se200pci_WM8776_set_agc(struct snd_ice1712 *ice, unsigned int agc) | ||
| 282 | { | ||
| 283 | /* AGC -- Auto Gain Control of the input */ | ||
| 284 | switch (agc) { | ||
| 285 | case 0: | ||
| 286 | se200pci_WM8776_write(ice, 0x11, 0x000); /* Off */ | ||
| 287 | break; | ||
| 288 | case 1: | ||
| 289 | se200pci_WM8776_write(ice, 0x10, 0x07b); | ||
| 290 | se200pci_WM8776_write(ice, 0x11, 0x100); /* LimiterMode */ | ||
| 291 | break; | ||
| 292 | case 2: | ||
| 293 | se200pci_WM8776_write(ice, 0x10, 0x1fb); | ||
| 294 | se200pci_WM8776_write(ice, 0x11, 0x100); /* ALCMode */ | ||
| 295 | break; | ||
| 296 | } | ||
| 297 | } | ||
| 298 | |||
| 299 | static void __devinit se200pci_WM8776_init(struct snd_ice1712 *ice) | ||
| 300 | { | ||
| 301 | int i; | ||
| 302 | static unsigned short __devinitdata default_values[] = { | ||
| 303 | 0x100, 0x100, 0x100, | ||
| 304 | 0x100, 0x100, 0x100, | ||
| 305 | 0x000, 0x090, 0x000, 0x000, | ||
| 306 | 0x022, 0x022, 0x022, | ||
| 307 | 0x008, 0x0cf, 0x0cf, 0x07b, 0x000, | ||
| 308 | 0x032, 0x000, 0x0a6, 0x001, 0x001 | ||
| 309 | }; | ||
| 310 | |||
| 311 | se200pci_WM8776_write(ice, 0x17, 0x000); /* reset all */ | ||
| 312 | /* ADC and DAC interface is I2S 24bits mode */ | ||
| 313 | /* The sample-rate are automatically changed */ | ||
| 314 | udelay(10); | ||
| 315 | /* BUT my board can not do reset all, so I load all by manually. */ | ||
| 316 | for (i = 0; i < ARRAY_SIZE(default_values); i++) | ||
| 317 | se200pci_WM8776_write(ice, i, default_values[i]); | ||
| 318 | |||
| 319 | se200pci_WM8776_set_input_selector(ice, 0); | ||
| 320 | se200pci_WM8776_set_afl(ice, 0); | ||
| 321 | se200pci_WM8776_set_agc(ice, 0); | ||
| 322 | se200pci_WM8776_set_input_volume(ice, 0, 0); | ||
| 323 | se200pci_WM8776_set_output_volume(ice, 0, 0); | ||
| 324 | |||
| 325 | /* head phone mute and power down */ | ||
| 326 | se200pci_WM8776_write(ice, 0x00, 0); | ||
| 327 | se200pci_WM8776_write(ice, 0x01, 0); | ||
| 328 | se200pci_WM8776_write(ice, 0x02, 0x100); | ||
| 329 | se200pci_WM8776_write(ice, 0x0d, 0x080); | ||
| 330 | } | ||
| 331 | |||
| 332 | static void se200pci_WM8776_set_pro_rate(struct snd_ice1712 *ice, | ||
| 333 | unsigned int rate) | ||
| 334 | { | ||
| 335 | /* nothing to do */ | ||
| 336 | } | ||
| 337 | |||
| 338 | |||
| 339 | /****************************************************************************/ | ||
| 340 | /* runtime interface */ | ||
| 341 | /****************************************************************************/ | ||
| 342 | |||
| 343 | static void se200pci_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate) | ||
| 344 | { | ||
| 345 | se200pci_WM8740_set_pro_rate(ice, rate); | ||
| 346 | se200pci_WM8766_set_pro_rate(ice, rate); | ||
| 347 | se200pci_WM8776_set_pro_rate(ice, rate); | ||
| 348 | } | ||
| 349 | |||
| 350 | struct se200pci_control { | ||
| 351 | char *name; | ||
| 352 | enum { | ||
| 353 | WM8766, | ||
| 354 | WM8776in, | ||
| 355 | WM8776out, | ||
| 356 | WM8776sel, | ||
| 357 | WM8776agc, | ||
| 358 | WM8776afl | ||
| 359 | } target; | ||
| 360 | enum { VOLUME1, VOLUME2, BOOLEAN, ENUM } type; | ||
| 361 | int ch; | ||
| 362 | const char **member; | ||
| 363 | const char *comment; | ||
| 364 | }; | ||
| 365 | |||
| 366 | static const struct se200pci_control se200pci_cont[] = { | ||
| 367 | { | ||
| 368 | .name = "Front Playback Volume", | ||
| 369 | .target = WM8776out, | ||
| 370 | .type = VOLUME1, | ||
| 371 | .comment = "Front(green)" | ||
| 372 | }, | ||
| 373 | { | ||
| 374 | .name = "Side Playback Volume", | ||
| 375 | .target = WM8766, | ||
| 376 | .type = VOLUME1, | ||
| 377 | .ch = 1, | ||
| 378 | .comment = "Surround(orange)" | ||
| 379 | }, | ||
| 380 | { | ||
| 381 | .name = "Surround Playback Volume", | ||
| 382 | .target = WM8766, | ||
| 383 | .type = VOLUME1, | ||
| 384 | .ch = 2, | ||
| 385 | .comment = "SurroundBack(white)" | ||
| 386 | }, | ||
| 387 | { | ||
| 388 | .name = "CLFE Playback Volume", | ||
| 389 | .target = WM8766, | ||
| 390 | .type = VOLUME1, | ||
| 391 | .ch = 0, | ||
| 392 | .comment = "Center(Lch)&SubWoofer(Rch)(black)" | ||
| 393 | }, | ||
| 394 | { | ||
| 395 | .name = "Capture Volume", | ||
| 396 | .target = WM8776in, | ||
| 397 | .type = VOLUME2 | ||
| 398 | }, | ||
| 399 | { | ||
| 400 | .name = "Capture Select", | ||
| 401 | .target = WM8776sel, | ||
| 402 | .type = ENUM, | ||
| 403 | .member = se200pci_sel | ||
| 404 | }, | ||
| 405 | { | ||
| 406 | .name = "AGC Capture Mode", | ||
| 407 | .target = WM8776agc, | ||
| 408 | .type = ENUM, | ||
| 409 | .member = se200pci_agc | ||
| 410 | }, | ||
| 411 | { | ||
| 412 | .name = "AFL Bypass Playback Switch", | ||
| 413 | .target = WM8776afl, | ||
| 414 | .type = BOOLEAN | ||
| 415 | } | ||
| 416 | }; | ||
| 417 | |||
| 418 | static int se200pci_cont_info(struct snd_kcontrol *kc, | ||
| 419 | struct snd_ctl_elem_info *uinfo) | ||
| 420 | { | ||
| 421 | struct snd_ice1712 *ice; | ||
| 422 | int n; | ||
| 423 | int c; | ||
| 424 | const char **member; | ||
| 425 | |||
| 426 | ice = snd_kcontrol_chip(kc); | ||
| 427 | n = kc->private_value; | ||
| 428 | |||
| 429 | if (se200pci_cont[n].type == VOLUME1 || | ||
| 430 | se200pci_cont[n].type == VOLUME2) { | ||
| 431 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
| 432 | uinfo->count = 2; | ||
| 433 | uinfo->value.integer.min = 0; /* mute */ | ||
| 434 | uinfo->value.integer.max = 0xff; /* 0dB */ | ||
| 435 | |||
| 436 | } else if (se200pci_cont[n].type == BOOLEAN) { | ||
| 437 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
| 438 | uinfo->count = 1; | ||
| 439 | uinfo->value.integer.min = 0; | ||
| 440 | uinfo->value.integer.max = 1; | ||
| 441 | |||
| 442 | } else if (se200pci_cont[n].type == ENUM) { | ||
| 443 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
| 444 | member = se200pci_cont[n].member; | ||
| 445 | if (member == NULL) | ||
| 446 | return -EINVAL; | ||
| 447 | for (c = 0; member[c]; c++) | ||
| 448 | ; | ||
| 449 | |||
| 450 | uinfo->count = 1; | ||
| 451 | uinfo->value.enumerated.items = c; | ||
| 452 | if (uinfo->value.enumerated.item >= c) | ||
| 453 | uinfo->value.enumerated.item = c - 1; | ||
| 454 | strcpy(uinfo->value.enumerated.name, | ||
| 455 | member[uinfo->value.enumerated.item]); | ||
| 456 | } | ||
| 457 | |||
| 458 | return 0; | ||
| 459 | } | ||
| 460 | |||
| 461 | static int se200pci_cont_get(struct snd_kcontrol *kc, | ||
| 462 | struct snd_ctl_elem_value *uc) | ||
| 463 | { | ||
| 464 | struct snd_ice1712 *ice; | ||
| 465 | int n; | ||
| 466 | |||
| 467 | ice = snd_kcontrol_chip(kc); | ||
| 468 | n = kc->private_value; | ||
| 469 | if (se200pci_cont[n].type == VOLUME1 || | ||
| 470 | se200pci_cont[n].type == VOLUME2) { | ||
| 471 | uc->value.integer.value[0] = ice->spec.se.vol[n].ch1; | ||
| 472 | uc->value.integer.value[1] = ice->spec.se.vol[n].ch2; | ||
| 473 | |||
| 474 | } else if (se200pci_cont[n].type == BOOLEAN || | ||
| 475 | se200pci_cont[n].type == ENUM) | ||
| 476 | uc->value.integer.value[0] = ice->spec.se.vol[n].ch1; | ||
| 477 | |||
| 478 | return 0; | ||
| 479 | } | ||
| 480 | |||
| 481 | static int se200pci_cont_put(struct snd_kcontrol *kc, | ||
| 482 | struct snd_ctl_elem_value *uc) | ||
| 483 | { | ||
| 484 | struct snd_ice1712 *ice; | ||
| 485 | int n; | ||
| 486 | unsigned int vol1, vol2; | ||
| 487 | int changed; | ||
| 488 | |||
| 489 | ice = snd_kcontrol_chip(kc); | ||
| 490 | n = kc->private_value; | ||
| 491 | |||
| 492 | changed = 0; | ||
| 493 | vol1 = 0; vol2 = 0; | ||
| 494 | if (se200pci_cont[n].type == VOLUME1 || | ||
| 495 | se200pci_cont[n].type == VOLUME2) { | ||
| 496 | vol1 = uc->value.integer.value[0]; | ||
| 497 | vol2 = uc->value.integer.value[1]; | ||
| 498 | if (ice->spec.se.vol[n].ch1 != vol1) | ||
| 499 | changed = 1; | ||
| 500 | if (ice->spec.se.vol[n].ch2 != vol2) | ||
| 501 | changed = 1; | ||
| 502 | ice->spec.se.vol[n].ch1 = vol1; | ||
| 503 | ice->spec.se.vol[n].ch2 = vol2; | ||
| 504 | |||
| 505 | } else if (se200pci_cont[n].type == BOOLEAN || | ||
| 506 | se200pci_cont[n].type == ENUM) { | ||
| 507 | vol1 = uc->value.integer.value[0]; | ||
| 508 | if (ice->spec.se.vol[n].ch1 != vol1) | ||
| 509 | changed = 1; | ||
| 510 | ice->spec.se.vol[n].ch1 = vol1; | ||
| 511 | } | ||
| 512 | |||
| 513 | switch (se200pci_cont[n].target) { | ||
| 514 | case WM8766: | ||
| 515 | se200pci_WM8766_set_volume(ice, | ||
| 516 | se200pci_cont[n].ch, vol1, vol2); | ||
| 517 | break; | ||
| 518 | |||
| 519 | case WM8776in: | ||
| 520 | se200pci_WM8776_set_input_volume(ice, vol1, vol2); | ||
| 521 | break; | ||
| 522 | |||
| 523 | case WM8776out: | ||
| 524 | se200pci_WM8776_set_output_volume(ice, vol1, vol2); | ||
| 525 | break; | ||
| 526 | |||
| 527 | case WM8776sel: | ||
| 528 | se200pci_WM8776_set_input_selector(ice, vol1); | ||
| 529 | break; | ||
| 530 | |||
| 531 | case WM8776agc: | ||
| 532 | se200pci_WM8776_set_agc(ice, vol1); | ||
| 533 | break; | ||
| 534 | |||
| 535 | case WM8776afl: | ||
| 536 | se200pci_WM8776_set_afl(ice, vol1); | ||
| 537 | break; | ||
| 538 | |||
| 539 | default: | ||
| 540 | break; | ||
| 541 | } | ||
| 542 | |||
| 543 | return changed; | ||
| 544 | } | ||
| 545 | |||
| 546 | static const DECLARE_TLV_DB_SCALE(db_scale_gain1, -12750, 50, 1); | ||
| 547 | static const DECLARE_TLV_DB_SCALE(db_scale_gain2, -10350, 50, 1); | ||
| 548 | |||
| 549 | static int __devinit se200pci_add_controls(struct snd_ice1712 *ice) | ||
| 550 | { | ||
| 551 | int i; | ||
| 552 | struct snd_kcontrol_new cont; | ||
| 553 | int err; | ||
| 554 | |||
| 555 | memset(&cont, 0, sizeof(cont)); | ||
| 556 | cont.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
| 557 | cont.info = se200pci_cont_info; | ||
| 558 | cont.get = se200pci_cont_get; | ||
| 559 | cont.put = se200pci_cont_put; | ||
| 560 | for (i = 0; i < ARRAY_SIZE(se200pci_cont); i++) { | ||
| 561 | cont.private_value = i; | ||
| 562 | cont.name = se200pci_cont[i].name; | ||
| 563 | cont.access = SNDRV_CTL_ELEM_ACCESS_READWRITE; | ||
| 564 | cont.tlv.p = NULL; | ||
| 565 | if (se200pci_cont[i].type == VOLUME1 || | ||
| 566 | se200pci_cont[i].type == VOLUME2) { | ||
| 567 | |||
| 568 | cont.access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ; | ||
| 569 | |||
| 570 | if (se200pci_cont[i].type == VOLUME1) | ||
| 571 | cont.tlv.p = db_scale_gain1; | ||
| 572 | else | ||
| 573 | cont.tlv.p = db_scale_gain2; | ||
| 574 | } | ||
| 575 | err = snd_ctl_add(ice->card, snd_ctl_new1(&cont, ice)); | ||
| 576 | if (err < 0) | ||
| 577 | return err; | ||
| 578 | } | ||
| 579 | |||
| 580 | return 0; | ||
| 581 | } | ||
| 582 | |||
| 583 | |||
| 584 | /****************************************************************************/ | ||
| 585 | /* ONKYO WAVIO SE-90PCI */ | ||
| 586 | /****************************************************************************/ | ||
| 587 | /* | ||
| 588 | * system configuration ICE_EEP2_SYSCONF=0x4b | ||
| 589 | * AC-Link configuration ICE_EEP2_ACLINK=0x80 | ||
| 590 | * I2S converters feature ICE_EEP2_I2S=0x78 | ||
| 591 | * S/PDIF configuration ICE_EEP2_SPDIF=0xc3 | ||
| 592 | * | ||
| 593 | * ** connected chip ** | ||
| 594 | * | ||
| 595 | * WM8716 | ||
| 596 | * A 2ch-DAC of main outputs. | ||
| 597 | * It setuped as I2S mode by wire, so no way to setup from software. | ||
| 598 | * ML/I2S (28pin) -- +5V | ||
| 599 | * MC/DM1 (27pin) -- GND | ||
| 600 | * MC/DM0 (26pin) -- GND | ||
| 601 | * MUTEB (25pin) -- open (internal pull-up) | ||
| 602 | * MODE (24pin) -- GND | ||
| 603 | * CSBIWO (23pin) -- +5V | ||
| 604 | * | ||
| 605 | */ | ||
| 606 | |||
| 607 | /* Nothing to do for this chip. */ | ||
| 608 | |||
| 609 | |||
| 610 | /****************************************************************************/ | ||
| 611 | /* probe/initialize/setup */ | ||
| 612 | /****************************************************************************/ | ||
| 613 | |||
| 614 | static int __devinit se_init(struct snd_ice1712 *ice) | ||
| 615 | { | ||
| 616 | if (ice->eeprom.subvendor == VT1724_SUBDEVICE_SE90PCI) { | ||
| 617 | ice->num_total_dacs = 2; | ||
| 618 | ice->num_total_adcs = 0; | ||
| 619 | ice->vt1720 = 1; | ||
| 620 | return 0; | ||
| 621 | |||
| 622 | } else if (ice->eeprom.subvendor == VT1724_SUBDEVICE_SE200PCI) { | ||
| 623 | ice->num_total_dacs = 8; | ||
| 624 | ice->num_total_adcs = 2; | ||
| 625 | se200pci_WM8740_init(ice); | ||
| 626 | se200pci_WM8766_init(ice); | ||
| 627 | se200pci_WM8776_init(ice); | ||
| 628 | ice->gpio.set_pro_rate = se200pci_set_pro_rate; | ||
| 629 | return 0; | ||
| 630 | } | ||
| 631 | |||
| 632 | return -ENOENT; | ||
| 633 | } | ||
| 634 | |||
| 635 | static int __devinit se_add_controls(struct snd_ice1712 *ice) | ||
| 636 | { | ||
| 637 | int err; | ||
| 638 | |||
| 639 | err = 0; | ||
| 640 | /* nothing to do for VT1724_SUBDEVICE_SE90PCI */ | ||
| 641 | if (ice->eeprom.subvendor == VT1724_SUBDEVICE_SE200PCI) | ||
| 642 | err = se200pci_add_controls(ice); | ||
| 643 | |||
| 644 | return err; | ||
| 645 | } | ||
| 646 | |||
| 647 | |||
| 648 | /****************************************************************************/ | ||
| 649 | /* entry point */ | ||
| 650 | /****************************************************************************/ | ||
| 651 | |||
| 652 | static unsigned char se200pci_eeprom[] __devinitdata = { | ||
| 653 | [ICE_EEP2_SYSCONF] = 0x4b, /* 49.152Hz, spdif-in/ADC, 4DACs */ | ||
| 654 | [ICE_EEP2_ACLINK] = 0x80, /* I2S */ | ||
| 655 | [ICE_EEP2_I2S] = 0x78, /* 96k-ok, 24bit, 192k-ok */ | ||
| 656 | [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */ | ||
| 657 | |||
| 658 | [ICE_EEP2_GPIO_DIR] = 0x02, /* WM8766 mute 1=output */ | ||
| 659 | [ICE_EEP2_GPIO_DIR1] = 0x00, /* not used */ | ||
| 660 | [ICE_EEP2_GPIO_DIR2] = 0x07, /* WM8766 ML/MC/MD 1=output */ | ||
| 661 | |||
| 662 | [ICE_EEP2_GPIO_MASK] = 0x00, /* 0=writable */ | ||
| 663 | [ICE_EEP2_GPIO_MASK1] = 0x00, /* 0=writable */ | ||
| 664 | [ICE_EEP2_GPIO_MASK2] = 0x00, /* 0=writable */ | ||
| 665 | |||
| 666 | [ICE_EEP2_GPIO_STATE] = 0x00, /* WM8766 mute=0 */ | ||
| 667 | [ICE_EEP2_GPIO_STATE1] = 0x00, /* not used */ | ||
| 668 | [ICE_EEP2_GPIO_STATE2] = 0x07, /* WM8766 ML/MC/MD */ | ||
| 669 | }; | ||
| 670 | |||
| 671 | static unsigned char se90pci_eeprom[] __devinitdata = { | ||
| 672 | [ICE_EEP2_SYSCONF] = 0x4b, /* 49.152Hz, spdif-in/ADC, 4DACs */ | ||
| 673 | [ICE_EEP2_ACLINK] = 0x80, /* I2S */ | ||
| 674 | [ICE_EEP2_I2S] = 0x78, /* 96k-ok, 24bit, 192k-ok */ | ||
| 675 | [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */ | ||
| 676 | |||
| 677 | /* ALL GPIO bits are in input mode */ | ||
| 678 | }; | ||
| 679 | |||
| 680 | struct snd_ice1712_card_info snd_vt1724_se_cards[] __devinitdata = { | ||
| 681 | { | ||
| 682 | .subvendor = VT1724_SUBDEVICE_SE200PCI, | ||
| 683 | .name = "ONKYO SE200PCI", | ||
| 684 | .model = "se200pci", | ||
| 685 | .chip_init = se_init, | ||
| 686 | .build_controls = se_add_controls, | ||
| 687 | .eeprom_size = sizeof(se200pci_eeprom), | ||
| 688 | .eeprom_data = se200pci_eeprom, | ||
| 689 | }, | ||
| 690 | { | ||
| 691 | .subvendor = VT1724_SUBDEVICE_SE90PCI, | ||
| 692 | .name = "ONKYO SE90PCI", | ||
| 693 | .model = "se90pci", | ||
| 694 | .chip_init = se_init, | ||
| 695 | .build_controls = se_add_controls, | ||
| 696 | .eeprom_size = sizeof(se90pci_eeprom), | ||
| 697 | .eeprom_data = se90pci_eeprom, | ||
| 698 | }, | ||
| 699 | {} /*terminator*/ | ||
| 700 | }; | ||
diff --git a/sound/pci/ice1712/se.h b/sound/pci/ice1712/se.h new file mode 100644 index 000000000000..0b0a9dabdcfb --- /dev/null +++ b/sound/pci/ice1712/se.h | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | #ifndef __SOUND_SE_H | ||
| 2 | #define __SOUND_SE_H | ||
| 3 | |||
| 4 | /* ID */ | ||
| 5 | #define SE_DEVICE_DESC \ | ||
| 6 | "{ONKYO INC,SE-90PCI},"\ | ||
| 7 | "{ONKYO INC,SE-200PCI}," | ||
| 8 | |||
| 9 | #define VT1724_SUBDEVICE_SE90PCI 0xb161000 | ||
| 10 | #define VT1724_SUBDEVICE_SE200PCI 0xb160100 | ||
| 11 | |||
| 12 | /* entry struct */ | ||
| 13 | extern struct snd_ice1712_card_info snd_vt1724_se_cards[]; | ||
| 14 | |||
| 15 | #endif /* __SOUND_SE_H */ | ||
