diff options
author | Takashi Iwai <tiwai@suse.de> | 2011-01-13 02:37:14 -0500 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2011-01-13 02:37:14 -0500 |
commit | e38302f78284e3e80ffc2eef54001fce7d183bd4 (patch) | |
tree | 0cb61d52ca9d11d446e3fc1bc97d8fd92ab1e934 | |
parent | 3c0eee3fe6a3a1c745379547c7e7c904aa64f6d5 (diff) | |
parent | c386735264da97e6b6d15aa56361e9ef188b26ab (diff) |
Merge branch 'topic/misc' into for-linus
59 files changed, 2752 insertions, 1125 deletions
diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index d0eb696d32e8..3c1eddd9fcc7 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt | |||
@@ -974,13 +974,6 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. | |||
974 | 974 | ||
975 | See hdspm.txt for details. | 975 | See hdspm.txt for details. |
976 | 976 | ||
977 | Module snd-hifier | ||
978 | ----------------- | ||
979 | |||
980 | Module for the MediaTek/TempoTec HiFier Fantasia sound card. | ||
981 | |||
982 | This module supports autoprobe and multiple cards. | ||
983 | |||
984 | Module snd-ice1712 | 977 | Module snd-ice1712 |
985 | ------------------ | 978 | ------------------ |
986 | 979 | ||
@@ -1531,15 +1524,20 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. | |||
1531 | Module snd-oxygen | 1524 | Module snd-oxygen |
1532 | ----------------- | 1525 | ----------------- |
1533 | 1526 | ||
1534 | Module for sound cards based on the C-Media CMI8788 chip: | 1527 | Module for sound cards based on the C-Media CMI8786/8787/8788 chip: |
1535 | * Asound A-8788 | 1528 | * Asound A-8788 |
1529 | * Asus Xonar DG | ||
1536 | * AuzenTech X-Meridian | 1530 | * AuzenTech X-Meridian |
1531 | * AuzenTech X-Meridian 2G | ||
1537 | * Bgears b-Enspirer | 1532 | * Bgears b-Enspirer |
1538 | * Club3D Theatron DTS | 1533 | * Club3D Theatron DTS |
1539 | * HT-Omega Claro (plus) | 1534 | * HT-Omega Claro (plus) |
1540 | * HT-Omega Claro halo (XT) | 1535 | * HT-Omega Claro halo (XT) |
1536 | * Kuroutoshikou CMI8787-HG2PCI | ||
1541 | * Razer Barracuda AC-1 | 1537 | * Razer Barracuda AC-1 |
1542 | * Sondigo Inferno | 1538 | * Sondigo Inferno |
1539 | * TempoTec HiFier Fantasia | ||
1540 | * TempoTec HiFier Serenade | ||
1543 | 1541 | ||
1544 | This module supports autoprobe and multiple cards. | 1542 | This module supports autoprobe and multiple cards. |
1545 | 1543 | ||
@@ -2006,9 +2004,9 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. | |||
2006 | Module snd-virtuoso | 2004 | Module snd-virtuoso |
2007 | ------------------- | 2005 | ------------------- |
2008 | 2006 | ||
2009 | Module for sound cards based on the Asus AV100/AV200 chips, | 2007 | Module for sound cards based on the Asus AV66/AV100/AV200 chips, |
2010 | i.e., Xonar D1, DX, D2, D2X, DS, HDAV1.3 (Deluxe), Essence ST | 2008 | i.e., Xonar D1, DX, D2, D2X, DS, Essence ST (Deluxe), Essence STX, |
2011 | (Deluxe) and Essence STX. | 2009 | HDAV1.3 (Deluxe), and HDAV1.3 Slim. |
2012 | 2010 | ||
2013 | This module supports autoprobe and multiple cards. | 2011 | This module supports autoprobe and multiple cards. |
2014 | 2012 | ||
diff --git a/MAINTAINERS b/MAINTAINERS index 7585e9dd835b..af58f0b01450 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -1434,6 +1434,14 @@ S: Supported | |||
1434 | F: block/bsg.c | 1434 | F: block/bsg.c |
1435 | F: include/linux/bsg.h | 1435 | F: include/linux/bsg.h |
1436 | 1436 | ||
1437 | BT87X AUDIO DRIVER | ||
1438 | M: Clemens Ladisch <clemens@ladisch.de> | ||
1439 | L: alsa-devel@alsa-project.org (moderated for non-subscribers) | ||
1440 | T: git git://git.alsa-project.org/alsa-kernel.git | ||
1441 | S: Maintained | ||
1442 | F: Documentation/sound/alsa/Bt87x.txt | ||
1443 | F: sound/pci/bt87x.c | ||
1444 | |||
1437 | BT8XXGPIO DRIVER | 1445 | BT8XXGPIO DRIVER |
1438 | M: Michael Buesch <mb@bu3sch.de> | 1446 | M: Michael Buesch <mb@bu3sch.de> |
1439 | W: http://bu3sch.de/btgpio.php | 1447 | W: http://bu3sch.de/btgpio.php |
@@ -1459,6 +1467,13 @@ S: Maintained | |||
1459 | F: Documentation/video4linux/bttv/ | 1467 | F: Documentation/video4linux/bttv/ |
1460 | F: drivers/media/video/bt8xx/bttv* | 1468 | F: drivers/media/video/bt8xx/bttv* |
1461 | 1469 | ||
1470 | C-MEDIA CMI8788 DRIVER | ||
1471 | M: Clemens Ladisch <clemens@ladisch.de> | ||
1472 | L: alsa-devel@alsa-project.org (moderated for non-subscribers) | ||
1473 | T: git git://git.alsa-project.org/alsa-kernel.git | ||
1474 | S: Maintained | ||
1475 | F: sound/pci/oxygen/ | ||
1476 | |||
1462 | CACHEFILES: FS-CACHE BACKEND FOR CACHING ON MOUNTED FILESYSTEMS | 1477 | CACHEFILES: FS-CACHE BACKEND FOR CACHING ON MOUNTED FILESYSTEMS |
1463 | M: David Howells <dhowells@redhat.com> | 1478 | M: David Howells <dhowells@redhat.com> |
1464 | L: linux-cachefs@redhat.com | 1479 | L: linux-cachefs@redhat.com |
@@ -2249,6 +2264,13 @@ W: bluesmoke.sourceforge.net | |||
2249 | S: Maintained | 2264 | S: Maintained |
2250 | F: drivers/edac/r82600_edac.c | 2265 | F: drivers/edac/r82600_edac.c |
2251 | 2266 | ||
2267 | EDIROL UA-101/UA-1000 DRIVER | ||
2268 | M: Clemens Ladisch <clemens@ladisch.de> | ||
2269 | L: alsa-devel@alsa-project.org (moderated for non-subscribers) | ||
2270 | T: git git://git.alsa-project.org/alsa-kernel.git | ||
2271 | S: Maintained | ||
2272 | F: sound/usb/misc/ua101.c | ||
2273 | |||
2252 | EEEPC LAPTOP EXTRAS DRIVER | 2274 | EEEPC LAPTOP EXTRAS DRIVER |
2253 | M: Corentin Chary <corentincj@iksaif.net> | 2275 | M: Corentin Chary <corentincj@iksaif.net> |
2254 | L: acpi4asus-user@lists.sourceforge.net | 2276 | L: acpi4asus-user@lists.sourceforge.net |
@@ -3393,6 +3415,13 @@ L: linux-serial@vger.kernel.org | |||
3393 | S: Maintained | 3415 | S: Maintained |
3394 | F: drivers/serial/jsm/ | 3416 | F: drivers/serial/jsm/ |
3395 | 3417 | ||
3418 | K10TEMP HARDWARE MONITORING DRIVER | ||
3419 | M: Clemens Ladisch <clemens@ladisch.de> | ||
3420 | L: lm-sensors@lm-sensors.org | ||
3421 | S: Maintained | ||
3422 | F: Documentation/hwmon/k10temp | ||
3423 | F: drivers/hwmon/k10temp.c | ||
3424 | |||
3396 | K8TEMP HARDWARE MONITORING DRIVER | 3425 | K8TEMP HARDWARE MONITORING DRIVER |
3397 | M: Rudolf Marek <r.marek@assembler.cz> | 3426 | M: Rudolf Marek <r.marek@assembler.cz> |
3398 | L: lm-sensors@lm-sensors.org | 3427 | L: lm-sensors@lm-sensors.org |
@@ -4409,6 +4438,13 @@ F: drivers/of | |||
4409 | F: include/linux/of*.h | 4438 | F: include/linux/of*.h |
4410 | K: of_get_property | 4439 | K: of_get_property |
4411 | 4440 | ||
4441 | OPL4 DRIVER | ||
4442 | M: Clemens Ladisch <clemens@ladisch.de> | ||
4443 | L: alsa-devel@alsa-project.org (moderated for non-subscribers) | ||
4444 | T: git git://git.alsa-project.org/alsa-kernel.git | ||
4445 | S: Maintained | ||
4446 | F: sound/drivers/opl4/ | ||
4447 | |||
4412 | OPROFILE | 4448 | OPROFILE |
4413 | M: Robert Richter <robert.richter@amd.com> | 4449 | M: Robert Richter <robert.richter@amd.com> |
4414 | L: oprofile-list@lists.sf.net | 4450 | L: oprofile-list@lists.sf.net |
@@ -6141,6 +6177,13 @@ S: Maintained | |||
6141 | W: http://www.one-eyed-alien.net/~mdharm/linux-usb/ | 6177 | W: http://www.one-eyed-alien.net/~mdharm/linux-usb/ |
6142 | F: drivers/usb/storage/ | 6178 | F: drivers/usb/storage/ |
6143 | 6179 | ||
6180 | USB MIDI DRIVER | ||
6181 | M: Clemens Ladisch <clemens@ladisch.de> | ||
6182 | L: alsa-devel@alsa-project.org (moderated for non-subscribers) | ||
6183 | T: git git://git.alsa-project.org/alsa-kernel.git | ||
6184 | S: Maintained | ||
6185 | F: sound/usb/midi.* | ||
6186 | |||
6144 | USB OHCI DRIVER | 6187 | USB OHCI DRIVER |
6145 | M: David Brownell <dbrownell@users.sourceforge.net> | 6188 | M: David Brownell <dbrownell@users.sourceforge.net> |
6146 | L: linux-usb@vger.kernel.org | 6189 | L: linux-usb@vger.kernel.org |
diff --git a/include/sound/asound.h b/include/sound/asound.h index a1803ecea34d..5d6074faa279 100644 --- a/include/sound/asound.h +++ b/include/sound/asound.h | |||
@@ -259,6 +259,7 @@ typedef int __bitwise snd_pcm_subformat_t; | |||
259 | #define SNDRV_PCM_INFO_HALF_DUPLEX 0x00100000 /* only half duplex */ | 259 | #define SNDRV_PCM_INFO_HALF_DUPLEX 0x00100000 /* only half duplex */ |
260 | #define SNDRV_PCM_INFO_JOINT_DUPLEX 0x00200000 /* playback and capture stream are somewhat correlated */ | 260 | #define SNDRV_PCM_INFO_JOINT_DUPLEX 0x00200000 /* playback and capture stream are somewhat correlated */ |
261 | #define SNDRV_PCM_INFO_SYNC_START 0x00400000 /* pcm support some kind of sync go */ | 261 | #define SNDRV_PCM_INFO_SYNC_START 0x00400000 /* pcm support some kind of sync go */ |
262 | #define SNDRV_PCM_INFO_NO_PERIOD_WAKEUP 0x00800000 /* period wakeup can be disabled */ | ||
262 | #define SNDRV_PCM_INFO_FIFO_IN_FRAMES 0x80000000 /* internal kernel flag - FIFO size is in frames */ | 263 | #define SNDRV_PCM_INFO_FIFO_IN_FRAMES 0x80000000 /* internal kernel flag - FIFO size is in frames */ |
263 | 264 | ||
264 | typedef int __bitwise snd_pcm_state_t; | 265 | typedef int __bitwise snd_pcm_state_t; |
@@ -334,6 +335,8 @@ typedef int snd_pcm_hw_param_t; | |||
334 | #define SNDRV_PCM_HW_PARAM_LAST_INTERVAL SNDRV_PCM_HW_PARAM_TICK_TIME | 335 | #define SNDRV_PCM_HW_PARAM_LAST_INTERVAL SNDRV_PCM_HW_PARAM_TICK_TIME |
335 | 336 | ||
336 | #define SNDRV_PCM_HW_PARAMS_NORESAMPLE (1<<0) /* avoid rate resampling */ | 337 | #define SNDRV_PCM_HW_PARAMS_NORESAMPLE (1<<0) /* avoid rate resampling */ |
338 | #define SNDRV_PCM_HW_PARAMS_EXPORT_BUFFER (1<<1) /* export buffer */ | ||
339 | #define SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP (1<<2) /* disable period wakeups */ | ||
337 | 340 | ||
338 | struct snd_interval { | 341 | struct snd_interval { |
339 | unsigned int min, max; | 342 | unsigned int min, max; |
diff --git a/include/sound/control.h b/include/sound/control.h index 112374dc0c58..7715e6f00d38 100644 --- a/include/sound/control.h +++ b/include/sound/control.h | |||
@@ -160,12 +160,14 @@ static inline struct snd_ctl_elem_id *snd_ctl_build_ioff(struct snd_ctl_elem_id | |||
160 | } | 160 | } |
161 | 161 | ||
162 | /* | 162 | /* |
163 | * Frequently used control callbacks | 163 | * Frequently used control callbacks/helpers |
164 | */ | 164 | */ |
165 | int snd_ctl_boolean_mono_info(struct snd_kcontrol *kcontrol, | 165 | int snd_ctl_boolean_mono_info(struct snd_kcontrol *kcontrol, |
166 | struct snd_ctl_elem_info *uinfo); | 166 | struct snd_ctl_elem_info *uinfo); |
167 | int snd_ctl_boolean_stereo_info(struct snd_kcontrol *kcontrol, | 167 | int snd_ctl_boolean_stereo_info(struct snd_kcontrol *kcontrol, |
168 | struct snd_ctl_elem_info *uinfo); | 168 | struct snd_ctl_elem_info *uinfo); |
169 | int snd_ctl_enum_info(struct snd_ctl_elem_info *info, unsigned int channels, | ||
170 | unsigned int items, const char *const names[]); | ||
169 | 171 | ||
170 | /* | 172 | /* |
171 | * virtual master control | 173 | * virtual master control |
diff --git a/include/sound/hdsp.h b/include/sound/hdsp.h index d98a78dff2db..0909a3843479 100644 --- a/include/sound/hdsp.h +++ b/include/sound/hdsp.h | |||
@@ -28,6 +28,7 @@ enum HDSP_IO_Type { | |||
28 | Multiface, | 28 | Multiface, |
29 | H9652, | 29 | H9652, |
30 | H9632, | 30 | H9632, |
31 | RPM, | ||
31 | Undefined, | 32 | Undefined, |
32 | }; | 33 | }; |
33 | 34 | ||
diff --git a/include/sound/minors.h b/include/sound/minors.h index a81798ab73ed..8f764204a856 100644 --- a/include/sound/minors.h +++ b/include/sound/minors.h | |||
@@ -31,8 +31,8 @@ | |||
31 | /* these minors can still be used for autoloading devices (/dev/aload*) */ | 31 | /* these minors can still be used for autoloading devices (/dev/aload*) */ |
32 | #define SNDRV_MINOR_CONTROL 0 /* 0 */ | 32 | #define SNDRV_MINOR_CONTROL 0 /* 0 */ |
33 | #define SNDRV_MINOR_GLOBAL 1 /* 1 */ | 33 | #define SNDRV_MINOR_GLOBAL 1 /* 1 */ |
34 | #define SNDRV_MINOR_SEQUENCER (SNDRV_MINOR_GLOBAL + 0 * 32) | 34 | #define SNDRV_MINOR_SEQUENCER 1 /* SNDRV_MINOR_GLOBAL + 0 * 32 */ |
35 | #define SNDRV_MINOR_TIMER (SNDRV_MINOR_GLOBAL + 1 * 32) | 35 | #define SNDRV_MINOR_TIMER 33 /* SNDRV_MINOR_GLOBAL + 1 * 32 */ |
36 | 36 | ||
37 | #ifndef CONFIG_SND_DYNAMIC_MINORS | 37 | #ifndef CONFIG_SND_DYNAMIC_MINORS |
38 | /* 2 - 3 (reserved) */ | 38 | /* 2 - 3 (reserved) */ |
diff --git a/include/sound/pcm.h b/include/sound/pcm.h index dfd9b76b1853..e731f8d71934 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h | |||
@@ -297,6 +297,7 @@ struct snd_pcm_runtime { | |||
297 | unsigned int info; | 297 | unsigned int info; |
298 | unsigned int rate_num; | 298 | unsigned int rate_num; |
299 | unsigned int rate_den; | 299 | unsigned int rate_den; |
300 | unsigned int no_period_wakeup: 1; | ||
300 | 301 | ||
301 | /* -- SW params -- */ | 302 | /* -- SW params -- */ |
302 | int tstamp_mode; /* mmap timestamp is updated */ | 303 | int tstamp_mode; /* mmap timestamp is updated */ |
diff --git a/sound/ac97_bus.c b/sound/ac97_bus.c index a351dd0a09c7..2b50cbe6aca9 100644 --- a/sound/ac97_bus.c +++ b/sound/ac97_bus.c | |||
@@ -19,8 +19,8 @@ | |||
19 | 19 | ||
20 | /* | 20 | /* |
21 | * Let drivers decide whether they want to support given codec from their | 21 | * Let drivers decide whether they want to support given codec from their |
22 | * probe method. Drivers have direct access to the struct snd_ac97 structure and may | 22 | * probe method. Drivers have direct access to the struct snd_ac97 |
23 | * decide based on the id field amongst other things. | 23 | * structure and may decide based on the id field amongst other things. |
24 | */ | 24 | */ |
25 | static int ac97_bus_match(struct device *dev, struct device_driver *drv) | 25 | static int ac97_bus_match(struct device *dev, struct device_driver *drv) |
26 | { | 26 | { |
diff --git a/sound/aoa/codecs/onyx.c b/sound/aoa/codecs/onyx.c index 91852e49910e..3687a6cc9881 100644 --- a/sound/aoa/codecs/onyx.c +++ b/sound/aoa/codecs/onyx.c | |||
@@ -1114,7 +1114,6 @@ static int onyx_i2c_remove(struct i2c_client *client) | |||
1114 | of_node_put(onyx->codec.node); | 1114 | of_node_put(onyx->codec.node); |
1115 | if (onyx->codec_info) | 1115 | if (onyx->codec_info) |
1116 | kfree(onyx->codec_info); | 1116 | kfree(onyx->codec_info); |
1117 | i2c_set_clientdata(client, onyx); | ||
1118 | kfree(onyx); | 1117 | kfree(onyx); |
1119 | return 0; | 1118 | return 0; |
1120 | } | 1119 | } |
diff --git a/sound/aoa/core/gpio-feature.c b/sound/aoa/core/gpio-feature.c index de8e03afa97b..faa317490545 100644 --- a/sound/aoa/core/gpio-feature.c +++ b/sound/aoa/core/gpio-feature.c | |||
@@ -287,10 +287,9 @@ static void ftr_gpio_exit(struct gpio_runtime *rt) | |||
287 | free_irq(linein_detect_irq, &rt->line_in_notify); | 287 | free_irq(linein_detect_irq, &rt->line_in_notify); |
288 | if (rt->line_out_notify.gpio_private) | 288 | if (rt->line_out_notify.gpio_private) |
289 | free_irq(lineout_detect_irq, &rt->line_out_notify); | 289 | free_irq(lineout_detect_irq, &rt->line_out_notify); |
290 | cancel_delayed_work(&rt->headphone_notify.work); | 290 | cancel_delayed_work_sync(&rt->headphone_notify.work); |
291 | cancel_delayed_work(&rt->line_in_notify.work); | 291 | cancel_delayed_work_sync(&rt->line_in_notify.work); |
292 | cancel_delayed_work(&rt->line_out_notify.work); | 292 | cancel_delayed_work_sync(&rt->line_out_notify.work); |
293 | flush_scheduled_work(); | ||
294 | mutex_destroy(&rt->headphone_notify.mutex); | 293 | mutex_destroy(&rt->headphone_notify.mutex); |
295 | mutex_destroy(&rt->line_in_notify.mutex); | 294 | mutex_destroy(&rt->line_in_notify.mutex); |
296 | mutex_destroy(&rt->line_out_notify.mutex); | 295 | mutex_destroy(&rt->line_out_notify.mutex); |
diff --git a/sound/aoa/core/gpio-pmf.c b/sound/aoa/core/gpio-pmf.c index 7e267c9379bc..c8d8a1a6f964 100644 --- a/sound/aoa/core/gpio-pmf.c +++ b/sound/aoa/core/gpio-pmf.c | |||
@@ -107,10 +107,9 @@ static void pmf_gpio_exit(struct gpio_runtime *rt) | |||
107 | 107 | ||
108 | /* make sure no work is pending before freeing | 108 | /* make sure no work is pending before freeing |
109 | * all things */ | 109 | * all things */ |
110 | cancel_delayed_work(&rt->headphone_notify.work); | 110 | cancel_delayed_work_sync(&rt->headphone_notify.work); |
111 | cancel_delayed_work(&rt->line_in_notify.work); | 111 | cancel_delayed_work_sync(&rt->line_in_notify.work); |
112 | cancel_delayed_work(&rt->line_out_notify.work); | 112 | cancel_delayed_work_sync(&rt->line_out_notify.work); |
113 | flush_scheduled_work(); | ||
114 | 113 | ||
115 | mutex_destroy(&rt->headphone_notify.mutex); | 114 | mutex_destroy(&rt->headphone_notify.mutex); |
116 | mutex_destroy(&rt->line_in_notify.mutex); | 115 | mutex_destroy(&rt->line_in_notify.mutex); |
diff --git a/sound/core/control.c b/sound/core/control.c index 45a818002d99..9ce00ed20fba 100644 --- a/sound/core/control.c +++ b/sound/core/control.c | |||
@@ -1488,7 +1488,7 @@ int snd_ctl_create(struct snd_card *card) | |||
1488 | } | 1488 | } |
1489 | 1489 | ||
1490 | /* | 1490 | /* |
1491 | * Frequently used control callbacks | 1491 | * Frequently used control callbacks/helpers |
1492 | */ | 1492 | */ |
1493 | int snd_ctl_boolean_mono_info(struct snd_kcontrol *kcontrol, | 1493 | int snd_ctl_boolean_mono_info(struct snd_kcontrol *kcontrol, |
1494 | struct snd_ctl_elem_info *uinfo) | 1494 | struct snd_ctl_elem_info *uinfo) |
@@ -1513,3 +1513,29 @@ int snd_ctl_boolean_stereo_info(struct snd_kcontrol *kcontrol, | |||
1513 | } | 1513 | } |
1514 | 1514 | ||
1515 | EXPORT_SYMBOL(snd_ctl_boolean_stereo_info); | 1515 | EXPORT_SYMBOL(snd_ctl_boolean_stereo_info); |
1516 | |||
1517 | /** | ||
1518 | * snd_ctl_enum_info - fills the info structure for an enumerated control | ||
1519 | * @info: the structure to be filled | ||
1520 | * @channels: the number of the control's channels; often one | ||
1521 | * @items: the number of control values; also the size of @names | ||
1522 | * @names: an array containing the names of all control values | ||
1523 | * | ||
1524 | * Sets all required fields in @info to their appropriate values. | ||
1525 | * If the control's accessibility is not the default (readable and writable), | ||
1526 | * the caller has to fill @info->access. | ||
1527 | */ | ||
1528 | int snd_ctl_enum_info(struct snd_ctl_elem_info *info, unsigned int channels, | ||
1529 | unsigned int items, const char *const names[]) | ||
1530 | { | ||
1531 | info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
1532 | info->count = channels; | ||
1533 | info->value.enumerated.items = items; | ||
1534 | if (info->value.enumerated.item >= items) | ||
1535 | info->value.enumerated.item = items - 1; | ||
1536 | strlcpy(info->value.enumerated.name, | ||
1537 | names[info->value.enumerated.item], | ||
1538 | sizeof(info->value.enumerated.name)); | ||
1539 | return 0; | ||
1540 | } | ||
1541 | EXPORT_SYMBOL(snd_ctl_enum_info); | ||
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index b753ec661fcf..a2e4eb324699 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c | |||
@@ -453,8 +453,10 @@ static int snd_pcm_hw_param_near(struct snd_pcm_substream *pcm, | |||
453 | } else { | 453 | } else { |
454 | *params = *save; | 454 | *params = *save; |
455 | max = snd_pcm_hw_param_max(pcm, params, var, max, &maxdir); | 455 | max = snd_pcm_hw_param_max(pcm, params, var, max, &maxdir); |
456 | if (max < 0) | 456 | if (max < 0) { |
457 | kfree(save); | ||
457 | return max; | 458 | return max; |
459 | } | ||
458 | last = 1; | 460 | last = 1; |
459 | } | 461 | } |
460 | _end: | 462 | _end: |
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 11446a1506da..a82e3756a72d 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c | |||
@@ -373,6 +373,27 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, | |||
373 | (unsigned long)new_hw_ptr, | 373 | (unsigned long)new_hw_ptr, |
374 | (unsigned long)runtime->hw_ptr_base); | 374 | (unsigned long)runtime->hw_ptr_base); |
375 | } | 375 | } |
376 | |||
377 | if (runtime->no_period_wakeup) { | ||
378 | /* | ||
379 | * Without regular period interrupts, we have to check | ||
380 | * the elapsed time to detect xruns. | ||
381 | */ | ||
382 | jdelta = jiffies - runtime->hw_ptr_jiffies; | ||
383 | if (jdelta < runtime->hw_ptr_buffer_jiffies / 2) | ||
384 | goto no_delta_check; | ||
385 | hdelta = jdelta - delta * HZ / runtime->rate; | ||
386 | while (hdelta > runtime->hw_ptr_buffer_jiffies / 2 + 1) { | ||
387 | delta += runtime->buffer_size; | ||
388 | hw_base += runtime->buffer_size; | ||
389 | if (hw_base >= runtime->boundary) | ||
390 | hw_base = 0; | ||
391 | new_hw_ptr = hw_base + pos; | ||
392 | hdelta -= runtime->hw_ptr_buffer_jiffies; | ||
393 | } | ||
394 | goto no_delta_check; | ||
395 | } | ||
396 | |||
376 | /* something must be really wrong */ | 397 | /* something must be really wrong */ |
377 | if (delta >= runtime->buffer_size + runtime->period_size) { | 398 | if (delta >= runtime->buffer_size + runtime->period_size) { |
378 | hw_ptr_error(substream, | 399 | hw_ptr_error(substream, |
@@ -442,6 +463,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, | |||
442 | (long)old_hw_ptr); | 463 | (long)old_hw_ptr); |
443 | } | 464 | } |
444 | 465 | ||
466 | no_delta_check: | ||
445 | if (runtime->status->hw_ptr == new_hw_ptr) | 467 | if (runtime->status->hw_ptr == new_hw_ptr) |
446 | return 0; | 468 | return 0; |
447 | 469 | ||
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index e82c1f97d99e..0db714e87a80 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c | |||
@@ -422,6 +422,9 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream, | |||
422 | runtime->info = params->info; | 422 | runtime->info = params->info; |
423 | runtime->rate_num = params->rate_num; | 423 | runtime->rate_num = params->rate_num; |
424 | runtime->rate_den = params->rate_den; | 424 | runtime->rate_den = params->rate_den; |
425 | runtime->no_period_wakeup = | ||
426 | (params->info & SNDRV_PCM_INFO_NO_PERIOD_WAKEUP) && | ||
427 | (params->flags & SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP); | ||
425 | 428 | ||
426 | bits = snd_pcm_format_physical_width(runtime->format); | 429 | bits = snd_pcm_format_physical_width(runtime->format); |
427 | runtime->sample_bits = bits; | 430 | runtime->sample_bits = bits; |
diff --git a/sound/core/seq/seq.c b/sound/core/seq/seq.c index bf09a5ad1865..119fddb6fc99 100644 --- a/sound/core/seq/seq.c +++ b/sound/core/seq/seq.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include "seq_timer.h" | 32 | #include "seq_timer.h" |
33 | #include "seq_system.h" | 33 | #include "seq_system.h" |
34 | #include "seq_info.h" | 34 | #include "seq_info.h" |
35 | #include <sound/minors.h> | ||
35 | #include <sound/seq_device.h> | 36 | #include <sound/seq_device.h> |
36 | 37 | ||
37 | #if defined(CONFIG_SND_SEQ_DUMMY_MODULE) | 38 | #if defined(CONFIG_SND_SEQ_DUMMY_MODULE) |
@@ -73,6 +74,9 @@ MODULE_PARM_DESC(seq_default_timer_subdevice, "The default timer subdevice numbe | |||
73 | module_param(seq_default_timer_resolution, int, 0644); | 74 | module_param(seq_default_timer_resolution, int, 0644); |
74 | MODULE_PARM_DESC(seq_default_timer_resolution, "The default timer resolution in Hz."); | 75 | MODULE_PARM_DESC(seq_default_timer_resolution, "The default timer resolution in Hz."); |
75 | 76 | ||
77 | MODULE_ALIAS_CHARDEV(CONFIG_SND_MAJOR, SNDRV_MINOR_SEQUENCER); | ||
78 | MODULE_ALIAS("devname:snd/seq"); | ||
79 | |||
76 | /* | 80 | /* |
77 | * INIT PART | 81 | * INIT PART |
78 | */ | 82 | */ |
diff --git a/sound/core/sound.c b/sound/core/sound.c index 66691fe437e6..1c7a3efe1778 100644 --- a/sound/core/sound.c +++ b/sound/core/sound.c | |||
@@ -188,14 +188,22 @@ static const struct file_operations snd_fops = | |||
188 | }; | 188 | }; |
189 | 189 | ||
190 | #ifdef CONFIG_SND_DYNAMIC_MINORS | 190 | #ifdef CONFIG_SND_DYNAMIC_MINORS |
191 | static int snd_find_free_minor(void) | 191 | static int snd_find_free_minor(int type) |
192 | { | 192 | { |
193 | int minor; | 193 | int minor; |
194 | 194 | ||
195 | /* static minors for module auto loading */ | ||
196 | if (type == SNDRV_DEVICE_TYPE_SEQUENCER) | ||
197 | return SNDRV_MINOR_SEQUENCER; | ||
198 | if (type == SNDRV_DEVICE_TYPE_TIMER) | ||
199 | return SNDRV_MINOR_TIMER; | ||
200 | |||
195 | for (minor = 0; minor < ARRAY_SIZE(snd_minors); ++minor) { | 201 | for (minor = 0; minor < ARRAY_SIZE(snd_minors); ++minor) { |
196 | /* skip minors still used statically for autoloading devices */ | 202 | /* skip static minors still used for module auto loading */ |
197 | if (SNDRV_MINOR_DEVICE(minor) == SNDRV_MINOR_CONTROL || | 203 | if (SNDRV_MINOR_DEVICE(minor) == SNDRV_MINOR_CONTROL) |
198 | minor == SNDRV_MINOR_SEQUENCER) | 204 | continue; |
205 | if (minor == SNDRV_MINOR_SEQUENCER || | ||
206 | minor == SNDRV_MINOR_TIMER) | ||
199 | continue; | 207 | continue; |
200 | if (!snd_minors[minor]) | 208 | if (!snd_minors[minor]) |
201 | return minor; | 209 | return minor; |
@@ -269,7 +277,7 @@ int snd_register_device_for_dev(int type, struct snd_card *card, int dev, | |||
269 | preg->private_data = private_data; | 277 | preg->private_data = private_data; |
270 | mutex_lock(&sound_mutex); | 278 | mutex_lock(&sound_mutex); |
271 | #ifdef CONFIG_SND_DYNAMIC_MINORS | 279 | #ifdef CONFIG_SND_DYNAMIC_MINORS |
272 | minor = snd_find_free_minor(); | 280 | minor = snd_find_free_minor(type); |
273 | #else | 281 | #else |
274 | minor = snd_kernel_minor(type, card, dev); | 282 | minor = snd_kernel_minor(type, card, dev); |
275 | if (minor >= 0 && snd_minors[minor]) | 283 | if (minor >= 0 && snd_minors[minor]) |
diff --git a/sound/core/timer.c b/sound/core/timer.c index 13afb60999b9..ed016329e911 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c | |||
@@ -34,8 +34,8 @@ | |||
34 | #include <sound/initval.h> | 34 | #include <sound/initval.h> |
35 | #include <linux/kmod.h> | 35 | #include <linux/kmod.h> |
36 | 36 | ||
37 | #if defined(CONFIG_SND_HPET) || defined(CONFIG_SND_HPET_MODULE) | 37 | #if defined(CONFIG_SND_HRTIMER) || defined(CONFIG_SND_HRTIMER_MODULE) |
38 | #define DEFAULT_TIMER_LIMIT 3 | 38 | #define DEFAULT_TIMER_LIMIT 4 |
39 | #elif defined(CONFIG_SND_RTCTIMER) || defined(CONFIG_SND_RTCTIMER_MODULE) | 39 | #elif defined(CONFIG_SND_RTCTIMER) || defined(CONFIG_SND_RTCTIMER_MODULE) |
40 | #define DEFAULT_TIMER_LIMIT 2 | 40 | #define DEFAULT_TIMER_LIMIT 2 |
41 | #else | 41 | #else |
@@ -52,6 +52,9 @@ MODULE_PARM_DESC(timer_limit, "Maximum global timers in system."); | |||
52 | module_param(timer_tstamp_monotonic, int, 0444); | 52 | module_param(timer_tstamp_monotonic, int, 0444); |
53 | MODULE_PARM_DESC(timer_tstamp_monotonic, "Use posix monotonic clock source for timestamps (default)."); | 53 | MODULE_PARM_DESC(timer_tstamp_monotonic, "Use posix monotonic clock source for timestamps (default)."); |
54 | 54 | ||
55 | MODULE_ALIAS_CHARDEV(CONFIG_SND_MAJOR, SNDRV_MINOR_TIMER); | ||
56 | MODULE_ALIAS("devname:snd/timer"); | ||
57 | |||
55 | struct snd_timer_user { | 58 | struct snd_timer_user { |
56 | struct snd_timer_instance *timeri; | 59 | struct snd_timer_instance *timeri; |
57 | int tread; /* enhanced read with timestamps and events */ | 60 | int tread; /* enhanced read with timestamps and events */ |
diff --git a/sound/drivers/ml403-ac97cr.c b/sound/drivers/ml403-ac97cr.c index a1282c1c0591..5cfcb908c430 100644 --- a/sound/drivers/ml403-ac97cr.c +++ b/sound/drivers/ml403-ac97cr.c | |||
@@ -1143,8 +1143,8 @@ snd_ml403_ac97cr_create(struct snd_card *card, struct platform_device *pfdev, | |||
1143 | (resource->start) + 1); | 1143 | (resource->start) + 1); |
1144 | if (ml403_ac97cr->port == NULL) { | 1144 | if (ml403_ac97cr->port == NULL) { |
1145 | snd_printk(KERN_ERR SND_ML403_AC97CR_DRIVER ": " | 1145 | snd_printk(KERN_ERR SND_ML403_AC97CR_DRIVER ": " |
1146 | "unable to remap memory region (%x to %x)\n", | 1146 | "unable to remap memory region (%pR)\n", |
1147 | resource->start, resource->end); | 1147 | resource); |
1148 | snd_ml403_ac97cr_free(ml403_ac97cr); | 1148 | snd_ml403_ac97cr_free(ml403_ac97cr); |
1149 | return -EBUSY; | 1149 | return -EBUSY; |
1150 | } | 1150 | } |
diff --git a/sound/i2c/other/ak4113.c b/sound/i2c/other/ak4113.c index 971a84a4fa77..c424d329f806 100644 --- a/sound/i2c/other/ak4113.c +++ b/sound/i2c/other/ak4113.c | |||
@@ -57,8 +57,7 @@ static void snd_ak4113_free(struct ak4113 *chip) | |||
57 | { | 57 | { |
58 | chip->init = 1; /* don't schedule new work */ | 58 | chip->init = 1; /* don't schedule new work */ |
59 | mb(); | 59 | mb(); |
60 | cancel_delayed_work(&chip->work); | 60 | cancel_delayed_work_sync(&chip->work); |
61 | flush_scheduled_work(); | ||
62 | kfree(chip); | 61 | kfree(chip); |
63 | } | 62 | } |
64 | 63 | ||
@@ -141,7 +140,7 @@ void snd_ak4113_reinit(struct ak4113 *chip) | |||
141 | { | 140 | { |
142 | chip->init = 1; | 141 | chip->init = 1; |
143 | mb(); | 142 | mb(); |
144 | flush_scheduled_work(); | 143 | flush_delayed_work_sync(&chip->work); |
145 | ak4113_init_regs(chip); | 144 | ak4113_init_regs(chip); |
146 | /* bring up statistics / event queing */ | 145 | /* bring up statistics / event queing */ |
147 | chip->init = 0; | 146 | chip->init = 0; |
diff --git a/sound/i2c/other/ak4114.c b/sound/i2c/other/ak4114.c index 0341451f814c..d9fb537b0b94 100644 --- a/sound/i2c/other/ak4114.c +++ b/sound/i2c/other/ak4114.c | |||
@@ -67,8 +67,7 @@ static void snd_ak4114_free(struct ak4114 *chip) | |||
67 | { | 67 | { |
68 | chip->init = 1; /* don't schedule new work */ | 68 | chip->init = 1; /* don't schedule new work */ |
69 | mb(); | 69 | mb(); |
70 | cancel_delayed_work(&chip->work); | 70 | cancel_delayed_work_sync(&chip->work); |
71 | flush_scheduled_work(); | ||
72 | kfree(chip); | 71 | kfree(chip); |
73 | } | 72 | } |
74 | 73 | ||
@@ -154,7 +153,7 @@ void snd_ak4114_reinit(struct ak4114 *chip) | |||
154 | { | 153 | { |
155 | chip->init = 1; | 154 | chip->init = 1; |
156 | mb(); | 155 | mb(); |
157 | flush_scheduled_work(); | 156 | flush_delayed_work_sync(&chip->work); |
158 | ak4114_init_regs(chip); | 157 | ak4114_init_regs(chip); |
159 | /* bring up statistics / event queing */ | 158 | /* bring up statistics / event queing */ |
160 | chip->init = 0; | 159 | chip->init = 0; |
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 12e34653b8a8..9823d59d7ad7 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig | |||
@@ -209,7 +209,7 @@ config SND_OXYGEN_LIB | |||
209 | tristate | 209 | tristate |
210 | 210 | ||
211 | config SND_OXYGEN | 211 | config SND_OXYGEN |
212 | tristate "C-Media 8788 (Oxygen)" | 212 | tristate "C-Media 8786, 8787, 8788 (Oxygen)" |
213 | select SND_OXYGEN_LIB | 213 | select SND_OXYGEN_LIB |
214 | select SND_PCM | 214 | select SND_PCM |
215 | select SND_MPU401_UART | 215 | select SND_MPU401_UART |
@@ -217,13 +217,18 @@ config SND_OXYGEN | |||
217 | Say Y here to include support for sound cards based on the | 217 | Say Y here to include support for sound cards based on the |
218 | C-Media CMI8788 (Oxygen HD Audio) chip: | 218 | C-Media CMI8788 (Oxygen HD Audio) chip: |
219 | * Asound A-8788 | 219 | * Asound A-8788 |
220 | * Asus Xonar DG | ||
220 | * AuzenTech X-Meridian | 221 | * AuzenTech X-Meridian |
222 | * AuzenTech X-Meridian 2G | ||
221 | * Bgears b-Enspirer | 223 | * Bgears b-Enspirer |
222 | * Club3D Theatron DTS | 224 | * Club3D Theatron DTS |
223 | * HT-Omega Claro (plus) | 225 | * HT-Omega Claro (plus) |
224 | * HT-Omega Claro halo (XT) | 226 | * HT-Omega Claro halo (XT) |
227 | * Kuroutoshikou CMI8787-HG2PCI | ||
225 | * Razer Barracuda AC-1 | 228 | * Razer Barracuda AC-1 |
226 | * Sondigo Inferno | 229 | * Sondigo Inferno |
230 | * TempoTec/MediaTek HiFier Fantasia | ||
231 | * TempoTec/MediaTek HiFier Serenade | ||
227 | 232 | ||
228 | To compile this driver as a module, choose M here: the module | 233 | To compile this driver as a module, choose M here: the module |
229 | will be called snd-oxygen. | 234 | will be called snd-oxygen. |
@@ -578,18 +583,6 @@ config SND_HDSPM | |||
578 | To compile this driver as a module, choose M here: the module | 583 | To compile this driver as a module, choose M here: the module |
579 | will be called snd-hdspm. | 584 | will be called snd-hdspm. |
580 | 585 | ||
581 | config SND_HIFIER | ||
582 | tristate "TempoTec HiFier Fantasia" | ||
583 | select SND_OXYGEN_LIB | ||
584 | select SND_PCM | ||
585 | select SND_MPU401_UART | ||
586 | help | ||
587 | Say Y here to include support for the MediaTek/TempoTec HiFier | ||
588 | Fantasia sound card. | ||
589 | |||
590 | To compile this driver as a module, choose M here: the module | ||
591 | will be called snd-hifier. | ||
592 | |||
593 | config SND_ICE1712 | 586 | config SND_ICE1712 |
594 | tristate "ICEnsemble ICE1712 (Envy24)" | 587 | tristate "ICEnsemble ICE1712 (Envy24)" |
595 | select SND_MPU401_UART | 588 | select SND_MPU401_UART |
@@ -826,8 +819,8 @@ config SND_VIRTUOSO | |||
826 | Say Y here to include support for sound cards based on the | 819 | Say Y here to include support for sound cards based on the |
827 | Asus AV66/AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X, DS, | 820 | Asus AV66/AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X, DS, |
828 | Essence ST (Deluxe), and Essence STX. | 821 | Essence ST (Deluxe), and Essence STX. |
829 | Support for the HDAV1.3 (Deluxe) is incomplete; for the | 822 | Support for the HDAV1.3 (Deluxe) and HDAV1.3 Slim is experimental; |
830 | HDAV1.3 Slim and Xense, missing. | 823 | for the Xense, missing. |
831 | 824 | ||
832 | To compile this driver as a module, choose M here: the module | 825 | To compile this driver as a module, choose M here: the module |
833 | will be called snd-virtuoso. | 826 | will be called snd-virtuoso. |
diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index a7630e9edf8a..0fc614ce16c1 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c | |||
@@ -1014,8 +1014,7 @@ static int snd_ac97_free(struct snd_ac97 *ac97) | |||
1014 | { | 1014 | { |
1015 | if (ac97) { | 1015 | if (ac97) { |
1016 | #ifdef CONFIG_SND_AC97_POWER_SAVE | 1016 | #ifdef CONFIG_SND_AC97_POWER_SAVE |
1017 | cancel_delayed_work(&ac97->power_work); | 1017 | cancel_delayed_work_sync(&ac97->power_work); |
1018 | flush_scheduled_work(); | ||
1019 | #endif | 1018 | #endif |
1020 | snd_ac97_proc_done(ac97); | 1019 | snd_ac97_proc_done(ac97); |
1021 | if (ac97->bus) | 1020 | if (ac97->bus) |
@@ -2456,8 +2455,7 @@ void snd_ac97_suspend(struct snd_ac97 *ac97) | |||
2456 | if (ac97->build_ops->suspend) | 2455 | if (ac97->build_ops->suspend) |
2457 | ac97->build_ops->suspend(ac97); | 2456 | ac97->build_ops->suspend(ac97); |
2458 | #ifdef CONFIG_SND_AC97_POWER_SAVE | 2457 | #ifdef CONFIG_SND_AC97_POWER_SAVE |
2459 | cancel_delayed_work(&ac97->power_work); | 2458 | cancel_delayed_work_sync(&ac97->power_work); |
2460 | flush_scheduled_work(); | ||
2461 | #endif | 2459 | #endif |
2462 | snd_ac97_powerdown(ac97); | 2460 | snd_ac97_powerdown(ac97); |
2463 | } | 2461 | } |
diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c index 2f3cacbd5528..6117595fc075 100644 --- a/sound/pci/azt3328.c +++ b/sound/pci/azt3328.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * azt3328.c - driver for Aztech AZF3328 based soundcards (e.g. PCI168). | 2 | * azt3328.c - driver for Aztech AZF3328 based soundcards (e.g. PCI168). |
3 | * Copyright (C) 2002, 2005 - 2009 by Andreas Mohr <andi AT lisas.de> | 3 | * Copyright (C) 2002, 2005 - 2010 by Andreas Mohr <andi AT lisas.de> |
4 | * | 4 | * |
5 | * Framework borrowed from Bart Hartgers's als4000.c. | 5 | * Framework borrowed from Bart Hartgers's als4000.c. |
6 | * Driver developed on PCI168 AP(W) version (PCI rev. 10, subsystem ID 1801), | 6 | * Driver developed on PCI168 AP(W) version (PCI rev. 10, subsystem ID 1801), |
@@ -175,6 +175,7 @@ | |||
175 | 175 | ||
176 | #include <asm/io.h> | 176 | #include <asm/io.h> |
177 | #include <linux/init.h> | 177 | #include <linux/init.h> |
178 | #include <linux/bug.h> /* WARN_ONCE */ | ||
178 | #include <linux/pci.h> | 179 | #include <linux/pci.h> |
179 | #include <linux/delay.h> | 180 | #include <linux/delay.h> |
180 | #include <linux/slab.h> | 181 | #include <linux/slab.h> |
@@ -201,14 +202,15 @@ MODULE_SUPPORTED_DEVICE("{{Aztech,AZF3328}}"); | |||
201 | 202 | ||
202 | /* === Debug settings === | 203 | /* === Debug settings === |
203 | Further diagnostic functionality than the settings below | 204 | Further diagnostic functionality than the settings below |
204 | does not need to be provided, since one can easily write a bash script | 205 | does not need to be provided, since one can easily write a POSIX shell script |
205 | to dump the card's I/O ports (those listed in lspci -v -v): | 206 | to dump the card's I/O ports (those listed in lspci -v -v): |
206 | function dump() | 207 | dump() |
207 | { | 208 | { |
208 | local descr=$1; local addr=$2; local count=$3 | 209 | local descr=$1; local addr=$2; local count=$3 |
209 | 210 | ||
210 | echo "${descr}: ${count} @ ${addr}:" | 211 | echo "${descr}: ${count} @ ${addr}:" |
211 | dd if=/dev/port skip=$[${addr}] count=${count} bs=1 2>/dev/null| hexdump -C | 212 | dd if=/dev/port skip=`printf %d ${addr}` count=${count} bs=1 \ |
213 | 2>/dev/null| hexdump -C | ||
212 | } | 214 | } |
213 | and then use something like | 215 | and then use something like |
214 | "dump joy200 0x200 8", "dump mpu388 0x388 4", "dump joy 0xb400 8", | 216 | "dump joy200 0x200 8", "dump mpu388 0x388 4", "dump joy 0xb400 8", |
@@ -216,14 +218,14 @@ MODULE_SUPPORTED_DEVICE("{{Aztech,AZF3328}}"); | |||
216 | possibly within a "while true; do ... sleep 1; done" loop. | 218 | possibly within a "while true; do ... sleep 1; done" loop. |
217 | Tweaking ports could be done using | 219 | Tweaking ports could be done using |
218 | VALSTRING="`printf "%02x" $value`" | 220 | VALSTRING="`printf "%02x" $value`" |
219 | printf "\x""$VALSTRING"|dd of=/dev/port seek=$[${addr}] bs=1 2>/dev/null | 221 | printf "\x""$VALSTRING"|dd of=/dev/port seek=`printf %d ${addr}` bs=1 \ |
222 | 2>/dev/null | ||
220 | */ | 223 | */ |
221 | 224 | ||
222 | #define DEBUG_MISC 0 | 225 | #define DEBUG_MISC 0 |
223 | #define DEBUG_CALLS 0 | 226 | #define DEBUG_CALLS 0 |
224 | #define DEBUG_MIXER 0 | 227 | #define DEBUG_MIXER 0 |
225 | #define DEBUG_CODEC 0 | 228 | #define DEBUG_CODEC 0 |
226 | #define DEBUG_IO 0 | ||
227 | #define DEBUG_TIMER 0 | 229 | #define DEBUG_TIMER 0 |
228 | #define DEBUG_GAME 0 | 230 | #define DEBUG_GAME 0 |
229 | #define DEBUG_PM 0 | 231 | #define DEBUG_PM 0 |
@@ -291,19 +293,23 @@ static int seqtimer_scaling = 128; | |||
291 | module_param(seqtimer_scaling, int, 0444); | 293 | module_param(seqtimer_scaling, int, 0444); |
292 | MODULE_PARM_DESC(seqtimer_scaling, "Set 1024000Hz sequencer timer scale factor (lockup danger!). Default 128."); | 294 | MODULE_PARM_DESC(seqtimer_scaling, "Set 1024000Hz sequencer timer scale factor (lockup danger!). Default 128."); |
293 | 295 | ||
294 | struct snd_azf3328_codec_data { | ||
295 | unsigned long io_base; | ||
296 | struct snd_pcm_substream *substream; | ||
297 | bool running; | ||
298 | const char *name; | ||
299 | }; | ||
300 | |||
301 | enum snd_azf3328_codec_type { | 296 | enum snd_azf3328_codec_type { |
297 | /* warning: fixed indices (also used for bitmask checks!) */ | ||
302 | AZF_CODEC_PLAYBACK = 0, | 298 | AZF_CODEC_PLAYBACK = 0, |
303 | AZF_CODEC_CAPTURE = 1, | 299 | AZF_CODEC_CAPTURE = 1, |
304 | AZF_CODEC_I2S_OUT = 2, | 300 | AZF_CODEC_I2S_OUT = 2, |
305 | }; | 301 | }; |
306 | 302 | ||
303 | struct snd_azf3328_codec_data { | ||
304 | unsigned long io_base; /* keep first! (avoid offset calc) */ | ||
305 | unsigned int dma_base; /* helper to avoid an indirection in hotpath */ | ||
306 | spinlock_t *lock; /* TODO: convert to our own per-codec lock member */ | ||
307 | struct snd_pcm_substream *substream; | ||
308 | bool running; | ||
309 | enum snd_azf3328_codec_type type; | ||
310 | const char *name; | ||
311 | }; | ||
312 | |||
307 | struct snd_azf3328 { | 313 | struct snd_azf3328 { |
308 | /* often-used fields towards beginning, then grouped */ | 314 | /* often-used fields towards beginning, then grouped */ |
309 | 315 | ||
@@ -362,6 +368,9 @@ MODULE_DEVICE_TABLE(pci, snd_azf3328_ids); | |||
362 | static int | 368 | static int |
363 | snd_azf3328_io_reg_setb(unsigned reg, u8 mask, bool do_set) | 369 | snd_azf3328_io_reg_setb(unsigned reg, u8 mask, bool do_set) |
364 | { | 370 | { |
371 | /* Well, strictly spoken, the inb/outb sequence isn't atomic | ||
372 | and would need locking. However we currently don't care | ||
373 | since it potentially complicates matters. */ | ||
365 | u8 prev = inb(reg), new; | 374 | u8 prev = inb(reg), new; |
366 | 375 | ||
367 | new = (do_set) ? (prev|mask) : (prev & ~mask); | 376 | new = (do_set) ? (prev|mask) : (prev & ~mask); |
@@ -413,6 +422,21 @@ snd_azf3328_codec_outl(const struct snd_azf3328_codec_data *codec, | |||
413 | outl(value, codec->io_base + reg); | 422 | outl(value, codec->io_base + reg); |
414 | } | 423 | } |
415 | 424 | ||
425 | static inline void | ||
426 | snd_azf3328_codec_outl_multi(const struct snd_azf3328_codec_data *codec, | ||
427 | unsigned reg, const void *buffer, int count | ||
428 | ) | ||
429 | { | ||
430 | unsigned long addr = codec->io_base + reg; | ||
431 | if (count) { | ||
432 | const u32 *buf = buffer; | ||
433 | do { | ||
434 | outl(*buf++, addr); | ||
435 | addr += 4; | ||
436 | } while (--count); | ||
437 | } | ||
438 | } | ||
439 | |||
416 | static inline u32 | 440 | static inline u32 |
417 | snd_azf3328_codec_inl(const struct snd_azf3328_codec_data *codec, unsigned reg) | 441 | snd_azf3328_codec_inl(const struct snd_azf3328_codec_data *codec, unsigned reg) |
418 | { | 442 | { |
@@ -943,38 +967,43 @@ snd_azf3328_hw_free(struct snd_pcm_substream *substream) | |||
943 | } | 967 | } |
944 | 968 | ||
945 | static void | 969 | static void |
946 | snd_azf3328_codec_setfmt(struct snd_azf3328 *chip, | 970 | snd_azf3328_codec_setfmt(struct snd_azf3328_codec_data *codec, |
947 | enum snd_azf3328_codec_type codec_type, | ||
948 | enum azf_freq_t bitrate, | 971 | enum azf_freq_t bitrate, |
949 | unsigned int format_width, | 972 | unsigned int format_width, |
950 | unsigned int channels | 973 | unsigned int channels |
951 | ) | 974 | ) |
952 | { | 975 | { |
953 | unsigned long flags; | 976 | unsigned long flags; |
954 | const struct snd_azf3328_codec_data *codec = &chip->codecs[codec_type]; | ||
955 | u16 val = 0xff00; | 977 | u16 val = 0xff00; |
978 | u8 freq = 0; | ||
956 | 979 | ||
957 | snd_azf3328_dbgcallenter(); | 980 | snd_azf3328_dbgcallenter(); |
958 | switch (bitrate) { | 981 | switch (bitrate) { |
959 | case AZF_FREQ_4000: val |= SOUNDFORMAT_FREQ_SUSPECTED_4000; break; | 982 | #define AZF_FMT_XLATE(in_freq, out_bits) \ |
960 | case AZF_FREQ_4800: val |= SOUNDFORMAT_FREQ_SUSPECTED_4800; break; | 983 | do { \ |
961 | case AZF_FREQ_5512: | 984 | case AZF_FREQ_ ## in_freq: \ |
962 | /* the AZF3328 names it "5510" for some strange reason */ | 985 | freq = SOUNDFORMAT_FREQ_ ## out_bits; \ |
963 | val |= SOUNDFORMAT_FREQ_5510; break; | 986 | break; \ |
964 | case AZF_FREQ_6620: val |= SOUNDFORMAT_FREQ_6620; break; | 987 | } while (0); |
965 | case AZF_FREQ_8000: val |= SOUNDFORMAT_FREQ_8000; break; | 988 | AZF_FMT_XLATE(4000, SUSPECTED_4000) |
966 | case AZF_FREQ_9600: val |= SOUNDFORMAT_FREQ_9600; break; | 989 | AZF_FMT_XLATE(4800, SUSPECTED_4800) |
967 | case AZF_FREQ_11025: val |= SOUNDFORMAT_FREQ_11025; break; | 990 | /* the AZF3328 names it "5510" for some strange reason: */ |
968 | case AZF_FREQ_13240: val |= SOUNDFORMAT_FREQ_SUSPECTED_13240; break; | 991 | AZF_FMT_XLATE(5512, 5510) |
969 | case AZF_FREQ_16000: val |= SOUNDFORMAT_FREQ_16000; break; | 992 | AZF_FMT_XLATE(6620, 6620) |
970 | case AZF_FREQ_22050: val |= SOUNDFORMAT_FREQ_22050; break; | 993 | AZF_FMT_XLATE(8000, 8000) |
971 | case AZF_FREQ_32000: val |= SOUNDFORMAT_FREQ_32000; break; | 994 | AZF_FMT_XLATE(9600, 9600) |
995 | AZF_FMT_XLATE(11025, 11025) | ||
996 | AZF_FMT_XLATE(13240, SUSPECTED_13240) | ||
997 | AZF_FMT_XLATE(16000, 16000) | ||
998 | AZF_FMT_XLATE(22050, 22050) | ||
999 | AZF_FMT_XLATE(32000, 32000) | ||
972 | default: | 1000 | default: |
973 | snd_printk(KERN_WARNING "unknown bitrate %d, assuming 44.1kHz!\n", bitrate); | 1001 | snd_printk(KERN_WARNING "unknown bitrate %d, assuming 44.1kHz!\n", bitrate); |
974 | /* fall-through */ | 1002 | /* fall-through */ |
975 | case AZF_FREQ_44100: val |= SOUNDFORMAT_FREQ_44100; break; | 1003 | AZF_FMT_XLATE(44100, 44100) |
976 | case AZF_FREQ_48000: val |= SOUNDFORMAT_FREQ_48000; break; | 1004 | AZF_FMT_XLATE(48000, 48000) |
977 | case AZF_FREQ_66200: val |= SOUNDFORMAT_FREQ_SUSPECTED_66200; break; | 1005 | AZF_FMT_XLATE(66200, SUSPECTED_66200) |
1006 | #undef AZF_FMT_XLATE | ||
978 | } | 1007 | } |
979 | /* val = 0xff07; 3m27.993s (65301Hz; -> 64000Hz???) hmm, 66120, 65967, 66123 */ | 1008 | /* val = 0xff07; 3m27.993s (65301Hz; -> 64000Hz???) hmm, 66120, 65967, 66123 */ |
980 | /* val = 0xff09; 17m15.098s (13123,478Hz; -> 12000Hz???) hmm, 13237.2Hz? */ | 1009 | /* val = 0xff09; 17m15.098s (13123,478Hz; -> 12000Hz???) hmm, 13237.2Hz? */ |
@@ -986,13 +1015,15 @@ snd_azf3328_codec_setfmt(struct snd_azf3328 *chip, | |||
986 | /* val = 0xff0d; 41m23.135s (5523,600Hz; -> 5512Hz???) */ | 1015 | /* val = 0xff0d; 41m23.135s (5523,600Hz; -> 5512Hz???) */ |
987 | /* val = 0xff0e; 28m30.777s (8017Hz; -> 8000Hz???) */ | 1016 | /* val = 0xff0e; 28m30.777s (8017Hz; -> 8000Hz???) */ |
988 | 1017 | ||
1018 | val |= freq; | ||
1019 | |||
989 | if (channels == 2) | 1020 | if (channels == 2) |
990 | val |= SOUNDFORMAT_FLAG_2CHANNELS; | 1021 | val |= SOUNDFORMAT_FLAG_2CHANNELS; |
991 | 1022 | ||
992 | if (format_width == 16) | 1023 | if (format_width == 16) |
993 | val |= SOUNDFORMAT_FLAG_16BIT; | 1024 | val |= SOUNDFORMAT_FLAG_16BIT; |
994 | 1025 | ||
995 | spin_lock_irqsave(&chip->reg_lock, flags); | 1026 | spin_lock_irqsave(codec->lock, flags); |
996 | 1027 | ||
997 | /* set bitrate/format */ | 1028 | /* set bitrate/format */ |
998 | snd_azf3328_codec_outw(codec, IDX_IO_CODEC_SOUNDFORMAT, val); | 1029 | snd_azf3328_codec_outw(codec, IDX_IO_CODEC_SOUNDFORMAT, val); |
@@ -1004,7 +1035,8 @@ snd_azf3328_codec_setfmt(struct snd_azf3328 *chip, | |||
1004 | * (FIXME: yes, it works, but what exactly am I doing here?? :) | 1035 | * (FIXME: yes, it works, but what exactly am I doing here?? :) |
1005 | * FIXME: does this have some side effects for full-duplex | 1036 | * FIXME: does this have some side effects for full-duplex |
1006 | * or other dramatic side effects? */ | 1037 | * or other dramatic side effects? */ |
1007 | if (codec_type == AZF_CODEC_PLAYBACK) /* only do it for playback */ | 1038 | /* do it for non-capture codecs only */ |
1039 | if (codec->type != AZF_CODEC_CAPTURE) | ||
1008 | snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, | 1040 | snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, |
1009 | snd_azf3328_codec_inw(codec, IDX_IO_CODEC_DMA_FLAGS) | | 1041 | snd_azf3328_codec_inw(codec, IDX_IO_CODEC_DMA_FLAGS) | |
1010 | DMA_RUN_SOMETHING1 | | 1042 | DMA_RUN_SOMETHING1 | |
@@ -1014,20 +1046,19 @@ snd_azf3328_codec_setfmt(struct snd_azf3328 *chip, | |||
1014 | DMA_SOMETHING_ELSE | 1046 | DMA_SOMETHING_ELSE |
1015 | ); | 1047 | ); |
1016 | 1048 | ||
1017 | spin_unlock_irqrestore(&chip->reg_lock, flags); | 1049 | spin_unlock_irqrestore(codec->lock, flags); |
1018 | snd_azf3328_dbgcallleave(); | 1050 | snd_azf3328_dbgcallleave(); |
1019 | } | 1051 | } |
1020 | 1052 | ||
1021 | static inline void | 1053 | static inline void |
1022 | snd_azf3328_codec_setfmt_lowpower(struct snd_azf3328 *chip, | 1054 | snd_azf3328_codec_setfmt_lowpower(struct snd_azf3328_codec_data *codec |
1023 | enum snd_azf3328_codec_type codec_type | ||
1024 | ) | 1055 | ) |
1025 | { | 1056 | { |
1026 | /* choose lowest frequency for low power consumption. | 1057 | /* choose lowest frequency for low power consumption. |
1027 | * While this will cause louder noise due to rather coarse frequency, | 1058 | * While this will cause louder noise due to rather coarse frequency, |
1028 | * it should never matter since output should always | 1059 | * it should never matter since output should always |
1029 | * get disabled properly when idle anyway. */ | 1060 | * get disabled properly when idle anyway. */ |
1030 | snd_azf3328_codec_setfmt(chip, codec_type, AZF_FREQ_4000, 8, 1); | 1061 | snd_azf3328_codec_setfmt(codec, AZF_FREQ_4000, 8, 1); |
1031 | } | 1062 | } |
1032 | 1063 | ||
1033 | static void | 1064 | static void |
@@ -1101,69 +1132,87 @@ snd_azf3328_ctrl_codec_activity(struct snd_azf3328 *chip, | |||
1101 | /* ...and adjust clock, too | 1132 | /* ...and adjust clock, too |
1102 | * (reduce noise and power consumption) */ | 1133 | * (reduce noise and power consumption) */ |
1103 | if (!enable) | 1134 | if (!enable) |
1104 | snd_azf3328_codec_setfmt_lowpower( | 1135 | snd_azf3328_codec_setfmt_lowpower(codec); |
1105 | chip, | ||
1106 | codec_type | ||
1107 | ); | ||
1108 | codec->running = enable; | 1136 | codec->running = enable; |
1109 | } | 1137 | } |
1110 | } | 1138 | } |
1111 | 1139 | ||
1112 | static void | 1140 | static void |
1113 | snd_azf3328_codec_setdmaa(struct snd_azf3328 *chip, | 1141 | snd_azf3328_codec_setdmaa(struct snd_azf3328_codec_data *codec, |
1114 | enum snd_azf3328_codec_type codec_type, | ||
1115 | unsigned long addr, | 1142 | unsigned long addr, |
1116 | unsigned int count, | 1143 | unsigned int period_bytes, |
1117 | unsigned int size | 1144 | unsigned int buffer_bytes |
1118 | ) | 1145 | ) |
1119 | { | 1146 | { |
1120 | const struct snd_azf3328_codec_data *codec = &chip->codecs[codec_type]; | ||
1121 | snd_azf3328_dbgcallenter(); | 1147 | snd_azf3328_dbgcallenter(); |
1148 | WARN_ONCE(period_bytes & 1, "odd period length!?\n"); | ||
1149 | WARN_ONCE(buffer_bytes != 2 * period_bytes, | ||
1150 | "missed our input expectations! %u vs. %u\n", | ||
1151 | buffer_bytes, period_bytes); | ||
1122 | if (!codec->running) { | 1152 | if (!codec->running) { |
1123 | /* AZF3328 uses a two buffer pointer DMA transfer approach */ | 1153 | /* AZF3328 uses a two buffer pointer DMA transfer approach */ |
1124 | 1154 | ||
1125 | unsigned long flags, addr_area2; | 1155 | unsigned long flags; |
1126 | 1156 | ||
1127 | /* width 32bit (prevent overflow): */ | 1157 | /* width 32bit (prevent overflow): */ |
1128 | u32 count_areas, lengths; | 1158 | u32 area_length; |
1159 | struct codec_setup_io { | ||
1160 | u32 dma_start_1; | ||
1161 | u32 dma_start_2; | ||
1162 | u32 dma_lengths; | ||
1163 | } __attribute__((packed)) setup_io; | ||
1164 | |||
1165 | area_length = buffer_bytes/2; | ||
1166 | |||
1167 | setup_io.dma_start_1 = addr; | ||
1168 | setup_io.dma_start_2 = addr+area_length; | ||
1129 | 1169 | ||
1130 | count_areas = size/2; | 1170 | snd_azf3328_dbgcodec( |
1131 | addr_area2 = addr+count_areas; | 1171 | "setdma: buffers %08x[%u] / %08x[%u], %u, %u\n", |
1132 | snd_azf3328_dbgcodec("setdma: buffers %08lx[%u] / %08lx[%u]\n", | 1172 | setup_io.dma_start_1, area_length, |
1133 | addr, count_areas, addr_area2, count_areas); | 1173 | setup_io.dma_start_2, area_length, |
1174 | period_bytes, buffer_bytes); | ||
1134 | 1175 | ||
1135 | count_areas--; /* max. index */ | 1176 | /* Hmm, are we really supposed to decrement this by 1?? |
1177 | Most definitely certainly not: configuring full length does | ||
1178 | work properly (i.e. likely better), and BTW we | ||
1179 | violated possibly differing frame sizes with this... | ||
1180 | |||
1181 | area_length--; |* max. index *| | ||
1182 | */ | ||
1136 | 1183 | ||
1137 | /* build combined I/O buffer length word */ | 1184 | /* build combined I/O buffer length word */ |
1138 | lengths = (count_areas << 16) | (count_areas); | 1185 | setup_io.dma_lengths = (area_length << 16) | (area_length); |
1139 | spin_lock_irqsave(&chip->reg_lock, flags); | 1186 | |
1140 | snd_azf3328_codec_outl(codec, IDX_IO_CODEC_DMA_START_1, addr); | 1187 | spin_lock_irqsave(codec->lock, flags); |
1141 | snd_azf3328_codec_outl(codec, IDX_IO_CODEC_DMA_START_2, | 1188 | snd_azf3328_codec_outl_multi( |
1142 | addr_area2); | 1189 | codec, IDX_IO_CODEC_DMA_START_1, &setup_io, 3 |
1143 | snd_azf3328_codec_outl(codec, IDX_IO_CODEC_DMA_LENGTHS, | 1190 | ); |
1144 | lengths); | 1191 | spin_unlock_irqrestore(codec->lock, flags); |
1145 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
1146 | } | 1192 | } |
1147 | snd_azf3328_dbgcallleave(); | 1193 | snd_azf3328_dbgcallleave(); |
1148 | } | 1194 | } |
1149 | 1195 | ||
1150 | static int | 1196 | static int |
1151 | snd_azf3328_codec_prepare(struct snd_pcm_substream *substream) | 1197 | snd_azf3328_pcm_prepare(struct snd_pcm_substream *substream) |
1152 | { | 1198 | { |
1153 | #if 0 | ||
1154 | struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); | ||
1155 | struct snd_pcm_runtime *runtime = substream->runtime; | 1199 | struct snd_pcm_runtime *runtime = substream->runtime; |
1200 | struct snd_azf3328_codec_data *codec = runtime->private_data; | ||
1201 | #if 0 | ||
1156 | unsigned int size = snd_pcm_lib_buffer_bytes(substream); | 1202 | unsigned int size = snd_pcm_lib_buffer_bytes(substream); |
1157 | unsigned int count = snd_pcm_lib_period_bytes(substream); | 1203 | unsigned int count = snd_pcm_lib_period_bytes(substream); |
1158 | #endif | 1204 | #endif |
1159 | 1205 | ||
1160 | snd_azf3328_dbgcallenter(); | 1206 | snd_azf3328_dbgcallenter(); |
1207 | |||
1208 | codec->dma_base = runtime->dma_addr; | ||
1209 | |||
1161 | #if 0 | 1210 | #if 0 |
1162 | snd_azf3328_codec_setfmt(chip, AZF_CODEC_..., | 1211 | snd_azf3328_codec_setfmt(codec, |
1163 | runtime->rate, | 1212 | runtime->rate, |
1164 | snd_pcm_format_width(runtime->format), | 1213 | snd_pcm_format_width(runtime->format), |
1165 | runtime->channels); | 1214 | runtime->channels); |
1166 | snd_azf3328_codec_setdmaa(chip, AZF_CODEC_..., | 1215 | snd_azf3328_codec_setdmaa(codec, |
1167 | runtime->dma_addr, count, size); | 1216 | runtime->dma_addr, count, size); |
1168 | #endif | 1217 | #endif |
1169 | snd_azf3328_dbgcallleave(); | 1218 | snd_azf3328_dbgcallleave(); |
@@ -1171,24 +1220,23 @@ snd_azf3328_codec_prepare(struct snd_pcm_substream *substream) | |||
1171 | } | 1220 | } |
1172 | 1221 | ||
1173 | static int | 1222 | static int |
1174 | snd_azf3328_codec_trigger(enum snd_azf3328_codec_type codec_type, | 1223 | snd_azf3328_pcm_trigger(struct snd_pcm_substream *substream, int cmd) |
1175 | struct snd_pcm_substream *substream, int cmd) | ||
1176 | { | 1224 | { |
1177 | struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); | 1225 | struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); |
1178 | const struct snd_azf3328_codec_data *codec = &chip->codecs[codec_type]; | ||
1179 | struct snd_pcm_runtime *runtime = substream->runtime; | 1226 | struct snd_pcm_runtime *runtime = substream->runtime; |
1227 | struct snd_azf3328_codec_data *codec = runtime->private_data; | ||
1180 | int result = 0; | 1228 | int result = 0; |
1181 | u16 flags1; | 1229 | u16 flags1; |
1182 | bool previously_muted = 0; | 1230 | bool previously_muted = 0; |
1183 | bool is_playback_codec = (AZF_CODEC_PLAYBACK == codec_type); | 1231 | bool is_main_mixer_playback_codec = (AZF_CODEC_PLAYBACK == codec->type); |
1184 | 1232 | ||
1185 | snd_azf3328_dbgcalls("snd_azf3328_codec_trigger cmd %d\n", cmd); | 1233 | snd_azf3328_dbgcalls("snd_azf3328_pcm_trigger cmd %d\n", cmd); |
1186 | 1234 | ||
1187 | switch (cmd) { | 1235 | switch (cmd) { |
1188 | case SNDRV_PCM_TRIGGER_START: | 1236 | case SNDRV_PCM_TRIGGER_START: |
1189 | snd_azf3328_dbgcodec("START %s\n", codec->name); | 1237 | snd_azf3328_dbgcodec("START %s\n", codec->name); |
1190 | 1238 | ||
1191 | if (is_playback_codec) { | 1239 | if (is_main_mixer_playback_codec) { |
1192 | /* mute WaveOut (avoid clicking during setup) */ | 1240 | /* mute WaveOut (avoid clicking during setup) */ |
1193 | previously_muted = | 1241 | previously_muted = |
1194 | snd_azf3328_mixer_set_mute( | 1242 | snd_azf3328_mixer_set_mute( |
@@ -1196,12 +1244,12 @@ snd_azf3328_codec_trigger(enum snd_azf3328_codec_type codec_type, | |||
1196 | ); | 1244 | ); |
1197 | } | 1245 | } |
1198 | 1246 | ||
1199 | snd_azf3328_codec_setfmt(chip, codec_type, | 1247 | snd_azf3328_codec_setfmt(codec, |
1200 | runtime->rate, | 1248 | runtime->rate, |
1201 | snd_pcm_format_width(runtime->format), | 1249 | snd_pcm_format_width(runtime->format), |
1202 | runtime->channels); | 1250 | runtime->channels); |
1203 | 1251 | ||
1204 | spin_lock(&chip->reg_lock); | 1252 | spin_lock(codec->lock); |
1205 | /* first, remember current value: */ | 1253 | /* first, remember current value: */ |
1206 | flags1 = snd_azf3328_codec_inw(codec, IDX_IO_CODEC_DMA_FLAGS); | 1254 | flags1 = snd_azf3328_codec_inw(codec, IDX_IO_CODEC_DMA_FLAGS); |
1207 | 1255 | ||
@@ -1211,14 +1259,14 @@ snd_azf3328_codec_trigger(enum snd_azf3328_codec_type codec_type, | |||
1211 | 1259 | ||
1212 | /* FIXME: clear interrupts or what??? */ | 1260 | /* FIXME: clear interrupts or what??? */ |
1213 | snd_azf3328_codec_outw(codec, IDX_IO_CODEC_IRQTYPE, 0xffff); | 1261 | snd_azf3328_codec_outw(codec, IDX_IO_CODEC_IRQTYPE, 0xffff); |
1214 | spin_unlock(&chip->reg_lock); | 1262 | spin_unlock(codec->lock); |
1215 | 1263 | ||
1216 | snd_azf3328_codec_setdmaa(chip, codec_type, runtime->dma_addr, | 1264 | snd_azf3328_codec_setdmaa(codec, runtime->dma_addr, |
1217 | snd_pcm_lib_period_bytes(substream), | 1265 | snd_pcm_lib_period_bytes(substream), |
1218 | snd_pcm_lib_buffer_bytes(substream) | 1266 | snd_pcm_lib_buffer_bytes(substream) |
1219 | ); | 1267 | ); |
1220 | 1268 | ||
1221 | spin_lock(&chip->reg_lock); | 1269 | spin_lock(codec->lock); |
1222 | #ifdef WIN9X | 1270 | #ifdef WIN9X |
1223 | /* FIXME: enable playback/recording??? */ | 1271 | /* FIXME: enable playback/recording??? */ |
1224 | flags1 |= DMA_RUN_SOMETHING1 | DMA_RUN_SOMETHING2; | 1272 | flags1 |= DMA_RUN_SOMETHING1 | DMA_RUN_SOMETHING2; |
@@ -1242,10 +1290,10 @@ snd_azf3328_codec_trigger(enum snd_azf3328_codec_type codec_type, | |||
1242 | DMA_EPILOGUE_SOMETHING | | 1290 | DMA_EPILOGUE_SOMETHING | |
1243 | DMA_SOMETHING_ELSE); | 1291 | DMA_SOMETHING_ELSE); |
1244 | #endif | 1292 | #endif |
1245 | spin_unlock(&chip->reg_lock); | 1293 | spin_unlock(codec->lock); |
1246 | snd_azf3328_ctrl_codec_activity(chip, codec_type, 1); | 1294 | snd_azf3328_ctrl_codec_activity(chip, codec->type, 1); |
1247 | 1295 | ||
1248 | if (is_playback_codec) { | 1296 | if (is_main_mixer_playback_codec) { |
1249 | /* now unmute WaveOut */ | 1297 | /* now unmute WaveOut */ |
1250 | if (!previously_muted) | 1298 | if (!previously_muted) |
1251 | snd_azf3328_mixer_set_mute( | 1299 | snd_azf3328_mixer_set_mute( |
@@ -1258,19 +1306,19 @@ snd_azf3328_codec_trigger(enum snd_azf3328_codec_type codec_type, | |||
1258 | case SNDRV_PCM_TRIGGER_RESUME: | 1306 | case SNDRV_PCM_TRIGGER_RESUME: |
1259 | snd_azf3328_dbgcodec("RESUME %s\n", codec->name); | 1307 | snd_azf3328_dbgcodec("RESUME %s\n", codec->name); |
1260 | /* resume codec if we were active */ | 1308 | /* resume codec if we were active */ |
1261 | spin_lock(&chip->reg_lock); | 1309 | spin_lock(codec->lock); |
1262 | if (codec->running) | 1310 | if (codec->running) |
1263 | snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, | 1311 | snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, |
1264 | snd_azf3328_codec_inw( | 1312 | snd_azf3328_codec_inw( |
1265 | codec, IDX_IO_CODEC_DMA_FLAGS | 1313 | codec, IDX_IO_CODEC_DMA_FLAGS |
1266 | ) | DMA_RESUME | 1314 | ) | DMA_RESUME |
1267 | ); | 1315 | ); |
1268 | spin_unlock(&chip->reg_lock); | 1316 | spin_unlock(codec->lock); |
1269 | break; | 1317 | break; |
1270 | case SNDRV_PCM_TRIGGER_STOP: | 1318 | case SNDRV_PCM_TRIGGER_STOP: |
1271 | snd_azf3328_dbgcodec("STOP %s\n", codec->name); | 1319 | snd_azf3328_dbgcodec("STOP %s\n", codec->name); |
1272 | 1320 | ||
1273 | if (is_playback_codec) { | 1321 | if (is_main_mixer_playback_codec) { |
1274 | /* mute WaveOut (avoid clicking during setup) */ | 1322 | /* mute WaveOut (avoid clicking during setup) */ |
1275 | previously_muted = | 1323 | previously_muted = |
1276 | snd_azf3328_mixer_set_mute( | 1324 | snd_azf3328_mixer_set_mute( |
@@ -1278,7 +1326,7 @@ snd_azf3328_codec_trigger(enum snd_azf3328_codec_type codec_type, | |||
1278 | ); | 1326 | ); |
1279 | } | 1327 | } |
1280 | 1328 | ||
1281 | spin_lock(&chip->reg_lock); | 1329 | spin_lock(codec->lock); |
1282 | /* first, remember current value: */ | 1330 | /* first, remember current value: */ |
1283 | flags1 = snd_azf3328_codec_inw(codec, IDX_IO_CODEC_DMA_FLAGS); | 1331 | flags1 = snd_azf3328_codec_inw(codec, IDX_IO_CODEC_DMA_FLAGS); |
1284 | 1332 | ||
@@ -1293,10 +1341,10 @@ snd_azf3328_codec_trigger(enum snd_azf3328_codec_type codec_type, | |||
1293 | 1341 | ||
1294 | flags1 &= ~DMA_RUN_SOMETHING1; | 1342 | flags1 &= ~DMA_RUN_SOMETHING1; |
1295 | snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, flags1); | 1343 | snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, flags1); |
1296 | spin_unlock(&chip->reg_lock); | 1344 | spin_unlock(codec->lock); |
1297 | snd_azf3328_ctrl_codec_activity(chip, codec_type, 0); | 1345 | snd_azf3328_ctrl_codec_activity(chip, codec->type, 0); |
1298 | 1346 | ||
1299 | if (is_playback_codec) { | 1347 | if (is_main_mixer_playback_codec) { |
1300 | /* now unmute WaveOut */ | 1348 | /* now unmute WaveOut */ |
1301 | if (!previously_muted) | 1349 | if (!previously_muted) |
1302 | snd_azf3328_mixer_set_mute( | 1350 | snd_azf3328_mixer_set_mute( |
@@ -1330,67 +1378,29 @@ snd_azf3328_codec_trigger(enum snd_azf3328_codec_type codec_type, | |||
1330 | return result; | 1378 | return result; |
1331 | } | 1379 | } |
1332 | 1380 | ||
1333 | static int | ||
1334 | snd_azf3328_codec_playback_trigger(struct snd_pcm_substream *substream, int cmd) | ||
1335 | { | ||
1336 | return snd_azf3328_codec_trigger(AZF_CODEC_PLAYBACK, substream, cmd); | ||
1337 | } | ||
1338 | |||
1339 | static int | ||
1340 | snd_azf3328_codec_capture_trigger(struct snd_pcm_substream *substream, int cmd) | ||
1341 | { | ||
1342 | return snd_azf3328_codec_trigger(AZF_CODEC_CAPTURE, substream, cmd); | ||
1343 | } | ||
1344 | |||
1345 | static int | ||
1346 | snd_azf3328_codec_i2s_out_trigger(struct snd_pcm_substream *substream, int cmd) | ||
1347 | { | ||
1348 | return snd_azf3328_codec_trigger(AZF_CODEC_I2S_OUT, substream, cmd); | ||
1349 | } | ||
1350 | |||
1351 | static snd_pcm_uframes_t | 1381 | static snd_pcm_uframes_t |
1352 | snd_azf3328_codec_pointer(struct snd_pcm_substream *substream, | 1382 | snd_azf3328_pcm_pointer(struct snd_pcm_substream *substream |
1353 | enum snd_azf3328_codec_type codec_type | ||
1354 | ) | 1383 | ) |
1355 | { | 1384 | { |
1356 | const struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); | 1385 | const struct snd_azf3328_codec_data *codec = |
1357 | const struct snd_azf3328_codec_data *codec = &chip->codecs[codec_type]; | 1386 | substream->runtime->private_data; |
1358 | unsigned long bufptr, result; | 1387 | unsigned long result; |
1359 | snd_pcm_uframes_t frmres; | 1388 | snd_pcm_uframes_t frmres; |
1360 | 1389 | ||
1361 | #ifdef QUERY_HARDWARE | ||
1362 | bufptr = snd_azf3328_codec_inl(codec, IDX_IO_CODEC_DMA_START_1); | ||
1363 | #else | ||
1364 | bufptr = substream->runtime->dma_addr; | ||
1365 | #endif | ||
1366 | result = snd_azf3328_codec_inl(codec, IDX_IO_CODEC_DMA_CURRPOS); | 1390 | result = snd_azf3328_codec_inl(codec, IDX_IO_CODEC_DMA_CURRPOS); |
1367 | 1391 | ||
1368 | /* calculate offset */ | 1392 | /* calculate offset */ |
1369 | result -= bufptr; | 1393 | #ifdef QUERY_HARDWARE |
1394 | result -= snd_azf3328_codec_inl(codec, IDX_IO_CODEC_DMA_START_1); | ||
1395 | #else | ||
1396 | result -= codec->dma_base; | ||
1397 | #endif | ||
1370 | frmres = bytes_to_frames( substream->runtime, result); | 1398 | frmres = bytes_to_frames( substream->runtime, result); |
1371 | snd_azf3328_dbgcodec("%s @ 0x%8lx, frames %8ld\n", | 1399 | snd_azf3328_dbgcodec("%08li %s @ 0x%8lx, frames %8ld\n", |
1372 | codec->name, result, frmres); | 1400 | jiffies, codec->name, result, frmres); |
1373 | return frmres; | 1401 | return frmres; |
1374 | } | 1402 | } |
1375 | 1403 | ||
1376 | static snd_pcm_uframes_t | ||
1377 | snd_azf3328_codec_playback_pointer(struct snd_pcm_substream *substream) | ||
1378 | { | ||
1379 | return snd_azf3328_codec_pointer(substream, AZF_CODEC_PLAYBACK); | ||
1380 | } | ||
1381 | |||
1382 | static snd_pcm_uframes_t | ||
1383 | snd_azf3328_codec_capture_pointer(struct snd_pcm_substream *substream) | ||
1384 | { | ||
1385 | return snd_azf3328_codec_pointer(substream, AZF_CODEC_CAPTURE); | ||
1386 | } | ||
1387 | |||
1388 | static snd_pcm_uframes_t | ||
1389 | snd_azf3328_codec_i2s_out_pointer(struct snd_pcm_substream *substream) | ||
1390 | { | ||
1391 | return snd_azf3328_codec_pointer(substream, AZF_CODEC_I2S_OUT); | ||
1392 | } | ||
1393 | |||
1394 | /******************************************************************/ | 1404 | /******************************************************************/ |
1395 | 1405 | ||
1396 | #ifdef SUPPORT_GAMEPORT | 1406 | #ifdef SUPPORT_GAMEPORT |
@@ -1532,7 +1542,7 @@ snd_azf3328_gameport_cooked_read(struct gameport *gameport, | |||
1532 | } | 1542 | } |
1533 | } | 1543 | } |
1534 | 1544 | ||
1535 | /* trigger next axes sampling, to be evaluated the next time we | 1545 | /* trigger next sampling of axes, to be evaluated the next time we |
1536 | * enter this function */ | 1546 | * enter this function */ |
1537 | 1547 | ||
1538 | /* for some very, very strange reason we cannot enable | 1548 | /* for some very, very strange reason we cannot enable |
@@ -1624,29 +1634,29 @@ snd_azf3328_irq_log_unknown_type(u8 which) | |||
1624 | } | 1634 | } |
1625 | 1635 | ||
1626 | static inline void | 1636 | static inline void |
1627 | snd_azf3328_codec_interrupt(struct snd_azf3328 *chip, u8 status) | 1637 | snd_azf3328_pcm_interrupt(const struct snd_azf3328_codec_data *first_codec, |
1638 | u8 status | ||
1639 | ) | ||
1628 | { | 1640 | { |
1629 | u8 which; | 1641 | u8 which; |
1630 | enum snd_azf3328_codec_type codec_type; | 1642 | enum snd_azf3328_codec_type codec_type; |
1631 | const struct snd_azf3328_codec_data *codec; | 1643 | const struct snd_azf3328_codec_data *codec = first_codec; |
1632 | 1644 | ||
1633 | for (codec_type = AZF_CODEC_PLAYBACK; | 1645 | for (codec_type = AZF_CODEC_PLAYBACK; |
1634 | codec_type <= AZF_CODEC_I2S_OUT; | 1646 | codec_type <= AZF_CODEC_I2S_OUT; |
1635 | ++codec_type) { | 1647 | ++codec_type, ++codec) { |
1636 | 1648 | ||
1637 | /* skip codec if there's no interrupt for it */ | 1649 | /* skip codec if there's no interrupt for it */ |
1638 | if (!(status & (1 << codec_type))) | 1650 | if (!(status & (1 << codec_type))) |
1639 | continue; | 1651 | continue; |
1640 | 1652 | ||
1641 | codec = &chip->codecs[codec_type]; | 1653 | spin_lock(codec->lock); |
1642 | |||
1643 | spin_lock(&chip->reg_lock); | ||
1644 | which = snd_azf3328_codec_inb(codec, IDX_IO_CODEC_IRQTYPE); | 1654 | which = snd_azf3328_codec_inb(codec, IDX_IO_CODEC_IRQTYPE); |
1645 | /* ack all IRQ types immediately */ | 1655 | /* ack all IRQ types immediately */ |
1646 | snd_azf3328_codec_outb(codec, IDX_IO_CODEC_IRQTYPE, which); | 1656 | snd_azf3328_codec_outb(codec, IDX_IO_CODEC_IRQTYPE, which); |
1647 | spin_unlock(&chip->reg_lock); | 1657 | spin_unlock(codec->lock); |
1648 | 1658 | ||
1649 | if ((chip->pcm[codec_type]) && (codec->substream)) { | 1659 | if (codec->substream) { |
1650 | snd_pcm_period_elapsed(codec->substream); | 1660 | snd_pcm_period_elapsed(codec->substream); |
1651 | snd_azf3328_dbgcodec("%s period done (#%x), @ %x\n", | 1661 | snd_azf3328_dbgcodec("%s period done (#%x), @ %x\n", |
1652 | codec->name, | 1662 | codec->name, |
@@ -1701,7 +1711,7 @@ snd_azf3328_interrupt(int irq, void *dev_id) | |||
1701 | } | 1711 | } |
1702 | 1712 | ||
1703 | if (status & (IRQ_PLAYBACK|IRQ_RECORDING|IRQ_I2S_OUT)) | 1713 | if (status & (IRQ_PLAYBACK|IRQ_RECORDING|IRQ_I2S_OUT)) |
1704 | snd_azf3328_codec_interrupt(chip, status); | 1714 | snd_azf3328_pcm_interrupt(chip->codecs, status); |
1705 | 1715 | ||
1706 | if (status & IRQ_GAMEPORT) | 1716 | if (status & IRQ_GAMEPORT) |
1707 | snd_azf3328_gameport_interrupt(chip); | 1717 | snd_azf3328_gameport_interrupt(chip); |
@@ -1789,101 +1799,85 @@ snd_azf3328_pcm_open(struct snd_pcm_substream *substream, | |||
1789 | { | 1799 | { |
1790 | struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); | 1800 | struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); |
1791 | struct snd_pcm_runtime *runtime = substream->runtime; | 1801 | struct snd_pcm_runtime *runtime = substream->runtime; |
1802 | struct snd_azf3328_codec_data *codec = &chip->codecs[codec_type]; | ||
1792 | 1803 | ||
1793 | snd_azf3328_dbgcallenter(); | 1804 | snd_azf3328_dbgcallenter(); |
1794 | chip->codecs[codec_type].substream = substream; | 1805 | codec->substream = substream; |
1795 | 1806 | ||
1796 | /* same parameters for all our codecs - at least we think so... */ | 1807 | /* same parameters for all our codecs - at least we think so... */ |
1797 | runtime->hw = snd_azf3328_hardware; | 1808 | runtime->hw = snd_azf3328_hardware; |
1798 | 1809 | ||
1799 | snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, | 1810 | snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, |
1800 | &snd_azf3328_hw_constraints_rates); | 1811 | &snd_azf3328_hw_constraints_rates); |
1812 | runtime->private_data = codec; | ||
1801 | snd_azf3328_dbgcallleave(); | 1813 | snd_azf3328_dbgcallleave(); |
1802 | return 0; | 1814 | return 0; |
1803 | } | 1815 | } |
1804 | 1816 | ||
1805 | static int | 1817 | static int |
1806 | snd_azf3328_playback_open(struct snd_pcm_substream *substream) | 1818 | snd_azf3328_pcm_playback_open(struct snd_pcm_substream *substream) |
1807 | { | 1819 | { |
1808 | return snd_azf3328_pcm_open(substream, AZF_CODEC_PLAYBACK); | 1820 | return snd_azf3328_pcm_open(substream, AZF_CODEC_PLAYBACK); |
1809 | } | 1821 | } |
1810 | 1822 | ||
1811 | static int | 1823 | static int |
1812 | snd_azf3328_capture_open(struct snd_pcm_substream *substream) | 1824 | snd_azf3328_pcm_capture_open(struct snd_pcm_substream *substream) |
1813 | { | 1825 | { |
1814 | return snd_azf3328_pcm_open(substream, AZF_CODEC_CAPTURE); | 1826 | return snd_azf3328_pcm_open(substream, AZF_CODEC_CAPTURE); |
1815 | } | 1827 | } |
1816 | 1828 | ||
1817 | static int | 1829 | static int |
1818 | snd_azf3328_i2s_out_open(struct snd_pcm_substream *substream) | 1830 | snd_azf3328_pcm_i2s_out_open(struct snd_pcm_substream *substream) |
1819 | { | 1831 | { |
1820 | return snd_azf3328_pcm_open(substream, AZF_CODEC_I2S_OUT); | 1832 | return snd_azf3328_pcm_open(substream, AZF_CODEC_I2S_OUT); |
1821 | } | 1833 | } |
1822 | 1834 | ||
1823 | static int | 1835 | static int |
1824 | snd_azf3328_pcm_close(struct snd_pcm_substream *substream, | 1836 | snd_azf3328_pcm_close(struct snd_pcm_substream *substream |
1825 | enum snd_azf3328_codec_type codec_type | ||
1826 | ) | 1837 | ) |
1827 | { | 1838 | { |
1828 | struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); | 1839 | struct snd_azf3328_codec_data *codec = |
1840 | substream->runtime->private_data; | ||
1829 | 1841 | ||
1830 | snd_azf3328_dbgcallenter(); | 1842 | snd_azf3328_dbgcallenter(); |
1831 | chip->codecs[codec_type].substream = NULL; | 1843 | codec->substream = NULL; |
1832 | snd_azf3328_dbgcallleave(); | 1844 | snd_azf3328_dbgcallleave(); |
1833 | return 0; | 1845 | return 0; |
1834 | } | 1846 | } |
1835 | 1847 | ||
1836 | static int | ||
1837 | snd_azf3328_playback_close(struct snd_pcm_substream *substream) | ||
1838 | { | ||
1839 | return snd_azf3328_pcm_close(substream, AZF_CODEC_PLAYBACK); | ||
1840 | } | ||
1841 | |||
1842 | static int | ||
1843 | snd_azf3328_capture_close(struct snd_pcm_substream *substream) | ||
1844 | { | ||
1845 | return snd_azf3328_pcm_close(substream, AZF_CODEC_CAPTURE); | ||
1846 | } | ||
1847 | |||
1848 | static int | ||
1849 | snd_azf3328_i2s_out_close(struct snd_pcm_substream *substream) | ||
1850 | { | ||
1851 | return snd_azf3328_pcm_close(substream, AZF_CODEC_I2S_OUT); | ||
1852 | } | ||
1853 | |||
1854 | /******************************************************************/ | 1848 | /******************************************************************/ |
1855 | 1849 | ||
1856 | static struct snd_pcm_ops snd_azf3328_playback_ops = { | 1850 | static struct snd_pcm_ops snd_azf3328_playback_ops = { |
1857 | .open = snd_azf3328_playback_open, | 1851 | .open = snd_azf3328_pcm_playback_open, |
1858 | .close = snd_azf3328_playback_close, | 1852 | .close = snd_azf3328_pcm_close, |
1859 | .ioctl = snd_pcm_lib_ioctl, | 1853 | .ioctl = snd_pcm_lib_ioctl, |
1860 | .hw_params = snd_azf3328_hw_params, | 1854 | .hw_params = snd_azf3328_hw_params, |
1861 | .hw_free = snd_azf3328_hw_free, | 1855 | .hw_free = snd_azf3328_hw_free, |
1862 | .prepare = snd_azf3328_codec_prepare, | 1856 | .prepare = snd_azf3328_pcm_prepare, |
1863 | .trigger = snd_azf3328_codec_playback_trigger, | 1857 | .trigger = snd_azf3328_pcm_trigger, |
1864 | .pointer = snd_azf3328_codec_playback_pointer | 1858 | .pointer = snd_azf3328_pcm_pointer |
1865 | }; | 1859 | }; |
1866 | 1860 | ||
1867 | static struct snd_pcm_ops snd_azf3328_capture_ops = { | 1861 | static struct snd_pcm_ops snd_azf3328_capture_ops = { |
1868 | .open = snd_azf3328_capture_open, | 1862 | .open = snd_azf3328_pcm_capture_open, |
1869 | .close = snd_azf3328_capture_close, | 1863 | .close = snd_azf3328_pcm_close, |
1870 | .ioctl = snd_pcm_lib_ioctl, | 1864 | .ioctl = snd_pcm_lib_ioctl, |
1871 | .hw_params = snd_azf3328_hw_params, | 1865 | .hw_params = snd_azf3328_hw_params, |
1872 | .hw_free = snd_azf3328_hw_free, | 1866 | .hw_free = snd_azf3328_hw_free, |
1873 | .prepare = snd_azf3328_codec_prepare, | 1867 | .prepare = snd_azf3328_pcm_prepare, |
1874 | .trigger = snd_azf3328_codec_capture_trigger, | 1868 | .trigger = snd_azf3328_pcm_trigger, |
1875 | .pointer = snd_azf3328_codec_capture_pointer | 1869 | .pointer = snd_azf3328_pcm_pointer |
1876 | }; | 1870 | }; |
1877 | 1871 | ||
1878 | static struct snd_pcm_ops snd_azf3328_i2s_out_ops = { | 1872 | static struct snd_pcm_ops snd_azf3328_i2s_out_ops = { |
1879 | .open = snd_azf3328_i2s_out_open, | 1873 | .open = snd_azf3328_pcm_i2s_out_open, |
1880 | .close = snd_azf3328_i2s_out_close, | 1874 | .close = snd_azf3328_pcm_close, |
1881 | .ioctl = snd_pcm_lib_ioctl, | 1875 | .ioctl = snd_pcm_lib_ioctl, |
1882 | .hw_params = snd_azf3328_hw_params, | 1876 | .hw_params = snd_azf3328_hw_params, |
1883 | .hw_free = snd_azf3328_hw_free, | 1877 | .hw_free = snd_azf3328_hw_free, |
1884 | .prepare = snd_azf3328_codec_prepare, | 1878 | .prepare = snd_azf3328_pcm_prepare, |
1885 | .trigger = snd_azf3328_codec_i2s_out_trigger, | 1879 | .trigger = snd_azf3328_pcm_trigger, |
1886 | .pointer = snd_azf3328_codec_i2s_out_pointer | 1880 | .pointer = snd_azf3328_pcm_pointer |
1887 | }; | 1881 | }; |
1888 | 1882 | ||
1889 | static int __devinit | 1883 | static int __devinit |
@@ -1966,7 +1960,7 @@ snd_azf3328_timer_start(struct snd_timer *timer) | |||
1966 | snd_azf3328_dbgtimer("delay was too low (%d)!\n", delay); | 1960 | snd_azf3328_dbgtimer("delay was too low (%d)!\n", delay); |
1967 | delay = 49; /* minimum time is 49 ticks */ | 1961 | delay = 49; /* minimum time is 49 ticks */ |
1968 | } | 1962 | } |
1969 | snd_azf3328_dbgtimer("setting timer countdown value %d, add COUNTDOWN|IRQ\n", delay); | 1963 | snd_azf3328_dbgtimer("setting timer countdown value %d\n", delay); |
1970 | delay |= TIMER_COUNTDOWN_ENABLE | TIMER_IRQ_ENABLE; | 1964 | delay |= TIMER_COUNTDOWN_ENABLE | TIMER_IRQ_ENABLE; |
1971 | spin_lock_irqsave(&chip->reg_lock, flags); | 1965 | spin_lock_irqsave(&chip->reg_lock, flags); |
1972 | snd_azf3328_ctrl_outl(chip, IDX_IO_TIMER_VALUE, delay); | 1966 | snd_azf3328_ctrl_outl(chip, IDX_IO_TIMER_VALUE, delay); |
@@ -2180,6 +2174,7 @@ snd_azf3328_create(struct snd_card *card, | |||
2180 | }; | 2174 | }; |
2181 | u8 dma_init; | 2175 | u8 dma_init; |
2182 | enum snd_azf3328_codec_type codec_type; | 2176 | enum snd_azf3328_codec_type codec_type; |
2177 | struct snd_azf3328_codec_data *codec_setup; | ||
2183 | 2178 | ||
2184 | *rchip = NULL; | 2179 | *rchip = NULL; |
2185 | 2180 | ||
@@ -2217,15 +2212,23 @@ snd_azf3328_create(struct snd_card *card, | |||
2217 | chip->opl3_io = pci_resource_start(pci, 3); | 2212 | chip->opl3_io = pci_resource_start(pci, 3); |
2218 | chip->mixer_io = pci_resource_start(pci, 4); | 2213 | chip->mixer_io = pci_resource_start(pci, 4); |
2219 | 2214 | ||
2220 | chip->codecs[AZF_CODEC_PLAYBACK].io_base = | 2215 | codec_setup = &chip->codecs[AZF_CODEC_PLAYBACK]; |
2221 | chip->ctrl_io + AZF_IO_OFFS_CODEC_PLAYBACK; | 2216 | codec_setup->io_base = chip->ctrl_io + AZF_IO_OFFS_CODEC_PLAYBACK; |
2222 | chip->codecs[AZF_CODEC_PLAYBACK].name = "PLAYBACK"; | 2217 | codec_setup->lock = &chip->reg_lock; |
2223 | chip->codecs[AZF_CODEC_CAPTURE].io_base = | 2218 | codec_setup->type = AZF_CODEC_PLAYBACK; |
2224 | chip->ctrl_io + AZF_IO_OFFS_CODEC_CAPTURE; | 2219 | codec_setup->name = "PLAYBACK"; |
2225 | chip->codecs[AZF_CODEC_CAPTURE].name = "CAPTURE"; | 2220 | |
2226 | chip->codecs[AZF_CODEC_I2S_OUT].io_base = | 2221 | codec_setup = &chip->codecs[AZF_CODEC_CAPTURE]; |
2227 | chip->ctrl_io + AZF_IO_OFFS_CODEC_I2S_OUT; | 2222 | codec_setup->io_base = chip->ctrl_io + AZF_IO_OFFS_CODEC_CAPTURE; |
2228 | chip->codecs[AZF_CODEC_I2S_OUT].name = "I2S_OUT"; | 2223 | codec_setup->lock = &chip->reg_lock; |
2224 | codec_setup->type = AZF_CODEC_CAPTURE; | ||
2225 | codec_setup->name = "CAPTURE"; | ||
2226 | |||
2227 | codec_setup = &chip->codecs[AZF_CODEC_I2S_OUT]; | ||
2228 | codec_setup->io_base = chip->ctrl_io + AZF_IO_OFFS_CODEC_I2S_OUT; | ||
2229 | codec_setup->lock = &chip->reg_lock; | ||
2230 | codec_setup->type = AZF_CODEC_I2S_OUT; | ||
2231 | codec_setup->name = "I2S_OUT"; | ||
2229 | 2232 | ||
2230 | if (request_irq(pci->irq, snd_azf3328_interrupt, | 2233 | if (request_irq(pci->irq, snd_azf3328_interrupt, |
2231 | IRQF_SHARED, card->shortname, chip)) { | 2234 | IRQF_SHARED, card->shortname, chip)) { |
@@ -2257,15 +2260,15 @@ snd_azf3328_create(struct snd_card *card, | |||
2257 | struct snd_azf3328_codec_data *codec = | 2260 | struct snd_azf3328_codec_data *codec = |
2258 | &chip->codecs[codec_type]; | 2261 | &chip->codecs[codec_type]; |
2259 | 2262 | ||
2260 | /* shutdown codecs to save power */ | 2263 | /* shutdown codecs to reduce power / noise */ |
2261 | /* have ...ctrl_codec_activity() act properly */ | 2264 | /* have ...ctrl_codec_activity() act properly */ |
2262 | codec->running = 1; | 2265 | codec->running = 1; |
2263 | snd_azf3328_ctrl_codec_activity(chip, codec_type, 0); | 2266 | snd_azf3328_ctrl_codec_activity(chip, codec_type, 0); |
2264 | 2267 | ||
2265 | spin_lock_irq(&chip->reg_lock); | 2268 | spin_lock_irq(codec->lock); |
2266 | snd_azf3328_codec_outb(codec, IDX_IO_CODEC_DMA_FLAGS, | 2269 | snd_azf3328_codec_outb(codec, IDX_IO_CODEC_DMA_FLAGS, |
2267 | dma_init); | 2270 | dma_init); |
2268 | spin_unlock_irq(&chip->reg_lock); | 2271 | spin_unlock_irq(codec->lock); |
2269 | } | 2272 | } |
2270 | 2273 | ||
2271 | snd_card_set_dev(card, &pci->dev); | 2274 | snd_card_set_dev(card, &pci->dev); |
@@ -2419,6 +2422,7 @@ snd_azf3328_suspend(struct pci_dev *pci, pm_message_t state) | |||
2419 | 2422 | ||
2420 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); | 2423 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); |
2421 | 2424 | ||
2425 | /* same pcm object for playback/capture */ | ||
2422 | snd_pcm_suspend_all(chip->pcm[AZF_CODEC_PLAYBACK]); | 2426 | snd_pcm_suspend_all(chip->pcm[AZF_CODEC_PLAYBACK]); |
2423 | snd_pcm_suspend_all(chip->pcm[AZF_CODEC_I2S_OUT]); | 2427 | snd_pcm_suspend_all(chip->pcm[AZF_CODEC_I2S_OUT]); |
2424 | 2428 | ||
diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c index 37e1b5df5ab8..2958a05b5293 100644 --- a/sound/pci/bt87x.c +++ b/sound/pci/bt87x.c | |||
@@ -637,15 +637,9 @@ static struct snd_kcontrol_new snd_bt87x_capture_boost = { | |||
637 | static int snd_bt87x_capture_source_info(struct snd_kcontrol *kcontrol, | 637 | static int snd_bt87x_capture_source_info(struct snd_kcontrol *kcontrol, |
638 | struct snd_ctl_elem_info *info) | 638 | struct snd_ctl_elem_info *info) |
639 | { | 639 | { |
640 | static char *texts[3] = {"TV Tuner", "FM", "Mic/Line"}; | 640 | static const char *const texts[3] = {"TV Tuner", "FM", "Mic/Line"}; |
641 | 641 | ||
642 | info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 642 | return snd_ctl_enum_info(info, 1, 3, texts); |
643 | info->count = 1; | ||
644 | info->value.enumerated.items = 3; | ||
645 | if (info->value.enumerated.item > 2) | ||
646 | info->value.enumerated.item = 2; | ||
647 | strcpy(info->value.enumerated.name, texts[info->value.enumerated.item]); | ||
648 | return 0; | ||
649 | } | 643 | } |
650 | 644 | ||
651 | static int snd_bt87x_capture_source_get(struct snd_kcontrol *kcontrol, | 645 | static int snd_bt87x_capture_source_get(struct snd_kcontrol *kcontrol, |
diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c index 329968edca9b..b5bb036ef73c 100644 --- a/sound/pci/cmipci.c +++ b/sound/pci/cmipci.c | |||
@@ -2507,14 +2507,12 @@ static int snd_cmipci_line_in_mode_info(struct snd_kcontrol *kcontrol, | |||
2507 | struct snd_ctl_elem_info *uinfo) | 2507 | struct snd_ctl_elem_info *uinfo) |
2508 | { | 2508 | { |
2509 | struct cmipci *cm = snd_kcontrol_chip(kcontrol); | 2509 | struct cmipci *cm = snd_kcontrol_chip(kcontrol); |
2510 | static char *texts[3] = { "Line-In", "Rear Output", "Bass Output" }; | 2510 | static const char *const texts[3] = { |
2511 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 2511 | "Line-In", "Rear Output", "Bass Output" |
2512 | uinfo->count = 1; | 2512 | }; |
2513 | uinfo->value.enumerated.items = cm->chip_version >= 39 ? 3 : 2; | 2513 | |
2514 | if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) | 2514 | return snd_ctl_enum_info(uinfo, 1, |
2515 | uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; | 2515 | cm->chip_version >= 39 ? 3 : 2, texts); |
2516 | strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); | ||
2517 | return 0; | ||
2518 | } | 2516 | } |
2519 | 2517 | ||
2520 | static inline unsigned int get_line_in_mode(struct cmipci *cm) | 2518 | 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, | |||
2564 | static int snd_cmipci_mic_in_mode_info(struct snd_kcontrol *kcontrol, | 2562 | static int snd_cmipci_mic_in_mode_info(struct snd_kcontrol *kcontrol, |
2565 | struct snd_ctl_elem_info *uinfo) | 2563 | struct snd_ctl_elem_info *uinfo) |
2566 | { | 2564 | { |
2567 | static char *texts[2] = { "Mic-In", "Center/LFE Output" }; | 2565 | static const char *const texts[2] = { "Mic-In", "Center/LFE Output" }; |
2568 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 2566 | |
2569 | uinfo->count = 1; | 2567 | return snd_ctl_enum_info(uinfo, 1, 2, texts); |
2570 | uinfo->value.enumerated.items = 2; | ||
2571 | if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) | ||
2572 | uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; | ||
2573 | strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); | ||
2574 | return 0; | ||
2575 | } | 2568 | } |
2576 | 2569 | ||
2577 | static int snd_cmipci_mic_in_mode_get(struct snd_kcontrol *kcontrol, | 2570 | static int snd_cmipci_mic_in_mode_get(struct snd_kcontrol *kcontrol, |
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index a1c4008af891..d3d18be483e1 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c | |||
@@ -1235,7 +1235,8 @@ static int azx_setup_periods(struct azx *chip, | |||
1235 | pos_adj = 0; | 1235 | pos_adj = 0; |
1236 | } else { | 1236 | } else { |
1237 | ofs = setup_bdle(substream, azx_dev, | 1237 | ofs = setup_bdle(substream, azx_dev, |
1238 | &bdl, ofs, pos_adj, 1); | 1238 | &bdl, ofs, pos_adj, |
1239 | !substream->runtime->no_period_wakeup); | ||
1239 | if (ofs < 0) | 1240 | if (ofs < 0) |
1240 | goto error; | 1241 | goto error; |
1241 | } | 1242 | } |
@@ -1247,7 +1248,8 @@ static int azx_setup_periods(struct azx *chip, | |||
1247 | period_bytes - pos_adj, 0); | 1248 | period_bytes - pos_adj, 0); |
1248 | else | 1249 | else |
1249 | ofs = setup_bdle(substream, azx_dev, &bdl, ofs, | 1250 | ofs = setup_bdle(substream, azx_dev, &bdl, ofs, |
1250 | period_bytes, 1); | 1251 | period_bytes, |
1252 | !substream->runtime->no_period_wakeup); | ||
1251 | if (ofs < 0) | 1253 | if (ofs < 0) |
1252 | goto error; | 1254 | goto error; |
1253 | } | 1255 | } |
@@ -1515,7 +1517,8 @@ static struct snd_pcm_hardware azx_pcm_hw = { | |||
1515 | /* No full-resume yet implemented */ | 1517 | /* No full-resume yet implemented */ |
1516 | /* SNDRV_PCM_INFO_RESUME |*/ | 1518 | /* SNDRV_PCM_INFO_RESUME |*/ |
1517 | SNDRV_PCM_INFO_PAUSE | | 1519 | SNDRV_PCM_INFO_PAUSE | |
1518 | SNDRV_PCM_INFO_SYNC_START), | 1520 | SNDRV_PCM_INFO_SYNC_START | |
1521 | SNDRV_PCM_INFO_NO_PERIOD_WAKEUP), | ||
1519 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | 1522 | .formats = SNDRV_PCM_FMTBIT_S16_LE, |
1520 | .rates = SNDRV_PCM_RATE_48000, | 1523 | .rates = SNDRV_PCM_RATE_48000, |
1521 | .rate_min = 48000, | 1524 | .rate_min = 48000, |
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 552a09e9211f..6e0d872bbf7b 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c | |||
@@ -10857,6 +10857,9 @@ static int alc_auto_add_mic_boost(struct hda_codec *codec) | |||
10857 | return 0; | 10857 | return 0; |
10858 | } | 10858 | } |
10859 | 10859 | ||
10860 | static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec, | ||
10861 | const struct auto_pin_cfg *cfg); | ||
10862 | |||
10860 | /* almost identical with ALC880 parser... */ | 10863 | /* almost identical with ALC880 parser... */ |
10861 | static int alc882_parse_auto_config(struct hda_codec *codec) | 10864 | static int alc882_parse_auto_config(struct hda_codec *codec) |
10862 | { | 10865 | { |
@@ -10874,7 +10877,10 @@ static int alc882_parse_auto_config(struct hda_codec *codec) | |||
10874 | err = alc880_auto_fill_dac_nids(spec, &spec->autocfg); | 10877 | err = alc880_auto_fill_dac_nids(spec, &spec->autocfg); |
10875 | if (err < 0) | 10878 | if (err < 0) |
10876 | return err; | 10879 | return err; |
10877 | err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg); | 10880 | if (codec->vendor_id == 0x10ec0887) |
10881 | err = alc861vd_auto_create_multi_out_ctls(spec, &spec->autocfg); | ||
10882 | else | ||
10883 | err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg); | ||
10878 | if (err < 0) | 10884 | if (err < 0) |
10879 | return err; | 10885 | return err; |
10880 | err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0], | 10886 | err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0], |
@@ -17043,7 +17049,7 @@ static void alc861vd_auto_init_analog_input(struct hda_codec *codec) | |||
17043 | #define alc861vd_idx_to_mixer_switch(nid) ((nid) + 0x0c) | 17049 | #define alc861vd_idx_to_mixer_switch(nid) ((nid) + 0x0c) |
17044 | 17050 | ||
17045 | /* add playback controls from the parsed DAC table */ | 17051 | /* add playback controls from the parsed DAC table */ |
17046 | /* Based on ALC880 version. But ALC861VD has separate, | 17052 | /* Based on ALC880 version. But ALC861VD and ALC887 have separate, |
17047 | * different NIDs for mute/unmute switch and volume control */ | 17053 | * different NIDs for mute/unmute switch and volume control */ |
17048 | static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec, | 17054 | static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec, |
17049 | const struct auto_pin_cfg *cfg) | 17055 | const struct auto_pin_cfg *cfg) |
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index d1c3f8defc48..7f4852a478a1 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c | |||
@@ -263,8 +263,7 @@ static void vt1708_stop_hp_work(struct via_spec *spec) | |||
263 | return; | 263 | return; |
264 | snd_hda_codec_write(spec->codec, 0x1, 0, 0xf81, | 264 | snd_hda_codec_write(spec->codec, 0x1, 0, 0xf81, |
265 | !spec->vt1708_jack_detectect); | 265 | !spec->vt1708_jack_detectect); |
266 | cancel_delayed_work(&spec->vt1708_hp_work); | 266 | cancel_delayed_work_sync(&spec->vt1708_hp_work); |
267 | flush_scheduled_work(); | ||
268 | } | 267 | } |
269 | 268 | ||
270 | 269 | ||
diff --git a/sound/pci/ice1712/delta.c b/sound/pci/ice1712/delta.c index 712c1710f9a2..7b62de089fee 100644 --- a/sound/pci/ice1712/delta.c +++ b/sound/pci/ice1712/delta.c | |||
@@ -96,6 +96,11 @@ static unsigned char ap_cs8427_codec_select(struct snd_ice1712 *ice) | |||
96 | tmp |= ICE1712_DELTA_AP_CCLK | ICE1712_DELTA_AP_CS_CODEC; | 96 | tmp |= ICE1712_DELTA_AP_CCLK | ICE1712_DELTA_AP_CS_CODEC; |
97 | tmp &= ~ICE1712_DELTA_AP_CS_DIGITAL; | 97 | tmp &= ~ICE1712_DELTA_AP_CS_DIGITAL; |
98 | break; | 98 | break; |
99 | case ICE1712_SUBDEVICE_DELTA66E: | ||
100 | tmp |= ICE1712_DELTA_66E_CCLK | ICE1712_DELTA_66E_CS_CHIP_A | | ||
101 | ICE1712_DELTA_66E_CS_CHIP_B; | ||
102 | tmp &= ~ICE1712_DELTA_66E_CS_CS8427; | ||
103 | break; | ||
99 | case ICE1712_SUBDEVICE_VX442: | 104 | case ICE1712_SUBDEVICE_VX442: |
100 | tmp |= ICE1712_VX442_CCLK | ICE1712_VX442_CODEC_CHIP_A | ICE1712_VX442_CODEC_CHIP_B; | 105 | tmp |= ICE1712_VX442_CCLK | ICE1712_VX442_CODEC_CHIP_A | ICE1712_VX442_CODEC_CHIP_B; |
101 | tmp &= ~ICE1712_VX442_CS_DIGITAL; | 106 | tmp &= ~ICE1712_VX442_CS_DIGITAL; |
@@ -119,6 +124,9 @@ static void ap_cs8427_codec_deassert(struct snd_ice1712 *ice, unsigned char tmp) | |||
119 | case ICE1712_SUBDEVICE_DELTA410: | 124 | case ICE1712_SUBDEVICE_DELTA410: |
120 | tmp |= ICE1712_DELTA_AP_CS_DIGITAL; | 125 | tmp |= ICE1712_DELTA_AP_CS_DIGITAL; |
121 | break; | 126 | break; |
127 | case ICE1712_SUBDEVICE_DELTA66E: | ||
128 | tmp |= ICE1712_DELTA_66E_CS_CS8427; | ||
129 | break; | ||
122 | case ICE1712_SUBDEVICE_VX442: | 130 | case ICE1712_SUBDEVICE_VX442: |
123 | tmp |= ICE1712_VX442_CS_DIGITAL; | 131 | tmp |= ICE1712_VX442_CS_DIGITAL; |
124 | break; | 132 | break; |
@@ -276,6 +284,20 @@ static void delta1010lt_ak4524_lock(struct snd_akm4xxx *ak, int chip) | |||
276 | } | 284 | } |
277 | 285 | ||
278 | /* | 286 | /* |
287 | * AK4524 on Delta66 rev E to choose the chip address | ||
288 | */ | ||
289 | static void delta66e_ak4524_lock(struct snd_akm4xxx *ak, int chip) | ||
290 | { | ||
291 | struct snd_ak4xxx_private *priv = (void *)ak->private_value[0]; | ||
292 | struct snd_ice1712 *ice = ak->private_data[0]; | ||
293 | |||
294 | snd_ice1712_save_gpio_status(ice); | ||
295 | priv->cs_mask = | ||
296 | priv->cs_addr = chip == 0 ? ICE1712_DELTA_66E_CS_CHIP_A : | ||
297 | ICE1712_DELTA_66E_CS_CHIP_B; | ||
298 | } | ||
299 | |||
300 | /* | ||
279 | * AK4528 on VX442 to choose the chip mask | 301 | * AK4528 on VX442 to choose the chip mask |
280 | */ | 302 | */ |
281 | static void vx442_ak4524_lock(struct snd_akm4xxx *ak, int chip) | 303 | static void vx442_ak4524_lock(struct snd_akm4xxx *ak, int chip) |
@@ -487,6 +509,29 @@ static struct snd_ak4xxx_private akm_delta1010lt_priv __devinitdata = { | |||
487 | .mask_flags = 0, | 509 | .mask_flags = 0, |
488 | }; | 510 | }; |
489 | 511 | ||
512 | static struct snd_akm4xxx akm_delta66e __devinitdata = { | ||
513 | .type = SND_AK4524, | ||
514 | .num_adcs = 4, | ||
515 | .num_dacs = 4, | ||
516 | .ops = { | ||
517 | .lock = delta66e_ak4524_lock, | ||
518 | .set_rate_val = delta_ak4524_set_rate_val | ||
519 | } | ||
520 | }; | ||
521 | |||
522 | static struct snd_ak4xxx_private akm_delta66e_priv __devinitdata = { | ||
523 | .caddr = 2, | ||
524 | .cif = 0, /* the default level of the CIF pin from AK4524 */ | ||
525 | .data_mask = ICE1712_DELTA_66E_DOUT, | ||
526 | .clk_mask = ICE1712_DELTA_66E_CCLK, | ||
527 | .cs_mask = 0, | ||
528 | .cs_addr = 0, /* set later */ | ||
529 | .cs_none = 0, | ||
530 | .add_flags = 0, | ||
531 | .mask_flags = 0, | ||
532 | }; | ||
533 | |||
534 | |||
490 | static struct snd_akm4xxx akm_delta44 __devinitdata = { | 535 | static struct snd_akm4xxx akm_delta44 __devinitdata = { |
491 | .type = SND_AK4524, | 536 | .type = SND_AK4524, |
492 | .num_adcs = 4, | 537 | .num_adcs = 4, |
@@ -644,9 +689,11 @@ static int __devinit snd_ice1712_delta_init(struct snd_ice1712 *ice) | |||
644 | err = snd_ice1712_akm4xxx_init(ak, &akm_delta44, &akm_delta44_priv, ice); | 689 | err = snd_ice1712_akm4xxx_init(ak, &akm_delta44, &akm_delta44_priv, ice); |
645 | break; | 690 | break; |
646 | case ICE1712_SUBDEVICE_VX442: | 691 | case ICE1712_SUBDEVICE_VX442: |
647 | case ICE1712_SUBDEVICE_DELTA66E: | ||
648 | err = snd_ice1712_akm4xxx_init(ak, &akm_vx442, &akm_vx442_priv, ice); | 692 | err = snd_ice1712_akm4xxx_init(ak, &akm_vx442, &akm_vx442_priv, ice); |
649 | break; | 693 | break; |
694 | case ICE1712_SUBDEVICE_DELTA66E: | ||
695 | err = snd_ice1712_akm4xxx_init(ak, &akm_delta66e, &akm_delta66e_priv, ice); | ||
696 | break; | ||
650 | default: | 697 | default: |
651 | snd_BUG(); | 698 | snd_BUG(); |
652 | return -EINVAL; | 699 | return -EINVAL; |
diff --git a/sound/pci/ice1712/delta.h b/sound/pci/ice1712/delta.h index 1a0ac6cd6501..11a9c3a76507 100644 --- a/sound/pci/ice1712/delta.h +++ b/sound/pci/ice1712/delta.h | |||
@@ -144,6 +144,17 @@ extern struct snd_ice1712_card_info snd_ice1712_delta_cards[]; | |||
144 | #define ICE1712_DELTA_1010LT_CS_NONE 0x50 /* nothing */ | 144 | #define ICE1712_DELTA_1010LT_CS_NONE 0x50 /* nothing */ |
145 | #define ICE1712_DELTA_1010LT_WORDCLOCK 0x80 /* sample clock source: 0 = Word Clock Input, 1 = S/PDIF Input ??? */ | 145 | #define ICE1712_DELTA_1010LT_WORDCLOCK 0x80 /* sample clock source: 0 = Word Clock Input, 1 = S/PDIF Input ??? */ |
146 | 146 | ||
147 | /* M-Audio Delta 66 rev. E definitions. | ||
148 | * Newer revisions of Delta 66 have CS8427 over SPI for | ||
149 | * S/PDIF transceiver instead of CS8404/CS8414. */ | ||
150 | /* 0x01 = DFS */ | ||
151 | #define ICE1712_DELTA_66E_CCLK 0x02 /* SPI clock */ | ||
152 | #define ICE1712_DELTA_66E_DIN 0x04 /* data input */ | ||
153 | #define ICE1712_DELTA_66E_DOUT 0x08 /* data output */ | ||
154 | #define ICE1712_DELTA_66E_CS_CS8427 0x10 /* chip select, low = CS8427 */ | ||
155 | #define ICE1712_DELTA_66E_CS_CHIP_A 0x20 /* AK4524 #0 */ | ||
156 | #define ICE1712_DELTA_66E_CS_CHIP_B 0x40 /* AK4524 #1 */ | ||
157 | |||
147 | /* Digigram VX442 definitions */ | 158 | /* Digigram VX442 definitions */ |
148 | #define ICE1712_VX442_CCLK 0x02 /* SPI clock */ | 159 | #define ICE1712_VX442_CCLK 0x02 /* SPI clock */ |
149 | #define ICE1712_VX442_DIN 0x04 /* data input */ | 160 | #define ICE1712_VX442_DIN 0x04 /* data input */ |
diff --git a/sound/pci/oxygen/Makefile b/sound/pci/oxygen/Makefile index acd8f15f7bff..0f8726551fde 100644 --- a/sound/pci/oxygen/Makefile +++ b/sound/pci/oxygen/Makefile | |||
@@ -1,10 +1,8 @@ | |||
1 | snd-oxygen-lib-objs := oxygen_io.o oxygen_lib.o oxygen_mixer.o oxygen_pcm.o | 1 | snd-oxygen-lib-objs := oxygen_io.o oxygen_lib.o oxygen_mixer.o oxygen_pcm.o |
2 | snd-hifier-objs := hifier.o | 2 | snd-oxygen-objs := oxygen.o xonar_dg.o |
3 | snd-oxygen-objs := oxygen.o | ||
4 | snd-virtuoso-objs := virtuoso.o xonar_lib.o \ | 3 | snd-virtuoso-objs := virtuoso.o xonar_lib.o \ |
5 | xonar_pcm179x.o xonar_cs43xx.o xonar_wm87x6.o xonar_hdmi.o | 4 | xonar_pcm179x.o xonar_cs43xx.o xonar_wm87x6.o xonar_hdmi.o |
6 | 5 | ||
7 | obj-$(CONFIG_SND_OXYGEN_LIB) += snd-oxygen-lib.o | 6 | obj-$(CONFIG_SND_OXYGEN_LIB) += snd-oxygen-lib.o |
8 | obj-$(CONFIG_SND_HIFIER) += snd-hifier.o | ||
9 | obj-$(CONFIG_SND_OXYGEN) += snd-oxygen.o | 7 | obj-$(CONFIG_SND_OXYGEN) += snd-oxygen.o |
10 | obj-$(CONFIG_SND_VIRTUOSO) += snd-virtuoso.o | 8 | obj-$(CONFIG_SND_VIRTUOSO) += snd-virtuoso.o |
diff --git a/sound/pci/oxygen/cs4245.h b/sound/pci/oxygen/cs4245.h new file mode 100644 index 000000000000..5e0197e07dd1 --- /dev/null +++ b/sound/pci/oxygen/cs4245.h | |||
@@ -0,0 +1,107 @@ | |||
1 | #define CS4245_CHIP_ID 0x01 | ||
2 | #define CS4245_POWER_CTRL 0x02 | ||
3 | #define CS4245_DAC_CTRL_1 0x03 | ||
4 | #define CS4245_ADC_CTRL 0x04 | ||
5 | #define CS4245_MCLK_FREQ 0x05 | ||
6 | #define CS4245_SIGNAL_SEL 0x06 | ||
7 | #define CS4245_PGA_B_CTRL 0x07 | ||
8 | #define CS4245_PGA_A_CTRL 0x08 | ||
9 | #define CS4245_ANALOG_IN 0x09 | ||
10 | #define CS4245_DAC_A_CTRL 0x0a | ||
11 | #define CS4245_DAC_B_CTRL 0x0b | ||
12 | #define CS4245_DAC_CTRL_2 0x0c | ||
13 | #define CS4245_INT_STATUS 0x0d | ||
14 | #define CS4245_INT_MASK 0x0e | ||
15 | #define CS4245_INT_MODE_MSB 0x0f | ||
16 | #define CS4245_INT_MODE_LSB 0x10 | ||
17 | |||
18 | /* Chip ID */ | ||
19 | #define CS4245_CHIP_PART_MASK 0xf0 | ||
20 | #define CS4245_CHIP_REV_MASK 0x0f | ||
21 | |||
22 | /* Power Control */ | ||
23 | #define CS4245_FREEZE 0x80 | ||
24 | #define CS4245_PDN_MIC 0x08 | ||
25 | #define CS4245_PDN_ADC 0x04 | ||
26 | #define CS4245_PDN_DAC 0x02 | ||
27 | #define CS4245_PDN 0x01 | ||
28 | |||
29 | /* DAC Control */ | ||
30 | #define CS4245_DAC_FM_MASK 0xc0 | ||
31 | #define CS4245_DAC_FM_SINGLE 0x00 | ||
32 | #define CS4245_DAC_FM_DOUBLE 0x40 | ||
33 | #define CS4245_DAC_FM_QUAD 0x80 | ||
34 | #define CS4245_DAC_DIF_MASK 0x30 | ||
35 | #define CS4245_DAC_DIF_LJUST 0x00 | ||
36 | #define CS4245_DAC_DIF_I2S 0x10 | ||
37 | #define CS4245_DAC_DIF_RJUST_16 0x20 | ||
38 | #define CS4245_DAC_DIF_RJUST_24 0x30 | ||
39 | #define CS4245_RESERVED_1 0x08 | ||
40 | #define CS4245_MUTE_DAC 0x04 | ||
41 | #define CS4245_DEEMPH 0x02 | ||
42 | #define CS4245_DAC_MASTER 0x01 | ||
43 | |||
44 | /* ADC Control */ | ||
45 | #define CS4245_ADC_FM_MASK 0xc0 | ||
46 | #define CS4245_ADC_FM_SINGLE 0x00 | ||
47 | #define CS4245_ADC_FM_DOUBLE 0x40 | ||
48 | #define CS4245_ADC_FM_QUAD 0x80 | ||
49 | #define CS4245_ADC_DIF_MASK 0x10 | ||
50 | #define CS4245_ADC_DIF_LJUST 0x00 | ||
51 | #define CS4245_ADC_DIF_I2S 0x10 | ||
52 | #define CS4245_MUTE_ADC 0x04 | ||
53 | #define CS4245_HPF_FREEZE 0x02 | ||
54 | #define CS4245_ADC_MASTER 0x01 | ||
55 | |||
56 | /* MCLK Frequency */ | ||
57 | #define CS4245_MCLK1_MASK 0x70 | ||
58 | #define CS4245_MCLK1_SHIFT 4 | ||
59 | #define CS4245_MCLK2_MASK 0x07 | ||
60 | #define CS4245_MCLK2_SHIFT 0 | ||
61 | #define CS4245_MCLK_1 0 | ||
62 | #define CS4245_MCLK_1_5 1 | ||
63 | #define CS4245_MCLK_2 2 | ||
64 | #define CS4245_MCLK_3 3 | ||
65 | #define CS4245_MCLK_4 4 | ||
66 | |||
67 | /* Signal Selection */ | ||
68 | #define CS4245_A_OUT_SEL_MASK 0x60 | ||
69 | #define CS4245_A_OUT_SEL_HIZ 0x00 | ||
70 | #define CS4245_A_OUT_SEL_DAC 0x20 | ||
71 | #define CS4245_A_OUT_SEL_PGA 0x40 | ||
72 | #define CS4245_LOOP 0x02 | ||
73 | #define CS4245_ASYNCH 0x01 | ||
74 | |||
75 | /* Channel B/A PGA Control */ | ||
76 | #define CS4245_PGA_GAIN_MASK 0x3f | ||
77 | |||
78 | /* ADC Input Control */ | ||
79 | #define CS4245_PGA_SOFT 0x10 | ||
80 | #define CS4245_PGA_ZERO 0x08 | ||
81 | #define CS4245_SEL_MASK 0x07 | ||
82 | #define CS4245_SEL_MIC 0x00 | ||
83 | #define CS4245_SEL_INPUT_1 0x01 | ||
84 | #define CS4245_SEL_INPUT_2 0x02 | ||
85 | #define CS4245_SEL_INPUT_3 0x03 | ||
86 | #define CS4245_SEL_INPUT_4 0x04 | ||
87 | #define CS4245_SEL_INPUT_5 0x05 | ||
88 | #define CS4245_SEL_INPUT_6 0x06 | ||
89 | |||
90 | /* DAC Channel A/B Volume Control */ | ||
91 | #define CS4245_VOL_MASK 0xff | ||
92 | |||
93 | /* DAC Control 2 */ | ||
94 | #define CS4245_DAC_SOFT 0x80 | ||
95 | #define CS4245_DAC_ZERO 0x40 | ||
96 | #define CS4245_INVERT_DAC 0x20 | ||
97 | #define CS4245_INT_ACTIVE_HIGH 0x01 | ||
98 | |||
99 | /* Interrupt Status/Mask/Mode */ | ||
100 | #define CS4245_ADC_CLK_ERR 0x08 | ||
101 | #define CS4245_DAC_CLK_ERR 0x04 | ||
102 | #define CS4245_ADC_OVFL 0x02 | ||
103 | #define CS4245_ADC_UNDRFL 0x01 | ||
104 | |||
105 | |||
106 | #define CS4245_SPI_ADDRESS (0x9e << 16) | ||
107 | #define CS4245_SPI_WRITE (0 << 16) | ||
diff --git a/sound/pci/oxygen/hifier.c b/sound/pci/oxygen/hifier.c deleted file mode 100644 index 5a87d683691f..000000000000 --- a/sound/pci/oxygen/hifier.c +++ /dev/null | |||
@@ -1,239 +0,0 @@ | |||
1 | /* | ||
2 | * C-Media CMI8788 driver for the MediaTek/TempoTec HiFier Fantasia | ||
3 | * | ||
4 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> | ||
5 | * | ||
6 | * | ||
7 | * This driver is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License, version 2. | ||
9 | * | ||
10 | * This driver is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this driver; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | /* | ||
21 | * CMI8788: | ||
22 | * | ||
23 | * SPI 0 -> AK4396 | ||
24 | */ | ||
25 | |||
26 | #include <linux/delay.h> | ||
27 | #include <linux/pci.h> | ||
28 | #include <sound/control.h> | ||
29 | #include <sound/core.h> | ||
30 | #include <sound/initval.h> | ||
31 | #include <sound/pcm.h> | ||
32 | #include <sound/tlv.h> | ||
33 | #include "oxygen.h" | ||
34 | #include "ak4396.h" | ||
35 | |||
36 | MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); | ||
37 | MODULE_DESCRIPTION("TempoTec HiFier driver"); | ||
38 | MODULE_LICENSE("GPL v2"); | ||
39 | |||
40 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; | ||
41 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; | ||
42 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; | ||
43 | |||
44 | module_param_array(index, int, NULL, 0444); | ||
45 | MODULE_PARM_DESC(index, "card index"); | ||
46 | module_param_array(id, charp, NULL, 0444); | ||
47 | MODULE_PARM_DESC(id, "ID string"); | ||
48 | module_param_array(enable, bool, NULL, 0444); | ||
49 | MODULE_PARM_DESC(enable, "enable card"); | ||
50 | |||
51 | static DEFINE_PCI_DEVICE_TABLE(hifier_ids) = { | ||
52 | { OXYGEN_PCI_SUBID(0x14c3, 0x1710) }, | ||
53 | { OXYGEN_PCI_SUBID(0x14c3, 0x1711) }, | ||
54 | { OXYGEN_PCI_SUBID_BROKEN_EEPROM }, | ||
55 | { } | ||
56 | }; | ||
57 | MODULE_DEVICE_TABLE(pci, hifier_ids); | ||
58 | |||
59 | struct hifier_data { | ||
60 | u8 ak4396_regs[5]; | ||
61 | }; | ||
62 | |||
63 | static void ak4396_write(struct oxygen *chip, u8 reg, u8 value) | ||
64 | { | ||
65 | struct hifier_data *data = chip->model_data; | ||
66 | |||
67 | oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER | | ||
68 | OXYGEN_SPI_DATA_LENGTH_2 | | ||
69 | OXYGEN_SPI_CLOCK_160 | | ||
70 | (0 << OXYGEN_SPI_CODEC_SHIFT) | | ||
71 | OXYGEN_SPI_CEN_LATCH_CLOCK_HI, | ||
72 | AK4396_WRITE | (reg << 8) | value); | ||
73 | data->ak4396_regs[reg] = value; | ||
74 | } | ||
75 | |||
76 | static void ak4396_write_cached(struct oxygen *chip, u8 reg, u8 value) | ||
77 | { | ||
78 | struct hifier_data *data = chip->model_data; | ||
79 | |||
80 | if (value != data->ak4396_regs[reg]) | ||
81 | ak4396_write(chip, reg, value); | ||
82 | } | ||
83 | |||
84 | static void hifier_registers_init(struct oxygen *chip) | ||
85 | { | ||
86 | struct hifier_data *data = chip->model_data; | ||
87 | |||
88 | ak4396_write(chip, AK4396_CONTROL_1, AK4396_DIF_24_MSB | AK4396_RSTN); | ||
89 | ak4396_write(chip, AK4396_CONTROL_2, | ||
90 | data->ak4396_regs[AK4396_CONTROL_2]); | ||
91 | ak4396_write(chip, AK4396_CONTROL_3, AK4396_PCM); | ||
92 | ak4396_write(chip, AK4396_LCH_ATT, chip->dac_volume[0]); | ||
93 | ak4396_write(chip, AK4396_RCH_ATT, chip->dac_volume[1]); | ||
94 | } | ||
95 | |||
96 | static void hifier_init(struct oxygen *chip) | ||
97 | { | ||
98 | struct hifier_data *data = chip->model_data; | ||
99 | |||
100 | data->ak4396_regs[AK4396_CONTROL_2] = | ||
101 | AK4396_SMUTE | AK4396_DEM_OFF | AK4396_DFS_NORMAL; | ||
102 | hifier_registers_init(chip); | ||
103 | |||
104 | snd_component_add(chip->card, "AK4396"); | ||
105 | snd_component_add(chip->card, "CS5340"); | ||
106 | } | ||
107 | |||
108 | static void hifier_cleanup(struct oxygen *chip) | ||
109 | { | ||
110 | } | ||
111 | |||
112 | static void hifier_resume(struct oxygen *chip) | ||
113 | { | ||
114 | hifier_registers_init(chip); | ||
115 | } | ||
116 | |||
117 | static void set_ak4396_params(struct oxygen *chip, | ||
118 | struct snd_pcm_hw_params *params) | ||
119 | { | ||
120 | struct hifier_data *data = chip->model_data; | ||
121 | u8 value; | ||
122 | |||
123 | value = data->ak4396_regs[AK4396_CONTROL_2] & ~AK4396_DFS_MASK; | ||
124 | if (params_rate(params) <= 54000) | ||
125 | value |= AK4396_DFS_NORMAL; | ||
126 | else if (params_rate(params) <= 108000) | ||
127 | value |= AK4396_DFS_DOUBLE; | ||
128 | else | ||
129 | value |= AK4396_DFS_QUAD; | ||
130 | |||
131 | msleep(1); /* wait for the new MCLK to become stable */ | ||
132 | |||
133 | if (value != data->ak4396_regs[AK4396_CONTROL_2]) { | ||
134 | ak4396_write(chip, AK4396_CONTROL_1, | ||
135 | AK4396_DIF_24_MSB); | ||
136 | ak4396_write(chip, AK4396_CONTROL_2, value); | ||
137 | ak4396_write(chip, AK4396_CONTROL_1, | ||
138 | AK4396_DIF_24_MSB | AK4396_RSTN); | ||
139 | } | ||
140 | } | ||
141 | |||
142 | static void update_ak4396_volume(struct oxygen *chip) | ||
143 | { | ||
144 | ak4396_write_cached(chip, AK4396_LCH_ATT, chip->dac_volume[0]); | ||
145 | ak4396_write_cached(chip, AK4396_RCH_ATT, chip->dac_volume[1]); | ||
146 | } | ||
147 | |||
148 | static void update_ak4396_mute(struct oxygen *chip) | ||
149 | { | ||
150 | struct hifier_data *data = chip->model_data; | ||
151 | u8 value; | ||
152 | |||
153 | value = data->ak4396_regs[AK4396_CONTROL_2] & ~AK4396_SMUTE; | ||
154 | if (chip->dac_mute) | ||
155 | value |= AK4396_SMUTE; | ||
156 | ak4396_write_cached(chip, AK4396_CONTROL_2, value); | ||
157 | } | ||
158 | |||
159 | static void set_cs5340_params(struct oxygen *chip, | ||
160 | struct snd_pcm_hw_params *params) | ||
161 | { | ||
162 | } | ||
163 | |||
164 | static const DECLARE_TLV_DB_LINEAR(ak4396_db_scale, TLV_DB_GAIN_MUTE, 0); | ||
165 | |||
166 | static const struct oxygen_model model_hifier = { | ||
167 | .shortname = "C-Media CMI8787", | ||
168 | .longname = "C-Media Oxygen HD Audio", | ||
169 | .chip = "CMI8788", | ||
170 | .init = hifier_init, | ||
171 | .cleanup = hifier_cleanup, | ||
172 | .resume = hifier_resume, | ||
173 | .get_i2s_mclk = oxygen_default_i2s_mclk, | ||
174 | .set_dac_params = set_ak4396_params, | ||
175 | .set_adc_params = set_cs5340_params, | ||
176 | .update_dac_volume = update_ak4396_volume, | ||
177 | .update_dac_mute = update_ak4396_mute, | ||
178 | .dac_tlv = ak4396_db_scale, | ||
179 | .model_data_size = sizeof(struct hifier_data), | ||
180 | .device_config = PLAYBACK_0_TO_I2S | | ||
181 | PLAYBACK_1_TO_SPDIF | | ||
182 | CAPTURE_0_FROM_I2S_1, | ||
183 | .dac_channels = 2, | ||
184 | .dac_volume_min = 0, | ||
185 | .dac_volume_max = 255, | ||
186 | .function_flags = OXYGEN_FUNCTION_SPI, | ||
187 | .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | ||
188 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | ||
189 | }; | ||
190 | |||
191 | static int __devinit get_hifier_model(struct oxygen *chip, | ||
192 | const struct pci_device_id *id) | ||
193 | { | ||
194 | chip->model = model_hifier; | ||
195 | return 0; | ||
196 | } | ||
197 | |||
198 | static int __devinit hifier_probe(struct pci_dev *pci, | ||
199 | const struct pci_device_id *pci_id) | ||
200 | { | ||
201 | static int dev; | ||
202 | int err; | ||
203 | |||
204 | if (dev >= SNDRV_CARDS) | ||
205 | return -ENODEV; | ||
206 | if (!enable[dev]) { | ||
207 | ++dev; | ||
208 | return -ENOENT; | ||
209 | } | ||
210 | err = oxygen_pci_probe(pci, index[dev], id[dev], THIS_MODULE, | ||
211 | hifier_ids, get_hifier_model); | ||
212 | if (err >= 0) | ||
213 | ++dev; | ||
214 | return err; | ||
215 | } | ||
216 | |||
217 | static struct pci_driver hifier_driver = { | ||
218 | .name = "CMI8787HiFier", | ||
219 | .id_table = hifier_ids, | ||
220 | .probe = hifier_probe, | ||
221 | .remove = __devexit_p(oxygen_pci_remove), | ||
222 | #ifdef CONFIG_PM | ||
223 | .suspend = oxygen_pci_suspend, | ||
224 | .resume = oxygen_pci_resume, | ||
225 | #endif | ||
226 | }; | ||
227 | |||
228 | static int __init alsa_card_hifier_init(void) | ||
229 | { | ||
230 | return pci_register_driver(&hifier_driver); | ||
231 | } | ||
232 | |||
233 | static void __exit alsa_card_hifier_exit(void) | ||
234 | { | ||
235 | pci_unregister_driver(&hifier_driver); | ||
236 | } | ||
237 | |||
238 | module_init(alsa_card_hifier_init) | ||
239 | module_exit(alsa_card_hifier_exit) | ||
diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index 98a8eb3c92f7..d7e8ddd9a67b 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c | |||
@@ -20,19 +20,32 @@ | |||
20 | /* | 20 | /* |
21 | * CMI8788: | 21 | * CMI8788: |
22 | * | 22 | * |
23 | * SPI 0 -> 1st AK4396 (front) | 23 | * SPI 0 -> 1st AK4396 (front) |
24 | * SPI 1 -> 2nd AK4396 (surround) | 24 | * SPI 1 -> 2nd AK4396 (surround) |
25 | * SPI 2 -> 3rd AK4396 (center/LFE) | 25 | * SPI 2 -> 3rd AK4396 (center/LFE) |
26 | * SPI 3 -> WM8785 | 26 | * SPI 3 -> WM8785 |
27 | * SPI 4 -> 4th AK4396 (back) | 27 | * SPI 4 -> 4th AK4396 (back) |
28 | * | 28 | * |
29 | * GPIO 0 -> DFS0 of AK5385 | 29 | * GPIO 0 -> DFS0 of AK5385 |
30 | * GPIO 1 -> DFS1 of AK5385 | 30 | * GPIO 1 -> DFS1 of AK5385 |
31 | * GPIO 8 -> enable headphone amplifier on HT-Omega models | 31 | * |
32 | * X-Meridian models: | ||
33 | * GPIO 4 -> enable extension S/PDIF input | ||
34 | * GPIO 6 -> enable on-board S/PDIF input | ||
35 | * | ||
36 | * Claro models: | ||
37 | * GPIO 6 -> S/PDIF from optical (0) or coaxial (1) input | ||
38 | * GPIO 8 -> enable headphone amplifier | ||
32 | * | 39 | * |
33 | * CM9780: | 40 | * CM9780: |
34 | * | 41 | * |
35 | * GPO 0 -> route line-in (0) or AC97 output (1) to ADC input | 42 | * LINE_OUT -> input of ADC |
43 | * | ||
44 | * AUX_IN <- aux | ||
45 | * CD_IN <- CD | ||
46 | * MIC_IN <- mic | ||
47 | * | ||
48 | * GPO 0 -> route line-in (0) or AC97 output (1) to ADC input | ||
36 | */ | 49 | */ |
37 | 50 | ||
38 | #include <linux/delay.h> | 51 | #include <linux/delay.h> |
@@ -41,18 +54,22 @@ | |||
41 | #include <sound/ac97_codec.h> | 54 | #include <sound/ac97_codec.h> |
42 | #include <sound/control.h> | 55 | #include <sound/control.h> |
43 | #include <sound/core.h> | 56 | #include <sound/core.h> |
57 | #include <sound/info.h> | ||
44 | #include <sound/initval.h> | 58 | #include <sound/initval.h> |
45 | #include <sound/pcm.h> | 59 | #include <sound/pcm.h> |
46 | #include <sound/pcm_params.h> | 60 | #include <sound/pcm_params.h> |
47 | #include <sound/tlv.h> | 61 | #include <sound/tlv.h> |
48 | #include "oxygen.h" | 62 | #include "oxygen.h" |
63 | #include "xonar_dg.h" | ||
49 | #include "ak4396.h" | 64 | #include "ak4396.h" |
50 | #include "wm8785.h" | 65 | #include "wm8785.h" |
51 | 66 | ||
52 | MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); | 67 | MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); |
53 | MODULE_DESCRIPTION("C-Media CMI8788 driver"); | 68 | MODULE_DESCRIPTION("C-Media CMI8788 driver"); |
54 | MODULE_LICENSE("GPL v2"); | 69 | MODULE_LICENSE("GPL v2"); |
55 | MODULE_SUPPORTED_DEVICE("{{C-Media,CMI8788}}"); | 70 | MODULE_SUPPORTED_DEVICE("{{C-Media,CMI8786}" |
71 | ",{C-Media,CMI8787}" | ||
72 | ",{C-Media,CMI8788}}"); | ||
56 | 73 | ||
57 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; | 74 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; |
58 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; | 75 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; |
@@ -66,24 +83,46 @@ module_param_array(enable, bool, NULL, 0444); | |||
66 | MODULE_PARM_DESC(enable, "enable card"); | 83 | MODULE_PARM_DESC(enable, "enable card"); |
67 | 84 | ||
68 | enum { | 85 | enum { |
69 | MODEL_CMEDIA_REF, /* C-Media's reference design */ | 86 | MODEL_CMEDIA_REF, |
70 | MODEL_MERIDIAN, /* AuzenTech X-Meridian */ | 87 | MODEL_MERIDIAN, |
71 | MODEL_CLARO, /* HT-Omega Claro */ | 88 | MODEL_MERIDIAN_2G, |
72 | MODEL_CLARO_HALO, /* HT-Omega Claro halo */ | 89 | MODEL_CLARO, |
90 | MODEL_CLARO_HALO, | ||
91 | MODEL_FANTASIA, | ||
92 | MODEL_SERENADE, | ||
93 | MODEL_2CH_OUTPUT, | ||
94 | MODEL_HG2PCI, | ||
95 | MODEL_XONAR_DG, | ||
73 | }; | 96 | }; |
74 | 97 | ||
75 | static DEFINE_PCI_DEVICE_TABLE(oxygen_ids) = { | 98 | static DEFINE_PCI_DEVICE_TABLE(oxygen_ids) = { |
99 | /* C-Media's reference design */ | ||
76 | { OXYGEN_PCI_SUBID(0x10b0, 0x0216), .driver_data = MODEL_CMEDIA_REF }, | 100 | { OXYGEN_PCI_SUBID(0x10b0, 0x0216), .driver_data = MODEL_CMEDIA_REF }, |
101 | { OXYGEN_PCI_SUBID(0x10b0, 0x0217), .driver_data = MODEL_CMEDIA_REF }, | ||
77 | { OXYGEN_PCI_SUBID(0x10b0, 0x0218), .driver_data = MODEL_CMEDIA_REF }, | 102 | { OXYGEN_PCI_SUBID(0x10b0, 0x0218), .driver_data = MODEL_CMEDIA_REF }, |
78 | { OXYGEN_PCI_SUBID(0x10b0, 0x0219), .driver_data = MODEL_CMEDIA_REF }, | 103 | { OXYGEN_PCI_SUBID(0x10b0, 0x0219), .driver_data = MODEL_CMEDIA_REF }, |
79 | { OXYGEN_PCI_SUBID(0x13f6, 0x0001), .driver_data = MODEL_CMEDIA_REF }, | 104 | { OXYGEN_PCI_SUBID(0x13f6, 0x0001), .driver_data = MODEL_CMEDIA_REF }, |
80 | { OXYGEN_PCI_SUBID(0x13f6, 0x0010), .driver_data = MODEL_CMEDIA_REF }, | 105 | { OXYGEN_PCI_SUBID(0x13f6, 0x0010), .driver_data = MODEL_CMEDIA_REF }, |
81 | { OXYGEN_PCI_SUBID(0x13f6, 0x8788), .driver_data = MODEL_CMEDIA_REF }, | 106 | { OXYGEN_PCI_SUBID(0x13f6, 0x8788), .driver_data = MODEL_CMEDIA_REF }, |
82 | { OXYGEN_PCI_SUBID(0x13f6, 0xffff), .driver_data = MODEL_CMEDIA_REF }, | ||
83 | { OXYGEN_PCI_SUBID(0x147a, 0xa017), .driver_data = MODEL_CMEDIA_REF }, | 107 | { OXYGEN_PCI_SUBID(0x147a, 0xa017), .driver_data = MODEL_CMEDIA_REF }, |
84 | { OXYGEN_PCI_SUBID(0x1a58, 0x0910), .driver_data = MODEL_CMEDIA_REF }, | 108 | { OXYGEN_PCI_SUBID(0x1a58, 0x0910), .driver_data = MODEL_CMEDIA_REF }, |
109 | /* Asus Xonar DG */ | ||
110 | { OXYGEN_PCI_SUBID(0x1043, 0x8467), .driver_data = MODEL_XONAR_DG }, | ||
111 | /* PCI 2.0 HD Audio */ | ||
112 | { OXYGEN_PCI_SUBID(0x13f6, 0x8782), .driver_data = MODEL_2CH_OUTPUT }, | ||
113 | /* Kuroutoshikou CMI8787-HG2PCI */ | ||
114 | { OXYGEN_PCI_SUBID(0x13f6, 0xffff), .driver_data = MODEL_HG2PCI }, | ||
115 | /* TempoTec HiFier Fantasia */ | ||
116 | { OXYGEN_PCI_SUBID(0x14c3, 0x1710), .driver_data = MODEL_FANTASIA }, | ||
117 | /* TempoTec HiFier Serenade */ | ||
118 | { OXYGEN_PCI_SUBID(0x14c3, 0x1711), .driver_data = MODEL_SERENADE }, | ||
119 | /* AuzenTech X-Meridian */ | ||
85 | { OXYGEN_PCI_SUBID(0x415a, 0x5431), .driver_data = MODEL_MERIDIAN }, | 120 | { OXYGEN_PCI_SUBID(0x415a, 0x5431), .driver_data = MODEL_MERIDIAN }, |
121 | /* AuzenTech X-Meridian 2G */ | ||
122 | { OXYGEN_PCI_SUBID(0x5431, 0x017a), .driver_data = MODEL_MERIDIAN_2G }, | ||
123 | /* HT-Omega Claro */ | ||
86 | { OXYGEN_PCI_SUBID(0x7284, 0x9761), .driver_data = MODEL_CLARO }, | 124 | { OXYGEN_PCI_SUBID(0x7284, 0x9761), .driver_data = MODEL_CLARO }, |
125 | /* HT-Omega Claro halo */ | ||
87 | { OXYGEN_PCI_SUBID(0x7284, 0x9781), .driver_data = MODEL_CLARO_HALO }, | 126 | { OXYGEN_PCI_SUBID(0x7284, 0x9781), .driver_data = MODEL_CLARO_HALO }, |
88 | { } | 127 | { } |
89 | }; | 128 | }; |
@@ -95,9 +134,15 @@ MODULE_DEVICE_TABLE(pci, oxygen_ids); | |||
95 | #define GPIO_AK5385_DFS_DOUBLE 0x0001 | 134 | #define GPIO_AK5385_DFS_DOUBLE 0x0001 |
96 | #define GPIO_AK5385_DFS_QUAD 0x0002 | 135 | #define GPIO_AK5385_DFS_QUAD 0x0002 |
97 | 136 | ||
137 | #define GPIO_MERIDIAN_DIG_MASK 0x0050 | ||
138 | #define GPIO_MERIDIAN_DIG_EXT 0x0010 | ||
139 | #define GPIO_MERIDIAN_DIG_BOARD 0x0040 | ||
140 | |||
141 | #define GPIO_CLARO_DIG_COAX 0x0040 | ||
98 | #define GPIO_CLARO_HP 0x0100 | 142 | #define GPIO_CLARO_HP 0x0100 |
99 | 143 | ||
100 | struct generic_data { | 144 | struct generic_data { |
145 | unsigned int dacs; | ||
101 | u8 ak4396_regs[4][5]; | 146 | u8 ak4396_regs[4][5]; |
102 | u16 wm8785_regs[3]; | 147 | u16 wm8785_regs[3]; |
103 | }; | 148 | }; |
@@ -148,7 +193,7 @@ static void ak4396_registers_init(struct oxygen *chip) | |||
148 | struct generic_data *data = chip->model_data; | 193 | struct generic_data *data = chip->model_data; |
149 | unsigned int i; | 194 | unsigned int i; |
150 | 195 | ||
151 | for (i = 0; i < 4; ++i) { | 196 | for (i = 0; i < data->dacs; ++i) { |
152 | ak4396_write(chip, i, AK4396_CONTROL_1, | 197 | ak4396_write(chip, i, AK4396_CONTROL_1, |
153 | AK4396_DIF_24_MSB | AK4396_RSTN); | 198 | AK4396_DIF_24_MSB | AK4396_RSTN); |
154 | ak4396_write(chip, i, AK4396_CONTROL_2, | 199 | ak4396_write(chip, i, AK4396_CONTROL_2, |
@@ -166,6 +211,7 @@ static void ak4396_init(struct oxygen *chip) | |||
166 | { | 211 | { |
167 | struct generic_data *data = chip->model_data; | 212 | struct generic_data *data = chip->model_data; |
168 | 213 | ||
214 | data->dacs = chip->model.dac_channels_pcm / 2; | ||
169 | data->ak4396_regs[0][AK4396_CONTROL_2] = | 215 | data->ak4396_regs[0][AK4396_CONTROL_2] = |
170 | AK4396_SMUTE | AK4396_DEM_OFF | AK4396_DFS_NORMAL; | 216 | AK4396_SMUTE | AK4396_DEM_OFF | AK4396_DFS_NORMAL; |
171 | ak4396_registers_init(chip); | 217 | ak4396_registers_init(chip); |
@@ -207,6 +253,10 @@ static void generic_init(struct oxygen *chip) | |||
207 | 253 | ||
208 | static void meridian_init(struct oxygen *chip) | 254 | static void meridian_init(struct oxygen *chip) |
209 | { | 255 | { |
256 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, | ||
257 | GPIO_MERIDIAN_DIG_MASK); | ||
258 | oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, | ||
259 | GPIO_MERIDIAN_DIG_BOARD, GPIO_MERIDIAN_DIG_MASK); | ||
210 | ak4396_init(chip); | 260 | ak4396_init(chip); |
211 | ak5385_init(chip); | 261 | ak5385_init(chip); |
212 | } | 262 | } |
@@ -220,6 +270,8 @@ static void claro_enable_hp(struct oxygen *chip) | |||
220 | 270 | ||
221 | static void claro_init(struct oxygen *chip) | 271 | static void claro_init(struct oxygen *chip) |
222 | { | 272 | { |
273 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_CLARO_DIG_COAX); | ||
274 | oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_CLARO_DIG_COAX); | ||
223 | ak4396_init(chip); | 275 | ak4396_init(chip); |
224 | wm8785_init(chip); | 276 | wm8785_init(chip); |
225 | claro_enable_hp(chip); | 277 | claro_enable_hp(chip); |
@@ -227,11 +279,24 @@ static void claro_init(struct oxygen *chip) | |||
227 | 279 | ||
228 | static void claro_halo_init(struct oxygen *chip) | 280 | static void claro_halo_init(struct oxygen *chip) |
229 | { | 281 | { |
282 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_CLARO_DIG_COAX); | ||
283 | oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_CLARO_DIG_COAX); | ||
230 | ak4396_init(chip); | 284 | ak4396_init(chip); |
231 | ak5385_init(chip); | 285 | ak5385_init(chip); |
232 | claro_enable_hp(chip); | 286 | claro_enable_hp(chip); |
233 | } | 287 | } |
234 | 288 | ||
289 | static void fantasia_init(struct oxygen *chip) | ||
290 | { | ||
291 | ak4396_init(chip); | ||
292 | snd_component_add(chip->card, "CS5340"); | ||
293 | } | ||
294 | |||
295 | static void stereo_output_init(struct oxygen *chip) | ||
296 | { | ||
297 | ak4396_init(chip); | ||
298 | } | ||
299 | |||
235 | static void generic_cleanup(struct oxygen *chip) | 300 | static void generic_cleanup(struct oxygen *chip) |
236 | { | 301 | { |
237 | } | 302 | } |
@@ -268,6 +333,11 @@ static void claro_resume(struct oxygen *chip) | |||
268 | claro_enable_hp(chip); | 333 | claro_enable_hp(chip); |
269 | } | 334 | } |
270 | 335 | ||
336 | static void stereo_resume(struct oxygen *chip) | ||
337 | { | ||
338 | ak4396_registers_init(chip); | ||
339 | } | ||
340 | |||
271 | static void set_ak4396_params(struct oxygen *chip, | 341 | static void set_ak4396_params(struct oxygen *chip, |
272 | struct snd_pcm_hw_params *params) | 342 | struct snd_pcm_hw_params *params) |
273 | { | 343 | { |
@@ -286,7 +356,7 @@ static void set_ak4396_params(struct oxygen *chip, | |||
286 | msleep(1); /* wait for the new MCLK to become stable */ | 356 | msleep(1); /* wait for the new MCLK to become stable */ |
287 | 357 | ||
288 | if (value != data->ak4396_regs[0][AK4396_CONTROL_2]) { | 358 | if (value != data->ak4396_regs[0][AK4396_CONTROL_2]) { |
289 | for (i = 0; i < 4; ++i) { | 359 | for (i = 0; i < data->dacs; ++i) { |
290 | ak4396_write(chip, i, AK4396_CONTROL_1, | 360 | ak4396_write(chip, i, AK4396_CONTROL_1, |
291 | AK4396_DIF_24_MSB); | 361 | AK4396_DIF_24_MSB); |
292 | ak4396_write(chip, i, AK4396_CONTROL_2, value); | 362 | ak4396_write(chip, i, AK4396_CONTROL_2, value); |
@@ -298,9 +368,10 @@ static void set_ak4396_params(struct oxygen *chip, | |||
298 | 368 | ||
299 | static void update_ak4396_volume(struct oxygen *chip) | 369 | static void update_ak4396_volume(struct oxygen *chip) |
300 | { | 370 | { |
371 | struct generic_data *data = chip->model_data; | ||
301 | unsigned int i; | 372 | unsigned int i; |
302 | 373 | ||
303 | for (i = 0; i < 4; ++i) { | 374 | for (i = 0; i < data->dacs; ++i) { |
304 | ak4396_write_cached(chip, i, AK4396_LCH_ATT, | 375 | ak4396_write_cached(chip, i, AK4396_LCH_ATT, |
305 | chip->dac_volume[i * 2]); | 376 | chip->dac_volume[i * 2]); |
306 | ak4396_write_cached(chip, i, AK4396_RCH_ATT, | 377 | ak4396_write_cached(chip, i, AK4396_RCH_ATT, |
@@ -317,7 +388,7 @@ static void update_ak4396_mute(struct oxygen *chip) | |||
317 | value = data->ak4396_regs[0][AK4396_CONTROL_2] & ~AK4396_SMUTE; | 388 | value = data->ak4396_regs[0][AK4396_CONTROL_2] & ~AK4396_SMUTE; |
318 | if (chip->dac_mute) | 389 | if (chip->dac_mute) |
319 | value |= AK4396_SMUTE; | 390 | value |= AK4396_SMUTE; |
320 | for (i = 0; i < 4; ++i) | 391 | for (i = 0; i < data->dacs; ++i) |
321 | ak4396_write_cached(chip, i, AK4396_CONTROL_2, value); | 392 | ak4396_write_cached(chip, i, AK4396_CONTROL_2, value); |
322 | } | 393 | } |
323 | 394 | ||
@@ -356,6 +427,10 @@ static void set_ak5385_params(struct oxygen *chip, | |||
356 | value, GPIO_AK5385_DFS_MASK); | 427 | value, GPIO_AK5385_DFS_MASK); |
357 | } | 428 | } |
358 | 429 | ||
430 | static void set_no_params(struct oxygen *chip, struct snd_pcm_hw_params *params) | ||
431 | { | ||
432 | } | ||
433 | |||
359 | static int rolloff_info(struct snd_kcontrol *ctl, | 434 | static int rolloff_info(struct snd_kcontrol *ctl, |
360 | struct snd_ctl_elem_info *info) | 435 | struct snd_ctl_elem_info *info) |
361 | { | 436 | { |
@@ -363,13 +438,7 @@ static int rolloff_info(struct snd_kcontrol *ctl, | |||
363 | "Sharp Roll-off", "Slow Roll-off" | 438 | "Sharp Roll-off", "Slow Roll-off" |
364 | }; | 439 | }; |
365 | 440 | ||
366 | info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 441 | return snd_ctl_enum_info(info, 1, 2, names); |
367 | info->count = 1; | ||
368 | info->value.enumerated.items = 2; | ||
369 | if (info->value.enumerated.item >= 2) | ||
370 | info->value.enumerated.item = 1; | ||
371 | strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); | ||
372 | return 0; | ||
373 | } | 442 | } |
374 | 443 | ||
375 | static int rolloff_get(struct snd_kcontrol *ctl, | 444 | static int rolloff_get(struct snd_kcontrol *ctl, |
@@ -400,7 +469,7 @@ static int rolloff_put(struct snd_kcontrol *ctl, | |||
400 | reg &= ~AK4396_SLOW; | 469 | reg &= ~AK4396_SLOW; |
401 | changed = reg != data->ak4396_regs[0][AK4396_CONTROL_2]; | 470 | changed = reg != data->ak4396_regs[0][AK4396_CONTROL_2]; |
402 | if (changed) { | 471 | if (changed) { |
403 | for (i = 0; i < 4; ++i) | 472 | for (i = 0; i < data->dacs; ++i) |
404 | ak4396_write(chip, i, AK4396_CONTROL_2, reg); | 473 | ak4396_write(chip, i, AK4396_CONTROL_2, reg); |
405 | } | 474 | } |
406 | mutex_unlock(&chip->mutex); | 475 | mutex_unlock(&chip->mutex); |
@@ -421,13 +490,7 @@ static int hpf_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) | |||
421 | "None", "High-pass Filter" | 490 | "None", "High-pass Filter" |
422 | }; | 491 | }; |
423 | 492 | ||
424 | info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 493 | return snd_ctl_enum_info(info, 1, 2, names); |
425 | info->count = 1; | ||
426 | info->value.enumerated.items = 2; | ||
427 | if (info->value.enumerated.item >= 2) | ||
428 | info->value.enumerated.item = 1; | ||
429 | strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); | ||
430 | return 0; | ||
431 | } | 494 | } |
432 | 495 | ||
433 | static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) | 496 | 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 = { | |||
466 | .put = hpf_put, | 529 | .put = hpf_put, |
467 | }; | 530 | }; |
468 | 531 | ||
532 | static int meridian_dig_source_info(struct snd_kcontrol *ctl, | ||
533 | struct snd_ctl_elem_info *info) | ||
534 | { | ||
535 | static const char *const names[2] = { "On-board", "Extension" }; | ||
536 | |||
537 | return snd_ctl_enum_info(info, 1, 2, names); | ||
538 | } | ||
539 | |||
540 | static int claro_dig_source_info(struct snd_kcontrol *ctl, | ||
541 | struct snd_ctl_elem_info *info) | ||
542 | { | ||
543 | static const char *const names[2] = { "Optical", "Coaxial" }; | ||
544 | |||
545 | return snd_ctl_enum_info(info, 1, 2, names); | ||
546 | } | ||
547 | |||
548 | static int meridian_dig_source_get(struct snd_kcontrol *ctl, | ||
549 | struct snd_ctl_elem_value *value) | ||
550 | { | ||
551 | struct oxygen *chip = ctl->private_data; | ||
552 | |||
553 | value->value.enumerated.item[0] = | ||
554 | !!(oxygen_read16(chip, OXYGEN_GPIO_DATA) & | ||
555 | GPIO_MERIDIAN_DIG_EXT); | ||
556 | return 0; | ||
557 | } | ||
558 | |||
559 | static int claro_dig_source_get(struct snd_kcontrol *ctl, | ||
560 | struct snd_ctl_elem_value *value) | ||
561 | { | ||
562 | struct oxygen *chip = ctl->private_data; | ||
563 | |||
564 | value->value.enumerated.item[0] = | ||
565 | !!(oxygen_read16(chip, OXYGEN_GPIO_DATA) & | ||
566 | GPIO_CLARO_DIG_COAX); | ||
567 | return 0; | ||
568 | } | ||
569 | |||
570 | static int meridian_dig_source_put(struct snd_kcontrol *ctl, | ||
571 | struct snd_ctl_elem_value *value) | ||
572 | { | ||
573 | struct oxygen *chip = ctl->private_data; | ||
574 | u16 old_reg, new_reg; | ||
575 | int changed; | ||
576 | |||
577 | mutex_lock(&chip->mutex); | ||
578 | old_reg = oxygen_read16(chip, OXYGEN_GPIO_DATA); | ||
579 | new_reg = old_reg & ~GPIO_MERIDIAN_DIG_MASK; | ||
580 | if (value->value.enumerated.item[0] == 0) | ||
581 | new_reg |= GPIO_MERIDIAN_DIG_BOARD; | ||
582 | else | ||
583 | new_reg |= GPIO_MERIDIAN_DIG_EXT; | ||
584 | changed = new_reg != old_reg; | ||
585 | if (changed) | ||
586 | oxygen_write16(chip, OXYGEN_GPIO_DATA, new_reg); | ||
587 | mutex_unlock(&chip->mutex); | ||
588 | return changed; | ||
589 | } | ||
590 | |||
591 | static int claro_dig_source_put(struct snd_kcontrol *ctl, | ||
592 | struct snd_ctl_elem_value *value) | ||
593 | { | ||
594 | struct oxygen *chip = ctl->private_data; | ||
595 | u16 old_reg, new_reg; | ||
596 | int changed; | ||
597 | |||
598 | mutex_lock(&chip->mutex); | ||
599 | old_reg = oxygen_read16(chip, OXYGEN_GPIO_DATA); | ||
600 | new_reg = old_reg & ~GPIO_CLARO_DIG_COAX; | ||
601 | if (value->value.enumerated.item[0]) | ||
602 | new_reg |= GPIO_CLARO_DIG_COAX; | ||
603 | changed = new_reg != old_reg; | ||
604 | if (changed) | ||
605 | oxygen_write16(chip, OXYGEN_GPIO_DATA, new_reg); | ||
606 | mutex_unlock(&chip->mutex); | ||
607 | return changed; | ||
608 | } | ||
609 | |||
610 | static const struct snd_kcontrol_new meridian_dig_source_control = { | ||
611 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
612 | .name = "IEC958 Source Capture Enum", | ||
613 | .info = meridian_dig_source_info, | ||
614 | .get = meridian_dig_source_get, | ||
615 | .put = meridian_dig_source_put, | ||
616 | }; | ||
617 | |||
618 | static const struct snd_kcontrol_new claro_dig_source_control = { | ||
619 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
620 | .name = "IEC958 Source Capture Enum", | ||
621 | .info = claro_dig_source_info, | ||
622 | .get = claro_dig_source_get, | ||
623 | .put = claro_dig_source_put, | ||
624 | }; | ||
625 | |||
469 | static int generic_mixer_init(struct oxygen *chip) | 626 | static int generic_mixer_init(struct oxygen *chip) |
470 | { | 627 | { |
471 | return snd_ctl_add(chip->card, snd_ctl_new1(&rolloff_control, chip)); | 628 | 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) | |||
484 | return 0; | 641 | return 0; |
485 | } | 642 | } |
486 | 643 | ||
644 | static int meridian_mixer_init(struct oxygen *chip) | ||
645 | { | ||
646 | int err; | ||
647 | |||
648 | err = generic_mixer_init(chip); | ||
649 | if (err < 0) | ||
650 | return err; | ||
651 | err = snd_ctl_add(chip->card, | ||
652 | snd_ctl_new1(&meridian_dig_source_control, chip)); | ||
653 | if (err < 0) | ||
654 | return err; | ||
655 | return 0; | ||
656 | } | ||
657 | |||
658 | static int claro_mixer_init(struct oxygen *chip) | ||
659 | { | ||
660 | int err; | ||
661 | |||
662 | err = generic_wm8785_mixer_init(chip); | ||
663 | if (err < 0) | ||
664 | return err; | ||
665 | err = snd_ctl_add(chip->card, | ||
666 | snd_ctl_new1(&claro_dig_source_control, chip)); | ||
667 | if (err < 0) | ||
668 | return err; | ||
669 | return 0; | ||
670 | } | ||
671 | |||
672 | static int claro_halo_mixer_init(struct oxygen *chip) | ||
673 | { | ||
674 | int err; | ||
675 | |||
676 | err = generic_mixer_init(chip); | ||
677 | if (err < 0) | ||
678 | return err; | ||
679 | err = snd_ctl_add(chip->card, | ||
680 | snd_ctl_new1(&claro_dig_source_control, chip)); | ||
681 | if (err < 0) | ||
682 | return err; | ||
683 | return 0; | ||
684 | } | ||
685 | |||
686 | static void dump_ak4396_registers(struct oxygen *chip, | ||
687 | struct snd_info_buffer *buffer) | ||
688 | { | ||
689 | struct generic_data *data = chip->model_data; | ||
690 | unsigned int dac, i; | ||
691 | |||
692 | for (dac = 0; dac < data->dacs; ++dac) { | ||
693 | snd_iprintf(buffer, "\nAK4396 %u:", dac + 1); | ||
694 | for (i = 0; i < 5; ++i) | ||
695 | snd_iprintf(buffer, " %02x", data->ak4396_regs[dac][i]); | ||
696 | } | ||
697 | snd_iprintf(buffer, "\n"); | ||
698 | } | ||
699 | |||
700 | static void dump_wm8785_registers(struct oxygen *chip, | ||
701 | struct snd_info_buffer *buffer) | ||
702 | { | ||
703 | struct generic_data *data = chip->model_data; | ||
704 | unsigned int i; | ||
705 | |||
706 | snd_iprintf(buffer, "\nWM8785:"); | ||
707 | for (i = 0; i < 3; ++i) | ||
708 | snd_iprintf(buffer, " %03x", data->wm8785_regs[i]); | ||
709 | snd_iprintf(buffer, "\n"); | ||
710 | } | ||
711 | |||
712 | static void dump_oxygen_registers(struct oxygen *chip, | ||
713 | struct snd_info_buffer *buffer) | ||
714 | { | ||
715 | dump_ak4396_registers(chip, buffer); | ||
716 | dump_wm8785_registers(chip, buffer); | ||
717 | } | ||
718 | |||
487 | static const DECLARE_TLV_DB_LINEAR(ak4396_db_scale, TLV_DB_GAIN_MUTE, 0); | 719 | static const DECLARE_TLV_DB_LINEAR(ak4396_db_scale, TLV_DB_GAIN_MUTE, 0); |
488 | 720 | ||
489 | static const struct oxygen_model model_generic = { | 721 | static const struct oxygen_model model_generic = { |
@@ -494,11 +726,11 @@ static const struct oxygen_model model_generic = { | |||
494 | .mixer_init = generic_wm8785_mixer_init, | 726 | .mixer_init = generic_wm8785_mixer_init, |
495 | .cleanup = generic_cleanup, | 727 | .cleanup = generic_cleanup, |
496 | .resume = generic_resume, | 728 | .resume = generic_resume, |
497 | .get_i2s_mclk = oxygen_default_i2s_mclk, | ||
498 | .set_dac_params = set_ak4396_params, | 729 | .set_dac_params = set_ak4396_params, |
499 | .set_adc_params = set_wm8785_params, | 730 | .set_adc_params = set_wm8785_params, |
500 | .update_dac_volume = update_ak4396_volume, | 731 | .update_dac_volume = update_ak4396_volume, |
501 | .update_dac_mute = update_ak4396_mute, | 732 | .update_dac_mute = update_ak4396_mute, |
733 | .dump_registers = dump_oxygen_registers, | ||
502 | .dac_tlv = ak4396_db_scale, | 734 | .dac_tlv = ak4396_db_scale, |
503 | .model_data_size = sizeof(struct generic_data), | 735 | .model_data_size = sizeof(struct generic_data), |
504 | .device_config = PLAYBACK_0_TO_I2S | | 736 | .device_config = PLAYBACK_0_TO_I2S | |
@@ -508,11 +740,14 @@ static const struct oxygen_model model_generic = { | |||
508 | CAPTURE_1_FROM_SPDIF | | 740 | CAPTURE_1_FROM_SPDIF | |
509 | CAPTURE_2_FROM_AC97_1 | | 741 | CAPTURE_2_FROM_AC97_1 | |
510 | AC97_CD_INPUT, | 742 | AC97_CD_INPUT, |
511 | .dac_channels = 8, | 743 | .dac_channels_pcm = 8, |
744 | .dac_channels_mixer = 8, | ||
512 | .dac_volume_min = 0, | 745 | .dac_volume_min = 0, |
513 | .dac_volume_max = 255, | 746 | .dac_volume_max = 255, |
514 | .function_flags = OXYGEN_FUNCTION_SPI | | 747 | .function_flags = OXYGEN_FUNCTION_SPI | |
515 | OXYGEN_FUNCTION_ENABLE_SPI_4_5, | 748 | OXYGEN_FUNCTION_ENABLE_SPI_4_5, |
749 | .dac_mclks = OXYGEN_MCLKS(256, 128, 128), | ||
750 | .adc_mclks = OXYGEN_MCLKS(256, 256, 128), | ||
516 | .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | 751 | .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, |
517 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | 752 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, |
518 | }; | 753 | }; |
@@ -520,42 +755,87 @@ static const struct oxygen_model model_generic = { | |||
520 | static int __devinit get_oxygen_model(struct oxygen *chip, | 755 | static int __devinit get_oxygen_model(struct oxygen *chip, |
521 | const struct pci_device_id *id) | 756 | const struct pci_device_id *id) |
522 | { | 757 | { |
758 | static const char *const names[] = { | ||
759 | [MODEL_MERIDIAN] = "AuzenTech X-Meridian", | ||
760 | [MODEL_MERIDIAN_2G] = "AuzenTech X-Meridian 2G", | ||
761 | [MODEL_CLARO] = "HT-Omega Claro", | ||
762 | [MODEL_CLARO_HALO] = "HT-Omega Claro halo", | ||
763 | [MODEL_FANTASIA] = "TempoTec HiFier Fantasia", | ||
764 | [MODEL_SERENADE] = "TempoTec HiFier Serenade", | ||
765 | [MODEL_HG2PCI] = "CMI8787-HG2PCI", | ||
766 | }; | ||
767 | |||
523 | chip->model = model_generic; | 768 | chip->model = model_generic; |
524 | switch (id->driver_data) { | 769 | switch (id->driver_data) { |
525 | case MODEL_MERIDIAN: | 770 | case MODEL_MERIDIAN: |
771 | case MODEL_MERIDIAN_2G: | ||
526 | chip->model.init = meridian_init; | 772 | chip->model.init = meridian_init; |
527 | chip->model.mixer_init = generic_mixer_init; | 773 | chip->model.mixer_init = meridian_mixer_init; |
528 | chip->model.resume = meridian_resume; | 774 | chip->model.resume = meridian_resume; |
529 | chip->model.set_adc_params = set_ak5385_params; | 775 | chip->model.set_adc_params = set_ak5385_params; |
776 | chip->model.dump_registers = dump_ak4396_registers; | ||
530 | chip->model.device_config = PLAYBACK_0_TO_I2S | | 777 | chip->model.device_config = PLAYBACK_0_TO_I2S | |
531 | PLAYBACK_1_TO_SPDIF | | 778 | PLAYBACK_1_TO_SPDIF | |
532 | CAPTURE_0_FROM_I2S_2 | | 779 | CAPTURE_0_FROM_I2S_2 | |
533 | CAPTURE_1_FROM_SPDIF; | 780 | CAPTURE_1_FROM_SPDIF; |
781 | if (id->driver_data == MODEL_MERIDIAN) | ||
782 | chip->model.device_config |= AC97_CD_INPUT; | ||
534 | break; | 783 | break; |
535 | case MODEL_CLARO: | 784 | case MODEL_CLARO: |
536 | chip->model.init = claro_init; | 785 | chip->model.init = claro_init; |
786 | chip->model.mixer_init = claro_mixer_init; | ||
537 | chip->model.cleanup = claro_cleanup; | 787 | chip->model.cleanup = claro_cleanup; |
538 | chip->model.suspend = claro_suspend; | 788 | chip->model.suspend = claro_suspend; |
539 | chip->model.resume = claro_resume; | 789 | chip->model.resume = claro_resume; |
540 | break; | 790 | break; |
541 | case MODEL_CLARO_HALO: | 791 | case MODEL_CLARO_HALO: |
542 | chip->model.init = claro_halo_init; | 792 | chip->model.init = claro_halo_init; |
543 | chip->model.mixer_init = generic_mixer_init; | 793 | chip->model.mixer_init = claro_halo_mixer_init; |
544 | chip->model.cleanup = claro_cleanup; | 794 | chip->model.cleanup = claro_cleanup; |
545 | chip->model.suspend = claro_suspend; | 795 | chip->model.suspend = claro_suspend; |
546 | chip->model.resume = claro_resume; | 796 | chip->model.resume = claro_resume; |
547 | chip->model.set_adc_params = set_ak5385_params; | 797 | chip->model.set_adc_params = set_ak5385_params; |
798 | chip->model.dump_registers = dump_ak4396_registers; | ||
548 | chip->model.device_config = PLAYBACK_0_TO_I2S | | 799 | chip->model.device_config = PLAYBACK_0_TO_I2S | |
549 | PLAYBACK_1_TO_SPDIF | | 800 | PLAYBACK_1_TO_SPDIF | |
550 | CAPTURE_0_FROM_I2S_2 | | 801 | CAPTURE_0_FROM_I2S_2 | |
551 | CAPTURE_1_FROM_SPDIF; | 802 | CAPTURE_1_FROM_SPDIF; |
552 | break; | 803 | break; |
804 | case MODEL_FANTASIA: | ||
805 | case MODEL_SERENADE: | ||
806 | case MODEL_2CH_OUTPUT: | ||
807 | case MODEL_HG2PCI: | ||
808 | chip->model.shortname = "C-Media CMI8787"; | ||
809 | chip->model.chip = "CMI8787"; | ||
810 | if (id->driver_data == MODEL_FANTASIA) | ||
811 | chip->model.init = fantasia_init; | ||
812 | else | ||
813 | chip->model.init = stereo_output_init; | ||
814 | chip->model.resume = stereo_resume; | ||
815 | chip->model.mixer_init = generic_mixer_init; | ||
816 | chip->model.set_adc_params = set_no_params; | ||
817 | chip->model.dump_registers = dump_ak4396_registers; | ||
818 | chip->model.device_config = PLAYBACK_0_TO_I2S | | ||
819 | PLAYBACK_1_TO_SPDIF; | ||
820 | if (id->driver_data == MODEL_FANTASIA) { | ||
821 | chip->model.device_config |= CAPTURE_0_FROM_I2S_1; | ||
822 | chip->model.adc_mclks = OXYGEN_MCLKS(256, 128, 128); | ||
823 | } | ||
824 | chip->model.dac_channels_pcm = 2; | ||
825 | chip->model.dac_channels_mixer = 2; | ||
826 | break; | ||
827 | case MODEL_XONAR_DG: | ||
828 | chip->model = model_xonar_dg; | ||
829 | break; | ||
553 | } | 830 | } |
554 | if (id->driver_data == MODEL_MERIDIAN || | 831 | if (id->driver_data == MODEL_MERIDIAN || |
832 | id->driver_data == MODEL_MERIDIAN_2G || | ||
555 | id->driver_data == MODEL_CLARO_HALO) { | 833 | id->driver_data == MODEL_CLARO_HALO) { |
556 | chip->model.misc_flags = OXYGEN_MISC_MIDI; | 834 | chip->model.misc_flags = OXYGEN_MISC_MIDI; |
557 | chip->model.device_config |= MIDI_OUTPUT | MIDI_INPUT; | 835 | chip->model.device_config |= MIDI_OUTPUT | MIDI_INPUT; |
558 | } | 836 | } |
837 | if (id->driver_data < ARRAY_SIZE(names) && names[id->driver_data]) | ||
838 | chip->model.shortname = names[id->driver_data]; | ||
559 | return 0; | 839 | return 0; |
560 | } | 840 | } |
561 | 841 | ||
diff --git a/sound/pci/oxygen/oxygen.h b/sound/pci/oxygen/oxygen.h index 7d5222caa0a9..c2ae63d17cd2 100644 --- a/sound/pci/oxygen/oxygen.h +++ b/sound/pci/oxygen/oxygen.h | |||
@@ -16,6 +16,10 @@ | |||
16 | #define PCM_AC97 5 | 16 | #define PCM_AC97 5 |
17 | #define PCM_COUNT 6 | 17 | #define PCM_COUNT 6 |
18 | 18 | ||
19 | #define OXYGEN_MCLKS(f_single, f_double, f_quad) ((MCLK_##f_single << 0) | \ | ||
20 | (MCLK_##f_double << 2) | \ | ||
21 | (MCLK_##f_quad << 4)) | ||
22 | |||
19 | #define OXYGEN_IO_SIZE 0x100 | 23 | #define OXYGEN_IO_SIZE 0x100 |
20 | 24 | ||
21 | #define OXYGEN_EEPROM_ID 0x434d /* "CM" */ | 25 | #define OXYGEN_EEPROM_ID 0x434d /* "CM" */ |
@@ -35,6 +39,7 @@ | |||
35 | #define MIDI_OUTPUT 0x0800 | 39 | #define MIDI_OUTPUT 0x0800 |
36 | #define MIDI_INPUT 0x1000 | 40 | #define MIDI_INPUT 0x1000 |
37 | #define AC97_CD_INPUT 0x2000 | 41 | #define AC97_CD_INPUT 0x2000 |
42 | #define AC97_FMIC_SWITCH 0x4000 | ||
38 | 43 | ||
39 | enum { | 44 | enum { |
40 | CONTROL_SPDIF_PCM, | 45 | CONTROL_SPDIF_PCM, |
@@ -65,6 +70,7 @@ struct snd_pcm_hardware; | |||
65 | struct snd_pcm_hw_params; | 70 | struct snd_pcm_hw_params; |
66 | struct snd_kcontrol_new; | 71 | struct snd_kcontrol_new; |
67 | struct snd_rawmidi; | 72 | struct snd_rawmidi; |
73 | struct snd_info_buffer; | ||
68 | struct oxygen; | 74 | struct oxygen; |
69 | 75 | ||
70 | struct oxygen_model { | 76 | struct oxygen_model { |
@@ -79,8 +85,6 @@ struct oxygen_model { | |||
79 | void (*resume)(struct oxygen *chip); | 85 | void (*resume)(struct oxygen *chip); |
80 | void (*pcm_hardware_filter)(unsigned int channel, | 86 | void (*pcm_hardware_filter)(unsigned int channel, |
81 | struct snd_pcm_hardware *hardware); | 87 | struct snd_pcm_hardware *hardware); |
82 | unsigned int (*get_i2s_mclk)(struct oxygen *chip, unsigned int channel, | ||
83 | struct snd_pcm_hw_params *hw_params); | ||
84 | void (*set_dac_params)(struct oxygen *chip, | 88 | void (*set_dac_params)(struct oxygen *chip, |
85 | struct snd_pcm_hw_params *params); | 89 | struct snd_pcm_hw_params *params); |
86 | void (*set_adc_params)(struct oxygen *chip, | 90 | void (*set_adc_params)(struct oxygen *chip, |
@@ -92,15 +96,19 @@ struct oxygen_model { | |||
92 | void (*uart_input)(struct oxygen *chip); | 96 | void (*uart_input)(struct oxygen *chip); |
93 | void (*ac97_switch)(struct oxygen *chip, | 97 | void (*ac97_switch)(struct oxygen *chip, |
94 | unsigned int reg, unsigned int mute); | 98 | unsigned int reg, unsigned int mute); |
99 | void (*dump_registers)(struct oxygen *chip, | ||
100 | struct snd_info_buffer *buffer); | ||
95 | const unsigned int *dac_tlv; | 101 | const unsigned int *dac_tlv; |
96 | unsigned long private_data; | ||
97 | size_t model_data_size; | 102 | size_t model_data_size; |
98 | unsigned int device_config; | 103 | unsigned int device_config; |
99 | u8 dac_channels; | 104 | u8 dac_channels_pcm; |
105 | u8 dac_channels_mixer; | ||
100 | u8 dac_volume_min; | 106 | u8 dac_volume_min; |
101 | u8 dac_volume_max; | 107 | u8 dac_volume_max; |
102 | u8 misc_flags; | 108 | u8 misc_flags; |
103 | u8 function_flags; | 109 | u8 function_flags; |
110 | u8 dac_mclks; | ||
111 | u8 adc_mclks; | ||
104 | u16 dac_i2s_format; | 112 | u16 dac_i2s_format; |
105 | u16 adc_i2s_format; | 113 | u16 adc_i2s_format; |
106 | }; | 114 | }; |
@@ -121,7 +129,6 @@ struct oxygen { | |||
121 | u8 pcm_running; | 129 | u8 pcm_running; |
122 | u8 dac_routing; | 130 | u8 dac_routing; |
123 | u8 spdif_playback_enable; | 131 | u8 spdif_playback_enable; |
124 | u8 revision; | ||
125 | u8 has_ac97_0; | 132 | u8 has_ac97_0; |
126 | u8 has_ac97_1; | 133 | u8 has_ac97_1; |
127 | u32 spdif_bits; | 134 | u32 spdif_bits; |
@@ -167,8 +174,6 @@ void oxygen_update_spdif_source(struct oxygen *chip); | |||
167 | /* oxygen_pcm.c */ | 174 | /* oxygen_pcm.c */ |
168 | 175 | ||
169 | int oxygen_pcm_init(struct oxygen *chip); | 176 | int oxygen_pcm_init(struct oxygen *chip); |
170 | unsigned int oxygen_default_i2s_mclk(struct oxygen *chip, unsigned int channel, | ||
171 | struct snd_pcm_hw_params *hw_params); | ||
172 | 177 | ||
173 | /* oxygen_io.c */ | 178 | /* oxygen_io.c */ |
174 | 179 | ||
diff --git a/sound/pci/oxygen/oxygen_io.c b/sound/pci/oxygen/oxygen_io.c index 09b2b2a36df5..f5164b1e1c80 100644 --- a/sound/pci/oxygen/oxygen_io.c +++ b/sound/pci/oxygen/oxygen_io.c | |||
@@ -197,11 +197,11 @@ void oxygen_write_spi(struct oxygen *chip, u8 control, unsigned int data) | |||
197 | { | 197 | { |
198 | unsigned int count; | 198 | unsigned int count; |
199 | 199 | ||
200 | /* should not need more than 7.68 us (24 * 320 ns) */ | 200 | /* should not need more than 30.72 us (24 * 1.28 us) */ |
201 | count = 10; | 201 | count = 10; |
202 | while ((oxygen_read8(chip, OXYGEN_SPI_CONTROL) & OXYGEN_SPI_BUSY) | 202 | while ((oxygen_read8(chip, OXYGEN_SPI_CONTROL) & OXYGEN_SPI_BUSY) |
203 | && count > 0) { | 203 | && count > 0) { |
204 | udelay(1); | 204 | udelay(4); |
205 | --count; | 205 | --count; |
206 | } | 206 | } |
207 | 207 | ||
diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c index e5ebe56fb0c5..70b739816fcc 100644 --- a/sound/pci/oxygen/oxygen_lib.c +++ b/sound/pci/oxygen/oxygen_lib.c | |||
@@ -202,7 +202,13 @@ static void oxygen_proc_read(struct snd_info_entry *entry, | |||
202 | struct oxygen *chip = entry->private_data; | 202 | struct oxygen *chip = entry->private_data; |
203 | int i, j; | 203 | int i, j; |
204 | 204 | ||
205 | snd_iprintf(buffer, "CMI8788\n\n"); | 205 | switch (oxygen_read8(chip, OXYGEN_REVISION) & OXYGEN_PACKAGE_ID_MASK) { |
206 | case OXYGEN_PACKAGE_ID_8786: i = '6'; break; | ||
207 | case OXYGEN_PACKAGE_ID_8787: i = '7'; break; | ||
208 | case OXYGEN_PACKAGE_ID_8788: i = '8'; break; | ||
209 | default: i = '?'; break; | ||
210 | } | ||
211 | snd_iprintf(buffer, "CMI878%c:\n", i); | ||
206 | for (i = 0; i < OXYGEN_IO_SIZE; i += 0x10) { | 212 | for (i = 0; i < OXYGEN_IO_SIZE; i += 0x10) { |
207 | snd_iprintf(buffer, "%02x:", i); | 213 | snd_iprintf(buffer, "%02x:", i); |
208 | for (j = 0; j < 0x10; ++j) | 214 | for (j = 0; j < 0x10; ++j) |
@@ -212,7 +218,7 @@ static void oxygen_proc_read(struct snd_info_entry *entry, | |||
212 | if (mutex_lock_interruptible(&chip->mutex) < 0) | 218 | if (mutex_lock_interruptible(&chip->mutex) < 0) |
213 | return; | 219 | return; |
214 | if (chip->has_ac97_0) { | 220 | if (chip->has_ac97_0) { |
215 | snd_iprintf(buffer, "\nAC97\n"); | 221 | snd_iprintf(buffer, "\nAC97:\n"); |
216 | for (i = 0; i < 0x80; i += 0x10) { | 222 | for (i = 0; i < 0x80; i += 0x10) { |
217 | snd_iprintf(buffer, "%02x:", i); | 223 | snd_iprintf(buffer, "%02x:", i); |
218 | for (j = 0; j < 0x10; j += 2) | 224 | for (j = 0; j < 0x10; j += 2) |
@@ -222,7 +228,7 @@ static void oxygen_proc_read(struct snd_info_entry *entry, | |||
222 | } | 228 | } |
223 | } | 229 | } |
224 | if (chip->has_ac97_1) { | 230 | if (chip->has_ac97_1) { |
225 | snd_iprintf(buffer, "\nAC97 2\n"); | 231 | snd_iprintf(buffer, "\nAC97 2:\n"); |
226 | for (i = 0; i < 0x80; i += 0x10) { | 232 | for (i = 0; i < 0x80; i += 0x10) { |
227 | snd_iprintf(buffer, "%02x:", i); | 233 | snd_iprintf(buffer, "%02x:", i); |
228 | for (j = 0; j < 0x10; j += 2) | 234 | for (j = 0; j < 0x10; j += 2) |
@@ -232,13 +238,15 @@ static void oxygen_proc_read(struct snd_info_entry *entry, | |||
232 | } | 238 | } |
233 | } | 239 | } |
234 | mutex_unlock(&chip->mutex); | 240 | mutex_unlock(&chip->mutex); |
241 | if (chip->model.dump_registers) | ||
242 | chip->model.dump_registers(chip, buffer); | ||
235 | } | 243 | } |
236 | 244 | ||
237 | static void oxygen_proc_init(struct oxygen *chip) | 245 | static void oxygen_proc_init(struct oxygen *chip) |
238 | { | 246 | { |
239 | struct snd_info_entry *entry; | 247 | struct snd_info_entry *entry; |
240 | 248 | ||
241 | if (!snd_card_proc_new(chip->card, "cmi8788", &entry)) | 249 | if (!snd_card_proc_new(chip->card, "oxygen", &entry)) |
242 | snd_info_set_text_ops(entry, chip, oxygen_proc_read); | 250 | snd_info_set_text_ops(entry, chip, oxygen_proc_read); |
243 | } | 251 | } |
244 | #else | 252 | #else |
@@ -262,7 +270,7 @@ oxygen_search_pci_id(struct oxygen *chip, const struct pci_device_id ids[]) | |||
262 | */ | 270 | */ |
263 | subdevice = oxygen_read_eeprom(chip, 2); | 271 | subdevice = oxygen_read_eeprom(chip, 2); |
264 | /* use default ID if EEPROM is missing */ | 272 | /* use default ID if EEPROM is missing */ |
265 | if (subdevice == 0xffff) | 273 | if (subdevice == 0xffff && oxygen_read_eeprom(chip, 1) == 0xffff) |
266 | subdevice = 0x8788; | 274 | subdevice = 0x8788; |
267 | /* | 275 | /* |
268 | * We use only the subsystem device ID for searching because it is | 276 | * We use only the subsystem device ID for searching because it is |
@@ -364,12 +372,7 @@ static void oxygen_init(struct oxygen *chip) | |||
364 | (IEC958_AES1_CON_PCM_CODER << OXYGEN_SPDIF_CATEGORY_SHIFT); | 372 | (IEC958_AES1_CON_PCM_CODER << OXYGEN_SPDIF_CATEGORY_SHIFT); |
365 | chip->spdif_pcm_bits = chip->spdif_bits; | 373 | chip->spdif_pcm_bits = chip->spdif_bits; |
366 | 374 | ||
367 | if (oxygen_read8(chip, OXYGEN_REVISION) & OXYGEN_REVISION_2) | 375 | if (!(oxygen_read8(chip, OXYGEN_REVISION) & OXYGEN_REVISION_2)) |
368 | chip->revision = 2; | ||
369 | else | ||
370 | chip->revision = 1; | ||
371 | |||
372 | if (chip->revision == 1) | ||
373 | oxygen_set_bits8(chip, OXYGEN_MISC, | 376 | oxygen_set_bits8(chip, OXYGEN_MISC, |
374 | OXYGEN_MISC_PCI_MEM_W_1_CLOCK); | 377 | OXYGEN_MISC_PCI_MEM_W_1_CLOCK); |
375 | 378 | ||
@@ -406,28 +409,40 @@ static void oxygen_init(struct oxygen *chip) | |||
406 | (OXYGEN_FORMAT_16 << OXYGEN_MULTICH_FORMAT_SHIFT)); | 409 | (OXYGEN_FORMAT_16 << OXYGEN_MULTICH_FORMAT_SHIFT)); |
407 | oxygen_write8(chip, OXYGEN_REC_CHANNELS, OXYGEN_REC_CHANNELS_2_2_2); | 410 | oxygen_write8(chip, OXYGEN_REC_CHANNELS, OXYGEN_REC_CHANNELS_2_2_2); |
408 | oxygen_write16(chip, OXYGEN_I2S_MULTICH_FORMAT, | 411 | oxygen_write16(chip, OXYGEN_I2S_MULTICH_FORMAT, |
409 | OXYGEN_RATE_48000 | chip->model.dac_i2s_format | | 412 | OXYGEN_RATE_48000 | |
410 | OXYGEN_I2S_MCLK_256 | OXYGEN_I2S_BITS_16 | | 413 | chip->model.dac_i2s_format | |
411 | OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64); | 414 | OXYGEN_I2S_MCLK(chip->model.dac_mclks) | |
415 | OXYGEN_I2S_BITS_16 | | ||
416 | OXYGEN_I2S_MASTER | | ||
417 | OXYGEN_I2S_BCLK_64); | ||
412 | if (chip->model.device_config & CAPTURE_0_FROM_I2S_1) | 418 | if (chip->model.device_config & CAPTURE_0_FROM_I2S_1) |
413 | oxygen_write16(chip, OXYGEN_I2S_A_FORMAT, | 419 | oxygen_write16(chip, OXYGEN_I2S_A_FORMAT, |
414 | OXYGEN_RATE_48000 | chip->model.adc_i2s_format | | 420 | OXYGEN_RATE_48000 | |
415 | OXYGEN_I2S_MCLK_256 | OXYGEN_I2S_BITS_16 | | 421 | chip->model.adc_i2s_format | |
416 | OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64); | 422 | OXYGEN_I2S_MCLK(chip->model.adc_mclks) | |
423 | OXYGEN_I2S_BITS_16 | | ||
424 | OXYGEN_I2S_MASTER | | ||
425 | OXYGEN_I2S_BCLK_64); | ||
417 | else | 426 | else |
418 | oxygen_write16(chip, OXYGEN_I2S_A_FORMAT, | 427 | oxygen_write16(chip, OXYGEN_I2S_A_FORMAT, |
419 | OXYGEN_I2S_MASTER | OXYGEN_I2S_MUTE_MCLK); | 428 | OXYGEN_I2S_MASTER | |
429 | OXYGEN_I2S_MUTE_MCLK); | ||
420 | if (chip->model.device_config & (CAPTURE_0_FROM_I2S_2 | | 430 | if (chip->model.device_config & (CAPTURE_0_FROM_I2S_2 | |
421 | CAPTURE_2_FROM_I2S_2)) | 431 | CAPTURE_2_FROM_I2S_2)) |
422 | oxygen_write16(chip, OXYGEN_I2S_B_FORMAT, | 432 | oxygen_write16(chip, OXYGEN_I2S_B_FORMAT, |
423 | OXYGEN_RATE_48000 | chip->model.adc_i2s_format | | 433 | OXYGEN_RATE_48000 | |
424 | OXYGEN_I2S_MCLK_256 | OXYGEN_I2S_BITS_16 | | 434 | chip->model.adc_i2s_format | |
425 | OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64); | 435 | OXYGEN_I2S_MCLK(chip->model.adc_mclks) | |
436 | OXYGEN_I2S_BITS_16 | | ||
437 | OXYGEN_I2S_MASTER | | ||
438 | OXYGEN_I2S_BCLK_64); | ||
426 | else | 439 | else |
427 | oxygen_write16(chip, OXYGEN_I2S_B_FORMAT, | 440 | oxygen_write16(chip, OXYGEN_I2S_B_FORMAT, |
428 | OXYGEN_I2S_MASTER | OXYGEN_I2S_MUTE_MCLK); | 441 | OXYGEN_I2S_MASTER | |
442 | OXYGEN_I2S_MUTE_MCLK); | ||
429 | oxygen_write16(chip, OXYGEN_I2S_C_FORMAT, | 443 | oxygen_write16(chip, OXYGEN_I2S_C_FORMAT, |
430 | OXYGEN_I2S_MASTER | OXYGEN_I2S_MUTE_MCLK); | 444 | OXYGEN_I2S_MASTER | |
445 | OXYGEN_I2S_MUTE_MCLK); | ||
431 | oxygen_clear_bits32(chip, OXYGEN_SPDIF_CONTROL, | 446 | oxygen_clear_bits32(chip, OXYGEN_SPDIF_CONTROL, |
432 | OXYGEN_SPDIF_OUT_ENABLE | | 447 | OXYGEN_SPDIF_OUT_ENABLE | |
433 | OXYGEN_SPDIF_LOOPBACK); | 448 | OXYGEN_SPDIF_LOOPBACK); |
@@ -557,7 +572,8 @@ static void oxygen_card_free(struct snd_card *card) | |||
557 | oxygen_shutdown(chip); | 572 | oxygen_shutdown(chip); |
558 | if (chip->irq >= 0) | 573 | if (chip->irq >= 0) |
559 | free_irq(chip->irq, chip); | 574 | free_irq(chip->irq, chip); |
560 | flush_scheduled_work(); | 575 | flush_work_sync(&chip->spdif_input_bits_work); |
576 | flush_work_sync(&chip->gpio_work); | ||
561 | chip->model.cleanup(chip); | 577 | chip->model.cleanup(chip); |
562 | kfree(chip->model_data); | 578 | kfree(chip->model_data); |
563 | mutex_destroy(&chip->mutex); | 579 | mutex_destroy(&chip->mutex); |
@@ -648,8 +664,8 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id, | |||
648 | 664 | ||
649 | strcpy(card->driver, chip->model.chip); | 665 | strcpy(card->driver, chip->model.chip); |
650 | strcpy(card->shortname, chip->model.shortname); | 666 | strcpy(card->shortname, chip->model.shortname); |
651 | sprintf(card->longname, "%s (rev %u) at %#lx, irq %i", | 667 | sprintf(card->longname, "%s at %#lx, irq %i", |
652 | chip->model.longname, chip->revision, chip->addr, chip->irq); | 668 | chip->model.longname, chip->addr, chip->irq); |
653 | strcpy(card->mixername, chip->model.chip); | 669 | strcpy(card->mixername, chip->model.chip); |
654 | snd_component_add(card, chip->model.chip); | 670 | snd_component_add(card, chip->model.chip); |
655 | 671 | ||
@@ -733,7 +749,8 @@ int oxygen_pci_suspend(struct pci_dev *pci, pm_message_t state) | |||
733 | spin_unlock_irq(&chip->reg_lock); | 749 | spin_unlock_irq(&chip->reg_lock); |
734 | 750 | ||
735 | synchronize_irq(chip->irq); | 751 | synchronize_irq(chip->irq); |
736 | flush_scheduled_work(); | 752 | flush_work_sync(&chip->spdif_input_bits_work); |
753 | flush_work_sync(&chip->gpio_work); | ||
737 | chip->interrupt_mask = saved_interrupt_mask; | 754 | chip->interrupt_mask = saved_interrupt_mask; |
738 | 755 | ||
739 | pci_disable_device(pci); | 756 | pci_disable_device(pci); |
diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c index 2849b36f5f7e..9bff14d5895d 100644 --- a/sound/pci/oxygen/oxygen_mixer.c +++ b/sound/pci/oxygen/oxygen_mixer.c | |||
@@ -31,7 +31,7 @@ static int dac_volume_info(struct snd_kcontrol *ctl, | |||
31 | struct oxygen *chip = ctl->private_data; | 31 | struct oxygen *chip = ctl->private_data; |
32 | 32 | ||
33 | info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | 33 | info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
34 | info->count = chip->model.dac_channels; | 34 | info->count = chip->model.dac_channels_mixer; |
35 | info->value.integer.min = chip->model.dac_volume_min; | 35 | info->value.integer.min = chip->model.dac_volume_min; |
36 | info->value.integer.max = chip->model.dac_volume_max; | 36 | info->value.integer.max = chip->model.dac_volume_max; |
37 | return 0; | 37 | return 0; |
@@ -44,7 +44,7 @@ static int dac_volume_get(struct snd_kcontrol *ctl, | |||
44 | unsigned int i; | 44 | unsigned int i; |
45 | 45 | ||
46 | mutex_lock(&chip->mutex); | 46 | mutex_lock(&chip->mutex); |
47 | for (i = 0; i < chip->model.dac_channels; ++i) | 47 | for (i = 0; i < chip->model.dac_channels_mixer; ++i) |
48 | value->value.integer.value[i] = chip->dac_volume[i]; | 48 | value->value.integer.value[i] = chip->dac_volume[i]; |
49 | mutex_unlock(&chip->mutex); | 49 | mutex_unlock(&chip->mutex); |
50 | return 0; | 50 | return 0; |
@@ -59,7 +59,7 @@ static int dac_volume_put(struct snd_kcontrol *ctl, | |||
59 | 59 | ||
60 | changed = 0; | 60 | changed = 0; |
61 | mutex_lock(&chip->mutex); | 61 | mutex_lock(&chip->mutex); |
62 | for (i = 0; i < chip->model.dac_channels; ++i) | 62 | for (i = 0; i < chip->model.dac_channels_mixer; ++i) |
63 | if (value->value.integer.value[i] != chip->dac_volume[i]) { | 63 | if (value->value.integer.value[i] != chip->dac_volume[i]) { |
64 | chip->dac_volume[i] = value->value.integer.value[i]; | 64 | chip->dac_volume[i] = value->value.integer.value[i]; |
65 | changed = 1; | 65 | changed = 1; |
@@ -97,6 +97,16 @@ static int dac_mute_put(struct snd_kcontrol *ctl, | |||
97 | return changed; | 97 | return changed; |
98 | } | 98 | } |
99 | 99 | ||
100 | static unsigned int upmix_item_count(struct oxygen *chip) | ||
101 | { | ||
102 | if (chip->model.dac_channels_pcm < 8) | ||
103 | return 2; | ||
104 | else if (chip->model.update_center_lfe_mix) | ||
105 | return 5; | ||
106 | else | ||
107 | return 3; | ||
108 | } | ||
109 | |||
100 | static int upmix_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) | 110 | static int upmix_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) |
101 | { | 111 | { |
102 | static const char *const names[5] = { | 112 | static const char *const names[5] = { |
@@ -107,15 +117,9 @@ static int upmix_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) | |||
107 | "Front+Surround+Center/LFE+Back", | 117 | "Front+Surround+Center/LFE+Back", |
108 | }; | 118 | }; |
109 | struct oxygen *chip = ctl->private_data; | 119 | struct oxygen *chip = ctl->private_data; |
110 | unsigned int count = chip->model.update_center_lfe_mix ? 5 : 3; | 120 | unsigned int count = upmix_item_count(chip); |
111 | 121 | ||
112 | info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 122 | return snd_ctl_enum_info(info, 1, count, names); |
113 | info->count = 1; | ||
114 | info->value.enumerated.items = count; | ||
115 | if (info->value.enumerated.item >= count) | ||
116 | info->value.enumerated.item = count - 1; | ||
117 | strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); | ||
118 | return 0; | ||
119 | } | 123 | } |
120 | 124 | ||
121 | static int upmix_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) | 125 | 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) | |||
188 | static int upmix_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) | 192 | static int upmix_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) |
189 | { | 193 | { |
190 | struct oxygen *chip = ctl->private_data; | 194 | struct oxygen *chip = ctl->private_data; |
191 | unsigned int count = chip->model.update_center_lfe_mix ? 5 : 3; | 195 | unsigned int count = upmix_item_count(chip); |
192 | int changed; | 196 | int changed; |
193 | 197 | ||
194 | if (value->value.enumerated.item[0] >= count) | 198 | if (value->value.enumerated.item[0] >= count) |
@@ -430,30 +434,31 @@ static int spdif_input_default_get(struct snd_kcontrol *ctl, | |||
430 | return 0; | 434 | return 0; |
431 | } | 435 | } |
432 | 436 | ||
433 | static int spdif_loopback_get(struct snd_kcontrol *ctl, | 437 | static int spdif_bit_switch_get(struct snd_kcontrol *ctl, |
434 | struct snd_ctl_elem_value *value) | 438 | struct snd_ctl_elem_value *value) |
435 | { | 439 | { |
436 | struct oxygen *chip = ctl->private_data; | 440 | struct oxygen *chip = ctl->private_data; |
441 | u32 bit = ctl->private_value; | ||
437 | 442 | ||
438 | value->value.integer.value[0] = | 443 | value->value.integer.value[0] = |
439 | !!(oxygen_read32(chip, OXYGEN_SPDIF_CONTROL) | 444 | !!(oxygen_read32(chip, OXYGEN_SPDIF_CONTROL) & bit); |
440 | & OXYGEN_SPDIF_LOOPBACK); | ||
441 | return 0; | 445 | return 0; |
442 | } | 446 | } |
443 | 447 | ||
444 | static int spdif_loopback_put(struct snd_kcontrol *ctl, | 448 | static int spdif_bit_switch_put(struct snd_kcontrol *ctl, |
445 | struct snd_ctl_elem_value *value) | 449 | struct snd_ctl_elem_value *value) |
446 | { | 450 | { |
447 | struct oxygen *chip = ctl->private_data; | 451 | struct oxygen *chip = ctl->private_data; |
452 | u32 bit = ctl->private_value; | ||
448 | u32 oldreg, newreg; | 453 | u32 oldreg, newreg; |
449 | int changed; | 454 | int changed; |
450 | 455 | ||
451 | spin_lock_irq(&chip->reg_lock); | 456 | spin_lock_irq(&chip->reg_lock); |
452 | oldreg = oxygen_read32(chip, OXYGEN_SPDIF_CONTROL); | 457 | oldreg = oxygen_read32(chip, OXYGEN_SPDIF_CONTROL); |
453 | if (value->value.integer.value[0]) | 458 | if (value->value.integer.value[0]) |
454 | newreg = oldreg | OXYGEN_SPDIF_LOOPBACK; | 459 | newreg = oldreg | bit; |
455 | else | 460 | else |
456 | newreg = oldreg & ~OXYGEN_SPDIF_LOOPBACK; | 461 | newreg = oldreg & ~bit; |
457 | changed = newreg != oldreg; | 462 | changed = newreg != oldreg; |
458 | if (changed) | 463 | if (changed) |
459 | oxygen_write32(chip, OXYGEN_SPDIF_CONTROL, newreg); | 464 | oxygen_write32(chip, OXYGEN_SPDIF_CONTROL, newreg); |
@@ -644,6 +649,46 @@ static int ac97_volume_put(struct snd_kcontrol *ctl, | |||
644 | return change; | 649 | return change; |
645 | } | 650 | } |
646 | 651 | ||
652 | static int mic_fmic_source_info(struct snd_kcontrol *ctl, | ||
653 | struct snd_ctl_elem_info *info) | ||
654 | { | ||
655 | static const char *const names[] = { "Mic Jack", "Front Panel" }; | ||
656 | |||
657 | return snd_ctl_enum_info(info, 1, 2, names); | ||
658 | } | ||
659 | |||
660 | static int mic_fmic_source_get(struct snd_kcontrol *ctl, | ||
661 | struct snd_ctl_elem_value *value) | ||
662 | { | ||
663 | struct oxygen *chip = ctl->private_data; | ||
664 | |||
665 | mutex_lock(&chip->mutex); | ||
666 | value->value.enumerated.item[0] = | ||
667 | !!(oxygen_read_ac97(chip, 0, CM9780_JACK) & CM9780_FMIC2MIC); | ||
668 | mutex_unlock(&chip->mutex); | ||
669 | return 0; | ||
670 | } | ||
671 | |||
672 | static int mic_fmic_source_put(struct snd_kcontrol *ctl, | ||
673 | struct snd_ctl_elem_value *value) | ||
674 | { | ||
675 | struct oxygen *chip = ctl->private_data; | ||
676 | u16 oldreg, newreg; | ||
677 | int change; | ||
678 | |||
679 | mutex_lock(&chip->mutex); | ||
680 | oldreg = oxygen_read_ac97(chip, 0, CM9780_JACK); | ||
681 | if (value->value.enumerated.item[0]) | ||
682 | newreg = oldreg | CM9780_FMIC2MIC; | ||
683 | else | ||
684 | newreg = oldreg & ~CM9780_FMIC2MIC; | ||
685 | change = newreg != oldreg; | ||
686 | if (change) | ||
687 | oxygen_write_ac97(chip, 0, CM9780_JACK, newreg); | ||
688 | mutex_unlock(&chip->mutex); | ||
689 | return change; | ||
690 | } | ||
691 | |||
647 | static int ac97_fp_rec_volume_info(struct snd_kcontrol *ctl, | 692 | static int ac97_fp_rec_volume_info(struct snd_kcontrol *ctl, |
648 | struct snd_ctl_elem_info *info) | 693 | struct snd_ctl_elem_info *info) |
649 | { | 694 | { |
@@ -791,8 +836,17 @@ static const struct snd_kcontrol_new spdif_input_controls[] = { | |||
791 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 836 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
792 | .name = SNDRV_CTL_NAME_IEC958("Loopback ", NONE, SWITCH), | 837 | .name = SNDRV_CTL_NAME_IEC958("Loopback ", NONE, SWITCH), |
793 | .info = snd_ctl_boolean_mono_info, | 838 | .info = snd_ctl_boolean_mono_info, |
794 | .get = spdif_loopback_get, | 839 | .get = spdif_bit_switch_get, |
795 | .put = spdif_loopback_put, | 840 | .put = spdif_bit_switch_put, |
841 | .private_value = OXYGEN_SPDIF_LOOPBACK, | ||
842 | }, | ||
843 | { | ||
844 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
845 | .name = SNDRV_CTL_NAME_IEC958("Validity Check ",CAPTURE,SWITCH), | ||
846 | .info = snd_ctl_boolean_mono_info, | ||
847 | .get = spdif_bit_switch_get, | ||
848 | .put = spdif_bit_switch_put, | ||
849 | .private_value = OXYGEN_SPDIF_SPDVALID, | ||
796 | }, | 850 | }, |
797 | }; | 851 | }; |
798 | 852 | ||
@@ -908,6 +962,13 @@ static const struct snd_kcontrol_new ac97_controls[] = { | |||
908 | AC97_VOLUME("Mic Capture Volume", 0, AC97_MIC, 0), | 962 | AC97_VOLUME("Mic Capture Volume", 0, AC97_MIC, 0), |
909 | AC97_SWITCH("Mic Capture Switch", 0, AC97_MIC, 15, 1), | 963 | AC97_SWITCH("Mic Capture Switch", 0, AC97_MIC, 15, 1), |
910 | AC97_SWITCH("Mic Boost (+20dB)", 0, AC97_MIC, 6, 0), | 964 | AC97_SWITCH("Mic Boost (+20dB)", 0, AC97_MIC, 6, 0), |
965 | { | ||
966 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
967 | .name = "Mic Source Capture Enum", | ||
968 | .info = mic_fmic_source_info, | ||
969 | .get = mic_fmic_source_get, | ||
970 | .put = mic_fmic_source_put, | ||
971 | }, | ||
911 | AC97_SWITCH("Line Capture Switch", 0, AC97_LINE, 15, 1), | 972 | AC97_SWITCH("Line Capture Switch", 0, AC97_LINE, 15, 1), |
912 | AC97_VOLUME("CD Capture Volume", 0, AC97_CD, 1), | 973 | AC97_VOLUME("CD Capture Volume", 0, AC97_CD, 1), |
913 | AC97_SWITCH("CD Capture Switch", 0, AC97_CD, 15, 1), | 974 | AC97_SWITCH("CD Capture Switch", 0, AC97_CD, 15, 1), |
@@ -970,7 +1031,10 @@ static int add_controls(struct oxygen *chip, | |||
970 | continue; | 1031 | continue; |
971 | } | 1032 | } |
972 | if (!strcmp(template.name, "Stereo Upmixing") && | 1033 | if (!strcmp(template.name, "Stereo Upmixing") && |
973 | chip->model.dac_channels == 2) | 1034 | chip->model.dac_channels_pcm == 2) |
1035 | continue; | ||
1036 | if (!strcmp(template.name, "Mic Source Capture Enum") && | ||
1037 | !(chip->model.device_config & AC97_FMIC_SWITCH)) | ||
974 | continue; | 1038 | continue; |
975 | if (!strncmp(template.name, "CD Capture ", 11) && | 1039 | if (!strncmp(template.name, "CD Capture ", 11) && |
976 | !(chip->model.device_config & AC97_CD_INPUT)) | 1040 | !(chip->model.device_config & AC97_CD_INPUT)) |
diff --git a/sound/pci/oxygen/oxygen_pcm.c b/sound/pci/oxygen/oxygen_pcm.c index 814667442eb0..d5533e34ece9 100644 --- a/sound/pci/oxygen/oxygen_pcm.c +++ b/sound/pci/oxygen/oxygen_pcm.c | |||
@@ -39,7 +39,8 @@ static const struct snd_pcm_hardware oxygen_stereo_hardware = { | |||
39 | SNDRV_PCM_INFO_MMAP_VALID | | 39 | SNDRV_PCM_INFO_MMAP_VALID | |
40 | SNDRV_PCM_INFO_INTERLEAVED | | 40 | SNDRV_PCM_INFO_INTERLEAVED | |
41 | SNDRV_PCM_INFO_PAUSE | | 41 | SNDRV_PCM_INFO_PAUSE | |
42 | SNDRV_PCM_INFO_SYNC_START, | 42 | SNDRV_PCM_INFO_SYNC_START | |
43 | SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, | ||
43 | .formats = SNDRV_PCM_FMTBIT_S16_LE | | 44 | .formats = SNDRV_PCM_FMTBIT_S16_LE | |
44 | SNDRV_PCM_FMTBIT_S32_LE, | 45 | SNDRV_PCM_FMTBIT_S32_LE, |
45 | .rates = SNDRV_PCM_RATE_32000 | | 46 | .rates = SNDRV_PCM_RATE_32000 | |
@@ -65,7 +66,8 @@ static const struct snd_pcm_hardware oxygen_multichannel_hardware = { | |||
65 | SNDRV_PCM_INFO_MMAP_VALID | | 66 | SNDRV_PCM_INFO_MMAP_VALID | |
66 | SNDRV_PCM_INFO_INTERLEAVED | | 67 | SNDRV_PCM_INFO_INTERLEAVED | |
67 | SNDRV_PCM_INFO_PAUSE | | 68 | SNDRV_PCM_INFO_PAUSE | |
68 | SNDRV_PCM_INFO_SYNC_START, | 69 | SNDRV_PCM_INFO_SYNC_START | |
70 | SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, | ||
69 | .formats = SNDRV_PCM_FMTBIT_S16_LE | | 71 | .formats = SNDRV_PCM_FMTBIT_S16_LE | |
70 | SNDRV_PCM_FMTBIT_S32_LE, | 72 | SNDRV_PCM_FMTBIT_S32_LE, |
71 | .rates = SNDRV_PCM_RATE_32000 | | 73 | .rates = SNDRV_PCM_RATE_32000 | |
@@ -91,7 +93,8 @@ static const struct snd_pcm_hardware oxygen_ac97_hardware = { | |||
91 | SNDRV_PCM_INFO_MMAP_VALID | | 93 | SNDRV_PCM_INFO_MMAP_VALID | |
92 | SNDRV_PCM_INFO_INTERLEAVED | | 94 | SNDRV_PCM_INFO_INTERLEAVED | |
93 | SNDRV_PCM_INFO_PAUSE | | 95 | SNDRV_PCM_INFO_PAUSE | |
94 | SNDRV_PCM_INFO_SYNC_START, | 96 | SNDRV_PCM_INFO_SYNC_START | |
97 | SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, | ||
95 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | 98 | .formats = SNDRV_PCM_FMTBIT_S16_LE, |
96 | .rates = SNDRV_PCM_RATE_48000, | 99 | .rates = SNDRV_PCM_RATE_48000, |
97 | .rate_min = 48000, | 100 | .rate_min = 48000, |
@@ -140,7 +143,7 @@ static int oxygen_open(struct snd_pcm_substream *substream, | |||
140 | runtime->hw.rate_min = 44100; | 143 | runtime->hw.rate_min = 44100; |
141 | break; | 144 | break; |
142 | case PCM_MULTICH: | 145 | case PCM_MULTICH: |
143 | runtime->hw.channels_max = chip->model.dac_channels; | 146 | runtime->hw.channels_max = chip->model.dac_channels_pcm; |
144 | break; | 147 | break; |
145 | } | 148 | } |
146 | if (chip->model.pcm_hardware_filter) | 149 | if (chip->model.pcm_hardware_filter) |
@@ -271,17 +274,6 @@ static unsigned int oxygen_rate(struct snd_pcm_hw_params *hw_params) | |||
271 | } | 274 | } |
272 | } | 275 | } |
273 | 276 | ||
274 | unsigned int oxygen_default_i2s_mclk(struct oxygen *chip, | ||
275 | unsigned int channel, | ||
276 | struct snd_pcm_hw_params *hw_params) | ||
277 | { | ||
278 | if (params_rate(hw_params) <= 96000) | ||
279 | return OXYGEN_I2S_MCLK_256; | ||
280 | else | ||
281 | return OXYGEN_I2S_MCLK_128; | ||
282 | } | ||
283 | EXPORT_SYMBOL(oxygen_default_i2s_mclk); | ||
284 | |||
285 | static unsigned int oxygen_i2s_bits(struct snd_pcm_hw_params *hw_params) | 277 | static unsigned int oxygen_i2s_bits(struct snd_pcm_hw_params *hw_params) |
286 | { | 278 | { |
287 | if (params_format(hw_params) == SNDRV_PCM_FORMAT_S32_LE) | 279 | if (params_format(hw_params) == SNDRV_PCM_FORMAT_S32_LE) |
@@ -341,6 +333,26 @@ static int oxygen_hw_params(struct snd_pcm_substream *substream, | |||
341 | return 0; | 333 | return 0; |
342 | } | 334 | } |
343 | 335 | ||
336 | static u16 get_mclk(struct oxygen *chip, unsigned int channel, | ||
337 | struct snd_pcm_hw_params *params) | ||
338 | { | ||
339 | unsigned int mclks, shift; | ||
340 | |||
341 | if (channel == PCM_MULTICH) | ||
342 | mclks = chip->model.dac_mclks; | ||
343 | else | ||
344 | mclks = chip->model.adc_mclks; | ||
345 | |||
346 | if (params_rate(params) <= 48000) | ||
347 | shift = 0; | ||
348 | else if (params_rate(params) <= 96000) | ||
349 | shift = 2; | ||
350 | else | ||
351 | shift = 4; | ||
352 | |||
353 | return OXYGEN_I2S_MCLK(mclks >> shift); | ||
354 | } | ||
355 | |||
344 | static int oxygen_rec_a_hw_params(struct snd_pcm_substream *substream, | 356 | static int oxygen_rec_a_hw_params(struct snd_pcm_substream *substream, |
345 | struct snd_pcm_hw_params *hw_params) | 357 | struct snd_pcm_hw_params *hw_params) |
346 | { | 358 | { |
@@ -357,8 +369,8 @@ static int oxygen_rec_a_hw_params(struct snd_pcm_substream *substream, | |||
357 | OXYGEN_REC_FORMAT_A_MASK); | 369 | OXYGEN_REC_FORMAT_A_MASK); |
358 | oxygen_write16_masked(chip, OXYGEN_I2S_A_FORMAT, | 370 | oxygen_write16_masked(chip, OXYGEN_I2S_A_FORMAT, |
359 | oxygen_rate(hw_params) | | 371 | oxygen_rate(hw_params) | |
360 | chip->model.get_i2s_mclk(chip, PCM_A, hw_params) | | ||
361 | chip->model.adc_i2s_format | | 372 | chip->model.adc_i2s_format | |
373 | get_mclk(chip, PCM_A, hw_params) | | ||
362 | oxygen_i2s_bits(hw_params), | 374 | oxygen_i2s_bits(hw_params), |
363 | OXYGEN_I2S_RATE_MASK | | 375 | OXYGEN_I2S_RATE_MASK | |
364 | OXYGEN_I2S_FORMAT_MASK | | 376 | OXYGEN_I2S_FORMAT_MASK | |
@@ -393,9 +405,8 @@ static int oxygen_rec_b_hw_params(struct snd_pcm_substream *substream, | |||
393 | if (!is_ac97) | 405 | if (!is_ac97) |
394 | oxygen_write16_masked(chip, OXYGEN_I2S_B_FORMAT, | 406 | oxygen_write16_masked(chip, OXYGEN_I2S_B_FORMAT, |
395 | oxygen_rate(hw_params) | | 407 | oxygen_rate(hw_params) | |
396 | chip->model.get_i2s_mclk(chip, PCM_B, | ||
397 | hw_params) | | ||
398 | chip->model.adc_i2s_format | | 408 | chip->model.adc_i2s_format | |
409 | get_mclk(chip, PCM_B, hw_params) | | ||
399 | oxygen_i2s_bits(hw_params), | 410 | oxygen_i2s_bits(hw_params), |
400 | OXYGEN_I2S_RATE_MASK | | 411 | OXYGEN_I2S_RATE_MASK | |
401 | OXYGEN_I2S_FORMAT_MASK | | 412 | OXYGEN_I2S_FORMAT_MASK | |
@@ -476,8 +487,7 @@ static int oxygen_multich_hw_params(struct snd_pcm_substream *substream, | |||
476 | oxygen_write16_masked(chip, OXYGEN_I2S_MULTICH_FORMAT, | 487 | oxygen_write16_masked(chip, OXYGEN_I2S_MULTICH_FORMAT, |
477 | oxygen_rate(hw_params) | | 488 | oxygen_rate(hw_params) | |
478 | chip->model.dac_i2s_format | | 489 | chip->model.dac_i2s_format | |
479 | chip->model.get_i2s_mclk(chip, PCM_MULTICH, | 490 | get_mclk(chip, PCM_MULTICH, hw_params) | |
480 | hw_params) | | ||
481 | oxygen_i2s_bits(hw_params), | 491 | oxygen_i2s_bits(hw_params), |
482 | OXYGEN_I2S_RATE_MASK | | 492 | OXYGEN_I2S_RATE_MASK | |
483 | OXYGEN_I2S_FORMAT_MASK | | 493 | OXYGEN_I2S_FORMAT_MASK | |
@@ -530,7 +540,10 @@ static int oxygen_prepare(struct snd_pcm_substream *substream) | |||
530 | oxygen_set_bits8(chip, OXYGEN_DMA_FLUSH, channel_mask); | 540 | oxygen_set_bits8(chip, OXYGEN_DMA_FLUSH, channel_mask); |
531 | oxygen_clear_bits8(chip, OXYGEN_DMA_FLUSH, channel_mask); | 541 | oxygen_clear_bits8(chip, OXYGEN_DMA_FLUSH, channel_mask); |
532 | 542 | ||
533 | chip->interrupt_mask |= channel_mask; | 543 | if (substream->runtime->no_period_wakeup) |
544 | chip->interrupt_mask &= ~channel_mask; | ||
545 | else | ||
546 | chip->interrupt_mask |= channel_mask; | ||
534 | oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, chip->interrupt_mask); | 547 | oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, chip->interrupt_mask); |
535 | spin_unlock_irq(&chip->reg_lock); | 548 | spin_unlock_irq(&chip->reg_lock); |
536 | return 0; | 549 | return 0; |
diff --git a/sound/pci/oxygen/oxygen_regs.h b/sound/pci/oxygen/oxygen_regs.h index 4dcd41b78258..63dc7a0ab555 100644 --- a/sound/pci/oxygen/oxygen_regs.h +++ b/sound/pci/oxygen/oxygen_regs.h | |||
@@ -139,9 +139,11 @@ | |||
139 | #define OXYGEN_I2S_FORMAT_I2S 0x0000 | 139 | #define OXYGEN_I2S_FORMAT_I2S 0x0000 |
140 | #define OXYGEN_I2S_FORMAT_LJUST 0x0008 | 140 | #define OXYGEN_I2S_FORMAT_LJUST 0x0008 |
141 | #define OXYGEN_I2S_MCLK_MASK 0x0030 /* MCLK/LRCK */ | 141 | #define OXYGEN_I2S_MCLK_MASK 0x0030 /* MCLK/LRCK */ |
142 | #define OXYGEN_I2S_MCLK_128 0x0000 | 142 | #define OXYGEN_I2S_MCLK_SHIFT 4 |
143 | #define OXYGEN_I2S_MCLK_256 0x0010 | 143 | #define MCLK_128 0 |
144 | #define OXYGEN_I2S_MCLK_512 0x0020 | 144 | #define MCLK_256 1 |
145 | #define MCLK_512 2 | ||
146 | #define OXYGEN_I2S_MCLK(f) (((f) & 3) << OXYGEN_I2S_MCLK_SHIFT) | ||
145 | #define OXYGEN_I2S_BITS_MASK 0x00c0 | 147 | #define OXYGEN_I2S_BITS_MASK 0x00c0 |
146 | #define OXYGEN_I2S_BITS_16 0x0000 | 148 | #define OXYGEN_I2S_BITS_16 0x0000 |
147 | #define OXYGEN_I2S_BITS_20 0x0040 | 149 | #define OXYGEN_I2S_BITS_20 0x0040 |
@@ -238,11 +240,11 @@ | |||
238 | #define OXYGEN_SPI_DATA_LENGTH_MASK 0x02 | 240 | #define OXYGEN_SPI_DATA_LENGTH_MASK 0x02 |
239 | #define OXYGEN_SPI_DATA_LENGTH_2 0x00 | 241 | #define OXYGEN_SPI_DATA_LENGTH_2 0x00 |
240 | #define OXYGEN_SPI_DATA_LENGTH_3 0x02 | 242 | #define OXYGEN_SPI_DATA_LENGTH_3 0x02 |
241 | #define OXYGEN_SPI_CLOCK_MASK 0xc0 | 243 | #define OXYGEN_SPI_CLOCK_MASK 0x0c |
242 | #define OXYGEN_SPI_CLOCK_160 0x00 /* ns */ | 244 | #define OXYGEN_SPI_CLOCK_160 0x00 /* ns */ |
243 | #define OXYGEN_SPI_CLOCK_320 0x40 | 245 | #define OXYGEN_SPI_CLOCK_320 0x04 |
244 | #define OXYGEN_SPI_CLOCK_640 0x80 | 246 | #define OXYGEN_SPI_CLOCK_640 0x08 |
245 | #define OXYGEN_SPI_CLOCK_1280 0xc0 | 247 | #define OXYGEN_SPI_CLOCK_1280 0x0c |
246 | #define OXYGEN_SPI_CODEC_MASK 0x70 /* 0..5 */ | 248 | #define OXYGEN_SPI_CODEC_MASK 0x70 /* 0..5 */ |
247 | #define OXYGEN_SPI_CODEC_SHIFT 4 | 249 | #define OXYGEN_SPI_CODEC_SHIFT 4 |
248 | #define OXYGEN_SPI_CEN_MASK 0x80 | 250 | #define OXYGEN_SPI_CEN_MASK 0x80 |
diff --git a/sound/pci/oxygen/xonar.h b/sound/pci/oxygen/xonar.h index b35343b0a9a5..0434c207e811 100644 --- a/sound/pci/oxygen/xonar.h +++ b/sound/pci/oxygen/xonar.h | |||
@@ -24,6 +24,8 @@ void xonar_init_ext_power(struct oxygen *chip); | |||
24 | void xonar_init_cs53x1(struct oxygen *chip); | 24 | void xonar_init_cs53x1(struct oxygen *chip); |
25 | void xonar_set_cs53x1_params(struct oxygen *chip, | 25 | void xonar_set_cs53x1_params(struct oxygen *chip, |
26 | struct snd_pcm_hw_params *params); | 26 | struct snd_pcm_hw_params *params); |
27 | |||
28 | #define XONAR_GPIO_BIT_INVERT (1 << 16) | ||
27 | int xonar_gpio_bit_switch_get(struct snd_kcontrol *ctl, | 29 | int xonar_gpio_bit_switch_get(struct snd_kcontrol *ctl, |
28 | struct snd_ctl_elem_value *value); | 30 | struct snd_ctl_elem_value *value); |
29 | int xonar_gpio_bit_switch_put(struct snd_kcontrol *ctl, | 31 | int xonar_gpio_bit_switch_put(struct snd_kcontrol *ctl, |
diff --git a/sound/pci/oxygen/xonar_cs43xx.c b/sound/pci/oxygen/xonar_cs43xx.c index aa27c31049af..9f72d424969c 100644 --- a/sound/pci/oxygen/xonar_cs43xx.c +++ b/sound/pci/oxygen/xonar_cs43xx.c | |||
@@ -22,29 +22,28 @@ | |||
22 | * | 22 | * |
23 | * CMI8788: | 23 | * CMI8788: |
24 | * | 24 | * |
25 | * I²C <-> CS4398 (front) | 25 | * I²C <-> CS4398 (addr 1001111) (front) |
26 | * <-> CS4362A (surround, center/LFE, back) | 26 | * <-> CS4362A (addr 0011000) (surround, center/LFE, back) |
27 | * | 27 | * |
28 | * GPI 0 <- external power present (DX only) | 28 | * GPI 0 <- external power present (DX only) |
29 | * | 29 | * |
30 | * GPIO 0 -> enable output to speakers | 30 | * GPIO 0 -> enable output to speakers |
31 | * GPIO 1 -> enable front panel I/O | 31 | * GPIO 1 -> route output to front panel |
32 | * GPIO 2 -> M0 of CS5361 | 32 | * GPIO 2 -> M0 of CS5361 |
33 | * GPIO 3 -> M1 of CS5361 | 33 | * GPIO 3 -> M1 of CS5361 |
34 | * GPIO 8 -> route input jack to line-in (0) or mic-in (1) | 34 | * GPIO 6 -> ? |
35 | * GPIO 7 -> ? | ||
36 | * GPIO 8 -> route input jack to line-in (0) or mic-in (1) | ||
35 | * | 37 | * |
36 | * CS4398: | 38 | * CM9780: |
37 | * | ||
38 | * AD0 <- 1 | ||
39 | * AD1 <- 1 | ||
40 | * | 39 | * |
41 | * CS4362A: | 40 | * LINE_OUT -> input of ADC |
42 | * | 41 | * |
43 | * AD0 <- 0 | 42 | * AUX_IN <- aux |
43 | * MIC_IN <- mic | ||
44 | * FMIC_IN <- front mic | ||
44 | * | 45 | * |
45 | * CM9780: | 46 | * GPO 0 -> route line-in (0) or AC97 output (1) to CS5361 input |
46 | * | ||
47 | * GPO 0 -> route line-in (0) or AC97 output (1) to CS5361 input | ||
48 | */ | 47 | */ |
49 | 48 | ||
50 | #include <linux/pci.h> | 49 | #include <linux/pci.h> |
@@ -63,6 +62,7 @@ | |||
63 | #define GPI_EXT_POWER 0x01 | 62 | #define GPI_EXT_POWER 0x01 |
64 | #define GPIO_D1_OUTPUT_ENABLE 0x0001 | 63 | #define GPIO_D1_OUTPUT_ENABLE 0x0001 |
65 | #define GPIO_D1_FRONT_PANEL 0x0002 | 64 | #define GPIO_D1_FRONT_PANEL 0x0002 |
65 | #define GPIO_D1_MAGIC 0x00c0 | ||
66 | #define GPIO_D1_INPUT_ROUTE 0x0100 | 66 | #define GPIO_D1_INPUT_ROUTE 0x0100 |
67 | 67 | ||
68 | #define I2C_DEVICE_CS4398 0x9e /* 10011, AD1=1, AD0=1, /W=0 */ | 68 | #define I2C_DEVICE_CS4398 0x9e /* 10011, AD1=1, AD0=1, /W=0 */ |
@@ -169,12 +169,12 @@ static void xonar_d1_init(struct oxygen *chip) | |||
169 | cs43xx_registers_init(chip); | 169 | cs43xx_registers_init(chip); |
170 | 170 | ||
171 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, | 171 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, |
172 | GPIO_D1_FRONT_PANEL | GPIO_D1_INPUT_ROUTE); | 172 | GPIO_D1_FRONT_PANEL | |
173 | GPIO_D1_MAGIC | | ||
174 | GPIO_D1_INPUT_ROUTE); | ||
173 | oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, | 175 | oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, |
174 | GPIO_D1_FRONT_PANEL | GPIO_D1_INPUT_ROUTE); | 176 | GPIO_D1_FRONT_PANEL | GPIO_D1_INPUT_ROUTE); |
175 | 177 | ||
176 | oxygen_ac97_set_bits(chip, 0, CM9780_JACK, CM9780_FMIC2MIC); | ||
177 | |||
178 | xonar_init_cs53x1(chip); | 178 | xonar_init_cs53x1(chip); |
179 | xonar_enable_output(chip); | 179 | xonar_enable_output(chip); |
180 | 180 | ||
@@ -284,7 +284,7 @@ static void update_cs43xx_center_lfe_mix(struct oxygen *chip, bool mixed) | |||
284 | 284 | ||
285 | static const struct snd_kcontrol_new front_panel_switch = { | 285 | static const struct snd_kcontrol_new front_panel_switch = { |
286 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 286 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
287 | .name = "Front Panel Switch", | 287 | .name = "Front Panel Playback Switch", |
288 | .info = snd_ctl_boolean_mono_info, | 288 | .info = snd_ctl_boolean_mono_info, |
289 | .get = xonar_gpio_bit_switch_get, | 289 | .get = xonar_gpio_bit_switch_get, |
290 | .put = xonar_gpio_bit_switch_put, | 290 | .put = xonar_gpio_bit_switch_put, |
@@ -298,13 +298,7 @@ static int rolloff_info(struct snd_kcontrol *ctl, | |||
298 | "Fast Roll-off", "Slow Roll-off" | 298 | "Fast Roll-off", "Slow Roll-off" |
299 | }; | 299 | }; |
300 | 300 | ||
301 | info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 301 | return snd_ctl_enum_info(info, 1, 2, names); |
302 | info->count = 1; | ||
303 | info->value.enumerated.items = 2; | ||
304 | if (info->value.enumerated.item >= 2) | ||
305 | info->value.enumerated.item = 1; | ||
306 | strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); | ||
307 | return 0; | ||
308 | } | 302 | } |
309 | 303 | ||
310 | static int rolloff_get(struct snd_kcontrol *ctl, | 304 | static int rolloff_get(struct snd_kcontrol *ctl, |
@@ -380,6 +374,30 @@ static int xonar_d1_mixer_init(struct oxygen *chip) | |||
380 | return 0; | 374 | return 0; |
381 | } | 375 | } |
382 | 376 | ||
377 | static void dump_cs4362a_registers(struct xonar_cs43xx *data, | ||
378 | struct snd_info_buffer *buffer) | ||
379 | { | ||
380 | unsigned int i; | ||
381 | |||
382 | snd_iprintf(buffer, "\nCS4362A:"); | ||
383 | for (i = 1; i <= 14; ++i) | ||
384 | snd_iprintf(buffer, " %02x", data->cs4362a_regs[i]); | ||
385 | snd_iprintf(buffer, "\n"); | ||
386 | } | ||
387 | |||
388 | static void dump_d1_registers(struct oxygen *chip, | ||
389 | struct snd_info_buffer *buffer) | ||
390 | { | ||
391 | struct xonar_cs43xx *data = chip->model_data; | ||
392 | unsigned int i; | ||
393 | |||
394 | snd_iprintf(buffer, "\nCS4398: 7?"); | ||
395 | for (i = 2; i <= 8; ++i) | ||
396 | snd_iprintf(buffer, " %02x", data->cs4398_regs[i]); | ||
397 | snd_iprintf(buffer, "\n"); | ||
398 | dump_cs4362a_registers(data, buffer); | ||
399 | } | ||
400 | |||
383 | static const struct oxygen_model model_xonar_d1 = { | 401 | static const struct oxygen_model model_xonar_d1 = { |
384 | .longname = "Asus Virtuoso 100", | 402 | .longname = "Asus Virtuoso 100", |
385 | .chip = "AV200", | 403 | .chip = "AV200", |
@@ -388,22 +406,26 @@ static const struct oxygen_model model_xonar_d1 = { | |||
388 | .cleanup = xonar_d1_cleanup, | 406 | .cleanup = xonar_d1_cleanup, |
389 | .suspend = xonar_d1_suspend, | 407 | .suspend = xonar_d1_suspend, |
390 | .resume = xonar_d1_resume, | 408 | .resume = xonar_d1_resume, |
391 | .get_i2s_mclk = oxygen_default_i2s_mclk, | ||
392 | .set_dac_params = set_cs43xx_params, | 409 | .set_dac_params = set_cs43xx_params, |
393 | .set_adc_params = xonar_set_cs53x1_params, | 410 | .set_adc_params = xonar_set_cs53x1_params, |
394 | .update_dac_volume = update_cs43xx_volume, | 411 | .update_dac_volume = update_cs43xx_volume, |
395 | .update_dac_mute = update_cs43xx_mute, | 412 | .update_dac_mute = update_cs43xx_mute, |
396 | .update_center_lfe_mix = update_cs43xx_center_lfe_mix, | 413 | .update_center_lfe_mix = update_cs43xx_center_lfe_mix, |
397 | .ac97_switch = xonar_d1_line_mic_ac97_switch, | 414 | .ac97_switch = xonar_d1_line_mic_ac97_switch, |
415 | .dump_registers = dump_d1_registers, | ||
398 | .dac_tlv = cs4362a_db_scale, | 416 | .dac_tlv = cs4362a_db_scale, |
399 | .model_data_size = sizeof(struct xonar_cs43xx), | 417 | .model_data_size = sizeof(struct xonar_cs43xx), |
400 | .device_config = PLAYBACK_0_TO_I2S | | 418 | .device_config = PLAYBACK_0_TO_I2S | |
401 | PLAYBACK_1_TO_SPDIF | | 419 | PLAYBACK_1_TO_SPDIF | |
402 | CAPTURE_0_FROM_I2S_2, | 420 | CAPTURE_0_FROM_I2S_2 | |
403 | .dac_channels = 8, | 421 | AC97_FMIC_SWITCH, |
422 | .dac_channels_pcm = 8, | ||
423 | .dac_channels_mixer = 8, | ||
404 | .dac_volume_min = 127 - 60, | 424 | .dac_volume_min = 127 - 60, |
405 | .dac_volume_max = 127, | 425 | .dac_volume_max = 127, |
406 | .function_flags = OXYGEN_FUNCTION_2WIRE, | 426 | .function_flags = OXYGEN_FUNCTION_2WIRE, |
427 | .dac_mclks = OXYGEN_MCLKS(256, 128, 128), | ||
428 | .adc_mclks = OXYGEN_MCLKS(256, 128, 128), | ||
407 | .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | 429 | .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, |
408 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | 430 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, |
409 | }; | 431 | }; |
diff --git a/sound/pci/oxygen/xonar_dg.c b/sound/pci/oxygen/xonar_dg.c new file mode 100644 index 000000000000..e4de0b8d087a --- /dev/null +++ b/sound/pci/oxygen/xonar_dg.c | |||
@@ -0,0 +1,572 @@ | |||
1 | /* | ||
2 | * card driver for the Xonar DG | ||
3 | * | ||
4 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> | ||
5 | * | ||
6 | * | ||
7 | * This driver is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License, version 2. | ||
9 | * | ||
10 | * This driver is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this driver; if not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | |||
19 | /* | ||
20 | * Xonar DG | ||
21 | * -------- | ||
22 | * | ||
23 | * CMI8788: | ||
24 | * | ||
25 | * SPI 0 -> CS4245 | ||
26 | * | ||
27 | * GPIO 3 <- ? | ||
28 | * GPIO 4 <- headphone detect | ||
29 | * GPIO 5 -> route input jack to line-in (0) or mic-in (1) | ||
30 | * GPIO 6 -> route input jack to line-in (0) or mic-in (1) | ||
31 | * GPIO 7 -> enable rear headphone amp | ||
32 | * GPIO 8 -> enable output to speakers | ||
33 | * | ||
34 | * CS4245: | ||
35 | * | ||
36 | * input 1 <- aux | ||
37 | * input 2 <- front mic | ||
38 | * input 4 <- line/mic | ||
39 | * aux out -> front panel headphones | ||
40 | */ | ||
41 | |||
42 | #include <linux/pci.h> | ||
43 | #include <linux/delay.h> | ||
44 | #include <sound/control.h> | ||
45 | #include <sound/core.h> | ||
46 | #include <sound/info.h> | ||
47 | #include <sound/pcm.h> | ||
48 | #include <sound/tlv.h> | ||
49 | #include "oxygen.h" | ||
50 | #include "xonar_dg.h" | ||
51 | #include "cs4245.h" | ||
52 | |||
53 | #define GPIO_MAGIC 0x0008 | ||
54 | #define GPIO_HP_DETECT 0x0010 | ||
55 | #define GPIO_INPUT_ROUTE 0x0060 | ||
56 | #define GPIO_HP_REAR 0x0080 | ||
57 | #define GPIO_OUTPUT_ENABLE 0x0100 | ||
58 | |||
59 | struct dg { | ||
60 | unsigned int output_sel; | ||
61 | s8 input_vol[4][2]; | ||
62 | unsigned int input_sel; | ||
63 | u8 hp_vol_att; | ||
64 | u8 cs4245_regs[0x11]; | ||
65 | }; | ||
66 | |||
67 | static void cs4245_write(struct oxygen *chip, unsigned int reg, u8 value) | ||
68 | { | ||
69 | struct dg *data = chip->model_data; | ||
70 | |||
71 | oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER | | ||
72 | OXYGEN_SPI_DATA_LENGTH_3 | | ||
73 | OXYGEN_SPI_CLOCK_1280 | | ||
74 | (0 << OXYGEN_SPI_CODEC_SHIFT) | | ||
75 | OXYGEN_SPI_CEN_LATCH_CLOCK_HI, | ||
76 | CS4245_SPI_ADDRESS | | ||
77 | CS4245_SPI_WRITE | | ||
78 | (value << 8) | reg); | ||
79 | data->cs4245_regs[reg] = value; | ||
80 | } | ||
81 | |||
82 | static void cs4245_write_cached(struct oxygen *chip, unsigned int reg, u8 value) | ||
83 | { | ||
84 | struct dg *data = chip->model_data; | ||
85 | |||
86 | if (value != data->cs4245_regs[reg]) | ||
87 | cs4245_write(chip, reg, value); | ||
88 | } | ||
89 | |||
90 | static void cs4245_registers_init(struct oxygen *chip) | ||
91 | { | ||
92 | struct dg *data = chip->model_data; | ||
93 | |||
94 | cs4245_write(chip, CS4245_POWER_CTRL, CS4245_PDN); | ||
95 | cs4245_write(chip, CS4245_DAC_CTRL_1, | ||
96 | data->cs4245_regs[CS4245_DAC_CTRL_1]); | ||
97 | cs4245_write(chip, CS4245_ADC_CTRL, | ||
98 | data->cs4245_regs[CS4245_ADC_CTRL]); | ||
99 | cs4245_write(chip, CS4245_SIGNAL_SEL, | ||
100 | data->cs4245_regs[CS4245_SIGNAL_SEL]); | ||
101 | cs4245_write(chip, CS4245_PGA_B_CTRL, | ||
102 | data->cs4245_regs[CS4245_PGA_B_CTRL]); | ||
103 | cs4245_write(chip, CS4245_PGA_A_CTRL, | ||
104 | data->cs4245_regs[CS4245_PGA_A_CTRL]); | ||
105 | cs4245_write(chip, CS4245_ANALOG_IN, | ||
106 | data->cs4245_regs[CS4245_ANALOG_IN]); | ||
107 | cs4245_write(chip, CS4245_DAC_A_CTRL, | ||
108 | data->cs4245_regs[CS4245_DAC_A_CTRL]); | ||
109 | cs4245_write(chip, CS4245_DAC_B_CTRL, | ||
110 | data->cs4245_regs[CS4245_DAC_B_CTRL]); | ||
111 | cs4245_write(chip, CS4245_DAC_CTRL_2, | ||
112 | CS4245_DAC_SOFT | CS4245_DAC_ZERO | CS4245_INVERT_DAC); | ||
113 | cs4245_write(chip, CS4245_INT_MASK, 0); | ||
114 | cs4245_write(chip, CS4245_POWER_CTRL, 0); | ||
115 | } | ||
116 | |||
117 | static void cs4245_init(struct oxygen *chip) | ||
118 | { | ||
119 | struct dg *data = chip->model_data; | ||
120 | |||
121 | data->cs4245_regs[CS4245_DAC_CTRL_1] = | ||
122 | CS4245_DAC_FM_SINGLE | CS4245_DAC_DIF_LJUST; | ||
123 | data->cs4245_regs[CS4245_ADC_CTRL] = | ||
124 | CS4245_ADC_FM_SINGLE | CS4245_ADC_DIF_LJUST; | ||
125 | data->cs4245_regs[CS4245_SIGNAL_SEL] = | ||
126 | CS4245_A_OUT_SEL_HIZ | CS4245_ASYNCH; | ||
127 | data->cs4245_regs[CS4245_PGA_B_CTRL] = 0; | ||
128 | data->cs4245_regs[CS4245_PGA_A_CTRL] = 0; | ||
129 | data->cs4245_regs[CS4245_ANALOG_IN] = | ||
130 | CS4245_PGA_SOFT | CS4245_PGA_ZERO | CS4245_SEL_INPUT_4; | ||
131 | data->cs4245_regs[CS4245_DAC_A_CTRL] = 0; | ||
132 | data->cs4245_regs[CS4245_DAC_B_CTRL] = 0; | ||
133 | cs4245_registers_init(chip); | ||
134 | snd_component_add(chip->card, "CS4245"); | ||
135 | } | ||
136 | |||
137 | static void dg_output_enable(struct oxygen *chip) | ||
138 | { | ||
139 | msleep(2500); | ||
140 | oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE); | ||
141 | } | ||
142 | |||
143 | static void dg_init(struct oxygen *chip) | ||
144 | { | ||
145 | struct dg *data = chip->model_data; | ||
146 | |||
147 | data->output_sel = 0; | ||
148 | data->input_sel = 3; | ||
149 | data->hp_vol_att = 2 * 16; | ||
150 | |||
151 | cs4245_init(chip); | ||
152 | |||
153 | oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, | ||
154 | GPIO_MAGIC | GPIO_HP_DETECT); | ||
155 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, | ||
156 | GPIO_INPUT_ROUTE | GPIO_HP_REAR | GPIO_OUTPUT_ENABLE); | ||
157 | oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, | ||
158 | GPIO_INPUT_ROUTE | GPIO_HP_REAR); | ||
159 | dg_output_enable(chip); | ||
160 | } | ||
161 | |||
162 | static void dg_cleanup(struct oxygen *chip) | ||
163 | { | ||
164 | oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE); | ||
165 | } | ||
166 | |||
167 | static void dg_suspend(struct oxygen *chip) | ||
168 | { | ||
169 | dg_cleanup(chip); | ||
170 | } | ||
171 | |||
172 | static void dg_resume(struct oxygen *chip) | ||
173 | { | ||
174 | cs4245_registers_init(chip); | ||
175 | dg_output_enable(chip); | ||
176 | } | ||
177 | |||
178 | static void set_cs4245_dac_params(struct oxygen *chip, | ||
179 | struct snd_pcm_hw_params *params) | ||
180 | { | ||
181 | struct dg *data = chip->model_data; | ||
182 | u8 value; | ||
183 | |||
184 | value = data->cs4245_regs[CS4245_DAC_CTRL_1] & ~CS4245_DAC_FM_MASK; | ||
185 | if (params_rate(params) <= 50000) | ||
186 | value |= CS4245_DAC_FM_SINGLE; | ||
187 | else if (params_rate(params) <= 100000) | ||
188 | value |= CS4245_DAC_FM_DOUBLE; | ||
189 | else | ||
190 | value |= CS4245_DAC_FM_QUAD; | ||
191 | cs4245_write_cached(chip, CS4245_DAC_CTRL_1, value); | ||
192 | } | ||
193 | |||
194 | static void set_cs4245_adc_params(struct oxygen *chip, | ||
195 | struct snd_pcm_hw_params *params) | ||
196 | { | ||
197 | struct dg *data = chip->model_data; | ||
198 | u8 value; | ||
199 | |||
200 | value = data->cs4245_regs[CS4245_ADC_CTRL] & ~CS4245_ADC_FM_MASK; | ||
201 | if (params_rate(params) <= 50000) | ||
202 | value |= CS4245_ADC_FM_SINGLE; | ||
203 | else if (params_rate(params) <= 100000) | ||
204 | value |= CS4245_ADC_FM_DOUBLE; | ||
205 | else | ||
206 | value |= CS4245_ADC_FM_QUAD; | ||
207 | cs4245_write_cached(chip, CS4245_ADC_CTRL, value); | ||
208 | } | ||
209 | |||
210 | static int output_switch_info(struct snd_kcontrol *ctl, | ||
211 | struct snd_ctl_elem_info *info) | ||
212 | { | ||
213 | static const char *const names[3] = { | ||
214 | "Speakers", "Headphones", "FP Headphones" | ||
215 | }; | ||
216 | |||
217 | return snd_ctl_enum_info(info, 1, 3, names); | ||
218 | } | ||
219 | |||
220 | static int output_switch_get(struct snd_kcontrol *ctl, | ||
221 | struct snd_ctl_elem_value *value) | ||
222 | { | ||
223 | struct oxygen *chip = ctl->private_data; | ||
224 | struct dg *data = chip->model_data; | ||
225 | |||
226 | mutex_lock(&chip->mutex); | ||
227 | value->value.enumerated.item[0] = data->output_sel; | ||
228 | mutex_unlock(&chip->mutex); | ||
229 | return 0; | ||
230 | } | ||
231 | |||
232 | static int output_switch_put(struct snd_kcontrol *ctl, | ||
233 | struct snd_ctl_elem_value *value) | ||
234 | { | ||
235 | struct oxygen *chip = ctl->private_data; | ||
236 | struct dg *data = chip->model_data; | ||
237 | u8 reg; | ||
238 | int changed; | ||
239 | |||
240 | if (value->value.enumerated.item[0] > 2) | ||
241 | return -EINVAL; | ||
242 | |||
243 | mutex_lock(&chip->mutex); | ||
244 | changed = value->value.enumerated.item[0] != data->output_sel; | ||
245 | if (changed) { | ||
246 | data->output_sel = value->value.enumerated.item[0]; | ||
247 | |||
248 | reg = data->cs4245_regs[CS4245_SIGNAL_SEL] & | ||
249 | ~CS4245_A_OUT_SEL_MASK; | ||
250 | reg |= data->output_sel == 2 ? | ||
251 | CS4245_A_OUT_SEL_DAC : CS4245_A_OUT_SEL_HIZ; | ||
252 | cs4245_write_cached(chip, CS4245_SIGNAL_SEL, reg); | ||
253 | |||
254 | cs4245_write_cached(chip, CS4245_DAC_A_CTRL, | ||
255 | data->output_sel ? data->hp_vol_att : 0); | ||
256 | cs4245_write_cached(chip, CS4245_DAC_B_CTRL, | ||
257 | data->output_sel ? data->hp_vol_att : 0); | ||
258 | |||
259 | oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, | ||
260 | data->output_sel == 1 ? GPIO_HP_REAR : 0, | ||
261 | GPIO_HP_REAR); | ||
262 | } | ||
263 | mutex_unlock(&chip->mutex); | ||
264 | return changed; | ||
265 | } | ||
266 | |||
267 | static int hp_volume_offset_info(struct snd_kcontrol *ctl, | ||
268 | struct snd_ctl_elem_info *info) | ||
269 | { | ||
270 | static const char *const names[3] = { | ||
271 | "< 64 ohms", "64-150 ohms", "150-300 ohms" | ||
272 | }; | ||
273 | |||
274 | return snd_ctl_enum_info(info, 1, 3, names); | ||
275 | } | ||
276 | |||
277 | static int hp_volume_offset_get(struct snd_kcontrol *ctl, | ||
278 | struct snd_ctl_elem_value *value) | ||
279 | { | ||
280 | struct oxygen *chip = ctl->private_data; | ||
281 | struct dg *data = chip->model_data; | ||
282 | |||
283 | mutex_lock(&chip->mutex); | ||
284 | if (data->hp_vol_att > 2 * 7) | ||
285 | value->value.enumerated.item[0] = 0; | ||
286 | else if (data->hp_vol_att > 0) | ||
287 | value->value.enumerated.item[0] = 1; | ||
288 | else | ||
289 | value->value.enumerated.item[0] = 2; | ||
290 | mutex_unlock(&chip->mutex); | ||
291 | return 0; | ||
292 | } | ||
293 | |||
294 | static int hp_volume_offset_put(struct snd_kcontrol *ctl, | ||
295 | struct snd_ctl_elem_value *value) | ||
296 | { | ||
297 | static const s8 atts[3] = { 2 * 16, 2 * 7, 0 }; | ||
298 | struct oxygen *chip = ctl->private_data; | ||
299 | struct dg *data = chip->model_data; | ||
300 | s8 att; | ||
301 | int changed; | ||
302 | |||
303 | if (value->value.enumerated.item[0] > 2) | ||
304 | return -EINVAL; | ||
305 | att = atts[value->value.enumerated.item[0]]; | ||
306 | mutex_lock(&chip->mutex); | ||
307 | changed = att != data->hp_vol_att; | ||
308 | if (changed) { | ||
309 | data->hp_vol_att = att; | ||
310 | if (data->output_sel) { | ||
311 | cs4245_write_cached(chip, CS4245_DAC_A_CTRL, att); | ||
312 | cs4245_write_cached(chip, CS4245_DAC_B_CTRL, att); | ||
313 | } | ||
314 | } | ||
315 | mutex_unlock(&chip->mutex); | ||
316 | return changed; | ||
317 | } | ||
318 | |||
319 | static int input_vol_info(struct snd_kcontrol *ctl, | ||
320 | struct snd_ctl_elem_info *info) | ||
321 | { | ||
322 | info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
323 | info->count = 2; | ||
324 | info->value.integer.min = 2 * -12; | ||
325 | info->value.integer.max = 2 * 12; | ||
326 | return 0; | ||
327 | } | ||
328 | |||
329 | static int input_vol_get(struct snd_kcontrol *ctl, | ||
330 | struct snd_ctl_elem_value *value) | ||
331 | { | ||
332 | struct oxygen *chip = ctl->private_data; | ||
333 | struct dg *data = chip->model_data; | ||
334 | unsigned int idx = ctl->private_value; | ||
335 | |||
336 | mutex_lock(&chip->mutex); | ||
337 | value->value.integer.value[0] = data->input_vol[idx][0]; | ||
338 | value->value.integer.value[1] = data->input_vol[idx][1]; | ||
339 | mutex_unlock(&chip->mutex); | ||
340 | return 0; | ||
341 | } | ||
342 | |||
343 | static int input_vol_put(struct snd_kcontrol *ctl, | ||
344 | struct snd_ctl_elem_value *value) | ||
345 | { | ||
346 | struct oxygen *chip = ctl->private_data; | ||
347 | struct dg *data = chip->model_data; | ||
348 | unsigned int idx = ctl->private_value; | ||
349 | int changed = 0; | ||
350 | |||
351 | if (value->value.integer.value[0] < 2 * -12 || | ||
352 | value->value.integer.value[0] > 2 * 12 || | ||
353 | value->value.integer.value[1] < 2 * -12 || | ||
354 | value->value.integer.value[1] > 2 * 12) | ||
355 | return -EINVAL; | ||
356 | mutex_lock(&chip->mutex); | ||
357 | changed = data->input_vol[idx][0] != value->value.integer.value[0] || | ||
358 | data->input_vol[idx][1] != value->value.integer.value[1]; | ||
359 | if (changed) { | ||
360 | data->input_vol[idx][0] = value->value.integer.value[0]; | ||
361 | data->input_vol[idx][1] = value->value.integer.value[1]; | ||
362 | if (idx == data->input_sel) { | ||
363 | cs4245_write_cached(chip, CS4245_PGA_A_CTRL, | ||
364 | data->input_vol[idx][0]); | ||
365 | cs4245_write_cached(chip, CS4245_PGA_B_CTRL, | ||
366 | data->input_vol[idx][1]); | ||
367 | } | ||
368 | } | ||
369 | mutex_unlock(&chip->mutex); | ||
370 | return changed; | ||
371 | } | ||
372 | |||
373 | static DECLARE_TLV_DB_SCALE(cs4245_pga_db_scale, -1200, 50, 0); | ||
374 | |||
375 | static int input_sel_info(struct snd_kcontrol *ctl, | ||
376 | struct snd_ctl_elem_info *info) | ||
377 | { | ||
378 | static const char *const names[4] = { | ||
379 | "Mic", "Aux", "Front Mic", "Line" | ||
380 | }; | ||
381 | |||
382 | return snd_ctl_enum_info(info, 1, 4, names); | ||
383 | } | ||
384 | |||
385 | static int input_sel_get(struct snd_kcontrol *ctl, | ||
386 | struct snd_ctl_elem_value *value) | ||
387 | { | ||
388 | struct oxygen *chip = ctl->private_data; | ||
389 | struct dg *data = chip->model_data; | ||
390 | |||
391 | mutex_lock(&chip->mutex); | ||
392 | value->value.enumerated.item[0] = data->input_sel; | ||
393 | mutex_unlock(&chip->mutex); | ||
394 | return 0; | ||
395 | } | ||
396 | |||
397 | static int input_sel_put(struct snd_kcontrol *ctl, | ||
398 | struct snd_ctl_elem_value *value) | ||
399 | { | ||
400 | static const u8 sel_values[4] = { | ||
401 | CS4245_SEL_MIC, | ||
402 | CS4245_SEL_INPUT_1, | ||
403 | CS4245_SEL_INPUT_2, | ||
404 | CS4245_SEL_INPUT_4 | ||
405 | }; | ||
406 | struct oxygen *chip = ctl->private_data; | ||
407 | struct dg *data = chip->model_data; | ||
408 | int changed; | ||
409 | |||
410 | if (value->value.enumerated.item[0] > 3) | ||
411 | return -EINVAL; | ||
412 | |||
413 | mutex_lock(&chip->mutex); | ||
414 | changed = value->value.enumerated.item[0] != data->input_sel; | ||
415 | if (changed) { | ||
416 | data->input_sel = value->value.enumerated.item[0]; | ||
417 | |||
418 | cs4245_write(chip, CS4245_ANALOG_IN, | ||
419 | (data->cs4245_regs[CS4245_ANALOG_IN] & | ||
420 | ~CS4245_SEL_MASK) | | ||
421 | sel_values[data->input_sel]); | ||
422 | |||
423 | cs4245_write_cached(chip, CS4245_PGA_A_CTRL, | ||
424 | data->input_vol[data->input_sel][0]); | ||
425 | cs4245_write_cached(chip, CS4245_PGA_B_CTRL, | ||
426 | data->input_vol[data->input_sel][1]); | ||
427 | |||
428 | oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, | ||
429 | data->input_sel ? 0 : GPIO_INPUT_ROUTE, | ||
430 | GPIO_INPUT_ROUTE); | ||
431 | } | ||
432 | mutex_unlock(&chip->mutex); | ||
433 | return changed; | ||
434 | } | ||
435 | |||
436 | static int hpf_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) | ||
437 | { | ||
438 | static const char *const names[2] = { "Active", "Frozen" }; | ||
439 | |||
440 | return snd_ctl_enum_info(info, 1, 2, names); | ||
441 | } | ||
442 | |||
443 | static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) | ||
444 | { | ||
445 | struct oxygen *chip = ctl->private_data; | ||
446 | struct dg *data = chip->model_data; | ||
447 | |||
448 | value->value.enumerated.item[0] = | ||
449 | !!(data->cs4245_regs[CS4245_ADC_CTRL] & CS4245_HPF_FREEZE); | ||
450 | return 0; | ||
451 | } | ||
452 | |||
453 | static int hpf_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) | ||
454 | { | ||
455 | struct oxygen *chip = ctl->private_data; | ||
456 | struct dg *data = chip->model_data; | ||
457 | u8 reg; | ||
458 | int changed; | ||
459 | |||
460 | mutex_lock(&chip->mutex); | ||
461 | reg = data->cs4245_regs[CS4245_ADC_CTRL] & ~CS4245_HPF_FREEZE; | ||
462 | if (value->value.enumerated.item[0]) | ||
463 | reg |= CS4245_HPF_FREEZE; | ||
464 | changed = reg != data->cs4245_regs[CS4245_ADC_CTRL]; | ||
465 | if (changed) | ||
466 | cs4245_write(chip, CS4245_ADC_CTRL, reg); | ||
467 | mutex_unlock(&chip->mutex); | ||
468 | return changed; | ||
469 | } | ||
470 | |||
471 | #define INPUT_VOLUME(xname, index) { \ | ||
472 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
473 | .name = xname, \ | ||
474 | .info = input_vol_info, \ | ||
475 | .get = input_vol_get, \ | ||
476 | .put = input_vol_put, \ | ||
477 | .tlv = { .p = cs4245_pga_db_scale }, \ | ||
478 | .private_value = index, \ | ||
479 | } | ||
480 | static const struct snd_kcontrol_new dg_controls[] = { | ||
481 | { | ||
482 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
483 | .name = "Analog Output Playback Enum", | ||
484 | .info = output_switch_info, | ||
485 | .get = output_switch_get, | ||
486 | .put = output_switch_put, | ||
487 | }, | ||
488 | { | ||
489 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
490 | .name = "Headphones Impedance Playback Enum", | ||
491 | .info = hp_volume_offset_info, | ||
492 | .get = hp_volume_offset_get, | ||
493 | .put = hp_volume_offset_put, | ||
494 | }, | ||
495 | INPUT_VOLUME("Mic Capture Volume", 0), | ||
496 | INPUT_VOLUME("Aux Capture Volume", 1), | ||
497 | INPUT_VOLUME("Front Mic Capture Volume", 2), | ||
498 | INPUT_VOLUME("Line Capture Volume", 3), | ||
499 | { | ||
500 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
501 | .name = "Capture Source", | ||
502 | .info = input_sel_info, | ||
503 | .get = input_sel_get, | ||
504 | .put = input_sel_put, | ||
505 | }, | ||
506 | { | ||
507 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
508 | .name = "ADC High-pass Filter Capture Enum", | ||
509 | .info = hpf_info, | ||
510 | .get = hpf_get, | ||
511 | .put = hpf_put, | ||
512 | }, | ||
513 | }; | ||
514 | |||
515 | static int dg_control_filter(struct snd_kcontrol_new *template) | ||
516 | { | ||
517 | if (!strncmp(template->name, "Master Playback ", 16)) | ||
518 | return 1; | ||
519 | return 0; | ||
520 | } | ||
521 | |||
522 | static int dg_mixer_init(struct oxygen *chip) | ||
523 | { | ||
524 | unsigned int i; | ||
525 | int err; | ||
526 | |||
527 | for (i = 0; i < ARRAY_SIZE(dg_controls); ++i) { | ||
528 | err = snd_ctl_add(chip->card, | ||
529 | snd_ctl_new1(&dg_controls[i], chip)); | ||
530 | if (err < 0) | ||
531 | return err; | ||
532 | } | ||
533 | return 0; | ||
534 | } | ||
535 | |||
536 | static void dump_cs4245_registers(struct oxygen *chip, | ||
537 | struct snd_info_buffer *buffer) | ||
538 | { | ||
539 | struct dg *data = chip->model_data; | ||
540 | unsigned int i; | ||
541 | |||
542 | snd_iprintf(buffer, "\nCS4245:"); | ||
543 | for (i = 1; i <= 0x10; ++i) | ||
544 | snd_iprintf(buffer, " %02x", data->cs4245_regs[i]); | ||
545 | snd_iprintf(buffer, "\n"); | ||
546 | } | ||
547 | |||
548 | struct oxygen_model model_xonar_dg = { | ||
549 | .shortname = "Xonar DG", | ||
550 | .longname = "C-Media Oxygen HD Audio", | ||
551 | .chip = "CMI8786", | ||
552 | .init = dg_init, | ||
553 | .control_filter = dg_control_filter, | ||
554 | .mixer_init = dg_mixer_init, | ||
555 | .cleanup = dg_cleanup, | ||
556 | .suspend = dg_suspend, | ||
557 | .resume = dg_resume, | ||
558 | .set_dac_params = set_cs4245_dac_params, | ||
559 | .set_adc_params = set_cs4245_adc_params, | ||
560 | .dump_registers = dump_cs4245_registers, | ||
561 | .model_data_size = sizeof(struct dg), | ||
562 | .device_config = PLAYBACK_0_TO_I2S | | ||
563 | PLAYBACK_1_TO_SPDIF | | ||
564 | CAPTURE_0_FROM_I2S_2, | ||
565 | .dac_channels_pcm = 6, | ||
566 | .dac_channels_mixer = 0, | ||
567 | .function_flags = OXYGEN_FUNCTION_SPI, | ||
568 | .dac_mclks = OXYGEN_MCLKS(256, 128, 128), | ||
569 | .adc_mclks = OXYGEN_MCLKS(256, 128, 128), | ||
570 | .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | ||
571 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | ||
572 | }; | ||
diff --git a/sound/pci/oxygen/xonar_dg.h b/sound/pci/oxygen/xonar_dg.h new file mode 100644 index 000000000000..5688d78609a9 --- /dev/null +++ b/sound/pci/oxygen/xonar_dg.h | |||
@@ -0,0 +1,8 @@ | |||
1 | #ifndef XONAR_DG_H_INCLUDED | ||
2 | #define XONAR_DG_H_INCLUDED | ||
3 | |||
4 | #include "oxygen.h" | ||
5 | |||
6 | extern struct oxygen_model model_xonar_dg; | ||
7 | |||
8 | #endif | ||
diff --git a/sound/pci/oxygen/xonar_hdmi.c b/sound/pci/oxygen/xonar_hdmi.c index b12db1f1cea9..136dac6a3964 100644 --- a/sound/pci/oxygen/xonar_hdmi.c +++ b/sound/pci/oxygen/xonar_hdmi.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * helper functions for HDMI models (Xonar HDAV1.3) | 2 | * helper functions for HDMI models (Xonar HDAV1.3/HDAV1.3 Slim) |
3 | * | 3 | * |
4 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> | 4 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> |
5 | * | 5 | * |
diff --git a/sound/pci/oxygen/xonar_lib.c b/sound/pci/oxygen/xonar_lib.c index b3ff71316653..0ebe7f5916f9 100644 --- a/sound/pci/oxygen/xonar_lib.c +++ b/sound/pci/oxygen/xonar_lib.c | |||
@@ -104,9 +104,10 @@ int xonar_gpio_bit_switch_get(struct snd_kcontrol *ctl, | |||
104 | { | 104 | { |
105 | struct oxygen *chip = ctl->private_data; | 105 | struct oxygen *chip = ctl->private_data; |
106 | u16 bit = ctl->private_value; | 106 | u16 bit = ctl->private_value; |
107 | bool invert = ctl->private_value & XONAR_GPIO_BIT_INVERT; | ||
107 | 108 | ||
108 | value->value.integer.value[0] = | 109 | value->value.integer.value[0] = |
109 | !!(oxygen_read16(chip, OXYGEN_GPIO_DATA) & bit); | 110 | !!(oxygen_read16(chip, OXYGEN_GPIO_DATA) & bit) ^ invert; |
110 | return 0; | 111 | return 0; |
111 | } | 112 | } |
112 | 113 | ||
@@ -115,12 +116,13 @@ int xonar_gpio_bit_switch_put(struct snd_kcontrol *ctl, | |||
115 | { | 116 | { |
116 | struct oxygen *chip = ctl->private_data; | 117 | struct oxygen *chip = ctl->private_data; |
117 | u16 bit = ctl->private_value; | 118 | u16 bit = ctl->private_value; |
119 | bool invert = ctl->private_value & XONAR_GPIO_BIT_INVERT; | ||
118 | u16 old_bits, new_bits; | 120 | u16 old_bits, new_bits; |
119 | int changed; | 121 | int changed; |
120 | 122 | ||
121 | spin_lock_irq(&chip->reg_lock); | 123 | spin_lock_irq(&chip->reg_lock); |
122 | old_bits = oxygen_read16(chip, OXYGEN_GPIO_DATA); | 124 | old_bits = oxygen_read16(chip, OXYGEN_GPIO_DATA); |
123 | if (value->value.integer.value[0]) | 125 | if (!!value->value.integer.value[0] ^ invert) |
124 | new_bits = old_bits | bit; | 126 | new_bits = old_bits | bit; |
125 | else | 127 | else |
126 | new_bits = old_bits & ~bit; | 128 | new_bits = old_bits & ~bit; |
diff --git a/sound/pci/oxygen/xonar_pcm179x.c b/sound/pci/oxygen/xonar_pcm179x.c index d491fd6c0be2..54cad38ec30a 100644 --- a/sound/pci/oxygen/xonar_pcm179x.c +++ b/sound/pci/oxygen/xonar_pcm179x.c | |||
@@ -22,20 +22,26 @@ | |||
22 | * | 22 | * |
23 | * CMI8788: | 23 | * CMI8788: |
24 | * | 24 | * |
25 | * SPI 0 -> 1st PCM1796 (front) | 25 | * SPI 0 -> 1st PCM1796 (front) |
26 | * SPI 1 -> 2nd PCM1796 (surround) | 26 | * SPI 1 -> 2nd PCM1796 (surround) |
27 | * SPI 2 -> 3rd PCM1796 (center/LFE) | 27 | * SPI 2 -> 3rd PCM1796 (center/LFE) |
28 | * SPI 4 -> 4th PCM1796 (back) | 28 | * SPI 4 -> 4th PCM1796 (back) |
29 | * | 29 | * |
30 | * GPIO 2 -> M0 of CS5381 | 30 | * GPIO 2 -> M0 of CS5381 |
31 | * GPIO 3 -> M1 of CS5381 | 31 | * GPIO 3 -> M1 of CS5381 |
32 | * GPIO 5 <- external power present (D2X only) | 32 | * GPIO 5 <- external power present (D2X only) |
33 | * GPIO 7 -> ALT | 33 | * GPIO 7 -> ALT |
34 | * GPIO 8 -> enable output to speakers | 34 | * GPIO 8 -> enable output to speakers |
35 | * | 35 | * |
36 | * CM9780: | 36 | * CM9780: |
37 | * | 37 | * |
38 | * GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input | 38 | * LINE_OUT -> input of ADC |
39 | * | ||
40 | * AUX_IN <- aux | ||
41 | * VIDEO_IN <- CD | ||
42 | * FMIC_IN <- mic | ||
43 | * | ||
44 | * GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input | ||
39 | */ | 45 | */ |
40 | 46 | ||
41 | /* | 47 | /* |
@@ -44,52 +50,53 @@ | |||
44 | * | 50 | * |
45 | * CMI8788: | 51 | * CMI8788: |
46 | * | 52 | * |
47 | * I²C <-> PCM1796 (front) | 53 | * I²C <-> PCM1796 (addr 1001100) (front) |
48 | * | 54 | * |
49 | * GPI 0 <- external power present | 55 | * GPI 0 <- external power present |
50 | * | 56 | * |
51 | * GPIO 0 -> enable output to speakers | 57 | * GPIO 0 -> enable HDMI (0) or speaker (1) output |
52 | * GPIO 2 -> M0 of CS5381 | 58 | * GPIO 2 -> M0 of CS5381 |
53 | * GPIO 3 -> M1 of CS5381 | 59 | * GPIO 3 -> M1 of CS5381 |
54 | * GPIO 8 -> route input jack to line-in (0) or mic-in (1) | 60 | * GPIO 4 <- daughterboard detection |
61 | * GPIO 5 <- daughterboard detection | ||
62 | * GPIO 6 -> ? | ||
63 | * GPIO 7 -> ? | ||
64 | * GPIO 8 -> route input jack to line-in (0) or mic-in (1) | ||
55 | * | 65 | * |
56 | * TXD -> HDMI controller | 66 | * UART <-> HDMI controller |
57 | * RXD <- HDMI controller | ||
58 | * | ||
59 | * PCM1796 front: AD1,0 <- 0,0 | ||
60 | * | 67 | * |
61 | * CM9780: | 68 | * CM9780: |
62 | * | 69 | * |
63 | * GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input | 70 | * LINE_OUT -> input of ADC |
71 | * | ||
72 | * AUX_IN <- aux | ||
73 | * CD_IN <- CD | ||
74 | * MIC_IN <- mic | ||
75 | * | ||
76 | * GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input | ||
64 | * | 77 | * |
65 | * no daughterboard | 78 | * no daughterboard |
66 | * ---------------- | 79 | * ---------------- |
67 | * | 80 | * |
68 | * GPIO 4 <- 1 | 81 | * GPIO 4 <- 1 |
69 | * | 82 | * |
70 | * H6 daughterboard | 83 | * H6 daughterboard |
71 | * ---------------- | 84 | * ---------------- |
72 | * | 85 | * |
73 | * GPIO 4 <- 0 | 86 | * GPIO 4 <- 0 |
74 | * GPIO 5 <- 0 | 87 | * GPIO 5 <- 0 |
75 | * | ||
76 | * I²C <-> PCM1796 (surround) | ||
77 | * <-> PCM1796 (center/LFE) | ||
78 | * <-> PCM1796 (back) | ||
79 | * | 88 | * |
80 | * PCM1796 surround: AD1,0 <- 0,1 | 89 | * I²C <-> PCM1796 (addr 1001101) (surround) |
81 | * PCM1796 center/LFE: AD1,0 <- 1,0 | 90 | * <-> PCM1796 (addr 1001110) (center/LFE) |
82 | * PCM1796 back: AD1,0 <- 1,1 | 91 | * <-> PCM1796 (addr 1001111) (back) |
83 | * | 92 | * |
84 | * unknown daughterboard | 93 | * unknown daughterboard |
85 | * --------------------- | 94 | * --------------------- |
86 | * | 95 | * |
87 | * GPIO 4 <- 0 | 96 | * GPIO 4 <- 0 |
88 | * GPIO 5 <- 1 | 97 | * GPIO 5 <- 1 |
89 | * | ||
90 | * I²C <-> CS4362A (surround, center/LFE, back) | ||
91 | * | 98 | * |
92 | * CS4362A: AD0 <- 0 | 99 | * I²C <-> CS4362A (addr 0011000) (surround, center/LFE, back) |
93 | */ | 100 | */ |
94 | 101 | ||
95 | /* | 102 | /* |
@@ -98,32 +105,35 @@ | |||
98 | * | 105 | * |
99 | * CMI8788: | 106 | * CMI8788: |
100 | * | 107 | * |
101 | * I²C <-> PCM1792A | 108 | * I²C <-> PCM1792A (addr 1001100) |
102 | * <-> CS2000 (ST only) | 109 | * <-> CS2000 (addr 1001110) (ST only) |
103 | * | 110 | * |
104 | * ADC1 MCLK -> REF_CLK of CS2000 (ST only) | 111 | * ADC1 MCLK -> REF_CLK of CS2000 (ST only) |
105 | * | 112 | * |
106 | * GPI 0 <- external power present (STX only) | 113 | * GPI 0 <- external power present (STX only) |
107 | * | 114 | * |
108 | * GPIO 0 -> enable output to speakers | 115 | * GPIO 0 -> enable output to speakers |
109 | * GPIO 1 -> route HP to front panel (0) or rear jack (1) | 116 | * GPIO 1 -> route HP to front panel (0) or rear jack (1) |
110 | * GPIO 2 -> M0 of CS5381 | 117 | * GPIO 2 -> M0 of CS5381 |
111 | * GPIO 3 -> M1 of CS5381 | 118 | * GPIO 3 -> M1 of CS5381 |
112 | * GPIO 7 -> route output to speaker jacks (0) or HP (1) | 119 | * GPIO 4 <- daughterboard detection |
113 | * GPIO 8 -> route input jack to line-in (0) or mic-in (1) | 120 | * GPIO 5 <- daughterboard detection |
121 | * GPIO 6 -> ? | ||
122 | * GPIO 7 -> route output to speaker jacks (0) or HP (1) | ||
123 | * GPIO 8 -> route input jack to line-in (0) or mic-in (1) | ||
114 | * | 124 | * |
115 | * PCM1792A: | 125 | * PCM1792A: |
116 | * | 126 | * |
117 | * AD1,0 <- 0,0 | 127 | * SCK <- CLK_OUT of CS2000 (ST only) |
118 | * SCK <- CLK_OUT of CS2000 (ST only) | ||
119 | * | 128 | * |
120 | * CS2000: | 129 | * CM9780: |
121 | * | 130 | * |
122 | * AD0 <- 0 | 131 | * LINE_OUT -> input of ADC |
123 | * | 132 | * |
124 | * CM9780: | 133 | * AUX_IN <- aux |
134 | * MIC_IN <- mic | ||
125 | * | 135 | * |
126 | * GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input | 136 | * GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input |
127 | * | 137 | * |
128 | * H6 daughterboard | 138 | * H6 daughterboard |
129 | * ---------------- | 139 | * ---------------- |
@@ -133,15 +143,39 @@ | |||
133 | */ | 143 | */ |
134 | 144 | ||
135 | /* | 145 | /* |
136 | * Xonar HDAV1.3 Slim | 146 | * Xonar Xense |
137 | * ------------------ | 147 | * ----------- |
138 | * | 148 | * |
139 | * CMI8788: | 149 | * CMI8788: |
140 | * | 150 | * |
141 | * GPIO 1 -> enable output | 151 | * I²C <-> PCM1796 (addr 1001100) (front) |
152 | * <-> CS4362A (addr 0011000) (surround, center/LFE, back) | ||
153 | * <-> CS2000 (addr 1001110) | ||
154 | * | ||
155 | * ADC1 MCLK -> REF_CLK of CS2000 | ||
156 | * | ||
157 | * GPI 0 <- external power present | ||
158 | * | ||
159 | * GPIO 0 -> enable output | ||
160 | * GPIO 1 -> route HP to front panel (0) or rear jack (1) | ||
161 | * GPIO 2 -> M0 of CS5381 | ||
162 | * GPIO 3 -> M1 of CS5381 | ||
163 | * GPIO 4 -> enable output | ||
164 | * GPIO 5 -> enable output | ||
165 | * GPIO 6 -> ? | ||
166 | * GPIO 7 -> route output to HP (0) or speaker (1) | ||
167 | * GPIO 8 -> route input jack to mic-in (0) or line-in (1) | ||
142 | * | 168 | * |
143 | * TXD -> HDMI controller | 169 | * CM9780: |
144 | * RXD <- HDMI controller | 170 | * |
171 | * LINE_OUT -> input of ADC | ||
172 | * | ||
173 | * AUX_IN <- aux | ||
174 | * VIDEO_IN <- ? | ||
175 | * FMIC_IN <- mic | ||
176 | * | ||
177 | * GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input | ||
178 | * GPO 1 -> route mic-in from input jack (0) or front panel header (1) | ||
145 | */ | 179 | */ |
146 | 180 | ||
147 | #include <linux/pci.h> | 181 | #include <linux/pci.h> |
@@ -150,6 +184,7 @@ | |||
150 | #include <sound/ac97_codec.h> | 184 | #include <sound/ac97_codec.h> |
151 | #include <sound/control.h> | 185 | #include <sound/control.h> |
152 | #include <sound/core.h> | 186 | #include <sound/core.h> |
187 | #include <sound/info.h> | ||
153 | #include <sound/pcm.h> | 188 | #include <sound/pcm.h> |
154 | #include <sound/pcm_params.h> | 189 | #include <sound/pcm_params.h> |
155 | #include <sound/tlv.h> | 190 | #include <sound/tlv.h> |
@@ -167,12 +202,14 @@ | |||
167 | #define GPIO_INPUT_ROUTE 0x0100 | 202 | #define GPIO_INPUT_ROUTE 0x0100 |
168 | 203 | ||
169 | #define GPIO_HDAV_OUTPUT_ENABLE 0x0001 | 204 | #define GPIO_HDAV_OUTPUT_ENABLE 0x0001 |
205 | #define GPIO_HDAV_MAGIC 0x00c0 | ||
170 | 206 | ||
171 | #define GPIO_DB_MASK 0x0030 | 207 | #define GPIO_DB_MASK 0x0030 |
172 | #define GPIO_DB_H6 0x0000 | 208 | #define GPIO_DB_H6 0x0000 |
173 | 209 | ||
174 | #define GPIO_ST_OUTPUT_ENABLE 0x0001 | 210 | #define GPIO_ST_OUTPUT_ENABLE 0x0001 |
175 | #define GPIO_ST_HP_REAR 0x0002 | 211 | #define GPIO_ST_HP_REAR 0x0002 |
212 | #define GPIO_ST_MAGIC 0x0040 | ||
176 | #define GPIO_ST_HP 0x0080 | 213 | #define GPIO_ST_HP 0x0080 |
177 | 214 | ||
178 | #define I2C_DEVICE_PCM1796(i) (0x98 + ((i) << 1)) /* 10011, ii, /W=0 */ | 215 | #define I2C_DEVICE_PCM1796(i) (0x98 + ((i) << 1)) /* 10011, ii, /W=0 */ |
@@ -186,11 +223,12 @@ struct xonar_pcm179x { | |||
186 | unsigned int dacs; | 223 | unsigned int dacs; |
187 | u8 pcm1796_regs[4][5]; | 224 | u8 pcm1796_regs[4][5]; |
188 | unsigned int current_rate; | 225 | unsigned int current_rate; |
189 | bool os_128; | 226 | bool h6; |
190 | bool hp_active; | 227 | bool hp_active; |
191 | s8 hp_gain_offset; | 228 | s8 hp_gain_offset; |
192 | bool has_cs2000; | 229 | bool has_cs2000; |
193 | u8 cs2000_fun_cfg_1; | 230 | u8 cs2000_regs[0x1f]; |
231 | bool broken_i2c; | ||
194 | }; | 232 | }; |
195 | 233 | ||
196 | struct xonar_hdav { | 234 | struct xonar_hdav { |
@@ -249,16 +287,14 @@ static void cs2000_write(struct oxygen *chip, u8 reg, u8 value) | |||
249 | struct xonar_pcm179x *data = chip->model_data; | 287 | struct xonar_pcm179x *data = chip->model_data; |
250 | 288 | ||
251 | oxygen_write_i2c(chip, I2C_DEVICE_CS2000, reg, value); | 289 | oxygen_write_i2c(chip, I2C_DEVICE_CS2000, reg, value); |
252 | if (reg == CS2000_FUN_CFG_1) | 290 | data->cs2000_regs[reg] = value; |
253 | data->cs2000_fun_cfg_1 = value; | ||
254 | } | 291 | } |
255 | 292 | ||
256 | static void cs2000_write_cached(struct oxygen *chip, u8 reg, u8 value) | 293 | static void cs2000_write_cached(struct oxygen *chip, u8 reg, u8 value) |
257 | { | 294 | { |
258 | struct xonar_pcm179x *data = chip->model_data; | 295 | struct xonar_pcm179x *data = chip->model_data; |
259 | 296 | ||
260 | if (reg != CS2000_FUN_CFG_1 || | 297 | if (value != data->cs2000_regs[reg]) |
261 | value != data->cs2000_fun_cfg_1) | ||
262 | cs2000_write(chip, reg, value); | 298 | cs2000_write(chip, reg, value); |
263 | } | 299 | } |
264 | 300 | ||
@@ -268,6 +304,7 @@ static void pcm1796_registers_init(struct oxygen *chip) | |||
268 | unsigned int i; | 304 | unsigned int i; |
269 | s8 gain_offset; | 305 | s8 gain_offset; |
270 | 306 | ||
307 | msleep(1); | ||
271 | gain_offset = data->hp_active ? data->hp_gain_offset : 0; | 308 | gain_offset = data->hp_active ? data->hp_gain_offset : 0; |
272 | for (i = 0; i < data->dacs; ++i) { | 309 | for (i = 0; i < data->dacs; ++i) { |
273 | /* set ATLD before ATL/ATR */ | 310 | /* set ATLD before ATL/ATR */ |
@@ -282,6 +319,7 @@ static void pcm1796_registers_init(struct oxygen *chip) | |||
282 | pcm1796_write(chip, i, 20, | 319 | pcm1796_write(chip, i, 20, |
283 | data->pcm1796_regs[0][20 - PCM1796_REG_BASE]); | 320 | data->pcm1796_regs[0][20 - PCM1796_REG_BASE]); |
284 | pcm1796_write(chip, i, 21, 0); | 321 | pcm1796_write(chip, i, 21, 0); |
322 | gain_offset = 0; | ||
285 | } | 323 | } |
286 | } | 324 | } |
287 | 325 | ||
@@ -290,10 +328,11 @@ static void pcm1796_init(struct oxygen *chip) | |||
290 | struct xonar_pcm179x *data = chip->model_data; | 328 | struct xonar_pcm179x *data = chip->model_data; |
291 | 329 | ||
292 | data->pcm1796_regs[0][18 - PCM1796_REG_BASE] = PCM1796_MUTE | | 330 | data->pcm1796_regs[0][18 - PCM1796_REG_BASE] = PCM1796_MUTE | |
293 | PCM1796_DMF_DISABLED | PCM1796_FMT_24_LJUST | PCM1796_ATLD; | 331 | PCM1796_DMF_DISABLED | PCM1796_FMT_24_I2S | PCM1796_ATLD; |
294 | data->pcm1796_regs[0][19 - PCM1796_REG_BASE] = | 332 | data->pcm1796_regs[0][19 - PCM1796_REG_BASE] = |
295 | PCM1796_FLT_SHARP | PCM1796_ATS_1; | 333 | PCM1796_FLT_SHARP | PCM1796_ATS_1; |
296 | data->pcm1796_regs[0][20 - PCM1796_REG_BASE] = PCM1796_OS_64; | 334 | data->pcm1796_regs[0][20 - PCM1796_REG_BASE] = |
335 | data->h6 ? PCM1796_OS_64 : PCM1796_OS_128; | ||
297 | pcm1796_registers_init(chip); | 336 | pcm1796_registers_init(chip); |
298 | data->current_rate = 48000; | 337 | data->current_rate = 48000; |
299 | } | 338 | } |
@@ -339,18 +378,20 @@ static void xonar_hdav_init(struct oxygen *chip) | |||
339 | oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS, | 378 | oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS, |
340 | OXYGEN_2WIRE_LENGTH_8 | | 379 | OXYGEN_2WIRE_LENGTH_8 | |
341 | OXYGEN_2WIRE_INTERRUPT_MASK | | 380 | OXYGEN_2WIRE_INTERRUPT_MASK | |
342 | OXYGEN_2WIRE_SPEED_FAST); | 381 | OXYGEN_2WIRE_SPEED_STANDARD); |
343 | 382 | ||
344 | data->pcm179x.generic.anti_pop_delay = 100; | 383 | data->pcm179x.generic.anti_pop_delay = 100; |
345 | data->pcm179x.generic.output_enable_bit = GPIO_HDAV_OUTPUT_ENABLE; | 384 | data->pcm179x.generic.output_enable_bit = GPIO_HDAV_OUTPUT_ENABLE; |
346 | data->pcm179x.generic.ext_power_reg = OXYGEN_GPI_DATA; | 385 | data->pcm179x.generic.ext_power_reg = OXYGEN_GPI_DATA; |
347 | data->pcm179x.generic.ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK; | 386 | data->pcm179x.generic.ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK; |
348 | data->pcm179x.generic.ext_power_bit = GPI_EXT_POWER; | 387 | data->pcm179x.generic.ext_power_bit = GPI_EXT_POWER; |
349 | data->pcm179x.dacs = chip->model.private_data ? 4 : 1; | 388 | data->pcm179x.dacs = chip->model.dac_channels_mixer / 2; |
389 | data->pcm179x.h6 = chip->model.dac_channels_mixer > 2; | ||
350 | 390 | ||
351 | pcm1796_init(chip); | 391 | pcm1796_init(chip); |
352 | 392 | ||
353 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_INPUT_ROUTE); | 393 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, |
394 | GPIO_HDAV_MAGIC | GPIO_INPUT_ROUTE); | ||
354 | oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_INPUT_ROUTE); | 395 | oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_INPUT_ROUTE); |
355 | 396 | ||
356 | xonar_init_cs53x1(chip); | 397 | xonar_init_cs53x1(chip); |
@@ -367,7 +408,7 @@ static void xonar_st_init_i2c(struct oxygen *chip) | |||
367 | oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS, | 408 | oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS, |
368 | OXYGEN_2WIRE_LENGTH_8 | | 409 | OXYGEN_2WIRE_LENGTH_8 | |
369 | OXYGEN_2WIRE_INTERRUPT_MASK | | 410 | OXYGEN_2WIRE_INTERRUPT_MASK | |
370 | OXYGEN_2WIRE_SPEED_FAST); | 411 | OXYGEN_2WIRE_SPEED_STANDARD); |
371 | } | 412 | } |
372 | 413 | ||
373 | static void xonar_st_init_common(struct oxygen *chip) | 414 | static void xonar_st_init_common(struct oxygen *chip) |
@@ -375,13 +416,14 @@ static void xonar_st_init_common(struct oxygen *chip) | |||
375 | struct xonar_pcm179x *data = chip->model_data; | 416 | struct xonar_pcm179x *data = chip->model_data; |
376 | 417 | ||
377 | data->generic.output_enable_bit = GPIO_ST_OUTPUT_ENABLE; | 418 | data->generic.output_enable_bit = GPIO_ST_OUTPUT_ENABLE; |
378 | data->dacs = chip->model.private_data ? 4 : 1; | 419 | data->dacs = chip->model.dac_channels_mixer / 2; |
379 | data->hp_gain_offset = 2*-18; | 420 | data->hp_gain_offset = 2*-18; |
380 | 421 | ||
381 | pcm1796_init(chip); | 422 | pcm1796_init(chip); |
382 | 423 | ||
383 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, | 424 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, |
384 | GPIO_INPUT_ROUTE | GPIO_ST_HP_REAR | GPIO_ST_HP); | 425 | GPIO_INPUT_ROUTE | GPIO_ST_HP_REAR | |
426 | GPIO_ST_MAGIC | GPIO_ST_HP); | ||
385 | oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, | 427 | oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, |
386 | GPIO_INPUT_ROUTE | GPIO_ST_HP_REAR | GPIO_ST_HP); | 428 | GPIO_INPUT_ROUTE | GPIO_ST_HP_REAR | GPIO_ST_HP); |
387 | 429 | ||
@@ -410,9 +452,11 @@ static void cs2000_registers_init(struct oxygen *chip) | |||
410 | cs2000_write(chip, CS2000_RATIO_0 + 1, 0x10); | 452 | cs2000_write(chip, CS2000_RATIO_0 + 1, 0x10); |
411 | cs2000_write(chip, CS2000_RATIO_0 + 2, 0x00); | 453 | cs2000_write(chip, CS2000_RATIO_0 + 2, 0x00); |
412 | cs2000_write(chip, CS2000_RATIO_0 + 3, 0x00); | 454 | cs2000_write(chip, CS2000_RATIO_0 + 3, 0x00); |
413 | cs2000_write(chip, CS2000_FUN_CFG_1, data->cs2000_fun_cfg_1); | 455 | cs2000_write(chip, CS2000_FUN_CFG_1, |
456 | data->cs2000_regs[CS2000_FUN_CFG_1]); | ||
414 | cs2000_write(chip, CS2000_FUN_CFG_2, 0); | 457 | cs2000_write(chip, CS2000_FUN_CFG_2, 0); |
415 | cs2000_write(chip, CS2000_GLOBAL_CFG, CS2000_EN_DEV_CFG_2); | 458 | cs2000_write(chip, CS2000_GLOBAL_CFG, CS2000_EN_DEV_CFG_2); |
459 | msleep(3); /* PLL lock delay */ | ||
416 | } | 460 | } |
417 | 461 | ||
418 | static void xonar_st_init(struct oxygen *chip) | 462 | static void xonar_st_init(struct oxygen *chip) |
@@ -420,13 +464,18 @@ static void xonar_st_init(struct oxygen *chip) | |||
420 | struct xonar_pcm179x *data = chip->model_data; | 464 | struct xonar_pcm179x *data = chip->model_data; |
421 | 465 | ||
422 | data->generic.anti_pop_delay = 100; | 466 | data->generic.anti_pop_delay = 100; |
467 | data->h6 = chip->model.dac_channels_mixer > 2; | ||
423 | data->has_cs2000 = 1; | 468 | data->has_cs2000 = 1; |
424 | data->cs2000_fun_cfg_1 = CS2000_REF_CLK_DIV_1; | 469 | data->cs2000_regs[CS2000_FUN_CFG_1] = CS2000_REF_CLK_DIV_1; |
470 | data->broken_i2c = true; | ||
425 | 471 | ||
426 | oxygen_write16(chip, OXYGEN_I2S_A_FORMAT, | 472 | oxygen_write16(chip, OXYGEN_I2S_A_FORMAT, |
427 | OXYGEN_RATE_48000 | OXYGEN_I2S_FORMAT_I2S | | 473 | OXYGEN_RATE_48000 | |
428 | OXYGEN_I2S_MCLK_128 | OXYGEN_I2S_BITS_16 | | 474 | OXYGEN_I2S_FORMAT_I2S | |
429 | OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64); | 475 | OXYGEN_I2S_MCLK(data->h6 ? MCLK_256 : MCLK_512) | |
476 | OXYGEN_I2S_BITS_16 | | ||
477 | OXYGEN_I2S_MASTER | | ||
478 | OXYGEN_I2S_BCLK_64); | ||
430 | 479 | ||
431 | xonar_st_init_i2c(chip); | 480 | xonar_st_init_i2c(chip); |
432 | cs2000_registers_init(chip); | 481 | cs2000_registers_init(chip); |
@@ -507,44 +556,16 @@ static void xonar_st_resume(struct oxygen *chip) | |||
507 | xonar_stx_resume(chip); | 556 | xonar_stx_resume(chip); |
508 | } | 557 | } |
509 | 558 | ||
510 | static unsigned int mclk_from_rate(struct oxygen *chip, unsigned int rate) | ||
511 | { | ||
512 | struct xonar_pcm179x *data = chip->model_data; | ||
513 | |||
514 | if (rate <= 32000) | ||
515 | return OXYGEN_I2S_MCLK_512; | ||
516 | else if (rate <= 48000 && data->os_128) | ||
517 | return OXYGEN_I2S_MCLK_512; | ||
518 | else if (rate <= 96000) | ||
519 | return OXYGEN_I2S_MCLK_256; | ||
520 | else | ||
521 | return OXYGEN_I2S_MCLK_128; | ||
522 | } | ||
523 | |||
524 | static unsigned int get_pcm1796_i2s_mclk(struct oxygen *chip, | ||
525 | unsigned int channel, | ||
526 | struct snd_pcm_hw_params *params) | ||
527 | { | ||
528 | if (channel == PCM_MULTICH) | ||
529 | return mclk_from_rate(chip, params_rate(params)); | ||
530 | else | ||
531 | return oxygen_default_i2s_mclk(chip, channel, params); | ||
532 | } | ||
533 | |||
534 | static void update_pcm1796_oversampling(struct oxygen *chip) | 559 | static void update_pcm1796_oversampling(struct oxygen *chip) |
535 | { | 560 | { |
536 | struct xonar_pcm179x *data = chip->model_data; | 561 | struct xonar_pcm179x *data = chip->model_data; |
537 | unsigned int i; | 562 | unsigned int i; |
538 | u8 reg; | 563 | u8 reg; |
539 | 564 | ||
540 | if (data->current_rate <= 32000) | 565 | if (data->current_rate <= 48000 && !data->h6) |
541 | reg = PCM1796_OS_128; | 566 | reg = PCM1796_OS_128; |
542 | else if (data->current_rate <= 48000 && data->os_128) | ||
543 | reg = PCM1796_OS_128; | ||
544 | else if (data->current_rate <= 96000 || data->os_128) | ||
545 | reg = PCM1796_OS_64; | ||
546 | else | 567 | else |
547 | reg = PCM1796_OS_32; | 568 | reg = PCM1796_OS_64; |
548 | for (i = 0; i < data->dacs; ++i) | 569 | for (i = 0; i < data->dacs; ++i) |
549 | pcm1796_write_cached(chip, i, 20, reg); | 570 | pcm1796_write_cached(chip, i, 20, reg); |
550 | } | 571 | } |
@@ -554,6 +575,7 @@ static void set_pcm1796_params(struct oxygen *chip, | |||
554 | { | 575 | { |
555 | struct xonar_pcm179x *data = chip->model_data; | 576 | struct xonar_pcm179x *data = chip->model_data; |
556 | 577 | ||
578 | msleep(1); | ||
557 | data->current_rate = params_rate(params); | 579 | data->current_rate = params_rate(params); |
558 | update_pcm1796_oversampling(chip); | 580 | update_pcm1796_oversampling(chip); |
559 | } | 581 | } |
@@ -570,6 +592,7 @@ static void update_pcm1796_volume(struct oxygen *chip) | |||
570 | + gain_offset); | 592 | + gain_offset); |
571 | pcm1796_write_cached(chip, i, 17, chip->dac_volume[i * 2 + 1] | 593 | pcm1796_write_cached(chip, i, 17, chip->dac_volume[i * 2 + 1] |
572 | + gain_offset); | 594 | + gain_offset); |
595 | gain_offset = 0; | ||
573 | } | 596 | } |
574 | } | 597 | } |
575 | 598 | ||
@@ -579,7 +602,7 @@ static void update_pcm1796_mute(struct oxygen *chip) | |||
579 | unsigned int i; | 602 | unsigned int i; |
580 | u8 value; | 603 | u8 value; |
581 | 604 | ||
582 | value = PCM1796_DMF_DISABLED | PCM1796_FMT_24_LJUST | PCM1796_ATLD; | 605 | value = PCM1796_DMF_DISABLED | PCM1796_FMT_24_I2S | PCM1796_ATLD; |
583 | if (chip->dac_mute) | 606 | if (chip->dac_mute) |
584 | value |= PCM1796_MUTE; | 607 | value |= PCM1796_MUTE; |
585 | for (i = 0; i < data->dacs; ++i) | 608 | for (i = 0; i < data->dacs; ++i) |
@@ -592,45 +615,35 @@ static void update_cs2000_rate(struct oxygen *chip, unsigned int rate) | |||
592 | u8 rate_mclk, reg; | 615 | u8 rate_mclk, reg; |
593 | 616 | ||
594 | switch (rate) { | 617 | switch (rate) { |
595 | /* XXX Why is the I2S A MCLK half the actual I2S MCLK? */ | ||
596 | case 32000: | 618 | case 32000: |
597 | rate_mclk = OXYGEN_RATE_32000 | OXYGEN_I2S_MCLK_256; | ||
598 | break; | ||
599 | case 44100: | ||
600 | if (data->os_128) | ||
601 | rate_mclk = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_256; | ||
602 | else | ||
603 | rate_mclk = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_128; | ||
604 | break; | ||
605 | default: /* 48000 */ | ||
606 | if (data->os_128) | ||
607 | rate_mclk = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_256; | ||
608 | else | ||
609 | rate_mclk = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_128; | ||
610 | break; | ||
611 | case 64000: | 619 | case 64000: |
612 | rate_mclk = OXYGEN_RATE_32000 | OXYGEN_I2S_MCLK_256; | 620 | rate_mclk = OXYGEN_RATE_32000; |
613 | break; | 621 | break; |
622 | case 44100: | ||
614 | case 88200: | 623 | case 88200: |
615 | rate_mclk = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_256; | ||
616 | break; | ||
617 | case 96000: | ||
618 | rate_mclk = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_256; | ||
619 | break; | ||
620 | case 176400: | 624 | case 176400: |
621 | rate_mclk = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_256; | 625 | rate_mclk = OXYGEN_RATE_44100; |
622 | break; | 626 | break; |
627 | default: | ||
628 | case 48000: | ||
629 | case 96000: | ||
623 | case 192000: | 630 | case 192000: |
624 | rate_mclk = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_256; | 631 | rate_mclk = OXYGEN_RATE_48000; |
625 | break; | 632 | break; |
626 | } | 633 | } |
627 | oxygen_write16_masked(chip, OXYGEN_I2S_A_FORMAT, rate_mclk, | 634 | |
628 | OXYGEN_I2S_RATE_MASK | OXYGEN_I2S_MCLK_MASK); | 635 | if (rate <= 96000 && (rate > 48000 || data->h6)) { |
629 | if ((rate_mclk & OXYGEN_I2S_MCLK_MASK) <= OXYGEN_I2S_MCLK_128) | 636 | rate_mclk |= OXYGEN_I2S_MCLK(MCLK_256); |
630 | reg = CS2000_REF_CLK_DIV_1; | 637 | reg = CS2000_REF_CLK_DIV_1; |
631 | else | 638 | } else { |
639 | rate_mclk |= OXYGEN_I2S_MCLK(MCLK_512); | ||
632 | reg = CS2000_REF_CLK_DIV_2; | 640 | reg = CS2000_REF_CLK_DIV_2; |
641 | } | ||
642 | |||
643 | oxygen_write16_masked(chip, OXYGEN_I2S_A_FORMAT, rate_mclk, | ||
644 | OXYGEN_I2S_RATE_MASK | OXYGEN_I2S_MCLK_MASK); | ||
633 | cs2000_write_cached(chip, CS2000_FUN_CFG_1, reg); | 645 | cs2000_write_cached(chip, CS2000_FUN_CFG_1, reg); |
646 | msleep(3); /* PLL lock delay */ | ||
634 | } | 647 | } |
635 | 648 | ||
636 | static void set_st_params(struct oxygen *chip, | 649 | static void set_st_params(struct oxygen *chip, |
@@ -665,13 +678,7 @@ static int rolloff_info(struct snd_kcontrol *ctl, | |||
665 | "Sharp Roll-off", "Slow Roll-off" | 678 | "Sharp Roll-off", "Slow Roll-off" |
666 | }; | 679 | }; |
667 | 680 | ||
668 | info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 681 | return snd_ctl_enum_info(info, 1, 2, names); |
669 | info->count = 1; | ||
670 | info->value.enumerated.items = 2; | ||
671 | if (info->value.enumerated.item >= 2) | ||
672 | info->value.enumerated.item = 1; | ||
673 | strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); | ||
674 | return 0; | ||
675 | } | 682 | } |
676 | 683 | ||
677 | static int rolloff_get(struct snd_kcontrol *ctl, | 684 | static int rolloff_get(struct snd_kcontrol *ctl, |
@@ -719,57 +726,13 @@ static const struct snd_kcontrol_new rolloff_control = { | |||
719 | .put = rolloff_put, | 726 | .put = rolloff_put, |
720 | }; | 727 | }; |
721 | 728 | ||
722 | static int os_128_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) | 729 | static const struct snd_kcontrol_new hdav_hdmi_control = { |
723 | { | ||
724 | static const char *const names[2] = { "64x", "128x" }; | ||
725 | |||
726 | info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
727 | info->count = 1; | ||
728 | info->value.enumerated.items = 2; | ||
729 | if (info->value.enumerated.item >= 2) | ||
730 | info->value.enumerated.item = 1; | ||
731 | strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); | ||
732 | return 0; | ||
733 | } | ||
734 | |||
735 | static int os_128_get(struct snd_kcontrol *ctl, | ||
736 | struct snd_ctl_elem_value *value) | ||
737 | { | ||
738 | struct oxygen *chip = ctl->private_data; | ||
739 | struct xonar_pcm179x *data = chip->model_data; | ||
740 | |||
741 | value->value.enumerated.item[0] = data->os_128; | ||
742 | return 0; | ||
743 | } | ||
744 | |||
745 | static int os_128_put(struct snd_kcontrol *ctl, | ||
746 | struct snd_ctl_elem_value *value) | ||
747 | { | ||
748 | struct oxygen *chip = ctl->private_data; | ||
749 | struct xonar_pcm179x *data = chip->model_data; | ||
750 | int changed; | ||
751 | |||
752 | mutex_lock(&chip->mutex); | ||
753 | changed = value->value.enumerated.item[0] != data->os_128; | ||
754 | if (changed) { | ||
755 | data->os_128 = value->value.enumerated.item[0]; | ||
756 | if (data->has_cs2000) | ||
757 | update_cs2000_rate(chip, data->current_rate); | ||
758 | oxygen_write16_masked(chip, OXYGEN_I2S_MULTICH_FORMAT, | ||
759 | mclk_from_rate(chip, data->current_rate), | ||
760 | OXYGEN_I2S_MCLK_MASK); | ||
761 | update_pcm1796_oversampling(chip); | ||
762 | } | ||
763 | mutex_unlock(&chip->mutex); | ||
764 | return changed; | ||
765 | } | ||
766 | |||
767 | static const struct snd_kcontrol_new os_128_control = { | ||
768 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 730 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
769 | .name = "DAC Oversampling Playback Enum", | 731 | .name = "HDMI Playback Switch", |
770 | .info = os_128_info, | 732 | .info = snd_ctl_boolean_mono_info, |
771 | .get = os_128_get, | 733 | .get = xonar_gpio_bit_switch_get, |
772 | .put = os_128_put, | 734 | .put = xonar_gpio_bit_switch_put, |
735 | .private_value = GPIO_HDAV_OUTPUT_ENABLE | XONAR_GPIO_BIT_INVERT, | ||
773 | }; | 736 | }; |
774 | 737 | ||
775 | static int st_output_switch_info(struct snd_kcontrol *ctl, | 738 | static int st_output_switch_info(struct snd_kcontrol *ctl, |
@@ -779,13 +742,7 @@ static int st_output_switch_info(struct snd_kcontrol *ctl, | |||
779 | "Speakers", "Headphones", "FP Headphones" | 742 | "Speakers", "Headphones", "FP Headphones" |
780 | }; | 743 | }; |
781 | 744 | ||
782 | info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 745 | return snd_ctl_enum_info(info, 1, 3, names); |
783 | info->count = 1; | ||
784 | info->value.enumerated.items = 3; | ||
785 | if (info->value.enumerated.item >= 3) | ||
786 | info->value.enumerated.item = 2; | ||
787 | strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); | ||
788 | return 0; | ||
789 | } | 746 | } |
790 | 747 | ||
791 | static int st_output_switch_get(struct snd_kcontrol *ctl, | 748 | 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, | |||
840 | "< 64 ohms", "64-300 ohms", "300-600 ohms" | 797 | "< 64 ohms", "64-300 ohms", "300-600 ohms" |
841 | }; | 798 | }; |
842 | 799 | ||
843 | info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 800 | return snd_ctl_enum_info(info, 1, 3, names); |
844 | info->count = 1; | ||
845 | info->value.enumerated.items = 3; | ||
846 | if (info->value.enumerated.item > 2) | ||
847 | info->value.enumerated.item = 2; | ||
848 | strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); | ||
849 | return 0; | ||
850 | } | 801 | } |
851 | 802 | ||
852 | static int st_hp_volume_offset_get(struct snd_kcontrol *ctl, | 803 | 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) | |||
928 | return 0; | 879 | return 0; |
929 | } | 880 | } |
930 | 881 | ||
882 | static int xonar_st_h6_control_filter(struct snd_kcontrol_new *template) | ||
883 | { | ||
884 | if (!strncmp(template->name, "Master Playback ", 16)) | ||
885 | /* no volume/mute, as I²C to the third DAC does not work */ | ||
886 | return 1; | ||
887 | return 0; | ||
888 | } | ||
889 | |||
931 | static int add_pcm1796_controls(struct oxygen *chip) | 890 | static int add_pcm1796_controls(struct oxygen *chip) |
932 | { | 891 | { |
892 | struct xonar_pcm179x *data = chip->model_data; | ||
933 | int err; | 893 | int err; |
934 | 894 | ||
935 | err = snd_ctl_add(chip->card, snd_ctl_new1(&rolloff_control, chip)); | 895 | if (!data->broken_i2c) { |
936 | if (err < 0) | 896 | err = snd_ctl_add(chip->card, |
937 | return err; | 897 | snd_ctl_new1(&rolloff_control, chip)); |
938 | err = snd_ctl_add(chip->card, snd_ctl_new1(&os_128_control, chip)); | 898 | if (err < 0) |
939 | if (err < 0) | 899 | return err; |
940 | return err; | 900 | } |
941 | return 0; | 901 | return 0; |
942 | } | 902 | } |
943 | 903 | ||
@@ -956,7 +916,15 @@ static int xonar_d2_mixer_init(struct oxygen *chip) | |||
956 | 916 | ||
957 | static int xonar_hdav_mixer_init(struct oxygen *chip) | 917 | static int xonar_hdav_mixer_init(struct oxygen *chip) |
958 | { | 918 | { |
959 | return add_pcm1796_controls(chip); | 919 | int err; |
920 | |||
921 | err = snd_ctl_add(chip->card, snd_ctl_new1(&hdav_hdmi_control, chip)); | ||
922 | if (err < 0) | ||
923 | return err; | ||
924 | err = add_pcm1796_controls(chip); | ||
925 | if (err < 0) | ||
926 | return err; | ||
927 | return 0; | ||
960 | } | 928 | } |
961 | 929 | ||
962 | static int xonar_st_mixer_init(struct oxygen *chip) | 930 | static int xonar_st_mixer_init(struct oxygen *chip) |
@@ -976,6 +944,45 @@ static int xonar_st_mixer_init(struct oxygen *chip) | |||
976 | return 0; | 944 | return 0; |
977 | } | 945 | } |
978 | 946 | ||
947 | static void dump_pcm1796_registers(struct oxygen *chip, | ||
948 | struct snd_info_buffer *buffer) | ||
949 | { | ||
950 | struct xonar_pcm179x *data = chip->model_data; | ||
951 | unsigned int dac, i; | ||
952 | |||
953 | for (dac = 0; dac < data->dacs; ++dac) { | ||
954 | snd_iprintf(buffer, "\nPCM1796 %u:", dac + 1); | ||
955 | for (i = 0; i < 5; ++i) | ||
956 | snd_iprintf(buffer, " %02x", | ||
957 | data->pcm1796_regs[dac][i]); | ||
958 | } | ||
959 | snd_iprintf(buffer, "\n"); | ||
960 | } | ||
961 | |||
962 | static void dump_cs2000_registers(struct oxygen *chip, | ||
963 | struct snd_info_buffer *buffer) | ||
964 | { | ||
965 | struct xonar_pcm179x *data = chip->model_data; | ||
966 | unsigned int i; | ||
967 | |||
968 | if (data->has_cs2000) { | ||
969 | snd_iprintf(buffer, "\nCS2000:\n00: "); | ||
970 | for (i = 1; i < 0x10; ++i) | ||
971 | snd_iprintf(buffer, " %02x", data->cs2000_regs[i]); | ||
972 | snd_iprintf(buffer, "\n10:"); | ||
973 | for (i = 0x10; i < 0x1f; ++i) | ||
974 | snd_iprintf(buffer, " %02x", data->cs2000_regs[i]); | ||
975 | snd_iprintf(buffer, "\n"); | ||
976 | } | ||
977 | } | ||
978 | |||
979 | static void dump_st_registers(struct oxygen *chip, | ||
980 | struct snd_info_buffer *buffer) | ||
981 | { | ||
982 | dump_pcm1796_registers(chip, buffer); | ||
983 | dump_cs2000_registers(chip, buffer); | ||
984 | } | ||
985 | |||
979 | static const struct oxygen_model model_xonar_d2 = { | 986 | static const struct oxygen_model model_xonar_d2 = { |
980 | .longname = "Asus Virtuoso 200", | 987 | .longname = "Asus Virtuoso 200", |
981 | .chip = "AV200", | 988 | .chip = "AV200", |
@@ -985,11 +992,11 @@ static const struct oxygen_model model_xonar_d2 = { | |||
985 | .cleanup = xonar_d2_cleanup, | 992 | .cleanup = xonar_d2_cleanup, |
986 | .suspend = xonar_d2_suspend, | 993 | .suspend = xonar_d2_suspend, |
987 | .resume = xonar_d2_resume, | 994 | .resume = xonar_d2_resume, |
988 | .get_i2s_mclk = get_pcm1796_i2s_mclk, | ||
989 | .set_dac_params = set_pcm1796_params, | 995 | .set_dac_params = set_pcm1796_params, |
990 | .set_adc_params = xonar_set_cs53x1_params, | 996 | .set_adc_params = xonar_set_cs53x1_params, |
991 | .update_dac_volume = update_pcm1796_volume, | 997 | .update_dac_volume = update_pcm1796_volume, |
992 | .update_dac_mute = update_pcm1796_mute, | 998 | .update_dac_mute = update_pcm1796_mute, |
999 | .dump_registers = dump_pcm1796_registers, | ||
993 | .dac_tlv = pcm1796_db_scale, | 1000 | .dac_tlv = pcm1796_db_scale, |
994 | .model_data_size = sizeof(struct xonar_pcm179x), | 1001 | .model_data_size = sizeof(struct xonar_pcm179x), |
995 | .device_config = PLAYBACK_0_TO_I2S | | 1002 | .device_config = PLAYBACK_0_TO_I2S | |
@@ -999,13 +1006,16 @@ static const struct oxygen_model model_xonar_d2 = { | |||
999 | MIDI_OUTPUT | | 1006 | MIDI_OUTPUT | |
1000 | MIDI_INPUT | | 1007 | MIDI_INPUT | |
1001 | AC97_CD_INPUT, | 1008 | AC97_CD_INPUT, |
1002 | .dac_channels = 8, | 1009 | .dac_channels_pcm = 8, |
1010 | .dac_channels_mixer = 8, | ||
1003 | .dac_volume_min = 255 - 2*60, | 1011 | .dac_volume_min = 255 - 2*60, |
1004 | .dac_volume_max = 255, | 1012 | .dac_volume_max = 255, |
1005 | .misc_flags = OXYGEN_MISC_MIDI, | 1013 | .misc_flags = OXYGEN_MISC_MIDI, |
1006 | .function_flags = OXYGEN_FUNCTION_SPI | | 1014 | .function_flags = OXYGEN_FUNCTION_SPI | |
1007 | OXYGEN_FUNCTION_ENABLE_SPI_4_5, | 1015 | OXYGEN_FUNCTION_ENABLE_SPI_4_5, |
1008 | .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | 1016 | .dac_mclks = OXYGEN_MCLKS(512, 128, 128), |
1017 | .adc_mclks = OXYGEN_MCLKS(256, 128, 128), | ||
1018 | .dac_i2s_format = OXYGEN_I2S_FORMAT_I2S, | ||
1009 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | 1019 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, |
1010 | }; | 1020 | }; |
1011 | 1021 | ||
@@ -1018,25 +1028,28 @@ static const struct oxygen_model model_xonar_hdav = { | |||
1018 | .suspend = xonar_hdav_suspend, | 1028 | .suspend = xonar_hdav_suspend, |
1019 | .resume = xonar_hdav_resume, | 1029 | .resume = xonar_hdav_resume, |
1020 | .pcm_hardware_filter = xonar_hdmi_pcm_hardware_filter, | 1030 | .pcm_hardware_filter = xonar_hdmi_pcm_hardware_filter, |
1021 | .get_i2s_mclk = get_pcm1796_i2s_mclk, | ||
1022 | .set_dac_params = set_hdav_params, | 1031 | .set_dac_params = set_hdav_params, |
1023 | .set_adc_params = xonar_set_cs53x1_params, | 1032 | .set_adc_params = xonar_set_cs53x1_params, |
1024 | .update_dac_volume = update_pcm1796_volume, | 1033 | .update_dac_volume = update_pcm1796_volume, |
1025 | .update_dac_mute = update_pcm1796_mute, | 1034 | .update_dac_mute = update_pcm1796_mute, |
1026 | .uart_input = xonar_hdmi_uart_input, | 1035 | .uart_input = xonar_hdmi_uart_input, |
1027 | .ac97_switch = xonar_line_mic_ac97_switch, | 1036 | .ac97_switch = xonar_line_mic_ac97_switch, |
1037 | .dump_registers = dump_pcm1796_registers, | ||
1028 | .dac_tlv = pcm1796_db_scale, | 1038 | .dac_tlv = pcm1796_db_scale, |
1029 | .model_data_size = sizeof(struct xonar_hdav), | 1039 | .model_data_size = sizeof(struct xonar_hdav), |
1030 | .device_config = PLAYBACK_0_TO_I2S | | 1040 | .device_config = PLAYBACK_0_TO_I2S | |
1031 | PLAYBACK_1_TO_SPDIF | | 1041 | PLAYBACK_1_TO_SPDIF | |
1032 | CAPTURE_0_FROM_I2S_2 | | 1042 | CAPTURE_0_FROM_I2S_2 | |
1033 | CAPTURE_1_FROM_SPDIF, | 1043 | CAPTURE_1_FROM_SPDIF, |
1034 | .dac_channels = 8, | 1044 | .dac_channels_pcm = 8, |
1045 | .dac_channels_mixer = 2, | ||
1035 | .dac_volume_min = 255 - 2*60, | 1046 | .dac_volume_min = 255 - 2*60, |
1036 | .dac_volume_max = 255, | 1047 | .dac_volume_max = 255, |
1037 | .misc_flags = OXYGEN_MISC_MIDI, | 1048 | .misc_flags = OXYGEN_MISC_MIDI, |
1038 | .function_flags = OXYGEN_FUNCTION_2WIRE, | 1049 | .function_flags = OXYGEN_FUNCTION_2WIRE, |
1039 | .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | 1050 | .dac_mclks = OXYGEN_MCLKS(512, 128, 128), |
1051 | .adc_mclks = OXYGEN_MCLKS(256, 128, 128), | ||
1052 | .dac_i2s_format = OXYGEN_I2S_FORMAT_I2S, | ||
1040 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | 1053 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, |
1041 | }; | 1054 | }; |
1042 | 1055 | ||
@@ -1048,22 +1061,26 @@ static const struct oxygen_model model_xonar_st = { | |||
1048 | .cleanup = xonar_st_cleanup, | 1061 | .cleanup = xonar_st_cleanup, |
1049 | .suspend = xonar_st_suspend, | 1062 | .suspend = xonar_st_suspend, |
1050 | .resume = xonar_st_resume, | 1063 | .resume = xonar_st_resume, |
1051 | .get_i2s_mclk = get_pcm1796_i2s_mclk, | ||
1052 | .set_dac_params = set_st_params, | 1064 | .set_dac_params = set_st_params, |
1053 | .set_adc_params = xonar_set_cs53x1_params, | 1065 | .set_adc_params = xonar_set_cs53x1_params, |
1054 | .update_dac_volume = update_pcm1796_volume, | 1066 | .update_dac_volume = update_pcm1796_volume, |
1055 | .update_dac_mute = update_pcm1796_mute, | 1067 | .update_dac_mute = update_pcm1796_mute, |
1056 | .ac97_switch = xonar_line_mic_ac97_switch, | 1068 | .ac97_switch = xonar_line_mic_ac97_switch, |
1069 | .dump_registers = dump_st_registers, | ||
1057 | .dac_tlv = pcm1796_db_scale, | 1070 | .dac_tlv = pcm1796_db_scale, |
1058 | .model_data_size = sizeof(struct xonar_pcm179x), | 1071 | .model_data_size = sizeof(struct xonar_pcm179x), |
1059 | .device_config = PLAYBACK_0_TO_I2S | | 1072 | .device_config = PLAYBACK_0_TO_I2S | |
1060 | PLAYBACK_1_TO_SPDIF | | 1073 | PLAYBACK_1_TO_SPDIF | |
1061 | CAPTURE_0_FROM_I2S_2, | 1074 | CAPTURE_0_FROM_I2S_2 | |
1062 | .dac_channels = 2, | 1075 | AC97_FMIC_SWITCH, |
1076 | .dac_channels_pcm = 2, | ||
1077 | .dac_channels_mixer = 2, | ||
1063 | .dac_volume_min = 255 - 2*60, | 1078 | .dac_volume_min = 255 - 2*60, |
1064 | .dac_volume_max = 255, | 1079 | .dac_volume_max = 255, |
1065 | .function_flags = OXYGEN_FUNCTION_2WIRE, | 1080 | .function_flags = OXYGEN_FUNCTION_2WIRE, |
1066 | .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | 1081 | .dac_mclks = OXYGEN_MCLKS(512, 128, 128), |
1082 | .adc_mclks = OXYGEN_MCLKS(256, 128, 128), | ||
1083 | .dac_i2s_format = OXYGEN_I2S_FORMAT_I2S, | ||
1067 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | 1084 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, |
1068 | }; | 1085 | }; |
1069 | 1086 | ||
@@ -1089,7 +1106,8 @@ int __devinit get_xonar_pcm179x_model(struct oxygen *chip, | |||
1089 | break; | 1106 | break; |
1090 | case GPIO_DB_H6: | 1107 | case GPIO_DB_H6: |
1091 | chip->model.shortname = "Xonar HDAV1.3+H6"; | 1108 | chip->model.shortname = "Xonar HDAV1.3+H6"; |
1092 | chip->model.private_data = 1; | 1109 | chip->model.dac_channels_mixer = 8; |
1110 | chip->model.dac_mclks = OXYGEN_MCLKS(256, 128, 128); | ||
1093 | break; | 1111 | break; |
1094 | } | 1112 | } |
1095 | break; | 1113 | break; |
@@ -1102,8 +1120,10 @@ int __devinit get_xonar_pcm179x_model(struct oxygen *chip, | |||
1102 | break; | 1120 | break; |
1103 | case GPIO_DB_H6: | 1121 | case GPIO_DB_H6: |
1104 | chip->model.shortname = "Xonar ST+H6"; | 1122 | chip->model.shortname = "Xonar ST+H6"; |
1105 | chip->model.dac_channels = 8; | 1123 | chip->model.control_filter = xonar_st_h6_control_filter; |
1106 | chip->model.private_data = 1; | 1124 | chip->model.dac_channels_pcm = 8; |
1125 | chip->model.dac_channels_mixer = 8; | ||
1126 | chip->model.dac_mclks = OXYGEN_MCLKS(256, 128, 128); | ||
1107 | break; | 1127 | break; |
1108 | } | 1128 | } |
1109 | break; | 1129 | break; |
@@ -1114,9 +1134,6 @@ int __devinit get_xonar_pcm179x_model(struct oxygen *chip, | |||
1114 | chip->model.resume = xonar_stx_resume; | 1134 | chip->model.resume = xonar_stx_resume; |
1115 | chip->model.set_dac_params = set_pcm1796_params; | 1135 | chip->model.set_dac_params = set_pcm1796_params; |
1116 | break; | 1136 | break; |
1117 | case 0x835e: | ||
1118 | snd_printk(KERN_ERR "the HDAV1.3 Slim is not supported\n"); | ||
1119 | return -ENODEV; | ||
1120 | default: | 1137 | default: |
1121 | return -EINVAL; | 1138 | return -EINVAL; |
1122 | } | 1139 | } |
diff --git a/sound/pci/oxygen/xonar_wm87x6.c b/sound/pci/oxygen/xonar_wm87x6.c index 200f7601276f..42d1ab136217 100644 --- a/sound/pci/oxygen/xonar_wm87x6.c +++ b/sound/pci/oxygen/xonar_wm87x6.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * card driver for models with WM8776/WM8766 DACs (Xonar DS) | 2 | * card driver for models with WM8776/WM8766 DACs (Xonar DS/HDAV1.3 Slim) |
3 | * | 3 | * |
4 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> | 4 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> |
5 | * | 5 | * |
@@ -22,26 +22,48 @@ | |||
22 | * | 22 | * |
23 | * CMI8788: | 23 | * CMI8788: |
24 | * | 24 | * |
25 | * SPI 0 -> WM8766 (surround, center/LFE, back) | 25 | * SPI 0 -> WM8766 (surround, center/LFE, back) |
26 | * SPI 1 -> WM8776 (front, input) | 26 | * SPI 1 -> WM8776 (front, input) |
27 | * | 27 | * |
28 | * GPIO 4 <- headphone detect, 0 = plugged | 28 | * GPIO 4 <- headphone detect, 0 = plugged |
29 | * GPIO 6 -> route input jack to mic-in (0) or line-in (1) | 29 | * GPIO 6 -> route input jack to mic-in (0) or line-in (1) |
30 | * GPIO 7 -> enable output to front L/R speaker channels | 30 | * GPIO 7 -> enable output to front L/R speaker channels |
31 | * GPIO 8 -> enable output to other speaker channels and front panel headphone | 31 | * GPIO 8 -> enable output to other speaker channels and front panel headphone |
32 | * | 32 | * |
33 | * WM8766: | 33 | * WM8776: |
34 | * | 34 | * |
35 | * input 1 <- line | 35 | * input 1 <- line |
36 | * input 2 <- mic | 36 | * input 2 <- mic |
37 | * input 3 <- front mic | 37 | * input 3 <- front mic |
38 | * input 4 <- aux | 38 | * input 4 <- aux |
39 | */ | ||
40 | |||
41 | /* | ||
42 | * Xonar HDAV1.3 Slim | ||
43 | * ------------------ | ||
44 | * | ||
45 | * CMI8788: | ||
46 | * | ||
47 | * I²C <-> WM8776 (addr 0011010) | ||
48 | * | ||
49 | * GPIO 0 -> disable HDMI output | ||
50 | * GPIO 1 -> enable HP output | ||
51 | * GPIO 6 -> firmware EEPROM I²C clock | ||
52 | * GPIO 7 <-> firmware EEPROM I²C data | ||
53 | * | ||
54 | * UART <-> HDMI controller | ||
55 | * | ||
56 | * WM8776: | ||
57 | * | ||
58 | * input 1 <- mic | ||
59 | * input 2 <- aux | ||
39 | */ | 60 | */ |
40 | 61 | ||
41 | #include <linux/pci.h> | 62 | #include <linux/pci.h> |
42 | #include <linux/delay.h> | 63 | #include <linux/delay.h> |
43 | #include <sound/control.h> | 64 | #include <sound/control.h> |
44 | #include <sound/core.h> | 65 | #include <sound/core.h> |
66 | #include <sound/info.h> | ||
45 | #include <sound/jack.h> | 67 | #include <sound/jack.h> |
46 | #include <sound/pcm.h> | 68 | #include <sound/pcm.h> |
47 | #include <sound/pcm_params.h> | 69 | #include <sound/pcm_params.h> |
@@ -55,6 +77,13 @@ | |||
55 | #define GPIO_DS_OUTPUT_FRONTLR 0x0080 | 77 | #define GPIO_DS_OUTPUT_FRONTLR 0x0080 |
56 | #define GPIO_DS_OUTPUT_ENABLE 0x0100 | 78 | #define GPIO_DS_OUTPUT_ENABLE 0x0100 |
57 | 79 | ||
80 | #define GPIO_SLIM_HDMI_DISABLE 0x0001 | ||
81 | #define GPIO_SLIM_OUTPUT_ENABLE 0x0002 | ||
82 | #define GPIO_SLIM_FIRMWARE_CLK 0x0040 | ||
83 | #define GPIO_SLIM_FIRMWARE_DATA 0x0080 | ||
84 | |||
85 | #define I2C_DEVICE_WM8776 0x34 /* 001101, 0, /W=0 */ | ||
86 | |||
58 | #define LC_CONTROL_LIMITER 0x40000000 | 87 | #define LC_CONTROL_LIMITER 0x40000000 |
59 | #define LC_CONTROL_ALC 0x20000000 | 88 | #define LC_CONTROL_ALC 0x20000000 |
60 | 89 | ||
@@ -66,19 +95,37 @@ struct xonar_wm87x6 { | |||
66 | struct snd_kcontrol *mic_adcmux_control; | 95 | struct snd_kcontrol *mic_adcmux_control; |
67 | struct snd_kcontrol *lc_controls[13]; | 96 | struct snd_kcontrol *lc_controls[13]; |
68 | struct snd_jack *hp_jack; | 97 | struct snd_jack *hp_jack; |
98 | struct xonar_hdmi hdmi; | ||
69 | }; | 99 | }; |
70 | 100 | ||
71 | static void wm8776_write(struct oxygen *chip, | 101 | static void wm8776_write_spi(struct oxygen *chip, |
72 | unsigned int reg, unsigned int value) | 102 | unsigned int reg, unsigned int value) |
73 | { | 103 | { |
74 | struct xonar_wm87x6 *data = chip->model_data; | ||
75 | |||
76 | oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER | | 104 | oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER | |
77 | OXYGEN_SPI_DATA_LENGTH_2 | | 105 | OXYGEN_SPI_DATA_LENGTH_2 | |
78 | OXYGEN_SPI_CLOCK_160 | | 106 | OXYGEN_SPI_CLOCK_160 | |
79 | (1 << OXYGEN_SPI_CODEC_SHIFT) | | 107 | (1 << OXYGEN_SPI_CODEC_SHIFT) | |
80 | OXYGEN_SPI_CEN_LATCH_CLOCK_LO, | 108 | OXYGEN_SPI_CEN_LATCH_CLOCK_LO, |
81 | (reg << 9) | value); | 109 | (reg << 9) | value); |
110 | } | ||
111 | |||
112 | static void wm8776_write_i2c(struct oxygen *chip, | ||
113 | unsigned int reg, unsigned int value) | ||
114 | { | ||
115 | oxygen_write_i2c(chip, I2C_DEVICE_WM8776, | ||
116 | (reg << 1) | (value >> 8), value); | ||
117 | } | ||
118 | |||
119 | static void wm8776_write(struct oxygen *chip, | ||
120 | unsigned int reg, unsigned int value) | ||
121 | { | ||
122 | struct xonar_wm87x6 *data = chip->model_data; | ||
123 | |||
124 | if ((chip->model.function_flags & OXYGEN_FUNCTION_2WIRE_SPI_MASK) == | ||
125 | OXYGEN_FUNCTION_SPI) | ||
126 | wm8776_write_spi(chip, reg, value); | ||
127 | else | ||
128 | wm8776_write_i2c(chip, reg, value); | ||
82 | if (reg < ARRAY_SIZE(data->wm8776_regs)) { | 129 | if (reg < ARRAY_SIZE(data->wm8776_regs)) { |
83 | if (reg >= WM8776_HPLVOL && reg <= WM8776_DACMASTER) | 130 | if (reg >= WM8776_HPLVOL && reg <= WM8776_DACMASTER) |
84 | value &= ~WM8776_UPDATE; | 131 | value &= ~WM8776_UPDATE; |
@@ -245,17 +292,50 @@ static void xonar_ds_init(struct oxygen *chip) | |||
245 | snd_component_add(chip->card, "WM8766"); | 292 | snd_component_add(chip->card, "WM8766"); |
246 | } | 293 | } |
247 | 294 | ||
295 | static void xonar_hdav_slim_init(struct oxygen *chip) | ||
296 | { | ||
297 | struct xonar_wm87x6 *data = chip->model_data; | ||
298 | |||
299 | data->generic.anti_pop_delay = 300; | ||
300 | data->generic.output_enable_bit = GPIO_SLIM_OUTPUT_ENABLE; | ||
301 | |||
302 | wm8776_init(chip); | ||
303 | |||
304 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, | ||
305 | GPIO_SLIM_HDMI_DISABLE | | ||
306 | GPIO_SLIM_FIRMWARE_CLK | | ||
307 | GPIO_SLIM_FIRMWARE_DATA); | ||
308 | |||
309 | xonar_hdmi_init(chip, &data->hdmi); | ||
310 | xonar_enable_output(chip); | ||
311 | |||
312 | snd_component_add(chip->card, "WM8776"); | ||
313 | } | ||
314 | |||
248 | static void xonar_ds_cleanup(struct oxygen *chip) | 315 | static void xonar_ds_cleanup(struct oxygen *chip) |
249 | { | 316 | { |
250 | xonar_disable_output(chip); | 317 | xonar_disable_output(chip); |
251 | wm8776_write(chip, WM8776_RESET, 0); | 318 | wm8776_write(chip, WM8776_RESET, 0); |
252 | } | 319 | } |
253 | 320 | ||
321 | static void xonar_hdav_slim_cleanup(struct oxygen *chip) | ||
322 | { | ||
323 | xonar_hdmi_cleanup(chip); | ||
324 | xonar_disable_output(chip); | ||
325 | wm8776_write(chip, WM8776_RESET, 0); | ||
326 | msleep(2); | ||
327 | } | ||
328 | |||
254 | static void xonar_ds_suspend(struct oxygen *chip) | 329 | static void xonar_ds_suspend(struct oxygen *chip) |
255 | { | 330 | { |
256 | xonar_ds_cleanup(chip); | 331 | xonar_ds_cleanup(chip); |
257 | } | 332 | } |
258 | 333 | ||
334 | static void xonar_hdav_slim_suspend(struct oxygen *chip) | ||
335 | { | ||
336 | xonar_hdav_slim_cleanup(chip); | ||
337 | } | ||
338 | |||
259 | static void xonar_ds_resume(struct oxygen *chip) | 339 | static void xonar_ds_resume(struct oxygen *chip) |
260 | { | 340 | { |
261 | wm8776_registers_init(chip); | 341 | wm8776_registers_init(chip); |
@@ -264,6 +344,15 @@ static void xonar_ds_resume(struct oxygen *chip) | |||
264 | xonar_ds_handle_hp_jack(chip); | 344 | xonar_ds_handle_hp_jack(chip); |
265 | } | 345 | } |
266 | 346 | ||
347 | static void xonar_hdav_slim_resume(struct oxygen *chip) | ||
348 | { | ||
349 | struct xonar_wm87x6 *data = chip->model_data; | ||
350 | |||
351 | wm8776_registers_init(chip); | ||
352 | xonar_hdmi_resume(chip, &data->hdmi); | ||
353 | xonar_enable_output(chip); | ||
354 | } | ||
355 | |||
267 | static void wm8776_adc_hardware_filter(unsigned int channel, | 356 | static void wm8776_adc_hardware_filter(unsigned int channel, |
268 | struct snd_pcm_hardware *hardware) | 357 | struct snd_pcm_hardware *hardware) |
269 | { | 358 | { |
@@ -278,6 +367,13 @@ static void wm8776_adc_hardware_filter(unsigned int channel, | |||
278 | } | 367 | } |
279 | } | 368 | } |
280 | 369 | ||
370 | static void xonar_hdav_slim_hardware_filter(unsigned int channel, | ||
371 | struct snd_pcm_hardware *hardware) | ||
372 | { | ||
373 | wm8776_adc_hardware_filter(channel, hardware); | ||
374 | xonar_hdmi_pcm_hardware_filter(channel, hardware); | ||
375 | } | ||
376 | |||
281 | static void set_wm87x6_dac_params(struct oxygen *chip, | 377 | static void set_wm87x6_dac_params(struct oxygen *chip, |
282 | struct snd_pcm_hw_params *params) | 378 | struct snd_pcm_hw_params *params) |
283 | { | 379 | { |
@@ -294,6 +390,14 @@ static void set_wm8776_adc_params(struct oxygen *chip, | |||
294 | wm8776_write_cached(chip, WM8776_MSTRCTRL, reg); | 390 | wm8776_write_cached(chip, WM8776_MSTRCTRL, reg); |
295 | } | 391 | } |
296 | 392 | ||
393 | static void set_hdav_slim_dac_params(struct oxygen *chip, | ||
394 | struct snd_pcm_hw_params *params) | ||
395 | { | ||
396 | struct xonar_wm87x6 *data = chip->model_data; | ||
397 | |||
398 | xonar_set_hdmi_params(chip, &data->hdmi, params); | ||
399 | } | ||
400 | |||
297 | static void update_wm8776_volume(struct oxygen *chip) | 401 | static void update_wm8776_volume(struct oxygen *chip) |
298 | { | 402 | { |
299 | struct xonar_wm87x6 *data = chip->model_data; | 403 | struct xonar_wm87x6 *data = chip->model_data; |
@@ -473,11 +577,6 @@ static int wm8776_field_enum_info(struct snd_kcontrol *ctl, | |||
473 | const char *const *names; | 577 | const char *const *names; |
474 | 578 | ||
475 | max = (ctl->private_value >> 12) & 0xf; | 579 | max = (ctl->private_value >> 12) & 0xf; |
476 | info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
477 | info->count = 1; | ||
478 | info->value.enumerated.items = max + 1; | ||
479 | if (info->value.enumerated.item > max) | ||
480 | info->value.enumerated.item = max; | ||
481 | switch ((ctl->private_value >> 24) & 0x1f) { | 580 | switch ((ctl->private_value >> 24) & 0x1f) { |
482 | case WM8776_ALCCTRL2: | 581 | case WM8776_ALCCTRL2: |
483 | names = hld; | 582 | names = hld; |
@@ -501,8 +600,7 @@ static int wm8776_field_enum_info(struct snd_kcontrol *ctl, | |||
501 | default: | 600 | default: |
502 | return -ENXIO; | 601 | return -ENXIO; |
503 | } | 602 | } |
504 | strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); | 603 | return snd_ctl_enum_info(info, 1, max + 1, names); |
505 | return 0; | ||
506 | } | 604 | } |
507 | 605 | ||
508 | static int wm8776_field_volume_info(struct snd_kcontrol *ctl, | 606 | static int wm8776_field_volume_info(struct snd_kcontrol *ctl, |
@@ -759,13 +857,8 @@ static int wm8776_level_control_info(struct snd_kcontrol *ctl, | |||
759 | static const char *const names[3] = { | 857 | static const char *const names[3] = { |
760 | "None", "Peak Limiter", "Automatic Level Control" | 858 | "None", "Peak Limiter", "Automatic Level Control" |
761 | }; | 859 | }; |
762 | info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 860 | |
763 | info->count = 1; | 861 | return snd_ctl_enum_info(info, 1, 3, names); |
764 | info->value.enumerated.items = 3; | ||
765 | if (info->value.enumerated.item >= 3) | ||
766 | info->value.enumerated.item = 2; | ||
767 | strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); | ||
768 | return 0; | ||
769 | } | 862 | } |
770 | 863 | ||
771 | static int wm8776_level_control_get(struct snd_kcontrol *ctl, | 864 | 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) | |||
851 | "None", "High-pass Filter" | 944 | "None", "High-pass Filter" |
852 | }; | 945 | }; |
853 | 946 | ||
854 | info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 947 | return snd_ctl_enum_info(info, 1, 2, names); |
855 | info->count = 1; | ||
856 | info->value.enumerated.items = 2; | ||
857 | if (info->value.enumerated.item >= 2) | ||
858 | info->value.enumerated.item = 1; | ||
859 | strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); | ||
860 | return 0; | ||
861 | } | 948 | } |
862 | 949 | ||
863 | static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) | 950 | 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[] = { | |||
985 | .private_value = 0, | 1072 | .private_value = 0, |
986 | }, | 1073 | }, |
987 | }; | 1074 | }; |
1075 | static const struct snd_kcontrol_new hdav_slim_controls[] = { | ||
1076 | { | ||
1077 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1078 | .name = "HDMI Playback Switch", | ||
1079 | .info = snd_ctl_boolean_mono_info, | ||
1080 | .get = xonar_gpio_bit_switch_get, | ||
1081 | .put = xonar_gpio_bit_switch_put, | ||
1082 | .private_value = GPIO_SLIM_HDMI_DISABLE | XONAR_GPIO_BIT_INVERT, | ||
1083 | }, | ||
1084 | { | ||
1085 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1086 | .name = "Headphone Playback Volume", | ||
1087 | .info = wm8776_hp_vol_info, | ||
1088 | .get = wm8776_hp_vol_get, | ||
1089 | .put = wm8776_hp_vol_put, | ||
1090 | .tlv = { .p = wm8776_hp_db_scale }, | ||
1091 | }, | ||
1092 | WM8776_BIT_SWITCH("Headphone Playback Switch", | ||
1093 | WM8776_PWRDOWN, WM8776_HPPD, 1, 0), | ||
1094 | { | ||
1095 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1096 | .name = "Input Capture Volume", | ||
1097 | .info = wm8776_input_vol_info, | ||
1098 | .get = wm8776_input_vol_get, | ||
1099 | .put = wm8776_input_vol_put, | ||
1100 | .tlv = { .p = wm8776_adc_db_scale }, | ||
1101 | }, | ||
1102 | WM8776_BIT_SWITCH("Mic Capture Switch", | ||
1103 | WM8776_ADCMUX, 1 << 0, 0, 0), | ||
1104 | WM8776_BIT_SWITCH("Aux Capture Switch", | ||
1105 | WM8776_ADCMUX, 1 << 1, 0, 0), | ||
1106 | { | ||
1107 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1108 | .name = "ADC Filter Capture Enum", | ||
1109 | .info = hpf_info, | ||
1110 | .get = hpf_get, | ||
1111 | .put = hpf_put, | ||
1112 | }, | ||
1113 | { | ||
1114 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1115 | .name = "Level Control Capture Enum", | ||
1116 | .info = wm8776_level_control_info, | ||
1117 | .get = wm8776_level_control_get, | ||
1118 | .put = wm8776_level_control_put, | ||
1119 | .private_value = 0, | ||
1120 | }, | ||
1121 | }; | ||
988 | static const struct snd_kcontrol_new lc_controls[] = { | 1122 | static const struct snd_kcontrol_new lc_controls[] = { |
989 | WM8776_FIELD_CTL_VOLUME("Limiter Threshold", | 1123 | WM8776_FIELD_CTL_VOLUME("Limiter Threshold", |
990 | WM8776_ALCCTRL1, 0, 11, 0, 15, 0xf, | 1124 | WM8776_ALCCTRL1, 0, 11, 0, 15, 0xf, |
@@ -1028,6 +1162,26 @@ static const struct snd_kcontrol_new lc_controls[] = { | |||
1028 | LC_CONTROL_ALC, wm8776_ngth_db_scale), | 1162 | LC_CONTROL_ALC, wm8776_ngth_db_scale), |
1029 | }; | 1163 | }; |
1030 | 1164 | ||
1165 | static int add_lc_controls(struct oxygen *chip) | ||
1166 | { | ||
1167 | struct xonar_wm87x6 *data = chip->model_data; | ||
1168 | unsigned int i; | ||
1169 | struct snd_kcontrol *ctl; | ||
1170 | int err; | ||
1171 | |||
1172 | BUILD_BUG_ON(ARRAY_SIZE(lc_controls) != ARRAY_SIZE(data->lc_controls)); | ||
1173 | for (i = 0; i < ARRAY_SIZE(lc_controls); ++i) { | ||
1174 | ctl = snd_ctl_new1(&lc_controls[i], chip); | ||
1175 | if (!ctl) | ||
1176 | return -ENOMEM; | ||
1177 | err = snd_ctl_add(chip->card, ctl); | ||
1178 | if (err < 0) | ||
1179 | return err; | ||
1180 | data->lc_controls[i] = ctl; | ||
1181 | } | ||
1182 | return 0; | ||
1183 | } | ||
1184 | |||
1031 | static int xonar_ds_mixer_init(struct oxygen *chip) | 1185 | static int xonar_ds_mixer_init(struct oxygen *chip) |
1032 | { | 1186 | { |
1033 | struct xonar_wm87x6 *data = chip->model_data; | 1187 | struct xonar_wm87x6 *data = chip->model_data; |
@@ -1049,17 +1203,54 @@ static int xonar_ds_mixer_init(struct oxygen *chip) | |||
1049 | } | 1203 | } |
1050 | if (!data->line_adcmux_control || !data->mic_adcmux_control) | 1204 | if (!data->line_adcmux_control || !data->mic_adcmux_control) |
1051 | return -ENXIO; | 1205 | return -ENXIO; |
1052 | BUILD_BUG_ON(ARRAY_SIZE(lc_controls) != ARRAY_SIZE(data->lc_controls)); | 1206 | |
1053 | for (i = 0; i < ARRAY_SIZE(lc_controls); ++i) { | 1207 | return add_lc_controls(chip); |
1054 | ctl = snd_ctl_new1(&lc_controls[i], chip); | 1208 | } |
1209 | |||
1210 | static int xonar_hdav_slim_mixer_init(struct oxygen *chip) | ||
1211 | { | ||
1212 | unsigned int i; | ||
1213 | struct snd_kcontrol *ctl; | ||
1214 | int err; | ||
1215 | |||
1216 | for (i = 0; i < ARRAY_SIZE(hdav_slim_controls); ++i) { | ||
1217 | ctl = snd_ctl_new1(&hdav_slim_controls[i], chip); | ||
1055 | if (!ctl) | 1218 | if (!ctl) |
1056 | return -ENOMEM; | 1219 | return -ENOMEM; |
1057 | err = snd_ctl_add(chip->card, ctl); | 1220 | err = snd_ctl_add(chip->card, ctl); |
1058 | if (err < 0) | 1221 | if (err < 0) |
1059 | return err; | 1222 | return err; |
1060 | data->lc_controls[i] = ctl; | ||
1061 | } | 1223 | } |
1062 | return 0; | 1224 | |
1225 | return add_lc_controls(chip); | ||
1226 | } | ||
1227 | |||
1228 | static void dump_wm8776_registers(struct oxygen *chip, | ||
1229 | struct snd_info_buffer *buffer) | ||
1230 | { | ||
1231 | struct xonar_wm87x6 *data = chip->model_data; | ||
1232 | unsigned int i; | ||
1233 | |||
1234 | snd_iprintf(buffer, "\nWM8776:\n00:"); | ||
1235 | for (i = 0; i < 0x10; ++i) | ||
1236 | snd_iprintf(buffer, " %03x", data->wm8776_regs[i]); | ||
1237 | snd_iprintf(buffer, "\n10:"); | ||
1238 | for (i = 0x10; i < 0x17; ++i) | ||
1239 | snd_iprintf(buffer, " %03x", data->wm8776_regs[i]); | ||
1240 | snd_iprintf(buffer, "\n"); | ||
1241 | } | ||
1242 | |||
1243 | static void dump_wm87x6_registers(struct oxygen *chip, | ||
1244 | struct snd_info_buffer *buffer) | ||
1245 | { | ||
1246 | struct xonar_wm87x6 *data = chip->model_data; | ||
1247 | unsigned int i; | ||
1248 | |||
1249 | dump_wm8776_registers(chip, buffer); | ||
1250 | snd_iprintf(buffer, "\nWM8766:\n00:"); | ||
1251 | for (i = 0; i < 0x10; ++i) | ||
1252 | snd_iprintf(buffer, " %03x", data->wm8766_regs[i]); | ||
1253 | snd_iprintf(buffer, "\n"); | ||
1063 | } | 1254 | } |
1064 | 1255 | ||
1065 | static const struct oxygen_model model_xonar_ds = { | 1256 | static const struct oxygen_model model_xonar_ds = { |
@@ -1072,22 +1263,57 @@ static const struct oxygen_model model_xonar_ds = { | |||
1072 | .suspend = xonar_ds_suspend, | 1263 | .suspend = xonar_ds_suspend, |
1073 | .resume = xonar_ds_resume, | 1264 | .resume = xonar_ds_resume, |
1074 | .pcm_hardware_filter = wm8776_adc_hardware_filter, | 1265 | .pcm_hardware_filter = wm8776_adc_hardware_filter, |
1075 | .get_i2s_mclk = oxygen_default_i2s_mclk, | ||
1076 | .set_dac_params = set_wm87x6_dac_params, | 1266 | .set_dac_params = set_wm87x6_dac_params, |
1077 | .set_adc_params = set_wm8776_adc_params, | 1267 | .set_adc_params = set_wm8776_adc_params, |
1078 | .update_dac_volume = update_wm87x6_volume, | 1268 | .update_dac_volume = update_wm87x6_volume, |
1079 | .update_dac_mute = update_wm87x6_mute, | 1269 | .update_dac_mute = update_wm87x6_mute, |
1080 | .update_center_lfe_mix = update_wm8766_center_lfe_mix, | 1270 | .update_center_lfe_mix = update_wm8766_center_lfe_mix, |
1081 | .gpio_changed = xonar_ds_gpio_changed, | 1271 | .gpio_changed = xonar_ds_gpio_changed, |
1272 | .dump_registers = dump_wm87x6_registers, | ||
1082 | .dac_tlv = wm87x6_dac_db_scale, | 1273 | .dac_tlv = wm87x6_dac_db_scale, |
1083 | .model_data_size = sizeof(struct xonar_wm87x6), | 1274 | .model_data_size = sizeof(struct xonar_wm87x6), |
1084 | .device_config = PLAYBACK_0_TO_I2S | | 1275 | .device_config = PLAYBACK_0_TO_I2S | |
1085 | PLAYBACK_1_TO_SPDIF | | 1276 | PLAYBACK_1_TO_SPDIF | |
1086 | CAPTURE_0_FROM_I2S_1, | 1277 | CAPTURE_0_FROM_I2S_1, |
1087 | .dac_channels = 8, | 1278 | .dac_channels_pcm = 8, |
1279 | .dac_channels_mixer = 8, | ||
1088 | .dac_volume_min = 255 - 2*60, | 1280 | .dac_volume_min = 255 - 2*60, |
1089 | .dac_volume_max = 255, | 1281 | .dac_volume_max = 255, |
1090 | .function_flags = OXYGEN_FUNCTION_SPI, | 1282 | .function_flags = OXYGEN_FUNCTION_SPI, |
1283 | .dac_mclks = OXYGEN_MCLKS(256, 256, 128), | ||
1284 | .adc_mclks = OXYGEN_MCLKS(256, 256, 128), | ||
1285 | .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | ||
1286 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | ||
1287 | }; | ||
1288 | |||
1289 | static const struct oxygen_model model_xonar_hdav_slim = { | ||
1290 | .shortname = "Xonar HDAV1.3 Slim", | ||
1291 | .longname = "Asus Virtuoso 200", | ||
1292 | .chip = "AV200", | ||
1293 | .init = xonar_hdav_slim_init, | ||
1294 | .mixer_init = xonar_hdav_slim_mixer_init, | ||
1295 | .cleanup = xonar_hdav_slim_cleanup, | ||
1296 | .suspend = xonar_hdav_slim_suspend, | ||
1297 | .resume = xonar_hdav_slim_resume, | ||
1298 | .pcm_hardware_filter = xonar_hdav_slim_hardware_filter, | ||
1299 | .set_dac_params = set_hdav_slim_dac_params, | ||
1300 | .set_adc_params = set_wm8776_adc_params, | ||
1301 | .update_dac_volume = update_wm8776_volume, | ||
1302 | .update_dac_mute = update_wm8776_mute, | ||
1303 | .uart_input = xonar_hdmi_uart_input, | ||
1304 | .dump_registers = dump_wm8776_registers, | ||
1305 | .dac_tlv = wm87x6_dac_db_scale, | ||
1306 | .model_data_size = sizeof(struct xonar_wm87x6), | ||
1307 | .device_config = PLAYBACK_0_TO_I2S | | ||
1308 | PLAYBACK_1_TO_SPDIF | | ||
1309 | CAPTURE_0_FROM_I2S_1, | ||
1310 | .dac_channels_pcm = 8, | ||
1311 | .dac_channels_mixer = 2, | ||
1312 | .dac_volume_min = 255 - 2*60, | ||
1313 | .dac_volume_max = 255, | ||
1314 | .function_flags = OXYGEN_FUNCTION_2WIRE, | ||
1315 | .dac_mclks = OXYGEN_MCLKS(256, 256, 128), | ||
1316 | .adc_mclks = OXYGEN_MCLKS(256, 256, 128), | ||
1091 | .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | 1317 | .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, |
1092 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | 1318 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, |
1093 | }; | 1319 | }; |
@@ -1099,6 +1325,9 @@ int __devinit get_xonar_wm87x6_model(struct oxygen *chip, | |||
1099 | case 0x838e: | 1325 | case 0x838e: |
1100 | chip->model = model_xonar_ds; | 1326 | chip->model = model_xonar_ds; |
1101 | break; | 1327 | break; |
1328 | case 0x835e: | ||
1329 | chip->model = model_xonar_hdav_slim; | ||
1330 | break; | ||
1102 | default: | 1331 | default: |
1103 | return -EINVAL; | 1332 | return -EINVAL; |
1104 | } | 1333 | } |
diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index 0b720cf7783e..2d8332416c83 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c | |||
@@ -60,6 +60,7 @@ MODULE_SUPPORTED_DEVICE("{{RME Hammerfall-DSP}," | |||
60 | "{RME HDSP-9652}," | 60 | "{RME HDSP-9652}," |
61 | "{RME HDSP-9632}}"); | 61 | "{RME HDSP-9632}}"); |
62 | #ifdef HDSP_FW_LOADER | 62 | #ifdef HDSP_FW_LOADER |
63 | MODULE_FIRMWARE("rpm_firmware.bin"); | ||
63 | MODULE_FIRMWARE("multiface_firmware.bin"); | 64 | MODULE_FIRMWARE("multiface_firmware.bin"); |
64 | MODULE_FIRMWARE("multiface_firmware_rev11.bin"); | 65 | MODULE_FIRMWARE("multiface_firmware_rev11.bin"); |
65 | MODULE_FIRMWARE("digiface_firmware.bin"); | 66 | MODULE_FIRMWARE("digiface_firmware.bin"); |
@@ -81,6 +82,7 @@ MODULE_FIRMWARE("digiface_firmware_rev11.bin"); | |||
81 | #define H9632_SS_CHANNELS 12 | 82 | #define H9632_SS_CHANNELS 12 |
82 | #define H9632_DS_CHANNELS 8 | 83 | #define H9632_DS_CHANNELS 8 |
83 | #define H9632_QS_CHANNELS 4 | 84 | #define H9632_QS_CHANNELS 4 |
85 | #define RPM_CHANNELS 6 | ||
84 | 86 | ||
85 | /* Write registers. These are defined as byte-offsets from the iobase value. | 87 | /* Write registers. These are defined as byte-offsets from the iobase value. |
86 | */ | 88 | */ |
@@ -191,6 +193,25 @@ MODULE_FIRMWARE("digiface_firmware_rev11.bin"); | |||
191 | #define HDSP_PhoneGain1 (1<<30) | 193 | #define HDSP_PhoneGain1 (1<<30) |
192 | #define HDSP_QuadSpeed (1<<31) | 194 | #define HDSP_QuadSpeed (1<<31) |
193 | 195 | ||
196 | /* RPM uses some of the registers for special purposes */ | ||
197 | #define HDSP_RPM_Inp12 0x04A00 | ||
198 | #define HDSP_RPM_Inp12_Phon_6dB 0x00800 /* Dolby */ | ||
199 | #define HDSP_RPM_Inp12_Phon_0dB 0x00000 /* .. */ | ||
200 | #define HDSP_RPM_Inp12_Phon_n6dB 0x04000 /* inp_0 */ | ||
201 | #define HDSP_RPM_Inp12_Line_0dB 0x04200 /* Dolby+PRO */ | ||
202 | #define HDSP_RPM_Inp12_Line_n6dB 0x00200 /* PRO */ | ||
203 | |||
204 | #define HDSP_RPM_Inp34 0x32000 | ||
205 | #define HDSP_RPM_Inp34_Phon_6dB 0x20000 /* SyncRef1 */ | ||
206 | #define HDSP_RPM_Inp34_Phon_0dB 0x00000 /* .. */ | ||
207 | #define HDSP_RPM_Inp34_Phon_n6dB 0x02000 /* SyncRef2 */ | ||
208 | #define HDSP_RPM_Inp34_Line_0dB 0x30000 /* SyncRef1+SyncRef0 */ | ||
209 | #define HDSP_RPM_Inp34_Line_n6dB 0x10000 /* SyncRef0 */ | ||
210 | |||
211 | #define HDSP_RPM_Bypass 0x01000 | ||
212 | |||
213 | #define HDSP_RPM_Disconnect 0x00001 | ||
214 | |||
194 | #define HDSP_ADGainMask (HDSP_ADGain0|HDSP_ADGain1) | 215 | #define HDSP_ADGainMask (HDSP_ADGain0|HDSP_ADGain1) |
195 | #define HDSP_ADGainMinus10dBV HDSP_ADGainMask | 216 | #define HDSP_ADGainMinus10dBV HDSP_ADGainMask |
196 | #define HDSP_ADGainPlus4dBu (HDSP_ADGain0) | 217 | #define HDSP_ADGainPlus4dBu (HDSP_ADGain0) |
@@ -450,7 +471,7 @@ struct hdsp { | |||
450 | u32 creg_spdif; | 471 | u32 creg_spdif; |
451 | u32 creg_spdif_stream; | 472 | u32 creg_spdif_stream; |
452 | int clock_source_locked; | 473 | int clock_source_locked; |
453 | char *card_name; /* digiface/multiface */ | 474 | char *card_name; /* digiface/multiface/rpm */ |
454 | enum HDSP_IO_Type io_type; /* ditto, but for code use */ | 475 | enum HDSP_IO_Type io_type; /* ditto, but for code use */ |
455 | unsigned short firmware_rev; | 476 | unsigned short firmware_rev; |
456 | unsigned short state; /* stores state bits */ | 477 | unsigned short state; /* stores state bits */ |
@@ -612,6 +633,7 @@ static int hdsp_playback_to_output_key (struct hdsp *hdsp, int in, int out) | |||
612 | switch (hdsp->io_type) { | 633 | switch (hdsp->io_type) { |
613 | case Multiface: | 634 | case Multiface: |
614 | case Digiface: | 635 | case Digiface: |
636 | case RPM: | ||
615 | default: | 637 | default: |
616 | if (hdsp->firmware_rev == 0xa) | 638 | if (hdsp->firmware_rev == 0xa) |
617 | return (64 * out) + (32 + (in)); | 639 | return (64 * out) + (32 + (in)); |
@@ -629,6 +651,7 @@ static int hdsp_input_to_output_key (struct hdsp *hdsp, int in, int out) | |||
629 | switch (hdsp->io_type) { | 651 | switch (hdsp->io_type) { |
630 | case Multiface: | 652 | case Multiface: |
631 | case Digiface: | 653 | case Digiface: |
654 | case RPM: | ||
632 | default: | 655 | default: |
633 | if (hdsp->firmware_rev == 0xa) | 656 | if (hdsp->firmware_rev == 0xa) |
634 | return (64 * out) + in; | 657 | return (64 * out) + in; |
@@ -655,7 +678,7 @@ static int hdsp_check_for_iobox (struct hdsp *hdsp) | |||
655 | { | 678 | { |
656 | if (hdsp->io_type == H9652 || hdsp->io_type == H9632) return 0; | 679 | if (hdsp->io_type == H9652 || hdsp->io_type == H9632) return 0; |
657 | if (hdsp_read (hdsp, HDSP_statusRegister) & HDSP_ConfigError) { | 680 | if (hdsp_read (hdsp, HDSP_statusRegister) & HDSP_ConfigError) { |
658 | snd_printk ("Hammerfall-DSP: no Digiface or Multiface connected!\n"); | 681 | snd_printk("Hammerfall-DSP: no IO box connected!\n"); |
659 | hdsp->state &= ~HDSP_FirmwareLoaded; | 682 | hdsp->state &= ~HDSP_FirmwareLoaded; |
660 | return -EIO; | 683 | return -EIO; |
661 | } | 684 | } |
@@ -680,7 +703,7 @@ static int hdsp_wait_for_iobox(struct hdsp *hdsp, unsigned int loops, | |||
680 | } | 703 | } |
681 | } | 704 | } |
682 | 705 | ||
683 | snd_printk("Hammerfall-DSP: no Digiface or Multiface connected!\n"); | 706 | snd_printk("Hammerfall-DSP: no IO box connected!\n"); |
684 | hdsp->state &= ~HDSP_FirmwareLoaded; | 707 | hdsp->state &= ~HDSP_FirmwareLoaded; |
685 | return -EIO; | 708 | return -EIO; |
686 | } | 709 | } |
@@ -752,17 +775,21 @@ static int hdsp_get_iobox_version (struct hdsp *hdsp) | |||
752 | hdsp_write (hdsp, HDSP_control2Reg, HDSP_S_LOAD); | 775 | hdsp_write (hdsp, HDSP_control2Reg, HDSP_S_LOAD); |
753 | hdsp_write (hdsp, HDSP_fifoData, 0); | 776 | hdsp_write (hdsp, HDSP_fifoData, 0); |
754 | 777 | ||
755 | if (hdsp_fifo_wait (hdsp, 0, HDSP_SHORT_WAIT)) { | 778 | if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT)) { |
756 | hdsp->io_type = Multiface; | 779 | hdsp_write(hdsp, HDSP_control2Reg, HDSP_VERSION_BIT); |
757 | hdsp_write (hdsp, HDSP_control2Reg, HDSP_VERSION_BIT); | 780 | hdsp_write(hdsp, HDSP_control2Reg, HDSP_S_LOAD); |
758 | hdsp_write (hdsp, HDSP_control2Reg, HDSP_S_LOAD); | 781 | if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT)) |
759 | hdsp_fifo_wait (hdsp, 0, HDSP_SHORT_WAIT); | 782 | hdsp->io_type = RPM; |
783 | else | ||
784 | hdsp->io_type = Multiface; | ||
760 | } else { | 785 | } else { |
761 | hdsp->io_type = Digiface; | 786 | hdsp->io_type = Digiface; |
762 | } | 787 | } |
763 | } else { | 788 | } else { |
764 | /* firmware was already loaded, get iobox type */ | 789 | /* firmware was already loaded, get iobox type */ |
765 | if (hdsp_read(hdsp, HDSP_status2Register) & HDSP_version1) | 790 | if (hdsp_read(hdsp, HDSP_status2Register) & HDSP_version2) |
791 | hdsp->io_type = RPM; | ||
792 | else if (hdsp_read(hdsp, HDSP_status2Register) & HDSP_version1) | ||
766 | hdsp->io_type = Multiface; | 793 | hdsp->io_type = Multiface; |
767 | else | 794 | else |
768 | hdsp->io_type = Digiface; | 795 | hdsp->io_type = Digiface; |
@@ -1184,6 +1211,7 @@ static int hdsp_set_rate(struct hdsp *hdsp, int rate, int called_internally) | |||
1184 | hdsp->channel_map = channel_map_ds; | 1211 | hdsp->channel_map = channel_map_ds; |
1185 | } else { | 1212 | } else { |
1186 | switch (hdsp->io_type) { | 1213 | switch (hdsp->io_type) { |
1214 | case RPM: | ||
1187 | case Multiface: | 1215 | case Multiface: |
1188 | hdsp->channel_map = channel_map_mf_ss; | 1216 | hdsp->channel_map = channel_map_mf_ss; |
1189 | break; | 1217 | break; |
@@ -3231,6 +3259,318 @@ HDSP_PRECISE_POINTER("Precise Pointer", 0), | |||
3231 | HDSP_USE_MIDI_TASKLET("Use Midi Tasklet", 0), | 3259 | HDSP_USE_MIDI_TASKLET("Use Midi Tasklet", 0), |
3232 | }; | 3260 | }; |
3233 | 3261 | ||
3262 | |||
3263 | static int hdsp_rpm_input12(struct hdsp *hdsp) | ||
3264 | { | ||
3265 | switch (hdsp->control_register & HDSP_RPM_Inp12) { | ||
3266 | case HDSP_RPM_Inp12_Phon_6dB: | ||
3267 | return 0; | ||
3268 | case HDSP_RPM_Inp12_Phon_n6dB: | ||
3269 | return 2; | ||
3270 | case HDSP_RPM_Inp12_Line_0dB: | ||
3271 | return 3; | ||
3272 | case HDSP_RPM_Inp12_Line_n6dB: | ||
3273 | return 4; | ||
3274 | } | ||
3275 | return 1; | ||
3276 | } | ||
3277 | |||
3278 | |||
3279 | static int snd_hdsp_get_rpm_input12(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
3280 | { | ||
3281 | struct hdsp *hdsp = snd_kcontrol_chip(kcontrol); | ||
3282 | |||
3283 | ucontrol->value.enumerated.item[0] = hdsp_rpm_input12(hdsp); | ||
3284 | return 0; | ||
3285 | } | ||
3286 | |||
3287 | |||
3288 | static int hdsp_set_rpm_input12(struct hdsp *hdsp, int mode) | ||
3289 | { | ||
3290 | hdsp->control_register &= ~HDSP_RPM_Inp12; | ||
3291 | switch (mode) { | ||
3292 | case 0: | ||
3293 | hdsp->control_register |= HDSP_RPM_Inp12_Phon_6dB; | ||
3294 | break; | ||
3295 | case 1: | ||
3296 | break; | ||
3297 | case 2: | ||
3298 | hdsp->control_register |= HDSP_RPM_Inp12_Phon_n6dB; | ||
3299 | break; | ||
3300 | case 3: | ||
3301 | hdsp->control_register |= HDSP_RPM_Inp12_Line_0dB; | ||
3302 | break; | ||
3303 | case 4: | ||
3304 | hdsp->control_register |= HDSP_RPM_Inp12_Line_n6dB; | ||
3305 | break; | ||
3306 | default: | ||
3307 | return -1; | ||
3308 | } | ||
3309 | |||
3310 | hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); | ||
3311 | return 0; | ||
3312 | } | ||
3313 | |||
3314 | |||
3315 | static int snd_hdsp_put_rpm_input12(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
3316 | { | ||
3317 | struct hdsp *hdsp = snd_kcontrol_chip(kcontrol); | ||
3318 | int change; | ||
3319 | int val; | ||
3320 | |||
3321 | if (!snd_hdsp_use_is_exclusive(hdsp)) | ||
3322 | return -EBUSY; | ||
3323 | val = ucontrol->value.enumerated.item[0]; | ||
3324 | if (val < 0) | ||
3325 | val = 0; | ||
3326 | if (val > 4) | ||
3327 | val = 4; | ||
3328 | spin_lock_irq(&hdsp->lock); | ||
3329 | if (val != hdsp_rpm_input12(hdsp)) | ||
3330 | change = (hdsp_set_rpm_input12(hdsp, val) == 0) ? 1 : 0; | ||
3331 | else | ||
3332 | change = 0; | ||
3333 | spin_unlock_irq(&hdsp->lock); | ||
3334 | return change; | ||
3335 | } | ||
3336 | |||
3337 | |||
3338 | static int snd_hdsp_info_rpm_input(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | ||
3339 | { | ||
3340 | static char *texts[] = {"Phono +6dB", "Phono 0dB", "Phono -6dB", "Line 0dB", "Line -6dB"}; | ||
3341 | |||
3342 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
3343 | uinfo->count = 1; | ||
3344 | uinfo->value.enumerated.items = 5; | ||
3345 | if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) | ||
3346 | uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; | ||
3347 | strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); | ||
3348 | return 0; | ||
3349 | } | ||
3350 | |||
3351 | |||
3352 | static int hdsp_rpm_input34(struct hdsp *hdsp) | ||
3353 | { | ||
3354 | switch (hdsp->control_register & HDSP_RPM_Inp34) { | ||
3355 | case HDSP_RPM_Inp34_Phon_6dB: | ||
3356 | return 0; | ||
3357 | case HDSP_RPM_Inp34_Phon_n6dB: | ||
3358 | return 2; | ||
3359 | case HDSP_RPM_Inp34_Line_0dB: | ||
3360 | return 3; | ||
3361 | case HDSP_RPM_Inp34_Line_n6dB: | ||
3362 | return 4; | ||
3363 | } | ||
3364 | return 1; | ||
3365 | } | ||
3366 | |||
3367 | |||
3368 | static int snd_hdsp_get_rpm_input34(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
3369 | { | ||
3370 | struct hdsp *hdsp = snd_kcontrol_chip(kcontrol); | ||
3371 | |||
3372 | ucontrol->value.enumerated.item[0] = hdsp_rpm_input34(hdsp); | ||
3373 | return 0; | ||
3374 | } | ||
3375 | |||
3376 | |||
3377 | static int hdsp_set_rpm_input34(struct hdsp *hdsp, int mode) | ||
3378 | { | ||
3379 | hdsp->control_register &= ~HDSP_RPM_Inp34; | ||
3380 | switch (mode) { | ||
3381 | case 0: | ||
3382 | hdsp->control_register |= HDSP_RPM_Inp34_Phon_6dB; | ||
3383 | break; | ||
3384 | case 1: | ||
3385 | break; | ||
3386 | case 2: | ||
3387 | hdsp->control_register |= HDSP_RPM_Inp34_Phon_n6dB; | ||
3388 | break; | ||
3389 | case 3: | ||
3390 | hdsp->control_register |= HDSP_RPM_Inp34_Line_0dB; | ||
3391 | break; | ||
3392 | case 4: | ||
3393 | hdsp->control_register |= HDSP_RPM_Inp34_Line_n6dB; | ||
3394 | break; | ||
3395 | default: | ||
3396 | return -1; | ||
3397 | } | ||
3398 | |||
3399 | hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); | ||
3400 | return 0; | ||
3401 | } | ||
3402 | |||
3403 | |||
3404 | static int snd_hdsp_put_rpm_input34(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
3405 | { | ||
3406 | struct hdsp *hdsp = snd_kcontrol_chip(kcontrol); | ||
3407 | int change; | ||
3408 | int val; | ||
3409 | |||
3410 | if (!snd_hdsp_use_is_exclusive(hdsp)) | ||
3411 | return -EBUSY; | ||
3412 | val = ucontrol->value.enumerated.item[0]; | ||
3413 | if (val < 0) | ||
3414 | val = 0; | ||
3415 | if (val > 4) | ||
3416 | val = 4; | ||
3417 | spin_lock_irq(&hdsp->lock); | ||
3418 | if (val != hdsp_rpm_input34(hdsp)) | ||
3419 | change = (hdsp_set_rpm_input34(hdsp, val) == 0) ? 1 : 0; | ||
3420 | else | ||
3421 | change = 0; | ||
3422 | spin_unlock_irq(&hdsp->lock); | ||
3423 | return change; | ||
3424 | } | ||
3425 | |||
3426 | |||
3427 | /* RPM Bypass switch */ | ||
3428 | static int hdsp_rpm_bypass(struct hdsp *hdsp) | ||
3429 | { | ||
3430 | return (hdsp->control_register & HDSP_RPM_Bypass) ? 1 : 0; | ||
3431 | } | ||
3432 | |||
3433 | |||
3434 | static int snd_hdsp_get_rpm_bypass(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
3435 | { | ||
3436 | struct hdsp *hdsp = snd_kcontrol_chip(kcontrol); | ||
3437 | |||
3438 | ucontrol->value.integer.value[0] = hdsp_rpm_bypass(hdsp); | ||
3439 | return 0; | ||
3440 | } | ||
3441 | |||
3442 | |||
3443 | static int hdsp_set_rpm_bypass(struct hdsp *hdsp, int on) | ||
3444 | { | ||
3445 | if (on) | ||
3446 | hdsp->control_register |= HDSP_RPM_Bypass; | ||
3447 | else | ||
3448 | hdsp->control_register &= ~HDSP_RPM_Bypass; | ||
3449 | hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); | ||
3450 | return 0; | ||
3451 | } | ||
3452 | |||
3453 | |||
3454 | static int snd_hdsp_put_rpm_bypass(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
3455 | { | ||
3456 | struct hdsp *hdsp = snd_kcontrol_chip(kcontrol); | ||
3457 | int change; | ||
3458 | unsigned int val; | ||
3459 | |||
3460 | if (!snd_hdsp_use_is_exclusive(hdsp)) | ||
3461 | return -EBUSY; | ||
3462 | val = ucontrol->value.integer.value[0] & 1; | ||
3463 | spin_lock_irq(&hdsp->lock); | ||
3464 | change = (int)val != hdsp_rpm_bypass(hdsp); | ||
3465 | hdsp_set_rpm_bypass(hdsp, val); | ||
3466 | spin_unlock_irq(&hdsp->lock); | ||
3467 | return change; | ||
3468 | } | ||
3469 | |||
3470 | |||
3471 | static int snd_hdsp_info_rpm_bypass(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | ||
3472 | { | ||
3473 | static char *texts[] = {"On", "Off"}; | ||
3474 | |||
3475 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
3476 | uinfo->count = 1; | ||
3477 | uinfo->value.enumerated.items = 2; | ||
3478 | if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) | ||
3479 | uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; | ||
3480 | strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); | ||
3481 | return 0; | ||
3482 | } | ||
3483 | |||
3484 | |||
3485 | /* RPM Disconnect switch */ | ||
3486 | static int hdsp_rpm_disconnect(struct hdsp *hdsp) | ||
3487 | { | ||
3488 | return (hdsp->control_register & HDSP_RPM_Disconnect) ? 1 : 0; | ||
3489 | } | ||
3490 | |||
3491 | |||
3492 | static int snd_hdsp_get_rpm_disconnect(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
3493 | { | ||
3494 | struct hdsp *hdsp = snd_kcontrol_chip(kcontrol); | ||
3495 | |||
3496 | ucontrol->value.integer.value[0] = hdsp_rpm_disconnect(hdsp); | ||
3497 | return 0; | ||
3498 | } | ||
3499 | |||
3500 | |||
3501 | static int hdsp_set_rpm_disconnect(struct hdsp *hdsp, int on) | ||
3502 | { | ||
3503 | if (on) | ||
3504 | hdsp->control_register |= HDSP_RPM_Disconnect; | ||
3505 | else | ||
3506 | hdsp->control_register &= ~HDSP_RPM_Disconnect; | ||
3507 | hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); | ||
3508 | return 0; | ||
3509 | } | ||
3510 | |||
3511 | |||
3512 | static int snd_hdsp_put_rpm_disconnect(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
3513 | { | ||
3514 | struct hdsp *hdsp = snd_kcontrol_chip(kcontrol); | ||
3515 | int change; | ||
3516 | unsigned int val; | ||
3517 | |||
3518 | if (!snd_hdsp_use_is_exclusive(hdsp)) | ||
3519 | return -EBUSY; | ||
3520 | val = ucontrol->value.integer.value[0] & 1; | ||
3521 | spin_lock_irq(&hdsp->lock); | ||
3522 | change = (int)val != hdsp_rpm_disconnect(hdsp); | ||
3523 | hdsp_set_rpm_disconnect(hdsp, val); | ||
3524 | spin_unlock_irq(&hdsp->lock); | ||
3525 | return change; | ||
3526 | } | ||
3527 | |||
3528 | static int snd_hdsp_info_rpm_disconnect(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | ||
3529 | { | ||
3530 | static char *texts[] = {"On", "Off"}; | ||
3531 | |||
3532 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
3533 | uinfo->count = 1; | ||
3534 | uinfo->value.enumerated.items = 2; | ||
3535 | if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) | ||
3536 | uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; | ||
3537 | strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); | ||
3538 | return 0; | ||
3539 | } | ||
3540 | |||
3541 | static struct snd_kcontrol_new snd_hdsp_rpm_controls[] = { | ||
3542 | { | ||
3543 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
3544 | .name = "RPM Bypass", | ||
3545 | .get = snd_hdsp_get_rpm_bypass, | ||
3546 | .put = snd_hdsp_put_rpm_bypass, | ||
3547 | .info = snd_hdsp_info_rpm_bypass | ||
3548 | }, | ||
3549 | { | ||
3550 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
3551 | .name = "RPM Disconnect", | ||
3552 | .get = snd_hdsp_get_rpm_disconnect, | ||
3553 | .put = snd_hdsp_put_rpm_disconnect, | ||
3554 | .info = snd_hdsp_info_rpm_disconnect | ||
3555 | }, | ||
3556 | { | ||
3557 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
3558 | .name = "Input 1/2", | ||
3559 | .get = snd_hdsp_get_rpm_input12, | ||
3560 | .put = snd_hdsp_put_rpm_input12, | ||
3561 | .info = snd_hdsp_info_rpm_input | ||
3562 | }, | ||
3563 | { | ||
3564 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
3565 | .name = "Input 3/4", | ||
3566 | .get = snd_hdsp_get_rpm_input34, | ||
3567 | .put = snd_hdsp_put_rpm_input34, | ||
3568 | .info = snd_hdsp_info_rpm_input | ||
3569 | }, | ||
3570 | HDSP_SYSTEM_SAMPLE_RATE("System Sample Rate", 0), | ||
3571 | HDSP_MIXER("Mixer", 0) | ||
3572 | }; | ||
3573 | |||
3234 | static struct snd_kcontrol_new snd_hdsp_96xx_aeb = HDSP_AEB("Analog Extension Board", 0); | 3574 | static struct snd_kcontrol_new snd_hdsp_96xx_aeb = HDSP_AEB("Analog Extension Board", 0); |
3235 | static struct snd_kcontrol_new snd_hdsp_adat_sync_check = HDSP_ADAT_SYNC_CHECK; | 3575 | static struct snd_kcontrol_new snd_hdsp_adat_sync_check = HDSP_ADAT_SYNC_CHECK; |
3236 | 3576 | ||
@@ -3240,6 +3580,16 @@ static int snd_hdsp_create_controls(struct snd_card *card, struct hdsp *hdsp) | |||
3240 | int err; | 3580 | int err; |
3241 | struct snd_kcontrol *kctl; | 3581 | struct snd_kcontrol *kctl; |
3242 | 3582 | ||
3583 | if (hdsp->io_type == RPM) { | ||
3584 | /* RPM Bypass, Disconnect and Input switches */ | ||
3585 | for (idx = 0; idx < ARRAY_SIZE(snd_hdsp_rpm_controls); idx++) { | ||
3586 | err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_hdsp_rpm_controls[idx], hdsp)); | ||
3587 | if (err < 0) | ||
3588 | return err; | ||
3589 | } | ||
3590 | return 0; | ||
3591 | } | ||
3592 | |||
3243 | for (idx = 0; idx < ARRAY_SIZE(snd_hdsp_controls); idx++) { | 3593 | for (idx = 0; idx < ARRAY_SIZE(snd_hdsp_controls); idx++) { |
3244 | if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_hdsp_controls[idx], hdsp))) < 0) | 3594 | if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_hdsp_controls[idx], hdsp))) < 0) |
3245 | return err; | 3595 | return err; |
@@ -3459,48 +3809,102 @@ snd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) | |||
3459 | 3809 | ||
3460 | snd_iprintf(buffer, "\n"); | 3810 | snd_iprintf(buffer, "\n"); |
3461 | 3811 | ||
3462 | switch (hdsp_spdif_in(hdsp)) { | 3812 | if (hdsp->io_type != RPM) { |
3463 | case HDSP_SPDIFIN_OPTICAL: | 3813 | switch (hdsp_spdif_in(hdsp)) { |
3464 | snd_iprintf(buffer, "IEC958 input: Optical\n"); | 3814 | case HDSP_SPDIFIN_OPTICAL: |
3465 | break; | 3815 | snd_iprintf(buffer, "IEC958 input: Optical\n"); |
3466 | case HDSP_SPDIFIN_COAXIAL: | 3816 | break; |
3467 | snd_iprintf(buffer, "IEC958 input: Coaxial\n"); | 3817 | case HDSP_SPDIFIN_COAXIAL: |
3468 | break; | 3818 | snd_iprintf(buffer, "IEC958 input: Coaxial\n"); |
3469 | case HDSP_SPDIFIN_INTERNAL: | 3819 | break; |
3470 | snd_iprintf(buffer, "IEC958 input: Internal\n"); | 3820 | case HDSP_SPDIFIN_INTERNAL: |
3471 | break; | 3821 | snd_iprintf(buffer, "IEC958 input: Internal\n"); |
3472 | case HDSP_SPDIFIN_AES: | 3822 | break; |
3473 | snd_iprintf(buffer, "IEC958 input: AES\n"); | 3823 | case HDSP_SPDIFIN_AES: |
3474 | break; | 3824 | snd_iprintf(buffer, "IEC958 input: AES\n"); |
3475 | default: | 3825 | break; |
3476 | snd_iprintf(buffer, "IEC958 input: ???\n"); | 3826 | default: |
3477 | break; | 3827 | snd_iprintf(buffer, "IEC958 input: ???\n"); |
3828 | break; | ||
3829 | } | ||
3478 | } | 3830 | } |
3479 | 3831 | ||
3480 | if (hdsp->control_register & HDSP_SPDIFOpticalOut) | 3832 | if (RPM == hdsp->io_type) { |
3481 | snd_iprintf(buffer, "IEC958 output: Coaxial & ADAT1\n"); | 3833 | if (hdsp->control_register & HDSP_RPM_Bypass) |
3482 | else | 3834 | snd_iprintf(buffer, "RPM Bypass: disabled\n"); |
3483 | snd_iprintf(buffer, "IEC958 output: Coaxial only\n"); | 3835 | else |
3836 | snd_iprintf(buffer, "RPM Bypass: enabled\n"); | ||
3837 | if (hdsp->control_register & HDSP_RPM_Disconnect) | ||
3838 | snd_iprintf(buffer, "RPM disconnected\n"); | ||
3839 | else | ||
3840 | snd_iprintf(buffer, "RPM connected\n"); | ||
3484 | 3841 | ||
3485 | if (hdsp->control_register & HDSP_SPDIFProfessional) | 3842 | switch (hdsp->control_register & HDSP_RPM_Inp12) { |
3486 | snd_iprintf(buffer, "IEC958 quality: Professional\n"); | 3843 | case HDSP_RPM_Inp12_Phon_6dB: |
3487 | else | 3844 | snd_iprintf(buffer, "Input 1/2: Phono, 6dB\n"); |
3488 | snd_iprintf(buffer, "IEC958 quality: Consumer\n"); | 3845 | break; |
3846 | case HDSP_RPM_Inp12_Phon_0dB: | ||
3847 | snd_iprintf(buffer, "Input 1/2: Phono, 0dB\n"); | ||
3848 | break; | ||
3849 | case HDSP_RPM_Inp12_Phon_n6dB: | ||
3850 | snd_iprintf(buffer, "Input 1/2: Phono, -6dB\n"); | ||
3851 | break; | ||
3852 | case HDSP_RPM_Inp12_Line_0dB: | ||
3853 | snd_iprintf(buffer, "Input 1/2: Line, 0dB\n"); | ||
3854 | break; | ||
3855 | case HDSP_RPM_Inp12_Line_n6dB: | ||
3856 | snd_iprintf(buffer, "Input 1/2: Line, -6dB\n"); | ||
3857 | break; | ||
3858 | default: | ||
3859 | snd_iprintf(buffer, "Input 1/2: ???\n"); | ||
3860 | } | ||
3489 | 3861 | ||
3490 | if (hdsp->control_register & HDSP_SPDIFEmphasis) | 3862 | switch (hdsp->control_register & HDSP_RPM_Inp34) { |
3491 | snd_iprintf(buffer, "IEC958 emphasis: on\n"); | 3863 | case HDSP_RPM_Inp34_Phon_6dB: |
3492 | else | 3864 | snd_iprintf(buffer, "Input 3/4: Phono, 6dB\n"); |
3493 | snd_iprintf(buffer, "IEC958 emphasis: off\n"); | 3865 | break; |
3866 | case HDSP_RPM_Inp34_Phon_0dB: | ||
3867 | snd_iprintf(buffer, "Input 3/4: Phono, 0dB\n"); | ||
3868 | break; | ||
3869 | case HDSP_RPM_Inp34_Phon_n6dB: | ||
3870 | snd_iprintf(buffer, "Input 3/4: Phono, -6dB\n"); | ||
3871 | break; | ||
3872 | case HDSP_RPM_Inp34_Line_0dB: | ||
3873 | snd_iprintf(buffer, "Input 3/4: Line, 0dB\n"); | ||
3874 | break; | ||
3875 | case HDSP_RPM_Inp34_Line_n6dB: | ||
3876 | snd_iprintf(buffer, "Input 3/4: Line, -6dB\n"); | ||
3877 | break; | ||
3878 | default: | ||
3879 | snd_iprintf(buffer, "Input 3/4: ???\n"); | ||
3880 | } | ||
3494 | 3881 | ||
3495 | if (hdsp->control_register & HDSP_SPDIFNonAudio) | 3882 | } else { |
3496 | snd_iprintf(buffer, "IEC958 NonAudio: on\n"); | 3883 | if (hdsp->control_register & HDSP_SPDIFOpticalOut) |
3497 | else | 3884 | snd_iprintf(buffer, "IEC958 output: Coaxial & ADAT1\n"); |
3498 | snd_iprintf(buffer, "IEC958 NonAudio: off\n"); | 3885 | else |
3499 | if ((x = hdsp_spdif_sample_rate (hdsp)) != 0) | 3886 | snd_iprintf(buffer, "IEC958 output: Coaxial only\n"); |
3500 | snd_iprintf (buffer, "IEC958 sample rate: %d\n", x); | 3887 | |
3501 | else | 3888 | if (hdsp->control_register & HDSP_SPDIFProfessional) |
3502 | snd_iprintf (buffer, "IEC958 sample rate: Error flag set\n"); | 3889 | snd_iprintf(buffer, "IEC958 quality: Professional\n"); |
3890 | else | ||
3891 | snd_iprintf(buffer, "IEC958 quality: Consumer\n"); | ||
3892 | |||
3893 | if (hdsp->control_register & HDSP_SPDIFEmphasis) | ||
3894 | snd_iprintf(buffer, "IEC958 emphasis: on\n"); | ||
3895 | else | ||
3896 | snd_iprintf(buffer, "IEC958 emphasis: off\n"); | ||
3503 | 3897 | ||
3898 | if (hdsp->control_register & HDSP_SPDIFNonAudio) | ||
3899 | snd_iprintf(buffer, "IEC958 NonAudio: on\n"); | ||
3900 | else | ||
3901 | snd_iprintf(buffer, "IEC958 NonAudio: off\n"); | ||
3902 | x = hdsp_spdif_sample_rate(hdsp); | ||
3903 | if (x != 0) | ||
3904 | snd_iprintf(buffer, "IEC958 sample rate: %d\n", x); | ||
3905 | else | ||
3906 | snd_iprintf(buffer, "IEC958 sample rate: Error flag set\n"); | ||
3907 | } | ||
3504 | snd_iprintf(buffer, "\n"); | 3908 | snd_iprintf(buffer, "\n"); |
3505 | 3909 | ||
3506 | /* Sync Check */ | 3910 | /* Sync Check */ |
@@ -3765,7 +4169,7 @@ static irqreturn_t snd_hdsp_interrupt(int irq, void *dev_id) | |||
3765 | snd_hdsp_midi_input_read (&hdsp->midi[0]); | 4169 | snd_hdsp_midi_input_read (&hdsp->midi[0]); |
3766 | } | 4170 | } |
3767 | } | 4171 | } |
3768 | if (hdsp->io_type != Multiface && hdsp->io_type != H9632 && midi1 && midi1status) { | 4172 | if (hdsp->io_type != Multiface && hdsp->io_type != RPM && hdsp->io_type != H9632 && midi1 && midi1status) { |
3769 | if (hdsp->use_midi_tasklet) { | 4173 | if (hdsp->use_midi_tasklet) { |
3770 | /* we disable interrupts for this input until processing is done */ | 4174 | /* we disable interrupts for this input until processing is done */ |
3771 | hdsp->control_register &= ~HDSP_Midi1InterruptEnable; | 4175 | hdsp->control_register &= ~HDSP_Midi1InterruptEnable; |
@@ -4093,7 +4497,7 @@ static struct snd_pcm_hardware snd_hdsp_playback_subinfo = | |||
4093 | SNDRV_PCM_RATE_96000), | 4497 | SNDRV_PCM_RATE_96000), |
4094 | .rate_min = 32000, | 4498 | .rate_min = 32000, |
4095 | .rate_max = 96000, | 4499 | .rate_max = 96000, |
4096 | .channels_min = 14, | 4500 | .channels_min = 6, |
4097 | .channels_max = HDSP_MAX_CHANNELS, | 4501 | .channels_max = HDSP_MAX_CHANNELS, |
4098 | .buffer_bytes_max = HDSP_CHANNEL_BUFFER_BYTES * HDSP_MAX_CHANNELS, | 4502 | .buffer_bytes_max = HDSP_CHANNEL_BUFFER_BYTES * HDSP_MAX_CHANNELS, |
4099 | .period_bytes_min = (64 * 4) * 10, | 4503 | .period_bytes_min = (64 * 4) * 10, |
@@ -4122,7 +4526,7 @@ static struct snd_pcm_hardware snd_hdsp_capture_subinfo = | |||
4122 | SNDRV_PCM_RATE_96000), | 4526 | SNDRV_PCM_RATE_96000), |
4123 | .rate_min = 32000, | 4527 | .rate_min = 32000, |
4124 | .rate_max = 96000, | 4528 | .rate_max = 96000, |
4125 | .channels_min = 14, | 4529 | .channels_min = 5, |
4126 | .channels_max = HDSP_MAX_CHANNELS, | 4530 | .channels_max = HDSP_MAX_CHANNELS, |
4127 | .buffer_bytes_max = HDSP_CHANNEL_BUFFER_BYTES * HDSP_MAX_CHANNELS, | 4531 | .buffer_bytes_max = HDSP_CHANNEL_BUFFER_BYTES * HDSP_MAX_CHANNELS, |
4128 | .period_bytes_min = (64 * 4) * 10, | 4532 | .period_bytes_min = (64 * 4) * 10, |
@@ -4357,10 +4761,12 @@ static int snd_hdsp_playback_open(struct snd_pcm_substream *substream) | |||
4357 | snd_hdsp_hw_rule_rate_out_channels, hdsp, | 4761 | snd_hdsp_hw_rule_rate_out_channels, hdsp, |
4358 | SNDRV_PCM_HW_PARAM_CHANNELS, -1); | 4762 | SNDRV_PCM_HW_PARAM_CHANNELS, -1); |
4359 | 4763 | ||
4360 | hdsp->creg_spdif_stream = hdsp->creg_spdif; | 4764 | if (RPM != hdsp->io_type) { |
4361 | hdsp->spdif_ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; | 4765 | hdsp->creg_spdif_stream = hdsp->creg_spdif; |
4362 | snd_ctl_notify(hdsp->card, SNDRV_CTL_EVENT_MASK_VALUE | | 4766 | hdsp->spdif_ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; |
4363 | SNDRV_CTL_EVENT_MASK_INFO, &hdsp->spdif_ctl->id); | 4767 | snd_ctl_notify(hdsp->card, SNDRV_CTL_EVENT_MASK_VALUE | |
4768 | SNDRV_CTL_EVENT_MASK_INFO, &hdsp->spdif_ctl->id); | ||
4769 | } | ||
4364 | return 0; | 4770 | return 0; |
4365 | } | 4771 | } |
4366 | 4772 | ||
@@ -4375,9 +4781,11 @@ static int snd_hdsp_playback_release(struct snd_pcm_substream *substream) | |||
4375 | 4781 | ||
4376 | spin_unlock_irq(&hdsp->lock); | 4782 | spin_unlock_irq(&hdsp->lock); |
4377 | 4783 | ||
4378 | hdsp->spdif_ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; | 4784 | if (RPM != hdsp->io_type) { |
4379 | snd_ctl_notify(hdsp->card, SNDRV_CTL_EVENT_MASK_VALUE | | 4785 | hdsp->spdif_ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; |
4380 | SNDRV_CTL_EVENT_MASK_INFO, &hdsp->spdif_ctl->id); | 4786 | snd_ctl_notify(hdsp->card, SNDRV_CTL_EVENT_MASK_VALUE | |
4787 | SNDRV_CTL_EVENT_MASK_INFO, &hdsp->spdif_ctl->id); | ||
4788 | } | ||
4381 | return 0; | 4789 | return 0; |
4382 | } | 4790 | } |
4383 | 4791 | ||
@@ -4616,7 +5024,7 @@ static int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigne | |||
4616 | if (hdsp->io_type != H9632) | 5024 | if (hdsp->io_type != H9632) |
4617 | info.adatsync_sync_check = (unsigned char)hdsp_adatsync_sync_check(hdsp); | 5025 | info.adatsync_sync_check = (unsigned char)hdsp_adatsync_sync_check(hdsp); |
4618 | info.spdif_sync_check = (unsigned char)hdsp_spdif_sync_check(hdsp); | 5026 | info.spdif_sync_check = (unsigned char)hdsp_spdif_sync_check(hdsp); |
4619 | for (i = 0; i < ((hdsp->io_type != Multiface && hdsp->io_type != H9632) ? 3 : 1); ++i) | 5027 | for (i = 0; i < ((hdsp->io_type != Multiface && hdsp->io_type != RPM && hdsp->io_type != H9632) ? 3 : 1); ++i) |
4620 | info.adat_sync_check[i] = (unsigned char)hdsp_adat_sync_check(hdsp, i); | 5028 | info.adat_sync_check[i] = (unsigned char)hdsp_adat_sync_check(hdsp, i); |
4621 | info.spdif_in = (unsigned char)hdsp_spdif_in(hdsp); | 5029 | info.spdif_in = (unsigned char)hdsp_spdif_in(hdsp); |
4622 | info.spdif_out = (unsigned char)hdsp_spdif_out(hdsp); | 5030 | 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 | |||
4636 | info.phone_gain = (unsigned char)hdsp_phone_gain(hdsp); | 5044 | info.phone_gain = (unsigned char)hdsp_phone_gain(hdsp); |
4637 | info.xlr_breakout_cable = (unsigned char)hdsp_xlr_breakout_cable(hdsp); | 5045 | info.xlr_breakout_cable = (unsigned char)hdsp_xlr_breakout_cable(hdsp); |
4638 | 5046 | ||
5047 | } else if (hdsp->io_type == RPM) { | ||
5048 | info.da_gain = (unsigned char) hdsp_rpm_input12(hdsp); | ||
5049 | info.ad_gain = (unsigned char) hdsp_rpm_input34(hdsp); | ||
4639 | } | 5050 | } |
4640 | if (hdsp->io_type == H9632 || hdsp->io_type == H9652) | 5051 | if (hdsp->io_type == H9632 || hdsp->io_type == H9652) |
4641 | info.analog_extension_board = (unsigned char)hdsp_aeb(hdsp); | 5052 | info.analog_extension_board = (unsigned char)hdsp_aeb(hdsp); |
@@ -4844,6 +5255,14 @@ static void snd_hdsp_initialize_channels(struct hdsp *hdsp) | |||
4844 | hdsp->ds_in_channels = hdsp->ds_out_channels = MULTIFACE_DS_CHANNELS; | 5255 | hdsp->ds_in_channels = hdsp->ds_out_channels = MULTIFACE_DS_CHANNELS; |
4845 | break; | 5256 | break; |
4846 | 5257 | ||
5258 | case RPM: | ||
5259 | hdsp->card_name = "RME Hammerfall DSP + RPM"; | ||
5260 | hdsp->ss_in_channels = RPM_CHANNELS-1; | ||
5261 | hdsp->ss_out_channels = RPM_CHANNELS; | ||
5262 | hdsp->ds_in_channels = RPM_CHANNELS-1; | ||
5263 | hdsp->ds_out_channels = RPM_CHANNELS; | ||
5264 | break; | ||
5265 | |||
4847 | default: | 5266 | default: |
4848 | /* should never get here */ | 5267 | /* should never get here */ |
4849 | break; | 5268 | break; |
@@ -4930,6 +5349,9 @@ static int hdsp_request_fw_loader(struct hdsp *hdsp) | |||
4930 | 5349 | ||
4931 | /* caution: max length of firmware filename is 30! */ | 5350 | /* caution: max length of firmware filename is 30! */ |
4932 | switch (hdsp->io_type) { | 5351 | switch (hdsp->io_type) { |
5352 | case RPM: | ||
5353 | fwfile = "rpm_firmware.bin"; | ||
5354 | break; | ||
4933 | case Multiface: | 5355 | case Multiface: |
4934 | if (hdsp->firmware_rev == 0xa) | 5356 | if (hdsp->firmware_rev == 0xa) |
4935 | fwfile = "multiface_firmware.bin"; | 5357 | fwfile = "multiface_firmware.bin"; |
@@ -5100,7 +5522,9 @@ static int __devinit snd_hdsp_create(struct snd_card *card, | |||
5100 | return 0; | 5522 | return 0; |
5101 | } else { | 5523 | } else { |
5102 | snd_printk(KERN_INFO "Hammerfall-DSP: Firmware already present, initializing card.\n"); | 5524 | snd_printk(KERN_INFO "Hammerfall-DSP: Firmware already present, initializing card.\n"); |
5103 | if (hdsp_read(hdsp, HDSP_status2Register) & HDSP_version1) | 5525 | if (hdsp_read(hdsp, HDSP_status2Register) & HDSP_version2) |
5526 | hdsp->io_type = RPM; | ||
5527 | else if (hdsp_read(hdsp, HDSP_status2Register) & HDSP_version1) | ||
5104 | hdsp->io_type = Multiface; | 5528 | hdsp->io_type = Multiface; |
5105 | else | 5529 | else |
5106 | hdsp->io_type = Digiface; | 5530 | hdsp->io_type = Digiface; |
diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c index 5518371db13f..c94c051ad0c8 100644 --- a/sound/pci/ymfpci/ymfpci_main.c +++ b/sound/pci/ymfpci/ymfpci_main.c | |||
@@ -1389,15 +1389,9 @@ static struct snd_kcontrol_new snd_ymfpci_spdif_stream __devinitdata = | |||
1389 | 1389 | ||
1390 | static int snd_ymfpci_drec_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *info) | 1390 | static int snd_ymfpci_drec_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *info) |
1391 | { | 1391 | { |
1392 | static char *texts[3] = {"AC'97", "IEC958", "ZV Port"}; | 1392 | static const char *const texts[3] = {"AC'97", "IEC958", "ZV Port"}; |
1393 | 1393 | ||
1394 | info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 1394 | return snd_ctl_enum_info(info, 1, 3, texts); |
1395 | info->count = 1; | ||
1396 | info->value.enumerated.items = 3; | ||
1397 | if (info->value.enumerated.item > 2) | ||
1398 | info->value.enumerated.item = 2; | ||
1399 | strcpy(info->value.enumerated.name, texts[info->value.enumerated.item]); | ||
1400 | return 0; | ||
1401 | } | 1395 | } |
1402 | 1396 | ||
1403 | static int snd_ymfpci_drec_source_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *value) | 1397 | static int snd_ymfpci_drec_source_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *value) |
diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index 7611add7f8c3..b3e9fac172e5 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c | |||
@@ -1626,7 +1626,6 @@ static int wm8350_codec_remove(struct snd_soc_codec *codec) | |||
1626 | { | 1626 | { |
1627 | struct wm8350_data *priv = snd_soc_codec_get_drvdata(codec); | 1627 | struct wm8350_data *priv = snd_soc_codec_get_drvdata(codec); |
1628 | struct wm8350 *wm8350 = dev_get_platdata(codec->dev); | 1628 | struct wm8350 *wm8350 = dev_get_platdata(codec->dev); |
1629 | int ret; | ||
1630 | 1629 | ||
1631 | wm8350_clear_bits(wm8350, WM8350_JACK_DETECT, | 1630 | wm8350_clear_bits(wm8350, WM8350_JACK_DETECT, |
1632 | WM8350_JDL_ENA | WM8350_JDR_ENA); | 1631 | WM8350_JDL_ENA | WM8350_JDR_ENA); |
@@ -1641,15 +1640,9 @@ static int wm8350_codec_remove(struct snd_soc_codec *codec) | |||
1641 | priv->hpr.jack = NULL; | 1640 | priv->hpr.jack = NULL; |
1642 | priv->mic.jack = NULL; | 1641 | priv->mic.jack = NULL; |
1643 | 1642 | ||
1644 | /* cancel any work waiting to be queued. */ | ||
1645 | ret = cancel_delayed_work(&codec->delayed_work); | ||
1646 | |||
1647 | /* if there was any work waiting then we run it now and | 1643 | /* if there was any work waiting then we run it now and |
1648 | * wait for its completion */ | 1644 | * wait for its completion */ |
1649 | if (ret) { | 1645 | flush_delayed_work_sync(&codec->delayed_work); |
1650 | schedule_delayed_work(&codec->delayed_work, 0); | ||
1651 | flush_scheduled_work(); | ||
1652 | } | ||
1653 | 1646 | ||
1654 | wm8350_set_bias_level(codec, SND_SOC_BIAS_OFF); | 1647 | wm8350_set_bias_level(codec, SND_SOC_BIAS_OFF); |
1655 | 1648 | ||
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index 87caae59e939..700f596a8be6 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c | |||
@@ -1476,25 +1476,6 @@ static int wm8753_resume(struct snd_soc_codec *codec) | |||
1476 | return 0; | 1476 | return 0; |
1477 | } | 1477 | } |
1478 | 1478 | ||
1479 | /* | ||
1480 | * This function forces any delayed work to be queued and run. | ||
1481 | */ | ||
1482 | static int run_delayed_work(struct delayed_work *dwork) | ||
1483 | { | ||
1484 | int ret; | ||
1485 | |||
1486 | /* cancel any work waiting to be queued. */ | ||
1487 | ret = cancel_delayed_work(dwork); | ||
1488 | |||
1489 | /* if there was any work waiting then we run it now and | ||
1490 | * wait for it's completion */ | ||
1491 | if (ret) { | ||
1492 | schedule_delayed_work(dwork, 0); | ||
1493 | flush_scheduled_work(); | ||
1494 | } | ||
1495 | return ret; | ||
1496 | } | ||
1497 | |||
1498 | static int wm8753_probe(struct snd_soc_codec *codec) | 1479 | static int wm8753_probe(struct snd_soc_codec *codec) |
1499 | { | 1480 | { |
1500 | struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec); | 1481 | struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec); |
@@ -1544,7 +1525,7 @@ static int wm8753_probe(struct snd_soc_codec *codec) | |||
1544 | /* power down chip */ | 1525 | /* power down chip */ |
1545 | static int wm8753_remove(struct snd_soc_codec *codec) | 1526 | static int wm8753_remove(struct snd_soc_codec *codec) |
1546 | { | 1527 | { |
1547 | run_delayed_work(&codec->delayed_work); | 1528 | flush_delayed_work_sync(&codec->delayed_work); |
1548 | wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF); | 1529 | wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF); |
1549 | 1530 | ||
1550 | return 0; | 1531 | return 0; |
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 85b7d548f167..df7b6a7e2e27 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c | |||
@@ -67,25 +67,6 @@ static int pmdown_time = 5000; | |||
67 | module_param(pmdown_time, int, 0); | 67 | module_param(pmdown_time, int, 0); |
68 | MODULE_PARM_DESC(pmdown_time, "DAPM stream powerdown time (msecs)"); | 68 | MODULE_PARM_DESC(pmdown_time, "DAPM stream powerdown time (msecs)"); |
69 | 69 | ||
70 | /* | ||
71 | * This function forces any delayed work to be queued and run. | ||
72 | */ | ||
73 | static int run_delayed_work(struct delayed_work *dwork) | ||
74 | { | ||
75 | int ret; | ||
76 | |||
77 | /* cancel any work waiting to be queued. */ | ||
78 | ret = cancel_delayed_work(dwork); | ||
79 | |||
80 | /* if there was any work waiting then we run it now and | ||
81 | * wait for it's completion */ | ||
82 | if (ret) { | ||
83 | schedule_delayed_work(dwork, 0); | ||
84 | flush_scheduled_work(); | ||
85 | } | ||
86 | return ret; | ||
87 | } | ||
88 | |||
89 | /* codec register dump */ | 70 | /* codec register dump */ |
90 | static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf) | 71 | static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf) |
91 | { | 72 | { |
@@ -1016,7 +997,7 @@ static int soc_suspend(struct device *dev) | |||
1016 | 997 | ||
1017 | /* close any waiting streams and save state */ | 998 | /* close any waiting streams and save state */ |
1018 | for (i = 0; i < card->num_rtd; i++) { | 999 | for (i = 0; i < card->num_rtd; i++) { |
1019 | run_delayed_work(&card->rtd[i].delayed_work); | 1000 | flush_delayed_work_sync(&card->rtd[i].delayed_work); |
1020 | card->rtd[i].codec->suspend_bias_level = card->rtd[i].codec->bias_level; | 1001 | card->rtd[i].codec->suspend_bias_level = card->rtd[i].codec->bias_level; |
1021 | } | 1002 | } |
1022 | 1003 | ||
@@ -1689,7 +1670,7 @@ static int soc_remove(struct platform_device *pdev) | |||
1689 | /* make sure any delayed work runs */ | 1670 | /* make sure any delayed work runs */ |
1690 | for (i = 0; i < card->num_rtd; i++) { | 1671 | for (i = 0; i < card->num_rtd; i++) { |
1691 | struct snd_soc_pcm_runtime *rtd = &card->rtd[i]; | 1672 | struct snd_soc_pcm_runtime *rtd = &card->rtd[i]; |
1692 | run_delayed_work(&rtd->delayed_work); | 1673 | flush_delayed_work_sync(&rtd->delayed_work); |
1693 | } | 1674 | } |
1694 | 1675 | ||
1695 | /* remove and free each DAI */ | 1676 | /* remove and free each DAI */ |
@@ -1720,7 +1701,7 @@ static int soc_poweroff(struct device *dev) | |||
1720 | * now, we're shutting down so no imminent restart. */ | 1701 | * now, we're shutting down so no imminent restart. */ |
1721 | for (i = 0; i < card->num_rtd; i++) { | 1702 | for (i = 0; i < card->num_rtd; i++) { |
1722 | struct snd_soc_pcm_runtime *rtd = &card->rtd[i]; | 1703 | struct snd_soc_pcm_runtime *rtd = &card->rtd[i]; |
1723 | run_delayed_work(&rtd->delayed_work); | 1704 | flush_delayed_work_sync(&rtd->delayed_work); |
1724 | } | 1705 | } |
1725 | 1706 | ||
1726 | snd_soc_dapm_shutdown(card); | 1707 | snd_soc_dapm_shutdown(card); |
diff --git a/sound/usb/format.c b/sound/usb/format.c index 69148212aa70..5b792d2c8061 100644 --- a/sound/usb/format.c +++ b/sound/usb/format.c | |||
@@ -76,7 +76,10 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip, | |||
76 | format = 1 << UAC_FORMAT_TYPE_I_PCM; | 76 | format = 1 << UAC_FORMAT_TYPE_I_PCM; |
77 | } | 77 | } |
78 | if (format & (1 << UAC_FORMAT_TYPE_I_PCM)) { | 78 | if (format & (1 << UAC_FORMAT_TYPE_I_PCM)) { |
79 | if (sample_width > sample_bytes * 8) { | 79 | if (chip->usb_id == USB_ID(0x0582, 0x0016) /* Edirol SD-90 */ && |
80 | sample_width == 24 && sample_bytes == 2) | ||
81 | sample_bytes = 3; | ||
82 | else if (sample_width > sample_bytes * 8) { | ||
80 | snd_printk(KERN_INFO "%d:%u:%d : sample bitwidth %d in over sample bytes %d\n", | 83 | snd_printk(KERN_INFO "%d:%u:%d : sample bitwidth %d in over sample bytes %d\n", |
81 | chip->dev->devnum, fp->iface, fp->altsetting, | 84 | chip->dev->devnum, fp->iface, fp->altsetting, |
82 | sample_width, sample_bytes); | 85 | sample_width, sample_bytes); |
diff --git a/sound/usb/midi.c b/sound/usb/midi.c index 25bce7e5b1af..db2dc5ffe6dd 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c | |||
@@ -850,8 +850,8 @@ static void snd_usbmidi_us122l_output(struct snd_usb_midi_out_endpoint *ep, | |||
850 | return; | 850 | return; |
851 | } | 851 | } |
852 | 852 | ||
853 | memset(urb->transfer_buffer + count, 0xFD, 9 - count); | 853 | memset(urb->transfer_buffer + count, 0xFD, ep->max_transfer - count); |
854 | urb->transfer_buffer_length = count; | 854 | urb->transfer_buffer_length = ep->max_transfer; |
855 | } | 855 | } |
856 | 856 | ||
857 | static struct usb_protocol_ops snd_usbmidi_122l_ops = { | 857 | static struct usb_protocol_ops snd_usbmidi_122l_ops = { |
@@ -1295,6 +1295,13 @@ static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi* umidi, | |||
1295 | case USB_ID(0x1a86, 0x752d): /* QinHeng CH345 "USB2.0-MIDI" */ | 1295 | case USB_ID(0x1a86, 0x752d): /* QinHeng CH345 "USB2.0-MIDI" */ |
1296 | ep->max_transfer = 4; | 1296 | ep->max_transfer = 4; |
1297 | break; | 1297 | break; |
1298 | /* | ||
1299 | * Some devices only work with 9 bytes packet size: | ||
1300 | */ | ||
1301 | case USB_ID(0x0644, 0x800E): /* Tascam US-122L */ | ||
1302 | case USB_ID(0x0644, 0x800F): /* Tascam US-144 */ | ||
1303 | ep->max_transfer = 9; | ||
1304 | break; | ||
1298 | } | 1305 | } |
1299 | for (i = 0; i < OUTPUT_URBS; ++i) { | 1306 | for (i = 0; i < OUTPUT_URBS; ++i) { |
1300 | buffer = usb_alloc_coherent(umidi->dev, | 1307 | buffer = usb_alloc_coherent(umidi->dev, |
@@ -1729,13 +1736,7 @@ static int roland_load_info(struct snd_kcontrol *kcontrol, | |||
1729 | { | 1736 | { |
1730 | static const char *const names[] = { "High Load", "Light Load" }; | 1737 | static const char *const names[] = { "High Load", "Light Load" }; |
1731 | 1738 | ||
1732 | info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 1739 | return snd_ctl_enum_info(info, 1, 2, names); |
1733 | info->count = 1; | ||
1734 | info->value.enumerated.items = 2; | ||
1735 | if (info->value.enumerated.item > 1) | ||
1736 | info->value.enumerated.item = 1; | ||
1737 | strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); | ||
1738 | return 0; | ||
1739 | } | 1740 | } |
1740 | 1741 | ||
1741 | static int roland_load_get(struct snd_kcontrol *kcontrol, | 1742 | static int roland_load_get(struct snd_kcontrol *kcontrol, |
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index f2d74d654b3c..7df89b3d7ded 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c | |||
@@ -1633,18 +1633,11 @@ static int parse_audio_extension_unit(struct mixer_build *state, int unitid, voi | |||
1633 | static int mixer_ctl_selector_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | 1633 | static int mixer_ctl_selector_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) |
1634 | { | 1634 | { |
1635 | struct usb_mixer_elem_info *cval = kcontrol->private_data; | 1635 | struct usb_mixer_elem_info *cval = kcontrol->private_data; |
1636 | char **itemlist = (char **)kcontrol->private_value; | 1636 | const char **itemlist = (const char **)kcontrol->private_value; |
1637 | 1637 | ||
1638 | if (snd_BUG_ON(!itemlist)) | 1638 | if (snd_BUG_ON(!itemlist)) |
1639 | return -EINVAL; | 1639 | return -EINVAL; |
1640 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 1640 | return snd_ctl_enum_info(uinfo, 1, cval->max, itemlist); |
1641 | uinfo->count = 1; | ||
1642 | uinfo->value.enumerated.items = cval->max; | ||
1643 | if (uinfo->value.enumerated.item >= cval->max) | ||
1644 | uinfo->value.enumerated.item = cval->max - 1; | ||
1645 | strlcpy(uinfo->value.enumerated.name, itemlist[uinfo->value.enumerated.item], | ||
1646 | sizeof(uinfo->value.enumerated.name)); | ||
1647 | return 0; | ||
1648 | } | 1641 | } |
1649 | 1642 | ||
1650 | /* get callback for selector unit */ | 1643 | /* get callback for selector unit */ |
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index ad7079d1676c..35999874d301 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h | |||
@@ -705,11 +705,11 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
705 | .data = (const struct snd_usb_audio_quirk[]) { | 705 | .data = (const struct snd_usb_audio_quirk[]) { |
706 | { | 706 | { |
707 | .ifnum = 0, | 707 | .ifnum = 0, |
708 | .type = QUIRK_IGNORE_INTERFACE | 708 | .type = QUIRK_AUDIO_STANDARD_INTERFACE |
709 | }, | 709 | }, |
710 | { | 710 | { |
711 | .ifnum = 1, | 711 | .ifnum = 1, |
712 | .type = QUIRK_IGNORE_INTERFACE | 712 | .type = QUIRK_AUDIO_STANDARD_INTERFACE |
713 | }, | 713 | }, |
714 | { | 714 | { |
715 | .ifnum = 2, | 715 | .ifnum = 2, |
diff --git a/sound/usb/usx2y/us122l.c b/sound/usb/usx2y/us122l.c index 6ef68e42138e..084e6fc8d5bf 100644 --- a/sound/usb/usx2y/us122l.c +++ b/sound/usb/usx2y/us122l.c | |||
@@ -273,29 +273,26 @@ static unsigned int usb_stream_hwdep_poll(struct snd_hwdep *hw, | |||
273 | struct file *file, poll_table *wait) | 273 | struct file *file, poll_table *wait) |
274 | { | 274 | { |
275 | struct us122l *us122l = hw->private_data; | 275 | struct us122l *us122l = hw->private_data; |
276 | struct usb_stream *s = us122l->sk.s; | ||
277 | unsigned *polled; | 276 | unsigned *polled; |
278 | unsigned int mask; | 277 | unsigned int mask; |
279 | 278 | ||
280 | poll_wait(file, &us122l->sk.sleep, wait); | 279 | poll_wait(file, &us122l->sk.sleep, wait); |
281 | 280 | ||
282 | switch (s->state) { | 281 | mask = POLLIN | POLLOUT | POLLWRNORM | POLLERR; |
283 | case usb_stream_ready: | 282 | if (mutex_trylock(&us122l->mutex)) { |
284 | if (us122l->first == file) | 283 | struct usb_stream *s = us122l->sk.s; |
285 | polled = &s->periods_polled; | 284 | if (s && s->state == usb_stream_ready) { |
286 | else | 285 | if (us122l->first == file) |
287 | polled = &us122l->second_periods_polled; | 286 | polled = &s->periods_polled; |
288 | if (*polled != s->periods_done) { | 287 | else |
289 | *polled = s->periods_done; | 288 | polled = &us122l->second_periods_polled; |
290 | mask = POLLIN | POLLOUT | POLLWRNORM; | 289 | if (*polled != s->periods_done) { |
291 | break; | 290 | *polled = s->periods_done; |
291 | mask = POLLIN | POLLOUT | POLLWRNORM; | ||
292 | } else | ||
293 | mask = 0; | ||
292 | } | 294 | } |
293 | /* Fall through */ | 295 | mutex_unlock(&us122l->mutex); |
294 | mask = 0; | ||
295 | break; | ||
296 | default: | ||
297 | mask = POLLIN | POLLOUT | POLLWRNORM | POLLERR; | ||
298 | break; | ||
299 | } | 296 | } |
300 | return mask; | 297 | return mask; |
301 | } | 298 | } |
@@ -381,6 +378,7 @@ static int usb_stream_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, | |||
381 | { | 378 | { |
382 | struct usb_stream_config *cfg; | 379 | struct usb_stream_config *cfg; |
383 | struct us122l *us122l = hw->private_data; | 380 | struct us122l *us122l = hw->private_data; |
381 | struct usb_stream *s; | ||
384 | unsigned min_period_frames; | 382 | unsigned min_period_frames; |
385 | int err = 0; | 383 | int err = 0; |
386 | bool high_speed; | 384 | bool high_speed; |
@@ -426,18 +424,18 @@ static int usb_stream_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, | |||
426 | snd_power_wait(hw->card, SNDRV_CTL_POWER_D0); | 424 | snd_power_wait(hw->card, SNDRV_CTL_POWER_D0); |
427 | 425 | ||
428 | mutex_lock(&us122l->mutex); | 426 | mutex_lock(&us122l->mutex); |
427 | s = us122l->sk.s; | ||
429 | if (!us122l->master) | 428 | if (!us122l->master) |
430 | us122l->master = file; | 429 | us122l->master = file; |
431 | else if (us122l->master != file) { | 430 | else if (us122l->master != file) { |
432 | if (memcmp(cfg, &us122l->sk.s->cfg, sizeof(*cfg))) { | 431 | if (!s || memcmp(cfg, &s->cfg, sizeof(*cfg))) { |
433 | err = -EIO; | 432 | err = -EIO; |
434 | goto unlock; | 433 | goto unlock; |
435 | } | 434 | } |
436 | us122l->slave = file; | 435 | us122l->slave = file; |
437 | } | 436 | } |
438 | if (!us122l->sk.s || | 437 | if (!s || memcmp(cfg, &s->cfg, sizeof(*cfg)) || |
439 | memcmp(cfg, &us122l->sk.s->cfg, sizeof(*cfg)) || | 438 | s->state == usb_stream_xrun) { |
440 | us122l->sk.s->state == usb_stream_xrun) { | ||
441 | us122l_stop(us122l); | 439 | us122l_stop(us122l); |
442 | if (!us122l_start(us122l, cfg->sample_rate, cfg->period_frames)) | 440 | if (!us122l_start(us122l, cfg->sample_rate, cfg->period_frames)) |
443 | err = -EIO; | 441 | err = -EIO; |
@@ -448,6 +446,7 @@ unlock: | |||
448 | mutex_unlock(&us122l->mutex); | 446 | mutex_unlock(&us122l->mutex); |
449 | free: | 447 | free: |
450 | kfree(cfg); | 448 | kfree(cfg); |
449 | wake_up_all(&us122l->sk.sleep); | ||
451 | return err; | 450 | return err; |
452 | } | 451 | } |
453 | 452 | ||