diff options
author | Clemens Ladisch <clemens@ladisch.de> | 2015-01-16 16:16:35 -0500 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2015-01-16 16:44:56 -0500 |
commit | 53c098bfc5b614cd28c416215f5fa68815f1cce9 (patch) | |
tree | 316a608919eed16fc25ec26203e01f8483ea68ed /sound/pci/oxygen/se6x.c | |
parent | a5a335336715d8648ffb1b105ea625790b9d984e (diff) |
ALSA: add Studio Evolution SE6X support
Add a driver for an embedded sound card.
Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/oxygen/se6x.c')
-rw-r--r-- | sound/pci/oxygen/se6x.c | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/sound/pci/oxygen/se6x.c b/sound/pci/oxygen/se6x.c new file mode 100644 index 000000000000..f70d514c1084 --- /dev/null +++ b/sound/pci/oxygen/se6x.c | |||
@@ -0,0 +1,160 @@ | |||
1 | /* | ||
2 | * C-Media CMI8787 driver for the Studio Evolution SE6X | ||
3 | * | ||
4 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> | ||
5 | * | ||
6 | * This driver is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License, version 2. | ||
8 | * | ||
9 | * This driver 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 driver; if not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | /* | ||
19 | * CMI8787: | ||
20 | * | ||
21 | * SPI -> microcontroller (not actually used) | ||
22 | * GPIO 0 -> do. | ||
23 | * GPIO 2 -> do. | ||
24 | * | ||
25 | * DAC0 -> both PCM1792A (L+R, each in mono mode) | ||
26 | * ADC1 <- 1st PCM1804 | ||
27 | * ADC2 <- 2nd PCM1804 | ||
28 | * ADC3 <- 3rd PCM1804 | ||
29 | */ | ||
30 | |||
31 | #include <linux/pci.h> | ||
32 | #include <linux/module.h> | ||
33 | #include <sound/core.h> | ||
34 | #include <sound/control.h> | ||
35 | #include <sound/initval.h> | ||
36 | #include <sound/pcm.h> | ||
37 | #include "oxygen.h" | ||
38 | |||
39 | MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); | ||
40 | MODULE_DESCRIPTION("Studio Evolution SE6X driver"); | ||
41 | MODULE_LICENSE("GPL v2"); | ||
42 | MODULE_SUPPORTED_DEVICE("{{Studio Evolution,SE6X}}"); | ||
43 | |||
44 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; | ||
45 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; | ||
46 | static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; | ||
47 | |||
48 | module_param_array(index, int, NULL, 0444); | ||
49 | MODULE_PARM_DESC(index, "card index"); | ||
50 | module_param_array(id, charp, NULL, 0444); | ||
51 | MODULE_PARM_DESC(id, "ID string"); | ||
52 | module_param_array(enable, bool, NULL, 0444); | ||
53 | MODULE_PARM_DESC(enable, "enable card"); | ||
54 | |||
55 | static const struct pci_device_id se6x_ids[] = { | ||
56 | { OXYGEN_PCI_SUBID(0x13f6, 0x8788) }, | ||
57 | { } | ||
58 | }; | ||
59 | MODULE_DEVICE_TABLE(pci, se6x_ids); | ||
60 | |||
61 | static void se6x_init(struct oxygen *chip) | ||
62 | { | ||
63 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, 0x005); | ||
64 | |||
65 | snd_component_add(chip->card, "PCM1792A"); | ||
66 | snd_component_add(chip->card, "PCM1804"); | ||
67 | } | ||
68 | |||
69 | static int se6x_control_filter(struct snd_kcontrol_new *template) | ||
70 | { | ||
71 | /* no DAC volume/mute */ | ||
72 | if (!strncmp(template->name, "Master Playback ", 16)) | ||
73 | return 1; | ||
74 | return 0; | ||
75 | } | ||
76 | |||
77 | static void se6x_cleanup(struct oxygen *chip) | ||
78 | { | ||
79 | } | ||
80 | |||
81 | static void set_pcm1792a_params(struct oxygen *chip, | ||
82 | struct snd_pcm_hw_params *params) | ||
83 | { | ||
84 | /* nothing to do (the microcontroller monitors DAC_LRCK) */ | ||
85 | } | ||
86 | |||
87 | static void set_pcm1804_params(struct oxygen *chip, | ||
88 | struct snd_pcm_hw_params *params) | ||
89 | { | ||
90 | } | ||
91 | |||
92 | static unsigned int se6x_adjust_dac_routing(struct oxygen *chip, | ||
93 | unsigned int play_routing) | ||
94 | { | ||
95 | /* route the same stereo pair to DAC0 and DAC1 */ | ||
96 | return ( play_routing & OXYGEN_PLAY_DAC0_SOURCE_MASK) | | ||
97 | ((play_routing << 2) & OXYGEN_PLAY_DAC1_SOURCE_MASK); | ||
98 | } | ||
99 | |||
100 | static const struct oxygen_model model_se6x = { | ||
101 | .shortname = "Studio Evolution SE6X", | ||
102 | .longname = "C-Media Oxygen HD Audio", | ||
103 | .chip = "CMI8787", | ||
104 | .init = se6x_init, | ||
105 | .control_filter = se6x_control_filter, | ||
106 | .cleanup = se6x_cleanup, | ||
107 | .set_dac_params = set_pcm1792a_params, | ||
108 | .set_adc_params = set_pcm1804_params, | ||
109 | .adjust_dac_routing = se6x_adjust_dac_routing, | ||
110 | .device_config = PLAYBACK_0_TO_I2S | | ||
111 | CAPTURE_0_FROM_I2S_1 | | ||
112 | CAPTURE_2_FROM_I2S_2 | | ||
113 | CAPTURE_3_FROM_I2S_3, | ||
114 | .dac_channels_pcm = 2, | ||
115 | .function_flags = OXYGEN_FUNCTION_SPI, | ||
116 | .dac_mclks = OXYGEN_MCLKS(256, 128, 128), | ||
117 | .adc_mclks = OXYGEN_MCLKS(256, 256, 128), | ||
118 | .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | ||
119 | .adc_i2s_format = OXYGEN_I2S_FORMAT_I2S, | ||
120 | }; | ||
121 | |||
122 | static int se6x_get_model(struct oxygen *chip, | ||
123 | const struct pci_device_id *pci_id) | ||
124 | { | ||
125 | chip->model = model_se6x; | ||
126 | return 0; | ||
127 | } | ||
128 | |||
129 | static int se6x_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) | ||
130 | { | ||
131 | static int dev; | ||
132 | int err; | ||
133 | |||
134 | if (dev >= SNDRV_CARDS) | ||
135 | return -ENODEV; | ||
136 | if (!enable[dev]) { | ||
137 | ++dev; | ||
138 | return -ENOENT; | ||
139 | } | ||
140 | err = oxygen_pci_probe(pci, index[dev], id[dev], THIS_MODULE, | ||
141 | se6x_ids, se6x_get_model); | ||
142 | if (err >= 0) | ||
143 | ++dev; | ||
144 | return err; | ||
145 | } | ||
146 | |||
147 | static struct pci_driver se6x_driver = { | ||
148 | .name = KBUILD_MODNAME, | ||
149 | .id_table = se6x_ids, | ||
150 | .probe = se6x_probe, | ||
151 | .remove = oxygen_pci_remove, | ||
152 | #ifdef CONFIG_PM_SLEEP | ||
153 | .driver = { | ||
154 | .pm = &oxygen_pci_pm, | ||
155 | }, | ||
156 | #endif | ||
157 | .shutdown = oxygen_pci_shutdown, | ||
158 | }; | ||
159 | |||
160 | module_pci_driver(se6x_driver); | ||