diff options
216 files changed, 28241 insertions, 3797 deletions
diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 9fef210ab50a..c30ff1bb2d10 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt | |||
@@ -242,6 +242,12 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. | |||
242 | ac97_clock - AC'97 clock (default = 48000) | 242 | ac97_clock - AC'97 clock (default = 48000) |
243 | ac97_quirk - AC'97 workaround for strange hardware | 243 | ac97_quirk - AC'97 workaround for strange hardware |
244 | See "AC97 Quirk Option" section below. | 244 | See "AC97 Quirk Option" section below. |
245 | ac97_codec - Workaround to specify which AC'97 codec | ||
246 | instead of probing. If this works for you | ||
247 | file a bug with your `lspci -vn` output. | ||
248 | -2 -- Force probing. | ||
249 | -1 -- Default behavior. | ||
250 | 0-2 -- Use the specified codec. | ||
245 | spdif_aclink - S/PDIF transfer over AC-link (default = 1) | 251 | spdif_aclink - S/PDIF transfer over AC-link (default = 1) |
246 | 252 | ||
247 | This module supports one card and autoprobe. | 253 | This module supports one card and autoprobe. |
@@ -779,6 +785,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. | |||
779 | asus-dig ASUS with SPDIF out | 785 | asus-dig ASUS with SPDIF out |
780 | asus-dig2 ASUS with SPDIF out (using GPIO2) | 786 | asus-dig2 ASUS with SPDIF out (using GPIO2) |
781 | uniwill 3-jack | 787 | uniwill 3-jack |
788 | fujitsu Fujitsu Laptops (Pi1536) | ||
782 | F1734 2-jack | 789 | F1734 2-jack |
783 | lg LG laptop (m1 express dual) | 790 | lg LG laptop (m1 express dual) |
784 | lg-lw LG LW20/LW25 laptop | 791 | lg-lw LG LW20/LW25 laptop |
@@ -800,14 +807,18 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. | |||
800 | ALC262 | 807 | ALC262 |
801 | fujitsu Fujitsu Laptop | 808 | fujitsu Fujitsu Laptop |
802 | hp-bpc HP xw4400/6400/8400/9400 laptops | 809 | hp-bpc HP xw4400/6400/8400/9400 laptops |
810 | hp-bpc-d7000 HP BPC D7000 | ||
803 | benq Benq ED8 | 811 | benq Benq ED8 |
812 | hippo Hippo (ATI) with jack detection, Sony UX-90s | ||
813 | hippo_1 Hippo (Benq) with jack detection | ||
804 | basic fixed pin assignment w/o SPDIF | 814 | basic fixed pin assignment w/o SPDIF |
805 | auto auto-config reading BIOS (default) | 815 | auto auto-config reading BIOS (default) |
806 | 816 | ||
807 | ALC882/885 | 817 | ALC882/885 |
808 | 3stack-dig 3-jack with SPDIF I/O | 818 | 3stack-dig 3-jack with SPDIF I/O |
809 | 6stck-dig 6-jack digital with SPDIF I/O | 819 | 6stack-dig 6-jack digital with SPDIF I/O |
810 | arima Arima W820Di1 | 820 | arima Arima W820Di1 |
821 | macpro MacPro support | ||
811 | auto auto-config reading BIOS (default) | 822 | auto auto-config reading BIOS (default) |
812 | 823 | ||
813 | ALC883/888 | 824 | ALC883/888 |
@@ -817,6 +828,10 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. | |||
817 | 3stack-6ch-dig 3-jack 6-channel with SPDIF I/O | 828 | 3stack-6ch-dig 3-jack 6-channel with SPDIF I/O |
818 | 6stack-dig-demo 6-jack digital for Intel demo board | 829 | 6stack-dig-demo 6-jack digital for Intel demo board |
819 | acer Acer laptops (Travelmate 3012WTMi, Aspire 5600, etc) | 830 | acer Acer laptops (Travelmate 3012WTMi, Aspire 5600, etc) |
831 | medion Medion Laptops | ||
832 | targa-dig Targa/MSI | ||
833 | targa-2ch-dig Targs/MSI with 2-channel | ||
834 | laptop-eapd 3-jack with SPDIF I/O and EAPD (Clevo M540JE, M550JE) | ||
820 | auto auto-config reading BIOS (default) | 835 | auto auto-config reading BIOS (default) |
821 | 836 | ||
822 | ALC861/660 | 837 | ALC861/660 |
@@ -825,6 +840,16 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. | |||
825 | 6stack-dig 6-jack with SPDIF I/O | 840 | 6stack-dig 6-jack with SPDIF I/O |
826 | 3stack-660 3-jack (for ALC660) | 841 | 3stack-660 3-jack (for ALC660) |
827 | uniwill-m31 Uniwill M31 laptop | 842 | uniwill-m31 Uniwill M31 laptop |
843 | toshiba Toshiba laptop support | ||
844 | asus Asus laptop support | ||
845 | asus-laptop ASUS F2/F3 laptops | ||
846 | auto auto-config reading BIOS (default) | ||
847 | |||
848 | ALC861VD/660VD | ||
849 | 3stack 3-jack | ||
850 | 3stack-dig 3-jack with SPDIF OUT | ||
851 | 6stack-dig 6-jack with SPDIF OUT | ||
852 | 3stack-660 3-jack (for ALC660VD) | ||
828 | auto auto-config reading BIOS (default) | 853 | auto auto-config reading BIOS (default) |
829 | 854 | ||
830 | CMI9880 | 855 | CMI9880 |
@@ -845,6 +870,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. | |||
845 | 3stack 3-stack, shared surrounds | 870 | 3stack 3-stack, shared surrounds |
846 | laptop 2-channel only (FSC V2060, Samsung M50) | 871 | laptop 2-channel only (FSC V2060, Samsung M50) |
847 | laptop-eapd 2-channel with EAPD (Samsung R65, ASUS A6J) | 872 | laptop-eapd 2-channel with EAPD (Samsung R65, ASUS A6J) |
873 | ultra 2-channel with EAPD (Samsung Ultra tablet PC) | ||
848 | 874 | ||
849 | AD1988 | 875 | AD1988 |
850 | 6stack 6-jack | 876 | 6stack 6-jack |
@@ -854,12 +880,31 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. | |||
854 | laptop 3-jack with hp-jack automute | 880 | laptop 3-jack with hp-jack automute |
855 | laptop-dig ditto with SPDIF | 881 | laptop-dig ditto with SPDIF |
856 | auto auto-config reading BIOS (default) | 882 | auto auto-config reading BIOS (default) |
883 | |||
884 | Conexant 5045 | ||
885 | laptop Laptop config | ||
886 | test for testing/debugging purpose, almost all controls | ||
887 | can be adjusted. Appearing only when compiled with | ||
888 | $CONFIG_SND_DEBUG=y | ||
889 | |||
890 | Conexant 5047 | ||
891 | laptop Basic Laptop config | ||
892 | laptop-hp Laptop config for some HP models (subdevice 30A5) | ||
893 | laptop-eapd Laptop config with EAPD support | ||
894 | test for testing/debugging purpose, almost all controls | ||
895 | can be adjusted. Appearing only when compiled with | ||
896 | $CONFIG_SND_DEBUG=y | ||
857 | 897 | ||
858 | STAC9200/9205/9220/9221/9254 | 898 | STAC9200/9205/9220/9221/9254 |
859 | ref Reference board | 899 | ref Reference board |
860 | 3stack D945 3stack | 900 | 3stack D945 3stack |
861 | 5stack D945 5stack + SPDIF | 901 | 5stack D945 5stack + SPDIF |
862 | 902 | ||
903 | STAC9202/9250/9251 | ||
904 | ref Reference board, base config | ||
905 | m2-2 Some Gateway MX series laptops | ||
906 | m6 Some Gateway NX series laptops | ||
907 | |||
863 | STAC9227/9228/9229/927x | 908 | STAC9227/9228/9229/927x |
864 | ref Reference board | 909 | ref Reference board |
865 | 3stack D965 3stack | 910 | 3stack D965 3stack |
@@ -974,6 +1019,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. | |||
974 | Module for Envy24HT (VT/ICE1724), Envy24PT (VT1720) based PCI sound cards. | 1019 | Module for Envy24HT (VT/ICE1724), Envy24PT (VT1720) based PCI sound cards. |
975 | * MidiMan M Audio Revolution 5.1 | 1020 | * MidiMan M Audio Revolution 5.1 |
976 | * MidiMan M Audio Revolution 7.1 | 1021 | * MidiMan M Audio Revolution 7.1 |
1022 | * MidiMan M Audio Audiophile 192 | ||
977 | * AMP Ltd AUDIO2000 | 1023 | * AMP Ltd AUDIO2000 |
978 | * TerraTec Aureon 5.1 Sky | 1024 | * TerraTec Aureon 5.1 Sky |
979 | * TerraTec Aureon 7.1 Space | 1025 | * TerraTec Aureon 7.1 Space |
@@ -993,7 +1039,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. | |||
993 | 1039 | ||
994 | model - Use the given board model, one of the following: | 1040 | model - Use the given board model, one of the following: |
995 | revo51, revo71, amp2000, prodigy71, prodigy71lt, | 1041 | revo51, revo71, amp2000, prodigy71, prodigy71lt, |
996 | prodigy192, aureon51, aureon71, universe, | 1042 | prodigy192, aureon51, aureon71, universe, ap192, |
997 | k8x800, phase22, phase28, ms300, av710 | 1043 | k8x800, phase22, phase28, ms300, av710 |
998 | 1044 | ||
999 | This module supports multiple cards and autoprobe. | 1045 | This module supports multiple cards and autoprobe. |
@@ -1049,6 +1095,9 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. | |||
1049 | buggy_semaphore - Enable workaround for hardwares with buggy | 1095 | buggy_semaphore - Enable workaround for hardwares with buggy |
1050 | semaphores (e.g. on some ASUS laptops) | 1096 | semaphores (e.g. on some ASUS laptops) |
1051 | (default off) | 1097 | (default off) |
1098 | spdif_aclink - Use S/PDIF over AC-link instead of direct connection | ||
1099 | from the controller chip | ||
1100 | (0 = off, 1 = on, -1 = default) | ||
1052 | 1101 | ||
1053 | This module supports one chip and autoprobe. | 1102 | This module supports one chip and autoprobe. |
1054 | 1103 | ||
@@ -1371,6 +1420,13 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. | |||
1371 | 1420 | ||
1372 | This module supports multiple cards. | 1421 | This module supports multiple cards. |
1373 | 1422 | ||
1423 | Module snd-portman2x4 | ||
1424 | --------------------- | ||
1425 | |||
1426 | Module for Midiman Portman 2x4 parallel port MIDI interface | ||
1427 | |||
1428 | This module supports multiple cards. | ||
1429 | |||
1374 | Module snd-powermac (on ppc only) | 1430 | Module snd-powermac (on ppc only) |
1375 | --------------------------------- | 1431 | --------------------------------- |
1376 | 1432 | ||
diff --git a/Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl b/Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl index 1f3ae3e32d69..c4d2e3507af9 100644 --- a/Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl +++ b/Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl | |||
@@ -36,7 +36,7 @@ | |||
36 | </bookinfo> | 36 | </bookinfo> |
37 | 37 | ||
38 | <chapter><title>Management of Cards and Devices</title> | 38 | <chapter><title>Management of Cards and Devices</title> |
39 | <sect1><title>Card Managment</title> | 39 | <sect1><title>Card Management</title> |
40 | !Esound/core/init.c | 40 | !Esound/core/init.c |
41 | </sect1> | 41 | </sect1> |
42 | <sect1><title>Device Components</title> | 42 | <sect1><title>Device Components</title> |
@@ -59,7 +59,7 @@ | |||
59 | <sect1><title>PCM Format Helpers</title> | 59 | <sect1><title>PCM Format Helpers</title> |
60 | !Esound/core/pcm_misc.c | 60 | !Esound/core/pcm_misc.c |
61 | </sect1> | 61 | </sect1> |
62 | <sect1><title>PCM Memory Managment</title> | 62 | <sect1><title>PCM Memory Management</title> |
63 | !Esound/core/pcm_memory.c | 63 | !Esound/core/pcm_memory.c |
64 | </sect1> | 64 | </sect1> |
65 | </chapter> | 65 | </chapter> |
diff --git a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl index ccd0a953953d..74d3a35b59bc 100644 --- a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl +++ b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl | |||
@@ -1360,8 +1360,7 @@ | |||
1360 | <informalexample> | 1360 | <informalexample> |
1361 | <programlisting> | 1361 | <programlisting> |
1362 | <![CDATA[ | 1362 | <![CDATA[ |
1363 | static irqreturn_t snd_mychip_interrupt(int irq, void *dev_id, | 1363 | static irqreturn_t snd_mychip_interrupt(int irq, void *dev_id) |
1364 | struct pt_regs *regs) | ||
1365 | { | 1364 | { |
1366 | struct mychip *chip = dev_id; | 1365 | struct mychip *chip = dev_id; |
1367 | .... | 1366 | .... |
@@ -2127,7 +2126,7 @@ | |||
2127 | accessible via <constant>substream->runtime</constant>. | 2126 | accessible via <constant>substream->runtime</constant>. |
2128 | This runtime pointer holds the various information; it holds | 2127 | This runtime pointer holds the various information; it holds |
2129 | the copy of hw_params and sw_params configurations, the buffer | 2128 | the copy of hw_params and sw_params configurations, the buffer |
2130 | pointers, mmap records, spinlocks, etc. Almost everyhing you | 2129 | pointers, mmap records, spinlocks, etc. Almost everything you |
2131 | need for controlling the PCM can be found there. | 2130 | need for controlling the PCM can be found there. |
2132 | </para> | 2131 | </para> |
2133 | 2132 | ||
@@ -2340,7 +2339,7 @@ struct _snd_pcm_runtime { | |||
2340 | 2339 | ||
2341 | <para> | 2340 | <para> |
2342 | When the PCM substreams can be synchronized (typically, | 2341 | When the PCM substreams can be synchronized (typically, |
2343 | synchorinized start/stop of a playback and a capture streams), | 2342 | synchronized start/stop of a playback and a capture streams), |
2344 | you can give <constant>SNDRV_PCM_INFO_SYNC_START</constant>, | 2343 | you can give <constant>SNDRV_PCM_INFO_SYNC_START</constant>, |
2345 | too. In this case, you'll need to check the linked-list of | 2344 | too. In this case, you'll need to check the linked-list of |
2346 | PCM substreams in the trigger callback. This will be | 2345 | PCM substreams in the trigger callback. This will be |
@@ -3062,8 +3061,7 @@ struct _snd_pcm_runtime { | |||
3062 | <title>Interrupt Handler Case #1</title> | 3061 | <title>Interrupt Handler Case #1</title> |
3063 | <programlisting> | 3062 | <programlisting> |
3064 | <![CDATA[ | 3063 | <![CDATA[ |
3065 | static irqreturn_t snd_mychip_interrupt(int irq, void *dev_id, | 3064 | static irqreturn_t snd_mychip_interrupt(int irq, void *dev_id) |
3066 | struct pt_regs *regs) | ||
3067 | { | 3065 | { |
3068 | struct mychip *chip = dev_id; | 3066 | struct mychip *chip = dev_id; |
3069 | spin_lock(&chip->lock); | 3067 | spin_lock(&chip->lock); |
@@ -3106,8 +3104,7 @@ struct _snd_pcm_runtime { | |||
3106 | <title>Interrupt Handler Case #2</title> | 3104 | <title>Interrupt Handler Case #2</title> |
3107 | <programlisting> | 3105 | <programlisting> |
3108 | <![CDATA[ | 3106 | <![CDATA[ |
3109 | static irqreturn_t snd_mychip_interrupt(int irq, void *dev_id, | 3107 | static irqreturn_t snd_mychip_interrupt(int irq, void *dev_id) |
3110 | struct pt_regs *regs) | ||
3111 | { | 3108 | { |
3112 | struct mychip *chip = dev_id; | 3109 | struct mychip *chip = dev_id; |
3113 | spin_lock(&chip->lock); | 3110 | spin_lock(&chip->lock); |
@@ -3247,7 +3244,7 @@ struct _snd_pcm_runtime { | |||
3247 | You can even define your own constraint rules. | 3244 | You can even define your own constraint rules. |
3248 | For example, let's suppose my_chip can manage a substream of 1 channel | 3245 | For example, let's suppose my_chip can manage a substream of 1 channel |
3249 | if and only if the format is S16_LE, otherwise it supports any format | 3246 | if and only if the format is S16_LE, otherwise it supports any format |
3250 | specified in the <structname>snd_pcm_hardware</structname> stucture (or in any | 3247 | specified in the <structname>snd_pcm_hardware</structname> structure (or in any |
3251 | other constraint_list). You can build a rule like this: | 3248 | other constraint_list). You can build a rule like this: |
3252 | 3249 | ||
3253 | <example> | 3250 | <example> |
@@ -3691,16 +3688,6 @@ struct _snd_pcm_runtime { | |||
3691 | </para> | 3688 | </para> |
3692 | 3689 | ||
3693 | <para> | 3690 | <para> |
3694 | Here, the chip instance is retrieved via | ||
3695 | <function>snd_kcontrol_chip()</function> macro. This macro | ||
3696 | just accesses to kcontrol->private_data. The | ||
3697 | kcontrol->private_data field is | ||
3698 | given as the argument of <function>snd_ctl_new()</function> | ||
3699 | (see the later subsection | ||
3700 | <link linkend="control-interface-constructor"><citetitle>Constructor</citetitle></link>). | ||
3701 | </para> | ||
3702 | |||
3703 | <para> | ||
3704 | The <structfield>value</structfield> field is depending on | 3691 | The <structfield>value</structfield> field is depending on |
3705 | the type of control as well as on info callback. For example, | 3692 | the type of control as well as on info callback. For example, |
3706 | the sb driver uses this field to store the register offset, | 3693 | the sb driver uses this field to store the register offset, |
@@ -3780,7 +3767,7 @@ struct _snd_pcm_runtime { | |||
3780 | <para> | 3767 | <para> |
3781 | Like <structfield>get</structfield> callback, | 3768 | Like <structfield>get</structfield> callback, |
3782 | when the control has more than one elements, | 3769 | when the control has more than one elements, |
3783 | all elemehts must be evaluated in this callback, too. | 3770 | all elements must be evaluated in this callback, too. |
3784 | </para> | 3771 | </para> |
3785 | </section> | 3772 | </section> |
3786 | 3773 | ||
@@ -5541,12 +5528,12 @@ struct _snd_pcm_runtime { | |||
5541 | #ifdef CONFIG_PM | 5528 | #ifdef CONFIG_PM |
5542 | static int snd_my_suspend(struct pci_dev *pci, pm_message_t state) | 5529 | static int snd_my_suspend(struct pci_dev *pci, pm_message_t state) |
5543 | { | 5530 | { |
5544 | .... /* do things for suspsend */ | 5531 | .... /* do things for suspend */ |
5545 | return 0; | 5532 | return 0; |
5546 | } | 5533 | } |
5547 | static int snd_my_resume(struct pci_dev *pci) | 5534 | static int snd_my_resume(struct pci_dev *pci) |
5548 | { | 5535 | { |
5549 | .... /* do things for suspsend */ | 5536 | .... /* do things for suspend */ |
5550 | return 0; | 5537 | return 0; |
5551 | } | 5538 | } |
5552 | #endif | 5539 | #endif |
@@ -6111,7 +6098,7 @@ struct _snd_pcm_runtime { | |||
6111 | <!-- ****************************************************** --> | 6098 | <!-- ****************************************************** --> |
6112 | <!-- Acknowledgments --> | 6099 | <!-- Acknowledgments --> |
6113 | <!-- ****************************************************** --> | 6100 | <!-- ****************************************************** --> |
6114 | <chapter id="acknowledments"> | 6101 | <chapter id="acknowledgments"> |
6115 | <title>Acknowledgments</title> | 6102 | <title>Acknowledgments</title> |
6116 | <para> | 6103 | <para> |
6117 | I would like to thank Phil Kerr for his help for improvement and | 6104 | I would like to thank Phil Kerr for his help for improvement and |
diff --git a/Documentation/sound/alsa/hda_codec.txt b/Documentation/sound/alsa/hda_codec.txt index 0be57ed81302..4eaae2a45534 100644 --- a/Documentation/sound/alsa/hda_codec.txt +++ b/Documentation/sound/alsa/hda_codec.txt | |||
@@ -277,11 +277,11 @@ Helper Functions | |||
277 | snd_hda_get_codec_name() stores the codec name on the given string. | 277 | snd_hda_get_codec_name() stores the codec name on the given string. |
278 | 278 | ||
279 | snd_hda_check_board_config() can be used to obtain the configuration | 279 | snd_hda_check_board_config() can be used to obtain the configuration |
280 | information matching with the device. Define the table with struct | 280 | information matching with the device. Define the model string table |
281 | hda_board_config entries (zero-terminated), and pass it to the | 281 | and the table with struct snd_pci_quirk entries (zero-terminated), |
282 | function. The function checks the modelname given as a module | 282 | and pass it to the function. The function checks the modelname given |
283 | parameter, and PCI subsystem IDs. If the matching entry is found, it | 283 | as a module parameter, and PCI subsystem IDs. If the matching entry |
284 | returns the config field value. | 284 | is found, it returns the config field value. |
285 | 285 | ||
286 | snd_hda_add_new_ctls() can be used to create and add control entries. | 286 | snd_hda_add_new_ctls() can be used to create and add control entries. |
287 | Pass the zero-terminated array of struct snd_kcontrol_new. The same array | 287 | Pass the zero-terminated array of struct snd_kcontrol_new. The same array |
diff --git a/Documentation/sound/alsa/soc/DAI.txt b/Documentation/sound/alsa/soc/DAI.txt new file mode 100644 index 000000000000..58cbfd01ea8f --- /dev/null +++ b/Documentation/sound/alsa/soc/DAI.txt | |||
@@ -0,0 +1,56 @@ | |||
1 | ASoC currently supports the three main Digital Audio Interfaces (DAI) found on | ||
2 | SoC controllers and portable audio CODECS today, namely AC97, I2S and PCM. | ||
3 | |||
4 | |||
5 | AC97 | ||
6 | ==== | ||
7 | |||
8 | AC97 is a five wire interface commonly found on many PC sound cards. It is | ||
9 | now also popular in many portable devices. This DAI has a reset line and time | ||
10 | multiplexes its data on its SDATA_OUT (playback) and SDATA_IN (capture) lines. | ||
11 | The bit clock (BCLK) is always driven by the CODEC (usually 12.288MHz) and the | ||
12 | frame (FRAME) (usually 48kHz) is always driven by the controller. Each AC97 | ||
13 | frame is 21uS long and is divided into 13 time slots. | ||
14 | |||
15 | The AC97 specification can be found at :- | ||
16 | http://www.intel.com/design/chipsets/audio/ac97_r23.pdf | ||
17 | |||
18 | |||
19 | I2S | ||
20 | === | ||
21 | |||
22 | I2S is a common 4 wire DAI used in HiFi, STB and portable devices. The Tx and | ||
23 | Rx lines are used for audio transmision, whilst the bit clock (BCLK) and | ||
24 | left/right clock (LRC) synchronise the link. I2S is flexible in that either the | ||
25 | controller or CODEC can drive (master) the BCLK and LRC clock lines. Bit clock | ||
26 | usually varies depending on the sample rate and the master system clock | ||
27 | (SYSCLK). LRCLK is the same as the sample rate. A few devices support separate | ||
28 | ADC and DAC LRCLK's, this allows for similtanious capture and playback at | ||
29 | different sample rates. | ||
30 | |||
31 | I2S has several different operating modes:- | ||
32 | |||
33 | o I2S - MSB is transmitted on the falling edge of the first BCLK after LRC | ||
34 | transition. | ||
35 | |||
36 | o Left Justified - MSB is transmitted on transition of LRC. | ||
37 | |||
38 | o Right Justified - MSB is transmitted sample size BCLK's before LRC | ||
39 | transition. | ||
40 | |||
41 | PCM | ||
42 | === | ||
43 | |||
44 | PCM is another 4 wire interface, very similar to I2S, that can support a more | ||
45 | flexible protocol. It has bit clock (BCLK) and sync (SYNC) lines that are used | ||
46 | to synchronise the link whilst the Tx and Rx lines are used to transmit and | ||
47 | receive the audio data. Bit clock usually varies depending on sample rate | ||
48 | whilst sync runs at the sample rate. PCM also supports Time Division | ||
49 | Multiplexing (TDM) in that several devices can use the bus similtaniuosly (This | ||
50 | is sometimes referred to as network mode). | ||
51 | |||
52 | Common PCM operating modes:- | ||
53 | |||
54 | o Mode A - MSB is transmitted on falling edge of first BCLK after FRAME/SYNC. | ||
55 | |||
56 | o Mode B - MSB is transmitted on rising edge of FRAME/SYNC. | ||
diff --git a/Documentation/sound/alsa/soc/clocking.txt b/Documentation/sound/alsa/soc/clocking.txt new file mode 100644 index 000000000000..e93960d53a1e --- /dev/null +++ b/Documentation/sound/alsa/soc/clocking.txt | |||
@@ -0,0 +1,51 @@ | |||
1 | Audio Clocking | ||
2 | ============== | ||
3 | |||
4 | This text describes the audio clocking terms in ASoC and digital audio in | ||
5 | general. Note: Audio clocking can be complex ! | ||
6 | |||
7 | |||
8 | Master Clock | ||
9 | ------------ | ||
10 | |||
11 | Every audio subsystem is driven by a master clock (sometimes refered to as MCLK | ||
12 | or SYSCLK). This audio master clock can be derived from a number of sources | ||
13 | (e.g. crystal, PLL, CPU clock) and is responsible for producing the correct | ||
14 | audio playback and capture sample rates. | ||
15 | |||
16 | Some master clocks (e.g. PLL's and CPU based clocks) are configuarble in that | ||
17 | their speed can be altered by software (depending on the system use and to save | ||
18 | power). Other master clocks are fixed at at set frequency (i.e. crystals). | ||
19 | |||
20 | |||
21 | DAI Clocks | ||
22 | ---------- | ||
23 | The Digital Audio Interface is usually driven by a Bit Clock (often referred to | ||
24 | as BCLK). This clock is used to drive the digital audio data across the link | ||
25 | between the codec and CPU. | ||
26 | |||
27 | The DAI also has a frame clock to signal the start of each audio frame. This | ||
28 | clock is sometimes referred to as LRC (left right clock) or FRAME. This clock | ||
29 | runs at exactly the sample rate (LRC = Rate). | ||
30 | |||
31 | Bit Clock can be generated as follows:- | ||
32 | |||
33 | BCLK = MCLK / x | ||
34 | |||
35 | or | ||
36 | |||
37 | BCLK = LRC * x | ||
38 | |||
39 | or | ||
40 | |||
41 | BCLK = LRC * Channels * Word Size | ||
42 | |||
43 | This relationship depends on the codec or SoC CPU in particular. In general | ||
44 | it's best to configure BCLK to the lowest possible speed (depending on your | ||
45 | rate, number of channels and wordsize) to save on power. | ||
46 | |||
47 | It's also desireable to use the codec (if possible) to drive (or master) the | ||
48 | audio clocks as it's usually gives more accurate sample rates than the CPU. | ||
49 | |||
50 | |||
51 | |||
diff --git a/Documentation/sound/alsa/soc/codec.txt b/Documentation/sound/alsa/soc/codec.txt new file mode 100644 index 000000000000..48983c75aad9 --- /dev/null +++ b/Documentation/sound/alsa/soc/codec.txt | |||
@@ -0,0 +1,197 @@ | |||
1 | ASoC Codec Driver | ||
2 | ================= | ||
3 | |||
4 | The codec driver is generic and hardware independent code that configures the | ||
5 | codec to provide audio capture and playback. It should contain no code that is | ||
6 | specific to the target platform or machine. All platform and machine specific | ||
7 | code should be added to the platform and machine drivers respectively. | ||
8 | |||
9 | Each codec driver *must* provide the following features:- | ||
10 | |||
11 | 1) Codec DAI and PCM configuration | ||
12 | 2) Codec control IO - using I2C, 3 Wire(SPI) or both API's | ||
13 | 3) Mixers and audio controls | ||
14 | 4) Codec audio operations | ||
15 | |||
16 | Optionally, codec drivers can also provide:- | ||
17 | |||
18 | 5) DAPM description. | ||
19 | 6) DAPM event handler. | ||
20 | 7) DAC Digital mute control. | ||
21 | |||
22 | It's probably best to use this guide in conjuction with the existing codec | ||
23 | driver code in sound/soc/codecs/ | ||
24 | |||
25 | ASoC Codec driver breakdown | ||
26 | =========================== | ||
27 | |||
28 | 1 - Codec DAI and PCM configuration | ||
29 | ----------------------------------- | ||
30 | Each codec driver must have a struct snd_soc_codec_dai to define it's DAI and | ||
31 | PCM's capablities and operations. This struct is exported so that it can be | ||
32 | registered with the core by your machine driver. | ||
33 | |||
34 | e.g. | ||
35 | |||
36 | struct snd_soc_codec_dai wm8731_dai = { | ||
37 | .name = "WM8731", | ||
38 | /* playback capabilities */ | ||
39 | .playback = { | ||
40 | .stream_name = "Playback", | ||
41 | .channels_min = 1, | ||
42 | .channels_max = 2, | ||
43 | .rates = WM8731_RATES, | ||
44 | .formats = WM8731_FORMATS,}, | ||
45 | /* capture capabilities */ | ||
46 | .capture = { | ||
47 | .stream_name = "Capture", | ||
48 | .channels_min = 1, | ||
49 | .channels_max = 2, | ||
50 | .rates = WM8731_RATES, | ||
51 | .formats = WM8731_FORMATS,}, | ||
52 | /* pcm operations - see section 4 below */ | ||
53 | .ops = { | ||
54 | .prepare = wm8731_pcm_prepare, | ||
55 | .hw_params = wm8731_hw_params, | ||
56 | .shutdown = wm8731_shutdown, | ||
57 | }, | ||
58 | /* DAI operations - see DAI.txt */ | ||
59 | .dai_ops = { | ||
60 | .digital_mute = wm8731_mute, | ||
61 | .set_sysclk = wm8731_set_dai_sysclk, | ||
62 | .set_fmt = wm8731_set_dai_fmt, | ||
63 | } | ||
64 | }; | ||
65 | EXPORT_SYMBOL_GPL(wm8731_dai); | ||
66 | |||
67 | |||
68 | 2 - Codec control IO | ||
69 | -------------------- | ||
70 | The codec can ususally be controlled via an I2C or SPI style interface (AC97 | ||
71 | combines control with data in the DAI). The codec drivers will have to provide | ||
72 | functions to read and write the codec registers along with supplying a register | ||
73 | cache:- | ||
74 | |||
75 | /* IO control data and register cache */ | ||
76 | void *control_data; /* codec control (i2c/3wire) data */ | ||
77 | void *reg_cache; | ||
78 | |||
79 | Codec read/write should do any data formatting and call the hardware read write | ||
80 | below to perform the IO. These functions are called by the core and alsa when | ||
81 | performing DAPM or changing the mixer:- | ||
82 | |||
83 | unsigned int (*read)(struct snd_soc_codec *, unsigned int); | ||
84 | int (*write)(struct snd_soc_codec *, unsigned int, unsigned int); | ||
85 | |||
86 | Codec hardware IO functions - usually points to either the I2C, SPI or AC97 | ||
87 | read/write:- | ||
88 | |||
89 | hw_write_t hw_write; | ||
90 | hw_read_t hw_read; | ||
91 | |||
92 | |||
93 | 3 - Mixers and audio controls | ||
94 | ----------------------------- | ||
95 | All the codec mixers and audio controls can be defined using the convenience | ||
96 | macros defined in soc.h. | ||
97 | |||
98 | #define SOC_SINGLE(xname, reg, shift, mask, invert) | ||
99 | |||
100 | Defines a single control as follows:- | ||
101 | |||
102 | xname = Control name e.g. "Playback Volume" | ||
103 | reg = codec register | ||
104 | shift = control bit(s) offset in register | ||
105 | mask = control bit size(s) e.g. mask of 7 = 3 bits | ||
106 | invert = the control is inverted | ||
107 | |||
108 | Other macros include:- | ||
109 | |||
110 | #define SOC_DOUBLE(xname, reg, shift_left, shift_right, mask, invert) | ||
111 | |||
112 | A stereo control | ||
113 | |||
114 | #define SOC_DOUBLE_R(xname, reg_left, reg_right, shift, mask, invert) | ||
115 | |||
116 | A stereo control spanning 2 registers | ||
117 | |||
118 | #define SOC_ENUM_SINGLE(xreg, xshift, xmask, xtexts) | ||
119 | |||
120 | Defines an single enumerated control as follows:- | ||
121 | |||
122 | xreg = register | ||
123 | xshift = control bit(s) offset in register | ||
124 | xmask = control bit(s) size | ||
125 | xtexts = pointer to array of strings that describe each setting | ||
126 | |||
127 | #define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, xtexts) | ||
128 | |||
129 | Defines a stereo enumerated control | ||
130 | |||
131 | |||
132 | 4 - Codec Audio Operations | ||
133 | -------------------------- | ||
134 | The codec driver also supports the following alsa operations:- | ||
135 | |||
136 | /* SoC audio ops */ | ||
137 | struct snd_soc_ops { | ||
138 | int (*startup)(struct snd_pcm_substream *); | ||
139 | void (*shutdown)(struct snd_pcm_substream *); | ||
140 | int (*hw_params)(struct snd_pcm_substream *, struct snd_pcm_hw_params *); | ||
141 | int (*hw_free)(struct snd_pcm_substream *); | ||
142 | int (*prepare)(struct snd_pcm_substream *); | ||
143 | }; | ||
144 | |||
145 | Please refer to the alsa driver PCM documentation for details. | ||
146 | http://www.alsa-project.org/~iwai/writing-an-alsa-driver/c436.htm | ||
147 | |||
148 | |||
149 | 5 - DAPM description. | ||
150 | --------------------- | ||
151 | The Dynamic Audio Power Management description describes the codec's power | ||
152 | components, their relationships and registers to the ASoC core. Please read | ||
153 | dapm.txt for details of building the description. | ||
154 | |||
155 | Please also see the examples in other codec drivers. | ||
156 | |||
157 | |||
158 | 6 - DAPM event handler | ||
159 | ---------------------- | ||
160 | This function is a callback that handles codec domain PM calls and system | ||
161 | domain PM calls (e.g. suspend and resume). It's used to put the codec to sleep | ||
162 | when not in use. | ||
163 | |||
164 | Power states:- | ||
165 | |||
166 | SNDRV_CTL_POWER_D0: /* full On */ | ||
167 | /* vref/mid, clk and osc on, active */ | ||
168 | |||
169 | SNDRV_CTL_POWER_D1: /* partial On */ | ||
170 | SNDRV_CTL_POWER_D2: /* partial On */ | ||
171 | |||
172 | SNDRV_CTL_POWER_D3hot: /* Off, with power */ | ||
173 | /* everything off except vref/vmid, inactive */ | ||
174 | |||
175 | SNDRV_CTL_POWER_D3cold: /* Everything Off, without power */ | ||
176 | |||
177 | |||
178 | 7 - Codec DAC digital mute control. | ||
179 | ------------------------------------ | ||
180 | Most codecs have a digital mute before the DAC's that can be used to minimise | ||
181 | any system noise. The mute stops any digital data from entering the DAC. | ||
182 | |||
183 | A callback can be created that is called by the core for each codec DAI when the | ||
184 | mute is applied or freed. | ||
185 | |||
186 | i.e. | ||
187 | |||
188 | static int wm8974_mute(struct snd_soc_codec *codec, | ||
189 | struct snd_soc_codec_dai *dai, int mute) | ||
190 | { | ||
191 | u16 mute_reg = wm8974_read_reg_cache(codec, WM8974_DAC) & 0xffbf; | ||
192 | if(mute) | ||
193 | wm8974_write(codec, WM8974_DAC, mute_reg | 0x40); | ||
194 | else | ||
195 | wm8974_write(codec, WM8974_DAC, mute_reg); | ||
196 | return 0; | ||
197 | } | ||
diff --git a/Documentation/sound/alsa/soc/dapm.txt b/Documentation/sound/alsa/soc/dapm.txt new file mode 100644 index 000000000000..c11877f5b4a1 --- /dev/null +++ b/Documentation/sound/alsa/soc/dapm.txt | |||
@@ -0,0 +1,297 @@ | |||
1 | Dynamic Audio Power Management for Portable Devices | ||
2 | =================================================== | ||
3 | |||
4 | 1. Description | ||
5 | ============== | ||
6 | |||
7 | Dynamic Audio Power Management (DAPM) is designed to allow portable Linux devices | ||
8 | to use the minimum amount of power within the audio subsystem at all times. It | ||
9 | is independent of other kernel PM and as such, can easily co-exist with the | ||
10 | other PM systems. | ||
11 | |||
12 | DAPM is also completely transparent to all user space applications as all power | ||
13 | switching is done within the ASoC core. No code changes or recompiling are | ||
14 | required for user space applications. DAPM makes power switching descisions based | ||
15 | upon any audio stream (capture/playback) activity and audio mixer settings | ||
16 | within the device. | ||
17 | |||
18 | DAPM spans the whole machine. It covers power control within the entire audio | ||
19 | subsystem, this includes internal codec power blocks and machine level power | ||
20 | systems. | ||
21 | |||
22 | There are 4 power domains within DAPM | ||
23 | |||
24 | 1. Codec domain - VREF, VMID (core codec and audio power) | ||
25 | Usually controlled at codec probe/remove and suspend/resume, although | ||
26 | can be set at stream time if power is not needed for sidetone, etc. | ||
27 | |||
28 | 2. Platform/Machine domain - physically connected inputs and outputs | ||
29 | Is platform/machine and user action specific, is configured by the | ||
30 | machine driver and responds to asynchronous events e.g when HP | ||
31 | are inserted | ||
32 | |||
33 | 3. Path domain - audio susbsystem signal paths | ||
34 | Automatically set when mixer and mux settings are changed by the user. | ||
35 | e.g. alsamixer, amixer. | ||
36 | |||
37 | 4. Stream domain - DAC's and ADC's. | ||
38 | Enabled and disabled when stream playback/capture is started and | ||
39 | stopped respectively. e.g. aplay, arecord. | ||
40 | |||
41 | All DAPM power switching descisons are made automatically by consulting an audio | ||
42 | routing map of the whole machine. This map is specific to each machine and | ||
43 | consists of the interconnections between every audio component (including | ||
44 | internal codec components). All audio components that effect power are called | ||
45 | widgets hereafter. | ||
46 | |||
47 | |||
48 | 2. DAPM Widgets | ||
49 | =============== | ||
50 | |||
51 | Audio DAPM widgets fall into a number of types:- | ||
52 | |||
53 | o Mixer - Mixes several analog signals into a single analog signal. | ||
54 | o Mux - An analog switch that outputs only 1 of it's inputs. | ||
55 | o PGA - A programmable gain amplifier or attenuation widget. | ||
56 | o ADC - Analog to Digital Converter | ||
57 | o DAC - Digital to Analog Converter | ||
58 | o Switch - An analog switch | ||
59 | o Input - A codec input pin | ||
60 | o Output - A codec output pin | ||
61 | o Headphone - Headphone (and optional Jack) | ||
62 | o Mic - Mic (and optional Jack) | ||
63 | o Line - Line Input/Output (and optional Jack) | ||
64 | o Speaker - Speaker | ||
65 | o Pre - Special PRE widget (exec before all others) | ||
66 | o Post - Special POST widget (exec after all others) | ||
67 | |||
68 | (Widgets are defined in include/sound/soc-dapm.h) | ||
69 | |||
70 | Widgets are usually added in the codec driver and the machine driver. There are | ||
71 | convience macros defined in soc-dapm.h that can be used to quickly build a | ||
72 | list of widgets of the codecs and machines DAPM widgets. | ||
73 | |||
74 | Most widgets have a name, register, shift and invert. Some widgets have extra | ||
75 | parameters for stream name and kcontrols. | ||
76 | |||
77 | |||
78 | 2.1 Stream Domain Widgets | ||
79 | ------------------------- | ||
80 | |||
81 | Stream Widgets relate to the stream power domain and only consist of ADC's | ||
82 | (analog to digital converters) and DAC's (digital to analog converters). | ||
83 | |||
84 | Stream widgets have the following format:- | ||
85 | |||
86 | SND_SOC_DAPM_DAC(name, stream name, reg, shift, invert), | ||
87 | |||
88 | NOTE: the stream name must match the corresponding stream name in your codecs | ||
89 | snd_soc_codec_dai. | ||
90 | |||
91 | e.g. stream widgets for HiFi playback and capture | ||
92 | |||
93 | SND_SOC_DAPM_DAC("HiFi DAC", "HiFi Playback", REG, 3, 1), | ||
94 | SND_SOC_DAPM_ADC("HiFi ADC", "HiFi Capture", REG, 2, 1), | ||
95 | |||
96 | |||
97 | 2.2 Path Domain Widgets | ||
98 | ----------------------- | ||
99 | |||
100 | Path domain widgets have a ability to control or effect the audio signal or | ||
101 | audio paths within the audio subsystem. They have the following form:- | ||
102 | |||
103 | SND_SOC_DAPM_PGA(name, reg, shift, invert, controls, num_controls) | ||
104 | |||
105 | Any widget kcontrols can be set using the controls and num_controls members. | ||
106 | |||
107 | e.g. Mixer widget (the kcontrols are declared first) | ||
108 | |||
109 | /* Output Mixer */ | ||
110 | static const snd_kcontrol_new_t wm8731_output_mixer_controls[] = { | ||
111 | SOC_DAPM_SINGLE("Line Bypass Switch", WM8731_APANA, 3, 1, 0), | ||
112 | SOC_DAPM_SINGLE("Mic Sidetone Switch", WM8731_APANA, 5, 1, 0), | ||
113 | SOC_DAPM_SINGLE("HiFi Playback Switch", WM8731_APANA, 4, 1, 0), | ||
114 | }; | ||
115 | |||
116 | SND_SOC_DAPM_MIXER("Output Mixer", WM8731_PWR, 4, 1, wm8731_output_mixer_controls, | ||
117 | ARRAY_SIZE(wm8731_output_mixer_controls)), | ||
118 | |||
119 | |||
120 | 2.3 Platform/Machine domain Widgets | ||
121 | ----------------------------------- | ||
122 | |||
123 | Machine widgets are different from codec widgets in that they don't have a | ||
124 | codec register bit associated with them. A machine widget is assigned to each | ||
125 | machine audio component (non codec) that can be independently powered. e.g. | ||
126 | |||
127 | o Speaker Amp | ||
128 | o Microphone Bias | ||
129 | o Jack connectors | ||
130 | |||
131 | A machine widget can have an optional call back. | ||
132 | |||
133 | e.g. Jack connector widget for an external Mic that enables Mic Bias | ||
134 | when the Mic is inserted:- | ||
135 | |||
136 | static int spitz_mic_bias(struct snd_soc_dapm_widget* w, int event) | ||
137 | { | ||
138 | if(SND_SOC_DAPM_EVENT_ON(event)) | ||
139 | set_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_MIC_BIAS); | ||
140 | else | ||
141 | reset_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_MIC_BIAS); | ||
142 | |||
143 | return 0; | ||
144 | } | ||
145 | |||
146 | SND_SOC_DAPM_MIC("Mic Jack", spitz_mic_bias), | ||
147 | |||
148 | |||
149 | 2.4 Codec Domain | ||
150 | ---------------- | ||
151 | |||
152 | The Codec power domain has no widgets and is handled by the codecs DAPM event | ||
153 | handler. This handler is called when the codec powerstate is changed wrt to any | ||
154 | stream event or by kernel PM events. | ||
155 | |||
156 | |||
157 | 2.5 Virtual Widgets | ||
158 | ------------------- | ||
159 | |||
160 | Sometimes widgets exist in the codec or machine audio map that don't have any | ||
161 | corresponding register bit for power control. In this case it's necessary to | ||
162 | create a virtual widget - a widget with no control bits e.g. | ||
163 | |||
164 | SND_SOC_DAPM_MIXER("AC97 Mixer", SND_SOC_DAPM_NOPM, 0, 0, NULL, 0), | ||
165 | |||
166 | This can be used to merge to signal paths together in software. | ||
167 | |||
168 | After all the widgets have been defined, they can then be added to the DAPM | ||
169 | subsystem individually with a call to snd_soc_dapm_new_control(). | ||
170 | |||
171 | |||
172 | 3. Codec Widget Interconnections | ||
173 | ================================ | ||
174 | |||
175 | Widgets are connected to each other within the codec and machine by audio | ||
176 | paths (called interconnections). Each interconnection must be defined in order | ||
177 | to create a map of all audio paths between widgets. | ||
178 | This is easiest with a diagram of the codec (and schematic of the machine audio | ||
179 | system), as it requires joining widgets together via their audio signal paths. | ||
180 | |||
181 | i.e. from the WM8731 codec's output mixer (wm8731.c) | ||
182 | |||
183 | The WM8731 output mixer has 3 inputs (sources) | ||
184 | |||
185 | 1. Line Bypass Input | ||
186 | 2. DAC (HiFi playback) | ||
187 | 3. Mic Sidetone Input | ||
188 | |||
189 | Each input in this example has a kcontrol associated with it (defined in example | ||
190 | above) and is connected to the output mixer via it's kcontrol name. We can now | ||
191 | connect the destination widget (wrt audio signal) with it's source widgets. | ||
192 | |||
193 | /* output mixer */ | ||
194 | {"Output Mixer", "Line Bypass Switch", "Line Input"}, | ||
195 | {"Output Mixer", "HiFi Playback Switch", "DAC"}, | ||
196 | {"Output Mixer", "Mic Sidetone Switch", "Mic Bias"}, | ||
197 | |||
198 | So we have :- | ||
199 | |||
200 | Destination Widget <=== Path Name <=== Source Widget | ||
201 | |||
202 | Or:- | ||
203 | |||
204 | Sink, Path, Source | ||
205 | |||
206 | Or :- | ||
207 | |||
208 | "Output Mixer" is connected to the "DAC" via the "HiFi Playback Switch". | ||
209 | |||
210 | When there is no path name connecting widgets (e.g. a direct connection) we | ||
211 | pass NULL for the path name. | ||
212 | |||
213 | Interconnections are created with a call to:- | ||
214 | |||
215 | snd_soc_dapm_connect_input(codec, sink, path, source); | ||
216 | |||
217 | Finally, snd_soc_dapm_new_widgets(codec) must be called after all widgets and | ||
218 | interconnections have been registered with the core. This causes the core to | ||
219 | scan the codec and machine so that the internal DAPM state matches the | ||
220 | physical state of the machine. | ||
221 | |||
222 | |||
223 | 3.1 Machine Widget Interconnections | ||
224 | ----------------------------------- | ||
225 | Machine widget interconnections are created in the same way as codec ones and | ||
226 | directly connect the codec pins to machine level widgets. | ||
227 | |||
228 | e.g. connects the speaker out codec pins to the internal speaker. | ||
229 | |||
230 | /* ext speaker connected to codec pins LOUT2, ROUT2 */ | ||
231 | {"Ext Spk", NULL , "ROUT2"}, | ||
232 | {"Ext Spk", NULL , "LOUT2"}, | ||
233 | |||
234 | This allows the DAPM to power on and off pins that are connected (and in use) | ||
235 | and pins that are NC respectively. | ||
236 | |||
237 | |||
238 | 4 Endpoint Widgets | ||
239 | =================== | ||
240 | An endpoint is a start or end point (widget) of an audio signal within the | ||
241 | machine and includes the codec. e.g. | ||
242 | |||
243 | o Headphone Jack | ||
244 | o Internal Speaker | ||
245 | o Internal Mic | ||
246 | o Mic Jack | ||
247 | o Codec Pins | ||
248 | |||
249 | When a codec pin is NC it can be marked as not used with a call to | ||
250 | |||
251 | snd_soc_dapm_set_endpoint(codec, "Widget Name", 0); | ||
252 | |||
253 | The last argument is 0 for inactive and 1 for active. This way the pin and its | ||
254 | input widget will never be powered up and consume power. | ||
255 | |||
256 | This also applies to machine widgets. e.g. if a headphone is connected to a | ||
257 | jack then the jack can be marked active. If the headphone is removed, then | ||
258 | the headphone jack can be marked inactive. | ||
259 | |||
260 | |||
261 | 5 DAPM Widget Events | ||
262 | ==================== | ||
263 | |||
264 | Some widgets can register their interest with the DAPM core in PM events. | ||
265 | e.g. A Speaker with an amplifier registers a widget so the amplifier can be | ||
266 | powered only when the spk is in use. | ||
267 | |||
268 | /* turn speaker amplifier on/off depending on use */ | ||
269 | static int corgi_amp_event(struct snd_soc_dapm_widget *w, int event) | ||
270 | { | ||
271 | if (SND_SOC_DAPM_EVENT_ON(event)) | ||
272 | set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_APM_ON); | ||
273 | else | ||
274 | reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_APM_ON); | ||
275 | |||
276 | return 0; | ||
277 | } | ||
278 | |||
279 | /* corgi machine dapm widgets */ | ||
280 | static const struct snd_soc_dapm_widget wm8731_dapm_widgets = | ||
281 | SND_SOC_DAPM_SPK("Ext Spk", corgi_amp_event); | ||
282 | |||
283 | Please see soc-dapm.h for all other widgets that support events. | ||
284 | |||
285 | |||
286 | 5.1 Event types | ||
287 | --------------- | ||
288 | |||
289 | The following event types are supported by event widgets. | ||
290 | |||
291 | /* dapm event types */ | ||
292 | #define SND_SOC_DAPM_PRE_PMU 0x1 /* before widget power up */ | ||
293 | #define SND_SOC_DAPM_POST_PMU 0x2 /* after widget power up */ | ||
294 | #define SND_SOC_DAPM_PRE_PMD 0x4 /* before widget power down */ | ||
295 | #define SND_SOC_DAPM_POST_PMD 0x8 /* after widget power down */ | ||
296 | #define SND_SOC_DAPM_PRE_REG 0x10 /* before audio path setup */ | ||
297 | #define SND_SOC_DAPM_POST_REG 0x20 /* after audio path setup */ | ||
diff --git a/Documentation/sound/alsa/soc/machine.txt b/Documentation/sound/alsa/soc/machine.txt new file mode 100644 index 000000000000..72bd222f2a21 --- /dev/null +++ b/Documentation/sound/alsa/soc/machine.txt | |||
@@ -0,0 +1,113 @@ | |||
1 | ASoC Machine Driver | ||
2 | =================== | ||
3 | |||
4 | The ASoC machine (or board) driver is the code that glues together the platform | ||
5 | and codec drivers. | ||
6 | |||
7 | The machine driver can contain codec and platform specific code. It registers | ||
8 | the audio subsystem with the kernel as a platform device and is represented by | ||
9 | the following struct:- | ||
10 | |||
11 | /* SoC machine */ | ||
12 | struct snd_soc_machine { | ||
13 | char *name; | ||
14 | |||
15 | int (*probe)(struct platform_device *pdev); | ||
16 | int (*remove)(struct platform_device *pdev); | ||
17 | |||
18 | /* the pre and post PM functions are used to do any PM work before and | ||
19 | * after the codec and DAI's do any PM work. */ | ||
20 | int (*suspend_pre)(struct platform_device *pdev, pm_message_t state); | ||
21 | int (*suspend_post)(struct platform_device *pdev, pm_message_t state); | ||
22 | int (*resume_pre)(struct platform_device *pdev); | ||
23 | int (*resume_post)(struct platform_device *pdev); | ||
24 | |||
25 | /* machine stream operations */ | ||
26 | struct snd_soc_ops *ops; | ||
27 | |||
28 | /* CPU <--> Codec DAI links */ | ||
29 | struct snd_soc_dai_link *dai_link; | ||
30 | int num_links; | ||
31 | }; | ||
32 | |||
33 | probe()/remove() | ||
34 | ---------------- | ||
35 | probe/remove are optional. Do any machine specific probe here. | ||
36 | |||
37 | |||
38 | suspend()/resume() | ||
39 | ------------------ | ||
40 | The machine driver has pre and post versions of suspend and resume to take care | ||
41 | of any machine audio tasks that have to be done before or after the codec, DAI's | ||
42 | and DMA is suspended and resumed. Optional. | ||
43 | |||
44 | |||
45 | Machine operations | ||
46 | ------------------ | ||
47 | The machine specific audio operations can be set here. Again this is optional. | ||
48 | |||
49 | |||
50 | Machine DAI Configuration | ||
51 | ------------------------- | ||
52 | The machine DAI configuration glues all the codec and CPU DAI's together. It can | ||
53 | also be used to set up the DAI system clock and for any machine related DAI | ||
54 | initialisation e.g. the machine audio map can be connected to the codec audio | ||
55 | map, unconnnected codec pins can be set as such. Please see corgi.c, spitz.c | ||
56 | for examples. | ||
57 | |||
58 | struct snd_soc_dai_link is used to set up each DAI in your machine. e.g. | ||
59 | |||
60 | /* corgi digital audio interface glue - connects codec <--> CPU */ | ||
61 | static struct snd_soc_dai_link corgi_dai = { | ||
62 | .name = "WM8731", | ||
63 | .stream_name = "WM8731", | ||
64 | .cpu_dai = &pxa_i2s_dai, | ||
65 | .codec_dai = &wm8731_dai, | ||
66 | .init = corgi_wm8731_init, | ||
67 | .ops = &corgi_ops, | ||
68 | }; | ||
69 | |||
70 | struct snd_soc_machine then sets up the machine with it's DAI's. e.g. | ||
71 | |||
72 | /* corgi audio machine driver */ | ||
73 | static struct snd_soc_machine snd_soc_machine_corgi = { | ||
74 | .name = "Corgi", | ||
75 | .dai_link = &corgi_dai, | ||
76 | .num_links = 1, | ||
77 | }; | ||
78 | |||
79 | |||
80 | Machine Audio Subsystem | ||
81 | ----------------------- | ||
82 | |||
83 | The machine soc device glues the platform, machine and codec driver together. | ||
84 | Private data can also be set here. e.g. | ||
85 | |||
86 | /* corgi audio private data */ | ||
87 | static struct wm8731_setup_data corgi_wm8731_setup = { | ||
88 | .i2c_address = 0x1b, | ||
89 | }; | ||
90 | |||
91 | /* corgi audio subsystem */ | ||
92 | static struct snd_soc_device corgi_snd_devdata = { | ||
93 | .machine = &snd_soc_machine_corgi, | ||
94 | .platform = &pxa2xx_soc_platform, | ||
95 | .codec_dev = &soc_codec_dev_wm8731, | ||
96 | .codec_data = &corgi_wm8731_setup, | ||
97 | }; | ||
98 | |||
99 | |||
100 | Machine Power Map | ||
101 | ----------------- | ||
102 | |||
103 | The machine driver can optionally extend the codec power map and to become an | ||
104 | audio power map of the audio subsystem. This allows for automatic power up/down | ||
105 | of speaker/HP amplifiers, etc. Codec pins can be connected to the machines jack | ||
106 | sockets in the machine init function. See soc/pxa/spitz.c and dapm.txt for | ||
107 | details. | ||
108 | |||
109 | |||
110 | Machine Controls | ||
111 | ---------------- | ||
112 | |||
113 | Machine specific audio mixer controls can be added in the dai init function. \ No newline at end of file | ||
diff --git a/Documentation/sound/alsa/soc/overview.txt b/Documentation/sound/alsa/soc/overview.txt new file mode 100644 index 000000000000..753c5cc5984a --- /dev/null +++ b/Documentation/sound/alsa/soc/overview.txt | |||
@@ -0,0 +1,83 @@ | |||
1 | ALSA SoC Layer | ||
2 | ============== | ||
3 | |||
4 | The overall project goal of the ALSA System on Chip (ASoC) layer is to provide | ||
5 | better ALSA support for embedded system on chip procesors (e.g. pxa2xx, au1x00, | ||
6 | iMX, etc) and portable audio codecs. Currently there is some support in the | ||
7 | kernel for SoC audio, however it has some limitations:- | ||
8 | |||
9 | * Currently, codec drivers are often tightly coupled to the underlying SoC | ||
10 | cpu. This is not ideal and leads to code duplication i.e. Linux now has 4 | ||
11 | different wm8731 drivers for 4 different SoC platforms. | ||
12 | |||
13 | * There is no standard method to signal user initiated audio events. | ||
14 | e.g. Headphone/Mic insertion, Headphone/Mic detection after an insertion | ||
15 | event. These are quite common events on portable devices and ofter require | ||
16 | machine specific code to re route audio, enable amps etc after such an event. | ||
17 | |||
18 | * Current drivers tend to power up the entire codec when playing | ||
19 | (or recording) audio. This is fine for a PC, but tends to waste a lot of | ||
20 | power on portable devices. There is also no support for saving power via | ||
21 | changing codec oversampling rates, bias currents, etc. | ||
22 | |||
23 | |||
24 | ASoC Design | ||
25 | =========== | ||
26 | |||
27 | The ASoC layer is designed to address these issues and provide the following | ||
28 | features :- | ||
29 | |||
30 | * Codec independence. Allows reuse of codec drivers on other platforms | ||
31 | and machines. | ||
32 | |||
33 | * Easy I2S/PCM audio interface setup between codec and SoC. Each SoC interface | ||
34 | and codec registers it's audio interface capabilities with the core and are | ||
35 | subsequently matched and configured when the application hw params are known. | ||
36 | |||
37 | * Dynamic Audio Power Management (DAPM). DAPM automatically sets the codec to | ||
38 | it's minimum power state at all times. This includes powering up/down | ||
39 | internal power blocks depending on the internal codec audio routing and any | ||
40 | active streams. | ||
41 | |||
42 | * Pop and click reduction. Pops and clicks can be reduced by powering the | ||
43 | codec up/down in the correct sequence (including using digital mute). ASoC | ||
44 | signals the codec when to change power states. | ||
45 | |||
46 | * Machine specific controls: Allow machines to add controls to the sound card | ||
47 | e.g. volume control for speaker amp. | ||
48 | |||
49 | To achieve all this, ASoC basically splits an embedded audio system into 3 | ||
50 | components :- | ||
51 | |||
52 | * Codec driver: The codec driver is platform independent and contains audio | ||
53 | controls, audio interface capabilities, codec dapm definition and codec IO | ||
54 | functions. | ||
55 | |||
56 | * Platform driver: The platform driver contains the audio dma engine and audio | ||
57 | interface drivers (e.g. I2S, AC97, PCM) for that platform. | ||
58 | |||
59 | * Machine driver: The machine driver handles any machine specific controls and | ||
60 | audio events. i.e. turing on an amp at start of playback. | ||
61 | |||
62 | |||
63 | Documentation | ||
64 | ============= | ||
65 | |||
66 | The documentation is spilt into the following sections:- | ||
67 | |||
68 | overview.txt: This file. | ||
69 | |||
70 | codec.txt: Codec driver internals. | ||
71 | |||
72 | DAI.txt: Description of Digital Audio Interface standards and how to configure | ||
73 | a DAI within your codec and CPU DAI drivers. | ||
74 | |||
75 | dapm.txt: Dynamic Audio Power Management | ||
76 | |||
77 | platform.txt: Platform audio DMA and DAI. | ||
78 | |||
79 | machine.txt: Machine driver internals. | ||
80 | |||
81 | pop_clicks.txt: How to minimise audio artifacts. | ||
82 | |||
83 | clocking.txt: ASoC clocking for best power performance. \ No newline at end of file | ||
diff --git a/Documentation/sound/alsa/soc/platform.txt b/Documentation/sound/alsa/soc/platform.txt new file mode 100644 index 000000000000..e95b16d5a53b --- /dev/null +++ b/Documentation/sound/alsa/soc/platform.txt | |||
@@ -0,0 +1,58 @@ | |||
1 | ASoC Platform Driver | ||
2 | ==================== | ||
3 | |||
4 | An ASoC platform driver can be divided into audio DMA and SoC DAI configuration | ||
5 | and control. The platform drivers only target the SoC CPU and must have no board | ||
6 | specific code. | ||
7 | |||
8 | Audio DMA | ||
9 | ========= | ||
10 | |||
11 | The platform DMA driver optionally supports the following alsa operations:- | ||
12 | |||
13 | /* SoC audio ops */ | ||
14 | struct snd_soc_ops { | ||
15 | int (*startup)(struct snd_pcm_substream *); | ||
16 | void (*shutdown)(struct snd_pcm_substream *); | ||
17 | int (*hw_params)(struct snd_pcm_substream *, struct snd_pcm_hw_params *); | ||
18 | int (*hw_free)(struct snd_pcm_substream *); | ||
19 | int (*prepare)(struct snd_pcm_substream *); | ||
20 | int (*trigger)(struct snd_pcm_substream *, int); | ||
21 | }; | ||
22 | |||
23 | The platform driver exports it's DMA functionailty via struct snd_soc_platform:- | ||
24 | |||
25 | struct snd_soc_platform { | ||
26 | char *name; | ||
27 | |||
28 | int (*probe)(struct platform_device *pdev); | ||
29 | int (*remove)(struct platform_device *pdev); | ||
30 | int (*suspend)(struct platform_device *pdev, struct snd_soc_cpu_dai *cpu_dai); | ||
31 | int (*resume)(struct platform_device *pdev, struct snd_soc_cpu_dai *cpu_dai); | ||
32 | |||
33 | /* pcm creation and destruction */ | ||
34 | int (*pcm_new)(struct snd_card *, struct snd_soc_codec_dai *, struct snd_pcm *); | ||
35 | void (*pcm_free)(struct snd_pcm *); | ||
36 | |||
37 | /* platform stream ops */ | ||
38 | struct snd_pcm_ops *pcm_ops; | ||
39 | }; | ||
40 | |||
41 | Please refer to the alsa driver documentation for details of audio DMA. | ||
42 | http://www.alsa-project.org/~iwai/writing-an-alsa-driver/c436.htm | ||
43 | |||
44 | An example DMA driver is soc/pxa/pxa2xx-pcm.c | ||
45 | |||
46 | |||
47 | SoC DAI Drivers | ||
48 | =============== | ||
49 | |||
50 | Each SoC DAI driver must provide the following features:- | ||
51 | |||
52 | 1) Digital audio interface (DAI) description | ||
53 | 2) Digital audio interface configuration | ||
54 | 3) PCM's description | ||
55 | 4) Sysclk configuration | ||
56 | 5) Suspend and resume (optional) | ||
57 | |||
58 | Please see codec.txt for a description of items 1 - 4. | ||
diff --git a/Documentation/sound/alsa/soc/pops_clicks.txt b/Documentation/sound/alsa/soc/pops_clicks.txt new file mode 100644 index 000000000000..2cf7ee5b3d74 --- /dev/null +++ b/Documentation/sound/alsa/soc/pops_clicks.txt | |||
@@ -0,0 +1,52 @@ | |||
1 | Audio Pops and Clicks | ||
2 | ===================== | ||
3 | |||
4 | Pops and clicks are unwanted audio artifacts caused by the powering up and down | ||
5 | of components within the audio subsystem. This is noticable on PC's when an | ||
6 | audio module is either loaded or unloaded (at module load time the sound card is | ||
7 | powered up and causes a popping noise on the speakers). | ||
8 | |||
9 | Pops and clicks can be more frequent on portable systems with DAPM. This is | ||
10 | because the components within the subsystem are being dynamically powered | ||
11 | depending on the audio usage and this can subsequently cause a small pop or | ||
12 | click every time a component power state is changed. | ||
13 | |||
14 | |||
15 | Minimising Playback Pops and Clicks | ||
16 | =================================== | ||
17 | |||
18 | Playback pops in portable audio subsystems cannot be completely eliminated atm, | ||
19 | however future audio codec hardware will have better pop and click supression. | ||
20 | Pops can be reduced within playback by powering the audio components in a | ||
21 | specific order. This order is different for startup and shutdown and follows | ||
22 | some basic rules:- | ||
23 | |||
24 | Startup Order :- DAC --> Mixers --> Output PGA --> Digital Unmute | ||
25 | |||
26 | Shutdown Order :- Digital Mute --> Output PGA --> Mixers --> DAC | ||
27 | |||
28 | This assumes that the codec PCM output path from the DAC is via a mixer and then | ||
29 | a PGA (programmable gain amplifier) before being output to the speakers. | ||
30 | |||
31 | |||
32 | Minimising Capture Pops and Clicks | ||
33 | ================================== | ||
34 | |||
35 | Capture artifacts are somewhat easier to get rid as we can delay activating the | ||
36 | ADC until all the pops have occured. This follows similar power rules to | ||
37 | playback in that components are powered in a sequence depending upon stream | ||
38 | startup or shutdown. | ||
39 | |||
40 | Startup Order - Input PGA --> Mixers --> ADC | ||
41 | |||
42 | Shutdown Order - ADC --> Mixers --> Input PGA | ||
43 | |||
44 | |||
45 | Zipper Noise | ||
46 | ============ | ||
47 | An unwanted zipper noise can occur within the audio playback or capture stream | ||
48 | when a volume control is changed near its maximum gain value. The zipper noise | ||
49 | is heard when the gain increase or decrease changes the mean audio signal | ||
50 | amplitude too quickly. It can be minimised by enabling the zero cross setting | ||
51 | for each volume control. The ZC forces the gain change to occur when the signal | ||
52 | crosses the zero amplitude line. | ||
diff --git a/MAINTAINERS b/MAINTAINERS index 6ddae2bb6821..f2a79481f1c1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -3037,6 +3037,12 @@ M: perex@suse.cz | |||
3037 | L: alsa-devel@alsa-project.org | 3037 | L: alsa-devel@alsa-project.org |
3038 | S: Maintained | 3038 | S: Maintained |
3039 | 3039 | ||
3040 | SOUND - SOC LAYER / DYNAMIC AUDIO POWER MANAGEMENT | ||
3041 | P: Liam Girdwood | ||
3042 | M: liam.girdwood@wolfsonmicro.com | ||
3043 | L: alsa-devel@alsa-project.org | ||
3044 | S: Supported | ||
3045 | |||
3040 | SPI SUBSYSTEM | 3046 | SPI SUBSYSTEM |
3041 | P: David Brownell | 3047 | P: David Brownell |
3042 | M: dbrownell@users.sourceforge.net | 3048 | M: dbrownell@users.sourceforge.net |
diff --git a/drivers/input/touchscreen/ucb1400_ts.c b/drivers/input/touchscreen/ucb1400_ts.c index 4358a0a78eaa..c7db4032ef02 100644 --- a/drivers/input/touchscreen/ucb1400_ts.c +++ b/drivers/input/touchscreen/ucb1400_ts.c | |||
@@ -83,7 +83,7 @@ | |||
83 | 83 | ||
84 | 84 | ||
85 | struct ucb1400 { | 85 | struct ucb1400 { |
86 | ac97_t *ac97; | 86 | struct snd_ac97 *ac97; |
87 | struct input_dev *ts_idev; | 87 | struct input_dev *ts_idev; |
88 | 88 | ||
89 | int irq; | 89 | int irq; |
diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h index d38778f2fbec..6e7ec4c76178 100644 --- a/include/linux/i2c-id.h +++ b/include/linux/i2c-id.h | |||
@@ -115,6 +115,8 @@ | |||
115 | #define I2C_DRIVERID_KS0127 86 /* Samsung ks0127 video decoder */ | 115 | #define I2C_DRIVERID_KS0127 86 /* Samsung ks0127 video decoder */ |
116 | #define I2C_DRIVERID_TLV320AIC23B 87 /* TI TLV320AIC23B audio codec */ | 116 | #define I2C_DRIVERID_TLV320AIC23B 87 /* TI TLV320AIC23B audio codec */ |
117 | #define I2C_DRIVERID_ISL1208 88 /* Intersil ISL1208 RTC */ | 117 | #define I2C_DRIVERID_ISL1208 88 /* Intersil ISL1208 RTC */ |
118 | #define I2C_DRIVERID_WM8731 89 /* Wolfson WM8731 audio codec */ | ||
119 | #define I2C_DRIVERID_WM8750 90 /* Wolfson WM8750 audio codec */ | ||
118 | 120 | ||
119 | #define I2C_DRIVERID_I2CDEV 900 | 121 | #define I2C_DRIVERID_I2CDEV 900 |
120 | #define I2C_DRIVERID_ARP 902 /* SMBus ARP Client */ | 122 | #define I2C_DRIVERID_ARP 902 /* SMBus ARP Client */ |
diff --git a/include/sound/ac97_codec.h b/include/sound/ac97_codec.h index 33720397a904..246ac23534bd 100644 --- a/include/sound/ac97_codec.h +++ b/include/sound/ac97_codec.h | |||
@@ -375,6 +375,7 @@ | |||
375 | #define AC97_SCAP_DETECT_BY_VENDOR (1<<8) /* use vendor registers for read tests */ | 375 | #define AC97_SCAP_DETECT_BY_VENDOR (1<<8) /* use vendor registers for read tests */ |
376 | #define AC97_SCAP_NO_SPDIF (1<<9) /* don't build SPDIF controls */ | 376 | #define AC97_SCAP_NO_SPDIF (1<<9) /* don't build SPDIF controls */ |
377 | #define AC97_SCAP_EAPD_LED (1<<10) /* EAPD as mute LED */ | 377 | #define AC97_SCAP_EAPD_LED (1<<10) /* EAPD as mute LED */ |
378 | #define AC97_SCAP_POWER_SAVE (1<<11) /* capable for aggresive power-saving */ | ||
378 | 379 | ||
379 | /* ac97->flags */ | 380 | /* ac97->flags */ |
380 | #define AC97_HAS_PC_BEEP (1<<0) /* force PC Speaker usage */ | 381 | #define AC97_HAS_PC_BEEP (1<<0) /* force PC Speaker usage */ |
@@ -425,6 +426,7 @@ struct snd_ac97_build_ops { | |||
425 | 426 | ||
426 | struct snd_ac97_bus_ops { | 427 | struct snd_ac97_bus_ops { |
427 | void (*reset) (struct snd_ac97 *ac97); | 428 | void (*reset) (struct snd_ac97 *ac97); |
429 | void (*warm_reset)(struct snd_ac97 *ac97); | ||
428 | void (*write) (struct snd_ac97 *ac97, unsigned short reg, unsigned short val); | 430 | void (*write) (struct snd_ac97 *ac97, unsigned short reg, unsigned short val); |
429 | unsigned short (*read) (struct snd_ac97 *ac97, unsigned short reg); | 431 | unsigned short (*read) (struct snd_ac97 *ac97, unsigned short reg); |
430 | void (*wait) (struct snd_ac97 *ac97); | 432 | void (*wait) (struct snd_ac97 *ac97); |
@@ -501,6 +503,7 @@ struct snd_ac97 { | |||
501 | unsigned short id[3]; // codec IDs (lower 16-bit word) | 503 | unsigned short id[3]; // codec IDs (lower 16-bit word) |
502 | unsigned short pcmreg[3]; // PCM registers | 504 | unsigned short pcmreg[3]; // PCM registers |
503 | unsigned short codec_cfg[3]; // CODEC_CFG bits | 505 | unsigned short codec_cfg[3]; // CODEC_CFG bits |
506 | unsigned char swap_mic_linein; // AD1986/AD1986A only | ||
504 | } ad18xx; | 507 | } ad18xx; |
505 | unsigned int dev_flags; /* device specific */ | 508 | unsigned int dev_flags; /* device specific */ |
506 | } spec; | 509 | } spec; |
@@ -510,7 +513,6 @@ struct snd_ac97 { | |||
510 | 513 | ||
511 | #ifdef CONFIG_SND_AC97_POWER_SAVE | 514 | #ifdef CONFIG_SND_AC97_POWER_SAVE |
512 | unsigned int power_up; /* power states */ | 515 | unsigned int power_up; /* power states */ |
513 | struct workqueue_struct *power_workq; | ||
514 | struct delayed_work power_work; | 516 | struct delayed_work power_work; |
515 | #endif | 517 | #endif |
516 | struct device dev; | 518 | struct device dev; |
diff --git a/include/sound/ad1848.h b/include/sound/ad1848.h index c8de6f83338f..b2c3f00a9b35 100644 --- a/include/sound/ad1848.h +++ b/include/sound/ad1848.h | |||
@@ -185,7 +185,7 @@ struct ad1848_mix_elem { | |||
185 | int index; | 185 | int index; |
186 | int type; | 186 | int type; |
187 | unsigned long private_value; | 187 | unsigned long private_value; |
188 | unsigned int *tlv; | 188 | const unsigned int *tlv; |
189 | }; | 189 | }; |
190 | 190 | ||
191 | #define AD1848_SINGLE(xname, xindex, reg, shift, mask, invert) \ | 191 | #define AD1848_SINGLE(xname, xindex, reg, shift, mask, invert) \ |
diff --git a/include/sound/ak4114.h b/include/sound/ak4114.h index 2ee061625fd0..c149d3b2558b 100644 --- a/include/sound/ak4114.h +++ b/include/sound/ak4114.h | |||
@@ -181,7 +181,6 @@ struct ak4114 { | |||
181 | unsigned long ccrc_errors; | 181 | unsigned long ccrc_errors; |
182 | unsigned char rcs0; | 182 | unsigned char rcs0; |
183 | unsigned char rcs1; | 183 | unsigned char rcs1; |
184 | struct workqueue_struct *workqueue; | ||
185 | struct delayed_work work; | 184 | struct delayed_work work; |
186 | void *change_callback_private; | 185 | void *change_callback_private; |
187 | void (*change_callback)(struct ak4114 *ak4114, unsigned char c0, unsigned char c1); | 186 | void (*change_callback)(struct ak4114 *ak4114, unsigned char c0, unsigned char c1); |
@@ -189,7 +188,7 @@ struct ak4114 { | |||
189 | 188 | ||
190 | int snd_ak4114_create(struct snd_card *card, | 189 | int snd_ak4114_create(struct snd_card *card, |
191 | ak4114_read_t *read, ak4114_write_t *write, | 190 | ak4114_read_t *read, ak4114_write_t *write, |
192 | unsigned char pgm[7], unsigned char txcsb[5], | 191 | const unsigned char pgm[7], const unsigned char txcsb[5], |
193 | void *private_data, struct ak4114 **r_ak4114); | 192 | void *private_data, struct ak4114 **r_ak4114); |
194 | void snd_ak4114_reg_write(struct ak4114 *ak4114, unsigned char reg, unsigned char mask, unsigned char val); | 193 | void snd_ak4114_reg_write(struct ak4114 *ak4114, unsigned char reg, unsigned char mask, unsigned char val); |
195 | void snd_ak4114_reinit(struct ak4114 *ak4114); | 194 | void snd_ak4114_reinit(struct ak4114 *ak4114); |
diff --git a/include/sound/ak4117.h b/include/sound/ak4117.h index 2b96c32f06fd..d650d52e3d29 100644 --- a/include/sound/ak4117.h +++ b/include/sound/ak4117.h | |||
@@ -178,7 +178,7 @@ struct ak4117 { | |||
178 | }; | 178 | }; |
179 | 179 | ||
180 | int snd_ak4117_create(struct snd_card *card, ak4117_read_t *read, ak4117_write_t *write, | 180 | int snd_ak4117_create(struct snd_card *card, ak4117_read_t *read, ak4117_write_t *write, |
181 | unsigned char pgm[5], void *private_data, struct ak4117 **r_ak4117); | 181 | const unsigned char pgm[5], void *private_data, struct ak4117 **r_ak4117); |
182 | void snd_ak4117_reg_write(struct ak4117 *ak4117, unsigned char reg, unsigned char mask, unsigned char val); | 182 | void snd_ak4117_reg_write(struct ak4117 *ak4117, unsigned char reg, unsigned char mask, unsigned char val); |
183 | void snd_ak4117_reinit(struct ak4117 *ak4117); | 183 | void snd_ak4117_reinit(struct ak4117 *ak4117); |
184 | int snd_ak4117_build(struct ak4117 *ak4117, struct snd_pcm_substream *capture_substream); | 184 | int snd_ak4117_build(struct ak4117 *ak4117, struct snd_pcm_substream *capture_substream); |
diff --git a/include/sound/ak4xxx-adda.h b/include/sound/ak4xxx-adda.h index d0deca669b92..aa49dda4f410 100644 --- a/include/sound/ak4xxx-adda.h +++ b/include/sound/ak4xxx-adda.h | |||
@@ -50,6 +50,8 @@ struct snd_akm4xxx_adc_channel { | |||
50 | char *name; /* capture gain volume label */ | 50 | char *name; /* capture gain volume label */ |
51 | char *switch_name; /* capture switch */ | 51 | char *switch_name; /* capture switch */ |
52 | unsigned int num_channels; | 52 | unsigned int num_channels; |
53 | char *selector_name; /* capture source select label */ | ||
54 | const char **input_names; /* capture source names (NULL terminated) */ | ||
53 | }; | 55 | }; |
54 | 56 | ||
55 | struct snd_akm4xxx { | 57 | struct snd_akm4xxx { |
@@ -69,8 +71,8 @@ struct snd_akm4xxx { | |||
69 | } type; | 71 | } type; |
70 | 72 | ||
71 | /* (array) information of combined codecs */ | 73 | /* (array) information of combined codecs */ |
72 | struct snd_akm4xxx_dac_channel *dac_info; | 74 | const struct snd_akm4xxx_dac_channel *dac_info; |
73 | struct snd_akm4xxx_adc_channel *adc_info; | 75 | const struct snd_akm4xxx_adc_channel *adc_info; |
74 | 76 | ||
75 | struct snd_ak4xxx_ops ops; | 77 | struct snd_ak4xxx_ops ops; |
76 | }; | 78 | }; |
diff --git a/include/sound/control.h b/include/sound/control.h index 1de148b0fd94..72e759f619b1 100644 --- a/include/sound/control.h +++ b/include/sound/control.h | |||
@@ -49,7 +49,7 @@ struct snd_kcontrol_new { | |||
49 | snd_kcontrol_put_t *put; | 49 | snd_kcontrol_put_t *put; |
50 | union { | 50 | union { |
51 | snd_kcontrol_tlv_rw_t *c; | 51 | snd_kcontrol_tlv_rw_t *c; |
52 | unsigned int *p; | 52 | const unsigned int *p; |
53 | } tlv; | 53 | } tlv; |
54 | unsigned long private_value; | 54 | unsigned long private_value; |
55 | }; | 55 | }; |
@@ -69,7 +69,7 @@ struct snd_kcontrol { | |||
69 | snd_kcontrol_put_t *put; | 69 | snd_kcontrol_put_t *put; |
70 | union { | 70 | union { |
71 | snd_kcontrol_tlv_rw_t *c; | 71 | snd_kcontrol_tlv_rw_t *c; |
72 | unsigned int *p; | 72 | const unsigned int *p; |
73 | } tlv; | 73 | } tlv; |
74 | unsigned long private_value; | 74 | unsigned long private_value; |
75 | void *private_data; | 75 | void *private_data; |
@@ -108,7 +108,6 @@ typedef int (*snd_kctl_ioctl_func_t) (struct snd_card * card, | |||
108 | 108 | ||
109 | void snd_ctl_notify(struct snd_card * card, unsigned int mask, struct snd_ctl_elem_id * id); | 109 | void snd_ctl_notify(struct snd_card * card, unsigned int mask, struct snd_ctl_elem_id * id); |
110 | 110 | ||
111 | struct snd_kcontrol *snd_ctl_new(struct snd_kcontrol * kcontrol, unsigned int access); | ||
112 | struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new * kcontrolnew, void * private_data); | 111 | struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new * kcontrolnew, void * private_data); |
113 | void snd_ctl_free_one(struct snd_kcontrol * kcontrol); | 112 | void snd_ctl_free_one(struct snd_kcontrol * kcontrol); |
114 | int snd_ctl_add(struct snd_card * card, struct snd_kcontrol * kcontrol); | 113 | int snd_ctl_add(struct snd_card * card, struct snd_kcontrol * kcontrol); |
diff --git a/include/sound/core.h b/include/sound/core.h index 521f036cce99..4b9e609975ab 100644 --- a/include/sound/core.h +++ b/include/sound/core.h | |||
@@ -211,9 +211,40 @@ extern struct class *sound_class; | |||
211 | 211 | ||
212 | void snd_request_card(int card); | 212 | void snd_request_card(int card); |
213 | 213 | ||
214 | int snd_register_device(int type, struct snd_card *card, int dev, | 214 | int snd_register_device_for_dev(int type, struct snd_card *card, |
215 | const struct file_operations *f_ops, void *private_data, | 215 | int dev, |
216 | const char *name); | 216 | const struct file_operations *f_ops, |
217 | void *private_data, | ||
218 | const char *name, | ||
219 | struct device *device); | ||
220 | |||
221 | /** | ||
222 | * snd_register_device - Register the ALSA device file for the card | ||
223 | * @type: the device type, SNDRV_DEVICE_TYPE_XXX | ||
224 | * @card: the card instance | ||
225 | * @dev: the device index | ||
226 | * @f_ops: the file operations | ||
227 | * @private_data: user pointer for f_ops->open() | ||
228 | * @name: the device file name | ||
229 | * | ||
230 | * Registers an ALSA device file for the given card. | ||
231 | * The operators have to be set in reg parameter. | ||
232 | * | ||
233 | * This function uses the card's device pointer to link to the | ||
234 | * correct &struct device. | ||
235 | * | ||
236 | * Returns zero if successful, or a negative error code on failure. | ||
237 | */ | ||
238 | static inline int snd_register_device(int type, struct snd_card *card, int dev, | ||
239 | const struct file_operations *f_ops, | ||
240 | void *private_data, | ||
241 | const char *name) | ||
242 | { | ||
243 | return snd_register_device_for_dev(type, card, dev, f_ops, | ||
244 | private_data, name, | ||
245 | snd_card_get_device_link(card)); | ||
246 | } | ||
247 | |||
217 | int snd_unregister_device(int type, struct snd_card *card, int dev); | 248 | int snd_unregister_device(int type, struct snd_card *card, int dev); |
218 | void *snd_lookup_minor_data(unsigned int minor, int type); | 249 | void *snd_lookup_minor_data(unsigned int minor, int type); |
219 | int snd_add_device_sysfs_file(int type, struct snd_card *card, int dev, | 250 | int snd_add_device_sysfs_file(int type, struct snd_card *card, int dev, |
@@ -396,6 +427,29 @@ void snd_verbose_printd(const char *file, int line, const char *format, ...) | |||
396 | #endif | 427 | #endif |
397 | #endif | 428 | #endif |
398 | 429 | ||
399 | #include "typedefs.h" | 430 | /* PCI quirk list helper */ |
431 | struct snd_pci_quirk { | ||
432 | unsigned short subvendor; /* PCI subvendor ID */ | ||
433 | unsigned short subdevice; /* PCI subdevice ID */ | ||
434 | int value; /* value */ | ||
435 | #ifdef CONFIG_SND_DEBUG_DETECT | ||
436 | const char *name; /* name of the device (optional) */ | ||
437 | #endif | ||
438 | }; | ||
439 | |||
440 | #define _SND_PCI_QUIRK_ID(vend,dev) \ | ||
441 | .subvendor = (vend), .subdevice = (dev) | ||
442 | #define SND_PCI_QUIRK_ID(vend,dev) {_SND_PCI_QUIRK_ID(vend, dev)} | ||
443 | #ifdef CONFIG_SND_DEBUG_DETECT | ||
444 | #define SND_PCI_QUIRK(vend,dev,xname,val) \ | ||
445 | {_SND_PCI_QUIRK_ID(vend, dev), .value = (val), .name = (xname)} | ||
446 | #else | ||
447 | #define SND_PCI_QUIRK(vend,dev,xname,val) \ | ||
448 | {_SND_PCI_QUIRK_ID(vend, dev), .value = (val)} | ||
449 | #endif | ||
450 | |||
451 | const struct snd_pci_quirk * | ||
452 | snd_pci_quirk_lookup(struct pci_dev *pci, const struct snd_pci_quirk *list); | ||
453 | |||
400 | 454 | ||
401 | #endif /* __SOUND_CORE_H */ | 455 | #endif /* __SOUND_CORE_H */ |
diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index 3d3c1514cf71..eb7ce96ddf3a 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h | |||
@@ -188,7 +188,35 @@ | |||
188 | #define HCFG_LEGACYINT 0x00200000 /* 1 = legacy event captured. Write 1 to clear. */ | 188 | #define HCFG_LEGACYINT 0x00200000 /* 1 = legacy event captured. Write 1 to clear. */ |
189 | /* NOTE: The rest of the bits in this register */ | 189 | /* NOTE: The rest of the bits in this register */ |
190 | /* _are_ relevant under Linux. */ | 190 | /* _are_ relevant under Linux. */ |
191 | #define HCFG_CODECFORMAT_MASK 0x00070000 /* CODEC format */ | 191 | #define HCFG_PUSH_BUTTON_ENABLE 0x00100000 /* Enables Volume Inc/Dec and Mute functions */ |
192 | #define HCFG_BAUD_RATE 0x00080000 /* 0 = 48kHz, 1 = 44.1kHz */ | ||
193 | #define HCFG_EXPANDED_MEM 0x00040000 /* 1 = any 16M of 4G addr, 0 = 32M of 2G addr */ | ||
194 | #define HCFG_CODECFORMAT_MASK 0x00030000 /* CODEC format */ | ||
195 | |||
196 | /* Specific to Alice2, CA0102 */ | ||
197 | #define HCFG_CODECFORMAT_AC97_1 0x00000000 /* AC97 CODEC format -- Ver 1.03 */ | ||
198 | #define HCFG_CODECFORMAT_AC97_2 0x00010000 /* AC97 CODEC format -- Ver 2.1 */ | ||
199 | #define HCFG_AUTOMUTE_ASYNC 0x00008000 /* When set, the async sample rate convertors */ | ||
200 | /* will automatically mute their output when */ | ||
201 | /* they are not rate-locked to the external */ | ||
202 | /* async audio source */ | ||
203 | #define HCFG_AUTOMUTE_SPDIF 0x00004000 /* When set, the async sample rate convertors */ | ||
204 | /* will automatically mute their output when */ | ||
205 | /* the SPDIF V-bit indicates invalid audio */ | ||
206 | #define HCFG_EMU32_SLAVE 0x00002000 /* 0 = Master, 1 = Slave. Slave for EMU1010 */ | ||
207 | #define HCFG_SLOW_RAMP 0x00001000 /* Increases Send Smoothing time constant */ | ||
208 | /* 0x00000800 not used on Alice2 */ | ||
209 | #define HCFG_PHASE_TRACK_MASK 0x00000700 /* When set, forces corresponding input to */ | ||
210 | /* phase track the previous input. */ | ||
211 | /* I2S0 can phase track the last S/PDIF input */ | ||
212 | #define HCFG_I2S_ASRC_ENABLE 0x00000070 /* When set, enables asynchronous sample rate */ | ||
213 | /* conversion for the corresponding */ | ||
214 | /* I2S format input */ | ||
215 | /* Rest of HCFG 0x0000000f same as below. LOCKSOUNDCACHE etc. */ | ||
216 | |||
217 | |||
218 | |||
219 | /* Older chips */ | ||
192 | #define HCFG_CODECFORMAT_AC97 0x00000000 /* AC97 CODEC format -- Primary Output */ | 220 | #define HCFG_CODECFORMAT_AC97 0x00000000 /* AC97 CODEC format -- Primary Output */ |
193 | #define HCFG_CODECFORMAT_I2S 0x00010000 /* I2S CODEC format -- Secondary (Rear) Output */ | 221 | #define HCFG_CODECFORMAT_I2S 0x00010000 /* I2S CODEC format -- Secondary (Rear) Output */ |
194 | #define HCFG_GPINPUT0 0x00004000 /* External pin112 */ | 222 | #define HCFG_GPINPUT0 0x00004000 /* External pin112 */ |
@@ -432,6 +460,7 @@ | |||
432 | #define FXRT_CHANNELC 0x0f000000 /* Effects send bus number for channel's effects send C */ | 460 | #define FXRT_CHANNELC 0x0f000000 /* Effects send bus number for channel's effects send C */ |
433 | #define FXRT_CHANNELD 0xf0000000 /* Effects send bus number for channel's effects send D */ | 461 | #define FXRT_CHANNELD 0xf0000000 /* Effects send bus number for channel's effects send D */ |
434 | 462 | ||
463 | #define A_HR 0x0b /* High Resolution. 24bit playback from host to DSP. */ | ||
435 | #define MAPA 0x0c /* Cache map A */ | 464 | #define MAPA 0x0c /* Cache map A */ |
436 | 465 | ||
437 | #define MAPB 0x0d /* Cache map B */ | 466 | #define MAPB 0x0d /* Cache map B */ |
@@ -439,6 +468,8 @@ | |||
439 | #define MAP_PTE_MASK 0xffffe000 /* The 19 MSBs of the PTE indexed by the PTI */ | 468 | #define MAP_PTE_MASK 0xffffe000 /* The 19 MSBs of the PTE indexed by the PTI */ |
440 | #define MAP_PTI_MASK 0x00001fff /* The 13 bit index to one of the 8192 PTE dwords */ | 469 | #define MAP_PTI_MASK 0x00001fff /* The 13 bit index to one of the 8192 PTE dwords */ |
441 | 470 | ||
471 | /* 0x0e, 0x0f: Not used */ | ||
472 | |||
442 | #define ENVVOL 0x10 /* Volume envelope register */ | 473 | #define ENVVOL 0x10 /* Volume envelope register */ |
443 | #define ENVVOL_MASK 0x0000ffff /* Current value of volume envelope state variable */ | 474 | #define ENVVOL_MASK 0x0000ffff /* Current value of volume envelope state variable */ |
444 | /* 0x8000-n == 666*n usec delay */ | 475 | /* 0x8000-n == 666*n usec delay */ |
@@ -527,7 +558,7 @@ | |||
527 | /* NOTE: All channels contain internal variables; do */ | 558 | /* NOTE: All channels contain internal variables; do */ |
528 | /* not write to these locations. */ | 559 | /* not write to these locations. */ |
529 | 560 | ||
530 | /* 1f something */ | 561 | /* 0x1f: not used */ |
531 | 562 | ||
532 | #define CD0 0x20 /* Cache data 0 register */ | 563 | #define CD0 0x20 /* Cache data 0 register */ |
533 | #define CD1 0x21 /* Cache data 1 register */ | 564 | #define CD1 0x21 /* Cache data 1 register */ |
@@ -597,6 +628,8 @@ | |||
597 | #define FXWC_SPDIFLEFT (1<<22) /* 0x00400000 */ | 628 | #define FXWC_SPDIFLEFT (1<<22) /* 0x00400000 */ |
598 | #define FXWC_SPDIFRIGHT (1<<23) /* 0x00800000 */ | 629 | #define FXWC_SPDIFRIGHT (1<<23) /* 0x00800000 */ |
599 | 630 | ||
631 | #define A_TBLSZ ` 0x43 /* Effects Tank Internal Table Size. Only low byte or register used */ | ||
632 | |||
600 | #define TCBS 0x44 /* Tank cache buffer size register */ | 633 | #define TCBS 0x44 /* Tank cache buffer size register */ |
601 | #define TCBS_MASK 0x00000007 /* Tank cache buffer size field */ | 634 | #define TCBS_MASK 0x00000007 /* Tank cache buffer size field */ |
602 | #define TCBS_BUFFSIZE_16K 0x00000000 | 635 | #define TCBS_BUFFSIZE_16K 0x00000000 |
@@ -617,7 +650,7 @@ | |||
617 | #define FXBA 0x47 /* FX Buffer Address */ | 650 | #define FXBA 0x47 /* FX Buffer Address */ |
618 | #define FXBA_MASK 0xfffff000 /* 20 bit base address */ | 651 | #define FXBA_MASK 0xfffff000 /* 20 bit base address */ |
619 | 652 | ||
620 | /* 0x48 something - word access, defaults to 3f */ | 653 | #define A_HWM 0x48 /* High PCI Water Mark - word access, defaults to 3f */ |
621 | 654 | ||
622 | #define MICBS 0x49 /* Microphone buffer size register */ | 655 | #define MICBS 0x49 /* Microphone buffer size register */ |
623 | 656 | ||
@@ -661,6 +694,18 @@ | |||
661 | #define ADCBS_BUFSIZE_57344 0x0000001e | 694 | #define ADCBS_BUFSIZE_57344 0x0000001e |
662 | #define ADCBS_BUFSIZE_65536 0x0000001f | 695 | #define ADCBS_BUFSIZE_65536 0x0000001f |
663 | 696 | ||
697 | /* Current Send B, A Amounts */ | ||
698 | #define A_CSBA 0x4c | ||
699 | |||
700 | /* Current Send D, C Amounts */ | ||
701 | #define A_CSDC 0x4d | ||
702 | |||
703 | /* Current Send F, E Amounts */ | ||
704 | #define A_CSFE 0x4e | ||
705 | |||
706 | /* Current Send H, G Amounts */ | ||
707 | #define A_CSHG 0x4f | ||
708 | |||
664 | 709 | ||
665 | #define CDCS 0x50 /* CD-ROM digital channel status register */ | 710 | #define CDCS 0x50 /* CD-ROM digital channel status register */ |
666 | 711 | ||
@@ -668,6 +713,9 @@ | |||
668 | 713 | ||
669 | #define DBG 0x52 /* DO NOT PROGRAM THIS REGISTER!!! MAY DESTROY CHIP */ | 714 | #define DBG 0x52 /* DO NOT PROGRAM THIS REGISTER!!! MAY DESTROY CHIP */ |
670 | 715 | ||
716 | /* S/PDIF Input C Channel Status */ | ||
717 | #define A_SPSC 0x52 | ||
718 | |||
671 | #define REG53 0x53 /* DO NOT PROGRAM THIS REGISTER!!! MAY DESTROY CHIP */ | 719 | #define REG53 0x53 /* DO NOT PROGRAM THIS REGISTER!!! MAY DESTROY CHIP */ |
672 | 720 | ||
673 | #define A_DBG 0x53 | 721 | #define A_DBG 0x53 |
@@ -708,6 +756,8 @@ | |||
708 | #define SPCS_NOTAUDIODATA 0x00000002 /* 0 = Digital audio, 1 = not audio */ | 756 | #define SPCS_NOTAUDIODATA 0x00000002 /* 0 = Digital audio, 1 = not audio */ |
709 | #define SPCS_PROFESSIONAL 0x00000001 /* 0 = Consumer (IEC-958), 1 = pro (AES3-1992) */ | 757 | #define SPCS_PROFESSIONAL 0x00000001 /* 0 = Consumer (IEC-958), 1 = pro (AES3-1992) */ |
710 | 758 | ||
759 | /* 0x57: Not used */ | ||
760 | |||
711 | /* The 32-bit CLIx and SOLx registers all have one bit per channel control/status */ | 761 | /* The 32-bit CLIx and SOLx registers all have one bit per channel control/status */ |
712 | #define CLIEL 0x58 /* Channel loop interrupt enable low register */ | 762 | #define CLIEL 0x58 /* Channel loop interrupt enable low register */ |
713 | 763 | ||
@@ -733,6 +783,9 @@ | |||
733 | #define AC97SLOT_CNTR 0x10 /* Center enable */ | 783 | #define AC97SLOT_CNTR 0x10 /* Center enable */ |
734 | #define AC97SLOT_LFE 0x20 /* LFE enable */ | 784 | #define AC97SLOT_LFE 0x20 /* LFE enable */ |
735 | 785 | ||
786 | /* PCB Revision */ | ||
787 | #define A_PCB 0x5f | ||
788 | |||
736 | // NOTE: 0x60,61,62: 64-bit | 789 | // NOTE: 0x60,61,62: 64-bit |
737 | #define CDSRCS 0x60 /* CD-ROM Sample Rate Converter status register */ | 790 | #define CDSRCS 0x60 /* CD-ROM Sample Rate Converter status register */ |
738 | 791 | ||
@@ -780,9 +833,18 @@ | |||
780 | 833 | ||
781 | #define HLIPH 0x69 /* Channel half loop interrupt pending high register */ | 834 | #define HLIPH 0x69 /* Channel half loop interrupt pending high register */ |
782 | 835 | ||
783 | // 0x6a,6b,6c used for some recording | 836 | /* S/PDIF Host Record Index (bypasses SRC) */ |
784 | // 0x6d unused | 837 | #define A_SPRI 0x6a |
785 | // 0x6e,6f - tanktable base / offset | 838 | /* S/PDIF Host Record Address */ |
839 | #define A_SPRA 0x6b | ||
840 | /* S/PDIF Host Record Control */ | ||
841 | #define A_SPRC 0x6c | ||
842 | /* Delayed Interrupt Counter & Enable */ | ||
843 | #define A_DICE 0x6d | ||
844 | /* Tank Table Base */ | ||
845 | #define A_TTB 0x6e | ||
846 | /* Tank Delay Offset */ | ||
847 | #define A_TDOF 0x6f | ||
786 | 848 | ||
787 | /* This is the MPU port on the card (via the game port) */ | 849 | /* This is the MPU port on the card (via the game port) */ |
788 | #define A_MUDATA1 0x70 | 850 | #define A_MUDATA1 0x70 |
@@ -800,6 +862,7 @@ | |||
800 | #define A_FXWC1 0x74 /* Selects 0x7f-0x60 for FX recording */ | 862 | #define A_FXWC1 0x74 /* Selects 0x7f-0x60 for FX recording */ |
801 | #define A_FXWC2 0x75 /* Selects 0x9f-0x80 for FX recording */ | 863 | #define A_FXWC2 0x75 /* Selects 0x9f-0x80 for FX recording */ |
802 | 864 | ||
865 | /* Extended Hardware Control */ | ||
803 | #define A_SPDIF_SAMPLERATE 0x76 /* Set the sample rate of SPDIF output */ | 866 | #define A_SPDIF_SAMPLERATE 0x76 /* Set the sample rate of SPDIF output */ |
804 | #define A_SAMPLE_RATE 0x76 /* Various sample rate settings. */ | 867 | #define A_SAMPLE_RATE 0x76 /* Various sample rate settings. */ |
805 | #define A_SAMPLE_RATE_NOT_USED 0x0ffc111e /* Bits that are not used and cannot be set. */ | 868 | #define A_SAMPLE_RATE_NOT_USED 0x0ffc111e /* Bits that are not used and cannot be set. */ |
@@ -822,8 +885,20 @@ | |||
822 | #define A_PCM_96000 0x00004000 | 885 | #define A_PCM_96000 0x00004000 |
823 | #define A_PCM_44100 0x00008000 | 886 | #define A_PCM_44100 0x00008000 |
824 | 887 | ||
825 | /* 0x77,0x78,0x79 "something i2s-related" - default to 0x01080000 on my audigy 2 ZS --rlrevell */ | 888 | /* I2S0 Sample Rate Tracker Status */ |
826 | /* 0x7a, 0x7b - lookup tables */ | 889 | #define A_SRT3 0x77 |
890 | |||
891 | /* I2S1 Sample Rate Tracker Status */ | ||
892 | #define A_SRT4 0x78 | ||
893 | |||
894 | /* I2S2 Sample Rate Tracker Status */ | ||
895 | #define A_SRT5 0x79 | ||
896 | /* - default to 0x01080000 on my audigy 2 ZS --rlrevell */ | ||
897 | |||
898 | /* Tank Table DMA Address */ | ||
899 | #define A_TTDA 0x7a | ||
900 | /* Tank Table DMA Data */ | ||
901 | #define A_TTDD 0x7b | ||
827 | 902 | ||
828 | #define A_FXRT2 0x7c | 903 | #define A_FXRT2 0x7c |
829 | #define A_FXRT_CHANNELE 0x0000003f /* Effects send bus number for channel's effects send E */ | 904 | #define A_FXRT_CHANNELE 0x0000003f /* Effects send bus number for channel's effects send E */ |
@@ -845,7 +920,7 @@ | |||
845 | #define A_FXRT_CHANNELC 0x003f0000 | 920 | #define A_FXRT_CHANNELC 0x003f0000 |
846 | #define A_FXRT_CHANNELD 0x3f000000 | 921 | #define A_FXRT_CHANNELD 0x3f000000 |
847 | 922 | ||
848 | 923 | /* 0x7f: Not used */ | |
849 | /* Each FX general purpose register is 32 bits in length, all bits are used */ | 924 | /* Each FX general purpose register is 32 bits in length, all bits are used */ |
850 | #define FXGPREGBASE 0x100 /* FX general purpose registers base */ | 925 | #define FXGPREGBASE 0x100 /* FX general purpose registers base */ |
851 | #define A_FXGPREGBASE 0x400 /* Audigy GPRs, 0x400 to 0x5ff */ | 926 | #define A_FXGPREGBASE 0x400 /* Audigy GPRs, 0x400 to 0x5ff */ |
@@ -886,6 +961,293 @@ | |||
886 | #define A_HIWORD_RESULT_MASK 0x007ff000 | 961 | #define A_HIWORD_RESULT_MASK 0x007ff000 |
887 | #define A_HIWORD_OPA_MASK 0x000007ff | 962 | #define A_HIWORD_OPA_MASK 0x000007ff |
888 | 963 | ||
964 | /************************************************************************************************/ | ||
965 | /* EMU1010m HANA FPGA registers */ | ||
966 | /************************************************************************************************/ | ||
967 | #define EMU_HANA_DESTHI 0x00 /* 0000xxx 3 bits Link Destination */ | ||
968 | #define EMU_HANA_DESTLO 0x01 /* 00xxxxx 5 bits */ | ||
969 | #define EMU_HANA_SRCHI 0x02 /* 0000xxx 3 bits Link Source */ | ||
970 | #define EMU_HANA_SRCLO 0x03 /* 00xxxxx 5 bits */ | ||
971 | #define EMU_HANA_DOCK_PWR 0x04 /* 000000x 1 bits Audio Dock power */ | ||
972 | #define EMU_HANA_DOCK_PWR_ON 0x01 /* Audio Dock power on */ | ||
973 | #define EMU_HANA_WCLOCK 0x05 /* 0000xxx 3 bits Word Clock source select */ | ||
974 | /* Must be written after power on to reset DLL */ | ||
975 | /* One is unable to detect the Audio dock without this */ | ||
976 | #define EMU_HANA_WCLOCK_SRC_MASK 0x07 | ||
977 | #define EMU_HANA_WCLOCK_INT_48K 0x00 | ||
978 | #define EMU_HANA_WCLOCK_INT_44_1K 0x01 | ||
979 | #define EMU_HANA_WCLOCK_HANA_SPDIF_IN 0x02 | ||
980 | #define EMU_HANA_WCLOCK_HANA_ADAT_IN 0x03 | ||
981 | #define EMU_HANA_WCLOCK_SYNC_BNCN 0x04 | ||
982 | #define EMU_HANA_WCLOCK_2ND_HANA 0x05 | ||
983 | #define EMU_HANA_WCLOCK_SRC_RESERVED 0x06 | ||
984 | #define EMU_HANA_WCLOCK_OFF 0x07 /* For testing, forces fallback to DEFCLOCK */ | ||
985 | #define EMU_HANA_WCLOCK_MULT_MASK 0x18 | ||
986 | #define EMU_HANA_WCLOCK_1X 0x00 | ||
987 | #define EMU_HANA_WCLOCK_2X 0x08 | ||
988 | #define EMU_HANA_WCLOCK_4X 0x10 | ||
989 | #define EMU_HANA_WCLOCK_MULT_RESERVED 0x18 | ||
990 | |||
991 | #define EMU_HANA_DEFCLOCK 0x06 /* 000000x 1 bits Default Word Clock */ | ||
992 | #define EMU_HANA_DEFCLOCK_48K 0x00 | ||
993 | #define EMU_HANA_DEFCLOCK_44_1K 0x01 | ||
994 | |||
995 | #define EMU_HANA_UNMUTE 0x07 /* 000000x 1 bits Mute all audio outputs */ | ||
996 | #define EMU_MUTE 0x00 | ||
997 | #define EMU_UNMUTE 0x01 | ||
998 | |||
999 | #define EMU_HANA_FPGA_CONFIG 0x08 /* 00000xx 2 bits Config control of FPGAs */ | ||
1000 | #define EMU_HANA_FPGA_CONFIG_AUDIODOCK 0x01 /* Set in order to program FPGA on Audio Dock */ | ||
1001 | #define EMU_HANA_FPGA_CONFIG_HANA 0x02 /* Set in order to program FPGA on Hana */ | ||
1002 | |||
1003 | #define EMU_HANA_IRQ_ENABLE 0x09 /* 000xxxx 4 bits IRQ Enable */ | ||
1004 | #define EMU_HANA_IRQ_WCLK_CHANGED 0x01 | ||
1005 | #define EMU_HANA_IRQ_ADAT 0x02 | ||
1006 | #define EMU_HANA_IRQ_DOCK 0x04 | ||
1007 | #define EMU_HANA_IRQ_DOCK_LOST 0x08 | ||
1008 | |||
1009 | #define EMU_HANA_SPDIF_MODE 0x0a /* 00xxxxx 5 bits SPDIF MODE */ | ||
1010 | #define EMU_HANA_SPDIF_MODE_TX_COMSUMER 0x00 | ||
1011 | #define EMU_HANA_SPDIF_MODE_TX_PRO 0x01 | ||
1012 | #define EMU_HANA_SPDIF_MODE_TX_NOCOPY 0x02 | ||
1013 | #define EMU_HANA_SPDIF_MODE_RX_COMSUMER 0x00 | ||
1014 | #define EMU_HANA_SPDIF_MODE_RX_PRO 0x04 | ||
1015 | #define EMU_HANA_SPDIF_MODE_RX_NOCOPY 0x08 | ||
1016 | #define EMU_HANA_SPDIF_MODE_RX_INVALID 0x10 | ||
1017 | |||
1018 | #define EMU_HANA_OPTICAL_TYPE 0x0b /* 00000xx 2 bits ADAT or SPDIF in/out */ | ||
1019 | #define EMU_HANA_OPTICAL_IN_SPDIF 0x00 | ||
1020 | #define EMU_HANA_OPTICAL_IN_ADAT 0x01 | ||
1021 | #define EMU_HANA_OPTICAL_OUT_SPDIF 0x00 | ||
1022 | #define EMU_HANA_OPTICAL_OUT_ADAT 0x02 | ||
1023 | |||
1024 | #define EMU_HANA_MIDI_IN 0x0c /* 000000x 1 bit Control MIDI */ | ||
1025 | #define EMU_HANA_MIDI_IN_FROM_HAMOA 0x00 /* HAMOA MIDI in to Alice 2 MIDI B */ | ||
1026 | #define EMU_HANA_MIDI_IN_FROM_DOCK 0x01 /* Audio Dock MIDI in to Alice 2 MIDI B */ | ||
1027 | |||
1028 | #define EMU_HANA_DOCK_LEDS_1 0x0d /* 000xxxx 4 bit Audio Dock LEDs */ | ||
1029 | #define EMU_HANA_DOCK_LEDS_1_MIDI1 0x01 /* MIDI 1 LED on */ | ||
1030 | #define EMU_HANA_DOCK_LEDS_1_MIDI2 0x02 /* MIDI 2 LED on */ | ||
1031 | #define EMU_HANA_DOCK_LEDS_1_SMPTE_IN 0x04 /* SMPTE IN LED on */ | ||
1032 | #define EMU_HANA_DOCK_LEDS_1_SMPTE_OUT 0x08 /* SMPTE OUT LED on */ | ||
1033 | |||
1034 | #define EMU_HANA_DOCK_LEDS_2 0x0e /* 0xxxxxx 6 bit Audio Dock LEDs */ | ||
1035 | #define EMU_HANA_DOCK_LEDS_2_44K 0x01 /* 44.1 kHz LED on */ | ||
1036 | #define EMU_HANA_DOCK_LEDS_2_48K 0x02 /* 48 kHz LED on */ | ||
1037 | #define EMU_HANA_DOCK_LEDS_2_96K 0x04 /* 96 kHz LED on */ | ||
1038 | #define EMU_HANA_DOCK_LEDS_2_192K 0x08 /* 192 kHz LED on */ | ||
1039 | #define EMU_HANA_DOCK_LEDS_2_LOCK 0x10 /* LOCK LED on */ | ||
1040 | #define EMU_HANA_DOCK_LEDS_2_EXT 0x20 /* EXT LED on */ | ||
1041 | |||
1042 | #define EMU_HANA_DOCK_LEDS_3 0x0f /* 0xxxxxx 6 bit Audio Dock LEDs */ | ||
1043 | #define EMU_HANA_DOCK_LEDS_3_CLIP_A 0x01 /* Mic A Clip LED on */ | ||
1044 | #define EMU_HANA_DOCK_LEDS_3_CLIP_B 0x02 /* Mic B Clip LED on */ | ||
1045 | #define EMU_HANA_DOCK_LEDS_3_SIGNAL_A 0x04 /* Signal A Clip LED on */ | ||
1046 | #define EMU_HANA_DOCK_LEDS_3_SIGNAL_B 0x08 /* Signal B Clip LED on */ | ||
1047 | #define EMU_HANA_DOCK_LEDS_3_MANUAL_CLIP 0x10 /* Manual Clip detection */ | ||
1048 | #define EMU_HANA_DOCK_LEDS_3_MANUAL_SIGNAL 0x20 /* Manual Signal detection */ | ||
1049 | |||
1050 | #define EMU_HANA_ADC_PADS 0x10 /* 0000xxx 3 bit Audio Dock ADC 14dB pads */ | ||
1051 | #define EMU_HANA_DOCK_ADC_PAD1 0x01 /* 14dB Attenuation on Audio Dock ADC 1 */ | ||
1052 | #define EMU_HANA_DOCK_ADC_PAD2 0x02 /* 14dB Attenuation on Audio Dock ADC 2 */ | ||
1053 | #define EMU_HANA_DOCK_ADC_PAD3 0x04 /* 14dB Attenuation on Audio Dock ADC 3 */ | ||
1054 | #define EMU_HANA_0202_ADC_PAD1 0x08 /* 14dB Attenuation on 0202 ADC 1 */ | ||
1055 | |||
1056 | #define EMU_HANA_DOCK_MISC 0x11 /* 0xxxxxx 6 bit Audio Dock misc bits */ | ||
1057 | #define EMU_HANA_DOCK_DAC1_MUTE 0x01 /* DAC 1 Mute */ | ||
1058 | #define EMU_HANA_DOCK_DAC2_MUTE 0x02 /* DAC 2 Mute */ | ||
1059 | #define EMU_HANA_DOCK_DAC3_MUTE 0x04 /* DAC 3 Mute */ | ||
1060 | #define EMU_HANA_DOCK_DAC4_MUTE 0x08 /* DAC 4 Mute */ | ||
1061 | #define EMU_HANA_DOCK_PHONES_192_DAC1 0x00 /* DAC 1 Headphones source at 192kHz */ | ||
1062 | #define EMU_HANA_DOCK_PHONES_192_DAC2 0x10 /* DAC 2 Headphones source at 192kHz */ | ||
1063 | #define EMU_HANA_DOCK_PHONES_192_DAC3 0x20 /* DAC 3 Headphones source at 192kHz */ | ||
1064 | #define EMU_HANA_DOCK_PHONES_192_DAC4 0x30 /* DAC 4 Headphones source at 192kHz */ | ||
1065 | |||
1066 | #define EMU_HANA_MIDI_OUT 0x12 /* 00xxxxx 5 bit Source for each MIDI out port */ | ||
1067 | #define EMU_HANA_MIDI_OUT_0202 0x01 /* 0202 MIDI from Alice 2. 0 = A, 1 = B */ | ||
1068 | #define EMU_HANA_MIDI_OUT_DOCK1 0x02 /* Audio Dock MIDI1 front, from Alice 2. 0 = A, 1 = B */ | ||
1069 | #define EMU_HANA_MIDI_OUT_DOCK2 0x04 /* Audio Dock MIDI2 rear, from Alice 2. 0 = A, 1 = B */ | ||
1070 | #define EMU_HANA_MIDI_OUT_SYNC2 0x08 /* Sync card. Not the actual MIDI out jack. 0 = A, 1 = B */ | ||
1071 | #define EMU_HANA_MIDI_OUT_LOOP 0x10 /* 0 = bits (3:0) normal. 1 = MIDI loopback enabled. */ | ||
1072 | |||
1073 | #define EMU_HANA_DAC_PADS 0x13 /* 00xxxxx 5 bit DAC 14dB attenuation pads */ | ||
1074 | #define EMU_HANA_DOCK_DAC_PAD1 0x01 /* 14dB Attenuation on AudioDock DAC 1. Left and Right */ | ||
1075 | #define EMU_HANA_DOCK_DAC_PAD2 0x02 /* 14dB Attenuation on AudioDock DAC 2. Left and Right */ | ||
1076 | #define EMU_HANA_DOCK_DAC_PAD3 0x04 /* 14dB Attenuation on AudioDock DAC 3. Left and Right */ | ||
1077 | #define EMU_HANA_DOCK_DAC_PAD4 0x08 /* 14dB Attenuation on AudioDock DAC 4. Left and Right */ | ||
1078 | #define EMU_HANA_0202_DAC_PAD1 0x10 /* 14dB Attenuation on 0202 DAC 1. Left and Right */ | ||
1079 | |||
1080 | /* 0x14 - 0x1f Unused R/W registers */ | ||
1081 | #define EMU_HANA_IRQ_STATUS 0x20 /* 000xxxx 4 bits IRQ Status */ | ||
1082 | #if 0 /* Already defined for reg 0x09 IRQ_ENABLE */ | ||
1083 | #define EMU_HANA_IRQ_WCLK_CHANGED 0x01 | ||
1084 | #define EMU_HANA_IRQ_ADAT 0x02 | ||
1085 | #define EMU_HANA_IRQ_DOCK 0x04 | ||
1086 | #define EMU_HANA_IRQ_DOCK_LOST 0x08 | ||
1087 | #endif | ||
1088 | |||
1089 | #define EMU_HANA_OPTION_CARDS 0x21 /* 000xxxx 4 bits Presence of option cards */ | ||
1090 | #define EMU_HANA_OPTION_HAMOA 0x01 /* HAMOA card present */ | ||
1091 | #define EMU_HANA_OPTION_SYNC 0x02 /* Sync card present */ | ||
1092 | #define EMU_HANA_OPTION_DOCK_ONLINE 0x04 /* Audio Dock online and FPGA configured */ | ||
1093 | #define EMU_HANA_OPTION_DOCK_OFFLINE 0x08 /* Audio Dock online and FPGA not configured */ | ||
1094 | |||
1095 | #define EMU_HANA_ID 0x22 /* 1010101 7 bits ID byte & 0x7f = 0x55 */ | ||
1096 | |||
1097 | #define EMU_HANA_MAJOR_REV 0x23 /* 0000xxx 3 bit Hana FPGA Major rev */ | ||
1098 | #define EMU_HANA_MINOR_REV 0x24 /* 0000xxx 3 bit Hana FPGA Minor rev */ | ||
1099 | |||
1100 | #define EMU_DOCK_MAJOR_REV 0x25 /* 0000xxx 3 bit Audio Dock FPGA Major rev */ | ||
1101 | #define EMU_DOCK_MINOR_REV 0x26 /* 0000xxx 3 bit Audio Dock FPGA Minor rev */ | ||
1102 | |||
1103 | #define EMU_DOCK_BOARD_ID 0x27 /* 00000xx 2 bits Audio Dock ID pins */ | ||
1104 | #define EMU_DOCK_BOARD_ID0 0x00 /* ID bit 0 */ | ||
1105 | #define EMU_DOCK_BOARD_ID1 0x03 /* ID bit 1 */ | ||
1106 | |||
1107 | #define EMU_HANA_WC_SPDIF_HI 0x28 /* 0xxxxxx 6 bit SPDIF IN Word clock, upper 6 bits */ | ||
1108 | #define EMU_HANA_WC_SPDIF_LO 0x29 /* 0xxxxxx 6 bit SPDIF IN Word clock, lower 6 bits */ | ||
1109 | |||
1110 | #define EMU_HANA_WC_ADAT_HI 0x2a /* 0xxxxxx 6 bit ADAT IN Word clock, upper 6 bits */ | ||
1111 | #define EMU_HANA_WC_ADAT_LO 0x2b /* 0xxxxxx 6 bit ADAT IN Word clock, lower 6 bits */ | ||
1112 | |||
1113 | #define EMU_HANA_WC_BNC_LO 0x2c /* 0xxxxxx 6 bit BNC IN Word clock, lower 6 bits */ | ||
1114 | #define EMU_HANA_WC_BNC_HI 0x2d /* 0xxxxxx 6 bit BNC IN Word clock, upper 6 bits */ | ||
1115 | |||
1116 | #define EMU_HANA2_WC_SPDIF_HI 0x2e /* 0xxxxxx 6 bit HANA2 SPDIF IN Word clock, upper 6 bits */ | ||
1117 | #define EMU_HANA2_WC_SPDIF_LO 0x2f /* 0xxxxxx 6 bit HANA2 SPDIF IN Word clock, lower 6 bits */ | ||
1118 | /* 0x30 - 0x3f Unused Read only registers */ | ||
1119 | |||
1120 | /************************************************************************************************/ | ||
1121 | /* EMU1010m HANA Destinations */ | ||
1122 | /************************************************************************************************/ | ||
1123 | #define EMU_DST_ALICE2_EMU32_0 0x000f /* 16 EMU32 channels to Alice2 +0 to +0xf */ | ||
1124 | #define EMU_DST_ALICE2_EMU32_1 0x0000 /* 16 EMU32 channels to Alice2 +0 to +0xf */ | ||
1125 | #define EMU_DST_ALICE2_EMU32_2 0x0001 /* 16 EMU32 channels to Alice2 +0 to +0xf */ | ||
1126 | #define EMU_DST_ALICE2_EMU32_3 0x0002 /* 16 EMU32 channels to Alice2 +0 to +0xf */ | ||
1127 | #define EMU_DST_ALICE2_EMU32_4 0x0003 /* 16 EMU32 channels to Alice2 +0 to +0xf */ | ||
1128 | #define EMU_DST_ALICE2_EMU32_5 0x0004 /* 16 EMU32 channels to Alice2 +0 to +0xf */ | ||
1129 | #define EMU_DST_ALICE2_EMU32_6 0x0005 /* 16 EMU32 channels to Alice2 +0 to +0xf */ | ||
1130 | #define EMU_DST_ALICE2_EMU32_7 0x0006 /* 16 EMU32 channels to Alice2 +0 to +0xf */ | ||
1131 | #define EMU_DST_ALICE2_EMU32_8 0x0007 /* 16 EMU32 channels to Alice2 +0 to +0xf */ | ||
1132 | #define EMU_DST_ALICE2_EMU32_9 0x0008 /* 16 EMU32 channels to Alice2 +0 to +0xf */ | ||
1133 | #define EMU_DST_ALICE2_EMU32_A 0x0009 /* 16 EMU32 channels to Alice2 +0 to +0xf */ | ||
1134 | #define EMU_DST_ALICE2_EMU32_B 0x000a /* 16 EMU32 channels to Alice2 +0 to +0xf */ | ||
1135 | #define EMU_DST_ALICE2_EMU32_C 0x000b /* 16 EMU32 channels to Alice2 +0 to +0xf */ | ||
1136 | #define EMU_DST_ALICE2_EMU32_D 0x000c /* 16 EMU32 channels to Alice2 +0 to +0xf */ | ||
1137 | #define EMU_DST_ALICE2_EMU32_E 0x000d /* 16 EMU32 channels to Alice2 +0 to +0xf */ | ||
1138 | #define EMU_DST_ALICE2_EMU32_F 0x000e /* 16 EMU32 channels to Alice2 +0 to +0xf */ | ||
1139 | #define EMU_DST_DOCK_DAC1_LEFT1 0x0100 /* Audio Dock DAC1 Left, 1st or 48kHz only */ | ||
1140 | #define EMU_DST_DOCK_DAC1_LEFT2 0x0101 /* Audio Dock DAC1 Left, 2nd or 96kHz */ | ||
1141 | #define EMU_DST_DOCK_DAC1_LEFT3 0x0102 /* Audio Dock DAC1 Left, 3rd or 192kHz */ | ||
1142 | #define EMU_DST_DOCK_DAC1_LEFT4 0x0103 /* Audio Dock DAC1 Left, 4th or 192kHz */ | ||
1143 | #define EMU_DST_DOCK_DAC1_RIGHT1 0x0104 /* Audio Dock DAC1 Right, 1st or 48kHz only */ | ||
1144 | #define EMU_DST_DOCK_DAC1_RIGHT2 0x0105 /* Audio Dock DAC1 Right, 2nd or 96kHz */ | ||
1145 | #define EMU_DST_DOCK_DAC1_RIGHT3 0x0106 /* Audio Dock DAC1 Right, 3rd or 192kHz */ | ||
1146 | #define EMU_DST_DOCK_DAC1_RIGHT4 0x0107 /* Audio Dock DAC1 Right, 4th or 192kHz */ | ||
1147 | #define EMU_DST_DOCK_DAC2_LEFT1 0x0108 /* Audio Dock DAC2 Left, 1st or 48kHz only */ | ||
1148 | #define EMU_DST_DOCK_DAC2_LEFT2 0x0109 /* Audio Dock DAC2 Left, 2nd or 96kHz */ | ||
1149 | #define EMU_DST_DOCK_DAC2_LEFT3 0x010a /* Audio Dock DAC2 Left, 3rd or 192kHz */ | ||
1150 | #define EMU_DST_DOCK_DAC2_LEFT4 0x010b /* Audio Dock DAC2 Left, 4th or 192kHz */ | ||
1151 | #define EMU_DST_DOCK_DAC2_RIGHT1 0x010c /* Audio Dock DAC2 Right, 1st or 48kHz only */ | ||
1152 | #define EMU_DST_DOCK_DAC2_RIGHT2 0x010d /* Audio Dock DAC2 Right, 2nd or 96kHz */ | ||
1153 | #define EMU_DST_DOCK_DAC2_RIGHT3 0x010e /* Audio Dock DAC2 Right, 3rd or 192kHz */ | ||
1154 | #define EMU_DST_DOCK_DAC2_RIGHT4 0x010f /* Audio Dock DAC2 Right, 4th or 192kHz */ | ||
1155 | #define EMU_DST_DOCK_DAC3_LEFT1 0x0110 /* Audio Dock DAC1 Left, 1st or 48kHz only */ | ||
1156 | #define EMU_DST_DOCK_DAC3_LEFT2 0x0111 /* Audio Dock DAC1 Left, 2nd or 96kHz */ | ||
1157 | #define EMU_DST_DOCK_DAC3_LEFT3 0x0112 /* Audio Dock DAC1 Left, 3rd or 192kHz */ | ||
1158 | #define EMU_DST_DOCK_DAC3_LEFT4 0x0113 /* Audio Dock DAC1 Left, 4th or 192kHz */ | ||
1159 | #define EMU_DST_DOCK_PHONES_LEFT1 0x0112 /* Audio Dock PHONES Left, 1st or 48kHz only */ | ||
1160 | #define EMU_DST_DOCK_PHONES_LEFT2 0x0113 /* Audio Dock PHONES Left, 2nd or 96kHz */ | ||
1161 | #define EMU_DST_DOCK_DAC3_RIGHT1 0x0114 /* Audio Dock DAC1 Right, 1st or 48kHz only */ | ||
1162 | #define EMU_DST_DOCK_DAC3_RIGHT2 0x0115 /* Audio Dock DAC1 Right, 2nd or 96kHz */ | ||
1163 | #define EMU_DST_DOCK_DAC3_RIGHT3 0x0116 /* Audio Dock DAC1 Right, 3rd or 192kHz */ | ||
1164 | #define EMU_DST_DOCK_DAC3_RIGHT4 0x0117 /* Audio Dock DAC1 Right, 4th or 192kHz */ | ||
1165 | #define EMU_DST_DOCK_PHONES_RIGHT1 0x0116 /* Audio Dock PHONES Right, 1st or 48kHz only */ | ||
1166 | #define EMU_DST_DOCK_PHONES_RIGHT2 0x0117 /* Audio Dock PHONES Right, 2nd or 96kHz */ | ||
1167 | #define EMU_DST_DOCK_DAC4_LEFT1 0x0118 /* Audio Dock DAC2 Left, 1st or 48kHz only */ | ||
1168 | #define EMU_DST_DOCK_DAC4_LEFT2 0x0119 /* Audio Dock DAC2 Left, 2nd or 96kHz */ | ||
1169 | #define EMU_DST_DOCK_DAC4_LEFT3 0x011a /* Audio Dock DAC2 Left, 3rd or 192kHz */ | ||
1170 | #define EMU_DST_DOCK_DAC4_LEFT4 0x011b /* Audio Dock DAC2 Left, 4th or 192kHz */ | ||
1171 | #define EMU_DST_DOCK_SPDIF_LEFT1 0x011a /* Audio Dock SPDIF Left, 1st or 48kHz only */ | ||
1172 | #define EMU_DST_DOCK_SPDIF_LEFT2 0x011b /* Audio Dock SPDIF Left, 2nd or 96kHz */ | ||
1173 | #define EMU_DST_DOCK_DAC4_RIGHT1 0x011c /* Audio Dock DAC2 Right, 1st or 48kHz only */ | ||
1174 | #define EMU_DST_DOCK_DAC4_RIGHT2 0x011d /* Audio Dock DAC2 Right, 2nd or 96kHz */ | ||
1175 | #define EMU_DST_DOCK_DAC4_RIGHT3 0x011e /* Audio Dock DAC2 Right, 3rd or 192kHz */ | ||
1176 | #define EMU_DST_DOCK_DAC4_RIGHT4 0x011f /* Audio Dock DAC2 Right, 4th or 192kHz */ | ||
1177 | #define EMU_DST_DOCK_SPDIF_RIGHT1 0x011e /* Audio Dock SPDIF Right, 1st or 48kHz only */ | ||
1178 | #define EMU_DST_DOCK_SPDIF_RIGHT2 0x011f /* Audio Dock SPDIF Right, 2nd or 96kHz */ | ||
1179 | #define EMU_DST_HANA_SPDIF_LEFT1 0x0200 /* Hana SPDIF Left, 1st or 48kHz only */ | ||
1180 | #define EMU_DST_HANA_SPDIF_LEFT2 0x0202 /* Hana SPDIF Left, 2nd or 96kHz */ | ||
1181 | #define EMU_DST_HANA_SPDIF_RIGHT1 0x0201 /* Hana SPDIF Right, 1st or 48kHz only */ | ||
1182 | #define EMU_DST_HANA_SPDIF_RIGHT2 0x0203 /* Hana SPDIF Right, 2nd or 96kHz */ | ||
1183 | #define EMU_DST_HAMOA_DAC_LEFT1 0x0300 /* Hamoa DAC Left, 1st or 48kHz only */ | ||
1184 | #define EMU_DST_HAMOA_DAC_LEFT2 0x0302 /* Hamoa DAC Left, 2nd or 96kHz */ | ||
1185 | #define EMU_DST_HAMOA_DAC_LEFT3 0x0304 /* Hamoa DAC Left, 3rd or 192kHz */ | ||
1186 | #define EMU_DST_HAMOA_DAC_LEFT4 0x0306 /* Hamoa DAC Left, 4th or 192kHz */ | ||
1187 | #define EMU_DST_HAMOA_DAC_RIGHT1 0x0301 /* Hamoa DAC Right, 1st or 48kHz only */ | ||
1188 | #define EMU_DST_HAMOA_DAC_RIGHT2 0x0303 /* Hamoa DAC Right, 2nd or 96kHz */ | ||
1189 | #define EMU_DST_HAMOA_DAC_RIGHT3 0x0305 /* Hamoa DAC Right, 3rd or 192kHz */ | ||
1190 | #define EMU_DST_HAMOA_DAC_RIGHT4 0x0307 /* Hamoa DAC Right, 4th or 192kHz */ | ||
1191 | #define EMU_DST_HANA_ADAT 0x0400 /* Hana ADAT 8 channel out +0 to +7 */ | ||
1192 | #define EMU_DST_ALICE_I2S0_LEFT 0x0500 /* Alice2 I2S0 Left */ | ||
1193 | #define EMU_DST_ALICE_I2S0_RIGHT 0x0501 /* Alice2 I2S0 Right */ | ||
1194 | #define EMU_DST_ALICE_I2S1_LEFT 0x0600 /* Alice2 I2S1 Left */ | ||
1195 | #define EMU_DST_ALICE_I2S1_RIGHT 0x0601 /* Alice2 I2S1 Right */ | ||
1196 | #define EMU_DST_ALICE_I2S2_LEFT 0x0700 /* Alice2 I2S2 Left */ | ||
1197 | #define EMU_DST_ALICE_I2S2_RIGHT 0x0701 /* Alice2 I2S2 Right */ | ||
1198 | |||
1199 | /************************************************************************************************/ | ||
1200 | /* EMU1010m HANA Sources */ | ||
1201 | /************************************************************************************************/ | ||
1202 | #define EMU_SRC_SILENCE 0x0000 /* Silence */ | ||
1203 | #define EMU_SRC_DOCK_MIC_A1 0x0100 /* Audio Dock Mic A, 1st or 48kHz only */ | ||
1204 | #define EMU_SRC_DOCK_MIC_A2 0x0101 /* Audio Dock Mic A, 2nd or 96kHz */ | ||
1205 | #define EMU_SRC_DOCK_MIC_A3 0x0102 /* Audio Dock Mic A, 3rd or 192kHz */ | ||
1206 | #define EMU_SRC_DOCK_MIC_A4 0x0103 /* Audio Dock Mic A, 4th or 192kHz */ | ||
1207 | #define EMU_SRC_DOCK_MIC_B1 0x0104 /* Audio Dock Mic B, 1st or 48kHz only */ | ||
1208 | #define EMU_SRC_DOCK_MIC_B2 0x0105 /* Audio Dock Mic B, 2nd or 96kHz */ | ||
1209 | #define EMU_SRC_DOCK_MIC_B3 0x0106 /* Audio Dock Mic B, 3rd or 192kHz */ | ||
1210 | #define EMU_SRC_DOCK_MIC_B4 0x0107 /* Audio Dock Mic B, 4th or 192kHz */ | ||
1211 | #define EMU_SRC_DOCK_ADC1_LEFT1 0x0108 /* Audio Dock ADC1 Left, 1st or 48kHz only */ | ||
1212 | #define EMU_SRC_DOCK_ADC1_LEFT2 0x0109 /* Audio Dock ADC1 Left, 2nd or 96kHz */ | ||
1213 | #define EMU_SRC_DOCK_ADC1_LEFT3 0x010a /* Audio Dock ADC1 Left, 3rd or 192kHz */ | ||
1214 | #define EMU_SRC_DOCK_ADC1_LEFT4 0x010b /* Audio Dock ADC1 Left, 4th or 192kHz */ | ||
1215 | #define EMU_SRC_DOCK_ADC1_RIGHT1 0x010c /* Audio Dock ADC1 Right, 1st or 48kHz only */ | ||
1216 | #define EMU_SRC_DOCK_ADC1_RIGHT2 0x010d /* Audio Dock ADC1 Right, 2nd or 96kHz */ | ||
1217 | #define EMU_SRC_DOCK_ADC1_RIGHT3 0x010e /* Audio Dock ADC1 Right, 3rd or 192kHz */ | ||
1218 | #define EMU_SRC_DOCK_ADC1_RIGHT4 0x010f /* Audio Dock ADC1 Right, 4th or 192kHz */ | ||
1219 | #define EMU_SRC_DOCK_ADC2_LEFT1 0x0110 /* Audio Dock ADC2 Left, 1st or 48kHz only */ | ||
1220 | #define EMU_SRC_DOCK_ADC2_LEFT2 0x0111 /* Audio Dock ADC2 Left, 2nd or 96kHz */ | ||
1221 | #define EMU_SRC_DOCK_ADC2_LEFT3 0x0112 /* Audio Dock ADC2 Left, 3rd or 192kHz */ | ||
1222 | #define EMU_SRC_DOCK_ADC2_LEFT4 0x0113 /* Audio Dock ADC2 Left, 4th or 192kHz */ | ||
1223 | #define EMU_SRC_DOCK_ADC2_RIGHT1 0x0114 /* Audio Dock ADC2 Right, 1st or 48kHz only */ | ||
1224 | #define EMU_SRC_DOCK_ADC2_RIGHT2 0x0115 /* Audio Dock ADC2 Right, 2nd or 96kHz */ | ||
1225 | #define EMU_SRC_DOCK_ADC2_RIGHT3 0x0116 /* Audio Dock ADC2 Right, 3rd or 192kHz */ | ||
1226 | #define EMU_SRC_DOCK_ADC2_RIGHT4 0x0117 /* Audio Dock ADC2 Right, 4th or 192kHz */ | ||
1227 | #define EMU_SRC_DOCK_ADC3_LEFT1 0x0118 /* Audio Dock ADC3 Left, 1st or 48kHz only */ | ||
1228 | #define EMU_SRC_DOCK_ADC3_LEFT2 0x0119 /* Audio Dock ADC3 Left, 2nd or 96kHz */ | ||
1229 | #define EMU_SRC_DOCK_ADC3_LEFT3 0x011a /* Audio Dock ADC3 Left, 3rd or 192kHz */ | ||
1230 | #define EMU_SRC_DOCK_ADC3_LEFT4 0x011b /* Audio Dock ADC3 Left, 4th or 192kHz */ | ||
1231 | #define EMU_SRC_DOCK_ADC3_RIGHT1 0x011c /* Audio Dock ADC3 Right, 1st or 48kHz only */ | ||
1232 | #define EMU_SRC_DOCK_ADC3_RIGHT2 0x011d /* Audio Dock ADC3 Right, 2nd or 96kHz */ | ||
1233 | #define EMU_SRC_DOCK_ADC3_RIGHT3 0x011e /* Audio Dock ADC3 Right, 3rd or 192kHz */ | ||
1234 | #define EMU_SRC_DOCK_ADC3_RIGHT4 0x011f /* Audio Dock ADC3 Right, 4th or 192kHz */ | ||
1235 | #define EMU_SRC_HAMOA_ADC_LEFT1 0x0200 /* Hamoa ADC Left, 1st or 48kHz only */ | ||
1236 | #define EMU_SRC_HAMOA_ADC_LEFT2 0x0202 /* Hamoa ADC Left, 2nd or 96kHz */ | ||
1237 | #define EMU_SRC_HAMOA_ADC_LEFT3 0x0204 /* Hamoa ADC Left, 3rd or 192kHz */ | ||
1238 | #define EMU_SRC_HAMOA_ADC_LEFT4 0x0206 /* Hamoa ADC Left, 4th or 192kHz */ | ||
1239 | #define EMU_SRC_HAMOA_ADC_RIGHT1 0x0201 /* Hamoa ADC Right, 1st or 48kHz only */ | ||
1240 | #define EMU_SRC_HAMOA_ADC_RIGHT2 0x0203 /* Hamoa ADC Right, 2nd or 96kHz */ | ||
1241 | #define EMU_SRC_HAMOA_ADC_RIGHT3 0x0205 /* Hamoa ADC Right, 3rd or 192kHz */ | ||
1242 | #define EMU_SRC_HAMOA_ADC_RIGHT4 0x0207 /* Hamoa ADC Right, 4th or 192kHz */ | ||
1243 | #define EMU_SRC_ALICE_EMU32A 0x0300 /* Alice2 EMU32a 16 outputs. +0 to +0xf */ | ||
1244 | #define EMU_SRC_ALICE_EMU32B 0x0310 /* Alice2 EMU32b 16 outputs. +0 to +0xf */ | ||
1245 | #define EMU_SRC_HANA_ADAT 0x0400 /* Hana ADAT 8 channel in +0 to +7 */ | ||
1246 | #define EMU_SRC_HANA_SPDIF_LEFT1 0x0500 /* Hana SPDIF Left, 1st or 48kHz only */ | ||
1247 | #define EMU_SRC_HANA_SPDIF_LEFT2 0x0502 /* Hana SPDIF Left, 2nd or 96kHz */ | ||
1248 | #define EMU_SRC_HANA_SPDIF_RIGHT1 0x0501 /* Hana SPDIF Right, 1st or 48kHz only */ | ||
1249 | #define EMU_SRC_HANA_SPDIF_RIGHT2 0x0503 /* Hana SPDIF Right, 2nd or 96kHz */ | ||
1250 | /* 0x600 and 0x700 no used */ | ||
889 | 1251 | ||
890 | /* ------------------- STRUCTURES -------------------- */ | 1252 | /* ------------------- STRUCTURES -------------------- */ |
891 | 1253 | ||
@@ -1063,7 +1425,7 @@ struct snd_emu_chip_details { | |||
1063 | unsigned char spdif_bug; /* Has Spdif phasing bug */ | 1425 | unsigned char spdif_bug; /* Has Spdif phasing bug */ |
1064 | unsigned char ac97_chip; /* Has an AC97 chip: 1 = mandatory, 2 = optional */ | 1426 | unsigned char ac97_chip; /* Has an AC97 chip: 1 = mandatory, 2 = optional */ |
1065 | unsigned char ecard; /* APS EEPROM */ | 1427 | unsigned char ecard; /* APS EEPROM */ |
1066 | unsigned char emu1212m; /* EMU 1212m card */ | 1428 | unsigned char emu1010; /* EMU 1010m card */ |
1067 | unsigned char spi_dac; /* SPI interface for DAC */ | 1429 | unsigned char spi_dac; /* SPI interface for DAC */ |
1068 | unsigned char i2c_adc; /* I2C interface for ADC */ | 1430 | unsigned char i2c_adc; /* I2C interface for ADC */ |
1069 | unsigned char adc_1361t; /* Use Philips 1361T ADC */ | 1431 | unsigned char adc_1361t; /* Use Philips 1361T ADC */ |
@@ -1072,6 +1434,14 @@ struct snd_emu_chip_details { | |||
1072 | const char *id; /* for backward compatibility - can be NULL if not needed */ | 1434 | const char *id; /* for backward compatibility - can be NULL if not needed */ |
1073 | }; | 1435 | }; |
1074 | 1436 | ||
1437 | struct snd_emu1010 { | ||
1438 | unsigned int output_source[64]; | ||
1439 | unsigned int input_source[64]; | ||
1440 | unsigned int adc_pads; /* bit mask */ | ||
1441 | unsigned int dac_pads; /* bit mask */ | ||
1442 | unsigned int internal_clock; /* 44100 or 48000 */ | ||
1443 | }; | ||
1444 | |||
1075 | struct snd_emu10k1 { | 1445 | struct snd_emu10k1 { |
1076 | int irq; | 1446 | int irq; |
1077 | 1447 | ||
@@ -1079,6 +1449,7 @@ struct snd_emu10k1 { | |||
1079 | unsigned int tos_link: 1, /* tos link detected */ | 1449 | unsigned int tos_link: 1, /* tos link detected */ |
1080 | rear_ac97: 1, /* rear channels are on AC'97 */ | 1450 | rear_ac97: 1, /* rear channels are on AC'97 */ |
1081 | enable_ir: 1; | 1451 | enable_ir: 1; |
1452 | unsigned int support_tlv :1; | ||
1082 | /* Contains profile of card capabilities */ | 1453 | /* Contains profile of card capabilities */ |
1083 | const struct snd_emu_chip_details *card_capabilities; | 1454 | const struct snd_emu_chip_details *card_capabilities; |
1084 | unsigned int audigy; /* is Audigy? */ | 1455 | unsigned int audigy; /* is Audigy? */ |
@@ -1104,6 +1475,8 @@ struct snd_emu10k1 { | |||
1104 | spinlock_t memblk_lock; | 1475 | spinlock_t memblk_lock; |
1105 | 1476 | ||
1106 | unsigned int spdif_bits[3]; /* s/pdif out setup */ | 1477 | unsigned int spdif_bits[3]; /* s/pdif out setup */ |
1478 | unsigned int i2c_capture_source; | ||
1479 | u8 i2c_capture_volume[4][2]; | ||
1107 | 1480 | ||
1108 | struct snd_emu10k1_fx8010 fx8010; /* FX8010 info */ | 1481 | struct snd_emu10k1_fx8010 fx8010; /* FX8010 info */ |
1109 | int gpr_base; | 1482 | int gpr_base; |
@@ -1132,6 +1505,7 @@ struct snd_emu10k1 { | |||
1132 | int p16v_device_offset; | 1505 | int p16v_device_offset; |
1133 | u32 p16v_capture_source; | 1506 | u32 p16v_capture_source; |
1134 | u32 p16v_capture_channel; | 1507 | u32 p16v_capture_channel; |
1508 | struct snd_emu1010 emu1010; | ||
1135 | struct snd_emu10k1_pcm_mixer pcm_mixer[32]; | 1509 | struct snd_emu10k1_pcm_mixer pcm_mixer[32]; |
1136 | struct snd_emu10k1_pcm_mixer efx_pcm_mixer[NUM_EFX_PLAYBACK]; | 1510 | struct snd_emu10k1_pcm_mixer efx_pcm_mixer[NUM_EFX_PLAYBACK]; |
1137 | struct snd_kcontrol *ctl_send_routing; | 1511 | struct snd_kcontrol *ctl_send_routing; |
@@ -1208,6 +1582,10 @@ void snd_emu10k1_ptr_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned i | |||
1208 | unsigned int snd_emu10k1_ptr20_read(struct snd_emu10k1 * emu, unsigned int reg, unsigned int chn); | 1582 | unsigned int snd_emu10k1_ptr20_read(struct snd_emu10k1 * emu, unsigned int reg, unsigned int chn); |
1209 | void snd_emu10k1_ptr20_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned int chn, unsigned int data); | 1583 | void snd_emu10k1_ptr20_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned int chn, unsigned int data); |
1210 | int snd_emu10k1_spi_write(struct snd_emu10k1 * emu, unsigned int data); | 1584 | int snd_emu10k1_spi_write(struct snd_emu10k1 * emu, unsigned int data); |
1585 | int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu, u32 reg, u32 value); | ||
1586 | int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, int reg, int value); | ||
1587 | int snd_emu1010_fpga_read(struct snd_emu10k1 * emu, int reg, int *value); | ||
1588 | int snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 * emu, int dst, int src); | ||
1211 | unsigned int snd_emu10k1_efx_read(struct snd_emu10k1 *emu, unsigned int pc); | 1589 | unsigned int snd_emu10k1_efx_read(struct snd_emu10k1 *emu, unsigned int pc); |
1212 | void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb); | 1590 | void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb); |
1213 | void snd_emu10k1_intr_disable(struct snd_emu10k1 *emu, unsigned int intrenb); | 1591 | void snd_emu10k1_intr_disable(struct snd_emu10k1 *emu, unsigned int intrenb); |
@@ -1524,11 +1902,20 @@ struct snd_emu10k1_fx8010_control_gpr { | |||
1524 | unsigned int value[32]; /* initial values */ | 1902 | unsigned int value[32]; /* initial values */ |
1525 | unsigned int min; /* minimum range */ | 1903 | unsigned int min; /* minimum range */ |
1526 | unsigned int max; /* maximum range */ | 1904 | unsigned int max; /* maximum range */ |
1527 | union { | ||
1528 | snd_kcontrol_tlv_rw_t *c; | ||
1529 | unsigned int *p; | ||
1530 | } tlv; | ||
1531 | unsigned int translation; /* translation type (EMU10K1_GPR_TRANSLATION*) */ | 1905 | unsigned int translation; /* translation type (EMU10K1_GPR_TRANSLATION*) */ |
1906 | const unsigned int *tlv; | ||
1907 | }; | ||
1908 | |||
1909 | /* old ABI without TLV support */ | ||
1910 | struct snd_emu10k1_fx8010_control_old_gpr { | ||
1911 | struct snd_ctl_elem_id id; | ||
1912 | unsigned int vcount; | ||
1913 | unsigned int count; | ||
1914 | unsigned short gpr[32]; | ||
1915 | unsigned int value[32]; | ||
1916 | unsigned int min; | ||
1917 | unsigned int max; | ||
1918 | unsigned int translation; | ||
1532 | }; | 1919 | }; |
1533 | 1920 | ||
1534 | struct snd_emu10k1_fx8010_code { | 1921 | struct snd_emu10k1_fx8010_code { |
@@ -1579,6 +1966,8 @@ struct snd_emu10k1_fx8010_pcm_rec { | |||
1579 | unsigned int res2; /* reserved */ | 1966 | unsigned int res2; /* reserved */ |
1580 | }; | 1967 | }; |
1581 | 1968 | ||
1969 | #define SNDRV_EMU10K1_VERSION SNDRV_PROTOCOL_VERSION(1, 0, 1) | ||
1970 | |||
1582 | #define SNDRV_EMU10K1_IOCTL_INFO _IOR ('H', 0x10, struct snd_emu10k1_fx8010_info) | 1971 | #define SNDRV_EMU10K1_IOCTL_INFO _IOR ('H', 0x10, struct snd_emu10k1_fx8010_info) |
1583 | #define SNDRV_EMU10K1_IOCTL_CODE_POKE _IOW ('H', 0x11, struct snd_emu10k1_fx8010_code) | 1972 | #define SNDRV_EMU10K1_IOCTL_CODE_POKE _IOW ('H', 0x11, struct snd_emu10k1_fx8010_code) |
1584 | #define SNDRV_EMU10K1_IOCTL_CODE_PEEK _IOWR('H', 0x12, struct snd_emu10k1_fx8010_code) | 1973 | #define SNDRV_EMU10K1_IOCTL_CODE_PEEK _IOWR('H', 0x12, struct snd_emu10k1_fx8010_code) |
@@ -1587,6 +1976,7 @@ struct snd_emu10k1_fx8010_pcm_rec { | |||
1587 | #define SNDRV_EMU10K1_IOCTL_TRAM_PEEK _IOWR('H', 0x22, struct snd_emu10k1_fx8010_tram) | 1976 | #define SNDRV_EMU10K1_IOCTL_TRAM_PEEK _IOWR('H', 0x22, struct snd_emu10k1_fx8010_tram) |
1588 | #define SNDRV_EMU10K1_IOCTL_PCM_POKE _IOW ('H', 0x30, struct snd_emu10k1_fx8010_pcm_rec) | 1977 | #define SNDRV_EMU10K1_IOCTL_PCM_POKE _IOW ('H', 0x30, struct snd_emu10k1_fx8010_pcm_rec) |
1589 | #define SNDRV_EMU10K1_IOCTL_PCM_PEEK _IOWR('H', 0x31, struct snd_emu10k1_fx8010_pcm_rec) | 1978 | #define SNDRV_EMU10K1_IOCTL_PCM_PEEK _IOWR('H', 0x31, struct snd_emu10k1_fx8010_pcm_rec) |
1979 | #define SNDRV_EMU10K1_IOCTL_PVERSION _IOR ('H', 0x40, int) | ||
1590 | #define SNDRV_EMU10K1_IOCTL_STOP _IO ('H', 0x80) | 1980 | #define SNDRV_EMU10K1_IOCTL_STOP _IO ('H', 0x80) |
1591 | #define SNDRV_EMU10K1_IOCTL_CONTINUE _IO ('H', 0x81) | 1981 | #define SNDRV_EMU10K1_IOCTL_CONTINUE _IO ('H', 0x81) |
1592 | #define SNDRV_EMU10K1_IOCTL_ZERO_TRAM_COUNTER _IO ('H', 0x82) | 1982 | #define SNDRV_EMU10K1_IOCTL_ZERO_TRAM_COUNTER _IO ('H', 0x82) |
diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 2f645dfd7f70..ee6bc2d06803 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h | |||
@@ -56,6 +56,8 @@ struct snd_pcm_hardware { | |||
56 | size_t fifo_size; /* fifo size in bytes */ | 56 | size_t fifo_size; /* fifo size in bytes */ |
57 | }; | 57 | }; |
58 | 58 | ||
59 | struct snd_pcm_substream; | ||
60 | |||
59 | struct snd_pcm_ops { | 61 | struct snd_pcm_ops { |
60 | int (*open)(struct snd_pcm_substream *substream); | 62 | int (*open)(struct snd_pcm_substream *substream); |
61 | int (*close)(struct snd_pcm_substream *substream); | 63 | int (*close)(struct snd_pcm_substream *substream); |
@@ -384,6 +386,7 @@ struct snd_pcm_substream { | |||
384 | struct snd_info_entry *proc_sw_params_entry; | 386 | struct snd_info_entry *proc_sw_params_entry; |
385 | struct snd_info_entry *proc_status_entry; | 387 | struct snd_info_entry *proc_status_entry; |
386 | struct snd_info_entry *proc_prealloc_entry; | 388 | struct snd_info_entry *proc_prealloc_entry; |
389 | struct snd_info_entry *proc_prealloc_max_entry; | ||
387 | #endif | 390 | #endif |
388 | /* misc flags */ | 391 | /* misc flags */ |
389 | unsigned int hw_opened: 1; | 392 | unsigned int hw_opened: 1; |
@@ -427,6 +430,7 @@ struct snd_pcm { | |||
427 | wait_queue_head_t open_wait; | 430 | wait_queue_head_t open_wait; |
428 | void *private_data; | 431 | void *private_data; |
429 | void (*private_free) (struct snd_pcm *pcm); | 432 | void (*private_free) (struct snd_pcm *pcm); |
433 | struct device *dev; /* actual hw device this belongs to */ | ||
430 | #if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE) | 434 | #if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE) |
431 | struct snd_pcm_oss oss; | 435 | struct snd_pcm_oss oss; |
432 | #endif | 436 | #endif |
diff --git a/include/sound/pt2258.h b/include/sound/pt2258.h new file mode 100644 index 000000000000..160f812faa42 --- /dev/null +++ b/include/sound/pt2258.h | |||
@@ -0,0 +1,37 @@ | |||
1 | /* | ||
2 | * ALSA Driver for the PT2258 volume controller. | ||
3 | * | ||
4 | * Copyright (c) 2006 Jochen Voss <voss@seehuhn.de> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #ifndef __SOUND_PT2258_H | ||
23 | #define __SOUND_PT2258_H | ||
24 | |||
25 | struct snd_pt2258 { | ||
26 | struct snd_card *card; | ||
27 | struct snd_i2c_bus *i2c_bus; | ||
28 | struct snd_i2c_device *i2c_dev; | ||
29 | |||
30 | unsigned char volume[6]; | ||
31 | int mute; | ||
32 | }; | ||
33 | |||
34 | extern int snd_pt2258_reset(struct snd_pt2258 *pt); | ||
35 | extern int snd_pt2258_build_controls(struct snd_pt2258 *pt); | ||
36 | |||
37 | #endif /* __SOUND_PT2258_H */ | ||
diff --git a/include/sound/sb16_csp.h b/include/sound/sb16_csp.h index caf6fe21514d..736eac71d053 100644 --- a/include/sound/sb16_csp.h +++ b/include/sound/sb16_csp.h | |||
@@ -114,9 +114,21 @@ struct snd_sb_csp_info { | |||
114 | #ifdef __KERNEL__ | 114 | #ifdef __KERNEL__ |
115 | #include "sb.h" | 115 | #include "sb.h" |
116 | #include "hwdep.h" | 116 | #include "hwdep.h" |
117 | #include <linux/firmware.h> | ||
117 | 118 | ||
118 | struct snd_sb_csp; | 119 | struct snd_sb_csp; |
119 | 120 | ||
121 | /* indices for the known CSP programs */ | ||
122 | enum { | ||
123 | CSP_PROGRAM_MULAW, | ||
124 | CSP_PROGRAM_ALAW, | ||
125 | CSP_PROGRAM_ADPCM_INIT, | ||
126 | CSP_PROGRAM_ADPCM_PLAYBACK, | ||
127 | CSP_PROGRAM_ADPCM_CAPTURE, | ||
128 | |||
129 | CSP_PROGRAM_COUNT | ||
130 | }; | ||
131 | |||
120 | /* | 132 | /* |
121 | * CSP operators | 133 | * CSP operators |
122 | */ | 134 | */ |
@@ -159,6 +171,8 @@ struct snd_sb_csp { | |||
159 | struct snd_kcontrol *qsound_space; | 171 | struct snd_kcontrol *qsound_space; |
160 | 172 | ||
161 | struct mutex access_mutex; /* locking */ | 173 | struct mutex access_mutex; /* locking */ |
174 | |||
175 | const struct firmware *csp_programs[CSP_PROGRAM_COUNT]; | ||
162 | }; | 176 | }; |
163 | 177 | ||
164 | int snd_sb_csp_new(struct snd_sb *chip, int device, struct snd_hwdep ** rhwdep); | 178 | int snd_sb_csp_new(struct snd_sb *chip, int device, struct snd_hwdep ** rhwdep); |
diff --git a/include/sound/snd_wavefront.h b/include/sound/snd_wavefront.h index 0b9e5de94ff1..9688d4be918e 100644 --- a/include/sound/snd_wavefront.h +++ b/include/sound/snd_wavefront.h | |||
@@ -85,6 +85,7 @@ struct _snd_wavefront { | |||
85 | char hw_version[2]; /* major = [0], minor = [1] */ | 85 | char hw_version[2]; /* major = [0], minor = [1] */ |
86 | char israw; /* needs Motorola microcode */ | 86 | char israw; /* needs Motorola microcode */ |
87 | char has_fx; /* has FX processor (Tropez+) */ | 87 | char has_fx; /* has FX processor (Tropez+) */ |
88 | char fx_initialized; /* FX's register pages initialized */ | ||
88 | char prog_status[WF_MAX_PROGRAM]; /* WF_SLOT_* */ | 89 | char prog_status[WF_MAX_PROGRAM]; /* WF_SLOT_* */ |
89 | char patch_status[WF_MAX_PATCH]; /* WF_SLOT_* */ | 90 | char patch_status[WF_MAX_PATCH]; /* WF_SLOT_* */ |
90 | char sample_status[WF_MAX_SAMPLE]; /* WF_ST_* | WF_SLOT_* */ | 91 | char sample_status[WF_MAX_SAMPLE]; /* WF_ST_* | WF_SLOT_* */ |
@@ -94,6 +95,7 @@ struct _snd_wavefront { | |||
94 | spinlock_t irq_lock; | 95 | spinlock_t irq_lock; |
95 | wait_queue_head_t interrupt_sleeper; | 96 | wait_queue_head_t interrupt_sleeper; |
96 | snd_wavefront_midi_t midi; /* ICS2115 MIDI interface */ | 97 | snd_wavefront_midi_t midi; /* ICS2115 MIDI interface */ |
98 | struct snd_card *card; | ||
97 | }; | 99 | }; |
98 | 100 | ||
99 | struct _snd_wavefront_card { | 101 | struct _snd_wavefront_card { |
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h new file mode 100644 index 000000000000..2b1ae8edc43c --- /dev/null +++ b/include/sound/soc-dapm.h | |||
@@ -0,0 +1,286 @@ | |||
1 | /* | ||
2 | * linux/sound/soc-dapm.h -- ALSA SoC Dynamic Audio Power Management | ||
3 | * | ||
4 | * Author: Liam Girdwood | ||
5 | * Created: Aug 11th 2005 | ||
6 | * Copyright: Wolfson Microelectronics. PLC. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #ifndef __LINUX_SND_SOC_DAPM_H | ||
14 | #define __LINUX_SND_SOC_DAPM_H | ||
15 | |||
16 | #include <linux/device.h> | ||
17 | #include <linux/types.h> | ||
18 | #include <sound/control.h> | ||
19 | #include <sound/soc.h> | ||
20 | |||
21 | /* widget has no PM register bit */ | ||
22 | #define SND_SOC_NOPM -1 | ||
23 | |||
24 | /* | ||
25 | * SoC dynamic audio power managment | ||
26 | * | ||
27 | * We can have upto 4 power domains | ||
28 | * 1. Codec domain - VREF, VMID | ||
29 | * Usually controlled at codec probe/remove, although can be set | ||
30 | * at stream time if power is not needed for sidetone, etc. | ||
31 | * 2. Platform/Machine domain - physically connected inputs and outputs | ||
32 | * Is platform/machine and user action specific, is set in the machine | ||
33 | * driver and by userspace e.g when HP are inserted | ||
34 | * 3. Path domain - Internal codec path mixers | ||
35 | * Are automatically set when mixer and mux settings are | ||
36 | * changed by the user. | ||
37 | * 4. Stream domain - DAC's and ADC's. | ||
38 | * Enabled when stream playback/capture is started. | ||
39 | */ | ||
40 | |||
41 | /* codec domain */ | ||
42 | #define SND_SOC_DAPM_VMID(wname) \ | ||
43 | { .id = snd_soc_dapm_vmid, .name = wname, .kcontrols = NULL, \ | ||
44 | .num_kcontrols = 0} | ||
45 | |||
46 | /* platform domain */ | ||
47 | #define SND_SOC_DAPM_INPUT(wname) \ | ||
48 | { .id = snd_soc_dapm_input, .name = wname, .kcontrols = NULL, \ | ||
49 | .num_kcontrols = 0} | ||
50 | #define SND_SOC_DAPM_OUTPUT(wname) \ | ||
51 | { .id = snd_soc_dapm_output, .name = wname, .kcontrols = NULL, \ | ||
52 | .num_kcontrols = 0} | ||
53 | #define SND_SOC_DAPM_MIC(wname, wevent) \ | ||
54 | { .id = snd_soc_dapm_mic, .name = wname, .kcontrols = NULL, \ | ||
55 | .num_kcontrols = 0, .event = wevent, \ | ||
56 | .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD} | ||
57 | #define SND_SOC_DAPM_HP(wname, wevent) \ | ||
58 | { .id = snd_soc_dapm_hp, .name = wname, .kcontrols = NULL, \ | ||
59 | .num_kcontrols = 0, .event = wevent, \ | ||
60 | .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD} | ||
61 | #define SND_SOC_DAPM_SPK(wname, wevent) \ | ||
62 | { .id = snd_soc_dapm_spk, .name = wname, .kcontrols = NULL, \ | ||
63 | .num_kcontrols = 0, .event = wevent, \ | ||
64 | .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD} | ||
65 | #define SND_SOC_DAPM_LINE(wname, wevent) \ | ||
66 | { .id = snd_soc_dapm_line, .name = wname, .kcontrols = NULL, \ | ||
67 | .num_kcontrols = 0, .event = wevent, \ | ||
68 | .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD} | ||
69 | |||
70 | /* path domain */ | ||
71 | #define SND_SOC_DAPM_PGA(wname, wreg, wshift, winvert,\ | ||
72 | wcontrols, wncontrols) \ | ||
73 | { .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \ | ||
74 | .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols} | ||
75 | #define SND_SOC_DAPM_MIXER(wname, wreg, wshift, winvert, \ | ||
76 | wcontrols, wncontrols)\ | ||
77 | { .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \ | ||
78 | .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols} | ||
79 | #define SND_SOC_DAPM_MICBIAS(wname, wreg, wshift, winvert) \ | ||
80 | { .id = snd_soc_dapm_micbias, .name = wname, .reg = wreg, .shift = wshift, \ | ||
81 | .invert = winvert, .kcontrols = NULL, .num_kcontrols = 0} | ||
82 | #define SND_SOC_DAPM_SWITCH(wname, wreg, wshift, winvert, wcontrols) \ | ||
83 | { .id = snd_soc_dapm_switch, .name = wname, .reg = wreg, .shift = wshift, \ | ||
84 | .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1} | ||
85 | #define SND_SOC_DAPM_MUX(wname, wreg, wshift, winvert, wcontrols) \ | ||
86 | { .id = snd_soc_dapm_mux, .name = wname, .reg = wreg, .shift = wshift, \ | ||
87 | .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1} | ||
88 | |||
89 | /* path domain with event - event handler must return 0 for success */ | ||
90 | #define SND_SOC_DAPM_PGA_E(wname, wreg, wshift, winvert, wcontrols, \ | ||
91 | wncontrols, wevent, wflags) \ | ||
92 | { .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \ | ||
93 | .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols, \ | ||
94 | .event = wevent, .event_flags = wflags} | ||
95 | #define SND_SOC_DAPM_MIXER_E(wname, wreg, wshift, winvert, wcontrols, \ | ||
96 | wncontrols, wevent, wflags) \ | ||
97 | { .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \ | ||
98 | .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols, \ | ||
99 | .event = wevent, .event_flags = wflags} | ||
100 | #define SND_SOC_DAPM_MICBIAS_E(wname, wreg, wshift, winvert, wevent, wflags) \ | ||
101 | { .id = snd_soc_dapm_micbias, .name = wname, .reg = wreg, .shift = wshift, \ | ||
102 | .invert = winvert, .kcontrols = NULL, .num_kcontrols = 0, \ | ||
103 | .event = wevent, .event_flags = wflags} | ||
104 | #define SND_SOC_DAPM_SWITCH_E(wname, wreg, wshift, winvert, wcontrols, \ | ||
105 | wevent, wflags) \ | ||
106 | { .id = snd_soc_dapm_switch, .name = wname, .reg = wreg, .shift = wshift, \ | ||
107 | .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1 \ | ||
108 | .event = wevent, .event_flags = wflags} | ||
109 | #define SND_SOC_DAPM_MUX_E(wname, wreg, wshift, winvert, wcontrols, \ | ||
110 | wevent, wflags) \ | ||
111 | { .id = snd_soc_dapm_mux, .name = wname, .reg = wreg, .shift = wshift, \ | ||
112 | .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1, \ | ||
113 | .event = wevent, .event_flags = wflags} | ||
114 | |||
115 | /* events that are pre and post DAPM */ | ||
116 | #define SND_SOC_DAPM_PRE(wname, wevent) \ | ||
117 | { .id = snd_soc_dapm_pre, .name = wname, .kcontrols = NULL, \ | ||
118 | .num_kcontrols = 0, .event = wevent, \ | ||
119 | .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD} | ||
120 | #define SND_SOC_DAPM_POST(wname, wevent) \ | ||
121 | { .id = snd_soc_dapm_post, .name = wname, .kcontrols = NULL, \ | ||
122 | .num_kcontrols = 0, .event = wevent, \ | ||
123 | .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD} | ||
124 | |||
125 | /* stream domain */ | ||
126 | #define SND_SOC_DAPM_DAC(wname, stname, wreg, wshift, winvert) \ | ||
127 | { .id = snd_soc_dapm_dac, .name = wname, .sname = stname, .reg = wreg, \ | ||
128 | .shift = wshift, .invert = winvert} | ||
129 | #define SND_SOC_DAPM_ADC(wname, stname, wreg, wshift, winvert) \ | ||
130 | { .id = snd_soc_dapm_adc, .name = wname, .sname = stname, .reg = wreg, \ | ||
131 | .shift = wshift, .invert = winvert} | ||
132 | |||
133 | /* dapm kcontrol types */ | ||
134 | #define SOC_DAPM_SINGLE(xname, reg, shift, mask, invert) \ | ||
135 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | ||
136 | .info = snd_soc_info_volsw, \ | ||
137 | .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \ | ||
138 | .private_value = SOC_SINGLE_VALUE(reg, shift, mask, invert) } | ||
139 | #define SOC_DAPM_DOUBLE(xname, reg, shift_left, shift_right, mask, invert, \ | ||
140 | power) \ | ||
141 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ | ||
142 | .info = snd_soc_info_volsw, \ | ||
143 | .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \ | ||
144 | .private_value = (reg) | ((shift_left) << 8) | ((shift_right) << 12) |\ | ||
145 | ((mask) << 16) | ((invert) << 24) } | ||
146 | #define SOC_DAPM_ENUM(xname, xenum) \ | ||
147 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | ||
148 | .info = snd_soc_info_enum_double, \ | ||
149 | .get = snd_soc_dapm_get_enum_double, \ | ||
150 | .put = snd_soc_dapm_put_enum_double, \ | ||
151 | .private_value = (unsigned long)&xenum } | ||
152 | |||
153 | /* dapm stream operations */ | ||
154 | #define SND_SOC_DAPM_STREAM_NOP 0x0 | ||
155 | #define SND_SOC_DAPM_STREAM_START 0x1 | ||
156 | #define SND_SOC_DAPM_STREAM_STOP 0x2 | ||
157 | #define SND_SOC_DAPM_STREAM_SUSPEND 0x4 | ||
158 | #define SND_SOC_DAPM_STREAM_RESUME 0x8 | ||
159 | #define SND_SOC_DAPM_STREAM_PAUSE_PUSH 0x10 | ||
160 | #define SND_SOC_DAPM_STREAM_PAUSE_RELEASE 0x20 | ||
161 | |||
162 | /* dapm event types */ | ||
163 | #define SND_SOC_DAPM_PRE_PMU 0x1 /* before widget power up */ | ||
164 | #define SND_SOC_DAPM_POST_PMU 0x2 /* after widget power up */ | ||
165 | #define SND_SOC_DAPM_PRE_PMD 0x4 /* before widget power down */ | ||
166 | #define SND_SOC_DAPM_POST_PMD 0x8 /* after widget power down */ | ||
167 | #define SND_SOC_DAPM_PRE_REG 0x10 /* before audio path setup */ | ||
168 | #define SND_SOC_DAPM_POST_REG 0x20 /* after audio path setup */ | ||
169 | |||
170 | /* convenience event type detection */ | ||
171 | #define SND_SOC_DAPM_EVENT_ON(e) \ | ||
172 | (e & (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU)) | ||
173 | #define SND_SOC_DAPM_EVENT_OFF(e) \ | ||
174 | (e & (SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD)) | ||
175 | |||
176 | struct snd_soc_dapm_widget; | ||
177 | enum snd_soc_dapm_type; | ||
178 | struct snd_soc_dapm_path; | ||
179 | struct snd_soc_dapm_pin; | ||
180 | |||
181 | /* dapm controls */ | ||
182 | int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, | ||
183 | struct snd_ctl_elem_value *ucontrol); | ||
184 | int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, | ||
185 | struct snd_ctl_elem_value *ucontrol); | ||
186 | int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol, | ||
187 | struct snd_ctl_elem_value *ucontrol); | ||
188 | int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, | ||
189 | struct snd_ctl_elem_value *ucontrol); | ||
190 | int snd_soc_dapm_new_control(struct snd_soc_codec *codec, | ||
191 | const struct snd_soc_dapm_widget *widget); | ||
192 | |||
193 | /* dapm path setup */ | ||
194 | int snd_soc_dapm_connect_input(struct snd_soc_codec *codec, | ||
195 | const char *sink_name, const char *control_name, const char *src_name); | ||
196 | int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec); | ||
197 | void snd_soc_dapm_free(struct snd_soc_device *socdev); | ||
198 | |||
199 | /* dapm events */ | ||
200 | int snd_soc_dapm_stream_event(struct snd_soc_codec *codec, char *stream, | ||
201 | int event); | ||
202 | |||
203 | /* dapm sys fs - used by the core */ | ||
204 | int snd_soc_dapm_sys_add(struct device *dev); | ||
205 | |||
206 | /* dapm audio endpoint control */ | ||
207 | int snd_soc_dapm_set_endpoint(struct snd_soc_codec *codec, | ||
208 | char *pin, int status); | ||
209 | int snd_soc_dapm_sync_endpoints(struct snd_soc_codec *codec); | ||
210 | |||
211 | /* dapm widget types */ | ||
212 | enum snd_soc_dapm_type { | ||
213 | snd_soc_dapm_input = 0, /* input pin */ | ||
214 | snd_soc_dapm_output, /* output pin */ | ||
215 | snd_soc_dapm_mux, /* selects 1 analog signal from many inputs */ | ||
216 | snd_soc_dapm_mixer, /* mixes several analog signals together */ | ||
217 | snd_soc_dapm_pga, /* programmable gain/attenuation (volume) */ | ||
218 | snd_soc_dapm_adc, /* analog to digital converter */ | ||
219 | snd_soc_dapm_dac, /* digital to analog converter */ | ||
220 | snd_soc_dapm_micbias, /* microphone bias (power) */ | ||
221 | snd_soc_dapm_mic, /* microphone */ | ||
222 | snd_soc_dapm_hp, /* headphones */ | ||
223 | snd_soc_dapm_spk, /* speaker */ | ||
224 | snd_soc_dapm_line, /* line input/output */ | ||
225 | snd_soc_dapm_switch, /* analog switch */ | ||
226 | snd_soc_dapm_vmid, /* codec bias/vmid - to minimise pops */ | ||
227 | snd_soc_dapm_pre, /* machine specific pre widget - exec first */ | ||
228 | snd_soc_dapm_post, /* machine specific post widget - exec last */ | ||
229 | }; | ||
230 | |||
231 | /* dapm audio path between two widgets */ | ||
232 | struct snd_soc_dapm_path { | ||
233 | char *name; | ||
234 | char *long_name; | ||
235 | |||
236 | /* source (input) and sink (output) widgets */ | ||
237 | struct snd_soc_dapm_widget *source; | ||
238 | struct snd_soc_dapm_widget *sink; | ||
239 | struct snd_kcontrol *kcontrol; | ||
240 | |||
241 | /* status */ | ||
242 | u32 connect:1; /* source and sink widgets are connected */ | ||
243 | u32 walked:1; /* path has been walked */ | ||
244 | |||
245 | struct list_head list_source; | ||
246 | struct list_head list_sink; | ||
247 | struct list_head list; | ||
248 | }; | ||
249 | |||
250 | /* dapm widget */ | ||
251 | struct snd_soc_dapm_widget { | ||
252 | enum snd_soc_dapm_type id; | ||
253 | char *name; /* widget name */ | ||
254 | char *sname; /* stream name */ | ||
255 | struct snd_soc_codec *codec; | ||
256 | struct list_head list; | ||
257 | |||
258 | /* dapm control */ | ||
259 | short reg; /* negative reg = no direct dapm */ | ||
260 | unsigned char shift; /* bits to shift */ | ||
261 | unsigned int saved_value; /* widget saved value */ | ||
262 | unsigned int value; /* widget current value */ | ||
263 | unsigned char power:1; /* block power status */ | ||
264 | unsigned char invert:1; /* invert the power bit */ | ||
265 | unsigned char active:1; /* active stream on DAC, ADC's */ | ||
266 | unsigned char connected:1; /* connected codec pin */ | ||
267 | unsigned char new:1; /* cnew complete */ | ||
268 | unsigned char ext:1; /* has external widgets */ | ||
269 | unsigned char muted:1; /* muted for pop reduction */ | ||
270 | unsigned char suspend:1; /* was active before suspend */ | ||
271 | unsigned char pmdown:1; /* waiting for timeout */ | ||
272 | |||
273 | /* external events */ | ||
274 | unsigned short event_flags; /* flags to specify event types */ | ||
275 | int (*event)(struct snd_soc_dapm_widget*, int); | ||
276 | |||
277 | /* kcontrols that relate to this widget */ | ||
278 | int num_kcontrols; | ||
279 | const struct snd_kcontrol_new *kcontrols; | ||
280 | |||
281 | /* widget input and outputs */ | ||
282 | struct list_head sources; | ||
283 | struct list_head sinks; | ||
284 | }; | ||
285 | |||
286 | #endif | ||
diff --git a/include/sound/soc.h b/include/sound/soc.h new file mode 100644 index 000000000000..b1dc364b8f74 --- /dev/null +++ b/include/sound/soc.h | |||
@@ -0,0 +1,461 @@ | |||
1 | /* | ||
2 | * linux/sound/soc.h -- ALSA SoC Layer | ||
3 | * | ||
4 | * Author: Liam Girdwood | ||
5 | * Created: Aug 11th 2005 | ||
6 | * Copyright: Wolfson Microelectronics. PLC. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #ifndef __LINUX_SND_SOC_H | ||
14 | #define __LINUX_SND_SOC_H | ||
15 | |||
16 | #include <linux/platform_device.h> | ||
17 | #include <linux/types.h> | ||
18 | #include <linux/workqueue.h> | ||
19 | #include <sound/driver.h> | ||
20 | #include <sound/core.h> | ||
21 | #include <sound/pcm.h> | ||
22 | #include <sound/control.h> | ||
23 | #include <sound/ac97_codec.h> | ||
24 | |||
25 | #define SND_SOC_VERSION "0.13.0" | ||
26 | |||
27 | /* | ||
28 | * Convenience kcontrol builders | ||
29 | */ | ||
30 | #define SOC_SINGLE_VALUE(reg,shift,mask,invert) ((reg) | ((shift) << 8) |\ | ||
31 | ((shift) << 12) | ((mask) << 16) | ((invert) << 24)) | ||
32 | #define SOC_SINGLE_VALUE_EXT(reg,mask,invert) ((reg) | ((mask) << 16) |\ | ||
33 | ((invert) << 31)) | ||
34 | #define SOC_SINGLE(xname, reg, shift, mask, invert) \ | ||
35 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | ||
36 | .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\ | ||
37 | .put = snd_soc_put_volsw, \ | ||
38 | .private_value = SOC_SINGLE_VALUE(reg, shift, mask, invert) } | ||
39 | #define SOC_DOUBLE(xname, reg, shift_left, shift_right, mask, invert) \ | ||
40 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ | ||
41 | .info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \ | ||
42 | .put = snd_soc_put_volsw, \ | ||
43 | .private_value = (reg) | ((shift_left) << 8) | \ | ||
44 | ((shift_right) << 12) | ((mask) << 16) | ((invert) << 24) } | ||
45 | #define SOC_DOUBLE_R(xname, reg_left, reg_right, shift, mask, invert) \ | ||
46 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ | ||
47 | .info = snd_soc_info_volsw_2r, \ | ||
48 | .get = snd_soc_get_volsw_2r, .put = snd_soc_put_volsw_2r, \ | ||
49 | .private_value = (reg_left) | ((shift) << 8) | \ | ||
50 | ((mask) << 12) | ((invert) << 20) | ((reg_right) << 24) } | ||
51 | #define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, xtexts) \ | ||
52 | { .reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \ | ||
53 | .mask = xmask, .texts = xtexts } | ||
54 | #define SOC_ENUM_SINGLE(xreg, xshift, xmask, xtexts) \ | ||
55 | SOC_ENUM_DOUBLE(xreg, xshift, xshift, xmask, xtexts) | ||
56 | #define SOC_ENUM_SINGLE_EXT(xmask, xtexts) \ | ||
57 | { .mask = xmask, .texts = xtexts } | ||
58 | #define SOC_ENUM(xname, xenum) \ | ||
59 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,\ | ||
60 | .info = snd_soc_info_enum_double, \ | ||
61 | .get = snd_soc_get_enum_double, .put = snd_soc_put_enum_double, \ | ||
62 | .private_value = (unsigned long)&xenum } | ||
63 | #define SOC_SINGLE_EXT(xname, xreg, xshift, xmask, xinvert,\ | ||
64 | xhandler_get, xhandler_put) \ | ||
65 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | ||
66 | .info = snd_soc_info_volsw, \ | ||
67 | .get = xhandler_get, .put = xhandler_put, \ | ||
68 | .private_value = SOC_SINGLE_VALUE(xreg, xshift, xmask, xinvert) } | ||
69 | #define SOC_SINGLE_BOOL_EXT(xname, xdata, xhandler_get, xhandler_put) \ | ||
70 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | ||
71 | .info = snd_soc_info_bool_ext, \ | ||
72 | .get = xhandler_get, .put = xhandler_put, \ | ||
73 | .private_value = xdata } | ||
74 | #define SOC_ENUM_EXT(xname, xenum, xhandler_get, xhandler_put) \ | ||
75 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | ||
76 | .info = snd_soc_info_enum_ext, \ | ||
77 | .get = xhandler_get, .put = xhandler_put, \ | ||
78 | .private_value = (unsigned long)&xenum } | ||
79 | |||
80 | /* | ||
81 | * Digital Audio Interface (DAI) types | ||
82 | */ | ||
83 | #define SND_SOC_DAI_AC97 0x1 | ||
84 | #define SND_SOC_DAI_I2S 0x2 | ||
85 | #define SND_SOC_DAI_PCM 0x4 | ||
86 | |||
87 | /* | ||
88 | * DAI hardware audio formats | ||
89 | */ | ||
90 | #define SND_SOC_DAIFMT_I2S 0 /* I2S mode */ | ||
91 | #define SND_SOC_DAIFMT_RIGHT_J 1 /* Right justified mode */ | ||
92 | #define SND_SOC_DAIFMT_LEFT_J 2 /* Left Justified mode */ | ||
93 | #define SND_SOC_DAIFMT_DSP_A 3 /* L data msb after FRM or LRC */ | ||
94 | #define SND_SOC_DAIFMT_DSP_B 4 /* L data msb during FRM or LRC */ | ||
95 | #define SND_SOC_DAIFMT_AC97 5 /* AC97 */ | ||
96 | |||
97 | #define SND_SOC_DAIFMT_MSB SND_SOC_DAIFMT_LEFT_J | ||
98 | #define SND_SOC_DAIFMT_LSB SND_SOC_DAIFMT_RIGHT_J | ||
99 | |||
100 | /* | ||
101 | * DAI Gating | ||
102 | */ | ||
103 | #define SND_SOC_DAIFMT_CONT (0 << 4) /* continuous clock */ | ||
104 | #define SND_SOC_DAIFMT_GATED (1 << 4) /* clock is gated when not Tx/Rx */ | ||
105 | |||
106 | /* | ||
107 | * DAI hardware signal inversions | ||
108 | */ | ||
109 | #define SND_SOC_DAIFMT_NB_NF (0 << 8) /* normal bit clock + frame */ | ||
110 | #define SND_SOC_DAIFMT_NB_IF (1 << 8) /* normal bclk + inv frm */ | ||
111 | #define SND_SOC_DAIFMT_IB_NF (2 << 8) /* invert bclk + nor frm */ | ||
112 | #define SND_SOC_DAIFMT_IB_IF (3 << 8) /* invert bclk + frm */ | ||
113 | |||
114 | /* | ||
115 | * DAI hardware clock masters | ||
116 | * This is wrt the codec, the inverse is true for the interface | ||
117 | * i.e. if the codec is clk and frm master then the interface is | ||
118 | * clk and frame slave. | ||
119 | */ | ||
120 | #define SND_SOC_DAIFMT_CBM_CFM (0 << 12) /* codec clk & frm master */ | ||
121 | #define SND_SOC_DAIFMT_CBS_CFM (1 << 12) /* codec clk slave & frm master */ | ||
122 | #define SND_SOC_DAIFMT_CBM_CFS (2 << 12) /* codec clk master & frame slave */ | ||
123 | #define SND_SOC_DAIFMT_CBS_CFS (3 << 12) /* codec clk & frm slave */ | ||
124 | |||
125 | #define SND_SOC_DAIFMT_FORMAT_MASK 0x000f | ||
126 | #define SND_SOC_DAIFMT_CLOCK_MASK 0x00f0 | ||
127 | #define SND_SOC_DAIFMT_INV_MASK 0x0f00 | ||
128 | #define SND_SOC_DAIFMT_MASTER_MASK 0xf000 | ||
129 | |||
130 | |||
131 | /* | ||
132 | * Master Clock Directions | ||
133 | */ | ||
134 | #define SND_SOC_CLOCK_IN 0 | ||
135 | #define SND_SOC_CLOCK_OUT 1 | ||
136 | |||
137 | /* | ||
138 | * AC97 codec ID's bitmask | ||
139 | */ | ||
140 | #define SND_SOC_DAI_AC97_ID0 (1 << 0) | ||
141 | #define SND_SOC_DAI_AC97_ID1 (1 << 1) | ||
142 | #define SND_SOC_DAI_AC97_ID2 (1 << 2) | ||
143 | #define SND_SOC_DAI_AC97_ID3 (1 << 3) | ||
144 | |||
145 | struct snd_soc_device; | ||
146 | struct snd_soc_pcm_stream; | ||
147 | struct snd_soc_ops; | ||
148 | struct snd_soc_dai_mode; | ||
149 | struct snd_soc_pcm_runtime; | ||
150 | struct snd_soc_codec_dai; | ||
151 | struct snd_soc_cpu_dai; | ||
152 | struct snd_soc_codec; | ||
153 | struct snd_soc_machine_config; | ||
154 | struct soc_enum; | ||
155 | struct snd_soc_ac97_ops; | ||
156 | struct snd_soc_clock_info; | ||
157 | |||
158 | typedef int (*hw_write_t)(void *,const char* ,int); | ||
159 | typedef int (*hw_read_t)(void *,char* ,int); | ||
160 | |||
161 | extern struct snd_ac97_bus_ops soc_ac97_ops; | ||
162 | |||
163 | /* pcm <-> DAI connect */ | ||
164 | void snd_soc_free_pcms(struct snd_soc_device *socdev); | ||
165 | int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid); | ||
166 | int snd_soc_register_card(struct snd_soc_device *socdev); | ||
167 | |||
168 | /* set runtime hw params */ | ||
169 | int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream, | ||
170 | const struct snd_pcm_hardware *hw); | ||
171 | |||
172 | /* codec IO */ | ||
173 | #define snd_soc_read(codec, reg) codec->read(codec, reg) | ||
174 | #define snd_soc_write(codec, reg, value) codec->write(codec, reg, value) | ||
175 | |||
176 | /* codec register bit access */ | ||
177 | int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg, | ||
178 | unsigned short mask, unsigned short value); | ||
179 | int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg, | ||
180 | unsigned short mask, unsigned short value); | ||
181 | |||
182 | int snd_soc_new_ac97_codec(struct snd_soc_codec *codec, | ||
183 | struct snd_ac97_bus_ops *ops, int num); | ||
184 | void snd_soc_free_ac97_codec(struct snd_soc_codec *codec); | ||
185 | |||
186 | /* | ||
187 | *Controls | ||
188 | */ | ||
189 | struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template, | ||
190 | void *data, char *long_name); | ||
191 | int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol, | ||
192 | struct snd_ctl_elem_info *uinfo); | ||
193 | int snd_soc_info_enum_ext(struct snd_kcontrol *kcontrol, | ||
194 | struct snd_ctl_elem_info *uinfo); | ||
195 | int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol, | ||
196 | struct snd_ctl_elem_value *ucontrol); | ||
197 | int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol, | ||
198 | struct snd_ctl_elem_value *ucontrol); | ||
199 | int snd_soc_info_volsw(struct snd_kcontrol *kcontrol, | ||
200 | struct snd_ctl_elem_info *uinfo); | ||
201 | int snd_soc_info_volsw_ext(struct snd_kcontrol *kcontrol, | ||
202 | struct snd_ctl_elem_info *uinfo); | ||
203 | int snd_soc_info_bool_ext(struct snd_kcontrol *kcontrol, | ||
204 | struct snd_ctl_elem_info *uinfo); | ||
205 | int snd_soc_get_volsw(struct snd_kcontrol *kcontrol, | ||
206 | struct snd_ctl_elem_value *ucontrol); | ||
207 | int snd_soc_put_volsw(struct snd_kcontrol *kcontrol, | ||
208 | struct snd_ctl_elem_value *ucontrol); | ||
209 | int snd_soc_info_volsw_2r(struct snd_kcontrol *kcontrol, | ||
210 | struct snd_ctl_elem_info *uinfo); | ||
211 | int snd_soc_get_volsw_2r(struct snd_kcontrol *kcontrol, | ||
212 | struct snd_ctl_elem_value *ucontrol); | ||
213 | int snd_soc_put_volsw_2r(struct snd_kcontrol *kcontrol, | ||
214 | struct snd_ctl_elem_value *ucontrol); | ||
215 | |||
216 | /* SoC PCM stream information */ | ||
217 | struct snd_soc_pcm_stream { | ||
218 | char *stream_name; | ||
219 | u64 formats; /* SNDRV_PCM_FMTBIT_* */ | ||
220 | unsigned int rates; /* SNDRV_PCM_RATE_* */ | ||
221 | unsigned int rate_min; /* min rate */ | ||
222 | unsigned int rate_max; /* max rate */ | ||
223 | unsigned int channels_min; /* min channels */ | ||
224 | unsigned int channels_max; /* max channels */ | ||
225 | unsigned int active:1; /* stream is in use */ | ||
226 | }; | ||
227 | |||
228 | /* SoC audio ops */ | ||
229 | struct snd_soc_ops { | ||
230 | int (*startup)(struct snd_pcm_substream *); | ||
231 | void (*shutdown)(struct snd_pcm_substream *); | ||
232 | int (*hw_params)(struct snd_pcm_substream *, struct snd_pcm_hw_params *); | ||
233 | int (*hw_free)(struct snd_pcm_substream *); | ||
234 | int (*prepare)(struct snd_pcm_substream *); | ||
235 | int (*trigger)(struct snd_pcm_substream *, int); | ||
236 | }; | ||
237 | |||
238 | /* ASoC codec DAI ops */ | ||
239 | struct snd_soc_codec_ops { | ||
240 | /* codec DAI clocking configuration */ | ||
241 | int (*set_sysclk)(struct snd_soc_codec_dai *codec_dai, | ||
242 | int clk_id, unsigned int freq, int dir); | ||
243 | int (*set_pll)(struct snd_soc_codec_dai *codec_dai, | ||
244 | int pll_id, unsigned int freq_in, unsigned int freq_out); | ||
245 | int (*set_clkdiv)(struct snd_soc_codec_dai *codec_dai, | ||
246 | int div_id, int div); | ||
247 | |||
248 | /* CPU DAI format configuration */ | ||
249 | int (*set_fmt)(struct snd_soc_codec_dai *codec_dai, | ||
250 | unsigned int fmt); | ||
251 | int (*set_tdm_slot)(struct snd_soc_codec_dai *codec_dai, | ||
252 | unsigned int mask, int slots); | ||
253 | int (*set_tristate)(struct snd_soc_codec_dai *, int tristate); | ||
254 | |||
255 | /* digital mute */ | ||
256 | int (*digital_mute)(struct snd_soc_codec_dai *, int mute); | ||
257 | }; | ||
258 | |||
259 | /* ASoC cpu DAI ops */ | ||
260 | struct snd_soc_cpu_ops { | ||
261 | /* CPU DAI clocking configuration */ | ||
262 | int (*set_sysclk)(struct snd_soc_cpu_dai *cpu_dai, | ||
263 | int clk_id, unsigned int freq, int dir); | ||
264 | int (*set_clkdiv)(struct snd_soc_cpu_dai *cpu_dai, | ||
265 | int div_id, int div); | ||
266 | int (*set_pll)(struct snd_soc_cpu_dai *cpu_dai, | ||
267 | int pll_id, unsigned int freq_in, unsigned int freq_out); | ||
268 | |||
269 | /* CPU DAI format configuration */ | ||
270 | int (*set_fmt)(struct snd_soc_cpu_dai *cpu_dai, | ||
271 | unsigned int fmt); | ||
272 | int (*set_tdm_slot)(struct snd_soc_cpu_dai *cpu_dai, | ||
273 | unsigned int mask, int slots); | ||
274 | int (*set_tristate)(struct snd_soc_cpu_dai *, int tristate); | ||
275 | }; | ||
276 | |||
277 | /* SoC Codec DAI */ | ||
278 | struct snd_soc_codec_dai { | ||
279 | char *name; | ||
280 | int id; | ||
281 | |||
282 | /* DAI capabilities */ | ||
283 | struct snd_soc_pcm_stream playback; | ||
284 | struct snd_soc_pcm_stream capture; | ||
285 | |||
286 | /* DAI runtime info */ | ||
287 | struct snd_soc_codec *codec; | ||
288 | unsigned int active; | ||
289 | unsigned char pop_wait:1; | ||
290 | |||
291 | /* ops */ | ||
292 | struct snd_soc_ops ops; | ||
293 | struct snd_soc_codec_ops dai_ops; | ||
294 | |||
295 | /* DAI private data */ | ||
296 | void *private_data; | ||
297 | }; | ||
298 | |||
299 | /* SoC CPU DAI */ | ||
300 | struct snd_soc_cpu_dai { | ||
301 | |||
302 | /* DAI description */ | ||
303 | char *name; | ||
304 | unsigned int id; | ||
305 | unsigned char type; | ||
306 | |||
307 | /* DAI callbacks */ | ||
308 | int (*probe)(struct platform_device *pdev); | ||
309 | void (*remove)(struct platform_device *pdev); | ||
310 | int (*suspend)(struct platform_device *pdev, | ||
311 | struct snd_soc_cpu_dai *cpu_dai); | ||
312 | int (*resume)(struct platform_device *pdev, | ||
313 | struct snd_soc_cpu_dai *cpu_dai); | ||
314 | |||
315 | /* ops */ | ||
316 | struct snd_soc_ops ops; | ||
317 | struct snd_soc_cpu_ops dai_ops; | ||
318 | |||
319 | /* DAI capabilities */ | ||
320 | struct snd_soc_pcm_stream capture; | ||
321 | struct snd_soc_pcm_stream playback; | ||
322 | |||
323 | /* DAI runtime info */ | ||
324 | struct snd_pcm_runtime *runtime; | ||
325 | unsigned char active:1; | ||
326 | void *dma_data; | ||
327 | |||
328 | /* DAI private data */ | ||
329 | void *private_data; | ||
330 | }; | ||
331 | |||
332 | /* SoC Audio Codec */ | ||
333 | struct snd_soc_codec { | ||
334 | char *name; | ||
335 | struct module *owner; | ||
336 | struct mutex mutex; | ||
337 | |||
338 | /* callbacks */ | ||
339 | int (*dapm_event)(struct snd_soc_codec *codec, int event); | ||
340 | |||
341 | /* runtime */ | ||
342 | struct snd_card *card; | ||
343 | struct snd_ac97 *ac97; /* for ad-hoc ac97 devices */ | ||
344 | unsigned int active; | ||
345 | unsigned int pcm_devs; | ||
346 | void *private_data; | ||
347 | |||
348 | /* codec IO */ | ||
349 | void *control_data; /* codec control (i2c/3wire) data */ | ||
350 | unsigned int (*read)(struct snd_soc_codec *, unsigned int); | ||
351 | int (*write)(struct snd_soc_codec *, unsigned int, unsigned int); | ||
352 | hw_write_t hw_write; | ||
353 | hw_read_t hw_read; | ||
354 | void *reg_cache; | ||
355 | short reg_cache_size; | ||
356 | short reg_cache_step; | ||
357 | |||
358 | /* dapm */ | ||
359 | struct list_head dapm_widgets; | ||
360 | struct list_head dapm_paths; | ||
361 | unsigned int dapm_state; | ||
362 | unsigned int suspend_dapm_state; | ||
363 | struct delayed_work delayed_work; | ||
364 | |||
365 | /* codec DAI's */ | ||
366 | struct snd_soc_codec_dai *dai; | ||
367 | unsigned int num_dai; | ||
368 | }; | ||
369 | |||
370 | /* codec device */ | ||
371 | struct snd_soc_codec_device { | ||
372 | int (*probe)(struct platform_device *pdev); | ||
373 | int (*remove)(struct platform_device *pdev); | ||
374 | int (*suspend)(struct platform_device *pdev, pm_message_t state); | ||
375 | int (*resume)(struct platform_device *pdev); | ||
376 | }; | ||
377 | |||
378 | /* SoC platform interface */ | ||
379 | struct snd_soc_platform { | ||
380 | char *name; | ||
381 | |||
382 | int (*probe)(struct platform_device *pdev); | ||
383 | int (*remove)(struct platform_device *pdev); | ||
384 | int (*suspend)(struct platform_device *pdev, | ||
385 | struct snd_soc_cpu_dai *cpu_dai); | ||
386 | int (*resume)(struct platform_device *pdev, | ||
387 | struct snd_soc_cpu_dai *cpu_dai); | ||
388 | |||
389 | /* pcm creation and destruction */ | ||
390 | int (*pcm_new)(struct snd_card *, struct snd_soc_codec_dai *, | ||
391 | struct snd_pcm *); | ||
392 | void (*pcm_free)(struct snd_pcm *); | ||
393 | |||
394 | /* platform stream ops */ | ||
395 | struct snd_pcm_ops *pcm_ops; | ||
396 | }; | ||
397 | |||
398 | /* SoC machine DAI configuration, glues a codec and cpu DAI together */ | ||
399 | struct snd_soc_dai_link { | ||
400 | char *name; /* Codec name */ | ||
401 | char *stream_name; /* Stream name */ | ||
402 | |||
403 | /* DAI */ | ||
404 | struct snd_soc_codec_dai *codec_dai; | ||
405 | struct snd_soc_cpu_dai *cpu_dai; | ||
406 | |||
407 | /* machine stream operations */ | ||
408 | struct snd_soc_ops *ops; | ||
409 | |||
410 | /* codec/machine specific init - e.g. add machine controls */ | ||
411 | int (*init)(struct snd_soc_codec *codec); | ||
412 | }; | ||
413 | |||
414 | /* SoC machine */ | ||
415 | struct snd_soc_machine { | ||
416 | char *name; | ||
417 | |||
418 | int (*probe)(struct platform_device *pdev); | ||
419 | int (*remove)(struct platform_device *pdev); | ||
420 | |||
421 | /* the pre and post PM functions are used to do any PM work before and | ||
422 | * after the codec and DAI's do any PM work. */ | ||
423 | int (*suspend_pre)(struct platform_device *pdev, pm_message_t state); | ||
424 | int (*suspend_post)(struct platform_device *pdev, pm_message_t state); | ||
425 | int (*resume_pre)(struct platform_device *pdev); | ||
426 | int (*resume_post)(struct platform_device *pdev); | ||
427 | |||
428 | /* CPU <--> Codec DAI links */ | ||
429 | struct snd_soc_dai_link *dai_link; | ||
430 | int num_links; | ||
431 | }; | ||
432 | |||
433 | /* SoC Device - the audio subsystem */ | ||
434 | struct snd_soc_device { | ||
435 | struct device *dev; | ||
436 | struct snd_soc_machine *machine; | ||
437 | struct snd_soc_platform *platform; | ||
438 | struct snd_soc_codec *codec; | ||
439 | struct snd_soc_codec_device *codec_dev; | ||
440 | struct delayed_work delayed_work; | ||
441 | void *codec_data; | ||
442 | }; | ||
443 | |||
444 | /* runtime channel data */ | ||
445 | struct snd_soc_pcm_runtime { | ||
446 | struct snd_soc_dai_link *dai; | ||
447 | struct snd_soc_device *socdev; | ||
448 | }; | ||
449 | |||
450 | /* enumerated kcontrol */ | ||
451 | struct soc_enum { | ||
452 | unsigned short reg; | ||
453 | unsigned short reg2; | ||
454 | unsigned char shift_l; | ||
455 | unsigned char shift_r; | ||
456 | unsigned int mask; | ||
457 | const char **texts; | ||
458 | void *dapm; | ||
459 | }; | ||
460 | |||
461 | #endif | ||
diff --git a/include/sound/typedefs.h b/include/sound/typedefs.h deleted file mode 100644 index f454b0206b93..000000000000 --- a/include/sound/typedefs.h +++ /dev/null | |||
@@ -1,173 +0,0 @@ | |||
1 | /* | ||
2 | * Typedef's for backward compatibility (for out-of-kernel drivers) | ||
3 | * | ||
4 | * This file will be removed soon in future | ||
5 | */ | ||
6 | |||
7 | /* core stuff */ | ||
8 | typedef struct snd_card snd_card_t; | ||
9 | typedef struct snd_device snd_device_t; | ||
10 | typedef struct snd_device_ops snd_device_ops_t; | ||
11 | typedef enum snd_card_type snd_card_type_t; | ||
12 | typedef struct snd_minor snd_minor_t; | ||
13 | |||
14 | /* info */ | ||
15 | typedef struct snd_info_entry snd_info_entry_t; | ||
16 | typedef struct snd_info_buffer snd_info_buffer_t; | ||
17 | |||
18 | /* control */ | ||
19 | typedef struct snd_ctl_file snd_ctl_file_t; | ||
20 | typedef struct snd_kcontrol snd_kcontrol_t; | ||
21 | typedef struct snd_kcontrol_new snd_kcontrol_new_t; | ||
22 | typedef struct snd_kcontrol_volatile snd_kcontrol_volatile_t; | ||
23 | typedef struct snd_kctl_event snd_kctl_event_t; | ||
24 | typedef struct snd_aes_iec958 snd_aes_iec958_t; | ||
25 | typedef struct snd_ctl_card_info snd_ctl_card_info_t; | ||
26 | typedef struct snd_ctl_elem_id snd_ctl_elem_id_t; | ||
27 | typedef struct snd_ctl_elem_list snd_ctl_elem_list_t; | ||
28 | typedef struct snd_ctl_elem_info snd_ctl_elem_info_t; | ||
29 | typedef struct snd_ctl_elem_value snd_ctl_elem_value_t; | ||
30 | typedef struct snd_ctl_event snd_ctl_event_t; | ||
31 | #if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) | ||
32 | typedef struct snd_mixer_oss snd_mixer_oss_t; | ||
33 | #endif | ||
34 | |||
35 | /* timer */ | ||
36 | typedef struct snd_timer snd_timer_t; | ||
37 | typedef struct snd_timer_instance snd_timer_instance_t; | ||
38 | typedef struct snd_timer_id snd_timer_id_t; | ||
39 | typedef struct snd_timer_ginfo snd_timer_ginfo_t; | ||
40 | typedef struct snd_timer_gparams snd_timer_gparams_t; | ||
41 | typedef struct snd_timer_gstatus snd_timer_gstatus_t; | ||
42 | typedef struct snd_timer_select snd_timer_select_t; | ||
43 | typedef struct snd_timer_info snd_timer_info_t; | ||
44 | typedef struct snd_timer_params snd_timer_params_t; | ||
45 | typedef struct snd_timer_status snd_timer_status_t; | ||
46 | typedef struct snd_timer_read snd_timer_read_t; | ||
47 | typedef struct snd_timer_tread snd_timer_tread_t; | ||
48 | |||
49 | /* PCM */ | ||
50 | typedef struct snd_pcm snd_pcm_t; | ||
51 | typedef struct snd_pcm_str snd_pcm_str_t; | ||
52 | typedef struct snd_pcm_substream snd_pcm_substream_t; | ||
53 | typedef struct snd_pcm_info snd_pcm_info_t; | ||
54 | typedef struct snd_pcm_hw_params snd_pcm_hw_params_t; | ||
55 | typedef struct snd_pcm_sw_params snd_pcm_sw_params_t; | ||
56 | typedef struct snd_pcm_channel_info snd_pcm_channel_info_t; | ||
57 | typedef struct snd_pcm_status snd_pcm_status_t; | ||
58 | typedef struct snd_pcm_mmap_status snd_pcm_mmap_status_t; | ||
59 | typedef struct snd_pcm_mmap_control snd_pcm_mmap_control_t; | ||
60 | typedef struct snd_mask snd_mask_t; | ||
61 | typedef struct snd_sg_buf snd_pcm_sgbuf_t; | ||
62 | |||
63 | typedef struct snd_interval snd_interval_t; | ||
64 | typedef struct snd_xferi snd_xferi_t; | ||
65 | typedef struct snd_xfern snd_xfern_t; | ||
66 | typedef struct snd_xferv snd_xferv_t; | ||
67 | |||
68 | typedef struct snd_pcm_file snd_pcm_file_t; | ||
69 | typedef struct snd_pcm_runtime snd_pcm_runtime_t; | ||
70 | typedef struct snd_pcm_hardware snd_pcm_hardware_t; | ||
71 | typedef struct snd_pcm_ops snd_pcm_ops_t; | ||
72 | typedef struct snd_pcm_hw_rule snd_pcm_hw_rule_t; | ||
73 | typedef struct snd_pcm_hw_constraints snd_pcm_hw_constraints_t; | ||
74 | typedef struct snd_ratnum ratnum_t; | ||
75 | typedef struct snd_ratden ratden_t; | ||
76 | typedef struct snd_pcm_hw_constraint_ratnums snd_pcm_hw_constraint_ratnums_t; | ||
77 | typedef struct snd_pcm_hw_constraint_ratdens snd_pcm_hw_constraint_ratdens_t; | ||
78 | typedef struct snd_pcm_hw_constraint_list snd_pcm_hw_constraint_list_t; | ||
79 | typedef struct snd_pcm_group snd_pcm_group_t; | ||
80 | typedef struct snd_pcm_notify snd_pcm_notify_t; | ||
81 | |||
82 | /* rawmidi */ | ||
83 | typedef struct snd_rawmidi snd_rawmidi_t; | ||
84 | typedef struct snd_rawmidi_info snd_rawmidi_info_t; | ||
85 | typedef struct snd_rawmidi_params snd_rawmidi_params_t; | ||
86 | typedef struct snd_rawmidi_status snd_rawmidi_status_t; | ||
87 | typedef struct snd_rawmidi_runtime snd_rawmidi_runtime_t; | ||
88 | typedef struct snd_rawmidi_substream snd_rawmidi_substream_t; | ||
89 | typedef struct snd_rawmidi_str snd_rawmidi_str_t; | ||
90 | typedef struct snd_rawmidi_ops snd_rawmidi_ops_t; | ||
91 | typedef struct snd_rawmidi_global_ops snd_rawmidi_global_ops_t; | ||
92 | typedef struct snd_rawmidi_file snd_rawmidi_file_t; | ||
93 | |||
94 | /* hwdep */ | ||
95 | typedef struct snd_hwdep snd_hwdep_t; | ||
96 | typedef struct snd_hwdep_info snd_hwdep_info_t; | ||
97 | typedef struct snd_hwdep_dsp_status snd_hwdep_dsp_status_t; | ||
98 | typedef struct snd_hwdep_dsp_image snd_hwdep_dsp_image_t; | ||
99 | typedef struct snd_hwdep_ops snd_hwdep_ops_t; | ||
100 | |||
101 | /* sequencer */ | ||
102 | typedef struct snd_seq_port_info snd_seq_port_info_t; | ||
103 | typedef struct snd_seq_port_subscribe snd_seq_port_subscribe_t; | ||
104 | typedef struct snd_seq_event snd_seq_event_t; | ||
105 | typedef struct snd_seq_addr snd_seq_addr_t; | ||
106 | typedef struct snd_seq_ev_volume snd_seq_ev_volume_t; | ||
107 | typedef struct snd_seq_ev_loop snd_seq_ev_loop_t; | ||
108 | typedef struct snd_seq_remove_events snd_seq_remove_events_t; | ||
109 | typedef struct snd_seq_query_subs snd_seq_query_subs_t; | ||
110 | typedef struct snd_seq_system_info snd_seq_system_info_t; | ||
111 | typedef struct snd_seq_client_info snd_seq_client_info_t; | ||
112 | typedef struct snd_seq_queue_info snd_seq_queue_info_t; | ||
113 | typedef struct snd_seq_queue_status snd_seq_queue_status_t; | ||
114 | typedef struct snd_seq_queue_tempo snd_seq_queue_tempo_t; | ||
115 | typedef struct snd_seq_queue_owner snd_seq_queue_owner_t; | ||
116 | typedef struct snd_seq_queue_timer snd_seq_queue_timer_t; | ||
117 | typedef struct snd_seq_queue_client snd_seq_queue_client_t; | ||
118 | typedef struct snd_seq_client_pool snd_seq_client_pool_t; | ||
119 | typedef struct snd_seq_instr snd_seq_instr_t; | ||
120 | typedef struct snd_seq_instr_data snd_seq_instr_data_t; | ||
121 | typedef struct snd_seq_instr_header snd_seq_instr_header_t; | ||
122 | |||
123 | typedef struct snd_seq_user_client user_client_t; | ||
124 | typedef struct snd_seq_kernel_client kernel_client_t; | ||
125 | typedef struct snd_seq_client client_t; | ||
126 | typedef struct snd_seq_queue queue_t; | ||
127 | |||
128 | /* seq_device */ | ||
129 | typedef struct snd_seq_device snd_seq_device_t; | ||
130 | typedef struct snd_seq_dev_ops snd_seq_dev_ops_t; | ||
131 | |||
132 | /* seq_midi */ | ||
133 | typedef struct snd_midi_event snd_midi_event_t; | ||
134 | |||
135 | /* seq_midi_emul */ | ||
136 | typedef struct snd_midi_channel snd_midi_channel_t; | ||
137 | typedef struct snd_midi_channel_set snd_midi_channel_set_t; | ||
138 | typedef struct snd_midi_op snd_midi_op_t; | ||
139 | |||
140 | /* seq_oss */ | ||
141 | typedef struct snd_seq_oss_arg snd_seq_oss_arg_t; | ||
142 | typedef struct snd_seq_oss_callback snd_seq_oss_callback_t; | ||
143 | typedef struct snd_seq_oss_reg snd_seq_oss_reg_t; | ||
144 | |||
145 | /* virmidi */ | ||
146 | typedef struct snd_virmidi_dev snd_virmidi_dev_t; | ||
147 | typedef struct snd_virmidi snd_virmidi_t; | ||
148 | |||
149 | /* seq_instr */ | ||
150 | typedef struct snd_seq_kcluster snd_seq_kcluster_t; | ||
151 | typedef struct snd_seq_kinstr_ops snd_seq_kinstr_ops_t; | ||
152 | typedef struct snd_seq_kinstr snd_seq_kinstr_t; | ||
153 | typedef struct snd_seq_kinstr_list snd_seq_kinstr_list_t; | ||
154 | |||
155 | /* ac97 */ | ||
156 | typedef struct snd_ac97_bus ac97_bus_t; | ||
157 | typedef struct snd_ac97_bus_ops ac97_bus_ops_t; | ||
158 | typedef struct snd_ac97_template ac97_template_t; | ||
159 | typedef struct snd_ac97 ac97_t; | ||
160 | |||
161 | /* opl3/4 */ | ||
162 | typedef struct snd_opl3 opl3_t; | ||
163 | typedef struct snd_opl4 opl4_t; | ||
164 | |||
165 | /* mpu401 */ | ||
166 | typedef struct snd_mpu401 mpu401_t; | ||
167 | |||
168 | /* i2c */ | ||
169 | typedef struct snd_i2c_device snd_i2c_device_t; | ||
170 | typedef struct snd_i2c_bus snd_i2c_bus_t; | ||
171 | |||
172 | typedef struct snd_ak4531 ak4531_t; | ||
173 | |||
diff --git a/include/sound/version.h b/include/sound/version.h index 20f7babad514..c39b3802cf18 100644 --- a/include/sound/version.h +++ b/include/sound/version.h | |||
@@ -1,3 +1,3 @@ | |||
1 | /* include/version.h. Generated by alsa/ksync script. */ | 1 | /* include/version.h. Generated by alsa/ksync script. */ |
2 | #define CONFIG_SND_VERSION "1.0.14rc1" | 2 | #define CONFIG_SND_VERSION "1.0.14rc2" |
3 | #define CONFIG_SND_DATE " (Tue Jan 09 09:56:17 2007 UTC)" | 3 | #define CONFIG_SND_DATE " (Fri Feb 09 13:50:10 2007 UTC)" |
diff --git a/include/sound/vx_core.h b/include/sound/vx_core.h index 217394652090..4830651cc4cf 100644 --- a/include/sound/vx_core.h +++ b/include/sound/vx_core.h | |||
@@ -128,7 +128,7 @@ struct snd_vx_hardware { | |||
128 | unsigned int num_ins; | 128 | unsigned int num_ins; |
129 | unsigned int num_outs; | 129 | unsigned int num_outs; |
130 | unsigned int output_level_max; | 130 | unsigned int output_level_max; |
131 | unsigned int *output_level_db_scale; | 131 | const unsigned int *output_level_db_scale; |
132 | }; | 132 | }; |
133 | 133 | ||
134 | /* hwdep id string */ | 134 | /* hwdep id string */ |
diff --git a/include/sound/ymfpci.h b/include/sound/ymfpci.h index f3514ee96bd9..203d2b45b788 100644 --- a/include/sound/ymfpci.h +++ b/include/sound/ymfpci.h | |||
@@ -270,6 +270,7 @@ struct snd_ymfpci_pcm { | |||
270 | struct snd_pcm_substream *substream; | 270 | struct snd_pcm_substream *substream; |
271 | struct snd_ymfpci_voice *voices[2]; /* playback only */ | 271 | struct snd_ymfpci_voice *voices[2]; /* playback only */ |
272 | unsigned int running: 1, | 272 | unsigned int running: 1, |
273 | use_441_slot: 1, | ||
273 | output_front: 1, | 274 | output_front: 1, |
274 | output_rear: 1, | 275 | output_rear: 1, |
275 | swap_rear: 1; | 276 | swap_rear: 1; |
@@ -324,6 +325,7 @@ struct snd_ymfpci { | |||
324 | 325 | ||
325 | u32 active_bank; | 326 | u32 active_bank; |
326 | struct snd_ymfpci_voice voices[64]; | 327 | struct snd_ymfpci_voice voices[64]; |
328 | int src441_used; | ||
327 | 329 | ||
328 | struct snd_ac97_bus *ac97_bus; | 330 | struct snd_ac97_bus *ac97_bus; |
329 | struct snd_ac97 *ac97; | 331 | struct snd_ac97 *ac97; |
@@ -346,7 +348,7 @@ struct snd_ymfpci { | |||
346 | int mode_dup4ch; | 348 | int mode_dup4ch; |
347 | int rear_opened; | 349 | int rear_opened; |
348 | int spdif_opened; | 350 | int spdif_opened; |
349 | struct { | 351 | struct snd_ymfpci_pcm_mixer { |
350 | u16 left; | 352 | u16 left; |
351 | u16 right; | 353 | u16 right; |
352 | struct snd_kcontrol *ctl; | 354 | struct snd_kcontrol *ctl; |
@@ -357,6 +359,8 @@ struct snd_ymfpci { | |||
357 | wait_queue_head_t interrupt_sleep; | 359 | wait_queue_head_t interrupt_sleep; |
358 | atomic_t interrupt_sleep_count; | 360 | atomic_t interrupt_sleep_count; |
359 | struct snd_info_entry *proc_entry; | 361 | struct snd_info_entry *proc_entry; |
362 | const struct firmware *dsp_microcode; | ||
363 | const struct firmware *controller_microcode; | ||
360 | 364 | ||
361 | #ifdef CONFIG_PM | 365 | #ifdef CONFIG_PM |
362 | u32 *saved_regs; | 366 | u32 *saved_regs; |
diff --git a/sound/Kconfig b/sound/Kconfig index 9d77300746c6..97532bbc2ccb 100644 --- a/sound/Kconfig +++ b/sound/Kconfig | |||
@@ -76,6 +76,8 @@ source "sound/sparc/Kconfig" | |||
76 | 76 | ||
77 | source "sound/parisc/Kconfig" | 77 | source "sound/parisc/Kconfig" |
78 | 78 | ||
79 | source "sound/soc/Kconfig" | ||
80 | |||
79 | endmenu | 81 | endmenu |
80 | 82 | ||
81 | menu "Open Sound System" | 83 | menu "Open Sound System" |
diff --git a/sound/Makefile b/sound/Makefile index 9aee54c4882d..b7c7fb7c24c8 100644 --- a/sound/Makefile +++ b/sound/Makefile | |||
@@ -5,7 +5,7 @@ obj-$(CONFIG_SOUND) += soundcore.o | |||
5 | obj-$(CONFIG_SOUND_PRIME) += sound_firmware.o | 5 | obj-$(CONFIG_SOUND_PRIME) += sound_firmware.o |
6 | obj-$(CONFIG_SOUND_PRIME) += oss/ | 6 | obj-$(CONFIG_SOUND_PRIME) += oss/ |
7 | obj-$(CONFIG_DMASOUND) += oss/ | 7 | obj-$(CONFIG_DMASOUND) += oss/ |
8 | obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ synth/ usb/ sparc/ parisc/ pcmcia/ mips/ | 8 | obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ synth/ usb/ sparc/ parisc/ pcmcia/ mips/ soc/ |
9 | obj-$(CONFIG_SND_AOA) += aoa/ | 9 | obj-$(CONFIG_SND_AOA) += aoa/ |
10 | 10 | ||
11 | # This one must be compilable even if sound is configured out | 11 | # This one must be compilable even if sound is configured out |
diff --git a/sound/ac97_bus.c b/sound/ac97_bus.c index 66de2c2f1554..7fa37e15f196 100644 --- a/sound/ac97_bus.c +++ b/sound/ac97_bus.c | |||
@@ -26,6 +26,7 @@ static int ac97_bus_match(struct device *dev, struct device_driver *drv) | |||
26 | return 1; | 26 | return 1; |
27 | } | 27 | } |
28 | 28 | ||
29 | #ifdef CONFIG_PM | ||
29 | static int ac97_bus_suspend(struct device *dev, pm_message_t state) | 30 | static int ac97_bus_suspend(struct device *dev, pm_message_t state) |
30 | { | 31 | { |
31 | int ret = 0; | 32 | int ret = 0; |
@@ -45,12 +46,15 @@ static int ac97_bus_resume(struct device *dev) | |||
45 | 46 | ||
46 | return ret; | 47 | return ret; |
47 | } | 48 | } |
49 | #endif /* CONFIG_PM */ | ||
48 | 50 | ||
49 | struct bus_type ac97_bus_type = { | 51 | struct bus_type ac97_bus_type = { |
50 | .name = "ac97", | 52 | .name = "ac97", |
51 | .match = ac97_bus_match, | 53 | .match = ac97_bus_match, |
54 | #ifdef CONFIG_PM | ||
52 | .suspend = ac97_bus_suspend, | 55 | .suspend = ac97_bus_suspend, |
53 | .resume = ac97_bus_resume, | 56 | .resume = ac97_bus_resume, |
57 | #endif /* CONFIG_PM */ | ||
54 | }; | 58 | }; |
55 | 59 | ||
56 | static int __init ac97_bus_init(void) | 60 | static int __init ac97_bus_init(void) |
diff --git a/sound/aoa/aoa.h b/sound/aoa/aoa.h index 378ef1e9879b..541b908f3cdf 100644 --- a/sound/aoa/aoa.h +++ b/sound/aoa/aoa.h | |||
@@ -99,7 +99,7 @@ struct aoa_fabric { | |||
99 | * that are not assigned yet are passed to the fabric | 99 | * that are not assigned yet are passed to the fabric |
100 | * again for reconsideration. */ | 100 | * again for reconsideration. */ |
101 | extern int | 101 | extern int |
102 | aoa_fabric_register(struct aoa_fabric *fabric); | 102 | aoa_fabric_register(struct aoa_fabric *fabric, struct device *dev); |
103 | 103 | ||
104 | /* it is vital to call this when the fabric exits! | 104 | /* it is vital to call this when the fabric exits! |
105 | * When calling, the remove_codec will be called | 105 | * When calling, the remove_codec will be called |
diff --git a/sound/aoa/codecs/snd-aoa-codec-onyx.c b/sound/aoa/codecs/snd-aoa-codec-onyx.c index 0b7650788f1f..b00fc4842c93 100644 --- a/sound/aoa/codecs/snd-aoa-codec-onyx.c +++ b/sound/aoa/codecs/snd-aoa-codec-onyx.c | |||
@@ -825,7 +825,16 @@ static int onyx_resume(struct codec_info_item *cii) | |||
825 | int err = -ENXIO; | 825 | int err = -ENXIO; |
826 | 826 | ||
827 | mutex_lock(&onyx->mutex); | 827 | mutex_lock(&onyx->mutex); |
828 | /* take codec out of suspend */ | 828 | |
829 | /* reset codec */ | ||
830 | onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 0); | ||
831 | msleep(1); | ||
832 | onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 1); | ||
833 | msleep(1); | ||
834 | onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 0); | ||
835 | msleep(1); | ||
836 | |||
837 | /* take codec out of suspend (if it still is after reset) */ | ||
829 | if (onyx_read_register(onyx, ONYX_REG_CONTROL, &v)) | 838 | if (onyx_read_register(onyx, ONYX_REG_CONTROL, &v)) |
830 | goto out_unlock; | 839 | goto out_unlock; |
831 | onyx_write_register(onyx, ONYX_REG_CONTROL, v & ~(ONYX_ADPSV | ONYX_DAPSV)); | 840 | onyx_write_register(onyx, ONYX_REG_CONTROL, v & ~(ONYX_ADPSV | ONYX_DAPSV)); |
diff --git a/sound/aoa/core/snd-aoa-alsa.c b/sound/aoa/core/snd-aoa-alsa.c index b42fdea77ed0..17fe689ed287 100644 --- a/sound/aoa/core/snd-aoa-alsa.c +++ b/sound/aoa/core/snd-aoa-alsa.c | |||
@@ -14,7 +14,7 @@ MODULE_PARM_DESC(index, "index for AOA sound card."); | |||
14 | 14 | ||
15 | static struct aoa_card *aoa_card; | 15 | static struct aoa_card *aoa_card; |
16 | 16 | ||
17 | int aoa_alsa_init(char *name, struct module *mod) | 17 | int aoa_alsa_init(char *name, struct module *mod, struct device *dev) |
18 | { | 18 | { |
19 | struct snd_card *alsa_card; | 19 | struct snd_card *alsa_card; |
20 | int err; | 20 | int err; |
@@ -28,6 +28,7 @@ int aoa_alsa_init(char *name, struct module *mod) | |||
28 | return -ENOMEM; | 28 | return -ENOMEM; |
29 | aoa_card = alsa_card->private_data; | 29 | aoa_card = alsa_card->private_data; |
30 | aoa_card->alsa_card = alsa_card; | 30 | aoa_card->alsa_card = alsa_card; |
31 | alsa_card->dev = dev; | ||
31 | strlcpy(alsa_card->driver, "AppleOnbdAudio", sizeof(alsa_card->driver)); | 32 | strlcpy(alsa_card->driver, "AppleOnbdAudio", sizeof(alsa_card->driver)); |
32 | strlcpy(alsa_card->shortname, name, sizeof(alsa_card->shortname)); | 33 | strlcpy(alsa_card->shortname, name, sizeof(alsa_card->shortname)); |
33 | strlcpy(alsa_card->longname, name, sizeof(alsa_card->longname)); | 34 | strlcpy(alsa_card->longname, name, sizeof(alsa_card->longname)); |
@@ -59,7 +60,7 @@ void aoa_alsa_cleanup(void) | |||
59 | } | 60 | } |
60 | 61 | ||
61 | int aoa_snd_device_new(snd_device_type_t type, | 62 | int aoa_snd_device_new(snd_device_type_t type, |
62 | void * device_data, struct snd_device_ops * ops) | 63 | void * device_data, struct snd_device_ops * ops) |
63 | { | 64 | { |
64 | struct snd_card *card = aoa_get_card(); | 65 | struct snd_card *card = aoa_get_card(); |
65 | int err; | 66 | int err; |
diff --git a/sound/aoa/core/snd-aoa-alsa.h b/sound/aoa/core/snd-aoa-alsa.h index 660d2f1793bb..9669e4489cab 100644 --- a/sound/aoa/core/snd-aoa-alsa.h +++ b/sound/aoa/core/snd-aoa-alsa.h | |||
@@ -10,7 +10,7 @@ | |||
10 | #define __SND_AOA_ALSA_H | 10 | #define __SND_AOA_ALSA_H |
11 | #include "../aoa.h" | 11 | #include "../aoa.h" |
12 | 12 | ||
13 | extern int aoa_alsa_init(char *name, struct module *mod); | 13 | extern int aoa_alsa_init(char *name, struct module *mod, struct device *dev); |
14 | extern void aoa_alsa_cleanup(void); | 14 | extern void aoa_alsa_cleanup(void); |
15 | 15 | ||
16 | #endif /* __SND_AOA_ALSA_H */ | 16 | #endif /* __SND_AOA_ALSA_H */ |
diff --git a/sound/aoa/core/snd-aoa-core.c b/sound/aoa/core/snd-aoa-core.c index ecd2d8263f2d..19fdae400687 100644 --- a/sound/aoa/core/snd-aoa-core.c +++ b/sound/aoa/core/snd-aoa-core.c | |||
@@ -82,7 +82,7 @@ void aoa_codec_unregister(struct aoa_codec *codec) | |||
82 | } | 82 | } |
83 | EXPORT_SYMBOL_GPL(aoa_codec_unregister); | 83 | EXPORT_SYMBOL_GPL(aoa_codec_unregister); |
84 | 84 | ||
85 | int aoa_fabric_register(struct aoa_fabric *new_fabric) | 85 | int aoa_fabric_register(struct aoa_fabric *new_fabric, struct device *dev) |
86 | { | 86 | { |
87 | struct aoa_codec *c; | 87 | struct aoa_codec *c; |
88 | int err; | 88 | int err; |
@@ -98,7 +98,7 @@ int aoa_fabric_register(struct aoa_fabric *new_fabric) | |||
98 | if (!new_fabric) | 98 | if (!new_fabric) |
99 | return -EINVAL; | 99 | return -EINVAL; |
100 | 100 | ||
101 | err = aoa_alsa_init(new_fabric->name, new_fabric->owner); | 101 | err = aoa_alsa_init(new_fabric->name, new_fabric->owner, dev); |
102 | if (err) | 102 | if (err) |
103 | return err; | 103 | return err; |
104 | 104 | ||
diff --git a/sound/aoa/fabrics/snd-aoa-fabric-layout.c b/sound/aoa/fabrics/snd-aoa-fabric-layout.c index 172eb95476c0..1b94ba6dd279 100644 --- a/sound/aoa/fabrics/snd-aoa-fabric-layout.c +++ b/sound/aoa/fabrics/snd-aoa-fabric-layout.c | |||
@@ -1014,7 +1014,7 @@ static int aoa_fabric_layout_probe(struct soundbus_dev *sdev) | |||
1014 | 1014 | ||
1015 | ldev->gpio.methods->init(&ldev->gpio); | 1015 | ldev->gpio.methods->init(&ldev->gpio); |
1016 | 1016 | ||
1017 | err = aoa_fabric_register(&layout_fabric); | 1017 | err = aoa_fabric_register(&layout_fabric, &sdev->ofdev.dev); |
1018 | if (err && err != -EALREADY) { | 1018 | if (err && err != -EALREADY) { |
1019 | printk(KERN_INFO "snd-aoa-fabric-layout: can't use," | 1019 | printk(KERN_INFO "snd-aoa-fabric-layout: can't use," |
1020 | " another fabric is active!\n"); | 1020 | " another fabric is active!\n"); |
@@ -1034,9 +1034,9 @@ static int aoa_fabric_layout_probe(struct soundbus_dev *sdev) | |||
1034 | list_del(&ldev->list); | 1034 | list_del(&ldev->list); |
1035 | layouts_list_items--; | 1035 | layouts_list_items--; |
1036 | outnodev: | 1036 | outnodev: |
1037 | if (sound) of_node_put(sound); | 1037 | of_node_put(sound); |
1038 | layout_device = NULL; | 1038 | layout_device = NULL; |
1039 | if (ldev) kfree(ldev); | 1039 | kfree(ldev); |
1040 | return -ENODEV; | 1040 | return -ENODEV; |
1041 | } | 1041 | } |
1042 | 1042 | ||
@@ -1077,8 +1077,6 @@ static int aoa_fabric_layout_suspend(struct soundbus_dev *sdev, pm_message_t sta | |||
1077 | { | 1077 | { |
1078 | struct layout_dev *ldev = sdev->ofdev.dev.driver_data; | 1078 | struct layout_dev *ldev = sdev->ofdev.dev.driver_data; |
1079 | 1079 | ||
1080 | printk("aoa_fabric_layout_suspend()\n"); | ||
1081 | |||
1082 | if (ldev->gpio.methods && ldev->gpio.methods->all_amps_off) | 1080 | if (ldev->gpio.methods && ldev->gpio.methods->all_amps_off) |
1083 | ldev->gpio.methods->all_amps_off(&ldev->gpio); | 1081 | ldev->gpio.methods->all_amps_off(&ldev->gpio); |
1084 | 1082 | ||
@@ -1089,8 +1087,6 @@ static int aoa_fabric_layout_resume(struct soundbus_dev *sdev) | |||
1089 | { | 1087 | { |
1090 | struct layout_dev *ldev = sdev->ofdev.dev.driver_data; | 1088 | struct layout_dev *ldev = sdev->ofdev.dev.driver_data; |
1091 | 1089 | ||
1092 | printk("aoa_fabric_layout_resume()\n"); | ||
1093 | |||
1094 | if (ldev->gpio.methods && ldev->gpio.methods->all_amps_off) | 1090 | if (ldev->gpio.methods && ldev->gpio.methods->all_amps_off) |
1095 | ldev->gpio.methods->all_amps_restore(&ldev->gpio); | 1091 | ldev->gpio.methods->all_amps_restore(&ldev->gpio); |
1096 | 1092 | ||
@@ -1107,6 +1103,9 @@ static struct soundbus_driver aoa_soundbus_driver = { | |||
1107 | .suspend = aoa_fabric_layout_suspend, | 1103 | .suspend = aoa_fabric_layout_suspend, |
1108 | .resume = aoa_fabric_layout_resume, | 1104 | .resume = aoa_fabric_layout_resume, |
1109 | #endif | 1105 | #endif |
1106 | .driver = { | ||
1107 | .owner = THIS_MODULE, | ||
1108 | } | ||
1110 | }; | 1109 | }; |
1111 | 1110 | ||
1112 | static int __init aoa_fabric_layout_init(void) | 1111 | static int __init aoa_fabric_layout_init(void) |
diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-core.c b/sound/aoa/soundbus/i2sbus/i2sbus-core.c index e593a1333fe3..e36f6aa448d4 100644 --- a/sound/aoa/soundbus/i2sbus/i2sbus-core.c +++ b/sound/aoa/soundbus/i2sbus/i2sbus-core.c | |||
@@ -41,8 +41,8 @@ static int alloc_dbdma_descriptor_ring(struct i2sbus_dev *i2sdev, | |||
41 | struct dbdma_command_mem *r, | 41 | struct dbdma_command_mem *r, |
42 | int numcmds) | 42 | int numcmds) |
43 | { | 43 | { |
44 | /* one more for rounding */ | 44 | /* one more for rounding, one for branch back, one for stop command */ |
45 | r->size = (numcmds+1) * sizeof(struct dbdma_cmd); | 45 | r->size = (numcmds + 3) * sizeof(struct dbdma_cmd); |
46 | /* We use the PCI APIs for now until the generic one gets fixed | 46 | /* We use the PCI APIs for now until the generic one gets fixed |
47 | * enough or until we get some macio-specific versions | 47 | * enough or until we get some macio-specific versions |
48 | */ | 48 | */ |
@@ -377,11 +377,8 @@ static int i2sbus_suspend(struct macio_dev* dev, pm_message_t state) | |||
377 | if (i2sdev->sound.pcm) { | 377 | if (i2sdev->sound.pcm) { |
378 | /* Suspend PCM streams */ | 378 | /* Suspend PCM streams */ |
379 | snd_pcm_suspend_all(i2sdev->sound.pcm); | 379 | snd_pcm_suspend_all(i2sdev->sound.pcm); |
380 | /* Probably useless as we handle | ||
381 | * power transitions ourselves */ | ||
382 | snd_power_change_state(i2sdev->sound.pcm->card, | ||
383 | SNDRV_CTL_POWER_D3hot); | ||
384 | } | 380 | } |
381 | |||
385 | /* Notify codecs */ | 382 | /* Notify codecs */ |
386 | list_for_each_entry(cii, &i2sdev->sound.codec_list, list) { | 383 | list_for_each_entry(cii, &i2sdev->sound.codec_list, list) { |
387 | err = 0; | 384 | err = 0; |
@@ -390,7 +387,11 @@ static int i2sbus_suspend(struct macio_dev* dev, pm_message_t state) | |||
390 | if (err) | 387 | if (err) |
391 | ret = err; | 388 | ret = err; |
392 | } | 389 | } |
390 | |||
391 | /* wait until streams are stopped */ | ||
392 | i2sbus_wait_for_stop_both(i2sdev); | ||
393 | } | 393 | } |
394 | |||
394 | return ret; | 395 | return ret; |
395 | } | 396 | } |
396 | 397 | ||
@@ -402,6 +403,9 @@ static int i2sbus_resume(struct macio_dev* dev) | |||
402 | int err, ret = 0; | 403 | int err, ret = 0; |
403 | 404 | ||
404 | list_for_each_entry(i2sdev, &control->list, item) { | 405 | list_for_each_entry(i2sdev, &control->list, item) { |
406 | /* reset i2s bus format etc. */ | ||
407 | i2sbus_pcm_prepare_both(i2sdev); | ||
408 | |||
405 | /* Notify codecs so they can re-initialize */ | 409 | /* Notify codecs so they can re-initialize */ |
406 | list_for_each_entry(cii, &i2sdev->sound.codec_list, list) { | 410 | list_for_each_entry(cii, &i2sdev->sound.codec_list, list) { |
407 | err = 0; | 411 | err = 0; |
@@ -410,12 +414,6 @@ static int i2sbus_resume(struct macio_dev* dev) | |||
410 | if (err) | 414 | if (err) |
411 | ret = err; | 415 | ret = err; |
412 | } | 416 | } |
413 | /* Notify Alsa */ | ||
414 | if (i2sdev->sound.pcm) { | ||
415 | /* Same comment as above, probably useless */ | ||
416 | snd_power_change_state(i2sdev->sound.pcm->card, | ||
417 | SNDRV_CTL_POWER_D0); | ||
418 | } | ||
419 | } | 417 | } |
420 | 418 | ||
421 | return ret; | 419 | return ret; |
diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c b/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c index 5eff30b10201..c6b42f9bdbc9 100644 --- a/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c +++ b/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c | |||
@@ -125,7 +125,8 @@ static int i2sbus_pcm_open(struct i2sbus_dev *i2sdev, int in) | |||
125 | } | 125 | } |
126 | /* bus dependent stuff */ | 126 | /* bus dependent stuff */ |
127 | hw->info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | | 127 | hw->info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | |
128 | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_RESUME; | 128 | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_RESUME | |
129 | SNDRV_PCM_INFO_JOINT_DUPLEX; | ||
129 | 130 | ||
130 | CHECK_RATE(5512); | 131 | CHECK_RATE(5512); |
131 | CHECK_RATE(8000); | 132 | CHECK_RATE(8000); |
@@ -245,18 +246,78 @@ static int i2sbus_pcm_close(struct i2sbus_dev *i2sdev, int in) | |||
245 | return err; | 246 | return err; |
246 | } | 247 | } |
247 | 248 | ||
249 | static void i2sbus_wait_for_stop(struct i2sbus_dev *i2sdev, | ||
250 | struct pcm_info *pi) | ||
251 | { | ||
252 | unsigned long flags; | ||
253 | struct completion done; | ||
254 | long timeout; | ||
255 | |||
256 | spin_lock_irqsave(&i2sdev->low_lock, flags); | ||
257 | if (pi->dbdma_ring.stopping) { | ||
258 | init_completion(&done); | ||
259 | pi->stop_completion = &done; | ||
260 | spin_unlock_irqrestore(&i2sdev->low_lock, flags); | ||
261 | timeout = wait_for_completion_timeout(&done, HZ); | ||
262 | spin_lock_irqsave(&i2sdev->low_lock, flags); | ||
263 | pi->stop_completion = NULL; | ||
264 | if (timeout == 0) { | ||
265 | /* timeout expired, stop dbdma forcefully */ | ||
266 | printk(KERN_ERR "i2sbus_wait_for_stop: timed out\n"); | ||
267 | /* make sure RUN, PAUSE and S0 bits are cleared */ | ||
268 | out_le32(&pi->dbdma->control, (RUN | PAUSE | 1) << 16); | ||
269 | pi->dbdma_ring.stopping = 0; | ||
270 | timeout = 10; | ||
271 | while (in_le32(&pi->dbdma->status) & ACTIVE) { | ||
272 | if (--timeout <= 0) | ||
273 | break; | ||
274 | udelay(1); | ||
275 | } | ||
276 | } | ||
277 | } | ||
278 | spin_unlock_irqrestore(&i2sdev->low_lock, flags); | ||
279 | } | ||
280 | |||
281 | #ifdef CONFIG_PM | ||
282 | void i2sbus_wait_for_stop_both(struct i2sbus_dev *i2sdev) | ||
283 | { | ||
284 | struct pcm_info *pi; | ||
285 | |||
286 | get_pcm_info(i2sdev, 0, &pi, NULL); | ||
287 | i2sbus_wait_for_stop(i2sdev, pi); | ||
288 | get_pcm_info(i2sdev, 1, &pi, NULL); | ||
289 | i2sbus_wait_for_stop(i2sdev, pi); | ||
290 | } | ||
291 | #endif | ||
292 | |||
248 | static int i2sbus_hw_params(struct snd_pcm_substream *substream, | 293 | static int i2sbus_hw_params(struct snd_pcm_substream *substream, |
249 | struct snd_pcm_hw_params *params) | 294 | struct snd_pcm_hw_params *params) |
250 | { | 295 | { |
251 | return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); | 296 | return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); |
252 | } | 297 | } |
253 | 298 | ||
254 | static int i2sbus_hw_free(struct snd_pcm_substream *substream) | 299 | static inline int i2sbus_hw_free(struct snd_pcm_substream *substream, int in) |
255 | { | 300 | { |
301 | struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream); | ||
302 | struct pcm_info *pi; | ||
303 | |||
304 | get_pcm_info(i2sdev, in, &pi, NULL); | ||
305 | if (pi->dbdma_ring.stopping) | ||
306 | i2sbus_wait_for_stop(i2sdev, pi); | ||
256 | snd_pcm_lib_free_pages(substream); | 307 | snd_pcm_lib_free_pages(substream); |
257 | return 0; | 308 | return 0; |
258 | } | 309 | } |
259 | 310 | ||
311 | static int i2sbus_playback_hw_free(struct snd_pcm_substream *substream) | ||
312 | { | ||
313 | return i2sbus_hw_free(substream, 0); | ||
314 | } | ||
315 | |||
316 | static int i2sbus_record_hw_free(struct snd_pcm_substream *substream) | ||
317 | { | ||
318 | return i2sbus_hw_free(substream, 1); | ||
319 | } | ||
320 | |||
260 | static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in) | 321 | static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in) |
261 | { | 322 | { |
262 | /* whee. Hard work now. The user has selected a bitrate | 323 | /* whee. Hard work now. The user has selected a bitrate |
@@ -264,7 +325,7 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in) | |||
264 | * I2S controller appropriately. */ | 325 | * I2S controller appropriately. */ |
265 | struct snd_pcm_runtime *runtime; | 326 | struct snd_pcm_runtime *runtime; |
266 | struct dbdma_cmd *command; | 327 | struct dbdma_cmd *command; |
267 | int i, periodsize; | 328 | int i, periodsize, nperiods; |
268 | dma_addr_t offset; | 329 | dma_addr_t offset; |
269 | struct bus_info bi; | 330 | struct bus_info bi; |
270 | struct codec_info_item *cii; | 331 | struct codec_info_item *cii; |
@@ -274,6 +335,7 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in) | |||
274 | struct pcm_info *pi, *other; | 335 | struct pcm_info *pi, *other; |
275 | int cnt; | 336 | int cnt; |
276 | int result = 0; | 337 | int result = 0; |
338 | unsigned int cmd, stopaddr; | ||
277 | 339 | ||
278 | mutex_lock(&i2sdev->lock); | 340 | mutex_lock(&i2sdev->lock); |
279 | 341 | ||
@@ -283,6 +345,13 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in) | |||
283 | result = -EBUSY; | 345 | result = -EBUSY; |
284 | goto out_unlock; | 346 | goto out_unlock; |
285 | } | 347 | } |
348 | if (pi->dbdma_ring.stopping) | ||
349 | i2sbus_wait_for_stop(i2sdev, pi); | ||
350 | |||
351 | if (!pi->substream || !pi->substream->runtime) { | ||
352 | result = -EINVAL; | ||
353 | goto out_unlock; | ||
354 | } | ||
286 | 355 | ||
287 | runtime = pi->substream->runtime; | 356 | runtime = pi->substream->runtime; |
288 | pi->active = 1; | 357 | pi->active = 1; |
@@ -297,24 +366,43 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in) | |||
297 | i2sdev->rate = runtime->rate; | 366 | i2sdev->rate = runtime->rate; |
298 | 367 | ||
299 | periodsize = snd_pcm_lib_period_bytes(pi->substream); | 368 | periodsize = snd_pcm_lib_period_bytes(pi->substream); |
369 | nperiods = pi->substream->runtime->periods; | ||
300 | pi->current_period = 0; | 370 | pi->current_period = 0; |
301 | 371 | ||
302 | /* generate dbdma command ring first */ | 372 | /* generate dbdma command ring first */ |
303 | command = pi->dbdma_ring.cmds; | 373 | command = pi->dbdma_ring.cmds; |
374 | memset(command, 0, (nperiods + 2) * sizeof(struct dbdma_cmd)); | ||
375 | |||
376 | /* commands to DMA to/from the ring */ | ||
377 | /* | ||
378 | * For input, we need to do a graceful stop; if we abort | ||
379 | * the DMA, we end up with leftover bytes that corrupt | ||
380 | * the next recording. To do this we set the S0 status | ||
381 | * bit and wait for the DMA controller to stop. Each | ||
382 | * command has a branch condition to | ||
383 | * make it branch to a stop command if S0 is set. | ||
384 | * On input we also need to wait for the S7 bit to be | ||
385 | * set before turning off the DMA controller. | ||
386 | * In fact we do the graceful stop for output as well. | ||
387 | */ | ||
304 | offset = runtime->dma_addr; | 388 | offset = runtime->dma_addr; |
305 | for (i = 0; i < pi->substream->runtime->periods; | 389 | cmd = (in? INPUT_MORE: OUTPUT_MORE) | BR_IFSET | INTR_ALWAYS; |
306 | i++, command++, offset += periodsize) { | 390 | stopaddr = pi->dbdma_ring.bus_cmd_start + |
307 | memset(command, 0, sizeof(struct dbdma_cmd)); | 391 | (nperiods + 1) * sizeof(struct dbdma_cmd); |
308 | command->command = | 392 | for (i = 0; i < nperiods; i++, command++, offset += periodsize) { |
309 | cpu_to_le16((in ? INPUT_MORE : OUTPUT_MORE) | INTR_ALWAYS); | 393 | command->command = cpu_to_le16(cmd); |
394 | command->cmd_dep = cpu_to_le32(stopaddr); | ||
310 | command->phy_addr = cpu_to_le32(offset); | 395 | command->phy_addr = cpu_to_le32(offset); |
311 | command->req_count = cpu_to_le16(periodsize); | 396 | command->req_count = cpu_to_le16(periodsize); |
312 | command->xfer_status = cpu_to_le16(0); | ||
313 | } | 397 | } |
314 | /* last one branches back to first */ | 398 | |
315 | command--; | 399 | /* branch back to beginning of ring */ |
316 | command->command |= cpu_to_le16(BR_ALWAYS); | 400 | command->command = cpu_to_le16(DBDMA_NOP | BR_ALWAYS); |
317 | command->cmd_dep = cpu_to_le32(pi->dbdma_ring.bus_cmd_start); | 401 | command->cmd_dep = cpu_to_le32(pi->dbdma_ring.bus_cmd_start); |
402 | command++; | ||
403 | |||
404 | /* set stop command */ | ||
405 | command->command = cpu_to_le16(DBDMA_STOP); | ||
318 | 406 | ||
319 | /* ok, let's set the serial format and stuff */ | 407 | /* ok, let's set the serial format and stuff */ |
320 | switch (runtime->format) { | 408 | switch (runtime->format) { |
@@ -435,16 +523,18 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in) | |||
435 | return result; | 523 | return result; |
436 | } | 524 | } |
437 | 525 | ||
438 | static struct dbdma_cmd STOP_CMD = { | 526 | #ifdef CONFIG_PM |
439 | .command = __constant_cpu_to_le16(DBDMA_STOP), | 527 | void i2sbus_pcm_prepare_both(struct i2sbus_dev *i2sdev) |
440 | }; | 528 | { |
529 | i2sbus_pcm_prepare(i2sdev, 0); | ||
530 | i2sbus_pcm_prepare(i2sdev, 1); | ||
531 | } | ||
532 | #endif | ||
441 | 533 | ||
442 | static int i2sbus_pcm_trigger(struct i2sbus_dev *i2sdev, int in, int cmd) | 534 | static int i2sbus_pcm_trigger(struct i2sbus_dev *i2sdev, int in, int cmd) |
443 | { | 535 | { |
444 | struct codec_info_item *cii; | 536 | struct codec_info_item *cii; |
445 | struct pcm_info *pi; | 537 | struct pcm_info *pi; |
446 | int timeout; | ||
447 | struct dbdma_cmd tmp; | ||
448 | int result = 0; | 538 | int result = 0; |
449 | unsigned long flags; | 539 | unsigned long flags; |
450 | 540 | ||
@@ -464,92 +554,50 @@ static int i2sbus_pcm_trigger(struct i2sbus_dev *i2sdev, int in, int cmd) | |||
464 | cii->codec->start(cii, pi->substream); | 554 | cii->codec->start(cii, pi->substream); |
465 | pi->dbdma_ring.running = 1; | 555 | pi->dbdma_ring.running = 1; |
466 | 556 | ||
467 | /* reset dma engine */ | 557 | if (pi->dbdma_ring.stopping) { |
468 | out_le32(&pi->dbdma->control, | 558 | /* Clear the S0 bit, then see if we stopped yet */ |
469 | 0 | (RUN | PAUSE | FLUSH | WAKE) << 16); | 559 | out_le32(&pi->dbdma->control, 1 << 16); |
470 | timeout = 100; | 560 | if (in_le32(&pi->dbdma->status) & ACTIVE) { |
471 | while (in_le32(&pi->dbdma->status) & RUN && timeout--) | 561 | /* possible race here? */ |
472 | udelay(1); | 562 | udelay(10); |
473 | if (timeout <= 0) { | 563 | if (in_le32(&pi->dbdma->status) & ACTIVE) { |
474 | printk(KERN_ERR | 564 | pi->dbdma_ring.stopping = 0; |
475 | "i2sbus: error waiting for dma reset\n"); | 565 | goto out_unlock; /* keep running */ |
476 | result = -ENXIO; | 566 | } |
477 | goto out_unlock; | 567 | } |
478 | } | 568 | } |
479 | 569 | ||
570 | /* make sure RUN, PAUSE and S0 bits are cleared */ | ||
571 | out_le32(&pi->dbdma->control, (RUN | PAUSE | 1) << 16); | ||
572 | |||
573 | /* set branch condition select register */ | ||
574 | out_le32(&pi->dbdma->br_sel, (1 << 16) | 1); | ||
575 | |||
480 | /* write dma command buffer address to the dbdma chip */ | 576 | /* write dma command buffer address to the dbdma chip */ |
481 | out_le32(&pi->dbdma->cmdptr, pi->dbdma_ring.bus_cmd_start); | 577 | out_le32(&pi->dbdma->cmdptr, pi->dbdma_ring.bus_cmd_start); |
482 | /* post PCI write */ | ||
483 | mb(); | ||
484 | (void)in_le32(&pi->dbdma->status); | ||
485 | |||
486 | /* change first command to STOP */ | ||
487 | tmp = *pi->dbdma_ring.cmds; | ||
488 | *pi->dbdma_ring.cmds = STOP_CMD; | ||
489 | |||
490 | /* set running state, remember that the first command is STOP */ | ||
491 | out_le32(&pi->dbdma->control, RUN | (RUN << 16)); | ||
492 | timeout = 100; | ||
493 | /* wait for STOP to be executed */ | ||
494 | while (in_le32(&pi->dbdma->status) & ACTIVE && timeout--) | ||
495 | udelay(1); | ||
496 | if (timeout <= 0) { | ||
497 | printk(KERN_ERR "i2sbus: error waiting for dma stop\n"); | ||
498 | result = -ENXIO; | ||
499 | goto out_unlock; | ||
500 | } | ||
501 | /* again, write dma command buffer address to the dbdma chip, | ||
502 | * this time of the first real command */ | ||
503 | *pi->dbdma_ring.cmds = tmp; | ||
504 | out_le32(&pi->dbdma->cmdptr, pi->dbdma_ring.bus_cmd_start); | ||
505 | /* post write */ | ||
506 | mb(); | ||
507 | (void)in_le32(&pi->dbdma->status); | ||
508 | |||
509 | /* reset dma engine again */ | ||
510 | out_le32(&pi->dbdma->control, | ||
511 | 0 | (RUN | PAUSE | FLUSH | WAKE) << 16); | ||
512 | timeout = 100; | ||
513 | while (in_le32(&pi->dbdma->status) & RUN && timeout--) | ||
514 | udelay(1); | ||
515 | if (timeout <= 0) { | ||
516 | printk(KERN_ERR | ||
517 | "i2sbus: error waiting for dma reset\n"); | ||
518 | result = -ENXIO; | ||
519 | goto out_unlock; | ||
520 | } | ||
521 | 578 | ||
522 | /* wake up the chip with the next descriptor */ | 579 | /* initialize the frame count and current period */ |
523 | out_le32(&pi->dbdma->control, | 580 | pi->current_period = 0; |
524 | (RUN | WAKE) | ((RUN | WAKE) << 16)); | ||
525 | /* get the frame count */ | ||
526 | pi->frame_count = in_le32(&i2sdev->intfregs->frame_count); | 581 | pi->frame_count = in_le32(&i2sdev->intfregs->frame_count); |
527 | 582 | ||
583 | /* set the DMA controller running */ | ||
584 | out_le32(&pi->dbdma->control, (RUN << 16) | RUN); | ||
585 | |||
528 | /* off you go! */ | 586 | /* off you go! */ |
529 | break; | 587 | break; |
588 | |||
530 | case SNDRV_PCM_TRIGGER_STOP: | 589 | case SNDRV_PCM_TRIGGER_STOP: |
531 | case SNDRV_PCM_TRIGGER_SUSPEND: | 590 | case SNDRV_PCM_TRIGGER_SUSPEND: |
532 | if (!pi->dbdma_ring.running) { | 591 | if (!pi->dbdma_ring.running) { |
533 | result = -EALREADY; | 592 | result = -EALREADY; |
534 | goto out_unlock; | 593 | goto out_unlock; |
535 | } | 594 | } |
595 | pi->dbdma_ring.running = 0; | ||
536 | 596 | ||
537 | /* turn off all relevant bits */ | 597 | /* Set the S0 bit to make the DMA branch to the stop cmd */ |
538 | out_le32(&pi->dbdma->control, | 598 | out_le32(&pi->dbdma->control, (1 << 16) | 1); |
539 | (RUN | WAKE | FLUSH | PAUSE) << 16); | 599 | pi->dbdma_ring.stopping = 1; |
540 | { | ||
541 | /* FIXME: move to own function */ | ||
542 | int timeout = 5000; | ||
543 | while ((in_le32(&pi->dbdma->status) & RUN) | ||
544 | && --timeout > 0) | ||
545 | udelay(1); | ||
546 | if (!timeout) | ||
547 | printk(KERN_ERR | ||
548 | "i2sbus: timed out turning " | ||
549 | "off dbdma engine!\n"); | ||
550 | } | ||
551 | 600 | ||
552 | pi->dbdma_ring.running = 0; | ||
553 | list_for_each_entry(cii, &i2sdev->sound.codec_list, list) | 601 | list_for_each_entry(cii, &i2sdev->sound.codec_list, list) |
554 | if (cii->codec->stop) | 602 | if (cii->codec->stop) |
555 | cii->codec->stop(cii, pi->substream); | 603 | cii->codec->stop(cii, pi->substream); |
@@ -574,70 +622,82 @@ static snd_pcm_uframes_t i2sbus_pcm_pointer(struct i2sbus_dev *i2sdev, int in) | |||
574 | fc = in_le32(&i2sdev->intfregs->frame_count); | 622 | fc = in_le32(&i2sdev->intfregs->frame_count); |
575 | fc = fc - pi->frame_count; | 623 | fc = fc - pi->frame_count; |
576 | 624 | ||
577 | return (bytes_to_frames(pi->substream->runtime, | 625 | if (fc >= pi->substream->runtime->buffer_size) |
578 | pi->current_period * | 626 | fc %= pi->substream->runtime->buffer_size; |
579 | snd_pcm_lib_period_bytes(pi->substream)) | 627 | return fc; |
580 | + fc) % pi->substream->runtime->buffer_size; | ||
581 | } | 628 | } |
582 | 629 | ||
583 | static inline void handle_interrupt(struct i2sbus_dev *i2sdev, int in) | 630 | static inline void handle_interrupt(struct i2sbus_dev *i2sdev, int in) |
584 | { | 631 | { |
585 | struct pcm_info *pi; | 632 | struct pcm_info *pi; |
586 | u32 fc; | 633 | u32 fc, nframes; |
587 | u32 delta; | 634 | u32 status; |
635 | int timeout, i; | ||
636 | int dma_stopped = 0; | ||
637 | struct snd_pcm_runtime *runtime; | ||
588 | 638 | ||
589 | spin_lock(&i2sdev->low_lock); | 639 | spin_lock(&i2sdev->low_lock); |
590 | get_pcm_info(i2sdev, in, &pi, NULL); | 640 | get_pcm_info(i2sdev, in, &pi, NULL); |
591 | 641 | if (!pi->dbdma_ring.running && !pi->dbdma_ring.stopping) | |
592 | if (!pi->dbdma_ring.running) { | ||
593 | /* there was still an interrupt pending | ||
594 | * while we stopped. or maybe another | ||
595 | * processor (not the one that was stopping | ||
596 | * the DMA engine) was spinning above | ||
597 | * waiting for the lock. */ | ||
598 | goto out_unlock; | 642 | goto out_unlock; |
599 | } | ||
600 | 643 | ||
601 | fc = in_le32(&i2sdev->intfregs->frame_count); | 644 | i = pi->current_period; |
602 | /* a counter overflow does not change the calculation. */ | 645 | runtime = pi->substream->runtime; |
603 | delta = fc - pi->frame_count; | 646 | while (pi->dbdma_ring.cmds[i].xfer_status) { |
604 | 647 | if (le16_to_cpu(pi->dbdma_ring.cmds[i].xfer_status) & BT) | |
605 | /* update current_period */ | 648 | /* |
606 | while (delta >= pi->substream->runtime->period_size) { | 649 | * BT is the branch taken bit. If it took a branch |
607 | pi->current_period++; | 650 | * it is because we set the S0 bit to make it |
608 | delta = delta - pi->substream->runtime->period_size; | 651 | * branch to the stop command. |
609 | } | 652 | */ |
610 | 653 | dma_stopped = 1; | |
611 | if (unlikely(delta)) { | 654 | pi->dbdma_ring.cmds[i].xfer_status = 0; |
612 | /* Some interrupt came late, so check the dbdma. | 655 | |
613 | * This special case exists to syncronize the frame_count with | 656 | if (++i >= runtime->periods) { |
614 | * the dbdma transfer, but is hit every once in a while. */ | 657 | i = 0; |
615 | int period; | 658 | pi->frame_count += runtime->buffer_size; |
616 | |||
617 | period = (in_le32(&pi->dbdma->cmdptr) | ||
618 | - pi->dbdma_ring.bus_cmd_start) | ||
619 | / sizeof(struct dbdma_cmd); | ||
620 | pi->current_period = pi->current_period | ||
621 | % pi->substream->runtime->periods; | ||
622 | |||
623 | while (pi->current_period != period) { | ||
624 | pi->current_period++; | ||
625 | pi->current_period %= pi->substream->runtime->periods; | ||
626 | /* Set delta to zero, as the frame_count value is too | ||
627 | * high (otherwise the code path will not be executed). | ||
628 | * This corrects the fact that the frame_count is too | ||
629 | * low at the beginning due to buffering. */ | ||
630 | delta = 0; | ||
631 | } | 659 | } |
660 | pi->current_period = i; | ||
661 | |||
662 | /* | ||
663 | * Check the frame count. The DMA tends to get a bit | ||
664 | * ahead of the frame counter, which confuses the core. | ||
665 | */ | ||
666 | fc = in_le32(&i2sdev->intfregs->frame_count); | ||
667 | nframes = i * runtime->period_size; | ||
668 | if (fc < pi->frame_count + nframes) | ||
669 | pi->frame_count = fc - nframes; | ||
632 | } | 670 | } |
633 | 671 | ||
634 | pi->frame_count = fc - delta; | 672 | if (dma_stopped) { |
635 | pi->current_period %= pi->substream->runtime->periods; | 673 | timeout = 1000; |
674 | for (;;) { | ||
675 | status = in_le32(&pi->dbdma->status); | ||
676 | if (!(status & ACTIVE) && (!in || (status & 0x80))) | ||
677 | break; | ||
678 | if (--timeout <= 0) { | ||
679 | printk(KERN_ERR "i2sbus: timed out " | ||
680 | "waiting for DMA to stop!\n"); | ||
681 | break; | ||
682 | } | ||
683 | udelay(1); | ||
684 | } | ||
685 | |||
686 | /* Turn off DMA controller, clear S0 bit */ | ||
687 | out_le32(&pi->dbdma->control, (RUN | PAUSE | 1) << 16); | ||
688 | |||
689 | pi->dbdma_ring.stopping = 0; | ||
690 | if (pi->stop_completion) | ||
691 | complete(pi->stop_completion); | ||
692 | } | ||
636 | 693 | ||
694 | if (!pi->dbdma_ring.running) | ||
695 | goto out_unlock; | ||
637 | spin_unlock(&i2sdev->low_lock); | 696 | spin_unlock(&i2sdev->low_lock); |
638 | /* may call _trigger again, hence needs to be unlocked */ | 697 | /* may call _trigger again, hence needs to be unlocked */ |
639 | snd_pcm_period_elapsed(pi->substream); | 698 | snd_pcm_period_elapsed(pi->substream); |
640 | return; | 699 | return; |
700 | |||
641 | out_unlock: | 701 | out_unlock: |
642 | spin_unlock(&i2sdev->low_lock); | 702 | spin_unlock(&i2sdev->low_lock); |
643 | } | 703 | } |
@@ -718,7 +778,7 @@ static struct snd_pcm_ops i2sbus_playback_ops = { | |||
718 | .close = i2sbus_playback_close, | 778 | .close = i2sbus_playback_close, |
719 | .ioctl = snd_pcm_lib_ioctl, | 779 | .ioctl = snd_pcm_lib_ioctl, |
720 | .hw_params = i2sbus_hw_params, | 780 | .hw_params = i2sbus_hw_params, |
721 | .hw_free = i2sbus_hw_free, | 781 | .hw_free = i2sbus_playback_hw_free, |
722 | .prepare = i2sbus_playback_prepare, | 782 | .prepare = i2sbus_playback_prepare, |
723 | .trigger = i2sbus_playback_trigger, | 783 | .trigger = i2sbus_playback_trigger, |
724 | .pointer = i2sbus_playback_pointer, | 784 | .pointer = i2sbus_playback_pointer, |
@@ -788,7 +848,7 @@ static struct snd_pcm_ops i2sbus_record_ops = { | |||
788 | .close = i2sbus_record_close, | 848 | .close = i2sbus_record_close, |
789 | .ioctl = snd_pcm_lib_ioctl, | 849 | .ioctl = snd_pcm_lib_ioctl, |
790 | .hw_params = i2sbus_hw_params, | 850 | .hw_params = i2sbus_hw_params, |
791 | .hw_free = i2sbus_hw_free, | 851 | .hw_free = i2sbus_record_hw_free, |
792 | .prepare = i2sbus_record_prepare, | 852 | .prepare = i2sbus_record_prepare, |
793 | .trigger = i2sbus_record_trigger, | 853 | .trigger = i2sbus_record_trigger, |
794 | .pointer = i2sbus_record_pointer, | 854 | .pointer = i2sbus_record_pointer, |
@@ -812,7 +872,6 @@ static void i2sbus_private_free(struct snd_pcm *pcm) | |||
812 | module_put(THIS_MODULE); | 872 | module_put(THIS_MODULE); |
813 | } | 873 | } |
814 | 874 | ||
815 | /* FIXME: this function needs an error handling strategy with labels */ | ||
816 | int | 875 | int |
817 | i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card, | 876 | i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card, |
818 | struct codec_info *ci, void *data) | 877 | struct codec_info *ci, void *data) |
@@ -880,41 +939,31 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card, | |||
880 | if (!cii->sdev) { | 939 | if (!cii->sdev) { |
881 | printk(KERN_DEBUG | 940 | printk(KERN_DEBUG |
882 | "i2sbus: failed to get soundbus dev reference\n"); | 941 | "i2sbus: failed to get soundbus dev reference\n"); |
883 | kfree(cii); | 942 | err = -ENODEV; |
884 | return -ENODEV; | 943 | goto out_free_cii; |
885 | } | 944 | } |
886 | 945 | ||
887 | if (!try_module_get(THIS_MODULE)) { | 946 | if (!try_module_get(THIS_MODULE)) { |
888 | printk(KERN_DEBUG "i2sbus: failed to get module reference!\n"); | 947 | printk(KERN_DEBUG "i2sbus: failed to get module reference!\n"); |
889 | soundbus_dev_put(dev); | 948 | err = -EBUSY; |
890 | kfree(cii); | 949 | goto out_put_sdev; |
891 | return -EBUSY; | ||
892 | } | 950 | } |
893 | 951 | ||
894 | if (!try_module_get(ci->owner)) { | 952 | if (!try_module_get(ci->owner)) { |
895 | printk(KERN_DEBUG | 953 | printk(KERN_DEBUG |
896 | "i2sbus: failed to get module reference to codec owner!\n"); | 954 | "i2sbus: failed to get module reference to codec owner!\n"); |
897 | module_put(THIS_MODULE); | 955 | err = -EBUSY; |
898 | soundbus_dev_put(dev); | 956 | goto out_put_this_module; |
899 | kfree(cii); | ||
900 | return -EBUSY; | ||
901 | } | 957 | } |
902 | 958 | ||
903 | if (!dev->pcm) { | 959 | if (!dev->pcm) { |
904 | err = snd_pcm_new(card, | 960 | err = snd_pcm_new(card, dev->pcmname, dev->pcmid, 0, 0, |
905 | dev->pcmname, | ||
906 | dev->pcmid, | ||
907 | 0, | ||
908 | 0, | ||
909 | &dev->pcm); | 961 | &dev->pcm); |
910 | if (err) { | 962 | if (err) { |
911 | printk(KERN_DEBUG "i2sbus: failed to create pcm\n"); | 963 | printk(KERN_DEBUG "i2sbus: failed to create pcm\n"); |
912 | kfree(cii); | 964 | goto out_put_ci_module; |
913 | module_put(ci->owner); | ||
914 | soundbus_dev_put(dev); | ||
915 | module_put(THIS_MODULE); | ||
916 | return err; | ||
917 | } | 965 | } |
966 | dev->pcm->dev = &dev->ofdev.dev; | ||
918 | } | 967 | } |
919 | 968 | ||
920 | /* ALSA yet again sucks. | 969 | /* ALSA yet again sucks. |
@@ -926,20 +975,12 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card, | |||
926 | /* eh? */ | 975 | /* eh? */ |
927 | printk(KERN_ERR | 976 | printk(KERN_ERR |
928 | "Can't attach same bus to different cards!\n"); | 977 | "Can't attach same bus to different cards!\n"); |
929 | module_put(ci->owner); | 978 | err = -EINVAL; |
930 | kfree(cii); | 979 | goto out_put_ci_module; |
931 | soundbus_dev_put(dev); | ||
932 | module_put(THIS_MODULE); | ||
933 | return -EINVAL; | ||
934 | } | ||
935 | if ((err = | ||
936 | snd_pcm_new_stream(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK, 1))) { | ||
937 | module_put(ci->owner); | ||
938 | kfree(cii); | ||
939 | soundbus_dev_put(dev); | ||
940 | module_put(THIS_MODULE); | ||
941 | return err; | ||
942 | } | 980 | } |
981 | err = snd_pcm_new_stream(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK, 1); | ||
982 | if (err) | ||
983 | goto out_put_ci_module; | ||
943 | snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK, | 984 | snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK, |
944 | &i2sbus_playback_ops); | 985 | &i2sbus_playback_ops); |
945 | i2sdev->out.created = 1; | 986 | i2sdev->out.created = 1; |
@@ -949,20 +990,11 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card, | |||
949 | if (dev->pcm->card != card) { | 990 | if (dev->pcm->card != card) { |
950 | printk(KERN_ERR | 991 | printk(KERN_ERR |
951 | "Can't attach same bus to different cards!\n"); | 992 | "Can't attach same bus to different cards!\n"); |
952 | module_put(ci->owner); | 993 | goto out_put_ci_module; |
953 | kfree(cii); | ||
954 | soundbus_dev_put(dev); | ||
955 | module_put(THIS_MODULE); | ||
956 | return -EINVAL; | ||
957 | } | ||
958 | if ((err = | ||
959 | snd_pcm_new_stream(dev->pcm, SNDRV_PCM_STREAM_CAPTURE, 1))) { | ||
960 | module_put(ci->owner); | ||
961 | kfree(cii); | ||
962 | soundbus_dev_put(dev); | ||
963 | module_put(THIS_MODULE); | ||
964 | return err; | ||
965 | } | 994 | } |
995 | err = snd_pcm_new_stream(dev->pcm, SNDRV_PCM_STREAM_CAPTURE, 1); | ||
996 | if (err) | ||
997 | goto out_put_ci_module; | ||
966 | snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_CAPTURE, | 998 | snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_CAPTURE, |
967 | &i2sbus_record_ops); | 999 | &i2sbus_record_ops); |
968 | i2sdev->in.created = 1; | 1000 | i2sdev->in.created = 1; |
@@ -977,11 +1009,7 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card, | |||
977 | err = snd_device_register(card, dev->pcm); | 1009 | err = snd_device_register(card, dev->pcm); |
978 | if (err) { | 1010 | if (err) { |
979 | printk(KERN_ERR "i2sbus: error registering new pcm\n"); | 1011 | printk(KERN_ERR "i2sbus: error registering new pcm\n"); |
980 | module_put(ci->owner); | 1012 | goto out_put_ci_module; |
981 | kfree(cii); | ||
982 | soundbus_dev_put(dev); | ||
983 | module_put(THIS_MODULE); | ||
984 | return err; | ||
985 | } | 1013 | } |
986 | /* no errors any more, so let's add this to our list */ | 1014 | /* no errors any more, so let's add this to our list */ |
987 | list_add(&cii->list, &dev->codec_list); | 1015 | list_add(&cii->list, &dev->codec_list); |
@@ -996,6 +1024,15 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card, | |||
996 | 64 * 1024, 64 * 1024); | 1024 | 64 * 1024, 64 * 1024); |
997 | 1025 | ||
998 | return 0; | 1026 | return 0; |
1027 | out_put_ci_module: | ||
1028 | module_put(ci->owner); | ||
1029 | out_put_this_module: | ||
1030 | module_put(THIS_MODULE); | ||
1031 | out_put_sdev: | ||
1032 | soundbus_dev_put(dev); | ||
1033 | out_free_cii: | ||
1034 | kfree(cii); | ||
1035 | return err; | ||
999 | } | 1036 | } |
1000 | 1037 | ||
1001 | void i2sbus_detach_codec(struct soundbus_dev *dev, void *data) | 1038 | void i2sbus_detach_codec(struct soundbus_dev *dev, void *data) |
diff --git a/sound/aoa/soundbus/i2sbus/i2sbus.h b/sound/aoa/soundbus/i2sbus/i2sbus.h index ec20ee615d7f..ff29654782c9 100644 --- a/sound/aoa/soundbus/i2sbus/i2sbus.h +++ b/sound/aoa/soundbus/i2sbus/i2sbus.h | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <linux/interrupt.h> | 10 | #include <linux/interrupt.h> |
11 | #include <linux/spinlock.h> | 11 | #include <linux/spinlock.h> |
12 | #include <linux/mutex.h> | 12 | #include <linux/mutex.h> |
13 | #include <linux/completion.h> | ||
13 | 14 | ||
14 | #include <sound/pcm.h> | 15 | #include <sound/pcm.h> |
15 | 16 | ||
@@ -34,6 +35,7 @@ struct dbdma_command_mem { | |||
34 | void *space; | 35 | void *space; |
35 | int size; | 36 | int size; |
36 | u32 running:1; | 37 | u32 running:1; |
38 | u32 stopping:1; | ||
37 | }; | 39 | }; |
38 | 40 | ||
39 | struct pcm_info { | 41 | struct pcm_info { |
@@ -45,6 +47,7 @@ struct pcm_info { | |||
45 | u32 frame_count; | 47 | u32 frame_count; |
46 | struct dbdma_command_mem dbdma_ring; | 48 | struct dbdma_command_mem dbdma_ring; |
47 | volatile struct dbdma_regs __iomem *dbdma; | 49 | volatile struct dbdma_regs __iomem *dbdma; |
50 | struct completion *stop_completion; | ||
48 | }; | 51 | }; |
49 | 52 | ||
50 | enum { | 53 | enum { |
@@ -101,6 +104,9 @@ i2sbus_tx_intr(int irq, void *devid); | |||
101 | extern irqreturn_t | 104 | extern irqreturn_t |
102 | i2sbus_rx_intr(int irq, void *devid); | 105 | i2sbus_rx_intr(int irq, void *devid); |
103 | 106 | ||
107 | extern void i2sbus_wait_for_stop_both(struct i2sbus_dev *i2sdev); | ||
108 | extern void i2sbus_pcm_prepare_both(struct i2sbus_dev *i2sdev); | ||
109 | |||
104 | /* control specific functions */ | 110 | /* control specific functions */ |
105 | extern int i2sbus_control_init(struct macio_dev* dev, | 111 | extern int i2sbus_control_init(struct macio_dev* dev, |
106 | struct i2sbus_control **c); | 112 | struct i2sbus_control **c); |
diff --git a/sound/arm/aaci.h b/sound/arm/aaci.h index 06295190606c..9175ff9ded01 100644 --- a/sound/arm/aaci.h +++ b/sound/arm/aaci.h | |||
@@ -228,7 +228,7 @@ struct aaci { | |||
228 | 228 | ||
229 | /* AC'97 */ | 229 | /* AC'97 */ |
230 | struct mutex ac97_sem; | 230 | struct mutex ac97_sem; |
231 | ac97_bus_t *ac97_bus; | 231 | struct snd_ac97_bus *ac97_bus; |
232 | 232 | ||
233 | u32 maincr; | 233 | u32 maincr; |
234 | spinlock_t lock; | 234 | spinlock_t lock; |
diff --git a/sound/core/control.c b/sound/core/control.c index 0c7bcd62e5b2..42bcf2794b28 100644 --- a/sound/core/control.c +++ b/sound/core/control.c | |||
@@ -108,7 +108,6 @@ static void snd_ctl_empty_read_queue(struct snd_ctl_file * ctl) | |||
108 | static int snd_ctl_release(struct inode *inode, struct file *file) | 108 | static int snd_ctl_release(struct inode *inode, struct file *file) |
109 | { | 109 | { |
110 | unsigned long flags; | 110 | unsigned long flags; |
111 | struct list_head *list; | ||
112 | struct snd_card *card; | 111 | struct snd_card *card; |
113 | struct snd_ctl_file *ctl; | 112 | struct snd_ctl_file *ctl; |
114 | struct snd_kcontrol *control; | 113 | struct snd_kcontrol *control; |
@@ -122,12 +121,10 @@ static int snd_ctl_release(struct inode *inode, struct file *file) | |||
122 | list_del(&ctl->list); | 121 | list_del(&ctl->list); |
123 | write_unlock_irqrestore(&card->ctl_files_rwlock, flags); | 122 | write_unlock_irqrestore(&card->ctl_files_rwlock, flags); |
124 | down_write(&card->controls_rwsem); | 123 | down_write(&card->controls_rwsem); |
125 | list_for_each(list, &card->controls) { | 124 | list_for_each_entry(control, &card->controls, list) |
126 | control = snd_kcontrol(list); | ||
127 | for (idx = 0; idx < control->count; idx++) | 125 | for (idx = 0; idx < control->count; idx++) |
128 | if (control->vd[idx].owner == ctl) | 126 | if (control->vd[idx].owner == ctl) |
129 | control->vd[idx].owner = NULL; | 127 | control->vd[idx].owner = NULL; |
130 | } | ||
131 | up_write(&card->controls_rwsem); | 128 | up_write(&card->controls_rwsem); |
132 | snd_ctl_empty_read_queue(ctl); | 129 | snd_ctl_empty_read_queue(ctl); |
133 | kfree(ctl); | 130 | kfree(ctl); |
@@ -140,7 +137,6 @@ void snd_ctl_notify(struct snd_card *card, unsigned int mask, | |||
140 | struct snd_ctl_elem_id *id) | 137 | struct snd_ctl_elem_id *id) |
141 | { | 138 | { |
142 | unsigned long flags; | 139 | unsigned long flags; |
143 | struct list_head *flist; | ||
144 | struct snd_ctl_file *ctl; | 140 | struct snd_ctl_file *ctl; |
145 | struct snd_kctl_event *ev; | 141 | struct snd_kctl_event *ev; |
146 | 142 | ||
@@ -149,14 +145,11 @@ void snd_ctl_notify(struct snd_card *card, unsigned int mask, | |||
149 | #if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) | 145 | #if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) |
150 | card->mixer_oss_change_count++; | 146 | card->mixer_oss_change_count++; |
151 | #endif | 147 | #endif |
152 | list_for_each(flist, &card->ctl_files) { | 148 | list_for_each_entry(ctl, &card->ctl_files, list) { |
153 | struct list_head *elist; | ||
154 | ctl = snd_ctl_file(flist); | ||
155 | if (!ctl->subscribed) | 149 | if (!ctl->subscribed) |
156 | continue; | 150 | continue; |
157 | spin_lock_irqsave(&ctl->read_lock, flags); | 151 | spin_lock_irqsave(&ctl->read_lock, flags); |
158 | list_for_each(elist, &ctl->events) { | 152 | list_for_each_entry(ev, &ctl->events, list) { |
159 | ev = snd_kctl_event(elist); | ||
160 | if (ev->id.numid == id->numid) { | 153 | if (ev->id.numid == id->numid) { |
161 | ev->mask |= mask; | 154 | ev->mask |= mask; |
162 | goto _found; | 155 | goto _found; |
@@ -190,7 +183,8 @@ EXPORT_SYMBOL(snd_ctl_notify); | |||
190 | * | 183 | * |
191 | * Returns the pointer of the new instance, or NULL on failure. | 184 | * Returns the pointer of the new instance, or NULL on failure. |
192 | */ | 185 | */ |
193 | struct snd_kcontrol *snd_ctl_new(struct snd_kcontrol *control, unsigned int access) | 186 | static struct snd_kcontrol *snd_ctl_new(struct snd_kcontrol *control, |
187 | unsigned int access) | ||
194 | { | 188 | { |
195 | struct snd_kcontrol *kctl; | 189 | struct snd_kcontrol *kctl; |
196 | unsigned int idx; | 190 | unsigned int idx; |
@@ -208,8 +202,6 @@ struct snd_kcontrol *snd_ctl_new(struct snd_kcontrol *control, unsigned int acce | |||
208 | return kctl; | 202 | return kctl; |
209 | } | 203 | } |
210 | 204 | ||
211 | EXPORT_SYMBOL(snd_ctl_new); | ||
212 | |||
213 | /** | 205 | /** |
214 | * snd_ctl_new1 - create a control instance from the template | 206 | * snd_ctl_new1 - create a control instance from the template |
215 | * @ncontrol: the initialization record | 207 | * @ncontrol: the initialization record |
@@ -277,11 +269,9 @@ EXPORT_SYMBOL(snd_ctl_free_one); | |||
277 | static unsigned int snd_ctl_hole_check(struct snd_card *card, | 269 | static unsigned int snd_ctl_hole_check(struct snd_card *card, |
278 | unsigned int count) | 270 | unsigned int count) |
279 | { | 271 | { |
280 | struct list_head *list; | ||
281 | struct snd_kcontrol *kctl; | 272 | struct snd_kcontrol *kctl; |
282 | 273 | ||
283 | list_for_each(list, &card->controls) { | 274 | list_for_each_entry(kctl, &card->controls, list) { |
284 | kctl = snd_kcontrol(list); | ||
285 | if ((kctl->id.numid <= card->last_numid && | 275 | if ((kctl->id.numid <= card->last_numid && |
286 | kctl->id.numid + kctl->count > card->last_numid) || | 276 | kctl->id.numid + kctl->count > card->last_numid) || |
287 | (kctl->id.numid <= card->last_numid + count - 1 && | 277 | (kctl->id.numid <= card->last_numid + count - 1 && |
@@ -498,12 +488,10 @@ EXPORT_SYMBOL(snd_ctl_rename_id); | |||
498 | */ | 488 | */ |
499 | struct snd_kcontrol *snd_ctl_find_numid(struct snd_card *card, unsigned int numid) | 489 | struct snd_kcontrol *snd_ctl_find_numid(struct snd_card *card, unsigned int numid) |
500 | { | 490 | { |
501 | struct list_head *list; | ||
502 | struct snd_kcontrol *kctl; | 491 | struct snd_kcontrol *kctl; |
503 | 492 | ||
504 | snd_assert(card != NULL && numid != 0, return NULL); | 493 | snd_assert(card != NULL && numid != 0, return NULL); |
505 | list_for_each(list, &card->controls) { | 494 | list_for_each_entry(kctl, &card->controls, list) { |
506 | kctl = snd_kcontrol(list); | ||
507 | if (kctl->id.numid <= numid && kctl->id.numid + kctl->count > numid) | 495 | if (kctl->id.numid <= numid && kctl->id.numid + kctl->count > numid) |
508 | return kctl; | 496 | return kctl; |
509 | } | 497 | } |
@@ -527,14 +515,12 @@ EXPORT_SYMBOL(snd_ctl_find_numid); | |||
527 | struct snd_kcontrol *snd_ctl_find_id(struct snd_card *card, | 515 | struct snd_kcontrol *snd_ctl_find_id(struct snd_card *card, |
528 | struct snd_ctl_elem_id *id) | 516 | struct snd_ctl_elem_id *id) |
529 | { | 517 | { |
530 | struct list_head *list; | ||
531 | struct snd_kcontrol *kctl; | 518 | struct snd_kcontrol *kctl; |
532 | 519 | ||
533 | snd_assert(card != NULL && id != NULL, return NULL); | 520 | snd_assert(card != NULL && id != NULL, return NULL); |
534 | if (id->numid != 0) | 521 | if (id->numid != 0) |
535 | return snd_ctl_find_numid(card, id->numid); | 522 | return snd_ctl_find_numid(card, id->numid); |
536 | list_for_each(list, &card->controls) { | 523 | list_for_each_entry(kctl, &card->controls, list) { |
537 | kctl = snd_kcontrol(list); | ||
538 | if (kctl->id.iface != id->iface) | 524 | if (kctl->id.iface != id->iface) |
539 | continue; | 525 | continue; |
540 | if (kctl->id.device != id->device) | 526 | if (kctl->id.device != id->device) |
@@ -1182,7 +1168,6 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg | |||
1182 | { | 1168 | { |
1183 | struct snd_ctl_file *ctl; | 1169 | struct snd_ctl_file *ctl; |
1184 | struct snd_card *card; | 1170 | struct snd_card *card; |
1185 | struct list_head *list; | ||
1186 | struct snd_kctl_ioctl *p; | 1171 | struct snd_kctl_ioctl *p; |
1187 | void __user *argp = (void __user *)arg; | 1172 | void __user *argp = (void __user *)arg; |
1188 | int __user *ip = argp; | 1173 | int __user *ip = argp; |
@@ -1232,8 +1217,7 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg | |||
1232 | #endif | 1217 | #endif |
1233 | } | 1218 | } |
1234 | down_read(&snd_ioctl_rwsem); | 1219 | down_read(&snd_ioctl_rwsem); |
1235 | list_for_each(list, &snd_control_ioctls) { | 1220 | list_for_each_entry(p, &snd_control_ioctls, list) { |
1236 | p = list_entry(list, struct snd_kctl_ioctl, list); | ||
1237 | err = p->fioctl(card, ctl, cmd, arg); | 1221 | err = p->fioctl(card, ctl, cmd, arg); |
1238 | if (err != -ENOIOCTLCMD) { | 1222 | if (err != -ENOIOCTLCMD) { |
1239 | up_read(&snd_ioctl_rwsem); | 1223 | up_read(&snd_ioctl_rwsem); |
@@ -1357,13 +1341,11 @@ EXPORT_SYMBOL(snd_ctl_register_ioctl_compat); | |||
1357 | static int _snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn, | 1341 | static int _snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn, |
1358 | struct list_head *lists) | 1342 | struct list_head *lists) |
1359 | { | 1343 | { |
1360 | struct list_head *list; | ||
1361 | struct snd_kctl_ioctl *p; | 1344 | struct snd_kctl_ioctl *p; |
1362 | 1345 | ||
1363 | snd_assert(fcn != NULL, return -EINVAL); | 1346 | snd_assert(fcn != NULL, return -EINVAL); |
1364 | down_write(&snd_ioctl_rwsem); | 1347 | down_write(&snd_ioctl_rwsem); |
1365 | list_for_each(list, lists) { | 1348 | list_for_each_entry(p, lists, list) { |
1366 | p = list_entry(list, struct snd_kctl_ioctl, list); | ||
1367 | if (p->fioctl == fcn) { | 1349 | if (p->fioctl == fcn) { |
1368 | list_del(&p->list); | 1350 | list_del(&p->list); |
1369 | up_write(&snd_ioctl_rwsem); | 1351 | up_write(&snd_ioctl_rwsem); |
@@ -1453,7 +1435,6 @@ static int snd_ctl_dev_register(struct snd_device *device) | |||
1453 | static int snd_ctl_dev_disconnect(struct snd_device *device) | 1435 | static int snd_ctl_dev_disconnect(struct snd_device *device) |
1454 | { | 1436 | { |
1455 | struct snd_card *card = device->device_data; | 1437 | struct snd_card *card = device->device_data; |
1456 | struct list_head *flist; | ||
1457 | struct snd_ctl_file *ctl; | 1438 | struct snd_ctl_file *ctl; |
1458 | int err, cardnum; | 1439 | int err, cardnum; |
1459 | 1440 | ||
@@ -1462,8 +1443,7 @@ static int snd_ctl_dev_disconnect(struct snd_device *device) | |||
1462 | snd_assert(cardnum >= 0 && cardnum < SNDRV_CARDS, return -ENXIO); | 1443 | snd_assert(cardnum >= 0 && cardnum < SNDRV_CARDS, return -ENXIO); |
1463 | 1444 | ||
1464 | down_read(&card->controls_rwsem); | 1445 | down_read(&card->controls_rwsem); |
1465 | list_for_each(flist, &card->ctl_files) { | 1446 | list_for_each_entry(ctl, &card->ctl_files, list) { |
1466 | ctl = snd_ctl_file(flist); | ||
1467 | wake_up(&ctl->change_sleep); | 1447 | wake_up(&ctl->change_sleep); |
1468 | kill_fasync(&ctl->fasync, SIGIO, POLL_ERR); | 1448 | kill_fasync(&ctl->fasync, SIGIO, POLL_ERR); |
1469 | } | 1449 | } |
diff --git a/sound/core/control_compat.c b/sound/core/control_compat.c index ab48962c48ce..9311ca397bbc 100644 --- a/sound/core/control_compat.c +++ b/sound/core/control_compat.c | |||
@@ -392,7 +392,7 @@ enum { | |||
392 | static inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg) | 392 | static inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg) |
393 | { | 393 | { |
394 | struct snd_ctl_file *ctl; | 394 | struct snd_ctl_file *ctl; |
395 | struct list_head *list; | 395 | struct snd_kctl_ioctl *p; |
396 | void __user *argp = compat_ptr(arg); | 396 | void __user *argp = compat_ptr(arg); |
397 | int err; | 397 | int err; |
398 | 398 | ||
@@ -427,8 +427,7 @@ static inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, uns | |||
427 | } | 427 | } |
428 | 428 | ||
429 | down_read(&snd_ioctl_rwsem); | 429 | down_read(&snd_ioctl_rwsem); |
430 | list_for_each(list, &snd_control_compat_ioctls) { | 430 | list_for_each_entry(p, &snd_control_compat_ioctls, list) { |
431 | struct snd_kctl_ioctl *p = list_entry(list, struct snd_kctl_ioctl, list); | ||
432 | if (p->fioctl) { | 431 | if (p->fioctl) { |
433 | err = p->fioctl(ctl->card, ctl, cmd, arg); | 432 | err = p->fioctl(ctl->card, ctl, cmd, arg); |
434 | if (err != -ENOIOCTLCMD) { | 433 | if (err != -ENOIOCTLCMD) { |
diff --git a/sound/core/device.c b/sound/core/device.c index ccb25816ac9e..5858b02b0b1d 100644 --- a/sound/core/device.c +++ b/sound/core/device.c | |||
@@ -79,13 +79,11 @@ EXPORT_SYMBOL(snd_device_new); | |||
79 | */ | 79 | */ |
80 | int snd_device_free(struct snd_card *card, void *device_data) | 80 | int snd_device_free(struct snd_card *card, void *device_data) |
81 | { | 81 | { |
82 | struct list_head *list; | ||
83 | struct snd_device *dev; | 82 | struct snd_device *dev; |
84 | 83 | ||
85 | snd_assert(card != NULL, return -ENXIO); | 84 | snd_assert(card != NULL, return -ENXIO); |
86 | snd_assert(device_data != NULL, return -ENXIO); | 85 | snd_assert(device_data != NULL, return -ENXIO); |
87 | list_for_each(list, &card->devices) { | 86 | list_for_each_entry(dev, &card->devices, list) { |
88 | dev = snd_device(list); | ||
89 | if (dev->device_data != device_data) | 87 | if (dev->device_data != device_data) |
90 | continue; | 88 | continue; |
91 | /* unlink */ | 89 | /* unlink */ |
@@ -124,13 +122,11 @@ EXPORT_SYMBOL(snd_device_free); | |||
124 | */ | 122 | */ |
125 | int snd_device_disconnect(struct snd_card *card, void *device_data) | 123 | int snd_device_disconnect(struct snd_card *card, void *device_data) |
126 | { | 124 | { |
127 | struct list_head *list; | ||
128 | struct snd_device *dev; | 125 | struct snd_device *dev; |
129 | 126 | ||
130 | snd_assert(card != NULL, return -ENXIO); | 127 | snd_assert(card != NULL, return -ENXIO); |
131 | snd_assert(device_data != NULL, return -ENXIO); | 128 | snd_assert(device_data != NULL, return -ENXIO); |
132 | list_for_each(list, &card->devices) { | 129 | list_for_each_entry(dev, &card->devices, list) { |
133 | dev = snd_device(list); | ||
134 | if (dev->device_data != device_data) | 130 | if (dev->device_data != device_data) |
135 | continue; | 131 | continue; |
136 | if (dev->state == SNDRV_DEV_REGISTERED && | 132 | if (dev->state == SNDRV_DEV_REGISTERED && |
@@ -161,14 +157,12 @@ int snd_device_disconnect(struct snd_card *card, void *device_data) | |||
161 | */ | 157 | */ |
162 | int snd_device_register(struct snd_card *card, void *device_data) | 158 | int snd_device_register(struct snd_card *card, void *device_data) |
163 | { | 159 | { |
164 | struct list_head *list; | ||
165 | struct snd_device *dev; | 160 | struct snd_device *dev; |
166 | int err; | 161 | int err; |
167 | 162 | ||
168 | snd_assert(card != NULL, return -ENXIO); | 163 | snd_assert(card != NULL, return -ENXIO); |
169 | snd_assert(device_data != NULL, return -ENXIO); | 164 | snd_assert(device_data != NULL, return -ENXIO); |
170 | list_for_each(list, &card->devices) { | 165 | list_for_each_entry(dev, &card->devices, list) { |
171 | dev = snd_device(list); | ||
172 | if (dev->device_data != device_data) | 166 | if (dev->device_data != device_data) |
173 | continue; | 167 | continue; |
174 | if (dev->state == SNDRV_DEV_BUILD && dev->ops->dev_register) { | 168 | if (dev->state == SNDRV_DEV_BUILD && dev->ops->dev_register) { |
@@ -192,13 +186,11 @@ EXPORT_SYMBOL(snd_device_register); | |||
192 | */ | 186 | */ |
193 | int snd_device_register_all(struct snd_card *card) | 187 | int snd_device_register_all(struct snd_card *card) |
194 | { | 188 | { |
195 | struct list_head *list; | ||
196 | struct snd_device *dev; | 189 | struct snd_device *dev; |
197 | int err; | 190 | int err; |
198 | 191 | ||
199 | snd_assert(card != NULL, return -ENXIO); | 192 | snd_assert(card != NULL, return -ENXIO); |
200 | list_for_each(list, &card->devices) { | 193 | list_for_each_entry(dev, &card->devices, list) { |
201 | dev = snd_device(list); | ||
202 | if (dev->state == SNDRV_DEV_BUILD && dev->ops->dev_register) { | 194 | if (dev->state == SNDRV_DEV_BUILD && dev->ops->dev_register) { |
203 | if ((err = dev->ops->dev_register(dev)) < 0) | 195 | if ((err = dev->ops->dev_register(dev)) < 0) |
204 | return err; | 196 | return err; |
@@ -215,12 +207,10 @@ int snd_device_register_all(struct snd_card *card) | |||
215 | int snd_device_disconnect_all(struct snd_card *card) | 207 | int snd_device_disconnect_all(struct snd_card *card) |
216 | { | 208 | { |
217 | struct snd_device *dev; | 209 | struct snd_device *dev; |
218 | struct list_head *list; | ||
219 | int err = 0; | 210 | int err = 0; |
220 | 211 | ||
221 | snd_assert(card != NULL, return -ENXIO); | 212 | snd_assert(card != NULL, return -ENXIO); |
222 | list_for_each(list, &card->devices) { | 213 | list_for_each_entry(dev, &card->devices, list) { |
223 | dev = snd_device(list); | ||
224 | if (snd_device_disconnect(card, dev->device_data) < 0) | 214 | if (snd_device_disconnect(card, dev->device_data) < 0) |
225 | err = -ENXIO; | 215 | err = -ENXIO; |
226 | } | 216 | } |
@@ -234,7 +224,6 @@ int snd_device_disconnect_all(struct snd_card *card) | |||
234 | int snd_device_free_all(struct snd_card *card, snd_device_cmd_t cmd) | 224 | int snd_device_free_all(struct snd_card *card, snd_device_cmd_t cmd) |
235 | { | 225 | { |
236 | struct snd_device *dev; | 226 | struct snd_device *dev; |
237 | struct list_head *list; | ||
238 | int err; | 227 | int err; |
239 | unsigned int range_low, range_high; | 228 | unsigned int range_low, range_high; |
240 | 229 | ||
@@ -242,8 +231,7 @@ int snd_device_free_all(struct snd_card *card, snd_device_cmd_t cmd) | |||
242 | range_low = cmd * SNDRV_DEV_TYPE_RANGE_SIZE; | 231 | range_low = cmd * SNDRV_DEV_TYPE_RANGE_SIZE; |
243 | range_high = range_low + SNDRV_DEV_TYPE_RANGE_SIZE - 1; | 232 | range_high = range_low + SNDRV_DEV_TYPE_RANGE_SIZE - 1; |
244 | __again: | 233 | __again: |
245 | list_for_each(list, &card->devices) { | 234 | list_for_each_entry(dev, &card->devices, list) { |
246 | dev = snd_device(list); | ||
247 | if (dev->type >= range_low && dev->type <= range_high) { | 235 | if (dev->type >= range_low && dev->type <= range_high) { |
248 | if ((err = snd_device_free(card, dev->device_data)) < 0) | 236 | if ((err = snd_device_free(card, dev->device_data)) < 0) |
249 | return err; | 237 | return err; |
diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c index 46b47689362c..39c03f3dfbfa 100644 --- a/sound/core/hwdep.c +++ b/sound/core/hwdep.c | |||
@@ -47,14 +47,11 @@ static int snd_hwdep_dev_disconnect(struct snd_device *device); | |||
47 | 47 | ||
48 | static struct snd_hwdep *snd_hwdep_search(struct snd_card *card, int device) | 48 | static struct snd_hwdep *snd_hwdep_search(struct snd_card *card, int device) |
49 | { | 49 | { |
50 | struct list_head *p; | ||
51 | struct snd_hwdep *hwdep; | 50 | struct snd_hwdep *hwdep; |
52 | 51 | ||
53 | list_for_each(p, &snd_hwdep_devices) { | 52 | list_for_each_entry(hwdep, &snd_hwdep_devices, list) |
54 | hwdep = list_entry(p, struct snd_hwdep, list); | ||
55 | if (hwdep->card == card && hwdep->device == device) | 53 | if (hwdep->card == card && hwdep->device == device) |
56 | return hwdep; | 54 | return hwdep; |
57 | } | ||
58 | return NULL; | 55 | return NULL; |
59 | } | 56 | } |
60 | 57 | ||
@@ -159,15 +156,16 @@ static int snd_hwdep_release(struct inode *inode, struct file * file) | |||
159 | int err = -ENXIO; | 156 | int err = -ENXIO; |
160 | struct snd_hwdep *hw = file->private_data; | 157 | struct snd_hwdep *hw = file->private_data; |
161 | struct module *mod = hw->card->module; | 158 | struct module *mod = hw->card->module; |
159 | |||
162 | mutex_lock(&hw->open_mutex); | 160 | mutex_lock(&hw->open_mutex); |
163 | if (hw->ops.release) { | 161 | if (hw->ops.release) |
164 | err = hw->ops.release(hw, file); | 162 | err = hw->ops.release(hw, file); |
165 | wake_up(&hw->open_wait); | ||
166 | } | ||
167 | if (hw->used > 0) | 163 | if (hw->used > 0) |
168 | hw->used--; | 164 | hw->used--; |
169 | snd_card_file_remove(hw->card, file); | ||
170 | mutex_unlock(&hw->open_mutex); | 165 | mutex_unlock(&hw->open_mutex); |
166 | wake_up(&hw->open_wait); | ||
167 | |||
168 | snd_card_file_remove(hw->card, file); | ||
171 | module_put(mod); | 169 | module_put(mod); |
172 | return err; | 170 | return err; |
173 | } | 171 | } |
@@ -468,15 +466,12 @@ static int snd_hwdep_dev_disconnect(struct snd_device *device) | |||
468 | static void snd_hwdep_proc_read(struct snd_info_entry *entry, | 466 | static void snd_hwdep_proc_read(struct snd_info_entry *entry, |
469 | struct snd_info_buffer *buffer) | 467 | struct snd_info_buffer *buffer) |
470 | { | 468 | { |
471 | struct list_head *p; | ||
472 | struct snd_hwdep *hwdep; | 469 | struct snd_hwdep *hwdep; |
473 | 470 | ||
474 | mutex_lock(®ister_mutex); | 471 | mutex_lock(®ister_mutex); |
475 | list_for_each(p, &snd_hwdep_devices) { | 472 | list_for_each_entry(hwdep, &snd_hwdep_devices, list) |
476 | hwdep = list_entry(p, struct snd_hwdep, list); | ||
477 | snd_iprintf(buffer, "%02i-%02i: %s\n", | 473 | snd_iprintf(buffer, "%02i-%02i: %s\n", |
478 | hwdep->card->number, hwdep->device, hwdep->name); | 474 | hwdep->card->number, hwdep->device, hwdep->name); |
479 | } | ||
480 | mutex_unlock(®ister_mutex); | 475 | mutex_unlock(®ister_mutex); |
481 | } | 476 | } |
482 | 477 | ||
diff --git a/sound/core/init.c b/sound/core/init.c index a4cc6b155ae9..db6103733742 100644 --- a/sound/core/init.c +++ b/sound/core/init.c | |||
@@ -114,22 +114,28 @@ struct snd_card *snd_card_new(int idx, const char *xid, | |||
114 | if (idx < 0) { | 114 | if (idx < 0) { |
115 | int idx2; | 115 | int idx2; |
116 | for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++) | 116 | for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++) |
117 | /* idx == -1 == 0xffff means: take any free slot */ | ||
117 | if (~snd_cards_lock & idx & 1<<idx2) { | 118 | if (~snd_cards_lock & idx & 1<<idx2) { |
118 | idx = idx2; | 119 | idx = idx2; |
119 | if (idx >= snd_ecards_limit) | 120 | if (idx >= snd_ecards_limit) |
120 | snd_ecards_limit = idx + 1; | 121 | snd_ecards_limit = idx + 1; |
121 | break; | 122 | break; |
122 | } | 123 | } |
123 | } else if (idx < snd_ecards_limit) { | 124 | } else { |
124 | if (snd_cards_lock & (1 << idx)) | 125 | if (idx < snd_ecards_limit) { |
125 | err = -ENODEV; /* invalid */ | 126 | if (snd_cards_lock & (1 << idx)) |
126 | } else if (idx < SNDRV_CARDS) | 127 | err = -EBUSY; /* invalid */ |
127 | snd_ecards_limit = idx + 1; /* increase the limit */ | 128 | } else { |
128 | else | 129 | if (idx < SNDRV_CARDS) |
129 | err = -ENODEV; | 130 | snd_ecards_limit = idx + 1; /* increase the limit */ |
131 | else | ||
132 | err = -ENODEV; | ||
133 | } | ||
134 | } | ||
130 | if (idx < 0 || err < 0) { | 135 | if (idx < 0 || err < 0) { |
131 | mutex_unlock(&snd_card_mutex); | 136 | mutex_unlock(&snd_card_mutex); |
132 | snd_printk(KERN_ERR "cannot find the slot for index %d (range 0-%i)\n", idx, snd_ecards_limit - 1); | 137 | snd_printk(KERN_ERR "cannot find the slot for index %d (range 0-%i), error: %d\n", |
138 | idx, snd_ecards_limit - 1, err); | ||
133 | goto __error; | 139 | goto __error; |
134 | } | 140 | } |
135 | snd_cards_lock |= 1 << idx; /* lock it */ | 141 | snd_cards_lock |= 1 << idx; /* lock it */ |
diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c index bc0bd0910a62..f057430db0d0 100644 --- a/sound/core/memalloc.c +++ b/sound/core/memalloc.c | |||
@@ -406,19 +406,17 @@ void snd_dma_free_pages(struct snd_dma_buffer *dmab) | |||
406 | */ | 406 | */ |
407 | size_t snd_dma_get_reserved_buf(struct snd_dma_buffer *dmab, unsigned int id) | 407 | size_t snd_dma_get_reserved_buf(struct snd_dma_buffer *dmab, unsigned int id) |
408 | { | 408 | { |
409 | struct list_head *p; | ||
410 | struct snd_mem_list *mem; | 409 | struct snd_mem_list *mem; |
411 | 410 | ||
412 | snd_assert(dmab, return 0); | 411 | snd_assert(dmab, return 0); |
413 | 412 | ||
414 | mutex_lock(&list_mutex); | 413 | mutex_lock(&list_mutex); |
415 | list_for_each(p, &mem_list_head) { | 414 | list_for_each_entry(mem, &mem_list_head, list) { |
416 | mem = list_entry(p, struct snd_mem_list, list); | ||
417 | if (mem->id == id && | 415 | if (mem->id == id && |
418 | (mem->buffer.dev.dev == NULL || dmab->dev.dev == NULL || | 416 | (mem->buffer.dev.dev == NULL || dmab->dev.dev == NULL || |
419 | ! memcmp(&mem->buffer.dev, &dmab->dev, sizeof(dmab->dev)))) { | 417 | ! memcmp(&mem->buffer.dev, &dmab->dev, sizeof(dmab->dev)))) { |
420 | struct device *dev = dmab->dev.dev; | 418 | struct device *dev = dmab->dev.dev; |
421 | list_del(p); | 419 | list_del(&mem->list); |
422 | *dmab = mem->buffer; | 420 | *dmab = mem->buffer; |
423 | if (dmab->dev.dev == NULL) | 421 | if (dmab->dev.dev == NULL) |
424 | dmab->dev.dev = dev; | 422 | dmab->dev.dev = dev; |
@@ -488,7 +486,6 @@ static int snd_mem_proc_read(char *page, char **start, off_t off, | |||
488 | { | 486 | { |
489 | int len = 0; | 487 | int len = 0; |
490 | long pages = snd_allocated_pages >> (PAGE_SHIFT-12); | 488 | long pages = snd_allocated_pages >> (PAGE_SHIFT-12); |
491 | struct list_head *p; | ||
492 | struct snd_mem_list *mem; | 489 | struct snd_mem_list *mem; |
493 | int devno; | 490 | int devno; |
494 | static char *types[] = { "UNKNOWN", "CONT", "DEV", "DEV-SG", "SBUS" }; | 491 | static char *types[] = { "UNKNOWN", "CONT", "DEV", "DEV-SG", "SBUS" }; |
@@ -498,8 +495,7 @@ static int snd_mem_proc_read(char *page, char **start, off_t off, | |||
498 | "pages : %li bytes (%li pages per %likB)\n", | 495 | "pages : %li bytes (%li pages per %likB)\n", |
499 | pages * PAGE_SIZE, pages, PAGE_SIZE / 1024); | 496 | pages * PAGE_SIZE, pages, PAGE_SIZE / 1024); |
500 | devno = 0; | 497 | devno = 0; |
501 | list_for_each(p, &mem_list_head) { | 498 | list_for_each_entry(mem, &mem_list_head, list) { |
502 | mem = list_entry(p, struct snd_mem_list, list); | ||
503 | devno++; | 499 | devno++; |
504 | len += snprintf(page + len, count - len, | 500 | len += snprintf(page + len, count - len, |
505 | "buffer %d : ID %08x : type %s\n", | 501 | "buffer %d : ID %08x : type %s\n", |
diff --git a/sound/core/misc.c b/sound/core/misc.c index 03fc711f4127..6db86a7c9704 100644 --- a/sound/core/misc.c +++ b/sound/core/misc.c | |||
@@ -78,3 +78,31 @@ void snd_verbose_printd(const char *file, int line, const char *format, ...) | |||
78 | 78 | ||
79 | EXPORT_SYMBOL(snd_verbose_printd); | 79 | EXPORT_SYMBOL(snd_verbose_printd); |
80 | #endif | 80 | #endif |
81 | |||
82 | #ifdef CONFIG_PCI | ||
83 | #include <linux/pci.h> | ||
84 | /** | ||
85 | * snd_pci_quirk_lookup - look up a PCI SSID quirk list | ||
86 | * @pci: pci_dev handle | ||
87 | * @list: quirk list, terminated by a null entry | ||
88 | * | ||
89 | * Look through the given quirk list and finds a matching entry | ||
90 | * with the same PCI SSID. When subdevice is 0, all subdevice | ||
91 | * values may match. | ||
92 | * | ||
93 | * Returns the matched entry pointer, or NULL if nothing matched. | ||
94 | */ | ||
95 | const struct snd_pci_quirk * | ||
96 | snd_pci_quirk_lookup(struct pci_dev *pci, const struct snd_pci_quirk *list) | ||
97 | { | ||
98 | const struct snd_pci_quirk *q; | ||
99 | |||
100 | for (q = list; q->subvendor; q++) | ||
101 | if (q->subvendor == pci->subsystem_vendor && | ||
102 | (!q->subdevice || q->subdevice == pci->subsystem_device)) | ||
103 | return q; | ||
104 | return NULL; | ||
105 | } | ||
106 | |||
107 | EXPORT_SYMBOL(snd_pci_quirk_lookup); | ||
108 | #endif | ||
diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 8e0189885516..2743414fc8fa 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c | |||
@@ -45,11 +45,9 @@ static int snd_pcm_dev_disconnect(struct snd_device *device); | |||
45 | 45 | ||
46 | static struct snd_pcm *snd_pcm_search(struct snd_card *card, int device) | 46 | static struct snd_pcm *snd_pcm_search(struct snd_card *card, int device) |
47 | { | 47 | { |
48 | struct list_head *p; | ||
49 | struct snd_pcm *pcm; | 48 | struct snd_pcm *pcm; |
50 | 49 | ||
51 | list_for_each(p, &snd_pcm_devices) { | 50 | list_for_each_entry(pcm, &snd_pcm_devices, list) { |
52 | pcm = list_entry(p, struct snd_pcm, list); | ||
53 | if (pcm->card == card && pcm->device == device) | 51 | if (pcm->card == card && pcm->device == device) |
54 | return pcm; | 52 | return pcm; |
55 | } | 53 | } |
@@ -782,7 +780,6 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, | |||
782 | struct snd_pcm_runtime *runtime; | 780 | struct snd_pcm_runtime *runtime; |
783 | struct snd_ctl_file *kctl; | 781 | struct snd_ctl_file *kctl; |
784 | struct snd_card *card; | 782 | struct snd_card *card; |
785 | struct list_head *list; | ||
786 | int prefer_subdevice = -1; | 783 | int prefer_subdevice = -1; |
787 | size_t size; | 784 | size_t size; |
788 | 785 | ||
@@ -795,8 +792,7 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, | |||
795 | 792 | ||
796 | card = pcm->card; | 793 | card = pcm->card; |
797 | down_read(&card->controls_rwsem); | 794 | down_read(&card->controls_rwsem); |
798 | list_for_each(list, &card->ctl_files) { | 795 | list_for_each_entry(kctl, &card->ctl_files, list) { |
799 | kctl = snd_ctl_file(list); | ||
800 | if (kctl->pid == current->pid) { | 796 | if (kctl->pid == current->pid) { |
801 | prefer_subdevice = kctl->prefer_pcm_subdevice; | 797 | prefer_subdevice = kctl->prefer_pcm_subdevice; |
802 | if (prefer_subdevice != -1) | 798 | if (prefer_subdevice != -1) |
@@ -941,9 +937,10 @@ static int snd_pcm_dev_register(struct snd_device *device) | |||
941 | { | 937 | { |
942 | int cidx, err; | 938 | int cidx, err; |
943 | struct snd_pcm_substream *substream; | 939 | struct snd_pcm_substream *substream; |
944 | struct list_head *list; | 940 | struct snd_pcm_notify *notify; |
945 | char str[16]; | 941 | char str[16]; |
946 | struct snd_pcm *pcm = device->device_data; | 942 | struct snd_pcm *pcm = device->device_data; |
943 | struct device *dev; | ||
947 | 944 | ||
948 | snd_assert(pcm != NULL && device != NULL, return -ENXIO); | 945 | snd_assert(pcm != NULL && device != NULL, return -ENXIO); |
949 | mutex_lock(®ister_mutex); | 946 | mutex_lock(®ister_mutex); |
@@ -966,11 +963,18 @@ static int snd_pcm_dev_register(struct snd_device *device) | |||
966 | devtype = SNDRV_DEVICE_TYPE_PCM_CAPTURE; | 963 | devtype = SNDRV_DEVICE_TYPE_PCM_CAPTURE; |
967 | break; | 964 | break; |
968 | } | 965 | } |
969 | if ((err = snd_register_device(devtype, pcm->card, | 966 | /* device pointer to use, pcm->dev takes precedence if |
970 | pcm->device, | 967 | * it is assigned, otherwise fall back to card's device |
971 | &snd_pcm_f_ops[cidx], | 968 | * if possible */ |
972 | pcm, str)) < 0) | 969 | dev = pcm->dev; |
973 | { | 970 | if (!dev) |
971 | dev = snd_card_get_device_link(pcm->card); | ||
972 | /* register pcm */ | ||
973 | err = snd_register_device_for_dev(devtype, pcm->card, | ||
974 | pcm->device, | ||
975 | &snd_pcm_f_ops[cidx], | ||
976 | pcm, str, dev); | ||
977 | if (err < 0) { | ||
974 | list_del(&pcm->list); | 978 | list_del(&pcm->list); |
975 | mutex_unlock(®ister_mutex); | 979 | mutex_unlock(®ister_mutex); |
976 | return err; | 980 | return err; |
@@ -980,11 +984,10 @@ static int snd_pcm_dev_register(struct snd_device *device) | |||
980 | for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) | 984 | for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) |
981 | snd_pcm_timer_init(substream); | 985 | snd_pcm_timer_init(substream); |
982 | } | 986 | } |
983 | list_for_each(list, &snd_pcm_notify_list) { | 987 | |
984 | struct snd_pcm_notify *notify; | 988 | list_for_each_entry(notify, &snd_pcm_notify_list, list) |
985 | notify = list_entry(list, struct snd_pcm_notify, list); | ||
986 | notify->n_register(pcm); | 989 | notify->n_register(pcm); |
987 | } | 990 | |
988 | mutex_unlock(®ister_mutex); | 991 | mutex_unlock(®ister_mutex); |
989 | return 0; | 992 | return 0; |
990 | } | 993 | } |
@@ -1027,7 +1030,7 @@ static int snd_pcm_dev_disconnect(struct snd_device *device) | |||
1027 | 1030 | ||
1028 | int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree) | 1031 | int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree) |
1029 | { | 1032 | { |
1030 | struct list_head *p; | 1033 | struct snd_pcm *pcm; |
1031 | 1034 | ||
1032 | snd_assert(notify != NULL && | 1035 | snd_assert(notify != NULL && |
1033 | notify->n_register != NULL && | 1036 | notify->n_register != NULL && |
@@ -1036,13 +1039,12 @@ int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree) | |||
1036 | mutex_lock(®ister_mutex); | 1039 | mutex_lock(®ister_mutex); |
1037 | if (nfree) { | 1040 | if (nfree) { |
1038 | list_del(¬ify->list); | 1041 | list_del(¬ify->list); |
1039 | list_for_each(p, &snd_pcm_devices) | 1042 | list_for_each_entry(pcm, &snd_pcm_devices, list) |
1040 | notify->n_unregister(list_entry(p, | 1043 | notify->n_unregister(pcm); |
1041 | struct snd_pcm, list)); | ||
1042 | } else { | 1044 | } else { |
1043 | list_add_tail(¬ify->list, &snd_pcm_notify_list); | 1045 | list_add_tail(¬ify->list, &snd_pcm_notify_list); |
1044 | list_for_each(p, &snd_pcm_devices) | 1046 | list_for_each_entry(pcm, &snd_pcm_devices, list) |
1045 | notify->n_register(list_entry(p, struct snd_pcm, list)); | 1047 | notify->n_register(pcm); |
1046 | } | 1048 | } |
1047 | mutex_unlock(®ister_mutex); | 1049 | mutex_unlock(®ister_mutex); |
1048 | return 0; | 1050 | return 0; |
@@ -1058,12 +1060,10 @@ EXPORT_SYMBOL(snd_pcm_notify); | |||
1058 | static void snd_pcm_proc_read(struct snd_info_entry *entry, | 1060 | static void snd_pcm_proc_read(struct snd_info_entry *entry, |
1059 | struct snd_info_buffer *buffer) | 1061 | struct snd_info_buffer *buffer) |
1060 | { | 1062 | { |
1061 | struct list_head *p; | ||
1062 | struct snd_pcm *pcm; | 1063 | struct snd_pcm *pcm; |
1063 | 1064 | ||
1064 | mutex_lock(®ister_mutex); | 1065 | mutex_lock(®ister_mutex); |
1065 | list_for_each(p, &snd_pcm_devices) { | 1066 | list_for_each_entry(pcm, &snd_pcm_devices, list) { |
1066 | pcm = list_entry(p, struct snd_pcm, list); | ||
1067 | snd_iprintf(buffer, "%02i-%02i: %s : %s", | 1067 | snd_iprintf(buffer, "%02i-%02i: %s : %s", |
1068 | pcm->card->number, pcm->device, pcm->id, pcm->name); | 1068 | pcm->card->number, pcm->device, pcm->id, pcm->name); |
1069 | if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) | 1069 | if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) |
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index b336797be4fc..9fefcaa2c324 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c | |||
@@ -781,6 +781,11 @@ int snd_interval_list(struct snd_interval *i, unsigned int count, unsigned int * | |||
781 | { | 781 | { |
782 | unsigned int k; | 782 | unsigned int k; |
783 | int changed = 0; | 783 | int changed = 0; |
784 | |||
785 | if (!count) { | ||
786 | i->empty = 1; | ||
787 | return -EINVAL; | ||
788 | } | ||
784 | for (k = 0; k < count; k++) { | 789 | for (k = 0; k < count; k++) { |
785 | if (mask && !(mask & (1 << k))) | 790 | if (mask && !(mask & (1 << k))) |
786 | continue; | 791 | continue; |
diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c index be030cb4d373..95b1b2f0b1e2 100644 --- a/sound/core/pcm_memory.c +++ b/sound/core/pcm_memory.c | |||
@@ -101,6 +101,8 @@ int snd_pcm_lib_preallocate_free(struct snd_pcm_substream *substream) | |||
101 | { | 101 | { |
102 | snd_pcm_lib_preallocate_dma_free(substream); | 102 | snd_pcm_lib_preallocate_dma_free(substream); |
103 | #ifdef CONFIG_SND_VERBOSE_PROCFS | 103 | #ifdef CONFIG_SND_VERBOSE_PROCFS |
104 | snd_info_free_entry(substream->proc_prealloc_max_entry); | ||
105 | substream->proc_prealloc_max_entry = NULL; | ||
104 | snd_info_free_entry(substream->proc_prealloc_entry); | 106 | snd_info_free_entry(substream->proc_prealloc_entry); |
105 | substream->proc_prealloc_entry = NULL; | 107 | substream->proc_prealloc_entry = NULL; |
106 | #endif | 108 | #endif |
@@ -142,6 +144,18 @@ static void snd_pcm_lib_preallocate_proc_read(struct snd_info_entry *entry, | |||
142 | } | 144 | } |
143 | 145 | ||
144 | /* | 146 | /* |
147 | * read callback for prealloc_max proc file | ||
148 | * | ||
149 | * prints the maximum allowed size in kB. | ||
150 | */ | ||
151 | static void snd_pcm_lib_preallocate_max_proc_read(struct snd_info_entry *entry, | ||
152 | struct snd_info_buffer *buffer) | ||
153 | { | ||
154 | struct snd_pcm_substream *substream = entry->private_data; | ||
155 | snd_iprintf(buffer, "%lu\n", (unsigned long) substream->dma_max / 1024); | ||
156 | } | ||
157 | |||
158 | /* | ||
145 | * write callback for prealloc proc file | 159 | * write callback for prealloc proc file |
146 | * | 160 | * |
147 | * accepts the preallocation size in kB. | 161 | * accepts the preallocation size in kB. |
@@ -203,6 +217,15 @@ static inline void preallocate_info_init(struct snd_pcm_substream *substream) | |||
203 | } | 217 | } |
204 | } | 218 | } |
205 | substream->proc_prealloc_entry = entry; | 219 | substream->proc_prealloc_entry = entry; |
220 | if ((entry = snd_info_create_card_entry(substream->pcm->card, "prealloc_max", substream->proc_root)) != NULL) { | ||
221 | entry->c.text.read = snd_pcm_lib_preallocate_max_proc_read; | ||
222 | entry->private_data = substream; | ||
223 | if (snd_info_register(entry) < 0) { | ||
224 | snd_info_free_entry(entry); | ||
225 | entry = NULL; | ||
226 | } | ||
227 | } | ||
228 | substream->proc_prealloc_max_entry = entry; | ||
206 | } | 229 | } |
207 | 230 | ||
208 | #else /* !CONFIG_SND_VERBOSE_PROCFS */ | 231 | #else /* !CONFIG_SND_VERBOSE_PROCFS */ |
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 0f055bfcbdac..7e6ceec738d5 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c | |||
@@ -61,14 +61,11 @@ static DEFINE_MUTEX(register_mutex); | |||
61 | 61 | ||
62 | static struct snd_rawmidi *snd_rawmidi_search(struct snd_card *card, int device) | 62 | static struct snd_rawmidi *snd_rawmidi_search(struct snd_card *card, int device) |
63 | { | 63 | { |
64 | struct list_head *p; | ||
65 | struct snd_rawmidi *rawmidi; | 64 | struct snd_rawmidi *rawmidi; |
66 | 65 | ||
67 | list_for_each(p, &snd_rawmidi_devices) { | 66 | list_for_each_entry(rawmidi, &snd_rawmidi_devices, list) |
68 | rawmidi = list_entry(p, struct snd_rawmidi, list); | ||
69 | if (rawmidi->card == card && rawmidi->device == device) | 67 | if (rawmidi->card == card && rawmidi->device == device) |
70 | return rawmidi; | 68 | return rawmidi; |
71 | } | ||
72 | return NULL; | 69 | return NULL; |
73 | } | 70 | } |
74 | 71 | ||
@@ -389,7 +386,6 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file) | |||
389 | struct snd_rawmidi *rmidi; | 386 | struct snd_rawmidi *rmidi; |
390 | struct snd_rawmidi_file *rawmidi_file; | 387 | struct snd_rawmidi_file *rawmidi_file; |
391 | wait_queue_t wait; | 388 | wait_queue_t wait; |
392 | struct list_head *list; | ||
393 | struct snd_ctl_file *kctl; | 389 | struct snd_ctl_file *kctl; |
394 | 390 | ||
395 | if (maj == snd_major) { | 391 | if (maj == snd_major) { |
@@ -426,8 +422,7 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file) | |||
426 | while (1) { | 422 | while (1) { |
427 | subdevice = -1; | 423 | subdevice = -1; |
428 | down_read(&card->controls_rwsem); | 424 | down_read(&card->controls_rwsem); |
429 | list_for_each(list, &card->ctl_files) { | 425 | list_for_each_entry(kctl, &card->ctl_files, list) { |
430 | kctl = snd_ctl_file(list); | ||
431 | if (kctl->pid == current->pid) { | 426 | if (kctl->pid == current->pid) { |
432 | subdevice = kctl->prefer_rawmidi_subdevice; | 427 | subdevice = kctl->prefer_rawmidi_subdevice; |
433 | if (subdevice != -1) | 428 | if (subdevice != -1) |
@@ -575,7 +570,6 @@ int snd_rawmidi_info_select(struct snd_card *card, struct snd_rawmidi_info *info | |||
575 | struct snd_rawmidi *rmidi; | 570 | struct snd_rawmidi *rmidi; |
576 | struct snd_rawmidi_str *pstr; | 571 | struct snd_rawmidi_str *pstr; |
577 | struct snd_rawmidi_substream *substream; | 572 | struct snd_rawmidi_substream *substream; |
578 | struct list_head *list; | ||
579 | 573 | ||
580 | mutex_lock(®ister_mutex); | 574 | mutex_lock(®ister_mutex); |
581 | rmidi = snd_rawmidi_search(card, info->device); | 575 | rmidi = snd_rawmidi_search(card, info->device); |
@@ -589,8 +583,7 @@ int snd_rawmidi_info_select(struct snd_card *card, struct snd_rawmidi_info *info | |||
589 | return -ENOENT; | 583 | return -ENOENT; |
590 | if (info->subdevice >= pstr->substream_count) | 584 | if (info->subdevice >= pstr->substream_count) |
591 | return -ENXIO; | 585 | return -ENXIO; |
592 | list_for_each(list, &pstr->substreams) { | 586 | list_for_each_entry(substream, &pstr->substreams, list) { |
593 | substream = list_entry(list, struct snd_rawmidi_substream, list); | ||
594 | if ((unsigned int)substream->number == info->subdevice) | 587 | if ((unsigned int)substream->number == info->subdevice) |
595 | return snd_rawmidi_info(substream, info); | 588 | return snd_rawmidi_info(substream, info); |
596 | } | 589 | } |
@@ -1313,14 +1306,14 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry, | |||
1313 | struct snd_rawmidi *rmidi; | 1306 | struct snd_rawmidi *rmidi; |
1314 | struct snd_rawmidi_substream *substream; | 1307 | struct snd_rawmidi_substream *substream; |
1315 | struct snd_rawmidi_runtime *runtime; | 1308 | struct snd_rawmidi_runtime *runtime; |
1316 | struct list_head *list; | ||
1317 | 1309 | ||
1318 | rmidi = entry->private_data; | 1310 | rmidi = entry->private_data; |
1319 | snd_iprintf(buffer, "%s\n\n", rmidi->name); | 1311 | snd_iprintf(buffer, "%s\n\n", rmidi->name); |
1320 | mutex_lock(&rmidi->open_mutex); | 1312 | mutex_lock(&rmidi->open_mutex); |
1321 | if (rmidi->info_flags & SNDRV_RAWMIDI_INFO_OUTPUT) { | 1313 | if (rmidi->info_flags & SNDRV_RAWMIDI_INFO_OUTPUT) { |
1322 | list_for_each(list, &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams) { | 1314 | list_for_each_entry(substream, |
1323 | substream = list_entry(list, struct snd_rawmidi_substream, list); | 1315 | &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams, |
1316 | list) { | ||
1324 | snd_iprintf(buffer, | 1317 | snd_iprintf(buffer, |
1325 | "Output %d\n" | 1318 | "Output %d\n" |
1326 | " Tx bytes : %lu\n", | 1319 | " Tx bytes : %lu\n", |
@@ -1339,8 +1332,9 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry, | |||
1339 | } | 1332 | } |
1340 | } | 1333 | } |
1341 | if (rmidi->info_flags & SNDRV_RAWMIDI_INFO_INPUT) { | 1334 | if (rmidi->info_flags & SNDRV_RAWMIDI_INFO_INPUT) { |
1342 | list_for_each(list, &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams) { | 1335 | list_for_each_entry(substream, |
1343 | substream = list_entry(list, struct snd_rawmidi_substream, list); | 1336 | &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams, |
1337 | list) { | ||
1344 | snd_iprintf(buffer, | 1338 | snd_iprintf(buffer, |
1345 | "Input %d\n" | 1339 | "Input %d\n" |
1346 | " Rx bytes : %lu\n", | 1340 | " Rx bytes : %lu\n", |
@@ -1625,13 +1619,10 @@ static int snd_rawmidi_dev_disconnect(struct snd_device *device) | |||
1625 | void snd_rawmidi_set_ops(struct snd_rawmidi *rmidi, int stream, | 1619 | void snd_rawmidi_set_ops(struct snd_rawmidi *rmidi, int stream, |
1626 | struct snd_rawmidi_ops *ops) | 1620 | struct snd_rawmidi_ops *ops) |
1627 | { | 1621 | { |
1628 | struct list_head *list; | ||
1629 | struct snd_rawmidi_substream *substream; | 1622 | struct snd_rawmidi_substream *substream; |
1630 | 1623 | ||
1631 | list_for_each(list, &rmidi->streams[stream].substreams) { | 1624 | list_for_each_entry(substream, &rmidi->streams[stream].substreams, list) |
1632 | substream = list_entry(list, struct snd_rawmidi_substream, list); | ||
1633 | substream->ops = ops; | 1625 | substream->ops = ops; |
1634 | } | ||
1635 | } | 1626 | } |
1636 | 1627 | ||
1637 | /* | 1628 | /* |
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index 532a660df51d..bb9dd9fa8e51 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c | |||
@@ -659,7 +659,6 @@ static int deliver_to_subscribers(struct snd_seq_client *client, | |||
659 | int err = 0, num_ev = 0; | 659 | int err = 0, num_ev = 0; |
660 | struct snd_seq_event event_saved; | 660 | struct snd_seq_event event_saved; |
661 | struct snd_seq_client_port *src_port; | 661 | struct snd_seq_client_port *src_port; |
662 | struct list_head *p; | ||
663 | struct snd_seq_port_subs_info *grp; | 662 | struct snd_seq_port_subs_info *grp; |
664 | 663 | ||
665 | src_port = snd_seq_port_use_ptr(client, event->source.port); | 664 | src_port = snd_seq_port_use_ptr(client, event->source.port); |
@@ -674,8 +673,7 @@ static int deliver_to_subscribers(struct snd_seq_client *client, | |||
674 | read_lock(&grp->list_lock); | 673 | read_lock(&grp->list_lock); |
675 | else | 674 | else |
676 | down_read(&grp->list_mutex); | 675 | down_read(&grp->list_mutex); |
677 | list_for_each(p, &grp->list_head) { | 676 | list_for_each_entry(subs, &grp->list_head, src_list) { |
678 | subs = list_entry(p, struct snd_seq_subscribers, src_list); | ||
679 | event->dest = subs->info.dest; | 677 | event->dest = subs->info.dest; |
680 | if (subs->info.flags & SNDRV_SEQ_PORT_SUBS_TIMESTAMP) | 678 | if (subs->info.flags & SNDRV_SEQ_PORT_SUBS_TIMESTAMP) |
681 | /* convert time according to flag with subscription */ | 679 | /* convert time according to flag with subscription */ |
@@ -709,15 +707,14 @@ static int port_broadcast_event(struct snd_seq_client *client, | |||
709 | { | 707 | { |
710 | int num_ev = 0, err = 0; | 708 | int num_ev = 0, err = 0; |
711 | struct snd_seq_client *dest_client; | 709 | struct snd_seq_client *dest_client; |
712 | struct list_head *p; | 710 | struct snd_seq_client_port *port; |
713 | 711 | ||
714 | dest_client = get_event_dest_client(event, SNDRV_SEQ_FILTER_BROADCAST); | 712 | dest_client = get_event_dest_client(event, SNDRV_SEQ_FILTER_BROADCAST); |
715 | if (dest_client == NULL) | 713 | if (dest_client == NULL) |
716 | return 0; /* no matching destination */ | 714 | return 0; /* no matching destination */ |
717 | 715 | ||
718 | read_lock(&dest_client->ports_lock); | 716 | read_lock(&dest_client->ports_lock); |
719 | list_for_each(p, &dest_client->ports_list_head) { | 717 | list_for_each_entry(port, &dest_client->ports_list_head, list) { |
720 | struct snd_seq_client_port *port = list_entry(p, struct snd_seq_client_port, list); | ||
721 | event->dest.port = port->addr.port; | 718 | event->dest.port = port->addr.port; |
722 | /* pass NULL as source client to avoid error bounce */ | 719 | /* pass NULL as source client to avoid error bounce */ |
723 | err = snd_seq_deliver_single_event(NULL, event, | 720 | err = snd_seq_deliver_single_event(NULL, event, |
@@ -2473,11 +2470,10 @@ static void snd_seq_info_dump_subscribers(struct snd_info_buffer *buffer, | |||
2473 | static void snd_seq_info_dump_ports(struct snd_info_buffer *buffer, | 2470 | static void snd_seq_info_dump_ports(struct snd_info_buffer *buffer, |
2474 | struct snd_seq_client *client) | 2471 | struct snd_seq_client *client) |
2475 | { | 2472 | { |
2476 | struct list_head *l; | 2473 | struct snd_seq_client_port *p; |
2477 | 2474 | ||
2478 | mutex_lock(&client->ports_mutex); | 2475 | mutex_lock(&client->ports_mutex); |
2479 | list_for_each(l, &client->ports_list_head) { | 2476 | list_for_each_entry(p, &client->ports_list_head, list) { |
2480 | struct snd_seq_client_port *p = list_entry(l, struct snd_seq_client_port, list); | ||
2481 | snd_iprintf(buffer, " Port %3d : \"%s\" (%c%c%c%c)\n", | 2477 | snd_iprintf(buffer, " Port %3d : \"%s\" (%c%c%c%c)\n", |
2482 | p->addr.port, p->name, | 2478 | p->addr.port, p->name, |
2483 | FLAG_PERM_RD(p->capability), | 2479 | FLAG_PERM_RD(p->capability), |
diff --git a/sound/core/seq/seq_device.c b/sound/core/seq/seq_device.c index b79d011813c0..37852cdace76 100644 --- a/sound/core/seq/seq_device.c +++ b/sound/core/seq/seq_device.c | |||
@@ -106,11 +106,10 @@ static void remove_drivers(void); | |||
106 | static void snd_seq_device_info(struct snd_info_entry *entry, | 106 | static void snd_seq_device_info(struct snd_info_entry *entry, |
107 | struct snd_info_buffer *buffer) | 107 | struct snd_info_buffer *buffer) |
108 | { | 108 | { |
109 | struct list_head *head; | 109 | struct ops_list *ops; |
110 | 110 | ||
111 | mutex_lock(&ops_mutex); | 111 | mutex_lock(&ops_mutex); |
112 | list_for_each(head, &opslist) { | 112 | list_for_each_entry(ops, &opslist, list) { |
113 | struct ops_list *ops = list_entry(head, struct ops_list, list); | ||
114 | snd_iprintf(buffer, "snd-%s%s%s%s,%d\n", | 113 | snd_iprintf(buffer, "snd-%s%s%s%s,%d\n", |
115 | ops->id, | 114 | ops->id, |
116 | ops->driver & DRIVER_LOADED ? ",loaded" : (ops->driver == DRIVER_EMPTY ? ",empty" : ""), | 115 | ops->driver & DRIVER_LOADED ? ",loaded" : (ops->driver == DRIVER_EMPTY ? ",empty" : ""), |
@@ -143,7 +142,7 @@ void snd_seq_autoload_unlock(void) | |||
143 | void snd_seq_device_load_drivers(void) | 142 | void snd_seq_device_load_drivers(void) |
144 | { | 143 | { |
145 | #ifdef CONFIG_KMOD | 144 | #ifdef CONFIG_KMOD |
146 | struct list_head *head; | 145 | struct ops_list *ops; |
147 | 146 | ||
148 | /* Calling request_module during module_init() | 147 | /* Calling request_module during module_init() |
149 | * may cause blocking. | 148 | * may cause blocking. |
@@ -155,8 +154,7 @@ void snd_seq_device_load_drivers(void) | |||
155 | return; | 154 | return; |
156 | 155 | ||
157 | mutex_lock(&ops_mutex); | 156 | mutex_lock(&ops_mutex); |
158 | list_for_each(head, &opslist) { | 157 | list_for_each_entry(ops, &opslist, list) { |
159 | struct ops_list *ops = list_entry(head, struct ops_list, list); | ||
160 | if (! (ops->driver & DRIVER_LOADED) && | 158 | if (! (ops->driver & DRIVER_LOADED) && |
161 | ! (ops->driver & DRIVER_REQUESTED)) { | 159 | ! (ops->driver & DRIVER_REQUESTED)) { |
162 | ops->used++; | 160 | ops->used++; |
@@ -314,8 +312,8 @@ static int snd_seq_device_dev_disconnect(struct snd_device *device) | |||
314 | int snd_seq_device_register_driver(char *id, struct snd_seq_dev_ops *entry, | 312 | int snd_seq_device_register_driver(char *id, struct snd_seq_dev_ops *entry, |
315 | int argsize) | 313 | int argsize) |
316 | { | 314 | { |
317 | struct list_head *head; | ||
318 | struct ops_list *ops; | 315 | struct ops_list *ops; |
316 | struct snd_seq_device *dev; | ||
319 | 317 | ||
320 | if (id == NULL || entry == NULL || | 318 | if (id == NULL || entry == NULL || |
321 | entry->init_device == NULL || entry->free_device == NULL) | 319 | entry->init_device == NULL || entry->free_device == NULL) |
@@ -341,8 +339,7 @@ int snd_seq_device_register_driver(char *id, struct snd_seq_dev_ops *entry, | |||
341 | ops->argsize = argsize; | 339 | ops->argsize = argsize; |
342 | 340 | ||
343 | /* initialize existing devices if necessary */ | 341 | /* initialize existing devices if necessary */ |
344 | list_for_each(head, &ops->dev_list) { | 342 | list_for_each_entry(dev, &ops->dev_list, list) { |
345 | struct snd_seq_device *dev = list_entry(head, struct snd_seq_device, list); | ||
346 | init_device(dev, ops); | 343 | init_device(dev, ops); |
347 | } | 344 | } |
348 | mutex_unlock(&ops->reg_mutex); | 345 | mutex_unlock(&ops->reg_mutex); |
@@ -394,8 +391,8 @@ static struct ops_list * create_driver(char *id) | |||
394 | */ | 391 | */ |
395 | int snd_seq_device_unregister_driver(char *id) | 392 | int snd_seq_device_unregister_driver(char *id) |
396 | { | 393 | { |
397 | struct list_head *head; | ||
398 | struct ops_list *ops; | 394 | struct ops_list *ops; |
395 | struct snd_seq_device *dev; | ||
399 | 396 | ||
400 | ops = find_driver(id, 0); | 397 | ops = find_driver(id, 0); |
401 | if (ops == NULL) | 398 | if (ops == NULL) |
@@ -411,8 +408,7 @@ int snd_seq_device_unregister_driver(char *id) | |||
411 | /* close and release all devices associated with this driver */ | 408 | /* close and release all devices associated with this driver */ |
412 | mutex_lock(&ops->reg_mutex); | 409 | mutex_lock(&ops->reg_mutex); |
413 | ops->driver |= DRIVER_LOCKED; /* do not remove this driver recursively */ | 410 | ops->driver |= DRIVER_LOCKED; /* do not remove this driver recursively */ |
414 | list_for_each(head, &ops->dev_list) { | 411 | list_for_each_entry(dev, &ops->dev_list, list) { |
415 | struct snd_seq_device *dev = list_entry(head, struct snd_seq_device, list); | ||
416 | free_device(dev, ops); | 412 | free_device(dev, ops); |
417 | } | 413 | } |
418 | 414 | ||
@@ -512,11 +508,10 @@ static int free_device(struct snd_seq_device *dev, struct ops_list *ops) | |||
512 | */ | 508 | */ |
513 | static struct ops_list * find_driver(char *id, int create_if_empty) | 509 | static struct ops_list * find_driver(char *id, int create_if_empty) |
514 | { | 510 | { |
515 | struct list_head *head; | 511 | struct ops_list *ops; |
516 | 512 | ||
517 | mutex_lock(&ops_mutex); | 513 | mutex_lock(&ops_mutex); |
518 | list_for_each(head, &opslist) { | 514 | list_for_each_entry(ops, &opslist, list) { |
519 | struct ops_list *ops = list_entry(head, struct ops_list, list); | ||
520 | if (strcmp(ops->id, id) == 0) { | 515 | if (strcmp(ops->id, id) == 0) { |
521 | ops->used++; | 516 | ops->used++; |
522 | mutex_unlock(&ops_mutex); | 517 | mutex_unlock(&ops_mutex); |
diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c index 8c64b58ff77b..eefd1cf872b4 100644 --- a/sound/core/seq/seq_ports.c +++ b/sound/core/seq/seq_ports.c | |||
@@ -59,14 +59,12 @@ much elements are in array. | |||
59 | struct snd_seq_client_port *snd_seq_port_use_ptr(struct snd_seq_client *client, | 59 | struct snd_seq_client_port *snd_seq_port_use_ptr(struct snd_seq_client *client, |
60 | int num) | 60 | int num) |
61 | { | 61 | { |
62 | struct list_head *p; | ||
63 | struct snd_seq_client_port *port; | 62 | struct snd_seq_client_port *port; |
64 | 63 | ||
65 | if (client == NULL) | 64 | if (client == NULL) |
66 | return NULL; | 65 | return NULL; |
67 | read_lock(&client->ports_lock); | 66 | read_lock(&client->ports_lock); |
68 | list_for_each(p, &client->ports_list_head) { | 67 | list_for_each_entry(port, &client->ports_list_head, list) { |
69 | port = list_entry(p, struct snd_seq_client_port, list); | ||
70 | if (port->addr.port == num) { | 68 | if (port->addr.port == num) { |
71 | if (port->closing) | 69 | if (port->closing) |
72 | break; /* deleting now */ | 70 | break; /* deleting now */ |
@@ -85,14 +83,12 @@ struct snd_seq_client_port *snd_seq_port_query_nearest(struct snd_seq_client *cl | |||
85 | struct snd_seq_port_info *pinfo) | 83 | struct snd_seq_port_info *pinfo) |
86 | { | 84 | { |
87 | int num; | 85 | int num; |
88 | struct list_head *p; | ||
89 | struct snd_seq_client_port *port, *found; | 86 | struct snd_seq_client_port *port, *found; |
90 | 87 | ||
91 | num = pinfo->addr.port; | 88 | num = pinfo->addr.port; |
92 | found = NULL; | 89 | found = NULL; |
93 | read_lock(&client->ports_lock); | 90 | read_lock(&client->ports_lock); |
94 | list_for_each(p, &client->ports_list_head) { | 91 | list_for_each_entry(port, &client->ports_list_head, list) { |
95 | port = list_entry(p, struct snd_seq_client_port, list); | ||
96 | if (port->addr.port < num) | 92 | if (port->addr.port < num) |
97 | continue; | 93 | continue; |
98 | if (port->addr.port == num) { | 94 | if (port->addr.port == num) { |
@@ -131,8 +127,7 @@ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client, | |||
131 | int port) | 127 | int port) |
132 | { | 128 | { |
133 | unsigned long flags; | 129 | unsigned long flags; |
134 | struct snd_seq_client_port *new_port; | 130 | struct snd_seq_client_port *new_port, *p; |
135 | struct list_head *l; | ||
136 | int num = -1; | 131 | int num = -1; |
137 | 132 | ||
138 | /* sanity check */ | 133 | /* sanity check */ |
@@ -161,15 +156,14 @@ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client, | |||
161 | num = port >= 0 ? port : 0; | 156 | num = port >= 0 ? port : 0; |
162 | mutex_lock(&client->ports_mutex); | 157 | mutex_lock(&client->ports_mutex); |
163 | write_lock_irqsave(&client->ports_lock, flags); | 158 | write_lock_irqsave(&client->ports_lock, flags); |
164 | list_for_each(l, &client->ports_list_head) { | 159 | list_for_each_entry(p, &client->ports_list_head, list) { |
165 | struct snd_seq_client_port *p = list_entry(l, struct snd_seq_client_port, list); | ||
166 | if (p->addr.port > num) | 160 | if (p->addr.port > num) |
167 | break; | 161 | break; |
168 | if (port < 0) /* auto-probe mode */ | 162 | if (port < 0) /* auto-probe mode */ |
169 | num = p->addr.port + 1; | 163 | num = p->addr.port + 1; |
170 | } | 164 | } |
171 | /* insert the new port */ | 165 | /* insert the new port */ |
172 | list_add_tail(&new_port->list, l); | 166 | list_add_tail(&new_port->list, &p->list); |
173 | client->num_ports++; | 167 | client->num_ports++; |
174 | new_port->addr.port = num; /* store the port number in the port */ | 168 | new_port->addr.port = num; /* store the port number in the port */ |
175 | write_unlock_irqrestore(&client->ports_lock, flags); | 169 | write_unlock_irqrestore(&client->ports_lock, flags); |
@@ -251,9 +245,9 @@ static void clear_subscriber_list(struct snd_seq_client *client, | |||
251 | list_del(&subs->dest_list); | 245 | list_del(&subs->dest_list); |
252 | else | 246 | else |
253 | list_del(&subs->src_list); | 247 | list_del(&subs->src_list); |
248 | up_write(&agrp->list_mutex); | ||
254 | unsubscribe_port(c, aport, agrp, &subs->info, 1); | 249 | unsubscribe_port(c, aport, agrp, &subs->info, 1); |
255 | kfree(subs); | 250 | kfree(subs); |
256 | up_write(&agrp->list_mutex); | ||
257 | snd_seq_port_unlock(aport); | 251 | snd_seq_port_unlock(aport); |
258 | snd_seq_client_unlock(c); | 252 | snd_seq_client_unlock(c); |
259 | } | 253 | } |
@@ -287,16 +281,14 @@ static int port_delete(struct snd_seq_client *client, | |||
287 | int snd_seq_delete_port(struct snd_seq_client *client, int port) | 281 | int snd_seq_delete_port(struct snd_seq_client *client, int port) |
288 | { | 282 | { |
289 | unsigned long flags; | 283 | unsigned long flags; |
290 | struct list_head *l; | 284 | struct snd_seq_client_port *found = NULL, *p; |
291 | struct snd_seq_client_port *found = NULL; | ||
292 | 285 | ||
293 | mutex_lock(&client->ports_mutex); | 286 | mutex_lock(&client->ports_mutex); |
294 | write_lock_irqsave(&client->ports_lock, flags); | 287 | write_lock_irqsave(&client->ports_lock, flags); |
295 | list_for_each(l, &client->ports_list_head) { | 288 | list_for_each_entry(p, &client->ports_list_head, list) { |
296 | struct snd_seq_client_port *p = list_entry(l, struct snd_seq_client_port, list); | ||
297 | if (p->addr.port == port) { | 289 | if (p->addr.port == port) { |
298 | /* ok found. delete from the list at first */ | 290 | /* ok found. delete from the list at first */ |
299 | list_del(l); | 291 | list_del(&p->list); |
300 | client->num_ports--; | 292 | client->num_ports--; |
301 | found = p; | 293 | found = p; |
302 | break; | 294 | break; |
@@ -314,7 +306,8 @@ int snd_seq_delete_port(struct snd_seq_client *client, int port) | |||
314 | int snd_seq_delete_all_ports(struct snd_seq_client *client) | 306 | int snd_seq_delete_all_ports(struct snd_seq_client *client) |
315 | { | 307 | { |
316 | unsigned long flags; | 308 | unsigned long flags; |
317 | struct list_head deleted_list, *p, *n; | 309 | struct list_head deleted_list; |
310 | struct snd_seq_client_port *port, *tmp; | ||
318 | 311 | ||
319 | /* move the port list to deleted_list, and | 312 | /* move the port list to deleted_list, and |
320 | * clear the port list in the client data. | 313 | * clear the port list in the client data. |
@@ -331,9 +324,8 @@ int snd_seq_delete_all_ports(struct snd_seq_client *client) | |||
331 | write_unlock_irqrestore(&client->ports_lock, flags); | 324 | write_unlock_irqrestore(&client->ports_lock, flags); |
332 | 325 | ||
333 | /* remove each port in deleted_list */ | 326 | /* remove each port in deleted_list */ |
334 | list_for_each_safe(p, n, &deleted_list) { | 327 | list_for_each_entry_safe(port, tmp, &deleted_list, list) { |
335 | struct snd_seq_client_port *port = list_entry(p, struct snd_seq_client_port, list); | 328 | list_del(&port->list); |
336 | list_del(p); | ||
337 | snd_seq_system_client_ev_port_exit(port->addr.client, port->addr.port); | 329 | snd_seq_system_client_ev_port_exit(port->addr.client, port->addr.port); |
338 | port_delete(client, port); | 330 | port_delete(client, port); |
339 | } | 331 | } |
@@ -500,8 +492,7 @@ int snd_seq_port_connect(struct snd_seq_client *connector, | |||
500 | { | 492 | { |
501 | struct snd_seq_port_subs_info *src = &src_port->c_src; | 493 | struct snd_seq_port_subs_info *src = &src_port->c_src; |
502 | struct snd_seq_port_subs_info *dest = &dest_port->c_dest; | 494 | struct snd_seq_port_subs_info *dest = &dest_port->c_dest; |
503 | struct snd_seq_subscribers *subs; | 495 | struct snd_seq_subscribers *subs, *s; |
504 | struct list_head *p; | ||
505 | int err, src_called = 0; | 496 | int err, src_called = 0; |
506 | unsigned long flags; | 497 | unsigned long flags; |
507 | int exclusive; | 498 | int exclusive; |
@@ -525,13 +516,11 @@ int snd_seq_port_connect(struct snd_seq_client *connector, | |||
525 | if (src->exclusive || dest->exclusive) | 516 | if (src->exclusive || dest->exclusive) |
526 | goto __error; | 517 | goto __error; |
527 | /* check whether already exists */ | 518 | /* check whether already exists */ |
528 | list_for_each(p, &src->list_head) { | 519 | list_for_each_entry(s, &src->list_head, src_list) { |
529 | struct snd_seq_subscribers *s = list_entry(p, struct snd_seq_subscribers, src_list); | ||
530 | if (match_subs_info(info, &s->info)) | 520 | if (match_subs_info(info, &s->info)) |
531 | goto __error; | 521 | goto __error; |
532 | } | 522 | } |
533 | list_for_each(p, &dest->list_head) { | 523 | list_for_each_entry(s, &dest->list_head, dest_list) { |
534 | struct snd_seq_subscribers *s = list_entry(p, struct snd_seq_subscribers, dest_list); | ||
535 | if (match_subs_info(info, &s->info)) | 524 | if (match_subs_info(info, &s->info)) |
536 | goto __error; | 525 | goto __error; |
537 | } | 526 | } |
@@ -582,7 +571,6 @@ int snd_seq_port_disconnect(struct snd_seq_client *connector, | |||
582 | struct snd_seq_port_subs_info *src = &src_port->c_src; | 571 | struct snd_seq_port_subs_info *src = &src_port->c_src; |
583 | struct snd_seq_port_subs_info *dest = &dest_port->c_dest; | 572 | struct snd_seq_port_subs_info *dest = &dest_port->c_dest; |
584 | struct snd_seq_subscribers *subs; | 573 | struct snd_seq_subscribers *subs; |
585 | struct list_head *p; | ||
586 | int err = -ENOENT; | 574 | int err = -ENOENT; |
587 | unsigned long flags; | 575 | unsigned long flags; |
588 | 576 | ||
@@ -590,8 +578,7 @@ int snd_seq_port_disconnect(struct snd_seq_client *connector, | |||
590 | down_write_nested(&dest->list_mutex, SINGLE_DEPTH_NESTING); | 578 | down_write_nested(&dest->list_mutex, SINGLE_DEPTH_NESTING); |
591 | 579 | ||
592 | /* look for the connection */ | 580 | /* look for the connection */ |
593 | list_for_each(p, &src->list_head) { | 581 | list_for_each_entry(subs, &src->list_head, src_list) { |
594 | subs = list_entry(p, struct snd_seq_subscribers, src_list); | ||
595 | if (match_subs_info(info, &subs->info)) { | 582 | if (match_subs_info(info, &subs->info)) { |
596 | write_lock_irqsave(&src->list_lock, flags); | 583 | write_lock_irqsave(&src->list_lock, flags); |
597 | // write_lock(&dest->list_lock); // no lock yet | 584 | // write_lock(&dest->list_lock); // no lock yet |
@@ -620,12 +607,10 @@ int snd_seq_port_disconnect(struct snd_seq_client *connector, | |||
620 | struct snd_seq_subscribers *snd_seq_port_get_subscription(struct snd_seq_port_subs_info *src_grp, | 607 | struct snd_seq_subscribers *snd_seq_port_get_subscription(struct snd_seq_port_subs_info *src_grp, |
621 | struct snd_seq_addr *dest_addr) | 608 | struct snd_seq_addr *dest_addr) |
622 | { | 609 | { |
623 | struct list_head *p; | ||
624 | struct snd_seq_subscribers *s, *found = NULL; | 610 | struct snd_seq_subscribers *s, *found = NULL; |
625 | 611 | ||
626 | down_read(&src_grp->list_mutex); | 612 | down_read(&src_grp->list_mutex); |
627 | list_for_each(p, &src_grp->list_head) { | 613 | list_for_each_entry(s, &src_grp->list_head, src_list) { |
628 | s = list_entry(p, struct snd_seq_subscribers, src_list); | ||
629 | if (addr_match(dest_addr, &s->info.dest)) { | 614 | if (addr_match(dest_addr, &s->info.dest)) { |
630 | found = s; | 615 | found = s; |
631 | break; | 616 | break; |
diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c index 0cfa06c6b81f..972f93405364 100644 --- a/sound/core/seq/seq_virmidi.c +++ b/sound/core/seq/seq_virmidi.c | |||
@@ -81,13 +81,11 @@ static int snd_virmidi_dev_receive_event(struct snd_virmidi_dev *rdev, | |||
81 | struct snd_seq_event *ev) | 81 | struct snd_seq_event *ev) |
82 | { | 82 | { |
83 | struct snd_virmidi *vmidi; | 83 | struct snd_virmidi *vmidi; |
84 | struct list_head *list; | ||
85 | unsigned char msg[4]; | 84 | unsigned char msg[4]; |
86 | int len; | 85 | int len; |
87 | 86 | ||
88 | read_lock(&rdev->filelist_lock); | 87 | read_lock(&rdev->filelist_lock); |
89 | list_for_each(list, &rdev->filelist) { | 88 | list_for_each_entry(vmidi, &rdev->filelist, list) { |
90 | vmidi = list_entry(list, struct snd_virmidi, list); | ||
91 | if (!vmidi->trigger) | 89 | if (!vmidi->trigger) |
92 | continue; | 90 | continue; |
93 | if (ev->type == SNDRV_SEQ_EVENT_SYSEX) { | 91 | if (ev->type == SNDRV_SEQ_EVENT_SYSEX) { |
diff --git a/sound/core/sound.c b/sound/core/sound.c index 82a61c67cf3a..4084de064127 100644 --- a/sound/core/sound.c +++ b/sound/core/sound.c | |||
@@ -219,26 +219,27 @@ static int snd_kernel_minor(int type, struct snd_card *card, int dev) | |||
219 | #endif | 219 | #endif |
220 | 220 | ||
221 | /** | 221 | /** |
222 | * snd_register_device - Register the ALSA device file for the card | 222 | * snd_register_device_for_dev - Register the ALSA device file for the card |
223 | * @type: the device type, SNDRV_DEVICE_TYPE_XXX | 223 | * @type: the device type, SNDRV_DEVICE_TYPE_XXX |
224 | * @card: the card instance | 224 | * @card: the card instance |
225 | * @dev: the device index | 225 | * @dev: the device index |
226 | * @f_ops: the file operations | 226 | * @f_ops: the file operations |
227 | * @private_data: user pointer for f_ops->open() | 227 | * @private_data: user pointer for f_ops->open() |
228 | * @name: the device file name | 228 | * @name: the device file name |
229 | * @device: the &struct device to link this new device to | ||
229 | * | 230 | * |
230 | * Registers an ALSA device file for the given card. | 231 | * Registers an ALSA device file for the given card. |
231 | * The operators have to be set in reg parameter. | 232 | * The operators have to be set in reg parameter. |
232 | * | 233 | * |
233 | * Retrurns zero if successful, or a negative error code on failure. | 234 | * Returns zero if successful, or a negative error code on failure. |
234 | */ | 235 | */ |
235 | int snd_register_device(int type, struct snd_card *card, int dev, | 236 | int snd_register_device_for_dev(int type, struct snd_card *card, int dev, |
236 | const struct file_operations *f_ops, void *private_data, | 237 | const struct file_operations *f_ops, |
237 | const char *name) | 238 | void *private_data, |
239 | const char *name, struct device *device) | ||
238 | { | 240 | { |
239 | int minor; | 241 | int minor; |
240 | struct snd_minor *preg; | 242 | struct snd_minor *preg; |
241 | struct device *device = snd_card_get_device_link(card); | ||
242 | 243 | ||
243 | snd_assert(name, return -EINVAL); | 244 | snd_assert(name, return -EINVAL); |
244 | preg = kmalloc(sizeof *preg, GFP_KERNEL); | 245 | preg = kmalloc(sizeof *preg, GFP_KERNEL); |
@@ -272,7 +273,7 @@ int snd_register_device(int type, struct snd_card *card, int dev, | |||
272 | return 0; | 273 | return 0; |
273 | } | 274 | } |
274 | 275 | ||
275 | EXPORT_SYMBOL(snd_register_device); | 276 | EXPORT_SYMBOL(snd_register_device_for_dev); |
276 | 277 | ||
277 | /* find the matching minor record | 278 | /* find the matching minor record |
278 | * return the index of snd_minor, or -1 if not found | 279 | * return the index of snd_minor, or -1 if not found |
diff --git a/sound/core/timer.c b/sound/core/timer.c index 10a79aed33f8..3e0638351069 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c | |||
@@ -35,9 +35,6 @@ | |||
35 | #include <sound/minors.h> | 35 | #include <sound/minors.h> |
36 | #include <sound/initval.h> | 36 | #include <sound/initval.h> |
37 | #include <linux/kmod.h> | 37 | #include <linux/kmod.h> |
38 | #ifdef CONFIG_KERNELD | ||
39 | #include <linux/kerneld.h> | ||
40 | #endif | ||
41 | 38 | ||
42 | #if defined(CONFIG_SND_HPET) || defined(CONFIG_SND_HPET_MODULE) | 39 | #if defined(CONFIG_SND_HPET) || defined(CONFIG_SND_HPET_MODULE) |
43 | #define DEFAULT_TIMER_LIMIT 3 | 40 | #define DEFAULT_TIMER_LIMIT 3 |
@@ -130,11 +127,8 @@ static struct snd_timer_instance *snd_timer_instance_new(char *owner, | |||
130 | static struct snd_timer *snd_timer_find(struct snd_timer_id *tid) | 127 | static struct snd_timer *snd_timer_find(struct snd_timer_id *tid) |
131 | { | 128 | { |
132 | struct snd_timer *timer = NULL; | 129 | struct snd_timer *timer = NULL; |
133 | struct list_head *p; | ||
134 | |||
135 | list_for_each(p, &snd_timer_list) { | ||
136 | timer = list_entry(p, struct snd_timer, device_list); | ||
137 | 130 | ||
131 | list_for_each_entry(timer, &snd_timer_list, device_list) { | ||
138 | if (timer->tmr_class != tid->dev_class) | 132 | if (timer->tmr_class != tid->dev_class) |
139 | continue; | 133 | continue; |
140 | if ((timer->tmr_class == SNDRV_TIMER_CLASS_CARD || | 134 | if ((timer->tmr_class == SNDRV_TIMER_CLASS_CARD || |
@@ -184,13 +178,10 @@ static void snd_timer_check_slave(struct snd_timer_instance *slave) | |||
184 | { | 178 | { |
185 | struct snd_timer *timer; | 179 | struct snd_timer *timer; |
186 | struct snd_timer_instance *master; | 180 | struct snd_timer_instance *master; |
187 | struct list_head *p, *q; | ||
188 | 181 | ||
189 | /* FIXME: it's really dumb to look up all entries.. */ | 182 | /* FIXME: it's really dumb to look up all entries.. */ |
190 | list_for_each(p, &snd_timer_list) { | 183 | list_for_each_entry(timer, &snd_timer_list, device_list) { |
191 | timer = list_entry(p, struct snd_timer, device_list); | 184 | list_for_each_entry(master, &timer->open_list_head, open_list) { |
192 | list_for_each(q, &timer->open_list_head) { | ||
193 | master = list_entry(q, struct snd_timer_instance, open_list); | ||
194 | if (slave->slave_class == master->slave_class && | 185 | if (slave->slave_class == master->slave_class && |
195 | slave->slave_id == master->slave_id) { | 186 | slave->slave_id == master->slave_id) { |
196 | list_del(&slave->open_list); | 187 | list_del(&slave->open_list); |
@@ -214,16 +205,13 @@ static void snd_timer_check_slave(struct snd_timer_instance *slave) | |||
214 | */ | 205 | */ |
215 | static void snd_timer_check_master(struct snd_timer_instance *master) | 206 | static void snd_timer_check_master(struct snd_timer_instance *master) |
216 | { | 207 | { |
217 | struct snd_timer_instance *slave; | 208 | struct snd_timer_instance *slave, *tmp; |
218 | struct list_head *p, *n; | ||
219 | 209 | ||
220 | /* check all pending slaves */ | 210 | /* check all pending slaves */ |
221 | list_for_each_safe(p, n, &snd_timer_slave_list) { | 211 | list_for_each_entry_safe(slave, tmp, &snd_timer_slave_list, open_list) { |
222 | slave = list_entry(p, struct snd_timer_instance, open_list); | ||
223 | if (slave->slave_class == master->slave_class && | 212 | if (slave->slave_class == master->slave_class && |
224 | slave->slave_id == master->slave_id) { | 213 | slave->slave_id == master->slave_id) { |
225 | list_del(p); | 214 | list_move_tail(&slave->open_list, &master->slave_list_head); |
226 | list_add_tail(p, &master->slave_list_head); | ||
227 | spin_lock_irq(&slave_active_lock); | 215 | spin_lock_irq(&slave_active_lock); |
228 | slave->master = master; | 216 | slave->master = master; |
229 | slave->timer = master->timer; | 217 | slave->timer = master->timer; |
@@ -317,8 +305,7 @@ static int _snd_timer_stop(struct snd_timer_instance *timeri, | |||
317 | int snd_timer_close(struct snd_timer_instance *timeri) | 305 | int snd_timer_close(struct snd_timer_instance *timeri) |
318 | { | 306 | { |
319 | struct snd_timer *timer = NULL; | 307 | struct snd_timer *timer = NULL; |
320 | struct list_head *p, *n; | 308 | struct snd_timer_instance *slave, *tmp; |
321 | struct snd_timer_instance *slave; | ||
322 | 309 | ||
323 | snd_assert(timeri != NULL, return -ENXIO); | 310 | snd_assert(timeri != NULL, return -ENXIO); |
324 | 311 | ||
@@ -353,12 +340,11 @@ int snd_timer_close(struct snd_timer_instance *timeri) | |||
353 | timer->hw.close) | 340 | timer->hw.close) |
354 | timer->hw.close(timer); | 341 | timer->hw.close(timer); |
355 | /* remove slave links */ | 342 | /* remove slave links */ |
356 | list_for_each_safe(p, n, &timeri->slave_list_head) { | 343 | list_for_each_entry_safe(slave, tmp, &timeri->slave_list_head, |
357 | slave = list_entry(p, struct snd_timer_instance, open_list); | 344 | open_list) { |
358 | spin_lock_irq(&slave_active_lock); | 345 | spin_lock_irq(&slave_active_lock); |
359 | _snd_timer_stop(slave, 1, SNDRV_TIMER_EVENT_RESOLUTION); | 346 | _snd_timer_stop(slave, 1, SNDRV_TIMER_EVENT_RESOLUTION); |
360 | list_del(p); | 347 | list_move_tail(&slave->open_list, &snd_timer_slave_list); |
361 | list_add_tail(p, &snd_timer_slave_list); | ||
362 | slave->master = NULL; | 348 | slave->master = NULL; |
363 | slave->timer = NULL; | 349 | slave->timer = NULL; |
364 | spin_unlock_irq(&slave_active_lock); | 350 | spin_unlock_irq(&slave_active_lock); |
@@ -394,7 +380,6 @@ static void snd_timer_notify1(struct snd_timer_instance *ti, int event) | |||
394 | unsigned long flags; | 380 | unsigned long flags; |
395 | unsigned long resolution = 0; | 381 | unsigned long resolution = 0; |
396 | struct snd_timer_instance *ts; | 382 | struct snd_timer_instance *ts; |
397 | struct list_head *n; | ||
398 | struct timespec tstamp; | 383 | struct timespec tstamp; |
399 | 384 | ||
400 | getnstimeofday(&tstamp); | 385 | getnstimeofday(&tstamp); |
@@ -413,11 +398,9 @@ static void snd_timer_notify1(struct snd_timer_instance *ti, int event) | |||
413 | if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE) | 398 | if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE) |
414 | return; | 399 | return; |
415 | spin_lock_irqsave(&timer->lock, flags); | 400 | spin_lock_irqsave(&timer->lock, flags); |
416 | list_for_each(n, &ti->slave_active_head) { | 401 | list_for_each_entry(ts, &ti->slave_active_head, active_list) |
417 | ts = list_entry(n, struct snd_timer_instance, active_list); | ||
418 | if (ts->ccallback) | 402 | if (ts->ccallback) |
419 | ts->ccallback(ti, event + 100, &tstamp, resolution); | 403 | ts->ccallback(ti, event + 100, &tstamp, resolution); |
420 | } | ||
421 | spin_unlock_irqrestore(&timer->lock, flags); | 404 | spin_unlock_irqrestore(&timer->lock, flags); |
422 | } | 405 | } |
423 | 406 | ||
@@ -593,10 +576,8 @@ static void snd_timer_reschedule(struct snd_timer * timer, unsigned long ticks_l | |||
593 | { | 576 | { |
594 | struct snd_timer_instance *ti; | 577 | struct snd_timer_instance *ti; |
595 | unsigned long ticks = ~0UL; | 578 | unsigned long ticks = ~0UL; |
596 | struct list_head *p; | ||
597 | 579 | ||
598 | list_for_each(p, &timer->active_list_head) { | 580 | list_for_each_entry(ti, &timer->active_list_head, active_list) { |
599 | ti = list_entry(p, struct snd_timer_instance, active_list); | ||
600 | if (ti->flags & SNDRV_TIMER_IFLG_START) { | 581 | if (ti->flags & SNDRV_TIMER_IFLG_START) { |
601 | ti->flags &= ~SNDRV_TIMER_IFLG_START; | 582 | ti->flags &= ~SNDRV_TIMER_IFLG_START; |
602 | ti->flags |= SNDRV_TIMER_IFLG_RUNNING; | 583 | ti->flags |= SNDRV_TIMER_IFLG_RUNNING; |
@@ -661,9 +642,9 @@ static void snd_timer_tasklet(unsigned long arg) | |||
661 | */ | 642 | */ |
662 | void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left) | 643 | void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left) |
663 | { | 644 | { |
664 | struct snd_timer_instance *ti, *ts; | 645 | struct snd_timer_instance *ti, *ts, *tmp; |
665 | unsigned long resolution, ticks; | 646 | unsigned long resolution, ticks; |
666 | struct list_head *p, *q, *n, *ack_list_head; | 647 | struct list_head *p, *ack_list_head; |
667 | unsigned long flags; | 648 | unsigned long flags; |
668 | int use_tasklet = 0; | 649 | int use_tasklet = 0; |
669 | 650 | ||
@@ -679,12 +660,12 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left) | |||
679 | resolution = timer->hw.resolution; | 660 | resolution = timer->hw.resolution; |
680 | 661 | ||
681 | /* loop for all active instances | 662 | /* loop for all active instances |
682 | * Here we cannot use list_for_each because the active_list of a | 663 | * Here we cannot use list_for_each_entry because the active_list of a |
683 | * processed instance is relinked to done_list_head before the callback | 664 | * processed instance is relinked to done_list_head before the callback |
684 | * is called. | 665 | * is called. |
685 | */ | 666 | */ |
686 | list_for_each_safe(p, n, &timer->active_list_head) { | 667 | list_for_each_entry_safe(ti, tmp, &timer->active_list_head, |
687 | ti = list_entry(p, struct snd_timer_instance, active_list); | 668 | active_list) { |
688 | if (!(ti->flags & SNDRV_TIMER_IFLG_RUNNING)) | 669 | if (!(ti->flags & SNDRV_TIMER_IFLG_RUNNING)) |
689 | continue; | 670 | continue; |
690 | ti->pticks += ticks_left; | 671 | ti->pticks += ticks_left; |
@@ -700,7 +681,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left) | |||
700 | } else { | 681 | } else { |
701 | ti->flags &= ~SNDRV_TIMER_IFLG_RUNNING; | 682 | ti->flags &= ~SNDRV_TIMER_IFLG_RUNNING; |
702 | if (--timer->running) | 683 | if (--timer->running) |
703 | list_del(p); | 684 | list_del(&ti->active_list); |
704 | } | 685 | } |
705 | if ((timer->hw.flags & SNDRV_TIMER_HW_TASKLET) || | 686 | if ((timer->hw.flags & SNDRV_TIMER_HW_TASKLET) || |
706 | (ti->flags & SNDRV_TIMER_IFLG_FAST)) | 687 | (ti->flags & SNDRV_TIMER_IFLG_FAST)) |
@@ -709,8 +690,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left) | |||
709 | ack_list_head = &timer->sack_list_head; | 690 | ack_list_head = &timer->sack_list_head; |
710 | if (list_empty(&ti->ack_list)) | 691 | if (list_empty(&ti->ack_list)) |
711 | list_add_tail(&ti->ack_list, ack_list_head); | 692 | list_add_tail(&ti->ack_list, ack_list_head); |
712 | list_for_each(q, &ti->slave_active_head) { | 693 | list_for_each_entry(ts, &ti->slave_active_head, active_list) { |
713 | ts = list_entry(q, struct snd_timer_instance, active_list); | ||
714 | ts->pticks = ti->pticks; | 694 | ts->pticks = ti->pticks; |
715 | ts->resolution = resolution; | 695 | ts->resolution = resolution; |
716 | if (list_empty(&ts->ack_list)) | 696 | if (list_empty(&ts->ack_list)) |
@@ -844,7 +824,6 @@ static int snd_timer_dev_register(struct snd_device *dev) | |||
844 | { | 824 | { |
845 | struct snd_timer *timer = dev->device_data; | 825 | struct snd_timer *timer = dev->device_data; |
846 | struct snd_timer *timer1; | 826 | struct snd_timer *timer1; |
847 | struct list_head *p; | ||
848 | 827 | ||
849 | snd_assert(timer != NULL && timer->hw.start != NULL && | 828 | snd_assert(timer != NULL && timer->hw.start != NULL && |
850 | timer->hw.stop != NULL, return -ENXIO); | 829 | timer->hw.stop != NULL, return -ENXIO); |
@@ -853,8 +832,7 @@ static int snd_timer_dev_register(struct snd_device *dev) | |||
853 | return -EINVAL; | 832 | return -EINVAL; |
854 | 833 | ||
855 | mutex_lock(®ister_mutex); | 834 | mutex_lock(®ister_mutex); |
856 | list_for_each(p, &snd_timer_list) { | 835 | list_for_each_entry(timer1, &snd_timer_list, device_list) { |
857 | timer1 = list_entry(p, struct snd_timer, device_list); | ||
858 | if (timer1->tmr_class > timer->tmr_class) | 836 | if (timer1->tmr_class > timer->tmr_class) |
859 | break; | 837 | break; |
860 | if (timer1->tmr_class < timer->tmr_class) | 838 | if (timer1->tmr_class < timer->tmr_class) |
@@ -877,7 +855,7 @@ static int snd_timer_dev_register(struct snd_device *dev) | |||
877 | mutex_unlock(®ister_mutex); | 855 | mutex_unlock(®ister_mutex); |
878 | return -EBUSY; | 856 | return -EBUSY; |
879 | } | 857 | } |
880 | list_add_tail(&timer->device_list, p); | 858 | list_add_tail(&timer->device_list, &timer1->device_list); |
881 | mutex_unlock(®ister_mutex); | 859 | mutex_unlock(®ister_mutex); |
882 | return 0; | 860 | return 0; |
883 | } | 861 | } |
@@ -896,7 +874,6 @@ void snd_timer_notify(struct snd_timer *timer, int event, struct timespec *tstam | |||
896 | unsigned long flags; | 874 | unsigned long flags; |
897 | unsigned long resolution = 0; | 875 | unsigned long resolution = 0; |
898 | struct snd_timer_instance *ti, *ts; | 876 | struct snd_timer_instance *ti, *ts; |
899 | struct list_head *p, *n; | ||
900 | 877 | ||
901 | if (! (timer->hw.flags & SNDRV_TIMER_HW_SLAVE)) | 878 | if (! (timer->hw.flags & SNDRV_TIMER_HW_SLAVE)) |
902 | return; | 879 | return; |
@@ -911,15 +888,12 @@ void snd_timer_notify(struct snd_timer *timer, int event, struct timespec *tstam | |||
911 | else | 888 | else |
912 | resolution = timer->hw.resolution; | 889 | resolution = timer->hw.resolution; |
913 | } | 890 | } |
914 | list_for_each(p, &timer->active_list_head) { | 891 | list_for_each_entry(ti, &timer->active_list_head, active_list) { |
915 | ti = list_entry(p, struct snd_timer_instance, active_list); | ||
916 | if (ti->ccallback) | 892 | if (ti->ccallback) |
917 | ti->ccallback(ti, event, tstamp, resolution); | 893 | ti->ccallback(ti, event, tstamp, resolution); |
918 | list_for_each(n, &ti->slave_active_head) { | 894 | list_for_each_entry(ts, &ti->slave_active_head, active_list) |
919 | ts = list_entry(n, struct snd_timer_instance, active_list); | ||
920 | if (ts->ccallback) | 895 | if (ts->ccallback) |
921 | ts->ccallback(ts, event, tstamp, resolution); | 896 | ts->ccallback(ts, event, tstamp, resolution); |
922 | } | ||
923 | } | 897 | } |
924 | spin_unlock_irqrestore(&timer->lock, flags); | 898 | spin_unlock_irqrestore(&timer->lock, flags); |
925 | } | 899 | } |
@@ -1057,11 +1031,9 @@ static void snd_timer_proc_read(struct snd_info_entry *entry, | |||
1057 | { | 1031 | { |
1058 | struct snd_timer *timer; | 1032 | struct snd_timer *timer; |
1059 | struct snd_timer_instance *ti; | 1033 | struct snd_timer_instance *ti; |
1060 | struct list_head *p, *q; | ||
1061 | 1034 | ||
1062 | mutex_lock(®ister_mutex); | 1035 | mutex_lock(®ister_mutex); |
1063 | list_for_each(p, &snd_timer_list) { | 1036 | list_for_each_entry(timer, &snd_timer_list, device_list) { |
1064 | timer = list_entry(p, struct snd_timer, device_list); | ||
1065 | switch (timer->tmr_class) { | 1037 | switch (timer->tmr_class) { |
1066 | case SNDRV_TIMER_CLASS_GLOBAL: | 1038 | case SNDRV_TIMER_CLASS_GLOBAL: |
1067 | snd_iprintf(buffer, "G%i: ", timer->tmr_device); | 1039 | snd_iprintf(buffer, "G%i: ", timer->tmr_device); |
@@ -1088,14 +1060,12 @@ static void snd_timer_proc_read(struct snd_info_entry *entry, | |||
1088 | if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE) | 1060 | if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE) |
1089 | snd_iprintf(buffer, " SLAVE"); | 1061 | snd_iprintf(buffer, " SLAVE"); |
1090 | snd_iprintf(buffer, "\n"); | 1062 | snd_iprintf(buffer, "\n"); |
1091 | list_for_each(q, &timer->open_list_head) { | 1063 | list_for_each_entry(ti, &timer->open_list_head, open_list) |
1092 | ti = list_entry(q, struct snd_timer_instance, open_list); | ||
1093 | snd_iprintf(buffer, " Client %s : %s\n", | 1064 | snd_iprintf(buffer, " Client %s : %s\n", |
1094 | ti->owner ? ti->owner : "unknown", | 1065 | ti->owner ? ti->owner : "unknown", |
1095 | ti->flags & (SNDRV_TIMER_IFLG_START | | 1066 | ti->flags & (SNDRV_TIMER_IFLG_START | |
1096 | SNDRV_TIMER_IFLG_RUNNING) | 1067 | SNDRV_TIMER_IFLG_RUNNING) |
1097 | ? "running" : "stopped"); | 1068 | ? "running" : "stopped"); |
1098 | } | ||
1099 | } | 1069 | } |
1100 | mutex_unlock(®ister_mutex); | 1070 | mutex_unlock(®ister_mutex); |
1101 | } | 1071 | } |
diff --git a/sound/drivers/Kconfig b/sound/drivers/Kconfig index 40ebd2f44056..83529b08d019 100644 --- a/sound/drivers/Kconfig +++ b/sound/drivers/Kconfig | |||
@@ -109,4 +109,15 @@ config SND_MPU401 | |||
109 | To compile this driver as a module, choose M here: the module | 109 | To compile this driver as a module, choose M here: the module |
110 | will be called snd-mpu401. | 110 | will be called snd-mpu401. |
111 | 111 | ||
112 | config SND_PORTMAN2X4 | ||
113 | tristate "Portman 2x4 driver" | ||
114 | depends on SND && PARPORT | ||
115 | select SND_RAWMIDI | ||
116 | help | ||
117 | Say Y here to include support for Midiman Portman 2x4 parallel | ||
118 | port MIDI device. | ||
119 | |||
120 | To compile this driver as a module, choose M here: the module | ||
121 | will be called snd-portman2x4. | ||
122 | |||
112 | endmenu | 123 | endmenu |
diff --git a/sound/drivers/Makefile b/sound/drivers/Makefile index c9bad6d67e73..04112642611a 100644 --- a/sound/drivers/Makefile +++ b/sound/drivers/Makefile | |||
@@ -6,6 +6,7 @@ | |||
6 | snd-dummy-objs := dummy.o | 6 | snd-dummy-objs := dummy.o |
7 | snd-mtpav-objs := mtpav.o | 7 | snd-mtpav-objs := mtpav.o |
8 | snd-mts64-objs := mts64.o | 8 | snd-mts64-objs := mts64.o |
9 | snd-portman2x4-objs := portman2x4.o | ||
9 | snd-serial-u16550-objs := serial-u16550.o | 10 | snd-serial-u16550-objs := serial-u16550.o |
10 | snd-virmidi-objs := virmidi.o | 11 | snd-virmidi-objs := virmidi.o |
11 | 12 | ||
@@ -15,5 +16,6 @@ obj-$(CONFIG_SND_VIRMIDI) += snd-virmidi.o | |||
15 | obj-$(CONFIG_SND_SERIAL_U16550) += snd-serial-u16550.o | 16 | obj-$(CONFIG_SND_SERIAL_U16550) += snd-serial-u16550.o |
16 | obj-$(CONFIG_SND_MTPAV) += snd-mtpav.o | 17 | obj-$(CONFIG_SND_MTPAV) += snd-mtpav.o |
17 | obj-$(CONFIG_SND_MTS64) += snd-mts64.o | 18 | obj-$(CONFIG_SND_MTS64) += snd-mts64.o |
19 | obj-$(CONFIG_SND_PORTMAN2X4) += snd-portman2x4.o | ||
18 | 20 | ||
19 | obj-$(CONFIG_SND) += opl3/ opl4/ mpu401/ vx/ | 21 | obj-$(CONFIG_SND) += opl3/ opl4/ mpu401/ vx/ |
diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c index 42001efa9f3e..8339bad969ba 100644 --- a/sound/drivers/dummy.c +++ b/sound/drivers/dummy.c | |||
@@ -501,7 +501,7 @@ static int snd_dummy_volume_put(struct snd_kcontrol *kcontrol, | |||
501 | return change; | 501 | return change; |
502 | } | 502 | } |
503 | 503 | ||
504 | static DECLARE_TLV_DB_SCALE(db_scale_dummy, -4500, 30, 0); | 504 | static const DECLARE_TLV_DB_SCALE(db_scale_dummy, -4500, 30, 0); |
505 | 505 | ||
506 | #define DUMMY_CAPSRC(xname, xindex, addr) \ | 506 | #define DUMMY_CAPSRC(xname, xindex, addr) \ |
507 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ | 507 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ |
diff --git a/sound/drivers/portman2x4.c b/sound/drivers/portman2x4.c new file mode 100644 index 000000000000..6c48772aaefd --- /dev/null +++ b/sound/drivers/portman2x4.c | |||
@@ -0,0 +1,876 @@ | |||
1 | /* | ||
2 | * Driver for Midiman Portman2x4 parallel port midi interface | ||
3 | * | ||
4 | * Copyright (c) by Levent Guendogdu <levon@feature-it.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | * | ||
20 | * ChangeLog | ||
21 | * Jan 24 2007 Matthias Koenig <mkoenig@suse.de> | ||
22 | * - cleanup and rewrite | ||
23 | * Sep 30 2004 Tobias Gehrig <tobias@gehrig.tk> | ||
24 | * - source code cleanup | ||
25 | * Sep 03 2004 Tobias Gehrig <tobias@gehrig.tk> | ||
26 | * - fixed compilation problem with alsa 1.0.6a (removed MODULE_CLASSES, | ||
27 | * MODULE_PARM_SYNTAX and changed MODULE_DEVICES to | ||
28 | * MODULE_SUPPORTED_DEVICE) | ||
29 | * Mar 24 2004 Tobias Gehrig <tobias@gehrig.tk> | ||
30 | * - added 2.6 kernel support | ||
31 | * Mar 18 2004 Tobias Gehrig <tobias@gehrig.tk> | ||
32 | * - added parport_unregister_driver to the startup routine if the driver fails to detect a portman | ||
33 | * - added support for all 4 output ports in portman_putmidi | ||
34 | * Mar 17 2004 Tobias Gehrig <tobias@gehrig.tk> | ||
35 | * - added checks for opened input device in interrupt handler | ||
36 | * Feb 20 2004 Tobias Gehrig <tobias@gehrig.tk> | ||
37 | * - ported from alsa 0.5 to 1.0 | ||
38 | */ | ||
39 | |||
40 | #include <sound/driver.h> | ||
41 | #include <linux/init.h> | ||
42 | #include <linux/platform_device.h> | ||
43 | #include <linux/parport.h> | ||
44 | #include <linux/spinlock.h> | ||
45 | #include <linux/delay.h> | ||
46 | #include <sound/core.h> | ||
47 | #include <sound/initval.h> | ||
48 | #include <sound/rawmidi.h> | ||
49 | #include <sound/control.h> | ||
50 | |||
51 | #define CARD_NAME "Portman 2x4" | ||
52 | #define DRIVER_NAME "portman" | ||
53 | #define PLATFORM_DRIVER "snd_portman2x4" | ||
54 | |||
55 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; | ||
56 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; | ||
57 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; | ||
58 | |||
59 | static struct platform_device *platform_devices[SNDRV_CARDS]; | ||
60 | static int device_count; | ||
61 | |||
62 | module_param_array(index, int, NULL, S_IRUGO); | ||
63 | MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard."); | ||
64 | module_param_array(id, charp, NULL, S_IRUGO); | ||
65 | MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard."); | ||
66 | module_param_array(enable, bool, NULL, S_IRUGO); | ||
67 | MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard."); | ||
68 | |||
69 | MODULE_AUTHOR("Levent Guendogdu, Tobias Gehrig, Matthias Koenig"); | ||
70 | MODULE_DESCRIPTION("Midiman Portman2x4"); | ||
71 | MODULE_LICENSE("GPL"); | ||
72 | MODULE_SUPPORTED_DEVICE("{{Midiman,Portman2x4}}"); | ||
73 | |||
74 | /********************************************************************* | ||
75 | * Chip specific | ||
76 | *********************************************************************/ | ||
77 | #define PORTMAN_NUM_INPUT_PORTS 2 | ||
78 | #define PORTMAN_NUM_OUTPUT_PORTS 4 | ||
79 | |||
80 | struct portman { | ||
81 | spinlock_t reg_lock; | ||
82 | struct snd_card *card; | ||
83 | struct snd_rawmidi *rmidi; | ||
84 | struct pardevice *pardev; | ||
85 | int pardev_claimed; | ||
86 | |||
87 | int open_count; | ||
88 | int mode[PORTMAN_NUM_INPUT_PORTS]; | ||
89 | struct snd_rawmidi_substream *midi_input[PORTMAN_NUM_INPUT_PORTS]; | ||
90 | }; | ||
91 | |||
92 | static int portman_free(struct portman *pm) | ||
93 | { | ||
94 | kfree(pm); | ||
95 | return 0; | ||
96 | } | ||
97 | |||
98 | static int __devinit portman_create(struct snd_card *card, | ||
99 | struct pardevice *pardev, | ||
100 | struct portman **rchip) | ||
101 | { | ||
102 | struct portman *pm; | ||
103 | |||
104 | *rchip = NULL; | ||
105 | |||
106 | pm = kzalloc(sizeof(struct portman), GFP_KERNEL); | ||
107 | if (pm == NULL) | ||
108 | return -ENOMEM; | ||
109 | |||
110 | /* Init chip specific data */ | ||
111 | spin_lock_init(&pm->reg_lock); | ||
112 | pm->card = card; | ||
113 | pm->pardev = pardev; | ||
114 | |||
115 | *rchip = pm; | ||
116 | |||
117 | return 0; | ||
118 | } | ||
119 | |||
120 | /********************************************************************* | ||
121 | * HW related constants | ||
122 | *********************************************************************/ | ||
123 | |||
124 | /* Standard PC parallel port status register equates. */ | ||
125 | #define PP_STAT_BSY 0x80 /* Busy status. Inverted. */ | ||
126 | #define PP_STAT_ACK 0x40 /* Acknowledge. Non-Inverted. */ | ||
127 | #define PP_STAT_POUT 0x20 /* Paper Out. Non-Inverted. */ | ||
128 | #define PP_STAT_SEL 0x10 /* Select. Non-Inverted. */ | ||
129 | #define PP_STAT_ERR 0x08 /* Error. Non-Inverted. */ | ||
130 | |||
131 | /* Standard PC parallel port command register equates. */ | ||
132 | #define PP_CMD_IEN 0x10 /* IRQ Enable. Non-Inverted. */ | ||
133 | #define PP_CMD_SELI 0x08 /* Select Input. Inverted. */ | ||
134 | #define PP_CMD_INIT 0x04 /* Init Printer. Non-Inverted. */ | ||
135 | #define PP_CMD_FEED 0x02 /* Auto Feed. Inverted. */ | ||
136 | #define PP_CMD_STB 0x01 /* Strobe. Inverted. */ | ||
137 | |||
138 | /* Parallel Port Command Register as implemented by PCP2x4. */ | ||
139 | #define INT_EN PP_CMD_IEN /* Interrupt enable. */ | ||
140 | #define STROBE PP_CMD_STB /* Command strobe. */ | ||
141 | |||
142 | /* The parallel port command register field (b1..b3) selects the | ||
143 | * various "registers" within the PC/P 2x4. These are the internal | ||
144 | * address of these "registers" that must be written to the parallel | ||
145 | * port command register. | ||
146 | */ | ||
147 | #define RXDATA0 (0 << 1) /* PCP RxData channel 0. */ | ||
148 | #define RXDATA1 (1 << 1) /* PCP RxData channel 1. */ | ||
149 | #define GEN_CTL (2 << 1) /* PCP General Control Register. */ | ||
150 | #define SYNC_CTL (3 << 1) /* PCP Sync Control Register. */ | ||
151 | #define TXDATA0 (4 << 1) /* PCP TxData channel 0. */ | ||
152 | #define TXDATA1 (5 << 1) /* PCP TxData channel 1. */ | ||
153 | #define TXDATA2 (6 << 1) /* PCP TxData channel 2. */ | ||
154 | #define TXDATA3 (7 << 1) /* PCP TxData channel 3. */ | ||
155 | |||
156 | /* Parallel Port Status Register as implemented by PCP2x4. */ | ||
157 | #define ESTB PP_STAT_POUT /* Echoed strobe. */ | ||
158 | #define INT_REQ PP_STAT_ACK /* Input data int request. */ | ||
159 | #define BUSY PP_STAT_ERR /* Interface Busy. */ | ||
160 | |||
161 | /* Parallel Port Status Register BUSY and SELECT lines are multiplexed | ||
162 | * between several functions. Depending on which 2x4 "register" is | ||
163 | * currently selected (b1..b3), the BUSY and SELECT lines are | ||
164 | * assigned as follows: | ||
165 | * | ||
166 | * SELECT LINE: A3 A2 A1 | ||
167 | * -------- | ||
168 | */ | ||
169 | #define RXAVAIL PP_STAT_SEL /* Rx Available, channel 0. 0 0 0 */ | ||
170 | // RXAVAIL1 PP_STAT_SEL /* Rx Available, channel 1. 0 0 1 */ | ||
171 | #define SYNC_STAT PP_STAT_SEL /* Reserved - Sync Status. 0 1 0 */ | ||
172 | // /* Reserved. 0 1 1 */ | ||
173 | #define TXEMPTY PP_STAT_SEL /* Tx Empty, channel 0. 1 0 0 */ | ||
174 | // TXEMPTY1 PP_STAT_SEL /* Tx Empty, channel 1. 1 0 1 */ | ||
175 | // TXEMPTY2 PP_STAT_SEL /* Tx Empty, channel 2. 1 1 0 */ | ||
176 | // TXEMPTY3 PP_STAT_SEL /* Tx Empty, channel 3. 1 1 1 */ | ||
177 | |||
178 | /* BUSY LINE: A3 A2 A1 | ||
179 | * -------- | ||
180 | */ | ||
181 | #define RXDATA PP_STAT_BSY /* Rx Input Data, channel 0. 0 0 0 */ | ||
182 | // RXDATA1 PP_STAT_BSY /* Rx Input Data, channel 1. 0 0 1 */ | ||
183 | #define SYNC_DATA PP_STAT_BSY /* Reserved - Sync Data. 0 1 0 */ | ||
184 | /* Reserved. 0 1 1 */ | ||
185 | #define DATA_ECHO PP_STAT_BSY /* Parallel Port Data Echo. 1 0 0 */ | ||
186 | #define A0_ECHO PP_STAT_BSY /* Address 0 Echo. 1 0 1 */ | ||
187 | #define A1_ECHO PP_STAT_BSY /* Address 1 Echo. 1 1 0 */ | ||
188 | #define A2_ECHO PP_STAT_BSY /* Address 2 Echo. 1 1 1 */ | ||
189 | |||
190 | #define PORTMAN2X4_MODE_INPUT_TRIGGERED 0x01 | ||
191 | |||
192 | /********************************************************************* | ||
193 | * Hardware specific functions | ||
194 | *********************************************************************/ | ||
195 | static inline void portman_write_command(struct portman *pm, u8 value) | ||
196 | { | ||
197 | parport_write_control(pm->pardev->port, value); | ||
198 | } | ||
199 | |||
200 | static inline u8 portman_read_command(struct portman *pm) | ||
201 | { | ||
202 | return parport_read_control(pm->pardev->port); | ||
203 | } | ||
204 | |||
205 | static inline u8 portman_read_status(struct portman *pm) | ||
206 | { | ||
207 | return parport_read_status(pm->pardev->port); | ||
208 | } | ||
209 | |||
210 | static inline u8 portman_read_data(struct portman *pm) | ||
211 | { | ||
212 | return parport_read_data(pm->pardev->port); | ||
213 | } | ||
214 | |||
215 | static inline void portman_write_data(struct portman *pm, u8 value) | ||
216 | { | ||
217 | parport_write_data(pm->pardev->port, value); | ||
218 | } | ||
219 | |||
220 | static void portman_write_midi(struct portman *pm, | ||
221 | int port, u8 mididata) | ||
222 | { | ||
223 | int command = ((port + 4) << 1); | ||
224 | |||
225 | /* Get entering data byte and port number in BL and BH respectively. | ||
226 | * Set up Tx Channel address field for use with PP Cmd Register. | ||
227 | * Store address field in BH register. | ||
228 | * Inputs: AH = Output port number (0..3). | ||
229 | * AL = Data byte. | ||
230 | * command = TXDATA0 | INT_EN; | ||
231 | * Align port num with address field (b1...b3), | ||
232 | * set address for TXDatax, Strobe=0 | ||
233 | */ | ||
234 | command |= INT_EN; | ||
235 | |||
236 | /* Disable interrupts so that the process is not interrupted, then | ||
237 | * write the address associated with the current Tx channel to the | ||
238 | * PP Command Reg. Do not set the Strobe signal yet. | ||
239 | */ | ||
240 | |||
241 | do { | ||
242 | portman_write_command(pm, command); | ||
243 | |||
244 | /* While the address lines settle, write parallel output data to | ||
245 | * PP Data Reg. This has no effect until Strobe signal is asserted. | ||
246 | */ | ||
247 | |||
248 | portman_write_data(pm, mididata); | ||
249 | |||
250 | /* If PCP channel's TxEmpty is set (TxEmpty is read through the PP | ||
251 | * Status Register), then go write data. Else go back and wait. | ||
252 | */ | ||
253 | } while ((portman_read_status(pm) & TXEMPTY) != TXEMPTY); | ||
254 | |||
255 | /* TxEmpty is set. Maintain PC/P destination address and assert | ||
256 | * Strobe through the PP Command Reg. This will Strobe data into | ||
257 | * the PC/P transmitter and set the PC/P BUSY signal. | ||
258 | */ | ||
259 | |||
260 | portman_write_command(pm, command | STROBE); | ||
261 | |||
262 | /* Wait for strobe line to settle and echo back through hardware. | ||
263 | * Once it has echoed back, assume that the address and data lines | ||
264 | * have settled! | ||
265 | */ | ||
266 | |||
267 | while ((portman_read_status(pm) & ESTB) == 0) | ||
268 | cpu_relax(); | ||
269 | |||
270 | /* Release strobe and immediately re-allow interrupts. */ | ||
271 | portman_write_command(pm, command); | ||
272 | |||
273 | while ((portman_read_status(pm) & ESTB) == ESTB) | ||
274 | cpu_relax(); | ||
275 | |||
276 | /* PC/P BUSY is now set. We must wait until BUSY resets itself. | ||
277 | * We'll reenable ints while we're waiting. | ||
278 | */ | ||
279 | |||
280 | while ((portman_read_status(pm) & BUSY) == BUSY) | ||
281 | cpu_relax(); | ||
282 | |||
283 | /* Data sent. */ | ||
284 | } | ||
285 | |||
286 | |||
287 | /* | ||
288 | * Read MIDI byte from port | ||
289 | * Attempt to read input byte from specified hardware input port (0..). | ||
290 | * Return -1 if no data | ||
291 | */ | ||
292 | static int portman_read_midi(struct portman *pm, int port) | ||
293 | { | ||
294 | unsigned char midi_data = 0; | ||
295 | unsigned char cmdout; /* Saved address+IE bit. */ | ||
296 | |||
297 | /* Make sure clocking edge is down before starting... */ | ||
298 | portman_write_data(pm, 0); /* Make sure edge is down. */ | ||
299 | |||
300 | /* Set destination address to PCP. */ | ||
301 | cmdout = (port << 1) | INT_EN; /* Address + IE + No Strobe. */ | ||
302 | portman_write_command(pm, cmdout); | ||
303 | |||
304 | while ((portman_read_status(pm) & ESTB) == ESTB) | ||
305 | cpu_relax(); /* Wait for strobe echo. */ | ||
306 | |||
307 | /* After the address lines settle, check multiplexed RxAvail signal. | ||
308 | * If data is available, read it. | ||
309 | */ | ||
310 | if ((portman_read_status(pm) & RXAVAIL) == 0) | ||
311 | return -1; /* No data. */ | ||
312 | |||
313 | /* Set the Strobe signal to enable the Rx clocking circuitry. */ | ||
314 | portman_write_command(pm, cmdout | STROBE); /* Write address+IE+Strobe. */ | ||
315 | |||
316 | while ((portman_read_status(pm) & ESTB) == 0) | ||
317 | cpu_relax(); /* Wait for strobe echo. */ | ||
318 | |||
319 | /* The first data bit (msb) is already sitting on the input line. */ | ||
320 | midi_data = (portman_read_status(pm) & 128); | ||
321 | portman_write_data(pm, 1); /* Cause rising edge, which shifts data. */ | ||
322 | |||
323 | /* Data bit 6. */ | ||
324 | portman_write_data(pm, 0); /* Cause falling edge while data settles. */ | ||
325 | midi_data |= (portman_read_status(pm) >> 1) & 64; | ||
326 | portman_write_data(pm, 1); /* Cause rising edge, which shifts data. */ | ||
327 | |||
328 | /* Data bit 5. */ | ||
329 | portman_write_data(pm, 0); /* Cause falling edge while data settles. */ | ||
330 | midi_data |= (portman_read_status(pm) >> 2) & 32; | ||
331 | portman_write_data(pm, 1); /* Cause rising edge, which shifts data. */ | ||
332 | |||
333 | /* Data bit 4. */ | ||
334 | portman_write_data(pm, 0); /* Cause falling edge while data settles. */ | ||
335 | midi_data |= (portman_read_status(pm) >> 3) & 16; | ||
336 | portman_write_data(pm, 1); /* Cause rising edge, which shifts data. */ | ||
337 | |||
338 | /* Data bit 3. */ | ||
339 | portman_write_data(pm, 0); /* Cause falling edge while data settles. */ | ||
340 | midi_data |= (portman_read_status(pm) >> 4) & 8; | ||
341 | portman_write_data(pm, 1); /* Cause rising edge, which shifts data. */ | ||
342 | |||
343 | /* Data bit 2. */ | ||
344 | portman_write_data(pm, 0); /* Cause falling edge while data settles. */ | ||
345 | midi_data |= (portman_read_status(pm) >> 5) & 4; | ||
346 | portman_write_data(pm, 1); /* Cause rising edge, which shifts data. */ | ||
347 | |||
348 | /* Data bit 1. */ | ||
349 | portman_write_data(pm, 0); /* Cause falling edge while data settles. */ | ||
350 | midi_data |= (portman_read_status(pm) >> 6) & 2; | ||
351 | portman_write_data(pm, 1); /* Cause rising edge, which shifts data. */ | ||
352 | |||
353 | /* Data bit 0. */ | ||
354 | portman_write_data(pm, 0); /* Cause falling edge while data settles. */ | ||
355 | midi_data |= (portman_read_status(pm) >> 7) & 1; | ||
356 | portman_write_data(pm, 1); /* Cause rising edge, which shifts data. */ | ||
357 | portman_write_data(pm, 0); /* Return data clock low. */ | ||
358 | |||
359 | |||
360 | /* De-assert Strobe and return data. */ | ||
361 | portman_write_command(pm, cmdout); /* Output saved address+IE. */ | ||
362 | |||
363 | /* Wait for strobe echo. */ | ||
364 | while ((portman_read_status(pm) & ESTB) == ESTB) | ||
365 | cpu_relax(); | ||
366 | |||
367 | return (midi_data & 255); /* Shift back and return value. */ | ||
368 | } | ||
369 | |||
370 | /* | ||
371 | * Checks if any input data on the given channel is available | ||
372 | * Checks RxAvail | ||
373 | */ | ||
374 | static int portman_data_avail(struct portman *pm, int channel) | ||
375 | { | ||
376 | int command = INT_EN; | ||
377 | switch (channel) { | ||
378 | case 0: | ||
379 | command |= RXDATA0; | ||
380 | break; | ||
381 | case 1: | ||
382 | command |= RXDATA1; | ||
383 | break; | ||
384 | } | ||
385 | /* Write hardware (assumme STROBE=0) */ | ||
386 | portman_write_command(pm, command); | ||
387 | /* Check multiplexed RxAvail signal */ | ||
388 | if ((portman_read_status(pm) & RXAVAIL) == RXAVAIL) | ||
389 | return 1; /* Data available */ | ||
390 | |||
391 | /* No Data available */ | ||
392 | return 0; | ||
393 | } | ||
394 | |||
395 | |||
396 | /* | ||
397 | * Flushes any input | ||
398 | */ | ||
399 | static void portman_flush_input(struct portman *pm, unsigned char port) | ||
400 | { | ||
401 | /* Local variable for counting things */ | ||
402 | unsigned int i = 0; | ||
403 | unsigned char command = 0; | ||
404 | |||
405 | switch (port) { | ||
406 | case 0: | ||
407 | command = RXDATA0; | ||
408 | break; | ||
409 | case 1: | ||
410 | command = RXDATA1; | ||
411 | break; | ||
412 | default: | ||
413 | snd_printk(KERN_WARNING | ||
414 | "portman_flush_input() Won't flush port %i\n", | ||
415 | port); | ||
416 | return; | ||
417 | } | ||
418 | |||
419 | /* Set address for specified channel in port and allow to settle. */ | ||
420 | portman_write_command(pm, command); | ||
421 | |||
422 | /* Assert the Strobe and wait for echo back. */ | ||
423 | portman_write_command(pm, command | STROBE); | ||
424 | |||
425 | /* Wait for ESTB */ | ||
426 | while ((portman_read_status(pm) & ESTB) == 0) | ||
427 | cpu_relax(); | ||
428 | |||
429 | /* Output clock cycles to the Rx circuitry. */ | ||
430 | portman_write_data(pm, 0); | ||
431 | |||
432 | /* Flush 250 bits... */ | ||
433 | for (i = 0; i < 250; i++) { | ||
434 | portman_write_data(pm, 1); | ||
435 | portman_write_data(pm, 0); | ||
436 | } | ||
437 | |||
438 | /* Deassert the Strobe signal of the port and wait for it to settle. */ | ||
439 | portman_write_command(pm, command | INT_EN); | ||
440 | |||
441 | /* Wait for settling */ | ||
442 | while ((portman_read_status(pm) & ESTB) == ESTB) | ||
443 | cpu_relax(); | ||
444 | } | ||
445 | |||
446 | static int portman_probe(struct parport *p) | ||
447 | { | ||
448 | /* Initialize the parallel port data register. Will set Rx clocks | ||
449 | * low in case we happen to be addressing the Rx ports at this time. | ||
450 | */ | ||
451 | /* 1 */ | ||
452 | parport_write_data(p, 0); | ||
453 | |||
454 | /* Initialize the parallel port command register, thus initializing | ||
455 | * hardware handshake lines to midi box: | ||
456 | * | ||
457 | * Strobe = 0 | ||
458 | * Interrupt Enable = 0 | ||
459 | */ | ||
460 | /* 2 */ | ||
461 | parport_write_control(p, 0); | ||
462 | |||
463 | /* Check if Portman PC/P 2x4 is out there. */ | ||
464 | /* 3 */ | ||
465 | parport_write_control(p, RXDATA0); /* Write Strobe=0 to command reg. */ | ||
466 | |||
467 | /* Check for ESTB to be clear */ | ||
468 | /* 4 */ | ||
469 | if ((parport_read_status(p) & ESTB) == ESTB) | ||
470 | return 1; /* CODE 1 - Strobe Failure. */ | ||
471 | |||
472 | /* Set for RXDATA0 where no damage will be done. */ | ||
473 | /* 5 */ | ||
474 | parport_write_control(p, RXDATA0 + STROBE); /* Write Strobe=1 to command reg. */ | ||
475 | |||
476 | /* 6 */ | ||
477 | if ((parport_read_status(p) & ESTB) != ESTB) | ||
478 | return 1; /* CODE 1 - Strobe Failure. */ | ||
479 | |||
480 | /* 7 */ | ||
481 | parport_write_control(p, 0); /* Reset Strobe=0. */ | ||
482 | |||
483 | /* Check if Tx circuitry is functioning properly. If initialized | ||
484 | * unit TxEmpty is false, send out char and see if if goes true. | ||
485 | */ | ||
486 | /* 8 */ | ||
487 | parport_write_control(p, TXDATA0); /* Tx channel 0, strobe off. */ | ||
488 | |||
489 | /* If PCP channel's TxEmpty is set (TxEmpty is read through the PP | ||
490 | * Status Register), then go write data. Else go back and wait. | ||
491 | */ | ||
492 | /* 9 */ | ||
493 | if ((parport_read_status(p) & TXEMPTY) == 0) | ||
494 | return 2; | ||
495 | |||
496 | /* Return OK status. */ | ||
497 | return 0; | ||
498 | } | ||
499 | |||
500 | static int portman_device_init(struct portman *pm) | ||
501 | { | ||
502 | portman_flush_input(pm, 0); | ||
503 | portman_flush_input(pm, 1); | ||
504 | |||
505 | return 0; | ||
506 | } | ||
507 | |||
508 | /********************************************************************* | ||
509 | * Rawmidi | ||
510 | *********************************************************************/ | ||
511 | static int snd_portman_midi_open(struct snd_rawmidi_substream *substream) | ||
512 | { | ||
513 | return 0; | ||
514 | } | ||
515 | |||
516 | static int snd_portman_midi_close(struct snd_rawmidi_substream *substream) | ||
517 | { | ||
518 | return 0; | ||
519 | } | ||
520 | |||
521 | static void snd_portman_midi_input_trigger(struct snd_rawmidi_substream *substream, | ||
522 | int up) | ||
523 | { | ||
524 | struct portman *pm = substream->rmidi->private_data; | ||
525 | unsigned long flags; | ||
526 | |||
527 | spin_lock_irqsave(&pm->reg_lock, flags); | ||
528 | if (up) | ||
529 | pm->mode[substream->number] |= PORTMAN2X4_MODE_INPUT_TRIGGERED; | ||
530 | else | ||
531 | pm->mode[substream->number] &= ~PORTMAN2X4_MODE_INPUT_TRIGGERED; | ||
532 | spin_unlock_irqrestore(&pm->reg_lock, flags); | ||
533 | } | ||
534 | |||
535 | static void snd_portman_midi_output_trigger(struct snd_rawmidi_substream *substream, | ||
536 | int up) | ||
537 | { | ||
538 | struct portman *pm = substream->rmidi->private_data; | ||
539 | unsigned long flags; | ||
540 | unsigned char byte; | ||
541 | |||
542 | spin_lock_irqsave(&pm->reg_lock, flags); | ||
543 | if (up) { | ||
544 | while ((snd_rawmidi_transmit(substream, &byte, 1) == 1)) | ||
545 | portman_write_midi(pm, substream->number, byte); | ||
546 | } | ||
547 | spin_unlock_irqrestore(&pm->reg_lock, flags); | ||
548 | } | ||
549 | |||
550 | static struct snd_rawmidi_ops snd_portman_midi_output = { | ||
551 | .open = snd_portman_midi_open, | ||
552 | .close = snd_portman_midi_close, | ||
553 | .trigger = snd_portman_midi_output_trigger, | ||
554 | }; | ||
555 | |||
556 | static struct snd_rawmidi_ops snd_portman_midi_input = { | ||
557 | .open = snd_portman_midi_open, | ||
558 | .close = snd_portman_midi_close, | ||
559 | .trigger = snd_portman_midi_input_trigger, | ||
560 | }; | ||
561 | |||
562 | /* Create and initialize the rawmidi component */ | ||
563 | static int __devinit snd_portman_rawmidi_create(struct snd_card *card) | ||
564 | { | ||
565 | struct portman *pm = card->private_data; | ||
566 | struct snd_rawmidi *rmidi; | ||
567 | struct snd_rawmidi_substream *substream; | ||
568 | int err; | ||
569 | |||
570 | err = snd_rawmidi_new(card, CARD_NAME, 0, | ||
571 | PORTMAN_NUM_OUTPUT_PORTS, | ||
572 | PORTMAN_NUM_INPUT_PORTS, | ||
573 | &rmidi); | ||
574 | if (err < 0) | ||
575 | return err; | ||
576 | |||
577 | rmidi->private_data = pm; | ||
578 | strcpy(rmidi->name, CARD_NAME); | ||
579 | rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT | | ||
580 | SNDRV_RAWMIDI_INFO_INPUT | | ||
581 | SNDRV_RAWMIDI_INFO_DUPLEX; | ||
582 | |||
583 | pm->rmidi = rmidi; | ||
584 | |||
585 | /* register rawmidi ops */ | ||
586 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, | ||
587 | &snd_portman_midi_output); | ||
588 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, | ||
589 | &snd_portman_midi_input); | ||
590 | |||
591 | /* name substreams */ | ||
592 | /* output */ | ||
593 | list_for_each_entry(substream, | ||
594 | &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams, | ||
595 | list) { | ||
596 | sprintf(substream->name, | ||
597 | "Portman2x4 %d", substream->number+1); | ||
598 | } | ||
599 | /* input */ | ||
600 | list_for_each_entry(substream, | ||
601 | &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams, | ||
602 | list) { | ||
603 | pm->midi_input[substream->number] = substream; | ||
604 | sprintf(substream->name, | ||
605 | "Portman2x4 %d", substream->number+1); | ||
606 | } | ||
607 | |||
608 | return err; | ||
609 | } | ||
610 | |||
611 | /********************************************************************* | ||
612 | * parport stuff | ||
613 | *********************************************************************/ | ||
614 | static void snd_portman_interrupt(int irq, void *userdata) | ||
615 | { | ||
616 | unsigned char midivalue = 0; | ||
617 | struct portman *pm = ((struct snd_card*)userdata)->private_data; | ||
618 | |||
619 | spin_lock(&pm->reg_lock); | ||
620 | |||
621 | /* While any input data is waiting */ | ||
622 | while ((portman_read_status(pm) & INT_REQ) == INT_REQ) { | ||
623 | /* If data available on channel 0, | ||
624 | read it and stuff it into the queue. */ | ||
625 | if (portman_data_avail(pm, 0)) { | ||
626 | /* Read Midi */ | ||
627 | midivalue = portman_read_midi(pm, 0); | ||
628 | /* put midi into queue... */ | ||
629 | if (pm->mode[0] & PORTMAN2X4_MODE_INPUT_TRIGGERED) | ||
630 | snd_rawmidi_receive(pm->midi_input[0], | ||
631 | &midivalue, 1); | ||
632 | |||
633 | } | ||
634 | /* If data available on channel 1, | ||
635 | read it and stuff it into the queue. */ | ||
636 | if (portman_data_avail(pm, 1)) { | ||
637 | /* Read Midi */ | ||
638 | midivalue = portman_read_midi(pm, 1); | ||
639 | /* put midi into queue... */ | ||
640 | if (pm->mode[1] & PORTMAN2X4_MODE_INPUT_TRIGGERED) | ||
641 | snd_rawmidi_receive(pm->midi_input[1], | ||
642 | &midivalue, 1); | ||
643 | } | ||
644 | |||
645 | } | ||
646 | |||
647 | spin_unlock(&pm->reg_lock); | ||
648 | } | ||
649 | |||
650 | static int __devinit snd_portman_probe_port(struct parport *p) | ||
651 | { | ||
652 | struct pardevice *pardev; | ||
653 | int res; | ||
654 | |||
655 | pardev = parport_register_device(p, DRIVER_NAME, | ||
656 | NULL, NULL, NULL, | ||
657 | 0, NULL); | ||
658 | if (!pardev) | ||
659 | return -EIO; | ||
660 | |||
661 | if (parport_claim(pardev)) { | ||
662 | parport_unregister_device(pardev); | ||
663 | return -EIO; | ||
664 | } | ||
665 | |||
666 | res = portman_probe(p); | ||
667 | |||
668 | parport_release(pardev); | ||
669 | parport_unregister_device(pardev); | ||
670 | |||
671 | return res; | ||
672 | } | ||
673 | |||
674 | static void __devinit snd_portman_attach(struct parport *p) | ||
675 | { | ||
676 | struct platform_device *device; | ||
677 | |||
678 | device = platform_device_alloc(PLATFORM_DRIVER, device_count); | ||
679 | if (!device) | ||
680 | return; | ||
681 | |||
682 | /* Temporary assignment to forward the parport */ | ||
683 | platform_set_drvdata(device, p); | ||
684 | |||
685 | if (platform_device_register(device) < 0) { | ||
686 | platform_device_put(device); | ||
687 | return; | ||
688 | } | ||
689 | |||
690 | /* Since we dont get the return value of probe | ||
691 | * We need to check if device probing succeeded or not */ | ||
692 | if (!platform_get_drvdata(device)) { | ||
693 | platform_device_unregister(device); | ||
694 | return; | ||
695 | } | ||
696 | |||
697 | /* register device in global table */ | ||
698 | platform_devices[device_count] = device; | ||
699 | device_count++; | ||
700 | } | ||
701 | |||
702 | static void snd_portman_detach(struct parport *p) | ||
703 | { | ||
704 | /* nothing to do here */ | ||
705 | } | ||
706 | |||
707 | static struct parport_driver portman_parport_driver = { | ||
708 | .name = "portman2x4", | ||
709 | .attach = snd_portman_attach, | ||
710 | .detach = snd_portman_detach | ||
711 | }; | ||
712 | |||
713 | /********************************************************************* | ||
714 | * platform stuff | ||
715 | *********************************************************************/ | ||
716 | static void snd_portman_card_private_free(struct snd_card *card) | ||
717 | { | ||
718 | struct portman *pm = card->private_data; | ||
719 | struct pardevice *pardev = pm->pardev; | ||
720 | |||
721 | if (pardev) { | ||
722 | if (pm->pardev_claimed) | ||
723 | parport_release(pardev); | ||
724 | parport_unregister_device(pardev); | ||
725 | } | ||
726 | |||
727 | portman_free(pm); | ||
728 | } | ||
729 | |||
730 | static int __devinit snd_portman_probe(struct platform_device *pdev) | ||
731 | { | ||
732 | struct pardevice *pardev; | ||
733 | struct parport *p; | ||
734 | int dev = pdev->id; | ||
735 | struct snd_card *card = NULL; | ||
736 | struct portman *pm = NULL; | ||
737 | int err; | ||
738 | |||
739 | p = platform_get_drvdata(pdev); | ||
740 | platform_set_drvdata(pdev, NULL); | ||
741 | |||
742 | if (dev >= SNDRV_CARDS) | ||
743 | return -ENODEV; | ||
744 | if (!enable[dev]) | ||
745 | return -ENOENT; | ||
746 | |||
747 | if ((err = snd_portman_probe_port(p)) < 0) | ||
748 | return err; | ||
749 | |||
750 | card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); | ||
751 | if (card == NULL) { | ||
752 | snd_printd("Cannot create card\n"); | ||
753 | return -ENOMEM; | ||
754 | } | ||
755 | strcpy(card->driver, DRIVER_NAME); | ||
756 | strcpy(card->shortname, CARD_NAME); | ||
757 | sprintf(card->longname, "%s at 0x%lx, irq %i", | ||
758 | card->shortname, p->base, p->irq); | ||
759 | |||
760 | pardev = parport_register_device(p, /* port */ | ||
761 | DRIVER_NAME, /* name */ | ||
762 | NULL, /* preempt */ | ||
763 | NULL, /* wakeup */ | ||
764 | snd_portman_interrupt, /* ISR */ | ||
765 | PARPORT_DEV_EXCL, /* flags */ | ||
766 | (void *)card); /* private */ | ||
767 | if (pardev == NULL) { | ||
768 | snd_printd("Cannot register pardevice\n"); | ||
769 | err = -EIO; | ||
770 | goto __err; | ||
771 | } | ||
772 | |||
773 | if ((err = portman_create(card, pardev, &pm)) < 0) { | ||
774 | snd_printd("Cannot create main component\n"); | ||
775 | parport_unregister_device(pardev); | ||
776 | goto __err; | ||
777 | } | ||
778 | card->private_data = pm; | ||
779 | card->private_free = snd_portman_card_private_free; | ||
780 | |||
781 | if ((err = snd_portman_rawmidi_create(card)) < 0) { | ||
782 | snd_printd("Creating Rawmidi component failed\n"); | ||
783 | goto __err; | ||
784 | } | ||
785 | |||
786 | /* claim parport */ | ||
787 | if (parport_claim(pardev)) { | ||
788 | snd_printd("Cannot claim parport 0x%lx\n", pardev->port->base); | ||
789 | err = -EIO; | ||
790 | goto __err; | ||
791 | } | ||
792 | pm->pardev_claimed = 1; | ||
793 | |||
794 | /* init device */ | ||
795 | if ((err = portman_device_init(pm)) < 0) | ||
796 | goto __err; | ||
797 | |||
798 | platform_set_drvdata(pdev, card); | ||
799 | |||
800 | /* At this point card will be usable */ | ||
801 | if ((err = snd_card_register(card)) < 0) { | ||
802 | snd_printd("Cannot register card\n"); | ||
803 | goto __err; | ||
804 | } | ||
805 | |||
806 | snd_printk(KERN_INFO "Portman 2x4 on 0x%lx\n", p->base); | ||
807 | return 0; | ||
808 | |||
809 | __err: | ||
810 | snd_card_free(card); | ||
811 | return err; | ||
812 | } | ||
813 | |||
814 | static int snd_portman_remove(struct platform_device *pdev) | ||
815 | { | ||
816 | struct snd_card *card = platform_get_drvdata(pdev); | ||
817 | |||
818 | if (card) | ||
819 | snd_card_free(card); | ||
820 | |||
821 | return 0; | ||
822 | } | ||
823 | |||
824 | |||
825 | static struct platform_driver snd_portman_driver = { | ||
826 | .probe = snd_portman_probe, | ||
827 | .remove = snd_portman_remove, | ||
828 | .driver = { | ||
829 | .name = PLATFORM_DRIVER | ||
830 | } | ||
831 | }; | ||
832 | |||
833 | /********************************************************************* | ||
834 | * module init stuff | ||
835 | *********************************************************************/ | ||
836 | static void snd_portman_unregister_all(void) | ||
837 | { | ||
838 | int i; | ||
839 | |||
840 | for (i = 0; i < SNDRV_CARDS; ++i) { | ||
841 | if (platform_devices[i]) { | ||
842 | platform_device_unregister(platform_devices[i]); | ||
843 | platform_devices[i] = NULL; | ||
844 | } | ||
845 | } | ||
846 | platform_driver_unregister(&snd_portman_driver); | ||
847 | parport_unregister_driver(&portman_parport_driver); | ||
848 | } | ||
849 | |||
850 | static int __init snd_portman_module_init(void) | ||
851 | { | ||
852 | int err; | ||
853 | |||
854 | if ((err = platform_driver_register(&snd_portman_driver)) < 0) | ||
855 | return err; | ||
856 | |||
857 | if (parport_register_driver(&portman_parport_driver) != 0) { | ||
858 | platform_driver_unregister(&snd_portman_driver); | ||
859 | return -EIO; | ||
860 | } | ||
861 | |||
862 | if (device_count == 0) { | ||
863 | snd_portman_unregister_all(); | ||
864 | return -ENODEV; | ||
865 | } | ||
866 | |||
867 | return 0; | ||
868 | } | ||
869 | |||
870 | static void __exit snd_portman_module_exit(void) | ||
871 | { | ||
872 | snd_portman_unregister_all(); | ||
873 | } | ||
874 | |||
875 | module_init(snd_portman_module_init); | ||
876 | module_exit(snd_portman_module_exit); | ||
diff --git a/sound/drivers/serial-u16550.c b/sound/drivers/serial-u16550.c index 74028b2219c2..3a86a5820726 100644 --- a/sound/drivers/serial-u16550.c +++ b/sound/drivers/serial-u16550.c | |||
@@ -117,13 +117,13 @@ MODULE_PARM_DESC(adaptor, "Type of adaptor."); | |||
117 | #define SERIAL_MODE_INPUT_TRIGGERED (1 << 2) | 117 | #define SERIAL_MODE_INPUT_TRIGGERED (1 << 2) |
118 | #define SERIAL_MODE_OUTPUT_TRIGGERED (1 << 3) | 118 | #define SERIAL_MODE_OUTPUT_TRIGGERED (1 << 3) |
119 | 119 | ||
120 | typedef struct _snd_uart16550 { | 120 | struct snd_uart16550 { |
121 | struct snd_card *card; | 121 | struct snd_card *card; |
122 | struct snd_rawmidi *rmidi; | 122 | struct snd_rawmidi *rmidi; |
123 | struct snd_rawmidi_substream *midi_output[SNDRV_SERIAL_MAX_OUTS]; | 123 | struct snd_rawmidi_substream *midi_output[SNDRV_SERIAL_MAX_OUTS]; |
124 | struct snd_rawmidi_substream *midi_input[SNDRV_SERIAL_MAX_INS]; | 124 | struct snd_rawmidi_substream *midi_input[SNDRV_SERIAL_MAX_INS]; |
125 | 125 | ||
126 | int filemode; //open status of file | 126 | int filemode; /* open status of file */ |
127 | 127 | ||
128 | spinlock_t open_lock; | 128 | spinlock_t open_lock; |
129 | 129 | ||
@@ -140,39 +140,39 @@ typedef struct _snd_uart16550 { | |||
140 | unsigned char old_divisor_msb; | 140 | unsigned char old_divisor_msb; |
141 | unsigned char old_line_ctrl_reg; | 141 | unsigned char old_line_ctrl_reg; |
142 | 142 | ||
143 | // parameter for using of write loop | 143 | /* parameter for using of write loop */ |
144 | short int fifo_limit; //used in uart16550 | 144 | short int fifo_limit; /* used in uart16550 */ |
145 | short int fifo_count; //used in uart16550 | 145 | short int fifo_count; /* used in uart16550 */ |
146 | 146 | ||
147 | // type of adaptor | 147 | /* type of adaptor */ |
148 | int adaptor; | 148 | int adaptor; |
149 | 149 | ||
150 | // inputs | 150 | /* inputs */ |
151 | int prev_in; | 151 | int prev_in; |
152 | unsigned char rstatus; | 152 | unsigned char rstatus; |
153 | 153 | ||
154 | // outputs | 154 | /* outputs */ |
155 | int prev_out; | 155 | int prev_out; |
156 | unsigned char prev_status[SNDRV_SERIAL_MAX_OUTS]; | 156 | unsigned char prev_status[SNDRV_SERIAL_MAX_OUTS]; |
157 | 157 | ||
158 | // write buffer and its writing/reading position | 158 | /* write buffer and its writing/reading position */ |
159 | unsigned char tx_buff[TX_BUFF_SIZE]; | 159 | unsigned char tx_buff[TX_BUFF_SIZE]; |
160 | int buff_in_count; | 160 | int buff_in_count; |
161 | int buff_in; | 161 | int buff_in; |
162 | int buff_out; | 162 | int buff_out; |
163 | int drop_on_full; | 163 | int drop_on_full; |
164 | 164 | ||
165 | // wait timer | 165 | /* wait timer */ |
166 | unsigned int timer_running:1; | 166 | unsigned int timer_running:1; |
167 | struct timer_list buffer_timer; | 167 | struct timer_list buffer_timer; |
168 | 168 | ||
169 | } snd_uart16550_t; | 169 | }; |
170 | 170 | ||
171 | static struct platform_device *devices[SNDRV_CARDS]; | 171 | static struct platform_device *devices[SNDRV_CARDS]; |
172 | 172 | ||
173 | static inline void snd_uart16550_add_timer(snd_uart16550_t *uart) | 173 | static inline void snd_uart16550_add_timer(struct snd_uart16550 *uart) |
174 | { | 174 | { |
175 | if (! uart->timer_running) { | 175 | if (!uart->timer_running) { |
176 | /* timer 38600bps * 10bit * 16byte */ | 176 | /* timer 38600bps * 10bit * 16byte */ |
177 | uart->buffer_timer.expires = jiffies + (HZ+255)/256; | 177 | uart->buffer_timer.expires = jiffies + (HZ+255)/256; |
178 | uart->timer_running = 1; | 178 | uart->timer_running = 1; |
@@ -180,7 +180,7 @@ static inline void snd_uart16550_add_timer(snd_uart16550_t *uart) | |||
180 | } | 180 | } |
181 | } | 181 | } |
182 | 182 | ||
183 | static inline void snd_uart16550_del_timer(snd_uart16550_t *uart) | 183 | static inline void snd_uart16550_del_timer(struct snd_uart16550 *uart) |
184 | { | 184 | { |
185 | if (uart->timer_running) { | 185 | if (uart->timer_running) { |
186 | del_timer(&uart->buffer_timer); | 186 | del_timer(&uart->buffer_timer); |
@@ -189,10 +189,10 @@ static inline void snd_uart16550_del_timer(snd_uart16550_t *uart) | |||
189 | } | 189 | } |
190 | 190 | ||
191 | /* This macro is only used in snd_uart16550_io_loop */ | 191 | /* This macro is only used in snd_uart16550_io_loop */ |
192 | static inline void snd_uart16550_buffer_output(snd_uart16550_t *uart) | 192 | static inline void snd_uart16550_buffer_output(struct snd_uart16550 *uart) |
193 | { | 193 | { |
194 | unsigned short buff_out = uart->buff_out; | 194 | unsigned short buff_out = uart->buff_out; |
195 | if( uart->buff_in_count > 0 ) { | 195 | if (uart->buff_in_count > 0) { |
196 | outb(uart->tx_buff[buff_out], uart->base + UART_TX); | 196 | outb(uart->tx_buff[buff_out], uart->base + UART_TX); |
197 | uart->fifo_count++; | 197 | uart->fifo_count++; |
198 | buff_out++; | 198 | buff_out++; |
@@ -206,7 +206,7 @@ static inline void snd_uart16550_buffer_output(snd_uart16550_t *uart) | |||
206 | * We don't want to interrupt this, | 206 | * We don't want to interrupt this, |
207 | * as we're already handling an interrupt | 207 | * as we're already handling an interrupt |
208 | */ | 208 | */ |
209 | static void snd_uart16550_io_loop(snd_uart16550_t * uart) | 209 | static void snd_uart16550_io_loop(struct snd_uart16550 * uart) |
210 | { | 210 | { |
211 | unsigned char c, status; | 211 | unsigned char c, status; |
212 | int substream; | 212 | int substream; |
@@ -220,9 +220,8 @@ static void snd_uart16550_io_loop(snd_uart16550_t * uart) | |||
220 | c = inb(uart->base + UART_RX); | 220 | c = inb(uart->base + UART_RX); |
221 | 221 | ||
222 | /* keep track of last status byte */ | 222 | /* keep track of last status byte */ |
223 | if (c & 0x80) { | 223 | if (c & 0x80) |
224 | uart->rstatus = c; | 224 | uart->rstatus = c; |
225 | } | ||
226 | 225 | ||
227 | /* handle stream switch */ | 226 | /* handle stream switch */ |
228 | if (uart->adaptor == SNDRV_SERIAL_GENERIC) { | 227 | if (uart->adaptor == SNDRV_SERIAL_GENERIC) { |
@@ -230,14 +229,16 @@ static void snd_uart16550_io_loop(snd_uart16550_t * uart) | |||
230 | if (c <= SNDRV_SERIAL_MAX_INS && c > 0) | 229 | if (c <= SNDRV_SERIAL_MAX_INS && c > 0) |
231 | substream = c - 1; | 230 | substream = c - 1; |
232 | if (c != 0xf5) | 231 | if (c != 0xf5) |
233 | uart->rstatus = 0; /* prevent future bytes from being interpreted as streams */ | 232 | /* prevent future bytes from being |
234 | } | 233 | interpreted as streams */ |
235 | else if ((uart->filemode & SERIAL_MODE_INPUT_OPEN) && (uart->midi_input[substream] != NULL)) { | 234 | uart->rstatus = 0; |
236 | snd_rawmidi_receive(uart->midi_input[substream], &c, 1); | 235 | } else if ((uart->filemode & SERIAL_MODE_INPUT_OPEN) |
237 | } | 236 | && uart->midi_input[substream]) |
238 | } else if ((uart->filemode & SERIAL_MODE_INPUT_OPEN) && (uart->midi_input[substream] != NULL)) { | 237 | snd_rawmidi_receive(uart->midi_input[substream], |
238 | &c, 1); | ||
239 | } else if ((uart->filemode & SERIAL_MODE_INPUT_OPEN) && | ||
240 | uart->midi_input[substream]) | ||
239 | snd_rawmidi_receive(uart->midi_input[substream], &c, 1); | 241 | snd_rawmidi_receive(uart->midi_input[substream], &c, 1); |
240 | } | ||
241 | 242 | ||
242 | if (status & UART_LSR_OE) | 243 | if (status & UART_LSR_OE) |
243 | snd_printk("%s: Overrun on device at 0x%lx\n", | 244 | snd_printk("%s: Overrun on device at 0x%lx\n", |
@@ -250,21 +251,20 @@ static void snd_uart16550_io_loop(snd_uart16550_t * uart) | |||
250 | /* no need of check SERIAL_MODE_OUTPUT_OPEN because if not, | 251 | /* no need of check SERIAL_MODE_OUTPUT_OPEN because if not, |
251 | buffer is never filled. */ | 252 | buffer is never filled. */ |
252 | /* Check write status */ | 253 | /* Check write status */ |
253 | if (status & UART_LSR_THRE) { | 254 | if (status & UART_LSR_THRE) |
254 | uart->fifo_count = 0; | 255 | uart->fifo_count = 0; |
255 | } | ||
256 | if (uart->adaptor == SNDRV_SERIAL_MS124W_SA | 256 | if (uart->adaptor == SNDRV_SERIAL_MS124W_SA |
257 | || uart->adaptor == SNDRV_SERIAL_GENERIC) { | 257 | || uart->adaptor == SNDRV_SERIAL_GENERIC) { |
258 | /* Can't use FIFO, must send only when CTS is true */ | 258 | /* Can't use FIFO, must send only when CTS is true */ |
259 | status = inb(uart->base + UART_MSR); | 259 | status = inb(uart->base + UART_MSR); |
260 | while( (uart->fifo_count == 0) && (status & UART_MSR_CTS) && | 260 | while (uart->fifo_count == 0 && (status & UART_MSR_CTS) && |
261 | (uart->buff_in_count > 0) ) { | 261 | uart->buff_in_count > 0) { |
262 | snd_uart16550_buffer_output(uart); | 262 | snd_uart16550_buffer_output(uart); |
263 | status = inb( uart->base + UART_MSR ); | 263 | status = inb(uart->base + UART_MSR); |
264 | } | 264 | } |
265 | } else { | 265 | } else { |
266 | /* Write loop */ | 266 | /* Write loop */ |
267 | while (uart->fifo_count < uart->fifo_limit /* Can we write ? */ | 267 | while (uart->fifo_count < uart->fifo_limit /* Can we write ? */ |
268 | && uart->buff_in_count > 0) /* Do we want to? */ | 268 | && uart->buff_in_count > 0) /* Do we want to? */ |
269 | snd_uart16550_buffer_output(uart); | 269 | snd_uart16550_buffer_output(uart); |
270 | } | 270 | } |
@@ -294,15 +294,16 @@ static void snd_uart16550_io_loop(snd_uart16550_t * uart) | |||
294 | */ | 294 | */ |
295 | static irqreturn_t snd_uart16550_interrupt(int irq, void *dev_id) | 295 | static irqreturn_t snd_uart16550_interrupt(int irq, void *dev_id) |
296 | { | 296 | { |
297 | snd_uart16550_t *uart; | 297 | struct snd_uart16550 *uart; |
298 | 298 | ||
299 | uart = (snd_uart16550_t *) dev_id; | 299 | uart = dev_id; |
300 | spin_lock(&uart->open_lock); | 300 | spin_lock(&uart->open_lock); |
301 | if (uart->filemode == SERIAL_MODE_NOT_OPENED) { | 301 | if (uart->filemode == SERIAL_MODE_NOT_OPENED) { |
302 | spin_unlock(&uart->open_lock); | 302 | spin_unlock(&uart->open_lock); |
303 | return IRQ_NONE; | 303 | return IRQ_NONE; |
304 | } | 304 | } |
305 | inb(uart->base + UART_IIR); /* indicate to the UART that the interrupt has been serviced */ | 305 | /* indicate to the UART that the interrupt has been serviced */ |
306 | inb(uart->base + UART_IIR); | ||
306 | snd_uart16550_io_loop(uart); | 307 | snd_uart16550_io_loop(uart); |
307 | spin_unlock(&uart->open_lock); | 308 | spin_unlock(&uart->open_lock); |
308 | return IRQ_HANDLED; | 309 | return IRQ_HANDLED; |
@@ -312,9 +313,9 @@ static irqreturn_t snd_uart16550_interrupt(int irq, void *dev_id) | |||
312 | static void snd_uart16550_buffer_timer(unsigned long data) | 313 | static void snd_uart16550_buffer_timer(unsigned long data) |
313 | { | 314 | { |
314 | unsigned long flags; | 315 | unsigned long flags; |
315 | snd_uart16550_t *uart; | 316 | struct snd_uart16550 *uart; |
316 | 317 | ||
317 | uart = (snd_uart16550_t *)data; | 318 | uart = (struct snd_uart16550 *)data; |
318 | spin_lock_irqsave(&uart->open_lock, flags); | 319 | spin_lock_irqsave(&uart->open_lock, flags); |
319 | snd_uart16550_del_timer(uart); | 320 | snd_uart16550_del_timer(uart); |
320 | snd_uart16550_io_loop(uart); | 321 | snd_uart16550_io_loop(uart); |
@@ -326,7 +327,7 @@ static void snd_uart16550_buffer_timer(unsigned long data) | |||
326 | * return 0 if found | 327 | * return 0 if found |
327 | * return negative error if not found | 328 | * return negative error if not found |
328 | */ | 329 | */ |
329 | static int __init snd_uart16550_detect(snd_uart16550_t *uart) | 330 | static int __init snd_uart16550_detect(struct snd_uart16550 *uart) |
330 | { | 331 | { |
331 | unsigned long io_base = uart->base; | 332 | unsigned long io_base = uart->base; |
332 | int ok; | 333 | int ok; |
@@ -343,7 +344,8 @@ static int __init snd_uart16550_detect(snd_uart16550_t *uart) | |||
343 | return -EBUSY; | 344 | return -EBUSY; |
344 | } | 345 | } |
345 | 346 | ||
346 | ok = 1; /* uart detected unless one of the following tests should fail */ | 347 | /* uart detected unless one of the following tests should fail */ |
348 | ok = 1; | ||
347 | /* 8 data-bits, 1 stop-bit, parity off, DLAB = 0 */ | 349 | /* 8 data-bits, 1 stop-bit, parity off, DLAB = 0 */ |
348 | outb(UART_LCR_WLEN8, io_base + UART_LCR); /* Line Control Register */ | 350 | outb(UART_LCR_WLEN8, io_base + UART_LCR); /* Line Control Register */ |
349 | c = inb(io_base + UART_IER); | 351 | c = inb(io_base + UART_IER); |
@@ -368,7 +370,7 @@ static int __init snd_uart16550_detect(snd_uart16550_t *uart) | |||
368 | return ok; | 370 | return ok; |
369 | } | 371 | } |
370 | 372 | ||
371 | static void snd_uart16550_do_open(snd_uart16550_t * uart) | 373 | static void snd_uart16550_do_open(struct snd_uart16550 * uart) |
372 | { | 374 | { |
373 | char byte; | 375 | char byte; |
374 | 376 | ||
@@ -460,7 +462,7 @@ static void snd_uart16550_do_open(snd_uart16550_t * uart) | |||
460 | inb(uart->base + UART_RX); /* Clear any pre-existing receive interrupt */ | 462 | inb(uart->base + UART_RX); /* Clear any pre-existing receive interrupt */ |
461 | } | 463 | } |
462 | 464 | ||
463 | static void snd_uart16550_do_close(snd_uart16550_t * uart) | 465 | static void snd_uart16550_do_close(struct snd_uart16550 * uart) |
464 | { | 466 | { |
465 | if (uart->irq < 0) | 467 | if (uart->irq < 0) |
466 | snd_uart16550_del_timer(uart); | 468 | snd_uart16550_del_timer(uart); |
@@ -514,7 +516,7 @@ static void snd_uart16550_do_close(snd_uart16550_t * uart) | |||
514 | static int snd_uart16550_input_open(struct snd_rawmidi_substream *substream) | 516 | static int snd_uart16550_input_open(struct snd_rawmidi_substream *substream) |
515 | { | 517 | { |
516 | unsigned long flags; | 518 | unsigned long flags; |
517 | snd_uart16550_t *uart = substream->rmidi->private_data; | 519 | struct snd_uart16550 *uart = substream->rmidi->private_data; |
518 | 520 | ||
519 | spin_lock_irqsave(&uart->open_lock, flags); | 521 | spin_lock_irqsave(&uart->open_lock, flags); |
520 | if (uart->filemode == SERIAL_MODE_NOT_OPENED) | 522 | if (uart->filemode == SERIAL_MODE_NOT_OPENED) |
@@ -528,7 +530,7 @@ static int snd_uart16550_input_open(struct snd_rawmidi_substream *substream) | |||
528 | static int snd_uart16550_input_close(struct snd_rawmidi_substream *substream) | 530 | static int snd_uart16550_input_close(struct snd_rawmidi_substream *substream) |
529 | { | 531 | { |
530 | unsigned long flags; | 532 | unsigned long flags; |
531 | snd_uart16550_t *uart = substream->rmidi->private_data; | 533 | struct snd_uart16550 *uart = substream->rmidi->private_data; |
532 | 534 | ||
533 | spin_lock_irqsave(&uart->open_lock, flags); | 535 | spin_lock_irqsave(&uart->open_lock, flags); |
534 | uart->filemode &= ~SERIAL_MODE_INPUT_OPEN; | 536 | uart->filemode &= ~SERIAL_MODE_INPUT_OPEN; |
@@ -539,24 +541,24 @@ static int snd_uart16550_input_close(struct snd_rawmidi_substream *substream) | |||
539 | return 0; | 541 | return 0; |
540 | } | 542 | } |
541 | 543 | ||
542 | static void snd_uart16550_input_trigger(struct snd_rawmidi_substream *substream, int up) | 544 | static void snd_uart16550_input_trigger(struct snd_rawmidi_substream *substream, |
545 | int up) | ||
543 | { | 546 | { |
544 | unsigned long flags; | 547 | unsigned long flags; |
545 | snd_uart16550_t *uart = substream->rmidi->private_data; | 548 | struct snd_uart16550 *uart = substream->rmidi->private_data; |
546 | 549 | ||
547 | spin_lock_irqsave(&uart->open_lock, flags); | 550 | spin_lock_irqsave(&uart->open_lock, flags); |
548 | if (up) { | 551 | if (up) |
549 | uart->filemode |= SERIAL_MODE_INPUT_TRIGGERED; | 552 | uart->filemode |= SERIAL_MODE_INPUT_TRIGGERED; |
550 | } else { | 553 | else |
551 | uart->filemode &= ~SERIAL_MODE_INPUT_TRIGGERED; | 554 | uart->filemode &= ~SERIAL_MODE_INPUT_TRIGGERED; |
552 | } | ||
553 | spin_unlock_irqrestore(&uart->open_lock, flags); | 555 | spin_unlock_irqrestore(&uart->open_lock, flags); |
554 | } | 556 | } |
555 | 557 | ||
556 | static int snd_uart16550_output_open(struct snd_rawmidi_substream *substream) | 558 | static int snd_uart16550_output_open(struct snd_rawmidi_substream *substream) |
557 | { | 559 | { |
558 | unsigned long flags; | 560 | unsigned long flags; |
559 | snd_uart16550_t *uart = substream->rmidi->private_data; | 561 | struct snd_uart16550 *uart = substream->rmidi->private_data; |
560 | 562 | ||
561 | spin_lock_irqsave(&uart->open_lock, flags); | 563 | spin_lock_irqsave(&uart->open_lock, flags); |
562 | if (uart->filemode == SERIAL_MODE_NOT_OPENED) | 564 | if (uart->filemode == SERIAL_MODE_NOT_OPENED) |
@@ -570,7 +572,7 @@ static int snd_uart16550_output_open(struct snd_rawmidi_substream *substream) | |||
570 | static int snd_uart16550_output_close(struct snd_rawmidi_substream *substream) | 572 | static int snd_uart16550_output_close(struct snd_rawmidi_substream *substream) |
571 | { | 573 | { |
572 | unsigned long flags; | 574 | unsigned long flags; |
573 | snd_uart16550_t *uart = substream->rmidi->private_data; | 575 | struct snd_uart16550 *uart = substream->rmidi->private_data; |
574 | 576 | ||
575 | spin_lock_irqsave(&uart->open_lock, flags); | 577 | spin_lock_irqsave(&uart->open_lock, flags); |
576 | uart->filemode &= ~SERIAL_MODE_OUTPUT_OPEN; | 578 | uart->filemode &= ~SERIAL_MODE_OUTPUT_OPEN; |
@@ -581,18 +583,20 @@ static int snd_uart16550_output_close(struct snd_rawmidi_substream *substream) | |||
581 | return 0; | 583 | return 0; |
582 | }; | 584 | }; |
583 | 585 | ||
584 | static inline int snd_uart16550_buffer_can_write( snd_uart16550_t *uart, int Num ) | 586 | static inline int snd_uart16550_buffer_can_write(struct snd_uart16550 *uart, |
587 | int Num) | ||
585 | { | 588 | { |
586 | if( uart->buff_in_count + Num < TX_BUFF_SIZE ) | 589 | if (uart->buff_in_count + Num < TX_BUFF_SIZE) |
587 | return 1; | 590 | return 1; |
588 | else | 591 | else |
589 | return 0; | 592 | return 0; |
590 | } | 593 | } |
591 | 594 | ||
592 | static inline int snd_uart16550_write_buffer(snd_uart16550_t *uart, unsigned char byte) | 595 | static inline int snd_uart16550_write_buffer(struct snd_uart16550 *uart, |
596 | unsigned char byte) | ||
593 | { | 597 | { |
594 | unsigned short buff_in = uart->buff_in; | 598 | unsigned short buff_in = uart->buff_in; |
595 | if( uart->buff_in_count < TX_BUFF_SIZE ) { | 599 | if (uart->buff_in_count < TX_BUFF_SIZE) { |
596 | uart->tx_buff[buff_in] = byte; | 600 | uart->tx_buff[buff_in] = byte; |
597 | buff_in++; | 601 | buff_in++; |
598 | buff_in &= TX_BUFF_MASK; | 602 | buff_in &= TX_BUFF_MASK; |
@@ -605,12 +609,14 @@ static inline int snd_uart16550_write_buffer(snd_uart16550_t *uart, unsigned cha | |||
605 | return 0; | 609 | return 0; |
606 | } | 610 | } |
607 | 611 | ||
608 | static int snd_uart16550_output_byte(snd_uart16550_t *uart, struct snd_rawmidi_substream *substream, unsigned char midi_byte) | 612 | static int snd_uart16550_output_byte(struct snd_uart16550 *uart, |
613 | struct snd_rawmidi_substream *substream, | ||
614 | unsigned char midi_byte) | ||
609 | { | 615 | { |
610 | if (uart->buff_in_count == 0 /* Buffer empty? */ | 616 | if (uart->buff_in_count == 0 /* Buffer empty? */ |
611 | && ((uart->adaptor != SNDRV_SERIAL_MS124W_SA && | 617 | && ((uart->adaptor != SNDRV_SERIAL_MS124W_SA && |
612 | uart->adaptor != SNDRV_SERIAL_GENERIC) || | 618 | uart->adaptor != SNDRV_SERIAL_GENERIC) || |
613 | (uart->fifo_count == 0 /* FIFO empty? */ | 619 | (uart->fifo_count == 0 /* FIFO empty? */ |
614 | && (inb(uart->base + UART_MSR) & UART_MSR_CTS)))) { /* CTS? */ | 620 | && (inb(uart->base + UART_MSR) & UART_MSR_CTS)))) { /* CTS? */ |
615 | 621 | ||
616 | /* Tx Buffer Empty - try to write immediately */ | 622 | /* Tx Buffer Empty - try to write immediately */ |
@@ -623,12 +629,13 @@ static int snd_uart16550_output_byte(snd_uart16550_t *uart, struct snd_rawmidi_s | |||
623 | uart->fifo_count++; | 629 | uart->fifo_count++; |
624 | outb(midi_byte, uart->base + UART_TX); | 630 | outb(midi_byte, uart->base + UART_TX); |
625 | } else { | 631 | } else { |
626 | /* Cannot write (buffer empty) - put char in buffer */ | 632 | /* Cannot write (buffer empty) - |
633 | * put char in buffer */ | ||
627 | snd_uart16550_write_buffer(uart, midi_byte); | 634 | snd_uart16550_write_buffer(uart, midi_byte); |
628 | } | 635 | } |
629 | } | 636 | } |
630 | } else { | 637 | } else { |
631 | if( !snd_uart16550_write_buffer(uart, midi_byte) ) { | 638 | if (!snd_uart16550_write_buffer(uart, midi_byte)) { |
632 | snd_printk("%s: Buffer overrun on device at 0x%lx\n", | 639 | snd_printk("%s: Buffer overrun on device at 0x%lx\n", |
633 | uart->rmidi->name, uart->base); | 640 | uart->rmidi->name, uart->base); |
634 | return 0; | 641 | return 0; |
@@ -642,9 +649,9 @@ static void snd_uart16550_output_write(struct snd_rawmidi_substream *substream) | |||
642 | { | 649 | { |
643 | unsigned long flags; | 650 | unsigned long flags; |
644 | unsigned char midi_byte, addr_byte; | 651 | unsigned char midi_byte, addr_byte; |
645 | snd_uart16550_t *uart = substream->rmidi->private_data; | 652 | struct snd_uart16550 *uart = substream->rmidi->private_data; |
646 | char first; | 653 | char first; |
647 | static unsigned long lasttime=0; | 654 | static unsigned long lasttime = 0; |
648 | 655 | ||
649 | /* Interupts are disabled during the updating of the tx_buff, | 656 | /* Interupts are disabled during the updating of the tx_buff, |
650 | * since it is 'bad' to have two processes updating the same | 657 | * since it is 'bad' to have two processes updating the same |
@@ -653,7 +660,7 @@ static void snd_uart16550_output_write(struct snd_rawmidi_substream *substream) | |||
653 | 660 | ||
654 | spin_lock_irqsave(&uart->open_lock, flags); | 661 | spin_lock_irqsave(&uart->open_lock, flags); |
655 | 662 | ||
656 | if (uart->irq < 0) //polling | 663 | if (uart->irq < 0) /* polling */ |
657 | snd_uart16550_io_loop(uart); | 664 | snd_uart16550_io_loop(uart); |
658 | 665 | ||
659 | if (uart->adaptor == SNDRV_SERIAL_MS124W_MB) { | 666 | if (uart->adaptor == SNDRV_SERIAL_MS124W_MB) { |
@@ -671,7 +678,8 @@ static void snd_uart16550_output_write(struct snd_rawmidi_substream *substream) | |||
671 | /* select any combination of the four ports */ | 678 | /* select any combination of the four ports */ |
672 | addr_byte = (substream->number << 4) | 0x08; | 679 | addr_byte = (substream->number << 4) | 0x08; |
673 | /* ...except none */ | 680 | /* ...except none */ |
674 | if (addr_byte == 0x08) addr_byte = 0xf8; | 681 | if (addr_byte == 0x08) |
682 | addr_byte = 0xf8; | ||
675 | #endif | 683 | #endif |
676 | snd_uart16550_output_byte(uart, substream, addr_byte); | 684 | snd_uart16550_output_byte(uart, substream, addr_byte); |
677 | /* send midi byte */ | 685 | /* send midi byte */ |
@@ -679,31 +687,42 @@ static void snd_uart16550_output_write(struct snd_rawmidi_substream *substream) | |||
679 | } | 687 | } |
680 | } else { | 688 | } else { |
681 | first = 0; | 689 | first = 0; |
682 | while( 1 == snd_rawmidi_transmit_peek(substream, &midi_byte, 1) ) { | 690 | while (snd_rawmidi_transmit_peek(substream, &midi_byte, 1) == 1) { |
683 | /* Also send F5 after 3 seconds with no data to handle device disconnect */ | 691 | /* Also send F5 after 3 seconds with no data |
684 | if (first == 0 && (uart->adaptor == SNDRV_SERIAL_SOUNDCANVAS || | 692 | * to handle device disconnect */ |
685 | uart->adaptor == SNDRV_SERIAL_GENERIC) && | 693 | if (first == 0 && |
686 | (uart->prev_out != substream->number || jiffies-lasttime > 3*HZ)) { | 694 | (uart->adaptor == SNDRV_SERIAL_SOUNDCANVAS || |
687 | 695 | uart->adaptor == SNDRV_SERIAL_GENERIC) && | |
688 | if( snd_uart16550_buffer_can_write( uart, 3 ) ) { | 696 | (uart->prev_out != substream->number || |
697 | jiffies-lasttime > 3*HZ)) { | ||
698 | |||
699 | if (snd_uart16550_buffer_can_write(uart, 3)) { | ||
689 | /* Roland Soundcanvas part selection */ | 700 | /* Roland Soundcanvas part selection */ |
690 | /* If this substream of the data is different previous | 701 | /* If this substream of the data is |
691 | substream in this uart, send the change part event */ | 702 | * different previous substream |
703 | * in this uart, send the change part | ||
704 | * event | ||
705 | */ | ||
692 | uart->prev_out = substream->number; | 706 | uart->prev_out = substream->number; |
693 | /* change part */ | 707 | /* change part */ |
694 | snd_uart16550_output_byte(uart, substream, 0xf5); | 708 | snd_uart16550_output_byte(uart, substream, |
709 | 0xf5); | ||
695 | /* data */ | 710 | /* data */ |
696 | snd_uart16550_output_byte(uart, substream, uart->prev_out + 1); | 711 | snd_uart16550_output_byte(uart, substream, |
697 | /* If midi_byte is a data byte, send the previous status byte */ | 712 | uart->prev_out + 1); |
698 | if ((midi_byte < 0x80) && (uart->adaptor == SNDRV_SERIAL_SOUNDCANVAS)) | 713 | /* If midi_byte is a data byte, |
714 | * send the previous status byte */ | ||
715 | if (midi_byte < 0x80 && | ||
716 | uart->adaptor == SNDRV_SERIAL_SOUNDCANVAS) | ||
699 | snd_uart16550_output_byte(uart, substream, uart->prev_status[uart->prev_out]); | 717 | snd_uart16550_output_byte(uart, substream, uart->prev_status[uart->prev_out]); |
700 | } else if( !uart->drop_on_full ) | 718 | } else if (!uart->drop_on_full) |
701 | break; | 719 | break; |
702 | 720 | ||
703 | } | 721 | } |
704 | 722 | ||
705 | /* send midi byte */ | 723 | /* send midi byte */ |
706 | if( !snd_uart16550_output_byte(uart, substream, midi_byte) && !uart->drop_on_full ) | 724 | if (!snd_uart16550_output_byte(uart, substream, midi_byte) && |
725 | !uart->drop_on_full ) | ||
707 | break; | 726 | break; |
708 | 727 | ||
709 | if (midi_byte >= 0x80 && midi_byte < 0xf0) | 728 | if (midi_byte >= 0x80 && midi_byte < 0xf0) |
@@ -717,17 +736,17 @@ static void snd_uart16550_output_write(struct snd_rawmidi_substream *substream) | |||
717 | spin_unlock_irqrestore(&uart->open_lock, flags); | 736 | spin_unlock_irqrestore(&uart->open_lock, flags); |
718 | } | 737 | } |
719 | 738 | ||
720 | static void snd_uart16550_output_trigger(struct snd_rawmidi_substream *substream, int up) | 739 | static void snd_uart16550_output_trigger(struct snd_rawmidi_substream *substream, |
740 | int up) | ||
721 | { | 741 | { |
722 | unsigned long flags; | 742 | unsigned long flags; |
723 | snd_uart16550_t *uart = substream->rmidi->private_data; | 743 | struct snd_uart16550 *uart = substream->rmidi->private_data; |
724 | 744 | ||
725 | spin_lock_irqsave(&uart->open_lock, flags); | 745 | spin_lock_irqsave(&uart->open_lock, flags); |
726 | if (up) { | 746 | if (up) |
727 | uart->filemode |= SERIAL_MODE_OUTPUT_TRIGGERED; | 747 | uart->filemode |= SERIAL_MODE_OUTPUT_TRIGGERED; |
728 | } else { | 748 | else |
729 | uart->filemode &= ~SERIAL_MODE_OUTPUT_TRIGGERED; | 749 | uart->filemode &= ~SERIAL_MODE_OUTPUT_TRIGGERED; |
730 | } | ||
731 | spin_unlock_irqrestore(&uart->open_lock, flags); | 750 | spin_unlock_irqrestore(&uart->open_lock, flags); |
732 | if (up) | 751 | if (up) |
733 | snd_uart16550_output_write(substream); | 752 | snd_uart16550_output_write(substream); |
@@ -747,10 +766,10 @@ static struct snd_rawmidi_ops snd_uart16550_input = | |||
747 | .trigger = snd_uart16550_input_trigger, | 766 | .trigger = snd_uart16550_input_trigger, |
748 | }; | 767 | }; |
749 | 768 | ||
750 | static int snd_uart16550_free(snd_uart16550_t *uart) | 769 | static int snd_uart16550_free(struct snd_uart16550 *uart) |
751 | { | 770 | { |
752 | if (uart->irq >= 0) | 771 | if (uart->irq >= 0) |
753 | free_irq(uart->irq, (void *)uart); | 772 | free_irq(uart->irq, uart); |
754 | release_and_free_resource(uart->res_base); | 773 | release_and_free_resource(uart->res_base); |
755 | kfree(uart); | 774 | kfree(uart); |
756 | return 0; | 775 | return 0; |
@@ -758,7 +777,7 @@ static int snd_uart16550_free(snd_uart16550_t *uart) | |||
758 | 777 | ||
759 | static int snd_uart16550_dev_free(struct snd_device *device) | 778 | static int snd_uart16550_dev_free(struct snd_device *device) |
760 | { | 779 | { |
761 | snd_uart16550_t *uart = device->device_data; | 780 | struct snd_uart16550 *uart = device->device_data; |
762 | return snd_uart16550_free(uart); | 781 | return snd_uart16550_free(uart); |
763 | } | 782 | } |
764 | 783 | ||
@@ -769,12 +788,12 @@ static int __init snd_uart16550_create(struct snd_card *card, | |||
769 | unsigned int base, | 788 | unsigned int base, |
770 | int adaptor, | 789 | int adaptor, |
771 | int droponfull, | 790 | int droponfull, |
772 | snd_uart16550_t **ruart) | 791 | struct snd_uart16550 **ruart) |
773 | { | 792 | { |
774 | static struct snd_device_ops ops = { | 793 | static struct snd_device_ops ops = { |
775 | .dev_free = snd_uart16550_dev_free, | 794 | .dev_free = snd_uart16550_dev_free, |
776 | }; | 795 | }; |
777 | snd_uart16550_t *uart; | 796 | struct snd_uart16550 *uart; |
778 | int err; | 797 | int err; |
779 | 798 | ||
780 | 799 | ||
@@ -795,7 +814,7 @@ static int __init snd_uart16550_create(struct snd_card *card, | |||
795 | 814 | ||
796 | if (irq >= 0 && irq != SNDRV_AUTO_IRQ) { | 815 | if (irq >= 0 && irq != SNDRV_AUTO_IRQ) { |
797 | if (request_irq(irq, snd_uart16550_interrupt, | 816 | if (request_irq(irq, snd_uart16550_interrupt, |
798 | IRQF_DISABLED, "Serial MIDI", (void *) uart)) { | 817 | IRQF_DISABLED, "Serial MIDI", uart)) { |
799 | snd_printk("irq %d busy. Using Polling.\n", irq); | 818 | snd_printk("irq %d busy. Using Polling.\n", irq); |
800 | } else { | 819 | } else { |
801 | uart->irq = irq; | 820 | uart->irq = irq; |
@@ -843,23 +862,28 @@ static int __init snd_uart16550_create(struct snd_card *card, | |||
843 | 862 | ||
844 | static void __init snd_uart16550_substreams(struct snd_rawmidi_str *stream) | 863 | static void __init snd_uart16550_substreams(struct snd_rawmidi_str *stream) |
845 | { | 864 | { |
846 | struct list_head *list; | 865 | struct snd_rawmidi_substream *substream; |
847 | 866 | ||
848 | list_for_each(list, &stream->substreams) { | 867 | list_for_each_entry(substream, &stream->substreams, list) { |
849 | struct snd_rawmidi_substream *substream = list_entry(list, struct snd_rawmidi_substream, list); | ||
850 | sprintf(substream->name, "Serial MIDI %d", substream->number + 1); | 868 | sprintf(substream->name, "Serial MIDI %d", substream->number + 1); |
851 | } | 869 | } |
852 | } | 870 | } |
853 | 871 | ||
854 | static int __init snd_uart16550_rmidi(snd_uart16550_t *uart, int device, int outs, int ins, struct snd_rawmidi **rmidi) | 872 | static int __init snd_uart16550_rmidi(struct snd_uart16550 *uart, int device, |
873 | int outs, int ins, | ||
874 | struct snd_rawmidi **rmidi) | ||
855 | { | 875 | { |
856 | struct snd_rawmidi *rrawmidi; | 876 | struct snd_rawmidi *rrawmidi; |
857 | int err; | 877 | int err; |
858 | 878 | ||
859 | if ((err = snd_rawmidi_new(uart->card, "UART Serial MIDI", device, outs, ins, &rrawmidi)) < 0) | 879 | err = snd_rawmidi_new(uart->card, "UART Serial MIDI", device, |
880 | outs, ins, &rrawmidi); | ||
881 | if (err < 0) | ||
860 | return err; | 882 | return err; |
861 | snd_rawmidi_set_ops(rrawmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_uart16550_input); | 883 | snd_rawmidi_set_ops(rrawmidi, SNDRV_RAWMIDI_STREAM_INPUT, |
862 | snd_rawmidi_set_ops(rrawmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_uart16550_output); | 884 | &snd_uart16550_input); |
885 | snd_rawmidi_set_ops(rrawmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, | ||
886 | &snd_uart16550_output); | ||
863 | strcpy(rrawmidi->name, "Serial MIDI"); | 887 | strcpy(rrawmidi->name, "Serial MIDI"); |
864 | snd_uart16550_substreams(&rrawmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]); | 888 | snd_uart16550_substreams(&rrawmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]); |
865 | snd_uart16550_substreams(&rrawmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT]); | 889 | snd_uart16550_substreams(&rrawmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT]); |
@@ -875,7 +899,7 @@ static int __init snd_uart16550_rmidi(snd_uart16550_t *uart, int device, int out | |||
875 | static int __init snd_serial_probe(struct platform_device *devptr) | 899 | static int __init snd_serial_probe(struct platform_device *devptr) |
876 | { | 900 | { |
877 | struct snd_card *card; | 901 | struct snd_card *card; |
878 | snd_uart16550_t *uart; | 902 | struct snd_uart16550 *uart; |
879 | int err; | 903 | int err; |
880 | int dev = devptr->id; | 904 | int dev = devptr->id; |
881 | 905 | ||
@@ -929,7 +953,8 @@ static int __init snd_serial_probe(struct platform_device *devptr) | |||
929 | &uart)) < 0) | 953 | &uart)) < 0) |
930 | goto _err; | 954 | goto _err; |
931 | 955 | ||
932 | if ((err = snd_uart16550_rmidi(uart, 0, outs[dev], ins[dev], &uart->rmidi)) < 0) | 956 | err = snd_uart16550_rmidi(uart, 0, outs[dev], ins[dev], &uart->rmidi); |
957 | if (err < 0) | ||
933 | goto _err; | 958 | goto _err; |
934 | 959 | ||
935 | sprintf(card->longname, "%s at 0x%lx, irq %d speed %d div %d outs %d ins %d adaptor %s droponfull %d", | 960 | sprintf(card->longname, "%s at 0x%lx, irq %d speed %d div %d outs %d ins %d adaptor %s droponfull %d", |
diff --git a/sound/drivers/vx/vx_mixer.c b/sound/drivers/vx/vx_mixer.c index 1613ed844ac6..f63152a6a223 100644 --- a/sound/drivers/vx/vx_mixer.c +++ b/sound/drivers/vx/vx_mixer.c | |||
@@ -716,7 +716,7 @@ static int vx_monitor_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_ | |||
716 | return 0; | 716 | return 0; |
717 | } | 717 | } |
718 | 718 | ||
719 | static DECLARE_TLV_DB_SCALE(db_scale_audio_gain, -10975, 25, 0); | 719 | static const DECLARE_TLV_DB_SCALE(db_scale_audio_gain, -10975, 25, 0); |
720 | 720 | ||
721 | static struct snd_kcontrol_new vx_control_audio_gain = { | 721 | static struct snd_kcontrol_new vx_control_audio_gain = { |
722 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 722 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
diff --git a/sound/i2c/Makefile b/sound/i2c/Makefile index 816a2e7c88ca..45902d48c89c 100644 --- a/sound/i2c/Makefile +++ b/sound/i2c/Makefile | |||
@@ -16,3 +16,4 @@ obj-$(CONFIG_SND) += other/ | |||
16 | # Toplevel Module Dependency | 16 | # Toplevel Module Dependency |
17 | obj-$(CONFIG_SND_INTERWAVE_STB) += snd-tea6330t.o snd-i2c.o | 17 | obj-$(CONFIG_SND_INTERWAVE_STB) += snd-tea6330t.o snd-i2c.o |
18 | obj-$(CONFIG_SND_ICE1712) += snd-cs8427.o snd-i2c.o | 18 | obj-$(CONFIG_SND_ICE1712) += snd-cs8427.o snd-i2c.o |
19 | obj-$(CONFIG_SND_ICE1724) += snd-i2c.o | ||
diff --git a/sound/i2c/other/Makefile b/sound/i2c/other/Makefile index 2fe023ef00a7..77a8a7c75dd9 100644 --- a/sound/i2c/other/Makefile +++ b/sound/i2c/other/Makefile | |||
@@ -6,11 +6,11 @@ | |||
6 | snd-ak4114-objs := ak4114.o | 6 | snd-ak4114-objs := ak4114.o |
7 | snd-ak4117-objs := ak4117.o | 7 | snd-ak4117-objs := ak4117.o |
8 | snd-ak4xxx-adda-objs := ak4xxx-adda.o | 8 | snd-ak4xxx-adda-objs := ak4xxx-adda.o |
9 | snd-pt2258-objs := pt2258.o | ||
9 | snd-tea575x-tuner-objs := tea575x-tuner.o | 10 | snd-tea575x-tuner-objs := tea575x-tuner.o |
10 | 11 | ||
11 | # Module Dependency | 12 | # Module Dependency |
12 | obj-$(CONFIG_SND_PDAUDIOCF) += snd-ak4117.o | 13 | obj-$(CONFIG_SND_PDAUDIOCF) += snd-ak4117.o |
13 | obj-$(CONFIG_SND_ICE1712) += snd-ak4xxx-adda.o | 14 | obj-$(CONFIG_SND_ICE1712) += snd-ak4xxx-adda.o |
14 | obj-$(CONFIG_SND_ICE1724) += snd-ak4xxx-adda.o | 15 | obj-$(CONFIG_SND_ICE1724) += snd-ak4114.o snd-ak4xxx-adda.o snd-pt2258.o |
15 | obj-$(CONFIG_SND_ICE1724) += snd-ak4114.o | ||
16 | obj-$(CONFIG_SND_FM801_TEA575X) += snd-tea575x-tuner.o | 16 | obj-$(CONFIG_SND_FM801_TEA575X) += snd-tea575x-tuner.o |
diff --git a/sound/i2c/other/ak4114.c b/sound/i2c/other/ak4114.c index d2f2c5078e65..adbfd5884d06 100644 --- a/sound/i2c/other/ak4114.c +++ b/sound/i2c/other/ak4114.c | |||
@@ -42,8 +42,8 @@ static void reg_write(struct ak4114 *ak4114, unsigned char reg, unsigned char va | |||
42 | ak4114->write(ak4114->private_data, reg, val); | 42 | ak4114->write(ak4114->private_data, reg, val); |
43 | if (reg <= AK4114_REG_INT1_MASK) | 43 | if (reg <= AK4114_REG_INT1_MASK) |
44 | ak4114->regmap[reg] = val; | 44 | ak4114->regmap[reg] = val; |
45 | else if (reg >= AK4114_REG_RXCSB0 && reg <= AK4114_REG_TXCSB4) | 45 | else if (reg >= AK4114_REG_TXCSB0 && reg <= AK4114_REG_TXCSB4) |
46 | ak4114->txcsb[reg-AK4114_REG_RXCSB0] = val; | 46 | ak4114->txcsb[reg-AK4114_REG_TXCSB0] = val; |
47 | } | 47 | } |
48 | 48 | ||
49 | static inline unsigned char reg_read(struct ak4114 *ak4114, unsigned char reg) | 49 | static inline unsigned char reg_read(struct ak4114 *ak4114, unsigned char reg) |
@@ -66,10 +66,8 @@ static void snd_ak4114_free(struct ak4114 *chip) | |||
66 | { | 66 | { |
67 | chip->init = 1; /* don't schedule new work */ | 67 | chip->init = 1; /* don't schedule new work */ |
68 | mb(); | 68 | mb(); |
69 | if (chip->workqueue != NULL) { | 69 | cancel_delayed_work(&chip->work); |
70 | flush_workqueue(chip->workqueue); | 70 | flush_scheduled_work(); |
71 | destroy_workqueue(chip->workqueue); | ||
72 | } | ||
73 | kfree(chip); | 71 | kfree(chip); |
74 | } | 72 | } |
75 | 73 | ||
@@ -82,7 +80,7 @@ static int snd_ak4114_dev_free(struct snd_device *device) | |||
82 | 80 | ||
83 | int snd_ak4114_create(struct snd_card *card, | 81 | int snd_ak4114_create(struct snd_card *card, |
84 | ak4114_read_t *read, ak4114_write_t *write, | 82 | ak4114_read_t *read, ak4114_write_t *write, |
85 | unsigned char pgm[7], unsigned char txcsb[5], | 83 | const unsigned char pgm[7], const unsigned char txcsb[5], |
86 | void *private_data, struct ak4114 **r_ak4114) | 84 | void *private_data, struct ak4114 **r_ak4114) |
87 | { | 85 | { |
88 | struct ak4114 *chip; | 86 | struct ak4114 *chip; |
@@ -100,18 +98,13 @@ int snd_ak4114_create(struct snd_card *card, | |||
100 | chip->read = read; | 98 | chip->read = read; |
101 | chip->write = write; | 99 | chip->write = write; |
102 | chip->private_data = private_data; | 100 | chip->private_data = private_data; |
101 | INIT_DELAYED_WORK(&chip->work, ak4114_stats); | ||
103 | 102 | ||
104 | for (reg = 0; reg < 7; reg++) | 103 | for (reg = 0; reg < 7; reg++) |
105 | chip->regmap[reg] = pgm[reg]; | 104 | chip->regmap[reg] = pgm[reg]; |
106 | for (reg = 0; reg < 5; reg++) | 105 | for (reg = 0; reg < 5; reg++) |
107 | chip->txcsb[reg] = txcsb[reg]; | 106 | chip->txcsb[reg] = txcsb[reg]; |
108 | 107 | ||
109 | chip->workqueue = create_workqueue("snd-ak4114"); | ||
110 | if (chip->workqueue == NULL) { | ||
111 | kfree(chip); | ||
112 | return -ENOMEM; | ||
113 | } | ||
114 | |||
115 | snd_ak4114_reinit(chip); | 108 | snd_ak4114_reinit(chip); |
116 | 109 | ||
117 | chip->rcs0 = reg_read(chip, AK4114_REG_RCS0) & ~(AK4114_QINT | AK4114_CINT); | 110 | chip->rcs0 = reg_read(chip, AK4114_REG_RCS0) & ~(AK4114_QINT | AK4114_CINT); |
@@ -134,7 +127,8 @@ void snd_ak4114_reg_write(struct ak4114 *chip, unsigned char reg, unsigned char | |||
134 | if (reg <= AK4114_REG_INT1_MASK) | 127 | if (reg <= AK4114_REG_INT1_MASK) |
135 | reg_write(chip, reg, (chip->regmap[reg] & ~mask) | val); | 128 | reg_write(chip, reg, (chip->regmap[reg] & ~mask) | val); |
136 | else if (reg >= AK4114_REG_TXCSB0 && reg <= AK4114_REG_TXCSB4) | 129 | else if (reg >= AK4114_REG_TXCSB0 && reg <= AK4114_REG_TXCSB4) |
137 | reg_write(chip, reg, (chip->txcsb[reg] & ~mask) | val); | 130 | reg_write(chip, reg, |
131 | (chip->txcsb[reg-AK4114_REG_TXCSB0] & ~mask) | val); | ||
138 | } | 132 | } |
139 | 133 | ||
140 | void snd_ak4114_reinit(struct ak4114 *chip) | 134 | void snd_ak4114_reinit(struct ak4114 *chip) |
@@ -143,7 +137,7 @@ void snd_ak4114_reinit(struct ak4114 *chip) | |||
143 | 137 | ||
144 | chip->init = 1; | 138 | chip->init = 1; |
145 | mb(); | 139 | mb(); |
146 | flush_workqueue(chip->workqueue); | 140 | flush_scheduled_work(); |
147 | /* bring the chip to reset state and powerdown state */ | 141 | /* bring the chip to reset state and powerdown state */ |
148 | reg_write(chip, AK4114_REG_PWRDN, old & ~(AK4114_RST|AK4114_PWN)); | 142 | reg_write(chip, AK4114_REG_PWRDN, old & ~(AK4114_RST|AK4114_PWN)); |
149 | udelay(200); | 143 | udelay(200); |
@@ -158,8 +152,7 @@ void snd_ak4114_reinit(struct ak4114 *chip) | |||
158 | reg_write(chip, AK4114_REG_PWRDN, old | AK4114_RST | AK4114_PWN); | 152 | reg_write(chip, AK4114_REG_PWRDN, old | AK4114_RST | AK4114_PWN); |
159 | /* bring up statistics / event queing */ | 153 | /* bring up statistics / event queing */ |
160 | chip->init = 0; | 154 | chip->init = 0; |
161 | INIT_DELAYED_WORK(&chip->work, ak4114_stats); | 155 | schedule_delayed_work(&chip->work, HZ / 10); |
162 | queue_delayed_work(chip->workqueue, &chip->work, HZ / 10); | ||
163 | } | 156 | } |
164 | 157 | ||
165 | static unsigned int external_rate(unsigned char rcs1) | 158 | static unsigned int external_rate(unsigned char rcs1) |
@@ -568,7 +561,7 @@ static void ak4114_stats(struct work_struct *work) | |||
568 | if (chip->init) | 561 | if (chip->init) |
569 | return; | 562 | return; |
570 | snd_ak4114_check_rate_and_errors(chip, 0); | 563 | snd_ak4114_check_rate_and_errors(chip, 0); |
571 | queue_delayed_work(chip->workqueue, &chip->work, HZ / 10); | 564 | schedule_delayed_work(&chip->work, HZ / 10); |
572 | } | 565 | } |
573 | 566 | ||
574 | EXPORT_SYMBOL(snd_ak4114_create); | 567 | EXPORT_SYMBOL(snd_ak4114_create); |
diff --git a/sound/i2c/other/ak4117.c b/sound/i2c/other/ak4117.c index 4e45952dd95a..c022f29da2f7 100644 --- a/sound/i2c/other/ak4117.c +++ b/sound/i2c/other/ak4117.c | |||
@@ -74,7 +74,7 @@ static int snd_ak4117_dev_free(struct snd_device *device) | |||
74 | } | 74 | } |
75 | 75 | ||
76 | int snd_ak4117_create(struct snd_card *card, ak4117_read_t *read, ak4117_write_t *write, | 76 | int snd_ak4117_create(struct snd_card *card, ak4117_read_t *read, ak4117_write_t *write, |
77 | unsigned char pgm[5], void *private_data, struct ak4117 **r_ak4117) | 77 | const unsigned char pgm[5], void *private_data, struct ak4117 **r_ak4117) |
78 | { | 78 | { |
79 | struct ak4117 *chip; | 79 | struct ak4117 *chip; |
80 | int err = 0; | 80 | int err = 0; |
diff --git a/sound/i2c/other/ak4xxx-adda.c b/sound/i2c/other/ak4xxx-adda.c index 5da49e2eb350..8805110017a7 100644 --- a/sound/i2c/other/ak4xxx-adda.c +++ b/sound/i2c/other/ak4xxx-adda.c | |||
@@ -140,7 +140,7 @@ EXPORT_SYMBOL(snd_akm4xxx_reset); | |||
140 | * Used for AK4524 input/ouput attenuation, AK4528, and | 140 | * Used for AK4524 input/ouput attenuation, AK4528, and |
141 | * AK5365 input attenuation | 141 | * AK5365 input attenuation |
142 | */ | 142 | */ |
143 | static unsigned char vol_cvt_datt[128] = { | 143 | static const unsigned char vol_cvt_datt[128] = { |
144 | 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04, | 144 | 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04, |
145 | 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x06, | 145 | 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x06, |
146 | 0x06, 0x07, 0x07, 0x08, 0x08, 0x08, 0x09, 0x0a, | 146 | 0x06, 0x07, 0x07, 0x08, 0x08, 0x08, 0x09, 0x0a, |
@@ -162,17 +162,17 @@ static unsigned char vol_cvt_datt[128] = { | |||
162 | /* | 162 | /* |
163 | * dB tables | 163 | * dB tables |
164 | */ | 164 | */ |
165 | static DECLARE_TLV_DB_SCALE(db_scale_vol_datt, -6350, 50, 1); | 165 | static const DECLARE_TLV_DB_SCALE(db_scale_vol_datt, -6350, 50, 1); |
166 | static DECLARE_TLV_DB_SCALE(db_scale_8bit, -12750, 50, 1); | 166 | static const DECLARE_TLV_DB_SCALE(db_scale_8bit, -12750, 50, 1); |
167 | static DECLARE_TLV_DB_SCALE(db_scale_7bit, -6350, 50, 1); | 167 | static const DECLARE_TLV_DB_SCALE(db_scale_7bit, -6350, 50, 1); |
168 | static DECLARE_TLV_DB_LINEAR(db_scale_linear, TLV_DB_GAIN_MUTE, 0); | 168 | static const DECLARE_TLV_DB_LINEAR(db_scale_linear, TLV_DB_GAIN_MUTE, 0); |
169 | 169 | ||
170 | /* | 170 | /* |
171 | * initialize all the ak4xxx chips | 171 | * initialize all the ak4xxx chips |
172 | */ | 172 | */ |
173 | void snd_akm4xxx_init(struct snd_akm4xxx *ak) | 173 | void snd_akm4xxx_init(struct snd_akm4xxx *ak) |
174 | { | 174 | { |
175 | static unsigned char inits_ak4524[] = { | 175 | static const unsigned char inits_ak4524[] = { |
176 | 0x00, 0x07, /* 0: all power up */ | 176 | 0x00, 0x07, /* 0: all power up */ |
177 | 0x01, 0x00, /* 1: ADC/DAC reset */ | 177 | 0x01, 0x00, /* 1: ADC/DAC reset */ |
178 | 0x02, 0x60, /* 2: 24bit I2S */ | 178 | 0x02, 0x60, /* 2: 24bit I2S */ |
@@ -184,7 +184,7 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak) | |||
184 | 0x07, 0x00, /* 7: DAC right muted */ | 184 | 0x07, 0x00, /* 7: DAC right muted */ |
185 | 0xff, 0xff | 185 | 0xff, 0xff |
186 | }; | 186 | }; |
187 | static unsigned char inits_ak4528[] = { | 187 | static const unsigned char inits_ak4528[] = { |
188 | 0x00, 0x07, /* 0: all power up */ | 188 | 0x00, 0x07, /* 0: all power up */ |
189 | 0x01, 0x00, /* 1: ADC/DAC reset */ | 189 | 0x01, 0x00, /* 1: ADC/DAC reset */ |
190 | 0x02, 0x60, /* 2: 24bit I2S */ | 190 | 0x02, 0x60, /* 2: 24bit I2S */ |
@@ -194,7 +194,7 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak) | |||
194 | 0x05, 0x00, /* 5: ADC right muted */ | 194 | 0x05, 0x00, /* 5: ADC right muted */ |
195 | 0xff, 0xff | 195 | 0xff, 0xff |
196 | }; | 196 | }; |
197 | static unsigned char inits_ak4529[] = { | 197 | static const unsigned char inits_ak4529[] = { |
198 | 0x09, 0x01, /* 9: ATS=0, RSTN=1 */ | 198 | 0x09, 0x01, /* 9: ATS=0, RSTN=1 */ |
199 | 0x0a, 0x3f, /* A: all power up, no zero/overflow detection */ | 199 | 0x0a, 0x3f, /* A: all power up, no zero/overflow detection */ |
200 | 0x00, 0x0c, /* 0: TDM=0, 24bit I2S, SMUTE=0 */ | 200 | 0x00, 0x0c, /* 0: TDM=0, 24bit I2S, SMUTE=0 */ |
@@ -210,7 +210,7 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak) | |||
210 | 0x08, 0x55, /* 8: deemphasis all off */ | 210 | 0x08, 0x55, /* 8: deemphasis all off */ |
211 | 0xff, 0xff | 211 | 0xff, 0xff |
212 | }; | 212 | }; |
213 | static unsigned char inits_ak4355[] = { | 213 | static const unsigned char inits_ak4355[] = { |
214 | 0x01, 0x02, /* 1: reset and soft-mute */ | 214 | 0x01, 0x02, /* 1: reset and soft-mute */ |
215 | 0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect, | 215 | 0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect, |
216 | * disable DZF, sharp roll-off, RSTN#=0 */ | 216 | * disable DZF, sharp roll-off, RSTN#=0 */ |
@@ -227,7 +227,7 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak) | |||
227 | 0x01, 0x01, /* 1: un-reset, unmute */ | 227 | 0x01, 0x01, /* 1: un-reset, unmute */ |
228 | 0xff, 0xff | 228 | 0xff, 0xff |
229 | }; | 229 | }; |
230 | static unsigned char inits_ak4358[] = { | 230 | static const unsigned char inits_ak4358[] = { |
231 | 0x01, 0x02, /* 1: reset and soft-mute */ | 231 | 0x01, 0x02, /* 1: reset and soft-mute */ |
232 | 0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect, | 232 | 0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect, |
233 | * disable DZF, sharp roll-off, RSTN#=0 */ | 233 | * disable DZF, sharp roll-off, RSTN#=0 */ |
@@ -246,7 +246,7 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak) | |||
246 | 0x01, 0x01, /* 1: un-reset, unmute */ | 246 | 0x01, 0x01, /* 1: un-reset, unmute */ |
247 | 0xff, 0xff | 247 | 0xff, 0xff |
248 | }; | 248 | }; |
249 | static unsigned char inits_ak4381[] = { | 249 | static const unsigned char inits_ak4381[] = { |
250 | 0x00, 0x0c, /* 0: mode3(i2s), disable auto-clock detect */ | 250 | 0x00, 0x0c, /* 0: mode3(i2s), disable auto-clock detect */ |
251 | 0x01, 0x02, /* 1: de-emphasis off, normal speed, | 251 | 0x01, 0x02, /* 1: de-emphasis off, normal speed, |
252 | * sharp roll-off, DZF off */ | 252 | * sharp roll-off, DZF off */ |
@@ -259,7 +259,8 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak) | |||
259 | }; | 259 | }; |
260 | 260 | ||
261 | int chip, num_chips; | 261 | int chip, num_chips; |
262 | unsigned char *ptr, reg, data, *inits; | 262 | const unsigned char *ptr, *inits; |
263 | unsigned char reg, data; | ||
263 | 264 | ||
264 | memset(ak->images, 0, sizeof(ak->images)); | 265 | memset(ak->images, 0, sizeof(ak->images)); |
265 | memset(ak->volumes, 0, sizeof(ak->volumes)); | 266 | memset(ak->volumes, 0, sizeof(ak->volumes)); |
@@ -513,6 +514,66 @@ static int ak4xxx_switch_put(struct snd_kcontrol *kcontrol, | |||
513 | return change; | 514 | return change; |
514 | } | 515 | } |
515 | 516 | ||
517 | #define AK5365_NUM_INPUTS 5 | ||
518 | |||
519 | static int ak4xxx_capture_source_info(struct snd_kcontrol *kcontrol, | ||
520 | struct snd_ctl_elem_info *uinfo) | ||
521 | { | ||
522 | struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol); | ||
523 | int mixer_ch = AK_GET_SHIFT(kcontrol->private_value); | ||
524 | const char **input_names; | ||
525 | int num_names, idx; | ||
526 | |||
527 | input_names = ak->adc_info[mixer_ch].input_names; | ||
528 | |||
529 | num_names = 0; | ||
530 | while (num_names < AK5365_NUM_INPUTS && input_names[num_names]) | ||
531 | ++num_names; | ||
532 | |||
533 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
534 | uinfo->count = 1; | ||
535 | uinfo->value.enumerated.items = num_names; | ||
536 | idx = uinfo->value.enumerated.item; | ||
537 | if (idx >= num_names) | ||
538 | return -EINVAL; | ||
539 | strncpy(uinfo->value.enumerated.name, input_names[idx], | ||
540 | sizeof(uinfo->value.enumerated.name)); | ||
541 | return 0; | ||
542 | } | ||
543 | |||
544 | static int ak4xxx_capture_source_get(struct snd_kcontrol *kcontrol, | ||
545 | struct snd_ctl_elem_value *ucontrol) | ||
546 | { | ||
547 | struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol); | ||
548 | int chip = AK_GET_CHIP(kcontrol->private_value); | ||
549 | int addr = AK_GET_ADDR(kcontrol->private_value); | ||
550 | int mask = AK_GET_MASK(kcontrol->private_value); | ||
551 | unsigned char val; | ||
552 | |||
553 | val = snd_akm4xxx_get(ak, chip, addr) & mask; | ||
554 | ucontrol->value.enumerated.item[0] = val; | ||
555 | return 0; | ||
556 | } | ||
557 | |||
558 | static int ak4xxx_capture_source_put(struct snd_kcontrol *kcontrol, | ||
559 | struct snd_ctl_elem_value *ucontrol) | ||
560 | { | ||
561 | struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol); | ||
562 | int chip = AK_GET_CHIP(kcontrol->private_value); | ||
563 | int addr = AK_GET_ADDR(kcontrol->private_value); | ||
564 | int mask = AK_GET_MASK(kcontrol->private_value); | ||
565 | unsigned char oval, val; | ||
566 | |||
567 | oval = snd_akm4xxx_get(ak, chip, addr); | ||
568 | val = oval & ~mask; | ||
569 | val |= ucontrol->value.enumerated.item[0] & mask; | ||
570 | if (val != oval) { | ||
571 | snd_akm4xxx_write(ak, chip, addr, val); | ||
572 | return 1; | ||
573 | } | ||
574 | return 0; | ||
575 | } | ||
576 | |||
516 | /* | 577 | /* |
517 | * build AK4xxx controls | 578 | * build AK4xxx controls |
518 | */ | 579 | */ |
@@ -647,9 +708,10 @@ static int build_adc_controls(struct snd_akm4xxx *ak) | |||
647 | 708 | ||
648 | if (ak->type == SND_AK5365 && (idx % 2) == 0) { | 709 | if (ak->type == SND_AK5365 && (idx % 2) == 0) { |
649 | if (! ak->adc_info || | 710 | if (! ak->adc_info || |
650 | ! ak->adc_info[mixer_ch].switch_name) | 711 | ! ak->adc_info[mixer_ch].switch_name) { |
651 | knew.name = "Capture Switch"; | 712 | knew.name = "Capture Switch"; |
652 | else | 713 | knew.index = mixer_ch + ak->idx_offset * 2; |
714 | } else | ||
653 | knew.name = ak->adc_info[mixer_ch].switch_name; | 715 | knew.name = ak->adc_info[mixer_ch].switch_name; |
654 | knew.info = ak4xxx_switch_info; | 716 | knew.info = ak4xxx_switch_info; |
655 | knew.get = ak4xxx_switch_get; | 717 | knew.get = ak4xxx_switch_get; |
@@ -662,6 +724,26 @@ static int build_adc_controls(struct snd_akm4xxx *ak) | |||
662 | err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak)); | 724 | err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak)); |
663 | if (err < 0) | 725 | if (err < 0) |
664 | return err; | 726 | return err; |
727 | |||
728 | memset(&knew, 0, sizeof(knew)); | ||
729 | knew.name = ak->adc_info[mixer_ch].selector_name; | ||
730 | if (!knew.name) { | ||
731 | knew.name = "Capture Channel"; | ||
732 | knew.index = mixer_ch + ak->idx_offset * 2; | ||
733 | } | ||
734 | |||
735 | knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
736 | knew.info = ak4xxx_capture_source_info; | ||
737 | knew.get = ak4xxx_capture_source_get; | ||
738 | knew.put = ak4xxx_capture_source_put; | ||
739 | knew.access = 0; | ||
740 | /* input selector control: reg. 1, bits 0-2. | ||
741 | * mis-use 'shift' to pass mixer_ch */ | ||
742 | knew.private_value | ||
743 | = AK_COMPOSE(idx/2, 1, mixer_ch, 0x07); | ||
744 | err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak)); | ||
745 | if (err < 0) | ||
746 | return err; | ||
665 | } | 747 | } |
666 | 748 | ||
667 | idx += num_stereo; | 749 | idx += num_stereo; |
diff --git a/sound/i2c/other/pt2258.c b/sound/i2c/other/pt2258.c new file mode 100644 index 000000000000..e91cc3b44de5 --- /dev/null +++ b/sound/i2c/other/pt2258.c | |||
@@ -0,0 +1,233 @@ | |||
1 | /* | ||
2 | * ALSA Driver for the PT2258 volume controller. | ||
3 | * | ||
4 | * Copyright (c) 2006 Jochen Voss <voss@seehuhn.de> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include <sound/driver.h> | ||
23 | #include <sound/core.h> | ||
24 | #include <sound/control.h> | ||
25 | #include <sound/tlv.h> | ||
26 | #include <sound/i2c.h> | ||
27 | #include <sound/pt2258.h> | ||
28 | |||
29 | MODULE_AUTHOR("Jochen Voss <voss@seehuhn.de>"); | ||
30 | MODULE_DESCRIPTION("PT2258 volume controller (Princeton Technology Corp.)"); | ||
31 | MODULE_LICENSE("GPL"); | ||
32 | |||
33 | #define PT2258_CMD_RESET 0xc0 | ||
34 | #define PT2258_CMD_UNMUTE 0xf8 | ||
35 | #define PT2258_CMD_MUTE 0xf9 | ||
36 | |||
37 | static const unsigned char pt2258_channel_code[12] = { | ||
38 | 0x80, 0x90, /* channel 1: -10dB, -1dB */ | ||
39 | 0x40, 0x50, /* channel 2: -10dB, -1dB */ | ||
40 | 0x00, 0x10, /* channel 3: -10dB, -1dB */ | ||
41 | 0x20, 0x30, /* channel 4: -10dB, -1dB */ | ||
42 | 0x60, 0x70, /* channel 5: -10dB, -1dB */ | ||
43 | 0xa0, 0xb0 /* channel 6: -10dB, -1dB */ | ||
44 | }; | ||
45 | |||
46 | int snd_pt2258_reset(struct snd_pt2258 *pt) | ||
47 | { | ||
48 | unsigned char bytes[2]; | ||
49 | int i; | ||
50 | |||
51 | /* reset chip */ | ||
52 | bytes[0] = PT2258_CMD_RESET; | ||
53 | snd_i2c_lock(pt->i2c_bus); | ||
54 | if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 1) != 1) | ||
55 | goto __error; | ||
56 | snd_i2c_unlock(pt->i2c_bus); | ||
57 | |||
58 | /* mute all channels */ | ||
59 | pt->mute = 1; | ||
60 | bytes[0] = PT2258_CMD_MUTE; | ||
61 | snd_i2c_lock(pt->i2c_bus); | ||
62 | if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 1) != 1) | ||
63 | goto __error; | ||
64 | snd_i2c_unlock(pt->i2c_bus); | ||
65 | |||
66 | /* set all channels to 0dB */ | ||
67 | for (i = 0; i < 6; ++i) | ||
68 | pt->volume[i] = 0; | ||
69 | bytes[0] = 0xd0; | ||
70 | bytes[1] = 0xe0; | ||
71 | snd_i2c_lock(pt->i2c_bus); | ||
72 | if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 2) != 2) | ||
73 | goto __error; | ||
74 | snd_i2c_unlock(pt->i2c_bus); | ||
75 | |||
76 | return 0; | ||
77 | |||
78 | __error: | ||
79 | snd_i2c_unlock(pt->i2c_bus); | ||
80 | snd_printk(KERN_ERR "PT2258 reset failed\n"); | ||
81 | return -EIO; | ||
82 | } | ||
83 | |||
84 | static int pt2258_stereo_volume_info(struct snd_kcontrol *kcontrol, | ||
85 | struct snd_ctl_elem_info *uinfo) | ||
86 | { | ||
87 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
88 | uinfo->count = 2; | ||
89 | uinfo->value.integer.min = 0; | ||
90 | uinfo->value.integer.max = 79; | ||
91 | return 0; | ||
92 | } | ||
93 | |||
94 | static int pt2258_stereo_volume_get(struct snd_kcontrol *kcontrol, | ||
95 | struct snd_ctl_elem_value *ucontrol) | ||
96 | { | ||
97 | struct snd_pt2258 *pt = kcontrol->private_data; | ||
98 | int base = kcontrol->private_value; | ||
99 | |||
100 | /* chip does not support register reads */ | ||
101 | ucontrol->value.integer.value[0] = 79 - pt->volume[base]; | ||
102 | ucontrol->value.integer.value[1] = 79 - pt->volume[base + 1]; | ||
103 | return 0; | ||
104 | } | ||
105 | |||
106 | static int pt2258_stereo_volume_put(struct snd_kcontrol *kcontrol, | ||
107 | struct snd_ctl_elem_value *ucontrol) | ||
108 | { | ||
109 | struct snd_pt2258 *pt = kcontrol->private_data; | ||
110 | int base = kcontrol->private_value; | ||
111 | unsigned char bytes[2]; | ||
112 | int val0, val1; | ||
113 | |||
114 | val0 = 79 - ucontrol->value.integer.value[0]; | ||
115 | val1 = 79 - ucontrol->value.integer.value[1]; | ||
116 | if (val0 == pt->volume[base] && val1 == pt->volume[base + 1]) | ||
117 | return 0; | ||
118 | |||
119 | pt->volume[base] = val0; | ||
120 | bytes[0] = pt2258_channel_code[2 * base] | (val0 / 10); | ||
121 | bytes[1] = pt2258_channel_code[2 * base + 1] | (val0 % 10); | ||
122 | snd_i2c_lock(pt->i2c_bus); | ||
123 | if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 2) != 2) | ||
124 | goto __error; | ||
125 | snd_i2c_unlock(pt->i2c_bus); | ||
126 | |||
127 | pt->volume[base + 1] = val1; | ||
128 | bytes[0] = pt2258_channel_code[2 * base + 2] | (val1 / 10); | ||
129 | bytes[1] = pt2258_channel_code[2 * base + 3] | (val1 % 10); | ||
130 | snd_i2c_lock(pt->i2c_bus); | ||
131 | if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 2) != 2) | ||
132 | goto __error; | ||
133 | snd_i2c_unlock(pt->i2c_bus); | ||
134 | |||
135 | return 1; | ||
136 | |||
137 | __error: | ||
138 | snd_i2c_unlock(pt->i2c_bus); | ||
139 | snd_printk(KERN_ERR "PT2258 access failed\n"); | ||
140 | return -EIO; | ||
141 | } | ||
142 | |||
143 | static int pt2258_switch_info(struct snd_kcontrol *kcontrol, | ||
144 | struct snd_ctl_elem_info *uinfo) | ||
145 | { | ||
146 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
147 | uinfo->count = 1; | ||
148 | uinfo->value.integer.min = 0; | ||
149 | uinfo->value.integer.max = 1; | ||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | static int pt2258_switch_get(struct snd_kcontrol *kcontrol, | ||
154 | struct snd_ctl_elem_value *ucontrol) | ||
155 | { | ||
156 | struct snd_pt2258 *pt = kcontrol->private_data; | ||
157 | |||
158 | ucontrol->value.integer.value[0] = !pt->mute; | ||
159 | return 0; | ||
160 | } | ||
161 | |||
162 | static int pt2258_switch_put(struct snd_kcontrol *kcontrol, | ||
163 | struct snd_ctl_elem_value *ucontrol) | ||
164 | { | ||
165 | struct snd_pt2258 *pt = kcontrol->private_data; | ||
166 | unsigned char bytes[2]; | ||
167 | int val; | ||
168 | |||
169 | val = !ucontrol->value.integer.value[0]; | ||
170 | if (pt->mute == val) | ||
171 | return 0; | ||
172 | |||
173 | pt->mute = val; | ||
174 | bytes[0] = val ? PT2258_CMD_MUTE : PT2258_CMD_UNMUTE; | ||
175 | snd_i2c_lock(pt->i2c_bus); | ||
176 | if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 1) != 1) | ||
177 | goto __error; | ||
178 | snd_i2c_unlock(pt->i2c_bus); | ||
179 | |||
180 | return 1; | ||
181 | |||
182 | __error: | ||
183 | snd_i2c_unlock(pt->i2c_bus); | ||
184 | snd_printk(KERN_ERR "PT2258 access failed 2\n"); | ||
185 | return -EIO; | ||
186 | } | ||
187 | |||
188 | static const DECLARE_TLV_DB_SCALE(pt2258_db_scale, -7900, 100, 0); | ||
189 | |||
190 | int snd_pt2258_build_controls(struct snd_pt2258 *pt) | ||
191 | { | ||
192 | struct snd_kcontrol_new knew; | ||
193 | char *names[3] = { | ||
194 | "Mic Loopback Playback Volume", | ||
195 | "Line Loopback Playback Volume", | ||
196 | "CD Loopback Playback Volume" | ||
197 | }; | ||
198 | int i, err; | ||
199 | |||
200 | for (i = 0; i < 3; ++i) { | ||
201 | memset(&knew, 0, sizeof(knew)); | ||
202 | knew.name = names[i]; | ||
203 | knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
204 | knew.count = 1; | ||
205 | knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
206 | SNDRV_CTL_ELEM_ACCESS_TLV_READ; | ||
207 | knew.private_value = 2 * i; | ||
208 | knew.info = pt2258_stereo_volume_info; | ||
209 | knew.get = pt2258_stereo_volume_get; | ||
210 | knew.put = pt2258_stereo_volume_put; | ||
211 | knew.tlv.p = pt2258_db_scale; | ||
212 | |||
213 | err = snd_ctl_add(pt->card, snd_ctl_new1(&knew, pt)); | ||
214 | if (err < 0) | ||
215 | return err; | ||
216 | } | ||
217 | |||
218 | memset(&knew, 0, sizeof(knew)); | ||
219 | knew.name = "Loopback Switch"; | ||
220 | knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
221 | knew.info = pt2258_switch_info; | ||
222 | knew.get = pt2258_switch_get; | ||
223 | knew.put = pt2258_switch_put; | ||
224 | knew.access = 0; | ||
225 | err = snd_ctl_add(pt->card, snd_ctl_new1(&knew, pt)); | ||
226 | if (err < 0) | ||
227 | return err; | ||
228 | |||
229 | return 0; | ||
230 | } | ||
231 | |||
232 | EXPORT_SYMBOL(snd_pt2258_reset); | ||
233 | EXPORT_SYMBOL(snd_pt2258_build_controls); | ||
diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig index 57371f1a441f..4e3a9729f569 100644 --- a/sound/isa/Kconfig +++ b/sound/isa/Kconfig | |||
@@ -358,6 +358,7 @@ config SND_SBAWE | |||
358 | config SND_SB16_CSP | 358 | config SND_SB16_CSP |
359 | bool "Sound Blaster 16/AWE CSP support" | 359 | bool "Sound Blaster 16/AWE CSP support" |
360 | depends on (SND_SB16 || SND_SBAWE) && (BROKEN || !PPC) | 360 | depends on (SND_SB16 || SND_SBAWE) && (BROKEN || !PPC) |
361 | select FW_LOADER | ||
361 | help | 362 | help |
362 | Say Y here to include support for the CSP core. This special | 363 | Say Y here to include support for the CSP core. This special |
363 | coprocessor can do variable tasks like various compression and | 364 | coprocessor can do variable tasks like various compression and |
@@ -390,6 +391,7 @@ config SND_SSCAPE | |||
390 | config SND_WAVEFRONT | 391 | config SND_WAVEFRONT |
391 | tristate "Turtle Beach Maui,Tropez,Tropez+ (Wavefront)" | 392 | tristate "Turtle Beach Maui,Tropez,Tropez+ (Wavefront)" |
392 | depends on SND | 393 | depends on SND |
394 | select FW_LOADER | ||
393 | select SND_OPL3_LIB | 395 | select SND_OPL3_LIB |
394 | select SND_MPU401_UART | 396 | select SND_MPU401_UART |
395 | select SND_CS4231_LIB | 397 | select SND_CS4231_LIB |
diff --git a/sound/isa/ad1816a/ad1816a_lib.c b/sound/isa/ad1816a/ad1816a_lib.c index b524e0d9ee44..ec9209cd5177 100644 --- a/sound/isa/ad1816a/ad1816a_lib.c +++ b/sound/isa/ad1816a/ad1816a_lib.c | |||
@@ -906,11 +906,11 @@ static int snd_ad1816a_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_ | |||
906 | return change; | 906 | return change; |
907 | } | 907 | } |
908 | 908 | ||
909 | static DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0); | 909 | static const DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0); |
910 | static DECLARE_TLV_DB_SCALE(db_scale_5bit, -4650, 150, 0); | 910 | static const DECLARE_TLV_DB_SCALE(db_scale_5bit, -4650, 150, 0); |
911 | static DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0); | 911 | static const DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0); |
912 | static DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0); | 912 | static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0); |
913 | static DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0); | 913 | static const DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0); |
914 | 914 | ||
915 | static struct snd_kcontrol_new snd_ad1816a_controls[] __devinitdata = { | 915 | static struct snd_kcontrol_new snd_ad1816a_controls[] __devinitdata = { |
916 | AD1816A_DOUBLE("Master Playback Switch", AD1816A_MASTER_ATT, 15, 7, 1, 1), | 916 | AD1816A_DOUBLE("Master Playback Switch", AD1816A_MASTER_ATT, 15, 7, 1, 1), |
diff --git a/sound/isa/ad1848/ad1848_lib.c b/sound/isa/ad1848/ad1848_lib.c index 666b3bcc19f0..8094282c2ae1 100644 --- a/sound/isa/ad1848/ad1848_lib.c +++ b/sound/isa/ad1848/ad1848_lib.c | |||
@@ -1223,9 +1223,9 @@ int snd_ad1848_add_ctl_elem(struct snd_ad1848 *chip, | |||
1223 | 1223 | ||
1224 | EXPORT_SYMBOL(snd_ad1848_add_ctl_elem); | 1224 | EXPORT_SYMBOL(snd_ad1848_add_ctl_elem); |
1225 | 1225 | ||
1226 | static DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0); | 1226 | static const DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0); |
1227 | static DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0); | 1227 | static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0); |
1228 | static DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0); | 1228 | static const DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0); |
1229 | 1229 | ||
1230 | static struct ad1848_mix_elem snd_ad1848_controls[] = { | 1230 | static struct ad1848_mix_elem snd_ad1848_controls[] = { |
1231 | AD1848_DOUBLE("PCM Playback Switch", 0, AD1848_LEFT_OUTPUT, AD1848_RIGHT_OUTPUT, 7, 7, 1, 1), | 1231 | AD1848_DOUBLE("PCM Playback Switch", 0, AD1848_LEFT_OUTPUT, AD1848_RIGHT_OUTPUT, 7, 7, 1, 1), |
diff --git a/sound/isa/gus/gus_main.c b/sound/isa/gus/gus_main.c index b680fddf0d74..8ced5e81b9a7 100644 --- a/sound/isa/gus/gus_main.c +++ b/sound/isa/gus/gus_main.c | |||
@@ -294,10 +294,10 @@ static int snd_gus_init_dma_irq(struct snd_gus_card * gus, int latches) | |||
294 | gus->mix_cntrl_reg |= 4; /* enable MIC */ | 294 | gus->mix_cntrl_reg |= 4; /* enable MIC */ |
295 | } | 295 | } |
296 | dma1 = gus->gf1.dma1; | 296 | dma1 = gus->gf1.dma1; |
297 | dma1 = dma1 < 0 ? -dma1 : dma1; | 297 | dma1 = abs(dma1); |
298 | dma1 = dmas[dma1 & 7]; | 298 | dma1 = dmas[dma1 & 7]; |
299 | dma2 = gus->gf1.dma2; | 299 | dma2 = gus->gf1.dma2; |
300 | dma2 = dma2 < 0 ? -dma2 : dma2; | 300 | dma2 = abs(dma2); |
301 | dma2 = dmas[dma2 & 7]; | 301 | dma2 = dmas[dma2 & 7]; |
302 | dma1 |= gus->equal_dma ? 0x40 : (dma2 << 3); | 302 | dma1 |= gus->equal_dma ? 0x40 : (dma2 << 3); |
303 | 303 | ||
@@ -306,7 +306,7 @@ static int snd_gus_init_dma_irq(struct snd_gus_card * gus, int latches) | |||
306 | return -EINVAL; | 306 | return -EINVAL; |
307 | } | 307 | } |
308 | irq = gus->gf1.irq; | 308 | irq = gus->gf1.irq; |
309 | irq = irq < 0 ? -irq : irq; | 309 | irq = abs(irq); |
310 | irq = irqs[irq & 0x0f]; | 310 | irq = irqs[irq & 0x0f]; |
311 | if (irq == 0) { | 311 | if (irq == 0) { |
312 | snd_printk(KERN_ERR "Error! IRQ isn't defined.\n"); | 312 | snd_printk(KERN_ERR "Error! IRQ isn't defined.\n"); |
diff --git a/sound/isa/opl3sa2.c b/sound/isa/opl3sa2.c index 419b4ebbf00e..1e30713d2cad 100644 --- a/sound/isa/opl3sa2.c +++ b/sound/isa/opl3sa2.c | |||
@@ -486,8 +486,8 @@ static int snd_opl3sa2_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_ | |||
486 | return change; | 486 | return change; |
487 | } | 487 | } |
488 | 488 | ||
489 | static DECLARE_TLV_DB_SCALE(db_scale_master, -3000, 200, 0); | 489 | static const DECLARE_TLV_DB_SCALE(db_scale_master, -3000, 200, 0); |
490 | static DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0); | 490 | static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0); |
491 | 491 | ||
492 | static struct snd_kcontrol_new snd_opl3sa2_controls[] = { | 492 | static struct snd_kcontrol_new snd_opl3sa2_controls[] = { |
493 | OPL3SA2_DOUBLE("Master Playback Switch", 0, 0x07, 0x08, 7, 7, 1, 1), | 493 | OPL3SA2_DOUBLE("Master Playback Switch", 0, 0x07, 0x08, 7, 7, 1, 1), |
diff --git a/sound/isa/sb/sb16_csp.c b/sound/isa/sb/sb16_csp.c index fcd638090a9e..3d9d7e0107ca 100644 --- a/sound/isa/sb/sb16_csp.c +++ b/sound/isa/sb/sb16_csp.c | |||
@@ -161,10 +161,13 @@ int snd_sb_csp_new(struct snd_sb *chip, int device, struct snd_hwdep ** rhwdep) | |||
161 | */ | 161 | */ |
162 | static void snd_sb_csp_free(struct snd_hwdep *hwdep) | 162 | static void snd_sb_csp_free(struct snd_hwdep *hwdep) |
163 | { | 163 | { |
164 | int i; | ||
164 | struct snd_sb_csp *p = hwdep->private_data; | 165 | struct snd_sb_csp *p = hwdep->private_data; |
165 | if (p) { | 166 | if (p) { |
166 | if (p->running & SNDRV_SB_CSP_ST_RUNNING) | 167 | if (p->running & SNDRV_SB_CSP_ST_RUNNING) |
167 | snd_sb_csp_stop(p); | 168 | snd_sb_csp_stop(p); |
169 | for (i = 0; i < ARRAY_SIZE(p->csp_programs); ++i) | ||
170 | release_firmware(p->csp_programs[i]); | ||
168 | kfree(p); | 171 | kfree(p); |
169 | } | 172 | } |
170 | } | 173 | } |
@@ -687,8 +690,50 @@ static int snd_sb_csp_load_user(struct snd_sb_csp * p, const unsigned char __use | |||
687 | return err; | 690 | return err; |
688 | } | 691 | } |
689 | 692 | ||
693 | #define FIRMWARE_IN_THE_KERNEL | ||
694 | |||
695 | #ifdef FIRMWARE_IN_THE_KERNEL | ||
690 | #include "sb16_csp_codecs.h" | 696 | #include "sb16_csp_codecs.h" |
691 | 697 | ||
698 | static const struct firmware snd_sb_csp_static_programs[] = { | ||
699 | { .data = mulaw_main, .size = sizeof mulaw_main }, | ||
700 | { .data = alaw_main, .size = sizeof alaw_main }, | ||
701 | { .data = ima_adpcm_init, .size = sizeof ima_adpcm_init }, | ||
702 | { .data = ima_adpcm_playback, .size = sizeof ima_adpcm_playback }, | ||
703 | { .data = ima_adpcm_capture, .size = sizeof ima_adpcm_capture }, | ||
704 | }; | ||
705 | #endif | ||
706 | |||
707 | static int snd_sb_csp_firmware_load(struct snd_sb_csp *p, int index, int flags) | ||
708 | { | ||
709 | static const char *const names[] = { | ||
710 | "sb16/mulaw_main.csp", | ||
711 | "sb16/alaw_main.csp", | ||
712 | "sb16/ima_adpcm_init.csp", | ||
713 | "sb16/ima_adpcm_playback.csp", | ||
714 | "sb16/ima_adpcm_capture.csp", | ||
715 | }; | ||
716 | const struct firmware *program; | ||
717 | int err; | ||
718 | |||
719 | BUILD_BUG_ON(ARRAY_SIZE(names) != CSP_PROGRAM_COUNT); | ||
720 | program = p->csp_programs[index]; | ||
721 | if (!program) { | ||
722 | err = request_firmware(&program, names[index], | ||
723 | p->chip->card->dev); | ||
724 | if (err >= 0) | ||
725 | p->csp_programs[index] = program; | ||
726 | else { | ||
727 | #ifdef FIRMWARE_IN_THE_KERNEL | ||
728 | program = &snd_sb_csp_static_programs[index]; | ||
729 | #else | ||
730 | return err; | ||
731 | #endif | ||
732 | } | ||
733 | } | ||
734 | return snd_sb_csp_load(p, program->data, program->size, flags); | ||
735 | } | ||
736 | |||
692 | /* | 737 | /* |
693 | * autoload hardware codec if necessary | 738 | * autoload hardware codec if necessary |
694 | * return 0 if CSP is loaded and ready to run (p->running != 0) | 739 | * return 0 if CSP is loaded and ready to run (p->running != 0) |
@@ -708,27 +753,27 @@ static int snd_sb_csp_autoload(struct snd_sb_csp * p, int pcm_sfmt, int play_rec | |||
708 | } else { | 753 | } else { |
709 | switch (pcm_sfmt) { | 754 | switch (pcm_sfmt) { |
710 | case SNDRV_PCM_FORMAT_MU_LAW: | 755 | case SNDRV_PCM_FORMAT_MU_LAW: |
711 | err = snd_sb_csp_load(p, &mulaw_main[0], sizeof(mulaw_main), 0); | 756 | err = snd_sb_csp_firmware_load(p, CSP_PROGRAM_MULAW, 0); |
712 | p->acc_format = SNDRV_PCM_FMTBIT_MU_LAW; | 757 | p->acc_format = SNDRV_PCM_FMTBIT_MU_LAW; |
713 | p->mode = SNDRV_SB_CSP_MODE_DSP_READ | SNDRV_SB_CSP_MODE_DSP_WRITE; | 758 | p->mode = SNDRV_SB_CSP_MODE_DSP_READ | SNDRV_SB_CSP_MODE_DSP_WRITE; |
714 | break; | 759 | break; |
715 | case SNDRV_PCM_FORMAT_A_LAW: | 760 | case SNDRV_PCM_FORMAT_A_LAW: |
716 | err = snd_sb_csp_load(p, &alaw_main[0], sizeof(alaw_main), 0); | 761 | err = snd_sb_csp_firmware_load(p, CSP_PROGRAM_ALAW, 0); |
717 | p->acc_format = SNDRV_PCM_FMTBIT_A_LAW; | 762 | p->acc_format = SNDRV_PCM_FMTBIT_A_LAW; |
718 | p->mode = SNDRV_SB_CSP_MODE_DSP_READ | SNDRV_SB_CSP_MODE_DSP_WRITE; | 763 | p->mode = SNDRV_SB_CSP_MODE_DSP_READ | SNDRV_SB_CSP_MODE_DSP_WRITE; |
719 | break; | 764 | break; |
720 | case SNDRV_PCM_FORMAT_IMA_ADPCM: | 765 | case SNDRV_PCM_FORMAT_IMA_ADPCM: |
721 | err = snd_sb_csp_load(p, &ima_adpcm_init[0], sizeof(ima_adpcm_init), | 766 | err = snd_sb_csp_firmware_load(p, CSP_PROGRAM_ADPCM_INIT, |
722 | SNDRV_SB_CSP_LOAD_INITBLOCK); | 767 | SNDRV_SB_CSP_LOAD_INITBLOCK); |
723 | if (err) | 768 | if (err) |
724 | break; | 769 | break; |
725 | if (play_rec_mode == SNDRV_SB_CSP_MODE_DSP_WRITE) { | 770 | if (play_rec_mode == SNDRV_SB_CSP_MODE_DSP_WRITE) { |
726 | err = snd_sb_csp_load(p, &ima_adpcm_playback[0], | 771 | err = snd_sb_csp_firmware_load |
727 | sizeof(ima_adpcm_playback), 0); | 772 | (p, CSP_PROGRAM_ADPCM_PLAYBACK, 0); |
728 | p->mode = SNDRV_SB_CSP_MODE_DSP_WRITE; | 773 | p->mode = SNDRV_SB_CSP_MODE_DSP_WRITE; |
729 | } else { | 774 | } else { |
730 | err = snd_sb_csp_load(p, &ima_adpcm_capture[0], | 775 | err = snd_sb_csp_firmware_load |
731 | sizeof(ima_adpcm_capture), 0); | 776 | (p, CSP_PROGRAM_ADPCM_CAPTURE, 0); |
732 | p->mode = SNDRV_SB_CSP_MODE_DSP_READ; | 777 | p->mode = SNDRV_SB_CSP_MODE_DSP_READ; |
733 | } | 778 | } |
734 | p->acc_format = SNDRV_PCM_FMTBIT_IMA_ADPCM; | 779 | p->acc_format = SNDRV_PCM_FMTBIT_IMA_ADPCM; |
diff --git a/sound/isa/wavefront/wavefront.c b/sound/isa/wavefront/wavefront.c index 85db535aea9b..e2fdd5fd39d0 100644 --- a/sound/isa/wavefront/wavefront.c +++ b/sound/isa/wavefront/wavefront.c | |||
@@ -402,6 +402,7 @@ static struct snd_card *snd_wavefront_card_new(int dev) | |||
402 | init_waitqueue_head(&acard->wavefront.interrupt_sleeper); | 402 | init_waitqueue_head(&acard->wavefront.interrupt_sleeper); |
403 | spin_lock_init(&acard->wavefront.midi.open); | 403 | spin_lock_init(&acard->wavefront.midi.open); |
404 | spin_lock_init(&acard->wavefront.midi.virtual); | 404 | spin_lock_init(&acard->wavefront.midi.virtual); |
405 | acard->wavefront.card = card; | ||
405 | card->private_free = snd_wavefront_free; | 406 | card->private_free = snd_wavefront_free; |
406 | 407 | ||
407 | return card; | 408 | return card; |
diff --git a/sound/isa/wavefront/wavefront_fx.c b/sound/isa/wavefront/wavefront_fx.c index 4f0846feb73f..15331ed88194 100644 --- a/sound/isa/wavefront/wavefront_fx.c +++ b/sound/isa/wavefront/wavefront_fx.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/init.h> | 21 | #include <linux/init.h> |
22 | #include <linux/time.h> | 22 | #include <linux/time.h> |
23 | #include <linux/wait.h> | 23 | #include <linux/wait.h> |
24 | #include <linux/firmware.h> | ||
24 | #include <sound/core.h> | 25 | #include <sound/core.h> |
25 | #include <sound/snd_wavefront.h> | 26 | #include <sound/snd_wavefront.h> |
26 | #include <sound/initval.h> | 27 | #include <sound/initval.h> |
@@ -32,325 +33,17 @@ | |||
32 | #define FX_MSB_TRANSFER 0x02 /* transfer after DSP MSB byte written */ | 33 | #define FX_MSB_TRANSFER 0x02 /* transfer after DSP MSB byte written */ |
33 | #define FX_AUTO_INCR 0x04 /* auto-increment DSP address after transfer */ | 34 | #define FX_AUTO_INCR 0x04 /* auto-increment DSP address after transfer */ |
34 | 35 | ||
35 | /* weird stuff, derived from port I/O tracing with dosemu */ | 36 | #define WAIT_IDLE 0xff |
36 | |||
37 | static unsigned char page_zero[] __devinitdata = { | ||
38 | 0x01, 0x7c, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf5, 0x00, | ||
39 | 0x11, 0x00, 0x20, 0x00, 0x32, 0x00, 0x40, 0x00, 0x13, 0x00, 0x00, | ||
40 | 0x00, 0x14, 0x02, 0x76, 0x00, 0x60, 0x00, 0x80, 0x02, 0x00, 0x00, | ||
41 | 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
42 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
43 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
44 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
45 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
46 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
47 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
48 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
49 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x19, | ||
50 | 0x01, 0x1a, 0x01, 0x20, 0x01, 0x40, 0x01, 0x17, 0x00, 0x00, 0x01, | ||
51 | 0x80, 0x01, 0x20, 0x00, 0x10, 0x01, 0xa0, 0x03, 0xd1, 0x00, 0x00, | ||
52 | 0x01, 0xf2, 0x02, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0xf4, 0x02, | ||
53 | 0xe0, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, | ||
54 | 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x50, 0x00, 0x00, 0x00, | ||
55 | 0x40, 0x00, 0x00, 0x00, 0x71, 0x02, 0x00, 0x00, 0x60, 0x00, 0x00, | ||
56 | 0x00, 0x92, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb3, 0x02, | ||
57 | 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, 0x40, | ||
58 | 0x00, 0x80, 0x00, 0xf5, 0x00, 0x20, 0x00, 0x70, 0x00, 0xa0, 0x02, | ||
59 | 0x11, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, | ||
60 | 0x02, 0x00, 0x00, 0x20, 0x00, 0x10, 0x00, 0x17, 0x00, 0x1b, 0x00, | ||
61 | 0x1d, 0x02, 0xdf | ||
62 | }; | ||
63 | |||
64 | static unsigned char page_one[] __devinitdata = { | ||
65 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x19, 0x00, | ||
66 | 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xd8, 0x00, 0x00, | ||
67 | 0x02, 0x20, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x01, | ||
68 | 0xc0, 0x01, 0xfa, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
69 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
70 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
71 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
72 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
73 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
74 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
75 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
76 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x40, 0x02, 0x60, | ||
77 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xc0, 0x02, 0x80, 0x00, | ||
78 | 0x00, 0x02, 0xfb, 0x02, 0xa0, 0x00, 0x00, 0x00, 0x1b, 0x02, 0xd7, | ||
79 | 0x00, 0x00, 0x02, 0xf7, 0x03, 0x20, 0x03, 0x00, 0x00, 0x00, 0x00, | ||
80 | 0x1c, 0x03, 0x3c, 0x00, 0x00, 0x03, 0x3f, 0x00, 0x00, 0x03, 0xc0, | ||
81 | 0x00, 0x00, 0x03, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x03, 0x5d, 0x00, | ||
82 | 0x00, 0x03, 0xc0, 0x00, 0x00, 0x03, 0x7d, 0x00, 0x00, 0x03, 0xc0, | ||
83 | 0x00, 0x00, 0x03, 0x9e, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x03, | ||
84 | 0xbe, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
85 | 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, | ||
86 | 0xdb, 0x00, 0x00, 0x02, 0xdb, 0x00, 0x00, 0x02, 0xe0, 0x00, 0x00, | ||
87 | 0x02, 0xfb, 0x00, 0x00, 0x02, 0xc0, 0x02, 0x40, 0x02, 0xfb, 0x02, | ||
88 | 0x60, 0x00, 0x1b | ||
89 | }; | ||
90 | |||
91 | static unsigned char page_two[] __devinitdata = { | ||
92 | 0xc4, 0x00, 0x44, 0x07, 0x44, 0x00, 0x40, 0x25, 0x01, 0x06, 0xc4, | ||
93 | 0x07, 0x40, 0x25, 0x01, 0x00, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, | ||
94 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
95 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
96 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
97 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x07, | ||
98 | 0x05, 0x05, 0x05, 0x04, 0x07, 0x05, 0x04, 0x07, 0x05, 0x44, 0x46, | ||
99 | 0x44, 0x46, 0x46, 0x07, 0x05, 0x44, 0x46, 0x05, 0x46, 0x05, 0x46, | ||
100 | 0x05, 0x46, 0x05, 0x44, 0x46, 0x05, 0x07, 0x44, 0x46, 0x05, 0x07, | ||
101 | 0x44, 0x46, 0x05, 0x07, 0x44, 0x46, 0x05, 0x07, 0x44, 0x05, 0x05, | ||
102 | 0x05, 0x44, 0x05, 0x05, 0x05, 0x46, 0x05, 0x46, 0x05, 0x46, 0x05, | ||
103 | 0x46, 0x05, 0x46, 0x07, 0x46, 0x07, 0x44 | ||
104 | }; | ||
105 | |||
106 | static unsigned char page_three[] __devinitdata = { | ||
107 | 0x07, 0x40, 0x00, 0x00, 0x00, 0x47, 0x00, 0x40, 0x00, 0x40, 0x06, | ||
108 | 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
109 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
110 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
111 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
112 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, | ||
113 | 0xc0, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x00, | ||
114 | 0x60, 0x00, 0x70, 0x00, 0x40, 0x00, 0x40, 0x00, 0x42, 0x00, 0x40, | ||
115 | 0x00, 0x02, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, | ||
116 | 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, | ||
117 | 0x00, 0x42, 0x00, 0x40, 0x00, 0x42, 0x00, 0x02, 0x00, 0x02, 0x00, | ||
118 | 0x02, 0x00, 0x42, 0x00, 0xc0, 0x00, 0x40 | ||
119 | }; | ||
120 | |||
121 | static unsigned char page_four[] __devinitdata = { | ||
122 | 0x63, 0x03, 0x26, 0x02, 0x2c, 0x00, 0x24, 0x00, 0x2e, 0x02, 0x02, | ||
123 | 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
124 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
125 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
126 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
127 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, | ||
128 | 0x20, 0x00, 0x60, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, | ||
129 | 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x60, 0x00, | ||
130 | 0x20, 0x00, 0x60, 0x00, 0x20, 0x00, 0x60, 0x00, 0x20, 0x00, 0x60, | ||
131 | 0x00, 0x20, 0x00, 0x60, 0x00, 0x20, 0x00, 0x60, 0x00, 0x20, 0x00, | ||
132 | 0x20, 0x00, 0x22, 0x02, 0x22, 0x02, 0x20, 0x00, 0x60, 0x00, 0x22, | ||
133 | 0x02, 0x62, 0x02, 0x20, 0x01, 0x21, 0x01 | ||
134 | }; | ||
135 | |||
136 | static unsigned char page_six[] __devinitdata = { | ||
137 | 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x04, 0x00, 0x00, 0x06, 0x00, | ||
138 | 0x00, 0x08, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x0e, | ||
139 | 0x00, 0x00, 0x10, 0x00, 0x00, 0x12, 0x00, 0x00, 0x14, 0x00, 0x00, | ||
140 | 0x16, 0x00, 0x00, 0x18, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x1c, 0x00, | ||
141 | 0x00, 0x1e, 0x00, 0x00, 0x20, 0x00, 0x00, 0x22, 0x00, 0x00, 0x24, | ||
142 | 0x00, 0x00, 0x26, 0x00, 0x00, 0x28, 0x00, 0x00, 0x2a, 0x00, 0x00, | ||
143 | 0x2c, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x30, 0x00, 0x00, 0x32, 0x00, | ||
144 | 0x00, 0x34, 0x00, 0x00, 0x36, 0x00, 0x00, 0x38, 0x00, 0x00, 0x3a, | ||
145 | 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x40, 0x00, 0x00, | ||
146 | 0x42, 0x03, 0x00, 0x44, 0x01, 0x00, 0x46, 0x0a, 0x21, 0x48, 0x0d, | ||
147 | 0x23, 0x4a, 0x23, 0x1b, 0x4c, 0x37, 0x8f, 0x4e, 0x45, 0x77, 0x50, | ||
148 | 0x52, 0xe2, 0x52, 0x1c, 0x92, 0x54, 0x1c, 0x52, 0x56, 0x07, 0x00, | ||
149 | 0x58, 0x2f, 0xc6, 0x5a, 0x0b, 0x00, 0x5c, 0x30, 0x06, 0x5e, 0x17, | ||
150 | 0x00, 0x60, 0x3d, 0xda, 0x62, 0x29, 0x00, 0x64, 0x3e, 0x41, 0x66, | ||
151 | 0x39, 0x00, 0x68, 0x4c, 0x48, 0x6a, 0x49, 0x00, 0x6c, 0x4c, 0x6c, | ||
152 | 0x6e, 0x11, 0xd2, 0x70, 0x16, 0x0c, 0x72, 0x00, 0x00, 0x74, 0x00, | ||
153 | 0x80, 0x76, 0x0f, 0x00, 0x78, 0x00, 0x80, 0x7a, 0x13, 0x00, 0x7c, | ||
154 | 0x80, 0x00, 0x7e, 0x80, 0x80 | ||
155 | }; | ||
156 | |||
157 | static unsigned char page_seven[] __devinitdata = { | ||
158 | 0x0f, 0xff, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00, | ||
159 | 0x00, 0x00, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, | ||
160 | 0x08, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x0f, | ||
161 | 0xff, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
162 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
163 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
164 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
165 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
166 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
167 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
168 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
169 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
170 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
171 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x0f, 0xff, | ||
172 | 0x0f, 0xff, 0x0f, 0xff, 0x02, 0xe9, 0x06, 0x8c, 0x06, 0x8c, 0x0f, | ||
173 | 0xff, 0x1a, 0x75, 0x0d, 0x8b, 0x04, 0xe9, 0x0b, 0x16, 0x1a, 0x38, | ||
174 | 0x0d, 0xc8, 0x04, 0x6f, 0x0b, 0x91, 0x0f, 0xff, 0x06, 0x40, 0x06, | ||
175 | 0x40, 0x02, 0x8f, 0x0f, 0xff, 0x06, 0x62, 0x06, 0x62, 0x02, 0x7b, | ||
176 | 0x0f, 0xff, 0x06, 0x97, 0x06, 0x97, 0x02, 0x52, 0x0f, 0xff, 0x06, | ||
177 | 0xf6, 0x06, 0xf6, 0x02, 0x19, 0x05, 0x55, 0x05, 0x55, 0x05, 0x55, | ||
178 | 0x05, 0x55, 0x05, 0x55, 0x05, 0x55, 0x05, 0x55, 0x05, 0x55, 0x14, | ||
179 | 0xda, 0x0d, 0x93, 0x04, 0xda, 0x05, 0x93, 0x14, 0xda, 0x0d, 0x93, | ||
180 | 0x04, 0xda, 0x05, 0x93, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
181 | 0x00, 0x02, 0x00 | ||
182 | }; | ||
183 | |||
184 | static unsigned char page_zero_v2[] __devinitdata = { | ||
185 | 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
186 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
187 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
188 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
189 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
190 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
191 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
192 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
193 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 | ||
194 | }; | ||
195 | |||
196 | static unsigned char page_one_v2[] __devinitdata = { | ||
197 | 0x01, 0xc0, 0x01, 0xfa, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
198 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
199 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
200 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
201 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
202 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
203 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
204 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
205 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 | ||
206 | }; | ||
207 | |||
208 | static unsigned char page_two_v2[] __devinitdata = { | ||
209 | 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
210 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
211 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
212 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
213 | 0x00, 0x00, 0x00, 0x00 | ||
214 | }; | ||
215 | static unsigned char page_three_v2[] __devinitdata = { | ||
216 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
217 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
218 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
219 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
220 | 0x00, 0x00, 0x00, 0x00 | ||
221 | }; | ||
222 | static unsigned char page_four_v2[] __devinitdata = { | ||
223 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
224 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
225 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
226 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
227 | 0x00, 0x00, 0x00, 0x00 | ||
228 | }; | ||
229 | 37 | ||
230 | static unsigned char page_seven_v2[] __devinitdata = { | 38 | #define FIRMWARE_IN_THE_KERNEL |
231 | 0x0f, 0xff, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
232 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
233 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
234 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
235 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
236 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
237 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
238 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
239 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 | ||
240 | }; | ||
241 | 39 | ||
242 | static unsigned char mod_v2[] __devinitdata = { | 40 | #ifdef FIRMWARE_IN_THE_KERNEL |
243 | 0x01, 0x00, 0x02, 0x00, 0x01, 0x01, 0x02, 0x00, 0x01, 0x02, 0x02, | 41 | #include "yss225.c" |
244 | 0x00, 0x01, 0x03, 0x02, 0x00, 0x01, 0x04, 0x02, 0x00, 0x01, 0x05, | 42 | static const struct firmware yss225_registers_firmware = { |
245 | 0x02, 0x00, 0x01, 0x06, 0x02, 0x00, 0x01, 0x07, 0x02, 0x00, 0xb0, | 43 | .data = (u8 *)yss225_registers, |
246 | 0x20, 0xb1, 0x20, 0xb2, 0x20, 0xb3, 0x20, 0xb4, 0x20, 0xb5, 0x20, | 44 | .size = sizeof yss225_registers |
247 | 0xb6, 0x20, 0xb7, 0x20, 0xf0, 0x20, 0xf1, 0x20, 0xf2, 0x20, 0xf3, | ||
248 | 0x20, 0xf4, 0x20, 0xf5, 0x20, 0xf6, 0x20, 0xf7, 0x20, 0x10, 0xff, | ||
249 | 0x11, 0xff, 0x12, 0xff, 0x13, 0xff, 0x14, 0xff, 0x15, 0xff, 0x16, | ||
250 | 0xff, 0x17, 0xff, 0x20, 0xff, 0x21, 0xff, 0x22, 0xff, 0x23, 0xff, | ||
251 | 0x24, 0xff, 0x25, 0xff, 0x26, 0xff, 0x27, 0xff, 0x30, 0x00, 0x31, | ||
252 | 0x00, 0x32, 0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00, 0x36, 0x00, | ||
253 | 0x37, 0x00, 0x40, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00, 0x44, | ||
254 | 0x00, 0x45, 0x00, 0x46, 0x00, 0x47, 0x00, 0x50, 0x00, 0x51, 0x00, | ||
255 | 0x52, 0x00, 0x53, 0x00, 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, | ||
256 | 0x00, 0x60, 0x00, 0x61, 0x00, 0x62, 0x00, 0x63, 0x00, 0x64, 0x00, | ||
257 | 0x65, 0x00, 0x66, 0x00, 0x67, 0x00, 0x70, 0xc0, 0x71, 0xc0, 0x72, | ||
258 | 0xc0, 0x73, 0xc0, 0x74, 0xc0, 0x75, 0xc0, 0x76, 0xc0, 0x77, 0xc0, | ||
259 | 0x80, 0x00, 0x81, 0x00, 0x82, 0x00, 0x83, 0x00, 0x84, 0x00, 0x85, | ||
260 | 0x00, 0x86, 0x00, 0x87, 0x00, 0x90, 0x00, 0x91, 0x00, 0x92, 0x00, | ||
261 | 0x93, 0x00, 0x94, 0x00, 0x95, 0x00, 0x96, 0x00, 0x97, 0x00, 0xa0, | ||
262 | 0x00, 0xa1, 0x00, 0xa2, 0x00, 0xa3, 0x00, 0xa4, 0x00, 0xa5, 0x00, | ||
263 | 0xa6, 0x00, 0xa7, 0x00, 0xc0, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc3, | ||
264 | 0x00, 0xc4, 0x00, 0xc5, 0x00, 0xc6, 0x00, 0xc7, 0x00, 0xd0, 0x00, | ||
265 | 0xd1, 0x00, 0xd2, 0x00, 0xd3, 0x00, 0xd4, 0x00, 0xd5, 0x00, 0xd6, | ||
266 | 0x00, 0xd7, 0x00, 0xe0, 0x00, 0xe1, 0x00, 0xe2, 0x00, 0xe3, 0x00, | ||
267 | 0xe4, 0x00, 0xe5, 0x00, 0xe6, 0x00, 0xe7, 0x00, 0x01, 0x00, 0x02, | ||
268 | 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x02, 0x02, 0x01, 0x01, 0x03, | ||
269 | 0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x05, 0x02, 0x01, 0x01, | ||
270 | 0x06, 0x02, 0x01, 0x01, 0x07, 0x02, 0x01 | ||
271 | }; | ||
272 | static unsigned char coefficients[] __devinitdata = { | ||
273 | 0x07, 0x46, 0x00, 0x00, 0x07, 0x49, 0x00, 0x00, 0x00, 0x4b, 0x03, | ||
274 | 0x11, 0x00, 0x4d, 0x01, 0x32, 0x07, 0x46, 0x00, 0x00, 0x07, 0x49, | ||
275 | 0x00, 0x00, 0x07, 0x40, 0x00, 0x00, 0x07, 0x41, 0x00, 0x00, 0x01, | ||
276 | 0x40, 0x02, 0x40, 0x01, 0x41, 0x02, 0x60, 0x07, 0x40, 0x00, 0x00, | ||
277 | 0x07, 0x41, 0x00, 0x00, 0x07, 0x47, 0x00, 0x00, 0x07, 0x4a, 0x00, | ||
278 | 0x00, 0x00, 0x47, 0x01, 0x00, 0x00, 0x4a, 0x01, 0x20, 0x07, 0x47, | ||
279 | 0x00, 0x00, 0x07, 0x4a, 0x00, 0x00, 0x07, 0x7c, 0x00, 0x00, 0x07, | ||
280 | 0x7e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x1c, 0x07, 0x7c, 0x00, 0x00, | ||
281 | 0x07, 0x7e, 0x00, 0x00, 0x07, 0x44, 0x00, 0x00, 0x00, 0x44, 0x01, | ||
282 | 0x00, 0x07, 0x44, 0x00, 0x00, 0x07, 0x42, 0x00, 0x00, 0x07, 0x43, | ||
283 | 0x00, 0x00, 0x00, 0x42, 0x01, 0x1a, 0x00, 0x43, 0x01, 0x20, 0x07, | ||
284 | 0x42, 0x00, 0x00, 0x07, 0x43, 0x00, 0x00, 0x07, 0x40, 0x00, 0x00, | ||
285 | 0x07, 0x41, 0x00, 0x00, 0x01, 0x40, 0x02, 0x40, 0x01, 0x41, 0x02, | ||
286 | 0x60, 0x07, 0x40, 0x00, 0x00, 0x07, 0x41, 0x00, 0x00, 0x07, 0x44, | ||
287 | 0x0f, 0xff, 0x07, 0x42, 0x00, 0x00, 0x07, 0x43, 0x00, 0x00, 0x07, | ||
288 | 0x40, 0x00, 0x00, 0x07, 0x41, 0x00, 0x00, 0x07, 0x51, 0x06, 0x40, | ||
289 | 0x07, 0x50, 0x06, 0x40, 0x07, 0x4f, 0x03, 0x81, 0x07, 0x53, 0x1a, | ||
290 | 0x76, 0x07, 0x54, 0x0d, 0x8b, 0x07, 0x55, 0x04, 0xe9, 0x07, 0x56, | ||
291 | 0x0b, 0x17, 0x07, 0x57, 0x1a, 0x38, 0x07, 0x58, 0x0d, 0xc9, 0x07, | ||
292 | 0x59, 0x04, 0x6f, 0x07, 0x5a, 0x0b, 0x91, 0x07, 0x73, 0x14, 0xda, | ||
293 | 0x07, 0x74, 0x0d, 0x93, 0x07, 0x75, 0x04, 0xd9, 0x07, 0x76, 0x05, | ||
294 | 0x93, 0x07, 0x77, 0x14, 0xda, 0x07, 0x78, 0x0d, 0x93, 0x07, 0x79, | ||
295 | 0x04, 0xd9, 0x07, 0x7a, 0x05, 0x93, 0x07, 0x5e, 0x03, 0x68, 0x07, | ||
296 | 0x5c, 0x04, 0x31, 0x07, 0x5d, 0x04, 0x31, 0x07, 0x62, 0x03, 0x52, | ||
297 | 0x07, 0x60, 0x04, 0x76, 0x07, 0x61, 0x04, 0x76, 0x07, 0x66, 0x03, | ||
298 | 0x2e, 0x07, 0x64, 0x04, 0xda, 0x07, 0x65, 0x04, 0xda, 0x07, 0x6a, | ||
299 | 0x02, 0xf6, 0x07, 0x68, 0x05, 0x62, 0x07, 0x69, 0x05, 0x62, 0x06, | ||
300 | 0x46, 0x0a, 0x22, 0x06, 0x48, 0x0d, 0x24, 0x06, 0x6e, 0x11, 0xd3, | ||
301 | 0x06, 0x70, 0x15, 0xcb, 0x06, 0x52, 0x20, 0x93, 0x06, 0x54, 0x20, | ||
302 | 0x54, 0x06, 0x4a, 0x27, 0x1d, 0x06, 0x58, 0x2f, 0xc8, 0x06, 0x5c, | ||
303 | 0x30, 0x07, 0x06, 0x4c, 0x37, 0x90, 0x06, 0x60, 0x3d, 0xdb, 0x06, | ||
304 | 0x64, 0x3e, 0x42, 0x06, 0x4e, 0x45, 0x78, 0x06, 0x68, 0x4c, 0x48, | ||
305 | 0x06, 0x6c, 0x4c, 0x6c, 0x06, 0x50, 0x52, 0xe2, 0x06, 0x42, 0x02, | ||
306 | 0xba | ||
307 | }; | ||
308 | static unsigned char coefficients2[] __devinitdata = { | ||
309 | 0x07, 0x46, 0x00, 0x00, 0x07, 0x49, 0x00, 0x00, 0x07, 0x45, 0x0f, | ||
310 | 0xff, 0x07, 0x48, 0x0f, 0xff, 0x07, 0x7b, 0x04, 0xcc, 0x07, 0x7d, | ||
311 | 0x04, 0xcc, 0x07, 0x7c, 0x00, 0x00, 0x07, 0x7e, 0x00, 0x00, 0x07, | ||
312 | 0x46, 0x00, 0x00, 0x07, 0x49, 0x00, 0x00, 0x07, 0x47, 0x00, 0x00, | ||
313 | 0x07, 0x4a, 0x00, 0x00, 0x07, 0x4c, 0x00, 0x00, 0x07, 0x4e, 0x00, 0x00 | ||
314 | }; | ||
315 | static unsigned char coefficients3[] __devinitdata = { | ||
316 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x28, 0x00, 0x51, 0x00, | ||
317 | 0x51, 0x00, 0x7a, 0x00, 0x7a, 0x00, 0xa3, 0x00, 0xa3, 0x00, 0xcc, | ||
318 | 0x00, 0xcc, 0x00, 0xf5, 0x00, 0xf5, 0x01, 0x1e, 0x01, 0x1e, 0x01, | ||
319 | 0x47, 0x01, 0x47, 0x01, 0x70, 0x01, 0x70, 0x01, 0x99, 0x01, 0x99, | ||
320 | 0x01, 0xc2, 0x01, 0xc2, 0x01, 0xeb, 0x01, 0xeb, 0x02, 0x14, 0x02, | ||
321 | 0x14, 0x02, 0x3d, 0x02, 0x3d, 0x02, 0x66, 0x02, 0x66, 0x02, 0x8f, | ||
322 | 0x02, 0x8f, 0x02, 0xb8, 0x02, 0xb8, 0x02, 0xe1, 0x02, 0xe1, 0x03, | ||
323 | 0x0a, 0x03, 0x0a, 0x03, 0x33, 0x03, 0x33, 0x03, 0x5c, 0x03, 0x5c, | ||
324 | 0x03, 0x85, 0x03, 0x85, 0x03, 0xae, 0x03, 0xae, 0x03, 0xd7, 0x03, | ||
325 | 0xd7, 0x04, 0x00, 0x04, 0x00, 0x04, 0x28, 0x04, 0x28, 0x04, 0x51, | ||
326 | 0x04, 0x51, 0x04, 0x7a, 0x04, 0x7a, 0x04, 0xa3, 0x04, 0xa3, 0x04, | ||
327 | 0xcc, 0x04, 0xcc, 0x04, 0xf5, 0x04, 0xf5, 0x05, 0x1e, 0x05, 0x1e, | ||
328 | 0x05, 0x47, 0x05, 0x47, 0x05, 0x70, 0x05, 0x70, 0x05, 0x99, 0x05, | ||
329 | 0x99, 0x05, 0xc2, 0x05, 0xc2, 0x05, 0xeb, 0x05, 0xeb, 0x06, 0x14, | ||
330 | 0x06, 0x14, 0x06, 0x3d, 0x06, 0x3d, 0x06, 0x66, 0x06, 0x66, 0x06, | ||
331 | 0x8f, 0x06, 0x8f, 0x06, 0xb8, 0x06, 0xb8, 0x06, 0xe1, 0x06, 0xe1, | ||
332 | 0x07, 0x0a, 0x07, 0x0a, 0x07, 0x33, 0x07, 0x33, 0x07, 0x5c, 0x07, | ||
333 | 0x5c, 0x07, 0x85, 0x07, 0x85, 0x07, 0xae, 0x07, 0xae, 0x07, 0xd7, | ||
334 | 0x07, 0xd7, 0x08, 0x00, 0x08, 0x00, 0x08, 0x28, 0x08, 0x28, 0x08, | ||
335 | 0x51, 0x08, 0x51, 0x08, 0x7a, 0x08, 0x7a, 0x08, 0xa3, 0x08, 0xa3, | ||
336 | 0x08, 0xcc, 0x08, 0xcc, 0x08, 0xf5, 0x08, 0xf5, 0x09, 0x1e, 0x09, | ||
337 | 0x1e, 0x09, 0x47, 0x09, 0x47, 0x09, 0x70, 0x09, 0x70, 0x09, 0x99, | ||
338 | 0x09, 0x99, 0x09, 0xc2, 0x09, 0xc2, 0x09, 0xeb, 0x09, 0xeb, 0x0a, | ||
339 | 0x14, 0x0a, 0x14, 0x0a, 0x3d, 0x0a, 0x3d, 0x0a, 0x66, 0x0a, 0x66, | ||
340 | 0x0a, 0x8f, 0x0a, 0x8f, 0x0a, 0xb8, 0x0a, 0xb8, 0x0a, 0xe1, 0x0a, | ||
341 | 0xe1, 0x0b, 0x0a, 0x0b, 0x0a, 0x0b, 0x33, 0x0b, 0x33, 0x0b, 0x5c, | ||
342 | 0x0b, 0x5c, 0x0b, 0x85, 0x0b, 0x85, 0x0b, 0xae, 0x0b, 0xae, 0x0b, | ||
343 | 0xd7, 0x0b, 0xd7, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x28, 0x0c, 0x28, | ||
344 | 0x0c, 0x51, 0x0c, 0x51, 0x0c, 0x7a, 0x0c, 0x7a, 0x0c, 0xa3, 0x0c, | ||
345 | 0xa3, 0x0c, 0xcc, 0x0c, 0xcc, 0x0c, 0xf5, 0x0c, 0xf5, 0x0d, 0x1e, | ||
346 | 0x0d, 0x1e, 0x0d, 0x47, 0x0d, 0x47, 0x0d, 0x70, 0x0d, 0x70, 0x0d, | ||
347 | 0x99, 0x0d, 0x99, 0x0d, 0xc2, 0x0d, 0xc2, 0x0d, 0xeb, 0x0d, 0xeb, | ||
348 | 0x0e, 0x14, 0x0e, 0x14, 0x0e, 0x3d, 0x0e, 0x3d, 0x0e, 0x66, 0x0e, | ||
349 | 0x66, 0x0e, 0x8f, 0x0e, 0x8f, 0x0e, 0xb8, 0x0e, 0xb8, 0x0e, 0xe1, | ||
350 | 0x0e, 0xe1, 0x0f, 0x0a, 0x0f, 0x0a, 0x0f, 0x33, 0x0f, 0x33, 0x0f, | ||
351 | 0x5c, 0x0f, 0x5c, 0x0f, 0x85, 0x0f, 0x85, 0x0f, 0xae, 0x0f, 0xae, | ||
352 | 0x0f, 0xd7, 0x0f, 0xd7, 0x0f, 0xff, 0x0f, 0xff | ||
353 | }; | 45 | }; |
46 | #endif | ||
354 | 47 | ||
355 | static int | 48 | static int |
356 | wavefront_fx_idle (snd_wavefront_t *dev) | 49 | wavefront_fx_idle (snd_wavefront_t *dev) |
@@ -555,465 +248,56 @@ snd_wavefront_fx_ioctl (struct snd_hwdep *sdev, struct file *file, | |||
555 | of the port I/O done, using the Yamaha faxback document as a guide | 248 | of the port I/O done, using the Yamaha faxback document as a guide |
556 | to add more logic to the code. Its really pretty weird. | 249 | to add more logic to the code. Its really pretty weird. |
557 | 250 | ||
558 | There was an alternative approach of just dumping the whole I/O | 251 | This is the approach of just dumping the whole I/O |
559 | sequence as a series of port/value pairs and a simple loop | 252 | sequence as a series of port/value pairs and a simple loop |
560 | that output it. However, I hope that eventually I'll get more | 253 | that outputs it. |
561 | control over what this code does, and so I tried to stick with | ||
562 | a somewhat "algorithmic" approach. | ||
563 | */ | 254 | */ |
564 | 255 | ||
565 | |||
566 | int __devinit | 256 | int __devinit |
567 | snd_wavefront_fx_start (snd_wavefront_t *dev) | 257 | snd_wavefront_fx_start (snd_wavefront_t *dev) |
568 | |||
569 | { | 258 | { |
570 | unsigned int i, j; | 259 | unsigned int i; |
260 | int err; | ||
261 | const struct firmware *firmware; | ||
571 | 262 | ||
572 | /* Set all bits for all channels on the MOD unit to zero */ | 263 | if (dev->fx_initialized) |
573 | /* XXX But why do this twice ? */ | 264 | return 0; |
574 | 265 | ||
575 | for (j = 0; j < 2; j++) { | 266 | err = request_firmware(&firmware, "yamaha/yss225_registers.bin", |
576 | for (i = 0x10; i <= 0xff; i++) { | 267 | dev->card->dev); |
577 | 268 | if (err < 0) { | |
578 | if (!wavefront_fx_idle (dev)) { | 269 | #ifdef FIRMWARE_IN_THE_KERNEL |
579 | return (-1); | 270 | firmware = &yss225_registers_firmware; |
271 | #else | ||
272 | err = -1; | ||
273 | goto out; | ||
274 | #endif | ||
275 | } | ||
276 | |||
277 | for (i = 0; i + 1 < firmware->size; i += 2) { | ||
278 | if (firmware->data[i] >= 8 && firmware->data[i] < 16) { | ||
279 | outb(firmware->data[i + 1], | ||
280 | dev->base + firmware->data[i]); | ||
281 | } else if (firmware->data[i] == WAIT_IDLE) { | ||
282 | if (!wavefront_fx_idle(dev)) { | ||
283 | err = -1; | ||
284 | goto out; | ||
580 | } | 285 | } |
581 | 286 | } else { | |
582 | outb (i, dev->fx_mod_addr); | 287 | snd_printk(KERN_ERR "invalid address" |
583 | outb (0x0, dev->fx_mod_data); | 288 | " in register data\n"); |
584 | } | 289 | err = -1; |
585 | } | 290 | goto out; |
586 | |||
587 | if (!wavefront_fx_idle (dev)) return (-1); | ||
588 | outb (0x02, dev->fx_op); /* mute on */ | ||
589 | |||
590 | if (!wavefront_fx_idle (dev)) return (-1); | ||
591 | outb (0x07, dev->fx_dsp_page); | ||
592 | outb (0x44, dev->fx_dsp_addr); | ||
593 | outb (0x00, dev->fx_dsp_msb); | ||
594 | outb (0x00, dev->fx_dsp_lsb); | ||
595 | if (!wavefront_fx_idle (dev)) return (-1); | ||
596 | outb (0x07, dev->fx_dsp_page); | ||
597 | outb (0x42, dev->fx_dsp_addr); | ||
598 | outb (0x00, dev->fx_dsp_msb); | ||
599 | outb (0x00, dev->fx_dsp_lsb); | ||
600 | if (!wavefront_fx_idle (dev)) return (-1); | ||
601 | outb (0x07, dev->fx_dsp_page); | ||
602 | outb (0x43, dev->fx_dsp_addr); | ||
603 | outb (0x00, dev->fx_dsp_msb); | ||
604 | outb (0x00, dev->fx_dsp_lsb); | ||
605 | if (!wavefront_fx_idle (dev)) return (-1); | ||
606 | outb (0x07, dev->fx_dsp_page); | ||
607 | outb (0x7c, dev->fx_dsp_addr); | ||
608 | outb (0x00, dev->fx_dsp_msb); | ||
609 | outb (0x00, dev->fx_dsp_lsb); | ||
610 | if (!wavefront_fx_idle (dev)) return (-1); | ||
611 | outb (0x07, dev->fx_dsp_page); | ||
612 | outb (0x7e, dev->fx_dsp_addr); | ||
613 | outb (0x00, dev->fx_dsp_msb); | ||
614 | outb (0x00, dev->fx_dsp_lsb); | ||
615 | if (!wavefront_fx_idle (dev)) return (-1); | ||
616 | outb (0x07, dev->fx_dsp_page); | ||
617 | outb (0x46, dev->fx_dsp_addr); | ||
618 | outb (0x00, dev->fx_dsp_msb); | ||
619 | outb (0x00, dev->fx_dsp_lsb); | ||
620 | if (!wavefront_fx_idle (dev)) return (-1); | ||
621 | outb (0x07, dev->fx_dsp_page); | ||
622 | outb (0x49, dev->fx_dsp_addr); | ||
623 | outb (0x00, dev->fx_dsp_msb); | ||
624 | outb (0x00, dev->fx_dsp_lsb); | ||
625 | if (!wavefront_fx_idle (dev)) return (-1); | ||
626 | outb (0x07, dev->fx_dsp_page); | ||
627 | outb (0x47, dev->fx_dsp_addr); | ||
628 | outb (0x00, dev->fx_dsp_msb); | ||
629 | outb (0x00, dev->fx_dsp_lsb); | ||
630 | if (!wavefront_fx_idle (dev)) return (-1); | ||
631 | outb (0x07, dev->fx_dsp_page); | ||
632 | outb (0x4a, dev->fx_dsp_addr); | ||
633 | outb (0x00, dev->fx_dsp_msb); | ||
634 | outb (0x00, dev->fx_dsp_lsb); | ||
635 | |||
636 | /* either because of stupidity by TB's programmers, or because it | ||
637 | actually does something, rezero the MOD page. | ||
638 | */ | ||
639 | for (i = 0x10; i <= 0xff; i++) { | ||
640 | |||
641 | if (!wavefront_fx_idle (dev)) { | ||
642 | return (-1); | ||
643 | } | 291 | } |
644 | |||
645 | outb (i, dev->fx_mod_addr); | ||
646 | outb (0x0, dev->fx_mod_data); | ||
647 | } | ||
648 | /* load page zero */ | ||
649 | |||
650 | outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr); | ||
651 | outb (0x00, dev->fx_dsp_page); | ||
652 | outb (0x00, dev->fx_dsp_addr); | ||
653 | |||
654 | for (i = 0; i < sizeof (page_zero); i += 2) { | ||
655 | outb (page_zero[i], dev->fx_dsp_msb); | ||
656 | outb (page_zero[i+1], dev->fx_dsp_lsb); | ||
657 | if (!wavefront_fx_idle (dev)) return (-1); | ||
658 | } | ||
659 | |||
660 | /* Now load page one */ | ||
661 | |||
662 | outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr); | ||
663 | outb (0x01, dev->fx_dsp_page); | ||
664 | outb (0x00, dev->fx_dsp_addr); | ||
665 | |||
666 | for (i = 0; i < sizeof (page_one); i += 2) { | ||
667 | outb (page_one[i], dev->fx_dsp_msb); | ||
668 | outb (page_one[i+1], dev->fx_dsp_lsb); | ||
669 | if (!wavefront_fx_idle (dev)) return (-1); | ||
670 | } | ||
671 | |||
672 | outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr); | ||
673 | outb (0x02, dev->fx_dsp_page); | ||
674 | outb (0x00, dev->fx_dsp_addr); | ||
675 | |||
676 | for (i = 0; i < sizeof (page_two); i++) { | ||
677 | outb (page_two[i], dev->fx_dsp_lsb); | ||
678 | if (!wavefront_fx_idle (dev)) return (-1); | ||
679 | } | ||
680 | |||
681 | outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr); | ||
682 | outb (0x03, dev->fx_dsp_page); | ||
683 | outb (0x00, dev->fx_dsp_addr); | ||
684 | |||
685 | for (i = 0; i < sizeof (page_three); i++) { | ||
686 | outb (page_three[i], dev->fx_dsp_lsb); | ||
687 | if (!wavefront_fx_idle (dev)) return (-1); | ||
688 | } | ||
689 | |||
690 | outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr); | ||
691 | outb (0x04, dev->fx_dsp_page); | ||
692 | outb (0x00, dev->fx_dsp_addr); | ||
693 | |||
694 | for (i = 0; i < sizeof (page_four); i++) { | ||
695 | outb (page_four[i], dev->fx_dsp_lsb); | ||
696 | if (!wavefront_fx_idle (dev)) return (-1); | ||
697 | } | ||
698 | |||
699 | /* Load memory area (page six) */ | ||
700 | |||
701 | outb (FX_LSB_TRANSFER, dev->fx_lcr); | ||
702 | outb (0x06, dev->fx_dsp_page); | ||
703 | |||
704 | for (i = 0; i < sizeof (page_six); i += 3) { | ||
705 | outb (page_six[i], dev->fx_dsp_addr); | ||
706 | outb (page_six[i+1], dev->fx_dsp_msb); | ||
707 | outb (page_six[i+2], dev->fx_dsp_lsb); | ||
708 | if (!wavefront_fx_idle (dev)) return (-1); | ||
709 | } | ||
710 | |||
711 | outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr); | ||
712 | outb (0x07, dev->fx_dsp_page); | ||
713 | outb (0x00, dev->fx_dsp_addr); | ||
714 | |||
715 | for (i = 0; i < sizeof (page_seven); i += 2) { | ||
716 | outb (page_seven[i], dev->fx_dsp_msb); | ||
717 | outb (page_seven[i+1], dev->fx_dsp_lsb); | ||
718 | if (!wavefront_fx_idle (dev)) return (-1); | ||
719 | } | ||
720 | |||
721 | /* Now setup the MOD area. We do this algorithmically in order to | ||
722 | save a little data space. It could be done in the same fashion | ||
723 | as the "pages". | ||
724 | */ | ||
725 | |||
726 | for (i = 0x00; i <= 0x0f; i++) { | ||
727 | outb (0x01, dev->fx_mod_addr); | ||
728 | outb (i, dev->fx_mod_data); | ||
729 | if (!wavefront_fx_idle (dev)) return (-1); | ||
730 | outb (0x02, dev->fx_mod_addr); | ||
731 | outb (0x00, dev->fx_mod_data); | ||
732 | if (!wavefront_fx_idle (dev)) return (-1); | ||
733 | } | ||
734 | |||
735 | for (i = 0xb0; i <= 0xbf; i++) { | ||
736 | outb (i, dev->fx_mod_addr); | ||
737 | outb (0x20, dev->fx_mod_data); | ||
738 | if (!wavefront_fx_idle (dev)) return (-1); | ||
739 | } | 292 | } |
740 | 293 | ||
741 | for (i = 0xf0; i <= 0xff; i++) { | 294 | dev->fx_initialized = 1; |
742 | outb (i, dev->fx_mod_addr); | 295 | err = 0; |
743 | outb (0x20, dev->fx_mod_data); | ||
744 | if (!wavefront_fx_idle (dev)) return (-1); | ||
745 | } | ||
746 | |||
747 | for (i = 0x10; i <= 0x1d; i++) { | ||
748 | outb (i, dev->fx_mod_addr); | ||
749 | outb (0xff, dev->fx_mod_data); | ||
750 | if (!wavefront_fx_idle (dev)) return (-1); | ||
751 | } | ||
752 | |||
753 | outb (0x1e, dev->fx_mod_addr); | ||
754 | outb (0x40, dev->fx_mod_data); | ||
755 | if (!wavefront_fx_idle (dev)) return (-1); | ||
756 | |||
757 | for (i = 0x1f; i <= 0x2d; i++) { | ||
758 | outb (i, dev->fx_mod_addr); | ||
759 | outb (0xff, dev->fx_mod_data); | ||
760 | if (!wavefront_fx_idle (dev)) return (-1); | ||
761 | } | ||
762 | |||
763 | outb (0x2e, dev->fx_mod_addr); | ||
764 | outb (0x00, dev->fx_mod_data); | ||
765 | if (!wavefront_fx_idle (dev)) return (-1); | ||
766 | |||
767 | for (i = 0x2f; i <= 0x3e; i++) { | ||
768 | outb (i, dev->fx_mod_addr); | ||
769 | outb (0x00, dev->fx_mod_data); | ||
770 | if (!wavefront_fx_idle (dev)) return (-1); | ||
771 | } | ||
772 | |||
773 | outb (0x3f, dev->fx_mod_addr); | ||
774 | outb (0x20, dev->fx_mod_data); | ||
775 | if (!wavefront_fx_idle (dev)) return (-1); | ||
776 | |||
777 | for (i = 0x40; i <= 0x4d; i++) { | ||
778 | outb (i, dev->fx_mod_addr); | ||
779 | outb (0x00, dev->fx_mod_data); | ||
780 | if (!wavefront_fx_idle (dev)) return (-1); | ||
781 | } | ||
782 | |||
783 | outb (0x4e, dev->fx_mod_addr); | ||
784 | outb (0x0e, dev->fx_mod_data); | ||
785 | if (!wavefront_fx_idle (dev)) return (-1); | ||
786 | outb (0x4f, dev->fx_mod_addr); | ||
787 | outb (0x0e, dev->fx_mod_data); | ||
788 | if (!wavefront_fx_idle (dev)) return (-1); | ||
789 | |||
790 | |||
791 | for (i = 0x50; i <= 0x6b; i++) { | ||
792 | outb (i, dev->fx_mod_addr); | ||
793 | outb (0x00, dev->fx_mod_data); | ||
794 | if (!wavefront_fx_idle (dev)) return (-1); | ||
795 | } | ||
796 | |||
797 | outb (0x6c, dev->fx_mod_addr); | ||
798 | outb (0x40, dev->fx_mod_data); | ||
799 | if (!wavefront_fx_idle (dev)) return (-1); | ||
800 | |||
801 | outb (0x6d, dev->fx_mod_addr); | ||
802 | outb (0x00, dev->fx_mod_data); | ||
803 | if (!wavefront_fx_idle (dev)) return (-1); | ||
804 | |||
805 | outb (0x6e, dev->fx_mod_addr); | ||
806 | outb (0x40, dev->fx_mod_data); | ||
807 | if (!wavefront_fx_idle (dev)) return (-1); | ||
808 | |||
809 | outb (0x6f, dev->fx_mod_addr); | ||
810 | outb (0x40, dev->fx_mod_data); | ||
811 | if (!wavefront_fx_idle (dev)) return (-1); | ||
812 | |||
813 | for (i = 0x70; i <= 0x7f; i++) { | ||
814 | outb (i, dev->fx_mod_addr); | ||
815 | outb (0xc0, dev->fx_mod_data); | ||
816 | if (!wavefront_fx_idle (dev)) return (-1); | ||
817 | } | ||
818 | |||
819 | for (i = 0x80; i <= 0xaf; i++) { | ||
820 | outb (i, dev->fx_mod_addr); | ||
821 | outb (0x00, dev->fx_mod_data); | ||
822 | if (!wavefront_fx_idle (dev)) return (-1); | ||
823 | } | ||
824 | |||
825 | for (i = 0xc0; i <= 0xdd; i++) { | ||
826 | outb (i, dev->fx_mod_addr); | ||
827 | outb (0x00, dev->fx_mod_data); | ||
828 | if (!wavefront_fx_idle (dev)) return (-1); | ||
829 | } | ||
830 | |||
831 | outb (0xde, dev->fx_mod_addr); | ||
832 | outb (0x10, dev->fx_mod_data); | ||
833 | if (!wavefront_fx_idle (dev)) return (-1); | ||
834 | outb (0xdf, dev->fx_mod_addr); | ||
835 | outb (0x10, dev->fx_mod_data); | ||
836 | if (!wavefront_fx_idle (dev)) return (-1); | ||
837 | |||
838 | for (i = 0xe0; i <= 0xef; i++) { | ||
839 | outb (i, dev->fx_mod_addr); | ||
840 | outb (0x00, dev->fx_mod_data); | ||
841 | if (!wavefront_fx_idle (dev)) return (-1); | ||
842 | } | ||
843 | |||
844 | for (i = 0x00; i <= 0x0f; i++) { | ||
845 | outb (0x01, dev->fx_mod_addr); | ||
846 | outb (i, dev->fx_mod_data); | ||
847 | outb (0x02, dev->fx_mod_addr); | ||
848 | outb (0x01, dev->fx_mod_data); | ||
849 | if (!wavefront_fx_idle (dev)) return (-1); | ||
850 | } | ||
851 | |||
852 | outb (0x02, dev->fx_op); /* mute on */ | ||
853 | |||
854 | /* Now set the coefficients and so forth for the programs above */ | ||
855 | |||
856 | for (i = 0; i < sizeof (coefficients); i += 4) { | ||
857 | outb (coefficients[i], dev->fx_dsp_page); | ||
858 | outb (coefficients[i+1], dev->fx_dsp_addr); | ||
859 | outb (coefficients[i+2], dev->fx_dsp_msb); | ||
860 | outb (coefficients[i+3], dev->fx_dsp_lsb); | ||
861 | if (!wavefront_fx_idle (dev)) return (-1); | ||
862 | } | ||
863 | |||
864 | /* Some settings (?) that are too small to bundle into loops */ | ||
865 | |||
866 | if (!wavefront_fx_idle (dev)) return (-1); | ||
867 | outb (0x1e, dev->fx_mod_addr); | ||
868 | outb (0x14, dev->fx_mod_data); | ||
869 | if (!wavefront_fx_idle (dev)) return (-1); | ||
870 | outb (0xde, dev->fx_mod_addr); | ||
871 | outb (0x20, dev->fx_mod_data); | ||
872 | if (!wavefront_fx_idle (dev)) return (-1); | ||
873 | outb (0xdf, dev->fx_mod_addr); | ||
874 | outb (0x20, dev->fx_mod_data); | ||
875 | |||
876 | /* some more coefficients */ | ||
877 | |||
878 | if (!wavefront_fx_idle (dev)) return (-1); | ||
879 | outb (0x06, dev->fx_dsp_page); | ||
880 | outb (0x78, dev->fx_dsp_addr); | ||
881 | outb (0x00, dev->fx_dsp_msb); | ||
882 | outb (0x40, dev->fx_dsp_lsb); | ||
883 | if (!wavefront_fx_idle (dev)) return (-1); | ||
884 | outb (0x07, dev->fx_dsp_page); | ||
885 | outb (0x03, dev->fx_dsp_addr); | ||
886 | outb (0x0f, dev->fx_dsp_msb); | ||
887 | outb (0xff, dev->fx_dsp_lsb); | ||
888 | if (!wavefront_fx_idle (dev)) return (-1); | ||
889 | outb (0x07, dev->fx_dsp_page); | ||
890 | outb (0x0b, dev->fx_dsp_addr); | ||
891 | outb (0x0f, dev->fx_dsp_msb); | ||
892 | outb (0xff, dev->fx_dsp_lsb); | ||
893 | if (!wavefront_fx_idle (dev)) return (-1); | ||
894 | outb (0x07, dev->fx_dsp_page); | ||
895 | outb (0x02, dev->fx_dsp_addr); | ||
896 | outb (0x00, dev->fx_dsp_msb); | ||
897 | outb (0x00, dev->fx_dsp_lsb); | ||
898 | if (!wavefront_fx_idle (dev)) return (-1); | ||
899 | outb (0x07, dev->fx_dsp_page); | ||
900 | outb (0x0a, dev->fx_dsp_addr); | ||
901 | outb (0x00, dev->fx_dsp_msb); | ||
902 | outb (0x00, dev->fx_dsp_lsb); | ||
903 | if (!wavefront_fx_idle (dev)) return (-1); | ||
904 | outb (0x07, dev->fx_dsp_page); | ||
905 | outb (0x46, dev->fx_dsp_addr); | ||
906 | outb (0x00, dev->fx_dsp_msb); | ||
907 | outb (0x00, dev->fx_dsp_lsb); | ||
908 | if (!wavefront_fx_idle (dev)) return (-1); | ||
909 | outb (0x07, dev->fx_dsp_page); | ||
910 | outb (0x49, dev->fx_dsp_addr); | ||
911 | outb (0x00, dev->fx_dsp_msb); | ||
912 | outb (0x00, dev->fx_dsp_lsb); | ||
913 | |||
914 | /* Now, for some strange reason, lets reload every page | ||
915 | and all the coefficients over again. I have *NO* idea | ||
916 | why this is done. I do know that no sound is produced | ||
917 | is this phase is omitted. | ||
918 | */ | ||
919 | |||
920 | outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr); | ||
921 | outb (0x00, dev->fx_dsp_page); | ||
922 | outb (0x10, dev->fx_dsp_addr); | ||
923 | |||
924 | for (i = 0; i < sizeof (page_zero_v2); i += 2) { | ||
925 | outb (page_zero_v2[i], dev->fx_dsp_msb); | ||
926 | outb (page_zero_v2[i+1], dev->fx_dsp_lsb); | ||
927 | if (!wavefront_fx_idle (dev)) return (-1); | ||
928 | } | ||
929 | |||
930 | outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr); | ||
931 | outb (0x01, dev->fx_dsp_page); | ||
932 | outb (0x10, dev->fx_dsp_addr); | ||
933 | |||
934 | for (i = 0; i < sizeof (page_one_v2); i += 2) { | ||
935 | outb (page_one_v2[i], dev->fx_dsp_msb); | ||
936 | outb (page_one_v2[i+1], dev->fx_dsp_lsb); | ||
937 | if (!wavefront_fx_idle (dev)) return (-1); | ||
938 | } | ||
939 | |||
940 | if (!wavefront_fx_idle (dev)) return (-1); | ||
941 | if (!wavefront_fx_idle (dev)) return (-1); | ||
942 | |||
943 | outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr); | ||
944 | outb (0x02, dev->fx_dsp_page); | ||
945 | outb (0x10, dev->fx_dsp_addr); | ||
946 | |||
947 | for (i = 0; i < sizeof (page_two_v2); i++) { | ||
948 | outb (page_two_v2[i], dev->fx_dsp_lsb); | ||
949 | if (!wavefront_fx_idle (dev)) return (-1); | ||
950 | } | ||
951 | outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr); | ||
952 | outb (0x03, dev->fx_dsp_page); | ||
953 | outb (0x10, dev->fx_dsp_addr); | ||
954 | |||
955 | for (i = 0; i < sizeof (page_three_v2); i++) { | ||
956 | outb (page_three_v2[i], dev->fx_dsp_lsb); | ||
957 | if (!wavefront_fx_idle (dev)) return (-1); | ||
958 | } | ||
959 | |||
960 | outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr); | ||
961 | outb (0x04, dev->fx_dsp_page); | ||
962 | outb (0x10, dev->fx_dsp_addr); | ||
963 | |||
964 | for (i = 0; i < sizeof (page_four_v2); i++) { | ||
965 | outb (page_four_v2[i], dev->fx_dsp_lsb); | ||
966 | if (!wavefront_fx_idle (dev)) return (-1); | ||
967 | } | ||
968 | |||
969 | outb (FX_LSB_TRANSFER, dev->fx_lcr); | ||
970 | outb (0x06, dev->fx_dsp_page); | ||
971 | |||
972 | /* Page six v.2 is algorithmic */ | ||
973 | |||
974 | for (i = 0x10; i <= 0x3e; i += 2) { | ||
975 | outb (i, dev->fx_dsp_addr); | ||
976 | outb (0x00, dev->fx_dsp_msb); | ||
977 | outb (0x00, dev->fx_dsp_lsb); | ||
978 | if (!wavefront_fx_idle (dev)) return (-1); | ||
979 | } | ||
980 | |||
981 | outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr); | ||
982 | outb (0x07, dev->fx_dsp_page); | ||
983 | outb (0x10, dev->fx_dsp_addr); | ||
984 | |||
985 | for (i = 0; i < sizeof (page_seven_v2); i += 2) { | ||
986 | outb (page_seven_v2[i], dev->fx_dsp_msb); | ||
987 | outb (page_seven_v2[i+1], dev->fx_dsp_lsb); | ||
988 | if (!wavefront_fx_idle (dev)) return (-1); | ||
989 | } | ||
990 | |||
991 | for (i = 0x00; i < sizeof(mod_v2); i += 2) { | ||
992 | outb (mod_v2[i], dev->fx_mod_addr); | ||
993 | outb (mod_v2[i+1], dev->fx_mod_data); | ||
994 | if (!wavefront_fx_idle (dev)) return (-1); | ||
995 | } | ||
996 | 296 | ||
997 | for (i = 0; i < sizeof (coefficients2); i += 4) { | 297 | out: |
998 | outb (coefficients2[i], dev->fx_dsp_page); | 298 | #ifdef FIRMWARE_IN_THE_KERNEL |
999 | outb (coefficients2[i+1], dev->fx_dsp_addr); | 299 | if (firmware != &yss225_registers_firmware) |
1000 | outb (coefficients2[i+2], dev->fx_dsp_msb); | 300 | #endif |
1001 | outb (coefficients2[i+3], dev->fx_dsp_lsb); | 301 | release_firmware(firmware); |
1002 | if (!wavefront_fx_idle (dev)) return (-1); | 302 | return err; |
1003 | } | ||
1004 | |||
1005 | for (i = 0; i < sizeof (coefficients3); i += 2) { | ||
1006 | int x; | ||
1007 | |||
1008 | outb (0x07, dev->fx_dsp_page); | ||
1009 | x = (i % 4) ? 0x4e : 0x4c; | ||
1010 | outb (x, dev->fx_dsp_addr); | ||
1011 | outb (coefficients3[i], dev->fx_dsp_msb); | ||
1012 | outb (coefficients3[i+1], dev->fx_dsp_lsb); | ||
1013 | } | ||
1014 | |||
1015 | outb (0x00, dev->fx_op); /* mute off */ | ||
1016 | if (!wavefront_fx_idle (dev)) return (-1); | ||
1017 | |||
1018 | return (0); | ||
1019 | } | 303 | } |
diff --git a/sound/isa/wavefront/yss225.c b/sound/isa/wavefront/yss225.c new file mode 100644 index 000000000000..9f6be3ff8ecf --- /dev/null +++ b/sound/isa/wavefront/yss225.c | |||
@@ -0,0 +1,2739 @@ | |||
1 | /* | ||
2 | * Copyright (c) 1998-2002 by Paul Davis <pbd@op.net> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | */ | ||
18 | |||
19 | /* weird stuff, derived from port I/O tracing with dosemu */ | ||
20 | |||
21 | static const struct { | ||
22 | unsigned char addr; | ||
23 | unsigned char data; | ||
24 | } yss225_registers[] __devinitdata = { | ||
25 | /* Set all bits for all channels on the MOD unit to zero */ | ||
26 | { WAIT_IDLE }, { 0xe, 0x10 }, { 0xf, 0x00 }, | ||
27 | { WAIT_IDLE }, { 0xe, 0x11 }, { 0xf, 0x00 }, | ||
28 | { WAIT_IDLE }, { 0xe, 0x12 }, { 0xf, 0x00 }, | ||
29 | { WAIT_IDLE }, { 0xe, 0x13 }, { 0xf, 0x00 }, | ||
30 | { WAIT_IDLE }, { 0xe, 0x14 }, { 0xf, 0x00 }, | ||
31 | { WAIT_IDLE }, { 0xe, 0x15 }, { 0xf, 0x00 }, | ||
32 | { WAIT_IDLE }, { 0xe, 0x16 }, { 0xf, 0x00 }, | ||
33 | { WAIT_IDLE }, { 0xe, 0x17 }, { 0xf, 0x00 }, | ||
34 | { WAIT_IDLE }, { 0xe, 0x18 }, { 0xf, 0x00 }, | ||
35 | { WAIT_IDLE }, { 0xe, 0x19 }, { 0xf, 0x00 }, | ||
36 | { WAIT_IDLE }, { 0xe, 0x1a }, { 0xf, 0x00 }, | ||
37 | { WAIT_IDLE }, { 0xe, 0x1b }, { 0xf, 0x00 }, | ||
38 | { WAIT_IDLE }, { 0xe, 0x1c }, { 0xf, 0x00 }, | ||
39 | { WAIT_IDLE }, { 0xe, 0x1d }, { 0xf, 0x00 }, | ||
40 | { WAIT_IDLE }, { 0xe, 0x1e }, { 0xf, 0x00 }, | ||
41 | { WAIT_IDLE }, { 0xe, 0x1f }, { 0xf, 0x00 }, | ||
42 | { WAIT_IDLE }, { 0xe, 0x20 }, { 0xf, 0x00 }, | ||
43 | { WAIT_IDLE }, { 0xe, 0x21 }, { 0xf, 0x00 }, | ||
44 | { WAIT_IDLE }, { 0xe, 0x22 }, { 0xf, 0x00 }, | ||
45 | { WAIT_IDLE }, { 0xe, 0x23 }, { 0xf, 0x00 }, | ||
46 | { WAIT_IDLE }, { 0xe, 0x24 }, { 0xf, 0x00 }, | ||
47 | { WAIT_IDLE }, { 0xe, 0x25 }, { 0xf, 0x00 }, | ||
48 | { WAIT_IDLE }, { 0xe, 0x26 }, { 0xf, 0x00 }, | ||
49 | { WAIT_IDLE }, { 0xe, 0x27 }, { 0xf, 0x00 }, | ||
50 | { WAIT_IDLE }, { 0xe, 0x28 }, { 0xf, 0x00 }, | ||
51 | { WAIT_IDLE }, { 0xe, 0x29 }, { 0xf, 0x00 }, | ||
52 | { WAIT_IDLE }, { 0xe, 0x2a }, { 0xf, 0x00 }, | ||
53 | { WAIT_IDLE }, { 0xe, 0x2b }, { 0xf, 0x00 }, | ||
54 | { WAIT_IDLE }, { 0xe, 0x2c }, { 0xf, 0x00 }, | ||
55 | { WAIT_IDLE }, { 0xe, 0x2d }, { 0xf, 0x00 }, | ||
56 | { WAIT_IDLE }, { 0xe, 0x2e }, { 0xf, 0x00 }, | ||
57 | { WAIT_IDLE }, { 0xe, 0x2f }, { 0xf, 0x00 }, | ||
58 | { WAIT_IDLE }, { 0xe, 0x30 }, { 0xf, 0x00 }, | ||
59 | { WAIT_IDLE }, { 0xe, 0x31 }, { 0xf, 0x00 }, | ||
60 | { WAIT_IDLE }, { 0xe, 0x32 }, { 0xf, 0x00 }, | ||
61 | { WAIT_IDLE }, { 0xe, 0x33 }, { 0xf, 0x00 }, | ||
62 | { WAIT_IDLE }, { 0xe, 0x34 }, { 0xf, 0x00 }, | ||
63 | { WAIT_IDLE }, { 0xe, 0x35 }, { 0xf, 0x00 }, | ||
64 | { WAIT_IDLE }, { 0xe, 0x36 }, { 0xf, 0x00 }, | ||
65 | { WAIT_IDLE }, { 0xe, 0x37 }, { 0xf, 0x00 }, | ||
66 | { WAIT_IDLE }, { 0xe, 0x38 }, { 0xf, 0x00 }, | ||
67 | { WAIT_IDLE }, { 0xe, 0x39 }, { 0xf, 0x00 }, | ||
68 | { WAIT_IDLE }, { 0xe, 0x3a }, { 0xf, 0x00 }, | ||
69 | { WAIT_IDLE }, { 0xe, 0x3b }, { 0xf, 0x00 }, | ||
70 | { WAIT_IDLE }, { 0xe, 0x3c }, { 0xf, 0x00 }, | ||
71 | { WAIT_IDLE }, { 0xe, 0x3d }, { 0xf, 0x00 }, | ||
72 | { WAIT_IDLE }, { 0xe, 0x3e }, { 0xf, 0x00 }, | ||
73 | { WAIT_IDLE }, { 0xe, 0x3f }, { 0xf, 0x00 }, | ||
74 | { WAIT_IDLE }, { 0xe, 0x40 }, { 0xf, 0x00 }, | ||
75 | { WAIT_IDLE }, { 0xe, 0x41 }, { 0xf, 0x00 }, | ||
76 | { WAIT_IDLE }, { 0xe, 0x42 }, { 0xf, 0x00 }, | ||
77 | { WAIT_IDLE }, { 0xe, 0x43 }, { 0xf, 0x00 }, | ||
78 | { WAIT_IDLE }, { 0xe, 0x44 }, { 0xf, 0x00 }, | ||
79 | { WAIT_IDLE }, { 0xe, 0x45 }, { 0xf, 0x00 }, | ||
80 | { WAIT_IDLE }, { 0xe, 0x46 }, { 0xf, 0x00 }, | ||
81 | { WAIT_IDLE }, { 0xe, 0x47 }, { 0xf, 0x00 }, | ||
82 | { WAIT_IDLE }, { 0xe, 0x48 }, { 0xf, 0x00 }, | ||
83 | { WAIT_IDLE }, { 0xe, 0x49 }, { 0xf, 0x00 }, | ||
84 | { WAIT_IDLE }, { 0xe, 0x4a }, { 0xf, 0x00 }, | ||
85 | { WAIT_IDLE }, { 0xe, 0x4b }, { 0xf, 0x00 }, | ||
86 | { WAIT_IDLE }, { 0xe, 0x4c }, { 0xf, 0x00 }, | ||
87 | { WAIT_IDLE }, { 0xe, 0x4d }, { 0xf, 0x00 }, | ||
88 | { WAIT_IDLE }, { 0xe, 0x4e }, { 0xf, 0x00 }, | ||
89 | { WAIT_IDLE }, { 0xe, 0x4f }, { 0xf, 0x00 }, | ||
90 | { WAIT_IDLE }, { 0xe, 0x50 }, { 0xf, 0x00 }, | ||
91 | { WAIT_IDLE }, { 0xe, 0x51 }, { 0xf, 0x00 }, | ||
92 | { WAIT_IDLE }, { 0xe, 0x52 }, { 0xf, 0x00 }, | ||
93 | { WAIT_IDLE }, { 0xe, 0x53 }, { 0xf, 0x00 }, | ||
94 | { WAIT_IDLE }, { 0xe, 0x54 }, { 0xf, 0x00 }, | ||
95 | { WAIT_IDLE }, { 0xe, 0x55 }, { 0xf, 0x00 }, | ||
96 | { WAIT_IDLE }, { 0xe, 0x56 }, { 0xf, 0x00 }, | ||
97 | { WAIT_IDLE }, { 0xe, 0x57 }, { 0xf, 0x00 }, | ||
98 | { WAIT_IDLE }, { 0xe, 0x58 }, { 0xf, 0x00 }, | ||
99 | { WAIT_IDLE }, { 0xe, 0x59 }, { 0xf, 0x00 }, | ||
100 | { WAIT_IDLE }, { 0xe, 0x5a }, { 0xf, 0x00 }, | ||
101 | { WAIT_IDLE }, { 0xe, 0x5b }, { 0xf, 0x00 }, | ||
102 | { WAIT_IDLE }, { 0xe, 0x5c }, { 0xf, 0x00 }, | ||
103 | { WAIT_IDLE }, { 0xe, 0x5d }, { 0xf, 0x00 }, | ||
104 | { WAIT_IDLE }, { 0xe, 0x5e }, { 0xf, 0x00 }, | ||
105 | { WAIT_IDLE }, { 0xe, 0x5f }, { 0xf, 0x00 }, | ||
106 | { WAIT_IDLE }, { 0xe, 0x60 }, { 0xf, 0x00 }, | ||
107 | { WAIT_IDLE }, { 0xe, 0x61 }, { 0xf, 0x00 }, | ||
108 | { WAIT_IDLE }, { 0xe, 0x62 }, { 0xf, 0x00 }, | ||
109 | { WAIT_IDLE }, { 0xe, 0x63 }, { 0xf, 0x00 }, | ||
110 | { WAIT_IDLE }, { 0xe, 0x64 }, { 0xf, 0x00 }, | ||
111 | { WAIT_IDLE }, { 0xe, 0x65 }, { 0xf, 0x00 }, | ||
112 | { WAIT_IDLE }, { 0xe, 0x66 }, { 0xf, 0x00 }, | ||
113 | { WAIT_IDLE }, { 0xe, 0x67 }, { 0xf, 0x00 }, | ||
114 | { WAIT_IDLE }, { 0xe, 0x68 }, { 0xf, 0x00 }, | ||
115 | { WAIT_IDLE }, { 0xe, 0x69 }, { 0xf, 0x00 }, | ||
116 | { WAIT_IDLE }, { 0xe, 0x6a }, { 0xf, 0x00 }, | ||
117 | { WAIT_IDLE }, { 0xe, 0x6b }, { 0xf, 0x00 }, | ||
118 | { WAIT_IDLE }, { 0xe, 0x6c }, { 0xf, 0x00 }, | ||
119 | { WAIT_IDLE }, { 0xe, 0x6d }, { 0xf, 0x00 }, | ||
120 | { WAIT_IDLE }, { 0xe, 0x6e }, { 0xf, 0x00 }, | ||
121 | { WAIT_IDLE }, { 0xe, 0x6f }, { 0xf, 0x00 }, | ||
122 | { WAIT_IDLE }, { 0xe, 0x70 }, { 0xf, 0x00 }, | ||
123 | { WAIT_IDLE }, { 0xe, 0x71 }, { 0xf, 0x00 }, | ||
124 | { WAIT_IDLE }, { 0xe, 0x72 }, { 0xf, 0x00 }, | ||
125 | { WAIT_IDLE }, { 0xe, 0x73 }, { 0xf, 0x00 }, | ||
126 | { WAIT_IDLE }, { 0xe, 0x74 }, { 0xf, 0x00 }, | ||
127 | { WAIT_IDLE }, { 0xe, 0x75 }, { 0xf, 0x00 }, | ||
128 | { WAIT_IDLE }, { 0xe, 0x76 }, { 0xf, 0x00 }, | ||
129 | { WAIT_IDLE }, { 0xe, 0x77 }, { 0xf, 0x00 }, | ||
130 | { WAIT_IDLE }, { 0xe, 0x78 }, { 0xf, 0x00 }, | ||
131 | { WAIT_IDLE }, { 0xe, 0x79 }, { 0xf, 0x00 }, | ||
132 | { WAIT_IDLE }, { 0xe, 0x7a }, { 0xf, 0x00 }, | ||
133 | { WAIT_IDLE }, { 0xe, 0x7b }, { 0xf, 0x00 }, | ||
134 | { WAIT_IDLE }, { 0xe, 0x7c }, { 0xf, 0x00 }, | ||
135 | { WAIT_IDLE }, { 0xe, 0x7d }, { 0xf, 0x00 }, | ||
136 | { WAIT_IDLE }, { 0xe, 0x7e }, { 0xf, 0x00 }, | ||
137 | { WAIT_IDLE }, { 0xe, 0x7f }, { 0xf, 0x00 }, | ||
138 | { WAIT_IDLE }, { 0xe, 0x80 }, { 0xf, 0x00 }, | ||
139 | { WAIT_IDLE }, { 0xe, 0x81 }, { 0xf, 0x00 }, | ||
140 | { WAIT_IDLE }, { 0xe, 0x82 }, { 0xf, 0x00 }, | ||
141 | { WAIT_IDLE }, { 0xe, 0x83 }, { 0xf, 0x00 }, | ||
142 | { WAIT_IDLE }, { 0xe, 0x84 }, { 0xf, 0x00 }, | ||
143 | { WAIT_IDLE }, { 0xe, 0x85 }, { 0xf, 0x00 }, | ||
144 | { WAIT_IDLE }, { 0xe, 0x86 }, { 0xf, 0x00 }, | ||
145 | { WAIT_IDLE }, { 0xe, 0x87 }, { 0xf, 0x00 }, | ||
146 | { WAIT_IDLE }, { 0xe, 0x88 }, { 0xf, 0x00 }, | ||
147 | { WAIT_IDLE }, { 0xe, 0x89 }, { 0xf, 0x00 }, | ||
148 | { WAIT_IDLE }, { 0xe, 0x8a }, { 0xf, 0x00 }, | ||
149 | { WAIT_IDLE }, { 0xe, 0x8b }, { 0xf, 0x00 }, | ||
150 | { WAIT_IDLE }, { 0xe, 0x8c }, { 0xf, 0x00 }, | ||
151 | { WAIT_IDLE }, { 0xe, 0x8d }, { 0xf, 0x00 }, | ||
152 | { WAIT_IDLE }, { 0xe, 0x8e }, { 0xf, 0x00 }, | ||
153 | { WAIT_IDLE }, { 0xe, 0x8f }, { 0xf, 0x00 }, | ||
154 | { WAIT_IDLE }, { 0xe, 0x90 }, { 0xf, 0x00 }, | ||
155 | { WAIT_IDLE }, { 0xe, 0x91 }, { 0xf, 0x00 }, | ||
156 | { WAIT_IDLE }, { 0xe, 0x92 }, { 0xf, 0x00 }, | ||
157 | { WAIT_IDLE }, { 0xe, 0x93 }, { 0xf, 0x00 }, | ||
158 | { WAIT_IDLE }, { 0xe, 0x94 }, { 0xf, 0x00 }, | ||
159 | { WAIT_IDLE }, { 0xe, 0x95 }, { 0xf, 0x00 }, | ||
160 | { WAIT_IDLE }, { 0xe, 0x96 }, { 0xf, 0x00 }, | ||
161 | { WAIT_IDLE }, { 0xe, 0x97 }, { 0xf, 0x00 }, | ||
162 | { WAIT_IDLE }, { 0xe, 0x98 }, { 0xf, 0x00 }, | ||
163 | { WAIT_IDLE }, { 0xe, 0x99 }, { 0xf, 0x00 }, | ||
164 | { WAIT_IDLE }, { 0xe, 0x9a }, { 0xf, 0x00 }, | ||
165 | { WAIT_IDLE }, { 0xe, 0x9b }, { 0xf, 0x00 }, | ||
166 | { WAIT_IDLE }, { 0xe, 0x9c }, { 0xf, 0x00 }, | ||
167 | { WAIT_IDLE }, { 0xe, 0x9d }, { 0xf, 0x00 }, | ||
168 | { WAIT_IDLE }, { 0xe, 0x9e }, { 0xf, 0x00 }, | ||
169 | { WAIT_IDLE }, { 0xe, 0x9f }, { 0xf, 0x00 }, | ||
170 | { WAIT_IDLE }, { 0xe, 0xa0 }, { 0xf, 0x00 }, | ||
171 | { WAIT_IDLE }, { 0xe, 0xa1 }, { 0xf, 0x00 }, | ||
172 | { WAIT_IDLE }, { 0xe, 0xa2 }, { 0xf, 0x00 }, | ||
173 | { WAIT_IDLE }, { 0xe, 0xa3 }, { 0xf, 0x00 }, | ||
174 | { WAIT_IDLE }, { 0xe, 0xa4 }, { 0xf, 0x00 }, | ||
175 | { WAIT_IDLE }, { 0xe, 0xa5 }, { 0xf, 0x00 }, | ||
176 | { WAIT_IDLE }, { 0xe, 0xa6 }, { 0xf, 0x00 }, | ||
177 | { WAIT_IDLE }, { 0xe, 0xa7 }, { 0xf, 0x00 }, | ||
178 | { WAIT_IDLE }, { 0xe, 0xa8 }, { 0xf, 0x00 }, | ||
179 | { WAIT_IDLE }, { 0xe, 0xa9 }, { 0xf, 0x00 }, | ||
180 | { WAIT_IDLE }, { 0xe, 0xaa }, { 0xf, 0x00 }, | ||
181 | { WAIT_IDLE }, { 0xe, 0xab }, { 0xf, 0x00 }, | ||
182 | { WAIT_IDLE }, { 0xe, 0xac }, { 0xf, 0x00 }, | ||
183 | { WAIT_IDLE }, { 0xe, 0xad }, { 0xf, 0x00 }, | ||
184 | { WAIT_IDLE }, { 0xe, 0xae }, { 0xf, 0x00 }, | ||
185 | { WAIT_IDLE }, { 0xe, 0xaf }, { 0xf, 0x00 }, | ||
186 | { WAIT_IDLE }, { 0xe, 0xb0 }, { 0xf, 0x00 }, | ||
187 | { WAIT_IDLE }, { 0xe, 0xb1 }, { 0xf, 0x00 }, | ||
188 | { WAIT_IDLE }, { 0xe, 0xb2 }, { 0xf, 0x00 }, | ||
189 | { WAIT_IDLE }, { 0xe, 0xb3 }, { 0xf, 0x00 }, | ||
190 | { WAIT_IDLE }, { 0xe, 0xb4 }, { 0xf, 0x00 }, | ||
191 | { WAIT_IDLE }, { 0xe, 0xb5 }, { 0xf, 0x00 }, | ||
192 | { WAIT_IDLE }, { 0xe, 0xb6 }, { 0xf, 0x00 }, | ||
193 | { WAIT_IDLE }, { 0xe, 0xb7 }, { 0xf, 0x00 }, | ||
194 | { WAIT_IDLE }, { 0xe, 0xb8 }, { 0xf, 0x00 }, | ||
195 | { WAIT_IDLE }, { 0xe, 0xb9 }, { 0xf, 0x00 }, | ||
196 | { WAIT_IDLE }, { 0xe, 0xba }, { 0xf, 0x00 }, | ||
197 | { WAIT_IDLE }, { 0xe, 0xbb }, { 0xf, 0x00 }, | ||
198 | { WAIT_IDLE }, { 0xe, 0xbc }, { 0xf, 0x00 }, | ||
199 | { WAIT_IDLE }, { 0xe, 0xbd }, { 0xf, 0x00 }, | ||
200 | { WAIT_IDLE }, { 0xe, 0xbe }, { 0xf, 0x00 }, | ||
201 | { WAIT_IDLE }, { 0xe, 0xbf }, { 0xf, 0x00 }, | ||
202 | { WAIT_IDLE }, { 0xe, 0xc0 }, { 0xf, 0x00 }, | ||
203 | { WAIT_IDLE }, { 0xe, 0xc1 }, { 0xf, 0x00 }, | ||
204 | { WAIT_IDLE }, { 0xe, 0xc2 }, { 0xf, 0x00 }, | ||
205 | { WAIT_IDLE }, { 0xe, 0xc3 }, { 0xf, 0x00 }, | ||
206 | { WAIT_IDLE }, { 0xe, 0xc4 }, { 0xf, 0x00 }, | ||
207 | { WAIT_IDLE }, { 0xe, 0xc5 }, { 0xf, 0x00 }, | ||
208 | { WAIT_IDLE }, { 0xe, 0xc6 }, { 0xf, 0x00 }, | ||
209 | { WAIT_IDLE }, { 0xe, 0xc7 }, { 0xf, 0x00 }, | ||
210 | { WAIT_IDLE }, { 0xe, 0xc8 }, { 0xf, 0x00 }, | ||
211 | { WAIT_IDLE }, { 0xe, 0xc9 }, { 0xf, 0x00 }, | ||
212 | { WAIT_IDLE }, { 0xe, 0xca }, { 0xf, 0x00 }, | ||
213 | { WAIT_IDLE }, { 0xe, 0xcb }, { 0xf, 0x00 }, | ||
214 | { WAIT_IDLE }, { 0xe, 0xcc }, { 0xf, 0x00 }, | ||
215 | { WAIT_IDLE }, { 0xe, 0xcd }, { 0xf, 0x00 }, | ||
216 | { WAIT_IDLE }, { 0xe, 0xce }, { 0xf, 0x00 }, | ||
217 | { WAIT_IDLE }, { 0xe, 0xcf }, { 0xf, 0x00 }, | ||
218 | { WAIT_IDLE }, { 0xe, 0xd0 }, { 0xf, 0x00 }, | ||
219 | { WAIT_IDLE }, { 0xe, 0xd1 }, { 0xf, 0x00 }, | ||
220 | { WAIT_IDLE }, { 0xe, 0xd2 }, { 0xf, 0x00 }, | ||
221 | { WAIT_IDLE }, { 0xe, 0xd3 }, { 0xf, 0x00 }, | ||
222 | { WAIT_IDLE }, { 0xe, 0xd4 }, { 0xf, 0x00 }, | ||
223 | { WAIT_IDLE }, { 0xe, 0xd5 }, { 0xf, 0x00 }, | ||
224 | { WAIT_IDLE }, { 0xe, 0xd6 }, { 0xf, 0x00 }, | ||
225 | { WAIT_IDLE }, { 0xe, 0xd7 }, { 0xf, 0x00 }, | ||
226 | { WAIT_IDLE }, { 0xe, 0xd8 }, { 0xf, 0x00 }, | ||
227 | { WAIT_IDLE }, { 0xe, 0xd9 }, { 0xf, 0x00 }, | ||
228 | { WAIT_IDLE }, { 0xe, 0xda }, { 0xf, 0x00 }, | ||
229 | { WAIT_IDLE }, { 0xe, 0xdb }, { 0xf, 0x00 }, | ||
230 | { WAIT_IDLE }, { 0xe, 0xdc }, { 0xf, 0x00 }, | ||
231 | { WAIT_IDLE }, { 0xe, 0xdd }, { 0xf, 0x00 }, | ||
232 | { WAIT_IDLE }, { 0xe, 0xde }, { 0xf, 0x00 }, | ||
233 | { WAIT_IDLE }, { 0xe, 0xdf }, { 0xf, 0x00 }, | ||
234 | { WAIT_IDLE }, { 0xe, 0xe0 }, { 0xf, 0x00 }, | ||
235 | { WAIT_IDLE }, { 0xe, 0xe1 }, { 0xf, 0x00 }, | ||
236 | { WAIT_IDLE }, { 0xe, 0xe2 }, { 0xf, 0x00 }, | ||
237 | { WAIT_IDLE }, { 0xe, 0xe3 }, { 0xf, 0x00 }, | ||
238 | { WAIT_IDLE }, { 0xe, 0xe4 }, { 0xf, 0x00 }, | ||
239 | { WAIT_IDLE }, { 0xe, 0xe5 }, { 0xf, 0x00 }, | ||
240 | { WAIT_IDLE }, { 0xe, 0xe6 }, { 0xf, 0x00 }, | ||
241 | { WAIT_IDLE }, { 0xe, 0xe7 }, { 0xf, 0x00 }, | ||
242 | { WAIT_IDLE }, { 0xe, 0xe8 }, { 0xf, 0x00 }, | ||
243 | { WAIT_IDLE }, { 0xe, 0xe9 }, { 0xf, 0x00 }, | ||
244 | { WAIT_IDLE }, { 0xe, 0xea }, { 0xf, 0x00 }, | ||
245 | { WAIT_IDLE }, { 0xe, 0xeb }, { 0xf, 0x00 }, | ||
246 | { WAIT_IDLE }, { 0xe, 0xec }, { 0xf, 0x00 }, | ||
247 | { WAIT_IDLE }, { 0xe, 0xed }, { 0xf, 0x00 }, | ||
248 | { WAIT_IDLE }, { 0xe, 0xee }, { 0xf, 0x00 }, | ||
249 | { WAIT_IDLE }, { 0xe, 0xef }, { 0xf, 0x00 }, | ||
250 | { WAIT_IDLE }, { 0xe, 0xf0 }, { 0xf, 0x00 }, | ||
251 | { WAIT_IDLE }, { 0xe, 0xf1 }, { 0xf, 0x00 }, | ||
252 | { WAIT_IDLE }, { 0xe, 0xf2 }, { 0xf, 0x00 }, | ||
253 | { WAIT_IDLE }, { 0xe, 0xf3 }, { 0xf, 0x00 }, | ||
254 | { WAIT_IDLE }, { 0xe, 0xf4 }, { 0xf, 0x00 }, | ||
255 | { WAIT_IDLE }, { 0xe, 0xf5 }, { 0xf, 0x00 }, | ||
256 | { WAIT_IDLE }, { 0xe, 0xf6 }, { 0xf, 0x00 }, | ||
257 | { WAIT_IDLE }, { 0xe, 0xf7 }, { 0xf, 0x00 }, | ||
258 | { WAIT_IDLE }, { 0xe, 0xf8 }, { 0xf, 0x00 }, | ||
259 | { WAIT_IDLE }, { 0xe, 0xf9 }, { 0xf, 0x00 }, | ||
260 | { WAIT_IDLE }, { 0xe, 0xfa }, { 0xf, 0x00 }, | ||
261 | { WAIT_IDLE }, { 0xe, 0xfb }, { 0xf, 0x00 }, | ||
262 | { WAIT_IDLE }, { 0xe, 0xfc }, { 0xf, 0x00 }, | ||
263 | { WAIT_IDLE }, { 0xe, 0xfd }, { 0xf, 0x00 }, | ||
264 | { WAIT_IDLE }, { 0xe, 0xfe }, { 0xf, 0x00 }, | ||
265 | { WAIT_IDLE }, { 0xe, 0xff }, { 0xf, 0x00 }, | ||
266 | |||
267 | /* XXX But why do this twice? */ | ||
268 | { WAIT_IDLE }, { 0xe, 0x10 }, { 0xf, 0x00 }, | ||
269 | { WAIT_IDLE }, { 0xe, 0x11 }, { 0xf, 0x00 }, | ||
270 | { WAIT_IDLE }, { 0xe, 0x12 }, { 0xf, 0x00 }, | ||
271 | { WAIT_IDLE }, { 0xe, 0x13 }, { 0xf, 0x00 }, | ||
272 | { WAIT_IDLE }, { 0xe, 0x14 }, { 0xf, 0x00 }, | ||
273 | { WAIT_IDLE }, { 0xe, 0x15 }, { 0xf, 0x00 }, | ||
274 | { WAIT_IDLE }, { 0xe, 0x16 }, { 0xf, 0x00 }, | ||
275 | { WAIT_IDLE }, { 0xe, 0x17 }, { 0xf, 0x00 }, | ||
276 | { WAIT_IDLE }, { 0xe, 0x18 }, { 0xf, 0x00 }, | ||
277 | { WAIT_IDLE }, { 0xe, 0x19 }, { 0xf, 0x00 }, | ||
278 | { WAIT_IDLE }, { 0xe, 0x1a }, { 0xf, 0x00 }, | ||
279 | { WAIT_IDLE }, { 0xe, 0x1b }, { 0xf, 0x00 }, | ||
280 | { WAIT_IDLE }, { 0xe, 0x1c }, { 0xf, 0x00 }, | ||
281 | { WAIT_IDLE }, { 0xe, 0x1d }, { 0xf, 0x00 }, | ||
282 | { WAIT_IDLE }, { 0xe, 0x1e }, { 0xf, 0x00 }, | ||
283 | { WAIT_IDLE }, { 0xe, 0x1f }, { 0xf, 0x00 }, | ||
284 | { WAIT_IDLE }, { 0xe, 0x20 }, { 0xf, 0x00 }, | ||
285 | { WAIT_IDLE }, { 0xe, 0x21 }, { 0xf, 0x00 }, | ||
286 | { WAIT_IDLE }, { 0xe, 0x22 }, { 0xf, 0x00 }, | ||
287 | { WAIT_IDLE }, { 0xe, 0x23 }, { 0xf, 0x00 }, | ||
288 | { WAIT_IDLE }, { 0xe, 0x24 }, { 0xf, 0x00 }, | ||
289 | { WAIT_IDLE }, { 0xe, 0x25 }, { 0xf, 0x00 }, | ||
290 | { WAIT_IDLE }, { 0xe, 0x26 }, { 0xf, 0x00 }, | ||
291 | { WAIT_IDLE }, { 0xe, 0x27 }, { 0xf, 0x00 }, | ||
292 | { WAIT_IDLE }, { 0xe, 0x28 }, { 0xf, 0x00 }, | ||
293 | { WAIT_IDLE }, { 0xe, 0x29 }, { 0xf, 0x00 }, | ||
294 | { WAIT_IDLE }, { 0xe, 0x2a }, { 0xf, 0x00 }, | ||
295 | { WAIT_IDLE }, { 0xe, 0x2b }, { 0xf, 0x00 }, | ||
296 | { WAIT_IDLE }, { 0xe, 0x2c }, { 0xf, 0x00 }, | ||
297 | { WAIT_IDLE }, { 0xe, 0x2d }, { 0xf, 0x00 }, | ||
298 | { WAIT_IDLE }, { 0xe, 0x2e }, { 0xf, 0x00 }, | ||
299 | { WAIT_IDLE }, { 0xe, 0x2f }, { 0xf, 0x00 }, | ||
300 | { WAIT_IDLE }, { 0xe, 0x30 }, { 0xf, 0x00 }, | ||
301 | { WAIT_IDLE }, { 0xe, 0x31 }, { 0xf, 0x00 }, | ||
302 | { WAIT_IDLE }, { 0xe, 0x32 }, { 0xf, 0x00 }, | ||
303 | { WAIT_IDLE }, { 0xe, 0x33 }, { 0xf, 0x00 }, | ||
304 | { WAIT_IDLE }, { 0xe, 0x34 }, { 0xf, 0x00 }, | ||
305 | { WAIT_IDLE }, { 0xe, 0x35 }, { 0xf, 0x00 }, | ||
306 | { WAIT_IDLE }, { 0xe, 0x36 }, { 0xf, 0x00 }, | ||
307 | { WAIT_IDLE }, { 0xe, 0x37 }, { 0xf, 0x00 }, | ||
308 | { WAIT_IDLE }, { 0xe, 0x38 }, { 0xf, 0x00 }, | ||
309 | { WAIT_IDLE }, { 0xe, 0x39 }, { 0xf, 0x00 }, | ||
310 | { WAIT_IDLE }, { 0xe, 0x3a }, { 0xf, 0x00 }, | ||
311 | { WAIT_IDLE }, { 0xe, 0x3b }, { 0xf, 0x00 }, | ||
312 | { WAIT_IDLE }, { 0xe, 0x3c }, { 0xf, 0x00 }, | ||
313 | { WAIT_IDLE }, { 0xe, 0x3d }, { 0xf, 0x00 }, | ||
314 | { WAIT_IDLE }, { 0xe, 0x3e }, { 0xf, 0x00 }, | ||
315 | { WAIT_IDLE }, { 0xe, 0x3f }, { 0xf, 0x00 }, | ||
316 | { WAIT_IDLE }, { 0xe, 0x40 }, { 0xf, 0x00 }, | ||
317 | { WAIT_IDLE }, { 0xe, 0x41 }, { 0xf, 0x00 }, | ||
318 | { WAIT_IDLE }, { 0xe, 0x42 }, { 0xf, 0x00 }, | ||
319 | { WAIT_IDLE }, { 0xe, 0x43 }, { 0xf, 0x00 }, | ||
320 | { WAIT_IDLE }, { 0xe, 0x44 }, { 0xf, 0x00 }, | ||
321 | { WAIT_IDLE }, { 0xe, 0x45 }, { 0xf, 0x00 }, | ||
322 | { WAIT_IDLE }, { 0xe, 0x46 }, { 0xf, 0x00 }, | ||
323 | { WAIT_IDLE }, { 0xe, 0x47 }, { 0xf, 0x00 }, | ||
324 | { WAIT_IDLE }, { 0xe, 0x48 }, { 0xf, 0x00 }, | ||
325 | { WAIT_IDLE }, { 0xe, 0x49 }, { 0xf, 0x00 }, | ||
326 | { WAIT_IDLE }, { 0xe, 0x4a }, { 0xf, 0x00 }, | ||
327 | { WAIT_IDLE }, { 0xe, 0x4b }, { 0xf, 0x00 }, | ||
328 | { WAIT_IDLE }, { 0xe, 0x4c }, { 0xf, 0x00 }, | ||
329 | { WAIT_IDLE }, { 0xe, 0x4d }, { 0xf, 0x00 }, | ||
330 | { WAIT_IDLE }, { 0xe, 0x4e }, { 0xf, 0x00 }, | ||
331 | { WAIT_IDLE }, { 0xe, 0x4f }, { 0xf, 0x00 }, | ||
332 | { WAIT_IDLE }, { 0xe, 0x50 }, { 0xf, 0x00 }, | ||
333 | { WAIT_IDLE }, { 0xe, 0x51 }, { 0xf, 0x00 }, | ||
334 | { WAIT_IDLE }, { 0xe, 0x52 }, { 0xf, 0x00 }, | ||
335 | { WAIT_IDLE }, { 0xe, 0x53 }, { 0xf, 0x00 }, | ||
336 | { WAIT_IDLE }, { 0xe, 0x54 }, { 0xf, 0x00 }, | ||
337 | { WAIT_IDLE }, { 0xe, 0x55 }, { 0xf, 0x00 }, | ||
338 | { WAIT_IDLE }, { 0xe, 0x56 }, { 0xf, 0x00 }, | ||
339 | { WAIT_IDLE }, { 0xe, 0x57 }, { 0xf, 0x00 }, | ||
340 | { WAIT_IDLE }, { 0xe, 0x58 }, { 0xf, 0x00 }, | ||
341 | { WAIT_IDLE }, { 0xe, 0x59 }, { 0xf, 0x00 }, | ||
342 | { WAIT_IDLE }, { 0xe, 0x5a }, { 0xf, 0x00 }, | ||
343 | { WAIT_IDLE }, { 0xe, 0x5b }, { 0xf, 0x00 }, | ||
344 | { WAIT_IDLE }, { 0xe, 0x5c }, { 0xf, 0x00 }, | ||
345 | { WAIT_IDLE }, { 0xe, 0x5d }, { 0xf, 0x00 }, | ||
346 | { WAIT_IDLE }, { 0xe, 0x5e }, { 0xf, 0x00 }, | ||
347 | { WAIT_IDLE }, { 0xe, 0x5f }, { 0xf, 0x00 }, | ||
348 | { WAIT_IDLE }, { 0xe, 0x60 }, { 0xf, 0x00 }, | ||
349 | { WAIT_IDLE }, { 0xe, 0x61 }, { 0xf, 0x00 }, | ||
350 | { WAIT_IDLE }, { 0xe, 0x62 }, { 0xf, 0x00 }, | ||
351 | { WAIT_IDLE }, { 0xe, 0x63 }, { 0xf, 0x00 }, | ||
352 | { WAIT_IDLE }, { 0xe, 0x64 }, { 0xf, 0x00 }, | ||
353 | { WAIT_IDLE }, { 0xe, 0x65 }, { 0xf, 0x00 }, | ||
354 | { WAIT_IDLE }, { 0xe, 0x66 }, { 0xf, 0x00 }, | ||
355 | { WAIT_IDLE }, { 0xe, 0x67 }, { 0xf, 0x00 }, | ||
356 | { WAIT_IDLE }, { 0xe, 0x68 }, { 0xf, 0x00 }, | ||
357 | { WAIT_IDLE }, { 0xe, 0x69 }, { 0xf, 0x00 }, | ||
358 | { WAIT_IDLE }, { 0xe, 0x6a }, { 0xf, 0x00 }, | ||
359 | { WAIT_IDLE }, { 0xe, 0x6b }, { 0xf, 0x00 }, | ||
360 | { WAIT_IDLE }, { 0xe, 0x6c }, { 0xf, 0x00 }, | ||
361 | { WAIT_IDLE }, { 0xe, 0x6d }, { 0xf, 0x00 }, | ||
362 | { WAIT_IDLE }, { 0xe, 0x6e }, { 0xf, 0x00 }, | ||
363 | { WAIT_IDLE }, { 0xe, 0x6f }, { 0xf, 0x00 }, | ||
364 | { WAIT_IDLE }, { 0xe, 0x70 }, { 0xf, 0x00 }, | ||
365 | { WAIT_IDLE }, { 0xe, 0x71 }, { 0xf, 0x00 }, | ||
366 | { WAIT_IDLE }, { 0xe, 0x72 }, { 0xf, 0x00 }, | ||
367 | { WAIT_IDLE }, { 0xe, 0x73 }, { 0xf, 0x00 }, | ||
368 | { WAIT_IDLE }, { 0xe, 0x74 }, { 0xf, 0x00 }, | ||
369 | { WAIT_IDLE }, { 0xe, 0x75 }, { 0xf, 0x00 }, | ||
370 | { WAIT_IDLE }, { 0xe, 0x76 }, { 0xf, 0x00 }, | ||
371 | { WAIT_IDLE }, { 0xe, 0x77 }, { 0xf, 0x00 }, | ||
372 | { WAIT_IDLE }, { 0xe, 0x78 }, { 0xf, 0x00 }, | ||
373 | { WAIT_IDLE }, { 0xe, 0x79 }, { 0xf, 0x00 }, | ||
374 | { WAIT_IDLE }, { 0xe, 0x7a }, { 0xf, 0x00 }, | ||
375 | { WAIT_IDLE }, { 0xe, 0x7b }, { 0xf, 0x00 }, | ||
376 | { WAIT_IDLE }, { 0xe, 0x7c }, { 0xf, 0x00 }, | ||
377 | { WAIT_IDLE }, { 0xe, 0x7d }, { 0xf, 0x00 }, | ||
378 | { WAIT_IDLE }, { 0xe, 0x7e }, { 0xf, 0x00 }, | ||
379 | { WAIT_IDLE }, { 0xe, 0x7f }, { 0xf, 0x00 }, | ||
380 | { WAIT_IDLE }, { 0xe, 0x80 }, { 0xf, 0x00 }, | ||
381 | { WAIT_IDLE }, { 0xe, 0x81 }, { 0xf, 0x00 }, | ||
382 | { WAIT_IDLE }, { 0xe, 0x82 }, { 0xf, 0x00 }, | ||
383 | { WAIT_IDLE }, { 0xe, 0x83 }, { 0xf, 0x00 }, | ||
384 | { WAIT_IDLE }, { 0xe, 0x84 }, { 0xf, 0x00 }, | ||
385 | { WAIT_IDLE }, { 0xe, 0x85 }, { 0xf, 0x00 }, | ||
386 | { WAIT_IDLE }, { 0xe, 0x86 }, { 0xf, 0x00 }, | ||
387 | { WAIT_IDLE }, { 0xe, 0x87 }, { 0xf, 0x00 }, | ||
388 | { WAIT_IDLE }, { 0xe, 0x88 }, { 0xf, 0x00 }, | ||
389 | { WAIT_IDLE }, { 0xe, 0x89 }, { 0xf, 0x00 }, | ||
390 | { WAIT_IDLE }, { 0xe, 0x8a }, { 0xf, 0x00 }, | ||
391 | { WAIT_IDLE }, { 0xe, 0x8b }, { 0xf, 0x00 }, | ||
392 | { WAIT_IDLE }, { 0xe, 0x8c }, { 0xf, 0x00 }, | ||
393 | { WAIT_IDLE }, { 0xe, 0x8d }, { 0xf, 0x00 }, | ||
394 | { WAIT_IDLE }, { 0xe, 0x8e }, { 0xf, 0x00 }, | ||
395 | { WAIT_IDLE }, { 0xe, 0x8f }, { 0xf, 0x00 }, | ||
396 | { WAIT_IDLE }, { 0xe, 0x90 }, { 0xf, 0x00 }, | ||
397 | { WAIT_IDLE }, { 0xe, 0x91 }, { 0xf, 0x00 }, | ||
398 | { WAIT_IDLE }, { 0xe, 0x92 }, { 0xf, 0x00 }, | ||
399 | { WAIT_IDLE }, { 0xe, 0x93 }, { 0xf, 0x00 }, | ||
400 | { WAIT_IDLE }, { 0xe, 0x94 }, { 0xf, 0x00 }, | ||
401 | { WAIT_IDLE }, { 0xe, 0x95 }, { 0xf, 0x00 }, | ||
402 | { WAIT_IDLE }, { 0xe, 0x96 }, { 0xf, 0x00 }, | ||
403 | { WAIT_IDLE }, { 0xe, 0x97 }, { 0xf, 0x00 }, | ||
404 | { WAIT_IDLE }, { 0xe, 0x98 }, { 0xf, 0x00 }, | ||
405 | { WAIT_IDLE }, { 0xe, 0x99 }, { 0xf, 0x00 }, | ||
406 | { WAIT_IDLE }, { 0xe, 0x9a }, { 0xf, 0x00 }, | ||
407 | { WAIT_IDLE }, { 0xe, 0x9b }, { 0xf, 0x00 }, | ||
408 | { WAIT_IDLE }, { 0xe, 0x9c }, { 0xf, 0x00 }, | ||
409 | { WAIT_IDLE }, { 0xe, 0x9d }, { 0xf, 0x00 }, | ||
410 | { WAIT_IDLE }, { 0xe, 0x9e }, { 0xf, 0x00 }, | ||
411 | { WAIT_IDLE }, { 0xe, 0x9f }, { 0xf, 0x00 }, | ||
412 | { WAIT_IDLE }, { 0xe, 0xa0 }, { 0xf, 0x00 }, | ||
413 | { WAIT_IDLE }, { 0xe, 0xa1 }, { 0xf, 0x00 }, | ||
414 | { WAIT_IDLE }, { 0xe, 0xa2 }, { 0xf, 0x00 }, | ||
415 | { WAIT_IDLE }, { 0xe, 0xa3 }, { 0xf, 0x00 }, | ||
416 | { WAIT_IDLE }, { 0xe, 0xa4 }, { 0xf, 0x00 }, | ||
417 | { WAIT_IDLE }, { 0xe, 0xa5 }, { 0xf, 0x00 }, | ||
418 | { WAIT_IDLE }, { 0xe, 0xa6 }, { 0xf, 0x00 }, | ||
419 | { WAIT_IDLE }, { 0xe, 0xa7 }, { 0xf, 0x00 }, | ||
420 | { WAIT_IDLE }, { 0xe, 0xa8 }, { 0xf, 0x00 }, | ||
421 | { WAIT_IDLE }, { 0xe, 0xa9 }, { 0xf, 0x00 }, | ||
422 | { WAIT_IDLE }, { 0xe, 0xaa }, { 0xf, 0x00 }, | ||
423 | { WAIT_IDLE }, { 0xe, 0xab }, { 0xf, 0x00 }, | ||
424 | { WAIT_IDLE }, { 0xe, 0xac }, { 0xf, 0x00 }, | ||
425 | { WAIT_IDLE }, { 0xe, 0xad }, { 0xf, 0x00 }, | ||
426 | { WAIT_IDLE }, { 0xe, 0xae }, { 0xf, 0x00 }, | ||
427 | { WAIT_IDLE }, { 0xe, 0xaf }, { 0xf, 0x00 }, | ||
428 | { WAIT_IDLE }, { 0xe, 0xb0 }, { 0xf, 0x00 }, | ||
429 | { WAIT_IDLE }, { 0xe, 0xb1 }, { 0xf, 0x00 }, | ||
430 | { WAIT_IDLE }, { 0xe, 0xb2 }, { 0xf, 0x00 }, | ||
431 | { WAIT_IDLE }, { 0xe, 0xb3 }, { 0xf, 0x00 }, | ||
432 | { WAIT_IDLE }, { 0xe, 0xb4 }, { 0xf, 0x00 }, | ||
433 | { WAIT_IDLE }, { 0xe, 0xb5 }, { 0xf, 0x00 }, | ||
434 | { WAIT_IDLE }, { 0xe, 0xb6 }, { 0xf, 0x00 }, | ||
435 | { WAIT_IDLE }, { 0xe, 0xb7 }, { 0xf, 0x00 }, | ||
436 | { WAIT_IDLE }, { 0xe, 0xb8 }, { 0xf, 0x00 }, | ||
437 | { WAIT_IDLE }, { 0xe, 0xb9 }, { 0xf, 0x00 }, | ||
438 | { WAIT_IDLE }, { 0xe, 0xba }, { 0xf, 0x00 }, | ||
439 | { WAIT_IDLE }, { 0xe, 0xbb }, { 0xf, 0x00 }, | ||
440 | { WAIT_IDLE }, { 0xe, 0xbc }, { 0xf, 0x00 }, | ||
441 | { WAIT_IDLE }, { 0xe, 0xbd }, { 0xf, 0x00 }, | ||
442 | { WAIT_IDLE }, { 0xe, 0xbe }, { 0xf, 0x00 }, | ||
443 | { WAIT_IDLE }, { 0xe, 0xbf }, { 0xf, 0x00 }, | ||
444 | { WAIT_IDLE }, { 0xe, 0xc0 }, { 0xf, 0x00 }, | ||
445 | { WAIT_IDLE }, { 0xe, 0xc1 }, { 0xf, 0x00 }, | ||
446 | { WAIT_IDLE }, { 0xe, 0xc2 }, { 0xf, 0x00 }, | ||
447 | { WAIT_IDLE }, { 0xe, 0xc3 }, { 0xf, 0x00 }, | ||
448 | { WAIT_IDLE }, { 0xe, 0xc4 }, { 0xf, 0x00 }, | ||
449 | { WAIT_IDLE }, { 0xe, 0xc5 }, { 0xf, 0x00 }, | ||
450 | { WAIT_IDLE }, { 0xe, 0xc6 }, { 0xf, 0x00 }, | ||
451 | { WAIT_IDLE }, { 0xe, 0xc7 }, { 0xf, 0x00 }, | ||
452 | { WAIT_IDLE }, { 0xe, 0xc8 }, { 0xf, 0x00 }, | ||
453 | { WAIT_IDLE }, { 0xe, 0xc9 }, { 0xf, 0x00 }, | ||
454 | { WAIT_IDLE }, { 0xe, 0xca }, { 0xf, 0x00 }, | ||
455 | { WAIT_IDLE }, { 0xe, 0xcb }, { 0xf, 0x00 }, | ||
456 | { WAIT_IDLE }, { 0xe, 0xcc }, { 0xf, 0x00 }, | ||
457 | { WAIT_IDLE }, { 0xe, 0xcd }, { 0xf, 0x00 }, | ||
458 | { WAIT_IDLE }, { 0xe, 0xce }, { 0xf, 0x00 }, | ||
459 | { WAIT_IDLE }, { 0xe, 0xcf }, { 0xf, 0x00 }, | ||
460 | { WAIT_IDLE }, { 0xe, 0xd0 }, { 0xf, 0x00 }, | ||
461 | { WAIT_IDLE }, { 0xe, 0xd1 }, { 0xf, 0x00 }, | ||
462 | { WAIT_IDLE }, { 0xe, 0xd2 }, { 0xf, 0x00 }, | ||
463 | { WAIT_IDLE }, { 0xe, 0xd3 }, { 0xf, 0x00 }, | ||
464 | { WAIT_IDLE }, { 0xe, 0xd4 }, { 0xf, 0x00 }, | ||
465 | { WAIT_IDLE }, { 0xe, 0xd5 }, { 0xf, 0x00 }, | ||
466 | { WAIT_IDLE }, { 0xe, 0xd6 }, { 0xf, 0x00 }, | ||
467 | { WAIT_IDLE }, { 0xe, 0xd7 }, { 0xf, 0x00 }, | ||
468 | { WAIT_IDLE }, { 0xe, 0xd8 }, { 0xf, 0x00 }, | ||
469 | { WAIT_IDLE }, { 0xe, 0xd9 }, { 0xf, 0x00 }, | ||
470 | { WAIT_IDLE }, { 0xe, 0xda }, { 0xf, 0x00 }, | ||
471 | { WAIT_IDLE }, { 0xe, 0xdb }, { 0xf, 0x00 }, | ||
472 | { WAIT_IDLE }, { 0xe, 0xdc }, { 0xf, 0x00 }, | ||
473 | { WAIT_IDLE }, { 0xe, 0xdd }, { 0xf, 0x00 }, | ||
474 | { WAIT_IDLE }, { 0xe, 0xde }, { 0xf, 0x00 }, | ||
475 | { WAIT_IDLE }, { 0xe, 0xdf }, { 0xf, 0x00 }, | ||
476 | { WAIT_IDLE }, { 0xe, 0xe0 }, { 0xf, 0x00 }, | ||
477 | { WAIT_IDLE }, { 0xe, 0xe1 }, { 0xf, 0x00 }, | ||
478 | { WAIT_IDLE }, { 0xe, 0xe2 }, { 0xf, 0x00 }, | ||
479 | { WAIT_IDLE }, { 0xe, 0xe3 }, { 0xf, 0x00 }, | ||
480 | { WAIT_IDLE }, { 0xe, 0xe4 }, { 0xf, 0x00 }, | ||
481 | { WAIT_IDLE }, { 0xe, 0xe5 }, { 0xf, 0x00 }, | ||
482 | { WAIT_IDLE }, { 0xe, 0xe6 }, { 0xf, 0x00 }, | ||
483 | { WAIT_IDLE }, { 0xe, 0xe7 }, { 0xf, 0x00 }, | ||
484 | { WAIT_IDLE }, { 0xe, 0xe8 }, { 0xf, 0x00 }, | ||
485 | { WAIT_IDLE }, { 0xe, 0xe9 }, { 0xf, 0x00 }, | ||
486 | { WAIT_IDLE }, { 0xe, 0xea }, { 0xf, 0x00 }, | ||
487 | { WAIT_IDLE }, { 0xe, 0xeb }, { 0xf, 0x00 }, | ||
488 | { WAIT_IDLE }, { 0xe, 0xec }, { 0xf, 0x00 }, | ||
489 | { WAIT_IDLE }, { 0xe, 0xed }, { 0xf, 0x00 }, | ||
490 | { WAIT_IDLE }, { 0xe, 0xee }, { 0xf, 0x00 }, | ||
491 | { WAIT_IDLE }, { 0xe, 0xef }, { 0xf, 0x00 }, | ||
492 | { WAIT_IDLE }, { 0xe, 0xf0 }, { 0xf, 0x00 }, | ||
493 | { WAIT_IDLE }, { 0xe, 0xf1 }, { 0xf, 0x00 }, | ||
494 | { WAIT_IDLE }, { 0xe, 0xf2 }, { 0xf, 0x00 }, | ||
495 | { WAIT_IDLE }, { 0xe, 0xf3 }, { 0xf, 0x00 }, | ||
496 | { WAIT_IDLE }, { 0xe, 0xf4 }, { 0xf, 0x00 }, | ||
497 | { WAIT_IDLE }, { 0xe, 0xf5 }, { 0xf, 0x00 }, | ||
498 | { WAIT_IDLE }, { 0xe, 0xf6 }, { 0xf, 0x00 }, | ||
499 | { WAIT_IDLE }, { 0xe, 0xf7 }, { 0xf, 0x00 }, | ||
500 | { WAIT_IDLE }, { 0xe, 0xf8 }, { 0xf, 0x00 }, | ||
501 | { WAIT_IDLE }, { 0xe, 0xf9 }, { 0xf, 0x00 }, | ||
502 | { WAIT_IDLE }, { 0xe, 0xfa }, { 0xf, 0x00 }, | ||
503 | { WAIT_IDLE }, { 0xe, 0xfb }, { 0xf, 0x00 }, | ||
504 | { WAIT_IDLE }, { 0xe, 0xfc }, { 0xf, 0x00 }, | ||
505 | { WAIT_IDLE }, { 0xe, 0xfd }, { 0xf, 0x00 }, | ||
506 | { WAIT_IDLE }, { 0xe, 0xfe }, { 0xf, 0x00 }, | ||
507 | { WAIT_IDLE }, { 0xe, 0xff }, { 0xf, 0x00 }, | ||
508 | |||
509 | /* mute on */ | ||
510 | { WAIT_IDLE }, { 0x8, 0x02 }, | ||
511 | |||
512 | { WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x44 }, { 0xd, 0x00 }, { 0xc, 0x00 }, | ||
513 | { WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x42 }, { 0xd, 0x00 }, { 0xc, 0x00 }, | ||
514 | { WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x43 }, { 0xd, 0x00 }, { 0xc, 0x00 }, | ||
515 | { WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x7c }, { 0xd, 0x00 }, { 0xc, 0x00 }, | ||
516 | { WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x7e }, { 0xd, 0x00 }, { 0xc, 0x00 }, | ||
517 | { WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x46 }, { 0xd, 0x00 }, { 0xc, 0x00 }, | ||
518 | { WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x49 }, { 0xd, 0x00 }, { 0xc, 0x00 }, | ||
519 | { WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x47 }, { 0xd, 0x00 }, { 0xc, 0x00 }, | ||
520 | { WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x4a }, { 0xd, 0x00 }, { 0xc, 0x00 }, | ||
521 | |||
522 | /* either because of stupidity by TB's programmers, or because it | ||
523 | actually does something, rezero the MOD page. */ | ||
524 | { WAIT_IDLE }, { 0xe, 0x10 }, { 0xf, 0x00 }, | ||
525 | { WAIT_IDLE }, { 0xe, 0x11 }, { 0xf, 0x00 }, | ||
526 | { WAIT_IDLE }, { 0xe, 0x12 }, { 0xf, 0x00 }, | ||
527 | { WAIT_IDLE }, { 0xe, 0x13 }, { 0xf, 0x00 }, | ||
528 | { WAIT_IDLE }, { 0xe, 0x14 }, { 0xf, 0x00 }, | ||
529 | { WAIT_IDLE }, { 0xe, 0x15 }, { 0xf, 0x00 }, | ||
530 | { WAIT_IDLE }, { 0xe, 0x16 }, { 0xf, 0x00 }, | ||
531 | { WAIT_IDLE }, { 0xe, 0x17 }, { 0xf, 0x00 }, | ||
532 | { WAIT_IDLE }, { 0xe, 0x18 }, { 0xf, 0x00 }, | ||
533 | { WAIT_IDLE }, { 0xe, 0x19 }, { 0xf, 0x00 }, | ||
534 | { WAIT_IDLE }, { 0xe, 0x1a }, { 0xf, 0x00 }, | ||
535 | { WAIT_IDLE }, { 0xe, 0x1b }, { 0xf, 0x00 }, | ||
536 | { WAIT_IDLE }, { 0xe, 0x1c }, { 0xf, 0x00 }, | ||
537 | { WAIT_IDLE }, { 0xe, 0x1d }, { 0xf, 0x00 }, | ||
538 | { WAIT_IDLE }, { 0xe, 0x1e }, { 0xf, 0x00 }, | ||
539 | { WAIT_IDLE }, { 0xe, 0x1f }, { 0xf, 0x00 }, | ||
540 | { WAIT_IDLE }, { 0xe, 0x20 }, { 0xf, 0x00 }, | ||
541 | { WAIT_IDLE }, { 0xe, 0x21 }, { 0xf, 0x00 }, | ||
542 | { WAIT_IDLE }, { 0xe, 0x22 }, { 0xf, 0x00 }, | ||
543 | { WAIT_IDLE }, { 0xe, 0x23 }, { 0xf, 0x00 }, | ||
544 | { WAIT_IDLE }, { 0xe, 0x24 }, { 0xf, 0x00 }, | ||
545 | { WAIT_IDLE }, { 0xe, 0x25 }, { 0xf, 0x00 }, | ||
546 | { WAIT_IDLE }, { 0xe, 0x26 }, { 0xf, 0x00 }, | ||
547 | { WAIT_IDLE }, { 0xe, 0x27 }, { 0xf, 0x00 }, | ||
548 | { WAIT_IDLE }, { 0xe, 0x28 }, { 0xf, 0x00 }, | ||
549 | { WAIT_IDLE }, { 0xe, 0x29 }, { 0xf, 0x00 }, | ||
550 | { WAIT_IDLE }, { 0xe, 0x2a }, { 0xf, 0x00 }, | ||
551 | { WAIT_IDLE }, { 0xe, 0x2b }, { 0xf, 0x00 }, | ||
552 | { WAIT_IDLE }, { 0xe, 0x2c }, { 0xf, 0x00 }, | ||
553 | { WAIT_IDLE }, { 0xe, 0x2d }, { 0xf, 0x00 }, | ||
554 | { WAIT_IDLE }, { 0xe, 0x2e }, { 0xf, 0x00 }, | ||
555 | { WAIT_IDLE }, { 0xe, 0x2f }, { 0xf, 0x00 }, | ||
556 | { WAIT_IDLE }, { 0xe, 0x30 }, { 0xf, 0x00 }, | ||
557 | { WAIT_IDLE }, { 0xe, 0x31 }, { 0xf, 0x00 }, | ||
558 | { WAIT_IDLE }, { 0xe, 0x32 }, { 0xf, 0x00 }, | ||
559 | { WAIT_IDLE }, { 0xe, 0x33 }, { 0xf, 0x00 }, | ||
560 | { WAIT_IDLE }, { 0xe, 0x34 }, { 0xf, 0x00 }, | ||
561 | { WAIT_IDLE }, { 0xe, 0x35 }, { 0xf, 0x00 }, | ||
562 | { WAIT_IDLE }, { 0xe, 0x36 }, { 0xf, 0x00 }, | ||
563 | { WAIT_IDLE }, { 0xe, 0x37 }, { 0xf, 0x00 }, | ||
564 | { WAIT_IDLE }, { 0xe, 0x38 }, { 0xf, 0x00 }, | ||
565 | { WAIT_IDLE }, { 0xe, 0x39 }, { 0xf, 0x00 }, | ||
566 | { WAIT_IDLE }, { 0xe, 0x3a }, { 0xf, 0x00 }, | ||
567 | { WAIT_IDLE }, { 0xe, 0x3b }, { 0xf, 0x00 }, | ||
568 | { WAIT_IDLE }, { 0xe, 0x3c }, { 0xf, 0x00 }, | ||
569 | { WAIT_IDLE }, { 0xe, 0x3d }, { 0xf, 0x00 }, | ||
570 | { WAIT_IDLE }, { 0xe, 0x3e }, { 0xf, 0x00 }, | ||
571 | { WAIT_IDLE }, { 0xe, 0x3f }, { 0xf, 0x00 }, | ||
572 | { WAIT_IDLE }, { 0xe, 0x40 }, { 0xf, 0x00 }, | ||
573 | { WAIT_IDLE }, { 0xe, 0x41 }, { 0xf, 0x00 }, | ||
574 | { WAIT_IDLE }, { 0xe, 0x42 }, { 0xf, 0x00 }, | ||
575 | { WAIT_IDLE }, { 0xe, 0x43 }, { 0xf, 0x00 }, | ||
576 | { WAIT_IDLE }, { 0xe, 0x44 }, { 0xf, 0x00 }, | ||
577 | { WAIT_IDLE }, { 0xe, 0x45 }, { 0xf, 0x00 }, | ||
578 | { WAIT_IDLE }, { 0xe, 0x46 }, { 0xf, 0x00 }, | ||
579 | { WAIT_IDLE }, { 0xe, 0x47 }, { 0xf, 0x00 }, | ||
580 | { WAIT_IDLE }, { 0xe, 0x48 }, { 0xf, 0x00 }, | ||
581 | { WAIT_IDLE }, { 0xe, 0x49 }, { 0xf, 0x00 }, | ||
582 | { WAIT_IDLE }, { 0xe, 0x4a }, { 0xf, 0x00 }, | ||
583 | { WAIT_IDLE }, { 0xe, 0x4b }, { 0xf, 0x00 }, | ||
584 | { WAIT_IDLE }, { 0xe, 0x4c }, { 0xf, 0x00 }, | ||
585 | { WAIT_IDLE }, { 0xe, 0x4d }, { 0xf, 0x00 }, | ||
586 | { WAIT_IDLE }, { 0xe, 0x4e }, { 0xf, 0x00 }, | ||
587 | { WAIT_IDLE }, { 0xe, 0x4f }, { 0xf, 0x00 }, | ||
588 | { WAIT_IDLE }, { 0xe, 0x50 }, { 0xf, 0x00 }, | ||
589 | { WAIT_IDLE }, { 0xe, 0x51 }, { 0xf, 0x00 }, | ||
590 | { WAIT_IDLE }, { 0xe, 0x52 }, { 0xf, 0x00 }, | ||
591 | { WAIT_IDLE }, { 0xe, 0x53 }, { 0xf, 0x00 }, | ||
592 | { WAIT_IDLE }, { 0xe, 0x54 }, { 0xf, 0x00 }, | ||
593 | { WAIT_IDLE }, { 0xe, 0x55 }, { 0xf, 0x00 }, | ||
594 | { WAIT_IDLE }, { 0xe, 0x56 }, { 0xf, 0x00 }, | ||
595 | { WAIT_IDLE }, { 0xe, 0x57 }, { 0xf, 0x00 }, | ||
596 | { WAIT_IDLE }, { 0xe, 0x58 }, { 0xf, 0x00 }, | ||
597 | { WAIT_IDLE }, { 0xe, 0x59 }, { 0xf, 0x00 }, | ||
598 | { WAIT_IDLE }, { 0xe, 0x5a }, { 0xf, 0x00 }, | ||
599 | { WAIT_IDLE }, { 0xe, 0x5b }, { 0xf, 0x00 }, | ||
600 | { WAIT_IDLE }, { 0xe, 0x5c }, { 0xf, 0x00 }, | ||
601 | { WAIT_IDLE }, { 0xe, 0x5d }, { 0xf, 0x00 }, | ||
602 | { WAIT_IDLE }, { 0xe, 0x5e }, { 0xf, 0x00 }, | ||
603 | { WAIT_IDLE }, { 0xe, 0x5f }, { 0xf, 0x00 }, | ||
604 | { WAIT_IDLE }, { 0xe, 0x60 }, { 0xf, 0x00 }, | ||
605 | { WAIT_IDLE }, { 0xe, 0x61 }, { 0xf, 0x00 }, | ||
606 | { WAIT_IDLE }, { 0xe, 0x62 }, { 0xf, 0x00 }, | ||
607 | { WAIT_IDLE }, { 0xe, 0x63 }, { 0xf, 0x00 }, | ||
608 | { WAIT_IDLE }, { 0xe, 0x64 }, { 0xf, 0x00 }, | ||
609 | { WAIT_IDLE }, { 0xe, 0x65 }, { 0xf, 0x00 }, | ||
610 | { WAIT_IDLE }, { 0xe, 0x66 }, { 0xf, 0x00 }, | ||
611 | { WAIT_IDLE }, { 0xe, 0x67 }, { 0xf, 0x00 }, | ||
612 | { WAIT_IDLE }, { 0xe, 0x68 }, { 0xf, 0x00 }, | ||
613 | { WAIT_IDLE }, { 0xe, 0x69 }, { 0xf, 0x00 }, | ||
614 | { WAIT_IDLE }, { 0xe, 0x6a }, { 0xf, 0x00 }, | ||
615 | { WAIT_IDLE }, { 0xe, 0x6b }, { 0xf, 0x00 }, | ||
616 | { WAIT_IDLE }, { 0xe, 0x6c }, { 0xf, 0x00 }, | ||
617 | { WAIT_IDLE }, { 0xe, 0x6d }, { 0xf, 0x00 }, | ||
618 | { WAIT_IDLE }, { 0xe, 0x6e }, { 0xf, 0x00 }, | ||
619 | { WAIT_IDLE }, { 0xe, 0x6f }, { 0xf, 0x00 }, | ||
620 | { WAIT_IDLE }, { 0xe, 0x70 }, { 0xf, 0x00 }, | ||
621 | { WAIT_IDLE }, { 0xe, 0x71 }, { 0xf, 0x00 }, | ||
622 | { WAIT_IDLE }, { 0xe, 0x72 }, { 0xf, 0x00 }, | ||
623 | { WAIT_IDLE }, { 0xe, 0x73 }, { 0xf, 0x00 }, | ||
624 | { WAIT_IDLE }, { 0xe, 0x74 }, { 0xf, 0x00 }, | ||
625 | { WAIT_IDLE }, { 0xe, 0x75 }, { 0xf, 0x00 }, | ||
626 | { WAIT_IDLE }, { 0xe, 0x76 }, { 0xf, 0x00 }, | ||
627 | { WAIT_IDLE }, { 0xe, 0x77 }, { 0xf, 0x00 }, | ||
628 | { WAIT_IDLE }, { 0xe, 0x78 }, { 0xf, 0x00 }, | ||
629 | { WAIT_IDLE }, { 0xe, 0x79 }, { 0xf, 0x00 }, | ||
630 | { WAIT_IDLE }, { 0xe, 0x7a }, { 0xf, 0x00 }, | ||
631 | { WAIT_IDLE }, { 0xe, 0x7b }, { 0xf, 0x00 }, | ||
632 | { WAIT_IDLE }, { 0xe, 0x7c }, { 0xf, 0x00 }, | ||
633 | { WAIT_IDLE }, { 0xe, 0x7d }, { 0xf, 0x00 }, | ||
634 | { WAIT_IDLE }, { 0xe, 0x7e }, { 0xf, 0x00 }, | ||
635 | { WAIT_IDLE }, { 0xe, 0x7f }, { 0xf, 0x00 }, | ||
636 | { WAIT_IDLE }, { 0xe, 0x80 }, { 0xf, 0x00 }, | ||
637 | { WAIT_IDLE }, { 0xe, 0x81 }, { 0xf, 0x00 }, | ||
638 | { WAIT_IDLE }, { 0xe, 0x82 }, { 0xf, 0x00 }, | ||
639 | { WAIT_IDLE }, { 0xe, 0x83 }, { 0xf, 0x00 }, | ||
640 | { WAIT_IDLE }, { 0xe, 0x84 }, { 0xf, 0x00 }, | ||
641 | { WAIT_IDLE }, { 0xe, 0x85 }, { 0xf, 0x00 }, | ||
642 | { WAIT_IDLE }, { 0xe, 0x86 }, { 0xf, 0x00 }, | ||
643 | { WAIT_IDLE }, { 0xe, 0x87 }, { 0xf, 0x00 }, | ||
644 | { WAIT_IDLE }, { 0xe, 0x88 }, { 0xf, 0x00 }, | ||
645 | { WAIT_IDLE }, { 0xe, 0x89 }, { 0xf, 0x00 }, | ||
646 | { WAIT_IDLE }, { 0xe, 0x8a }, { 0xf, 0x00 }, | ||
647 | { WAIT_IDLE }, { 0xe, 0x8b }, { 0xf, 0x00 }, | ||
648 | { WAIT_IDLE }, { 0xe, 0x8c }, { 0xf, 0x00 }, | ||
649 | { WAIT_IDLE }, { 0xe, 0x8d }, { 0xf, 0x00 }, | ||
650 | { WAIT_IDLE }, { 0xe, 0x8e }, { 0xf, 0x00 }, | ||
651 | { WAIT_IDLE }, { 0xe, 0x8f }, { 0xf, 0x00 }, | ||
652 | { WAIT_IDLE }, { 0xe, 0x90 }, { 0xf, 0x00 }, | ||
653 | { WAIT_IDLE }, { 0xe, 0x91 }, { 0xf, 0x00 }, | ||
654 | { WAIT_IDLE }, { 0xe, 0x92 }, { 0xf, 0x00 }, | ||
655 | { WAIT_IDLE }, { 0xe, 0x93 }, { 0xf, 0x00 }, | ||
656 | { WAIT_IDLE }, { 0xe, 0x94 }, { 0xf, 0x00 }, | ||
657 | { WAIT_IDLE }, { 0xe, 0x95 }, { 0xf, 0x00 }, | ||
658 | { WAIT_IDLE }, { 0xe, 0x96 }, { 0xf, 0x00 }, | ||
659 | { WAIT_IDLE }, { 0xe, 0x97 }, { 0xf, 0x00 }, | ||
660 | { WAIT_IDLE }, { 0xe, 0x98 }, { 0xf, 0x00 }, | ||
661 | { WAIT_IDLE }, { 0xe, 0x99 }, { 0xf, 0x00 }, | ||
662 | { WAIT_IDLE }, { 0xe, 0x9a }, { 0xf, 0x00 }, | ||
663 | { WAIT_IDLE }, { 0xe, 0x9b }, { 0xf, 0x00 }, | ||
664 | { WAIT_IDLE }, { 0xe, 0x9c }, { 0xf, 0x00 }, | ||
665 | { WAIT_IDLE }, { 0xe, 0x9d }, { 0xf, 0x00 }, | ||
666 | { WAIT_IDLE }, { 0xe, 0x9e }, { 0xf, 0x00 }, | ||
667 | { WAIT_IDLE }, { 0xe, 0x9f }, { 0xf, 0x00 }, | ||
668 | { WAIT_IDLE }, { 0xe, 0xa0 }, { 0xf, 0x00 }, | ||
669 | { WAIT_IDLE }, { 0xe, 0xa1 }, { 0xf, 0x00 }, | ||
670 | { WAIT_IDLE }, { 0xe, 0xa2 }, { 0xf, 0x00 }, | ||
671 | { WAIT_IDLE }, { 0xe, 0xa3 }, { 0xf, 0x00 }, | ||
672 | { WAIT_IDLE }, { 0xe, 0xa4 }, { 0xf, 0x00 }, | ||
673 | { WAIT_IDLE }, { 0xe, 0xa5 }, { 0xf, 0x00 }, | ||
674 | { WAIT_IDLE }, { 0xe, 0xa6 }, { 0xf, 0x00 }, | ||
675 | { WAIT_IDLE }, { 0xe, 0xa7 }, { 0xf, 0x00 }, | ||
676 | { WAIT_IDLE }, { 0xe, 0xa8 }, { 0xf, 0x00 }, | ||
677 | { WAIT_IDLE }, { 0xe, 0xa9 }, { 0xf, 0x00 }, | ||
678 | { WAIT_IDLE }, { 0xe, 0xaa }, { 0xf, 0x00 }, | ||
679 | { WAIT_IDLE }, { 0xe, 0xab }, { 0xf, 0x00 }, | ||
680 | { WAIT_IDLE }, { 0xe, 0xac }, { 0xf, 0x00 }, | ||
681 | { WAIT_IDLE }, { 0xe, 0xad }, { 0xf, 0x00 }, | ||
682 | { WAIT_IDLE }, { 0xe, 0xae }, { 0xf, 0x00 }, | ||
683 | { WAIT_IDLE }, { 0xe, 0xaf }, { 0xf, 0x00 }, | ||
684 | { WAIT_IDLE }, { 0xe, 0xb0 }, { 0xf, 0x00 }, | ||
685 | { WAIT_IDLE }, { 0xe, 0xb1 }, { 0xf, 0x00 }, | ||
686 | { WAIT_IDLE }, { 0xe, 0xb2 }, { 0xf, 0x00 }, | ||
687 | { WAIT_IDLE }, { 0xe, 0xb3 }, { 0xf, 0x00 }, | ||
688 | { WAIT_IDLE }, { 0xe, 0xb4 }, { 0xf, 0x00 }, | ||
689 | { WAIT_IDLE }, { 0xe, 0xb5 }, { 0xf, 0x00 }, | ||
690 | { WAIT_IDLE }, { 0xe, 0xb6 }, { 0xf, 0x00 }, | ||
691 | { WAIT_IDLE }, { 0xe, 0xb7 }, { 0xf, 0x00 }, | ||
692 | { WAIT_IDLE }, { 0xe, 0xb8 }, { 0xf, 0x00 }, | ||
693 | { WAIT_IDLE }, { 0xe, 0xb9 }, { 0xf, 0x00 }, | ||
694 | { WAIT_IDLE }, { 0xe, 0xba }, { 0xf, 0x00 }, | ||
695 | { WAIT_IDLE }, { 0xe, 0xbb }, { 0xf, 0x00 }, | ||
696 | { WAIT_IDLE }, { 0xe, 0xbc }, { 0xf, 0x00 }, | ||
697 | { WAIT_IDLE }, { 0xe, 0xbd }, { 0xf, 0x00 }, | ||
698 | { WAIT_IDLE }, { 0xe, 0xbe }, { 0xf, 0x00 }, | ||
699 | { WAIT_IDLE }, { 0xe, 0xbf }, { 0xf, 0x00 }, | ||
700 | { WAIT_IDLE }, { 0xe, 0xc0 }, { 0xf, 0x00 }, | ||
701 | { WAIT_IDLE }, { 0xe, 0xc1 }, { 0xf, 0x00 }, | ||
702 | { WAIT_IDLE }, { 0xe, 0xc2 }, { 0xf, 0x00 }, | ||
703 | { WAIT_IDLE }, { 0xe, 0xc3 }, { 0xf, 0x00 }, | ||
704 | { WAIT_IDLE }, { 0xe, 0xc4 }, { 0xf, 0x00 }, | ||
705 | { WAIT_IDLE }, { 0xe, 0xc5 }, { 0xf, 0x00 }, | ||
706 | { WAIT_IDLE }, { 0xe, 0xc6 }, { 0xf, 0x00 }, | ||
707 | { WAIT_IDLE }, { 0xe, 0xc7 }, { 0xf, 0x00 }, | ||
708 | { WAIT_IDLE }, { 0xe, 0xc8 }, { 0xf, 0x00 }, | ||
709 | { WAIT_IDLE }, { 0xe, 0xc9 }, { 0xf, 0x00 }, | ||
710 | { WAIT_IDLE }, { 0xe, 0xca }, { 0xf, 0x00 }, | ||
711 | { WAIT_IDLE }, { 0xe, 0xcb }, { 0xf, 0x00 }, | ||
712 | { WAIT_IDLE }, { 0xe, 0xcc }, { 0xf, 0x00 }, | ||
713 | { WAIT_IDLE }, { 0xe, 0xcd }, { 0xf, 0x00 }, | ||
714 | { WAIT_IDLE }, { 0xe, 0xce }, { 0xf, 0x00 }, | ||
715 | { WAIT_IDLE }, { 0xe, 0xcf }, { 0xf, 0x00 }, | ||
716 | { WAIT_IDLE }, { 0xe, 0xd0 }, { 0xf, 0x00 }, | ||
717 | { WAIT_IDLE }, { 0xe, 0xd1 }, { 0xf, 0x00 }, | ||
718 | { WAIT_IDLE }, { 0xe, 0xd2 }, { 0xf, 0x00 }, | ||
719 | { WAIT_IDLE }, { 0xe, 0xd3 }, { 0xf, 0x00 }, | ||
720 | { WAIT_IDLE }, { 0xe, 0xd4 }, { 0xf, 0x00 }, | ||
721 | { WAIT_IDLE }, { 0xe, 0xd5 }, { 0xf, 0x00 }, | ||
722 | { WAIT_IDLE }, { 0xe, 0xd6 }, { 0xf, 0x00 }, | ||
723 | { WAIT_IDLE }, { 0xe, 0xd7 }, { 0xf, 0x00 }, | ||
724 | { WAIT_IDLE }, { 0xe, 0xd8 }, { 0xf, 0x00 }, | ||
725 | { WAIT_IDLE }, { 0xe, 0xd9 }, { 0xf, 0x00 }, | ||
726 | { WAIT_IDLE }, { 0xe, 0xda }, { 0xf, 0x00 }, | ||
727 | { WAIT_IDLE }, { 0xe, 0xdb }, { 0xf, 0x00 }, | ||
728 | { WAIT_IDLE }, { 0xe, 0xdc }, { 0xf, 0x00 }, | ||
729 | { WAIT_IDLE }, { 0xe, 0xdd }, { 0xf, 0x00 }, | ||
730 | { WAIT_IDLE }, { 0xe, 0xde }, { 0xf, 0x00 }, | ||
731 | { WAIT_IDLE }, { 0xe, 0xdf }, { 0xf, 0x00 }, | ||
732 | { WAIT_IDLE }, { 0xe, 0xe0 }, { 0xf, 0x00 }, | ||
733 | { WAIT_IDLE }, { 0xe, 0xe1 }, { 0xf, 0x00 }, | ||
734 | { WAIT_IDLE }, { 0xe, 0xe2 }, { 0xf, 0x00 }, | ||
735 | { WAIT_IDLE }, { 0xe, 0xe3 }, { 0xf, 0x00 }, | ||
736 | { WAIT_IDLE }, { 0xe, 0xe4 }, { 0xf, 0x00 }, | ||
737 | { WAIT_IDLE }, { 0xe, 0xe5 }, { 0xf, 0x00 }, | ||
738 | { WAIT_IDLE }, { 0xe, 0xe6 }, { 0xf, 0x00 }, | ||
739 | { WAIT_IDLE }, { 0xe, 0xe7 }, { 0xf, 0x00 }, | ||
740 | { WAIT_IDLE }, { 0xe, 0xe8 }, { 0xf, 0x00 }, | ||
741 | { WAIT_IDLE }, { 0xe, 0xe9 }, { 0xf, 0x00 }, | ||
742 | { WAIT_IDLE }, { 0xe, 0xea }, { 0xf, 0x00 }, | ||
743 | { WAIT_IDLE }, { 0xe, 0xeb }, { 0xf, 0x00 }, | ||
744 | { WAIT_IDLE }, { 0xe, 0xec }, { 0xf, 0x00 }, | ||
745 | { WAIT_IDLE }, { 0xe, 0xed }, { 0xf, 0x00 }, | ||
746 | { WAIT_IDLE }, { 0xe, 0xee }, { 0xf, 0x00 }, | ||
747 | { WAIT_IDLE }, { 0xe, 0xef }, { 0xf, 0x00 }, | ||
748 | { WAIT_IDLE }, { 0xe, 0xf0 }, { 0xf, 0x00 }, | ||
749 | { WAIT_IDLE }, { 0xe, 0xf1 }, { 0xf, 0x00 }, | ||
750 | { WAIT_IDLE }, { 0xe, 0xf2 }, { 0xf, 0x00 }, | ||
751 | { WAIT_IDLE }, { 0xe, 0xf3 }, { 0xf, 0x00 }, | ||
752 | { WAIT_IDLE }, { 0xe, 0xf4 }, { 0xf, 0x00 }, | ||
753 | { WAIT_IDLE }, { 0xe, 0xf5 }, { 0xf, 0x00 }, | ||
754 | { WAIT_IDLE }, { 0xe, 0xf6 }, { 0xf, 0x00 }, | ||
755 | { WAIT_IDLE }, { 0xe, 0xf7 }, { 0xf, 0x00 }, | ||
756 | { WAIT_IDLE }, { 0xe, 0xf8 }, { 0xf, 0x00 }, | ||
757 | { WAIT_IDLE }, { 0xe, 0xf9 }, { 0xf, 0x00 }, | ||
758 | { WAIT_IDLE }, { 0xe, 0xfa }, { 0xf, 0x00 }, | ||
759 | { WAIT_IDLE }, { 0xe, 0xfb }, { 0xf, 0x00 }, | ||
760 | { WAIT_IDLE }, { 0xe, 0xfc }, { 0xf, 0x00 }, | ||
761 | { WAIT_IDLE }, { 0xe, 0xfd }, { 0xf, 0x00 }, | ||
762 | { WAIT_IDLE }, { 0xe, 0xfe }, { 0xf, 0x00 }, | ||
763 | { WAIT_IDLE }, { 0xe, 0xff }, { 0xf, 0x00 }, | ||
764 | |||
765 | /* load page zero */ | ||
766 | { 0x9, 0x05 }, { 0xb, 0x00 }, { 0xa, 0x00 }, | ||
767 | |||
768 | { 0xd, 0x01 }, { 0xc, 0x7c }, { WAIT_IDLE }, | ||
769 | { 0xd, 0x00 }, { 0xc, 0x1e }, { WAIT_IDLE }, | ||
770 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
771 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
772 | { 0xd, 0x00 }, { 0xc, 0xf5 }, { WAIT_IDLE }, | ||
773 | { 0xd, 0x00 }, { 0xc, 0x11 }, { WAIT_IDLE }, | ||
774 | { 0xd, 0x00 }, { 0xc, 0x20 }, { WAIT_IDLE }, | ||
775 | { 0xd, 0x00 }, { 0xc, 0x32 }, { WAIT_IDLE }, | ||
776 | { 0xd, 0x00 }, { 0xc, 0x40 }, { WAIT_IDLE }, | ||
777 | { 0xd, 0x00 }, { 0xc, 0x13 }, { WAIT_IDLE }, | ||
778 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
779 | { 0xd, 0x00 }, { 0xc, 0x14 }, { WAIT_IDLE }, | ||
780 | { 0xd, 0x02 }, { 0xc, 0x76 }, { WAIT_IDLE }, | ||
781 | { 0xd, 0x00 }, { 0xc, 0x60 }, { WAIT_IDLE }, | ||
782 | { 0xd, 0x00 }, { 0xc, 0x80 }, { WAIT_IDLE }, | ||
783 | { 0xd, 0x02 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
784 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
785 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
786 | { 0xd, 0x02 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
787 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
788 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
789 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
790 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
791 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
792 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
793 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
794 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
795 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
796 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
797 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
798 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
799 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
800 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
801 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
802 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
803 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
804 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
805 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
806 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
807 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
808 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
809 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
810 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
811 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
812 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
813 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
814 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
815 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
816 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
817 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
818 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
819 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
820 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
821 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
822 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
823 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
824 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
825 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
826 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
827 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
828 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
829 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
830 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
831 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
832 | { 0xd, 0x00 }, { 0xc, 0x18 }, { WAIT_IDLE }, | ||
833 | { 0xd, 0x00 }, { 0xc, 0x19 }, { WAIT_IDLE }, | ||
834 | { 0xd, 0x01 }, { 0xc, 0x1a }, { WAIT_IDLE }, | ||
835 | { 0xd, 0x01 }, { 0xc, 0x20 }, { WAIT_IDLE }, | ||
836 | { 0xd, 0x01 }, { 0xc, 0x40 }, { WAIT_IDLE }, | ||
837 | { 0xd, 0x01 }, { 0xc, 0x17 }, { WAIT_IDLE }, | ||
838 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
839 | { 0xd, 0x01 }, { 0xc, 0x80 }, { WAIT_IDLE }, | ||
840 | { 0xd, 0x01 }, { 0xc, 0x20 }, { WAIT_IDLE }, | ||
841 | { 0xd, 0x00 }, { 0xc, 0x10 }, { WAIT_IDLE }, | ||
842 | { 0xd, 0x01 }, { 0xc, 0xa0 }, { WAIT_IDLE }, | ||
843 | { 0xd, 0x03 }, { 0xc, 0xd1 }, { WAIT_IDLE }, | ||
844 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
845 | { 0xd, 0x01 }, { 0xc, 0xf2 }, { WAIT_IDLE }, | ||
846 | { 0xd, 0x02 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
847 | { 0xd, 0x00 }, { 0xc, 0x13 }, { WAIT_IDLE }, | ||
848 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
849 | { 0xd, 0x00 }, { 0xc, 0xf4 }, { WAIT_IDLE }, | ||
850 | { 0xd, 0x02 }, { 0xc, 0xe0 }, { WAIT_IDLE }, | ||
851 | { 0xd, 0x00 }, { 0xc, 0x15 }, { WAIT_IDLE }, | ||
852 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
853 | { 0xd, 0x00 }, { 0xc, 0x16 }, { WAIT_IDLE }, | ||
854 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
855 | { 0xd, 0x00 }, { 0xc, 0x17 }, { WAIT_IDLE }, | ||
856 | { 0xd, 0x00 }, { 0xc, 0x20 }, { WAIT_IDLE }, | ||
857 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
858 | { 0xd, 0x00 }, { 0xc, 0x20 }, { WAIT_IDLE }, | ||
859 | { 0xd, 0x00 }, { 0xc, 0x50 }, { WAIT_IDLE }, | ||
860 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
861 | { 0xd, 0x00 }, { 0xc, 0x40 }, { WAIT_IDLE }, | ||
862 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
863 | { 0xd, 0x00 }, { 0xc, 0x71 }, { WAIT_IDLE }, | ||
864 | { 0xd, 0x02 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
865 | { 0xd, 0x00 }, { 0xc, 0x60 }, { WAIT_IDLE }, | ||
866 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
867 | { 0xd, 0x00 }, { 0xc, 0x92 }, { WAIT_IDLE }, | ||
868 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
869 | { 0xd, 0x00 }, { 0xc, 0x80 }, { WAIT_IDLE }, | ||
870 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
871 | { 0xd, 0x00 }, { 0xc, 0xb3 }, { WAIT_IDLE }, | ||
872 | { 0xd, 0x02 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
873 | { 0xd, 0x00 }, { 0xc, 0xa0 }, { WAIT_IDLE }, | ||
874 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
875 | { 0xd, 0x00 }, { 0xc, 0xd4 }, { WAIT_IDLE }, | ||
876 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
877 | { 0xd, 0x00 }, { 0xc, 0x40 }, { WAIT_IDLE }, | ||
878 | { 0xd, 0x00 }, { 0xc, 0x80 }, { WAIT_IDLE }, | ||
879 | { 0xd, 0x00 }, { 0xc, 0xf5 }, { WAIT_IDLE }, | ||
880 | { 0xd, 0x00 }, { 0xc, 0x20 }, { WAIT_IDLE }, | ||
881 | { 0xd, 0x00 }, { 0xc, 0x70 }, { WAIT_IDLE }, | ||
882 | { 0xd, 0x00 }, { 0xc, 0xa0 }, { WAIT_IDLE }, | ||
883 | { 0xd, 0x02 }, { 0xc, 0x11 }, { WAIT_IDLE }, | ||
884 | { 0xd, 0x00 }, { 0xc, 0x16 }, { WAIT_IDLE }, | ||
885 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
886 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
887 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
888 | { 0xd, 0x00 }, { 0xc, 0x20 }, { WAIT_IDLE }, | ||
889 | { 0xd, 0x02 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
890 | { 0xd, 0x00 }, { 0xc, 0x20 }, { WAIT_IDLE }, | ||
891 | { 0xd, 0x00 }, { 0xc, 0x10 }, { WAIT_IDLE }, | ||
892 | { 0xd, 0x00 }, { 0xc, 0x17 }, { WAIT_IDLE }, | ||
893 | { 0xd, 0x00 }, { 0xc, 0x1b }, { WAIT_IDLE }, | ||
894 | { 0xd, 0x00 }, { 0xc, 0x1d }, { WAIT_IDLE }, | ||
895 | { 0xd, 0x02 }, { 0xc, 0xdf }, { WAIT_IDLE }, | ||
896 | |||
897 | /* Now load page one */ | ||
898 | { 0x9, 0x05 }, { 0xb, 0x01 }, { 0xa, 0x00 }, | ||
899 | |||
900 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
901 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
902 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
903 | { 0xd, 0x02 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
904 | { 0xd, 0x00 }, { 0xc, 0x19 }, { WAIT_IDLE }, | ||
905 | { 0xd, 0x00 }, { 0xc, 0x1f }, { WAIT_IDLE }, | ||
906 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
907 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
908 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
909 | { 0xd, 0x03 }, { 0xc, 0xd8 }, { WAIT_IDLE }, | ||
910 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
911 | { 0xd, 0x02 }, { 0xc, 0x20 }, { WAIT_IDLE }, | ||
912 | { 0xd, 0x00 }, { 0xc, 0x19 }, { WAIT_IDLE }, | ||
913 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
914 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
915 | { 0xd, 0x00 }, { 0xc, 0x18 }, { WAIT_IDLE }, | ||
916 | { 0xd, 0x01 }, { 0xc, 0xc0 }, { WAIT_IDLE }, | ||
917 | { 0xd, 0x01 }, { 0xc, 0xfa }, { WAIT_IDLE }, | ||
918 | { 0xd, 0x00 }, { 0xc, 0x1a }, { WAIT_IDLE }, | ||
919 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
920 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
921 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
922 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
923 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
924 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
925 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
926 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
927 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
928 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
929 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
930 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
931 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
932 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
933 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
934 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
935 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
936 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
937 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
938 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
939 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
940 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
941 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
942 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
943 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
944 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
945 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
946 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
947 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
948 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
949 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
950 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
951 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
952 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
953 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
954 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
955 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
956 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
957 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
958 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
959 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
960 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
961 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
962 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
963 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
964 | { 0xd, 0x02 }, { 0xc, 0x40 }, { WAIT_IDLE }, | ||
965 | { 0xd, 0x02 }, { 0xc, 0x60 }, { WAIT_IDLE }, | ||
966 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
967 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
968 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
969 | { 0xd, 0x02 }, { 0xc, 0xc0 }, { WAIT_IDLE }, | ||
970 | { 0xd, 0x02 }, { 0xc, 0x80 }, { WAIT_IDLE }, | ||
971 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
972 | { 0xd, 0x02 }, { 0xc, 0xfb }, { WAIT_IDLE }, | ||
973 | { 0xd, 0x02 }, { 0xc, 0xa0 }, { WAIT_IDLE }, | ||
974 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
975 | { 0xd, 0x00 }, { 0xc, 0x1b }, { WAIT_IDLE }, | ||
976 | { 0xd, 0x02 }, { 0xc, 0xd7 }, { WAIT_IDLE }, | ||
977 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
978 | { 0xd, 0x02 }, { 0xc, 0xf7 }, { WAIT_IDLE }, | ||
979 | { 0xd, 0x03 }, { 0xc, 0x20 }, { WAIT_IDLE }, | ||
980 | { 0xd, 0x03 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
981 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
982 | { 0xd, 0x00 }, { 0xc, 0x1c }, { WAIT_IDLE }, | ||
983 | { 0xd, 0x03 }, { 0xc, 0x3c }, { WAIT_IDLE }, | ||
984 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
985 | { 0xd, 0x03 }, { 0xc, 0x3f }, { WAIT_IDLE }, | ||
986 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
987 | { 0xd, 0x03 }, { 0xc, 0xc0 }, { WAIT_IDLE }, | ||
988 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
989 | { 0xd, 0x03 }, { 0xc, 0xdf }, { WAIT_IDLE }, | ||
990 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
991 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
992 | { 0xd, 0x03 }, { 0xc, 0x5d }, { WAIT_IDLE }, | ||
993 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
994 | { 0xd, 0x03 }, { 0xc, 0xc0 }, { WAIT_IDLE }, | ||
995 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
996 | { 0xd, 0x03 }, { 0xc, 0x7d }, { WAIT_IDLE }, | ||
997 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
998 | { 0xd, 0x03 }, { 0xc, 0xc0 }, { WAIT_IDLE }, | ||
999 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1000 | { 0xd, 0x03 }, { 0xc, 0x9e }, { WAIT_IDLE }, | ||
1001 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1002 | { 0xd, 0x03 }, { 0xc, 0xc0 }, { WAIT_IDLE }, | ||
1003 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1004 | { 0xd, 0x03 }, { 0xc, 0xbe }, { WAIT_IDLE }, | ||
1005 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1006 | { 0xd, 0x03 }, { 0xc, 0xc0 }, { WAIT_IDLE }, | ||
1007 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1008 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1009 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1010 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1011 | { 0xd, 0x00 }, { 0xc, 0x1b }, { WAIT_IDLE }, | ||
1012 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1013 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1014 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1015 | { 0xd, 0x02 }, { 0xc, 0xdb }, { WAIT_IDLE }, | ||
1016 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1017 | { 0xd, 0x02 }, { 0xc, 0xdb }, { WAIT_IDLE }, | ||
1018 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1019 | { 0xd, 0x02 }, { 0xc, 0xe0 }, { WAIT_IDLE }, | ||
1020 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1021 | { 0xd, 0x02 }, { 0xc, 0xfb }, { WAIT_IDLE }, | ||
1022 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1023 | { 0xd, 0x02 }, { 0xc, 0xc0 }, { WAIT_IDLE }, | ||
1024 | { 0xd, 0x02 }, { 0xc, 0x40 }, { WAIT_IDLE }, | ||
1025 | { 0xd, 0x02 }, { 0xc, 0xfb }, { WAIT_IDLE }, | ||
1026 | { 0xd, 0x02 }, { 0xc, 0x60 }, { WAIT_IDLE }, | ||
1027 | { 0xd, 0x00 }, { 0xc, 0x1b }, { WAIT_IDLE }, | ||
1028 | |||
1029 | { 0x9, 0x05 }, { 0xb, 0x02 }, { 0xa, 0x00 }, | ||
1030 | |||
1031 | { 0xc, 0xc4 }, { WAIT_IDLE }, | ||
1032 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1033 | { 0xc, 0x44 }, { WAIT_IDLE }, | ||
1034 | { 0xc, 0x07 }, { WAIT_IDLE }, | ||
1035 | { 0xc, 0x44 }, { WAIT_IDLE }, | ||
1036 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1037 | { 0xc, 0x40 }, { WAIT_IDLE }, | ||
1038 | { 0xc, 0x25 }, { WAIT_IDLE }, | ||
1039 | { 0xc, 0x01 }, { WAIT_IDLE }, | ||
1040 | { 0xc, 0x06 }, { WAIT_IDLE }, | ||
1041 | { 0xc, 0xc4 }, { WAIT_IDLE }, | ||
1042 | { 0xc, 0x07 }, { WAIT_IDLE }, | ||
1043 | { 0xc, 0x40 }, { WAIT_IDLE }, | ||
1044 | { 0xc, 0x25 }, { WAIT_IDLE }, | ||
1045 | { 0xc, 0x01 }, { WAIT_IDLE }, | ||
1046 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1047 | { 0xc, 0x46 }, { WAIT_IDLE }, | ||
1048 | { 0xc, 0x46 }, { WAIT_IDLE }, | ||
1049 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1050 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1051 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1052 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1053 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1054 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1055 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1056 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1057 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1058 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1059 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1060 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1061 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1062 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1063 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1064 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1065 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1066 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1067 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1068 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1069 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1070 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1071 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1072 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1073 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1074 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1075 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1076 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1077 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1078 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1079 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1080 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1081 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1082 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1083 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1084 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1085 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1086 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1087 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1088 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1089 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1090 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1091 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1092 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1093 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1094 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1095 | { 0xc, 0x46 }, { WAIT_IDLE }, | ||
1096 | { 0xc, 0x07 }, { WAIT_IDLE }, | ||
1097 | { 0xc, 0x05 }, { WAIT_IDLE }, | ||
1098 | { 0xc, 0x05 }, { WAIT_IDLE }, | ||
1099 | { 0xc, 0x05 }, { WAIT_IDLE }, | ||
1100 | { 0xc, 0x04 }, { WAIT_IDLE }, | ||
1101 | { 0xc, 0x07 }, { WAIT_IDLE }, | ||
1102 | { 0xc, 0x05 }, { WAIT_IDLE }, | ||
1103 | { 0xc, 0x04 }, { WAIT_IDLE }, | ||
1104 | { 0xc, 0x07 }, { WAIT_IDLE }, | ||
1105 | { 0xc, 0x05 }, { WAIT_IDLE }, | ||
1106 | { 0xc, 0x44 }, { WAIT_IDLE }, | ||
1107 | { 0xc, 0x46 }, { WAIT_IDLE }, | ||
1108 | { 0xc, 0x44 }, { WAIT_IDLE }, | ||
1109 | { 0xc, 0x46 }, { WAIT_IDLE }, | ||
1110 | { 0xc, 0x46 }, { WAIT_IDLE }, | ||
1111 | { 0xc, 0x07 }, { WAIT_IDLE }, | ||
1112 | { 0xc, 0x05 }, { WAIT_IDLE }, | ||
1113 | { 0xc, 0x44 }, { WAIT_IDLE }, | ||
1114 | { 0xc, 0x46 }, { WAIT_IDLE }, | ||
1115 | { 0xc, 0x05 }, { WAIT_IDLE }, | ||
1116 | { 0xc, 0x46 }, { WAIT_IDLE }, | ||
1117 | { 0xc, 0x05 }, { WAIT_IDLE }, | ||
1118 | { 0xc, 0x46 }, { WAIT_IDLE }, | ||
1119 | { 0xc, 0x05 }, { WAIT_IDLE }, | ||
1120 | { 0xc, 0x46 }, { WAIT_IDLE }, | ||
1121 | { 0xc, 0x05 }, { WAIT_IDLE }, | ||
1122 | { 0xc, 0x44 }, { WAIT_IDLE }, | ||
1123 | { 0xc, 0x46 }, { WAIT_IDLE }, | ||
1124 | { 0xc, 0x05 }, { WAIT_IDLE }, | ||
1125 | { 0xc, 0x07 }, { WAIT_IDLE }, | ||
1126 | { 0xc, 0x44 }, { WAIT_IDLE }, | ||
1127 | { 0xc, 0x46 }, { WAIT_IDLE }, | ||
1128 | { 0xc, 0x05 }, { WAIT_IDLE }, | ||
1129 | { 0xc, 0x07 }, { WAIT_IDLE }, | ||
1130 | { 0xc, 0x44 }, { WAIT_IDLE }, | ||
1131 | { 0xc, 0x46 }, { WAIT_IDLE }, | ||
1132 | { 0xc, 0x05 }, { WAIT_IDLE }, | ||
1133 | { 0xc, 0x07 }, { WAIT_IDLE }, | ||
1134 | { 0xc, 0x44 }, { WAIT_IDLE }, | ||
1135 | { 0xc, 0x46 }, { WAIT_IDLE }, | ||
1136 | { 0xc, 0x05 }, { WAIT_IDLE }, | ||
1137 | { 0xc, 0x07 }, { WAIT_IDLE }, | ||
1138 | { 0xc, 0x44 }, { WAIT_IDLE }, | ||
1139 | { 0xc, 0x05 }, { WAIT_IDLE }, | ||
1140 | { 0xc, 0x05 }, { WAIT_IDLE }, | ||
1141 | { 0xc, 0x05 }, { WAIT_IDLE }, | ||
1142 | { 0xc, 0x44 }, { WAIT_IDLE }, | ||
1143 | { 0xc, 0x05 }, { WAIT_IDLE }, | ||
1144 | { 0xc, 0x05 }, { WAIT_IDLE }, | ||
1145 | { 0xc, 0x05 }, { WAIT_IDLE }, | ||
1146 | { 0xc, 0x46 }, { WAIT_IDLE }, | ||
1147 | { 0xc, 0x05 }, { WAIT_IDLE }, | ||
1148 | { 0xc, 0x46 }, { WAIT_IDLE }, | ||
1149 | { 0xc, 0x05 }, { WAIT_IDLE }, | ||
1150 | { 0xc, 0x46 }, { WAIT_IDLE }, | ||
1151 | { 0xc, 0x05 }, { WAIT_IDLE }, | ||
1152 | { 0xc, 0x46 }, { WAIT_IDLE }, | ||
1153 | { 0xc, 0x05 }, { WAIT_IDLE }, | ||
1154 | { 0xc, 0x46 }, { WAIT_IDLE }, | ||
1155 | { 0xc, 0x07 }, { WAIT_IDLE }, | ||
1156 | { 0xc, 0x46 }, { WAIT_IDLE }, | ||
1157 | { 0xc, 0x07 }, { WAIT_IDLE }, | ||
1158 | { 0xc, 0x44 }, { WAIT_IDLE }, | ||
1159 | |||
1160 | { 0x9, 0x05 }, { 0xb, 0x03 }, { 0xa, 0x00 }, | ||
1161 | |||
1162 | { 0xc, 0x07 }, { WAIT_IDLE }, | ||
1163 | { 0xc, 0x40 }, { WAIT_IDLE }, | ||
1164 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1165 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1166 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1167 | { 0xc, 0x47 }, { WAIT_IDLE }, | ||
1168 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1169 | { 0xc, 0x40 }, { WAIT_IDLE }, | ||
1170 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1171 | { 0xc, 0x40 }, { WAIT_IDLE }, | ||
1172 | { 0xc, 0x06 }, { WAIT_IDLE }, | ||
1173 | { 0xc, 0x40 }, { WAIT_IDLE }, | ||
1174 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1175 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1176 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1177 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1178 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1179 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1180 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1181 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1182 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1183 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1184 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1185 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1186 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1187 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1188 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1189 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1190 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1191 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1192 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1193 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1194 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1195 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1196 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1197 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1198 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1199 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1200 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1201 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1202 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1203 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1204 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1205 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1206 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1207 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1208 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1209 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1210 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1211 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1212 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1213 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1214 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1215 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1216 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1217 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1218 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1219 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1220 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1221 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1222 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1223 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1224 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1225 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1226 | { 0xc, 0x80 }, { WAIT_IDLE }, | ||
1227 | { 0xc, 0x80 }, { WAIT_IDLE }, | ||
1228 | { 0xc, 0xc0 }, { WAIT_IDLE }, | ||
1229 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1230 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1231 | { 0xc, 0x40 }, { WAIT_IDLE }, | ||
1232 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1233 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1234 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1235 | { 0xc, 0x40 }, { WAIT_IDLE }, | ||
1236 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1237 | { 0xc, 0x40 }, { WAIT_IDLE }, | ||
1238 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1239 | { 0xc, 0x60 }, { WAIT_IDLE }, | ||
1240 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1241 | { 0xc, 0x70 }, { WAIT_IDLE }, | ||
1242 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1243 | { 0xc, 0x40 }, { WAIT_IDLE }, | ||
1244 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1245 | { 0xc, 0x40 }, { WAIT_IDLE }, | ||
1246 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1247 | { 0xc, 0x42 }, { WAIT_IDLE }, | ||
1248 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1249 | { 0xc, 0x40 }, { WAIT_IDLE }, | ||
1250 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1251 | { 0xc, 0x02 }, { WAIT_IDLE }, | ||
1252 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1253 | { 0xc, 0x40 }, { WAIT_IDLE }, | ||
1254 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1255 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1256 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1257 | { 0xc, 0x40 }, { WAIT_IDLE }, | ||
1258 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1259 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1260 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1261 | { 0xc, 0x40 }, { WAIT_IDLE }, | ||
1262 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1263 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1264 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1265 | { 0xc, 0x40 }, { WAIT_IDLE }, | ||
1266 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1267 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1268 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1269 | { 0xc, 0x40 }, { WAIT_IDLE }, | ||
1270 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1271 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1272 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1273 | { 0xc, 0x42 }, { WAIT_IDLE }, | ||
1274 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1275 | { 0xc, 0x40 }, { WAIT_IDLE }, | ||
1276 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1277 | { 0xc, 0x42 }, { WAIT_IDLE }, | ||
1278 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1279 | { 0xc, 0x02 }, { WAIT_IDLE }, | ||
1280 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1281 | { 0xc, 0x02 }, { WAIT_IDLE }, | ||
1282 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1283 | { 0xc, 0x02 }, { WAIT_IDLE }, | ||
1284 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1285 | { 0xc, 0x42 }, { WAIT_IDLE }, | ||
1286 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1287 | { 0xc, 0xc0 }, { WAIT_IDLE }, | ||
1288 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1289 | { 0xc, 0x40 }, { WAIT_IDLE }, | ||
1290 | |||
1291 | { 0x9, 0x05 }, { 0xb, 0x04 }, { 0xa, 0x00 }, | ||
1292 | |||
1293 | { 0xc, 0x63 }, { WAIT_IDLE }, | ||
1294 | { 0xc, 0x03 }, { WAIT_IDLE }, | ||
1295 | { 0xc, 0x26 }, { WAIT_IDLE }, | ||
1296 | { 0xc, 0x02 }, { WAIT_IDLE }, | ||
1297 | { 0xc, 0x2c }, { WAIT_IDLE }, | ||
1298 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1299 | { 0xc, 0x24 }, { WAIT_IDLE }, | ||
1300 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1301 | { 0xc, 0x2e }, { WAIT_IDLE }, | ||
1302 | { 0xc, 0x02 }, { WAIT_IDLE }, | ||
1303 | { 0xc, 0x02 }, { WAIT_IDLE }, | ||
1304 | { 0xc, 0x02 }, { WAIT_IDLE }, | ||
1305 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1306 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1307 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1308 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1309 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1310 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1311 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1312 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1313 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1314 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1315 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1316 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1317 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1318 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1319 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1320 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1321 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1322 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1323 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1324 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1325 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1326 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1327 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1328 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1329 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1330 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1331 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1332 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1333 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1334 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1335 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1336 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1337 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1338 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1339 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1340 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1341 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1342 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1343 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1344 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1345 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1346 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1347 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1348 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1349 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1350 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1351 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1352 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1353 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1354 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1355 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1356 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1357 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1358 | { 0xc, 0x01 }, { WAIT_IDLE }, | ||
1359 | { 0xc, 0x20 }, { WAIT_IDLE }, | ||
1360 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1361 | { 0xc, 0x60 }, { WAIT_IDLE }, | ||
1362 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1363 | { 0xc, 0x20 }, { WAIT_IDLE }, | ||
1364 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1365 | { 0xc, 0x20 }, { WAIT_IDLE }, | ||
1366 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1367 | { 0xc, 0x20 }, { WAIT_IDLE }, | ||
1368 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1369 | { 0xc, 0x20 }, { WAIT_IDLE }, | ||
1370 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1371 | { 0xc, 0x20 }, { WAIT_IDLE }, | ||
1372 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1373 | { 0xc, 0x20 }, { WAIT_IDLE }, | ||
1374 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1375 | { 0xc, 0x20 }, { WAIT_IDLE }, | ||
1376 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1377 | { 0xc, 0x20 }, { WAIT_IDLE }, | ||
1378 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1379 | { 0xc, 0x60 }, { WAIT_IDLE }, | ||
1380 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1381 | { 0xc, 0x20 }, { WAIT_IDLE }, | ||
1382 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1383 | { 0xc, 0x60 }, { WAIT_IDLE }, | ||
1384 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1385 | { 0xc, 0x20 }, { WAIT_IDLE }, | ||
1386 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1387 | { 0xc, 0x60 }, { WAIT_IDLE }, | ||
1388 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1389 | { 0xc, 0x20 }, { WAIT_IDLE }, | ||
1390 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1391 | { 0xc, 0x60 }, { WAIT_IDLE }, | ||
1392 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1393 | { 0xc, 0x20 }, { WAIT_IDLE }, | ||
1394 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1395 | { 0xc, 0x60 }, { WAIT_IDLE }, | ||
1396 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1397 | { 0xc, 0x20 }, { WAIT_IDLE }, | ||
1398 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1399 | { 0xc, 0x60 }, { WAIT_IDLE }, | ||
1400 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1401 | { 0xc, 0x20 }, { WAIT_IDLE }, | ||
1402 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1403 | { 0xc, 0x20 }, { WAIT_IDLE }, | ||
1404 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1405 | { 0xc, 0x22 }, { WAIT_IDLE }, | ||
1406 | { 0xc, 0x02 }, { WAIT_IDLE }, | ||
1407 | { 0xc, 0x22 }, { WAIT_IDLE }, | ||
1408 | { 0xc, 0x02 }, { WAIT_IDLE }, | ||
1409 | { 0xc, 0x20 }, { WAIT_IDLE }, | ||
1410 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1411 | { 0xc, 0x60 }, { WAIT_IDLE }, | ||
1412 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1413 | { 0xc, 0x22 }, { WAIT_IDLE }, | ||
1414 | { 0xc, 0x02 }, { WAIT_IDLE }, | ||
1415 | { 0xc, 0x62 }, { WAIT_IDLE }, | ||
1416 | { 0xc, 0x02 }, { WAIT_IDLE }, | ||
1417 | { 0xc, 0x20 }, { WAIT_IDLE }, | ||
1418 | { 0xc, 0x01 }, { WAIT_IDLE }, | ||
1419 | { 0xc, 0x21 }, { WAIT_IDLE }, | ||
1420 | { 0xc, 0x01 }, { WAIT_IDLE }, | ||
1421 | |||
1422 | /* Load memory area (page six) */ | ||
1423 | { 0x9, 0x01 }, { 0xb, 0x06 }, | ||
1424 | |||
1425 | { 0xa, 0x00 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1426 | { 0xa, 0x02 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1427 | { 0xa, 0x04 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1428 | { 0xa, 0x06 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1429 | { 0xa, 0x08 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1430 | { 0xa, 0x0a }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1431 | { 0xa, 0x0c }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1432 | { 0xa, 0x0e }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1433 | { 0xa, 0x10 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1434 | { 0xa, 0x12 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1435 | { 0xa, 0x14 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1436 | { 0xa, 0x16 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1437 | { 0xa, 0x18 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1438 | { 0xa, 0x1a }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1439 | { 0xa, 0x1c }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1440 | { 0xa, 0x1e }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1441 | { 0xa, 0x20 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1442 | { 0xa, 0x22 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1443 | { 0xa, 0x24 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1444 | { 0xa, 0x26 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1445 | { 0xa, 0x28 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1446 | { 0xa, 0x2a }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1447 | { 0xa, 0x2c }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1448 | { 0xa, 0x2e }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1449 | { 0xa, 0x30 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1450 | { 0xa, 0x32 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1451 | { 0xa, 0x34 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1452 | { 0xa, 0x36 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1453 | { 0xa, 0x38 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1454 | { 0xa, 0x3a }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1455 | { 0xa, 0x3c }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1456 | { 0xa, 0x3e }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1457 | { 0xa, 0x40 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1458 | { 0xa, 0x42 }, { 0xd, 0x03 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1459 | { 0xa, 0x44 }, { 0xd, 0x01 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1460 | { 0xa, 0x46 }, { 0xd, 0x0a }, { 0xc, 0x21 }, { WAIT_IDLE }, | ||
1461 | { 0xa, 0x48 }, { 0xd, 0x0d }, { 0xc, 0x23 }, { WAIT_IDLE }, | ||
1462 | { 0xa, 0x4a }, { 0xd, 0x23 }, { 0xc, 0x1b }, { WAIT_IDLE }, | ||
1463 | { 0xa, 0x4c }, { 0xd, 0x37 }, { 0xc, 0x8f }, { WAIT_IDLE }, | ||
1464 | { 0xa, 0x4e }, { 0xd, 0x45 }, { 0xc, 0x77 }, { WAIT_IDLE }, | ||
1465 | { 0xa, 0x50 }, { 0xd, 0x52 }, { 0xc, 0xe2 }, { WAIT_IDLE }, | ||
1466 | { 0xa, 0x52 }, { 0xd, 0x1c }, { 0xc, 0x92 }, { WAIT_IDLE }, | ||
1467 | { 0xa, 0x54 }, { 0xd, 0x1c }, { 0xc, 0x52 }, { WAIT_IDLE }, | ||
1468 | { 0xa, 0x56 }, { 0xd, 0x07 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1469 | { 0xa, 0x58 }, { 0xd, 0x2f }, { 0xc, 0xc6 }, { WAIT_IDLE }, | ||
1470 | { 0xa, 0x5a }, { 0xd, 0x0b }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1471 | { 0xa, 0x5c }, { 0xd, 0x30 }, { 0xc, 0x06 }, { WAIT_IDLE }, | ||
1472 | { 0xa, 0x5e }, { 0xd, 0x17 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1473 | { 0xa, 0x60 }, { 0xd, 0x3d }, { 0xc, 0xda }, { WAIT_IDLE }, | ||
1474 | { 0xa, 0x62 }, { 0xd, 0x29 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1475 | { 0xa, 0x64 }, { 0xd, 0x3e }, { 0xc, 0x41 }, { WAIT_IDLE }, | ||
1476 | { 0xa, 0x66 }, { 0xd, 0x39 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1477 | { 0xa, 0x68 }, { 0xd, 0x4c }, { 0xc, 0x48 }, { WAIT_IDLE }, | ||
1478 | { 0xa, 0x6a }, { 0xd, 0x49 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1479 | { 0xa, 0x6c }, { 0xd, 0x4c }, { 0xc, 0x6c }, { WAIT_IDLE }, | ||
1480 | { 0xa, 0x6e }, { 0xd, 0x11 }, { 0xc, 0xd2 }, { WAIT_IDLE }, | ||
1481 | { 0xa, 0x70 }, { 0xd, 0x16 }, { 0xc, 0x0c }, { WAIT_IDLE }, | ||
1482 | { 0xa, 0x72 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1483 | { 0xa, 0x74 }, { 0xd, 0x00 }, { 0xc, 0x80 }, { WAIT_IDLE }, | ||
1484 | { 0xa, 0x76 }, { 0xd, 0x0f }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1485 | { 0xa, 0x78 }, { 0xd, 0x00 }, { 0xc, 0x80 }, { WAIT_IDLE }, | ||
1486 | { 0xa, 0x7a }, { 0xd, 0x13 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1487 | { 0xa, 0x7c }, { 0xd, 0x80 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1488 | { 0xa, 0x7e }, { 0xd, 0x80 }, { 0xc, 0x80 }, { WAIT_IDLE }, | ||
1489 | |||
1490 | { 0x9, 0x05 }, { 0xb, 0x07 }, { 0xa, 0x00 }, | ||
1491 | |||
1492 | { 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE }, | ||
1493 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1494 | { 0xd, 0x08 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1495 | { 0xd, 0x08 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1496 | { 0xd, 0x02 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1497 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1498 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1499 | { 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE }, | ||
1500 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1501 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1502 | { 0xd, 0x08 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1503 | { 0xd, 0x08 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1504 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1505 | { 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE }, | ||
1506 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1507 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1508 | { 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE }, | ||
1509 | { 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE }, | ||
1510 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1511 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1512 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1513 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1514 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1515 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1516 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1517 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1518 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1519 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1520 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1521 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1522 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1523 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1524 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1525 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1526 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1527 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1528 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1529 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1530 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1531 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1532 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1533 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1534 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1535 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1536 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1537 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1538 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1539 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1540 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1541 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1542 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1543 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1544 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1545 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1546 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1547 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1548 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1549 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1550 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1551 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1552 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1553 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1554 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1555 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1556 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1557 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1558 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1559 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1560 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1561 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1562 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1563 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1564 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1565 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1566 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1567 | { 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE }, | ||
1568 | { 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE }, | ||
1569 | { 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE }, | ||
1570 | { 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE }, | ||
1571 | { 0xd, 0x02 }, { 0xc, 0xe9 }, { WAIT_IDLE }, | ||
1572 | { 0xd, 0x06 }, { 0xc, 0x8c }, { WAIT_IDLE }, | ||
1573 | { 0xd, 0x06 }, { 0xc, 0x8c }, { WAIT_IDLE }, | ||
1574 | { 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE }, | ||
1575 | { 0xd, 0x1a }, { 0xc, 0x75 }, { WAIT_IDLE }, | ||
1576 | { 0xd, 0x0d }, { 0xc, 0x8b }, { WAIT_IDLE }, | ||
1577 | { 0xd, 0x04 }, { 0xc, 0xe9 }, { WAIT_IDLE }, | ||
1578 | { 0xd, 0x0b }, { 0xc, 0x16 }, { WAIT_IDLE }, | ||
1579 | { 0xd, 0x1a }, { 0xc, 0x38 }, { WAIT_IDLE }, | ||
1580 | { 0xd, 0x0d }, { 0xc, 0xc8 }, { WAIT_IDLE }, | ||
1581 | { 0xd, 0x04 }, { 0xc, 0x6f }, { WAIT_IDLE }, | ||
1582 | { 0xd, 0x0b }, { 0xc, 0x91 }, { WAIT_IDLE }, | ||
1583 | { 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE }, | ||
1584 | { 0xd, 0x06 }, { 0xc, 0x40 }, { WAIT_IDLE }, | ||
1585 | { 0xd, 0x06 }, { 0xc, 0x40 }, { WAIT_IDLE }, | ||
1586 | { 0xd, 0x02 }, { 0xc, 0x8f }, { WAIT_IDLE }, | ||
1587 | { 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE }, | ||
1588 | { 0xd, 0x06 }, { 0xc, 0x62 }, { WAIT_IDLE }, | ||
1589 | { 0xd, 0x06 }, { 0xc, 0x62 }, { WAIT_IDLE }, | ||
1590 | { 0xd, 0x02 }, { 0xc, 0x7b }, { WAIT_IDLE }, | ||
1591 | { 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE }, | ||
1592 | { 0xd, 0x06 }, { 0xc, 0x97 }, { WAIT_IDLE }, | ||
1593 | { 0xd, 0x06 }, { 0xc, 0x97 }, { WAIT_IDLE }, | ||
1594 | { 0xd, 0x02 }, { 0xc, 0x52 }, { WAIT_IDLE }, | ||
1595 | { 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE }, | ||
1596 | { 0xd, 0x06 }, { 0xc, 0xf6 }, { WAIT_IDLE }, | ||
1597 | { 0xd, 0x06 }, { 0xc, 0xf6 }, { WAIT_IDLE }, | ||
1598 | { 0xd, 0x02 }, { 0xc, 0x19 }, { WAIT_IDLE }, | ||
1599 | { 0xd, 0x05 }, { 0xc, 0x55 }, { WAIT_IDLE }, | ||
1600 | { 0xd, 0x05 }, { 0xc, 0x55 }, { WAIT_IDLE }, | ||
1601 | { 0xd, 0x05 }, { 0xc, 0x55 }, { WAIT_IDLE }, | ||
1602 | { 0xd, 0x05 }, { 0xc, 0x55 }, { WAIT_IDLE }, | ||
1603 | { 0xd, 0x05 }, { 0xc, 0x55 }, { WAIT_IDLE }, | ||
1604 | { 0xd, 0x05 }, { 0xc, 0x55 }, { WAIT_IDLE }, | ||
1605 | { 0xd, 0x05 }, { 0xc, 0x55 }, { WAIT_IDLE }, | ||
1606 | { 0xd, 0x05 }, { 0xc, 0x55 }, { WAIT_IDLE }, | ||
1607 | { 0xd, 0x14 }, { 0xc, 0xda }, { WAIT_IDLE }, | ||
1608 | { 0xd, 0x0d }, { 0xc, 0x93 }, { WAIT_IDLE }, | ||
1609 | { 0xd, 0x04 }, { 0xc, 0xda }, { WAIT_IDLE }, | ||
1610 | { 0xd, 0x05 }, { 0xc, 0x93 }, { WAIT_IDLE }, | ||
1611 | { 0xd, 0x14 }, { 0xc, 0xda }, { WAIT_IDLE }, | ||
1612 | { 0xd, 0x0d }, { 0xc, 0x93 }, { WAIT_IDLE }, | ||
1613 | { 0xd, 0x04 }, { 0xc, 0xda }, { WAIT_IDLE }, | ||
1614 | { 0xd, 0x05 }, { 0xc, 0x93 }, { WAIT_IDLE }, | ||
1615 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1616 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1617 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1618 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1619 | { 0xd, 0x02 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1620 | |||
1621 | /* Now setup the MOD area. */ | ||
1622 | { 0xe, 0x01 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1623 | { 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1624 | { 0xe, 0x01 }, { 0xf, 0x01 }, { WAIT_IDLE }, | ||
1625 | { 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1626 | { 0xe, 0x01 }, { 0xf, 0x02 }, { WAIT_IDLE }, | ||
1627 | { 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1628 | { 0xe, 0x01 }, { 0xf, 0x03 }, { WAIT_IDLE }, | ||
1629 | { 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1630 | { 0xe, 0x01 }, { 0xf, 0x04 }, { WAIT_IDLE }, | ||
1631 | { 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1632 | { 0xe, 0x01 }, { 0xf, 0x05 }, { WAIT_IDLE }, | ||
1633 | { 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1634 | { 0xe, 0x01 }, { 0xf, 0x06 }, { WAIT_IDLE }, | ||
1635 | { 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1636 | { 0xe, 0x01 }, { 0xf, 0x07 }, { WAIT_IDLE }, | ||
1637 | { 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1638 | { 0xe, 0x01 }, { 0xf, 0x08 }, { WAIT_IDLE }, | ||
1639 | { 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1640 | { 0xe, 0x01 }, { 0xf, 0x09 }, { WAIT_IDLE }, | ||
1641 | { 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1642 | { 0xe, 0x01 }, { 0xf, 0x0a }, { WAIT_IDLE }, | ||
1643 | { 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1644 | { 0xe, 0x01 }, { 0xf, 0x0b }, { WAIT_IDLE }, | ||
1645 | { 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1646 | { 0xe, 0x01 }, { 0xf, 0x0c }, { WAIT_IDLE }, | ||
1647 | { 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1648 | { 0xe, 0x01 }, { 0xf, 0x0d }, { WAIT_IDLE }, | ||
1649 | { 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1650 | { 0xe, 0x01 }, { 0xf, 0x0e }, { WAIT_IDLE }, | ||
1651 | { 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1652 | { 0xe, 0x01 }, { 0xf, 0x0f }, { WAIT_IDLE }, | ||
1653 | { 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1654 | |||
1655 | { 0xe, 0xb0 }, { 0xf, 0x20 }, { WAIT_IDLE }, | ||
1656 | { 0xe, 0xb1 }, { 0xf, 0x20 }, { WAIT_IDLE }, | ||
1657 | { 0xe, 0xb2 }, { 0xf, 0x20 }, { WAIT_IDLE }, | ||
1658 | { 0xe, 0xb3 }, { 0xf, 0x20 }, { WAIT_IDLE }, | ||
1659 | { 0xe, 0xb4 }, { 0xf, 0x20 }, { WAIT_IDLE }, | ||
1660 | { 0xe, 0xb5 }, { 0xf, 0x20 }, { WAIT_IDLE }, | ||
1661 | { 0xe, 0xb6 }, { 0xf, 0x20 }, { WAIT_IDLE }, | ||
1662 | { 0xe, 0xb7 }, { 0xf, 0x20 }, { WAIT_IDLE }, | ||
1663 | { 0xe, 0xb8 }, { 0xf, 0x20 }, { WAIT_IDLE }, | ||
1664 | { 0xe, 0xb9 }, { 0xf, 0x20 }, { WAIT_IDLE }, | ||
1665 | { 0xe, 0xba }, { 0xf, 0x20 }, { WAIT_IDLE }, | ||
1666 | { 0xe, 0xbb }, { 0xf, 0x20 }, { WAIT_IDLE }, | ||
1667 | { 0xe, 0xbc }, { 0xf, 0x20 }, { WAIT_IDLE }, | ||
1668 | { 0xe, 0xbd }, { 0xf, 0x20 }, { WAIT_IDLE }, | ||
1669 | { 0xe, 0xbe }, { 0xf, 0x20 }, { WAIT_IDLE }, | ||
1670 | { 0xe, 0xbf }, { 0xf, 0x20 }, { WAIT_IDLE }, | ||
1671 | |||
1672 | { 0xe, 0xf0 }, { 0xf, 0x20 }, { WAIT_IDLE }, | ||
1673 | { 0xe, 0xf1 }, { 0xf, 0x20 }, { WAIT_IDLE }, | ||
1674 | { 0xe, 0xf2 }, { 0xf, 0x20 }, { WAIT_IDLE }, | ||
1675 | { 0xe, 0xf3 }, { 0xf, 0x20 }, { WAIT_IDLE }, | ||
1676 | { 0xe, 0xf4 }, { 0xf, 0x20 }, { WAIT_IDLE }, | ||
1677 | { 0xe, 0xf5 }, { 0xf, 0x20 }, { WAIT_IDLE }, | ||
1678 | { 0xe, 0xf6 }, { 0xf, 0x20 }, { WAIT_IDLE }, | ||
1679 | { 0xe, 0xf7 }, { 0xf, 0x20 }, { WAIT_IDLE }, | ||
1680 | { 0xe, 0xf8 }, { 0xf, 0x20 }, { WAIT_IDLE }, | ||
1681 | { 0xe, 0xf9 }, { 0xf, 0x20 }, { WAIT_IDLE }, | ||
1682 | { 0xe, 0xfa }, { 0xf, 0x20 }, { WAIT_IDLE }, | ||
1683 | { 0xe, 0xfb }, { 0xf, 0x20 }, { WAIT_IDLE }, | ||
1684 | { 0xe, 0xfc }, { 0xf, 0x20 }, { WAIT_IDLE }, | ||
1685 | { 0xe, 0xfd }, { 0xf, 0x20 }, { WAIT_IDLE }, | ||
1686 | { 0xe, 0xfe }, { 0xf, 0x20 }, { WAIT_IDLE }, | ||
1687 | { 0xe, 0xff }, { 0xf, 0x20 }, { WAIT_IDLE }, | ||
1688 | |||
1689 | { 0xe, 0x10 }, { 0xf, 0xff }, { WAIT_IDLE }, | ||
1690 | { 0xe, 0x11 }, { 0xf, 0xff }, { WAIT_IDLE }, | ||
1691 | { 0xe, 0x12 }, { 0xf, 0xff }, { WAIT_IDLE }, | ||
1692 | { 0xe, 0x13 }, { 0xf, 0xff }, { WAIT_IDLE }, | ||
1693 | { 0xe, 0x14 }, { 0xf, 0xff }, { WAIT_IDLE }, | ||
1694 | { 0xe, 0x15 }, { 0xf, 0xff }, { WAIT_IDLE }, | ||
1695 | { 0xe, 0x16 }, { 0xf, 0xff }, { WAIT_IDLE }, | ||
1696 | { 0xe, 0x17 }, { 0xf, 0xff }, { WAIT_IDLE }, | ||
1697 | { 0xe, 0x18 }, { 0xf, 0xff }, { WAIT_IDLE }, | ||
1698 | { 0xe, 0x19 }, { 0xf, 0xff }, { WAIT_IDLE }, | ||
1699 | { 0xe, 0x1a }, { 0xf, 0xff }, { WAIT_IDLE }, | ||
1700 | { 0xe, 0x1b }, { 0xf, 0xff }, { WAIT_IDLE }, | ||
1701 | { 0xe, 0x1c }, { 0xf, 0xff }, { WAIT_IDLE }, | ||
1702 | { 0xe, 0x1d }, { 0xf, 0xff }, { WAIT_IDLE }, | ||
1703 | { 0xe, 0x1e }, { 0xf, 0x40 }, { WAIT_IDLE }, | ||
1704 | { 0xe, 0x1f }, { 0xf, 0xff }, { WAIT_IDLE }, | ||
1705 | { 0xe, 0x20 }, { 0xf, 0xff }, { WAIT_IDLE }, | ||
1706 | { 0xe, 0x21 }, { 0xf, 0xff }, { WAIT_IDLE }, | ||
1707 | { 0xe, 0x22 }, { 0xf, 0xff }, { WAIT_IDLE }, | ||
1708 | { 0xe, 0x23 }, { 0xf, 0xff }, { WAIT_IDLE }, | ||
1709 | { 0xe, 0x24 }, { 0xf, 0xff }, { WAIT_IDLE }, | ||
1710 | { 0xe, 0x25 }, { 0xf, 0xff }, { WAIT_IDLE }, | ||
1711 | { 0xe, 0x26 }, { 0xf, 0xff }, { WAIT_IDLE }, | ||
1712 | { 0xe, 0x27 }, { 0xf, 0xff }, { WAIT_IDLE }, | ||
1713 | { 0xe, 0x28 }, { 0xf, 0xff }, { WAIT_IDLE }, | ||
1714 | { 0xe, 0x29 }, { 0xf, 0xff }, { WAIT_IDLE }, | ||
1715 | { 0xe, 0x2a }, { 0xf, 0xff }, { WAIT_IDLE }, | ||
1716 | { 0xe, 0x2b }, { 0xf, 0xff }, { WAIT_IDLE }, | ||
1717 | { 0xe, 0x2c }, { 0xf, 0xff }, { WAIT_IDLE }, | ||
1718 | { 0xe, 0x2d }, { 0xf, 0xff }, { WAIT_IDLE }, | ||
1719 | { 0xe, 0x2e }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1720 | { 0xe, 0x2f }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1721 | { 0xe, 0x30 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1722 | { 0xe, 0x31 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1723 | { 0xe, 0x32 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1724 | { 0xe, 0x33 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1725 | { 0xe, 0x34 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1726 | { 0xe, 0x35 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1727 | { 0xe, 0x36 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1728 | { 0xe, 0x37 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1729 | { 0xe, 0x38 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1730 | { 0xe, 0x39 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1731 | { 0xe, 0x3a }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1732 | { 0xe, 0x3b }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1733 | { 0xe, 0x3c }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1734 | { 0xe, 0x3d }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1735 | { 0xe, 0x3e }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1736 | { 0xe, 0x3f }, { 0xf, 0x20 }, { WAIT_IDLE }, | ||
1737 | { 0xe, 0x40 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1738 | { 0xe, 0x41 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1739 | { 0xe, 0x42 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1740 | { 0xe, 0x43 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1741 | { 0xe, 0x44 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1742 | { 0xe, 0x45 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1743 | { 0xe, 0x46 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1744 | { 0xe, 0x47 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1745 | { 0xe, 0x48 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1746 | { 0xe, 0x49 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1747 | { 0xe, 0x4a }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1748 | { 0xe, 0x4b }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1749 | { 0xe, 0x4c }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1750 | { 0xe, 0x4d }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1751 | { 0xe, 0x4e }, { 0xf, 0x0e }, { WAIT_IDLE }, | ||
1752 | { 0xe, 0x4f }, { 0xf, 0x0e }, { WAIT_IDLE }, | ||
1753 | { 0xe, 0x50 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1754 | { 0xe, 0x51 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1755 | { 0xe, 0x52 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1756 | { 0xe, 0x53 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1757 | { 0xe, 0x54 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1758 | { 0xe, 0x55 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1759 | { 0xe, 0x56 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1760 | { 0xe, 0x57 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1761 | { 0xe, 0x58 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1762 | { 0xe, 0x59 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1763 | { 0xe, 0x5a }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1764 | { 0xe, 0x5b }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1765 | { 0xe, 0x5c }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1766 | { 0xe, 0x5d }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1767 | { 0xe, 0x5e }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1768 | { 0xe, 0x5f }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1769 | { 0xe, 0x60 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1770 | { 0xe, 0x61 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1771 | { 0xe, 0x62 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1772 | { 0xe, 0x63 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1773 | { 0xe, 0x64 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1774 | { 0xe, 0x65 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1775 | { 0xe, 0x66 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1776 | { 0xe, 0x67 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1777 | { 0xe, 0x68 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1778 | { 0xe, 0x69 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1779 | { 0xe, 0x6a }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1780 | { 0xe, 0x6b }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1781 | { 0xe, 0x6c }, { 0xf, 0x40 }, { WAIT_IDLE }, | ||
1782 | { 0xe, 0x6d }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1783 | { 0xe, 0x6e }, { 0xf, 0x40 }, { WAIT_IDLE }, | ||
1784 | { 0xe, 0x6f }, { 0xf, 0x40 }, { WAIT_IDLE }, | ||
1785 | { 0xe, 0x70 }, { 0xf, 0xc0 }, { WAIT_IDLE }, | ||
1786 | { 0xe, 0x71 }, { 0xf, 0xc0 }, { WAIT_IDLE }, | ||
1787 | { 0xe, 0x72 }, { 0xf, 0xc0 }, { WAIT_IDLE }, | ||
1788 | { 0xe, 0x73 }, { 0xf, 0xc0 }, { WAIT_IDLE }, | ||
1789 | { 0xe, 0x74 }, { 0xf, 0xc0 }, { WAIT_IDLE }, | ||
1790 | { 0xe, 0x75 }, { 0xf, 0xc0 }, { WAIT_IDLE }, | ||
1791 | { 0xe, 0x76 }, { 0xf, 0xc0 }, { WAIT_IDLE }, | ||
1792 | { 0xe, 0x77 }, { 0xf, 0xc0 }, { WAIT_IDLE }, | ||
1793 | { 0xe, 0x78 }, { 0xf, 0xc0 }, { WAIT_IDLE }, | ||
1794 | { 0xe, 0x79 }, { 0xf, 0xc0 }, { WAIT_IDLE }, | ||
1795 | { 0xe, 0x7a }, { 0xf, 0xc0 }, { WAIT_IDLE }, | ||
1796 | { 0xe, 0x7b }, { 0xf, 0xc0 }, { WAIT_IDLE }, | ||
1797 | { 0xe, 0x7c }, { 0xf, 0xc0 }, { WAIT_IDLE }, | ||
1798 | { 0xe, 0x7d }, { 0xf, 0xc0 }, { WAIT_IDLE }, | ||
1799 | { 0xe, 0x7e }, { 0xf, 0xc0 }, { WAIT_IDLE }, | ||
1800 | { 0xe, 0x7f }, { 0xf, 0xc0 }, { WAIT_IDLE }, | ||
1801 | { 0xe, 0x80 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1802 | { 0xe, 0x81 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1803 | { 0xe, 0x82 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1804 | { 0xe, 0x83 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1805 | { 0xe, 0x84 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1806 | { 0xe, 0x85 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1807 | { 0xe, 0x86 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1808 | { 0xe, 0x87 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1809 | { 0xe, 0x88 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1810 | { 0xe, 0x89 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1811 | { 0xe, 0x8a }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1812 | { 0xe, 0x8b }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1813 | { 0xe, 0x8c }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1814 | { 0xe, 0x8d }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1815 | { 0xe, 0x8e }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1816 | { 0xe, 0x8f }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1817 | { 0xe, 0x90 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1818 | { 0xe, 0x91 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1819 | { 0xe, 0x92 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1820 | { 0xe, 0x93 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1821 | { 0xe, 0x94 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1822 | { 0xe, 0x95 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1823 | { 0xe, 0x96 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1824 | { 0xe, 0x97 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1825 | { 0xe, 0x98 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1826 | { 0xe, 0x99 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1827 | { 0xe, 0x9a }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1828 | { 0xe, 0x9b }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1829 | { 0xe, 0x9c }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1830 | { 0xe, 0x9d }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1831 | { 0xe, 0x9e }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1832 | { 0xe, 0x9f }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1833 | { 0xe, 0xa0 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1834 | { 0xe, 0xa1 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1835 | { 0xe, 0xa2 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1836 | { 0xe, 0xa3 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1837 | { 0xe, 0xa4 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1838 | { 0xe, 0xa5 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1839 | { 0xe, 0xa6 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1840 | { 0xe, 0xa7 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1841 | { 0xe, 0xa8 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1842 | { 0xe, 0xa9 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1843 | { 0xe, 0xaa }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1844 | { 0xe, 0xab }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1845 | { 0xe, 0xac }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1846 | { 0xe, 0xad }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1847 | { 0xe, 0xae }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1848 | { 0xe, 0xaf }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1849 | |||
1850 | { 0xe, 0xc0 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1851 | { 0xe, 0xc1 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1852 | { 0xe, 0xc2 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1853 | { 0xe, 0xc3 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1854 | { 0xe, 0xc4 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1855 | { 0xe, 0xc5 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1856 | { 0xe, 0xc6 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1857 | { 0xe, 0xc7 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1858 | { 0xe, 0xc8 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1859 | { 0xe, 0xc9 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1860 | { 0xe, 0xca }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1861 | { 0xe, 0xcb }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1862 | { 0xe, 0xcc }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1863 | { 0xe, 0xcd }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1864 | { 0xe, 0xce }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1865 | { 0xe, 0xcf }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1866 | { 0xe, 0xd0 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1867 | { 0xe, 0xd1 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1868 | { 0xe, 0xd2 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1869 | { 0xe, 0xd3 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1870 | { 0xe, 0xd4 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1871 | { 0xe, 0xd5 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1872 | { 0xe, 0xd6 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1873 | { 0xe, 0xd7 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1874 | { 0xe, 0xd8 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1875 | { 0xe, 0xd9 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1876 | { 0xe, 0xda }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1877 | { 0xe, 0xdb }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1878 | { 0xe, 0xdc }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1879 | { 0xe, 0xdd }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1880 | { 0xe, 0xde }, { 0xf, 0x10 }, { WAIT_IDLE }, | ||
1881 | { 0xe, 0xdf }, { 0xf, 0x10 }, { WAIT_IDLE }, | ||
1882 | { 0xe, 0xe0 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1883 | { 0xe, 0xe1 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1884 | { 0xe, 0xe2 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1885 | { 0xe, 0xe3 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1886 | { 0xe, 0xe4 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1887 | { 0xe, 0xe5 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1888 | { 0xe, 0xe6 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1889 | { 0xe, 0xe7 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1890 | { 0xe, 0xe8 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1891 | { 0xe, 0xe9 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1892 | { 0xe, 0xea }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1893 | { 0xe, 0xeb }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1894 | { 0xe, 0xec }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1895 | { 0xe, 0xed }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1896 | { 0xe, 0xee }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1897 | { 0xe, 0xef }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
1898 | |||
1899 | { 0xe, 0x01 }, { 0xf, 0x00 }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, | ||
1900 | { 0xe, 0x01 }, { 0xf, 0x01 }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, | ||
1901 | { 0xe, 0x01 }, { 0xf, 0x02 }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, | ||
1902 | { 0xe, 0x01 }, { 0xf, 0x03 }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, | ||
1903 | { 0xe, 0x01 }, { 0xf, 0x04 }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, | ||
1904 | { 0xe, 0x01 }, { 0xf, 0x05 }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, | ||
1905 | { 0xe, 0x01 }, { 0xf, 0x06 }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, | ||
1906 | { 0xe, 0x01 }, { 0xf, 0x07 }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, | ||
1907 | { 0xe, 0x01 }, { 0xf, 0x08 }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, | ||
1908 | { 0xe, 0x01 }, { 0xf, 0x09 }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, | ||
1909 | { 0xe, 0x01 }, { 0xf, 0x0a }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, | ||
1910 | { 0xe, 0x01 }, { 0xf, 0x0b }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, | ||
1911 | { 0xe, 0x01 }, { 0xf, 0x0c }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, | ||
1912 | { 0xe, 0x01 }, { 0xf, 0x0d }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, | ||
1913 | { 0xe, 0x01 }, { 0xf, 0x0e }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, | ||
1914 | { 0xe, 0x01 }, { 0xf, 0x0f }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, | ||
1915 | |||
1916 | /* mute on */ | ||
1917 | { 0x8, 0x02 }, | ||
1918 | |||
1919 | /* Now set the coefficients and so forth for the programs above */ | ||
1920 | { 0xb, 0x07 }, { 0xa, 0x46 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1921 | { 0xb, 0x07 }, { 0xa, 0x49 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1922 | { 0xb, 0x00 }, { 0xa, 0x4b }, { 0xd, 0x03 }, { 0xc, 0x11 }, { WAIT_IDLE }, | ||
1923 | { 0xb, 0x00 }, { 0xa, 0x4d }, { 0xd, 0x01 }, { 0xc, 0x32 }, { WAIT_IDLE }, | ||
1924 | { 0xb, 0x07 }, { 0xa, 0x46 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1925 | { 0xb, 0x07 }, { 0xa, 0x49 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1926 | { 0xb, 0x07 }, { 0xa, 0x40 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1927 | { 0xb, 0x07 }, { 0xa, 0x41 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1928 | { 0xb, 0x01 }, { 0xa, 0x40 }, { 0xd, 0x02 }, { 0xc, 0x40 }, { WAIT_IDLE }, | ||
1929 | { 0xb, 0x01 }, { 0xa, 0x41 }, { 0xd, 0x02 }, { 0xc, 0x60 }, { WAIT_IDLE }, | ||
1930 | { 0xb, 0x07 }, { 0xa, 0x40 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1931 | { 0xb, 0x07 }, { 0xa, 0x41 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1932 | { 0xb, 0x07 }, { 0xa, 0x47 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1933 | { 0xb, 0x07 }, { 0xa, 0x4a }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1934 | { 0xb, 0x00 }, { 0xa, 0x47 }, { 0xd, 0x01 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1935 | { 0xb, 0x00 }, { 0xa, 0x4a }, { 0xd, 0x01 }, { 0xc, 0x20 }, { WAIT_IDLE }, | ||
1936 | { 0xb, 0x07 }, { 0xa, 0x47 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1937 | { 0xb, 0x07 }, { 0xa, 0x4a }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1938 | { 0xb, 0x07 }, { 0xa, 0x7c }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1939 | { 0xb, 0x07 }, { 0xa, 0x7e }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1940 | { 0xb, 0x00 }, { 0xa, 0x00 }, { 0xd, 0x01 }, { 0xc, 0x1c }, { WAIT_IDLE }, | ||
1941 | { 0xb, 0x07 }, { 0xa, 0x7c }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1942 | { 0xb, 0x07 }, { 0xa, 0x7e }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1943 | { 0xb, 0x07 }, { 0xa, 0x44 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1944 | { 0xb, 0x00 }, { 0xa, 0x44 }, { 0xd, 0x01 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1945 | { 0xb, 0x07 }, { 0xa, 0x44 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1946 | { 0xb, 0x07 }, { 0xa, 0x42 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1947 | { 0xb, 0x07 }, { 0xa, 0x43 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1948 | { 0xb, 0x00 }, { 0xa, 0x42 }, { 0xd, 0x01 }, { 0xc, 0x1a }, { WAIT_IDLE }, | ||
1949 | { 0xb, 0x00 }, { 0xa, 0x43 }, { 0xd, 0x01 }, { 0xc, 0x20 }, { WAIT_IDLE }, | ||
1950 | { 0xb, 0x07 }, { 0xa, 0x42 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1951 | { 0xb, 0x07 }, { 0xa, 0x43 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1952 | { 0xb, 0x07 }, { 0xa, 0x40 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1953 | { 0xb, 0x07 }, { 0xa, 0x41 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1954 | { 0xb, 0x01 }, { 0xa, 0x40 }, { 0xd, 0x02 }, { 0xc, 0x40 }, { WAIT_IDLE }, | ||
1955 | { 0xb, 0x01 }, { 0xa, 0x41 }, { 0xd, 0x02 }, { 0xc, 0x60 }, { WAIT_IDLE }, | ||
1956 | { 0xb, 0x07 }, { 0xa, 0x40 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1957 | { 0xb, 0x07 }, { 0xa, 0x41 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1958 | { 0xb, 0x07 }, { 0xa, 0x44 }, { 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE }, | ||
1959 | { 0xb, 0x07 }, { 0xa, 0x42 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1960 | { 0xb, 0x07 }, { 0xa, 0x43 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1961 | { 0xb, 0x07 }, { 0xa, 0x40 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1962 | { 0xb, 0x07 }, { 0xa, 0x41 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
1963 | { 0xb, 0x07 }, { 0xa, 0x51 }, { 0xd, 0x06 }, { 0xc, 0x40 }, { WAIT_IDLE }, | ||
1964 | { 0xb, 0x07 }, { 0xa, 0x50 }, { 0xd, 0x06 }, { 0xc, 0x40 }, { WAIT_IDLE }, | ||
1965 | { 0xb, 0x07 }, { 0xa, 0x4f }, { 0xd, 0x03 }, { 0xc, 0x81 }, { WAIT_IDLE }, | ||
1966 | { 0xb, 0x07 }, { 0xa, 0x53 }, { 0xd, 0x1a }, { 0xc, 0x76 }, { WAIT_IDLE }, | ||
1967 | { 0xb, 0x07 }, { 0xa, 0x54 }, { 0xd, 0x0d }, { 0xc, 0x8b }, { WAIT_IDLE }, | ||
1968 | { 0xb, 0x07 }, { 0xa, 0x55 }, { 0xd, 0x04 }, { 0xc, 0xe9 }, { WAIT_IDLE }, | ||
1969 | { 0xb, 0x07 }, { 0xa, 0x56 }, { 0xd, 0x0b }, { 0xc, 0x17 }, { WAIT_IDLE }, | ||
1970 | { 0xb, 0x07 }, { 0xa, 0x57 }, { 0xd, 0x1a }, { 0xc, 0x38 }, { WAIT_IDLE }, | ||
1971 | { 0xb, 0x07 }, { 0xa, 0x58 }, { 0xd, 0x0d }, { 0xc, 0xc9 }, { WAIT_IDLE }, | ||
1972 | { 0xb, 0x07 }, { 0xa, 0x59 }, { 0xd, 0x04 }, { 0xc, 0x6f }, { WAIT_IDLE }, | ||
1973 | { 0xb, 0x07 }, { 0xa, 0x5a }, { 0xd, 0x0b }, { 0xc, 0x91 }, { WAIT_IDLE }, | ||
1974 | { 0xb, 0x07 }, { 0xa, 0x73 }, { 0xd, 0x14 }, { 0xc, 0xda }, { WAIT_IDLE }, | ||
1975 | { 0xb, 0x07 }, { 0xa, 0x74 }, { 0xd, 0x0d }, { 0xc, 0x93 }, { WAIT_IDLE }, | ||
1976 | { 0xb, 0x07 }, { 0xa, 0x75 }, { 0xd, 0x04 }, { 0xc, 0xd9 }, { WAIT_IDLE }, | ||
1977 | { 0xb, 0x07 }, { 0xa, 0x76 }, { 0xd, 0x05 }, { 0xc, 0x93 }, { WAIT_IDLE }, | ||
1978 | { 0xb, 0x07 }, { 0xa, 0x77 }, { 0xd, 0x14 }, { 0xc, 0xda }, { WAIT_IDLE }, | ||
1979 | { 0xb, 0x07 }, { 0xa, 0x78 }, { 0xd, 0x0d }, { 0xc, 0x93 }, { WAIT_IDLE }, | ||
1980 | { 0xb, 0x07 }, { 0xa, 0x79 }, { 0xd, 0x04 }, { 0xc, 0xd9 }, { WAIT_IDLE }, | ||
1981 | { 0xb, 0x07 }, { 0xa, 0x7a }, { 0xd, 0x05 }, { 0xc, 0x93 }, { WAIT_IDLE }, | ||
1982 | { 0xb, 0x07 }, { 0xa, 0x5e }, { 0xd, 0x03 }, { 0xc, 0x68 }, { WAIT_IDLE }, | ||
1983 | { 0xb, 0x07 }, { 0xa, 0x5c }, { 0xd, 0x04 }, { 0xc, 0x31 }, { WAIT_IDLE }, | ||
1984 | { 0xb, 0x07 }, { 0xa, 0x5d }, { 0xd, 0x04 }, { 0xc, 0x31 }, { WAIT_IDLE }, | ||
1985 | { 0xb, 0x07 }, { 0xa, 0x62 }, { 0xd, 0x03 }, { 0xc, 0x52 }, { WAIT_IDLE }, | ||
1986 | { 0xb, 0x07 }, { 0xa, 0x60 }, { 0xd, 0x04 }, { 0xc, 0x76 }, { WAIT_IDLE }, | ||
1987 | { 0xb, 0x07 }, { 0xa, 0x61 }, { 0xd, 0x04 }, { 0xc, 0x76 }, { WAIT_IDLE }, | ||
1988 | { 0xb, 0x07 }, { 0xa, 0x66 }, { 0xd, 0x03 }, { 0xc, 0x2e }, { WAIT_IDLE }, | ||
1989 | { 0xb, 0x07 }, { 0xa, 0x64 }, { 0xd, 0x04 }, { 0xc, 0xda }, { WAIT_IDLE }, | ||
1990 | { 0xb, 0x07 }, { 0xa, 0x65 }, { 0xd, 0x04 }, { 0xc, 0xda }, { WAIT_IDLE }, | ||
1991 | { 0xb, 0x07 }, { 0xa, 0x6a }, { 0xd, 0x02 }, { 0xc, 0xf6 }, { WAIT_IDLE }, | ||
1992 | { 0xb, 0x07 }, { 0xa, 0x68 }, { 0xd, 0x05 }, { 0xc, 0x62 }, { WAIT_IDLE }, | ||
1993 | { 0xb, 0x07 }, { 0xa, 0x69 }, { 0xd, 0x05 }, { 0xc, 0x62 }, { WAIT_IDLE }, | ||
1994 | { 0xb, 0x06 }, { 0xa, 0x46 }, { 0xd, 0x0a }, { 0xc, 0x22 }, { WAIT_IDLE }, | ||
1995 | { 0xb, 0x06 }, { 0xa, 0x48 }, { 0xd, 0x0d }, { 0xc, 0x24 }, { WAIT_IDLE }, | ||
1996 | { 0xb, 0x06 }, { 0xa, 0x6e }, { 0xd, 0x11 }, { 0xc, 0xd3 }, { WAIT_IDLE }, | ||
1997 | { 0xb, 0x06 }, { 0xa, 0x70 }, { 0xd, 0x15 }, { 0xc, 0xcb }, { WAIT_IDLE }, | ||
1998 | { 0xb, 0x06 }, { 0xa, 0x52 }, { 0xd, 0x20 }, { 0xc, 0x93 }, { WAIT_IDLE }, | ||
1999 | { 0xb, 0x06 }, { 0xa, 0x54 }, { 0xd, 0x20 }, { 0xc, 0x54 }, { WAIT_IDLE }, | ||
2000 | { 0xb, 0x06 }, { 0xa, 0x4a }, { 0xd, 0x27 }, { 0xc, 0x1d }, { WAIT_IDLE }, | ||
2001 | { 0xb, 0x06 }, { 0xa, 0x58 }, { 0xd, 0x2f }, { 0xc, 0xc8 }, { WAIT_IDLE }, | ||
2002 | { 0xb, 0x06 }, { 0xa, 0x5c }, { 0xd, 0x30 }, { 0xc, 0x07 }, { WAIT_IDLE }, | ||
2003 | { 0xb, 0x06 }, { 0xa, 0x4c }, { 0xd, 0x37 }, { 0xc, 0x90 }, { WAIT_IDLE }, | ||
2004 | { 0xb, 0x06 }, { 0xa, 0x60 }, { 0xd, 0x3d }, { 0xc, 0xdb }, { WAIT_IDLE }, | ||
2005 | { 0xb, 0x06 }, { 0xa, 0x64 }, { 0xd, 0x3e }, { 0xc, 0x42 }, { WAIT_IDLE }, | ||
2006 | { 0xb, 0x06 }, { 0xa, 0x4e }, { 0xd, 0x45 }, { 0xc, 0x78 }, { WAIT_IDLE }, | ||
2007 | { 0xb, 0x06 }, { 0xa, 0x68 }, { 0xd, 0x4c }, { 0xc, 0x48 }, { WAIT_IDLE }, | ||
2008 | { 0xb, 0x06 }, { 0xa, 0x6c }, { 0xd, 0x4c }, { 0xc, 0x6c }, { WAIT_IDLE }, | ||
2009 | { 0xb, 0x06 }, { 0xa, 0x50 }, { 0xd, 0x52 }, { 0xc, 0xe2 }, { WAIT_IDLE }, | ||
2010 | { 0xb, 0x06 }, { 0xa, 0x42 }, { 0xd, 0x02 }, { 0xc, 0xba }, { WAIT_IDLE }, | ||
2011 | |||
2012 | /* Some settings (?) */ | ||
2013 | { WAIT_IDLE }, { 0xe, 0x1e }, { 0xf, 0x14 }, | ||
2014 | { WAIT_IDLE }, { 0xe, 0xde }, { 0xf, 0x20 }, | ||
2015 | { WAIT_IDLE }, { 0xe, 0xdf }, { 0xf, 0x20 }, | ||
2016 | |||
2017 | /* some more coefficients */ | ||
2018 | { WAIT_IDLE }, { 0xb, 0x06 }, { 0xa, 0x78 }, { 0xd, 0x00 }, { 0xc, 0x40 }, | ||
2019 | { WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x03 }, { 0xd, 0x0f }, { 0xc, 0xff }, | ||
2020 | { WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x0b }, { 0xd, 0x0f }, { 0xc, 0xff }, | ||
2021 | { WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x02 }, { 0xd, 0x00 }, { 0xc, 0x00 }, | ||
2022 | { WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x0a }, { 0xd, 0x00 }, { 0xc, 0x00 }, | ||
2023 | { WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x46 }, { 0xd, 0x00 }, { 0xc, 0x00 }, | ||
2024 | { WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x49 }, { 0xd, 0x00 }, { 0xc, 0x00 }, | ||
2025 | |||
2026 | /* Now, for some strange reason, lets reload every page | ||
2027 | and all the coefficients over again. I have *NO* idea | ||
2028 | why this is done. I do know that no sound is produced | ||
2029 | is this phase is omitted. */ | ||
2030 | { 0x9, 0x05 }, { 0xb, 0x00 }, { 0xa, 0x10 }, | ||
2031 | |||
2032 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2033 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2034 | { 0xd, 0x02 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2035 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2036 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2037 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2038 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2039 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2040 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2041 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2042 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2043 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2044 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2045 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2046 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2047 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2048 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2049 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2050 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2051 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2052 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2053 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2054 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2055 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2056 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2057 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2058 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2059 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2060 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2061 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2062 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2063 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2064 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2065 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2066 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2067 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2068 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2069 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2070 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2071 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2072 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2073 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2074 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2075 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2076 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2077 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2078 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2079 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2080 | |||
2081 | { 0x9, 0x05 }, { 0xb, 0x01 }, { 0xa, 0x10 }, | ||
2082 | |||
2083 | { 0xd, 0x01 }, { 0xc, 0xc0 }, { WAIT_IDLE }, | ||
2084 | { 0xd, 0x01 }, { 0xc, 0xfa }, { WAIT_IDLE }, | ||
2085 | { 0xd, 0x00 }, { 0xc, 0x1a }, { WAIT_IDLE }, | ||
2086 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2087 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2088 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2089 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2090 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2091 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2092 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2093 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2094 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2095 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2096 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2097 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2098 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2099 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2100 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2101 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2102 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2103 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2104 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2105 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2106 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2107 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2108 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2109 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2110 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2111 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2112 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2113 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2114 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2115 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2116 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2117 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2118 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2119 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2120 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2121 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2122 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2123 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2124 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2125 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2126 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2127 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2128 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2129 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2130 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2131 | |||
2132 | { WAIT_IDLE }, { WAIT_IDLE }, | ||
2133 | |||
2134 | { 0x9, 0x05 }, { 0xb, 0x02 }, { 0xa, 0x10 }, | ||
2135 | |||
2136 | { 0xc, 0x46 }, { WAIT_IDLE }, | ||
2137 | { 0xc, 0x46 }, { WAIT_IDLE }, | ||
2138 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2139 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2140 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2141 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2142 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2143 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2144 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2145 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2146 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2147 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2148 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2149 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2150 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2151 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2152 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2153 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2154 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2155 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2156 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2157 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2158 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2159 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2160 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2161 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2162 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2163 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2164 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2165 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2166 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2167 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2168 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2169 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2170 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2171 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2172 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2173 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2174 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2175 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2176 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2177 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2178 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2179 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2180 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2181 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2182 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2183 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2184 | |||
2185 | { 0x9, 0x05 }, { 0xb, 0x03 }, { 0xa, 0x10 }, | ||
2186 | |||
2187 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2188 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2189 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2190 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2191 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2192 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2193 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2194 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2195 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2196 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2197 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2198 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2199 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2200 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2201 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2202 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2203 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2204 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2205 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2206 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2207 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2208 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2209 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2210 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2211 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2212 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2213 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2214 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2215 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2216 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2217 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2218 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2219 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2220 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2221 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2222 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2223 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2224 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2225 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2226 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2227 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2228 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2229 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2230 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2231 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2232 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2233 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2234 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2235 | |||
2236 | { 0x9, 0x05 }, { 0xb, 0x04 }, { 0xa, 0x10 }, | ||
2237 | |||
2238 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2239 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2240 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2241 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2242 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2243 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2244 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2245 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2246 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2247 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2248 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2249 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2250 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2251 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2252 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2253 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2254 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2255 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2256 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2257 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2258 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2259 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2260 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2261 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2262 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2263 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2264 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2265 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2266 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2267 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2268 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2269 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2270 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2271 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2272 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2273 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2274 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2275 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2276 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2277 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2278 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2279 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2280 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2281 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2282 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2283 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2284 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2285 | { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2286 | |||
2287 | /* Page six v.2 */ | ||
2288 | { 0x9, 0x01 }, { 0xb, 0x06 }, | ||
2289 | |||
2290 | { 0xa, 0x10 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2291 | { 0xa, 0x12 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2292 | { 0xa, 0x14 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2293 | { 0xa, 0x16 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2294 | { 0xa, 0x18 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2295 | { 0xa, 0x1a }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2296 | { 0xa, 0x1c }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2297 | { 0xa, 0x1e }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2298 | { 0xa, 0x20 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2299 | { 0xa, 0x22 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2300 | { 0xa, 0x24 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2301 | { 0xa, 0x26 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2302 | { 0xa, 0x28 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2303 | { 0xa, 0x2a }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2304 | { 0xa, 0x2c }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2305 | { 0xa, 0x2e }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2306 | { 0xa, 0x30 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2307 | { 0xa, 0x32 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2308 | { 0xa, 0x34 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2309 | { 0xa, 0x36 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2310 | { 0xa, 0x38 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2311 | { 0xa, 0x3a }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2312 | { 0xa, 0x3c }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2313 | { 0xa, 0x3e }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2314 | |||
2315 | { 0x9, 0x05 }, { 0xb, 0x07 }, { 0xa, 0x10 }, | ||
2316 | |||
2317 | { 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE }, | ||
2318 | { 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE }, | ||
2319 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2320 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2321 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2322 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2323 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2324 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2325 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2326 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2327 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2328 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2329 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2330 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2331 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2332 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2333 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2334 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2335 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2336 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2337 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2338 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2339 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2340 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2341 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2342 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2343 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2344 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2345 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2346 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2347 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2348 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2349 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2350 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2351 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2352 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2353 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2354 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2355 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2356 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2357 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2358 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2359 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2360 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2361 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2362 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2363 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2364 | { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2365 | |||
2366 | { 0xe, 0x01 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2367 | { 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2368 | { 0xe, 0x01 }, { 0xf, 0x01 }, { WAIT_IDLE }, | ||
2369 | { 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2370 | { 0xe, 0x01 }, { 0xf, 0x02 }, { WAIT_IDLE }, | ||
2371 | { 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2372 | { 0xe, 0x01 }, { 0xf, 0x03 }, { WAIT_IDLE }, | ||
2373 | { 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2374 | { 0xe, 0x01 }, { 0xf, 0x04 }, { WAIT_IDLE }, | ||
2375 | { 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2376 | { 0xe, 0x01 }, { 0xf, 0x05 }, { WAIT_IDLE }, | ||
2377 | { 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2378 | { 0xe, 0x01 }, { 0xf, 0x06 }, { WAIT_IDLE }, | ||
2379 | { 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2380 | { 0xe, 0x01 }, { 0xf, 0x07 }, { WAIT_IDLE }, | ||
2381 | { 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2382 | { 0xe, 0xb0 }, { 0xf, 0x20 }, { WAIT_IDLE }, | ||
2383 | { 0xe, 0xb1 }, { 0xf, 0x20 }, { WAIT_IDLE }, | ||
2384 | { 0xe, 0xb2 }, { 0xf, 0x20 }, { WAIT_IDLE }, | ||
2385 | { 0xe, 0xb3 }, { 0xf, 0x20 }, { WAIT_IDLE }, | ||
2386 | { 0xe, 0xb4 }, { 0xf, 0x20 }, { WAIT_IDLE }, | ||
2387 | { 0xe, 0xb5 }, { 0xf, 0x20 }, { WAIT_IDLE }, | ||
2388 | { 0xe, 0xb6 }, { 0xf, 0x20 }, { WAIT_IDLE }, | ||
2389 | { 0xe, 0xb7 }, { 0xf, 0x20 }, { WAIT_IDLE }, | ||
2390 | { 0xe, 0xf0 }, { 0xf, 0x20 }, { WAIT_IDLE }, | ||
2391 | { 0xe, 0xf1 }, { 0xf, 0x20 }, { WAIT_IDLE }, | ||
2392 | { 0xe, 0xf2 }, { 0xf, 0x20 }, { WAIT_IDLE }, | ||
2393 | { 0xe, 0xf3 }, { 0xf, 0x20 }, { WAIT_IDLE }, | ||
2394 | { 0xe, 0xf4 }, { 0xf, 0x20 }, { WAIT_IDLE }, | ||
2395 | { 0xe, 0xf5 }, { 0xf, 0x20 }, { WAIT_IDLE }, | ||
2396 | { 0xe, 0xf6 }, { 0xf, 0x20 }, { WAIT_IDLE }, | ||
2397 | { 0xe, 0xf7 }, { 0xf, 0x20 }, { WAIT_IDLE }, | ||
2398 | { 0xe, 0x10 }, { 0xf, 0xff }, { WAIT_IDLE }, | ||
2399 | { 0xe, 0x11 }, { 0xf, 0xff }, { WAIT_IDLE }, | ||
2400 | { 0xe, 0x12 }, { 0xf, 0xff }, { WAIT_IDLE }, | ||
2401 | { 0xe, 0x13 }, { 0xf, 0xff }, { WAIT_IDLE }, | ||
2402 | { 0xe, 0x14 }, { 0xf, 0xff }, { WAIT_IDLE }, | ||
2403 | { 0xe, 0x15 }, { 0xf, 0xff }, { WAIT_IDLE }, | ||
2404 | { 0xe, 0x16 }, { 0xf, 0xff }, { WAIT_IDLE }, | ||
2405 | { 0xe, 0x17 }, { 0xf, 0xff }, { WAIT_IDLE }, | ||
2406 | { 0xe, 0x20 }, { 0xf, 0xff }, { WAIT_IDLE }, | ||
2407 | { 0xe, 0x21 }, { 0xf, 0xff }, { WAIT_IDLE }, | ||
2408 | { 0xe, 0x22 }, { 0xf, 0xff }, { WAIT_IDLE }, | ||
2409 | { 0xe, 0x23 }, { 0xf, 0xff }, { WAIT_IDLE }, | ||
2410 | { 0xe, 0x24 }, { 0xf, 0xff }, { WAIT_IDLE }, | ||
2411 | { 0xe, 0x25 }, { 0xf, 0xff }, { WAIT_IDLE }, | ||
2412 | { 0xe, 0x26 }, { 0xf, 0xff }, { WAIT_IDLE }, | ||
2413 | { 0xe, 0x27 }, { 0xf, 0xff }, { WAIT_IDLE }, | ||
2414 | { 0xe, 0x30 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2415 | { 0xe, 0x31 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2416 | { 0xe, 0x32 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2417 | { 0xe, 0x33 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2418 | { 0xe, 0x34 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2419 | { 0xe, 0x35 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2420 | { 0xe, 0x36 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2421 | { 0xe, 0x37 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2422 | { 0xe, 0x40 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2423 | { 0xe, 0x41 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2424 | { 0xe, 0x42 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2425 | { 0xe, 0x43 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2426 | { 0xe, 0x44 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2427 | { 0xe, 0x45 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2428 | { 0xe, 0x46 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2429 | { 0xe, 0x47 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2430 | { 0xe, 0x50 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2431 | { 0xe, 0x51 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2432 | { 0xe, 0x52 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2433 | { 0xe, 0x53 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2434 | { 0xe, 0x54 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2435 | { 0xe, 0x55 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2436 | { 0xe, 0x56 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2437 | { 0xe, 0x57 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2438 | { 0xe, 0x60 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2439 | { 0xe, 0x61 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2440 | { 0xe, 0x62 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2441 | { 0xe, 0x63 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2442 | { 0xe, 0x64 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2443 | { 0xe, 0x65 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2444 | { 0xe, 0x66 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2445 | { 0xe, 0x67 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2446 | { 0xe, 0x70 }, { 0xf, 0xc0 }, { WAIT_IDLE }, | ||
2447 | { 0xe, 0x71 }, { 0xf, 0xc0 }, { WAIT_IDLE }, | ||
2448 | { 0xe, 0x72 }, { 0xf, 0xc0 }, { WAIT_IDLE }, | ||
2449 | { 0xe, 0x73 }, { 0xf, 0xc0 }, { WAIT_IDLE }, | ||
2450 | { 0xe, 0x74 }, { 0xf, 0xc0 }, { WAIT_IDLE }, | ||
2451 | { 0xe, 0x75 }, { 0xf, 0xc0 }, { WAIT_IDLE }, | ||
2452 | { 0xe, 0x76 }, { 0xf, 0xc0 }, { WAIT_IDLE }, | ||
2453 | { 0xe, 0x77 }, { 0xf, 0xc0 }, { WAIT_IDLE }, | ||
2454 | { 0xe, 0x80 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2455 | { 0xe, 0x81 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2456 | { 0xe, 0x82 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2457 | { 0xe, 0x83 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2458 | { 0xe, 0x84 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2459 | { 0xe, 0x85 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2460 | { 0xe, 0x86 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2461 | { 0xe, 0x87 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2462 | { 0xe, 0x90 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2463 | { 0xe, 0x91 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2464 | { 0xe, 0x92 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2465 | { 0xe, 0x93 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2466 | { 0xe, 0x94 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2467 | { 0xe, 0x95 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2468 | { 0xe, 0x96 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2469 | { 0xe, 0x97 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2470 | { 0xe, 0xa0 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2471 | { 0xe, 0xa1 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2472 | { 0xe, 0xa2 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2473 | { 0xe, 0xa3 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2474 | { 0xe, 0xa4 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2475 | { 0xe, 0xa5 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2476 | { 0xe, 0xa6 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2477 | { 0xe, 0xa7 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2478 | { 0xe, 0xc0 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2479 | { 0xe, 0xc1 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2480 | { 0xe, 0xc2 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2481 | { 0xe, 0xc3 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2482 | { 0xe, 0xc4 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2483 | { 0xe, 0xc5 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2484 | { 0xe, 0xc6 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2485 | { 0xe, 0xc7 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2486 | { 0xe, 0xd0 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2487 | { 0xe, 0xd1 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2488 | { 0xe, 0xd2 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2489 | { 0xe, 0xd3 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2490 | { 0xe, 0xd4 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2491 | { 0xe, 0xd5 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2492 | { 0xe, 0xd6 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2493 | { 0xe, 0xd7 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2494 | { 0xe, 0xe0 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2495 | { 0xe, 0xe1 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2496 | { 0xe, 0xe2 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2497 | { 0xe, 0xe3 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2498 | { 0xe, 0xe4 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2499 | { 0xe, 0xe5 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2500 | { 0xe, 0xe6 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2501 | { 0xe, 0xe7 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2502 | { 0xe, 0x01 }, { 0xf, 0x00 }, { WAIT_IDLE }, | ||
2503 | { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, | ||
2504 | { 0xe, 0x01 }, { 0xf, 0x01 }, { WAIT_IDLE }, | ||
2505 | { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, | ||
2506 | { 0xe, 0x01 }, { 0xf, 0x02 }, { WAIT_IDLE }, | ||
2507 | { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, | ||
2508 | { 0xe, 0x01 }, { 0xf, 0x03 }, { WAIT_IDLE }, | ||
2509 | { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, | ||
2510 | { 0xe, 0x01 }, { 0xf, 0x04 }, { WAIT_IDLE }, | ||
2511 | { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, | ||
2512 | { 0xe, 0x01 }, { 0xf, 0x05 }, { WAIT_IDLE }, | ||
2513 | { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, | ||
2514 | { 0xe, 0x01 }, { 0xf, 0x06 }, { WAIT_IDLE }, | ||
2515 | { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, | ||
2516 | { 0xe, 0x01 }, { 0xf, 0x07 }, { WAIT_IDLE }, | ||
2517 | { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, | ||
2518 | |||
2519 | { 0xb, 0x07 }, { 0xa, 0x46 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2520 | { 0xb, 0x07 }, { 0xa, 0x49 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2521 | { 0xb, 0x07 }, { 0xa, 0x45 }, { 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE }, | ||
2522 | { 0xb, 0x07 }, { 0xa, 0x48 }, { 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE }, | ||
2523 | { 0xb, 0x07 }, { 0xa, 0x7b }, { 0xd, 0x04 }, { 0xc, 0xcc }, { WAIT_IDLE }, | ||
2524 | { 0xb, 0x07 }, { 0xa, 0x7d }, { 0xd, 0x04 }, { 0xc, 0xcc }, { WAIT_IDLE }, | ||
2525 | { 0xb, 0x07 }, { 0xa, 0x7c }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2526 | { 0xb, 0x07 }, { 0xa, 0x7e }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2527 | { 0xb, 0x07 }, { 0xa, 0x46 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2528 | { 0xb, 0x07 }, { 0xa, 0x49 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2529 | { 0xb, 0x07 }, { 0xa, 0x47 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2530 | { 0xb, 0x07 }, { 0xa, 0x4a }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2531 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2532 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, | ||
2533 | |||
2534 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x00 }, { 0xc, 0x00 }, | ||
2535 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x00 }, { 0xc, 0x00 }, | ||
2536 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x00 }, { 0xc, 0x28 }, | ||
2537 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x00 }, { 0xc, 0x28 }, | ||
2538 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x00 }, { 0xc, 0x51 }, | ||
2539 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x00 }, { 0xc, 0x51 }, | ||
2540 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x00 }, { 0xc, 0x7a }, | ||
2541 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x00 }, { 0xc, 0x7a }, | ||
2542 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x00 }, { 0xc, 0xa3 }, | ||
2543 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x00 }, { 0xc, 0xa3 }, | ||
2544 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x00 }, { 0xc, 0xcc }, | ||
2545 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x00 }, { 0xc, 0xcc }, | ||
2546 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x00 }, { 0xc, 0xf5 }, | ||
2547 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x00 }, { 0xc, 0xf5 }, | ||
2548 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x01 }, { 0xc, 0x1e }, | ||
2549 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x01 }, { 0xc, 0x1e }, | ||
2550 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x01 }, { 0xc, 0x47 }, | ||
2551 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x01 }, { 0xc, 0x47 }, | ||
2552 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x01 }, { 0xc, 0x70 }, | ||
2553 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x01 }, { 0xc, 0x70 }, | ||
2554 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x01 }, { 0xc, 0x99 }, | ||
2555 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x01 }, { 0xc, 0x99 }, | ||
2556 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x01 }, { 0xc, 0xc2 }, | ||
2557 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x01 }, { 0xc, 0xc2 }, | ||
2558 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x01 }, { 0xc, 0xeb }, | ||
2559 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x01 }, { 0xc, 0xeb }, | ||
2560 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x02 }, { 0xc, 0x14 }, | ||
2561 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x02 }, { 0xc, 0x14 }, | ||
2562 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x02 }, { 0xc, 0x3d }, | ||
2563 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x02 }, { 0xc, 0x3d }, | ||
2564 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x02 }, { 0xc, 0x66 }, | ||
2565 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x02 }, { 0xc, 0x66 }, | ||
2566 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x02 }, { 0xc, 0x8f }, | ||
2567 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x02 }, { 0xc, 0x8f }, | ||
2568 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x02 }, { 0xc, 0xb8 }, | ||
2569 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x02 }, { 0xc, 0xb8 }, | ||
2570 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x02 }, { 0xc, 0xe1 }, | ||
2571 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x02 }, { 0xc, 0xe1 }, | ||
2572 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x03 }, { 0xc, 0x0a }, | ||
2573 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x03 }, { 0xc, 0x0a }, | ||
2574 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x03 }, { 0xc, 0x33 }, | ||
2575 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x03 }, { 0xc, 0x33 }, | ||
2576 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x03 }, { 0xc, 0x5c }, | ||
2577 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x03 }, { 0xc, 0x5c }, | ||
2578 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x03 }, { 0xc, 0x85 }, | ||
2579 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x03 }, { 0xc, 0x85 }, | ||
2580 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x03 }, { 0xc, 0xae }, | ||
2581 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x03 }, { 0xc, 0xae }, | ||
2582 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x03 }, { 0xc, 0xd7 }, | ||
2583 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x03 }, { 0xc, 0xd7 }, | ||
2584 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x04 }, { 0xc, 0x00 }, | ||
2585 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x04 }, { 0xc, 0x00 }, | ||
2586 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x04 }, { 0xc, 0x28 }, | ||
2587 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x04 }, { 0xc, 0x28 }, | ||
2588 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x04 }, { 0xc, 0x51 }, | ||
2589 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x04 }, { 0xc, 0x51 }, | ||
2590 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x04 }, { 0xc, 0x7a }, | ||
2591 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x04 }, { 0xc, 0x7a }, | ||
2592 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x04 }, { 0xc, 0xa3 }, | ||
2593 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x04 }, { 0xc, 0xa3 }, | ||
2594 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x04 }, { 0xc, 0xcc }, | ||
2595 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x04 }, { 0xc, 0xcc }, | ||
2596 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x04 }, { 0xc, 0xf5 }, | ||
2597 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x04 }, { 0xc, 0xf5 }, | ||
2598 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x05 }, { 0xc, 0x1e }, | ||
2599 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x05 }, { 0xc, 0x1e }, | ||
2600 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x05 }, { 0xc, 0x47 }, | ||
2601 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x05 }, { 0xc, 0x47 }, | ||
2602 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x05 }, { 0xc, 0x70 }, | ||
2603 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x05 }, { 0xc, 0x70 }, | ||
2604 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x05 }, { 0xc, 0x99 }, | ||
2605 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x05 }, { 0xc, 0x99 }, | ||
2606 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x05 }, { 0xc, 0xc2 }, | ||
2607 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x05 }, { 0xc, 0xc2 }, | ||
2608 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x05 }, { 0xc, 0xeb }, | ||
2609 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x05 }, { 0xc, 0xeb }, | ||
2610 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x06 }, { 0xc, 0x14 }, | ||
2611 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x06 }, { 0xc, 0x14 }, | ||
2612 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x06 }, { 0xc, 0x3d }, | ||
2613 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x06 }, { 0xc, 0x3d }, | ||
2614 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x06 }, { 0xc, 0x66 }, | ||
2615 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x06 }, { 0xc, 0x66 }, | ||
2616 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x06 }, { 0xc, 0x8f }, | ||
2617 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x06 }, { 0xc, 0x8f }, | ||
2618 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x06 }, { 0xc, 0xb8 }, | ||
2619 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x06 }, { 0xc, 0xb8 }, | ||
2620 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x06 }, { 0xc, 0xe1 }, | ||
2621 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x06 }, { 0xc, 0xe1 }, | ||
2622 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x07 }, { 0xc, 0x0a }, | ||
2623 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x07 }, { 0xc, 0x0a }, | ||
2624 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x07 }, { 0xc, 0x33 }, | ||
2625 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x07 }, { 0xc, 0x33 }, | ||
2626 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x07 }, { 0xc, 0x5c }, | ||
2627 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x07 }, { 0xc, 0x5c }, | ||
2628 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x07 }, { 0xc, 0x85 }, | ||
2629 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x07 }, { 0xc, 0x85 }, | ||
2630 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x07 }, { 0xc, 0xae }, | ||
2631 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x07 }, { 0xc, 0xae }, | ||
2632 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x07 }, { 0xc, 0xd7 }, | ||
2633 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x07 }, { 0xc, 0xd7 }, | ||
2634 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x08 }, { 0xc, 0x00 }, | ||
2635 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x08 }, { 0xc, 0x00 }, | ||
2636 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x08 }, { 0xc, 0x28 }, | ||
2637 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x08 }, { 0xc, 0x28 }, | ||
2638 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x08 }, { 0xc, 0x51 }, | ||
2639 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x08 }, { 0xc, 0x51 }, | ||
2640 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x08 }, { 0xc, 0x7a }, | ||
2641 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x08 }, { 0xc, 0x7a }, | ||
2642 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x08 }, { 0xc, 0xa3 }, | ||
2643 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x08 }, { 0xc, 0xa3 }, | ||
2644 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x08 }, { 0xc, 0xcc }, | ||
2645 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x08 }, { 0xc, 0xcc }, | ||
2646 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x08 }, { 0xc, 0xf5 }, | ||
2647 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x08 }, { 0xc, 0xf5 }, | ||
2648 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x09 }, { 0xc, 0x1e }, | ||
2649 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x09 }, { 0xc, 0x1e }, | ||
2650 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x09 }, { 0xc, 0x47 }, | ||
2651 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x09 }, { 0xc, 0x47 }, | ||
2652 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x09 }, { 0xc, 0x70 }, | ||
2653 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x09 }, { 0xc, 0x70 }, | ||
2654 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x09 }, { 0xc, 0x99 }, | ||
2655 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x09 }, { 0xc, 0x99 }, | ||
2656 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x09 }, { 0xc, 0xc2 }, | ||
2657 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x09 }, { 0xc, 0xc2 }, | ||
2658 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x09 }, { 0xc, 0xeb }, | ||
2659 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x09 }, { 0xc, 0xeb }, | ||
2660 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0a }, { 0xc, 0x14 }, | ||
2661 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0a }, { 0xc, 0x14 }, | ||
2662 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0a }, { 0xc, 0x3d }, | ||
2663 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0a }, { 0xc, 0x3d }, | ||
2664 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0a }, { 0xc, 0x66 }, | ||
2665 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0a }, { 0xc, 0x66 }, | ||
2666 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0a }, { 0xc, 0x8f }, | ||
2667 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0a }, { 0xc, 0x8f }, | ||
2668 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0a }, { 0xc, 0xb8 }, | ||
2669 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0a }, { 0xc, 0xb8 }, | ||
2670 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0a }, { 0xc, 0xe1 }, | ||
2671 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0a }, { 0xc, 0xe1 }, | ||
2672 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0b }, { 0xc, 0x0a }, | ||
2673 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0b }, { 0xc, 0x0a }, | ||
2674 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0b }, { 0xc, 0x33 }, | ||
2675 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0b }, { 0xc, 0x33 }, | ||
2676 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0b }, { 0xc, 0x5c }, | ||
2677 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0b }, { 0xc, 0x5c }, | ||
2678 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0b }, { 0xc, 0x85 }, | ||
2679 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0b }, { 0xc, 0x85 }, | ||
2680 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0b }, { 0xc, 0xae }, | ||
2681 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0b }, { 0xc, 0xae }, | ||
2682 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0b }, { 0xc, 0xd7 }, | ||
2683 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0b }, { 0xc, 0xd7 }, | ||
2684 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0c }, { 0xc, 0x00 }, | ||
2685 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0c }, { 0xc, 0x00 }, | ||
2686 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0c }, { 0xc, 0x28 }, | ||
2687 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0c }, { 0xc, 0x28 }, | ||
2688 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0c }, { 0xc, 0x51 }, | ||
2689 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0c }, { 0xc, 0x51 }, | ||
2690 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0c }, { 0xc, 0x7a }, | ||
2691 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0c }, { 0xc, 0x7a }, | ||
2692 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0c }, { 0xc, 0xa3 }, | ||
2693 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0c }, { 0xc, 0xa3 }, | ||
2694 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0c }, { 0xc, 0xcc }, | ||
2695 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0c }, { 0xc, 0xcc }, | ||
2696 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0c }, { 0xc, 0xf5 }, | ||
2697 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0c }, { 0xc, 0xf5 }, | ||
2698 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0d }, { 0xc, 0x1e }, | ||
2699 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0d }, { 0xc, 0x1e }, | ||
2700 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0d }, { 0xc, 0x47 }, | ||
2701 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0d }, { 0xc, 0x47 }, | ||
2702 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0d }, { 0xc, 0x70 }, | ||
2703 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0d }, { 0xc, 0x70 }, | ||
2704 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0d }, { 0xc, 0x99 }, | ||
2705 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0d }, { 0xc, 0x99 }, | ||
2706 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0d }, { 0xc, 0xc2 }, | ||
2707 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0d }, { 0xc, 0xc2 }, | ||
2708 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0d }, { 0xc, 0xeb }, | ||
2709 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0d }, { 0xc, 0xeb }, | ||
2710 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0e }, { 0xc, 0x14 }, | ||
2711 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0e }, { 0xc, 0x14 }, | ||
2712 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0e }, { 0xc, 0x3d }, | ||
2713 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0e }, { 0xc, 0x3d }, | ||
2714 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0e }, { 0xc, 0x66 }, | ||
2715 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0e }, { 0xc, 0x66 }, | ||
2716 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0e }, { 0xc, 0x8f }, | ||
2717 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0e }, { 0xc, 0x8f }, | ||
2718 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0e }, { 0xc, 0xb8 }, | ||
2719 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0e }, { 0xc, 0xb8 }, | ||
2720 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0e }, { 0xc, 0xe1 }, | ||
2721 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0e }, { 0xc, 0xe1 }, | ||
2722 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0f }, { 0xc, 0x0a }, | ||
2723 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0f }, { 0xc, 0x0a }, | ||
2724 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0f }, { 0xc, 0x33 }, | ||
2725 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0f }, { 0xc, 0x33 }, | ||
2726 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0f }, { 0xc, 0x5c }, | ||
2727 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0f }, { 0xc, 0x5c }, | ||
2728 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0f }, { 0xc, 0x85 }, | ||
2729 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0f }, { 0xc, 0x85 }, | ||
2730 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0f }, { 0xc, 0xae }, | ||
2731 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0f }, { 0xc, 0xae }, | ||
2732 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0f }, { 0xc, 0xd7 }, | ||
2733 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0f }, { 0xc, 0xd7 }, | ||
2734 | { 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0f }, { 0xc, 0xff }, | ||
2735 | { 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0f }, { 0xc, 0xff }, | ||
2736 | |||
2737 | /* mute off */ | ||
2738 | { 0x8, 0x00 }, { WAIT_IDLE } | ||
2739 | }; | ||
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 8a6b1803c763..1bcfb3aac18d 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig | |||
@@ -236,7 +236,7 @@ config SND_CS5535AUDIO | |||
236 | config SND_DARLA20 | 236 | config SND_DARLA20 |
237 | tristate "(Echoaudio) Darla20" | 237 | tristate "(Echoaudio) Darla20" |
238 | depends on SND | 238 | depends on SND |
239 | depends on FW_LOADER | 239 | select FW_LOADER |
240 | select SND_PCM | 240 | select SND_PCM |
241 | help | 241 | help |
242 | Say 'Y' or 'M' to include support for Echoaudio Darla. | 242 | Say 'Y' or 'M' to include support for Echoaudio Darla. |
@@ -247,7 +247,7 @@ config SND_DARLA20 | |||
247 | config SND_GINA20 | 247 | config SND_GINA20 |
248 | tristate "(Echoaudio) Gina20" | 248 | tristate "(Echoaudio) Gina20" |
249 | depends on SND | 249 | depends on SND |
250 | depends on FW_LOADER | 250 | select FW_LOADER |
251 | select SND_PCM | 251 | select SND_PCM |
252 | help | 252 | help |
253 | Say 'Y' or 'M' to include support for Echoaudio Gina. | 253 | Say 'Y' or 'M' to include support for Echoaudio Gina. |
@@ -258,7 +258,7 @@ config SND_GINA20 | |||
258 | config SND_LAYLA20 | 258 | config SND_LAYLA20 |
259 | tristate "(Echoaudio) Layla20" | 259 | tristate "(Echoaudio) Layla20" |
260 | depends on SND | 260 | depends on SND |
261 | depends on FW_LOADER | 261 | select FW_LOADER |
262 | select SND_RAWMIDI | 262 | select SND_RAWMIDI |
263 | select SND_PCM | 263 | select SND_PCM |
264 | help | 264 | help |
@@ -270,7 +270,7 @@ config SND_LAYLA20 | |||
270 | config SND_DARLA24 | 270 | config SND_DARLA24 |
271 | tristate "(Echoaudio) Darla24" | 271 | tristate "(Echoaudio) Darla24" |
272 | depends on SND | 272 | depends on SND |
273 | depends on FW_LOADER | 273 | select FW_LOADER |
274 | select SND_PCM | 274 | select SND_PCM |
275 | help | 275 | help |
276 | Say 'Y' or 'M' to include support for Echoaudio Darla24. | 276 | Say 'Y' or 'M' to include support for Echoaudio Darla24. |
@@ -281,7 +281,7 @@ config SND_DARLA24 | |||
281 | config SND_GINA24 | 281 | config SND_GINA24 |
282 | tristate "(Echoaudio) Gina24" | 282 | tristate "(Echoaudio) Gina24" |
283 | depends on SND | 283 | depends on SND |
284 | depends on FW_LOADER | 284 | select FW_LOADER |
285 | select SND_PCM | 285 | select SND_PCM |
286 | help | 286 | help |
287 | Say 'Y' or 'M' to include support for Echoaudio Gina24. | 287 | Say 'Y' or 'M' to include support for Echoaudio Gina24. |
@@ -292,7 +292,7 @@ config SND_GINA24 | |||
292 | config SND_LAYLA24 | 292 | config SND_LAYLA24 |
293 | tristate "(Echoaudio) Layla24" | 293 | tristate "(Echoaudio) Layla24" |
294 | depends on SND | 294 | depends on SND |
295 | depends on FW_LOADER | 295 | select FW_LOADER |
296 | select SND_RAWMIDI | 296 | select SND_RAWMIDI |
297 | select SND_PCM | 297 | select SND_PCM |
298 | help | 298 | help |
@@ -304,7 +304,7 @@ config SND_LAYLA24 | |||
304 | config SND_MONA | 304 | config SND_MONA |
305 | tristate "(Echoaudio) Mona" | 305 | tristate "(Echoaudio) Mona" |
306 | depends on SND | 306 | depends on SND |
307 | depends on FW_LOADER | 307 | select FW_LOADER |
308 | select SND_RAWMIDI | 308 | select SND_RAWMIDI |
309 | select SND_PCM | 309 | select SND_PCM |
310 | help | 310 | help |
@@ -316,7 +316,7 @@ config SND_MONA | |||
316 | config SND_MIA | 316 | config SND_MIA |
317 | tristate "(Echoaudio) Mia" | 317 | tristate "(Echoaudio) Mia" |
318 | depends on SND | 318 | depends on SND |
319 | depends on FW_LOADER | 319 | select FW_LOADER |
320 | select SND_RAWMIDI | 320 | select SND_RAWMIDI |
321 | select SND_PCM | 321 | select SND_PCM |
322 | help | 322 | help |
@@ -328,7 +328,7 @@ config SND_MIA | |||
328 | config SND_ECHO3G | 328 | config SND_ECHO3G |
329 | tristate "(Echoaudio) 3G cards" | 329 | tristate "(Echoaudio) 3G cards" |
330 | depends on SND | 330 | depends on SND |
331 | depends on FW_LOADER | 331 | select FW_LOADER |
332 | select SND_RAWMIDI | 332 | select SND_RAWMIDI |
333 | select SND_PCM | 333 | select SND_PCM |
334 | help | 334 | help |
@@ -340,7 +340,7 @@ config SND_ECHO3G | |||
340 | config SND_INDIGO | 340 | config SND_INDIGO |
341 | tristate "(Echoaudio) Indigo" | 341 | tristate "(Echoaudio) Indigo" |
342 | depends on SND | 342 | depends on SND |
343 | depends on FW_LOADER | 343 | select FW_LOADER |
344 | select SND_PCM | 344 | select SND_PCM |
345 | help | 345 | help |
346 | Say 'Y' or 'M' to include support for Echoaudio Indigo. | 346 | Say 'Y' or 'M' to include support for Echoaudio Indigo. |
@@ -351,7 +351,7 @@ config SND_INDIGO | |||
351 | config SND_INDIGOIO | 351 | config SND_INDIGOIO |
352 | tristate "(Echoaudio) Indigo IO" | 352 | tristate "(Echoaudio) Indigo IO" |
353 | depends on SND | 353 | depends on SND |
354 | depends on FW_LOADER | 354 | select FW_LOADER |
355 | select SND_PCM | 355 | select SND_PCM |
356 | help | 356 | help |
357 | Say 'Y' or 'M' to include support for Echoaudio Indigo IO. | 357 | Say 'Y' or 'M' to include support for Echoaudio Indigo IO. |
@@ -362,7 +362,7 @@ config SND_INDIGOIO | |||
362 | config SND_INDIGODJ | 362 | config SND_INDIGODJ |
363 | tristate "(Echoaudio) Indigo DJ" | 363 | tristate "(Echoaudio) Indigo DJ" |
364 | depends on SND | 364 | depends on SND |
365 | depends on FW_LOADER | 365 | select FW_LOADER |
366 | select SND_PCM | 366 | select SND_PCM |
367 | help | 367 | help |
368 | Say 'Y' or 'M' to include support for Echoaudio Indigo DJ. | 368 | Say 'Y' or 'M' to include support for Echoaudio Indigo DJ. |
@@ -373,6 +373,7 @@ config SND_INDIGODJ | |||
373 | config SND_EMU10K1 | 373 | config SND_EMU10K1 |
374 | tristate "Emu10k1 (SB Live!, Audigy, E-mu APS)" | 374 | tristate "Emu10k1 (SB Live!, Audigy, E-mu APS)" |
375 | depends on SND | 375 | depends on SND |
376 | select FW_LOADER | ||
376 | select SND_HWDEP | 377 | select SND_HWDEP |
377 | select SND_RAWMIDI | 378 | select SND_RAWMIDI |
378 | select SND_AC97_CODEC | 379 | select SND_AC97_CODEC |
@@ -575,6 +576,7 @@ config SND_INTEL8X0M | |||
575 | config SND_KORG1212 | 576 | config SND_KORG1212 |
576 | tristate "Korg 1212 IO" | 577 | tristate "Korg 1212 IO" |
577 | depends on SND | 578 | depends on SND |
579 | select FW_LOADER | ||
578 | select SND_PCM | 580 | select SND_PCM |
579 | help | 581 | help |
580 | Say Y here to include support for Korg 1212IO soundcards. | 582 | Say Y here to include support for Korg 1212IO soundcards. |
@@ -585,6 +587,7 @@ config SND_KORG1212 | |||
585 | config SND_MAESTRO3 | 587 | config SND_MAESTRO3 |
586 | tristate "ESS Allegro/Maestro3" | 588 | tristate "ESS Allegro/Maestro3" |
587 | depends on SND | 589 | depends on SND |
590 | select FW_LOADER | ||
588 | select SND_AC97_CODEC | 591 | select SND_AC97_CODEC |
589 | help | 592 | help |
590 | Say Y here to include support for soundcards based on ESS Maestro 3 | 593 | Say Y here to include support for soundcards based on ESS Maestro 3 |
@@ -629,7 +632,7 @@ config SND_PCXHR | |||
629 | config SND_RIPTIDE | 632 | config SND_RIPTIDE |
630 | tristate "Conexant Riptide" | 633 | tristate "Conexant Riptide" |
631 | depends on SND | 634 | depends on SND |
632 | depends on FW_LOADER | 635 | select FW_LOADER |
633 | select SND_OPL3_LIB | 636 | select SND_OPL3_LIB |
634 | select SND_MPU401_UART | 637 | select SND_MPU401_UART |
635 | select SND_AC97_CODEC | 638 | select SND_AC97_CODEC |
@@ -734,6 +737,7 @@ config SND_VX222 | |||
734 | config SND_YMFPCI | 737 | config SND_YMFPCI |
735 | tristate "Yamaha YMF724/740/744/754" | 738 | tristate "Yamaha YMF724/740/744/754" |
736 | depends on SND | 739 | depends on SND |
740 | select FW_LOADER | ||
737 | select SND_OPL3_LIB | 741 | select SND_OPL3_LIB |
738 | select SND_MPU401_UART | 742 | select SND_MPU401_UART |
739 | select SND_AC97_CODEC | 743 | select SND_AC97_CODEC |
diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index d2994cb4c8c9..74ed81081478 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c | |||
@@ -111,7 +111,7 @@ static const struct ac97_codec_id snd_ac97_codec_ids[] = { | |||
111 | { 0x41445372, 0xffffffff, "AD1981A", patch_ad1981a, NULL }, | 111 | { 0x41445372, 0xffffffff, "AD1981A", patch_ad1981a, NULL }, |
112 | { 0x41445374, 0xffffffff, "AD1981B", patch_ad1981b, NULL }, | 112 | { 0x41445374, 0xffffffff, "AD1981B", patch_ad1981b, NULL }, |
113 | { 0x41445375, 0xffffffff, "AD1985", patch_ad1985, NULL }, | 113 | { 0x41445375, 0xffffffff, "AD1985", patch_ad1985, NULL }, |
114 | { 0x41445378, 0xffffffff, "AD1986", patch_ad1985, NULL }, | 114 | { 0x41445378, 0xffffffff, "AD1986", patch_ad1986, NULL }, |
115 | { 0x414c4300, 0xffffff00, "ALC100,100P", NULL, NULL }, | 115 | { 0x414c4300, 0xffffff00, "ALC100,100P", NULL, NULL }, |
116 | { 0x414c4710, 0xfffffff0, "ALC200,200P", NULL, NULL }, | 116 | { 0x414c4710, 0xfffffff0, "ALC200,200P", NULL, NULL }, |
117 | { 0x414c4721, 0xffffffff, "ALC650D", NULL, NULL }, /* already patched */ | 117 | { 0x414c4721, 0xffffffff, "ALC650D", NULL, NULL }, /* already patched */ |
@@ -194,6 +194,13 @@ static const struct ac97_codec_id snd_ac97_codec_ids[] = { | |||
194 | 194 | ||
195 | 195 | ||
196 | static void update_power_regs(struct snd_ac97 *ac97); | 196 | static void update_power_regs(struct snd_ac97 *ac97); |
197 | #ifdef CONFIG_SND_AC97_POWER_SAVE | ||
198 | #define ac97_is_power_save_mode(ac97) \ | ||
199 | ((ac97->scaps & AC97_SCAP_POWER_SAVE) && power_save) | ||
200 | #else | ||
201 | #define ac97_is_power_save_mode(ac97) 0 | ||
202 | #endif | ||
203 | |||
197 | 204 | ||
198 | /* | 205 | /* |
199 | * I/O routines | 206 | * I/O routines |
@@ -982,8 +989,8 @@ static int snd_ac97_free(struct snd_ac97 *ac97) | |||
982 | { | 989 | { |
983 | if (ac97) { | 990 | if (ac97) { |
984 | #ifdef CONFIG_SND_AC97_POWER_SAVE | 991 | #ifdef CONFIG_SND_AC97_POWER_SAVE |
985 | if (ac97->power_workq) | 992 | cancel_delayed_work(&ac97->power_work); |
986 | destroy_workqueue(ac97->power_workq); | 993 | flush_scheduled_work(); |
987 | #endif | 994 | #endif |
988 | snd_ac97_proc_done(ac97); | 995 | snd_ac97_proc_done(ac97); |
989 | if (ac97->bus) | 996 | if (ac97->bus) |
@@ -1184,13 +1191,13 @@ static int snd_ac97_cmute_new_stereo(struct snd_card *card, char *name, int reg, | |||
1184 | /* | 1191 | /* |
1185 | * set dB information | 1192 | * set dB information |
1186 | */ | 1193 | */ |
1187 | static DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0); | 1194 | static const DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0); |
1188 | static DECLARE_TLV_DB_SCALE(db_scale_5bit, -4650, 150, 0); | 1195 | static const DECLARE_TLV_DB_SCALE(db_scale_5bit, -4650, 150, 0); |
1189 | static DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0); | 1196 | static const DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0); |
1190 | static DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0); | 1197 | static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0); |
1191 | static DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0); | 1198 | static const DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0); |
1192 | 1199 | ||
1193 | static unsigned int *find_db_scale(unsigned int maxval) | 1200 | static const unsigned int *find_db_scale(unsigned int maxval) |
1194 | { | 1201 | { |
1195 | switch (maxval) { | 1202 | switch (maxval) { |
1196 | case 0x0f: return db_scale_4bit; | 1203 | case 0x0f: return db_scale_4bit; |
@@ -1200,8 +1207,8 @@ static unsigned int *find_db_scale(unsigned int maxval) | |||
1200 | return NULL; | 1207 | return NULL; |
1201 | } | 1208 | } |
1202 | 1209 | ||
1203 | static void set_tlv_db_scale(struct snd_kcontrol *kctl, unsigned int *tlv) | 1210 | static void set_tlv_db_scale(struct snd_kcontrol *kctl, const unsigned int *tlv) |
1204 | { | 1211 | { |
1205 | kctl->tlv.p = tlv; | 1212 | kctl->tlv.p = tlv; |
1206 | if (tlv) | 1213 | if (tlv) |
1207 | kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ; | 1214 | kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ; |
@@ -1989,7 +1996,6 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template, | |||
1989 | mutex_init(&ac97->reg_mutex); | 1996 | mutex_init(&ac97->reg_mutex); |
1990 | mutex_init(&ac97->page_mutex); | 1997 | mutex_init(&ac97->page_mutex); |
1991 | #ifdef CONFIG_SND_AC97_POWER_SAVE | 1998 | #ifdef CONFIG_SND_AC97_POWER_SAVE |
1992 | ac97->power_workq = create_workqueue("ac97"); | ||
1993 | INIT_DELAYED_WORK(&ac97->power_work, do_update_power); | 1999 | INIT_DELAYED_WORK(&ac97->power_work, do_update_power); |
1994 | #endif | 2000 | #endif |
1995 | 2001 | ||
@@ -2275,15 +2281,13 @@ static void snd_ac97_powerdown(struct snd_ac97 *ac97) | |||
2275 | udelay(100); | 2281 | udelay(100); |
2276 | power |= AC97_PD_PR2 | AC97_PD_PR3; /* Analog Mixer powerdown */ | 2282 | power |= AC97_PD_PR2 | AC97_PD_PR3; /* Analog Mixer powerdown */ |
2277 | snd_ac97_write(ac97, AC97_POWERDOWN, power); | 2283 | snd_ac97_write(ac97, AC97_POWERDOWN, power); |
2278 | #ifdef CONFIG_SND_AC97_POWER_SAVE | 2284 | if (ac97_is_power_save_mode(ac97)) { |
2279 | if (power_save) { | ||
2280 | udelay(100); | 2285 | udelay(100); |
2281 | /* AC-link powerdown, internal Clk disable */ | 2286 | /* AC-link powerdown, internal Clk disable */ |
2282 | /* FIXME: this may cause click noises on some boards */ | 2287 | /* FIXME: this may cause click noises on some boards */ |
2283 | power |= AC97_PD_PR4 | AC97_PD_PR5; | 2288 | power |= AC97_PD_PR4 | AC97_PD_PR5; |
2284 | snd_ac97_write(ac97, AC97_POWERDOWN, power); | 2289 | snd_ac97_write(ac97, AC97_POWERDOWN, power); |
2285 | } | 2290 | } |
2286 | #endif | ||
2287 | } | 2291 | } |
2288 | 2292 | ||
2289 | 2293 | ||
@@ -2337,14 +2341,16 @@ int snd_ac97_update_power(struct snd_ac97 *ac97, int reg, int powerup) | |||
2337 | } | 2341 | } |
2338 | } | 2342 | } |
2339 | 2343 | ||
2340 | if (power_save && !powerup && ac97->power_workq) | 2344 | if (ac97_is_power_save_mode(ac97) && !powerup) |
2341 | /* adjust power-down bits after two seconds delay | 2345 | /* adjust power-down bits after two seconds delay |
2342 | * (for avoiding loud click noises for many (OSS) apps | 2346 | * (for avoiding loud click noises for many (OSS) apps |
2343 | * that open/close frequently) | 2347 | * that open/close frequently) |
2344 | */ | 2348 | */ |
2345 | queue_delayed_work(ac97->power_workq, &ac97->power_work, HZ*2); | 2349 | schedule_delayed_work(&ac97->power_work, HZ*2); |
2346 | else | 2350 | else { |
2351 | cancel_delayed_work(&ac97->power_work); | ||
2347 | update_power_regs(ac97); | 2352 | update_power_regs(ac97); |
2353 | } | ||
2348 | 2354 | ||
2349 | return 0; | 2355 | return 0; |
2350 | } | 2356 | } |
@@ -2357,19 +2363,15 @@ static void update_power_regs(struct snd_ac97 *ac97) | |||
2357 | unsigned int power_up, bits; | 2363 | unsigned int power_up, bits; |
2358 | int i; | 2364 | int i; |
2359 | 2365 | ||
2366 | power_up = (1 << PWIDX_FRONT) | (1 << PWIDX_ADC); | ||
2367 | power_up |= (1 << PWIDX_MIC); | ||
2368 | if (ac97->scaps & AC97_SCAP_SURROUND_DAC) | ||
2369 | power_up |= (1 << PWIDX_SURR); | ||
2370 | if (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC) | ||
2371 | power_up |= (1 << PWIDX_CLFE); | ||
2360 | #ifdef CONFIG_SND_AC97_POWER_SAVE | 2372 | #ifdef CONFIG_SND_AC97_POWER_SAVE |
2361 | if (power_save) | 2373 | if (ac97_is_power_save_mode(ac97)) |
2362 | power_up = ac97->power_up; | 2374 | power_up = ac97->power_up; |
2363 | else { | ||
2364 | #endif | ||
2365 | power_up = (1 << PWIDX_FRONT) | (1 << PWIDX_ADC); | ||
2366 | power_up |= (1 << PWIDX_MIC); | ||
2367 | if (ac97->scaps & AC97_SCAP_SURROUND_DAC) | ||
2368 | power_up |= (1 << PWIDX_SURR); | ||
2369 | if (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC) | ||
2370 | power_up |= (1 << PWIDX_CLFE); | ||
2371 | #ifdef CONFIG_SND_AC97_POWER_SAVE | ||
2372 | } | ||
2373 | #endif | 2375 | #endif |
2374 | if (power_up) { | 2376 | if (power_up) { |
2375 | if (ac97->regs[AC97_POWERDOWN] & AC97_PD_PR2) { | 2377 | if (ac97->regs[AC97_POWERDOWN] & AC97_PD_PR2) { |
@@ -2414,6 +2416,10 @@ void snd_ac97_suspend(struct snd_ac97 *ac97) | |||
2414 | return; | 2416 | return; |
2415 | if (ac97->build_ops->suspend) | 2417 | if (ac97->build_ops->suspend) |
2416 | ac97->build_ops->suspend(ac97); | 2418 | ac97->build_ops->suspend(ac97); |
2419 | #ifdef CONFIG_SND_AC97_POWER_SAVE | ||
2420 | cancel_delayed_work(&ac97->power_work); | ||
2421 | flush_scheduled_work(); | ||
2422 | #endif | ||
2417 | snd_ac97_powerdown(ac97); | 2423 | snd_ac97_powerdown(ac97); |
2418 | } | 2424 | } |
2419 | 2425 | ||
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index e813968e0cf8..641d0c8d659e 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c | |||
@@ -54,7 +54,7 @@ static int patch_build_controls(struct snd_ac97 * ac97, const struct snd_kcontro | |||
54 | 54 | ||
55 | /* replace with a new TLV */ | 55 | /* replace with a new TLV */ |
56 | static void reset_tlv(struct snd_ac97 *ac97, const char *name, | 56 | static void reset_tlv(struct snd_ac97 *ac97, const char *name, |
57 | unsigned int *tlv) | 57 | const unsigned int *tlv) |
58 | { | 58 | { |
59 | struct snd_ctl_elem_id sid; | 59 | struct snd_ctl_elem_id sid; |
60 | struct snd_kcontrol *kctl; | 60 | struct snd_kcontrol *kctl; |
@@ -190,14 +190,28 @@ static inline int is_clfe_on(struct snd_ac97 *ac97) | |||
190 | return ac97->channel_mode >= 2; | 190 | return ac97->channel_mode >= 2; |
191 | } | 191 | } |
192 | 192 | ||
193 | /* system has shared jacks with surround out enabled */ | ||
194 | static inline int is_shared_surrout(struct snd_ac97 *ac97) | ||
195 | { | ||
196 | return !ac97->indep_surround && is_surround_on(ac97); | ||
197 | } | ||
198 | |||
199 | /* system has shared jacks with center/lfe out enabled */ | ||
200 | static inline int is_shared_clfeout(struct snd_ac97 *ac97) | ||
201 | { | ||
202 | return !ac97->indep_surround && is_clfe_on(ac97); | ||
203 | } | ||
204 | |||
205 | /* system has shared jacks with line in enabled */ | ||
193 | static inline int is_shared_linein(struct snd_ac97 *ac97) | 206 | static inline int is_shared_linein(struct snd_ac97 *ac97) |
194 | { | 207 | { |
195 | return ! ac97->indep_surround && is_surround_on(ac97); | 208 | return !ac97->indep_surround && !is_surround_on(ac97); |
196 | } | 209 | } |
197 | 210 | ||
211 | /* system has shared jacks with mic in enabled */ | ||
198 | static inline int is_shared_micin(struct snd_ac97 *ac97) | 212 | static inline int is_shared_micin(struct snd_ac97 *ac97) |
199 | { | 213 | { |
200 | return ! ac97->indep_surround && is_clfe_on(ac97); | 214 | return !ac97->indep_surround && !is_clfe_on(ac97); |
201 | } | 215 | } |
202 | 216 | ||
203 | 217 | ||
@@ -941,6 +955,9 @@ static int patch_sigmatel_stac9708_specific(struct snd_ac97 *ac97) | |||
941 | { | 955 | { |
942 | int err; | 956 | int err; |
943 | 957 | ||
958 | /* the register bit is writable, but the function is not implemented: */ | ||
959 | snd_ac97_remove_ctl(ac97, "PCM Out Path & Mute", NULL); | ||
960 | |||
944 | snd_ac97_rename_vol_ctl(ac97, "Headphone Playback", "Sigmatel Surround Playback"); | 961 | snd_ac97_rename_vol_ctl(ac97, "Headphone Playback", "Sigmatel Surround Playback"); |
945 | if ((err = patch_build_controls(ac97, &snd_ac97_stac9708_bias_control, 1)) < 0) | 962 | if ((err = patch_build_controls(ac97, &snd_ac97_stac9708_bias_control, 1)) < 0) |
946 | return err; | 963 | return err; |
@@ -1552,7 +1569,7 @@ static const struct snd_kcontrol_new snd_ac97_controls_ad1885[] = { | |||
1552 | AC97_SINGLE("Line Jack Sense", AC97_AD_JACK_SPDIF, 8, 1, 1), /* inverted */ | 1569 | AC97_SINGLE("Line Jack Sense", AC97_AD_JACK_SPDIF, 8, 1, 1), /* inverted */ |
1553 | }; | 1570 | }; |
1554 | 1571 | ||
1555 | static DECLARE_TLV_DB_SCALE(db_scale_6bit_6db_max, -8850, 150, 0); | 1572 | static const DECLARE_TLV_DB_SCALE(db_scale_6bit_6db_max, -8850, 150, 0); |
1556 | 1573 | ||
1557 | static int patch_ad1885_specific(struct snd_ac97 * ac97) | 1574 | static int patch_ad1885_specific(struct snd_ac97 * ac97) |
1558 | { | 1575 | { |
@@ -1609,19 +1626,22 @@ int patch_ad1886(struct snd_ac97 * ac97) | |||
1609 | return 0; | 1626 | return 0; |
1610 | } | 1627 | } |
1611 | 1628 | ||
1612 | /* MISC bits */ | 1629 | /* MISC bits (AD1888/AD1980/AD1985 register 0x76) */ |
1613 | #define AC97_AD198X_MBC 0x0003 /* mic boost */ | 1630 | #define AC97_AD198X_MBC 0x0003 /* mic boost */ |
1614 | #define AC97_AD198X_MBC_20 0x0000 /* +20dB */ | 1631 | #define AC97_AD198X_MBC_20 0x0000 /* +20dB */ |
1615 | #define AC97_AD198X_MBC_10 0x0001 /* +10dB */ | 1632 | #define AC97_AD198X_MBC_10 0x0001 /* +10dB */ |
1616 | #define AC97_AD198X_MBC_30 0x0002 /* +30dB */ | 1633 | #define AC97_AD198X_MBC_30 0x0002 /* +30dB */ |
1617 | #define AC97_AD198X_VREFD 0x0004 /* VREF high-Z */ | 1634 | #define AC97_AD198X_VREFD 0x0004 /* VREF high-Z */ |
1618 | #define AC97_AD198X_VREFH 0x0008 /* 2.25V, 3.7V */ | 1635 | #define AC97_AD198X_VREFH 0x0008 /* 0=2.25V, 1=3.7V */ |
1619 | #define AC97_AD198X_VREF_0 0x000c /* 0V */ | 1636 | #define AC97_AD198X_VREF_0 0x000c /* 0V (AD1985 only) */ |
1637 | #define AC97_AD198X_VREF_MASK (AC97_AD198X_VREFH | AC97_AD198X_VREFD) | ||
1638 | #define AC97_AD198X_VREF_SHIFT 2 | ||
1620 | #define AC97_AD198X_SRU 0x0010 /* sample rate unlock */ | 1639 | #define AC97_AD198X_SRU 0x0010 /* sample rate unlock */ |
1621 | #define AC97_AD198X_LOSEL 0x0020 /* LINE_OUT amplifiers input select */ | 1640 | #define AC97_AD198X_LOSEL 0x0020 /* LINE_OUT amplifiers input select */ |
1622 | #define AC97_AD198X_2MIC 0x0040 /* 2-channel mic select */ | 1641 | #define AC97_AD198X_2MIC 0x0040 /* 2-channel mic select */ |
1623 | #define AC97_AD198X_SPRD 0x0080 /* SPREAD enable */ | 1642 | #define AC97_AD198X_SPRD 0x0080 /* SPREAD enable */ |
1624 | #define AC97_AD198X_DMIX0 0x0100 /* downmix mode: 0 = 6-to-4, 1 = 6-to-2 downmix */ | 1643 | #define AC97_AD198X_DMIX0 0x0100 /* downmix mode: */ |
1644 | /* 0 = 6-to-4, 1 = 6-to-2 downmix */ | ||
1625 | #define AC97_AD198X_DMIX1 0x0200 /* downmix mode: 1 = enabled */ | 1645 | #define AC97_AD198X_DMIX1 0x0200 /* downmix mode: 1 = enabled */ |
1626 | #define AC97_AD198X_HPSEL 0x0400 /* headphone amplifier input select */ | 1646 | #define AC97_AD198X_HPSEL 0x0400 /* headphone amplifier input select */ |
1627 | #define AC97_AD198X_CLDIS 0x0800 /* center/lfe disable */ | 1647 | #define AC97_AD198X_CLDIS 0x0800 /* center/lfe disable */ |
@@ -1630,6 +1650,83 @@ int patch_ad1886(struct snd_ac97 * ac97) | |||
1630 | #define AC97_AD198X_AC97NC 0x4000 /* AC97 no compatible mode */ | 1650 | #define AC97_AD198X_AC97NC 0x4000 /* AC97 no compatible mode */ |
1631 | #define AC97_AD198X_DACZ 0x8000 /* DAC zero-fill mode */ | 1651 | #define AC97_AD198X_DACZ 0x8000 /* DAC zero-fill mode */ |
1632 | 1652 | ||
1653 | /* MISC 1 bits (AD1986 register 0x76) */ | ||
1654 | #define AC97_AD1986_MBC 0x0003 /* mic boost */ | ||
1655 | #define AC97_AD1986_MBC_20 0x0000 /* +20dB */ | ||
1656 | #define AC97_AD1986_MBC_10 0x0001 /* +10dB */ | ||
1657 | #define AC97_AD1986_MBC_30 0x0002 /* +30dB */ | ||
1658 | #define AC97_AD1986_LISEL0 0x0004 /* LINE_IN select bit 0 */ | ||
1659 | #define AC97_AD1986_LISEL1 0x0008 /* LINE_IN select bit 1 */ | ||
1660 | #define AC97_AD1986_LISEL_MASK (AC97_AD1986_LISEL1 | AC97_AD1986_LISEL0) | ||
1661 | #define AC97_AD1986_LISEL_LI 0x0000 /* LINE_IN pins as LINE_IN source */ | ||
1662 | #define AC97_AD1986_LISEL_SURR 0x0004 /* SURROUND pins as LINE_IN source */ | ||
1663 | #define AC97_AD1986_LISEL_MIC 0x0008 /* MIC_1/2 pins as LINE_IN source */ | ||
1664 | #define AC97_AD1986_SRU 0x0010 /* sample rate unlock */ | ||
1665 | #define AC97_AD1986_SOSEL 0x0020 /* SURROUND_OUT amplifiers input sel */ | ||
1666 | #define AC97_AD1986_2MIC 0x0040 /* 2-channel mic select */ | ||
1667 | #define AC97_AD1986_SPRD 0x0080 /* SPREAD enable */ | ||
1668 | #define AC97_AD1986_DMIX0 0x0100 /* downmix mode: */ | ||
1669 | /* 0 = 6-to-4, 1 = 6-to-2 downmix */ | ||
1670 | #define AC97_AD1986_DMIX1 0x0200 /* downmix mode: 1 = enabled */ | ||
1671 | #define AC97_AD1986_CLDIS 0x0800 /* center/lfe disable */ | ||
1672 | #define AC97_AD1986_SODIS 0x1000 /* SURROUND_OUT disable */ | ||
1673 | #define AC97_AD1986_MSPLT 0x2000 /* mute split (read only 1) */ | ||
1674 | #define AC97_AD1986_AC97NC 0x4000 /* AC97 no compatible mode (r/o 1) */ | ||
1675 | #define AC97_AD1986_DACZ 0x8000 /* DAC zero-fill mode */ | ||
1676 | |||
1677 | /* MISC 2 bits (AD1986 register 0x70) */ | ||
1678 | #define AC97_AD_MISC2 0x70 /* Misc Control Bits 2 (AD1986) */ | ||
1679 | |||
1680 | #define AC97_AD1986_CVREF0 0x0004 /* C/LFE VREF_OUT 2.25V */ | ||
1681 | #define AC97_AD1986_CVREF1 0x0008 /* C/LFE VREF_OUT 0V */ | ||
1682 | #define AC97_AD1986_CVREF2 0x0010 /* C/LFE VREF_OUT 3.7V */ | ||
1683 | #define AC97_AD1986_CVREF_MASK \ | ||
1684 | (AC97_AD1986_CVREF2 | AC97_AD1986_CVREF1 | AC97_AD1986_CVREF0) | ||
1685 | #define AC97_AD1986_JSMAP 0x0020 /* Jack Sense Mapping 1 = alternate */ | ||
1686 | #define AC97_AD1986_MMDIS 0x0080 /* Mono Mute Disable */ | ||
1687 | #define AC97_AD1986_MVREF0 0x0400 /* MIC VREF_OUT 2.25V */ | ||
1688 | #define AC97_AD1986_MVREF1 0x0800 /* MIC VREF_OUT 0V */ | ||
1689 | #define AC97_AD1986_MVREF2 0x1000 /* MIC VREF_OUT 3.7V */ | ||
1690 | #define AC97_AD1986_MVREF_MASK \ | ||
1691 | (AC97_AD1986_MVREF2 | AC97_AD1986_MVREF1 | AC97_AD1986_MVREF0) | ||
1692 | |||
1693 | /* MISC 3 bits (AD1986 register 0x7a) */ | ||
1694 | #define AC97_AD_MISC3 0x7a /* Misc Control Bits 3 (AD1986) */ | ||
1695 | |||
1696 | #define AC97_AD1986_MMIX 0x0004 /* Mic Mix, left/right */ | ||
1697 | #define AC97_AD1986_GPO 0x0008 /* General Purpose Out */ | ||
1698 | #define AC97_AD1986_LOHPEN 0x0010 /* LINE_OUT headphone drive */ | ||
1699 | #define AC97_AD1986_LVREF0 0x0100 /* LINE_OUT VREF_OUT 2.25V */ | ||
1700 | #define AC97_AD1986_LVREF1 0x0200 /* LINE_OUT VREF_OUT 0V */ | ||
1701 | #define AC97_AD1986_LVREF2 0x0400 /* LINE_OUT VREF_OUT 3.7V */ | ||
1702 | #define AC97_AD1986_LVREF_MASK \ | ||
1703 | (AC97_AD1986_LVREF2 | AC97_AD1986_LVREF1 | AC97_AD1986_LVREF0) | ||
1704 | #define AC97_AD1986_JSINVA 0x0800 /* Jack Sense Invert SENSE_A */ | ||
1705 | #define AC97_AD1986_LOSEL 0x1000 /* LINE_OUT amplifiers input select */ | ||
1706 | #define AC97_AD1986_HPSEL0 0x2000 /* Headphone amplifiers */ | ||
1707 | /* input select Surround DACs */ | ||
1708 | #define AC97_AD1986_HPSEL1 0x4000 /* Headphone amplifiers input */ | ||
1709 | /* select C/LFE DACs */ | ||
1710 | #define AC97_AD1986_JSINVB 0x8000 /* Jack Sense Invert SENSE_B */ | ||
1711 | |||
1712 | /* Serial Config bits (AD1986 register 0x74) (incomplete) */ | ||
1713 | #define AC97_AD1986_OMS0 0x0100 /* Optional Mic Selector bit 0 */ | ||
1714 | #define AC97_AD1986_OMS1 0x0200 /* Optional Mic Selector bit 1 */ | ||
1715 | #define AC97_AD1986_OMS2 0x0400 /* Optional Mic Selector bit 2 */ | ||
1716 | #define AC97_AD1986_OMS_MASK \ | ||
1717 | (AC97_AD1986_OMS2 | AC97_AD1986_OMS1 | AC97_AD1986_OMS0) | ||
1718 | #define AC97_AD1986_OMS_M 0x0000 /* MIC_1/2 pins are MIC sources */ | ||
1719 | #define AC97_AD1986_OMS_L 0x0100 /* LINE_IN pins are MIC sources */ | ||
1720 | #define AC97_AD1986_OMS_C 0x0200 /* Center/LFE pins are MCI sources */ | ||
1721 | #define AC97_AD1986_OMS_MC 0x0400 /* Mix of MIC and C/LFE pins */ | ||
1722 | /* are MIC sources */ | ||
1723 | #define AC97_AD1986_OMS_ML 0x0500 /* MIX of MIC and LINE_IN pins */ | ||
1724 | /* are MIC sources */ | ||
1725 | #define AC97_AD1986_OMS_LC 0x0600 /* MIX of LINE_IN and C/LFE pins */ | ||
1726 | /* are MIC sources */ | ||
1727 | #define AC97_AD1986_OMS_MLC 0x0700 /* MIX of MIC, LINE_IN, C/LFE pins */ | ||
1728 | /* are MIC sources */ | ||
1729 | |||
1633 | 1730 | ||
1634 | static int snd_ac97_ad198x_spdif_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | 1731 | static int snd_ac97_ad198x_spdif_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) |
1635 | { | 1732 | { |
@@ -1952,8 +2049,80 @@ int patch_ad1980(struct snd_ac97 * ac97) | |||
1952 | return 0; | 2049 | return 0; |
1953 | } | 2050 | } |
1954 | 2051 | ||
2052 | static int snd_ac97_ad1985_vrefout_info(struct snd_kcontrol *kcontrol, | ||
2053 | struct snd_ctl_elem_info *uinfo) | ||
2054 | { | ||
2055 | static char *texts[4] = {"High-Z", "3.7 V", "2.25 V", "0 V"}; | ||
2056 | |||
2057 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
2058 | uinfo->count = 1; | ||
2059 | uinfo->value.enumerated.items = 4; | ||
2060 | if (uinfo->value.enumerated.item > 3) | ||
2061 | uinfo->value.enumerated.item = 3; | ||
2062 | strcpy(uinfo->value.enumerated.name, | ||
2063 | texts[uinfo->value.enumerated.item]); | ||
2064 | return 0; | ||
2065 | } | ||
2066 | |||
2067 | static int snd_ac97_ad1985_vrefout_get(struct snd_kcontrol *kcontrol, | ||
2068 | struct snd_ctl_elem_value *ucontrol) | ||
2069 | { | ||
2070 | static const int reg2ctrl[4] = {2, 0, 1, 3}; | ||
2071 | struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); | ||
2072 | unsigned short val; | ||
2073 | val = (ac97->regs[AC97_AD_MISC] & AC97_AD198X_VREF_MASK) | ||
2074 | >> AC97_AD198X_VREF_SHIFT; | ||
2075 | ucontrol->value.enumerated.item[0] = reg2ctrl[val]; | ||
2076 | return 0; | ||
2077 | } | ||
2078 | |||
2079 | static int snd_ac97_ad1985_vrefout_put(struct snd_kcontrol *kcontrol, | ||
2080 | struct snd_ctl_elem_value *ucontrol) | ||
2081 | { | ||
2082 | static const int ctrl2reg[4] = {1, 2, 0, 3}; | ||
2083 | struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); | ||
2084 | unsigned short val; | ||
2085 | |||
2086 | if (ucontrol->value.enumerated.item[0] > 3 | ||
2087 | || ucontrol->value.enumerated.item[0] < 0) | ||
2088 | return -EINVAL; | ||
2089 | val = ctrl2reg[ucontrol->value.enumerated.item[0]] | ||
2090 | << AC97_AD198X_VREF_SHIFT; | ||
2091 | return snd_ac97_update_bits(ac97, AC97_AD_MISC, | ||
2092 | AC97_AD198X_VREF_MASK, val); | ||
2093 | } | ||
2094 | |||
1955 | static const struct snd_kcontrol_new snd_ac97_ad1985_controls[] = { | 2095 | static const struct snd_kcontrol_new snd_ac97_ad1985_controls[] = { |
1956 | AC97_SINGLE("Exchange Center/LFE", AC97_AD_SERIAL_CFG, 3, 1, 0) | 2096 | AC97_SINGLE("Exchange Center/LFE", AC97_AD_SERIAL_CFG, 3, 1, 0), |
2097 | { | ||
2098 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2099 | .name = "Exchange Front/Surround", | ||
2100 | .info = snd_ac97_ad1888_lohpsel_info, | ||
2101 | .get = snd_ac97_ad1888_lohpsel_get, | ||
2102 | .put = snd_ac97_ad1888_lohpsel_put | ||
2103 | }, | ||
2104 | AC97_SINGLE("High Pass Filter Enable", AC97_AD_TEST2, 12, 1, 1), | ||
2105 | AC97_SINGLE("Spread Front to Surround and Center/LFE", | ||
2106 | AC97_AD_MISC, 7, 1, 0), | ||
2107 | { | ||
2108 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2109 | .name = "Downmix", | ||
2110 | .info = snd_ac97_ad1888_downmix_info, | ||
2111 | .get = snd_ac97_ad1888_downmix_get, | ||
2112 | .put = snd_ac97_ad1888_downmix_put | ||
2113 | }, | ||
2114 | { | ||
2115 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2116 | .name = "V_REFOUT", | ||
2117 | .info = snd_ac97_ad1985_vrefout_info, | ||
2118 | .get = snd_ac97_ad1985_vrefout_get, | ||
2119 | .put = snd_ac97_ad1985_vrefout_put | ||
2120 | }, | ||
2121 | AC97_SURROUND_JACK_MODE_CTL, | ||
2122 | AC97_CHANNEL_MODE_CTL, | ||
2123 | |||
2124 | AC97_SINGLE("Headphone Jack Sense", AC97_AD_JACK_SPDIF, 10, 1, 0), | ||
2125 | AC97_SINGLE("Line Jack Sense", AC97_AD_JACK_SPDIF, 12, 1, 0), | ||
1957 | }; | 2126 | }; |
1958 | 2127 | ||
1959 | static void ad1985_update_jacks(struct snd_ac97 *ac97) | 2128 | static void ad1985_update_jacks(struct snd_ac97 *ac97) |
@@ -1967,9 +2136,16 @@ static int patch_ad1985_specific(struct snd_ac97 *ac97) | |||
1967 | { | 2136 | { |
1968 | int err; | 2137 | int err; |
1969 | 2138 | ||
1970 | if ((err = patch_ad1980_specific(ac97)) < 0) | 2139 | /* rename 0x04 as "Master" and 0x02 as "Master Surround" */ |
2140 | snd_ac97_rename_vol_ctl(ac97, "Master Playback", | ||
2141 | "Master Surround Playback"); | ||
2142 | snd_ac97_rename_vol_ctl(ac97, "Headphone Playback", "Master Playback"); | ||
2143 | |||
2144 | if ((err = patch_build_controls(ac97, &snd_ac97_ad198x_2cmic, 1)) < 0) | ||
1971 | return err; | 2145 | return err; |
1972 | return patch_build_controls(ac97, snd_ac97_ad1985_controls, ARRAY_SIZE(snd_ac97_ad1985_controls)); | 2146 | |
2147 | return patch_build_controls(ac97, snd_ac97_ad1985_controls, | ||
2148 | ARRAY_SIZE(snd_ac97_ad1985_controls)); | ||
1973 | } | 2149 | } |
1974 | 2150 | ||
1975 | static struct snd_ac97_build_ops patch_ad1985_build_ops = { | 2151 | static struct snd_ac97_build_ops patch_ad1985_build_ops = { |
@@ -1989,24 +2165,311 @@ int patch_ad1985(struct snd_ac97 * ac97) | |||
1989 | ac97->build_ops = &patch_ad1985_build_ops; | 2165 | ac97->build_ops = &patch_ad1985_build_ops; |
1990 | misc = snd_ac97_read(ac97, AC97_AD_MISC); | 2166 | misc = snd_ac97_read(ac97, AC97_AD_MISC); |
1991 | /* switch front/surround line-out/hp-out */ | 2167 | /* switch front/surround line-out/hp-out */ |
1992 | /* center/LFE, mic in 3.75V mode */ | ||
1993 | /* AD-compatible mode */ | 2168 | /* AD-compatible mode */ |
1994 | /* Stereo mutes enabled */ | 2169 | /* Stereo mutes enabled */ |
1995 | /* in accordance with ADI driver: misc | 0x5c28 */ | ||
1996 | snd_ac97_write_cache(ac97, AC97_AD_MISC, misc | | 2170 | snd_ac97_write_cache(ac97, AC97_AD_MISC, misc | |
1997 | AC97_AD198X_VREFH | | ||
1998 | AC97_AD198X_LOSEL | | 2171 | AC97_AD198X_LOSEL | |
1999 | AC97_AD198X_HPSEL | | 2172 | AC97_AD198X_HPSEL | |
2000 | AC97_AD198X_CLDIS | | ||
2001 | AC97_AD198X_LODIS | | ||
2002 | AC97_AD198X_MSPLT | | 2173 | AC97_AD198X_MSPLT | |
2003 | AC97_AD198X_AC97NC); | 2174 | AC97_AD198X_AC97NC); |
2004 | ac97->flags |= AC97_STEREO_MUTES; | 2175 | ac97->flags |= AC97_STEREO_MUTES; |
2176 | |||
2177 | /* update current jack configuration */ | ||
2178 | ad1985_update_jacks(ac97); | ||
2179 | |||
2005 | /* on AD1985 rev. 3, AC'97 revision bits are zero */ | 2180 | /* on AD1985 rev. 3, AC'97 revision bits are zero */ |
2006 | ac97->ext_id = (ac97->ext_id & ~AC97_EI_REV_MASK) | AC97_EI_REV_23; | 2181 | ac97->ext_id = (ac97->ext_id & ~AC97_EI_REV_MASK) | AC97_EI_REV_23; |
2007 | return 0; | 2182 | return 0; |
2008 | } | 2183 | } |
2009 | 2184 | ||
2185 | static int snd_ac97_ad1986_bool_info(struct snd_kcontrol *kcontrol, | ||
2186 | struct snd_ctl_elem_info *uinfo) | ||
2187 | { | ||
2188 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
2189 | uinfo->count = 1; | ||
2190 | uinfo->value.integer.min = 0; | ||
2191 | uinfo->value.integer.max = 1; | ||
2192 | return 0; | ||
2193 | } | ||
2194 | |||
2195 | static int snd_ac97_ad1986_lososel_get(struct snd_kcontrol *kcontrol, | ||
2196 | struct snd_ctl_elem_value *ucontrol) | ||
2197 | { | ||
2198 | struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); | ||
2199 | unsigned short val; | ||
2200 | |||
2201 | val = ac97->regs[AC97_AD_MISC3]; | ||
2202 | ucontrol->value.integer.value[0] = (val & AC97_AD1986_LOSEL) != 0; | ||
2203 | return 0; | ||
2204 | } | ||
2205 | |||
2206 | static int snd_ac97_ad1986_lososel_put(struct snd_kcontrol *kcontrol, | ||
2207 | struct snd_ctl_elem_value *ucontrol) | ||
2208 | { | ||
2209 | struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); | ||
2210 | int ret0; | ||
2211 | int ret1; | ||
2212 | int sprd = (ac97->regs[AC97_AD_MISC] & AC97_AD1986_SPRD) != 0; | ||
2213 | |||
2214 | ret0 = snd_ac97_update_bits(ac97, AC97_AD_MISC3, AC97_AD1986_LOSEL, | ||
2215 | ucontrol->value.integer.value[0] != 0 | ||
2216 | ? AC97_AD1986_LOSEL : 0); | ||
2217 | if (ret0 < 0) | ||
2218 | return ret0; | ||
2219 | |||
2220 | /* SOSEL is set to values of "Spread" or "Exchange F/S" controls */ | ||
2221 | ret1 = snd_ac97_update_bits(ac97, AC97_AD_MISC, AC97_AD1986_SOSEL, | ||
2222 | (ucontrol->value.integer.value[0] != 0 | ||
2223 | || sprd) | ||
2224 | ? AC97_AD1986_SOSEL : 0); | ||
2225 | if (ret1 < 0) | ||
2226 | return ret1; | ||
2227 | |||
2228 | return (ret0 > 0 || ret1 > 0) ? 1 : 0; | ||
2229 | } | ||
2230 | |||
2231 | static int snd_ac97_ad1986_spread_get(struct snd_kcontrol *kcontrol, | ||
2232 | struct snd_ctl_elem_value *ucontrol) | ||
2233 | { | ||
2234 | struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); | ||
2235 | unsigned short val; | ||
2236 | |||
2237 | val = ac97->regs[AC97_AD_MISC]; | ||
2238 | ucontrol->value.integer.value[0] = (val & AC97_AD1986_SPRD) != 0; | ||
2239 | return 0; | ||
2240 | } | ||
2241 | |||
2242 | static int snd_ac97_ad1986_spread_put(struct snd_kcontrol *kcontrol, | ||
2243 | struct snd_ctl_elem_value *ucontrol) | ||
2244 | { | ||
2245 | struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); | ||
2246 | int ret0; | ||
2247 | int ret1; | ||
2248 | int sprd = (ac97->regs[AC97_AD_MISC3] & AC97_AD1986_LOSEL) != 0; | ||
2249 | |||
2250 | ret0 = snd_ac97_update_bits(ac97, AC97_AD_MISC, AC97_AD1986_SPRD, | ||
2251 | ucontrol->value.integer.value[0] != 0 | ||
2252 | ? AC97_AD1986_SPRD : 0); | ||
2253 | if (ret0 < 0) | ||
2254 | return ret0; | ||
2255 | |||
2256 | /* SOSEL is set to values of "Spread" or "Exchange F/S" controls */ | ||
2257 | ret1 = snd_ac97_update_bits(ac97, AC97_AD_MISC, AC97_AD1986_SOSEL, | ||
2258 | (ucontrol->value.integer.value[0] != 0 | ||
2259 | || sprd) | ||
2260 | ? AC97_AD1986_SOSEL : 0); | ||
2261 | if (ret1 < 0) | ||
2262 | return ret1; | ||
2263 | |||
2264 | return (ret0 > 0 || ret1 > 0) ? 1 : 0; | ||
2265 | } | ||
2266 | |||
2267 | static int snd_ac97_ad1986_miclisel_get(struct snd_kcontrol *kcontrol, | ||
2268 | struct snd_ctl_elem_value *ucontrol) | ||
2269 | { | ||
2270 | struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); | ||
2271 | |||
2272 | ucontrol->value.integer.value[0] = ac97->spec.ad18xx.swap_mic_linein; | ||
2273 | return 0; | ||
2274 | } | ||
2275 | |||
2276 | static int snd_ac97_ad1986_miclisel_put(struct snd_kcontrol *kcontrol, | ||
2277 | struct snd_ctl_elem_value *ucontrol) | ||
2278 | { | ||
2279 | struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); | ||
2280 | unsigned char swap = ucontrol->value.integer.value[0] != 0; | ||
2281 | |||
2282 | if (swap != ac97->spec.ad18xx.swap_mic_linein) { | ||
2283 | ac97->spec.ad18xx.swap_mic_linein = swap; | ||
2284 | if (ac97->build_ops->update_jacks) | ||
2285 | ac97->build_ops->update_jacks(ac97); | ||
2286 | return 1; | ||
2287 | } | ||
2288 | return 0; | ||
2289 | } | ||
2290 | |||
2291 | static int snd_ac97_ad1986_vrefout_get(struct snd_kcontrol *kcontrol, | ||
2292 | struct snd_ctl_elem_value *ucontrol) | ||
2293 | { | ||
2294 | /* Use MIC_1/2 V_REFOUT as the "get" value */ | ||
2295 | struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); | ||
2296 | unsigned short val; | ||
2297 | unsigned short reg = ac97->regs[AC97_AD_MISC2]; | ||
2298 | if ((reg & AC97_AD1986_MVREF0) != 0) | ||
2299 | val = 2; | ||
2300 | else if ((reg & AC97_AD1986_MVREF1) != 0) | ||
2301 | val = 3; | ||
2302 | else if ((reg & AC97_AD1986_MVREF2) != 0) | ||
2303 | val = 1; | ||
2304 | else | ||
2305 | val = 0; | ||
2306 | ucontrol->value.enumerated.item[0] = val; | ||
2307 | return 0; | ||
2308 | } | ||
2309 | |||
2310 | static int snd_ac97_ad1986_vrefout_put(struct snd_kcontrol *kcontrol, | ||
2311 | struct snd_ctl_elem_value *ucontrol) | ||
2312 | { | ||
2313 | struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); | ||
2314 | unsigned short cval; | ||
2315 | unsigned short lval; | ||
2316 | unsigned short mval; | ||
2317 | int cret; | ||
2318 | int lret; | ||
2319 | int mret; | ||
2320 | |||
2321 | switch (ucontrol->value.enumerated.item[0]) | ||
2322 | { | ||
2323 | case 0: /* High-Z */ | ||
2324 | cval = 0; | ||
2325 | lval = 0; | ||
2326 | mval = 0; | ||
2327 | break; | ||
2328 | case 1: /* 3.7 V */ | ||
2329 | cval = AC97_AD1986_CVREF2; | ||
2330 | lval = AC97_AD1986_LVREF2; | ||
2331 | mval = AC97_AD1986_MVREF2; | ||
2332 | break; | ||
2333 | case 2: /* 2.25 V */ | ||
2334 | cval = AC97_AD1986_CVREF0; | ||
2335 | lval = AC97_AD1986_LVREF0; | ||
2336 | mval = AC97_AD1986_MVREF0; | ||
2337 | break; | ||
2338 | case 3: /* 0 V */ | ||
2339 | cval = AC97_AD1986_CVREF1; | ||
2340 | lval = AC97_AD1986_LVREF1; | ||
2341 | mval = AC97_AD1986_MVREF1; | ||
2342 | break; | ||
2343 | default: | ||
2344 | return -EINVAL; | ||
2345 | } | ||
2346 | |||
2347 | cret = snd_ac97_update_bits(ac97, AC97_AD_MISC2, | ||
2348 | AC97_AD1986_CVREF_MASK, cval); | ||
2349 | if (cret < 0) | ||
2350 | return cret; | ||
2351 | lret = snd_ac97_update_bits(ac97, AC97_AD_MISC3, | ||
2352 | AC97_AD1986_LVREF_MASK, lval); | ||
2353 | if (lret < 0) | ||
2354 | return lret; | ||
2355 | mret = snd_ac97_update_bits(ac97, AC97_AD_MISC2, | ||
2356 | AC97_AD1986_MVREF_MASK, mval); | ||
2357 | if (mret < 0) | ||
2358 | return mret; | ||
2359 | |||
2360 | return (cret > 0 || lret > 0 || mret > 0) ? 1 : 0; | ||
2361 | } | ||
2362 | |||
2363 | static const struct snd_kcontrol_new snd_ac97_ad1986_controls[] = { | ||
2364 | AC97_SINGLE("Exchange Center/LFE", AC97_AD_SERIAL_CFG, 3, 1, 0), | ||
2365 | { | ||
2366 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2367 | .name = "Exchange Front/Surround", | ||
2368 | .info = snd_ac97_ad1986_bool_info, | ||
2369 | .get = snd_ac97_ad1986_lososel_get, | ||
2370 | .put = snd_ac97_ad1986_lososel_put | ||
2371 | }, | ||
2372 | { | ||
2373 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2374 | .name = "Exchange Mic/Line In", | ||
2375 | .info = snd_ac97_ad1986_bool_info, | ||
2376 | .get = snd_ac97_ad1986_miclisel_get, | ||
2377 | .put = snd_ac97_ad1986_miclisel_put | ||
2378 | }, | ||
2379 | { | ||
2380 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2381 | .name = "Spread Front to Surround and Center/LFE", | ||
2382 | .info = snd_ac97_ad1986_bool_info, | ||
2383 | .get = snd_ac97_ad1986_spread_get, | ||
2384 | .put = snd_ac97_ad1986_spread_put | ||
2385 | }, | ||
2386 | { | ||
2387 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2388 | .name = "Downmix", | ||
2389 | .info = snd_ac97_ad1888_downmix_info, | ||
2390 | .get = snd_ac97_ad1888_downmix_get, | ||
2391 | .put = snd_ac97_ad1888_downmix_put | ||
2392 | }, | ||
2393 | { | ||
2394 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2395 | .name = "V_REFOUT", | ||
2396 | .info = snd_ac97_ad1985_vrefout_info, | ||
2397 | .get = snd_ac97_ad1986_vrefout_get, | ||
2398 | .put = snd_ac97_ad1986_vrefout_put | ||
2399 | }, | ||
2400 | AC97_SURROUND_JACK_MODE_CTL, | ||
2401 | AC97_CHANNEL_MODE_CTL, | ||
2402 | |||
2403 | AC97_SINGLE("Headphone Jack Sense", AC97_AD_JACK_SPDIF, 10, 1, 0), | ||
2404 | AC97_SINGLE("Line Jack Sense", AC97_AD_JACK_SPDIF, 12, 1, 0) | ||
2405 | }; | ||
2406 | |||
2407 | static void ad1986_update_jacks(struct snd_ac97 *ac97) | ||
2408 | { | ||
2409 | unsigned short misc_val = 0; | ||
2410 | unsigned short ser_val; | ||
2411 | |||
2412 | /* disable SURROUND and CENTER/LFE if not surround mode */ | ||
2413 | if (! is_surround_on(ac97)) | ||
2414 | misc_val |= AC97_AD1986_SODIS; | ||
2415 | if (! is_clfe_on(ac97)) | ||
2416 | misc_val |= AC97_AD1986_CLDIS; | ||
2417 | |||
2418 | /* select line input (default=LINE_IN, SURROUND or MIC_1/2) */ | ||
2419 | if (is_shared_linein(ac97)) | ||
2420 | misc_val |= AC97_AD1986_LISEL_SURR; | ||
2421 | else if (ac97->spec.ad18xx.swap_mic_linein != 0) | ||
2422 | misc_val |= AC97_AD1986_LISEL_MIC; | ||
2423 | snd_ac97_update_bits(ac97, AC97_AD_MISC, | ||
2424 | AC97_AD1986_SODIS | AC97_AD1986_CLDIS | | ||
2425 | AC97_AD1986_LISEL_MASK, | ||
2426 | misc_val); | ||
2427 | |||
2428 | /* select microphone input (MIC_1/2, Center/LFE or LINE_IN) */ | ||
2429 | if (is_shared_micin(ac97)) | ||
2430 | ser_val = AC97_AD1986_OMS_C; | ||
2431 | else if (ac97->spec.ad18xx.swap_mic_linein != 0) | ||
2432 | ser_val = AC97_AD1986_OMS_L; | ||
2433 | else | ||
2434 | ser_val = AC97_AD1986_OMS_M; | ||
2435 | snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, | ||
2436 | AC97_AD1986_OMS_MASK, | ||
2437 | ser_val); | ||
2438 | } | ||
2439 | |||
2440 | static int patch_ad1986_specific(struct snd_ac97 *ac97) | ||
2441 | { | ||
2442 | int err; | ||
2443 | |||
2444 | if ((err = patch_build_controls(ac97, &snd_ac97_ad198x_2cmic, 1)) < 0) | ||
2445 | return err; | ||
2446 | |||
2447 | return patch_build_controls(ac97, snd_ac97_ad1986_controls, | ||
2448 | ARRAY_SIZE(snd_ac97_ad1985_controls)); | ||
2449 | } | ||
2450 | |||
2451 | static struct snd_ac97_build_ops patch_ad1986_build_ops = { | ||
2452 | .build_post_spdif = patch_ad198x_post_spdif, | ||
2453 | .build_specific = patch_ad1986_specific, | ||
2454 | #ifdef CONFIG_PM | ||
2455 | .resume = ad18xx_resume, | ||
2456 | #endif | ||
2457 | .update_jacks = ad1986_update_jacks, | ||
2458 | }; | ||
2459 | |||
2460 | int patch_ad1986(struct snd_ac97 * ac97) | ||
2461 | { | ||
2462 | patch_ad1881(ac97); | ||
2463 | ac97->build_ops = &patch_ad1986_build_ops; | ||
2464 | ac97->flags |= AC97_STEREO_MUTES; | ||
2465 | |||
2466 | /* update current jack configuration */ | ||
2467 | ad1986_update_jacks(ac97); | ||
2468 | |||
2469 | return 0; | ||
2470 | } | ||
2471 | |||
2472 | |||
2010 | /* | 2473 | /* |
2011 | * realtek ALC65x/850 codecs | 2474 | * realtek ALC65x/850 codecs |
2012 | */ | 2475 | */ |
@@ -2014,12 +2477,12 @@ static void alc650_update_jacks(struct snd_ac97 *ac97) | |||
2014 | { | 2477 | { |
2015 | int shared; | 2478 | int shared; |
2016 | 2479 | ||
2017 | /* shared Line-In */ | 2480 | /* shared Line-In / Surround Out */ |
2018 | shared = is_shared_linein(ac97); | 2481 | shared = is_shared_surrout(ac97); |
2019 | snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 1 << 9, | 2482 | snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 1 << 9, |
2020 | shared ? (1 << 9) : 0); | 2483 | shared ? (1 << 9) : 0); |
2021 | /* update shared Mic */ | 2484 | /* update shared Mic In / Center/LFE Out */ |
2022 | shared = is_shared_micin(ac97); | 2485 | shared = is_shared_clfeout(ac97); |
2023 | /* disable/enable vref */ | 2486 | /* disable/enable vref */ |
2024 | snd_ac97_update_bits(ac97, AC97_ALC650_CLOCK, 1 << 12, | 2487 | snd_ac97_update_bits(ac97, AC97_ALC650_CLOCK, 1 << 12, |
2025 | shared ? (1 << 12) : 0); | 2488 | shared ? (1 << 12) : 0); |
@@ -2064,7 +2527,7 @@ static const struct snd_kcontrol_new snd_ac97_spdif_controls_alc650[] = { | |||
2064 | /* AC97_SINGLE("IEC958 Input Monitor", AC97_ALC650_MULTICH, 13, 1, 0), */ | 2527 | /* AC97_SINGLE("IEC958 Input Monitor", AC97_ALC650_MULTICH, 13, 1, 0), */ |
2065 | }; | 2528 | }; |
2066 | 2529 | ||
2067 | static DECLARE_TLV_DB_SCALE(db_scale_5bit_3db_max, -4350, 150, 0); | 2530 | static const DECLARE_TLV_DB_SCALE(db_scale_5bit_3db_max, -4350, 150, 0); |
2068 | 2531 | ||
2069 | static int patch_alc650_specific(struct snd_ac97 * ac97) | 2532 | static int patch_alc650_specific(struct snd_ac97 * ac97) |
2070 | { | 2533 | { |
@@ -2149,12 +2612,12 @@ static void alc655_update_jacks(struct snd_ac97 *ac97) | |||
2149 | { | 2612 | { |
2150 | int shared; | 2613 | int shared; |
2151 | 2614 | ||
2152 | /* shared Line-In */ | 2615 | /* shared Line-In / Surround Out */ |
2153 | shared = is_shared_linein(ac97); | 2616 | shared = is_shared_surrout(ac97); |
2154 | ac97_update_bits_page(ac97, AC97_ALC650_MULTICH, 1 << 9, | 2617 | ac97_update_bits_page(ac97, AC97_ALC650_MULTICH, 1 << 9, |
2155 | shared ? (1 << 9) : 0, 0); | 2618 | shared ? (1 << 9) : 0, 0); |
2156 | /* update shared mic */ | 2619 | /* update shared Mic In / Center/LFE Out */ |
2157 | shared = is_shared_micin(ac97); | 2620 | shared = is_shared_clfeout(ac97); |
2158 | /* misc control; vrefout disable */ | 2621 | /* misc control; vrefout disable */ |
2159 | snd_ac97_update_bits(ac97, AC97_ALC650_CLOCK, 1 << 12, | 2622 | snd_ac97_update_bits(ac97, AC97_ALC650_CLOCK, 1 << 12, |
2160 | shared ? (1 << 12) : 0); | 2623 | shared ? (1 << 12) : 0); |
@@ -2264,7 +2727,8 @@ int patch_alc655(struct snd_ac97 * ac97) | |||
2264 | if (ac97->subsystem_vendor == 0x1462 && | 2727 | if (ac97->subsystem_vendor == 0x1462 && |
2265 | (ac97->subsystem_device == 0x0131 || /* MSI S270 laptop */ | 2728 | (ac97->subsystem_device == 0x0131 || /* MSI S270 laptop */ |
2266 | ac97->subsystem_device == 0x0161 || /* LG K1 Express */ | 2729 | ac97->subsystem_device == 0x0161 || /* LG K1 Express */ |
2267 | ac97->subsystem_device == 0x0351)) /* MSI L725 laptop */ | 2730 | ac97->subsystem_device == 0x0351 || /* MSI L725 laptop */ |
2731 | ac97->subsystem_device == 0x0061)) /* MSI S250 laptop */ | ||
2268 | val &= ~(1 << 1); /* Pin 47 is EAPD (for internal speaker) */ | 2732 | val &= ~(1 << 1); /* Pin 47 is EAPD (for internal speaker) */ |
2269 | else | 2733 | else |
2270 | val |= (1 << 1); /* Pin 47 is spdif input pin */ | 2734 | val |= (1 << 1); /* Pin 47 is spdif input pin */ |
@@ -2297,16 +2761,16 @@ static void alc850_update_jacks(struct snd_ac97 *ac97) | |||
2297 | { | 2761 | { |
2298 | int shared; | 2762 | int shared; |
2299 | 2763 | ||
2300 | /* shared Line-In */ | 2764 | /* shared Line-In / Surround Out */ |
2301 | shared = is_shared_linein(ac97); | 2765 | shared = is_shared_surrout(ac97); |
2302 | /* SURR 1kOhm (bit4), Amp (bit5) */ | 2766 | /* SURR 1kOhm (bit4), Amp (bit5) */ |
2303 | snd_ac97_update_bits(ac97, AC97_ALC850_MISC1, (1<<4)|(1<<5), | 2767 | snd_ac97_update_bits(ac97, AC97_ALC850_MISC1, (1<<4)|(1<<5), |
2304 | shared ? (1<<5) : (1<<4)); | 2768 | shared ? (1<<5) : (1<<4)); |
2305 | /* LINE-IN = 0, SURROUND = 2 */ | 2769 | /* LINE-IN = 0, SURROUND = 2 */ |
2306 | snd_ac97_update_bits(ac97, AC97_ALC850_JACK_SELECT, 7 << 12, | 2770 | snd_ac97_update_bits(ac97, AC97_ALC850_JACK_SELECT, 7 << 12, |
2307 | shared ? (2<<12) : (0<<12)); | 2771 | shared ? (2<<12) : (0<<12)); |
2308 | /* update shared mic */ | 2772 | /* update shared Mic In / Center/LFE Out */ |
2309 | shared = is_shared_micin(ac97); | 2773 | shared = is_shared_clfeout(ac97); |
2310 | /* Vref disable (bit12), 1kOhm (bit13) */ | 2774 | /* Vref disable (bit12), 1kOhm (bit13) */ |
2311 | snd_ac97_update_bits(ac97, AC97_ALC850_MISC1, (1<<12)|(1<<13), | 2775 | snd_ac97_update_bits(ac97, AC97_ALC850_MISC1, (1<<12)|(1<<13), |
2312 | shared ? (1<<12) : (1<<13)); | 2776 | shared ? (1<<12) : (1<<13)); |
@@ -2379,9 +2843,9 @@ int patch_alc850(struct snd_ac97 *ac97) | |||
2379 | */ | 2843 | */ |
2380 | static void cm9738_update_jacks(struct snd_ac97 *ac97) | 2844 | static void cm9738_update_jacks(struct snd_ac97 *ac97) |
2381 | { | 2845 | { |
2382 | /* shared Line-In */ | 2846 | /* shared Line-In / Surround Out */ |
2383 | snd_ac97_update_bits(ac97, AC97_CM9738_VENDOR_CTRL, 1 << 10, | 2847 | snd_ac97_update_bits(ac97, AC97_CM9738_VENDOR_CTRL, 1 << 10, |
2384 | is_shared_linein(ac97) ? (1 << 10) : 0); | 2848 | is_shared_surrout(ac97) ? (1 << 10) : 0); |
2385 | } | 2849 | } |
2386 | 2850 | ||
2387 | static const struct snd_kcontrol_new snd_ac97_cm9738_controls[] = { | 2851 | static const struct snd_kcontrol_new snd_ac97_cm9738_controls[] = { |
@@ -2463,12 +2927,12 @@ static const struct snd_kcontrol_new snd_ac97_cm9739_controls_spdif[] = { | |||
2463 | 2927 | ||
2464 | static void cm9739_update_jacks(struct snd_ac97 *ac97) | 2928 | static void cm9739_update_jacks(struct snd_ac97 *ac97) |
2465 | { | 2929 | { |
2466 | /* shared Line-In */ | 2930 | /* shared Line-In / Surround Out */ |
2467 | snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 1 << 10, | 2931 | snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 1 << 10, |
2468 | is_shared_linein(ac97) ? (1 << 10) : 0); | 2932 | is_shared_surrout(ac97) ? (1 << 10) : 0); |
2469 | /* shared Mic */ | 2933 | /* shared Mic In / Center/LFE Out **/ |
2470 | snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 0x3000, | 2934 | snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 0x3000, |
2471 | is_shared_micin(ac97) ? 0x1000 : 0x2000); | 2935 | is_shared_clfeout(ac97) ? 0x1000 : 0x2000); |
2472 | } | 2936 | } |
2473 | 2937 | ||
2474 | static const struct snd_kcontrol_new snd_ac97_cm9739_controls[] = { | 2938 | static const struct snd_kcontrol_new snd_ac97_cm9739_controls[] = { |
@@ -2580,8 +3044,8 @@ static void cm9761_update_jacks(struct snd_ac97 *ac97) | |||
2580 | 3044 | ||
2581 | val |= surr_on[ac97->spec.dev_flags][is_surround_on(ac97)]; | 3045 | val |= surr_on[ac97->spec.dev_flags][is_surround_on(ac97)]; |
2582 | val |= clfe_on[ac97->spec.dev_flags][is_clfe_on(ac97)]; | 3046 | val |= clfe_on[ac97->spec.dev_flags][is_clfe_on(ac97)]; |
2583 | val |= surr_shared[ac97->spec.dev_flags][is_shared_linein(ac97)]; | 3047 | val |= surr_shared[ac97->spec.dev_flags][is_shared_surrout(ac97)]; |
2584 | val |= clfe_shared[ac97->spec.dev_flags][is_shared_micin(ac97)]; | 3048 | val |= clfe_shared[ac97->spec.dev_flags][is_shared_clfeout(ac97)]; |
2585 | 3049 | ||
2586 | snd_ac97_update_bits(ac97, AC97_CM9761_MULTI_CHAN, 0x3c88, val); | 3050 | snd_ac97_update_bits(ac97, AC97_CM9761_MULTI_CHAN, 0x3c88, val); |
2587 | } | 3051 | } |
@@ -2821,6 +3285,7 @@ int patch_vt1617a(struct snd_ac97 * ac97) | |||
2821 | snd_ac97_write_cache(ac97, 0x5c, 0x20); | 3285 | snd_ac97_write_cache(ac97, 0x5c, 0x20); |
2822 | ac97->ext_id |= AC97_EI_SPDIF; /* force the detection of spdif */ | 3286 | ac97->ext_id |= AC97_EI_SPDIF; /* force the detection of spdif */ |
2823 | ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000; | 3287 | ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000; |
3288 | ac97->build_ops = &patch_vt1616_ops; | ||
2824 | return 0; | 3289 | return 0; |
2825 | } | 3290 | } |
2826 | 3291 | ||
@@ -2828,12 +3293,12 @@ int patch_vt1617a(struct snd_ac97 * ac97) | |||
2828 | */ | 3293 | */ |
2829 | static void it2646_update_jacks(struct snd_ac97 *ac97) | 3294 | static void it2646_update_jacks(struct snd_ac97 *ac97) |
2830 | { | 3295 | { |
2831 | /* shared Line-In */ | 3296 | /* shared Line-In / Surround Out */ |
2832 | snd_ac97_update_bits(ac97, 0x76, 1 << 9, | 3297 | snd_ac97_update_bits(ac97, 0x76, 1 << 9, |
2833 | is_shared_linein(ac97) ? (1<<9) : 0); | 3298 | is_shared_surrout(ac97) ? (1<<9) : 0); |
2834 | /* shared Mic */ | 3299 | /* shared Mic / Center/LFE Out */ |
2835 | snd_ac97_update_bits(ac97, 0x76, 1 << 10, | 3300 | snd_ac97_update_bits(ac97, 0x76, 1 << 10, |
2836 | is_shared_micin(ac97) ? (1<<10) : 0); | 3301 | is_shared_clfeout(ac97) ? (1<<10) : 0); |
2837 | } | 3302 | } |
2838 | 3303 | ||
2839 | static const struct snd_kcontrol_new snd_ac97_controls_it2646[] = { | 3304 | static const struct snd_kcontrol_new snd_ac97_controls_it2646[] = { |
diff --git a/sound/pci/ac97/ac97_patch.h b/sound/pci/ac97/ac97_patch.h index 741979217207..94340daaaf1f 100644 --- a/sound/pci/ac97/ac97_patch.h +++ b/sound/pci/ac97/ac97_patch.h | |||
@@ -48,6 +48,7 @@ int patch_ad1980(struct snd_ac97 * ac97); | |||
48 | int patch_ad1981a(struct snd_ac97 * ac97); | 48 | int patch_ad1981a(struct snd_ac97 * ac97); |
49 | int patch_ad1981b(struct snd_ac97 * ac97); | 49 | int patch_ad1981b(struct snd_ac97 * ac97); |
50 | int patch_ad1985(struct snd_ac97 * ac97); | 50 | int patch_ad1985(struct snd_ac97 * ac97); |
51 | int patch_ad1986(struct snd_ac97 * ac97); | ||
51 | int patch_alc650(struct snd_ac97 * ac97); | 52 | int patch_alc650(struct snd_ac97 * ac97); |
52 | int patch_alc655(struct snd_ac97 * ac97); | 53 | int patch_alc655(struct snd_ac97 * ac97); |
53 | int patch_alc850(struct snd_ac97 * ac97); | 54 | int patch_alc850(struct snd_ac97 * ac97); |
diff --git a/sound/pci/ac97/ak4531_codec.c b/sound/pci/ac97/ak4531_codec.c index c153cb79c518..dc26820a03a5 100644 --- a/sound/pci/ac97/ak4531_codec.c +++ b/sound/pci/ac97/ak4531_codec.c | |||
@@ -267,9 +267,9 @@ static int snd_ak4531_put_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl | |||
267 | return change; | 267 | return change; |
268 | } | 268 | } |
269 | 269 | ||
270 | static DECLARE_TLV_DB_SCALE(db_scale_master, -6200, 200, 0); | 270 | static const DECLARE_TLV_DB_SCALE(db_scale_master, -6200, 200, 0); |
271 | static DECLARE_TLV_DB_SCALE(db_scale_mono, -2800, 400, 0); | 271 | static const DECLARE_TLV_DB_SCALE(db_scale_mono, -2800, 400, 0); |
272 | static DECLARE_TLV_DB_SCALE(db_scale_input, -5000, 200, 0); | 272 | static const DECLARE_TLV_DB_SCALE(db_scale_input, -5000, 200, 0); |
273 | 273 | ||
274 | static struct snd_kcontrol_new snd_ak4531_controls[] = { | 274 | static struct snd_kcontrol_new snd_ak4531_controls[] = { |
275 | 275 | ||
diff --git a/sound/pci/als300.c b/sound/pci/als300.c index 9f406fbe0d95..8afcb98ca7bb 100644 --- a/sound/pci/als300.c +++ b/sound/pci/als300.c | |||
@@ -444,7 +444,7 @@ static int snd_als300_capture_close(struct snd_pcm_substream *substream) | |||
444 | } | 444 | } |
445 | 445 | ||
446 | static int snd_als300_pcm_hw_params(struct snd_pcm_substream *substream, | 446 | static int snd_als300_pcm_hw_params(struct snd_pcm_substream *substream, |
447 | snd_pcm_hw_params_t * hw_params) | 447 | struct snd_pcm_hw_params *hw_params) |
448 | { | 448 | { |
449 | return snd_pcm_lib_malloc_pages(substream, | 449 | return snd_pcm_lib_malloc_pages(substream, |
450 | params_buffer_bytes(hw_params)); | 450 | params_buffer_bytes(hw_params)); |
@@ -673,7 +673,7 @@ static void snd_als300_init(struct snd_als300 *chip) | |||
673 | snd_als300_dbgcallleave(); | 673 | snd_als300_dbgcallleave(); |
674 | } | 674 | } |
675 | 675 | ||
676 | static int __devinit snd_als300_create(snd_card_t *card, | 676 | static int __devinit snd_als300_create(struct snd_card *card, |
677 | struct pci_dev *pci, int chip_type, | 677 | struct pci_dev *pci, int chip_type, |
678 | struct snd_als300 **rchip) | 678 | struct snd_als300 **rchip) |
679 | { | 679 | { |
@@ -681,7 +681,7 @@ static int __devinit snd_als300_create(snd_card_t *card, | |||
681 | void *irq_handler; | 681 | void *irq_handler; |
682 | int err; | 682 | int err; |
683 | 683 | ||
684 | static snd_device_ops_t ops = { | 684 | static struct snd_device_ops ops = { |
685 | .dev_free = snd_als300_dev_free, | 685 | .dev_free = snd_als300_dev_free, |
686 | }; | 686 | }; |
687 | *rchip = NULL; | 687 | *rchip = NULL; |
diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c index 476c3433073e..7d8053b5e8d5 100644 --- a/sound/pci/atiixp.c +++ b/sound/pci/atiixp.c | |||
@@ -45,6 +45,7 @@ static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */ | |||
45 | static int ac97_clock = 48000; | 45 | static int ac97_clock = 48000; |
46 | static char *ac97_quirk; | 46 | static char *ac97_quirk; |
47 | static int spdif_aclink = 1; | 47 | static int spdif_aclink = 1; |
48 | static int ac97_codec = -1; | ||
48 | 49 | ||
49 | module_param(index, int, 0444); | 50 | module_param(index, int, 0444); |
50 | MODULE_PARM_DESC(index, "Index value for ATI IXP controller."); | 51 | MODULE_PARM_DESC(index, "Index value for ATI IXP controller."); |
@@ -54,6 +55,8 @@ module_param(ac97_clock, int, 0444); | |||
54 | MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (default 48000Hz)."); | 55 | MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (default 48000Hz)."); |
55 | module_param(ac97_quirk, charp, 0444); | 56 | module_param(ac97_quirk, charp, 0444); |
56 | MODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware."); | 57 | MODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware."); |
58 | module_param(ac97_codec, int, 0444); | ||
59 | MODULE_PARM_DESC(ac97_codec, "Specify codec instead of probing."); | ||
57 | module_param(spdif_aclink, bool, 0444); | 60 | module_param(spdif_aclink, bool, 0444); |
58 | MODULE_PARM_DESC(spdif_aclink, "S/PDIF over AC-link."); | 61 | MODULE_PARM_DESC(spdif_aclink, "S/PDIF over AC-link."); |
59 | 62 | ||
@@ -293,6 +296,10 @@ static struct pci_device_id snd_atiixp_ids[] = { | |||
293 | 296 | ||
294 | MODULE_DEVICE_TABLE(pci, snd_atiixp_ids); | 297 | MODULE_DEVICE_TABLE(pci, snd_atiixp_ids); |
295 | 298 | ||
299 | static struct snd_pci_quirk atiixp_quirks[] __devinitdata = { | ||
300 | SND_PCI_QUIRK(0x15bd, 0x3100, "DFI RS482", 0), | ||
301 | { } /* terminator */ | ||
302 | }; | ||
296 | 303 | ||
297 | /* | 304 | /* |
298 | * lowlevel functions | 305 | * lowlevel functions |
@@ -553,11 +560,33 @@ static int snd_atiixp_aclink_down(struct atiixp *chip) | |||
553 | ATI_REG_ISR_CODEC2_NOT_READY) | 560 | ATI_REG_ISR_CODEC2_NOT_READY) |
554 | #define CODEC_CHECK_BITS (ALL_CODEC_NOT_READY|ATI_REG_ISR_NEW_FRAME) | 561 | #define CODEC_CHECK_BITS (ALL_CODEC_NOT_READY|ATI_REG_ISR_NEW_FRAME) |
555 | 562 | ||
563 | static int ac97_probing_bugs(struct pci_dev *pci) | ||
564 | { | ||
565 | const struct snd_pci_quirk *q; | ||
566 | |||
567 | q = snd_pci_quirk_lookup(pci, atiixp_quirks); | ||
568 | if (q) { | ||
569 | snd_printdd(KERN_INFO "Atiixp quirk for %s. " | ||
570 | "Forcing codec %d\n", q->name, q->value); | ||
571 | return q->value; | ||
572 | } | ||
573 | /* this hardware doesn't need workarounds. Probe for codec */ | ||
574 | return -1; | ||
575 | } | ||
576 | |||
556 | static int snd_atiixp_codec_detect(struct atiixp *chip) | 577 | static int snd_atiixp_codec_detect(struct atiixp *chip) |
557 | { | 578 | { |
558 | int timeout; | 579 | int timeout; |
559 | 580 | ||
560 | chip->codec_not_ready_bits = 0; | 581 | chip->codec_not_ready_bits = 0; |
582 | if (ac97_codec == -1) | ||
583 | ac97_codec = ac97_probing_bugs(chip->pci); | ||
584 | if (ac97_codec >= 0) { | ||
585 | chip->codec_not_ready_bits |= | ||
586 | CODEC_CHECK_BITS ^ (1 << (ac97_codec + 10)); | ||
587 | return 0; | ||
588 | } | ||
589 | |||
561 | atiixp_write(chip, IER, CODEC_CHECK_BITS); | 590 | atiixp_write(chip, IER, CODEC_CHECK_BITS); |
562 | /* wait for the interrupts */ | 591 | /* wait for the interrupts */ |
563 | timeout = 50; | 592 | timeout = 50; |
@@ -1396,7 +1425,7 @@ static int __devinit snd_atiixp_mixer_new(struct atiixp *chip, int clock, | |||
1396 | ac97.private_data = chip; | 1425 | ac97.private_data = chip; |
1397 | ac97.pci = chip->pci; | 1426 | ac97.pci = chip->pci; |
1398 | ac97.num = i; | 1427 | ac97.num = i; |
1399 | ac97.scaps = AC97_SCAP_SKIP_MODEM; | 1428 | ac97.scaps = AC97_SCAP_SKIP_MODEM | AC97_SCAP_POWER_SAVE; |
1400 | if (! chip->spdif_over_aclink) | 1429 | if (! chip->spdif_over_aclink) |
1401 | ac97.scaps |= AC97_SCAP_NO_SPDIF; | 1430 | ac97.scaps |= AC97_SCAP_NO_SPDIF; |
1402 | if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97[i])) < 0) { | 1431 | if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97[i])) < 0) { |
diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c index cc2e6b9d407e..904023fe4f26 100644 --- a/sound/pci/atiixp_modem.c +++ b/sound/pci/atiixp_modem.c | |||
@@ -1090,7 +1090,7 @@ static int __devinit snd_atiixp_mixer_new(struct atiixp_modem *chip, int clock) | |||
1090 | ac97.private_data = chip; | 1090 | ac97.private_data = chip; |
1091 | ac97.pci = chip->pci; | 1091 | ac97.pci = chip->pci; |
1092 | ac97.num = i; | 1092 | ac97.num = i; |
1093 | ac97.scaps = AC97_SCAP_SKIP_AUDIO; | 1093 | ac97.scaps = AC97_SCAP_SKIP_AUDIO | AC97_SCAP_POWER_SAVE; |
1094 | if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97[i])) < 0) { | 1094 | if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97[i])) < 0) { |
1095 | chip->ac97[i] = NULL; /* to be sure */ | 1095 | chip->ac97[i] = NULL; /* to be sure */ |
1096 | snd_printdd("atiixp-modem: codec %d not available for modem\n", i); | 1096 | snd_printdd("atiixp-modem: codec %d not available for modem\n", i); |
diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index f61f052f6d14..ea6712b63c9f 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c | |||
@@ -1382,7 +1382,6 @@ static int __devinit snd_ca0106_create(int dev, struct snd_card *card, | |||
1382 | snd_ca0106_ptr_write(chip, SPDIF_SELECT1, 0, 0xf); | 1382 | snd_ca0106_ptr_write(chip, SPDIF_SELECT1, 0, 0xf); |
1383 | snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0x000f0000); /* 0x0b000000 for digital, 0x000b0000 for analog, from win2000 drivers. Use 0x000f0000 for surround71 */ | 1383 | snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0x000f0000); /* 0x0b000000 for digital, 0x000b0000 for analog, from win2000 drivers. Use 0x000f0000 for surround71 */ |
1384 | chip->spdif_enable = 0; /* Set digital SPDIF output off */ | 1384 | chip->spdif_enable = 0; /* Set digital SPDIF output off */ |
1385 | chip->capture_source = 3; /* Set CAPTURE_SOURCE */ | ||
1386 | //snd_ca0106_ptr_write(chip, 0x45, 0, 0); /* Analogue out */ | 1385 | //snd_ca0106_ptr_write(chip, 0x45, 0, 0); /* Analogue out */ |
1387 | //snd_ca0106_ptr_write(chip, 0x45, 0, 0xf00); /* Digital out */ | 1386 | //snd_ca0106_ptr_write(chip, 0x45, 0, 0xf00); /* Digital out */ |
1388 | 1387 | ||
@@ -1402,8 +1401,22 @@ static int __devinit snd_ca0106_create(int dev, struct snd_card *card, | |||
1402 | snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME1, ch, 0xffffffff); /* Mute */ | 1401 | snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME1, ch, 0xffffffff); /* Mute */ |
1403 | snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME2, ch, 0xffffffff); /* Mute */ | 1402 | snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME2, ch, 0xffffffff); /* Mute */ |
1404 | } | 1403 | } |
1405 | snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x333300e4); /* Select MIC, Line in, TAD in, AUX in */ | 1404 | if (chip->details->i2c_adc == 1) { |
1406 | chip->capture_source = 3; /* Set CAPTURE_SOURCE */ | 1405 | /* Select MIC, Line in, TAD in, AUX in */ |
1406 | snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x333300e4); | ||
1407 | /* Default to CAPTURE_SOURCE to i2s in */ | ||
1408 | chip->capture_source = 3; | ||
1409 | } else if (chip->details->ac97 == 1) { | ||
1410 | /* Default to AC97 in */ | ||
1411 | snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x444400e4); | ||
1412 | /* Default to CAPTURE_SOURCE to AC97 in */ | ||
1413 | chip->capture_source = 4; | ||
1414 | } else { | ||
1415 | /* Select MIC, Line in, TAD in, AUX in */ | ||
1416 | snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x333300e4); | ||
1417 | /* Default to Set CAPTURE_SOURCE to i2s in */ | ||
1418 | chip->capture_source = 3; | ||
1419 | } | ||
1407 | 1420 | ||
1408 | if (chip->details->gpio_type == 2) { /* The SB0438 use GPIO differently. */ | 1421 | if (chip->details->gpio_type == 2) { /* The SB0438 use GPIO differently. */ |
1409 | /* FIXME: Still need to find out what the other GPIO bits do. E.g. For digital spdif out. */ | 1422 | /* FIXME: Still need to find out what the other GPIO bits do. E.g. For digital spdif out. */ |
@@ -1605,6 +1618,8 @@ static int __devinit snd_ca0106_probe(struct pci_dev *pci, | |||
1605 | snd_ca0106_proc_init(chip); | 1618 | snd_ca0106_proc_init(chip); |
1606 | #endif | 1619 | #endif |
1607 | 1620 | ||
1621 | snd_card_set_dev(card, &pci->dev); | ||
1622 | |||
1608 | if ((err = snd_card_register(card)) < 0) { | 1623 | if ((err = snd_card_register(card)) < 0) { |
1609 | snd_card_free(card); | 1624 | snd_card_free(card); |
1610 | return err; | 1625 | return err; |
diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c index 9855f528ea78..b913a1fb8c21 100644 --- a/sound/pci/ca0106/ca0106_mixer.c +++ b/sound/pci/ca0106/ca0106_mixer.c | |||
@@ -74,8 +74,8 @@ | |||
74 | 74 | ||
75 | #include "ca0106.h" | 75 | #include "ca0106.h" |
76 | 76 | ||
77 | static DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale1, -5175, 25, 1); | 77 | static const DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale1, -5175, 25, 1); |
78 | static DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale2, -10350, 50, 1); | 78 | static const DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale2, -10350, 50, 1); |
79 | 79 | ||
80 | static int snd_ca0106_shared_spdif_info(struct snd_kcontrol *kcontrol, | 80 | static int snd_ca0106_shared_spdif_info(struct snd_kcontrol *kcontrol, |
81 | struct snd_ctl_elem_info *uinfo) | 81 | struct snd_ctl_elem_info *uinfo) |
@@ -482,19 +482,6 @@ static int snd_ca0106_i2c_volume_put(struct snd_kcontrol *kcontrol, | |||
482 | .private_value = ((chid) << 8) | (reg) \ | 482 | .private_value = ((chid) << 8) | (reg) \ |
483 | } | 483 | } |
484 | 484 | ||
485 | #define I2C_VOLUME(xname,chid) \ | ||
486 | { \ | ||
487 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | ||
488 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ | ||
489 | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ | ||
490 | .info = snd_ca0106_i2c_volume_info, \ | ||
491 | .get = snd_ca0106_i2c_volume_get, \ | ||
492 | .put = snd_ca0106_i2c_volume_put, \ | ||
493 | .tlv = { .p = snd_ca0106_db_scale2 }, \ | ||
494 | .private_value = chid \ | ||
495 | } | ||
496 | |||
497 | |||
498 | static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = { | 485 | static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = { |
499 | CA_VOLUME("Analog Front Playback Volume", | 486 | CA_VOLUME("Analog Front Playback Volume", |
500 | CONTROL_FRONT_CHANNEL, PLAYBACK_VOLUME2), | 487 | CONTROL_FRONT_CHANNEL, PLAYBACK_VOLUME2), |
@@ -517,11 +504,6 @@ static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = { | |||
517 | CA_VOLUME("CAPTURE feedback Playback Volume", | 504 | CA_VOLUME("CAPTURE feedback Playback Volume", |
518 | 1, CAPTURE_CONTROL), | 505 | 1, CAPTURE_CONTROL), |
519 | 506 | ||
520 | I2C_VOLUME("Phone Capture Volume", 0), | ||
521 | I2C_VOLUME("Mic Capture Volume", 1), | ||
522 | I2C_VOLUME("Line in Capture Volume", 2), | ||
523 | I2C_VOLUME("Aux Capture Volume", 3), | ||
524 | |||
525 | { | 507 | { |
526 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | 508 | .access = SNDRV_CTL_ELEM_ACCESS_READ, |
527 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | 509 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
@@ -539,14 +521,14 @@ static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = { | |||
539 | }, | 521 | }, |
540 | { | 522 | { |
541 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 523 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
542 | .name = "Digital Capture Source", | 524 | .name = "Digital Source Capture Enum", |
543 | .info = snd_ca0106_capture_source_info, | 525 | .info = snd_ca0106_capture_source_info, |
544 | .get = snd_ca0106_capture_source_get, | 526 | .get = snd_ca0106_capture_source_get, |
545 | .put = snd_ca0106_capture_source_put | 527 | .put = snd_ca0106_capture_source_put |
546 | }, | 528 | }, |
547 | { | 529 | { |
548 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 530 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
549 | .name = "Capture Source", | 531 | .name = "Analog Source Capture Enum", |
550 | .info = snd_ca0106_i2c_capture_source_info, | 532 | .info = snd_ca0106_i2c_capture_source_info, |
551 | .get = snd_ca0106_i2c_capture_source_get, | 533 | .get = snd_ca0106_i2c_capture_source_get, |
552 | .put = snd_ca0106_i2c_capture_source_put | 534 | .put = snd_ca0106_i2c_capture_source_put |
@@ -561,6 +543,25 @@ static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = { | |||
561 | }, | 543 | }, |
562 | }; | 544 | }; |
563 | 545 | ||
546 | #define I2C_VOLUME(xname,chid) \ | ||
547 | { \ | ||
548 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | ||
549 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ | ||
550 | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ | ||
551 | .info = snd_ca0106_i2c_volume_info, \ | ||
552 | .get = snd_ca0106_i2c_volume_get, \ | ||
553 | .put = snd_ca0106_i2c_volume_put, \ | ||
554 | .tlv = { .p = snd_ca0106_db_scale2 }, \ | ||
555 | .private_value = chid \ | ||
556 | } | ||
557 | |||
558 | static struct snd_kcontrol_new snd_ca0106_volume_i2c_adc_ctls[] __devinitdata = { | ||
559 | I2C_VOLUME("Phone Capture Volume", 0), | ||
560 | I2C_VOLUME("Mic Capture Volume", 1), | ||
561 | I2C_VOLUME("Line in Capture Volume", 2), | ||
562 | I2C_VOLUME("Aux Capture Volume", 3), | ||
563 | }; | ||
564 | |||
564 | static int __devinit remove_ctl(struct snd_card *card, const char *name) | 565 | static int __devinit remove_ctl(struct snd_card *card, const char *name) |
565 | { | 566 | { |
566 | struct snd_ctl_elem_id id; | 567 | struct snd_ctl_elem_id id; |
@@ -645,6 +646,11 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu) | |||
645 | return err; | 646 | return err; |
646 | } | 647 | } |
647 | if (emu->details->i2c_adc == 1) { | 648 | if (emu->details->i2c_adc == 1) { |
649 | for (i = 0; i < ARRAY_SIZE(snd_ca0106_volume_i2c_adc_ctls); i++) { | ||
650 | err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_volume_i2c_adc_ctls[i], emu)); | ||
651 | if (err < 0) | ||
652 | return err; | ||
653 | } | ||
648 | if (emu->details->gpio_type == 1) | 654 | if (emu->details->gpio_type == 1) |
649 | err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_capture_mic_line_in, emu)); | 655 | err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_capture_mic_line_in, emu)); |
650 | else /* gpio_type == 2 */ | 656 | else /* gpio_type == 2 */ |
diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c index 8e5519de7115..44cf54607647 100644 --- a/sound/pci/cs4281.c +++ b/sound/pci/cs4281.c | |||
@@ -1055,7 +1055,7 @@ static int snd_cs4281_put_volume(struct snd_kcontrol *kcontrol, | |||
1055 | return change; | 1055 | return change; |
1056 | } | 1056 | } |
1057 | 1057 | ||
1058 | static DECLARE_TLV_DB_SCALE(db_scale_dsp, -4650, 150, 0); | 1058 | static const DECLARE_TLV_DB_SCALE(db_scale_dsp, -4650, 150, 0); |
1059 | 1059 | ||
1060 | static struct snd_kcontrol_new snd_cs4281_fm_vol = | 1060 | static struct snd_kcontrol_new snd_cs4281_fm_vol = |
1061 | { | 1061 | { |
diff --git a/sound/pci/echoaudio/darla20.c b/sound/pci/echoaudio/darla20.c index b7108e29a668..8e7fe033270f 100644 --- a/sound/pci/echoaudio/darla20.c +++ b/sound/pci/echoaudio/darla20.c | |||
@@ -47,6 +47,7 @@ | |||
47 | #include <sound/core.h> | 47 | #include <sound/core.h> |
48 | #include <sound/info.h> | 48 | #include <sound/info.h> |
49 | #include <sound/control.h> | 49 | #include <sound/control.h> |
50 | #include <sound/tlv.h> | ||
50 | #include <sound/pcm.h> | 51 | #include <sound/pcm.h> |
51 | #include <sound/pcm_params.h> | 52 | #include <sound/pcm_params.h> |
52 | #include <sound/asoundef.h> | 53 | #include <sound/asoundef.h> |
diff --git a/sound/pci/echoaudio/darla24.c b/sound/pci/echoaudio/darla24.c index e59a982ee361..a13c623eb999 100644 --- a/sound/pci/echoaudio/darla24.c +++ b/sound/pci/echoaudio/darla24.c | |||
@@ -51,6 +51,7 @@ | |||
51 | #include <sound/core.h> | 51 | #include <sound/core.h> |
52 | #include <sound/info.h> | 52 | #include <sound/info.h> |
53 | #include <sound/control.h> | 53 | #include <sound/control.h> |
54 | #include <sound/tlv.h> | ||
54 | #include <sound/pcm.h> | 55 | #include <sound/pcm.h> |
55 | #include <sound/pcm_params.h> | 56 | #include <sound/pcm_params.h> |
56 | #include <sound/asoundef.h> | 57 | #include <sound/asoundef.h> |
diff --git a/sound/pci/echoaudio/echo3g.c b/sound/pci/echoaudio/echo3g.c index 12099fe1547d..8fb15823aca5 100644 --- a/sound/pci/echoaudio/echo3g.c +++ b/sound/pci/echoaudio/echo3g.c | |||
@@ -58,6 +58,7 @@ | |||
58 | #include <sound/core.h> | 58 | #include <sound/core.h> |
59 | #include <sound/info.h> | 59 | #include <sound/info.h> |
60 | #include <sound/control.h> | 60 | #include <sound/control.h> |
61 | #include <sound/tlv.h> | ||
61 | #include <sound/pcm.h> | 62 | #include <sound/pcm.h> |
62 | #include <sound/pcm_params.h> | 63 | #include <sound/pcm_params.h> |
63 | #include <sound/asoundef.h> | 64 | #include <sound/asoundef.h> |
diff --git a/sound/pci/echoaudio/echo3g_dsp.c b/sound/pci/echoaudio/echo3g_dsp.c index d26a1d1f3ed1..48eb7c599111 100644 --- a/sound/pci/echoaudio/echo3g_dsp.c +++ b/sound/pci/echoaudio/echo3g_dsp.c | |||
@@ -39,7 +39,7 @@ static int set_phantom_power(struct echoaudio *chip, char on); | |||
39 | static int write_control_reg(struct echoaudio *chip, u32 ctl, u32 frq, | 39 | static int write_control_reg(struct echoaudio *chip, u32 ctl, u32 frq, |
40 | char force); | 40 | char force); |
41 | 41 | ||
42 | #include <linux/irq.h> | 42 | #include <linux/interrupt.h> |
43 | 43 | ||
44 | static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | 44 | static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) |
45 | { | 45 | { |
diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c index 047e0b5bf15d..6a428b81dba6 100644 --- a/sound/pci/echoaudio/echoaudio.c +++ b/sound/pci/echoaudio/echoaudio.c | |||
@@ -34,6 +34,7 @@ module_param_array(enable, bool, NULL, 0444); | |||
34 | MODULE_PARM_DESC(enable, "Enable " ECHOCARD_NAME " soundcard."); | 34 | MODULE_PARM_DESC(enable, "Enable " ECHOCARD_NAME " soundcard."); |
35 | 35 | ||
36 | static unsigned int channels_list[10] = {1, 2, 4, 6, 8, 10, 12, 14, 16, 999999}; | 36 | static unsigned int channels_list[10] = {1, 2, 4, 6, 8, 10, 12, 14, 16, 999999}; |
37 | static const DECLARE_TLV_DB_SCALE(db_scale_output_gain, -12800, 100, 1); | ||
37 | 38 | ||
38 | static int get_firmware(const struct firmware **fw_entry, | 39 | static int get_firmware(const struct firmware **fw_entry, |
39 | const struct firmware *frm, struct echoaudio *chip) | 40 | const struct firmware *frm, struct echoaudio *chip) |
@@ -1011,17 +1012,21 @@ static int snd_echo_output_gain_put(struct snd_kcontrol *kcontrol, | |||
1011 | static struct snd_kcontrol_new snd_echo_line_output_gain __devinitdata = { | 1012 | static struct snd_kcontrol_new snd_echo_line_output_gain __devinitdata = { |
1012 | .name = "Line Playback Volume", | 1013 | .name = "Line Playback Volume", |
1013 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1014 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1015 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, | ||
1014 | .info = snd_echo_output_gain_info, | 1016 | .info = snd_echo_output_gain_info, |
1015 | .get = snd_echo_output_gain_get, | 1017 | .get = snd_echo_output_gain_get, |
1016 | .put = snd_echo_output_gain_put, | 1018 | .put = snd_echo_output_gain_put, |
1019 | .tlv = {.p = db_scale_output_gain}, | ||
1017 | }; | 1020 | }; |
1018 | #else | 1021 | #else |
1019 | static struct snd_kcontrol_new snd_echo_pcm_output_gain __devinitdata = { | 1022 | static struct snd_kcontrol_new snd_echo_pcm_output_gain __devinitdata = { |
1020 | .name = "PCM Playback Volume", | 1023 | .name = "PCM Playback Volume", |
1021 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1024 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1025 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, | ||
1022 | .info = snd_echo_output_gain_info, | 1026 | .info = snd_echo_output_gain_info, |
1023 | .get = snd_echo_output_gain_get, | 1027 | .get = snd_echo_output_gain_get, |
1024 | .put = snd_echo_output_gain_put, | 1028 | .put = snd_echo_output_gain_put, |
1029 | .tlv = {.p = db_scale_output_gain}, | ||
1025 | }; | 1030 | }; |
1026 | #endif | 1031 | #endif |
1027 | 1032 | ||
@@ -1080,12 +1085,16 @@ static int snd_echo_input_gain_put(struct snd_kcontrol *kcontrol, | |||
1080 | return changed; | 1085 | return changed; |
1081 | } | 1086 | } |
1082 | 1087 | ||
1088 | static const DECLARE_TLV_DB_SCALE(db_scale_input_gain, -2500, 50, 0); | ||
1089 | |||
1083 | static struct snd_kcontrol_new snd_echo_line_input_gain __devinitdata = { | 1090 | static struct snd_kcontrol_new snd_echo_line_input_gain __devinitdata = { |
1084 | .name = "Line Capture Volume", | 1091 | .name = "Line Capture Volume", |
1085 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1092 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1093 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, | ||
1086 | .info = snd_echo_input_gain_info, | 1094 | .info = snd_echo_input_gain_info, |
1087 | .get = snd_echo_input_gain_get, | 1095 | .get = snd_echo_input_gain_get, |
1088 | .put = snd_echo_input_gain_put, | 1096 | .put = snd_echo_input_gain_put, |
1097 | .tlv = {.p = db_scale_input_gain}, | ||
1089 | }; | 1098 | }; |
1090 | 1099 | ||
1091 | #endif /* ECHOCARD_HAS_INPUT_GAIN */ | 1100 | #endif /* ECHOCARD_HAS_INPUT_GAIN */ |
@@ -1277,9 +1286,11 @@ static int snd_echo_mixer_put(struct snd_kcontrol *kcontrol, | |||
1277 | static struct snd_kcontrol_new snd_echo_monitor_mixer __devinitdata = { | 1286 | static struct snd_kcontrol_new snd_echo_monitor_mixer __devinitdata = { |
1278 | .name = "Monitor Mixer Volume", | 1287 | .name = "Monitor Mixer Volume", |
1279 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1288 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1289 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, | ||
1280 | .info = snd_echo_mixer_info, | 1290 | .info = snd_echo_mixer_info, |
1281 | .get = snd_echo_mixer_get, | 1291 | .get = snd_echo_mixer_get, |
1282 | .put = snd_echo_mixer_put, | 1292 | .put = snd_echo_mixer_put, |
1293 | .tlv = {.p = db_scale_output_gain}, | ||
1283 | }; | 1294 | }; |
1284 | 1295 | ||
1285 | #endif /* ECHOCARD_HAS_MONITOR */ | 1296 | #endif /* ECHOCARD_HAS_MONITOR */ |
@@ -1343,9 +1354,11 @@ static int snd_echo_vmixer_put(struct snd_kcontrol *kcontrol, | |||
1343 | static struct snd_kcontrol_new snd_echo_vmixer __devinitdata = { | 1354 | static struct snd_kcontrol_new snd_echo_vmixer __devinitdata = { |
1344 | .name = "VMixer Volume", | 1355 | .name = "VMixer Volume", |
1345 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1356 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1357 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, | ||
1346 | .info = snd_echo_vmixer_info, | 1358 | .info = snd_echo_vmixer_info, |
1347 | .get = snd_echo_vmixer_get, | 1359 | .get = snd_echo_vmixer_get, |
1348 | .put = snd_echo_vmixer_put, | 1360 | .put = snd_echo_vmixer_put, |
1361 | .tlv = {.p = db_scale_output_gain}, | ||
1349 | }; | 1362 | }; |
1350 | 1363 | ||
1351 | #endif /* ECHOCARD_HAS_VMIXER */ | 1364 | #endif /* ECHOCARD_HAS_VMIXER */ |
@@ -1753,9 +1766,12 @@ static int snd_echo_vumeters_get(struct snd_kcontrol *kcontrol, | |||
1753 | static struct snd_kcontrol_new snd_echo_vumeters __devinitdata = { | 1766 | static struct snd_kcontrol_new snd_echo_vumeters __devinitdata = { |
1754 | .name = "VU-meters", | 1767 | .name = "VU-meters", |
1755 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1768 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1756 | .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, | 1769 | .access = SNDRV_CTL_ELEM_ACCESS_READ | |
1770 | SNDRV_CTL_ELEM_ACCESS_VOLATILE | | ||
1771 | SNDRV_CTL_ELEM_ACCESS_TLV_READ, | ||
1757 | .info = snd_echo_vumeters_info, | 1772 | .info = snd_echo_vumeters_info, |
1758 | .get = snd_echo_vumeters_get, | 1773 | .get = snd_echo_vumeters_get, |
1774 | .tlv = {.p = db_scale_output_gain}, | ||
1759 | }; | 1775 | }; |
1760 | 1776 | ||
1761 | 1777 | ||
diff --git a/sound/pci/echoaudio/gina20.c b/sound/pci/echoaudio/gina20.c index 29d6d12f80ca..af4d32026e4a 100644 --- a/sound/pci/echoaudio/gina20.c +++ b/sound/pci/echoaudio/gina20.c | |||
@@ -51,6 +51,7 @@ | |||
51 | #include <sound/core.h> | 51 | #include <sound/core.h> |
52 | #include <sound/info.h> | 52 | #include <sound/info.h> |
53 | #include <sound/control.h> | 53 | #include <sound/control.h> |
54 | #include <sound/tlv.h> | ||
54 | #include <sound/pcm.h> | 55 | #include <sound/pcm.h> |
55 | #include <sound/pcm_params.h> | 56 | #include <sound/pcm_params.h> |
56 | #include <sound/asoundef.h> | 57 | #include <sound/asoundef.h> |
diff --git a/sound/pci/echoaudio/gina24.c b/sound/pci/echoaudio/gina24.c index e464d720d0bd..9ff454a947ed 100644 --- a/sound/pci/echoaudio/gina24.c +++ b/sound/pci/echoaudio/gina24.c | |||
@@ -57,6 +57,7 @@ | |||
57 | #include <sound/core.h> | 57 | #include <sound/core.h> |
58 | #include <sound/info.h> | 58 | #include <sound/info.h> |
59 | #include <sound/control.h> | 59 | #include <sound/control.h> |
60 | #include <sound/tlv.h> | ||
60 | #include <sound/pcm.h> | 61 | #include <sound/pcm.h> |
61 | #include <sound/pcm_params.h> | 62 | #include <sound/pcm_params.h> |
62 | #include <sound/asoundef.h> | 63 | #include <sound/asoundef.h> |
diff --git a/sound/pci/echoaudio/indigo.c b/sound/pci/echoaudio/indigo.c index bfd2467099ac..37eb726fd03d 100644 --- a/sound/pci/echoaudio/indigo.c +++ b/sound/pci/echoaudio/indigo.c | |||
@@ -49,6 +49,7 @@ | |||
49 | #include <sound/core.h> | 49 | #include <sound/core.h> |
50 | #include <sound/info.h> | 50 | #include <sound/info.h> |
51 | #include <sound/control.h> | 51 | #include <sound/control.h> |
52 | #include <sound/tlv.h> | ||
52 | #include <sound/pcm.h> | 53 | #include <sound/pcm.h> |
53 | #include <sound/pcm_params.h> | 54 | #include <sound/pcm_params.h> |
54 | #include <sound/asoundef.h> | 55 | #include <sound/asoundef.h> |
diff --git a/sound/pci/echoaudio/indigodj.c b/sound/pci/echoaudio/indigodj.c index 8ed7ff1fd875..dc8b91824181 100644 --- a/sound/pci/echoaudio/indigodj.c +++ b/sound/pci/echoaudio/indigodj.c | |||
@@ -49,6 +49,7 @@ | |||
49 | #include <sound/core.h> | 49 | #include <sound/core.h> |
50 | #include <sound/info.h> | 50 | #include <sound/info.h> |
51 | #include <sound/control.h> | 51 | #include <sound/control.h> |
52 | #include <sound/tlv.h> | ||
52 | #include <sound/pcm.h> | 53 | #include <sound/pcm.h> |
53 | #include <sound/pcm_params.h> | 54 | #include <sound/pcm_params.h> |
54 | #include <sound/asoundef.h> | 55 | #include <sound/asoundef.h> |
diff --git a/sound/pci/echoaudio/indigoio.c b/sound/pci/echoaudio/indigoio.c index a8788e959171..eadf3263453a 100644 --- a/sound/pci/echoaudio/indigoio.c +++ b/sound/pci/echoaudio/indigoio.c | |||
@@ -50,6 +50,7 @@ | |||
50 | #include <sound/core.h> | 50 | #include <sound/core.h> |
51 | #include <sound/info.h> | 51 | #include <sound/info.h> |
52 | #include <sound/control.h> | 52 | #include <sound/control.h> |
53 | #include <sound/tlv.h> | ||
53 | #include <sound/pcm.h> | 54 | #include <sound/pcm.h> |
54 | #include <sound/pcm_params.h> | 55 | #include <sound/pcm_params.h> |
55 | #include <sound/asoundef.h> | 56 | #include <sound/asoundef.h> |
diff --git a/sound/pci/echoaudio/layla20.c b/sound/pci/echoaudio/layla20.c index e503d74b3ba9..6cede497579e 100644 --- a/sound/pci/echoaudio/layla20.c +++ b/sound/pci/echoaudio/layla20.c | |||
@@ -56,6 +56,7 @@ | |||
56 | #include <sound/core.h> | 56 | #include <sound/core.h> |
57 | #include <sound/info.h> | 57 | #include <sound/info.h> |
58 | #include <sound/control.h> | 58 | #include <sound/control.h> |
59 | #include <sound/tlv.h> | ||
59 | #include <sound/pcm.h> | 60 | #include <sound/pcm.h> |
60 | #include <sound/pcm_params.h> | 61 | #include <sound/pcm_params.h> |
61 | #include <sound/asoundef.h> | 62 | #include <sound/asoundef.h> |
diff --git a/sound/pci/echoaudio/layla24.c b/sound/pci/echoaudio/layla24.c index d4581fdc841c..44f735426aa0 100644 --- a/sound/pci/echoaudio/layla24.c +++ b/sound/pci/echoaudio/layla24.c | |||
@@ -58,6 +58,7 @@ | |||
58 | #include <sound/core.h> | 58 | #include <sound/core.h> |
59 | #include <sound/info.h> | 59 | #include <sound/info.h> |
60 | #include <sound/control.h> | 60 | #include <sound/control.h> |
61 | #include <sound/tlv.h> | ||
61 | #include <sound/pcm.h> | 62 | #include <sound/pcm.h> |
62 | #include <sound/pcm_params.h> | 63 | #include <sound/pcm_params.h> |
63 | #include <sound/asoundef.h> | 64 | #include <sound/asoundef.h> |
diff --git a/sound/pci/echoaudio/mia.c b/sound/pci/echoaudio/mia.c index be40c64263d2..dc172d03ac3f 100644 --- a/sound/pci/echoaudio/mia.c +++ b/sound/pci/echoaudio/mia.c | |||
@@ -56,6 +56,7 @@ | |||
56 | #include <sound/core.h> | 56 | #include <sound/core.h> |
57 | #include <sound/info.h> | 57 | #include <sound/info.h> |
58 | #include <sound/control.h> | 58 | #include <sound/control.h> |
59 | #include <sound/tlv.h> | ||
59 | #include <sound/pcm.h> | 60 | #include <sound/pcm.h> |
60 | #include <sound/pcm_params.h> | 61 | #include <sound/pcm_params.h> |
61 | #include <sound/asoundef.h> | 62 | #include <sound/asoundef.h> |
diff --git a/sound/pci/echoaudio/mona.c b/sound/pci/echoaudio/mona.c index 5dc512add372..c856ed50dd9a 100644 --- a/sound/pci/echoaudio/mona.c +++ b/sound/pci/echoaudio/mona.c | |||
@@ -55,6 +55,7 @@ | |||
55 | #include <sound/core.h> | 55 | #include <sound/core.h> |
56 | #include <sound/info.h> | 56 | #include <sound/info.h> |
57 | #include <sound/control.h> | 57 | #include <sound/control.h> |
58 | #include <sound/tlv.h> | ||
58 | #include <sound/pcm.h> | 59 | #include <sound/pcm.h> |
59 | #include <sound/pcm_params.h> | 60 | #include <sound/pcm_params.h> |
60 | #include <sound/asoundef.h> | 61 | #include <sound/asoundef.h> |
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index 972ec40d8166..80aa585eade4 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c | |||
@@ -3,8 +3,10 @@ | |||
3 | * Creative Labs, Inc. | 3 | * Creative Labs, Inc. |
4 | * Routines for control of EMU10K1 chips | 4 | * Routines for control of EMU10K1 chips |
5 | * | 5 | * |
6 | * Copyright (c) by James Courtier-Dutton <James@superbug.demon.co.uk> | 6 | * Copyright (c) by James Courtier-Dutton <James@superbug.co.uk> |
7 | * Added support for Audigy 2 Value. | 7 | * Added support for Audigy 2 Value. |
8 | * Added EMU 1010 support. | ||
9 | * General bug fixes and enhancements. | ||
8 | * | 10 | * |
9 | * | 11 | * |
10 | * BUGS: | 12 | * BUGS: |
@@ -41,8 +43,10 @@ | |||
41 | 43 | ||
42 | #include <sound/core.h> | 44 | #include <sound/core.h> |
43 | #include <sound/emu10k1.h> | 45 | #include <sound/emu10k1.h> |
46 | #include <linux/firmware.h> | ||
44 | #include "p16v.h" | 47 | #include "p16v.h" |
45 | #include "tina2.h" | 48 | #include "tina2.h" |
49 | #include "p17v.h" | ||
46 | 50 | ||
47 | 51 | ||
48 | /************************************************************************* | 52 | /************************************************************************* |
@@ -117,11 +121,28 @@ static unsigned int spi_dac_init[] = { | |||
117 | 0x0622, | 121 | 0x0622, |
118 | 0x1400, | 122 | 0x1400, |
119 | }; | 123 | }; |
124 | |||
125 | static unsigned int i2c_adc_init[][2] = { | ||
126 | { 0x17, 0x00 }, /* Reset */ | ||
127 | { 0x07, 0x00 }, /* Timeout */ | ||
128 | { 0x0b, 0x22 }, /* Interface control */ | ||
129 | { 0x0c, 0x22 }, /* Master mode control */ | ||
130 | { 0x0d, 0x08 }, /* Powerdown control */ | ||
131 | { 0x0e, 0xcf }, /* Attenuation Left 0x01 = -103dB, 0xff = 24dB */ | ||
132 | { 0x0f, 0xcf }, /* Attenuation Right 0.5dB steps */ | ||
133 | { 0x10, 0x7b }, /* ALC Control 1 */ | ||
134 | { 0x11, 0x00 }, /* ALC Control 2 */ | ||
135 | { 0x12, 0x32 }, /* ALC Control 3 */ | ||
136 | { 0x13, 0x00 }, /* Noise gate control */ | ||
137 | { 0x14, 0xa6 }, /* Limiter control */ | ||
138 | { 0x15, ADC_MUX_2 }, /* ADC Mixer control. Mic for Audigy 2 ZS Notebook */ | ||
139 | }; | ||
120 | 140 | ||
121 | static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) | 141 | static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) |
122 | { | 142 | { |
123 | unsigned int silent_page; | 143 | unsigned int silent_page; |
124 | int ch; | 144 | int ch; |
145 | u32 tmp; | ||
125 | 146 | ||
126 | /* disable audio and lock cache */ | 147 | /* disable audio and lock cache */ |
127 | outl(HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK | HCFG_MUTEBUTTONENABLE, | 148 | outl(HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK | HCFG_MUTEBUTTONENABLE, |
@@ -160,8 +181,6 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) | |||
160 | 181 | ||
161 | if (emu->card_capabilities->ca0151_chip) { /* audigy2 */ | 182 | if (emu->card_capabilities->ca0151_chip) { /* audigy2 */ |
162 | /* Hacks for Alice3 to work independent of haP16V driver */ | 183 | /* Hacks for Alice3 to work independent of haP16V driver */ |
163 | u32 tmp; | ||
164 | |||
165 | //Setup SRCMulti_I2S SamplingRate | 184 | //Setup SRCMulti_I2S SamplingRate |
166 | tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); | 185 | tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); |
167 | tmp &= 0xfffff1ff; | 186 | tmp &= 0xfffff1ff; |
@@ -181,8 +200,6 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) | |||
181 | } | 200 | } |
182 | if (emu->card_capabilities->ca0108_chip) { /* audigy2 Value */ | 201 | if (emu->card_capabilities->ca0108_chip) { /* audigy2 Value */ |
183 | /* Hacks for Alice3 to work independent of haP16V driver */ | 202 | /* Hacks for Alice3 to work independent of haP16V driver */ |
184 | u32 tmp; | ||
185 | |||
186 | snd_printk(KERN_INFO "Audigy2 value: Special config.\n"); | 203 | snd_printk(KERN_INFO "Audigy2 value: Special config.\n"); |
187 | //Setup SRCMulti_I2S SamplingRate | 204 | //Setup SRCMulti_I2S SamplingRate |
188 | tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); | 205 | tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); |
@@ -211,7 +228,7 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) | |||
211 | int size, n; | 228 | int size, n; |
212 | 229 | ||
213 | size = ARRAY_SIZE(spi_dac_init); | 230 | size = ARRAY_SIZE(spi_dac_init); |
214 | for (n=0; n < size; n++) | 231 | for (n = 0; n < size; n++) |
215 | snd_emu10k1_spi_write(emu, spi_dac_init[n]); | 232 | snd_emu10k1_spi_write(emu, spi_dac_init[n]); |
216 | 233 | ||
217 | snd_emu10k1_ptr20_write(emu, 0x60, 0, 0x10); | 234 | snd_emu10k1_ptr20_write(emu, 0x60, 0, 0x10); |
@@ -228,6 +245,23 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) | |||
228 | outl(0x76, emu->port + A_IOCFG); /* Windows uses 0x3f76 */ | 245 | outl(0x76, emu->port + A_IOCFG); /* Windows uses 0x3f76 */ |
229 | 246 | ||
230 | } | 247 | } |
248 | if (emu->card_capabilities->i2c_adc) { /* Audigy 2 ZS Notebook with ADC Wolfson WM8775 */ | ||
249 | int size, n; | ||
250 | |||
251 | snd_emu10k1_ptr20_write(emu, P17V_I2S_SRC_SEL, 0, 0x2020205f); | ||
252 | tmp = inl(emu->port + A_IOCFG); | ||
253 | outl(tmp | 0x4, emu->port + A_IOCFG); /* Set bit 2 for mic input */ | ||
254 | tmp = inl(emu->port + A_IOCFG); | ||
255 | size = ARRAY_SIZE(i2c_adc_init); | ||
256 | for (n = 0; n < size; n++) | ||
257 | snd_emu10k1_i2c_write(emu, i2c_adc_init[n][0], i2c_adc_init[n][1]); | ||
258 | for (n=0; n < 4; n++) { | ||
259 | emu->i2c_capture_volume[n][0]= 0xcf; | ||
260 | emu->i2c_capture_volume[n][1]= 0xcf; | ||
261 | } | ||
262 | |||
263 | } | ||
264 | |||
231 | 265 | ||
232 | snd_emu10k1_ptr_write(emu, PTB, 0, emu->ptb_pages.addr); | 266 | snd_emu10k1_ptr_write(emu, PTB, 0, emu->ptb_pages.addr); |
233 | snd_emu10k1_ptr_write(emu, TCB, 0, 0); /* taken from original driver */ | 267 | snd_emu10k1_ptr_write(emu, TCB, 0, 0); /* taken from original driver */ |
@@ -239,6 +273,10 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) | |||
239 | snd_emu10k1_ptr_write(emu, MAPB, ch, silent_page); | 273 | snd_emu10k1_ptr_write(emu, MAPB, ch, silent_page); |
240 | } | 274 | } |
241 | 275 | ||
276 | if (emu->card_capabilities->emu1010) { | ||
277 | outl(HCFG_AUTOMUTE_ASYNC | | ||
278 | HCFG_EMU32_SLAVE | | ||
279 | HCFG_AUDIOENABLE, emu->port + HCFG); | ||
242 | /* | 280 | /* |
243 | * Hokay, setup HCFG | 281 | * Hokay, setup HCFG |
244 | * Mute Disable Audio = 0 | 282 | * Mute Disable Audio = 0 |
@@ -246,7 +284,7 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) | |||
246 | * Lock Sound Memory = 0 | 284 | * Lock Sound Memory = 0 |
247 | * Auto Mute = 1 | 285 | * Auto Mute = 1 |
248 | */ | 286 | */ |
249 | if (emu->audigy) { | 287 | } else if (emu->audigy) { |
250 | if (emu->revision == 4) /* audigy2 */ | 288 | if (emu->revision == 4) /* audigy2 */ |
251 | outl(HCFG_AUDIOENABLE | | 289 | outl(HCFG_AUDIOENABLE | |
252 | HCFG_AC3ENABLE_CDSPDIF | | 290 | HCFG_AC3ENABLE_CDSPDIF | |
@@ -265,8 +303,10 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) | |||
265 | outl(HCFG_LOCKTANKCACHE_MASK | HCFG_AUTOMUTE | HCFG_JOYENABLE, emu->port + HCFG); | 303 | outl(HCFG_LOCKTANKCACHE_MASK | HCFG_AUTOMUTE | HCFG_JOYENABLE, emu->port + HCFG); |
266 | 304 | ||
267 | if (enable_ir) { /* enable IR for SB Live */ | 305 | if (enable_ir) { /* enable IR for SB Live */ |
268 | if ( emu->card_capabilities->emu1212m) { | 306 | if (emu->card_capabilities->emu1010) { |
269 | ; /* Disable all access to A_IOCFG for the emu1212m */ | 307 | ; /* Disable all access to A_IOCFG for the emu1010 */ |
308 | } else if (emu->card_capabilities->i2c_adc) { | ||
309 | ; /* Disable A_IOCFG for Audigy 2 ZS Notebook */ | ||
270 | } else if (emu->audigy) { | 310 | } else if (emu->audigy) { |
271 | unsigned int reg = inl(emu->port + A_IOCFG); | 311 | unsigned int reg = inl(emu->port + A_IOCFG); |
272 | outl(reg | A_IOCFG_GPOUT2, emu->port + A_IOCFG); | 312 | outl(reg | A_IOCFG_GPOUT2, emu->port + A_IOCFG); |
@@ -284,8 +324,10 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) | |||
284 | } | 324 | } |
285 | } | 325 | } |
286 | 326 | ||
287 | if ( emu->card_capabilities->emu1212m) { | 327 | if (emu->card_capabilities->emu1010) { |
288 | ; /* Disable all access to A_IOCFG for the emu1212m */ | 328 | ; /* Disable all access to A_IOCFG for the emu1010 */ |
329 | } else if (emu->card_capabilities->i2c_adc) { | ||
330 | ; /* Disable A_IOCFG for Audigy 2 ZS Notebook */ | ||
289 | } else if (emu->audigy) { /* enable analog output */ | 331 | } else if (emu->audigy) { /* enable analog output */ |
290 | unsigned int reg = inl(emu->port + A_IOCFG); | 332 | unsigned int reg = inl(emu->port + A_IOCFG); |
291 | outl(reg | A_IOCFG_GPOUT0, emu->port + A_IOCFG); | 333 | outl(reg | A_IOCFG_GPOUT0, emu->port + A_IOCFG); |
@@ -302,8 +344,10 @@ static void snd_emu10k1_audio_enable(struct snd_emu10k1 *emu) | |||
302 | outl(inl(emu->port + HCFG) | HCFG_AUDIOENABLE, emu->port + HCFG); | 344 | outl(inl(emu->port + HCFG) | HCFG_AUDIOENABLE, emu->port + HCFG); |
303 | 345 | ||
304 | /* Enable analog/digital outs on audigy */ | 346 | /* Enable analog/digital outs on audigy */ |
305 | if ( emu->card_capabilities->emu1212m) { | 347 | if (emu->card_capabilities->emu1010) { |
306 | ; /* Disable all access to A_IOCFG for the emu1212m */ | 348 | ; /* Disable all access to A_IOCFG for the emu1010 */ |
349 | } else if (emu->card_capabilities->i2c_adc) { | ||
350 | ; /* Disable A_IOCFG for Audigy 2 ZS Notebook */ | ||
307 | } else if (emu->audigy) { | 351 | } else if (emu->audigy) { |
308 | outl(inl(emu->port + A_IOCFG) & ~0x44, emu->port + A_IOCFG); | 352 | outl(inl(emu->port + A_IOCFG) & ~0x44, emu->port + A_IOCFG); |
309 | 353 | ||
@@ -596,133 +640,423 @@ static int snd_emu10k1_cardbus_init(struct snd_emu10k1 * emu) | |||
596 | return 0; | 640 | return 0; |
597 | } | 641 | } |
598 | 642 | ||
599 | static int snd_emu1212m_fpga_write(struct snd_emu10k1 * emu, int reg, int value) | 643 | static int snd_emu1010_load_firmware(struct snd_emu10k1 * emu, const char * filename) |
600 | { | 644 | { |
601 | if (reg<0 || reg>0x3f) | 645 | int err; |
602 | return 1; | 646 | int n, i; |
603 | reg+=0x40; /* 0x40 upwards are registers. */ | 647 | int reg; |
604 | if (value<0 || value>0x3f) /* 0 to 0x3f are values */ | 648 | int value; |
605 | return 1; | 649 | const struct firmware *fw_entry; |
606 | outl(reg, emu->port + A_IOCFG); | 650 | |
607 | outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */ | 651 | if ((err = request_firmware(&fw_entry, filename, &emu->pci->dev)) != 0) { |
608 | outl(value, emu->port + A_IOCFG); | 652 | snd_printk(KERN_ERR "firmware: %s not found. Err=%d\n",filename, err); |
609 | outl(value | 0x80 , emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */ | 653 | return err; |
610 | 654 | } | |
611 | return 0; | 655 | snd_printk(KERN_INFO "firmware size=0x%zx\n", fw_entry->size); |
612 | } | 656 | if (fw_entry->size != 0x133a4) { |
613 | 657 | snd_printk(KERN_ERR "firmware: %s wrong size.\n",filename); | |
614 | static int snd_emu1212m_fpga_read(struct snd_emu10k1 * emu, int reg, int *value) | 658 | return -EINVAL; |
615 | { | 659 | } |
616 | if (reg<0 || reg>0x3f) | ||
617 | return 1; | ||
618 | reg+=0x40; /* 0x40 upwards are registers. */ | ||
619 | outl(reg, emu->port + A_IOCFG); | ||
620 | outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */ | ||
621 | *value = inl(emu->port + A_IOCFG); | ||
622 | |||
623 | return 0; | ||
624 | } | ||
625 | 660 | ||
626 | static int snd_emu1212m_fpga_netlist_write(struct snd_emu10k1 * emu, int reg, int value) | 661 | /* The FPGA is a Xilinx Spartan IIE XC2S50E */ |
627 | { | 662 | /* GPIO7 -> FPGA PGMN |
628 | snd_emu1212m_fpga_write(emu, 0x00, ((reg >> 8) & 0x3f) ); | 663 | * GPIO6 -> FPGA CCLK |
629 | snd_emu1212m_fpga_write(emu, 0x01, (reg & 0x3f) ); | 664 | * GPIO5 -> FPGA DIN |
630 | snd_emu1212m_fpga_write(emu, 0x02, ((value >> 8) & 0x3f) ); | 665 | * FPGA CONFIG OFF -> FPGA PGMN |
631 | snd_emu1212m_fpga_write(emu, 0x03, (value & 0x3f) ); | 666 | */ |
667 | outl(0x00, emu->port + A_IOCFG); /* Set PGMN low for 1uS. */ | ||
668 | udelay(1); | ||
669 | outl(0x80, emu->port + A_IOCFG); /* Leave bit 7 set during netlist setup. */ | ||
670 | udelay(100); /* Allow FPGA memory to clean */ | ||
671 | for(n = 0; n < fw_entry->size; n++) { | ||
672 | value=fw_entry->data[n]; | ||
673 | for(i = 0; i < 8; i++) { | ||
674 | reg = 0x80; | ||
675 | if (value & 0x1) | ||
676 | reg = reg | 0x20; | ||
677 | value = value >> 1; | ||
678 | outl(reg, emu->port + A_IOCFG); | ||
679 | outl(reg | 0x40, emu->port + A_IOCFG); | ||
680 | } | ||
681 | } | ||
682 | /* After programming, set GPIO bit 4 high again. */ | ||
683 | outl(0x10, emu->port + A_IOCFG); | ||
684 | |||
632 | 685 | ||
686 | release_firmware(fw_entry); | ||
633 | return 0; | 687 | return 0; |
634 | } | 688 | } |
635 | 689 | ||
636 | static int snd_emu10k1_emu1212m_init(struct snd_emu10k1 * emu) | 690 | static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu) |
637 | { | 691 | { |
638 | unsigned int i; | 692 | unsigned int i; |
639 | int tmp; | 693 | int tmp,tmp2; |
640 | 694 | int reg; | |
641 | snd_printk(KERN_ERR "emu1212m: Special config.\n"); | 695 | int err; |
696 | const char *hana_filename = "emu/hana.fw"; | ||
697 | const char *dock_filename = "emu/audio_dock.fw"; | ||
698 | |||
699 | snd_printk(KERN_INFO "emu1010: Special config.\n"); | ||
700 | /* AC97 2.1, Any 16Meg of 4Gig address, Auto-Mute, EMU32 Slave, | ||
701 | * Lock Sound Memory Cache, Lock Tank Memory Cache, | ||
702 | * Mute all codecs. | ||
703 | */ | ||
642 | outl(0x0005a00c, emu->port + HCFG); | 704 | outl(0x0005a00c, emu->port + HCFG); |
643 | outl(0x0005a004, emu->port + HCFG); | 705 | /* AC97 2.1, Any 16Meg of 4Gig address, Auto-Mute, EMU32 Slave, |
706 | * Lock Tank Memory Cache, | ||
707 | * Mute all codecs. | ||
708 | */ | ||
709 | outl(0x0005a004, emu->port + HCFG); | ||
710 | /* AC97 2.1, Any 16Meg of 4Gig address, Auto-Mute, EMU32 Slave, | ||
711 | * Mute all codecs. | ||
712 | */ | ||
644 | outl(0x0005a000, emu->port + HCFG); | 713 | outl(0x0005a000, emu->port + HCFG); |
714 | /* AC97 2.1, Any 16Meg of 4Gig address, Auto-Mute, EMU32 Slave, | ||
715 | * Mute all codecs. | ||
716 | */ | ||
645 | outl(0x0005a000, emu->port + HCFG); | 717 | outl(0x0005a000, emu->port + HCFG); |
646 | 718 | ||
647 | snd_emu1212m_fpga_read(emu, 0x22, &tmp ); | 719 | /* Disable 48Volt power to Audio Dock */ |
648 | snd_emu1212m_fpga_read(emu, 0x23, &tmp ); | 720 | snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0 ); |
649 | snd_emu1212m_fpga_read(emu, 0x24, &tmp ); | 721 | |
650 | snd_emu1212m_fpga_write(emu, 0x04, 0x01 ); | 722 | /* ID, should read & 0x7f = 0x55. (Bit 7 is the IRQ bit) */ |
651 | snd_emu1212m_fpga_read(emu, 0x0b, &tmp ); | 723 | snd_emu1010_fpga_read(emu, EMU_HANA_ID, ® ); |
652 | snd_emu1212m_fpga_write(emu, 0x0b, 0x01 ); | 724 | snd_printdd("reg1=0x%x\n",reg); |
653 | snd_emu1212m_fpga_read(emu, 0x10, &tmp ); | 725 | if (reg == 0x55) { |
654 | snd_emu1212m_fpga_write(emu, 0x10, 0x00 ); | 726 | /* FPGA netlist already present so clear it */ |
655 | snd_emu1212m_fpga_read(emu, 0x11, &tmp ); | 727 | /* Return to programming mode */ |
656 | snd_emu1212m_fpga_write(emu, 0x11, 0x30 ); | 728 | |
657 | snd_emu1212m_fpga_read(emu, 0x13, &tmp ); | 729 | snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0x02 ); |
658 | snd_emu1212m_fpga_write(emu, 0x13, 0x0f ); | ||
659 | snd_emu1212m_fpga_read(emu, 0x11, &tmp ); | ||
660 | snd_emu1212m_fpga_write(emu, 0x11, 0x30 ); | ||
661 | snd_emu1212m_fpga_read(emu, 0x0a, &tmp ); | ||
662 | snd_emu1212m_fpga_write(emu, 0x0a, 0x10 ); | ||
663 | snd_emu1212m_fpga_write(emu, 0x0c, 0x19 ); | ||
664 | snd_emu1212m_fpga_write(emu, 0x12, 0x0c ); | ||
665 | snd_emu1212m_fpga_write(emu, 0x09, 0x0f ); | ||
666 | snd_emu1212m_fpga_write(emu, 0x06, 0x00 ); | ||
667 | snd_emu1212m_fpga_write(emu, 0x05, 0x00 ); | ||
668 | snd_emu1212m_fpga_write(emu, 0x0e, 0x12 ); | ||
669 | snd_emu1212m_fpga_netlist_write(emu, 0x0000, 0x0200); | ||
670 | snd_emu1212m_fpga_netlist_write(emu, 0x0001, 0x0201); | ||
671 | snd_emu1212m_fpga_netlist_write(emu, 0x0002, 0x0500); | ||
672 | snd_emu1212m_fpga_netlist_write(emu, 0x0003, 0x0501); | ||
673 | snd_emu1212m_fpga_netlist_write(emu, 0x0004, 0x0400); | ||
674 | snd_emu1212m_fpga_netlist_write(emu, 0x0005, 0x0401); | ||
675 | snd_emu1212m_fpga_netlist_write(emu, 0x0006, 0x0402); | ||
676 | snd_emu1212m_fpga_netlist_write(emu, 0x0007, 0x0403); | ||
677 | snd_emu1212m_fpga_netlist_write(emu, 0x0008, 0x0404); | ||
678 | snd_emu1212m_fpga_netlist_write(emu, 0x0009, 0x0405); | ||
679 | snd_emu1212m_fpga_netlist_write(emu, 0x000a, 0x0406); | ||
680 | snd_emu1212m_fpga_netlist_write(emu, 0x000b, 0x0407); | ||
681 | snd_emu1212m_fpga_netlist_write(emu, 0x000c, 0x0100); | ||
682 | snd_emu1212m_fpga_netlist_write(emu, 0x000d, 0x0104); | ||
683 | snd_emu1212m_fpga_netlist_write(emu, 0x000e, 0x0200); | ||
684 | snd_emu1212m_fpga_netlist_write(emu, 0x000f, 0x0201); | ||
685 | for (i=0;i < 0x20;i++) { | ||
686 | snd_emu1212m_fpga_netlist_write(emu, 0x0100+i, 0x0000); | ||
687 | } | 730 | } |
688 | for (i=0;i < 4;i++) { | 731 | snd_emu1010_fpga_read(emu, EMU_HANA_ID, ® ); |
689 | snd_emu1212m_fpga_netlist_write(emu, 0x0200+i, 0x0000); | 732 | snd_printdd("reg2=0x%x\n",reg); |
733 | if (reg == 0x55) { | ||
734 | /* FPGA failed to return to programming mode */ | ||
735 | return -ENODEV; | ||
690 | } | 736 | } |
691 | for (i=0;i < 7;i++) { | 737 | snd_printk(KERN_INFO "emu1010: EMU_HANA_ID=0x%x\n",reg); |
692 | snd_emu1212m_fpga_netlist_write(emu, 0x0300+i, 0x0000); | 738 | if ((err = snd_emu1010_load_firmware(emu, hana_filename)) != 0) { |
739 | snd_printk(KERN_INFO "emu1010: Loading Hana Firmware file %s failed\n", hana_filename); | ||
740 | return err; | ||
693 | } | 741 | } |
694 | for (i=0;i < 7;i++) { | 742 | |
695 | snd_emu1212m_fpga_netlist_write(emu, 0x0400+i, 0x0000); | 743 | /* ID, should read & 0x7f = 0x55 when FPGA programmed. */ |
744 | snd_emu1010_fpga_read(emu, EMU_HANA_ID, ® ); | ||
745 | if (reg != 0x55) { | ||
746 | /* FPGA failed to be programmed */ | ||
747 | snd_printk(KERN_INFO "emu1010: Loading Hana Firmware file failed, reg=0x%x\n", reg); | ||
748 | return -ENODEV; | ||
696 | } | 749 | } |
697 | snd_emu1212m_fpga_netlist_write(emu, 0x0500, 0x0108); | ||
698 | snd_emu1212m_fpga_netlist_write(emu, 0x0501, 0x010c); | ||
699 | snd_emu1212m_fpga_netlist_write(emu, 0x0600, 0x0110); | ||
700 | snd_emu1212m_fpga_netlist_write(emu, 0x0601, 0x0114); | ||
701 | snd_emu1212m_fpga_netlist_write(emu, 0x0700, 0x0118); | ||
702 | snd_emu1212m_fpga_netlist_write(emu, 0x0701, 0x011c); | ||
703 | snd_emu1212m_fpga_write(emu, 0x07, 0x01 ); | ||
704 | 750 | ||
705 | snd_emu1212m_fpga_read(emu, 0x21, &tmp ); | 751 | snd_printk(KERN_INFO "emu1010: Hana Firmware loaded\n"); |
752 | snd_emu1010_fpga_read(emu, EMU_HANA_MAJOR_REV, &tmp ); | ||
753 | snd_emu1010_fpga_read(emu, EMU_HANA_MINOR_REV, &tmp2 ); | ||
754 | snd_printk("Hana ver:%d.%d\n",tmp ,tmp2); | ||
755 | /* Enable 48Volt power to Audio Dock */ | ||
756 | snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, EMU_HANA_DOCK_PWR_ON ); | ||
757 | |||
758 | snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ® ); | ||
759 | snd_printk(KERN_INFO "emu1010: Card options=0x%x\n",reg); | ||
760 | snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ® ); | ||
761 | snd_printk(KERN_INFO "emu1010: Card options=0x%x\n",reg); | ||
762 | snd_emu1010_fpga_read(emu, EMU_HANA_OPTICAL_TYPE, &tmp ); | ||
763 | /* ADAT input. */ | ||
764 | snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, 0x01 ); | ||
765 | snd_emu1010_fpga_read(emu, EMU_HANA_ADC_PADS, &tmp ); | ||
766 | /* Set no attenuation on Audio Dock pads. */ | ||
767 | snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, 0x00 ); | ||
768 | emu->emu1010.adc_pads = 0x00; | ||
769 | snd_emu1010_fpga_read(emu, EMU_HANA_DOCK_MISC, &tmp ); | ||
770 | /* Unmute Audio dock DACs, Headphone source DAC-4. */ | ||
771 | snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_MISC, 0x30 ); | ||
772 | snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 0x12 ); | ||
773 | snd_emu1010_fpga_read(emu, EMU_HANA_DAC_PADS, &tmp ); | ||
774 | /* DAC PADs. */ | ||
775 | snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, 0x0f ); | ||
776 | emu->emu1010.dac_pads = 0x0f; | ||
777 | snd_emu1010_fpga_read(emu, EMU_HANA_DOCK_MISC, &tmp ); | ||
778 | snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_MISC, 0x30 ); | ||
779 | snd_emu1010_fpga_read(emu, EMU_HANA_SPDIF_MODE, &tmp ); | ||
780 | /* SPDIF Format. Set Consumer mode, 24bit, copy enable */ | ||
781 | snd_emu1010_fpga_write(emu, EMU_HANA_SPDIF_MODE, 0x10 ); | ||
782 | /* MIDI routing */ | ||
783 | snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, 0x19 ); | ||
784 | /* Unknown. */ | ||
785 | snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, 0x0c ); | ||
786 | /* snd_emu1010_fpga_write(emu, 0x09, 0x0f ); // IRQ Enable: All on */ | ||
787 | /* IRQ Enable: All off */ | ||
788 | snd_emu1010_fpga_write(emu, EMU_HANA_IRQ_ENABLE, 0x00 ); | ||
789 | |||
790 | snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ® ); | ||
791 | snd_printk(KERN_INFO "emu1010: Card options3=0x%x\n",reg); | ||
792 | /* Default WCLK set to 48kHz. */ | ||
793 | snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, 0x00 ); | ||
794 | /* Word Clock source, Internal 48kHz x1 */ | ||
795 | snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K ); | ||
796 | //snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_4X ); | ||
797 | /* Audio Dock LEDs. */ | ||
798 | snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 0x12 ); | ||
706 | 799 | ||
707 | outl(0x0000a000, emu->port + HCFG); | 800 | #if 0 |
801 | /* For 96kHz */ | ||
802 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
803 | EMU_DST_ALICE2_EMU32_0, EMU_SRC_HAMOA_ADC_LEFT1); | ||
804 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
805 | EMU_DST_ALICE2_EMU32_1, EMU_SRC_HAMOA_ADC_RIGHT1); | ||
806 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
807 | EMU_DST_ALICE2_EMU32_4, EMU_SRC_HAMOA_ADC_LEFT2); | ||
808 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
809 | EMU_DST_ALICE2_EMU32_5, EMU_SRC_HAMOA_ADC_RIGHT2); | ||
810 | #endif | ||
811 | #if 0 | ||
812 | /* For 192kHz */ | ||
813 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
814 | EMU_DST_ALICE2_EMU32_0, EMU_SRC_HAMOA_ADC_LEFT1); | ||
815 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
816 | EMU_DST_ALICE2_EMU32_1, EMU_SRC_HAMOA_ADC_RIGHT1); | ||
817 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
818 | EMU_DST_ALICE2_EMU32_2, EMU_SRC_HAMOA_ADC_LEFT2); | ||
819 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
820 | EMU_DST_ALICE2_EMU32_3, EMU_SRC_HAMOA_ADC_RIGHT2); | ||
821 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
822 | EMU_DST_ALICE2_EMU32_4, EMU_SRC_HAMOA_ADC_LEFT3); | ||
823 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
824 | EMU_DST_ALICE2_EMU32_5, EMU_SRC_HAMOA_ADC_RIGHT3); | ||
825 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
826 | EMU_DST_ALICE2_EMU32_6, EMU_SRC_HAMOA_ADC_LEFT4); | ||
827 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
828 | EMU_DST_ALICE2_EMU32_7, EMU_SRC_HAMOA_ADC_RIGHT4); | ||
829 | #endif | ||
830 | #if 1 | ||
831 | /* For 48kHz */ | ||
832 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
833 | EMU_DST_ALICE2_EMU32_0, EMU_SRC_DOCK_MIC_A1); | ||
834 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
835 | EMU_DST_ALICE2_EMU32_1, EMU_SRC_DOCK_MIC_B1); | ||
836 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
837 | EMU_DST_ALICE2_EMU32_2, EMU_SRC_HAMOA_ADC_LEFT2); | ||
838 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
839 | EMU_DST_ALICE2_EMU32_3, EMU_SRC_HAMOA_ADC_LEFT2); | ||
840 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
841 | EMU_DST_ALICE2_EMU32_4, EMU_SRC_DOCK_ADC1_LEFT1); | ||
842 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
843 | EMU_DST_ALICE2_EMU32_5, EMU_SRC_DOCK_ADC1_RIGHT1); | ||
844 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
845 | EMU_DST_ALICE2_EMU32_6, EMU_SRC_DOCK_ADC2_LEFT1); | ||
846 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
847 | EMU_DST_ALICE2_EMU32_7, EMU_SRC_DOCK_ADC2_RIGHT1); | ||
848 | #endif | ||
849 | #if 0 | ||
850 | /* Original */ | ||
851 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
852 | EMU_DST_ALICE2_EMU32_4, EMU_SRC_HANA_ADAT); | ||
853 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
854 | EMU_DST_ALICE2_EMU32_5, EMU_SRC_HANA_ADAT + 1); | ||
855 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
856 | EMU_DST_ALICE2_EMU32_6, EMU_SRC_HANA_ADAT + 2); | ||
857 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
858 | EMU_DST_ALICE2_EMU32_7, EMU_SRC_HANA_ADAT + 3); | ||
859 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
860 | EMU_DST_ALICE2_EMU32_8, EMU_SRC_HANA_ADAT + 4); | ||
861 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
862 | EMU_DST_ALICE2_EMU32_9, EMU_SRC_HANA_ADAT + 5); | ||
863 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
864 | EMU_DST_ALICE2_EMU32_A, EMU_SRC_HANA_ADAT + 6); | ||
865 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
866 | EMU_DST_ALICE2_EMU32_B, EMU_SRC_HANA_ADAT + 7); | ||
867 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
868 | EMU_DST_ALICE2_EMU32_C, EMU_SRC_DOCK_MIC_A1); | ||
869 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
870 | EMU_DST_ALICE2_EMU32_D, EMU_SRC_DOCK_MIC_B1); | ||
871 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
872 | EMU_DST_ALICE2_EMU32_E, EMU_SRC_HAMOA_ADC_LEFT2); | ||
873 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
874 | EMU_DST_ALICE2_EMU32_F, EMU_SRC_HAMOA_ADC_LEFT2); | ||
875 | #endif | ||
876 | for (i = 0;i < 0x20; i++ ) { | ||
877 | /* AudioDock Elink <- Silence */ | ||
878 | snd_emu1010_fpga_link_dst_src_write(emu, 0x0100+i, EMU_SRC_SILENCE); | ||
879 | } | ||
880 | for (i = 0;i < 4; i++) { | ||
881 | /* Hana SPDIF Out <- Silence */ | ||
882 | snd_emu1010_fpga_link_dst_src_write(emu, 0x0200+i, EMU_SRC_SILENCE); | ||
883 | } | ||
884 | for (i = 0;i < 7; i++) { | ||
885 | /* Hamoa DAC <- Silence */ | ||
886 | snd_emu1010_fpga_link_dst_src_write(emu, 0x0300+i, EMU_SRC_SILENCE); | ||
887 | } | ||
888 | for (i = 0;i < 7; i++) { | ||
889 | /* Hana ADAT Out <- Silence */ | ||
890 | snd_emu1010_fpga_link_dst_src_write(emu, EMU_DST_HANA_ADAT + i, EMU_SRC_SILENCE); | ||
891 | } | ||
892 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
893 | EMU_DST_ALICE_I2S0_LEFT, EMU_SRC_DOCK_ADC1_LEFT1); | ||
894 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
895 | EMU_DST_ALICE_I2S0_RIGHT, EMU_SRC_DOCK_ADC1_RIGHT1); | ||
896 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
897 | EMU_DST_ALICE_I2S1_LEFT, EMU_SRC_DOCK_ADC2_LEFT1); | ||
898 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
899 | EMU_DST_ALICE_I2S1_RIGHT, EMU_SRC_DOCK_ADC2_RIGHT1); | ||
900 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
901 | EMU_DST_ALICE_I2S2_LEFT, EMU_SRC_DOCK_ADC3_LEFT1); | ||
902 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
903 | EMU_DST_ALICE_I2S2_RIGHT, EMU_SRC_DOCK_ADC3_RIGHT1); | ||
904 | snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, 0x01 ); // Unmute all | ||
905 | |||
906 | snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &tmp ); | ||
907 | |||
908 | /* AC97 1.03, Any 32Meg of 2Gig address, Auto-Mute, EMU32 Slave, | ||
909 | * Lock Sound Memory Cache, Lock Tank Memory Cache, | ||
910 | * Mute all codecs. | ||
911 | */ | ||
912 | outl(0x0000a000, emu->port + HCFG); | ||
913 | /* AC97 1.03, Any 32Meg of 2Gig address, Auto-Mute, EMU32 Slave, | ||
914 | * Lock Sound Memory Cache, Lock Tank Memory Cache, | ||
915 | * Un-Mute all codecs. | ||
916 | */ | ||
708 | outl(0x0000a001, emu->port + HCFG); | 917 | outl(0x0000a001, emu->port + HCFG); |
918 | |||
709 | /* Initial boot complete. Now patches */ | 919 | /* Initial boot complete. Now patches */ |
710 | 920 | ||
711 | snd_emu1212m_fpga_read(emu, 0x21, &tmp ); | 921 | snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &tmp ); |
712 | snd_emu1212m_fpga_write(emu, 0x0c, 0x19 ); | 922 | snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, 0x19 ); /* MIDI Route */ |
713 | snd_emu1212m_fpga_write(emu, 0x12, 0x0c ); | 923 | snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, 0x0c ); /* Unknown */ |
714 | snd_emu1212m_fpga_write(emu, 0x0c, 0x19 ); | 924 | snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, 0x19 ); /* MIDI Route */ |
715 | snd_emu1212m_fpga_write(emu, 0x12, 0x0c ); | 925 | snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, 0x0c ); /* Unknown */ |
716 | snd_emu1212m_fpga_read(emu, 0x0a, &tmp ); | 926 | snd_emu1010_fpga_read(emu, EMU_HANA_SPDIF_MODE, &tmp ); |
717 | snd_emu1212m_fpga_write(emu, 0x0a, 0x10 ); | 927 | snd_emu1010_fpga_write(emu, EMU_HANA_SPDIF_MODE, 0x10 ); /* SPDIF Format spdif (or 0x11 for aes/ebu) */ |
718 | 928 | ||
719 | snd_emu1212m_fpga_read(emu, 0x20, &tmp ); | 929 | /* Delay to allow Audio Dock to settle */ |
720 | snd_emu1212m_fpga_read(emu, 0x21, &tmp ); | 930 | msleep(100); |
721 | 931 | snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &tmp ); /* IRQ Status */ | |
722 | snd_emu1212m_fpga_netlist_write(emu, 0x0300, 0x0312); | 932 | snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ® ); /* OPTIONS: Which cards are attached to the EMU */ |
723 | snd_emu1212m_fpga_netlist_write(emu, 0x0301, 0x0313); | 933 | /* FIXME: The loading of this should be able to happen any time, |
724 | snd_emu1212m_fpga_netlist_write(emu, 0x0200, 0x0302); | 934 | * as the user can plug/unplug it at any time |
725 | snd_emu1212m_fpga_netlist_write(emu, 0x0201, 0x0303); | 935 | */ |
936 | if (reg & (EMU_HANA_OPTION_DOCK_ONLINE | EMU_HANA_OPTION_DOCK_OFFLINE) ) { | ||
937 | /* Audio Dock attached */ | ||
938 | /* Return to Audio Dock programming mode */ | ||
939 | snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware\n"); | ||
940 | snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, EMU_HANA_FPGA_CONFIG_AUDIODOCK ); | ||
941 | if ((err = snd_emu1010_load_firmware(emu, dock_filename)) != 0) { | ||
942 | return err; | ||
943 | } | ||
944 | snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0 ); | ||
945 | snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, ® ); | ||
946 | snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_IRQ_STATUS=0x%x\n",reg); | ||
947 | /* ID, should read & 0x7f = 0x55 when FPGA programmed. */ | ||
948 | snd_emu1010_fpga_read(emu, EMU_HANA_ID, ® ); | ||
949 | snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_ID=0x%x\n",reg); | ||
950 | if (reg != 0x55) { | ||
951 | /* FPGA failed to be programmed */ | ||
952 | snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware file failed, reg=0x%x\n", reg); | ||
953 | return 0; | ||
954 | return -ENODEV; | ||
955 | } | ||
956 | snd_printk(KERN_INFO "emu1010: Audio Dock Firmware loaded\n"); | ||
957 | snd_emu1010_fpga_read(emu, EMU_DOCK_MAJOR_REV, &tmp ); | ||
958 | snd_emu1010_fpga_read(emu, EMU_DOCK_MINOR_REV, &tmp2 ); | ||
959 | snd_printk("Audio Dock ver:%d.%d\n",tmp ,tmp2); | ||
960 | } | ||
961 | #if 0 | ||
962 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
963 | EMU_DST_HAMOA_DAC_LEFT1, EMU_SRC_ALICE_EMU32B + 2); /* ALICE2 bus 0xa2 */ | ||
964 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
965 | EMU_DST_HAMOA_DAC_RIGHT1, EMU_SRC_ALICE_EMU32B + 3); /* ALICE2 bus 0xa3 */ | ||
966 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
967 | EMU_DST_HANA_SPDIF_LEFT1, EMU_SRC_ALICE_EMU32A + 2); /* ALICE2 bus 0xb2 */ | ||
968 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
969 | EMU_DST_HANA_SPDIF_RIGHT1, EMU_SRC_ALICE_EMU32A + 3); /* ALICE2 bus 0xb3 */ | ||
970 | #endif | ||
971 | /* Default outputs */ | ||
972 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
973 | EMU_DST_DOCK_DAC1_LEFT1, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */ | ||
974 | emu->emu1010.output_source[0] = 21; | ||
975 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
976 | EMU_DST_DOCK_DAC1_RIGHT1, EMU_SRC_ALICE_EMU32A + 1); | ||
977 | emu->emu1010.output_source[1] = 22; | ||
978 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
979 | EMU_DST_DOCK_DAC2_LEFT1, EMU_SRC_ALICE_EMU32A + 2); | ||
980 | emu->emu1010.output_source[2] = 23; | ||
981 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
982 | EMU_DST_DOCK_DAC2_RIGHT1, EMU_SRC_ALICE_EMU32A + 3); | ||
983 | emu->emu1010.output_source[3] = 24; | ||
984 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
985 | EMU_DST_DOCK_DAC3_LEFT1, EMU_SRC_ALICE_EMU32A + 4); | ||
986 | emu->emu1010.output_source[4] = 25; | ||
987 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
988 | EMU_DST_DOCK_DAC3_RIGHT1, EMU_SRC_ALICE_EMU32A + 5); | ||
989 | emu->emu1010.output_source[5] = 26; | ||
990 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
991 | EMU_DST_DOCK_DAC4_LEFT1, EMU_SRC_ALICE_EMU32A + 6); | ||
992 | emu->emu1010.output_source[6] = 27; | ||
993 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
994 | EMU_DST_DOCK_DAC4_RIGHT1, EMU_SRC_ALICE_EMU32A + 7); | ||
995 | emu->emu1010.output_source[7] = 28; | ||
996 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
997 | EMU_DST_DOCK_PHONES_LEFT1, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */ | ||
998 | emu->emu1010.output_source[8] = 21; | ||
999 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
1000 | EMU_DST_DOCK_PHONES_RIGHT1, EMU_SRC_ALICE_EMU32A + 1); | ||
1001 | emu->emu1010.output_source[9] = 22; | ||
1002 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
1003 | EMU_DST_DOCK_SPDIF_LEFT1, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */ | ||
1004 | emu->emu1010.output_source[10] = 21; | ||
1005 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
1006 | EMU_DST_DOCK_SPDIF_RIGHT1, EMU_SRC_ALICE_EMU32A + 1); | ||
1007 | emu->emu1010.output_source[11] = 22; | ||
1008 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
1009 | EMU_DST_HANA_SPDIF_LEFT1, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */ | ||
1010 | emu->emu1010.output_source[12] = 21; | ||
1011 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
1012 | EMU_DST_HANA_SPDIF_RIGHT1, EMU_SRC_ALICE_EMU32A + 1); | ||
1013 | emu->emu1010.output_source[13] = 22; | ||
1014 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
1015 | EMU_DST_HAMOA_DAC_LEFT1, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */ | ||
1016 | emu->emu1010.output_source[14] = 21; | ||
1017 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
1018 | EMU_DST_HAMOA_DAC_RIGHT1, EMU_SRC_ALICE_EMU32A + 1); | ||
1019 | emu->emu1010.output_source[15] = 22; | ||
1020 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
1021 | EMU_DST_HANA_ADAT, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */ | ||
1022 | emu->emu1010.output_source[16] = 21; | ||
1023 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
1024 | EMU_DST_HANA_ADAT + 1, EMU_SRC_ALICE_EMU32A + 1); | ||
1025 | emu->emu1010.output_source[17] = 22; | ||
1026 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
1027 | EMU_DST_HANA_ADAT + 2, EMU_SRC_ALICE_EMU32A + 2); | ||
1028 | emu->emu1010.output_source[18] = 23; | ||
1029 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
1030 | EMU_DST_HANA_ADAT + 3, EMU_SRC_ALICE_EMU32A + 3); | ||
1031 | emu->emu1010.output_source[19] = 24; | ||
1032 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
1033 | EMU_DST_HANA_ADAT + 4, EMU_SRC_ALICE_EMU32A + 4); | ||
1034 | emu->emu1010.output_source[20] = 25; | ||
1035 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
1036 | EMU_DST_HANA_ADAT + 5, EMU_SRC_ALICE_EMU32A + 5); | ||
1037 | emu->emu1010.output_source[21] = 26; | ||
1038 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
1039 | EMU_DST_HANA_ADAT + 6, EMU_SRC_ALICE_EMU32A + 6); | ||
1040 | emu->emu1010.output_source[22] = 27; | ||
1041 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
1042 | EMU_DST_HANA_ADAT + 7, EMU_SRC_ALICE_EMU32A + 7); | ||
1043 | emu->emu1010.output_source[23] = 28; | ||
1044 | |||
1045 | /* TEMP: Select SPDIF in/out */ | ||
1046 | snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, 0x0); /* Output spdif */ | ||
1047 | |||
1048 | /* TEMP: Select 48kHz SPDIF out */ | ||
1049 | snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, 0x0); /* Mute all */ | ||
1050 | snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, 0x0); /* Default fallback clock 48kHz */ | ||
1051 | /* Word Clock source, Internal 48kHz x1 */ | ||
1052 | snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K ); | ||
1053 | //snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_4X ); | ||
1054 | emu->emu1010.internal_clock = 1; /* 48000 */ | ||
1055 | snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 0x12);/* Set LEDs on Audio Dock */ | ||
1056 | snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, 0x1); /* Unmute all */ | ||
1057 | //snd_emu1010_fpga_write(emu, 0x7, 0x0); /* Mute all */ | ||
1058 | //snd_emu1010_fpga_write(emu, 0x7, 0x1); /* Unmute all */ | ||
1059 | //snd_emu1010_fpga_write(emu, 0xe, 0x12); /* Set LEDs on Audio Dock */ | ||
726 | 1060 | ||
727 | return 0; | 1061 | return 0; |
728 | } | 1062 | } |
@@ -747,6 +1081,10 @@ static int snd_emu10k1_free(struct snd_emu10k1 *emu) | |||
747 | } | 1081 | } |
748 | snd_emu10k1_free_efx(emu); | 1082 | snd_emu10k1_free_efx(emu); |
749 | } | 1083 | } |
1084 | if (emu->card_capabilities->emu1010) { | ||
1085 | /* Disable 48Volt power to Audio Dock */ | ||
1086 | snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0 ); | ||
1087 | } | ||
750 | if (emu->memhdr) | 1088 | if (emu->memhdr) |
751 | snd_util_memhdr_free(emu->memhdr); | 1089 | snd_util_memhdr_free(emu->memhdr); |
752 | if (emu->silent_page.area) | 1090 | if (emu->silent_page.area) |
@@ -838,10 +1176,11 @@ static struct snd_emu_chip_details emu_chip_details[] = { | |||
838 | .adc_1361t = 1, /* 24 bit capture instead of 16bit */ | 1176 | .adc_1361t = 1, /* 24 bit capture instead of 16bit */ |
839 | .ac97_chip = 1} , | 1177 | .ac97_chip = 1} , |
840 | /* Audigy 2 ZS Notebook Cardbus card.*/ | 1178 | /* Audigy 2 ZS Notebook Cardbus card.*/ |
841 | /* Tested by James@superbug.co.uk 22th December 2005 */ | 1179 | /* Tested by James@superbug.co.uk 6th November 2006 */ |
842 | /* Audio output 7.1/Headphones working. | 1180 | /* Audio output 7.1/Headphones working. |
843 | * Digital output working. (AC3 not checked, only PCM) | 1181 | * Digital output working. (AC3 not checked, only PCM) |
844 | * Audio inputs not tested. | 1182 | * Audio Mic/Line inputs working. |
1183 | * Digital input not tested. | ||
845 | */ | 1184 | */ |
846 | /* DSP: Tina2 | 1185 | /* DSP: Tina2 |
847 | * DAC: Wolfson WM8768/WM8568 | 1186 | * DAC: Wolfson WM8768/WM8568 |
@@ -849,6 +1188,25 @@ static struct snd_emu_chip_details emu_chip_details[] = { | |||
849 | * AC97: None | 1188 | * AC97: None |
850 | * CA0151: None | 1189 | * CA0151: None |
851 | */ | 1190 | */ |
1191 | /* Tested by James@superbug.co.uk 4th April 2006 */ | ||
1192 | /* A_IOCFG bits | ||
1193 | * Output | ||
1194 | * 0: Not Used | ||
1195 | * 1: 0 = Mute all the 7.1 channel out. 1 = unmute. | ||
1196 | * 2: Analog input 0 = line in, 1 = mic in | ||
1197 | * 3: Not Used | ||
1198 | * 4: Digital output 0 = off, 1 = on. | ||
1199 | * 5: Not Used | ||
1200 | * 6: Not Used | ||
1201 | * 7: Not Used | ||
1202 | * Input | ||
1203 | * All bits 1 (0x3fxx) means nothing plugged in. | ||
1204 | * 8-9: 0 = Line in/Mic, 2 = Optical in, 3 = Nothing. | ||
1205 | * A-B: 0 = Headphones, 2 = Optical out, 3 = Nothing. | ||
1206 | * C-D: 2 = Front/Rear/etc, 3 = nothing. | ||
1207 | * E-F: Always 0 | ||
1208 | * | ||
1209 | */ | ||
852 | {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x20011102, | 1210 | {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x20011102, |
853 | .driver = "Audigy2", .name = "Audigy 2 ZS Notebook [SB0530]", | 1211 | .driver = "Audigy2", .name = "Audigy 2 ZS Notebook [SB0530]", |
854 | .id = "Audigy2", | 1212 | .id = "Audigy2", |
@@ -856,6 +1214,7 @@ static struct snd_emu_chip_details emu_chip_details[] = { | |||
856 | .ca0108_chip = 1, | 1214 | .ca0108_chip = 1, |
857 | .ca_cardbus_chip = 1, | 1215 | .ca_cardbus_chip = 1, |
858 | .spi_dac = 1, | 1216 | .spi_dac = 1, |
1217 | .i2c_adc = 1, | ||
859 | .spk71 = 1} , | 1218 | .spk71 = 1} , |
860 | {.vendor = 0x1102, .device = 0x0008, | 1219 | {.vendor = 0x1102, .device = 0x0008, |
861 | .driver = "Audigy2", .name = "Audigy 2 Value [Unknown]", | 1220 | .driver = "Audigy2", .name = "Audigy 2 Value [Unknown]", |
@@ -865,11 +1224,12 @@ static struct snd_emu_chip_details emu_chip_details[] = { | |||
865 | .ac97_chip = 1} , | 1224 | .ac97_chip = 1} , |
866 | /* Tested by James@superbug.co.uk 8th July 2005. No sound available yet. */ | 1225 | /* Tested by James@superbug.co.uk 8th July 2005. No sound available yet. */ |
867 | {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x40011102, | 1226 | {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x40011102, |
868 | .driver = "Audigy2", .name = "E-mu 1212m [4001]", | 1227 | .driver = "Audigy2", .name = "E-mu 1010 [4001]", |
869 | .id = "EMU1212m", | 1228 | .id = "EMU1010", |
870 | .emu10k2_chip = 1, | 1229 | .emu10k2_chip = 1, |
871 | .ca0102_chip = 1, | 1230 | .ca0102_chip = 1, |
872 | .emu1212m = 1} , | 1231 | .spk71 = 1, |
1232 | .emu1010 = 1} , | ||
873 | /* Tested by James@superbug.co.uk 3rd July 2005 */ | 1233 | /* Tested by James@superbug.co.uk 3rd July 2005 */ |
874 | {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20071102, | 1234 | {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20071102, |
875 | .driver = "Audigy2", .name = "Audigy 4 PRO [SB0380]", | 1235 | .driver = "Audigy2", .name = "Audigy 4 PRO [SB0380]", |
@@ -1297,8 +1657,8 @@ int __devinit snd_emu10k1_create(struct snd_card *card, | |||
1297 | } else if (emu->card_capabilities->ca_cardbus_chip) { | 1657 | } else if (emu->card_capabilities->ca_cardbus_chip) { |
1298 | if ((err = snd_emu10k1_cardbus_init(emu)) < 0) | 1658 | if ((err = snd_emu10k1_cardbus_init(emu)) < 0) |
1299 | goto error; | 1659 | goto error; |
1300 | } else if (emu->card_capabilities->emu1212m) { | 1660 | } else if (emu->card_capabilities->emu1010) { |
1301 | if ((err = snd_emu10k1_emu1212m_init(emu)) < 0) { | 1661 | if ((err = snd_emu10k1_emu1010_init(emu)) < 0) { |
1302 | snd_emu10k1_free(emu); | 1662 | snd_emu10k1_free(emu); |
1303 | return err; | 1663 | return err; |
1304 | } | 1664 | } |
@@ -1446,8 +1806,8 @@ void snd_emu10k1_resume_init(struct snd_emu10k1 *emu) | |||
1446 | snd_emu10k1_ecard_init(emu); | 1806 | snd_emu10k1_ecard_init(emu); |
1447 | else if (emu->card_capabilities->ca_cardbus_chip) | 1807 | else if (emu->card_capabilities->ca_cardbus_chip) |
1448 | snd_emu10k1_cardbus_init(emu); | 1808 | snd_emu10k1_cardbus_init(emu); |
1449 | else if (emu->card_capabilities->emu1212m) | 1809 | else if (emu->card_capabilities->emu1010) |
1450 | snd_emu10k1_emu1212m_init(emu); | 1810 | snd_emu10k1_emu1010_init(emu); |
1451 | else | 1811 | else |
1452 | snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE); | 1812 | snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE); |
1453 | snd_emu10k1_init(emu, emu->enable_ir, 1); | 1813 | snd_emu10k1_init(emu, emu->enable_ir, 1); |
diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c index 2199b42a6019..bb0fec7f7e1b 100644 --- a/sound/pci/emu10k1/emu10k1x.c +++ b/sound/pci/emu10k1/emu10k1x.c | |||
@@ -460,7 +460,7 @@ static int snd_emu10k1x_pcm_prepare(struct snd_pcm_substream *substream) | |||
460 | u32 period_size_bytes = frames_to_bytes(runtime, runtime->period_size); | 460 | u32 period_size_bytes = frames_to_bytes(runtime, runtime->period_size); |
461 | int i; | 461 | int i; |
462 | 462 | ||
463 | for(i=0; i < runtime->periods; i++) { | 463 | for(i = 0; i < runtime->periods; i++) { |
464 | *table_base++=runtime->dma_addr+(i*period_size_bytes); | 464 | *table_base++=runtime->dma_addr+(i*period_size_bytes); |
465 | *table_base++=period_size_bytes<<16; | 465 | *table_base++=period_size_bytes<<16; |
466 | } | 466 | } |
@@ -1042,8 +1042,8 @@ static void snd_emu10k1x_proc_reg_write(struct snd_info_entry *entry, | |||
1042 | if (sscanf(line, "%x %x %x", ®, &channel_id, &val) != 3) | 1042 | if (sscanf(line, "%x %x %x", ®, &channel_id, &val) != 3) |
1043 | continue; | 1043 | continue; |
1044 | 1044 | ||
1045 | if ((reg < 0x49) && (reg >=0) && (val <= 0xffffffff) | 1045 | if ((reg < 0x49) && (reg >= 0) && (val <= 0xffffffff) |
1046 | && (channel_id >=0) && (channel_id <= 2) ) | 1046 | && (channel_id >= 0) && (channel_id <= 2) ) |
1047 | snd_emu10k1x_ptr_write(emu, reg, channel_id, val); | 1047 | snd_emu10k1x_ptr_write(emu, reg, channel_id, val); |
1048 | } | 1048 | } |
1049 | } | 1049 | } |
diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c index 13cd6ce89811..c02012cccd8e 100644 --- a/sound/pci/emu10k1/emufx.c +++ b/sound/pci/emu10k1/emufx.c | |||
@@ -3,6 +3,9 @@ | |||
3 | * Creative Labs, Inc. | 3 | * Creative Labs, Inc. |
4 | * Routines for effect processor FX8010 | 4 | * Routines for effect processor FX8010 |
5 | * | 5 | * |
6 | * Copyright (c) by James Courtier-Dutton <James@superbug.co.uk> | ||
7 | * Added EMU 1010 support. | ||
8 | * | ||
6 | * BUGS: | 9 | * BUGS: |
7 | * -- | 10 | * -- |
8 | * | 11 | * |
@@ -293,7 +296,7 @@ static const u32 db_table[101] = { | |||
293 | }; | 296 | }; |
294 | 297 | ||
295 | /* EMU10k1/EMU10k2 DSP control db gain */ | 298 | /* EMU10k1/EMU10k2 DSP control db gain */ |
296 | static DECLARE_TLV_DB_SCALE(snd_emu10k1_db_scale1, -4000, 40, 1); | 299 | static const DECLARE_TLV_DB_SCALE(snd_emu10k1_db_scale1, -4000, 40, 1); |
297 | 300 | ||
298 | static const u32 onoff_table[2] = { | 301 | static const u32 onoff_table[2] = { |
299 | 0x00000000, 0x00000001 | 302 | 0x00000000, 0x00000001 |
@@ -652,13 +655,66 @@ snd_emu10k1_look_for_ctl(struct snd_emu10k1 *emu, struct snd_ctl_elem_id *id) | |||
652 | return NULL; | 655 | return NULL; |
653 | } | 656 | } |
654 | 657 | ||
658 | #define MAX_TLV_SIZE 256 | ||
659 | |||
660 | static unsigned int *copy_tlv(const unsigned int __user *_tlv) | ||
661 | { | ||
662 | unsigned int data[2]; | ||
663 | unsigned int *tlv; | ||
664 | |||
665 | if (!_tlv) | ||
666 | return NULL; | ||
667 | if (copy_from_user(data, _tlv, sizeof(data))) | ||
668 | return NULL; | ||
669 | if (data[1] >= MAX_TLV_SIZE) | ||
670 | return NULL; | ||
671 | tlv = kmalloc(data[1] * 4 + sizeof(data), GFP_KERNEL); | ||
672 | if (!tlv) | ||
673 | return NULL; | ||
674 | memcpy(tlv, data, sizeof(data)); | ||
675 | if (copy_from_user(tlv + 2, _tlv + 2, data[1])) { | ||
676 | kfree(tlv); | ||
677 | return NULL; | ||
678 | } | ||
679 | return tlv; | ||
680 | } | ||
681 | |||
682 | static int copy_gctl(struct snd_emu10k1 *emu, | ||
683 | struct snd_emu10k1_fx8010_control_gpr *gctl, | ||
684 | struct snd_emu10k1_fx8010_control_gpr __user *_gctl, | ||
685 | int idx) | ||
686 | { | ||
687 | struct snd_emu10k1_fx8010_control_old_gpr __user *octl; | ||
688 | |||
689 | if (emu->support_tlv) | ||
690 | return copy_from_user(gctl, &_gctl[idx], sizeof(*gctl)); | ||
691 | octl = (struct snd_emu10k1_fx8010_control_old_gpr __user *)_gctl; | ||
692 | if (copy_from_user(gctl, &octl[idx], sizeof(*octl))) | ||
693 | return -EFAULT; | ||
694 | gctl->tlv = NULL; | ||
695 | return 0; | ||
696 | } | ||
697 | |||
698 | static int copy_gctl_to_user(struct snd_emu10k1 *emu, | ||
699 | struct snd_emu10k1_fx8010_control_gpr __user *_gctl, | ||
700 | struct snd_emu10k1_fx8010_control_gpr *gctl, | ||
701 | int idx) | ||
702 | { | ||
703 | struct snd_emu10k1_fx8010_control_old_gpr __user *octl; | ||
704 | |||
705 | if (emu->support_tlv) | ||
706 | return copy_to_user(&_gctl[idx], gctl, sizeof(*gctl)); | ||
707 | |||
708 | octl = (struct snd_emu10k1_fx8010_control_old_gpr __user *)_gctl; | ||
709 | return copy_to_user(&octl[idx], gctl, sizeof(*octl)); | ||
710 | } | ||
711 | |||
655 | static int snd_emu10k1_verify_controls(struct snd_emu10k1 *emu, | 712 | static int snd_emu10k1_verify_controls(struct snd_emu10k1 *emu, |
656 | struct snd_emu10k1_fx8010_code *icode) | 713 | struct snd_emu10k1_fx8010_code *icode) |
657 | { | 714 | { |
658 | unsigned int i; | 715 | unsigned int i; |
659 | struct snd_ctl_elem_id __user *_id; | 716 | struct snd_ctl_elem_id __user *_id; |
660 | struct snd_ctl_elem_id id; | 717 | struct snd_ctl_elem_id id; |
661 | struct snd_emu10k1_fx8010_control_gpr __user *_gctl; | ||
662 | struct snd_emu10k1_fx8010_control_gpr *gctl; | 718 | struct snd_emu10k1_fx8010_control_gpr *gctl; |
663 | int err; | 719 | int err; |
664 | 720 | ||
@@ -673,9 +729,8 @@ static int snd_emu10k1_verify_controls(struct snd_emu10k1 *emu, | |||
673 | if (! gctl) | 729 | if (! gctl) |
674 | return -ENOMEM; | 730 | return -ENOMEM; |
675 | err = 0; | 731 | err = 0; |
676 | for (i = 0, _gctl = icode->gpr_add_controls; | 732 | for (i = 0; i < icode->gpr_add_control_count; i++) { |
677 | i < icode->gpr_add_control_count; i++, _gctl++) { | 733 | if (copy_gctl(emu, gctl, icode->gpr_add_controls, i)) { |
678 | if (copy_from_user(gctl, _gctl, sizeof(*gctl))) { | ||
679 | err = -EFAULT; | 734 | err = -EFAULT; |
680 | goto __error; | 735 | goto __error; |
681 | } | 736 | } |
@@ -694,10 +749,9 @@ static int snd_emu10k1_verify_controls(struct snd_emu10k1 *emu, | |||
694 | goto __error; | 749 | goto __error; |
695 | } | 750 | } |
696 | } | 751 | } |
697 | for (i = 0, _gctl = icode->gpr_list_controls; | 752 | for (i = 0; i < icode->gpr_list_control_count; i++) { |
698 | i < icode->gpr_list_control_count; i++, _gctl++) { | ||
699 | /* FIXME: we need to check the WRITE access */ | 753 | /* FIXME: we need to check the WRITE access */ |
700 | if (copy_from_user(gctl, _gctl, sizeof(*gctl))) { | 754 | if (copy_gctl(emu, gctl, icode->gpr_list_controls, i)) { |
701 | err = -EFAULT; | 755 | err = -EFAULT; |
702 | goto __error; | 756 | goto __error; |
703 | } | 757 | } |
@@ -715,13 +769,14 @@ static void snd_emu10k1_ctl_private_free(struct snd_kcontrol *kctl) | |||
715 | kctl->private_value = 0; | 769 | kctl->private_value = 0; |
716 | list_del(&ctl->list); | 770 | list_del(&ctl->list); |
717 | kfree(ctl); | 771 | kfree(ctl); |
772 | if (kctl->tlv.p) | ||
773 | kfree(kctl->tlv.p); | ||
718 | } | 774 | } |
719 | 775 | ||
720 | static int snd_emu10k1_add_controls(struct snd_emu10k1 *emu, | 776 | static int snd_emu10k1_add_controls(struct snd_emu10k1 *emu, |
721 | struct snd_emu10k1_fx8010_code *icode) | 777 | struct snd_emu10k1_fx8010_code *icode) |
722 | { | 778 | { |
723 | unsigned int i, j; | 779 | unsigned int i, j; |
724 | struct snd_emu10k1_fx8010_control_gpr __user *_gctl; | ||
725 | struct snd_emu10k1_fx8010_control_gpr *gctl; | 780 | struct snd_emu10k1_fx8010_control_gpr *gctl; |
726 | struct snd_emu10k1_fx8010_ctl *ctl, *nctl; | 781 | struct snd_emu10k1_fx8010_ctl *ctl, *nctl; |
727 | struct snd_kcontrol_new knew; | 782 | struct snd_kcontrol_new knew; |
@@ -737,9 +792,8 @@ static int snd_emu10k1_add_controls(struct snd_emu10k1 *emu, | |||
737 | goto __error; | 792 | goto __error; |
738 | } | 793 | } |
739 | 794 | ||
740 | for (i = 0, _gctl = icode->gpr_add_controls; | 795 | for (i = 0; i < icode->gpr_add_control_count; i++) { |
741 | i < icode->gpr_add_control_count; i++, _gctl++) { | 796 | if (copy_gctl(emu, gctl, icode->gpr_add_controls, i)) { |
742 | if (copy_from_user(gctl, _gctl, sizeof(*gctl))) { | ||
743 | err = -EFAULT; | 797 | err = -EFAULT; |
744 | goto __error; | 798 | goto __error; |
745 | } | 799 | } |
@@ -760,11 +814,10 @@ static int snd_emu10k1_add_controls(struct snd_emu10k1 *emu, | |||
760 | knew.device = gctl->id.device; | 814 | knew.device = gctl->id.device; |
761 | knew.subdevice = gctl->id.subdevice; | 815 | knew.subdevice = gctl->id.subdevice; |
762 | knew.info = snd_emu10k1_gpr_ctl_info; | 816 | knew.info = snd_emu10k1_gpr_ctl_info; |
763 | if (gctl->tlv.p) { | 817 | knew.tlv.p = copy_tlv(gctl->tlv); |
764 | knew.tlv.p = gctl->tlv.p; | 818 | if (knew.tlv.p) |
765 | knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | 819 | knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | |
766 | SNDRV_CTL_ELEM_ACCESS_TLV_READ; | 820 | SNDRV_CTL_ELEM_ACCESS_TLV_READ; |
767 | } | ||
768 | knew.get = snd_emu10k1_gpr_ctl_get; | 821 | knew.get = snd_emu10k1_gpr_ctl_get; |
769 | knew.put = snd_emu10k1_gpr_ctl_put; | 822 | knew.put = snd_emu10k1_gpr_ctl_put; |
770 | memset(nctl, 0, sizeof(*nctl)); | 823 | memset(nctl, 0, sizeof(*nctl)); |
@@ -782,12 +835,14 @@ static int snd_emu10k1_add_controls(struct snd_emu10k1 *emu, | |||
782 | ctl = kmalloc(sizeof(*ctl), GFP_KERNEL); | 835 | ctl = kmalloc(sizeof(*ctl), GFP_KERNEL); |
783 | if (ctl == NULL) { | 836 | if (ctl == NULL) { |
784 | err = -ENOMEM; | 837 | err = -ENOMEM; |
838 | kfree(knew.tlv.p); | ||
785 | goto __error; | 839 | goto __error; |
786 | } | 840 | } |
787 | knew.private_value = (unsigned long)ctl; | 841 | knew.private_value = (unsigned long)ctl; |
788 | *ctl = *nctl; | 842 | *ctl = *nctl; |
789 | if ((err = snd_ctl_add(emu->card, kctl = snd_ctl_new1(&knew, emu))) < 0) { | 843 | if ((err = snd_ctl_add(emu->card, kctl = snd_ctl_new1(&knew, emu))) < 0) { |
790 | kfree(ctl); | 844 | kfree(ctl); |
845 | kfree(knew.tlv.p); | ||
791 | goto __error; | 846 | goto __error; |
792 | } | 847 | } |
793 | kctl->private_free = snd_emu10k1_ctl_private_free; | 848 | kctl->private_free = snd_emu10k1_ctl_private_free; |
@@ -838,7 +893,6 @@ static int snd_emu10k1_list_controls(struct snd_emu10k1 *emu, | |||
838 | unsigned int i = 0, j; | 893 | unsigned int i = 0, j; |
839 | unsigned int total = 0; | 894 | unsigned int total = 0; |
840 | struct snd_emu10k1_fx8010_control_gpr *gctl; | 895 | struct snd_emu10k1_fx8010_control_gpr *gctl; |
841 | struct snd_emu10k1_fx8010_control_gpr __user *_gctl; | ||
842 | struct snd_emu10k1_fx8010_ctl *ctl; | 896 | struct snd_emu10k1_fx8010_ctl *ctl; |
843 | struct snd_ctl_elem_id *id; | 897 | struct snd_ctl_elem_id *id; |
844 | struct list_head *list; | 898 | struct list_head *list; |
@@ -847,11 +901,11 @@ static int snd_emu10k1_list_controls(struct snd_emu10k1 *emu, | |||
847 | if (! gctl) | 901 | if (! gctl) |
848 | return -ENOMEM; | 902 | return -ENOMEM; |
849 | 903 | ||
850 | _gctl = icode->gpr_list_controls; | ||
851 | list_for_each(list, &emu->fx8010.gpr_ctl) { | 904 | list_for_each(list, &emu->fx8010.gpr_ctl) { |
852 | ctl = emu10k1_gpr_ctl(list); | 905 | ctl = emu10k1_gpr_ctl(list); |
853 | total++; | 906 | total++; |
854 | if (_gctl && i < icode->gpr_list_control_count) { | 907 | if (icode->gpr_list_controls && |
908 | i < icode->gpr_list_control_count) { | ||
855 | memset(gctl, 0, sizeof(*gctl)); | 909 | memset(gctl, 0, sizeof(*gctl)); |
856 | id = &ctl->kcontrol->id; | 910 | id = &ctl->kcontrol->id; |
857 | gctl->id.iface = id->iface; | 911 | gctl->id.iface = id->iface; |
@@ -868,11 +922,11 @@ static int snd_emu10k1_list_controls(struct snd_emu10k1 *emu, | |||
868 | gctl->min = ctl->min; | 922 | gctl->min = ctl->min; |
869 | gctl->max = ctl->max; | 923 | gctl->max = ctl->max; |
870 | gctl->translation = ctl->translation; | 924 | gctl->translation = ctl->translation; |
871 | if (copy_to_user(_gctl, gctl, sizeof(*gctl))) { | 925 | if (copy_gctl_to_user(emu, icode->gpr_list_controls, |
926 | gctl, i)) { | ||
872 | kfree(gctl); | 927 | kfree(gctl); |
873 | return -EFAULT; | 928 | return -EFAULT; |
874 | } | 929 | } |
875 | _gctl++; | ||
876 | i++; | 930 | i++; |
877 | } | 931 | } |
878 | } | 932 | } |
@@ -1023,7 +1077,7 @@ snd_emu10k1_init_mono_control(struct snd_emu10k1_fx8010_control_gpr *ctl, | |||
1023 | ctl->gpr[0] = gpr + 0; ctl->value[0] = defval; | 1077 | ctl->gpr[0] = gpr + 0; ctl->value[0] = defval; |
1024 | ctl->min = 0; | 1078 | ctl->min = 0; |
1025 | ctl->max = 100; | 1079 | ctl->max = 100; |
1026 | ctl->tlv.p = snd_emu10k1_db_scale1; | 1080 | ctl->tlv = snd_emu10k1_db_scale1; |
1027 | ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100; | 1081 | ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100; |
1028 | } | 1082 | } |
1029 | 1083 | ||
@@ -1038,7 +1092,7 @@ snd_emu10k1_init_stereo_control(struct snd_emu10k1_fx8010_control_gpr *ctl, | |||
1038 | ctl->gpr[1] = gpr + 1; ctl->value[1] = defval; | 1092 | ctl->gpr[1] = gpr + 1; ctl->value[1] = defval; |
1039 | ctl->min = 0; | 1093 | ctl->min = 0; |
1040 | ctl->max = 100; | 1094 | ctl->max = 100; |
1041 | ctl->tlv.p = snd_emu10k1_db_scale1; | 1095 | ctl->tlv = snd_emu10k1_db_scale1; |
1042 | ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100; | 1096 | ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100; |
1043 | } | 1097 | } |
1044 | 1098 | ||
@@ -1069,6 +1123,21 @@ snd_emu10k1_init_stereo_onoff_control(struct snd_emu10k1_fx8010_control_gpr *ctl | |||
1069 | ctl->translation = EMU10K1_GPR_TRANSLATION_ONOFF; | 1123 | ctl->translation = EMU10K1_GPR_TRANSLATION_ONOFF; |
1070 | } | 1124 | } |
1071 | 1125 | ||
1126 | static int snd_emu10k1_audigy_dsp_convert_32_to_2x16( | ||
1127 | struct snd_emu10k1_fx8010_code *icode, | ||
1128 | u32 *ptr, int tmp, int bit_shifter16, | ||
1129 | int reg_in, int reg_out) | ||
1130 | { | ||
1131 | A_OP(icode, ptr, iACC3, A_GPR(tmp + 1), reg_in, A_C_00000000, A_C_00000000); | ||
1132 | A_OP(icode, ptr, iANDXOR, A_GPR(tmp), A_GPR(tmp + 1), A_GPR(bit_shifter16 - 1), A_C_00000000); | ||
1133 | A_OP(icode, ptr, iTSTNEG, A_GPR(tmp + 2), A_GPR(tmp), A_C_80000000, A_GPR(bit_shifter16 - 2)); | ||
1134 | A_OP(icode, ptr, iANDXOR, A_GPR(tmp + 2), A_GPR(tmp + 2), A_C_80000000, A_C_00000000); | ||
1135 | A_OP(icode, ptr, iANDXOR, A_GPR(tmp), A_GPR(tmp), A_GPR(bit_shifter16 - 3), A_C_00000000); | ||
1136 | A_OP(icode, ptr, iMACINT0, A_GPR(tmp), A_C_00000000, A_GPR(tmp), A_C_00010000); | ||
1137 | A_OP(icode, ptr, iANDXOR, reg_out, A_GPR(tmp), A_C_ffffffff, A_GPR(tmp + 2)); | ||
1138 | A_OP(icode, ptr, iACC3, reg_out + 1, A_GPR(tmp + 1), A_C_00000000, A_C_00000000); | ||
1139 | return 1; | ||
1140 | } | ||
1072 | 1141 | ||
1073 | /* | 1142 | /* |
1074 | * initial DSP configuration for Audigy | 1143 | * initial DSP configuration for Audigy |
@@ -1077,6 +1146,7 @@ snd_emu10k1_init_stereo_onoff_control(struct snd_emu10k1_fx8010_control_gpr *ctl | |||
1077 | static int __devinit _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu) | 1146 | static int __devinit _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu) |
1078 | { | 1147 | { |
1079 | int err, i, z, gpr, nctl; | 1148 | int err, i, z, gpr, nctl; |
1149 | int bit_shifter16; | ||
1080 | const int playback = 10; | 1150 | const int playback = 10; |
1081 | const int capture = playback + (SND_EMU10K1_PLAYBACK_CHANNELS * 2); /* we reserve 10 voices */ | 1151 | const int capture = playback + (SND_EMU10K1_PLAYBACK_CHANNELS * 2); /* we reserve 10 voices */ |
1082 | const int stereo_mix = capture + 2; | 1152 | const int stereo_mix = capture + 2; |
@@ -1114,17 +1184,14 @@ static int __devinit _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu) | |||
1114 | ptr = 0; | 1184 | ptr = 0; |
1115 | nctl = 0; | 1185 | nctl = 0; |
1116 | gpr = stereo_mix + 10; | 1186 | gpr = stereo_mix + 10; |
1187 | gpr_map[gpr++] = 0x00007fff; | ||
1188 | gpr_map[gpr++] = 0x00008000; | ||
1189 | gpr_map[gpr++] = 0x0000ffff; | ||
1190 | bit_shifter16 = gpr; | ||
1117 | 1191 | ||
1118 | /* stop FX processor */ | 1192 | /* stop FX processor */ |
1119 | snd_emu10k1_ptr_write(emu, A_DBG, 0, (emu->fx8010.dbg = 0) | A_DBG_SINGLE_STEP); | 1193 | snd_emu10k1_ptr_write(emu, A_DBG, 0, (emu->fx8010.dbg = 0) | A_DBG_SINGLE_STEP); |
1120 | 1194 | ||
1121 | #if 0 | ||
1122 | /* FIX: jcd test */ | ||
1123 | for (z = 0; z < 80; z=z+2) { | ||
1124 | A_OP(icode, &ptr, iACC3, A_EXTOUT(z), A_FXBUS(FXBUS_PCM_LEFT_FRONT), A_C_00000000, A_C_00000000); /* left */ | ||
1125 | A_OP(icode, &ptr, iACC3, A_EXTOUT(z+1), A_FXBUS(FXBUS_PCM_RIGHT_FRONT), A_C_00000000, A_C_00000000); /* right */ | ||
1126 | } | ||
1127 | #endif /* jcd test */ | ||
1128 | #if 1 | 1195 | #if 1 |
1129 | /* PCM front Playback Volume (independent from stereo mix) */ | 1196 | /* PCM front Playback Volume (independent from stereo mix) */ |
1130 | A_OP(icode, &ptr, iMAC0, A_GPR(playback), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_FRONT)); | 1197 | A_OP(icode, &ptr, iMAC0, A_GPR(playback), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_FRONT)); |
@@ -1182,13 +1249,20 @@ static int __devinit _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu) | |||
1182 | A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr+1), A_FXBUS(FXBUS_MIDI_RIGHT)); | 1249 | A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr+1), A_FXBUS(FXBUS_MIDI_RIGHT)); |
1183 | snd_emu10k1_init_stereo_control(&controls[nctl++], "Synth Capture Volume", gpr, 0); | 1250 | snd_emu10k1_init_stereo_control(&controls[nctl++], "Synth Capture Volume", gpr, 0); |
1184 | gpr += 2; | 1251 | gpr += 2; |
1185 | 1252 | ||
1186 | /* | 1253 | /* |
1187 | * inputs | 1254 | * inputs |
1188 | */ | 1255 | */ |
1189 | #define A_ADD_VOLUME_IN(var,vol,input) \ | 1256 | #define A_ADD_VOLUME_IN(var,vol,input) \ |
1190 | A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) | 1257 | A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) |
1191 | 1258 | ||
1259 | /* emu1212 DSP 0 and DSP 1 Capture */ | ||
1260 | if (emu->card_capabilities->emu1010) { | ||
1261 | A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_GPR(capture+0), A_GPR(gpr), A_P16VIN(0x0)); | ||
1262 | A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr+1), A_P16VIN(0x1)); | ||
1263 | snd_emu10k1_init_stereo_control(&controls[nctl++], "EMU Capture Volume", gpr, 0); | ||
1264 | gpr += 2; | ||
1265 | } | ||
1192 | /* AC'97 Playback Volume - used only for mic (renamed later) */ | 1266 | /* AC'97 Playback Volume - used only for mic (renamed later) */ |
1193 | A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_AC97_L); | 1267 | A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_AC97_L); |
1194 | A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_AC97_R); | 1268 | A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_AC97_R); |
@@ -1429,6 +1503,13 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) | |||
1429 | 1503 | ||
1430 | /* digital outputs */ | 1504 | /* digital outputs */ |
1431 | /* A_PUT_STEREO_OUTPUT(A_EXTOUT_FRONT_L, A_EXTOUT_FRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS); */ | 1505 | /* A_PUT_STEREO_OUTPUT(A_EXTOUT_FRONT_L, A_EXTOUT_FRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS); */ |
1506 | if (emu->card_capabilities->emu1010) { | ||
1507 | /* EMU1010 Outputs from PCM Front, Rear, Center, LFE, Side */ | ||
1508 | snd_printk("EMU outputs on\n"); | ||
1509 | for (z = 0; z < 8; z++) { | ||
1510 | A_OP(icode, &ptr, iACC3, A_EMU32OUTL(z), A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), A_C_00000000, A_C_00000000); | ||
1511 | } | ||
1512 | } | ||
1432 | 1513 | ||
1433 | /* IEC958 Optical Raw Playback Switch */ | 1514 | /* IEC958 Optical Raw Playback Switch */ |
1434 | gpr_map[gpr++] = 0; | 1515 | gpr_map[gpr++] = 0; |
@@ -1466,9 +1547,57 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) | |||
1466 | A_PUT_OUTPUT(A_EXTOUT_ADC_CAP_R, capture+1); | 1547 | A_PUT_OUTPUT(A_EXTOUT_ADC_CAP_R, capture+1); |
1467 | #endif | 1548 | #endif |
1468 | 1549 | ||
1469 | /* EFX capture - capture the 16 EXTINs */ | 1550 | if (emu->card_capabilities->emu1010) { |
1470 | for (z = 0; z < 16; z++) { | 1551 | snd_printk("EMU inputs on\n"); |
1471 | A_OP(icode, &ptr, iACC3, A_FXBUS2(z), A_C_00000000, A_C_00000000, A_EXTIN(z)); | 1552 | /* Capture 8 channels of S32_LE sound */ |
1553 | |||
1554 | /* printk("emufx.c: gpr=0x%x, tmp=0x%x\n",gpr, tmp); */ | ||
1555 | /* For the EMU1010: How to get 32bit values from the DSP. High 16bits into L, low 16bits into R. */ | ||
1556 | /* A_P16VIN(0) is delayed by one sample, | ||
1557 | * so all other A_P16VIN channels will need to also be delayed | ||
1558 | */ | ||
1559 | /* Left ADC in. 1 of 2 */ | ||
1560 | snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_P16VIN(0x0), A_FXBUS2(0) ); | ||
1561 | /* Right ADC in 1 of 2 */ | ||
1562 | gpr_map[gpr++] = 0x00000000; | ||
1563 | snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(2) ); | ||
1564 | A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x1), A_C_00000000, A_C_00000000); | ||
1565 | gpr_map[gpr++] = 0x00000000; | ||
1566 | snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(4) ); | ||
1567 | A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x2), A_C_00000000, A_C_00000000); | ||
1568 | gpr_map[gpr++] = 0x00000000; | ||
1569 | snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(6) ); | ||
1570 | A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x3), A_C_00000000, A_C_00000000); | ||
1571 | /* For 96kHz mode */ | ||
1572 | /* Left ADC in. 2 of 2 */ | ||
1573 | gpr_map[gpr++] = 0x00000000; | ||
1574 | snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0x8) ); | ||
1575 | A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x4), A_C_00000000, A_C_00000000); | ||
1576 | /* Right ADC in 2 of 2 */ | ||
1577 | gpr_map[gpr++] = 0x00000000; | ||
1578 | snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xa) ); | ||
1579 | A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x5), A_C_00000000, A_C_00000000); | ||
1580 | gpr_map[gpr++] = 0x00000000; | ||
1581 | snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xc) ); | ||
1582 | A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x6), A_C_00000000, A_C_00000000); | ||
1583 | gpr_map[gpr++] = 0x00000000; | ||
1584 | snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xe) ); | ||
1585 | A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x7), A_C_00000000, A_C_00000000); | ||
1586 | |||
1587 | #if 0 | ||
1588 | for (z = 4; z < 8; z++) { | ||
1589 | A_OP(icode, &ptr, iACC3, A_FXBUS2(z), A_C_00000000, A_C_00000000, A_C_00000000); | ||
1590 | } | ||
1591 | for (z = 0xc; z < 0x10; z++) { | ||
1592 | A_OP(icode, &ptr, iACC3, A_FXBUS2(z), A_C_00000000, A_C_00000000, A_C_00000000); | ||
1593 | } | ||
1594 | #endif | ||
1595 | } else { | ||
1596 | /* EFX capture - capture the 16 EXTINs */ | ||
1597 | /* Capture 16 channels of S16_LE sound */ | ||
1598 | for (z = 0; z < 16; z++) { | ||
1599 | A_OP(icode, &ptr, iACC3, A_FXBUS2(z), A_C_00000000, A_C_00000000, A_EXTIN(z)); | ||
1600 | } | ||
1472 | } | 1601 | } |
1473 | 1602 | ||
1474 | #endif /* JCD test */ | 1603 | #endif /* JCD test */ |
@@ -1488,7 +1617,9 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) | |||
1488 | seg = snd_enter_user(); | 1617 | seg = snd_enter_user(); |
1489 | icode->gpr_add_control_count = nctl; | 1618 | icode->gpr_add_control_count = nctl; |
1490 | icode->gpr_add_controls = (struct snd_emu10k1_fx8010_control_gpr __user *)controls; | 1619 | icode->gpr_add_controls = (struct snd_emu10k1_fx8010_control_gpr __user *)controls; |
1620 | emu->support_tlv = 1; /* support TLV */ | ||
1491 | err = snd_emu10k1_icode_poke(emu, icode); | 1621 | err = snd_emu10k1_icode_poke(emu, icode); |
1622 | emu->support_tlv = 0; /* clear again */ | ||
1492 | snd_leave_user(seg); | 1623 | snd_leave_user(seg); |
1493 | 1624 | ||
1494 | __err: | 1625 | __err: |
@@ -2105,7 +2236,9 @@ static int __devinit _snd_emu10k1_init_efx(struct snd_emu10k1 *emu) | |||
2105 | seg = snd_enter_user(); | 2236 | seg = snd_enter_user(); |
2106 | icode->gpr_add_control_count = i; | 2237 | icode->gpr_add_control_count = i; |
2107 | icode->gpr_add_controls = (struct snd_emu10k1_fx8010_control_gpr __user *)controls; | 2238 | icode->gpr_add_controls = (struct snd_emu10k1_fx8010_control_gpr __user *)controls; |
2239 | emu->support_tlv = 1; /* support TLV */ | ||
2108 | err = snd_emu10k1_icode_poke(emu, icode); | 2240 | err = snd_emu10k1_icode_poke(emu, icode); |
2241 | emu->support_tlv = 0; /* clear again */ | ||
2109 | snd_leave_user(seg); | 2242 | snd_leave_user(seg); |
2110 | if (err >= 0) | 2243 | if (err >= 0) |
2111 | err = snd_emu10k1_ipcm_poke(emu, ipcm); | 2244 | err = snd_emu10k1_ipcm_poke(emu, ipcm); |
@@ -2138,7 +2271,7 @@ void snd_emu10k1_free_efx(struct snd_emu10k1 *emu) | |||
2138 | snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg = EMU10K1_DBG_SINGLE_STEP); | 2271 | snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg = EMU10K1_DBG_SINGLE_STEP); |
2139 | } | 2272 | } |
2140 | 2273 | ||
2141 | #if 0 // FIXME: who use them? | 2274 | #if 0 /* FIXME: who use them? */ |
2142 | int snd_emu10k1_fx8010_tone_control_activate(struct snd_emu10k1 *emu, int output) | 2275 | int snd_emu10k1_fx8010_tone_control_activate(struct snd_emu10k1 *emu, int output) |
2143 | { | 2276 | { |
2144 | if (output < 0 || output >= 6) | 2277 | if (output < 0 || output >= 6) |
@@ -2249,6 +2382,9 @@ static int snd_emu10k1_fx8010_ioctl(struct snd_hwdep * hw, struct file *file, un | |||
2249 | int res; | 2382 | int res; |
2250 | 2383 | ||
2251 | switch (cmd) { | 2384 | switch (cmd) { |
2385 | case SNDRV_EMU10K1_IOCTL_PVERSION: | ||
2386 | emu->support_tlv = 1; | ||
2387 | return put_user(SNDRV_EMU10K1_VERSION, (int __user *)argp); | ||
2252 | case SNDRV_EMU10K1_IOCTL_INFO: | 2388 | case SNDRV_EMU10K1_IOCTL_INFO: |
2253 | info = kmalloc(sizeof(*info), GFP_KERNEL); | 2389 | info = kmalloc(sizeof(*info), GFP_KERNEL); |
2254 | if (!info) | 2390 | if (!info) |
diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index c31f3d0877fa..4db6e1ca1665 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c | |||
@@ -5,6 +5,9 @@ | |||
5 | * Routines for control of EMU10K1 chips / mixer routines | 5 | * Routines for control of EMU10K1 chips / mixer routines |
6 | * Multichannel PCM support Copyright (c) Lee Revell <rlrevell@joe-job.com> | 6 | * Multichannel PCM support Copyright (c) Lee Revell <rlrevell@joe-job.com> |
7 | * | 7 | * |
8 | * Copyright (c) by James Courtier-Dutton <James@superbug.co.uk> | ||
9 | * Added EMU 1010 support. | ||
10 | * | ||
8 | * BUGS: | 11 | * BUGS: |
9 | * -- | 12 | * -- |
10 | * | 13 | * |
@@ -32,9 +35,15 @@ | |||
32 | #include <linux/init.h> | 35 | #include <linux/init.h> |
33 | #include <sound/core.h> | 36 | #include <sound/core.h> |
34 | #include <sound/emu10k1.h> | 37 | #include <sound/emu10k1.h> |
38 | #include <linux/delay.h> | ||
39 | #include <sound/tlv.h> | ||
40 | |||
41 | #include "p17v.h" | ||
35 | 42 | ||
36 | #define AC97_ID_STAC9758 0x83847658 | 43 | #define AC97_ID_STAC9758 0x83847658 |
37 | 44 | ||
45 | static const DECLARE_TLV_DB_SCALE(snd_audigy_db_scale2, -10350, 50, 1); /* WM8775 gain scale */ | ||
46 | |||
38 | static int snd_emu10k1_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | 47 | static int snd_emu10k1_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) |
39 | { | 48 | { |
40 | uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; | 49 | uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; |
@@ -68,6 +77,669 @@ static int snd_emu10k1_spdif_get_mask(struct snd_kcontrol *kcontrol, | |||
68 | return 0; | 77 | return 0; |
69 | } | 78 | } |
70 | 79 | ||
80 | static char *emu1010_src_texts[] = { | ||
81 | "Silence", | ||
82 | "Dock Mic A", | ||
83 | "Dock Mic B", | ||
84 | "Dock ADC1 Left", | ||
85 | "Dock ADC1 Right", | ||
86 | "Dock ADC2 Left", | ||
87 | "Dock ADC2 Right", | ||
88 | "Dock ADC3 Left", | ||
89 | "Dock ADC3 Right", | ||
90 | "0202 ADC Left", | ||
91 | "0202 ADC Right", | ||
92 | "0202 SPDIF Left", | ||
93 | "0202 SPDIF Right", | ||
94 | "ADAT 0", | ||
95 | "ADAT 1", | ||
96 | "ADAT 2", | ||
97 | "ADAT 3", | ||
98 | "ADAT 4", | ||
99 | "ADAT 5", | ||
100 | "ADAT 6", | ||
101 | "ADAT 7", | ||
102 | "DSP 0", | ||
103 | "DSP 1", | ||
104 | "DSP 2", | ||
105 | "DSP 3", | ||
106 | "DSP 4", | ||
107 | "DSP 5", | ||
108 | "DSP 6", | ||
109 | "DSP 7", | ||
110 | "DSP 8", | ||
111 | "DSP 9", | ||
112 | "DSP 10", | ||
113 | "DSP 11", | ||
114 | "DSP 12", | ||
115 | "DSP 13", | ||
116 | "DSP 14", | ||
117 | "DSP 15", | ||
118 | "DSP 16", | ||
119 | "DSP 17", | ||
120 | "DSP 18", | ||
121 | "DSP 19", | ||
122 | "DSP 20", | ||
123 | "DSP 21", | ||
124 | "DSP 22", | ||
125 | "DSP 23", | ||
126 | "DSP 24", | ||
127 | "DSP 25", | ||
128 | "DSP 26", | ||
129 | "DSP 27", | ||
130 | "DSP 28", | ||
131 | "DSP 29", | ||
132 | "DSP 30", | ||
133 | "DSP 31", | ||
134 | }; | ||
135 | |||
136 | static unsigned int emu1010_src_regs[] = { | ||
137 | EMU_SRC_SILENCE,/* 0 */ | ||
138 | EMU_SRC_DOCK_MIC_A1, /* 1 */ | ||
139 | EMU_SRC_DOCK_MIC_B1, /* 2 */ | ||
140 | EMU_SRC_DOCK_ADC1_LEFT1, /* 3 */ | ||
141 | EMU_SRC_DOCK_ADC1_RIGHT1, /* 4 */ | ||
142 | EMU_SRC_DOCK_ADC2_LEFT1, /* 5 */ | ||
143 | EMU_SRC_DOCK_ADC2_RIGHT1, /* 6 */ | ||
144 | EMU_SRC_DOCK_ADC3_LEFT1, /* 7 */ | ||
145 | EMU_SRC_DOCK_ADC3_RIGHT1, /* 8 */ | ||
146 | EMU_SRC_HAMOA_ADC_LEFT1, /* 9 */ | ||
147 | EMU_SRC_HAMOA_ADC_RIGHT1, /* 10 */ | ||
148 | EMU_SRC_HANA_SPDIF_LEFT1, /* 11 */ | ||
149 | EMU_SRC_HANA_SPDIF_RIGHT1, /* 12 */ | ||
150 | EMU_SRC_HANA_ADAT, /* 13 */ | ||
151 | EMU_SRC_HANA_ADAT+1, /* 14 */ | ||
152 | EMU_SRC_HANA_ADAT+2, /* 15 */ | ||
153 | EMU_SRC_HANA_ADAT+3, /* 16 */ | ||
154 | EMU_SRC_HANA_ADAT+4, /* 17 */ | ||
155 | EMU_SRC_HANA_ADAT+5, /* 18 */ | ||
156 | EMU_SRC_HANA_ADAT+6, /* 19 */ | ||
157 | EMU_SRC_HANA_ADAT+7, /* 20 */ | ||
158 | EMU_SRC_ALICE_EMU32A, /* 21 */ | ||
159 | EMU_SRC_ALICE_EMU32A+1, /* 22 */ | ||
160 | EMU_SRC_ALICE_EMU32A+2, /* 23 */ | ||
161 | EMU_SRC_ALICE_EMU32A+3, /* 24 */ | ||
162 | EMU_SRC_ALICE_EMU32A+4, /* 25 */ | ||
163 | EMU_SRC_ALICE_EMU32A+5, /* 26 */ | ||
164 | EMU_SRC_ALICE_EMU32A+6, /* 27 */ | ||
165 | EMU_SRC_ALICE_EMU32A+7, /* 28 */ | ||
166 | EMU_SRC_ALICE_EMU32A+8, /* 29 */ | ||
167 | EMU_SRC_ALICE_EMU32A+9, /* 30 */ | ||
168 | EMU_SRC_ALICE_EMU32A+0xa, /* 31 */ | ||
169 | EMU_SRC_ALICE_EMU32A+0xb, /* 32 */ | ||
170 | EMU_SRC_ALICE_EMU32A+0xc, /* 33 */ | ||
171 | EMU_SRC_ALICE_EMU32A+0xd, /* 34 */ | ||
172 | EMU_SRC_ALICE_EMU32A+0xe, /* 35 */ | ||
173 | EMU_SRC_ALICE_EMU32A+0xf, /* 36 */ | ||
174 | EMU_SRC_ALICE_EMU32B, /* 37 */ | ||
175 | EMU_SRC_ALICE_EMU32B+1, /* 38 */ | ||
176 | EMU_SRC_ALICE_EMU32B+2, /* 39 */ | ||
177 | EMU_SRC_ALICE_EMU32B+3, /* 40 */ | ||
178 | EMU_SRC_ALICE_EMU32B+4, /* 41 */ | ||
179 | EMU_SRC_ALICE_EMU32B+5, /* 42 */ | ||
180 | EMU_SRC_ALICE_EMU32B+6, /* 43 */ | ||
181 | EMU_SRC_ALICE_EMU32B+7, /* 44 */ | ||
182 | EMU_SRC_ALICE_EMU32B+8, /* 45 */ | ||
183 | EMU_SRC_ALICE_EMU32B+9, /* 46 */ | ||
184 | EMU_SRC_ALICE_EMU32B+0xa, /* 47 */ | ||
185 | EMU_SRC_ALICE_EMU32B+0xb, /* 48 */ | ||
186 | EMU_SRC_ALICE_EMU32B+0xc, /* 49 */ | ||
187 | EMU_SRC_ALICE_EMU32B+0xd, /* 50 */ | ||
188 | EMU_SRC_ALICE_EMU32B+0xe, /* 51 */ | ||
189 | EMU_SRC_ALICE_EMU32B+0xf, /* 52 */ | ||
190 | }; | ||
191 | |||
192 | static unsigned int emu1010_output_dst[] = { | ||
193 | EMU_DST_DOCK_DAC1_LEFT1, /* 0 */ | ||
194 | EMU_DST_DOCK_DAC1_RIGHT1, /* 1 */ | ||
195 | EMU_DST_DOCK_DAC2_LEFT1, /* 2 */ | ||
196 | EMU_DST_DOCK_DAC2_RIGHT1, /* 3 */ | ||
197 | EMU_DST_DOCK_DAC3_LEFT1, /* 4 */ | ||
198 | EMU_DST_DOCK_DAC3_RIGHT1, /* 5 */ | ||
199 | EMU_DST_DOCK_DAC4_LEFT1, /* 6 */ | ||
200 | EMU_DST_DOCK_DAC4_RIGHT1, /* 7 */ | ||
201 | EMU_DST_DOCK_PHONES_LEFT1, /* 8 */ | ||
202 | EMU_DST_DOCK_PHONES_RIGHT1, /* 9 */ | ||
203 | EMU_DST_DOCK_SPDIF_LEFT1, /* 10 */ | ||
204 | EMU_DST_DOCK_SPDIF_RIGHT1, /* 11 */ | ||
205 | EMU_DST_HANA_SPDIF_LEFT1, /* 12 */ | ||
206 | EMU_DST_HANA_SPDIF_RIGHT1, /* 13 */ | ||
207 | EMU_DST_HAMOA_DAC_LEFT1, /* 14 */ | ||
208 | EMU_DST_HAMOA_DAC_RIGHT1, /* 15 */ | ||
209 | EMU_DST_HANA_ADAT, /* 16 */ | ||
210 | EMU_DST_HANA_ADAT+1, /* 17 */ | ||
211 | EMU_DST_HANA_ADAT+2, /* 18 */ | ||
212 | EMU_DST_HANA_ADAT+3, /* 19 */ | ||
213 | EMU_DST_HANA_ADAT+4, /* 20 */ | ||
214 | EMU_DST_HANA_ADAT+5, /* 21 */ | ||
215 | EMU_DST_HANA_ADAT+6, /* 22 */ | ||
216 | EMU_DST_HANA_ADAT+7, /* 23 */ | ||
217 | }; | ||
218 | |||
219 | static unsigned int emu1010_input_dst[] = { | ||
220 | EMU_DST_ALICE2_EMU32_0, | ||
221 | EMU_DST_ALICE2_EMU32_1, | ||
222 | EMU_DST_ALICE2_EMU32_2, | ||
223 | EMU_DST_ALICE2_EMU32_3, | ||
224 | EMU_DST_ALICE2_EMU32_4, | ||
225 | EMU_DST_ALICE2_EMU32_5, | ||
226 | EMU_DST_ALICE2_EMU32_6, | ||
227 | EMU_DST_ALICE2_EMU32_7, | ||
228 | EMU_DST_ALICE2_EMU32_8, | ||
229 | EMU_DST_ALICE2_EMU32_9, | ||
230 | EMU_DST_ALICE2_EMU32_A, | ||
231 | EMU_DST_ALICE2_EMU32_B, | ||
232 | EMU_DST_ALICE2_EMU32_C, | ||
233 | EMU_DST_ALICE2_EMU32_D, | ||
234 | EMU_DST_ALICE2_EMU32_E, | ||
235 | EMU_DST_ALICE2_EMU32_F, | ||
236 | EMU_DST_ALICE_I2S0_LEFT, | ||
237 | EMU_DST_ALICE_I2S0_RIGHT, | ||
238 | EMU_DST_ALICE_I2S1_LEFT, | ||
239 | EMU_DST_ALICE_I2S1_RIGHT, | ||
240 | EMU_DST_ALICE_I2S2_LEFT, | ||
241 | EMU_DST_ALICE_I2S2_RIGHT, | ||
242 | }; | ||
243 | |||
244 | static int snd_emu1010_input_output_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | ||
245 | { | ||
246 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
247 | uinfo->count = 1; | ||
248 | uinfo->value.enumerated.items = 53; | ||
249 | if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) | ||
250 | uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; | ||
251 | strcpy(uinfo->value.enumerated.name, emu1010_src_texts[uinfo->value.enumerated.item]); | ||
252 | return 0; | ||
253 | } | ||
254 | |||
255 | static int snd_emu1010_output_source_get(struct snd_kcontrol *kcontrol, | ||
256 | struct snd_ctl_elem_value *ucontrol) | ||
257 | { | ||
258 | struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); | ||
259 | int channel; | ||
260 | |||
261 | channel = (kcontrol->private_value) & 0xff; | ||
262 | ucontrol->value.enumerated.item[0] = emu->emu1010.output_source[channel]; | ||
263 | return 0; | ||
264 | } | ||
265 | |||
266 | static int snd_emu1010_output_source_put(struct snd_kcontrol *kcontrol, | ||
267 | struct snd_ctl_elem_value *ucontrol) | ||
268 | { | ||
269 | struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); | ||
270 | int change = 0; | ||
271 | unsigned int val; | ||
272 | int channel; | ||
273 | |||
274 | channel = (kcontrol->private_value) & 0xff; | ||
275 | if (emu->emu1010.output_source[channel] != ucontrol->value.enumerated.item[0]) { | ||
276 | val = emu->emu1010.output_source[channel] = ucontrol->value.enumerated.item[0]; | ||
277 | change = 1; | ||
278 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
279 | emu1010_output_dst[channel], emu1010_src_regs[val]); | ||
280 | } | ||
281 | return change; | ||
282 | } | ||
283 | |||
284 | static int snd_emu1010_input_source_get(struct snd_kcontrol *kcontrol, | ||
285 | struct snd_ctl_elem_value *ucontrol) | ||
286 | { | ||
287 | struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); | ||
288 | int channel; | ||
289 | |||
290 | channel = (kcontrol->private_value) & 0xff; | ||
291 | ucontrol->value.enumerated.item[0] = emu->emu1010.input_source[channel]; | ||
292 | return 0; | ||
293 | } | ||
294 | |||
295 | static int snd_emu1010_input_source_put(struct snd_kcontrol *kcontrol, | ||
296 | struct snd_ctl_elem_value *ucontrol) | ||
297 | { | ||
298 | struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); | ||
299 | int change = 0; | ||
300 | unsigned int val; | ||
301 | int channel; | ||
302 | |||
303 | channel = (kcontrol->private_value) & 0xff; | ||
304 | if (emu->emu1010.input_source[channel] != ucontrol->value.enumerated.item[0]) { | ||
305 | val = emu->emu1010.input_source[channel] = ucontrol->value.enumerated.item[0]; | ||
306 | change = 1; | ||
307 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
308 | emu1010_input_dst[channel], emu1010_src_regs[val]); | ||
309 | } | ||
310 | return change; | ||
311 | } | ||
312 | |||
313 | #define EMU1010_SOURCE_OUTPUT(xname,chid) \ | ||
314 | { \ | ||
315 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | ||
316 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ | ||
317 | .info = snd_emu1010_input_output_source_info, \ | ||
318 | .get = snd_emu1010_output_source_get, \ | ||
319 | .put = snd_emu1010_output_source_put, \ | ||
320 | .private_value = chid \ | ||
321 | } | ||
322 | |||
323 | static struct snd_kcontrol_new snd_emu1010_output_enum_ctls[] __devinitdata = { | ||
324 | EMU1010_SOURCE_OUTPUT("Dock DAC1 Left Playback Enum", 0), | ||
325 | EMU1010_SOURCE_OUTPUT("Dock DAC1 Right Playback Enum", 1), | ||
326 | EMU1010_SOURCE_OUTPUT("Dock DAC2 Left Playback Enum", 2), | ||
327 | EMU1010_SOURCE_OUTPUT("Dock DAC2 Right Playback Enum", 3), | ||
328 | EMU1010_SOURCE_OUTPUT("Dock DAC3 Left Playback Enum", 4), | ||
329 | EMU1010_SOURCE_OUTPUT("Dock DAC3 Right Playback Enum", 5), | ||
330 | EMU1010_SOURCE_OUTPUT("Dock DAC4 Left Playback Enum", 6), | ||
331 | EMU1010_SOURCE_OUTPUT("Dock DAC4 Right Playback Enum", 7), | ||
332 | EMU1010_SOURCE_OUTPUT("Dock Phones Left Playback Enum", 8), | ||
333 | EMU1010_SOURCE_OUTPUT("Dock Phones Right Playback Enum", 9), | ||
334 | EMU1010_SOURCE_OUTPUT("Dock SPDIF Left Playback Enum", 0xa), | ||
335 | EMU1010_SOURCE_OUTPUT("Dock SPDIF Right Playback Enum", 0xb), | ||
336 | EMU1010_SOURCE_OUTPUT("1010 SPDIF Left Playback Enum", 0xc), | ||
337 | EMU1010_SOURCE_OUTPUT("1010 SPDIF Right Playback Enum", 0xd), | ||
338 | EMU1010_SOURCE_OUTPUT("0202 DAC Left Playback Enum", 0xe), | ||
339 | EMU1010_SOURCE_OUTPUT("0202 DAC Right Playback Enum", 0xf), | ||
340 | EMU1010_SOURCE_OUTPUT("1010 ADAT 0 Playback Enum", 0x10), | ||
341 | EMU1010_SOURCE_OUTPUT("1010 ADAT 1 Playback Enum", 0x11), | ||
342 | EMU1010_SOURCE_OUTPUT("1010 ADAT 2 Playback Enum", 0x12), | ||
343 | EMU1010_SOURCE_OUTPUT("1010 ADAT 3 Playback Enum", 0x13), | ||
344 | EMU1010_SOURCE_OUTPUT("1010 ADAT 4 Playback Enum", 0x14), | ||
345 | EMU1010_SOURCE_OUTPUT("1010 ADAT 5 Playback Enum", 0x15), | ||
346 | EMU1010_SOURCE_OUTPUT("1010 ADAT 6 Playback Enum", 0x16), | ||
347 | EMU1010_SOURCE_OUTPUT("1010 ADAT 7 Playback Enum", 0x17), | ||
348 | }; | ||
349 | |||
350 | #define EMU1010_SOURCE_INPUT(xname,chid) \ | ||
351 | { \ | ||
352 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | ||
353 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ | ||
354 | .info = snd_emu1010_input_output_source_info, \ | ||
355 | .get = snd_emu1010_input_source_get, \ | ||
356 | .put = snd_emu1010_input_source_put, \ | ||
357 | .private_value = chid \ | ||
358 | } | ||
359 | |||
360 | static struct snd_kcontrol_new snd_emu1010_input_enum_ctls[] __devinitdata = { | ||
361 | EMU1010_SOURCE_INPUT("DSP 0 Capture Enum", 0), | ||
362 | EMU1010_SOURCE_INPUT("DSP 1 Capture Enum", 1), | ||
363 | EMU1010_SOURCE_INPUT("DSP 2 Capture Enum", 2), | ||
364 | EMU1010_SOURCE_INPUT("DSP 3 Capture Enum", 3), | ||
365 | EMU1010_SOURCE_INPUT("DSP 4 Capture Enum", 4), | ||
366 | EMU1010_SOURCE_INPUT("DSP 5 Capture Enum", 5), | ||
367 | EMU1010_SOURCE_INPUT("DSP 6 Capture Enum", 6), | ||
368 | EMU1010_SOURCE_INPUT("DSP 7 Capture Enum", 7), | ||
369 | EMU1010_SOURCE_INPUT("DSP 8 Capture Enum", 8), | ||
370 | EMU1010_SOURCE_INPUT("DSP 9 Capture Enum", 9), | ||
371 | EMU1010_SOURCE_INPUT("DSP A Capture Enum", 0xa), | ||
372 | EMU1010_SOURCE_INPUT("DSP B Capture Enum", 0xb), | ||
373 | EMU1010_SOURCE_INPUT("DSP C Capture Enum", 0xc), | ||
374 | EMU1010_SOURCE_INPUT("DSP D Capture Enum", 0xd), | ||
375 | EMU1010_SOURCE_INPUT("DSP E Capture Enum", 0xe), | ||
376 | EMU1010_SOURCE_INPUT("DSP F Capture Enum", 0xf), | ||
377 | EMU1010_SOURCE_INPUT("DSP 10 Capture Enum", 0x10), | ||
378 | EMU1010_SOURCE_INPUT("DSP 11 Capture Enum", 0x11), | ||
379 | EMU1010_SOURCE_INPUT("DSP 12 Capture Enum", 0x12), | ||
380 | EMU1010_SOURCE_INPUT("DSP 13 Capture Enum", 0x13), | ||
381 | EMU1010_SOURCE_INPUT("DSP 14 Capture Enum", 0x14), | ||
382 | EMU1010_SOURCE_INPUT("DSP 15 Capture Enum", 0x15), | ||
383 | }; | ||
384 | |||
385 | |||
386 | |||
387 | |||
388 | static int snd_emu1010_adc_pads_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | ||
389 | { | ||
390 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
391 | uinfo->count = 1; | ||
392 | uinfo->value.integer.min = 0; | ||
393 | uinfo->value.integer.max = 1; | ||
394 | return 0; | ||
395 | } | ||
396 | |||
397 | static int snd_emu1010_adc_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
398 | { | ||
399 | struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); | ||
400 | unsigned int mask = kcontrol->private_value & 0xff; | ||
401 | ucontrol->value.integer.value[0] = (emu->emu1010.adc_pads & mask) ? 1 : 0; | ||
402 | return 0; | ||
403 | } | ||
404 | |||
405 | static int snd_emu1010_adc_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
406 | { | ||
407 | struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); | ||
408 | unsigned int mask = kcontrol->private_value & 0xff; | ||
409 | unsigned int val, cache; | ||
410 | val = ucontrol->value.integer.value[0]; | ||
411 | cache = emu->emu1010.adc_pads; | ||
412 | if (val == 1) | ||
413 | cache = cache | mask; | ||
414 | else | ||
415 | cache = cache & ~mask; | ||
416 | if (cache != emu->emu1010.adc_pads) { | ||
417 | snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, cache ); | ||
418 | emu->emu1010.adc_pads = cache; | ||
419 | } | ||
420 | |||
421 | return 0; | ||
422 | } | ||
423 | |||
424 | |||
425 | |||
426 | #define EMU1010_ADC_PADS(xname,chid) \ | ||
427 | { \ | ||
428 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | ||
429 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ | ||
430 | .info = snd_emu1010_adc_pads_info, \ | ||
431 | .get = snd_emu1010_adc_pads_get, \ | ||
432 | .put = snd_emu1010_adc_pads_put, \ | ||
433 | .private_value = chid \ | ||
434 | } | ||
435 | |||
436 | static struct snd_kcontrol_new snd_emu1010_adc_pads[] __devinitdata = { | ||
437 | EMU1010_ADC_PADS("ADC1 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD1), | ||
438 | EMU1010_ADC_PADS("ADC2 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD2), | ||
439 | EMU1010_ADC_PADS("ADC3 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD3), | ||
440 | EMU1010_ADC_PADS("ADC1 14dB PAD 0202 Capture Switch", EMU_HANA_0202_ADC_PAD1), | ||
441 | }; | ||
442 | |||
443 | static int snd_emu1010_dac_pads_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | ||
444 | { | ||
445 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
446 | uinfo->count = 1; | ||
447 | uinfo->value.integer.min = 0; | ||
448 | uinfo->value.integer.max = 1; | ||
449 | return 0; | ||
450 | } | ||
451 | |||
452 | static int snd_emu1010_dac_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
453 | { | ||
454 | struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); | ||
455 | unsigned int mask = kcontrol->private_value & 0xff; | ||
456 | ucontrol->value.integer.value[0] = (emu->emu1010.dac_pads & mask) ? 1 : 0; | ||
457 | return 0; | ||
458 | } | ||
459 | |||
460 | static int snd_emu1010_dac_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
461 | { | ||
462 | struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); | ||
463 | unsigned int mask = kcontrol->private_value & 0xff; | ||
464 | unsigned int val, cache; | ||
465 | val = ucontrol->value.integer.value[0]; | ||
466 | cache = emu->emu1010.dac_pads; | ||
467 | if (val == 1) | ||
468 | cache = cache | mask; | ||
469 | else | ||
470 | cache = cache & ~mask; | ||
471 | if (cache != emu->emu1010.dac_pads) { | ||
472 | snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, cache ); | ||
473 | emu->emu1010.dac_pads = cache; | ||
474 | } | ||
475 | |||
476 | return 0; | ||
477 | } | ||
478 | |||
479 | |||
480 | |||
481 | #define EMU1010_DAC_PADS(xname,chid) \ | ||
482 | { \ | ||
483 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | ||
484 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ | ||
485 | .info = snd_emu1010_dac_pads_info, \ | ||
486 | .get = snd_emu1010_dac_pads_get, \ | ||
487 | .put = snd_emu1010_dac_pads_put, \ | ||
488 | .private_value = chid \ | ||
489 | } | ||
490 | |||
491 | static struct snd_kcontrol_new snd_emu1010_dac_pads[] __devinitdata = { | ||
492 | EMU1010_DAC_PADS("DAC1 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD1), | ||
493 | EMU1010_DAC_PADS("DAC2 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD2), | ||
494 | EMU1010_DAC_PADS("DAC3 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD3), | ||
495 | EMU1010_DAC_PADS("DAC4 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD4), | ||
496 | EMU1010_DAC_PADS("DAC1 0202 14dB PAD Playback Switch", EMU_HANA_0202_DAC_PAD1), | ||
497 | }; | ||
498 | |||
499 | |||
500 | static int snd_emu1010_internal_clock_info(struct snd_kcontrol *kcontrol, | ||
501 | struct snd_ctl_elem_info *uinfo) | ||
502 | { | ||
503 | static char *texts[2] = { | ||
504 | "44100", "48000" | ||
505 | }; | ||
506 | |||
507 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
508 | uinfo->count = 1; | ||
509 | uinfo->value.enumerated.items = 2; | ||
510 | if (uinfo->value.enumerated.item > 1) | ||
511 | uinfo->value.enumerated.item = 1; | ||
512 | strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); | ||
513 | return 0; | ||
514 | } | ||
515 | |||
516 | static int snd_emu1010_internal_clock_get(struct snd_kcontrol *kcontrol, | ||
517 | struct snd_ctl_elem_value *ucontrol) | ||
518 | { | ||
519 | struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); | ||
520 | |||
521 | ucontrol->value.enumerated.item[0] = emu->emu1010.internal_clock; | ||
522 | return 0; | ||
523 | } | ||
524 | |||
525 | static int snd_emu1010_internal_clock_put(struct snd_kcontrol *kcontrol, | ||
526 | struct snd_ctl_elem_value *ucontrol) | ||
527 | { | ||
528 | struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); | ||
529 | unsigned int val; | ||
530 | int change = 0; | ||
531 | |||
532 | val = ucontrol->value.enumerated.item[0] ; | ||
533 | change = (emu->emu1010.internal_clock != val); | ||
534 | if (change) { | ||
535 | emu->emu1010.internal_clock = val; | ||
536 | switch (val) { | ||
537 | case 0: | ||
538 | /* 44100 */ | ||
539 | /* Mute all */ | ||
540 | snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); | ||
541 | /* Default fallback clock 48kHz */ | ||
542 | snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_44_1K ); | ||
543 | /* Word Clock source, Internal 44.1kHz x1 */ | ||
544 | snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, | ||
545 | EMU_HANA_WCLOCK_INT_44_1K | EMU_HANA_WCLOCK_1X ); | ||
546 | /* Set LEDs on Audio Dock */ | ||
547 | snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, | ||
548 | EMU_HANA_DOCK_LEDS_2_44K | EMU_HANA_DOCK_LEDS_2_LOCK ); | ||
549 | /* Allow DLL to settle */ | ||
550 | msleep(10); | ||
551 | /* Unmute all */ | ||
552 | snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); | ||
553 | break; | ||
554 | case 1: | ||
555 | /* 48000 */ | ||
556 | /* Mute all */ | ||
557 | snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); | ||
558 | /* Default fallback clock 48kHz */ | ||
559 | snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K ); | ||
560 | /* Word Clock source, Internal 48kHz x1 */ | ||
561 | snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, | ||
562 | EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_1X ); | ||
563 | /* Set LEDs on Audio Dock */ | ||
564 | snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, | ||
565 | EMU_HANA_DOCK_LEDS_2_48K | EMU_HANA_DOCK_LEDS_2_LOCK ); | ||
566 | /* Allow DLL to settle */ | ||
567 | msleep(10); | ||
568 | /* Unmute all */ | ||
569 | snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); | ||
570 | break; | ||
571 | } | ||
572 | } | ||
573 | return change; | ||
574 | } | ||
575 | |||
576 | static struct snd_kcontrol_new snd_emu1010_internal_clock = | ||
577 | { | ||
578 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
579 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
580 | .name = "Clock Internal Rate", | ||
581 | .count = 1, | ||
582 | .info = snd_emu1010_internal_clock_info, | ||
583 | .get = snd_emu1010_internal_clock_get, | ||
584 | .put = snd_emu1010_internal_clock_put | ||
585 | }; | ||
586 | |||
587 | static int snd_audigy_i2c_capture_source_info(struct snd_kcontrol *kcontrol, | ||
588 | struct snd_ctl_elem_info *uinfo) | ||
589 | { | ||
590 | #if 0 | ||
591 | static char *texts[4] = { | ||
592 | "Unknown1", "Unknown2", "Mic", "Line" | ||
593 | }; | ||
594 | #endif | ||
595 | static char *texts[2] = { | ||
596 | "Mic", "Line" | ||
597 | }; | ||
598 | |||
599 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
600 | uinfo->count = 1; | ||
601 | uinfo->value.enumerated.items = 2; | ||
602 | if (uinfo->value.enumerated.item > 1) | ||
603 | uinfo->value.enumerated.item = 1; | ||
604 | strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); | ||
605 | return 0; | ||
606 | } | ||
607 | |||
608 | static int snd_audigy_i2c_capture_source_get(struct snd_kcontrol *kcontrol, | ||
609 | struct snd_ctl_elem_value *ucontrol) | ||
610 | { | ||
611 | struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); | ||
612 | |||
613 | ucontrol->value.enumerated.item[0] = emu->i2c_capture_source; | ||
614 | return 0; | ||
615 | } | ||
616 | |||
617 | static int snd_audigy_i2c_capture_source_put(struct snd_kcontrol *kcontrol, | ||
618 | struct snd_ctl_elem_value *ucontrol) | ||
619 | { | ||
620 | struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); | ||
621 | unsigned int source_id; | ||
622 | unsigned int ngain, ogain; | ||
623 | u32 gpio; | ||
624 | int change = 0; | ||
625 | unsigned long flags; | ||
626 | u32 source; | ||
627 | /* If the capture source has changed, | ||
628 | * update the capture volume from the cached value | ||
629 | * for the particular source. | ||
630 | */ | ||
631 | source_id = ucontrol->value.enumerated.item[0]; /* Use 2 and 3 */ | ||
632 | change = (emu->i2c_capture_source != source_id); | ||
633 | if (change) { | ||
634 | snd_emu10k1_i2c_write(emu, ADC_MUX, 0); /* Mute input */ | ||
635 | spin_lock_irqsave(&emu->emu_lock, flags); | ||
636 | gpio = inl(emu->port + A_IOCFG); | ||
637 | if (source_id==0) | ||
638 | outl(gpio | 0x4, emu->port + A_IOCFG); | ||
639 | else | ||
640 | outl(gpio & ~0x4, emu->port + A_IOCFG); | ||
641 | spin_unlock_irqrestore(&emu->emu_lock, flags); | ||
642 | |||
643 | ngain = emu->i2c_capture_volume[source_id][0]; /* Left */ | ||
644 | ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */ | ||
645 | if (ngain != ogain) | ||
646 | snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff)); | ||
647 | ngain = emu->i2c_capture_volume[source_id][1]; /* Right */ | ||
648 | ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Right */ | ||
649 | if (ngain != ogain) | ||
650 | snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff)); | ||
651 | |||
652 | source = 1 << (source_id + 2); | ||
653 | snd_emu10k1_i2c_write(emu, ADC_MUX, source); /* Set source */ | ||
654 | emu->i2c_capture_source = source_id; | ||
655 | } | ||
656 | return change; | ||
657 | } | ||
658 | |||
659 | static struct snd_kcontrol_new snd_audigy_i2c_capture_source = | ||
660 | { | ||
661 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
662 | .name = "Capture Source", | ||
663 | .info = snd_audigy_i2c_capture_source_info, | ||
664 | .get = snd_audigy_i2c_capture_source_get, | ||
665 | .put = snd_audigy_i2c_capture_source_put | ||
666 | }; | ||
667 | |||
668 | static int snd_audigy_i2c_volume_info(struct snd_kcontrol *kcontrol, | ||
669 | struct snd_ctl_elem_info *uinfo) | ||
670 | { | ||
671 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
672 | uinfo->count = 2; | ||
673 | uinfo->value.integer.min = 0; | ||
674 | uinfo->value.integer.max = 255; | ||
675 | return 0; | ||
676 | } | ||
677 | |||
678 | static int snd_audigy_i2c_volume_get(struct snd_kcontrol *kcontrol, | ||
679 | struct snd_ctl_elem_value *ucontrol) | ||
680 | { | ||
681 | struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); | ||
682 | int source_id; | ||
683 | |||
684 | source_id = kcontrol->private_value; | ||
685 | |||
686 | ucontrol->value.integer.value[0] = emu->i2c_capture_volume[source_id][0]; | ||
687 | ucontrol->value.integer.value[1] = emu->i2c_capture_volume[source_id][1]; | ||
688 | return 0; | ||
689 | } | ||
690 | |||
691 | static int snd_audigy_i2c_volume_put(struct snd_kcontrol *kcontrol, | ||
692 | struct snd_ctl_elem_value *ucontrol) | ||
693 | { | ||
694 | struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); | ||
695 | unsigned int ogain; | ||
696 | unsigned int ngain; | ||
697 | int source_id; | ||
698 | int change = 0; | ||
699 | |||
700 | source_id = kcontrol->private_value; | ||
701 | ogain = emu->i2c_capture_volume[source_id][0]; /* Left */ | ||
702 | ngain = ucontrol->value.integer.value[0]; | ||
703 | if (ngain > 0xff) | ||
704 | return 0; | ||
705 | if (ogain != ngain) { | ||
706 | if (emu->i2c_capture_source == source_id) | ||
707 | snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff) ); | ||
708 | emu->i2c_capture_volume[source_id][0] = ucontrol->value.integer.value[0]; | ||
709 | change = 1; | ||
710 | } | ||
711 | ogain = emu->i2c_capture_volume[source_id][1]; /* Right */ | ||
712 | ngain = ucontrol->value.integer.value[1]; | ||
713 | if (ngain > 0xff) | ||
714 | return 0; | ||
715 | if (ogain != ngain) { | ||
716 | if (emu->i2c_capture_source == source_id) | ||
717 | snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff)); | ||
718 | emu->i2c_capture_volume[source_id][1] = ucontrol->value.integer.value[1]; | ||
719 | change = 1; | ||
720 | } | ||
721 | |||
722 | return change; | ||
723 | } | ||
724 | |||
725 | #define I2C_VOLUME(xname,chid) \ | ||
726 | { \ | ||
727 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | ||
728 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ | ||
729 | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ | ||
730 | .info = snd_audigy_i2c_volume_info, \ | ||
731 | .get = snd_audigy_i2c_volume_get, \ | ||
732 | .put = snd_audigy_i2c_volume_put, \ | ||
733 | .tlv = { .p = snd_audigy_db_scale2 }, \ | ||
734 | .private_value = chid \ | ||
735 | } | ||
736 | |||
737 | |||
738 | static struct snd_kcontrol_new snd_audigy_i2c_volume_ctls[] __devinitdata = { | ||
739 | I2C_VOLUME("Mic Capture Volume", 0), | ||
740 | I2C_VOLUME("Line Capture Volume", 0) | ||
741 | }; | ||
742 | |||
71 | #if 0 | 743 | #if 0 |
72 | static int snd_audigy_spdif_output_rate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | 744 | static int snd_audigy_spdif_output_rate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) |
73 | { | 745 | { |
@@ -668,7 +1340,9 @@ static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol, | |||
668 | int change = 0; | 1340 | int change = 0; |
669 | 1341 | ||
670 | spin_lock_irqsave(&emu->reg_lock, flags); | 1342 | spin_lock_irqsave(&emu->reg_lock, flags); |
671 | if (emu->audigy) { | 1343 | if ( emu->card_capabilities->i2c_adc) { |
1344 | /* Do nothing for Audigy 2 ZS Notebook */ | ||
1345 | } else if (emu->audigy) { | ||
672 | reg = inl(emu->port + A_IOCFG); | 1346 | reg = inl(emu->port + A_IOCFG); |
673 | val = ucontrol->value.integer.value[0] ? A_IOCFG_GPOUT0 : 0; | 1347 | val = ucontrol->value.integer.value[0] ? A_IOCFG_GPOUT0 : 0; |
674 | change = (reg & A_IOCFG_GPOUT0) != val; | 1348 | change = (reg & A_IOCFG_GPOUT0) != val; |
@@ -806,6 +1480,24 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, | |||
806 | "AMic Playback Volume", "Mic Playback Volume", | 1480 | "AMic Playback Volume", "Mic Playback Volume", |
807 | NULL | 1481 | NULL |
808 | }; | 1482 | }; |
1483 | static char *audigy_rename_ctls_i2c_adc[] = { | ||
1484 | //"Analog Mix Capture Volume","OLD Analog Mix Capture Volume", | ||
1485 | "Line Capture Volume", "Analog Mix Capture Volume", | ||
1486 | "Wave Playback Volume", "OLD PCM Playback Volume", | ||
1487 | "Wave Master Playback Volume", "Master Playback Volume", | ||
1488 | "AMic Playback Volume", "Old Mic Playback Volume", | ||
1489 | "CD Capture Volume", "IEC958 Optical Capture Volume", | ||
1490 | NULL | ||
1491 | }; | ||
1492 | static char *audigy_remove_ctls_i2c_adc[] = { | ||
1493 | /* On the Audigy2 ZS Notebook | ||
1494 | * Capture via WM8775 */ | ||
1495 | "Mic Capture Volume", | ||
1496 | "Analog Mix Capture Volume", | ||
1497 | "Aux Capture Volume", | ||
1498 | "IEC958 Optical Capture Volume", | ||
1499 | NULL | ||
1500 | }; | ||
809 | static char *audigy_remove_ctls_1361t_adc[] = { | 1501 | static char *audigy_remove_ctls_1361t_adc[] = { |
810 | /* On the Audigy2 the AC97 playback is piped into | 1502 | /* On the Audigy2 the AC97 playback is piped into |
811 | * the Philips ADC for 24bit capture */ | 1503 | * the Philips ADC for 24bit capture */ |
@@ -890,6 +1582,7 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, | |||
890 | if (emu->ac97->id == AC97_ID_STAC9758) { | 1582 | if (emu->ac97->id == AC97_ID_STAC9758) { |
891 | emu->rear_ac97 = 1; | 1583 | emu->rear_ac97 = 1; |
892 | snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE|AC97SLOT_REAR_LEFT|AC97SLOT_REAR_RIGHT); | 1584 | snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE|AC97SLOT_REAR_LEFT|AC97SLOT_REAR_RIGHT); |
1585 | snd_ac97_write_cache(emu->ac97, AC97_HEADPHONE, 0x0202); | ||
893 | } | 1586 | } |
894 | /* remove unused AC97 controls */ | 1587 | /* remove unused AC97 controls */ |
895 | snd_ac97_write_cache(emu->ac97, AC97_SURROUND_MASTER, 0x0202); | 1588 | snd_ac97_write_cache(emu->ac97, AC97_SURROUND_MASTER, 0x0202); |
@@ -898,6 +1591,10 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, | |||
898 | } | 1591 | } |
899 | for (; *c; c++) | 1592 | for (; *c; c++) |
900 | remove_ctl(card, *c); | 1593 | remove_ctl(card, *c); |
1594 | } else if (emu->card_capabilities->i2c_adc) { | ||
1595 | c = audigy_remove_ctls_i2c_adc; | ||
1596 | for (; *c; c++) | ||
1597 | remove_ctl(card, *c); | ||
901 | } else { | 1598 | } else { |
902 | no_ac97: | 1599 | no_ac97: |
903 | if (emu->card_capabilities->ecard) | 1600 | if (emu->card_capabilities->ecard) |
@@ -911,6 +1608,8 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, | |||
911 | if (emu->audigy) | 1608 | if (emu->audigy) |
912 | if (emu->card_capabilities->adc_1361t) | 1609 | if (emu->card_capabilities->adc_1361t) |
913 | c = audigy_rename_ctls_1361t_adc; | 1610 | c = audigy_rename_ctls_1361t_adc; |
1611 | else if (emu->card_capabilities->i2c_adc) | ||
1612 | c = audigy_rename_ctls_i2c_adc; | ||
914 | else | 1613 | else |
915 | c = audigy_rename_ctls; | 1614 | c = audigy_rename_ctls; |
916 | else | 1615 | else |
@@ -1021,7 +1720,7 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, | |||
1021 | return err; | 1720 | return err; |
1022 | } | 1721 | } |
1023 | 1722 | ||
1024 | if ( emu->card_capabilities->emu1212m) { | 1723 | if ( emu->card_capabilities->emu1010) { |
1025 | ; /* Disable the snd_audigy_spdif_shared_spdif */ | 1724 | ; /* Disable the snd_audigy_spdif_shared_spdif */ |
1026 | } else if (emu->audigy) { | 1725 | } else if (emu->audigy) { |
1027 | if ((kctl = snd_ctl_new1(&snd_audigy_shared_spdif, emu)) == NULL) | 1726 | if ((kctl = snd_ctl_new1(&snd_audigy_shared_spdif, emu)) == NULL) |
@@ -1045,6 +1744,48 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, | |||
1045 | if ((err = snd_p16v_mixer(emu))) | 1744 | if ((err = snd_p16v_mixer(emu))) |
1046 | return err; | 1745 | return err; |
1047 | } | 1746 | } |
1747 | |||
1748 | if ( emu->card_capabilities->emu1010) { | ||
1749 | int i; | ||
1750 | |||
1751 | for (i = 0; i < ARRAY_SIZE(snd_emu1010_output_enum_ctls); i++) { | ||
1752 | err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_output_enum_ctls[i], emu)); | ||
1753 | if (err < 0) | ||
1754 | return err; | ||
1755 | } | ||
1756 | for (i = 0; i < ARRAY_SIZE(snd_emu1010_input_enum_ctls); i++) { | ||
1757 | err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_input_enum_ctls[i], emu)); | ||
1758 | if (err < 0) | ||
1759 | return err; | ||
1760 | } | ||
1761 | for (i = 0; i < ARRAY_SIZE(snd_emu1010_adc_pads); i++) { | ||
1762 | err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_adc_pads[i], emu)); | ||
1763 | if (err < 0) | ||
1764 | return err; | ||
1765 | } | ||
1766 | for (i = 0; i < ARRAY_SIZE(snd_emu1010_dac_pads); i++) { | ||
1767 | err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_dac_pads[i], emu)); | ||
1768 | if (err < 0) | ||
1769 | return err; | ||
1770 | } | ||
1771 | err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_internal_clock, emu)); | ||
1772 | if (err < 0) | ||
1773 | return err; | ||
1774 | } | ||
1775 | |||
1776 | if ( emu->card_capabilities->i2c_adc) { | ||
1777 | int i; | ||
1778 | |||
1779 | err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_capture_source, emu)); | ||
1780 | if (err < 0) | ||
1781 | return err; | ||
1782 | |||
1783 | for (i = 0; i < ARRAY_SIZE(snd_audigy_i2c_volume_ctls); i++) { | ||
1784 | err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_volume_ctls[i], emu)); | ||
1785 | if (err < 0) | ||
1786 | return err; | ||
1787 | } | ||
1788 | } | ||
1048 | 1789 | ||
1049 | return 0; | 1790 | return 0; |
1050 | } | 1791 | } |
diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index 717e92ec9e0a..ab4f5df5241b 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c | |||
@@ -147,7 +147,7 @@ static int snd_emu10k1_pcm_channel_alloc(struct snd_emu10k1_pcm * epcm, int voic | |||
147 | 1, | 147 | 1, |
148 | &epcm->extra); | 148 | &epcm->extra); |
149 | if (err < 0) { | 149 | if (err < 0) { |
150 | // printk("pcm_channel_alloc: failed extra: voices=%d, frame=%d\n", voices, frame); | 150 | /* printk("pcm_channel_alloc: failed extra: voices=%d, frame=%d\n", voices, frame); */ |
151 | for (i = 0; i < voices; i++) { | 151 | for (i = 0; i < voices; i++) { |
152 | snd_emu10k1_voice_free(epcm->emu, epcm->voices[i]); | 152 | snd_emu10k1_voice_free(epcm->emu, epcm->voices[i]); |
153 | epcm->voices[i] = NULL; | 153 | epcm->voices[i] = NULL; |
@@ -339,7 +339,7 @@ static void snd_emu10k1_pcm_init_voice(struct snd_emu10k1 *emu, | |||
339 | } | 339 | } |
340 | } | 340 | } |
341 | 341 | ||
342 | // setup routing | 342 | /* setup routing */ |
343 | if (emu->audigy) { | 343 | if (emu->audigy) { |
344 | snd_emu10k1_ptr_write(emu, A_FXRT1, voice, | 344 | snd_emu10k1_ptr_write(emu, A_FXRT1, voice, |
345 | snd_emu10k1_compose_audigy_fxrt1(send_routing)); | 345 | snd_emu10k1_compose_audigy_fxrt1(send_routing)); |
@@ -353,12 +353,15 @@ static void snd_emu10k1_pcm_init_voice(struct snd_emu10k1 *emu, | |||
353 | } else | 353 | } else |
354 | snd_emu10k1_ptr_write(emu, FXRT, voice, | 354 | snd_emu10k1_ptr_write(emu, FXRT, voice, |
355 | snd_emu10k1_compose_send_routing(send_routing)); | 355 | snd_emu10k1_compose_send_routing(send_routing)); |
356 | // Stop CA | 356 | /* Stop CA */ |
357 | // Assumption that PT is already 0 so no harm overwriting | 357 | /* Assumption that PT is already 0 so no harm overwriting */ |
358 | snd_emu10k1_ptr_write(emu, PTRX, voice, (send_amount[0] << 8) | send_amount[1]); | 358 | snd_emu10k1_ptr_write(emu, PTRX, voice, (send_amount[0] << 8) | send_amount[1]); |
359 | snd_emu10k1_ptr_write(emu, DSL, voice, end_addr | (send_amount[3] << 24)); | 359 | snd_emu10k1_ptr_write(emu, DSL, voice, end_addr | (send_amount[3] << 24)); |
360 | snd_emu10k1_ptr_write(emu, PSST, voice, start_addr | (send_amount[2] << 24)); | 360 | snd_emu10k1_ptr_write(emu, PSST, voice, start_addr | (send_amount[2] << 24)); |
361 | pitch_target = emu10k1_calc_pitch_target(runtime->rate); | 361 | if (emu->card_capabilities->emu1010) |
362 | pitch_target = PITCH_48000; /* Disable interpolators on emu1010 card */ | ||
363 | else | ||
364 | pitch_target = emu10k1_calc_pitch_target(runtime->rate); | ||
362 | if (extra) | 365 | if (extra) |
363 | snd_emu10k1_ptr_write(emu, CCCA, voice, start_addr | | 366 | snd_emu10k1_ptr_write(emu, CCCA, voice, start_addr | |
364 | emu10k1_select_interprom(pitch_target) | | 367 | emu10k1_select_interprom(pitch_target) | |
@@ -367,14 +370,14 @@ static void snd_emu10k1_pcm_init_voice(struct snd_emu10k1 *emu, | |||
367 | snd_emu10k1_ptr_write(emu, CCCA, voice, (start_addr + ccis) | | 370 | snd_emu10k1_ptr_write(emu, CCCA, voice, (start_addr + ccis) | |
368 | emu10k1_select_interprom(pitch_target) | | 371 | emu10k1_select_interprom(pitch_target) | |
369 | (w_16 ? 0 : CCCA_8BITSELECT)); | 372 | (w_16 ? 0 : CCCA_8BITSELECT)); |
370 | // Clear filter delay memory | 373 | /* Clear filter delay memory */ |
371 | snd_emu10k1_ptr_write(emu, Z1, voice, 0); | 374 | snd_emu10k1_ptr_write(emu, Z1, voice, 0); |
372 | snd_emu10k1_ptr_write(emu, Z2, voice, 0); | 375 | snd_emu10k1_ptr_write(emu, Z2, voice, 0); |
373 | // invalidate maps | 376 | /* invalidate maps */ |
374 | silent_page = ((unsigned int)emu->silent_page.addr << 1) | MAP_PTI_MASK; | 377 | silent_page = ((unsigned int)emu->silent_page.addr << 1) | MAP_PTI_MASK; |
375 | snd_emu10k1_ptr_write(emu, MAPA, voice, silent_page); | 378 | snd_emu10k1_ptr_write(emu, MAPA, voice, silent_page); |
376 | snd_emu10k1_ptr_write(emu, MAPB, voice, silent_page); | 379 | snd_emu10k1_ptr_write(emu, MAPB, voice, silent_page); |
377 | // modulation envelope | 380 | /* modulation envelope */ |
378 | snd_emu10k1_ptr_write(emu, CVCF, voice, 0xffff); | 381 | snd_emu10k1_ptr_write(emu, CVCF, voice, 0xffff); |
379 | snd_emu10k1_ptr_write(emu, VTFT, voice, 0xffff); | 382 | snd_emu10k1_ptr_write(emu, VTFT, voice, 0xffff); |
380 | snd_emu10k1_ptr_write(emu, ATKHLDM, voice, 0); | 383 | snd_emu10k1_ptr_write(emu, ATKHLDM, voice, 0); |
@@ -385,12 +388,12 @@ static void snd_emu10k1_pcm_init_voice(struct snd_emu10k1 *emu, | |||
385 | snd_emu10k1_ptr_write(emu, TREMFRQ, voice, 0); | 388 | snd_emu10k1_ptr_write(emu, TREMFRQ, voice, 0); |
386 | snd_emu10k1_ptr_write(emu, FM2FRQ2, voice, 0); | 389 | snd_emu10k1_ptr_write(emu, FM2FRQ2, voice, 0); |
387 | snd_emu10k1_ptr_write(emu, ENVVAL, voice, 0x8000); | 390 | snd_emu10k1_ptr_write(emu, ENVVAL, voice, 0x8000); |
388 | // volume envelope | 391 | /* volume envelope */ |
389 | snd_emu10k1_ptr_write(emu, ATKHLDV, voice, 0x7f7f); | 392 | snd_emu10k1_ptr_write(emu, ATKHLDV, voice, 0x7f7f); |
390 | snd_emu10k1_ptr_write(emu, ENVVOL, voice, 0x0000); | 393 | snd_emu10k1_ptr_write(emu, ENVVOL, voice, 0x0000); |
391 | // filter envelope | 394 | /* filter envelope */ |
392 | snd_emu10k1_ptr_write(emu, PEFE_FILTERAMOUNT, voice, 0x7f); | 395 | snd_emu10k1_ptr_write(emu, PEFE_FILTERAMOUNT, voice, 0x7f); |
393 | // pitch envelope | 396 | /* pitch envelope */ |
394 | snd_emu10k1_ptr_write(emu, PEFE_PITCHAMOUNT, voice, 0); | 397 | snd_emu10k1_ptr_write(emu, PEFE_PITCHAMOUNT, voice, 0); |
395 | 398 | ||
396 | spin_unlock_irqrestore(&emu->reg_lock, flags); | 399 | spin_unlock_irqrestore(&emu->reg_lock, flags); |
@@ -468,7 +471,7 @@ static int snd_emu10k1_efx_playback_hw_free(struct snd_pcm_substream *substream) | |||
468 | snd_emu10k1_voice_free(epcm->emu, epcm->extra); | 471 | snd_emu10k1_voice_free(epcm->emu, epcm->extra); |
469 | epcm->extra = NULL; | 472 | epcm->extra = NULL; |
470 | } | 473 | } |
471 | for (i=0; i < NUM_EFX_PLAYBACK; i++) { | 474 | for (i = 0; i < NUM_EFX_PLAYBACK; i++) { |
472 | if (epcm->voices[i]) { | 475 | if (epcm->voices[i]) { |
473 | snd_emu10k1_voice_free(epcm->emu, epcm->voices[i]); | 476 | snd_emu10k1_voice_free(epcm->emu, epcm->voices[i]); |
474 | epcm->voices[i] = NULL; | 477 | epcm->voices[i] = NULL; |
@@ -637,7 +640,7 @@ static void snd_emu10k1_playback_invalidate_cache(struct snd_emu10k1 *emu, int e | |||
637 | stereo = (!extra && runtime->channels == 2); | 640 | stereo = (!extra && runtime->channels == 2); |
638 | sample = snd_pcm_format_width(runtime->format) == 16 ? 0 : 0x80808080; | 641 | sample = snd_pcm_format_width(runtime->format) == 16 ? 0 : 0x80808080; |
639 | ccis = emu10k1_ccis(stereo, sample == 0); | 642 | ccis = emu10k1_ccis(stereo, sample == 0); |
640 | // set cs to 2 * number of cache registers beside the invalidated | 643 | /* set cs to 2 * number of cache registers beside the invalidated */ |
641 | cs = (sample == 0) ? (32-ccis) : (64-ccis+1) >> 1; | 644 | cs = (sample == 0) ? (32-ccis) : (64-ccis+1) >> 1; |
642 | if (cs > 16) cs = 16; | 645 | if (cs > 16) cs = 16; |
643 | for (i = 0; i < cs; i++) { | 646 | for (i = 0; i < cs; i++) { |
@@ -646,14 +649,14 @@ static void snd_emu10k1_playback_invalidate_cache(struct snd_emu10k1 *emu, int e | |||
646 | snd_emu10k1_ptr_write(emu, CD0 + i, voice + 1, sample); | 649 | snd_emu10k1_ptr_write(emu, CD0 + i, voice + 1, sample); |
647 | } | 650 | } |
648 | } | 651 | } |
649 | // reset cache | 652 | /* reset cache */ |
650 | snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice, 0); | 653 | snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice, 0); |
651 | snd_emu10k1_ptr_write(emu, CCR_READADDRESS, voice, cra); | 654 | snd_emu10k1_ptr_write(emu, CCR_READADDRESS, voice, cra); |
652 | if (stereo) { | 655 | if (stereo) { |
653 | snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice + 1, 0); | 656 | snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice + 1, 0); |
654 | snd_emu10k1_ptr_write(emu, CCR_READADDRESS, voice + 1, cra); | 657 | snd_emu10k1_ptr_write(emu, CCR_READADDRESS, voice + 1, cra); |
655 | } | 658 | } |
656 | // fill cache | 659 | /* fill cache */ |
657 | snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice, ccis); | 660 | snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice, ccis); |
658 | if (stereo) { | 661 | if (stereo) { |
659 | snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice+1, ccis); | 662 | snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice+1, ccis); |
@@ -698,7 +701,10 @@ static void snd_emu10k1_playback_trigger_voice(struct snd_emu10k1 *emu, struct s | |||
698 | voice = evoice->number; | 701 | voice = evoice->number; |
699 | 702 | ||
700 | pitch = snd_emu10k1_rate_to_pitch(runtime->rate) >> 8; | 703 | pitch = snd_emu10k1_rate_to_pitch(runtime->rate) >> 8; |
701 | pitch_target = emu10k1_calc_pitch_target(runtime->rate); | 704 | if (emu->card_capabilities->emu1010) |
705 | pitch_target = PITCH_48000; /* Disable interpolators on emu1010 card */ | ||
706 | else | ||
707 | pitch_target = emu10k1_calc_pitch_target(runtime->rate); | ||
702 | snd_emu10k1_ptr_write(emu, PTRX_PITCHTARGET, voice, pitch_target); | 708 | snd_emu10k1_ptr_write(emu, PTRX_PITCHTARGET, voice, pitch_target); |
703 | if (master || evoice->epcm->type == PLAYBACK_EFX) | 709 | if (master || evoice->epcm->type == PLAYBACK_EFX) |
704 | snd_emu10k1_ptr_write(emu, CPF_CURRENTPITCH, voice, pitch_target); | 710 | snd_emu10k1_ptr_write(emu, CPF_CURRENTPITCH, voice, pitch_target); |
@@ -732,7 +738,7 @@ static int snd_emu10k1_playback_trigger(struct snd_pcm_substream *substream, | |||
732 | struct snd_emu10k1_pcm_mixer *mix; | 738 | struct snd_emu10k1_pcm_mixer *mix; |
733 | int result = 0; | 739 | int result = 0; |
734 | 740 | ||
735 | // printk("trigger - emu10k1 = 0x%x, cmd = %i, pointer = %i\n", (int)emu, cmd, substream->ops->pointer(substream)); | 741 | /* printk("trigger - emu10k1 = 0x%x, cmd = %i, pointer = %i\n", (int)emu, cmd, substream->ops->pointer(substream)); */ |
736 | spin_lock(&emu->reg_lock); | 742 | spin_lock(&emu->reg_lock); |
737 | switch (cmd) { | 743 | switch (cmd) { |
738 | case SNDRV_PCM_TRIGGER_START: | 744 | case SNDRV_PCM_TRIGGER_START: |
@@ -778,10 +784,10 @@ static int snd_emu10k1_capture_trigger(struct snd_pcm_substream *substream, | |||
778 | switch (cmd) { | 784 | switch (cmd) { |
779 | case SNDRV_PCM_TRIGGER_START: | 785 | case SNDRV_PCM_TRIGGER_START: |
780 | case SNDRV_PCM_TRIGGER_RESUME: | 786 | case SNDRV_PCM_TRIGGER_RESUME: |
781 | // hmm this should cause full and half full interrupt to be raised? | 787 | /* hmm this should cause full and half full interrupt to be raised? */ |
782 | outl(epcm->capture_ipr, emu->port + IPR); | 788 | outl(epcm->capture_ipr, emu->port + IPR); |
783 | snd_emu10k1_intr_enable(emu, epcm->capture_inte); | 789 | snd_emu10k1_intr_enable(emu, epcm->capture_inte); |
784 | // printk("adccr = 0x%x, adcbs = 0x%x\n", epcm->adccr, epcm->adcbs); | 790 | /* printk("adccr = 0x%x, adcbs = 0x%x\n", epcm->adccr, epcm->adcbs); */ |
785 | switch (epcm->type) { | 791 | switch (epcm->type) { |
786 | case CAPTURE_AC97ADC: | 792 | case CAPTURE_AC97ADC: |
787 | snd_emu10k1_ptr_write(emu, ADCCR, 0, epcm->capture_cr_val); | 793 | snd_emu10k1_ptr_write(emu, ADCCR, 0, epcm->capture_cr_val); |
@@ -790,6 +796,7 @@ static int snd_emu10k1_capture_trigger(struct snd_pcm_substream *substream, | |||
790 | if (emu->audigy) { | 796 | if (emu->audigy) { |
791 | snd_emu10k1_ptr_write(emu, A_FXWC1, 0, epcm->capture_cr_val); | 797 | snd_emu10k1_ptr_write(emu, A_FXWC1, 0, epcm->capture_cr_val); |
792 | snd_emu10k1_ptr_write(emu, A_FXWC2, 0, epcm->capture_cr_val2); | 798 | snd_emu10k1_ptr_write(emu, A_FXWC2, 0, epcm->capture_cr_val2); |
799 | snd_printdd("cr_val=0x%x, cr_val2=0x%x\n", epcm->capture_cr_val, epcm->capture_cr_val2); | ||
793 | } else | 800 | } else |
794 | snd_emu10k1_ptr_write(emu, FXWC, 0, epcm->capture_cr_val); | 801 | snd_emu10k1_ptr_write(emu, FXWC, 0, epcm->capture_cr_val); |
795 | break; | 802 | break; |
@@ -851,7 +858,7 @@ static snd_pcm_uframes_t snd_emu10k1_playback_pointer(struct snd_pcm_substream * | |||
851 | ptr -= runtime->buffer_size; | 858 | ptr -= runtime->buffer_size; |
852 | } | 859 | } |
853 | #endif | 860 | #endif |
854 | // printk("ptr = 0x%x, buffer_size = 0x%x, period_size = 0x%x\n", ptr, runtime->buffer_size, runtime->period_size); | 861 | /* printk("ptr = 0x%x, buffer_size = 0x%x, period_size = 0x%x\n", ptr, runtime->buffer_size, runtime->period_size); */ |
855 | return ptr; | 862 | return ptr; |
856 | } | 863 | } |
857 | 864 | ||
@@ -868,7 +875,7 @@ static int snd_emu10k1_efx_playback_trigger(struct snd_pcm_substream *substream, | |||
868 | spin_lock(&emu->reg_lock); | 875 | spin_lock(&emu->reg_lock); |
869 | switch (cmd) { | 876 | switch (cmd) { |
870 | case SNDRV_PCM_TRIGGER_START: | 877 | case SNDRV_PCM_TRIGGER_START: |
871 | // prepare voices | 878 | /* prepare voices */ |
872 | for (i = 0; i < NUM_EFX_PLAYBACK; i++) { | 879 | for (i = 0; i < NUM_EFX_PLAYBACK; i++) { |
873 | snd_emu10k1_playback_invalidate_cache(emu, 0, epcm->voices[i]); | 880 | snd_emu10k1_playback_invalidate_cache(emu, 0, epcm->voices[i]); |
874 | } | 881 | } |
@@ -917,7 +924,7 @@ static snd_pcm_uframes_t snd_emu10k1_capture_pointer(struct snd_pcm_substream *s | |||
917 | if (!epcm->running) | 924 | if (!epcm->running) |
918 | return 0; | 925 | return 0; |
919 | if (epcm->first_ptr) { | 926 | if (epcm->first_ptr) { |
920 | udelay(50); // hack, it takes awhile until capture is started | 927 | udelay(50); /* hack, it takes awhile until capture is started */ |
921 | epcm->first_ptr = 0; | 928 | epcm->first_ptr = 0; |
922 | } | 929 | } |
923 | ptr = snd_emu10k1_ptr_read(emu, epcm->capture_idx_reg, 0) & 0x0000ffff; | 930 | ptr = snd_emu10k1_ptr_read(emu, epcm->capture_idx_reg, 0) & 0x0000ffff; |
@@ -972,6 +979,28 @@ static struct snd_pcm_hardware snd_emu10k1_capture = | |||
972 | .fifo_size = 0, | 979 | .fifo_size = 0, |
973 | }; | 980 | }; |
974 | 981 | ||
982 | static struct snd_pcm_hardware snd_emu10k1_capture_efx = | ||
983 | { | ||
984 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | | ||
985 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | ||
986 | SNDRV_PCM_INFO_RESUME | | ||
987 | SNDRV_PCM_INFO_MMAP_VALID), | ||
988 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
989 | .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | | ||
990 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | | ||
991 | SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000, | ||
992 | .rate_min = 44100, | ||
993 | .rate_max = 192000, | ||
994 | .channels_min = 8, | ||
995 | .channels_max = 8, | ||
996 | .buffer_bytes_max = (64*1024), | ||
997 | .period_bytes_min = 384, | ||
998 | .period_bytes_max = (64*1024), | ||
999 | .periods_min = 2, | ||
1000 | .periods_max = 2, | ||
1001 | .fifo_size = 0, | ||
1002 | }; | ||
1003 | |||
975 | /* | 1004 | /* |
976 | * | 1005 | * |
977 | */ | 1006 | */ |
@@ -1016,7 +1045,7 @@ static int snd_emu10k1_efx_playback_close(struct snd_pcm_substream *substream) | |||
1016 | struct snd_emu10k1_pcm_mixer *mix; | 1045 | struct snd_emu10k1_pcm_mixer *mix; |
1017 | int i; | 1046 | int i; |
1018 | 1047 | ||
1019 | for (i=0; i < NUM_EFX_PLAYBACK; i++) { | 1048 | for (i = 0; i < NUM_EFX_PLAYBACK; i++) { |
1020 | mix = &emu->efx_pcm_mixer[i]; | 1049 | mix = &emu->efx_pcm_mixer[i]; |
1021 | mix->epcm = NULL; | 1050 | mix->epcm = NULL; |
1022 | snd_emu10k1_pcm_efx_mixer_notify(emu, i, 0); | 1051 | snd_emu10k1_pcm_efx_mixer_notify(emu, i, 0); |
@@ -1045,7 +1074,7 @@ static int snd_emu10k1_efx_playback_open(struct snd_pcm_substream *substream) | |||
1045 | runtime->private_free = snd_emu10k1_pcm_free_substream; | 1074 | runtime->private_free = snd_emu10k1_pcm_free_substream; |
1046 | runtime->hw = snd_emu10k1_efx_playback; | 1075 | runtime->hw = snd_emu10k1_efx_playback; |
1047 | 1076 | ||
1048 | for (i=0; i < NUM_EFX_PLAYBACK; i++) { | 1077 | for (i = 0; i < NUM_EFX_PLAYBACK; i++) { |
1049 | mix = &emu->efx_pcm_mixer[i]; | 1078 | mix = &emu->efx_pcm_mixer[i]; |
1050 | mix->send_routing[0][0] = i; | 1079 | mix->send_routing[0][0] = i; |
1051 | memset(&mix->send_volume, 0, sizeof(mix->send_volume)); | 1080 | memset(&mix->send_volume, 0, sizeof(mix->send_volume)); |
@@ -1199,15 +1228,69 @@ static int snd_emu10k1_capture_efx_open(struct snd_pcm_substream *substream) | |||
1199 | epcm->capture_idx_reg = FXIDX; | 1228 | epcm->capture_idx_reg = FXIDX; |
1200 | substream->runtime->private_data = epcm; | 1229 | substream->runtime->private_data = epcm; |
1201 | substream->runtime->private_free = snd_emu10k1_pcm_free_substream; | 1230 | substream->runtime->private_free = snd_emu10k1_pcm_free_substream; |
1202 | runtime->hw = snd_emu10k1_capture; | 1231 | runtime->hw = snd_emu10k1_capture_efx; |
1203 | runtime->hw.rates = SNDRV_PCM_RATE_48000; | 1232 | runtime->hw.rates = SNDRV_PCM_RATE_48000; |
1204 | runtime->hw.rate_min = runtime->hw.rate_max = 48000; | 1233 | runtime->hw.rate_min = runtime->hw.rate_max = 48000; |
1205 | spin_lock_irq(&emu->reg_lock); | 1234 | spin_lock_irq(&emu->reg_lock); |
1206 | runtime->hw.channels_min = runtime->hw.channels_max = 0; | 1235 | if (emu->card_capabilities->emu1010) { |
1207 | for (idx = 0; idx < nefx; idx++) { | 1236 | /* TODO |
1208 | if (emu->efx_voices_mask[idx/32] & (1 << (idx%32))) { | 1237 | * SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE |
1209 | runtime->hw.channels_min++; | 1238 | * SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | |
1210 | runtime->hw.channels_max++; | 1239 | * SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | |
1240 | * SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000 | ||
1241 | * rate_min = 44100, | ||
1242 | * rate_max = 192000, | ||
1243 | * channels_min = 8, | ||
1244 | * channels_max = 8, | ||
1245 | * Need to add mixer control to fix sample rate | ||
1246 | * | ||
1247 | * There are 16 mono channels of 16bits each. | ||
1248 | * 24bit Audio uses 2x channels over 16bit | ||
1249 | * 96kHz uses 2x channels over 48kHz | ||
1250 | * 192kHz uses 4x channels over 48kHz | ||
1251 | * So, for 48kHz 24bit, one has 8 channels | ||
1252 | * for 96kHz 24bit, one has 4 channels | ||
1253 | * for 192kHz 24bit, one has 2 channels | ||
1254 | */ | ||
1255 | #if 1 | ||
1256 | switch (emu->emu1010.internal_clock) { | ||
1257 | case 0: | ||
1258 | /* For 44.1kHz */ | ||
1259 | runtime->hw.rates = SNDRV_PCM_RATE_44100; | ||
1260 | runtime->hw.rate_min = runtime->hw.rate_max = 44100; | ||
1261 | runtime->hw.channels_min = runtime->hw.channels_max = 8; | ||
1262 | break; | ||
1263 | case 1: | ||
1264 | /* For 48kHz */ | ||
1265 | runtime->hw.rates = SNDRV_PCM_RATE_48000; | ||
1266 | runtime->hw.rate_min = runtime->hw.rate_max = 48000; | ||
1267 | runtime->hw.channels_min = runtime->hw.channels_max = 8; | ||
1268 | break; | ||
1269 | }; | ||
1270 | #endif | ||
1271 | #if 0 | ||
1272 | /* For 96kHz */ | ||
1273 | runtime->hw.rates = SNDRV_PCM_RATE_96000; | ||
1274 | runtime->hw.rate_min = runtime->hw.rate_max = 96000; | ||
1275 | runtime->hw.channels_min = runtime->hw.channels_max = 4; | ||
1276 | #endif | ||
1277 | #if 0 | ||
1278 | /* For 192kHz */ | ||
1279 | runtime->hw.rates = SNDRV_PCM_RATE_192000; | ||
1280 | runtime->hw.rate_min = runtime->hw.rate_max = 192000; | ||
1281 | runtime->hw.channels_min = runtime->hw.channels_max = 2; | ||
1282 | #endif | ||
1283 | runtime->hw.formats = SNDRV_PCM_FMTBIT_S32_LE; | ||
1284 | /* efx_voices_mask[0] is expected to be zero | ||
1285 | * efx_voices_mask[1] is expected to have 16bits set | ||
1286 | */ | ||
1287 | } else { | ||
1288 | runtime->hw.channels_min = runtime->hw.channels_max = 0; | ||
1289 | for (idx = 0; idx < nefx; idx++) { | ||
1290 | if (emu->efx_voices_mask[idx/32] & (1 << (idx%32))) { | ||
1291 | runtime->hw.channels_min++; | ||
1292 | runtime->hw.channels_max++; | ||
1293 | } | ||
1211 | } | 1294 | } |
1212 | } | 1295 | } |
1213 | epcm->capture_cr_val = emu->efx_voices_mask[0]; | 1296 | epcm->capture_cr_val = emu->efx_voices_mask[0]; |
@@ -1460,7 +1543,7 @@ static void snd_emu10k1_fx8010_playback_tram_poke1(unsigned short *dst_left, | |||
1460 | unsigned int count, | 1543 | unsigned int count, |
1461 | unsigned int tram_shift) | 1544 | unsigned int tram_shift) |
1462 | { | 1545 | { |
1463 | // printk("tram_poke1: dst_left = 0x%p, dst_right = 0x%p, src = 0x%p, count = 0x%x\n", dst_left, dst_right, src, count); | 1546 | /* printk("tram_poke1: dst_left = 0x%p, dst_right = 0x%p, src = 0x%p, count = 0x%x\n", dst_left, dst_right, src, count); */ |
1464 | if ((tram_shift & 1) == 0) { | 1547 | if ((tram_shift & 1) == 0) { |
1465 | while (count--) { | 1548 | while (count--) { |
1466 | *dst_left-- = *src++; | 1549 | *dst_left-- = *src++; |
@@ -1537,7 +1620,7 @@ static int snd_emu10k1_fx8010_playback_prepare(struct snd_pcm_substream *substre | |||
1537 | struct snd_emu10k1_fx8010_pcm *pcm = &emu->fx8010.pcm[substream->number]; | 1620 | struct snd_emu10k1_fx8010_pcm *pcm = &emu->fx8010.pcm[substream->number]; |
1538 | unsigned int i; | 1621 | unsigned int i; |
1539 | 1622 | ||
1540 | // printk("prepare: etram_pages = 0x%p, dma_area = 0x%x, buffer_size = 0x%x (0x%x)\n", emu->fx8010.etram_pages, runtime->dma_area, runtime->buffer_size, runtime->buffer_size << 2); | 1623 | /* printk("prepare: etram_pages = 0x%p, dma_area = 0x%x, buffer_size = 0x%x (0x%x)\n", emu->fx8010.etram_pages, runtime->dma_area, runtime->buffer_size, runtime->buffer_size << 2); */ |
1541 | memset(&pcm->pcm_rec, 0, sizeof(pcm->pcm_rec)); | 1624 | memset(&pcm->pcm_rec, 0, sizeof(pcm->pcm_rec)); |
1542 | pcm->pcm_rec.hw_buffer_size = pcm->buffer_size * 2; /* byte size */ | 1625 | pcm->pcm_rec.hw_buffer_size = pcm->buffer_size * 2; /* byte size */ |
1543 | pcm->pcm_rec.sw_buffer_size = snd_pcm_lib_buffer_bytes(substream); | 1626 | pcm->pcm_rec.sw_buffer_size = snd_pcm_lib_buffer_bytes(substream); |
diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c index b939e03aaedf..2c1585991bc8 100644 --- a/sound/pci/emu10k1/emuproc.c +++ b/sound/pci/emu10k1/emuproc.c | |||
@@ -3,6 +3,9 @@ | |||
3 | * Creative Labs, Inc. | 3 | * Creative Labs, Inc. |
4 | * Routines for control of EMU10K1 chips / proc interface routines | 4 | * Routines for control of EMU10K1 chips / proc interface routines |
5 | * | 5 | * |
6 | * Copyright (c) by James Courtier-Dutton <James@superbug.co.uk> | ||
7 | * Added EMU 1010 support. | ||
8 | * | ||
6 | * BUGS: | 9 | * BUGS: |
7 | * -- | 10 | * -- |
8 | * | 11 | * |
@@ -255,7 +258,7 @@ static void snd_emu10k1_proc_rates_read(struct snd_info_entry *entry, | |||
255 | unsigned int val, tmp, n; | 258 | unsigned int val, tmp, n; |
256 | val = snd_emu10k1_ptr20_read(emu, CAPTURE_RATE_STATUS, 0); | 259 | val = snd_emu10k1_ptr20_read(emu, CAPTURE_RATE_STATUS, 0); |
257 | tmp = (val >> 16) & 0x8; | 260 | tmp = (val >> 16) & 0x8; |
258 | for (n=0;n<4;n++) { | 261 | for (n = 0; n < 4; n++) { |
259 | tmp = val >> (16 + (n*4)); | 262 | tmp = val >> (16 + (n*4)); |
260 | if (tmp & 0x8) snd_iprintf(buffer, "Channel %d: Rate=%d\n", n, samplerate[tmp & 0x7]); | 263 | if (tmp & 0x8) snd_iprintf(buffer, "Channel %d: Rate=%d\n", n, samplerate[tmp & 0x7]); |
261 | else snd_iprintf(buffer, "Channel %d: No input\n", n); | 264 | else snd_iprintf(buffer, "Channel %d: No input\n", n); |
@@ -372,6 +375,27 @@ static void snd_emu10k1_proc_voices_read(struct snd_info_entry *entry, | |||
372 | } | 375 | } |
373 | 376 | ||
374 | #ifdef CONFIG_SND_DEBUG | 377 | #ifdef CONFIG_SND_DEBUG |
378 | static void snd_emu_proc_emu1010_reg_read(struct snd_info_entry *entry, | ||
379 | struct snd_info_buffer *buffer) | ||
380 | { | ||
381 | struct snd_emu10k1 *emu = entry->private_data; | ||
382 | unsigned long value; | ||
383 | unsigned long flags; | ||
384 | unsigned long regs; | ||
385 | int i; | ||
386 | snd_iprintf(buffer, "EMU1010 Registers:\n\n"); | ||
387 | |||
388 | for(i = 0; i < 0x30; i+=1) { | ||
389 | spin_lock_irqsave(&emu->emu_lock, flags); | ||
390 | regs=i+0x40; /* 0x40 upwards are registers. */ | ||
391 | outl(regs, emu->port + A_IOCFG); | ||
392 | outl(regs | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */ | ||
393 | value = inl(emu->port + A_IOCFG); | ||
394 | spin_unlock_irqrestore(&emu->emu_lock, flags); | ||
395 | snd_iprintf(buffer, "%02X: %08lX, %02lX\n", i, value, (value >> 8) & 0x7f); | ||
396 | } | ||
397 | } | ||
398 | |||
375 | static void snd_emu_proc_io_reg_read(struct snd_info_entry *entry, | 399 | static void snd_emu_proc_io_reg_read(struct snd_info_entry *entry, |
376 | struct snd_info_buffer *buffer) | 400 | struct snd_info_buffer *buffer) |
377 | { | 401 | { |
@@ -398,7 +422,7 @@ static void snd_emu_proc_io_reg_write(struct snd_info_entry *entry, | |||
398 | while (!snd_info_get_line(buffer, line, sizeof(line))) { | 422 | while (!snd_info_get_line(buffer, line, sizeof(line))) { |
399 | if (sscanf(line, "%x %x", ®, &val) != 2) | 423 | if (sscanf(line, "%x %x", ®, &val) != 2) |
400 | continue; | 424 | continue; |
401 | if ((reg < 0x40) && (reg >=0) && (val <= 0xffffffff) ) { | 425 | if ((reg < 0x40) && (reg >= 0) && (val <= 0xffffffff) ) { |
402 | spin_lock_irqsave(&emu->emu_lock, flags); | 426 | spin_lock_irqsave(&emu->emu_lock, flags); |
403 | outl(val, emu->port + (reg & 0xfffffffc)); | 427 | outl(val, emu->port + (reg & 0xfffffffc)); |
404 | spin_unlock_irqrestore(&emu->emu_lock, flags); | 428 | spin_unlock_irqrestore(&emu->emu_lock, flags); |
@@ -474,7 +498,7 @@ static void snd_emu_proc_ptr_reg_write(struct snd_info_entry *entry, | |||
474 | while (!snd_info_get_line(buffer, line, sizeof(line))) { | 498 | while (!snd_info_get_line(buffer, line, sizeof(line))) { |
475 | if (sscanf(line, "%x %x %x", ®, &channel_id, &val) != 3) | 499 | if (sscanf(line, "%x %x %x", ®, &channel_id, &val) != 3) |
476 | continue; | 500 | continue; |
477 | if ((reg < 0xa0) && (reg >=0) && (val <= 0xffffffff) && (channel_id >=0) && (channel_id <= 3) ) | 501 | if ((reg < 0xa0) && (reg >= 0) && (val <= 0xffffffff) && (channel_id >= 0) && (channel_id <= 3) ) |
478 | snd_ptr_write(emu, iobase, reg, channel_id, val); | 502 | snd_ptr_write(emu, iobase, reg, channel_id, val); |
479 | } | 503 | } |
480 | } | 504 | } |
@@ -531,6 +555,10 @@ int __devinit snd_emu10k1_proc_init(struct snd_emu10k1 * emu) | |||
531 | { | 555 | { |
532 | struct snd_info_entry *entry; | 556 | struct snd_info_entry *entry; |
533 | #ifdef CONFIG_SND_DEBUG | 557 | #ifdef CONFIG_SND_DEBUG |
558 | if ((emu->card_capabilities->emu1010) && | ||
559 | snd_card_proc_new(emu->card, "emu1010_regs", &entry)) { | ||
560 | snd_info_set_text_ops(entry, emu, snd_emu_proc_emu1010_reg_read); | ||
561 | } | ||
534 | if (! snd_card_proc_new(emu->card, "io_regs", &entry)) { | 562 | if (! snd_card_proc_new(emu->card, "io_regs", &entry)) { |
535 | snd_info_set_text_ops(entry, emu, snd_emu_proc_io_reg_read); | 563 | snd_info_set_text_ops(entry, emu, snd_emu_proc_io_reg_read); |
536 | entry->c.text.write = snd_emu_proc_io_reg_write; | 564 | entry->c.text.write = snd_emu_proc_io_reg_write; |
diff --git a/sound/pci/emu10k1/io.c b/sound/pci/emu10k1/io.c index 029e7856c43b..116e1c8d9361 100644 --- a/sound/pci/emu10k1/io.c +++ b/sound/pci/emu10k1/io.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <sound/core.h> | 30 | #include <sound/core.h> |
31 | #include <sound/emu10k1.h> | 31 | #include <sound/emu10k1.h> |
32 | #include <linux/delay.h> | 32 | #include <linux/delay.h> |
33 | #include "p17v.h" | ||
33 | 34 | ||
34 | unsigned int snd_emu10k1_ptr_read(struct snd_emu10k1 * emu, unsigned int reg, unsigned int chn) | 35 | unsigned int snd_emu10k1_ptr_read(struct snd_emu10k1 * emu, unsigned int reg, unsigned int chn) |
35 | { | 36 | { |
@@ -167,6 +168,109 @@ int snd_emu10k1_spi_write(struct snd_emu10k1 * emu, | |||
167 | return 0; | 168 | return 0; |
168 | } | 169 | } |
169 | 170 | ||
171 | /* The ADC does not support i2c read, so only write is implemented */ | ||
172 | int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu, | ||
173 | u32 reg, | ||
174 | u32 value) | ||
175 | { | ||
176 | u32 tmp; | ||
177 | int timeout = 0; | ||
178 | int status; | ||
179 | int retry; | ||
180 | if ((reg > 0x7f) || (value > 0x1ff)) { | ||
181 | snd_printk(KERN_ERR "i2c_write: invalid values.\n"); | ||
182 | return -EINVAL; | ||
183 | } | ||
184 | |||
185 | tmp = reg << 25 | value << 16; | ||
186 | // snd_printk("I2C-write:reg=0x%x, value=0x%x\n", reg, value); | ||
187 | /* Not sure what this I2C channel controls. */ | ||
188 | /* snd_emu10k1_ptr_write(emu, P17V_I2C_0, 0, tmp); */ | ||
189 | |||
190 | /* This controls the I2C connected to the WM8775 ADC Codec */ | ||
191 | snd_emu10k1_ptr20_write(emu, P17V_I2C_1, 0, tmp); | ||
192 | tmp = snd_emu10k1_ptr20_read(emu, P17V_I2C_1, 0); /* write post */ | ||
193 | |||
194 | for (retry = 0; retry < 10; retry++) { | ||
195 | /* Send the data to i2c */ | ||
196 | //tmp = snd_emu10k1_ptr_read(emu, P17V_I2C_ADDR, 0); | ||
197 | //tmp = tmp & ~(I2C_A_ADC_READ|I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD_MASK); | ||
198 | tmp = 0; | ||
199 | tmp = tmp | (I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD); | ||
200 | snd_emu10k1_ptr20_write(emu, P17V_I2C_ADDR, 0, tmp); | ||
201 | |||
202 | /* Wait till the transaction ends */ | ||
203 | while (1) { | ||
204 | udelay(10); | ||
205 | status = snd_emu10k1_ptr20_read(emu, P17V_I2C_ADDR, 0); | ||
206 | // snd_printk("I2C:status=0x%x\n", status); | ||
207 | timeout++; | ||
208 | if ((status & I2C_A_ADC_START) == 0) | ||
209 | break; | ||
210 | |||
211 | if (timeout > 1000) { | ||
212 | snd_printk("emu10k1:I2C:timeout status=0x%x\n", status); | ||
213 | break; | ||
214 | } | ||
215 | } | ||
216 | //Read back and see if the transaction is successful | ||
217 | if ((status & I2C_A_ADC_ABORT) == 0) | ||
218 | break; | ||
219 | } | ||
220 | |||
221 | if (retry == 10) { | ||
222 | snd_printk(KERN_ERR "Writing to ADC failed!\n"); | ||
223 | return -EINVAL; | ||
224 | } | ||
225 | |||
226 | return 0; | ||
227 | } | ||
228 | |||
229 | int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, int reg, int value) | ||
230 | { | ||
231 | if (reg < 0 || reg > 0x3f) | ||
232 | return 1; | ||
233 | reg += 0x40; /* 0x40 upwards are registers. */ | ||
234 | if (value < 0 || value > 0x3f) /* 0 to 0x3f are values */ | ||
235 | return 1; | ||
236 | outl(reg, emu->port + A_IOCFG); | ||
237 | udelay(10); | ||
238 | outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */ | ||
239 | udelay(10); | ||
240 | outl(value, emu->port + A_IOCFG); | ||
241 | udelay(10); | ||
242 | outl(value | 0x80 , emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */ | ||
243 | |||
244 | return 0; | ||
245 | } | ||
246 | |||
247 | int snd_emu1010_fpga_read(struct snd_emu10k1 * emu, int reg, int *value) | ||
248 | { | ||
249 | if (reg < 0 || reg > 0x3f) | ||
250 | return 1; | ||
251 | reg += 0x40; /* 0x40 upwards are registers. */ | ||
252 | outl(reg, emu->port + A_IOCFG); | ||
253 | udelay(10); | ||
254 | outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */ | ||
255 | udelay(10); | ||
256 | *value = ((inl(emu->port + A_IOCFG) >> 8) & 0x7f); | ||
257 | |||
258 | return 0; | ||
259 | } | ||
260 | |||
261 | /* Each Destination has one and only one Source, | ||
262 | * but one Source can feed any number of Destinations simultaneously. | ||
263 | */ | ||
264 | int snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 * emu, int dst, int src) | ||
265 | { | ||
266 | snd_emu1010_fpga_write(emu, 0x00, ((dst >> 8) & 0x3f) ); | ||
267 | snd_emu1010_fpga_write(emu, 0x01, (dst & 0x3f) ); | ||
268 | snd_emu1010_fpga_write(emu, 0x02, ((src >> 8) & 0x3f) ); | ||
269 | snd_emu1010_fpga_write(emu, 0x03, (src & 0x3f) ); | ||
270 | |||
271 | return 0; | ||
272 | } | ||
273 | |||
170 | void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb) | 274 | void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb) |
171 | { | 275 | { |
172 | unsigned long flags; | 276 | unsigned long flags; |
diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c index 4e0f95438f47..465f8d505329 100644 --- a/sound/pci/emu10k1/p16v.c +++ b/sound/pci/emu10k1/p16v.c | |||
@@ -253,7 +253,7 @@ static int snd_p16v_pcm_close_playback(struct snd_pcm_substream *substream) | |||
253 | struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); | 253 | struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); |
254 | //struct snd_pcm_runtime *runtime = substream->runtime; | 254 | //struct snd_pcm_runtime *runtime = substream->runtime; |
255 | //struct snd_emu10k1_pcm *epcm = runtime->private_data; | 255 | //struct snd_emu10k1_pcm *epcm = runtime->private_data; |
256 | emu->p16v_voices[substream->pcm->device - emu->p16v_device_offset].use=0; | 256 | emu->p16v_voices[substream->pcm->device - emu->p16v_device_offset].use = 0; |
257 | /* FIXME: maybe zero others */ | 257 | /* FIXME: maybe zero others */ |
258 | return 0; | 258 | return 0; |
259 | } | 259 | } |
@@ -264,7 +264,7 @@ static int snd_p16v_pcm_close_capture(struct snd_pcm_substream *substream) | |||
264 | struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); | 264 | struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); |
265 | //struct snd_pcm_runtime *runtime = substream->runtime; | 265 | //struct snd_pcm_runtime *runtime = substream->runtime; |
266 | //struct snd_emu10k1_pcm *epcm = runtime->private_data; | 266 | //struct snd_emu10k1_pcm *epcm = runtime->private_data; |
267 | emu->p16v_capture_voice.use=0; | 267 | emu->p16v_capture_voice.use = 0; |
268 | /* FIXME: maybe zero others */ | 268 | /* FIXME: maybe zero others */ |
269 | return 0; | 269 | return 0; |
270 | } | 270 | } |
@@ -349,7 +349,7 @@ static int snd_p16v_pcm_prepare_playback(struct snd_pcm_substream *substream) | |||
349 | break; | 349 | break; |
350 | } | 350 | } |
351 | /* FIXME: Check emu->buffer.size before actually writing to it. */ | 351 | /* FIXME: Check emu->buffer.size before actually writing to it. */ |
352 | for(i=0; i < runtime->periods; i++) { | 352 | for(i = 0; i < runtime->periods; i++) { |
353 | table_base[i*2]=runtime->dma_addr+(i*period_size_bytes); | 353 | table_base[i*2]=runtime->dma_addr+(i*period_size_bytes); |
354 | table_base[(i*2)+1]=period_size_bytes<<16; | 354 | table_base[(i*2)+1]=period_size_bytes<<16; |
355 | } | 355 | } |
@@ -394,7 +394,7 @@ static int snd_p16v_pcm_prepare_capture(struct snd_pcm_substream *substream) | |||
394 | /* FIXME: Check emu->buffer.size before actually writing to it. */ | 394 | /* FIXME: Check emu->buffer.size before actually writing to it. */ |
395 | snd_emu10k1_ptr20_write(emu, 0x13, channel, 0); | 395 | snd_emu10k1_ptr20_write(emu, 0x13, channel, 0); |
396 | snd_emu10k1_ptr20_write(emu, CAPTURE_DMA_ADDR, channel, runtime->dma_addr); | 396 | snd_emu10k1_ptr20_write(emu, CAPTURE_DMA_ADDR, channel, runtime->dma_addr); |
397 | snd_emu10k1_ptr20_write(emu, CAPTURE_BUFFER_SIZE, channel, frames_to_bytes(runtime, runtime->buffer_size)<<16); // buffer size in bytes | 397 | snd_emu10k1_ptr20_write(emu, CAPTURE_BUFFER_SIZE, channel, frames_to_bytes(runtime, runtime->buffer_size) << 16); // buffer size in bytes |
398 | snd_emu10k1_ptr20_write(emu, CAPTURE_POINTER, channel, 0); | 398 | snd_emu10k1_ptr20_write(emu, CAPTURE_POINTER, channel, 0); |
399 | //snd_emu10k1_ptr20_write(emu, CAPTURE_SOURCE, 0x0, 0x333300e4); /* Select MIC or Line in */ | 399 | //snd_emu10k1_ptr20_write(emu, CAPTURE_SOURCE, 0x0, 0x333300e4); /* Select MIC or Line in */ |
400 | //snd_emu10k1_ptr20_write(emu, EXTENDED_INT_MASK, 0, snd_emu10k1_ptr20_read(emu, EXTENDED_INT_MASK, 0) | (0x110000<<channel)); | 400 | //snd_emu10k1_ptr20_write(emu, EXTENDED_INT_MASK, 0, snd_emu10k1_ptr20_read(emu, EXTENDED_INT_MASK, 0) | (0x110000<<channel)); |
@@ -437,7 +437,7 @@ static int snd_p16v_pcm_trigger_playback(struct snd_pcm_substream *substream, | |||
437 | struct snd_pcm_substream *s; | 437 | struct snd_pcm_substream *s; |
438 | u32 basic = 0; | 438 | u32 basic = 0; |
439 | u32 inte = 0; | 439 | u32 inte = 0; |
440 | int running=0; | 440 | int running = 0; |
441 | 441 | ||
442 | switch (cmd) { | 442 | switch (cmd) { |
443 | case SNDRV_PCM_TRIGGER_START: | 443 | case SNDRV_PCM_TRIGGER_START: |
@@ -445,7 +445,7 @@ static int snd_p16v_pcm_trigger_playback(struct snd_pcm_substream *substream, | |||
445 | break; | 445 | break; |
446 | case SNDRV_PCM_TRIGGER_STOP: | 446 | case SNDRV_PCM_TRIGGER_STOP: |
447 | default: | 447 | default: |
448 | running=0; | 448 | running = 0; |
449 | break; | 449 | break; |
450 | } | 450 | } |
451 | snd_pcm_group_for_each(pos, substream) { | 451 | snd_pcm_group_for_each(pos, substream) { |
@@ -785,7 +785,7 @@ static int snd_p16v_capture_channel_put(struct snd_kcontrol *kcontrol, | |||
785 | } | 785 | } |
786 | return change; | 786 | return change; |
787 | } | 787 | } |
788 | static DECLARE_TLV_DB_SCALE(snd_p16v_db_scale1, -5175, 25, 1); | 788 | static const DECLARE_TLV_DB_SCALE(snd_p16v_db_scale1, -5175, 25, 1); |
789 | 789 | ||
790 | #define P16V_VOL(xname,xreg,xhl) { \ | 790 | #define P16V_VOL(xname,xreg,xhl) { \ |
791 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 791 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ |
diff --git a/sound/pci/emu10k1/p17v.h b/sound/pci/emu10k1/p17v.h index 7ddb5be632cf..4ef5f68a9cd0 100644 --- a/sound/pci/emu10k1/p17v.h +++ b/sound/pci/emu10k1/p17v.h | |||
@@ -43,6 +43,53 @@ | |||
43 | #define P17V_I2C_ADDR 0x3d /* I2C Address */ | 43 | #define P17V_I2C_ADDR 0x3d /* I2C Address */ |
44 | #define P17V_I2C_0 0x3e /* I2C Data */ | 44 | #define P17V_I2C_0 0x3e /* I2C Data */ |
45 | #define P17V_I2C_1 0x3f /* I2C Data */ | 45 | #define P17V_I2C_1 0x3f /* I2C Data */ |
46 | /* I2C values */ | ||
47 | #define I2C_A_ADC_ADD_MASK 0x000000fe /*The address is a 7 bit address */ | ||
48 | #define I2C_A_ADC_RW_MASK 0x00000001 /*bit mask for R/W */ | ||
49 | #define I2C_A_ADC_TRANS_MASK 0x00000010 /*Bit mask for I2c address DAC value */ | ||
50 | #define I2C_A_ADC_ABORT_MASK 0x00000020 /*Bit mask for I2C transaction abort flag */ | ||
51 | #define I2C_A_ADC_LAST_MASK 0x00000040 /*Bit mask for Last word transaction */ | ||
52 | #define I2C_A_ADC_BYTE_MASK 0x00000080 /*Bit mask for Byte Mode */ | ||
53 | |||
54 | #define I2C_A_ADC_ADD 0x00000034 /*This is the Device address for ADC */ | ||
55 | #define I2C_A_ADC_READ 0x00000001 /*To perform a read operation */ | ||
56 | #define I2C_A_ADC_START 0x00000100 /*Start I2C transaction */ | ||
57 | #define I2C_A_ADC_ABORT 0x00000200 /*I2C transaction abort */ | ||
58 | #define I2C_A_ADC_LAST 0x00000400 /*I2C last transaction */ | ||
59 | #define I2C_A_ADC_BYTE 0x00000800 /*I2C one byte mode */ | ||
60 | |||
61 | #define I2C_D_ADC_REG_MASK 0xfe000000 /*ADC address register */ | ||
62 | #define I2C_D_ADC_DAT_MASK 0x01ff0000 /*ADC data register */ | ||
63 | |||
64 | #define ADC_TIMEOUT 0x00000007 /*ADC Timeout Clock Disable */ | ||
65 | #define ADC_IFC_CTRL 0x0000000b /*ADC Interface Control */ | ||
66 | #define ADC_MASTER 0x0000000c /*ADC Master Mode Control */ | ||
67 | #define ADC_POWER 0x0000000d /*ADC PowerDown Control */ | ||
68 | #define ADC_ATTEN_ADCL 0x0000000e /*ADC Attenuation ADCL */ | ||
69 | #define ADC_ATTEN_ADCR 0x0000000f /*ADC Attenuation ADCR */ | ||
70 | #define ADC_ALC_CTRL1 0x00000010 /*ADC ALC Control 1 */ | ||
71 | #define ADC_ALC_CTRL2 0x00000011 /*ADC ALC Control 2 */ | ||
72 | #define ADC_ALC_CTRL3 0x00000012 /*ADC ALC Control 3 */ | ||
73 | #define ADC_NOISE_CTRL 0x00000013 /*ADC Noise Gate Control */ | ||
74 | #define ADC_LIMIT_CTRL 0x00000014 /*ADC Limiter Control */ | ||
75 | #define ADC_MUX 0x00000015 /*ADC Mux offset */ | ||
76 | #if 0 | ||
77 | /* FIXME: Not tested yet. */ | ||
78 | #define ADC_GAIN_MASK 0x000000ff //Mask for ADC Gain | ||
79 | #define ADC_ZERODB 0x000000cf //Value to set ADC to 0dB | ||
80 | #define ADC_MUTE_MASK 0x000000c0 //Mask for ADC mute | ||
81 | #define ADC_MUTE 0x000000c0 //Value to mute ADC | ||
82 | #define ADC_OSR 0x00000008 //Mask for ADC oversample rate select | ||
83 | #define ADC_TIMEOUT_DISABLE 0x00000008 //Value and mask to disable Timeout clock | ||
84 | #define ADC_HPF_DISABLE 0x00000100 //Value and mask to disable High pass filter | ||
85 | #define ADC_TRANWIN_MASK 0x00000070 //Mask for Length of Transient Window | ||
86 | #endif | ||
87 | |||
88 | #define ADC_MUX_MASK 0x0000000f //Mask for ADC Mux | ||
89 | #define ADC_MUX_0 0x00000001 //Value to select Unknown at ADC Mux (Not used) | ||
90 | #define ADC_MUX_1 0x00000002 //Value to select Unknown at ADC Mux (Not used) | ||
91 | #define ADC_MUX_2 0x00000004 //Value to select Mic at ADC Mux | ||
92 | #define ADC_MUX_3 0x00000008 //Value to select Line-In at ADC Mux | ||
46 | 93 | ||
47 | #define P17V_START_AUDIO 0x40 /* Start Audio bit */ | 94 | #define P17V_START_AUDIO 0x40 /* Start Audio bit */ |
48 | /* 41 - 47: Reserved */ | 95 | /* 41 - 47: Reserved */ |
diff --git a/sound/pci/emu10k1/voice.c b/sound/pci/emu10k1/voice.c index 94eca82dd4fc..1db50fe61475 100644 --- a/sound/pci/emu10k1/voice.c +++ b/sound/pci/emu10k1/voice.c | |||
@@ -83,7 +83,7 @@ static int voice_alloc(struct snd_emu10k1 *emu, int type, int number, | |||
83 | if (first_voice == last_voice) | 83 | if (first_voice == last_voice) |
84 | return -ENOMEM; | 84 | return -ENOMEM; |
85 | 85 | ||
86 | for (i=0; i < number; i++) { | 86 | for (i = 0; i < number; i++) { |
87 | voice = &emu->voices[(first_voice + i) % NUM_G]; | 87 | voice = &emu->voices[(first_voice + i) % NUM_G]; |
88 | // printk("voice alloc - %i, %i of %i\n", voice->number, idx-first_voice+1, number); | 88 | // printk("voice alloc - %i, %i of %i\n", voice->number, idx-first_voice+1, number); |
89 | voice->use = 1; | 89 | voice->use = 1; |
diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c index a84f6b21024f..425b167522d5 100644 --- a/sound/pci/ens1370.c +++ b/sound/pci/ens1370.c | |||
@@ -413,8 +413,6 @@ struct ensoniq { | |||
413 | } u; | 413 | } u; |
414 | 414 | ||
415 | struct pci_dev *pci; | 415 | struct pci_dev *pci; |
416 | unsigned short subsystem_vendor_id; | ||
417 | unsigned short subsystem_device_id; | ||
418 | struct snd_card *card; | 416 | struct snd_card *card; |
419 | struct snd_pcm *pcm1; /* DAC1/ADC PCM */ | 417 | struct snd_pcm *pcm1; /* DAC1/ADC PCM */ |
420 | struct snd_pcm *pcm2; /* DAC2 PCM */ | 418 | struct snd_pcm *pcm2; /* DAC2 PCM */ |
@@ -1607,11 +1605,26 @@ static void snd_ensoniq_mixer_free_ac97(struct snd_ac97 *ac97) | |||
1607 | ensoniq->u.es1371.ac97 = NULL; | 1605 | ensoniq->u.es1371.ac97 = NULL; |
1608 | } | 1606 | } |
1609 | 1607 | ||
1610 | static struct { | 1608 | struct es1371_quirk { |
1611 | unsigned short vid; /* vendor ID */ | 1609 | unsigned short vid; /* vendor ID */ |
1612 | unsigned short did; /* device ID */ | 1610 | unsigned short did; /* device ID */ |
1613 | unsigned char rev; /* revision */ | 1611 | unsigned char rev; /* revision */ |
1614 | } es1371_spdif_present[] __devinitdata = { | 1612 | }; |
1613 | |||
1614 | static int __devinit es1371_quirk_lookup(struct ensoniq *ensoniq, | ||
1615 | struct es1371_quirk *list) | ||
1616 | { | ||
1617 | while (list->vid != (unsigned short)PCI_ANY_ID) { | ||
1618 | if (ensoniq->pci->vendor == list->vid && | ||
1619 | ensoniq->pci->device == list->did && | ||
1620 | ensoniq->rev == list->rev) | ||
1621 | return 1; | ||
1622 | list++; | ||
1623 | } | ||
1624 | return 0; | ||
1625 | } | ||
1626 | |||
1627 | static struct es1371_quirk es1371_spdif_present[] __devinitdata = { | ||
1615 | { .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_C }, | 1628 | { .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_C }, |
1616 | { .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_D }, | 1629 | { .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_D }, |
1617 | { .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_E }, | 1630 | { .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_E }, |
@@ -1620,12 +1633,19 @@ static struct { | |||
1620 | { .vid = PCI_ANY_ID, .did = PCI_ANY_ID } | 1633 | { .vid = PCI_ANY_ID, .did = PCI_ANY_ID } |
1621 | }; | 1634 | }; |
1622 | 1635 | ||
1623 | static int snd_ensoniq_1371_mixer(struct ensoniq * ensoniq, int has_spdif, int has_line) | 1636 | static struct snd_pci_quirk ens1373_line_quirk[] __devinitdata = { |
1637 | SND_PCI_QUIRK_ID(0x1274, 0x2000), /* GA-7DXR */ | ||
1638 | SND_PCI_QUIRK_ID(0x1458, 0xa000), /* GA-8IEXP */ | ||
1639 | { } /* end */ | ||
1640 | }; | ||
1641 | |||
1642 | static int __devinit snd_ensoniq_1371_mixer(struct ensoniq *ensoniq, | ||
1643 | int has_spdif, int has_line) | ||
1624 | { | 1644 | { |
1625 | struct snd_card *card = ensoniq->card; | 1645 | struct snd_card *card = ensoniq->card; |
1626 | struct snd_ac97_bus *pbus; | 1646 | struct snd_ac97_bus *pbus; |
1627 | struct snd_ac97_template ac97; | 1647 | struct snd_ac97_template ac97; |
1628 | int err, idx; | 1648 | int err; |
1629 | static struct snd_ac97_bus_ops ops = { | 1649 | static struct snd_ac97_bus_ops ops = { |
1630 | .write = snd_es1371_codec_write, | 1650 | .write = snd_es1371_codec_write, |
1631 | .read = snd_es1371_codec_read, | 1651 | .read = snd_es1371_codec_read, |
@@ -1641,33 +1661,28 @@ static int snd_ensoniq_1371_mixer(struct ensoniq * ensoniq, int has_spdif, int h | |||
1641 | ac97.scaps = AC97_SCAP_AUDIO; | 1661 | ac97.scaps = AC97_SCAP_AUDIO; |
1642 | if ((err = snd_ac97_mixer(pbus, &ac97, &ensoniq->u.es1371.ac97)) < 0) | 1662 | if ((err = snd_ac97_mixer(pbus, &ac97, &ensoniq->u.es1371.ac97)) < 0) |
1643 | return err; | 1663 | return err; |
1644 | for (idx = 0; es1371_spdif_present[idx].vid != (unsigned short)PCI_ANY_ID; idx++) | 1664 | if (has_spdif > 0 || |
1645 | if ((ensoniq->pci->vendor == es1371_spdif_present[idx].vid && | 1665 | (!has_spdif && es1371_quirk_lookup(ensoniq, es1371_spdif_present))) { |
1646 | ensoniq->pci->device == es1371_spdif_present[idx].did && | 1666 | struct snd_kcontrol *kctl; |
1647 | ensoniq->rev == es1371_spdif_present[idx].rev) || has_spdif > 0) { | 1667 | int i, index = 0; |
1648 | struct snd_kcontrol *kctl; | 1668 | |
1649 | int i, index = 0; | 1669 | ensoniq->spdif_default = ensoniq->spdif_stream = |
1650 | 1670 | SNDRV_PCM_DEFAULT_CON_SPDIF; | |
1651 | if (has_spdif < 0) | 1671 | outl(ensoniq->spdif_default, ES_REG(ensoniq, CHANNEL_STATUS)); |
1652 | break; | 1672 | |
1653 | 1673 | if (ensoniq->u.es1371.ac97->ext_id & AC97_EI_SPDIF) | |
1654 | ensoniq->spdif_default = ensoniq->spdif_stream = | 1674 | index++; |
1655 | SNDRV_PCM_DEFAULT_CON_SPDIF; | 1675 | |
1656 | outl(ensoniq->spdif_default, ES_REG(ensoniq, CHANNEL_STATUS)); | 1676 | for (i = 0; i < ARRAY_SIZE(snd_es1371_mixer_spdif); i++) { |
1657 | 1677 | kctl = snd_ctl_new1(&snd_es1371_mixer_spdif[i], ensoniq); | |
1658 | if (ensoniq->u.es1371.ac97->ext_id & AC97_EI_SPDIF) | 1678 | if (!kctl) |
1659 | index++; | 1679 | return -ENOMEM; |
1660 | 1680 | kctl->id.index = index; | |
1661 | for (i = 0; i < (int)ARRAY_SIZE(snd_es1371_mixer_spdif); i++) { | 1681 | err = snd_ctl_add(card, kctl); |
1662 | kctl = snd_ctl_new1(&snd_es1371_mixer_spdif[i], ensoniq); | 1682 | if (err < 0) |
1663 | if (! kctl) | 1683 | return err; |
1664 | return -ENOMEM; | ||
1665 | kctl->id.index = index; | ||
1666 | if ((err = snd_ctl_add(card, kctl)) < 0) | ||
1667 | return err; | ||
1668 | } | ||
1669 | break; | ||
1670 | } | 1684 | } |
1685 | } | ||
1671 | if (ensoniq->u.es1371.ac97->ext_id & AC97_EI_SDAC) { | 1686 | if (ensoniq->u.es1371.ac97->ext_id & AC97_EI_SDAC) { |
1672 | /* mirror rear to front speakers */ | 1687 | /* mirror rear to front speakers */ |
1673 | ensoniq->cssr &= ~(ES_1373_REAR_BIT27|ES_1373_REAR_BIT24); | 1688 | ensoniq->cssr &= ~(ES_1373_REAR_BIT27|ES_1373_REAR_BIT24); |
@@ -1676,12 +1691,10 @@ static int snd_ensoniq_1371_mixer(struct ensoniq * ensoniq, int has_spdif, int h | |||
1676 | if (err < 0) | 1691 | if (err < 0) |
1677 | return err; | 1692 | return err; |
1678 | } | 1693 | } |
1679 | if (((ensoniq->subsystem_vendor_id == 0x1274) && | 1694 | if (has_line > 0 || |
1680 | (ensoniq->subsystem_device_id == 0x2000)) || /* GA-7DXR */ | 1695 | snd_pci_quirk_lookup(ensoniq->pci, ens1373_line_quirk)) { |
1681 | ((ensoniq->subsystem_vendor_id == 0x1458) && | 1696 | err = snd_ctl_add(card, snd_ctl_new1(&snd_ens1373_line, |
1682 | (ensoniq->subsystem_device_id == 0xa000)) || /* GA-8IEXP */ | 1697 | ensoniq)); |
1683 | has_line > 0) { | ||
1684 | err = snd_ctl_add(card, snd_ctl_new1(&snd_ens1373_line, ensoniq)); | ||
1685 | if (err < 0) | 1698 | if (err < 0) |
1686 | return err; | 1699 | return err; |
1687 | } | 1700 | } |
@@ -1956,21 +1969,15 @@ static int snd_ensoniq_dev_free(struct snd_device *device) | |||
1956 | } | 1969 | } |
1957 | 1970 | ||
1958 | #ifdef CHIP1371 | 1971 | #ifdef CHIP1371 |
1959 | static struct { | 1972 | static struct snd_pci_quirk es1371_amplifier_hack[] __devinitdata = { |
1960 | unsigned short svid; /* subsystem vendor ID */ | 1973 | SND_PCI_QUIRK_ID(0x107b, 0x2150), /* Gateway Solo 2150 */ |
1961 | unsigned short sdid; /* subsystem device ID */ | 1974 | SND_PCI_QUIRK_ID(0x13bd, 0x100c), /* EV1938 on Mebius PC-MJ100V */ |
1962 | } es1371_amplifier_hack[] = { | 1975 | SND_PCI_QUIRK_ID(0x1102, 0x5938), /* Targa Xtender300 */ |
1963 | { .svid = 0x107b, .sdid = 0x2150 }, /* Gateway Solo 2150 */ | 1976 | SND_PCI_QUIRK_ID(0x1102, 0x8938), /* IPC Topnote G notebook */ |
1964 | { .svid = 0x13bd, .sdid = 0x100c }, /* EV1938 on Mebius PC-MJ100V */ | 1977 | { } /* end */ |
1965 | { .svid = 0x1102, .sdid = 0x5938 }, /* Targa Xtender300 */ | ||
1966 | { .svid = 0x1102, .sdid = 0x8938 }, /* IPC Topnote G notebook */ | ||
1967 | { .svid = PCI_ANY_ID, .sdid = PCI_ANY_ID } | ||
1968 | }; | 1978 | }; |
1969 | static struct { | 1979 | |
1970 | unsigned short vid; /* vendor ID */ | 1980 | static struct es1371_quirk es1371_ac97_reset_hack[] = { |
1971 | unsigned short did; /* device ID */ | ||
1972 | unsigned char rev; /* revision */ | ||
1973 | } es1371_ac97_reset_hack[] = { | ||
1974 | { .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_C }, | 1981 | { .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_C }, |
1975 | { .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_D }, | 1982 | { .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_D }, |
1976 | { .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_E }, | 1983 | { .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_E }, |
@@ -1984,7 +1991,6 @@ static void snd_ensoniq_chip_init(struct ensoniq *ensoniq) | |||
1984 | { | 1991 | { |
1985 | #ifdef CHIP1371 | 1992 | #ifdef CHIP1371 |
1986 | int idx; | 1993 | int idx; |
1987 | struct pci_dev *pci = ensoniq->pci; | ||
1988 | #endif | 1994 | #endif |
1989 | /* this code was part of snd_ensoniq_create before intruduction | 1995 | /* this code was part of snd_ensoniq_create before intruduction |
1990 | * of suspend/resume | 1996 | * of suspend/resume |
@@ -1999,16 +2005,12 @@ static void snd_ensoniq_chip_init(struct ensoniq *ensoniq) | |||
1999 | outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL)); | 2005 | outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL)); |
2000 | outl(ensoniq->sctrl, ES_REG(ensoniq, SERIAL)); | 2006 | outl(ensoniq->sctrl, ES_REG(ensoniq, SERIAL)); |
2001 | outl(0, ES_REG(ensoniq, 1371_LEGACY)); | 2007 | outl(0, ES_REG(ensoniq, 1371_LEGACY)); |
2002 | for (idx = 0; es1371_ac97_reset_hack[idx].vid != (unsigned short)PCI_ANY_ID; idx++) | 2008 | if (es1371_quirk_lookup(ensoniq, es1371_ac97_reset_hack)) { |
2003 | if (pci->vendor == es1371_ac97_reset_hack[idx].vid && | 2009 | outl(ensoniq->cssr, ES_REG(ensoniq, STATUS)); |
2004 | pci->device == es1371_ac97_reset_hack[idx].did && | 2010 | /* need to delay around 20ms(bleech) to give |
2005 | ensoniq->rev == es1371_ac97_reset_hack[idx].rev) { | 2011 | some CODECs enough time to wakeup */ |
2006 | outl(ensoniq->cssr, ES_REG(ensoniq, STATUS)); | 2012 | msleep(20); |
2007 | /* need to delay around 20ms(bleech) to give | 2013 | } |
2008 | some CODECs enough time to wakeup */ | ||
2009 | msleep(20); | ||
2010 | break; | ||
2011 | } | ||
2012 | /* AC'97 warm reset to start the bitclk */ | 2014 | /* AC'97 warm reset to start the bitclk */ |
2013 | outl(ensoniq->ctrl | ES_1371_SYNC_RES, ES_REG(ensoniq, CONTROL)); | 2015 | outl(ensoniq->ctrl | ES_1371_SYNC_RES, ES_REG(ensoniq, CONTROL)); |
2014 | inl(ES_REG(ensoniq, CONTROL)); | 2016 | inl(ES_REG(ensoniq, CONTROL)); |
@@ -2112,11 +2114,7 @@ static int __devinit snd_ensoniq_create(struct snd_card *card, | |||
2112 | struct ensoniq ** rensoniq) | 2114 | struct ensoniq ** rensoniq) |
2113 | { | 2115 | { |
2114 | struct ensoniq *ensoniq; | 2116 | struct ensoniq *ensoniq; |
2115 | unsigned short cmdw; | ||
2116 | unsigned char cmdb; | 2117 | unsigned char cmdb; |
2117 | #ifdef CHIP1371 | ||
2118 | int idx; | ||
2119 | #endif | ||
2120 | int err; | 2118 | int err; |
2121 | static struct snd_device_ops ops = { | 2119 | static struct snd_device_ops ops = { |
2122 | .dev_free = snd_ensoniq_dev_free, | 2120 | .dev_free = snd_ensoniq_dev_free, |
@@ -2159,10 +2157,6 @@ static int __devinit snd_ensoniq_create(struct snd_card *card, | |||
2159 | pci_set_master(pci); | 2157 | pci_set_master(pci); |
2160 | pci_read_config_byte(pci, PCI_REVISION_ID, &cmdb); | 2158 | pci_read_config_byte(pci, PCI_REVISION_ID, &cmdb); |
2161 | ensoniq->rev = cmdb; | 2159 | ensoniq->rev = cmdb; |
2162 | pci_read_config_word(pci, PCI_SUBSYSTEM_VENDOR_ID, &cmdw); | ||
2163 | ensoniq->subsystem_vendor_id = cmdw; | ||
2164 | pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &cmdw); | ||
2165 | ensoniq->subsystem_device_id = cmdw; | ||
2166 | #ifdef CHIP1370 | 2160 | #ifdef CHIP1370 |
2167 | #if 0 | 2161 | #if 0 |
2168 | ensoniq->ctrl = ES_1370_CDC_EN | ES_1370_SERR_DISABLE | | 2162 | ensoniq->ctrl = ES_1370_CDC_EN | ES_1370_SERR_DISABLE | |
@@ -2175,19 +2169,11 @@ static int __devinit snd_ensoniq_create(struct snd_card *card, | |||
2175 | ensoniq->ctrl = 0; | 2169 | ensoniq->ctrl = 0; |
2176 | ensoniq->sctrl = 0; | 2170 | ensoniq->sctrl = 0; |
2177 | ensoniq->cssr = 0; | 2171 | ensoniq->cssr = 0; |
2178 | for (idx = 0; es1371_amplifier_hack[idx].svid != (unsigned short)PCI_ANY_ID; idx++) | 2172 | if (snd_pci_quirk_lookup(pci, es1371_amplifier_hack)) |
2179 | if (ensoniq->subsystem_vendor_id == es1371_amplifier_hack[idx].svid && | 2173 | ensoniq->ctrl |= ES_1371_GPIO_OUT(1); /* turn amplifier on */ |
2180 | ensoniq->subsystem_device_id == es1371_amplifier_hack[idx].sdid) { | 2174 | |
2181 | ensoniq->ctrl |= ES_1371_GPIO_OUT(1); /* turn amplifier on */ | 2175 | if (es1371_quirk_lookup(ensoniq, es1371_ac97_reset_hack)) |
2182 | break; | 2176 | ensoniq->cssr |= ES_1371_ST_AC97_RST; |
2183 | } | ||
2184 | for (idx = 0; es1371_ac97_reset_hack[idx].vid != (unsigned short)PCI_ANY_ID; idx++) | ||
2185 | if (pci->vendor == es1371_ac97_reset_hack[idx].vid && | ||
2186 | pci->device == es1371_ac97_reset_hack[idx].did && | ||
2187 | ensoniq->rev == es1371_ac97_reset_hack[idx].rev) { | ||
2188 | ensoniq->cssr |= ES_1371_ST_AC97_RST; | ||
2189 | break; | ||
2190 | } | ||
2191 | #endif | 2177 | #endif |
2192 | 2178 | ||
2193 | snd_ensoniq_chip_init(ensoniq); | 2179 | snd_ensoniq_chip_init(ensoniq); |
diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c index 66ac26c5a240..fec29a108945 100644 --- a/sound/pci/es1938.c +++ b/sound/pci/es1938.c | |||
@@ -1344,7 +1344,7 @@ static unsigned int db_scale_line[] = { | |||
1344 | 8, 15, TLV_DB_SCALE_ITEM(-750, 150, 0), | 1344 | 8, 15, TLV_DB_SCALE_ITEM(-750, 150, 0), |
1345 | }; | 1345 | }; |
1346 | 1346 | ||
1347 | static DECLARE_TLV_DB_SCALE(db_scale_capture, 0, 150, 0); | 1347 | static const DECLARE_TLV_DB_SCALE(db_scale_capture, 0, 150, 0); |
1348 | 1348 | ||
1349 | static struct snd_kcontrol_new snd_es1938_controls[] = { | 1349 | static struct snd_kcontrol_new snd_es1938_controls[] = { |
1350 | ES1938_DOUBLE_TLV("Master Playback Volume", 0, 0x60, 0x62, 0, 0, 63, 0, | 1350 | ES1938_DOUBLE_TLV("Master Playback Volume", 0, 0x60, 0x62, 0, 0, 63, 0, |
diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index b7b361ce3a93..6dc578bbeec9 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c | |||
@@ -1157,7 +1157,7 @@ static int snd_fm801_put_mux(struct snd_kcontrol *kcontrol, | |||
1157 | return snd_fm801_update_bits(chip, FM801_REC_SRC, 7, val); | 1157 | return snd_fm801_update_bits(chip, FM801_REC_SRC, 7, val); |
1158 | } | 1158 | } |
1159 | 1159 | ||
1160 | static DECLARE_TLV_DB_SCALE(db_scale_dsp, -3450, 150, 0); | 1160 | static const DECLARE_TLV_DB_SCALE(db_scale_dsp, -3450, 150, 0); |
1161 | 1161 | ||
1162 | #define FM801_CONTROLS ARRAY_SIZE(snd_fm801_controls) | 1162 | #define FM801_CONTROLS ARRAY_SIZE(snd_fm801_controls) |
1163 | 1163 | ||
diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index dbacba6177db..60d7b05a204a 100644 --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile | |||
@@ -1,5 +1,14 @@ | |||
1 | snd-hda-intel-objs := hda_intel.o | 1 | snd-hda-intel-objs := hda_intel.o |
2 | snd-hda-codec-objs := hda_codec.o hda_generic.o patch_realtek.o patch_cmedia.o patch_analog.o patch_sigmatel.o patch_si3054.o patch_atihdmi.o | 2 | snd-hda-codec-objs := hda_codec.o \ |
3 | hda_generic.o \ | ||
4 | patch_realtek.o \ | ||
5 | patch_cmedia.o \ | ||
6 | patch_analog.o \ | ||
7 | patch_sigmatel.o \ | ||
8 | patch_si3054.o \ | ||
9 | patch_atihdmi.o \ | ||
10 | patch_conexant.o \ | ||
11 | patch_via.o | ||
3 | ifdef CONFIG_PROC_FS | 12 | ifdef CONFIG_PROC_FS |
4 | snd-hda-codec-objs += hda_proc.o | 13 | snd-hda-codec-objs += hda_proc.o |
5 | endif | 14 | endif |
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 18bbc87e376f..8f34fb447983 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c | |||
@@ -52,6 +52,7 @@ struct hda_vendor_id { | |||
52 | static struct hda_vendor_id hda_vendor_ids[] = { | 52 | static struct hda_vendor_id hda_vendor_ids[] = { |
53 | { 0x10ec, "Realtek" }, | 53 | { 0x10ec, "Realtek" }, |
54 | { 0x1057, "Motorola" }, | 54 | { 0x1057, "Motorola" }, |
55 | { 0x1106, "VIA" }, | ||
55 | { 0x11d4, "Analog Devices" }, | 56 | { 0x11d4, "Analog Devices" }, |
56 | { 0x13f6, "C-Media" }, | 57 | { 0x13f6, "C-Media" }, |
57 | { 0x14f1, "Conexant" }, | 58 | { 0x14f1, "Conexant" }, |
@@ -262,7 +263,7 @@ int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex) | |||
262 | unsol->queue[wp] = res; | 263 | unsol->queue[wp] = res; |
263 | unsol->queue[wp + 1] = res_ex; | 264 | unsol->queue[wp + 1] = res_ex; |
264 | 265 | ||
265 | queue_work(unsol->workq, &unsol->work); | 266 | schedule_work(&unsol->work); |
266 | 267 | ||
267 | return 0; | 268 | return 0; |
268 | } | 269 | } |
@@ -309,12 +310,6 @@ static int init_unsol_queue(struct hda_bus *bus) | |||
309 | snd_printk(KERN_ERR "hda_codec: can't allocate unsolicited queue\n"); | 310 | snd_printk(KERN_ERR "hda_codec: can't allocate unsolicited queue\n"); |
310 | return -ENOMEM; | 311 | return -ENOMEM; |
311 | } | 312 | } |
312 | unsol->workq = create_singlethread_workqueue("hda_codec"); | ||
313 | if (! unsol->workq) { | ||
314 | snd_printk(KERN_ERR "hda_codec: can't create workqueue\n"); | ||
315 | kfree(unsol); | ||
316 | return -ENOMEM; | ||
317 | } | ||
318 | INIT_WORK(&unsol->work, process_unsol_events); | 313 | INIT_WORK(&unsol->work, process_unsol_events); |
319 | unsol->bus = bus; | 314 | unsol->bus = bus; |
320 | bus->unsol = unsol; | 315 | bus->unsol = unsol; |
@@ -333,7 +328,7 @@ static int snd_hda_bus_free(struct hda_bus *bus) | |||
333 | if (! bus) | 328 | if (! bus) |
334 | return 0; | 329 | return 0; |
335 | if (bus->unsol) { | 330 | if (bus->unsol) { |
336 | destroy_workqueue(bus->unsol->workq); | 331 | flush_scheduled_work(); |
337 | kfree(bus->unsol); | 332 | kfree(bus->unsol); |
338 | } | 333 | } |
339 | list_for_each_safe(p, n, &bus->codec_list) { | 334 | list_for_each_safe(p, n, &bus->codec_list) { |
@@ -1714,6 +1709,8 @@ EXPORT_SYMBOL(snd_hda_build_pcms); | |||
1714 | /** | 1709 | /** |
1715 | * snd_hda_check_board_config - compare the current codec with the config table | 1710 | * snd_hda_check_board_config - compare the current codec with the config table |
1716 | * @codec: the HDA codec | 1711 | * @codec: the HDA codec |
1712 | * @num_configs: number of config enums | ||
1713 | * @models: array of model name strings | ||
1717 | * @tbl: configuration table, terminated by null entries | 1714 | * @tbl: configuration table, terminated by null entries |
1718 | * | 1715 | * |
1719 | * Compares the modelname or PCI subsystem id of the current codec with the | 1716 | * Compares the modelname or PCI subsystem id of the current codec with the |
@@ -1722,33 +1719,44 @@ EXPORT_SYMBOL(snd_hda_build_pcms); | |||
1722 | * | 1719 | * |
1723 | * If no entries are matching, the function returns a negative value. | 1720 | * If no entries are matching, the function returns a negative value. |
1724 | */ | 1721 | */ |
1725 | int snd_hda_check_board_config(struct hda_codec *codec, const struct hda_board_config *tbl) | 1722 | int snd_hda_check_board_config(struct hda_codec *codec, |
1726 | { | 1723 | int num_configs, const char **models, |
1727 | const struct hda_board_config *c; | 1724 | const struct snd_pci_quirk *tbl) |
1728 | 1725 | { | |
1729 | if (codec->bus->modelname) { | 1726 | if (codec->bus->modelname && models) { |
1730 | for (c = tbl; c->modelname || c->pci_subvendor; c++) { | 1727 | int i; |
1731 | if (c->modelname && | 1728 | for (i = 0; i < num_configs; i++) { |
1732 | ! strcmp(codec->bus->modelname, c->modelname)) { | 1729 | if (models[i] && |
1733 | snd_printd(KERN_INFO "hda_codec: model '%s' is selected\n", c->modelname); | 1730 | !strcmp(codec->bus->modelname, models[i])) { |
1734 | return c->config; | 1731 | snd_printd(KERN_INFO "hda_codec: model '%s' is " |
1732 | "selected\n", models[i]); | ||
1733 | return i; | ||
1735 | } | 1734 | } |
1736 | } | 1735 | } |
1737 | } | 1736 | } |
1738 | 1737 | ||
1739 | if (codec->bus->pci) { | 1738 | if (!codec->bus->pci || !tbl) |
1740 | u16 subsystem_vendor, subsystem_device; | 1739 | return -1; |
1741 | pci_read_config_word(codec->bus->pci, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vendor); | 1740 | |
1742 | pci_read_config_word(codec->bus->pci, PCI_SUBSYSTEM_ID, &subsystem_device); | 1741 | tbl = snd_pci_quirk_lookup(codec->bus->pci, tbl); |
1743 | for (c = tbl; c->modelname || c->pci_subvendor; c++) { | 1742 | if (!tbl) |
1744 | if (c->pci_subvendor == subsystem_vendor && | 1743 | return -1; |
1745 | (! c->pci_subdevice /* all match */|| | 1744 | if (tbl->value >= 0 && tbl->value < num_configs) { |
1746 | (c->pci_subdevice == subsystem_device))) { | 1745 | #ifdef CONFIG_SND_DEBUG_DETECT |
1747 | snd_printdd(KERN_INFO "hda_codec: PCI %x:%x, codec config %d is selected\n", | 1746 | char tmp[10]; |
1748 | subsystem_vendor, subsystem_device, c->config); | 1747 | const char *model = NULL; |
1749 | return c->config; | 1748 | if (models) |
1750 | } | 1749 | model = models[tbl->value]; |
1750 | if (!model) { | ||
1751 | sprintf(tmp, "#%d", tbl->value); | ||
1752 | model = tmp; | ||
1751 | } | 1753 | } |
1754 | snd_printdd(KERN_INFO "hda_codec: model '%s' is selected " | ||
1755 | "for config %x:%x (%s)\n", | ||
1756 | model, tbl->subvendor, tbl->subdevice, | ||
1757 | (tbl->name ? tbl->name : "Unknown device")); | ||
1758 | #endif | ||
1759 | return tbl->value; | ||
1752 | } | 1760 | } |
1753 | return -1; | 1761 | return -1; |
1754 | } | 1762 | } |
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 1a7e82104bb9..b9a8e238b0a8 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c | |||
@@ -199,7 +199,7 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; | |||
199 | 199 | ||
200 | /* STATESTS int mask: SD2,SD1,SD0 */ | 200 | /* STATESTS int mask: SD2,SD1,SD0 */ |
201 | #define STATESTS_INT_MASK 0x07 | 201 | #define STATESTS_INT_MASK 0x07 |
202 | #define AZX_MAX_CODECS 4 | 202 | #define AZX_MAX_CODECS 3 |
203 | 203 | ||
204 | /* SD_CTL bits */ | 204 | /* SD_CTL bits */ |
205 | #define SD_CTL_STREAM_RESET 0x01 /* stream reset bit */ | 205 | #define SD_CTL_STREAM_RESET 0x01 /* stream reset bit */ |
@@ -1285,7 +1285,7 @@ static int __devinit create_codec_pcm(struct azx *chip, struct hda_codec *codec, | |||
1285 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &azx_pcm_ops); | 1285 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &azx_pcm_ops); |
1286 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, | 1286 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, |
1287 | snd_dma_pci_data(chip->pci), | 1287 | snd_dma_pci_data(chip->pci), |
1288 | 1024 * 64, 1024 * 128); | 1288 | 1024 * 64, 1024 * 1024); |
1289 | chip->pcm[pcm_dev] = pcm; | 1289 | chip->pcm[pcm_dev] = pcm; |
1290 | if (chip->pcm_devs < pcm_dev + 1) | 1290 | if (chip->pcm_devs < pcm_dev + 1) |
1291 | chip->pcm_devs = pcm_dev + 1; | 1291 | chip->pcm_devs = pcm_dev + 1; |
@@ -1391,6 +1391,7 @@ static int azx_acquire_irq(struct azx *chip, int do_disconnect) | |||
1391 | return -1; | 1391 | return -1; |
1392 | } | 1392 | } |
1393 | chip->irq = chip->pci->irq; | 1393 | chip->irq = chip->pci->irq; |
1394 | pci_intx(chip->pci, !chip->msi); | ||
1394 | return 0; | 1395 | return 0; |
1395 | } | 1396 | } |
1396 | 1397 | ||
@@ -1502,6 +1503,31 @@ static int azx_dev_free(struct snd_device *device) | |||
1502 | } | 1503 | } |
1503 | 1504 | ||
1504 | /* | 1505 | /* |
1506 | * white/black-listing for position_fix | ||
1507 | */ | ||
1508 | static const struct snd_pci_quirk position_fix_list[] __devinitdata = { | ||
1509 | SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_NONE), | ||
1510 | {} | ||
1511 | }; | ||
1512 | |||
1513 | static int __devinit check_position_fix(struct azx *chip, int fix) | ||
1514 | { | ||
1515 | const struct snd_pci_quirk *q; | ||
1516 | |||
1517 | if (fix == POS_FIX_AUTO) { | ||
1518 | q = snd_pci_quirk_lookup(chip->pci, position_fix_list); | ||
1519 | if (q) { | ||
1520 | snd_printdd(KERN_INFO | ||
1521 | "hda_intel: position_fix set to %d " | ||
1522 | "for device %04x:%04x\n", | ||
1523 | q->value, q->subvendor, q->subdevice); | ||
1524 | return q->value; | ||
1525 | } | ||
1526 | } | ||
1527 | return fix; | ||
1528 | } | ||
1529 | |||
1530 | /* | ||
1505 | * constructor | 1531 | * constructor |
1506 | */ | 1532 | */ |
1507 | static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, | 1533 | static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, |
@@ -1535,7 +1561,8 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, | |||
1535 | chip->driver_type = driver_type; | 1561 | chip->driver_type = driver_type; |
1536 | chip->msi = enable_msi; | 1562 | chip->msi = enable_msi; |
1537 | 1563 | ||
1538 | chip->position_fix = position_fix; | 1564 | chip->position_fix = check_position_fix(chip, position_fix); |
1565 | |||
1539 | chip->single_cmd = single_cmd; | 1566 | chip->single_cmd = single_cmd; |
1540 | 1567 | ||
1541 | #if BITS_PER_LONG != 64 | 1568 | #if BITS_PER_LONG != 64 |
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 9ca1baf860bd..39718d6cdadd 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h | |||
@@ -173,14 +173,9 @@ static inline int snd_hda_codec_proc_new(struct hda_codec *codec) { return 0; } | |||
173 | /* | 173 | /* |
174 | * Misc | 174 | * Misc |
175 | */ | 175 | */ |
176 | struct hda_board_config { | 176 | int snd_hda_check_board_config(struct hda_codec *codec, int num_configs, |
177 | const char *modelname; | 177 | const char **modelnames, |
178 | int config; | 178 | const struct snd_pci_quirk *pci_list); |
179 | unsigned short pci_subvendor; | ||
180 | unsigned short pci_subdevice; | ||
181 | }; | ||
182 | |||
183 | int snd_hda_check_board_config(struct hda_codec *codec, const struct hda_board_config *tbl); | ||
184 | int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew); | 179 | int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew); |
185 | 180 | ||
186 | /* | 181 | /* |
@@ -204,7 +199,6 @@ struct hda_bus_unsolicited { | |||
204 | unsigned int rp, wp; | 199 | unsigned int rp, wp; |
205 | 200 | ||
206 | /* workqueue */ | 201 | /* workqueue */ |
207 | struct workqueue_struct *workq; | ||
208 | struct work_struct work; | 202 | struct work_struct work; |
209 | struct hda_bus *bus; | 203 | struct hda_bus *bus; |
210 | }; | 204 | }; |
diff --git a/sound/pci/hda/hda_patch.h b/sound/pci/hda/hda_patch.h index 0b668793face..9f9e9ae44a9d 100644 --- a/sound/pci/hda/hda_patch.h +++ b/sound/pci/hda/hda_patch.h | |||
@@ -14,6 +14,10 @@ extern struct hda_codec_preset snd_hda_preset_sigmatel[]; | |||
14 | extern struct hda_codec_preset snd_hda_preset_si3054[]; | 14 | extern struct hda_codec_preset snd_hda_preset_si3054[]; |
15 | /* ATI HDMI codecs */ | 15 | /* ATI HDMI codecs */ |
16 | extern struct hda_codec_preset snd_hda_preset_atihdmi[]; | 16 | extern struct hda_codec_preset snd_hda_preset_atihdmi[]; |
17 | /* Conexant audio codec */ | ||
18 | extern struct hda_codec_preset snd_hda_preset_conexant[]; | ||
19 | /* VIA codecs */ | ||
20 | extern struct hda_codec_preset snd_hda_preset_via[]; | ||
17 | 21 | ||
18 | static const struct hda_codec_preset *hda_preset_tables[] = { | 22 | static const struct hda_codec_preset *hda_preset_tables[] = { |
19 | snd_hda_preset_realtek, | 23 | snd_hda_preset_realtek, |
@@ -22,5 +26,7 @@ static const struct hda_codec_preset *hda_preset_tables[] = { | |||
22 | snd_hda_preset_sigmatel, | 26 | snd_hda_preset_sigmatel, |
23 | snd_hda_preset_si3054, | 27 | snd_hda_preset_si3054, |
24 | snd_hda_preset_atihdmi, | 28 | snd_hda_preset_atihdmi, |
29 | snd_hda_preset_conexant, | ||
30 | snd_hda_preset_via, | ||
25 | NULL | 31 | NULL |
26 | }; | 32 | }; |
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 076365bc10e9..38977bce70e2 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c | |||
@@ -782,54 +782,63 @@ static struct hda_channel_mode ad1986a_modes[3] = { | |||
782 | 782 | ||
783 | /* eapd initialization */ | 783 | /* eapd initialization */ |
784 | static struct hda_verb ad1986a_eapd_init_verbs[] = { | 784 | static struct hda_verb ad1986a_eapd_init_verbs[] = { |
785 | {0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00}, | 785 | {0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 }, |
786 | {} | 786 | {} |
787 | }; | 787 | }; |
788 | 788 | ||
789 | /* Ultra initialization */ | ||
790 | static struct hda_verb ad1986a_ultra_init[] = { | ||
791 | /* eapd initialization */ | ||
792 | { 0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 }, | ||
793 | /* CLFE -> Mic in */ | ||
794 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2 }, | ||
795 | { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | ||
796 | { 0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 }, | ||
797 | { } /* end */ | ||
798 | }; | ||
799 | |||
789 | /* models */ | 800 | /* models */ |
790 | enum { AD1986A_6STACK, AD1986A_3STACK, AD1986A_LAPTOP, AD1986A_LAPTOP_EAPD }; | 801 | enum { |
791 | 802 | AD1986A_6STACK, | |
792 | static struct hda_board_config ad1986a_cfg_tbl[] = { | 803 | AD1986A_3STACK, |
793 | { .modelname = "6stack", .config = AD1986A_6STACK }, | 804 | AD1986A_LAPTOP, |
794 | { .modelname = "3stack", .config = AD1986A_3STACK }, | 805 | AD1986A_LAPTOP_EAPD, |
795 | { .pci_subvendor = 0x10de, .pci_subdevice = 0xcb84, | 806 | AD1986A_ULTRA, |
796 | .config = AD1986A_3STACK }, /* ASUS A8N-VM CSM */ | 807 | AD1986A_MODELS |
797 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x817f, | 808 | }; |
798 | .config = AD1986A_3STACK }, /* ASUS P5P-L2 */ | 809 | |
799 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x81b3, | 810 | static const char *ad1986a_models[AD1986A_MODELS] = { |
800 | .config = AD1986A_3STACK }, /* ASUS P5RD2-VM / P5GPL-X SE */ | 811 | [AD1986A_6STACK] = "6stack", |
801 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x81cb, | 812 | [AD1986A_3STACK] = "3stack", |
802 | .config = AD1986A_3STACK }, /* ASUS M2NPV-VM */ | 813 | [AD1986A_LAPTOP] = "laptop", |
803 | { .modelname = "laptop", .config = AD1986A_LAPTOP }, | 814 | [AD1986A_LAPTOP_EAPD] = "laptop-eapd", |
804 | { .pci_subvendor = 0x144d, .pci_subdevice = 0xc01e, | 815 | [AD1986A_ULTRA] = "ultra", |
805 | .config = AD1986A_LAPTOP }, /* FSC V2060 */ | 816 | }; |
806 | { .pci_subvendor = 0x17c0, .pci_subdevice = 0x2017, | 817 | |
807 | .config = AD1986A_LAPTOP }, /* Samsung M50 */ | 818 | static struct snd_pci_quirk ad1986a_cfg_tbl[] = { |
808 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x818f, | 819 | SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_LAPTOP_EAPD), |
809 | .config = AD1986A_LAPTOP }, /* ASUS P5GV-MX */ | 820 | SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_3STACK), |
810 | { .modelname = "laptop-eapd", .config = AD1986A_LAPTOP_EAPD }, | 821 | SND_PCI_QUIRK(0x1043, 0x1153, "ASUS M9", AD1986A_LAPTOP_EAPD), |
811 | { .pci_subvendor = 0x144d, .pci_subdevice = 0xc023, | 822 | SND_PCI_QUIRK(0x1043, 0x1213, "ASUS A6J", AD1986A_LAPTOP_EAPD), |
812 | .config = AD1986A_LAPTOP_EAPD }, /* Samsung X60 Chane */ | 823 | SND_PCI_QUIRK(0x1043, 0x11f7, "ASUS U5A", AD1986A_LAPTOP_EAPD), |
813 | { .pci_subvendor = 0x144d, .pci_subdevice = 0xc024, | 824 | SND_PCI_QUIRK(0x1043, 0x1263, "ASUS U5F", AD1986A_LAPTOP_EAPD), |
814 | .config = AD1986A_LAPTOP_EAPD }, /* Samsung R65-T2300 Charis */ | 825 | SND_PCI_QUIRK(0x1043, 0x1297, "ASUS Z62F", AD1986A_LAPTOP_EAPD), |
815 | { .pci_subvendor = 0x144d, .pci_subdevice = 0xc026, | 826 | SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS V1j", AD1986A_LAPTOP_EAPD), |
816 | .config = AD1986A_LAPTOP_EAPD }, /* Samsung X11-T2300 Culesa */ | 827 | SND_PCI_QUIRK(0x1043, 0x1302, "ASUS W3j", AD1986A_LAPTOP_EAPD), |
817 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1153, | 828 | SND_PCI_QUIRK(0x1043, 0x817f, "ASUS P5", AD1986A_3STACK), |
818 | .config = AD1986A_LAPTOP_EAPD }, /* ASUS M9 */ | 829 | SND_PCI_QUIRK(0x1043, 0x818f, "ASUS P5", AD1986A_LAPTOP), |
819 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1213, | 830 | SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS P5", AD1986A_3STACK), |
820 | .config = AD1986A_LAPTOP_EAPD }, /* ASUS A6J */ | 831 | SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS M2N", AD1986A_3STACK), |
821 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x11f7, | 832 | SND_PCI_QUIRK(0x1043, 0x8234, "ASUS M2N", AD1986A_3STACK), |
822 | .config = AD1986A_LAPTOP_EAPD }, /* ASUS U5A */ | 833 | SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP), |
823 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1263, | 834 | SND_PCI_QUIRK(0x144d, 0xc023, "Samsung X60", AD1986A_LAPTOP_EAPD), |
824 | .config = AD1986A_LAPTOP_EAPD }, /* ASUS U5F */ | 835 | SND_PCI_QUIRK(0x144d, 0xc024, "Samsung R65", AD1986A_LAPTOP_EAPD), |
825 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1297, | 836 | SND_PCI_QUIRK(0x144d, 0xc026, "Samsung X11", AD1986A_LAPTOP_EAPD), |
826 | .config = AD1986A_LAPTOP_EAPD }, /* ASUS Z62F */ | 837 | SND_PCI_QUIRK(0x144d, 0xc504, "Samsung Q35", AD1986A_3STACK), |
827 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x12b3, | 838 | SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_ULTRA), |
828 | .config = AD1986A_LAPTOP_EAPD }, /* ASUS V1j */ | 839 | SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_3STACK), |
829 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x30af, | 840 | SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_LAPTOP_EAPD), |
830 | .config = AD1986A_LAPTOP_EAPD }, /* HP Compaq Presario B2800 */ | 841 | SND_PCI_QUIRK(0x17c0, 0x2017, "Samsung M50", AD1986A_LAPTOP), |
831 | { .pci_subvendor = 0x17aa, .pci_subdevice = 0x2066, | ||
832 | .config = AD1986A_LAPTOP_EAPD }, /* Lenovo 3000 N100-07684JU */ | ||
833 | {} | 842 | {} |
834 | }; | 843 | }; |
835 | 844 | ||
@@ -861,7 +870,9 @@ static int patch_ad1986a(struct hda_codec *codec) | |||
861 | codec->patch_ops = ad198x_patch_ops; | 870 | codec->patch_ops = ad198x_patch_ops; |
862 | 871 | ||
863 | /* override some parameters */ | 872 | /* override some parameters */ |
864 | board_config = snd_hda_check_board_config(codec, ad1986a_cfg_tbl); | 873 | board_config = snd_hda_check_board_config(codec, AD1986A_MODELS, |
874 | ad1986a_models, | ||
875 | ad1986a_cfg_tbl); | ||
865 | switch (board_config) { | 876 | switch (board_config) { |
866 | case AD1986A_3STACK: | 877 | case AD1986A_3STACK: |
867 | spec->num_mixers = 2; | 878 | spec->num_mixers = 2; |
@@ -891,6 +902,15 @@ static int patch_ad1986a(struct hda_codec *codec) | |||
891 | spec->multiout.dig_out_nid = 0; | 902 | spec->multiout.dig_out_nid = 0; |
892 | spec->input_mux = &ad1986a_laptop_eapd_capture_source; | 903 | spec->input_mux = &ad1986a_laptop_eapd_capture_source; |
893 | break; | 904 | break; |
905 | case AD1986A_ULTRA: | ||
906 | spec->mixers[0] = ad1986a_laptop_eapd_mixers; | ||
907 | spec->num_init_verbs = 2; | ||
908 | spec->init_verbs[1] = ad1986a_ultra_init; | ||
909 | spec->multiout.max_channels = 2; | ||
910 | spec->multiout.num_dacs = 1; | ||
911 | spec->multiout.dac_nids = ad1986a_laptop_dac_nids; | ||
912 | spec->multiout.dig_out_nid = 0; | ||
913 | break; | ||
894 | } | 914 | } |
895 | 915 | ||
896 | return 0; | 916 | return 0; |
@@ -1391,20 +1411,27 @@ static struct hda_input_mux ad1981_thinkpad_capture_source = { | |||
1391 | }; | 1411 | }; |
1392 | 1412 | ||
1393 | /* models */ | 1413 | /* models */ |
1394 | enum { AD1981_BASIC, AD1981_HP, AD1981_THINKPAD }; | 1414 | enum { |
1415 | AD1981_BASIC, | ||
1416 | AD1981_HP, | ||
1417 | AD1981_THINKPAD, | ||
1418 | AD1981_MODELS | ||
1419 | }; | ||
1420 | |||
1421 | static const char *ad1981_models[AD1981_MODELS] = { | ||
1422 | [AD1981_HP] = "hp", | ||
1423 | [AD1981_THINKPAD] = "thinkpad", | ||
1424 | [AD1981_BASIC] = "basic", | ||
1425 | }; | ||
1395 | 1426 | ||
1396 | static struct hda_board_config ad1981_cfg_tbl[] = { | 1427 | static struct snd_pci_quirk ad1981_cfg_tbl[] = { |
1397 | { .modelname = "hp", .config = AD1981_HP }, | ||
1398 | /* All HP models */ | 1428 | /* All HP models */ |
1399 | { .pci_subvendor = 0x103c, .config = AD1981_HP }, | 1429 | SND_PCI_QUIRK(0x103c, 0, "HP nx", AD1981_HP), |
1400 | { .pci_subvendor = 0x30b0, .pci_subdevice = 0x103c, | 1430 | /* HP nx6320 (reversed SSID, H/W bug) */ |
1401 | .config = AD1981_HP }, /* HP nx6320 (reversed SSID, H/W bug) */ | 1431 | SND_PCI_QUIRK(0x30b0, 0x103c, "HP nx6320", AD1981_HP), |
1402 | { .modelname = "thinkpad", .config = AD1981_THINKPAD }, | ||
1403 | /* Lenovo Thinkpad T60/X60/Z6xx */ | 1432 | /* Lenovo Thinkpad T60/X60/Z6xx */ |
1404 | { .pci_subvendor = 0x17aa, .config = AD1981_THINKPAD }, | 1433 | SND_PCI_QUIRK(0x17aa, 0, "Lenovo Thinkpad", AD1981_THINKPAD), |
1405 | { .pci_subvendor = 0x1014, .pci_subdevice = 0x0597, | 1434 | SND_PCI_QUIRK(0x1014, 0x0597, "Lenovo Z60", AD1981_THINKPAD), |
1406 | .config = AD1981_THINKPAD }, /* Z60m/t */ | ||
1407 | { .modelname = "basic", .config = AD1981_BASIC }, | ||
1408 | {} | 1435 | {} |
1409 | }; | 1436 | }; |
1410 | 1437 | ||
@@ -1437,7 +1464,9 @@ static int patch_ad1981(struct hda_codec *codec) | |||
1437 | codec->patch_ops = ad198x_patch_ops; | 1464 | codec->patch_ops = ad198x_patch_ops; |
1438 | 1465 | ||
1439 | /* override some parameters */ | 1466 | /* override some parameters */ |
1440 | board_config = snd_hda_check_board_config(codec, ad1981_cfg_tbl); | 1467 | board_config = snd_hda_check_board_config(codec, AD1981_MODELS, |
1468 | ad1981_models, | ||
1469 | ad1981_cfg_tbl); | ||
1441 | switch (board_config) { | 1470 | switch (board_config) { |
1442 | case AD1981_HP: | 1471 | case AD1981_HP: |
1443 | spec->mixers[0] = ad1981_hp_mixers; | 1472 | spec->mixers[0] = ad1981_hp_mixers; |
@@ -2565,15 +2594,14 @@ static int ad1988_auto_init(struct hda_codec *codec) | |||
2565 | /* | 2594 | /* |
2566 | */ | 2595 | */ |
2567 | 2596 | ||
2568 | static struct hda_board_config ad1988_cfg_tbl[] = { | 2597 | static const char *ad1988_models[AD1988_MODEL_LAST] = { |
2569 | { .modelname = "6stack", .config = AD1988_6STACK }, | 2598 | [AD1988_6STACK] = "6stack", |
2570 | { .modelname = "6stack-dig", .config = AD1988_6STACK_DIG }, | 2599 | [AD1988_6STACK_DIG] = "6stack-dig", |
2571 | { .modelname = "3stack", .config = AD1988_3STACK }, | 2600 | [AD1988_3STACK] = "3stack", |
2572 | { .modelname = "3stack-dig", .config = AD1988_3STACK_DIG }, | 2601 | [AD1988_3STACK_DIG] = "3stack-dig", |
2573 | { .modelname = "laptop", .config = AD1988_LAPTOP }, | 2602 | [AD1988_LAPTOP] = "laptop", |
2574 | { .modelname = "laptop-dig", .config = AD1988_LAPTOP_DIG }, | 2603 | [AD1988_LAPTOP_DIG] = "laptop-dig", |
2575 | { .modelname = "auto", .config = AD1988_AUTO }, | 2604 | [AD1988_AUTO] = "auto", |
2576 | {} | ||
2577 | }; | 2605 | }; |
2578 | 2606 | ||
2579 | static int patch_ad1988(struct hda_codec *codec) | 2607 | static int patch_ad1988(struct hda_codec *codec) |
@@ -2591,8 +2619,9 @@ static int patch_ad1988(struct hda_codec *codec) | |||
2591 | if (is_rev2(codec)) | 2619 | if (is_rev2(codec)) |
2592 | snd_printk(KERN_INFO "patch_analog: AD1988A rev.2 is detected, enable workarounds\n"); | 2620 | snd_printk(KERN_INFO "patch_analog: AD1988A rev.2 is detected, enable workarounds\n"); |
2593 | 2621 | ||
2594 | board_config = snd_hda_check_board_config(codec, ad1988_cfg_tbl); | 2622 | board_config = snd_hda_check_board_config(codec, AD1988_MODEL_LAST, |
2595 | if (board_config < 0 || board_config >= AD1988_MODEL_LAST) { | 2623 | ad1988_models, NULL); |
2624 | if (board_config < 0) { | ||
2596 | printk(KERN_INFO "hda_codec: Unknown model for AD1988, trying auto-probe from BIOS...\n"); | 2625 | printk(KERN_INFO "hda_codec: Unknown model for AD1988, trying auto-probe from BIOS...\n"); |
2597 | board_config = AD1988_AUTO; | 2626 | board_config = AD1988_AUTO; |
2598 | } | 2627 | } |
diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c index d38ce22507ae..5b9d3a31a1ae 100644 --- a/sound/pci/hda/patch_cmedia.c +++ b/sound/pci/hda/patch_cmedia.c | |||
@@ -40,6 +40,7 @@ enum { | |||
40 | CMI_FULL_DIG, /* back 6-jack + front-panel 2-jack + digital I/O */ | 40 | CMI_FULL_DIG, /* back 6-jack + front-panel 2-jack + digital I/O */ |
41 | CMI_ALLOUT, /* back 5-jack + front-panel 2-jack + digital out */ | 41 | CMI_ALLOUT, /* back 5-jack + front-panel 2-jack + digital out */ |
42 | CMI_AUTO, /* let driver guess it */ | 42 | CMI_AUTO, /* let driver guess it */ |
43 | CMI_MODELS | ||
43 | }; | 44 | }; |
44 | 45 | ||
45 | struct cmi_spec { | 46 | struct cmi_spec { |
@@ -603,14 +604,17 @@ static void cmi9880_free(struct hda_codec *codec) | |||
603 | /* | 604 | /* |
604 | */ | 605 | */ |
605 | 606 | ||
606 | static struct hda_board_config cmi9880_cfg_tbl[] = { | 607 | static const char *cmi9880_models[CMI_MODELS] = { |
607 | { .modelname = "minimal", .config = CMI_MINIMAL }, | 608 | [CMI_MINIMAL] = "minimal", |
608 | { .modelname = "min_fp", .config = CMI_MIN_FP }, | 609 | [CMI_MIN_FP] = "min_fp", |
609 | { .modelname = "full", .config = CMI_FULL }, | 610 | [CMI_FULL] = "full", |
610 | { .modelname = "full_dig", .config = CMI_FULL_DIG }, | 611 | [CMI_FULL_DIG] = "full_dig", |
611 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x813d, .config = CMI_FULL_DIG }, /* ASUS P5AD2 */ | 612 | [CMI_ALLOUT] = "allout", |
612 | { .modelname = "allout", .config = CMI_ALLOUT }, | 613 | [CMI_AUTO] = "auto", |
613 | { .modelname = "auto", .config = CMI_AUTO }, | 614 | }; |
615 | |||
616 | static struct snd_pci_quirk cmi9880_cfg_tbl[] = { | ||
617 | SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", CMI_FULL_DIG), | ||
614 | {} /* terminator */ | 618 | {} /* terminator */ |
615 | }; | 619 | }; |
616 | 620 | ||
@@ -633,7 +637,9 @@ static int patch_cmi9880(struct hda_codec *codec) | |||
633 | return -ENOMEM; | 637 | return -ENOMEM; |
634 | 638 | ||
635 | codec->spec = spec; | 639 | codec->spec = spec; |
636 | spec->board_config = snd_hda_check_board_config(codec, cmi9880_cfg_tbl); | 640 | spec->board_config = snd_hda_check_board_config(codec, CMI_MODELS, |
641 | cmi9880_models, | ||
642 | cmi9880_cfg_tbl); | ||
637 | if (spec->board_config < 0) { | 643 | if (spec->board_config < 0) { |
638 | snd_printdd(KERN_INFO "hda_codec: Unknown model for CMI9880\n"); | 644 | snd_printdd(KERN_INFO "hda_codec: Unknown model for CMI9880\n"); |
639 | spec->board_config = CMI_AUTO; /* try everything */ | 645 | spec->board_config = CMI_AUTO; /* try everything */ |
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c new file mode 100644 index 000000000000..73f4668238c6 --- /dev/null +++ b/sound/pci/hda/patch_conexant.c | |||
@@ -0,0 +1,1311 @@ | |||
1 | /* | ||
2 | * HD audio interface patch for Conexant HDA audio codec | ||
3 | * | ||
4 | * Copyright (c) 2006 Pototskiy Akex <alex.pototskiy@gmail.com> | ||
5 | * Takashi Iwai <tiwai@suse.de> | ||
6 | * Tobin Davis <tdavis@dsl-only.net> | ||
7 | * | ||
8 | * This driver is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This driver is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
21 | */ | ||
22 | |||
23 | #include <sound/driver.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/delay.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <linux/pci.h> | ||
28 | #include <sound/core.h> | ||
29 | #include "hda_codec.h" | ||
30 | #include "hda_local.h" | ||
31 | |||
32 | #define CXT_PIN_DIR_IN 0x00 | ||
33 | #define CXT_PIN_DIR_OUT 0x01 | ||
34 | #define CXT_PIN_DIR_INOUT 0x02 | ||
35 | #define CXT_PIN_DIR_IN_NOMICBIAS 0x03 | ||
36 | #define CXT_PIN_DIR_INOUT_NOMICBIAS 0x04 | ||
37 | |||
38 | #define CONEXANT_HP_EVENT 0x37 | ||
39 | #define CONEXANT_MIC_EVENT 0x38 | ||
40 | |||
41 | |||
42 | |||
43 | struct conexant_spec { | ||
44 | |||
45 | struct snd_kcontrol_new *mixers[5]; | ||
46 | int num_mixers; | ||
47 | |||
48 | const struct hda_verb *init_verbs[5]; /* initialization verbs | ||
49 | * don't forget NULL | ||
50 | * termination! | ||
51 | */ | ||
52 | unsigned int num_init_verbs; | ||
53 | |||
54 | /* playback */ | ||
55 | struct hda_multi_out multiout; /* playback set-up | ||
56 | * max_channels, dacs must be set | ||
57 | * dig_out_nid and hp_nid are optional | ||
58 | */ | ||
59 | unsigned int cur_eapd; | ||
60 | unsigned int need_dac_fix; | ||
61 | |||
62 | /* capture */ | ||
63 | unsigned int num_adc_nids; | ||
64 | hda_nid_t *adc_nids; | ||
65 | hda_nid_t dig_in_nid; /* digital-in NID; optional */ | ||
66 | |||
67 | /* capture source */ | ||
68 | const struct hda_input_mux *input_mux; | ||
69 | hda_nid_t *capsrc_nids; | ||
70 | unsigned int cur_mux[3]; | ||
71 | |||
72 | /* channel model */ | ||
73 | const struct hda_channel_mode *channel_mode; | ||
74 | int num_channel_mode; | ||
75 | |||
76 | /* PCM information */ | ||
77 | struct hda_pcm pcm_rec[2]; /* used in build_pcms() */ | ||
78 | |||
79 | struct mutex amp_mutex; /* PCM volume/mute control mutex */ | ||
80 | unsigned int spdif_route; | ||
81 | |||
82 | /* dynamic controls, init_verbs and input_mux */ | ||
83 | struct auto_pin_cfg autocfg; | ||
84 | unsigned int num_kctl_alloc, num_kctl_used; | ||
85 | struct snd_kcontrol_new *kctl_alloc; | ||
86 | struct hda_input_mux private_imux; | ||
87 | hda_nid_t private_dac_nids[4]; | ||
88 | |||
89 | }; | ||
90 | |||
91 | static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo, | ||
92 | struct hda_codec *codec, | ||
93 | struct snd_pcm_substream *substream) | ||
94 | { | ||
95 | struct conexant_spec *spec = codec->spec; | ||
96 | return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream); | ||
97 | } | ||
98 | |||
99 | static int conexant_playback_pcm_prepare(struct hda_pcm_stream *hinfo, | ||
100 | struct hda_codec *codec, | ||
101 | unsigned int stream_tag, | ||
102 | unsigned int format, | ||
103 | struct snd_pcm_substream *substream) | ||
104 | { | ||
105 | struct conexant_spec *spec = codec->spec; | ||
106 | return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, | ||
107 | stream_tag, | ||
108 | format, substream); | ||
109 | } | ||
110 | |||
111 | static int conexant_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, | ||
112 | struct hda_codec *codec, | ||
113 | struct snd_pcm_substream *substream) | ||
114 | { | ||
115 | struct conexant_spec *spec = codec->spec; | ||
116 | return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); | ||
117 | } | ||
118 | |||
119 | /* | ||
120 | * Digital out | ||
121 | */ | ||
122 | static int conexant_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, | ||
123 | struct hda_codec *codec, | ||
124 | struct snd_pcm_substream *substream) | ||
125 | { | ||
126 | struct conexant_spec *spec = codec->spec; | ||
127 | return snd_hda_multi_out_dig_open(codec, &spec->multiout); | ||
128 | } | ||
129 | |||
130 | static int conexant_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, | ||
131 | struct hda_codec *codec, | ||
132 | struct snd_pcm_substream *substream) | ||
133 | { | ||
134 | struct conexant_spec *spec = codec->spec; | ||
135 | return snd_hda_multi_out_dig_close(codec, &spec->multiout); | ||
136 | } | ||
137 | |||
138 | /* | ||
139 | * Analog capture | ||
140 | */ | ||
141 | static int conexant_capture_pcm_prepare(struct hda_pcm_stream *hinfo, | ||
142 | struct hda_codec *codec, | ||
143 | unsigned int stream_tag, | ||
144 | unsigned int format, | ||
145 | struct snd_pcm_substream *substream) | ||
146 | { | ||
147 | struct conexant_spec *spec = codec->spec; | ||
148 | snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], | ||
149 | stream_tag, 0, format); | ||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | static int conexant_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, | ||
154 | struct hda_codec *codec, | ||
155 | struct snd_pcm_substream *substream) | ||
156 | { | ||
157 | struct conexant_spec *spec = codec->spec; | ||
158 | snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], | ||
159 | 0, 0, 0); | ||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | |||
164 | |||
165 | static struct hda_pcm_stream conexant_pcm_analog_playback = { | ||
166 | .substreams = 1, | ||
167 | .channels_min = 2, | ||
168 | .channels_max = 2, | ||
169 | .nid = 0, /* fill later */ | ||
170 | .ops = { | ||
171 | .open = conexant_playback_pcm_open, | ||
172 | .prepare = conexant_playback_pcm_prepare, | ||
173 | .cleanup = conexant_playback_pcm_cleanup | ||
174 | }, | ||
175 | }; | ||
176 | |||
177 | static struct hda_pcm_stream conexant_pcm_analog_capture = { | ||
178 | .substreams = 1, | ||
179 | .channels_min = 2, | ||
180 | .channels_max = 2, | ||
181 | .nid = 0, /* fill later */ | ||
182 | .ops = { | ||
183 | .prepare = conexant_capture_pcm_prepare, | ||
184 | .cleanup = conexant_capture_pcm_cleanup | ||
185 | }, | ||
186 | }; | ||
187 | |||
188 | |||
189 | static struct hda_pcm_stream conexant_pcm_digital_playback = { | ||
190 | .substreams = 1, | ||
191 | .channels_min = 2, | ||
192 | .channels_max = 2, | ||
193 | .nid = 0, /* fill later */ | ||
194 | .ops = { | ||
195 | .open = conexant_dig_playback_pcm_open, | ||
196 | .close = conexant_dig_playback_pcm_close | ||
197 | }, | ||
198 | }; | ||
199 | |||
200 | static struct hda_pcm_stream conexant_pcm_digital_capture = { | ||
201 | .substreams = 1, | ||
202 | .channels_min = 2, | ||
203 | .channels_max = 2, | ||
204 | /* NID is set in alc_build_pcms */ | ||
205 | }; | ||
206 | |||
207 | static int conexant_build_pcms(struct hda_codec *codec) | ||
208 | { | ||
209 | struct conexant_spec *spec = codec->spec; | ||
210 | struct hda_pcm *info = spec->pcm_rec; | ||
211 | |||
212 | codec->num_pcms = 1; | ||
213 | codec->pcm_info = info; | ||
214 | |||
215 | info->name = "CONEXANT Analog"; | ||
216 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = conexant_pcm_analog_playback; | ||
217 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = | ||
218 | spec->multiout.max_channels; | ||
219 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = | ||
220 | spec->multiout.dac_nids[0]; | ||
221 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = conexant_pcm_analog_capture; | ||
222 | info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adc_nids; | ||
223 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; | ||
224 | |||
225 | if (spec->multiout.dig_out_nid) { | ||
226 | info++; | ||
227 | codec->num_pcms++; | ||
228 | info->name = "Conexant Digital"; | ||
229 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = | ||
230 | conexant_pcm_digital_playback; | ||
231 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = | ||
232 | spec->multiout.dig_out_nid; | ||
233 | if (spec->dig_in_nid) { | ||
234 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = | ||
235 | conexant_pcm_digital_capture; | ||
236 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = | ||
237 | spec->dig_in_nid; | ||
238 | } | ||
239 | } | ||
240 | |||
241 | return 0; | ||
242 | } | ||
243 | |||
244 | static int conexant_mux_enum_info(struct snd_kcontrol *kcontrol, | ||
245 | struct snd_ctl_elem_info *uinfo) | ||
246 | { | ||
247 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
248 | struct conexant_spec *spec = codec->spec; | ||
249 | |||
250 | return snd_hda_input_mux_info(spec->input_mux, uinfo); | ||
251 | } | ||
252 | |||
253 | static int conexant_mux_enum_get(struct snd_kcontrol *kcontrol, | ||
254 | struct snd_ctl_elem_value *ucontrol) | ||
255 | { | ||
256 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
257 | struct conexant_spec *spec = codec->spec; | ||
258 | unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | ||
259 | |||
260 | ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx]; | ||
261 | return 0; | ||
262 | } | ||
263 | |||
264 | static int conexant_mux_enum_put(struct snd_kcontrol *kcontrol, | ||
265 | struct snd_ctl_elem_value *ucontrol) | ||
266 | { | ||
267 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
268 | struct conexant_spec *spec = codec->spec; | ||
269 | unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | ||
270 | |||
271 | return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, | ||
272 | spec->capsrc_nids[adc_idx], | ||
273 | &spec->cur_mux[adc_idx]); | ||
274 | } | ||
275 | |||
276 | static int conexant_init(struct hda_codec *codec) | ||
277 | { | ||
278 | struct conexant_spec *spec = codec->spec; | ||
279 | int i; | ||
280 | |||
281 | for (i = 0; i < spec->num_init_verbs; i++) | ||
282 | snd_hda_sequence_write(codec, spec->init_verbs[i]); | ||
283 | return 0; | ||
284 | } | ||
285 | |||
286 | static void conexant_free(struct hda_codec *codec) | ||
287 | { | ||
288 | struct conexant_spec *spec = codec->spec; | ||
289 | unsigned int i; | ||
290 | |||
291 | if (spec->kctl_alloc) { | ||
292 | for (i = 0; i < spec->num_kctl_used; i++) | ||
293 | kfree(spec->kctl_alloc[i].name); | ||
294 | kfree(spec->kctl_alloc); | ||
295 | } | ||
296 | |||
297 | kfree(codec->spec); | ||
298 | } | ||
299 | |||
300 | #ifdef CONFIG_PM | ||
301 | static int conexant_resume(struct hda_codec *codec) | ||
302 | { | ||
303 | struct conexant_spec *spec = codec->spec; | ||
304 | int i; | ||
305 | |||
306 | codec->patch_ops.init(codec); | ||
307 | for (i = 0; i < spec->num_mixers; i++) | ||
308 | snd_hda_resume_ctls(codec, spec->mixers[i]); | ||
309 | if (spec->multiout.dig_out_nid) | ||
310 | snd_hda_resume_spdif_out(codec); | ||
311 | if (spec->dig_in_nid) | ||
312 | snd_hda_resume_spdif_in(codec); | ||
313 | return 0; | ||
314 | } | ||
315 | #endif | ||
316 | |||
317 | static int conexant_build_controls(struct hda_codec *codec) | ||
318 | { | ||
319 | struct conexant_spec *spec = codec->spec; | ||
320 | unsigned int i; | ||
321 | int err; | ||
322 | |||
323 | for (i = 0; i < spec->num_mixers; i++) { | ||
324 | err = snd_hda_add_new_ctls(codec, spec->mixers[i]); | ||
325 | if (err < 0) | ||
326 | return err; | ||
327 | } | ||
328 | if (spec->multiout.dig_out_nid) { | ||
329 | err = snd_hda_create_spdif_out_ctls(codec, | ||
330 | spec->multiout.dig_out_nid); | ||
331 | if (err < 0) | ||
332 | return err; | ||
333 | } | ||
334 | if (spec->dig_in_nid) { | ||
335 | err = snd_hda_create_spdif_in_ctls(codec,spec->dig_in_nid); | ||
336 | if (err < 0) | ||
337 | return err; | ||
338 | } | ||
339 | return 0; | ||
340 | } | ||
341 | |||
342 | static struct hda_codec_ops conexant_patch_ops = { | ||
343 | .build_controls = conexant_build_controls, | ||
344 | .build_pcms = conexant_build_pcms, | ||
345 | .init = conexant_init, | ||
346 | .free = conexant_free, | ||
347 | #ifdef CONFIG_PM | ||
348 | .resume = conexant_resume, | ||
349 | #endif | ||
350 | }; | ||
351 | |||
352 | /* | ||
353 | * EAPD control | ||
354 | * the private value = nid | (invert << 8) | ||
355 | */ | ||
356 | |||
357 | static int conexant_eapd_info(struct snd_kcontrol *kcontrol, | ||
358 | struct snd_ctl_elem_info *uinfo) | ||
359 | { | ||
360 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
361 | uinfo->count = 1; | ||
362 | uinfo->value.integer.min = 0; | ||
363 | uinfo->value.integer.max = 1; | ||
364 | return 0; | ||
365 | } | ||
366 | |||
367 | static int conexant_eapd_get(struct snd_kcontrol *kcontrol, | ||
368 | struct snd_ctl_elem_value *ucontrol) | ||
369 | { | ||
370 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
371 | struct conexant_spec *spec = codec->spec; | ||
372 | int invert = (kcontrol->private_value >> 8) & 1; | ||
373 | if (invert) | ||
374 | ucontrol->value.integer.value[0] = !spec->cur_eapd; | ||
375 | else | ||
376 | ucontrol->value.integer.value[0] = spec->cur_eapd; | ||
377 | return 0; | ||
378 | } | ||
379 | |||
380 | static int conexant_eapd_put(struct snd_kcontrol *kcontrol, | ||
381 | struct snd_ctl_elem_value *ucontrol) | ||
382 | { | ||
383 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
384 | struct conexant_spec *spec = codec->spec; | ||
385 | int invert = (kcontrol->private_value >> 8) & 1; | ||
386 | hda_nid_t nid = kcontrol->private_value & 0xff; | ||
387 | unsigned int eapd; | ||
388 | eapd = ucontrol->value.integer.value[0]; | ||
389 | if (invert) | ||
390 | eapd = !eapd; | ||
391 | if (eapd == spec->cur_eapd && !codec->in_resume) | ||
392 | return 0; | ||
393 | spec->cur_eapd = eapd; | ||
394 | snd_hda_codec_write(codec, nid, | ||
395 | 0, AC_VERB_SET_EAPD_BTLENABLE, | ||
396 | eapd ? 0x02 : 0x00); | ||
397 | return 1; | ||
398 | } | ||
399 | |||
400 | /* controls for test mode */ | ||
401 | #ifdef CONFIG_SND_DEBUG | ||
402 | |||
403 | static int conexant_ch_mode_info(struct snd_kcontrol *kcontrol, | ||
404 | struct snd_ctl_elem_info *uinfo) | ||
405 | { | ||
406 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
407 | struct conexant_spec *spec = codec->spec; | ||
408 | return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode, | ||
409 | spec->num_channel_mode); | ||
410 | } | ||
411 | |||
412 | static int conexant_ch_mode_get(struct snd_kcontrol *kcontrol, | ||
413 | struct snd_ctl_elem_value *ucontrol) | ||
414 | { | ||
415 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
416 | struct conexant_spec *spec = codec->spec; | ||
417 | return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode, | ||
418 | spec->num_channel_mode, | ||
419 | spec->multiout.max_channels); | ||
420 | } | ||
421 | |||
422 | static int conexant_ch_mode_put(struct snd_kcontrol *kcontrol, | ||
423 | struct snd_ctl_elem_value *ucontrol) | ||
424 | { | ||
425 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
426 | struct conexant_spec *spec = codec->spec; | ||
427 | int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode, | ||
428 | spec->num_channel_mode, | ||
429 | &spec->multiout.max_channels); | ||
430 | if (err >= 0 && spec->need_dac_fix) | ||
431 | spec->multiout.num_dacs = spec->multiout.max_channels / 2; | ||
432 | return err; | ||
433 | } | ||
434 | |||
435 | #define CXT_PIN_MODE(xname, nid, dir) \ | ||
436 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ | ||
437 | .info = conexant_ch_mode_info, \ | ||
438 | .get = conexant_ch_mode_get, \ | ||
439 | .put = conexant_ch_mode_put, \ | ||
440 | .private_value = nid | (dir<<16) } | ||
441 | |||
442 | static int cxt_gpio_data_info(struct snd_kcontrol *kcontrol, | ||
443 | struct snd_ctl_elem_info *uinfo) | ||
444 | { | ||
445 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
446 | uinfo->count = 1; | ||
447 | uinfo->value.integer.min = 0; | ||
448 | uinfo->value.integer.max = 1; | ||
449 | return 0; | ||
450 | } | ||
451 | |||
452 | static int cxt_gpio_data_get(struct snd_kcontrol *kcontrol, | ||
453 | struct snd_ctl_elem_value *ucontrol) | ||
454 | { | ||
455 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
456 | hda_nid_t nid = kcontrol->private_value & 0xffff; | ||
457 | unsigned char mask = (kcontrol->private_value >> 16) & 0xff; | ||
458 | long *valp = ucontrol->value.integer.value; | ||
459 | unsigned int val = snd_hda_codec_read(codec, nid, 0, | ||
460 | AC_VERB_GET_GPIO_DATA, 0x00); | ||
461 | |||
462 | *valp = (val & mask) != 0; | ||
463 | return 0; | ||
464 | } | ||
465 | |||
466 | static int cxt_gpio_data_put(struct snd_kcontrol *kcontrol, | ||
467 | struct snd_ctl_elem_value *ucontrol) | ||
468 | { | ||
469 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
470 | hda_nid_t nid = kcontrol->private_value & 0xffff; | ||
471 | unsigned char mask = (kcontrol->private_value >> 16) & 0xff; | ||
472 | long val = *ucontrol->value.integer.value; | ||
473 | unsigned int gpio_data = snd_hda_codec_read(codec, nid, 0, | ||
474 | AC_VERB_GET_GPIO_DATA, | ||
475 | 0x00); | ||
476 | unsigned int old_data = gpio_data; | ||
477 | |||
478 | /* Set/unset the masked GPIO bit(s) as needed */ | ||
479 | if (val == 0) | ||
480 | gpio_data &= ~mask; | ||
481 | else | ||
482 | gpio_data |= mask; | ||
483 | if (gpio_data == old_data && !codec->in_resume) | ||
484 | return 0; | ||
485 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_GPIO_DATA, gpio_data); | ||
486 | return 1; | ||
487 | } | ||
488 | |||
489 | #define CXT_GPIO_DATA_SWITCH(xname, nid, mask) \ | ||
490 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ | ||
491 | .info = cxt_gpio_data_info, \ | ||
492 | .get = cxt_gpio_data_get, \ | ||
493 | .put = cxt_gpio_data_put, \ | ||
494 | .private_value = nid | (mask<<16) } | ||
495 | |||
496 | static int cxt_spdif_ctrl_info(struct snd_kcontrol *kcontrol, | ||
497 | struct snd_ctl_elem_info *uinfo) | ||
498 | { | ||
499 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
500 | uinfo->count = 1; | ||
501 | uinfo->value.integer.min = 0; | ||
502 | uinfo->value.integer.max = 1; | ||
503 | return 0; | ||
504 | } | ||
505 | |||
506 | static int cxt_spdif_ctrl_get(struct snd_kcontrol *kcontrol, | ||
507 | struct snd_ctl_elem_value *ucontrol) | ||
508 | { | ||
509 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
510 | hda_nid_t nid = kcontrol->private_value & 0xffff; | ||
511 | unsigned char mask = (kcontrol->private_value >> 16) & 0xff; | ||
512 | long *valp = ucontrol->value.integer.value; | ||
513 | unsigned int val = snd_hda_codec_read(codec, nid, 0, | ||
514 | AC_VERB_GET_DIGI_CONVERT, 0x00); | ||
515 | |||
516 | *valp = (val & mask) != 0; | ||
517 | return 0; | ||
518 | } | ||
519 | |||
520 | static int cxt_spdif_ctrl_put(struct snd_kcontrol *kcontrol, | ||
521 | struct snd_ctl_elem_value *ucontrol) | ||
522 | { | ||
523 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
524 | hda_nid_t nid = kcontrol->private_value & 0xffff; | ||
525 | unsigned char mask = (kcontrol->private_value >> 16) & 0xff; | ||
526 | long val = *ucontrol->value.integer.value; | ||
527 | unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0, | ||
528 | AC_VERB_GET_DIGI_CONVERT, | ||
529 | 0x00); | ||
530 | unsigned int old_data = ctrl_data; | ||
531 | |||
532 | /* Set/unset the masked control bit(s) as needed */ | ||
533 | if (val == 0) | ||
534 | ctrl_data &= ~mask; | ||
535 | else | ||
536 | ctrl_data |= mask; | ||
537 | if (ctrl_data == old_data && !codec->in_resume) | ||
538 | return 0; | ||
539 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, | ||
540 | ctrl_data); | ||
541 | return 1; | ||
542 | } | ||
543 | |||
544 | #define CXT_SPDIF_CTRL_SWITCH(xname, nid, mask) \ | ||
545 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ | ||
546 | .info = cxt_spdif_ctrl_info, \ | ||
547 | .get = cxt_spdif_ctrl_get, \ | ||
548 | .put = cxt_spdif_ctrl_put, \ | ||
549 | .private_value = nid | (mask<<16) } | ||
550 | |||
551 | #endif /* CONFIG_SND_DEBUG */ | ||
552 | |||
553 | /* Conexant 5045 specific */ | ||
554 | |||
555 | static hda_nid_t cxt5045_dac_nids[1] = { 0x19 }; | ||
556 | static hda_nid_t cxt5045_adc_nids[1] = { 0x1a }; | ||
557 | static hda_nid_t cxt5045_capsrc_nids[1] = { 0x1a }; | ||
558 | #define CXT5045_SPDIF_OUT 0x13 | ||
559 | |||
560 | static struct hda_channel_mode cxt5045_modes[1] = { | ||
561 | { 2, NULL }, | ||
562 | }; | ||
563 | |||
564 | static struct hda_input_mux cxt5045_capture_source = { | ||
565 | .num_items = 2, | ||
566 | .items = { | ||
567 | { "ExtMic", 0x1 }, | ||
568 | { "LineIn", 0x2 }, | ||
569 | } | ||
570 | }; | ||
571 | |||
572 | /* turn on/off EAPD (+ mute HP) as a master switch */ | ||
573 | static int cxt5045_hp_master_sw_put(struct snd_kcontrol *kcontrol, | ||
574 | struct snd_ctl_elem_value *ucontrol) | ||
575 | { | ||
576 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
577 | struct conexant_spec *spec = codec->spec; | ||
578 | |||
579 | if (!conexant_eapd_put(kcontrol, ucontrol)) | ||
580 | return 0; | ||
581 | |||
582 | /* toggle HP mute appropriately */ | ||
583 | snd_hda_codec_amp_update(codec, 0x11, 0, HDA_OUTPUT, 0, | ||
584 | 0x80, spec->cur_eapd ? 0 : 0x80); | ||
585 | snd_hda_codec_amp_update(codec, 0x11, 1, HDA_OUTPUT, 0, | ||
586 | 0x80, spec->cur_eapd ? 0 : 0x80); | ||
587 | return 1; | ||
588 | } | ||
589 | |||
590 | /* bind volumes of both NID 0x10 and 0x11 */ | ||
591 | static int cxt5045_hp_master_vol_put(struct snd_kcontrol *kcontrol, | ||
592 | struct snd_ctl_elem_value *ucontrol) | ||
593 | { | ||
594 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
595 | long *valp = ucontrol->value.integer.value; | ||
596 | int change; | ||
597 | |||
598 | change = snd_hda_codec_amp_update(codec, 0x10, 0, HDA_OUTPUT, 0, | ||
599 | 0x7f, valp[0] & 0x7f); | ||
600 | change |= snd_hda_codec_amp_update(codec, 0x10, 1, HDA_OUTPUT, 0, | ||
601 | 0x7f, valp[1] & 0x7f); | ||
602 | snd_hda_codec_amp_update(codec, 0x11, 0, HDA_OUTPUT, 0, | ||
603 | 0x7f, valp[0] & 0x7f); | ||
604 | snd_hda_codec_amp_update(codec, 0x11, 1, HDA_OUTPUT, 0, | ||
605 | 0x7f, valp[1] & 0x7f); | ||
606 | return change; | ||
607 | } | ||
608 | |||
609 | |||
610 | /* mute internal speaker if HP is plugged */ | ||
611 | static void cxt5045_hp_automute(struct hda_codec *codec) | ||
612 | { | ||
613 | unsigned int present; | ||
614 | |||
615 | present = snd_hda_codec_read(codec, 0x11, 0, | ||
616 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
617 | snd_hda_codec_amp_update(codec, 0x10, 0, HDA_OUTPUT, 0, | ||
618 | 0x80, present ? 0x80 : 0); | ||
619 | snd_hda_codec_amp_update(codec, 0x10, 1, HDA_OUTPUT, 0, | ||
620 | 0x80, present ? 0x80 : 0); | ||
621 | } | ||
622 | |||
623 | /* unsolicited event for HP jack sensing */ | ||
624 | static void cxt5045_hp_unsol_event(struct hda_codec *codec, | ||
625 | unsigned int res) | ||
626 | { | ||
627 | res >>= 26; | ||
628 | switch (res) { | ||
629 | case CONEXANT_HP_EVENT: | ||
630 | cxt5045_hp_automute(codec); | ||
631 | break; | ||
632 | } | ||
633 | } | ||
634 | |||
635 | static struct snd_kcontrol_new cxt5045_mixers[] = { | ||
636 | { | ||
637 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
638 | .name = "Capture Source", | ||
639 | .info = conexant_mux_enum_info, | ||
640 | .get = conexant_mux_enum_get, | ||
641 | .put = conexant_mux_enum_put | ||
642 | }, | ||
643 | HDA_CODEC_VOLUME("Mic Bypass Capture Volume", 0x17, 0x02, HDA_INPUT), | ||
644 | HDA_CODEC_MUTE("Mic Bypass Capture Switch", 0x17, 0x02, HDA_INPUT), | ||
645 | HDA_CODEC_VOLUME("Capture Volume", 0x1a, 0x02, HDA_INPUT), | ||
646 | HDA_CODEC_MUTE("Capture Switch", 0x1a, 0x02, HDA_INPUT), | ||
647 | { | ||
648 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
649 | .name = "Master Playback Volume", | ||
650 | .info = snd_hda_mixer_amp_volume_info, | ||
651 | .get = snd_hda_mixer_amp_volume_get, | ||
652 | .put = cxt5045_hp_master_vol_put, | ||
653 | .private_value = HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT), | ||
654 | }, | ||
655 | { | ||
656 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
657 | .name = "Master Playback Switch", | ||
658 | .info = conexant_eapd_info, | ||
659 | .get = conexant_eapd_get, | ||
660 | .put = cxt5045_hp_master_sw_put, | ||
661 | .private_value = 0x11, | ||
662 | }, | ||
663 | |||
664 | {} | ||
665 | }; | ||
666 | |||
667 | static struct hda_verb cxt5045_init_verbs[] = { | ||
668 | /* Line in, Mic */ | ||
669 | {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, | ||
670 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_50 }, | ||
671 | /* HP, Amp */ | ||
672 | {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
673 | {0x1A, AC_VERB_SET_CONNECT_SEL,0x01}, | ||
674 | {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, | ||
675 | AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x00}, | ||
676 | {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, | ||
677 | AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x03}, | ||
678 | /* Record selector: Front mic */ | ||
679 | {0x14, AC_VERB_SET_CONNECT_SEL,0x03}, | ||
680 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, | ||
681 | AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17}, | ||
682 | /* SPDIF route: PCM */ | ||
683 | { 0x13, AC_VERB_SET_CONNECT_SEL, 0x0 }, | ||
684 | /* pin sensing on HP and Mic jacks */ | ||
685 | {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, | ||
686 | /* EAPD */ | ||
687 | {0x10, AC_VERB_SET_EAPD_BTLENABLE, 0x0 }, /* default on */ | ||
688 | { } /* end */ | ||
689 | }; | ||
690 | |||
691 | #ifdef CONFIG_SND_DEBUG | ||
692 | /* Test configuration for debugging, modelled after the ALC260 test | ||
693 | * configuration. | ||
694 | */ | ||
695 | static struct hda_input_mux cxt5045_test_capture_source = { | ||
696 | .num_items = 5, | ||
697 | .items = { | ||
698 | { "MIXER", 0x0 }, | ||
699 | { "MIC1 pin", 0x1 }, | ||
700 | { "LINE1 pin", 0x2 }, | ||
701 | { "HP-OUT pin", 0x3 }, | ||
702 | { "CD pin", 0x4 }, | ||
703 | }, | ||
704 | }; | ||
705 | |||
706 | static struct snd_kcontrol_new cxt5045_test_mixer[] = { | ||
707 | |||
708 | /* Output controls */ | ||
709 | HDA_CODEC_VOLUME("OutAmp-1 Volume", 0x19, 0x00, HDA_OUTPUT), | ||
710 | HDA_CODEC_MUTE("OutAmp-1 Switch", 0x19,0x00, HDA_OUTPUT), | ||
711 | HDA_CODEC_VOLUME("Speaker Playback Volume", 0x10, 0x0, HDA_OUTPUT), | ||
712 | HDA_CODEC_MUTE("Speaker Playback Switch", 0x10, 0x0, HDA_OUTPUT), | ||
713 | |||
714 | /* Modes for retasking pin widgets */ | ||
715 | CXT_PIN_MODE("HP-OUT pin mode", 0x11, CXT_PIN_DIR_INOUT), | ||
716 | CXT_PIN_MODE("LINE1 pin mode", 0x12, CXT_PIN_DIR_INOUT), | ||
717 | |||
718 | /* Loopback mixer controls */ | ||
719 | HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x17, 0x01, HDA_INPUT), | ||
720 | HDA_CODEC_MUTE("MIC1 Playback Switch", 0x17, 0x01, HDA_INPUT), | ||
721 | HDA_CODEC_VOLUME("LINE loopback Playback Volume", 0x17, 0x02, HDA_INPUT), | ||
722 | HDA_CODEC_MUTE("LINE loopback Playback Switch", 0x17, 0x02, HDA_INPUT), | ||
723 | HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x17, 0x03, HDA_INPUT), | ||
724 | HDA_CODEC_MUTE("HP-OUT loopback Playback Switch", 0x17, 0x03, HDA_INPUT), | ||
725 | HDA_CODEC_VOLUME("CD Playback Volume", 0x17, 0x04, HDA_INPUT), | ||
726 | HDA_CODEC_MUTE("CD Playback Switch", 0x17, 0x04, HDA_INPUT), | ||
727 | |||
728 | /* Controls for GPIO pins, assuming they exist and are configured as outputs */ | ||
729 | CXT_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01), | ||
730 | #if 0 /* limit this to one GPIO pin for now */ | ||
731 | CXT_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02), | ||
732 | CXT_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04), | ||
733 | CXT_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08), | ||
734 | #endif | ||
735 | CXT_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x13, 0x01), | ||
736 | |||
737 | HDA_CODEC_VOLUME("Capture Volume", 0x17, 0x0, HDA_OUTPUT), | ||
738 | HDA_CODEC_MUTE("Capture Switch", 0x17, 0x0, HDA_OUTPUT), | ||
739 | { | ||
740 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
741 | .name = "Input Source", | ||
742 | .info = conexant_mux_enum_info, | ||
743 | .get = conexant_mux_enum_get, | ||
744 | .put = conexant_mux_enum_put, | ||
745 | }, | ||
746 | |||
747 | { } /* end */ | ||
748 | }; | ||
749 | |||
750 | static struct hda_verb cxt5045_test_init_verbs[] = { | ||
751 | /* Enable all GPIOs as outputs with an initial value of 0 */ | ||
752 | {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f}, | ||
753 | {0x01, AC_VERB_SET_GPIO_DATA, 0x00}, | ||
754 | {0x01, AC_VERB_SET_GPIO_MASK, 0x0f}, | ||
755 | |||
756 | /* Enable retasking pins as output, initially without power amp */ | ||
757 | {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
758 | {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
759 | |||
760 | /* Disable digital (SPDIF) pins initially, but users can enable | ||
761 | * them via a mixer switch. In the case of SPDIF-out, this initverb | ||
762 | * payload also sets the generation to 0, output to be in "consumer" | ||
763 | * PCM format, copyright asserted, no pre-emphasis and no validity | ||
764 | * control. | ||
765 | */ | ||
766 | {0x13, AC_VERB_SET_DIGI_CONVERT_1, 0}, | ||
767 | |||
768 | /* Start with output sum widgets muted and their output gains at min */ | ||
769 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
770 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
771 | |||
772 | /* Unmute retasking pin widget output buffers since the default | ||
773 | * state appears to be output. As the pin mode is changed by the | ||
774 | * user the pin mode control will take care of enabling the pin's | ||
775 | * input/output buffers as needed. | ||
776 | */ | ||
777 | {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
778 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
779 | |||
780 | /* Mute capture amp left and right */ | ||
781 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
782 | |||
783 | /* Set ADC connection select to match default mixer setting (mic1 | ||
784 | * pin) | ||
785 | */ | ||
786 | {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
787 | |||
788 | /* Mute all inputs to mixer widget (even unconnected ones) */ | ||
789 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* Mixer pin */ | ||
790 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* Mic1 pin */ | ||
791 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* Line pin */ | ||
792 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* HP pin */ | ||
793 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */ | ||
794 | |||
795 | { } | ||
796 | }; | ||
797 | #endif | ||
798 | |||
799 | |||
800 | /* initialize jack-sensing, too */ | ||
801 | static int cxt5045_init(struct hda_codec *codec) | ||
802 | { | ||
803 | conexant_init(codec); | ||
804 | cxt5045_hp_automute(codec); | ||
805 | return 0; | ||
806 | } | ||
807 | |||
808 | |||
809 | enum { | ||
810 | CXT5045_LAPTOP, /* Laptops w/ EAPD support */ | ||
811 | #ifdef CONFIG_SND_DEBUG | ||
812 | CXT5045_TEST, | ||
813 | #endif | ||
814 | CXT5045_MODELS | ||
815 | }; | ||
816 | |||
817 | static const char *cxt5045_models[CXT5045_MODELS] = { | ||
818 | [CXT5045_LAPTOP] = "laptop", | ||
819 | #ifdef CONFIG_SND_DEBUG | ||
820 | [CXT5045_TEST] = "test", | ||
821 | #endif | ||
822 | }; | ||
823 | |||
824 | static struct snd_pci_quirk cxt5045_cfg_tbl[] = { | ||
825 | SND_PCI_QUIRK(0x103c, 0x30b7, "HP DV6000Z", CXT5045_LAPTOP), | ||
826 | {} | ||
827 | }; | ||
828 | |||
829 | static int patch_cxt5045(struct hda_codec *codec) | ||
830 | { | ||
831 | struct conexant_spec *spec; | ||
832 | int board_config; | ||
833 | |||
834 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
835 | if (!spec) | ||
836 | return -ENOMEM; | ||
837 | mutex_init(&spec->amp_mutex); | ||
838 | codec->spec = spec; | ||
839 | |||
840 | spec->multiout.max_channels = 2; | ||
841 | spec->multiout.num_dacs = ARRAY_SIZE(cxt5045_dac_nids); | ||
842 | spec->multiout.dac_nids = cxt5045_dac_nids; | ||
843 | spec->multiout.dig_out_nid = CXT5045_SPDIF_OUT; | ||
844 | spec->num_adc_nids = 1; | ||
845 | spec->adc_nids = cxt5045_adc_nids; | ||
846 | spec->capsrc_nids = cxt5045_capsrc_nids; | ||
847 | spec->input_mux = &cxt5045_capture_source; | ||
848 | spec->num_mixers = 1; | ||
849 | spec->mixers[0] = cxt5045_mixers; | ||
850 | spec->num_init_verbs = 1; | ||
851 | spec->init_verbs[0] = cxt5045_init_verbs; | ||
852 | spec->spdif_route = 0; | ||
853 | spec->num_channel_mode = ARRAY_SIZE(cxt5045_modes), | ||
854 | spec->channel_mode = cxt5045_modes, | ||
855 | |||
856 | |||
857 | codec->patch_ops = conexant_patch_ops; | ||
858 | codec->patch_ops.unsol_event = cxt5045_hp_unsol_event; | ||
859 | |||
860 | board_config = snd_hda_check_board_config(codec, CXT5045_MODELS, | ||
861 | cxt5045_models, | ||
862 | cxt5045_cfg_tbl); | ||
863 | switch (board_config) { | ||
864 | case CXT5045_LAPTOP: | ||
865 | spec->input_mux = &cxt5045_capture_source; | ||
866 | spec->num_init_verbs = 2; | ||
867 | spec->init_verbs[1] = cxt5045_init_verbs; | ||
868 | spec->mixers[0] = cxt5045_mixers; | ||
869 | codec->patch_ops.init = cxt5045_init; | ||
870 | break; | ||
871 | #ifdef CONFIG_SND_DEBUG | ||
872 | case CXT5045_TEST: | ||
873 | spec->input_mux = &cxt5045_test_capture_source; | ||
874 | spec->mixers[0] = cxt5045_test_mixer; | ||
875 | spec->init_verbs[0] = cxt5045_test_init_verbs; | ||
876 | #endif | ||
877 | } | ||
878 | return 0; | ||
879 | } | ||
880 | |||
881 | |||
882 | /* Conexant 5047 specific */ | ||
883 | |||
884 | static hda_nid_t cxt5047_dac_nids[1] = { 0x10 }; | ||
885 | static hda_nid_t cxt5047_adc_nids[1] = { 0x12 }; | ||
886 | static hda_nid_t cxt5047_capsrc_nids[1] = { 0x1a }; | ||
887 | #define CXT5047_SPDIF_OUT 0x11 | ||
888 | |||
889 | static struct hda_channel_mode cxt5047_modes[1] = { | ||
890 | { 2, NULL }, | ||
891 | }; | ||
892 | |||
893 | static struct hda_input_mux cxt5047_capture_source = { | ||
894 | .num_items = 2, | ||
895 | .items = { | ||
896 | { "ExtMic", 0x1 }, | ||
897 | { "IntMic", 0x2 }, | ||
898 | } | ||
899 | }; | ||
900 | |||
901 | static struct hda_input_mux cxt5047_hp_capture_source = { | ||
902 | .num_items = 1, | ||
903 | .items = { | ||
904 | { "ExtMic", 0x1 }, | ||
905 | } | ||
906 | }; | ||
907 | |||
908 | /* turn on/off EAPD (+ mute HP) as a master switch */ | ||
909 | static int cxt5047_hp_master_sw_put(struct snd_kcontrol *kcontrol, | ||
910 | struct snd_ctl_elem_value *ucontrol) | ||
911 | { | ||
912 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
913 | struct conexant_spec *spec = codec->spec; | ||
914 | |||
915 | if (!conexant_eapd_put(kcontrol, ucontrol)) | ||
916 | return 0; | ||
917 | |||
918 | /* toggle HP mute appropriately */ | ||
919 | snd_hda_codec_amp_update(codec, 0x13, 0, HDA_OUTPUT, 0, | ||
920 | 0x80, spec->cur_eapd ? 0 : 0x80); | ||
921 | snd_hda_codec_amp_update(codec, 0x13, 1, HDA_OUTPUT, 0, | ||
922 | 0x80, spec->cur_eapd ? 0 : 0x80); | ||
923 | return 1; | ||
924 | } | ||
925 | |||
926 | #if 0 | ||
927 | /* bind volumes of both NID 0x13 and 0x1d */ | ||
928 | static int cxt5047_hp_master_vol_put(struct snd_kcontrol *kcontrol, | ||
929 | struct snd_ctl_elem_value *ucontrol) | ||
930 | { | ||
931 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
932 | long *valp = ucontrol->value.integer.value; | ||
933 | int change; | ||
934 | |||
935 | change = snd_hda_codec_amp_update(codec, 0x1c, 0, HDA_OUTPUT, 0, | ||
936 | 0x7f, valp[0] & 0x7f); | ||
937 | change |= snd_hda_codec_amp_update(codec, 0x1c, 1, HDA_OUTPUT, 0, | ||
938 | 0x7f, valp[1] & 0x7f); | ||
939 | snd_hda_codec_amp_update(codec, 0x13, 0, HDA_OUTPUT, 0, | ||
940 | 0x7f, valp[0] & 0x7f); | ||
941 | snd_hda_codec_amp_update(codec, 0x13, 1, HDA_OUTPUT, 0, | ||
942 | 0x7f, valp[1] & 0x7f); | ||
943 | return change; | ||
944 | } | ||
945 | #endif | ||
946 | |||
947 | /* mute internal speaker if HP is plugged */ | ||
948 | static void cxt5047_hp_automute(struct hda_codec *codec) | ||
949 | { | ||
950 | unsigned int present; | ||
951 | |||
952 | present = snd_hda_codec_read(codec, 0x13, 0, | ||
953 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
954 | snd_hda_codec_amp_update(codec, 0x1c, 0, HDA_OUTPUT, 0, | ||
955 | 0x80, present ? 0x80 : 0); | ||
956 | snd_hda_codec_amp_update(codec, 0x1c, 1, HDA_OUTPUT, 0, | ||
957 | 0x80, present ? 0x80 : 0); | ||
958 | } | ||
959 | |||
960 | /* toggle input of built-in and mic jack appropriately */ | ||
961 | static void cxt5047_hp_automic(struct hda_codec *codec) | ||
962 | { | ||
963 | static struct hda_verb mic_jack_on[] = { | ||
964 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
965 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
966 | {} | ||
967 | }; | ||
968 | static struct hda_verb mic_jack_off[] = { | ||
969 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
970 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
971 | {} | ||
972 | }; | ||
973 | unsigned int present; | ||
974 | |||
975 | present = snd_hda_codec_read(codec, 0x08, 0, | ||
976 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
977 | if (present) | ||
978 | snd_hda_sequence_write(codec, mic_jack_on); | ||
979 | else | ||
980 | snd_hda_sequence_write(codec, mic_jack_off); | ||
981 | } | ||
982 | |||
983 | /* unsolicited event for HP jack sensing */ | ||
984 | static void cxt5047_hp_unsol_event(struct hda_codec *codec, | ||
985 | unsigned int res) | ||
986 | { | ||
987 | res >>= 26; | ||
988 | switch (res) { | ||
989 | case CONEXANT_HP_EVENT: | ||
990 | cxt5047_hp_automute(codec); | ||
991 | break; | ||
992 | case CONEXANT_MIC_EVENT: | ||
993 | cxt5047_hp_automic(codec); | ||
994 | break; | ||
995 | } | ||
996 | } | ||
997 | |||
998 | static struct snd_kcontrol_new cxt5047_mixers[] = { | ||
999 | { | ||
1000 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1001 | .name = "Capture Source", | ||
1002 | .info = conexant_mux_enum_info, | ||
1003 | .get = conexant_mux_enum_get, | ||
1004 | .put = conexant_mux_enum_put | ||
1005 | }, | ||
1006 | HDA_CODEC_VOLUME("Mic Bypass Capture Volume", 0x19, 0x02, HDA_INPUT), | ||
1007 | HDA_CODEC_MUTE("Mic Bypass Capture Switch", 0x19, 0x02, HDA_INPUT), | ||
1008 | HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x03, HDA_INPUT), | ||
1009 | HDA_CODEC_MUTE("Capture Switch", 0x12, 0x03, HDA_INPUT), | ||
1010 | HDA_CODEC_VOLUME("PCM Volume", 0x10, 0x00, HDA_OUTPUT), | ||
1011 | HDA_CODEC_MUTE("PCM Switch", 0x10, 0x00, HDA_OUTPUT), | ||
1012 | HDA_CODEC_VOLUME("Master Playback Volume", 0x13, 0x00, HDA_OUTPUT), | ||
1013 | { | ||
1014 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1015 | .name = "Master Playback Switch", | ||
1016 | .info = conexant_eapd_info, | ||
1017 | .get = conexant_eapd_get, | ||
1018 | .put = cxt5047_hp_master_sw_put, | ||
1019 | .private_value = 0x13, | ||
1020 | }, | ||
1021 | |||
1022 | {} | ||
1023 | }; | ||
1024 | |||
1025 | static struct snd_kcontrol_new cxt5047_hp_mixers[] = { | ||
1026 | { | ||
1027 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1028 | .name = "Capture Source", | ||
1029 | .info = conexant_mux_enum_info, | ||
1030 | .get = conexant_mux_enum_get, | ||
1031 | .put = conexant_mux_enum_put | ||
1032 | }, | ||
1033 | HDA_CODEC_VOLUME("Mic Bypass Capture Volume", 0x19, 0x02, HDA_INPUT), | ||
1034 | HDA_CODEC_MUTE("Mic Bypass Capture Switch", 0x19,0x02,HDA_INPUT), | ||
1035 | HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x03, HDA_INPUT), | ||
1036 | HDA_CODEC_MUTE("Capture Switch", 0x12, 0x03, HDA_INPUT), | ||
1037 | HDA_CODEC_VOLUME("PCM Volume", 0x10, 0x00, HDA_OUTPUT), | ||
1038 | HDA_CODEC_MUTE("PCM Switch", 0x10, 0x00, HDA_OUTPUT), | ||
1039 | HDA_CODEC_VOLUME("Master Playback Volume", 0x13, 0x00, HDA_OUTPUT), | ||
1040 | { | ||
1041 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1042 | .name = "Master Playback Switch", | ||
1043 | .info = conexant_eapd_info, | ||
1044 | .get = conexant_eapd_get, | ||
1045 | .put = cxt5047_hp_master_sw_put, | ||
1046 | .private_value = 0x13, | ||
1047 | }, | ||
1048 | { } /* end */ | ||
1049 | }; | ||
1050 | |||
1051 | static struct hda_verb cxt5047_init_verbs[] = { | ||
1052 | /* Line in, Mic, Built-in Mic */ | ||
1053 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, | ||
1054 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_50 }, | ||
1055 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_50 }, | ||
1056 | /* HP, Amp */ | ||
1057 | {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
1058 | {0x1A, AC_VERB_SET_CONNECT_SEL,0x03}, | ||
1059 | {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, | ||
1060 | AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x00}, | ||
1061 | {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, | ||
1062 | AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x03}, | ||
1063 | /* Record selector: Front mic */ | ||
1064 | {0x12, AC_VERB_SET_CONNECT_SEL,0x03}, | ||
1065 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, | ||
1066 | AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17}, | ||
1067 | /* SPDIF route: PCM */ | ||
1068 | { 0x18, AC_VERB_SET_CONNECT_SEL, 0x0 }, | ||
1069 | { } /* end */ | ||
1070 | }; | ||
1071 | |||
1072 | /* configuration for Toshiba Laptops */ | ||
1073 | static struct hda_verb cxt5047_toshiba_init_verbs[] = { | ||
1074 | {0x13, AC_VERB_SET_EAPD_BTLENABLE, 0x0 }, /* default on */ | ||
1075 | /* pin sensing on HP and Mic jacks */ | ||
1076 | {0x13, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, | ||
1077 | {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, | ||
1078 | {} | ||
1079 | }; | ||
1080 | |||
1081 | /* configuration for HP Laptops */ | ||
1082 | static struct hda_verb cxt5047_hp_init_verbs[] = { | ||
1083 | /* pin sensing on HP and Mic jacks */ | ||
1084 | {0x13, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, | ||
1085 | {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, | ||
1086 | {} | ||
1087 | }; | ||
1088 | |||
1089 | /* Test configuration for debugging, modelled after the ALC260 test | ||
1090 | * configuration. | ||
1091 | */ | ||
1092 | #ifdef CONFIG_SND_DEBUG | ||
1093 | static struct hda_input_mux cxt5047_test_capture_source = { | ||
1094 | .num_items = 5, | ||
1095 | .items = { | ||
1096 | { "MIXER", 0x0 }, | ||
1097 | { "LINE1 pin", 0x1 }, | ||
1098 | { "MIC1 pin", 0x2 }, | ||
1099 | { "MIC2 pin", 0x3 }, | ||
1100 | { "CD pin", 0x4 }, | ||
1101 | }, | ||
1102 | }; | ||
1103 | |||
1104 | static struct snd_kcontrol_new cxt5047_test_mixer[] = { | ||
1105 | |||
1106 | /* Output only controls */ | ||
1107 | HDA_CODEC_VOLUME("OutAmp-1 Volume", 0x10, 0x00, HDA_OUTPUT), | ||
1108 | HDA_CODEC_MUTE("OutAmp-1 Switch", 0x10,0x00, HDA_OUTPUT), | ||
1109 | HDA_CODEC_VOLUME("OutAmp-2 Volume", 0x1c, 0x00, HDA_OUTPUT), | ||
1110 | HDA_CODEC_MUTE("OutAmp-2 Switch", 0x1c, 0x00, HDA_OUTPUT), | ||
1111 | HDA_CODEC_VOLUME("Speaker Playback Volume", 0x1d, 0x0, HDA_OUTPUT), | ||
1112 | HDA_CODEC_MUTE("Speaker Playback Switch", 0x1d, 0x0, HDA_OUTPUT), | ||
1113 | HDA_CODEC_VOLUME("HeadPhone Playback Volume", 0x13, 0x0, HDA_OUTPUT), | ||
1114 | HDA_CODEC_MUTE("HeadPhone Playback Switch", 0x13, 0x0, HDA_OUTPUT), | ||
1115 | |||
1116 | /* Modes for retasking pin widgets */ | ||
1117 | CXT_PIN_MODE("LINE1 pin mode", 0x14, CXT_PIN_DIR_INOUT), | ||
1118 | CXT_PIN_MODE("MIC1 pin mode", 0x15, CXT_PIN_DIR_INOUT), | ||
1119 | |||
1120 | /* Loopback mixer controls */ | ||
1121 | HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x19, 0x02, HDA_INPUT), | ||
1122 | HDA_CODEC_MUTE("MIC1 Playback Switch", 0x19, 0x02, HDA_INPUT), | ||
1123 | HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x19, 0x03, HDA_INPUT), | ||
1124 | HDA_CODEC_MUTE("MIC2 Playback Switch", 0x19, 0x03, HDA_INPUT), | ||
1125 | HDA_CODEC_VOLUME("LINE Playback Volume", 0x19, 0x01, HDA_INPUT), | ||
1126 | HDA_CODEC_MUTE("LINE Playback Switch", 0x19, 0x01, HDA_INPUT), | ||
1127 | HDA_CODEC_VOLUME("CD Playback Volume", 0x19, 0x04, HDA_INPUT), | ||
1128 | HDA_CODEC_MUTE("CD Playback Switch", 0x19, 0x04, HDA_INPUT), | ||
1129 | |||
1130 | #if 0 | ||
1131 | /* Controls for GPIO pins, assuming they exist and are configured as outputs */ | ||
1132 | CXT_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01), | ||
1133 | CXT_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02), | ||
1134 | CXT_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04), | ||
1135 | CXT_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08), | ||
1136 | #endif | ||
1137 | CXT_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x18, 0x01), | ||
1138 | |||
1139 | HDA_CODEC_VOLUME("Capture Volume", 0x19, 0x0, HDA_OUTPUT), | ||
1140 | HDA_CODEC_MUTE("Capture Switch", 0x19, 0x0, HDA_OUTPUT), | ||
1141 | { | ||
1142 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1143 | .name = "Input Source", | ||
1144 | .info = conexant_mux_enum_info, | ||
1145 | .get = conexant_mux_enum_get, | ||
1146 | .put = conexant_mux_enum_put, | ||
1147 | }, | ||
1148 | |||
1149 | { } /* end */ | ||
1150 | }; | ||
1151 | |||
1152 | static struct hda_verb cxt5047_test_init_verbs[] = { | ||
1153 | /* Enable all GPIOs as outputs with an initial value of 0 */ | ||
1154 | {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f}, | ||
1155 | {0x01, AC_VERB_SET_GPIO_DATA, 0x00}, | ||
1156 | {0x01, AC_VERB_SET_GPIO_MASK, 0x0f}, | ||
1157 | |||
1158 | /* Enable retasking pins as output, initially without power amp */ | ||
1159 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
1160 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
1161 | {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
1162 | |||
1163 | /* Disable digital (SPDIF) pins initially, but users can enable | ||
1164 | * them via a mixer switch. In the case of SPDIF-out, this initverb | ||
1165 | * payload also sets the generation to 0, output to be in "consumer" | ||
1166 | * PCM format, copyright asserted, no pre-emphasis and no validity | ||
1167 | * control. | ||
1168 | */ | ||
1169 | {0x18, AC_VERB_SET_DIGI_CONVERT_1, 0}, | ||
1170 | |||
1171 | /* Ensure mic1, mic2, line1 pin widgets take input from the | ||
1172 | * OUT1 sum bus when acting as an output. | ||
1173 | */ | ||
1174 | {0x1a, AC_VERB_SET_CONNECT_SEL, 0}, | ||
1175 | {0x1b, AC_VERB_SET_CONNECT_SEL, 0}, | ||
1176 | |||
1177 | /* Start with output sum widgets muted and their output gains at min */ | ||
1178 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
1179 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
1180 | |||
1181 | /* Unmute retasking pin widget output buffers since the default | ||
1182 | * state appears to be output. As the pin mode is changed by the | ||
1183 | * user the pin mode control will take care of enabling the pin's | ||
1184 | * input/output buffers as needed. | ||
1185 | */ | ||
1186 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
1187 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
1188 | {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
1189 | |||
1190 | /* Mute capture amp left and right */ | ||
1191 | {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
1192 | |||
1193 | /* Set ADC connection select to match default mixer setting (mic1 | ||
1194 | * pin) | ||
1195 | */ | ||
1196 | {0x12, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
1197 | |||
1198 | /* Mute all inputs to mixer widget (even unconnected ones) */ | ||
1199 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */ | ||
1200 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */ | ||
1201 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */ | ||
1202 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */ | ||
1203 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */ | ||
1204 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */ | ||
1205 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */ | ||
1206 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */ | ||
1207 | |||
1208 | { } | ||
1209 | }; | ||
1210 | #endif | ||
1211 | |||
1212 | |||
1213 | /* initialize jack-sensing, too */ | ||
1214 | static int cxt5047_hp_init(struct hda_codec *codec) | ||
1215 | { | ||
1216 | conexant_init(codec); | ||
1217 | cxt5047_hp_automute(codec); | ||
1218 | cxt5047_hp_automic(codec); | ||
1219 | return 0; | ||
1220 | } | ||
1221 | |||
1222 | |||
1223 | enum { | ||
1224 | CXT5047_LAPTOP, /* Laptops w/o EAPD support */ | ||
1225 | CXT5047_LAPTOP_HP, /* Some HP laptops */ | ||
1226 | CXT5047_LAPTOP_EAPD, /* Laptops with EAPD support */ | ||
1227 | #ifdef CONFIG_SND_DEBUG | ||
1228 | CXT5047_TEST, | ||
1229 | #endif | ||
1230 | CXT5047_MODELS | ||
1231 | }; | ||
1232 | |||
1233 | static const char *cxt5047_models[CXT5047_MODELS] = { | ||
1234 | [CXT5047_LAPTOP] = "laptop", | ||
1235 | [CXT5047_LAPTOP_HP] = "laptop-hp", | ||
1236 | [CXT5047_LAPTOP_EAPD] = "laptop-eapd", | ||
1237 | #ifdef CONFIG_SND_DEBUG | ||
1238 | [CXT5047_TEST] = "test", | ||
1239 | #endif | ||
1240 | }; | ||
1241 | |||
1242 | static struct snd_pci_quirk cxt5047_cfg_tbl[] = { | ||
1243 | SND_PCI_QUIRK(0x103c, 0x30a0, "HP DV1000", CXT5047_LAPTOP), | ||
1244 | SND_PCI_QUIRK(0x103c, 0x30b2, "HP DV2000T/DV3000T", CXT5047_LAPTOP), | ||
1245 | SND_PCI_QUIRK(0x103c, 0x30a5, "HP DV5200T/DV8000T", CXT5047_LAPTOP_HP), | ||
1246 | SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P100", CXT5047_LAPTOP_EAPD), | ||
1247 | {} | ||
1248 | }; | ||
1249 | |||
1250 | static int patch_cxt5047(struct hda_codec *codec) | ||
1251 | { | ||
1252 | struct conexant_spec *spec; | ||
1253 | int board_config; | ||
1254 | |||
1255 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
1256 | if (!spec) | ||
1257 | return -ENOMEM; | ||
1258 | mutex_init(&spec->amp_mutex); | ||
1259 | codec->spec = spec; | ||
1260 | |||
1261 | spec->multiout.max_channels = 2; | ||
1262 | spec->multiout.num_dacs = ARRAY_SIZE(cxt5047_dac_nids); | ||
1263 | spec->multiout.dac_nids = cxt5047_dac_nids; | ||
1264 | spec->multiout.dig_out_nid = CXT5047_SPDIF_OUT; | ||
1265 | spec->num_adc_nids = 1; | ||
1266 | spec->adc_nids = cxt5047_adc_nids; | ||
1267 | spec->capsrc_nids = cxt5047_capsrc_nids; | ||
1268 | spec->input_mux = &cxt5047_capture_source; | ||
1269 | spec->num_mixers = 1; | ||
1270 | spec->mixers[0] = cxt5047_mixers; | ||
1271 | spec->num_init_verbs = 1; | ||
1272 | spec->init_verbs[0] = cxt5047_init_verbs; | ||
1273 | spec->spdif_route = 0; | ||
1274 | spec->num_channel_mode = ARRAY_SIZE(cxt5047_modes), | ||
1275 | spec->channel_mode = cxt5047_modes, | ||
1276 | |||
1277 | codec->patch_ops = conexant_patch_ops; | ||
1278 | codec->patch_ops.unsol_event = cxt5047_hp_unsol_event; | ||
1279 | |||
1280 | board_config = snd_hda_check_board_config(codec, CXT5047_MODELS, | ||
1281 | cxt5047_models, | ||
1282 | cxt5047_cfg_tbl); | ||
1283 | switch (board_config) { | ||
1284 | case CXT5047_LAPTOP: | ||
1285 | break; | ||
1286 | case CXT5047_LAPTOP_HP: | ||
1287 | spec->input_mux = &cxt5047_hp_capture_source; | ||
1288 | spec->num_init_verbs = 2; | ||
1289 | spec->init_verbs[1] = cxt5047_hp_init_verbs; | ||
1290 | spec->mixers[0] = cxt5047_hp_mixers; | ||
1291 | codec->patch_ops.init = cxt5047_hp_init; | ||
1292 | break; | ||
1293 | case CXT5047_LAPTOP_EAPD: | ||
1294 | spec->num_init_verbs = 2; | ||
1295 | spec->init_verbs[1] = cxt5047_toshiba_init_verbs; | ||
1296 | break; | ||
1297 | #ifdef CONFIG_SND_DEBUG | ||
1298 | case CXT5047_TEST: | ||
1299 | spec->input_mux = &cxt5047_test_capture_source; | ||
1300 | spec->mixers[0] = cxt5047_test_mixer; | ||
1301 | spec->init_verbs[0] = cxt5047_test_init_verbs; | ||
1302 | #endif | ||
1303 | } | ||
1304 | return 0; | ||
1305 | } | ||
1306 | |||
1307 | struct hda_codec_preset snd_hda_preset_conexant[] = { | ||
1308 | { .id = 0x14f15045, .name = "CXT5045", .patch = patch_cxt5045 }, | ||
1309 | { .id = 0x14f15047, .name = "CXT5047", .patch = patch_cxt5047 }, | ||
1310 | {} /* terminator */ | ||
1311 | }; | ||
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 4e0c3c1b908b..145682b78071 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c | |||
@@ -32,6 +32,10 @@ | |||
32 | #include "hda_codec.h" | 32 | #include "hda_codec.h" |
33 | #include "hda_local.h" | 33 | #include "hda_local.h" |
34 | 34 | ||
35 | #define ALC880_FRONT_EVENT 0x01 | ||
36 | #define ALC880_DCVOL_EVENT 0x02 | ||
37 | #define ALC880_HP_EVENT 0x04 | ||
38 | #define ALC880_MIC_EVENT 0x08 | ||
35 | 39 | ||
36 | /* ALC880 board config type */ | 40 | /* ALC880 board config type */ |
37 | enum { | 41 | enum { |
@@ -48,7 +52,10 @@ enum { | |||
48 | ALC880_ASUS_DIG, | 52 | ALC880_ASUS_DIG, |
49 | ALC880_ASUS_W1V, | 53 | ALC880_ASUS_W1V, |
50 | ALC880_ASUS_DIG2, | 54 | ALC880_ASUS_DIG2, |
55 | ALC880_FUJITSU, | ||
51 | ALC880_UNIWILL_DIG, | 56 | ALC880_UNIWILL_DIG, |
57 | ALC880_UNIWILL, | ||
58 | ALC880_UNIWILL_P53, | ||
52 | ALC880_CLEVO, | 59 | ALC880_CLEVO, |
53 | ALC880_TCL_S700, | 60 | ALC880_TCL_S700, |
54 | ALC880_LG, | 61 | ALC880_LG, |
@@ -77,8 +84,12 @@ enum { | |||
77 | /* ALC262 models */ | 84 | /* ALC262 models */ |
78 | enum { | 85 | enum { |
79 | ALC262_BASIC, | 86 | ALC262_BASIC, |
87 | ALC262_HIPPO, | ||
88 | ALC262_HIPPO_1, | ||
80 | ALC262_FUJITSU, | 89 | ALC262_FUJITSU, |
81 | ALC262_HP_BPC, | 90 | ALC262_HP_BPC, |
91 | ALC262_HP_BPC_D7000_WL, | ||
92 | ALC262_HP_BPC_D7000_WF, | ||
82 | ALC262_BENQ_ED8, | 93 | ALC262_BENQ_ED8, |
83 | ALC262_AUTO, | 94 | ALC262_AUTO, |
84 | ALC262_MODEL_LAST /* last tag */ | 95 | ALC262_MODEL_LAST /* last tag */ |
@@ -91,16 +102,30 @@ enum { | |||
91 | ALC861_3ST_DIG, | 102 | ALC861_3ST_DIG, |
92 | ALC861_6ST_DIG, | 103 | ALC861_6ST_DIG, |
93 | ALC861_UNIWILL_M31, | 104 | ALC861_UNIWILL_M31, |
105 | ALC861_TOSHIBA, | ||
106 | ALC861_ASUS, | ||
107 | ALC861_ASUS_LAPTOP, | ||
94 | ALC861_AUTO, | 108 | ALC861_AUTO, |
95 | ALC861_MODEL_LAST, | 109 | ALC861_MODEL_LAST, |
96 | }; | 110 | }; |
97 | 111 | ||
112 | /* ALC861-VD models */ | ||
113 | enum { | ||
114 | ALC660VD_3ST, | ||
115 | ALC861VD_3ST, | ||
116 | ALC861VD_3ST_DIG, | ||
117 | ALC861VD_6ST_DIG, | ||
118 | ALC861VD_AUTO, | ||
119 | ALC861VD_MODEL_LAST, | ||
120 | }; | ||
121 | |||
98 | /* ALC882 models */ | 122 | /* ALC882 models */ |
99 | enum { | 123 | enum { |
100 | ALC882_3ST_DIG, | 124 | ALC882_3ST_DIG, |
101 | ALC882_6ST_DIG, | 125 | ALC882_6ST_DIG, |
102 | ALC882_ARIMA, | 126 | ALC882_ARIMA, |
103 | ALC882_AUTO, | 127 | ALC882_AUTO, |
128 | ALC885_MACPRO, | ||
104 | ALC882_MODEL_LAST, | 129 | ALC882_MODEL_LAST, |
105 | }; | 130 | }; |
106 | 131 | ||
@@ -110,8 +135,12 @@ enum { | |||
110 | ALC883_3ST_6ch_DIG, | 135 | ALC883_3ST_6ch_DIG, |
111 | ALC883_3ST_6ch, | 136 | ALC883_3ST_6ch, |
112 | ALC883_6ST_DIG, | 137 | ALC883_6ST_DIG, |
138 | ALC883_TARGA_DIG, | ||
139 | ALC883_TARGA_2ch_DIG, | ||
113 | ALC888_DEMO_BOARD, | 140 | ALC888_DEMO_BOARD, |
114 | ALC883_ACER, | 141 | ALC883_ACER, |
142 | ALC883_MEDION, | ||
143 | ALC883_LAPTOP_EAPD, | ||
115 | ALC883_AUTO, | 144 | ALC883_AUTO, |
116 | ALC883_MODEL_LAST, | 145 | ALC883_MODEL_LAST, |
117 | }; | 146 | }; |
@@ -1015,6 +1044,60 @@ static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = { | |||
1015 | { } /* end */ | 1044 | { } /* end */ |
1016 | }; | 1045 | }; |
1017 | 1046 | ||
1047 | /* Uniwill */ | ||
1048 | static struct snd_kcontrol_new alc880_uniwill_mixer[] = { | ||
1049 | HDA_CODEC_VOLUME("HPhone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
1050 | HDA_BIND_MUTE("HPhone Playback Switch", 0x0c, 2, HDA_INPUT), | ||
1051 | HDA_CODEC_VOLUME("iSpeaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), | ||
1052 | HDA_BIND_MUTE("iSpeaker Playback Switch", 0x0d, 2, HDA_INPUT), | ||
1053 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), | ||
1054 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), | ||
1055 | HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), | ||
1056 | HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), | ||
1057 | HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), | ||
1058 | HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), | ||
1059 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), | ||
1060 | HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), | ||
1061 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | ||
1062 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | ||
1063 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), | ||
1064 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), | ||
1065 | HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), | ||
1066 | HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), | ||
1067 | { | ||
1068 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1069 | .name = "Channel Mode", | ||
1070 | .info = alc_ch_mode_info, | ||
1071 | .get = alc_ch_mode_get, | ||
1072 | .put = alc_ch_mode_put, | ||
1073 | }, | ||
1074 | { } /* end */ | ||
1075 | }; | ||
1076 | |||
1077 | static struct snd_kcontrol_new alc880_fujitsu_mixer[] = { | ||
1078 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
1079 | HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), | ||
1080 | HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), | ||
1081 | HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT), | ||
1082 | HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), | ||
1083 | HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), | ||
1084 | HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | ||
1085 | HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | ||
1086 | HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), | ||
1087 | HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), | ||
1088 | { } /* end */ | ||
1089 | }; | ||
1090 | |||
1091 | static struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = { | ||
1092 | HDA_CODEC_VOLUME("HPhone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
1093 | HDA_BIND_MUTE("HPhone Playback Switch", 0x0c, 2, HDA_INPUT), | ||
1094 | HDA_CODEC_VOLUME("iSpeaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), | ||
1095 | HDA_BIND_MUTE("iSpeaker Playback Switch", 0x0d, 2, HDA_INPUT), | ||
1096 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | ||
1097 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | ||
1098 | { } /* end */ | ||
1099 | }; | ||
1100 | |||
1018 | /* | 1101 | /* |
1019 | * build control elements | 1102 | * build control elements |
1020 | */ | 1103 | */ |
@@ -1248,6 +1331,159 @@ static struct hda_verb alc880_pin_6stack_init_verbs[] = { | |||
1248 | { } | 1331 | { } |
1249 | }; | 1332 | }; |
1250 | 1333 | ||
1334 | /* | ||
1335 | * Uniwill pin configuration: | ||
1336 | * HP = 0x14, InternalSpeaker = 0x15, mic = 0x18, internal mic = 0x19, | ||
1337 | * line = 0x1a | ||
1338 | */ | ||
1339 | static struct hda_verb alc880_uniwill_init_verbs[] = { | ||
1340 | {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ | ||
1341 | |||
1342 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
1343 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
1344 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
1345 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
1346 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
1347 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
1348 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
1349 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
1350 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | ||
1351 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, | ||
1352 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | ||
1353 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, | ||
1354 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | ||
1355 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, | ||
1356 | |||
1357 | {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
1358 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
1359 | {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
1360 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
1361 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
1362 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
1363 | /* {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, */ | ||
1364 | /* {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */ | ||
1365 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
1366 | |||
1367 | {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, | ||
1368 | {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, | ||
1369 | |||
1370 | { } | ||
1371 | }; | ||
1372 | |||
1373 | /* | ||
1374 | * Uniwill P53 | ||
1375 | * HP = 0x14, InternalSpeaker = 0x15, mic = 0x19, | ||
1376 | */ | ||
1377 | static struct hda_verb alc880_uniwill_p53_init_verbs[] = { | ||
1378 | {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ | ||
1379 | |||
1380 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
1381 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
1382 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
1383 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
1384 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
1385 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
1386 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | ||
1387 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, | ||
1388 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | ||
1389 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, | ||
1390 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | ||
1391 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, | ||
1392 | |||
1393 | {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
1394 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
1395 | {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
1396 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
1397 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
1398 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
1399 | |||
1400 | {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, | ||
1401 | {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_DCVOL_EVENT}, | ||
1402 | |||
1403 | { } | ||
1404 | }; | ||
1405 | |||
1406 | static struct hda_verb alc880_beep_init_verbs[] = { | ||
1407 | { 0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) }, | ||
1408 | { } | ||
1409 | }; | ||
1410 | |||
1411 | /* toggle speaker-output according to the hp-jack state */ | ||
1412 | static void alc880_uniwill_automute(struct hda_codec *codec) | ||
1413 | { | ||
1414 | unsigned int present; | ||
1415 | |||
1416 | present = snd_hda_codec_read(codec, 0x14, 0, | ||
1417 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
1418 | snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, | ||
1419 | 0x80, present ? 0x80 : 0); | ||
1420 | snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, | ||
1421 | 0x80, present ? 0x80 : 0); | ||
1422 | snd_hda_codec_amp_update(codec, 0x16, 0, HDA_OUTPUT, 0, | ||
1423 | 0x80, present ? 0x80 : 0); | ||
1424 | snd_hda_codec_amp_update(codec, 0x16, 1, HDA_OUTPUT, 0, | ||
1425 | 0x80, present ? 0x80 : 0); | ||
1426 | |||
1427 | present = snd_hda_codec_read(codec, 0x18, 0, | ||
1428 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
1429 | snd_hda_codec_write(codec, 0x0b, 0, AC_VERB_SET_AMP_GAIN_MUTE, | ||
1430 | 0x7000 | (0x01 << 8) | (present ? 0x80 : 0)); | ||
1431 | } | ||
1432 | |||
1433 | static void alc880_uniwill_unsol_event(struct hda_codec *codec, | ||
1434 | unsigned int res) | ||
1435 | { | ||
1436 | /* Looks like the unsol event is incompatible with the standard | ||
1437 | * definition. 4bit tag is placed at 28 bit! | ||
1438 | */ | ||
1439 | if ((res >> 28) == ALC880_HP_EVENT || | ||
1440 | (res >> 28) == ALC880_MIC_EVENT) | ||
1441 | alc880_uniwill_automute(codec); | ||
1442 | } | ||
1443 | |||
1444 | static void alc880_uniwill_p53_hp_automute(struct hda_codec *codec) | ||
1445 | { | ||
1446 | unsigned int present; | ||
1447 | |||
1448 | present = snd_hda_codec_read(codec, 0x14, 0, | ||
1449 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
1450 | |||
1451 | snd_hda_codec_amp_update(codec, 0x15, 0, HDA_INPUT, 0, | ||
1452 | 0x80, present ? 0x80 : 0); | ||
1453 | snd_hda_codec_amp_update(codec, 0x15, 1, HDA_INPUT, 0, | ||
1454 | 0x80, present ? 0x80 : 0); | ||
1455 | } | ||
1456 | |||
1457 | static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec) | ||
1458 | { | ||
1459 | unsigned int present; | ||
1460 | |||
1461 | present = snd_hda_codec_read(codec, 0x21, 0, | ||
1462 | AC_VERB_GET_VOLUME_KNOB_CONTROL, 0) & 0x7f; | ||
1463 | |||
1464 | snd_hda_codec_amp_update(codec, 0x0c, 0, HDA_OUTPUT, 0, | ||
1465 | 0x7f, present); | ||
1466 | snd_hda_codec_amp_update(codec, 0x0c, 1, HDA_OUTPUT, 0, | ||
1467 | 0x7f, present); | ||
1468 | |||
1469 | snd_hda_codec_amp_update(codec, 0x0d, 0, HDA_OUTPUT, 0, | ||
1470 | 0x7f, present); | ||
1471 | snd_hda_codec_amp_update(codec, 0x0d, 1, HDA_OUTPUT, 0, | ||
1472 | 0x7f, present); | ||
1473 | |||
1474 | } | ||
1475 | static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec, | ||
1476 | unsigned int res) | ||
1477 | { | ||
1478 | /* Looks like the unsol event is incompatible with the standard | ||
1479 | * definition. 4bit tag is placed at 28 bit! | ||
1480 | */ | ||
1481 | if ((res >> 28) == ALC880_HP_EVENT) | ||
1482 | alc880_uniwill_p53_hp_automute(codec); | ||
1483 | if ((res >> 28) == ALC880_DCVOL_EVENT) | ||
1484 | alc880_uniwill_p53_dcvol_automute(codec); | ||
1485 | } | ||
1486 | |||
1251 | /* FIXME! */ | 1487 | /* FIXME! */ |
1252 | /* | 1488 | /* |
1253 | * F1734 pin configuration: | 1489 | * F1734 pin configuration: |
@@ -2125,159 +2361,112 @@ static struct hda_verb alc880_test_init_verbs[] = { | |||
2125 | /* | 2361 | /* |
2126 | */ | 2362 | */ |
2127 | 2363 | ||
2128 | static struct hda_board_config alc880_cfg_tbl[] = { | 2364 | static const char *alc880_models[ALC880_MODEL_LAST] = { |
2129 | /* Back 3 jack, front 2 jack */ | 2365 | [ALC880_3ST] = "3stack", |
2130 | { .modelname = "3stack", .config = ALC880_3ST }, | 2366 | [ALC880_TCL_S700] = "tcl", |
2131 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe200, .config = ALC880_3ST }, | 2367 | [ALC880_3ST_DIG] = "3stack-digout", |
2132 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe201, .config = ALC880_3ST }, | 2368 | [ALC880_CLEVO] = "clevo", |
2133 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe202, .config = ALC880_3ST }, | 2369 | [ALC880_5ST] = "5stack", |
2134 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe203, .config = ALC880_3ST }, | 2370 | [ALC880_5ST_DIG] = "5stack-digout", |
2135 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe204, .config = ALC880_3ST }, | 2371 | [ALC880_W810] = "w810", |
2136 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe205, .config = ALC880_3ST }, | 2372 | [ALC880_Z71V] = "z71v", |
2137 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe206, .config = ALC880_3ST }, | 2373 | [ALC880_6ST] = "6stack", |
2138 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe207, .config = ALC880_3ST }, | 2374 | [ALC880_6ST_DIG] = "6stack-digout", |
2139 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe208, .config = ALC880_3ST }, | 2375 | [ALC880_ASUS] = "asus", |
2140 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe209, .config = ALC880_3ST }, | 2376 | [ALC880_ASUS_W1V] = "asus-w1v", |
2141 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20a, .config = ALC880_3ST }, | 2377 | [ALC880_ASUS_DIG] = "asus-dig", |
2142 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20b, .config = ALC880_3ST }, | 2378 | [ALC880_ASUS_DIG2] = "asus-dig2", |
2143 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20c, .config = ALC880_3ST }, | 2379 | [ALC880_UNIWILL_DIG] = "uniwill", |
2144 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20d, .config = ALC880_3ST }, | 2380 | [ALC880_UNIWILL_P53] = "uniwill-p53", |
2145 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20e, .config = ALC880_3ST }, | 2381 | [ALC880_FUJITSU] = "fujitsu", |
2146 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20f, .config = ALC880_3ST }, | 2382 | [ALC880_F1734] = "F1734", |
2147 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe210, .config = ALC880_3ST }, | 2383 | [ALC880_LG] = "lg", |
2148 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe211, .config = ALC880_3ST }, | 2384 | [ALC880_LG_LW] = "lg-lw", |
2149 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe212, .config = ALC880_3ST }, | ||
2150 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe213, .config = ALC880_3ST }, | ||
2151 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe214, .config = ALC880_3ST }, | ||
2152 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe234, .config = ALC880_3ST }, | ||
2153 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe302, .config = ALC880_3ST }, | ||
2154 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe303, .config = ALC880_3ST }, | ||
2155 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe304, .config = ALC880_3ST }, | ||
2156 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe306, .config = ALC880_3ST }, | ||
2157 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe307, .config = ALC880_3ST }, | ||
2158 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe404, .config = ALC880_3ST }, | ||
2159 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xa101, .config = ALC880_3ST }, | ||
2160 | { .pci_subvendor = 0x107b, .pci_subdevice = 0x3031, .config = ALC880_3ST }, | ||
2161 | { .pci_subvendor = 0x107b, .pci_subdevice = 0x4036, .config = ALC880_3ST }, | ||
2162 | { .pci_subvendor = 0x107b, .pci_subdevice = 0x4037, .config = ALC880_3ST }, | ||
2163 | { .pci_subvendor = 0x107b, .pci_subdevice = 0x4038, .config = ALC880_3ST }, | ||
2164 | { .pci_subvendor = 0x107b, .pci_subdevice = 0x4040, .config = ALC880_3ST }, | ||
2165 | { .pci_subvendor = 0x107b, .pci_subdevice = 0x4041, .config = ALC880_3ST }, | ||
2166 | /* TCL S700 */ | ||
2167 | { .modelname = "tcl", .config = ALC880_TCL_S700 }, | ||
2168 | { .pci_subvendor = 0x19db, .pci_subdevice = 0x4188, .config = ALC880_TCL_S700 }, | ||
2169 | |||
2170 | /* Back 3 jack, front 2 jack (Internal add Aux-In) */ | ||
2171 | { .pci_subvendor = 0x1025, .pci_subdevice = 0xe310, .config = ALC880_3ST }, | ||
2172 | { .pci_subvendor = 0x104d, .pci_subdevice = 0x81d6, .config = ALC880_3ST }, | ||
2173 | { .pci_subvendor = 0x104d, .pci_subdevice = 0x81a0, .config = ALC880_3ST }, | ||
2174 | |||
2175 | /* Back 3 jack plus 1 SPDIF out jack, front 2 jack */ | ||
2176 | { .modelname = "3stack-digout", .config = ALC880_3ST_DIG }, | ||
2177 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe308, .config = ALC880_3ST_DIG }, | ||
2178 | { .pci_subvendor = 0x1025, .pci_subdevice = 0x0070, .config = ALC880_3ST_DIG }, | ||
2179 | |||
2180 | /* Clevo laptops */ | ||
2181 | { .modelname = "clevo", .config = ALC880_CLEVO }, | ||
2182 | { .pci_subvendor = 0x1558, .pci_subdevice = 0x0520, | ||
2183 | .config = ALC880_CLEVO }, /* Clevo m520G NB */ | ||
2184 | { .pci_subvendor = 0x1558, .pci_subdevice = 0x0660, | ||
2185 | .config = ALC880_CLEVO }, /* Clevo m665n */ | ||
2186 | |||
2187 | /* Back 3 jack plus 1 SPDIF out jack, front 2 jack (Internal add Aux-In)*/ | ||
2188 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe305, .config = ALC880_3ST_DIG }, | ||
2189 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xd402, .config = ALC880_3ST_DIG }, | ||
2190 | { .pci_subvendor = 0x1025, .pci_subdevice = 0xe309, .config = ALC880_3ST_DIG }, | ||
2191 | |||
2192 | /* Back 5 jack, front 2 jack */ | ||
2193 | { .modelname = "5stack", .config = ALC880_5ST }, | ||
2194 | { .pci_subvendor = 0x107b, .pci_subdevice = 0x3033, .config = ALC880_5ST }, | ||
2195 | { .pci_subvendor = 0x107b, .pci_subdevice = 0x4039, .config = ALC880_5ST }, | ||
2196 | { .pci_subvendor = 0x107b, .pci_subdevice = 0x3032, .config = ALC880_5ST }, | ||
2197 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x2a09, .config = ALC880_5ST }, | ||
2198 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x814e, .config = ALC880_5ST }, | ||
2199 | |||
2200 | /* Back 5 jack plus 1 SPDIF out jack, front 2 jack */ | ||
2201 | { .modelname = "5stack-digout", .config = ALC880_5ST_DIG }, | ||
2202 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe224, .config = ALC880_5ST_DIG }, | ||
2203 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe400, .config = ALC880_5ST_DIG }, | ||
2204 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe401, .config = ALC880_5ST_DIG }, | ||
2205 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe402, .config = ALC880_5ST_DIG }, | ||
2206 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xd400, .config = ALC880_5ST_DIG }, | ||
2207 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xd401, .config = ALC880_5ST_DIG }, | ||
2208 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xa100, .config = ALC880_5ST_DIG }, | ||
2209 | { .pci_subvendor = 0x1565, .pci_subdevice = 0x8202, .config = ALC880_5ST_DIG }, | ||
2210 | { .pci_subvendor = 0x1019, .pci_subdevice = 0xa880, .config = ALC880_5ST_DIG }, | ||
2211 | { .pci_subvendor = 0xa0a0, .pci_subdevice = 0x0560, | ||
2212 | .config = ALC880_5ST_DIG }, /* Aopen i915GMm-HFS */ | ||
2213 | /* { .pci_subvendor = 0x1019, .pci_subdevice = 0xa884, .config = ALC880_5ST_DIG }, */ /* conflict with 6stack */ | ||
2214 | { .pci_subvendor = 0x1695, .pci_subdevice = 0x400d, .config = ALC880_5ST_DIG }, | ||
2215 | /* note subvendor = 0 below */ | ||
2216 | /* { .pci_subvendor = 0x0000, .pci_subdevice = 0x8086, .config = ALC880_5ST_DIG }, */ | ||
2217 | |||
2218 | { .modelname = "w810", .config = ALC880_W810 }, | ||
2219 | { .pci_subvendor = 0x161f, .pci_subdevice = 0x203d, .config = ALC880_W810 }, | ||
2220 | |||
2221 | { .modelname = "z71v", .config = ALC880_Z71V }, | ||
2222 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1964, .config = ALC880_Z71V }, | ||
2223 | |||
2224 | { .modelname = "6stack", .config = ALC880_6ST }, | ||
2225 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x8196, .config = ALC880_6ST }, /* ASUS P5GD1-HVM */ | ||
2226 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x81b4, .config = ALC880_6ST }, | ||
2227 | { .pci_subvendor = 0x1019, .pci_subdevice = 0xa884, .config = ALC880_6ST }, /* Acer APFV */ | ||
2228 | { .pci_subvendor = 0x1458, .pci_subdevice = 0xa102, .config = ALC880_6ST }, /* Gigabyte K8N51 */ | ||
2229 | |||
2230 | { .modelname = "6stack-digout", .config = ALC880_6ST_DIG }, | ||
2231 | { .pci_subvendor = 0x2668, .pci_subdevice = 0x8086, .config = ALC880_6ST_DIG }, | ||
2232 | { .pci_subvendor = 0x8086, .pci_subdevice = 0x2668, .config = ALC880_6ST_DIG }, | ||
2233 | { .pci_subvendor = 0x1462, .pci_subdevice = 0x1150, .config = ALC880_6ST_DIG }, | ||
2234 | { .pci_subvendor = 0xe803, .pci_subdevice = 0x1019, .config = ALC880_6ST_DIG }, | ||
2235 | { .pci_subvendor = 0x1039, .pci_subdevice = 0x1234, .config = ALC880_6ST_DIG }, | ||
2236 | { .pci_subvendor = 0x1025, .pci_subdevice = 0x0077, .config = ALC880_6ST_DIG }, | ||
2237 | { .pci_subvendor = 0x1025, .pci_subdevice = 0x0078, .config = ALC880_6ST_DIG }, | ||
2238 | { .pci_subvendor = 0x1025, .pci_subdevice = 0x0087, .config = ALC880_6ST_DIG }, | ||
2239 | { .pci_subvendor = 0x1297, .pci_subdevice = 0xc790, .config = ALC880_6ST_DIG }, /* Shuttle ST20G5 */ | ||
2240 | { .pci_subvendor = 0x1509, .pci_subdevice = 0x925d, .config = ALC880_6ST_DIG }, /* FIC P4M-915GD1 */ | ||
2241 | { .pci_subvendor = 0x1695, .pci_subdevice = 0x4012, .config = ALC880_5ST_DIG }, /* Epox EP-5LDA+ GLi */ | ||
2242 | |||
2243 | { .modelname = "asus", .config = ALC880_ASUS }, | ||
2244 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1964, .config = ALC880_ASUS_DIG }, | ||
2245 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1973, .config = ALC880_ASUS_DIG }, | ||
2246 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x19b3, .config = ALC880_ASUS_DIG }, | ||
2247 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1113, .config = ALC880_ASUS_DIG }, | ||
2248 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1173, .config = ALC880_ASUS_DIG }, | ||
2249 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1993, .config = ALC880_ASUS }, | ||
2250 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x10c2, .config = ALC880_ASUS_DIG }, /* Asus W6A */ | ||
2251 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x10c3, .config = ALC880_ASUS_DIG }, | ||
2252 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1133, .config = ALC880_ASUS }, | ||
2253 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1123, .config = ALC880_ASUS_DIG }, | ||
2254 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1143, .config = ALC880_ASUS }, | ||
2255 | { .modelname = "asus-w1v", .config = ALC880_ASUS_W1V }, | ||
2256 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x10b3, .config = ALC880_ASUS_W1V }, | ||
2257 | { .modelname = "asus-dig", .config = ALC880_ASUS_DIG }, | ||
2258 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x8181, .config = ALC880_ASUS_DIG }, /* ASUS P4GPL-X */ | ||
2259 | { .modelname = "asus-dig2", .config = ALC880_ASUS_DIG2 }, | ||
2260 | { .pci_subvendor = 0x1558, .pci_subdevice = 0x5401, .config = ALC880_ASUS_DIG2 }, | ||
2261 | |||
2262 | { .modelname = "uniwill", .config = ALC880_UNIWILL_DIG }, | ||
2263 | { .pci_subvendor = 0x1584, .pci_subdevice = 0x9050, .config = ALC880_UNIWILL_DIG }, | ||
2264 | |||
2265 | { .modelname = "F1734", .config = ALC880_F1734 }, | ||
2266 | { .pci_subvendor = 0x1734, .pci_subdevice = 0x107c, .config = ALC880_F1734 }, | ||
2267 | { .pci_subvendor = 0x1584, .pci_subdevice = 0x9054, .config = ALC880_F1734 }, | ||
2268 | |||
2269 | { .modelname = "lg", .config = ALC880_LG }, | ||
2270 | { .pci_subvendor = 0x1854, .pci_subdevice = 0x003b, .config = ALC880_LG }, | ||
2271 | { .pci_subvendor = 0x1854, .pci_subdevice = 0x0068, .config = ALC880_LG }, | ||
2272 | |||
2273 | { .modelname = "lg-lw", .config = ALC880_LG_LW }, | ||
2274 | { .pci_subvendor = 0x1854, .pci_subdevice = 0x0018, .config = ALC880_LG_LW }, | ||
2275 | { .pci_subvendor = 0x1854, .pci_subdevice = 0x0077, .config = ALC880_LG_LW }, | ||
2276 | |||
2277 | #ifdef CONFIG_SND_DEBUG | 2385 | #ifdef CONFIG_SND_DEBUG |
2278 | { .modelname = "test", .config = ALC880_TEST }, | 2386 | [ALC880_TEST] = "test", |
2279 | #endif | 2387 | #endif |
2280 | { .modelname = "auto", .config = ALC880_AUTO }, | 2388 | [ALC880_AUTO] = "auto", |
2389 | }; | ||
2390 | |||
2391 | static struct snd_pci_quirk alc880_cfg_tbl[] = { | ||
2392 | /* Broken BIOS configuration */ | ||
2393 | SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG), | ||
2394 | SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG), | ||
2395 | |||
2396 | SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG), | ||
2397 | SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST), | ||
2398 | SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810), | ||
2399 | SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_3ST_DIG), | ||
2400 | SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_6ST_DIG), | ||
2401 | SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_6ST_DIG), | ||
2402 | SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_6ST_DIG), | ||
2403 | SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_3ST_DIG), | ||
2404 | SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_3ST), | ||
2405 | |||
2406 | SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_6ST_DIG), | ||
2407 | SND_PCI_QUIRK(0x103c, 0x2a09, "HP", ALC880_5ST), | ||
2408 | |||
2409 | SND_PCI_QUIRK(0x1043, 0x10b3, "ASUS W1V", ALC880_ASUS_W1V), | ||
2410 | SND_PCI_QUIRK(0x1043, 0x10c2, "ASUS W6A", ALC880_ASUS_DIG), | ||
2411 | SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS Wxx", ALC880_ASUS_DIG), | ||
2412 | SND_PCI_QUIRK(0x1043, 0x1113, "ASUS", ALC880_ASUS_DIG), | ||
2413 | SND_PCI_QUIRK(0x1043, 0x1123, "ASUS", ALC880_ASUS_DIG), | ||
2414 | SND_PCI_QUIRK(0x1043, 0x1173, "ASUS", ALC880_ASUS_DIG), | ||
2415 | SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_Z71V), | ||
2416 | /* SND_PCI_QUIRK(0x1043, 0x1964, "ASUS", ALC880_ASUS_DIG), */ | ||
2417 | SND_PCI_QUIRK(0x1043, 0x1973, "ASUS", ALC880_ASUS_DIG), | ||
2418 | SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS", ALC880_ASUS_DIG), | ||
2419 | SND_PCI_QUIRK(0x1043, 0x814e, "ASUS", ALC880_ASUS), | ||
2420 | SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG), | ||
2421 | SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST), | ||
2422 | SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST), | ||
2423 | SND_PCI_QUIRK(0x1043, 0, "ASUS", ALC880_ASUS), | ||
2424 | |||
2425 | SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST), | ||
2426 | SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST), | ||
2427 | SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_5ST), | ||
2428 | SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_5ST), | ||
2429 | SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST), | ||
2430 | SND_PCI_QUIRK(0x1558, 0x0520, "Clevo m520G", ALC880_CLEVO), | ||
2431 | SND_PCI_QUIRK(0x1558, 0x0660, "Clevo m655n", ALC880_CLEVO), | ||
2432 | SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG), | ||
2433 | SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810), | ||
2434 | SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG), | ||
2435 | SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700), | ||
2436 | SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG), | ||
2437 | SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG), | ||
2438 | SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_6ST_DIG), | ||
2439 | SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_6ST_DIG), | ||
2440 | SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_6ST_DIG), | ||
2441 | SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_6ST_DIG), | ||
2442 | SND_PCI_QUIRK(0x1558, 0x5401, "ASUS", ALC880_ASUS_DIG2), | ||
2443 | |||
2444 | SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_UNIWILL_DIG), | ||
2445 | SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL), | ||
2446 | SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53), | ||
2447 | SND_PCI_QUIRK(0x1584, 0x9054, "Uniwlll", ALC880_F1734), | ||
2448 | |||
2449 | SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG), | ||
2450 | SND_PCI_QUIRK(0x1734, 0x10ac, "FSC", ALC880_UNIWILL), | ||
2451 | SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734), | ||
2452 | SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU), | ||
2453 | |||
2454 | SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG), | ||
2455 | SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG), | ||
2456 | SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW), | ||
2457 | SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW), | ||
2458 | |||
2459 | SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_3ST_DIG), | ||
2460 | SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_3ST_DIG), | ||
2461 | SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_3ST_DIG), | ||
2462 | SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_5ST_DIG), | ||
2463 | SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_5ST_DIG), | ||
2464 | SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_5ST_DIG), | ||
2465 | SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG), | ||
2466 | SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG), | ||
2467 | SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG), | ||
2468 | SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_5ST_DIG), | ||
2469 | SND_PCI_QUIRK(0x8086, 0, "Intel mobo", ALC880_3ST), | ||
2281 | 2470 | ||
2282 | {} | 2471 | {} |
2283 | }; | 2472 | }; |
@@ -2438,7 +2627,8 @@ static struct alc_config_preset alc880_presets[] = { | |||
2438 | }, | 2627 | }, |
2439 | [ALC880_UNIWILL_DIG] = { | 2628 | [ALC880_UNIWILL_DIG] = { |
2440 | .mixers = { alc880_asus_mixer, alc880_pcbeep_mixer }, | 2629 | .mixers = { alc880_asus_mixer, alc880_pcbeep_mixer }, |
2441 | .init_verbs = { alc880_volume_init_verbs, alc880_pin_asus_init_verbs }, | 2630 | .init_verbs = { alc880_volume_init_verbs, |
2631 | alc880_pin_asus_init_verbs }, | ||
2442 | .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), | 2632 | .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), |
2443 | .dac_nids = alc880_asus_dac_nids, | 2633 | .dac_nids = alc880_asus_dac_nids, |
2444 | .dig_out_nid = ALC880_DIGOUT_NID, | 2634 | .dig_out_nid = ALC880_DIGOUT_NID, |
@@ -2447,6 +2637,46 @@ static struct alc_config_preset alc880_presets[] = { | |||
2447 | .need_dac_fix = 1, | 2637 | .need_dac_fix = 1, |
2448 | .input_mux = &alc880_capture_source, | 2638 | .input_mux = &alc880_capture_source, |
2449 | }, | 2639 | }, |
2640 | [ALC880_UNIWILL] = { | ||
2641 | .mixers = { alc880_uniwill_mixer }, | ||
2642 | .init_verbs = { alc880_volume_init_verbs, | ||
2643 | alc880_uniwill_init_verbs }, | ||
2644 | .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), | ||
2645 | .dac_nids = alc880_asus_dac_nids, | ||
2646 | .dig_out_nid = ALC880_DIGOUT_NID, | ||
2647 | .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), | ||
2648 | .channel_mode = alc880_threestack_modes, | ||
2649 | .need_dac_fix = 1, | ||
2650 | .input_mux = &alc880_capture_source, | ||
2651 | .unsol_event = alc880_uniwill_unsol_event, | ||
2652 | .init_hook = alc880_uniwill_automute, | ||
2653 | }, | ||
2654 | [ALC880_UNIWILL_P53] = { | ||
2655 | .mixers = { alc880_uniwill_p53_mixer }, | ||
2656 | .init_verbs = { alc880_volume_init_verbs, | ||
2657 | alc880_uniwill_p53_init_verbs }, | ||
2658 | .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), | ||
2659 | .dac_nids = alc880_asus_dac_nids, | ||
2660 | .num_channel_mode = ARRAY_SIZE(alc880_w810_modes), | ||
2661 | .channel_mode = alc880_threestack_modes, | ||
2662 | .input_mux = &alc880_capture_source, | ||
2663 | .unsol_event = alc880_uniwill_p53_unsol_event, | ||
2664 | .init_hook = alc880_uniwill_p53_hp_automute, | ||
2665 | }, | ||
2666 | [ALC880_FUJITSU] = { | ||
2667 | .mixers = { alc880_fujitsu_mixer, | ||
2668 | alc880_pcbeep_mixer, }, | ||
2669 | .init_verbs = { alc880_volume_init_verbs, | ||
2670 | alc880_uniwill_p53_init_verbs, | ||
2671 | alc880_beep_init_verbs }, | ||
2672 | .num_dacs = ARRAY_SIZE(alc880_dac_nids), | ||
2673 | .dac_nids = alc880_dac_nids, | ||
2674 | .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes), | ||
2675 | .channel_mode = alc880_2_jack_modes, | ||
2676 | .input_mux = &alc880_capture_source, | ||
2677 | .unsol_event = alc880_uniwill_p53_unsol_event, | ||
2678 | .init_hook = alc880_uniwill_p53_hp_automute, | ||
2679 | }, | ||
2450 | [ALC880_CLEVO] = { | 2680 | [ALC880_CLEVO] = { |
2451 | .mixers = { alc880_three_stack_mixer }, | 2681 | .mixers = { alc880_three_stack_mixer }, |
2452 | .init_verbs = { alc880_volume_init_verbs, | 2682 | .init_verbs = { alc880_volume_init_verbs, |
@@ -2841,8 +3071,10 @@ static int patch_alc880(struct hda_codec *codec) | |||
2841 | 3071 | ||
2842 | codec->spec = spec; | 3072 | codec->spec = spec; |
2843 | 3073 | ||
2844 | board_config = snd_hda_check_board_config(codec, alc880_cfg_tbl); | 3074 | board_config = snd_hda_check_board_config(codec, ALC880_MODEL_LAST, |
2845 | if (board_config < 0 || board_config >= ALC880_MODEL_LAST) { | 3075 | alc880_models, |
3076 | alc880_cfg_tbl); | ||
3077 | if (board_config < 0) { | ||
2846 | printk(KERN_INFO "hda_codec: Unknown model for ALC880, " | 3078 | printk(KERN_INFO "hda_codec: Unknown model for ALC880, " |
2847 | "trying auto-probe from BIOS...\n"); | 3079 | "trying auto-probe from BIOS...\n"); |
2848 | board_config = ALC880_AUTO; | 3080 | board_config = ALC880_AUTO; |
@@ -3090,11 +3322,20 @@ static struct snd_kcontrol_new alc260_fujitsu_mixer[] = { | |||
3090 | * and the output jack. If this turns out to be the case for all such | 3322 | * and the output jack. If this turns out to be the case for all such |
3091 | * models the "Line Jack Mode" mode could be changed from ALC_PIN_DIR_INOUT | 3323 | * models the "Line Jack Mode" mode could be changed from ALC_PIN_DIR_INOUT |
3092 | * to ALC_PIN_DIR_INOUT_NOMICBIAS. | 3324 | * to ALC_PIN_DIR_INOUT_NOMICBIAS. |
3325 | * | ||
3326 | * The C20x Tablet series have a mono internal speaker which is controlled | ||
3327 | * via the chip's Mono sum widget and pin complex, so include the necessary | ||
3328 | * controls for such models. On models without a "mono speaker" the control | ||
3329 | * won't do anything. | ||
3093 | */ | 3330 | */ |
3094 | static struct snd_kcontrol_new alc260_acer_mixer[] = { | 3331 | static struct snd_kcontrol_new alc260_acer_mixer[] = { |
3095 | HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT), | 3332 | HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT), |
3096 | HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT), | 3333 | HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT), |
3097 | ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT), | 3334 | ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT), |
3335 | HDA_CODEC_VOLUME_MONO("Mono Speaker Playback Volume", 0x0a, 1, 0x0, | ||
3336 | HDA_OUTPUT), | ||
3337 | HDA_BIND_MUTE_MONO("Mono Speaker Playback Switch", 0x0a, 1, 2, | ||
3338 | HDA_INPUT), | ||
3098 | HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), | 3339 | HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), |
3099 | HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), | 3340 | HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), |
3100 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT), | 3341 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT), |
@@ -3409,11 +3650,11 @@ static struct hda_verb alc260_acer_init_verbs[] = { | |||
3409 | {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, | 3650 | {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, |
3410 | /* Line In jack is connected to Line1 pin */ | 3651 | /* Line In jack is connected to Line1 pin */ |
3411 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | 3652 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, |
3653 | /* Some Acers (eg: C20x Tablets) use Mono pin for internal speaker */ | ||
3654 | {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
3412 | /* Ensure all other unused pins are disabled and muted. */ | 3655 | /* Ensure all other unused pins are disabled and muted. */ |
3413 | {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | 3656 | {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, |
3414 | {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | 3657 | {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, |
3415 | {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | ||
3416 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
3417 | {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | 3658 | {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, |
3418 | {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | 3659 | {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, |
3419 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | 3660 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, |
@@ -3441,6 +3682,8 @@ static struct hda_verb alc260_acer_init_verbs[] = { | |||
3441 | 3682 | ||
3442 | /* Unmute Line-out pin widget amp left and right (no equiv mixer ctrl) */ | 3683 | /* Unmute Line-out pin widget amp left and right (no equiv mixer ctrl) */ |
3443 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | 3684 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, |
3685 | /* Unmute mono pin widget amp output (no equiv mixer ctrl) */ | ||
3686 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
3444 | /* Unmute Mic1 and Line1 pin widget input buffers since they start as | 3687 | /* Unmute Mic1 and Line1 pin widget input buffers since they start as |
3445 | * inputs. If the pin mode is changed by the user the pin mode control | 3688 | * inputs. If the pin mode is changed by the user the pin mode control |
3446 | * will take care of enabling the pin's input/output buffers as needed. | 3689 | * will take care of enabling the pin's input/output buffers as needed. |
@@ -3928,33 +4171,33 @@ static void alc260_auto_init(struct hda_codec *codec) | |||
3928 | /* | 4171 | /* |
3929 | * ALC260 configurations | 4172 | * ALC260 configurations |
3930 | */ | 4173 | */ |
3931 | static struct hda_board_config alc260_cfg_tbl[] = { | 4174 | static const char *alc260_models[ALC260_MODEL_LAST] = { |
3932 | { .modelname = "basic", .config = ALC260_BASIC }, | 4175 | [ALC260_BASIC] = "basic", |
3933 | { .pci_subvendor = 0x104d, .pci_subdevice = 0x81bb, | 4176 | [ALC260_HP] = "hp", |
3934 | .config = ALC260_BASIC }, /* Sony VAIO */ | 4177 | [ALC260_HP_3013] = "hp-3013", |
3935 | { .pci_subvendor = 0x104d, .pci_subdevice = 0x81cc, | 4178 | [ALC260_FUJITSU_S702X] = "fujitsu", |
3936 | .config = ALC260_BASIC }, /* Sony VAIO VGN-S3HP */ | 4179 | [ALC260_ACER] = "acer", |
3937 | { .pci_subvendor = 0x104d, .pci_subdevice = 0x81cd, | ||
3938 | .config = ALC260_BASIC }, /* Sony VAIO */ | ||
3939 | { .pci_subvendor = 0x152d, .pci_subdevice = 0x0729, | ||
3940 | .config = ALC260_BASIC }, /* CTL Travel Master U553W */ | ||
3941 | { .modelname = "hp", .config = ALC260_HP }, | ||
3942 | { .modelname = "hp-3013", .config = ALC260_HP_3013 }, | ||
3943 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x3010, .config = ALC260_HP_3013 }, | ||
3944 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x3011, .config = ALC260_HP }, | ||
3945 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x3012, .config = ALC260_HP_3013 }, | ||
3946 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x3013, .config = ALC260_HP_3013 }, | ||
3947 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x3014, .config = ALC260_HP }, | ||
3948 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x3015, .config = ALC260_HP }, | ||
3949 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x3016, .config = ALC260_HP }, | ||
3950 | { .modelname = "fujitsu", .config = ALC260_FUJITSU_S702X }, | ||
3951 | { .pci_subvendor = 0x10cf, .pci_subdevice = 0x1326, .config = ALC260_FUJITSU_S702X }, | ||
3952 | { .modelname = "acer", .config = ALC260_ACER }, | ||
3953 | { .pci_subvendor = 0x1025, .pci_subdevice = 0x008f, .config = ALC260_ACER }, | ||
3954 | #ifdef CONFIG_SND_DEBUG | 4180 | #ifdef CONFIG_SND_DEBUG |
3955 | { .modelname = "test", .config = ALC260_TEST }, | 4181 | [ALC260_TEST] = "test", |
3956 | #endif | 4182 | #endif |
3957 | { .modelname = "auto", .config = ALC260_AUTO }, | 4183 | [ALC260_AUTO] = "auto", |
4184 | }; | ||
4185 | |||
4186 | static struct snd_pci_quirk alc260_cfg_tbl[] = { | ||
4187 | SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER), | ||
4188 | SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER), | ||
4189 | SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013), | ||
4190 | SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP), | ||
4191 | SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_3013), | ||
4192 | SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013), | ||
4193 | SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP), | ||
4194 | SND_PCI_QUIRK(0x103c, 0x3015, "HP", ALC260_HP), | ||
4195 | SND_PCI_QUIRK(0x103c, 0x3016, "HP", ALC260_HP), | ||
4196 | SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_BASIC), | ||
4197 | SND_PCI_QUIRK(0x104d, 0x81cc, "Sony VAIO", ALC260_BASIC), | ||
4198 | SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC), | ||
4199 | SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X), | ||
4200 | SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC), | ||
3958 | {} | 4201 | {} |
3959 | }; | 4202 | }; |
3960 | 4203 | ||
@@ -4053,8 +4296,10 @@ static int patch_alc260(struct hda_codec *codec) | |||
4053 | 4296 | ||
4054 | codec->spec = spec; | 4297 | codec->spec = spec; |
4055 | 4298 | ||
4056 | board_config = snd_hda_check_board_config(codec, alc260_cfg_tbl); | 4299 | board_config = snd_hda_check_board_config(codec, ALC260_MODEL_LAST, |
4057 | if (board_config < 0 || board_config >= ALC260_MODEL_LAST) { | 4300 | alc260_models, |
4301 | alc260_cfg_tbl); | ||
4302 | if (board_config < 0) { | ||
4058 | snd_printd(KERN_INFO "hda_codec: Unknown model for ALC260, " | 4303 | snd_printd(KERN_INFO "hda_codec: Unknown model for ALC260, " |
4059 | "trying auto-probe from BIOS...\n"); | 4304 | "trying auto-probe from BIOS...\n"); |
4060 | board_config = ALC260_AUTO; | 4305 | board_config = ALC260_AUTO; |
@@ -4207,8 +4452,10 @@ static struct snd_kcontrol_new alc882_base_mixer[] = { | |||
4207 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), | 4452 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), |
4208 | HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), | 4453 | HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), |
4209 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | 4454 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), |
4455 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), | ||
4210 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | 4456 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), |
4211 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), | 4457 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), |
4458 | HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), | ||
4212 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), | 4459 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), |
4213 | HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), | 4460 | HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), |
4214 | HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), | 4461 | HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), |
@@ -4313,6 +4560,100 @@ static struct hda_verb alc882_eapd_verbs[] = { | |||
4313 | { } | 4560 | { } |
4314 | }; | 4561 | }; |
4315 | 4562 | ||
4563 | /* Mac Pro test */ | ||
4564 | static struct snd_kcontrol_new alc882_macpro_mixer[] = { | ||
4565 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
4566 | HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), | ||
4567 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x18, 0x0, HDA_OUTPUT), | ||
4568 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT), | ||
4569 | HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT), | ||
4570 | HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x02, HDA_INPUT), | ||
4571 | HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x02, HDA_INPUT), | ||
4572 | { } /* end */ | ||
4573 | }; | ||
4574 | |||
4575 | static struct hda_verb alc882_macpro_init_verbs[] = { | ||
4576 | /* Front mixer: unmute input/output amp left and right (volume = 0) */ | ||
4577 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
4578 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
4579 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
4580 | /* Front Pin: output 0 (0x0c) */ | ||
4581 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
4582 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
4583 | {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
4584 | /* Front Mic pin: input vref at 80% */ | ||
4585 | {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
4586 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4587 | /* Speaker: output */ | ||
4588 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
4589 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
4590 | {0x1a, AC_VERB_SET_CONNECT_SEL, 0x04}, | ||
4591 | /* Headphone output (output 0 - 0x0c) */ | ||
4592 | {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
4593 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
4594 | {0x18, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
4595 | |||
4596 | /* FIXME: use matrix-type input source selection */ | ||
4597 | /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ | ||
4598 | /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ | ||
4599 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
4600 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
4601 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
4602 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
4603 | /* Input mixer2 */ | ||
4604 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
4605 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
4606 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
4607 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
4608 | /* Input mixer3 */ | ||
4609 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
4610 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
4611 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
4612 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
4613 | /* ADC1: mute amp left and right */ | ||
4614 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
4615 | {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
4616 | /* ADC2: mute amp left and right */ | ||
4617 | {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
4618 | {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
4619 | /* ADC3: mute amp left and right */ | ||
4620 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
4621 | {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
4622 | |||
4623 | { } | ||
4624 | }; | ||
4625 | static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted) | ||
4626 | { | ||
4627 | unsigned int gpiostate, gpiomask, gpiodir; | ||
4628 | |||
4629 | gpiostate = snd_hda_codec_read(codec, codec->afg, 0, | ||
4630 | AC_VERB_GET_GPIO_DATA, 0); | ||
4631 | |||
4632 | if (!muted) | ||
4633 | gpiostate |= (1 << pin); | ||
4634 | else | ||
4635 | gpiostate &= ~(1 << pin); | ||
4636 | |||
4637 | gpiomask = snd_hda_codec_read(codec, codec->afg, 0, | ||
4638 | AC_VERB_GET_GPIO_MASK, 0); | ||
4639 | gpiomask |= (1 << pin); | ||
4640 | |||
4641 | gpiodir = snd_hda_codec_read(codec, codec->afg, 0, | ||
4642 | AC_VERB_GET_GPIO_DIRECTION, 0); | ||
4643 | gpiodir |= (1 << pin); | ||
4644 | |||
4645 | |||
4646 | snd_hda_codec_write(codec, codec->afg, 0, | ||
4647 | AC_VERB_SET_GPIO_MASK, gpiomask); | ||
4648 | snd_hda_codec_write(codec, codec->afg, 0, | ||
4649 | AC_VERB_SET_GPIO_DIRECTION, gpiodir); | ||
4650 | |||
4651 | msleep(1); | ||
4652 | |||
4653 | snd_hda_codec_write(codec, codec->afg, 0, | ||
4654 | AC_VERB_SET_GPIO_DATA, gpiostate); | ||
4655 | } | ||
4656 | |||
4316 | /* | 4657 | /* |
4317 | * generic initialization of ADC, input mixers and output mixers | 4658 | * generic initialization of ADC, input mixers and output mixers |
4318 | */ | 4659 | */ |
@@ -4435,19 +4776,20 @@ static struct snd_kcontrol_new alc882_capture_mixer[] = { | |||
4435 | /* | 4776 | /* |
4436 | * configuration and preset | 4777 | * configuration and preset |
4437 | */ | 4778 | */ |
4438 | static struct hda_board_config alc882_cfg_tbl[] = { | 4779 | static const char *alc882_models[ALC882_MODEL_LAST] = { |
4439 | { .modelname = "3stack-dig", .config = ALC882_3ST_DIG }, | 4780 | [ALC882_3ST_DIG] = "3stack-dig", |
4440 | { .modelname = "6stack-dig", .config = ALC882_6ST_DIG }, | 4781 | [ALC882_6ST_DIG] = "6stack-dig", |
4441 | { .pci_subvendor = 0x1462, .pci_subdevice = 0x6668, | 4782 | [ALC882_ARIMA] = "arima", |
4442 | .config = ALC882_6ST_DIG }, /* MSI */ | 4783 | [ALC885_MACPRO] = "macpro", |
4443 | { .pci_subvendor = 0x105b, .pci_subdevice = 0x6668, | 4784 | [ALC882_AUTO] = "auto", |
4444 | .config = ALC882_6ST_DIG }, /* Foxconn */ | 4785 | }; |
4445 | { .pci_subvendor = 0x1019, .pci_subdevice = 0x6668, | 4786 | |
4446 | .config = ALC882_6ST_DIG }, /* ECS to Intel*/ | 4787 | static struct snd_pci_quirk alc882_cfg_tbl[] = { |
4447 | { .modelname = "arima", .config = ALC882_ARIMA }, | 4788 | SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG), |
4448 | { .pci_subvendor = 0x161f, .pci_subdevice = 0x2054, | 4789 | SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG), |
4449 | .config = ALC882_ARIMA }, /* Arima W820Di1 */ | 4790 | SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG), |
4450 | { .modelname = "auto", .config = ALC882_AUTO }, | 4791 | SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA), |
4792 | SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG), | ||
4451 | {} | 4793 | {} |
4452 | }; | 4794 | }; |
4453 | 4795 | ||
@@ -4484,6 +4826,17 @@ static struct alc_config_preset alc882_presets[] = { | |||
4484 | .channel_mode = alc882_sixstack_modes, | 4826 | .channel_mode = alc882_sixstack_modes, |
4485 | .input_mux = &alc882_capture_source, | 4827 | .input_mux = &alc882_capture_source, |
4486 | }, | 4828 | }, |
4829 | [ALC885_MACPRO] = { | ||
4830 | .mixers = { alc882_macpro_mixer }, | ||
4831 | .init_verbs = { alc882_macpro_init_verbs }, | ||
4832 | .num_dacs = ARRAY_SIZE(alc882_dac_nids), | ||
4833 | .dac_nids = alc882_dac_nids, | ||
4834 | .dig_out_nid = ALC882_DIGOUT_NID, | ||
4835 | .dig_in_nid = ALC882_DIGIN_NID, | ||
4836 | .num_channel_mode = ARRAY_SIZE(alc882_ch_modes), | ||
4837 | .channel_mode = alc882_ch_modes, | ||
4838 | .input_mux = &alc882_capture_source, | ||
4839 | }, | ||
4487 | }; | 4840 | }; |
4488 | 4841 | ||
4489 | 4842 | ||
@@ -4584,7 +4937,9 @@ static int patch_alc882(struct hda_codec *codec) | |||
4584 | 4937 | ||
4585 | codec->spec = spec; | 4938 | codec->spec = spec; |
4586 | 4939 | ||
4587 | board_config = snd_hda_check_board_config(codec, alc882_cfg_tbl); | 4940 | board_config = snd_hda_check_board_config(codec, ALC882_MODEL_LAST, |
4941 | alc882_models, | ||
4942 | alc882_cfg_tbl); | ||
4588 | 4943 | ||
4589 | if (board_config < 0 || board_config >= ALC882_MODEL_LAST) { | 4944 | if (board_config < 0 || board_config >= ALC882_MODEL_LAST) { |
4590 | printk(KERN_INFO "hda_codec: Unknown model for ALC882, " | 4945 | printk(KERN_INFO "hda_codec: Unknown model for ALC882, " |
@@ -4609,6 +4964,11 @@ static int patch_alc882(struct hda_codec *codec) | |||
4609 | if (board_config != ALC882_AUTO) | 4964 | if (board_config != ALC882_AUTO) |
4610 | setup_preset(spec, &alc882_presets[board_config]); | 4965 | setup_preset(spec, &alc882_presets[board_config]); |
4611 | 4966 | ||
4967 | if (board_config == ALC885_MACPRO) { | ||
4968 | alc882_gpio_mute(codec, 0, 0); | ||
4969 | alc882_gpio_mute(codec, 1, 0); | ||
4970 | } | ||
4971 | |||
4612 | spec->stream_name_analog = "ALC882 Analog"; | 4972 | spec->stream_name_analog = "ALC882 Analog"; |
4613 | spec->stream_analog_playback = &alc882_pcm_analog_playback; | 4973 | spec->stream_analog_playback = &alc882_pcm_analog_playback; |
4614 | spec->stream_analog_capture = &alc882_pcm_analog_capture; | 4974 | spec->stream_analog_capture = &alc882_pcm_analog_capture; |
@@ -4767,6 +5127,13 @@ static struct hda_channel_mode alc883_sixstack_modes[2] = { | |||
4767 | { 8, alc883_sixstack_ch8_init }, | 5127 | { 8, alc883_sixstack_ch8_init }, |
4768 | }; | 5128 | }; |
4769 | 5129 | ||
5130 | static struct hda_verb alc883_medion_eapd_verbs[] = { | ||
5131 | /* eanable EAPD on medion laptop */ | ||
5132 | {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, | ||
5133 | {0x20, AC_VERB_SET_PROC_COEF, 0x3070}, | ||
5134 | { } | ||
5135 | }; | ||
5136 | |||
4770 | /* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17 | 5137 | /* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17 |
4771 | * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b | 5138 | * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b |
4772 | */ | 5139 | */ |
@@ -4788,8 +5155,10 @@ static struct snd_kcontrol_new alc883_base_mixer[] = { | |||
4788 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), | 5155 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), |
4789 | HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), | 5156 | HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), |
4790 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | 5157 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), |
5158 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), | ||
4791 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | 5159 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), |
4792 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), | 5160 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), |
5161 | HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), | ||
4793 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), | 5162 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), |
4794 | HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), | 5163 | HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), |
4795 | HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), | 5164 | HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), |
@@ -4818,8 +5187,10 @@ static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = { | |||
4818 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), | 5187 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), |
4819 | HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), | 5188 | HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), |
4820 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | 5189 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), |
5190 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), | ||
4821 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | 5191 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), |
4822 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), | 5192 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), |
5193 | HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), | ||
4823 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), | 5194 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), |
4824 | HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), | 5195 | HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), |
4825 | HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), | 5196 | HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), |
@@ -4854,8 +5225,10 @@ static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = { | |||
4854 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), | 5225 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), |
4855 | HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), | 5226 | HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), |
4856 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | 5227 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), |
5228 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), | ||
4857 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | 5229 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), |
4858 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), | 5230 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), |
5231 | HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), | ||
4859 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), | 5232 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), |
4860 | HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), | 5233 | HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), |
4861 | HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), | 5234 | HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), |
@@ -4875,6 +5248,101 @@ static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = { | |||
4875 | { } /* end */ | 5248 | { } /* end */ |
4876 | }; | 5249 | }; |
4877 | 5250 | ||
5251 | static struct snd_kcontrol_new alc883_fivestack_mixer[] = { | ||
5252 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
5253 | HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), | ||
5254 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), | ||
5255 | HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT), | ||
5256 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), | ||
5257 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), | ||
5258 | HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x16, 1, 0x0, HDA_OUTPUT), | ||
5259 | HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT), | ||
5260 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), | ||
5261 | HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), | ||
5262 | HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), | ||
5263 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), | ||
5264 | HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), | ||
5265 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | ||
5266 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), | ||
5267 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | ||
5268 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), | ||
5269 | HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), | ||
5270 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), | ||
5271 | HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), | ||
5272 | HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), | ||
5273 | HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), | ||
5274 | HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), | ||
5275 | |||
5276 | { | ||
5277 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
5278 | /* .name = "Capture Source", */ | ||
5279 | .name = "Input Source", | ||
5280 | .count = 1, | ||
5281 | .info = alc883_mux_enum_info, | ||
5282 | .get = alc883_mux_enum_get, | ||
5283 | .put = alc883_mux_enum_put, | ||
5284 | }, | ||
5285 | { } /* end */ | ||
5286 | }; | ||
5287 | |||
5288 | static struct snd_kcontrol_new alc883_tagra_mixer[] = { | ||
5289 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
5290 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT), | ||
5291 | HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT), | ||
5292 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), | ||
5293 | HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), | ||
5294 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), | ||
5295 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), | ||
5296 | HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), | ||
5297 | HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), | ||
5298 | HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), | ||
5299 | HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), | ||
5300 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), | ||
5301 | HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), | ||
5302 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | ||
5303 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), | ||
5304 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | ||
5305 | HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), | ||
5306 | HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), | ||
5307 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), | ||
5308 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), | ||
5309 | { | ||
5310 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
5311 | /* .name = "Capture Source", */ | ||
5312 | .name = "Input Source", | ||
5313 | .count = 2, | ||
5314 | .info = alc883_mux_enum_info, | ||
5315 | .get = alc883_mux_enum_get, | ||
5316 | .put = alc883_mux_enum_put, | ||
5317 | }, | ||
5318 | { } /* end */ | ||
5319 | }; | ||
5320 | |||
5321 | static struct snd_kcontrol_new alc883_tagra_2ch_mixer[] = { | ||
5322 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
5323 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT), | ||
5324 | HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT), | ||
5325 | HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), | ||
5326 | HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), | ||
5327 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | ||
5328 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), | ||
5329 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | ||
5330 | HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), | ||
5331 | HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), | ||
5332 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), | ||
5333 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), | ||
5334 | { | ||
5335 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
5336 | /* .name = "Capture Source", */ | ||
5337 | .name = "Input Source", | ||
5338 | .count = 2, | ||
5339 | .info = alc883_mux_enum_info, | ||
5340 | .get = alc883_mux_enum_get, | ||
5341 | .put = alc883_mux_enum_put, | ||
5342 | }, | ||
5343 | { } /* end */ | ||
5344 | }; | ||
5345 | |||
4878 | static struct snd_kcontrol_new alc883_chmode_mixer[] = { | 5346 | static struct snd_kcontrol_new alc883_chmode_mixer[] = { |
4879 | { | 5347 | { |
4880 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 5348 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -4963,6 +5431,45 @@ static struct hda_verb alc883_init_verbs[] = { | |||
4963 | { } | 5431 | { } |
4964 | }; | 5432 | }; |
4965 | 5433 | ||
5434 | static struct hda_verb alc883_tagra_verbs[] = { | ||
5435 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
5436 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
5437 | |||
5438 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
5439 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
5440 | |||
5441 | {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */ | ||
5442 | {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */ | ||
5443 | {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ | ||
5444 | |||
5445 | {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, | ||
5446 | {0x01, AC_VERB_SET_GPIO_MASK, 0x03}, | ||
5447 | {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03}, | ||
5448 | {0x01, AC_VERB_SET_GPIO_DATA, 0x03}, | ||
5449 | |||
5450 | { } /* end */ | ||
5451 | }; | ||
5452 | |||
5453 | /* toggle speaker-output according to the hp-jack state */ | ||
5454 | static void alc883_tagra_automute(struct hda_codec *codec) | ||
5455 | { | ||
5456 | unsigned int present; | ||
5457 | |||
5458 | present = snd_hda_codec_read(codec, 0x14, 0, | ||
5459 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
5460 | snd_hda_codec_amp_update(codec, 0x1b, 0, HDA_OUTPUT, 0, | ||
5461 | 0x80, present ? 0x80 : 0); | ||
5462 | snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0, | ||
5463 | 0x80, present ? 0x80 : 0); | ||
5464 | snd_hda_codec_write(codec, 1, 0, AC_VERB_SET_GPIO_DATA, present ? 1 : 3); | ||
5465 | } | ||
5466 | |||
5467 | static void alc883_tagra_unsol_event(struct hda_codec *codec, unsigned int res) | ||
5468 | { | ||
5469 | if ((res >> 26) == ALC880_HP_EVENT) | ||
5470 | alc883_tagra_automute(codec); | ||
5471 | } | ||
5472 | |||
4966 | /* | 5473 | /* |
4967 | * generic initialization of ADC, input mixers and output mixers | 5474 | * generic initialization of ADC, input mixers and output mixers |
4968 | */ | 5475 | */ |
@@ -5057,32 +5564,42 @@ static struct snd_kcontrol_new alc883_capture_mixer[] = { | |||
5057 | /* | 5564 | /* |
5058 | * configuration and preset | 5565 | * configuration and preset |
5059 | */ | 5566 | */ |
5060 | static struct hda_board_config alc883_cfg_tbl[] = { | 5567 | static const char *alc883_models[ALC883_MODEL_LAST] = { |
5061 | { .modelname = "3stack-dig", .config = ALC883_3ST_2ch_DIG }, | 5568 | [ALC883_3ST_2ch_DIG] = "3stack-dig", |
5062 | { .modelname = "3stack-6ch-dig", .config = ALC883_3ST_6ch_DIG }, | 5569 | [ALC883_3ST_6ch_DIG] = "3stack-6ch-dig", |
5063 | { .pci_subvendor = 0x1019, .pci_subdevice = 0x6668, | 5570 | [ALC883_3ST_6ch] = "3stack-6ch", |
5064 | .config = ALC883_3ST_6ch_DIG }, /* ECS to Intel*/ | 5571 | [ALC883_6ST_DIG] = "6stack-dig", |
5065 | { .modelname = "3stack-6ch", .config = ALC883_3ST_6ch }, | 5572 | [ALC883_TARGA_DIG] = "targa-dig", |
5066 | { .pci_subvendor = 0x108e, .pci_subdevice = 0x534d, | 5573 | [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig", |
5067 | .config = ALC883_3ST_6ch }, | 5574 | [ALC888_DEMO_BOARD] = "6stack-dig-demo", |
5068 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xd601, | 5575 | [ALC883_ACER] = "acer", |
5069 | .config = ALC883_3ST_6ch }, /* D102GGC */ | 5576 | [ALC883_MEDION] = "medion", |
5070 | { .modelname = "6stack-dig", .config = ALC883_6ST_DIG }, | 5577 | [ALC883_LAPTOP_EAPD] = "laptop-eapd", |
5071 | { .pci_subvendor = 0x1462, .pci_subdevice = 0x6668, | 5578 | [ALC883_AUTO] = "auto", |
5072 | .config = ALC883_6ST_DIG }, /* MSI */ | 5579 | }; |
5073 | { .pci_subvendor = 0x1462, .pci_subdevice = 0x7280, | 5580 | |
5074 | .config = ALC883_6ST_DIG }, /* MSI K9A Platinum (MS-7280) */ | 5581 | static struct snd_pci_quirk alc883_cfg_tbl[] = { |
5075 | { .pci_subvendor = 0x105b, .pci_subdevice = 0x6668, | 5582 | SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC883_3ST_6ch_DIG), |
5076 | .config = ALC883_6ST_DIG }, /* Foxconn */ | 5583 | SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch), |
5077 | { .modelname = "6stack-dig-demo", .config = ALC888_DEMO_BOARD }, | 5584 | SND_PCI_QUIRK(0x1558, 0, "Clevo laptop", ALC883_LAPTOP_EAPD), |
5078 | { .modelname = "acer", .config = ALC883_ACER }, | 5585 | SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC883_6ST_DIG), |
5079 | { .pci_subvendor = 0x1025, .pci_subdevice = 0/*0x0102*/, | 5586 | SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG), |
5080 | .config = ALC883_ACER }, | 5587 | SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG), |
5081 | { .pci_subvendor = 0x1025, .pci_subdevice = 0x0102, | 5588 | SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG), |
5082 | .config = ALC883_ACER }, | 5589 | SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG), |
5083 | { .pci_subvendor = 0x1025, .pci_subdevice = 0x009f, | 5590 | SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG), |
5084 | .config = ALC883_ACER }, | 5591 | SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG), |
5085 | { .modelname = "auto", .config = ALC883_AUTO }, | 5592 | SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG), |
5593 | SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG), | ||
5594 | SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG), | ||
5595 | SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG), | ||
5596 | SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG), | ||
5597 | SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG), | ||
5598 | SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG), | ||
5599 | SND_PCI_QUIRK(0x1025, 0, "Acer laptop", ALC883_ACER), | ||
5600 | SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION), | ||
5601 | SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD), | ||
5602 | SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch), | ||
5086 | {} | 5603 | {} |
5087 | }; | 5604 | }; |
5088 | 5605 | ||
@@ -5139,6 +5656,35 @@ static struct alc_config_preset alc883_presets[] = { | |||
5139 | .channel_mode = alc883_sixstack_modes, | 5656 | .channel_mode = alc883_sixstack_modes, |
5140 | .input_mux = &alc883_capture_source, | 5657 | .input_mux = &alc883_capture_source, |
5141 | }, | 5658 | }, |
5659 | [ALC883_TARGA_DIG] = { | ||
5660 | .mixers = { alc883_tagra_mixer, alc883_chmode_mixer }, | ||
5661 | .init_verbs = { alc883_init_verbs, alc883_tagra_verbs}, | ||
5662 | .num_dacs = ARRAY_SIZE(alc883_dac_nids), | ||
5663 | .dac_nids = alc883_dac_nids, | ||
5664 | .dig_out_nid = ALC883_DIGOUT_NID, | ||
5665 | .num_adc_nids = ARRAY_SIZE(alc883_adc_nids), | ||
5666 | .adc_nids = alc883_adc_nids, | ||
5667 | .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes), | ||
5668 | .channel_mode = alc883_3ST_6ch_modes, | ||
5669 | .need_dac_fix = 1, | ||
5670 | .input_mux = &alc883_capture_source, | ||
5671 | .unsol_event = alc883_tagra_unsol_event, | ||
5672 | .init_hook = alc883_tagra_automute, | ||
5673 | }, | ||
5674 | [ALC883_TARGA_2ch_DIG] = { | ||
5675 | .mixers = { alc883_tagra_2ch_mixer}, | ||
5676 | .init_verbs = { alc883_init_verbs, alc883_tagra_verbs}, | ||
5677 | .num_dacs = ARRAY_SIZE(alc883_dac_nids), | ||
5678 | .dac_nids = alc883_dac_nids, | ||
5679 | .dig_out_nid = ALC883_DIGOUT_NID, | ||
5680 | .num_adc_nids = ARRAY_SIZE(alc883_adc_nids), | ||
5681 | .adc_nids = alc883_adc_nids, | ||
5682 | .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), | ||
5683 | .channel_mode = alc883_3ST_2ch_modes, | ||
5684 | .input_mux = &alc883_capture_source, | ||
5685 | .unsol_event = alc883_tagra_unsol_event, | ||
5686 | .init_hook = alc883_tagra_automute, | ||
5687 | }, | ||
5142 | [ALC888_DEMO_BOARD] = { | 5688 | [ALC888_DEMO_BOARD] = { |
5143 | .mixers = { alc883_base_mixer, alc883_chmode_mixer }, | 5689 | .mixers = { alc883_base_mixer, alc883_chmode_mixer }, |
5144 | .init_verbs = { alc883_init_verbs }, | 5690 | .init_verbs = { alc883_init_verbs }, |
@@ -5169,6 +5715,31 @@ static struct alc_config_preset alc883_presets[] = { | |||
5169 | .channel_mode = alc883_3ST_2ch_modes, | 5715 | .channel_mode = alc883_3ST_2ch_modes, |
5170 | .input_mux = &alc883_capture_source, | 5716 | .input_mux = &alc883_capture_source, |
5171 | }, | 5717 | }, |
5718 | [ALC883_MEDION] = { | ||
5719 | .mixers = { alc883_fivestack_mixer, | ||
5720 | alc883_chmode_mixer }, | ||
5721 | .init_verbs = { alc883_init_verbs, | ||
5722 | alc883_medion_eapd_verbs }, | ||
5723 | .num_dacs = ARRAY_SIZE(alc883_dac_nids), | ||
5724 | .dac_nids = alc883_dac_nids, | ||
5725 | .num_adc_nids = ARRAY_SIZE(alc883_adc_nids), | ||
5726 | .adc_nids = alc883_adc_nids, | ||
5727 | .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes), | ||
5728 | .channel_mode = alc883_sixstack_modes, | ||
5729 | .input_mux = &alc883_capture_source, | ||
5730 | }, | ||
5731 | [ALC883_LAPTOP_EAPD] = { | ||
5732 | .mixers = { alc883_base_mixer, | ||
5733 | alc883_chmode_mixer }, | ||
5734 | .init_verbs = { alc883_init_verbs, alc882_eapd_verbs }, | ||
5735 | .num_dacs = ARRAY_SIZE(alc883_dac_nids), | ||
5736 | .dac_nids = alc883_dac_nids, | ||
5737 | .num_adc_nids = ARRAY_SIZE(alc883_adc_nids), | ||
5738 | .adc_nids = alc883_adc_nids, | ||
5739 | .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), | ||
5740 | .channel_mode = alc883_3ST_2ch_modes, | ||
5741 | .input_mux = &alc883_capture_source, | ||
5742 | }, | ||
5172 | }; | 5743 | }; |
5173 | 5744 | ||
5174 | 5745 | ||
@@ -5277,8 +5848,10 @@ static int patch_alc883(struct hda_codec *codec) | |||
5277 | 5848 | ||
5278 | codec->spec = spec; | 5849 | codec->spec = spec; |
5279 | 5850 | ||
5280 | board_config = snd_hda_check_board_config(codec, alc883_cfg_tbl); | 5851 | board_config = snd_hda_check_board_config(codec, ALC883_MODEL_LAST, |
5281 | if (board_config < 0 || board_config >= ALC883_MODEL_LAST) { | 5852 | alc883_models, |
5853 | alc883_cfg_tbl); | ||
5854 | if (board_config < 0) { | ||
5282 | printk(KERN_INFO "hda_codec: Unknown model for ALC883, " | 5855 | printk(KERN_INFO "hda_codec: Unknown model for ALC883, " |
5283 | "trying auto-probe from BIOS...\n"); | 5856 | "trying auto-probe from BIOS...\n"); |
5284 | board_config = ALC883_AUTO; | 5857 | board_config = ALC883_AUTO; |
@@ -5355,6 +5928,24 @@ static struct snd_kcontrol_new alc262_base_mixer[] = { | |||
5355 | { } /* end */ | 5928 | { } /* end */ |
5356 | }; | 5929 | }; |
5357 | 5930 | ||
5931 | static struct snd_kcontrol_new alc262_hippo1_mixer[] = { | ||
5932 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
5933 | HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), | ||
5934 | HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), | ||
5935 | HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), | ||
5936 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), | ||
5937 | HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), | ||
5938 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | ||
5939 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | ||
5940 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), | ||
5941 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), | ||
5942 | /* HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT), | ||
5943 | HDA_CODEC_MUTE("PC Beelp Playback Switch", 0x0b, 0x05, HDA_INPUT), */ | ||
5944 | /*HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),*/ | ||
5945 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), | ||
5946 | { } /* end */ | ||
5947 | }; | ||
5948 | |||
5358 | static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = { | 5949 | static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = { |
5359 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | 5950 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), |
5360 | HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT), | 5951 | HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT), |
@@ -5377,6 +5968,30 @@ static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = { | |||
5377 | { } /* end */ | 5968 | { } /* end */ |
5378 | }; | 5969 | }; |
5379 | 5970 | ||
5971 | static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = { | ||
5972 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
5973 | HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT), | ||
5974 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), | ||
5975 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), | ||
5976 | HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), | ||
5977 | HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT), | ||
5978 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT), | ||
5979 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT), | ||
5980 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT), | ||
5981 | HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT), | ||
5982 | HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), | ||
5983 | HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), | ||
5984 | HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT), | ||
5985 | HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT), | ||
5986 | { } /* end */ | ||
5987 | }; | ||
5988 | |||
5989 | static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = { | ||
5990 | HDA_CODEC_VOLUME("Rear Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | ||
5991 | HDA_CODEC_MUTE("Rear Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | ||
5992 | { } /* end */ | ||
5993 | }; | ||
5994 | |||
5380 | #define alc262_capture_mixer alc882_capture_mixer | 5995 | #define alc262_capture_mixer alc882_capture_mixer |
5381 | #define alc262_capture_alt_mixer alc882_capture_alt_mixer | 5996 | #define alc262_capture_alt_mixer alc882_capture_alt_mixer |
5382 | 5997 | ||
@@ -5459,6 +6074,103 @@ static struct hda_verb alc262_init_verbs[] = { | |||
5459 | { } | 6074 | { } |
5460 | }; | 6075 | }; |
5461 | 6076 | ||
6077 | static struct hda_verb alc262_hippo_unsol_verbs[] = { | ||
6078 | {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, | ||
6079 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
6080 | {} | ||
6081 | }; | ||
6082 | |||
6083 | static struct hda_verb alc262_hippo1_unsol_verbs[] = { | ||
6084 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, | ||
6085 | {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
6086 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, | ||
6087 | |||
6088 | {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, | ||
6089 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
6090 | {} | ||
6091 | }; | ||
6092 | |||
6093 | /* mute/unmute internal speaker according to the hp jack and mute state */ | ||
6094 | static void alc262_hippo_automute(struct hda_codec *codec, int force) | ||
6095 | { | ||
6096 | struct alc_spec *spec = codec->spec; | ||
6097 | unsigned int mute; | ||
6098 | |||
6099 | if (force || ! spec->sense_updated) { | ||
6100 | unsigned int present; | ||
6101 | /* need to execute and sync at first */ | ||
6102 | snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0); | ||
6103 | present = snd_hda_codec_read(codec, 0x15, 0, | ||
6104 | AC_VERB_GET_PIN_SENSE, 0); | ||
6105 | spec->jack_present = (present & 0x80000000) != 0; | ||
6106 | spec->sense_updated = 1; | ||
6107 | } | ||
6108 | if (spec->jack_present) { | ||
6109 | /* mute internal speaker */ | ||
6110 | snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, | ||
6111 | 0x80, 0x80); | ||
6112 | snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, | ||
6113 | 0x80, 0x80); | ||
6114 | } else { | ||
6115 | /* unmute internal speaker if necessary */ | ||
6116 | mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0); | ||
6117 | snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, | ||
6118 | 0x80, mute & 0x80); | ||
6119 | mute = snd_hda_codec_amp_read(codec, 0x15, 1, HDA_OUTPUT, 0); | ||
6120 | snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, | ||
6121 | 0x80, mute & 0x80); | ||
6122 | } | ||
6123 | } | ||
6124 | |||
6125 | /* unsolicited event for HP jack sensing */ | ||
6126 | static void alc262_hippo_unsol_event(struct hda_codec *codec, | ||
6127 | unsigned int res) | ||
6128 | { | ||
6129 | if ((res >> 26) != ALC880_HP_EVENT) | ||
6130 | return; | ||
6131 | alc262_hippo_automute(codec, 1); | ||
6132 | } | ||
6133 | |||
6134 | static void alc262_hippo1_automute(struct hda_codec *codec, int force) | ||
6135 | { | ||
6136 | struct alc_spec *spec = codec->spec; | ||
6137 | unsigned int mute; | ||
6138 | |||
6139 | if (force || ! spec->sense_updated) { | ||
6140 | unsigned int present; | ||
6141 | /* need to execute and sync at first */ | ||
6142 | snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0); | ||
6143 | present = snd_hda_codec_read(codec, 0x1b, 0, | ||
6144 | AC_VERB_GET_PIN_SENSE, 0); | ||
6145 | spec->jack_present = (present & 0x80000000) != 0; | ||
6146 | spec->sense_updated = 1; | ||
6147 | } | ||
6148 | if (spec->jack_present) { | ||
6149 | /* mute internal speaker */ | ||
6150 | snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, | ||
6151 | 0x80, 0x80); | ||
6152 | snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, | ||
6153 | 0x80, 0x80); | ||
6154 | } else { | ||
6155 | /* unmute internal speaker if necessary */ | ||
6156 | mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0); | ||
6157 | snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, | ||
6158 | 0x80, mute & 0x80); | ||
6159 | mute = snd_hda_codec_amp_read(codec, 0x1b, 1, HDA_OUTPUT, 0); | ||
6160 | snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, | ||
6161 | 0x80, mute & 0x80); | ||
6162 | } | ||
6163 | } | ||
6164 | |||
6165 | /* unsolicited event for HP jack sensing */ | ||
6166 | static void alc262_hippo1_unsol_event(struct hda_codec *codec, | ||
6167 | unsigned int res) | ||
6168 | { | ||
6169 | if ((res >> 26) != ALC880_HP_EVENT) | ||
6170 | return; | ||
6171 | alc262_hippo1_automute(codec, 1); | ||
6172 | } | ||
6173 | |||
5462 | /* | 6174 | /* |
5463 | * fujitsu model | 6175 | * fujitsu model |
5464 | * 0x14 = headphone/spdif-out, 0x15 = internal speaker | 6176 | * 0x14 = headphone/spdif-out, 0x15 = internal speaker |
@@ -5809,6 +6521,100 @@ static struct hda_verb alc262_HP_BPC_init_verbs[] = { | |||
5809 | { } | 6521 | { } |
5810 | }; | 6522 | }; |
5811 | 6523 | ||
6524 | static struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = { | ||
6525 | /* | ||
6526 | * Unmute ADC0-2 and set the default input to mic-in | ||
6527 | */ | ||
6528 | {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
6529 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
6530 | {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
6531 | {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
6532 | {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
6533 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
6534 | |||
6535 | /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback | ||
6536 | * mixer widget | ||
6537 | * Note: PASD motherboards uses the Line In 2 as the input for front | ||
6538 | * panel mic (mic 2) | ||
6539 | */ | ||
6540 | /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ | ||
6541 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
6542 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
6543 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, | ||
6544 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, | ||
6545 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, | ||
6546 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)}, | ||
6547 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(6)}, | ||
6548 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(7)}, | ||
6549 | /* | ||
6550 | * Set up output mixers (0x0c - 0x0e) | ||
6551 | */ | ||
6552 | /* set vol=0 to output mixers */ | ||
6553 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
6554 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
6555 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
6556 | |||
6557 | /* set up input amps for analog loopback */ | ||
6558 | /* Amp Indices: DAC = 0, mixer = 1 */ | ||
6559 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
6560 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
6561 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
6562 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
6563 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
6564 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
6565 | |||
6566 | |||
6567 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP */ | ||
6568 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Mono */ | ||
6569 | {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* rear MIC */ | ||
6570 | {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* Line in */ | ||
6571 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */ | ||
6572 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Line out */ | ||
6573 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD in */ | ||
6574 | |||
6575 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, | ||
6576 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, | ||
6577 | |||
6578 | {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
6579 | {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
6580 | |||
6581 | /* {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, */ | ||
6582 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, | ||
6583 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, | ||
6584 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, | ||
6585 | {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, | ||
6586 | {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, | ||
6587 | |||
6588 | /* FIXME: use matrix-type input source selection */ | ||
6589 | /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ | ||
6590 | /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ | ||
6591 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, /*rear MIC*/ | ||
6592 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, /*Line in*/ | ||
6593 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, /*F MIC*/ | ||
6594 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, /*Front*/ | ||
6595 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, /*CD*/ | ||
6596 | /* {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */ | ||
6597 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, /*HP*/ | ||
6598 | /* Input mixer2 */ | ||
6599 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | ||
6600 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, | ||
6601 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, | ||
6602 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, | ||
6603 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, | ||
6604 | /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */ | ||
6605 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, | ||
6606 | /* Input mixer3 */ | ||
6607 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | ||
6608 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, | ||
6609 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, | ||
6610 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, | ||
6611 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, | ||
6612 | /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */ | ||
6613 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, | ||
6614 | |||
6615 | { } | ||
6616 | }; | ||
6617 | |||
5812 | /* pcm configuration: identiacal with ALC880 */ | 6618 | /* pcm configuration: identiacal with ALC880 */ |
5813 | #define alc262_pcm_analog_playback alc880_pcm_analog_playback | 6619 | #define alc262_pcm_analog_playback alc880_pcm_analog_playback |
5814 | #define alc262_pcm_analog_capture alc880_pcm_analog_capture | 6620 | #define alc262_pcm_analog_capture alc880_pcm_analog_capture |
@@ -5866,26 +6672,35 @@ static void alc262_auto_init(struct hda_codec *codec) | |||
5866 | /* | 6672 | /* |
5867 | * configuration and preset | 6673 | * configuration and preset |
5868 | */ | 6674 | */ |
5869 | static struct hda_board_config alc262_cfg_tbl[] = { | 6675 | static const char *alc262_models[ALC262_MODEL_LAST] = { |
5870 | { .modelname = "basic", .config = ALC262_BASIC }, | 6676 | [ALC262_BASIC] = "basic", |
5871 | { .modelname = "fujitsu", .config = ALC262_FUJITSU }, | 6677 | [ALC262_HIPPO] = "hippo", |
5872 | { .pci_subvendor = 0x10cf, .pci_subdevice = 0x1397, | 6678 | [ALC262_HIPPO_1] = "hippo_1", |
5873 | .config = ALC262_FUJITSU }, | 6679 | [ALC262_FUJITSU] = "fujitsu", |
5874 | { .modelname = "hp-bpc", .config = ALC262_HP_BPC }, | 6680 | [ALC262_HP_BPC] = "hp-bpc", |
5875 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x280c, | 6681 | [ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000", |
5876 | .config = ALC262_HP_BPC }, /* xw4400 */ | 6682 | [ALC262_BENQ_ED8] = "benq", |
5877 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x2801, | 6683 | [ALC262_AUTO] = "auto", |
5878 | .config = ALC262_HP_BPC }, /* q965 */ | 6684 | }; |
5879 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x3014, | 6685 | |
5880 | .config = ALC262_HP_BPC }, /* xw6400 */ | 6686 | static struct snd_pci_quirk alc262_cfg_tbl[] = { |
5881 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x3015, | 6687 | SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO), |
5882 | .config = ALC262_HP_BPC }, /* xw8400 */ | 6688 | SND_PCI_QUIRK(0x103c, 0x12fe, "HP xw9400", ALC262_HP_BPC), |
5883 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x12fe, | 6689 | SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC), |
5884 | .config = ALC262_HP_BPC }, /* xw9400 */ | 6690 | SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC), |
5885 | { .modelname = "benq", .config = ALC262_BENQ_ED8 }, | 6691 | SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC), |
5886 | { .pci_subvendor = 0x17ff, .pci_subdevice = 0x0560, | 6692 | SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL), |
5887 | .config = ALC262_BENQ_ED8 }, | 6693 | SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL), |
5888 | { .modelname = "auto", .config = ALC262_AUTO }, | 6694 | SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL), |
6695 | SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL), | ||
6696 | SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF), | ||
6697 | SND_PCI_QUIRK(0x103c, 0x2803, "HP D7000", ALC262_HP_BPC_D7000_WF), | ||
6698 | SND_PCI_QUIRK(0x103c, 0x2805, "HP D7000", ALC262_HP_BPC_D7000_WF), | ||
6699 | SND_PCI_QUIRK(0x103c, 0x2807, "HP D7000", ALC262_HP_BPC_D7000_WF), | ||
6700 | SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO), | ||
6701 | SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU), | ||
6702 | SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1), | ||
6703 | SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8), | ||
5889 | {} | 6704 | {} |
5890 | }; | 6705 | }; |
5891 | 6706 | ||
@@ -5900,6 +6715,30 @@ static struct alc_config_preset alc262_presets[] = { | |||
5900 | .channel_mode = alc262_modes, | 6715 | .channel_mode = alc262_modes, |
5901 | .input_mux = &alc262_capture_source, | 6716 | .input_mux = &alc262_capture_source, |
5902 | }, | 6717 | }, |
6718 | [ALC262_HIPPO] = { | ||
6719 | .mixers = { alc262_base_mixer }, | ||
6720 | .init_verbs = { alc262_init_verbs, alc262_hippo_unsol_verbs}, | ||
6721 | .num_dacs = ARRAY_SIZE(alc262_dac_nids), | ||
6722 | .dac_nids = alc262_dac_nids, | ||
6723 | .hp_nid = 0x03, | ||
6724 | .dig_out_nid = ALC262_DIGOUT_NID, | ||
6725 | .num_channel_mode = ARRAY_SIZE(alc262_modes), | ||
6726 | .channel_mode = alc262_modes, | ||
6727 | .input_mux = &alc262_capture_source, | ||
6728 | .unsol_event = alc262_hippo_unsol_event, | ||
6729 | }, | ||
6730 | [ALC262_HIPPO_1] = { | ||
6731 | .mixers = { alc262_hippo1_mixer }, | ||
6732 | .init_verbs = { alc262_init_verbs, alc262_hippo1_unsol_verbs}, | ||
6733 | .num_dacs = ARRAY_SIZE(alc262_dac_nids), | ||
6734 | .dac_nids = alc262_dac_nids, | ||
6735 | .hp_nid = 0x02, | ||
6736 | .dig_out_nid = ALC262_DIGOUT_NID, | ||
6737 | .num_channel_mode = ARRAY_SIZE(alc262_modes), | ||
6738 | .channel_mode = alc262_modes, | ||
6739 | .input_mux = &alc262_capture_source, | ||
6740 | .unsol_event = alc262_hippo1_unsol_event, | ||
6741 | }, | ||
5903 | [ALC262_FUJITSU] = { | 6742 | [ALC262_FUJITSU] = { |
5904 | .mixers = { alc262_fujitsu_mixer }, | 6743 | .mixers = { alc262_fujitsu_mixer }, |
5905 | .init_verbs = { alc262_init_verbs, alc262_fujitsu_unsol_verbs }, | 6744 | .init_verbs = { alc262_init_verbs, alc262_fujitsu_unsol_verbs }, |
@@ -5922,6 +6761,27 @@ static struct alc_config_preset alc262_presets[] = { | |||
5922 | .channel_mode = alc262_modes, | 6761 | .channel_mode = alc262_modes, |
5923 | .input_mux = &alc262_HP_capture_source, | 6762 | .input_mux = &alc262_HP_capture_source, |
5924 | }, | 6763 | }, |
6764 | [ALC262_HP_BPC_D7000_WF] = { | ||
6765 | .mixers = { alc262_HP_BPC_WildWest_mixer }, | ||
6766 | .init_verbs = { alc262_HP_BPC_WildWest_init_verbs }, | ||
6767 | .num_dacs = ARRAY_SIZE(alc262_dac_nids), | ||
6768 | .dac_nids = alc262_dac_nids, | ||
6769 | .hp_nid = 0x03, | ||
6770 | .num_channel_mode = ARRAY_SIZE(alc262_modes), | ||
6771 | .channel_mode = alc262_modes, | ||
6772 | .input_mux = &alc262_HP_capture_source, | ||
6773 | }, | ||
6774 | [ALC262_HP_BPC_D7000_WL] = { | ||
6775 | .mixers = { alc262_HP_BPC_WildWest_mixer, | ||
6776 | alc262_HP_BPC_WildWest_option_mixer }, | ||
6777 | .init_verbs = { alc262_HP_BPC_WildWest_init_verbs }, | ||
6778 | .num_dacs = ARRAY_SIZE(alc262_dac_nids), | ||
6779 | .dac_nids = alc262_dac_nids, | ||
6780 | .hp_nid = 0x03, | ||
6781 | .num_channel_mode = ARRAY_SIZE(alc262_modes), | ||
6782 | .channel_mode = alc262_modes, | ||
6783 | .input_mux = &alc262_HP_capture_source, | ||
6784 | }, | ||
5925 | [ALC262_BENQ_ED8] = { | 6785 | [ALC262_BENQ_ED8] = { |
5926 | .mixers = { alc262_base_mixer }, | 6786 | .mixers = { alc262_base_mixer }, |
5927 | .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs }, | 6787 | .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs }, |
@@ -5940,7 +6800,7 @@ static int patch_alc262(struct hda_codec *codec) | |||
5940 | int board_config; | 6800 | int board_config; |
5941 | int err; | 6801 | int err; |
5942 | 6802 | ||
5943 | spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); | 6803 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); |
5944 | if (spec == NULL) | 6804 | if (spec == NULL) |
5945 | return -ENOMEM; | 6805 | return -ENOMEM; |
5946 | 6806 | ||
@@ -5956,9 +6816,11 @@ static int patch_alc262(struct hda_codec *codec) | |||
5956 | } | 6816 | } |
5957 | #endif | 6817 | #endif |
5958 | 6818 | ||
5959 | board_config = snd_hda_check_board_config(codec, alc262_cfg_tbl); | 6819 | board_config = snd_hda_check_board_config(codec, ALC262_MODEL_LAST, |
5960 | 6820 | alc262_models, | |
5961 | if (board_config < 0 || board_config >= ALC262_MODEL_LAST) { | 6821 | alc262_cfg_tbl); |
6822 | |||
6823 | if (board_config < 0) { | ||
5962 | printk(KERN_INFO "hda_codec: Unknown model for ALC262, " | 6824 | printk(KERN_INFO "hda_codec: Unknown model for ALC262, " |
5963 | "trying auto-probe from BIOS...\n"); | 6825 | "trying auto-probe from BIOS...\n"); |
5964 | board_config = ALC262_AUTO; | 6826 | board_config = ALC262_AUTO; |
@@ -6078,6 +6940,44 @@ static struct hda_channel_mode alc861_uniwill_m31_modes[2] = { | |||
6078 | { 4, alc861_uniwill_m31_ch4_init }, | 6940 | { 4, alc861_uniwill_m31_ch4_init }, |
6079 | }; | 6941 | }; |
6080 | 6942 | ||
6943 | /* Set mic1 and line-in as input and unmute the mixer */ | ||
6944 | static struct hda_verb alc861_asus_ch2_init[] = { | ||
6945 | /* set pin widget 1Ah (line in) for input */ | ||
6946 | { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | ||
6947 | /* set pin widget 18h (mic1/2) for input, for mic also enable the vref */ | ||
6948 | { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | ||
6949 | |||
6950 | { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c }, | ||
6951 | #if 0 | ||
6952 | { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/ | ||
6953 | { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/ | ||
6954 | #endif | ||
6955 | { } /* end */ | ||
6956 | }; | ||
6957 | /* Set mic1 nad line-in as output and mute mixer */ | ||
6958 | static struct hda_verb alc861_asus_ch6_init[] = { | ||
6959 | /* set pin widget 1Ah (line in) for output (Back Surround)*/ | ||
6960 | { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
6961 | /* { 0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */ | ||
6962 | /* set pin widget 18h (mic1) for output (CLFE)*/ | ||
6963 | { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
6964 | /* { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */ | ||
6965 | { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 }, | ||
6966 | { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 }, | ||
6967 | |||
6968 | { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 }, | ||
6969 | #if 0 | ||
6970 | { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/ | ||
6971 | { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/ | ||
6972 | #endif | ||
6973 | { } /* end */ | ||
6974 | }; | ||
6975 | |||
6976 | static struct hda_channel_mode alc861_asus_modes[2] = { | ||
6977 | { 2, alc861_asus_ch2_init }, | ||
6978 | { 6, alc861_asus_ch6_init }, | ||
6979 | }; | ||
6980 | |||
6081 | /* patch-ALC861 */ | 6981 | /* patch-ALC861 */ |
6082 | 6982 | ||
6083 | static struct snd_kcontrol_new alc861_base_mixer[] = { | 6983 | static struct snd_kcontrol_new alc861_base_mixer[] = { |
@@ -6154,7 +7054,29 @@ static struct snd_kcontrol_new alc861_3ST_mixer[] = { | |||
6154 | .private_value = ARRAY_SIZE(alc861_threestack_modes), | 7054 | .private_value = ARRAY_SIZE(alc861_threestack_modes), |
6155 | }, | 7055 | }, |
6156 | { } /* end */ | 7056 | { } /* end */ |
6157 | }; | 7057 | }; |
7058 | |||
7059 | static struct snd_kcontrol_new alc861_toshiba_mixer[] = { | ||
7060 | /* output mixer control */ | ||
7061 | HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT), | ||
7062 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT), | ||
7063 | HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT), | ||
7064 | |||
7065 | /*Capture mixer control */ | ||
7066 | HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), | ||
7067 | HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), | ||
7068 | { | ||
7069 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
7070 | .name = "Capture Source", | ||
7071 | .count = 1, | ||
7072 | .info = alc_mux_enum_info, | ||
7073 | .get = alc_mux_enum_get, | ||
7074 | .put = alc_mux_enum_put, | ||
7075 | }, | ||
7076 | |||
7077 | { } /* end */ | ||
7078 | }; | ||
7079 | |||
6158 | static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = { | 7080 | static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = { |
6159 | /* output mixer control */ | 7081 | /* output mixer control */ |
6160 | HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT), | 7082 | HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT), |
@@ -6196,7 +7118,58 @@ static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = { | |||
6196 | }, | 7118 | }, |
6197 | { } /* end */ | 7119 | { } /* end */ |
6198 | }; | 7120 | }; |
6199 | 7121 | ||
7122 | static struct snd_kcontrol_new alc861_asus_mixer[] = { | ||
7123 | /* output mixer control */ | ||
7124 | HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT), | ||
7125 | HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT), | ||
7126 | HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT), | ||
7127 | HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT), | ||
7128 | HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), | ||
7129 | |||
7130 | /* Input mixer control */ | ||
7131 | HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT), | ||
7132 | HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), | ||
7133 | HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT), | ||
7134 | HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT), | ||
7135 | HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT), | ||
7136 | HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT), | ||
7137 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT), | ||
7138 | HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT), | ||
7139 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT), | ||
7140 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_OUTPUT), /* was HDA_INPUT (why?) */ | ||
7141 | |||
7142 | /* Capture mixer control */ | ||
7143 | HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), | ||
7144 | HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), | ||
7145 | { | ||
7146 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
7147 | .name = "Capture Source", | ||
7148 | .count = 1, | ||
7149 | .info = alc_mux_enum_info, | ||
7150 | .get = alc_mux_enum_get, | ||
7151 | .put = alc_mux_enum_put, | ||
7152 | }, | ||
7153 | { | ||
7154 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
7155 | .name = "Channel Mode", | ||
7156 | .info = alc_ch_mode_info, | ||
7157 | .get = alc_ch_mode_get, | ||
7158 | .put = alc_ch_mode_put, | ||
7159 | .private_value = ARRAY_SIZE(alc861_asus_modes), | ||
7160 | }, | ||
7161 | { } | ||
7162 | }; | ||
7163 | |||
7164 | /* additional mixer */ | ||
7165 | static struct snd_kcontrol_new alc861_asus_laptop_mixer[] = { | ||
7166 | HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT), | ||
7167 | HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT), | ||
7168 | HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x23, 0x0, HDA_OUTPUT), | ||
7169 | HDA_CODEC_MUTE("PC Beep Playback Switch", 0x23, 0x0, HDA_OUTPUT), | ||
7170 | { } | ||
7171 | }; | ||
7172 | |||
6200 | /* | 7173 | /* |
6201 | * generic initialization of ADC, input mixers and output mixers | 7174 | * generic initialization of ADC, input mixers and output mixers |
6202 | */ | 7175 | */ |
@@ -6217,7 +7190,7 @@ static struct hda_verb alc861_base_init_verbs[] = { | |||
6217 | /* port-E for HP out (front panel) */ | 7190 | /* port-E for HP out (front panel) */ |
6218 | { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, | 7191 | { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, |
6219 | /* route front PCM to HP */ | 7192 | /* route front PCM to HP */ |
6220 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x01 }, | 7193 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, |
6221 | /* port-F for mic-in (front panel) with vref */ | 7194 | /* port-F for mic-in (front panel) with vref */ |
6222 | { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | 7195 | { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, |
6223 | /* port-G for CLFE (rear panel) */ | 7196 | /* port-G for CLFE (rear panel) */ |
@@ -6281,7 +7254,7 @@ static struct hda_verb alc861_threestack_init_verbs[] = { | |||
6281 | /* port-E for HP out (front panel) */ | 7254 | /* port-E for HP out (front panel) */ |
6282 | { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, | 7255 | { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, |
6283 | /* route front PCM to HP */ | 7256 | /* route front PCM to HP */ |
6284 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x01 }, | 7257 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, |
6285 | /* port-F for mic-in (front panel) with vref */ | 7258 | /* port-F for mic-in (front panel) with vref */ |
6286 | { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | 7259 | { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, |
6287 | /* port-G for CLFE (rear panel) */ | 7260 | /* port-G for CLFE (rear panel) */ |
@@ -6341,7 +7314,7 @@ static struct hda_verb alc861_uniwill_m31_init_verbs[] = { | |||
6341 | /* port-E for HP out (front panel) */ | 7314 | /* port-E for HP out (front panel) */ |
6342 | { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, // this has to be set to VREF80 | 7315 | { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, // this has to be set to VREF80 |
6343 | /* route front PCM to HP */ | 7316 | /* route front PCM to HP */ |
6344 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x01 }, | 7317 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, |
6345 | /* port-F for mic-in (front panel) with vref */ | 7318 | /* port-F for mic-in (front panel) with vref */ |
6346 | { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | 7319 | { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, |
6347 | /* port-G for CLFE (rear panel) */ | 7320 | /* port-G for CLFE (rear panel) */ |
@@ -6385,6 +7358,74 @@ static struct hda_verb alc861_uniwill_m31_init_verbs[] = { | |||
6385 | { } | 7358 | { } |
6386 | }; | 7359 | }; |
6387 | 7360 | ||
7361 | static struct hda_verb alc861_asus_init_verbs[] = { | ||
7362 | /* | ||
7363 | * Unmute ADC0 and set the default input to mic-in | ||
7364 | */ | ||
7365 | /* port-A for surround (rear panel) | according to codec#0 this is the HP jack*/ | ||
7366 | { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* was 0x00 */ | ||
7367 | /* route front PCM to HP */ | ||
7368 | { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x01 }, | ||
7369 | /* port-B for mic-in (rear panel) with vref */ | ||
7370 | { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | ||
7371 | /* port-C for line-in (rear panel) */ | ||
7372 | { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | ||
7373 | /* port-D for Front */ | ||
7374 | { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
7375 | { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 }, | ||
7376 | /* port-E for HP out (front panel) */ | ||
7377 | { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, /* this has to be set to VREF80 */ | ||
7378 | /* route front PCM to HP */ | ||
7379 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, | ||
7380 | /* port-F for mic-in (front panel) with vref */ | ||
7381 | { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | ||
7382 | /* port-G for CLFE (rear panel) */ | ||
7383 | { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
7384 | /* port-H for side (rear panel) */ | ||
7385 | { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
7386 | /* CD-in */ | ||
7387 | { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | ||
7388 | /* route front mic to ADC1*/ | ||
7389 | {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
7390 | {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
7391 | /* Unmute DAC0~3 & spdif out*/ | ||
7392 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
7393 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
7394 | {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
7395 | {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
7396 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
7397 | /* Unmute Mixer 14 (mic) 1c (Line in)*/ | ||
7398 | {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
7399 | {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
7400 | {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
7401 | {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
7402 | |||
7403 | /* Unmute Stereo Mixer 15 */ | ||
7404 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
7405 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
7406 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, | ||
7407 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c }, /* Output 0~12 step */ | ||
7408 | |||
7409 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
7410 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
7411 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
7412 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
7413 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
7414 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
7415 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
7416 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
7417 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, /* hp used DAC 3 (Front) */ | ||
7418 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, | ||
7419 | { } | ||
7420 | }; | ||
7421 | |||
7422 | /* additional init verbs for ASUS laptops */ | ||
7423 | static struct hda_verb alc861_asus_laptop_init_verbs[] = { | ||
7424 | { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x45 }, /* HP-out */ | ||
7425 | { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, /* mute line-in */ | ||
7426 | { } | ||
7427 | }; | ||
7428 | |||
6388 | /* | 7429 | /* |
6389 | * generic initialization of ADC, input mixers and output mixers | 7430 | * generic initialization of ADC, input mixers and output mixers |
6390 | */ | 7431 | */ |
@@ -6437,6 +7478,39 @@ static struct hda_verb alc861_auto_init_verbs[] = { | |||
6437 | { } | 7478 | { } |
6438 | }; | 7479 | }; |
6439 | 7480 | ||
7481 | static struct hda_verb alc861_toshiba_init_verbs[] = { | ||
7482 | {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, | ||
7483 | |||
7484 | { } | ||
7485 | }; | ||
7486 | |||
7487 | /* toggle speaker-output according to the hp-jack state */ | ||
7488 | static void alc861_toshiba_automute(struct hda_codec *codec) | ||
7489 | { | ||
7490 | unsigned int present; | ||
7491 | |||
7492 | present = snd_hda_codec_read(codec, 0x0f, 0, | ||
7493 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
7494 | snd_hda_codec_amp_update(codec, 0x16, 0, HDA_INPUT, 0, | ||
7495 | 0x80, present ? 0x80 : 0); | ||
7496 | snd_hda_codec_amp_update(codec, 0x16, 1, HDA_INPUT, 0, | ||
7497 | 0x80, present ? 0x80 : 0); | ||
7498 | snd_hda_codec_amp_update(codec, 0x1a, 0, HDA_INPUT, 3, | ||
7499 | 0x80, present ? 0 : 0x80); | ||
7500 | snd_hda_codec_amp_update(codec, 0x1a, 1, HDA_INPUT, 3, | ||
7501 | 0x80, present ? 0 : 0x80); | ||
7502 | } | ||
7503 | |||
7504 | static void alc861_toshiba_unsol_event(struct hda_codec *codec, | ||
7505 | unsigned int res) | ||
7506 | { | ||
7507 | /* Looks like the unsol event is incompatible with the standard | ||
7508 | * definition. 6bit tag is placed at 26 bit! | ||
7509 | */ | ||
7510 | if ((res >> 26) == ALC880_HP_EVENT) | ||
7511 | alc861_toshiba_automute(codec); | ||
7512 | } | ||
7513 | |||
6440 | /* pcm configuration: identiacal with ALC880 */ | 7514 | /* pcm configuration: identiacal with ALC880 */ |
6441 | #define alc861_pcm_analog_playback alc880_pcm_analog_playback | 7515 | #define alc861_pcm_analog_playback alc880_pcm_analog_playback |
6442 | #define alc861_pcm_analog_capture alc880_pcm_analog_capture | 7516 | #define alc861_pcm_analog_capture alc880_pcm_analog_capture |
@@ -6710,19 +7784,29 @@ static void alc861_auto_init(struct hda_codec *codec) | |||
6710 | /* | 7784 | /* |
6711 | * configuration and preset | 7785 | * configuration and preset |
6712 | */ | 7786 | */ |
6713 | static struct hda_board_config alc861_cfg_tbl[] = { | 7787 | static const char *alc861_models[ALC861_MODEL_LAST] = { |
6714 | { .modelname = "3stack", .config = ALC861_3ST }, | 7788 | [ALC861_3ST] = "3stack", |
6715 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xd600, | 7789 | [ALC660_3ST] = "3stack-660", |
6716 | .config = ALC861_3ST }, | 7790 | [ALC861_3ST_DIG] = "3stack-dig", |
6717 | { .modelname = "3stack-660", .config = ALC660_3ST }, | 7791 | [ALC861_6ST_DIG] = "6stack-dig", |
6718 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x81e7, | 7792 | [ALC861_UNIWILL_M31] = "uniwill-m31", |
6719 | .config = ALC660_3ST }, | 7793 | [ALC861_TOSHIBA] = "toshiba", |
6720 | { .modelname = "3stack-dig", .config = ALC861_3ST_DIG }, | 7794 | [ALC861_ASUS] = "asus", |
6721 | { .modelname = "6stack-dig", .config = ALC861_6ST_DIG }, | 7795 | [ALC861_ASUS_LAPTOP] = "asus-laptop", |
6722 | { .modelname = "uniwill-m31", .config = ALC861_UNIWILL_M31}, | 7796 | [ALC861_AUTO] = "auto", |
6723 | { .pci_subvendor = 0x1584, .pci_subdevice = 0x9072, | 7797 | }; |
6724 | .config = ALC861_UNIWILL_M31 }, | 7798 | |
6725 | { .modelname = "auto", .config = ALC861_AUTO }, | 7799 | static struct snd_pci_quirk alc861_cfg_tbl[] = { |
7800 | SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST), | ||
7801 | SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP), | ||
7802 | SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP), | ||
7803 | SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS), | ||
7804 | SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660_3ST), | ||
7805 | SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA), | ||
7806 | SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), | ||
7807 | SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31), | ||
7808 | SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31), | ||
7809 | SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST), | ||
6726 | {} | 7810 | {} |
6727 | }; | 7811 | }; |
6728 | 7812 | ||
@@ -6789,8 +7873,48 @@ static struct alc_config_preset alc861_presets[] = { | |||
6789 | .adc_nids = alc861_adc_nids, | 7873 | .adc_nids = alc861_adc_nids, |
6790 | .input_mux = &alc861_capture_source, | 7874 | .input_mux = &alc861_capture_source, |
6791 | }, | 7875 | }, |
6792 | 7876 | [ALC861_TOSHIBA] = { | |
6793 | }; | 7877 | .mixers = { alc861_toshiba_mixer }, |
7878 | .init_verbs = { alc861_base_init_verbs, alc861_toshiba_init_verbs }, | ||
7879 | .num_dacs = ARRAY_SIZE(alc861_dac_nids), | ||
7880 | .dac_nids = alc861_dac_nids, | ||
7881 | .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), | ||
7882 | .channel_mode = alc883_3ST_2ch_modes, | ||
7883 | .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), | ||
7884 | .adc_nids = alc861_adc_nids, | ||
7885 | .input_mux = &alc861_capture_source, | ||
7886 | .unsol_event = alc861_toshiba_unsol_event, | ||
7887 | .init_hook = alc861_toshiba_automute, | ||
7888 | }, | ||
7889 | [ALC861_ASUS] = { | ||
7890 | .mixers = { alc861_asus_mixer }, | ||
7891 | .init_verbs = { alc861_asus_init_verbs }, | ||
7892 | .num_dacs = ARRAY_SIZE(alc861_dac_nids), | ||
7893 | .dac_nids = alc861_dac_nids, | ||
7894 | .dig_out_nid = ALC861_DIGOUT_NID, | ||
7895 | .num_channel_mode = ARRAY_SIZE(alc861_asus_modes), | ||
7896 | .channel_mode = alc861_asus_modes, | ||
7897 | .need_dac_fix = 1, | ||
7898 | .hp_nid = 0x06, | ||
7899 | .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), | ||
7900 | .adc_nids = alc861_adc_nids, | ||
7901 | .input_mux = &alc861_capture_source, | ||
7902 | }, | ||
7903 | [ALC861_ASUS_LAPTOP] = { | ||
7904 | .mixers = { alc861_toshiba_mixer, alc861_asus_laptop_mixer }, | ||
7905 | .init_verbs = { alc861_asus_init_verbs, | ||
7906 | alc861_asus_laptop_init_verbs }, | ||
7907 | .num_dacs = ARRAY_SIZE(alc861_dac_nids), | ||
7908 | .dac_nids = alc861_dac_nids, | ||
7909 | .dig_out_nid = ALC861_DIGOUT_NID, | ||
7910 | .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), | ||
7911 | .channel_mode = alc883_3ST_2ch_modes, | ||
7912 | .need_dac_fix = 1, | ||
7913 | .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), | ||
7914 | .adc_nids = alc861_adc_nids, | ||
7915 | .input_mux = &alc861_capture_source, | ||
7916 | }, | ||
7917 | }; | ||
6794 | 7918 | ||
6795 | 7919 | ||
6796 | static int patch_alc861(struct hda_codec *codec) | 7920 | static int patch_alc861(struct hda_codec *codec) |
@@ -6799,15 +7923,17 @@ static int patch_alc861(struct hda_codec *codec) | |||
6799 | int board_config; | 7923 | int board_config; |
6800 | int err; | 7924 | int err; |
6801 | 7925 | ||
6802 | spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); | 7926 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); |
6803 | if (spec == NULL) | 7927 | if (spec == NULL) |
6804 | return -ENOMEM; | 7928 | return -ENOMEM; |
6805 | 7929 | ||
6806 | codec->spec = spec; | 7930 | codec->spec = spec; |
6807 | 7931 | ||
6808 | board_config = snd_hda_check_board_config(codec, alc861_cfg_tbl); | 7932 | board_config = snd_hda_check_board_config(codec, ALC861_MODEL_LAST, |
7933 | alc861_models, | ||
7934 | alc861_cfg_tbl); | ||
6809 | 7935 | ||
6810 | if (board_config < 0 || board_config >= ALC861_MODEL_LAST) { | 7936 | if (board_config < 0) { |
6811 | printk(KERN_INFO "hda_codec: Unknown model for ALC861, " | 7937 | printk(KERN_INFO "hda_codec: Unknown model for ALC861, " |
6812 | "trying auto-probe from BIOS...\n"); | 7938 | "trying auto-probe from BIOS...\n"); |
6813 | board_config = ALC861_AUTO; | 7939 | board_config = ALC861_AUTO; |
@@ -6846,19 +7972,706 @@ static int patch_alc861(struct hda_codec *codec) | |||
6846 | } | 7972 | } |
6847 | 7973 | ||
6848 | /* | 7974 | /* |
7975 | * ALC861-VD support | ||
7976 | * | ||
7977 | * Based on ALC882 | ||
7978 | * | ||
7979 | * In addition, an independent DAC | ||
7980 | */ | ||
7981 | #define ALC861VD_DIGOUT_NID 0x06 | ||
7982 | |||
7983 | static hda_nid_t alc861vd_dac_nids[4] = { | ||
7984 | /* front, surr, clfe, side surr */ | ||
7985 | 0x02, 0x03, 0x04, 0x05 | ||
7986 | }; | ||
7987 | |||
7988 | /* dac_nids for ALC660vd are in a different order - according to | ||
7989 | * Realtek's driver. | ||
7990 | * This should probably tesult in a different mixer for 6stack models | ||
7991 | * of ALC660vd codecs, but for now there is only 3stack mixer | ||
7992 | * - and it is the same as in 861vd. | ||
7993 | * adc_nids in ALC660vd are (is) the same as in 861vd | ||
7994 | */ | ||
7995 | static hda_nid_t alc660vd_dac_nids[3] = { | ||
7996 | /* front, rear, clfe, rear_surr */ | ||
7997 | 0x02, 0x04, 0x03 | ||
7998 | }; | ||
7999 | |||
8000 | static hda_nid_t alc861vd_adc_nids[1] = { | ||
8001 | /* ADC0 */ | ||
8002 | 0x09, | ||
8003 | }; | ||
8004 | |||
8005 | /* input MUX */ | ||
8006 | /* FIXME: should be a matrix-type input source selection */ | ||
8007 | static struct hda_input_mux alc861vd_capture_source = { | ||
8008 | .num_items = 4, | ||
8009 | .items = { | ||
8010 | { "Mic", 0x0 }, | ||
8011 | { "Front Mic", 0x1 }, | ||
8012 | { "Line", 0x2 }, | ||
8013 | { "CD", 0x4 }, | ||
8014 | }, | ||
8015 | }; | ||
8016 | |||
8017 | #define alc861vd_mux_enum_info alc_mux_enum_info | ||
8018 | #define alc861vd_mux_enum_get alc_mux_enum_get | ||
8019 | |||
8020 | static int alc861vd_mux_enum_put(struct snd_kcontrol *kcontrol, | ||
8021 | struct snd_ctl_elem_value *ucontrol) | ||
8022 | { | ||
8023 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
8024 | struct alc_spec *spec = codec->spec; | ||
8025 | const struct hda_input_mux *imux = spec->input_mux; | ||
8026 | unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | ||
8027 | static hda_nid_t capture_mixers[1] = { 0x22 }; | ||
8028 | hda_nid_t nid = capture_mixers[adc_idx]; | ||
8029 | unsigned int *cur_val = &spec->cur_mux[adc_idx]; | ||
8030 | unsigned int i, idx; | ||
8031 | |||
8032 | idx = ucontrol->value.enumerated.item[0]; | ||
8033 | if (idx >= imux->num_items) | ||
8034 | idx = imux->num_items - 1; | ||
8035 | if (*cur_val == idx && ! codec->in_resume) | ||
8036 | return 0; | ||
8037 | for (i = 0; i < imux->num_items; i++) { | ||
8038 | unsigned int v = (i == idx) ? 0x7000 : 0x7080; | ||
8039 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, | ||
8040 | v | (imux->items[i].index << 8)); | ||
8041 | } | ||
8042 | *cur_val = idx; | ||
8043 | return 1; | ||
8044 | } | ||
8045 | |||
8046 | /* | ||
8047 | * 2ch mode | ||
8048 | */ | ||
8049 | static struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = { | ||
8050 | { 2, NULL } | ||
8051 | }; | ||
8052 | |||
8053 | /* | ||
8054 | * 6ch mode | ||
8055 | */ | ||
8056 | static struct hda_verb alc861vd_6stack_ch6_init[] = { | ||
8057 | { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, | ||
8058 | { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
8059 | { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
8060 | { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
8061 | { } /* end */ | ||
8062 | }; | ||
8063 | |||
8064 | /* | ||
8065 | * 8ch mode | ||
8066 | */ | ||
8067 | static struct hda_verb alc861vd_6stack_ch8_init[] = { | ||
8068 | { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
8069 | { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
8070 | { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
8071 | { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
8072 | { } /* end */ | ||
8073 | }; | ||
8074 | |||
8075 | static struct hda_channel_mode alc861vd_6stack_modes[2] = { | ||
8076 | { 6, alc861vd_6stack_ch6_init }, | ||
8077 | { 8, alc861vd_6stack_ch8_init }, | ||
8078 | }; | ||
8079 | |||
8080 | static struct snd_kcontrol_new alc861vd_chmode_mixer[] = { | ||
8081 | { | ||
8082 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
8083 | .name = "Channel Mode", | ||
8084 | .info = alc_ch_mode_info, | ||
8085 | .get = alc_ch_mode_get, | ||
8086 | .put = alc_ch_mode_put, | ||
8087 | }, | ||
8088 | { } /* end */ | ||
8089 | }; | ||
8090 | |||
8091 | static struct snd_kcontrol_new alc861vd_capture_mixer[] = { | ||
8092 | HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), | ||
8093 | HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), | ||
8094 | |||
8095 | { | ||
8096 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
8097 | /* The multiple "Capture Source" controls confuse alsamixer | ||
8098 | * So call somewhat different.. | ||
8099 | *FIXME: the controls appear in the "playback" view! | ||
8100 | */ | ||
8101 | /* .name = "Capture Source", */ | ||
8102 | .name = "Input Source", | ||
8103 | .count = 1, | ||
8104 | .info = alc861vd_mux_enum_info, | ||
8105 | .get = alc861vd_mux_enum_get, | ||
8106 | .put = alc861vd_mux_enum_put, | ||
8107 | }, | ||
8108 | { } /* end */ | ||
8109 | }; | ||
8110 | |||
8111 | /* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17 | ||
8112 | * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b | ||
8113 | */ | ||
8114 | static struct snd_kcontrol_new alc861vd_6st_mixer[] = { | ||
8115 | HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), | ||
8116 | HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), | ||
8117 | |||
8118 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT), | ||
8119 | HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), | ||
8120 | |||
8121 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, | ||
8122 | HDA_OUTPUT), | ||
8123 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, | ||
8124 | HDA_OUTPUT), | ||
8125 | HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), | ||
8126 | HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), | ||
8127 | |||
8128 | HDA_CODEC_VOLUME("Side Playback Volume", 0x05, 0x0, HDA_OUTPUT), | ||
8129 | HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), | ||
8130 | |||
8131 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), | ||
8132 | |||
8133 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), | ||
8134 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | ||
8135 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | ||
8136 | |||
8137 | HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), | ||
8138 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), | ||
8139 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), | ||
8140 | |||
8141 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), | ||
8142 | HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), | ||
8143 | |||
8144 | HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), | ||
8145 | HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), | ||
8146 | |||
8147 | HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), | ||
8148 | HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), | ||
8149 | |||
8150 | { } /* end */ | ||
8151 | }; | ||
8152 | |||
8153 | static struct snd_kcontrol_new alc861vd_3st_mixer[] = { | ||
8154 | HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), | ||
8155 | HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), | ||
8156 | |||
8157 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), | ||
8158 | |||
8159 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), | ||
8160 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | ||
8161 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | ||
8162 | |||
8163 | HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), | ||
8164 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), | ||
8165 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), | ||
8166 | |||
8167 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), | ||
8168 | HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), | ||
8169 | |||
8170 | HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), | ||
8171 | HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), | ||
8172 | |||
8173 | HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), | ||
8174 | HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), | ||
8175 | |||
8176 | { } /* end */ | ||
8177 | }; | ||
8178 | |||
8179 | /* | ||
8180 | * generic initialization of ADC, input mixers and output mixers | ||
8181 | */ | ||
8182 | static struct hda_verb alc861vd_volume_init_verbs[] = { | ||
8183 | /* | ||
8184 | * Unmute ADC0 and set the default input to mic-in | ||
8185 | */ | ||
8186 | {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
8187 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
8188 | |||
8189 | /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of | ||
8190 | * the analog-loopback mixer widget | ||
8191 | */ | ||
8192 | /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ | ||
8193 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
8194 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
8195 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, | ||
8196 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, | ||
8197 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, | ||
8198 | |||
8199 | /* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */ | ||
8200 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, | ||
8201 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)}, | ||
8202 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(6)}, | ||
8203 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(8)}, | ||
8204 | |||
8205 | /* | ||
8206 | * Set up output mixers (0x02 - 0x05) | ||
8207 | */ | ||
8208 | /* set vol=0 to output mixers */ | ||
8209 | {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
8210 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
8211 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
8212 | {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
8213 | |||
8214 | /* set up input amps for analog loopback */ | ||
8215 | /* Amp Indices: DAC = 0, mixer = 1 */ | ||
8216 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
8217 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
8218 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
8219 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
8220 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
8221 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
8222 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
8223 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
8224 | |||
8225 | { } | ||
8226 | }; | ||
8227 | |||
8228 | /* | ||
8229 | * 3-stack pin configuration: | ||
8230 | * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b | ||
8231 | */ | ||
8232 | static struct hda_verb alc861vd_3stack_init_verbs[] = { | ||
8233 | /* | ||
8234 | * Set pin mode and muting | ||
8235 | */ | ||
8236 | /* set front pin widgets 0x14 for output */ | ||
8237 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
8238 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
8239 | {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
8240 | |||
8241 | /* Mic (rear) pin: input vref at 80% */ | ||
8242 | {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
8243 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
8244 | /* Front Mic pin: input vref at 80% */ | ||
8245 | {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
8246 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
8247 | /* Line In pin: input */ | ||
8248 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
8249 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
8250 | /* Line-2 In: Headphone output (output 0 - 0x0c) */ | ||
8251 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
8252 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
8253 | {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
8254 | /* CD pin widget for input */ | ||
8255 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
8256 | |||
8257 | { } | ||
8258 | }; | ||
8259 | |||
8260 | /* | ||
8261 | * 6-stack pin configuration: | ||
8262 | */ | ||
8263 | static struct hda_verb alc861vd_6stack_init_verbs[] = { | ||
8264 | /* | ||
8265 | * Set pin mode and muting | ||
8266 | */ | ||
8267 | /* set front pin widgets 0x14 for output */ | ||
8268 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
8269 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
8270 | {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
8271 | |||
8272 | /* Rear Pin: output 1 (0x0d) */ | ||
8273 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
8274 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
8275 | {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
8276 | /* CLFE Pin: output 2 (0x0e) */ | ||
8277 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
8278 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
8279 | {0x16, AC_VERB_SET_CONNECT_SEL, 0x02}, | ||
8280 | /* Side Pin: output 3 (0x0f) */ | ||
8281 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
8282 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
8283 | {0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, | ||
8284 | |||
8285 | /* Mic (rear) pin: input vref at 80% */ | ||
8286 | {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
8287 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
8288 | /* Front Mic pin: input vref at 80% */ | ||
8289 | {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
8290 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
8291 | /* Line In pin: input */ | ||
8292 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
8293 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
8294 | /* Line-2 In: Headphone output (output 0 - 0x0c) */ | ||
8295 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
8296 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
8297 | {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
8298 | /* CD pin widget for input */ | ||
8299 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
8300 | |||
8301 | { } | ||
8302 | }; | ||
8303 | |||
8304 | /* pcm configuration: identiacal with ALC880 */ | ||
8305 | #define alc861vd_pcm_analog_playback alc880_pcm_analog_playback | ||
8306 | #define alc861vd_pcm_analog_capture alc880_pcm_analog_capture | ||
8307 | #define alc861vd_pcm_digital_playback alc880_pcm_digital_playback | ||
8308 | #define alc861vd_pcm_digital_capture alc880_pcm_digital_capture | ||
8309 | |||
8310 | /* | ||
8311 | * configuration and preset | ||
8312 | */ | ||
8313 | static const char *alc861vd_models[ALC861VD_MODEL_LAST] = { | ||
8314 | [ALC660VD_3ST] = "3stack-660", | ||
8315 | [ALC861VD_3ST] = "3stack", | ||
8316 | [ALC861VD_3ST_DIG] = "3stack-digout", | ||
8317 | [ALC861VD_6ST_DIG] = "6stack-digout", | ||
8318 | [ALC861VD_AUTO] = "auto", | ||
8319 | }; | ||
8320 | |||
8321 | static struct snd_pci_quirk alc861vd_cfg_tbl[] = { | ||
8322 | SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST), | ||
8323 | SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST), | ||
8324 | SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST), | ||
8325 | |||
8326 | SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo 3000 C200", ALC861VD_3ST), | ||
8327 | {} | ||
8328 | }; | ||
8329 | |||
8330 | static struct alc_config_preset alc861vd_presets[] = { | ||
8331 | [ALC660VD_3ST] = { | ||
8332 | .mixers = { alc861vd_3st_mixer }, | ||
8333 | .init_verbs = { alc861vd_volume_init_verbs, | ||
8334 | alc861vd_3stack_init_verbs }, | ||
8335 | .num_dacs = ARRAY_SIZE(alc660vd_dac_nids), | ||
8336 | .dac_nids = alc660vd_dac_nids, | ||
8337 | .num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids), | ||
8338 | .adc_nids = alc861vd_adc_nids, | ||
8339 | .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), | ||
8340 | .channel_mode = alc861vd_3stack_2ch_modes, | ||
8341 | .input_mux = &alc861vd_capture_source, | ||
8342 | }, | ||
8343 | [ALC861VD_3ST] = { | ||
8344 | .mixers = { alc861vd_3st_mixer }, | ||
8345 | .init_verbs = { alc861vd_volume_init_verbs, | ||
8346 | alc861vd_3stack_init_verbs }, | ||
8347 | .num_dacs = ARRAY_SIZE(alc861vd_dac_nids), | ||
8348 | .dac_nids = alc861vd_dac_nids, | ||
8349 | .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), | ||
8350 | .channel_mode = alc861vd_3stack_2ch_modes, | ||
8351 | .input_mux = &alc861vd_capture_source, | ||
8352 | }, | ||
8353 | [ALC861VD_3ST_DIG] = { | ||
8354 | .mixers = { alc861vd_3st_mixer }, | ||
8355 | .init_verbs = { alc861vd_volume_init_verbs, | ||
8356 | alc861vd_3stack_init_verbs }, | ||
8357 | .num_dacs = ARRAY_SIZE(alc861vd_dac_nids), | ||
8358 | .dac_nids = alc861vd_dac_nids, | ||
8359 | .dig_out_nid = ALC861VD_DIGOUT_NID, | ||
8360 | .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), | ||
8361 | .channel_mode = alc861vd_3stack_2ch_modes, | ||
8362 | .input_mux = &alc861vd_capture_source, | ||
8363 | }, | ||
8364 | [ALC861VD_6ST_DIG] = { | ||
8365 | .mixers = { alc861vd_6st_mixer, alc861vd_chmode_mixer }, | ||
8366 | .init_verbs = { alc861vd_volume_init_verbs, | ||
8367 | alc861vd_6stack_init_verbs }, | ||
8368 | .num_dacs = ARRAY_SIZE(alc861vd_dac_nids), | ||
8369 | .dac_nids = alc861vd_dac_nids, | ||
8370 | .dig_out_nid = ALC861VD_DIGOUT_NID, | ||
8371 | .num_channel_mode = ARRAY_SIZE(alc861vd_6stack_modes), | ||
8372 | .channel_mode = alc861vd_6stack_modes, | ||
8373 | .input_mux = &alc861vd_capture_source, | ||
8374 | }, | ||
8375 | }; | ||
8376 | |||
8377 | /* | ||
8378 | * BIOS auto configuration | ||
8379 | */ | ||
8380 | static void alc861vd_auto_set_output_and_unmute(struct hda_codec *codec, | ||
8381 | hda_nid_t nid, int pin_type, int dac_idx) | ||
8382 | { | ||
8383 | /* set as output */ | ||
8384 | snd_hda_codec_write(codec, nid, 0, | ||
8385 | AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type); | ||
8386 | snd_hda_codec_write(codec, nid, 0, | ||
8387 | AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); | ||
8388 | } | ||
8389 | |||
8390 | static void alc861vd_auto_init_multi_out(struct hda_codec *codec) | ||
8391 | { | ||
8392 | struct alc_spec *spec = codec->spec; | ||
8393 | int i; | ||
8394 | |||
8395 | for (i = 0; i <= HDA_SIDE; i++) { | ||
8396 | hda_nid_t nid = spec->autocfg.line_out_pins[i]; | ||
8397 | if (nid) | ||
8398 | alc861vd_auto_set_output_and_unmute(codec, nid, | ||
8399 | PIN_OUT, i); | ||
8400 | } | ||
8401 | } | ||
8402 | |||
8403 | |||
8404 | static void alc861vd_auto_init_hp_out(struct hda_codec *codec) | ||
8405 | { | ||
8406 | struct alc_spec *spec = codec->spec; | ||
8407 | hda_nid_t pin; | ||
8408 | |||
8409 | pin = spec->autocfg.hp_pins[0]; | ||
8410 | if (pin) /* connect to front and use dac 0 */ | ||
8411 | alc861vd_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); | ||
8412 | } | ||
8413 | |||
8414 | #define alc861vd_is_input_pin(nid) alc880_is_input_pin(nid) | ||
8415 | #define ALC861VD_PIN_CD_NID ALC880_PIN_CD_NID | ||
8416 | |||
8417 | static void alc861vd_auto_init_analog_input(struct hda_codec *codec) | ||
8418 | { | ||
8419 | struct alc_spec *spec = codec->spec; | ||
8420 | int i; | ||
8421 | |||
8422 | for (i = 0; i < AUTO_PIN_LAST; i++) { | ||
8423 | hda_nid_t nid = spec->autocfg.input_pins[i]; | ||
8424 | if (alc861vd_is_input_pin(nid)) { | ||
8425 | snd_hda_codec_write(codec, nid, 0, | ||
8426 | AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
8427 | i <= AUTO_PIN_FRONT_MIC ? | ||
8428 | PIN_VREF80 : PIN_IN); | ||
8429 | if (nid != ALC861VD_PIN_CD_NID) | ||
8430 | snd_hda_codec_write(codec, nid, 0, | ||
8431 | AC_VERB_SET_AMP_GAIN_MUTE, | ||
8432 | AMP_OUT_MUTE); | ||
8433 | } | ||
8434 | } | ||
8435 | } | ||
8436 | |||
8437 | #define alc861vd_idx_to_mixer_vol(nid) ((nid) + 0x02) | ||
8438 | #define alc861vd_idx_to_mixer_switch(nid) ((nid) + 0x0c) | ||
8439 | |||
8440 | /* add playback controls from the parsed DAC table */ | ||
8441 | /* Based on ALC880 version. But ALC861VD has separate, | ||
8442 | * different NIDs for mute/unmute switch and volume control */ | ||
8443 | static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec, | ||
8444 | const struct auto_pin_cfg *cfg) | ||
8445 | { | ||
8446 | char name[32]; | ||
8447 | static const char *chname[4] = {"Front", "Surround", "CLFE", "Side"}; | ||
8448 | hda_nid_t nid_v, nid_s; | ||
8449 | int i, err; | ||
8450 | |||
8451 | for (i = 0; i < cfg->line_outs; i++) { | ||
8452 | if (! spec->multiout.dac_nids[i]) | ||
8453 | continue; | ||
8454 | nid_v = alc861vd_idx_to_mixer_vol( | ||
8455 | alc880_dac_to_idx( | ||
8456 | spec->multiout.dac_nids[i])); | ||
8457 | nid_s = alc861vd_idx_to_mixer_switch( | ||
8458 | alc880_dac_to_idx( | ||
8459 | spec->multiout.dac_nids[i])); | ||
8460 | |||
8461 | if (i == 2) { | ||
8462 | /* Center/LFE */ | ||
8463 | if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, | ||
8464 | "Center Playback Volume", | ||
8465 | HDA_COMPOSE_AMP_VAL(nid_v, 1, | ||
8466 | 0, HDA_OUTPUT))) < 0) | ||
8467 | return err; | ||
8468 | if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, | ||
8469 | "LFE Playback Volume", | ||
8470 | HDA_COMPOSE_AMP_VAL(nid_v, 2, | ||
8471 | 0, HDA_OUTPUT))) < 0) | ||
8472 | return err; | ||
8473 | if ((err = add_control(spec, ALC_CTL_BIND_MUTE, | ||
8474 | "Center Playback Switch", | ||
8475 | HDA_COMPOSE_AMP_VAL(nid_s, 1, | ||
8476 | 2, HDA_INPUT))) < 0) | ||
8477 | return err; | ||
8478 | if ((err = add_control(spec, ALC_CTL_BIND_MUTE, | ||
8479 | "LFE Playback Switch", | ||
8480 | HDA_COMPOSE_AMP_VAL(nid_s, 2, | ||
8481 | 2, HDA_INPUT))) < 0) | ||
8482 | return err; | ||
8483 | } else { | ||
8484 | sprintf(name, "%s Playback Volume", chname[i]); | ||
8485 | if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, name, | ||
8486 | HDA_COMPOSE_AMP_VAL(nid_v, 3, | ||
8487 | 0, HDA_OUTPUT))) < 0) | ||
8488 | return err; | ||
8489 | sprintf(name, "%s Playback Switch", chname[i]); | ||
8490 | if ((err = add_control(spec, ALC_CTL_BIND_MUTE, name, | ||
8491 | HDA_COMPOSE_AMP_VAL(nid_v, 3, | ||
8492 | 2, HDA_INPUT))) < 0) | ||
8493 | return err; | ||
8494 | } | ||
8495 | } | ||
8496 | return 0; | ||
8497 | } | ||
8498 | |||
8499 | /* add playback controls for speaker and HP outputs */ | ||
8500 | /* Based on ALC880 version. But ALC861VD has separate, | ||
8501 | * different NIDs for mute/unmute switch and volume control */ | ||
8502 | static int alc861vd_auto_create_extra_out(struct alc_spec *spec, | ||
8503 | hda_nid_t pin, const char *pfx) | ||
8504 | { | ||
8505 | hda_nid_t nid_v, nid_s; | ||
8506 | int err; | ||
8507 | char name[32]; | ||
8508 | |||
8509 | if (! pin) | ||
8510 | return 0; | ||
8511 | |||
8512 | if (alc880_is_fixed_pin(pin)) { | ||
8513 | nid_v = alc880_idx_to_dac(alc880_fixed_pin_idx(pin)); | ||
8514 | /* specify the DAC as the extra output */ | ||
8515 | if (! spec->multiout.hp_nid) | ||
8516 | spec->multiout.hp_nid = nid_v; | ||
8517 | else | ||
8518 | spec->multiout.extra_out_nid[0] = nid_v; | ||
8519 | /* control HP volume/switch on the output mixer amp */ | ||
8520 | nid_v = alc861vd_idx_to_mixer_vol( | ||
8521 | alc880_fixed_pin_idx(pin)); | ||
8522 | nid_s = alc861vd_idx_to_mixer_switch( | ||
8523 | alc880_fixed_pin_idx(pin)); | ||
8524 | |||
8525 | sprintf(name, "%s Playback Volume", pfx); | ||
8526 | if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, name, | ||
8527 | HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, | ||
8528 | HDA_OUTPUT))) < 0) | ||
8529 | return err; | ||
8530 | sprintf(name, "%s Playback Switch", pfx); | ||
8531 | if ((err = add_control(spec, ALC_CTL_BIND_MUTE, name, | ||
8532 | HDA_COMPOSE_AMP_VAL(nid_s, 3, 2, | ||
8533 | HDA_INPUT))) < 0) | ||
8534 | return err; | ||
8535 | } else if (alc880_is_multi_pin(pin)) { | ||
8536 | /* set manual connection */ | ||
8537 | /* we have only a switch on HP-out PIN */ | ||
8538 | sprintf(name, "%s Playback Switch", pfx); | ||
8539 | if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, | ||
8540 | HDA_COMPOSE_AMP_VAL(pin, 3, 0, | ||
8541 | HDA_OUTPUT))) < 0) | ||
8542 | return err; | ||
8543 | } | ||
8544 | return 0; | ||
8545 | } | ||
8546 | |||
8547 | /* parse the BIOS configuration and set up the alc_spec | ||
8548 | * return 1 if successful, 0 if the proper config is not found, | ||
8549 | * or a negative error code | ||
8550 | * Based on ALC880 version - had to change it to override | ||
8551 | * alc880_auto_create_extra_out and alc880_auto_create_multi_out_ctls */ | ||
8552 | static int alc861vd_parse_auto_config(struct hda_codec *codec) | ||
8553 | { | ||
8554 | struct alc_spec *spec = codec->spec; | ||
8555 | int err; | ||
8556 | static hda_nid_t alc861vd_ignore[] = { 0x1d, 0 }; | ||
8557 | |||
8558 | if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, | ||
8559 | alc861vd_ignore)) < 0) | ||
8560 | return err; | ||
8561 | if (! spec->autocfg.line_outs) | ||
8562 | return 0; /* can't find valid BIOS pin config */ | ||
8563 | |||
8564 | if ((err = alc880_auto_fill_dac_nids(spec, &spec->autocfg)) < 0 || | ||
8565 | (err = alc861vd_auto_create_multi_out_ctls(spec, | ||
8566 | &spec->autocfg)) < 0 || | ||
8567 | (err = alc861vd_auto_create_extra_out(spec, | ||
8568 | spec->autocfg.speaker_pins[0], "Speaker")) < 0 || | ||
8569 | (err = alc861vd_auto_create_extra_out(spec, | ||
8570 | spec->autocfg.hp_pins[0], "Headphone")) < 0 || | ||
8571 | (err = alc880_auto_create_analog_input_ctls(spec, | ||
8572 | &spec->autocfg)) < 0) | ||
8573 | return err; | ||
8574 | |||
8575 | spec->multiout.max_channels = spec->multiout.num_dacs * 2; | ||
8576 | |||
8577 | if (spec->autocfg.dig_out_pin) | ||
8578 | spec->multiout.dig_out_nid = ALC861VD_DIGOUT_NID; | ||
8579 | |||
8580 | if (spec->kctl_alloc) | ||
8581 | spec->mixers[spec->num_mixers++] = spec->kctl_alloc; | ||
8582 | |||
8583 | spec->init_verbs[spec->num_init_verbs++] | ||
8584 | = alc861vd_volume_init_verbs; | ||
8585 | |||
8586 | spec->num_mux_defs = 1; | ||
8587 | spec->input_mux = &spec->private_imux; | ||
8588 | |||
8589 | return 1; | ||
8590 | } | ||
8591 | |||
8592 | /* additional initialization for auto-configuration model */ | ||
8593 | static void alc861vd_auto_init(struct hda_codec *codec) | ||
8594 | { | ||
8595 | alc861vd_auto_init_multi_out(codec); | ||
8596 | alc861vd_auto_init_hp_out(codec); | ||
8597 | alc861vd_auto_init_analog_input(codec); | ||
8598 | } | ||
8599 | |||
8600 | static int patch_alc861vd(struct hda_codec *codec) | ||
8601 | { | ||
8602 | struct alc_spec *spec; | ||
8603 | int err, board_config; | ||
8604 | |||
8605 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
8606 | if (spec == NULL) | ||
8607 | return -ENOMEM; | ||
8608 | |||
8609 | codec->spec = spec; | ||
8610 | |||
8611 | board_config = snd_hda_check_board_config(codec, ALC861VD_MODEL_LAST, | ||
8612 | alc861vd_models, | ||
8613 | alc861vd_cfg_tbl); | ||
8614 | |||
8615 | if (board_config < 0 || board_config >= ALC861VD_MODEL_LAST) { | ||
8616 | printk(KERN_INFO "hda_codec: Unknown model for ALC660VD/" | ||
8617 | "ALC861VD, trying auto-probe from BIOS...\n"); | ||
8618 | board_config = ALC861VD_AUTO; | ||
8619 | } | ||
8620 | |||
8621 | if (board_config == ALC861VD_AUTO) { | ||
8622 | /* automatic parse from the BIOS config */ | ||
8623 | err = alc861vd_parse_auto_config(codec); | ||
8624 | if (err < 0) { | ||
8625 | alc_free(codec); | ||
8626 | return err; | ||
8627 | } else if (! err) { | ||
8628 | printk(KERN_INFO | ||
8629 | "hda_codec: Cannot set up configuration " | ||
8630 | "from BIOS. Using base mode...\n"); | ||
8631 | board_config = ALC861VD_3ST; | ||
8632 | } | ||
8633 | } | ||
8634 | |||
8635 | if (board_config != ALC861VD_AUTO) | ||
8636 | setup_preset(spec, &alc861vd_presets[board_config]); | ||
8637 | |||
8638 | spec->stream_name_analog = "ALC861VD Analog"; | ||
8639 | spec->stream_analog_playback = &alc861vd_pcm_analog_playback; | ||
8640 | spec->stream_analog_capture = &alc861vd_pcm_analog_capture; | ||
8641 | |||
8642 | spec->stream_name_digital = "ALC861VD Digital"; | ||
8643 | spec->stream_digital_playback = &alc861vd_pcm_digital_playback; | ||
8644 | spec->stream_digital_capture = &alc861vd_pcm_digital_capture; | ||
8645 | |||
8646 | spec->adc_nids = alc861vd_adc_nids; | ||
8647 | spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids); | ||
8648 | |||
8649 | spec->mixers[spec->num_mixers] = alc861vd_capture_mixer; | ||
8650 | spec->num_mixers++; | ||
8651 | |||
8652 | codec->patch_ops = alc_patch_ops; | ||
8653 | |||
8654 | if (board_config == ALC861VD_AUTO) | ||
8655 | spec->init_hook = alc861vd_auto_init; | ||
8656 | |||
8657 | return 0; | ||
8658 | } | ||
8659 | |||
8660 | /* | ||
6849 | * patch entries | 8661 | * patch entries |
6850 | */ | 8662 | */ |
6851 | struct hda_codec_preset snd_hda_preset_realtek[] = { | 8663 | struct hda_codec_preset snd_hda_preset_realtek[] = { |
6852 | { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 }, | 8664 | { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 }, |
6853 | { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 }, | 8665 | { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 }, |
6854 | { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 }, | 8666 | { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660", |
8667 | .patch = patch_alc861 }, | ||
8668 | { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd }, | ||
8669 | { .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 }, | ||
8670 | { .id = 0x10ec0862, .name = "ALC861-VD", .patch = patch_alc861vd }, | ||
8671 | { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 }, | ||
6855 | { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 }, | 8672 | { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 }, |
6856 | { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc883 }, | 8673 | { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc883 }, |
6857 | { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 }, | 8674 | { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 }, |
6858 | { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc883 }, | 8675 | { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc883 }, |
6859 | { .id = 0x10ec0861, .rev = 0x100300, .name = "ALC861", | ||
6860 | .patch = patch_alc861 }, | ||
6861 | { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660", | ||
6862 | .patch = patch_alc861 }, | ||
6863 | {} /* terminator */ | 8676 | {} /* terminator */ |
6864 | }; | 8677 | }; |
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index fe51ef3e49d2..6f4a39273b98 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c | |||
@@ -37,14 +37,37 @@ | |||
37 | #define NUM_CONTROL_ALLOC 32 | 37 | #define NUM_CONTROL_ALLOC 32 |
38 | #define STAC_HP_EVENT 0x37 | 38 | #define STAC_HP_EVENT 0x37 |
39 | 39 | ||
40 | #define STAC_REF 0 | 40 | enum { |
41 | #define STAC_D945GTP3 1 | 41 | STAC_REF, |
42 | #define STAC_D945GTP5 2 | 42 | STAC_9200_MODELS |
43 | #define STAC_MACMINI 3 | 43 | }; |
44 | #define STAC_922X_MODELS 4 /* number of 922x models */ | 44 | |
45 | #define STAC_D965_3ST 4 | 45 | enum { |
46 | #define STAC_D965_5ST 5 | 46 | STAC_9205_REF, |
47 | #define STAC_927X_MODELS 6 /* number of 922x models */ | 47 | STAC_9205_MODELS |
48 | }; | ||
49 | |||
50 | enum { | ||
51 | STAC_925x_REF, | ||
52 | STAC_M2_2, | ||
53 | STAC_MA6, | ||
54 | STAC_925x_MODELS | ||
55 | }; | ||
56 | |||
57 | enum { | ||
58 | STAC_D945_REF, | ||
59 | STAC_D945GTP3, | ||
60 | STAC_D945GTP5, | ||
61 | STAC_MACMINI, | ||
62 | STAC_922X_MODELS | ||
63 | }; | ||
64 | |||
65 | enum { | ||
66 | STAC_D965_REF, | ||
67 | STAC_D965_3ST, | ||
68 | STAC_D965_5ST, | ||
69 | STAC_927X_MODELS | ||
70 | }; | ||
48 | 71 | ||
49 | struct sigmatel_spec { | 72 | struct sigmatel_spec { |
50 | struct snd_kcontrol_new *mixers[4]; | 73 | struct snd_kcontrol_new *mixers[4]; |
@@ -67,6 +90,9 @@ struct sigmatel_spec { | |||
67 | unsigned int num_adcs; | 90 | unsigned int num_adcs; |
68 | hda_nid_t *mux_nids; | 91 | hda_nid_t *mux_nids; |
69 | unsigned int num_muxes; | 92 | unsigned int num_muxes; |
93 | hda_nid_t *dmic_nids; | ||
94 | unsigned int num_dmics; | ||
95 | hda_nid_t dmux_nid; | ||
70 | hda_nid_t dig_in_nid; | 96 | hda_nid_t dig_in_nid; |
71 | 97 | ||
72 | /* pin widgets */ | 98 | /* pin widgets */ |
@@ -80,6 +106,8 @@ struct sigmatel_spec { | |||
80 | struct snd_kcontrol_new *mixer; | 106 | struct snd_kcontrol_new *mixer; |
81 | 107 | ||
82 | /* capture source */ | 108 | /* capture source */ |
109 | struct hda_input_mux *dinput_mux; | ||
110 | unsigned int cur_dmux; | ||
83 | struct hda_input_mux *input_mux; | 111 | struct hda_input_mux *input_mux; |
84 | unsigned int cur_mux[3]; | 112 | unsigned int cur_mux[3]; |
85 | 113 | ||
@@ -92,6 +120,7 @@ struct sigmatel_spec { | |||
92 | struct auto_pin_cfg autocfg; | 120 | struct auto_pin_cfg autocfg; |
93 | unsigned int num_kctl_alloc, num_kctl_used; | 121 | unsigned int num_kctl_alloc, num_kctl_used; |
94 | struct snd_kcontrol_new *kctl_alloc; | 122 | struct snd_kcontrol_new *kctl_alloc; |
123 | struct hda_input_mux private_dimux; | ||
95 | struct hda_input_mux private_imux; | 124 | struct hda_input_mux private_imux; |
96 | }; | 125 | }; |
97 | 126 | ||
@@ -107,6 +136,18 @@ static hda_nid_t stac9200_dac_nids[1] = { | |||
107 | 0x02, | 136 | 0x02, |
108 | }; | 137 | }; |
109 | 138 | ||
139 | static hda_nid_t stac925x_adc_nids[1] = { | ||
140 | 0x03, | ||
141 | }; | ||
142 | |||
143 | static hda_nid_t stac925x_mux_nids[1] = { | ||
144 | 0x0f, | ||
145 | }; | ||
146 | |||
147 | static hda_nid_t stac925x_dac_nids[1] = { | ||
148 | 0x02, | ||
149 | }; | ||
150 | |||
110 | static hda_nid_t stac922x_adc_nids[2] = { | 151 | static hda_nid_t stac922x_adc_nids[2] = { |
111 | 0x06, 0x07, | 152 | 0x06, 0x07, |
112 | }; | 153 | }; |
@@ -131,11 +172,20 @@ static hda_nid_t stac9205_mux_nids[2] = { | |||
131 | 0x19, 0x1a | 172 | 0x19, 0x1a |
132 | }; | 173 | }; |
133 | 174 | ||
175 | static hda_nid_t stac9205_dmic_nids[3] = { | ||
176 | 0x17, 0x18, 0 | ||
177 | }; | ||
178 | |||
134 | static hda_nid_t stac9200_pin_nids[8] = { | 179 | static hda_nid_t stac9200_pin_nids[8] = { |
135 | 0x08, 0x09, 0x0d, 0x0e, | 180 | 0x08, 0x09, 0x0d, 0x0e, |
136 | 0x0f, 0x10, 0x11, 0x12, | 181 | 0x0f, 0x10, 0x11, 0x12, |
137 | }; | 182 | }; |
138 | 183 | ||
184 | static hda_nid_t stac925x_pin_nids[8] = { | ||
185 | 0x07, 0x08, 0x0a, 0x0b, | ||
186 | 0x0c, 0x0d, 0x10, 0x11, | ||
187 | }; | ||
188 | |||
139 | static hda_nid_t stac922x_pin_nids[10] = { | 189 | static hda_nid_t stac922x_pin_nids[10] = { |
140 | 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, | 190 | 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, |
141 | 0x0f, 0x10, 0x11, 0x15, 0x1b, | 191 | 0x0f, 0x10, 0x11, 0x15, 0x1b, |
@@ -154,6 +204,34 @@ static hda_nid_t stac9205_pin_nids[12] = { | |||
154 | 204 | ||
155 | }; | 205 | }; |
156 | 206 | ||
207 | static int stac92xx_dmux_enum_info(struct snd_kcontrol *kcontrol, | ||
208 | struct snd_ctl_elem_info *uinfo) | ||
209 | { | ||
210 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
211 | struct sigmatel_spec *spec = codec->spec; | ||
212 | return snd_hda_input_mux_info(spec->dinput_mux, uinfo); | ||
213 | } | ||
214 | |||
215 | static int stac92xx_dmux_enum_get(struct snd_kcontrol *kcontrol, | ||
216 | struct snd_ctl_elem_value *ucontrol) | ||
217 | { | ||
218 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
219 | struct sigmatel_spec *spec = codec->spec; | ||
220 | |||
221 | ucontrol->value.enumerated.item[0] = spec->cur_dmux; | ||
222 | return 0; | ||
223 | } | ||
224 | |||
225 | static int stac92xx_dmux_enum_put(struct snd_kcontrol *kcontrol, | ||
226 | struct snd_ctl_elem_value *ucontrol) | ||
227 | { | ||
228 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
229 | struct sigmatel_spec *spec = codec->spec; | ||
230 | |||
231 | return snd_hda_input_mux_put(codec, spec->dinput_mux, ucontrol, | ||
232 | spec->dmux_nid, &spec->cur_dmux); | ||
233 | } | ||
234 | |||
157 | static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | 235 | static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) |
158 | { | 236 | { |
159 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 237 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
@@ -187,6 +265,12 @@ static struct hda_verb stac9200_core_init[] = { | |||
187 | {} | 265 | {} |
188 | }; | 266 | }; |
189 | 267 | ||
268 | static struct hda_verb stac925x_core_init[] = { | ||
269 | /* set dac0mux for dac converter */ | ||
270 | { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
271 | {} | ||
272 | }; | ||
273 | |||
190 | static struct hda_verb stac922x_core_init[] = { | 274 | static struct hda_verb stac922x_core_init[] = { |
191 | /* set master volume and direct control */ | 275 | /* set master volume and direct control */ |
192 | { 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, | 276 | { 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, |
@@ -232,6 +316,23 @@ static struct snd_kcontrol_new stac9200_mixer[] = { | |||
232 | { } /* end */ | 316 | { } /* end */ |
233 | }; | 317 | }; |
234 | 318 | ||
319 | static struct snd_kcontrol_new stac925x_mixer[] = { | ||
320 | HDA_CODEC_VOLUME("Master Playback Volume", 0xe, 0, HDA_OUTPUT), | ||
321 | HDA_CODEC_MUTE("Master Playback Switch", 0xe, 0, HDA_OUTPUT), | ||
322 | { | ||
323 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
324 | .name = "Input Source", | ||
325 | .count = 1, | ||
326 | .info = stac92xx_mux_enum_info, | ||
327 | .get = stac92xx_mux_enum_get, | ||
328 | .put = stac92xx_mux_enum_put, | ||
329 | }, | ||
330 | HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT), | ||
331 | HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_OUTPUT), | ||
332 | HDA_CODEC_VOLUME("Capture Mux Volume", 0x0f, 0, HDA_OUTPUT), | ||
333 | { } /* end */ | ||
334 | }; | ||
335 | |||
235 | /* This needs to be generated dynamically based on sequence */ | 336 | /* This needs to be generated dynamically based on sequence */ |
236 | static struct snd_kcontrol_new stac922x_mixer[] = { | 337 | static struct snd_kcontrol_new stac922x_mixer[] = { |
237 | { | 338 | { |
@@ -263,7 +364,7 @@ static struct snd_kcontrol_new stac9227_mixer[] = { | |||
263 | { } /* end */ | 364 | { } /* end */ |
264 | }; | 365 | }; |
265 | 366 | ||
266 | static snd_kcontrol_new_t stac927x_mixer[] = { | 367 | static struct snd_kcontrol_new stac927x_mixer[] = { |
267 | { | 368 | { |
268 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 369 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
269 | .name = "Input Source", | 370 | .name = "Input Source", |
@@ -278,7 +379,15 @@ static snd_kcontrol_new_t stac927x_mixer[] = { | |||
278 | { } /* end */ | 379 | { } /* end */ |
279 | }; | 380 | }; |
280 | 381 | ||
281 | static snd_kcontrol_new_t stac9205_mixer[] = { | 382 | static struct snd_kcontrol_new stac9205_mixer[] = { |
383 | { | ||
384 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
385 | .name = "Digital Input Source", | ||
386 | .count = 1, | ||
387 | .info = stac92xx_dmux_enum_info, | ||
388 | .get = stac92xx_dmux_enum_get, | ||
389 | .put = stac92xx_dmux_enum_put, | ||
390 | }, | ||
282 | { | 391 | { |
283 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 392 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
284 | .name = "Input Source", | 393 | .name = "Input Source", |
@@ -327,22 +436,64 @@ static unsigned int ref9200_pin_configs[8] = { | |||
327 | 0x02a19020, 0x01a19021, 0x90100140, 0x01813122, | 436 | 0x02a19020, 0x01a19021, 0x90100140, 0x01813122, |
328 | }; | 437 | }; |
329 | 438 | ||
330 | static unsigned int *stac9200_brd_tbl[] = { | 439 | static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = { |
331 | ref9200_pin_configs, | 440 | [STAC_REF] = ref9200_pin_configs, |
441 | }; | ||
442 | |||
443 | static const char *stac9200_models[STAC_9200_MODELS] = { | ||
444 | [STAC_REF] = "ref", | ||
332 | }; | 445 | }; |
333 | 446 | ||
334 | static struct hda_board_config stac9200_cfg_tbl[] = { | 447 | static struct snd_pci_quirk stac9200_cfg_tbl[] = { |
335 | { .modelname = "ref", | 448 | /* SigmaTel reference board */ |
336 | .pci_subvendor = PCI_VENDOR_ID_INTEL, | 449 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, |
337 | .pci_subdevice = 0x2668, /* DFI LanParty */ | 450 | "DFI LanParty", STAC_REF), |
338 | .config = STAC_REF }, | ||
339 | /* Dell laptops have BIOS problem */ | 451 | /* Dell laptops have BIOS problem */ |
340 | { .pci_subvendor = PCI_VENDOR_ID_DELL, .pci_subdevice = 0x01b5, | 452 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01b5, |
341 | .config = STAC_REF }, /* Dell Inspiron 630m */ | 453 | "Dell Inspiron 630m", STAC_REF), |
342 | { .pci_subvendor = PCI_VENDOR_ID_DELL, .pci_subdevice = 0x01c2, | 454 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c2, |
343 | .config = STAC_REF }, /* Dell Latitude D620 */ | 455 | "Dell Latitude D620", STAC_REF), |
344 | { .pci_subvendor = PCI_VENDOR_ID_DELL, .pci_subdevice = 0x01cb, | 456 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cb, |
345 | .config = STAC_REF }, /* Dell Latitude 120L */ | 457 | "Dell Latitude 120L", STAC_REF), |
458 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cc, | ||
459 | "Dell Latitude D820", STAC_REF), | ||
460 | {} /* terminator */ | ||
461 | }; | ||
462 | |||
463 | static unsigned int ref925x_pin_configs[8] = { | ||
464 | 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021, | ||
465 | 0x90a70320, 0x02214210, 0x400003f1, 0x9033032e, | ||
466 | }; | ||
467 | |||
468 | static unsigned int stac925x_MA6_pin_configs[8] = { | ||
469 | 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021, | ||
470 | 0x90a70320, 0x90100211, 0x400003f1, 0x9033032e, | ||
471 | }; | ||
472 | |||
473 | static unsigned int stac925xM2_2_pin_configs[8] = { | ||
474 | 0x40c003f3, 0x424503f2, 0x041800f4, 0x02a19020, | ||
475 | 0x50a103F0, 0x90100210, 0x400003f1, 0x9033032e, | ||
476 | }; | ||
477 | |||
478 | static unsigned int *stac925x_brd_tbl[STAC_925x_MODELS] = { | ||
479 | [STAC_REF] = ref925x_pin_configs, | ||
480 | [STAC_M2_2] = stac925xM2_2_pin_configs, | ||
481 | [STAC_MA6] = stac925x_MA6_pin_configs, | ||
482 | }; | ||
483 | |||
484 | static const char *stac925x_models[STAC_925x_MODELS] = { | ||
485 | [STAC_REF] = "ref", | ||
486 | [STAC_M2_2] = "m2-2", | ||
487 | [STAC_MA6] = "m6", | ||
488 | }; | ||
489 | |||
490 | static struct snd_pci_quirk stac925x_cfg_tbl[] = { | ||
491 | /* SigmaTel reference board */ | ||
492 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF), | ||
493 | SND_PCI_QUIRK(0x107b, 0x0316, "Gateway M255", STAC_REF), | ||
494 | SND_PCI_QUIRK(0x107b, 0x0366, "Gateway MP6954", STAC_REF), | ||
495 | SND_PCI_QUIRK(0x107b, 0x0461, "Gateway NX560XL", STAC_MA6), | ||
496 | SND_PCI_QUIRK(0x1002, 0x437b, "Gateway MX6453", STAC_M2_2), | ||
346 | {} /* terminator */ | 497 | {} /* terminator */ |
347 | }; | 498 | }; |
348 | 499 | ||
@@ -365,100 +516,80 @@ static unsigned int d945gtp5_pin_configs[10] = { | |||
365 | }; | 516 | }; |
366 | 517 | ||
367 | static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = { | 518 | static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = { |
368 | [STAC_REF] = ref922x_pin_configs, | 519 | [STAC_D945_REF] = ref922x_pin_configs, |
369 | [STAC_D945GTP3] = d945gtp3_pin_configs, | 520 | [STAC_D945GTP3] = d945gtp3_pin_configs, |
370 | [STAC_D945GTP5] = d945gtp5_pin_configs, | 521 | [STAC_D945GTP5] = d945gtp5_pin_configs, |
371 | [STAC_MACMINI] = d945gtp5_pin_configs, | 522 | [STAC_MACMINI] = d945gtp5_pin_configs, |
372 | }; | 523 | }; |
373 | 524 | ||
374 | static struct hda_board_config stac922x_cfg_tbl[] = { | 525 | static const char *stac922x_models[STAC_922X_MODELS] = { |
375 | { .modelname = "5stack", .config = STAC_D945GTP5 }, | 526 | [STAC_D945_REF] = "ref", |
376 | { .modelname = "3stack", .config = STAC_D945GTP3 }, | 527 | [STAC_D945GTP5] = "5stack", |
377 | { .modelname = "ref", | 528 | [STAC_D945GTP3] = "3stack", |
378 | .pci_subvendor = PCI_VENDOR_ID_INTEL, | 529 | [STAC_MACMINI] = "macmini", |
379 | .pci_subdevice = 0x2668, /* DFI LanParty */ | 530 | }; |
380 | .config = STAC_REF }, /* SigmaTel reference board */ | 531 | |
381 | /* Intel 945G based systems */ | 532 | static struct snd_pci_quirk stac922x_cfg_tbl[] = { |
382 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | 533 | /* SigmaTel reference board */ |
383 | .pci_subdevice = 0x0101, | 534 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, |
384 | .config = STAC_D945GTP3 }, /* Intel D945GTP - 3 Stack */ | 535 | "DFI LanParty", STAC_D945_REF), |
385 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | 536 | /* Intel 945G based systems */ |
386 | .pci_subdevice = 0x0202, | 537 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0101, |
387 | .config = STAC_D945GTP3 }, /* Intel D945GNT - 3 Stack */ | 538 | "Intel D945G", STAC_D945GTP3), |
388 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | 539 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0202, |
389 | .pci_subdevice = 0x0606, | 540 | "Intel D945G", STAC_D945GTP3), |
390 | .config = STAC_D945GTP3 }, /* Intel D945GTP - 3 Stack */ | 541 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0606, |
391 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | 542 | "Intel D945G", STAC_D945GTP3), |
392 | .pci_subdevice = 0x0601, | 543 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0601, |
393 | .config = STAC_D945GTP3 }, /* Intel D945GTP - 3 Stack */ | 544 | "Intel D945G", STAC_D945GTP3), |
394 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | 545 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0111, |
395 | .pci_subdevice = 0x0111, | 546 | "Intel D945G", STAC_D945GTP3), |
396 | .config = STAC_D945GTP3 }, /* Intel D945GZP - 3 Stack */ | 547 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1115, |
397 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | 548 | "Intel D945G", STAC_D945GTP3), |
398 | .pci_subdevice = 0x1115, | 549 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1116, |
399 | .config = STAC_D945GTP3 }, /* Intel D945GPM - 3 Stack */ | 550 | "Intel D945G", STAC_D945GTP3), |
400 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | 551 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1117, |
401 | .pci_subdevice = 0x1116, | 552 | "Intel D945G", STAC_D945GTP3), |
402 | .config = STAC_D945GTP3 }, /* Intel D945GBO - 3 Stack */ | 553 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1118, |
403 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | 554 | "Intel D945G", STAC_D945GTP3), |
404 | .pci_subdevice = 0x1117, | 555 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1119, |
405 | .config = STAC_D945GTP3 }, /* Intel D945GPM - 3 Stack */ | 556 | "Intel D945G", STAC_D945GTP3), |
406 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | 557 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x8826, |
407 | .pci_subdevice = 0x1118, | 558 | "Intel D945G", STAC_D945GTP3), |
408 | .config = STAC_D945GTP3 }, /* Intel D945GPM - 3 Stack */ | 559 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5049, |
409 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | 560 | "Intel D945G", STAC_D945GTP3), |
410 | .pci_subdevice = 0x1119, | 561 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5055, |
411 | .config = STAC_D945GTP3 }, /* Intel D945GPM - 3 Stack */ | 562 | "Intel D945G", STAC_D945GTP3), |
412 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | 563 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5048, |
413 | .pci_subdevice = 0x8826, | 564 | "Intel D945G", STAC_D945GTP3), |
414 | .config = STAC_D945GTP3 }, /* Intel D945GPM - 3 Stack */ | 565 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0110, |
415 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | 566 | "Intel D945G", STAC_D945GTP3), |
416 | .pci_subdevice = 0x5049, | 567 | /* Intel D945G 5-stack systems */ |
417 | .config = STAC_D945GTP3 }, /* Intel D945GCZ - 3 Stack */ | 568 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0404, |
418 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | 569 | "Intel D945G", STAC_D945GTP5), |
419 | .pci_subdevice = 0x5055, | 570 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0303, |
420 | .config = STAC_D945GTP3 }, /* Intel D945GCZ - 3 Stack */ | 571 | "Intel D945G", STAC_D945GTP5), |
421 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | 572 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0013, |
422 | .pci_subdevice = 0x5048, | 573 | "Intel D945G", STAC_D945GTP5), |
423 | .config = STAC_D945GTP3 }, /* Intel D945GPB - 3 Stack */ | 574 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0417, |
424 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | 575 | "Intel D945G", STAC_D945GTP5), |
425 | .pci_subdevice = 0x0110, | 576 | /* Intel 945P based systems */ |
426 | .config = STAC_D945GTP3 }, /* Intel D945GLR - 3 Stack */ | 577 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0b0b, |
427 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | 578 | "Intel D945P", STAC_D945GTP3), |
428 | .pci_subdevice = 0x0404, | 579 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0112, |
429 | .config = STAC_D945GTP5 }, /* Intel D945GTP - 5 Stack */ | 580 | "Intel D945P", STAC_D945GTP3), |
430 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | 581 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0d0d, |
431 | .pci_subdevice = 0x0303, | 582 | "Intel D945P", STAC_D945GTP3), |
432 | .config = STAC_D945GTP5 }, /* Intel D945GNT - 5 Stack */ | 583 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0909, |
433 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | 584 | "Intel D945P", STAC_D945GTP3), |
434 | .pci_subdevice = 0x0013, | 585 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0505, |
435 | .config = STAC_D945GTP5 }, /* Intel D955XBK - 5 Stack */ | 586 | "Intel D945P", STAC_D945GTP3), |
436 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | 587 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0707, |
437 | .pci_subdevice = 0x0417, | 588 | "Intel D945P", STAC_D945GTP5), |
438 | .config = STAC_D945GTP5 }, /* Intel D975XBK - 5 Stack */ | 589 | /* other systems */ |
439 | /* Intel 945P based systems */ | 590 | /* Apple Mac Mini (early 2006) */ |
440 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | 591 | SND_PCI_QUIRK(0x8384, 0x7680, |
441 | .pci_subdevice = 0x0b0b, | 592 | "Mac Mini", STAC_MACMINI), |
442 | .config = STAC_D945GTP3 }, /* Intel D945PSN - 3 Stack */ | ||
443 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
444 | .pci_subdevice = 0x0112, | ||
445 | .config = STAC_D945GTP3 }, /* Intel D945PLN - 3 Stack */ | ||
446 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
447 | .pci_subdevice = 0x0d0d, | ||
448 | .config = STAC_D945GTP3 }, /* Intel D945PLM - 3 Stack */ | ||
449 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
450 | .pci_subdevice = 0x0909, | ||
451 | .config = STAC_D945GTP3 }, /* Intel D945PAW - 3 Stack */ | ||
452 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
453 | .pci_subdevice = 0x0505, | ||
454 | .config = STAC_D945GTP3 }, /* Intel D945PLM - 3 Stack */ | ||
455 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
456 | .pci_subdevice = 0x0707, | ||
457 | .config = STAC_D945GTP5 }, /* Intel D945PSV - 5 Stack */ | ||
458 | /* other systems */ | ||
459 | { .pci_subvendor = 0x8384, | ||
460 | .pci_subdevice = 0x7680, | ||
461 | .config = STAC_MACMINI }, /* Apple Mac Mini (early 2006) */ | ||
462 | {} /* terminator */ | 593 | {} /* terminator */ |
463 | }; | 594 | }; |
464 | 595 | ||
@@ -484,120 +615,72 @@ static unsigned int d965_5st_pin_configs[14] = { | |||
484 | }; | 615 | }; |
485 | 616 | ||
486 | static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = { | 617 | static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = { |
487 | [STAC_REF] = ref927x_pin_configs, | 618 | [STAC_D965_REF] = ref927x_pin_configs, |
488 | [STAC_D965_3ST] = d965_3st_pin_configs, | 619 | [STAC_D965_3ST] = d965_3st_pin_configs, |
489 | [STAC_D965_5ST] = d965_5st_pin_configs, | 620 | [STAC_D965_5ST] = d965_5st_pin_configs, |
490 | }; | 621 | }; |
491 | 622 | ||
492 | static struct hda_board_config stac927x_cfg_tbl[] = { | 623 | static const char *stac927x_models[STAC_927X_MODELS] = { |
493 | { .modelname = "5stack", .config = STAC_D965_5ST }, | 624 | [STAC_D965_REF] = "ref", |
494 | { .modelname = "3stack", .config = STAC_D965_3ST }, | 625 | [STAC_D965_3ST] = "3stack", |
495 | { .modelname = "ref", | 626 | [STAC_D965_5ST] = "5stack", |
496 | .pci_subvendor = PCI_VENDOR_ID_INTEL, | 627 | }; |
497 | .pci_subdevice = 0x2668, /* DFI LanParty */ | 628 | |
498 | .config = STAC_REF }, /* SigmaTel reference board */ | 629 | static struct snd_pci_quirk stac927x_cfg_tbl[] = { |
630 | /* SigmaTel reference board */ | ||
631 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, | ||
632 | "DFI LanParty", STAC_D965_REF), | ||
499 | /* Intel 946 based systems */ | 633 | /* Intel 946 based systems */ |
500 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | 634 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x3d01, "Intel D946", STAC_D965_3ST), |
501 | .pci_subdevice = 0x3d01, | 635 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0xa301, "Intel D946", STAC_D965_3ST), |
502 | .config = STAC_D965_3ST }, /* D946 configuration */ | ||
503 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
504 | .pci_subdevice = 0xa301, | ||
505 | .config = STAC_D965_3ST }, /* Intel D946GZT - 3 stack */ | ||
506 | /* 965 based 3 stack systems */ | 636 | /* 965 based 3 stack systems */ |
507 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | 637 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2116, "Intel D965", STAC_D965_3ST), |
508 | .pci_subdevice = 0x2116, | 638 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2115, "Intel D965", STAC_D965_3ST), |
509 | .config = STAC_D965_3ST }, /* Intel D965 3Stack config */ | 639 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2114, "Intel D965", STAC_D965_3ST), |
510 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | 640 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2113, "Intel D965", STAC_D965_3ST), |
511 | .pci_subdevice = 0x2115, | 641 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2112, "Intel D965", STAC_D965_3ST), |
512 | .config = STAC_D965_3ST }, /* Intel DQ965WC - 3 Stack */ | 642 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2111, "Intel D965", STAC_D965_3ST), |
513 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | 643 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2110, "Intel D965", STAC_D965_3ST), |
514 | .pci_subdevice = 0x2114, | 644 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2009, "Intel D965", STAC_D965_3ST), |
515 | .config = STAC_D965_3ST }, /* Intel D965 3Stack config */ | 645 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2008, "Intel D965", STAC_D965_3ST), |
516 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | 646 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2007, "Intel D965", STAC_D965_3ST), |
517 | .pci_subdevice = 0x2113, | 647 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2006, "Intel D965", STAC_D965_3ST), |
518 | .config = STAC_D965_3ST }, /* Intel D965 3Stack config */ | 648 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2005, "Intel D965", STAC_D965_3ST), |
519 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | 649 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2004, "Intel D965", STAC_D965_3ST), |
520 | .pci_subdevice = 0x2112, | 650 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2003, "Intel D965", STAC_D965_3ST), |
521 | .config = STAC_D965_3ST }, /* Intel DG965MS - 3 Stack */ | 651 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2002, "Intel D965", STAC_D965_3ST), |
522 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | 652 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2001, "Intel D965", STAC_D965_3ST), |
523 | .pci_subdevice = 0x2111, | ||
524 | .config = STAC_D965_3ST }, /* Intel D965 3Stack config */ | ||
525 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
526 | .pci_subdevice = 0x2110, | ||
527 | .config = STAC_D965_3ST }, /* Intel D965 3Stack config */ | ||
528 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
529 | .pci_subdevice = 0x2009, | ||
530 | .config = STAC_D965_3ST }, /* Intel D965 3Stack config */ | ||
531 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
532 | .pci_subdevice = 0x2008, | ||
533 | .config = STAC_D965_3ST }, /* Intel DQ965GF - 3 Stack */ | ||
534 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
535 | .pci_subdevice = 0x2007, | ||
536 | .config = STAC_D965_3ST }, /* Intel D965 3Stack config */ | ||
537 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
538 | .pci_subdevice = 0x2006, | ||
539 | .config = STAC_D965_3ST }, /* Intel D965 3Stack config */ | ||
540 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
541 | .pci_subdevice = 0x2005, | ||
542 | .config = STAC_D965_3ST }, /* Intel D965 3Stack config */ | ||
543 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
544 | .pci_subdevice = 0x2004, | ||
545 | .config = STAC_D965_3ST }, /* Intel D965 3Stack config */ | ||
546 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
547 | .pci_subdevice = 0x2003, | ||
548 | .config = STAC_D965_3ST }, /* Intel D965 3Stack config */ | ||
549 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
550 | .pci_subdevice = 0x2002, | ||
551 | .config = STAC_D965_3ST }, /* Intel D965 3Stack config */ | ||
552 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
553 | .pci_subdevice = 0x2001, | ||
554 | .config = STAC_D965_3ST }, /* Intel DQ965GF - 3 Stack */ | ||
555 | /* 965 based 5 stack systems */ | 653 | /* 965 based 5 stack systems */ |
556 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | 654 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2301, "Intel D965", STAC_D965_5ST), |
557 | .pci_subdevice = 0x2301, | 655 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2302, "Intel D965", STAC_D965_5ST), |
558 | .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */ | 656 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2303, "Intel D965", STAC_D965_5ST), |
559 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | 657 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2304, "Intel D965", STAC_D965_5ST), |
560 | .pci_subdevice = 0x2302, | 658 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2305, "Intel D965", STAC_D965_5ST), |
561 | .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */ | 659 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2501, "Intel D965", STAC_D965_5ST), |
562 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | 660 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2502, "Intel D965", STAC_D965_5ST), |
563 | .pci_subdevice = 0x2303, | 661 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2503, "Intel D965", STAC_D965_5ST), |
564 | .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */ | 662 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2504, "Intel D965", STAC_D965_5ST), |
565 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
566 | .pci_subdevice = 0x2304, | ||
567 | .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */ | ||
568 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
569 | .pci_subdevice = 0x2305, | ||
570 | .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */ | ||
571 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
572 | .pci_subdevice = 0x2501, | ||
573 | .config = STAC_D965_5ST }, /* Intel DG965MQ - 5 Stack */ | ||
574 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
575 | .pci_subdevice = 0x2502, | ||
576 | .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */ | ||
577 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
578 | .pci_subdevice = 0x2503, | ||
579 | .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */ | ||
580 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
581 | .pci_subdevice = 0x2504, | ||
582 | .config = STAC_D965_5ST }, /* Intel DQ965GF - 5 Stack */ | ||
583 | {} /* terminator */ | 663 | {} /* terminator */ |
584 | }; | 664 | }; |
585 | 665 | ||
586 | static unsigned int ref9205_pin_configs[12] = { | 666 | static unsigned int ref9205_pin_configs[12] = { |
587 | 0x40000100, 0x40000100, 0x01016011, 0x01014010, | 667 | 0x40000100, 0x40000100, 0x01016011, 0x01014010, |
588 | 0x01813122, 0x01a19021, 0x40000100, 0x40000100, | 668 | 0x01813122, 0x01a19021, 0x40000100, 0x40000100, |
589 | 0x40000100, 0x40000100, 0x01441030, 0x01c41030 | 669 | 0x90a000f0, 0x90a000f0, 0x01441030, 0x01c41030 |
590 | }; | 670 | }; |
591 | 671 | ||
592 | static unsigned int *stac9205_brd_tbl[] = { | 672 | static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = { |
593 | ref9205_pin_configs, | 673 | ref9205_pin_configs, |
594 | }; | 674 | }; |
595 | 675 | ||
596 | static struct hda_board_config stac9205_cfg_tbl[] = { | 676 | static const char *stac9205_models[STAC_9205_MODELS] = { |
597 | { .modelname = "ref", | 677 | [STAC_9205_REF] = "ref", |
598 | .pci_subvendor = PCI_VENDOR_ID_INTEL, | 678 | }; |
599 | .pci_subdevice = 0x2668, /* DFI LanParty */ | 679 | |
600 | .config = STAC_REF }, /* SigmaTel reference board */ | 680 | static struct snd_pci_quirk stac9205_cfg_tbl[] = { |
681 | /* SigmaTel reference board */ | ||
682 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, | ||
683 | "DFI LanParty", STAC_9205_REF), | ||
601 | {} /* terminator */ | 684 | {} /* terminator */ |
602 | }; | 685 | }; |
603 | 686 | ||
@@ -1154,6 +1237,58 @@ static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec, | |||
1154 | return 0; | 1237 | return 0; |
1155 | } | 1238 | } |
1156 | 1239 | ||
1240 | /* labels for dmic mux inputs */ | ||
1241 | static const char *stac92xx_dmic_labels[5] = { | ||
1242 | "Analog Inputs", "Digital Mic 1", "Digital Mic 2", | ||
1243 | "Digital Mic 3", "Digital Mic 4" | ||
1244 | }; | ||
1245 | |||
1246 | /* create playback/capture controls for input pins on dmic capable codecs */ | ||
1247 | static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec, | ||
1248 | const struct auto_pin_cfg *cfg) | ||
1249 | { | ||
1250 | struct sigmatel_spec *spec = codec->spec; | ||
1251 | struct hda_input_mux *dimux = &spec->private_dimux; | ||
1252 | hda_nid_t con_lst[HDA_MAX_NUM_INPUTS]; | ||
1253 | int i, j; | ||
1254 | |||
1255 | dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0]; | ||
1256 | dimux->items[dimux->num_items].index = 0; | ||
1257 | dimux->num_items++; | ||
1258 | |||
1259 | for (i = 0; i < spec->num_dmics; i++) { | ||
1260 | int index; | ||
1261 | int num_cons; | ||
1262 | unsigned int def_conf; | ||
1263 | |||
1264 | def_conf = snd_hda_codec_read(codec, | ||
1265 | spec->dmic_nids[i], | ||
1266 | 0, | ||
1267 | AC_VERB_GET_CONFIG_DEFAULT, | ||
1268 | 0); | ||
1269 | if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) | ||
1270 | continue; | ||
1271 | |||
1272 | num_cons = snd_hda_get_connections(codec, | ||
1273 | spec->dmux_nid, | ||
1274 | con_lst, | ||
1275 | HDA_MAX_NUM_INPUTS); | ||
1276 | for (j = 0; j < num_cons; j++) | ||
1277 | if (con_lst[j] == spec->dmic_nids[i]) { | ||
1278 | index = j; | ||
1279 | goto found; | ||
1280 | } | ||
1281 | continue; | ||
1282 | found: | ||
1283 | dimux->items[dimux->num_items].label = | ||
1284 | stac92xx_dmic_labels[dimux->num_items]; | ||
1285 | dimux->items[dimux->num_items].index = index; | ||
1286 | dimux->num_items++; | ||
1287 | } | ||
1288 | |||
1289 | return 0; | ||
1290 | } | ||
1291 | |||
1157 | /* create playback/capture controls for input pins */ | 1292 | /* create playback/capture controls for input pins */ |
1158 | static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) | 1293 | static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) |
1159 | { | 1294 | { |
@@ -1238,7 +1373,9 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out | |||
1238 | struct sigmatel_spec *spec = codec->spec; | 1373 | struct sigmatel_spec *spec = codec->spec; |
1239 | int err; | 1374 | int err; |
1240 | 1375 | ||
1241 | if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0) | 1376 | if ((err = snd_hda_parse_pin_def_config(codec, |
1377 | &spec->autocfg, | ||
1378 | spec->dmic_nids)) < 0) | ||
1242 | return err; | 1379 | return err; |
1243 | if (! spec->autocfg.line_outs) | 1380 | if (! spec->autocfg.line_outs) |
1244 | return 0; /* can't find valid pin config */ | 1381 | return 0; /* can't find valid pin config */ |
@@ -1254,6 +1391,11 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out | |||
1254 | (err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0) | 1391 | (err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0) |
1255 | return err; | 1392 | return err; |
1256 | 1393 | ||
1394 | if (spec->num_dmics > 0) | ||
1395 | if ((err = stac92xx_auto_create_dmic_input_ctls(codec, | ||
1396 | &spec->autocfg)) < 0) | ||
1397 | return err; | ||
1398 | |||
1257 | spec->multiout.max_channels = spec->multiout.num_dacs * 2; | 1399 | spec->multiout.max_channels = spec->multiout.num_dacs * 2; |
1258 | if (spec->multiout.max_channels > 2) | 1400 | if (spec->multiout.max_channels > 2) |
1259 | spec->surr_switch = 1; | 1401 | spec->surr_switch = 1; |
@@ -1267,6 +1409,7 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out | |||
1267 | spec->mixers[spec->num_mixers++] = spec->kctl_alloc; | 1409 | spec->mixers[spec->num_mixers++] = spec->kctl_alloc; |
1268 | 1410 | ||
1269 | spec->input_mux = &spec->private_imux; | 1411 | spec->input_mux = &spec->private_imux; |
1412 | spec->dinput_mux = &spec->private_dimux; | ||
1270 | 1413 | ||
1271 | return 1; | 1414 | return 1; |
1272 | } | 1415 | } |
@@ -1366,6 +1509,7 @@ static int stac9200_parse_auto_config(struct hda_codec *codec) | |||
1366 | spec->mixers[spec->num_mixers++] = spec->kctl_alloc; | 1509 | spec->mixers[spec->num_mixers++] = spec->kctl_alloc; |
1367 | 1510 | ||
1368 | spec->input_mux = &spec->private_imux; | 1511 | spec->input_mux = &spec->private_imux; |
1512 | spec->dinput_mux = &spec->private_dimux; | ||
1369 | 1513 | ||
1370 | return 1; | 1514 | return 1; |
1371 | } | 1515 | } |
@@ -1448,6 +1592,11 @@ static int stac92xx_init(struct hda_codec *codec) | |||
1448 | stac92xx_auto_set_pinctl(codec, nid, pinctl); | 1592 | stac92xx_auto_set_pinctl(codec, nid, pinctl); |
1449 | } | 1593 | } |
1450 | } | 1594 | } |
1595 | if (spec->num_dmics > 0) | ||
1596 | for (i = 0; i < spec->num_dmics; i++) | ||
1597 | stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i], | ||
1598 | AC_PINCTL_IN_EN); | ||
1599 | |||
1451 | if (cfg->dig_out_pin) | 1600 | if (cfg->dig_out_pin) |
1452 | stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin, | 1601 | stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin, |
1453 | AC_PINCTL_OUT_EN); | 1602 | AC_PINCTL_OUT_EN); |
@@ -1598,7 +1747,9 @@ static int patch_stac9200(struct hda_codec *codec) | |||
1598 | codec->spec = spec; | 1747 | codec->spec = spec; |
1599 | spec->num_pins = 8; | 1748 | spec->num_pins = 8; |
1600 | spec->pin_nids = stac9200_pin_nids; | 1749 | spec->pin_nids = stac9200_pin_nids; |
1601 | spec->board_config = snd_hda_check_board_config(codec, stac9200_cfg_tbl); | 1750 | spec->board_config = snd_hda_check_board_config(codec, STAC_9200_MODELS, |
1751 | stac9200_models, | ||
1752 | stac9200_cfg_tbl); | ||
1602 | if (spec->board_config < 0) { | 1753 | if (spec->board_config < 0) { |
1603 | snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, using BIOS defaults\n"); | 1754 | snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, using BIOS defaults\n"); |
1604 | err = stac92xx_save_bios_config_regs(codec); | 1755 | err = stac92xx_save_bios_config_regs(codec); |
@@ -1618,6 +1769,7 @@ static int patch_stac9200(struct hda_codec *codec) | |||
1618 | spec->adc_nids = stac9200_adc_nids; | 1769 | spec->adc_nids = stac9200_adc_nids; |
1619 | spec->mux_nids = stac9200_mux_nids; | 1770 | spec->mux_nids = stac9200_mux_nids; |
1620 | spec->num_muxes = 1; | 1771 | spec->num_muxes = 1; |
1772 | spec->num_dmics = 0; | ||
1621 | 1773 | ||
1622 | spec->init = stac9200_core_init; | 1774 | spec->init = stac9200_core_init; |
1623 | spec->mixer = stac9200_mixer; | 1775 | spec->mixer = stac9200_mixer; |
@@ -1633,6 +1785,56 @@ static int patch_stac9200(struct hda_codec *codec) | |||
1633 | return 0; | 1785 | return 0; |
1634 | } | 1786 | } |
1635 | 1787 | ||
1788 | static int patch_stac925x(struct hda_codec *codec) | ||
1789 | { | ||
1790 | struct sigmatel_spec *spec; | ||
1791 | int err; | ||
1792 | |||
1793 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
1794 | if (spec == NULL) | ||
1795 | return -ENOMEM; | ||
1796 | |||
1797 | codec->spec = spec; | ||
1798 | spec->num_pins = 8; | ||
1799 | spec->pin_nids = stac925x_pin_nids; | ||
1800 | spec->board_config = snd_hda_check_board_config(codec, STAC_925x_MODELS, | ||
1801 | stac925x_models, | ||
1802 | stac925x_cfg_tbl); | ||
1803 | if (spec->board_config < 0) { | ||
1804 | snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC925x, using BIOS defaults\n"); | ||
1805 | err = stac92xx_save_bios_config_regs(codec); | ||
1806 | if (err < 0) { | ||
1807 | stac92xx_free(codec); | ||
1808 | return err; | ||
1809 | } | ||
1810 | spec->pin_configs = spec->bios_pin_configs; | ||
1811 | } else if (stac925x_brd_tbl[spec->board_config] != NULL){ | ||
1812 | spec->pin_configs = stac925x_brd_tbl[spec->board_config]; | ||
1813 | stac92xx_set_config_regs(codec); | ||
1814 | } | ||
1815 | |||
1816 | spec->multiout.max_channels = 2; | ||
1817 | spec->multiout.num_dacs = 1; | ||
1818 | spec->multiout.dac_nids = stac925x_dac_nids; | ||
1819 | spec->adc_nids = stac925x_adc_nids; | ||
1820 | spec->mux_nids = stac925x_mux_nids; | ||
1821 | spec->num_muxes = 1; | ||
1822 | spec->num_dmics = 0; | ||
1823 | |||
1824 | spec->init = stac925x_core_init; | ||
1825 | spec->mixer = stac925x_mixer; | ||
1826 | |||
1827 | err = stac92xx_parse_auto_config(codec, 0x8, 0x7); | ||
1828 | if (err < 0) { | ||
1829 | stac92xx_free(codec); | ||
1830 | return err; | ||
1831 | } | ||
1832 | |||
1833 | codec->patch_ops = stac92xx_patch_ops; | ||
1834 | |||
1835 | return 0; | ||
1836 | } | ||
1837 | |||
1636 | static int patch_stac922x(struct hda_codec *codec) | 1838 | static int patch_stac922x(struct hda_codec *codec) |
1637 | { | 1839 | { |
1638 | struct sigmatel_spec *spec; | 1840 | struct sigmatel_spec *spec; |
@@ -1645,7 +1847,9 @@ static int patch_stac922x(struct hda_codec *codec) | |||
1645 | codec->spec = spec; | 1847 | codec->spec = spec; |
1646 | spec->num_pins = 10; | 1848 | spec->num_pins = 10; |
1647 | spec->pin_nids = stac922x_pin_nids; | 1849 | spec->pin_nids = stac922x_pin_nids; |
1648 | spec->board_config = snd_hda_check_board_config(codec, stac922x_cfg_tbl); | 1850 | spec->board_config = snd_hda_check_board_config(codec, STAC_922X_MODELS, |
1851 | stac922x_models, | ||
1852 | stac922x_cfg_tbl); | ||
1649 | if (spec->board_config < 0) { | 1853 | if (spec->board_config < 0) { |
1650 | snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, " | 1854 | snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, " |
1651 | "using BIOS defaults\n"); | 1855 | "using BIOS defaults\n"); |
@@ -1663,6 +1867,7 @@ static int patch_stac922x(struct hda_codec *codec) | |||
1663 | spec->adc_nids = stac922x_adc_nids; | 1867 | spec->adc_nids = stac922x_adc_nids; |
1664 | spec->mux_nids = stac922x_mux_nids; | 1868 | spec->mux_nids = stac922x_mux_nids; |
1665 | spec->num_muxes = 2; | 1869 | spec->num_muxes = 2; |
1870 | spec->num_dmics = 0; | ||
1666 | 1871 | ||
1667 | spec->init = stac922x_core_init; | 1872 | spec->init = stac922x_core_init; |
1668 | spec->mixer = stac922x_mixer; | 1873 | spec->mixer = stac922x_mixer; |
@@ -1695,7 +1900,9 @@ static int patch_stac927x(struct hda_codec *codec) | |||
1695 | codec->spec = spec; | 1900 | codec->spec = spec; |
1696 | spec->num_pins = 14; | 1901 | spec->num_pins = 14; |
1697 | spec->pin_nids = stac927x_pin_nids; | 1902 | spec->pin_nids = stac927x_pin_nids; |
1698 | spec->board_config = snd_hda_check_board_config(codec, stac927x_cfg_tbl); | 1903 | spec->board_config = snd_hda_check_board_config(codec, STAC_927X_MODELS, |
1904 | stac927x_models, | ||
1905 | stac927x_cfg_tbl); | ||
1699 | if (spec->board_config < 0) { | 1906 | if (spec->board_config < 0) { |
1700 | snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC927x, using BIOS defaults\n"); | 1907 | snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC927x, using BIOS defaults\n"); |
1701 | err = stac92xx_save_bios_config_regs(codec); | 1908 | err = stac92xx_save_bios_config_regs(codec); |
@@ -1714,6 +1921,7 @@ static int patch_stac927x(struct hda_codec *codec) | |||
1714 | spec->adc_nids = stac927x_adc_nids; | 1921 | spec->adc_nids = stac927x_adc_nids; |
1715 | spec->mux_nids = stac927x_mux_nids; | 1922 | spec->mux_nids = stac927x_mux_nids; |
1716 | spec->num_muxes = 3; | 1923 | spec->num_muxes = 3; |
1924 | spec->num_dmics = 0; | ||
1717 | spec->init = d965_core_init; | 1925 | spec->init = d965_core_init; |
1718 | spec->mixer = stac9227_mixer; | 1926 | spec->mixer = stac9227_mixer; |
1719 | break; | 1927 | break; |
@@ -1721,6 +1929,7 @@ static int patch_stac927x(struct hda_codec *codec) | |||
1721 | spec->adc_nids = stac927x_adc_nids; | 1929 | spec->adc_nids = stac927x_adc_nids; |
1722 | spec->mux_nids = stac927x_mux_nids; | 1930 | spec->mux_nids = stac927x_mux_nids; |
1723 | spec->num_muxes = 3; | 1931 | spec->num_muxes = 3; |
1932 | spec->num_dmics = 0; | ||
1724 | spec->init = d965_core_init; | 1933 | spec->init = d965_core_init; |
1725 | spec->mixer = stac9227_mixer; | 1934 | spec->mixer = stac9227_mixer; |
1726 | break; | 1935 | break; |
@@ -1728,6 +1937,7 @@ static int patch_stac927x(struct hda_codec *codec) | |||
1728 | spec->adc_nids = stac927x_adc_nids; | 1937 | spec->adc_nids = stac927x_adc_nids; |
1729 | spec->mux_nids = stac927x_mux_nids; | 1938 | spec->mux_nids = stac927x_mux_nids; |
1730 | spec->num_muxes = 3; | 1939 | spec->num_muxes = 3; |
1940 | spec->num_dmics = 0; | ||
1731 | spec->init = stac927x_core_init; | 1941 | spec->init = stac927x_core_init; |
1732 | spec->mixer = stac927x_mixer; | 1942 | spec->mixer = stac927x_mixer; |
1733 | } | 1943 | } |
@@ -1757,7 +1967,9 @@ static int patch_stac9205(struct hda_codec *codec) | |||
1757 | codec->spec = spec; | 1967 | codec->spec = spec; |
1758 | spec->num_pins = 14; | 1968 | spec->num_pins = 14; |
1759 | spec->pin_nids = stac9205_pin_nids; | 1969 | spec->pin_nids = stac9205_pin_nids; |
1760 | spec->board_config = snd_hda_check_board_config(codec, stac9205_cfg_tbl); | 1970 | spec->board_config = snd_hda_check_board_config(codec, STAC_9205_MODELS, |
1971 | stac9205_models, | ||
1972 | stac9205_cfg_tbl); | ||
1761 | if (spec->board_config < 0) { | 1973 | if (spec->board_config < 0) { |
1762 | snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9205, using BIOS defaults\n"); | 1974 | snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9205, using BIOS defaults\n"); |
1763 | err = stac92xx_save_bios_config_regs(codec); | 1975 | err = stac92xx_save_bios_config_regs(codec); |
@@ -1773,13 +1985,28 @@ static int patch_stac9205(struct hda_codec *codec) | |||
1773 | 1985 | ||
1774 | spec->adc_nids = stac9205_adc_nids; | 1986 | spec->adc_nids = stac9205_adc_nids; |
1775 | spec->mux_nids = stac9205_mux_nids; | 1987 | spec->mux_nids = stac9205_mux_nids; |
1776 | spec->num_muxes = 3; | 1988 | spec->num_muxes = 2; |
1989 | spec->dmic_nids = stac9205_dmic_nids; | ||
1990 | spec->num_dmics = 2; | ||
1991 | spec->dmux_nid = 0x1d; | ||
1777 | 1992 | ||
1778 | spec->init = stac9205_core_init; | 1993 | spec->init = stac9205_core_init; |
1779 | spec->mixer = stac9205_mixer; | 1994 | spec->mixer = stac9205_mixer; |
1780 | 1995 | ||
1781 | spec->multiout.dac_nids = spec->dac_nids; | 1996 | spec->multiout.dac_nids = spec->dac_nids; |
1782 | 1997 | ||
1998 | /* Configure GPIO0 as EAPD output */ | ||
1999 | snd_hda_codec_write(codec, codec->afg, 0, | ||
2000 | AC_VERB_SET_GPIO_DIRECTION, 0x00000001); | ||
2001 | /* Configure GPIO0 as CMOS */ | ||
2002 | snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0x00000000); | ||
2003 | /* Assert GPIO0 high */ | ||
2004 | snd_hda_codec_write(codec, codec->afg, 0, | ||
2005 | AC_VERB_SET_GPIO_DATA, 0x00000001); | ||
2006 | /* Enable GPIO0 */ | ||
2007 | snd_hda_codec_write(codec, codec->afg, 0, | ||
2008 | AC_VERB_SET_GPIO_MASK, 0x00000001); | ||
2009 | |||
1783 | err = stac92xx_parse_auto_config(codec, 0x1f, 0x20); | 2010 | err = stac92xx_parse_auto_config(codec, 0x1f, 0x20); |
1784 | if (err < 0) { | 2011 | if (err < 0) { |
1785 | stac92xx_free(codec); | 2012 | stac92xx_free(codec); |
@@ -1963,18 +2190,19 @@ enum { /* FE and SZ series. id=0x83847661 and subsys=0x104D0700 or 104D1000. */ | |||
1963 | /* Unknown. id=0x83847661 and subsys=0x104D1200. */ | 2190 | /* Unknown. id=0x83847661 and subsys=0x104D1200. */ |
1964 | STAC9872K_VAIO, | 2191 | STAC9872K_VAIO, |
1965 | /* AR Series. id=0x83847664 and subsys=104D1300 */ | 2192 | /* AR Series. id=0x83847664 and subsys=104D1300 */ |
1966 | CXD9872AKD_VAIO | 2193 | CXD9872AKD_VAIO, |
1967 | }; | 2194 | STAC_9872_MODELS, |
1968 | 2195 | }; | |
1969 | static struct hda_board_config stac9872_cfg_tbl[] = { | 2196 | |
1970 | { .modelname = "vaio", .config = CXD9872RD_VAIO }, | 2197 | static const char *stac9872_models[STAC_9872_MODELS] = { |
1971 | { .modelname = "vaio-ar", .config = CXD9872AKD_VAIO }, | 2198 | [CXD9872RD_VAIO] = "vaio", |
1972 | { .pci_subvendor = 0x104d, .pci_subdevice = 0x81e6, | 2199 | [CXD9872AKD_VAIO] = "vaio-ar", |
1973 | .config = CXD9872RD_VAIO }, | 2200 | }; |
1974 | { .pci_subvendor = 0x104d, .pci_subdevice = 0x81ef, | 2201 | |
1975 | .config = CXD9872RD_VAIO }, | 2202 | static struct snd_pci_quirk stac9872_cfg_tbl[] = { |
1976 | { .pci_subvendor = 0x104d, .pci_subdevice = 0x81fd, | 2203 | SND_PCI_QUIRK(0x104d, 0x81e6, "Sony VAIO F/S", CXD9872RD_VAIO), |
1977 | .config = CXD9872AKD_VAIO }, | 2204 | SND_PCI_QUIRK(0x104d, 0x81ef, "Sony VAIO F/S", CXD9872RD_VAIO), |
2205 | SND_PCI_QUIRK(0x104d, 0x81fd, "Sony VAIO AR", CXD9872AKD_VAIO), | ||
1978 | {} | 2206 | {} |
1979 | }; | 2207 | }; |
1980 | 2208 | ||
@@ -1983,7 +2211,9 @@ static int patch_stac9872(struct hda_codec *codec) | |||
1983 | struct sigmatel_spec *spec; | 2211 | struct sigmatel_spec *spec; |
1984 | int board_config; | 2212 | int board_config; |
1985 | 2213 | ||
1986 | board_config = snd_hda_check_board_config(codec, stac9872_cfg_tbl); | 2214 | board_config = snd_hda_check_board_config(codec, STAC_9872_MODELS, |
2215 | stac9872_models, | ||
2216 | stac9872_cfg_tbl); | ||
1987 | if (board_config < 0) | 2217 | if (board_config < 0) |
1988 | /* unknown config, let generic-parser do its job... */ | 2218 | /* unknown config, let generic-parser do its job... */ |
1989 | return snd_hda_parse_generic_codec(codec); | 2219 | return snd_hda_parse_generic_codec(codec); |
@@ -2055,6 +2285,12 @@ struct hda_codec_preset snd_hda_preset_sigmatel[] = { | |||
2055 | { .id = 0x83847627, .name = "STAC9271D", .patch = patch_stac927x }, | 2285 | { .id = 0x83847627, .name = "STAC9271D", .patch = patch_stac927x }, |
2056 | { .id = 0x83847628, .name = "STAC9274X5NH", .patch = patch_stac927x }, | 2286 | { .id = 0x83847628, .name = "STAC9274X5NH", .patch = patch_stac927x }, |
2057 | { .id = 0x83847629, .name = "STAC9274D5NH", .patch = patch_stac927x }, | 2287 | { .id = 0x83847629, .name = "STAC9274D5NH", .patch = patch_stac927x }, |
2288 | { .id = 0x83847632, .name = "STAC9202", .patch = patch_stac925x }, | ||
2289 | { .id = 0x83847633, .name = "STAC9202D", .patch = patch_stac925x }, | ||
2290 | { .id = 0x83847634, .name = "STAC9250", .patch = patch_stac925x }, | ||
2291 | { .id = 0x83847635, .name = "STAC9250D", .patch = patch_stac925x }, | ||
2292 | { .id = 0x83847636, .name = "STAC9251", .patch = patch_stac925x }, | ||
2293 | { .id = 0x83847637, .name = "STAC9250D", .patch = patch_stac925x }, | ||
2058 | /* The following does not take into account .id=0x83847661 when subsys = | 2294 | /* The following does not take into account .id=0x83847661 when subsys = |
2059 | * 104D0C00 which is STAC9225s. Because of this, some SZ Notebooks are | 2295 | * 104D0C00 which is STAC9225s. Because of this, some SZ Notebooks are |
2060 | * currently not fully supported. | 2296 | * currently not fully supported. |
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c new file mode 100644 index 000000000000..4c839b031729 --- /dev/null +++ b/sound/pci/hda/patch_via.c | |||
@@ -0,0 +1,1396 @@ | |||
1 | /* | ||
2 | * Universal Interface for Intel High Definition Audio Codec | ||
3 | * | ||
4 | * HD audio interface patch for VIA VT1708 codec | ||
5 | * | ||
6 | * Copyright (c) 2006 Lydia Wang <lydiawang@viatech.com> | ||
7 | * Takashi Iwai <tiwai@suse.de> | ||
8 | * | ||
9 | * This driver is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This driver is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | */ | ||
23 | |||
24 | /* * * * * * * * * * * * * * Release History * * * * * * * * * * * * * * * * */ | ||
25 | /* */ | ||
26 | /* 2006-03-03 Lydia Wang Create the basic patch to support VT1708 codec */ | ||
27 | /* 2006-03-14 Lydia Wang Modify hard code for some pin widget nid */ | ||
28 | /* 2006-08-02 Lydia Wang Add support to VT1709 codec */ | ||
29 | /* 2006-09-08 Lydia Wang Fix internal loopback recording source select bug */ | ||
30 | /* */ | ||
31 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | ||
32 | |||
33 | |||
34 | #include <sound/driver.h> | ||
35 | #include <linux/init.h> | ||
36 | #include <linux/delay.h> | ||
37 | #include <linux/slab.h> | ||
38 | #include <linux/pci.h> | ||
39 | #include <sound/core.h> | ||
40 | #include "hda_codec.h" | ||
41 | #include "hda_local.h" | ||
42 | |||
43 | |||
44 | /* amp values */ | ||
45 | #define AMP_VAL_IDX_SHIFT 19 | ||
46 | #define AMP_VAL_IDX_MASK (0x0f<<19) | ||
47 | |||
48 | #define NUM_CONTROL_ALLOC 32 | ||
49 | #define NUM_VERB_ALLOC 32 | ||
50 | |||
51 | /* Pin Widget NID */ | ||
52 | #define VT1708_HP_NID 0x13 | ||
53 | #define VT1708_DIGOUT_NID 0x14 | ||
54 | #define VT1708_DIGIN_NID 0x16 | ||
55 | |||
56 | #define VT1709_HP_DAC_NID 0x28 | ||
57 | #define VT1709_DIGOUT_NID 0x13 | ||
58 | #define VT1709_DIGIN_NID 0x17 | ||
59 | |||
60 | #define IS_VT1708_VENDORID(x) ((x) >= 0x11061708 && (x) <= 0x1106170b) | ||
61 | #define IS_VT1709_10CH_VENDORID(x) ((x) >= 0x1106e710 && (x) <= 0x1106e713) | ||
62 | #define IS_VT1709_6CH_VENDORID(x) ((x) >= 0x1106e714 && (x) <= 0x1106e717) | ||
63 | |||
64 | |||
65 | enum { | ||
66 | VIA_CTL_WIDGET_VOL, | ||
67 | VIA_CTL_WIDGET_MUTE, | ||
68 | }; | ||
69 | |||
70 | enum { | ||
71 | AUTO_SEQ_FRONT, | ||
72 | AUTO_SEQ_SURROUND, | ||
73 | AUTO_SEQ_CENLFE, | ||
74 | AUTO_SEQ_SIDE | ||
75 | }; | ||
76 | |||
77 | static struct snd_kcontrol_new vt1708_control_templates[] = { | ||
78 | HDA_CODEC_VOLUME(NULL, 0, 0, 0), | ||
79 | HDA_CODEC_MUTE(NULL, 0, 0, 0), | ||
80 | }; | ||
81 | |||
82 | |||
83 | struct via_spec { | ||
84 | /* codec parameterization */ | ||
85 | struct snd_kcontrol_new *mixers[3]; | ||
86 | unsigned int num_mixers; | ||
87 | |||
88 | struct hda_verb *init_verbs; | ||
89 | |||
90 | char *stream_name_analog; | ||
91 | struct hda_pcm_stream *stream_analog_playback; | ||
92 | struct hda_pcm_stream *stream_analog_capture; | ||
93 | |||
94 | char *stream_name_digital; | ||
95 | struct hda_pcm_stream *stream_digital_playback; | ||
96 | struct hda_pcm_stream *stream_digital_capture; | ||
97 | |||
98 | /* playback */ | ||
99 | struct hda_multi_out multiout; | ||
100 | |||
101 | /* capture */ | ||
102 | unsigned int num_adc_nids; | ||
103 | hda_nid_t *adc_nids; | ||
104 | hda_nid_t dig_in_nid; | ||
105 | |||
106 | /* capture source */ | ||
107 | const struct hda_input_mux *input_mux; | ||
108 | unsigned int cur_mux[3]; | ||
109 | |||
110 | /* PCM information */ | ||
111 | struct hda_pcm pcm_rec[2]; | ||
112 | |||
113 | /* dynamic controls, init_verbs and input_mux */ | ||
114 | struct auto_pin_cfg autocfg; | ||
115 | unsigned int num_kctl_alloc, num_kctl_used; | ||
116 | struct snd_kcontrol_new *kctl_alloc; | ||
117 | struct hda_input_mux private_imux; | ||
118 | hda_nid_t private_dac_nids[4]; | ||
119 | }; | ||
120 | |||
121 | static hda_nid_t vt1708_adc_nids[2] = { | ||
122 | /* ADC1-2 */ | ||
123 | 0x15, 0x27 | ||
124 | }; | ||
125 | |||
126 | static hda_nid_t vt1709_adc_nids[3] = { | ||
127 | /* ADC1-2 */ | ||
128 | 0x14, 0x15, 0x16 | ||
129 | }; | ||
130 | |||
131 | /* add dynamic controls */ | ||
132 | static int via_add_control(struct via_spec *spec, int type, const char *name, | ||
133 | unsigned long val) | ||
134 | { | ||
135 | struct snd_kcontrol_new *knew; | ||
136 | |||
137 | if (spec->num_kctl_used >= spec->num_kctl_alloc) { | ||
138 | int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC; | ||
139 | |||
140 | /* array + terminator */ | ||
141 | knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); | ||
142 | if (!knew) | ||
143 | return -ENOMEM; | ||
144 | if (spec->kctl_alloc) { | ||
145 | memcpy(knew, spec->kctl_alloc, | ||
146 | sizeof(*knew) * spec->num_kctl_alloc); | ||
147 | kfree(spec->kctl_alloc); | ||
148 | } | ||
149 | spec->kctl_alloc = knew; | ||
150 | spec->num_kctl_alloc = num; | ||
151 | } | ||
152 | |||
153 | knew = &spec->kctl_alloc[spec->num_kctl_used]; | ||
154 | *knew = vt1708_control_templates[type]; | ||
155 | knew->name = kstrdup(name, GFP_KERNEL); | ||
156 | |||
157 | if (!knew->name) | ||
158 | return -ENOMEM; | ||
159 | knew->private_value = val; | ||
160 | spec->num_kctl_used++; | ||
161 | return 0; | ||
162 | } | ||
163 | |||
164 | /* create input playback/capture controls for the given pin */ | ||
165 | static int via_new_analog_input(struct via_spec *spec, hda_nid_t pin, | ||
166 | const char *ctlname, int idx, int mix_nid) | ||
167 | { | ||
168 | char name[32]; | ||
169 | int err; | ||
170 | |||
171 | sprintf(name, "%s Playback Volume", ctlname); | ||
172 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, | ||
173 | HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT)); | ||
174 | if (err < 0) | ||
175 | return err; | ||
176 | sprintf(name, "%s Playback Switch", ctlname); | ||
177 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, | ||
178 | HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT)); | ||
179 | if (err < 0) | ||
180 | return err; | ||
181 | return 0; | ||
182 | } | ||
183 | |||
184 | static void via_auto_set_output_and_unmute(struct hda_codec *codec, | ||
185 | hda_nid_t nid, int pin_type, | ||
186 | int dac_idx) | ||
187 | { | ||
188 | /* set as output */ | ||
189 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
190 | pin_type); | ||
191 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, | ||
192 | AMP_OUT_UNMUTE); | ||
193 | } | ||
194 | |||
195 | |||
196 | static void via_auto_init_multi_out(struct hda_codec *codec) | ||
197 | { | ||
198 | struct via_spec *spec = codec->spec; | ||
199 | int i; | ||
200 | |||
201 | for (i = 0; i <= AUTO_SEQ_SIDE; i++) { | ||
202 | hda_nid_t nid = spec->autocfg.line_out_pins[i]; | ||
203 | if (nid) | ||
204 | via_auto_set_output_and_unmute(codec, nid, PIN_OUT, i); | ||
205 | } | ||
206 | } | ||
207 | |||
208 | static void via_auto_init_hp_out(struct hda_codec *codec) | ||
209 | { | ||
210 | struct via_spec *spec = codec->spec; | ||
211 | hda_nid_t pin; | ||
212 | |||
213 | pin = spec->autocfg.hp_pins[0]; | ||
214 | if (pin) /* connect to front */ | ||
215 | via_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); | ||
216 | } | ||
217 | |||
218 | static void via_auto_init_analog_input(struct hda_codec *codec) | ||
219 | { | ||
220 | struct via_spec *spec = codec->spec; | ||
221 | int i; | ||
222 | |||
223 | for (i = 0; i < AUTO_PIN_LAST; i++) { | ||
224 | hda_nid_t nid = spec->autocfg.input_pins[i]; | ||
225 | |||
226 | snd_hda_codec_write(codec, nid, 0, | ||
227 | AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
228 | (i <= AUTO_PIN_FRONT_MIC ? | ||
229 | PIN_VREF50 : PIN_IN)); | ||
230 | |||
231 | } | ||
232 | } | ||
233 | /* | ||
234 | * input MUX handling | ||
235 | */ | ||
236 | static int via_mux_enum_info(struct snd_kcontrol *kcontrol, | ||
237 | struct snd_ctl_elem_info *uinfo) | ||
238 | { | ||
239 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
240 | struct via_spec *spec = codec->spec; | ||
241 | return snd_hda_input_mux_info(spec->input_mux, uinfo); | ||
242 | } | ||
243 | |||
244 | static int via_mux_enum_get(struct snd_kcontrol *kcontrol, | ||
245 | struct snd_ctl_elem_value *ucontrol) | ||
246 | { | ||
247 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
248 | struct via_spec *spec = codec->spec; | ||
249 | unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | ||
250 | |||
251 | ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx]; | ||
252 | return 0; | ||
253 | } | ||
254 | |||
255 | static int via_mux_enum_put(struct snd_kcontrol *kcontrol, | ||
256 | struct snd_ctl_elem_value *ucontrol) | ||
257 | { | ||
258 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
259 | struct via_spec *spec = codec->spec; | ||
260 | unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | ||
261 | unsigned int vendor_id = codec->vendor_id; | ||
262 | |||
263 | /* AIW0 lydia 060801 add for correct sw0 input select */ | ||
264 | if (IS_VT1708_VENDORID(vendor_id) && (adc_idx == 0)) | ||
265 | return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, | ||
266 | 0x18, &spec->cur_mux[adc_idx]); | ||
267 | else if ((IS_VT1709_10CH_VENDORID(vendor_id) || | ||
268 | IS_VT1709_6CH_VENDORID(vendor_id)) && (adc_idx == 0) ) | ||
269 | return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, | ||
270 | 0x19, &spec->cur_mux[adc_idx]); | ||
271 | else | ||
272 | return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, | ||
273 | spec->adc_nids[adc_idx], | ||
274 | &spec->cur_mux[adc_idx]); | ||
275 | } | ||
276 | |||
277 | /* capture mixer elements */ | ||
278 | static struct snd_kcontrol_new vt1708_capture_mixer[] = { | ||
279 | HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_INPUT), | ||
280 | HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_INPUT), | ||
281 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x27, 0x0, HDA_INPUT), | ||
282 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x27, 0x0, HDA_INPUT), | ||
283 | { | ||
284 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
285 | /* The multiple "Capture Source" controls confuse alsamixer | ||
286 | * So call somewhat different.. | ||
287 | * FIXME: the controls appear in the "playback" view! | ||
288 | */ | ||
289 | /* .name = "Capture Source", */ | ||
290 | .name = "Input Source", | ||
291 | .count = 1, | ||
292 | .info = via_mux_enum_info, | ||
293 | .get = via_mux_enum_get, | ||
294 | .put = via_mux_enum_put, | ||
295 | }, | ||
296 | { } /* end */ | ||
297 | }; | ||
298 | /* | ||
299 | * generic initialization of ADC, input mixers and output mixers | ||
300 | */ | ||
301 | static struct hda_verb vt1708_volume_init_verbs[] = { | ||
302 | /* | ||
303 | * Unmute ADC0-1 and set the default input to mic-in | ||
304 | */ | ||
305 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
306 | {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
307 | |||
308 | |||
309 | /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback | ||
310 | * mixer widget | ||
311 | */ | ||
312 | /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ | ||
313 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
314 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
315 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, | ||
316 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, | ||
317 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, | ||
318 | |||
319 | /* | ||
320 | * Set up output mixers (0x19 - 0x1b) | ||
321 | */ | ||
322 | /* set vol=0 to output mixers */ | ||
323 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
324 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
325 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
326 | |||
327 | /* Setup default input to PW4 */ | ||
328 | {0x20, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
329 | /* Set mic as default input of sw0 */ | ||
330 | {0x18, AC_VERB_SET_CONNECT_SEL, 0x2}, | ||
331 | /* PW9 Output enable */ | ||
332 | {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | ||
333 | }; | ||
334 | |||
335 | static int via_playback_pcm_open(struct hda_pcm_stream *hinfo, | ||
336 | struct hda_codec *codec, | ||
337 | struct snd_pcm_substream *substream) | ||
338 | { | ||
339 | struct via_spec *spec = codec->spec; | ||
340 | return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream); | ||
341 | } | ||
342 | |||
343 | static int via_playback_pcm_prepare(struct hda_pcm_stream *hinfo, | ||
344 | struct hda_codec *codec, | ||
345 | unsigned int stream_tag, | ||
346 | unsigned int format, | ||
347 | struct snd_pcm_substream *substream) | ||
348 | { | ||
349 | struct via_spec *spec = codec->spec; | ||
350 | return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, | ||
351 | stream_tag, format, substream); | ||
352 | } | ||
353 | |||
354 | static int via_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, | ||
355 | struct hda_codec *codec, | ||
356 | struct snd_pcm_substream *substream) | ||
357 | { | ||
358 | struct via_spec *spec = codec->spec; | ||
359 | return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); | ||
360 | } | ||
361 | |||
362 | /* | ||
363 | * Digital out | ||
364 | */ | ||
365 | static int via_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, | ||
366 | struct hda_codec *codec, | ||
367 | struct snd_pcm_substream *substream) | ||
368 | { | ||
369 | struct via_spec *spec = codec->spec; | ||
370 | return snd_hda_multi_out_dig_open(codec, &spec->multiout); | ||
371 | } | ||
372 | |||
373 | static int via_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, | ||
374 | struct hda_codec *codec, | ||
375 | struct snd_pcm_substream *substream) | ||
376 | { | ||
377 | struct via_spec *spec = codec->spec; | ||
378 | return snd_hda_multi_out_dig_close(codec, &spec->multiout); | ||
379 | } | ||
380 | |||
381 | /* | ||
382 | * Analog capture | ||
383 | */ | ||
384 | static int via_capture_pcm_prepare(struct hda_pcm_stream *hinfo, | ||
385 | struct hda_codec *codec, | ||
386 | unsigned int stream_tag, | ||
387 | unsigned int format, | ||
388 | struct snd_pcm_substream *substream) | ||
389 | { | ||
390 | struct via_spec *spec = codec->spec; | ||
391 | |||
392 | snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], | ||
393 | stream_tag, 0, format); | ||
394 | return 0; | ||
395 | } | ||
396 | |||
397 | static int via_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, | ||
398 | struct hda_codec *codec, | ||
399 | struct snd_pcm_substream *substream) | ||
400 | { | ||
401 | struct via_spec *spec = codec->spec; | ||
402 | snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], | ||
403 | 0, 0, 0); | ||
404 | return 0; | ||
405 | } | ||
406 | |||
407 | static struct hda_pcm_stream vt1708_pcm_analog_playback = { | ||
408 | .substreams = 1, | ||
409 | .channels_min = 2, | ||
410 | .channels_max = 8, | ||
411 | .nid = 0x10, /* NID to query formats and rates */ | ||
412 | .ops = { | ||
413 | .open = via_playback_pcm_open, | ||
414 | .prepare = via_playback_pcm_prepare, | ||
415 | .cleanup = via_playback_pcm_cleanup | ||
416 | }, | ||
417 | }; | ||
418 | |||
419 | static struct hda_pcm_stream vt1708_pcm_analog_capture = { | ||
420 | .substreams = 2, | ||
421 | .channels_min = 2, | ||
422 | .channels_max = 2, | ||
423 | .nid = 0x15, /* NID to query formats and rates */ | ||
424 | .ops = { | ||
425 | .prepare = via_capture_pcm_prepare, | ||
426 | .cleanup = via_capture_pcm_cleanup | ||
427 | }, | ||
428 | }; | ||
429 | |||
430 | static struct hda_pcm_stream vt1708_pcm_digital_playback = { | ||
431 | .substreams = 1, | ||
432 | .channels_min = 2, | ||
433 | .channels_max = 2, | ||
434 | /* NID is set in via_build_pcms */ | ||
435 | .ops = { | ||
436 | .open = via_dig_playback_pcm_open, | ||
437 | .close = via_dig_playback_pcm_close | ||
438 | }, | ||
439 | }; | ||
440 | |||
441 | static struct hda_pcm_stream vt1708_pcm_digital_capture = { | ||
442 | .substreams = 1, | ||
443 | .channels_min = 2, | ||
444 | .channels_max = 2, | ||
445 | }; | ||
446 | |||
447 | static int via_build_controls(struct hda_codec *codec) | ||
448 | { | ||
449 | struct via_spec *spec = codec->spec; | ||
450 | int err; | ||
451 | int i; | ||
452 | |||
453 | for (i = 0; i < spec->num_mixers; i++) { | ||
454 | err = snd_hda_add_new_ctls(codec, spec->mixers[i]); | ||
455 | if (err < 0) | ||
456 | return err; | ||
457 | } | ||
458 | |||
459 | if (spec->multiout.dig_out_nid) { | ||
460 | err = snd_hda_create_spdif_out_ctls(codec, | ||
461 | spec->multiout.dig_out_nid); | ||
462 | if (err < 0) | ||
463 | return err; | ||
464 | } | ||
465 | if (spec->dig_in_nid) { | ||
466 | err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); | ||
467 | if (err < 0) | ||
468 | return err; | ||
469 | } | ||
470 | return 0; | ||
471 | } | ||
472 | |||
473 | static int via_build_pcms(struct hda_codec *codec) | ||
474 | { | ||
475 | struct via_spec *spec = codec->spec; | ||
476 | struct hda_pcm *info = spec->pcm_rec; | ||
477 | |||
478 | codec->num_pcms = 1; | ||
479 | codec->pcm_info = info; | ||
480 | |||
481 | info->name = spec->stream_name_analog; | ||
482 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback); | ||
483 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0]; | ||
484 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture); | ||
485 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; | ||
486 | |||
487 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = | ||
488 | spec->multiout.max_channels; | ||
489 | |||
490 | if (spec->multiout.dig_out_nid || spec->dig_in_nid) { | ||
491 | codec->num_pcms++; | ||
492 | info++; | ||
493 | info->name = spec->stream_name_digital; | ||
494 | if (spec->multiout.dig_out_nid) { | ||
495 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = | ||
496 | *(spec->stream_digital_playback); | ||
497 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = | ||
498 | spec->multiout.dig_out_nid; | ||
499 | } | ||
500 | if (spec->dig_in_nid) { | ||
501 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = | ||
502 | *(spec->stream_digital_capture); | ||
503 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = | ||
504 | spec->dig_in_nid; | ||
505 | } | ||
506 | } | ||
507 | |||
508 | return 0; | ||
509 | } | ||
510 | |||
511 | static void via_free(struct hda_codec *codec) | ||
512 | { | ||
513 | struct via_spec *spec = codec->spec; | ||
514 | unsigned int i; | ||
515 | |||
516 | if (!spec) | ||
517 | return; | ||
518 | |||
519 | if (spec->kctl_alloc) { | ||
520 | for (i = 0; i < spec->num_kctl_used; i++) | ||
521 | kfree(spec->kctl_alloc[i].name); | ||
522 | kfree(spec->kctl_alloc); | ||
523 | } | ||
524 | |||
525 | kfree(codec->spec); | ||
526 | } | ||
527 | |||
528 | static int via_init(struct hda_codec *codec) | ||
529 | { | ||
530 | struct via_spec *spec = codec->spec; | ||
531 | snd_hda_sequence_write(codec, spec->init_verbs); | ||
532 | return 0; | ||
533 | } | ||
534 | |||
535 | #ifdef CONFIG_PM | ||
536 | /* | ||
537 | * resume | ||
538 | */ | ||
539 | static int via_resume(struct hda_codec *codec) | ||
540 | { | ||
541 | struct via_spec *spec = codec->spec; | ||
542 | int i; | ||
543 | |||
544 | via_init(codec); | ||
545 | for (i = 0; i < spec->num_mixers; i++) | ||
546 | snd_hda_resume_ctls(codec, spec->mixers[i]); | ||
547 | if (spec->multiout.dig_out_nid) | ||
548 | snd_hda_resume_spdif_out(codec); | ||
549 | if (spec->dig_in_nid) | ||
550 | snd_hda_resume_spdif_in(codec); | ||
551 | |||
552 | return 0; | ||
553 | } | ||
554 | #endif | ||
555 | |||
556 | /* | ||
557 | */ | ||
558 | static struct hda_codec_ops via_patch_ops = { | ||
559 | .build_controls = via_build_controls, | ||
560 | .build_pcms = via_build_pcms, | ||
561 | .init = via_init, | ||
562 | .free = via_free, | ||
563 | #ifdef CONFIG_PM | ||
564 | .resume = via_resume, | ||
565 | #endif | ||
566 | }; | ||
567 | |||
568 | /* fill in the dac_nids table from the parsed pin configuration */ | ||
569 | static int vt1708_auto_fill_dac_nids(struct via_spec *spec, | ||
570 | const struct auto_pin_cfg *cfg) | ||
571 | { | ||
572 | int i; | ||
573 | hda_nid_t nid; | ||
574 | |||
575 | spec->multiout.num_dacs = cfg->line_outs; | ||
576 | |||
577 | spec->multiout.dac_nids = spec->private_dac_nids; | ||
578 | |||
579 | for(i = 0; i < 4; i++) { | ||
580 | nid = cfg->line_out_pins[i]; | ||
581 | if (nid) { | ||
582 | /* config dac list */ | ||
583 | switch (i) { | ||
584 | case AUTO_SEQ_FRONT: | ||
585 | spec->multiout.dac_nids[i] = 0x10; | ||
586 | break; | ||
587 | case AUTO_SEQ_CENLFE: | ||
588 | spec->multiout.dac_nids[i] = 0x12; | ||
589 | break; | ||
590 | case AUTO_SEQ_SURROUND: | ||
591 | spec->multiout.dac_nids[i] = 0x13; | ||
592 | break; | ||
593 | case AUTO_SEQ_SIDE: | ||
594 | spec->multiout.dac_nids[i] = 0x11; | ||
595 | break; | ||
596 | } | ||
597 | } | ||
598 | } | ||
599 | |||
600 | return 0; | ||
601 | } | ||
602 | |||
603 | /* add playback controls from the parsed DAC table */ | ||
604 | static int vt1708_auto_create_multi_out_ctls(struct via_spec *spec, | ||
605 | const struct auto_pin_cfg *cfg) | ||
606 | { | ||
607 | char name[32]; | ||
608 | static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" }; | ||
609 | hda_nid_t nid, nid_vol = 0; | ||
610 | int i, err; | ||
611 | |||
612 | for (i = 0; i <= AUTO_SEQ_SIDE; i++) { | ||
613 | nid = cfg->line_out_pins[i]; | ||
614 | |||
615 | if (!nid) | ||
616 | continue; | ||
617 | |||
618 | if (i != AUTO_SEQ_FRONT) | ||
619 | nid_vol = 0x1b - i + 1; | ||
620 | |||
621 | if (i == AUTO_SEQ_CENLFE) { | ||
622 | /* Center/LFE */ | ||
623 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | ||
624 | "Center Playback Volume", | ||
625 | HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, HDA_OUTPUT)); | ||
626 | if (err < 0) | ||
627 | return err; | ||
628 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | ||
629 | "LFE Playback Volume", | ||
630 | HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT)); | ||
631 | if (err < 0) | ||
632 | return err; | ||
633 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, | ||
634 | "Center Playback Switch", | ||
635 | HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, HDA_OUTPUT)); | ||
636 | if (err < 0) | ||
637 | return err; | ||
638 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, | ||
639 | "LFE Playback Switch", | ||
640 | HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT)); | ||
641 | if (err < 0) | ||
642 | return err; | ||
643 | } else if (i == AUTO_SEQ_FRONT){ | ||
644 | /* add control to mixer index 0 */ | ||
645 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | ||
646 | "Master Front Playback Volume", | ||
647 | HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_INPUT)); | ||
648 | if (err < 0) | ||
649 | return err; | ||
650 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, | ||
651 | "Master Front Playback Switch", | ||
652 | HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_INPUT)); | ||
653 | if (err < 0) | ||
654 | return err; | ||
655 | |||
656 | /* add control to PW3 */ | ||
657 | sprintf(name, "%s Playback Volume", chname[i]); | ||
658 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, | ||
659 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT)); | ||
660 | if (err < 0) | ||
661 | return err; | ||
662 | sprintf(name, "%s Playback Switch", chname[i]); | ||
663 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, | ||
664 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT)); | ||
665 | if (err < 0) | ||
666 | return err; | ||
667 | } else { | ||
668 | sprintf(name, "%s Playback Volume", chname[i]); | ||
669 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, | ||
670 | HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT)); | ||
671 | if (err < 0) | ||
672 | return err; | ||
673 | sprintf(name, "%s Playback Switch", chname[i]); | ||
674 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, | ||
675 | HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT)); | ||
676 | if (err < 0) | ||
677 | return err; | ||
678 | } | ||
679 | } | ||
680 | |||
681 | return 0; | ||
682 | } | ||
683 | |||
684 | static int vt1708_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) | ||
685 | { | ||
686 | int err; | ||
687 | |||
688 | if (!pin) | ||
689 | return 0; | ||
690 | |||
691 | spec->multiout.hp_nid = VT1708_HP_NID; /* AOW3 */ | ||
692 | |||
693 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | ||
694 | "Headphone Playback Volume", | ||
695 | HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); | ||
696 | if (err < 0) | ||
697 | return err; | ||
698 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, | ||
699 | "Headphone Playback Switch", | ||
700 | HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); | ||
701 | if (err < 0) | ||
702 | return err; | ||
703 | |||
704 | return 0; | ||
705 | } | ||
706 | |||
707 | /* create playback/capture controls for input pins */ | ||
708 | static int vt1708_auto_create_analog_input_ctls(struct via_spec *spec, | ||
709 | const struct auto_pin_cfg *cfg) | ||
710 | { | ||
711 | static char *labels[] = { | ||
712 | "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL | ||
713 | }; | ||
714 | struct hda_input_mux *imux = &spec->private_imux; | ||
715 | int i, err, idx = 0; | ||
716 | |||
717 | /* for internal loopback recording select */ | ||
718 | imux->items[imux->num_items].label = "Stereo Mixer"; | ||
719 | imux->items[imux->num_items].index = idx; | ||
720 | imux->num_items++; | ||
721 | |||
722 | for (i = 0; i < AUTO_PIN_LAST; i++) { | ||
723 | if (!cfg->input_pins[i]) | ||
724 | continue; | ||
725 | |||
726 | switch (cfg->input_pins[i]) { | ||
727 | case 0x1d: /* Mic */ | ||
728 | idx = 2; | ||
729 | break; | ||
730 | |||
731 | case 0x1e: /* Line In */ | ||
732 | idx = 3; | ||
733 | break; | ||
734 | |||
735 | case 0x21: /* Front Mic */ | ||
736 | idx = 4; | ||
737 | break; | ||
738 | |||
739 | case 0x24: /* CD */ | ||
740 | idx = 1; | ||
741 | break; | ||
742 | } | ||
743 | err = via_new_analog_input(spec, cfg->input_pins[i], labels[i], | ||
744 | idx, 0x17); | ||
745 | if (err < 0) | ||
746 | return err; | ||
747 | imux->items[imux->num_items].label = labels[i]; | ||
748 | imux->items[imux->num_items].index = idx; | ||
749 | imux->num_items++; | ||
750 | } | ||
751 | return 0; | ||
752 | } | ||
753 | |||
754 | static int vt1708_parse_auto_config(struct hda_codec *codec) | ||
755 | { | ||
756 | struct via_spec *spec = codec->spec; | ||
757 | int err; | ||
758 | |||
759 | err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); | ||
760 | if (err < 0) | ||
761 | return err; | ||
762 | err = vt1708_auto_fill_dac_nids(spec, &spec->autocfg); | ||
763 | if (err < 0) | ||
764 | return err; | ||
765 | if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0]) | ||
766 | return 0; /* can't find valid BIOS pin config */ | ||
767 | |||
768 | err = vt1708_auto_create_multi_out_ctls(spec, &spec->autocfg); | ||
769 | if (err < 0) | ||
770 | return err; | ||
771 | err = vt1708_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); | ||
772 | if (err < 0) | ||
773 | return err; | ||
774 | err = vt1708_auto_create_analog_input_ctls(spec, &spec->autocfg); | ||
775 | if (err < 0) | ||
776 | return err; | ||
777 | |||
778 | spec->multiout.max_channels = spec->multiout.num_dacs * 2; | ||
779 | |||
780 | if (spec->autocfg.dig_out_pin) | ||
781 | spec->multiout.dig_out_nid = VT1708_DIGOUT_NID; | ||
782 | if (spec->autocfg.dig_in_pin) | ||
783 | spec->dig_in_nid = VT1708_DIGIN_NID; | ||
784 | |||
785 | if (spec->kctl_alloc) | ||
786 | spec->mixers[spec->num_mixers++] = spec->kctl_alloc; | ||
787 | |||
788 | spec->init_verbs = vt1708_volume_init_verbs; | ||
789 | |||
790 | spec->input_mux = &spec->private_imux; | ||
791 | |||
792 | return 1; | ||
793 | } | ||
794 | |||
795 | /* init callback for auto-configuration model -- overriding the default init */ | ||
796 | static int via_auto_init(struct hda_codec *codec) | ||
797 | { | ||
798 | via_init(codec); | ||
799 | via_auto_init_multi_out(codec); | ||
800 | via_auto_init_hp_out(codec); | ||
801 | via_auto_init_analog_input(codec); | ||
802 | return 0; | ||
803 | } | ||
804 | |||
805 | static int patch_vt1708(struct hda_codec *codec) | ||
806 | { | ||
807 | struct via_spec *spec; | ||
808 | int err; | ||
809 | |||
810 | /* create a codec specific record */ | ||
811 | spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); | ||
812 | if (spec == NULL) | ||
813 | return -ENOMEM; | ||
814 | |||
815 | codec->spec = spec; | ||
816 | |||
817 | /* automatic parse from the BIOS config */ | ||
818 | err = vt1708_parse_auto_config(codec); | ||
819 | if (err < 0) { | ||
820 | via_free(codec); | ||
821 | return err; | ||
822 | } else if (!err) { | ||
823 | printk(KERN_INFO "hda_codec: Cannot set up configuration " | ||
824 | "from BIOS. Using genenic mode...\n"); | ||
825 | } | ||
826 | |||
827 | |||
828 | spec->stream_name_analog = "VT1708 Analog"; | ||
829 | spec->stream_analog_playback = &vt1708_pcm_analog_playback; | ||
830 | spec->stream_analog_capture = &vt1708_pcm_analog_capture; | ||
831 | |||
832 | spec->stream_name_digital = "VT1708 Digital"; | ||
833 | spec->stream_digital_playback = &vt1708_pcm_digital_playback; | ||
834 | spec->stream_digital_capture = &vt1708_pcm_digital_capture; | ||
835 | |||
836 | |||
837 | if (!spec->adc_nids && spec->input_mux) { | ||
838 | spec->adc_nids = vt1708_adc_nids; | ||
839 | spec->num_adc_nids = ARRAY_SIZE(vt1708_adc_nids); | ||
840 | spec->mixers[spec->num_mixers] = vt1708_capture_mixer; | ||
841 | spec->num_mixers++; | ||
842 | } | ||
843 | |||
844 | codec->patch_ops = via_patch_ops; | ||
845 | |||
846 | codec->patch_ops.init = via_auto_init; | ||
847 | |||
848 | return 0; | ||
849 | } | ||
850 | |||
851 | /* capture mixer elements */ | ||
852 | static struct snd_kcontrol_new vt1709_capture_mixer[] = { | ||
853 | HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x0, HDA_INPUT), | ||
854 | HDA_CODEC_MUTE("Capture Switch", 0x14, 0x0, HDA_INPUT), | ||
855 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x15, 0x0, HDA_INPUT), | ||
856 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x15, 0x0, HDA_INPUT), | ||
857 | HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x16, 0x0, HDA_INPUT), | ||
858 | HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x16, 0x0, HDA_INPUT), | ||
859 | { | ||
860 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
861 | /* The multiple "Capture Source" controls confuse alsamixer | ||
862 | * So call somewhat different.. | ||
863 | * FIXME: the controls appear in the "playback" view! | ||
864 | */ | ||
865 | /* .name = "Capture Source", */ | ||
866 | .name = "Input Source", | ||
867 | .count = 1, | ||
868 | .info = via_mux_enum_info, | ||
869 | .get = via_mux_enum_get, | ||
870 | .put = via_mux_enum_put, | ||
871 | }, | ||
872 | { } /* end */ | ||
873 | }; | ||
874 | |||
875 | /* | ||
876 | * generic initialization of ADC, input mixers and output mixers | ||
877 | */ | ||
878 | static struct hda_verb vt1709_10ch_volume_init_verbs[] = { | ||
879 | /* | ||
880 | * Unmute ADC0-2 and set the default input to mic-in | ||
881 | */ | ||
882 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
883 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
884 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
885 | |||
886 | |||
887 | /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback | ||
888 | * mixer widget | ||
889 | */ | ||
890 | /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ | ||
891 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
892 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
893 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, | ||
894 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, | ||
895 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, | ||
896 | |||
897 | /* | ||
898 | * Set up output selector (0x1a, 0x1b, 0x29) | ||
899 | */ | ||
900 | /* set vol=0 to output mixers */ | ||
901 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
902 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
903 | {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
904 | |||
905 | /* | ||
906 | * Unmute PW3 and PW4 | ||
907 | */ | ||
908 | {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
909 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
910 | |||
911 | /* Set input of PW4 as AOW4 */ | ||
912 | {0x20, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
913 | /* Set mic as default input of sw0 */ | ||
914 | {0x19, AC_VERB_SET_CONNECT_SEL, 0x2}, | ||
915 | /* PW9 Output enable */ | ||
916 | {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | ||
917 | { } | ||
918 | }; | ||
919 | |||
920 | static struct hda_pcm_stream vt1709_10ch_pcm_analog_playback = { | ||
921 | .substreams = 1, | ||
922 | .channels_min = 2, | ||
923 | .channels_max = 10, | ||
924 | .nid = 0x10, /* NID to query formats and rates */ | ||
925 | .ops = { | ||
926 | .open = via_playback_pcm_open, | ||
927 | .prepare = via_playback_pcm_prepare, | ||
928 | .cleanup = via_playback_pcm_cleanup | ||
929 | }, | ||
930 | }; | ||
931 | |||
932 | static struct hda_pcm_stream vt1709_6ch_pcm_analog_playback = { | ||
933 | .substreams = 1, | ||
934 | .channels_min = 2, | ||
935 | .channels_max = 6, | ||
936 | .nid = 0x10, /* NID to query formats and rates */ | ||
937 | .ops = { | ||
938 | .open = via_playback_pcm_open, | ||
939 | .prepare = via_playback_pcm_prepare, | ||
940 | .cleanup = via_playback_pcm_cleanup | ||
941 | }, | ||
942 | }; | ||
943 | |||
944 | static struct hda_pcm_stream vt1709_pcm_analog_capture = { | ||
945 | .substreams = 2, | ||
946 | .channels_min = 2, | ||
947 | .channels_max = 2, | ||
948 | .nid = 0x14, /* NID to query formats and rates */ | ||
949 | .ops = { | ||
950 | .prepare = via_capture_pcm_prepare, | ||
951 | .cleanup = via_capture_pcm_cleanup | ||
952 | }, | ||
953 | }; | ||
954 | |||
955 | static struct hda_pcm_stream vt1709_pcm_digital_playback = { | ||
956 | .substreams = 1, | ||
957 | .channels_min = 2, | ||
958 | .channels_max = 2, | ||
959 | /* NID is set in via_build_pcms */ | ||
960 | .ops = { | ||
961 | .open = via_dig_playback_pcm_open, | ||
962 | .close = via_dig_playback_pcm_close | ||
963 | }, | ||
964 | }; | ||
965 | |||
966 | static struct hda_pcm_stream vt1709_pcm_digital_capture = { | ||
967 | .substreams = 1, | ||
968 | .channels_min = 2, | ||
969 | .channels_max = 2, | ||
970 | }; | ||
971 | |||
972 | static int vt1709_auto_fill_dac_nids(struct via_spec *spec, | ||
973 | const struct auto_pin_cfg *cfg) | ||
974 | { | ||
975 | int i; | ||
976 | hda_nid_t nid; | ||
977 | |||
978 | if (cfg->line_outs == 4) /* 10 channels */ | ||
979 | spec->multiout.num_dacs = cfg->line_outs+1; /* AOW0~AOW4 */ | ||
980 | else if (cfg->line_outs == 3) /* 6 channels */ | ||
981 | spec->multiout.num_dacs = cfg->line_outs; /* AOW0~AOW2 */ | ||
982 | |||
983 | spec->multiout.dac_nids = spec->private_dac_nids; | ||
984 | |||
985 | if (cfg->line_outs == 4) { /* 10 channels */ | ||
986 | for (i = 0; i < cfg->line_outs; i++) { | ||
987 | nid = cfg->line_out_pins[i]; | ||
988 | if (nid) { | ||
989 | /* config dac list */ | ||
990 | switch (i) { | ||
991 | case AUTO_SEQ_FRONT: | ||
992 | /* AOW0 */ | ||
993 | spec->multiout.dac_nids[i] = 0x10; | ||
994 | break; | ||
995 | case AUTO_SEQ_CENLFE: | ||
996 | /* AOW2 */ | ||
997 | spec->multiout.dac_nids[i] = 0x12; | ||
998 | break; | ||
999 | case AUTO_SEQ_SURROUND: | ||
1000 | /* AOW3 */ | ||
1001 | spec->multiout.dac_nids[i] = 0x27; | ||
1002 | break; | ||
1003 | case AUTO_SEQ_SIDE: | ||
1004 | /* AOW1 */ | ||
1005 | spec->multiout.dac_nids[i] = 0x11; | ||
1006 | break; | ||
1007 | default: | ||
1008 | break; | ||
1009 | } | ||
1010 | } | ||
1011 | } | ||
1012 | spec->multiout.dac_nids[cfg->line_outs] = 0x28; /* AOW4 */ | ||
1013 | |||
1014 | } else if (cfg->line_outs == 3) { /* 6 channels */ | ||
1015 | for(i = 0; i < cfg->line_outs; i++) { | ||
1016 | nid = cfg->line_out_pins[i]; | ||
1017 | if (nid) { | ||
1018 | /* config dac list */ | ||
1019 | switch(i) { | ||
1020 | case AUTO_SEQ_FRONT: | ||
1021 | /* AOW0 */ | ||
1022 | spec->multiout.dac_nids[i] = 0x10; | ||
1023 | break; | ||
1024 | case AUTO_SEQ_CENLFE: | ||
1025 | /* AOW2 */ | ||
1026 | spec->multiout.dac_nids[i] = 0x12; | ||
1027 | break; | ||
1028 | case AUTO_SEQ_SURROUND: | ||
1029 | /* AOW1 */ | ||
1030 | spec->multiout.dac_nids[i] = 0x11; | ||
1031 | break; | ||
1032 | default: | ||
1033 | break; | ||
1034 | } | ||
1035 | } | ||
1036 | } | ||
1037 | } | ||
1038 | |||
1039 | return 0; | ||
1040 | } | ||
1041 | |||
1042 | /* add playback controls from the parsed DAC table */ | ||
1043 | static int vt1709_auto_create_multi_out_ctls(struct via_spec *spec, | ||
1044 | const struct auto_pin_cfg *cfg) | ||
1045 | { | ||
1046 | char name[32]; | ||
1047 | static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" }; | ||
1048 | hda_nid_t nid = 0; | ||
1049 | int i, err; | ||
1050 | |||
1051 | for (i = 0; i <= AUTO_SEQ_SIDE; i++) { | ||
1052 | nid = cfg->line_out_pins[i]; | ||
1053 | |||
1054 | if (!nid) | ||
1055 | continue; | ||
1056 | |||
1057 | if (i == AUTO_SEQ_CENLFE) { | ||
1058 | /* Center/LFE */ | ||
1059 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | ||
1060 | "Center Playback Volume", | ||
1061 | HDA_COMPOSE_AMP_VAL(0x1b, 1, 0, HDA_OUTPUT)); | ||
1062 | if (err < 0) | ||
1063 | return err; | ||
1064 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | ||
1065 | "LFE Playback Volume", | ||
1066 | HDA_COMPOSE_AMP_VAL(0x1b, 2, 0, HDA_OUTPUT)); | ||
1067 | if (err < 0) | ||
1068 | return err; | ||
1069 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, | ||
1070 | "Center Playback Switch", | ||
1071 | HDA_COMPOSE_AMP_VAL(0x1b, 1, 0, HDA_OUTPUT)); | ||
1072 | if (err < 0) | ||
1073 | return err; | ||
1074 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, | ||
1075 | "LFE Playback Switch", | ||
1076 | HDA_COMPOSE_AMP_VAL(0x1b, 2, 0, HDA_OUTPUT)); | ||
1077 | if (err < 0) | ||
1078 | return err; | ||
1079 | } else if (i == AUTO_SEQ_FRONT){ | ||
1080 | /* add control to mixer index 0 */ | ||
1081 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | ||
1082 | "Master Front Playback Volume", | ||
1083 | HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT)); | ||
1084 | if (err < 0) | ||
1085 | return err; | ||
1086 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, | ||
1087 | "Master Front Playback Switch", | ||
1088 | HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT)); | ||
1089 | if (err < 0) | ||
1090 | return err; | ||
1091 | |||
1092 | /* add control to PW3 */ | ||
1093 | sprintf(name, "%s Playback Volume", chname[i]); | ||
1094 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, | ||
1095 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT)); | ||
1096 | if (err < 0) | ||
1097 | return err; | ||
1098 | sprintf(name, "%s Playback Switch", chname[i]); | ||
1099 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, | ||
1100 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT)); | ||
1101 | if (err < 0) | ||
1102 | return err; | ||
1103 | } else if (i == AUTO_SEQ_SURROUND) { | ||
1104 | sprintf(name, "%s Playback Volume", chname[i]); | ||
1105 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, | ||
1106 | HDA_COMPOSE_AMP_VAL(0x29, 3, 0, HDA_OUTPUT)); | ||
1107 | if (err < 0) | ||
1108 | return err; | ||
1109 | sprintf(name, "%s Playback Switch", chname[i]); | ||
1110 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, | ||
1111 | HDA_COMPOSE_AMP_VAL(0x29, 3, 0, HDA_OUTPUT)); | ||
1112 | if (err < 0) | ||
1113 | return err; | ||
1114 | } else if (i == AUTO_SEQ_SIDE) { | ||
1115 | sprintf(name, "%s Playback Volume", chname[i]); | ||
1116 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, | ||
1117 | HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT)); | ||
1118 | if (err < 0) | ||
1119 | return err; | ||
1120 | sprintf(name, "%s Playback Switch", chname[i]); | ||
1121 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, | ||
1122 | HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT)); | ||
1123 | if (err < 0) | ||
1124 | return err; | ||
1125 | } | ||
1126 | } | ||
1127 | |||
1128 | return 0; | ||
1129 | } | ||
1130 | |||
1131 | static int vt1709_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) | ||
1132 | { | ||
1133 | int err; | ||
1134 | |||
1135 | if (!pin) | ||
1136 | return 0; | ||
1137 | |||
1138 | if (spec->multiout.num_dacs == 5) /* 10 channels */ | ||
1139 | spec->multiout.hp_nid = VT1709_HP_DAC_NID; | ||
1140 | else if (spec->multiout.num_dacs == 3) /* 6 channels */ | ||
1141 | spec->multiout.hp_nid = 0; | ||
1142 | |||
1143 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | ||
1144 | "Headphone Playback Volume", | ||
1145 | HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); | ||
1146 | if (err < 0) | ||
1147 | return err; | ||
1148 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, | ||
1149 | "Headphone Playback Switch", | ||
1150 | HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); | ||
1151 | if (err < 0) | ||
1152 | return err; | ||
1153 | |||
1154 | return 0; | ||
1155 | } | ||
1156 | |||
1157 | /* create playback/capture controls for input pins */ | ||
1158 | static int vt1709_auto_create_analog_input_ctls(struct via_spec *spec, | ||
1159 | const struct auto_pin_cfg *cfg) | ||
1160 | { | ||
1161 | static char *labels[] = { | ||
1162 | "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL | ||
1163 | }; | ||
1164 | struct hda_input_mux *imux = &spec->private_imux; | ||
1165 | int i, err, idx = 0; | ||
1166 | |||
1167 | /* for internal loopback recording select */ | ||
1168 | imux->items[imux->num_items].label = "Stereo Mixer"; | ||
1169 | imux->items[imux->num_items].index = idx; | ||
1170 | imux->num_items++; | ||
1171 | |||
1172 | for (i = 0; i < AUTO_PIN_LAST; i++) { | ||
1173 | if (!cfg->input_pins[i]) | ||
1174 | continue; | ||
1175 | |||
1176 | switch (cfg->input_pins[i]) { | ||
1177 | case 0x1d: /* Mic */ | ||
1178 | idx = 2; | ||
1179 | break; | ||
1180 | |||
1181 | case 0x1e: /* Line In */ | ||
1182 | idx = 3; | ||
1183 | break; | ||
1184 | |||
1185 | case 0x21: /* Front Mic */ | ||
1186 | idx = 4; | ||
1187 | break; | ||
1188 | |||
1189 | case 0x23: /* CD */ | ||
1190 | idx = 1; | ||
1191 | break; | ||
1192 | } | ||
1193 | err = via_new_analog_input(spec, cfg->input_pins[i], labels[i], | ||
1194 | idx, 0x18); | ||
1195 | if (err < 0) | ||
1196 | return err; | ||
1197 | imux->items[imux->num_items].label = labels[i]; | ||
1198 | imux->items[imux->num_items].index = idx; | ||
1199 | imux->num_items++; | ||
1200 | } | ||
1201 | return 0; | ||
1202 | } | ||
1203 | |||
1204 | static int vt1709_parse_auto_config(struct hda_codec *codec) | ||
1205 | { | ||
1206 | struct via_spec *spec = codec->spec; | ||
1207 | int err; | ||
1208 | |||
1209 | err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); | ||
1210 | if (err < 0) | ||
1211 | return err; | ||
1212 | err = vt1709_auto_fill_dac_nids(spec, &spec->autocfg); | ||
1213 | if (err < 0) | ||
1214 | return err; | ||
1215 | if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0]) | ||
1216 | return 0; /* can't find valid BIOS pin config */ | ||
1217 | |||
1218 | err = vt1709_auto_create_multi_out_ctls(spec, &spec->autocfg); | ||
1219 | if (err < 0) | ||
1220 | return err; | ||
1221 | err = vt1709_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); | ||
1222 | if (err < 0) | ||
1223 | return err; | ||
1224 | err = vt1709_auto_create_analog_input_ctls(spec, &spec->autocfg); | ||
1225 | if (err < 0) | ||
1226 | return err; | ||
1227 | |||
1228 | spec->multiout.max_channels = spec->multiout.num_dacs * 2; | ||
1229 | |||
1230 | if (spec->autocfg.dig_out_pin) | ||
1231 | spec->multiout.dig_out_nid = VT1709_DIGOUT_NID; | ||
1232 | if (spec->autocfg.dig_in_pin) | ||
1233 | spec->dig_in_nid = VT1709_DIGIN_NID; | ||
1234 | |||
1235 | if (spec->kctl_alloc) | ||
1236 | spec->mixers[spec->num_mixers++] = spec->kctl_alloc; | ||
1237 | |||
1238 | spec->input_mux = &spec->private_imux; | ||
1239 | |||
1240 | return 1; | ||
1241 | } | ||
1242 | |||
1243 | static int patch_vt1709_10ch(struct hda_codec *codec) | ||
1244 | { | ||
1245 | struct via_spec *spec; | ||
1246 | int err; | ||
1247 | |||
1248 | /* create a codec specific record */ | ||
1249 | spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); | ||
1250 | if (spec == NULL) | ||
1251 | return -ENOMEM; | ||
1252 | |||
1253 | codec->spec = spec; | ||
1254 | |||
1255 | err = vt1709_parse_auto_config(codec); | ||
1256 | if (err < 0) { | ||
1257 | via_free(codec); | ||
1258 | return err; | ||
1259 | } else if (!err) { | ||
1260 | printk(KERN_INFO "hda_codec: Cannot set up configuration. " | ||
1261 | "Using genenic mode...\n"); | ||
1262 | } | ||
1263 | |||
1264 | spec->init_verbs = vt1709_10ch_volume_init_verbs; | ||
1265 | |||
1266 | spec->stream_name_analog = "VT1709 Analog"; | ||
1267 | spec->stream_analog_playback = &vt1709_10ch_pcm_analog_playback; | ||
1268 | spec->stream_analog_capture = &vt1709_pcm_analog_capture; | ||
1269 | |||
1270 | spec->stream_name_digital = "VT1709 Digital"; | ||
1271 | spec->stream_digital_playback = &vt1709_pcm_digital_playback; | ||
1272 | spec->stream_digital_capture = &vt1709_pcm_digital_capture; | ||
1273 | |||
1274 | |||
1275 | if (!spec->adc_nids && spec->input_mux) { | ||
1276 | spec->adc_nids = vt1709_adc_nids; | ||
1277 | spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids); | ||
1278 | spec->mixers[spec->num_mixers] = vt1709_capture_mixer; | ||
1279 | spec->num_mixers++; | ||
1280 | } | ||
1281 | |||
1282 | codec->patch_ops = via_patch_ops; | ||
1283 | |||
1284 | codec->patch_ops.init = via_auto_init; | ||
1285 | |||
1286 | return 0; | ||
1287 | } | ||
1288 | /* | ||
1289 | * generic initialization of ADC, input mixers and output mixers | ||
1290 | */ | ||
1291 | static struct hda_verb vt1709_6ch_volume_init_verbs[] = { | ||
1292 | /* | ||
1293 | * Unmute ADC0-2 and set the default input to mic-in | ||
1294 | */ | ||
1295 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
1296 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
1297 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
1298 | |||
1299 | |||
1300 | /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback | ||
1301 | * mixer widget | ||
1302 | */ | ||
1303 | /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ | ||
1304 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
1305 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
1306 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, | ||
1307 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, | ||
1308 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, | ||
1309 | |||
1310 | /* | ||
1311 | * Set up output selector (0x1a, 0x1b, 0x29) | ||
1312 | */ | ||
1313 | /* set vol=0 to output mixers */ | ||
1314 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
1315 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
1316 | {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
1317 | |||
1318 | /* | ||
1319 | * Unmute PW3 and PW4 | ||
1320 | */ | ||
1321 | {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
1322 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
1323 | |||
1324 | /* Set input of PW4 as MW0 */ | ||
1325 | {0x20, AC_VERB_SET_CONNECT_SEL, 0}, | ||
1326 | /* Set mic as default input of sw0 */ | ||
1327 | {0x19, AC_VERB_SET_CONNECT_SEL, 0x2}, | ||
1328 | /* PW9 Output enable */ | ||
1329 | {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | ||
1330 | { } | ||
1331 | }; | ||
1332 | |||
1333 | static int patch_vt1709_6ch(struct hda_codec *codec) | ||
1334 | { | ||
1335 | struct via_spec *spec; | ||
1336 | int err; | ||
1337 | |||
1338 | /* create a codec specific record */ | ||
1339 | spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); | ||
1340 | if (spec == NULL) | ||
1341 | return -ENOMEM; | ||
1342 | |||
1343 | codec->spec = spec; | ||
1344 | |||
1345 | err = vt1709_parse_auto_config(codec); | ||
1346 | if (err < 0) { | ||
1347 | via_free(codec); | ||
1348 | return err; | ||
1349 | } else if (!err) { | ||
1350 | printk(KERN_INFO "hda_codec: Cannot set up configuration. " | ||
1351 | "Using genenic mode...\n"); | ||
1352 | } | ||
1353 | |||
1354 | spec->init_verbs = vt1709_6ch_volume_init_verbs; | ||
1355 | |||
1356 | spec->stream_name_analog = "VT1709 Analog"; | ||
1357 | spec->stream_analog_playback = &vt1709_6ch_pcm_analog_playback; | ||
1358 | spec->stream_analog_capture = &vt1709_pcm_analog_capture; | ||
1359 | |||
1360 | spec->stream_name_digital = "VT1709 Digital"; | ||
1361 | spec->stream_digital_playback = &vt1709_pcm_digital_playback; | ||
1362 | spec->stream_digital_capture = &vt1709_pcm_digital_capture; | ||
1363 | |||
1364 | |||
1365 | if (!spec->adc_nids && spec->input_mux) { | ||
1366 | spec->adc_nids = vt1709_adc_nids; | ||
1367 | spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids); | ||
1368 | spec->mixers[spec->num_mixers] = vt1709_capture_mixer; | ||
1369 | spec->num_mixers++; | ||
1370 | } | ||
1371 | |||
1372 | codec->patch_ops = via_patch_ops; | ||
1373 | |||
1374 | codec->patch_ops.init = via_auto_init; | ||
1375 | |||
1376 | return 0; | ||
1377 | } | ||
1378 | |||
1379 | /* | ||
1380 | * patch entries | ||
1381 | */ | ||
1382 | struct hda_codec_preset snd_hda_preset_via[] = { | ||
1383 | { .id = 0x11061708, .name = "VIA VT1708", .patch = patch_vt1708}, | ||
1384 | { .id = 0x11061709, .name = "VIA VT1708", .patch = patch_vt1708}, | ||
1385 | { .id = 0x1106170A, .name = "VIA VT1708", .patch = patch_vt1708}, | ||
1386 | { .id = 0x1106170B, .name = "VIA VT1708", .patch = patch_vt1708}, | ||
1387 | { .id = 0x1106E710, .name = "VIA VT1709 10-Ch", .patch = patch_vt1709_10ch}, | ||
1388 | { .id = 0x1106E711, .name = "VIA VT1709 10-Ch", .patch = patch_vt1709_10ch}, | ||
1389 | { .id = 0x1106E712, .name = "VIA VT1709 10-Ch", .patch = patch_vt1709_10ch}, | ||
1390 | { .id = 0x1106E713, .name = "VIA VT1709 10-Ch", .patch = patch_vt1709_10ch}, | ||
1391 | { .id = 0x1106E714, .name = "VIA VT1709 6-Ch", .patch = patch_vt1709_6ch}, | ||
1392 | { .id = 0x1106E715, .name = "VIA VT1709 6-Ch", .patch = patch_vt1709_6ch}, | ||
1393 | { .id = 0x1106E716, .name = "VIA VT1709 6-Ch", .patch = patch_vt1709_6ch}, | ||
1394 | { .id = 0x1106E717, .name = "VIA VT1709 6-Ch", .patch = patch_vt1709_6ch}, | ||
1395 | {} /* terminator */ | ||
1396 | }; | ||
diff --git a/sound/pci/ice1712/Makefile b/sound/pci/ice1712/Makefile index 7837cef8855c..6efdd62f6837 100644 --- a/sound/pci/ice1712/Makefile +++ b/sound/pci/ice1712/Makefile | |||
@@ -5,7 +5,7 @@ | |||
5 | 5 | ||
6 | snd-ice17xx-ak4xxx-objs := ak4xxx.o | 6 | snd-ice17xx-ak4xxx-objs := ak4xxx.o |
7 | snd-ice1712-objs := ice1712.o delta.o hoontech.o ews.o | 7 | snd-ice1712-objs := ice1712.o delta.o hoontech.o ews.o |
8 | snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o vt1720_mobo.o pontis.o prodigy192.o juli.o phase.o | 8 | snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o vt1720_mobo.o pontis.o prodigy192.o juli.o phase.o wtm.o |
9 | 9 | ||
10 | # Toplevel Module Dependency | 10 | # Toplevel Module Dependency |
11 | obj-$(CONFIG_SND_ICE1712) += snd-ice1712.o snd-ice17xx-ak4xxx.o | 11 | obj-$(CONFIG_SND_ICE1712) += snd-ice1712.o snd-ice17xx-ak4xxx.o |
diff --git a/sound/pci/ice1712/amp.c b/sound/pci/ice1712/amp.c index 59c4078ad331..6e22d326df32 100644 --- a/sound/pci/ice1712/amp.c +++ b/sound/pci/ice1712/amp.c | |||
@@ -42,7 +42,7 @@ static void wm_put(struct snd_ice1712 *ice, int reg, unsigned short val) | |||
42 | 42 | ||
43 | static int __devinit snd_vt1724_amp_init(struct snd_ice1712 *ice) | 43 | static int __devinit snd_vt1724_amp_init(struct snd_ice1712 *ice) |
44 | { | 44 | { |
45 | static unsigned short wm_inits[] = { | 45 | static const unsigned short wm_inits[] = { |
46 | WM_ATTEN_L, 0x0000, /* 0 db */ | 46 | WM_ATTEN_L, 0x0000, /* 0 db */ |
47 | WM_ATTEN_R, 0x0000, /* 0 db */ | 47 | WM_ATTEN_R, 0x0000, /* 0 db */ |
48 | WM_DAC_CTRL, 0x0008, /* 24bit I2S */ | 48 | WM_DAC_CTRL, 0x0008, /* 24bit I2S */ |
@@ -75,7 +75,7 @@ static int __devinit snd_vt1724_amp_add_controls(struct snd_ice1712 *ice) | |||
75 | 75 | ||
76 | 76 | ||
77 | /* entry point */ | 77 | /* entry point */ |
78 | struct snd_ice1712_card_info snd_vt1724_amp_cards[] __devinitdata = { | 78 | const struct snd_ice1712_card_info snd_vt1724_amp_cards[] __devinitdata = { |
79 | { | 79 | { |
80 | .subvendor = VT1724_SUBDEVICE_AV710, | 80 | .subvendor = VT1724_SUBDEVICE_AV710, |
81 | .name = "Chaintech AV-710", | 81 | .name = "Chaintech AV-710", |
diff --git a/sound/pci/ice1712/amp.h b/sound/pci/ice1712/amp.h index a0fc89b48122..7b667bad0c6b 100644 --- a/sound/pci/ice1712/amp.h +++ b/sound/pci/ice1712/amp.h | |||
@@ -42,7 +42,7 @@ | |||
42 | #define WM_DAC_CTRL 0x02 | 42 | #define WM_DAC_CTRL 0x02 |
43 | #define WM_INT_CTRL 0x03 | 43 | #define WM_INT_CTRL 0x03 |
44 | 44 | ||
45 | extern struct snd_ice1712_card_info snd_vt1724_amp_cards[]; | 45 | extern const struct snd_ice1712_card_info snd_vt1724_amp_cards[]; |
46 | 46 | ||
47 | 47 | ||
48 | #endif /* __SOUND_AMP_H */ | 48 | #endif /* __SOUND_AMP_H */ |
diff --git a/sound/pci/ice1712/aureon.c b/sound/pci/ice1712/aureon.c index 9e76cebd2d22..6941d85dfec9 100644 --- a/sound/pci/ice1712/aureon.c +++ b/sound/pci/ice1712/aureon.c | |||
@@ -294,7 +294,7 @@ static unsigned short aureon_ac97_read(struct snd_ice1712 *ice, unsigned short r | |||
294 | static int aureon_ac97_init (struct snd_ice1712 *ice) | 294 | static int aureon_ac97_init (struct snd_ice1712 *ice) |
295 | { | 295 | { |
296 | int i; | 296 | int i; |
297 | static unsigned short ac97_defaults[] = { | 297 | static const unsigned short ac97_defaults[] = { |
298 | 0x00, 0x9640, | 298 | 0x00, 0x9640, |
299 | 0x02, 0x8000, | 299 | 0x02, 0x8000, |
300 | 0x04, 0x8000, | 300 | 0x04, 0x8000, |
@@ -474,7 +474,8 @@ static void aureon_spi_write(struct snd_ice1712 *ice, unsigned int cs, unsigned | |||
474 | 474 | ||
475 | tmp = snd_ice1712_gpio_read(ice); | 475 | tmp = snd_ice1712_gpio_read(ice); |
476 | 476 | ||
477 | if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT) { | 477 | if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT || |
478 | ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71XT) { | ||
478 | snd_ice1712_gpio_set_mask(ice, ~(PRODIGY_SPI_MOSI|PRODIGY_SPI_CLK|PRODIGY_WM_CS)); | 479 | snd_ice1712_gpio_set_mask(ice, ~(PRODIGY_SPI_MOSI|PRODIGY_SPI_CLK|PRODIGY_WM_CS)); |
479 | mosi = PRODIGY_SPI_MOSI; | 480 | mosi = PRODIGY_SPI_MOSI; |
480 | clk = PRODIGY_SPI_CLK; | 481 | clk = PRODIGY_SPI_CLK; |
@@ -601,7 +602,9 @@ static unsigned short wm_get(struct snd_ice1712 *ice, int reg) | |||
601 | static void wm_put_nocache(struct snd_ice1712 *ice, int reg, unsigned short val) | 602 | static void wm_put_nocache(struct snd_ice1712 *ice, int reg, unsigned short val) |
602 | { | 603 | { |
603 | aureon_spi_write(ice, | 604 | aureon_spi_write(ice, |
604 | (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT ? PRODIGY_WM_CS : AUREON_WM_CS), | 605 | ((ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT || |
606 | ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71XT) ? | ||
607 | PRODIGY_WM_CS : AUREON_WM_CS), | ||
605 | (reg << 9) | (val & 0x1ff), 16); | 608 | (reg << 9) | (val & 0x1ff), 16); |
606 | } | 609 | } |
607 | 610 | ||
@@ -661,17 +664,17 @@ static int aureon_ac97_mmute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e | |||
661 | return change; | 664 | return change; |
662 | } | 665 | } |
663 | 666 | ||
664 | static DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1); | 667 | static const DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1); |
665 | static DECLARE_TLV_DB_SCALE(db_scale_wm_pcm, -6400, 50, 1); | 668 | static const DECLARE_TLV_DB_SCALE(db_scale_wm_pcm, -6400, 50, 1); |
666 | static DECLARE_TLV_DB_SCALE(db_scale_wm_adc, -1200, 100, 0); | 669 | static const DECLARE_TLV_DB_SCALE(db_scale_wm_adc, -1200, 100, 0); |
667 | static DECLARE_TLV_DB_SCALE(db_scale_ac97_master, -4650, 150, 0); | 670 | static const DECLARE_TLV_DB_SCALE(db_scale_ac97_master, -4650, 150, 0); |
668 | static DECLARE_TLV_DB_SCALE(db_scale_ac97_gain, -3450, 150, 0); | 671 | static const DECLARE_TLV_DB_SCALE(db_scale_ac97_gain, -3450, 150, 0); |
669 | 672 | ||
670 | /* | 673 | /* |
671 | * Logarithmic volume values for WM8770 | 674 | * Logarithmic volume values for WM8770 |
672 | * Computed as 20 * Log10(255 / x) | 675 | * Computed as 20 * Log10(255 / x) |
673 | */ | 676 | */ |
674 | static unsigned char wm_vol[256] = { | 677 | static const unsigned char wm_vol[256] = { |
675 | 127, 48, 42, 39, 36, 34, 33, 31, 30, 29, 28, 27, 27, 26, 25, 25, 24, 24, 23, | 678 | 127, 48, 42, 39, 36, 34, 33, 31, 30, 29, 28, 27, 27, 26, 25, 25, 24, 24, 23, |
676 | 23, 22, 22, 21, 21, 21, 20, 20, 20, 19, 19, 19, 18, 18, 18, 18, 17, 17, 17, | 679 | 23, 22, 22, 21, 21, 21, 20, 20, 20, 19, 19, 19, 18, 18, 18, 18, 17, 17, 17, |
677 | 17, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 13, 13, 13, | 680 | 17, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 13, 13, 13, |
@@ -1064,14 +1067,14 @@ static int wm_adc_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val | |||
1064 | */ | 1067 | */ |
1065 | static int wm_adc_mux_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | 1068 | static int wm_adc_mux_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) |
1066 | { | 1069 | { |
1067 | static char *texts[] = { | 1070 | static const char * const texts[] = { |
1068 | "CD", //AIN1 | 1071 | "CD", //AIN1 |
1069 | "Aux", //AIN2 | 1072 | "Aux", //AIN2 |
1070 | "Line", //AIN3 | 1073 | "Line", //AIN3 |
1071 | "Mic", //AIN4 | 1074 | "Mic", //AIN4 |
1072 | "AC97" //AIN5 | 1075 | "AC97" //AIN5 |
1073 | }; | 1076 | }; |
1074 | static char *universe_texts[] = { | 1077 | static const char * const universe_texts[] = { |
1075 | "Aux1", //AIN1 | 1078 | "Aux1", //AIN1 |
1076 | "CD", //AIN2 | 1079 | "CD", //AIN2 |
1077 | "Phono", //AIN3 | 1080 | "Phono", //AIN3 |
@@ -1137,11 +1140,11 @@ static int wm_adc_mux_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val | |||
1137 | static int aureon_cs8415_mux_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | 1140 | static int aureon_cs8415_mux_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) |
1138 | { | 1141 | { |
1139 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 1142 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
1140 | static char *aureon_texts[] = { | 1143 | static const char * const aureon_texts[] = { |
1141 | "CD", //RXP0 | 1144 | "CD", //RXP0 |
1142 | "Optical" //RXP1 | 1145 | "Optical" //RXP1 |
1143 | }; | 1146 | }; |
1144 | static char *prodigy_texts[] = { | 1147 | static const char * const prodigy_texts[] = { |
1145 | "CD", | 1148 | "CD", |
1146 | "Coax" | 1149 | "Coax" |
1147 | }; | 1150 | }; |
@@ -1288,12 +1291,14 @@ static int aureon_set_headphone_amp(struct snd_ice1712 *ice, int enable) | |||
1288 | 1291 | ||
1289 | tmp2 = tmp = snd_ice1712_gpio_read(ice); | 1292 | tmp2 = tmp = snd_ice1712_gpio_read(ice); |
1290 | if (enable) | 1293 | if (enable) |
1291 | if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT) | 1294 | if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT && |
1295 | ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT) | ||
1292 | tmp |= AUREON_HP_SEL; | 1296 | tmp |= AUREON_HP_SEL; |
1293 | else | 1297 | else |
1294 | tmp |= PRODIGY_HP_SEL; | 1298 | tmp |= PRODIGY_HP_SEL; |
1295 | else | 1299 | else |
1296 | if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT) | 1300 | if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT && |
1301 | ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT) | ||
1297 | tmp &= ~ AUREON_HP_SEL; | 1302 | tmp &= ~ AUREON_HP_SEL; |
1298 | else | 1303 | else |
1299 | tmp &= ~ PRODIGY_HP_SEL; | 1304 | tmp &= ~ PRODIGY_HP_SEL; |
@@ -1363,7 +1368,7 @@ static int aureon_deemp_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v | |||
1363 | */ | 1368 | */ |
1364 | static int aureon_oversampling_info(struct snd_kcontrol *k, struct snd_ctl_elem_info *uinfo) | 1369 | static int aureon_oversampling_info(struct snd_kcontrol *k, struct snd_ctl_elem_info *uinfo) |
1365 | { | 1370 | { |
1366 | static char *texts[2] = { "128x", "64x" }; | 1371 | static const char * const texts[2] = { "128x", "64x" }; |
1367 | 1372 | ||
1368 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 1373 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; |
1369 | uinfo->count = 1; | 1374 | uinfo->count = 1; |
@@ -1406,7 +1411,7 @@ static int aureon_oversampling_put(struct snd_kcontrol *kcontrol, struct snd_ctl | |||
1406 | * mixers | 1411 | * mixers |
1407 | */ | 1412 | */ |
1408 | 1413 | ||
1409 | static struct snd_kcontrol_new aureon_dac_controls[] __devinitdata = { | 1414 | static const struct snd_kcontrol_new aureon_dac_controls[] __devinitdata = { |
1410 | { | 1415 | { |
1411 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1416 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1412 | .name = "Master Playback Switch", | 1417 | .name = "Master Playback Switch", |
@@ -1521,7 +1526,7 @@ static struct snd_kcontrol_new aureon_dac_controls[] __devinitdata = { | |||
1521 | } | 1526 | } |
1522 | }; | 1527 | }; |
1523 | 1528 | ||
1524 | static struct snd_kcontrol_new wm_controls[] __devinitdata = { | 1529 | static const struct snd_kcontrol_new wm_controls[] __devinitdata = { |
1525 | { | 1530 | { |
1526 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1531 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1527 | .name = "PCM Playback Switch", | 1532 | .name = "PCM Playback Switch", |
@@ -1587,7 +1592,7 @@ static struct snd_kcontrol_new wm_controls[] __devinitdata = { | |||
1587 | } | 1592 | } |
1588 | }; | 1593 | }; |
1589 | 1594 | ||
1590 | static struct snd_kcontrol_new ac97_controls[] __devinitdata = { | 1595 | static const struct snd_kcontrol_new ac97_controls[] __devinitdata = { |
1591 | { | 1596 | { |
1592 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1597 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1593 | .name = "AC97 Playback Switch", | 1598 | .name = "AC97 Playback Switch", |
@@ -1692,7 +1697,7 @@ static struct snd_kcontrol_new ac97_controls[] __devinitdata = { | |||
1692 | } | 1697 | } |
1693 | }; | 1698 | }; |
1694 | 1699 | ||
1695 | static struct snd_kcontrol_new universe_ac97_controls[] __devinitdata = { | 1700 | static const struct snd_kcontrol_new universe_ac97_controls[] __devinitdata = { |
1696 | { | 1701 | { |
1697 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1702 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1698 | .name = "AC97 Playback Switch", | 1703 | .name = "AC97 Playback Switch", |
@@ -1824,8 +1829,7 @@ static struct snd_kcontrol_new universe_ac97_controls[] __devinitdata = { | |||
1824 | 1829 | ||
1825 | }; | 1830 | }; |
1826 | 1831 | ||
1827 | 1832 | static const struct snd_kcontrol_new cs8415_controls[] __devinitdata = { | |
1828 | static struct snd_kcontrol_new cs8415_controls[] __devinitdata = { | ||
1829 | { | 1833 | { |
1830 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1834 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1831 | .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), | 1835 | .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), |
@@ -1870,7 +1874,6 @@ static struct snd_kcontrol_new cs8415_controls[] __devinitdata = { | |||
1870 | } | 1874 | } |
1871 | }; | 1875 | }; |
1872 | 1876 | ||
1873 | |||
1874 | static int __devinit aureon_add_controls(struct snd_ice1712 *ice) | 1877 | static int __devinit aureon_add_controls(struct snd_ice1712 *ice) |
1875 | { | 1878 | { |
1876 | unsigned int i, counts; | 1879 | unsigned int i, counts; |
@@ -1898,7 +1901,8 @@ static int __devinit aureon_add_controls(struct snd_ice1712 *ice) | |||
1898 | return err; | 1901 | return err; |
1899 | } | 1902 | } |
1900 | } | 1903 | } |
1901 | else if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT) { | 1904 | else if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT && |
1905 | ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT) { | ||
1902 | for (i = 0; i < ARRAY_SIZE(ac97_controls); i++) { | 1906 | for (i = 0; i < ARRAY_SIZE(ac97_controls); i++) { |
1903 | err = snd_ctl_add(ice->card, snd_ctl_new1(&ac97_controls[i], ice)); | 1907 | err = snd_ctl_add(ice->card, snd_ctl_new1(&ac97_controls[i], ice)); |
1904 | if (err < 0) | 1908 | if (err < 0) |
@@ -1906,7 +1910,8 @@ static int __devinit aureon_add_controls(struct snd_ice1712 *ice) | |||
1906 | } | 1910 | } |
1907 | } | 1911 | } |
1908 | 1912 | ||
1909 | if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT) { | 1913 | if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT && |
1914 | ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT) { | ||
1910 | unsigned char id; | 1915 | unsigned char id; |
1911 | snd_ice1712_save_gpio_status(ice); | 1916 | snd_ice1712_save_gpio_status(ice); |
1912 | id = aureon_cs8415_get(ice, CS8415_ID); | 1917 | id = aureon_cs8415_get(ice, CS8415_ID); |
@@ -1936,7 +1941,7 @@ static int __devinit aureon_add_controls(struct snd_ice1712 *ice) | |||
1936 | */ | 1941 | */ |
1937 | static int __devinit aureon_init(struct snd_ice1712 *ice) | 1942 | static int __devinit aureon_init(struct snd_ice1712 *ice) |
1938 | { | 1943 | { |
1939 | static unsigned short wm_inits_aureon[] = { | 1944 | static const unsigned short wm_inits_aureon[] = { |
1940 | /* These come first to reduce init pop noise */ | 1945 | /* These come first to reduce init pop noise */ |
1941 | 0x1b, 0x044, /* ADC Mux (AC'97 source) */ | 1946 | 0x1b, 0x044, /* ADC Mux (AC'97 source) */ |
1942 | 0x1c, 0x00B, /* Out Mux1 (VOUT1 = DAC+AUX, VOUT2 = DAC) */ | 1947 | 0x1c, 0x00B, /* Out Mux1 (VOUT1 = DAC+AUX, VOUT2 = DAC) */ |
@@ -1972,7 +1977,7 @@ static int __devinit aureon_init(struct snd_ice1712 *ice) | |||
1972 | 0x1a, 0x000, /* -12dB ADC/R */ | 1977 | 0x1a, 0x000, /* -12dB ADC/R */ |
1973 | (unsigned short)-1 | 1978 | (unsigned short)-1 |
1974 | }; | 1979 | }; |
1975 | static unsigned short wm_inits_prodigy[] = { | 1980 | static const unsigned short wm_inits_prodigy[] = { |
1976 | 1981 | ||
1977 | /* These come first to reduce init pop noise */ | 1982 | /* These come first to reduce init pop noise */ |
1978 | 0x1b, 0x000, /* ADC Mux */ | 1983 | 0x1b, 0x000, /* ADC Mux */ |
@@ -2014,7 +2019,7 @@ static int __devinit aureon_init(struct snd_ice1712 *ice) | |||
2014 | (unsigned short)-1 | 2019 | (unsigned short)-1 |
2015 | 2020 | ||
2016 | }; | 2021 | }; |
2017 | static unsigned short cs_inits[] = { | 2022 | static const unsigned short cs_inits[] = { |
2018 | 0x0441, /* RUN */ | 2023 | 0x0441, /* RUN */ |
2019 | 0x0180, /* no mute, OMCK output on RMCK pin */ | 2024 | 0x0180, /* no mute, OMCK output on RMCK pin */ |
2020 | 0x0201, /* S/PDIF source on RXP1 */ | 2025 | 0x0201, /* S/PDIF source on RXP1 */ |
@@ -2022,7 +2027,7 @@ static int __devinit aureon_init(struct snd_ice1712 *ice) | |||
2022 | (unsigned short)-1 | 2027 | (unsigned short)-1 |
2023 | }; | 2028 | }; |
2024 | unsigned int tmp; | 2029 | unsigned int tmp; |
2025 | unsigned short *p; | 2030 | const unsigned short *p; |
2026 | int err, i; | 2031 | int err, i; |
2027 | 2032 | ||
2028 | if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON51_SKY) { | 2033 | if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON51_SKY) { |
@@ -2062,7 +2067,8 @@ static int __devinit aureon_init(struct snd_ice1712 *ice) | |||
2062 | 2067 | ||
2063 | /* initialize WM8770 codec */ | 2068 | /* initialize WM8770 codec */ |
2064 | if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71 || | 2069 | if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71 || |
2065 | ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT) | 2070 | ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT || |
2071 | ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71XT) | ||
2066 | p = wm_inits_prodigy; | 2072 | p = wm_inits_prodigy; |
2067 | else | 2073 | else |
2068 | p = wm_inits_aureon; | 2074 | p = wm_inits_aureon; |
@@ -2070,7 +2076,8 @@ static int __devinit aureon_init(struct snd_ice1712 *ice) | |||
2070 | wm_put(ice, p[0], p[1]); | 2076 | wm_put(ice, p[0], p[1]); |
2071 | 2077 | ||
2072 | /* initialize CS8415A codec */ | 2078 | /* initialize CS8415A codec */ |
2073 | if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT) { | 2079 | if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT && |
2080 | ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT) { | ||
2074 | for (p = cs_inits; *p != (unsigned short)-1; p++) | 2081 | for (p = cs_inits; *p != (unsigned short)-1; p++) |
2075 | aureon_spi_write(ice, AUREON_CS8415_CS, *p | 0x200000, 24); | 2082 | aureon_spi_write(ice, AUREON_CS8415_CS, *p | 0x200000, 24); |
2076 | ice->spec.aureon.cs8415_mux = 1; | 2083 | ice->spec.aureon.cs8415_mux = 1; |
@@ -2100,73 +2107,58 @@ static int __devinit aureon_init(struct snd_ice1712 *ice) | |||
2100 | * hence the driver needs to sets up it properly. | 2107 | * hence the driver needs to sets up it properly. |
2101 | */ | 2108 | */ |
2102 | 2109 | ||
2103 | static unsigned char aureon51_eeprom[] __devinitdata = { | 2110 | static const unsigned char aureon51_eeprom[] __devinitdata = { |
2104 | 0x0a, /* SYSCONF: clock 512, spdif-in/ADC, 3DACs */ | 2111 | [ICE_EEP2_SYSCONF] = 0x0a, /* clock 512, spdif-in/ADC, 3DACs */ |
2105 | 0x80, /* ACLINK: I2S */ | 2112 | [ICE_EEP2_ACLINK] = 0x80, /* I2S */ |
2106 | 0xfc, /* I2S: vol, 96k, 24bit, 192k */ | 2113 | [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */ |
2107 | 0xc3, /* SPDIF: out-en, out-int, spdif-in */ | 2114 | [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */ |
2108 | 0xff, /* GPIO_DIR */ | 2115 | [ICE_EEP2_GPIO_DIR] = 0xff, |
2109 | 0xff, /* GPIO_DIR1 */ | 2116 | [ICE_EEP2_GPIO_DIR1] = 0xff, |
2110 | 0x5f, /* GPIO_DIR2 */ | 2117 | [ICE_EEP2_GPIO_DIR2] = 0x5f, |
2111 | 0x00, /* GPIO_MASK */ | 2118 | [ICE_EEP2_GPIO_MASK] = 0x00, |
2112 | 0x00, /* GPIO_MASK1 */ | 2119 | [ICE_EEP2_GPIO_MASK1] = 0x00, |
2113 | 0x00, /* GPIO_MASK2 */ | 2120 | [ICE_EEP2_GPIO_MASK2] = 0x00, |
2114 | 0x00, /* GPIO_STATE */ | 2121 | [ICE_EEP2_GPIO_STATE] = 0x00, |
2115 | 0x00, /* GPIO_STATE1 */ | 2122 | [ICE_EEP2_GPIO_STATE1] = 0x00, |
2116 | 0x00, /* GPIO_STATE2 */ | 2123 | [ICE_EEP2_GPIO_STATE2] = 0x00, |
2117 | }; | 2124 | }; |
2118 | 2125 | ||
2119 | static unsigned char aureon71_eeprom[] __devinitdata = { | 2126 | static const unsigned char aureon71_eeprom[] __devinitdata = { |
2120 | 0x0b, /* SYSCONF: clock 512, spdif-in/ADC, 4DACs */ | 2127 | [ICE_EEP2_SYSCONF] = 0x0b, /* clock 512, spdif-in/ADC, 4DACs */ |
2121 | 0x80, /* ACLINK: I2S */ | 2128 | [ICE_EEP2_ACLINK] = 0x80, /* I2S */ |
2122 | 0xfc, /* I2S: vol, 96k, 24bit, 192k */ | 2129 | [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */ |
2123 | 0xc3, /* SPDIF: out-en, out-int, spdif-in */ | 2130 | [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */ |
2124 | 0xff, /* GPIO_DIR */ | 2131 | [ICE_EEP2_GPIO_DIR] = 0xff, |
2125 | 0xff, /* GPIO_DIR1 */ | 2132 | [ICE_EEP2_GPIO_DIR1] = 0xff, |
2126 | 0x5f, /* GPIO_DIR2 */ | 2133 | [ICE_EEP2_GPIO_DIR2] = 0x5f, |
2127 | 0x00, /* GPIO_MASK */ | 2134 | [ICE_EEP2_GPIO_MASK] = 0x00, |
2128 | 0x00, /* GPIO_MASK1 */ | 2135 | [ICE_EEP2_GPIO_MASK1] = 0x00, |
2129 | 0x00, /* GPIO_MASK2 */ | 2136 | [ICE_EEP2_GPIO_MASK2] = 0x00, |
2130 | 0x00, /* GPIO_STATE */ | 2137 | [ICE_EEP2_GPIO_STATE] = 0x00, |
2131 | 0x00, /* GPIO_STATE1 */ | 2138 | [ICE_EEP2_GPIO_STATE1] = 0x00, |
2132 | 0x00, /* GPIO_STATE2 */ | 2139 | [ICE_EEP2_GPIO_STATE2] = 0x00, |
2133 | }; | 2140 | }; |
2134 | 2141 | #define prodigy71_eeprom aureon71_eeprom | |
2135 | static unsigned char prodigy71_eeprom[] __devinitdata = { | 2142 | |
2136 | 0x0b, /* SYSCONF: clock 512, spdif-in/ADC, 4DACs */ | 2143 | static const unsigned char prodigy71lt_eeprom[] __devinitdata = { |
2137 | 0x80, /* ACLINK: I2S */ | 2144 | [ICE_EEP2_SYSCONF] = 0x4b, /* clock 384, spdif-in/ADC, 4DACs */ |
2138 | 0xfc, /* I2S: vol, 96k, 24bit, 192k */ | 2145 | [ICE_EEP2_ACLINK] = 0x80, /* I2S */ |
2139 | 0xc3, /* SPDIF: out-en, out-int, spdif-in */ | 2146 | [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */ |
2140 | 0xff, /* GPIO_DIR */ | 2147 | [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */ |
2141 | 0xff, /* GPIO_DIR1 */ | 2148 | [ICE_EEP2_GPIO_DIR] = 0xff, |
2142 | 0x5f, /* GPIO_DIR2 */ | 2149 | [ICE_EEP2_GPIO_DIR1] = 0xff, |
2143 | 0x00, /* GPIO_MASK */ | 2150 | [ICE_EEP2_GPIO_DIR2] = 0x5f, |
2144 | 0x00, /* GPIO_MASK1 */ | 2151 | [ICE_EEP2_GPIO_MASK] = 0x00, |
2145 | 0x00, /* GPIO_MASK2 */ | 2152 | [ICE_EEP2_GPIO_MASK1] = 0x00, |
2146 | 0x00, /* GPIO_STATE */ | 2153 | [ICE_EEP2_GPIO_MASK2] = 0x00, |
2147 | 0x00, /* GPIO_STATE1 */ | 2154 | [ICE_EEP2_GPIO_STATE] = 0x00, |
2148 | 0x00, /* GPIO_STATE2 */ | 2155 | [ICE_EEP2_GPIO_STATE1] = 0x00, |
2156 | [ICE_EEP2_GPIO_STATE2] = 0x00, | ||
2149 | }; | 2157 | }; |
2150 | 2158 | #define prodigy71xt_eeprom prodigy71lt_eeprom | |
2151 | static unsigned char prodigy71lt_eeprom[] __devinitdata = { | ||
2152 | 0x4b, /* SYSCINF: clock 512, spdif-in/ADC, 4DACs */ | ||
2153 | 0x80, /* ACLINK: I2S */ | ||
2154 | 0xfc, /* I2S: vol, 96k, 24bit, 192k */ | ||
2155 | 0xc3, /* SPDIF: out-en, out-int, spdif-in */ | ||
2156 | 0xff, /* GPIO_DIR */ | ||
2157 | 0xff, /* GPIO_DIR1 */ | ||
2158 | 0x5f, /* GPIO_DIR2 */ | ||
2159 | 0x00, /* GPIO_MASK */ | ||
2160 | 0x00, /* GPIO_MASK1 */ | ||
2161 | 0x00, /* GPIO_MASK2 */ | ||
2162 | 0x00, /* GPIO_STATE */ | ||
2163 | 0x00, /* GPIO_STATE1 */ | ||
2164 | 0x00, /* GPIO_STATE2 */ | ||
2165 | }; | ||
2166 | |||
2167 | 2159 | ||
2168 | /* entry point */ | 2160 | /* entry point */ |
2169 | struct snd_ice1712_card_info snd_vt1724_aureon_cards[] __devinitdata = { | 2161 | const struct snd_ice1712_card_info snd_vt1724_aureon_cards[] __devinitdata = { |
2170 | { | 2162 | { |
2171 | .subvendor = VT1724_SUBDEVICE_AUREON51_SKY, | 2163 | .subvendor = VT1724_SUBDEVICE_AUREON51_SKY, |
2172 | .name = "Terratec Aureon 5.1-Sky", | 2164 | .name = "Terratec Aureon 5.1-Sky", |
@@ -2217,5 +2209,15 @@ struct snd_ice1712_card_info snd_vt1724_aureon_cards[] __devinitdata = { | |||
2217 | .eeprom_data = prodigy71lt_eeprom, | 2209 | .eeprom_data = prodigy71lt_eeprom, |
2218 | .driver = "Prodigy71LT", | 2210 | .driver = "Prodigy71LT", |
2219 | }, | 2211 | }, |
2212 | { | ||
2213 | .subvendor = VT1724_SUBDEVICE_PRODIGY71XT, | ||
2214 | .name = "Audiotrak Prodigy 7.1 XT", | ||
2215 | .model = "prodigy71xt", | ||
2216 | .chip_init = aureon_init, | ||
2217 | .build_controls = aureon_add_controls, | ||
2218 | .eeprom_size = sizeof(prodigy71xt_eeprom), | ||
2219 | .eeprom_data = prodigy71xt_eeprom, | ||
2220 | .driver = "Prodigy71LT", | ||
2221 | }, | ||
2220 | { } /* terminator */ | 2222 | { } /* terminator */ |
2221 | }; | 2223 | }; |
diff --git a/sound/pci/ice1712/aureon.h b/sound/pci/ice1712/aureon.h index 3b7bea656c57..79e58e88ed47 100644 --- a/sound/pci/ice1712/aureon.h +++ b/sound/pci/ice1712/aureon.h | |||
@@ -28,15 +28,17 @@ | |||
28 | "{Terratec,Aureon 7.1 Space},"\ | 28 | "{Terratec,Aureon 7.1 Space},"\ |
29 | "{Terratec,Aureon 7.1 Universe}," \ | 29 | "{Terratec,Aureon 7.1 Universe}," \ |
30 | "{AudioTrak,Prodigy 7.1}," \ | 30 | "{AudioTrak,Prodigy 7.1}," \ |
31 | "{AudioTrak,Prodigy 7.1 LT}," | 31 | "{AudioTrak,Prodigy 7.1 LT},"\ |
32 | "{AudioTrak,Prodigy 7.1 XT}," | ||
32 | 33 | ||
33 | #define VT1724_SUBDEVICE_AUREON51_SKY 0x3b154711 /* Aureon 5.1 Sky */ | 34 | #define VT1724_SUBDEVICE_AUREON51_SKY 0x3b154711 /* Aureon 5.1 Sky */ |
34 | #define VT1724_SUBDEVICE_AUREON71_SPACE 0x3b154511 /* Aureon 7.1 Space */ | 35 | #define VT1724_SUBDEVICE_AUREON71_SPACE 0x3b154511 /* Aureon 7.1 Space */ |
35 | #define VT1724_SUBDEVICE_AUREON71_UNIVERSE 0x3b155311 /* Aureon 7.1 Universe */ | 36 | #define VT1724_SUBDEVICE_AUREON71_UNIVERSE 0x3b155311 /* Aureon 7.1 Universe */ |
36 | #define VT1724_SUBDEVICE_PRODIGY71 0x33495345 /* PRODIGY 7.1 */ | 37 | #define VT1724_SUBDEVICE_PRODIGY71 0x33495345 /* PRODIGY 7.1 */ |
37 | #define VT1724_SUBDEVICE_PRODIGY71LT 0x32315441 /* PRODIGY 7.1 LT */ | 38 | #define VT1724_SUBDEVICE_PRODIGY71LT 0x32315441 /* PRODIGY 7.1 LT */ |
39 | #define VT1724_SUBDEVICE_PRODIGY71XT 0x36315441 /* PRODIGY 7.1 XT*/ | ||
38 | 40 | ||
39 | extern struct snd_ice1712_card_info snd_vt1724_aureon_cards[]; | 41 | extern const struct snd_ice1712_card_info snd_vt1724_aureon_cards[]; |
40 | 42 | ||
41 | /* GPIO bits */ | 43 | /* GPIO bits */ |
42 | #define AUREON_CS8415_CS (1 << 22) | 44 | #define AUREON_CS8415_CS (1 << 22) |
diff --git a/sound/pci/ice1712/delta.c b/sound/pci/ice1712/delta.c index af659800c9b0..3eeb36c6e985 100644 --- a/sound/pci/ice1712/delta.c +++ b/sound/pci/ice1712/delta.c | |||
@@ -416,7 +416,7 @@ static int snd_ice1712_delta1010lt_wordclock_status_get(struct snd_kcontrol *kco | |||
416 | return 0; | 416 | return 0; |
417 | } | 417 | } |
418 | 418 | ||
419 | static struct snd_kcontrol_new snd_ice1712_delta1010lt_wordclock_status __devinitdata = | 419 | static const struct snd_kcontrol_new snd_ice1712_delta1010lt_wordclock_status __devinitdata = |
420 | { | 420 | { |
421 | .access = (SNDRV_CTL_ELEM_ACCESS_READ), | 421 | .access = (SNDRV_CTL_ELEM_ACCESS_READ), |
422 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 422 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -429,7 +429,7 @@ static struct snd_kcontrol_new snd_ice1712_delta1010lt_wordclock_status __devini | |||
429 | * initialize the chips on M-Audio cards | 429 | * initialize the chips on M-Audio cards |
430 | */ | 430 | */ |
431 | 431 | ||
432 | static struct snd_akm4xxx akm_audiophile __devinitdata = { | 432 | static const struct snd_akm4xxx akm_audiophile __devinitdata = { |
433 | .type = SND_AK4528, | 433 | .type = SND_AK4528, |
434 | .num_adcs = 2, | 434 | .num_adcs = 2, |
435 | .num_dacs = 2, | 435 | .num_dacs = 2, |
@@ -438,7 +438,7 @@ static struct snd_akm4xxx akm_audiophile __devinitdata = { | |||
438 | } | 438 | } |
439 | }; | 439 | }; |
440 | 440 | ||
441 | static struct snd_ak4xxx_private akm_audiophile_priv __devinitdata = { | 441 | static const struct snd_ak4xxx_private akm_audiophile_priv __devinitdata = { |
442 | .caddr = 2, | 442 | .caddr = 2, |
443 | .cif = 0, | 443 | .cif = 0, |
444 | .data_mask = ICE1712_DELTA_AP_DOUT, | 444 | .data_mask = ICE1712_DELTA_AP_DOUT, |
@@ -450,7 +450,7 @@ static struct snd_ak4xxx_private akm_audiophile_priv __devinitdata = { | |||
450 | .mask_flags = 0, | 450 | .mask_flags = 0, |
451 | }; | 451 | }; |
452 | 452 | ||
453 | static struct snd_akm4xxx akm_delta410 __devinitdata = { | 453 | static const struct snd_akm4xxx akm_delta410 __devinitdata = { |
454 | .type = SND_AK4529, | 454 | .type = SND_AK4529, |
455 | .num_adcs = 2, | 455 | .num_adcs = 2, |
456 | .num_dacs = 8, | 456 | .num_dacs = 8, |
@@ -459,7 +459,7 @@ static struct snd_akm4xxx akm_delta410 __devinitdata = { | |||
459 | } | 459 | } |
460 | }; | 460 | }; |
461 | 461 | ||
462 | static struct snd_ak4xxx_private akm_delta410_priv __devinitdata = { | 462 | static const struct snd_ak4xxx_private akm_delta410_priv __devinitdata = { |
463 | .caddr = 0, | 463 | .caddr = 0, |
464 | .cif = 0, | 464 | .cif = 0, |
465 | .data_mask = ICE1712_DELTA_AP_DOUT, | 465 | .data_mask = ICE1712_DELTA_AP_DOUT, |
@@ -471,7 +471,7 @@ static struct snd_ak4xxx_private akm_delta410_priv __devinitdata = { | |||
471 | .mask_flags = 0, | 471 | .mask_flags = 0, |
472 | }; | 472 | }; |
473 | 473 | ||
474 | static struct snd_akm4xxx akm_delta1010lt __devinitdata = { | 474 | static const struct snd_akm4xxx akm_delta1010lt __devinitdata = { |
475 | .type = SND_AK4524, | 475 | .type = SND_AK4524, |
476 | .num_adcs = 8, | 476 | .num_adcs = 8, |
477 | .num_dacs = 8, | 477 | .num_dacs = 8, |
@@ -481,7 +481,7 @@ static struct snd_akm4xxx akm_delta1010lt __devinitdata = { | |||
481 | } | 481 | } |
482 | }; | 482 | }; |
483 | 483 | ||
484 | static struct snd_ak4xxx_private akm_delta1010lt_priv __devinitdata = { | 484 | static const struct snd_ak4xxx_private akm_delta1010lt_priv __devinitdata = { |
485 | .caddr = 2, | 485 | .caddr = 2, |
486 | .cif = 0, /* the default level of the CIF pin from AK4524 */ | 486 | .cif = 0, /* the default level of the CIF pin from AK4524 */ |
487 | .data_mask = ICE1712_DELTA_1010LT_DOUT, | 487 | .data_mask = ICE1712_DELTA_1010LT_DOUT, |
@@ -493,7 +493,7 @@ static struct snd_ak4xxx_private akm_delta1010lt_priv __devinitdata = { | |||
493 | .mask_flags = 0, | 493 | .mask_flags = 0, |
494 | }; | 494 | }; |
495 | 495 | ||
496 | static struct snd_akm4xxx akm_delta44 __devinitdata = { | 496 | static const struct snd_akm4xxx akm_delta44 __devinitdata = { |
497 | .type = SND_AK4524, | 497 | .type = SND_AK4524, |
498 | .num_adcs = 4, | 498 | .num_adcs = 4, |
499 | .num_dacs = 4, | 499 | .num_dacs = 4, |
@@ -503,7 +503,7 @@ static struct snd_akm4xxx akm_delta44 __devinitdata = { | |||
503 | } | 503 | } |
504 | }; | 504 | }; |
505 | 505 | ||
506 | static struct snd_ak4xxx_private akm_delta44_priv __devinitdata = { | 506 | static const struct snd_ak4xxx_private akm_delta44_priv __devinitdata = { |
507 | .caddr = 2, | 507 | .caddr = 2, |
508 | .cif = 0, /* the default level of the CIF pin from AK4524 */ | 508 | .cif = 0, /* the default level of the CIF pin from AK4524 */ |
509 | .data_mask = ICE1712_DELTA_CODEC_SERIAL_DATA, | 509 | .data_mask = ICE1712_DELTA_CODEC_SERIAL_DATA, |
@@ -515,7 +515,7 @@ static struct snd_ak4xxx_private akm_delta44_priv __devinitdata = { | |||
515 | .mask_flags = 0, | 515 | .mask_flags = 0, |
516 | }; | 516 | }; |
517 | 517 | ||
518 | static struct snd_akm4xxx akm_vx442 __devinitdata = { | 518 | static const struct snd_akm4xxx akm_vx442 __devinitdata = { |
519 | .type = SND_AK4524, | 519 | .type = SND_AK4524, |
520 | .num_adcs = 4, | 520 | .num_adcs = 4, |
521 | .num_dacs = 4, | 521 | .num_dacs = 4, |
@@ -525,7 +525,7 @@ static struct snd_akm4xxx akm_vx442 __devinitdata = { | |||
525 | } | 525 | } |
526 | }; | 526 | }; |
527 | 527 | ||
528 | static struct snd_ak4xxx_private akm_vx442_priv __devinitdata = { | 528 | static const struct snd_ak4xxx_private akm_vx442_priv __devinitdata = { |
529 | .caddr = 2, | 529 | .caddr = 2, |
530 | .cif = 0, | 530 | .cif = 0, |
531 | .data_mask = ICE1712_VX442_DOUT, | 531 | .data_mask = ICE1712_VX442_DOUT, |
@@ -650,15 +650,15 @@ static int __devinit snd_ice1712_delta_init(struct snd_ice1712 *ice) | |||
650 | * additional controls for M-Audio cards | 650 | * additional controls for M-Audio cards |
651 | */ | 651 | */ |
652 | 652 | ||
653 | static struct snd_kcontrol_new snd_ice1712_delta1010_wordclock_select __devinitdata = | 653 | static const struct snd_kcontrol_new snd_ice1712_delta1010_wordclock_select __devinitdata = |
654 | ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "Word Clock Sync", 0, ICE1712_DELTA_WORD_CLOCK_SELECT, 1, 0); | 654 | ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "Word Clock Sync", 0, ICE1712_DELTA_WORD_CLOCK_SELECT, 1, 0); |
655 | static struct snd_kcontrol_new snd_ice1712_delta1010lt_wordclock_select __devinitdata = | 655 | static const struct snd_kcontrol_new snd_ice1712_delta1010lt_wordclock_select __devinitdata = |
656 | ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "Word Clock Sync", 0, ICE1712_DELTA_1010LT_WORDCLOCK, 0, 0); | 656 | ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "Word Clock Sync", 0, ICE1712_DELTA_1010LT_WORDCLOCK, 0, 0); |
657 | static struct snd_kcontrol_new snd_ice1712_delta1010_wordclock_status __devinitdata = | 657 | static const struct snd_kcontrol_new snd_ice1712_delta1010_wordclock_status __devinitdata = |
658 | ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "Word Clock Status", 0, ICE1712_DELTA_WORD_CLOCK_STATUS, 1, SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE); | 658 | ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "Word Clock Status", 0, ICE1712_DELTA_WORD_CLOCK_STATUS, 1, SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE); |
659 | static struct snd_kcontrol_new snd_ice1712_deltadio2496_spdif_in_select __devinitdata = | 659 | static const struct snd_kcontrol_new snd_ice1712_deltadio2496_spdif_in_select __devinitdata = |
660 | ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "IEC958 Input Optical", 0, ICE1712_DELTA_SPDIF_INPUT_SELECT, 0, 0); | 660 | ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "IEC958 Input Optical", 0, ICE1712_DELTA_SPDIF_INPUT_SELECT, 0, 0); |
661 | static struct snd_kcontrol_new snd_ice1712_delta_spdif_in_status __devinitdata = | 661 | static const struct snd_kcontrol_new snd_ice1712_delta_spdif_in_status __devinitdata = |
662 | ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "Delta IEC958 Input Status", 0, ICE1712_DELTA_SPDIF_IN_STAT, 1, SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE); | 662 | ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "Delta IEC958 Input Status", 0, ICE1712_DELTA_SPDIF_IN_STAT, 1, SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE); |
663 | 663 | ||
664 | 664 | ||
@@ -735,7 +735,7 @@ static int __devinit snd_ice1712_delta_add_controls(struct snd_ice1712 *ice) | |||
735 | 735 | ||
736 | 736 | ||
737 | /* entry point */ | 737 | /* entry point */ |
738 | struct snd_ice1712_card_info snd_ice1712_delta_cards[] __devinitdata = { | 738 | const struct snd_ice1712_card_info snd_ice1712_delta_cards[] __devinitdata = { |
739 | { | 739 | { |
740 | .subvendor = ICE1712_SUBDEVICE_DELTA1010, | 740 | .subvendor = ICE1712_SUBDEVICE_DELTA1010, |
741 | .name = "M Audio Delta 1010", | 741 | .name = "M Audio Delta 1010", |
diff --git a/sound/pci/ice1712/delta.h b/sound/pci/ice1712/delta.h index 746ebde94522..e65d669af639 100644 --- a/sound/pci/ice1712/delta.h +++ b/sound/pci/ice1712/delta.h | |||
@@ -46,7 +46,7 @@ | |||
46 | #define ICE1712_SUBDEVICE_MEDIASTATION 0x694c0100 | 46 | #define ICE1712_SUBDEVICE_MEDIASTATION 0x694c0100 |
47 | 47 | ||
48 | /* entry point */ | 48 | /* entry point */ |
49 | extern struct snd_ice1712_card_info snd_ice1712_delta_cards[]; | 49 | extern const struct snd_ice1712_card_info snd_ice1712_delta_cards[]; |
50 | 50 | ||
51 | 51 | ||
52 | /* | 52 | /* |
diff --git a/sound/pci/ice1712/ews.c b/sound/pci/ice1712/ews.c index b135389fec6c..9b7ff302c072 100644 --- a/sound/pci/ice1712/ews.c +++ b/sound/pci/ice1712/ews.c | |||
@@ -332,7 +332,7 @@ static void ews88_setup_spdif(struct snd_ice1712 *ice, int rate) | |||
332 | 332 | ||
333 | /* | 333 | /* |
334 | */ | 334 | */ |
335 | static struct snd_akm4xxx akm_ews88mt __devinitdata = { | 335 | static const struct snd_akm4xxx akm_ews88mt __devinitdata = { |
336 | .num_adcs = 8, | 336 | .num_adcs = 8, |
337 | .num_dacs = 8, | 337 | .num_dacs = 8, |
338 | .type = SND_AK4524, | 338 | .type = SND_AK4524, |
@@ -342,7 +342,7 @@ static struct snd_akm4xxx akm_ews88mt __devinitdata = { | |||
342 | } | 342 | } |
343 | }; | 343 | }; |
344 | 344 | ||
345 | static struct snd_ak4xxx_private akm_ews88mt_priv __devinitdata = { | 345 | static const struct snd_ak4xxx_private akm_ews88mt_priv __devinitdata = { |
346 | .caddr = 2, | 346 | .caddr = 2, |
347 | .cif = 1, /* CIF high */ | 347 | .cif = 1, /* CIF high */ |
348 | .data_mask = ICE1712_EWS88_SERIAL_DATA, | 348 | .data_mask = ICE1712_EWS88_SERIAL_DATA, |
@@ -354,7 +354,7 @@ static struct snd_ak4xxx_private akm_ews88mt_priv __devinitdata = { | |||
354 | .mask_flags = 0, | 354 | .mask_flags = 0, |
355 | }; | 355 | }; |
356 | 356 | ||
357 | static struct snd_akm4xxx akm_ewx2496 __devinitdata = { | 357 | static const struct snd_akm4xxx akm_ewx2496 __devinitdata = { |
358 | .num_adcs = 2, | 358 | .num_adcs = 2, |
359 | .num_dacs = 2, | 359 | .num_dacs = 2, |
360 | .type = SND_AK4524, | 360 | .type = SND_AK4524, |
@@ -363,7 +363,7 @@ static struct snd_akm4xxx akm_ewx2496 __devinitdata = { | |||
363 | } | 363 | } |
364 | }; | 364 | }; |
365 | 365 | ||
366 | static struct snd_ak4xxx_private akm_ewx2496_priv __devinitdata = { | 366 | static const struct snd_ak4xxx_private akm_ewx2496_priv __devinitdata = { |
367 | .caddr = 2, | 367 | .caddr = 2, |
368 | .cif = 1, /* CIF high */ | 368 | .cif = 1, /* CIF high */ |
369 | .data_mask = ICE1712_EWS88_SERIAL_DATA, | 369 | .data_mask = ICE1712_EWS88_SERIAL_DATA, |
@@ -375,7 +375,7 @@ static struct snd_ak4xxx_private akm_ewx2496_priv __devinitdata = { | |||
375 | .mask_flags = 0, | 375 | .mask_flags = 0, |
376 | }; | 376 | }; |
377 | 377 | ||
378 | static struct snd_akm4xxx akm_6fire __devinitdata = { | 378 | static const struct snd_akm4xxx akm_6fire __devinitdata = { |
379 | .num_adcs = 6, | 379 | .num_adcs = 6, |
380 | .num_dacs = 6, | 380 | .num_dacs = 6, |
381 | .type = SND_AK4524, | 381 | .type = SND_AK4524, |
@@ -384,7 +384,7 @@ static struct snd_akm4xxx akm_6fire __devinitdata = { | |||
384 | } | 384 | } |
385 | }; | 385 | }; |
386 | 386 | ||
387 | static struct snd_ak4xxx_private akm_6fire_priv __devinitdata = { | 387 | static const struct snd_ak4xxx_private akm_6fire_priv __devinitdata = { |
388 | .caddr = 2, | 388 | .caddr = 2, |
389 | .cif = 1, /* CIF high */ | 389 | .cif = 1, /* CIF high */ |
390 | .data_mask = ICE1712_6FIRE_SERIAL_DATA, | 390 | .data_mask = ICE1712_6FIRE_SERIAL_DATA, |
@@ -578,7 +578,7 @@ static int snd_ice1712_ewx_io_sense_put(struct snd_kcontrol *kcontrol, struct sn | |||
578 | return val != nval; | 578 | return val != nval; |
579 | } | 579 | } |
580 | 580 | ||
581 | static struct snd_kcontrol_new snd_ice1712_ewx2496_controls[] __devinitdata = { | 581 | static const struct snd_kcontrol_new snd_ice1712_ewx2496_controls[] __devinitdata = { |
582 | { | 582 | { |
583 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 583 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
584 | .name = "Input Sensitivity Switch", | 584 | .name = "Input Sensitivity Switch", |
@@ -678,7 +678,7 @@ static int snd_ice1712_ews88mt_input_sense_put(struct snd_kcontrol *kcontrol, st | |||
678 | return ndata != data; | 678 | return ndata != data; |
679 | } | 679 | } |
680 | 680 | ||
681 | static struct snd_kcontrol_new snd_ice1712_ews88mt_input_sense __devinitdata = { | 681 | static const struct snd_kcontrol_new snd_ice1712_ews88mt_input_sense __devinitdata = { |
682 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 682 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
683 | .name = "Input Sensitivity Switch", | 683 | .name = "Input Sensitivity Switch", |
684 | .info = snd_ice1712_ewx_io_sense_info, | 684 | .info = snd_ice1712_ewx_io_sense_info, |
@@ -687,7 +687,7 @@ static struct snd_kcontrol_new snd_ice1712_ews88mt_input_sense __devinitdata = { | |||
687 | .count = 8, | 687 | .count = 8, |
688 | }; | 688 | }; |
689 | 689 | ||
690 | static struct snd_kcontrol_new snd_ice1712_ews88mt_output_sense __devinitdata = { | 690 | static const struct snd_kcontrol_new snd_ice1712_ews88mt_output_sense __devinitdata = { |
691 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 691 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
692 | .name = "Output Sensitivity Switch", | 692 | .name = "Output Sensitivity Switch", |
693 | .info = snd_ice1712_ewx_io_sense_info, | 693 | .info = snd_ice1712_ewx_io_sense_info, |
@@ -769,7 +769,7 @@ static int snd_ice1712_ews88d_control_put(struct snd_kcontrol *kcontrol, struct | |||
769 | .private_value = xshift | (xinvert << 8),\ | 769 | .private_value = xshift | (xinvert << 8),\ |
770 | } | 770 | } |
771 | 771 | ||
772 | static struct snd_kcontrol_new snd_ice1712_ews88d_controls[] __devinitdata = { | 772 | static const struct snd_kcontrol_new snd_ice1712_ews88d_controls[] __devinitdata = { |
773 | EWS88D_CONTROL(SNDRV_CTL_ELEM_IFACE_MIXER, "IEC958 Input Optical", 0, 1, 0), /* inverted */ | 773 | EWS88D_CONTROL(SNDRV_CTL_ELEM_IFACE_MIXER, "IEC958 Input Optical", 0, 1, 0), /* inverted */ |
774 | EWS88D_CONTROL(SNDRV_CTL_ELEM_IFACE_MIXER, "ADAT Output Optical", 1, 0, 0), | 774 | EWS88D_CONTROL(SNDRV_CTL_ELEM_IFACE_MIXER, "ADAT Output Optical", 1, 0, 0), |
775 | EWS88D_CONTROL(SNDRV_CTL_ELEM_IFACE_MIXER, "ADAT External Master Clock", 2, 0, 0), | 775 | EWS88D_CONTROL(SNDRV_CTL_ELEM_IFACE_MIXER, "ADAT External Master Clock", 2, 0, 0), |
@@ -909,7 +909,7 @@ static int snd_ice1712_6fire_select_input_put(struct snd_kcontrol *kcontrol, str | |||
909 | .private_value = xshift | (xinvert << 8),\ | 909 | .private_value = xshift | (xinvert << 8),\ |
910 | } | 910 | } |
911 | 911 | ||
912 | static struct snd_kcontrol_new snd_ice1712_6fire_controls[] __devinitdata = { | 912 | static const struct snd_kcontrol_new snd_ice1712_6fire_controls[] __devinitdata = { |
913 | { | 913 | { |
914 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 914 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
915 | .name = "Analog Input Select", | 915 | .name = "Analog Input Select", |
@@ -989,7 +989,7 @@ static int __devinit snd_ice1712_ews_add_controls(struct snd_ice1712 *ice) | |||
989 | 989 | ||
990 | 990 | ||
991 | /* entry point */ | 991 | /* entry point */ |
992 | struct snd_ice1712_card_info snd_ice1712_ews_cards[] __devinitdata = { | 992 | const struct snd_ice1712_card_info snd_ice1712_ews_cards[] __devinitdata = { |
993 | { | 993 | { |
994 | .subvendor = ICE1712_SUBDEVICE_EWX2496, | 994 | .subvendor = ICE1712_SUBDEVICE_EWX2496, |
995 | .name = "TerraTec EWX24/96", | 995 | .name = "TerraTec EWX24/96", |
diff --git a/sound/pci/ice1712/ews.h b/sound/pci/ice1712/ews.h index a12a0b053558..df449b4741f6 100644 --- a/sound/pci/ice1712/ews.h +++ b/sound/pci/ice1712/ews.h | |||
@@ -40,7 +40,7 @@ | |||
40 | #define ICE1712_SUBDEVICE_PHASE88 0x3b155111 | 40 | #define ICE1712_SUBDEVICE_PHASE88 0x3b155111 |
41 | 41 | ||
42 | /* entry point */ | 42 | /* entry point */ |
43 | extern struct snd_ice1712_card_info snd_ice1712_ews_cards[]; | 43 | extern const struct snd_ice1712_card_info snd_ice1712_ews_cards[]; |
44 | 44 | ||
45 | 45 | ||
46 | /* TerraTec EWX 24/96 configuration definitions */ | 46 | /* TerraTec EWX 24/96 configuration definitions */ |
diff --git a/sound/pci/ice1712/hoontech.c b/sound/pci/ice1712/hoontech.c index 3f27d04e7d3c..df97313aaf83 100644 --- a/sound/pci/ice1712/hoontech.c +++ b/sound/pci/ice1712/hoontech.c | |||
@@ -239,7 +239,7 @@ static void stdsp24_ak4524_lock(struct snd_akm4xxx *ak, int chip) | |||
239 | static int __devinit snd_ice1712_value_init(struct snd_ice1712 *ice) | 239 | static int __devinit snd_ice1712_value_init(struct snd_ice1712 *ice) |
240 | { | 240 | { |
241 | /* Hoontech STDSP24 with modified hardware */ | 241 | /* Hoontech STDSP24 with modified hardware */ |
242 | static struct snd_akm4xxx akm_stdsp24_mv __devinitdata = { | 242 | static const struct snd_akm4xxx akm_stdsp24_mv __devinitdata = { |
243 | .num_adcs = 2, | 243 | .num_adcs = 2, |
244 | .num_dacs = 2, | 244 | .num_dacs = 2, |
245 | .type = SND_AK4524, | 245 | .type = SND_AK4524, |
@@ -248,7 +248,7 @@ static int __devinit snd_ice1712_value_init(struct snd_ice1712 *ice) | |||
248 | } | 248 | } |
249 | }; | 249 | }; |
250 | 250 | ||
251 | static struct snd_ak4xxx_private akm_stdsp24_mv_priv __devinitdata = { | 251 | static const struct snd_ak4xxx_private akm_stdsp24_mv_priv __devinitdata = { |
252 | .caddr = 2, | 252 | .caddr = 2, |
253 | .cif = 1, /* CIF high */ | 253 | .cif = 1, /* CIF high */ |
254 | .data_mask = ICE1712_STDSP24_SERIAL_DATA, | 254 | .data_mask = ICE1712_STDSP24_SERIAL_DATA, |
@@ -298,7 +298,7 @@ static int __devinit snd_ice1712_ez8_init(struct snd_ice1712 *ice) | |||
298 | 298 | ||
299 | 299 | ||
300 | /* entry point */ | 300 | /* entry point */ |
301 | struct snd_ice1712_card_info snd_ice1712_hoontech_cards[] __devinitdata = { | 301 | const struct snd_ice1712_card_info snd_ice1712_hoontech_cards[] __devinitdata = { |
302 | { | 302 | { |
303 | .subvendor = ICE1712_SUBDEVICE_STDSP24, | 303 | .subvendor = ICE1712_SUBDEVICE_STDSP24, |
304 | .name = "Hoontech SoundTrack Audio DSP24", | 304 | .name = "Hoontech SoundTrack Audio DSP24", |
@@ -325,4 +325,3 @@ struct snd_ice1712_card_info snd_ice1712_hoontech_cards[] __devinitdata = { | |||
325 | }, | 325 | }, |
326 | { } /* terminator */ | 326 | { } /* terminator */ |
327 | }; | 327 | }; |
328 | |||
diff --git a/sound/pci/ice1712/hoontech.h b/sound/pci/ice1712/hoontech.h index 1ee538b20fbf..b62d6e4f6c71 100644 --- a/sound/pci/ice1712/hoontech.h +++ b/sound/pci/ice1712/hoontech.h | |||
@@ -35,7 +35,7 @@ | |||
35 | #define ICE1712_SUBDEVICE_STDSP24_MEDIA7_1 0x16141217 /* Hoontech ST Audio DSP24 Media 7.1 */ | 35 | #define ICE1712_SUBDEVICE_STDSP24_MEDIA7_1 0x16141217 /* Hoontech ST Audio DSP24 Media 7.1 */ |
36 | #define ICE1712_SUBDEVICE_EVENT_EZ8 0x00010001 /* A dummy id for EZ8 */ | 36 | #define ICE1712_SUBDEVICE_EVENT_EZ8 0x00010001 /* A dummy id for EZ8 */ |
37 | 37 | ||
38 | extern struct snd_ice1712_card_info snd_ice1712_hoontech_cards[]; | 38 | extern const struct snd_ice1712_card_info snd_ice1712_hoontech_cards[]; |
39 | 39 | ||
40 | 40 | ||
41 | /* Hoontech SoundTrack Audio DSP 24 GPIO definitions */ | 41 | /* Hoontech SoundTrack Audio DSP 24 GPIO definitions */ |
diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c index 8ba31cfb9045..830a1bbd7110 100644 --- a/sound/pci/ice1712/ice1712.c +++ b/sound/pci/ice1712/ice1712.c | |||
@@ -107,7 +107,7 @@ module_param_array(dxr_enable, int, NULL, 0444); | |||
107 | MODULE_PARM_DESC(dxr_enable, "Enable DXR support for Terratec DMX6FIRE."); | 107 | MODULE_PARM_DESC(dxr_enable, "Enable DXR support for Terratec DMX6FIRE."); |
108 | 108 | ||
109 | 109 | ||
110 | static struct pci_device_id snd_ice1712_ids[] = { | 110 | static const struct pci_device_id snd_ice1712_ids[] = { |
111 | { PCI_VENDOR_ID_ICE, PCI_DEVICE_ID_ICE_1712, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ICE1712 */ | 111 | { PCI_VENDOR_ID_ICE, PCI_DEVICE_ID_ICE_1712, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ICE1712 */ |
112 | { 0, } | 112 | { 0, } |
113 | }; | 113 | }; |
@@ -287,7 +287,7 @@ static int snd_ice1712_digmix_route_ac97_put(struct snd_kcontrol *kcontrol, stru | |||
287 | return val != nval; | 287 | return val != nval; |
288 | } | 288 | } |
289 | 289 | ||
290 | static struct snd_kcontrol_new snd_ice1712_mixer_digmix_route_ac97 __devinitdata = { | 290 | static const struct snd_kcontrol_new snd_ice1712_mixer_digmix_route_ac97 __devinitdata = { |
291 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 291 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
292 | .name = "Digital Mixer To AC97", | 292 | .name = "Digital Mixer To AC97", |
293 | .info = snd_ice1712_digmix_route_ac97_info, | 293 | .info = snd_ice1712_digmix_route_ac97_info, |
@@ -719,7 +719,7 @@ static snd_pcm_uframes_t snd_ice1712_capture_pointer(struct snd_pcm_substream *s | |||
719 | return bytes_to_frames(substream->runtime, ptr); | 719 | return bytes_to_frames(substream->runtime, ptr); |
720 | } | 720 | } |
721 | 721 | ||
722 | static struct snd_pcm_hardware snd_ice1712_playback = | 722 | static const struct snd_pcm_hardware snd_ice1712_playback = |
723 | { | 723 | { |
724 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | | 724 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | |
725 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | 725 | SNDRV_PCM_INFO_BLOCK_TRANSFER | |
@@ -739,7 +739,7 @@ static struct snd_pcm_hardware snd_ice1712_playback = | |||
739 | .fifo_size = 0, | 739 | .fifo_size = 0, |
740 | }; | 740 | }; |
741 | 741 | ||
742 | static struct snd_pcm_hardware snd_ice1712_playback_ds = | 742 | static const struct snd_pcm_hardware snd_ice1712_playback_ds = |
743 | { | 743 | { |
744 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | | 744 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | |
745 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | 745 | SNDRV_PCM_INFO_BLOCK_TRANSFER | |
@@ -759,7 +759,7 @@ static struct snd_pcm_hardware snd_ice1712_playback_ds = | |||
759 | .fifo_size = 0, | 759 | .fifo_size = 0, |
760 | }; | 760 | }; |
761 | 761 | ||
762 | static struct snd_pcm_hardware snd_ice1712_capture = | 762 | static const struct snd_pcm_hardware snd_ice1712_capture = |
763 | { | 763 | { |
764 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | | 764 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | |
765 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | 765 | SNDRV_PCM_INFO_BLOCK_TRANSFER | |
@@ -1133,7 +1133,7 @@ static snd_pcm_uframes_t snd_ice1712_capture_pro_pointer(struct snd_pcm_substrea | |||
1133 | return bytes_to_frames(substream->runtime, ptr); | 1133 | return bytes_to_frames(substream->runtime, ptr); |
1134 | } | 1134 | } |
1135 | 1135 | ||
1136 | static struct snd_pcm_hardware snd_ice1712_playback_pro = | 1136 | static const struct snd_pcm_hardware snd_ice1712_playback_pro = |
1137 | { | 1137 | { |
1138 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | | 1138 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | |
1139 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | 1139 | SNDRV_PCM_INFO_BLOCK_TRANSFER | |
@@ -1153,7 +1153,7 @@ static struct snd_pcm_hardware snd_ice1712_playback_pro = | |||
1153 | .fifo_size = 0, | 1153 | .fifo_size = 0, |
1154 | }; | 1154 | }; |
1155 | 1155 | ||
1156 | static struct snd_pcm_hardware snd_ice1712_capture_pro = | 1156 | static const struct snd_pcm_hardware snd_ice1712_capture_pro = |
1157 | { | 1157 | { |
1158 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | | 1158 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | |
1159 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | 1159 | SNDRV_PCM_INFO_BLOCK_TRANSFER | |
@@ -1378,9 +1378,9 @@ static int snd_ice1712_pro_mixer_volume_put(struct snd_kcontrol *kcontrol, struc | |||
1378 | return change; | 1378 | return change; |
1379 | } | 1379 | } |
1380 | 1380 | ||
1381 | static DECLARE_TLV_DB_SCALE(db_scale_playback, -14400, 150, 0); | 1381 | static const DECLARE_TLV_DB_SCALE(db_scale_playback, -14400, 150, 0); |
1382 | 1382 | ||
1383 | static struct snd_kcontrol_new snd_ice1712_multi_playback_ctrls[] __devinitdata = { | 1383 | static const struct snd_kcontrol_new snd_ice1712_multi_playback_ctrls[] __devinitdata = { |
1384 | { | 1384 | { |
1385 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1385 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1386 | .name = "Multi Playback Switch", | 1386 | .name = "Multi Playback Switch", |
@@ -1404,7 +1404,7 @@ static struct snd_kcontrol_new snd_ice1712_multi_playback_ctrls[] __devinitdata | |||
1404 | }, | 1404 | }, |
1405 | }; | 1405 | }; |
1406 | 1406 | ||
1407 | static struct snd_kcontrol_new snd_ice1712_multi_capture_analog_switch __devinitdata = { | 1407 | static const struct snd_kcontrol_new snd_ice1712_multi_capture_analog_switch __devinitdata = { |
1408 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1408 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1409 | .name = "H/W Multi Capture Switch", | 1409 | .name = "H/W Multi Capture Switch", |
1410 | .info = snd_ice1712_pro_mixer_switch_info, | 1410 | .info = snd_ice1712_pro_mixer_switch_info, |
@@ -1413,7 +1413,7 @@ static struct snd_kcontrol_new snd_ice1712_multi_capture_analog_switch __devinit | |||
1413 | .private_value = 10, | 1413 | .private_value = 10, |
1414 | }; | 1414 | }; |
1415 | 1415 | ||
1416 | static struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_switch __devinitdata = { | 1416 | static const struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_switch __devinitdata = { |
1417 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1417 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1418 | .name = SNDRV_CTL_NAME_IEC958("Multi ",CAPTURE,SWITCH), | 1418 | .name = SNDRV_CTL_NAME_IEC958("Multi ",CAPTURE,SWITCH), |
1419 | .info = snd_ice1712_pro_mixer_switch_info, | 1419 | .info = snd_ice1712_pro_mixer_switch_info, |
@@ -1423,7 +1423,7 @@ static struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_switch __devinitd | |||
1423 | .count = 2, | 1423 | .count = 2, |
1424 | }; | 1424 | }; |
1425 | 1425 | ||
1426 | static struct snd_kcontrol_new snd_ice1712_multi_capture_analog_volume __devinitdata = { | 1426 | static const struct snd_kcontrol_new snd_ice1712_multi_capture_analog_volume __devinitdata = { |
1427 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1427 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1428 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | 1428 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | |
1429 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | 1429 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), |
@@ -1435,7 +1435,7 @@ static struct snd_kcontrol_new snd_ice1712_multi_capture_analog_volume __devinit | |||
1435 | .tlv = { .p = db_scale_playback } | 1435 | .tlv = { .p = db_scale_playback } |
1436 | }; | 1436 | }; |
1437 | 1437 | ||
1438 | static struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_volume __devinitdata = { | 1438 | static const struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_volume __devinitdata = { |
1439 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1439 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1440 | .name = SNDRV_CTL_NAME_IEC958("Multi ",CAPTURE,VOLUME), | 1440 | .name = SNDRV_CTL_NAME_IEC958("Multi ",CAPTURE,VOLUME), |
1441 | .info = snd_ice1712_pro_mixer_volume_info, | 1441 | .info = snd_ice1712_pro_mixer_volume_info, |
@@ -1627,7 +1627,7 @@ static int snd_ice1712_eeprom_get(struct snd_kcontrol *kcontrol, | |||
1627 | return 0; | 1627 | return 0; |
1628 | } | 1628 | } |
1629 | 1629 | ||
1630 | static struct snd_kcontrol_new snd_ice1712_eeprom __devinitdata = { | 1630 | static const struct snd_kcontrol_new snd_ice1712_eeprom __devinitdata = { |
1631 | .iface = SNDRV_CTL_ELEM_IFACE_CARD, | 1631 | .iface = SNDRV_CTL_ELEM_IFACE_CARD, |
1632 | .name = "ICE1712 EEPROM", | 1632 | .name = "ICE1712 EEPROM", |
1633 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | 1633 | .access = SNDRV_CTL_ELEM_ACCESS_READ, |
@@ -1663,7 +1663,7 @@ static int snd_ice1712_spdif_default_put(struct snd_kcontrol *kcontrol, | |||
1663 | return 0; | 1663 | return 0; |
1664 | } | 1664 | } |
1665 | 1665 | ||
1666 | static struct snd_kcontrol_new snd_ice1712_spdif_default __devinitdata = | 1666 | static const struct snd_kcontrol_new snd_ice1712_spdif_default __devinitdata = |
1667 | { | 1667 | { |
1668 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | 1668 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
1669 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), | 1669 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), |
@@ -1714,7 +1714,7 @@ static int snd_ice1712_spdif_maskp_get(struct snd_kcontrol *kcontrol, | |||
1714 | return 0; | 1714 | return 0; |
1715 | } | 1715 | } |
1716 | 1716 | ||
1717 | static struct snd_kcontrol_new snd_ice1712_spdif_maskc __devinitdata = | 1717 | static const struct snd_kcontrol_new snd_ice1712_spdif_maskc __devinitdata = |
1718 | { | 1718 | { |
1719 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | 1719 | .access = SNDRV_CTL_ELEM_ACCESS_READ, |
1720 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | 1720 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
@@ -1723,7 +1723,7 @@ static struct snd_kcontrol_new snd_ice1712_spdif_maskc __devinitdata = | |||
1723 | .get = snd_ice1712_spdif_maskc_get, | 1723 | .get = snd_ice1712_spdif_maskc_get, |
1724 | }; | 1724 | }; |
1725 | 1725 | ||
1726 | static struct snd_kcontrol_new snd_ice1712_spdif_maskp __devinitdata = | 1726 | static const struct snd_kcontrol_new snd_ice1712_spdif_maskp __devinitdata = |
1727 | { | 1727 | { |
1728 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | 1728 | .access = SNDRV_CTL_ELEM_ACCESS_READ, |
1729 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | 1729 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
@@ -1750,7 +1750,7 @@ static int snd_ice1712_spdif_stream_put(struct snd_kcontrol *kcontrol, | |||
1750 | return 0; | 1750 | return 0; |
1751 | } | 1751 | } |
1752 | 1752 | ||
1753 | static struct snd_kcontrol_new snd_ice1712_spdif_stream __devinitdata = | 1753 | static const struct snd_kcontrol_new snd_ice1712_spdif_stream __devinitdata = |
1754 | { | 1754 | { |
1755 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | 1755 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | |
1756 | SNDRV_CTL_ELEM_ACCESS_INACTIVE), | 1756 | SNDRV_CTL_ELEM_ACCESS_INACTIVE), |
@@ -1811,7 +1811,7 @@ int snd_ice1712_gpio_put(struct snd_kcontrol *kcontrol, | |||
1811 | static int snd_ice1712_pro_internal_clock_info(struct snd_kcontrol *kcontrol, | 1811 | static int snd_ice1712_pro_internal_clock_info(struct snd_kcontrol *kcontrol, |
1812 | struct snd_ctl_elem_info *uinfo) | 1812 | struct snd_ctl_elem_info *uinfo) |
1813 | { | 1813 | { |
1814 | static char *texts[] = { | 1814 | static const char * const texts[] = { |
1815 | "8000", /* 0: 6 */ | 1815 | "8000", /* 0: 6 */ |
1816 | "9600", /* 1: 3 */ | 1816 | "9600", /* 1: 3 */ |
1817 | "11025", /* 2: 10 */ | 1817 | "11025", /* 2: 10 */ |
@@ -1840,7 +1840,7 @@ static int snd_ice1712_pro_internal_clock_get(struct snd_kcontrol *kcontrol, | |||
1840 | struct snd_ctl_elem_value *ucontrol) | 1840 | struct snd_ctl_elem_value *ucontrol) |
1841 | { | 1841 | { |
1842 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 1842 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
1843 | static unsigned char xlate[16] = { | 1843 | static const unsigned char xlate[16] = { |
1844 | 9, 6, 3, 1, 7, 4, 0, 12, 8, 5, 2, 11, 255, 255, 255, 10 | 1844 | 9, 6, 3, 1, 7, 4, 0, 12, 8, 5, 2, 11, 255, 255, 255, 10 |
1845 | }; | 1845 | }; |
1846 | unsigned char val; | 1846 | unsigned char val; |
@@ -1864,7 +1864,7 @@ static int snd_ice1712_pro_internal_clock_put(struct snd_kcontrol *kcontrol, | |||
1864 | struct snd_ctl_elem_value *ucontrol) | 1864 | struct snd_ctl_elem_value *ucontrol) |
1865 | { | 1865 | { |
1866 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 1866 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
1867 | static unsigned int xrate[13] = { | 1867 | static const unsigned int xrate[13] = { |
1868 | 8000, 9600, 11025, 12000, 16000, 22050, 24000, | 1868 | 8000, 9600, 11025, 12000, 16000, 22050, 24000, |
1869 | 32000, 44100, 48000, 64000, 88200, 96000 | 1869 | 32000, 44100, 48000, 64000, 88200, 96000 |
1870 | }; | 1870 | }; |
@@ -1891,7 +1891,7 @@ static int snd_ice1712_pro_internal_clock_put(struct snd_kcontrol *kcontrol, | |||
1891 | return change; | 1891 | return change; |
1892 | } | 1892 | } |
1893 | 1893 | ||
1894 | static struct snd_kcontrol_new snd_ice1712_pro_internal_clock __devinitdata = { | 1894 | static const struct snd_kcontrol_new snd_ice1712_pro_internal_clock __devinitdata = { |
1895 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1895 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1896 | .name = "Multi Track Internal Clock", | 1896 | .name = "Multi Track Internal Clock", |
1897 | .info = snd_ice1712_pro_internal_clock_info, | 1897 | .info = snd_ice1712_pro_internal_clock_info, |
@@ -1902,7 +1902,7 @@ static struct snd_kcontrol_new snd_ice1712_pro_internal_clock __devinitdata = { | |||
1902 | static int snd_ice1712_pro_internal_clock_default_info(struct snd_kcontrol *kcontrol, | 1902 | static int snd_ice1712_pro_internal_clock_default_info(struct snd_kcontrol *kcontrol, |
1903 | struct snd_ctl_elem_info *uinfo) | 1903 | struct snd_ctl_elem_info *uinfo) |
1904 | { | 1904 | { |
1905 | static char *texts[] = { | 1905 | static const char * const texts[] = { |
1906 | "8000", /* 0: 6 */ | 1906 | "8000", /* 0: 6 */ |
1907 | "9600", /* 1: 3 */ | 1907 | "9600", /* 1: 3 */ |
1908 | "11025", /* 2: 10 */ | 1908 | "11025", /* 2: 10 */ |
@@ -1931,7 +1931,7 @@ static int snd_ice1712_pro_internal_clock_default_get(struct snd_kcontrol *kcont | |||
1931 | struct snd_ctl_elem_value *ucontrol) | 1931 | struct snd_ctl_elem_value *ucontrol) |
1932 | { | 1932 | { |
1933 | int val; | 1933 | int val; |
1934 | static unsigned int xrate[13] = { | 1934 | static const unsigned int xrate[13] = { |
1935 | 8000, 9600, 11025, 12000, 16000, 22050, 24000, | 1935 | 8000, 9600, 11025, 12000, 16000, 22050, 24000, |
1936 | 32000, 44100, 48000, 64000, 88200, 96000 | 1936 | 32000, 44100, 48000, 64000, 88200, 96000 |
1937 | }; | 1937 | }; |
@@ -1948,7 +1948,7 @@ static int snd_ice1712_pro_internal_clock_default_get(struct snd_kcontrol *kcont | |||
1948 | static int snd_ice1712_pro_internal_clock_default_put(struct snd_kcontrol *kcontrol, | 1948 | static int snd_ice1712_pro_internal_clock_default_put(struct snd_kcontrol *kcontrol, |
1949 | struct snd_ctl_elem_value *ucontrol) | 1949 | struct snd_ctl_elem_value *ucontrol) |
1950 | { | 1950 | { |
1951 | static unsigned int xrate[13] = { | 1951 | static const unsigned int xrate[13] = { |
1952 | 8000, 9600, 11025, 12000, 16000, 22050, 24000, | 1952 | 8000, 9600, 11025, 12000, 16000, 22050, 24000, |
1953 | 32000, 44100, 48000, 64000, 88200, 96000 | 1953 | 32000, 44100, 48000, 64000, 88200, 96000 |
1954 | }; | 1954 | }; |
@@ -1962,7 +1962,7 @@ static int snd_ice1712_pro_internal_clock_default_put(struct snd_kcontrol *kcont | |||
1962 | return change; | 1962 | return change; |
1963 | } | 1963 | } |
1964 | 1964 | ||
1965 | static struct snd_kcontrol_new snd_ice1712_pro_internal_clock_default __devinitdata = { | 1965 | static const struct snd_kcontrol_new snd_ice1712_pro_internal_clock_default __devinitdata = { |
1966 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1966 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1967 | .name = "Multi Track Internal Clock Default", | 1967 | .name = "Multi Track Internal Clock Default", |
1968 | .info = snd_ice1712_pro_internal_clock_default_info, | 1968 | .info = snd_ice1712_pro_internal_clock_default_info, |
@@ -2001,7 +2001,7 @@ static int snd_ice1712_pro_rate_locking_put(struct snd_kcontrol *kcontrol, | |||
2001 | return change; | 2001 | return change; |
2002 | } | 2002 | } |
2003 | 2003 | ||
2004 | static struct snd_kcontrol_new snd_ice1712_pro_rate_locking __devinitdata = { | 2004 | static const struct snd_kcontrol_new snd_ice1712_pro_rate_locking __devinitdata = { |
2005 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2005 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
2006 | .name = "Multi Track Rate Locking", | 2006 | .name = "Multi Track Rate Locking", |
2007 | .info = snd_ice1712_pro_rate_locking_info, | 2007 | .info = snd_ice1712_pro_rate_locking_info, |
@@ -2040,7 +2040,7 @@ static int snd_ice1712_pro_rate_reset_put(struct snd_kcontrol *kcontrol, | |||
2040 | return change; | 2040 | return change; |
2041 | } | 2041 | } |
2042 | 2042 | ||
2043 | static struct snd_kcontrol_new snd_ice1712_pro_rate_reset __devinitdata = { | 2043 | static const struct snd_kcontrol_new snd_ice1712_pro_rate_reset __devinitdata = { |
2044 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2044 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
2045 | .name = "Multi Track Rate Reset", | 2045 | .name = "Multi Track Rate Reset", |
2046 | .info = snd_ice1712_pro_rate_reset_info, | 2046 | .info = snd_ice1712_pro_rate_reset_info, |
@@ -2054,7 +2054,7 @@ static struct snd_kcontrol_new snd_ice1712_pro_rate_reset __devinitdata = { | |||
2054 | static int snd_ice1712_pro_route_info(struct snd_kcontrol *kcontrol, | 2054 | static int snd_ice1712_pro_route_info(struct snd_kcontrol *kcontrol, |
2055 | struct snd_ctl_elem_info *uinfo) | 2055 | struct snd_ctl_elem_info *uinfo) |
2056 | { | 2056 | { |
2057 | static char *texts[] = { | 2057 | static const char * const texts[] = { |
2058 | "PCM Out", /* 0 */ | 2058 | "PCM Out", /* 0 */ |
2059 | "H/W In 0", "H/W In 1", "H/W In 2", "H/W In 3", /* 1-4 */ | 2059 | "H/W In 0", "H/W In 1", "H/W In 2", "H/W In 3", /* 1-4 */ |
2060 | "H/W In 4", "H/W In 5", "H/W In 6", "H/W In 7", /* 5-8 */ | 2060 | "H/W In 4", "H/W In 5", "H/W In 6", "H/W In 7", /* 5-8 */ |
@@ -2207,7 +2207,7 @@ static int snd_ice1712_pro_route_spdif_put(struct snd_kcontrol *kcontrol, | |||
2207 | return change; | 2207 | return change; |
2208 | } | 2208 | } |
2209 | 2209 | ||
2210 | static struct snd_kcontrol_new snd_ice1712_mixer_pro_analog_route __devinitdata = { | 2210 | static const struct snd_kcontrol_new snd_ice1712_mixer_pro_analog_route __devinitdata = { |
2211 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2211 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
2212 | .name = "H/W Playback Route", | 2212 | .name = "H/W Playback Route", |
2213 | .info = snd_ice1712_pro_route_info, | 2213 | .info = snd_ice1712_pro_route_info, |
@@ -2215,7 +2215,7 @@ static struct snd_kcontrol_new snd_ice1712_mixer_pro_analog_route __devinitdata | |||
2215 | .put = snd_ice1712_pro_route_analog_put, | 2215 | .put = snd_ice1712_pro_route_analog_put, |
2216 | }; | 2216 | }; |
2217 | 2217 | ||
2218 | static struct snd_kcontrol_new snd_ice1712_mixer_pro_spdif_route __devinitdata = { | 2218 | static const struct snd_kcontrol_new snd_ice1712_mixer_pro_spdif_route __devinitdata = { |
2219 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2219 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
2220 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Route", | 2220 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Route", |
2221 | .info = snd_ice1712_pro_route_info, | 2221 | .info = snd_ice1712_pro_route_info, |
@@ -2257,7 +2257,7 @@ static int snd_ice1712_pro_volume_rate_put(struct snd_kcontrol *kcontrol, | |||
2257 | return change; | 2257 | return change; |
2258 | } | 2258 | } |
2259 | 2259 | ||
2260 | static struct snd_kcontrol_new snd_ice1712_mixer_pro_volume_rate __devinitdata = { | 2260 | static const struct snd_kcontrol_new snd_ice1712_mixer_pro_volume_rate __devinitdata = { |
2261 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2261 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
2262 | .name = "Multi Track Volume Rate", | 2262 | .name = "Multi Track Volume Rate", |
2263 | .info = snd_ice1712_pro_volume_rate_info, | 2263 | .info = snd_ice1712_pro_volume_rate_info, |
@@ -2290,7 +2290,7 @@ static int snd_ice1712_pro_peak_get(struct snd_kcontrol *kcontrol, | |||
2290 | return 0; | 2290 | return 0; |
2291 | } | 2291 | } |
2292 | 2292 | ||
2293 | static struct snd_kcontrol_new snd_ice1712_mixer_pro_peak __devinitdata = { | 2293 | static const struct snd_kcontrol_new snd_ice1712_mixer_pro_peak __devinitdata = { |
2294 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2294 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
2295 | .name = "Multi Track Peak", | 2295 | .name = "Multi Track Peak", |
2296 | .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, | 2296 | .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, |
@@ -2305,7 +2305,7 @@ static struct snd_kcontrol_new snd_ice1712_mixer_pro_peak __devinitdata = { | |||
2305 | /* | 2305 | /* |
2306 | * list of available boards | 2306 | * list of available boards |
2307 | */ | 2307 | */ |
2308 | static struct snd_ice1712_card_info *card_tables[] __devinitdata = { | 2308 | static const struct snd_ice1712_card_info *card_tables[] __devinitdata = { |
2309 | snd_ice1712_hoontech_cards, | 2309 | snd_ice1712_hoontech_cards, |
2310 | snd_ice1712_delta_cards, | 2310 | snd_ice1712_delta_cards, |
2311 | snd_ice1712_ews_cards, | 2311 | snd_ice1712_ews_cards, |
@@ -2329,7 +2329,7 @@ static int __devinit snd_ice1712_read_eeprom(struct snd_ice1712 *ice, | |||
2329 | { | 2329 | { |
2330 | int dev = 0xa0; /* EEPROM device address */ | 2330 | int dev = 0xa0; /* EEPROM device address */ |
2331 | unsigned int i, size; | 2331 | unsigned int i, size; |
2332 | struct snd_ice1712_card_info **tbl, *c; | 2332 | const struct snd_ice1712_card_info **tbl, *c; |
2333 | 2333 | ||
2334 | if (! modelname || ! *modelname) { | 2334 | if (! modelname || ! *modelname) { |
2335 | ice->eeprom.subvendor = 0; | 2335 | ice->eeprom.subvendor = 0; |
@@ -2658,7 +2658,7 @@ static int __devinit snd_ice1712_create(struct snd_card *card, | |||
2658 | * | 2658 | * |
2659 | */ | 2659 | */ |
2660 | 2660 | ||
2661 | static struct snd_ice1712_card_info no_matched __devinitdata; | 2661 | static const struct snd_ice1712_card_info no_matched __devinitdata; |
2662 | 2662 | ||
2663 | static int __devinit snd_ice1712_probe(struct pci_dev *pci, | 2663 | static int __devinit snd_ice1712_probe(struct pci_dev *pci, |
2664 | const struct pci_device_id *pci_id) | 2664 | const struct pci_device_id *pci_id) |
@@ -2667,7 +2667,7 @@ static int __devinit snd_ice1712_probe(struct pci_dev *pci, | |||
2667 | struct snd_card *card; | 2667 | struct snd_card *card; |
2668 | struct snd_ice1712 *ice; | 2668 | struct snd_ice1712 *ice; |
2669 | int pcm_dev = 0, err; | 2669 | int pcm_dev = 0, err; |
2670 | struct snd_ice1712_card_info **tbl, *c; | 2670 | const struct snd_ice1712_card_info **tbl, *c; |
2671 | 2671 | ||
2672 | if (dev >= SNDRV_CARDS) | 2672 | if (dev >= SNDRV_CARDS) |
2673 | return -ENODEV; | 2673 | return -ENODEV; |
diff --git a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h index ce27eac40d4e..c3d9feaaf57d 100644 --- a/sound/pci/ice1712/ice1712.h +++ b/sound/pci/ice1712/ice1712.h | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <sound/i2c.h> | 28 | #include <sound/i2c.h> |
29 | #include <sound/ak4xxx-adda.h> | 29 | #include <sound/ak4xxx-adda.h> |
30 | #include <sound/ak4114.h> | 30 | #include <sound/ak4114.h> |
31 | #include <sound/pt2258.h> | ||
31 | #include <sound/pcm.h> | 32 | #include <sound/pcm.h> |
32 | #include <sound/mpu401.h> | 33 | #include <sound/mpu401.h> |
33 | 34 | ||
@@ -381,6 +382,11 @@ struct snd_ice1712 { | |||
381 | unsigned short master[2]; | 382 | unsigned short master[2]; |
382 | unsigned short vol[8]; | 383 | unsigned short vol[8]; |
383 | } phase28; | 384 | } phase28; |
385 | /* a non-standard I2C device for revo51 */ | ||
386 | struct revo51_spec { | ||
387 | struct snd_i2c_device *dev; | ||
388 | struct snd_pt2258 *pt2258; | ||
389 | } revo51; | ||
384 | /* Hoontech-specific setting */ | 390 | /* Hoontech-specific setting */ |
385 | struct hoontech_spec { | 391 | struct hoontech_spec { |
386 | unsigned char boxbits[4]; | 392 | unsigned char boxbits[4]; |
@@ -462,6 +468,14 @@ static inline void snd_ice1712_gpio_write_bits(struct snd_ice1712 *ice, | |||
462 | snd_ice1712_gpio_write(ice, mask & bits); | 468 | snd_ice1712_gpio_write(ice, mask & bits); |
463 | } | 469 | } |
464 | 470 | ||
471 | static inline int snd_ice1712_gpio_read_bits(struct snd_ice1712 *ice, | ||
472 | unsigned int mask) | ||
473 | { | ||
474 | ice->gpio.direction &= ~mask; | ||
475 | snd_ice1712_gpio_set_dir(ice, ice->gpio.direction); | ||
476 | return (snd_ice1712_gpio_read(ice) & mask); | ||
477 | } | ||
478 | |||
465 | int snd_ice1712_spdif_build_controls(struct snd_ice1712 *ice); | 479 | int snd_ice1712_spdif_build_controls(struct snd_ice1712 *ice); |
466 | 480 | ||
467 | int snd_ice1712_akm4xxx_init(struct snd_akm4xxx *ak, const struct snd_akm4xxx *template, | 481 | int snd_ice1712_akm4xxx_init(struct snd_akm4xxx *ak, const struct snd_akm4xxx *template, |
@@ -500,8 +514,8 @@ struct snd_ice1712_card_info { | |||
500 | unsigned int mpu401_2_info_flags; | 514 | unsigned int mpu401_2_info_flags; |
501 | const char *mpu401_1_name; | 515 | const char *mpu401_1_name; |
502 | const char *mpu401_2_name; | 516 | const char *mpu401_2_name; |
503 | unsigned int eeprom_size; | 517 | const unsigned int eeprom_size; |
504 | unsigned char *eeprom_data; | 518 | const unsigned char *eeprom_data; |
505 | }; | 519 | }; |
506 | 520 | ||
507 | 521 | ||
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index 3e3a102e6c34..1127ebdf5fec 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c | |||
@@ -50,7 +50,7 @@ | |||
50 | #include "prodigy192.h" | 50 | #include "prodigy192.h" |
51 | #include "juli.h" | 51 | #include "juli.h" |
52 | #include "phase.h" | 52 | #include "phase.h" |
53 | 53 | #include "wtm.h" | |
54 | 54 | ||
55 | MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); | 55 | MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); |
56 | MODULE_DESCRIPTION("VIA ICEnsemble ICE1724/1720 (Envy24HT/PT)"); | 56 | MODULE_DESCRIPTION("VIA ICEnsemble ICE1724/1720 (Envy24HT/PT)"); |
@@ -64,6 +64,7 @@ MODULE_SUPPORTED_DEVICE("{" | |||
64 | PRODIGY192_DEVICE_DESC | 64 | PRODIGY192_DEVICE_DESC |
65 | JULI_DEVICE_DESC | 65 | JULI_DEVICE_DESC |
66 | PHASE_DEVICE_DESC | 66 | PHASE_DEVICE_DESC |
67 | WTM_DEVICE_DESC | ||
67 | "{VIA,VT1720}," | 68 | "{VIA,VT1720}," |
68 | "{VIA,VT1724}," | 69 | "{VIA,VT1724}," |
69 | "{ICEnsemble,Generic ICE1724}," | 70 | "{ICEnsemble,Generic ICE1724}," |
@@ -86,7 +87,7 @@ MODULE_PARM_DESC(model, "Use the given board model."); | |||
86 | 87 | ||
87 | 88 | ||
88 | /* Both VT1720 and VT1724 have the same PCI IDs */ | 89 | /* Both VT1720 and VT1724 have the same PCI IDs */ |
89 | static struct pci_device_id snd_vt1724_ids[] = { | 90 | static const struct pci_device_id snd_vt1724_ids[] = { |
90 | { PCI_VENDOR_ID_ICE, PCI_DEVICE_ID_VT1724, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, | 91 | { PCI_VENDOR_ID_ICE, PCI_DEVICE_ID_VT1724, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, |
91 | { 0, } | 92 | { 0, } |
92 | }; | 93 | }; |
@@ -341,7 +342,7 @@ static int snd_vt1724_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | |||
341 | 342 | ||
342 | what = 0; | 343 | what = 0; |
343 | snd_pcm_group_for_each(pos, substream) { | 344 | snd_pcm_group_for_each(pos, substream) { |
344 | struct vt1724_pcm_reg *reg; | 345 | const struct vt1724_pcm_reg *reg; |
345 | s = snd_pcm_group_substream_entry(pos); | 346 | s = snd_pcm_group_substream_entry(pos); |
346 | reg = s->runtime->private_data; | 347 | reg = s->runtime->private_data; |
347 | what |= reg->start; | 348 | what |= reg->start; |
@@ -605,7 +606,7 @@ static snd_pcm_uframes_t snd_vt1724_playback_pro_pointer(struct snd_pcm_substrea | |||
605 | static int snd_vt1724_pcm_prepare(struct snd_pcm_substream *substream) | 606 | static int snd_vt1724_pcm_prepare(struct snd_pcm_substream *substream) |
606 | { | 607 | { |
607 | struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); | 608 | struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); |
608 | struct vt1724_pcm_reg *reg = substream->runtime->private_data; | 609 | const struct vt1724_pcm_reg *reg = substream->runtime->private_data; |
609 | 610 | ||
610 | spin_lock_irq(&ice->reg_lock); | 611 | spin_lock_irq(&ice->reg_lock); |
611 | outl(substream->runtime->dma_addr, ice->profi_port + reg->addr); | 612 | outl(substream->runtime->dma_addr, ice->profi_port + reg->addr); |
@@ -620,7 +621,7 @@ static int snd_vt1724_pcm_prepare(struct snd_pcm_substream *substream) | |||
620 | static snd_pcm_uframes_t snd_vt1724_pcm_pointer(struct snd_pcm_substream *substream) | 621 | static snd_pcm_uframes_t snd_vt1724_pcm_pointer(struct snd_pcm_substream *substream) |
621 | { | 622 | { |
622 | struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); | 623 | struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); |
623 | struct vt1724_pcm_reg *reg = substream->runtime->private_data; | 624 | const struct vt1724_pcm_reg *reg = substream->runtime->private_data; |
624 | size_t ptr; | 625 | size_t ptr; |
625 | 626 | ||
626 | if (!(inl(ICEMT1724(ice, DMA_CONTROL)) & reg->start)) | 627 | if (!(inl(ICEMT1724(ice, DMA_CONTROL)) & reg->start)) |
@@ -646,21 +647,21 @@ static snd_pcm_uframes_t snd_vt1724_pcm_pointer(struct snd_pcm_substream *substr | |||
646 | #endif | 647 | #endif |
647 | } | 648 | } |
648 | 649 | ||
649 | static struct vt1724_pcm_reg vt1724_playback_pro_reg = { | 650 | static const struct vt1724_pcm_reg vt1724_playback_pro_reg = { |
650 | .addr = VT1724_MT_PLAYBACK_ADDR, | 651 | .addr = VT1724_MT_PLAYBACK_ADDR, |
651 | .size = VT1724_MT_PLAYBACK_SIZE, | 652 | .size = VT1724_MT_PLAYBACK_SIZE, |
652 | .count = VT1724_MT_PLAYBACK_COUNT, | 653 | .count = VT1724_MT_PLAYBACK_COUNT, |
653 | .start = VT1724_PDMA0_START, | 654 | .start = VT1724_PDMA0_START, |
654 | }; | 655 | }; |
655 | 656 | ||
656 | static struct vt1724_pcm_reg vt1724_capture_pro_reg = { | 657 | static const struct vt1724_pcm_reg vt1724_capture_pro_reg = { |
657 | .addr = VT1724_MT_CAPTURE_ADDR, | 658 | .addr = VT1724_MT_CAPTURE_ADDR, |
658 | .size = VT1724_MT_CAPTURE_SIZE, | 659 | .size = VT1724_MT_CAPTURE_SIZE, |
659 | .count = VT1724_MT_CAPTURE_COUNT, | 660 | .count = VT1724_MT_CAPTURE_COUNT, |
660 | .start = VT1724_RDMA0_START, | 661 | .start = VT1724_RDMA0_START, |
661 | }; | 662 | }; |
662 | 663 | ||
663 | static struct snd_pcm_hardware snd_vt1724_playback_pro = | 664 | static const struct snd_pcm_hardware snd_vt1724_playback_pro = |
664 | { | 665 | { |
665 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | | 666 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | |
666 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | 667 | SNDRV_PCM_INFO_BLOCK_TRANSFER | |
@@ -679,7 +680,7 @@ static struct snd_pcm_hardware snd_vt1724_playback_pro = | |||
679 | .periods_max = 1024, | 680 | .periods_max = 1024, |
680 | }; | 681 | }; |
681 | 682 | ||
682 | static struct snd_pcm_hardware snd_vt1724_spdif = | 683 | static const struct snd_pcm_hardware snd_vt1724_spdif = |
683 | { | 684 | { |
684 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | | 685 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | |
685 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | 686 | SNDRV_PCM_INFO_BLOCK_TRANSFER | |
@@ -701,7 +702,7 @@ static struct snd_pcm_hardware snd_vt1724_spdif = | |||
701 | .periods_max = 1024, | 702 | .periods_max = 1024, |
702 | }; | 703 | }; |
703 | 704 | ||
704 | static struct snd_pcm_hardware snd_vt1724_2ch_stereo = | 705 | static const struct snd_pcm_hardware snd_vt1724_2ch_stereo = |
705 | { | 706 | { |
706 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | | 707 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | |
707 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | 708 | SNDRV_PCM_INFO_BLOCK_TRANSFER | |
@@ -773,7 +774,7 @@ static int snd_vt1724_playback_pro_open(struct snd_pcm_substream *substream) | |||
773 | struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); | 774 | struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); |
774 | int chs; | 775 | int chs; |
775 | 776 | ||
776 | runtime->private_data = &vt1724_playback_pro_reg; | 777 | runtime->private_data = (void *)&vt1724_playback_pro_reg; |
777 | ice->playback_pro_substream = substream; | 778 | ice->playback_pro_substream = substream; |
778 | runtime->hw = snd_vt1724_playback_pro; | 779 | runtime->hw = snd_vt1724_playback_pro; |
779 | snd_pcm_set_sync(substream); | 780 | snd_pcm_set_sync(substream); |
@@ -802,7 +803,7 @@ static int snd_vt1724_capture_pro_open(struct snd_pcm_substream *substream) | |||
802 | struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); | 803 | struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); |
803 | struct snd_pcm_runtime *runtime = substream->runtime; | 804 | struct snd_pcm_runtime *runtime = substream->runtime; |
804 | 805 | ||
805 | runtime->private_data = &vt1724_capture_pro_reg; | 806 | runtime->private_data = (void *)&vt1724_capture_pro_reg; |
806 | ice->capture_pro_substream = substream; | 807 | ice->capture_pro_substream = substream; |
807 | runtime->hw = snd_vt1724_2ch_stereo; | 808 | runtime->hw = snd_vt1724_2ch_stereo; |
808 | snd_pcm_set_sync(substream); | 809 | snd_pcm_set_sync(substream); |
@@ -888,14 +889,14 @@ static int __devinit snd_vt1724_pcm_profi(struct snd_ice1712 * ice, int device) | |||
888 | * SPDIF PCM | 889 | * SPDIF PCM |
889 | */ | 890 | */ |
890 | 891 | ||
891 | static struct vt1724_pcm_reg vt1724_playback_spdif_reg = { | 892 | static const struct vt1724_pcm_reg vt1724_playback_spdif_reg = { |
892 | .addr = VT1724_MT_PDMA4_ADDR, | 893 | .addr = VT1724_MT_PDMA4_ADDR, |
893 | .size = VT1724_MT_PDMA4_SIZE, | 894 | .size = VT1724_MT_PDMA4_SIZE, |
894 | .count = VT1724_MT_PDMA4_COUNT, | 895 | .count = VT1724_MT_PDMA4_COUNT, |
895 | .start = VT1724_PDMA4_START, | 896 | .start = VT1724_PDMA4_START, |
896 | }; | 897 | }; |
897 | 898 | ||
898 | static struct vt1724_pcm_reg vt1724_capture_spdif_reg = { | 899 | static const struct vt1724_pcm_reg vt1724_capture_spdif_reg = { |
899 | .addr = VT1724_MT_RDMA1_ADDR, | 900 | .addr = VT1724_MT_RDMA1_ADDR, |
900 | .size = VT1724_MT_RDMA1_SIZE, | 901 | .size = VT1724_MT_RDMA1_SIZE, |
901 | .count = VT1724_MT_RDMA1_COUNT, | 902 | .count = VT1724_MT_RDMA1_COUNT, |
@@ -953,7 +954,7 @@ static int snd_vt1724_playback_spdif_open(struct snd_pcm_substream *substream) | |||
953 | struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); | 954 | struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); |
954 | struct snd_pcm_runtime *runtime = substream->runtime; | 955 | struct snd_pcm_runtime *runtime = substream->runtime; |
955 | 956 | ||
956 | runtime->private_data = &vt1724_playback_spdif_reg; | 957 | runtime->private_data = (void *)&vt1724_playback_spdif_reg; |
957 | ice->playback_con_substream = substream; | 958 | ice->playback_con_substream = substream; |
958 | if (ice->force_pdma4) { | 959 | if (ice->force_pdma4) { |
959 | runtime->hw = snd_vt1724_2ch_stereo; | 960 | runtime->hw = snd_vt1724_2ch_stereo; |
@@ -985,7 +986,7 @@ static int snd_vt1724_capture_spdif_open(struct snd_pcm_substream *substream) | |||
985 | struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); | 986 | struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); |
986 | struct snd_pcm_runtime *runtime = substream->runtime; | 987 | struct snd_pcm_runtime *runtime = substream->runtime; |
987 | 988 | ||
988 | runtime->private_data = &vt1724_capture_spdif_reg; | 989 | runtime->private_data = (void *)&vt1724_capture_spdif_reg; |
989 | ice->capture_con_substream = substream; | 990 | ice->capture_con_substream = substream; |
990 | if (ice->force_rdma1) { | 991 | if (ice->force_rdma1) { |
991 | runtime->hw = snd_vt1724_2ch_stereo; | 992 | runtime->hw = snd_vt1724_2ch_stereo; |
@@ -1090,7 +1091,7 @@ static int __devinit snd_vt1724_pcm_spdif(struct snd_ice1712 * ice, int device) | |||
1090 | * independent surround PCMs | 1091 | * independent surround PCMs |
1091 | */ | 1092 | */ |
1092 | 1093 | ||
1093 | static struct vt1724_pcm_reg vt1724_playback_dma_regs[3] = { | 1094 | static const struct vt1724_pcm_reg vt1724_playback_dma_regs[3] = { |
1094 | { | 1095 | { |
1095 | .addr = VT1724_MT_PDMA1_ADDR, | 1096 | .addr = VT1724_MT_PDMA1_ADDR, |
1096 | .size = VT1724_MT_PDMA1_SIZE, | 1097 | .size = VT1724_MT_PDMA1_SIZE, |
@@ -1136,7 +1137,7 @@ static int snd_vt1724_playback_indep_open(struct snd_pcm_substream *substream) | |||
1136 | return -EBUSY; /* FIXME: should handle blocking mode properly */ | 1137 | return -EBUSY; /* FIXME: should handle blocking mode properly */ |
1137 | } | 1138 | } |
1138 | mutex_unlock(&ice->open_mutex); | 1139 | mutex_unlock(&ice->open_mutex); |
1139 | runtime->private_data = &vt1724_playback_dma_regs[substream->number]; | 1140 | runtime->private_data = (void *)&vt1724_playback_dma_regs[substream->number]; |
1140 | ice->playback_con_substream_ds[substream->number] = substream; | 1141 | ice->playback_con_substream_ds[substream->number] = substream; |
1141 | runtime->hw = snd_vt1724_2ch_stereo; | 1142 | runtime->hw = snd_vt1724_2ch_stereo; |
1142 | snd_pcm_set_sync(substream); | 1143 | snd_pcm_set_sync(substream); |
@@ -1317,7 +1318,7 @@ static int snd_vt1724_eeprom_get(struct snd_kcontrol *kcontrol, | |||
1317 | return 0; | 1318 | return 0; |
1318 | } | 1319 | } |
1319 | 1320 | ||
1320 | static struct snd_kcontrol_new snd_vt1724_eeprom __devinitdata = { | 1321 | static const struct snd_kcontrol_new snd_vt1724_eeprom __devinitdata = { |
1321 | .iface = SNDRV_CTL_ELEM_IFACE_CARD, | 1322 | .iface = SNDRV_CTL_ELEM_IFACE_CARD, |
1322 | .name = "ICE1724 EEPROM", | 1323 | .name = "ICE1724 EEPROM", |
1323 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | 1324 | .access = SNDRV_CTL_ELEM_ACCESS_READ, |
@@ -1430,7 +1431,7 @@ static int snd_vt1724_spdif_default_put(struct snd_kcontrol *kcontrol, | |||
1430 | return (val != old); | 1431 | return (val != old); |
1431 | } | 1432 | } |
1432 | 1433 | ||
1433 | static struct snd_kcontrol_new snd_vt1724_spdif_default __devinitdata = | 1434 | static const struct snd_kcontrol_new snd_vt1724_spdif_default __devinitdata = |
1434 | { | 1435 | { |
1435 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | 1436 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
1436 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), | 1437 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), |
@@ -1462,7 +1463,7 @@ static int snd_vt1724_spdif_maskp_get(struct snd_kcontrol *kcontrol, | |||
1462 | return 0; | 1463 | return 0; |
1463 | } | 1464 | } |
1464 | 1465 | ||
1465 | static struct snd_kcontrol_new snd_vt1724_spdif_maskc __devinitdata = | 1466 | static const struct snd_kcontrol_new snd_vt1724_spdif_maskc __devinitdata = |
1466 | { | 1467 | { |
1467 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | 1468 | .access = SNDRV_CTL_ELEM_ACCESS_READ, |
1468 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | 1469 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
@@ -1471,7 +1472,7 @@ static struct snd_kcontrol_new snd_vt1724_spdif_maskc __devinitdata = | |||
1471 | .get = snd_vt1724_spdif_maskc_get, | 1472 | .get = snd_vt1724_spdif_maskc_get, |
1472 | }; | 1473 | }; |
1473 | 1474 | ||
1474 | static struct snd_kcontrol_new snd_vt1724_spdif_maskp __devinitdata = | 1475 | static const struct snd_kcontrol_new snd_vt1724_spdif_maskp __devinitdata = |
1475 | { | 1476 | { |
1476 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | 1477 | .access = SNDRV_CTL_ELEM_ACCESS_READ, |
1477 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | 1478 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
@@ -1516,7 +1517,7 @@ static int snd_vt1724_spdif_sw_put(struct snd_kcontrol *kcontrol, | |||
1516 | return old != val; | 1517 | return old != val; |
1517 | } | 1518 | } |
1518 | 1519 | ||
1519 | static struct snd_kcontrol_new snd_vt1724_spdif_switch __devinitdata = | 1520 | static const struct snd_kcontrol_new snd_vt1724_spdif_switch __devinitdata = |
1520 | { | 1521 | { |
1521 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1522 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1522 | /* FIXME: the following conflict with IEC958 Playback Route */ | 1523 | /* FIXME: the following conflict with IEC958 Playback Route */ |
@@ -1584,7 +1585,7 @@ int snd_ice1712_gpio_put(struct snd_kcontrol *kcontrol, | |||
1584 | static int snd_vt1724_pro_internal_clock_info(struct snd_kcontrol *kcontrol, | 1585 | static int snd_vt1724_pro_internal_clock_info(struct snd_kcontrol *kcontrol, |
1585 | struct snd_ctl_elem_info *uinfo) | 1586 | struct snd_ctl_elem_info *uinfo) |
1586 | { | 1587 | { |
1587 | static char *texts_1724[] = { | 1588 | static const char * const texts_1724[] = { |
1588 | "8000", /* 0: 6 */ | 1589 | "8000", /* 0: 6 */ |
1589 | "9600", /* 1: 3 */ | 1590 | "9600", /* 1: 3 */ |
1590 | "11025", /* 2: 10 */ | 1591 | "11025", /* 2: 10 */ |
@@ -1602,7 +1603,7 @@ static int snd_vt1724_pro_internal_clock_info(struct snd_kcontrol *kcontrol, | |||
1602 | "192000", /* 14: 14 */ | 1603 | "192000", /* 14: 14 */ |
1603 | "IEC958 Input", /* 15: -- */ | 1604 | "IEC958 Input", /* 15: -- */ |
1604 | }; | 1605 | }; |
1605 | static char *texts_1720[] = { | 1606 | static const char * const texts_1720[] = { |
1606 | "8000", /* 0: 6 */ | 1607 | "8000", /* 0: 6 */ |
1607 | "9600", /* 1: 3 */ | 1608 | "9600", /* 1: 3 */ |
1608 | "11025", /* 2: 10 */ | 1609 | "11025", /* 2: 10 */ |
@@ -1635,7 +1636,7 @@ static int snd_vt1724_pro_internal_clock_get(struct snd_kcontrol *kcontrol, | |||
1635 | struct snd_ctl_elem_value *ucontrol) | 1636 | struct snd_ctl_elem_value *ucontrol) |
1636 | { | 1637 | { |
1637 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 1638 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
1638 | static unsigned char xlate[16] = { | 1639 | static const unsigned char xlate[16] = { |
1639 | 9, 6, 3, 1, 7, 4, 0, 12, 8, 5, 2, 11, 13, 255, 14, 10 | 1640 | 9, 6, 3, 1, 7, 4, 0, 12, 8, 5, 2, 11, 13, 255, 14, 10 |
1640 | }; | 1641 | }; |
1641 | unsigned char val; | 1642 | unsigned char val; |
@@ -1694,7 +1695,7 @@ static int snd_vt1724_pro_internal_clock_put(struct snd_kcontrol *kcontrol, | |||
1694 | return change; | 1695 | return change; |
1695 | } | 1696 | } |
1696 | 1697 | ||
1697 | static struct snd_kcontrol_new snd_vt1724_pro_internal_clock __devinitdata = { | 1698 | static const struct snd_kcontrol_new snd_vt1724_pro_internal_clock __devinitdata = { |
1698 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1699 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1699 | .name = "Multi Track Internal Clock", | 1700 | .name = "Multi Track Internal Clock", |
1700 | .info = snd_vt1724_pro_internal_clock_info, | 1701 | .info = snd_vt1724_pro_internal_clock_info, |
@@ -1733,7 +1734,7 @@ static int snd_vt1724_pro_rate_locking_put(struct snd_kcontrol *kcontrol, | |||
1733 | return change; | 1734 | return change; |
1734 | } | 1735 | } |
1735 | 1736 | ||
1736 | static struct snd_kcontrol_new snd_vt1724_pro_rate_locking __devinitdata = { | 1737 | static const struct snd_kcontrol_new snd_vt1724_pro_rate_locking __devinitdata = { |
1737 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1738 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1738 | .name = "Multi Track Rate Locking", | 1739 | .name = "Multi Track Rate Locking", |
1739 | .info = snd_vt1724_pro_rate_locking_info, | 1740 | .info = snd_vt1724_pro_rate_locking_info, |
@@ -1772,7 +1773,7 @@ static int snd_vt1724_pro_rate_reset_put(struct snd_kcontrol *kcontrol, | |||
1772 | return change; | 1773 | return change; |
1773 | } | 1774 | } |
1774 | 1775 | ||
1775 | static struct snd_kcontrol_new snd_vt1724_pro_rate_reset __devinitdata = { | 1776 | static const struct snd_kcontrol_new snd_vt1724_pro_rate_reset __devinitdata = { |
1776 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1777 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1777 | .name = "Multi Track Rate Reset", | 1778 | .name = "Multi Track Rate Reset", |
1778 | .info = snd_vt1724_pro_rate_reset_info, | 1779 | .info = snd_vt1724_pro_rate_reset_info, |
@@ -1816,7 +1817,7 @@ static int get_route_val(struct snd_ice1712 *ice, int shift) | |||
1816 | { | 1817 | { |
1817 | unsigned long val; | 1818 | unsigned long val; |
1818 | unsigned char eitem; | 1819 | unsigned char eitem; |
1819 | static unsigned char xlate[8] = { | 1820 | static const unsigned char xlate[8] = { |
1820 | 0, 255, 1, 2, 255, 255, 3, 4, | 1821 | 0, 255, 1, 2, 255, 255, 3, 4, |
1821 | }; | 1822 | }; |
1822 | 1823 | ||
@@ -1835,7 +1836,7 @@ static int put_route_val(struct snd_ice1712 *ice, unsigned int val, int shift) | |||
1835 | { | 1836 | { |
1836 | unsigned int old_val, nval; | 1837 | unsigned int old_val, nval; |
1837 | int change; | 1838 | int change; |
1838 | static unsigned char xroute[8] = { | 1839 | static const unsigned char xroute[8] = { |
1839 | 0, /* PCM */ | 1840 | 0, /* PCM */ |
1840 | 2, /* PSDIN0 Left */ | 1841 | 2, /* PSDIN0 Left */ |
1841 | 3, /* PSDIN0 Right */ | 1842 | 3, /* PSDIN0 Right */ |
@@ -1891,7 +1892,7 @@ static int snd_vt1724_pro_route_spdif_put(struct snd_kcontrol *kcontrol, | |||
1891 | digital_route_shift(idx)); | 1892 | digital_route_shift(idx)); |
1892 | } | 1893 | } |
1893 | 1894 | ||
1894 | static struct snd_kcontrol_new snd_vt1724_mixer_pro_analog_route __devinitdata = { | 1895 | static const struct snd_kcontrol_new snd_vt1724_mixer_pro_analog_route __devinitdata = { |
1895 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1896 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1896 | .name = "H/W Playback Route", | 1897 | .name = "H/W Playback Route", |
1897 | .info = snd_vt1724_pro_route_info, | 1898 | .info = snd_vt1724_pro_route_info, |
@@ -1899,7 +1900,7 @@ static struct snd_kcontrol_new snd_vt1724_mixer_pro_analog_route __devinitdata = | |||
1899 | .put = snd_vt1724_pro_route_analog_put, | 1900 | .put = snd_vt1724_pro_route_analog_put, |
1900 | }; | 1901 | }; |
1901 | 1902 | ||
1902 | static struct snd_kcontrol_new snd_vt1724_mixer_pro_spdif_route __devinitdata = { | 1903 | static const struct snd_kcontrol_new snd_vt1724_mixer_pro_spdif_route __devinitdata = { |
1903 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1904 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1904 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Route", | 1905 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Route", |
1905 | .info = snd_vt1724_pro_route_info, | 1906 | .info = snd_vt1724_pro_route_info, |
@@ -1935,7 +1936,7 @@ static int snd_vt1724_pro_peak_get(struct snd_kcontrol *kcontrol, | |||
1935 | return 0; | 1936 | return 0; |
1936 | } | 1937 | } |
1937 | 1938 | ||
1938 | static struct snd_kcontrol_new snd_vt1724_mixer_pro_peak __devinitdata = { | 1939 | static const struct snd_kcontrol_new snd_vt1724_mixer_pro_peak __devinitdata = { |
1939 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1940 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1940 | .name = "Multi Track Peak", | 1941 | .name = "Multi Track Peak", |
1941 | .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, | 1942 | .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, |
@@ -1947,9 +1948,9 @@ static struct snd_kcontrol_new snd_vt1724_mixer_pro_peak __devinitdata = { | |||
1947 | * | 1948 | * |
1948 | */ | 1949 | */ |
1949 | 1950 | ||
1950 | static struct snd_ice1712_card_info no_matched __devinitdata; | 1951 | static const struct snd_ice1712_card_info no_matched __devinitdata; |
1951 | 1952 | ||
1952 | static struct snd_ice1712_card_info *card_tables[] __devinitdata = { | 1953 | static const struct snd_ice1712_card_info *card_tables[] __devinitdata = { |
1953 | snd_vt1724_revo_cards, | 1954 | snd_vt1724_revo_cards, |
1954 | snd_vt1724_amp_cards, | 1955 | snd_vt1724_amp_cards, |
1955 | snd_vt1724_aureon_cards, | 1956 | snd_vt1724_aureon_cards, |
@@ -1958,6 +1959,7 @@ static struct snd_ice1712_card_info *card_tables[] __devinitdata = { | |||
1958 | snd_vt1724_prodigy192_cards, | 1959 | snd_vt1724_prodigy192_cards, |
1959 | snd_vt1724_juli_cards, | 1960 | snd_vt1724_juli_cards, |
1960 | snd_vt1724_phase_cards, | 1961 | snd_vt1724_phase_cards, |
1962 | snd_vt1724_wtm_cards, | ||
1961 | NULL, | 1963 | NULL, |
1962 | }; | 1964 | }; |
1963 | 1965 | ||
@@ -2007,7 +2009,7 @@ static int __devinit snd_vt1724_read_eeprom(struct snd_ice1712 *ice, | |||
2007 | { | 2009 | { |
2008 | const int dev = 0xa0; /* EEPROM device address */ | 2010 | const int dev = 0xa0; /* EEPROM device address */ |
2009 | unsigned int i, size; | 2011 | unsigned int i, size; |
2010 | struct snd_ice1712_card_info **tbl, *c; | 2012 | const struct snd_ice1712_card_info **tbl, *c; |
2011 | 2013 | ||
2012 | if (! modelname || ! *modelname) { | 2014 | if (! modelname || ! *modelname) { |
2013 | ice->eeprom.subvendor = 0; | 2015 | ice->eeprom.subvendor = 0; |
@@ -2306,7 +2308,7 @@ static int __devinit snd_vt1724_probe(struct pci_dev *pci, | |||
2306 | struct snd_card *card; | 2308 | struct snd_card *card; |
2307 | struct snd_ice1712 *ice; | 2309 | struct snd_ice1712 *ice; |
2308 | int pcm_dev = 0, err; | 2310 | int pcm_dev = 0, err; |
2309 | struct snd_ice1712_card_info **tbl, *c; | 2311 | const struct snd_ice1712_card_info **tbl, *c; |
2310 | 2312 | ||
2311 | if (dev >= SNDRV_CARDS) | 2313 | if (dev >= SNDRV_CARDS) |
2312 | return -ENODEV; | 2314 | return -ENODEV; |
diff --git a/sound/pci/ice1712/juli.c b/sound/pci/ice1712/juli.c index 5176b41ea9d3..d88172fa95da 100644 --- a/sound/pci/ice1712/juli.c +++ b/sound/pci/ice1712/juli.c | |||
@@ -125,7 +125,7 @@ static void juli_akm_set_rate_val(struct snd_akm4xxx *ak, unsigned int rate) | |||
125 | snd_akm4xxx_reset(ak, 0); | 125 | snd_akm4xxx_reset(ak, 0); |
126 | } | 126 | } |
127 | 127 | ||
128 | static struct snd_akm4xxx akm_juli_dac __devinitdata = { | 128 | static const struct snd_akm4xxx akm_juli_dac __devinitdata = { |
129 | .type = SND_AK4358, | 129 | .type = SND_AK4358, |
130 | .num_dacs = 2, | 130 | .num_dacs = 2, |
131 | .ops = { | 131 | .ops = { |
@@ -146,7 +146,7 @@ static int __devinit juli_add_controls(struct snd_ice1712 *ice) | |||
146 | */ | 146 | */ |
147 | static int __devinit juli_init(struct snd_ice1712 *ice) | 147 | static int __devinit juli_init(struct snd_ice1712 *ice) |
148 | { | 148 | { |
149 | static unsigned char ak4114_init_vals[] = { | 149 | static const unsigned char ak4114_init_vals[] = { |
150 | /* AK4117_REG_PWRDN */ AK4114_RST | AK4114_PWN | AK4114_OCKS0 | AK4114_OCKS1, | 150 | /* AK4117_REG_PWRDN */ AK4114_RST | AK4114_PWN | AK4114_OCKS0 | AK4114_OCKS1, |
151 | /* AK4114_REQ_FORMAT */ AK4114_DIF_I24I2S, | 151 | /* AK4114_REQ_FORMAT */ AK4114_DIF_I24I2S, |
152 | /* AK4114_REG_IO0 */ AK4114_TX1E, | 152 | /* AK4114_REG_IO0 */ AK4114_TX1E, |
@@ -154,7 +154,7 @@ static int __devinit juli_init(struct snd_ice1712 *ice) | |||
154 | /* AK4114_REG_INT0_MASK */ 0, | 154 | /* AK4114_REG_INT0_MASK */ 0, |
155 | /* AK4114_REG_INT1_MASK */ 0 | 155 | /* AK4114_REG_INT1_MASK */ 0 |
156 | }; | 156 | }; |
157 | static unsigned char ak4114_init_txcsb[] = { | 157 | static const unsigned char ak4114_init_txcsb[] = { |
158 | 0x41, 0x02, 0x2c, 0x00, 0x00 | 158 | 0x41, 0x02, 0x2c, 0x00, 0x00 |
159 | }; | 159 | }; |
160 | int err; | 160 | int err; |
@@ -206,24 +206,24 @@ static int __devinit juli_init(struct snd_ice1712 *ice) | |||
206 | * hence the driver needs to sets up it properly. | 206 | * hence the driver needs to sets up it properly. |
207 | */ | 207 | */ |
208 | 208 | ||
209 | static unsigned char juli_eeprom[] __devinitdata = { | 209 | static const unsigned char juli_eeprom[] __devinitdata = { |
210 | 0x20, /* SYSCONF: clock 512, mpu401, 1xADC, 1xDACs */ | 210 | [ICE_EEP2_SYSCONF] = 0x20, /* clock 512, mpu401, 1xADC, 1xDACs */ |
211 | 0x80, /* ACLINK: I2S */ | 211 | [ICE_EEP2_ACLINK] = 0x80, /* I2S */ |
212 | 0xf8, /* I2S: vol, 96k, 24bit, 192k */ | 212 | [ICE_EEP2_I2S] = 0xf8, /* vol, 96k, 24bit, 192k */ |
213 | 0xc3, /* SPDIF: out-en, out-int, spdif-in */ | 213 | [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */ |
214 | 0x9f, /* GPIO_DIR */ | 214 | [ICE_EEP2_GPIO_DIR] = 0x9f, |
215 | 0xff, /* GPIO_DIR1 */ | 215 | [ICE_EEP2_GPIO_DIR1] = 0xff, |
216 | 0x7f, /* GPIO_DIR2 */ | 216 | [ICE_EEP2_GPIO_DIR2] = 0x7f, |
217 | 0x9f, /* GPIO_MASK */ | 217 | [ICE_EEP2_GPIO_MASK] = 0x9f, |
218 | 0xff, /* GPIO_MASK1 */ | 218 | [ICE_EEP2_GPIO_MASK1] = 0xff, |
219 | 0x7f, /* GPIO_MASK2 */ | 219 | [ICE_EEP2_GPIO_MASK2] = 0x7f, |
220 | 0x16, /* GPIO_STATE: internal clock, multiple 1x, 48kHz */ | 220 | [ICE_EEP2_GPIO_STATE] = 0x16, /* internal clock, multiple 1x, 48kHz */ |
221 | 0x80, /* GPIO_STATE1: mute */ | 221 | [ICE_EEP2_GPIO_STATE1] = 0x80, /* mute */ |
222 | 0x00, /* GPIO_STATE2 */ | 222 | [ICE_EEP2_GPIO_STATE2] = 0x00, |
223 | }; | 223 | }; |
224 | 224 | ||
225 | /* entry point */ | 225 | /* entry point */ |
226 | struct snd_ice1712_card_info snd_vt1724_juli_cards[] __devinitdata = { | 226 | const struct snd_ice1712_card_info snd_vt1724_juli_cards[] __devinitdata = { |
227 | { | 227 | { |
228 | .subvendor = VT1724_SUBDEVICE_JULI, | 228 | .subvendor = VT1724_SUBDEVICE_JULI, |
229 | .name = "ESI Juli@", | 229 | .name = "ESI Juli@", |
diff --git a/sound/pci/ice1712/juli.h b/sound/pci/ice1712/juli.h index d9f8534fd92e..1b9294f8bce3 100644 --- a/sound/pci/ice1712/juli.h +++ b/sound/pci/ice1712/juli.h | |||
@@ -5,6 +5,6 @@ | |||
5 | 5 | ||
6 | #define VT1724_SUBDEVICE_JULI 0x31305345 /* Juli@ */ | 6 | #define VT1724_SUBDEVICE_JULI 0x31305345 /* Juli@ */ |
7 | 7 | ||
8 | extern struct snd_ice1712_card_info snd_vt1724_juli_cards[]; | 8 | extern const struct snd_ice1712_card_info snd_vt1724_juli_cards[]; |
9 | 9 | ||
10 | #endif /* __SOUND_JULI_H */ | 10 | #endif /* __SOUND_JULI_H */ |
diff --git a/sound/pci/ice1712/phase.c b/sound/pci/ice1712/phase.c index e08d73f4ff85..0751718f4d7b 100644 --- a/sound/pci/ice1712/phase.c +++ b/sound/pci/ice1712/phase.c | |||
@@ -71,7 +71,7 @@ | |||
71 | * Logarithmic volume values for WM8770 | 71 | * Logarithmic volume values for WM8770 |
72 | * Computed as 20 * Log10(255 / x) | 72 | * Computed as 20 * Log10(255 / x) |
73 | */ | 73 | */ |
74 | static unsigned char wm_vol[256] = { | 74 | static const unsigned char wm_vol[256] = { |
75 | 127, 48, 42, 39, 36, 34, 33, 31, 30, 29, 28, 27, 27, 26, 25, 25, 24, 24, 23, | 75 | 127, 48, 42, 39, 36, 34, 33, 31, 30, 29, 28, 27, 27, 26, 25, 25, 24, 24, 23, |
76 | 23, 22, 22, 21, 21, 21, 20, 20, 20, 19, 19, 19, 18, 18, 18, 18, 17, 17, 17, | 76 | 23, 22, 22, 21, 21, 21, 20, 20, 20, 19, 19, 19, 18, 18, 18, 18, 17, 17, 17, |
77 | 17, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 13, 13, 13, | 77 | 17, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 13, 13, 13, |
@@ -89,13 +89,13 @@ static unsigned char wm_vol[256] = { | |||
89 | #define WM_VOL_MAX (sizeof(wm_vol) - 1) | 89 | #define WM_VOL_MAX (sizeof(wm_vol) - 1) |
90 | #define WM_VOL_MUTE 0x8000 | 90 | #define WM_VOL_MUTE 0x8000 |
91 | 91 | ||
92 | static struct snd_akm4xxx akm_phase22 __devinitdata = { | 92 | static const struct snd_akm4xxx akm_phase22 __devinitdata = { |
93 | .type = SND_AK4524, | 93 | .type = SND_AK4524, |
94 | .num_dacs = 2, | 94 | .num_dacs = 2, |
95 | .num_adcs = 2, | 95 | .num_adcs = 2, |
96 | }; | 96 | }; |
97 | 97 | ||
98 | static struct snd_ak4xxx_private akm_phase22_priv __devinitdata = { | 98 | static const struct snd_ak4xxx_private akm_phase22_priv __devinitdata = { |
99 | .caddr = 2, | 99 | .caddr = 2, |
100 | .cif = 1, | 100 | .cif = 1, |
101 | .data_mask = 1 << 4, | 101 | .data_mask = 1 << 4, |
@@ -152,36 +152,36 @@ static int __devinit phase22_add_controls(struct snd_ice1712 *ice) | |||
152 | return 0; | 152 | return 0; |
153 | } | 153 | } |
154 | 154 | ||
155 | static unsigned char phase22_eeprom[] __devinitdata = { | 155 | static const unsigned char phase22_eeprom[] __devinitdata = { |
156 | 0x00, /* SYSCONF: 1xADC, 1xDACs */ | 156 | [ICE_EEP2_SYSCONF] = 0x00, /* 1xADC, 1xDACs */ |
157 | 0x80, /* ACLINK: I2S */ | 157 | [ICE_EEP2_ACLINK] = 0x80, /* I2S */ |
158 | 0xf8, /* I2S: vol, 96k, 24bit*/ | 158 | [ICE_EEP2_I2S] = 0xf8, /* vol, 96k, 24bit */ |
159 | 0xc3, /* SPDIF: out-en, out-int, spdif-in */ | 159 | [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */ |
160 | 0xFF, /* GPIO_DIR */ | 160 | [ICE_EEP2_GPIO_DIR] = 0xff, |
161 | 0xFF, /* GPIO_DIR1 */ | 161 | [ICE_EEP2_GPIO_DIR1] = 0xff, |
162 | 0xFF, /* GPIO_DIR2 */ | 162 | [ICE_EEP2_GPIO_DIR2] = 0xff, |
163 | 0x00, /* GPIO_MASK */ | 163 | [ICE_EEP2_GPIO_MASK] = 0x00, |
164 | 0x00, /* GPIO_MASK1 */ | 164 | [ICE_EEP2_GPIO_MASK1] = 0x00, |
165 | 0x00, /* GPIO_MASK2 */ | 165 | [ICE_EEP2_GPIO_MASK2] = 0x00, |
166 | 0x00, /* GPIO_STATE: */ | 166 | [ICE_EEP2_GPIO_STATE] = 0x00, |
167 | 0x00, /* GPIO_STATE1: */ | 167 | [ICE_EEP2_GPIO_STATE1] = 0x00, |
168 | 0x00, /* GPIO_STATE2 */ | 168 | [ICE_EEP2_GPIO_STATE2] = 0x00, |
169 | }; | 169 | }; |
170 | 170 | ||
171 | static unsigned char phase28_eeprom[] __devinitdata = { | 171 | static const unsigned char phase28_eeprom[] __devinitdata = { |
172 | 0x0b, /* SYSCONF: clock 512, spdif-in/ADC, 4DACs */ | 172 | [ICE_EEP2_SYSCONF] = 0x0b, /* clock 512, spdif-in/ADC, 4DACs */ |
173 | 0x80, /* ACLINK: I2S */ | 173 | [ICE_EEP2_ACLINK] = 0x80, /* I2S */ |
174 | 0xfc, /* I2S: vol, 96k, 24bit, 192k */ | 174 | [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */ |
175 | 0xc3, /* SPDIF: out-en, out-int, spdif-in */ | 175 | [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */ |
176 | 0xff, /* GPIO_DIR */ | 176 | [ICE_EEP2_GPIO_DIR] = 0xff, |
177 | 0xff, /* GPIO_DIR1 */ | 177 | [ICE_EEP2_GPIO_DIR1] = 0xff, |
178 | 0x5f, /* GPIO_DIR2 */ | 178 | [ICE_EEP2_GPIO_DIR2] = 0x5f, |
179 | 0x00, /* GPIO_MASK */ | 179 | [ICE_EEP2_GPIO_MASK] = 0x00, |
180 | 0x00, /* GPIO_MASK1 */ | 180 | [ICE_EEP2_GPIO_MASK1] = 0x00, |
181 | 0x00, /* GPIO_MASK2 */ | 181 | [ICE_EEP2_GPIO_MASK2] = 0x00, |
182 | 0x00, /* GPIO_STATE */ | 182 | [ICE_EEP2_GPIO_STATE] = 0x00, |
183 | 0x00, /* GPIO_STATE1 */ | 183 | [ICE_EEP2_GPIO_STATE1] = 0x00, |
184 | 0x00, /* GPIO_STATE2 */ | 184 | [ICE_EEP2_GPIO_STATE2] = 0x00, |
185 | }; | 185 | }; |
186 | 186 | ||
187 | /* | 187 | /* |
@@ -343,7 +343,7 @@ static int wm_master_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_ | |||
343 | 343 | ||
344 | static int __devinit phase28_init(struct snd_ice1712 *ice) | 344 | static int __devinit phase28_init(struct snd_ice1712 *ice) |
345 | { | 345 | { |
346 | static unsigned short wm_inits_phase28[] = { | 346 | static const unsigned short wm_inits_phase28[] = { |
347 | /* These come first to reduce init pop noise */ | 347 | /* These come first to reduce init pop noise */ |
348 | 0x1b, 0x044, /* ADC Mux (AC'97 source) */ | 348 | 0x1b, 0x044, /* ADC Mux (AC'97 source) */ |
349 | 0x1c, 0x00B, /* Out Mux1 (VOUT1 = DAC+AUX, VOUT2 = DAC) */ | 349 | 0x1c, 0x00B, /* Out Mux1 (VOUT1 = DAC+AUX, VOUT2 = DAC) */ |
@@ -382,7 +382,7 @@ static int __devinit phase28_init(struct snd_ice1712 *ice) | |||
382 | 382 | ||
383 | unsigned int tmp; | 383 | unsigned int tmp; |
384 | struct snd_akm4xxx *ak; | 384 | struct snd_akm4xxx *ak; |
385 | unsigned short *p; | 385 | const unsigned short *p; |
386 | int i; | 386 | int i; |
387 | 387 | ||
388 | ice->num_total_dacs = 8; | 388 | ice->num_total_dacs = 8; |
@@ -697,10 +697,10 @@ static int phase28_oversampling_put(struct snd_kcontrol *kcontrol, struct snd_ct | |||
697 | return 0; | 697 | return 0; |
698 | } | 698 | } |
699 | 699 | ||
700 | static DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1); | 700 | static const DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1); |
701 | static DECLARE_TLV_DB_SCALE(db_scale_wm_pcm, -6400, 50, 1); | 701 | static const DECLARE_TLV_DB_SCALE(db_scale_wm_pcm, -6400, 50, 1); |
702 | 702 | ||
703 | static struct snd_kcontrol_new phase28_dac_controls[] __devinitdata = { | 703 | static const struct snd_kcontrol_new phase28_dac_controls[] __devinitdata = { |
704 | { | 704 | { |
705 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 705 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
706 | .name = "Master Playback Switch", | 706 | .name = "Master Playback Switch", |
@@ -815,7 +815,7 @@ static struct snd_kcontrol_new phase28_dac_controls[] __devinitdata = { | |||
815 | } | 815 | } |
816 | }; | 816 | }; |
817 | 817 | ||
818 | static struct snd_kcontrol_new wm_controls[] __devinitdata = { | 818 | static const struct snd_kcontrol_new wm_controls[] __devinitdata = { |
819 | { | 819 | { |
820 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 820 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
821 | .name = "PCM Playback Switch", | 821 | .name = "PCM Playback Switch", |
@@ -870,7 +870,7 @@ static int __devinit phase28_add_controls(struct snd_ice1712 *ice) | |||
870 | return 0; | 870 | return 0; |
871 | } | 871 | } |
872 | 872 | ||
873 | struct snd_ice1712_card_info snd_vt1724_phase_cards[] __devinitdata = { | 873 | const struct snd_ice1712_card_info snd_vt1724_phase_cards[] __devinitdata = { |
874 | { | 874 | { |
875 | .subvendor = VT1724_SUBDEVICE_PHASE22, | 875 | .subvendor = VT1724_SUBDEVICE_PHASE22, |
876 | .name = "Terratec PHASE 22", | 876 | .name = "Terratec PHASE 22", |
diff --git a/sound/pci/ice1712/phase.h b/sound/pci/ice1712/phase.h index 13e841b55488..ad379a99bf92 100644 --- a/sound/pci/ice1712/phase.h +++ b/sound/pci/ice1712/phase.h | |||
@@ -31,7 +31,7 @@ | |||
31 | #define VT1724_SUBDEVICE_PHASE28 0x3b154911 | 31 | #define VT1724_SUBDEVICE_PHASE28 0x3b154911 |
32 | 32 | ||
33 | /* entry point */ | 33 | /* entry point */ |
34 | extern struct snd_ice1712_card_info snd_vt1724_phase_cards[]; | 34 | extern const struct snd_ice1712_card_info snd_vt1724_phase_cards[]; |
35 | 35 | ||
36 | /* PHASE28 GPIO bits */ | 36 | /* PHASE28 GPIO bits */ |
37 | #define PHASE28_SPI_MISO (1 << 21) | 37 | #define PHASE28_SPI_MISO (1 << 21) |
diff --git a/sound/pci/ice1712/pontis.c b/sound/pci/ice1712/pontis.c index 6c74c2d2e7f3..9552497f0765 100644 --- a/sound/pci/ice1712/pontis.c +++ b/sound/pci/ice1712/pontis.c | |||
@@ -434,7 +434,7 @@ static unsigned int spi_read(struct snd_ice1712 *ice, unsigned int dev, unsigned | |||
434 | */ | 434 | */ |
435 | static int cs_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | 435 | static int cs_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) |
436 | { | 436 | { |
437 | static char *texts[] = { | 437 | static const char * const texts[] = { |
438 | "Coax", /* RXP0 */ | 438 | "Coax", /* RXP0 */ |
439 | "Optical", /* RXP1 */ | 439 | "Optical", /* RXP1 */ |
440 | "CD", /* RXP2 */ | 440 | "CD", /* RXP2 */ |
@@ -565,13 +565,13 @@ static int pontis_gpio_data_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el | |||
565 | return changed; | 565 | return changed; |
566 | } | 566 | } |
567 | 567 | ||
568 | static DECLARE_TLV_DB_SCALE(db_scale_volume, -6400, 50, 1); | 568 | static const DECLARE_TLV_DB_SCALE(db_scale_volume, -6400, 50, 1); |
569 | 569 | ||
570 | /* | 570 | /* |
571 | * mixers | 571 | * mixers |
572 | */ | 572 | */ |
573 | 573 | ||
574 | static struct snd_kcontrol_new pontis_controls[] __devinitdata = { | 574 | static const struct snd_kcontrol_new pontis_controls[] __devinitdata = { |
575 | { | 575 | { |
576 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 576 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
577 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | 577 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | |
@@ -741,7 +741,7 @@ static int __devinit pontis_add_controls(struct snd_ice1712 *ice) | |||
741 | */ | 741 | */ |
742 | static int __devinit pontis_init(struct snd_ice1712 *ice) | 742 | static int __devinit pontis_init(struct snd_ice1712 *ice) |
743 | { | 743 | { |
744 | static unsigned short wm_inits[] = { | 744 | static const unsigned short wm_inits[] = { |
745 | /* These come first to reduce init pop noise */ | 745 | /* These come first to reduce init pop noise */ |
746 | WM_ADC_MUX, 0x00c0, /* ADC mute */ | 746 | WM_ADC_MUX, 0x00c0, /* ADC mute */ |
747 | WM_DAC_MUTE, 0x0001, /* DAC softmute */ | 747 | WM_DAC_MUTE, 0x0001, /* DAC softmute */ |
@@ -750,7 +750,7 @@ static int __devinit pontis_init(struct snd_ice1712 *ice) | |||
750 | WM_POWERDOWN, 0x0008, /* All power-up except HP */ | 750 | WM_POWERDOWN, 0x0008, /* All power-up except HP */ |
751 | WM_RESET, 0x0000, /* reset */ | 751 | WM_RESET, 0x0000, /* reset */ |
752 | }; | 752 | }; |
753 | static unsigned short wm_inits2[] = { | 753 | static const unsigned short wm_inits2[] = { |
754 | WM_MASTER_CTRL, 0x0022, /* 256fs, slave mode */ | 754 | WM_MASTER_CTRL, 0x0022, /* 256fs, slave mode */ |
755 | WM_DAC_INT, 0x0022, /* I2S, normal polarity, 24bit */ | 755 | WM_DAC_INT, 0x0022, /* I2S, normal polarity, 24bit */ |
756 | WM_ADC_INT, 0x0022, /* I2S, normal polarity, 24bit */ | 756 | WM_ADC_INT, 0x0022, /* I2S, normal polarity, 24bit */ |
@@ -776,7 +776,7 @@ static int __devinit pontis_init(struct snd_ice1712 *ice) | |||
776 | WM_DAC_MUTE, 0x0000, /* DAC unmute */ | 776 | WM_DAC_MUTE, 0x0000, /* DAC unmute */ |
777 | WM_ADC_MUX, 0x0003, /* ADC unmute, both CD/Line On */ | 777 | WM_ADC_MUX, 0x0003, /* ADC unmute, both CD/Line On */ |
778 | }; | 778 | }; |
779 | static unsigned char cs_inits[] = { | 779 | static const unsigned char cs_inits[] = { |
780 | 0x04, 0x80, /* RUN, RXP0 */ | 780 | 0x04, 0x80, /* RUN, RXP0 */ |
781 | 0x05, 0x05, /* slave, 24bit */ | 781 | 0x05, 0x05, /* slave, 24bit */ |
782 | 0x01, 0x00, | 782 | 0x01, 0x00, |
@@ -826,24 +826,24 @@ static int __devinit pontis_init(struct snd_ice1712 *ice) | |||
826 | * hence the driver needs to sets up it properly. | 826 | * hence the driver needs to sets up it properly. |
827 | */ | 827 | */ |
828 | 828 | ||
829 | static unsigned char pontis_eeprom[] __devinitdata = { | 829 | static const unsigned char pontis_eeprom[] __devinitdata = { |
830 | 0x08, /* SYSCONF: clock 256, mpu401, spdif-in/ADC, 1DAC */ | 830 | [ICE_EEP2_SYSCONF] = 0x08, /* clock 256, mpu401, spdif-in/ADC, 1DAC */ |
831 | 0x80, /* ACLINK: I2S */ | 831 | [ICE_EEP2_ACLINK] = 0x80, /* I2S */ |
832 | 0xf8, /* I2S: vol, 96k, 24bit, 192k */ | 832 | [ICE_EEP2_I2S] = 0xf8, /* vol, 96k, 24bit, 192k */ |
833 | 0xc3, /* SPDIF: out-en, out-int, spdif-in */ | 833 | [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */ |
834 | 0x07, /* GPIO_DIR */ | 834 | [ICE_EEP2_GPIO_DIR] = 0x07, |
835 | 0x00, /* GPIO_DIR1 */ | 835 | [ICE_EEP2_GPIO_DIR1] = 0x00, |
836 | 0x00, /* GPIO_DIR2 (ignored) */ | 836 | [ICE_EEP2_GPIO_DIR2] = 0x00, /* ignored */ |
837 | 0x0f, /* GPIO_MASK (4-7 reserved for CS8416) */ | 837 | [ICE_EEP2_GPIO_MASK] = 0x0f, /* 4-7 reserved for CS8416 */ |
838 | 0xff, /* GPIO_MASK1 */ | 838 | [ICE_EEP2_GPIO_MASK1] = 0xff, |
839 | 0x00, /* GPIO_MASK2 (ignored) */ | 839 | [ICE_EEP2_GPIO_MASK2] = 0x00, /* ignored */ |
840 | 0x06, /* GPIO_STATE (0-low, 1-high, 2-high) */ | 840 | [ICE_EEP2_GPIO_STATE] = 0x06, /* 0-low, 1-high, 2-high */ |
841 | 0x00, /* GPIO_STATE1 */ | 841 | [ICE_EEP2_GPIO_STATE1] = 0x00, |
842 | 0x00, /* GPIO_STATE2 (ignored) */ | 842 | [ICE_EEP2_GPIO_STATE2] = 0x00, /* ignored */ |
843 | }; | 843 | }; |
844 | 844 | ||
845 | /* entry point */ | 845 | /* entry point */ |
846 | struct snd_ice1712_card_info snd_vt1720_pontis_cards[] __devinitdata = { | 846 | const struct snd_ice1712_card_info snd_vt1720_pontis_cards[] __devinitdata = { |
847 | { | 847 | { |
848 | .subvendor = VT1720_SUBDEVICE_PONTIS_MS300, | 848 | .subvendor = VT1720_SUBDEVICE_PONTIS_MS300, |
849 | .name = "Pontis MS300", | 849 | .name = "Pontis MS300", |
diff --git a/sound/pci/ice1712/pontis.h b/sound/pci/ice1712/pontis.h index d0d1378b935c..1a418255c19e 100644 --- a/sound/pci/ice1712/pontis.h +++ b/sound/pci/ice1712/pontis.h | |||
@@ -28,6 +28,6 @@ | |||
28 | 28 | ||
29 | #define VT1720_SUBDEVICE_PONTIS_MS300 0x00020002 /* a dummy id for MS300 */ | 29 | #define VT1720_SUBDEVICE_PONTIS_MS300 0x00020002 /* a dummy id for MS300 */ |
30 | 30 | ||
31 | extern struct snd_ice1712_card_info snd_vt1720_pontis_cards[]; | 31 | extern const struct snd_ice1712_card_info snd_vt1720_pontis_cards[]; |
32 | 32 | ||
33 | #endif /* __SOUND_PONTIS_H */ | 33 | #endif /* __SOUND_PONTIS_H */ |
diff --git a/sound/pci/ice1712/prodigy192.c b/sound/pci/ice1712/prodigy192.c index 41b2605daa3a..31cc66eb9f8f 100644 --- a/sound/pci/ice1712/prodigy192.c +++ b/sound/pci/ice1712/prodigy192.c | |||
@@ -357,14 +357,14 @@ static int aureon_oversampling_put(struct snd_kcontrol *kcontrol, struct snd_ctl | |||
357 | } | 357 | } |
358 | #endif | 358 | #endif |
359 | 359 | ||
360 | static DECLARE_TLV_DB_SCALE(db_scale_dac, -19125, 75, 0); | 360 | static const DECLARE_TLV_DB_SCALE(db_scale_dac, -19125, 75, 0); |
361 | static DECLARE_TLV_DB_SCALE(db_scale_adc, 0, 150, 0); | 361 | static const DECLARE_TLV_DB_SCALE(db_scale_adc, 0, 150, 0); |
362 | 362 | ||
363 | /* | 363 | /* |
364 | * mixers | 364 | * mixers |
365 | */ | 365 | */ |
366 | 366 | ||
367 | static struct snd_kcontrol_new stac_controls[] __devinitdata = { | 367 | static const struct snd_kcontrol_new stac_controls[] __devinitdata = { |
368 | { | 368 | { |
369 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 369 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
370 | .name = "Master Playback Switch", | 370 | .name = "Master Playback Switch", |
@@ -475,7 +475,7 @@ static int __devinit prodigy192_add_controls(struct snd_ice1712 *ice) | |||
475 | */ | 475 | */ |
476 | static int __devinit prodigy192_init(struct snd_ice1712 *ice) | 476 | static int __devinit prodigy192_init(struct snd_ice1712 *ice) |
477 | { | 477 | { |
478 | static unsigned short stac_inits_prodigy[] = { | 478 | static const unsigned short stac_inits_prodigy[] = { |
479 | STAC946X_RESET, 0, | 479 | STAC946X_RESET, 0, |
480 | /* STAC946X_MASTER_VOLUME, 0, | 480 | /* STAC946X_MASTER_VOLUME, 0, |
481 | STAC946X_LF_VOLUME, 0, | 481 | STAC946X_LF_VOLUME, 0, |
@@ -486,7 +486,7 @@ static int __devinit prodigy192_init(struct snd_ice1712 *ice) | |||
486 | STAC946X_LFE_VOLUME, 0,*/ | 486 | STAC946X_LFE_VOLUME, 0,*/ |
487 | (unsigned short)-1 | 487 | (unsigned short)-1 |
488 | }; | 488 | }; |
489 | unsigned short *p; | 489 | const unsigned short *p; |
490 | 490 | ||
491 | /* prodigy 192 */ | 491 | /* prodigy 192 */ |
492 | ice->num_total_dacs = 6; | 492 | ice->num_total_dacs = 6; |
@@ -506,25 +506,25 @@ static int __devinit prodigy192_init(struct snd_ice1712 *ice) | |||
506 | * hence the driver needs to sets up it properly. | 506 | * hence the driver needs to sets up it properly. |
507 | */ | 507 | */ |
508 | 508 | ||
509 | static unsigned char prodigy71_eeprom[] __devinitdata = { | 509 | static const unsigned char prodigy71_eeprom[] __devinitdata = { |
510 | 0x2b, /* SYSCONF: clock 512, mpu401, spdif-in/ADC, 4DACs */ | 510 | [ICE_EEP2_SYSCONF] = 0x2b, /* clock 512, mpu401, spdif-in/ADC, 4DACs */ |
511 | 0x80, /* ACLINK: I2S */ | 511 | [ICE_EEP2_ACLINK] = 0x80, /* I2S */ |
512 | 0xf8, /* I2S: vol, 96k, 24bit, 192k */ | 512 | [ICE_EEP2_I2S] = 0xf8, /* vol, 96k, 24bit, 192k */ |
513 | 0xc3, /* SPDIF: out-en, out-int, spdif-in */ | 513 | [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */ |
514 | 0xff, /* GPIO_DIR */ | 514 | [ICE_EEP2_GPIO_DIR] = 0xff, |
515 | 0xff, /* GPIO_DIR1 */ | 515 | [ICE_EEP2_GPIO_DIR1] = 0xff, |
516 | 0xbf, /* GPIO_DIR2 */ | 516 | [ICE_EEP2_GPIO_DIR2] = 0xbf, |
517 | 0x00, /* GPIO_MASK */ | 517 | [ICE_EEP2_GPIO_MASK] = 0x00, |
518 | 0x00, /* GPIO_MASK1 */ | 518 | [ICE_EEP2_GPIO_MASK1] = 0x00, |
519 | 0x00, /* GPIO_MASK2 */ | 519 | [ICE_EEP2_GPIO_MASK2] = 0x00, |
520 | 0x00, /* GPIO_STATE */ | 520 | [ICE_EEP2_GPIO_STATE] = 0x00, |
521 | 0x00, /* GPIO_STATE1 */ | 521 | [ICE_EEP2_GPIO_STATE1] = 0x00, |
522 | 0x00, /* GPIO_STATE2 */ | 522 | [ICE_EEP2_GPIO_STATE2] = 0x00, |
523 | }; | 523 | }; |
524 | 524 | ||
525 | 525 | ||
526 | /* entry point */ | 526 | /* entry point */ |
527 | struct snd_ice1712_card_info snd_vt1724_prodigy192_cards[] __devinitdata = { | 527 | const struct snd_ice1712_card_info snd_vt1724_prodigy192_cards[] __devinitdata = { |
528 | { | 528 | { |
529 | .subvendor = VT1724_SUBDEVICE_PRODIGY192VE, | 529 | .subvendor = VT1724_SUBDEVICE_PRODIGY192VE, |
530 | .name = "Audiotrak Prodigy 192", | 530 | .name = "Audiotrak Prodigy 192", |
diff --git a/sound/pci/ice1712/prodigy192.h b/sound/pci/ice1712/prodigy192.h index 94c824e24e06..2fa2e62b9e04 100644 --- a/sound/pci/ice1712/prodigy192.h +++ b/sound/pci/ice1712/prodigy192.h | |||
@@ -6,6 +6,6 @@ | |||
6 | 6 | ||
7 | #define VT1724_SUBDEVICE_PRODIGY192VE 0x34495345 /* PRODIGY 192 VE */ | 7 | #define VT1724_SUBDEVICE_PRODIGY192VE 0x34495345 /* PRODIGY 192 VE */ |
8 | 8 | ||
9 | extern struct snd_ice1712_card_info snd_vt1724_prodigy192_cards[]; | 9 | extern const struct snd_ice1712_card_info snd_vt1724_prodigy192_cards[]; |
10 | 10 | ||
11 | #endif /* __SOUND_PRODIGY192_H */ | 11 | #endif /* __SOUND_PRODIGY192_H */ |
diff --git a/sound/pci/ice1712/revo.c b/sound/pci/ice1712/revo.c index bf98ea34feb0..025a7e8497c3 100644 --- a/sound/pci/ice1712/revo.c +++ b/sound/pci/ice1712/revo.c | |||
@@ -84,38 +84,142 @@ static void revo_set_rate_val(struct snd_akm4xxx *ak, unsigned int rate) | |||
84 | } | 84 | } |
85 | 85 | ||
86 | /* | 86 | /* |
87 | * I2C access to the PT2258 volume controller on GPIO 6/7 (Revolution 5.1) | ||
88 | */ | ||
89 | |||
90 | static void revo_i2c_start(struct snd_i2c_bus *bus) | ||
91 | { | ||
92 | struct snd_ice1712 *ice = bus->private_data; | ||
93 | snd_ice1712_save_gpio_status(ice); | ||
94 | } | ||
95 | |||
96 | static void revo_i2c_stop(struct snd_i2c_bus *bus) | ||
97 | { | ||
98 | struct snd_ice1712 *ice = bus->private_data; | ||
99 | snd_ice1712_restore_gpio_status(ice); | ||
100 | } | ||
101 | |||
102 | static void revo_i2c_direction(struct snd_i2c_bus *bus, int clock, int data) | ||
103 | { | ||
104 | struct snd_ice1712 *ice = bus->private_data; | ||
105 | unsigned int mask, val; | ||
106 | |||
107 | val = 0; | ||
108 | if (clock) | ||
109 | val |= VT1724_REVO_I2C_CLOCK; /* write SCL */ | ||
110 | if (data) | ||
111 | val |= VT1724_REVO_I2C_DATA; /* write SDA */ | ||
112 | mask = VT1724_REVO_I2C_CLOCK | VT1724_REVO_I2C_DATA; | ||
113 | ice->gpio.direction &= ~mask; | ||
114 | ice->gpio.direction |= val; | ||
115 | snd_ice1712_gpio_set_dir(ice, ice->gpio.direction); | ||
116 | snd_ice1712_gpio_set_mask(ice, ~mask); | ||
117 | } | ||
118 | |||
119 | static void revo_i2c_setlines(struct snd_i2c_bus *bus, int clk, int data) | ||
120 | { | ||
121 | struct snd_ice1712 *ice = bus->private_data; | ||
122 | unsigned int val = 0; | ||
123 | |||
124 | if (clk) | ||
125 | val |= VT1724_REVO_I2C_CLOCK; | ||
126 | if (data) | ||
127 | val |= VT1724_REVO_I2C_DATA; | ||
128 | snd_ice1712_gpio_write_bits(ice, | ||
129 | VT1724_REVO_I2C_DATA | | ||
130 | VT1724_REVO_I2C_CLOCK, val); | ||
131 | udelay(5); | ||
132 | } | ||
133 | |||
134 | static int revo_i2c_getdata(struct snd_i2c_bus *bus, int ack) | ||
135 | { | ||
136 | struct snd_ice1712 *ice = bus->private_data; | ||
137 | int bit; | ||
138 | |||
139 | if (ack) | ||
140 | udelay(5); | ||
141 | bit = snd_ice1712_gpio_read_bits(ice, VT1724_REVO_I2C_DATA) ? 1 : 0; | ||
142 | return bit; | ||
143 | } | ||
144 | |||
145 | static struct snd_i2c_bit_ops revo51_bit_ops = { | ||
146 | .start = revo_i2c_start, | ||
147 | .stop = revo_i2c_stop, | ||
148 | .direction = revo_i2c_direction, | ||
149 | .setlines = revo_i2c_setlines, | ||
150 | .getdata = revo_i2c_getdata, | ||
151 | }; | ||
152 | |||
153 | static int revo51_i2c_init(struct snd_ice1712 *ice, | ||
154 | struct snd_pt2258 *pt) | ||
155 | { | ||
156 | int err; | ||
157 | |||
158 | /* create the I2C bus */ | ||
159 | err = snd_i2c_bus_create(ice->card, "ICE1724 GPIO6", NULL, &ice->i2c); | ||
160 | if (err < 0) | ||
161 | return err; | ||
162 | |||
163 | ice->i2c->private_data = ice; | ||
164 | ice->i2c->hw_ops.bit = &revo51_bit_ops; | ||
165 | |||
166 | /* create the I2C device */ | ||
167 | err = snd_i2c_device_create(ice->i2c, "PT2258", 0x40, | ||
168 | &ice->spec.revo51.dev); | ||
169 | if (err < 0) | ||
170 | return err; | ||
171 | |||
172 | pt->card = ice->card; | ||
173 | pt->i2c_bus = ice->i2c; | ||
174 | pt->i2c_dev = ice->spec.revo51.dev; | ||
175 | ice->spec.revo51.pt2258 = pt; | ||
176 | |||
177 | snd_pt2258_reset(pt); | ||
178 | |||
179 | return 0; | ||
180 | } | ||
181 | |||
182 | /* | ||
87 | * initialize the chips on M-Audio Revolution cards | 183 | * initialize the chips on M-Audio Revolution cards |
88 | */ | 184 | */ |
89 | 185 | ||
90 | #define AK_DAC(xname,xch) { .name = xname, .num_channels = xch } | 186 | #define AK_DAC(xname,xch) { .name = xname, .num_channels = xch } |
91 | 187 | ||
92 | static struct snd_akm4xxx_dac_channel revo71_front[] = { | 188 | static const struct snd_akm4xxx_dac_channel revo71_front[] = { |
93 | AK_DAC("PCM Playback Volume", 2) | 189 | AK_DAC("PCM Playback Volume", 2) |
94 | }; | 190 | }; |
95 | 191 | ||
96 | static struct snd_akm4xxx_dac_channel revo71_surround[] = { | 192 | static const struct snd_akm4xxx_dac_channel revo71_surround[] = { |
97 | AK_DAC("PCM Center Playback Volume", 1), | 193 | AK_DAC("PCM Center Playback Volume", 1), |
98 | AK_DAC("PCM LFE Playback Volume", 1), | 194 | AK_DAC("PCM LFE Playback Volume", 1), |
99 | AK_DAC("PCM Side Playback Volume", 2), | 195 | AK_DAC("PCM Side Playback Volume", 2), |
100 | AK_DAC("PCM Rear Playback Volume", 2), | 196 | AK_DAC("PCM Rear Playback Volume", 2), |
101 | }; | 197 | }; |
102 | 198 | ||
103 | static struct snd_akm4xxx_dac_channel revo51_dac[] = { | 199 | static const struct snd_akm4xxx_dac_channel revo51_dac[] = { |
104 | AK_DAC("PCM Playback Volume", 2), | 200 | AK_DAC("PCM Playback Volume", 2), |
105 | AK_DAC("PCM Center Playback Volume", 1), | 201 | AK_DAC("PCM Center Playback Volume", 1), |
106 | AK_DAC("PCM LFE Playback Volume", 1), | 202 | AK_DAC("PCM LFE Playback Volume", 1), |
107 | AK_DAC("PCM Rear Playback Volume", 2), | 203 | AK_DAC("PCM Rear Playback Volume", 2), |
108 | }; | 204 | }; |
109 | 205 | ||
110 | static struct snd_akm4xxx_adc_channel revo51_adc[] = { | 206 | static const char *revo51_adc_input_names[] = { |
207 | "Mic", | ||
208 | "Line", | ||
209 | "CD", | ||
210 | NULL | ||
211 | }; | ||
212 | |||
213 | static const struct snd_akm4xxx_adc_channel revo51_adc[] = { | ||
111 | { | 214 | { |
112 | .name = "PCM Capture Volume", | 215 | .name = "PCM Capture Volume", |
113 | .switch_name = "PCM Capture Switch", | 216 | .switch_name = "PCM Capture Switch", |
114 | .num_channels = 2 | 217 | .num_channels = 2, |
218 | .input_names = revo51_adc_input_names | ||
115 | }, | 219 | }, |
116 | }; | 220 | }; |
117 | 221 | ||
118 | static struct snd_akm4xxx akm_revo_front __devinitdata = { | 222 | static const struct snd_akm4xxx akm_revo_front __devinitdata = { |
119 | .type = SND_AK4381, | 223 | .type = SND_AK4381, |
120 | .num_dacs = 2, | 224 | .num_dacs = 2, |
121 | .ops = { | 225 | .ops = { |
@@ -124,7 +228,7 @@ static struct snd_akm4xxx akm_revo_front __devinitdata = { | |||
124 | .dac_info = revo71_front, | 228 | .dac_info = revo71_front, |
125 | }; | 229 | }; |
126 | 230 | ||
127 | static struct snd_ak4xxx_private akm_revo_front_priv __devinitdata = { | 231 | static const struct snd_ak4xxx_private akm_revo_front_priv __devinitdata = { |
128 | .caddr = 1, | 232 | .caddr = 1, |
129 | .cif = 0, | 233 | .cif = 0, |
130 | .data_mask = VT1724_REVO_CDOUT, | 234 | .data_mask = VT1724_REVO_CDOUT, |
@@ -136,7 +240,7 @@ static struct snd_ak4xxx_private akm_revo_front_priv __devinitdata = { | |||
136 | .mask_flags = 0, | 240 | .mask_flags = 0, |
137 | }; | 241 | }; |
138 | 242 | ||
139 | static struct snd_akm4xxx akm_revo_surround __devinitdata = { | 243 | static const struct snd_akm4xxx akm_revo_surround __devinitdata = { |
140 | .type = SND_AK4355, | 244 | .type = SND_AK4355, |
141 | .idx_offset = 1, | 245 | .idx_offset = 1, |
142 | .num_dacs = 6, | 246 | .num_dacs = 6, |
@@ -146,7 +250,7 @@ static struct snd_akm4xxx akm_revo_surround __devinitdata = { | |||
146 | .dac_info = revo71_surround, | 250 | .dac_info = revo71_surround, |
147 | }; | 251 | }; |
148 | 252 | ||
149 | static struct snd_ak4xxx_private akm_revo_surround_priv __devinitdata = { | 253 | static const struct snd_ak4xxx_private akm_revo_surround_priv __devinitdata = { |
150 | .caddr = 3, | 254 | .caddr = 3, |
151 | .cif = 0, | 255 | .cif = 0, |
152 | .data_mask = VT1724_REVO_CDOUT, | 256 | .data_mask = VT1724_REVO_CDOUT, |
@@ -158,7 +262,7 @@ static struct snd_ak4xxx_private akm_revo_surround_priv __devinitdata = { | |||
158 | .mask_flags = 0, | 262 | .mask_flags = 0, |
159 | }; | 263 | }; |
160 | 264 | ||
161 | static struct snd_akm4xxx akm_revo51 __devinitdata = { | 265 | static const struct snd_akm4xxx akm_revo51 __devinitdata = { |
162 | .type = SND_AK4358, | 266 | .type = SND_AK4358, |
163 | .num_dacs = 6, | 267 | .num_dacs = 6, |
164 | .ops = { | 268 | .ops = { |
@@ -167,36 +271,213 @@ static struct snd_akm4xxx akm_revo51 __devinitdata = { | |||
167 | .dac_info = revo51_dac, | 271 | .dac_info = revo51_dac, |
168 | }; | 272 | }; |
169 | 273 | ||
170 | static struct snd_ak4xxx_private akm_revo51_priv __devinitdata = { | 274 | static const struct snd_ak4xxx_private akm_revo51_priv __devinitdata = { |
171 | .caddr = 2, | 275 | .caddr = 2, |
172 | .cif = 0, | 276 | .cif = 0, |
173 | .data_mask = VT1724_REVO_CDOUT, | 277 | .data_mask = VT1724_REVO_CDOUT, |
174 | .clk_mask = VT1724_REVO_CCLK, | 278 | .clk_mask = VT1724_REVO_CCLK, |
175 | .cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2, | 279 | .cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS1, |
176 | .cs_addr = VT1724_REVO_CS1 | VT1724_REVO_CS2, | 280 | .cs_addr = VT1724_REVO_CS1, |
177 | .cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2, | 281 | .cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS1, |
178 | .add_flags = VT1724_REVO_CCLK, /* high at init */ | 282 | .add_flags = VT1724_REVO_CCLK, /* high at init */ |
179 | .mask_flags = 0, | 283 | .mask_flags = 0, |
180 | }; | 284 | }; |
181 | 285 | ||
182 | static struct snd_akm4xxx akm_revo51_adc __devinitdata = { | 286 | static const struct snd_akm4xxx akm_revo51_adc __devinitdata = { |
183 | .type = SND_AK5365, | 287 | .type = SND_AK5365, |
184 | .num_adcs = 2, | 288 | .num_adcs = 2, |
185 | .adc_info = revo51_adc, | 289 | .adc_info = revo51_adc, |
186 | }; | 290 | }; |
187 | 291 | ||
188 | static struct snd_ak4xxx_private akm_revo51_adc_priv __devinitdata = { | 292 | static const struct snd_ak4xxx_private akm_revo51_adc_priv __devinitdata = { |
189 | .caddr = 2, | 293 | .caddr = 2, |
190 | .cif = 0, | 294 | .cif = 0, |
191 | .data_mask = VT1724_REVO_CDOUT, | 295 | .data_mask = VT1724_REVO_CDOUT, |
192 | .clk_mask = VT1724_REVO_CCLK, | 296 | .clk_mask = VT1724_REVO_CCLK, |
193 | .cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2, | 297 | .cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS1, |
194 | .cs_addr = VT1724_REVO_CS0 | VT1724_REVO_CS2, | 298 | .cs_addr = VT1724_REVO_CS0, |
195 | .cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2, | 299 | .cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS1, |
300 | .add_flags = VT1724_REVO_CCLK, /* high at init */ | ||
301 | .mask_flags = 0, | ||
302 | }; | ||
303 | |||
304 | static struct snd_pt2258 ptc_revo51_volume; | ||
305 | |||
306 | /* AK4358 for AP192 DAC, AK5385A for ADC */ | ||
307 | static void ap192_set_rate_val(struct snd_akm4xxx *ak, unsigned int rate) | ||
308 | { | ||
309 | struct snd_ice1712 *ice = ak->private_data[0]; | ||
310 | |||
311 | revo_set_rate_val(ak, rate); | ||
312 | |||
313 | #if 1 /* FIXME: do we need this procedure? */ | ||
314 | /* reset DFS pin of AK5385A for ADC, too */ | ||
315 | /* DFS0 (pin 18) -- GPIO10 pin 77 */ | ||
316 | snd_ice1712_save_gpio_status(ice); | ||
317 | snd_ice1712_gpio_write_bits(ice, 1 << 10, | ||
318 | rate > 48000 ? (1 << 10) : 0); | ||
319 | snd_ice1712_restore_gpio_status(ice); | ||
320 | #endif | ||
321 | } | ||
322 | |||
323 | static const struct snd_akm4xxx_dac_channel ap192_dac[] = { | ||
324 | AK_DAC("PCM Playback Volume", 2) | ||
325 | }; | ||
326 | |||
327 | static const struct snd_akm4xxx akm_ap192 __devinitdata = { | ||
328 | .type = SND_AK4358, | ||
329 | .num_dacs = 2, | ||
330 | .ops = { | ||
331 | .set_rate_val = ap192_set_rate_val | ||
332 | }, | ||
333 | .dac_info = ap192_dac, | ||
334 | }; | ||
335 | |||
336 | static const struct snd_ak4xxx_private akm_ap192_priv __devinitdata = { | ||
337 | .caddr = 2, | ||
338 | .cif = 0, | ||
339 | .data_mask = VT1724_REVO_CDOUT, | ||
340 | .clk_mask = VT1724_REVO_CCLK, | ||
341 | .cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS3, | ||
342 | .cs_addr = VT1724_REVO_CS3, | ||
343 | .cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS3, | ||
196 | .add_flags = VT1724_REVO_CCLK, /* high at init */ | 344 | .add_flags = VT1724_REVO_CCLK, /* high at init */ |
197 | .mask_flags = 0, | 345 | .mask_flags = 0, |
198 | }; | 346 | }; |
199 | 347 | ||
348 | #if 0 | ||
349 | /* FIXME: ak4114 makes the sound much lower due to some confliction, | ||
350 | * so let's disable it right now... | ||
351 | */ | ||
352 | #define BUILD_AK4114_AP192 | ||
353 | #endif | ||
354 | |||
355 | #ifdef BUILD_AK4114_AP192 | ||
356 | /* AK4114 support on Audiophile 192 */ | ||
357 | /* CDTO (pin 32) -- GPIO2 pin 52 | ||
358 | * CDTI (pin 33) -- GPIO3 pin 53 (shared with AK4358) | ||
359 | * CCLK (pin 34) -- GPIO1 pin 51 (shared with AK4358) | ||
360 | * CSN (pin 35) -- GPIO7 pin 59 | ||
361 | */ | ||
362 | #define AK4114_ADDR 0x00 | ||
363 | |||
364 | static void write_data(struct snd_ice1712 *ice, unsigned int gpio, | ||
365 | unsigned int data, int idx) | ||
366 | { | ||
367 | for (; idx >= 0; idx--) { | ||
368 | /* drop clock */ | ||
369 | gpio &= ~VT1724_REVO_CCLK; | ||
370 | snd_ice1712_gpio_write(ice, gpio); | ||
371 | udelay(1); | ||
372 | /* set data */ | ||
373 | if (data & (1 << idx)) | ||
374 | gpio |= VT1724_REVO_CDOUT; | ||
375 | else | ||
376 | gpio &= ~VT1724_REVO_CDOUT; | ||
377 | snd_ice1712_gpio_write(ice, gpio); | ||
378 | udelay(1); | ||
379 | /* raise clock */ | ||
380 | gpio |= VT1724_REVO_CCLK; | ||
381 | snd_ice1712_gpio_write(ice, gpio); | ||
382 | udelay(1); | ||
383 | } | ||
384 | } | ||
385 | |||
386 | static unsigned char read_data(struct snd_ice1712 *ice, unsigned int gpio, | ||
387 | int idx) | ||
388 | { | ||
389 | unsigned char data = 0; | ||
390 | |||
391 | for (; idx >= 0; idx--) { | ||
392 | /* drop clock */ | ||
393 | gpio &= ~VT1724_REVO_CCLK; | ||
394 | snd_ice1712_gpio_write(ice, gpio); | ||
395 | udelay(1); | ||
396 | /* read data */ | ||
397 | if (snd_ice1712_gpio_read(ice) & VT1724_REVO_CDIN) | ||
398 | data |= (1 << idx); | ||
399 | udelay(1); | ||
400 | /* raise clock */ | ||
401 | gpio |= VT1724_REVO_CCLK; | ||
402 | snd_ice1712_gpio_write(ice, gpio); | ||
403 | udelay(1); | ||
404 | } | ||
405 | return data; | ||
406 | } | ||
407 | |||
408 | static unsigned char ap192_4wire_start(struct snd_ice1712 *ice) | ||
409 | { | ||
410 | unsigned int tmp; | ||
411 | |||
412 | snd_ice1712_save_gpio_status(ice); | ||
413 | tmp = snd_ice1712_gpio_read(ice); | ||
414 | tmp |= VT1724_REVO_CCLK; /* high at init */ | ||
415 | tmp |= VT1724_REVO_CS0; | ||
416 | tmp &= ~VT1724_REVO_CS3; | ||
417 | snd_ice1712_gpio_write(ice, tmp); | ||
418 | udelay(1); | ||
419 | return tmp; | ||
420 | } | ||
421 | |||
422 | static void ap192_4wire_finish(struct snd_ice1712 *ice, unsigned int tmp) | ||
423 | { | ||
424 | tmp |= VT1724_REVO_CS3; | ||
425 | tmp |= VT1724_REVO_CS0; | ||
426 | snd_ice1712_gpio_write(ice, tmp); | ||
427 | udelay(1); | ||
428 | snd_ice1712_restore_gpio_status(ice); | ||
429 | } | ||
430 | |||
431 | static void ap192_ak4114_write(void *private_data, unsigned char addr, | ||
432 | unsigned char data) | ||
433 | { | ||
434 | struct snd_ice1712 *ice = private_data; | ||
435 | unsigned int tmp, addrdata; | ||
436 | |||
437 | tmp = ap192_4wire_start(ice); | ||
438 | addrdata = (AK4114_ADDR << 6) | 0x20 | (addr & 0x1f); | ||
439 | addrdata = (addrdata << 8) | data; | ||
440 | write_data(ice, tmp, addrdata, 15); | ||
441 | ap192_4wire_finish(ice, tmp); | ||
442 | } | ||
443 | |||
444 | static unsigned char ap192_ak4114_read(void *private_data, unsigned char addr) | ||
445 | { | ||
446 | struct snd_ice1712 *ice = private_data; | ||
447 | unsigned int tmp; | ||
448 | unsigned char data; | ||
449 | |||
450 | tmp = ap192_4wire_start(ice); | ||
451 | write_data(ice, tmp, (AK4114_ADDR << 6) | (addr & 0x1f), 7); | ||
452 | data = read_data(ice, tmp, 7); | ||
453 | ap192_4wire_finish(ice, tmp); | ||
454 | return data; | ||
455 | } | ||
456 | |||
457 | static int ap192_ak4114_init(struct snd_ice1712 *ice) | ||
458 | { | ||
459 | static const unsigned char ak4114_init_vals[] = { | ||
460 | AK4114_RST | AK4114_PWN | AK4114_OCKS0 | AK4114_OCKS1, | ||
461 | AK4114_DIF_I24I2S, | ||
462 | AK4114_TX1E, | ||
463 | AK4114_EFH_1024 | AK4114_DIT | AK4114_IPS(1), | ||
464 | 0, | ||
465 | 0 | ||
466 | }; | ||
467 | static const unsigned char ak4114_init_txcsb[] = { | ||
468 | 0x41, 0x02, 0x2c, 0x00, 0x00 | ||
469 | }; | ||
470 | struct ak4114 *ak; | ||
471 | int err; | ||
472 | |||
473 | return snd_ak4114_create(ice->card, | ||
474 | ap192_ak4114_read, | ||
475 | ap192_ak4114_write, | ||
476 | ak4114_init_vals, ak4114_init_txcsb, | ||
477 | ice, &ak); | ||
478 | } | ||
479 | #endif /* BUILD_AK4114_AP192 */ | ||
480 | |||
200 | static int __devinit revo_init(struct snd_ice1712 *ice) | 481 | static int __devinit revo_init(struct snd_ice1712 *ice) |
201 | { | 482 | { |
202 | struct snd_akm4xxx *ak; | 483 | struct snd_akm4xxx *ak; |
@@ -213,6 +494,10 @@ static int __devinit revo_init(struct snd_ice1712 *ice) | |||
213 | ice->num_total_dacs = 6; | 494 | ice->num_total_dacs = 6; |
214 | ice->num_total_adcs = 2; | 495 | ice->num_total_adcs = 2; |
215 | break; | 496 | break; |
497 | case VT1724_SUBDEVICE_AUDIOPHILE192: | ||
498 | ice->num_total_dacs = 2; | ||
499 | ice->num_total_adcs = 2; | ||
500 | break; | ||
216 | default: | 501 | default: |
217 | snd_BUG(); | 502 | snd_BUG(); |
218 | return -EINVAL; | 503 | return -EINVAL; |
@@ -235,14 +520,28 @@ static int __devinit revo_init(struct snd_ice1712 *ice) | |||
235 | break; | 520 | break; |
236 | case VT1724_SUBDEVICE_REVOLUTION51: | 521 | case VT1724_SUBDEVICE_REVOLUTION51: |
237 | ice->akm_codecs = 2; | 522 | ice->akm_codecs = 2; |
238 | if ((err = snd_ice1712_akm4xxx_init(ak, &akm_revo51, &akm_revo51_priv, ice)) < 0) | 523 | err = snd_ice1712_akm4xxx_init(ak, &akm_revo51, |
524 | &akm_revo51_priv, ice); | ||
525 | if (err < 0) | ||
239 | return err; | 526 | return err; |
240 | err = snd_ice1712_akm4xxx_init(ak + 1, &akm_revo51_adc, | 527 | err = snd_ice1712_akm4xxx_init(ak+1, &akm_revo51_adc, |
241 | &akm_revo51_adc_priv, ice); | 528 | &akm_revo51_adc_priv, ice); |
242 | if (err < 0) | 529 | if (err < 0) |
243 | return err; | 530 | return err; |
244 | /* unmute all codecs - needed! */ | 531 | err = revo51_i2c_init(ice, &ptc_revo51_volume); |
245 | snd_ice1712_gpio_write_bits(ice, VT1724_REVO_MUTE, VT1724_REVO_MUTE); | 532 | if (err < 0) |
533 | return err; | ||
534 | /* unmute all codecs */ | ||
535 | snd_ice1712_gpio_write_bits(ice, VT1724_REVO_MUTE, | ||
536 | VT1724_REVO_MUTE); | ||
537 | break; | ||
538 | case VT1724_SUBDEVICE_AUDIOPHILE192: | ||
539 | ice->akm_codecs = 1; | ||
540 | err = snd_ice1712_akm4xxx_init(ak, &akm_ap192, &akm_ap192_priv, | ||
541 | ice); | ||
542 | if (err < 0) | ||
543 | return err; | ||
544 | |||
246 | break; | 545 | break; |
247 | } | 546 | } |
248 | 547 | ||
@@ -256,16 +555,34 @@ static int __devinit revo_add_controls(struct snd_ice1712 *ice) | |||
256 | 555 | ||
257 | switch (ice->eeprom.subvendor) { | 556 | switch (ice->eeprom.subvendor) { |
258 | case VT1724_SUBDEVICE_REVOLUTION71: | 557 | case VT1724_SUBDEVICE_REVOLUTION71: |
558 | err = snd_ice1712_akm4xxx_build_controls(ice); | ||
559 | if (err < 0) | ||
560 | return err; | ||
561 | break; | ||
259 | case VT1724_SUBDEVICE_REVOLUTION51: | 562 | case VT1724_SUBDEVICE_REVOLUTION51: |
260 | err = snd_ice1712_akm4xxx_build_controls(ice); | 563 | err = snd_ice1712_akm4xxx_build_controls(ice); |
261 | if (err < 0) | 564 | if (err < 0) |
262 | return err; | 565 | return err; |
566 | err = snd_pt2258_build_controls(ice->spec.revo51.pt2258); | ||
567 | if (err < 0) | ||
568 | return err; | ||
569 | break; | ||
570 | case VT1724_SUBDEVICE_AUDIOPHILE192: | ||
571 | err = snd_ice1712_akm4xxx_build_controls(ice); | ||
572 | if (err < 0) | ||
573 | return err; | ||
574 | #ifdef BUILD_AK4114_AP192 | ||
575 | err = ap192_ak4114_init(ice); | ||
576 | if (err < 0) | ||
577 | return err; | ||
578 | #endif | ||
579 | break; | ||
263 | } | 580 | } |
264 | return 0; | 581 | return 0; |
265 | } | 582 | } |
266 | 583 | ||
267 | /* entry point */ | 584 | /* entry point */ |
268 | struct snd_ice1712_card_info snd_vt1724_revo_cards[] __devinitdata = { | 585 | const struct snd_ice1712_card_info snd_vt1724_revo_cards[] __devinitdata = { |
269 | { | 586 | { |
270 | .subvendor = VT1724_SUBDEVICE_REVOLUTION71, | 587 | .subvendor = VT1724_SUBDEVICE_REVOLUTION71, |
271 | .name = "M Audio Revolution-7.1", | 588 | .name = "M Audio Revolution-7.1", |
@@ -280,5 +597,12 @@ struct snd_ice1712_card_info snd_vt1724_revo_cards[] __devinitdata = { | |||
280 | .chip_init = revo_init, | 597 | .chip_init = revo_init, |
281 | .build_controls = revo_add_controls, | 598 | .build_controls = revo_add_controls, |
282 | }, | 599 | }, |
600 | { | ||
601 | .subvendor = VT1724_SUBDEVICE_AUDIOPHILE192, | ||
602 | .name = "M Audio Audiophile192", | ||
603 | .model = "ap192", | ||
604 | .chip_init = revo_init, | ||
605 | .build_controls = revo_add_controls, | ||
606 | }, | ||
283 | { } /* terminator */ | 607 | { } /* terminator */ |
284 | }; | 608 | }; |
diff --git a/sound/pci/ice1712/revo.h b/sound/pci/ice1712/revo.h index efbb86ec3289..2a24488fad80 100644 --- a/sound/pci/ice1712/revo.h +++ b/sound/pci/ice1712/revo.h | |||
@@ -26,13 +26,15 @@ | |||
26 | 26 | ||
27 | #define REVO_DEVICE_DESC \ | 27 | #define REVO_DEVICE_DESC \ |
28 | "{MidiMan M Audio,Revolution 7.1},"\ | 28 | "{MidiMan M Audio,Revolution 7.1},"\ |
29 | "{MidiMan M Audio,Revolution 5.1}," | 29 | "{MidiMan M Audio,Revolution 5.1},"\ |
30 | "{MidiMan M Audio,Audiophile 192}," | ||
30 | 31 | ||
31 | #define VT1724_SUBDEVICE_REVOLUTION71 0x12143036 | 32 | #define VT1724_SUBDEVICE_REVOLUTION71 0x12143036 |
32 | #define VT1724_SUBDEVICE_REVOLUTION51 0x12143136 | 33 | #define VT1724_SUBDEVICE_REVOLUTION51 0x12143136 |
34 | #define VT1724_SUBDEVICE_AUDIOPHILE192 0x12143236 | ||
33 | 35 | ||
34 | /* entry point */ | 36 | /* entry point */ |
35 | extern struct snd_ice1712_card_info snd_vt1724_revo_cards[]; | 37 | extern const struct snd_ice1712_card_info snd_vt1724_revo_cards[]; |
36 | 38 | ||
37 | 39 | ||
38 | /* | 40 | /* |
@@ -42,9 +44,12 @@ extern struct snd_ice1712_card_info snd_vt1724_revo_cards[]; | |||
42 | #define VT1724_REVO_CCLK 0x02 | 44 | #define VT1724_REVO_CCLK 0x02 |
43 | #define VT1724_REVO_CDIN 0x04 /* not used */ | 45 | #define VT1724_REVO_CDIN 0x04 /* not used */ |
44 | #define VT1724_REVO_CDOUT 0x08 | 46 | #define VT1724_REVO_CDOUT 0x08 |
45 | #define VT1724_REVO_CS0 0x10 /* AK5365 chipselect for Rev. 5.1 */ | 47 | #define VT1724_REVO_CS0 0x10 /* AK5365 chipselect for (revo51) */ |
46 | #define VT1724_REVO_CS1 0x20 /* front AKM4381 chipselect */ | 48 | #define VT1724_REVO_CS1 0x20 /* front AKM4381 chipselect */ |
47 | #define VT1724_REVO_CS2 0x40 /* surround AKM4355 chipselect */ | 49 | #define VT1724_REVO_CS2 0x40 /* surround AKM4355 CS (revo71) */ |
50 | #define VT1724_REVO_I2C_DATA 0x40 /* I2C: PT 2258 SDA (on revo51) */ | ||
51 | #define VT1724_REVO_I2C_CLOCK 0x80 /* I2C: PT 2258 SCL (on revo51) */ | ||
52 | #define VT1724_REVO_CS3 0x80 /* AK4114 for AP192 */ | ||
48 | #define VT1724_REVO_MUTE (1<<22) /* 0 = all mute, 1 = normal operation */ | 53 | #define VT1724_REVO_MUTE (1<<22) /* 0 = all mute, 1 = normal operation */ |
49 | 54 | ||
50 | #endif /* __SOUND_REVO_H */ | 55 | #endif /* __SOUND_REVO_H */ |
diff --git a/sound/pci/ice1712/vt1720_mobo.c b/sound/pci/ice1712/vt1720_mobo.c index 7ca263c13091..72b060d63c29 100644 --- a/sound/pci/ice1712/vt1720_mobo.c +++ b/sound/pci/ice1712/vt1720_mobo.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <sound/core.h> | 30 | #include <sound/core.h> |
31 | 31 | ||
32 | #include "ice1712.h" | 32 | #include "ice1712.h" |
33 | #include "envy24ht.h" | ||
33 | #include "vt1720_mobo.h" | 34 | #include "vt1720_mobo.h" |
34 | 35 | ||
35 | 36 | ||
@@ -55,41 +56,41 @@ static int __devinit k8x800_add_controls(struct snd_ice1712 *ice) | |||
55 | 56 | ||
56 | /* EEPROM image */ | 57 | /* EEPROM image */ |
57 | 58 | ||
58 | static unsigned char k8x800_eeprom[] __devinitdata = { | 59 | static const unsigned char k8x800_eeprom[] __devinitdata = { |
59 | 0x01, /* SYSCONF: clock 256, 1ADC, 2DACs */ | 60 | [ICE_EEP2_SYSCONF] = 0x01, /* clock 256, 1ADC, 2DACs */ |
60 | 0x02, /* ACLINK: ACLINK, packed */ | 61 | [ICE_EEP2_ACLINK] = 0x02, /* ACLINK, packed */ |
61 | 0x00, /* I2S: - */ | 62 | [ICE_EEP2_I2S] = 0x00, /* - */ |
62 | 0x00, /* SPDIF: - */ | 63 | [ICE_EEP2_SPDIF] = 0x00, /* - */ |
63 | 0xff, /* GPIO_DIR */ | 64 | [ICE_EEP2_GPIO_DIR] = 0xff, |
64 | 0xff, /* GPIO_DIR1 */ | 65 | [ICE_EEP2_GPIO_DIR1] = 0xff, |
65 | 0x00, /* - */ | 66 | [ICE_EEP2_GPIO_DIR2] = 0x00, /* - */ |
66 | 0xff, /* GPIO_MASK */ | 67 | [ICE_EEP2_GPIO_MASK] = 0xff, |
67 | 0xff, /* GPIO_MASK1 */ | 68 | [ICE_EEP2_GPIO_MASK1] = 0xff, |
68 | 0x00, /* - */ | 69 | [ICE_EEP2_GPIO_MASK2] = 0x00, /* - */ |
69 | 0x00, /* GPIO_STATE */ | 70 | [ICE_EEP2_GPIO_STATE] = 0x00, |
70 | 0x00, /* GPIO_STATE1 */ | 71 | [ICE_EEP2_GPIO_STATE1] = 0x00, |
71 | 0x00, /* - */ | 72 | [ICE_EEP2_GPIO_STATE2] = 0x00, /* - */ |
72 | }; | 73 | }; |
73 | 74 | ||
74 | static unsigned char sn25p_eeprom[] __devinitdata = { | 75 | static const unsigned char sn25p_eeprom[] __devinitdata = { |
75 | 0x01, /* SYSCONF: clock 256, 1ADC, 2DACs */ | 76 | [ICE_EEP2_SYSCONF] = 0x01, /* clock 256, 1ADC, 2DACs */ |
76 | 0x02, /* ACLINK: ACLINK, packed */ | 77 | [ICE_EEP2_ACLINK] = 0x02, /* ACLINK, packed */ |
77 | 0x00, /* I2S: - */ | 78 | [ICE_EEP2_I2S] = 0x00, /* - */ |
78 | 0x41, /* SPDIF: - */ | 79 | [ICE_EEP2_SPDIF] = 0x41, /* - */ |
79 | 0xff, /* GPIO_DIR */ | 80 | [ICE_EEP2_GPIO_DIR] = 0xff, |
80 | 0xff, /* GPIO_DIR1 */ | 81 | [ICE_EEP2_GPIO_DIR1] = 0xff, |
81 | 0x00, /* - */ | 82 | [ICE_EEP2_GPIO_DIR2] = 0x00, /* - */ |
82 | 0xff, /* GPIO_MASK */ | 83 | [ICE_EEP2_GPIO_MASK] = 0xff, |
83 | 0xff, /* GPIO_MASK1 */ | 84 | [ICE_EEP2_GPIO_MASK1] = 0xff, |
84 | 0x00, /* - */ | 85 | [ICE_EEP2_GPIO_MASK2] = 0x00, /* - */ |
85 | 0x00, /* GPIO_STATE */ | 86 | [ICE_EEP2_GPIO_STATE] = 0x00, |
86 | 0x00, /* GPIO_STATE1 */ | 87 | [ICE_EEP2_GPIO_STATE1] = 0x00, |
87 | 0x00, /* - */ | 88 | [ICE_EEP2_GPIO_STATE2] = 0x00, /* - */ |
88 | }; | 89 | }; |
89 | 90 | ||
90 | 91 | ||
91 | /* entry point */ | 92 | /* entry point */ |
92 | struct snd_ice1712_card_info snd_vt1720_mobo_cards[] __devinitdata = { | 93 | const struct snd_ice1712_card_info snd_vt1720_mobo_cards[] __devinitdata = { |
93 | { | 94 | { |
94 | .subvendor = VT1720_SUBDEVICE_K8X800, | 95 | .subvendor = VT1720_SUBDEVICE_K8X800, |
95 | .name = "Albatron K8X800 Pro II", | 96 | .name = "Albatron K8X800 Pro II", |
diff --git a/sound/pci/ice1712/vt1720_mobo.h b/sound/pci/ice1712/vt1720_mobo.h index 0b1b0ee1bea7..70af3ad64a5d 100644 --- a/sound/pci/ice1712/vt1720_mobo.h +++ b/sound/pci/ice1712/vt1720_mobo.h | |||
@@ -36,6 +36,6 @@ | |||
36 | #define VT1720_SUBDEVICE_9CJS 0x0f272327 | 36 | #define VT1720_SUBDEVICE_9CJS 0x0f272327 |
37 | #define VT1720_SUBDEVICE_SN25P 0x97123650 | 37 | #define VT1720_SUBDEVICE_SN25P 0x97123650 |
38 | 38 | ||
39 | extern struct snd_ice1712_card_info snd_vt1720_mobo_cards[]; | 39 | extern const struct snd_ice1712_card_info snd_vt1720_mobo_cards[]; |
40 | 40 | ||
41 | #endif /* __SOUND_VT1720_MOBO_H */ | 41 | #endif /* __SOUND_VT1720_MOBO_H */ |
diff --git a/sound/pci/ice1712/wtm.c b/sound/pci/ice1712/wtm.c new file mode 100644 index 000000000000..4a706b16a0b9 --- /dev/null +++ b/sound/pci/ice1712/wtm.c | |||
@@ -0,0 +1,542 @@ | |||
1 | /* | ||
2 | * ALSA driver for ICEnsemble VT1724 (Envy24HT) | ||
3 | * | ||
4 | * Lowlevel functions for Ego Sys Waveterminal 192M | ||
5 | * | ||
6 | * Copyright (c) 2006 Guedez Clement <klem.dev@gmail.com> | ||
7 | * Some functions are taken from the Prodigy192 driver | ||
8 | * source | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | |||
27 | |||
28 | #include <sound/driver.h> | ||
29 | #include <asm/io.h> | ||
30 | #include <linux/delay.h> | ||
31 | #include <linux/interrupt.h> | ||
32 | #include <linux/init.h> | ||
33 | #include <linux/slab.h> | ||
34 | #include <sound/core.h> | ||
35 | |||
36 | #include "ice1712.h" | ||
37 | #include "envy24ht.h" | ||
38 | #include "wtm.h" | ||
39 | #include "stac946x.h" | ||
40 | |||
41 | |||
42 | /* | ||
43 | * 2*ADC 6*DAC no1 ringbuffer r/w on i2c bus | ||
44 | */ | ||
45 | static inline void stac9460_put(struct snd_ice1712 *ice, int reg, | ||
46 | unsigned char val) | ||
47 | { | ||
48 | snd_vt1724_write_i2c(ice, STAC9460_I2C_ADDR, reg, val); | ||
49 | } | ||
50 | |||
51 | static inline unsigned char stac9460_get(struct snd_ice1712 *ice, int reg) | ||
52 | { | ||
53 | return snd_vt1724_read_i2c(ice, STAC9460_I2C_ADDR, reg); | ||
54 | } | ||
55 | |||
56 | /* | ||
57 | * 2*ADC 2*DAC no2 ringbuffer r/w on i2c bus | ||
58 | */ | ||
59 | static inline void stac9460_2_put(struct snd_ice1712 *ice, int reg, | ||
60 | unsigned char val) | ||
61 | { | ||
62 | snd_vt1724_write_i2c(ice, STAC9460_2_I2C_ADDR, reg, val); | ||
63 | } | ||
64 | |||
65 | static inline unsigned char stac9460_2_get(struct snd_ice1712 *ice, int reg) | ||
66 | { | ||
67 | return snd_vt1724_read_i2c(ice, STAC9460_2_I2C_ADDR, reg); | ||
68 | } | ||
69 | |||
70 | |||
71 | /* | ||
72 | * DAC mute control | ||
73 | */ | ||
74 | static int stac9460_dac_mute_info(struct snd_kcontrol *kcontrol, | ||
75 | struct snd_ctl_elem_info *uinfo) | ||
76 | { | ||
77 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
78 | uinfo->count = 1; | ||
79 | uinfo->value.integer.min = 0; | ||
80 | return 0; | ||
81 | } | ||
82 | |||
83 | static int stac9460_dac_mute_get(struct snd_kcontrol *kcontrol, | ||
84 | struct snd_ctl_elem_value *ucontrol) | ||
85 | { | ||
86 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
87 | unsigned char val; | ||
88 | int idx, id; | ||
89 | |||
90 | if (kcontrol->private_value) { | ||
91 | idx = STAC946X_MASTER_VOLUME; | ||
92 | id = 0; | ||
93 | } else { | ||
94 | id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | ||
95 | idx = id + STAC946X_LF_VOLUME; | ||
96 | } | ||
97 | if (id < 6) | ||
98 | val = stac9460_get(ice, idx); | ||
99 | else | ||
100 | val = stac9460_2_get(ice,idx - 6); | ||
101 | ucontrol->value.integer.value[0] = (~val >> 7) & 0x1; | ||
102 | return 0; | ||
103 | } | ||
104 | |||
105 | static int stac9460_dac_mute_put(struct snd_kcontrol *kcontrol, | ||
106 | struct snd_ctl_elem_value *ucontrol) | ||
107 | { | ||
108 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
109 | unsigned char new, old; | ||
110 | int id, idx; | ||
111 | int change; | ||
112 | |||
113 | if (kcontrol->private_value) { | ||
114 | idx = STAC946X_MASTER_VOLUME; | ||
115 | old = stac9460_get(ice, idx); | ||
116 | new = (~ucontrol->value.integer.value[0]<< 7 & 0x80) | | ||
117 | (old & ~0x80); | ||
118 | change = (new != old); | ||
119 | if (change) { | ||
120 | stac9460_put(ice, idx, new); | ||
121 | stac9460_2_put(ice, idx, new); | ||
122 | } | ||
123 | } else { | ||
124 | id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | ||
125 | idx = id + STAC946X_LF_VOLUME; | ||
126 | if (id < 6) | ||
127 | old = stac9460_get(ice, idx); | ||
128 | else | ||
129 | old = stac9460_2_get(ice, idx - 6); | ||
130 | new = (~ucontrol->value.integer.value[0]<< 7 & 0x80) | | ||
131 | (old & ~0x80); | ||
132 | change = (new != old); | ||
133 | if (change) { | ||
134 | if (id < 6) | ||
135 | stac9460_put(ice, idx, new); | ||
136 | else | ||
137 | stac9460_2_put(ice, idx - 6, new); | ||
138 | } | ||
139 | } | ||
140 | return change; | ||
141 | } | ||
142 | |||
143 | /* | ||
144 | * DAC volume attenuation mixer control | ||
145 | */ | ||
146 | static int stac9460_dac_vol_info(struct snd_kcontrol *kcontrol, | ||
147 | struct snd_ctl_elem_info *uinfo) | ||
148 | { | ||
149 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
150 | uinfo->count = 1; | ||
151 | uinfo->value.integer.min = 0; /* mute */ | ||
152 | uinfo->value.integer.max = 0x7f; /* 0dB */ | ||
153 | return 0; | ||
154 | } | ||
155 | |||
156 | static int stac9460_dac_vol_get(struct snd_kcontrol *kcontrol, | ||
157 | struct snd_ctl_elem_value *ucontrol) | ||
158 | { | ||
159 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
160 | int idx, id; | ||
161 | unsigned char vol; | ||
162 | |||
163 | if (kcontrol->private_value) { | ||
164 | idx = STAC946X_MASTER_VOLUME; | ||
165 | id = 0; | ||
166 | } else { | ||
167 | id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | ||
168 | idx = id + STAC946X_LF_VOLUME; | ||
169 | } | ||
170 | if (id < 6) | ||
171 | vol = stac9460_get(ice, idx) & 0x7f; | ||
172 | else | ||
173 | vol = stac9460_2_get(ice, idx - 6) & 0x7f; | ||
174 | ucontrol->value.integer.value[0] = 0x7f - vol; | ||
175 | return 0; | ||
176 | } | ||
177 | |||
178 | static int stac9460_dac_vol_put(struct snd_kcontrol *kcontrol, | ||
179 | struct snd_ctl_elem_value *ucontrol) | ||
180 | { | ||
181 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
182 | int idx, id; | ||
183 | unsigned char tmp, ovol, nvol; | ||
184 | int change; | ||
185 | |||
186 | if (kcontrol->private_value) { | ||
187 | idx = STAC946X_MASTER_VOLUME; | ||
188 | nvol = ucontrol->value.integer.value[0]; | ||
189 | tmp = stac9460_get(ice, idx); | ||
190 | ovol = 0x7f - (tmp & 0x7f); | ||
191 | change = (ovol != nvol); | ||
192 | if (change) { | ||
193 | stac9460_put(ice, idx, (0x7f - nvol) | (tmp & 0x80)); | ||
194 | stac9460_2_put(ice, idx, (0x7f - nvol) | (tmp & 0x80)); | ||
195 | } | ||
196 | } else { | ||
197 | id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | ||
198 | idx = id + STAC946X_LF_VOLUME; | ||
199 | nvol = ucontrol->value.integer.value[0]; | ||
200 | if (id < 6) | ||
201 | tmp = stac9460_get(ice, idx); | ||
202 | else | ||
203 | tmp = stac9460_2_get(ice, idx - 6); | ||
204 | ovol = 0x7f - (tmp & 0x7f); | ||
205 | change = (ovol != nvol); | ||
206 | if (change) { | ||
207 | if (id < 6) | ||
208 | stac9460_put(ice, idx, (0x7f - nvol) | | ||
209 | (tmp & 0x80)); | ||
210 | else | ||
211 | stac9460_2_put(ice, idx-6, (0x7f - nvol) | | ||
212 | (tmp & 0x80)); | ||
213 | } | ||
214 | } | ||
215 | return change; | ||
216 | } | ||
217 | |||
218 | /* | ||
219 | * ADC mute control | ||
220 | */ | ||
221 | static int stac9460_adc_mute_info(struct snd_kcontrol *kcontrol, | ||
222 | struct snd_ctl_elem_info *uinfo) | ||
223 | { | ||
224 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
225 | uinfo->count = 2; | ||
226 | uinfo->value.integer.min = 0; | ||
227 | uinfo->value.integer.max = 1; | ||
228 | return 0; | ||
229 | } | ||
230 | |||
231 | static int stac9460_adc_mute_get(struct snd_kcontrol *kcontrol, | ||
232 | struct snd_ctl_elem_value *ucontrol) | ||
233 | { | ||
234 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
235 | unsigned char val; | ||
236 | int i, id; | ||
237 | |||
238 | id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | ||
239 | if (id == 0) { | ||
240 | for (i = 0; i < 2; ++i) { | ||
241 | val = stac9460_get(ice, STAC946X_MIC_L_VOLUME + i); | ||
242 | ucontrol->value.integer.value[i] = ~val>>7 & 0x1; | ||
243 | } | ||
244 | } else { | ||
245 | for (i = 0; i < 2; ++i) { | ||
246 | val = stac9460_2_get(ice, STAC946X_MIC_L_VOLUME + i); | ||
247 | ucontrol->value.integer.value[i] = ~val>>7 & 0x1; | ||
248 | } | ||
249 | } | ||
250 | return 0; | ||
251 | } | ||
252 | |||
253 | static int stac9460_adc_mute_put(struct snd_kcontrol *kcontrol, | ||
254 | struct snd_ctl_elem_value *ucontrol) | ||
255 | { | ||
256 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
257 | unsigned char new, old; | ||
258 | int i, reg, id; | ||
259 | int change; | ||
260 | |||
261 | id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | ||
262 | if (id == 0) { | ||
263 | for (i = 0; i < 2; ++i) { | ||
264 | reg = STAC946X_MIC_L_VOLUME + i; | ||
265 | old = stac9460_get(ice, reg); | ||
266 | new = (~ucontrol->value.integer.value[i]<<7&0x80) | | ||
267 | (old&~0x80); | ||
268 | change = (new != old); | ||
269 | if (change) | ||
270 | stac9460_put(ice, reg, new); | ||
271 | } | ||
272 | } else { | ||
273 | for (i = 0; i < 2; ++i) { | ||
274 | reg = STAC946X_MIC_L_VOLUME + i; | ||
275 | old = stac9460_2_get(ice, reg); | ||
276 | new = (~ucontrol->value.integer.value[i]<<7&0x80) | | ||
277 | (old&~0x80); | ||
278 | change = (new != old); | ||
279 | if (change) | ||
280 | stac9460_2_put(ice, reg, new); | ||
281 | } | ||
282 | } | ||
283 | return change; | ||
284 | } | ||
285 | |||
286 | /* | ||
287 | *ADC gain mixer control | ||
288 | */ | ||
289 | static int stac9460_adc_vol_info(struct snd_kcontrol *kcontrol, | ||
290 | struct snd_ctl_elem_info *uinfo) | ||
291 | { | ||
292 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
293 | uinfo->count = 2; | ||
294 | uinfo->value.integer.min = 0; /* 0dB */ | ||
295 | uinfo->value.integer.max = 0x0f; /* 22.5dB */ | ||
296 | return 0; | ||
297 | } | ||
298 | |||
299 | static int stac9460_adc_vol_get(struct snd_kcontrol *kcontrol, | ||
300 | struct snd_ctl_elem_value *ucontrol) | ||
301 | { | ||
302 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
303 | int i, reg, id; | ||
304 | unsigned char vol; | ||
305 | |||
306 | id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | ||
307 | if (id == 0) { | ||
308 | for (i = 0; i < 2; ++i) { | ||
309 | reg = STAC946X_MIC_L_VOLUME + i; | ||
310 | vol = stac9460_get(ice, reg) & 0x0f; | ||
311 | ucontrol->value.integer.value[i] = 0x0f - vol; | ||
312 | } | ||
313 | } else { | ||
314 | for (i = 0; i < 2; ++i) { | ||
315 | reg = STAC946X_MIC_L_VOLUME + i; | ||
316 | vol = stac9460_2_get(ice, reg) & 0x0f; | ||
317 | ucontrol->value.integer.value[i] = 0x0f - vol; | ||
318 | } | ||
319 | } | ||
320 | return 0; | ||
321 | } | ||
322 | |||
323 | static int stac9460_adc_vol_put(struct snd_kcontrol *kcontrol, | ||
324 | struct snd_ctl_elem_value *ucontrol) | ||
325 | { | ||
326 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
327 | int i, reg, id; | ||
328 | unsigned char ovol, nvol; | ||
329 | int change; | ||
330 | |||
331 | id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | ||
332 | if (id == 0) { | ||
333 | for (i = 0; i < 2; ++i) { | ||
334 | reg = STAC946X_MIC_L_VOLUME + i; | ||
335 | nvol = ucontrol->value.integer.value[i]; | ||
336 | ovol = 0x0f - stac9460_get(ice, reg); | ||
337 | change = ((ovol & 0x0f) != nvol); | ||
338 | if (change) | ||
339 | stac9460_put(ice, reg, (0x0f - nvol) | | ||
340 | (ovol & ~0x0f)); | ||
341 | } | ||
342 | } else { | ||
343 | for (i = 0; i < 2; ++i) { | ||
344 | reg = STAC946X_MIC_L_VOLUME + i; | ||
345 | nvol = ucontrol->value.integer.value[i]; | ||
346 | ovol = 0x0f - stac9460_2_get(ice, reg); | ||
347 | change = ((ovol & 0x0f) != nvol); | ||
348 | if (change) | ||
349 | stac9460_2_put(ice, reg, (0x0f - nvol) | | ||
350 | (ovol & ~0x0f)); | ||
351 | } | ||
352 | } | ||
353 | return change; | ||
354 | } | ||
355 | |||
356 | /* | ||
357 | * MIC / LINE switch fonction | ||
358 | */ | ||
359 | |||
360 | static int stac9460_mic_sw_info(struct snd_kcontrol *kcontrol, | ||
361 | struct snd_ctl_elem_info *uinfo) | ||
362 | { | ||
363 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
364 | uinfo->count = 1; | ||
365 | uinfo->value.integer.min = 0; | ||
366 | uinfo->value.integer.max = 1; | ||
367 | return 0; | ||
368 | } | ||
369 | |||
370 | static int stac9460_mic_sw_get(struct snd_kcontrol *kcontrol, | ||
371 | struct snd_ctl_elem_value *ucontrol) | ||
372 | { | ||
373 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
374 | unsigned char val; | ||
375 | int id; | ||
376 | |||
377 | id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | ||
378 | if (id == 0) | ||
379 | val = stac9460_get(ice, STAC946X_GENERAL_PURPOSE); | ||
380 | else | ||
381 | val = stac9460_2_get(ice, STAC946X_GENERAL_PURPOSE); | ||
382 | ucontrol->value.integer.value[0] = ~val>>7 & 0x1; | ||
383 | return 0; | ||
384 | } | ||
385 | |||
386 | static int stac9460_mic_sw_put(struct snd_kcontrol *kcontrol, | ||
387 | struct snd_ctl_elem_value *ucontrol) | ||
388 | { | ||
389 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
390 | unsigned char new, old; | ||
391 | int change, id; | ||
392 | |||
393 | id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | ||
394 | if (id == 0) | ||
395 | old = stac9460_get(ice, STAC946X_GENERAL_PURPOSE); | ||
396 | else | ||
397 | old = stac9460_2_get(ice, STAC946X_GENERAL_PURPOSE); | ||
398 | new = (~ucontrol->value.integer.value[0]<< 7 & 0x80) | (old & ~0x80); | ||
399 | change = (new != old); | ||
400 | if (change) { | ||
401 | if (id == 0) | ||
402 | stac9460_put(ice, STAC946X_GENERAL_PURPOSE, new); | ||
403 | else | ||
404 | stac9460_2_put(ice, STAC946X_GENERAL_PURPOSE, new); | ||
405 | } | ||
406 | return change; | ||
407 | } | ||
408 | |||
409 | /* | ||
410 | * Control tabs | ||
411 | */ | ||
412 | static const struct snd_kcontrol_new stac9640_controls[] __devinitdata = { | ||
413 | { | ||
414 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
415 | .name = "Master Playback Switch", | ||
416 | .info = stac9460_dac_mute_info, | ||
417 | .get = stac9460_dac_mute_get, | ||
418 | .put = stac9460_dac_mute_put, | ||
419 | .private_value = 1 | ||
420 | }, | ||
421 | { | ||
422 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
423 | .name = "Master Playback Volume", | ||
424 | .info = stac9460_dac_vol_info, | ||
425 | .get = stac9460_dac_vol_get, | ||
426 | .put = stac9460_dac_vol_put, | ||
427 | .private_value = 1, | ||
428 | }, | ||
429 | { | ||
430 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
431 | .name = "MIC/Line switch", | ||
432 | .count = 2, | ||
433 | .info = stac9460_mic_sw_info, | ||
434 | .get = stac9460_mic_sw_get, | ||
435 | .put = stac9460_mic_sw_put, | ||
436 | |||
437 | }, | ||
438 | { | ||
439 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
440 | .name = "DAC Switch", | ||
441 | .count = 8, | ||
442 | .info = stac9460_dac_mute_info, | ||
443 | .get = stac9460_dac_mute_get, | ||
444 | .put = stac9460_dac_mute_put, | ||
445 | }, | ||
446 | { | ||
447 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
448 | .name = "DAC Volume", | ||
449 | .count = 8, | ||
450 | .info = stac9460_dac_vol_info, | ||
451 | .get = stac9460_dac_vol_get, | ||
452 | .put = stac9460_dac_vol_put, | ||
453 | }, | ||
454 | { | ||
455 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
456 | .name = "ADC Switch", | ||
457 | .count = 2, | ||
458 | .info = stac9460_adc_mute_info, | ||
459 | .get = stac9460_adc_mute_get, | ||
460 | .put = stac9460_adc_mute_put, | ||
461 | }, | ||
462 | { | ||
463 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
464 | .name = "ADC Volume", | ||
465 | .count = 2, | ||
466 | .info = stac9460_adc_vol_info, | ||
467 | .get = stac9460_adc_vol_get, | ||
468 | .put = stac9460_adc_vol_put, | ||
469 | |||
470 | } | ||
471 | }; | ||
472 | |||
473 | |||
474 | |||
475 | /*INIT*/ | ||
476 | static int __devinit wtm_add_controls(struct snd_ice1712 *ice) | ||
477 | { | ||
478 | unsigned int i; | ||
479 | int err; | ||
480 | |||
481 | for (i = 0; i < ARRAY_SIZE(stac9640_controls); i++) { | ||
482 | err = snd_ctl_add(ice->card, | ||
483 | snd_ctl_new1(&stac9640_controls[i], ice)); | ||
484 | if (err < 0) | ||
485 | return err; | ||
486 | } | ||
487 | return 0; | ||
488 | } | ||
489 | |||
490 | static int __devinit wtm_init(struct snd_ice1712 *ice) | ||
491 | { | ||
492 | static unsigned short stac_inits_prodigy[] = { | ||
493 | STAC946X_RESET, 0, | ||
494 | (unsigned short)-1 | ||
495 | }; | ||
496 | unsigned short *p; | ||
497 | |||
498 | /*WTM 192M*/ | ||
499 | ice->num_total_dacs = 8; | ||
500 | ice->num_total_adcs = 4; | ||
501 | ice->force_rdma1 = 1; | ||
502 | |||
503 | /*initialize codec*/ | ||
504 | p = stac_inits_prodigy; | ||
505 | for (; *p != (unsigned short)-1; p += 2) { | ||
506 | stac9460_put(ice, p[0], p[1]); | ||
507 | stac9460_2_put(ice, p[0], p[1]); | ||
508 | } | ||
509 | return 0; | ||
510 | } | ||
511 | |||
512 | |||
513 | static unsigned char wtm_eeprom[] __devinitdata = { | ||
514 | 0x47, /*SYSCONF: clock 192KHz, 4ADC, 8DAC */ | ||
515 | 0x80, /* ACLINK : I2S */ | ||
516 | 0xf8, /* I2S: vol; 96k, 24bit, 192k */ | ||
517 | 0xc1 /*SPDIF: out-en, spidf ext out*/, | ||
518 | 0x9f, /* GPIO_DIR */ | ||
519 | 0xff, /* GPIO_DIR1 */ | ||
520 | 0x7f, /* GPIO_DIR2 */ | ||
521 | 0x9f, /* GPIO_MASK */ | ||
522 | 0xff, /* GPIO_MASK1 */ | ||
523 | 0x7f, /* GPIO_MASK2 */ | ||
524 | 0x16, /* GPIO_STATE */ | ||
525 | 0x80, /* GPIO_STATE1 */ | ||
526 | 0x00, /* GPIO_STATE2 */ | ||
527 | }; | ||
528 | |||
529 | |||
530 | /*entry point*/ | ||
531 | struct snd_ice1712_card_info snd_vt1724_wtm_cards[] __devinitdata = { | ||
532 | { | ||
533 | .subvendor = VT1724_SUBDEVICE_WTM, | ||
534 | .name = "ESI Waveterminal 192M", | ||
535 | .model = "WT192M", | ||
536 | .chip_init = wtm_init, | ||
537 | .build_controls = wtm_add_controls, | ||
538 | .eeprom_size = sizeof(wtm_eeprom), | ||
539 | .eeprom_data = wtm_eeprom, | ||
540 | }, | ||
541 | {} /*terminator*/ | ||
542 | }; | ||
diff --git a/sound/pci/ice1712/wtm.h b/sound/pci/ice1712/wtm.h new file mode 100644 index 000000000000..03a394e442f1 --- /dev/null +++ b/sound/pci/ice1712/wtm.h | |||
@@ -0,0 +1,20 @@ | |||
1 | #ifndef __SOUND_WTM_H | ||
2 | #define __SOUND_WTM_H | ||
3 | |||
4 | /* ID */ | ||
5 | #define WTM_DEVICE_DESC "{EGO SYS INC,WaveTerminal 192M}," | ||
6 | #define VT1724_SUBDEVICE_WTM 0x36495345 /* WT192M ver1.0 */ | ||
7 | |||
8 | /* | ||
9 | *chip addresses on I2C bus | ||
10 | */ | ||
11 | |||
12 | #define AK4114_ADDR 0x20 /*S/PDIF receiver*/ | ||
13 | #define STAC9460_I2C_ADDR 0x54 /* ADC*2 | DAC*6 */ | ||
14 | #define STAC9460_2_I2C_ADDR 0x56 /* ADC|DAC *2 */ | ||
15 | |||
16 | |||
17 | extern struct snd_ice1712_card_info snd_vt1724_wtm_cards[]; | ||
18 | |||
19 | #endif /* __SOUND_WTM_H */ | ||
20 | |||
diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 30aaa6092a84..a289abfc7172 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c | |||
@@ -71,6 +71,7 @@ static char *ac97_quirk; | |||
71 | static int buggy_semaphore; | 71 | static int buggy_semaphore; |
72 | static int buggy_irq = -1; /* auto-check */ | 72 | static int buggy_irq = -1; /* auto-check */ |
73 | static int xbox; | 73 | static int xbox; |
74 | static int spdif_aclink = -1; | ||
74 | 75 | ||
75 | module_param(index, int, 0444); | 76 | module_param(index, int, 0444); |
76 | MODULE_PARM_DESC(index, "Index value for Intel i8x0 soundcard."); | 77 | MODULE_PARM_DESC(index, "Index value for Intel i8x0 soundcard."); |
@@ -86,6 +87,8 @@ module_param(buggy_irq, bool, 0444); | |||
86 | MODULE_PARM_DESC(buggy_irq, "Enable workaround for buggy interrupts on some motherboards."); | 87 | MODULE_PARM_DESC(buggy_irq, "Enable workaround for buggy interrupts on some motherboards."); |
87 | module_param(xbox, bool, 0444); | 88 | module_param(xbox, bool, 0444); |
88 | MODULE_PARM_DESC(xbox, "Set to 1 for Xbox, if you have problems with the AC'97 codec detection."); | 89 | MODULE_PARM_DESC(xbox, "Set to 1 for Xbox, if you have problems with the AC'97 codec detection."); |
90 | module_param(spdif_aclink, int, 0444); | ||
91 | MODULE_PARM_DESC(spdif_aclink, "S/PDIF over AC-link."); | ||
89 | 92 | ||
90 | /* just for backward compatibility */ | 93 | /* just for backward compatibility */ |
91 | static int enable; | 94 | static int enable; |
@@ -368,12 +371,8 @@ struct intel8x0 { | |||
368 | 371 | ||
369 | int irq; | 372 | int irq; |
370 | 373 | ||
371 | unsigned int mmio; | 374 | void __iomem *addr; |
372 | unsigned long addr; | 375 | void __iomem *bmaddr; |
373 | void __iomem *remap_addr; | ||
374 | unsigned int bm_mmio; | ||
375 | unsigned long bmaddr; | ||
376 | void __iomem *remap_bmaddr; | ||
377 | 376 | ||
378 | struct pci_dev *pci; | 377 | struct pci_dev *pci; |
379 | struct snd_card *card; | 378 | struct snd_card *card; |
@@ -446,72 +445,48 @@ MODULE_DEVICE_TABLE(pci, snd_intel8x0_ids); | |||
446 | * Lowlevel I/O - busmaster | 445 | * Lowlevel I/O - busmaster |
447 | */ | 446 | */ |
448 | 447 | ||
449 | static u8 igetbyte(struct intel8x0 *chip, u32 offset) | 448 | static inline u8 igetbyte(struct intel8x0 *chip, u32 offset) |
450 | { | 449 | { |
451 | if (chip->bm_mmio) | 450 | return ioread8(chip->bmaddr + offset); |
452 | return readb(chip->remap_bmaddr + offset); | ||
453 | else | ||
454 | return inb(chip->bmaddr + offset); | ||
455 | } | 451 | } |
456 | 452 | ||
457 | static u16 igetword(struct intel8x0 *chip, u32 offset) | 453 | static inline u16 igetword(struct intel8x0 *chip, u32 offset) |
458 | { | 454 | { |
459 | if (chip->bm_mmio) | 455 | return ioread16(chip->bmaddr + offset); |
460 | return readw(chip->remap_bmaddr + offset); | ||
461 | else | ||
462 | return inw(chip->bmaddr + offset); | ||
463 | } | 456 | } |
464 | 457 | ||
465 | static u32 igetdword(struct intel8x0 *chip, u32 offset) | 458 | static inline u32 igetdword(struct intel8x0 *chip, u32 offset) |
466 | { | 459 | { |
467 | if (chip->bm_mmio) | 460 | return ioread32(chip->bmaddr + offset); |
468 | return readl(chip->remap_bmaddr + offset); | ||
469 | else | ||
470 | return inl(chip->bmaddr + offset); | ||
471 | } | 461 | } |
472 | 462 | ||
473 | static void iputbyte(struct intel8x0 *chip, u32 offset, u8 val) | 463 | static inline void iputbyte(struct intel8x0 *chip, u32 offset, u8 val) |
474 | { | 464 | { |
475 | if (chip->bm_mmio) | 465 | iowrite8(val, chip->bmaddr + offset); |
476 | writeb(val, chip->remap_bmaddr + offset); | ||
477 | else | ||
478 | outb(val, chip->bmaddr + offset); | ||
479 | } | 466 | } |
480 | 467 | ||
481 | static void iputword(struct intel8x0 *chip, u32 offset, u16 val) | 468 | static inline void iputword(struct intel8x0 *chip, u32 offset, u16 val) |
482 | { | 469 | { |
483 | if (chip->bm_mmio) | 470 | iowrite16(val, chip->bmaddr + offset); |
484 | writew(val, chip->remap_bmaddr + offset); | ||
485 | else | ||
486 | outw(val, chip->bmaddr + offset); | ||
487 | } | 471 | } |
488 | 472 | ||
489 | static void iputdword(struct intel8x0 *chip, u32 offset, u32 val) | 473 | static inline void iputdword(struct intel8x0 *chip, u32 offset, u32 val) |
490 | { | 474 | { |
491 | if (chip->bm_mmio) | 475 | iowrite32(val, chip->bmaddr + offset); |
492 | writel(val, chip->remap_bmaddr + offset); | ||
493 | else | ||
494 | outl(val, chip->bmaddr + offset); | ||
495 | } | 476 | } |
496 | 477 | ||
497 | /* | 478 | /* |
498 | * Lowlevel I/O - AC'97 registers | 479 | * Lowlevel I/O - AC'97 registers |
499 | */ | 480 | */ |
500 | 481 | ||
501 | static u16 iagetword(struct intel8x0 *chip, u32 offset) | 482 | static inline u16 iagetword(struct intel8x0 *chip, u32 offset) |
502 | { | 483 | { |
503 | if (chip->mmio) | 484 | return ioread16(chip->addr + offset); |
504 | return readw(chip->remap_addr + offset); | ||
505 | else | ||
506 | return inw(chip->addr + offset); | ||
507 | } | 485 | } |
508 | 486 | ||
509 | static void iaputword(struct intel8x0 *chip, u32 offset, u16 val) | 487 | static inline void iaputword(struct intel8x0 *chip, u32 offset, u16 val) |
510 | { | 488 | { |
511 | if (chip->mmio) | 489 | iowrite16(val, chip->addr + offset); |
512 | writew(val, chip->remap_addr + offset); | ||
513 | else | ||
514 | outw(val, chip->addr + offset); | ||
515 | } | 490 | } |
516 | 491 | ||
517 | /* | 492 | /* |
@@ -1606,10 +1581,14 @@ static int __devinit snd_intel8x0_pcm(struct intel8x0 *chip) | |||
1606 | case DEVICE_INTEL_ICH4: | 1581 | case DEVICE_INTEL_ICH4: |
1607 | tbl = intel_pcms; | 1582 | tbl = intel_pcms; |
1608 | tblsize = ARRAY_SIZE(intel_pcms); | 1583 | tblsize = ARRAY_SIZE(intel_pcms); |
1584 | if (spdif_aclink) | ||
1585 | tblsize--; | ||
1609 | break; | 1586 | break; |
1610 | case DEVICE_NFORCE: | 1587 | case DEVICE_NFORCE: |
1611 | tbl = nforce_pcms; | 1588 | tbl = nforce_pcms; |
1612 | tblsize = ARRAY_SIZE(nforce_pcms); | 1589 | tblsize = ARRAY_SIZE(nforce_pcms); |
1590 | if (spdif_aclink) | ||
1591 | tblsize--; | ||
1613 | break; | 1592 | break; |
1614 | case DEVICE_ALI: | 1593 | case DEVICE_ALI: |
1615 | tbl = ali_pcms; | 1594 | tbl = ali_pcms; |
@@ -2068,24 +2047,26 @@ static int __devinit snd_intel8x0_mixer(struct intel8x0 *chip, int ac97_clock, | |||
2068 | }; | 2047 | }; |
2069 | 2048 | ||
2070 | chip->spdif_idx = -1; /* use PCMOUT (or disabled) */ | 2049 | chip->spdif_idx = -1; /* use PCMOUT (or disabled) */ |
2071 | switch (chip->device_type) { | 2050 | if (!spdif_aclink) { |
2072 | case DEVICE_NFORCE: | 2051 | switch (chip->device_type) { |
2073 | chip->spdif_idx = NVD_SPBAR; | 2052 | case DEVICE_NFORCE: |
2074 | break; | 2053 | chip->spdif_idx = NVD_SPBAR; |
2075 | case DEVICE_ALI: | 2054 | break; |
2076 | chip->spdif_idx = ALID_AC97SPDIFOUT; | 2055 | case DEVICE_ALI: |
2077 | break; | 2056 | chip->spdif_idx = ALID_AC97SPDIFOUT; |
2078 | case DEVICE_INTEL_ICH4: | 2057 | break; |
2079 | chip->spdif_idx = ICHD_SPBAR; | 2058 | case DEVICE_INTEL_ICH4: |
2080 | break; | 2059 | chip->spdif_idx = ICHD_SPBAR; |
2081 | }; | 2060 | break; |
2061 | }; | ||
2062 | } | ||
2082 | 2063 | ||
2083 | chip->in_ac97_init = 1; | 2064 | chip->in_ac97_init = 1; |
2084 | 2065 | ||
2085 | memset(&ac97, 0, sizeof(ac97)); | 2066 | memset(&ac97, 0, sizeof(ac97)); |
2086 | ac97.private_data = chip; | 2067 | ac97.private_data = chip; |
2087 | ac97.private_free = snd_intel8x0_mixer_free_ac97; | 2068 | ac97.private_free = snd_intel8x0_mixer_free_ac97; |
2088 | ac97.scaps = AC97_SCAP_SKIP_MODEM; | 2069 | ac97.scaps = AC97_SCAP_SKIP_MODEM | AC97_SCAP_POWER_SAVE; |
2089 | if (chip->xbox) | 2070 | if (chip->xbox) |
2090 | ac97.scaps |= AC97_SCAP_DETECT_BY_VENDOR; | 2071 | ac97.scaps |= AC97_SCAP_DETECT_BY_VENDOR; |
2091 | if (chip->device_type != DEVICE_ALI) { | 2072 | if (chip->device_type != DEVICE_ALI) { |
@@ -2201,11 +2182,11 @@ static int __devinit snd_intel8x0_mixer(struct intel8x0 *chip, int ac97_clock, | |||
2201 | if ((igetdword(chip, ICHREG(GLOB_STA)) & ICH_SAMPLE_CAP) == ICH_SAMPLE_16_20) | 2182 | if ((igetdword(chip, ICHREG(GLOB_STA)) & ICH_SAMPLE_CAP) == ICH_SAMPLE_16_20) |
2202 | chip->smp20bit = 1; | 2183 | chip->smp20bit = 1; |
2203 | } | 2184 | } |
2204 | if (chip->device_type == DEVICE_NFORCE) { | 2185 | if (chip->device_type == DEVICE_NFORCE && !spdif_aclink) { |
2205 | /* 48kHz only */ | 2186 | /* 48kHz only */ |
2206 | chip->ichd[chip->spdif_idx].pcm->rates = SNDRV_PCM_RATE_48000; | 2187 | chip->ichd[chip->spdif_idx].pcm->rates = SNDRV_PCM_RATE_48000; |
2207 | } | 2188 | } |
2208 | if (chip->device_type == DEVICE_INTEL_ICH4) { | 2189 | if (chip->device_type == DEVICE_INTEL_ICH4 && !spdif_aclink) { |
2209 | /* use slot 10/11 for SPDIF */ | 2190 | /* use slot 10/11 for SPDIF */ |
2210 | u32 val; | 2191 | u32 val; |
2211 | val = igetdword(chip, ICHREG(GLOB_CNT)) & ~ICH_PCM_SPDIF_MASK; | 2192 | val = igetdword(chip, ICHREG(GLOB_CNT)) & ~ICH_PCM_SPDIF_MASK; |
@@ -2333,7 +2314,7 @@ static int snd_intel8x0_ich_chip_init(struct intel8x0 *chip, int probing) | |||
2333 | /* unmute the output on SIS7012 */ | 2314 | /* unmute the output on SIS7012 */ |
2334 | iputword(chip, 0x4c, igetword(chip, 0x4c) | 1); | 2315 | iputword(chip, 0x4c, igetword(chip, 0x4c) | 1); |
2335 | } | 2316 | } |
2336 | if (chip->device_type == DEVICE_NFORCE) { | 2317 | if (chip->device_type == DEVICE_NFORCE && !spdif_aclink) { |
2337 | /* enable SPDIF interrupt */ | 2318 | /* enable SPDIF interrupt */ |
2338 | unsigned int val; | 2319 | unsigned int val; |
2339 | pci_read_config_dword(chip->pci, 0x4c, &val); | 2320 | pci_read_config_dword(chip->pci, 0x4c, &val); |
@@ -2426,7 +2407,7 @@ static int snd_intel8x0_free(struct intel8x0 *chip) | |||
2426 | /* reset channels */ | 2407 | /* reset channels */ |
2427 | for (i = 0; i < chip->bdbars_count; i++) | 2408 | for (i = 0; i < chip->bdbars_count; i++) |
2428 | iputbyte(chip, ICH_REG_OFF_CR + chip->ichd[i].reg_offset, ICH_RESETREGS); | 2409 | iputbyte(chip, ICH_REG_OFF_CR + chip->ichd[i].reg_offset, ICH_RESETREGS); |
2429 | if (chip->device_type == DEVICE_NFORCE) { | 2410 | if (chip->device_type == DEVICE_NFORCE && !spdif_aclink) { |
2430 | /* stop the spdif interrupt */ | 2411 | /* stop the spdif interrupt */ |
2431 | unsigned int val; | 2412 | unsigned int val; |
2432 | pci_read_config_dword(chip->pci, 0x4c, &val); | 2413 | pci_read_config_dword(chip->pci, 0x4c, &val); |
@@ -2443,10 +2424,10 @@ static int snd_intel8x0_free(struct intel8x0 *chip) | |||
2443 | fill_nocache(chip->bdbars.area, chip->bdbars.bytes, 0); | 2424 | fill_nocache(chip->bdbars.area, chip->bdbars.bytes, 0); |
2444 | snd_dma_free_pages(&chip->bdbars); | 2425 | snd_dma_free_pages(&chip->bdbars); |
2445 | } | 2426 | } |
2446 | if (chip->remap_addr) | 2427 | if (chip->addr) |
2447 | iounmap(chip->remap_addr); | 2428 | pci_iounmap(chip->pci, chip->addr); |
2448 | if (chip->remap_bmaddr) | 2429 | if (chip->bmaddr) |
2449 | iounmap(chip->remap_bmaddr); | 2430 | pci_iounmap(chip->pci, chip->bmaddr); |
2450 | pci_release_regions(chip->pci); | 2431 | pci_release_regions(chip->pci); |
2451 | pci_disable_device(chip->pci); | 2432 | pci_disable_device(chip->pci); |
2452 | kfree(chip); | 2433 | kfree(chip); |
@@ -2520,7 +2501,7 @@ static int intel8x0_resume(struct pci_dev *pci) | |||
2520 | snd_intel8x0_chip_init(chip, 0); | 2501 | snd_intel8x0_chip_init(chip, 0); |
2521 | 2502 | ||
2522 | /* re-initialize mixer stuff */ | 2503 | /* re-initialize mixer stuff */ |
2523 | if (chip->device_type == DEVICE_INTEL_ICH4) { | 2504 | if (chip->device_type == DEVICE_INTEL_ICH4 && !spdif_aclink) { |
2524 | /* enable separate SDINs for ICH4 */ | 2505 | /* enable separate SDINs for ICH4 */ |
2525 | iputbyte(chip, ICHREG(SDM), chip->sdm_saved); | 2506 | iputbyte(chip, ICHREG(SDM), chip->sdm_saved); |
2526 | /* use slot 10/11 for SPDIF */ | 2507 | /* use slot 10/11 for SPDIF */ |
@@ -2793,35 +2774,27 @@ static int __devinit snd_intel8x0_create(struct snd_card *card, | |||
2793 | 2774 | ||
2794 | if (device_type == DEVICE_ALI) { | 2775 | if (device_type == DEVICE_ALI) { |
2795 | /* ALI5455 has no ac97 region */ | 2776 | /* ALI5455 has no ac97 region */ |
2796 | chip->bmaddr = pci_resource_start(pci, 0); | 2777 | chip->bmaddr = pci_iomap(pci, 0, 0); |
2797 | goto port_inited; | 2778 | goto port_inited; |
2798 | } | 2779 | } |
2799 | 2780 | ||
2800 | if (pci_resource_flags(pci, 2) & IORESOURCE_MEM) { /* ICH4 and Nforce */ | 2781 | if (pci_resource_flags(pci, 2) & IORESOURCE_MEM) /* ICH4 and Nforce */ |
2801 | chip->mmio = 1; | 2782 | chip->addr = pci_iomap(pci, 2, 0); |
2802 | chip->addr = pci_resource_start(pci, 2); | 2783 | else |
2803 | chip->remap_addr = ioremap_nocache(chip->addr, | 2784 | chip->addr = pci_iomap(pci, 0, 0); |
2804 | pci_resource_len(pci, 2)); | 2785 | if (!chip->addr) { |
2805 | if (chip->remap_addr == NULL) { | 2786 | snd_printk(KERN_ERR "AC'97 space ioremap problem\n"); |
2806 | snd_printk(KERN_ERR "AC'97 space ioremap problem\n"); | 2787 | snd_intel8x0_free(chip); |
2807 | snd_intel8x0_free(chip); | 2788 | return -EIO; |
2808 | return -EIO; | 2789 | } |
2809 | } | 2790 | if (pci_resource_flags(pci, 3) & IORESOURCE_MEM) /* ICH4 */ |
2810 | } else { | 2791 | chip->bmaddr = pci_iomap(pci, 3, 0); |
2811 | chip->addr = pci_resource_start(pci, 0); | 2792 | else |
2812 | } | 2793 | chip->bmaddr = pci_iomap(pci, 1, 0); |
2813 | if (pci_resource_flags(pci, 3) & IORESOURCE_MEM) { /* ICH4 */ | 2794 | if (!chip->bmaddr) { |
2814 | chip->bm_mmio = 1; | 2795 | snd_printk(KERN_ERR "Controller space ioremap problem\n"); |
2815 | chip->bmaddr = pci_resource_start(pci, 3); | 2796 | snd_intel8x0_free(chip); |
2816 | chip->remap_bmaddr = ioremap_nocache(chip->bmaddr, | 2797 | return -EIO; |
2817 | pci_resource_len(pci, 3)); | ||
2818 | if (chip->remap_bmaddr == NULL) { | ||
2819 | snd_printk(KERN_ERR "Controller space ioremap problem\n"); | ||
2820 | snd_intel8x0_free(chip); | ||
2821 | return -EIO; | ||
2822 | } | ||
2823 | } else { | ||
2824 | chip->bmaddr = pci_resource_start(pci, 1); | ||
2825 | } | 2798 | } |
2826 | 2799 | ||
2827 | port_inited: | 2800 | port_inited: |
@@ -2964,6 +2937,29 @@ static struct shortname_table { | |||
2964 | { 0, NULL }, | 2937 | { 0, NULL }, |
2965 | }; | 2938 | }; |
2966 | 2939 | ||
2940 | static struct snd_pci_quirk spdif_aclink_defaults[] __devinitdata = { | ||
2941 | SND_PCI_QUIRK(0x147b, 0x1c1a, "ASUS KN8", 1), | ||
2942 | { } /* end */ | ||
2943 | }; | ||
2944 | |||
2945 | /* look up white/black list for SPDIF over ac-link */ | ||
2946 | static int __devinit check_default_spdif_aclink(struct pci_dev *pci) | ||
2947 | { | ||
2948 | const struct snd_pci_quirk *w; | ||
2949 | |||
2950 | w = snd_pci_quirk_lookup(pci, spdif_aclink_defaults); | ||
2951 | if (w) { | ||
2952 | if (w->value) | ||
2953 | snd_printdd(KERN_INFO "intel8x0: Using SPDIF over " | ||
2954 | "AC-Link for %s\n", w->name); | ||
2955 | else | ||
2956 | snd_printdd(KERN_INFO "intel8x0: Using integrated " | ||
2957 | "SPDIF DMA for %s\n", w->name); | ||
2958 | return w->value; | ||
2959 | } | ||
2960 | return 0; | ||
2961 | } | ||
2962 | |||
2967 | static int __devinit snd_intel8x0_probe(struct pci_dev *pci, | 2963 | static int __devinit snd_intel8x0_probe(struct pci_dev *pci, |
2968 | const struct pci_device_id *pci_id) | 2964 | const struct pci_device_id *pci_id) |
2969 | { | 2965 | { |
@@ -2976,16 +2972,18 @@ static int __devinit snd_intel8x0_probe(struct pci_dev *pci, | |||
2976 | if (card == NULL) | 2972 | if (card == NULL) |
2977 | return -ENOMEM; | 2973 | return -ENOMEM; |
2978 | 2974 | ||
2979 | switch (pci_id->driver_data) { | 2975 | if (spdif_aclink < 0) |
2980 | case DEVICE_NFORCE: | 2976 | spdif_aclink = check_default_spdif_aclink(pci); |
2981 | strcpy(card->driver, "NFORCE"); | 2977 | |
2982 | break; | 2978 | strcpy(card->driver, "ICH"); |
2983 | case DEVICE_INTEL_ICH4: | 2979 | if (!spdif_aclink) { |
2984 | strcpy(card->driver, "ICH4"); | 2980 | switch (pci_id->driver_data) { |
2985 | break; | 2981 | case DEVICE_NFORCE: |
2986 | default: | 2982 | strcpy(card->driver, "NFORCE"); |
2987 | strcpy(card->driver, "ICH"); | 2983 | break; |
2988 | break; | 2984 | case DEVICE_INTEL_ICH4: |
2985 | strcpy(card->driver, "ICH4"); | ||
2986 | } | ||
2989 | } | 2987 | } |
2990 | 2988 | ||
2991 | strcpy(card->shortname, "Intel ICH"); | 2989 | strcpy(card->shortname, "Intel ICH"); |
@@ -3025,8 +3023,8 @@ static int __devinit snd_intel8x0_probe(struct pci_dev *pci, | |||
3025 | snd_intel8x0_proc_init(chip); | 3023 | snd_intel8x0_proc_init(chip); |
3026 | 3024 | ||
3027 | snprintf(card->longname, sizeof(card->longname), | 3025 | snprintf(card->longname, sizeof(card->longname), |
3028 | "%s with %s at %#lx, irq %i", card->shortname, | 3026 | "%s with %s at irq %i", card->shortname, |
3029 | snd_ac97_get_short_name(chip->ac97[0]), chip->addr, chip->irq); | 3027 | snd_ac97_get_short_name(chip->ac97[0]), chip->irq); |
3030 | 3028 | ||
3031 | if (! ac97_clock) | 3029 | if (! ac97_clock) |
3032 | intel8x0_measure_ac97_clock(chip); | 3030 | intel8x0_measure_ac97_clock(chip); |
diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c index 09dcf923b547..c155e1f3a0e5 100644 --- a/sound/pci/intel8x0m.c +++ b/sound/pci/intel8x0m.c | |||
@@ -196,12 +196,8 @@ struct intel8x0m { | |||
196 | 196 | ||
197 | int irq; | 197 | int irq; |
198 | 198 | ||
199 | unsigned int mmio; | 199 | void __iomem *addr; |
200 | unsigned long addr; | 200 | void __iomem *bmaddr; |
201 | void __iomem *remap_addr; | ||
202 | unsigned int bm_mmio; | ||
203 | unsigned long bmaddr; | ||
204 | void __iomem *remap_bmaddr; | ||
205 | 201 | ||
206 | struct pci_dev *pci; | 202 | struct pci_dev *pci; |
207 | struct snd_card *card; | 203 | struct snd_card *card; |
@@ -253,72 +249,48 @@ MODULE_DEVICE_TABLE(pci, snd_intel8x0m_ids); | |||
253 | * Lowlevel I/O - busmaster | 249 | * Lowlevel I/O - busmaster |
254 | */ | 250 | */ |
255 | 251 | ||
256 | static u8 igetbyte(struct intel8x0m *chip, u32 offset) | 252 | static inline u8 igetbyte(struct intel8x0m *chip, u32 offset) |
257 | { | 253 | { |
258 | if (chip->bm_mmio) | 254 | return ioread8(chip->bmaddr + offset); |
259 | return readb(chip->remap_bmaddr + offset); | ||
260 | else | ||
261 | return inb(chip->bmaddr + offset); | ||
262 | } | 255 | } |
263 | 256 | ||
264 | static u16 igetword(struct intel8x0m *chip, u32 offset) | 257 | static inline u16 igetword(struct intel8x0m *chip, u32 offset) |
265 | { | 258 | { |
266 | if (chip->bm_mmio) | 259 | return ioread16(chip->bmaddr + offset); |
267 | return readw(chip->remap_bmaddr + offset); | ||
268 | else | ||
269 | return inw(chip->bmaddr + offset); | ||
270 | } | 260 | } |
271 | 261 | ||
272 | static u32 igetdword(struct intel8x0m *chip, u32 offset) | 262 | static inline u32 igetdword(struct intel8x0m *chip, u32 offset) |
273 | { | 263 | { |
274 | if (chip->bm_mmio) | 264 | return ioread32(chip->bmaddr + offset); |
275 | return readl(chip->remap_bmaddr + offset); | ||
276 | else | ||
277 | return inl(chip->bmaddr + offset); | ||
278 | } | 265 | } |
279 | 266 | ||
280 | static void iputbyte(struct intel8x0m *chip, u32 offset, u8 val) | 267 | static inline void iputbyte(struct intel8x0m *chip, u32 offset, u8 val) |
281 | { | 268 | { |
282 | if (chip->bm_mmio) | 269 | iowrite8(val, chip->bmaddr + offset); |
283 | writeb(val, chip->remap_bmaddr + offset); | ||
284 | else | ||
285 | outb(val, chip->bmaddr + offset); | ||
286 | } | 270 | } |
287 | 271 | ||
288 | static void iputword(struct intel8x0m *chip, u32 offset, u16 val) | 272 | static inline void iputword(struct intel8x0m *chip, u32 offset, u16 val) |
289 | { | 273 | { |
290 | if (chip->bm_mmio) | 274 | iowrite16(val, chip->bmaddr + offset); |
291 | writew(val, chip->remap_bmaddr + offset); | ||
292 | else | ||
293 | outw(val, chip->bmaddr + offset); | ||
294 | } | 275 | } |
295 | 276 | ||
296 | static void iputdword(struct intel8x0m *chip, u32 offset, u32 val) | 277 | static inline void iputdword(struct intel8x0m *chip, u32 offset, u32 val) |
297 | { | 278 | { |
298 | if (chip->bm_mmio) | 279 | iowrite32(val, chip->bmaddr + offset); |
299 | writel(val, chip->remap_bmaddr + offset); | ||
300 | else | ||
301 | outl(val, chip->bmaddr + offset); | ||
302 | } | 280 | } |
303 | 281 | ||
304 | /* | 282 | /* |
305 | * Lowlevel I/O - AC'97 registers | 283 | * Lowlevel I/O - AC'97 registers |
306 | */ | 284 | */ |
307 | 285 | ||
308 | static u16 iagetword(struct intel8x0m *chip, u32 offset) | 286 | static inline u16 iagetword(struct intel8x0m *chip, u32 offset) |
309 | { | 287 | { |
310 | if (chip->mmio) | 288 | return ioread16(chip->addr + offset); |
311 | return readw(chip->remap_addr + offset); | ||
312 | else | ||
313 | return inw(chip->addr + offset); | ||
314 | } | 289 | } |
315 | 290 | ||
316 | static void iaputword(struct intel8x0m *chip, u32 offset, u16 val) | 291 | static inline void iaputword(struct intel8x0m *chip, u32 offset, u16 val) |
317 | { | 292 | { |
318 | if (chip->mmio) | 293 | iowrite16(val, chip->addr + offset); |
319 | writew(val, chip->remap_addr + offset); | ||
320 | else | ||
321 | outw(val, chip->addr + offset); | ||
322 | } | 294 | } |
323 | 295 | ||
324 | /* | 296 | /* |
@@ -858,7 +830,7 @@ static int __devinit snd_intel8x0_mixer(struct intel8x0m *chip, int ac97_clock) | |||
858 | memset(&ac97, 0, sizeof(ac97)); | 830 | memset(&ac97, 0, sizeof(ac97)); |
859 | ac97.private_data = chip; | 831 | ac97.private_data = chip; |
860 | ac97.private_free = snd_intel8x0_mixer_free_ac97; | 832 | ac97.private_free = snd_intel8x0_mixer_free_ac97; |
861 | ac97.scaps = AC97_SCAP_SKIP_AUDIO; | 833 | ac97.scaps = AC97_SCAP_SKIP_AUDIO | AC97_SCAP_POWER_SAVE; |
862 | 834 | ||
863 | glob_sta = igetdword(chip, ICHREG(GLOB_STA)); | 835 | glob_sta = igetdword(chip, ICHREG(GLOB_STA)); |
864 | 836 | ||
@@ -1019,10 +991,10 @@ static int snd_intel8x0_free(struct intel8x0m *chip) | |||
1019 | __hw_end: | 991 | __hw_end: |
1020 | if (chip->bdbars.area) | 992 | if (chip->bdbars.area) |
1021 | snd_dma_free_pages(&chip->bdbars); | 993 | snd_dma_free_pages(&chip->bdbars); |
1022 | if (chip->remap_addr) | 994 | if (chip->addr) |
1023 | iounmap(chip->remap_addr); | 995 | pci_iounmap(chip->pci, chip->addr); |
1024 | if (chip->remap_bmaddr) | 996 | if (chip->bmaddr) |
1025 | iounmap(chip->remap_bmaddr); | 997 | pci_iounmap(chip->pci, chip->bmaddr); |
1026 | if (chip->irq >= 0) | 998 | if (chip->irq >= 0) |
1027 | free_irq(chip->irq, chip); | 999 | free_irq(chip->irq, chip); |
1028 | pci_release_regions(chip->pci); | 1000 | pci_release_regions(chip->pci); |
@@ -1173,35 +1145,27 @@ static int __devinit snd_intel8x0m_create(struct snd_card *card, | |||
1173 | 1145 | ||
1174 | if (device_type == DEVICE_ALI) { | 1146 | if (device_type == DEVICE_ALI) { |
1175 | /* ALI5455 has no ac97 region */ | 1147 | /* ALI5455 has no ac97 region */ |
1176 | chip->bmaddr = pci_resource_start(pci, 0); | 1148 | chip->bmaddr = pci_iomap(pci, 0, 0); |
1177 | goto port_inited; | 1149 | goto port_inited; |
1178 | } | 1150 | } |
1179 | 1151 | ||
1180 | if (pci_resource_flags(pci, 2) & IORESOURCE_MEM) { /* ICH4 and Nforce */ | 1152 | if (pci_resource_flags(pci, 2) & IORESOURCE_MEM) /* ICH4 and Nforce */ |
1181 | chip->mmio = 1; | 1153 | chip->addr = pci_iomap(pci, 2, 0); |
1182 | chip->addr = pci_resource_start(pci, 2); | 1154 | else |
1183 | chip->remap_addr = ioremap_nocache(chip->addr, | 1155 | chip->addr = pci_iomap(pci, 0, 0); |
1184 | pci_resource_len(pci, 2)); | 1156 | if (!chip->addr) { |
1185 | if (chip->remap_addr == NULL) { | 1157 | snd_printk(KERN_ERR "AC'97 space ioremap problem\n"); |
1186 | snd_printk(KERN_ERR "AC'97 space ioremap problem\n"); | 1158 | snd_intel8x0_free(chip); |
1187 | snd_intel8x0_free(chip); | 1159 | return -EIO; |
1188 | return -EIO; | ||
1189 | } | ||
1190 | } else { | ||
1191 | chip->addr = pci_resource_start(pci, 0); | ||
1192 | } | 1160 | } |
1193 | if (pci_resource_flags(pci, 3) & IORESOURCE_MEM) { /* ICH4 */ | 1161 | if (pci_resource_flags(pci, 3) & IORESOURCE_MEM) /* ICH4 */ |
1194 | chip->bm_mmio = 1; | 1162 | chip->bmaddr = pci_iomap(pci, 3, 0); |
1195 | chip->bmaddr = pci_resource_start(pci, 3); | 1163 | else |
1196 | chip->remap_bmaddr = ioremap_nocache(chip->bmaddr, | 1164 | chip->bmaddr = pci_iomap(pci, 1, 0); |
1197 | pci_resource_len(pci, 3)); | 1165 | if (!chip->bmaddr) { |
1198 | if (chip->remap_bmaddr == NULL) { | 1166 | snd_printk(KERN_ERR "Controller space ioremap problem\n"); |
1199 | snd_printk(KERN_ERR "Controller space ioremap problem\n"); | 1167 | snd_intel8x0_free(chip); |
1200 | snd_intel8x0_free(chip); | 1168 | return -EIO; |
1201 | return -EIO; | ||
1202 | } | ||
1203 | } else { | ||
1204 | chip->bmaddr = pci_resource_start(pci, 1); | ||
1205 | } | 1169 | } |
1206 | 1170 | ||
1207 | port_inited: | 1171 | port_inited: |
@@ -1339,8 +1303,8 @@ static int __devinit snd_intel8x0m_probe(struct pci_dev *pci, | |||
1339 | 1303 | ||
1340 | snd_intel8x0m_proc_init(chip); | 1304 | snd_intel8x0m_proc_init(chip); |
1341 | 1305 | ||
1342 | sprintf(card->longname, "%s at 0x%lx, irq %i", | 1306 | sprintf(card->longname, "%s at irq %i", |
1343 | card->shortname, chip->addr, chip->irq); | 1307 | card->shortname, chip->irq); |
1344 | 1308 | ||
1345 | if ((err = snd_card_register(card)) < 0) { | 1309 | if ((err = snd_card_register(card)) < 0) { |
1346 | snd_card_free(card); | 1310 | snd_card_free(card); |
diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c index 345eefeedb39..21d0899ac382 100644 --- a/sound/pci/korg1212/korg1212.c +++ b/sound/pci/korg1212/korg1212.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/wait.h> | 28 | #include <linux/wait.h> |
29 | #include <linux/moduleparam.h> | 29 | #include <linux/moduleparam.h> |
30 | #include <linux/mutex.h> | 30 | #include <linux/mutex.h> |
31 | #include <linux/firmware.h> | ||
31 | 32 | ||
32 | #include <sound/core.h> | 33 | #include <sound/core.h> |
33 | #include <sound/info.h> | 34 | #include <sound/info.h> |
@@ -263,7 +264,15 @@ enum MonitorModeSelector { | |||
263 | #define COMMAND_ACK_DELAY 13 // number of RTC ticks to wait for an acknowledgement | 264 | #define COMMAND_ACK_DELAY 13 // number of RTC ticks to wait for an acknowledgement |
264 | // from the card after sending a command. | 265 | // from the card after sending a command. |
265 | 266 | ||
267 | #define FIRMWARE_IN_THE_KERNEL | ||
268 | |||
269 | #ifdef FIRMWARE_IN_THE_KERNEL | ||
266 | #include "korg1212-firmware.h" | 270 | #include "korg1212-firmware.h" |
271 | static const struct firmware static_dsp_code = { | ||
272 | .data = (u8 *)dspCode, | ||
273 | .size = sizeof dspCode | ||
274 | }; | ||
275 | #endif | ||
267 | 276 | ||
268 | enum ClockSourceIndex { | 277 | enum ClockSourceIndex { |
269 | K1212_CLKIDX_AdatAt44_1K = 0, // selects source as ADAT at 44.1 kHz | 278 | K1212_CLKIDX_AdatAt44_1K = 0, // selects source as ADAT at 44.1 kHz |
@@ -345,8 +354,6 @@ struct snd_korg1212 { | |||
345 | struct snd_dma_buffer dma_rec; | 354 | struct snd_dma_buffer dma_rec; |
346 | struct snd_dma_buffer dma_shared; | 355 | struct snd_dma_buffer dma_shared; |
347 | 356 | ||
348 | u32 dspCodeSize; | ||
349 | |||
350 | u32 DataBufsSize; | 357 | u32 DataBufsSize; |
351 | 358 | ||
352 | struct KorgAudioBuffer * playDataBufsPtr; | 359 | struct KorgAudioBuffer * playDataBufsPtr; |
@@ -1223,8 +1230,6 @@ static int snd_korg1212_downloadDSPCode(struct snd_korg1212 *korg1212) | |||
1223 | 1230 | ||
1224 | snd_korg1212_setCardState(korg1212, K1212_STATE_DSP_IN_PROCESS); | 1231 | snd_korg1212_setCardState(korg1212, K1212_STATE_DSP_IN_PROCESS); |
1225 | 1232 | ||
1226 | memcpy(korg1212->dma_dsp.area, dspCode, korg1212->dspCodeSize); | ||
1227 | |||
1228 | rc = snd_korg1212_Send1212Command(korg1212, K1212_DB_StartDSPDownload, | 1233 | rc = snd_korg1212_Send1212Command(korg1212, K1212_DB_StartDSPDownload, |
1229 | UpperWordSwap(korg1212->dma_dsp.addr), | 1234 | UpperWordSwap(korg1212->dma_dsp.addr), |
1230 | 0, 0, 0); | 1235 | 0, 0, 0); |
@@ -2156,6 +2161,7 @@ static int __devinit snd_korg1212_create(struct snd_card *card, struct pci_dev * | |||
2156 | unsigned int i; | 2161 | unsigned int i; |
2157 | unsigned ioport_size, iomem_size, iomem2_size; | 2162 | unsigned ioport_size, iomem_size, iomem2_size; |
2158 | struct snd_korg1212 * korg1212; | 2163 | struct snd_korg1212 * korg1212; |
2164 | const struct firmware *dsp_code; | ||
2159 | 2165 | ||
2160 | static struct snd_device_ops ops = { | 2166 | static struct snd_device_ops ops = { |
2161 | .dev_free = snd_korg1212_dev_free, | 2167 | .dev_free = snd_korg1212_dev_free, |
@@ -2329,8 +2335,6 @@ static int __devinit snd_korg1212_create(struct snd_card *card, struct pci_dev * | |||
2329 | 2335 | ||
2330 | #endif // K1212_LARGEALLOC | 2336 | #endif // K1212_LARGEALLOC |
2331 | 2337 | ||
2332 | korg1212->dspCodeSize = sizeof (dspCode); | ||
2333 | |||
2334 | korg1212->VolumeTablePhy = korg1212->sharedBufferPhy + | 2338 | korg1212->VolumeTablePhy = korg1212->sharedBufferPhy + |
2335 | offsetof(struct KorgSharedBuffer, volumeData); | 2339 | offsetof(struct KorgSharedBuffer, volumeData); |
2336 | korg1212->RoutingTablePhy = korg1212->sharedBufferPhy + | 2340 | korg1212->RoutingTablePhy = korg1212->sharedBufferPhy + |
@@ -2338,17 +2342,40 @@ static int __devinit snd_korg1212_create(struct snd_card *card, struct pci_dev * | |||
2338 | korg1212->AdatTimeCodePhy = korg1212->sharedBufferPhy + | 2342 | korg1212->AdatTimeCodePhy = korg1212->sharedBufferPhy + |
2339 | offsetof(struct KorgSharedBuffer, AdatTimeCode); | 2343 | offsetof(struct KorgSharedBuffer, AdatTimeCode); |
2340 | 2344 | ||
2345 | err = request_firmware(&dsp_code, "korg/k1212.dsp", &pci->dev); | ||
2346 | if (err < 0) { | ||
2347 | release_firmware(dsp_code); | ||
2348 | #ifdef FIRMWARE_IN_THE_KERNEL | ||
2349 | dsp_code = &static_dsp_code; | ||
2350 | #else | ||
2351 | snd_printk(KERN_ERR "firmware not available\n"); | ||
2352 | snd_korg1212_free(korg1212); | ||
2353 | return err; | ||
2354 | #endif | ||
2355 | } | ||
2356 | |||
2341 | if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), | 2357 | if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), |
2342 | korg1212->dspCodeSize, &korg1212->dma_dsp) < 0) { | 2358 | dsp_code->size, &korg1212->dma_dsp) < 0) { |
2343 | snd_printk(KERN_ERR "korg1212: can not allocate dsp code memory (%d bytes)\n", korg1212->dspCodeSize); | 2359 | snd_printk(KERN_ERR "korg1212: cannot allocate dsp code memory (%zd bytes)\n", dsp_code->size); |
2344 | snd_korg1212_free(korg1212); | 2360 | snd_korg1212_free(korg1212); |
2361 | #ifdef FIRMWARE_IN_THE_KERNEL | ||
2362 | if (dsp_code != &static_dsp_code) | ||
2363 | #endif | ||
2364 | release_firmware(dsp_code); | ||
2345 | return -ENOMEM; | 2365 | return -ENOMEM; |
2346 | } | 2366 | } |
2347 | 2367 | ||
2348 | K1212_DEBUG_PRINTK("K1212_DEBUG: DSP Code area = 0x%p (0x%08x) %d bytes [%s]\n", | 2368 | K1212_DEBUG_PRINTK("K1212_DEBUG: DSP Code area = 0x%p (0x%08x) %d bytes [%s]\n", |
2349 | korg1212->dma_dsp.area, korg1212->dma_dsp.addr, korg1212->dspCodeSize, | 2369 | korg1212->dma_dsp.area, korg1212->dma_dsp.addr, dsp_code->size, |
2350 | stateName[korg1212->cardState]); | 2370 | stateName[korg1212->cardState]); |
2351 | 2371 | ||
2372 | memcpy(korg1212->dma_dsp.area, dsp_code->data, dsp_code->size); | ||
2373 | |||
2374 | #ifdef FIRMWARE_IN_THE_KERNEL | ||
2375 | if (dsp_code != &static_dsp_code) | ||
2376 | #endif | ||
2377 | release_firmware(dsp_code); | ||
2378 | |||
2352 | rc = snd_korg1212_Send1212Command(korg1212, K1212_DB_RebootCard, 0, 0, 0, 0); | 2379 | rc = snd_korg1212_Send1212Command(korg1212, K1212_DB_RebootCard, 0, 0, 0, 0); |
2353 | 2380 | ||
2354 | if (rc) | 2381 | if (rc) |
diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index 6efe6d5ade1e..4526904e3f86 100644 --- a/sound/pci/maestro3.c +++ b/sound/pci/maestro3.c | |||
@@ -41,6 +41,7 @@ | |||
41 | #include <linux/slab.h> | 41 | #include <linux/slab.h> |
42 | #include <linux/vmalloc.h> | 42 | #include <linux/vmalloc.h> |
43 | #include <linux/moduleparam.h> | 43 | #include <linux/moduleparam.h> |
44 | #include <linux/firmware.h> | ||
44 | #include <sound/core.h> | 45 | #include <sound/core.h> |
45 | #include <sound/info.h> | 46 | #include <sound/info.h> |
46 | #include <sound/control.h> | 47 | #include <sound/control.h> |
@@ -48,6 +49,7 @@ | |||
48 | #include <sound/mpu401.h> | 49 | #include <sound/mpu401.h> |
49 | #include <sound/ac97_codec.h> | 50 | #include <sound/ac97_codec.h> |
50 | #include <sound/initval.h> | 51 | #include <sound/initval.h> |
52 | #include <asm/byteorder.h> | ||
51 | 53 | ||
52 | MODULE_AUTHOR("Zach Brown <zab@zabbo.net>, Takashi Iwai <tiwai@suse.de>"); | 54 | MODULE_AUTHOR("Zach Brown <zab@zabbo.net>, Takashi Iwai <tiwai@suse.de>"); |
53 | MODULE_DESCRIPTION("ESS Maestro3 PCI"); | 55 | MODULE_DESCRIPTION("ESS Maestro3 PCI"); |
@@ -768,21 +770,6 @@ MODULE_PARM_DESC(amp_gpio, "GPIO pin number for external amp. (default = -1)"); | |||
768 | /* | 770 | /* |
769 | */ | 771 | */ |
770 | 772 | ||
771 | /* quirk lists */ | ||
772 | struct m3_quirk { | ||
773 | const char *name; /* device name */ | ||
774 | u16 vendor, device; /* subsystem ids */ | ||
775 | int amp_gpio; /* gpio pin # for external amp, -1 = default */ | ||
776 | int irda_workaround; /* non-zero if avoid to touch 0x10 on GPIO_DIRECTION | ||
777 | (e.g. for IrDA on Dell Inspirons) */ | ||
778 | }; | ||
779 | |||
780 | struct m3_hv_quirk { | ||
781 | u16 vendor, device, subsystem_vendor, subsystem_device; | ||
782 | u32 config; /* ALLEGRO_CONFIG hardware volume bits */ | ||
783 | int is_omnibook; /* Do HP OmniBook GPIO magic? */ | ||
784 | }; | ||
785 | |||
786 | struct m3_list { | 773 | struct m3_list { |
787 | int curlen; | 774 | int curlen; |
788 | int mem_addr; | 775 | int mem_addr; |
@@ -830,8 +817,6 @@ struct snd_m3 { | |||
830 | struct snd_pcm *pcm; | 817 | struct snd_pcm *pcm; |
831 | 818 | ||
832 | struct pci_dev *pci; | 819 | struct pci_dev *pci; |
833 | const struct m3_quirk *quirk; | ||
834 | const struct m3_hv_quirk *hv_quirk; | ||
835 | 820 | ||
836 | int dacs_active; | 821 | int dacs_active; |
837 | int timer_users; | 822 | int timer_users; |
@@ -845,7 +830,11 @@ struct snd_m3 { | |||
845 | u8 reset_state; | 830 | u8 reset_state; |
846 | 831 | ||
847 | int external_amp; | 832 | int external_amp; |
848 | int amp_gpio; | 833 | int amp_gpio; /* gpio pin # for external amp, -1 = default */ |
834 | unsigned int hv_config; /* hardware-volume config bits */ | ||
835 | unsigned irda_workaround :1; /* avoid to touch 0x10 on GPIO_DIRECTION | ||
836 | (e.g. for IrDA on Dell Inspirons) */ | ||
837 | unsigned is_omnibook :1; /* Do HP OmniBook GPIO magic? */ | ||
849 | 838 | ||
850 | /* midi */ | 839 | /* midi */ |
851 | struct snd_rawmidi *rmidi; | 840 | struct snd_rawmidi *rmidi; |
@@ -864,6 +853,9 @@ struct snd_m3 { | |||
864 | #ifdef CONFIG_PM | 853 | #ifdef CONFIG_PM |
865 | u16 *suspend_mem; | 854 | u16 *suspend_mem; |
866 | #endif | 855 | #endif |
856 | |||
857 | const struct firmware *assp_kernel_image; | ||
858 | const struct firmware *assp_minisrc_image; | ||
867 | }; | 859 | }; |
868 | 860 | ||
869 | /* | 861 | /* |
@@ -891,127 +883,104 @@ static struct pci_device_id snd_m3_ids[] = { | |||
891 | 883 | ||
892 | MODULE_DEVICE_TABLE(pci, snd_m3_ids); | 884 | MODULE_DEVICE_TABLE(pci, snd_m3_ids); |
893 | 885 | ||
894 | static const struct m3_quirk m3_quirk_list[] = { | 886 | static struct snd_pci_quirk m3_amp_quirk_list[] __devinitdata = { |
895 | /* panasonic CF-28 "toughbook" */ | 887 | SND_PCI_QUIRK(0x10f7, 0x833e, "Panasonic CF-28", 0x0d), |
896 | { | 888 | SND_PCI_QUIRK(0x10f7, 0x833d, "Panasonic CF-72", 0x0d), |
897 | .name = "Panasonic CF-28", | 889 | SND_PCI_QUIRK(0x1033, 0x80f1, "NEC LM800J/7", 0x03), |
898 | .vendor = 0x10f7, | 890 | SND_PCI_QUIRK(0x1509, 0x1740, "LEGEND ZhaoYang 3100CF", 0x03), |
899 | .device = 0x833e, | 891 | { } /* END */ |
900 | .amp_gpio = 0x0d, | ||
901 | }, | ||
902 | /* panasonic CF-72 "toughbook" */ | ||
903 | { | ||
904 | .name = "Panasonic CF-72", | ||
905 | .vendor = 0x10f7, | ||
906 | .device = 0x833d, | ||
907 | .amp_gpio = 0x0d, | ||
908 | }, | ||
909 | /* Dell Inspiron 4000 */ | ||
910 | { | ||
911 | .name = "Dell Inspiron 4000", | ||
912 | .vendor = 0x1028, | ||
913 | .device = 0x00b0, | ||
914 | .amp_gpio = -1, | ||
915 | .irda_workaround = 1, | ||
916 | }, | ||
917 | /* Dell Inspiron 8000 */ | ||
918 | { | ||
919 | .name = "Dell Inspiron 8000", | ||
920 | .vendor = 0x1028, | ||
921 | .device = 0x00a4, | ||
922 | .amp_gpio = -1, | ||
923 | .irda_workaround = 1, | ||
924 | }, | ||
925 | /* Dell Inspiron 8100 */ | ||
926 | { | ||
927 | .name = "Dell Inspiron 8100", | ||
928 | .vendor = 0x1028, | ||
929 | .device = 0x00e6, | ||
930 | .amp_gpio = -1, | ||
931 | .irda_workaround = 1, | ||
932 | }, | ||
933 | /* NEC LM800J/7 */ | ||
934 | { | ||
935 | .name = "NEC LM800J/7", | ||
936 | .vendor = 0x1033, | ||
937 | .device = 0x80f1, | ||
938 | .amp_gpio = 0x03, | ||
939 | }, | ||
940 | /* LEGEND ZhaoYang 3100CF */ | ||
941 | { | ||
942 | .name = "LEGEND ZhaoYang 3100CF", | ||
943 | .vendor = 0x1509, | ||
944 | .device = 0x1740, | ||
945 | .amp_gpio = 0x03, | ||
946 | }, | ||
947 | /* END */ | ||
948 | { NULL } | ||
949 | }; | 892 | }; |
950 | 893 | ||
951 | /* These values came from the Windows driver. */ | 894 | static struct snd_pci_quirk m3_irda_quirk_list[] __devinitdata = { |
952 | static const struct m3_hv_quirk m3_hv_quirk_list[] = { | 895 | SND_PCI_QUIRK(0x1028, 0x00b0, "Dell Inspiron 4000", 1), |
896 | SND_PCI_QUIRK(0x1028, 0x00a4, "Dell Inspiron 8000", 1), | ||
897 | SND_PCI_QUIRK(0x1028, 0x00e6, "Dell Inspiron 8100", 1), | ||
898 | { } /* END */ | ||
899 | }; | ||
900 | |||
901 | /* hardware volume quirks */ | ||
902 | static struct snd_pci_quirk m3_hv_quirk_list[] __devinitdata = { | ||
953 | /* Allegro chips */ | 903 | /* Allegro chips */ |
954 | { 0x125D, 0x1988, 0x0E11, 0x002E, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, | 904 | SND_PCI_QUIRK(0x0E11, 0x002E, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), |
955 | { 0x125D, 0x1988, 0x0E11, 0x0094, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, | 905 | SND_PCI_QUIRK(0x0E11, 0x0094, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), |
956 | { 0x125D, 0x1988, 0x0E11, 0xB112, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, | 906 | SND_PCI_QUIRK(0x0E11, 0xB112, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), |
957 | { 0x125D, 0x1988, 0x0E11, 0xB114, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, | 907 | SND_PCI_QUIRK(0x0E11, 0xB114, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), |
958 | { 0x125D, 0x1988, 0x103C, 0x0012, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, | 908 | SND_PCI_QUIRK(0x103C, 0x0012, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), |
959 | { 0x125D, 0x1988, 0x103C, 0x0018, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, | 909 | SND_PCI_QUIRK(0x103C, 0x0018, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), |
960 | { 0x125D, 0x1988, 0x103C, 0x001C, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, | 910 | SND_PCI_QUIRK(0x103C, 0x001C, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), |
961 | { 0x125D, 0x1988, 0x103C, 0x001D, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, | 911 | SND_PCI_QUIRK(0x103C, 0x001D, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), |
962 | { 0x125D, 0x1988, 0x103C, 0x001E, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, | 912 | SND_PCI_QUIRK(0x103C, 0x001E, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), |
963 | { 0x125D, 0x1988, 0x107B, 0x3350, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, | 913 | SND_PCI_QUIRK(0x107B, 0x3350, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), |
964 | { 0x125D, 0x1988, 0x10F7, 0x8338, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, | 914 | SND_PCI_QUIRK(0x10F7, 0x8338, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), |
965 | { 0x125D, 0x1988, 0x10F7, 0x833C, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, | 915 | SND_PCI_QUIRK(0x10F7, 0x833C, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), |
966 | { 0x125D, 0x1988, 0x10F7, 0x833D, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, | 916 | SND_PCI_QUIRK(0x10F7, 0x833D, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), |
967 | { 0x125D, 0x1988, 0x10F7, 0x833E, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, | 917 | SND_PCI_QUIRK(0x10F7, 0x833E, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), |
968 | { 0x125D, 0x1988, 0x10F7, 0x833F, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, | 918 | SND_PCI_QUIRK(0x10F7, 0x833F, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), |
969 | { 0x125D, 0x1988, 0x13BD, 0x1018, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, | 919 | SND_PCI_QUIRK(0x13BD, 0x1018, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), |
970 | { 0x125D, 0x1988, 0x13BD, 0x1019, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, | 920 | SND_PCI_QUIRK(0x13BD, 0x1019, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), |
971 | { 0x125D, 0x1988, 0x13BD, 0x101A, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, | 921 | SND_PCI_QUIRK(0x13BD, 0x101A, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), |
972 | { 0x125D, 0x1988, 0x14FF, 0x0F03, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, | 922 | SND_PCI_QUIRK(0x14FF, 0x0F03, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), |
973 | { 0x125D, 0x1988, 0x14FF, 0x0F04, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, | 923 | SND_PCI_QUIRK(0x14FF, 0x0F04, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), |
974 | { 0x125D, 0x1988, 0x14FF, 0x0F05, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, | 924 | SND_PCI_QUIRK(0x14FF, 0x0F05, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), |
975 | { 0x125D, 0x1988, 0x156D, 0xB400, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, | 925 | SND_PCI_QUIRK(0x156D, 0xB400, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), |
976 | { 0x125D, 0x1988, 0x156D, 0xB795, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, | 926 | SND_PCI_QUIRK(0x156D, 0xB795, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), |
977 | { 0x125D, 0x1988, 0x156D, 0xB797, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, | 927 | SND_PCI_QUIRK(0x156D, 0xB797, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), |
978 | { 0x125D, 0x1988, 0x156D, 0xC700, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, | 928 | SND_PCI_QUIRK(0x156D, 0xC700, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), |
979 | { 0x125D, 0x1988, 0x1033, 0x80F1, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, | 929 | SND_PCI_QUIRK(0x1033, 0x80F1, NULL, |
980 | { 0x125D, 0x1988, 0x103C, 0x001A, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, /* HP OmniBook 6100 */ | 930 | HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE), |
981 | { 0x125D, 0x1988, 0x107B, 0x340A, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, | 931 | SND_PCI_QUIRK(0x103C, 0x001A, NULL, /* HP OmniBook 6100 */ |
982 | { 0x125D, 0x1988, 0x107B, 0x3450, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, | 932 | HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE), |
983 | { 0x125D, 0x1988, 0x109F, 0x3134, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, | 933 | SND_PCI_QUIRK(0x107B, 0x340A, NULL, |
984 | { 0x125D, 0x1988, 0x109F, 0x3161, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, | 934 | HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE), |
985 | { 0x125D, 0x1988, 0x144D, 0x3280, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, | 935 | SND_PCI_QUIRK(0x107B, 0x3450, NULL, |
986 | { 0x125D, 0x1988, 0x144D, 0x3281, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, | 936 | HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE), |
987 | { 0x125D, 0x1988, 0x144D, 0xC002, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, | 937 | SND_PCI_QUIRK(0x109F, 0x3134, NULL, |
988 | { 0x125D, 0x1988, 0x144D, 0xC003, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, | 938 | HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE), |
989 | { 0x125D, 0x1988, 0x1509, 0x1740, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, | 939 | SND_PCI_QUIRK(0x109F, 0x3161, NULL, |
990 | { 0x125D, 0x1988, 0x1610, 0x0010, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, | 940 | HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE), |
991 | { 0x125D, 0x1988, 0x1042, 0x1042, HV_CTRL_ENABLE, 0 }, | 941 | SND_PCI_QUIRK(0x144D, 0x3280, NULL, |
992 | { 0x125D, 0x1988, 0x107B, 0x9500, HV_CTRL_ENABLE, 0 }, | 942 | HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE), |
993 | { 0x125D, 0x1988, 0x14FF, 0x0F06, HV_CTRL_ENABLE, 0 }, | 943 | SND_PCI_QUIRK(0x144D, 0x3281, NULL, |
994 | { 0x125D, 0x1988, 0x1558, 0x8586, HV_CTRL_ENABLE, 0 }, | 944 | HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE), |
995 | { 0x125D, 0x1988, 0x161F, 0x2011, HV_CTRL_ENABLE, 0 }, | 945 | SND_PCI_QUIRK(0x144D, 0xC002, NULL, |
946 | HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE), | ||
947 | SND_PCI_QUIRK(0x144D, 0xC003, NULL, | ||
948 | HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE), | ||
949 | SND_PCI_QUIRK(0x1509, 0x1740, NULL, | ||
950 | HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE), | ||
951 | SND_PCI_QUIRK(0x1610, 0x0010, NULL, | ||
952 | HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE), | ||
953 | SND_PCI_QUIRK(0x1042, 0x1042, NULL, HV_CTRL_ENABLE), | ||
954 | SND_PCI_QUIRK(0x107B, 0x9500, NULL, HV_CTRL_ENABLE), | ||
955 | SND_PCI_QUIRK(0x14FF, 0x0F06, NULL, HV_CTRL_ENABLE), | ||
956 | SND_PCI_QUIRK(0x1558, 0x8586, NULL, HV_CTRL_ENABLE), | ||
957 | SND_PCI_QUIRK(0x161F, 0x2011, NULL, HV_CTRL_ENABLE), | ||
996 | /* Maestro3 chips */ | 958 | /* Maestro3 chips */ |
997 | { 0x125D, 0x1998, 0x103C, 0x000E, HV_CTRL_ENABLE, 0 }, | 959 | SND_PCI_QUIRK(0x103C, 0x000E, NULL, HV_CTRL_ENABLE), |
998 | { 0x125D, 0x1998, 0x103C, 0x0010, HV_CTRL_ENABLE, 1 }, /* HP OmniBook 6000 */ | 960 | SND_PCI_QUIRK(0x103C, 0x0010, NULL, HV_CTRL_ENABLE), |
999 | { 0x125D, 0x1998, 0x103C, 0x0011, HV_CTRL_ENABLE, 1 }, /* HP OmniBook 500 */ | 961 | SND_PCI_QUIRK(0x103C, 0x0011, NULL, HV_CTRL_ENABLE), |
1000 | { 0x125D, 0x1998, 0x103C, 0x001B, HV_CTRL_ENABLE, 0 }, | 962 | SND_PCI_QUIRK(0x103C, 0x001B, NULL, HV_CTRL_ENABLE), |
1001 | { 0x125D, 0x1998, 0x104D, 0x80A6, HV_CTRL_ENABLE, 0 }, | 963 | SND_PCI_QUIRK(0x104D, 0x80A6, NULL, HV_CTRL_ENABLE), |
1002 | { 0x125D, 0x1998, 0x104D, 0x80AA, HV_CTRL_ENABLE, 0 }, | 964 | SND_PCI_QUIRK(0x104D, 0x80AA, NULL, HV_CTRL_ENABLE), |
1003 | { 0x125D, 0x1998, 0x107B, 0x5300, HV_CTRL_ENABLE, 0 }, | 965 | SND_PCI_QUIRK(0x107B, 0x5300, NULL, HV_CTRL_ENABLE), |
1004 | { 0x125D, 0x1998, 0x110A, 0x1998, HV_CTRL_ENABLE, 0 }, | 966 | SND_PCI_QUIRK(0x110A, 0x1998, NULL, HV_CTRL_ENABLE), |
1005 | { 0x125D, 0x1998, 0x13BD, 0x1015, HV_CTRL_ENABLE, 0 }, | 967 | SND_PCI_QUIRK(0x13BD, 0x1015, NULL, HV_CTRL_ENABLE), |
1006 | { 0x125D, 0x1998, 0x13BD, 0x101C, HV_CTRL_ENABLE, 0 }, | 968 | SND_PCI_QUIRK(0x13BD, 0x101C, NULL, HV_CTRL_ENABLE), |
1007 | { 0x125D, 0x1998, 0x13BD, 0x1802, HV_CTRL_ENABLE, 0 }, | 969 | SND_PCI_QUIRK(0x13BD, 0x1802, NULL, HV_CTRL_ENABLE), |
1008 | { 0x125D, 0x1998, 0x1599, 0x0715, HV_CTRL_ENABLE, 0 }, | 970 | SND_PCI_QUIRK(0x1599, 0x0715, NULL, HV_CTRL_ENABLE), |
1009 | { 0x125D, 0x1998, 0x5643, 0x5643, HV_CTRL_ENABLE, 0 }, | 971 | SND_PCI_QUIRK(0x5643, 0x5643, NULL, HV_CTRL_ENABLE), |
1010 | { 0x125D, 0x199A, 0x144D, 0x3260, HV_CTRL_ENABLE | REDUCED_DEBOUNCE, 0 }, | 972 | SND_PCI_QUIRK(0x144D, 0x3260, NULL, HV_CTRL_ENABLE | REDUCED_DEBOUNCE), |
1011 | { 0x125D, 0x199A, 0x144D, 0x3261, HV_CTRL_ENABLE | REDUCED_DEBOUNCE, 0 }, | 973 | SND_PCI_QUIRK(0x144D, 0x3261, NULL, HV_CTRL_ENABLE | REDUCED_DEBOUNCE), |
1012 | { 0x125D, 0x199A, 0x144D, 0xC000, HV_CTRL_ENABLE | REDUCED_DEBOUNCE, 0 }, | 974 | SND_PCI_QUIRK(0x144D, 0xC000, NULL, HV_CTRL_ENABLE | REDUCED_DEBOUNCE), |
1013 | { 0x125D, 0x199A, 0x144D, 0xC001, HV_CTRL_ENABLE | REDUCED_DEBOUNCE, 0 }, | 975 | SND_PCI_QUIRK(0x144D, 0xC001, NULL, HV_CTRL_ENABLE | REDUCED_DEBOUNCE), |
1014 | { 0 } | 976 | { } /* END */ |
977 | }; | ||
978 | |||
979 | /* HP Omnibook quirks */ | ||
980 | static struct snd_pci_quirk m3_omnibook_quirk_list[] __devinitdata = { | ||
981 | SND_PCI_QUIRK_ID(0x103c, 0x0010), /* HP OmniBook 6000 */ | ||
982 | SND_PCI_QUIRK_ID(0x103c, 0x0011), /* HP OmniBook 500 */ | ||
983 | { } /* END */ | ||
1015 | }; | 984 | }; |
1016 | 985 | ||
1017 | /* | 986 | /* |
@@ -2050,7 +2019,7 @@ static void snd_m3_ac97_reset(struct snd_m3 *chip) | |||
2050 | 2019 | ||
2051 | for (i = 0; i < 5; i++) { | 2020 | for (i = 0; i < 5; i++) { |
2052 | dir = inw(io + GPIO_DIRECTION); | 2021 | dir = inw(io + GPIO_DIRECTION); |
2053 | if (! chip->quirk || ! chip->quirk->irda_workaround) | 2022 | if (!chip->irda_workaround) |
2054 | dir |= 0x10; /* assuming pci bus master? */ | 2023 | dir |= 0x10; /* assuming pci bus master? */ |
2055 | 2024 | ||
2056 | snd_m3_remote_codec_config(io, 0); | 2025 | snd_m3_remote_codec_config(io, 0); |
@@ -2132,6 +2101,10 @@ static int __devinit snd_m3_mixer(struct snd_m3 *chip) | |||
2132 | } | 2101 | } |
2133 | 2102 | ||
2134 | 2103 | ||
2104 | #define FIRMWARE_IN_THE_KERNEL | ||
2105 | |||
2106 | #ifdef FIRMWARE_IN_THE_KERNEL | ||
2107 | |||
2135 | /* | 2108 | /* |
2136 | * DSP Code images | 2109 | * DSP Code images |
2137 | */ | 2110 | */ |
@@ -2260,6 +2233,30 @@ static const u16 assp_minisrc_image[] = { | |||
2260 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | 2233 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, |
2261 | }; | 2234 | }; |
2262 | 2235 | ||
2236 | static const struct firmware assp_kernel = { | ||
2237 | .data = (u8 *)assp_kernel_image, | ||
2238 | .size = sizeof assp_kernel_image | ||
2239 | }; | ||
2240 | static const struct firmware assp_minisrc = { | ||
2241 | .data = (u8 *)assp_minisrc_image, | ||
2242 | .size = sizeof assp_minisrc_image | ||
2243 | }; | ||
2244 | |||
2245 | #endif /* FIRMWARE_IN_THE_KERNEL */ | ||
2246 | |||
2247 | #ifdef __LITTLE_ENDIAN | ||
2248 | static inline void snd_m3_convert_from_le(const struct firmware *fw) { } | ||
2249 | #else | ||
2250 | static void snd_m3_convert_from_le(const struct firmware *fw) | ||
2251 | { | ||
2252 | int i; | ||
2253 | u16 *data = (u16 *)fw->data; | ||
2254 | |||
2255 | for (i = 0; i < fw->size / 2; ++i) | ||
2256 | le16_to_cpus(&data[i]); | ||
2257 | } | ||
2258 | #endif | ||
2259 | |||
2263 | 2260 | ||
2264 | /* | 2261 | /* |
2265 | * initialize ASSP | 2262 | * initialize ASSP |
@@ -2274,6 +2271,7 @@ static const u16 minisrc_lpf[MINISRC_LPF_LEN] = { | |||
2274 | static void snd_m3_assp_init(struct snd_m3 *chip) | 2271 | static void snd_m3_assp_init(struct snd_m3 *chip) |
2275 | { | 2272 | { |
2276 | unsigned int i; | 2273 | unsigned int i; |
2274 | u16 *data; | ||
2277 | 2275 | ||
2278 | /* zero kernel data */ | 2276 | /* zero kernel data */ |
2279 | for (i = 0; i < (REV_B_DATA_MEMORY_UNIT_LENGTH * NUM_UNITS_KERNEL_DATA) / 2; i++) | 2277 | for (i = 0; i < (REV_B_DATA_MEMORY_UNIT_LENGTH * NUM_UNITS_KERNEL_DATA) / 2; i++) |
@@ -2291,10 +2289,10 @@ static void snd_m3_assp_init(struct snd_m3 *chip) | |||
2291 | KDATA_DMA_XFER0); | 2289 | KDATA_DMA_XFER0); |
2292 | 2290 | ||
2293 | /* write kernel into code memory.. */ | 2291 | /* write kernel into code memory.. */ |
2294 | for (i = 0 ; i < ARRAY_SIZE(assp_kernel_image); i++) { | 2292 | data = (u16 *)chip->assp_kernel_image->data; |
2293 | for (i = 0 ; i * 2 < chip->assp_kernel_image->size; i++) { | ||
2295 | snd_m3_assp_write(chip, MEMTYPE_INTERNAL_CODE, | 2294 | snd_m3_assp_write(chip, MEMTYPE_INTERNAL_CODE, |
2296 | REV_B_CODE_MEMORY_BEGIN + i, | 2295 | REV_B_CODE_MEMORY_BEGIN + i, data[i]); |
2297 | assp_kernel_image[i]); | ||
2298 | } | 2296 | } |
2299 | 2297 | ||
2300 | /* | 2298 | /* |
@@ -2303,10 +2301,10 @@ static void snd_m3_assp_init(struct snd_m3 *chip) | |||
2303 | * drop it there. It seems that the minisrc doesn't | 2301 | * drop it there. It seems that the minisrc doesn't |
2304 | * need vectors, so we won't bother with them.. | 2302 | * need vectors, so we won't bother with them.. |
2305 | */ | 2303 | */ |
2306 | for (i = 0; i < ARRAY_SIZE(assp_minisrc_image); i++) { | 2304 | data = (u16 *)chip->assp_minisrc_image->data; |
2305 | for (i = 0; i * 2 < chip->assp_minisrc_image->size; i++) { | ||
2307 | snd_m3_assp_write(chip, MEMTYPE_INTERNAL_CODE, | 2306 | snd_m3_assp_write(chip, MEMTYPE_INTERNAL_CODE, |
2308 | 0x400 + i, | 2307 | 0x400 + i, data[i]); |
2309 | assp_minisrc_image[i]); | ||
2310 | } | 2308 | } |
2311 | 2309 | ||
2312 | /* | 2310 | /* |
@@ -2444,7 +2442,7 @@ snd_m3_chip_init(struct snd_m3 *chip) | |||
2444 | DISABLE_LEGACY); | 2442 | DISABLE_LEGACY); |
2445 | pci_write_config_word(pcidev, PCI_LEGACY_AUDIO_CTRL, w); | 2443 | pci_write_config_word(pcidev, PCI_LEGACY_AUDIO_CTRL, w); |
2446 | 2444 | ||
2447 | if (chip->hv_quirk && chip->hv_quirk->is_omnibook) { | 2445 | if (chip->is_omnibook) { |
2448 | /* | 2446 | /* |
2449 | * Volume buttons on some HP OmniBook laptops don't work | 2447 | * Volume buttons on some HP OmniBook laptops don't work |
2450 | * correctly. This makes them work for the most part. | 2448 | * correctly. This makes them work for the most part. |
@@ -2461,8 +2459,7 @@ snd_m3_chip_init(struct snd_m3 *chip) | |||
2461 | } | 2459 | } |
2462 | pci_read_config_dword(pcidev, PCI_ALLEGRO_CONFIG, &n); | 2460 | pci_read_config_dword(pcidev, PCI_ALLEGRO_CONFIG, &n); |
2463 | n &= ~(HV_CTRL_ENABLE | REDUCED_DEBOUNCE | HV_BUTTON_FROM_GD); | 2461 | n &= ~(HV_CTRL_ENABLE | REDUCED_DEBOUNCE | HV_BUTTON_FROM_GD); |
2464 | if (chip->hv_quirk) | 2462 | n |= chip->hv_config; |
2465 | n |= chip->hv_quirk->config; | ||
2466 | /* For some reason we must always use reduced debounce. */ | 2463 | /* For some reason we must always use reduced debounce. */ |
2467 | n |= REDUCED_DEBOUNCE; | 2464 | n |= REDUCED_DEBOUNCE; |
2468 | n |= PM_CTRL_ENABLE | CLK_DIV_BY_49 | USE_PCI_TIMING; | 2465 | n |= PM_CTRL_ENABLE | CLK_DIV_BY_49 | USE_PCI_TIMING; |
@@ -2510,7 +2507,7 @@ snd_m3_enable_ints(struct snd_m3 *chip) | |||
2510 | 2507 | ||
2511 | /* TODO: MPU401 not supported yet */ | 2508 | /* TODO: MPU401 not supported yet */ |
2512 | val = ASSP_INT_ENABLE /*| MPU401_INT_ENABLE*/; | 2509 | val = ASSP_INT_ENABLE /*| MPU401_INT_ENABLE*/; |
2513 | if (chip->hv_quirk && (chip->hv_quirk->config & HV_CTRL_ENABLE)) | 2510 | if (chip->hv_config & HV_CTRL_ENABLE) |
2514 | val |= HV_INT_ENABLE; | 2511 | val |= HV_INT_ENABLE; |
2515 | outw(val, io + HOST_INT_CTRL); | 2512 | outw(val, io + HOST_INT_CTRL); |
2516 | outb(inb(io + ASSP_CONTROL_C) | ASSP_HOST_INT_ENABLE, | 2513 | outb(inb(io + ASSP_CONTROL_C) | ASSP_HOST_INT_ENABLE, |
@@ -2553,6 +2550,15 @@ static int snd_m3_free(struct snd_m3 *chip) | |||
2553 | if (chip->iobase) | 2550 | if (chip->iobase) |
2554 | pci_release_regions(chip->pci); | 2551 | pci_release_regions(chip->pci); |
2555 | 2552 | ||
2553 | #ifdef FIRMWARE_IN_THE_KERNEL | ||
2554 | if (chip->assp_kernel_image != &assp_kernel) | ||
2555 | #endif | ||
2556 | release_firmware(chip->assp_kernel_image); | ||
2557 | #ifdef FIRMWARE_IN_THE_KERNEL | ||
2558 | if (chip->assp_minisrc_image != &assp_minisrc) | ||
2559 | #endif | ||
2560 | release_firmware(chip->assp_minisrc_image); | ||
2561 | |||
2556 | pci_disable_device(chip->pci); | 2562 | pci_disable_device(chip->pci); |
2557 | kfree(chip); | 2563 | kfree(chip); |
2558 | return 0; | 2564 | return 0; |
@@ -2665,8 +2671,7 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci, | |||
2665 | { | 2671 | { |
2666 | struct snd_m3 *chip; | 2672 | struct snd_m3 *chip; |
2667 | int i, err; | 2673 | int i, err; |
2668 | const struct m3_quirk *quirk; | 2674 | const struct snd_pci_quirk *quirk; |
2669 | const struct m3_hv_quirk *hv_quirk; | ||
2670 | static struct snd_device_ops ops = { | 2675 | static struct snd_device_ops ops = { |
2671 | .dev_free = snd_m3_dev_free, | 2676 | .dev_free = snd_m3_dev_free, |
2672 | }; | 2677 | }; |
@@ -2706,34 +2711,32 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci, | |||
2706 | chip->pci = pci; | 2711 | chip->pci = pci; |
2707 | chip->irq = -1; | 2712 | chip->irq = -1; |
2708 | 2713 | ||
2709 | for (quirk = m3_quirk_list; quirk->vendor; quirk++) { | ||
2710 | if (pci->subsystem_vendor == quirk->vendor && | ||
2711 | pci->subsystem_device == quirk->device) { | ||
2712 | printk(KERN_INFO "maestro3: enabled hack for '%s'\n", quirk->name); | ||
2713 | chip->quirk = quirk; | ||
2714 | break; | ||
2715 | } | ||
2716 | } | ||
2717 | |||
2718 | for (hv_quirk = m3_hv_quirk_list; hv_quirk->vendor; hv_quirk++) { | ||
2719 | if (pci->vendor == hv_quirk->vendor && | ||
2720 | pci->device == hv_quirk->device && | ||
2721 | pci->subsystem_vendor == hv_quirk->subsystem_vendor && | ||
2722 | pci->subsystem_device == hv_quirk->subsystem_device) { | ||
2723 | chip->hv_quirk = hv_quirk; | ||
2724 | break; | ||
2725 | } | ||
2726 | } | ||
2727 | |||
2728 | chip->external_amp = enable_amp; | 2714 | chip->external_amp = enable_amp; |
2729 | if (amp_gpio >= 0 && amp_gpio <= 0x0f) | 2715 | if (amp_gpio >= 0 && amp_gpio <= 0x0f) |
2730 | chip->amp_gpio = amp_gpio; | 2716 | chip->amp_gpio = amp_gpio; |
2731 | else if (chip->quirk && chip->quirk->amp_gpio >= 0) | 2717 | else { |
2732 | chip->amp_gpio = chip->quirk->amp_gpio; | 2718 | quirk = snd_pci_quirk_lookup(pci, m3_amp_quirk_list); |
2733 | else if (chip->allegro_flag) | 2719 | if (quirk) { |
2734 | chip->amp_gpio = GPO_EXT_AMP_ALLEGRO; | 2720 | snd_printdd(KERN_INFO "maestro3: set amp-gpio " |
2735 | else /* presumably this is for all 'maestro3's.. */ | 2721 | "for '%s'\n", quirk->name); |
2736 | chip->amp_gpio = GPO_EXT_AMP_M3; | 2722 | chip->amp_gpio = quirk->value; |
2723 | } else if (chip->allegro_flag) | ||
2724 | chip->amp_gpio = GPO_EXT_AMP_ALLEGRO; | ||
2725 | else /* presumably this is for all 'maestro3's.. */ | ||
2726 | chip->amp_gpio = GPO_EXT_AMP_M3; | ||
2727 | } | ||
2728 | |||
2729 | quirk = snd_pci_quirk_lookup(pci, m3_irda_quirk_list); | ||
2730 | if (quirk) { | ||
2731 | snd_printdd(KERN_INFO "maestro3: enabled irda workaround " | ||
2732 | "for '%s'\n", quirk->name); | ||
2733 | chip->irda_workaround = 1; | ||
2734 | } | ||
2735 | quirk = snd_pci_quirk_lookup(pci, m3_hv_quirk_list); | ||
2736 | if (quirk) | ||
2737 | chip->hv_config = quirk->value; | ||
2738 | if (snd_pci_quirk_lookup(pci, m3_omnibook_quirk_list)) | ||
2739 | chip->is_omnibook = 1; | ||
2737 | 2740 | ||
2738 | chip->num_substreams = NR_DSPS; | 2741 | chip->num_substreams = NR_DSPS; |
2739 | chip->substreams = kcalloc(chip->num_substreams, sizeof(struct m3_dma), | 2742 | chip->substreams = kcalloc(chip->num_substreams, sizeof(struct m3_dma), |
@@ -2744,6 +2747,30 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci, | |||
2744 | return -ENOMEM; | 2747 | return -ENOMEM; |
2745 | } | 2748 | } |
2746 | 2749 | ||
2750 | err = request_firmware(&chip->assp_kernel_image, | ||
2751 | "ess/maestro3_assp_kernel.fw", &pci->dev); | ||
2752 | if (err < 0) { | ||
2753 | #ifdef FIRMWARE_IN_THE_KERNEL | ||
2754 | chip->assp_kernel_image = &assp_kernel; | ||
2755 | #else | ||
2756 | snd_m3_free(chip); | ||
2757 | return err; | ||
2758 | #endif | ||
2759 | } else | ||
2760 | snd_m3_convert_from_le(chip->assp_kernel_image); | ||
2761 | |||
2762 | err = request_firmware(&chip->assp_minisrc_image, | ||
2763 | "ess/maestro3_assp_minisrc.fw", &pci->dev); | ||
2764 | if (err < 0) { | ||
2765 | #ifdef FIRMWARE_IN_THE_KERNEL | ||
2766 | chip->assp_minisrc_image = &assp_minisrc; | ||
2767 | #else | ||
2768 | snd_m3_free(chip); | ||
2769 | return err; | ||
2770 | #endif | ||
2771 | } else | ||
2772 | snd_m3_convert_from_le(chip->assp_minisrc_image); | ||
2773 | |||
2747 | if ((err = pci_request_regions(pci, card->driver)) < 0) { | 2774 | if ((err = pci_request_regions(pci, card->driver)) < 0) { |
2748 | snd_m3_free(chip); | 2775 | snd_m3_free(chip); |
2749 | return err; | 2776 | return err; |
diff --git a/sound/pci/mixart/mixart_mixer.c b/sound/pci/mixart/mixart_mixer.c index 13de0f71d4b7..d7d15c036e02 100644 --- a/sound/pci/mixart/mixart_mixer.c +++ b/sound/pci/mixart/mixart_mixer.c | |||
@@ -389,7 +389,7 @@ static int mixart_analog_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e | |||
389 | return changed; | 389 | return changed; |
390 | } | 390 | } |
391 | 391 | ||
392 | static DECLARE_TLV_DB_SCALE(db_scale_analog, -9600, 50, 0); | 392 | static const DECLARE_TLV_DB_SCALE(db_scale_analog, -9600, 50, 0); |
393 | 393 | ||
394 | static struct snd_kcontrol_new mixart_control_analog_level = { | 394 | static struct snd_kcontrol_new mixart_control_analog_level = { |
395 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 395 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -872,7 +872,7 @@ static int mixart_pcm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem | |||
872 | return changed; | 872 | return changed; |
873 | } | 873 | } |
874 | 874 | ||
875 | static DECLARE_TLV_DB_SCALE(db_scale_digital, -10950, 50, 0); | 875 | static const DECLARE_TLV_DB_SCALE(db_scale_digital, -10950, 50, 0); |
876 | 876 | ||
877 | static struct snd_kcontrol_new snd_mixart_pcm_vol = | 877 | static struct snd_kcontrol_new snd_mixart_pcm_vol = |
878 | { | 878 | { |
diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c index 879e31a9f9c6..03b3a4792f73 100644 --- a/sound/pci/nm256/nm256.c +++ b/sound/pci/nm256/nm256.c | |||
@@ -1628,23 +1628,15 @@ __error: | |||
1628 | } | 1628 | } |
1629 | 1629 | ||
1630 | 1630 | ||
1631 | struct nm256_quirk { | ||
1632 | unsigned short vendor; | ||
1633 | unsigned short device; | ||
1634 | int type; | ||
1635 | }; | ||
1636 | |||
1637 | enum { NM_BLACKLISTED, NM_RESET_WORKAROUND, NM_RESET_WORKAROUND_2 }; | 1631 | enum { NM_BLACKLISTED, NM_RESET_WORKAROUND, NM_RESET_WORKAROUND_2 }; |
1638 | 1632 | ||
1639 | static struct nm256_quirk nm256_quirks[] __devinitdata = { | 1633 | static struct snd_pci_quirk nm256_quirks[] __devinitdata = { |
1640 | /* HP omnibook 4150 has cs4232 codec internally */ | 1634 | /* HP omnibook 4150 has cs4232 codec internally */ |
1641 | { .vendor = 0x103c, .device = 0x0007, .type = NM_BLACKLISTED }, | 1635 | SND_PCI_QUIRK(0x103c, 0x0007, "HP omnibook 4150", NM_BLACKLISTED), |
1642 | /* Sony PCG-F305 */ | 1636 | /* Reset workarounds to avoid lock-ups */ |
1643 | { .vendor = 0x104d, .device = 0x8041, .type = NM_RESET_WORKAROUND }, | 1637 | SND_PCI_QUIRK(0x104d, 0x8041, "Sony PCG-F305", NM_RESET_WORKAROUND), |
1644 | /* Dell Latitude LS */ | 1638 | SND_PCI_QUIRK(0x1028, 0x0080, "Dell Latitude LS", NM_RESET_WORKAROUND), |
1645 | { .vendor = 0x1028, .device = 0x0080, .type = NM_RESET_WORKAROUND }, | 1639 | SND_PCI_QUIRK(0x1028, 0x0091, "Dell Latitude CSx", NM_RESET_WORKAROUND_2), |
1646 | /* Dell Latitude CSx */ | ||
1647 | { .vendor = 0x1028, .device = 0x0091, .type = NM_RESET_WORKAROUND_2 }, | ||
1648 | { } /* terminator */ | 1640 | { } /* terminator */ |
1649 | }; | 1641 | }; |
1650 | 1642 | ||
@@ -1655,26 +1647,22 @@ static int __devinit snd_nm256_probe(struct pci_dev *pci, | |||
1655 | struct snd_card *card; | 1647 | struct snd_card *card; |
1656 | struct nm256 *chip; | 1648 | struct nm256 *chip; |
1657 | int err; | 1649 | int err; |
1658 | struct nm256_quirk *q; | 1650 | const struct snd_pci_quirk *q; |
1659 | u16 subsystem_vendor, subsystem_device; | 1651 | |
1660 | 1652 | q = snd_pci_quirk_lookup(pci, nm256_quirks); | |
1661 | pci_read_config_word(pci, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vendor); | 1653 | if (q) { |
1662 | pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &subsystem_device); | 1654 | snd_printdd(KERN_INFO "nm256: Enabled quirk for %s.\n", q->name); |
1663 | 1655 | switch (q->value) { | |
1664 | for (q = nm256_quirks; q->vendor; q++) { | 1656 | case NM_BLACKLISTED: |
1665 | if (q->vendor == subsystem_vendor && q->device == subsystem_device) { | 1657 | printk(KERN_INFO "nm256: The device is blacklisted. " |
1666 | switch (q->type) { | 1658 | "Loading stopped\n"); |
1667 | case NM_BLACKLISTED: | 1659 | return -ENODEV; |
1668 | printk(KERN_INFO "nm256: The device is blacklisted. " | 1660 | case NM_RESET_WORKAROUND_2: |
1669 | "Loading stopped\n"); | 1661 | reset_workaround_2 = 1; |
1670 | return -ENODEV; | 1662 | /* Fall-through */ |
1671 | case NM_RESET_WORKAROUND_2: | 1663 | case NM_RESET_WORKAROUND: |
1672 | reset_workaround_2 = 1; | 1664 | reset_workaround = 1; |
1673 | /* Fall-through */ | 1665 | break; |
1674 | case NM_RESET_WORKAROUND: | ||
1675 | reset_workaround = 1; | ||
1676 | break; | ||
1677 | } | ||
1678 | } | 1666 | } |
1679 | } | 1667 | } |
1680 | 1668 | ||
diff --git a/sound/pci/pcxhr/pcxhr_mixer.c b/sound/pci/pcxhr/pcxhr_mixer.c index b133ad9e095e..d9cc8d2beb6d 100644 --- a/sound/pci/pcxhr/pcxhr_mixer.c +++ b/sound/pci/pcxhr/pcxhr_mixer.c | |||
@@ -44,8 +44,8 @@ | |||
44 | #define PCXHR_ANALOG_PLAYBACK_LEVEL_MAX 128 /* 0.0 dB */ | 44 | #define PCXHR_ANALOG_PLAYBACK_LEVEL_MAX 128 /* 0.0 dB */ |
45 | #define PCXHR_ANALOG_PLAYBACK_ZERO_LEVEL 104 /* -24.0 dB ( 0.0 dB - fix level +24.0 dB ) */ | 45 | #define PCXHR_ANALOG_PLAYBACK_ZERO_LEVEL 104 /* -24.0 dB ( 0.0 dB - fix level +24.0 dB ) */ |
46 | 46 | ||
47 | static DECLARE_TLV_DB_SCALE(db_scale_analog_capture, -9600, 50, 0); | 47 | static const DECLARE_TLV_DB_SCALE(db_scale_analog_capture, -9600, 50, 0); |
48 | static DECLARE_TLV_DB_SCALE(db_scale_analog_playback, -12800, 100, 0); | 48 | static const DECLARE_TLV_DB_SCALE(db_scale_analog_playback, -12800, 100, 0); |
49 | 49 | ||
50 | static int pcxhr_update_analog_audio_level(struct snd_pcxhr *chip, int is_capture, int channel) | 50 | static int pcxhr_update_analog_audio_level(struct snd_pcxhr *chip, int is_capture, int channel) |
51 | { | 51 | { |
@@ -195,7 +195,7 @@ static struct snd_kcontrol_new pcxhr_control_output_switch = { | |||
195 | #define PCXHR_DIGITAL_LEVEL_MAX 0x1ff /* +18 dB */ | 195 | #define PCXHR_DIGITAL_LEVEL_MAX 0x1ff /* +18 dB */ |
196 | #define PCXHR_DIGITAL_ZERO_LEVEL 0x1b7 /* 0 dB */ | 196 | #define PCXHR_DIGITAL_ZERO_LEVEL 0x1b7 /* 0 dB */ |
197 | 197 | ||
198 | static DECLARE_TLV_DB_SCALE(db_scale_digital, -10950, 50, 0); | 198 | static const DECLARE_TLV_DB_SCALE(db_scale_digital, -10950, 50, 0); |
199 | 199 | ||
200 | #define MORE_THAN_ONE_STREAM_LEVEL 0x000001 | 200 | #define MORE_THAN_ONE_STREAM_LEVEL 0x000001 |
201 | #define VALID_STREAM_PAN_LEVEL_MASK 0x800000 | 201 | #define VALID_STREAM_PAN_LEVEL_MASK 0x800000 |
diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index 6383987b460e..89b3c7ff5037 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c | |||
@@ -80,6 +80,7 @@ MODULE_SUPPORTED_DEVICE("{{RME Hammerfall-DSP}," | |||
80 | /* Write registers. These are defined as byte-offsets from the iobase value. | 80 | /* Write registers. These are defined as byte-offsets from the iobase value. |
81 | */ | 81 | */ |
82 | #define HDSP_resetPointer 0 | 82 | #define HDSP_resetPointer 0 |
83 | #define HDSP_freqReg 0 | ||
83 | #define HDSP_outputBufferAddress 32 | 84 | #define HDSP_outputBufferAddress 32 |
84 | #define HDSP_inputBufferAddress 36 | 85 | #define HDSP_inputBufferAddress 36 |
85 | #define HDSP_controlRegister 64 | 86 | #define HDSP_controlRegister 64 |
@@ -469,6 +470,7 @@ struct hdsp { | |||
469 | struct pci_dev *pci; | 470 | struct pci_dev *pci; |
470 | struct snd_kcontrol *spdif_ctl; | 471 | struct snd_kcontrol *spdif_ctl; |
471 | unsigned short mixer_matrix[HDSP_MATRIX_MIXER_SIZE]; | 472 | unsigned short mixer_matrix[HDSP_MATRIX_MIXER_SIZE]; |
473 | unsigned int dds_value; /* last value written to freq register */ | ||
472 | }; | 474 | }; |
473 | 475 | ||
474 | /* These tables map the ALSA channels 1..N to the channels that we | 476 | /* These tables map the ALSA channels 1..N to the channels that we |
@@ -598,6 +600,7 @@ static int hdsp_playback_to_output_key (struct hdsp *hdsp, int in, int out) | |||
598 | return (64 * out) + (32 + (in)); | 600 | return (64 * out) + (32 + (in)); |
599 | case 0x96: | 601 | case 0x96: |
600 | case 0x97: | 602 | case 0x97: |
603 | case 0x98: | ||
601 | return (32 * out) + (16 + (in)); | 604 | return (32 * out) + (16 + (in)); |
602 | default: | 605 | default: |
603 | return (52 * out) + (26 + (in)); | 606 | return (52 * out) + (26 + (in)); |
@@ -611,6 +614,7 @@ static int hdsp_input_to_output_key (struct hdsp *hdsp, int in, int out) | |||
611 | return (64 * out) + in; | 614 | return (64 * out) + in; |
612 | case 0x96: | 615 | case 0x96: |
613 | case 0x97: | 616 | case 0x97: |
617 | case 0x98: | ||
614 | return (32 * out) + in; | 618 | return (32 * out) + in; |
615 | default: | 619 | default: |
616 | return (52 * out) + in; | 620 | return (52 * out) + in; |
@@ -938,6 +942,11 @@ static snd_pcm_uframes_t hdsp_hw_pointer(struct hdsp *hdsp) | |||
938 | static void hdsp_reset_hw_pointer(struct hdsp *hdsp) | 942 | static void hdsp_reset_hw_pointer(struct hdsp *hdsp) |
939 | { | 943 | { |
940 | hdsp_write (hdsp, HDSP_resetPointer, 0); | 944 | hdsp_write (hdsp, HDSP_resetPointer, 0); |
945 | if (hdsp->io_type == H9632 && hdsp->firmware_rev >= 152) | ||
946 | /* HDSP_resetPointer = HDSP_freqReg, which is strange and | ||
947 | * requires (?) to write again DDS value after a reset pointer | ||
948 | * (at least, it works like this) */ | ||
949 | hdsp_write (hdsp, HDSP_freqReg, hdsp->dds_value); | ||
941 | } | 950 | } |
942 | 951 | ||
943 | static void hdsp_start_audio(struct hdsp *s) | 952 | static void hdsp_start_audio(struct hdsp *s) |
@@ -982,6 +991,30 @@ static int hdsp_set_interrupt_interval(struct hdsp *s, unsigned int frames) | |||
982 | return 0; | 991 | return 0; |
983 | } | 992 | } |
984 | 993 | ||
994 | static void hdsp_set_dds_value(struct hdsp *hdsp, int rate) | ||
995 | { | ||
996 | u64 n; | ||
997 | u32 r; | ||
998 | |||
999 | if (rate >= 112000) | ||
1000 | rate /= 4; | ||
1001 | else if (rate >= 56000) | ||
1002 | rate /= 2; | ||
1003 | |||
1004 | /* RME says n = 104857600000000, but in the windows MADI driver, I see: | ||
1005 | // return 104857600000000 / rate; // 100 MHz | ||
1006 | return 110100480000000 / rate; // 105 MHz | ||
1007 | */ | ||
1008 | n = 104857600000000ULL; /* = 2^20 * 10^8 */ | ||
1009 | div64_32(&n, rate, &r); | ||
1010 | /* n should be less than 2^32 for being written to FREQ register */ | ||
1011 | snd_assert((n >> 32) == 0); | ||
1012 | /* HDSP_freqReg and HDSP_resetPointer are the same, so keep the DDS | ||
1013 | value to write it after a reset */ | ||
1014 | hdsp->dds_value = n; | ||
1015 | hdsp_write(hdsp, HDSP_freqReg, hdsp->dds_value); | ||
1016 | } | ||
1017 | |||
985 | static int hdsp_set_rate(struct hdsp *hdsp, int rate, int called_internally) | 1018 | static int hdsp_set_rate(struct hdsp *hdsp, int rate, int called_internally) |
986 | { | 1019 | { |
987 | int reject_if_open = 0; | 1020 | int reject_if_open = 0; |
@@ -1090,6 +1123,10 @@ static int hdsp_set_rate(struct hdsp *hdsp, int rate, int called_internally) | |||
1090 | hdsp->control_register |= rate_bits; | 1123 | hdsp->control_register |= rate_bits; |
1091 | hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); | 1124 | hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); |
1092 | 1125 | ||
1126 | /* For HDSP9632 rev 152, need to set DDS value in FREQ register */ | ||
1127 | if (hdsp->io_type == H9632 && hdsp->firmware_rev >= 152) | ||
1128 | hdsp_set_dds_value(hdsp, rate); | ||
1129 | |||
1093 | if (rate >= 128000) { | 1130 | if (rate >= 128000) { |
1094 | hdsp->channel_map = channel_map_H9632_qs; | 1131 | hdsp->channel_map = channel_map_H9632_qs; |
1095 | } else if (rate > 48000) { | 1132 | } else if (rate > 48000) { |
@@ -4943,6 +4980,7 @@ static int __devinit snd_hdsp_create(struct snd_card *card, | |||
4943 | hdsp->irq = pci->irq; | 4980 | hdsp->irq = pci->irq; |
4944 | hdsp->precise_ptr = 0; | 4981 | hdsp->precise_ptr = 0; |
4945 | hdsp->use_midi_tasklet = 1; | 4982 | hdsp->use_midi_tasklet = 1; |
4983 | hdsp->dds_value = 0; | ||
4946 | 4984 | ||
4947 | if ((err = snd_hdsp_initialize_memory(hdsp)) < 0) | 4985 | if ((err = snd_hdsp_initialize_memory(hdsp)) < 0) |
4948 | return err; | 4986 | return err; |
diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 0547f6f04bdc..e0215aca1193 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c | |||
@@ -6,6 +6,8 @@ | |||
6 | * code based on hdsp.c Paul Davis | 6 | * code based on hdsp.c Paul Davis |
7 | * Marcus Andersson | 7 | * Marcus Andersson |
8 | * Thomas Charbonnel | 8 | * Thomas Charbonnel |
9 | * Modified 2006-06-01 for AES32 support by Remy Bruno | ||
10 | * <remy.bruno@trinnov.com> | ||
9 | * | 11 | * |
10 | * This program is free software; you can redistribute it and/or modify | 12 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of the GNU General Public License as published by | 13 | * it under the terms of the GNU General Public License as published by |
@@ -77,7 +79,8 @@ MODULE_PARM_DESC(enable_monitor, | |||
77 | 79 | ||
78 | MODULE_AUTHOR | 80 | MODULE_AUTHOR |
79 | ("Winfried Ritsch <ritsch_AT_iem.at>, Paul Davis <paul@linuxaudiosystems.com>, " | 81 | ("Winfried Ritsch <ritsch_AT_iem.at>, Paul Davis <paul@linuxaudiosystems.com>, " |
80 | "Marcus Andersson, Thomas Charbonnel <thomas@undata.org>"); | 82 | "Marcus Andersson, Thomas Charbonnel <thomas@undata.org>, " |
83 | "Remy Bruno <remy.bruno@trinnov.com>"); | ||
81 | MODULE_DESCRIPTION("RME HDSPM"); | 84 | MODULE_DESCRIPTION("RME HDSPM"); |
82 | MODULE_LICENSE("GPL"); | 85 | MODULE_LICENSE("GPL"); |
83 | MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); | 86 | MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); |
@@ -107,7 +110,12 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); | |||
107 | /* --- Read registers. --- | 110 | /* --- Read registers. --- |
108 | These are defined as byte-offsets from the iobase value */ | 111 | These are defined as byte-offsets from the iobase value */ |
109 | #define HDSPM_statusRegister 0 | 112 | #define HDSPM_statusRegister 0 |
110 | #define HDSPM_statusRegister2 96 | 113 | /*#define HDSPM_statusRegister2 96 */ |
114 | /* after RME Windows driver sources, status2 is 4-byte word # 48 = word at | ||
115 | * offset 192, for AES32 *and* MADI | ||
116 | * => need to check that offset 192 is working on MADI */ | ||
117 | #define HDSPM_statusRegister2 192 | ||
118 | #define HDSPM_timecodeRegister 128 | ||
111 | 119 | ||
112 | #define HDSPM_midiDataIn0 360 | 120 | #define HDSPM_midiDataIn0 360 |
113 | #define HDSPM_midiDataIn1 364 | 121 | #define HDSPM_midiDataIn1 364 |
@@ -140,37 +148,50 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); | |||
140 | #define HDSPM_Frequency0 (1<<6) /* 0=44.1kHz/88.2kHz 1=48kHz/96kHz */ | 148 | #define HDSPM_Frequency0 (1<<6) /* 0=44.1kHz/88.2kHz 1=48kHz/96kHz */ |
141 | #define HDSPM_Frequency1 (1<<7) /* 0=32kHz/64kHz */ | 149 | #define HDSPM_Frequency1 (1<<7) /* 0=32kHz/64kHz */ |
142 | #define HDSPM_DoubleSpeed (1<<8) /* 0=normal speed, 1=double speed */ | 150 | #define HDSPM_DoubleSpeed (1<<8) /* 0=normal speed, 1=double speed */ |
143 | #define HDSPM_QuadSpeed (1<<31) /* quad speed bit, not implemented now */ | 151 | #define HDSPM_QuadSpeed (1<<31) /* quad speed bit */ |
144 | 152 | ||
153 | #define HDSPM_Professional (1<<9) /* Professional */ /* AES32 ONLY */ | ||
145 | #define HDSPM_TX_64ch (1<<10) /* Output 64channel MODE=1, | 154 | #define HDSPM_TX_64ch (1<<10) /* Output 64channel MODE=1, |
146 | 56channelMODE=0 */ | 155 | 56channelMODE=0 */ /* MADI ONLY*/ |
156 | #define HDSPM_Emphasis (1<<10) /* Emphasis */ /* AES32 ONLY */ | ||
147 | 157 | ||
148 | #define HDSPM_AutoInp (1<<11) /* Auto Input (takeover) == Safe Mode, | 158 | #define HDSPM_AutoInp (1<<11) /* Auto Input (takeover) == Safe Mode, |
149 | 0=off, 1=on */ | 159 | 0=off, 1=on */ /* MADI ONLY */ |
160 | #define HDSPM_Dolby (1<<11) /* Dolby = "NonAudio" ?? */ /* AES32 ONLY */ | ||
150 | 161 | ||
151 | #define HDSPM_InputSelect0 (1<<14) /* Input select 0= optical, 1=coax */ | 162 | #define HDSPM_InputSelect0 (1<<14) /* Input select 0= optical, 1=coax */ /* MADI ONLY*/ |
152 | #define HDSPM_InputSelect1 (1<<15) /* should be 0 */ | 163 | #define HDSPM_InputSelect1 (1<<15) /* should be 0 */ |
153 | 164 | ||
154 | #define HDSPM_SyncRef0 (1<<16) /* 0=WOrd, 1=MADI */ | 165 | #define HDSPM_SyncRef0 (1<<16) /* 0=WOrd, 1=MADI */ |
155 | #define HDSPM_SyncRef1 (1<<17) /* should be 0 */ | 166 | #define HDSPM_SyncRef1 (1<<17) /* for AES32: SyncRefN codes the AES # */ |
167 | #define HDSPM_SyncRef2 (1<<13) | ||
168 | #define HDSPM_SyncRef3 (1<<25) | ||
156 | 169 | ||
170 | #define HDSPM_SMUX (1<<18) /* Frame ??? */ /* MADI ONY */ | ||
157 | #define HDSPM_clr_tms (1<<19) /* clear track marker, do not use | 171 | #define HDSPM_clr_tms (1<<19) /* clear track marker, do not use |
158 | AES additional bits in | 172 | AES additional bits in |
159 | lower 5 Audiodatabits ??? */ | 173 | lower 5 Audiodatabits ??? */ |
174 | #define HDSPM_taxi_reset (1<<20) /* ??? */ /* MADI ONLY ? */ | ||
175 | #define HDSPM_WCK48 (1<<20) /* Frame ??? = HDSPM_SMUX */ /* AES32 ONLY */ | ||
160 | 176 | ||
161 | #define HDSPM_Midi0InterruptEnable (1<<22) | 177 | #define HDSPM_Midi0InterruptEnable (1<<22) |
162 | #define HDSPM_Midi1InterruptEnable (1<<23) | 178 | #define HDSPM_Midi1InterruptEnable (1<<23) |
163 | 179 | ||
164 | #define HDSPM_LineOut (1<<24) /* Analog Out on channel 63/64 on=1, mute=0 */ | 180 | #define HDSPM_LineOut (1<<24) /* Analog Out on channel 63/64 on=1, mute=0 */ |
165 | 181 | ||
182 | #define HDSPM_DS_DoubleWire (1<<26) /* AES32 ONLY */ | ||
183 | #define HDSPM_QS_DoubleWire (1<<27) /* AES32 ONLY */ | ||
184 | #define HDSPM_QS_QuadWire (1<<28) /* AES32 ONLY */ | ||
185 | |||
186 | #define HDSPM_wclk_sel (1<<30) | ||
166 | 187 | ||
167 | /* --- bit helper defines */ | 188 | /* --- bit helper defines */ |
168 | #define HDSPM_LatencyMask (HDSPM_Latency0|HDSPM_Latency1|HDSPM_Latency2) | 189 | #define HDSPM_LatencyMask (HDSPM_Latency0|HDSPM_Latency1|HDSPM_Latency2) |
169 | #define HDSPM_FrequencyMask (HDSPM_Frequency0|HDSPM_Frequency1) | 190 | #define HDSPM_FrequencyMask (HDSPM_Frequency0|HDSPM_Frequency1|HDSPM_DoubleSpeed|HDSPM_QuadSpeed) |
170 | #define HDSPM_InputMask (HDSPM_InputSelect0|HDSPM_InputSelect1) | 191 | #define HDSPM_InputMask (HDSPM_InputSelect0|HDSPM_InputSelect1) |
171 | #define HDSPM_InputOptical 0 | 192 | #define HDSPM_InputOptical 0 |
172 | #define HDSPM_InputCoaxial (HDSPM_InputSelect0) | 193 | #define HDSPM_InputCoaxial (HDSPM_InputSelect0) |
173 | #define HDSPM_SyncRefMask (HDSPM_SyncRef0|HDSPM_SyncRef1) | 194 | #define HDSPM_SyncRefMask (HDSPM_SyncRef0|HDSPM_SyncRef1|HDSPM_SyncRef2|HDSPM_SyncRef3) |
174 | #define HDSPM_SyncRef_Word 0 | 195 | #define HDSPM_SyncRef_Word 0 |
175 | #define HDSPM_SyncRef_MADI (HDSPM_SyncRef0) | 196 | #define HDSPM_SyncRef_MADI (HDSPM_SyncRef0) |
176 | 197 | ||
@@ -183,6 +204,9 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); | |||
183 | #define HDSPM_Frequency64KHz (HDSPM_DoubleSpeed|HDSPM_Frequency0) | 204 | #define HDSPM_Frequency64KHz (HDSPM_DoubleSpeed|HDSPM_Frequency0) |
184 | #define HDSPM_Frequency88_2KHz (HDSPM_DoubleSpeed|HDSPM_Frequency1) | 205 | #define HDSPM_Frequency88_2KHz (HDSPM_DoubleSpeed|HDSPM_Frequency1) |
185 | #define HDSPM_Frequency96KHz (HDSPM_DoubleSpeed|HDSPM_Frequency1|HDSPM_Frequency0) | 206 | #define HDSPM_Frequency96KHz (HDSPM_DoubleSpeed|HDSPM_Frequency1|HDSPM_Frequency0) |
207 | #define HDSPM_Frequency128KHz (HDSPM_QuadSpeed|HDSPM_Frequency0) | ||
208 | #define HDSPM_Frequency176_4KHz (HDSPM_QuadSpeed|HDSPM_Frequency1) | ||
209 | #define HDSPM_Frequency192KHz (HDSPM_QuadSpeed|HDSPM_Frequency1|HDSPM_Frequency0) | ||
186 | 210 | ||
187 | /* --- for internal discrimination */ | 211 | /* --- for internal discrimination */ |
188 | #define HDSPM_CLOCK_SOURCE_AUTOSYNC 0 /* Sample Clock Sources */ | 212 | #define HDSPM_CLOCK_SOURCE_AUTOSYNC 0 /* Sample Clock Sources */ |
@@ -229,7 +253,8 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); | |||
229 | #define HDSPM_BIGENDIAN_MODE (1<<9) | 253 | #define HDSPM_BIGENDIAN_MODE (1<<9) |
230 | #define HDSPM_RD_MULTIPLE (1<<10) | 254 | #define HDSPM_RD_MULTIPLE (1<<10) |
231 | 255 | ||
232 | /* --- Status Register bits --- */ | 256 | /* --- Status Register bits --- */ /* MADI ONLY */ /* Bits defined here and |
257 | that do not conflict with specific bits for AES32 seem to be valid also for the AES32 */ | ||
233 | #define HDSPM_audioIRQPending (1<<0) /* IRQ is high and pending */ | 258 | #define HDSPM_audioIRQPending (1<<0) /* IRQ is high and pending */ |
234 | #define HDSPM_RX_64ch (1<<1) /* Input 64chan. MODE=1, 56chn. MODE=0 */ | 259 | #define HDSPM_RX_64ch (1<<1) /* Input 64chan. MODE=1, 56chn. MODE=0 */ |
235 | #define HDSPM_AB_int (1<<2) /* InputChannel Opt=0, Coax=1 (like inp0) */ | 260 | #define HDSPM_AB_int (1<<2) /* InputChannel Opt=0, Coax=1 (like inp0) */ |
@@ -263,7 +288,7 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); | |||
263 | #define HDSPM_madiFreq176_4 (HDSPM_madiFreq3) | 288 | #define HDSPM_madiFreq176_4 (HDSPM_madiFreq3) |
264 | #define HDSPM_madiFreq192 (HDSPM_madiFreq3|HDSPM_madiFreq0) | 289 | #define HDSPM_madiFreq192 (HDSPM_madiFreq3|HDSPM_madiFreq0) |
265 | 290 | ||
266 | /* Status2 Register bits */ | 291 | /* Status2 Register bits */ /* MADI ONLY */ |
267 | 292 | ||
268 | #define HDSPM_version0 (1<<0) /* not realy defined but I guess */ | 293 | #define HDSPM_version0 (1<<0) /* not realy defined but I guess */ |
269 | #define HDSPM_version1 (1<<1) /* in former cards it was ??? */ | 294 | #define HDSPM_version1 (1<<1) /* in former cards it was ??? */ |
@@ -297,6 +322,56 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); | |||
297 | #define HDSPM_SelSyncRef_MADI (HDSPM_SelSyncRef0) | 322 | #define HDSPM_SelSyncRef_MADI (HDSPM_SelSyncRef0) |
298 | #define HDSPM_SelSyncRef_NVALID (HDSPM_SelSyncRef0|HDSPM_SelSyncRef1|HDSPM_SelSyncRef2) | 323 | #define HDSPM_SelSyncRef_NVALID (HDSPM_SelSyncRef0|HDSPM_SelSyncRef1|HDSPM_SelSyncRef2) |
299 | 324 | ||
325 | /* | ||
326 | For AES32, bits for status, status2 and timecode are different | ||
327 | */ | ||
328 | /* status */ | ||
329 | #define HDSPM_AES32_wcLock 0x0200000 | ||
330 | #define HDSPM_AES32_wcFreq_bit 22 | ||
331 | /* (status >> HDSPM_AES32_wcFreq_bit) & 0xF gives WC frequency (cf function | ||
332 | HDSPM_bit2freq */ | ||
333 | #define HDSPM_AES32_syncref_bit 16 | ||
334 | /* (status >> HDSPM_AES32_syncref_bit) & 0xF gives sync source */ | ||
335 | |||
336 | #define HDSPM_AES32_AUTOSYNC_FROM_WORD 0 | ||
337 | #define HDSPM_AES32_AUTOSYNC_FROM_AES1 1 | ||
338 | #define HDSPM_AES32_AUTOSYNC_FROM_AES2 2 | ||
339 | #define HDSPM_AES32_AUTOSYNC_FROM_AES3 3 | ||
340 | #define HDSPM_AES32_AUTOSYNC_FROM_AES4 4 | ||
341 | #define HDSPM_AES32_AUTOSYNC_FROM_AES5 5 | ||
342 | #define HDSPM_AES32_AUTOSYNC_FROM_AES6 6 | ||
343 | #define HDSPM_AES32_AUTOSYNC_FROM_AES7 7 | ||
344 | #define HDSPM_AES32_AUTOSYNC_FROM_AES8 8 | ||
345 | #define HDSPM_AES32_AUTOSYNC_FROM_NONE -1 | ||
346 | |||
347 | /* status2 */ | ||
348 | /* HDSPM_LockAES_bit is given by HDSPM_LockAES >> (AES# - 1) */ | ||
349 | #define HDSPM_LockAES 0x80 | ||
350 | #define HDSPM_LockAES1 0x80 | ||
351 | #define HDSPM_LockAES2 0x40 | ||
352 | #define HDSPM_LockAES3 0x20 | ||
353 | #define HDSPM_LockAES4 0x10 | ||
354 | #define HDSPM_LockAES5 0x8 | ||
355 | #define HDSPM_LockAES6 0x4 | ||
356 | #define HDSPM_LockAES7 0x2 | ||
357 | #define HDSPM_LockAES8 0x1 | ||
358 | /* | ||
359 | Timecode | ||
360 | After windows driver sources, bits 4*i to 4*i+3 give the input frequency on | ||
361 | AES i+1 | ||
362 | bits 3210 | ||
363 | 0001 32kHz | ||
364 | 0010 44.1kHz | ||
365 | 0011 48kHz | ||
366 | 0100 64kHz | ||
367 | 0101 88.2kHz | ||
368 | 0110 96kHz | ||
369 | 0111 128kHz | ||
370 | 1000 176.4kHz | ||
371 | 1001 192kHz | ||
372 | NB: Timecode register doesn't seem to work on AES32 card revision 230 | ||
373 | */ | ||
374 | |||
300 | /* Mixer Values */ | 375 | /* Mixer Values */ |
301 | #define UNITY_GAIN 32768 /* = 65536/2 */ | 376 | #define UNITY_GAIN 32768 /* = 65536/2 */ |
302 | #define MINUS_INFINITY_GAIN 0 | 377 | #define MINUS_INFINITY_GAIN 0 |
@@ -314,10 +389,14 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); | |||
314 | size is the same regardless of the number of channels, and | 389 | size is the same regardless of the number of channels, and |
315 | also the latency to use. | 390 | also the latency to use. |
316 | for one direction !!! | 391 | for one direction !!! |
392 | => need to mupltiply by 2!! | ||
317 | */ | 393 | */ |
318 | #define HDSPM_DMA_AREA_BYTES (HDSPM_MAX_CHANNELS * HDSPM_CHANNEL_BUFFER_BYTES) | 394 | #define HDSPM_DMA_AREA_BYTES (2 * HDSPM_MAX_CHANNELS * HDSPM_CHANNEL_BUFFER_BYTES) |
319 | #define HDSPM_DMA_AREA_KILOBYTES (HDSPM_DMA_AREA_BYTES/1024) | 395 | #define HDSPM_DMA_AREA_KILOBYTES (HDSPM_DMA_AREA_BYTES/1024) |
320 | 396 | ||
397 | /* revisions >= 230 indicate AES32 card */ | ||
398 | #define HDSPM_AESREVISION 230 | ||
399 | |||
321 | struct hdspm_midi { | 400 | struct hdspm_midi { |
322 | struct hdspm *hdspm; | 401 | struct hdspm *hdspm; |
323 | int id; | 402 | int id; |
@@ -336,7 +415,9 @@ struct hdspm { | |||
336 | struct snd_pcm_substream *playback_substream; /* and/or capture stream */ | 415 | struct snd_pcm_substream *playback_substream; /* and/or capture stream */ |
337 | 416 | ||
338 | char *card_name; /* for procinfo */ | 417 | char *card_name; /* for procinfo */ |
339 | unsigned short firmware_rev; /* dont know if relevant */ | 418 | unsigned short firmware_rev; /* dont know if relevant (yes if AES32)*/ |
419 | |||
420 | unsigned char is_aes32; /* indicates if card is AES32 */ | ||
340 | 421 | ||
341 | int precise_ptr; /* use precise pointers, to be tested */ | 422 | int precise_ptr; /* use precise pointers, to be tested */ |
342 | int monitor_outs; /* set up monitoring outs init flag */ | 423 | int monitor_outs; /* set up monitoring outs init flag */ |
@@ -453,6 +534,15 @@ static int snd_hdspm_set_defaults(struct hdspm * hdspm); | |||
453 | static void hdspm_set_sgbuf(struct hdspm * hdspm, struct snd_sg_buf *sgbuf, | 534 | static void hdspm_set_sgbuf(struct hdspm * hdspm, struct snd_sg_buf *sgbuf, |
454 | unsigned int reg, int channels); | 535 | unsigned int reg, int channels); |
455 | 536 | ||
537 | static inline int HDSPM_bit2freq(int n) | ||
538 | { | ||
539 | static int bit2freq_tab[] = { 0, 32000, 44100, 48000, 64000, 88200, | ||
540 | 96000, 128000, 176400, 192000 }; | ||
541 | if (n < 1 || n > 9) | ||
542 | return 0; | ||
543 | return bit2freq_tab[n]; | ||
544 | } | ||
545 | |||
456 | /* Write/read to/from HDSPM with Adresses in Bytes | 546 | /* Write/read to/from HDSPM with Adresses in Bytes |
457 | not words but only 32Bit writes are allowed */ | 547 | not words but only 32Bit writes are allowed */ |
458 | 548 | ||
@@ -544,86 +634,105 @@ static inline int snd_hdspm_use_is_exclusive(struct hdspm * hdspm) | |||
544 | /* check for external sample rate */ | 634 | /* check for external sample rate */ |
545 | static inline int hdspm_external_sample_rate(struct hdspm * hdspm) | 635 | static inline int hdspm_external_sample_rate(struct hdspm * hdspm) |
546 | { | 636 | { |
547 | unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2); | 637 | if (hdspm->is_aes32) { |
548 | unsigned int status = hdspm_read(hdspm, HDSPM_statusRegister); | 638 | unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2); |
549 | unsigned int rate_bits; | 639 | unsigned int status = hdspm_read(hdspm, HDSPM_statusRegister); |
550 | int rate = 0; | 640 | unsigned int timecode = hdspm_read(hdspm, HDSPM_timecodeRegister); |
641 | |||
642 | int syncref = hdspm_autosync_ref(hdspm); | ||
643 | |||
644 | if (syncref == HDSPM_AES32_AUTOSYNC_FROM_WORD && | ||
645 | status & HDSPM_AES32_wcLock) | ||
646 | return HDSPM_bit2freq((status >> HDSPM_AES32_wcFreq_bit) & 0xF); | ||
647 | if (syncref >= HDSPM_AES32_AUTOSYNC_FROM_AES1 && | ||
648 | syncref <= HDSPM_AES32_AUTOSYNC_FROM_AES8 && | ||
649 | status2 & (HDSPM_LockAES >> | ||
650 | (syncref - HDSPM_AES32_AUTOSYNC_FROM_AES1))) | ||
651 | return HDSPM_bit2freq((timecode >> | ||
652 | (4*(syncref-HDSPM_AES32_AUTOSYNC_FROM_AES1))) & 0xF); | ||
653 | return 0; | ||
654 | } else { | ||
655 | unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2); | ||
656 | unsigned int status = hdspm_read(hdspm, HDSPM_statusRegister); | ||
657 | unsigned int rate_bits; | ||
658 | int rate = 0; | ||
551 | 659 | ||
552 | /* if wordclock has synced freq and wordclock is valid */ | 660 | /* if wordclock has synced freq and wordclock is valid */ |
553 | if ((status2 & HDSPM_wcLock) != 0 && | 661 | if ((status2 & HDSPM_wcLock) != 0 && |
554 | (status & HDSPM_SelSyncRef0) == 0) { | 662 | (status & HDSPM_SelSyncRef0) == 0) { |
555 | 663 | ||
556 | rate_bits = status2 & HDSPM_wcFreqMask; | 664 | rate_bits = status2 & HDSPM_wcFreqMask; |
557 | 665 | ||
558 | switch (rate_bits) { | 666 | switch (rate_bits) { |
559 | case HDSPM_wcFreq32: | 667 | case HDSPM_wcFreq32: |
560 | rate = 32000; | 668 | rate = 32000; |
561 | break; | 669 | break; |
562 | case HDSPM_wcFreq44_1: | 670 | case HDSPM_wcFreq44_1: |
563 | rate = 44100; | 671 | rate = 44100; |
564 | break; | 672 | break; |
565 | case HDSPM_wcFreq48: | 673 | case HDSPM_wcFreq48: |
566 | rate = 48000; | 674 | rate = 48000; |
567 | break; | 675 | break; |
568 | case HDSPM_wcFreq64: | 676 | case HDSPM_wcFreq64: |
569 | rate = 64000; | 677 | rate = 64000; |
570 | break; | 678 | break; |
571 | case HDSPM_wcFreq88_2: | 679 | case HDSPM_wcFreq88_2: |
572 | rate = 88200; | 680 | rate = 88200; |
573 | break; | 681 | break; |
574 | case HDSPM_wcFreq96: | 682 | case HDSPM_wcFreq96: |
575 | rate = 96000; | 683 | rate = 96000; |
576 | break; | 684 | break; |
577 | /* Quadspeed Bit missing ???? */ | 685 | /* Quadspeed Bit missing ???? */ |
578 | default: | 686 | default: |
579 | rate = 0; | 687 | rate = 0; |
580 | break; | 688 | break; |
689 | } | ||
581 | } | 690 | } |
582 | } | ||
583 | 691 | ||
584 | /* if rate detected and Syncref is Word than have it, word has priority to MADI */ | 692 | /* if rate detected and Syncref is Word than have it, word has priority to MADI */ |
585 | if (rate != 0 | 693 | if (rate != 0 && |
586 | && (status2 & HDSPM_SelSyncRefMask) == HDSPM_SelSyncRef_WORD) | 694 | (status2 & HDSPM_SelSyncRefMask) == HDSPM_SelSyncRef_WORD) |
587 | return rate; | 695 | return rate; |
588 | 696 | ||
589 | /* maby a madi input (which is taken if sel sync is madi) */ | 697 | /* maby a madi input (which is taken if sel sync is madi) */ |
590 | if (status & HDSPM_madiLock) { | 698 | if (status & HDSPM_madiLock) { |
591 | rate_bits = status & HDSPM_madiFreqMask; | 699 | rate_bits = status & HDSPM_madiFreqMask; |
592 | 700 | ||
593 | switch (rate_bits) { | 701 | switch (rate_bits) { |
594 | case HDSPM_madiFreq32: | 702 | case HDSPM_madiFreq32: |
595 | rate = 32000; | 703 | rate = 32000; |
596 | break; | 704 | break; |
597 | case HDSPM_madiFreq44_1: | 705 | case HDSPM_madiFreq44_1: |
598 | rate = 44100; | 706 | rate = 44100; |
599 | break; | 707 | break; |
600 | case HDSPM_madiFreq48: | 708 | case HDSPM_madiFreq48: |
601 | rate = 48000; | 709 | rate = 48000; |
602 | break; | 710 | break; |
603 | case HDSPM_madiFreq64: | 711 | case HDSPM_madiFreq64: |
604 | rate = 64000; | 712 | rate = 64000; |
605 | break; | 713 | break; |
606 | case HDSPM_madiFreq88_2: | 714 | case HDSPM_madiFreq88_2: |
607 | rate = 88200; | 715 | rate = 88200; |
608 | break; | 716 | break; |
609 | case HDSPM_madiFreq96: | 717 | case HDSPM_madiFreq96: |
610 | rate = 96000; | 718 | rate = 96000; |
611 | break; | 719 | break; |
612 | case HDSPM_madiFreq128: | 720 | case HDSPM_madiFreq128: |
613 | rate = 128000; | 721 | rate = 128000; |
614 | break; | 722 | break; |
615 | case HDSPM_madiFreq176_4: | 723 | case HDSPM_madiFreq176_4: |
616 | rate = 176400; | 724 | rate = 176400; |
617 | break; | 725 | break; |
618 | case HDSPM_madiFreq192: | 726 | case HDSPM_madiFreq192: |
619 | rate = 192000; | 727 | rate = 192000; |
620 | break; | 728 | break; |
621 | default: | 729 | default: |
622 | rate = 0; | 730 | rate = 0; |
623 | break; | 731 | break; |
732 | } | ||
624 | } | 733 | } |
734 | return rate; | ||
625 | } | 735 | } |
626 | return rate; | ||
627 | } | 736 | } |
628 | 737 | ||
629 | /* Latency function */ | 738 | /* Latency function */ |
@@ -676,7 +785,8 @@ static inline void hdspm_silence_playback(struct hdspm * hdspm) | |||
676 | int n = hdspm->period_bytes; | 785 | int n = hdspm->period_bytes; |
677 | void *buf = hdspm->playback_buffer; | 786 | void *buf = hdspm->playback_buffer; |
678 | 787 | ||
679 | snd_assert(buf != NULL, return); | 788 | if (buf == NULL) |
789 | return; | ||
680 | 790 | ||
681 | for (i = 0; i < HDSPM_MAX_CHANNELS; i++) { | 791 | for (i = 0; i < HDSPM_MAX_CHANNELS; i++) { |
682 | memset(buf, 0, n); | 792 | memset(buf, 0, n); |
@@ -716,6 +826,7 @@ static int hdspm_set_rate(struct hdspm * hdspm, int rate, int called_internally) | |||
716 | int current_rate; | 826 | int current_rate; |
717 | int rate_bits; | 827 | int rate_bits; |
718 | int not_set = 0; | 828 | int not_set = 0; |
829 | int is_single, is_double, is_quad; | ||
719 | 830 | ||
720 | /* ASSUMPTION: hdspm->lock is either set, or there is no need for | 831 | /* ASSUMPTION: hdspm->lock is either set, or there is no need for |
721 | it (e.g. during module initialization). | 832 | it (e.g. during module initialization). |
@@ -766,43 +877,56 @@ static int hdspm_set_rate(struct hdspm * hdspm, int rate, int called_internally) | |||
766 | changes in the read/write routines. | 877 | changes in the read/write routines. |
767 | */ | 878 | */ |
768 | 879 | ||
880 | is_single = (current_rate <= 48000); | ||
881 | is_double = (current_rate > 48000 && current_rate <= 96000); | ||
882 | is_quad = (current_rate > 96000); | ||
883 | |||
769 | switch (rate) { | 884 | switch (rate) { |
770 | case 32000: | 885 | case 32000: |
771 | if (current_rate > 48000) { | 886 | if (!is_single) |
772 | reject_if_open = 1; | 887 | reject_if_open = 1; |
773 | } | ||
774 | rate_bits = HDSPM_Frequency32KHz; | 888 | rate_bits = HDSPM_Frequency32KHz; |
775 | break; | 889 | break; |
776 | case 44100: | 890 | case 44100: |
777 | if (current_rate > 48000) { | 891 | if (!is_single) |
778 | reject_if_open = 1; | 892 | reject_if_open = 1; |
779 | } | ||
780 | rate_bits = HDSPM_Frequency44_1KHz; | 893 | rate_bits = HDSPM_Frequency44_1KHz; |
781 | break; | 894 | break; |
782 | case 48000: | 895 | case 48000: |
783 | if (current_rate > 48000) { | 896 | if (!is_single) |
784 | reject_if_open = 1; | 897 | reject_if_open = 1; |
785 | } | ||
786 | rate_bits = HDSPM_Frequency48KHz; | 898 | rate_bits = HDSPM_Frequency48KHz; |
787 | break; | 899 | break; |
788 | case 64000: | 900 | case 64000: |
789 | if (current_rate <= 48000) { | 901 | if (!is_double) |
790 | reject_if_open = 1; | 902 | reject_if_open = 1; |
791 | } | ||
792 | rate_bits = HDSPM_Frequency64KHz; | 903 | rate_bits = HDSPM_Frequency64KHz; |
793 | break; | 904 | break; |
794 | case 88200: | 905 | case 88200: |
795 | if (current_rate <= 48000) { | 906 | if (!is_double) |
796 | reject_if_open = 1; | 907 | reject_if_open = 1; |
797 | } | ||
798 | rate_bits = HDSPM_Frequency88_2KHz; | 908 | rate_bits = HDSPM_Frequency88_2KHz; |
799 | break; | 909 | break; |
800 | case 96000: | 910 | case 96000: |
801 | if (current_rate <= 48000) { | 911 | if (!is_double) |
802 | reject_if_open = 1; | 912 | reject_if_open = 1; |
803 | } | ||
804 | rate_bits = HDSPM_Frequency96KHz; | 913 | rate_bits = HDSPM_Frequency96KHz; |
805 | break; | 914 | break; |
915 | case 128000: | ||
916 | if (!is_quad) | ||
917 | reject_if_open = 1; | ||
918 | rate_bits = HDSPM_Frequency128KHz; | ||
919 | break; | ||
920 | case 176400: | ||
921 | if (!is_quad) | ||
922 | reject_if_open = 1; | ||
923 | rate_bits = HDSPM_Frequency176_4KHz; | ||
924 | break; | ||
925 | case 192000: | ||
926 | if (!is_quad) | ||
927 | reject_if_open = 1; | ||
928 | rate_bits = HDSPM_Frequency192KHz; | ||
929 | break; | ||
806 | default: | 930 | default: |
807 | return -EINVAL; | 931 | return -EINVAL; |
808 | } | 932 | } |
@@ -819,7 +943,7 @@ static int hdspm_set_rate(struct hdspm * hdspm, int rate, int called_internally) | |||
819 | hdspm->control_register |= rate_bits; | 943 | hdspm->control_register |= rate_bits; |
820 | hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); | 944 | hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); |
821 | 945 | ||
822 | if (rate > 64000) | 946 | if (rate > 96000 /* 64000*/) |
823 | hdspm->channel_map = channel_map_madi_qs; | 947 | hdspm->channel_map = channel_map_madi_qs; |
824 | else if (rate > 48000) | 948 | else if (rate > 48000) |
825 | hdspm->channel_map = channel_map_madi_ds; | 949 | hdspm->channel_map = channel_map_madi_ds; |
@@ -1455,11 +1579,27 @@ static int hdspm_pref_sync_ref(struct hdspm * hdspm) | |||
1455 | /* Notice that this looks at the requested sync source, | 1579 | /* Notice that this looks at the requested sync source, |
1456 | not the one actually in use. | 1580 | not the one actually in use. |
1457 | */ | 1581 | */ |
1458 | switch (hdspm->control_register & HDSPM_SyncRefMask) { | 1582 | if (hdspm->is_aes32) { |
1459 | case HDSPM_SyncRef_Word: | 1583 | switch (hdspm->control_register & HDSPM_SyncRefMask) { |
1460 | return HDSPM_SYNC_FROM_WORD; | 1584 | /* number gives AES index, except for 0 which |
1461 | case HDSPM_SyncRef_MADI: | 1585 | corresponds to WordClock */ |
1462 | return HDSPM_SYNC_FROM_MADI; | 1586 | case 0: return 0; |
1587 | case HDSPM_SyncRef0: return 1; | ||
1588 | case HDSPM_SyncRef1: return 2; | ||
1589 | case HDSPM_SyncRef1+HDSPM_SyncRef0: return 3; | ||
1590 | case HDSPM_SyncRef2: return 4; | ||
1591 | case HDSPM_SyncRef2+HDSPM_SyncRef0: return 5; | ||
1592 | case HDSPM_SyncRef2+HDSPM_SyncRef1: return 6; | ||
1593 | case HDSPM_SyncRef2+HDSPM_SyncRef1+HDSPM_SyncRef0: return 7; | ||
1594 | case HDSPM_SyncRef3: return 8; | ||
1595 | } | ||
1596 | } else { | ||
1597 | switch (hdspm->control_register & HDSPM_SyncRefMask) { | ||
1598 | case HDSPM_SyncRef_Word: | ||
1599 | return HDSPM_SYNC_FROM_WORD; | ||
1600 | case HDSPM_SyncRef_MADI: | ||
1601 | return HDSPM_SYNC_FROM_MADI; | ||
1602 | } | ||
1463 | } | 1603 | } |
1464 | 1604 | ||
1465 | return HDSPM_SYNC_FROM_WORD; | 1605 | return HDSPM_SYNC_FROM_WORD; |
@@ -1469,15 +1609,49 @@ static int hdspm_set_pref_sync_ref(struct hdspm * hdspm, int pref) | |||
1469 | { | 1609 | { |
1470 | hdspm->control_register &= ~HDSPM_SyncRefMask; | 1610 | hdspm->control_register &= ~HDSPM_SyncRefMask; |
1471 | 1611 | ||
1472 | switch (pref) { | 1612 | if (hdspm->is_aes32) { |
1473 | case HDSPM_SYNC_FROM_MADI: | 1613 | switch (pref) { |
1474 | hdspm->control_register |= HDSPM_SyncRef_MADI; | 1614 | case 0: |
1475 | break; | 1615 | hdspm->control_register |= 0; |
1476 | case HDSPM_SYNC_FROM_WORD: | 1616 | break; |
1477 | hdspm->control_register |= HDSPM_SyncRef_Word; | 1617 | case 1: |
1478 | break; | 1618 | hdspm->control_register |= HDSPM_SyncRef0; |
1479 | default: | 1619 | break; |
1480 | return -1; | 1620 | case 2: |
1621 | hdspm->control_register |= HDSPM_SyncRef1; | ||
1622 | break; | ||
1623 | case 3: | ||
1624 | hdspm->control_register |= HDSPM_SyncRef1+HDSPM_SyncRef0; | ||
1625 | break; | ||
1626 | case 4: | ||
1627 | hdspm->control_register |= HDSPM_SyncRef2; | ||
1628 | break; | ||
1629 | case 5: | ||
1630 | hdspm->control_register |= HDSPM_SyncRef2+HDSPM_SyncRef0; | ||
1631 | break; | ||
1632 | case 6: | ||
1633 | hdspm->control_register |= HDSPM_SyncRef2+HDSPM_SyncRef1; | ||
1634 | break; | ||
1635 | case 7: | ||
1636 | hdspm->control_register |= HDSPM_SyncRef2+HDSPM_SyncRef1+HDSPM_SyncRef0; | ||
1637 | break; | ||
1638 | case 8: | ||
1639 | hdspm->control_register |= HDSPM_SyncRef3; | ||
1640 | break; | ||
1641 | default: | ||
1642 | return -1; | ||
1643 | } | ||
1644 | } else { | ||
1645 | switch (pref) { | ||
1646 | case HDSPM_SYNC_FROM_MADI: | ||
1647 | hdspm->control_register |= HDSPM_SyncRef_MADI; | ||
1648 | break; | ||
1649 | case HDSPM_SYNC_FROM_WORD: | ||
1650 | hdspm->control_register |= HDSPM_SyncRef_Word; | ||
1651 | break; | ||
1652 | default: | ||
1653 | return -1; | ||
1654 | } | ||
1481 | } | 1655 | } |
1482 | hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); | 1656 | hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); |
1483 | return 0; | 1657 | return 0; |
@@ -1486,18 +1660,36 @@ static int hdspm_set_pref_sync_ref(struct hdspm * hdspm, int pref) | |||
1486 | static int snd_hdspm_info_pref_sync_ref(struct snd_kcontrol *kcontrol, | 1660 | static int snd_hdspm_info_pref_sync_ref(struct snd_kcontrol *kcontrol, |
1487 | struct snd_ctl_elem_info *uinfo) | 1661 | struct snd_ctl_elem_info *uinfo) |
1488 | { | 1662 | { |
1489 | static char *texts[] = { "Word", "MADI" }; | 1663 | struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); |
1490 | 1664 | ||
1491 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 1665 | if (hdspm->is_aes32) { |
1492 | uinfo->count = 1; | 1666 | static char *texts[] = { "Word", "AES1", "AES2", "AES3", |
1667 | "AES4", "AES5", "AES6", "AES7", "AES8" }; | ||
1493 | 1668 | ||
1494 | uinfo->value.enumerated.items = 2; | 1669 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; |
1670 | uinfo->count = 1; | ||
1495 | 1671 | ||
1496 | if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) | 1672 | uinfo->value.enumerated.items = 9; |
1497 | uinfo->value.enumerated.item = | 1673 | |
1498 | uinfo->value.enumerated.items - 1; | 1674 | if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) |
1499 | strcpy(uinfo->value.enumerated.name, | 1675 | uinfo->value.enumerated.item = |
1500 | texts[uinfo->value.enumerated.item]); | 1676 | uinfo->value.enumerated.items - 1; |
1677 | strcpy(uinfo->value.enumerated.name, | ||
1678 | texts[uinfo->value.enumerated.item]); | ||
1679 | } else { | ||
1680 | static char *texts[] = { "Word", "MADI" }; | ||
1681 | |||
1682 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
1683 | uinfo->count = 1; | ||
1684 | |||
1685 | uinfo->value.enumerated.items = 2; | ||
1686 | |||
1687 | if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) | ||
1688 | uinfo->value.enumerated.item = | ||
1689 | uinfo->value.enumerated.items - 1; | ||
1690 | strcpy(uinfo->value.enumerated.name, | ||
1691 | texts[uinfo->value.enumerated.item]); | ||
1692 | } | ||
1501 | return 0; | 1693 | return 0; |
1502 | } | 1694 | } |
1503 | 1695 | ||
@@ -1517,7 +1709,7 @@ static int snd_hdspm_put_pref_sync_ref(struct snd_kcontrol *kcontrol, | |||
1517 | int change, max; | 1709 | int change, max; |
1518 | unsigned int val; | 1710 | unsigned int val; |
1519 | 1711 | ||
1520 | max = 2; | 1712 | max = hdspm->is_aes32 ? 9 : 2; |
1521 | 1713 | ||
1522 | if (!snd_hdspm_use_is_exclusive(hdspm)) | 1714 | if (!snd_hdspm_use_is_exclusive(hdspm)) |
1523 | return -EBUSY; | 1715 | return -EBUSY; |
@@ -1542,40 +1734,64 @@ static int snd_hdspm_put_pref_sync_ref(struct snd_kcontrol *kcontrol, | |||
1542 | 1734 | ||
1543 | static int hdspm_autosync_ref(struct hdspm * hdspm) | 1735 | static int hdspm_autosync_ref(struct hdspm * hdspm) |
1544 | { | 1736 | { |
1545 | /* This looks at the autosync selected sync reference */ | 1737 | if (hdspm->is_aes32) { |
1546 | unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2); | 1738 | unsigned int status = hdspm_read(hdspm, HDSPM_statusRegister); |
1547 | 1739 | unsigned int syncref = (status >> HDSPM_AES32_syncref_bit) & 0xF; | |
1548 | switch (status2 & HDSPM_SelSyncRefMask) { | 1740 | if (syncref == 0) |
1549 | 1741 | return HDSPM_AES32_AUTOSYNC_FROM_WORD; | |
1550 | case HDSPM_SelSyncRef_WORD: | 1742 | if (syncref <= 8) |
1551 | return HDSPM_AUTOSYNC_FROM_WORD; | 1743 | return syncref; |
1552 | 1744 | return HDSPM_AES32_AUTOSYNC_FROM_NONE; | |
1553 | case HDSPM_SelSyncRef_MADI: | 1745 | } else { |
1554 | return HDSPM_AUTOSYNC_FROM_MADI; | 1746 | /* This looks at the autosync selected sync reference */ |
1555 | 1747 | unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2); | |
1556 | case HDSPM_SelSyncRef_NVALID: | 1748 | |
1557 | return HDSPM_AUTOSYNC_FROM_NONE; | 1749 | switch (status2 & HDSPM_SelSyncRefMask) { |
1750 | case HDSPM_SelSyncRef_WORD: | ||
1751 | return HDSPM_AUTOSYNC_FROM_WORD; | ||
1752 | case HDSPM_SelSyncRef_MADI: | ||
1753 | return HDSPM_AUTOSYNC_FROM_MADI; | ||
1754 | case HDSPM_SelSyncRef_NVALID: | ||
1755 | return HDSPM_AUTOSYNC_FROM_NONE; | ||
1756 | default: | ||
1757 | return 0; | ||
1758 | } | ||
1558 | 1759 | ||
1559 | default: | ||
1560 | return 0; | 1760 | return 0; |
1561 | } | 1761 | } |
1562 | |||
1563 | return 0; | ||
1564 | } | 1762 | } |
1565 | 1763 | ||
1566 | static int snd_hdspm_info_autosync_ref(struct snd_kcontrol *kcontrol, | 1764 | static int snd_hdspm_info_autosync_ref(struct snd_kcontrol *kcontrol, |
1567 | struct snd_ctl_elem_info *uinfo) | 1765 | struct snd_ctl_elem_info *uinfo) |
1568 | { | 1766 | { |
1569 | static char *texts[] = { "WordClock", "MADI", "None" }; | 1767 | struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); |
1570 | 1768 | ||
1571 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 1769 | if (hdspm->is_aes32) { |
1572 | uinfo->count = 1; | 1770 | static char *texts[] = { "WordClock", "AES1", "AES2", "AES3", |
1573 | uinfo->value.enumerated.items = 3; | 1771 | "AES4", "AES5", "AES6", "AES7", "AES8", "None"}; |
1574 | if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) | 1772 | |
1575 | uinfo->value.enumerated.item = | 1773 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; |
1576 | uinfo->value.enumerated.items - 1; | 1774 | uinfo->count = 1; |
1577 | strcpy(uinfo->value.enumerated.name, | 1775 | uinfo->value.enumerated.items = 10; |
1578 | texts[uinfo->value.enumerated.item]); | 1776 | if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) |
1777 | uinfo->value.enumerated.item = | ||
1778 | uinfo->value.enumerated.items - 1; | ||
1779 | strcpy(uinfo->value.enumerated.name, | ||
1780 | texts[uinfo->value.enumerated.item]); | ||
1781 | } | ||
1782 | else | ||
1783 | { | ||
1784 | static char *texts[] = { "WordClock", "MADI", "None" }; | ||
1785 | |||
1786 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
1787 | uinfo->count = 1; | ||
1788 | uinfo->value.enumerated.items = 3; | ||
1789 | if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) | ||
1790 | uinfo->value.enumerated.item = | ||
1791 | uinfo->value.enumerated.items - 1; | ||
1792 | strcpy(uinfo->value.enumerated.name, | ||
1793 | texts[uinfo->value.enumerated.item]); | ||
1794 | } | ||
1579 | return 0; | 1795 | return 0; |
1580 | } | 1796 | } |
1581 | 1797 | ||
@@ -1841,6 +2057,195 @@ static int snd_hdspm_put_safe_mode(struct snd_kcontrol *kcontrol, | |||
1841 | return change; | 2057 | return change; |
1842 | } | 2058 | } |
1843 | 2059 | ||
2060 | #define HDSPM_EMPHASIS(xname, xindex) \ | ||
2061 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
2062 | .name = xname, \ | ||
2063 | .index = xindex, \ | ||
2064 | .info = snd_hdspm_info_emphasis, \ | ||
2065 | .get = snd_hdspm_get_emphasis, \ | ||
2066 | .put = snd_hdspm_put_emphasis \ | ||
2067 | } | ||
2068 | |||
2069 | static int hdspm_emphasis(struct hdspm * hdspm) | ||
2070 | { | ||
2071 | return (hdspm->control_register & HDSPM_Emphasis) ? 1 : 0; | ||
2072 | } | ||
2073 | |||
2074 | static int hdspm_set_emphasis(struct hdspm * hdspm, int emp) | ||
2075 | { | ||
2076 | if (emp) | ||
2077 | hdspm->control_register |= HDSPM_Emphasis; | ||
2078 | else | ||
2079 | hdspm->control_register &= ~HDSPM_Emphasis; | ||
2080 | hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); | ||
2081 | |||
2082 | return 0; | ||
2083 | } | ||
2084 | |||
2085 | static int snd_hdspm_info_emphasis(struct snd_kcontrol *kcontrol, | ||
2086 | struct snd_ctl_elem_info *uinfo) | ||
2087 | { | ||
2088 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
2089 | uinfo->count = 1; | ||
2090 | uinfo->value.integer.min = 0; | ||
2091 | uinfo->value.integer.max = 1; | ||
2092 | return 0; | ||
2093 | } | ||
2094 | |||
2095 | static int snd_hdspm_get_emphasis(struct snd_kcontrol *kcontrol, | ||
2096 | struct snd_ctl_elem_value *ucontrol) | ||
2097 | { | ||
2098 | struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); | ||
2099 | |||
2100 | spin_lock_irq(&hdspm->lock); | ||
2101 | ucontrol->value.enumerated.item[0] = hdspm_emphasis(hdspm); | ||
2102 | spin_unlock_irq(&hdspm->lock); | ||
2103 | return 0; | ||
2104 | } | ||
2105 | |||
2106 | static int snd_hdspm_put_emphasis(struct snd_kcontrol *kcontrol, | ||
2107 | struct snd_ctl_elem_value *ucontrol) | ||
2108 | { | ||
2109 | struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); | ||
2110 | int change; | ||
2111 | unsigned int val; | ||
2112 | |||
2113 | if (!snd_hdspm_use_is_exclusive(hdspm)) | ||
2114 | return -EBUSY; | ||
2115 | val = ucontrol->value.integer.value[0] & 1; | ||
2116 | spin_lock_irq(&hdspm->lock); | ||
2117 | change = (int) val != hdspm_emphasis(hdspm); | ||
2118 | hdspm_set_emphasis(hdspm, val); | ||
2119 | spin_unlock_irq(&hdspm->lock); | ||
2120 | return change; | ||
2121 | } | ||
2122 | |||
2123 | #define HDSPM_DOLBY(xname, xindex) \ | ||
2124 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
2125 | .name = xname, \ | ||
2126 | .index = xindex, \ | ||
2127 | .info = snd_hdspm_info_dolby, \ | ||
2128 | .get = snd_hdspm_get_dolby, \ | ||
2129 | .put = snd_hdspm_put_dolby \ | ||
2130 | } | ||
2131 | |||
2132 | static int hdspm_dolby(struct hdspm * hdspm) | ||
2133 | { | ||
2134 | return (hdspm->control_register & HDSPM_Dolby) ? 1 : 0; | ||
2135 | } | ||
2136 | |||
2137 | static int hdspm_set_dolby(struct hdspm * hdspm, int dol) | ||
2138 | { | ||
2139 | if (dol) | ||
2140 | hdspm->control_register |= HDSPM_Dolby; | ||
2141 | else | ||
2142 | hdspm->control_register &= ~HDSPM_Dolby; | ||
2143 | hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); | ||
2144 | |||
2145 | return 0; | ||
2146 | } | ||
2147 | |||
2148 | static int snd_hdspm_info_dolby(struct snd_kcontrol *kcontrol, | ||
2149 | struct snd_ctl_elem_info *uinfo) | ||
2150 | { | ||
2151 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
2152 | uinfo->count = 1; | ||
2153 | uinfo->value.integer.min = 0; | ||
2154 | uinfo->value.integer.max = 1; | ||
2155 | return 0; | ||
2156 | } | ||
2157 | |||
2158 | static int snd_hdspm_get_dolby(struct snd_kcontrol *kcontrol, | ||
2159 | struct snd_ctl_elem_value *ucontrol) | ||
2160 | { | ||
2161 | struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); | ||
2162 | |||
2163 | spin_lock_irq(&hdspm->lock); | ||
2164 | ucontrol->value.enumerated.item[0] = hdspm_dolby(hdspm); | ||
2165 | spin_unlock_irq(&hdspm->lock); | ||
2166 | return 0; | ||
2167 | } | ||
2168 | |||
2169 | static int snd_hdspm_put_dolby(struct snd_kcontrol *kcontrol, | ||
2170 | struct snd_ctl_elem_value *ucontrol) | ||
2171 | { | ||
2172 | struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); | ||
2173 | int change; | ||
2174 | unsigned int val; | ||
2175 | |||
2176 | if (!snd_hdspm_use_is_exclusive(hdspm)) | ||
2177 | return -EBUSY; | ||
2178 | val = ucontrol->value.integer.value[0] & 1; | ||
2179 | spin_lock_irq(&hdspm->lock); | ||
2180 | change = (int) val != hdspm_dolby(hdspm); | ||
2181 | hdspm_set_dolby(hdspm, val); | ||
2182 | spin_unlock_irq(&hdspm->lock); | ||
2183 | return change; | ||
2184 | } | ||
2185 | |||
2186 | #define HDSPM_PROFESSIONAL(xname, xindex) \ | ||
2187 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
2188 | .name = xname, \ | ||
2189 | .index = xindex, \ | ||
2190 | .info = snd_hdspm_info_professional, \ | ||
2191 | .get = snd_hdspm_get_professional, \ | ||
2192 | .put = snd_hdspm_put_professional \ | ||
2193 | } | ||
2194 | |||
2195 | static int hdspm_professional(struct hdspm * hdspm) | ||
2196 | { | ||
2197 | return (hdspm->control_register & HDSPM_Professional) ? 1 : 0; | ||
2198 | } | ||
2199 | |||
2200 | static int hdspm_set_professional(struct hdspm * hdspm, int dol) | ||
2201 | { | ||
2202 | if (dol) | ||
2203 | hdspm->control_register |= HDSPM_Professional; | ||
2204 | else | ||
2205 | hdspm->control_register &= ~HDSPM_Professional; | ||
2206 | hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); | ||
2207 | |||
2208 | return 0; | ||
2209 | } | ||
2210 | |||
2211 | static int snd_hdspm_info_professional(struct snd_kcontrol *kcontrol, | ||
2212 | struct snd_ctl_elem_info *uinfo) | ||
2213 | { | ||
2214 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
2215 | uinfo->count = 1; | ||
2216 | uinfo->value.integer.min = 0; | ||
2217 | uinfo->value.integer.max = 1; | ||
2218 | return 0; | ||
2219 | } | ||
2220 | |||
2221 | static int snd_hdspm_get_professional(struct snd_kcontrol *kcontrol, | ||
2222 | struct snd_ctl_elem_value *ucontrol) | ||
2223 | { | ||
2224 | struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); | ||
2225 | |||
2226 | spin_lock_irq(&hdspm->lock); | ||
2227 | ucontrol->value.enumerated.item[0] = hdspm_professional(hdspm); | ||
2228 | spin_unlock_irq(&hdspm->lock); | ||
2229 | return 0; | ||
2230 | } | ||
2231 | |||
2232 | static int snd_hdspm_put_professional(struct snd_kcontrol *kcontrol, | ||
2233 | struct snd_ctl_elem_value *ucontrol) | ||
2234 | { | ||
2235 | struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); | ||
2236 | int change; | ||
2237 | unsigned int val; | ||
2238 | |||
2239 | if (!snd_hdspm_use_is_exclusive(hdspm)) | ||
2240 | return -EBUSY; | ||
2241 | val = ucontrol->value.integer.value[0] & 1; | ||
2242 | spin_lock_irq(&hdspm->lock); | ||
2243 | change = (int) val != hdspm_professional(hdspm); | ||
2244 | hdspm_set_professional(hdspm, val); | ||
2245 | spin_unlock_irq(&hdspm->lock); | ||
2246 | return change; | ||
2247 | } | ||
2248 | |||
1844 | #define HDSPM_INPUT_SELECT(xname, xindex) \ | 2249 | #define HDSPM_INPUT_SELECT(xname, xindex) \ |
1845 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | 2250 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ |
1846 | .name = xname, \ | 2251 | .name = xname, \ |
@@ -1912,6 +2317,163 @@ static int snd_hdspm_put_input_select(struct snd_kcontrol *kcontrol, | |||
1912 | return change; | 2317 | return change; |
1913 | } | 2318 | } |
1914 | 2319 | ||
2320 | #define HDSPM_DS_WIRE(xname, xindex) \ | ||
2321 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
2322 | .name = xname, \ | ||
2323 | .index = xindex, \ | ||
2324 | .info = snd_hdspm_info_ds_wire, \ | ||
2325 | .get = snd_hdspm_get_ds_wire, \ | ||
2326 | .put = snd_hdspm_put_ds_wire \ | ||
2327 | } | ||
2328 | |||
2329 | static int hdspm_ds_wire(struct hdspm * hdspm) | ||
2330 | { | ||
2331 | return (hdspm->control_register & HDSPM_DS_DoubleWire) ? 1 : 0; | ||
2332 | } | ||
2333 | |||
2334 | static int hdspm_set_ds_wire(struct hdspm * hdspm, int ds) | ||
2335 | { | ||
2336 | if (ds) | ||
2337 | hdspm->control_register |= HDSPM_DS_DoubleWire; | ||
2338 | else | ||
2339 | hdspm->control_register &= ~HDSPM_DS_DoubleWire; | ||
2340 | hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); | ||
2341 | |||
2342 | return 0; | ||
2343 | } | ||
2344 | |||
2345 | static int snd_hdspm_info_ds_wire(struct snd_kcontrol *kcontrol, | ||
2346 | struct snd_ctl_elem_info *uinfo) | ||
2347 | { | ||
2348 | static char *texts[] = { "Single", "Double" }; | ||
2349 | |||
2350 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
2351 | uinfo->count = 1; | ||
2352 | uinfo->value.enumerated.items = 2; | ||
2353 | |||
2354 | if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) | ||
2355 | uinfo->value.enumerated.item = | ||
2356 | uinfo->value.enumerated.items - 1; | ||
2357 | strcpy(uinfo->value.enumerated.name, | ||
2358 | texts[uinfo->value.enumerated.item]); | ||
2359 | |||
2360 | return 0; | ||
2361 | } | ||
2362 | |||
2363 | static int snd_hdspm_get_ds_wire(struct snd_kcontrol *kcontrol, | ||
2364 | struct snd_ctl_elem_value *ucontrol) | ||
2365 | { | ||
2366 | struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); | ||
2367 | |||
2368 | spin_lock_irq(&hdspm->lock); | ||
2369 | ucontrol->value.enumerated.item[0] = hdspm_ds_wire(hdspm); | ||
2370 | spin_unlock_irq(&hdspm->lock); | ||
2371 | return 0; | ||
2372 | } | ||
2373 | |||
2374 | static int snd_hdspm_put_ds_wire(struct snd_kcontrol *kcontrol, | ||
2375 | struct snd_ctl_elem_value *ucontrol) | ||
2376 | { | ||
2377 | struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); | ||
2378 | int change; | ||
2379 | unsigned int val; | ||
2380 | |||
2381 | if (!snd_hdspm_use_is_exclusive(hdspm)) | ||
2382 | return -EBUSY; | ||
2383 | val = ucontrol->value.integer.value[0] & 1; | ||
2384 | spin_lock_irq(&hdspm->lock); | ||
2385 | change = (int) val != hdspm_ds_wire(hdspm); | ||
2386 | hdspm_set_ds_wire(hdspm, val); | ||
2387 | spin_unlock_irq(&hdspm->lock); | ||
2388 | return change; | ||
2389 | } | ||
2390 | |||
2391 | #define HDSPM_QS_WIRE(xname, xindex) \ | ||
2392 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
2393 | .name = xname, \ | ||
2394 | .index = xindex, \ | ||
2395 | .info = snd_hdspm_info_qs_wire, \ | ||
2396 | .get = snd_hdspm_get_qs_wire, \ | ||
2397 | .put = snd_hdspm_put_qs_wire \ | ||
2398 | } | ||
2399 | |||
2400 | static int hdspm_qs_wire(struct hdspm * hdspm) | ||
2401 | { | ||
2402 | if (hdspm->control_register & HDSPM_QS_DoubleWire) | ||
2403 | return 1; | ||
2404 | if (hdspm->control_register & HDSPM_QS_QuadWire) | ||
2405 | return 2; | ||
2406 | return 0; | ||
2407 | } | ||
2408 | |||
2409 | static int hdspm_set_qs_wire(struct hdspm * hdspm, int mode) | ||
2410 | { | ||
2411 | hdspm->control_register &= ~(HDSPM_QS_DoubleWire | HDSPM_QS_QuadWire); | ||
2412 | switch (mode) { | ||
2413 | case 0: | ||
2414 | break; | ||
2415 | case 1: | ||
2416 | hdspm->control_register |= HDSPM_QS_DoubleWire; | ||
2417 | break; | ||
2418 | case 2: | ||
2419 | hdspm->control_register |= HDSPM_QS_QuadWire; | ||
2420 | break; | ||
2421 | } | ||
2422 | hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); | ||
2423 | |||
2424 | return 0; | ||
2425 | } | ||
2426 | |||
2427 | static int snd_hdspm_info_qs_wire(struct snd_kcontrol *kcontrol, | ||
2428 | struct snd_ctl_elem_info *uinfo) | ||
2429 | { | ||
2430 | static char *texts[] = { "Single", "Double", "Quad" }; | ||
2431 | |||
2432 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
2433 | uinfo->count = 1; | ||
2434 | uinfo->value.enumerated.items = 3; | ||
2435 | |||
2436 | if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) | ||
2437 | uinfo->value.enumerated.item = | ||
2438 | uinfo->value.enumerated.items - 1; | ||
2439 | strcpy(uinfo->value.enumerated.name, | ||
2440 | texts[uinfo->value.enumerated.item]); | ||
2441 | |||
2442 | return 0; | ||
2443 | } | ||
2444 | |||
2445 | static int snd_hdspm_get_qs_wire(struct snd_kcontrol *kcontrol, | ||
2446 | struct snd_ctl_elem_value *ucontrol) | ||
2447 | { | ||
2448 | struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); | ||
2449 | |||
2450 | spin_lock_irq(&hdspm->lock); | ||
2451 | ucontrol->value.enumerated.item[0] = hdspm_qs_wire(hdspm); | ||
2452 | spin_unlock_irq(&hdspm->lock); | ||
2453 | return 0; | ||
2454 | } | ||
2455 | |||
2456 | static int snd_hdspm_put_qs_wire(struct snd_kcontrol *kcontrol, | ||
2457 | struct snd_ctl_elem_value *ucontrol) | ||
2458 | { | ||
2459 | struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); | ||
2460 | int change; | ||
2461 | int val; | ||
2462 | |||
2463 | if (!snd_hdspm_use_is_exclusive(hdspm)) | ||
2464 | return -EBUSY; | ||
2465 | val = ucontrol->value.integer.value[0]; | ||
2466 | if (val < 0) | ||
2467 | val = 0; | ||
2468 | if (val > 2) | ||
2469 | val = 2; | ||
2470 | spin_lock_irq(&hdspm->lock); | ||
2471 | change = (int) val != hdspm_qs_wire(hdspm); | ||
2472 | hdspm_set_qs_wire(hdspm, val); | ||
2473 | spin_unlock_irq(&hdspm->lock); | ||
2474 | return change; | ||
2475 | } | ||
2476 | |||
1915 | /* Simple Mixer | 2477 | /* Simple Mixer |
1916 | deprecated since to much faders ??? | 2478 | deprecated since to much faders ??? |
1917 | MIXER interface says output (source, destination, value) | 2479 | MIXER interface says output (source, destination, value) |
@@ -2135,14 +2697,24 @@ static int snd_hdspm_info_sync_check(struct snd_kcontrol *kcontrol, | |||
2135 | 2697 | ||
2136 | static int hdspm_wc_sync_check(struct hdspm * hdspm) | 2698 | static int hdspm_wc_sync_check(struct hdspm * hdspm) |
2137 | { | 2699 | { |
2138 | int status2 = hdspm_read(hdspm, HDSPM_statusRegister2); | 2700 | if (hdspm->is_aes32) { |
2139 | if (status2 & HDSPM_wcLock) { | 2701 | int status = hdspm_read(hdspm, HDSPM_statusRegister); |
2140 | if (status2 & HDSPM_wcSync) | 2702 | if (status & HDSPM_AES32_wcLock) { |
2703 | /* I don't know how to differenciate sync from lock. | ||
2704 | Doing as if sync for now */ | ||
2141 | return 2; | 2705 | return 2; |
2142 | else | 2706 | } |
2143 | return 1; | 2707 | return 0; |
2708 | } else { | ||
2709 | int status2 = hdspm_read(hdspm, HDSPM_statusRegister2); | ||
2710 | if (status2 & HDSPM_wcLock) { | ||
2711 | if (status2 & HDSPM_wcSync) | ||
2712 | return 2; | ||
2713 | else | ||
2714 | return 1; | ||
2715 | } | ||
2716 | return 0; | ||
2144 | } | 2717 | } |
2145 | return 0; | ||
2146 | } | 2718 | } |
2147 | 2719 | ||
2148 | static int snd_hdspm_get_wc_sync_check(struct snd_kcontrol *kcontrol, | 2720 | static int snd_hdspm_get_wc_sync_check(struct snd_kcontrol *kcontrol, |
@@ -2188,9 +2760,43 @@ static int snd_hdspm_get_madisync_sync_check(struct snd_kcontrol *kcontrol, | |||
2188 | } | 2760 | } |
2189 | 2761 | ||
2190 | 2762 | ||
2763 | #define HDSPM_AES_SYNC_CHECK(xname, xindex) \ | ||
2764 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
2765 | .name = xname, \ | ||
2766 | .index = xindex, \ | ||
2767 | .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ | ||
2768 | .info = snd_hdspm_info_sync_check, \ | ||
2769 | .get = snd_hdspm_get_aes_sync_check \ | ||
2770 | } | ||
2771 | |||
2772 | static int hdspm_aes_sync_check(struct hdspm * hdspm, int idx) | ||
2773 | { | ||
2774 | int status2 = hdspm_read(hdspm, HDSPM_statusRegister2); | ||
2775 | if (status2 & (HDSPM_LockAES >> idx)) { | ||
2776 | /* I don't know how to differenciate sync from lock. | ||
2777 | Doing as if sync for now */ | ||
2778 | return 2; | ||
2779 | } | ||
2780 | return 0; | ||
2781 | } | ||
2782 | |||
2783 | static int snd_hdspm_get_aes_sync_check(struct snd_kcontrol *kcontrol, | ||
2784 | struct snd_ctl_elem_value *ucontrol) | ||
2785 | { | ||
2786 | int offset; | ||
2787 | struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); | ||
2788 | |||
2789 | offset = ucontrol->id.index - 1; | ||
2790 | if (offset < 0 || offset >= 8) | ||
2791 | return -EINVAL; | ||
2792 | |||
2793 | ucontrol->value.enumerated.item[0] = | ||
2794 | hdspm_aes_sync_check(hdspm, offset); | ||
2795 | return 0; | ||
2796 | } | ||
2191 | 2797 | ||
2192 | 2798 | ||
2193 | static struct snd_kcontrol_new snd_hdspm_controls[] = { | 2799 | static struct snd_kcontrol_new snd_hdspm_controls_madi[] = { |
2194 | 2800 | ||
2195 | HDSPM_MIXER("Mixer", 0), | 2801 | HDSPM_MIXER("Mixer", 0), |
2196 | /* 'Sample Clock Source' complies with the alsa control naming scheme */ | 2802 | /* 'Sample Clock Source' complies with the alsa control naming scheme */ |
@@ -2211,6 +2817,29 @@ static struct snd_kcontrol_new snd_hdspm_controls[] = { | |||
2211 | HDSPM_INPUT_SELECT("Input Select", 0), | 2817 | HDSPM_INPUT_SELECT("Input Select", 0), |
2212 | }; | 2818 | }; |
2213 | 2819 | ||
2820 | static struct snd_kcontrol_new snd_hdspm_controls_aes32[] = { | ||
2821 | |||
2822 | HDSPM_MIXER("Mixer", 0), | ||
2823 | /* 'Sample Clock Source' complies with the alsa control naming scheme */ | ||
2824 | HDSPM_CLOCK_SOURCE("Sample Clock Source", 0), | ||
2825 | |||
2826 | HDSPM_SYSTEM_CLOCK_MODE("System Clock Mode", 0), | ||
2827 | HDSPM_PREF_SYNC_REF("Preferred Sync Reference", 0), | ||
2828 | HDSPM_AUTOSYNC_REF("AutoSync Reference", 0), | ||
2829 | HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0), | ||
2830 | /* 'External Rate' complies with the alsa control naming scheme */ | ||
2831 | HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 0), | ||
2832 | HDSPM_WC_SYNC_CHECK("Word Clock Lock Status", 0), | ||
2833 | /* HDSPM_AES_SYNC_CHECK("AES Lock Status", 0),*/ /* created in snd_hdspm_create_controls() */ | ||
2834 | HDSPM_LINE_OUT("Line Out", 0), | ||
2835 | HDSPM_EMPHASIS("Emphasis", 0), | ||
2836 | HDSPM_DOLBY("Non Audio", 0), | ||
2837 | HDSPM_PROFESSIONAL("Professional", 0), | ||
2838 | HDSPM_C_TMS("Clear Track Marker", 0), | ||
2839 | HDSPM_DS_WIRE("Double Speed Wire Mode", 0), | ||
2840 | HDSPM_QS_WIRE("Quad Speed Wire Mode", 0), | ||
2841 | }; | ||
2842 | |||
2214 | static struct snd_kcontrol_new snd_hdspm_playback_mixer = HDSPM_PLAYBACK_MIXER; | 2843 | static struct snd_kcontrol_new snd_hdspm_playback_mixer = HDSPM_PLAYBACK_MIXER; |
2215 | 2844 | ||
2216 | 2845 | ||
@@ -2245,20 +2874,40 @@ static int snd_hdspm_create_controls(struct snd_card *card, struct hdspm * hdspm | |||
2245 | struct snd_kcontrol *kctl; | 2874 | struct snd_kcontrol *kctl; |
2246 | 2875 | ||
2247 | /* add control list first */ | 2876 | /* add control list first */ |
2248 | 2877 | if (hdspm->is_aes32) { | |
2249 | for (idx = 0; idx < ARRAY_SIZE(snd_hdspm_controls); idx++) { | 2878 | struct snd_kcontrol_new aes_sync_ctl = |
2250 | if ((err = | 2879 | HDSPM_AES_SYNC_CHECK("AES Lock Status", 0); |
2251 | snd_ctl_add(card, kctl = | 2880 | |
2252 | snd_ctl_new1(&snd_hdspm_controls[idx], | 2881 | for (idx = 0; idx < ARRAY_SIZE(snd_hdspm_controls_aes32); |
2253 | hdspm))) < 0) { | 2882 | idx++) { |
2254 | return err; | 2883 | err = snd_ctl_add(card, |
2884 | snd_ctl_new1(&snd_hdspm_controls_aes32[idx], | ||
2885 | hdspm)); | ||
2886 | if (err < 0) | ||
2887 | return err; | ||
2888 | } | ||
2889 | for (idx = 1; idx <= 8; idx++) { | ||
2890 | aes_sync_ctl.index = idx; | ||
2891 | err = snd_ctl_add(card, | ||
2892 | snd_ctl_new1(&aes_sync_ctl, hdspm)); | ||
2893 | if (err < 0) | ||
2894 | return err; | ||
2895 | } | ||
2896 | } else { | ||
2897 | for (idx = 0; idx < ARRAY_SIZE(snd_hdspm_controls_madi); | ||
2898 | idx++) { | ||
2899 | err = snd_ctl_add(card, | ||
2900 | snd_ctl_new1(&snd_hdspm_controls_madi[idx], | ||
2901 | hdspm)); | ||
2902 | if (err < 0) | ||
2903 | return err; | ||
2255 | } | 2904 | } |
2256 | } | 2905 | } |
2257 | 2906 | ||
2258 | /* Channel playback mixer as default control | 2907 | /* Channel playback mixer as default control |
2259 | Note: the whole matrix would be 128*HDSPM_MIXER_CHANNELS Faders, thats too big for any alsamixer | 2908 | Note: the whole matrix would be 128*HDSPM_MIXER_CHANNELS Faders, thats too big for any alsamixer |
2260 | they are accesible via special IOCTL on hwdep | 2909 | they are accesible via special IOCTL on hwdep |
2261 | and the mixer 2dimensional mixer control */ | 2910 | and the mixer 2dimensional mixer control */ |
2262 | 2911 | ||
2263 | snd_hdspm_playback_mixer.name = "Chn"; | 2912 | snd_hdspm_playback_mixer.name = "Chn"; |
2264 | limit = HDSPM_MAX_CHANNELS; | 2913 | limit = HDSPM_MAX_CHANNELS; |
@@ -2289,7 +2938,8 @@ static int snd_hdspm_create_controls(struct snd_card *card, struct hdspm * hdspm | |||
2289 | ------------------------------------------------------------*/ | 2938 | ------------------------------------------------------------*/ |
2290 | 2939 | ||
2291 | static void | 2940 | static void |
2292 | snd_hdspm_proc_read(struct snd_info_entry * entry, struct snd_info_buffer *buffer) | 2941 | snd_hdspm_proc_read_madi(struct snd_info_entry * entry, |
2942 | struct snd_info_buffer *buffer) | ||
2293 | { | 2943 | { |
2294 | struct hdspm *hdspm = (struct hdspm *) entry->private_data; | 2944 | struct hdspm *hdspm = (struct hdspm *) entry->private_data; |
2295 | unsigned int status; | 2945 | unsigned int status; |
@@ -2420,11 +3070,10 @@ snd_hdspm_proc_read(struct snd_info_entry * entry, struct snd_info_buffer *buffe | |||
2420 | clock_source = "Error"; | 3070 | clock_source = "Error"; |
2421 | } | 3071 | } |
2422 | snd_iprintf(buffer, "Sample Clock Source: %s\n", clock_source); | 3072 | snd_iprintf(buffer, "Sample Clock Source: %s\n", clock_source); |
2423 | if (!(hdspm->control_register & HDSPM_ClockModeMaster)) { | 3073 | if (!(hdspm->control_register & HDSPM_ClockModeMaster)) |
2424 | system_clock_mode = "Slave"; | 3074 | system_clock_mode = "Slave"; |
2425 | } else { | 3075 | else |
2426 | system_clock_mode = "Master"; | 3076 | system_clock_mode = "Master"; |
2427 | } | ||
2428 | snd_iprintf(buffer, "System Clock Mode: %s\n", system_clock_mode); | 3077 | snd_iprintf(buffer, "System Clock Mode: %s\n", system_clock_mode); |
2429 | 3078 | ||
2430 | switch (hdspm_pref_sync_ref(hdspm)) { | 3079 | switch (hdspm_pref_sync_ref(hdspm)) { |
@@ -2484,13 +3133,213 @@ snd_hdspm_proc_read(struct snd_info_entry * entry, struct snd_info_buffer *buffe | |||
2484 | snd_iprintf(buffer, "\n"); | 3133 | snd_iprintf(buffer, "\n"); |
2485 | } | 3134 | } |
2486 | 3135 | ||
3136 | static void | ||
3137 | snd_hdspm_proc_read_aes32(struct snd_info_entry * entry, | ||
3138 | struct snd_info_buffer *buffer) | ||
3139 | { | ||
3140 | struct hdspm *hdspm = (struct hdspm *) entry->private_data; | ||
3141 | unsigned int status; | ||
3142 | unsigned int status2; | ||
3143 | unsigned int timecode; | ||
3144 | int pref_syncref; | ||
3145 | char *autosync_ref; | ||
3146 | char *system_clock_mode; | ||
3147 | char *clock_source; | ||
3148 | int x; | ||
3149 | |||
3150 | status = hdspm_read(hdspm, HDSPM_statusRegister); | ||
3151 | status2 = hdspm_read(hdspm, HDSPM_statusRegister2); | ||
3152 | timecode = hdspm_read(hdspm, HDSPM_timecodeRegister); | ||
3153 | |||
3154 | snd_iprintf(buffer, "%s (Card #%d) Rev.%x\n", | ||
3155 | hdspm->card_name, hdspm->card->number + 1, | ||
3156 | hdspm->firmware_rev); | ||
3157 | |||
3158 | snd_iprintf(buffer, "IRQ: %d Registers bus: 0x%lx VM: 0x%lx\n", | ||
3159 | hdspm->irq, hdspm->port, (unsigned long)hdspm->iobase); | ||
3160 | |||
3161 | snd_iprintf(buffer, "--- System ---\n"); | ||
3162 | |||
3163 | snd_iprintf(buffer, | ||
3164 | "IRQ Pending: Audio=%d, MIDI0=%d, MIDI1=%d, IRQcount=%d\n", | ||
3165 | status & HDSPM_audioIRQPending, | ||
3166 | (status & HDSPM_midi0IRQPending) ? 1 : 0, | ||
3167 | (status & HDSPM_midi1IRQPending) ? 1 : 0, | ||
3168 | hdspm->irq_count); | ||
3169 | snd_iprintf(buffer, | ||
3170 | "HW pointer: id = %d, rawptr = %d (%d->%d) estimated= %ld (bytes)\n", | ||
3171 | ((status & HDSPM_BufferID) ? 1 : 0), | ||
3172 | (status & HDSPM_BufferPositionMask), | ||
3173 | (status & HDSPM_BufferPositionMask) % (2 * | ||
3174 | (int)hdspm-> | ||
3175 | period_bytes), | ||
3176 | ((status & HDSPM_BufferPositionMask) - | ||
3177 | 64) % (2 * (int)hdspm->period_bytes), | ||
3178 | (long) hdspm_hw_pointer(hdspm) * 4); | ||
3179 | |||
3180 | snd_iprintf(buffer, | ||
3181 | "MIDI FIFO: Out1=0x%x, Out2=0x%x, In1=0x%x, In2=0x%x \n", | ||
3182 | hdspm_read(hdspm, HDSPM_midiStatusOut0) & 0xFF, | ||
3183 | hdspm_read(hdspm, HDSPM_midiStatusOut1) & 0xFF, | ||
3184 | hdspm_read(hdspm, HDSPM_midiStatusIn0) & 0xFF, | ||
3185 | hdspm_read(hdspm, HDSPM_midiStatusIn1) & 0xFF); | ||
3186 | snd_iprintf(buffer, | ||
3187 | "Register: ctrl1=0x%x, ctrl2=0x%x, status1=0x%x, status2=0x%x, timecode=0x%x\n", | ||
3188 | hdspm->control_register, hdspm->control2_register, | ||
3189 | status, status2, timecode); | ||
3190 | |||
3191 | snd_iprintf(buffer, "--- Settings ---\n"); | ||
3192 | |||
3193 | x = 1 << (6 + | ||
3194 | hdspm_decode_latency(hdspm-> | ||
3195 | control_register & | ||
3196 | HDSPM_LatencyMask)); | ||
3197 | |||
3198 | snd_iprintf(buffer, | ||
3199 | "Size (Latency): %d samples (2 periods of %lu bytes)\n", | ||
3200 | x, (unsigned long) hdspm->period_bytes); | ||
3201 | |||
3202 | snd_iprintf(buffer, "Line out: %s, Precise Pointer: %s\n", | ||
3203 | (hdspm-> | ||
3204 | control_register & HDSPM_LineOut) ? "on " : "off", | ||
3205 | (hdspm->precise_ptr) ? "on" : "off"); | ||
3206 | |||
3207 | snd_iprintf(buffer, | ||
3208 | "ClearTrackMarker %s, Emphasis %s, Dolby %s\n", | ||
3209 | (hdspm-> | ||
3210 | control_register & HDSPM_clr_tms) ? "on" : "off", | ||
3211 | (hdspm-> | ||
3212 | control_register & HDSPM_Emphasis) ? "on" : "off", | ||
3213 | (hdspm-> | ||
3214 | control_register & HDSPM_Dolby) ? "on" : "off"); | ||
3215 | |||
3216 | switch (hdspm_clock_source(hdspm)) { | ||
3217 | case HDSPM_CLOCK_SOURCE_AUTOSYNC: | ||
3218 | clock_source = "AutoSync"; | ||
3219 | break; | ||
3220 | case HDSPM_CLOCK_SOURCE_INTERNAL_32KHZ: | ||
3221 | clock_source = "Internal 32 kHz"; | ||
3222 | break; | ||
3223 | case HDSPM_CLOCK_SOURCE_INTERNAL_44_1KHZ: | ||
3224 | clock_source = "Internal 44.1 kHz"; | ||
3225 | break; | ||
3226 | case HDSPM_CLOCK_SOURCE_INTERNAL_48KHZ: | ||
3227 | clock_source = "Internal 48 kHz"; | ||
3228 | break; | ||
3229 | case HDSPM_CLOCK_SOURCE_INTERNAL_64KHZ: | ||
3230 | clock_source = "Internal 64 kHz"; | ||
3231 | break; | ||
3232 | case HDSPM_CLOCK_SOURCE_INTERNAL_88_2KHZ: | ||
3233 | clock_source = "Internal 88.2 kHz"; | ||
3234 | break; | ||
3235 | case HDSPM_CLOCK_SOURCE_INTERNAL_96KHZ: | ||
3236 | clock_source = "Internal 96 kHz"; | ||
3237 | break; | ||
3238 | case HDSPM_CLOCK_SOURCE_INTERNAL_128KHZ: | ||
3239 | clock_source = "Internal 128 kHz"; | ||
3240 | break; | ||
3241 | case HDSPM_CLOCK_SOURCE_INTERNAL_176_4KHZ: | ||
3242 | clock_source = "Internal 176.4 kHz"; | ||
3243 | break; | ||
3244 | case HDSPM_CLOCK_SOURCE_INTERNAL_192KHZ: | ||
3245 | clock_source = "Internal 192 kHz"; | ||
3246 | break; | ||
3247 | default: | ||
3248 | clock_source = "Error"; | ||
3249 | } | ||
3250 | snd_iprintf(buffer, "Sample Clock Source: %s\n", clock_source); | ||
3251 | if (!(hdspm->control_register & HDSPM_ClockModeMaster)) | ||
3252 | system_clock_mode = "Slave"; | ||
3253 | else | ||
3254 | system_clock_mode = "Master"; | ||
3255 | snd_iprintf(buffer, "System Clock Mode: %s\n", system_clock_mode); | ||
3256 | |||
3257 | pref_syncref = hdspm_pref_sync_ref(hdspm); | ||
3258 | if (pref_syncref == 0) | ||
3259 | snd_iprintf(buffer, "Preferred Sync Reference: Word Clock\n"); | ||
3260 | else | ||
3261 | snd_iprintf(buffer, "Preferred Sync Reference: AES%d\n", | ||
3262 | pref_syncref); | ||
3263 | |||
3264 | snd_iprintf(buffer, "System Clock Frequency: %d\n", | ||
3265 | hdspm->system_sample_rate); | ||
3266 | |||
3267 | snd_iprintf(buffer, "Double speed: %s\n", | ||
3268 | hdspm->control_register & HDSPM_DS_DoubleWire? | ||
3269 | "Double wire" : "Single wire"); | ||
3270 | snd_iprintf(buffer, "Quad speed: %s\n", | ||
3271 | hdspm->control_register & HDSPM_QS_DoubleWire? | ||
3272 | "Double wire" : | ||
3273 | hdspm->control_register & HDSPM_QS_QuadWire? | ||
3274 | "Quad wire" : "Single wire"); | ||
3275 | |||
3276 | snd_iprintf(buffer, "--- Status:\n"); | ||
3277 | |||
3278 | snd_iprintf(buffer, "Word: %s Frequency: %d\n", | ||
3279 | (status & HDSPM_AES32_wcLock)? "Sync " : "No Lock", | ||
3280 | HDSPM_bit2freq((status >> HDSPM_AES32_wcFreq_bit) & 0xF)); | ||
3281 | |||
3282 | for (x = 0; x < 8; x++) { | ||
3283 | snd_iprintf(buffer, "AES%d: %s Frequency: %d\n", | ||
3284 | x+1, | ||
3285 | (status2 & (HDSPM_LockAES >> x))? "Sync ": "No Lock", | ||
3286 | HDSPM_bit2freq((timecode >> (4*x)) & 0xF)); | ||
3287 | } | ||
3288 | |||
3289 | switch (hdspm_autosync_ref(hdspm)) { | ||
3290 | case HDSPM_AES32_AUTOSYNC_FROM_NONE: autosync_ref="None"; break; | ||
3291 | case HDSPM_AES32_AUTOSYNC_FROM_WORD: autosync_ref="Word Clock"; break; | ||
3292 | case HDSPM_AES32_AUTOSYNC_FROM_AES1: autosync_ref="AES1"; break; | ||
3293 | case HDSPM_AES32_AUTOSYNC_FROM_AES2: autosync_ref="AES2"; break; | ||
3294 | case HDSPM_AES32_AUTOSYNC_FROM_AES3: autosync_ref="AES3"; break; | ||
3295 | case HDSPM_AES32_AUTOSYNC_FROM_AES4: autosync_ref="AES4"; break; | ||
3296 | case HDSPM_AES32_AUTOSYNC_FROM_AES5: autosync_ref="AES5"; break; | ||
3297 | case HDSPM_AES32_AUTOSYNC_FROM_AES6: autosync_ref="AES6"; break; | ||
3298 | case HDSPM_AES32_AUTOSYNC_FROM_AES7: autosync_ref="AES7"; break; | ||
3299 | case HDSPM_AES32_AUTOSYNC_FROM_AES8: autosync_ref="AES8"; break; | ||
3300 | default: autosync_ref = "---"; break; | ||
3301 | } | ||
3302 | snd_iprintf(buffer, "AutoSync ref = %s\n", autosync_ref); | ||
3303 | |||
3304 | snd_iprintf(buffer, "\n"); | ||
3305 | } | ||
3306 | |||
3307 | #ifdef CONFIG_SND_DEBUG | ||
3308 | static void | ||
3309 | snd_hdspm_proc_read_debug(struct snd_info_entry * entry, | ||
3310 | struct snd_info_buffer *buffer) | ||
3311 | { | ||
3312 | struct hdspm *hdspm = (struct hdspm *)entry->private_data; | ||
3313 | |||
3314 | int j,i; | ||
3315 | |||
3316 | for (i = 0; i < 256 /* 1024*64 */; i += j) | ||
3317 | { | ||
3318 | snd_iprintf(buffer, "0x%08X: ", i); | ||
3319 | for (j = 0; j < 16; j += 4) | ||
3320 | snd_iprintf(buffer, "%08X ", hdspm_read(hdspm, i + j)); | ||
3321 | snd_iprintf(buffer, "\n"); | ||
3322 | } | ||
3323 | } | ||
3324 | #endif | ||
3325 | |||
3326 | |||
3327 | |||
2487 | static void __devinit snd_hdspm_proc_init(struct hdspm * hdspm) | 3328 | static void __devinit snd_hdspm_proc_init(struct hdspm * hdspm) |
2488 | { | 3329 | { |
2489 | struct snd_info_entry *entry; | 3330 | struct snd_info_entry *entry; |
2490 | 3331 | ||
2491 | if (!snd_card_proc_new(hdspm->card, "hdspm", &entry)) | 3332 | if (!snd_card_proc_new(hdspm->card, "hdspm", &entry)) |
2492 | snd_info_set_text_ops(entry, hdspm, | 3333 | snd_info_set_text_ops(entry, hdspm, |
2493 | snd_hdspm_proc_read); | 3334 | hdspm->is_aes32 ? |
3335 | snd_hdspm_proc_read_aes32 : | ||
3336 | snd_hdspm_proc_read_madi); | ||
3337 | #ifdef CONFIG_SND_DEBUG | ||
3338 | /* debug file to read all hdspm registers */ | ||
3339 | if (!snd_card_proc_new(hdspm->card, "debug", &entry)) | ||
3340 | snd_info_set_text_ops(entry, hdspm, | ||
3341 | snd_hdspm_proc_read_debug); | ||
3342 | #endif | ||
2494 | } | 3343 | } |
2495 | 3344 | ||
2496 | /*------------------------------------------------------------ | 3345 | /*------------------------------------------------------------ |
@@ -2507,13 +3356,20 @@ static int snd_hdspm_set_defaults(struct hdspm * hdspm) | |||
2507 | 3356 | ||
2508 | /* set defaults: */ | 3357 | /* set defaults: */ |
2509 | 3358 | ||
2510 | hdspm->control_register = HDSPM_ClockModeMaster | /* Master Cloack Mode on */ | 3359 | if (hdspm->is_aes32) |
2511 | hdspm_encode_latency(7) | /* latency maximum = 8192 samples */ | 3360 | hdspm->control_register = HDSPM_ClockModeMaster | /* Master Cloack Mode on */ |
2512 | HDSPM_InputCoaxial | /* Input Coax not Optical */ | 3361 | hdspm_encode_latency(7) | /* latency maximum = 8192 samples */ |
2513 | HDSPM_SyncRef_MADI | /* Madi is syncclock */ | 3362 | HDSPM_SyncRef0 | /* AES1 is syncclock */ |
2514 | HDSPM_LineOut | /* Analog output in */ | 3363 | HDSPM_LineOut | /* Analog output in */ |
2515 | HDSPM_TX_64ch | /* transmit in 64ch mode */ | 3364 | HDSPM_Professional; /* Professional mode */ |
2516 | HDSPM_AutoInp; /* AutoInput chossing (takeover) */ | 3365 | else |
3366 | hdspm->control_register = HDSPM_ClockModeMaster | /* Master Cloack Mode on */ | ||
3367 | hdspm_encode_latency(7) | /* latency maximum = 8192 samples */ | ||
3368 | HDSPM_InputCoaxial | /* Input Coax not Optical */ | ||
3369 | HDSPM_SyncRef_MADI | /* Madi is syncclock */ | ||
3370 | HDSPM_LineOut | /* Analog output in */ | ||
3371 | HDSPM_TX_64ch | /* transmit in 64ch mode */ | ||
3372 | HDSPM_AutoInp; /* AutoInput chossing (takeover) */ | ||
2517 | 3373 | ||
2518 | /* ! HDSPM_Frequency0|HDSPM_Frequency1 = 44.1khz */ | 3374 | /* ! HDSPM_Frequency0|HDSPM_Frequency1 = 44.1khz */ |
2519 | /* ! HDSPM_DoubleSpeed HDSPM_QuadSpeed = normal speed */ | 3375 | /* ! HDSPM_DoubleSpeed HDSPM_QuadSpeed = normal speed */ |
@@ -2822,6 +3678,8 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream, | |||
2822 | 3678 | ||
2823 | hdspm->playback_buffer = | 3679 | hdspm->playback_buffer = |
2824 | (unsigned char *) substream->runtime->dma_area; | 3680 | (unsigned char *) substream->runtime->dma_area; |
3681 | snd_printdd("Allocated sample buffer for playback at %p\n", | ||
3682 | hdspm->playback_buffer); | ||
2825 | } else { | 3683 | } else { |
2826 | hdspm_set_sgbuf(hdspm, sgbuf, HDSPM_pageAddressBufferIn, | 3684 | hdspm_set_sgbuf(hdspm, sgbuf, HDSPM_pageAddressBufferIn, |
2827 | params_channels(params)); | 3685 | params_channels(params)); |
@@ -2831,7 +3689,15 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream, | |||
2831 | 3689 | ||
2832 | hdspm->capture_buffer = | 3690 | hdspm->capture_buffer = |
2833 | (unsigned char *) substream->runtime->dma_area; | 3691 | (unsigned char *) substream->runtime->dma_area; |
3692 | snd_printdd("Allocated sample buffer for capture at %p\n", | ||
3693 | hdspm->capture_buffer); | ||
2834 | } | 3694 | } |
3695 | /* | ||
3696 | snd_printdd("Allocated sample buffer for %s at 0x%08X\n", | ||
3697 | substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? | ||
3698 | "playback" : "capture", | ||
3699 | snd_pcm_sgbuf_get_addr(sgbuf, 0)); | ||
3700 | */ | ||
2835 | return 0; | 3701 | return 0; |
2836 | } | 3702 | } |
2837 | 3703 | ||
@@ -2982,9 +3848,10 @@ static struct snd_pcm_hardware snd_hdspm_playback_subinfo = { | |||
2982 | SNDRV_PCM_RATE_44100 | | 3848 | SNDRV_PCM_RATE_44100 | |
2983 | SNDRV_PCM_RATE_48000 | | 3849 | SNDRV_PCM_RATE_48000 | |
2984 | SNDRV_PCM_RATE_64000 | | 3850 | SNDRV_PCM_RATE_64000 | |
2985 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000), | 3851 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | |
3852 | SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000 ), | ||
2986 | .rate_min = 32000, | 3853 | .rate_min = 32000, |
2987 | .rate_max = 96000, | 3854 | .rate_max = 192000, |
2988 | .channels_min = 1, | 3855 | .channels_min = 1, |
2989 | .channels_max = HDSPM_MAX_CHANNELS, | 3856 | .channels_max = HDSPM_MAX_CHANNELS, |
2990 | .buffer_bytes_max = | 3857 | .buffer_bytes_max = |
@@ -3006,9 +3873,10 @@ static struct snd_pcm_hardware snd_hdspm_capture_subinfo = { | |||
3006 | SNDRV_PCM_RATE_44100 | | 3873 | SNDRV_PCM_RATE_44100 | |
3007 | SNDRV_PCM_RATE_48000 | | 3874 | SNDRV_PCM_RATE_48000 | |
3008 | SNDRV_PCM_RATE_64000 | | 3875 | SNDRV_PCM_RATE_64000 | |
3009 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000), | 3876 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | |
3877 | SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000), | ||
3010 | .rate_min = 32000, | 3878 | .rate_min = 32000, |
3011 | .rate_max = 96000, | 3879 | .rate_max = 192000, |
3012 | .channels_min = 1, | 3880 | .channels_min = 1, |
3013 | .channels_max = HDSPM_MAX_CHANNELS, | 3881 | .channels_max = HDSPM_MAX_CHANNELS, |
3014 | .buffer_bytes_max = | 3882 | .buffer_bytes_max = |
@@ -3315,7 +4183,8 @@ static int __devinit snd_hdspm_preallocate_memory(struct hdspm * hdspm) | |||
3315 | 4183 | ||
3316 | pcm = hdspm->pcm; | 4184 | pcm = hdspm->pcm; |
3317 | 4185 | ||
3318 | wanted = HDSPM_DMA_AREA_BYTES + 4096; /* dont know why, but it works */ | 4186 | /* wanted = HDSPM_DMA_AREA_BYTES + 4096;*/ /* dont know why, but it works */ |
4187 | wanted = HDSPM_DMA_AREA_BYTES; | ||
3319 | 4188 | ||
3320 | if ((err = | 4189 | if ((err = |
3321 | snd_pcm_lib_preallocate_pages_for_all(pcm, | 4190 | snd_pcm_lib_preallocate_pages_for_all(pcm, |
@@ -3467,9 +4336,16 @@ static int __devinit snd_hdspm_create(struct snd_card *card, struct hdspm * hdsp | |||
3467 | pci_read_config_word(hdspm->pci, | 4336 | pci_read_config_word(hdspm->pci, |
3468 | PCI_CLASS_REVISION, &hdspm->firmware_rev); | 4337 | PCI_CLASS_REVISION, &hdspm->firmware_rev); |
3469 | 4338 | ||
3470 | strcpy(card->driver, "HDSPM"); | 4339 | hdspm->is_aes32 = (hdspm->firmware_rev >= HDSPM_AESREVISION); |
4340 | |||
3471 | strcpy(card->mixername, "Xilinx FPGA"); | 4341 | strcpy(card->mixername, "Xilinx FPGA"); |
3472 | hdspm->card_name = "RME HDSPM MADI"; | 4342 | if (hdspm->is_aes32) { |
4343 | strcpy(card->driver, "HDSPAES32"); | ||
4344 | hdspm->card_name = "RME HDSPM AES32"; | ||
4345 | } else { | ||
4346 | strcpy(card->driver, "HDSPM"); | ||
4347 | hdspm->card_name = "RME HDSPM MADI"; | ||
4348 | } | ||
3473 | 4349 | ||
3474 | if ((err = pci_enable_device(pci)) < 0) | 4350 | if ((err = pci_enable_device(pci)) < 0) |
3475 | return err; | 4351 | return err; |
diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c index 474f2d451ae8..3bff32167f66 100644 --- a/sound/pci/trident/trident_main.c +++ b/sound/pci/trident/trident_main.c | |||
@@ -2627,7 +2627,7 @@ static int snd_trident_vol_control_get(struct snd_kcontrol *kcontrol, | |||
2627 | return 0; | 2627 | return 0; |
2628 | } | 2628 | } |
2629 | 2629 | ||
2630 | static DECLARE_TLV_DB_SCALE(db_scale_gvol, -6375, 25, 0); | 2630 | static const DECLARE_TLV_DB_SCALE(db_scale_gvol, -6375, 25, 0); |
2631 | 2631 | ||
2632 | static int snd_trident_vol_control_put(struct snd_kcontrol *kcontrol, | 2632 | static int snd_trident_vol_control_put(struct snd_kcontrol *kcontrol, |
2633 | struct snd_ctl_elem_value *ucontrol) | 2633 | struct snd_ctl_elem_value *ucontrol) |
@@ -2844,7 +2844,7 @@ static int snd_trident_pcm_rvol_control_put(struct snd_kcontrol *kcontrol, | |||
2844 | return change; | 2844 | return change; |
2845 | } | 2845 | } |
2846 | 2846 | ||
2847 | static DECLARE_TLV_DB_SCALE(db_scale_crvol, -3175, 25, 1); | 2847 | static const DECLARE_TLV_DB_SCALE(db_scale_crvol, -3175, 25, 1); |
2848 | 2848 | ||
2849 | static struct snd_kcontrol_new snd_trident_pcm_rvol_control __devinitdata = | 2849 | static struct snd_kcontrol_new snd_trident_pcm_rvol_control __devinitdata = |
2850 | { | 2850 | { |
diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index a572b018807f..a28992269f5e 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c | |||
@@ -1699,7 +1699,7 @@ static int snd_via8233_pcmdxs_volume_put(struct snd_kcontrol *kcontrol, | |||
1699 | return change; | 1699 | return change; |
1700 | } | 1700 | } |
1701 | 1701 | ||
1702 | static DECLARE_TLV_DB_SCALE(db_scale_dxs, -9450, 150, 1); | 1702 | static const DECLARE_TLV_DB_SCALE(db_scale_dxs, -9450, 150, 1); |
1703 | 1703 | ||
1704 | static struct snd_kcontrol_new snd_via8233_pcmdxs_volume_control __devinitdata = { | 1704 | static struct snd_kcontrol_new snd_via8233_pcmdxs_volume_control __devinitdata = { |
1705 | .name = "PCM Playback Volume", | 1705 | .name = "PCM Playback Volume", |
@@ -1823,7 +1823,7 @@ static int __devinit snd_via82xx_mixer_new(struct via82xx *chip, const char *qui | |||
1823 | ac97.private_data = chip; | 1823 | ac97.private_data = chip; |
1824 | ac97.private_free = snd_via82xx_mixer_free_ac97; | 1824 | ac97.private_free = snd_via82xx_mixer_free_ac97; |
1825 | ac97.pci = chip->pci; | 1825 | ac97.pci = chip->pci; |
1826 | ac97.scaps = AC97_SCAP_SKIP_MODEM; | 1826 | ac97.scaps = AC97_SCAP_SKIP_MODEM | AC97_SCAP_POWER_SAVE; |
1827 | if ((err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97)) < 0) | 1827 | if ((err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97)) < 0) |
1828 | return err; | 1828 | return err; |
1829 | 1829 | ||
@@ -2357,93 +2357,59 @@ static struct via823x_info via823x_cards[] __devinitdata = { | |||
2357 | /* | 2357 | /* |
2358 | * auto detection of DXS channel supports. | 2358 | * auto detection of DXS channel supports. |
2359 | */ | 2359 | */ |
2360 | struct dxs_whitelist { | 2360 | |
2361 | unsigned short subvendor; | 2361 | static struct snd_pci_quirk dxs_whitelist[] __devinitdata = { |
2362 | unsigned short subdevice; | 2362 | SND_PCI_QUIRK(0x1005, 0x4710, "Avance Logic Mobo", VIA_DXS_ENABLE), |
2363 | unsigned short mask; | 2363 | SND_PCI_QUIRK(0x1019, 0x0996, "ESC Mobo", VIA_DXS_48K), |
2364 | short action; /* new dxs_support value */ | 2364 | SND_PCI_QUIRK(0x1019, 0x0a81, "ECS K7VTA3 v8.0", VIA_DXS_NO_VRA), |
2365 | SND_PCI_QUIRK(0x1019, 0x0a85, "ECS L7VMM2", VIA_DXS_NO_VRA), | ||
2366 | SND_PCI_QUIRK(0x1019, 0, "ESC K8", VIA_DXS_SRC), | ||
2367 | SND_PCI_QUIRK(0x1019, 0xaa01, "ESC K8T890-A", VIA_DXS_SRC), | ||
2368 | SND_PCI_QUIRK(0x1025, 0x0033, "Acer Inspire 1353LM", VIA_DXS_NO_VRA), | ||
2369 | SND_PCI_QUIRK(0x1025, 0x0046, "Acer Aspire 1524 WLMi", VIA_DXS_SRC), | ||
2370 | SND_PCI_QUIRK(0x1043, 0, "ASUS A7/A8", VIA_DXS_NO_VRA), | ||
2371 | SND_PCI_QUIRK(0x1071, 0, "Diverse Notebook", VIA_DXS_NO_VRA), | ||
2372 | SND_PCI_QUIRK(0x10cf, 0x118e, "FSC Laptop", VIA_DXS_ENABLE), | ||
2373 | SND_PCI_QUIRK(0x1106, 0, "ASRock", VIA_DXS_SRC), | ||
2374 | SND_PCI_QUIRK(0x1297, 0xa232, "Shuttle", VIA_DXS_ENABLE), | ||
2375 | SND_PCI_QUIRK(0x1297, 0xc160, "Shuttle Sk41G", VIA_DXS_ENABLE), | ||
2376 | SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte GA-7VAXP", VIA_DXS_ENABLE), | ||
2377 | SND_PCI_QUIRK(0x1462, 0x3800, "MSI KT266", VIA_DXS_ENABLE), | ||
2378 | SND_PCI_QUIRK(0x1462, 0x7120, "MSI KT4V", VIA_DXS_ENABLE), | ||
2379 | SND_PCI_QUIRK(0x1462, 0x7142, "MSI K8MM-V", VIA_DXS_ENABLE), | ||
2380 | SND_PCI_QUIRK(0x1462, 0, "MSI Mobo", VIA_DXS_SRC), | ||
2381 | SND_PCI_QUIRK(0x147b, 0x1401, "ABIT KD7(-RAID)", VIA_DXS_ENABLE), | ||
2382 | SND_PCI_QUIRK(0x147b, 0x1411, "ABIT VA-20", VIA_DXS_ENABLE), | ||
2383 | SND_PCI_QUIRK(0x147b, 0x1413, "ABIT KV8 Pro", VIA_DXS_ENABLE), | ||
2384 | SND_PCI_QUIRK(0x147b, 0x1415, "ABIT AV8", VIA_DXS_NO_VRA), | ||
2385 | SND_PCI_QUIRK(0x14ff, 0x0403, "Twinhead mobo", VIA_DXS_ENABLE), | ||
2386 | SND_PCI_QUIRK(0x14ff, 0x0408, "Twinhead laptop", VIA_DXS_SRC), | ||
2387 | SND_PCI_QUIRK(0x1558, 0x4701, "Clevo D470", VIA_DXS_SRC), | ||
2388 | SND_PCI_QUIRK(0x1584, 0x8120, "Diverse Laptop", VIA_DXS_ENABLE), | ||
2389 | SND_PCI_QUIRK(0x1584, 0x8123, "Targa/Uniwill", VIA_DXS_NO_VRA), | ||
2390 | SND_PCI_QUIRK(0x161f, 0x202b, "Amira Notebook", VIA_DXS_NO_VRA), | ||
2391 | SND_PCI_QUIRK(0x161f, 0x2032, "m680x machines", VIA_DXS_48K), | ||
2392 | SND_PCI_QUIRK(0x1631, 0xe004, "PB EasyNote 3174", VIA_DXS_ENABLE), | ||
2393 | SND_PCI_QUIRK(0x1695, 0x3005, "EPoX EP-8K9A", VIA_DXS_ENABLE), | ||
2394 | SND_PCI_QUIRK(0x1695, 0, "EPoX mobo", VIA_DXS_SRC), | ||
2395 | SND_PCI_QUIRK(0x16f3, 0, "Jetway K8", VIA_DXS_SRC), | ||
2396 | SND_PCI_QUIRK(0x1734, 0, "FSC Laptop", VIA_DXS_SRC), | ||
2397 | SND_PCI_QUIRK(0x1849, 0x3059, "ASRock K7VM2", VIA_DXS_NO_VRA), | ||
2398 | SND_PCI_QUIRK(0x1849, 0, "ASRock mobo", VIA_DXS_SRC), | ||
2399 | SND_PCI_QUIRK(0x1919, 0x200a, "Soltek SL-K8", VIA_DXS_NO_VRA), | ||
2400 | SND_PCI_QUIRK(0x4005, 0x4710, "MSI K7T266", VIA_DXS_SRC), | ||
2401 | { } /* terminator */ | ||
2365 | }; | 2402 | }; |
2366 | 2403 | ||
2367 | static int __devinit check_dxs_list(struct pci_dev *pci, int revision) | 2404 | static int __devinit check_dxs_list(struct pci_dev *pci, int revision) |
2368 | { | 2405 | { |
2369 | static struct dxs_whitelist whitelist[] __devinitdata = { | 2406 | const struct snd_pci_quirk *w; |
2370 | { .subvendor = 0x1005, .subdevice = 0x4710, .action = VIA_DXS_ENABLE }, /* Avance Logic Mobo */ | ||
2371 | { .subvendor = 0x1019, .subdevice = 0x0996, .action = VIA_DXS_48K }, | ||
2372 | { .subvendor = 0x1019, .subdevice = 0x0a81, .action = VIA_DXS_NO_VRA }, /* ECS K7VTA3 v8.0 */ | ||
2373 | { .subvendor = 0x1019, .subdevice = 0x0a85, .action = VIA_DXS_NO_VRA }, /* ECS L7VMM2 */ | ||
2374 | { .subvendor = 0x1019, .subdevice = 0xa101, .action = VIA_DXS_SRC }, | ||
2375 | { .subvendor = 0x1019, .subdevice = 0xaa01, .action = VIA_DXS_SRC }, /* ECS K8T890-A */ | ||
2376 | { .subvendor = 0x1025, .subdevice = 0x0033, .action = VIA_DXS_NO_VRA }, /* Acer Inspire 1353LM */ | ||
2377 | { .subvendor = 0x1025, .subdevice = 0x0046, .action = VIA_DXS_SRC }, /* Acer Aspire 1524 WLMi */ | ||
2378 | { .subvendor = 0x1043, .subdevice = 0x8095, .action = VIA_DXS_NO_VRA }, /* ASUS A7V8X (FIXME: possibly VIA_DXS_ENABLE?)*/ | ||
2379 | { .subvendor = 0x1043, .subdevice = 0x80a1, .action = VIA_DXS_NO_VRA }, /* ASUS A7V8-X */ | ||
2380 | { .subvendor = 0x1043, .subdevice = 0x80b0, .action = VIA_DXS_NO_VRA }, /* ASUS A7V600 & K8V*/ | ||
2381 | { .subvendor = 0x1043, .subdevice = 0x810d, .action = VIA_DXS_SRC }, /* ASUS */ | ||
2382 | { .subvendor = 0x1043, .subdevice = 0x812a, .action = VIA_DXS_SRC }, /* ASUS A8V Deluxe */ | ||
2383 | { .subvendor = 0x1043, .subdevice = 0x8174, .action = VIA_DXS_SRC }, /* ASUS */ | ||
2384 | { .subvendor = 0x1043, .subdevice = 0x81b9, .action = VIA_DXS_SRC }, /* ASUS A8V-MX */ | ||
2385 | { .subvendor = 0x1071, .subdevice = 0x8375, .action = VIA_DXS_NO_VRA }, /* Vobis/Yakumo/Mitac notebook */ | ||
2386 | { .subvendor = 0x1071, .subdevice = 0x8399, .action = VIA_DXS_NO_VRA }, /* Umax AB 595T (VIA K8N800A - VT8237) */ | ||
2387 | { .subvendor = 0x10cf, .subdevice = 0x118e, .action = VIA_DXS_ENABLE }, /* FSC laptop */ | ||
2388 | { .subvendor = 0x1106, .subdevice = 0x4161, .action = VIA_DXS_NO_VRA }, /* ASRock K7VT2 */ | ||
2389 | { .subvendor = 0x1106, .subdevice = 0x4552, .action = VIA_DXS_NO_VRA }, /* QDI Kudoz 7X/600-6AL */ | ||
2390 | { .subvendor = 0x1106, .subdevice = 0xaa01, .action = VIA_DXS_NO_VRA }, /* EPIA MII */ | ||
2391 | { .subvendor = 0x1106, .subdevice = 0xc001, .action = VIA_DXS_SRC }, /* Insight P4-ITX */ | ||
2392 | { .subvendor = 0x1297, .subdevice = 0xa232, .action = VIA_DXS_ENABLE }, /* Shuttle ?? */ | ||
2393 | { .subvendor = 0x1297, .subdevice = 0xc160, .action = VIA_DXS_ENABLE }, /* Shuttle SK41G */ | ||
2394 | { .subvendor = 0x1458, .subdevice = 0xa002, .action = VIA_DXS_ENABLE }, /* Gigabyte GA-7VAXP */ | ||
2395 | { .subvendor = 0x1462, .subdevice = 0x0080, .action = VIA_DXS_SRC }, /* MSI K8T Neo-FIS2R */ | ||
2396 | { .subvendor = 0x1462, .subdevice = 0x0430, .action = VIA_DXS_SRC }, /* MSI 7142 (K8MM-V) */ | ||
2397 | { .subvendor = 0x1462, .subdevice = 0x0470, .action = VIA_DXS_SRC }, /* MSI KT880 Delta-FSR */ | ||
2398 | { .subvendor = 0x1462, .subdevice = 0x3800, .action = VIA_DXS_ENABLE }, /* MSI KT266 */ | ||
2399 | { .subvendor = 0x1462, .subdevice = 0x5901, .action = VIA_DXS_NO_VRA }, /* MSI KT6 Delta-SR */ | ||
2400 | { .subvendor = 0x1462, .subdevice = 0x7023, .action = VIA_DXS_SRC }, /* MSI K8T Neo2-FI */ | ||
2401 | { .subvendor = 0x1462, .subdevice = 0x7120, .action = VIA_DXS_ENABLE }, /* MSI KT4V */ | ||
2402 | { .subvendor = 0x1462, .subdevice = 0x7142, .action = VIA_DXS_ENABLE }, /* MSI K8MM-V */ | ||
2403 | { .subvendor = 0x1462, .subdevice = 0xb012, .action = VIA_DXS_SRC }, /* P4M800/VIA8237R */ | ||
2404 | { .subvendor = 0x147b, .subdevice = 0x1401, .action = VIA_DXS_ENABLE }, /* ABIT KD7(-RAID) */ | ||
2405 | { .subvendor = 0x147b, .subdevice = 0x1411, .action = VIA_DXS_ENABLE }, /* ABIT VA-20 */ | ||
2406 | { .subvendor = 0x147b, .subdevice = 0x1413, .action = VIA_DXS_ENABLE }, /* ABIT KV8 Pro */ | ||
2407 | { .subvendor = 0x147b, .subdevice = 0x1415, .action = VIA_DXS_NO_VRA }, /* Abit AV8 */ | ||
2408 | { .subvendor = 0x14ff, .subdevice = 0x0403, .action = VIA_DXS_ENABLE }, /* Twinhead mobo */ | ||
2409 | { .subvendor = 0x14ff, .subdevice = 0x0408, .action = VIA_DXS_SRC }, /* Twinhead laptop */ | ||
2410 | { .subvendor = 0x1558, .subdevice = 0x4701, .action = VIA_DXS_SRC }, /* Clevo D470 */ | ||
2411 | { .subvendor = 0x1584, .subdevice = 0x8120, .action = VIA_DXS_ENABLE }, /* Gericom/Targa/Vobis/Uniwill laptop */ | ||
2412 | { .subvendor = 0x1584, .subdevice = 0x8123, .action = VIA_DXS_NO_VRA }, /* Uniwill (Targa Visionary XP-210) */ | ||
2413 | { .subvendor = 0x161f, .subdevice = 0x202b, .action = VIA_DXS_NO_VRA }, /* Amira Note book */ | ||
2414 | { .subvendor = 0x161f, .subdevice = 0x2032, .action = VIA_DXS_48K }, /* m680x machines */ | ||
2415 | { .subvendor = 0x1631, .subdevice = 0xe004, .action = VIA_DXS_ENABLE }, /* Easy Note 3174, Packard Bell */ | ||
2416 | { .subvendor = 0x1695, .subdevice = 0x3005, .action = VIA_DXS_ENABLE }, /* EPoX EP-8K9A */ | ||
2417 | { .subvendor = 0x1695, .subdevice = 0x300c, .action = VIA_DXS_SRC }, /* EPoX EP-8KRAI */ | ||
2418 | { .subvendor = 0x1695, .subdevice = 0x300e, .action = VIA_DXS_SRC }, /* EPoX 9HEAI */ | ||
2419 | { .subvendor = 0x16f3, .subdevice = 0x6405, .action = VIA_DXS_SRC }, /* Jetway K8M8MS */ | ||
2420 | { .subvendor = 0x1734, .subdevice = 0x1078, .action = VIA_DXS_SRC }, /* FSC Amilo L7300 */ | ||
2421 | { .subvendor = 0x1734, .subdevice = 0x1093, .action = VIA_DXS_SRC }, /* FSC */ | ||
2422 | { .subvendor = 0x1734, .subdevice = 0x10ab, .action = VIA_DXS_SRC }, /* FSC */ | ||
2423 | { .subvendor = 0x1849, .subdevice = 0x3059, .action = VIA_DXS_NO_VRA }, /* ASRock K7VM2 */ | ||
2424 | { .subvendor = 0x1849, .subdevice = 0x9739, .action = VIA_DXS_SRC }, /* ASRock mobo(?) */ | ||
2425 | { .subvendor = 0x1849, .subdevice = 0x9761, .action = VIA_DXS_SRC }, /* ASRock mobo(?) */ | ||
2426 | { .subvendor = 0x1919, .subdevice = 0x200a, .action = VIA_DXS_NO_VRA }, /* Soltek SL-K8Tpro-939 */ | ||
2427 | { .subvendor = 0x4005, .subdevice = 0x4710, .action = VIA_DXS_SRC }, /* MSI K7T266 Pro2 (MS-6380 V2.0) BIOS 3.7 */ | ||
2428 | { } /* terminator */ | ||
2429 | }; | ||
2430 | const struct dxs_whitelist *w; | ||
2431 | unsigned short subsystem_vendor; | ||
2432 | unsigned short subsystem_device; | ||
2433 | |||
2434 | pci_read_config_word(pci, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vendor); | ||
2435 | pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &subsystem_device); | ||
2436 | 2407 | ||
2437 | for (w = whitelist; w->subvendor; w++) { | 2408 | w = snd_pci_quirk_lookup(pci, dxs_whitelist); |
2438 | if (w->subvendor != subsystem_vendor) | 2409 | if (w) { |
2439 | continue; | 2410 | snd_printdd(KERN_INFO "via82xx: DXS white list for %s found\n", |
2440 | if (w->mask) { | 2411 | w->name); |
2441 | if ((w->mask & subsystem_device) == w->subdevice) | 2412 | return w->value; |
2442 | return w->action; | ||
2443 | } else { | ||
2444 | if (subsystem_device == w->subdevice) | ||
2445 | return w->action; | ||
2446 | } | ||
2447 | } | 2413 | } |
2448 | 2414 | ||
2449 | /* for newer revision, default to DXS_SRC */ | 2415 | /* for newer revision, default to DXS_SRC */ |
diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c index 17d6b847585f..b338e15db0d9 100644 --- a/sound/pci/via82xx_modem.c +++ b/sound/pci/via82xx_modem.c | |||
@@ -900,7 +900,7 @@ static int __devinit snd_via82xx_mixer_new(struct via82xx_modem *chip) | |||
900 | ac97.private_data = chip; | 900 | ac97.private_data = chip; |
901 | ac97.private_free = snd_via82xx_mixer_free_ac97; | 901 | ac97.private_free = snd_via82xx_mixer_free_ac97; |
902 | ac97.pci = chip->pci; | 902 | ac97.pci = chip->pci; |
903 | ac97.scaps = AC97_SCAP_SKIP_AUDIO; | 903 | ac97.scaps = AC97_SCAP_SKIP_AUDIO | AC97_SCAP_POWER_SAVE; |
904 | ac97.num = chip->ac97_secondary; | 904 | ac97.num = chip->ac97_secondary; |
905 | 905 | ||
906 | if ((err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97)) < 0) | 906 | if ((err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97)) < 0) |
diff --git a/sound/pci/vx222/vx222.c b/sound/pci/vx222/vx222.c index 89f58ea180b3..474eac9490ae 100644 --- a/sound/pci/vx222/vx222.c +++ b/sound/pci/vx222/vx222.c | |||
@@ -73,8 +73,8 @@ MODULE_DEVICE_TABLE(pci, snd_vx222_ids); | |||
73 | /* | 73 | /* |
74 | */ | 74 | */ |
75 | 75 | ||
76 | static DECLARE_TLV_DB_SCALE(db_scale_old_vol, -11350, 50, 0); | 76 | static const DECLARE_TLV_DB_SCALE(db_scale_old_vol, -11350, 50, 0); |
77 | static DECLARE_TLV_DB_SCALE(db_scale_akm, -7350, 50, 0); | 77 | static const DECLARE_TLV_DB_SCALE(db_scale_akm, -7350, 50, 0); |
78 | 78 | ||
79 | static struct snd_vx_hardware vx222_old_hw = { | 79 | static struct snd_vx_hardware vx222_old_hw = { |
80 | 80 | ||
diff --git a/sound/pci/vx222/vx222_ops.c b/sound/pci/vx222/vx222_ops.c index 5e51950e05f9..55558bef7166 100644 --- a/sound/pci/vx222/vx222_ops.c +++ b/sound/pci/vx222/vx222_ops.c | |||
@@ -846,7 +846,7 @@ static void vx2_set_input_level(struct snd_vx222 *chip) | |||
846 | 846 | ||
847 | #define MIC_LEVEL_MAX 0xff | 847 | #define MIC_LEVEL_MAX 0xff |
848 | 848 | ||
849 | static DECLARE_TLV_DB_SCALE(db_scale_mic, -6450, 50, 0); | 849 | static const DECLARE_TLV_DB_SCALE(db_scale_mic, -6450, 50, 0); |
850 | 850 | ||
851 | /* | 851 | /* |
852 | * controls API for input levels | 852 | * controls API for input levels |
diff --git a/sound/pci/ymfpci/ymfpci_image.h b/sound/pci/ymfpci/ymfpci_image.h index 1b0746991669..112f2fff6c8e 100644 --- a/sound/pci/ymfpci/ymfpci_image.h +++ b/sound/pci/ymfpci/ymfpci_image.h | |||
@@ -1,7 +1,7 @@ | |||
1 | #ifndef _HWMCODE_ | 1 | #ifndef _HWMCODE_ |
2 | #define _HWMCODE_ | 2 | #define _HWMCODE_ |
3 | 3 | ||
4 | static unsigned long DspInst[YDSXG_DSPLENGTH / 4] = { | 4 | static u32 DspInst[YDSXG_DSPLENGTH / 4] = { |
5 | 0x00000081, 0x000001a4, 0x0000000a, 0x0000002f, | 5 | 0x00000081, 0x000001a4, 0x0000000a, 0x0000002f, |
6 | 0x00080253, 0x01800317, 0x0000407b, 0x0000843f, | 6 | 0x00080253, 0x01800317, 0x0000407b, 0x0000843f, |
7 | 0x0001483c, 0x0001943c, 0x0005d83c, 0x00001c3c, | 7 | 0x0001483c, 0x0001943c, 0x0005d83c, 0x00001c3c, |
@@ -12,7 +12,7 @@ static unsigned long DspInst[YDSXG_DSPLENGTH / 4] = { | |||
12 | 0x00000000, 0x00000000, 0x00000000, 0x00000000 | 12 | 0x00000000, 0x00000000, 0x00000000, 0x00000000 |
13 | }; | 13 | }; |
14 | 14 | ||
15 | static unsigned long CntrlInst[YDSXG_CTRLLENGTH / 4] = { | 15 | static u32 CntrlInst[YDSXG_CTRLLENGTH / 4] = { |
16 | 0x000007, 0x240007, 0x0C0007, 0x1C0007, | 16 | 0x000007, 0x240007, 0x0C0007, 0x1C0007, |
17 | 0x060007, 0x700002, 0x000020, 0x030040, | 17 | 0x060007, 0x700002, 0x000020, 0x030040, |
18 | 0x007104, 0x004286, 0x030040, 0x000F0D, | 18 | 0x007104, 0x004286, 0x030040, 0x000F0D, |
@@ -791,7 +791,7 @@ static unsigned long CntrlInst[YDSXG_CTRLLENGTH / 4] = { | |||
791 | // 04/09 creat | 791 | // 04/09 creat |
792 | // 04/12 stop nise fix | 792 | // 04/12 stop nise fix |
793 | // 06/21 WorkingOff timming | 793 | // 06/21 WorkingOff timming |
794 | static unsigned long CntrlInst1E[YDSXG_CTRLLENGTH / 4] = { | 794 | static u32 CntrlInst1E[YDSXG_CTRLLENGTH / 4] = { |
795 | 0x000007, 0x240007, 0x0C0007, 0x1C0007, | 795 | 0x000007, 0x240007, 0x0C0007, 0x1C0007, |
796 | 0x060007, 0x700002, 0x000020, 0x030040, | 796 | 0x060007, 0x700002, 0x000020, 0x030040, |
797 | 0x007104, 0x004286, 0x030040, 0x000F0D, | 797 | 0x007104, 0x004286, 0x030040, 0x000F0D, |
diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c index 7881944a1957..fd12674d0394 100644 --- a/sound/pci/ymfpci/ymfpci_main.c +++ b/sound/pci/ymfpci/ymfpci_main.c | |||
@@ -2,12 +2,6 @@ | |||
2 | * Copyright (c) by Jaroslav Kysela <perex@suse.cz> | 2 | * Copyright (c) by Jaroslav Kysela <perex@suse.cz> |
3 | * Routines for control of YMF724/740/744/754 chips | 3 | * Routines for control of YMF724/740/744/754 chips |
4 | * | 4 | * |
5 | * BUGS: | ||
6 | * -- | ||
7 | * | ||
8 | * TODO: | ||
9 | * -- | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | 5 | * This program is free software; you can redistribute it and/or modify |
12 | * it under the terms of the GNU General Public License as published by | 6 | * it under the terms of the GNU General Public License as published by |
13 | * the Free Software Foundation; either version 2 of the License, or | 7 | * the Free Software Foundation; either version 2 of the License, or |
@@ -26,6 +20,7 @@ | |||
26 | 20 | ||
27 | #include <sound/driver.h> | 21 | #include <sound/driver.h> |
28 | #include <linux/delay.h> | 22 | #include <linux/delay.h> |
23 | #include <linux/firmware.h> | ||
29 | #include <linux/init.h> | 24 | #include <linux/init.h> |
30 | #include <linux/interrupt.h> | 25 | #include <linux/interrupt.h> |
31 | #include <linux/pci.h> | 26 | #include <linux/pci.h> |
@@ -42,10 +37,7 @@ | |||
42 | #include <sound/mpu401.h> | 37 | #include <sound/mpu401.h> |
43 | 38 | ||
44 | #include <asm/io.h> | 39 | #include <asm/io.h> |
45 | 40 | #include <asm/byteorder.h> | |
46 | /* | ||
47 | * constants | ||
48 | */ | ||
49 | 41 | ||
50 | /* | 42 | /* |
51 | * common I/O routines | 43 | * common I/O routines |
@@ -179,6 +171,17 @@ static u32 snd_ymfpci_calc_lpfQ(u32 rate) | |||
179 | return val[0]; | 171 | return val[0]; |
180 | } | 172 | } |
181 | 173 | ||
174 | static void snd_ymfpci_pcm_441_volume_set(struct snd_ymfpci_pcm *ypcm) | ||
175 | { | ||
176 | unsigned int value; | ||
177 | struct snd_ymfpci_pcm_mixer *mixer; | ||
178 | |||
179 | mixer = &ypcm->chip->pcm_mixer[ypcm->substream->number]; | ||
180 | value = min_t(unsigned int, mixer->left, 0x7fff) >> 1; | ||
181 | value |= (min_t(unsigned int, mixer->right, 0x7fff) >> 1) << 16; | ||
182 | snd_ymfpci_writel(ypcm->chip, YDSXGR_BUF441OUTVOL, value); | ||
183 | } | ||
184 | |||
182 | /* | 185 | /* |
183 | * Hardware start management | 186 | * Hardware start management |
184 | */ | 187 | */ |
@@ -290,6 +293,10 @@ static int snd_ymfpci_voice_free(struct snd_ymfpci *chip, struct snd_ymfpci_voic | |||
290 | snd_assert(pvoice != NULL, return -EINVAL); | 293 | snd_assert(pvoice != NULL, return -EINVAL); |
291 | snd_ymfpci_hw_stop(chip); | 294 | snd_ymfpci_hw_stop(chip); |
292 | spin_lock_irqsave(&chip->voice_lock, flags); | 295 | spin_lock_irqsave(&chip->voice_lock, flags); |
296 | if (pvoice->number == chip->src441_used) { | ||
297 | chip->src441_used = -1; | ||
298 | pvoice->ypcm->use_441_slot = 0; | ||
299 | } | ||
293 | pvoice->use = pvoice->pcm = pvoice->synth = pvoice->midi = 0; | 300 | pvoice->use = pvoice->pcm = pvoice->synth = pvoice->midi = 0; |
294 | pvoice->ypcm = NULL; | 301 | pvoice->ypcm = NULL; |
295 | pvoice->interrupt = NULL; | 302 | pvoice->interrupt = NULL; |
@@ -394,7 +401,7 @@ static int snd_ymfpci_playback_trigger(struct snd_pcm_substream *substream, | |||
394 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 401 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
395 | case SNDRV_PCM_TRIGGER_RESUME: | 402 | case SNDRV_PCM_TRIGGER_RESUME: |
396 | chip->ctrl_playback[ypcm->voices[0]->number + 1] = cpu_to_le32(ypcm->voices[0]->bank_addr); | 403 | chip->ctrl_playback[ypcm->voices[0]->number + 1] = cpu_to_le32(ypcm->voices[0]->bank_addr); |
397 | if (ypcm->voices[1] != NULL) | 404 | if (ypcm->voices[1] != NULL && !ypcm->use_441_slot) |
398 | chip->ctrl_playback[ypcm->voices[1]->number + 1] = cpu_to_le32(ypcm->voices[1]->bank_addr); | 405 | chip->ctrl_playback[ypcm->voices[1]->number + 1] = cpu_to_le32(ypcm->voices[1]->bank_addr); |
399 | ypcm->running = 1; | 406 | ypcm->running = 1; |
400 | break; | 407 | break; |
@@ -402,7 +409,7 @@ static int snd_ymfpci_playback_trigger(struct snd_pcm_substream *substream, | |||
402 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 409 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
403 | case SNDRV_PCM_TRIGGER_SUSPEND: | 410 | case SNDRV_PCM_TRIGGER_SUSPEND: |
404 | chip->ctrl_playback[ypcm->voices[0]->number + 1] = 0; | 411 | chip->ctrl_playback[ypcm->voices[0]->number + 1] = 0; |
405 | if (ypcm->voices[1] != NULL) | 412 | if (ypcm->voices[1] != NULL && !ypcm->use_441_slot) |
406 | chip->ctrl_playback[ypcm->voices[1]->number + 1] = 0; | 413 | chip->ctrl_playback[ypcm->voices[1]->number + 1] = 0; |
407 | ypcm->running = 0; | 414 | ypcm->running = 0; |
408 | break; | 415 | break; |
@@ -489,6 +496,7 @@ static void snd_ymfpci_pcm_init_voice(struct snd_ymfpci_pcm *ypcm, unsigned int | |||
489 | unsigned int nbank; | 496 | unsigned int nbank; |
490 | u32 vol_left, vol_right; | 497 | u32 vol_left, vol_right; |
491 | u8 use_left, use_right; | 498 | u8 use_left, use_right; |
499 | unsigned long flags; | ||
492 | 500 | ||
493 | snd_assert(voice != NULL, return); | 501 | snd_assert(voice != NULL, return); |
494 | if (runtime->channels == 1) { | 502 | if (runtime->channels == 1) { |
@@ -507,11 +515,27 @@ static void snd_ymfpci_pcm_init_voice(struct snd_ymfpci_pcm *ypcm, unsigned int | |||
507 | vol_left = cpu_to_le32(0x40000000); | 515 | vol_left = cpu_to_le32(0x40000000); |
508 | vol_right = cpu_to_le32(0x40000000); | 516 | vol_right = cpu_to_le32(0x40000000); |
509 | } | 517 | } |
518 | spin_lock_irqsave(&ypcm->chip->voice_lock, flags); | ||
510 | format = runtime->channels == 2 ? 0x00010000 : 0; | 519 | format = runtime->channels == 2 ? 0x00010000 : 0; |
511 | if (snd_pcm_format_width(runtime->format) == 8) | 520 | if (snd_pcm_format_width(runtime->format) == 8) |
512 | format |= 0x80000000; | 521 | format |= 0x80000000; |
522 | else if (ypcm->chip->device_id == PCI_DEVICE_ID_YAMAHA_754 && | ||
523 | runtime->rate == 44100 && runtime->channels == 2 && | ||
524 | voiceidx == 0 && (ypcm->chip->src441_used == -1 || | ||
525 | ypcm->chip->src441_used == voice->number)) { | ||
526 | ypcm->chip->src441_used = voice->number; | ||
527 | ypcm->use_441_slot = 1; | ||
528 | format |= 0x10000000; | ||
529 | snd_ymfpci_pcm_441_volume_set(ypcm); | ||
530 | } | ||
531 | if (ypcm->chip->src441_used == voice->number && | ||
532 | (format & 0x10000000) == 0) { | ||
533 | ypcm->chip->src441_used = -1; | ||
534 | ypcm->use_441_slot = 0; | ||
535 | } | ||
513 | if (runtime->channels == 2 && (voiceidx & 1) != 0) | 536 | if (runtime->channels == 2 && (voiceidx & 1) != 0) |
514 | format |= 1; | 537 | format |= 1; |
538 | spin_unlock_irqrestore(&ypcm->chip->voice_lock, flags); | ||
515 | for (nbank = 0; nbank < 2; nbank++) { | 539 | for (nbank = 0; nbank < 2; nbank++) { |
516 | bank = &voice->bank[nbank]; | 540 | bank = &voice->bank[nbank]; |
517 | memset(bank, 0, sizeof(*bank)); | 541 | memset(bank, 0, sizeof(*bank)); |
@@ -1480,7 +1504,7 @@ static int snd_ymfpci_put_single(struct snd_kcontrol *kcontrol, | |||
1480 | return change; | 1504 | return change; |
1481 | } | 1505 | } |
1482 | 1506 | ||
1483 | static DECLARE_TLV_DB_LINEAR(db_scale_native, TLV_DB_GAIN_MUTE, 0); | 1507 | static const DECLARE_TLV_DB_LINEAR(db_scale_native, TLV_DB_GAIN_MUTE, 0); |
1484 | 1508 | ||
1485 | #define YMFPCI_DOUBLE(xname, xindex, reg) \ | 1509 | #define YMFPCI_DOUBLE(xname, xindex, reg) \ |
1486 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ | 1510 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ |
@@ -1722,7 +1746,10 @@ static int snd_ymfpci_pcm_vol_put(struct snd_kcontrol *kcontrol, | |||
1722 | spin_lock_irqsave(&chip->voice_lock, flags); | 1746 | spin_lock_irqsave(&chip->voice_lock, flags); |
1723 | if (substream->runtime && substream->runtime->private_data) { | 1747 | if (substream->runtime && substream->runtime->private_data) { |
1724 | struct snd_ymfpci_pcm *ypcm = substream->runtime->private_data; | 1748 | struct snd_ymfpci_pcm *ypcm = substream->runtime->private_data; |
1725 | ypcm->update_pcm_vol = 2; | 1749 | if (!ypcm->use_441_slot) |
1750 | ypcm->update_pcm_vol = 2; | ||
1751 | else | ||
1752 | snd_ymfpci_pcm_441_volume_set(ypcm); | ||
1726 | } | 1753 | } |
1727 | spin_unlock_irqrestore(&chip->voice_lock, flags); | 1754 | spin_unlock_irqrestore(&chip->voice_lock, flags); |
1728 | return 1; | 1755 | return 1; |
@@ -1971,13 +1998,94 @@ static void snd_ymfpci_disable_dsp(struct snd_ymfpci *chip) | |||
1971 | } | 1998 | } |
1972 | } | 1999 | } |
1973 | 2000 | ||
2001 | #define FIRMWARE_IN_THE_KERNEL | ||
2002 | |||
2003 | #ifdef FIRMWARE_IN_THE_KERNEL | ||
2004 | |||
1974 | #include "ymfpci_image.h" | 2005 | #include "ymfpci_image.h" |
1975 | 2006 | ||
2007 | static struct firmware snd_ymfpci_dsp_microcode = { | ||
2008 | .size = YDSXG_DSPLENGTH, | ||
2009 | .data = (u8 *)DspInst, | ||
2010 | }; | ||
2011 | static struct firmware snd_ymfpci_controller_microcode = { | ||
2012 | .size = YDSXG_CTRLLENGTH, | ||
2013 | .data = (u8 *)CntrlInst, | ||
2014 | }; | ||
2015 | static struct firmware snd_ymfpci_controller_1e_microcode = { | ||
2016 | .size = YDSXG_CTRLLENGTH, | ||
2017 | .data = (u8 *)CntrlInst1E, | ||
2018 | }; | ||
2019 | #endif | ||
2020 | |||
2021 | #ifdef __LITTLE_ENDIAN | ||
2022 | static inline void snd_ymfpci_convert_from_le(const struct firmware *fw) { } | ||
2023 | #else | ||
2024 | static void snd_ymfpci_convert_from_le(const struct firmware *fw) | ||
2025 | { | ||
2026 | int i; | ||
2027 | u32 *data = (u32 *)fw->data; | ||
2028 | |||
2029 | for (i = 0; i < fw->size / 4; ++i) | ||
2030 | le32_to_cpus(&data[i]); | ||
2031 | } | ||
2032 | #endif | ||
2033 | |||
2034 | static int snd_ymfpci_request_firmware(struct snd_ymfpci *chip) | ||
2035 | { | ||
2036 | int err, is_1e; | ||
2037 | const char *name; | ||
2038 | |||
2039 | err = request_firmware(&chip->dsp_microcode, "yamaha/ds1_dsp.fw", | ||
2040 | &chip->pci->dev); | ||
2041 | if (err >= 0) { | ||
2042 | if (chip->dsp_microcode->size == YDSXG_DSPLENGTH) | ||
2043 | snd_ymfpci_convert_from_le(chip->dsp_microcode); | ||
2044 | else { | ||
2045 | snd_printk(KERN_ERR "DSP microcode has wrong size\n"); | ||
2046 | err = -EINVAL; | ||
2047 | } | ||
2048 | } | ||
2049 | if (err < 0) { | ||
2050 | #ifdef FIRMWARE_IN_THE_KERNEL | ||
2051 | chip->dsp_microcode = &snd_ymfpci_dsp_microcode; | ||
2052 | #else | ||
2053 | return err; | ||
2054 | #endif | ||
2055 | } | ||
2056 | is_1e = chip->device_id == PCI_DEVICE_ID_YAMAHA_724F || | ||
2057 | chip->device_id == PCI_DEVICE_ID_YAMAHA_740C || | ||
2058 | chip->device_id == PCI_DEVICE_ID_YAMAHA_744 || | ||
2059 | chip->device_id == PCI_DEVICE_ID_YAMAHA_754; | ||
2060 | name = is_1e ? "yamaha/ds1e_ctrl.fw" : "yamaha/ds1_ctrl.fw"; | ||
2061 | err = request_firmware(&chip->controller_microcode, name, | ||
2062 | &chip->pci->dev); | ||
2063 | if (err >= 0) { | ||
2064 | if (chip->controller_microcode->size == YDSXG_CTRLLENGTH) | ||
2065 | snd_ymfpci_convert_from_le(chip->controller_microcode); | ||
2066 | else { | ||
2067 | snd_printk(KERN_ERR "controller microcode" | ||
2068 | " has wrong size\n"); | ||
2069 | err = -EINVAL; | ||
2070 | } | ||
2071 | } | ||
2072 | if (err < 0) { | ||
2073 | #ifdef FIRMWARE_IN_THE_KERNEL | ||
2074 | chip->controller_microcode = | ||
2075 | is_1e ? &snd_ymfpci_controller_1e_microcode | ||
2076 | : &snd_ymfpci_controller_microcode; | ||
2077 | #else | ||
2078 | return err; | ||
2079 | #endif | ||
2080 | } | ||
2081 | return 0; | ||
2082 | } | ||
2083 | |||
1976 | static void snd_ymfpci_download_image(struct snd_ymfpci *chip) | 2084 | static void snd_ymfpci_download_image(struct snd_ymfpci *chip) |
1977 | { | 2085 | { |
1978 | int i; | 2086 | int i; |
1979 | u16 ctrl; | 2087 | u16 ctrl; |
1980 | unsigned long *inst; | 2088 | u32 *inst; |
1981 | 2089 | ||
1982 | snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0x00000000); | 2090 | snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0x00000000); |
1983 | snd_ymfpci_disable_dsp(chip); | 2091 | snd_ymfpci_disable_dsp(chip); |
@@ -1992,21 +2100,12 @@ static void snd_ymfpci_download_image(struct snd_ymfpci *chip) | |||
1992 | snd_ymfpci_writew(chip, YDSXGR_GLOBALCTRL, ctrl & ~0x0007); | 2100 | snd_ymfpci_writew(chip, YDSXGR_GLOBALCTRL, ctrl & ~0x0007); |
1993 | 2101 | ||
1994 | /* setup DSP instruction code */ | 2102 | /* setup DSP instruction code */ |
2103 | inst = (u32 *)chip->dsp_microcode->data; | ||
1995 | for (i = 0; i < YDSXG_DSPLENGTH / 4; i++) | 2104 | for (i = 0; i < YDSXG_DSPLENGTH / 4; i++) |
1996 | snd_ymfpci_writel(chip, YDSXGR_DSPINSTRAM + (i << 2), DspInst[i]); | 2105 | snd_ymfpci_writel(chip, YDSXGR_DSPINSTRAM + (i << 2), inst[i]); |
1997 | 2106 | ||
1998 | /* setup control instruction code */ | 2107 | /* setup control instruction code */ |
1999 | switch (chip->device_id) { | 2108 | inst = (u32 *)chip->controller_microcode->data; |
2000 | case PCI_DEVICE_ID_YAMAHA_724F: | ||
2001 | case PCI_DEVICE_ID_YAMAHA_740C: | ||
2002 | case PCI_DEVICE_ID_YAMAHA_744: | ||
2003 | case PCI_DEVICE_ID_YAMAHA_754: | ||
2004 | inst = CntrlInst1E; | ||
2005 | break; | ||
2006 | default: | ||
2007 | inst = CntrlInst; | ||
2008 | break; | ||
2009 | } | ||
2010 | for (i = 0; i < YDSXG_CTRLLENGTH / 4; i++) | 2109 | for (i = 0; i < YDSXG_CTRLLENGTH / 4; i++) |
2011 | snd_ymfpci_writel(chip, YDSXGR_CTRLINSTRAM + (i << 2), inst[i]); | 2110 | snd_ymfpci_writel(chip, YDSXGR_CTRLINSTRAM + (i << 2), inst[i]); |
2012 | 2111 | ||
@@ -2160,6 +2259,15 @@ static int snd_ymfpci_free(struct snd_ymfpci *chip) | |||
2160 | pci_write_config_word(chip->pci, 0x40, chip->old_legacy_ctrl); | 2259 | pci_write_config_word(chip->pci, 0x40, chip->old_legacy_ctrl); |
2161 | 2260 | ||
2162 | pci_disable_device(chip->pci); | 2261 | pci_disable_device(chip->pci); |
2262 | #ifdef FIRMWARE_IN_THE_KERNEL | ||
2263 | if (chip->dsp_microcode != &snd_ymfpci_dsp_microcode) | ||
2264 | #endif | ||
2265 | release_firmware(chip->dsp_microcode); | ||
2266 | #ifdef FIRMWARE_IN_THE_KERNEL | ||
2267 | if (chip->controller_microcode != &snd_ymfpci_controller_microcode && | ||
2268 | chip->controller_microcode != &snd_ymfpci_controller_1e_microcode) | ||
2269 | #endif | ||
2270 | release_firmware(chip->controller_microcode); | ||
2163 | kfree(chip); | 2271 | kfree(chip); |
2164 | return 0; | 2272 | return 0; |
2165 | } | 2273 | } |
@@ -2180,7 +2288,7 @@ static int saved_regs_index[] = { | |||
2180 | YDSXGR_PRIADCLOOPVOL, | 2288 | YDSXGR_PRIADCLOOPVOL, |
2181 | YDSXGR_NATIVEDACINVOL, | 2289 | YDSXGR_NATIVEDACINVOL, |
2182 | YDSXGR_NATIVEDACOUTVOL, | 2290 | YDSXGR_NATIVEDACOUTVOL, |
2183 | // YDSXGR_BUF441OUTVOL, | 2291 | YDSXGR_BUF441OUTVOL, |
2184 | YDSXGR_NATIVEADCINVOL, | 2292 | YDSXGR_NATIVEADCINVOL, |
2185 | YDSXGR_SPDIFLOOPVOL, | 2293 | YDSXGR_SPDIFLOOPVOL, |
2186 | YDSXGR_SPDIFOUTVOL, | 2294 | YDSXGR_SPDIFOUTVOL, |
@@ -2295,6 +2403,7 @@ int __devinit snd_ymfpci_create(struct snd_card *card, | |||
2295 | chip->reg_area_phys = pci_resource_start(pci, 0); | 2403 | chip->reg_area_phys = pci_resource_start(pci, 0); |
2296 | chip->reg_area_virt = ioremap_nocache(chip->reg_area_phys, 0x8000); | 2404 | chip->reg_area_virt = ioremap_nocache(chip->reg_area_phys, 0x8000); |
2297 | pci_set_master(pci); | 2405 | pci_set_master(pci); |
2406 | chip->src441_used = -1; | ||
2298 | 2407 | ||
2299 | if ((chip->res_reg_area = request_mem_region(chip->reg_area_phys, 0x8000, "YMFPCI")) == NULL) { | 2408 | if ((chip->res_reg_area = request_mem_region(chip->reg_area_phys, 0x8000, "YMFPCI")) == NULL) { |
2300 | snd_printk(KERN_ERR "unable to grab memory region 0x%lx-0x%lx\n", chip->reg_area_phys, chip->reg_area_phys + 0x8000 - 1); | 2409 | snd_printk(KERN_ERR "unable to grab memory region 0x%lx-0x%lx\n", chip->reg_area_phys, chip->reg_area_phys + 0x8000 - 1); |
@@ -2315,6 +2424,12 @@ int __devinit snd_ymfpci_create(struct snd_card *card, | |||
2315 | return -EIO; | 2424 | return -EIO; |
2316 | } | 2425 | } |
2317 | 2426 | ||
2427 | err = snd_ymfpci_request_firmware(chip); | ||
2428 | if (err < 0) { | ||
2429 | snd_printk(KERN_ERR "firmware request failed: %d\n", err); | ||
2430 | snd_ymfpci_free(chip); | ||
2431 | return err; | ||
2432 | } | ||
2318 | snd_ymfpci_download_image(chip); | 2433 | snd_ymfpci_download_image(chip); |
2319 | 2434 | ||
2320 | udelay(100); /* seems we need a delay after downloading image.. */ | 2435 | udelay(100); /* seems we need a delay after downloading image.. */ |
diff --git a/sound/pcmcia/vx/vxp_mixer.c b/sound/pcmcia/vx/vxp_mixer.c index bced7b623b12..2b1f996c898d 100644 --- a/sound/pcmcia/vx/vxp_mixer.c +++ b/sound/pcmcia/vx/vxp_mixer.c | |||
@@ -64,7 +64,7 @@ static int vx_mic_level_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v | |||
64 | return 0; | 64 | return 0; |
65 | } | 65 | } |
66 | 66 | ||
67 | static DECLARE_TLV_DB_SCALE(db_scale_mic, -21, 3, 0); | 67 | static const DECLARE_TLV_DB_SCALE(db_scale_mic, -21, 3, 0); |
68 | 68 | ||
69 | static struct snd_kcontrol_new vx_control_mic_level = { | 69 | static struct snd_kcontrol_new vx_control_mic_level = { |
70 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 70 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
diff --git a/sound/pcmcia/vx/vxpocket.c b/sound/pcmcia/vx/vxpocket.c index d7df59e9c647..363bcb5f08e6 100644 --- a/sound/pcmcia/vx/vxpocket.c +++ b/sound/pcmcia/vx/vxpocket.c | |||
@@ -91,7 +91,7 @@ static int snd_vxpocket_dev_free(struct snd_device *device) | |||
91 | * Only output levels can be modified | 91 | * Only output levels can be modified |
92 | */ | 92 | */ |
93 | 93 | ||
94 | static DECLARE_TLV_DB_SCALE(db_scale_old_vol, -11350, 50, 0); | 94 | static const DECLARE_TLV_DB_SCALE(db_scale_old_vol, -11350, 50, 0); |
95 | 95 | ||
96 | static struct snd_vx_hardware vxpocket_hw = { | 96 | static struct snd_vx_hardware vxpocket_hw = { |
97 | .name = "VXPocket", | 97 | .name = "VXPocket", |
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig new file mode 100644 index 000000000000..ec821a57f843 --- /dev/null +++ b/sound/soc/Kconfig | |||
@@ -0,0 +1,32 @@ | |||
1 | # | ||
2 | # SoC audio configuration | ||
3 | # | ||
4 | |||
5 | menu "SoC audio support" | ||
6 | depends on SND!=n | ||
7 | |||
8 | config SND_SOC_AC97_BUS | ||
9 | bool | ||
10 | |||
11 | config SND_SOC | ||
12 | tristate "SoC audio support" | ||
13 | ---help--- | ||
14 | |||
15 | If you want SoC support, you should say Y here and also to the | ||
16 | specific driver for your SoC below. You will also need to select the | ||
17 | specific codec(s) attached to the SoC | ||
18 | |||
19 | This SoC audio support can also be built as a module. If so, the module | ||
20 | will be called snd-soc-core. | ||
21 | |||
22 | # All the supported Soc's | ||
23 | menu "SoC Platforms" | ||
24 | depends on SND_SOC | ||
25 | source "sound/soc/at91/Kconfig" | ||
26 | source "sound/soc/pxa/Kconfig" | ||
27 | endmenu | ||
28 | |||
29 | # Supported codecs | ||
30 | source "sound/soc/codecs/Kconfig" | ||
31 | |||
32 | endmenu | ||
diff --git a/sound/soc/Makefile b/sound/soc/Makefile new file mode 100644 index 000000000000..98e6f49dafc2 --- /dev/null +++ b/sound/soc/Makefile | |||
@@ -0,0 +1,4 @@ | |||
1 | snd-soc-core-objs := soc-core.o soc-dapm.o | ||
2 | |||
3 | obj-$(CONFIG_SND_SOC) += snd-soc-core.o | ||
4 | obj-$(CONFIG_SND_SOC) += codecs/ at91/ pxa/ | ||
diff --git a/sound/soc/at91/Kconfig b/sound/soc/at91/Kconfig new file mode 100644 index 000000000000..5bcf08b728b0 --- /dev/null +++ b/sound/soc/at91/Kconfig | |||
@@ -0,0 +1,32 @@ | |||
1 | menu "SoC Audio for the Atmel AT91" | ||
2 | |||
3 | config SND_AT91_SOC | ||
4 | tristate "SoC Audio for the Atmel AT91 System-on-Chip" | ||
5 | depends on ARCH_AT91 && SND | ||
6 | select SND_PCM | ||
7 | help | ||
8 | Say Y or M if you want to add support for codecs attached to | ||
9 | the AT91 SSC interface. You will also need | ||
10 | to select the audio interfaces to support below. | ||
11 | |||
12 | config SND_AT91_SOC_I2S | ||
13 | tristate | ||
14 | |||
15 | config SND_AT91_SOC_ETI_B1_WM8731 | ||
16 | tristate "SoC I2S Audio support for WM8731-based Endrelia ETI-B1 boards" | ||
17 | depends on SND_AT91_SOC && (MACH_ETI_B1 || MACH_ETI_C1) | ||
18 | select SND_AT91_SOC_I2S | ||
19 | select SND_SOC_WM8731 | ||
20 | help | ||
21 | Say Y if you want to add support for SoC audio on WM8731-based | ||
22 | Endrelia Technologies Inc ETI-B1 or ETI-C1 boards. | ||
23 | |||
24 | config SND_AT91_SOC_ETI_SLAVE | ||
25 | bool "Run codec in slave Mode on Endrelia boards" | ||
26 | depends on SND_AT91_SOC_ETI_B1_WM8731 | ||
27 | default n | ||
28 | help | ||
29 | Say Y if you want to run with the AT91 SSC generating the BCLK | ||
30 | and LRC signals on Endrelia boards. | ||
31 | |||
32 | endmenu | ||
diff --git a/sound/soc/at91/Makefile b/sound/soc/at91/Makefile new file mode 100644 index 000000000000..b77b01ab2028 --- /dev/null +++ b/sound/soc/at91/Makefile | |||
@@ -0,0 +1,11 @@ | |||
1 | # AT91 Platform Support | ||
2 | snd-soc-at91-objs := at91-pcm.o | ||
3 | snd-soc-at91-i2s-objs := at91-i2s.o | ||
4 | |||
5 | obj-$(CONFIG_SND_AT91_SOC) += snd-soc-at91.o | ||
6 | obj-$(CONFIG_SND_AT91_SOC_I2S) += snd-soc-at91-i2s.o | ||
7 | |||
8 | # AT91 Machine Support | ||
9 | snd-soc-eti-b1-wm8731-objs := eti_b1_wm8731.o | ||
10 | |||
11 | obj-$(CONFIG_SND_AT91_SOC_ETI_B1_WM8731) += snd-soc-eti-b1-wm8731.o | ||
diff --git a/sound/soc/at91/at91-i2s.c b/sound/soc/at91/at91-i2s.c new file mode 100644 index 000000000000..fcc544a96ba3 --- /dev/null +++ b/sound/soc/at91/at91-i2s.c | |||
@@ -0,0 +1,720 @@ | |||
1 | /* | ||
2 | * at91-i2s.c -- ALSA SoC I2S Audio Layer Platform driver | ||
3 | * | ||
4 | * Author: Frank Mandarino <fmandarino@endrelia.com> | ||
5 | * Endrelia Technologies Inc. | ||
6 | * | ||
7 | * Based on pxa2xx Platform drivers by | ||
8 | * Liam Girdwood <liam.girdwood@wolfsonmicro.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify it | ||
11 | * under the terms of the GNU General Public License as published by the | ||
12 | * Free Software Foundation; either version 2 of the License, or (at your | ||
13 | * option) any later version. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #include <linux/init.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/interrupt.h> | ||
20 | #include <linux/device.h> | ||
21 | #include <linux/delay.h> | ||
22 | #include <linux/clk.h> | ||
23 | #include <sound/driver.h> | ||
24 | #include <sound/core.h> | ||
25 | #include <sound/pcm.h> | ||
26 | #include <sound/initval.h> | ||
27 | #include <sound/soc.h> | ||
28 | |||
29 | #include <asm/arch/hardware.h> | ||
30 | #include <asm/arch/at91_pmc.h> | ||
31 | #include <asm/arch/at91_ssc.h> | ||
32 | #include <asm/arch/at91_pdc.h> | ||
33 | |||
34 | #include "at91-pcm.h" | ||
35 | #include "at91-i2s.h" | ||
36 | |||
37 | #if 0 | ||
38 | #define DBG(x...) printk(KERN_DEBUG "at91-i2s:" x) | ||
39 | #else | ||
40 | #define DBG(x...) | ||
41 | #endif | ||
42 | |||
43 | #if defined(CONFIG_ARCH_AT91SAM9260) | ||
44 | #define NUM_SSC_DEVICES 1 | ||
45 | #else | ||
46 | #define NUM_SSC_DEVICES 3 | ||
47 | #endif | ||
48 | |||
49 | |||
50 | /* | ||
51 | * SSC PDC registers required by the PCM DMA engine. | ||
52 | */ | ||
53 | static struct at91_pdc_regs pdc_tx_reg = { | ||
54 | .xpr = AT91_PDC_TPR, | ||
55 | .xcr = AT91_PDC_TCR, | ||
56 | .xnpr = AT91_PDC_TNPR, | ||
57 | .xncr = AT91_PDC_TNCR, | ||
58 | }; | ||
59 | |||
60 | static struct at91_pdc_regs pdc_rx_reg = { | ||
61 | .xpr = AT91_PDC_RPR, | ||
62 | .xcr = AT91_PDC_RCR, | ||
63 | .xnpr = AT91_PDC_RNPR, | ||
64 | .xncr = AT91_PDC_RNCR, | ||
65 | }; | ||
66 | |||
67 | /* | ||
68 | * SSC & PDC status bits for transmit and receive. | ||
69 | */ | ||
70 | static struct at91_ssc_mask ssc_tx_mask = { | ||
71 | .ssc_enable = AT91_SSC_TXEN, | ||
72 | .ssc_disable = AT91_SSC_TXDIS, | ||
73 | .ssc_endx = AT91_SSC_ENDTX, | ||
74 | .ssc_endbuf = AT91_SSC_TXBUFE, | ||
75 | .pdc_enable = AT91_PDC_TXTEN, | ||
76 | .pdc_disable = AT91_PDC_TXTDIS, | ||
77 | }; | ||
78 | |||
79 | static struct at91_ssc_mask ssc_rx_mask = { | ||
80 | .ssc_enable = AT91_SSC_RXEN, | ||
81 | .ssc_disable = AT91_SSC_RXDIS, | ||
82 | .ssc_endx = AT91_SSC_ENDRX, | ||
83 | .ssc_endbuf = AT91_SSC_RXBUFF, | ||
84 | .pdc_enable = AT91_PDC_RXTEN, | ||
85 | .pdc_disable = AT91_PDC_RXTDIS, | ||
86 | }; | ||
87 | |||
88 | |||
89 | /* | ||
90 | * DMA parameters. | ||
91 | */ | ||
92 | static struct at91_pcm_dma_params ssc_dma_params[NUM_SSC_DEVICES][2] = { | ||
93 | {{ | ||
94 | .name = "SSC0/I2S PCM Stereo out", | ||
95 | .pdc = &pdc_tx_reg, | ||
96 | .mask = &ssc_tx_mask, | ||
97 | }, | ||
98 | { | ||
99 | .name = "SSC0/I2S PCM Stereo in", | ||
100 | .pdc = &pdc_rx_reg, | ||
101 | .mask = &ssc_rx_mask, | ||
102 | }}, | ||
103 | #if NUM_SSC_DEVICES == 3 | ||
104 | {{ | ||
105 | .name = "SSC1/I2S PCM Stereo out", | ||
106 | .pdc = &pdc_tx_reg, | ||
107 | .mask = &ssc_tx_mask, | ||
108 | }, | ||
109 | { | ||
110 | .name = "SSC1/I2S PCM Stereo in", | ||
111 | .pdc = &pdc_rx_reg, | ||
112 | .mask = &ssc_rx_mask, | ||
113 | }}, | ||
114 | {{ | ||
115 | .name = "SSC2/I2S PCM Stereo out", | ||
116 | .pdc = &pdc_tx_reg, | ||
117 | .mask = &ssc_tx_mask, | ||
118 | }, | ||
119 | { | ||
120 | .name = "SSC1/I2S PCM Stereo in", | ||
121 | .pdc = &pdc_rx_reg, | ||
122 | .mask = &ssc_rx_mask, | ||
123 | }}, | ||
124 | #endif | ||
125 | }; | ||
126 | |||
127 | struct at91_ssc_state { | ||
128 | u32 ssc_cmr; | ||
129 | u32 ssc_rcmr; | ||
130 | u32 ssc_rfmr; | ||
131 | u32 ssc_tcmr; | ||
132 | u32 ssc_tfmr; | ||
133 | u32 ssc_sr; | ||
134 | u32 ssc_imr; | ||
135 | }; | ||
136 | |||
137 | static struct at91_ssc_info { | ||
138 | char *name; | ||
139 | struct at91_ssc_periph ssc; | ||
140 | spinlock_t lock; /* lock for dir_mask */ | ||
141 | unsigned short dir_mask; /* 0=unused, 1=playback, 2=capture */ | ||
142 | unsigned short initialized; /* 1=SSC has been initialized */ | ||
143 | unsigned short daifmt; | ||
144 | unsigned short cmr_div; | ||
145 | unsigned short tcmr_period; | ||
146 | unsigned short rcmr_period; | ||
147 | struct at91_pcm_dma_params *dma_params[2]; | ||
148 | struct at91_ssc_state ssc_state; | ||
149 | |||
150 | } ssc_info[NUM_SSC_DEVICES] = { | ||
151 | { | ||
152 | .name = "ssc0", | ||
153 | .lock = SPIN_LOCK_UNLOCKED, | ||
154 | .dir_mask = 0, | ||
155 | .initialized = 0, | ||
156 | }, | ||
157 | #if NUM_SSC_DEVICES == 3 | ||
158 | { | ||
159 | .name = "ssc1", | ||
160 | .lock = SPIN_LOCK_UNLOCKED, | ||
161 | .dir_mask = 0, | ||
162 | .initialized = 0, | ||
163 | }, | ||
164 | { | ||
165 | .name = "ssc2", | ||
166 | .lock = SPIN_LOCK_UNLOCKED, | ||
167 | .dir_mask = 0, | ||
168 | .initialized = 0, | ||
169 | }, | ||
170 | #endif | ||
171 | }; | ||
172 | |||
173 | static unsigned int at91_i2s_sysclk; | ||
174 | |||
175 | /* | ||
176 | * SSC interrupt handler. Passes PDC interrupts to the DMA | ||
177 | * interrupt handler in the PCM driver. | ||
178 | */ | ||
179 | static irqreturn_t at91_i2s_interrupt(int irq, void *dev_id) | ||
180 | { | ||
181 | struct at91_ssc_info *ssc_p = dev_id; | ||
182 | struct at91_pcm_dma_params *dma_params; | ||
183 | u32 ssc_sr; | ||
184 | int i; | ||
185 | |||
186 | ssc_sr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_SR) | ||
187 | & at91_ssc_read(ssc_p->ssc.base + AT91_SSC_IMR); | ||
188 | |||
189 | /* | ||
190 | * Loop through the substreams attached to this SSC. If | ||
191 | * a DMA-related interrupt occurred on that substream, call | ||
192 | * the DMA interrupt handler function, if one has been | ||
193 | * registered in the dma_params structure by the PCM driver. | ||
194 | */ | ||
195 | for (i = 0; i < ARRAY_SIZE(ssc_p->dma_params); i++) { | ||
196 | dma_params = ssc_p->dma_params[i]; | ||
197 | |||
198 | if (dma_params != NULL && dma_params->dma_intr_handler != NULL && | ||
199 | (ssc_sr & | ||
200 | (dma_params->mask->ssc_endx | dma_params->mask->ssc_endbuf))) | ||
201 | |||
202 | dma_params->dma_intr_handler(ssc_sr, dma_params->substream); | ||
203 | } | ||
204 | |||
205 | return IRQ_HANDLED; | ||
206 | } | ||
207 | |||
208 | /* | ||
209 | * Startup. Only that one substream allowed in each direction. | ||
210 | */ | ||
211 | static int at91_i2s_startup(struct snd_pcm_substream *substream) | ||
212 | { | ||
213 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
214 | struct at91_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id]; | ||
215 | int dir_mask; | ||
216 | |||
217 | DBG("i2s_startup: SSC_SR=0x%08lx\n", | ||
218 | at91_ssc_read(ssc_p->ssc.base + AT91_SSC_SR)); | ||
219 | dir_mask = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0x1 : 0x2; | ||
220 | |||
221 | spin_lock_irq(&ssc_p->lock); | ||
222 | if (ssc_p->dir_mask & dir_mask) { | ||
223 | spin_unlock_irq(&ssc_p->lock); | ||
224 | return -EBUSY; | ||
225 | } | ||
226 | ssc_p->dir_mask |= dir_mask; | ||
227 | spin_unlock_irq(&ssc_p->lock); | ||
228 | |||
229 | return 0; | ||
230 | } | ||
231 | |||
232 | /* | ||
233 | * Shutdown. Clear DMA parameters and shutdown the SSC if there | ||
234 | * are no other substreams open. | ||
235 | */ | ||
236 | static void at91_i2s_shutdown(struct snd_pcm_substream *substream) | ||
237 | { | ||
238 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
239 | struct at91_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id]; | ||
240 | struct at91_pcm_dma_params *dma_params; | ||
241 | int dir, dir_mask; | ||
242 | |||
243 | dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1; | ||
244 | dma_params = ssc_p->dma_params[dir]; | ||
245 | |||
246 | if (dma_params != NULL) { | ||
247 | at91_ssc_write(dma_params->ssc_base + AT91_SSC_CR, | ||
248 | dma_params->mask->ssc_disable); | ||
249 | DBG("%s disabled SSC_SR=0x%08lx\n", (dir ? "receive" : "transmit"), | ||
250 | at91_ssc_read(ssc_p->ssc.base + AT91_SSC_SR)); | ||
251 | |||
252 | dma_params->ssc_base = NULL; | ||
253 | dma_params->substream = NULL; | ||
254 | ssc_p->dma_params[dir] = NULL; | ||
255 | } | ||
256 | |||
257 | dir_mask = 1 << dir; | ||
258 | |||
259 | spin_lock_irq(&ssc_p->lock); | ||
260 | ssc_p->dir_mask &= ~dir_mask; | ||
261 | if (!ssc_p->dir_mask) { | ||
262 | /* Shutdown the SSC clock. */ | ||
263 | DBG("Stopping pid %d clock\n", ssc_p->ssc.pid); | ||
264 | at91_sys_write(AT91_PMC_PCDR, 1<<ssc_p->ssc.pid); | ||
265 | |||
266 | if (ssc_p->initialized) { | ||
267 | free_irq(ssc_p->ssc.pid, ssc_p); | ||
268 | ssc_p->initialized = 0; | ||
269 | } | ||
270 | |||
271 | /* Reset the SSC */ | ||
272 | at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR, AT91_SSC_SWRST); | ||
273 | |||
274 | /* Clear the SSC dividers */ | ||
275 | ssc_p->cmr_div = ssc_p->tcmr_period = ssc_p->rcmr_period = 0; | ||
276 | } | ||
277 | spin_unlock_irq(&ssc_p->lock); | ||
278 | } | ||
279 | |||
280 | /* | ||
281 | * Record the SSC system clock rate. | ||
282 | */ | ||
283 | static int at91_i2s_set_dai_sysclk(struct snd_soc_cpu_dai *cpu_dai, | ||
284 | int clk_id, unsigned int freq, int dir) | ||
285 | { | ||
286 | /* | ||
287 | * The only clock supplied to the SSC is the AT91 master clock, | ||
288 | * which is only used if the SSC is generating BCLK and/or | ||
289 | * LRC clocks. | ||
290 | */ | ||
291 | switch (clk_id) { | ||
292 | case AT91_SYSCLK_MCK: | ||
293 | at91_i2s_sysclk = freq; | ||
294 | break; | ||
295 | default: | ||
296 | return -EINVAL; | ||
297 | } | ||
298 | |||
299 | return 0; | ||
300 | } | ||
301 | |||
302 | /* | ||
303 | * Record the DAI format for use in hw_params(). | ||
304 | */ | ||
305 | static int at91_i2s_set_dai_fmt(struct snd_soc_cpu_dai *cpu_dai, | ||
306 | unsigned int fmt) | ||
307 | { | ||
308 | struct at91_ssc_info *ssc_p = &ssc_info[cpu_dai->id]; | ||
309 | |||
310 | if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_I2S) | ||
311 | return -EINVAL; | ||
312 | |||
313 | ssc_p->daifmt = fmt; | ||
314 | return 0; | ||
315 | } | ||
316 | |||
317 | /* | ||
318 | * Record SSC clock dividers for use in hw_params(). | ||
319 | */ | ||
320 | static int at91_i2s_set_dai_clkdiv(struct snd_soc_cpu_dai *cpu_dai, | ||
321 | int div_id, int div) | ||
322 | { | ||
323 | struct at91_ssc_info *ssc_p = &ssc_info[cpu_dai->id]; | ||
324 | |||
325 | switch (div_id) { | ||
326 | case AT91SSC_CMR_DIV: | ||
327 | /* | ||
328 | * The same master clock divider is used for both | ||
329 | * transmit and receive, so if a value has already | ||
330 | * been set, it must match this value. | ||
331 | */ | ||
332 | if (ssc_p->cmr_div == 0) | ||
333 | ssc_p->cmr_div = div; | ||
334 | else | ||
335 | if (div != ssc_p->cmr_div) | ||
336 | return -EBUSY; | ||
337 | break; | ||
338 | |||
339 | case AT91SSC_TCMR_PERIOD: | ||
340 | ssc_p->tcmr_period = div; | ||
341 | break; | ||
342 | |||
343 | case AT91SSC_RCMR_PERIOD: | ||
344 | ssc_p->rcmr_period = div; | ||
345 | break; | ||
346 | |||
347 | default: | ||
348 | return -EINVAL; | ||
349 | } | ||
350 | |||
351 | return 0; | ||
352 | } | ||
353 | |||
354 | /* | ||
355 | * Configure the SSC. | ||
356 | */ | ||
357 | static int at91_i2s_hw_params(struct snd_pcm_substream *substream, | ||
358 | struct snd_pcm_hw_params *params) | ||
359 | { | ||
360 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
361 | int id = rtd->dai->cpu_dai->id; | ||
362 | struct at91_ssc_info *ssc_p = &ssc_info[id]; | ||
363 | struct at91_pcm_dma_params *dma_params; | ||
364 | int dir, channels, bits; | ||
365 | u32 tfmr, rfmr, tcmr, rcmr; | ||
366 | int start_event; | ||
367 | int ret; | ||
368 | |||
369 | /* | ||
370 | * Currently, there is only one set of dma params for | ||
371 | * each direction. If more are added, this code will | ||
372 | * have to be changed to select the proper set. | ||
373 | */ | ||
374 | dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1; | ||
375 | |||
376 | dma_params = &ssc_dma_params[id][dir]; | ||
377 | dma_params->ssc_base = ssc_p->ssc.base; | ||
378 | dma_params->substream = substream; | ||
379 | |||
380 | ssc_p->dma_params[dir] = dma_params; | ||
381 | |||
382 | /* | ||
383 | * The cpu_dai->dma_data field is only used to communicate the | ||
384 | * appropriate DMA parameters to the pcm driver hw_params() | ||
385 | * function. It should not be used for other purposes | ||
386 | * as it is common to all substreams. | ||
387 | */ | ||
388 | rtd->dai->cpu_dai->dma_data = dma_params; | ||
389 | |||
390 | channels = params_channels(params); | ||
391 | |||
392 | /* | ||
393 | * The SSC only supports up to 16-bit samples in I2S format, due | ||
394 | * to the size of the Frame Mode Register FSLEN field. Also, I2S | ||
395 | * implies signed data. | ||
396 | */ | ||
397 | bits = 16; | ||
398 | dma_params->pdc_xfer_size = 2; | ||
399 | |||
400 | /* | ||
401 | * Compute SSC register settings. | ||
402 | */ | ||
403 | switch (ssc_p->daifmt) { | ||
404 | case SND_SOC_DAIFMT_CBS_CFS: | ||
405 | /* | ||
406 | * SSC provides BCLK and LRC clocks. | ||
407 | * | ||
408 | * The SSC transmit and receive clocks are generated from the | ||
409 | * MCK divider, and the BCLK signal is output on the SSC TK line. | ||
410 | */ | ||
411 | rcmr = (( ssc_p->rcmr_period << 24) & AT91_SSC_PERIOD) | ||
412 | | (( 1 << 16) & AT91_SSC_STTDLY) | ||
413 | | (( AT91_SSC_START_FALLING_RF ) & AT91_SSC_START) | ||
414 | | (( AT91_SSC_CK_RISING ) & AT91_SSC_CKI) | ||
415 | | (( AT91_SSC_CKO_NONE ) & AT91_SSC_CKO) | ||
416 | | (( AT91_SSC_CKS_DIV ) & AT91_SSC_CKS); | ||
417 | |||
418 | rfmr = (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE) | ||
419 | | (( AT91_SSC_FSOS_NEGATIVE ) & AT91_SSC_FSOS) | ||
420 | | (((bits - 1) << 16) & AT91_SSC_FSLEN) | ||
421 | | (((channels - 1) << 8) & AT91_SSC_DATNB) | ||
422 | | (( 1 << 7) & AT91_SSC_MSBF) | ||
423 | | (( 0 << 5) & AT91_SSC_LOOP) | ||
424 | | (((bits - 1) << 0) & AT91_SSC_DATALEN); | ||
425 | |||
426 | tcmr = (( ssc_p->tcmr_period << 24) & AT91_SSC_PERIOD) | ||
427 | | (( 1 << 16) & AT91_SSC_STTDLY) | ||
428 | | (( AT91_SSC_START_FALLING_RF ) & AT91_SSC_START) | ||
429 | | (( AT91_SSC_CKI_FALLING ) & AT91_SSC_CKI) | ||
430 | | (( AT91_SSC_CKO_CONTINUOUS ) & AT91_SSC_CKO) | ||
431 | | (( AT91_SSC_CKS_DIV ) & AT91_SSC_CKS); | ||
432 | |||
433 | tfmr = (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE) | ||
434 | | (( 0 << 23) & AT91_SSC_FSDEN) | ||
435 | | (( AT91_SSC_FSOS_NEGATIVE ) & AT91_SSC_FSOS) | ||
436 | | (((bits - 1) << 16) & AT91_SSC_FSLEN) | ||
437 | | (((channels - 1) << 8) & AT91_SSC_DATNB) | ||
438 | | (( 1 << 7) & AT91_SSC_MSBF) | ||
439 | | (( 0 << 5) & AT91_SSC_DATDEF) | ||
440 | | (((bits - 1) << 0) & AT91_SSC_DATALEN); | ||
441 | break; | ||
442 | |||
443 | case SND_SOC_DAIFMT_CBM_CFM: | ||
444 | |||
445 | /* | ||
446 | * CODEC supplies BCLK and LRC clocks. | ||
447 | * | ||
448 | * The SSC transmit clock is obtained from the BCLK signal on | ||
449 | * on the TK line, and the SSC receive clock is generated from the | ||
450 | * transmit clock. | ||
451 | * | ||
452 | * For single channel data, one sample is transferred on the falling | ||
453 | * edge of the LRC clock. For two channel data, one sample is | ||
454 | * transferred on both edges of the LRC clock. | ||
455 | */ | ||
456 | start_event = channels == 1 | ||
457 | ? AT91_SSC_START_FALLING_RF | ||
458 | : AT91_SSC_START_EDGE_RF; | ||
459 | |||
460 | rcmr = (( 0 << 24) & AT91_SSC_PERIOD) | ||
461 | | (( 1 << 16) & AT91_SSC_STTDLY) | ||
462 | | (( start_event ) & AT91_SSC_START) | ||
463 | | (( AT91_SSC_CK_RISING ) & AT91_SSC_CKI) | ||
464 | | (( AT91_SSC_CKO_NONE ) & AT91_SSC_CKO) | ||
465 | | (( AT91_SSC_CKS_CLOCK ) & AT91_SSC_CKS); | ||
466 | |||
467 | rfmr = (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE) | ||
468 | | (( AT91_SSC_FSOS_NONE ) & AT91_SSC_FSOS) | ||
469 | | (( 0 << 16) & AT91_SSC_FSLEN) | ||
470 | | (( 0 << 8) & AT91_SSC_DATNB) | ||
471 | | (( 1 << 7) & AT91_SSC_MSBF) | ||
472 | | (( 0 << 5) & AT91_SSC_LOOP) | ||
473 | | (((bits - 1) << 0) & AT91_SSC_DATALEN); | ||
474 | |||
475 | tcmr = (( 0 << 24) & AT91_SSC_PERIOD) | ||
476 | | (( 1 << 16) & AT91_SSC_STTDLY) | ||
477 | | (( start_event ) & AT91_SSC_START) | ||
478 | | (( AT91_SSC_CKI_FALLING ) & AT91_SSC_CKI) | ||
479 | | (( AT91_SSC_CKO_NONE ) & AT91_SSC_CKO) | ||
480 | | (( AT91_SSC_CKS_PIN ) & AT91_SSC_CKS); | ||
481 | |||
482 | tfmr = (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE) | ||
483 | | (( 0 << 23) & AT91_SSC_FSDEN) | ||
484 | | (( AT91_SSC_FSOS_NONE ) & AT91_SSC_FSOS) | ||
485 | | (( 0 << 16) & AT91_SSC_FSLEN) | ||
486 | | (( 0 << 8) & AT91_SSC_DATNB) | ||
487 | | (( 1 << 7) & AT91_SSC_MSBF) | ||
488 | | (( 0 << 5) & AT91_SSC_DATDEF) | ||
489 | | (((bits - 1) << 0) & AT91_SSC_DATALEN); | ||
490 | break; | ||
491 | |||
492 | case SND_SOC_DAIFMT_CBS_CFM: | ||
493 | case SND_SOC_DAIFMT_CBM_CFS: | ||
494 | default: | ||
495 | printk(KERN_WARNING "at91-i2s: unsupported DAI format 0x%x.\n", | ||
496 | ssc_p->daifmt); | ||
497 | return -EINVAL; | ||
498 | break; | ||
499 | } | ||
500 | DBG("RCMR=%08x RFMR=%08x TCMR=%08x TFMR=%08x\n", rcmr, rfmr, tcmr, tfmr); | ||
501 | |||
502 | if (!ssc_p->initialized) { | ||
503 | |||
504 | /* Enable PMC peripheral clock for this SSC */ | ||
505 | DBG("Starting pid %d clock\n", ssc_p->ssc.pid); | ||
506 | at91_sys_write(AT91_PMC_PCER, 1<<ssc_p->ssc.pid); | ||
507 | |||
508 | /* Reset the SSC and its PDC registers */ | ||
509 | at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR, AT91_SSC_SWRST); | ||
510 | |||
511 | at91_ssc_write(ssc_p->ssc.base + AT91_PDC_RPR, 0); | ||
512 | at91_ssc_write(ssc_p->ssc.base + AT91_PDC_RCR, 0); | ||
513 | at91_ssc_write(ssc_p->ssc.base + AT91_PDC_RNPR, 0); | ||
514 | at91_ssc_write(ssc_p->ssc.base + AT91_PDC_RNCR, 0); | ||
515 | at91_ssc_write(ssc_p->ssc.base + AT91_PDC_TPR, 0); | ||
516 | at91_ssc_write(ssc_p->ssc.base + AT91_PDC_TCR, 0); | ||
517 | at91_ssc_write(ssc_p->ssc.base + AT91_PDC_TNPR, 0); | ||
518 | at91_ssc_write(ssc_p->ssc.base + AT91_PDC_TNCR, 0); | ||
519 | |||
520 | if ((ret = request_irq(ssc_p->ssc.pid, at91_i2s_interrupt, | ||
521 | 0, ssc_p->name, ssc_p)) < 0) { | ||
522 | printk(KERN_WARNING "at91-i2s: request_irq failure\n"); | ||
523 | |||
524 | DBG("Stopping pid %d clock\n", ssc_p->ssc.pid); | ||
525 | at91_sys_write(AT91_PMC_PCER, 1<<ssc_p->ssc.pid); | ||
526 | return ret; | ||
527 | } | ||
528 | |||
529 | ssc_p->initialized = 1; | ||
530 | } | ||
531 | |||
532 | /* set SSC clock mode register */ | ||
533 | at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CMR, ssc_p->cmr_div); | ||
534 | |||
535 | /* set receive clock mode and format */ | ||
536 | at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RCMR, rcmr); | ||
537 | at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RFMR, rfmr); | ||
538 | |||
539 | /* set transmit clock mode and format */ | ||
540 | at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TCMR, tcmr); | ||
541 | at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TFMR, tfmr); | ||
542 | |||
543 | DBG("hw_params: SSC initialized\n"); | ||
544 | return 0; | ||
545 | } | ||
546 | |||
547 | |||
548 | static int at91_i2s_prepare(struct snd_pcm_substream *substream) | ||
549 | { | ||
550 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
551 | struct at91_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id]; | ||
552 | struct at91_pcm_dma_params *dma_params; | ||
553 | int dir; | ||
554 | |||
555 | dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1; | ||
556 | dma_params = ssc_p->dma_params[dir]; | ||
557 | |||
558 | at91_ssc_write(dma_params->ssc_base + AT91_SSC_CR, | ||
559 | dma_params->mask->ssc_enable); | ||
560 | |||
561 | DBG("%s enabled SSC_SR=0x%08lx\n", dir ? "receive" : "transmit", | ||
562 | at91_ssc_read(dma_params->ssc_base + AT91_SSC_SR)); | ||
563 | return 0; | ||
564 | } | ||
565 | |||
566 | |||
567 | #ifdef CONFIG_PM | ||
568 | static int at91_i2s_suspend(struct platform_device *pdev, | ||
569 | struct snd_soc_cpu_dai *cpu_dai) | ||
570 | { | ||
571 | struct at91_ssc_info *ssc_p; | ||
572 | |||
573 | if(!cpu_dai->active) | ||
574 | return 0; | ||
575 | |||
576 | ssc_p = &ssc_info[cpu_dai->id]; | ||
577 | |||
578 | /* Save the status register before disabling transmit and receive. */ | ||
579 | ssc_p->ssc_state.ssc_sr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_SR); | ||
580 | at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR, | ||
581 | AT91_SSC_TXDIS | AT91_SSC_RXDIS); | ||
582 | |||
583 | /* Save the current interrupt mask, then disable unmasked interrupts. */ | ||
584 | ssc_p->ssc_state.ssc_imr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_IMR); | ||
585 | at91_ssc_write(ssc_p->ssc.base + AT91_SSC_IDR, ssc_p->ssc_state.ssc_imr); | ||
586 | |||
587 | ssc_p->ssc_state.ssc_cmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_CMR); | ||
588 | ssc_p->ssc_state.ssc_rcmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_RCMR); | ||
589 | ssc_p->ssc_state.ssc_rfmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_RFMR); | ||
590 | ssc_p->ssc_state.ssc_tcmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_TCMR); | ||
591 | ssc_p->ssc_state.ssc_tfmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_TFMR); | ||
592 | |||
593 | return 0; | ||
594 | } | ||
595 | |||
596 | static int at91_i2s_resume(struct platform_device *pdev, | ||
597 | struct snd_soc_cpu_dai *cpu_dai) | ||
598 | { | ||
599 | struct at91_ssc_info *ssc_p; | ||
600 | |||
601 | if(!cpu_dai->active) | ||
602 | return 0; | ||
603 | |||
604 | ssc_p = &ssc_info[cpu_dai->id]; | ||
605 | |||
606 | at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TFMR, ssc_p->ssc_state.ssc_tfmr); | ||
607 | at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TCMR, ssc_p->ssc_state.ssc_tcmr); | ||
608 | at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RFMR, ssc_p->ssc_state.ssc_rfmr); | ||
609 | at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RCMR, ssc_p->ssc_state.ssc_rcmr); | ||
610 | at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CMR, ssc_p->ssc_state.ssc_cmr); | ||
611 | |||
612 | at91_ssc_write(ssc_p->ssc.base + AT91_SSC_IER, ssc_p->ssc_state.ssc_imr); | ||
613 | |||
614 | at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR, | ||
615 | ((ssc_p->ssc_state.ssc_sr & AT91_SSC_RXENA) ? AT91_SSC_RXEN : 0) | | ||
616 | ((ssc_p->ssc_state.ssc_sr & AT91_SSC_TXENA) ? AT91_SSC_TXEN : 0)); | ||
617 | |||
618 | return 0; | ||
619 | } | ||
620 | |||
621 | #else | ||
622 | #define at91_i2s_suspend NULL | ||
623 | #define at91_i2s_resume NULL | ||
624 | #endif | ||
625 | |||
626 | #define AT91_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ | ||
627 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ | ||
628 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\ | ||
629 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\ | ||
630 | SNDRV_PCM_RATE_96000) | ||
631 | |||
632 | struct snd_soc_cpu_dai at91_i2s_dai[NUM_SSC_DEVICES] = { | ||
633 | { .name = "at91_ssc0/i2s", | ||
634 | .id = 0, | ||
635 | .type = SND_SOC_DAI_I2S, | ||
636 | .suspend = at91_i2s_suspend, | ||
637 | .resume = at91_i2s_resume, | ||
638 | .playback = { | ||
639 | .channels_min = 1, | ||
640 | .channels_max = 2, | ||
641 | .rates = AT91_I2S_RATES, | ||
642 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | ||
643 | .capture = { | ||
644 | .channels_min = 1, | ||
645 | .channels_max = 2, | ||
646 | .rates = AT91_I2S_RATES, | ||
647 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | ||
648 | .ops = { | ||
649 | .startup = at91_i2s_startup, | ||
650 | .shutdown = at91_i2s_shutdown, | ||
651 | .prepare = at91_i2s_prepare, | ||
652 | .hw_params = at91_i2s_hw_params,}, | ||
653 | .dai_ops = { | ||
654 | .set_sysclk = at91_i2s_set_dai_sysclk, | ||
655 | .set_fmt = at91_i2s_set_dai_fmt, | ||
656 | .set_clkdiv = at91_i2s_set_dai_clkdiv,}, | ||
657 | .private_data = &ssc_info[0].ssc, | ||
658 | }, | ||
659 | #if NUM_SSC_DEVICES == 3 | ||
660 | { .name = "at91_ssc1/i2s", | ||
661 | .id = 1, | ||
662 | .type = SND_SOC_DAI_I2S, | ||
663 | .suspend = at91_i2s_suspend, | ||
664 | .resume = at91_i2s_resume, | ||
665 | .playback = { | ||
666 | .channels_min = 1, | ||
667 | .channels_max = 2, | ||
668 | .rates = AT91_I2S_RATES, | ||
669 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | ||
670 | .capture = { | ||
671 | .channels_min = 1, | ||
672 | .channels_max = 2, | ||
673 | .rates = AT91_I2S_RATES, | ||
674 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | ||
675 | .ops = { | ||
676 | .startup = at91_i2s_startup, | ||
677 | .shutdown = at91_i2s_shutdown, | ||
678 | .prepare = at91_i2s_prepare, | ||
679 | .hw_params = at91_i2s_hw_params,}, | ||
680 | .dai_ops = { | ||
681 | .set_sysclk = at91_i2s_set_dai_sysclk, | ||
682 | .set_fmt = at91_i2s_set_dai_fmt, | ||
683 | .set_clkdiv = at91_i2s_set_dai_clkdiv,}, | ||
684 | .private_data = &ssc_info[1].ssc, | ||
685 | }, | ||
686 | { .name = "at91_ssc2/i2s", | ||
687 | .id = 2, | ||
688 | .type = SND_SOC_DAI_I2S, | ||
689 | .suspend = at91_i2s_suspend, | ||
690 | .resume = at91_i2s_resume, | ||
691 | .playback = { | ||
692 | .channels_min = 1, | ||
693 | .channels_max = 2, | ||
694 | .rates = AT91_I2S_RATES, | ||
695 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | ||
696 | .capture = { | ||
697 | .channels_min = 1, | ||
698 | .channels_max = 2, | ||
699 | .rates = AT91_I2S_RATES, | ||
700 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | ||
701 | .ops = { | ||
702 | .startup = at91_i2s_startup, | ||
703 | .shutdown = at91_i2s_shutdown, | ||
704 | .prepare = at91_i2s_prepare, | ||
705 | .hw_params = at91_i2s_hw_params,}, | ||
706 | .dai_ops = { | ||
707 | .set_sysclk = at91_i2s_set_dai_sysclk, | ||
708 | .set_fmt = at91_i2s_set_dai_fmt, | ||
709 | .set_clkdiv = at91_i2s_set_dai_clkdiv,}, | ||
710 | .private_data = &ssc_info[2].ssc, | ||
711 | }, | ||
712 | #endif | ||
713 | }; | ||
714 | |||
715 | EXPORT_SYMBOL_GPL(at91_i2s_dai); | ||
716 | |||
717 | /* Module information */ | ||
718 | MODULE_AUTHOR("Frank Mandarino, fmandarino@endrelia.com, www.endrelia.com"); | ||
719 | MODULE_DESCRIPTION("AT91 I2S ASoC Interface"); | ||
720 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/at91/at91-i2s.h b/sound/soc/at91/at91-i2s.h new file mode 100644 index 000000000000..f8a875ba0ccc --- /dev/null +++ b/sound/soc/at91/at91-i2s.h | |||
@@ -0,0 +1,27 @@ | |||
1 | /* | ||
2 | * at91-i2s.h - ALSA I2S interface for the Atmel AT91 SoC | ||
3 | * | ||
4 | * Author: Frank Mandarino <fmandarino@endrelia.com> | ||
5 | * Endrelia Technologies Inc. | ||
6 | * Created: Jan 9, 2007 | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #ifndef _AT91_I2S_H | ||
14 | #define _AT91_I2S_H | ||
15 | |||
16 | /* I2S system clock ids */ | ||
17 | #define AT91_SYSCLK_MCK 0 /* SSC uses AT91 MCK as system clock */ | ||
18 | |||
19 | /* I2S divider ids */ | ||
20 | #define AT91SSC_CMR_DIV 0 /* MCK divider for BCLK */ | ||
21 | #define AT91SSC_TCMR_PERIOD 1 /* BCLK divider for transmit FS */ | ||
22 | #define AT91SSC_RCMR_PERIOD 2 /* BCLK divider for receive FS */ | ||
23 | |||
24 | extern struct snd_soc_cpu_dai at91_i2s_dai[]; | ||
25 | |||
26 | #endif /* _AT91_I2S_H */ | ||
27 | |||
diff --git a/sound/soc/at91/at91-pcm.c b/sound/soc/at91/at91-pcm.c new file mode 100644 index 000000000000..e88b12e7cc40 --- /dev/null +++ b/sound/soc/at91/at91-pcm.c | |||
@@ -0,0 +1,432 @@ | |||
1 | /* | ||
2 | * at91-pcm.c -- ALSA PCM interface for the Atmel AT91 SoC | ||
3 | * | ||
4 | * Author: Frank Mandarino <fmandarino@endrelia.com> | ||
5 | * Endrelia Technologies Inc. | ||
6 | * Created: Mar 3, 2006 | ||
7 | * | ||
8 | * Based on pxa2xx-pcm.c by: | ||
9 | * | ||
10 | * Author: Nicolas Pitre | ||
11 | * Created: Nov 30, 2004 | ||
12 | * Copyright: (C) 2004 MontaVista Software, Inc. | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or modify | ||
15 | * it under the terms of the GNU General Public License version 2 as | ||
16 | * published by the Free Software Foundation. | ||
17 | */ | ||
18 | |||
19 | #include <linux/module.h> | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/dma-mapping.h> | ||
24 | |||
25 | #include <sound/driver.h> | ||
26 | #include <sound/core.h> | ||
27 | #include <sound/pcm.h> | ||
28 | #include <sound/pcm_params.h> | ||
29 | #include <sound/soc.h> | ||
30 | |||
31 | #include <asm/arch/hardware.h> | ||
32 | #include <asm/arch/at91_ssc.h> | ||
33 | #include <asm/arch/at91_pdc.h> | ||
34 | |||
35 | #include "at91-pcm.h" | ||
36 | |||
37 | #if 0 | ||
38 | #define DBG(x...) printk(KERN_INFO "at91-pcm: " x) | ||
39 | #else | ||
40 | #define DBG(x...) | ||
41 | #endif | ||
42 | |||
43 | static const struct snd_pcm_hardware at91_pcm_hardware = { | ||
44 | .info = SNDRV_PCM_INFO_MMAP | | ||
45 | SNDRV_PCM_INFO_MMAP_VALID | | ||
46 | SNDRV_PCM_INFO_INTERLEAVED | | ||
47 | SNDRV_PCM_INFO_PAUSE, | ||
48 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
49 | .period_bytes_min = 32, | ||
50 | .period_bytes_max = 8192, | ||
51 | .periods_min = 2, | ||
52 | .periods_max = 1024, | ||
53 | .buffer_bytes_max = 32 * 1024, | ||
54 | }; | ||
55 | |||
56 | struct at91_runtime_data { | ||
57 | struct at91_pcm_dma_params *params; | ||
58 | dma_addr_t dma_buffer; /* physical address of dma buffer */ | ||
59 | dma_addr_t dma_buffer_end; /* first address beyond DMA buffer */ | ||
60 | size_t period_size; | ||
61 | dma_addr_t period_ptr; /* physical address of next period */ | ||
62 | u32 pdc_xpr_save; /* PDC register save */ | ||
63 | u32 pdc_xcr_save; | ||
64 | u32 pdc_xnpr_save; | ||
65 | u32 pdc_xncr_save; | ||
66 | }; | ||
67 | |||
68 | static void at91_pcm_dma_irq(u32 ssc_sr, | ||
69 | struct snd_pcm_substream *substream) | ||
70 | { | ||
71 | struct at91_runtime_data *prtd = substream->runtime->private_data; | ||
72 | struct at91_pcm_dma_params *params = prtd->params; | ||
73 | static int count = 0; | ||
74 | |||
75 | count++; | ||
76 | |||
77 | if (ssc_sr & params->mask->ssc_endbuf) { | ||
78 | |||
79 | printk(KERN_WARNING | ||
80 | "at91-pcm: buffer %s on %s (SSC_SR=%#x, count=%d)\n", | ||
81 | substream->stream == SNDRV_PCM_STREAM_PLAYBACK | ||
82 | ? "underrun" : "overrun", | ||
83 | params->name, ssc_sr, count); | ||
84 | |||
85 | /* re-start the PDC */ | ||
86 | at91_ssc_write(params->ssc_base + AT91_PDC_PTCR, params->mask->pdc_disable); | ||
87 | |||
88 | prtd->period_ptr += prtd->period_size; | ||
89 | if (prtd->period_ptr >= prtd->dma_buffer_end) { | ||
90 | prtd->period_ptr = prtd->dma_buffer; | ||
91 | } | ||
92 | |||
93 | at91_ssc_write(params->ssc_base + params->pdc->xpr, prtd->period_ptr); | ||
94 | at91_ssc_write(params->ssc_base + params->pdc->xcr, | ||
95 | prtd->period_size / params->pdc_xfer_size); | ||
96 | |||
97 | at91_ssc_write(params->ssc_base + AT91_PDC_PTCR, params->mask->pdc_enable); | ||
98 | } | ||
99 | |||
100 | if (ssc_sr & params->mask->ssc_endx) { | ||
101 | |||
102 | /* Load the PDC next pointer and counter registers */ | ||
103 | prtd->period_ptr += prtd->period_size; | ||
104 | if (prtd->period_ptr >= prtd->dma_buffer_end) { | ||
105 | prtd->period_ptr = prtd->dma_buffer; | ||
106 | } | ||
107 | at91_ssc_write(params->ssc_base + params->pdc->xnpr, prtd->period_ptr); | ||
108 | at91_ssc_write(params->ssc_base + params->pdc->xncr, | ||
109 | prtd->period_size / params->pdc_xfer_size); | ||
110 | } | ||
111 | |||
112 | snd_pcm_period_elapsed(substream); | ||
113 | } | ||
114 | |||
115 | static int at91_pcm_hw_params(struct snd_pcm_substream *substream, | ||
116 | struct snd_pcm_hw_params *params) | ||
117 | { | ||
118 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
119 | struct at91_runtime_data *prtd = runtime->private_data; | ||
120 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
121 | |||
122 | /* this may get called several times by oss emulation | ||
123 | * with different params */ | ||
124 | |||
125 | snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); | ||
126 | runtime->dma_bytes = params_buffer_bytes(params); | ||
127 | |||
128 | prtd->params = rtd->dai->cpu_dai->dma_data; | ||
129 | prtd->params->dma_intr_handler = at91_pcm_dma_irq; | ||
130 | |||
131 | prtd->dma_buffer = runtime->dma_addr; | ||
132 | prtd->dma_buffer_end = runtime->dma_addr + runtime->dma_bytes; | ||
133 | prtd->period_size = params_period_bytes(params); | ||
134 | |||
135 | DBG("hw_params: DMA for %s initialized (dma_bytes=%d, period_size=%d)\n", | ||
136 | prtd->params->name, runtime->dma_bytes, prtd->period_size); | ||
137 | return 0; | ||
138 | } | ||
139 | |||
140 | static int at91_pcm_hw_free(struct snd_pcm_substream *substream) | ||
141 | { | ||
142 | struct at91_runtime_data *prtd = substream->runtime->private_data; | ||
143 | struct at91_pcm_dma_params *params = prtd->params; | ||
144 | |||
145 | if (params != NULL) { | ||
146 | at91_ssc_write(params->ssc_base + AT91_PDC_PTCR, params->mask->pdc_disable); | ||
147 | prtd->params->dma_intr_handler = NULL; | ||
148 | } | ||
149 | |||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | static int at91_pcm_prepare(struct snd_pcm_substream *substream) | ||
154 | { | ||
155 | struct at91_runtime_data *prtd = substream->runtime->private_data; | ||
156 | struct at91_pcm_dma_params *params = prtd->params; | ||
157 | |||
158 | at91_ssc_write(params->ssc_base + AT91_SSC_IDR, | ||
159 | params->mask->ssc_endx | params->mask->ssc_endbuf); | ||
160 | |||
161 | at91_ssc_write(params->ssc_base + AT91_PDC_PTCR, params->mask->pdc_disable); | ||
162 | return 0; | ||
163 | } | ||
164 | |||
165 | static int at91_pcm_trigger(struct snd_pcm_substream *substream, | ||
166 | int cmd) | ||
167 | { | ||
168 | struct at91_runtime_data *prtd = substream->runtime->private_data; | ||
169 | struct at91_pcm_dma_params *params = prtd->params; | ||
170 | int ret = 0; | ||
171 | |||
172 | switch (cmd) { | ||
173 | case SNDRV_PCM_TRIGGER_START: | ||
174 | prtd->period_ptr = prtd->dma_buffer; | ||
175 | |||
176 | at91_ssc_write(params->ssc_base + params->pdc->xpr, prtd->period_ptr); | ||
177 | at91_ssc_write(params->ssc_base + params->pdc->xcr, | ||
178 | prtd->period_size / params->pdc_xfer_size); | ||
179 | |||
180 | prtd->period_ptr += prtd->period_size; | ||
181 | at91_ssc_write(params->ssc_base + params->pdc->xnpr, prtd->period_ptr); | ||
182 | at91_ssc_write(params->ssc_base + params->pdc->xncr, | ||
183 | prtd->period_size / params->pdc_xfer_size); | ||
184 | |||
185 | DBG("trigger: period_ptr=%lx, xpr=%lx, xcr=%ld, xnpr=%lx, xncr=%ld\n", | ||
186 | (unsigned long) prtd->period_ptr, | ||
187 | at91_ssc_read(params->ssc_base + params->pdc->xpr), | ||
188 | at91_ssc_read(params->ssc_base + params->pdc->xcr), | ||
189 | at91_ssc_read(params->ssc_base + params->pdc->xnpr), | ||
190 | at91_ssc_read(params->ssc_base + params->pdc->xncr)); | ||
191 | |||
192 | at91_ssc_write(params->ssc_base + AT91_SSC_IER, | ||
193 | params->mask->ssc_endx | params->mask->ssc_endbuf); | ||
194 | |||
195 | at91_ssc_write(params->ssc_base + AT91_PDC_PTCR, params->mask->pdc_enable); | ||
196 | |||
197 | DBG("sr=%lx imr=%lx\n", at91_ssc_read(params->ssc_base + AT91_SSC_SR), | ||
198 | at91_ssc_read(params->ssc_base + AT91_SSC_IER)); | ||
199 | break; | ||
200 | |||
201 | case SNDRV_PCM_TRIGGER_STOP: | ||
202 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
203 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
204 | at91_ssc_write(params->ssc_base + AT91_PDC_PTCR, params->mask->pdc_disable); | ||
205 | break; | ||
206 | |||
207 | case SNDRV_PCM_TRIGGER_RESUME: | ||
208 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
209 | at91_ssc_write(params->ssc_base + AT91_PDC_PTCR, params->mask->pdc_enable); | ||
210 | break; | ||
211 | |||
212 | default: | ||
213 | ret = -EINVAL; | ||
214 | } | ||
215 | |||
216 | return ret; | ||
217 | } | ||
218 | |||
219 | static snd_pcm_uframes_t at91_pcm_pointer( | ||
220 | struct snd_pcm_substream *substream) | ||
221 | { | ||
222 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
223 | struct at91_runtime_data *prtd = runtime->private_data; | ||
224 | struct at91_pcm_dma_params *params = prtd->params; | ||
225 | dma_addr_t ptr; | ||
226 | snd_pcm_uframes_t x; | ||
227 | |||
228 | ptr = (dma_addr_t) at91_ssc_read(params->ssc_base + params->pdc->xpr); | ||
229 | x = bytes_to_frames(runtime, ptr - prtd->dma_buffer); | ||
230 | |||
231 | if (x == runtime->buffer_size) | ||
232 | x = 0; | ||
233 | return x; | ||
234 | } | ||
235 | |||
236 | static int at91_pcm_open(struct snd_pcm_substream *substream) | ||
237 | { | ||
238 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
239 | struct at91_runtime_data *prtd; | ||
240 | int ret = 0; | ||
241 | |||
242 | snd_soc_set_runtime_hwparams(substream, &at91_pcm_hardware); | ||
243 | |||
244 | /* ensure that buffer size is a multiple of period size */ | ||
245 | ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); | ||
246 | if (ret < 0) | ||
247 | goto out; | ||
248 | |||
249 | prtd = kzalloc(sizeof(struct at91_runtime_data), GFP_KERNEL); | ||
250 | if (prtd == NULL) { | ||
251 | ret = -ENOMEM; | ||
252 | goto out; | ||
253 | } | ||
254 | runtime->private_data = prtd; | ||
255 | |||
256 | out: | ||
257 | return ret; | ||
258 | } | ||
259 | |||
260 | static int at91_pcm_close(struct snd_pcm_substream *substream) | ||
261 | { | ||
262 | struct at91_runtime_data *prtd = substream->runtime->private_data; | ||
263 | |||
264 | kfree(prtd); | ||
265 | return 0; | ||
266 | } | ||
267 | |||
268 | static int at91_pcm_mmap(struct snd_pcm_substream *substream, | ||
269 | struct vm_area_struct *vma) | ||
270 | { | ||
271 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
272 | |||
273 | return dma_mmap_writecombine(substream->pcm->card->dev, vma, | ||
274 | runtime->dma_area, | ||
275 | runtime->dma_addr, | ||
276 | runtime->dma_bytes); | ||
277 | } | ||
278 | |||
279 | struct snd_pcm_ops at91_pcm_ops = { | ||
280 | .open = at91_pcm_open, | ||
281 | .close = at91_pcm_close, | ||
282 | .ioctl = snd_pcm_lib_ioctl, | ||
283 | .hw_params = at91_pcm_hw_params, | ||
284 | .hw_free = at91_pcm_hw_free, | ||
285 | .prepare = at91_pcm_prepare, | ||
286 | .trigger = at91_pcm_trigger, | ||
287 | .pointer = at91_pcm_pointer, | ||
288 | .mmap = at91_pcm_mmap, | ||
289 | }; | ||
290 | |||
291 | static int at91_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, | ||
292 | int stream) | ||
293 | { | ||
294 | struct snd_pcm_substream *substream = pcm->streams[stream].substream; | ||
295 | struct snd_dma_buffer *buf = &substream->dma_buffer; | ||
296 | size_t size = at91_pcm_hardware.buffer_bytes_max; | ||
297 | |||
298 | buf->dev.type = SNDRV_DMA_TYPE_DEV; | ||
299 | buf->dev.dev = pcm->card->dev; | ||
300 | buf->private_data = NULL; | ||
301 | buf->area = dma_alloc_writecombine(pcm->card->dev, size, | ||
302 | &buf->addr, GFP_KERNEL); | ||
303 | |||
304 | DBG("preallocate_dma_buffer: area=%p, addr=%p, size=%d\n", | ||
305 | (void *) buf->area, | ||
306 | (void *) buf->addr, | ||
307 | size); | ||
308 | |||
309 | if (!buf->area) | ||
310 | return -ENOMEM; | ||
311 | |||
312 | buf->bytes = size; | ||
313 | return 0; | ||
314 | } | ||
315 | |||
316 | static u64 at91_pcm_dmamask = 0xffffffff; | ||
317 | |||
318 | static int at91_pcm_new(struct snd_card *card, | ||
319 | struct snd_soc_codec_dai *dai, struct snd_pcm *pcm) | ||
320 | { | ||
321 | int ret = 0; | ||
322 | |||
323 | if (!card->dev->dma_mask) | ||
324 | card->dev->dma_mask = &at91_pcm_dmamask; | ||
325 | if (!card->dev->coherent_dma_mask) | ||
326 | card->dev->coherent_dma_mask = 0xffffffff; | ||
327 | |||
328 | if (dai->playback.channels_min) { | ||
329 | ret = at91_pcm_preallocate_dma_buffer(pcm, | ||
330 | SNDRV_PCM_STREAM_PLAYBACK); | ||
331 | if (ret) | ||
332 | goto out; | ||
333 | } | ||
334 | |||
335 | if (dai->capture.channels_min) { | ||
336 | ret = at91_pcm_preallocate_dma_buffer(pcm, | ||
337 | SNDRV_PCM_STREAM_CAPTURE); | ||
338 | if (ret) | ||
339 | goto out; | ||
340 | } | ||
341 | out: | ||
342 | return ret; | ||
343 | } | ||
344 | |||
345 | static void at91_pcm_free_dma_buffers(struct snd_pcm *pcm) | ||
346 | { | ||
347 | struct snd_pcm_substream *substream; | ||
348 | struct snd_dma_buffer *buf; | ||
349 | int stream; | ||
350 | |||
351 | for (stream = 0; stream < 2; stream++) { | ||
352 | substream = pcm->streams[stream].substream; | ||
353 | if (!substream) | ||
354 | continue; | ||
355 | |||
356 | buf = &substream->dma_buffer; | ||
357 | if (!buf->area) | ||
358 | continue; | ||
359 | |||
360 | dma_free_writecombine(pcm->card->dev, buf->bytes, | ||
361 | buf->area, buf->addr); | ||
362 | buf->area = NULL; | ||
363 | } | ||
364 | } | ||
365 | |||
366 | #ifdef CONFIG_PM | ||
367 | static int at91_pcm_suspend(struct platform_device *pdev, | ||
368 | struct snd_soc_cpu_dai *dai) | ||
369 | { | ||
370 | struct snd_pcm_runtime *runtime = dai->runtime; | ||
371 | struct at91_runtime_data *prtd; | ||
372 | struct at91_pcm_dma_params *params; | ||
373 | |||
374 | if (!runtime) | ||
375 | return 0; | ||
376 | |||
377 | prtd = runtime->private_data; | ||
378 | params = prtd->params; | ||
379 | |||
380 | /* disable the PDC and save the PDC registers */ | ||
381 | |||
382 | at91_ssc_write(params->ssc_base + AT91_PDC_PTCR, params->mask->pdc_disable); | ||
383 | |||
384 | prtd->pdc_xpr_save = at91_ssc_read(params->ssc_base + params->pdc->xpr); | ||
385 | prtd->pdc_xcr_save = at91_ssc_read(params->ssc_base + params->pdc->xcr); | ||
386 | prtd->pdc_xnpr_save = at91_ssc_read(params->ssc_base + params->pdc->xnpr); | ||
387 | prtd->pdc_xncr_save = at91_ssc_read(params->ssc_base + params->pdc->xncr); | ||
388 | |||
389 | return 0; | ||
390 | } | ||
391 | |||
392 | static int at91_pcm_resume(struct platform_device *pdev, | ||
393 | struct snd_soc_cpu_dai *dai) | ||
394 | { | ||
395 | struct snd_pcm_runtime *runtime = dai->runtime; | ||
396 | struct at91_runtime_data *prtd; | ||
397 | struct at91_pcm_dma_params *params; | ||
398 | |||
399 | if (!runtime) | ||
400 | return 0; | ||
401 | |||
402 | prtd = runtime->private_data; | ||
403 | params = prtd->params; | ||
404 | |||
405 | /* restore the PDC registers and enable the PDC */ | ||
406 | at91_ssc_write(params->ssc_base + params->pdc->xpr, prtd->pdc_xpr_save); | ||
407 | at91_ssc_write(params->ssc_base + params->pdc->xcr, prtd->pdc_xcr_save); | ||
408 | at91_ssc_write(params->ssc_base + params->pdc->xnpr, prtd->pdc_xnpr_save); | ||
409 | at91_ssc_write(params->ssc_base + params->pdc->xncr, prtd->pdc_xncr_save); | ||
410 | |||
411 | at91_ssc_write(params->ssc_base + AT91_PDC_PTCR, params->mask->pdc_enable); | ||
412 | return 0; | ||
413 | } | ||
414 | #else | ||
415 | #define at91_pcm_suspend NULL | ||
416 | #define at91_pcm_resume NULL | ||
417 | #endif | ||
418 | |||
419 | struct snd_soc_platform at91_soc_platform = { | ||
420 | .name = "at91-audio", | ||
421 | .pcm_ops = &at91_pcm_ops, | ||
422 | .pcm_new = at91_pcm_new, | ||
423 | .pcm_free = at91_pcm_free_dma_buffers, | ||
424 | .suspend = at91_pcm_suspend, | ||
425 | .resume = at91_pcm_resume, | ||
426 | }; | ||
427 | |||
428 | EXPORT_SYMBOL_GPL(at91_soc_platform); | ||
429 | |||
430 | MODULE_AUTHOR("Frank Mandarino <fmandarino@endrelia.com>"); | ||
431 | MODULE_DESCRIPTION("Atmel AT91 PCM module"); | ||
432 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/at91/at91-pcm.h b/sound/soc/at91/at91-pcm.h new file mode 100644 index 000000000000..58d0f00a07b2 --- /dev/null +++ b/sound/soc/at91/at91-pcm.h | |||
@@ -0,0 +1,72 @@ | |||
1 | /* | ||
2 | * at91-pcm.h - ALSA PCM interface for the Atmel AT91 SoC | ||
3 | * | ||
4 | * Author: Frank Mandarino <fmandarino@endrelia.com> | ||
5 | * Endrelia Technologies Inc. | ||
6 | * Created: Mar 3, 2006 | ||
7 | * | ||
8 | * Based on pxa2xx-pcm.h by: | ||
9 | * | ||
10 | * Author: Nicolas Pitre | ||
11 | * Created: Nov 30, 2004 | ||
12 | * Copyright: MontaVista Software, Inc. | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or modify | ||
15 | * it under the terms of the GNU General Public License version 2 as | ||
16 | * published by the Free Software Foundation. | ||
17 | */ | ||
18 | |||
19 | #ifndef _AT91_PCM_H | ||
20 | #define _AT91_PCM_H | ||
21 | |||
22 | #include <asm/arch/hardware.h> | ||
23 | |||
24 | struct at91_ssc_periph { | ||
25 | void __iomem *base; | ||
26 | u32 pid; | ||
27 | }; | ||
28 | |||
29 | /* | ||
30 | * Registers and status bits that are required by the PCM driver. | ||
31 | */ | ||
32 | struct at91_pdc_regs { | ||
33 | unsigned int xpr; /* PDC recv/trans pointer */ | ||
34 | unsigned int xcr; /* PDC recv/trans counter */ | ||
35 | unsigned int xnpr; /* PDC next recv/trans pointer */ | ||
36 | unsigned int xncr; /* PDC next recv/trans counter */ | ||
37 | unsigned int ptcr; /* PDC transfer control */ | ||
38 | }; | ||
39 | |||
40 | struct at91_ssc_mask { | ||
41 | u32 ssc_enable; /* SSC recv/trans enable */ | ||
42 | u32 ssc_disable; /* SSC recv/trans disable */ | ||
43 | u32 ssc_endx; /* SSC ENDTX or ENDRX */ | ||
44 | u32 ssc_endbuf; /* SSC TXBUFE or RXBUFF */ | ||
45 | u32 pdc_enable; /* PDC recv/trans enable */ | ||
46 | u32 pdc_disable; /* PDC recv/trans disable */ | ||
47 | }; | ||
48 | |||
49 | /* | ||
50 | * This structure, shared between the PCM driver and the interface, | ||
51 | * contains all information required by the PCM driver to perform the | ||
52 | * PDC DMA operation. All fields except dma_intr_handler() are initialized | ||
53 | * by the interface. The dms_intr_handler() pointer is set by the PCM | ||
54 | * driver and called by the interface SSC interrupt handler if it is | ||
55 | * non-NULL. | ||
56 | */ | ||
57 | struct at91_pcm_dma_params { | ||
58 | char *name; /* stream identifier */ | ||
59 | int pdc_xfer_size; /* PDC counter increment in bytes */ | ||
60 | void __iomem *ssc_base; /* SSC base address */ | ||
61 | struct at91_pdc_regs *pdc; /* PDC receive or transmit registers */ | ||
62 | struct at91_ssc_mask *mask;/* SSC & PDC status bits */ | ||
63 | struct snd_pcm_substream *substream; | ||
64 | void (*dma_intr_handler)(u32, struct snd_pcm_substream *); | ||
65 | }; | ||
66 | |||
67 | extern struct snd_soc_platform at91_soc_platform; | ||
68 | |||
69 | #define at91_ssc_read(a) ((unsigned long) __raw_readl(a)) | ||
70 | #define at91_ssc_write(a,v) __raw_writel((v),(a)) | ||
71 | |||
72 | #endif /* _AT91_PCM_H */ | ||
diff --git a/sound/soc/at91/eti_b1_wm8731.c b/sound/soc/at91/eti_b1_wm8731.c new file mode 100644 index 000000000000..8179df3bb2f3 --- /dev/null +++ b/sound/soc/at91/eti_b1_wm8731.c | |||
@@ -0,0 +1,375 @@ | |||
1 | /* | ||
2 | * eti_b1_wm8731 -- SoC audio for AT91RM9200-based Endrelia ETI_B1 board. | ||
3 | * | ||
4 | * Author: Frank Mandarino <fmandarino@endrelia.com> | ||
5 | * Endrelia Technologies Inc. | ||
6 | * Created: Mar 29, 2006 | ||
7 | * | ||
8 | * Based on corgi.c by: | ||
9 | * | ||
10 | * Copyright 2005 Wolfson Microelectronics PLC. | ||
11 | * Copyright 2005 Openedhand Ltd. | ||
12 | * | ||
13 | * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com> | ||
14 | * Richard Purdie <richard@openedhand.com> | ||
15 | * | ||
16 | * This program is free software; you can redistribute it and/or modify it | ||
17 | * under the terms of the GNU General Public License as published by the | ||
18 | * Free Software Foundation; either version 2 of the License, or (at your | ||
19 | * option) any later version. | ||
20 | * | ||
21 | */ | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/moduleparam.h> | ||
25 | #include <linux/version.h> | ||
26 | #include <linux/kernel.h> | ||
27 | #include <linux/clk.h> | ||
28 | #include <linux/timer.h> | ||
29 | #include <linux/interrupt.h> | ||
30 | #include <linux/platform_device.h> | ||
31 | #include <sound/driver.h> | ||
32 | #include <sound/core.h> | ||
33 | #include <sound/pcm.h> | ||
34 | #include <sound/soc.h> | ||
35 | #include <sound/soc-dapm.h> | ||
36 | |||
37 | #include <asm/arch/hardware.h> | ||
38 | #include <asm/arch/at91_pio.h> | ||
39 | #include <asm/arch/gpio.h> | ||
40 | |||
41 | #include "../codecs/wm8731.h" | ||
42 | #include "at91-pcm.h" | ||
43 | #include "at91-i2s.h" | ||
44 | |||
45 | #if 0 | ||
46 | #define DBG(x...) printk(KERN_INFO "eti_b1_wm8731: " x) | ||
47 | #else | ||
48 | #define DBG(x...) | ||
49 | #endif | ||
50 | |||
51 | #define AT91_PIO_TF1 (1 << (AT91_PIN_PB6 - PIN_BASE) % 32) | ||
52 | #define AT91_PIO_TK1 (1 << (AT91_PIN_PB7 - PIN_BASE) % 32) | ||
53 | #define AT91_PIO_TD1 (1 << (AT91_PIN_PB8 - PIN_BASE) % 32) | ||
54 | #define AT91_PIO_RD1 (1 << (AT91_PIN_PB9 - PIN_BASE) % 32) | ||
55 | #define AT91_PIO_RK1 (1 << (AT91_PIN_PB10 - PIN_BASE) % 32) | ||
56 | #define AT91_PIO_RF1 (1 << (AT91_PIN_PB11 - PIN_BASE) % 32) | ||
57 | |||
58 | static struct clk *pck1_clk; | ||
59 | static struct clk *pllb_clk; | ||
60 | |||
61 | |||
62 | static int eti_b1_startup(struct snd_pcm_substream *substream) | ||
63 | { | ||
64 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
65 | struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; | ||
66 | struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; | ||
67 | int ret; | ||
68 | |||
69 | /* cpu clock is the AT91 master clock sent to the SSC */ | ||
70 | ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, AT91_SYSCLK_MCK, | ||
71 | 60000000, SND_SOC_CLOCK_IN); | ||
72 | if (ret < 0) | ||
73 | return ret; | ||
74 | |||
75 | /* codec system clock is supplied by PCK1, set to 12MHz */ | ||
76 | ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8731_SYSCLK, | ||
77 | 12000000, SND_SOC_CLOCK_IN); | ||
78 | if (ret < 0) | ||
79 | return ret; | ||
80 | |||
81 | /* Start PCK1 clock. */ | ||
82 | clk_enable(pck1_clk); | ||
83 | DBG("pck1 started\n"); | ||
84 | |||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | static void eti_b1_shutdown(struct snd_pcm_substream *substream) | ||
89 | { | ||
90 | /* Stop PCK1 clock. */ | ||
91 | clk_disable(pck1_clk); | ||
92 | DBG("pck1 stopped\n"); | ||
93 | } | ||
94 | |||
95 | static int eti_b1_hw_params(struct snd_pcm_substream *substream, | ||
96 | struct snd_pcm_hw_params *params) | ||
97 | { | ||
98 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
99 | struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; | ||
100 | struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; | ||
101 | int ret; | ||
102 | |||
103 | #ifdef CONFIG_SND_AT91_SOC_ETI_SLAVE | ||
104 | unsigned int rate; | ||
105 | int cmr_div, period; | ||
106 | |||
107 | /* set codec DAI configuration */ | ||
108 | ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | | ||
109 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); | ||
110 | if (ret < 0) | ||
111 | return ret; | ||
112 | |||
113 | /* set cpu DAI configuration */ | ||
114 | ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | | ||
115 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); | ||
116 | if (ret < 0) | ||
117 | return ret; | ||
118 | |||
119 | /* | ||
120 | * The SSC clock dividers depend on the sample rate. The CMR.DIV | ||
121 | * field divides the system master clock MCK to drive the SSC TK | ||
122 | * signal which provides the codec BCLK. The TCMR.PERIOD and | ||
123 | * RCMR.PERIOD fields further divide the BCLK signal to drive | ||
124 | * the SSC TF and RF signals which provide the codec DACLRC and | ||
125 | * ADCLRC clocks. | ||
126 | * | ||
127 | * The dividers were determined through trial and error, where a | ||
128 | * CMR.DIV value is chosen such that the resulting BCLK value is | ||
129 | * divisible, or almost divisible, by (2 * sample rate), and then | ||
130 | * the TCMR.PERIOD or RCMR.PERIOD is BCLK / (2 * sample rate) - 1. | ||
131 | */ | ||
132 | rate = params_rate(params); | ||
133 | |||
134 | switch (rate) { | ||
135 | case 8000: | ||
136 | cmr_div = 25; /* BCLK = 60MHz/(2*25) = 1.2MHz */ | ||
137 | period = 74; /* LRC = BCLK/(2*(74+1)) = 8000Hz */ | ||
138 | break; | ||
139 | case 32000: | ||
140 | cmr_div = 7; /* BCLK = 60MHz/(2*7) ~= 4.28571428MHz */ | ||
141 | period = 66; /* LRC = BCLK/(2*(66+1)) = 31982.942Hz */ | ||
142 | break; | ||
143 | case 48000: | ||
144 | cmr_div = 13; /* BCLK = 60MHz/(2*13) ~= 2.3076923MHz */ | ||
145 | period = 23; /* LRC = BCLK/(2*(23+1)) = 48076.923Hz */ | ||
146 | break; | ||
147 | default: | ||
148 | printk(KERN_WARNING "unsupported rate %d on ETI-B1 board\n", rate); | ||
149 | return -EINVAL; | ||
150 | } | ||
151 | |||
152 | /* set the MCK divider for BCLK */ | ||
153 | ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, AT91SSC_CMR_DIV, cmr_div); | ||
154 | if (ret < 0) | ||
155 | return ret; | ||
156 | |||
157 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
158 | /* set the BCLK divider for DACLRC */ | ||
159 | ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, | ||
160 | AT91SSC_TCMR_PERIOD, period); | ||
161 | } else { | ||
162 | /* set the BCLK divider for ADCLRC */ | ||
163 | ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, | ||
164 | AT91SSC_RCMR_PERIOD, period); | ||
165 | } | ||
166 | if (ret < 0) | ||
167 | return ret; | ||
168 | |||
169 | #else /* CONFIG_SND_AT91_SOC_ETI_SLAVE */ | ||
170 | /* | ||
171 | * Codec in Master Mode. | ||
172 | */ | ||
173 | |||
174 | /* set codec DAI configuration */ | ||
175 | ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | | ||
176 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); | ||
177 | if (ret < 0) | ||
178 | return ret; | ||
179 | |||
180 | /* set cpu DAI configuration */ | ||
181 | ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | | ||
182 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); | ||
183 | if (ret < 0) | ||
184 | return ret; | ||
185 | |||
186 | #endif /* CONFIG_SND_AT91_SOC_ETI_SLAVE */ | ||
187 | |||
188 | return 0; | ||
189 | } | ||
190 | |||
191 | static struct snd_soc_ops eti_b1_ops = { | ||
192 | .startup = eti_b1_startup, | ||
193 | .hw_params = eti_b1_hw_params, | ||
194 | .shutdown = eti_b1_shutdown, | ||
195 | }; | ||
196 | |||
197 | |||
198 | static const struct snd_soc_dapm_widget eti_b1_dapm_widgets[] = { | ||
199 | SND_SOC_DAPM_MIC("Int Mic", NULL), | ||
200 | SND_SOC_DAPM_SPK("Ext Spk", NULL), | ||
201 | }; | ||
202 | |||
203 | static const char *intercon[][3] = { | ||
204 | |||
205 | /* speaker connected to LHPOUT */ | ||
206 | {"Ext Spk", NULL, "LHPOUT"}, | ||
207 | |||
208 | /* mic is connected to Mic Jack, with WM8731 Mic Bias */ | ||
209 | {"MICIN", NULL, "Mic Bias"}, | ||
210 | {"Mic Bias", NULL, "Int Mic"}, | ||
211 | |||
212 | /* terminator */ | ||
213 | {NULL, NULL, NULL}, | ||
214 | }; | ||
215 | |||
216 | /* | ||
217 | * Logic for a wm8731 as connected on a Endrelia ETI-B1 board. | ||
218 | */ | ||
219 | static int eti_b1_wm8731_init(struct snd_soc_codec *codec) | ||
220 | { | ||
221 | int i; | ||
222 | |||
223 | DBG("eti_b1_wm8731_init() called\n"); | ||
224 | |||
225 | /* Add specific widgets */ | ||
226 | for(i = 0; i < ARRAY_SIZE(eti_b1_dapm_widgets); i++) { | ||
227 | snd_soc_dapm_new_control(codec, &eti_b1_dapm_widgets[i]); | ||
228 | } | ||
229 | |||
230 | /* Set up specific audio path interconnects */ | ||
231 | for(i = 0; intercon[i][0] != NULL; i++) { | ||
232 | snd_soc_dapm_connect_input(codec, intercon[i][0], | ||
233 | intercon[i][1], intercon[i][2]); | ||
234 | } | ||
235 | |||
236 | /* not connected */ | ||
237 | snd_soc_dapm_set_endpoint(codec, "RLINEIN", 0); | ||
238 | snd_soc_dapm_set_endpoint(codec, "LLINEIN", 0); | ||
239 | |||
240 | /* always connected */ | ||
241 | snd_soc_dapm_set_endpoint(codec, "Int Mic", 1); | ||
242 | snd_soc_dapm_set_endpoint(codec, "Ext Spk", 1); | ||
243 | |||
244 | snd_soc_dapm_sync_endpoints(codec); | ||
245 | |||
246 | return 0; | ||
247 | } | ||
248 | |||
249 | static struct snd_soc_dai_link eti_b1_dai = { | ||
250 | .name = "WM8731", | ||
251 | .stream_name = "WM8731", | ||
252 | .cpu_dai = &at91_i2s_dai[1], | ||
253 | .codec_dai = &wm8731_dai, | ||
254 | .init = eti_b1_wm8731_init, | ||
255 | .ops = &eti_b1_ops, | ||
256 | }; | ||
257 | |||
258 | static struct snd_soc_machine snd_soc_machine_eti_b1 = { | ||
259 | .name = "ETI_B1", | ||
260 | .dai_link = &eti_b1_dai, | ||
261 | .num_links = 1, | ||
262 | }; | ||
263 | |||
264 | static struct wm8731_setup_data eti_b1_wm8731_setup = { | ||
265 | .i2c_address = 0x1a, | ||
266 | }; | ||
267 | |||
268 | static struct snd_soc_device eti_b1_snd_devdata = { | ||
269 | .machine = &snd_soc_machine_eti_b1, | ||
270 | .platform = &at91_soc_platform, | ||
271 | .codec_dev = &soc_codec_dev_wm8731, | ||
272 | .codec_data = &eti_b1_wm8731_setup, | ||
273 | }; | ||
274 | |||
275 | static struct platform_device *eti_b1_snd_device; | ||
276 | |||
277 | static int __init eti_b1_init(void) | ||
278 | { | ||
279 | int ret; | ||
280 | u32 ssc_pio_lines; | ||
281 | struct at91_ssc_periph *ssc = eti_b1_dai.cpu_dai->private_data; | ||
282 | |||
283 | if (!request_mem_region(AT91RM9200_BASE_SSC1, SZ_16K, "soc-audio")) { | ||
284 | DBG("SSC1 memory region is busy\n"); | ||
285 | return -EBUSY; | ||
286 | } | ||
287 | |||
288 | ssc->base = ioremap(AT91RM9200_BASE_SSC1, SZ_16K); | ||
289 | if (!ssc->base) { | ||
290 | DBG("SSC1 memory ioremap failed\n"); | ||
291 | ret = -ENOMEM; | ||
292 | goto fail_release_mem; | ||
293 | } | ||
294 | |||
295 | ssc->pid = AT91RM9200_ID_SSC1; | ||
296 | |||
297 | eti_b1_snd_device = platform_device_alloc("soc-audio", -1); | ||
298 | if (!eti_b1_snd_device) { | ||
299 | DBG("platform device allocation failed\n"); | ||
300 | ret = -ENOMEM; | ||
301 | goto fail_io_unmap; | ||
302 | } | ||
303 | |||
304 | platform_set_drvdata(eti_b1_snd_device, &eti_b1_snd_devdata); | ||
305 | eti_b1_snd_devdata.dev = &eti_b1_snd_device->dev; | ||
306 | |||
307 | ret = platform_device_add(eti_b1_snd_device); | ||
308 | if (ret) { | ||
309 | DBG("platform device add failed\n"); | ||
310 | platform_device_put(eti_b1_snd_device); | ||
311 | goto fail_io_unmap; | ||
312 | } | ||
313 | |||
314 | ssc_pio_lines = AT91_PIO_TF1 | AT91_PIO_TK1 | AT91_PIO_TD1 | ||
315 | | AT91_PIO_RD1 /* | AT91_PIO_RK1 */ | AT91_PIO_RF1; | ||
316 | |||
317 | /* Reset all PIO registers and assign lines to peripheral A */ | ||
318 | at91_sys_write(AT91_PIOB + PIO_PDR, ssc_pio_lines); | ||
319 | at91_sys_write(AT91_PIOB + PIO_ODR, ssc_pio_lines); | ||
320 | at91_sys_write(AT91_PIOB + PIO_IFDR, ssc_pio_lines); | ||
321 | at91_sys_write(AT91_PIOB + PIO_CODR, ssc_pio_lines); | ||
322 | at91_sys_write(AT91_PIOB + PIO_IDR, ssc_pio_lines); | ||
323 | at91_sys_write(AT91_PIOB + PIO_MDDR, ssc_pio_lines); | ||
324 | at91_sys_write(AT91_PIOB + PIO_PUDR, ssc_pio_lines); | ||
325 | at91_sys_write(AT91_PIOB + PIO_ASR, ssc_pio_lines); | ||
326 | at91_sys_write(AT91_PIOB + PIO_OWDR, ssc_pio_lines); | ||
327 | |||
328 | /* | ||
329 | * Set PCK1 parent to PLLB and its rate to 12 Mhz. | ||
330 | */ | ||
331 | pllb_clk = clk_get(NULL, "pllb"); | ||
332 | pck1_clk = clk_get(NULL, "pck1"); | ||
333 | |||
334 | clk_set_parent(pck1_clk, pllb_clk); | ||
335 | clk_set_rate(pck1_clk, 12000000); | ||
336 | |||
337 | DBG("MCLK rate %luHz\n", clk_get_rate(pck1_clk)); | ||
338 | |||
339 | /* assign the GPIO pin to PCK1 */ | ||
340 | at91_set_B_periph(AT91_PIN_PA24, 0); | ||
341 | |||
342 | #ifdef CONFIG_SND_AT91_SOC_ETI_SLAVE | ||
343 | printk(KERN_INFO "eti_b1_wm8731: Codec in Slave Mode\n"); | ||
344 | #else | ||
345 | printk(KERN_INFO "eti_b1_wm8731: Codec in Master Mode\n"); | ||
346 | #endif | ||
347 | return ret; | ||
348 | |||
349 | fail_io_unmap: | ||
350 | iounmap(ssc->base); | ||
351 | fail_release_mem: | ||
352 | release_mem_region(AT91RM9200_BASE_SSC1, SZ_16K); | ||
353 | return ret; | ||
354 | } | ||
355 | |||
356 | static void __exit eti_b1_exit(void) | ||
357 | { | ||
358 | struct at91_ssc_periph *ssc = eti_b1_dai.cpu_dai->private_data; | ||
359 | |||
360 | clk_put(pck1_clk); | ||
361 | clk_put(pllb_clk); | ||
362 | |||
363 | platform_device_unregister(eti_b1_snd_device); | ||
364 | |||
365 | iounmap(ssc->base); | ||
366 | release_mem_region(AT91RM9200_BASE_SSC1, SZ_16K); | ||
367 | } | ||
368 | |||
369 | module_init(eti_b1_init); | ||
370 | module_exit(eti_b1_exit); | ||
371 | |||
372 | /* Module information */ | ||
373 | MODULE_AUTHOR("Frank Mandarino <fmandarino@endrelia.com>"); | ||
374 | MODULE_DESCRIPTION("ALSA SoC ETI-B1-WM8731"); | ||
375 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig new file mode 100644 index 000000000000..78ac2688e124 --- /dev/null +++ b/sound/soc/codecs/Kconfig | |||
@@ -0,0 +1,15 @@ | |||
1 | config SND_SOC_AC97_CODEC | ||
2 | tristate | ||
3 | depends SND_SOC | ||
4 | |||
5 | config SND_SOC_WM8731 | ||
6 | tristate | ||
7 | depends SND_SOC | ||
8 | |||
9 | config SND_SOC_WM8750 | ||
10 | tristate | ||
11 | depends SND_SOC | ||
12 | |||
13 | config SND_SOC_WM9712 | ||
14 | tristate | ||
15 | depends SND_SOC | ||
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile new file mode 100644 index 000000000000..3249a6e4f1d0 --- /dev/null +++ b/sound/soc/codecs/Makefile | |||
@@ -0,0 +1,9 @@ | |||
1 | snd-soc-ac97-objs := ac97.o | ||
2 | snd-soc-wm8731-objs := wm8731.o | ||
3 | snd-soc-wm8750-objs := wm8750.o | ||
4 | snd-soc-wm9712-objs := wm9712.o | ||
5 | |||
6 | obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o | ||
7 | obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o | ||
8 | obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o | ||
9 | obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o | ||
diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c new file mode 100644 index 000000000000..55bc55eb6e24 --- /dev/null +++ b/sound/soc/codecs/ac97.c | |||
@@ -0,0 +1,156 @@ | |||
1 | /* | ||
2 | * ac97.c -- ALSA Soc AC97 codec support | ||
3 | * | ||
4 | * Copyright 2005 Wolfson Microelectronics PLC. | ||
5 | * Author: Liam Girdwood | ||
6 | * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | * | ||
13 | * Revision history | ||
14 | * 17th Oct 2005 Initial version. | ||
15 | * | ||
16 | * Generic AC97 support. | ||
17 | */ | ||
18 | |||
19 | #include <linux/init.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/device.h> | ||
22 | #include <sound/driver.h> | ||
23 | #include <sound/core.h> | ||
24 | #include <sound/pcm.h> | ||
25 | #include <sound/ac97_codec.h> | ||
26 | #include <sound/initval.h> | ||
27 | #include <sound/soc.h> | ||
28 | |||
29 | #define AC97_VERSION "0.6" | ||
30 | |||
31 | static int ac97_prepare(struct snd_pcm_substream *substream) | ||
32 | { | ||
33 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
34 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
35 | struct snd_soc_device *socdev = rtd->socdev; | ||
36 | struct snd_soc_codec *codec = socdev->codec; | ||
37 | |||
38 | int reg = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? | ||
39 | AC97_PCM_FRONT_DAC_RATE : AC97_PCM_LR_ADC_RATE; | ||
40 | return snd_ac97_set_rate(codec->ac97, reg, runtime->rate); | ||
41 | } | ||
42 | |||
43 | #define STD_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ | ||
44 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) | ||
45 | |||
46 | static struct snd_soc_codec_dai ac97_dai = { | ||
47 | .name = "AC97 HiFi", | ||
48 | .playback = { | ||
49 | .stream_name = "AC97 Playback", | ||
50 | .channels_min = 1, | ||
51 | .channels_max = 2, | ||
52 | .rates = STD_AC97_RATES, | ||
53 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | ||
54 | .capture = { | ||
55 | .stream_name = "AC97 Capture", | ||
56 | .channels_min = 1, | ||
57 | .channels_max = 2, | ||
58 | .rates = STD_AC97_RATES, | ||
59 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | ||
60 | .ops = { | ||
61 | .prepare = ac97_prepare,}, | ||
62 | }; | ||
63 | |||
64 | static unsigned int ac97_read(struct snd_soc_codec *codec, | ||
65 | unsigned int reg) | ||
66 | { | ||
67 | return soc_ac97_ops.read(codec->ac97, reg); | ||
68 | } | ||
69 | |||
70 | static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, | ||
71 | unsigned int val) | ||
72 | { | ||
73 | soc_ac97_ops.write(codec->ac97, reg, val); | ||
74 | return 0; | ||
75 | } | ||
76 | |||
77 | static int ac97_soc_probe(struct platform_device *pdev) | ||
78 | { | ||
79 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
80 | struct snd_soc_codec *codec; | ||
81 | struct snd_ac97_bus *ac97_bus; | ||
82 | struct snd_ac97_template ac97_template; | ||
83 | int ret = 0; | ||
84 | |||
85 | printk(KERN_INFO "AC97 SoC Audio Codec %s\n", AC97_VERSION); | ||
86 | |||
87 | socdev->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | ||
88 | if (socdev->codec == NULL) | ||
89 | return -ENOMEM; | ||
90 | codec = socdev->codec; | ||
91 | mutex_init(&codec->mutex); | ||
92 | |||
93 | codec->name = "AC97"; | ||
94 | codec->owner = THIS_MODULE; | ||
95 | codec->dai = &ac97_dai; | ||
96 | codec->num_dai = 1; | ||
97 | codec->write = ac97_write; | ||
98 | codec->read = ac97_read; | ||
99 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
100 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
101 | |||
102 | /* register pcms */ | ||
103 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
104 | if(ret < 0) | ||
105 | goto err; | ||
106 | |||
107 | /* add codec as bus device for standard ac97 */ | ||
108 | ret = snd_ac97_bus(codec->card, 0, &soc_ac97_ops, NULL, &ac97_bus); | ||
109 | if(ret < 0) | ||
110 | goto bus_err; | ||
111 | |||
112 | memset(&ac97_template, 0, sizeof(struct snd_ac97_template)); | ||
113 | ret = snd_ac97_mixer(ac97_bus, &ac97_template, &codec->ac97); | ||
114 | if(ret < 0) | ||
115 | goto bus_err; | ||
116 | |||
117 | ret = snd_soc_register_card(socdev); | ||
118 | if (ret < 0) | ||
119 | goto bus_err; | ||
120 | return 0; | ||
121 | |||
122 | bus_err: | ||
123 | snd_soc_free_pcms(socdev); | ||
124 | |||
125 | err: | ||
126 | kfree(socdev->codec->reg_cache); | ||
127 | kfree(socdev->codec); | ||
128 | socdev->codec = NULL; | ||
129 | return ret; | ||
130 | } | ||
131 | |||
132 | static int ac97_soc_remove(struct platform_device *pdev) | ||
133 | { | ||
134 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
135 | struct snd_soc_codec *codec = socdev->codec; | ||
136 | |||
137 | if(codec == NULL) | ||
138 | return 0; | ||
139 | |||
140 | snd_soc_free_pcms(socdev); | ||
141 | kfree(socdev->codec->reg_cache); | ||
142 | kfree(socdev->codec); | ||
143 | |||
144 | return 0; | ||
145 | } | ||
146 | |||
147 | struct snd_soc_codec_device soc_codec_dev_ac97= { | ||
148 | .probe = ac97_soc_probe, | ||
149 | .remove = ac97_soc_remove, | ||
150 | }; | ||
151 | |||
152 | EXPORT_SYMBOL_GPL(soc_codec_dev_ac97); | ||
153 | |||
154 | MODULE_DESCRIPTION("Soc Generic AC97 driver"); | ||
155 | MODULE_AUTHOR("Liam Girdwood"); | ||
156 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/ac97.h b/sound/soc/codecs/ac97.h new file mode 100644 index 000000000000..930ddfc2321a --- /dev/null +++ b/sound/soc/codecs/ac97.h | |||
@@ -0,0 +1,18 @@ | |||
1 | /* | ||
2 | * linux/sound/codecs/ac97.h -- ALSA SoC Layer | ||
3 | * | ||
4 | * Author: Liam Girdwood | ||
5 | * Created: Dec 1st 2005 | ||
6 | * Copyright: Wolfson Microelectronics. PLC. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #ifndef __LINUX_SND_SOC_AC97_H | ||
14 | #define __LINUX_SND_SOC_AC97_H | ||
15 | |||
16 | extern struct snd_soc_codec_device soc_codec_dev_ac97; | ||
17 | |||
18 | #endif | ||
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c new file mode 100644 index 000000000000..7ca0b5268289 --- /dev/null +++ b/sound/soc/codecs/wm8731.c | |||
@@ -0,0 +1,758 @@ | |||
1 | /* | ||
2 | * wm8731.c -- WM8731 ALSA SoC Audio driver | ||
3 | * | ||
4 | * Copyright 2005 Openedhand Ltd. | ||
5 | * | ||
6 | * Author: Richard Purdie <richard@openedhand.com> | ||
7 | * | ||
8 | * Based on wm8753.c by Liam Girdwood | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #include <linux/module.h> | ||
16 | #include <linux/moduleparam.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/delay.h> | ||
19 | #include <linux/pm.h> | ||
20 | #include <linux/i2c.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | #include <sound/driver.h> | ||
23 | #include <sound/core.h> | ||
24 | #include <sound/pcm.h> | ||
25 | #include <sound/pcm_params.h> | ||
26 | #include <sound/soc.h> | ||
27 | #include <sound/soc-dapm.h> | ||
28 | #include <sound/initval.h> | ||
29 | |||
30 | #include "wm8731.h" | ||
31 | |||
32 | #define AUDIO_NAME "wm8731" | ||
33 | #define WM8731_VERSION "0.13" | ||
34 | |||
35 | /* | ||
36 | * Debug | ||
37 | */ | ||
38 | |||
39 | #define WM8731_DEBUG 0 | ||
40 | |||
41 | #ifdef WM8731_DEBUG | ||
42 | #define dbg(format, arg...) \ | ||
43 | printk(KERN_DEBUG AUDIO_NAME ": " format "\n" , ## arg) | ||
44 | #else | ||
45 | #define dbg(format, arg...) do {} while (0) | ||
46 | #endif | ||
47 | #define err(format, arg...) \ | ||
48 | printk(KERN_ERR AUDIO_NAME ": " format "\n" , ## arg) | ||
49 | #define info(format, arg...) \ | ||
50 | printk(KERN_INFO AUDIO_NAME ": " format "\n" , ## arg) | ||
51 | #define warn(format, arg...) \ | ||
52 | printk(KERN_WARNING AUDIO_NAME ": " format "\n" , ## arg) | ||
53 | |||
54 | struct snd_soc_codec_device soc_codec_dev_wm8731; | ||
55 | |||
56 | /* codec private data */ | ||
57 | struct wm8731_priv { | ||
58 | unsigned int sysclk; | ||
59 | }; | ||
60 | |||
61 | /* | ||
62 | * wm8731 register cache | ||
63 | * We can't read the WM8731 register space when we are | ||
64 | * using 2 wire for device control, so we cache them instead. | ||
65 | * There is no point in caching the reset register | ||
66 | */ | ||
67 | static const u16 wm8731_reg[WM8731_CACHEREGNUM] = { | ||
68 | 0x0097, 0x0097, 0x0079, 0x0079, | ||
69 | 0x000a, 0x0008, 0x009f, 0x000a, | ||
70 | 0x0000, 0x0000 | ||
71 | }; | ||
72 | |||
73 | /* | ||
74 | * read wm8731 register cache | ||
75 | */ | ||
76 | static inline unsigned int wm8731_read_reg_cache(struct snd_soc_codec *codec, | ||
77 | unsigned int reg) | ||
78 | { | ||
79 | u16 *cache = codec->reg_cache; | ||
80 | if (reg == WM8731_RESET) | ||
81 | return 0; | ||
82 | if (reg >= WM8731_CACHEREGNUM) | ||
83 | return -1; | ||
84 | return cache[reg]; | ||
85 | } | ||
86 | |||
87 | /* | ||
88 | * write wm8731 register cache | ||
89 | */ | ||
90 | static inline void wm8731_write_reg_cache(struct snd_soc_codec *codec, | ||
91 | u16 reg, unsigned int value) | ||
92 | { | ||
93 | u16 *cache = codec->reg_cache; | ||
94 | if (reg >= WM8731_CACHEREGNUM) | ||
95 | return; | ||
96 | cache[reg] = value; | ||
97 | } | ||
98 | |||
99 | /* | ||
100 | * write to the WM8731 register space | ||
101 | */ | ||
102 | static int wm8731_write(struct snd_soc_codec *codec, unsigned int reg, | ||
103 | unsigned int value) | ||
104 | { | ||
105 | u8 data[2]; | ||
106 | |||
107 | /* data is | ||
108 | * D15..D9 WM8731 register offset | ||
109 | * D8...D0 register data | ||
110 | */ | ||
111 | data[0] = (reg << 1) | ((value >> 8) & 0x0001); | ||
112 | data[1] = value & 0x00ff; | ||
113 | |||
114 | wm8731_write_reg_cache (codec, reg, value); | ||
115 | if (codec->hw_write(codec->control_data, data, 2) == 2) | ||
116 | return 0; | ||
117 | else | ||
118 | return -EIO; | ||
119 | } | ||
120 | |||
121 | #define wm8731_reset(c) wm8731_write(c, WM8731_RESET, 0) | ||
122 | |||
123 | static const char *wm8731_input_select[] = {"Line In", "Mic"}; | ||
124 | static const char *wm8731_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"}; | ||
125 | |||
126 | static const struct soc_enum wm8731_enum[] = { | ||
127 | SOC_ENUM_SINGLE(WM8731_APANA, 2, 2, wm8731_input_select), | ||
128 | SOC_ENUM_SINGLE(WM8731_APDIGI, 1, 4, wm8731_deemph), | ||
129 | }; | ||
130 | |||
131 | static const struct snd_kcontrol_new wm8731_snd_controls[] = { | ||
132 | |||
133 | SOC_DOUBLE_R("Master Playback Volume", WM8731_LOUT1V, WM8731_ROUT1V, | ||
134 | 0, 127, 0), | ||
135 | SOC_DOUBLE_R("Master Playback ZC Switch", WM8731_LOUT1V, WM8731_ROUT1V, | ||
136 | 7, 1, 0), | ||
137 | |||
138 | SOC_DOUBLE_R("Capture Volume", WM8731_LINVOL, WM8731_RINVOL, 0, 31, 0), | ||
139 | SOC_DOUBLE_R("Line Capture Switch", WM8731_LINVOL, WM8731_RINVOL, 7, 1, 1), | ||
140 | |||
141 | SOC_SINGLE("Mic Boost (+20dB)", WM8731_APANA, 0, 1, 0), | ||
142 | SOC_SINGLE("Capture Mic Switch", WM8731_APANA, 1, 1, 1), | ||
143 | |||
144 | SOC_SINGLE("Sidetone Playback Volume", WM8731_APANA, 6, 3, 1), | ||
145 | |||
146 | SOC_SINGLE("ADC High Pass Filter Switch", WM8731_APDIGI, 0, 1, 1), | ||
147 | SOC_SINGLE("Store DC Offset Switch", WM8731_APDIGI, 4, 1, 0), | ||
148 | |||
149 | SOC_ENUM("Playback De-emphasis", wm8731_enum[1]), | ||
150 | }; | ||
151 | |||
152 | /* add non dapm controls */ | ||
153 | static int wm8731_add_controls(struct snd_soc_codec *codec) | ||
154 | { | ||
155 | int err, i; | ||
156 | |||
157 | for (i = 0; i < ARRAY_SIZE(wm8731_snd_controls); i++) { | ||
158 | if ((err = snd_ctl_add(codec->card, | ||
159 | snd_soc_cnew(&wm8731_snd_controls[i],codec, NULL))) < 0) | ||
160 | return err; | ||
161 | } | ||
162 | |||
163 | return 0; | ||
164 | } | ||
165 | |||
166 | /* Output Mixer */ | ||
167 | static const struct snd_kcontrol_new wm8731_output_mixer_controls[] = { | ||
168 | SOC_DAPM_SINGLE("Line Bypass Switch", WM8731_APANA, 3, 1, 0), | ||
169 | SOC_DAPM_SINGLE("Mic Sidetone Switch", WM8731_APANA, 5, 1, 0), | ||
170 | SOC_DAPM_SINGLE("HiFi Playback Switch", WM8731_APANA, 4, 1, 0), | ||
171 | }; | ||
172 | |||
173 | /* Input mux */ | ||
174 | static const struct snd_kcontrol_new wm8731_input_mux_controls = | ||
175 | SOC_DAPM_ENUM("Input Select", wm8731_enum[0]); | ||
176 | |||
177 | static const struct snd_soc_dapm_widget wm8731_dapm_widgets[] = { | ||
178 | SND_SOC_DAPM_MIXER("Output Mixer", WM8731_PWR, 4, 1, | ||
179 | &wm8731_output_mixer_controls[0], | ||
180 | ARRAY_SIZE(wm8731_output_mixer_controls)), | ||
181 | SND_SOC_DAPM_DAC("DAC", "HiFi Playback", WM8731_PWR, 3, 1), | ||
182 | SND_SOC_DAPM_OUTPUT("LOUT"), | ||
183 | SND_SOC_DAPM_OUTPUT("LHPOUT"), | ||
184 | SND_SOC_DAPM_OUTPUT("ROUT"), | ||
185 | SND_SOC_DAPM_OUTPUT("RHPOUT"), | ||
186 | SND_SOC_DAPM_ADC("ADC", "HiFi Capture", WM8731_PWR, 2, 1), | ||
187 | SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, &wm8731_input_mux_controls), | ||
188 | SND_SOC_DAPM_PGA("Line Input", WM8731_PWR, 0, 1, NULL, 0), | ||
189 | SND_SOC_DAPM_MICBIAS("Mic Bias", WM8731_PWR, 1, 1), | ||
190 | SND_SOC_DAPM_INPUT("MICIN"), | ||
191 | SND_SOC_DAPM_INPUT("RLINEIN"), | ||
192 | SND_SOC_DAPM_INPUT("LLINEIN"), | ||
193 | }; | ||
194 | |||
195 | static const char *intercon[][3] = { | ||
196 | /* output mixer */ | ||
197 | {"Output Mixer", "Line Bypass Switch", "Line Input"}, | ||
198 | {"Output Mixer", "HiFi Playback Switch", "DAC"}, | ||
199 | {"Output Mixer", "Mic Sidetone Switch", "Mic Bias"}, | ||
200 | |||
201 | /* outputs */ | ||
202 | {"RHPOUT", NULL, "Output Mixer"}, | ||
203 | {"ROUT", NULL, "Output Mixer"}, | ||
204 | {"LHPOUT", NULL, "Output Mixer"}, | ||
205 | {"LOUT", NULL, "Output Mixer"}, | ||
206 | |||
207 | /* input mux */ | ||
208 | {"Input Mux", "Line In", "Line Input"}, | ||
209 | {"Input Mux", "Mic", "Mic Bias"}, | ||
210 | {"ADC", NULL, "Input Mux"}, | ||
211 | |||
212 | /* inputs */ | ||
213 | {"Line Input", NULL, "LLINEIN"}, | ||
214 | {"Line Input", NULL, "RLINEIN"}, | ||
215 | {"Mic Bias", NULL, "MICIN"}, | ||
216 | |||
217 | /* terminator */ | ||
218 | {NULL, NULL, NULL}, | ||
219 | }; | ||
220 | |||
221 | static int wm8731_add_widgets(struct snd_soc_codec *codec) | ||
222 | { | ||
223 | int i; | ||
224 | |||
225 | for(i = 0; i < ARRAY_SIZE(wm8731_dapm_widgets); i++) { | ||
226 | snd_soc_dapm_new_control(codec, &wm8731_dapm_widgets[i]); | ||
227 | } | ||
228 | |||
229 | /* set up audio path interconnects */ | ||
230 | for(i = 0; intercon[i][0] != NULL; i++) { | ||
231 | snd_soc_dapm_connect_input(codec, intercon[i][0], | ||
232 | intercon[i][1], intercon[i][2]); | ||
233 | } | ||
234 | |||
235 | snd_soc_dapm_new_widgets(codec); | ||
236 | return 0; | ||
237 | } | ||
238 | |||
239 | struct _coeff_div { | ||
240 | u32 mclk; | ||
241 | u32 rate; | ||
242 | u16 fs; | ||
243 | u8 sr:4; | ||
244 | u8 bosr:1; | ||
245 | u8 usb:1; | ||
246 | }; | ||
247 | |||
248 | /* codec mclk clock divider coefficients */ | ||
249 | static const struct _coeff_div coeff_div[] = { | ||
250 | /* 48k */ | ||
251 | {12288000, 48000, 256, 0x0, 0x0, 0x0}, | ||
252 | {18432000, 48000, 384, 0x0, 0x1, 0x0}, | ||
253 | {12000000, 48000, 250, 0x0, 0x0, 0x1}, | ||
254 | |||
255 | /* 32k */ | ||
256 | {12288000, 32000, 384, 0x6, 0x0, 0x0}, | ||
257 | {18432000, 32000, 576, 0x6, 0x1, 0x0}, | ||
258 | {12000000, 32000, 375, 0x6, 0x0, 0x1}, | ||
259 | |||
260 | /* 8k */ | ||
261 | {12288000, 8000, 1536, 0x3, 0x0, 0x0}, | ||
262 | {18432000, 8000, 2304, 0x3, 0x1, 0x0}, | ||
263 | {11289600, 8000, 1408, 0xb, 0x0, 0x0}, | ||
264 | {16934400, 8000, 2112, 0xb, 0x1, 0x0}, | ||
265 | {12000000, 8000, 1500, 0x3, 0x0, 0x1}, | ||
266 | |||
267 | /* 96k */ | ||
268 | {12288000, 96000, 128, 0x7, 0x0, 0x0}, | ||
269 | {18432000, 96000, 192, 0x7, 0x1, 0x0}, | ||
270 | {12000000, 96000, 125, 0x7, 0x0, 0x1}, | ||
271 | |||
272 | /* 44.1k */ | ||
273 | {11289600, 44100, 256, 0x8, 0x0, 0x0}, | ||
274 | {16934400, 44100, 384, 0x8, 0x1, 0x0}, | ||
275 | {12000000, 44100, 272, 0x8, 0x1, 0x1}, | ||
276 | |||
277 | /* 88.2k */ | ||
278 | {11289600, 88200, 128, 0xf, 0x0, 0x0}, | ||
279 | {16934400, 88200, 192, 0xf, 0x1, 0x0}, | ||
280 | {12000000, 88200, 136, 0xf, 0x1, 0x1}, | ||
281 | }; | ||
282 | |||
283 | static inline int get_coeff(int mclk, int rate) | ||
284 | { | ||
285 | int i; | ||
286 | |||
287 | for (i = 0; i < ARRAY_SIZE(coeff_div); i++) { | ||
288 | if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk) | ||
289 | return i; | ||
290 | } | ||
291 | return 0; | ||
292 | } | ||
293 | |||
294 | static int wm8731_hw_params(struct snd_pcm_substream *substream, | ||
295 | struct snd_pcm_hw_params *params) | ||
296 | { | ||
297 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
298 | struct snd_soc_device *socdev = rtd->socdev; | ||
299 | struct snd_soc_codec *codec = socdev->codec; | ||
300 | struct wm8731_priv *wm8731 = codec->private_data; | ||
301 | u16 iface = wm8731_read_reg_cache(codec, WM8731_IFACE) & 0xfff3; | ||
302 | int i = get_coeff(wm8731->sysclk, params_rate(params)); | ||
303 | u16 srate = (coeff_div[i].sr << 2) | | ||
304 | (coeff_div[i].bosr << 1) | coeff_div[i].usb; | ||
305 | |||
306 | wm8731_write(codec, WM8731_SRATE, srate); | ||
307 | |||
308 | /* bit size */ | ||
309 | switch (params_format(params)) { | ||
310 | case SNDRV_PCM_FORMAT_S16_LE: | ||
311 | break; | ||
312 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
313 | iface |= 0x0004; | ||
314 | break; | ||
315 | case SNDRV_PCM_FORMAT_S24_LE: | ||
316 | iface |= 0x0008; | ||
317 | break; | ||
318 | } | ||
319 | |||
320 | wm8731_write(codec, WM8731_IFACE, iface); | ||
321 | return 0; | ||
322 | } | ||
323 | |||
324 | static int wm8731_pcm_prepare(struct snd_pcm_substream *substream) | ||
325 | { | ||
326 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
327 | struct snd_soc_device *socdev = rtd->socdev; | ||
328 | struct snd_soc_codec *codec = socdev->codec; | ||
329 | |||
330 | /* set active */ | ||
331 | wm8731_write(codec, WM8731_ACTIVE, 0x0001); | ||
332 | |||
333 | return 0; | ||
334 | } | ||
335 | |||
336 | static void wm8731_shutdown(struct snd_pcm_substream *substream) | ||
337 | { | ||
338 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
339 | struct snd_soc_device *socdev = rtd->socdev; | ||
340 | struct snd_soc_codec *codec = socdev->codec; | ||
341 | |||
342 | /* deactivate */ | ||
343 | if (!codec->active) { | ||
344 | udelay(50); | ||
345 | wm8731_write(codec, WM8731_ACTIVE, 0x0); | ||
346 | } | ||
347 | } | ||
348 | |||
349 | static int wm8731_mute(struct snd_soc_codec_dai *dai, int mute) | ||
350 | { | ||
351 | struct snd_soc_codec *codec = dai->codec; | ||
352 | u16 mute_reg = wm8731_read_reg_cache(codec, WM8731_APDIGI) & 0xfff7; | ||
353 | |||
354 | if (mute) | ||
355 | wm8731_write(codec, WM8731_APDIGI, mute_reg | 0x8); | ||
356 | else | ||
357 | wm8731_write(codec, WM8731_APDIGI, mute_reg); | ||
358 | return 0; | ||
359 | } | ||
360 | |||
361 | static int wm8731_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai, | ||
362 | int clk_id, unsigned int freq, int dir) | ||
363 | { | ||
364 | struct snd_soc_codec *codec = codec_dai->codec; | ||
365 | struct wm8731_priv *wm8731 = codec->private_data; | ||
366 | |||
367 | switch (freq) { | ||
368 | case 11289600: | ||
369 | case 12000000: | ||
370 | case 12288000: | ||
371 | case 16934400: | ||
372 | case 18432000: | ||
373 | wm8731->sysclk = freq; | ||
374 | return 0; | ||
375 | } | ||
376 | return -EINVAL; | ||
377 | } | ||
378 | |||
379 | |||
380 | static int wm8731_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | ||
381 | unsigned int fmt) | ||
382 | { | ||
383 | struct snd_soc_codec *codec = codec_dai->codec; | ||
384 | u16 iface = 0; | ||
385 | |||
386 | /* set master/slave audio interface */ | ||
387 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
388 | case SND_SOC_DAIFMT_CBM_CFM: | ||
389 | iface |= 0x0040; | ||
390 | break; | ||
391 | case SND_SOC_DAIFMT_CBS_CFS: | ||
392 | break; | ||
393 | default: | ||
394 | return -EINVAL; | ||
395 | } | ||
396 | |||
397 | /* interface format */ | ||
398 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
399 | case SND_SOC_DAIFMT_I2S: | ||
400 | iface |= 0x0002; | ||
401 | break; | ||
402 | case SND_SOC_DAIFMT_RIGHT_J: | ||
403 | break; | ||
404 | case SND_SOC_DAIFMT_LEFT_J: | ||
405 | iface |= 0x0001; | ||
406 | break; | ||
407 | case SND_SOC_DAIFMT_DSP_A: | ||
408 | iface |= 0x0003; | ||
409 | break; | ||
410 | case SND_SOC_DAIFMT_DSP_B: | ||
411 | iface |= 0x0013; | ||
412 | break; | ||
413 | default: | ||
414 | return -EINVAL; | ||
415 | } | ||
416 | |||
417 | /* clock inversion */ | ||
418 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
419 | case SND_SOC_DAIFMT_NB_NF: | ||
420 | break; | ||
421 | case SND_SOC_DAIFMT_IB_IF: | ||
422 | iface |= 0x0090; | ||
423 | break; | ||
424 | case SND_SOC_DAIFMT_IB_NF: | ||
425 | iface |= 0x0080; | ||
426 | break; | ||
427 | case SND_SOC_DAIFMT_NB_IF: | ||
428 | iface |= 0x0010; | ||
429 | break; | ||
430 | default: | ||
431 | return -EINVAL; | ||
432 | } | ||
433 | |||
434 | /* set iface */ | ||
435 | wm8731_write(codec, WM8731_IFACE, iface); | ||
436 | return 0; | ||
437 | } | ||
438 | |||
439 | static int wm8731_dapm_event(struct snd_soc_codec *codec, int event) | ||
440 | { | ||
441 | u16 reg = wm8731_read_reg_cache(codec, WM8731_PWR) & 0xff7f; | ||
442 | |||
443 | switch (event) { | ||
444 | case SNDRV_CTL_POWER_D0: /* full On */ | ||
445 | /* vref/mid, osc on, dac unmute */ | ||
446 | wm8731_write(codec, WM8731_PWR, reg); | ||
447 | break; | ||
448 | case SNDRV_CTL_POWER_D1: /* partial On */ | ||
449 | case SNDRV_CTL_POWER_D2: /* partial On */ | ||
450 | break; | ||
451 | case SNDRV_CTL_POWER_D3hot: /* Off, with power */ | ||
452 | /* everything off except vref/vmid, */ | ||
453 | wm8731_write(codec, WM8731_PWR, reg | 0x0040); | ||
454 | break; | ||
455 | case SNDRV_CTL_POWER_D3cold: /* Off, without power */ | ||
456 | /* everything off, dac mute, inactive */ | ||
457 | wm8731_write(codec, WM8731_ACTIVE, 0x0); | ||
458 | wm8731_write(codec, WM8731_PWR, 0xffff); | ||
459 | break; | ||
460 | } | ||
461 | codec->dapm_state = event; | ||
462 | return 0; | ||
463 | } | ||
464 | |||
465 | #define WM8731_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ | ||
466 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ | ||
467 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\ | ||
468 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\ | ||
469 | SNDRV_PCM_RATE_96000) | ||
470 | |||
471 | #define WM8731_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | ||
472 | SNDRV_PCM_FMTBIT_S24_LE) | ||
473 | |||
474 | struct snd_soc_codec_dai wm8731_dai = { | ||
475 | .name = "WM8731", | ||
476 | .playback = { | ||
477 | .stream_name = "Playback", | ||
478 | .channels_min = 1, | ||
479 | .channels_max = 2, | ||
480 | .rates = WM8731_RATES, | ||
481 | .formats = WM8731_FORMATS,}, | ||
482 | .capture = { | ||
483 | .stream_name = "Capture", | ||
484 | .channels_min = 1, | ||
485 | .channels_max = 2, | ||
486 | .rates = WM8731_RATES, | ||
487 | .formats = WM8731_FORMATS,}, | ||
488 | .ops = { | ||
489 | .prepare = wm8731_pcm_prepare, | ||
490 | .hw_params = wm8731_hw_params, | ||
491 | .shutdown = wm8731_shutdown, | ||
492 | }, | ||
493 | .dai_ops = { | ||
494 | .digital_mute = wm8731_mute, | ||
495 | .set_sysclk = wm8731_set_dai_sysclk, | ||
496 | .set_fmt = wm8731_set_dai_fmt, | ||
497 | } | ||
498 | }; | ||
499 | EXPORT_SYMBOL_GPL(wm8731_dai); | ||
500 | |||
501 | static int wm8731_suspend(struct platform_device *pdev, pm_message_t state) | ||
502 | { | ||
503 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
504 | struct snd_soc_codec *codec = socdev->codec; | ||
505 | |||
506 | wm8731_write(codec, WM8731_ACTIVE, 0x0); | ||
507 | wm8731_dapm_event(codec, SNDRV_CTL_POWER_D3cold); | ||
508 | return 0; | ||
509 | } | ||
510 | |||
511 | static int wm8731_resume(struct platform_device *pdev) | ||
512 | { | ||
513 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
514 | struct snd_soc_codec *codec = socdev->codec; | ||
515 | int i; | ||
516 | u8 data[2]; | ||
517 | u16 *cache = codec->reg_cache; | ||
518 | |||
519 | /* Sync reg_cache with the hardware */ | ||
520 | for (i = 0; i < ARRAY_SIZE(wm8731_reg); i++) { | ||
521 | data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001); | ||
522 | data[1] = cache[i] & 0x00ff; | ||
523 | codec->hw_write(codec->control_data, data, 2); | ||
524 | } | ||
525 | wm8731_dapm_event(codec, SNDRV_CTL_POWER_D3hot); | ||
526 | wm8731_dapm_event(codec, codec->suspend_dapm_state); | ||
527 | return 0; | ||
528 | } | ||
529 | |||
530 | /* | ||
531 | * initialise the WM8731 driver | ||
532 | * register the mixer and dsp interfaces with the kernel | ||
533 | */ | ||
534 | static int wm8731_init(struct snd_soc_device *socdev) | ||
535 | { | ||
536 | struct snd_soc_codec *codec = socdev->codec; | ||
537 | int reg, ret = 0; | ||
538 | |||
539 | codec->name = "WM8731"; | ||
540 | codec->owner = THIS_MODULE; | ||
541 | codec->read = wm8731_read_reg_cache; | ||
542 | codec->write = wm8731_write; | ||
543 | codec->dapm_event = wm8731_dapm_event; | ||
544 | codec->dai = &wm8731_dai; | ||
545 | codec->num_dai = 1; | ||
546 | codec->reg_cache_size = sizeof(wm8731_reg); | ||
547 | codec->reg_cache = kmemdup(wm8731_reg, sizeof(wm8731_reg), GFP_KERNEL); | ||
548 | if (codec->reg_cache == NULL) | ||
549 | return -ENOMEM; | ||
550 | |||
551 | wm8731_reset(codec); | ||
552 | |||
553 | /* register pcms */ | ||
554 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
555 | if (ret < 0) { | ||
556 | printk(KERN_ERR "wm8731: failed to create pcms\n"); | ||
557 | goto pcm_err; | ||
558 | } | ||
559 | |||
560 | /* power on device */ | ||
561 | wm8731_dapm_event(codec, SNDRV_CTL_POWER_D3hot); | ||
562 | |||
563 | /* set the update bits */ | ||
564 | reg = wm8731_read_reg_cache(codec, WM8731_LOUT1V); | ||
565 | wm8731_write(codec, WM8731_LOUT1V, reg | 0x0100); | ||
566 | reg = wm8731_read_reg_cache(codec, WM8731_ROUT1V); | ||
567 | wm8731_write(codec, WM8731_ROUT1V, reg | 0x0100); | ||
568 | reg = wm8731_read_reg_cache(codec, WM8731_LINVOL); | ||
569 | wm8731_write(codec, WM8731_LINVOL, reg | 0x0100); | ||
570 | reg = wm8731_read_reg_cache(codec, WM8731_RINVOL); | ||
571 | wm8731_write(codec, WM8731_RINVOL, reg | 0x0100); | ||
572 | |||
573 | wm8731_add_controls(codec); | ||
574 | wm8731_add_widgets(codec); | ||
575 | ret = snd_soc_register_card(socdev); | ||
576 | if (ret < 0) { | ||
577 | printk(KERN_ERR "wm8731: failed to register card\n"); | ||
578 | goto card_err; | ||
579 | } | ||
580 | |||
581 | return ret; | ||
582 | |||
583 | card_err: | ||
584 | snd_soc_free_pcms(socdev); | ||
585 | snd_soc_dapm_free(socdev); | ||
586 | pcm_err: | ||
587 | kfree(codec->reg_cache); | ||
588 | return ret; | ||
589 | } | ||
590 | |||
591 | static struct snd_soc_device *wm8731_socdev; | ||
592 | |||
593 | #if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE) | ||
594 | |||
595 | /* | ||
596 | * WM8731 2 wire address is determined by GPIO5 | ||
597 | * state during powerup. | ||
598 | * low = 0x1a | ||
599 | * high = 0x1b | ||
600 | */ | ||
601 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; | ||
602 | |||
603 | /* Magic definition of all other variables and things */ | ||
604 | I2C_CLIENT_INSMOD; | ||
605 | |||
606 | static struct i2c_driver wm8731_i2c_driver; | ||
607 | static struct i2c_client client_template; | ||
608 | |||
609 | /* If the i2c layer weren't so broken, we could pass this kind of data | ||
610 | around */ | ||
611 | |||
612 | static int wm8731_codec_probe(struct i2c_adapter *adap, int addr, int kind) | ||
613 | { | ||
614 | struct snd_soc_device *socdev = wm8731_socdev; | ||
615 | struct wm8731_setup_data *setup = socdev->codec_data; | ||
616 | struct snd_soc_codec *codec = socdev->codec; | ||
617 | struct i2c_client *i2c; | ||
618 | int ret; | ||
619 | |||
620 | if (addr != setup->i2c_address) | ||
621 | return -ENODEV; | ||
622 | |||
623 | client_template.adapter = adap; | ||
624 | client_template.addr = addr; | ||
625 | |||
626 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | ||
627 | if (i2c == NULL) { | ||
628 | kfree(codec); | ||
629 | return -ENOMEM; | ||
630 | } | ||
631 | i2c_set_clientdata(i2c, codec); | ||
632 | codec->control_data = i2c; | ||
633 | |||
634 | ret = i2c_attach_client(i2c); | ||
635 | if (ret < 0) { | ||
636 | err("failed to attach codec at addr %x\n", addr); | ||
637 | goto err; | ||
638 | } | ||
639 | |||
640 | ret = wm8731_init(socdev); | ||
641 | if (ret < 0) { | ||
642 | err("failed to initialise WM8731\n"); | ||
643 | goto err; | ||
644 | } | ||
645 | return ret; | ||
646 | |||
647 | err: | ||
648 | kfree(codec); | ||
649 | kfree(i2c); | ||
650 | return ret; | ||
651 | } | ||
652 | |||
653 | static int wm8731_i2c_detach(struct i2c_client *client) | ||
654 | { | ||
655 | struct snd_soc_codec* codec = i2c_get_clientdata(client); | ||
656 | i2c_detach_client(client); | ||
657 | kfree(codec->reg_cache); | ||
658 | kfree(client); | ||
659 | return 0; | ||
660 | } | ||
661 | |||
662 | static int wm8731_i2c_attach(struct i2c_adapter *adap) | ||
663 | { | ||
664 | return i2c_probe(adap, &addr_data, wm8731_codec_probe); | ||
665 | } | ||
666 | |||
667 | /* corgi i2c codec control layer */ | ||
668 | static struct i2c_driver wm8731_i2c_driver = { | ||
669 | .driver = { | ||
670 | .name = "WM8731 I2C Codec", | ||
671 | .owner = THIS_MODULE, | ||
672 | }, | ||
673 | .id = I2C_DRIVERID_WM8731, | ||
674 | .attach_adapter = wm8731_i2c_attach, | ||
675 | .detach_client = wm8731_i2c_detach, | ||
676 | .command = NULL, | ||
677 | }; | ||
678 | |||
679 | static struct i2c_client client_template = { | ||
680 | .name = "WM8731", | ||
681 | .driver = &wm8731_i2c_driver, | ||
682 | }; | ||
683 | #endif | ||
684 | |||
685 | static int wm8731_probe(struct platform_device *pdev) | ||
686 | { | ||
687 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
688 | struct wm8731_setup_data *setup; | ||
689 | struct snd_soc_codec *codec; | ||
690 | struct wm8731_priv *wm8731; | ||
691 | int ret = 0; | ||
692 | |||
693 | info("WM8731 Audio Codec %s", WM8731_VERSION); | ||
694 | |||
695 | setup = socdev->codec_data; | ||
696 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | ||
697 | if (codec == NULL) | ||
698 | return -ENOMEM; | ||
699 | |||
700 | wm8731 = kzalloc(sizeof(struct wm8731_priv), GFP_KERNEL); | ||
701 | if (wm8731 == NULL) { | ||
702 | kfree(codec); | ||
703 | return -ENOMEM; | ||
704 | } | ||
705 | |||
706 | codec->private_data = wm8731; | ||
707 | socdev->codec = codec; | ||
708 | mutex_init(&codec->mutex); | ||
709 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
710 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
711 | |||
712 | wm8731_socdev = socdev; | ||
713 | #if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE) | ||
714 | if (setup->i2c_address) { | ||
715 | normal_i2c[0] = setup->i2c_address; | ||
716 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
717 | ret = i2c_add_driver(&wm8731_i2c_driver); | ||
718 | if (ret != 0) | ||
719 | printk(KERN_ERR "can't add i2c driver"); | ||
720 | } | ||
721 | #else | ||
722 | /* Add other interfaces here */ | ||
723 | #endif | ||
724 | return ret; | ||
725 | } | ||
726 | |||
727 | /* power down chip */ | ||
728 | static int wm8731_remove(struct platform_device *pdev) | ||
729 | { | ||
730 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
731 | struct snd_soc_codec *codec = socdev->codec; | ||
732 | |||
733 | if (codec->control_data) | ||
734 | wm8731_dapm_event(codec, SNDRV_CTL_POWER_D3cold); | ||
735 | |||
736 | snd_soc_free_pcms(socdev); | ||
737 | snd_soc_dapm_free(socdev); | ||
738 | #if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE) | ||
739 | i2c_del_driver(&wm8731_i2c_driver); | ||
740 | #endif | ||
741 | kfree(codec->private_data); | ||
742 | kfree(codec); | ||
743 | |||
744 | return 0; | ||
745 | } | ||
746 | |||
747 | struct snd_soc_codec_device soc_codec_dev_wm8731 = { | ||
748 | .probe = wm8731_probe, | ||
749 | .remove = wm8731_remove, | ||
750 | .suspend = wm8731_suspend, | ||
751 | .resume = wm8731_resume, | ||
752 | }; | ||
753 | |||
754 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8731); | ||
755 | |||
756 | MODULE_DESCRIPTION("ASoC WM8731 driver"); | ||
757 | MODULE_AUTHOR("Richard Purdie"); | ||
758 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/wm8731.h b/sound/soc/codecs/wm8731.h new file mode 100644 index 000000000000..5bcab6a7afb4 --- /dev/null +++ b/sound/soc/codecs/wm8731.h | |||
@@ -0,0 +1,44 @@ | |||
1 | /* | ||
2 | * wm8731.h -- WM8731 Soc Audio driver | ||
3 | * | ||
4 | * Copyright 2005 Openedhand Ltd. | ||
5 | * | ||
6 | * Author: Richard Purdie <richard@openedhand.com> | ||
7 | * | ||
8 | * Based on wm8753.h | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #ifndef _WM8731_H | ||
16 | #define _WM8731_H | ||
17 | |||
18 | /* WM8731 register space */ | ||
19 | |||
20 | #define WM8731_LINVOL 0x00 | ||
21 | #define WM8731_RINVOL 0x01 | ||
22 | #define WM8731_LOUT1V 0x02 | ||
23 | #define WM8731_ROUT1V 0x03 | ||
24 | #define WM8731_APANA 0x04 | ||
25 | #define WM8731_APDIGI 0x05 | ||
26 | #define WM8731_PWR 0x06 | ||
27 | #define WM8731_IFACE 0x07 | ||
28 | #define WM8731_SRATE 0x08 | ||
29 | #define WM8731_ACTIVE 0x09 | ||
30 | #define WM8731_RESET 0x0f | ||
31 | |||
32 | #define WM8731_CACHEREGNUM 10 | ||
33 | |||
34 | #define WM8731_SYSCLK 0 | ||
35 | #define WM8731_DAI 0 | ||
36 | |||
37 | struct wm8731_setup_data { | ||
38 | unsigned short i2c_address; | ||
39 | }; | ||
40 | |||
41 | extern struct snd_soc_codec_dai wm8731_dai; | ||
42 | extern struct snd_soc_codec_device soc_codec_dev_wm8731; | ||
43 | |||
44 | #endif | ||
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c new file mode 100644 index 000000000000..7073e8e294fc --- /dev/null +++ b/sound/soc/codecs/wm8750.c | |||
@@ -0,0 +1,1049 @@ | |||
1 | /* | ||
2 | * wm8750.c -- WM8750 ALSA SoC audio driver | ||
3 | * | ||
4 | * Copyright 2005 Openedhand Ltd. | ||
5 | * | ||
6 | * Author: Richard Purdie <richard@openedhand.com> | ||
7 | * | ||
8 | * Based on WM8753.c | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #include <linux/module.h> | ||
16 | #include <linux/moduleparam.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/delay.h> | ||
19 | #include <linux/pm.h> | ||
20 | #include <linux/i2c.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | #include <sound/driver.h> | ||
23 | #include <sound/core.h> | ||
24 | #include <sound/pcm.h> | ||
25 | #include <sound/pcm_params.h> | ||
26 | #include <sound/soc.h> | ||
27 | #include <sound/soc-dapm.h> | ||
28 | #include <sound/initval.h> | ||
29 | |||
30 | #include "wm8750.h" | ||
31 | |||
32 | #define AUDIO_NAME "WM8750" | ||
33 | #define WM8750_VERSION "0.12" | ||
34 | |||
35 | /* | ||
36 | * Debug | ||
37 | */ | ||
38 | |||
39 | #define WM8750_DEBUG 0 | ||
40 | |||
41 | #ifdef WM8750_DEBUG | ||
42 | #define dbg(format, arg...) \ | ||
43 | printk(KERN_DEBUG AUDIO_NAME ": " format "\n" , ## arg) | ||
44 | #else | ||
45 | #define dbg(format, arg...) do {} while (0) | ||
46 | #endif | ||
47 | #define err(format, arg...) \ | ||
48 | printk(KERN_ERR AUDIO_NAME ": " format "\n" , ## arg) | ||
49 | #define info(format, arg...) \ | ||
50 | printk(KERN_INFO AUDIO_NAME ": " format "\n" , ## arg) | ||
51 | #define warn(format, arg...) \ | ||
52 | printk(KERN_WARNING AUDIO_NAME ": " format "\n" , ## arg) | ||
53 | |||
54 | /* codec private data */ | ||
55 | struct wm8750_priv { | ||
56 | unsigned int sysclk; | ||
57 | }; | ||
58 | |||
59 | /* | ||
60 | * wm8750 register cache | ||
61 | * We can't read the WM8750 register space when we | ||
62 | * are using 2 wire for device control, so we cache them instead. | ||
63 | */ | ||
64 | static const u16 wm8750_reg[] = { | ||
65 | 0x0097, 0x0097, 0x0079, 0x0079, /* 0 */ | ||
66 | 0x0000, 0x0008, 0x0000, 0x000a, /* 4 */ | ||
67 | 0x0000, 0x0000, 0x00ff, 0x00ff, /* 8 */ | ||
68 | 0x000f, 0x000f, 0x0000, 0x0000, /* 12 */ | ||
69 | 0x0000, 0x007b, 0x0000, 0x0032, /* 16 */ | ||
70 | 0x0000, 0x00c3, 0x00c3, 0x00c0, /* 20 */ | ||
71 | 0x0000, 0x0000, 0x0000, 0x0000, /* 24 */ | ||
72 | 0x0000, 0x0000, 0x0000, 0x0000, /* 28 */ | ||
73 | 0x0000, 0x0000, 0x0050, 0x0050, /* 32 */ | ||
74 | 0x0050, 0x0050, 0x0050, 0x0050, /* 36 */ | ||
75 | 0x0079, 0x0079, 0x0079, /* 40 */ | ||
76 | }; | ||
77 | |||
78 | /* | ||
79 | * read wm8750 register cache | ||
80 | */ | ||
81 | static inline unsigned int wm8750_read_reg_cache(struct snd_soc_codec *codec, | ||
82 | unsigned int reg) | ||
83 | { | ||
84 | u16 *cache = codec->reg_cache; | ||
85 | if (reg > WM8750_CACHE_REGNUM) | ||
86 | return -1; | ||
87 | return cache[reg]; | ||
88 | } | ||
89 | |||
90 | /* | ||
91 | * write wm8750 register cache | ||
92 | */ | ||
93 | static inline void wm8750_write_reg_cache(struct snd_soc_codec *codec, | ||
94 | unsigned int reg, unsigned int value) | ||
95 | { | ||
96 | u16 *cache = codec->reg_cache; | ||
97 | if (reg > WM8750_CACHE_REGNUM) | ||
98 | return; | ||
99 | cache[reg] = value; | ||
100 | } | ||
101 | |||
102 | static int wm8750_write(struct snd_soc_codec *codec, unsigned int reg, | ||
103 | unsigned int value) | ||
104 | { | ||
105 | u8 data[2]; | ||
106 | |||
107 | /* data is | ||
108 | * D15..D9 WM8753 register offset | ||
109 | * D8...D0 register data | ||
110 | */ | ||
111 | data[0] = (reg << 1) | ((value >> 8) & 0x0001); | ||
112 | data[1] = value & 0x00ff; | ||
113 | |||
114 | wm8750_write_reg_cache (codec, reg, value); | ||
115 | if (codec->hw_write(codec->control_data, data, 2) == 2) | ||
116 | return 0; | ||
117 | else | ||
118 | return -EIO; | ||
119 | } | ||
120 | |||
121 | #define wm8750_reset(c) wm8750_write(c, WM8750_RESET, 0) | ||
122 | |||
123 | /* | ||
124 | * WM8750 Controls | ||
125 | */ | ||
126 | static const char *wm8750_bass[] = {"Linear Control", "Adaptive Boost"}; | ||
127 | static const char *wm8750_bass_filter[] = { "130Hz @ 48kHz", "200Hz @ 48kHz" }; | ||
128 | static const char *wm8750_treble[] = {"8kHz", "4kHz"}; | ||
129 | static const char *wm8750_3d_lc[] = {"200Hz", "500Hz"}; | ||
130 | static const char *wm8750_3d_uc[] = {"2.2kHz", "1.5kHz"}; | ||
131 | static const char *wm8750_3d_func[] = {"Capture", "Playback"}; | ||
132 | static const char *wm8750_alc_func[] = {"Off", "Right", "Left", "Stereo"}; | ||
133 | static const char *wm8750_ng_type[] = {"Constant PGA Gain", | ||
134 | "Mute ADC Output"}; | ||
135 | static const char *wm8750_line_mux[] = {"Line 1", "Line 2", "Line 3", "PGA", | ||
136 | "Differential"}; | ||
137 | static const char *wm8750_pga_sel[] = {"Line 1", "Line 2", "Line 3", | ||
138 | "Differential"}; | ||
139 | static const char *wm8750_out3[] = {"VREF", "ROUT1 + Vol", "MonoOut", | ||
140 | "ROUT1"}; | ||
141 | static const char *wm8750_diff_sel[] = {"Line 1", "Line 2"}; | ||
142 | static const char *wm8750_adcpol[] = {"Normal", "L Invert", "R Invert", | ||
143 | "L + R Invert"}; | ||
144 | static const char *wm8750_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"}; | ||
145 | static const char *wm8750_mono_mux[] = {"Stereo", "Mono (Left)", | ||
146 | "Mono (Right)", "Digital Mono"}; | ||
147 | |||
148 | static const struct soc_enum wm8750_enum[] = { | ||
149 | SOC_ENUM_SINGLE(WM8750_BASS, 7, 2, wm8750_bass), | ||
150 | SOC_ENUM_SINGLE(WM8750_BASS, 6, 2, wm8750_bass_filter), | ||
151 | SOC_ENUM_SINGLE(WM8750_TREBLE, 6, 2, wm8750_treble), | ||
152 | SOC_ENUM_SINGLE(WM8750_3D, 5, 2, wm8750_3d_lc), | ||
153 | SOC_ENUM_SINGLE(WM8750_3D, 6, 2, wm8750_3d_uc), | ||
154 | SOC_ENUM_SINGLE(WM8750_3D, 7, 2, wm8750_3d_func), | ||
155 | SOC_ENUM_SINGLE(WM8750_ALC1, 7, 4, wm8750_alc_func), | ||
156 | SOC_ENUM_SINGLE(WM8750_NGATE, 1, 2, wm8750_ng_type), | ||
157 | SOC_ENUM_SINGLE(WM8750_LOUTM1, 0, 5, wm8750_line_mux), | ||
158 | SOC_ENUM_SINGLE(WM8750_ROUTM1, 0, 5, wm8750_line_mux), | ||
159 | SOC_ENUM_SINGLE(WM8750_LADCIN, 6, 4, wm8750_pga_sel), /* 10 */ | ||
160 | SOC_ENUM_SINGLE(WM8750_RADCIN, 6, 4, wm8750_pga_sel), | ||
161 | SOC_ENUM_SINGLE(WM8750_ADCTL2, 7, 4, wm8750_out3), | ||
162 | SOC_ENUM_SINGLE(WM8750_ADCIN, 8, 2, wm8750_diff_sel), | ||
163 | SOC_ENUM_SINGLE(WM8750_ADCDAC, 5, 4, wm8750_adcpol), | ||
164 | SOC_ENUM_SINGLE(WM8750_ADCDAC, 1, 4, wm8750_deemph), | ||
165 | SOC_ENUM_SINGLE(WM8750_ADCIN, 6, 4, wm8750_mono_mux), /* 16 */ | ||
166 | |||
167 | }; | ||
168 | |||
169 | static const struct snd_kcontrol_new wm8750_snd_controls[] = { | ||
170 | |||
171 | SOC_DOUBLE_R("Capture Volume", WM8750_LINVOL, WM8750_RINVOL, 0, 63, 0), | ||
172 | SOC_DOUBLE_R("Capture ZC Switch", WM8750_LINVOL, WM8750_RINVOL, 6, 1, 0), | ||
173 | SOC_DOUBLE_R("Capture Switch", WM8750_LINVOL, WM8750_RINVOL, 7, 1, 1), | ||
174 | |||
175 | SOC_DOUBLE_R("Headphone Playback ZC Switch", WM8750_LOUT1V, | ||
176 | WM8750_ROUT1V, 7, 1, 0), | ||
177 | SOC_DOUBLE_R("Speaker Playback ZC Switch", WM8750_LOUT2V, | ||
178 | WM8750_ROUT2V, 7, 1, 0), | ||
179 | |||
180 | SOC_ENUM("Playback De-emphasis", wm8750_enum[15]), | ||
181 | |||
182 | SOC_ENUM("Capture Polarity", wm8750_enum[14]), | ||
183 | SOC_SINGLE("Playback 6dB Attenuate", WM8750_ADCDAC, 7, 1, 0), | ||
184 | SOC_SINGLE("Capture 6dB Attenuate", WM8750_ADCDAC, 8, 1, 0), | ||
185 | |||
186 | SOC_DOUBLE_R("PCM Volume", WM8750_LDAC, WM8750_RDAC, 0, 255, 0), | ||
187 | |||
188 | SOC_ENUM("Bass Boost", wm8750_enum[0]), | ||
189 | SOC_ENUM("Bass Filter", wm8750_enum[1]), | ||
190 | SOC_SINGLE("Bass Volume", WM8750_BASS, 0, 15, 1), | ||
191 | |||
192 | SOC_SINGLE("Treble Volume", WM8750_TREBLE, 0, 15, 0), | ||
193 | SOC_ENUM("Treble Cut-off", wm8750_enum[2]), | ||
194 | |||
195 | SOC_SINGLE("3D Switch", WM8750_3D, 0, 1, 0), | ||
196 | SOC_SINGLE("3D Volume", WM8750_3D, 1, 15, 0), | ||
197 | SOC_ENUM("3D Lower Cut-off", wm8750_enum[3]), | ||
198 | SOC_ENUM("3D Upper Cut-off", wm8750_enum[4]), | ||
199 | SOC_ENUM("3D Mode", wm8750_enum[5]), | ||
200 | |||
201 | SOC_SINGLE("ALC Capture Target Volume", WM8750_ALC1, 0, 7, 0), | ||
202 | SOC_SINGLE("ALC Capture Max Volume", WM8750_ALC1, 4, 7, 0), | ||
203 | SOC_ENUM("ALC Capture Function", wm8750_enum[6]), | ||
204 | SOC_SINGLE("ALC Capture ZC Switch", WM8750_ALC2, 7, 1, 0), | ||
205 | SOC_SINGLE("ALC Capture Hold Time", WM8750_ALC2, 0, 15, 0), | ||
206 | SOC_SINGLE("ALC Capture Decay Time", WM8750_ALC3, 4, 15, 0), | ||
207 | SOC_SINGLE("ALC Capture Attack Time", WM8750_ALC3, 0, 15, 0), | ||
208 | SOC_SINGLE("ALC Capture NG Threshold", WM8750_NGATE, 3, 31, 0), | ||
209 | SOC_ENUM("ALC Capture NG Type", wm8750_enum[4]), | ||
210 | SOC_SINGLE("ALC Capture NG Switch", WM8750_NGATE, 0, 1, 0), | ||
211 | |||
212 | SOC_SINGLE("Left ADC Capture Volume", WM8750_LADC, 0, 255, 0), | ||
213 | SOC_SINGLE("Right ADC Capture Volume", WM8750_RADC, 0, 255, 0), | ||
214 | |||
215 | SOC_SINGLE("ZC Timeout Switch", WM8750_ADCTL1, 0, 1, 0), | ||
216 | SOC_SINGLE("Playback Invert Switch", WM8750_ADCTL1, 1, 1, 0), | ||
217 | |||
218 | SOC_SINGLE("Right Speaker Playback Invert Switch", WM8750_ADCTL2, 4, 1, 0), | ||
219 | |||
220 | /* Unimplemented */ | ||
221 | /* ADCDAC Bit 0 - ADCHPD */ | ||
222 | /* ADCDAC Bit 4 - HPOR */ | ||
223 | /* ADCTL1 Bit 2,3 - DATSEL */ | ||
224 | /* ADCTL1 Bit 4,5 - DMONOMIX */ | ||
225 | /* ADCTL1 Bit 6,7 - VSEL */ | ||
226 | /* ADCTL2 Bit 2 - LRCM */ | ||
227 | /* ADCTL2 Bit 3 - TRI */ | ||
228 | /* ADCTL3 Bit 5 - HPFLREN */ | ||
229 | /* ADCTL3 Bit 6 - VROI */ | ||
230 | /* ADCTL3 Bit 7,8 - ADCLRM */ | ||
231 | /* ADCIN Bit 4 - LDCM */ | ||
232 | /* ADCIN Bit 5 - RDCM */ | ||
233 | |||
234 | SOC_DOUBLE_R("Mic Boost", WM8750_LADCIN, WM8750_RADCIN, 4, 3, 0), | ||
235 | |||
236 | SOC_DOUBLE_R("Bypass Left Playback Volume", WM8750_LOUTM1, | ||
237 | WM8750_LOUTM2, 4, 7, 1), | ||
238 | SOC_DOUBLE_R("Bypass Right Playback Volume", WM8750_ROUTM1, | ||
239 | WM8750_ROUTM2, 4, 7, 1), | ||
240 | SOC_DOUBLE_R("Bypass Mono Playback Volume", WM8750_MOUTM1, | ||
241 | WM8750_MOUTM2, 4, 7, 1), | ||
242 | |||
243 | SOC_SINGLE("Mono Playback ZC Switch", WM8750_MOUTV, 7, 1, 0), | ||
244 | |||
245 | SOC_DOUBLE_R("Headphone Playback Volume", WM8750_LOUT1V, WM8750_ROUT1V, | ||
246 | 0, 127, 0), | ||
247 | SOC_DOUBLE_R("Speaker Playback Volume", WM8750_LOUT2V, WM8750_ROUT2V, | ||
248 | 0, 127, 0), | ||
249 | |||
250 | SOC_SINGLE("Mono Playback Volume", WM8750_MOUTV, 0, 127, 0), | ||
251 | |||
252 | }; | ||
253 | |||
254 | /* add non dapm controls */ | ||
255 | static int wm8750_add_controls(struct snd_soc_codec *codec) | ||
256 | { | ||
257 | int err, i; | ||
258 | |||
259 | for (i = 0; i < ARRAY_SIZE(wm8750_snd_controls); i++) { | ||
260 | err = snd_ctl_add(codec->card, | ||
261 | snd_soc_cnew(&wm8750_snd_controls[i],codec, NULL)); | ||
262 | if (err < 0) | ||
263 | return err; | ||
264 | } | ||
265 | return 0; | ||
266 | } | ||
267 | |||
268 | /* | ||
269 | * DAPM Controls | ||
270 | */ | ||
271 | |||
272 | /* Left Mixer */ | ||
273 | static const struct snd_kcontrol_new wm8750_left_mixer_controls[] = { | ||
274 | SOC_DAPM_SINGLE("Playback Switch", WM8750_LOUTM1, 8, 1, 0), | ||
275 | SOC_DAPM_SINGLE("Left Bypass Switch", WM8750_LOUTM1, 7, 1, 0), | ||
276 | SOC_DAPM_SINGLE("Right Playback Switch", WM8750_LOUTM2, 8, 1, 0), | ||
277 | SOC_DAPM_SINGLE("Right Bypass Switch", WM8750_LOUTM2, 7, 1, 0), | ||
278 | }; | ||
279 | |||
280 | /* Right Mixer */ | ||
281 | static const struct snd_kcontrol_new wm8750_right_mixer_controls[] = { | ||
282 | SOC_DAPM_SINGLE("Left Playback Switch", WM8750_ROUTM1, 8, 1, 0), | ||
283 | SOC_DAPM_SINGLE("Left Bypass Switch", WM8750_ROUTM1, 7, 1, 0), | ||
284 | SOC_DAPM_SINGLE("Playback Switch", WM8750_ROUTM2, 8, 1, 0), | ||
285 | SOC_DAPM_SINGLE("Right Bypass Switch", WM8750_ROUTM2, 7, 1, 0), | ||
286 | }; | ||
287 | |||
288 | /* Mono Mixer */ | ||
289 | static const struct snd_kcontrol_new wm8750_mono_mixer_controls[] = { | ||
290 | SOC_DAPM_SINGLE("Left Playback Switch", WM8750_MOUTM1, 8, 1, 0), | ||
291 | SOC_DAPM_SINGLE("Left Bypass Switch", WM8750_MOUTM1, 7, 1, 0), | ||
292 | SOC_DAPM_SINGLE("Right Playback Switch", WM8750_MOUTM2, 8, 1, 0), | ||
293 | SOC_DAPM_SINGLE("Right Bypass Switch", WM8750_MOUTM2, 7, 1, 0), | ||
294 | }; | ||
295 | |||
296 | /* Left Line Mux */ | ||
297 | static const struct snd_kcontrol_new wm8750_left_line_controls = | ||
298 | SOC_DAPM_ENUM("Route", wm8750_enum[8]); | ||
299 | |||
300 | /* Right Line Mux */ | ||
301 | static const struct snd_kcontrol_new wm8750_right_line_controls = | ||
302 | SOC_DAPM_ENUM("Route", wm8750_enum[9]); | ||
303 | |||
304 | /* Left PGA Mux */ | ||
305 | static const struct snd_kcontrol_new wm8750_left_pga_controls = | ||
306 | SOC_DAPM_ENUM("Route", wm8750_enum[10]); | ||
307 | |||
308 | /* Right PGA Mux */ | ||
309 | static const struct snd_kcontrol_new wm8750_right_pga_controls = | ||
310 | SOC_DAPM_ENUM("Route", wm8750_enum[11]); | ||
311 | |||
312 | /* Out 3 Mux */ | ||
313 | static const struct snd_kcontrol_new wm8750_out3_controls = | ||
314 | SOC_DAPM_ENUM("Route", wm8750_enum[12]); | ||
315 | |||
316 | /* Differential Mux */ | ||
317 | static const struct snd_kcontrol_new wm8750_diffmux_controls = | ||
318 | SOC_DAPM_ENUM("Route", wm8750_enum[13]); | ||
319 | |||
320 | /* Mono ADC Mux */ | ||
321 | static const struct snd_kcontrol_new wm8750_monomux_controls = | ||
322 | SOC_DAPM_ENUM("Route", wm8750_enum[16]); | ||
323 | |||
324 | static const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = { | ||
325 | SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0, | ||
326 | &wm8750_left_mixer_controls[0], | ||
327 | ARRAY_SIZE(wm8750_left_mixer_controls)), | ||
328 | SND_SOC_DAPM_MIXER("Right Mixer", SND_SOC_NOPM, 0, 0, | ||
329 | &wm8750_right_mixer_controls[0], | ||
330 | ARRAY_SIZE(wm8750_right_mixer_controls)), | ||
331 | SND_SOC_DAPM_MIXER("Mono Mixer", WM8750_PWR2, 2, 0, | ||
332 | &wm8750_mono_mixer_controls[0], | ||
333 | ARRAY_SIZE(wm8750_mono_mixer_controls)), | ||
334 | |||
335 | SND_SOC_DAPM_PGA("Right Out 2", WM8750_PWR2, 3, 0, NULL, 0), | ||
336 | SND_SOC_DAPM_PGA("Left Out 2", WM8750_PWR2, 4, 0, NULL, 0), | ||
337 | SND_SOC_DAPM_PGA("Right Out 1", WM8750_PWR2, 5, 0, NULL, 0), | ||
338 | SND_SOC_DAPM_PGA("Left Out 1", WM8750_PWR2, 6, 0, NULL, 0), | ||
339 | SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8750_PWR2, 7, 0), | ||
340 | SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8750_PWR2, 8, 0), | ||
341 | |||
342 | SND_SOC_DAPM_MICBIAS("Mic Bias", WM8750_PWR1, 1, 0), | ||
343 | SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8750_PWR1, 2, 0), | ||
344 | SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8750_PWR1, 3, 0), | ||
345 | |||
346 | SND_SOC_DAPM_MUX("Left PGA Mux", WM8750_PWR1, 5, 0, | ||
347 | &wm8750_left_pga_controls), | ||
348 | SND_SOC_DAPM_MUX("Right PGA Mux", WM8750_PWR1, 4, 0, | ||
349 | &wm8750_right_pga_controls), | ||
350 | SND_SOC_DAPM_MUX("Left Line Mux", SND_SOC_NOPM, 0, 0, | ||
351 | &wm8750_left_line_controls), | ||
352 | SND_SOC_DAPM_MUX("Right Line Mux", SND_SOC_NOPM, 0, 0, | ||
353 | &wm8750_right_line_controls), | ||
354 | |||
355 | SND_SOC_DAPM_MUX("Out3 Mux", SND_SOC_NOPM, 0, 0, &wm8750_out3_controls), | ||
356 | SND_SOC_DAPM_PGA("Out 3", WM8750_PWR2, 1, 0, NULL, 0), | ||
357 | SND_SOC_DAPM_PGA("Mono Out 1", WM8750_PWR2, 2, 0, NULL, 0), | ||
358 | |||
359 | SND_SOC_DAPM_MUX("Differential Mux", SND_SOC_NOPM, 0, 0, | ||
360 | &wm8750_diffmux_controls), | ||
361 | SND_SOC_DAPM_MUX("Left ADC Mux", SND_SOC_NOPM, 0, 0, | ||
362 | &wm8750_monomux_controls), | ||
363 | SND_SOC_DAPM_MUX("Right ADC Mux", SND_SOC_NOPM, 0, 0, | ||
364 | &wm8750_monomux_controls), | ||
365 | |||
366 | SND_SOC_DAPM_OUTPUT("LOUT1"), | ||
367 | SND_SOC_DAPM_OUTPUT("ROUT1"), | ||
368 | SND_SOC_DAPM_OUTPUT("LOUT2"), | ||
369 | SND_SOC_DAPM_OUTPUT("ROUT2"), | ||
370 | SND_SOC_DAPM_OUTPUT("MONO"), | ||
371 | SND_SOC_DAPM_OUTPUT("OUT3"), | ||
372 | |||
373 | SND_SOC_DAPM_INPUT("LINPUT1"), | ||
374 | SND_SOC_DAPM_INPUT("LINPUT2"), | ||
375 | SND_SOC_DAPM_INPUT("LINPUT3"), | ||
376 | SND_SOC_DAPM_INPUT("RINPUT1"), | ||
377 | SND_SOC_DAPM_INPUT("RINPUT2"), | ||
378 | SND_SOC_DAPM_INPUT("RINPUT3"), | ||
379 | }; | ||
380 | |||
381 | static const char *audio_map[][3] = { | ||
382 | /* left mixer */ | ||
383 | {"Left Mixer", "Playback Switch", "Left DAC"}, | ||
384 | {"Left Mixer", "Left Bypass Switch", "Left Line Mux"}, | ||
385 | {"Left Mixer", "Right Playback Switch", "Right DAC"}, | ||
386 | {"Left Mixer", "Right Bypass Switch", "Right Line Mux"}, | ||
387 | |||
388 | /* right mixer */ | ||
389 | {"Right Mixer", "Left Playback Switch", "Left DAC"}, | ||
390 | {"Right Mixer", "Left Bypass Switch", "Left Line Mux"}, | ||
391 | {"Right Mixer", "Playback Switch", "Right DAC"}, | ||
392 | {"Right Mixer", "Right Bypass Switch", "Right Line Mux"}, | ||
393 | |||
394 | /* left out 1 */ | ||
395 | {"Left Out 1", NULL, "Left Mixer"}, | ||
396 | {"LOUT1", NULL, "Left Out 1"}, | ||
397 | |||
398 | /* left out 2 */ | ||
399 | {"Left Out 2", NULL, "Left Mixer"}, | ||
400 | {"LOUT2", NULL, "Left Out 2"}, | ||
401 | |||
402 | /* right out 1 */ | ||
403 | {"Right Out 1", NULL, "Right Mixer"}, | ||
404 | {"ROUT1", NULL, "Right Out 1"}, | ||
405 | |||
406 | /* right out 2 */ | ||
407 | {"Right Out 2", NULL, "Right Mixer"}, | ||
408 | {"ROUT2", NULL, "Right Out 2"}, | ||
409 | |||
410 | /* mono mixer */ | ||
411 | {"Mono Mixer", "Left Playback Switch", "Left DAC"}, | ||
412 | {"Mono Mixer", "Left Bypass Switch", "Left Line Mux"}, | ||
413 | {"Mono Mixer", "Right Playback Switch", "Right DAC"}, | ||
414 | {"Mono Mixer", "Right Bypass Switch", "Right Line Mux"}, | ||
415 | |||
416 | /* mono out */ | ||
417 | {"Mono Out 1", NULL, "Mono Mixer"}, | ||
418 | {"MONO1", NULL, "Mono Out 1"}, | ||
419 | |||
420 | /* out 3 */ | ||
421 | {"Out3 Mux", "VREF", "VREF"}, | ||
422 | {"Out3 Mux", "ROUT1 + Vol", "ROUT1"}, | ||
423 | {"Out3 Mux", "ROUT1", "Right Mixer"}, | ||
424 | {"Out3 Mux", "MonoOut", "MONO1"}, | ||
425 | {"Out 3", NULL, "Out3 Mux"}, | ||
426 | {"OUT3", NULL, "Out 3"}, | ||
427 | |||
428 | /* Left Line Mux */ | ||
429 | {"Left Line Mux", "Line 1", "LINPUT1"}, | ||
430 | {"Left Line Mux", "Line 2", "LINPUT2"}, | ||
431 | {"Left Line Mux", "Line 3", "LINPUT3"}, | ||
432 | {"Left Line Mux", "PGA", "Left PGA Mux"}, | ||
433 | {"Left Line Mux", "Differential", "Differential Mux"}, | ||
434 | |||
435 | /* Right Line Mux */ | ||
436 | {"Right Line Mux", "Line 1", "RINPUT1"}, | ||
437 | {"Right Line Mux", "Line 2", "RINPUT2"}, | ||
438 | {"Right Line Mux", "Line 3", "RINPUT3"}, | ||
439 | {"Right Line Mux", "PGA", "Right PGA Mux"}, | ||
440 | {"Right Line Mux", "Differential", "Differential Mux"}, | ||
441 | |||
442 | /* Left PGA Mux */ | ||
443 | {"Left PGA Mux", "Line 1", "LINPUT1"}, | ||
444 | {"Left PGA Mux", "Line 2", "LINPUT2"}, | ||
445 | {"Left PGA Mux", "Line 3", "LINPUT3"}, | ||
446 | {"Left PGA Mux", "Differential", "Differential Mux"}, | ||
447 | |||
448 | /* Right PGA Mux */ | ||
449 | {"Right PGA Mux", "Line 1", "RINPUT1"}, | ||
450 | {"Right PGA Mux", "Line 2", "RINPUT2"}, | ||
451 | {"Right PGA Mux", "Line 3", "RINPUT3"}, | ||
452 | {"Right PGA Mux", "Differential", "Differential Mux"}, | ||
453 | |||
454 | /* Differential Mux */ | ||
455 | {"Differential Mux", "Line 1", "LINPUT1"}, | ||
456 | {"Differential Mux", "Line 1", "RINPUT1"}, | ||
457 | {"Differential Mux", "Line 2", "LINPUT2"}, | ||
458 | {"Differential Mux", "Line 2", "RINPUT2"}, | ||
459 | |||
460 | /* Left ADC Mux */ | ||
461 | {"Left ADC Mux", "Stereo", "Left PGA Mux"}, | ||
462 | {"Left ADC Mux", "Mono (Left)", "Left PGA Mux"}, | ||
463 | {"Left ADC Mux", "Digital Mono", "Left PGA Mux"}, | ||
464 | |||
465 | /* Right ADC Mux */ | ||
466 | {"Right ADC Mux", "Stereo", "Right PGA Mux"}, | ||
467 | {"Right ADC Mux", "Mono (Right)", "Right PGA Mux"}, | ||
468 | {"Right ADC Mux", "Digital Mono", "Right PGA Mux"}, | ||
469 | |||
470 | /* ADC */ | ||
471 | {"Left ADC", NULL, "Left ADC Mux"}, | ||
472 | {"Right ADC", NULL, "Right ADC Mux"}, | ||
473 | |||
474 | /* terminator */ | ||
475 | {NULL, NULL, NULL}, | ||
476 | }; | ||
477 | |||
478 | static int wm8750_add_widgets(struct snd_soc_codec *codec) | ||
479 | { | ||
480 | int i; | ||
481 | |||
482 | for(i = 0; i < ARRAY_SIZE(wm8750_dapm_widgets); i++) { | ||
483 | snd_soc_dapm_new_control(codec, &wm8750_dapm_widgets[i]); | ||
484 | } | ||
485 | |||
486 | /* set up audio path audio_mapnects */ | ||
487 | for(i = 0; audio_map[i][0] != NULL; i++) { | ||
488 | snd_soc_dapm_connect_input(codec, audio_map[i][0], | ||
489 | audio_map[i][1], audio_map[i][2]); | ||
490 | } | ||
491 | |||
492 | snd_soc_dapm_new_widgets(codec); | ||
493 | return 0; | ||
494 | } | ||
495 | |||
496 | struct _coeff_div { | ||
497 | u32 mclk; | ||
498 | u32 rate; | ||
499 | u16 fs; | ||
500 | u8 sr:5; | ||
501 | u8 usb:1; | ||
502 | }; | ||
503 | |||
504 | /* codec hifi mclk clock divider coefficients */ | ||
505 | static const struct _coeff_div coeff_div[] = { | ||
506 | /* 8k */ | ||
507 | {12288000, 8000, 1536, 0x6, 0x0}, | ||
508 | {11289600, 8000, 1408, 0x16, 0x0}, | ||
509 | {18432000, 8000, 2304, 0x7, 0x0}, | ||
510 | {16934400, 8000, 2112, 0x17, 0x0}, | ||
511 | {12000000, 8000, 1500, 0x6, 0x1}, | ||
512 | |||
513 | /* 11.025k */ | ||
514 | {11289600, 11025, 1024, 0x18, 0x0}, | ||
515 | {16934400, 11025, 1536, 0x19, 0x0}, | ||
516 | {12000000, 11025, 1088, 0x19, 0x1}, | ||
517 | |||
518 | /* 16k */ | ||
519 | {12288000, 16000, 768, 0xa, 0x0}, | ||
520 | {18432000, 16000, 1152, 0xb, 0x0}, | ||
521 | {12000000, 16000, 750, 0xa, 0x1}, | ||
522 | |||
523 | /* 22.05k */ | ||
524 | {11289600, 22050, 512, 0x1a, 0x0}, | ||
525 | {16934400, 22050, 768, 0x1b, 0x0}, | ||
526 | {12000000, 22050, 544, 0x1b, 0x1}, | ||
527 | |||
528 | /* 32k */ | ||
529 | {12288000, 32000, 384, 0xc, 0x0}, | ||
530 | {18432000, 32000, 576, 0xd, 0x0}, | ||
531 | {12000000, 32000, 375, 0xa, 0x1}, | ||
532 | |||
533 | /* 44.1k */ | ||
534 | {11289600, 44100, 256, 0x10, 0x0}, | ||
535 | {16934400, 44100, 384, 0x11, 0x0}, | ||
536 | {12000000, 44100, 272, 0x11, 0x1}, | ||
537 | |||
538 | /* 48k */ | ||
539 | {12288000, 48000, 256, 0x0, 0x0}, | ||
540 | {18432000, 48000, 384, 0x1, 0x0}, | ||
541 | {12000000, 48000, 250, 0x0, 0x1}, | ||
542 | |||
543 | /* 88.2k */ | ||
544 | {11289600, 88200, 128, 0x1e, 0x0}, | ||
545 | {16934400, 88200, 192, 0x1f, 0x0}, | ||
546 | {12000000, 88200, 136, 0x1f, 0x1}, | ||
547 | |||
548 | /* 96k */ | ||
549 | {12288000, 96000, 128, 0xe, 0x0}, | ||
550 | {18432000, 96000, 192, 0xf, 0x0}, | ||
551 | {12000000, 96000, 125, 0xe, 0x1}, | ||
552 | }; | ||
553 | |||
554 | static inline int get_coeff(int mclk, int rate) | ||
555 | { | ||
556 | int i; | ||
557 | |||
558 | for (i = 0; i < ARRAY_SIZE(coeff_div); i++) { | ||
559 | if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk) | ||
560 | return i; | ||
561 | } | ||
562 | |||
563 | printk(KERN_ERR "wm8750: could not get coeff for mclk %d @ rate %d\n", | ||
564 | mclk, rate); | ||
565 | return -EINVAL; | ||
566 | } | ||
567 | |||
568 | static int wm8750_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai, | ||
569 | int clk_id, unsigned int freq, int dir) | ||
570 | { | ||
571 | struct snd_soc_codec *codec = codec_dai->codec; | ||
572 | struct wm8750_priv *wm8750 = codec->private_data; | ||
573 | |||
574 | switch (freq) { | ||
575 | case 11289600: | ||
576 | case 12000000: | ||
577 | case 12288000: | ||
578 | case 16934400: | ||
579 | case 18432000: | ||
580 | wm8750->sysclk = freq; | ||
581 | return 0; | ||
582 | } | ||
583 | return -EINVAL; | ||
584 | } | ||
585 | |||
586 | static int wm8750_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | ||
587 | unsigned int fmt) | ||
588 | { | ||
589 | struct snd_soc_codec *codec = codec_dai->codec; | ||
590 | u16 iface = 0; | ||
591 | |||
592 | /* set master/slave audio interface */ | ||
593 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
594 | case SND_SOC_DAIFMT_CBM_CFM: | ||
595 | iface = 0x0040; | ||
596 | break; | ||
597 | case SND_SOC_DAIFMT_CBS_CFS: | ||
598 | break; | ||
599 | default: | ||
600 | return -EINVAL; | ||
601 | } | ||
602 | |||
603 | /* interface format */ | ||
604 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
605 | case SND_SOC_DAIFMT_I2S: | ||
606 | iface |= 0x0002; | ||
607 | break; | ||
608 | case SND_SOC_DAIFMT_RIGHT_J: | ||
609 | break; | ||
610 | case SND_SOC_DAIFMT_LEFT_J: | ||
611 | iface |= 0x0001; | ||
612 | break; | ||
613 | case SND_SOC_DAIFMT_DSP_A: | ||
614 | iface |= 0x0003; | ||
615 | break; | ||
616 | case SND_SOC_DAIFMT_DSP_B: | ||
617 | iface |= 0x0013; | ||
618 | break; | ||
619 | default: | ||
620 | return -EINVAL; | ||
621 | } | ||
622 | |||
623 | /* clock inversion */ | ||
624 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
625 | case SND_SOC_DAIFMT_NB_NF: | ||
626 | break; | ||
627 | case SND_SOC_DAIFMT_IB_IF: | ||
628 | iface |= 0x0090; | ||
629 | break; | ||
630 | case SND_SOC_DAIFMT_IB_NF: | ||
631 | iface |= 0x0080; | ||
632 | break; | ||
633 | case SND_SOC_DAIFMT_NB_IF: | ||
634 | iface |= 0x0010; | ||
635 | break; | ||
636 | default: | ||
637 | return -EINVAL; | ||
638 | } | ||
639 | |||
640 | wm8750_write(codec, WM8750_IFACE, iface); | ||
641 | return 0; | ||
642 | } | ||
643 | |||
644 | static int wm8750_pcm_hw_params(struct snd_pcm_substream *substream, | ||
645 | struct snd_pcm_hw_params *params) | ||
646 | { | ||
647 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
648 | struct snd_soc_device *socdev = rtd->socdev; | ||
649 | struct snd_soc_codec *codec = socdev->codec; | ||
650 | struct wm8750_priv *wm8750 = codec->private_data; | ||
651 | u16 iface = wm8750_read_reg_cache(codec, WM8750_IFACE) & 0x1f3; | ||
652 | u16 srate = wm8750_read_reg_cache(codec, WM8750_SRATE) & 0x1c0; | ||
653 | int coeff = get_coeff(wm8750->sysclk, params_rate(params)); | ||
654 | |||
655 | /* bit size */ | ||
656 | switch (params_format(params)) { | ||
657 | case SNDRV_PCM_FORMAT_S16_LE: | ||
658 | break; | ||
659 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
660 | iface |= 0x0004; | ||
661 | break; | ||
662 | case SNDRV_PCM_FORMAT_S24_LE: | ||
663 | iface |= 0x0008; | ||
664 | break; | ||
665 | case SNDRV_PCM_FORMAT_S32_LE: | ||
666 | iface |= 0x000c; | ||
667 | break; | ||
668 | } | ||
669 | |||
670 | /* set iface & srate */ | ||
671 | wm8750_write(codec, WM8750_IFACE, iface); | ||
672 | if (coeff >= 0) | ||
673 | wm8750_write(codec, WM8750_SRATE, srate | | ||
674 | (coeff_div[coeff].sr << 1) | coeff_div[coeff].usb); | ||
675 | |||
676 | return 0; | ||
677 | } | ||
678 | |||
679 | static int wm8750_mute(struct snd_soc_codec_dai *dai, int mute) | ||
680 | { | ||
681 | struct snd_soc_codec *codec = dai->codec; | ||
682 | u16 mute_reg = wm8750_read_reg_cache(codec, WM8750_ADCDAC) & 0xfff7; | ||
683 | |||
684 | if (mute) | ||
685 | wm8750_write(codec, WM8750_ADCDAC, mute_reg | 0x8); | ||
686 | else | ||
687 | wm8750_write(codec, WM8750_ADCDAC, mute_reg); | ||
688 | return 0; | ||
689 | } | ||
690 | |||
691 | static int wm8750_dapm_event(struct snd_soc_codec *codec, int event) | ||
692 | { | ||
693 | u16 pwr_reg = wm8750_read_reg_cache(codec, WM8750_PWR1) & 0xfe3e; | ||
694 | |||
695 | switch (event) { | ||
696 | case SNDRV_CTL_POWER_D0: /* full On */ | ||
697 | /* set vmid to 50k and unmute dac */ | ||
698 | wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x00c0); | ||
699 | break; | ||
700 | case SNDRV_CTL_POWER_D1: /* partial On */ | ||
701 | case SNDRV_CTL_POWER_D2: /* partial On */ | ||
702 | /* set vmid to 5k for quick power up */ | ||
703 | wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x01c1); | ||
704 | break; | ||
705 | case SNDRV_CTL_POWER_D3hot: /* Off, with power */ | ||
706 | /* mute dac and set vmid to 500k, enable VREF */ | ||
707 | wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x0141); | ||
708 | break; | ||
709 | case SNDRV_CTL_POWER_D3cold: /* Off, without power */ | ||
710 | wm8750_write(codec, WM8750_PWR1, 0x0001); | ||
711 | break; | ||
712 | } | ||
713 | codec->dapm_state = event; | ||
714 | return 0; | ||
715 | } | ||
716 | |||
717 | #define WM8750_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ | ||
718 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \ | ||
719 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) | ||
720 | |||
721 | #define WM8750_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | ||
722 | SNDRV_PCM_FMTBIT_S24_LE) | ||
723 | |||
724 | struct snd_soc_codec_dai wm8750_dai = { | ||
725 | .name = "WM8750", | ||
726 | .playback = { | ||
727 | .stream_name = "Playback", | ||
728 | .channels_min = 1, | ||
729 | .channels_max = 2, | ||
730 | .rates = WM8750_RATES, | ||
731 | .formats = WM8750_FORMATS,}, | ||
732 | .capture = { | ||
733 | .stream_name = "Capture", | ||
734 | .channels_min = 1, | ||
735 | .channels_max = 2, | ||
736 | .rates = WM8750_RATES, | ||
737 | .formats = WM8750_FORMATS,}, | ||
738 | .ops = { | ||
739 | .hw_params = wm8750_pcm_hw_params, | ||
740 | }, | ||
741 | .dai_ops = { | ||
742 | .digital_mute = wm8750_mute, | ||
743 | .set_fmt = wm8750_set_dai_fmt, | ||
744 | .set_sysclk = wm8750_set_dai_sysclk, | ||
745 | }, | ||
746 | }; | ||
747 | EXPORT_SYMBOL_GPL(wm8750_dai); | ||
748 | |||
749 | static void wm8750_work(struct work_struct *work) | ||
750 | { | ||
751 | struct snd_soc_codec *codec = | ||
752 | container_of(work, struct snd_soc_codec, delayed_work.work); | ||
753 | wm8750_dapm_event(codec, codec->dapm_state); | ||
754 | } | ||
755 | |||
756 | static int wm8750_suspend(struct platform_device *pdev, pm_message_t state) | ||
757 | { | ||
758 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
759 | struct snd_soc_codec *codec = socdev->codec; | ||
760 | |||
761 | wm8750_dapm_event(codec, SNDRV_CTL_POWER_D3cold); | ||
762 | return 0; | ||
763 | } | ||
764 | |||
765 | static int wm8750_resume(struct platform_device *pdev) | ||
766 | { | ||
767 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
768 | struct snd_soc_codec *codec = socdev->codec; | ||
769 | int i; | ||
770 | u8 data[2]; | ||
771 | u16 *cache = codec->reg_cache; | ||
772 | |||
773 | /* Sync reg_cache with the hardware */ | ||
774 | for (i = 0; i < ARRAY_SIZE(wm8750_reg); i++) { | ||
775 | if (i == WM8750_RESET) | ||
776 | continue; | ||
777 | data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001); | ||
778 | data[1] = cache[i] & 0x00ff; | ||
779 | codec->hw_write(codec->control_data, data, 2); | ||
780 | } | ||
781 | |||
782 | wm8750_dapm_event(codec, SNDRV_CTL_POWER_D3hot); | ||
783 | |||
784 | /* charge wm8750 caps */ | ||
785 | if (codec->suspend_dapm_state == SNDRV_CTL_POWER_D0) { | ||
786 | wm8750_dapm_event(codec, SNDRV_CTL_POWER_D2); | ||
787 | codec->dapm_state = SNDRV_CTL_POWER_D0; | ||
788 | schedule_delayed_work(&codec->delayed_work, msecs_to_jiffies(1000)); | ||
789 | } | ||
790 | |||
791 | return 0; | ||
792 | } | ||
793 | |||
794 | /* | ||
795 | * initialise the WM8750 driver | ||
796 | * register the mixer and dsp interfaces with the kernel | ||
797 | */ | ||
798 | static int wm8750_init(struct snd_soc_device *socdev) | ||
799 | { | ||
800 | struct snd_soc_codec *codec = socdev->codec; | ||
801 | int reg, ret = 0; | ||
802 | |||
803 | codec->name = "WM8750"; | ||
804 | codec->owner = THIS_MODULE; | ||
805 | codec->read = wm8750_read_reg_cache; | ||
806 | codec->write = wm8750_write; | ||
807 | codec->dapm_event = wm8750_dapm_event; | ||
808 | codec->dai = &wm8750_dai; | ||
809 | codec->num_dai = 1; | ||
810 | codec->reg_cache_size = sizeof(wm8750_reg); | ||
811 | codec->reg_cache = kmemdup(wm8750_reg, sizeof(wm8750_reg), GFP_KRENEL); | ||
812 | if (codec->reg_cache == NULL) | ||
813 | return -ENOMEM; | ||
814 | |||
815 | wm8750_reset(codec); | ||
816 | |||
817 | /* register pcms */ | ||
818 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
819 | if (ret < 0) { | ||
820 | printk(KERN_ERR "wm8750: failed to create pcms\n"); | ||
821 | goto pcm_err; | ||
822 | } | ||
823 | |||
824 | /* charge output caps */ | ||
825 | wm8750_dapm_event(codec, SNDRV_CTL_POWER_D2); | ||
826 | codec->dapm_state = SNDRV_CTL_POWER_D3hot; | ||
827 | schedule_delayed_work(&codec->delayed_work, msecs_to_jiffies(1000)); | ||
828 | |||
829 | /* set the update bits */ | ||
830 | reg = wm8750_read_reg_cache(codec, WM8750_LDAC); | ||
831 | wm8750_write(codec, WM8750_LDAC, reg | 0x0100); | ||
832 | reg = wm8750_read_reg_cache(codec, WM8750_RDAC); | ||
833 | wm8750_write(codec, WM8750_RDAC, reg | 0x0100); | ||
834 | reg = wm8750_read_reg_cache(codec, WM8750_LOUT1V); | ||
835 | wm8750_write(codec, WM8750_LOUT1V, reg | 0x0100); | ||
836 | reg = wm8750_read_reg_cache(codec, WM8750_ROUT1V); | ||
837 | wm8750_write(codec, WM8750_ROUT1V, reg | 0x0100); | ||
838 | reg = wm8750_read_reg_cache(codec, WM8750_LOUT2V); | ||
839 | wm8750_write(codec, WM8750_LOUT2V, reg | 0x0100); | ||
840 | reg = wm8750_read_reg_cache(codec, WM8750_ROUT2V); | ||
841 | wm8750_write(codec, WM8750_ROUT2V, reg | 0x0100); | ||
842 | reg = wm8750_read_reg_cache(codec, WM8750_LINVOL); | ||
843 | wm8750_write(codec, WM8750_LINVOL, reg | 0x0100); | ||
844 | reg = wm8750_read_reg_cache(codec, WM8750_RINVOL); | ||
845 | wm8750_write(codec, WM8750_RINVOL, reg | 0x0100); | ||
846 | |||
847 | wm8750_add_controls(codec); | ||
848 | wm8750_add_widgets(codec); | ||
849 | ret = snd_soc_register_card(socdev); | ||
850 | if (ret < 0) { | ||
851 | printk(KERN_ERR "wm8750: failed to register card\n"); | ||
852 | goto card_err; | ||
853 | } | ||
854 | return ret; | ||
855 | |||
856 | card_err: | ||
857 | snd_soc_free_pcms(socdev); | ||
858 | snd_soc_dapm_free(socdev); | ||
859 | pcm_err: | ||
860 | kfree(codec->reg_cache); | ||
861 | return ret; | ||
862 | } | ||
863 | |||
864 | /* If the i2c layer weren't so broken, we could pass this kind of data | ||
865 | around */ | ||
866 | static struct snd_soc_device *wm8750_socdev; | ||
867 | |||
868 | #if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE) | ||
869 | |||
870 | /* | ||
871 | * WM8731 2 wire address is determined by GPIO5 | ||
872 | * state during powerup. | ||
873 | * low = 0x1a | ||
874 | * high = 0x1b | ||
875 | */ | ||
876 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; | ||
877 | |||
878 | /* Magic definition of all other variables and things */ | ||
879 | I2C_CLIENT_INSMOD; | ||
880 | |||
881 | static struct i2c_driver wm8750_i2c_driver; | ||
882 | static struct i2c_client client_template; | ||
883 | |||
884 | static int wm8750_codec_probe(struct i2c_adapter *adap, int addr, int kind) | ||
885 | { | ||
886 | struct snd_soc_device *socdev = wm8750_socdev; | ||
887 | struct wm8750_setup_data *setup = socdev->codec_data; | ||
888 | struct snd_soc_codec *codec = socdev->codec; | ||
889 | struct i2c_client *i2c; | ||
890 | int ret; | ||
891 | |||
892 | if (addr != setup->i2c_address) | ||
893 | return -ENODEV; | ||
894 | |||
895 | client_template.adapter = adap; | ||
896 | client_template.addr = addr; | ||
897 | |||
898 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | ||
899 | if (i2c == NULL) { | ||
900 | kfree(codec); | ||
901 | return -ENOMEM; | ||
902 | } | ||
903 | i2c_set_clientdata(i2c, codec); | ||
904 | codec->control_data = i2c; | ||
905 | |||
906 | ret = i2c_attach_client(i2c); | ||
907 | if (ret < 0) { | ||
908 | err("failed to attach codec at addr %x\n", addr); | ||
909 | goto err; | ||
910 | } | ||
911 | |||
912 | ret = wm8750_init(socdev); | ||
913 | if (ret < 0) { | ||
914 | err("failed to initialise WM8750\n"); | ||
915 | goto err; | ||
916 | } | ||
917 | return ret; | ||
918 | |||
919 | err: | ||
920 | kfree(codec); | ||
921 | kfree(i2c); | ||
922 | return ret; | ||
923 | } | ||
924 | |||
925 | static int wm8750_i2c_detach(struct i2c_client *client) | ||
926 | { | ||
927 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | ||
928 | i2c_detach_client(client); | ||
929 | kfree(codec->reg_cache); | ||
930 | kfree(client); | ||
931 | return 0; | ||
932 | } | ||
933 | |||
934 | static int wm8750_i2c_attach(struct i2c_adapter *adap) | ||
935 | { | ||
936 | return i2c_probe(adap, &addr_data, wm8750_codec_probe); | ||
937 | } | ||
938 | |||
939 | /* corgi i2c codec control layer */ | ||
940 | static struct i2c_driver wm8750_i2c_driver = { | ||
941 | .driver = { | ||
942 | .name = "WM8750 I2C Codec", | ||
943 | .owner = THIS_MODULE, | ||
944 | }, | ||
945 | .id = I2C_DRIVERID_WM8750, | ||
946 | .attach_adapter = wm8750_i2c_attach, | ||
947 | .detach_client = wm8750_i2c_detach, | ||
948 | .command = NULL, | ||
949 | }; | ||
950 | |||
951 | static struct i2c_client client_template = { | ||
952 | .name = "WM8750", | ||
953 | .driver = &wm8750_i2c_driver, | ||
954 | }; | ||
955 | #endif | ||
956 | |||
957 | static int wm8750_probe(struct platform_device *pdev) | ||
958 | { | ||
959 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
960 | struct wm8750_setup_data *setup = socdev->codec_data; | ||
961 | struct snd_soc_codec *codec; | ||
962 | struct wm8750_priv *wm8750; | ||
963 | int ret = 0; | ||
964 | |||
965 | info("WM8750 Audio Codec %s", WM8750_VERSION); | ||
966 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | ||
967 | if (codec == NULL) | ||
968 | return -ENOMEM; | ||
969 | |||
970 | wm8750 = kzalloc(sizeof(struct wm8750_priv), GFP_KERNEL); | ||
971 | if (wm8750 == NULL) { | ||
972 | kfree(codec); | ||
973 | return -ENOMEM; | ||
974 | } | ||
975 | |||
976 | codec->private_data = wm8750; | ||
977 | socdev->codec = codec; | ||
978 | mutex_init(&codec->mutex); | ||
979 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
980 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
981 | wm8750_socdev = socdev; | ||
982 | INIT_DELAYED_WORK(&codec->delayed_work, wm8750_work); | ||
983 | |||
984 | #if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE) | ||
985 | if (setup->i2c_address) { | ||
986 | normal_i2c[0] = setup->i2c_address; | ||
987 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
988 | ret = i2c_add_driver(&wm8750_i2c_driver); | ||
989 | if (ret != 0) | ||
990 | printk(KERN_ERR "can't add i2c driver"); | ||
991 | } | ||
992 | #else | ||
993 | /* Add other interfaces here */ | ||
994 | #endif | ||
995 | |||
996 | return ret; | ||
997 | } | ||
998 | |||
999 | /* | ||
1000 | * This function forces any delayed work to be queued and run. | ||
1001 | */ | ||
1002 | static int run_delayed_work(struct delayed_work *dwork) | ||
1003 | { | ||
1004 | int ret; | ||
1005 | |||
1006 | /* cancel any work waiting to be queued. */ | ||
1007 | ret = cancel_delayed_work(dwork); | ||
1008 | |||
1009 | /* if there was any work waiting then we run it now and | ||
1010 | * wait for it's completion */ | ||
1011 | if (ret) { | ||
1012 | schedule_delayed_work(dwork, 0); | ||
1013 | flush_scheduled_work(); | ||
1014 | } | ||
1015 | return ret; | ||
1016 | } | ||
1017 | |||
1018 | /* power down chip */ | ||
1019 | static int wm8750_remove(struct platform_device *pdev) | ||
1020 | { | ||
1021 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1022 | struct snd_soc_codec *codec = socdev->codec; | ||
1023 | |||
1024 | if (codec->control_data) | ||
1025 | wm8750_dapm_event(codec, SNDRV_CTL_POWER_D3cold); | ||
1026 | run_delayed_work(&codec->delayed_work); | ||
1027 | snd_soc_free_pcms(socdev); | ||
1028 | snd_soc_dapm_free(socdev); | ||
1029 | #if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE) | ||
1030 | i2c_del_driver(&wm8750_i2c_driver); | ||
1031 | #endif | ||
1032 | kfree(codec->private_data); | ||
1033 | kfree(codec); | ||
1034 | |||
1035 | return 0; | ||
1036 | } | ||
1037 | |||
1038 | struct snd_soc_codec_device soc_codec_dev_wm8750 = { | ||
1039 | .probe = wm8750_probe, | ||
1040 | .remove = wm8750_remove, | ||
1041 | .suspend = wm8750_suspend, | ||
1042 | .resume = wm8750_resume, | ||
1043 | }; | ||
1044 | |||
1045 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8750); | ||
1046 | |||
1047 | MODULE_DESCRIPTION("ASoC WM8750 driver"); | ||
1048 | MODULE_AUTHOR("Liam Girdwood"); | ||
1049 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/wm8750.h b/sound/soc/codecs/wm8750.h new file mode 100644 index 000000000000..a97a54a6348e --- /dev/null +++ b/sound/soc/codecs/wm8750.h | |||
@@ -0,0 +1,67 @@ | |||
1 | /* | ||
2 | * Copyright 2005 Openedhand Ltd. | ||
3 | * | ||
4 | * Author: Richard Purdie <richard@openedhand.com> | ||
5 | * | ||
6 | * Based on WM8753.h | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #ifndef _WM8750_H | ||
15 | #define _WM8750_H | ||
16 | |||
17 | /* WM8750 register space */ | ||
18 | |||
19 | #define WM8750_LINVOL 0x00 | ||
20 | #define WM8750_RINVOL 0x01 | ||
21 | #define WM8750_LOUT1V 0x02 | ||
22 | #define WM8750_ROUT1V 0x03 | ||
23 | #define WM8750_ADCDAC 0x05 | ||
24 | #define WM8750_IFACE 0x07 | ||
25 | #define WM8750_SRATE 0x08 | ||
26 | #define WM8750_LDAC 0x0a | ||
27 | #define WM8750_RDAC 0x0b | ||
28 | #define WM8750_BASS 0x0c | ||
29 | #define WM8750_TREBLE 0x0d | ||
30 | #define WM8750_RESET 0x0f | ||
31 | #define WM8750_3D 0x10 | ||
32 | #define WM8750_ALC1 0x11 | ||
33 | #define WM8750_ALC2 0x12 | ||
34 | #define WM8750_ALC3 0x13 | ||
35 | #define WM8750_NGATE 0x14 | ||
36 | #define WM8750_LADC 0x15 | ||
37 | #define WM8750_RADC 0x16 | ||
38 | #define WM8750_ADCTL1 0x17 | ||
39 | #define WM8750_ADCTL2 0x18 | ||
40 | #define WM8750_PWR1 0x19 | ||
41 | #define WM8750_PWR2 0x1a | ||
42 | #define WM8750_ADCTL3 0x1b | ||
43 | #define WM8750_ADCIN 0x1f | ||
44 | #define WM8750_LADCIN 0x20 | ||
45 | #define WM8750_RADCIN 0x21 | ||
46 | #define WM8750_LOUTM1 0x22 | ||
47 | #define WM8750_LOUTM2 0x23 | ||
48 | #define WM8750_ROUTM1 0x24 | ||
49 | #define WM8750_ROUTM2 0x25 | ||
50 | #define WM8750_MOUTM1 0x26 | ||
51 | #define WM8750_MOUTM2 0x27 | ||
52 | #define WM8750_LOUT2V 0x28 | ||
53 | #define WM8750_ROUT2V 0x29 | ||
54 | #define WM8750_MOUTV 0x2a | ||
55 | |||
56 | #define WM8750_CACHE_REGNUM 0x2a | ||
57 | |||
58 | #define WM8750_SYSCLK 0 | ||
59 | |||
60 | struct wm8750_setup_data { | ||
61 | unsigned short i2c_address; | ||
62 | }; | ||
63 | |||
64 | extern struct snd_soc_codec_dai wm8750_dai; | ||
65 | extern struct snd_soc_codec_device soc_codec_dev_wm8750; | ||
66 | |||
67 | #endif | ||
diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c new file mode 100644 index 000000000000..92a64871bcd0 --- /dev/null +++ b/sound/soc/codecs/wm9712.c | |||
@@ -0,0 +1,771 @@ | |||
1 | /* | ||
2 | * wm9712.c -- ALSA Soc WM9712 codec support | ||
3 | * | ||
4 | * Copyright 2006 Wolfson Microelectronics PLC. | ||
5 | * Author: Liam Girdwood | ||
6 | * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | * | ||
13 | * Revision history | ||
14 | * 4th Feb 2006 Initial version. | ||
15 | */ | ||
16 | |||
17 | #include <linux/init.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/version.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/device.h> | ||
22 | #include <sound/driver.h> | ||
23 | #include <sound/core.h> | ||
24 | #include <sound/pcm.h> | ||
25 | #include <sound/ac97_codec.h> | ||
26 | #include <sound/initval.h> | ||
27 | #include <sound/soc.h> | ||
28 | #include <sound/soc-dapm.h> | ||
29 | |||
30 | #define WM9712_VERSION "0.4" | ||
31 | |||
32 | static unsigned int ac97_read(struct snd_soc_codec *codec, | ||
33 | unsigned int reg); | ||
34 | static int ac97_write(struct snd_soc_codec *codec, | ||
35 | unsigned int reg, unsigned int val); | ||
36 | |||
37 | /* | ||
38 | * WM9712 register cache | ||
39 | */ | ||
40 | static const u16 wm9712_reg[] = { | ||
41 | 0x6174, 0x8000, 0x8000, 0x8000, // 6 | ||
42 | 0xf0f0, 0xaaa0, 0xc008, 0x6808, // e | ||
43 | 0xe808, 0xaaa0, 0xad00, 0x8000, // 16 | ||
44 | 0xe808, 0x3000, 0x8000, 0x0000, // 1e | ||
45 | 0x0000, 0x0000, 0x0000, 0x000f, // 26 | ||
46 | 0x0405, 0x0410, 0xbb80, 0xbb80, // 2e | ||
47 | 0x0000, 0xbb80, 0x0000, 0x0000, // 36 | ||
48 | 0x0000, 0x2000, 0x0000, 0x0000, // 3e | ||
49 | 0x0000, 0x0000, 0x0000, 0x0000, // 46 | ||
50 | 0x0000, 0x0000, 0xf83e, 0xffff, // 4e | ||
51 | 0x0000, 0x0000, 0x0000, 0xf83e, // 56 | ||
52 | 0x0008, 0x0000, 0x0000, 0x0000, // 5e | ||
53 | 0xb032, 0x3e00, 0x0000, 0x0000, // 66 | ||
54 | 0x0000, 0x0000, 0x0000, 0x0000, // 6e | ||
55 | 0x0000, 0x0000, 0x0000, 0x0006, // 76 | ||
56 | 0x0001, 0x0000, 0x574d, 0x4c12, // 7e | ||
57 | 0x0000, 0x0000 // virtual hp mixers | ||
58 | }; | ||
59 | |||
60 | /* virtual HP mixers regs */ | ||
61 | #define HPL_MIXER 0x80 | ||
62 | #define HPR_MIXER 0x82 | ||
63 | |||
64 | static const char *wm9712_alc_select[] = {"None", "Left", "Right", "Stereo"}; | ||
65 | static const char *wm9712_alc_mux[] = {"Stereo", "Left", "Right", "None"}; | ||
66 | static const char *wm9712_out3_src[] = {"Left", "VREF", "Left + Right", | ||
67 | "Mono"}; | ||
68 | static const char *wm9712_spk_src[] = {"Speaker Mix", "Headphone Mix"}; | ||
69 | static const char *wm9712_rec_adc[] = {"Stereo", "Left", "Right", "Mute"}; | ||
70 | static const char *wm9712_base[] = {"Linear Control", "Adaptive Boost"}; | ||
71 | static const char *wm9712_rec_gain[] = {"+1.5dB Steps", "+0.75dB Steps"}; | ||
72 | static const char *wm9712_mic[] = {"Mic 1", "Differential", "Mic 2", | ||
73 | "Stereo"}; | ||
74 | static const char *wm9712_rec_sel[] = {"Mic", "NC", "NC", "Speaker Mixer", | ||
75 | "Line", "Headphone Mixer", "Phone Mixer", "Phone"}; | ||
76 | static const char *wm9712_ng_type[] = {"Constant Gain", "Mute"}; | ||
77 | static const char *wm9712_diff_sel[] = {"Mic", "Line"}; | ||
78 | |||
79 | static const struct soc_enum wm9712_enum[] = { | ||
80 | SOC_ENUM_SINGLE(AC97_PCI_SVID, 14, 4, wm9712_alc_select), | ||
81 | SOC_ENUM_SINGLE(AC97_VIDEO, 12, 4, wm9712_alc_mux), | ||
82 | SOC_ENUM_SINGLE(AC97_AUX, 9, 4, wm9712_out3_src), | ||
83 | SOC_ENUM_SINGLE(AC97_AUX, 8, 2, wm9712_spk_src), | ||
84 | SOC_ENUM_SINGLE(AC97_REC_SEL, 12, 4, wm9712_rec_adc), | ||
85 | SOC_ENUM_SINGLE(AC97_MASTER_TONE, 15, 2, wm9712_base), | ||
86 | SOC_ENUM_DOUBLE(AC97_REC_GAIN, 14, 6, 2, wm9712_rec_gain), | ||
87 | SOC_ENUM_SINGLE(AC97_MIC, 5, 4, wm9712_mic), | ||
88 | SOC_ENUM_SINGLE(AC97_REC_SEL, 8, 8, wm9712_rec_sel), | ||
89 | SOC_ENUM_SINGLE(AC97_REC_SEL, 0, 8, wm9712_rec_sel), | ||
90 | SOC_ENUM_SINGLE(AC97_PCI_SVID, 5, 2, wm9712_ng_type), | ||
91 | SOC_ENUM_SINGLE(0x5c, 8, 2, wm9712_diff_sel), | ||
92 | }; | ||
93 | |||
94 | static const struct snd_kcontrol_new wm9712_snd_ac97_controls[] = { | ||
95 | SOC_DOUBLE("Speaker Playback Volume", AC97_MASTER, 8, 0, 31, 1), | ||
96 | SOC_SINGLE("Speaker Playback Switch", AC97_MASTER, 15, 1, 1), | ||
97 | SOC_DOUBLE("Headphone Playback Volume", AC97_HEADPHONE, 8, 0, 31, 1), | ||
98 | SOC_SINGLE("Headphone Playback Switch", AC97_HEADPHONE,15, 1, 1), | ||
99 | |||
100 | SOC_SINGLE("Speaker Playback ZC Switch", AC97_MASTER, 7, 1, 0), | ||
101 | SOC_SINGLE("Speaker Playback Invert Switch", AC97_MASTER, 6, 1, 0), | ||
102 | SOC_SINGLE("Headphone Playback ZC Switch", AC97_HEADPHONE, 7, 1, 0), | ||
103 | SOC_SINGLE("Mono Playback ZC Switch", AC97_MASTER_MONO, 7, 1, 0), | ||
104 | SOC_SINGLE("Mono Playback Volume", AC97_MASTER_MONO, 0, 31, 0), | ||
105 | |||
106 | SOC_SINGLE("ALC Target Volume", AC97_CODEC_CLASS_REV, 12, 15, 0), | ||
107 | SOC_SINGLE("ALC Hold Time", AC97_CODEC_CLASS_REV, 8, 15, 0), | ||
108 | SOC_SINGLE("ALC Decay Time", AC97_CODEC_CLASS_REV, 4, 15, 0), | ||
109 | SOC_SINGLE("ALC Attack Time", AC97_CODEC_CLASS_REV, 0, 15, 0), | ||
110 | SOC_ENUM("ALC Function", wm9712_enum[0]), | ||
111 | SOC_SINGLE("ALC Max Volume", AC97_PCI_SVID, 11, 7, 0), | ||
112 | SOC_SINGLE("ALC ZC Timeout", AC97_PCI_SVID, 9, 3, 1), | ||
113 | SOC_SINGLE("ALC ZC Switch", AC97_PCI_SVID, 8, 1, 0), | ||
114 | SOC_SINGLE("ALC NG Switch", AC97_PCI_SVID, 7, 1, 0), | ||
115 | SOC_ENUM("ALC NG Type", wm9712_enum[10]), | ||
116 | SOC_SINGLE("ALC NG Threshold", AC97_PCI_SVID, 0, 31, 1), | ||
117 | |||
118 | SOC_SINGLE("Mic Headphone Volume", AC97_VIDEO, 12, 7, 1), | ||
119 | SOC_SINGLE("ALC Headphone Volume", AC97_VIDEO, 7, 7, 1), | ||
120 | |||
121 | SOC_SINGLE("Out3 Switch", AC97_AUX, 15, 1, 1), | ||
122 | SOC_SINGLE("Out3 ZC Switch", AC97_AUX, 7, 1, 1), | ||
123 | SOC_SINGLE("Out3 Volume", AC97_AUX, 0, 31, 1), | ||
124 | |||
125 | SOC_SINGLE("PCBeep Bypass Headphone Volume", AC97_PC_BEEP, 12, 7, 1), | ||
126 | SOC_SINGLE("PCBeep Bypass Speaker Volume", AC97_PC_BEEP, 8, 7, 1), | ||
127 | SOC_SINGLE("PCBeep Bypass Phone Volume", AC97_PC_BEEP, 4, 7, 1), | ||
128 | |||
129 | SOC_SINGLE("Aux Playback Headphone Volume", AC97_CD, 12, 7, 1), | ||
130 | SOC_SINGLE("Aux Playback Speaker Volume", AC97_CD, 8, 7, 1), | ||
131 | SOC_SINGLE("Aux Playback Phone Volume", AC97_CD, 4, 7, 1), | ||
132 | |||
133 | SOC_SINGLE("Phone Volume", AC97_PHONE, 0, 15, 0), | ||
134 | SOC_DOUBLE("Line Capture Volume", AC97_LINE, 8, 0, 31, 1), | ||
135 | |||
136 | SOC_SINGLE("Capture 20dB Boost Switch", AC97_REC_SEL, 14, 1, 0), | ||
137 | SOC_SINGLE("Capture to Phone 20dB Boost Switch", AC97_REC_SEL, 11, 1, 1), | ||
138 | |||
139 | SOC_SINGLE("3D Upper Cut-off Switch", AC97_3D_CONTROL, 5, 1, 1), | ||
140 | SOC_SINGLE("3D Lower Cut-off Switch", AC97_3D_CONTROL, 4, 1, 1), | ||
141 | SOC_SINGLE("3D Playback Volume", AC97_3D_CONTROL, 0, 15, 0), | ||
142 | |||
143 | SOC_ENUM("Bass Control", wm9712_enum[5]), | ||
144 | SOC_SINGLE("Bass Cut-off Switch", AC97_MASTER_TONE, 12, 1, 1), | ||
145 | SOC_SINGLE("Tone Cut-off Switch", AC97_MASTER_TONE, 4, 1, 1), | ||
146 | SOC_SINGLE("Playback Attenuate (-6dB) Switch", AC97_MASTER_TONE, 6, 1, 0), | ||
147 | SOC_SINGLE("Bass Volume", AC97_MASTER_TONE, 8, 15, 0), | ||
148 | SOC_SINGLE("Treble Volume", AC97_MASTER_TONE, 0, 15, 0), | ||
149 | |||
150 | SOC_SINGLE("Capture ADC Switch", AC97_REC_GAIN, 15, 1, 1), | ||
151 | SOC_ENUM("Capture Volume Steps", wm9712_enum[6]), | ||
152 | SOC_DOUBLE("Capture Volume", AC97_REC_GAIN, 8, 0, 63, 1), | ||
153 | SOC_SINGLE("Capture ZC Switch", AC97_REC_GAIN, 7, 1, 0), | ||
154 | |||
155 | SOC_SINGLE("Mic 1 Volume", AC97_MIC, 8, 31, 1), | ||
156 | SOC_SINGLE("Mic 2 Volume", AC97_MIC, 0, 31, 1), | ||
157 | SOC_SINGLE("Mic 20dB Boost Switch", AC97_MIC, 7, 1, 0), | ||
158 | }; | ||
159 | |||
160 | /* add non dapm controls */ | ||
161 | static int wm9712_add_controls(struct snd_soc_codec *codec) | ||
162 | { | ||
163 | int err, i; | ||
164 | |||
165 | for (i = 0; i < ARRAY_SIZE(wm9712_snd_ac97_controls); i++) { | ||
166 | err = snd_ctl_add(codec->card, | ||
167 | snd_soc_cnew(&wm9712_snd_ac97_controls[i],codec, NULL)); | ||
168 | if (err < 0) | ||
169 | return err; | ||
170 | } | ||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | /* We have to create a fake left and right HP mixers because | ||
175 | * the codec only has a single control that is shared by both channels. | ||
176 | * This makes it impossible to determine the audio path. | ||
177 | */ | ||
178 | static int mixer_event (struct snd_soc_dapm_widget *w, int event) | ||
179 | { | ||
180 | u16 l, r, beep, line, phone, mic, pcm, aux; | ||
181 | |||
182 | l = ac97_read(w->codec, HPL_MIXER); | ||
183 | r = ac97_read(w->codec, HPR_MIXER); | ||
184 | beep = ac97_read(w->codec, AC97_PC_BEEP); | ||
185 | mic = ac97_read(w->codec, AC97_VIDEO); | ||
186 | phone = ac97_read(w->codec, AC97_PHONE); | ||
187 | line = ac97_read(w->codec, AC97_LINE); | ||
188 | pcm = ac97_read(w->codec, AC97_PCM); | ||
189 | aux = ac97_read(w->codec, AC97_CD); | ||
190 | |||
191 | if (l & 0x1 || r & 0x1) | ||
192 | ac97_write(w->codec, AC97_VIDEO, mic & 0x7fff); | ||
193 | else | ||
194 | ac97_write(w->codec, AC97_VIDEO, mic | 0x8000); | ||
195 | |||
196 | if (l & 0x2 || r & 0x2) | ||
197 | ac97_write(w->codec, AC97_PCM, pcm & 0x7fff); | ||
198 | else | ||
199 | ac97_write(w->codec, AC97_PCM, pcm | 0x8000); | ||
200 | |||
201 | if (l & 0x4 || r & 0x4) | ||
202 | ac97_write(w->codec, AC97_LINE, line & 0x7fff); | ||
203 | else | ||
204 | ac97_write(w->codec, AC97_LINE, line | 0x8000); | ||
205 | |||
206 | if (l & 0x8 || r & 0x8) | ||
207 | ac97_write(w->codec, AC97_PHONE, phone & 0x7fff); | ||
208 | else | ||
209 | ac97_write(w->codec, AC97_PHONE, phone | 0x8000); | ||
210 | |||
211 | if (l & 0x10 || r & 0x10) | ||
212 | ac97_write(w->codec, AC97_CD, aux & 0x7fff); | ||
213 | else | ||
214 | ac97_write(w->codec, AC97_CD, aux | 0x8000); | ||
215 | |||
216 | if (l & 0x20 || r & 0x20) | ||
217 | ac97_write(w->codec, AC97_PC_BEEP, beep & 0x7fff); | ||
218 | else | ||
219 | ac97_write(w->codec, AC97_PC_BEEP, beep | 0x8000); | ||
220 | |||
221 | return 0; | ||
222 | } | ||
223 | |||
224 | /* Left Headphone Mixers */ | ||
225 | static const struct snd_kcontrol_new wm9712_hpl_mixer_controls[] = { | ||
226 | SOC_DAPM_SINGLE("PCBeep Bypass Switch", HPL_MIXER, 5, 1, 0), | ||
227 | SOC_DAPM_SINGLE("Aux Playback Switch", HPL_MIXER, 4, 1, 0), | ||
228 | SOC_DAPM_SINGLE("Phone Bypass Switch", HPL_MIXER, 3, 1, 0), | ||
229 | SOC_DAPM_SINGLE("Line Bypass Switch", HPL_MIXER, 2, 1, 0), | ||
230 | SOC_DAPM_SINGLE("PCM Playback Switch", HPL_MIXER, 1, 1, 0), | ||
231 | SOC_DAPM_SINGLE("Mic Sidetone Switch", HPL_MIXER, 0, 1, 0), | ||
232 | }; | ||
233 | |||
234 | /* Right Headphone Mixers */ | ||
235 | static const struct snd_kcontrol_new wm9712_hpr_mixer_controls[] = { | ||
236 | SOC_DAPM_SINGLE("PCBeep Bypass Switch", HPR_MIXER, 5, 1, 0), | ||
237 | SOC_DAPM_SINGLE("Aux Playback Switch", HPR_MIXER, 4, 1, 0), | ||
238 | SOC_DAPM_SINGLE("Phone Bypass Switch", HPR_MIXER, 3, 1, 0), | ||
239 | SOC_DAPM_SINGLE("Line Bypass Switch", HPR_MIXER, 2, 1, 0), | ||
240 | SOC_DAPM_SINGLE("PCM Playback Switch", HPR_MIXER, 1, 1, 0), | ||
241 | SOC_DAPM_SINGLE("Mic Sidetone Switch", HPR_MIXER, 0, 1, 0), | ||
242 | }; | ||
243 | |||
244 | /* Speaker Mixer */ | ||
245 | static const struct snd_kcontrol_new wm9712_speaker_mixer_controls[] = { | ||
246 | SOC_DAPM_SINGLE("PCBeep Bypass Switch", AC97_PC_BEEP, 11, 1, 1), | ||
247 | SOC_DAPM_SINGLE("Aux Playback Switch", AC97_CD, 11, 1, 1), | ||
248 | SOC_DAPM_SINGLE("Phone Bypass Switch", AC97_PHONE, 14, 1, 1), | ||
249 | SOC_DAPM_SINGLE("Line Bypass Switch", AC97_LINE, 14, 1, 1), | ||
250 | SOC_DAPM_SINGLE("PCM Playback Switch", AC97_PCM, 14, 1, 1), | ||
251 | }; | ||
252 | |||
253 | /* Phone Mixer */ | ||
254 | static const struct snd_kcontrol_new wm9712_phone_mixer_controls[] = { | ||
255 | SOC_DAPM_SINGLE("PCBeep Bypass Switch", AC97_PC_BEEP, 7, 1, 1), | ||
256 | SOC_DAPM_SINGLE("Aux Playback Switch", AC97_CD, 7, 1, 1), | ||
257 | SOC_DAPM_SINGLE("Line Bypass Switch", AC97_LINE, 13, 1, 1), | ||
258 | SOC_DAPM_SINGLE("PCM Playback Switch", AC97_PCM, 13, 1, 1), | ||
259 | SOC_DAPM_SINGLE("Mic 1 Sidetone Switch", AC97_MIC, 14, 1, 1), | ||
260 | SOC_DAPM_SINGLE("Mic 2 Sidetone Switch", AC97_MIC, 13, 1, 1), | ||
261 | }; | ||
262 | |||
263 | /* ALC headphone mux */ | ||
264 | static const struct snd_kcontrol_new wm9712_alc_mux_controls = | ||
265 | SOC_DAPM_ENUM("Route", wm9712_enum[1]); | ||
266 | |||
267 | /* out 3 mux */ | ||
268 | static const struct snd_kcontrol_new wm9712_out3_mux_controls = | ||
269 | SOC_DAPM_ENUM("Route", wm9712_enum[2]); | ||
270 | |||
271 | /* spk mux */ | ||
272 | static const struct snd_kcontrol_new wm9712_spk_mux_controls = | ||
273 | SOC_DAPM_ENUM("Route", wm9712_enum[3]); | ||
274 | |||
275 | /* Capture to Phone mux */ | ||
276 | static const struct snd_kcontrol_new wm9712_capture_phone_mux_controls = | ||
277 | SOC_DAPM_ENUM("Route", wm9712_enum[4]); | ||
278 | |||
279 | /* Capture left select */ | ||
280 | static const struct snd_kcontrol_new wm9712_capture_selectl_controls = | ||
281 | SOC_DAPM_ENUM("Route", wm9712_enum[8]); | ||
282 | |||
283 | /* Capture right select */ | ||
284 | static const struct snd_kcontrol_new wm9712_capture_selectr_controls = | ||
285 | SOC_DAPM_ENUM("Route", wm9712_enum[9]); | ||
286 | |||
287 | /* Mic select */ | ||
288 | static const struct snd_kcontrol_new wm9712_mic_src_controls = | ||
289 | SOC_DAPM_ENUM("Route", wm9712_enum[7]); | ||
290 | |||
291 | /* diff select */ | ||
292 | static const struct snd_kcontrol_new wm9712_diff_sel_controls = | ||
293 | SOC_DAPM_ENUM("Route", wm9712_enum[11]); | ||
294 | |||
295 | static const struct snd_soc_dapm_widget wm9712_dapm_widgets[] = { | ||
296 | SND_SOC_DAPM_MUX("ALC Sidetone Mux", SND_SOC_NOPM, 0, 0, | ||
297 | &wm9712_alc_mux_controls), | ||
298 | SND_SOC_DAPM_MUX("Out3 Mux", SND_SOC_NOPM, 0, 0, | ||
299 | &wm9712_out3_mux_controls), | ||
300 | SND_SOC_DAPM_MUX("Speaker Mux", SND_SOC_NOPM, 0, 0, | ||
301 | &wm9712_spk_mux_controls), | ||
302 | SND_SOC_DAPM_MUX("Capture Phone Mux", SND_SOC_NOPM, 0, 0, | ||
303 | &wm9712_capture_phone_mux_controls), | ||
304 | SND_SOC_DAPM_MUX("Left Capture Select", SND_SOC_NOPM, 0, 0, | ||
305 | &wm9712_capture_selectl_controls), | ||
306 | SND_SOC_DAPM_MUX("Right Capture Select", SND_SOC_NOPM, 0, 0, | ||
307 | &wm9712_capture_selectr_controls), | ||
308 | SND_SOC_DAPM_MUX("Mic Select Source", SND_SOC_NOPM, 0, 0, | ||
309 | &wm9712_mic_src_controls), | ||
310 | SND_SOC_DAPM_MUX("Differential Source", SND_SOC_NOPM, 0, 0, | ||
311 | &wm9712_diff_sel_controls), | ||
312 | SND_SOC_DAPM_MIXER("AC97 Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
313 | SND_SOC_DAPM_MIXER_E("Left HP Mixer", AC97_INT_PAGING, 9, 1, | ||
314 | &wm9712_hpl_mixer_controls[0], ARRAY_SIZE(wm9712_hpl_mixer_controls), | ||
315 | mixer_event, SND_SOC_DAPM_POST_REG), | ||
316 | SND_SOC_DAPM_MIXER_E("Right HP Mixer", AC97_INT_PAGING, 8, 1, | ||
317 | &wm9712_hpr_mixer_controls[0], ARRAY_SIZE(wm9712_hpr_mixer_controls), | ||
318 | mixer_event, SND_SOC_DAPM_POST_REG), | ||
319 | SND_SOC_DAPM_MIXER("Phone Mixer", AC97_INT_PAGING, 6, 1, | ||
320 | &wm9712_phone_mixer_controls[0], ARRAY_SIZE(wm9712_phone_mixer_controls)), | ||
321 | SND_SOC_DAPM_MIXER("Speaker Mixer", AC97_INT_PAGING, 7, 1, | ||
322 | &wm9712_speaker_mixer_controls[0], | ||
323 | ARRAY_SIZE(wm9712_speaker_mixer_controls)), | ||
324 | SND_SOC_DAPM_MIXER("Mono Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
325 | SND_SOC_DAPM_DAC("Left DAC", "Left HiFi Playback", AC97_INT_PAGING, 14, 1), | ||
326 | SND_SOC_DAPM_DAC("Right DAC", "Right HiFi Playback", AC97_INT_PAGING, 13, 1), | ||
327 | SND_SOC_DAPM_DAC("Aux DAC", "Aux Playback", SND_SOC_NOPM, 0, 0), | ||
328 | SND_SOC_DAPM_ADC("Left ADC", "Left HiFi Capture", AC97_INT_PAGING, 12, 1), | ||
329 | SND_SOC_DAPM_ADC("Right ADC", "Right HiFi Capture", AC97_INT_PAGING, 11, 1), | ||
330 | SND_SOC_DAPM_PGA("Headphone PGA", AC97_INT_PAGING, 4, 1, NULL, 0), | ||
331 | SND_SOC_DAPM_PGA("Speaker PGA", AC97_INT_PAGING, 3, 1, NULL, 0), | ||
332 | SND_SOC_DAPM_PGA("Out 3 PGA", AC97_INT_PAGING, 5, 1, NULL, 0), | ||
333 | SND_SOC_DAPM_PGA("Line PGA", AC97_INT_PAGING, 2, 1, NULL, 0), | ||
334 | SND_SOC_DAPM_PGA("Phone PGA", AC97_INT_PAGING, 1, 1, NULL, 0), | ||
335 | SND_SOC_DAPM_PGA("Mic PGA", AC97_INT_PAGING, 0, 1, NULL, 0), | ||
336 | SND_SOC_DAPM_MICBIAS("Mic Bias", AC97_INT_PAGING, 10, 1), | ||
337 | SND_SOC_DAPM_OUTPUT("MONOOUT"), | ||
338 | SND_SOC_DAPM_OUTPUT("HPOUTL"), | ||
339 | SND_SOC_DAPM_OUTPUT("HPOUTR"), | ||
340 | SND_SOC_DAPM_OUTPUT("LOUT2"), | ||
341 | SND_SOC_DAPM_OUTPUT("ROUT2"), | ||
342 | SND_SOC_DAPM_OUTPUT("OUT3"), | ||
343 | SND_SOC_DAPM_INPUT("LINEINL"), | ||
344 | SND_SOC_DAPM_INPUT("LINEINR"), | ||
345 | SND_SOC_DAPM_INPUT("PHONE"), | ||
346 | SND_SOC_DAPM_INPUT("PCBEEP"), | ||
347 | SND_SOC_DAPM_INPUT("MIC1"), | ||
348 | SND_SOC_DAPM_INPUT("MIC2"), | ||
349 | }; | ||
350 | |||
351 | static const char *audio_map[][3] = { | ||
352 | /* virtual mixer - mixes left & right channels for spk and mono */ | ||
353 | {"AC97 Mixer", NULL, "Left DAC"}, | ||
354 | {"AC97 Mixer", NULL, "Right DAC"}, | ||
355 | |||
356 | /* Left HP mixer */ | ||
357 | {"Left HP Mixer", "PCBeep Bypass Switch", "PCBEEP"}, | ||
358 | {"Left HP Mixer", "Aux Playback Switch", "Aux DAC"}, | ||
359 | {"Left HP Mixer", "Phone Bypass Switch", "Phone PGA"}, | ||
360 | {"Left HP Mixer", "Line Bypass Switch", "Line PGA"}, | ||
361 | {"Left HP Mixer", "PCM Playback Switch", "Left DAC"}, | ||
362 | {"Left HP Mixer", "Mic Sidetone Switch", "Mic PGA"}, | ||
363 | {"Left HP Mixer", NULL, "ALC Sidetone Mux"}, | ||
364 | //{"Right HP Mixer", NULL, "HP Mixer"}, | ||
365 | |||
366 | /* Right HP mixer */ | ||
367 | {"Right HP Mixer", "PCBeep Bypass Switch", "PCBEEP"}, | ||
368 | {"Right HP Mixer", "Aux Playback Switch", "Aux DAC"}, | ||
369 | {"Right HP Mixer", "Phone Bypass Switch", "Phone PGA"}, | ||
370 | {"Right HP Mixer", "Line Bypass Switch", "Line PGA"}, | ||
371 | {"Right HP Mixer", "PCM Playback Switch", "Right DAC"}, | ||
372 | {"Right HP Mixer", "Mic Sidetone Switch", "Mic PGA"}, | ||
373 | {"Right HP Mixer", NULL, "ALC Sidetone Mux"}, | ||
374 | |||
375 | /* speaker mixer */ | ||
376 | {"Speaker Mixer", "PCBeep Bypass Switch", "PCBEEP"}, | ||
377 | {"Speaker Mixer", "Line Bypass Switch", "Line PGA"}, | ||
378 | {"Speaker Mixer", "PCM Playback Switch", "AC97 Mixer"}, | ||
379 | {"Speaker Mixer", "Phone Bypass Switch", "Phone PGA"}, | ||
380 | {"Speaker Mixer", "Aux Playback Switch", "Aux DAC"}, | ||
381 | |||
382 | /* Phone mixer */ | ||
383 | {"Phone Mixer", "PCBeep Bypass Switch", "PCBEEP"}, | ||
384 | {"Phone Mixer", "Line Bypass Switch", "Line PGA"}, | ||
385 | {"Phone Mixer", "Aux Playback Switch", "Aux DAC"}, | ||
386 | {"Phone Mixer", "PCM Playback Switch", "AC97 Mixer"}, | ||
387 | {"Phone Mixer", "Mic 1 Sidetone Switch", "Mic PGA"}, | ||
388 | {"Phone Mixer", "Mic 2 Sidetone Switch", "Mic PGA"}, | ||
389 | |||
390 | /* inputs */ | ||
391 | {"Line PGA", NULL, "LINEINL"}, | ||
392 | {"Line PGA", NULL, "LINEINR"}, | ||
393 | {"Phone PGA", NULL, "PHONE"}, | ||
394 | {"Mic PGA", NULL, "MIC1"}, | ||
395 | {"Mic PGA", NULL, "MIC2"}, | ||
396 | |||
397 | /* left capture selector */ | ||
398 | {"Left Capture Select", "Mic", "MIC1"}, | ||
399 | {"Left Capture Select", "Speaker Mixer", "Speaker Mixer"}, | ||
400 | {"Left Capture Select", "Line", "LINEINL"}, | ||
401 | {"Left Capture Select", "Headphone Mixer", "Left HP Mixer"}, | ||
402 | {"Left Capture Select", "Phone Mixer", "Phone Mixer"}, | ||
403 | {"Left Capture Select", "Phone", "PHONE"}, | ||
404 | |||
405 | /* right capture selector */ | ||
406 | {"Right Capture Select", "Mic", "MIC2"}, | ||
407 | {"Right Capture Select", "Speaker Mixer", "Speaker Mixer"}, | ||
408 | {"Right Capture Select", "Line", "LINEINR"}, | ||
409 | {"Right Capture Select", "Headphone Mixer", "Right HP Mixer"}, | ||
410 | {"Right Capture Select", "Phone Mixer", "Phone Mixer"}, | ||
411 | {"Right Capture Select", "Phone", "PHONE"}, | ||
412 | |||
413 | /* ALC Sidetone */ | ||
414 | {"ALC Sidetone Mux", "Stereo", "Left Capture Select"}, | ||
415 | {"ALC Sidetone Mux", "Stereo", "Right Capture Select"}, | ||
416 | {"ALC Sidetone Mux", "Left", "Left Capture Select"}, | ||
417 | {"ALC Sidetone Mux", "Right", "Right Capture Select"}, | ||
418 | |||
419 | /* ADC's */ | ||
420 | {"Left ADC", NULL, "Left Capture Select"}, | ||
421 | {"Right ADC", NULL, "Right Capture Select"}, | ||
422 | |||
423 | /* outputs */ | ||
424 | {"MONOOUT", NULL, "Phone Mixer"}, | ||
425 | {"HPOUTL", NULL, "Headphone PGA"}, | ||
426 | {"Headphone PGA", NULL, "Left HP Mixer"}, | ||
427 | {"HPOUTR", NULL, "Headphone PGA"}, | ||
428 | {"Headphone PGA", NULL, "Right HP Mixer"}, | ||
429 | |||
430 | /* mono hp mixer */ | ||
431 | {"Mono HP Mixer", NULL, "Left HP Mixer"}, | ||
432 | {"Mono HP Mixer", NULL, "Right HP Mixer"}, | ||
433 | |||
434 | /* Out3 Mux */ | ||
435 | {"Out3 Mux", "Left", "Left HP Mixer"}, | ||
436 | {"Out3 Mux", "Mono", "Phone Mixer"}, | ||
437 | {"Out3 Mux", "Left + Right", "Mono HP Mixer"}, | ||
438 | {"Out 3 PGA", NULL, "Out3 Mux"}, | ||
439 | {"OUT3", NULL, "Out 3 PGA"}, | ||
440 | |||
441 | /* speaker Mux */ | ||
442 | {"Speaker Mux", "Speaker Mix", "Speaker Mixer"}, | ||
443 | {"Speaker Mux", "Headphone Mix", "Mono HP Mixer"}, | ||
444 | {"Speaker PGA", NULL, "Speaker Mux"}, | ||
445 | {"LOUT2", NULL, "Speaker PGA"}, | ||
446 | {"ROUT2", NULL, "Speaker PGA"}, | ||
447 | |||
448 | {NULL, NULL, NULL}, | ||
449 | }; | ||
450 | |||
451 | static int wm9712_add_widgets(struct snd_soc_codec *codec) | ||
452 | { | ||
453 | int i; | ||
454 | |||
455 | for(i = 0; i < ARRAY_SIZE(wm9712_dapm_widgets); i++) { | ||
456 | snd_soc_dapm_new_control(codec, &wm9712_dapm_widgets[i]); | ||
457 | } | ||
458 | |||
459 | /* set up audio path audio_mapnects */ | ||
460 | for(i = 0; audio_map[i][0] != NULL; i++) { | ||
461 | snd_soc_dapm_connect_input(codec, audio_map[i][0], | ||
462 | audio_map[i][1], audio_map[i][2]); | ||
463 | } | ||
464 | |||
465 | snd_soc_dapm_new_widgets(codec); | ||
466 | return 0; | ||
467 | } | ||
468 | |||
469 | static unsigned int ac97_read(struct snd_soc_codec *codec, | ||
470 | unsigned int reg) | ||
471 | { | ||
472 | u16 *cache = codec->reg_cache; | ||
473 | |||
474 | if (reg == AC97_RESET || reg == AC97_GPIO_STATUS || | ||
475 | reg == AC97_VENDOR_ID1 || reg == AC97_VENDOR_ID2 || | ||
476 | reg == AC97_REC_GAIN) | ||
477 | return soc_ac97_ops.read(codec->ac97, reg); | ||
478 | else { | ||
479 | reg = reg >> 1; | ||
480 | |||
481 | if (reg > (ARRAY_SIZE(wm9712_reg))) | ||
482 | return -EIO; | ||
483 | |||
484 | return cache[reg]; | ||
485 | } | ||
486 | } | ||
487 | |||
488 | static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, | ||
489 | unsigned int val) | ||
490 | { | ||
491 | u16 *cache = codec->reg_cache; | ||
492 | |||
493 | soc_ac97_ops.write(codec->ac97, reg, val); | ||
494 | reg = reg >> 1; | ||
495 | if (reg <= (ARRAY_SIZE(wm9712_reg))) | ||
496 | cache[reg] = val; | ||
497 | |||
498 | return 0; | ||
499 | } | ||
500 | |||
501 | static int ac97_prepare(struct snd_pcm_substream *substream) | ||
502 | { | ||
503 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
504 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
505 | struct snd_soc_device *socdev = rtd->socdev; | ||
506 | struct snd_soc_codec *codec = socdev->codec; | ||
507 | int reg; | ||
508 | u16 vra; | ||
509 | |||
510 | vra = ac97_read(codec, AC97_EXTENDED_STATUS); | ||
511 | ac97_write(codec, AC97_EXTENDED_STATUS, vra | 0x1); | ||
512 | |||
513 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
514 | reg = AC97_PCM_FRONT_DAC_RATE; | ||
515 | else | ||
516 | reg = AC97_PCM_LR_ADC_RATE; | ||
517 | |||
518 | return ac97_write(codec, reg, runtime->rate); | ||
519 | } | ||
520 | |||
521 | static int ac97_aux_prepare(struct snd_pcm_substream *substream) | ||
522 | { | ||
523 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
524 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
525 | struct snd_soc_device *socdev = rtd->socdev; | ||
526 | struct snd_soc_codec *codec = socdev->codec; | ||
527 | u16 vra, xsle; | ||
528 | |||
529 | vra = ac97_read(codec, AC97_EXTENDED_STATUS); | ||
530 | ac97_write(codec, AC97_EXTENDED_STATUS, vra | 0x1); | ||
531 | xsle = ac97_read(codec, AC97_PCI_SID); | ||
532 | ac97_write(codec, AC97_PCI_SID, xsle | 0x8000); | ||
533 | |||
534 | if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) | ||
535 | return -ENODEV; | ||
536 | |||
537 | return ac97_write(codec, AC97_PCM_SURR_DAC_RATE, runtime->rate); | ||
538 | } | ||
539 | |||
540 | #define WM9712_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ | ||
541 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) | ||
542 | |||
543 | struct snd_soc_codec_dai wm9712_dai[] = { | ||
544 | { | ||
545 | .name = "AC97 HiFi", | ||
546 | .playback = { | ||
547 | .stream_name = "HiFi Playback", | ||
548 | .channels_min = 1, | ||
549 | .channels_max = 2, | ||
550 | .rates = WM9712_AC97_RATES, | ||
551 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | ||
552 | .capture = { | ||
553 | .stream_name = "HiFi Capture", | ||
554 | .channels_min = 1, | ||
555 | .channels_max = 2, | ||
556 | .rates = WM9712_AC97_RATES, | ||
557 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | ||
558 | .ops = { | ||
559 | .prepare = ac97_prepare,}, | ||
560 | }, | ||
561 | { | ||
562 | .name = "AC97 Aux", | ||
563 | .playback = { | ||
564 | .stream_name = "Aux Playback", | ||
565 | .channels_min = 1, | ||
566 | .channels_max = 1, | ||
567 | .rates = WM9712_AC97_RATES, | ||
568 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | ||
569 | .ops = { | ||
570 | .prepare = ac97_aux_prepare,}, | ||
571 | } | ||
572 | }; | ||
573 | EXPORT_SYMBOL_GPL(wm9712_dai); | ||
574 | |||
575 | static int wm9712_dapm_event(struct snd_soc_codec *codec, int event) | ||
576 | { | ||
577 | u16 reg; | ||
578 | |||
579 | switch (event) { | ||
580 | case SNDRV_CTL_POWER_D0: /* full On */ | ||
581 | /* liam - maybe enable thermal shutdown */ | ||
582 | reg = ac97_read(codec, AC97_EXTENDED_MID) & 0xdfff; | ||
583 | ac97_write(codec, AC97_EXTENDED_MID, reg); | ||
584 | break; | ||
585 | case SNDRV_CTL_POWER_D1: /* partial On */ | ||
586 | case SNDRV_CTL_POWER_D2: /* partial On */ | ||
587 | break; | ||
588 | case SNDRV_CTL_POWER_D3hot: /* Off, with power */ | ||
589 | /* enable master bias and vmid */ | ||
590 | reg = ac97_read(codec, AC97_EXTENDED_MID) & 0xbbff; | ||
591 | ac97_write(codec, AC97_EXTENDED_MID, reg); | ||
592 | ac97_write(codec, AC97_POWERDOWN, 0x0000); | ||
593 | break; | ||
594 | case SNDRV_CTL_POWER_D3cold: /* Off, without power */ | ||
595 | /* disable everything including AC link */ | ||
596 | ac97_write(codec, AC97_EXTENDED_MID, 0xffff); | ||
597 | ac97_write(codec, AC97_EXTENDED_MSTATUS, 0xffff); | ||
598 | ac97_write(codec, AC97_POWERDOWN, 0xffff); | ||
599 | break; | ||
600 | } | ||
601 | codec->dapm_state = event; | ||
602 | return 0; | ||
603 | } | ||
604 | |||
605 | static int wm9712_reset(struct snd_soc_codec *codec, int try_warm) | ||
606 | { | ||
607 | if (try_warm && soc_ac97_ops.warm_reset) { | ||
608 | soc_ac97_ops.warm_reset(codec->ac97); | ||
609 | if (!(ac97_read(codec, 0) & 0x8000)) | ||
610 | return 1; | ||
611 | } | ||
612 | |||
613 | soc_ac97_ops.reset(codec->ac97); | ||
614 | if (ac97_read(codec, 0) & 0x8000) | ||
615 | goto err; | ||
616 | return 0; | ||
617 | |||
618 | err: | ||
619 | printk(KERN_ERR "WM9712 AC97 reset failed\n"); | ||
620 | return -EIO; | ||
621 | } | ||
622 | |||
623 | static int wm9712_soc_suspend(struct platform_device *pdev, | ||
624 | pm_message_t state) | ||
625 | { | ||
626 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
627 | struct snd_soc_codec *codec = socdev->codec; | ||
628 | |||
629 | wm9712_dapm_event(codec, SNDRV_CTL_POWER_D3cold); | ||
630 | return 0; | ||
631 | } | ||
632 | |||
633 | static int wm9712_soc_resume(struct platform_device *pdev) | ||
634 | { | ||
635 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
636 | struct snd_soc_codec *codec = socdev->codec; | ||
637 | int i, ret; | ||
638 | u16 *cache = codec->reg_cache; | ||
639 | |||
640 | ret = wm9712_reset(codec, 1); | ||
641 | if (ret < 0){ | ||
642 | printk(KERN_ERR "could not reset AC97 codec\n"); | ||
643 | return ret; | ||
644 | } | ||
645 | |||
646 | wm9712_dapm_event(codec, SNDRV_CTL_POWER_D3hot); | ||
647 | |||
648 | if (ret == 0) { | ||
649 | /* Sync reg_cache with the hardware after cold reset */ | ||
650 | for (i = 2; i < ARRAY_SIZE(wm9712_reg) << 1; i+=2) { | ||
651 | if (i == AC97_INT_PAGING || i == AC97_POWERDOWN || | ||
652 | (i > 0x58 && i != 0x5c)) | ||
653 | continue; | ||
654 | soc_ac97_ops.write(codec->ac97, i, cache[i>>1]); | ||
655 | } | ||
656 | } | ||
657 | |||
658 | if (codec->suspend_dapm_state == SNDRV_CTL_POWER_D0) | ||
659 | wm9712_dapm_event(codec, SNDRV_CTL_POWER_D0); | ||
660 | |||
661 | return ret; | ||
662 | } | ||
663 | |||
664 | static int wm9712_soc_probe(struct platform_device *pdev) | ||
665 | { | ||
666 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
667 | struct snd_soc_codec *codec; | ||
668 | int ret = 0; | ||
669 | |||
670 | printk(KERN_INFO "WM9711/WM9712 SoC Audio Codec %s\n", WM9712_VERSION); | ||
671 | |||
672 | socdev->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | ||
673 | if (socdev->codec == NULL) | ||
674 | return -ENOMEM; | ||
675 | codec = socdev->codec; | ||
676 | mutex_init(&codec->mutex); | ||
677 | |||
678 | codec->reg_cache = | ||
679 | kzalloc(sizeof(u16) * ARRAY_SIZE(wm9712_reg), GFP_KERNEL); | ||
680 | if (codec->reg_cache == NULL) { | ||
681 | ret = -ENOMEM; | ||
682 | goto cache_err; | ||
683 | } | ||
684 | memcpy(codec->reg_cache, wm9712_reg, sizeof(u16) * ARRAY_SIZE(wm9712_reg)); | ||
685 | codec->reg_cache_size = sizeof(u16) * ARRAY_SIZE(wm9712_reg); | ||
686 | codec->reg_cache_step = 2; | ||
687 | |||
688 | codec->name = "WM9712"; | ||
689 | codec->owner = THIS_MODULE; | ||
690 | codec->dai = wm9712_dai; | ||
691 | codec->num_dai = ARRAY_SIZE(wm9712_dai); | ||
692 | codec->write = ac97_write; | ||
693 | codec->read = ac97_read; | ||
694 | codec->dapm_event = wm9712_dapm_event; | ||
695 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
696 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
697 | |||
698 | ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0); | ||
699 | if (ret < 0) { | ||
700 | printk(KERN_ERR "wm9712: failed to register AC97 codec\n"); | ||
701 | goto codec_err; | ||
702 | } | ||
703 | |||
704 | /* register pcms */ | ||
705 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
706 | if (ret < 0) | ||
707 | goto pcm_err; | ||
708 | |||
709 | ret = wm9712_reset(codec, 0); | ||
710 | if (ret < 0) { | ||
711 | printk(KERN_ERR "AC97 link error\n"); | ||
712 | goto reset_err; | ||
713 | } | ||
714 | |||
715 | /* set alc mux to none */ | ||
716 | ac97_write(codec, AC97_VIDEO, ac97_read(codec, AC97_VIDEO) | 0x3000); | ||
717 | |||
718 | wm9712_dapm_event(codec, SNDRV_CTL_POWER_D3hot); | ||
719 | wm9712_add_controls(codec); | ||
720 | wm9712_add_widgets(codec); | ||
721 | ret = snd_soc_register_card(socdev); | ||
722 | if (ret < 0) { | ||
723 | printk(KERN_ERR "wm9712: failed to register card\n"); | ||
724 | goto reset_err; | ||
725 | } | ||
726 | |||
727 | return 0; | ||
728 | |||
729 | reset_err: | ||
730 | snd_soc_free_pcms(socdev); | ||
731 | |||
732 | pcm_err: | ||
733 | snd_soc_free_ac97_codec(codec); | ||
734 | |||
735 | codec_err: | ||
736 | kfree(codec->reg_cache); | ||
737 | |||
738 | cache_err: | ||
739 | kfree(socdev->codec); | ||
740 | socdev->codec = NULL; | ||
741 | return ret; | ||
742 | } | ||
743 | |||
744 | static int wm9712_soc_remove(struct platform_device *pdev) | ||
745 | { | ||
746 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
747 | struct snd_soc_codec *codec = socdev->codec; | ||
748 | |||
749 | if (codec == NULL) | ||
750 | return 0; | ||
751 | |||
752 | snd_soc_dapm_free(socdev); | ||
753 | snd_soc_free_pcms(socdev); | ||
754 | snd_soc_free_ac97_codec(codec); | ||
755 | kfree(codec->reg_cache); | ||
756 | kfree(codec); | ||
757 | return 0; | ||
758 | } | ||
759 | |||
760 | struct snd_soc_codec_device soc_codec_dev_wm9712 = { | ||
761 | .probe = wm9712_soc_probe, | ||
762 | .remove = wm9712_soc_remove, | ||
763 | .suspend = wm9712_soc_suspend, | ||
764 | .resume = wm9712_soc_resume, | ||
765 | }; | ||
766 | |||
767 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm9712); | ||
768 | |||
769 | MODULE_DESCRIPTION("ASoC WM9711/WM9712 driver"); | ||
770 | MODULE_AUTHOR("Liam Girdwood"); | ||
771 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/wm9712.h b/sound/soc/codecs/wm9712.h new file mode 100644 index 000000000000..719105d61e65 --- /dev/null +++ b/sound/soc/codecs/wm9712.h | |||
@@ -0,0 +1,14 @@ | |||
1 | /* | ||
2 | * wm9712.h -- WM9712 Soc Audio driver | ||
3 | */ | ||
4 | |||
5 | #ifndef _WM9712_H | ||
6 | #define _WM9712_H | ||
7 | |||
8 | #define WM9712_DAI_AC97_HIFI 0 | ||
9 | #define WM9712_DAI_AC97_AUX 1 | ||
10 | |||
11 | extern struct snd_soc_codec_dai wm9712_dai[2]; | ||
12 | extern struct snd_soc_codec_device soc_codec_dev_wm9712; | ||
13 | |||
14 | #endif | ||
diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig new file mode 100644 index 000000000000..579e1c8d2b28 --- /dev/null +++ b/sound/soc/pxa/Kconfig | |||
@@ -0,0 +1,60 @@ | |||
1 | menu "SoC Audio for the Intel PXA2xx" | ||
2 | |||
3 | config SND_PXA2XX_SOC | ||
4 | tristate "SoC Audio for the Intel PXA2xx chip" | ||
5 | depends on ARCH_PXA && SND | ||
6 | select SND_PCM | ||
7 | help | ||
8 | Say Y or M if you want to add support for codecs attached to | ||
9 | the PXA2xx AC97, I2S or SSP interface. You will also need | ||
10 | to select the audio interfaces to support below. | ||
11 | |||
12 | config SND_PXA2XX_AC97 | ||
13 | tristate | ||
14 | select SND_AC97_CODEC | ||
15 | |||
16 | config SND_PXA2XX_SOC_AC97 | ||
17 | tristate | ||
18 | select AC97_BUS | ||
19 | select SND_SOC_AC97_BUS | ||
20 | |||
21 | config SND_PXA2XX_SOC_I2S | ||
22 | tristate | ||
23 | |||
24 | config SND_PXA2XX_SOC_CORGI | ||
25 | tristate "SoC Audio support for Sharp Zaurus SL-C7x0" | ||
26 | depends on SND_PXA2XX_SOC && PXA_SHARP_C7xx | ||
27 | select SND_PXA2XX_SOC_I2S | ||
28 | select SND_SOC_WM8731 | ||
29 | help | ||
30 | Say Y if you want to add support for SoC audio on Sharp | ||
31 | Zaurus SL-C7x0 models (Corgi, Shepherd, Husky). | ||
32 | |||
33 | config SND_PXA2XX_SOC_SPITZ | ||
34 | tristate "SoC Audio support for Sharp Zaurus SL-Cxx00" | ||
35 | depends on SND_PXA2XX_SOC && PXA_SHARP_Cxx00 | ||
36 | select SND_PXA2XX_SOC_I2S | ||
37 | select SND_SOC_WM8750 | ||
38 | help | ||
39 | Say Y if you want to add support for SoC audio on Sharp | ||
40 | Zaurus SL-Cxx00 models (Spitz, Borzoi and Akita). | ||
41 | |||
42 | config SND_PXA2XX_SOC_POODLE | ||
43 | tristate "SoC Audio support for Poodle" | ||
44 | depends on SND_PXA2XX_SOC && MACH_POODLE | ||
45 | select SND_PXA2XX_SOC_I2S | ||
46 | select SND_SOC_WM8731 | ||
47 | help | ||
48 | Say Y if you want to add support for SoC audio on Sharp | ||
49 | Zaurus SL-5600 model (Poodle). | ||
50 | |||
51 | config SND_PXA2XX_SOC_TOSA | ||
52 | tristate "SoC AC97 Audio support for Tosa" | ||
53 | depends on SND_PXA2XX_SOC && MACH_TOSA | ||
54 | select SND_PXA2XX_SOC_AC97 | ||
55 | select SND_SOC_WM9712 | ||
56 | help | ||
57 | Say Y if you want to add support for SoC audio on Sharp | ||
58 | Zaurus SL-C6000x models (Tosa). | ||
59 | |||
60 | endmenu | ||
diff --git a/sound/soc/pxa/Makefile b/sound/soc/pxa/Makefile new file mode 100644 index 000000000000..78e0d6b07d1d --- /dev/null +++ b/sound/soc/pxa/Makefile | |||
@@ -0,0 +1,20 @@ | |||
1 | # PXA Platform Support | ||
2 | snd-soc-pxa2xx-objs := pxa2xx-pcm.o | ||
3 | snd-soc-pxa2xx-ac97-objs := pxa2xx-ac97.o | ||
4 | snd-soc-pxa2xx-i2s-objs := pxa2xx-i2s.o | ||
5 | |||
6 | obj-$(CONFIG_SND_PXA2XX_SOC) += snd-soc-pxa2xx.o | ||
7 | obj-$(CONFIG_SND_PXA2XX_SOC_AC97) += snd-soc-pxa2xx-ac97.o | ||
8 | obj-$(CONFIG_SND_PXA2XX_SOC_I2S) += snd-soc-pxa2xx-i2s.o | ||
9 | |||
10 | # PXA Machine Support | ||
11 | snd-soc-corgi-objs := corgi.o | ||
12 | snd-soc-poodle-objs := poodle.o | ||
13 | snd-soc-tosa-objs := tosa.o | ||
14 | snd-soc-spitz-objs := spitz.o | ||
15 | |||
16 | obj-$(CONFIG_SND_PXA2XX_SOC_CORGI) += snd-soc-corgi.o | ||
17 | obj-$(CONFIG_SND_PXA2XX_SOC_POODLE) += snd-soc-poodle.o | ||
18 | obj-$(CONFIG_SND_PXA2XX_SOC_TOSA) += snd-soc-tosa.o | ||
19 | obj-$(CONFIG_SND_PXA2XX_SOC_SPITZ) += snd-soc-spitz.o | ||
20 | |||
diff --git a/sound/soc/pxa/corgi.c b/sound/soc/pxa/corgi.c new file mode 100644 index 000000000000..5ee51a994ac3 --- /dev/null +++ b/sound/soc/pxa/corgi.c | |||
@@ -0,0 +1,383 @@ | |||
1 | /* | ||
2 | * corgi.c -- SoC audio for Corgi | ||
3 | * | ||
4 | * Copyright 2005 Wolfson Microelectronics PLC. | ||
5 | * Copyright 2005 Openedhand Ltd. | ||
6 | * | ||
7 | * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com> | ||
8 | * Richard Purdie <richard@openedhand.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify it | ||
11 | * under the terms of the GNU General Public License as published by the | ||
12 | * Free Software Foundation; either version 2 of the License, or (at your | ||
13 | * option) any later version. | ||
14 | * | ||
15 | * Revision history | ||
16 | * 30th Nov 2005 Initial version. | ||
17 | * | ||
18 | */ | ||
19 | |||
20 | #include <linux/module.h> | ||
21 | #include <linux/moduleparam.h> | ||
22 | #include <linux/timer.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/platform_device.h> | ||
25 | #include <sound/driver.h> | ||
26 | #include <sound/core.h> | ||
27 | #include <sound/pcm.h> | ||
28 | #include <sound/soc.h> | ||
29 | #include <sound/soc-dapm.h> | ||
30 | |||
31 | #include <asm/mach-types.h> | ||
32 | #include <asm/hardware/scoop.h> | ||
33 | #include <asm/arch/pxa-regs.h> | ||
34 | #include <asm/arch/hardware.h> | ||
35 | #include <asm/arch/corgi.h> | ||
36 | #include <asm/arch/audio.h> | ||
37 | |||
38 | #include "../codecs/wm8731.h" | ||
39 | #include "pxa2xx-pcm.h" | ||
40 | #include "pxa2xx-i2s.h" | ||
41 | |||
42 | #define CORGI_HP 0 | ||
43 | #define CORGI_MIC 1 | ||
44 | #define CORGI_LINE 2 | ||
45 | #define CORGI_HEADSET 3 | ||
46 | #define CORGI_HP_OFF 4 | ||
47 | #define CORGI_SPK_ON 0 | ||
48 | #define CORGI_SPK_OFF 1 | ||
49 | |||
50 | /* audio clock in Hz - rounded from 12.235MHz */ | ||
51 | #define CORGI_AUDIO_CLOCK 12288000 | ||
52 | |||
53 | static int corgi_jack_func; | ||
54 | static int corgi_spk_func; | ||
55 | |||
56 | static void corgi_ext_control(struct snd_soc_codec *codec) | ||
57 | { | ||
58 | int spk = 0, mic = 0, line = 0, hp = 0, hs = 0; | ||
59 | |||
60 | /* set up jack connection */ | ||
61 | switch (corgi_jack_func) { | ||
62 | case CORGI_HP: | ||
63 | hp = 1; | ||
64 | /* set = unmute headphone */ | ||
65 | set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L); | ||
66 | set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R); | ||
67 | break; | ||
68 | case CORGI_MIC: | ||
69 | mic = 1; | ||
70 | /* reset = mute headphone */ | ||
71 | reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L); | ||
72 | reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R); | ||
73 | break; | ||
74 | case CORGI_LINE: | ||
75 | line = 1; | ||
76 | reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L); | ||
77 | reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R); | ||
78 | break; | ||
79 | case CORGI_HEADSET: | ||
80 | hs = 1; | ||
81 | mic = 1; | ||
82 | reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L); | ||
83 | set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R); | ||
84 | break; | ||
85 | } | ||
86 | |||
87 | if (corgi_spk_func == CORGI_SPK_ON) | ||
88 | spk = 1; | ||
89 | |||
90 | /* set the enpoints to their new connetion states */ | ||
91 | snd_soc_dapm_set_endpoint(codec, "Ext Spk", spk); | ||
92 | snd_soc_dapm_set_endpoint(codec, "Mic Jack", mic); | ||
93 | snd_soc_dapm_set_endpoint(codec, "Line Jack", line); | ||
94 | snd_soc_dapm_set_endpoint(codec, "Headphone Jack", hp); | ||
95 | snd_soc_dapm_set_endpoint(codec, "Headset Jack", hs); | ||
96 | |||
97 | /* signal a DAPM event */ | ||
98 | snd_soc_dapm_sync_endpoints(codec); | ||
99 | } | ||
100 | |||
101 | static int corgi_startup(struct snd_pcm_substream *substream) | ||
102 | { | ||
103 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
104 | struct snd_soc_codec *codec = rtd->socdev->codec; | ||
105 | |||
106 | /* check the jack status at stream startup */ | ||
107 | corgi_ext_control(codec); | ||
108 | return 0; | ||
109 | } | ||
110 | |||
111 | /* we need to unmute the HP at shutdown as the mute burns power on corgi */ | ||
112 | static int corgi_shutdown(struct snd_pcm_substream *substream) | ||
113 | { | ||
114 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
115 | struct snd_soc_codec *codec = rtd->socdev->codec; | ||
116 | |||
117 | /* set = unmute headphone */ | ||
118 | set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L); | ||
119 | set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R); | ||
120 | return 0; | ||
121 | } | ||
122 | |||
123 | static int corgi_hw_params(struct snd_pcm_substream *substream, | ||
124 | struct snd_pcm_hw_params *params) | ||
125 | { | ||
126 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
127 | struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; | ||
128 | struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; | ||
129 | unsigned int clk = 0; | ||
130 | int ret = 0; | ||
131 | |||
132 | switch (params_rate(params)) { | ||
133 | case 8000: | ||
134 | case 16000: | ||
135 | case 48000: | ||
136 | case 96000: | ||
137 | clk = 12288000; | ||
138 | break; | ||
139 | case 11025: | ||
140 | case 22050: | ||
141 | case 44100: | ||
142 | clk = 11289600; | ||
143 | break; | ||
144 | } | ||
145 | |||
146 | /* set codec DAI configuration */ | ||
147 | ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | | ||
148 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); | ||
149 | if (ret < 0) | ||
150 | return ret; | ||
151 | |||
152 | /* set cpu DAI configuration */ | ||
153 | ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | | ||
154 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); | ||
155 | if (ret < 0) | ||
156 | return ret; | ||
157 | |||
158 | /* set the codec system clock for DAC and ADC */ | ||
159 | ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8731_SYSCLK, clk, | ||
160 | SND_SOC_CLOCK_IN); | ||
161 | if (ret < 0) | ||
162 | return ret; | ||
163 | |||
164 | /* set the I2S system clock as input (unused) */ | ||
165 | ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0, | ||
166 | SND_SOC_CLOCK_IN); | ||
167 | if (ret < 0) | ||
168 | return ret; | ||
169 | |||
170 | return 0; | ||
171 | } | ||
172 | |||
173 | static struct snd_soc_ops corgi_ops = { | ||
174 | .startup = corgi_startup, | ||
175 | .hw_params = corgi_hw_params, | ||
176 | .shutdown = corgi_shutdown, | ||
177 | }; | ||
178 | |||
179 | static int corgi_get_jack(struct snd_kcontrol *kcontrol, | ||
180 | struct snd_ctl_elem_value *ucontrol) | ||
181 | { | ||
182 | ucontrol->value.integer.value[0] = corgi_jack_func; | ||
183 | return 0; | ||
184 | } | ||
185 | |||
186 | static int corgi_set_jack(struct snd_kcontrol *kcontrol, | ||
187 | struct snd_ctl_elem_value *ucontrol) | ||
188 | { | ||
189 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
190 | |||
191 | if (corgi_jack_func == ucontrol->value.integer.value[0]) | ||
192 | return 0; | ||
193 | |||
194 | corgi_jack_func = ucontrol->value.integer.value[0]; | ||
195 | corgi_ext_control(codec); | ||
196 | return 1; | ||
197 | } | ||
198 | |||
199 | static int corgi_get_spk(struct snd_kcontrol *kcontrol, | ||
200 | struct snd_ctl_elem_value *ucontrol) | ||
201 | { | ||
202 | ucontrol->value.integer.value[0] = corgi_spk_func; | ||
203 | return 0; | ||
204 | } | ||
205 | |||
206 | static int corgi_set_spk(struct snd_kcontrol *kcontrol, | ||
207 | struct snd_ctl_elem_value *ucontrol) | ||
208 | { | ||
209 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
210 | |||
211 | if (corgi_spk_func == ucontrol->value.integer.value[0]) | ||
212 | return 0; | ||
213 | |||
214 | corgi_spk_func = ucontrol->value.integer.value[0]; | ||
215 | corgi_ext_control(codec); | ||
216 | return 1; | ||
217 | } | ||
218 | |||
219 | static int corgi_amp_event(struct snd_soc_dapm_widget *w, int event) | ||
220 | { | ||
221 | if (SND_SOC_DAPM_EVENT_ON(event)) | ||
222 | set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_APM_ON); | ||
223 | else | ||
224 | reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_APM_ON); | ||
225 | |||
226 | return 0; | ||
227 | } | ||
228 | |||
229 | static int corgi_mic_event(struct snd_soc_dapm_widget *w, int event) | ||
230 | { | ||
231 | if (SND_SOC_DAPM_EVENT_ON(event)) | ||
232 | set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MIC_BIAS); | ||
233 | else | ||
234 | reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MIC_BIAS); | ||
235 | |||
236 | return 0; | ||
237 | } | ||
238 | |||
239 | /* corgi machine dapm widgets */ | ||
240 | static const struct snd_soc_dapm_widget wm8731_dapm_widgets[] = { | ||
241 | SND_SOC_DAPM_HP("Headphone Jack", NULL), | ||
242 | SND_SOC_DAPM_MIC("Mic Jack", corgi_mic_event), | ||
243 | SND_SOC_DAPM_SPK("Ext Spk", corgi_amp_event), | ||
244 | SND_SOC_DAPM_LINE("Line Jack", NULL), | ||
245 | SND_SOC_DAPM_HP("Headset Jack", NULL), | ||
246 | }; | ||
247 | |||
248 | /* Corgi machine audio map (connections to the codec pins) */ | ||
249 | static const char *audio_map[][3] = { | ||
250 | |||
251 | /* headset Jack - in = micin, out = LHPOUT*/ | ||
252 | {"Headset Jack", NULL, "LHPOUT"}, | ||
253 | |||
254 | /* headphone connected to LHPOUT1, RHPOUT1 */ | ||
255 | {"Headphone Jack", NULL, "LHPOUT"}, | ||
256 | {"Headphone Jack", NULL, "RHPOUT"}, | ||
257 | |||
258 | /* speaker connected to LOUT, ROUT */ | ||
259 | {"Ext Spk", NULL, "ROUT"}, | ||
260 | {"Ext Spk", NULL, "LOUT"}, | ||
261 | |||
262 | /* mic is connected to MICIN (via right channel of headphone jack) */ | ||
263 | {"MICIN", NULL, "Mic Jack"}, | ||
264 | |||
265 | /* Same as the above but no mic bias for line signals */ | ||
266 | {"MICIN", NULL, "Line Jack"}, | ||
267 | |||
268 | {NULL, NULL, NULL}, | ||
269 | }; | ||
270 | |||
271 | static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset", | ||
272 | "Off"}; | ||
273 | static const char *spk_function[] = {"On", "Off"}; | ||
274 | static const struct soc_enum corgi_enum[] = { | ||
275 | SOC_ENUM_SINGLE_EXT(5, jack_function), | ||
276 | SOC_ENUM_SINGLE_EXT(2, spk_function), | ||
277 | }; | ||
278 | |||
279 | static const struct snd_kcontrol_new wm8731_corgi_controls[] = { | ||
280 | SOC_ENUM_EXT("Jack Function", corgi_enum[0], corgi_get_jack, | ||
281 | corgi_set_jack), | ||
282 | SOC_ENUM_EXT("Speaker Function", corgi_enum[1], corgi_get_spk, | ||
283 | corgi_set_spk), | ||
284 | }; | ||
285 | |||
286 | /* | ||
287 | * Logic for a wm8731 as connected on a Sharp SL-C7x0 Device | ||
288 | */ | ||
289 | static int corgi_wm8731_init(struct snd_soc_codec *codec) | ||
290 | { | ||
291 | int i, err; | ||
292 | |||
293 | snd_soc_dapm_set_endpoint(codec, "LLINEIN", 0); | ||
294 | snd_soc_dapm_set_endpoint(codec, "RLINEIN", 0); | ||
295 | |||
296 | /* Add corgi specific controls */ | ||
297 | for (i = 0; i < ARRAY_SIZE(wm8731_corgi_controls); i++) { | ||
298 | err = snd_ctl_add(codec->card, | ||
299 | snd_soc_cnew(&wm8731_corgi_controls[i],codec, NULL)); | ||
300 | if (err < 0) | ||
301 | return err; | ||
302 | } | ||
303 | |||
304 | /* Add corgi specific widgets */ | ||
305 | for(i = 0; i < ARRAY_SIZE(wm8731_dapm_widgets); i++) { | ||
306 | snd_soc_dapm_new_control(codec, &wm8731_dapm_widgets[i]); | ||
307 | } | ||
308 | |||
309 | /* Set up corgi specific audio path audio_map */ | ||
310 | for(i = 0; audio_map[i][0] != NULL; i++) { | ||
311 | snd_soc_dapm_connect_input(codec, audio_map[i][0], | ||
312 | audio_map[i][1], audio_map[i][2]); | ||
313 | } | ||
314 | |||
315 | snd_soc_dapm_sync_endpoints(codec); | ||
316 | return 0; | ||
317 | } | ||
318 | |||
319 | /* corgi digital audio interface glue - connects codec <--> CPU */ | ||
320 | static struct snd_soc_dai_link corgi_dai = { | ||
321 | .name = "WM8731", | ||
322 | .stream_name = "WM8731", | ||
323 | .cpu_dai = &pxa_i2s_dai, | ||
324 | .codec_dai = &wm8731_dai, | ||
325 | .init = corgi_wm8731_init, | ||
326 | .ops = &corgi_ops, | ||
327 | }; | ||
328 | |||
329 | /* corgi audio machine driver */ | ||
330 | static struct snd_soc_machine snd_soc_machine_corgi = { | ||
331 | .name = "Corgi", | ||
332 | .dai_link = &corgi_dai, | ||
333 | .num_links = 1, | ||
334 | }; | ||
335 | |||
336 | /* corgi audio private data */ | ||
337 | static struct wm8731_setup_data corgi_wm8731_setup = { | ||
338 | .i2c_address = 0x1b, | ||
339 | }; | ||
340 | |||
341 | /* corgi audio subsystem */ | ||
342 | static struct snd_soc_device corgi_snd_devdata = { | ||
343 | .machine = &snd_soc_machine_corgi, | ||
344 | .platform = &pxa2xx_soc_platform, | ||
345 | .codec_dev = &soc_codec_dev_wm8731, | ||
346 | .codec_data = &corgi_wm8731_setup, | ||
347 | }; | ||
348 | |||
349 | static struct platform_device *corgi_snd_device; | ||
350 | |||
351 | static int __init corgi_init(void) | ||
352 | { | ||
353 | int ret; | ||
354 | |||
355 | if (!(machine_is_corgi() || machine_is_shepherd() || machine_is_husky())) | ||
356 | return -ENODEV; | ||
357 | |||
358 | corgi_snd_device = platform_device_alloc("soc-audio", -1); | ||
359 | if (!corgi_snd_device) | ||
360 | return -ENOMEM; | ||
361 | |||
362 | platform_set_drvdata(corgi_snd_device, &corgi_snd_devdata); | ||
363 | corgi_snd_devdata.dev = &corgi_snd_device->dev; | ||
364 | ret = platform_device_add(corgi_snd_device); | ||
365 | |||
366 | if (ret) | ||
367 | platform_device_put(corgi_snd_device); | ||
368 | |||
369 | return ret; | ||
370 | } | ||
371 | |||
372 | static void __exit corgi_exit(void) | ||
373 | { | ||
374 | platform_device_unregister(corgi_snd_device); | ||
375 | } | ||
376 | |||
377 | module_init(corgi_init); | ||
378 | module_exit(corgi_exit); | ||
379 | |||
380 | /* Module information */ | ||
381 | MODULE_AUTHOR("Richard Purdie"); | ||
382 | MODULE_DESCRIPTION("ALSA SoC Corgi"); | ||
383 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/pxa/poodle.c b/sound/soc/pxa/poodle.c new file mode 100644 index 000000000000..0915cf740421 --- /dev/null +++ b/sound/soc/pxa/poodle.c | |||
@@ -0,0 +1,352 @@ | |||
1 | /* | ||
2 | * poodle.c -- SoC audio for Poodle | ||
3 | * | ||
4 | * Copyright 2005 Wolfson Microelectronics PLC. | ||
5 | * Copyright 2005 Openedhand Ltd. | ||
6 | * | ||
7 | * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com> | ||
8 | * Richard Purdie <richard@openedhand.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify it | ||
11 | * under the terms of the GNU General Public License as published by the | ||
12 | * Free Software Foundation; either version 2 of the License, or (at your | ||
13 | * option) any later version. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #include <linux/module.h> | ||
18 | #include <linux/moduleparam.h> | ||
19 | #include <linux/timer.h> | ||
20 | #include <linux/interrupt.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | #include <sound/driver.h> | ||
23 | #include <sound/core.h> | ||
24 | #include <sound/pcm.h> | ||
25 | #include <sound/soc.h> | ||
26 | #include <sound/soc-dapm.h> | ||
27 | |||
28 | #include <asm/mach-types.h> | ||
29 | #include <asm/hardware/locomo.h> | ||
30 | #include <asm/arch/pxa-regs.h> | ||
31 | #include <asm/arch/hardware.h> | ||
32 | #include <asm/arch/poodle.h> | ||
33 | #include <asm/arch/audio.h> | ||
34 | |||
35 | #include "../codecs/wm8731.h" | ||
36 | #include "pxa2xx-pcm.h" | ||
37 | #include "pxa2xx-i2s.h" | ||
38 | |||
39 | #define POODLE_HP 1 | ||
40 | #define POODLE_HP_OFF 0 | ||
41 | #define POODLE_SPK_ON 1 | ||
42 | #define POODLE_SPK_OFF 0 | ||
43 | |||
44 | /* audio clock in Hz - rounded from 12.235MHz */ | ||
45 | #define POODLE_AUDIO_CLOCK 12288000 | ||
46 | |||
47 | static int poodle_jack_func; | ||
48 | static int poodle_spk_func; | ||
49 | |||
50 | static void poodle_ext_control(struct snd_soc_codec *codec) | ||
51 | { | ||
52 | int spk = 0; | ||
53 | |||
54 | /* set up jack connection */ | ||
55 | if (poodle_jack_func == POODLE_HP) { | ||
56 | /* set = unmute headphone */ | ||
57 | locomo_gpio_write(&poodle_locomo_device.dev, | ||
58 | POODLE_LOCOMO_GPIO_MUTE_L, 1); | ||
59 | locomo_gpio_write(&poodle_locomo_device.dev, | ||
60 | POODLE_LOCOMO_GPIO_MUTE_R, 1); | ||
61 | snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 1); | ||
62 | } else { | ||
63 | locomo_gpio_write(&poodle_locomo_device.dev, | ||
64 | POODLE_LOCOMO_GPIO_MUTE_L, 0); | ||
65 | locomo_gpio_write(&poodle_locomo_device.dev, | ||
66 | POODLE_LOCOMO_GPIO_MUTE_R, 0); | ||
67 | snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 0); | ||
68 | } | ||
69 | |||
70 | if (poodle_spk_func == POODLE_SPK_ON) | ||
71 | spk = 1; | ||
72 | |||
73 | /* set the enpoints to their new connetion states */ | ||
74 | snd_soc_dapm_set_endpoint(codec, "Ext Spk", spk); | ||
75 | |||
76 | /* signal a DAPM event */ | ||
77 | snd_soc_dapm_sync_endpoints(codec); | ||
78 | } | ||
79 | |||
80 | static int poodle_startup(struct snd_pcm_substream *substream) | ||
81 | { | ||
82 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
83 | struct snd_soc_codec *codec = rtd->socdev->codec; | ||
84 | |||
85 | /* check the jack status at stream startup */ | ||
86 | poodle_ext_control(codec); | ||
87 | return 0; | ||
88 | } | ||
89 | |||
90 | /* we need to unmute the HP at shutdown as the mute burns power on poodle */ | ||
91 | static int poodle_shutdown(struct snd_pcm_substream *substream) | ||
92 | { | ||
93 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
94 | struct snd_soc_codec *codec = rtd->socdev->codec; | ||
95 | |||
96 | /* set = unmute headphone */ | ||
97 | locomo_gpio_write(&poodle_locomo_device.dev, | ||
98 | POODLE_LOCOMO_GPIO_MUTE_L, 1); | ||
99 | locomo_gpio_write(&poodle_locomo_device.dev, | ||
100 | POODLE_LOCOMO_GPIO_MUTE_R, 1); | ||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | static int poodle_hw_params(struct snd_pcm_substream *substream, | ||
105 | struct snd_pcm_hw_params *params) | ||
106 | { | ||
107 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
108 | struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; | ||
109 | struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; | ||
110 | unsigned int clk = 0; | ||
111 | int ret = 0; | ||
112 | |||
113 | switch (params_rate(params)) { | ||
114 | case 8000: | ||
115 | case 16000: | ||
116 | case 48000: | ||
117 | case 96000: | ||
118 | clk = 12288000; | ||
119 | break; | ||
120 | case 11025: | ||
121 | case 22050: | ||
122 | case 44100: | ||
123 | clk = 11289600; | ||
124 | break; | ||
125 | } | ||
126 | |||
127 | /* set codec DAI configuration */ | ||
128 | ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | | ||
129 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); | ||
130 | if (ret < 0) | ||
131 | return ret; | ||
132 | |||
133 | /* set cpu DAI configuration */ | ||
134 | ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | | ||
135 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); | ||
136 | if (ret < 0) | ||
137 | return ret; | ||
138 | |||
139 | /* set the codec system clock for DAC and ADC */ | ||
140 | ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8731_SYSCLK, clk, | ||
141 | SND_SOC_CLOCK_IN); | ||
142 | if (ret < 0) | ||
143 | return ret; | ||
144 | |||
145 | /* set the I2S system clock as input (unused) */ | ||
146 | ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0, | ||
147 | SND_SOC_CLOCK_IN); | ||
148 | if (ret < 0) | ||
149 | return ret; | ||
150 | |||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | static struct snd_soc_ops poodle_ops = { | ||
155 | .startup = poodle_startup, | ||
156 | .hw_params = poodle_hw_params, | ||
157 | .shutdown = poodle_shutdown, | ||
158 | }; | ||
159 | |||
160 | static int poodle_get_jack(struct snd_kcontrol *kcontrol, | ||
161 | struct snd_ctl_elem_value *ucontrol) | ||
162 | { | ||
163 | ucontrol->value.integer.value[0] = poodle_jack_func; | ||
164 | return 0; | ||
165 | } | ||
166 | |||
167 | static int poodle_set_jack(struct snd_kcontrol *kcontrol, | ||
168 | struct snd_ctl_elem_value *ucontrol) | ||
169 | { | ||
170 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
171 | |||
172 | if (poodle_jack_func == ucontrol->value.integer.value[0]) | ||
173 | return 0; | ||
174 | |||
175 | poodle_jack_func = ucontrol->value.integer.value[0]; | ||
176 | poodle_ext_control(codec); | ||
177 | return 1; | ||
178 | } | ||
179 | |||
180 | static int poodle_get_spk(struct snd_kcontrol *kcontrol, | ||
181 | struct snd_ctl_elem_value *ucontrol) | ||
182 | { | ||
183 | ucontrol->value.integer.value[0] = poodle_spk_func; | ||
184 | return 0; | ||
185 | } | ||
186 | |||
187 | static int poodle_set_spk(struct snd_kcontrol *kcontrol, | ||
188 | struct snd_ctl_elem_value *ucontrol) | ||
189 | { | ||
190 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
191 | |||
192 | if (poodle_spk_func == ucontrol->value.integer.value[0]) | ||
193 | return 0; | ||
194 | |||
195 | poodle_spk_func = ucontrol->value.integer.value[0]; | ||
196 | poodle_ext_control(codec); | ||
197 | return 1; | ||
198 | } | ||
199 | |||
200 | static int poodle_amp_event(struct snd_soc_dapm_widget *w, int event) | ||
201 | { | ||
202 | if (SND_SOC_DAPM_EVENT_ON(event)) | ||
203 | locomo_gpio_write(&poodle_locomo_device.dev, | ||
204 | POODLE_LOCOMO_GPIO_AMP_ON, 0); | ||
205 | else | ||
206 | locomo_gpio_write(&poodle_locomo_device.dev, | ||
207 | POODLE_LOCOMO_GPIO_AMP_ON, 1); | ||
208 | |||
209 | return 0; | ||
210 | } | ||
211 | |||
212 | /* poodle machine dapm widgets */ | ||
213 | static const struct snd_soc_dapm_widget wm8731_dapm_widgets[] = { | ||
214 | SND_SOC_DAPM_HP("Headphone Jack", NULL), | ||
215 | SND_SOC_DAPM_SPK("Ext Spk", poodle_amp_event), | ||
216 | }; | ||
217 | |||
218 | /* Corgi machine audio_mapnections to the codec pins */ | ||
219 | static const char *audio_map[][3] = { | ||
220 | |||
221 | /* headphone connected to LHPOUT1, RHPOUT1 */ | ||
222 | {"Headphone Jack", NULL, "LHPOUT"}, | ||
223 | {"Headphone Jack", NULL, "RHPOUT"}, | ||
224 | |||
225 | /* speaker connected to LOUT, ROUT */ | ||
226 | {"Ext Spk", NULL, "ROUT"}, | ||
227 | {"Ext Spk", NULL, "LOUT"}, | ||
228 | |||
229 | {NULL, NULL, NULL}, | ||
230 | }; | ||
231 | |||
232 | static const char *jack_function[] = {"Off", "Headphone"}; | ||
233 | static const char *spk_function[] = {"Off", "On"}; | ||
234 | static const struct soc_enum poodle_enum[] = { | ||
235 | SOC_ENUM_SINGLE_EXT(2, jack_function), | ||
236 | SOC_ENUM_SINGLE_EXT(2, spk_function), | ||
237 | }; | ||
238 | |||
239 | static const snd_kcontrol_new_t wm8731_poodle_controls[] = { | ||
240 | SOC_ENUM_EXT("Jack Function", poodle_enum[0], poodle_get_jack, | ||
241 | poodle_set_jack), | ||
242 | SOC_ENUM_EXT("Speaker Function", poodle_enum[1], poodle_get_spk, | ||
243 | poodle_set_spk), | ||
244 | }; | ||
245 | |||
246 | /* | ||
247 | * Logic for a wm8731 as connected on a Sharp SL-C7x0 Device | ||
248 | */ | ||
249 | static int poodle_wm8731_init(struct snd_soc_codec *codec) | ||
250 | { | ||
251 | int i, err; | ||
252 | |||
253 | snd_soc_dapm_set_endpoint(codec, "LLINEIN", 0); | ||
254 | snd_soc_dapm_set_endpoint(codec, "RLINEIN", 0); | ||
255 | snd_soc_dapm_set_endpoint(codec, "MICIN", 1); | ||
256 | |||
257 | /* Add poodle specific controls */ | ||
258 | for (i = 0; i < ARRAY_SIZE(wm8731_poodle_controls); i++) { | ||
259 | err = snd_ctl_add(codec->card, | ||
260 | snd_soc_cnew(&wm8731_poodle_controls[i],codec, NULL)); | ||
261 | if (err < 0) | ||
262 | return err; | ||
263 | } | ||
264 | |||
265 | /* Add poodle specific widgets */ | ||
266 | for (i = 0; i < ARRAY_SIZE(wm8731_dapm_widgets); i++) { | ||
267 | snd_soc_dapm_new_control(codec, &wm8731_dapm_widgets[i]); | ||
268 | } | ||
269 | |||
270 | /* Set up poodle specific audio path audio_map */ | ||
271 | for (i = 0; audio_map[i][0] != NULL; i++) { | ||
272 | snd_soc_dapm_connect_input(codec, audio_map[i][0], | ||
273 | audio_map[i][1], audio_map[i][2]); | ||
274 | } | ||
275 | |||
276 | snd_soc_dapm_sync_endpoints(codec); | ||
277 | return 0; | ||
278 | } | ||
279 | |||
280 | /* poodle digital audio interface glue - connects codec <--> CPU */ | ||
281 | static struct snd_soc_dai_link poodle_dai = { | ||
282 | .name = "WM8731", | ||
283 | .stream_name = "WM8731", | ||
284 | .cpu_dai = &pxa_i2s_dai, | ||
285 | .codec_dai = &wm8731_dai, | ||
286 | .init = poodle_wm8731_init, | ||
287 | .ops = &poodle_ops, | ||
288 | }; | ||
289 | |||
290 | /* poodle audio machine driver */ | ||
291 | static struct snd_soc_machine snd_soc_machine_poodle = { | ||
292 | .name = "Poodle", | ||
293 | .dai_link = &poodle_dai, | ||
294 | .num_links = 1, | ||
295 | }; | ||
296 | |||
297 | /* poodle audio private data */ | ||
298 | static struct wm8731_setup_data poodle_wm8731_setup = { | ||
299 | .i2c_address = 0x1b, | ||
300 | }; | ||
301 | |||
302 | /* poodle audio subsystem */ | ||
303 | static struct snd_soc_device poodle_snd_devdata = { | ||
304 | .machine = &snd_soc_machine_poodle, | ||
305 | .platform = &pxa2xx_soc_platform, | ||
306 | .codec_dev = &soc_codec_dev_wm8731, | ||
307 | .codec_data = &poodle_wm8731_setup, | ||
308 | }; | ||
309 | |||
310 | static struct platform_device *poodle_snd_device; | ||
311 | |||
312 | static int __init poodle_init(void) | ||
313 | { | ||
314 | int ret; | ||
315 | |||
316 | if (!machine_is_poodle()) | ||
317 | return -ENODEV; | ||
318 | |||
319 | locomo_gpio_set_dir(&poodle_locomo_device.dev, | ||
320 | POODLE_LOCOMO_GPIO_AMP_ON, 0); | ||
321 | /* should we mute HP at startup - burning power ?*/ | ||
322 | locomo_gpio_set_dir(&poodle_locomo_device.dev, | ||
323 | POODLE_LOCOMO_GPIO_MUTE_L, 0); | ||
324 | locomo_gpio_set_dir(&poodle_locomo_device.dev, | ||
325 | POODLE_LOCOMO_GPIO_MUTE_R, 0); | ||
326 | |||
327 | poodle_snd_device = platform_device_alloc("soc-audio", -1); | ||
328 | if (!poodle_snd_device) | ||
329 | return -ENOMEM; | ||
330 | |||
331 | platform_set_drvdata(poodle_snd_device, &poodle_snd_devdata); | ||
332 | poodle_snd_devdata.dev = &poodle_snd_device->dev; | ||
333 | ret = platform_device_add(poodle_snd_device); | ||
334 | |||
335 | if (ret) | ||
336 | platform_device_put(poodle_snd_device); | ||
337 | |||
338 | return ret; | ||
339 | } | ||
340 | |||
341 | static void __exit poodle_exit(void) | ||
342 | { | ||
343 | platform_device_unregister(poodle_snd_device); | ||
344 | } | ||
345 | |||
346 | module_init(poodle_init); | ||
347 | module_exit(poodle_exit); | ||
348 | |||
349 | /* Module information */ | ||
350 | MODULE_AUTHOR("Richard Purdie"); | ||
351 | MODULE_DESCRIPTION("ALSA SoC Poodle"); | ||
352 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c new file mode 100644 index 000000000000..1bbbeff84ef0 --- /dev/null +++ b/sound/soc/pxa/pxa2xx-ac97.c | |||
@@ -0,0 +1,431 @@ | |||
1 | /* | ||
2 | * linux/sound/pxa2xx-ac97.c -- AC97 support for the Intel PXA2xx chip. | ||
3 | * | ||
4 | * Author: Nicolas Pitre | ||
5 | * Created: Dec 02, 2004 | ||
6 | * Copyright: MontaVista Software Inc. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/init.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/platform_device.h> | ||
16 | #include <linux/interrupt.h> | ||
17 | #include <linux/wait.h> | ||
18 | #include <linux/delay.h> | ||
19 | |||
20 | #include <sound/driver.h> | ||
21 | #include <sound/core.h> | ||
22 | #include <sound/pcm.h> | ||
23 | #include <sound/ac97_codec.h> | ||
24 | #include <sound/initval.h> | ||
25 | #include <sound/soc.h> | ||
26 | |||
27 | #include <asm/irq.h> | ||
28 | #include <linux/mutex.h> | ||
29 | #include <asm/hardware.h> | ||
30 | #include <asm/arch/pxa-regs.h> | ||
31 | #include <asm/arch/audio.h> | ||
32 | |||
33 | #include "pxa2xx-pcm.h" | ||
34 | #include "pxa2xx-ac97.h" | ||
35 | |||
36 | static DEFINE_MUTEX(car_mutex); | ||
37 | static DECLARE_WAIT_QUEUE_HEAD(gsr_wq); | ||
38 | static volatile long gsr_bits; | ||
39 | |||
40 | /* | ||
41 | * Beware PXA27x bugs: | ||
42 | * | ||
43 | * o Slot 12 read from modem space will hang controller. | ||
44 | * o CDONE, SDONE interrupt fails after any slot 12 IO. | ||
45 | * | ||
46 | * We therefore have an hybrid approach for waiting on SDONE (interrupt or | ||
47 | * 1 jiffy timeout if interrupt never comes). | ||
48 | */ | ||
49 | |||
50 | static unsigned short pxa2xx_ac97_read(struct snd_ac97 *ac97, | ||
51 | unsigned short reg) | ||
52 | { | ||
53 | unsigned short val = -1; | ||
54 | volatile u32 *reg_addr; | ||
55 | |||
56 | mutex_lock(&car_mutex); | ||
57 | |||
58 | /* set up primary or secondary codec/modem space */ | ||
59 | #ifdef CONFIG_PXA27x | ||
60 | reg_addr = ac97->num ? &SAC_REG_BASE : &PAC_REG_BASE; | ||
61 | #else | ||
62 | if (reg == AC97_GPIO_STATUS) | ||
63 | reg_addr = ac97->num ? &SMC_REG_BASE : &PMC_REG_BASE; | ||
64 | else | ||
65 | reg_addr = ac97->num ? &SAC_REG_BASE : &PAC_REG_BASE; | ||
66 | #endif | ||
67 | reg_addr += (reg >> 1); | ||
68 | |||
69 | #ifndef CONFIG_PXA27x | ||
70 | if (reg == AC97_GPIO_STATUS) { | ||
71 | /* read from controller cache */ | ||
72 | val = *reg_addr; | ||
73 | goto out; | ||
74 | } | ||
75 | #endif | ||
76 | |||
77 | /* start read access across the ac97 link */ | ||
78 | GSR = GSR_CDONE | GSR_SDONE; | ||
79 | gsr_bits = 0; | ||
80 | val = *reg_addr; | ||
81 | |||
82 | wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_SDONE, 1); | ||
83 | if (!((GSR | gsr_bits) & GSR_SDONE)) { | ||
84 | printk(KERN_ERR "%s: read error (ac97_reg=%x GSR=%#lx)\n", | ||
85 | __FUNCTION__, reg, GSR | gsr_bits); | ||
86 | val = -1; | ||
87 | goto out; | ||
88 | } | ||
89 | |||
90 | /* valid data now */ | ||
91 | GSR = GSR_CDONE | GSR_SDONE; | ||
92 | gsr_bits = 0; | ||
93 | val = *reg_addr; | ||
94 | /* but we've just started another cycle... */ | ||
95 | wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_SDONE, 1); | ||
96 | |||
97 | out: mutex_unlock(&car_mutex); | ||
98 | return val; | ||
99 | } | ||
100 | |||
101 | static void pxa2xx_ac97_write(struct snd_ac97 *ac97, unsigned short reg, | ||
102 | unsigned short val) | ||
103 | { | ||
104 | volatile u32 *reg_addr; | ||
105 | |||
106 | mutex_lock(&car_mutex); | ||
107 | |||
108 | /* set up primary or secondary codec/modem space */ | ||
109 | #ifdef CONFIG_PXA27x | ||
110 | reg_addr = ac97->num ? &SAC_REG_BASE : &PAC_REG_BASE; | ||
111 | #else | ||
112 | if (reg == AC97_GPIO_STATUS) | ||
113 | reg_addr = ac97->num ? &SMC_REG_BASE : &PMC_REG_BASE; | ||
114 | else | ||
115 | reg_addr = ac97->num ? &SAC_REG_BASE : &PAC_REG_BASE; | ||
116 | #endif | ||
117 | reg_addr += (reg >> 1); | ||
118 | |||
119 | GSR = GSR_CDONE | GSR_SDONE; | ||
120 | gsr_bits = 0; | ||
121 | *reg_addr = val; | ||
122 | wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_CDONE, 1); | ||
123 | if (!((GSR | gsr_bits) & GSR_CDONE)) | ||
124 | printk(KERN_ERR "%s: write error (ac97_reg=%x GSR=%#lx)\n", | ||
125 | __FUNCTION__, reg, GSR | gsr_bits); | ||
126 | |||
127 | mutex_unlock(&car_mutex); | ||
128 | } | ||
129 | |||
130 | static void pxa2xx_ac97_warm_reset(struct snd_ac97 *ac97) | ||
131 | { | ||
132 | gsr_bits = 0; | ||
133 | |||
134 | #ifdef CONFIG_PXA27x | ||
135 | /* warm reset broken on Bulverde, | ||
136 | so manually keep AC97 reset high */ | ||
137 | pxa_gpio_mode(113 | GPIO_OUT | GPIO_DFLT_HIGH); | ||
138 | udelay(10); | ||
139 | GCR |= GCR_WARM_RST; | ||
140 | pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT); | ||
141 | udelay(500); | ||
142 | #else | ||
143 | GCR |= GCR_WARM_RST | GCR_PRIRDY_IEN | GCR_SECRDY_IEN; | ||
144 | wait_event_timeout(gsr_wq, gsr_bits & (GSR_PCR | GSR_SCR), 1); | ||
145 | #endif | ||
146 | |||
147 | if (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR))) | ||
148 | printk(KERN_INFO "%s: warm reset timeout (GSR=%#lx)\n", | ||
149 | __FUNCTION__, gsr_bits); | ||
150 | |||
151 | GCR &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN); | ||
152 | GCR |= GCR_SDONE_IE|GCR_CDONE_IE; | ||
153 | } | ||
154 | |||
155 | static void pxa2xx_ac97_cold_reset(struct snd_ac97 *ac97) | ||
156 | { | ||
157 | GCR &= GCR_COLD_RST; /* clear everything but nCRST */ | ||
158 | GCR &= ~GCR_COLD_RST; /* then assert nCRST */ | ||
159 | |||
160 | gsr_bits = 0; | ||
161 | #ifdef CONFIG_PXA27x | ||
162 | /* PXA27x Developers Manual section 13.5.2.2.1 */ | ||
163 | pxa_set_cken(1 << 31, 1); | ||
164 | udelay(5); | ||
165 | pxa_set_cken(1 << 31, 0); | ||
166 | GCR = GCR_COLD_RST; | ||
167 | udelay(50); | ||
168 | #else | ||
169 | GCR = GCR_COLD_RST; | ||
170 | GCR |= GCR_CDONE_IE|GCR_SDONE_IE; | ||
171 | wait_event_timeout(gsr_wq, gsr_bits & (GSR_PCR | GSR_SCR), 1); | ||
172 | #endif | ||
173 | |||
174 | if (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR))) | ||
175 | printk(KERN_INFO "%s: cold reset timeout (GSR=%#lx)\n", | ||
176 | __FUNCTION__, gsr_bits); | ||
177 | |||
178 | GCR &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN); | ||
179 | GCR |= GCR_SDONE_IE|GCR_CDONE_IE; | ||
180 | } | ||
181 | |||
182 | static irqreturn_t pxa2xx_ac97_irq(int irq, void *dev_id) | ||
183 | { | ||
184 | long status; | ||
185 | |||
186 | status = GSR; | ||
187 | if (status) { | ||
188 | GSR = status; | ||
189 | gsr_bits |= status; | ||
190 | wake_up(&gsr_wq); | ||
191 | |||
192 | #ifdef CONFIG_PXA27x | ||
193 | /* Although we don't use those we still need to clear them | ||
194 | since they tend to spuriously trigger when MMC is used | ||
195 | (hardware bug? go figure)... */ | ||
196 | MISR = MISR_EOC; | ||
197 | PISR = PISR_EOC; | ||
198 | MCSR = MCSR_EOC; | ||
199 | #endif | ||
200 | |||
201 | return IRQ_HANDLED; | ||
202 | } | ||
203 | |||
204 | return IRQ_NONE; | ||
205 | } | ||
206 | |||
207 | struct snd_ac97_bus_ops soc_ac97_ops = { | ||
208 | .read = pxa2xx_ac97_read, | ||
209 | .write = pxa2xx_ac97_write, | ||
210 | .warm_reset = pxa2xx_ac97_warm_reset, | ||
211 | .reset = pxa2xx_ac97_cold_reset, | ||
212 | }; | ||
213 | |||
214 | static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_stereo_out = { | ||
215 | .name = "AC97 PCM Stereo out", | ||
216 | .dev_addr = __PREG(PCDR), | ||
217 | .drcmr = &DRCMRTXPCDR, | ||
218 | .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | | ||
219 | DCMD_BURST32 | DCMD_WIDTH4, | ||
220 | }; | ||
221 | |||
222 | static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_stereo_in = { | ||
223 | .name = "AC97 PCM Stereo in", | ||
224 | .dev_addr = __PREG(PCDR), | ||
225 | .drcmr = &DRCMRRXPCDR, | ||
226 | .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | | ||
227 | DCMD_BURST32 | DCMD_WIDTH4, | ||
228 | }; | ||
229 | |||
230 | static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_aux_mono_out = { | ||
231 | .name = "AC97 Aux PCM (Slot 5) Mono out", | ||
232 | .dev_addr = __PREG(MODR), | ||
233 | .drcmr = &DRCMRTXMODR, | ||
234 | .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | | ||
235 | DCMD_BURST16 | DCMD_WIDTH2, | ||
236 | }; | ||
237 | |||
238 | static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_aux_mono_in = { | ||
239 | .name = "AC97 Aux PCM (Slot 5) Mono in", | ||
240 | .dev_addr = __PREG(MODR), | ||
241 | .drcmr = &DRCMRRXMODR, | ||
242 | .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | | ||
243 | DCMD_BURST16 | DCMD_WIDTH2, | ||
244 | }; | ||
245 | |||
246 | static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_mic_mono_in = { | ||
247 | .name = "AC97 Mic PCM (Slot 6) Mono in", | ||
248 | .dev_addr = __PREG(MCDR), | ||
249 | .drcmr = &DRCMRRXMCDR, | ||
250 | .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | | ||
251 | DCMD_BURST16 | DCMD_WIDTH2, | ||
252 | }; | ||
253 | |||
254 | #ifdef CONFIG_PM | ||
255 | static int pxa2xx_ac97_suspend(struct platform_device *pdev, | ||
256 | struct snd_soc_cpu_dai *dai) | ||
257 | { | ||
258 | GCR |= GCR_ACLINK_OFF; | ||
259 | pxa_set_cken(CKEN2_AC97, 0); | ||
260 | return 0; | ||
261 | } | ||
262 | |||
263 | static int pxa2xx_ac97_resume(struct platform_device *pdev, | ||
264 | struct snd_soc_cpu_dai *dai) | ||
265 | { | ||
266 | pxa_gpio_mode(GPIO31_SYNC_AC97_MD); | ||
267 | pxa_gpio_mode(GPIO30_SDATA_OUT_AC97_MD); | ||
268 | pxa_gpio_mode(GPIO28_BITCLK_AC97_MD); | ||
269 | pxa_gpio_mode(GPIO29_SDATA_IN_AC97_MD); | ||
270 | #ifdef CONFIG_PXA27x | ||
271 | /* Use GPIO 113 as AC97 Reset on Bulverde */ | ||
272 | pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT); | ||
273 | #endif | ||
274 | pxa_set_cken(CKEN2_AC97, 1); | ||
275 | return 0; | ||
276 | } | ||
277 | |||
278 | #else | ||
279 | #define pxa2xx_ac97_suspend NULL | ||
280 | #define pxa2xx_ac97_resume NULL | ||
281 | #endif | ||
282 | |||
283 | static int pxa2xx_ac97_probe(struct platform_device *pdev) | ||
284 | { | ||
285 | int ret; | ||
286 | |||
287 | ret = request_irq(IRQ_AC97, pxa2xx_ac97_irq, IRQF_DISABLED, "AC97", NULL); | ||
288 | if (ret < 0) | ||
289 | goto err; | ||
290 | |||
291 | pxa_gpio_mode(GPIO31_SYNC_AC97_MD); | ||
292 | pxa_gpio_mode(GPIO30_SDATA_OUT_AC97_MD); | ||
293 | pxa_gpio_mode(GPIO28_BITCLK_AC97_MD); | ||
294 | pxa_gpio_mode(GPIO29_SDATA_IN_AC97_MD); | ||
295 | #ifdef CONFIG_PXA27x | ||
296 | /* Use GPIO 113 as AC97 Reset on Bulverde */ | ||
297 | pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT); | ||
298 | #endif | ||
299 | pxa_set_cken(CKEN2_AC97, 1); | ||
300 | return 0; | ||
301 | |||
302 | err: | ||
303 | if (CKEN & CKEN2_AC97) { | ||
304 | GCR |= GCR_ACLINK_OFF; | ||
305 | free_irq(IRQ_AC97, NULL); | ||
306 | pxa_set_cken(CKEN2_AC97, 0); | ||
307 | } | ||
308 | return ret; | ||
309 | } | ||
310 | |||
311 | static void pxa2xx_ac97_remove(struct platform_device *pdev) | ||
312 | { | ||
313 | GCR |= GCR_ACLINK_OFF; | ||
314 | free_irq(IRQ_AC97, NULL); | ||
315 | pxa_set_cken(CKEN2_AC97, 0); | ||
316 | } | ||
317 | |||
318 | static int pxa2xx_ac97_hw_params(struct snd_pcm_substream *substream, | ||
319 | struct snd_pcm_hw_params *params) | ||
320 | { | ||
321 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
322 | struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; | ||
323 | |||
324 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
325 | cpu_dai->dma_data = &pxa2xx_ac97_pcm_stereo_out; | ||
326 | else | ||
327 | cpu_dai->dma_data = &pxa2xx_ac97_pcm_stereo_in; | ||
328 | |||
329 | return 0; | ||
330 | } | ||
331 | |||
332 | static int pxa2xx_ac97_hw_aux_params(struct snd_pcm_substream *substream, | ||
333 | struct snd_pcm_hw_params *params) | ||
334 | { | ||
335 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
336 | struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; | ||
337 | |||
338 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
339 | cpu_dai->dma_data = &pxa2xx_ac97_pcm_aux_mono_out; | ||
340 | else | ||
341 | cpu_dai->dma_data = &pxa2xx_ac97_pcm_aux_mono_in; | ||
342 | |||
343 | return 0; | ||
344 | } | ||
345 | |||
346 | static int pxa2xx_ac97_hw_mic_params(struct snd_pcm_substream *substream, | ||
347 | struct snd_pcm_hw_params *params) | ||
348 | { | ||
349 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
350 | struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; | ||
351 | |||
352 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
353 | return -ENODEV; | ||
354 | else | ||
355 | cpu_dai->dma_data = &pxa2xx_ac97_pcm_mic_mono_in; | ||
356 | |||
357 | return 0; | ||
358 | } | ||
359 | |||
360 | #define PXA2XX_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ | ||
361 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \ | ||
362 | SNDRV_PCM_RATE_48000) | ||
363 | |||
364 | /* | ||
365 | * There is only 1 physical AC97 interface for pxa2xx, but it | ||
366 | * has extra fifo's that can be used for aux DACs and ADCs. | ||
367 | */ | ||
368 | struct snd_soc_cpu_dai pxa_ac97_dai[] = { | ||
369 | { | ||
370 | .name = "pxa2xx-ac97", | ||
371 | .id = 0, | ||
372 | .type = SND_SOC_DAI_AC97, | ||
373 | .probe = pxa2xx_ac97_probe, | ||
374 | .remove = pxa2xx_ac97_remove, | ||
375 | .suspend = pxa2xx_ac97_suspend, | ||
376 | .resume = pxa2xx_ac97_resume, | ||
377 | .playback = { | ||
378 | .stream_name = "AC97 Playback", | ||
379 | .channels_min = 2, | ||
380 | .channels_max = 2, | ||
381 | .rates = PXA2XX_AC97_RATES, | ||
382 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | ||
383 | .capture = { | ||
384 | .stream_name = "AC97 Capture", | ||
385 | .channels_min = 2, | ||
386 | .channels_max = 2, | ||
387 | .rates = PXA2XX_AC97_RATES, | ||
388 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | ||
389 | .ops = { | ||
390 | .hw_params = pxa2xx_ac97_hw_params,}, | ||
391 | }, | ||
392 | { | ||
393 | .name = "pxa2xx-ac97-aux", | ||
394 | .id = 1, | ||
395 | .type = SND_SOC_DAI_AC97, | ||
396 | .playback = { | ||
397 | .stream_name = "AC97 Aux Playback", | ||
398 | .channels_min = 1, | ||
399 | .channels_max = 1, | ||
400 | .rates = PXA2XX_AC97_RATES, | ||
401 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | ||
402 | .capture = { | ||
403 | .stream_name = "AC97 Aux Capture", | ||
404 | .channels_min = 1, | ||
405 | .channels_max = 1, | ||
406 | .rates = PXA2XX_AC97_RATES, | ||
407 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | ||
408 | .ops = { | ||
409 | .hw_params = pxa2xx_ac97_hw_aux_params,}, | ||
410 | }, | ||
411 | { | ||
412 | .name = "pxa2xx-ac97-mic", | ||
413 | .id = 2, | ||
414 | .type = SND_SOC_DAI_AC97, | ||
415 | .capture = { | ||
416 | .stream_name = "AC97 Mic Capture", | ||
417 | .channels_min = 1, | ||
418 | .channels_max = 1, | ||
419 | .rates = PXA2XX_AC97_RATES, | ||
420 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | ||
421 | .ops = { | ||
422 | .hw_params = pxa2xx_ac97_hw_mic_params,}, | ||
423 | }, | ||
424 | }; | ||
425 | |||
426 | EXPORT_SYMBOL_GPL(pxa_ac97_dai); | ||
427 | EXPORT_SYMBOL_GPL(soc_ac97_ops); | ||
428 | |||
429 | MODULE_AUTHOR("Nicolas Pitre"); | ||
430 | MODULE_DESCRIPTION("AC97 driver for the Intel PXA2xx chip"); | ||
431 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/pxa/pxa2xx-ac97.h b/sound/soc/pxa/pxa2xx-ac97.h new file mode 100644 index 000000000000..4c4b882316ac --- /dev/null +++ b/sound/soc/pxa/pxa2xx-ac97.h | |||
@@ -0,0 +1,22 @@ | |||
1 | /* | ||
2 | * linux/sound/arm/pxa2xx-ac97.h | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #ifndef _PXA2XX_AC97_H | ||
10 | #define _PXA2XX_AC97_H | ||
11 | |||
12 | /* pxa2xx DAI ID's */ | ||
13 | #define PXA2XX_DAI_AC97_HIFI 0 | ||
14 | #define PXA2XX_DAI_AC97_AUX 1 | ||
15 | #define PXA2XX_DAI_AC97_MIC 2 | ||
16 | |||
17 | extern struct snd_soc_cpu_dai pxa_ac97_dai[3]; | ||
18 | |||
19 | /* platform data */ | ||
20 | extern struct snd_ac97_bus_ops pxa2xx_ac97_ops; | ||
21 | |||
22 | #endif | ||
diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c new file mode 100644 index 000000000000..575a6137c040 --- /dev/null +++ b/sound/soc/pxa/pxa2xx-i2s.c | |||
@@ -0,0 +1,318 @@ | |||
1 | /* | ||
2 | * pxa2xx-i2s.c -- ALSA Soc Audio Layer | ||
3 | * | ||
4 | * Copyright 2005 Wolfson Microelectronics PLC. | ||
5 | * Author: Liam Girdwood | ||
6 | * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | * | ||
13 | * Revision history | ||
14 | * 12th Aug 2005 Initial version. | ||
15 | */ | ||
16 | |||
17 | #include <linux/init.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/device.h> | ||
20 | #include <linux/delay.h> | ||
21 | #include <sound/driver.h> | ||
22 | #include <sound/core.h> | ||
23 | #include <sound/pcm.h> | ||
24 | #include <sound/initval.h> | ||
25 | #include <sound/soc.h> | ||
26 | |||
27 | #include <asm/hardware.h> | ||
28 | #include <asm/arch/pxa-regs.h> | ||
29 | #include <asm/arch/audio.h> | ||
30 | |||
31 | #include "pxa2xx-pcm.h" | ||
32 | #include "pxa2xx-i2s.h" | ||
33 | |||
34 | struct pxa_i2s_port { | ||
35 | u32 sadiv; | ||
36 | u32 sacr0; | ||
37 | u32 sacr1; | ||
38 | u32 saimr; | ||
39 | int master; | ||
40 | u32 fmt; | ||
41 | }; | ||
42 | static struct pxa_i2s_port pxa_i2s; | ||
43 | |||
44 | static struct pxa2xx_pcm_dma_params pxa2xx_i2s_pcm_stereo_out = { | ||
45 | .name = "I2S PCM Stereo out", | ||
46 | .dev_addr = __PREG(SADR), | ||
47 | .drcmr = &DRCMRTXSADR, | ||
48 | .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | | ||
49 | DCMD_BURST32 | DCMD_WIDTH4, | ||
50 | }; | ||
51 | |||
52 | static struct pxa2xx_pcm_dma_params pxa2xx_i2s_pcm_stereo_in = { | ||
53 | .name = "I2S PCM Stereo in", | ||
54 | .dev_addr = __PREG(SADR), | ||
55 | .drcmr = &DRCMRRXSADR, | ||
56 | .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | | ||
57 | DCMD_BURST32 | DCMD_WIDTH4, | ||
58 | }; | ||
59 | |||
60 | static struct pxa2xx_gpio gpio_bus[] = { | ||
61 | { /* I2S SoC Slave */ | ||
62 | .rx = GPIO29_SDATA_IN_I2S_MD, | ||
63 | .tx = GPIO30_SDATA_OUT_I2S_MD, | ||
64 | .clk = GPIO28_BITCLK_IN_I2S_MD, | ||
65 | .frm = GPIO31_SYNC_I2S_MD, | ||
66 | }, | ||
67 | { /* I2S SoC Master */ | ||
68 | #ifdef CONFIG_PXA27x | ||
69 | .sys = GPIO113_I2S_SYSCLK_MD, | ||
70 | #else | ||
71 | .sys = GPIO32_SYSCLK_I2S_MD, | ||
72 | #endif | ||
73 | .rx = GPIO29_SDATA_IN_I2S_MD, | ||
74 | .tx = GPIO30_SDATA_OUT_I2S_MD, | ||
75 | .clk = GPIO28_BITCLK_OUT_I2S_MD, | ||
76 | .frm = GPIO31_SYNC_I2S_MD, | ||
77 | }, | ||
78 | }; | ||
79 | |||
80 | static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream) | ||
81 | { | ||
82 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
83 | struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; | ||
84 | |||
85 | if (!cpu_dai->active) { | ||
86 | SACR0 |= SACR0_RST; | ||
87 | SACR0 = 0; | ||
88 | } | ||
89 | |||
90 | return 0; | ||
91 | } | ||
92 | |||
93 | /* wait for I2S controller to be ready */ | ||
94 | static int pxa_i2s_wait(void) | ||
95 | { | ||
96 | int i; | ||
97 | |||
98 | /* flush the Rx FIFO */ | ||
99 | for(i = 0; i < 16; i++) | ||
100 | SADR; | ||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | static int pxa2xx_i2s_set_dai_fmt(struct snd_soc_cpu_dai *cpu_dai, | ||
105 | unsigned int fmt) | ||
106 | { | ||
107 | /* interface format */ | ||
108 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
109 | case SND_SOC_DAIFMT_I2S: | ||
110 | pxa_i2s.fmt = 0; | ||
111 | break; | ||
112 | case SND_SOC_DAIFMT_LEFT_J: | ||
113 | pxa_i2s.fmt = SACR1_AMSL; | ||
114 | break; | ||
115 | } | ||
116 | |||
117 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
118 | case SND_SOC_DAIFMT_CBS_CFS: | ||
119 | pxa_i2s.master = 1; | ||
120 | break; | ||
121 | case SND_SOC_DAIFMT_CBM_CFS: | ||
122 | pxa_i2s.master = 0; | ||
123 | break; | ||
124 | default: | ||
125 | break; | ||
126 | } | ||
127 | return 0; | ||
128 | } | ||
129 | |||
130 | static int pxa2xx_i2s_set_dai_sysclk(struct snd_soc_cpu_dai *cpu_dai, | ||
131 | int clk_id, unsigned int freq, int dir) | ||
132 | { | ||
133 | if (clk_id != PXA2XX_I2S_SYSCLK) | ||
134 | return -ENODEV; | ||
135 | |||
136 | if (pxa_i2s.master && dir == SND_SOC_CLOCK_OUT) | ||
137 | pxa_gpio_mode(gpio_bus[pxa_i2s.master].sys); | ||
138 | |||
139 | return 0; | ||
140 | } | ||
141 | |||
142 | static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream, | ||
143 | struct snd_pcm_hw_params *params) | ||
144 | { | ||
145 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
146 | struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; | ||
147 | |||
148 | pxa_gpio_mode(gpio_bus[pxa_i2s.master].rx); | ||
149 | pxa_gpio_mode(gpio_bus[pxa_i2s.master].tx); | ||
150 | pxa_gpio_mode(gpio_bus[pxa_i2s.master].frm); | ||
151 | pxa_gpio_mode(gpio_bus[pxa_i2s.master].clk); | ||
152 | pxa_set_cken(CKEN8_I2S, 1); | ||
153 | pxa_i2s_wait(); | ||
154 | |||
155 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
156 | cpu_dai->dma_data = &pxa2xx_i2s_pcm_stereo_out; | ||
157 | else | ||
158 | cpu_dai->dma_data = &pxa2xx_i2s_pcm_stereo_in; | ||
159 | |||
160 | /* is port used by another stream */ | ||
161 | if (!(SACR0 & SACR0_ENB)) { | ||
162 | |||
163 | SACR0 = 0; | ||
164 | SACR1 = 0; | ||
165 | if (pxa_i2s.master) | ||
166 | SACR0 |= SACR0_BCKD; | ||
167 | |||
168 | SACR0 |= SACR0_RFTH(14) | SACR0_TFTH(1); | ||
169 | SACR1 |= pxa_i2s.fmt; | ||
170 | } | ||
171 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
172 | SAIMR |= SAIMR_TFS; | ||
173 | else | ||
174 | SAIMR |= SAIMR_RFS; | ||
175 | |||
176 | switch (params_rate(params)) { | ||
177 | case 8000: | ||
178 | SADIV = 0x48; | ||
179 | break; | ||
180 | case 11025: | ||
181 | SADIV = 0x34; | ||
182 | break; | ||
183 | case 16000: | ||
184 | SADIV = 0x24; | ||
185 | break; | ||
186 | case 22050: | ||
187 | SADIV = 0x1a; | ||
188 | break; | ||
189 | case 44100: | ||
190 | SADIV = 0xd; | ||
191 | break; | ||
192 | case 48000: | ||
193 | SADIV = 0xc; | ||
194 | break; | ||
195 | case 96000: /* not in manual and possibly slightly inaccurate */ | ||
196 | SADIV = 0x6; | ||
197 | break; | ||
198 | } | ||
199 | |||
200 | return 0; | ||
201 | } | ||
202 | |||
203 | static int pxa2xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd) | ||
204 | { | ||
205 | int ret = 0; | ||
206 | |||
207 | switch (cmd) { | ||
208 | case SNDRV_PCM_TRIGGER_START: | ||
209 | SACR0 |= SACR0_ENB; | ||
210 | break; | ||
211 | case SNDRV_PCM_TRIGGER_RESUME: | ||
212 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
213 | case SNDRV_PCM_TRIGGER_STOP: | ||
214 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
215 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
216 | break; | ||
217 | default: | ||
218 | ret = -EINVAL; | ||
219 | } | ||
220 | |||
221 | return ret; | ||
222 | } | ||
223 | |||
224 | static void pxa2xx_i2s_shutdown(struct snd_pcm_substream *substream) | ||
225 | { | ||
226 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
227 | SACR1 |= SACR1_DRPL; | ||
228 | SAIMR &= ~SAIMR_TFS; | ||
229 | } else { | ||
230 | SACR1 |= SACR1_DREC; | ||
231 | SAIMR &= ~SAIMR_RFS; | ||
232 | } | ||
233 | |||
234 | if (SACR1 & (SACR1_DREC | SACR1_DRPL)) { | ||
235 | SACR0 &= ~SACR0_ENB; | ||
236 | pxa_i2s_wait(); | ||
237 | pxa_set_cken(CKEN8_I2S, 0); | ||
238 | } | ||
239 | } | ||
240 | |||
241 | #ifdef CONFIG_PM | ||
242 | static int pxa2xx_i2s_suspend(struct platform_device *dev, | ||
243 | struct snd_soc_cpu_dai *dai) | ||
244 | { | ||
245 | if (!dai->active) | ||
246 | return 0; | ||
247 | |||
248 | /* store registers */ | ||
249 | pxa_i2s.sacr0 = SACR0; | ||
250 | pxa_i2s.sacr1 = SACR1; | ||
251 | pxa_i2s.saimr = SAIMR; | ||
252 | pxa_i2s.sadiv = SADIV; | ||
253 | |||
254 | /* deactivate link */ | ||
255 | SACR0 &= ~SACR0_ENB; | ||
256 | pxa_i2s_wait(); | ||
257 | return 0; | ||
258 | } | ||
259 | |||
260 | static int pxa2xx_i2s_resume(struct platform_device *pdev, | ||
261 | struct snd_soc_cpu_dai *dai) | ||
262 | { | ||
263 | if (!dai->active) | ||
264 | return 0; | ||
265 | |||
266 | pxa_i2s_wait(); | ||
267 | |||
268 | SACR0 = pxa_i2s.sacr0 &= ~SACR0_ENB; | ||
269 | SACR1 = pxa_i2s.sacr1; | ||
270 | SAIMR = pxa_i2s.saimr; | ||
271 | SADIV = pxa_i2s.sadiv; | ||
272 | SACR0 |= SACR0_ENB; | ||
273 | |||
274 | return 0; | ||
275 | } | ||
276 | |||
277 | #else | ||
278 | #define pxa2xx_i2s_suspend NULL | ||
279 | #define pxa2xx_i2s_resume NULL | ||
280 | #endif | ||
281 | |||
282 | #define PXA2XX_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ | ||
283 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \ | ||
284 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000) | ||
285 | |||
286 | struct snd_soc_cpu_dai pxa_i2s_dai = { | ||
287 | .name = "pxa2xx-i2s", | ||
288 | .id = 0, | ||
289 | .type = SND_SOC_DAI_I2S, | ||
290 | .suspend = pxa2xx_i2s_suspend, | ||
291 | .resume = pxa2xx_i2s_resume, | ||
292 | .playback = { | ||
293 | .channels_min = 2, | ||
294 | .channels_max = 2, | ||
295 | .rates = PXA2XX_I2S_RATES, | ||
296 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | ||
297 | .capture = { | ||
298 | .channels_min = 2, | ||
299 | .channels_max = 2, | ||
300 | .rates = PXA2XX_I2S_RATES, | ||
301 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | ||
302 | .ops = { | ||
303 | .startup = pxa2xx_i2s_startup, | ||
304 | .shutdown = pxa2xx_i2s_shutdown, | ||
305 | .trigger = pxa2xx_i2s_trigger, | ||
306 | .hw_params = pxa2xx_i2s_hw_params,}, | ||
307 | .dai_ops = { | ||
308 | .set_fmt = pxa2xx_i2s_set_dai_fmt, | ||
309 | .set_sysclk = pxa2xx_i2s_set_dai_sysclk, | ||
310 | }, | ||
311 | }; | ||
312 | |||
313 | EXPORT_SYMBOL_GPL(pxa_i2s_dai); | ||
314 | |||
315 | /* Module information */ | ||
316 | MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com"); | ||
317 | MODULE_DESCRIPTION("pxa2xx I2S SoC Interface"); | ||
318 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/pxa/pxa2xx-i2s.h b/sound/soc/pxa/pxa2xx-i2s.h new file mode 100644 index 000000000000..a2484f0881f1 --- /dev/null +++ b/sound/soc/pxa/pxa2xx-i2s.h | |||
@@ -0,0 +1,20 @@ | |||
1 | /* | ||
2 | * linux/sound/arm/pxa2xx-i2s.h | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #ifndef _PXA2XX_I2S_H | ||
10 | #define _PXA2XX_I2S_H | ||
11 | |||
12 | /* pxa2xx DAI ID's */ | ||
13 | #define PXA2XX_DAI_I2S 0 | ||
14 | |||
15 | /* I2S clock */ | ||
16 | #define PXA2XX_I2S_SYSCLK 0 | ||
17 | |||
18 | extern struct snd_soc_cpu_dai pxa_i2s_dai; | ||
19 | |||
20 | #endif | ||
diff --git a/sound/soc/pxa/pxa2xx-pcm.c b/sound/soc/pxa/pxa2xx-pcm.c new file mode 100644 index 000000000000..35e8fa3a469c --- /dev/null +++ b/sound/soc/pxa/pxa2xx-pcm.c | |||
@@ -0,0 +1,372 @@ | |||
1 | /* | ||
2 | * linux/sound/arm/pxa2xx-pcm.c -- ALSA PCM interface for the Intel PXA2xx chip | ||
3 | * | ||
4 | * Author: Nicolas Pitre | ||
5 | * Created: Nov 30, 2004 | ||
6 | * Copyright: (C) 2004 MontaVista Software, Inc. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/module.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/platform_device.h> | ||
16 | #include <linux/slab.h> | ||
17 | #include <linux/dma-mapping.h> | ||
18 | |||
19 | #include <sound/driver.h> | ||
20 | #include <sound/core.h> | ||
21 | #include <sound/pcm.h> | ||
22 | #include <sound/pcm_params.h> | ||
23 | #include <sound/soc.h> | ||
24 | |||
25 | #include <asm/dma.h> | ||
26 | #include <asm/hardware.h> | ||
27 | #include <asm/arch/pxa-regs.h> | ||
28 | #include <asm/arch/audio.h> | ||
29 | |||
30 | #include "pxa2xx-pcm.h" | ||
31 | |||
32 | static const struct snd_pcm_hardware pxa2xx_pcm_hardware = { | ||
33 | .info = SNDRV_PCM_INFO_MMAP | | ||
34 | SNDRV_PCM_INFO_MMAP_VALID | | ||
35 | SNDRV_PCM_INFO_INTERLEAVED | | ||
36 | SNDRV_PCM_INFO_PAUSE | | ||
37 | SNDRV_PCM_INFO_RESUME, | ||
38 | .formats = SNDRV_PCM_FMTBIT_S16_LE | | ||
39 | SNDRV_PCM_FMTBIT_S24_LE | | ||
40 | SNDRV_PCM_FMTBIT_S32_LE, | ||
41 | .period_bytes_min = 32, | ||
42 | .period_bytes_max = 8192 - 32, | ||
43 | .periods_min = 1, | ||
44 | .periods_max = PAGE_SIZE/sizeof(pxa_dma_desc), | ||
45 | .buffer_bytes_max = 128 * 1024, | ||
46 | .fifo_size = 32, | ||
47 | }; | ||
48 | |||
49 | struct pxa2xx_runtime_data { | ||
50 | int dma_ch; | ||
51 | struct pxa2xx_pcm_dma_params *params; | ||
52 | pxa_dma_desc *dma_desc_array; | ||
53 | dma_addr_t dma_desc_array_phys; | ||
54 | }; | ||
55 | |||
56 | static void pxa2xx_pcm_dma_irq(int dma_ch, void *dev_id) | ||
57 | { | ||
58 | struct snd_pcm_substream *substream = dev_id; | ||
59 | struct pxa2xx_runtime_data *prtd = substream->runtime->private_data; | ||
60 | int dcsr; | ||
61 | |||
62 | dcsr = DCSR(dma_ch); | ||
63 | DCSR(dma_ch) = dcsr & ~DCSR_STOPIRQEN; | ||
64 | |||
65 | if (dcsr & DCSR_ENDINTR) { | ||
66 | snd_pcm_period_elapsed(substream); | ||
67 | } else { | ||
68 | printk( KERN_ERR "%s: DMA error on channel %d (DCSR=%#x)\n", | ||
69 | prtd->params->name, dma_ch, dcsr ); | ||
70 | } | ||
71 | } | ||
72 | |||
73 | static int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream, | ||
74 | struct snd_pcm_hw_params *params) | ||
75 | { | ||
76 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
77 | struct pxa2xx_runtime_data *prtd = runtime->private_data; | ||
78 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
79 | struct pxa2xx_pcm_dma_params *dma = rtd->dai->cpu_dai->dma_data; | ||
80 | size_t totsize = params_buffer_bytes(params); | ||
81 | size_t period = params_period_bytes(params); | ||
82 | pxa_dma_desc *dma_desc; | ||
83 | dma_addr_t dma_buff_phys, next_desc_phys; | ||
84 | int ret; | ||
85 | |||
86 | /* return if this is a bufferless transfer e.g. | ||
87 | * codec <--> BT codec or GSM modem -- lg FIXME */ | ||
88 | if (!dma) | ||
89 | return 0; | ||
90 | |||
91 | /* this may get called several times by oss emulation | ||
92 | * with different params */ | ||
93 | if (prtd->params == NULL) { | ||
94 | prtd->params = dma; | ||
95 | ret = pxa_request_dma(prtd->params->name, DMA_PRIO_LOW, | ||
96 | pxa2xx_pcm_dma_irq, substream); | ||
97 | if (ret < 0) | ||
98 | return ret; | ||
99 | prtd->dma_ch = ret; | ||
100 | } else if (prtd->params != dma) { | ||
101 | pxa_free_dma(prtd->dma_ch); | ||
102 | prtd->params = dma; | ||
103 | ret = pxa_request_dma(prtd->params->name, DMA_PRIO_LOW, | ||
104 | pxa2xx_pcm_dma_irq, substream); | ||
105 | if (ret < 0) | ||
106 | return ret; | ||
107 | prtd->dma_ch = ret; | ||
108 | } | ||
109 | |||
110 | snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); | ||
111 | runtime->dma_bytes = totsize; | ||
112 | |||
113 | dma_desc = prtd->dma_desc_array; | ||
114 | next_desc_phys = prtd->dma_desc_array_phys; | ||
115 | dma_buff_phys = runtime->dma_addr; | ||
116 | do { | ||
117 | next_desc_phys += sizeof(pxa_dma_desc); | ||
118 | dma_desc->ddadr = next_desc_phys; | ||
119 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
120 | dma_desc->dsadr = dma_buff_phys; | ||
121 | dma_desc->dtadr = prtd->params->dev_addr; | ||
122 | } else { | ||
123 | dma_desc->dsadr = prtd->params->dev_addr; | ||
124 | dma_desc->dtadr = dma_buff_phys; | ||
125 | } | ||
126 | if (period > totsize) | ||
127 | period = totsize; | ||
128 | dma_desc->dcmd = prtd->params->dcmd | period | DCMD_ENDIRQEN; | ||
129 | dma_desc++; | ||
130 | dma_buff_phys += period; | ||
131 | } while (totsize -= period); | ||
132 | dma_desc[-1].ddadr = prtd->dma_desc_array_phys; | ||
133 | |||
134 | return 0; | ||
135 | } | ||
136 | |||
137 | static int pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream) | ||
138 | { | ||
139 | struct pxa2xx_runtime_data *prtd = substream->runtime->private_data; | ||
140 | |||
141 | if (prtd && prtd->params) | ||
142 | *prtd->params->drcmr = 0; | ||
143 | |||
144 | if (prtd->dma_ch) { | ||
145 | snd_pcm_set_runtime_buffer(substream, NULL); | ||
146 | pxa_free_dma(prtd->dma_ch); | ||
147 | prtd->dma_ch = 0; | ||
148 | } | ||
149 | |||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | static int pxa2xx_pcm_prepare(struct snd_pcm_substream *substream) | ||
154 | { | ||
155 | struct pxa2xx_runtime_data *prtd = substream->runtime->private_data; | ||
156 | |||
157 | DCSR(prtd->dma_ch) &= ~DCSR_RUN; | ||
158 | DCSR(prtd->dma_ch) = 0; | ||
159 | DCMD(prtd->dma_ch) = 0; | ||
160 | *prtd->params->drcmr = prtd->dma_ch | DRCMR_MAPVLD; | ||
161 | |||
162 | return 0; | ||
163 | } | ||
164 | |||
165 | static int pxa2xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | ||
166 | { | ||
167 | struct pxa2xx_runtime_data *prtd = substream->runtime->private_data; | ||
168 | int ret = 0; | ||
169 | |||
170 | switch (cmd) { | ||
171 | case SNDRV_PCM_TRIGGER_START: | ||
172 | DDADR(prtd->dma_ch) = prtd->dma_desc_array_phys; | ||
173 | DCSR(prtd->dma_ch) = DCSR_RUN; | ||
174 | break; | ||
175 | |||
176 | case SNDRV_PCM_TRIGGER_STOP: | ||
177 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
178 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
179 | DCSR(prtd->dma_ch) &= ~DCSR_RUN; | ||
180 | break; | ||
181 | |||
182 | case SNDRV_PCM_TRIGGER_RESUME: | ||
183 | DCSR(prtd->dma_ch) |= DCSR_RUN; | ||
184 | break; | ||
185 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
186 | DDADR(prtd->dma_ch) = prtd->dma_desc_array_phys; | ||
187 | DCSR(prtd->dma_ch) |= DCSR_RUN; | ||
188 | break; | ||
189 | |||
190 | default: | ||
191 | ret = -EINVAL; | ||
192 | } | ||
193 | |||
194 | return ret; | ||
195 | } | ||
196 | |||
197 | static snd_pcm_uframes_t | ||
198 | pxa2xx_pcm_pointer(struct snd_pcm_substream *substream) | ||
199 | { | ||
200 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
201 | struct pxa2xx_runtime_data *prtd = runtime->private_data; | ||
202 | |||
203 | dma_addr_t ptr = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? | ||
204 | DSADR(prtd->dma_ch) : DTADR(prtd->dma_ch); | ||
205 | snd_pcm_uframes_t x = bytes_to_frames(runtime, ptr - runtime->dma_addr); | ||
206 | |||
207 | if (x == runtime->buffer_size) | ||
208 | x = 0; | ||
209 | return x; | ||
210 | } | ||
211 | |||
212 | static int pxa2xx_pcm_open(struct snd_pcm_substream *substream) | ||
213 | { | ||
214 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
215 | struct pxa2xx_runtime_data *prtd; | ||
216 | int ret; | ||
217 | |||
218 | snd_soc_set_runtime_hwparams(substream, &pxa2xx_pcm_hardware); | ||
219 | |||
220 | /* | ||
221 | * For mysterious reasons (and despite what the manual says) | ||
222 | * playback samples are lost if the DMA count is not a multiple | ||
223 | * of the DMA burst size. Let's add a rule to enforce that. | ||
224 | */ | ||
225 | ret = snd_pcm_hw_constraint_step(runtime, 0, | ||
226 | SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32); | ||
227 | if (ret) | ||
228 | goto out; | ||
229 | |||
230 | ret = snd_pcm_hw_constraint_step(runtime, 0, | ||
231 | SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32); | ||
232 | if (ret) | ||
233 | goto out; | ||
234 | |||
235 | ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); | ||
236 | if (ret < 0) | ||
237 | goto out; | ||
238 | |||
239 | prtd = kzalloc(sizeof(struct pxa2xx_runtime_data), GFP_KERNEL); | ||
240 | if (prtd == NULL) { | ||
241 | ret = -ENOMEM; | ||
242 | goto out; | ||
243 | } | ||
244 | |||
245 | prtd->dma_desc_array = | ||
246 | dma_alloc_writecombine(substream->pcm->card->dev, PAGE_SIZE, | ||
247 | &prtd->dma_desc_array_phys, GFP_KERNEL); | ||
248 | if (!prtd->dma_desc_array) { | ||
249 | ret = -ENOMEM; | ||
250 | goto err1; | ||
251 | } | ||
252 | |||
253 | runtime->private_data = prtd; | ||
254 | return 0; | ||
255 | |||
256 | err1: | ||
257 | kfree(prtd); | ||
258 | out: | ||
259 | return ret; | ||
260 | } | ||
261 | |||
262 | static int pxa2xx_pcm_close(struct snd_pcm_substream *substream) | ||
263 | { | ||
264 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
265 | struct pxa2xx_runtime_data *prtd = runtime->private_data; | ||
266 | |||
267 | dma_free_writecombine(substream->pcm->card->dev, PAGE_SIZE, | ||
268 | prtd->dma_desc_array, prtd->dma_desc_array_phys); | ||
269 | kfree(prtd); | ||
270 | return 0; | ||
271 | } | ||
272 | |||
273 | static int pxa2xx_pcm_mmap(struct snd_pcm_substream *substream, | ||
274 | struct vm_area_struct *vma) | ||
275 | { | ||
276 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
277 | return dma_mmap_writecombine(substream->pcm->card->dev, vma, | ||
278 | runtime->dma_area, | ||
279 | runtime->dma_addr, | ||
280 | runtime->dma_bytes); | ||
281 | } | ||
282 | |||
283 | struct snd_pcm_ops pxa2xx_pcm_ops = { | ||
284 | .open = pxa2xx_pcm_open, | ||
285 | .close = pxa2xx_pcm_close, | ||
286 | .ioctl = snd_pcm_lib_ioctl, | ||
287 | .hw_params = pxa2xx_pcm_hw_params, | ||
288 | .hw_free = pxa2xx_pcm_hw_free, | ||
289 | .prepare = pxa2xx_pcm_prepare, | ||
290 | .trigger = pxa2xx_pcm_trigger, | ||
291 | .pointer = pxa2xx_pcm_pointer, | ||
292 | .mmap = pxa2xx_pcm_mmap, | ||
293 | }; | ||
294 | |||
295 | static int pxa2xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) | ||
296 | { | ||
297 | struct snd_pcm_substream *substream = pcm->streams[stream].substream; | ||
298 | struct snd_dma_buffer *buf = &substream->dma_buffer; | ||
299 | size_t size = pxa2xx_pcm_hardware.buffer_bytes_max; | ||
300 | buf->dev.type = SNDRV_DMA_TYPE_DEV; | ||
301 | buf->dev.dev = pcm->card->dev; | ||
302 | buf->private_data = NULL; | ||
303 | buf->area = dma_alloc_writecombine(pcm->card->dev, size, | ||
304 | &buf->addr, GFP_KERNEL); | ||
305 | if (!buf->area) | ||
306 | return -ENOMEM; | ||
307 | buf->bytes = size; | ||
308 | return 0; | ||
309 | } | ||
310 | |||
311 | static void pxa2xx_pcm_free_dma_buffers(struct snd_pcm *pcm) | ||
312 | { | ||
313 | struct snd_pcm_substream *substream; | ||
314 | struct snd_dma_buffer *buf; | ||
315 | int stream; | ||
316 | |||
317 | for (stream = 0; stream < 2; stream++) { | ||
318 | substream = pcm->streams[stream].substream; | ||
319 | if (!substream) | ||
320 | continue; | ||
321 | |||
322 | buf = &substream->dma_buffer; | ||
323 | if (!buf->area) | ||
324 | continue; | ||
325 | |||
326 | dma_free_writecombine(pcm->card->dev, buf->bytes, | ||
327 | buf->area, buf->addr); | ||
328 | buf->area = NULL; | ||
329 | } | ||
330 | } | ||
331 | |||
332 | static u64 pxa2xx_pcm_dmamask = DMA_32BIT_MASK; | ||
333 | |||
334 | int pxa2xx_pcm_new(struct snd_card *card, struct snd_soc_codec_dai *dai, | ||
335 | struct snd_pcm *pcm) | ||
336 | { | ||
337 | int ret = 0; | ||
338 | |||
339 | if (!card->dev->dma_mask) | ||
340 | card->dev->dma_mask = &pxa2xx_pcm_dmamask; | ||
341 | if (!card->dev->coherent_dma_mask) | ||
342 | card->dev->coherent_dma_mask = DMA_32BIT_MASK; | ||
343 | |||
344 | if (dai->playback.channels_min) { | ||
345 | ret = pxa2xx_pcm_preallocate_dma_buffer(pcm, | ||
346 | SNDRV_PCM_STREAM_PLAYBACK); | ||
347 | if (ret) | ||
348 | goto out; | ||
349 | } | ||
350 | |||
351 | if (dai->capture.channels_min) { | ||
352 | ret = pxa2xx_pcm_preallocate_dma_buffer(pcm, | ||
353 | SNDRV_PCM_STREAM_CAPTURE); | ||
354 | if (ret) | ||
355 | goto out; | ||
356 | } | ||
357 | out: | ||
358 | return ret; | ||
359 | } | ||
360 | |||
361 | struct snd_soc_platform pxa2xx_soc_platform = { | ||
362 | .name = "pxa2xx-audio", | ||
363 | .pcm_ops = &pxa2xx_pcm_ops, | ||
364 | .pcm_new = pxa2xx_pcm_new, | ||
365 | .pcm_free = pxa2xx_pcm_free_dma_buffers, | ||
366 | }; | ||
367 | |||
368 | EXPORT_SYMBOL_GPL(pxa2xx_soc_platform); | ||
369 | |||
370 | MODULE_AUTHOR("Nicolas Pitre"); | ||
371 | MODULE_DESCRIPTION("Intel PXA2xx PCM DMA module"); | ||
372 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/pxa/pxa2xx-pcm.h b/sound/soc/pxa/pxa2xx-pcm.h new file mode 100644 index 000000000000..54c9c755e508 --- /dev/null +++ b/sound/soc/pxa/pxa2xx-pcm.h | |||
@@ -0,0 +1,34 @@ | |||
1 | /* | ||
2 | * linux/sound/arm/pxa2xx-pcm.h -- ALSA PCM interface for the Intel PXA2xx chip | ||
3 | * | ||
4 | * Author: Nicolas Pitre | ||
5 | * Created: Nov 30, 2004 | ||
6 | * Copyright: MontaVista Software, Inc. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #ifndef _PXA2XX_PCM_H | ||
14 | #define _PXA2XX_PCM_H | ||
15 | |||
16 | struct pxa2xx_pcm_dma_params { | ||
17 | char *name; /* stream identifier */ | ||
18 | u32 dcmd; /* DMA descriptor dcmd field */ | ||
19 | volatile u32 *drcmr; /* the DMA request channel to use */ | ||
20 | u32 dev_addr; /* device physical address for DMA */ | ||
21 | }; | ||
22 | |||
23 | struct pxa2xx_gpio { | ||
24 | u32 sys; | ||
25 | u32 rx; | ||
26 | u32 tx; | ||
27 | u32 clk; | ||
28 | u32 frm; | ||
29 | }; | ||
30 | |||
31 | /* platform data */ | ||
32 | extern struct snd_soc_platform pxa2xx_soc_platform; | ||
33 | |||
34 | #endif | ||
diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c new file mode 100644 index 000000000000..80e82109fef7 --- /dev/null +++ b/sound/soc/pxa/spitz.c | |||
@@ -0,0 +1,394 @@ | |||
1 | /* | ||
2 | * spitz.c -- SoC audio for Sharp SL-Cxx00 models Spitz, Borzoi and Akita | ||
3 | * | ||
4 | * Copyright 2005 Wolfson Microelectronics PLC. | ||
5 | * Copyright 2005 Openedhand Ltd. | ||
6 | * | ||
7 | * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com> | ||
8 | * Richard Purdie <richard@openedhand.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify it | ||
11 | * under the terms of the GNU General Public License as published by the | ||
12 | * Free Software Foundation; either version 2 of the License, or (at your | ||
13 | * option) any later version. | ||
14 | * | ||
15 | * Revision history | ||
16 | * 30th Nov 2005 Initial version. | ||
17 | * | ||
18 | */ | ||
19 | |||
20 | #include <linux/module.h> | ||
21 | #include <linux/moduleparam.h> | ||
22 | #include <linux/timer.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/platform_device.h> | ||
25 | #include <sound/driver.h> | ||
26 | #include <sound/core.h> | ||
27 | #include <sound/pcm.h> | ||
28 | #include <sound/soc.h> | ||
29 | #include <sound/soc-dapm.h> | ||
30 | |||
31 | #include <asm/mach-types.h> | ||
32 | #include <asm/hardware/scoop.h> | ||
33 | #include <asm/arch/pxa-regs.h> | ||
34 | #include <asm/arch/hardware.h> | ||
35 | #include <asm/arch/akita.h> | ||
36 | #include <asm/arch/spitz.h> | ||
37 | #include <asm/mach-types.h> | ||
38 | #include "../codecs/wm8750.h" | ||
39 | #include "pxa2xx-pcm.h" | ||
40 | #include "pxa2xx-i2s.h" | ||
41 | |||
42 | #define SPITZ_HP 0 | ||
43 | #define SPITZ_MIC 1 | ||
44 | #define SPITZ_LINE 2 | ||
45 | #define SPITZ_HEADSET 3 | ||
46 | #define SPITZ_HP_OFF 4 | ||
47 | #define SPITZ_SPK_ON 0 | ||
48 | #define SPITZ_SPK_OFF 1 | ||
49 | |||
50 | /* audio clock in Hz - rounded from 12.235MHz */ | ||
51 | #define SPITZ_AUDIO_CLOCK 12288000 | ||
52 | |||
53 | static int spitz_jack_func; | ||
54 | static int spitz_spk_func; | ||
55 | |||
56 | static void spitz_ext_control(struct snd_soc_codec *codec) | ||
57 | { | ||
58 | if (spitz_spk_func == SPITZ_SPK_ON) | ||
59 | snd_soc_dapm_set_endpoint(codec, "Ext Spk", 1); | ||
60 | else | ||
61 | snd_soc_dapm_set_endpoint(codec, "Ext Spk", 0); | ||
62 | |||
63 | /* set up jack connection */ | ||
64 | switch (spitz_jack_func) { | ||
65 | case SPITZ_HP: | ||
66 | /* enable and unmute hp jack, disable mic bias */ | ||
67 | snd_soc_dapm_set_endpoint(codec, "Headset Jack", 0); | ||
68 | snd_soc_dapm_set_endpoint(codec, "Mic Jack", 0); | ||
69 | snd_soc_dapm_set_endpoint(codec, "Line Jack", 0); | ||
70 | snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 1); | ||
71 | set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L); | ||
72 | set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R); | ||
73 | break; | ||
74 | case SPITZ_MIC: | ||
75 | /* enable mic jack and bias, mute hp */ | ||
76 | snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 0); | ||
77 | snd_soc_dapm_set_endpoint(codec, "Headset Jack", 0); | ||
78 | snd_soc_dapm_set_endpoint(codec, "Line Jack", 0); | ||
79 | snd_soc_dapm_set_endpoint(codec, "Mic Jack", 1); | ||
80 | reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L); | ||
81 | reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R); | ||
82 | break; | ||
83 | case SPITZ_LINE: | ||
84 | /* enable line jack, disable mic bias and mute hp */ | ||
85 | snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 0); | ||
86 | snd_soc_dapm_set_endpoint(codec, "Headset Jack", 0); | ||
87 | snd_soc_dapm_set_endpoint(codec, "Mic Jack", 0); | ||
88 | snd_soc_dapm_set_endpoint(codec, "Line Jack", 1); | ||
89 | reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L); | ||
90 | reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R); | ||
91 | break; | ||
92 | case SPITZ_HEADSET: | ||
93 | /* enable and unmute headset jack enable mic bias, mute L hp */ | ||
94 | snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 0); | ||
95 | snd_soc_dapm_set_endpoint(codec, "Mic Jack", 1); | ||
96 | snd_soc_dapm_set_endpoint(codec, "Line Jack", 0); | ||
97 | snd_soc_dapm_set_endpoint(codec, "Headset Jack", 1); | ||
98 | reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L); | ||
99 | set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R); | ||
100 | break; | ||
101 | case SPITZ_HP_OFF: | ||
102 | |||
103 | /* jack removed, everything off */ | ||
104 | snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 0); | ||
105 | snd_soc_dapm_set_endpoint(codec, "Headset Jack", 0); | ||
106 | snd_soc_dapm_set_endpoint(codec, "Mic Jack", 0); | ||
107 | snd_soc_dapm_set_endpoint(codec, "Line Jack", 0); | ||
108 | reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L); | ||
109 | reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R); | ||
110 | break; | ||
111 | } | ||
112 | snd_soc_dapm_sync_endpoints(codec); | ||
113 | } | ||
114 | |||
115 | static int spitz_startup(struct snd_pcm_substream *substream) | ||
116 | { | ||
117 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
118 | struct snd_soc_codec *codec = rtd->socdev->codec; | ||
119 | |||
120 | /* check the jack status at stream startup */ | ||
121 | spitz_ext_control(codec); | ||
122 | return 0; | ||
123 | } | ||
124 | |||
125 | static int spitz_hw_params(struct snd_pcm_substream *substream, | ||
126 | struct snd_pcm_hw_params *params) | ||
127 | { | ||
128 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
129 | struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; | ||
130 | struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; | ||
131 | unsigned int clk = 0; | ||
132 | int ret = 0; | ||
133 | |||
134 | switch (params_rate(params)) { | ||
135 | case 8000: | ||
136 | case 16000: | ||
137 | case 48000: | ||
138 | case 96000: | ||
139 | clk = 12288000; | ||
140 | break; | ||
141 | case 11025: | ||
142 | case 22050: | ||
143 | case 44100: | ||
144 | clk = 11289600; | ||
145 | break; | ||
146 | } | ||
147 | |||
148 | /* set codec DAI configuration */ | ||
149 | ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | | ||
150 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); | ||
151 | if (ret < 0) | ||
152 | return ret; | ||
153 | |||
154 | /* set cpu DAI configuration */ | ||
155 | ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | | ||
156 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); | ||
157 | if (ret < 0) | ||
158 | return ret; | ||
159 | |||
160 | /* set the codec system clock for DAC and ADC */ | ||
161 | ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8750_SYSCLK, clk, | ||
162 | SND_SOC_CLOCK_IN); | ||
163 | if (ret < 0) | ||
164 | return ret; | ||
165 | |||
166 | /* set the I2S system clock as input (unused) */ | ||
167 | ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0, | ||
168 | SND_SOC_CLOCK_IN); | ||
169 | if (ret < 0) | ||
170 | return ret; | ||
171 | |||
172 | return 0; | ||
173 | } | ||
174 | |||
175 | static struct snd_soc_ops spitz_ops = { | ||
176 | .startup = spitz_startup, | ||
177 | .hw_params = spitz_hw_params, | ||
178 | }; | ||
179 | |||
180 | static int spitz_get_jack(struct snd_kcontrol *kcontrol, | ||
181 | struct snd_ctl_elem_value *ucontrol) | ||
182 | { | ||
183 | ucontrol->value.integer.value[0] = spitz_jack_func; | ||
184 | return 0; | ||
185 | } | ||
186 | |||
187 | static int spitz_set_jack(struct snd_kcontrol *kcontrol, | ||
188 | struct snd_ctl_elem_value *ucontrol) | ||
189 | { | ||
190 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
191 | |||
192 | if (spitz_jack_func == ucontrol->value.integer.value[0]) | ||
193 | return 0; | ||
194 | |||
195 | spitz_jack_func = ucontrol->value.integer.value[0]; | ||
196 | spitz_ext_control(codec); | ||
197 | return 1; | ||
198 | } | ||
199 | |||
200 | static int spitz_get_spk(struct snd_kcontrol *kcontrol, | ||
201 | struct snd_ctl_elem_value *ucontrol) | ||
202 | { | ||
203 | ucontrol->value.integer.value[0] = spitz_spk_func; | ||
204 | return 0; | ||
205 | } | ||
206 | |||
207 | static int spitz_set_spk(struct snd_kcontrol *kcontrol, | ||
208 | struct snd_ctl_elem_value *ucontrol) | ||
209 | { | ||
210 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
211 | |||
212 | if (spitz_spk_func == ucontrol->value.integer.value[0]) | ||
213 | return 0; | ||
214 | |||
215 | spitz_spk_func = ucontrol->value.integer.value[0]; | ||
216 | spitz_ext_control(codec); | ||
217 | return 1; | ||
218 | } | ||
219 | |||
220 | static int spitz_mic_bias(struct snd_soc_dapm_widget *w, int event) | ||
221 | { | ||
222 | if (machine_is_borzoi() || machine_is_spitz()) { | ||
223 | if (SND_SOC_DAPM_EVENT_ON(event)) | ||
224 | set_scoop_gpio(&spitzscoop2_device.dev, | ||
225 | SPITZ_SCP2_MIC_BIAS); | ||
226 | else | ||
227 | reset_scoop_gpio(&spitzscoop2_device.dev, | ||
228 | SPITZ_SCP2_MIC_BIAS); | ||
229 | } | ||
230 | |||
231 | if (machine_is_akita()) { | ||
232 | if (SND_SOC_DAPM_EVENT_ON(event)) | ||
233 | akita_set_ioexp(&akitaioexp_device.dev, | ||
234 | AKITA_IOEXP_MIC_BIAS); | ||
235 | else | ||
236 | akita_reset_ioexp(&akitaioexp_device.dev, | ||
237 | AKITA_IOEXP_MIC_BIAS); | ||
238 | } | ||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | /* spitz machine dapm widgets */ | ||
243 | static const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = { | ||
244 | SND_SOC_DAPM_HP("Headphone Jack", NULL), | ||
245 | SND_SOC_DAPM_MIC("Mic Jack", spitz_mic_bias), | ||
246 | SND_SOC_DAPM_SPK("Ext Spk", NULL), | ||
247 | SND_SOC_DAPM_LINE("Line Jack", NULL), | ||
248 | |||
249 | /* headset is a mic and mono headphone */ | ||
250 | SND_SOC_DAPM_HP("Headset Jack", NULL), | ||
251 | }; | ||
252 | |||
253 | /* Spitz machine audio_map */ | ||
254 | static const char *audio_map[][3] = { | ||
255 | |||
256 | /* headphone connected to LOUT1, ROUT1 */ | ||
257 | {"Headphone Jack", NULL, "LOUT1"}, | ||
258 | {"Headphone Jack", NULL, "ROUT1"}, | ||
259 | |||
260 | /* headset connected to ROUT1 and LINPUT1 with bias (def below) */ | ||
261 | {"Headset Jack", NULL, "ROUT1"}, | ||
262 | |||
263 | /* ext speaker connected to LOUT2, ROUT2 */ | ||
264 | {"Ext Spk", NULL , "ROUT2"}, | ||
265 | {"Ext Spk", NULL , "LOUT2"}, | ||
266 | |||
267 | /* mic is connected to input 1 - with bias */ | ||
268 | {"LINPUT1", NULL, "Mic Bias"}, | ||
269 | {"Mic Bias", NULL, "Mic Jack"}, | ||
270 | |||
271 | /* line is connected to input 1 - no bias */ | ||
272 | {"LINPUT1", NULL, "Line Jack"}, | ||
273 | |||
274 | {NULL, NULL, NULL}, | ||
275 | }; | ||
276 | |||
277 | static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset", | ||
278 | "Off"}; | ||
279 | static const char *spk_function[] = {"On", "Off"}; | ||
280 | static const struct soc_enum spitz_enum[] = { | ||
281 | SOC_ENUM_SINGLE_EXT(5, jack_function), | ||
282 | SOC_ENUM_SINGLE_EXT(2, spk_function), | ||
283 | }; | ||
284 | |||
285 | static const struct snd_kcontrol_new wm8750_spitz_controls[] = { | ||
286 | SOC_ENUM_EXT("Jack Function", spitz_enum[0], spitz_get_jack, | ||
287 | spitz_set_jack), | ||
288 | SOC_ENUM_EXT("Speaker Function", spitz_enum[1], spitz_get_spk, | ||
289 | spitz_set_spk), | ||
290 | }; | ||
291 | |||
292 | /* | ||
293 | * Logic for a wm8750 as connected on a Sharp SL-Cxx00 Device | ||
294 | */ | ||
295 | static int spitz_wm8750_init(struct snd_soc_codec *codec) | ||
296 | { | ||
297 | int i, err; | ||
298 | |||
299 | /* NC codec pins */ | ||
300 | snd_soc_dapm_set_endpoint(codec, "RINPUT1", 0); | ||
301 | snd_soc_dapm_set_endpoint(codec, "LINPUT2", 0); | ||
302 | snd_soc_dapm_set_endpoint(codec, "RINPUT2", 0); | ||
303 | snd_soc_dapm_set_endpoint(codec, "LINPUT3", 0); | ||
304 | snd_soc_dapm_set_endpoint(codec, "RINPUT3", 0); | ||
305 | snd_soc_dapm_set_endpoint(codec, "OUT3", 0); | ||
306 | snd_soc_dapm_set_endpoint(codec, "MONO", 0); | ||
307 | |||
308 | /* Add spitz specific controls */ | ||
309 | for (i = 0; i < ARRAY_SIZE(wm8750_spitz_controls); i++) { | ||
310 | err = snd_ctl_add(codec->card, | ||
311 | snd_soc_cnew(&wm8750_spitz_controls[i], codec, NULL)); | ||
312 | if (err < 0) | ||
313 | return err; | ||
314 | } | ||
315 | |||
316 | /* Add spitz specific widgets */ | ||
317 | for (i = 0; i < ARRAY_SIZE(wm8750_dapm_widgets); i++) { | ||
318 | snd_soc_dapm_new_control(codec, &wm8750_dapm_widgets[i]); | ||
319 | } | ||
320 | |||
321 | /* Set up spitz specific audio path audio_map */ | ||
322 | for (i = 0; audio_map[i][0] != NULL; i++) { | ||
323 | snd_soc_dapm_connect_input(codec, audio_map[i][0], | ||
324 | audio_map[i][1], audio_map[i][2]); | ||
325 | } | ||
326 | |||
327 | snd_soc_dapm_sync_endpoints(codec); | ||
328 | return 0; | ||
329 | } | ||
330 | |||
331 | /* spitz digital audio interface glue - connects codec <--> CPU */ | ||
332 | static struct snd_soc_dai_link spitz_dai = { | ||
333 | .name = "wm8750", | ||
334 | .stream_name = "WM8750", | ||
335 | .cpu_dai = &pxa_i2s_dai, | ||
336 | .codec_dai = &wm8750_dai, | ||
337 | .init = spitz_wm8750_init, | ||
338 | .ops = &spitz_ops, | ||
339 | }; | ||
340 | |||
341 | /* spitz audio machine driver */ | ||
342 | static struct snd_soc_machine snd_soc_machine_spitz = { | ||
343 | .name = "Spitz", | ||
344 | .dai_link = &spitz_dai, | ||
345 | .num_links = 1, | ||
346 | }; | ||
347 | |||
348 | /* spitz audio private data */ | ||
349 | static struct wm8750_setup_data spitz_wm8750_setup = { | ||
350 | .i2c_address = 0x1b, | ||
351 | }; | ||
352 | |||
353 | /* spitz audio subsystem */ | ||
354 | static struct snd_soc_device spitz_snd_devdata = { | ||
355 | .machine = &snd_soc_machine_spitz, | ||
356 | .platform = &pxa2xx_soc_platform, | ||
357 | .codec_dev = &soc_codec_dev_wm8750, | ||
358 | .codec_data = &spitz_wm8750_setup, | ||
359 | }; | ||
360 | |||
361 | static struct platform_device *spitz_snd_device; | ||
362 | |||
363 | static int __init spitz_init(void) | ||
364 | { | ||
365 | int ret; | ||
366 | |||
367 | if (!(machine_is_spitz() || machine_is_borzoi() || machine_is_akita())) | ||
368 | return -ENODEV; | ||
369 | |||
370 | spitz_snd_device = platform_device_alloc("soc-audio", -1); | ||
371 | if (!spitz_snd_device) | ||
372 | return -ENOMEM; | ||
373 | |||
374 | platform_set_drvdata(spitz_snd_device, &spitz_snd_devdata); | ||
375 | spitz_snd_devdata.dev = &spitz_snd_device->dev; | ||
376 | ret = platform_device_add(spitz_snd_device); | ||
377 | |||
378 | if (ret) | ||
379 | platform_device_put(spitz_snd_device); | ||
380 | |||
381 | return ret; | ||
382 | } | ||
383 | |||
384 | static void __exit spitz_exit(void) | ||
385 | { | ||
386 | platform_device_unregister(spitz_snd_device); | ||
387 | } | ||
388 | |||
389 | module_init(spitz_init); | ||
390 | module_exit(spitz_exit); | ||
391 | |||
392 | MODULE_AUTHOR("Richard Purdie"); | ||
393 | MODULE_DESCRIPTION("ALSA SoC Spitz"); | ||
394 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/pxa/tosa.c b/sound/soc/pxa/tosa.c new file mode 100644 index 000000000000..5504e30acf14 --- /dev/null +++ b/sound/soc/pxa/tosa.c | |||
@@ -0,0 +1,289 @@ | |||
1 | /* | ||
2 | * tosa.c -- SoC audio for Tosa | ||
3 | * | ||
4 | * Copyright 2005 Wolfson Microelectronics PLC. | ||
5 | * Copyright 2005 Openedhand Ltd. | ||
6 | * | ||
7 | * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com> | ||
8 | * Richard Purdie <richard@openedhand.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify it | ||
11 | * under the terms of the GNU General Public License as published by the | ||
12 | * Free Software Foundation; either version 2 of the License, or (at your | ||
13 | * option) any later version. | ||
14 | * | ||
15 | * Revision history | ||
16 | * 30th Nov 2005 Initial version. | ||
17 | * | ||
18 | * GPIO's | ||
19 | * 1 - Jack Insertion | ||
20 | * 5 - Hookswitch (headset answer/hang up switch) | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include <linux/module.h> | ||
25 | #include <linux/moduleparam.h> | ||
26 | #include <linux/device.h> | ||
27 | |||
28 | #include <sound/driver.h> | ||
29 | #include <sound/core.h> | ||
30 | #include <sound/pcm.h> | ||
31 | #include <sound/soc.h> | ||
32 | #include <sound/soc-dapm.h> | ||
33 | |||
34 | #include <asm/mach-types.h> | ||
35 | #include <asm/hardware/tmio.h> | ||
36 | #include <asm/arch/pxa-regs.h> | ||
37 | #include <asm/arch/hardware.h> | ||
38 | #include <asm/arch/audio.h> | ||
39 | #include <asm/arch/tosa.h> | ||
40 | |||
41 | #include "../codecs/wm9712.h" | ||
42 | #include "pxa2xx-pcm.h" | ||
43 | #include "pxa2xx-ac97.h" | ||
44 | |||
45 | static struct snd_soc_machine tosa; | ||
46 | |||
47 | #define TOSA_HP 0 | ||
48 | #define TOSA_MIC_INT 1 | ||
49 | #define TOSA_HEADSET 2 | ||
50 | #define TOSA_HP_OFF 3 | ||
51 | #define TOSA_SPK_ON 0 | ||
52 | #define TOSA_SPK_OFF 1 | ||
53 | |||
54 | static int tosa_jack_func; | ||
55 | static int tosa_spk_func; | ||
56 | |||
57 | static void tosa_ext_control(struct snd_soc_codec *codec) | ||
58 | { | ||
59 | int spk = 0, mic_int = 0, hp = 0, hs = 0; | ||
60 | |||
61 | /* set up jack connection */ | ||
62 | switch (tosa_jack_func) { | ||
63 | case TOSA_HP: | ||
64 | hp = 1; | ||
65 | break; | ||
66 | case TOSA_MIC_INT: | ||
67 | mic_int = 1; | ||
68 | break; | ||
69 | case TOSA_HEADSET: | ||
70 | hs = 1; | ||
71 | break; | ||
72 | } | ||
73 | |||
74 | if (tosa_spk_func == TOSA_SPK_ON) | ||
75 | spk = 1; | ||
76 | |||
77 | snd_soc_dapm_set_endpoint(codec, "Speaker", spk); | ||
78 | snd_soc_dapm_set_endpoint(codec, "Mic (Internal)", mic_int); | ||
79 | snd_soc_dapm_set_endpoint(codec, "Headphone Jack", hp); | ||
80 | snd_soc_dapm_set_endpoint(codec, "Headset Jack", hs); | ||
81 | snd_soc_dapm_sync_endpoints(codec); | ||
82 | } | ||
83 | |||
84 | static int tosa_startup(struct snd_pcm_substream *substream) | ||
85 | { | ||
86 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
87 | struct snd_soc_codec *codec = rtd->socdev->codec; | ||
88 | |||
89 | /* check the jack status at stream startup */ | ||
90 | tosa_ext_control(codec); | ||
91 | return 0; | ||
92 | } | ||
93 | |||
94 | static struct snd_soc_ops tosa_ops = { | ||
95 | .startup = tosa_startup, | ||
96 | }; | ||
97 | |||
98 | static int tosa_get_jack(struct snd_kcontrol *kcontrol, | ||
99 | struct snd_ctl_elem_value *ucontrol) | ||
100 | { | ||
101 | ucontrol->value.integer.value[0] = tosa_jack_func; | ||
102 | return 0; | ||
103 | } | ||
104 | |||
105 | static int tosa_set_jack(struct snd_kcontrol *kcontrol, | ||
106 | struct snd_ctl_elem_value *ucontrol) | ||
107 | { | ||
108 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
109 | |||
110 | if (tosa_jack_func == ucontrol->value.integer.value[0]) | ||
111 | return 0; | ||
112 | |||
113 | tosa_jack_func = ucontrol->value.integer.value[0]; | ||
114 | tosa_ext_control(codec); | ||
115 | return 1; | ||
116 | } | ||
117 | |||
118 | static int tosa_get_spk(struct snd_kcontrol *kcontrol, | ||
119 | struct snd_ctl_elem_value *ucontrol) | ||
120 | { | ||
121 | ucontrol->value.integer.value[0] = tosa_spk_func; | ||
122 | return 0; | ||
123 | } | ||
124 | |||
125 | static int tosa_set_spk(struct snd_kcontrol *kcontrol, | ||
126 | struct snd_ctl_elem_value *ucontrol) | ||
127 | { | ||
128 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
129 | |||
130 | if (tosa_spk_func == ucontrol->value.integer.value[0]) | ||
131 | return 0; | ||
132 | |||
133 | tosa_spk_func = ucontrol->value.integer.value[0]; | ||
134 | tosa_ext_control(codec); | ||
135 | return 1; | ||
136 | } | ||
137 | |||
138 | /* tosa dapm event handlers */ | ||
139 | static int tosa_hp_event(struct snd_soc_dapm_widget *w, int event) | ||
140 | { | ||
141 | if (SND_SOC_DAPM_EVENT_ON(event)) | ||
142 | set_tc6393_gpio(&tc6393_device.dev,TOSA_TC6393_L_MUTE); | ||
143 | else | ||
144 | reset_tc6393_gpio(&tc6393_device.dev,TOSA_TC6393_L_MUTE); | ||
145 | return 0; | ||
146 | } | ||
147 | |||
148 | /* tosa machine dapm widgets */ | ||
149 | static const struct snd_soc_dapm_widget tosa_dapm_widgets[] = { | ||
150 | SND_SOC_DAPM_HP("Headphone Jack", tosa_hp_event), | ||
151 | SND_SOC_DAPM_HP("Headset Jack", NULL), | ||
152 | SND_SOC_DAPM_MIC("Mic (Internal)", NULL), | ||
153 | SND_SOC_DAPM_SPK("Speaker", NULL), | ||
154 | }; | ||
155 | |||
156 | /* tosa audio map */ | ||
157 | static const char *audio_map[][3] = { | ||
158 | |||
159 | /* headphone connected to HPOUTL, HPOUTR */ | ||
160 | {"Headphone Jack", NULL, "HPOUTL"}, | ||
161 | {"Headphone Jack", NULL, "HPOUTR"}, | ||
162 | |||
163 | /* ext speaker connected to LOUT2, ROUT2 */ | ||
164 | {"Speaker", NULL, "LOUT2"}, | ||
165 | {"Speaker", NULL, "ROUT2"}, | ||
166 | |||
167 | /* internal mic is connected to mic1, mic2 differential - with bias */ | ||
168 | {"MIC1", NULL, "Mic Bias"}, | ||
169 | {"MIC2", NULL, "Mic Bias"}, | ||
170 | {"Mic Bias", NULL, "Mic (Internal)"}, | ||
171 | |||
172 | /* headset is connected to HPOUTR, and LINEINR with bias */ | ||
173 | {"Headset Jack", NULL, "HPOUTR"}, | ||
174 | {"LINEINR", NULL, "Mic Bias"}, | ||
175 | {"Mic Bias", NULL, "Headset Jack"}, | ||
176 | |||
177 | {NULL, NULL, NULL}, | ||
178 | }; | ||
179 | |||
180 | static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset", | ||
181 | "Off"}; | ||
182 | static const char *spk_function[] = {"On", "Off"}; | ||
183 | static const struct soc_enum tosa_enum[] = { | ||
184 | SOC_ENUM_SINGLE_EXT(5, jack_function), | ||
185 | SOC_ENUM_SINGLE_EXT(2, spk_function), | ||
186 | }; | ||
187 | |||
188 | static const struct snd_kcontrol_new tosa_controls[] = { | ||
189 | SOC_ENUM_EXT("Jack Function", tosa_enum[0], tosa_get_jack, | ||
190 | tosa_set_jack), | ||
191 | SOC_ENUM_EXT("Speaker Function", tosa_enum[1], tosa_get_spk, | ||
192 | tosa_set_spk), | ||
193 | }; | ||
194 | |||
195 | static int tosa_ac97_init(struct snd_soc_codec *codec) | ||
196 | { | ||
197 | int i, err; | ||
198 | |||
199 | snd_soc_dapm_set_endpoint(codec, "OUT3", 0); | ||
200 | snd_soc_dapm_set_endpoint(codec, "MONOOUT", 0); | ||
201 | |||
202 | /* add tosa specific controls */ | ||
203 | for (i = 0; i < ARRAY_SIZE(tosa_controls); i++) { | ||
204 | err = snd_ctl_add(codec->card, | ||
205 | snd_soc_cnew(&tosa_controls[i],codec, NULL)); | ||
206 | if (err < 0) | ||
207 | return err; | ||
208 | } | ||
209 | |||
210 | /* add tosa specific widgets */ | ||
211 | for (i = 0; i < ARRAY_SIZE(tosa_dapm_widgets); i++) { | ||
212 | snd_soc_dapm_new_control(codec, &tosa_dapm_widgets[i]); | ||
213 | } | ||
214 | |||
215 | /* set up tosa specific audio path audio_map */ | ||
216 | for (i = 0; audio_map[i][0] != NULL; i++) { | ||
217 | snd_soc_dapm_connect_input(codec, audio_map[i][0], | ||
218 | audio_map[i][1], audio_map[i][2]); | ||
219 | } | ||
220 | |||
221 | snd_soc_dapm_sync_endpoints(codec); | ||
222 | return 0; | ||
223 | } | ||
224 | |||
225 | static struct snd_soc_dai_link tosa_dai[] = { | ||
226 | { | ||
227 | .name = "AC97", | ||
228 | .stream_name = "AC97 HiFi", | ||
229 | .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI], | ||
230 | .codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI], | ||
231 | .init = tosa_ac97_init, | ||
232 | .ops = &tosa_ops, | ||
233 | }, | ||
234 | { | ||
235 | .name = "AC97 Aux", | ||
236 | .stream_name = "AC97 Aux", | ||
237 | .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX], | ||
238 | .codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX], | ||
239 | .ops = &tosa_ops, | ||
240 | }, | ||
241 | }; | ||
242 | |||
243 | static struct snd_soc_machine tosa = { | ||
244 | .name = "Tosa", | ||
245 | .dai_link = tosa_dai, | ||
246 | .num_links = ARRAY_SIZE(tosa_dai), | ||
247 | }; | ||
248 | |||
249 | static struct snd_soc_device tosa_snd_devdata = { | ||
250 | .machine = &tosa, | ||
251 | .platform = &pxa2xx_soc_platform, | ||
252 | .codec_dev = &soc_codec_dev_wm9712, | ||
253 | }; | ||
254 | |||
255 | static struct platform_device *tosa_snd_device; | ||
256 | |||
257 | static int __init tosa_init(void) | ||
258 | { | ||
259 | int ret; | ||
260 | |||
261 | if (!machine_is_tosa()) | ||
262 | return -ENODEV; | ||
263 | |||
264 | tosa_snd_device = platform_device_alloc("soc-audio", -1); | ||
265 | if (!tosa_snd_device) | ||
266 | return -ENOMEM; | ||
267 | |||
268 | platform_set_drvdata(tosa_snd_device, &tosa_snd_devdata); | ||
269 | tosa_snd_devdata.dev = &tosa_snd_device->dev; | ||
270 | ret = platform_device_add(tosa_snd_device); | ||
271 | |||
272 | if (ret) | ||
273 | platform_device_put(tosa_snd_device); | ||
274 | |||
275 | return ret; | ||
276 | } | ||
277 | |||
278 | static void __exit tosa_exit(void) | ||
279 | { | ||
280 | platform_device_unregister(tosa_snd_device); | ||
281 | } | ||
282 | |||
283 | module_init(tosa_init); | ||
284 | module_exit(tosa_exit); | ||
285 | |||
286 | /* Module information */ | ||
287 | MODULE_AUTHOR("Richard Purdie"); | ||
288 | MODULE_DESCRIPTION("ALSA SoC Tosa"); | ||
289 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c new file mode 100644 index 000000000000..36519aef55d9 --- /dev/null +++ b/sound/soc/soc-core.c | |||
@@ -0,0 +1,1587 @@ | |||
1 | /* | ||
2 | * soc-core.c -- ALSA SoC Audio Layer | ||
3 | * | ||
4 | * Copyright 2005 Wolfson Microelectronics PLC. | ||
5 | * Copyright 2005 Openedhand Ltd. | ||
6 | * | ||
7 | * Author: Liam Girdwood | ||
8 | * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com | ||
9 | * with code, comments and ideas from :- | ||
10 | * Richard Purdie <richard@openedhand.com> | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify it | ||
13 | * under the terms of the GNU General Public License as published by the | ||
14 | * Free Software Foundation; either version 2 of the License, or (at your | ||
15 | * option) any later version. | ||
16 | * | ||
17 | * Revision history | ||
18 | * 12th Aug 2005 Initial version. | ||
19 | * 25th Oct 2005 Working Codec, Interface and Platform registration. | ||
20 | * | ||
21 | * TODO: | ||
22 | * o Add hw rules to enforce rates, etc. | ||
23 | * o More testing with other codecs/machines. | ||
24 | * o Add more codecs and platforms to ensure good API coverage. | ||
25 | * o Support TDM on PCM and I2S | ||
26 | */ | ||
27 | |||
28 | #include <linux/module.h> | ||
29 | #include <linux/moduleparam.h> | ||
30 | #include <linux/init.h> | ||
31 | #include <linux/delay.h> | ||
32 | #include <linux/pm.h> | ||
33 | #include <linux/bitops.h> | ||
34 | #include <linux/platform_device.h> | ||
35 | #include <sound/driver.h> | ||
36 | #include <sound/core.h> | ||
37 | #include <sound/pcm.h> | ||
38 | #include <sound/pcm_params.h> | ||
39 | #include <sound/soc.h> | ||
40 | #include <sound/soc-dapm.h> | ||
41 | #include <sound/initval.h> | ||
42 | |||
43 | /* debug */ | ||
44 | #define SOC_DEBUG 0 | ||
45 | #if SOC_DEBUG | ||
46 | #define dbg(format, arg...) printk(format, ## arg) | ||
47 | #else | ||
48 | #define dbg(format, arg...) | ||
49 | #endif | ||
50 | |||
51 | static DEFINE_MUTEX(pcm_mutex); | ||
52 | static DEFINE_MUTEX(io_mutex); | ||
53 | static DECLARE_WAIT_QUEUE_HEAD(soc_pm_waitq); | ||
54 | |||
55 | /* | ||
56 | * This is a timeout to do a DAPM powerdown after a stream is closed(). | ||
57 | * It can be used to eliminate pops between different playback streams, e.g. | ||
58 | * between two audio tracks. | ||
59 | */ | ||
60 | static int pmdown_time = 5000; | ||
61 | module_param(pmdown_time, int, 0); | ||
62 | MODULE_PARM_DESC(pmdown_time, "DAPM stream powerdown time (msecs)"); | ||
63 | |||
64 | /* | ||
65 | * This function forces any delayed work to be queued and run. | ||
66 | */ | ||
67 | static int run_delayed_work(struct delayed_work *dwork) | ||
68 | { | ||
69 | int ret; | ||
70 | |||
71 | /* cancel any work waiting to be queued. */ | ||
72 | ret = cancel_delayed_work(dwork); | ||
73 | |||
74 | /* if there was any work waiting then we run it now and | ||
75 | * wait for it's completion */ | ||
76 | if (ret) { | ||
77 | schedule_delayed_work(dwork, 0); | ||
78 | flush_scheduled_work(); | ||
79 | } | ||
80 | return ret; | ||
81 | } | ||
82 | |||
83 | #ifdef CONFIG_SND_SOC_AC97_BUS | ||
84 | /* unregister ac97 codec */ | ||
85 | static int soc_ac97_dev_unregister(struct snd_soc_codec *codec) | ||
86 | { | ||
87 | if (codec->ac97->dev.bus) | ||
88 | device_unregister(&codec->ac97->dev); | ||
89 | return 0; | ||
90 | } | ||
91 | |||
92 | /* stop no dev release warning */ | ||
93 | static void soc_ac97_device_release(struct device *dev){} | ||
94 | |||
95 | /* register ac97 codec to bus */ | ||
96 | static int soc_ac97_dev_register(struct snd_soc_codec *codec) | ||
97 | { | ||
98 | int err; | ||
99 | |||
100 | codec->ac97->dev.bus = &ac97_bus_type; | ||
101 | codec->ac97->dev.parent = NULL; | ||
102 | codec->ac97->dev.release = soc_ac97_device_release; | ||
103 | |||
104 | snprintf(codec->ac97->dev.bus_id, BUS_ID_SIZE, "%d-%d:%s", | ||
105 | codec->card->number, 0, codec->name); | ||
106 | err = device_register(&codec->ac97->dev); | ||
107 | if (err < 0) { | ||
108 | snd_printk(KERN_ERR "Can't register ac97 bus\n"); | ||
109 | codec->ac97->dev.bus = NULL; | ||
110 | return err; | ||
111 | } | ||
112 | return 0; | ||
113 | } | ||
114 | #endif | ||
115 | |||
116 | static inline const char* get_dai_name(int type) | ||
117 | { | ||
118 | switch(type) { | ||
119 | case SND_SOC_DAI_AC97: | ||
120 | return "AC97"; | ||
121 | case SND_SOC_DAI_I2S: | ||
122 | return "I2S"; | ||
123 | case SND_SOC_DAI_PCM: | ||
124 | return "PCM"; | ||
125 | } | ||
126 | return NULL; | ||
127 | } | ||
128 | |||
129 | /* | ||
130 | * Called by ALSA when a PCM substream is opened, the runtime->hw record is | ||
131 | * then initialized and any private data can be allocated. This also calls | ||
132 | * startup for the cpu DAI, platform, machine and codec DAI. | ||
133 | */ | ||
134 | static int soc_pcm_open(struct snd_pcm_substream *substream) | ||
135 | { | ||
136 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
137 | struct snd_soc_device *socdev = rtd->socdev; | ||
138 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
139 | struct snd_soc_dai_link *machine = rtd->dai; | ||
140 | struct snd_soc_platform *platform = socdev->platform; | ||
141 | struct snd_soc_cpu_dai *cpu_dai = machine->cpu_dai; | ||
142 | struct snd_soc_codec_dai *codec_dai = machine->codec_dai; | ||
143 | int ret = 0; | ||
144 | |||
145 | mutex_lock(&pcm_mutex); | ||
146 | |||
147 | /* startup the audio subsystem */ | ||
148 | if (cpu_dai->ops.startup) { | ||
149 | ret = cpu_dai->ops.startup(substream); | ||
150 | if (ret < 0) { | ||
151 | printk(KERN_ERR "asoc: can't open interface %s\n", | ||
152 | cpu_dai->name); | ||
153 | goto out; | ||
154 | } | ||
155 | } | ||
156 | |||
157 | if (platform->pcm_ops->open) { | ||
158 | ret = platform->pcm_ops->open(substream); | ||
159 | if (ret < 0) { | ||
160 | printk(KERN_ERR "asoc: can't open platform %s\n", platform->name); | ||
161 | goto platform_err; | ||
162 | } | ||
163 | } | ||
164 | |||
165 | if (codec_dai->ops.startup) { | ||
166 | ret = codec_dai->ops.startup(substream); | ||
167 | if (ret < 0) { | ||
168 | printk(KERN_ERR "asoc: can't open codec %s\n", | ||
169 | codec_dai->name); | ||
170 | goto codec_dai_err; | ||
171 | } | ||
172 | } | ||
173 | |||
174 | if (machine->ops && machine->ops->startup) { | ||
175 | ret = machine->ops->startup(substream); | ||
176 | if (ret < 0) { | ||
177 | printk(KERN_ERR "asoc: %s startup failed\n", machine->name); | ||
178 | goto machine_err; | ||
179 | } | ||
180 | } | ||
181 | |||
182 | /* Check that the codec and cpu DAI's are compatible */ | ||
183 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
184 | runtime->hw.rate_min = | ||
185 | max(codec_dai->playback.rate_min, cpu_dai->playback.rate_min); | ||
186 | runtime->hw.rate_max = | ||
187 | min(codec_dai->playback.rate_max, cpu_dai->playback.rate_max); | ||
188 | runtime->hw.channels_min = | ||
189 | max(codec_dai->playback.channels_min, | ||
190 | cpu_dai->playback.channels_min); | ||
191 | runtime->hw.channels_max = | ||
192 | min(codec_dai->playback.channels_max, | ||
193 | cpu_dai->playback.channels_max); | ||
194 | runtime->hw.formats = | ||
195 | codec_dai->playback.formats & cpu_dai->playback.formats; | ||
196 | runtime->hw.rates = | ||
197 | codec_dai->playback.rates & cpu_dai->playback.rates; | ||
198 | } else { | ||
199 | runtime->hw.rate_min = | ||
200 | max(codec_dai->capture.rate_min, cpu_dai->capture.rate_min); | ||
201 | runtime->hw.rate_max = | ||
202 | min(codec_dai->capture.rate_max, cpu_dai->capture.rate_max); | ||
203 | runtime->hw.channels_min = | ||
204 | max(codec_dai->capture.channels_min, | ||
205 | cpu_dai->capture.channels_min); | ||
206 | runtime->hw.channels_max = | ||
207 | min(codec_dai->capture.channels_max, | ||
208 | cpu_dai->capture.channels_max); | ||
209 | runtime->hw.formats = | ||
210 | codec_dai->capture.formats & cpu_dai->capture.formats; | ||
211 | runtime->hw.rates = | ||
212 | codec_dai->capture.rates & cpu_dai->capture.rates; | ||
213 | } | ||
214 | |||
215 | snd_pcm_limit_hw_rates(runtime); | ||
216 | if (!runtime->hw.rates) { | ||
217 | printk(KERN_ERR "asoc: %s <-> %s No matching rates\n", | ||
218 | codec_dai->name, cpu_dai->name); | ||
219 | goto machine_err; | ||
220 | } | ||
221 | if (!runtime->hw.formats) { | ||
222 | printk(KERN_ERR "asoc: %s <-> %s No matching formats\n", | ||
223 | codec_dai->name, cpu_dai->name); | ||
224 | goto machine_err; | ||
225 | } | ||
226 | if (!runtime->hw.channels_min || !runtime->hw.channels_max) { | ||
227 | printk(KERN_ERR "asoc: %s <-> %s No matching channels\n", | ||
228 | codec_dai->name, cpu_dai->name); | ||
229 | goto machine_err; | ||
230 | } | ||
231 | |||
232 | dbg("asoc: %s <-> %s info:\n",codec_dai->name, cpu_dai->name); | ||
233 | dbg("asoc: rate mask 0x%x\n", runtime->hw.rates); | ||
234 | dbg("asoc: min ch %d max ch %d\n", runtime->hw.channels_min, | ||
235 | runtime->hw.channels_max); | ||
236 | dbg("asoc: min rate %d max rate %d\n", runtime->hw.rate_min, | ||
237 | runtime->hw.rate_max); | ||
238 | |||
239 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
240 | cpu_dai->playback.active = codec_dai->playback.active = 1; | ||
241 | else | ||
242 | cpu_dai->capture.active = codec_dai->capture.active = 1; | ||
243 | cpu_dai->active = codec_dai->active = 1; | ||
244 | cpu_dai->runtime = runtime; | ||
245 | socdev->codec->active++; | ||
246 | mutex_unlock(&pcm_mutex); | ||
247 | return 0; | ||
248 | |||
249 | machine_err: | ||
250 | if (machine->ops && machine->ops->shutdown) | ||
251 | machine->ops->shutdown(substream); | ||
252 | |||
253 | codec_dai_err: | ||
254 | if (platform->pcm_ops->close) | ||
255 | platform->pcm_ops->close(substream); | ||
256 | |||
257 | platform_err: | ||
258 | if (cpu_dai->ops.shutdown) | ||
259 | cpu_dai->ops.shutdown(substream); | ||
260 | out: | ||
261 | mutex_unlock(&pcm_mutex); | ||
262 | return ret; | ||
263 | } | ||
264 | |||
265 | /* | ||
266 | * Power down the audio subsytem pmdown_time msecs after close is called. | ||
267 | * This is to ensure there are no pops or clicks in between any music tracks | ||
268 | * due to DAPM power cycling. | ||
269 | */ | ||
270 | static void close_delayed_work(struct work_struct *work) | ||
271 | { | ||
272 | struct snd_soc_device *socdev = | ||
273 | container_of(work, struct snd_soc_device, delayed_work.work); | ||
274 | struct snd_soc_codec *codec = socdev->codec; | ||
275 | struct snd_soc_codec_dai *codec_dai; | ||
276 | int i; | ||
277 | |||
278 | mutex_lock(&pcm_mutex); | ||
279 | for(i = 0; i < codec->num_dai; i++) { | ||
280 | codec_dai = &codec->dai[i]; | ||
281 | |||
282 | dbg("pop wq checking: %s status: %s waiting: %s\n", | ||
283 | codec_dai->playback.stream_name, | ||
284 | codec_dai->playback.active ? "active" : "inactive", | ||
285 | codec_dai->pop_wait ? "yes" : "no"); | ||
286 | |||
287 | /* are we waiting on this codec DAI stream */ | ||
288 | if (codec_dai->pop_wait == 1) { | ||
289 | |||
290 | codec_dai->pop_wait = 0; | ||
291 | snd_soc_dapm_stream_event(codec, codec_dai->playback.stream_name, | ||
292 | SND_SOC_DAPM_STREAM_STOP); | ||
293 | |||
294 | /* power down the codec power domain if no longer active */ | ||
295 | if (codec->active == 0) { | ||
296 | dbg("pop wq D3 %s %s\n", codec->name, | ||
297 | codec_dai->playback.stream_name); | ||
298 | if (codec->dapm_event) | ||
299 | codec->dapm_event(codec, SNDRV_CTL_POWER_D3hot); | ||
300 | } | ||
301 | } | ||
302 | } | ||
303 | mutex_unlock(&pcm_mutex); | ||
304 | } | ||
305 | |||
306 | /* | ||
307 | * Called by ALSA when a PCM substream is closed. Private data can be | ||
308 | * freed here. The cpu DAI, codec DAI, machine and platform are also | ||
309 | * shutdown. | ||
310 | */ | ||
311 | static int soc_codec_close(struct snd_pcm_substream *substream) | ||
312 | { | ||
313 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
314 | struct snd_soc_device *socdev = rtd->socdev; | ||
315 | struct snd_soc_dai_link *machine = rtd->dai; | ||
316 | struct snd_soc_platform *platform = socdev->platform; | ||
317 | struct snd_soc_cpu_dai *cpu_dai = machine->cpu_dai; | ||
318 | struct snd_soc_codec_dai *codec_dai = machine->codec_dai; | ||
319 | struct snd_soc_codec *codec = socdev->codec; | ||
320 | |||
321 | mutex_lock(&pcm_mutex); | ||
322 | |||
323 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
324 | cpu_dai->playback.active = codec_dai->playback.active = 0; | ||
325 | else | ||
326 | cpu_dai->capture.active = codec_dai->capture.active = 0; | ||
327 | |||
328 | if (codec_dai->playback.active == 0 && | ||
329 | codec_dai->capture.active == 0) { | ||
330 | cpu_dai->active = codec_dai->active = 0; | ||
331 | } | ||
332 | codec->active--; | ||
333 | |||
334 | if (cpu_dai->ops.shutdown) | ||
335 | cpu_dai->ops.shutdown(substream); | ||
336 | |||
337 | if (codec_dai->ops.shutdown) | ||
338 | codec_dai->ops.shutdown(substream); | ||
339 | |||
340 | if (machine->ops && machine->ops->shutdown) | ||
341 | machine->ops->shutdown(substream); | ||
342 | |||
343 | if (platform->pcm_ops->close) | ||
344 | platform->pcm_ops->close(substream); | ||
345 | cpu_dai->runtime = NULL; | ||
346 | |||
347 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
348 | /* start delayed pop wq here for playback streams */ | ||
349 | codec_dai->pop_wait = 1; | ||
350 | schedule_delayed_work(&socdev->delayed_work, | ||
351 | msecs_to_jiffies(pmdown_time)); | ||
352 | } else { | ||
353 | /* capture streams can be powered down now */ | ||
354 | snd_soc_dapm_stream_event(codec, | ||
355 | codec_dai->capture.stream_name, SND_SOC_DAPM_STREAM_STOP); | ||
356 | |||
357 | if (codec->active == 0 && codec_dai->pop_wait == 0){ | ||
358 | if (codec->dapm_event) | ||
359 | codec->dapm_event(codec, SNDRV_CTL_POWER_D3hot); | ||
360 | } | ||
361 | } | ||
362 | |||
363 | mutex_unlock(&pcm_mutex); | ||
364 | return 0; | ||
365 | } | ||
366 | |||
367 | /* | ||
368 | * Called by ALSA when the PCM substream is prepared, can set format, sample | ||
369 | * rate, etc. This function is non atomic and can be called multiple times, | ||
370 | * it can refer to the runtime info. | ||
371 | */ | ||
372 | static int soc_pcm_prepare(struct snd_pcm_substream *substream) | ||
373 | { | ||
374 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
375 | struct snd_soc_device *socdev = rtd->socdev; | ||
376 | struct snd_soc_dai_link *machine = rtd->dai; | ||
377 | struct snd_soc_platform *platform = socdev->platform; | ||
378 | struct snd_soc_cpu_dai *cpu_dai = machine->cpu_dai; | ||
379 | struct snd_soc_codec_dai *codec_dai = machine->codec_dai; | ||
380 | struct snd_soc_codec *codec = socdev->codec; | ||
381 | int ret = 0; | ||
382 | |||
383 | mutex_lock(&pcm_mutex); | ||
384 | |||
385 | if (machine->ops && machine->ops->prepare) { | ||
386 | ret = machine->ops->prepare(substream); | ||
387 | if (ret < 0) { | ||
388 | printk(KERN_ERR "asoc: machine prepare error\n"); | ||
389 | goto out; | ||
390 | } | ||
391 | } | ||
392 | |||
393 | if (platform->pcm_ops->prepare) { | ||
394 | ret = platform->pcm_ops->prepare(substream); | ||
395 | if (ret < 0) { | ||
396 | printk(KERN_ERR "asoc: platform prepare error\n"); | ||
397 | goto out; | ||
398 | } | ||
399 | } | ||
400 | |||
401 | if (codec_dai->ops.prepare) { | ||
402 | ret = codec_dai->ops.prepare(substream); | ||
403 | if (ret < 0) { | ||
404 | printk(KERN_ERR "asoc: codec DAI prepare error\n"); | ||
405 | goto out; | ||
406 | } | ||
407 | } | ||
408 | |||
409 | if (cpu_dai->ops.prepare) { | ||
410 | ret = cpu_dai->ops.prepare(substream); | ||
411 | if (ret < 0) { | ||
412 | printk(KERN_ERR "asoc: cpu DAI prepare error\n"); | ||
413 | goto out; | ||
414 | } | ||
415 | } | ||
416 | |||
417 | /* we only want to start a DAPM playback stream if we are not waiting | ||
418 | * on an existing one stopping */ | ||
419 | if (codec_dai->pop_wait) { | ||
420 | /* we are waiting for the delayed work to start */ | ||
421 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) | ||
422 | snd_soc_dapm_stream_event(socdev->codec, | ||
423 | codec_dai->capture.stream_name, | ||
424 | SND_SOC_DAPM_STREAM_START); | ||
425 | else { | ||
426 | codec_dai->pop_wait = 0; | ||
427 | cancel_delayed_work(&socdev->delayed_work); | ||
428 | if (codec_dai->dai_ops.digital_mute) | ||
429 | codec_dai->dai_ops.digital_mute(codec_dai, 0); | ||
430 | } | ||
431 | } else { | ||
432 | /* no delayed work - do we need to power up codec */ | ||
433 | if (codec->dapm_state != SNDRV_CTL_POWER_D0) { | ||
434 | |||
435 | if (codec->dapm_event) | ||
436 | codec->dapm_event(codec, SNDRV_CTL_POWER_D1); | ||
437 | |||
438 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
439 | snd_soc_dapm_stream_event(codec, | ||
440 | codec_dai->playback.stream_name, | ||
441 | SND_SOC_DAPM_STREAM_START); | ||
442 | else | ||
443 | snd_soc_dapm_stream_event(codec, | ||
444 | codec_dai->capture.stream_name, | ||
445 | SND_SOC_DAPM_STREAM_START); | ||
446 | |||
447 | if (codec->dapm_event) | ||
448 | codec->dapm_event(codec, SNDRV_CTL_POWER_D0); | ||
449 | if (codec_dai->dai_ops.digital_mute) | ||
450 | codec_dai->dai_ops.digital_mute(codec_dai, 0); | ||
451 | |||
452 | } else { | ||
453 | /* codec already powered - power on widgets */ | ||
454 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
455 | snd_soc_dapm_stream_event(codec, | ||
456 | codec_dai->playback.stream_name, | ||
457 | SND_SOC_DAPM_STREAM_START); | ||
458 | else | ||
459 | snd_soc_dapm_stream_event(codec, | ||
460 | codec_dai->capture.stream_name, | ||
461 | SND_SOC_DAPM_STREAM_START); | ||
462 | if (codec_dai->dai_ops.digital_mute) | ||
463 | codec_dai->dai_ops.digital_mute(codec_dai, 0); | ||
464 | } | ||
465 | } | ||
466 | |||
467 | out: | ||
468 | mutex_unlock(&pcm_mutex); | ||
469 | return ret; | ||
470 | } | ||
471 | |||
472 | /* | ||
473 | * Called by ALSA when the hardware params are set by application. This | ||
474 | * function can also be called multiple times and can allocate buffers | ||
475 | * (using snd_pcm_lib_* ). It's non-atomic. | ||
476 | */ | ||
477 | static int soc_pcm_hw_params(struct snd_pcm_substream *substream, | ||
478 | struct snd_pcm_hw_params *params) | ||
479 | { | ||
480 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
481 | struct snd_soc_device *socdev = rtd->socdev; | ||
482 | struct snd_soc_dai_link *machine = rtd->dai; | ||
483 | struct snd_soc_platform *platform = socdev->platform; | ||
484 | struct snd_soc_cpu_dai *cpu_dai = machine->cpu_dai; | ||
485 | struct snd_soc_codec_dai *codec_dai = machine->codec_dai; | ||
486 | int ret = 0; | ||
487 | |||
488 | mutex_lock(&pcm_mutex); | ||
489 | |||
490 | if (machine->ops && machine->ops->hw_params) { | ||
491 | ret = machine->ops->hw_params(substream, params); | ||
492 | if (ret < 0) { | ||
493 | printk(KERN_ERR "asoc: machine hw_params failed\n"); | ||
494 | goto out; | ||
495 | } | ||
496 | } | ||
497 | |||
498 | if (codec_dai->ops.hw_params) { | ||
499 | ret = codec_dai->ops.hw_params(substream, params); | ||
500 | if (ret < 0) { | ||
501 | printk(KERN_ERR "asoc: can't set codec %s hw params\n", | ||
502 | codec_dai->name); | ||
503 | goto codec_err; | ||
504 | } | ||
505 | } | ||
506 | |||
507 | if (cpu_dai->ops.hw_params) { | ||
508 | ret = cpu_dai->ops.hw_params(substream, params); | ||
509 | if (ret < 0) { | ||
510 | printk(KERN_ERR "asoc: can't set interface %s hw params\n", | ||
511 | cpu_dai->name); | ||
512 | goto interface_err; | ||
513 | } | ||
514 | } | ||
515 | |||
516 | if (platform->pcm_ops->hw_params) { | ||
517 | ret = platform->pcm_ops->hw_params(substream, params); | ||
518 | if (ret < 0) { | ||
519 | printk(KERN_ERR "asoc: can't set platform %s hw params\n", | ||
520 | platform->name); | ||
521 | goto platform_err; | ||
522 | } | ||
523 | } | ||
524 | |||
525 | out: | ||
526 | mutex_unlock(&pcm_mutex); | ||
527 | return ret; | ||
528 | |||
529 | platform_err: | ||
530 | if (cpu_dai->ops.hw_free) | ||
531 | cpu_dai->ops.hw_free(substream); | ||
532 | |||
533 | interface_err: | ||
534 | if (codec_dai->ops.hw_free) | ||
535 | codec_dai->ops.hw_free(substream); | ||
536 | |||
537 | codec_err: | ||
538 | if(machine->ops && machine->ops->hw_free) | ||
539 | machine->ops->hw_free(substream); | ||
540 | |||
541 | mutex_unlock(&pcm_mutex); | ||
542 | return ret; | ||
543 | } | ||
544 | |||
545 | /* | ||
546 | * Free's resources allocated by hw_params, can be called multiple times | ||
547 | */ | ||
548 | static int soc_pcm_hw_free(struct snd_pcm_substream *substream) | ||
549 | { | ||
550 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
551 | struct snd_soc_device *socdev = rtd->socdev; | ||
552 | struct snd_soc_dai_link *machine = rtd->dai; | ||
553 | struct snd_soc_platform *platform = socdev->platform; | ||
554 | struct snd_soc_cpu_dai *cpu_dai = machine->cpu_dai; | ||
555 | struct snd_soc_codec_dai *codec_dai = machine->codec_dai; | ||
556 | struct snd_soc_codec *codec = socdev->codec; | ||
557 | |||
558 | mutex_lock(&pcm_mutex); | ||
559 | |||
560 | /* apply codec digital mute */ | ||
561 | if (!codec->active && codec_dai->dai_ops.digital_mute) | ||
562 | codec_dai->dai_ops.digital_mute(codec_dai, 1); | ||
563 | |||
564 | /* free any machine hw params */ | ||
565 | if (machine->ops && machine->ops->hw_free) | ||
566 | machine->ops->hw_free(substream); | ||
567 | |||
568 | /* free any DMA resources */ | ||
569 | if (platform->pcm_ops->hw_free) | ||
570 | platform->pcm_ops->hw_free(substream); | ||
571 | |||
572 | /* now free hw params for the DAI's */ | ||
573 | if (codec_dai->ops.hw_free) | ||
574 | codec_dai->ops.hw_free(substream); | ||
575 | |||
576 | if (cpu_dai->ops.hw_free) | ||
577 | cpu_dai->ops.hw_free(substream); | ||
578 | |||
579 | mutex_unlock(&pcm_mutex); | ||
580 | return 0; | ||
581 | } | ||
582 | |||
583 | static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | ||
584 | { | ||
585 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
586 | struct snd_soc_device *socdev = rtd->socdev; | ||
587 | struct snd_soc_dai_link *machine = rtd->dai; | ||
588 | struct snd_soc_platform *platform = socdev->platform; | ||
589 | struct snd_soc_cpu_dai *cpu_dai = machine->cpu_dai; | ||
590 | struct snd_soc_codec_dai *codec_dai = machine->codec_dai; | ||
591 | int ret; | ||
592 | |||
593 | if (codec_dai->ops.trigger) { | ||
594 | ret = codec_dai->ops.trigger(substream, cmd); | ||
595 | if (ret < 0) | ||
596 | return ret; | ||
597 | } | ||
598 | |||
599 | if (platform->pcm_ops->trigger) { | ||
600 | ret = platform->pcm_ops->trigger(substream, cmd); | ||
601 | if (ret < 0) | ||
602 | return ret; | ||
603 | } | ||
604 | |||
605 | if (cpu_dai->ops.trigger) { | ||
606 | ret = cpu_dai->ops.trigger(substream, cmd); | ||
607 | if (ret < 0) | ||
608 | return ret; | ||
609 | } | ||
610 | return 0; | ||
611 | } | ||
612 | |||
613 | /* ASoC PCM operations */ | ||
614 | static struct snd_pcm_ops soc_pcm_ops = { | ||
615 | .open = soc_pcm_open, | ||
616 | .close = soc_codec_close, | ||
617 | .hw_params = soc_pcm_hw_params, | ||
618 | .hw_free = soc_pcm_hw_free, | ||
619 | .prepare = soc_pcm_prepare, | ||
620 | .trigger = soc_pcm_trigger, | ||
621 | }; | ||
622 | |||
623 | #ifdef CONFIG_PM | ||
624 | /* powers down audio subsystem for suspend */ | ||
625 | static int soc_suspend(struct platform_device *pdev, pm_message_t state) | ||
626 | { | ||
627 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
628 | struct snd_soc_machine *machine = socdev->machine; | ||
629 | struct snd_soc_platform *platform = socdev->platform; | ||
630 | struct snd_soc_codec_device *codec_dev = socdev->codec_dev; | ||
631 | struct snd_soc_codec *codec = socdev->codec; | ||
632 | int i; | ||
633 | |||
634 | /* mute any active DAC's */ | ||
635 | for(i = 0; i < machine->num_links; i++) { | ||
636 | struct snd_soc_codec_dai *dai = machine->dai_link[i].codec_dai; | ||
637 | if (dai->dai_ops.digital_mute && dai->playback.active) | ||
638 | dai->dai_ops.digital_mute(dai, 1); | ||
639 | } | ||
640 | |||
641 | if (machine->suspend_pre) | ||
642 | machine->suspend_pre(pdev, state); | ||
643 | |||
644 | for(i = 0; i < machine->num_links; i++) { | ||
645 | struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai; | ||
646 | if (cpu_dai->suspend && cpu_dai->type != SND_SOC_DAI_AC97) | ||
647 | cpu_dai->suspend(pdev, cpu_dai); | ||
648 | if (platform->suspend) | ||
649 | platform->suspend(pdev, cpu_dai); | ||
650 | } | ||
651 | |||
652 | /* close any waiting streams and save state */ | ||
653 | run_delayed_work(&socdev->delayed_work); | ||
654 | codec->suspend_dapm_state = codec->dapm_state; | ||
655 | |||
656 | for(i = 0; i < codec->num_dai; i++) { | ||
657 | char *stream = codec->dai[i].playback.stream_name; | ||
658 | if (stream != NULL) | ||
659 | snd_soc_dapm_stream_event(codec, stream, | ||
660 | SND_SOC_DAPM_STREAM_SUSPEND); | ||
661 | stream = codec->dai[i].capture.stream_name; | ||
662 | if (stream != NULL) | ||
663 | snd_soc_dapm_stream_event(codec, stream, | ||
664 | SND_SOC_DAPM_STREAM_SUSPEND); | ||
665 | } | ||
666 | |||
667 | if (codec_dev->suspend) | ||
668 | codec_dev->suspend(pdev, state); | ||
669 | |||
670 | for(i = 0; i < machine->num_links; i++) { | ||
671 | struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai; | ||
672 | if (cpu_dai->suspend && cpu_dai->type == SND_SOC_DAI_AC97) | ||
673 | cpu_dai->suspend(pdev, cpu_dai); | ||
674 | } | ||
675 | |||
676 | if (machine->suspend_post) | ||
677 | machine->suspend_post(pdev, state); | ||
678 | |||
679 | return 0; | ||
680 | } | ||
681 | |||
682 | /* powers up audio subsystem after a suspend */ | ||
683 | static int soc_resume(struct platform_device *pdev) | ||
684 | { | ||
685 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
686 | struct snd_soc_machine *machine = socdev->machine; | ||
687 | struct snd_soc_platform *platform = socdev->platform; | ||
688 | struct snd_soc_codec_device *codec_dev = socdev->codec_dev; | ||
689 | struct snd_soc_codec *codec = socdev->codec; | ||
690 | int i; | ||
691 | |||
692 | if (machine->resume_pre) | ||
693 | machine->resume_pre(pdev); | ||
694 | |||
695 | for(i = 0; i < machine->num_links; i++) { | ||
696 | struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai; | ||
697 | if (cpu_dai->resume && cpu_dai->type == SND_SOC_DAI_AC97) | ||
698 | cpu_dai->resume(pdev, cpu_dai); | ||
699 | } | ||
700 | |||
701 | if (codec_dev->resume) | ||
702 | codec_dev->resume(pdev); | ||
703 | |||
704 | for(i = 0; i < codec->num_dai; i++) { | ||
705 | char* stream = codec->dai[i].playback.stream_name; | ||
706 | if (stream != NULL) | ||
707 | snd_soc_dapm_stream_event(codec, stream, | ||
708 | SND_SOC_DAPM_STREAM_RESUME); | ||
709 | stream = codec->dai[i].capture.stream_name; | ||
710 | if (stream != NULL) | ||
711 | snd_soc_dapm_stream_event(codec, stream, | ||
712 | SND_SOC_DAPM_STREAM_RESUME); | ||
713 | } | ||
714 | |||
715 | /* unmute any active DAC's */ | ||
716 | for(i = 0; i < machine->num_links; i++) { | ||
717 | struct snd_soc_codec_dai *dai = machine->dai_link[i].codec_dai; | ||
718 | if (dai->dai_ops.digital_mute && dai->playback.active) | ||
719 | dai->dai_ops.digital_mute(dai, 0); | ||
720 | } | ||
721 | |||
722 | for(i = 0; i < machine->num_links; i++) { | ||
723 | struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai; | ||
724 | if (cpu_dai->resume && cpu_dai->type != SND_SOC_DAI_AC97) | ||
725 | cpu_dai->resume(pdev, cpu_dai); | ||
726 | if (platform->resume) | ||
727 | platform->resume(pdev, cpu_dai); | ||
728 | } | ||
729 | |||
730 | if (machine->resume_post) | ||
731 | machine->resume_post(pdev); | ||
732 | |||
733 | return 0; | ||
734 | } | ||
735 | |||
736 | #else | ||
737 | #define soc_suspend NULL | ||
738 | #define soc_resume NULL | ||
739 | #endif | ||
740 | |||
741 | /* probes a new socdev */ | ||
742 | static int soc_probe(struct platform_device *pdev) | ||
743 | { | ||
744 | int ret = 0, i; | ||
745 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
746 | struct snd_soc_machine *machine = socdev->machine; | ||
747 | struct snd_soc_platform *platform = socdev->platform; | ||
748 | struct snd_soc_codec_device *codec_dev = socdev->codec_dev; | ||
749 | |||
750 | if (machine->probe) { | ||
751 | ret = machine->probe(pdev); | ||
752 | if(ret < 0) | ||
753 | return ret; | ||
754 | } | ||
755 | |||
756 | for (i = 0; i < machine->num_links; i++) { | ||
757 | struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai; | ||
758 | if (cpu_dai->probe) { | ||
759 | ret = cpu_dai->probe(pdev); | ||
760 | if(ret < 0) | ||
761 | goto cpu_dai_err; | ||
762 | } | ||
763 | } | ||
764 | |||
765 | if (codec_dev->probe) { | ||
766 | ret = codec_dev->probe(pdev); | ||
767 | if(ret < 0) | ||
768 | goto cpu_dai_err; | ||
769 | } | ||
770 | |||
771 | if (platform->probe) { | ||
772 | ret = platform->probe(pdev); | ||
773 | if(ret < 0) | ||
774 | goto platform_err; | ||
775 | } | ||
776 | |||
777 | /* DAPM stream work */ | ||
778 | INIT_DELAYED_WORK(&socdev->delayed_work, close_delayed_work); | ||
779 | return 0; | ||
780 | |||
781 | platform_err: | ||
782 | if (codec_dev->remove) | ||
783 | codec_dev->remove(pdev); | ||
784 | |||
785 | cpu_dai_err: | ||
786 | for (i--; i >= 0; i--) { | ||
787 | struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai; | ||
788 | if (cpu_dai->remove) | ||
789 | cpu_dai->remove(pdev); | ||
790 | } | ||
791 | |||
792 | if (machine->remove) | ||
793 | machine->remove(pdev); | ||
794 | |||
795 | return ret; | ||
796 | } | ||
797 | |||
798 | /* removes a socdev */ | ||
799 | static int soc_remove(struct platform_device *pdev) | ||
800 | { | ||
801 | int i; | ||
802 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
803 | struct snd_soc_machine *machine = socdev->machine; | ||
804 | struct snd_soc_platform *platform = socdev->platform; | ||
805 | struct snd_soc_codec_device *codec_dev = socdev->codec_dev; | ||
806 | |||
807 | run_delayed_work(&socdev->delayed_work); | ||
808 | |||
809 | if (platform->remove) | ||
810 | platform->remove(pdev); | ||
811 | |||
812 | if (codec_dev->remove) | ||
813 | codec_dev->remove(pdev); | ||
814 | |||
815 | for (i = 0; i < machine->num_links; i++) { | ||
816 | struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai; | ||
817 | if (cpu_dai->remove) | ||
818 | cpu_dai->remove(pdev); | ||
819 | } | ||
820 | |||
821 | if (machine->remove) | ||
822 | machine->remove(pdev); | ||
823 | |||
824 | return 0; | ||
825 | } | ||
826 | |||
827 | /* ASoC platform driver */ | ||
828 | static struct platform_driver soc_driver = { | ||
829 | .driver = { | ||
830 | .name = "soc-audio", | ||
831 | }, | ||
832 | .probe = soc_probe, | ||
833 | .remove = soc_remove, | ||
834 | .suspend = soc_suspend, | ||
835 | .resume = soc_resume, | ||
836 | }; | ||
837 | |||
838 | /* create a new pcm */ | ||
839 | static int soc_new_pcm(struct snd_soc_device *socdev, | ||
840 | struct snd_soc_dai_link *dai_link, int num) | ||
841 | { | ||
842 | struct snd_soc_codec *codec = socdev->codec; | ||
843 | struct snd_soc_codec_dai *codec_dai = dai_link->codec_dai; | ||
844 | struct snd_soc_cpu_dai *cpu_dai = dai_link->cpu_dai; | ||
845 | struct snd_soc_pcm_runtime *rtd; | ||
846 | struct snd_pcm *pcm; | ||
847 | char new_name[64]; | ||
848 | int ret = 0, playback = 0, capture = 0; | ||
849 | |||
850 | rtd = kzalloc(sizeof(struct snd_soc_pcm_runtime), GFP_KERNEL); | ||
851 | if (rtd == NULL) | ||
852 | return -ENOMEM; | ||
853 | |||
854 | rtd->dai = dai_link; | ||
855 | rtd->socdev = socdev; | ||
856 | codec_dai->codec = socdev->codec; | ||
857 | |||
858 | /* check client and interface hw capabilities */ | ||
859 | sprintf(new_name, "%s %s-%s-%d",dai_link->stream_name, codec_dai->name, | ||
860 | get_dai_name(cpu_dai->type), num); | ||
861 | |||
862 | if (codec_dai->playback.channels_min) | ||
863 | playback = 1; | ||
864 | if (codec_dai->capture.channels_min) | ||
865 | capture = 1; | ||
866 | |||
867 | ret = snd_pcm_new(codec->card, new_name, codec->pcm_devs++, playback, | ||
868 | capture, &pcm); | ||
869 | if (ret < 0) { | ||
870 | printk(KERN_ERR "asoc: can't create pcm for codec %s\n", codec->name); | ||
871 | kfree(rtd); | ||
872 | return ret; | ||
873 | } | ||
874 | |||
875 | pcm->private_data = rtd; | ||
876 | soc_pcm_ops.mmap = socdev->platform->pcm_ops->mmap; | ||
877 | soc_pcm_ops.pointer = socdev->platform->pcm_ops->pointer; | ||
878 | soc_pcm_ops.ioctl = socdev->platform->pcm_ops->ioctl; | ||
879 | soc_pcm_ops.copy = socdev->platform->pcm_ops->copy; | ||
880 | soc_pcm_ops.silence = socdev->platform->pcm_ops->silence; | ||
881 | soc_pcm_ops.ack = socdev->platform->pcm_ops->ack; | ||
882 | soc_pcm_ops.page = socdev->platform->pcm_ops->page; | ||
883 | |||
884 | if (playback) | ||
885 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &soc_pcm_ops); | ||
886 | |||
887 | if (capture) | ||
888 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &soc_pcm_ops); | ||
889 | |||
890 | ret = socdev->platform->pcm_new(codec->card, codec_dai, pcm); | ||
891 | if (ret < 0) { | ||
892 | printk(KERN_ERR "asoc: platform pcm constructor failed\n"); | ||
893 | kfree(rtd); | ||
894 | return ret; | ||
895 | } | ||
896 | |||
897 | pcm->private_free = socdev->platform->pcm_free; | ||
898 | printk(KERN_INFO "asoc: %s <-> %s mapping ok\n", codec_dai->name, | ||
899 | cpu_dai->name); | ||
900 | return ret; | ||
901 | } | ||
902 | |||
903 | /* codec register dump */ | ||
904 | static ssize_t codec_reg_show(struct device *dev, | ||
905 | struct device_attribute *attr, char *buf) | ||
906 | { | ||
907 | struct snd_soc_device *devdata = dev_get_drvdata(dev); | ||
908 | struct snd_soc_codec *codec = devdata->codec; | ||
909 | int i, step = 1, count = 0; | ||
910 | |||
911 | if (!codec->reg_cache_size) | ||
912 | return 0; | ||
913 | |||
914 | if (codec->reg_cache_step) | ||
915 | step = codec->reg_cache_step; | ||
916 | |||
917 | count += sprintf(buf, "%s registers\n", codec->name); | ||
918 | for(i = 0; i < codec->reg_cache_size; i += step) | ||
919 | count += sprintf(buf + count, "%2x: %4x\n", i, codec->read(codec, i)); | ||
920 | |||
921 | return count; | ||
922 | } | ||
923 | static DEVICE_ATTR(codec_reg, 0444, codec_reg_show, NULL); | ||
924 | |||
925 | /** | ||
926 | * snd_soc_new_ac97_codec - initailise AC97 device | ||
927 | * @codec: audio codec | ||
928 | * @ops: AC97 bus operations | ||
929 | * @num: AC97 codec number | ||
930 | * | ||
931 | * Initialises AC97 codec resources for use by ad-hoc devices only. | ||
932 | */ | ||
933 | int snd_soc_new_ac97_codec(struct snd_soc_codec *codec, | ||
934 | struct snd_ac97_bus_ops *ops, int num) | ||
935 | { | ||
936 | mutex_lock(&codec->mutex); | ||
937 | |||
938 | codec->ac97 = kzalloc(sizeof(struct snd_ac97), GFP_KERNEL); | ||
939 | if (codec->ac97 == NULL) { | ||
940 | mutex_unlock(&codec->mutex); | ||
941 | return -ENOMEM; | ||
942 | } | ||
943 | |||
944 | codec->ac97->bus = kzalloc(sizeof(struct snd_ac97_bus), GFP_KERNEL); | ||
945 | if (codec->ac97->bus == NULL) { | ||
946 | kfree(codec->ac97); | ||
947 | codec->ac97 = NULL; | ||
948 | mutex_unlock(&codec->mutex); | ||
949 | return -ENOMEM; | ||
950 | } | ||
951 | |||
952 | codec->ac97->bus->ops = ops; | ||
953 | codec->ac97->num = num; | ||
954 | mutex_unlock(&codec->mutex); | ||
955 | return 0; | ||
956 | } | ||
957 | EXPORT_SYMBOL_GPL(snd_soc_new_ac97_codec); | ||
958 | |||
959 | /** | ||
960 | * snd_soc_free_ac97_codec - free AC97 codec device | ||
961 | * @codec: audio codec | ||
962 | * | ||
963 | * Frees AC97 codec device resources. | ||
964 | */ | ||
965 | void snd_soc_free_ac97_codec(struct snd_soc_codec *codec) | ||
966 | { | ||
967 | mutex_lock(&codec->mutex); | ||
968 | kfree(codec->ac97->bus); | ||
969 | kfree(codec->ac97); | ||
970 | codec->ac97 = NULL; | ||
971 | mutex_unlock(&codec->mutex); | ||
972 | } | ||
973 | EXPORT_SYMBOL_GPL(snd_soc_free_ac97_codec); | ||
974 | |||
975 | /** | ||
976 | * snd_soc_update_bits - update codec register bits | ||
977 | * @codec: audio codec | ||
978 | * @reg: codec register | ||
979 | * @mask: register mask | ||
980 | * @value: new value | ||
981 | * | ||
982 | * Writes new register value. | ||
983 | * | ||
984 | * Returns 1 for change else 0. | ||
985 | */ | ||
986 | int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg, | ||
987 | unsigned short mask, unsigned short value) | ||
988 | { | ||
989 | int change; | ||
990 | unsigned short old, new; | ||
991 | |||
992 | mutex_lock(&io_mutex); | ||
993 | old = snd_soc_read(codec, reg); | ||
994 | new = (old & ~mask) | value; | ||
995 | change = old != new; | ||
996 | if (change) | ||
997 | snd_soc_write(codec, reg, new); | ||
998 | |||
999 | mutex_unlock(&io_mutex); | ||
1000 | return change; | ||
1001 | } | ||
1002 | EXPORT_SYMBOL_GPL(snd_soc_update_bits); | ||
1003 | |||
1004 | /** | ||
1005 | * snd_soc_test_bits - test register for change | ||
1006 | * @codec: audio codec | ||
1007 | * @reg: codec register | ||
1008 | * @mask: register mask | ||
1009 | * @value: new value | ||
1010 | * | ||
1011 | * Tests a register with a new value and checks if the new value is | ||
1012 | * different from the old value. | ||
1013 | * | ||
1014 | * Returns 1 for change else 0. | ||
1015 | */ | ||
1016 | int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg, | ||
1017 | unsigned short mask, unsigned short value) | ||
1018 | { | ||
1019 | int change; | ||
1020 | unsigned short old, new; | ||
1021 | |||
1022 | mutex_lock(&io_mutex); | ||
1023 | old = snd_soc_read(codec, reg); | ||
1024 | new = (old & ~mask) | value; | ||
1025 | change = old != new; | ||
1026 | mutex_unlock(&io_mutex); | ||
1027 | |||
1028 | return change; | ||
1029 | } | ||
1030 | EXPORT_SYMBOL_GPL(snd_soc_test_bits); | ||
1031 | |||
1032 | /** | ||
1033 | * snd_soc_new_pcms - create new sound card and pcms | ||
1034 | * @socdev: the SoC audio device | ||
1035 | * | ||
1036 | * Create a new sound card based upon the codec and interface pcms. | ||
1037 | * | ||
1038 | * Returns 0 for success, else error. | ||
1039 | */ | ||
1040 | int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid) | ||
1041 | { | ||
1042 | struct snd_soc_codec *codec = socdev->codec; | ||
1043 | struct snd_soc_machine *machine = socdev->machine; | ||
1044 | int ret = 0, i; | ||
1045 | |||
1046 | mutex_lock(&codec->mutex); | ||
1047 | |||
1048 | /* register a sound card */ | ||
1049 | codec->card = snd_card_new(idx, xid, codec->owner, 0); | ||
1050 | if (!codec->card) { | ||
1051 | printk(KERN_ERR "asoc: can't create sound card for codec %s\n", | ||
1052 | codec->name); | ||
1053 | mutex_unlock(&codec->mutex); | ||
1054 | return -ENODEV; | ||
1055 | } | ||
1056 | |||
1057 | codec->card->dev = socdev->dev; | ||
1058 | codec->card->private_data = codec; | ||
1059 | strncpy(codec->card->driver, codec->name, sizeof(codec->card->driver)); | ||
1060 | |||
1061 | /* create the pcms */ | ||
1062 | for(i = 0; i < machine->num_links; i++) { | ||
1063 | ret = soc_new_pcm(socdev, &machine->dai_link[i], i); | ||
1064 | if (ret < 0) { | ||
1065 | printk(KERN_ERR "asoc: can't create pcm %s\n", | ||
1066 | machine->dai_link[i].stream_name); | ||
1067 | mutex_unlock(&codec->mutex); | ||
1068 | return ret; | ||
1069 | } | ||
1070 | } | ||
1071 | |||
1072 | mutex_unlock(&codec->mutex); | ||
1073 | return ret; | ||
1074 | } | ||
1075 | EXPORT_SYMBOL_GPL(snd_soc_new_pcms); | ||
1076 | |||
1077 | /** | ||
1078 | * snd_soc_register_card - register sound card | ||
1079 | * @socdev: the SoC audio device | ||
1080 | * | ||
1081 | * Register a SoC sound card. Also registers an AC97 device if the | ||
1082 | * codec is AC97 for ad hoc devices. | ||
1083 | * | ||
1084 | * Returns 0 for success, else error. | ||
1085 | */ | ||
1086 | int snd_soc_register_card(struct snd_soc_device *socdev) | ||
1087 | { | ||
1088 | struct snd_soc_codec *codec = socdev->codec; | ||
1089 | struct snd_soc_machine *machine = socdev->machine; | ||
1090 | int ret = 0, i, ac97 = 0, err = 0; | ||
1091 | |||
1092 | mutex_lock(&codec->mutex); | ||
1093 | for(i = 0; i < machine->num_links; i++) { | ||
1094 | if (socdev->machine->dai_link[i].init) { | ||
1095 | err = socdev->machine->dai_link[i].init(codec); | ||
1096 | if (err < 0) { | ||
1097 | printk(KERN_ERR "asoc: failed to init %s\n", | ||
1098 | socdev->machine->dai_link[i].stream_name); | ||
1099 | continue; | ||
1100 | } | ||
1101 | } | ||
1102 | if (socdev->machine->dai_link[i].cpu_dai->type == SND_SOC_DAI_AC97) | ||
1103 | ac97 = 1; | ||
1104 | } | ||
1105 | snprintf(codec->card->shortname, sizeof(codec->card->shortname), | ||
1106 | "%s", machine->name); | ||
1107 | snprintf(codec->card->longname, sizeof(codec->card->longname), | ||
1108 | "%s (%s)", machine->name, codec->name); | ||
1109 | |||
1110 | ret = snd_card_register(codec->card); | ||
1111 | if (ret < 0) { | ||
1112 | printk(KERN_ERR "asoc: failed to register soundcard for codec %s\n", | ||
1113 | codec->name); | ||
1114 | goto out; | ||
1115 | } | ||
1116 | |||
1117 | #ifdef CONFIG_SND_SOC_AC97_BUS | ||
1118 | if (ac97) { | ||
1119 | ret = soc_ac97_dev_register(codec); | ||
1120 | if (ret < 0) { | ||
1121 | printk(KERN_ERR "asoc: AC97 device register failed\n"); | ||
1122 | snd_card_free(codec->card); | ||
1123 | goto out; | ||
1124 | } | ||
1125 | } | ||
1126 | #endif | ||
1127 | |||
1128 | err = snd_soc_dapm_sys_add(socdev->dev); | ||
1129 | if (err < 0) | ||
1130 | printk(KERN_WARNING "asoc: failed to add dapm sysfs entries\n"); | ||
1131 | |||
1132 | err = device_create_file(socdev->dev, &dev_attr_codec_reg); | ||
1133 | if (err < 0) | ||
1134 | printk(KERN_WARNING "asoc: failed to add codec sysfs entries\n"); | ||
1135 | out: | ||
1136 | mutex_unlock(&codec->mutex); | ||
1137 | return ret; | ||
1138 | } | ||
1139 | EXPORT_SYMBOL_GPL(snd_soc_register_card); | ||
1140 | |||
1141 | /** | ||
1142 | * snd_soc_free_pcms - free sound card and pcms | ||
1143 | * @socdev: the SoC audio device | ||
1144 | * | ||
1145 | * Frees sound card and pcms associated with the socdev. | ||
1146 | * Also unregister the codec if it is an AC97 device. | ||
1147 | */ | ||
1148 | void snd_soc_free_pcms(struct snd_soc_device *socdev) | ||
1149 | { | ||
1150 | struct snd_soc_codec *codec = socdev->codec; | ||
1151 | |||
1152 | mutex_lock(&codec->mutex); | ||
1153 | #ifdef CONFIG_SND_SOC_AC97_BUS | ||
1154 | if (codec->ac97) | ||
1155 | soc_ac97_dev_unregister(codec); | ||
1156 | #endif | ||
1157 | |||
1158 | if (codec->card) | ||
1159 | snd_card_free(codec->card); | ||
1160 | device_remove_file(socdev->dev, &dev_attr_codec_reg); | ||
1161 | mutex_unlock(&codec->mutex); | ||
1162 | } | ||
1163 | EXPORT_SYMBOL_GPL(snd_soc_free_pcms); | ||
1164 | |||
1165 | /** | ||
1166 | * snd_soc_set_runtime_hwparams - set the runtime hardware parameters | ||
1167 | * @substream: the pcm substream | ||
1168 | * @hw: the hardware parameters | ||
1169 | * | ||
1170 | * Sets the substream runtime hardware parameters. | ||
1171 | */ | ||
1172 | int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream, | ||
1173 | const struct snd_pcm_hardware *hw) | ||
1174 | { | ||
1175 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
1176 | runtime->hw.info = hw->info; | ||
1177 | runtime->hw.formats = hw->formats; | ||
1178 | runtime->hw.period_bytes_min = hw->period_bytes_min; | ||
1179 | runtime->hw.period_bytes_max = hw->period_bytes_max; | ||
1180 | runtime->hw.periods_min = hw->periods_min; | ||
1181 | runtime->hw.periods_max = hw->periods_max; | ||
1182 | runtime->hw.buffer_bytes_max = hw->buffer_bytes_max; | ||
1183 | runtime->hw.fifo_size = hw->fifo_size; | ||
1184 | return 0; | ||
1185 | } | ||
1186 | EXPORT_SYMBOL_GPL(snd_soc_set_runtime_hwparams); | ||
1187 | |||
1188 | /** | ||
1189 | * snd_soc_cnew - create new control | ||
1190 | * @_template: control template | ||
1191 | * @data: control private data | ||
1192 | * @lnng_name: control long name | ||
1193 | * | ||
1194 | * Create a new mixer control from a template control. | ||
1195 | * | ||
1196 | * Returns 0 for success, else error. | ||
1197 | */ | ||
1198 | struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template, | ||
1199 | void *data, char *long_name) | ||
1200 | { | ||
1201 | struct snd_kcontrol_new template; | ||
1202 | |||
1203 | memcpy(&template, _template, sizeof(template)); | ||
1204 | if (long_name) | ||
1205 | template.name = long_name; | ||
1206 | template.access = SNDRV_CTL_ELEM_ACCESS_READWRITE; | ||
1207 | template.index = 0; | ||
1208 | |||
1209 | return snd_ctl_new1(&template, data); | ||
1210 | } | ||
1211 | EXPORT_SYMBOL_GPL(snd_soc_cnew); | ||
1212 | |||
1213 | /** | ||
1214 | * snd_soc_info_enum_double - enumerated double mixer info callback | ||
1215 | * @kcontrol: mixer control | ||
1216 | * @uinfo: control element information | ||
1217 | * | ||
1218 | * Callback to provide information about a double enumerated | ||
1219 | * mixer control. | ||
1220 | * | ||
1221 | * Returns 0 for success. | ||
1222 | */ | ||
1223 | int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol, | ||
1224 | struct snd_ctl_elem_info *uinfo) | ||
1225 | { | ||
1226 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | ||
1227 | |||
1228 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
1229 | uinfo->count = e->shift_l == e->shift_r ? 1 : 2; | ||
1230 | uinfo->value.enumerated.items = e->mask; | ||
1231 | |||
1232 | if (uinfo->value.enumerated.item > e->mask - 1) | ||
1233 | uinfo->value.enumerated.item = e->mask - 1; | ||
1234 | strcpy(uinfo->value.enumerated.name, | ||
1235 | e->texts[uinfo->value.enumerated.item]); | ||
1236 | return 0; | ||
1237 | } | ||
1238 | EXPORT_SYMBOL_GPL(snd_soc_info_enum_double); | ||
1239 | |||
1240 | /** | ||
1241 | * snd_soc_get_enum_double - enumerated double mixer get callback | ||
1242 | * @kcontrol: mixer control | ||
1243 | * @uinfo: control element information | ||
1244 | * | ||
1245 | * Callback to get the value of a double enumerated mixer. | ||
1246 | * | ||
1247 | * Returns 0 for success. | ||
1248 | */ | ||
1249 | int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol, | ||
1250 | struct snd_ctl_elem_value *ucontrol) | ||
1251 | { | ||
1252 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1253 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | ||
1254 | unsigned short val, bitmask; | ||
1255 | |||
1256 | for (bitmask = 1; bitmask < e->mask; bitmask <<= 1) | ||
1257 | ; | ||
1258 | val = snd_soc_read(codec, e->reg); | ||
1259 | ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & (bitmask - 1); | ||
1260 | if (e->shift_l != e->shift_r) | ||
1261 | ucontrol->value.enumerated.item[1] = | ||
1262 | (val >> e->shift_r) & (bitmask - 1); | ||
1263 | |||
1264 | return 0; | ||
1265 | } | ||
1266 | EXPORT_SYMBOL_GPL(snd_soc_get_enum_double); | ||
1267 | |||
1268 | /** | ||
1269 | * snd_soc_put_enum_double - enumerated double mixer put callback | ||
1270 | * @kcontrol: mixer control | ||
1271 | * @uinfo: control element information | ||
1272 | * | ||
1273 | * Callback to set the value of a double enumerated mixer. | ||
1274 | * | ||
1275 | * Returns 0 for success. | ||
1276 | */ | ||
1277 | int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol, | ||
1278 | struct snd_ctl_elem_value *ucontrol) | ||
1279 | { | ||
1280 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1281 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | ||
1282 | unsigned short val; | ||
1283 | unsigned short mask, bitmask; | ||
1284 | |||
1285 | for (bitmask = 1; bitmask < e->mask; bitmask <<= 1) | ||
1286 | ; | ||
1287 | if (ucontrol->value.enumerated.item[0] > e->mask - 1) | ||
1288 | return -EINVAL; | ||
1289 | val = ucontrol->value.enumerated.item[0] << e->shift_l; | ||
1290 | mask = (bitmask - 1) << e->shift_l; | ||
1291 | if (e->shift_l != e->shift_r) { | ||
1292 | if (ucontrol->value.enumerated.item[1] > e->mask - 1) | ||
1293 | return -EINVAL; | ||
1294 | val |= ucontrol->value.enumerated.item[1] << e->shift_r; | ||
1295 | mask |= (bitmask - 1) << e->shift_r; | ||
1296 | } | ||
1297 | |||
1298 | return snd_soc_update_bits(codec, e->reg, mask, val); | ||
1299 | } | ||
1300 | EXPORT_SYMBOL_GPL(snd_soc_put_enum_double); | ||
1301 | |||
1302 | /** | ||
1303 | * snd_soc_info_enum_ext - external enumerated single mixer info callback | ||
1304 | * @kcontrol: mixer control | ||
1305 | * @uinfo: control element information | ||
1306 | * | ||
1307 | * Callback to provide information about an external enumerated | ||
1308 | * single mixer. | ||
1309 | * | ||
1310 | * Returns 0 for success. | ||
1311 | */ | ||
1312 | int snd_soc_info_enum_ext(struct snd_kcontrol *kcontrol, | ||
1313 | struct snd_ctl_elem_info *uinfo) | ||
1314 | { | ||
1315 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | ||
1316 | |||
1317 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
1318 | uinfo->count = 1; | ||
1319 | uinfo->value.enumerated.items = e->mask; | ||
1320 | |||
1321 | if (uinfo->value.enumerated.item > e->mask - 1) | ||
1322 | uinfo->value.enumerated.item = e->mask - 1; | ||
1323 | strcpy(uinfo->value.enumerated.name, | ||
1324 | e->texts[uinfo->value.enumerated.item]); | ||
1325 | return 0; | ||
1326 | } | ||
1327 | EXPORT_SYMBOL_GPL(snd_soc_info_enum_ext); | ||
1328 | |||
1329 | /** | ||
1330 | * snd_soc_info_volsw_ext - external single mixer info callback | ||
1331 | * @kcontrol: mixer control | ||
1332 | * @uinfo: control element information | ||
1333 | * | ||
1334 | * Callback to provide information about a single external mixer control. | ||
1335 | * | ||
1336 | * Returns 0 for success. | ||
1337 | */ | ||
1338 | int snd_soc_info_volsw_ext(struct snd_kcontrol *kcontrol, | ||
1339 | struct snd_ctl_elem_info *uinfo) | ||
1340 | { | ||
1341 | int mask = kcontrol->private_value; | ||
1342 | |||
1343 | uinfo->type = | ||
1344 | mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
1345 | uinfo->count = 1; | ||
1346 | uinfo->value.integer.min = 0; | ||
1347 | uinfo->value.integer.max = mask; | ||
1348 | return 0; | ||
1349 | } | ||
1350 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw_ext); | ||
1351 | |||
1352 | /** | ||
1353 | * snd_soc_info_bool_ext - external single boolean mixer info callback | ||
1354 | * @kcontrol: mixer control | ||
1355 | * @uinfo: control element information | ||
1356 | * | ||
1357 | * Callback to provide information about a single boolean external mixer control. | ||
1358 | * | ||
1359 | * Returns 0 for success. | ||
1360 | */ | ||
1361 | int snd_soc_info_bool_ext(struct snd_kcontrol *kcontrol, | ||
1362 | struct snd_ctl_elem_info *uinfo) | ||
1363 | { | ||
1364 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
1365 | uinfo->count = 1; | ||
1366 | uinfo->value.integer.min = 0; | ||
1367 | uinfo->value.integer.max = 1; | ||
1368 | return 0; | ||
1369 | } | ||
1370 | EXPORT_SYMBOL_GPL(snd_soc_info_bool_ext); | ||
1371 | |||
1372 | /** | ||
1373 | * snd_soc_info_volsw - single mixer info callback | ||
1374 | * @kcontrol: mixer control | ||
1375 | * @uinfo: control element information | ||
1376 | * | ||
1377 | * Callback to provide information about a single mixer control. | ||
1378 | * | ||
1379 | * Returns 0 for success. | ||
1380 | */ | ||
1381 | int snd_soc_info_volsw(struct snd_kcontrol *kcontrol, | ||
1382 | struct snd_ctl_elem_info *uinfo) | ||
1383 | { | ||
1384 | int mask = (kcontrol->private_value >> 16) & 0xff; | ||
1385 | int shift = (kcontrol->private_value >> 8) & 0x0f; | ||
1386 | int rshift = (kcontrol->private_value >> 12) & 0x0f; | ||
1387 | |||
1388 | uinfo->type = | ||
1389 | mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
1390 | uinfo->count = shift == rshift ? 1 : 2; | ||
1391 | uinfo->value.integer.min = 0; | ||
1392 | uinfo->value.integer.max = mask; | ||
1393 | return 0; | ||
1394 | } | ||
1395 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw); | ||
1396 | |||
1397 | /** | ||
1398 | * snd_soc_get_volsw - single mixer get callback | ||
1399 | * @kcontrol: mixer control | ||
1400 | * @uinfo: control element information | ||
1401 | * | ||
1402 | * Callback to get the value of a single mixer control. | ||
1403 | * | ||
1404 | * Returns 0 for success. | ||
1405 | */ | ||
1406 | int snd_soc_get_volsw(struct snd_kcontrol *kcontrol, | ||
1407 | struct snd_ctl_elem_value *ucontrol) | ||
1408 | { | ||
1409 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1410 | int reg = kcontrol->private_value & 0xff; | ||
1411 | int shift = (kcontrol->private_value >> 8) & 0x0f; | ||
1412 | int rshift = (kcontrol->private_value >> 12) & 0x0f; | ||
1413 | int mask = (kcontrol->private_value >> 16) & 0xff; | ||
1414 | int invert = (kcontrol->private_value >> 24) & 0x01; | ||
1415 | |||
1416 | ucontrol->value.integer.value[0] = | ||
1417 | (snd_soc_read(codec, reg) >> shift) & mask; | ||
1418 | if (shift != rshift) | ||
1419 | ucontrol->value.integer.value[1] = | ||
1420 | (snd_soc_read(codec, reg) >> rshift) & mask; | ||
1421 | if (invert) { | ||
1422 | ucontrol->value.integer.value[0] = | ||
1423 | mask - ucontrol->value.integer.value[0]; | ||
1424 | if (shift != rshift) | ||
1425 | ucontrol->value.integer.value[1] = | ||
1426 | mask - ucontrol->value.integer.value[1]; | ||
1427 | } | ||
1428 | |||
1429 | return 0; | ||
1430 | } | ||
1431 | EXPORT_SYMBOL_GPL(snd_soc_get_volsw); | ||
1432 | |||
1433 | /** | ||
1434 | * snd_soc_put_volsw - single mixer put callback | ||
1435 | * @kcontrol: mixer control | ||
1436 | * @uinfo: control element information | ||
1437 | * | ||
1438 | * Callback to set the value of a single mixer control. | ||
1439 | * | ||
1440 | * Returns 0 for success. | ||
1441 | */ | ||
1442 | int snd_soc_put_volsw(struct snd_kcontrol *kcontrol, | ||
1443 | struct snd_ctl_elem_value *ucontrol) | ||
1444 | { | ||
1445 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1446 | int reg = kcontrol->private_value & 0xff; | ||
1447 | int shift = (kcontrol->private_value >> 8) & 0x0f; | ||
1448 | int rshift = (kcontrol->private_value >> 12) & 0x0f; | ||
1449 | int mask = (kcontrol->private_value >> 16) & 0xff; | ||
1450 | int invert = (kcontrol->private_value >> 24) & 0x01; | ||
1451 | int err; | ||
1452 | unsigned short val, val2, val_mask; | ||
1453 | |||
1454 | val = (ucontrol->value.integer.value[0] & mask); | ||
1455 | if (invert) | ||
1456 | val = mask - val; | ||
1457 | val_mask = mask << shift; | ||
1458 | val = val << shift; | ||
1459 | if (shift != rshift) { | ||
1460 | val2 = (ucontrol->value.integer.value[1] & mask); | ||
1461 | if (invert) | ||
1462 | val2 = mask - val2; | ||
1463 | val_mask |= mask << rshift; | ||
1464 | val |= val2 << rshift; | ||
1465 | } | ||
1466 | err = snd_soc_update_bits(codec, reg, val_mask, val); | ||
1467 | return err; | ||
1468 | } | ||
1469 | EXPORT_SYMBOL_GPL(snd_soc_put_volsw); | ||
1470 | |||
1471 | /** | ||
1472 | * snd_soc_info_volsw_2r - double mixer info callback | ||
1473 | * @kcontrol: mixer control | ||
1474 | * @uinfo: control element information | ||
1475 | * | ||
1476 | * Callback to provide information about a double mixer control that | ||
1477 | * spans 2 codec registers. | ||
1478 | * | ||
1479 | * Returns 0 for success. | ||
1480 | */ | ||
1481 | int snd_soc_info_volsw_2r(struct snd_kcontrol *kcontrol, | ||
1482 | struct snd_ctl_elem_info *uinfo) | ||
1483 | { | ||
1484 | int mask = (kcontrol->private_value >> 12) & 0xff; | ||
1485 | |||
1486 | uinfo->type = | ||
1487 | mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
1488 | uinfo->count = 2; | ||
1489 | uinfo->value.integer.min = 0; | ||
1490 | uinfo->value.integer.max = mask; | ||
1491 | return 0; | ||
1492 | } | ||
1493 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw_2r); | ||
1494 | |||
1495 | /** | ||
1496 | * snd_soc_get_volsw_2r - double mixer get callback | ||
1497 | * @kcontrol: mixer control | ||
1498 | * @uinfo: control element information | ||
1499 | * | ||
1500 | * Callback to get the value of a double mixer control that spans 2 registers. | ||
1501 | * | ||
1502 | * Returns 0 for success. | ||
1503 | */ | ||
1504 | int snd_soc_get_volsw_2r(struct snd_kcontrol *kcontrol, | ||
1505 | struct snd_ctl_elem_value *ucontrol) | ||
1506 | { | ||
1507 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1508 | int reg = kcontrol->private_value & 0xff; | ||
1509 | int reg2 = (kcontrol->private_value >> 24) & 0xff; | ||
1510 | int shift = (kcontrol->private_value >> 8) & 0x0f; | ||
1511 | int mask = (kcontrol->private_value >> 12) & 0xff; | ||
1512 | int invert = (kcontrol->private_value >> 20) & 0x01; | ||
1513 | |||
1514 | ucontrol->value.integer.value[0] = | ||
1515 | (snd_soc_read(codec, reg) >> shift) & mask; | ||
1516 | ucontrol->value.integer.value[1] = | ||
1517 | (snd_soc_read(codec, reg2) >> shift) & mask; | ||
1518 | if (invert) { | ||
1519 | ucontrol->value.integer.value[0] = | ||
1520 | mask - ucontrol->value.integer.value[0]; | ||
1521 | ucontrol->value.integer.value[1] = | ||
1522 | mask - ucontrol->value.integer.value[1]; | ||
1523 | } | ||
1524 | |||
1525 | return 0; | ||
1526 | } | ||
1527 | EXPORT_SYMBOL_GPL(snd_soc_get_volsw_2r); | ||
1528 | |||
1529 | /** | ||
1530 | * snd_soc_put_volsw_2r - double mixer set callback | ||
1531 | * @kcontrol: mixer control | ||
1532 | * @uinfo: control element information | ||
1533 | * | ||
1534 | * Callback to set the value of a double mixer control that spans 2 registers. | ||
1535 | * | ||
1536 | * Returns 0 for success. | ||
1537 | */ | ||
1538 | int snd_soc_put_volsw_2r(struct snd_kcontrol *kcontrol, | ||
1539 | struct snd_ctl_elem_value *ucontrol) | ||
1540 | { | ||
1541 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1542 | int reg = kcontrol->private_value & 0xff; | ||
1543 | int reg2 = (kcontrol->private_value >> 24) & 0xff; | ||
1544 | int shift = (kcontrol->private_value >> 8) & 0x0f; | ||
1545 | int mask = (kcontrol->private_value >> 12) & 0xff; | ||
1546 | int invert = (kcontrol->private_value >> 20) & 0x01; | ||
1547 | int err; | ||
1548 | unsigned short val, val2, val_mask; | ||
1549 | |||
1550 | val_mask = mask << shift; | ||
1551 | val = (ucontrol->value.integer.value[0] & mask); | ||
1552 | val2 = (ucontrol->value.integer.value[1] & mask); | ||
1553 | |||
1554 | if (invert) { | ||
1555 | val = mask - val; | ||
1556 | val2 = mask - val2; | ||
1557 | } | ||
1558 | |||
1559 | val = val << shift; | ||
1560 | val2 = val2 << shift; | ||
1561 | |||
1562 | if ((err = snd_soc_update_bits(codec, reg, val_mask, val)) < 0) | ||
1563 | return err; | ||
1564 | |||
1565 | err = snd_soc_update_bits(codec, reg2, val_mask, val2); | ||
1566 | return err; | ||
1567 | } | ||
1568 | EXPORT_SYMBOL_GPL(snd_soc_put_volsw_2r); | ||
1569 | |||
1570 | static int __devinit snd_soc_init(void) | ||
1571 | { | ||
1572 | printk(KERN_INFO "ASoC version %s\n", SND_SOC_VERSION); | ||
1573 | return platform_driver_register(&soc_driver); | ||
1574 | } | ||
1575 | |||
1576 | static void snd_soc_exit(void) | ||
1577 | { | ||
1578 | platform_driver_unregister(&soc_driver); | ||
1579 | } | ||
1580 | |||
1581 | module_init(snd_soc_init); | ||
1582 | module_exit(snd_soc_exit); | ||
1583 | |||
1584 | /* Module information */ | ||
1585 | MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com"); | ||
1586 | MODULE_DESCRIPTION("ALSA SoC Core"); | ||
1587 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c new file mode 100644 index 000000000000..7caf8c7b0ac5 --- /dev/null +++ b/sound/soc/soc-dapm.c | |||
@@ -0,0 +1,1323 @@ | |||
1 | /* | ||
2 | * soc-dapm.c -- ALSA SoC Dynamic Audio Power Management | ||
3 | * | ||
4 | * Copyright 2005 Wolfson Microelectronics PLC. | ||
5 | * Author: Liam Girdwood | ||
6 | * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | * | ||
13 | * Revision history | ||
14 | * 12th Aug 2005 Initial version. | ||
15 | * 25th Oct 2005 Implemented path power domain. | ||
16 | * 18th Dec 2005 Implemented machine and stream level power domain. | ||
17 | * | ||
18 | * Features: | ||
19 | * o Changes power status of internal codec blocks depending on the | ||
20 | * dynamic configuration of codec internal audio paths and active | ||
21 | * DAC's/ADC's. | ||
22 | * o Platform power domain - can support external components i.e. amps and | ||
23 | * mic/meadphone insertion events. | ||
24 | * o Automatic Mic Bias support | ||
25 | * o Jack insertion power event initiation - e.g. hp insertion will enable | ||
26 | * sinks, dacs, etc | ||
27 | * o Delayed powerdown of audio susbsytem to reduce pops between a quick | ||
28 | * device reopen. | ||
29 | * | ||
30 | * Todo: | ||
31 | * o DAPM power change sequencing - allow for configurable per | ||
32 | * codec sequences. | ||
33 | * o Support for analogue bias optimisation. | ||
34 | * o Support for reduced codec oversampling rates. | ||
35 | * o Support for reduced codec bias currents. | ||
36 | */ | ||
37 | |||
38 | #include <linux/module.h> | ||
39 | #include <linux/moduleparam.h> | ||
40 | #include <linux/init.h> | ||
41 | #include <linux/delay.h> | ||
42 | #include <linux/pm.h> | ||
43 | #include <linux/bitops.h> | ||
44 | #include <linux/platform_device.h> | ||
45 | #include <linux/jiffies.h> | ||
46 | #include <sound/driver.h> | ||
47 | #include <sound/core.h> | ||
48 | #include <sound/pcm.h> | ||
49 | #include <sound/pcm_params.h> | ||
50 | #include <sound/soc-dapm.h> | ||
51 | #include <sound/initval.h> | ||
52 | |||
53 | /* debug */ | ||
54 | #define DAPM_DEBUG 0 | ||
55 | #if DAPM_DEBUG | ||
56 | #define dump_dapm(codec, action) dbg_dump_dapm(codec, action) | ||
57 | #define dbg(format, arg...) printk(format, ## arg) | ||
58 | #else | ||
59 | #define dump_dapm(codec, action) | ||
60 | #define dbg(format, arg...) | ||
61 | #endif | ||
62 | |||
63 | #define POP_DEBUG 0 | ||
64 | #if POP_DEBUG | ||
65 | #define POP_TIME 500 /* 500 msecs - change if pop debug is too fast */ | ||
66 | #define pop_wait(time) schedule_timeout_interruptible(msecs_to_jiffies(time)) | ||
67 | #define pop_dbg(format, arg...) printk(format, ## arg); pop_wait(POP_TIME) | ||
68 | #else | ||
69 | #define pop_dbg(format, arg...) | ||
70 | #define pop_wait(time) | ||
71 | #endif | ||
72 | |||
73 | /* dapm power sequences - make this per codec in the future */ | ||
74 | static int dapm_up_seq[] = { | ||
75 | snd_soc_dapm_pre, snd_soc_dapm_micbias, snd_soc_dapm_mic, | ||
76 | snd_soc_dapm_mux, snd_soc_dapm_dac, snd_soc_dapm_mixer, snd_soc_dapm_pga, | ||
77 | snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk, snd_soc_dapm_post | ||
78 | }; | ||
79 | static int dapm_down_seq[] = { | ||
80 | snd_soc_dapm_pre, snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk, | ||
81 | snd_soc_dapm_pga, snd_soc_dapm_mixer, snd_soc_dapm_dac, snd_soc_dapm_mic, | ||
82 | snd_soc_dapm_micbias, snd_soc_dapm_mux, snd_soc_dapm_post | ||
83 | }; | ||
84 | |||
85 | static int dapm_status = 1; | ||
86 | module_param(dapm_status, int, 0); | ||
87 | MODULE_PARM_DESC(dapm_status, "enable DPM sysfs entries"); | ||
88 | |||
89 | /* create a new dapm widget */ | ||
90 | static inline struct snd_soc_dapm_widget *dapm_cnew_widget( | ||
91 | const struct snd_soc_dapm_widget *_widget) | ||
92 | { | ||
93 | return kmemdup(_widget, sizeof(*_widget), GFP_KERNEL); | ||
94 | } | ||
95 | |||
96 | /* set up initial codec paths */ | ||
97 | static void dapm_set_path_status(struct snd_soc_dapm_widget *w, | ||
98 | struct snd_soc_dapm_path *p, int i) | ||
99 | { | ||
100 | switch (w->id) { | ||
101 | case snd_soc_dapm_switch: | ||
102 | case snd_soc_dapm_mixer: { | ||
103 | int val; | ||
104 | int reg = w->kcontrols[i].private_value & 0xff; | ||
105 | int shift = (w->kcontrols[i].private_value >> 8) & 0x0f; | ||
106 | int mask = (w->kcontrols[i].private_value >> 16) & 0xff; | ||
107 | int invert = (w->kcontrols[i].private_value >> 24) & 0x01; | ||
108 | |||
109 | val = snd_soc_read(w->codec, reg); | ||
110 | val = (val >> shift) & mask; | ||
111 | |||
112 | if ((invert && !val) || (!invert && val)) | ||
113 | p->connect = 1; | ||
114 | else | ||
115 | p->connect = 0; | ||
116 | } | ||
117 | break; | ||
118 | case snd_soc_dapm_mux: { | ||
119 | struct soc_enum *e = (struct soc_enum *)w->kcontrols[i].private_value; | ||
120 | int val, item, bitmask; | ||
121 | |||
122 | for (bitmask = 1; bitmask < e->mask; bitmask <<= 1) | ||
123 | ; | ||
124 | val = snd_soc_read(w->codec, e->reg); | ||
125 | item = (val >> e->shift_l) & (bitmask - 1); | ||
126 | |||
127 | p->connect = 0; | ||
128 | for (i = 0; i < e->mask; i++) { | ||
129 | if (!(strcmp(p->name, e->texts[i])) && item == i) | ||
130 | p->connect = 1; | ||
131 | } | ||
132 | } | ||
133 | break; | ||
134 | /* does not effect routing - always connected */ | ||
135 | case snd_soc_dapm_pga: | ||
136 | case snd_soc_dapm_output: | ||
137 | case snd_soc_dapm_adc: | ||
138 | case snd_soc_dapm_input: | ||
139 | case snd_soc_dapm_dac: | ||
140 | case snd_soc_dapm_micbias: | ||
141 | case snd_soc_dapm_vmid: | ||
142 | p->connect = 1; | ||
143 | break; | ||
144 | /* does effect routing - dynamically connected */ | ||
145 | case snd_soc_dapm_hp: | ||
146 | case snd_soc_dapm_mic: | ||
147 | case snd_soc_dapm_spk: | ||
148 | case snd_soc_dapm_line: | ||
149 | case snd_soc_dapm_pre: | ||
150 | case snd_soc_dapm_post: | ||
151 | p->connect = 0; | ||
152 | break; | ||
153 | } | ||
154 | } | ||
155 | |||
156 | /* connect mux widget to it's interconnecting audio paths */ | ||
157 | static int dapm_connect_mux(struct snd_soc_codec *codec, | ||
158 | struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest, | ||
159 | struct snd_soc_dapm_path *path, const char *control_name, | ||
160 | const struct snd_kcontrol_new *kcontrol) | ||
161 | { | ||
162 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | ||
163 | int i; | ||
164 | |||
165 | for (i = 0; i < e->mask; i++) { | ||
166 | if (!(strcmp(control_name, e->texts[i]))) { | ||
167 | list_add(&path->list, &codec->dapm_paths); | ||
168 | list_add(&path->list_sink, &dest->sources); | ||
169 | list_add(&path->list_source, &src->sinks); | ||
170 | path->name = (char*)e->texts[i]; | ||
171 | dapm_set_path_status(dest, path, 0); | ||
172 | return 0; | ||
173 | } | ||
174 | } | ||
175 | |||
176 | return -ENODEV; | ||
177 | } | ||
178 | |||
179 | /* connect mixer widget to it's interconnecting audio paths */ | ||
180 | static int dapm_connect_mixer(struct snd_soc_codec *codec, | ||
181 | struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest, | ||
182 | struct snd_soc_dapm_path *path, const char *control_name) | ||
183 | { | ||
184 | int i; | ||
185 | |||
186 | /* search for mixer kcontrol */ | ||
187 | for (i = 0; i < dest->num_kcontrols; i++) { | ||
188 | if (!strcmp(control_name, dest->kcontrols[i].name)) { | ||
189 | list_add(&path->list, &codec->dapm_paths); | ||
190 | list_add(&path->list_sink, &dest->sources); | ||
191 | list_add(&path->list_source, &src->sinks); | ||
192 | path->name = dest->kcontrols[i].name; | ||
193 | dapm_set_path_status(dest, path, i); | ||
194 | return 0; | ||
195 | } | ||
196 | } | ||
197 | return -ENODEV; | ||
198 | } | ||
199 | |||
200 | /* update dapm codec register bits */ | ||
201 | static int dapm_update_bits(struct snd_soc_dapm_widget *widget) | ||
202 | { | ||
203 | int change, power; | ||
204 | unsigned short old, new; | ||
205 | struct snd_soc_codec *codec = widget->codec; | ||
206 | |||
207 | /* check for valid widgets */ | ||
208 | if (widget->reg < 0 || widget->id == snd_soc_dapm_input || | ||
209 | widget->id == snd_soc_dapm_output || | ||
210 | widget->id == snd_soc_dapm_hp || | ||
211 | widget->id == snd_soc_dapm_mic || | ||
212 | widget->id == snd_soc_dapm_line || | ||
213 | widget->id == snd_soc_dapm_spk) | ||
214 | return 0; | ||
215 | |||
216 | power = widget->power; | ||
217 | if (widget->invert) | ||
218 | power = (power ? 0:1); | ||
219 | |||
220 | old = snd_soc_read(codec, widget->reg); | ||
221 | new = (old & ~(0x1 << widget->shift)) | (power << widget->shift); | ||
222 | |||
223 | change = old != new; | ||
224 | if (change) { | ||
225 | pop_dbg("pop test %s : %s in %d ms\n", widget->name, | ||
226 | widget->power ? "on" : "off", POP_TIME); | ||
227 | snd_soc_write(codec, widget->reg, new); | ||
228 | pop_wait(POP_TIME); | ||
229 | } | ||
230 | dbg("reg old %x new %x change %d\n", old, new, change); | ||
231 | return change; | ||
232 | } | ||
233 | |||
234 | /* ramps the volume up or down to minimise pops before or after a | ||
235 | * DAPM power event */ | ||
236 | static int dapm_set_pga(struct snd_soc_dapm_widget *widget, int power) | ||
237 | { | ||
238 | const struct snd_kcontrol_new *k = widget->kcontrols; | ||
239 | |||
240 | if (widget->muted && !power) | ||
241 | return 0; | ||
242 | if (!widget->muted && power) | ||
243 | return 0; | ||
244 | |||
245 | if (widget->num_kcontrols && k) { | ||
246 | int reg = k->private_value & 0xff; | ||
247 | int shift = (k->private_value >> 8) & 0x0f; | ||
248 | int mask = (k->private_value >> 16) & 0xff; | ||
249 | int invert = (k->private_value >> 24) & 0x01; | ||
250 | |||
251 | if (power) { | ||
252 | int i; | ||
253 | /* power up has happended, increase volume to last level */ | ||
254 | if (invert) { | ||
255 | for (i = mask; i > widget->saved_value; i--) | ||
256 | snd_soc_update_bits(widget->codec, reg, mask, i); | ||
257 | } else { | ||
258 | for (i = 0; i < widget->saved_value; i++) | ||
259 | snd_soc_update_bits(widget->codec, reg, mask, i); | ||
260 | } | ||
261 | widget->muted = 0; | ||
262 | } else { | ||
263 | /* power down is about to occur, decrease volume to mute */ | ||
264 | int val = snd_soc_read(widget->codec, reg); | ||
265 | int i = widget->saved_value = (val >> shift) & mask; | ||
266 | if (invert) { | ||
267 | for (; i < mask; i++) | ||
268 | snd_soc_update_bits(widget->codec, reg, mask, i); | ||
269 | } else { | ||
270 | for (; i > 0; i--) | ||
271 | snd_soc_update_bits(widget->codec, reg, mask, i); | ||
272 | } | ||
273 | widget->muted = 1; | ||
274 | } | ||
275 | } | ||
276 | return 0; | ||
277 | } | ||
278 | |||
279 | /* create new dapm mixer control */ | ||
280 | static int dapm_new_mixer(struct snd_soc_codec *codec, | ||
281 | struct snd_soc_dapm_widget *w) | ||
282 | { | ||
283 | int i, ret = 0; | ||
284 | char name[32]; | ||
285 | struct snd_soc_dapm_path *path; | ||
286 | |||
287 | /* add kcontrol */ | ||
288 | for (i = 0; i < w->num_kcontrols; i++) { | ||
289 | |||
290 | /* match name */ | ||
291 | list_for_each_entry(path, &w->sources, list_sink) { | ||
292 | |||
293 | /* mixer/mux paths name must match control name */ | ||
294 | if (path->name != (char*)w->kcontrols[i].name) | ||
295 | continue; | ||
296 | |||
297 | /* add dapm control with long name */ | ||
298 | snprintf(name, 32, "%s %s", w->name, w->kcontrols[i].name); | ||
299 | path->long_name = kstrdup (name, GFP_KERNEL); | ||
300 | if (path->long_name == NULL) | ||
301 | return -ENOMEM; | ||
302 | |||
303 | path->kcontrol = snd_soc_cnew(&w->kcontrols[i], w, | ||
304 | path->long_name); | ||
305 | ret = snd_ctl_add(codec->card, path->kcontrol); | ||
306 | if (ret < 0) { | ||
307 | printk(KERN_ERR "asoc: failed to add dapm kcontrol %s\n", | ||
308 | path->long_name); | ||
309 | kfree(path->long_name); | ||
310 | path->long_name = NULL; | ||
311 | return ret; | ||
312 | } | ||
313 | } | ||
314 | } | ||
315 | return ret; | ||
316 | } | ||
317 | |||
318 | /* create new dapm mux control */ | ||
319 | static int dapm_new_mux(struct snd_soc_codec *codec, | ||
320 | struct snd_soc_dapm_widget *w) | ||
321 | { | ||
322 | struct snd_soc_dapm_path *path = NULL; | ||
323 | struct snd_kcontrol *kcontrol; | ||
324 | int ret = 0; | ||
325 | |||
326 | if (!w->num_kcontrols) { | ||
327 | printk(KERN_ERR "asoc: mux %s has no controls\n", w->name); | ||
328 | return -EINVAL; | ||
329 | } | ||
330 | |||
331 | kcontrol = snd_soc_cnew(&w->kcontrols[0], w, w->name); | ||
332 | ret = snd_ctl_add(codec->card, kcontrol); | ||
333 | if (ret < 0) | ||
334 | goto err; | ||
335 | |||
336 | list_for_each_entry(path, &w->sources, list_sink) | ||
337 | path->kcontrol = kcontrol; | ||
338 | |||
339 | return ret; | ||
340 | |||
341 | err: | ||
342 | printk(KERN_ERR "asoc: failed to add kcontrol %s\n", w->name); | ||
343 | return ret; | ||
344 | } | ||
345 | |||
346 | /* create new dapm volume control */ | ||
347 | static int dapm_new_pga(struct snd_soc_codec *codec, | ||
348 | struct snd_soc_dapm_widget *w) | ||
349 | { | ||
350 | struct snd_kcontrol *kcontrol; | ||
351 | int ret = 0; | ||
352 | |||
353 | if (!w->num_kcontrols) | ||
354 | return -EINVAL; | ||
355 | |||
356 | kcontrol = snd_soc_cnew(&w->kcontrols[0], w, w->name); | ||
357 | ret = snd_ctl_add(codec->card, kcontrol); | ||
358 | if (ret < 0) { | ||
359 | printk(KERN_ERR "asoc: failed to add kcontrol %s\n", w->name); | ||
360 | return ret; | ||
361 | } | ||
362 | |||
363 | return ret; | ||
364 | } | ||
365 | |||
366 | /* reset 'walked' bit for each dapm path */ | ||
367 | static inline void dapm_clear_walk(struct snd_soc_codec *codec) | ||
368 | { | ||
369 | struct snd_soc_dapm_path *p; | ||
370 | |||
371 | list_for_each_entry(p, &codec->dapm_paths, list) | ||
372 | p->walked = 0; | ||
373 | } | ||
374 | |||
375 | /* | ||
376 | * Recursively check for a completed path to an active or physically connected | ||
377 | * output widget. Returns number of complete paths. | ||
378 | */ | ||
379 | static int is_connected_output_ep(struct snd_soc_dapm_widget *widget) | ||
380 | { | ||
381 | struct snd_soc_dapm_path *path; | ||
382 | int con = 0; | ||
383 | |||
384 | if (widget->id == snd_soc_dapm_adc && widget->active) | ||
385 | return 1; | ||
386 | |||
387 | if (widget->connected) { | ||
388 | /* connected pin ? */ | ||
389 | if (widget->id == snd_soc_dapm_output && !widget->ext) | ||
390 | return 1; | ||
391 | |||
392 | /* connected jack or spk ? */ | ||
393 | if (widget->id == snd_soc_dapm_hp || widget->id == snd_soc_dapm_spk || | ||
394 | widget->id == snd_soc_dapm_line) | ||
395 | return 1; | ||
396 | } | ||
397 | |||
398 | list_for_each_entry(path, &widget->sinks, list_source) { | ||
399 | if (path->walked) | ||
400 | continue; | ||
401 | |||
402 | if (path->sink && path->connect) { | ||
403 | path->walked = 1; | ||
404 | con += is_connected_output_ep(path->sink); | ||
405 | } | ||
406 | } | ||
407 | |||
408 | return con; | ||
409 | } | ||
410 | |||
411 | /* | ||
412 | * Recursively check for a completed path to an active or physically connected | ||
413 | * input widget. Returns number of complete paths. | ||
414 | */ | ||
415 | static int is_connected_input_ep(struct snd_soc_dapm_widget *widget) | ||
416 | { | ||
417 | struct snd_soc_dapm_path *path; | ||
418 | int con = 0; | ||
419 | |||
420 | /* active stream ? */ | ||
421 | if (widget->id == snd_soc_dapm_dac && widget->active) | ||
422 | return 1; | ||
423 | |||
424 | if (widget->connected) { | ||
425 | /* connected pin ? */ | ||
426 | if (widget->id == snd_soc_dapm_input && !widget->ext) | ||
427 | return 1; | ||
428 | |||
429 | /* connected VMID/Bias for lower pops */ | ||
430 | if (widget->id == snd_soc_dapm_vmid) | ||
431 | return 1; | ||
432 | |||
433 | /* connected jack ? */ | ||
434 | if (widget->id == snd_soc_dapm_mic || widget->id == snd_soc_dapm_line) | ||
435 | return 1; | ||
436 | } | ||
437 | |||
438 | list_for_each_entry(path, &widget->sources, list_sink) { | ||
439 | if (path->walked) | ||
440 | continue; | ||
441 | |||
442 | if (path->source && path->connect) { | ||
443 | path->walked = 1; | ||
444 | con += is_connected_input_ep(path->source); | ||
445 | } | ||
446 | } | ||
447 | |||
448 | return con; | ||
449 | } | ||
450 | |||
451 | /* | ||
452 | * Scan each dapm widget for complete audio path. | ||
453 | * A complete path is a route that has valid endpoints i.e.:- | ||
454 | * | ||
455 | * o DAC to output pin. | ||
456 | * o Input Pin to ADC. | ||
457 | * o Input pin to Output pin (bypass, sidetone) | ||
458 | * o DAC to ADC (loopback). | ||
459 | */ | ||
460 | static int dapm_power_widgets(struct snd_soc_codec *codec, int event) | ||
461 | { | ||
462 | struct snd_soc_dapm_widget *w; | ||
463 | int in, out, i, c = 1, *seq = NULL, ret = 0, power_change, power; | ||
464 | |||
465 | /* do we have a sequenced stream event */ | ||
466 | if (event == SND_SOC_DAPM_STREAM_START) { | ||
467 | c = ARRAY_SIZE(dapm_up_seq); | ||
468 | seq = dapm_up_seq; | ||
469 | } else if (event == SND_SOC_DAPM_STREAM_STOP) { | ||
470 | c = ARRAY_SIZE(dapm_down_seq); | ||
471 | seq = dapm_down_seq; | ||
472 | } | ||
473 | |||
474 | for(i = 0; i < c; i++) { | ||
475 | list_for_each_entry(w, &codec->dapm_widgets, list) { | ||
476 | |||
477 | /* is widget in stream order */ | ||
478 | if (seq && seq[i] && w->id != seq[i]) | ||
479 | continue; | ||
480 | |||
481 | /* vmid - no action */ | ||
482 | if (w->id == snd_soc_dapm_vmid) | ||
483 | continue; | ||
484 | |||
485 | /* active ADC */ | ||
486 | if (w->id == snd_soc_dapm_adc && w->active) { | ||
487 | in = is_connected_input_ep(w); | ||
488 | dapm_clear_walk(w->codec); | ||
489 | w->power = (in != 0) ? 1 : 0; | ||
490 | dapm_update_bits(w); | ||
491 | continue; | ||
492 | } | ||
493 | |||
494 | /* active DAC */ | ||
495 | if (w->id == snd_soc_dapm_dac && w->active) { | ||
496 | out = is_connected_output_ep(w); | ||
497 | dapm_clear_walk(w->codec); | ||
498 | w->power = (out != 0) ? 1 : 0; | ||
499 | dapm_update_bits(w); | ||
500 | continue; | ||
501 | } | ||
502 | |||
503 | /* programmable gain/attenuation */ | ||
504 | if (w->id == snd_soc_dapm_pga) { | ||
505 | int on; | ||
506 | in = is_connected_input_ep(w); | ||
507 | dapm_clear_walk(w->codec); | ||
508 | out = is_connected_output_ep(w); | ||
509 | dapm_clear_walk(w->codec); | ||
510 | w->power = on = (out != 0 && in != 0) ? 1 : 0; | ||
511 | |||
512 | if (!on) | ||
513 | dapm_set_pga(w, on); /* lower volume to reduce pops */ | ||
514 | dapm_update_bits(w); | ||
515 | if (on) | ||
516 | dapm_set_pga(w, on); /* restore volume from zero */ | ||
517 | |||
518 | continue; | ||
519 | } | ||
520 | |||
521 | /* pre and post event widgets */ | ||
522 | if (w->id == snd_soc_dapm_pre) { | ||
523 | if (!w->event) | ||
524 | continue; | ||
525 | |||
526 | if (event == SND_SOC_DAPM_STREAM_START) { | ||
527 | ret = w->event(w, SND_SOC_DAPM_PRE_PMU); | ||
528 | if (ret < 0) | ||
529 | return ret; | ||
530 | } else if (event == SND_SOC_DAPM_STREAM_STOP) { | ||
531 | ret = w->event(w, SND_SOC_DAPM_PRE_PMD); | ||
532 | if (ret < 0) | ||
533 | return ret; | ||
534 | } | ||
535 | continue; | ||
536 | } | ||
537 | if (w->id == snd_soc_dapm_post) { | ||
538 | if (!w->event) | ||
539 | continue; | ||
540 | |||
541 | if (event == SND_SOC_DAPM_STREAM_START) { | ||
542 | ret = w->event(w, SND_SOC_DAPM_POST_PMU); | ||
543 | if (ret < 0) | ||
544 | return ret; | ||
545 | } else if (event == SND_SOC_DAPM_STREAM_STOP) { | ||
546 | ret = w->event(w, SND_SOC_DAPM_POST_PMD); | ||
547 | if (ret < 0) | ||
548 | return ret; | ||
549 | } | ||
550 | continue; | ||
551 | } | ||
552 | |||
553 | /* all other widgets */ | ||
554 | in = is_connected_input_ep(w); | ||
555 | dapm_clear_walk(w->codec); | ||
556 | out = is_connected_output_ep(w); | ||
557 | dapm_clear_walk(w->codec); | ||
558 | power = (out != 0 && in != 0) ? 1 : 0; | ||
559 | power_change = (w->power == power) ? 0: 1; | ||
560 | w->power = power; | ||
561 | |||
562 | /* call any power change event handlers */ | ||
563 | if (power_change) { | ||
564 | if (w->event) { | ||
565 | dbg("power %s event for %s flags %x\n", | ||
566 | w->power ? "on" : "off", w->name, w->event_flags); | ||
567 | if (power) { | ||
568 | /* power up event */ | ||
569 | if (w->event_flags & SND_SOC_DAPM_PRE_PMU) { | ||
570 | ret = w->event(w, SND_SOC_DAPM_PRE_PMU); | ||
571 | if (ret < 0) | ||
572 | return ret; | ||
573 | } | ||
574 | dapm_update_bits(w); | ||
575 | if (w->event_flags & SND_SOC_DAPM_POST_PMU){ | ||
576 | ret = w->event(w, SND_SOC_DAPM_POST_PMU); | ||
577 | if (ret < 0) | ||
578 | return ret; | ||
579 | } | ||
580 | } else { | ||
581 | /* power down event */ | ||
582 | if (w->event_flags & SND_SOC_DAPM_PRE_PMD) { | ||
583 | ret = w->event(w, SND_SOC_DAPM_PRE_PMD); | ||
584 | if (ret < 0) | ||
585 | return ret; | ||
586 | } | ||
587 | dapm_update_bits(w); | ||
588 | if (w->event_flags & SND_SOC_DAPM_POST_PMD) { | ||
589 | ret = w->event(w, SND_SOC_DAPM_POST_PMD); | ||
590 | if (ret < 0) | ||
591 | return ret; | ||
592 | } | ||
593 | } | ||
594 | } else | ||
595 | /* no event handler */ | ||
596 | dapm_update_bits(w); | ||
597 | } | ||
598 | } | ||
599 | } | ||
600 | |||
601 | return ret; | ||
602 | } | ||
603 | |||
604 | #if DAPM_DEBUG | ||
605 | static void dbg_dump_dapm(struct snd_soc_codec* codec, const char *action) | ||
606 | { | ||
607 | struct snd_soc_dapm_widget *w; | ||
608 | struct snd_soc_dapm_path *p = NULL; | ||
609 | int in, out; | ||
610 | |||
611 | printk("DAPM %s %s\n", codec->name, action); | ||
612 | |||
613 | list_for_each_entry(w, &codec->dapm_widgets, list) { | ||
614 | |||
615 | /* only display widgets that effect routing */ | ||
616 | switch (w->id) { | ||
617 | case snd_soc_dapm_pre: | ||
618 | case snd_soc_dapm_post: | ||
619 | case snd_soc_dapm_vmid: | ||
620 | continue; | ||
621 | case snd_soc_dapm_mux: | ||
622 | case snd_soc_dapm_output: | ||
623 | case snd_soc_dapm_input: | ||
624 | case snd_soc_dapm_switch: | ||
625 | case snd_soc_dapm_hp: | ||
626 | case snd_soc_dapm_mic: | ||
627 | case snd_soc_dapm_spk: | ||
628 | case snd_soc_dapm_line: | ||
629 | case snd_soc_dapm_micbias: | ||
630 | case snd_soc_dapm_dac: | ||
631 | case snd_soc_dapm_adc: | ||
632 | case snd_soc_dapm_pga: | ||
633 | case snd_soc_dapm_mixer: | ||
634 | if (w->name) { | ||
635 | in = is_connected_input_ep(w); | ||
636 | dapm_clear_walk(w->codec); | ||
637 | out = is_connected_output_ep(w); | ||
638 | dapm_clear_walk(w->codec); | ||
639 | printk("%s: %s in %d out %d\n", w->name, | ||
640 | w->power ? "On":"Off",in, out); | ||
641 | |||
642 | list_for_each_entry(p, &w->sources, list_sink) { | ||
643 | if (p->connect) | ||
644 | printk(" in %s %s\n", p->name ? p->name : "static", | ||
645 | p->source->name); | ||
646 | } | ||
647 | list_for_each_entry(p, &w->sinks, list_source) { | ||
648 | if (p->connect) | ||
649 | printk(" out %s %s\n", p->name ? p->name : "static", | ||
650 | p->sink->name); | ||
651 | } | ||
652 | } | ||
653 | break; | ||
654 | } | ||
655 | } | ||
656 | } | ||
657 | #endif | ||
658 | |||
659 | /* test and update the power status of a mux widget */ | ||
660 | static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, | ||
661 | struct snd_kcontrol *kcontrol, int mask, | ||
662 | int val, struct soc_enum* e) | ||
663 | { | ||
664 | struct snd_soc_dapm_path *path; | ||
665 | int found = 0; | ||
666 | |||
667 | if (widget->id != snd_soc_dapm_mux) | ||
668 | return -ENODEV; | ||
669 | |||
670 | if (!snd_soc_test_bits(widget->codec, e->reg, mask, val)) | ||
671 | return 0; | ||
672 | |||
673 | /* find dapm widget path assoc with kcontrol */ | ||
674 | list_for_each_entry(path, &widget->codec->dapm_paths, list) { | ||
675 | if (path->kcontrol != kcontrol) | ||
676 | continue; | ||
677 | |||
678 | if (!path->name || ! e->texts[val]) | ||
679 | continue; | ||
680 | |||
681 | found = 1; | ||
682 | /* we now need to match the string in the enum to the path */ | ||
683 | if (!(strcmp(path->name, e->texts[val]))) | ||
684 | path->connect = 1; /* new connection */ | ||
685 | else | ||
686 | path->connect = 0; /* old connection must be powered down */ | ||
687 | } | ||
688 | |||
689 | if (found) | ||
690 | dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP); | ||
691 | |||
692 | return 0; | ||
693 | } | ||
694 | |||
695 | /* test and update the power status of a mixer widget */ | ||
696 | static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, | ||
697 | struct snd_kcontrol *kcontrol, int reg, | ||
698 | int val_mask, int val, int invert) | ||
699 | { | ||
700 | struct snd_soc_dapm_path *path; | ||
701 | int found = 0; | ||
702 | |||
703 | if (widget->id != snd_soc_dapm_mixer) | ||
704 | return -ENODEV; | ||
705 | |||
706 | if (!snd_soc_test_bits(widget->codec, reg, val_mask, val)) | ||
707 | return 0; | ||
708 | |||
709 | /* find dapm widget path assoc with kcontrol */ | ||
710 | list_for_each_entry(path, &widget->codec->dapm_paths, list) { | ||
711 | if (path->kcontrol != kcontrol) | ||
712 | continue; | ||
713 | |||
714 | /* found, now check type */ | ||
715 | found = 1; | ||
716 | if (val) | ||
717 | /* new connection */ | ||
718 | path->connect = invert ? 0:1; | ||
719 | else | ||
720 | /* old connection must be powered down */ | ||
721 | path->connect = invert ? 1:0; | ||
722 | break; | ||
723 | } | ||
724 | |||
725 | if (found) | ||
726 | dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP); | ||
727 | |||
728 | return 0; | ||
729 | } | ||
730 | |||
731 | /* show dapm widget status in sys fs */ | ||
732 | static ssize_t dapm_widget_show(struct device *dev, | ||
733 | struct device_attribute *attr, char *buf) | ||
734 | { | ||
735 | struct snd_soc_device *devdata = dev_get_drvdata(dev); | ||
736 | struct snd_soc_codec *codec = devdata->codec; | ||
737 | struct snd_soc_dapm_widget *w; | ||
738 | int count = 0; | ||
739 | char *state = "not set"; | ||
740 | |||
741 | list_for_each_entry(w, &codec->dapm_widgets, list) { | ||
742 | |||
743 | /* only display widgets that burnm power */ | ||
744 | switch (w->id) { | ||
745 | case snd_soc_dapm_hp: | ||
746 | case snd_soc_dapm_mic: | ||
747 | case snd_soc_dapm_spk: | ||
748 | case snd_soc_dapm_line: | ||
749 | case snd_soc_dapm_micbias: | ||
750 | case snd_soc_dapm_dac: | ||
751 | case snd_soc_dapm_adc: | ||
752 | case snd_soc_dapm_pga: | ||
753 | case snd_soc_dapm_mixer: | ||
754 | if (w->name) | ||
755 | count += sprintf(buf + count, "%s: %s\n", | ||
756 | w->name, w->power ? "On":"Off"); | ||
757 | break; | ||
758 | default: | ||
759 | break; | ||
760 | } | ||
761 | } | ||
762 | |||
763 | switch(codec->dapm_state){ | ||
764 | case SNDRV_CTL_POWER_D0: | ||
765 | state = "D0"; | ||
766 | break; | ||
767 | case SNDRV_CTL_POWER_D1: | ||
768 | state = "D1"; | ||
769 | break; | ||
770 | case SNDRV_CTL_POWER_D2: | ||
771 | state = "D2"; | ||
772 | break; | ||
773 | case SNDRV_CTL_POWER_D3hot: | ||
774 | state = "D3hot"; | ||
775 | break; | ||
776 | case SNDRV_CTL_POWER_D3cold: | ||
777 | state = "D3cold"; | ||
778 | break; | ||
779 | } | ||
780 | count += sprintf(buf + count, "PM State: %s\n", state); | ||
781 | |||
782 | return count; | ||
783 | } | ||
784 | |||
785 | static DEVICE_ATTR(dapm_widget, 0444, dapm_widget_show, NULL); | ||
786 | |||
787 | int snd_soc_dapm_sys_add(struct device *dev) | ||
788 | { | ||
789 | int ret = 0; | ||
790 | |||
791 | if (dapm_status) | ||
792 | ret = device_create_file(dev, &dev_attr_dapm_widget); | ||
793 | |||
794 | return ret; | ||
795 | } | ||
796 | |||
797 | static void snd_soc_dapm_sys_remove(struct device *dev) | ||
798 | { | ||
799 | if (dapm_status) | ||
800 | device_remove_file(dev, &dev_attr_dapm_widget); | ||
801 | } | ||
802 | |||
803 | /* free all dapm widgets and resources */ | ||
804 | static void dapm_free_widgets(struct snd_soc_codec *codec) | ||
805 | { | ||
806 | struct snd_soc_dapm_widget *w, *next_w; | ||
807 | struct snd_soc_dapm_path *p, *next_p; | ||
808 | |||
809 | list_for_each_entry_safe(w, next_w, &codec->dapm_widgets, list) { | ||
810 | list_del(&w->list); | ||
811 | kfree(w); | ||
812 | } | ||
813 | |||
814 | list_for_each_entry_safe(p, next_p, &codec->dapm_paths, list) { | ||
815 | list_del(&p->list); | ||
816 | kfree(p->long_name); | ||
817 | kfree(p); | ||
818 | } | ||
819 | } | ||
820 | |||
821 | /** | ||
822 | * snd_soc_dapm_sync_endpoints - scan and power dapm paths | ||
823 | * @codec: audio codec | ||
824 | * | ||
825 | * Walks all dapm audio paths and powers widgets according to their | ||
826 | * stream or path usage. | ||
827 | * | ||
828 | * Returns 0 for success. | ||
829 | */ | ||
830 | int snd_soc_dapm_sync_endpoints(struct snd_soc_codec *codec) | ||
831 | { | ||
832 | return dapm_power_widgets(codec, SND_SOC_DAPM_STREAM_NOP); | ||
833 | } | ||
834 | EXPORT_SYMBOL_GPL(snd_soc_dapm_sync_endpoints); | ||
835 | |||
836 | /** | ||
837 | * snd_soc_dapm_connect_input - connect dapm widgets | ||
838 | * @codec: audio codec | ||
839 | * @sink: name of target widget | ||
840 | * @control: mixer control name | ||
841 | * @source: name of source name | ||
842 | * | ||
843 | * Connects 2 dapm widgets together via a named audio path. The sink is | ||
844 | * the widget receiving the audio signal, whilst the source is the sender | ||
845 | * of the audio signal. | ||
846 | * | ||
847 | * Returns 0 for success else error. | ||
848 | */ | ||
849 | int snd_soc_dapm_connect_input(struct snd_soc_codec *codec, const char *sink, | ||
850 | const char * control, const char *source) | ||
851 | { | ||
852 | struct snd_soc_dapm_path *path; | ||
853 | struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w; | ||
854 | int ret = 0; | ||
855 | |||
856 | /* find src and dest widgets */ | ||
857 | list_for_each_entry(w, &codec->dapm_widgets, list) { | ||
858 | |||
859 | if (!wsink && !(strcmp(w->name, sink))) { | ||
860 | wsink = w; | ||
861 | continue; | ||
862 | } | ||
863 | if (!wsource && !(strcmp(w->name, source))) { | ||
864 | wsource = w; | ||
865 | } | ||
866 | } | ||
867 | |||
868 | if (wsource == NULL || wsink == NULL) | ||
869 | return -ENODEV; | ||
870 | |||
871 | path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL); | ||
872 | if (!path) | ||
873 | return -ENOMEM; | ||
874 | |||
875 | path->source = wsource; | ||
876 | path->sink = wsink; | ||
877 | INIT_LIST_HEAD(&path->list); | ||
878 | INIT_LIST_HEAD(&path->list_source); | ||
879 | INIT_LIST_HEAD(&path->list_sink); | ||
880 | |||
881 | /* check for external widgets */ | ||
882 | if (wsink->id == snd_soc_dapm_input) { | ||
883 | if (wsource->id == snd_soc_dapm_micbias || | ||
884 | wsource->id == snd_soc_dapm_mic || | ||
885 | wsink->id == snd_soc_dapm_line) | ||
886 | wsink->ext = 1; | ||
887 | } | ||
888 | if (wsource->id == snd_soc_dapm_output) { | ||
889 | if (wsink->id == snd_soc_dapm_spk || | ||
890 | wsink->id == snd_soc_dapm_hp || | ||
891 | wsink->id == snd_soc_dapm_line) | ||
892 | wsource->ext = 1; | ||
893 | } | ||
894 | |||
895 | /* connect static paths */ | ||
896 | if (control == NULL) { | ||
897 | list_add(&path->list, &codec->dapm_paths); | ||
898 | list_add(&path->list_sink, &wsink->sources); | ||
899 | list_add(&path->list_source, &wsource->sinks); | ||
900 | path->connect = 1; | ||
901 | return 0; | ||
902 | } | ||
903 | |||
904 | /* connect dynamic paths */ | ||
905 | switch(wsink->id) { | ||
906 | case snd_soc_dapm_adc: | ||
907 | case snd_soc_dapm_dac: | ||
908 | case snd_soc_dapm_pga: | ||
909 | case snd_soc_dapm_input: | ||
910 | case snd_soc_dapm_output: | ||
911 | case snd_soc_dapm_micbias: | ||
912 | case snd_soc_dapm_vmid: | ||
913 | case snd_soc_dapm_pre: | ||
914 | case snd_soc_dapm_post: | ||
915 | list_add(&path->list, &codec->dapm_paths); | ||
916 | list_add(&path->list_sink, &wsink->sources); | ||
917 | list_add(&path->list_source, &wsource->sinks); | ||
918 | path->connect = 1; | ||
919 | return 0; | ||
920 | case snd_soc_dapm_mux: | ||
921 | ret = dapm_connect_mux(codec, wsource, wsink, path, control, | ||
922 | &wsink->kcontrols[0]); | ||
923 | if (ret != 0) | ||
924 | goto err; | ||
925 | break; | ||
926 | case snd_soc_dapm_switch: | ||
927 | case snd_soc_dapm_mixer: | ||
928 | ret = dapm_connect_mixer(codec, wsource, wsink, path, control); | ||
929 | if (ret != 0) | ||
930 | goto err; | ||
931 | break; | ||
932 | case snd_soc_dapm_hp: | ||
933 | case snd_soc_dapm_mic: | ||
934 | case snd_soc_dapm_line: | ||
935 | case snd_soc_dapm_spk: | ||
936 | list_add(&path->list, &codec->dapm_paths); | ||
937 | list_add(&path->list_sink, &wsink->sources); | ||
938 | list_add(&path->list_source, &wsource->sinks); | ||
939 | path->connect = 0; | ||
940 | return 0; | ||
941 | } | ||
942 | return 0; | ||
943 | |||
944 | err: | ||
945 | printk(KERN_WARNING "asoc: no dapm match for %s --> %s --> %s\n", source, | ||
946 | control, sink); | ||
947 | kfree(path); | ||
948 | return ret; | ||
949 | } | ||
950 | EXPORT_SYMBOL_GPL(snd_soc_dapm_connect_input); | ||
951 | |||
952 | /** | ||
953 | * snd_soc_dapm_new_widgets - add new dapm widgets | ||
954 | * @codec: audio codec | ||
955 | * | ||
956 | * Checks the codec for any new dapm widgets and creates them if found. | ||
957 | * | ||
958 | * Returns 0 for success. | ||
959 | */ | ||
960 | int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec) | ||
961 | { | ||
962 | struct snd_soc_dapm_widget *w; | ||
963 | |||
964 | mutex_lock(&codec->mutex); | ||
965 | list_for_each_entry(w, &codec->dapm_widgets, list) | ||
966 | { | ||
967 | if (w->new) | ||
968 | continue; | ||
969 | |||
970 | switch(w->id) { | ||
971 | case snd_soc_dapm_switch: | ||
972 | case snd_soc_dapm_mixer: | ||
973 | dapm_new_mixer(codec, w); | ||
974 | break; | ||
975 | case snd_soc_dapm_mux: | ||
976 | dapm_new_mux(codec, w); | ||
977 | break; | ||
978 | case snd_soc_dapm_adc: | ||
979 | case snd_soc_dapm_dac: | ||
980 | case snd_soc_dapm_pga: | ||
981 | dapm_new_pga(codec, w); | ||
982 | break; | ||
983 | case snd_soc_dapm_input: | ||
984 | case snd_soc_dapm_output: | ||
985 | case snd_soc_dapm_micbias: | ||
986 | case snd_soc_dapm_spk: | ||
987 | case snd_soc_dapm_hp: | ||
988 | case snd_soc_dapm_mic: | ||
989 | case snd_soc_dapm_line: | ||
990 | case snd_soc_dapm_vmid: | ||
991 | case snd_soc_dapm_pre: | ||
992 | case snd_soc_dapm_post: | ||
993 | break; | ||
994 | } | ||
995 | w->new = 1; | ||
996 | } | ||
997 | |||
998 | dapm_power_widgets(codec, SND_SOC_DAPM_STREAM_NOP); | ||
999 | mutex_unlock(&codec->mutex); | ||
1000 | return 0; | ||
1001 | } | ||
1002 | EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets); | ||
1003 | |||
1004 | /** | ||
1005 | * snd_soc_dapm_get_volsw - dapm mixer get callback | ||
1006 | * @kcontrol: mixer control | ||
1007 | * @uinfo: control element information | ||
1008 | * | ||
1009 | * Callback to get the value of a dapm mixer control. | ||
1010 | * | ||
1011 | * Returns 0 for success. | ||
1012 | */ | ||
1013 | int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, | ||
1014 | struct snd_ctl_elem_value *ucontrol) | ||
1015 | { | ||
1016 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); | ||
1017 | int reg = kcontrol->private_value & 0xff; | ||
1018 | int shift = (kcontrol->private_value >> 8) & 0x0f; | ||
1019 | int rshift = (kcontrol->private_value >> 12) & 0x0f; | ||
1020 | int mask = (kcontrol->private_value >> 16) & 0xff; | ||
1021 | int invert = (kcontrol->private_value >> 24) & 0x01; | ||
1022 | |||
1023 | /* return the saved value if we are powered down */ | ||
1024 | if (widget->id == snd_soc_dapm_pga && !widget->power) { | ||
1025 | ucontrol->value.integer.value[0] = widget->saved_value; | ||
1026 | return 0; | ||
1027 | } | ||
1028 | |||
1029 | ucontrol->value.integer.value[0] = | ||
1030 | (snd_soc_read(widget->codec, reg) >> shift) & mask; | ||
1031 | if (shift != rshift) | ||
1032 | ucontrol->value.integer.value[1] = | ||
1033 | (snd_soc_read(widget->codec, reg) >> rshift) & mask; | ||
1034 | if (invert) { | ||
1035 | ucontrol->value.integer.value[0] = | ||
1036 | mask - ucontrol->value.integer.value[0]; | ||
1037 | if (shift != rshift) | ||
1038 | ucontrol->value.integer.value[1] = | ||
1039 | mask - ucontrol->value.integer.value[1]; | ||
1040 | } | ||
1041 | |||
1042 | return 0; | ||
1043 | } | ||
1044 | EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw); | ||
1045 | |||
1046 | /** | ||
1047 | * snd_soc_dapm_put_volsw - dapm mixer set callback | ||
1048 | * @kcontrol: mixer control | ||
1049 | * @uinfo: control element information | ||
1050 | * | ||
1051 | * Callback to set the value of a dapm mixer control. | ||
1052 | * | ||
1053 | * Returns 0 for success. | ||
1054 | */ | ||
1055 | int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, | ||
1056 | struct snd_ctl_elem_value *ucontrol) | ||
1057 | { | ||
1058 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); | ||
1059 | int reg = kcontrol->private_value & 0xff; | ||
1060 | int shift = (kcontrol->private_value >> 8) & 0x0f; | ||
1061 | int rshift = (kcontrol->private_value >> 12) & 0x0f; | ||
1062 | int mask = (kcontrol->private_value >> 16) & 0xff; | ||
1063 | int invert = (kcontrol->private_value >> 24) & 0x01; | ||
1064 | unsigned short val, val2, val_mask; | ||
1065 | int ret; | ||
1066 | |||
1067 | val = (ucontrol->value.integer.value[0] & mask); | ||
1068 | |||
1069 | if (invert) | ||
1070 | val = mask - val; | ||
1071 | val_mask = mask << shift; | ||
1072 | val = val << shift; | ||
1073 | if (shift != rshift) { | ||
1074 | val2 = (ucontrol->value.integer.value[1] & mask); | ||
1075 | if (invert) | ||
1076 | val2 = mask - val2; | ||
1077 | val_mask |= mask << rshift; | ||
1078 | val |= val2 << rshift; | ||
1079 | } | ||
1080 | |||
1081 | mutex_lock(&widget->codec->mutex); | ||
1082 | widget->value = val; | ||
1083 | |||
1084 | /* save volume value if the widget is powered down */ | ||
1085 | if (widget->id == snd_soc_dapm_pga && !widget->power) { | ||
1086 | widget->saved_value = val; | ||
1087 | mutex_unlock(&widget->codec->mutex); | ||
1088 | return 1; | ||
1089 | } | ||
1090 | |||
1091 | dapm_mixer_update_power(widget, kcontrol, reg, val_mask, val, invert); | ||
1092 | if (widget->event) { | ||
1093 | if (widget->event_flags & SND_SOC_DAPM_PRE_REG) { | ||
1094 | ret = widget->event(widget, SND_SOC_DAPM_PRE_REG); | ||
1095 | if (ret < 0) | ||
1096 | goto out; | ||
1097 | } | ||
1098 | ret = snd_soc_update_bits(widget->codec, reg, val_mask, val); | ||
1099 | if (widget->event_flags & SND_SOC_DAPM_POST_REG) | ||
1100 | ret = widget->event(widget, SND_SOC_DAPM_POST_REG); | ||
1101 | } else | ||
1102 | ret = snd_soc_update_bits(widget->codec, reg, val_mask, val); | ||
1103 | |||
1104 | out: | ||
1105 | mutex_unlock(&widget->codec->mutex); | ||
1106 | return ret; | ||
1107 | } | ||
1108 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw); | ||
1109 | |||
1110 | /** | ||
1111 | * snd_soc_dapm_get_enum_double - dapm enumerated double mixer get callback | ||
1112 | * @kcontrol: mixer control | ||
1113 | * @uinfo: control element information | ||
1114 | * | ||
1115 | * Callback to get the value of a dapm enumerated double mixer control. | ||
1116 | * | ||
1117 | * Returns 0 for success. | ||
1118 | */ | ||
1119 | int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol, | ||
1120 | struct snd_ctl_elem_value *ucontrol) | ||
1121 | { | ||
1122 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); | ||
1123 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | ||
1124 | unsigned short val, bitmask; | ||
1125 | |||
1126 | for (bitmask = 1; bitmask < e->mask; bitmask <<= 1) | ||
1127 | ; | ||
1128 | val = snd_soc_read(widget->codec, e->reg); | ||
1129 | ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & (bitmask - 1); | ||
1130 | if (e->shift_l != e->shift_r) | ||
1131 | ucontrol->value.enumerated.item[1] = | ||
1132 | (val >> e->shift_r) & (bitmask - 1); | ||
1133 | |||
1134 | return 0; | ||
1135 | } | ||
1136 | EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double); | ||
1137 | |||
1138 | /** | ||
1139 | * snd_soc_dapm_put_enum_double - dapm enumerated double mixer set callback | ||
1140 | * @kcontrol: mixer control | ||
1141 | * @uinfo: control element information | ||
1142 | * | ||
1143 | * Callback to set the value of a dapm enumerated double mixer control. | ||
1144 | * | ||
1145 | * Returns 0 for success. | ||
1146 | */ | ||
1147 | int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, | ||
1148 | struct snd_ctl_elem_value *ucontrol) | ||
1149 | { | ||
1150 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); | ||
1151 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | ||
1152 | unsigned short val, mux; | ||
1153 | unsigned short mask, bitmask; | ||
1154 | int ret = 0; | ||
1155 | |||
1156 | for (bitmask = 1; bitmask < e->mask; bitmask <<= 1) | ||
1157 | ; | ||
1158 | if (ucontrol->value.enumerated.item[0] > e->mask - 1) | ||
1159 | return -EINVAL; | ||
1160 | mux = ucontrol->value.enumerated.item[0]; | ||
1161 | val = mux << e->shift_l; | ||
1162 | mask = (bitmask - 1) << e->shift_l; | ||
1163 | if (e->shift_l != e->shift_r) { | ||
1164 | if (ucontrol->value.enumerated.item[1] > e->mask - 1) | ||
1165 | return -EINVAL; | ||
1166 | val |= ucontrol->value.enumerated.item[1] << e->shift_r; | ||
1167 | mask |= (bitmask - 1) << e->shift_r; | ||
1168 | } | ||
1169 | |||
1170 | mutex_lock(&widget->codec->mutex); | ||
1171 | widget->value = val; | ||
1172 | dapm_mux_update_power(widget, kcontrol, mask, mux, e); | ||
1173 | if (widget->event) { | ||
1174 | if (widget->event_flags & SND_SOC_DAPM_PRE_REG) { | ||
1175 | ret = widget->event(widget, SND_SOC_DAPM_PRE_REG); | ||
1176 | if (ret < 0) | ||
1177 | goto out; | ||
1178 | } | ||
1179 | ret = snd_soc_update_bits(widget->codec, e->reg, mask, val); | ||
1180 | if (widget->event_flags & SND_SOC_DAPM_POST_REG) | ||
1181 | ret = widget->event(widget, SND_SOC_DAPM_POST_REG); | ||
1182 | } else | ||
1183 | ret = snd_soc_update_bits(widget->codec, e->reg, mask, val); | ||
1184 | |||
1185 | out: | ||
1186 | mutex_unlock(&widget->codec->mutex); | ||
1187 | return ret; | ||
1188 | } | ||
1189 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double); | ||
1190 | |||
1191 | /** | ||
1192 | * snd_soc_dapm_new_control - create new dapm control | ||
1193 | * @codec: audio codec | ||
1194 | * @widget: widget template | ||
1195 | * | ||
1196 | * Creates a new dapm control based upon the template. | ||
1197 | * | ||
1198 | * Returns 0 for success else error. | ||
1199 | */ | ||
1200 | int snd_soc_dapm_new_control(struct snd_soc_codec *codec, | ||
1201 | const struct snd_soc_dapm_widget *widget) | ||
1202 | { | ||
1203 | struct snd_soc_dapm_widget *w; | ||
1204 | |||
1205 | if ((w = dapm_cnew_widget(widget)) == NULL) | ||
1206 | return -ENOMEM; | ||
1207 | |||
1208 | w->codec = codec; | ||
1209 | INIT_LIST_HEAD(&w->sources); | ||
1210 | INIT_LIST_HEAD(&w->sinks); | ||
1211 | INIT_LIST_HEAD(&w->list); | ||
1212 | list_add(&w->list, &codec->dapm_widgets); | ||
1213 | |||
1214 | /* machine layer set ups unconnected pins and insertions */ | ||
1215 | w->connected = 1; | ||
1216 | return 0; | ||
1217 | } | ||
1218 | EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control); | ||
1219 | |||
1220 | /** | ||
1221 | * snd_soc_dapm_stream_event - send a stream event to the dapm core | ||
1222 | * @codec: audio codec | ||
1223 | * @stream: stream name | ||
1224 | * @event: stream event | ||
1225 | * | ||
1226 | * Sends a stream event to the dapm core. The core then makes any | ||
1227 | * necessary widget power changes. | ||
1228 | * | ||
1229 | * Returns 0 for success else error. | ||
1230 | */ | ||
1231 | int snd_soc_dapm_stream_event(struct snd_soc_codec *codec, | ||
1232 | char *stream, int event) | ||
1233 | { | ||
1234 | struct snd_soc_dapm_widget *w; | ||
1235 | |||
1236 | if (stream == NULL) | ||
1237 | return 0; | ||
1238 | |||
1239 | mutex_lock(&codec->mutex); | ||
1240 | list_for_each_entry(w, &codec->dapm_widgets, list) | ||
1241 | { | ||
1242 | if (!w->sname) | ||
1243 | continue; | ||
1244 | dbg("widget %s\n %s stream %s event %d\n", w->name, w->sname, | ||
1245 | stream, event); | ||
1246 | if (strstr(w->sname, stream)) { | ||
1247 | switch(event) { | ||
1248 | case SND_SOC_DAPM_STREAM_START: | ||
1249 | w->active = 1; | ||
1250 | break; | ||
1251 | case SND_SOC_DAPM_STREAM_STOP: | ||
1252 | w->active = 0; | ||
1253 | break; | ||
1254 | case SND_SOC_DAPM_STREAM_SUSPEND: | ||
1255 | if (w->active) | ||
1256 | w->suspend = 1; | ||
1257 | w->active = 0; | ||
1258 | break; | ||
1259 | case SND_SOC_DAPM_STREAM_RESUME: | ||
1260 | if (w->suspend) { | ||
1261 | w->active = 1; | ||
1262 | w->suspend = 0; | ||
1263 | } | ||
1264 | break; | ||
1265 | case SND_SOC_DAPM_STREAM_PAUSE_PUSH: | ||
1266 | break; | ||
1267 | case SND_SOC_DAPM_STREAM_PAUSE_RELEASE: | ||
1268 | break; | ||
1269 | } | ||
1270 | } | ||
1271 | } | ||
1272 | mutex_unlock(&codec->mutex); | ||
1273 | |||
1274 | dapm_power_widgets(codec, event); | ||
1275 | dump_dapm(codec, __FUNCTION__); | ||
1276 | return 0; | ||
1277 | } | ||
1278 | EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_event); | ||
1279 | |||
1280 | /** | ||
1281 | * snd_soc_dapm_set_endpoint - set audio endpoint status | ||
1282 | * @codec: audio codec | ||
1283 | * @endpoint: audio signal endpoint (or start point) | ||
1284 | * @status: point status | ||
1285 | * | ||
1286 | * Set audio endpoint status - connected or disconnected. | ||
1287 | * | ||
1288 | * Returns 0 for success else error. | ||
1289 | */ | ||
1290 | int snd_soc_dapm_set_endpoint(struct snd_soc_codec *codec, | ||
1291 | char *endpoint, int status) | ||
1292 | { | ||
1293 | struct snd_soc_dapm_widget *w; | ||
1294 | |||
1295 | list_for_each_entry(w, &codec->dapm_widgets, list) { | ||
1296 | if (!strcmp(w->name, endpoint)) { | ||
1297 | w->connected = status; | ||
1298 | } | ||
1299 | } | ||
1300 | |||
1301 | return 0; | ||
1302 | } | ||
1303 | EXPORT_SYMBOL_GPL(snd_soc_dapm_set_endpoint); | ||
1304 | |||
1305 | /** | ||
1306 | * snd_soc_dapm_free - free dapm resources | ||
1307 | * @socdev: SoC device | ||
1308 | * | ||
1309 | * Free all dapm widgets and resources. | ||
1310 | */ | ||
1311 | void snd_soc_dapm_free(struct snd_soc_device *socdev) | ||
1312 | { | ||
1313 | struct snd_soc_codec *codec = socdev->codec; | ||
1314 | |||
1315 | snd_soc_dapm_sys_remove(socdev->dev); | ||
1316 | dapm_free_widgets(codec); | ||
1317 | } | ||
1318 | EXPORT_SYMBOL_GPL(snd_soc_dapm_free); | ||
1319 | |||
1320 | /* Module information */ | ||
1321 | MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com"); | ||
1322 | MODULE_DESCRIPTION("Dynamic Audio Power Management core for ALSA SoC"); | ||
1323 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c index 4ceb09d215d8..25a2a7333006 100644 --- a/sound/sparc/dbri.c +++ b/sound/sparc/dbri.c | |||
@@ -678,7 +678,7 @@ static s32 *dbri_cmdlock(struct snd_dbri * dbri, int len) | |||
678 | * The JUMP cmd points to the new cmd string. | 678 | * The JUMP cmd points to the new cmd string. |
679 | * It also releases the cmdlock spinlock. | 679 | * It also releases the cmdlock spinlock. |
680 | * | 680 | * |
681 | * Lock must not be held before calling this. | 681 | * Lock must be held before calling this. |
682 | */ | 682 | */ |
683 | static void dbri_cmdsend(struct snd_dbri * dbri, s32 * cmd,int len) | 683 | static void dbri_cmdsend(struct snd_dbri * dbri, s32 * cmd,int len) |
684 | { | 684 | { |
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 19bdcc74c96c..4dfb91d4398a 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c | |||
@@ -186,6 +186,7 @@ struct snd_usb_substream { | |||
186 | u64 formats; /* format bitmasks (all or'ed) */ | 186 | u64 formats; /* format bitmasks (all or'ed) */ |
187 | unsigned int num_formats; /* number of supported audio formats (list) */ | 187 | unsigned int num_formats; /* number of supported audio formats (list) */ |
188 | struct list_head fmt_list; /* format list */ | 188 | struct list_head fmt_list; /* format list */ |
189 | struct snd_pcm_hw_constraint_list rate_list; /* limited rates */ | ||
189 | spinlock_t lock; | 190 | spinlock_t lock; |
190 | 191 | ||
191 | struct snd_urb_ops ops; /* callbacks (must be filled at init) */ | 192 | struct snd_urb_ops ops; /* callbacks (must be filled at init) */ |
@@ -253,7 +254,7 @@ static int prepare_capture_sync_urb(struct snd_usb_substream *subs, | |||
253 | struct urb *urb) | 254 | struct urb *urb) |
254 | { | 255 | { |
255 | unsigned char *cp = urb->transfer_buffer; | 256 | unsigned char *cp = urb->transfer_buffer; |
256 | struct snd_urb_ctx *ctx = (struct snd_urb_ctx *)urb->context; | 257 | struct snd_urb_ctx *ctx = urb->context; |
257 | 258 | ||
258 | urb->dev = ctx->subs->dev; /* we need to set this at each time */ | 259 | urb->dev = ctx->subs->dev; /* we need to set this at each time */ |
259 | urb->iso_frame_desc[0].length = 3; | 260 | urb->iso_frame_desc[0].length = 3; |
@@ -275,7 +276,7 @@ static int prepare_capture_sync_urb_hs(struct snd_usb_substream *subs, | |||
275 | struct urb *urb) | 276 | struct urb *urb) |
276 | { | 277 | { |
277 | unsigned char *cp = urb->transfer_buffer; | 278 | unsigned char *cp = urb->transfer_buffer; |
278 | struct snd_urb_ctx *ctx = (struct snd_urb_ctx *)urb->context; | 279 | struct snd_urb_ctx *ctx = urb->context; |
279 | 280 | ||
280 | urb->dev = ctx->subs->dev; /* we need to set this at each time */ | 281 | urb->dev = ctx->subs->dev; /* we need to set this at each time */ |
281 | urb->iso_frame_desc[0].length = 4; | 282 | urb->iso_frame_desc[0].length = 4; |
@@ -313,7 +314,7 @@ static int prepare_capture_urb(struct snd_usb_substream *subs, | |||
313 | struct urb *urb) | 314 | struct urb *urb) |
314 | { | 315 | { |
315 | int i, offs; | 316 | int i, offs; |
316 | struct snd_urb_ctx *ctx = (struct snd_urb_ctx *)urb->context; | 317 | struct snd_urb_ctx *ctx = urb->context; |
317 | 318 | ||
318 | offs = 0; | 319 | offs = 0; |
319 | urb->dev = ctx->subs->dev; /* we need to set this at each time */ | 320 | urb->dev = ctx->subs->dev; /* we need to set this at each time */ |
@@ -391,6 +392,16 @@ static int retire_capture_urb(struct snd_usb_substream *subs, | |||
391 | return 0; | 392 | return 0; |
392 | } | 393 | } |
393 | 394 | ||
395 | /* | ||
396 | * Process after capture complete when paused. Nothing to do. | ||
397 | */ | ||
398 | static int retire_paused_capture_urb(struct snd_usb_substream *subs, | ||
399 | struct snd_pcm_runtime *runtime, | ||
400 | struct urb *urb) | ||
401 | { | ||
402 | return 0; | ||
403 | } | ||
404 | |||
394 | 405 | ||
395 | /* | 406 | /* |
396 | * prepare urb for full speed playback sync pipe | 407 | * prepare urb for full speed playback sync pipe |
@@ -402,7 +413,7 @@ static int prepare_playback_sync_urb(struct snd_usb_substream *subs, | |||
402 | struct snd_pcm_runtime *runtime, | 413 | struct snd_pcm_runtime *runtime, |
403 | struct urb *urb) | 414 | struct urb *urb) |
404 | { | 415 | { |
405 | struct snd_urb_ctx *ctx = (struct snd_urb_ctx *)urb->context; | 416 | struct snd_urb_ctx *ctx = urb->context; |
406 | 417 | ||
407 | urb->dev = ctx->subs->dev; /* we need to set this at each time */ | 418 | urb->dev = ctx->subs->dev; /* we need to set this at each time */ |
408 | urb->iso_frame_desc[0].length = 3; | 419 | urb->iso_frame_desc[0].length = 3; |
@@ -420,7 +431,7 @@ static int prepare_playback_sync_urb_hs(struct snd_usb_substream *subs, | |||
420 | struct snd_pcm_runtime *runtime, | 431 | struct snd_pcm_runtime *runtime, |
421 | struct urb *urb) | 432 | struct urb *urb) |
422 | { | 433 | { |
423 | struct snd_urb_ctx *ctx = (struct snd_urb_ctx *)urb->context; | 434 | struct snd_urb_ctx *ctx = urb->context; |
424 | 435 | ||
425 | urb->dev = ctx->subs->dev; /* we need to set this at each time */ | 436 | urb->dev = ctx->subs->dev; /* we need to set this at each time */ |
426 | urb->iso_frame_desc[0].length = 4; | 437 | urb->iso_frame_desc[0].length = 4; |
@@ -493,13 +504,13 @@ static int snd_usb_audio_next_packet_size(struct snd_usb_substream *subs) | |||
493 | } | 504 | } |
494 | 505 | ||
495 | /* | 506 | /* |
496 | * Prepare urb for streaming before playback starts. | 507 | * Prepare urb for streaming before playback starts or when paused. |
497 | * | 508 | * |
498 | * We don't yet have data, so we send a frame of silence. | 509 | * We don't have any data, so we send a frame of silence. |
499 | */ | 510 | */ |
500 | static int prepare_startup_playback_urb(struct snd_usb_substream *subs, | 511 | static int prepare_nodata_playback_urb(struct snd_usb_substream *subs, |
501 | struct snd_pcm_runtime *runtime, | 512 | struct snd_pcm_runtime *runtime, |
502 | struct urb *urb) | 513 | struct urb *urb) |
503 | { | 514 | { |
504 | unsigned int i, offs, counts; | 515 | unsigned int i, offs, counts; |
505 | struct snd_urb_ctx *ctx = urb->context; | 516 | struct snd_urb_ctx *ctx = urb->context; |
@@ -537,7 +548,7 @@ static int prepare_playback_urb(struct snd_usb_substream *subs, | |||
537 | unsigned int counts; | 548 | unsigned int counts; |
538 | unsigned long flags; | 549 | unsigned long flags; |
539 | int period_elapsed = 0; | 550 | int period_elapsed = 0; |
540 | struct snd_urb_ctx *ctx = (struct snd_urb_ctx *)urb->context; | 551 | struct snd_urb_ctx *ctx = urb->context; |
541 | 552 | ||
542 | stride = runtime->frame_bits >> 3; | 553 | stride = runtime->frame_bits >> 3; |
543 | 554 | ||
@@ -622,7 +633,7 @@ static int retire_playback_urb(struct snd_usb_substream *subs, | |||
622 | */ | 633 | */ |
623 | static struct snd_urb_ops audio_urb_ops[2] = { | 634 | static struct snd_urb_ops audio_urb_ops[2] = { |
624 | { | 635 | { |
625 | .prepare = prepare_startup_playback_urb, | 636 | .prepare = prepare_nodata_playback_urb, |
626 | .retire = retire_playback_urb, | 637 | .retire = retire_playback_urb, |
627 | .prepare_sync = prepare_playback_sync_urb, | 638 | .prepare_sync = prepare_playback_sync_urb, |
628 | .retire_sync = retire_playback_sync_urb, | 639 | .retire_sync = retire_playback_sync_urb, |
@@ -637,7 +648,7 @@ static struct snd_urb_ops audio_urb_ops[2] = { | |||
637 | 648 | ||
638 | static struct snd_urb_ops audio_urb_ops_high_speed[2] = { | 649 | static struct snd_urb_ops audio_urb_ops_high_speed[2] = { |
639 | { | 650 | { |
640 | .prepare = prepare_startup_playback_urb, | 651 | .prepare = prepare_nodata_playback_urb, |
641 | .retire = retire_playback_urb, | 652 | .retire = retire_playback_urb, |
642 | .prepare_sync = prepare_playback_sync_urb_hs, | 653 | .prepare_sync = prepare_playback_sync_urb_hs, |
643 | .retire_sync = retire_playback_sync_urb_hs, | 654 | .retire_sync = retire_playback_sync_urb_hs, |
@@ -655,7 +666,7 @@ static struct snd_urb_ops audio_urb_ops_high_speed[2] = { | |||
655 | */ | 666 | */ |
656 | static void snd_complete_urb(struct urb *urb) | 667 | static void snd_complete_urb(struct urb *urb) |
657 | { | 668 | { |
658 | struct snd_urb_ctx *ctx = (struct snd_urb_ctx *)urb->context; | 669 | struct snd_urb_ctx *ctx = urb->context; |
659 | struct snd_usb_substream *subs = ctx->subs; | 670 | struct snd_usb_substream *subs = ctx->subs; |
660 | struct snd_pcm_substream *substream = ctx->subs->pcm_substream; | 671 | struct snd_pcm_substream *substream = ctx->subs->pcm_substream; |
661 | int err = 0; | 672 | int err = 0; |
@@ -678,7 +689,7 @@ static void snd_complete_urb(struct urb *urb) | |||
678 | */ | 689 | */ |
679 | static void snd_complete_sync_urb(struct urb *urb) | 690 | static void snd_complete_sync_urb(struct urb *urb) |
680 | { | 691 | { |
681 | struct snd_urb_ctx *ctx = (struct snd_urb_ctx *)urb->context; | 692 | struct snd_urb_ctx *ctx = urb->context; |
682 | struct snd_usb_substream *subs = ctx->subs; | 693 | struct snd_usb_substream *subs = ctx->subs; |
683 | struct snd_pcm_substream *substream = ctx->subs->pcm_substream; | 694 | struct snd_pcm_substream *substream = ctx->subs->pcm_substream; |
684 | int err = 0; | 695 | int err = 0; |
@@ -925,10 +936,14 @@ static int snd_usb_pcm_playback_trigger(struct snd_pcm_substream *substream, | |||
925 | 936 | ||
926 | switch (cmd) { | 937 | switch (cmd) { |
927 | case SNDRV_PCM_TRIGGER_START: | 938 | case SNDRV_PCM_TRIGGER_START: |
939 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
928 | subs->ops.prepare = prepare_playback_urb; | 940 | subs->ops.prepare = prepare_playback_urb; |
929 | return 0; | 941 | return 0; |
930 | case SNDRV_PCM_TRIGGER_STOP: | 942 | case SNDRV_PCM_TRIGGER_STOP: |
931 | return deactivate_urbs(subs, 0, 0); | 943 | return deactivate_urbs(subs, 0, 0); |
944 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
945 | subs->ops.prepare = prepare_nodata_playback_urb; | ||
946 | return 0; | ||
932 | default: | 947 | default: |
933 | return -EINVAL; | 948 | return -EINVAL; |
934 | } | 949 | } |
@@ -944,9 +959,16 @@ static int snd_usb_pcm_capture_trigger(struct snd_pcm_substream *substream, | |||
944 | 959 | ||
945 | switch (cmd) { | 960 | switch (cmd) { |
946 | case SNDRV_PCM_TRIGGER_START: | 961 | case SNDRV_PCM_TRIGGER_START: |
962 | subs->ops.retire = retire_capture_urb; | ||
947 | return start_urbs(subs, substream->runtime); | 963 | return start_urbs(subs, substream->runtime); |
948 | case SNDRV_PCM_TRIGGER_STOP: | 964 | case SNDRV_PCM_TRIGGER_STOP: |
949 | return deactivate_urbs(subs, 0, 0); | 965 | return deactivate_urbs(subs, 0, 0); |
966 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
967 | subs->ops.retire = retire_paused_capture_urb; | ||
968 | return 0; | ||
969 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
970 | subs->ops.retire = retire_capture_urb; | ||
971 | return 0; | ||
950 | default: | 972 | default: |
951 | return -EINVAL; | 973 | return -EINVAL; |
952 | } | 974 | } |
@@ -1408,7 +1430,7 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) | |||
1408 | static int snd_usb_hw_params(struct snd_pcm_substream *substream, | 1430 | static int snd_usb_hw_params(struct snd_pcm_substream *substream, |
1409 | struct snd_pcm_hw_params *hw_params) | 1431 | struct snd_pcm_hw_params *hw_params) |
1410 | { | 1432 | { |
1411 | struct snd_usb_substream *subs = (struct snd_usb_substream *)substream->runtime->private_data; | 1433 | struct snd_usb_substream *subs = substream->runtime->private_data; |
1412 | struct audioformat *fmt; | 1434 | struct audioformat *fmt; |
1413 | unsigned int channels, rate, format; | 1435 | unsigned int channels, rate, format; |
1414 | int ret, changed; | 1436 | int ret, changed; |
@@ -1464,7 +1486,7 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, | |||
1464 | */ | 1486 | */ |
1465 | static int snd_usb_hw_free(struct snd_pcm_substream *substream) | 1487 | static int snd_usb_hw_free(struct snd_pcm_substream *substream) |
1466 | { | 1488 | { |
1467 | struct snd_usb_substream *subs = (struct snd_usb_substream *)substream->runtime->private_data; | 1489 | struct snd_usb_substream *subs = substream->runtime->private_data; |
1468 | 1490 | ||
1469 | subs->cur_audiofmt = NULL; | 1491 | subs->cur_audiofmt = NULL; |
1470 | subs->cur_rate = 0; | 1492 | subs->cur_rate = 0; |
@@ -1505,33 +1527,20 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) | |||
1505 | /* for playback, submit the URBs now; otherwise, the first hwptr_done | 1527 | /* for playback, submit the URBs now; otherwise, the first hwptr_done |
1506 | * updates for all URBs would happen at the same time when starting */ | 1528 | * updates for all URBs would happen at the same time when starting */ |
1507 | if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) { | 1529 | if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) { |
1508 | subs->ops.prepare = prepare_startup_playback_urb; | 1530 | subs->ops.prepare = prepare_nodata_playback_urb; |
1509 | return start_urbs(subs, runtime); | 1531 | return start_urbs(subs, runtime); |
1510 | } else | 1532 | } else |
1511 | return 0; | 1533 | return 0; |
1512 | } | 1534 | } |
1513 | 1535 | ||
1514 | static struct snd_pcm_hardware snd_usb_playback = | 1536 | static struct snd_pcm_hardware snd_usb_hardware = |
1515 | { | 1537 | { |
1516 | .info = SNDRV_PCM_INFO_MMAP | | 1538 | .info = SNDRV_PCM_INFO_MMAP | |
1517 | SNDRV_PCM_INFO_MMAP_VALID | | 1539 | SNDRV_PCM_INFO_MMAP_VALID | |
1518 | SNDRV_PCM_INFO_BATCH | | 1540 | SNDRV_PCM_INFO_BATCH | |
1519 | SNDRV_PCM_INFO_INTERLEAVED | | 1541 | SNDRV_PCM_INFO_INTERLEAVED | |
1520 | SNDRV_PCM_INFO_BLOCK_TRANSFER, | 1542 | SNDRV_PCM_INFO_BLOCK_TRANSFER | |
1521 | .buffer_bytes_max = 1024 * 1024, | 1543 | SNDRV_PCM_INFO_PAUSE, |
1522 | .period_bytes_min = 64, | ||
1523 | .period_bytes_max = 512 * 1024, | ||
1524 | .periods_min = 2, | ||
1525 | .periods_max = 1024, | ||
1526 | }; | ||
1527 | |||
1528 | static struct snd_pcm_hardware snd_usb_capture = | ||
1529 | { | ||
1530 | .info = SNDRV_PCM_INFO_MMAP | | ||
1531 | SNDRV_PCM_INFO_MMAP_VALID | | ||
1532 | SNDRV_PCM_INFO_BATCH | | ||
1533 | SNDRV_PCM_INFO_INTERLEAVED | | ||
1534 | SNDRV_PCM_INFO_BLOCK_TRANSFER, | ||
1535 | .buffer_bytes_max = 1024 * 1024, | 1544 | .buffer_bytes_max = 1024 * 1024, |
1536 | .period_bytes_min = 64, | 1545 | .period_bytes_min = 64, |
1537 | .period_bytes_max = 512 * 1024, | 1546 | .period_bytes_max = 512 * 1024, |
@@ -1810,28 +1819,33 @@ static int check_hw_params_convention(struct snd_usb_substream *subs) | |||
1810 | static int snd_usb_pcm_check_knot(struct snd_pcm_runtime *runtime, | 1819 | static int snd_usb_pcm_check_knot(struct snd_pcm_runtime *runtime, |
1811 | struct snd_usb_substream *subs) | 1820 | struct snd_usb_substream *subs) |
1812 | { | 1821 | { |
1813 | struct list_head *p; | 1822 | struct audioformat *fp; |
1814 | struct snd_pcm_hw_constraint_list constraints_rates; | 1823 | int count = 0, needs_knot = 0; |
1815 | int err; | 1824 | int err; |
1816 | 1825 | ||
1817 | list_for_each(p, &subs->fmt_list) { | 1826 | list_for_each_entry(fp, &subs->fmt_list, list) { |
1818 | struct audioformat *fp; | 1827 | if (fp->rates & SNDRV_PCM_RATE_CONTINUOUS) |
1819 | fp = list_entry(p, struct audioformat, list); | 1828 | return 0; |
1820 | 1829 | count += fp->nr_rates; | |
1821 | if (!fp->needs_knot) | 1830 | if (fp->needs_knot) |
1822 | continue; | 1831 | needs_knot = 1; |
1823 | |||
1824 | constraints_rates.count = fp->nr_rates; | ||
1825 | constraints_rates.list = fp->rate_table; | ||
1826 | constraints_rates.mask = 0; | ||
1827 | |||
1828 | err = snd_pcm_hw_constraint_list(runtime, 0, | ||
1829 | SNDRV_PCM_HW_PARAM_RATE, | ||
1830 | &constraints_rates); | ||
1831 | |||
1832 | if (err < 0) | ||
1833 | return err; | ||
1834 | } | 1832 | } |
1833 | if (!needs_knot) | ||
1834 | return 0; | ||
1835 | |||
1836 | subs->rate_list.count = count; | ||
1837 | subs->rate_list.list = kmalloc(sizeof(int) * count, GFP_KERNEL); | ||
1838 | subs->rate_list.mask = 0; | ||
1839 | count = 0; | ||
1840 | list_for_each_entry(fp, &subs->fmt_list, list) { | ||
1841 | int i; | ||
1842 | for (i = 0; i < fp->nr_rates; i++) | ||
1843 | subs->rate_list.list[count++] = fp->rate_table[i]; | ||
1844 | } | ||
1845 | err = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, | ||
1846 | &subs->rate_list); | ||
1847 | if (err < 0) | ||
1848 | return err; | ||
1835 | 1849 | ||
1836 | return 0; | 1850 | return 0; |
1837 | } | 1851 | } |
@@ -1904,8 +1918,7 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre | |||
1904 | return 0; | 1918 | return 0; |
1905 | } | 1919 | } |
1906 | 1920 | ||
1907 | static int snd_usb_pcm_open(struct snd_pcm_substream *substream, int direction, | 1921 | static int snd_usb_pcm_open(struct snd_pcm_substream *substream, int direction) |
1908 | struct snd_pcm_hardware *hw) | ||
1909 | { | 1922 | { |
1910 | struct snd_usb_stream *as = snd_pcm_substream_chip(substream); | 1923 | struct snd_usb_stream *as = snd_pcm_substream_chip(substream); |
1911 | struct snd_pcm_runtime *runtime = substream->runtime; | 1924 | struct snd_pcm_runtime *runtime = substream->runtime; |
@@ -1913,7 +1926,7 @@ static int snd_usb_pcm_open(struct snd_pcm_substream *substream, int direction, | |||
1913 | 1926 | ||
1914 | subs->interface = -1; | 1927 | subs->interface = -1; |
1915 | subs->format = 0; | 1928 | subs->format = 0; |
1916 | runtime->hw = *hw; | 1929 | runtime->hw = snd_usb_hardware; |
1917 | runtime->private_data = subs; | 1930 | runtime->private_data = subs; |
1918 | subs->pcm_substream = substream; | 1931 | subs->pcm_substream = substream; |
1919 | return setup_hw_info(runtime, subs); | 1932 | return setup_hw_info(runtime, subs); |
@@ -1934,7 +1947,7 @@ static int snd_usb_pcm_close(struct snd_pcm_substream *substream, int direction) | |||
1934 | 1947 | ||
1935 | static int snd_usb_playback_open(struct snd_pcm_substream *substream) | 1948 | static int snd_usb_playback_open(struct snd_pcm_substream *substream) |
1936 | { | 1949 | { |
1937 | return snd_usb_pcm_open(substream, SNDRV_PCM_STREAM_PLAYBACK, &snd_usb_playback); | 1950 | return snd_usb_pcm_open(substream, SNDRV_PCM_STREAM_PLAYBACK); |
1938 | } | 1951 | } |
1939 | 1952 | ||
1940 | static int snd_usb_playback_close(struct snd_pcm_substream *substream) | 1953 | static int snd_usb_playback_close(struct snd_pcm_substream *substream) |
@@ -1944,7 +1957,7 @@ static int snd_usb_playback_close(struct snd_pcm_substream *substream) | |||
1944 | 1957 | ||
1945 | static int snd_usb_capture_open(struct snd_pcm_substream *substream) | 1958 | static int snd_usb_capture_open(struct snd_pcm_substream *substream) |
1946 | { | 1959 | { |
1947 | return snd_usb_pcm_open(substream, SNDRV_PCM_STREAM_CAPTURE, &snd_usb_capture); | 1960 | return snd_usb_pcm_open(substream, SNDRV_PCM_STREAM_CAPTURE); |
1948 | } | 1961 | } |
1949 | 1962 | ||
1950 | static int snd_usb_capture_close(struct snd_pcm_substream *substream) | 1963 | static int snd_usb_capture_close(struct snd_pcm_substream *substream) |
@@ -2231,6 +2244,7 @@ static void free_substream(struct snd_usb_substream *subs) | |||
2231 | kfree(fp->rate_table); | 2244 | kfree(fp->rate_table); |
2232 | kfree(fp); | 2245 | kfree(fp); |
2233 | } | 2246 | } |
2247 | kfree(subs->rate_list.list); | ||
2234 | } | 2248 | } |
2235 | 2249 | ||
2236 | 2250 | ||
@@ -2456,6 +2470,7 @@ static int parse_audio_format_rates(struct snd_usb_audio *chip, struct audioform | |||
2456 | * build the rate table and bitmap flags | 2470 | * build the rate table and bitmap flags |
2457 | */ | 2471 | */ |
2458 | int r, idx, c; | 2472 | int r, idx, c; |
2473 | unsigned int nonzero_rates = 0; | ||
2459 | /* this table corresponds to the SNDRV_PCM_RATE_XXX bit */ | 2474 | /* this table corresponds to the SNDRV_PCM_RATE_XXX bit */ |
2460 | static unsigned int conv_rates[] = { | 2475 | static unsigned int conv_rates[] = { |
2461 | 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000, | 2476 | 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000, |
@@ -2478,6 +2493,7 @@ static int parse_audio_format_rates(struct snd_usb_audio *chip, struct audioform | |||
2478 | fp->altsetting == 5 && fp->maxpacksize == 392) | 2493 | fp->altsetting == 5 && fp->maxpacksize == 392) |
2479 | rate = 96000; | 2494 | rate = 96000; |
2480 | fp->rate_table[r] = rate; | 2495 | fp->rate_table[r] = rate; |
2496 | nonzero_rates |= rate; | ||
2481 | if (rate < fp->rate_min) | 2497 | if (rate < fp->rate_min) |
2482 | fp->rate_min = rate; | 2498 | fp->rate_min = rate; |
2483 | else if (rate > fp->rate_max) | 2499 | else if (rate > fp->rate_max) |
@@ -2493,6 +2509,10 @@ static int parse_audio_format_rates(struct snd_usb_audio *chip, struct audioform | |||
2493 | if (!found) | 2509 | if (!found) |
2494 | fp->needs_knot = 1; | 2510 | fp->needs_knot = 1; |
2495 | } | 2511 | } |
2512 | if (!nonzero_rates) { | ||
2513 | hwc_debug("All rates were zero. Skipping format!\n"); | ||
2514 | return -1; | ||
2515 | } | ||
2496 | if (fp->needs_knot) | 2516 | if (fp->needs_knot) |
2497 | fp->rates |= SNDRV_PCM_RATE_KNOT; | 2517 | fp->rates |= SNDRV_PCM_RATE_KNOT; |
2498 | } else { | 2518 | } else { |
@@ -3057,6 +3077,58 @@ static int create_ua1000_quirk(struct snd_usb_audio *chip, | |||
3057 | return 0; | 3077 | return 0; |
3058 | } | 3078 | } |
3059 | 3079 | ||
3080 | /* | ||
3081 | * Create a stream for an Edirol UA-101 interface. | ||
3082 | * Copy, paste and modify from Edirol UA-1000 | ||
3083 | */ | ||
3084 | static int create_ua101_quirk(struct snd_usb_audio *chip, | ||
3085 | struct usb_interface *iface, | ||
3086 | const struct snd_usb_audio_quirk *quirk) | ||
3087 | { | ||
3088 | static const struct audioformat ua101_format = { | ||
3089 | .format = SNDRV_PCM_FORMAT_S32_LE, | ||
3090 | .fmt_type = USB_FORMAT_TYPE_I, | ||
3091 | .altsetting = 1, | ||
3092 | .altset_idx = 1, | ||
3093 | .attributes = 0, | ||
3094 | .rates = SNDRV_PCM_RATE_CONTINUOUS, | ||
3095 | }; | ||
3096 | struct usb_host_interface *alts; | ||
3097 | struct usb_interface_descriptor *altsd; | ||
3098 | struct audioformat *fp; | ||
3099 | int stream, err; | ||
3100 | |||
3101 | if (iface->num_altsetting != 2) | ||
3102 | return -ENXIO; | ||
3103 | alts = &iface->altsetting[1]; | ||
3104 | altsd = get_iface_desc(alts); | ||
3105 | if (alts->extralen != 18 || alts->extra[1] != USB_DT_CS_INTERFACE || | ||
3106 | altsd->bNumEndpoints != 1) | ||
3107 | return -ENXIO; | ||
3108 | |||
3109 | fp = kmemdup(&ua101_format, sizeof(*fp), GFP_KERNEL); | ||
3110 | if (!fp) | ||
3111 | return -ENOMEM; | ||
3112 | |||
3113 | fp->channels = alts->extra[11]; | ||
3114 | fp->iface = altsd->bInterfaceNumber; | ||
3115 | fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress; | ||
3116 | fp->ep_attr = get_endpoint(alts, 0)->bmAttributes; | ||
3117 | fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize); | ||
3118 | fp->rate_max = fp->rate_min = combine_triple(&alts->extra[15]); | ||
3119 | |||
3120 | stream = (fp->endpoint & USB_DIR_IN) | ||
3121 | ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK; | ||
3122 | err = add_audio_endpoint(chip, stream, fp); | ||
3123 | if (err < 0) { | ||
3124 | kfree(fp); | ||
3125 | return err; | ||
3126 | } | ||
3127 | /* FIXME: playback must be synchronized to capture */ | ||
3128 | usb_set_interface(chip->dev, fp->iface, 0); | ||
3129 | return 0; | ||
3130 | } | ||
3131 | |||
3060 | static int snd_usb_create_quirk(struct snd_usb_audio *chip, | 3132 | static int snd_usb_create_quirk(struct snd_usb_audio *chip, |
3061 | struct usb_interface *iface, | 3133 | struct usb_interface *iface, |
3062 | const struct snd_usb_audio_quirk *quirk); | 3134 | const struct snd_usb_audio_quirk *quirk); |
@@ -3238,6 +3310,7 @@ static int snd_usb_create_quirk(struct snd_usb_audio *chip, | |||
3238 | [QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk, | 3310 | [QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk, |
3239 | [QUIRK_AUDIO_EDIROL_UA700_UA25] = create_ua700_ua25_quirk, | 3311 | [QUIRK_AUDIO_EDIROL_UA700_UA25] = create_ua700_ua25_quirk, |
3240 | [QUIRK_AUDIO_EDIROL_UA1000] = create_ua1000_quirk, | 3312 | [QUIRK_AUDIO_EDIROL_UA1000] = create_ua1000_quirk, |
3313 | [QUIRK_AUDIO_EDIROL_UA101] = create_ua101_quirk, | ||
3241 | }; | 3314 | }; |
3242 | 3315 | ||
3243 | if (quirk->type < QUIRK_TYPE_COUNT) { | 3316 | if (quirk->type < QUIRK_TYPE_COUNT) { |
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 0f4b2b8541d6..2272f45a1867 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h | |||
@@ -159,6 +159,7 @@ enum quirk_type { | |||
159 | QUIRK_AUDIO_FIXED_ENDPOINT, | 159 | QUIRK_AUDIO_FIXED_ENDPOINT, |
160 | QUIRK_AUDIO_EDIROL_UA700_UA25, | 160 | QUIRK_AUDIO_EDIROL_UA700_UA25, |
161 | QUIRK_AUDIO_EDIROL_UA1000, | 161 | QUIRK_AUDIO_EDIROL_UA1000, |
162 | QUIRK_AUDIO_EDIROL_UA101, | ||
162 | 163 | ||
163 | QUIRK_TYPE_COUNT | 164 | QUIRK_TYPE_COUNT |
164 | }; | 165 | }; |
diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h index a7e9563a01df..25b4ab4f61e7 100644 --- a/sound/usb/usbquirks.h +++ b/sound/usb/usbquirks.h | |||
@@ -1098,7 +1098,37 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
1098 | } | 1098 | } |
1099 | } | 1099 | } |
1100 | }, | 1100 | }, |
1101 | /* TODO: add Edirol UA-101 support */ | 1101 | /* Roland UA-101 in High-Speed Mode only */ |
1102 | { | ||
1103 | USB_DEVICE(0x0582, 0x007d), | ||
1104 | .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { | ||
1105 | .vendor_name = "Roland", | ||
1106 | .product_name = "UA-101", | ||
1107 | .ifnum = QUIRK_ANY_INTERFACE, | ||
1108 | .type = QUIRK_COMPOSITE, | ||
1109 | .data = (const struct snd_usb_audio_quirk[]) { | ||
1110 | { | ||
1111 | .ifnum = 0, | ||
1112 | .type = QUIRK_AUDIO_EDIROL_UA101 | ||
1113 | }, | ||
1114 | { | ||
1115 | .ifnum = 1, | ||
1116 | .type = QUIRK_AUDIO_EDIROL_UA101 | ||
1117 | }, | ||
1118 | { | ||
1119 | .ifnum = 2, | ||
1120 | .type = QUIRK_MIDI_FIXED_ENDPOINT, | ||
1121 | .data = & (const struct snd_usb_midi_endpoint_info) { | ||
1122 | .out_cables = 0x0001, | ||
1123 | .in_cables = 0x0001 | ||
1124 | } | ||
1125 | }, | ||
1126 | { | ||
1127 | .ifnum = -1 | ||
1128 | } | ||
1129 | } | ||
1130 | } | ||
1131 | }, | ||
1102 | { | 1132 | { |
1103 | /* has ID 0x0081 when not in "Advanced Driver" mode */ | 1133 | /* has ID 0x0081 when not in "Advanced Driver" mode */ |
1104 | USB_DEVICE(0x0582, 0x0080), | 1134 | USB_DEVICE(0x0582, 0x0080), |