diff options
Diffstat (limited to 'sound')
255 files changed, 27744 insertions, 6349 deletions
diff --git a/sound/aoa/fabrics/layout.c b/sound/aoa/fabrics/layout.c index 586965f9605f..7a437da05646 100644 --- a/sound/aoa/fabrics/layout.c +++ b/sound/aoa/fabrics/layout.c | |||
@@ -768,7 +768,7 @@ static int check_codec(struct aoa_codec *codec, | |||
768 | "required property %s not present\n", propname); | 768 | "required property %s not present\n", propname); |
769 | return -ENODEV; | 769 | return -ENODEV; |
770 | } | 770 | } |
771 | if (*ref != codec->node->linux_phandle) { | 771 | if (*ref != codec->node->phandle) { |
772 | printk(KERN_INFO "snd-aoa-fabric-layout: " | 772 | printk(KERN_INFO "snd-aoa-fabric-layout: " |
773 | "%s doesn't match!\n", propname); | 773 | "%s doesn't match!\n", propname); |
774 | return -ENODEV; | 774 | return -ENODEV; |
diff --git a/sound/core/control.c b/sound/core/control.c index 268ab7471224..439ce64f9d82 100644 --- a/sound/core/control.c +++ b/sound/core/control.c | |||
@@ -237,8 +237,9 @@ struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new *ncontrol, | |||
237 | access = ncontrol->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE : | 237 | access = ncontrol->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE : |
238 | (ncontrol->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE| | 238 | (ncontrol->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE| |
239 | SNDRV_CTL_ELEM_ACCESS_INACTIVE| | 239 | SNDRV_CTL_ELEM_ACCESS_INACTIVE| |
240 | SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE| | 240 | SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE| |
241 | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK)); | 241 | SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND| |
242 | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK)); | ||
242 | kctl.info = ncontrol->info; | 243 | kctl.info = ncontrol->info; |
243 | kctl.get = ncontrol->get; | 244 | kctl.get = ncontrol->get; |
244 | kctl.put = ncontrol->put; | 245 | kctl.put = ncontrol->put; |
@@ -1099,7 +1100,7 @@ static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file, | |||
1099 | 1100 | ||
1100 | if (copy_from_user(&tlv, _tlv, sizeof(tlv))) | 1101 | if (copy_from_user(&tlv, _tlv, sizeof(tlv))) |
1101 | return -EFAULT; | 1102 | return -EFAULT; |
1102 | if (tlv.length < sizeof(unsigned int) * 3) | 1103 | if (tlv.length < sizeof(unsigned int) * 2) |
1103 | return -EINVAL; | 1104 | return -EINVAL; |
1104 | down_read(&card->controls_rwsem); | 1105 | down_read(&card->controls_rwsem); |
1105 | kctl = snd_ctl_find_numid(card, tlv.numid); | 1106 | kctl = snd_ctl_find_numid(card, tlv.numid); |
diff --git a/sound/core/misc.c b/sound/core/misc.c index 23a032c6d487..3da4f92427d8 100644 --- a/sound/core/misc.c +++ b/sound/core/misc.c | |||
@@ -101,8 +101,9 @@ EXPORT_SYMBOL_GPL(__snd_printk); | |||
101 | #ifdef CONFIG_PCI | 101 | #ifdef CONFIG_PCI |
102 | #include <linux/pci.h> | 102 | #include <linux/pci.h> |
103 | /** | 103 | /** |
104 | * snd_pci_quirk_lookup - look up a PCI SSID quirk list | 104 | * snd_pci_quirk_lookup_id - look up a PCI SSID quirk list |
105 | * @pci: pci_dev handle | 105 | * @vendor: PCI SSV id |
106 | * @device: PCI SSD id | ||
106 | * @list: quirk list, terminated by a null entry | 107 | * @list: quirk list, terminated by a null entry |
107 | * | 108 | * |
108 | * Look through the given quirk list and finds a matching entry | 109 | * Look through the given quirk list and finds a matching entry |
@@ -112,18 +113,39 @@ EXPORT_SYMBOL_GPL(__snd_printk); | |||
112 | * Returns the matched entry pointer, or NULL if nothing matched. | 113 | * Returns the matched entry pointer, or NULL if nothing matched. |
113 | */ | 114 | */ |
114 | const struct snd_pci_quirk * | 115 | const struct snd_pci_quirk * |
115 | snd_pci_quirk_lookup(struct pci_dev *pci, const struct snd_pci_quirk *list) | 116 | snd_pci_quirk_lookup_id(u16 vendor, u16 device, |
117 | const struct snd_pci_quirk *list) | ||
116 | { | 118 | { |
117 | const struct snd_pci_quirk *q; | 119 | const struct snd_pci_quirk *q; |
118 | 120 | ||
119 | for (q = list; q->subvendor; q++) { | 121 | for (q = list; q->subvendor; q++) { |
120 | if (q->subvendor != pci->subsystem_vendor) | 122 | if (q->subvendor != vendor) |
121 | continue; | 123 | continue; |
122 | if (!q->subdevice || | 124 | if (!q->subdevice || |
123 | (pci->subsystem_device & q->subdevice_mask) == q->subdevice) | 125 | (device & q->subdevice_mask) == q->subdevice) |
124 | return q; | 126 | return q; |
125 | } | 127 | } |
126 | return NULL; | 128 | return NULL; |
127 | } | 129 | } |
130 | EXPORT_SYMBOL(snd_pci_quirk_lookup_id); | ||
131 | |||
132 | /** | ||
133 | * snd_pci_quirk_lookup - look up a PCI SSID quirk list | ||
134 | * @pci: pci_dev handle | ||
135 | * @list: quirk list, terminated by a null entry | ||
136 | * | ||
137 | * Look through the given quirk list and finds a matching entry | ||
138 | * with the same PCI SSID. When subdevice is 0, all subdevice | ||
139 | * values may match. | ||
140 | * | ||
141 | * Returns the matched entry pointer, or NULL if nothing matched. | ||
142 | */ | ||
143 | const struct snd_pci_quirk * | ||
144 | snd_pci_quirk_lookup(struct pci_dev *pci, const struct snd_pci_quirk *list) | ||
145 | { | ||
146 | return snd_pci_quirk_lookup_id(pci->subsystem_vendor, | ||
147 | pci->subsystem_device, | ||
148 | list); | ||
149 | } | ||
128 | EXPORT_SYMBOL(snd_pci_quirk_lookup); | 150 | EXPORT_SYMBOL(snd_pci_quirk_lookup); |
129 | #endif | 151 | #endif |
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index d9c96353121a..82d4e3329b3d 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c | |||
@@ -632,6 +632,12 @@ static long snd_pcm_alsa_frames(struct snd_pcm_substream *substream, long bytes) | |||
632 | return bytes_to_frames(runtime, (buffer_size * bytes) / runtime->oss.buffer_bytes); | 632 | return bytes_to_frames(runtime, (buffer_size * bytes) / runtime->oss.buffer_bytes); |
633 | } | 633 | } |
634 | 634 | ||
635 | static inline | ||
636 | snd_pcm_uframes_t get_hw_ptr_period(struct snd_pcm_runtime *runtime) | ||
637 | { | ||
638 | return runtime->hw_ptr_interrupt; | ||
639 | } | ||
640 | |||
635 | /* define extended formats in the recent OSS versions (if any) */ | 641 | /* define extended formats in the recent OSS versions (if any) */ |
636 | /* linear formats */ | 642 | /* linear formats */ |
637 | #define AFMT_S32_LE 0x00001000 | 643 | #define AFMT_S32_LE 0x00001000 |
@@ -1102,7 +1108,7 @@ static int snd_pcm_oss_prepare(struct snd_pcm_substream *substream) | |||
1102 | return err; | 1108 | return err; |
1103 | } | 1109 | } |
1104 | runtime->oss.prepare = 0; | 1110 | runtime->oss.prepare = 0; |
1105 | runtime->oss.prev_hw_ptr_interrupt = 0; | 1111 | runtime->oss.prev_hw_ptr_period = 0; |
1106 | runtime->oss.period_ptr = 0; | 1112 | runtime->oss.period_ptr = 0; |
1107 | runtime->oss.buffer_used = 0; | 1113 | runtime->oss.buffer_used = 0; |
1108 | 1114 | ||
@@ -1950,7 +1956,8 @@ static int snd_pcm_oss_get_caps(struct snd_pcm_oss_file *pcm_oss_file) | |||
1950 | return result; | 1956 | return result; |
1951 | } | 1957 | } |
1952 | 1958 | ||
1953 | static void snd_pcm_oss_simulate_fill(struct snd_pcm_substream *substream, snd_pcm_uframes_t hw_ptr) | 1959 | static void snd_pcm_oss_simulate_fill(struct snd_pcm_substream *substream, |
1960 | snd_pcm_uframes_t hw_ptr) | ||
1954 | { | 1961 | { |
1955 | struct snd_pcm_runtime *runtime = substream->runtime; | 1962 | struct snd_pcm_runtime *runtime = substream->runtime; |
1956 | snd_pcm_uframes_t appl_ptr; | 1963 | snd_pcm_uframes_t appl_ptr; |
@@ -1986,7 +1993,8 @@ static int snd_pcm_oss_set_trigger(struct snd_pcm_oss_file *pcm_oss_file, int tr | |||
1986 | if (runtime->oss.trigger) | 1993 | if (runtime->oss.trigger) |
1987 | goto _skip1; | 1994 | goto _skip1; |
1988 | if (atomic_read(&psubstream->mmap_count)) | 1995 | if (atomic_read(&psubstream->mmap_count)) |
1989 | snd_pcm_oss_simulate_fill(psubstream, runtime->hw_ptr_interrupt); | 1996 | snd_pcm_oss_simulate_fill(psubstream, |
1997 | get_hw_ptr_period(runtime)); | ||
1990 | runtime->oss.trigger = 1; | 1998 | runtime->oss.trigger = 1; |
1991 | runtime->start_threshold = 1; | 1999 | runtime->start_threshold = 1; |
1992 | cmd = SNDRV_PCM_IOCTL_START; | 2000 | cmd = SNDRV_PCM_IOCTL_START; |
@@ -2105,11 +2113,12 @@ static int snd_pcm_oss_get_ptr(struct snd_pcm_oss_file *pcm_oss_file, int stream | |||
2105 | info.ptr = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr % runtime->buffer_size); | 2113 | info.ptr = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr % runtime->buffer_size); |
2106 | if (atomic_read(&substream->mmap_count)) { | 2114 | if (atomic_read(&substream->mmap_count)) { |
2107 | snd_pcm_sframes_t n; | 2115 | snd_pcm_sframes_t n; |
2108 | n = (delay = runtime->hw_ptr_interrupt) - runtime->oss.prev_hw_ptr_interrupt; | 2116 | delay = get_hw_ptr_period(runtime); |
2117 | n = delay - runtime->oss.prev_hw_ptr_period; | ||
2109 | if (n < 0) | 2118 | if (n < 0) |
2110 | n += runtime->boundary; | 2119 | n += runtime->boundary; |
2111 | info.blocks = n / runtime->period_size; | 2120 | info.blocks = n / runtime->period_size; |
2112 | runtime->oss.prev_hw_ptr_interrupt = delay; | 2121 | runtime->oss.prev_hw_ptr_period = delay; |
2113 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 2122 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
2114 | snd_pcm_oss_simulate_fill(substream, delay); | 2123 | snd_pcm_oss_simulate_fill(substream, delay); |
2115 | info.bytes = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr) & INT_MAX; | 2124 | info.bytes = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr) & INT_MAX; |
@@ -2673,18 +2682,22 @@ static int snd_pcm_oss_playback_ready(struct snd_pcm_substream *substream) | |||
2673 | { | 2682 | { |
2674 | struct snd_pcm_runtime *runtime = substream->runtime; | 2683 | struct snd_pcm_runtime *runtime = substream->runtime; |
2675 | if (atomic_read(&substream->mmap_count)) | 2684 | if (atomic_read(&substream->mmap_count)) |
2676 | return runtime->oss.prev_hw_ptr_interrupt != runtime->hw_ptr_interrupt; | 2685 | return runtime->oss.prev_hw_ptr_period != |
2686 | get_hw_ptr_period(runtime); | ||
2677 | else | 2687 | else |
2678 | return snd_pcm_playback_avail(runtime) >= runtime->oss.period_frames; | 2688 | return snd_pcm_playback_avail(runtime) >= |
2689 | runtime->oss.period_frames; | ||
2679 | } | 2690 | } |
2680 | 2691 | ||
2681 | static int snd_pcm_oss_capture_ready(struct snd_pcm_substream *substream) | 2692 | static int snd_pcm_oss_capture_ready(struct snd_pcm_substream *substream) |
2682 | { | 2693 | { |
2683 | struct snd_pcm_runtime *runtime = substream->runtime; | 2694 | struct snd_pcm_runtime *runtime = substream->runtime; |
2684 | if (atomic_read(&substream->mmap_count)) | 2695 | if (atomic_read(&substream->mmap_count)) |
2685 | return runtime->oss.prev_hw_ptr_interrupt != runtime->hw_ptr_interrupt; | 2696 | return runtime->oss.prev_hw_ptr_period != |
2697 | get_hw_ptr_period(runtime); | ||
2686 | else | 2698 | else |
2687 | return snd_pcm_capture_avail(runtime) >= runtime->oss.period_frames; | 2699 | return snd_pcm_capture_avail(runtime) >= |
2700 | runtime->oss.period_frames; | ||
2688 | } | 2701 | } |
2689 | 2702 | ||
2690 | static unsigned int snd_pcm_oss_poll(struct file *file, poll_table * wait) | 2703 | static unsigned int snd_pcm_oss_poll(struct file *file, poll_table * wait) |
diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 6884ae031f6f..0d428d0896db 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c | |||
@@ -894,6 +894,7 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, | |||
894 | memset((void*)runtime->control, 0, size); | 894 | memset((void*)runtime->control, 0, size); |
895 | 895 | ||
896 | init_waitqueue_head(&runtime->sleep); | 896 | init_waitqueue_head(&runtime->sleep); |
897 | init_waitqueue_head(&runtime->tsleep); | ||
897 | 898 | ||
898 | runtime->status->state = SNDRV_PCM_STATE_OPEN; | 899 | runtime->status->state = SNDRV_PCM_STATE_OPEN; |
899 | 900 | ||
@@ -921,6 +922,10 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream) | |||
921 | snd_free_pages((void*)runtime->control, | 922 | snd_free_pages((void*)runtime->control, |
922 | PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control))); | 923 | PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control))); |
923 | kfree(runtime->hw_constraints.rules); | 924 | kfree(runtime->hw_constraints.rules); |
925 | #ifdef CONFIG_SND_PCM_XRUN_DEBUG | ||
926 | if (runtime->hwptr_log) | ||
927 | kfree(runtime->hwptr_log); | ||
928 | #endif | ||
924 | kfree(runtime); | 929 | kfree(runtime); |
925 | substream->runtime = NULL; | 930 | substream->runtime = NULL; |
926 | put_pid(substream->pid); | 931 | put_pid(substream->pid); |
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index a27545b23ee9..b546ac2660f9 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c | |||
@@ -126,17 +126,6 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram | |||
126 | } | 126 | } |
127 | } | 127 | } |
128 | 128 | ||
129 | #ifdef CONFIG_SND_PCM_XRUN_DEBUG | ||
130 | #define xrun_debug(substream, mask) ((substream)->pstr->xrun_debug & (mask)) | ||
131 | #else | ||
132 | #define xrun_debug(substream, mask) 0 | ||
133 | #endif | ||
134 | |||
135 | #define dump_stack_on_xrun(substream) do { \ | ||
136 | if (xrun_debug(substream, 2)) \ | ||
137 | dump_stack(); \ | ||
138 | } while (0) | ||
139 | |||
140 | static void pcm_debug_name(struct snd_pcm_substream *substream, | 129 | static void pcm_debug_name(struct snd_pcm_substream *substream, |
141 | char *name, size_t len) | 130 | char *name, size_t len) |
142 | { | 131 | { |
@@ -147,6 +136,24 @@ static void pcm_debug_name(struct snd_pcm_substream *substream, | |||
147 | substream->number); | 136 | substream->number); |
148 | } | 137 | } |
149 | 138 | ||
139 | #define XRUN_DEBUG_BASIC (1<<0) | ||
140 | #define XRUN_DEBUG_STACK (1<<1) /* dump also stack */ | ||
141 | #define XRUN_DEBUG_JIFFIESCHECK (1<<2) /* do jiffies check */ | ||
142 | #define XRUN_DEBUG_PERIODUPDATE (1<<3) /* full period update info */ | ||
143 | #define XRUN_DEBUG_HWPTRUPDATE (1<<4) /* full hwptr update info */ | ||
144 | #define XRUN_DEBUG_LOG (1<<5) /* show last 10 positions on err */ | ||
145 | #define XRUN_DEBUG_LOGONCE (1<<6) /* do above only once */ | ||
146 | |||
147 | #ifdef CONFIG_SND_PCM_XRUN_DEBUG | ||
148 | |||
149 | #define xrun_debug(substream, mask) \ | ||
150 | ((substream)->pstr->xrun_debug & (mask)) | ||
151 | |||
152 | #define dump_stack_on_xrun(substream) do { \ | ||
153 | if (xrun_debug(substream, XRUN_DEBUG_STACK)) \ | ||
154 | dump_stack(); \ | ||
155 | } while (0) | ||
156 | |||
150 | static void xrun(struct snd_pcm_substream *substream) | 157 | static void xrun(struct snd_pcm_substream *substream) |
151 | { | 158 | { |
152 | struct snd_pcm_runtime *runtime = substream->runtime; | 159 | struct snd_pcm_runtime *runtime = substream->runtime; |
@@ -154,7 +161,7 @@ static void xrun(struct snd_pcm_substream *substream) | |||
154 | if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) | 161 | if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) |
155 | snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp); | 162 | snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp); |
156 | snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); | 163 | snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); |
157 | if (xrun_debug(substream, 1)) { | 164 | if (xrun_debug(substream, XRUN_DEBUG_BASIC)) { |
158 | char name[16]; | 165 | char name[16]; |
159 | pcm_debug_name(substream, name, sizeof(name)); | 166 | pcm_debug_name(substream, name, sizeof(name)); |
160 | snd_printd(KERN_DEBUG "XRUN: %s\n", name); | 167 | snd_printd(KERN_DEBUG "XRUN: %s\n", name); |
@@ -162,32 +169,102 @@ static void xrun(struct snd_pcm_substream *substream) | |||
162 | } | 169 | } |
163 | } | 170 | } |
164 | 171 | ||
165 | static snd_pcm_uframes_t | 172 | #define hw_ptr_error(substream, fmt, args...) \ |
166 | snd_pcm_update_hw_ptr_pos(struct snd_pcm_substream *substream, | 173 | do { \ |
167 | struct snd_pcm_runtime *runtime) | 174 | if (xrun_debug(substream, XRUN_DEBUG_BASIC)) { \ |
168 | { | 175 | xrun_log_show(substream); \ |
176 | if (printk_ratelimit()) { \ | ||
177 | snd_printd("PCM: " fmt, ##args); \ | ||
178 | } \ | ||
179 | dump_stack_on_xrun(substream); \ | ||
180 | } \ | ||
181 | } while (0) | ||
182 | |||
183 | #define XRUN_LOG_CNT 10 | ||
184 | |||
185 | struct hwptr_log_entry { | ||
186 | unsigned long jiffies; | ||
169 | snd_pcm_uframes_t pos; | 187 | snd_pcm_uframes_t pos; |
188 | snd_pcm_uframes_t period_size; | ||
189 | snd_pcm_uframes_t buffer_size; | ||
190 | snd_pcm_uframes_t old_hw_ptr; | ||
191 | snd_pcm_uframes_t hw_ptr_base; | ||
192 | }; | ||
170 | 193 | ||
171 | pos = substream->ops->pointer(substream); | 194 | struct snd_pcm_hwptr_log { |
172 | if (pos == SNDRV_PCM_POS_XRUN) | 195 | unsigned int idx; |
173 | return pos; /* XRUN */ | 196 | unsigned int hit: 1; |
174 | if (pos >= runtime->buffer_size) { | 197 | struct hwptr_log_entry entries[XRUN_LOG_CNT]; |
175 | if (printk_ratelimit()) { | 198 | }; |
176 | char name[16]; | 199 | |
177 | pcm_debug_name(substream, name, sizeof(name)); | 200 | static void xrun_log(struct snd_pcm_substream *substream, |
178 | snd_printd(KERN_ERR "BUG: %s, pos = 0x%lx, " | 201 | snd_pcm_uframes_t pos) |
179 | "buffer size = 0x%lx, period size = 0x%lx\n", | 202 | { |
180 | name, pos, runtime->buffer_size, | 203 | struct snd_pcm_runtime *runtime = substream->runtime; |
181 | runtime->period_size); | 204 | struct snd_pcm_hwptr_log *log = runtime->hwptr_log; |
182 | } | 205 | struct hwptr_log_entry *entry; |
183 | pos = 0; | 206 | |
207 | if (log == NULL) { | ||
208 | log = kzalloc(sizeof(*log), GFP_ATOMIC); | ||
209 | if (log == NULL) | ||
210 | return; | ||
211 | runtime->hwptr_log = log; | ||
212 | } else { | ||
213 | if (xrun_debug(substream, XRUN_DEBUG_LOGONCE) && log->hit) | ||
214 | return; | ||
184 | } | 215 | } |
185 | pos -= pos % runtime->min_align; | 216 | entry = &log->entries[log->idx]; |
186 | return pos; | 217 | entry->jiffies = jiffies; |
218 | entry->pos = pos; | ||
219 | entry->period_size = runtime->period_size; | ||
220 | entry->buffer_size = runtime->buffer_size;; | ||
221 | entry->old_hw_ptr = runtime->status->hw_ptr; | ||
222 | entry->hw_ptr_base = runtime->hw_ptr_base; | ||
223 | log->idx = (log->idx + 1) % XRUN_LOG_CNT; | ||
224 | } | ||
225 | |||
226 | static void xrun_log_show(struct snd_pcm_substream *substream) | ||
227 | { | ||
228 | struct snd_pcm_hwptr_log *log = substream->runtime->hwptr_log; | ||
229 | struct hwptr_log_entry *entry; | ||
230 | char name[16]; | ||
231 | unsigned int idx; | ||
232 | int cnt; | ||
233 | |||
234 | if (log == NULL) | ||
235 | return; | ||
236 | if (xrun_debug(substream, XRUN_DEBUG_LOGONCE) && log->hit) | ||
237 | return; | ||
238 | pcm_debug_name(substream, name, sizeof(name)); | ||
239 | for (cnt = 0, idx = log->idx; cnt < XRUN_LOG_CNT; cnt++) { | ||
240 | entry = &log->entries[idx]; | ||
241 | if (entry->period_size == 0) | ||
242 | break; | ||
243 | snd_printd("hwptr log: %s: j=%lu, pos=%ld/%ld/%ld, " | ||
244 | "hwptr=%ld/%ld\n", | ||
245 | name, entry->jiffies, (unsigned long)entry->pos, | ||
246 | (unsigned long)entry->period_size, | ||
247 | (unsigned long)entry->buffer_size, | ||
248 | (unsigned long)entry->old_hw_ptr, | ||
249 | (unsigned long)entry->hw_ptr_base); | ||
250 | idx++; | ||
251 | idx %= XRUN_LOG_CNT; | ||
252 | } | ||
253 | log->hit = 1; | ||
187 | } | 254 | } |
188 | 255 | ||
189 | static int snd_pcm_update_hw_ptr_post(struct snd_pcm_substream *substream, | 256 | #else /* ! CONFIG_SND_PCM_XRUN_DEBUG */ |
190 | struct snd_pcm_runtime *runtime) | 257 | |
258 | #define xrun_debug(substream, mask) 0 | ||
259 | #define xrun(substream) do { } while (0) | ||
260 | #define hw_ptr_error(substream, fmt, args...) do { } while (0) | ||
261 | #define xrun_log(substream, pos) do { } while (0) | ||
262 | #define xrun_log_show(substream) do { } while (0) | ||
263 | |||
264 | #endif | ||
265 | |||
266 | int snd_pcm_update_state(struct snd_pcm_substream *substream, | ||
267 | struct snd_pcm_runtime *runtime) | ||
191 | { | 268 | { |
192 | snd_pcm_uframes_t avail; | 269 | snd_pcm_uframes_t avail; |
193 | 270 | ||
@@ -209,88 +286,94 @@ static int snd_pcm_update_hw_ptr_post(struct snd_pcm_substream *substream, | |||
209 | } | 286 | } |
210 | } | 287 | } |
211 | if (avail >= runtime->control->avail_min) | 288 | if (avail >= runtime->control->avail_min) |
212 | wake_up(&runtime->sleep); | 289 | wake_up(runtime->twake ? &runtime->tsleep : &runtime->sleep); |
213 | return 0; | 290 | return 0; |
214 | } | 291 | } |
215 | 292 | ||
216 | #define hw_ptr_error(substream, fmt, args...) \ | 293 | static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, |
217 | do { \ | 294 | unsigned int in_interrupt) |
218 | if (xrun_debug(substream, 1)) { \ | ||
219 | if (printk_ratelimit()) { \ | ||
220 | snd_printd("PCM: " fmt, ##args); \ | ||
221 | } \ | ||
222 | dump_stack_on_xrun(substream); \ | ||
223 | } \ | ||
224 | } while (0) | ||
225 | |||
226 | static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream) | ||
227 | { | 295 | { |
228 | struct snd_pcm_runtime *runtime = substream->runtime; | 296 | struct snd_pcm_runtime *runtime = substream->runtime; |
229 | snd_pcm_uframes_t pos; | 297 | snd_pcm_uframes_t pos; |
230 | snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_ptr_interrupt, hw_base; | 298 | snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_base; |
231 | snd_pcm_sframes_t hdelta, delta; | 299 | snd_pcm_sframes_t hdelta, delta; |
232 | unsigned long jdelta; | 300 | unsigned long jdelta; |
233 | 301 | ||
234 | old_hw_ptr = runtime->status->hw_ptr; | 302 | old_hw_ptr = runtime->status->hw_ptr; |
235 | pos = snd_pcm_update_hw_ptr_pos(substream, runtime); | 303 | pos = substream->ops->pointer(substream); |
236 | if (pos == SNDRV_PCM_POS_XRUN) { | 304 | if (pos == SNDRV_PCM_POS_XRUN) { |
237 | xrun(substream); | 305 | xrun(substream); |
238 | return -EPIPE; | 306 | return -EPIPE; |
239 | } | 307 | } |
240 | if (xrun_debug(substream, 8)) { | 308 | if (pos >= runtime->buffer_size) { |
241 | char name[16]; | 309 | if (printk_ratelimit()) { |
242 | pcm_debug_name(substream, name, sizeof(name)); | 310 | char name[16]; |
243 | snd_printd("period_update: %s: pos=0x%x/0x%x/0x%x, " | 311 | pcm_debug_name(substream, name, sizeof(name)); |
244 | "hwptr=0x%lx, hw_base=0x%lx, hw_intr=0x%lx\n", | 312 | xrun_log_show(substream); |
245 | name, (unsigned int)pos, | 313 | snd_printd(KERN_ERR "BUG: %s, pos = %ld, " |
246 | (unsigned int)runtime->period_size, | 314 | "buffer size = %ld, period size = %ld\n", |
247 | (unsigned int)runtime->buffer_size, | 315 | name, pos, runtime->buffer_size, |
248 | (unsigned long)old_hw_ptr, | 316 | runtime->period_size); |
249 | (unsigned long)runtime->hw_ptr_base, | 317 | } |
250 | (unsigned long)runtime->hw_ptr_interrupt); | 318 | pos = 0; |
251 | } | 319 | } |
320 | pos -= pos % runtime->min_align; | ||
321 | if (xrun_debug(substream, XRUN_DEBUG_LOG)) | ||
322 | xrun_log(substream, pos); | ||
252 | hw_base = runtime->hw_ptr_base; | 323 | hw_base = runtime->hw_ptr_base; |
253 | new_hw_ptr = hw_base + pos; | 324 | new_hw_ptr = hw_base + pos; |
254 | hw_ptr_interrupt = runtime->hw_ptr_interrupt + runtime->period_size; | 325 | if (in_interrupt) { |
255 | delta = new_hw_ptr - hw_ptr_interrupt; | 326 | /* we know that one period was processed */ |
256 | if (hw_ptr_interrupt >= runtime->boundary) { | 327 | /* delta = "expected next hw_ptr" for in_interrupt != 0 */ |
257 | hw_ptr_interrupt -= runtime->boundary; | 328 | delta = runtime->hw_ptr_interrupt + runtime->period_size; |
258 | if (hw_base < runtime->boundary / 2) | 329 | if (delta > new_hw_ptr) { |
259 | /* hw_base was already lapped; recalc delta */ | ||
260 | delta = new_hw_ptr - hw_ptr_interrupt; | ||
261 | } | ||
262 | if (delta < 0) { | ||
263 | if (runtime->periods == 1 || new_hw_ptr < old_hw_ptr) | ||
264 | delta += runtime->buffer_size; | ||
265 | if (delta < 0) { | ||
266 | hw_ptr_error(substream, | ||
267 | "Unexpected hw_pointer value " | ||
268 | "(stream=%i, pos=%ld, intr_ptr=%ld)\n", | ||
269 | substream->stream, (long)pos, | ||
270 | (long)hw_ptr_interrupt); | ||
271 | #if 1 | ||
272 | /* simply skipping the hwptr update seems more | ||
273 | * robust in some cases, e.g. on VMware with | ||
274 | * inaccurate timer source | ||
275 | */ | ||
276 | return 0; /* skip this update */ | ||
277 | #else | ||
278 | /* rebase to interrupt position */ | ||
279 | hw_base = new_hw_ptr = hw_ptr_interrupt; | ||
280 | /* align hw_base to buffer_size */ | ||
281 | hw_base -= hw_base % runtime->buffer_size; | ||
282 | delta = 0; | ||
283 | #endif | ||
284 | } else { | ||
285 | hw_base += runtime->buffer_size; | 330 | hw_base += runtime->buffer_size; |
286 | if (hw_base >= runtime->boundary) | 331 | if (hw_base >= runtime->boundary) |
287 | hw_base = 0; | 332 | hw_base = 0; |
288 | new_hw_ptr = hw_base + pos; | 333 | new_hw_ptr = hw_base + pos; |
334 | goto __delta; | ||
289 | } | 335 | } |
290 | } | 336 | } |
337 | /* new_hw_ptr might be lower than old_hw_ptr in case when */ | ||
338 | /* pointer crosses the end of the ring buffer */ | ||
339 | if (new_hw_ptr < old_hw_ptr) { | ||
340 | hw_base += runtime->buffer_size; | ||
341 | if (hw_base >= runtime->boundary) | ||
342 | hw_base = 0; | ||
343 | new_hw_ptr = hw_base + pos; | ||
344 | } | ||
345 | __delta: | ||
346 | delta = (new_hw_ptr - old_hw_ptr) % runtime->boundary; | ||
347 | if (xrun_debug(substream, in_interrupt ? | ||
348 | XRUN_DEBUG_PERIODUPDATE : XRUN_DEBUG_HWPTRUPDATE)) { | ||
349 | char name[16]; | ||
350 | pcm_debug_name(substream, name, sizeof(name)); | ||
351 | snd_printd("%s_update: %s: pos=%u/%u/%u, " | ||
352 | "hwptr=%ld/%ld/%ld/%ld\n", | ||
353 | in_interrupt ? "period" : "hwptr", | ||
354 | name, | ||
355 | (unsigned int)pos, | ||
356 | (unsigned int)runtime->period_size, | ||
357 | (unsigned int)runtime->buffer_size, | ||
358 | (unsigned long)delta, | ||
359 | (unsigned long)old_hw_ptr, | ||
360 | (unsigned long)new_hw_ptr, | ||
361 | (unsigned long)runtime->hw_ptr_base); | ||
362 | } | ||
363 | /* something must be really wrong */ | ||
364 | if (delta >= runtime->buffer_size + runtime->period_size) { | ||
365 | hw_ptr_error(substream, | ||
366 | "Unexpected hw_pointer value %s" | ||
367 | "(stream=%i, pos=%ld, new_hw_ptr=%ld, " | ||
368 | "old_hw_ptr=%ld)\n", | ||
369 | in_interrupt ? "[Q] " : "[P]", | ||
370 | substream->stream, (long)pos, | ||
371 | (long)new_hw_ptr, (long)old_hw_ptr); | ||
372 | return 0; | ||
373 | } | ||
291 | 374 | ||
292 | /* Do jiffies check only in xrun_debug mode */ | 375 | /* Do jiffies check only in xrun_debug mode */ |
293 | if (!xrun_debug(substream, 4)) | 376 | if (!xrun_debug(substream, XRUN_DEBUG_JIFFIESCHECK)) |
294 | goto no_jiffies_check; | 377 | goto no_jiffies_check; |
295 | 378 | ||
296 | /* Skip the jiffies check for hardwares with BATCH flag. | 379 | /* Skip the jiffies check for hardwares with BATCH flag. |
@@ -299,7 +382,7 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream) | |||
299 | */ | 382 | */ |
300 | if (runtime->hw.info & SNDRV_PCM_INFO_BATCH) | 383 | if (runtime->hw.info & SNDRV_PCM_INFO_BATCH) |
301 | goto no_jiffies_check; | 384 | goto no_jiffies_check; |
302 | hdelta = new_hw_ptr - old_hw_ptr; | 385 | hdelta = delta; |
303 | if (hdelta < runtime->delay) | 386 | if (hdelta < runtime->delay) |
304 | goto no_jiffies_check; | 387 | goto no_jiffies_check; |
305 | hdelta -= runtime->delay; | 388 | hdelta -= runtime->delay; |
@@ -308,130 +391,68 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream) | |||
308 | delta = jdelta / | 391 | delta = jdelta / |
309 | (((runtime->period_size * HZ) / runtime->rate) | 392 | (((runtime->period_size * HZ) / runtime->rate) |
310 | + HZ/100); | 393 | + HZ/100); |
394 | /* move new_hw_ptr according jiffies not pos variable */ | ||
395 | new_hw_ptr = old_hw_ptr; | ||
396 | hw_base = delta; | ||
397 | /* use loop to avoid checks for delta overflows */ | ||
398 | /* the delta value is small or zero in most cases */ | ||
399 | while (delta > 0) { | ||
400 | new_hw_ptr += runtime->period_size; | ||
401 | if (new_hw_ptr >= runtime->boundary) | ||
402 | new_hw_ptr -= runtime->boundary; | ||
403 | delta--; | ||
404 | } | ||
405 | /* align hw_base to buffer_size */ | ||
311 | hw_ptr_error(substream, | 406 | hw_ptr_error(substream, |
312 | "hw_ptr skipping! [Q] " | 407 | "hw_ptr skipping! %s" |
313 | "(pos=%ld, delta=%ld, period=%ld, " | 408 | "(pos=%ld, delta=%ld, period=%ld, " |
314 | "jdelta=%lu/%lu/%lu)\n", | 409 | "jdelta=%lu/%lu/%lu, hw_ptr=%ld/%ld)\n", |
410 | in_interrupt ? "[Q] " : "", | ||
315 | (long)pos, (long)hdelta, | 411 | (long)pos, (long)hdelta, |
316 | (long)runtime->period_size, jdelta, | 412 | (long)runtime->period_size, jdelta, |
317 | ((hdelta * HZ) / runtime->rate), delta); | 413 | ((hdelta * HZ) / runtime->rate), hw_base, |
318 | hw_ptr_interrupt = runtime->hw_ptr_interrupt + | 414 | (unsigned long)old_hw_ptr, |
319 | runtime->period_size * delta; | 415 | (unsigned long)new_hw_ptr); |
320 | if (hw_ptr_interrupt >= runtime->boundary) | 416 | /* reset values to proper state */ |
321 | hw_ptr_interrupt -= runtime->boundary; | ||
322 | /* rebase to interrupt position */ | ||
323 | hw_base = new_hw_ptr = hw_ptr_interrupt; | ||
324 | /* align hw_base to buffer_size */ | ||
325 | hw_base -= hw_base % runtime->buffer_size; | ||
326 | delta = 0; | 417 | delta = 0; |
418 | hw_base = new_hw_ptr - (new_hw_ptr % runtime->buffer_size); | ||
327 | } | 419 | } |
328 | no_jiffies_check: | 420 | no_jiffies_check: |
329 | if (delta > runtime->period_size + runtime->period_size / 2) { | 421 | if (delta > runtime->period_size + runtime->period_size / 2) { |
330 | hw_ptr_error(substream, | 422 | hw_ptr_error(substream, |
331 | "Lost interrupts? " | 423 | "Lost interrupts? %s" |
332 | "(stream=%i, delta=%ld, intr_ptr=%ld)\n", | 424 | "(stream=%i, delta=%ld, new_hw_ptr=%ld, " |
425 | "old_hw_ptr=%ld)\n", | ||
426 | in_interrupt ? "[Q] " : "", | ||
333 | substream->stream, (long)delta, | 427 | substream->stream, (long)delta, |
334 | (long)hw_ptr_interrupt); | 428 | (long)new_hw_ptr, |
335 | /* rebase hw_ptr_interrupt */ | 429 | (long)old_hw_ptr); |
336 | hw_ptr_interrupt = | ||
337 | new_hw_ptr - new_hw_ptr % runtime->period_size; | ||
338 | } | 430 | } |
339 | runtime->hw_ptr_interrupt = hw_ptr_interrupt; | 431 | |
432 | if (runtime->status->hw_ptr == new_hw_ptr) | ||
433 | return 0; | ||
340 | 434 | ||
341 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && | 435 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && |
342 | runtime->silence_size > 0) | 436 | runtime->silence_size > 0) |
343 | snd_pcm_playback_silence(substream, new_hw_ptr); | 437 | snd_pcm_playback_silence(substream, new_hw_ptr); |
344 | 438 | ||
345 | if (runtime->status->hw_ptr == new_hw_ptr) | 439 | if (in_interrupt) { |
346 | return 0; | 440 | runtime->hw_ptr_interrupt = new_hw_ptr - |
347 | 441 | (new_hw_ptr % runtime->period_size); | |
442 | } | ||
348 | runtime->hw_ptr_base = hw_base; | 443 | runtime->hw_ptr_base = hw_base; |
349 | runtime->status->hw_ptr = new_hw_ptr; | 444 | runtime->status->hw_ptr = new_hw_ptr; |
350 | runtime->hw_ptr_jiffies = jiffies; | 445 | runtime->hw_ptr_jiffies = jiffies; |
351 | if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) | 446 | if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) |
352 | snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp); | 447 | snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp); |
353 | 448 | ||
354 | return snd_pcm_update_hw_ptr_post(substream, runtime); | 449 | return snd_pcm_update_state(substream, runtime); |
355 | } | 450 | } |
356 | 451 | ||
357 | /* CAUTION: call it with irq disabled */ | 452 | /* CAUTION: call it with irq disabled */ |
358 | int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream) | 453 | int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream) |
359 | { | 454 | { |
360 | struct snd_pcm_runtime *runtime = substream->runtime; | 455 | return snd_pcm_update_hw_ptr0(substream, 0); |
361 | snd_pcm_uframes_t pos; | ||
362 | snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_base; | ||
363 | snd_pcm_sframes_t delta; | ||
364 | unsigned long jdelta; | ||
365 | |||
366 | old_hw_ptr = runtime->status->hw_ptr; | ||
367 | pos = snd_pcm_update_hw_ptr_pos(substream, runtime); | ||
368 | if (pos == SNDRV_PCM_POS_XRUN) { | ||
369 | xrun(substream); | ||
370 | return -EPIPE; | ||
371 | } | ||
372 | if (xrun_debug(substream, 16)) { | ||
373 | char name[16]; | ||
374 | pcm_debug_name(substream, name, sizeof(name)); | ||
375 | snd_printd("hw_update: %s: pos=0x%x/0x%x/0x%x, " | ||
376 | "hwptr=0x%lx, hw_base=0x%lx, hw_intr=0x%lx\n", | ||
377 | name, (unsigned int)pos, | ||
378 | (unsigned int)runtime->period_size, | ||
379 | (unsigned int)runtime->buffer_size, | ||
380 | (unsigned long)old_hw_ptr, | ||
381 | (unsigned long)runtime->hw_ptr_base, | ||
382 | (unsigned long)runtime->hw_ptr_interrupt); | ||
383 | } | ||
384 | |||
385 | hw_base = runtime->hw_ptr_base; | ||
386 | new_hw_ptr = hw_base + pos; | ||
387 | |||
388 | delta = new_hw_ptr - old_hw_ptr; | ||
389 | jdelta = jiffies - runtime->hw_ptr_jiffies; | ||
390 | if (delta < 0) { | ||
391 | delta += runtime->buffer_size; | ||
392 | if (delta < 0) { | ||
393 | hw_ptr_error(substream, | ||
394 | "Unexpected hw_pointer value [2] " | ||
395 | "(stream=%i, pos=%ld, old_ptr=%ld, jdelta=%li)\n", | ||
396 | substream->stream, (long)pos, | ||
397 | (long)old_hw_ptr, jdelta); | ||
398 | return 0; | ||
399 | } | ||
400 | hw_base += runtime->buffer_size; | ||
401 | if (hw_base >= runtime->boundary) | ||
402 | hw_base = 0; | ||
403 | new_hw_ptr = hw_base + pos; | ||
404 | } | ||
405 | /* Do jiffies check only in xrun_debug mode */ | ||
406 | if (!xrun_debug(substream, 4)) | ||
407 | goto no_jiffies_check; | ||
408 | if (delta < runtime->delay) | ||
409 | goto no_jiffies_check; | ||
410 | delta -= runtime->delay; | ||
411 | if (((delta * HZ) / runtime->rate) > jdelta + HZ/100) { | ||
412 | hw_ptr_error(substream, | ||
413 | "hw_ptr skipping! " | ||
414 | "(pos=%ld, delta=%ld, period=%ld, jdelta=%lu/%lu)\n", | ||
415 | (long)pos, (long)delta, | ||
416 | (long)runtime->period_size, jdelta, | ||
417 | ((delta * HZ) / runtime->rate)); | ||
418 | return 0; | ||
419 | } | ||
420 | no_jiffies_check: | ||
421 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && | ||
422 | runtime->silence_size > 0) | ||
423 | snd_pcm_playback_silence(substream, new_hw_ptr); | ||
424 | |||
425 | if (runtime->status->hw_ptr == new_hw_ptr) | ||
426 | return 0; | ||
427 | |||
428 | runtime->hw_ptr_base = hw_base; | ||
429 | runtime->status->hw_ptr = new_hw_ptr; | ||
430 | runtime->hw_ptr_jiffies = jiffies; | ||
431 | if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) | ||
432 | snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp); | ||
433 | |||
434 | return snd_pcm_update_hw_ptr_post(substream, runtime); | ||
435 | } | 456 | } |
436 | 457 | ||
437 | /** | 458 | /** |
@@ -745,10 +766,13 @@ int snd_interval_ratnum(struct snd_interval *i, | |||
745 | unsigned int rats_count, struct snd_ratnum *rats, | 766 | unsigned int rats_count, struct snd_ratnum *rats, |
746 | unsigned int *nump, unsigned int *denp) | 767 | unsigned int *nump, unsigned int *denp) |
747 | { | 768 | { |
748 | unsigned int best_num, best_diff, best_den; | 769 | unsigned int best_num, best_den; |
770 | int best_diff; | ||
749 | unsigned int k; | 771 | unsigned int k; |
750 | struct snd_interval t; | 772 | struct snd_interval t; |
751 | int err; | 773 | int err; |
774 | unsigned int result_num, result_den; | ||
775 | int result_diff; | ||
752 | 776 | ||
753 | best_num = best_den = best_diff = 0; | 777 | best_num = best_den = best_diff = 0; |
754 | for (k = 0; k < rats_count; ++k) { | 778 | for (k = 0; k < rats_count; ++k) { |
@@ -770,6 +794,8 @@ int snd_interval_ratnum(struct snd_interval *i, | |||
770 | den -= r; | 794 | den -= r; |
771 | } | 795 | } |
772 | diff = num - q * den; | 796 | diff = num - q * den; |
797 | if (diff < 0) | ||
798 | diff = -diff; | ||
773 | if (best_num == 0 || | 799 | if (best_num == 0 || |
774 | diff * best_den < best_diff * den) { | 800 | diff * best_den < best_diff * den) { |
775 | best_diff = diff; | 801 | best_diff = diff; |
@@ -784,6 +810,9 @@ int snd_interval_ratnum(struct snd_interval *i, | |||
784 | t.min = div_down(best_num, best_den); | 810 | t.min = div_down(best_num, best_den); |
785 | t.openmin = !!(best_num % best_den); | 811 | t.openmin = !!(best_num % best_den); |
786 | 812 | ||
813 | result_num = best_num; | ||
814 | result_diff = best_diff; | ||
815 | result_den = best_den; | ||
787 | best_num = best_den = best_diff = 0; | 816 | best_num = best_den = best_diff = 0; |
788 | for (k = 0; k < rats_count; ++k) { | 817 | for (k = 0; k < rats_count; ++k) { |
789 | unsigned int num = rats[k].num; | 818 | unsigned int num = rats[k].num; |
@@ -806,6 +835,8 @@ int snd_interval_ratnum(struct snd_interval *i, | |||
806 | den += rats[k].den_step - r; | 835 | den += rats[k].den_step - r; |
807 | } | 836 | } |
808 | diff = q * den - num; | 837 | diff = q * den - num; |
838 | if (diff < 0) | ||
839 | diff = -diff; | ||
809 | if (best_num == 0 || | 840 | if (best_num == 0 || |
810 | diff * best_den < best_diff * den) { | 841 | diff * best_den < best_diff * den) { |
811 | best_diff = diff; | 842 | best_diff = diff; |
@@ -825,10 +856,14 @@ int snd_interval_ratnum(struct snd_interval *i, | |||
825 | return err; | 856 | return err; |
826 | 857 | ||
827 | if (snd_interval_single(i)) { | 858 | if (snd_interval_single(i)) { |
859 | if (best_diff * result_den < result_diff * best_den) { | ||
860 | result_num = best_num; | ||
861 | result_den = best_den; | ||
862 | } | ||
828 | if (nump) | 863 | if (nump) |
829 | *nump = best_num; | 864 | *nump = result_num; |
830 | if (denp) | 865 | if (denp) |
831 | *denp = best_den; | 866 | *denp = result_den; |
832 | } | 867 | } |
833 | return err; | 868 | return err; |
834 | } | 869 | } |
@@ -1643,7 +1678,7 @@ void snd_pcm_period_elapsed(struct snd_pcm_substream *substream) | |||
1643 | 1678 | ||
1644 | snd_pcm_stream_lock_irqsave(substream, flags); | 1679 | snd_pcm_stream_lock_irqsave(substream, flags); |
1645 | if (!snd_pcm_running(substream) || | 1680 | if (!snd_pcm_running(substream) || |
1646 | snd_pcm_update_hw_ptr_interrupt(substream) < 0) | 1681 | snd_pcm_update_hw_ptr0(substream, 1) < 0) |
1647 | goto _end; | 1682 | goto _end; |
1648 | 1683 | ||
1649 | if (substream->timer_running) | 1684 | if (substream->timer_running) |
@@ -1674,7 +1709,7 @@ static int wait_for_avail_min(struct snd_pcm_substream *substream, | |||
1674 | long tout; | 1709 | long tout; |
1675 | 1710 | ||
1676 | init_waitqueue_entry(&wait, current); | 1711 | init_waitqueue_entry(&wait, current); |
1677 | add_wait_queue(&runtime->sleep, &wait); | 1712 | add_wait_queue(&runtime->tsleep, &wait); |
1678 | for (;;) { | 1713 | for (;;) { |
1679 | if (signal_pending(current)) { | 1714 | if (signal_pending(current)) { |
1680 | err = -ERESTARTSYS; | 1715 | err = -ERESTARTSYS; |
@@ -1717,7 +1752,7 @@ static int wait_for_avail_min(struct snd_pcm_substream *substream, | |||
1717 | break; | 1752 | break; |
1718 | } | 1753 | } |
1719 | _endloop: | 1754 | _endloop: |
1720 | remove_wait_queue(&runtime->sleep, &wait); | 1755 | remove_wait_queue(&runtime->tsleep, &wait); |
1721 | *availp = avail; | 1756 | *availp = avail; |
1722 | return err; | 1757 | return err; |
1723 | } | 1758 | } |
@@ -1776,6 +1811,7 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream, | |||
1776 | goto _end_unlock; | 1811 | goto _end_unlock; |
1777 | } | 1812 | } |
1778 | 1813 | ||
1814 | runtime->twake = 1; | ||
1779 | while (size > 0) { | 1815 | while (size > 0) { |
1780 | snd_pcm_uframes_t frames, appl_ptr, appl_ofs; | 1816 | snd_pcm_uframes_t frames, appl_ptr, appl_ofs; |
1781 | snd_pcm_uframes_t avail; | 1817 | snd_pcm_uframes_t avail; |
@@ -1797,15 +1833,17 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream, | |||
1797 | if (frames > cont) | 1833 | if (frames > cont) |
1798 | frames = cont; | 1834 | frames = cont; |
1799 | if (snd_BUG_ON(!frames)) { | 1835 | if (snd_BUG_ON(!frames)) { |
1836 | runtime->twake = 0; | ||
1800 | snd_pcm_stream_unlock_irq(substream); | 1837 | snd_pcm_stream_unlock_irq(substream); |
1801 | return -EINVAL; | 1838 | return -EINVAL; |
1802 | } | 1839 | } |
1803 | appl_ptr = runtime->control->appl_ptr; | 1840 | appl_ptr = runtime->control->appl_ptr; |
1804 | appl_ofs = appl_ptr % runtime->buffer_size; | 1841 | appl_ofs = appl_ptr % runtime->buffer_size; |
1805 | snd_pcm_stream_unlock_irq(substream); | 1842 | snd_pcm_stream_unlock_irq(substream); |
1806 | if ((err = transfer(substream, appl_ofs, data, offset, frames)) < 0) | 1843 | err = transfer(substream, appl_ofs, data, offset, frames); |
1807 | goto _end; | ||
1808 | snd_pcm_stream_lock_irq(substream); | 1844 | snd_pcm_stream_lock_irq(substream); |
1845 | if (err < 0) | ||
1846 | goto _end_unlock; | ||
1809 | switch (runtime->status->state) { | 1847 | switch (runtime->status->state) { |
1810 | case SNDRV_PCM_STATE_XRUN: | 1848 | case SNDRV_PCM_STATE_XRUN: |
1811 | err = -EPIPE; | 1849 | err = -EPIPE; |
@@ -1834,8 +1872,10 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream, | |||
1834 | } | 1872 | } |
1835 | } | 1873 | } |
1836 | _end_unlock: | 1874 | _end_unlock: |
1875 | runtime->twake = 0; | ||
1876 | if (xfer > 0 && err >= 0) | ||
1877 | snd_pcm_update_state(substream, runtime); | ||
1837 | snd_pcm_stream_unlock_irq(substream); | 1878 | snd_pcm_stream_unlock_irq(substream); |
1838 | _end: | ||
1839 | return xfer > 0 ? (snd_pcm_sframes_t)xfer : err; | 1879 | return xfer > 0 ? (snd_pcm_sframes_t)xfer : err; |
1840 | } | 1880 | } |
1841 | 1881 | ||
@@ -1993,6 +2033,7 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream, | |||
1993 | goto _end_unlock; | 2033 | goto _end_unlock; |
1994 | } | 2034 | } |
1995 | 2035 | ||
2036 | runtime->twake = 1; | ||
1996 | while (size > 0) { | 2037 | while (size > 0) { |
1997 | snd_pcm_uframes_t frames, appl_ptr, appl_ofs; | 2038 | snd_pcm_uframes_t frames, appl_ptr, appl_ofs; |
1998 | snd_pcm_uframes_t avail; | 2039 | snd_pcm_uframes_t avail; |
@@ -2021,15 +2062,17 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream, | |||
2021 | if (frames > cont) | 2062 | if (frames > cont) |
2022 | frames = cont; | 2063 | frames = cont; |
2023 | if (snd_BUG_ON(!frames)) { | 2064 | if (snd_BUG_ON(!frames)) { |
2065 | runtime->twake = 0; | ||
2024 | snd_pcm_stream_unlock_irq(substream); | 2066 | snd_pcm_stream_unlock_irq(substream); |
2025 | return -EINVAL; | 2067 | return -EINVAL; |
2026 | } | 2068 | } |
2027 | appl_ptr = runtime->control->appl_ptr; | 2069 | appl_ptr = runtime->control->appl_ptr; |
2028 | appl_ofs = appl_ptr % runtime->buffer_size; | 2070 | appl_ofs = appl_ptr % runtime->buffer_size; |
2029 | snd_pcm_stream_unlock_irq(substream); | 2071 | snd_pcm_stream_unlock_irq(substream); |
2030 | if ((err = transfer(substream, appl_ofs, data, offset, frames)) < 0) | 2072 | err = transfer(substream, appl_ofs, data, offset, frames); |
2031 | goto _end; | ||
2032 | snd_pcm_stream_lock_irq(substream); | 2073 | snd_pcm_stream_lock_irq(substream); |
2074 | if (err < 0) | ||
2075 | goto _end_unlock; | ||
2033 | switch (runtime->status->state) { | 2076 | switch (runtime->status->state) { |
2034 | case SNDRV_PCM_STATE_XRUN: | 2077 | case SNDRV_PCM_STATE_XRUN: |
2035 | err = -EPIPE; | 2078 | err = -EPIPE; |
@@ -2052,8 +2095,10 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream, | |||
2052 | xfer += frames; | 2095 | xfer += frames; |
2053 | } | 2096 | } |
2054 | _end_unlock: | 2097 | _end_unlock: |
2098 | runtime->twake = 0; | ||
2099 | if (xfer > 0 && err >= 0) | ||
2100 | snd_pcm_update_state(substream, runtime); | ||
2055 | snd_pcm_stream_unlock_irq(substream); | 2101 | snd_pcm_stream_unlock_irq(substream); |
2056 | _end: | ||
2057 | return xfer > 0 ? (snd_pcm_sframes_t)xfer : err; | 2102 | return xfer > 0 ? (snd_pcm_sframes_t)xfer : err; |
2058 | } | 2103 | } |
2059 | 2104 | ||
diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c index caa7796bc2f5..d6d49d6651f9 100644 --- a/sound/core/pcm_memory.c +++ b/sound/core/pcm_memory.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/time.h> | 23 | #include <linux/time.h> |
24 | #include <linux/init.h> | 24 | #include <linux/init.h> |
25 | #include <linux/moduleparam.h> | 25 | #include <linux/moduleparam.h> |
26 | #include <linux/vmalloc.h> | ||
26 | #include <sound/core.h> | 27 | #include <sound/core.h> |
27 | #include <sound/pcm.h> | 28 | #include <sound/pcm.h> |
28 | #include <sound/info.h> | 29 | #include <sound/info.h> |
@@ -434,3 +435,57 @@ int snd_pcm_lib_free_pages(struct snd_pcm_substream *substream) | |||
434 | } | 435 | } |
435 | 436 | ||
436 | EXPORT_SYMBOL(snd_pcm_lib_free_pages); | 437 | EXPORT_SYMBOL(snd_pcm_lib_free_pages); |
438 | |||
439 | int _snd_pcm_lib_alloc_vmalloc_buffer(struct snd_pcm_substream *substream, | ||
440 | size_t size, gfp_t gfp_flags) | ||
441 | { | ||
442 | struct snd_pcm_runtime *runtime; | ||
443 | |||
444 | if (PCM_RUNTIME_CHECK(substream)) | ||
445 | return -EINVAL; | ||
446 | runtime = substream->runtime; | ||
447 | if (runtime->dma_area) { | ||
448 | if (runtime->dma_bytes >= size) | ||
449 | return 0; /* already large enough */ | ||
450 | vfree(runtime->dma_area); | ||
451 | } | ||
452 | runtime->dma_area = __vmalloc(size, gfp_flags, PAGE_KERNEL); | ||
453 | if (!runtime->dma_area) | ||
454 | return -ENOMEM; | ||
455 | runtime->dma_bytes = size; | ||
456 | return 1; | ||
457 | } | ||
458 | EXPORT_SYMBOL(_snd_pcm_lib_alloc_vmalloc_buffer); | ||
459 | |||
460 | /** | ||
461 | * snd_pcm_lib_free_vmalloc_buffer - free vmalloc buffer | ||
462 | * @substream: the substream with a buffer allocated by | ||
463 | * snd_pcm_lib_alloc_vmalloc_buffer() | ||
464 | */ | ||
465 | int snd_pcm_lib_free_vmalloc_buffer(struct snd_pcm_substream *substream) | ||
466 | { | ||
467 | struct snd_pcm_runtime *runtime; | ||
468 | |||
469 | if (PCM_RUNTIME_CHECK(substream)) | ||
470 | return -EINVAL; | ||
471 | runtime = substream->runtime; | ||
472 | vfree(runtime->dma_area); | ||
473 | runtime->dma_area = NULL; | ||
474 | return 0; | ||
475 | } | ||
476 | EXPORT_SYMBOL(snd_pcm_lib_free_vmalloc_buffer); | ||
477 | |||
478 | /** | ||
479 | * snd_pcm_lib_get_vmalloc_page - map vmalloc buffer offset to page struct | ||
480 | * @substream: the substream with a buffer allocated by | ||
481 | * snd_pcm_lib_alloc_vmalloc_buffer() | ||
482 | * @offset: offset in the buffer | ||
483 | * | ||
484 | * This function is to be used as the page callback in the PCM ops. | ||
485 | */ | ||
486 | struct page *snd_pcm_lib_get_vmalloc_page(struct snd_pcm_substream *substream, | ||
487 | unsigned long offset) | ||
488 | { | ||
489 | return vmalloc_to_page(substream->runtime->dma_area + offset); | ||
490 | } | ||
491 | EXPORT_SYMBOL(snd_pcm_lib_get_vmalloc_page); | ||
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 25b0641e6b8c..872887624030 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/pm_qos_params.h> | 27 | #include <linux/pm_qos_params.h> |
28 | #include <linux/uio.h> | 28 | #include <linux/uio.h> |
29 | #include <linux/dma-mapping.h> | 29 | #include <linux/dma-mapping.h> |
30 | #include <linux/math64.h> | ||
30 | #include <sound/core.h> | 31 | #include <sound/core.h> |
31 | #include <sound/control.h> | 32 | #include <sound/control.h> |
32 | #include <sound/info.h> | 33 | #include <sound/info.h> |
@@ -315,10 +316,10 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream, | |||
315 | if (!params->info) | 316 | if (!params->info) |
316 | params->info = hw->info & ~SNDRV_PCM_INFO_FIFO_IN_FRAMES; | 317 | params->info = hw->info & ~SNDRV_PCM_INFO_FIFO_IN_FRAMES; |
317 | if (!params->fifo_size) { | 318 | if (!params->fifo_size) { |
318 | if (snd_mask_min(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT]) == | 319 | m = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); |
319 | snd_mask_max(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT]) && | 320 | i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); |
320 | snd_mask_min(¶ms->masks[SNDRV_PCM_HW_PARAM_CHANNELS]) == | 321 | if (snd_mask_min(m) == snd_mask_max(m) && |
321 | snd_mask_max(¶ms->masks[SNDRV_PCM_HW_PARAM_CHANNELS])) { | 322 | snd_interval_min(i) == snd_interval_max(i)) { |
322 | changed = substream->ops->ioctl(substream, | 323 | changed = substream->ops->ioctl(substream, |
323 | SNDRV_PCM_IOCTL1_FIFO_SIZE, params); | 324 | SNDRV_PCM_IOCTL1_FIFO_SIZE, params); |
324 | if (changed < 0) | 325 | if (changed < 0) |
@@ -366,6 +367,38 @@ static int period_to_usecs(struct snd_pcm_runtime *runtime) | |||
366 | return usecs; | 367 | return usecs; |
367 | } | 368 | } |
368 | 369 | ||
370 | static int calc_boundary(struct snd_pcm_runtime *runtime) | ||
371 | { | ||
372 | u_int64_t boundary; | ||
373 | |||
374 | boundary = (u_int64_t)runtime->buffer_size * | ||
375 | (u_int64_t)runtime->period_size; | ||
376 | #if BITS_PER_LONG < 64 | ||
377 | /* try to find lowest common multiple for buffer and period */ | ||
378 | if (boundary > LONG_MAX - runtime->buffer_size) { | ||
379 | u_int32_t remainder = -1; | ||
380 | u_int32_t divident = runtime->buffer_size; | ||
381 | u_int32_t divisor = runtime->period_size; | ||
382 | while (remainder) { | ||
383 | remainder = divident % divisor; | ||
384 | if (remainder) { | ||
385 | divident = divisor; | ||
386 | divisor = remainder; | ||
387 | } | ||
388 | } | ||
389 | boundary = div_u64(boundary, divisor); | ||
390 | if (boundary > LONG_MAX - runtime->buffer_size) | ||
391 | return -ERANGE; | ||
392 | } | ||
393 | #endif | ||
394 | if (boundary == 0) | ||
395 | return -ERANGE; | ||
396 | runtime->boundary = boundary; | ||
397 | while (runtime->boundary * 2 <= LONG_MAX - runtime->buffer_size) | ||
398 | runtime->boundary *= 2; | ||
399 | return 0; | ||
400 | } | ||
401 | |||
369 | static int snd_pcm_hw_params(struct snd_pcm_substream *substream, | 402 | static int snd_pcm_hw_params(struct snd_pcm_substream *substream, |
370 | struct snd_pcm_hw_params *params) | 403 | struct snd_pcm_hw_params *params) |
371 | { | 404 | { |
@@ -441,9 +474,9 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream, | |||
441 | runtime->stop_threshold = runtime->buffer_size; | 474 | runtime->stop_threshold = runtime->buffer_size; |
442 | runtime->silence_threshold = 0; | 475 | runtime->silence_threshold = 0; |
443 | runtime->silence_size = 0; | 476 | runtime->silence_size = 0; |
444 | runtime->boundary = runtime->buffer_size; | 477 | err = calc_boundary(runtime); |
445 | while (runtime->boundary * 2 <= LONG_MAX - runtime->buffer_size) | 478 | if (err < 0) |
446 | runtime->boundary *= 2; | 479 | goto _error; |
447 | 480 | ||
448 | snd_pcm_timer_resolution_change(substream); | 481 | snd_pcm_timer_resolution_change(substream); |
449 | runtime->status->state = SNDRV_PCM_STATE_SETUP; | 482 | runtime->status->state = SNDRV_PCM_STATE_SETUP; |
@@ -516,6 +549,7 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream, | |||
516 | struct snd_pcm_sw_params *params) | 549 | struct snd_pcm_sw_params *params) |
517 | { | 550 | { |
518 | struct snd_pcm_runtime *runtime; | 551 | struct snd_pcm_runtime *runtime; |
552 | int err; | ||
519 | 553 | ||
520 | if (PCM_RUNTIME_CHECK(substream)) | 554 | if (PCM_RUNTIME_CHECK(substream)) |
521 | return -ENXIO; | 555 | return -ENXIO; |
@@ -540,6 +574,7 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream, | |||
540 | if (params->silence_threshold > runtime->buffer_size) | 574 | if (params->silence_threshold > runtime->buffer_size) |
541 | return -EINVAL; | 575 | return -EINVAL; |
542 | } | 576 | } |
577 | err = 0; | ||
543 | snd_pcm_stream_lock_irq(substream); | 578 | snd_pcm_stream_lock_irq(substream); |
544 | runtime->tstamp_mode = params->tstamp_mode; | 579 | runtime->tstamp_mode = params->tstamp_mode; |
545 | runtime->period_step = params->period_step; | 580 | runtime->period_step = params->period_step; |
@@ -553,10 +588,10 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream, | |||
553 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && | 588 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && |
554 | runtime->silence_size > 0) | 589 | runtime->silence_size > 0) |
555 | snd_pcm_playback_silence(substream, ULONG_MAX); | 590 | snd_pcm_playback_silence(substream, ULONG_MAX); |
556 | wake_up(&runtime->sleep); | 591 | err = snd_pcm_update_state(substream, runtime); |
557 | } | 592 | } |
558 | snd_pcm_stream_unlock_irq(substream); | 593 | snd_pcm_stream_unlock_irq(substream); |
559 | return 0; | 594 | return err; |
560 | } | 595 | } |
561 | 596 | ||
562 | static int snd_pcm_sw_params_user(struct snd_pcm_substream *substream, | 597 | static int snd_pcm_sw_params_user(struct snd_pcm_substream *substream, |
@@ -917,6 +952,7 @@ static void snd_pcm_post_stop(struct snd_pcm_substream *substream, int state) | |||
917 | runtime->status->state = state; | 952 | runtime->status->state = state; |
918 | } | 953 | } |
919 | wake_up(&runtime->sleep); | 954 | wake_up(&runtime->sleep); |
955 | wake_up(&runtime->tsleep); | ||
920 | } | 956 | } |
921 | 957 | ||
922 | static struct action_ops snd_pcm_action_stop = { | 958 | static struct action_ops snd_pcm_action_stop = { |
@@ -1002,6 +1038,7 @@ static void snd_pcm_post_pause(struct snd_pcm_substream *substream, int push) | |||
1002 | SNDRV_TIMER_EVENT_MPAUSE, | 1038 | SNDRV_TIMER_EVENT_MPAUSE, |
1003 | &runtime->trigger_tstamp); | 1039 | &runtime->trigger_tstamp); |
1004 | wake_up(&runtime->sleep); | 1040 | wake_up(&runtime->sleep); |
1041 | wake_up(&runtime->tsleep); | ||
1005 | } else { | 1042 | } else { |
1006 | runtime->status->state = SNDRV_PCM_STATE_RUNNING; | 1043 | runtime->status->state = SNDRV_PCM_STATE_RUNNING; |
1007 | if (substream->timer) | 1044 | if (substream->timer) |
@@ -1059,6 +1096,7 @@ static void snd_pcm_post_suspend(struct snd_pcm_substream *substream, int state) | |||
1059 | runtime->status->suspended_state = runtime->status->state; | 1096 | runtime->status->suspended_state = runtime->status->state; |
1060 | runtime->status->state = SNDRV_PCM_STATE_SUSPENDED; | 1097 | runtime->status->state = SNDRV_PCM_STATE_SUSPENDED; |
1061 | wake_up(&runtime->sleep); | 1098 | wake_up(&runtime->sleep); |
1099 | wake_up(&runtime->tsleep); | ||
1062 | } | 1100 | } |
1063 | 1101 | ||
1064 | static struct action_ops snd_pcm_action_suspend = { | 1102 | static struct action_ops snd_pcm_action_suspend = { |
@@ -3162,9 +3200,7 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream, | |||
3162 | long size; | 3200 | long size; |
3163 | unsigned long offset; | 3201 | unsigned long offset; |
3164 | 3202 | ||
3165 | #ifdef pgprot_noncached | ||
3166 | area->vm_page_prot = pgprot_noncached(area->vm_page_prot); | 3203 | area->vm_page_prot = pgprot_noncached(area->vm_page_prot); |
3167 | #endif | ||
3168 | area->vm_flags |= VM_IO; | 3204 | area->vm_flags |= VM_IO; |
3169 | size = area->vm_end - area->vm_start; | 3205 | size = area->vm_end - area->vm_start; |
3170 | offset = area->vm_pgoff << PAGE_SHIFT; | 3206 | offset = area->vm_pgoff << PAGE_SHIFT; |
@@ -3178,6 +3214,15 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream, | |||
3178 | EXPORT_SYMBOL(snd_pcm_lib_mmap_iomem); | 3214 | EXPORT_SYMBOL(snd_pcm_lib_mmap_iomem); |
3179 | #endif /* SNDRV_PCM_INFO_MMAP */ | 3215 | #endif /* SNDRV_PCM_INFO_MMAP */ |
3180 | 3216 | ||
3217 | /* mmap callback with pgprot_noncached */ | ||
3218 | int snd_pcm_lib_mmap_noncached(struct snd_pcm_substream *substream, | ||
3219 | struct vm_area_struct *area) | ||
3220 | { | ||
3221 | area->vm_page_prot = pgprot_noncached(area->vm_page_prot); | ||
3222 | return snd_pcm_default_mmap(substream, area); | ||
3223 | } | ||
3224 | EXPORT_SYMBOL(snd_pcm_lib_mmap_noncached); | ||
3225 | |||
3181 | /* | 3226 | /* |
3182 | * mmap DMA buffer | 3227 | * mmap DMA buffer |
3183 | */ | 3228 | */ |
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index 8ca2be339f3b..48eca9ff9ee7 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c | |||
@@ -2190,7 +2190,7 @@ static int snd_seq_do_ioctl(struct snd_seq_client *client, unsigned int cmd, | |||
2190 | if (p->cmd == cmd) | 2190 | if (p->cmd == cmd) |
2191 | return p->func(client, arg); | 2191 | return p->func(client, arg); |
2192 | } | 2192 | } |
2193 | snd_printd("seq unknown ioctl() 0x%x (type='%c', number=0x%2x)\n", | 2193 | snd_printd("seq unknown ioctl() 0x%x (type='%c', number=0x%02x)\n", |
2194 | cmd, _IOC_TYPE(cmd), _IOC_NR(cmd)); | 2194 | cmd, _IOC_TYPE(cmd), _IOC_NR(cmd)); |
2195 | return -ENOTTY; | 2195 | return -ENOTTY; |
2196 | } | 2196 | } |
diff --git a/sound/core/seq/seq_timer.c b/sound/core/seq/seq_timer.c index f745c317d6af..160b1bd0cd62 100644 --- a/sound/core/seq/seq_timer.c +++ b/sound/core/seq/seq_timer.c | |||
@@ -33,22 +33,21 @@ | |||
33 | 33 | ||
34 | #define SKEW_BASE 0x10000 /* 16bit shift */ | 34 | #define SKEW_BASE 0x10000 /* 16bit shift */ |
35 | 35 | ||
36 | static void snd_seq_timer_set_tick_resolution(struct snd_seq_timer_tick *tick, | 36 | static void snd_seq_timer_set_tick_resolution(struct snd_seq_timer *tmr) |
37 | int tempo, int ppq) | ||
38 | { | 37 | { |
39 | if (tempo < 1000000) | 38 | if (tmr->tempo < 1000000) |
40 | tick->resolution = (tempo * 1000) / ppq; | 39 | tmr->tick.resolution = (tmr->tempo * 1000) / tmr->ppq; |
41 | else { | 40 | else { |
42 | /* might overflow.. */ | 41 | /* might overflow.. */ |
43 | unsigned int s; | 42 | unsigned int s; |
44 | s = tempo % ppq; | 43 | s = tmr->tempo % tmr->ppq; |
45 | s = (s * 1000) / ppq; | 44 | s = (s * 1000) / tmr->ppq; |
46 | tick->resolution = (tempo / ppq) * 1000; | 45 | tmr->tick.resolution = (tmr->tempo / tmr->ppq) * 1000; |
47 | tick->resolution += s; | 46 | tmr->tick.resolution += s; |
48 | } | 47 | } |
49 | if (tick->resolution <= 0) | 48 | if (tmr->tick.resolution <= 0) |
50 | tick->resolution = 1; | 49 | tmr->tick.resolution = 1; |
51 | snd_seq_timer_update_tick(tick, 0); | 50 | snd_seq_timer_update_tick(&tmr->tick, 0); |
52 | } | 51 | } |
53 | 52 | ||
54 | /* create new timer (constructor) */ | 53 | /* create new timer (constructor) */ |
@@ -96,7 +95,7 @@ void snd_seq_timer_defaults(struct snd_seq_timer * tmr) | |||
96 | /* setup defaults */ | 95 | /* setup defaults */ |
97 | tmr->ppq = 96; /* 96 PPQ */ | 96 | tmr->ppq = 96; /* 96 PPQ */ |
98 | tmr->tempo = 500000; /* 120 BPM */ | 97 | tmr->tempo = 500000; /* 120 BPM */ |
99 | snd_seq_timer_set_tick_resolution(&tmr->tick, tmr->tempo, tmr->ppq); | 98 | snd_seq_timer_set_tick_resolution(tmr); |
100 | tmr->running = 0; | 99 | tmr->running = 0; |
101 | 100 | ||
102 | tmr->type = SNDRV_SEQ_TIMER_ALSA; | 101 | tmr->type = SNDRV_SEQ_TIMER_ALSA; |
@@ -180,7 +179,7 @@ int snd_seq_timer_set_tempo(struct snd_seq_timer * tmr, int tempo) | |||
180 | spin_lock_irqsave(&tmr->lock, flags); | 179 | spin_lock_irqsave(&tmr->lock, flags); |
181 | if ((unsigned int)tempo != tmr->tempo) { | 180 | if ((unsigned int)tempo != tmr->tempo) { |
182 | tmr->tempo = tempo; | 181 | tmr->tempo = tempo; |
183 | snd_seq_timer_set_tick_resolution(&tmr->tick, tmr->tempo, tmr->ppq); | 182 | snd_seq_timer_set_tick_resolution(tmr); |
184 | } | 183 | } |
185 | spin_unlock_irqrestore(&tmr->lock, flags); | 184 | spin_unlock_irqrestore(&tmr->lock, flags); |
186 | return 0; | 185 | return 0; |
@@ -205,7 +204,7 @@ int snd_seq_timer_set_ppq(struct snd_seq_timer * tmr, int ppq) | |||
205 | } | 204 | } |
206 | 205 | ||
207 | tmr->ppq = ppq; | 206 | tmr->ppq = ppq; |
208 | snd_seq_timer_set_tick_resolution(&tmr->tick, tmr->tempo, tmr->ppq); | 207 | snd_seq_timer_set_tick_resolution(tmr); |
209 | spin_unlock_irqrestore(&tmr->lock, flags); | 208 | spin_unlock_irqrestore(&tmr->lock, flags); |
210 | return 0; | 209 | return 0; |
211 | } | 210 | } |
diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c index 252e04ce602f..7f41990ed68b 100644 --- a/sound/drivers/dummy.c +++ b/sound/drivers/dummy.c | |||
@@ -45,109 +45,23 @@ MODULE_SUPPORTED_DEVICE("{{ALSA,Dummy soundcard}}"); | |||
45 | #define MAX_PCM_SUBSTREAMS 128 | 45 | #define MAX_PCM_SUBSTREAMS 128 |
46 | #define MAX_MIDI_DEVICES 2 | 46 | #define MAX_MIDI_DEVICES 2 |
47 | 47 | ||
48 | #if 0 /* emu10k1 emulation */ | ||
49 | #define MAX_BUFFER_SIZE (128 * 1024) | ||
50 | static int emu10k1_playback_constraints(struct snd_pcm_runtime *runtime) | ||
51 | { | ||
52 | int err; | ||
53 | err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); | ||
54 | if (err < 0) | ||
55 | return err; | ||
56 | err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 256, UINT_MAX); | ||
57 | if (err < 0) | ||
58 | return err; | ||
59 | return 0; | ||
60 | } | ||
61 | #define add_playback_constraints emu10k1_playback_constraints | ||
62 | #endif | ||
63 | |||
64 | #if 0 /* RME9652 emulation */ | ||
65 | #define MAX_BUFFER_SIZE (26 * 64 * 1024) | ||
66 | #define USE_FORMATS SNDRV_PCM_FMTBIT_S32_LE | ||
67 | #define USE_CHANNELS_MIN 26 | ||
68 | #define USE_CHANNELS_MAX 26 | ||
69 | #define USE_PERIODS_MIN 2 | ||
70 | #define USE_PERIODS_MAX 2 | ||
71 | #endif | ||
72 | |||
73 | #if 0 /* ICE1712 emulation */ | ||
74 | #define MAX_BUFFER_SIZE (256 * 1024) | ||
75 | #define USE_FORMATS SNDRV_PCM_FMTBIT_S32_LE | ||
76 | #define USE_CHANNELS_MIN 10 | ||
77 | #define USE_CHANNELS_MAX 10 | ||
78 | #define USE_PERIODS_MIN 1 | ||
79 | #define USE_PERIODS_MAX 1024 | ||
80 | #endif | ||
81 | |||
82 | #if 0 /* UDA1341 emulation */ | ||
83 | #define MAX_BUFFER_SIZE (16380) | ||
84 | #define USE_FORMATS SNDRV_PCM_FMTBIT_S16_LE | ||
85 | #define USE_CHANNELS_MIN 2 | ||
86 | #define USE_CHANNELS_MAX 2 | ||
87 | #define USE_PERIODS_MIN 2 | ||
88 | #define USE_PERIODS_MAX 255 | ||
89 | #endif | ||
90 | |||
91 | #if 0 /* simple AC97 bridge (intel8x0) with 48kHz AC97 only codec */ | ||
92 | #define USE_FORMATS SNDRV_PCM_FMTBIT_S16_LE | ||
93 | #define USE_CHANNELS_MIN 2 | ||
94 | #define USE_CHANNELS_MAX 2 | ||
95 | #define USE_RATE SNDRV_PCM_RATE_48000 | ||
96 | #define USE_RATE_MIN 48000 | ||
97 | #define USE_RATE_MAX 48000 | ||
98 | #endif | ||
99 | |||
100 | #if 0 /* CA0106 */ | ||
101 | #define USE_FORMATS SNDRV_PCM_FMTBIT_S16_LE | ||
102 | #define USE_CHANNELS_MIN 2 | ||
103 | #define USE_CHANNELS_MAX 2 | ||
104 | #define USE_RATE (SNDRV_PCM_RATE_48000|SNDRV_PCM_RATE_96000|SNDRV_PCM_RATE_192000) | ||
105 | #define USE_RATE_MIN 48000 | ||
106 | #define USE_RATE_MAX 192000 | ||
107 | #define MAX_BUFFER_SIZE ((65536-64)*8) | ||
108 | #define MAX_PERIOD_SIZE (65536-64) | ||
109 | #define USE_PERIODS_MIN 2 | ||
110 | #define USE_PERIODS_MAX 8 | ||
111 | #endif | ||
112 | |||
113 | |||
114 | /* defaults */ | 48 | /* defaults */ |
115 | #ifndef MAX_BUFFER_SIZE | ||
116 | #define MAX_BUFFER_SIZE (64*1024) | 49 | #define MAX_BUFFER_SIZE (64*1024) |
117 | #endif | 50 | #define MIN_PERIOD_SIZE 64 |
118 | #ifndef MAX_PERIOD_SIZE | ||
119 | #define MAX_PERIOD_SIZE MAX_BUFFER_SIZE | 51 | #define MAX_PERIOD_SIZE MAX_BUFFER_SIZE |
120 | #endif | ||
121 | #ifndef USE_FORMATS | ||
122 | #define USE_FORMATS (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE) | 52 | #define USE_FORMATS (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE) |
123 | #endif | ||
124 | #ifndef USE_RATE | ||
125 | #define USE_RATE SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000 | 53 | #define USE_RATE SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000 |
126 | #define USE_RATE_MIN 5500 | 54 | #define USE_RATE_MIN 5500 |
127 | #define USE_RATE_MAX 48000 | 55 | #define USE_RATE_MAX 48000 |
128 | #endif | ||
129 | #ifndef USE_CHANNELS_MIN | ||
130 | #define USE_CHANNELS_MIN 1 | 56 | #define USE_CHANNELS_MIN 1 |
131 | #endif | ||
132 | #ifndef USE_CHANNELS_MAX | ||
133 | #define USE_CHANNELS_MAX 2 | 57 | #define USE_CHANNELS_MAX 2 |
134 | #endif | ||
135 | #ifndef USE_PERIODS_MIN | ||
136 | #define USE_PERIODS_MIN 1 | 58 | #define USE_PERIODS_MIN 1 |
137 | #endif | ||
138 | #ifndef USE_PERIODS_MAX | ||
139 | #define USE_PERIODS_MAX 1024 | 59 | #define USE_PERIODS_MAX 1024 |
140 | #endif | ||
141 | #ifndef add_playback_constraints | ||
142 | #define add_playback_constraints(x) 0 | ||
143 | #endif | ||
144 | #ifndef add_capture_constraints | ||
145 | #define add_capture_constraints(x) 0 | ||
146 | #endif | ||
147 | 60 | ||
148 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ | 61 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ |
149 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ | 62 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ |
150 | static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 0}; | 63 | static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 0}; |
64 | static char *model[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = NULL}; | ||
151 | static int pcm_devs[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1}; | 65 | static int pcm_devs[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1}; |
152 | static int pcm_substreams[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 8}; | 66 | static int pcm_substreams[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 8}; |
153 | //static int midi_devs[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2}; | 67 | //static int midi_devs[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2}; |
@@ -162,6 +76,8 @@ module_param_array(id, charp, NULL, 0444); | |||
162 | MODULE_PARM_DESC(id, "ID string for dummy soundcard."); | 76 | MODULE_PARM_DESC(id, "ID string for dummy soundcard."); |
163 | module_param_array(enable, bool, NULL, 0444); | 77 | module_param_array(enable, bool, NULL, 0444); |
164 | MODULE_PARM_DESC(enable, "Enable this dummy soundcard."); | 78 | MODULE_PARM_DESC(enable, "Enable this dummy soundcard."); |
79 | module_param_array(model, charp, NULL, 0444); | ||
80 | MODULE_PARM_DESC(model, "Soundcard model."); | ||
165 | module_param_array(pcm_devs, int, NULL, 0444); | 81 | module_param_array(pcm_devs, int, NULL, 0444); |
166 | MODULE_PARM_DESC(pcm_devs, "PCM devices # (0-4) for dummy driver."); | 82 | MODULE_PARM_DESC(pcm_devs, "PCM devices # (0-4) for dummy driver."); |
167 | module_param_array(pcm_substreams, int, NULL, 0444); | 83 | module_param_array(pcm_substreams, int, NULL, 0444); |
@@ -193,9 +109,28 @@ struct dummy_timer_ops { | |||
193 | snd_pcm_uframes_t (*pointer)(struct snd_pcm_substream *); | 109 | snd_pcm_uframes_t (*pointer)(struct snd_pcm_substream *); |
194 | }; | 110 | }; |
195 | 111 | ||
112 | struct dummy_model { | ||
113 | const char *name; | ||
114 | int (*playback_constraints)(struct snd_pcm_runtime *runtime); | ||
115 | int (*capture_constraints)(struct snd_pcm_runtime *runtime); | ||
116 | u64 formats; | ||
117 | size_t buffer_bytes_max; | ||
118 | size_t period_bytes_min; | ||
119 | size_t period_bytes_max; | ||
120 | unsigned int periods_min; | ||
121 | unsigned int periods_max; | ||
122 | unsigned int rates; | ||
123 | unsigned int rate_min; | ||
124 | unsigned int rate_max; | ||
125 | unsigned int channels_min; | ||
126 | unsigned int channels_max; | ||
127 | }; | ||
128 | |||
196 | struct snd_dummy { | 129 | struct snd_dummy { |
197 | struct snd_card *card; | 130 | struct snd_card *card; |
131 | struct dummy_model *model; | ||
198 | struct snd_pcm *pcm; | 132 | struct snd_pcm *pcm; |
133 | struct snd_pcm_hardware pcm_hw; | ||
199 | spinlock_t mixer_lock; | 134 | spinlock_t mixer_lock; |
200 | int mixer_volume[MIXER_ADDR_LAST+1][2]; | 135 | int mixer_volume[MIXER_ADDR_LAST+1][2]; |
201 | int capture_source[MIXER_ADDR_LAST+1][2]; | 136 | int capture_source[MIXER_ADDR_LAST+1][2]; |
@@ -203,6 +138,92 @@ struct snd_dummy { | |||
203 | }; | 138 | }; |
204 | 139 | ||
205 | /* | 140 | /* |
141 | * card models | ||
142 | */ | ||
143 | |||
144 | static int emu10k1_playback_constraints(struct snd_pcm_runtime *runtime) | ||
145 | { | ||
146 | int err; | ||
147 | err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); | ||
148 | if (err < 0) | ||
149 | return err; | ||
150 | err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 256, UINT_MAX); | ||
151 | if (err < 0) | ||
152 | return err; | ||
153 | return 0; | ||
154 | } | ||
155 | |||
156 | struct dummy_model model_emu10k1 = { | ||
157 | .name = "emu10k1", | ||
158 | .playback_constraints = emu10k1_playback_constraints, | ||
159 | .buffer_bytes_max = 128 * 1024, | ||
160 | }; | ||
161 | |||
162 | struct dummy_model model_rme9652 = { | ||
163 | .name = "rme9652", | ||
164 | .buffer_bytes_max = 26 * 64 * 1024, | ||
165 | .formats = SNDRV_PCM_FMTBIT_S32_LE, | ||
166 | .channels_min = 26, | ||
167 | .channels_max = 26, | ||
168 | .periods_min = 2, | ||
169 | .periods_max = 2, | ||
170 | }; | ||
171 | |||
172 | struct dummy_model model_ice1712 = { | ||
173 | .name = "ice1712", | ||
174 | .buffer_bytes_max = 256 * 1024, | ||
175 | .formats = SNDRV_PCM_FMTBIT_S32_LE, | ||
176 | .channels_min = 10, | ||
177 | .channels_max = 10, | ||
178 | .periods_min = 1, | ||
179 | .periods_max = 1024, | ||
180 | }; | ||
181 | |||
182 | struct dummy_model model_uda1341 = { | ||
183 | .name = "uda1341", | ||
184 | .buffer_bytes_max = 16380, | ||
185 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
186 | .channels_min = 2, | ||
187 | .channels_max = 2, | ||
188 | .periods_min = 2, | ||
189 | .periods_max = 255, | ||
190 | }; | ||
191 | |||
192 | struct dummy_model model_ac97 = { | ||
193 | .name = "ac97", | ||
194 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
195 | .channels_min = 2, | ||
196 | .channels_max = 2, | ||
197 | .rates = SNDRV_PCM_RATE_48000, | ||
198 | .rate_min = 48000, | ||
199 | .rate_max = 48000, | ||
200 | }; | ||
201 | |||
202 | struct dummy_model model_ca0106 = { | ||
203 | .name = "ca0106", | ||
204 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
205 | .buffer_bytes_max = ((65536-64)*8), | ||
206 | .period_bytes_max = (65536-64), | ||
207 | .periods_min = 2, | ||
208 | .periods_max = 8, | ||
209 | .channels_min = 2, | ||
210 | .channels_max = 2, | ||
211 | .rates = SNDRV_PCM_RATE_48000|SNDRV_PCM_RATE_96000|SNDRV_PCM_RATE_192000, | ||
212 | .rate_min = 48000, | ||
213 | .rate_max = 192000, | ||
214 | }; | ||
215 | |||
216 | struct dummy_model *dummy_models[] = { | ||
217 | &model_emu10k1, | ||
218 | &model_rme9652, | ||
219 | &model_ice1712, | ||
220 | &model_uda1341, | ||
221 | &model_ac97, | ||
222 | &model_ca0106, | ||
223 | NULL | ||
224 | }; | ||
225 | |||
226 | /* | ||
206 | * system timer interface | 227 | * system timer interface |
207 | */ | 228 | */ |
208 | 229 | ||
@@ -509,7 +530,7 @@ static struct snd_pcm_hardware dummy_pcm_hardware = { | |||
509 | .channels_min = USE_CHANNELS_MIN, | 530 | .channels_min = USE_CHANNELS_MIN, |
510 | .channels_max = USE_CHANNELS_MAX, | 531 | .channels_max = USE_CHANNELS_MAX, |
511 | .buffer_bytes_max = MAX_BUFFER_SIZE, | 532 | .buffer_bytes_max = MAX_BUFFER_SIZE, |
512 | .period_bytes_min = 64, | 533 | .period_bytes_min = MIN_PERIOD_SIZE, |
513 | .period_bytes_max = MAX_PERIOD_SIZE, | 534 | .period_bytes_max = MAX_PERIOD_SIZE, |
514 | .periods_min = USE_PERIODS_MIN, | 535 | .periods_min = USE_PERIODS_MIN, |
515 | .periods_max = USE_PERIODS_MAX, | 536 | .periods_max = USE_PERIODS_MAX, |
@@ -538,6 +559,7 @@ static int dummy_pcm_hw_free(struct snd_pcm_substream *substream) | |||
538 | static int dummy_pcm_open(struct snd_pcm_substream *substream) | 559 | static int dummy_pcm_open(struct snd_pcm_substream *substream) |
539 | { | 560 | { |
540 | struct snd_dummy *dummy = snd_pcm_substream_chip(substream); | 561 | struct snd_dummy *dummy = snd_pcm_substream_chip(substream); |
562 | struct dummy_model *model = dummy->model; | ||
541 | struct snd_pcm_runtime *runtime = substream->runtime; | 563 | struct snd_pcm_runtime *runtime = substream->runtime; |
542 | int err; | 564 | int err; |
543 | 565 | ||
@@ -551,7 +573,7 @@ static int dummy_pcm_open(struct snd_pcm_substream *substream) | |||
551 | if (err < 0) | 573 | if (err < 0) |
552 | return err; | 574 | return err; |
553 | 575 | ||
554 | runtime->hw = dummy_pcm_hardware; | 576 | runtime->hw = dummy->pcm_hw; |
555 | if (substream->pcm->device & 1) { | 577 | if (substream->pcm->device & 1) { |
556 | runtime->hw.info &= ~SNDRV_PCM_INFO_INTERLEAVED; | 578 | runtime->hw.info &= ~SNDRV_PCM_INFO_INTERLEAVED; |
557 | runtime->hw.info |= SNDRV_PCM_INFO_NONINTERLEAVED; | 579 | runtime->hw.info |= SNDRV_PCM_INFO_NONINTERLEAVED; |
@@ -560,10 +582,16 @@ static int dummy_pcm_open(struct snd_pcm_substream *substream) | |||
560 | runtime->hw.info &= ~(SNDRV_PCM_INFO_MMAP | | 582 | runtime->hw.info &= ~(SNDRV_PCM_INFO_MMAP | |
561 | SNDRV_PCM_INFO_MMAP_VALID); | 583 | SNDRV_PCM_INFO_MMAP_VALID); |
562 | 584 | ||
563 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 585 | if (model == NULL) |
564 | err = add_playback_constraints(substream->runtime); | 586 | return 0; |
565 | else | 587 | |
566 | err = add_capture_constraints(substream->runtime); | 588 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
589 | if (model->playback_constraints) | ||
590 | err = model->playback_constraints(substream->runtime); | ||
591 | } else { | ||
592 | if (model->capture_constraints) | ||
593 | err = model->capture_constraints(substream->runtime); | ||
594 | } | ||
567 | if (err < 0) { | 595 | if (err < 0) { |
568 | dummy->timer_ops->free(substream); | 596 | dummy->timer_ops->free(substream); |
569 | return err; | 597 | return err; |
@@ -823,17 +851,19 @@ static int __devinit snd_card_dummy_new_mixer(struct snd_dummy *dummy) | |||
823 | /* | 851 | /* |
824 | * proc interface | 852 | * proc interface |
825 | */ | 853 | */ |
826 | static void print_formats(struct snd_info_buffer *buffer) | 854 | static void print_formats(struct snd_dummy *dummy, |
855 | struct snd_info_buffer *buffer) | ||
827 | { | 856 | { |
828 | int i; | 857 | int i; |
829 | 858 | ||
830 | for (i = 0; i < SNDRV_PCM_FORMAT_LAST; i++) { | 859 | for (i = 0; i < SNDRV_PCM_FORMAT_LAST; i++) { |
831 | if (dummy_pcm_hardware.formats & (1ULL << i)) | 860 | if (dummy->pcm_hw.formats & (1ULL << i)) |
832 | snd_iprintf(buffer, " %s", snd_pcm_format_name(i)); | 861 | snd_iprintf(buffer, " %s", snd_pcm_format_name(i)); |
833 | } | 862 | } |
834 | } | 863 | } |
835 | 864 | ||
836 | static void print_rates(struct snd_info_buffer *buffer) | 865 | static void print_rates(struct snd_dummy *dummy, |
866 | struct snd_info_buffer *buffer) | ||
837 | { | 867 | { |
838 | static int rates[] = { | 868 | static int rates[] = { |
839 | 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000, | 869 | 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000, |
@@ -841,19 +871,19 @@ static void print_rates(struct snd_info_buffer *buffer) | |||
841 | }; | 871 | }; |
842 | int i; | 872 | int i; |
843 | 873 | ||
844 | if (dummy_pcm_hardware.rates & SNDRV_PCM_RATE_CONTINUOUS) | 874 | if (dummy->pcm_hw.rates & SNDRV_PCM_RATE_CONTINUOUS) |
845 | snd_iprintf(buffer, " continuous"); | 875 | snd_iprintf(buffer, " continuous"); |
846 | if (dummy_pcm_hardware.rates & SNDRV_PCM_RATE_KNOT) | 876 | if (dummy->pcm_hw.rates & SNDRV_PCM_RATE_KNOT) |
847 | snd_iprintf(buffer, " knot"); | 877 | snd_iprintf(buffer, " knot"); |
848 | for (i = 0; i < ARRAY_SIZE(rates); i++) | 878 | for (i = 0; i < ARRAY_SIZE(rates); i++) |
849 | if (dummy_pcm_hardware.rates & (1 << i)) | 879 | if (dummy->pcm_hw.rates & (1 << i)) |
850 | snd_iprintf(buffer, " %d", rates[i]); | 880 | snd_iprintf(buffer, " %d", rates[i]); |
851 | } | 881 | } |
852 | 882 | ||
853 | #define get_dummy_int_ptr(ofs) \ | 883 | #define get_dummy_int_ptr(dummy, ofs) \ |
854 | (unsigned int *)((char *)&dummy_pcm_hardware + (ofs)) | 884 | (unsigned int *)((char *)&((dummy)->pcm_hw) + (ofs)) |
855 | #define get_dummy_ll_ptr(ofs) \ | 885 | #define get_dummy_ll_ptr(dummy, ofs) \ |
856 | (unsigned long long *)((char *)&dummy_pcm_hardware + (ofs)) | 886 | (unsigned long long *)((char *)&((dummy)->pcm_hw) + (ofs)) |
857 | 887 | ||
858 | struct dummy_hw_field { | 888 | struct dummy_hw_field { |
859 | const char *name; | 889 | const char *name; |
@@ -884,20 +914,21 @@ static struct dummy_hw_field fields[] = { | |||
884 | static void dummy_proc_read(struct snd_info_entry *entry, | 914 | static void dummy_proc_read(struct snd_info_entry *entry, |
885 | struct snd_info_buffer *buffer) | 915 | struct snd_info_buffer *buffer) |
886 | { | 916 | { |
917 | struct snd_dummy *dummy = entry->private_data; | ||
887 | int i; | 918 | int i; |
888 | 919 | ||
889 | for (i = 0; i < ARRAY_SIZE(fields); i++) { | 920 | for (i = 0; i < ARRAY_SIZE(fields); i++) { |
890 | snd_iprintf(buffer, "%s ", fields[i].name); | 921 | snd_iprintf(buffer, "%s ", fields[i].name); |
891 | if (fields[i].size == sizeof(int)) | 922 | if (fields[i].size == sizeof(int)) |
892 | snd_iprintf(buffer, fields[i].format, | 923 | snd_iprintf(buffer, fields[i].format, |
893 | *get_dummy_int_ptr(fields[i].offset)); | 924 | *get_dummy_int_ptr(dummy, fields[i].offset)); |
894 | else | 925 | else |
895 | snd_iprintf(buffer, fields[i].format, | 926 | snd_iprintf(buffer, fields[i].format, |
896 | *get_dummy_ll_ptr(fields[i].offset)); | 927 | *get_dummy_ll_ptr(dummy, fields[i].offset)); |
897 | if (!strcmp(fields[i].name, "formats")) | 928 | if (!strcmp(fields[i].name, "formats")) |
898 | print_formats(buffer); | 929 | print_formats(dummy, buffer); |
899 | else if (!strcmp(fields[i].name, "rates")) | 930 | else if (!strcmp(fields[i].name, "rates")) |
900 | print_rates(buffer); | 931 | print_rates(dummy, buffer); |
901 | snd_iprintf(buffer, "\n"); | 932 | snd_iprintf(buffer, "\n"); |
902 | } | 933 | } |
903 | } | 934 | } |
@@ -905,6 +936,7 @@ static void dummy_proc_read(struct snd_info_entry *entry, | |||
905 | static void dummy_proc_write(struct snd_info_entry *entry, | 936 | static void dummy_proc_write(struct snd_info_entry *entry, |
906 | struct snd_info_buffer *buffer) | 937 | struct snd_info_buffer *buffer) |
907 | { | 938 | { |
939 | struct snd_dummy *dummy = entry->private_data; | ||
908 | char line[64]; | 940 | char line[64]; |
909 | 941 | ||
910 | while (!snd_info_get_line(buffer, line, sizeof(line))) { | 942 | while (!snd_info_get_line(buffer, line, sizeof(line))) { |
@@ -924,9 +956,9 @@ static void dummy_proc_write(struct snd_info_entry *entry, | |||
924 | if (strict_strtoull(item, 0, &val)) | 956 | if (strict_strtoull(item, 0, &val)) |
925 | continue; | 957 | continue; |
926 | if (fields[i].size == sizeof(int)) | 958 | if (fields[i].size == sizeof(int)) |
927 | *get_dummy_int_ptr(fields[i].offset) = val; | 959 | *get_dummy_int_ptr(dummy, fields[i].offset) = val; |
928 | else | 960 | else |
929 | *get_dummy_ll_ptr(fields[i].offset) = val; | 961 | *get_dummy_ll_ptr(dummy, fields[i].offset) = val; |
930 | } | 962 | } |
931 | } | 963 | } |
932 | 964 | ||
@@ -938,6 +970,7 @@ static void __devinit dummy_proc_init(struct snd_dummy *chip) | |||
938 | snd_info_set_text_ops(entry, chip, dummy_proc_read); | 970 | snd_info_set_text_ops(entry, chip, dummy_proc_read); |
939 | entry->c.text.write = dummy_proc_write; | 971 | entry->c.text.write = dummy_proc_write; |
940 | entry->mode |= S_IWUSR; | 972 | entry->mode |= S_IWUSR; |
973 | entry->private_data = chip; | ||
941 | } | 974 | } |
942 | } | 975 | } |
943 | #else | 976 | #else |
@@ -948,6 +981,7 @@ static int __devinit snd_dummy_probe(struct platform_device *devptr) | |||
948 | { | 981 | { |
949 | struct snd_card *card; | 982 | struct snd_card *card; |
950 | struct snd_dummy *dummy; | 983 | struct snd_dummy *dummy; |
984 | struct dummy_model *m = NULL, **mdl; | ||
951 | int idx, err; | 985 | int idx, err; |
952 | int dev = devptr->id; | 986 | int dev = devptr->id; |
953 | 987 | ||
@@ -957,6 +991,15 @@ static int __devinit snd_dummy_probe(struct platform_device *devptr) | |||
957 | return err; | 991 | return err; |
958 | dummy = card->private_data; | 992 | dummy = card->private_data; |
959 | dummy->card = card; | 993 | dummy->card = card; |
994 | for (mdl = dummy_models; *mdl && model[dev]; mdl++) { | ||
995 | if (strcmp(model[dev], (*mdl)->name) == 0) { | ||
996 | printk(KERN_INFO | ||
997 | "snd-dummy: Using model '%s' for card %i\n", | ||
998 | (*mdl)->name, card->number); | ||
999 | m = dummy->model = *mdl; | ||
1000 | break; | ||
1001 | } | ||
1002 | } | ||
960 | for (idx = 0; idx < MAX_PCM_DEVICES && idx < pcm_devs[dev]; idx++) { | 1003 | for (idx = 0; idx < MAX_PCM_DEVICES && idx < pcm_devs[dev]; idx++) { |
961 | if (pcm_substreams[dev] < 1) | 1004 | if (pcm_substreams[dev] < 1) |
962 | pcm_substreams[dev] = 1; | 1005 | pcm_substreams[dev] = 1; |
@@ -966,6 +1009,33 @@ static int __devinit snd_dummy_probe(struct platform_device *devptr) | |||
966 | if (err < 0) | 1009 | if (err < 0) |
967 | goto __nodev; | 1010 | goto __nodev; |
968 | } | 1011 | } |
1012 | |||
1013 | dummy->pcm_hw = dummy_pcm_hardware; | ||
1014 | if (m) { | ||
1015 | if (m->formats) | ||
1016 | dummy->pcm_hw.formats = m->formats; | ||
1017 | if (m->buffer_bytes_max) | ||
1018 | dummy->pcm_hw.buffer_bytes_max = m->buffer_bytes_max; | ||
1019 | if (m->period_bytes_min) | ||
1020 | dummy->pcm_hw.period_bytes_min = m->period_bytes_min; | ||
1021 | if (m->period_bytes_max) | ||
1022 | dummy->pcm_hw.period_bytes_max = m->period_bytes_max; | ||
1023 | if (m->periods_min) | ||
1024 | dummy->pcm_hw.periods_min = m->periods_min; | ||
1025 | if (m->periods_max) | ||
1026 | dummy->pcm_hw.periods_max = m->periods_max; | ||
1027 | if (m->rates) | ||
1028 | dummy->pcm_hw.rates = m->rates; | ||
1029 | if (m->rate_min) | ||
1030 | dummy->pcm_hw.rate_min = m->rate_min; | ||
1031 | if (m->rate_max) | ||
1032 | dummy->pcm_hw.rate_max = m->rate_max; | ||
1033 | if (m->channels_min) | ||
1034 | dummy->pcm_hw.channels_min = m->channels_min; | ||
1035 | if (m->channels_max) | ||
1036 | dummy->pcm_hw.channels_max = m->channels_max; | ||
1037 | } | ||
1038 | |||
969 | err = snd_card_dummy_new_mixer(dummy); | 1039 | err = snd_card_dummy_new_mixer(dummy); |
970 | if (err < 0) | 1040 | if (err < 0) |
971 | goto __nodev; | 1041 | goto __nodev; |
diff --git a/sound/drivers/vx/vx_pcm.c b/sound/drivers/vx/vx_pcm.c index 6644d0034fba..35a2f71a6af5 100644 --- a/sound/drivers/vx/vx_pcm.c +++ b/sound/drivers/vx/vx_pcm.c | |||
@@ -46,7 +46,6 @@ | |||
46 | */ | 46 | */ |
47 | 47 | ||
48 | #include <linux/slab.h> | 48 | #include <linux/slab.h> |
49 | #include <linux/vmalloc.h> | ||
50 | #include <linux/delay.h> | 49 | #include <linux/delay.h> |
51 | #include <sound/core.h> | 50 | #include <sound/core.h> |
52 | #include <sound/asoundef.h> | 51 | #include <sound/asoundef.h> |
@@ -56,55 +55,6 @@ | |||
56 | 55 | ||
57 | 56 | ||
58 | /* | 57 | /* |
59 | * we use a vmalloc'ed (sg-)buffer | ||
60 | */ | ||
61 | |||
62 | /* get the physical page pointer on the given offset */ | ||
63 | static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs, | ||
64 | unsigned long offset) | ||
65 | { | ||
66 | void *pageptr = subs->runtime->dma_area + offset; | ||
67 | return vmalloc_to_page(pageptr); | ||
68 | } | ||
69 | |||
70 | /* | ||
71 | * allocate a buffer via vmalloc_32(). | ||
72 | * called from hw_params | ||
73 | * NOTE: this may be called not only once per pcm open! | ||
74 | */ | ||
75 | static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, size_t size) | ||
76 | { | ||
77 | struct snd_pcm_runtime *runtime = subs->runtime; | ||
78 | if (runtime->dma_area) { | ||
79 | /* already allocated */ | ||
80 | if (runtime->dma_bytes >= size) | ||
81 | return 0; /* already enough large */ | ||
82 | vfree(runtime->dma_area); | ||
83 | } | ||
84 | runtime->dma_area = vmalloc_32(size); | ||
85 | if (! runtime->dma_area) | ||
86 | return -ENOMEM; | ||
87 | memset(runtime->dma_area, 0, size); | ||
88 | runtime->dma_bytes = size; | ||
89 | return 1; /* changed */ | ||
90 | } | ||
91 | |||
92 | /* | ||
93 | * free the buffer. | ||
94 | * called from hw_free callback | ||
95 | * NOTE: this may be called not only once per pcm open! | ||
96 | */ | ||
97 | static int snd_pcm_free_vmalloc_buffer(struct snd_pcm_substream *subs) | ||
98 | { | ||
99 | struct snd_pcm_runtime *runtime = subs->runtime; | ||
100 | |||
101 | vfree(runtime->dma_area); | ||
102 | runtime->dma_area = NULL; | ||
103 | return 0; | ||
104 | } | ||
105 | |||
106 | |||
107 | /* | ||
108 | * read three pending pcm bytes via inb() | 58 | * read three pending pcm bytes via inb() |
109 | */ | 59 | */ |
110 | static void vx_pcm_read_per_bytes(struct vx_core *chip, struct snd_pcm_runtime *runtime, | 60 | static void vx_pcm_read_per_bytes(struct vx_core *chip, struct snd_pcm_runtime *runtime, |
@@ -865,7 +815,8 @@ static snd_pcm_uframes_t vx_pcm_playback_pointer(struct snd_pcm_substream *subs) | |||
865 | static int vx_pcm_hw_params(struct snd_pcm_substream *subs, | 815 | static int vx_pcm_hw_params(struct snd_pcm_substream *subs, |
866 | struct snd_pcm_hw_params *hw_params) | 816 | struct snd_pcm_hw_params *hw_params) |
867 | { | 817 | { |
868 | return snd_pcm_alloc_vmalloc_buffer(subs, params_buffer_bytes(hw_params)); | 818 | return snd_pcm_lib_alloc_vmalloc_32_buffer |
819 | (subs, params_buffer_bytes(hw_params)); | ||
869 | } | 820 | } |
870 | 821 | ||
871 | /* | 822 | /* |
@@ -873,7 +824,7 @@ static int vx_pcm_hw_params(struct snd_pcm_substream *subs, | |||
873 | */ | 824 | */ |
874 | static int vx_pcm_hw_free(struct snd_pcm_substream *subs) | 825 | static int vx_pcm_hw_free(struct snd_pcm_substream *subs) |
875 | { | 826 | { |
876 | return snd_pcm_free_vmalloc_buffer(subs); | 827 | return snd_pcm_lib_free_vmalloc_buffer(subs); |
877 | } | 828 | } |
878 | 829 | ||
879 | /* | 830 | /* |
@@ -953,7 +904,8 @@ static struct snd_pcm_ops vx_pcm_playback_ops = { | |||
953 | .prepare = vx_pcm_prepare, | 904 | .prepare = vx_pcm_prepare, |
954 | .trigger = vx_pcm_trigger, | 905 | .trigger = vx_pcm_trigger, |
955 | .pointer = vx_pcm_playback_pointer, | 906 | .pointer = vx_pcm_playback_pointer, |
956 | .page = snd_pcm_get_vmalloc_page, | 907 | .page = snd_pcm_lib_get_vmalloc_page, |
908 | .mmap = snd_pcm_lib_mmap_vmalloc, | ||
957 | }; | 909 | }; |
958 | 910 | ||
959 | 911 | ||
@@ -1173,7 +1125,8 @@ static struct snd_pcm_ops vx_pcm_capture_ops = { | |||
1173 | .prepare = vx_pcm_prepare, | 1125 | .prepare = vx_pcm_prepare, |
1174 | .trigger = vx_pcm_trigger, | 1126 | .trigger = vx_pcm_trigger, |
1175 | .pointer = vx_pcm_capture_pointer, | 1127 | .pointer = vx_pcm_capture_pointer, |
1176 | .page = snd_pcm_get_vmalloc_page, | 1128 | .page = snd_pcm_lib_get_vmalloc_page, |
1129 | .mmap = snd_pcm_lib_mmap_vmalloc, | ||
1177 | }; | 1130 | }; |
1178 | 1131 | ||
1179 | 1132 | ||
diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig index 02fe81ca88fd..755a0a5f0e3f 100644 --- a/sound/isa/Kconfig +++ b/sound/isa/Kconfig | |||
@@ -63,15 +63,16 @@ config SND_AD1848 | |||
63 | will be called snd-ad1848. | 63 | will be called snd-ad1848. |
64 | 64 | ||
65 | config SND_ALS100 | 65 | config SND_ALS100 |
66 | tristate "Avance Logic ALS100/ALS120" | 66 | tristate "Diamond Tech. DT-019x and Avance Logic ALSxxx" |
67 | depends on PNP | 67 | depends on PNP |
68 | select ISAPNP | 68 | select ISAPNP |
69 | select SND_OPL3_LIB | 69 | select SND_OPL3_LIB |
70 | select SND_MPU401_UART | 70 | select SND_MPU401_UART |
71 | select SND_SB16_DSP | 71 | select SND_SB16_DSP |
72 | help | 72 | help |
73 | Say Y here to include support for soundcards based on Avance | 73 | Say Y here to include support for soundcards based on the |
74 | Logic ALS100, ALS110, ALS120 and ALS200 chips. | 74 | Diamond Technologies DT-019X or Avance Logic chips: ALS007, |
75 | ALS100, ALS110, ALS120 and ALS200 chips. | ||
75 | 76 | ||
76 | To compile this driver as a module, choose M here: the module | 77 | To compile this driver as a module, choose M here: the module |
77 | will be called snd-als100. | 78 | will be called snd-als100. |
@@ -127,20 +128,6 @@ config SND_CS4236 | |||
127 | To compile this driver as a module, choose M here: the module | 128 | To compile this driver as a module, choose M here: the module |
128 | will be called snd-cs4236. | 129 | will be called snd-cs4236. |
129 | 130 | ||
130 | config SND_DT019X | ||
131 | tristate "Diamond Technologies DT-019X, Avance Logic ALS-007" | ||
132 | depends on PNP | ||
133 | select ISAPNP | ||
134 | select SND_OPL3_LIB | ||
135 | select SND_MPU401_UART | ||
136 | select SND_SB16_DSP | ||
137 | help | ||
138 | Say Y here to include support for soundcards based on the | ||
139 | Diamond Technologies DT-019X or Avance Logic ALS-007 chips. | ||
140 | |||
141 | To compile this driver as a module, choose M here: the module | ||
142 | will be called snd-dt019x. | ||
143 | |||
144 | config SND_ES968 | 131 | config SND_ES968 |
145 | tristate "Generic ESS ES968 driver" | 132 | tristate "Generic ESS ES968 driver" |
146 | depends on PNP | 133 | depends on PNP |
@@ -252,6 +239,22 @@ config SND_INTERWAVE_STB | |||
252 | To compile this driver as a module, choose M here: the module | 239 | To compile this driver as a module, choose M here: the module |
253 | will be called snd-interwave-stb. | 240 | will be called snd-interwave-stb. |
254 | 241 | ||
242 | config SND_JAZZ16 | ||
243 | tristate "Media Vision Jazz16 card and compatibles" | ||
244 | select SND_OPL3_LIB | ||
245 | select SND_MPU401_UART | ||
246 | select SND_SB8_DSP | ||
247 | help | ||
248 | Say Y here to include support for soundcards based on the | ||
249 | Media Vision Jazz16 chipset: digital chip MVD1216 (Jazz16), | ||
250 | codec MVA416 (CS4216) and mixer MVA514 (ICS2514). | ||
251 | Media Vision's Jazz16 cards were sold under names Pro Sonic 16, | ||
252 | Premium 3-D and Pro 3-D. There were also OEMs cards with the | ||
253 | Jazz16 chipset. | ||
254 | |||
255 | To compile this driver as a module, choose M here: the module | ||
256 | will be called snd-jazz16. | ||
257 | |||
255 | config SND_OPL3SA2 | 258 | config SND_OPL3SA2 |
256 | tristate "Yamaha OPL3-SA2/SA3" | 259 | tristate "Yamaha OPL3-SA2/SA3" |
257 | select SND_OPL3_LIB | 260 | select SND_OPL3_LIB |
diff --git a/sound/isa/Makefile b/sound/isa/Makefile index b906b9a1a81e..c73d30c4f462 100644 --- a/sound/isa/Makefile +++ b/sound/isa/Makefile | |||
@@ -7,7 +7,6 @@ snd-adlib-objs := adlib.o | |||
7 | snd-als100-objs := als100.o | 7 | snd-als100-objs := als100.o |
8 | snd-azt2320-objs := azt2320.o | 8 | snd-azt2320-objs := azt2320.o |
9 | snd-cmi8330-objs := cmi8330.o | 9 | snd-cmi8330-objs := cmi8330.o |
10 | snd-dt019x-objs := dt019x.o | ||
11 | snd-es18xx-objs := es18xx.o | 10 | snd-es18xx-objs := es18xx.o |
12 | snd-opl3sa2-objs := opl3sa2.o | 11 | snd-opl3sa2-objs := opl3sa2.o |
13 | snd-sc6000-objs := sc6000.o | 12 | snd-sc6000-objs := sc6000.o |
@@ -19,7 +18,6 @@ obj-$(CONFIG_SND_ADLIB) += snd-adlib.o | |||
19 | obj-$(CONFIG_SND_ALS100) += snd-als100.o | 18 | obj-$(CONFIG_SND_ALS100) += snd-als100.o |
20 | obj-$(CONFIG_SND_AZT2320) += snd-azt2320.o | 19 | obj-$(CONFIG_SND_AZT2320) += snd-azt2320.o |
21 | obj-$(CONFIG_SND_CMI8330) += snd-cmi8330.o | 20 | obj-$(CONFIG_SND_CMI8330) += snd-cmi8330.o |
22 | obj-$(CONFIG_SND_DT019X) += snd-dt019x.o | ||
23 | obj-$(CONFIG_SND_ES18XX) += snd-es18xx.o | 21 | obj-$(CONFIG_SND_ES18XX) += snd-es18xx.o |
24 | obj-$(CONFIG_SND_OPL3SA2) += snd-opl3sa2.o | 22 | obj-$(CONFIG_SND_OPL3SA2) += snd-opl3sa2.o |
25 | obj-$(CONFIG_SND_SC6000) += snd-sc6000.o | 23 | obj-$(CONFIG_SND_SC6000) += snd-sc6000.o |
diff --git a/sound/isa/als100.c b/sound/isa/als100.c index 5fd52e4d7079..20becc89f6f6 100644 --- a/sound/isa/als100.c +++ b/sound/isa/als100.c | |||
@@ -2,9 +2,13 @@ | |||
2 | /* | 2 | /* |
3 | card-als100.c - driver for Avance Logic ALS100 based soundcards. | 3 | card-als100.c - driver for Avance Logic ALS100 based soundcards. |
4 | Copyright (C) 1999-2000 by Massimo Piccioni <dafastidio@libero.it> | 4 | Copyright (C) 1999-2000 by Massimo Piccioni <dafastidio@libero.it> |
5 | Copyright (C) 1999-2002 by Massimo Piccioni <dafastidio@libero.it> | ||
5 | 6 | ||
6 | Thanks to Pierfrancesco 'qM2' Passerini. | 7 | Thanks to Pierfrancesco 'qM2' Passerini. |
7 | 8 | ||
9 | Generalised for soundcards based on DT-0196 and ALS-007 chips | ||
10 | by Jonathan Woithe <jwoithe@physics.adelaide.edu.au>: June 2002. | ||
11 | |||
8 | 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 |
9 | 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 |
10 | the Free Software Foundation; either version 2 of the License, or | 14 | the Free Software Foundation; either version 2 of the License, or |
@@ -33,10 +37,10 @@ | |||
33 | 37 | ||
34 | #define PFX "als100: " | 38 | #define PFX "als100: " |
35 | 39 | ||
36 | MODULE_AUTHOR("Massimo Piccioni <dafastidio@libero.it>"); | 40 | MODULE_DESCRIPTION("Avance Logic ALS007/ALS1X0"); |
37 | MODULE_DESCRIPTION("Avance Logic ALS1X0"); | 41 | MODULE_SUPPORTED_DEVICE("{{Diamond Technologies DT-019X}," |
38 | MODULE_LICENSE("GPL"); | 42 | "{Avance Logic ALS-007}}" |
39 | MODULE_SUPPORTED_DEVICE("{{Avance Logic,ALS100 - PRO16PNP}," | 43 | "{{Avance Logic,ALS100 - PRO16PNP}," |
40 | "{Avance Logic,ALS110}," | 44 | "{Avance Logic,ALS110}," |
41 | "{Avance Logic,ALS120}," | 45 | "{Avance Logic,ALS120}," |
42 | "{Avance Logic,ALS200}," | 46 | "{Avance Logic,ALS200}," |
@@ -45,9 +49,12 @@ MODULE_SUPPORTED_DEVICE("{{Avance Logic,ALS100 - PRO16PNP}," | |||
45 | "{Avance Logic,ALS120}," | 49 | "{Avance Logic,ALS120}," |
46 | "{RTL,RTL3000}}"); | 50 | "{RTL,RTL3000}}"); |
47 | 51 | ||
52 | MODULE_AUTHOR("Massimo Piccioni <dafastidio@libero.it>"); | ||
53 | MODULE_LICENSE("GPL"); | ||
54 | |||
48 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ | 55 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ |
49 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ | 56 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ |
50 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; /* Enable this card */ | 57 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */ |
51 | static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */ | 58 | static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */ |
52 | static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */ | 59 | static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */ |
53 | static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */ | 60 | static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */ |
@@ -57,14 +64,15 @@ static int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* PnP setup */ | |||
57 | static int dma16[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* PnP setup */ | 64 | static int dma16[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* PnP setup */ |
58 | 65 | ||
59 | module_param_array(index, int, NULL, 0444); | 66 | module_param_array(index, int, NULL, 0444); |
60 | MODULE_PARM_DESC(index, "Index value for als100 based soundcard."); | 67 | MODULE_PARM_DESC(index, "Index value for Avance Logic based soundcard."); |
61 | module_param_array(id, charp, NULL, 0444); | 68 | module_param_array(id, charp, NULL, 0444); |
62 | MODULE_PARM_DESC(id, "ID string for als100 based soundcard."); | 69 | MODULE_PARM_DESC(id, "ID string for Avance Logic based soundcard."); |
63 | module_param_array(enable, bool, NULL, 0444); | 70 | module_param_array(enable, bool, NULL, 0444); |
64 | MODULE_PARM_DESC(enable, "Enable als100 based soundcard."); | 71 | MODULE_PARM_DESC(enable, "Enable Avance Logic based soundcard."); |
72 | |||
73 | MODULE_ALIAS("snd-dt019x"); | ||
65 | 74 | ||
66 | struct snd_card_als100 { | 75 | struct snd_card_als100 { |
67 | int dev_no; | ||
68 | struct pnp_dev *dev; | 76 | struct pnp_dev *dev; |
69 | struct pnp_dev *devmpu; | 77 | struct pnp_dev *devmpu; |
70 | struct pnp_dev *devopl; | 78 | struct pnp_dev *devopl; |
@@ -72,25 +80,43 @@ struct snd_card_als100 { | |||
72 | }; | 80 | }; |
73 | 81 | ||
74 | static struct pnp_card_device_id snd_als100_pnpids[] = { | 82 | static struct pnp_card_device_id snd_als100_pnpids[] = { |
83 | /* DT197A30 */ | ||
84 | { .id = "RWB1688", | ||
85 | .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" } }, | ||
86 | .driver_data = SB_HW_DT019X }, | ||
87 | /* DT0196 / ALS-007 */ | ||
88 | { .id = "ALS0007", | ||
89 | .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" } }, | ||
90 | .driver_data = SB_HW_DT019X }, | ||
75 | /* ALS100 - PRO16PNP */ | 91 | /* ALS100 - PRO16PNP */ |
76 | { .id = "ALS0001", .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" } } }, | 92 | { .id = "ALS0001", |
93 | .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" } }, | ||
94 | .driver_data = SB_HW_ALS100 }, | ||
77 | /* ALS110 - MF1000 - Digimate 3D Sound */ | 95 | /* ALS110 - MF1000 - Digimate 3D Sound */ |
78 | { .id = "ALS0110", .devs = { { "@@@1001" }, { "@X@1001" }, { "@H@1001" } } }, | 96 | { .id = "ALS0110", |
97 | .devs = { { "@@@1001" }, { "@X@1001" }, { "@H@1001" } }, | ||
98 | .driver_data = SB_HW_ALS100 }, | ||
79 | /* ALS120 */ | 99 | /* ALS120 */ |
80 | { .id = "ALS0120", .devs = { { "@@@2001" }, { "@X@2001" }, { "@H@2001" } } }, | 100 | { .id = "ALS0120", |
101 | .devs = { { "@@@2001" }, { "@X@2001" }, { "@H@2001" } }, | ||
102 | .driver_data = SB_HW_ALS100 }, | ||
81 | /* ALS200 */ | 103 | /* ALS200 */ |
82 | { .id = "ALS0200", .devs = { { "@@@0020" }, { "@X@0020" }, { "@H@0001" } } }, | 104 | { .id = "ALS0200", |
105 | .devs = { { "@@@0020" }, { "@X@0020" }, { "@H@0001" } }, | ||
106 | .driver_data = SB_HW_ALS100 }, | ||
83 | /* ALS200 OEM */ | 107 | /* ALS200 OEM */ |
84 | { .id = "ALS0200", .devs = { { "@@@0020" }, { "@X@0020" }, { "@H@0020" } } }, | 108 | { .id = "ALS0200", |
109 | .devs = { { "@@@0020" }, { "@X@0020" }, { "@H@0020" } }, | ||
110 | .driver_data = SB_HW_ALS100 }, | ||
85 | /* RTL3000 */ | 111 | /* RTL3000 */ |
86 | { .id = "RTL3000", .devs = { { "@@@2001" }, { "@X@2001" }, { "@H@2001" } } }, | 112 | { .id = "RTL3000", |
87 | { .id = "", } /* end */ | 113 | .devs = { { "@@@2001" }, { "@X@2001" }, { "@H@2001" } }, |
114 | .driver_data = SB_HW_ALS100 }, | ||
115 | { .id = "" } /* end */ | ||
88 | }; | 116 | }; |
89 | 117 | ||
90 | MODULE_DEVICE_TABLE(pnp_card, snd_als100_pnpids); | 118 | MODULE_DEVICE_TABLE(pnp_card, snd_als100_pnpids); |
91 | 119 | ||
92 | #define DRIVER_NAME "snd-card-als100" | ||
93 | |||
94 | static int __devinit snd_card_als100_pnp(int dev, struct snd_card_als100 *acard, | 120 | static int __devinit snd_card_als100_pnp(int dev, struct snd_card_als100 *acard, |
95 | struct pnp_card_link *card, | 121 | struct pnp_card_link *card, |
96 | const struct pnp_card_device_id *id) | 122 | const struct pnp_card_device_id *id) |
@@ -113,8 +139,12 @@ static int __devinit snd_card_als100_pnp(int dev, struct snd_card_als100 *acard, | |||
113 | return err; | 139 | return err; |
114 | } | 140 | } |
115 | port[dev] = pnp_port_start(pdev, 0); | 141 | port[dev] = pnp_port_start(pdev, 0); |
116 | dma8[dev] = pnp_dma(pdev, 1); | 142 | if (id->driver_data == SB_HW_DT019X) |
117 | dma16[dev] = pnp_dma(pdev, 0); | 143 | dma8[dev] = pnp_dma(pdev, 0); |
144 | else { | ||
145 | dma8[dev] = pnp_dma(pdev, 1); | ||
146 | dma16[dev] = pnp_dma(pdev, 0); | ||
147 | } | ||
118 | irq[dev] = pnp_irq(pdev, 0); | 148 | irq[dev] = pnp_irq(pdev, 0); |
119 | 149 | ||
120 | pdev = acard->devmpu; | 150 | pdev = acard->devmpu; |
@@ -175,22 +205,33 @@ static int __devinit snd_card_als100_probe(int dev, | |||
175 | } | 205 | } |
176 | snd_card_set_dev(card, &pcard->card->dev); | 206 | snd_card_set_dev(card, &pcard->card->dev); |
177 | 207 | ||
178 | if ((error = snd_sbdsp_create(card, port[dev], | 208 | if (pid->driver_data == SB_HW_DT019X) |
179 | irq[dev], | 209 | dma16[dev] = -1; |
180 | snd_sb16dsp_interrupt, | 210 | |
181 | dma8[dev], | 211 | error = snd_sbdsp_create(card, port[dev], irq[dev], |
182 | dma16[dev], | 212 | snd_sb16dsp_interrupt, |
183 | SB_HW_ALS100, &chip)) < 0) { | 213 | dma8[dev], dma16[dev], |
214 | pid->driver_data, | ||
215 | &chip); | ||
216 | if (error < 0) { | ||
184 | snd_card_free(card); | 217 | snd_card_free(card); |
185 | return error; | 218 | return error; |
186 | } | 219 | } |
187 | acard->chip = chip; | 220 | acard->chip = chip; |
188 | 221 | ||
189 | strcpy(card->driver, "ALS100"); | 222 | if (pid->driver_data == SB_HW_DT019X) { |
190 | strcpy(card->shortname, "Avance Logic ALS100"); | 223 | strcpy(card->driver, "DT-019X"); |
191 | sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d&%d", | 224 | strcpy(card->shortname, "Diamond Tech. DT-019X"); |
192 | card->shortname, chip->name, chip->port, | 225 | sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d", |
193 | irq[dev], dma8[dev], dma16[dev]); | 226 | card->shortname, chip->name, chip->port, |
227 | irq[dev], dma8[dev]); | ||
228 | } else { | ||
229 | strcpy(card->driver, "ALS100"); | ||
230 | strcpy(card->shortname, "Avance Logic ALS100"); | ||
231 | sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d&%d", | ||
232 | card->shortname, chip->name, chip->port, | ||
233 | irq[dev], dma8[dev], dma16[dev]); | ||
234 | } | ||
194 | 235 | ||
195 | if ((error = snd_sb16dsp_pcm(chip, 0, NULL)) < 0) { | 236 | if ((error = snd_sb16dsp_pcm(chip, 0, NULL)) < 0) { |
196 | snd_card_free(card); | 237 | snd_card_free(card); |
@@ -203,9 +244,19 @@ static int __devinit snd_card_als100_probe(int dev, | |||
203 | } | 244 | } |
204 | 245 | ||
205 | if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) { | 246 | if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) { |
206 | if (snd_mpu401_uart_new(card, 0, MPU401_HW_ALS100, | 247 | int mpu_type = MPU401_HW_ALS100; |
248 | |||
249 | if (mpu_irq[dev] == SNDRV_AUTO_IRQ) | ||
250 | mpu_irq[dev] = -1; | ||
251 | |||
252 | if (pid->driver_data == SB_HW_DT019X) | ||
253 | mpu_type = MPU401_HW_MPU401; | ||
254 | |||
255 | if (snd_mpu401_uart_new(card, 0, | ||
256 | mpu_type, | ||
207 | mpu_port[dev], 0, | 257 | mpu_port[dev], 0, |
208 | mpu_irq[dev], IRQF_DISABLED, | 258 | mpu_irq[dev], |
259 | mpu_irq[dev] >= 0 ? IRQF_DISABLED : 0, | ||
209 | NULL) < 0) | 260 | NULL) < 0) |
210 | snd_printk(KERN_ERR PFX "no MPU-401 device at 0x%lx\n", mpu_port[dev]); | 261 | snd_printk(KERN_ERR PFX "no MPU-401 device at 0x%lx\n", mpu_port[dev]); |
211 | } | 262 | } |
@@ -291,7 +342,7 @@ static int snd_als100_pnp_resume(struct pnp_card_link *pcard) | |||
291 | 342 | ||
292 | static struct pnp_card_driver als100_pnpc_driver = { | 343 | static struct pnp_card_driver als100_pnpc_driver = { |
293 | .flags = PNP_DRIVER_RES_DISABLE, | 344 | .flags = PNP_DRIVER_RES_DISABLE, |
294 | .name = "als100", | 345 | .name = "als100", |
295 | .id_table = snd_als100_pnpids, | 346 | .id_table = snd_als100_pnpids, |
296 | .probe = snd_als100_pnp_detect, | 347 | .probe = snd_als100_pnp_detect, |
297 | .remove = __devexit_p(snd_als100_pnp_remove), | 348 | .remove = __devexit_p(snd_als100_pnp_remove), |
@@ -312,7 +363,7 @@ static int __init alsa_card_als100_init(void) | |||
312 | if (!als100_devices) { | 363 | if (!als100_devices) { |
313 | pnp_unregister_card_driver(&als100_pnpc_driver); | 364 | pnp_unregister_card_driver(&als100_pnpc_driver); |
314 | #ifdef MODULE | 365 | #ifdef MODULE |
315 | snd_printk(KERN_ERR "no ALS100 based soundcards found\n"); | 366 | snd_printk(KERN_ERR "no Avance Logic based soundcards found\n"); |
316 | #endif | 367 | #endif |
317 | return -ENODEV; | 368 | return -ENODEV; |
318 | } | 369 | } |
diff --git a/sound/isa/dt019x.c b/sound/isa/dt019x.c deleted file mode 100644 index 80f5b1af9be8..000000000000 --- a/sound/isa/dt019x.c +++ /dev/null | |||
@@ -1,321 +0,0 @@ | |||
1 | |||
2 | /* | ||
3 | dt019x.c - driver for Diamond Technologies DT-0197H based soundcards. | ||
4 | Copyright (C) 1999, 2002 by Massimo Piccioni <dafastidio@libero.it> | ||
5 | |||
6 | Generalised for soundcards based on DT-0196 and ALS-007 chips | ||
7 | by Jonathan Woithe <jwoithe@physics.adelaide.edu.au>: June 2002. | ||
8 | |||
9 | This program is free software; you can redistribute it and/or modify | ||
10 | it under the terms of the GNU General Public License as published by | ||
11 | the Free Software Foundation; either version 2 of the License, or | ||
12 | (at your option) any later version. | ||
13 | |||
14 | This program is distributed in the hope that it will be useful, | ||
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | GNU General Public License for more details. | ||
18 | |||
19 | You should have received a copy of the GNU General Public License | ||
20 | along with this program; if not, write to the Free Software | ||
21 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | */ | ||
23 | |||
24 | #include <linux/init.h> | ||
25 | #include <linux/wait.h> | ||
26 | #include <linux/pnp.h> | ||
27 | #include <linux/moduleparam.h> | ||
28 | #include <sound/core.h> | ||
29 | #include <sound/initval.h> | ||
30 | #include <sound/mpu401.h> | ||
31 | #include <sound/opl3.h> | ||
32 | #include <sound/sb.h> | ||
33 | |||
34 | #define PFX "dt019x: " | ||
35 | |||
36 | MODULE_AUTHOR("Massimo Piccioni <dafastidio@libero.it>"); | ||
37 | MODULE_DESCRIPTION("Diamond Technologies DT-019X / Avance Logic ALS-007"); | ||
38 | MODULE_LICENSE("GPL"); | ||
39 | MODULE_SUPPORTED_DEVICE("{{Diamond Technologies DT-019X}," | ||
40 | "{Avance Logic ALS-007}}"); | ||
41 | |||
42 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ | ||
43 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ | ||
44 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */ | ||
45 | static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */ | ||
46 | static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */ | ||
47 | static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */ | ||
48 | static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* PnP setup */ | ||
49 | static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* PnP setup */ | ||
50 | static int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* PnP setup */ | ||
51 | |||
52 | module_param_array(index, int, NULL, 0444); | ||
53 | MODULE_PARM_DESC(index, "Index value for DT-019X based soundcard."); | ||
54 | module_param_array(id, charp, NULL, 0444); | ||
55 | MODULE_PARM_DESC(id, "ID string for DT-019X based soundcard."); | ||
56 | module_param_array(enable, bool, NULL, 0444); | ||
57 | MODULE_PARM_DESC(enable, "Enable DT-019X based soundcard."); | ||
58 | |||
59 | struct snd_card_dt019x { | ||
60 | struct pnp_dev *dev; | ||
61 | struct pnp_dev *devmpu; | ||
62 | struct pnp_dev *devopl; | ||
63 | struct snd_sb *chip; | ||
64 | }; | ||
65 | |||
66 | static struct pnp_card_device_id snd_dt019x_pnpids[] = { | ||
67 | /* DT197A30 */ | ||
68 | { .id = "RWB1688", .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" }, } }, | ||
69 | /* DT0196 / ALS-007 */ | ||
70 | { .id = "ALS0007", .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" }, } }, | ||
71 | { .id = "", } | ||
72 | }; | ||
73 | |||
74 | MODULE_DEVICE_TABLE(pnp_card, snd_dt019x_pnpids); | ||
75 | |||
76 | |||
77 | #define DRIVER_NAME "snd-card-dt019x" | ||
78 | |||
79 | |||
80 | static int __devinit snd_card_dt019x_pnp(int dev, struct snd_card_dt019x *acard, | ||
81 | struct pnp_card_link *card, | ||
82 | const struct pnp_card_device_id *pid) | ||
83 | { | ||
84 | struct pnp_dev *pdev; | ||
85 | int err; | ||
86 | |||
87 | acard->dev = pnp_request_card_device(card, pid->devs[0].id, NULL); | ||
88 | if (acard->dev == NULL) | ||
89 | return -ENODEV; | ||
90 | |||
91 | acard->devmpu = pnp_request_card_device(card, pid->devs[1].id, NULL); | ||
92 | acard->devopl = pnp_request_card_device(card, pid->devs[2].id, NULL); | ||
93 | |||
94 | pdev = acard->dev; | ||
95 | |||
96 | err = pnp_activate_dev(pdev); | ||
97 | if (err < 0) { | ||
98 | snd_printk(KERN_ERR PFX "DT-019X AUDIO pnp configure failure\n"); | ||
99 | return err; | ||
100 | } | ||
101 | |||
102 | port[dev] = pnp_port_start(pdev, 0); | ||
103 | dma8[dev] = pnp_dma(pdev, 0); | ||
104 | irq[dev] = pnp_irq(pdev, 0); | ||
105 | snd_printdd("dt019x: found audio interface: port=0x%lx, irq=0x%x, dma=0x%x\n", | ||
106 | port[dev],irq[dev],dma8[dev]); | ||
107 | |||
108 | pdev = acard->devmpu; | ||
109 | if (pdev != NULL) { | ||
110 | err = pnp_activate_dev(pdev); | ||
111 | if (err < 0) { | ||
112 | pnp_release_card_device(pdev); | ||
113 | snd_printk(KERN_ERR PFX "DT-019X MPU401 pnp configure failure, skipping\n"); | ||
114 | goto __mpu_error; | ||
115 | } | ||
116 | mpu_port[dev] = pnp_port_start(pdev, 0); | ||
117 | mpu_irq[dev] = pnp_irq(pdev, 0); | ||
118 | snd_printdd("dt019x: found MPU-401: port=0x%lx, irq=0x%x\n", | ||
119 | mpu_port[dev],mpu_irq[dev]); | ||
120 | } else { | ||
121 | __mpu_error: | ||
122 | acard->devmpu = NULL; | ||
123 | mpu_port[dev] = -1; | ||
124 | } | ||
125 | |||
126 | pdev = acard->devopl; | ||
127 | if (pdev != NULL) { | ||
128 | err = pnp_activate_dev(pdev); | ||
129 | if (err < 0) { | ||
130 | pnp_release_card_device(pdev); | ||
131 | snd_printk(KERN_ERR PFX "DT-019X OPL3 pnp configure failure, skipping\n"); | ||
132 | goto __fm_error; | ||
133 | } | ||
134 | fm_port[dev] = pnp_port_start(pdev, 0); | ||
135 | snd_printdd("dt019x: found OPL3 synth: port=0x%lx\n",fm_port[dev]); | ||
136 | } else { | ||
137 | __fm_error: | ||
138 | acard->devopl = NULL; | ||
139 | fm_port[dev] = -1; | ||
140 | } | ||
141 | |||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | static int __devinit snd_card_dt019x_probe(int dev, struct pnp_card_link *pcard, const struct pnp_card_device_id *pid) | ||
146 | { | ||
147 | int error; | ||
148 | struct snd_sb *chip; | ||
149 | struct snd_card *card; | ||
150 | struct snd_card_dt019x *acard; | ||
151 | struct snd_opl3 *opl3; | ||
152 | |||
153 | error = snd_card_create(index[dev], id[dev], THIS_MODULE, | ||
154 | sizeof(struct snd_card_dt019x), &card); | ||
155 | if (error < 0) | ||
156 | return error; | ||
157 | acard = card->private_data; | ||
158 | |||
159 | snd_card_set_dev(card, &pcard->card->dev); | ||
160 | if ((error = snd_card_dt019x_pnp(dev, acard, pcard, pid))) { | ||
161 | snd_card_free(card); | ||
162 | return error; | ||
163 | } | ||
164 | |||
165 | if ((error = snd_sbdsp_create(card, port[dev], | ||
166 | irq[dev], | ||
167 | snd_sb16dsp_interrupt, | ||
168 | dma8[dev], | ||
169 | -1, | ||
170 | SB_HW_DT019X, | ||
171 | &chip)) < 0) { | ||
172 | snd_card_free(card); | ||
173 | return error; | ||
174 | } | ||
175 | acard->chip = chip; | ||
176 | |||
177 | strcpy(card->driver, "DT-019X"); | ||
178 | strcpy(card->shortname, "Diamond Tech. DT-019X"); | ||
179 | sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d", | ||
180 | card->shortname, chip->name, chip->port, | ||
181 | irq[dev], dma8[dev]); | ||
182 | |||
183 | if ((error = snd_sb16dsp_pcm(chip, 0, NULL)) < 0) { | ||
184 | snd_card_free(card); | ||
185 | return error; | ||
186 | } | ||
187 | if ((error = snd_sbmixer_new(chip)) < 0) { | ||
188 | snd_card_free(card); | ||
189 | return error; | ||
190 | } | ||
191 | |||
192 | if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) { | ||
193 | if (mpu_irq[dev] == SNDRV_AUTO_IRQ) | ||
194 | mpu_irq[dev] = -1; | ||
195 | if (snd_mpu401_uart_new(card, 0, | ||
196 | /* MPU401_HW_SB,*/ | ||
197 | MPU401_HW_MPU401, | ||
198 | mpu_port[dev], 0, | ||
199 | mpu_irq[dev], | ||
200 | mpu_irq[dev] >= 0 ? IRQF_DISABLED : 0, | ||
201 | NULL) < 0) | ||
202 | snd_printk(KERN_ERR PFX "no MPU-401 device at 0x%lx ?\n", mpu_port[dev]); | ||
203 | } | ||
204 | |||
205 | if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) { | ||
206 | if (snd_opl3_create(card, | ||
207 | fm_port[dev], | ||
208 | fm_port[dev] + 2, | ||
209 | OPL3_HW_AUTO, 0, &opl3) < 0) { | ||
210 | snd_printk(KERN_ERR PFX "no OPL device at 0x%lx-0x%lx ?\n", | ||
211 | fm_port[dev], fm_port[dev] + 2); | ||
212 | } else { | ||
213 | if ((error = snd_opl3_timer_new(opl3, 0, 1)) < 0) { | ||
214 | snd_card_free(card); | ||
215 | return error; | ||
216 | } | ||
217 | if ((error = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) { | ||
218 | snd_card_free(card); | ||
219 | return error; | ||
220 | } | ||
221 | } | ||
222 | } | ||
223 | |||
224 | if ((error = snd_card_register(card)) < 0) { | ||
225 | snd_card_free(card); | ||
226 | return error; | ||
227 | } | ||
228 | pnp_set_card_drvdata(pcard, card); | ||
229 | return 0; | ||
230 | } | ||
231 | |||
232 | static unsigned int __devinitdata dt019x_devices; | ||
233 | |||
234 | static int __devinit snd_dt019x_pnp_probe(struct pnp_card_link *card, | ||
235 | const struct pnp_card_device_id *pid) | ||
236 | { | ||
237 | static int dev; | ||
238 | int res; | ||
239 | |||
240 | for ( ; dev < SNDRV_CARDS; dev++) { | ||
241 | if (!enable[dev]) | ||
242 | continue; | ||
243 | res = snd_card_dt019x_probe(dev, card, pid); | ||
244 | if (res < 0) | ||
245 | return res; | ||
246 | dev++; | ||
247 | dt019x_devices++; | ||
248 | return 0; | ||
249 | } | ||
250 | return -ENODEV; | ||
251 | } | ||
252 | |||
253 | static void __devexit snd_dt019x_pnp_remove(struct pnp_card_link * pcard) | ||
254 | { | ||
255 | snd_card_free(pnp_get_card_drvdata(pcard)); | ||
256 | pnp_set_card_drvdata(pcard, NULL); | ||
257 | } | ||
258 | |||
259 | #ifdef CONFIG_PM | ||
260 | static int snd_dt019x_pnp_suspend(struct pnp_card_link *pcard, pm_message_t state) | ||
261 | { | ||
262 | struct snd_card *card = pnp_get_card_drvdata(pcard); | ||
263 | struct snd_card_dt019x *acard = card->private_data; | ||
264 | struct snd_sb *chip = acard->chip; | ||
265 | |||
266 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); | ||
267 | snd_pcm_suspend_all(chip->pcm); | ||
268 | snd_sbmixer_suspend(chip); | ||
269 | return 0; | ||
270 | } | ||
271 | |||
272 | static int snd_dt019x_pnp_resume(struct pnp_card_link *pcard) | ||
273 | { | ||
274 | struct snd_card *card = pnp_get_card_drvdata(pcard); | ||
275 | struct snd_card_dt019x *acard = card->private_data; | ||
276 | struct snd_sb *chip = acard->chip; | ||
277 | |||
278 | snd_sbdsp_reset(chip); | ||
279 | snd_sbmixer_resume(chip); | ||
280 | snd_power_change_state(card, SNDRV_CTL_POWER_D0); | ||
281 | return 0; | ||
282 | } | ||
283 | #endif | ||
284 | |||
285 | static struct pnp_card_driver dt019x_pnpc_driver = { | ||
286 | .flags = PNP_DRIVER_RES_DISABLE, | ||
287 | .name = "dt019x", | ||
288 | .id_table = snd_dt019x_pnpids, | ||
289 | .probe = snd_dt019x_pnp_probe, | ||
290 | .remove = __devexit_p(snd_dt019x_pnp_remove), | ||
291 | #ifdef CONFIG_PM | ||
292 | .suspend = snd_dt019x_pnp_suspend, | ||
293 | .resume = snd_dt019x_pnp_resume, | ||
294 | #endif | ||
295 | }; | ||
296 | |||
297 | static int __init alsa_card_dt019x_init(void) | ||
298 | { | ||
299 | int err; | ||
300 | |||
301 | err = pnp_register_card_driver(&dt019x_pnpc_driver); | ||
302 | if (err) | ||
303 | return err; | ||
304 | |||
305 | if (!dt019x_devices) { | ||
306 | pnp_unregister_card_driver(&dt019x_pnpc_driver); | ||
307 | #ifdef MODULE | ||
308 | snd_printk(KERN_ERR "no DT-019X / ALS-007 based soundcards found\n"); | ||
309 | #endif | ||
310 | return -ENODEV; | ||
311 | } | ||
312 | return 0; | ||
313 | } | ||
314 | |||
315 | static void __exit alsa_card_dt019x_exit(void) | ||
316 | { | ||
317 | pnp_unregister_card_driver(&dt019x_pnpc_driver); | ||
318 | } | ||
319 | |||
320 | module_init(alsa_card_dt019x_init) | ||
321 | module_exit(alsa_card_dt019x_exit) | ||
diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c index c8a8da0d4036..a4af53b5c1cf 100644 --- a/sound/isa/opti9xx/opti92x-ad1848.c +++ b/sound/isa/opti9xx/opti92x-ad1848.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <asm/io.h> | 33 | #include <asm/io.h> |
34 | #include <asm/dma.h> | 34 | #include <asm/dma.h> |
35 | #include <sound/core.h> | 35 | #include <sound/core.h> |
36 | #include <sound/tlv.h> | ||
36 | #include <sound/wss.h> | 37 | #include <sound/wss.h> |
37 | #include <sound/mpu401.h> | 38 | #include <sound/mpu401.h> |
38 | #include <sound/opl3.h> | 39 | #include <sound/opl3.h> |
@@ -546,6 +547,93 @@ __skip_mpu: | |||
546 | 547 | ||
547 | #ifdef OPTi93X | 548 | #ifdef OPTi93X |
548 | 549 | ||
550 | static const DECLARE_TLV_DB_SCALE(db_scale_5bit_3db_step, -9300, 300, 0); | ||
551 | static const DECLARE_TLV_DB_SCALE(db_scale_5bit, -4650, 150, 0); | ||
552 | static const DECLARE_TLV_DB_SCALE(db_scale_4bit_12db_max, -3300, 300, 0); | ||
553 | |||
554 | static struct snd_kcontrol_new snd_opti93x_controls[] = { | ||
555 | WSS_DOUBLE("Master Playback Switch", 0, | ||
556 | OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 7, 7, 1, 1), | ||
557 | WSS_DOUBLE_TLV("Master Playback Volume", 0, | ||
558 | OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 1, 1, 31, 1, | ||
559 | db_scale_5bit_3db_step), | ||
560 | WSS_DOUBLE_TLV("PCM Playback Volume", 0, | ||
561 | CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 31, 1, | ||
562 | db_scale_5bit), | ||
563 | WSS_DOUBLE_TLV("FM Playback Volume", 0, | ||
564 | CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 1, 1, 15, 1, | ||
565 | db_scale_4bit_12db_max), | ||
566 | WSS_DOUBLE("Line Playback Switch", 0, | ||
567 | CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1), | ||
568 | WSS_DOUBLE_TLV("Line Playback Volume", 0, | ||
569 | CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 15, 1, | ||
570 | db_scale_4bit_12db_max), | ||
571 | WSS_DOUBLE("Mic Playback Switch", 0, | ||
572 | OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 7, 7, 1, 1), | ||
573 | WSS_DOUBLE_TLV("Mic Playback Volume", 0, | ||
574 | OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 1, 1, 15, 1, | ||
575 | db_scale_4bit_12db_max), | ||
576 | WSS_DOUBLE_TLV("CD Playback Volume", 0, | ||
577 | CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 1, 1, 15, 1, | ||
578 | db_scale_4bit_12db_max), | ||
579 | WSS_DOUBLE("Aux Playback Switch", 0, | ||
580 | OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 7, 7, 1, 1), | ||
581 | WSS_DOUBLE_TLV("Aux Playback Volume", 0, | ||
582 | OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 1, 1, 15, 1, | ||
583 | db_scale_4bit_12db_max), | ||
584 | }; | ||
585 | |||
586 | static int __devinit snd_opti93x_mixer(struct snd_wss *chip) | ||
587 | { | ||
588 | struct snd_card *card; | ||
589 | unsigned int idx; | ||
590 | struct snd_ctl_elem_id id1, id2; | ||
591 | int err; | ||
592 | |||
593 | if (snd_BUG_ON(!chip || !chip->pcm)) | ||
594 | return -EINVAL; | ||
595 | |||
596 | card = chip->card; | ||
597 | |||
598 | strcpy(card->mixername, chip->pcm->name); | ||
599 | |||
600 | memset(&id1, 0, sizeof(id1)); | ||
601 | memset(&id2, 0, sizeof(id2)); | ||
602 | id1.iface = id2.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
603 | /* reassign AUX0 switch to CD */ | ||
604 | strcpy(id1.name, "Aux Playback Switch"); | ||
605 | strcpy(id2.name, "CD Playback Switch"); | ||
606 | err = snd_ctl_rename_id(card, &id1, &id2); | ||
607 | if (err < 0) { | ||
608 | snd_printk(KERN_ERR "Cannot rename opti93x control\n"); | ||
609 | return err; | ||
610 | } | ||
611 | /* reassign AUX1 switch to FM */ | ||
612 | strcpy(id1.name, "Aux Playback Switch"); id1.index = 1; | ||
613 | strcpy(id2.name, "FM Playback Switch"); | ||
614 | err = snd_ctl_rename_id(card, &id1, &id2); | ||
615 | if (err < 0) { | ||
616 | snd_printk(KERN_ERR "Cannot rename opti93x control\n"); | ||
617 | return err; | ||
618 | } | ||
619 | /* remove AUX1 volume */ | ||
620 | strcpy(id1.name, "Aux Playback Volume"); id1.index = 1; | ||
621 | snd_ctl_remove_id(card, &id1); | ||
622 | |||
623 | /* Replace WSS volume controls with OPTi93x volume controls */ | ||
624 | id1.index = 0; | ||
625 | for (idx = 0; idx < ARRAY_SIZE(snd_opti93x_controls); idx++) { | ||
626 | strcpy(id1.name, snd_opti93x_controls[idx].name); | ||
627 | snd_ctl_remove_id(card, &id1); | ||
628 | |||
629 | err = snd_ctl_add(card, | ||
630 | snd_ctl_new1(&snd_opti93x_controls[idx], chip)); | ||
631 | if (err < 0) | ||
632 | return err; | ||
633 | } | ||
634 | return 0; | ||
635 | } | ||
636 | |||
549 | static irqreturn_t snd_opti93x_interrupt(int irq, void *dev_id) | 637 | static irqreturn_t snd_opti93x_interrupt(int irq, void *dev_id) |
550 | { | 638 | { |
551 | struct snd_opti9xx *chip = dev_id; | 639 | struct snd_opti9xx *chip = dev_id; |
@@ -754,6 +842,11 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card) | |||
754 | error = snd_wss_mixer(codec); | 842 | error = snd_wss_mixer(codec); |
755 | if (error < 0) | 843 | if (error < 0) |
756 | return error; | 844 | return error; |
845 | #ifdef OPTi93X | ||
846 | error = snd_opti93x_mixer(codec); | ||
847 | if (error < 0) | ||
848 | return error; | ||
849 | #endif | ||
757 | #ifdef CS4231 | 850 | #ifdef CS4231 |
758 | error = snd_wss_timer(codec, 0, &timer); | 851 | error = snd_wss_timer(codec, 0, &timer); |
759 | if (error < 0) | 852 | if (error < 0) |
diff --git a/sound/isa/sb/Makefile b/sound/isa/sb/Makefile index faeffceb01b7..af3669681788 100644 --- a/sound/isa/sb/Makefile +++ b/sound/isa/sb/Makefile | |||
@@ -12,6 +12,7 @@ snd-sb16-objs := sb16.o | |||
12 | snd-sbawe-objs := sbawe.o emu8000.o | 12 | snd-sbawe-objs := sbawe.o emu8000.o |
13 | snd-emu8000-synth-objs := emu8000_synth.o emu8000_callback.o emu8000_patch.o emu8000_pcm.o | 13 | snd-emu8000-synth-objs := emu8000_synth.o emu8000_callback.o emu8000_patch.o emu8000_pcm.o |
14 | snd-es968-objs := es968.o | 14 | snd-es968-objs := es968.o |
15 | snd-jazz16-objs := jazz16.o | ||
15 | 16 | ||
16 | # Toplevel Module Dependency | 17 | # Toplevel Module Dependency |
17 | obj-$(CONFIG_SND_SB_COMMON) += snd-sb-common.o | 18 | obj-$(CONFIG_SND_SB_COMMON) += snd-sb-common.o |
@@ -21,6 +22,7 @@ obj-$(CONFIG_SND_SB8) += snd-sb8.o | |||
21 | obj-$(CONFIG_SND_SB16) += snd-sb16.o | 22 | obj-$(CONFIG_SND_SB16) += snd-sb16.o |
22 | obj-$(CONFIG_SND_SBAWE) += snd-sbawe.o | 23 | obj-$(CONFIG_SND_SBAWE) += snd-sbawe.o |
23 | obj-$(CONFIG_SND_ES968) += snd-es968.o | 24 | obj-$(CONFIG_SND_ES968) += snd-es968.o |
25 | obj-$(CONFIG_SND_JAZZ16) += snd-jazz16.o | ||
24 | ifeq ($(CONFIG_SND_SB16_CSP),y) | 26 | ifeq ($(CONFIG_SND_SB16_CSP),y) |
25 | obj-$(CONFIG_SND_SB16) += snd-sb16-csp.o | 27 | obj-$(CONFIG_SND_SB16) += snd-sb16-csp.o |
26 | obj-$(CONFIG_SND_SBAWE) += snd-sb16-csp.o | 28 | obj-$(CONFIG_SND_SBAWE) += snd-sb16-csp.o |
diff --git a/sound/isa/sb/jazz16.c b/sound/isa/sb/jazz16.c new file mode 100644 index 000000000000..8d21a3feda3a --- /dev/null +++ b/sound/isa/sb/jazz16.c | |||
@@ -0,0 +1,404 @@ | |||
1 | |||
2 | /* | ||
3 | * jazz16.c - driver for Media Vision Jazz16 based soundcards. | ||
4 | * Copyright (C) 2009 Krzysztof Helt <krzysztof.h1@wp.pl> | ||
5 | * Based on patches posted by Rask Ingemann Lambertsen and Rene Herman. | ||
6 | * Based on OSS Sound Blaster driver. | ||
7 | * | ||
8 | * This file is subject to the terms and conditions of the GNU General Public | ||
9 | * License. See the file COPYING in the main directory of this archive for | ||
10 | * more details. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <linux/init.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/io.h> | ||
17 | #include <asm/dma.h> | ||
18 | #include <linux/isa.h> | ||
19 | #include <sound/core.h> | ||
20 | #include <sound/mpu401.h> | ||
21 | #include <sound/opl3.h> | ||
22 | #include <sound/sb.h> | ||
23 | #define SNDRV_LEGACY_FIND_FREE_IRQ | ||
24 | #define SNDRV_LEGACY_FIND_FREE_DMA | ||
25 | #include <sound/initval.h> | ||
26 | |||
27 | #define PFX "jazz16: " | ||
28 | |||
29 | MODULE_DESCRIPTION("Media Vision Jazz16"); | ||
30 | MODULE_SUPPORTED_DEVICE("{{Media Vision ??? }," | ||
31 | "{RTL,RTL3000}}"); | ||
32 | |||
33 | MODULE_AUTHOR("Krzysztof Helt <krzysztof.h1@wp.pl>"); | ||
34 | MODULE_LICENSE("GPL"); | ||
35 | |||
36 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ | ||
37 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ | ||
38 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */ | ||
39 | static unsigned long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; | ||
40 | static unsigned long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; | ||
41 | static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; | ||
42 | static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; | ||
43 | static int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; | ||
44 | static int dma16[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; | ||
45 | |||
46 | module_param_array(index, int, NULL, 0444); | ||
47 | MODULE_PARM_DESC(index, "Index value for Media Vision Jazz16 based soundcard."); | ||
48 | module_param_array(id, charp, NULL, 0444); | ||
49 | MODULE_PARM_DESC(id, "ID string for Media Vision Jazz16 based soundcard."); | ||
50 | module_param_array(enable, bool, NULL, 0444); | ||
51 | MODULE_PARM_DESC(enable, "Enable Media Vision Jazz16 based soundcard."); | ||
52 | module_param_array(port, long, NULL, 0444); | ||
53 | MODULE_PARM_DESC(port, "Port # for jazz16 driver."); | ||
54 | module_param_array(mpu_port, long, NULL, 0444); | ||
55 | MODULE_PARM_DESC(mpu_port, "MPU-401 port # for jazz16 driver."); | ||
56 | module_param_array(irq, int, NULL, 0444); | ||
57 | MODULE_PARM_DESC(irq, "IRQ # for jazz16 driver."); | ||
58 | module_param_array(mpu_irq, int, NULL, 0444); | ||
59 | MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for jazz16 driver."); | ||
60 | module_param_array(dma8, int, NULL, 0444); | ||
61 | MODULE_PARM_DESC(dma8, "DMA8 # for jazz16 driver."); | ||
62 | module_param_array(dma16, int, NULL, 0444); | ||
63 | MODULE_PARM_DESC(dma16, "DMA16 # for jazz16 driver."); | ||
64 | |||
65 | #define SB_JAZZ16_WAKEUP 0xaf | ||
66 | #define SB_JAZZ16_SET_PORTS 0x50 | ||
67 | #define SB_DSP_GET_JAZZ_BRD_REV 0xfa | ||
68 | #define SB_JAZZ16_SET_DMAINTR 0xfb | ||
69 | #define SB_DSP_GET_JAZZ_MODEL 0xfe | ||
70 | |||
71 | struct snd_card_jazz16 { | ||
72 | struct snd_sb *chip; | ||
73 | }; | ||
74 | |||
75 | static irqreturn_t jazz16_interrupt(int irq, void *chip) | ||
76 | { | ||
77 | return snd_sb8dsp_interrupt(chip); | ||
78 | } | ||
79 | |||
80 | static int __devinit jazz16_configure_ports(unsigned long port, | ||
81 | unsigned long mpu_port, int idx) | ||
82 | { | ||
83 | unsigned char val; | ||
84 | |||
85 | if (!request_region(0x201, 1, "jazz16 config")) { | ||
86 | snd_printk(KERN_ERR "config port region is already in use.\n"); | ||
87 | return -EBUSY; | ||
88 | } | ||
89 | outb(SB_JAZZ16_WAKEUP - idx, 0x201); | ||
90 | udelay(100); | ||
91 | outb(SB_JAZZ16_SET_PORTS + idx, 0x201); | ||
92 | udelay(100); | ||
93 | val = port & 0x70; | ||
94 | val |= (mpu_port & 0x30) >> 4; | ||
95 | outb(val, 0x201); | ||
96 | |||
97 | release_region(0x201, 1); | ||
98 | return 0; | ||
99 | } | ||
100 | |||
101 | static int __devinit jazz16_detect_board(unsigned long port, | ||
102 | unsigned long mpu_port) | ||
103 | { | ||
104 | int err; | ||
105 | int val; | ||
106 | struct snd_sb chip; | ||
107 | |||
108 | if (!request_region(port, 0x10, "jazz16")) { | ||
109 | snd_printk(KERN_ERR "I/O port region is already in use.\n"); | ||
110 | return -EBUSY; | ||
111 | } | ||
112 | /* just to call snd_sbdsp_command/reset/get_byte() */ | ||
113 | chip.port = port; | ||
114 | |||
115 | err = snd_sbdsp_reset(&chip); | ||
116 | if (err < 0) | ||
117 | for (val = 0; val < 4; val++) { | ||
118 | err = jazz16_configure_ports(port, mpu_port, val); | ||
119 | if (err < 0) | ||
120 | break; | ||
121 | |||
122 | err = snd_sbdsp_reset(&chip); | ||
123 | if (!err) | ||
124 | break; | ||
125 | } | ||
126 | if (err < 0) { | ||
127 | err = -ENODEV; | ||
128 | goto err_unmap; | ||
129 | } | ||
130 | if (!snd_sbdsp_command(&chip, SB_DSP_GET_JAZZ_BRD_REV)) { | ||
131 | err = -EBUSY; | ||
132 | goto err_unmap; | ||
133 | } | ||
134 | val = snd_sbdsp_get_byte(&chip); | ||
135 | if (val >= 0x30) | ||
136 | snd_sbdsp_get_byte(&chip); | ||
137 | |||
138 | if ((val & 0xf0) != 0x10) { | ||
139 | err = -ENODEV; | ||
140 | goto err_unmap; | ||
141 | } | ||
142 | if (!snd_sbdsp_command(&chip, SB_DSP_GET_JAZZ_MODEL)) { | ||
143 | err = -EBUSY; | ||
144 | goto err_unmap; | ||
145 | } | ||
146 | snd_sbdsp_get_byte(&chip); | ||
147 | err = snd_sbdsp_get_byte(&chip); | ||
148 | snd_printd("Media Vision Jazz16 board detected: rev 0x%x, model 0x%x\n", | ||
149 | val, err); | ||
150 | |||
151 | err = 0; | ||
152 | |||
153 | err_unmap: | ||
154 | release_region(port, 0x10); | ||
155 | return err; | ||
156 | } | ||
157 | |||
158 | static int __devinit jazz16_configure_board(struct snd_sb *chip, int mpu_irq) | ||
159 | { | ||
160 | static unsigned char jazz_irq_bits[] = { 0, 0, 2, 3, 0, 1, 0, 4, | ||
161 | 0, 2, 5, 0, 0, 0, 0, 6 }; | ||
162 | static unsigned char jazz_dma_bits[] = { 0, 1, 0, 2, 0, 3, 0, 4 }; | ||
163 | |||
164 | if (jazz_dma_bits[chip->dma8] == 0 || | ||
165 | jazz_dma_bits[chip->dma16] == 0 || | ||
166 | jazz_irq_bits[chip->irq] == 0) | ||
167 | return -EINVAL; | ||
168 | |||
169 | if (!snd_sbdsp_command(chip, SB_JAZZ16_SET_DMAINTR)) | ||
170 | return -EBUSY; | ||
171 | |||
172 | if (!snd_sbdsp_command(chip, | ||
173 | jazz_dma_bits[chip->dma8] | | ||
174 | (jazz_dma_bits[chip->dma16] << 4))) | ||
175 | return -EBUSY; | ||
176 | |||
177 | if (!snd_sbdsp_command(chip, | ||
178 | jazz_irq_bits[chip->irq] | | ||
179 | (jazz_irq_bits[mpu_irq] << 4))) | ||
180 | return -EBUSY; | ||
181 | |||
182 | return 0; | ||
183 | } | ||
184 | |||
185 | static int __devinit snd_jazz16_match(struct device *devptr, unsigned int dev) | ||
186 | { | ||
187 | if (!enable[dev]) | ||
188 | return 0; | ||
189 | if (port[dev] == SNDRV_AUTO_PORT) { | ||
190 | snd_printk(KERN_ERR "please specify port\n"); | ||
191 | return 0; | ||
192 | } else if (port[dev] == 0x200 || (port[dev] & ~0x270)) { | ||
193 | snd_printk(KERN_ERR "incorrect port specified\n"); | ||
194 | return 0; | ||
195 | } | ||
196 | if (dma8[dev] != SNDRV_AUTO_DMA && | ||
197 | dma8[dev] != 1 && dma8[dev] != 3) { | ||
198 | snd_printk(KERN_ERR "dma8 must be 1 or 3\n"); | ||
199 | return 0; | ||
200 | } | ||
201 | if (dma16[dev] != SNDRV_AUTO_DMA && | ||
202 | dma16[dev] != 5 && dma16[dev] != 7) { | ||
203 | snd_printk(KERN_ERR "dma16 must be 5 or 7\n"); | ||
204 | return 0; | ||
205 | } | ||
206 | if (mpu_port[dev] != SNDRV_AUTO_PORT && | ||
207 | (mpu_port[dev] & ~0x030) != 0x300) { | ||
208 | snd_printk(KERN_ERR "incorrect mpu_port specified\n"); | ||
209 | return 0; | ||
210 | } | ||
211 | if (mpu_irq[dev] != SNDRV_AUTO_DMA && | ||
212 | mpu_irq[dev] != 2 && mpu_irq[dev] != 3 && | ||
213 | mpu_irq[dev] != 5 && mpu_irq[dev] != 7) { | ||
214 | snd_printk(KERN_ERR "mpu_irq must be 2, 3, 5 or 7\n"); | ||
215 | return 0; | ||
216 | } | ||
217 | return 1; | ||
218 | } | ||
219 | |||
220 | static int __devinit snd_jazz16_probe(struct device *devptr, unsigned int dev) | ||
221 | { | ||
222 | struct snd_card *card; | ||
223 | struct snd_card_jazz16 *jazz16; | ||
224 | struct snd_sb *chip; | ||
225 | struct snd_opl3 *opl3; | ||
226 | static int possible_irqs[] = {2, 3, 5, 7, 9, 10, 15, -1}; | ||
227 | static int possible_dmas8[] = {1, 3, -1}; | ||
228 | static int possible_dmas16[] = {5, 7, -1}; | ||
229 | int err, xirq, xdma8, xdma16, xmpu_port, xmpu_irq; | ||
230 | |||
231 | err = snd_card_create(index[dev], id[dev], THIS_MODULE, | ||
232 | sizeof(struct snd_card_jazz16), &card); | ||
233 | if (err < 0) | ||
234 | return err; | ||
235 | |||
236 | jazz16 = card->private_data; | ||
237 | |||
238 | xirq = irq[dev]; | ||
239 | if (xirq == SNDRV_AUTO_IRQ) { | ||
240 | xirq = snd_legacy_find_free_irq(possible_irqs); | ||
241 | if (xirq < 0) { | ||
242 | snd_printk(KERN_ERR "unable to find a free IRQ\n"); | ||
243 | err = -EBUSY; | ||
244 | goto err_free; | ||
245 | } | ||
246 | } | ||
247 | xdma8 = dma8[dev]; | ||
248 | if (xdma8 == SNDRV_AUTO_DMA) { | ||
249 | xdma8 = snd_legacy_find_free_dma(possible_dmas8); | ||
250 | if (xdma8 < 0) { | ||
251 | snd_printk(KERN_ERR "unable to find a free DMA8\n"); | ||
252 | err = -EBUSY; | ||
253 | goto err_free; | ||
254 | } | ||
255 | } | ||
256 | xdma16 = dma16[dev]; | ||
257 | if (xdma16 == SNDRV_AUTO_DMA) { | ||
258 | xdma16 = snd_legacy_find_free_dma(possible_dmas16); | ||
259 | if (xdma16 < 0) { | ||
260 | snd_printk(KERN_ERR "unable to find a free DMA16\n"); | ||
261 | err = -EBUSY; | ||
262 | goto err_free; | ||
263 | } | ||
264 | } | ||
265 | |||
266 | xmpu_port = mpu_port[dev]; | ||
267 | if (xmpu_port == SNDRV_AUTO_PORT) | ||
268 | xmpu_port = 0; | ||
269 | err = jazz16_detect_board(port[dev], xmpu_port); | ||
270 | if (err < 0) { | ||
271 | printk(KERN_ERR "Media Vision Jazz16 board not detected\n"); | ||
272 | goto err_free; | ||
273 | } | ||
274 | err = snd_sbdsp_create(card, port[dev], irq[dev], | ||
275 | jazz16_interrupt, | ||
276 | dma8[dev], dma16[dev], | ||
277 | SB_HW_JAZZ16, | ||
278 | &chip); | ||
279 | if (err < 0) | ||
280 | goto err_free; | ||
281 | |||
282 | xmpu_irq = mpu_irq[dev]; | ||
283 | if (xmpu_irq == SNDRV_AUTO_IRQ || mpu_port[dev] == SNDRV_AUTO_PORT) | ||
284 | xmpu_irq = 0; | ||
285 | err = jazz16_configure_board(chip, xmpu_irq); | ||
286 | if (err < 0) { | ||
287 | printk(KERN_ERR "Media Vision Jazz16 configuration failed\n"); | ||
288 | goto err_free; | ||
289 | } | ||
290 | |||
291 | jazz16->chip = chip; | ||
292 | |||
293 | strcpy(card->driver, "jazz16"); | ||
294 | strcpy(card->shortname, "Media Vision Jazz16"); | ||
295 | sprintf(card->longname, | ||
296 | "Media Vision Jazz16 at 0x%lx, irq %d, dma8 %d, dma16 %d", | ||
297 | port[dev], xirq, xdma8, xdma16); | ||
298 | |||
299 | err = snd_sb8dsp_pcm(chip, 0, NULL); | ||
300 | if (err < 0) | ||
301 | goto err_free; | ||
302 | err = snd_sbmixer_new(chip); | ||
303 | if (err < 0) | ||
304 | goto err_free; | ||
305 | |||
306 | err = snd_opl3_create(card, chip->port, chip->port + 2, | ||
307 | OPL3_HW_AUTO, 1, &opl3); | ||
308 | if (err < 0) | ||
309 | snd_printk(KERN_WARNING "no OPL device at 0x%lx-0x%lx\n", | ||
310 | chip->port, chip->port + 2); | ||
311 | else { | ||
312 | err = snd_opl3_hwdep_new(opl3, 0, 1, NULL); | ||
313 | if (err < 0) | ||
314 | goto err_free; | ||
315 | } | ||
316 | if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) { | ||
317 | if (mpu_irq[dev] == SNDRV_AUTO_IRQ) | ||
318 | mpu_irq[dev] = -1; | ||
319 | |||
320 | if (snd_mpu401_uart_new(card, 0, | ||
321 | MPU401_HW_MPU401, | ||
322 | mpu_port[dev], 0, | ||
323 | mpu_irq[dev], | ||
324 | mpu_irq[dev] >= 0 ? IRQF_DISABLED : 0, | ||
325 | NULL) < 0) | ||
326 | snd_printk(KERN_ERR "no MPU-401 device at 0x%lx\n", | ||
327 | mpu_port[dev]); | ||
328 | } | ||
329 | |||
330 | snd_card_set_dev(card, devptr); | ||
331 | |||
332 | err = snd_card_register(card); | ||
333 | if (err < 0) | ||
334 | goto err_free; | ||
335 | |||
336 | dev_set_drvdata(devptr, card); | ||
337 | return 0; | ||
338 | |||
339 | err_free: | ||
340 | snd_card_free(card); | ||
341 | return err; | ||
342 | } | ||
343 | |||
344 | static int __devexit snd_jazz16_remove(struct device *devptr, unsigned int dev) | ||
345 | { | ||
346 | struct snd_card *card = dev_get_drvdata(devptr); | ||
347 | |||
348 | dev_set_drvdata(devptr, NULL); | ||
349 | snd_card_free(card); | ||
350 | return 0; | ||
351 | } | ||
352 | |||
353 | #ifdef CONFIG_PM | ||
354 | static int snd_jazz16_suspend(struct device *pdev, unsigned int n, | ||
355 | pm_message_t state) | ||
356 | { | ||
357 | struct snd_card *card = dev_get_drvdata(pdev); | ||
358 | struct snd_card_jazz16 *acard = card->private_data; | ||
359 | struct snd_sb *chip = acard->chip; | ||
360 | |||
361 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); | ||
362 | snd_pcm_suspend_all(chip->pcm); | ||
363 | snd_sbmixer_suspend(chip); | ||
364 | return 0; | ||
365 | } | ||
366 | |||
367 | static int snd_jazz16_resume(struct device *pdev, unsigned int n) | ||
368 | { | ||
369 | struct snd_card *card = dev_get_drvdata(pdev); | ||
370 | struct snd_card_jazz16 *acard = card->private_data; | ||
371 | struct snd_sb *chip = acard->chip; | ||
372 | |||
373 | snd_sbdsp_reset(chip); | ||
374 | snd_sbmixer_resume(chip); | ||
375 | snd_power_change_state(card, SNDRV_CTL_POWER_D0); | ||
376 | return 0; | ||
377 | } | ||
378 | #endif | ||
379 | |||
380 | static struct isa_driver snd_jazz16_driver = { | ||
381 | .match = snd_jazz16_match, | ||
382 | .probe = snd_jazz16_probe, | ||
383 | .remove = __devexit_p(snd_jazz16_remove), | ||
384 | #ifdef CONFIG_PM | ||
385 | .suspend = snd_jazz16_suspend, | ||
386 | .resume = snd_jazz16_resume, | ||
387 | #endif | ||
388 | .driver = { | ||
389 | .name = "jazz16" | ||
390 | }, | ||
391 | }; | ||
392 | |||
393 | static int __init alsa_card_jazz16_init(void) | ||
394 | { | ||
395 | return isa_register_driver(&snd_jazz16_driver, SNDRV_CARDS); | ||
396 | } | ||
397 | |||
398 | static void __exit alsa_card_jazz16_exit(void) | ||
399 | { | ||
400 | isa_unregister_driver(&snd_jazz16_driver); | ||
401 | } | ||
402 | |||
403 | module_init(alsa_card_jazz16_init) | ||
404 | module_exit(alsa_card_jazz16_exit) | ||
diff --git a/sound/isa/sb/sb8_main.c b/sound/isa/sb/sb8_main.c index 658d55769c9c..7d84c9f34dc9 100644 --- a/sound/isa/sb/sb8_main.c +++ b/sound/isa/sb/sb8_main.c | |||
@@ -106,9 +106,21 @@ static int snd_sb8_playback_prepare(struct snd_pcm_substream *substream) | |||
106 | struct snd_sb *chip = snd_pcm_substream_chip(substream); | 106 | struct snd_sb *chip = snd_pcm_substream_chip(substream); |
107 | struct snd_pcm_runtime *runtime = substream->runtime; | 107 | struct snd_pcm_runtime *runtime = substream->runtime; |
108 | unsigned int mixreg, rate, size, count; | 108 | unsigned int mixreg, rate, size, count; |
109 | unsigned char format; | ||
110 | unsigned char stereo = runtime->channels > 1; | ||
111 | int dma; | ||
109 | 112 | ||
110 | rate = runtime->rate; | 113 | rate = runtime->rate; |
111 | switch (chip->hardware) { | 114 | switch (chip->hardware) { |
115 | case SB_HW_JAZZ16: | ||
116 | if (runtime->format == SNDRV_PCM_FORMAT_S16_LE) { | ||
117 | if (chip->mode & SB_MODE_CAPTURE_16) | ||
118 | return -EBUSY; | ||
119 | else | ||
120 | chip->mode |= SB_MODE_PLAYBACK_16; | ||
121 | } | ||
122 | chip->playback_format = SB_DSP_LO_OUTPUT_AUTO; | ||
123 | break; | ||
112 | case SB_HW_PRO: | 124 | case SB_HW_PRO: |
113 | if (runtime->channels > 1) { | 125 | if (runtime->channels > 1) { |
114 | if (snd_BUG_ON(rate != SB8_RATE(11025) && | 126 | if (snd_BUG_ON(rate != SB8_RATE(11025) && |
@@ -133,11 +145,21 @@ static int snd_sb8_playback_prepare(struct snd_pcm_substream *substream) | |||
133 | default: | 145 | default: |
134 | return -EINVAL; | 146 | return -EINVAL; |
135 | } | 147 | } |
148 | if (chip->mode & SB_MODE_PLAYBACK_16) { | ||
149 | format = stereo ? SB_DSP_STEREO_16BIT : SB_DSP_MONO_16BIT; | ||
150 | dma = chip->dma16; | ||
151 | } else { | ||
152 | format = stereo ? SB_DSP_STEREO_8BIT : SB_DSP_MONO_8BIT; | ||
153 | chip->mode |= SB_MODE_PLAYBACK_8; | ||
154 | dma = chip->dma8; | ||
155 | } | ||
136 | size = chip->p_dma_size = snd_pcm_lib_buffer_bytes(substream); | 156 | size = chip->p_dma_size = snd_pcm_lib_buffer_bytes(substream); |
137 | count = chip->p_period_size = snd_pcm_lib_period_bytes(substream); | 157 | count = chip->p_period_size = snd_pcm_lib_period_bytes(substream); |
138 | spin_lock_irqsave(&chip->reg_lock, flags); | 158 | spin_lock_irqsave(&chip->reg_lock, flags); |
139 | snd_sbdsp_command(chip, SB_DSP_SPEAKER_ON); | 159 | snd_sbdsp_command(chip, SB_DSP_SPEAKER_ON); |
140 | if (runtime->channels > 1) { | 160 | if (chip->hardware == SB_HW_JAZZ16) |
161 | snd_sbdsp_command(chip, format); | ||
162 | else if (stereo) { | ||
141 | /* set playback stereo mode */ | 163 | /* set playback stereo mode */ |
142 | spin_lock(&chip->mixer_lock); | 164 | spin_lock(&chip->mixer_lock); |
143 | mixreg = snd_sbmixer_read(chip, SB_DSP_STEREO_SW); | 165 | mixreg = snd_sbmixer_read(chip, SB_DSP_STEREO_SW); |
@@ -147,15 +169,14 @@ static int snd_sb8_playback_prepare(struct snd_pcm_substream *substream) | |||
147 | /* Soundblaster hardware programming reference guide, 3-23 */ | 169 | /* Soundblaster hardware programming reference guide, 3-23 */ |
148 | snd_sbdsp_command(chip, SB_DSP_DMA8_EXIT); | 170 | snd_sbdsp_command(chip, SB_DSP_DMA8_EXIT); |
149 | runtime->dma_area[0] = 0x80; | 171 | runtime->dma_area[0] = 0x80; |
150 | snd_dma_program(chip->dma8, runtime->dma_addr, 1, DMA_MODE_WRITE); | 172 | snd_dma_program(dma, runtime->dma_addr, 1, DMA_MODE_WRITE); |
151 | /* force interrupt */ | 173 | /* force interrupt */ |
152 | chip->mode = SB_MODE_HALT; | ||
153 | snd_sbdsp_command(chip, SB_DSP_OUTPUT); | 174 | snd_sbdsp_command(chip, SB_DSP_OUTPUT); |
154 | snd_sbdsp_command(chip, 0); | 175 | snd_sbdsp_command(chip, 0); |
155 | snd_sbdsp_command(chip, 0); | 176 | snd_sbdsp_command(chip, 0); |
156 | } | 177 | } |
157 | snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE); | 178 | snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE); |
158 | if (runtime->channels > 1) { | 179 | if (stereo) { |
159 | snd_sbdsp_command(chip, 256 - runtime->rate_den / 2); | 180 | snd_sbdsp_command(chip, 256 - runtime->rate_den / 2); |
160 | spin_lock(&chip->mixer_lock); | 181 | spin_lock(&chip->mixer_lock); |
161 | /* save output filter status and turn it off */ | 182 | /* save output filter status and turn it off */ |
@@ -168,13 +189,15 @@ static int snd_sb8_playback_prepare(struct snd_pcm_substream *substream) | |||
168 | snd_sbdsp_command(chip, 256 - runtime->rate_den); | 189 | snd_sbdsp_command(chip, 256 - runtime->rate_den); |
169 | } | 190 | } |
170 | if (chip->playback_format != SB_DSP_OUTPUT) { | 191 | if (chip->playback_format != SB_DSP_OUTPUT) { |
192 | if (chip->mode & SB_MODE_PLAYBACK_16) | ||
193 | count /= 2; | ||
171 | count--; | 194 | count--; |
172 | snd_sbdsp_command(chip, SB_DSP_BLOCK_SIZE); | 195 | snd_sbdsp_command(chip, SB_DSP_BLOCK_SIZE); |
173 | snd_sbdsp_command(chip, count & 0xff); | 196 | snd_sbdsp_command(chip, count & 0xff); |
174 | snd_sbdsp_command(chip, count >> 8); | 197 | snd_sbdsp_command(chip, count >> 8); |
175 | } | 198 | } |
176 | spin_unlock_irqrestore(&chip->reg_lock, flags); | 199 | spin_unlock_irqrestore(&chip->reg_lock, flags); |
177 | snd_dma_program(chip->dma8, runtime->dma_addr, | 200 | snd_dma_program(dma, runtime->dma_addr, |
178 | size, DMA_MODE_WRITE | DMA_AUTOINIT); | 201 | size, DMA_MODE_WRITE | DMA_AUTOINIT); |
179 | return 0; | 202 | return 0; |
180 | } | 203 | } |
@@ -212,7 +235,6 @@ static int snd_sb8_playback_trigger(struct snd_pcm_substream *substream, | |||
212 | snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF); | 235 | snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF); |
213 | } | 236 | } |
214 | spin_unlock_irqrestore(&chip->reg_lock, flags); | 237 | spin_unlock_irqrestore(&chip->reg_lock, flags); |
215 | chip->mode = (cmd == SNDRV_PCM_TRIGGER_START) ? SB_MODE_PLAYBACK_8 : SB_MODE_HALT; | ||
216 | return 0; | 238 | return 0; |
217 | } | 239 | } |
218 | 240 | ||
@@ -234,9 +256,21 @@ static int snd_sb8_capture_prepare(struct snd_pcm_substream *substream) | |||
234 | struct snd_sb *chip = snd_pcm_substream_chip(substream); | 256 | struct snd_sb *chip = snd_pcm_substream_chip(substream); |
235 | struct snd_pcm_runtime *runtime = substream->runtime; | 257 | struct snd_pcm_runtime *runtime = substream->runtime; |
236 | unsigned int mixreg, rate, size, count; | 258 | unsigned int mixreg, rate, size, count; |
259 | unsigned char format; | ||
260 | unsigned char stereo = runtime->channels > 1; | ||
261 | int dma; | ||
237 | 262 | ||
238 | rate = runtime->rate; | 263 | rate = runtime->rate; |
239 | switch (chip->hardware) { | 264 | switch (chip->hardware) { |
265 | case SB_HW_JAZZ16: | ||
266 | if (runtime->format == SNDRV_PCM_FORMAT_S16_LE) { | ||
267 | if (chip->mode & SB_MODE_PLAYBACK_16) | ||
268 | return -EBUSY; | ||
269 | else | ||
270 | chip->mode |= SB_MODE_CAPTURE_16; | ||
271 | } | ||
272 | chip->capture_format = SB_DSP_LO_INPUT_AUTO; | ||
273 | break; | ||
240 | case SB_HW_PRO: | 274 | case SB_HW_PRO: |
241 | if (runtime->channels > 1) { | 275 | if (runtime->channels > 1) { |
242 | if (snd_BUG_ON(rate != SB8_RATE(11025) && | 276 | if (snd_BUG_ON(rate != SB8_RATE(11025) && |
@@ -262,14 +296,24 @@ static int snd_sb8_capture_prepare(struct snd_pcm_substream *substream) | |||
262 | default: | 296 | default: |
263 | return -EINVAL; | 297 | return -EINVAL; |
264 | } | 298 | } |
299 | if (chip->mode & SB_MODE_CAPTURE_16) { | ||
300 | format = stereo ? SB_DSP_STEREO_16BIT : SB_DSP_MONO_16BIT; | ||
301 | dma = chip->dma16; | ||
302 | } else { | ||
303 | format = stereo ? SB_DSP_STEREO_8BIT : SB_DSP_MONO_8BIT; | ||
304 | chip->mode |= SB_MODE_CAPTURE_8; | ||
305 | dma = chip->dma8; | ||
306 | } | ||
265 | size = chip->c_dma_size = snd_pcm_lib_buffer_bytes(substream); | 307 | size = chip->c_dma_size = snd_pcm_lib_buffer_bytes(substream); |
266 | count = chip->c_period_size = snd_pcm_lib_period_bytes(substream); | 308 | count = chip->c_period_size = snd_pcm_lib_period_bytes(substream); |
267 | spin_lock_irqsave(&chip->reg_lock, flags); | 309 | spin_lock_irqsave(&chip->reg_lock, flags); |
268 | snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF); | 310 | snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF); |
269 | if (runtime->channels > 1) | 311 | if (chip->hardware == SB_HW_JAZZ16) |
312 | snd_sbdsp_command(chip, format); | ||
313 | else if (stereo) | ||
270 | snd_sbdsp_command(chip, SB_DSP_STEREO_8BIT); | 314 | snd_sbdsp_command(chip, SB_DSP_STEREO_8BIT); |
271 | snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE); | 315 | snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE); |
272 | if (runtime->channels > 1) { | 316 | if (stereo) { |
273 | snd_sbdsp_command(chip, 256 - runtime->rate_den / 2); | 317 | snd_sbdsp_command(chip, 256 - runtime->rate_den / 2); |
274 | spin_lock(&chip->mixer_lock); | 318 | spin_lock(&chip->mixer_lock); |
275 | /* save input filter status and turn it off */ | 319 | /* save input filter status and turn it off */ |
@@ -282,13 +326,15 @@ static int snd_sb8_capture_prepare(struct snd_pcm_substream *substream) | |||
282 | snd_sbdsp_command(chip, 256 - runtime->rate_den); | 326 | snd_sbdsp_command(chip, 256 - runtime->rate_den); |
283 | } | 327 | } |
284 | if (chip->capture_format != SB_DSP_INPUT) { | 328 | if (chip->capture_format != SB_DSP_INPUT) { |
329 | if (chip->mode & SB_MODE_PLAYBACK_16) | ||
330 | count /= 2; | ||
285 | count--; | 331 | count--; |
286 | snd_sbdsp_command(chip, SB_DSP_BLOCK_SIZE); | 332 | snd_sbdsp_command(chip, SB_DSP_BLOCK_SIZE); |
287 | snd_sbdsp_command(chip, count & 0xff); | 333 | snd_sbdsp_command(chip, count & 0xff); |
288 | snd_sbdsp_command(chip, count >> 8); | 334 | snd_sbdsp_command(chip, count >> 8); |
289 | } | 335 | } |
290 | spin_unlock_irqrestore(&chip->reg_lock, flags); | 336 | spin_unlock_irqrestore(&chip->reg_lock, flags); |
291 | snd_dma_program(chip->dma8, runtime->dma_addr, | 337 | snd_dma_program(dma, runtime->dma_addr, |
292 | size, DMA_MODE_READ | DMA_AUTOINIT); | 338 | size, DMA_MODE_READ | DMA_AUTOINIT); |
293 | return 0; | 339 | return 0; |
294 | } | 340 | } |
@@ -328,7 +374,6 @@ static int snd_sb8_capture_trigger(struct snd_pcm_substream *substream, | |||
328 | snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF); | 374 | snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF); |
329 | } | 375 | } |
330 | spin_unlock_irqrestore(&chip->reg_lock, flags); | 376 | spin_unlock_irqrestore(&chip->reg_lock, flags); |
331 | chip->mode = (cmd == SNDRV_PCM_TRIGGER_START) ? SB_MODE_CAPTURE_8 : SB_MODE_HALT; | ||
332 | return 0; | 377 | return 0; |
333 | } | 378 | } |
334 | 379 | ||
@@ -339,13 +384,21 @@ irqreturn_t snd_sb8dsp_interrupt(struct snd_sb *chip) | |||
339 | 384 | ||
340 | snd_sb_ack_8bit(chip); | 385 | snd_sb_ack_8bit(chip); |
341 | switch (chip->mode) { | 386 | switch (chip->mode) { |
342 | case SB_MODE_PLAYBACK_8: /* ok.. playback is active */ | 387 | case SB_MODE_PLAYBACK_16: /* ok.. playback is active */ |
388 | if (chip->hardware != SB_HW_JAZZ16) | ||
389 | break; | ||
390 | /* fallthru */ | ||
391 | case SB_MODE_PLAYBACK_8: | ||
343 | substream = chip->playback_substream; | 392 | substream = chip->playback_substream; |
344 | runtime = substream->runtime; | 393 | runtime = substream->runtime; |
345 | if (chip->playback_format == SB_DSP_OUTPUT) | 394 | if (chip->playback_format == SB_DSP_OUTPUT) |
346 | snd_sb8_playback_trigger(substream, SNDRV_PCM_TRIGGER_START); | 395 | snd_sb8_playback_trigger(substream, SNDRV_PCM_TRIGGER_START); |
347 | snd_pcm_period_elapsed(substream); | 396 | snd_pcm_period_elapsed(substream); |
348 | break; | 397 | break; |
398 | case SB_MODE_CAPTURE_16: | ||
399 | if (chip->hardware != SB_HW_JAZZ16) | ||
400 | break; | ||
401 | /* fallthru */ | ||
349 | case SB_MODE_CAPTURE_8: | 402 | case SB_MODE_CAPTURE_8: |
350 | substream = chip->capture_substream; | 403 | substream = chip->capture_substream; |
351 | runtime = substream->runtime; | 404 | runtime = substream->runtime; |
@@ -361,10 +414,15 @@ static snd_pcm_uframes_t snd_sb8_playback_pointer(struct snd_pcm_substream *subs | |||
361 | { | 414 | { |
362 | struct snd_sb *chip = snd_pcm_substream_chip(substream); | 415 | struct snd_sb *chip = snd_pcm_substream_chip(substream); |
363 | size_t ptr; | 416 | size_t ptr; |
417 | int dma; | ||
364 | 418 | ||
365 | if (chip->mode != SB_MODE_PLAYBACK_8) | 419 | if (chip->mode & SB_MODE_PLAYBACK_8) |
420 | dma = chip->dma8; | ||
421 | else if (chip->mode & SB_MODE_PLAYBACK_16) | ||
422 | dma = chip->dma16; | ||
423 | else | ||
366 | return 0; | 424 | return 0; |
367 | ptr = snd_dma_pointer(chip->dma8, chip->p_dma_size); | 425 | ptr = snd_dma_pointer(dma, chip->p_dma_size); |
368 | return bytes_to_frames(substream->runtime, ptr); | 426 | return bytes_to_frames(substream->runtime, ptr); |
369 | } | 427 | } |
370 | 428 | ||
@@ -372,10 +430,15 @@ static snd_pcm_uframes_t snd_sb8_capture_pointer(struct snd_pcm_substream *subst | |||
372 | { | 430 | { |
373 | struct snd_sb *chip = snd_pcm_substream_chip(substream); | 431 | struct snd_sb *chip = snd_pcm_substream_chip(substream); |
374 | size_t ptr; | 432 | size_t ptr; |
433 | int dma; | ||
375 | 434 | ||
376 | if (chip->mode != SB_MODE_CAPTURE_8) | 435 | if (chip->mode & SB_MODE_CAPTURE_8) |
436 | dma = chip->dma8; | ||
437 | else if (chip->mode & SB_MODE_CAPTURE_16) | ||
438 | dma = chip->dma16; | ||
439 | else | ||
377 | return 0; | 440 | return 0; |
378 | ptr = snd_dma_pointer(chip->dma8, chip->c_dma_size); | 441 | ptr = snd_dma_pointer(dma, chip->c_dma_size); |
379 | return bytes_to_frames(substream->runtime, ptr); | 442 | return bytes_to_frames(substream->runtime, ptr); |
380 | } | 443 | } |
381 | 444 | ||
@@ -446,6 +509,14 @@ static int snd_sb8_open(struct snd_pcm_substream *substream) | |||
446 | runtime->hw = snd_sb8_capture; | 509 | runtime->hw = snd_sb8_capture; |
447 | } | 510 | } |
448 | switch (chip->hardware) { | 511 | switch (chip->hardware) { |
512 | case SB_HW_JAZZ16: | ||
513 | if (chip->dma16 == 5 || chip->dma16 == 7) | ||
514 | runtime->hw.formats |= SNDRV_PCM_FMTBIT_S16_LE; | ||
515 | runtime->hw.rates |= SNDRV_PCM_RATE_8000_48000; | ||
516 | runtime->hw.rate_min = 4000; | ||
517 | runtime->hw.rate_max = 50000; | ||
518 | runtime->hw.channels_max = 2; | ||
519 | break; | ||
449 | case SB_HW_PRO: | 520 | case SB_HW_PRO: |
450 | runtime->hw.rate_max = 44100; | 521 | runtime->hw.rate_max = 44100; |
451 | runtime->hw.channels_max = 2; | 522 | runtime->hw.channels_max = 2; |
@@ -468,6 +539,14 @@ static int snd_sb8_open(struct snd_pcm_substream *substream) | |||
468 | } | 539 | } |
469 | snd_pcm_hw_constraint_ratnums(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, | 540 | snd_pcm_hw_constraint_ratnums(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, |
470 | &hw_constraints_clock); | 541 | &hw_constraints_clock); |
542 | if (chip->dma8 > 3 || chip->dma16 >= 0) { | ||
543 | snd_pcm_hw_constraint_step(runtime, 0, | ||
544 | SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 2); | ||
545 | snd_pcm_hw_constraint_step(runtime, 0, | ||
546 | SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 2); | ||
547 | runtime->hw.buffer_bytes_max = 128 * 1024 * 1024; | ||
548 | runtime->hw.period_bytes_max = 128 * 1024 * 1024; | ||
549 | } | ||
471 | return 0; | 550 | return 0; |
472 | } | 551 | } |
473 | 552 | ||
@@ -480,6 +559,10 @@ static int snd_sb8_close(struct snd_pcm_substream *substream) | |||
480 | chip->capture_substream = NULL; | 559 | chip->capture_substream = NULL; |
481 | spin_lock_irqsave(&chip->open_lock, flags); | 560 | spin_lock_irqsave(&chip->open_lock, flags); |
482 | chip->open &= ~SB_OPEN_PCM; | 561 | chip->open &= ~SB_OPEN_PCM; |
562 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
563 | chip->mode &= ~SB_MODE_PLAYBACK; | ||
564 | else | ||
565 | chip->mode &= ~SB_MODE_CAPTURE; | ||
483 | spin_unlock_irqrestore(&chip->open_lock, flags); | 566 | spin_unlock_irqrestore(&chip->open_lock, flags); |
484 | return 0; | 567 | return 0; |
485 | } | 568 | } |
@@ -515,6 +598,7 @@ int snd_sb8dsp_pcm(struct snd_sb *chip, int device, struct snd_pcm ** rpcm) | |||
515 | struct snd_card *card = chip->card; | 598 | struct snd_card *card = chip->card; |
516 | struct snd_pcm *pcm; | 599 | struct snd_pcm *pcm; |
517 | int err; | 600 | int err; |
601 | size_t max_prealloc = 64 * 1024; | ||
518 | 602 | ||
519 | if (rpcm) | 603 | if (rpcm) |
520 | *rpcm = NULL; | 604 | *rpcm = NULL; |
@@ -527,9 +611,11 @@ int snd_sb8dsp_pcm(struct snd_sb *chip, int device, struct snd_pcm ** rpcm) | |||
527 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_sb8_playback_ops); | 611 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_sb8_playback_ops); |
528 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_sb8_capture_ops); | 612 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_sb8_capture_ops); |
529 | 613 | ||
614 | if (chip->dma8 > 3 || chip->dma16 >= 0) | ||
615 | max_prealloc = 128 * 1024; | ||
530 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, | 616 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, |
531 | snd_dma_isa_data(), | 617 | snd_dma_isa_data(), |
532 | 64*1024, 64*1024); | 618 | 64*1024, max_prealloc); |
533 | 619 | ||
534 | if (rpcm) | 620 | if (rpcm) |
535 | *rpcm = pcm; | 621 | *rpcm = pcm; |
diff --git a/sound/isa/sb/sb_common.c b/sound/isa/sb/sb_common.c index 27a651502251..eae6c1c0eff9 100644 --- a/sound/isa/sb/sb_common.c +++ b/sound/isa/sb/sb_common.c | |||
@@ -170,6 +170,9 @@ static int snd_sbdsp_probe(struct snd_sb * chip) | |||
170 | case SB_HW_CS5530: | 170 | case SB_HW_CS5530: |
171 | str = "16 (CS5530)"; | 171 | str = "16 (CS5530)"; |
172 | break; | 172 | break; |
173 | case SB_HW_JAZZ16: | ||
174 | str = "Pro (Jazz16)"; | ||
175 | break; | ||
173 | default: | 176 | default: |
174 | return -ENODEV; | 177 | return -ENODEV; |
175 | } | 178 | } |
diff --git a/sound/isa/sb/sb_mixer.c b/sound/isa/sb/sb_mixer.c index 318ff0c823e7..6496822c1808 100644 --- a/sound/isa/sb/sb_mixer.c +++ b/sound/isa/sb/sb_mixer.c | |||
@@ -528,20 +528,11 @@ int snd_sbmixer_add_ctl(struct snd_sb *chip, const char *name, int index, int ty | |||
528 | * SB 2.0 specific mixer elements | 528 | * SB 2.0 specific mixer elements |
529 | */ | 529 | */ |
530 | 530 | ||
531 | static struct sbmix_elem snd_sb20_ctl_master_play_vol = | 531 | static struct sbmix_elem snd_sb20_controls[] = { |
532 | SB_SINGLE("Master Playback Volume", SB_DSP20_MASTER_DEV, 1, 7); | 532 | SB_SINGLE("Master Playback Volume", SB_DSP20_MASTER_DEV, 1, 7), |
533 | static struct sbmix_elem snd_sb20_ctl_pcm_play_vol = | 533 | SB_SINGLE("PCM Playback Volume", SB_DSP20_PCM_DEV, 1, 3), |
534 | SB_SINGLE("PCM Playback Volume", SB_DSP20_PCM_DEV, 1, 3); | 534 | SB_SINGLE("Synth Playback Volume", SB_DSP20_FM_DEV, 1, 7), |
535 | static struct sbmix_elem snd_sb20_ctl_synth_play_vol = | 535 | SB_SINGLE("CD Playback Volume", SB_DSP20_CD_DEV, 1, 7) |
536 | SB_SINGLE("Synth Playback Volume", SB_DSP20_FM_DEV, 1, 7); | ||
537 | static struct sbmix_elem snd_sb20_ctl_cd_play_vol = | ||
538 | SB_SINGLE("CD Playback Volume", SB_DSP20_CD_DEV, 1, 7); | ||
539 | |||
540 | static struct sbmix_elem *snd_sb20_controls[] = { | ||
541 | &snd_sb20_ctl_master_play_vol, | ||
542 | &snd_sb20_ctl_pcm_play_vol, | ||
543 | &snd_sb20_ctl_synth_play_vol, | ||
544 | &snd_sb20_ctl_cd_play_vol | ||
545 | }; | 536 | }; |
546 | 537 | ||
547 | static unsigned char snd_sb20_init_values[][2] = { | 538 | static unsigned char snd_sb20_init_values[][2] = { |
@@ -552,41 +543,24 @@ static unsigned char snd_sb20_init_values[][2] = { | |||
552 | /* | 543 | /* |
553 | * SB Pro specific mixer elements | 544 | * SB Pro specific mixer elements |
554 | */ | 545 | */ |
555 | static struct sbmix_elem snd_sbpro_ctl_master_play_vol = | 546 | static struct sbmix_elem snd_sbpro_controls[] = { |
556 | SB_DOUBLE("Master Playback Volume", SB_DSP_MASTER_DEV, SB_DSP_MASTER_DEV, 5, 1, 7); | 547 | SB_DOUBLE("Master Playback Volume", |
557 | static struct sbmix_elem snd_sbpro_ctl_pcm_play_vol = | 548 | SB_DSP_MASTER_DEV, SB_DSP_MASTER_DEV, 5, 1, 7), |
558 | SB_DOUBLE("PCM Playback Volume", SB_DSP_PCM_DEV, SB_DSP_PCM_DEV, 5, 1, 7); | 549 | SB_DOUBLE("PCM Playback Volume", |
559 | static struct sbmix_elem snd_sbpro_ctl_pcm_play_filter = | 550 | SB_DSP_PCM_DEV, SB_DSP_PCM_DEV, 5, 1, 7), |
560 | SB_SINGLE("PCM Playback Filter", SB_DSP_PLAYBACK_FILT, 5, 1); | 551 | SB_SINGLE("PCM Playback Filter", SB_DSP_PLAYBACK_FILT, 5, 1), |
561 | static struct sbmix_elem snd_sbpro_ctl_synth_play_vol = | 552 | SB_DOUBLE("Synth Playback Volume", |
562 | SB_DOUBLE("Synth Playback Volume", SB_DSP_FM_DEV, SB_DSP_FM_DEV, 5, 1, 7); | 553 | SB_DSP_FM_DEV, SB_DSP_FM_DEV, 5, 1, 7), |
563 | static struct sbmix_elem snd_sbpro_ctl_cd_play_vol = | 554 | SB_DOUBLE("CD Playback Volume", SB_DSP_CD_DEV, SB_DSP_CD_DEV, 5, 1, 7), |
564 | SB_DOUBLE("CD Playback Volume", SB_DSP_CD_DEV, SB_DSP_CD_DEV, 5, 1, 7); | 555 | SB_DOUBLE("Line Playback Volume", |
565 | static struct sbmix_elem snd_sbpro_ctl_line_play_vol = | 556 | SB_DSP_LINE_DEV, SB_DSP_LINE_DEV, 5, 1, 7), |
566 | SB_DOUBLE("Line Playback Volume", SB_DSP_LINE_DEV, SB_DSP_LINE_DEV, 5, 1, 7); | 557 | SB_SINGLE("Mic Playback Volume", SB_DSP_MIC_DEV, 1, 3), |
567 | static struct sbmix_elem snd_sbpro_ctl_mic_play_vol = | ||
568 | SB_SINGLE("Mic Playback Volume", SB_DSP_MIC_DEV, 1, 3); | ||
569 | static struct sbmix_elem snd_sbpro_ctl_capture_source = | ||
570 | { | 558 | { |
571 | .name = "Capture Source", | 559 | .name = "Capture Source", |
572 | .type = SB_MIX_CAPTURE_PRO | 560 | .type = SB_MIX_CAPTURE_PRO |
573 | }; | 561 | }, |
574 | static struct sbmix_elem snd_sbpro_ctl_capture_filter = | 562 | SB_SINGLE("Capture Filter", SB_DSP_CAPTURE_FILT, 5, 1), |
575 | SB_SINGLE("Capture Filter", SB_DSP_CAPTURE_FILT, 5, 1); | 563 | SB_SINGLE("Capture Low-Pass Filter", SB_DSP_CAPTURE_FILT, 3, 1) |
576 | static struct sbmix_elem snd_sbpro_ctl_capture_low_filter = | ||
577 | SB_SINGLE("Capture Low-Pass Filter", SB_DSP_CAPTURE_FILT, 3, 1); | ||
578 | |||
579 | static struct sbmix_elem *snd_sbpro_controls[] = { | ||
580 | &snd_sbpro_ctl_master_play_vol, | ||
581 | &snd_sbpro_ctl_pcm_play_vol, | ||
582 | &snd_sbpro_ctl_pcm_play_filter, | ||
583 | &snd_sbpro_ctl_synth_play_vol, | ||
584 | &snd_sbpro_ctl_cd_play_vol, | ||
585 | &snd_sbpro_ctl_line_play_vol, | ||
586 | &snd_sbpro_ctl_mic_play_vol, | ||
587 | &snd_sbpro_ctl_capture_source, | ||
588 | &snd_sbpro_ctl_capture_filter, | ||
589 | &snd_sbpro_ctl_capture_low_filter | ||
590 | }; | 564 | }; |
591 | 565 | ||
592 | static unsigned char snd_sbpro_init_values[][2] = { | 566 | static unsigned char snd_sbpro_init_values[][2] = { |
@@ -598,68 +572,42 @@ static unsigned char snd_sbpro_init_values[][2] = { | |||
598 | /* | 572 | /* |
599 | * SB16 specific mixer elements | 573 | * SB16 specific mixer elements |
600 | */ | 574 | */ |
601 | static struct sbmix_elem snd_sb16_ctl_master_play_vol = | 575 | static struct sbmix_elem snd_sb16_controls[] = { |
602 | SB_DOUBLE("Master Playback Volume", SB_DSP4_MASTER_DEV, (SB_DSP4_MASTER_DEV + 1), 3, 3, 31); | 576 | SB_DOUBLE("Master Playback Volume", |
603 | static struct sbmix_elem snd_sb16_ctl_3d_enhance_switch = | 577 | SB_DSP4_MASTER_DEV, (SB_DSP4_MASTER_DEV + 1), 3, 3, 31), |
604 | SB_SINGLE("3D Enhancement Switch", SB_DSP4_3DSE, 0, 1); | 578 | SB_DOUBLE("PCM Playback Volume", |
605 | static struct sbmix_elem snd_sb16_ctl_tone_bass = | 579 | SB_DSP4_PCM_DEV, (SB_DSP4_PCM_DEV + 1), 3, 3, 31), |
606 | SB_DOUBLE("Tone Control - Bass", SB_DSP4_BASS_DEV, (SB_DSP4_BASS_DEV + 1), 4, 4, 15); | 580 | SB16_INPUT_SW("Synth Capture Route", |
607 | static struct sbmix_elem snd_sb16_ctl_tone_treble = | 581 | SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 6, 5), |
608 | SB_DOUBLE("Tone Control - Treble", SB_DSP4_TREBLE_DEV, (SB_DSP4_TREBLE_DEV + 1), 4, 4, 15); | 582 | SB_DOUBLE("Synth Playback Volume", |
609 | static struct sbmix_elem snd_sb16_ctl_pcm_play_vol = | 583 | SB_DSP4_SYNTH_DEV, (SB_DSP4_SYNTH_DEV + 1), 3, 3, 31), |
610 | SB_DOUBLE("PCM Playback Volume", SB_DSP4_PCM_DEV, (SB_DSP4_PCM_DEV + 1), 3, 3, 31); | 584 | SB16_INPUT_SW("CD Capture Route", |
611 | static struct sbmix_elem snd_sb16_ctl_synth_capture_route = | 585 | SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 2, 1), |
612 | SB16_INPUT_SW("Synth Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 6, 5); | 586 | SB_DOUBLE("CD Playback Switch", |
613 | static struct sbmix_elem snd_sb16_ctl_synth_play_vol = | 587 | SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 2, 1, 1), |
614 | SB_DOUBLE("Synth Playback Volume", SB_DSP4_SYNTH_DEV, (SB_DSP4_SYNTH_DEV + 1), 3, 3, 31); | 588 | SB_DOUBLE("CD Playback Volume", |
615 | static struct sbmix_elem snd_sb16_ctl_cd_capture_route = | 589 | SB_DSP4_CD_DEV, (SB_DSP4_CD_DEV + 1), 3, 3, 31), |
616 | SB16_INPUT_SW("CD Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 2, 1); | 590 | SB16_INPUT_SW("Mic Capture Route", |
617 | static struct sbmix_elem snd_sb16_ctl_cd_play_switch = | 591 | SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 0, 0), |
618 | SB_DOUBLE("CD Playback Switch", SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 2, 1, 1); | 592 | SB_SINGLE("Mic Playback Switch", SB_DSP4_OUTPUT_SW, 0, 1), |
619 | static struct sbmix_elem snd_sb16_ctl_cd_play_vol = | 593 | SB_SINGLE("Mic Playback Volume", SB_DSP4_MIC_DEV, 3, 31), |
620 | SB_DOUBLE("CD Playback Volume", SB_DSP4_CD_DEV, (SB_DSP4_CD_DEV + 1), 3, 3, 31); | 594 | SB_SINGLE("Beep Volume", SB_DSP4_SPEAKER_DEV, 6, 3), |
621 | static struct sbmix_elem snd_sb16_ctl_line_capture_route = | 595 | SB_DOUBLE("Capture Volume", |
622 | SB16_INPUT_SW("Line Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 4, 3); | 596 | SB_DSP4_IGAIN_DEV, (SB_DSP4_IGAIN_DEV + 1), 6, 6, 3), |
623 | static struct sbmix_elem snd_sb16_ctl_line_play_switch = | 597 | SB_DOUBLE("Playback Volume", |
624 | SB_DOUBLE("Line Playback Switch", SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 4, 3, 1); | 598 | SB_DSP4_OGAIN_DEV, (SB_DSP4_OGAIN_DEV + 1), 6, 6, 3), |
625 | static struct sbmix_elem snd_sb16_ctl_line_play_vol = | 599 | SB16_INPUT_SW("Line Capture Route", |
626 | SB_DOUBLE("Line Playback Volume", SB_DSP4_LINE_DEV, (SB_DSP4_LINE_DEV + 1), 3, 3, 31); | 600 | SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 4, 3), |
627 | static struct sbmix_elem snd_sb16_ctl_mic_capture_route = | 601 | SB_DOUBLE("Line Playback Switch", |
628 | SB16_INPUT_SW("Mic Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 0, 0); | 602 | SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 4, 3, 1), |
629 | static struct sbmix_elem snd_sb16_ctl_mic_play_switch = | 603 | SB_DOUBLE("Line Playback Volume", |
630 | SB_SINGLE("Mic Playback Switch", SB_DSP4_OUTPUT_SW, 0, 1); | 604 | SB_DSP4_LINE_DEV, (SB_DSP4_LINE_DEV + 1), 3, 3, 31), |
631 | static struct sbmix_elem snd_sb16_ctl_mic_play_vol = | 605 | SB_SINGLE("Mic Auto Gain", SB_DSP4_MIC_AGC, 0, 1), |
632 | SB_SINGLE("Mic Playback Volume", SB_DSP4_MIC_DEV, 3, 31); | 606 | SB_SINGLE("3D Enhancement Switch", SB_DSP4_3DSE, 0, 1), |
633 | static struct sbmix_elem snd_sb16_ctl_pc_speaker_vol = | 607 | SB_DOUBLE("Tone Control - Bass", |
634 | SB_SINGLE("Beep Volume", SB_DSP4_SPEAKER_DEV, 6, 3); | 608 | SB_DSP4_BASS_DEV, (SB_DSP4_BASS_DEV + 1), 4, 4, 15), |
635 | static struct sbmix_elem snd_sb16_ctl_capture_vol = | 609 | SB_DOUBLE("Tone Control - Treble", |
636 | SB_DOUBLE("Capture Volume", SB_DSP4_IGAIN_DEV, (SB_DSP4_IGAIN_DEV + 1), 6, 6, 3); | 610 | SB_DSP4_TREBLE_DEV, (SB_DSP4_TREBLE_DEV + 1), 4, 4, 15) |
637 | static struct sbmix_elem snd_sb16_ctl_play_vol = | ||
638 | SB_DOUBLE("Playback Volume", SB_DSP4_OGAIN_DEV, (SB_DSP4_OGAIN_DEV + 1), 6, 6, 3); | ||
639 | static struct sbmix_elem snd_sb16_ctl_auto_mic_gain = | ||
640 | SB_SINGLE("Mic Auto Gain", SB_DSP4_MIC_AGC, 0, 1); | ||
641 | |||
642 | static struct sbmix_elem *snd_sb16_controls[] = { | ||
643 | &snd_sb16_ctl_master_play_vol, | ||
644 | &snd_sb16_ctl_3d_enhance_switch, | ||
645 | &snd_sb16_ctl_tone_bass, | ||
646 | &snd_sb16_ctl_tone_treble, | ||
647 | &snd_sb16_ctl_pcm_play_vol, | ||
648 | &snd_sb16_ctl_synth_capture_route, | ||
649 | &snd_sb16_ctl_synth_play_vol, | ||
650 | &snd_sb16_ctl_cd_capture_route, | ||
651 | &snd_sb16_ctl_cd_play_switch, | ||
652 | &snd_sb16_ctl_cd_play_vol, | ||
653 | &snd_sb16_ctl_line_capture_route, | ||
654 | &snd_sb16_ctl_line_play_switch, | ||
655 | &snd_sb16_ctl_line_play_vol, | ||
656 | &snd_sb16_ctl_mic_capture_route, | ||
657 | &snd_sb16_ctl_mic_play_switch, | ||
658 | &snd_sb16_ctl_mic_play_vol, | ||
659 | &snd_sb16_ctl_pc_speaker_vol, | ||
660 | &snd_sb16_ctl_capture_vol, | ||
661 | &snd_sb16_ctl_play_vol, | ||
662 | &snd_sb16_ctl_auto_mic_gain | ||
663 | }; | 611 | }; |
664 | 612 | ||
665 | static unsigned char snd_sb16_init_values[][2] = { | 613 | static unsigned char snd_sb16_init_values[][2] = { |
@@ -678,46 +626,34 @@ static unsigned char snd_sb16_init_values[][2] = { | |||
678 | /* | 626 | /* |
679 | * DT019x specific mixer elements | 627 | * DT019x specific mixer elements |
680 | */ | 628 | */ |
681 | static struct sbmix_elem snd_dt019x_ctl_master_play_vol = | 629 | static struct sbmix_elem snd_dt019x_controls[] = { |
682 | SB_DOUBLE("Master Playback Volume", SB_DT019X_MASTER_DEV, SB_DT019X_MASTER_DEV, 4,0, 15); | 630 | /* ALS4000 below has some parts which we might be lacking, |
683 | static struct sbmix_elem snd_dt019x_ctl_pcm_play_vol = | 631 | * e.g. snd_als4000_ctl_mono_playback_switch - check it! */ |
684 | SB_DOUBLE("PCM Playback Volume", SB_DT019X_PCM_DEV, SB_DT019X_PCM_DEV, 4,0, 15); | 632 | SB_DOUBLE("Master Playback Volume", |
685 | static struct sbmix_elem snd_dt019x_ctl_synth_play_vol = | 633 | SB_DT019X_MASTER_DEV, SB_DT019X_MASTER_DEV, 4, 0, 15), |
686 | SB_DOUBLE("Synth Playback Volume", SB_DT019X_SYNTH_DEV, SB_DT019X_SYNTH_DEV, 4,0, 15); | 634 | SB_DOUBLE("PCM Playback Switch", |
687 | static struct sbmix_elem snd_dt019x_ctl_cd_play_vol = | 635 | SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 2, 1, 1), |
688 | SB_DOUBLE("CD Playback Volume", SB_DT019X_CD_DEV, SB_DT019X_CD_DEV, 4,0, 15); | 636 | SB_DOUBLE("PCM Playback Volume", |
689 | static struct sbmix_elem snd_dt019x_ctl_mic_play_vol = | 637 | SB_DT019X_PCM_DEV, SB_DT019X_PCM_DEV, 4, 0, 15), |
690 | SB_SINGLE("Mic Playback Volume", SB_DT019X_MIC_DEV, 4, 7); | 638 | SB_DOUBLE("Synth Playback Switch", |
691 | static struct sbmix_elem snd_dt019x_ctl_pc_speaker_vol = | 639 | SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 4, 3, 1), |
692 | SB_SINGLE("Beep Volume", SB_DT019X_SPKR_DEV, 0, 7); | 640 | SB_DOUBLE("Synth Playback Volume", |
693 | static struct sbmix_elem snd_dt019x_ctl_line_play_vol = | 641 | SB_DT019X_SYNTH_DEV, SB_DT019X_SYNTH_DEV, 4, 0, 15), |
694 | SB_DOUBLE("Line Playback Volume", SB_DT019X_LINE_DEV, SB_DT019X_LINE_DEV, 4,0, 15); | 642 | SB_DOUBLE("CD Playback Switch", |
695 | static struct sbmix_elem snd_dt019x_ctl_pcm_play_switch = | 643 | SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 2, 1, 1), |
696 | SB_DOUBLE("PCM Playback Switch", SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 2,1, 1); | 644 | SB_DOUBLE("CD Playback Volume", |
697 | static struct sbmix_elem snd_dt019x_ctl_synth_play_switch = | 645 | SB_DT019X_CD_DEV, SB_DT019X_CD_DEV, 4, 0, 15), |
698 | SB_DOUBLE("Synth Playback Switch", SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 4,3, 1); | 646 | SB_SINGLE("Mic Playback Switch", SB_DSP4_OUTPUT_SW, 0, 1), |
699 | static struct sbmix_elem snd_dt019x_ctl_capture_source = | 647 | SB_SINGLE("Mic Playback Volume", SB_DT019X_MIC_DEV, 4, 7), |
648 | SB_SINGLE("Beep Volume", SB_DT019X_SPKR_DEV, 0, 7), | ||
649 | SB_DOUBLE("Line Playback Switch", | ||
650 | SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 4, 3, 1), | ||
651 | SB_DOUBLE("Line Playback Volume", | ||
652 | SB_DT019X_LINE_DEV, SB_DT019X_LINE_DEV, 4, 0, 15), | ||
700 | { | 653 | { |
701 | .name = "Capture Source", | 654 | .name = "Capture Source", |
702 | .type = SB_MIX_CAPTURE_DT019X | 655 | .type = SB_MIX_CAPTURE_DT019X |
703 | }; | 656 | } |
704 | |||
705 | static struct sbmix_elem *snd_dt019x_controls[] = { | ||
706 | /* ALS4000 below has some parts which we might be lacking, | ||
707 | * e.g. snd_als4000_ctl_mono_playback_switch - check it! */ | ||
708 | &snd_dt019x_ctl_master_play_vol, | ||
709 | &snd_dt019x_ctl_pcm_play_vol, | ||
710 | &snd_dt019x_ctl_synth_play_vol, | ||
711 | &snd_dt019x_ctl_cd_play_vol, | ||
712 | &snd_dt019x_ctl_mic_play_vol, | ||
713 | &snd_dt019x_ctl_pc_speaker_vol, | ||
714 | &snd_dt019x_ctl_line_play_vol, | ||
715 | &snd_sb16_ctl_mic_play_switch, | ||
716 | &snd_sb16_ctl_cd_play_switch, | ||
717 | &snd_sb16_ctl_line_play_switch, | ||
718 | &snd_dt019x_ctl_pcm_play_switch, | ||
719 | &snd_dt019x_ctl_synth_play_switch, | ||
720 | &snd_dt019x_ctl_capture_source | ||
721 | }; | 657 | }; |
722 | 658 | ||
723 | static unsigned char snd_dt019x_init_values[][2] = { | 659 | static unsigned char snd_dt019x_init_values[][2] = { |
@@ -735,82 +671,37 @@ static unsigned char snd_dt019x_init_values[][2] = { | |||
735 | /* | 671 | /* |
736 | * ALS4000 specific mixer elements | 672 | * ALS4000 specific mixer elements |
737 | */ | 673 | */ |
738 | static struct sbmix_elem snd_als4000_ctl_master_mono_playback_switch = | 674 | static struct sbmix_elem snd_als4000_controls[] = { |
739 | SB_SINGLE("Master Mono Playback Switch", SB_ALS4000_MONO_IO_CTRL, 5, 1); | 675 | SB_DOUBLE("PCM Playback Switch", |
740 | static struct sbmix_elem snd_als4k_ctl_master_mono_capture_route = { | 676 | SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 2, 1, 1), |
677 | SB_DOUBLE("Synth Playback Switch", | ||
678 | SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 4, 3, 1), | ||
679 | SB_SINGLE("Mic Boost (+20dB)", SB_ALS4000_MIC_IN_GAIN, 0, 0x03), | ||
680 | SB_SINGLE("Master Mono Playback Switch", SB_ALS4000_MONO_IO_CTRL, 5, 1), | ||
681 | { | ||
741 | .name = "Master Mono Capture Route", | 682 | .name = "Master Mono Capture Route", |
742 | .type = SB_MIX_MONO_CAPTURE_ALS4K | 683 | .type = SB_MIX_MONO_CAPTURE_ALS4K |
743 | }; | 684 | }, |
744 | static struct sbmix_elem snd_als4000_ctl_mono_playback_switch = | 685 | SB_SINGLE("Mono Playback Switch", SB_DT019X_OUTPUT_SW2, 0, 1), |
745 | SB_SINGLE("Mono Playback Switch", SB_DT019X_OUTPUT_SW2, 0, 1); | 686 | SB_SINGLE("Analog Loopback Switch", SB_ALS4000_MIC_IN_GAIN, 7, 0x01), |
746 | static struct sbmix_elem snd_als4000_ctl_mic_20db_boost = | 687 | SB_SINGLE("3D Control - Switch", SB_ALS4000_3D_SND_FX, 6, 0x01), |
747 | SB_SINGLE("Mic Boost (+20dB)", SB_ALS4000_MIC_IN_GAIN, 0, 0x03); | ||
748 | static struct sbmix_elem snd_als4000_ctl_mixer_analog_loopback = | ||
749 | SB_SINGLE("Analog Loopback Switch", SB_ALS4000_MIC_IN_GAIN, 7, 0x01); | ||
750 | static struct sbmix_elem snd_als4000_ctl_mixer_digital_loopback = | ||
751 | SB_SINGLE("Digital Loopback Switch", | 688 | SB_SINGLE("Digital Loopback Switch", |
752 | SB_ALS4000_CR3_CONFIGURATION, 7, 0x01); | 689 | SB_ALS4000_CR3_CONFIGURATION, 7, 0x01), |
753 | /* FIXME: functionality of 3D controls might be swapped, I didn't find | 690 | /* FIXME: functionality of 3D controls might be swapped, I didn't find |
754 | * a description of how to identify what is supposed to be what */ | 691 | * a description of how to identify what is supposed to be what */ |
755 | static struct sbmix_elem snd_als4000_3d_control_switch = | 692 | SB_SINGLE("3D Control - Level", SB_ALS4000_3D_SND_FX, 0, 0x07), |
756 | SB_SINGLE("3D Control - Switch", SB_ALS4000_3D_SND_FX, 6, 0x01); | ||
757 | static struct sbmix_elem snd_als4000_3d_control_ratio = | ||
758 | SB_SINGLE("3D Control - Level", SB_ALS4000_3D_SND_FX, 0, 0x07); | ||
759 | static struct sbmix_elem snd_als4000_3d_control_freq = | ||
760 | /* FIXME: maybe there's actually some standard 3D ctrl name for it?? */ | 693 | /* FIXME: maybe there's actually some standard 3D ctrl name for it?? */ |
761 | SB_SINGLE("3D Control - Freq", SB_ALS4000_3D_SND_FX, 4, 0x03); | 694 | SB_SINGLE("3D Control - Freq", SB_ALS4000_3D_SND_FX, 4, 0x03), |
762 | static struct sbmix_elem snd_als4000_3d_control_delay = | ||
763 | /* FIXME: ALS4000a.pdf mentions BBD (Bucket Brigade Device) time delay, | 695 | /* FIXME: ALS4000a.pdf mentions BBD (Bucket Brigade Device) time delay, |
764 | * but what ALSA 3D attribute is that actually? "Center", "Depth", | 696 | * but what ALSA 3D attribute is that actually? "Center", "Depth", |
765 | * "Wide" or "Space" or even "Level"? Assuming "Wide" for now... */ | 697 | * "Wide" or "Space" or even "Level"? Assuming "Wide" for now... */ |
766 | SB_SINGLE("3D Control - Wide", SB_ALS4000_3D_TIME_DELAY, 0, 0x0f); | 698 | SB_SINGLE("3D Control - Wide", SB_ALS4000_3D_TIME_DELAY, 0, 0x0f), |
767 | static struct sbmix_elem snd_als4000_3d_control_poweroff_switch = | 699 | SB_SINGLE("3D PowerOff Switch", SB_ALS4000_3D_TIME_DELAY, 4, 0x01), |
768 | SB_SINGLE("3D PowerOff Switch", SB_ALS4000_3D_TIME_DELAY, 4, 0x01); | ||
769 | static struct sbmix_elem snd_als4000_ctl_3db_freq_control_switch = | ||
770 | SB_SINGLE("Master Playback 8kHz / 20kHz LPF Switch", | 700 | SB_SINGLE("Master Playback 8kHz / 20kHz LPF Switch", |
771 | SB_ALS4000_FMDAC, 5, 0x01); | 701 | SB_ALS4000_FMDAC, 5, 0x01), |
772 | #ifdef NOT_AVAILABLE | 702 | #ifdef NOT_AVAILABLE |
773 | static struct sbmix_elem snd_als4000_ctl_fmdac = | 703 | SB_SINGLE("FMDAC Switch (Option ?)", SB_ALS4000_FMDAC, 0, 0x01), |
774 | SB_SINGLE("FMDAC Switch (Option ?)", SB_ALS4000_FMDAC, 0, 0x01); | 704 | SB_SINGLE("QSound Mode", SB_ALS4000_QSOUND, 1, 0x1f), |
775 | static struct sbmix_elem snd_als4000_ctl_qsound = | ||
776 | SB_SINGLE("QSound Mode", SB_ALS4000_QSOUND, 1, 0x1f); | ||
777 | #endif | ||
778 | |||
779 | static struct sbmix_elem *snd_als4000_controls[] = { | ||
780 | /* ALS4000a.PDF regs page */ | ||
781 | &snd_sb16_ctl_master_play_vol, /* MX30/31 12 */ | ||
782 | &snd_dt019x_ctl_pcm_play_switch, /* MX4C 16 */ | ||
783 | &snd_sb16_ctl_pcm_play_vol, /* MX32/33 12 */ | ||
784 | &snd_sb16_ctl_synth_capture_route, /* MX3D/3E 14 */ | ||
785 | &snd_dt019x_ctl_synth_play_switch, /* MX4C 16 */ | ||
786 | &snd_sb16_ctl_synth_play_vol, /* MX34/35 12/13 */ | ||
787 | &snd_sb16_ctl_cd_capture_route, /* MX3D/3E 14 */ | ||
788 | &snd_sb16_ctl_cd_play_switch, /* MX3C 14 */ | ||
789 | &snd_sb16_ctl_cd_play_vol, /* MX36/37 13 */ | ||
790 | &snd_sb16_ctl_line_capture_route, /* MX3D/3E 14 */ | ||
791 | &snd_sb16_ctl_line_play_switch, /* MX3C 14 */ | ||
792 | &snd_sb16_ctl_line_play_vol, /* MX38/39 13 */ | ||
793 | &snd_sb16_ctl_mic_capture_route, /* MX3D/3E 14 */ | ||
794 | &snd_als4000_ctl_mic_20db_boost, /* MX4D 16 */ | ||
795 | &snd_sb16_ctl_mic_play_switch, /* MX3C 14 */ | ||
796 | &snd_sb16_ctl_mic_play_vol, /* MX3A 13 */ | ||
797 | &snd_sb16_ctl_pc_speaker_vol, /* MX3B 14 */ | ||
798 | &snd_sb16_ctl_capture_vol, /* MX3F/40 15 */ | ||
799 | &snd_sb16_ctl_play_vol, /* MX41/42 15 */ | ||
800 | &snd_als4000_ctl_master_mono_playback_switch, /* MX4C 16 */ | ||
801 | &snd_als4k_ctl_master_mono_capture_route, /* MX4B 16 */ | ||
802 | &snd_als4000_ctl_mono_playback_switch, /* MX4C 16 */ | ||
803 | &snd_als4000_ctl_mixer_analog_loopback, /* MX4D 16 */ | ||
804 | &snd_als4000_ctl_mixer_digital_loopback, /* CR3 21 */ | ||
805 | &snd_als4000_3d_control_switch, /* MX50 17 */ | ||
806 | &snd_als4000_3d_control_ratio, /* MX50 17 */ | ||
807 | &snd_als4000_3d_control_freq, /* MX50 17 */ | ||
808 | &snd_als4000_3d_control_delay, /* MX51 18 */ | ||
809 | &snd_als4000_3d_control_poweroff_switch, /* MX51 18 */ | ||
810 | &snd_als4000_ctl_3db_freq_control_switch, /* MX4F 17 */ | ||
811 | #ifdef NOT_AVAILABLE | ||
812 | &snd_als4000_ctl_fmdac, | ||
813 | &snd_als4000_ctl_qsound, | ||
814 | #endif | 705 | #endif |
815 | }; | 706 | }; |
816 | 707 | ||
@@ -829,11 +720,10 @@ static unsigned char snd_als4000_init_values[][2] = { | |||
829 | { SB_ALS4000_MIC_IN_GAIN, 0 }, | 720 | { SB_ALS4000_MIC_IN_GAIN, 0 }, |
830 | }; | 721 | }; |
831 | 722 | ||
832 | |||
833 | /* | 723 | /* |
834 | */ | 724 | */ |
835 | static int snd_sbmixer_init(struct snd_sb *chip, | 725 | static int snd_sbmixer_init(struct snd_sb *chip, |
836 | struct sbmix_elem **controls, | 726 | struct sbmix_elem *controls, |
837 | int controls_count, | 727 | int controls_count, |
838 | unsigned char map[][2], | 728 | unsigned char map[][2], |
839 | int map_count, | 729 | int map_count, |
@@ -856,7 +746,8 @@ static int snd_sbmixer_init(struct snd_sb *chip, | |||
856 | } | 746 | } |
857 | 747 | ||
858 | for (idx = 0; idx < controls_count; idx++) { | 748 | for (idx = 0; idx < controls_count; idx++) { |
859 | if ((err = snd_sbmixer_add_ctl_elem(chip, controls[idx])) < 0) | 749 | err = snd_sbmixer_add_ctl_elem(chip, &controls[idx]); |
750 | if (err < 0) | ||
860 | return err; | 751 | return err; |
861 | } | 752 | } |
862 | snd_component_add(card, name); | 753 | snd_component_add(card, name); |
@@ -888,6 +779,7 @@ int snd_sbmixer_new(struct snd_sb *chip) | |||
888 | return err; | 779 | return err; |
889 | break; | 780 | break; |
890 | case SB_HW_PRO: | 781 | case SB_HW_PRO: |
782 | case SB_HW_JAZZ16: | ||
891 | if ((err = snd_sbmixer_init(chip, | 783 | if ((err = snd_sbmixer_init(chip, |
892 | snd_sbpro_controls, | 784 | snd_sbpro_controls, |
893 | ARRAY_SIZE(snd_sbpro_controls), | 785 | ARRAY_SIZE(snd_sbpro_controls), |
@@ -908,6 +800,15 @@ int snd_sbmixer_new(struct snd_sb *chip) | |||
908 | return err; | 800 | return err; |
909 | break; | 801 | break; |
910 | case SB_HW_ALS4000: | 802 | case SB_HW_ALS4000: |
803 | /* use only the first 16 controls from SB16 */ | ||
804 | err = snd_sbmixer_init(chip, | ||
805 | snd_sb16_controls, | ||
806 | 16, | ||
807 | snd_sb16_init_values, | ||
808 | ARRAY_SIZE(snd_sb16_init_values), | ||
809 | "ALS4000"); | ||
810 | if (err < 0) | ||
811 | return err; | ||
911 | if ((err = snd_sbmixer_init(chip, | 812 | if ((err = snd_sbmixer_init(chip, |
912 | snd_als4000_controls, | 813 | snd_als4000_controls, |
913 | ARRAY_SIZE(snd_als4000_controls), | 814 | ARRAY_SIZE(snd_als4000_controls), |
@@ -1029,6 +930,7 @@ void snd_sbmixer_suspend(struct snd_sb *chip) | |||
1029 | save_mixer(chip, sb20_saved_regs, ARRAY_SIZE(sb20_saved_regs)); | 930 | save_mixer(chip, sb20_saved_regs, ARRAY_SIZE(sb20_saved_regs)); |
1030 | break; | 931 | break; |
1031 | case SB_HW_PRO: | 932 | case SB_HW_PRO: |
933 | case SB_HW_JAZZ16: | ||
1032 | save_mixer(chip, sbpro_saved_regs, ARRAY_SIZE(sbpro_saved_regs)); | 934 | save_mixer(chip, sbpro_saved_regs, ARRAY_SIZE(sbpro_saved_regs)); |
1033 | break; | 935 | break; |
1034 | case SB_HW_16: | 936 | case SB_HW_16: |
@@ -1055,6 +957,7 @@ void snd_sbmixer_resume(struct snd_sb *chip) | |||
1055 | restore_mixer(chip, sb20_saved_regs, ARRAY_SIZE(sb20_saved_regs)); | 957 | restore_mixer(chip, sb20_saved_regs, ARRAY_SIZE(sb20_saved_regs)); |
1056 | break; | 958 | break; |
1057 | case SB_HW_PRO: | 959 | case SB_HW_PRO: |
960 | case SB_HW_JAZZ16: | ||
1058 | restore_mixer(chip, sbpro_saved_regs, ARRAY_SIZE(sbpro_saved_regs)); | 961 | restore_mixer(chip, sbpro_saved_regs, ARRAY_SIZE(sbpro_saved_regs)); |
1059 | break; | 962 | break; |
1060 | case SB_HW_16: | 963 | case SB_HW_16: |
diff --git a/sound/isa/wss/wss_lib.c b/sound/isa/wss/wss_lib.c index 5b9d6c18bc45..9191b32d9130 100644 --- a/sound/isa/wss/wss_lib.c +++ b/sound/isa/wss/wss_lib.c | |||
@@ -2014,6 +2014,7 @@ static int snd_wss_info_mux(struct snd_kcontrol *kcontrol, | |||
2014 | case WSS_HW_INTERWAVE: | 2014 | case WSS_HW_INTERWAVE: |
2015 | ptexts = gusmax_texts; | 2015 | ptexts = gusmax_texts; |
2016 | break; | 2016 | break; |
2017 | case WSS_HW_OPTI93X: | ||
2017 | case WSS_HW_OPL3SA2: | 2018 | case WSS_HW_OPL3SA2: |
2018 | ptexts = opl3sa_texts; | 2019 | ptexts = opl3sa_texts; |
2019 | break; | 2020 | break; |
@@ -2246,54 +2247,12 @@ WSS_SINGLE("Beep Bypass Playback Switch", 0, | |||
2246 | CS4231_MONO_CTRL, 5, 1, 0), | 2247 | CS4231_MONO_CTRL, 5, 1, 0), |
2247 | }; | 2248 | }; |
2248 | 2249 | ||
2249 | static struct snd_kcontrol_new snd_opti93x_controls[] = { | ||
2250 | WSS_DOUBLE("Master Playback Switch", 0, | ||
2251 | OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 7, 7, 1, 1), | ||
2252 | WSS_DOUBLE_TLV("Master Playback Volume", 0, | ||
2253 | OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 1, 1, 31, 1, | ||
2254 | db_scale_6bit), | ||
2255 | WSS_DOUBLE("PCM Playback Switch", 0, | ||
2256 | CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1), | ||
2257 | WSS_DOUBLE("PCM Playback Volume", 0, | ||
2258 | CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 31, 1), | ||
2259 | WSS_DOUBLE("FM Playback Switch", 0, | ||
2260 | CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1), | ||
2261 | WSS_DOUBLE("FM Playback Volume", 0, | ||
2262 | CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 1, 1, 15, 1), | ||
2263 | WSS_DOUBLE("Line Playback Switch", 0, | ||
2264 | CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1), | ||
2265 | WSS_DOUBLE("Line Playback Volume", 0, | ||
2266 | CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 15, 1), | ||
2267 | WSS_DOUBLE("Mic Playback Switch", 0, | ||
2268 | OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 7, 7, 1, 1), | ||
2269 | WSS_DOUBLE("Mic Playback Volume", 0, | ||
2270 | OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 1, 1, 15, 1), | ||
2271 | WSS_DOUBLE("Mic Boost", 0, | ||
2272 | CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 5, 5, 1, 0), | ||
2273 | WSS_DOUBLE("CD Playback Switch", 0, | ||
2274 | CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1), | ||
2275 | WSS_DOUBLE("CD Playback Volume", 0, | ||
2276 | CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 1, 1, 15, 1), | ||
2277 | WSS_DOUBLE("Aux Playback Switch", 0, | ||
2278 | OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 7, 7, 1, 1), | ||
2279 | WSS_DOUBLE("Aux Playback Volume", 0, | ||
2280 | OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 1, 1, 15, 1), | ||
2281 | WSS_DOUBLE("Capture Volume", 0, | ||
2282 | CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0), | ||
2283 | { | ||
2284 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2285 | .name = "Capture Source", | ||
2286 | .info = snd_wss_info_mux, | ||
2287 | .get = snd_wss_get_mux, | ||
2288 | .put = snd_wss_put_mux, | ||
2289 | } | ||
2290 | }; | ||
2291 | |||
2292 | int snd_wss_mixer(struct snd_wss *chip) | 2250 | int snd_wss_mixer(struct snd_wss *chip) |
2293 | { | 2251 | { |
2294 | struct snd_card *card; | 2252 | struct snd_card *card; |
2295 | unsigned int idx; | 2253 | unsigned int idx; |
2296 | int err; | 2254 | int err; |
2255 | int count = ARRAY_SIZE(snd_wss_controls); | ||
2297 | 2256 | ||
2298 | if (snd_BUG_ON(!chip || !chip->pcm)) | 2257 | if (snd_BUG_ON(!chip || !chip->pcm)) |
2299 | return -EINVAL; | 2258 | return -EINVAL; |
@@ -2302,28 +2261,19 @@ int snd_wss_mixer(struct snd_wss *chip) | |||
2302 | 2261 | ||
2303 | strcpy(card->mixername, chip->pcm->name); | 2262 | strcpy(card->mixername, chip->pcm->name); |
2304 | 2263 | ||
2305 | if (chip->hardware == WSS_HW_OPTI93X) | 2264 | /* Use only the first 11 entries on AD1848 */ |
2306 | for (idx = 0; idx < ARRAY_SIZE(snd_opti93x_controls); idx++) { | 2265 | if (chip->hardware & WSS_HW_AD1848_MASK) |
2307 | err = snd_ctl_add(card, | 2266 | count = 11; |
2308 | snd_ctl_new1(&snd_opti93x_controls[idx], | 2267 | /* There is no loopback on OPTI93X */ |
2309 | chip)); | 2268 | else if (chip->hardware == WSS_HW_OPTI93X) |
2310 | if (err < 0) | 2269 | count = 9; |
2311 | return err; | 2270 | |
2312 | } | 2271 | for (idx = 0; idx < count; idx++) { |
2313 | else { | 2272 | err = snd_ctl_add(card, |
2314 | int count = ARRAY_SIZE(snd_wss_controls); | 2273 | snd_ctl_new1(&snd_wss_controls[idx], |
2315 | 2274 | chip)); | |
2316 | /* Use only the first 11 entries on AD1848 */ | 2275 | if (err < 0) |
2317 | if (chip->hardware & WSS_HW_AD1848_MASK) | 2276 | return err; |
2318 | count = 11; | ||
2319 | |||
2320 | for (idx = 0; idx < count; idx++) { | ||
2321 | err = snd_ctl_add(card, | ||
2322 | snd_ctl_new1(&snd_wss_controls[idx], | ||
2323 | chip)); | ||
2324 | if (err < 0) | ||
2325 | return err; | ||
2326 | } | ||
2327 | } | 2277 | } |
2328 | return 0; | 2278 | return 0; |
2329 | } | 2279 | } |
diff --git a/sound/mips/sgio2audio.c b/sound/mips/sgio2audio.c index f1d9d16b5486..6aff217379d9 100644 --- a/sound/mips/sgio2audio.c +++ b/sound/mips/sgio2audio.c | |||
@@ -26,7 +26,6 @@ | |||
26 | #include <linux/delay.h> | 26 | #include <linux/delay.h> |
27 | #include <linux/spinlock.h> | 27 | #include <linux/spinlock.h> |
28 | #include <linux/gfp.h> | 28 | #include <linux/gfp.h> |
29 | #include <linux/vmalloc.h> | ||
30 | #include <linux/interrupt.h> | 29 | #include <linux/interrupt.h> |
31 | #include <linux/dma-mapping.h> | 30 | #include <linux/dma-mapping.h> |
32 | #include <linux/platform_device.h> | 31 | #include <linux/platform_device.h> |
@@ -603,25 +602,14 @@ static int snd_sgio2audio_pcm_close(struct snd_pcm_substream *substream) | |||
603 | static int snd_sgio2audio_pcm_hw_params(struct snd_pcm_substream *substream, | 602 | static int snd_sgio2audio_pcm_hw_params(struct snd_pcm_substream *substream, |
604 | struct snd_pcm_hw_params *hw_params) | 603 | struct snd_pcm_hw_params *hw_params) |
605 | { | 604 | { |
606 | struct snd_pcm_runtime *runtime = substream->runtime; | 605 | return snd_pcm_lib_alloc_vmalloc_buffer(substream, |
607 | int size = params_buffer_bytes(hw_params); | 606 | params_buffer_bytes(hw_params)); |
608 | |||
609 | /* alloc virtual 'dma' area */ | ||
610 | if (runtime->dma_area) | ||
611 | vfree(runtime->dma_area); | ||
612 | runtime->dma_area = vmalloc_user(size); | ||
613 | if (runtime->dma_area == NULL) | ||
614 | return -ENOMEM; | ||
615 | runtime->dma_bytes = size; | ||
616 | return 0; | ||
617 | } | 607 | } |
618 | 608 | ||
619 | /* hw_free callback */ | 609 | /* hw_free callback */ |
620 | static int snd_sgio2audio_pcm_hw_free(struct snd_pcm_substream *substream) | 610 | static int snd_sgio2audio_pcm_hw_free(struct snd_pcm_substream *substream) |
621 | { | 611 | { |
622 | vfree(substream->runtime->dma_area); | 612 | return snd_pcm_lib_free_vmalloc_buffer(substream); |
623 | substream->runtime->dma_area = NULL; | ||
624 | return 0; | ||
625 | } | 613 | } |
626 | 614 | ||
627 | /* prepare callback */ | 615 | /* prepare callback */ |
@@ -692,13 +680,6 @@ snd_sgio2audio_pcm_pointer(struct snd_pcm_substream *substream) | |||
692 | chip->channel[chan->idx].pos); | 680 | chip->channel[chan->idx].pos); |
693 | } | 681 | } |
694 | 682 | ||
695 | /* get the physical page pointer on the given offset */ | ||
696 | static struct page *snd_sgio2audio_page(struct snd_pcm_substream *substream, | ||
697 | unsigned long offset) | ||
698 | { | ||
699 | return vmalloc_to_page(substream->runtime->dma_area + offset); | ||
700 | } | ||
701 | |||
702 | /* operators */ | 683 | /* operators */ |
703 | static struct snd_pcm_ops snd_sgio2audio_playback1_ops = { | 684 | static struct snd_pcm_ops snd_sgio2audio_playback1_ops = { |
704 | .open = snd_sgio2audio_playback1_open, | 685 | .open = snd_sgio2audio_playback1_open, |
@@ -709,7 +690,8 @@ static struct snd_pcm_ops snd_sgio2audio_playback1_ops = { | |||
709 | .prepare = snd_sgio2audio_pcm_prepare, | 690 | .prepare = snd_sgio2audio_pcm_prepare, |
710 | .trigger = snd_sgio2audio_pcm_trigger, | 691 | .trigger = snd_sgio2audio_pcm_trigger, |
711 | .pointer = snd_sgio2audio_pcm_pointer, | 692 | .pointer = snd_sgio2audio_pcm_pointer, |
712 | .page = snd_sgio2audio_page, | 693 | .page = snd_pcm_lib_get_vmalloc_page, |
694 | .mmap = snd_pcm_lib_mmap_vmalloc, | ||
713 | }; | 695 | }; |
714 | 696 | ||
715 | static struct snd_pcm_ops snd_sgio2audio_playback2_ops = { | 697 | static struct snd_pcm_ops snd_sgio2audio_playback2_ops = { |
@@ -721,7 +703,8 @@ static struct snd_pcm_ops snd_sgio2audio_playback2_ops = { | |||
721 | .prepare = snd_sgio2audio_pcm_prepare, | 703 | .prepare = snd_sgio2audio_pcm_prepare, |
722 | .trigger = snd_sgio2audio_pcm_trigger, | 704 | .trigger = snd_sgio2audio_pcm_trigger, |
723 | .pointer = snd_sgio2audio_pcm_pointer, | 705 | .pointer = snd_sgio2audio_pcm_pointer, |
724 | .page = snd_sgio2audio_page, | 706 | .page = snd_pcm_lib_get_vmalloc_page, |
707 | .mmap = snd_pcm_lib_mmap_vmalloc, | ||
725 | }; | 708 | }; |
726 | 709 | ||
727 | static struct snd_pcm_ops snd_sgio2audio_capture_ops = { | 710 | static struct snd_pcm_ops snd_sgio2audio_capture_ops = { |
@@ -733,7 +716,8 @@ static struct snd_pcm_ops snd_sgio2audio_capture_ops = { | |||
733 | .prepare = snd_sgio2audio_pcm_prepare, | 716 | .prepare = snd_sgio2audio_pcm_prepare, |
734 | .trigger = snd_sgio2audio_pcm_trigger, | 717 | .trigger = snd_sgio2audio_pcm_trigger, |
735 | .pointer = snd_sgio2audio_pcm_pointer, | 718 | .pointer = snd_sgio2audio_pcm_pointer, |
736 | .page = snd_sgio2audio_page, | 719 | .page = snd_pcm_lib_get_vmalloc_page, |
720 | .mmap = snd_pcm_lib_mmap_vmalloc, | ||
737 | }; | 721 | }; |
738 | 722 | ||
739 | /* | 723 | /* |
diff --git a/sound/oss/au1550_ac97.c b/sound/oss/au1550_ac97.c index 4191acccbcdb..c1070e33b32f 100644 --- a/sound/oss/au1550_ac97.c +++ b/sound/oss/au1550_ac97.c | |||
@@ -614,7 +614,8 @@ start_adc(struct au1550_state *s) | |||
614 | /* Put two buffers on the ring to get things started. | 614 | /* Put two buffers on the ring to get things started. |
615 | */ | 615 | */ |
616 | for (i=0; i<2; i++) { | 616 | for (i=0; i<2; i++) { |
617 | au1xxx_dbdma_put_dest(db->dmanr, db->nextIn, db->dma_fragsize); | 617 | au1xxx_dbdma_put_dest(db->dmanr, virt_to_phys(db->nextIn), |
618 | db->dma_fragsize, DDMA_FLAGS_IE); | ||
618 | 619 | ||
619 | db->nextIn += db->dma_fragsize; | 620 | db->nextIn += db->dma_fragsize; |
620 | if (db->nextIn >= db->rawbuf + db->dmasize) | 621 | if (db->nextIn >= db->rawbuf + db->dmasize) |
@@ -732,8 +733,9 @@ static void dac_dma_interrupt(int irq, void *dev_id) | |||
732 | db->dma_qcount--; | 733 | db->dma_qcount--; |
733 | 734 | ||
734 | if (db->count >= db->fragsize) { | 735 | if (db->count >= db->fragsize) { |
735 | if (au1xxx_dbdma_put_source(db->dmanr, db->nextOut, | 736 | if (au1xxx_dbdma_put_source(db->dmanr, |
736 | db->fragsize) == 0) { | 737 | virt_to_phys(db->nextOut), db->fragsize, |
738 | DDMA_FLAGS_IE) == 0) { | ||
737 | err("qcount < 2 and no ring room!"); | 739 | err("qcount < 2 and no ring room!"); |
738 | } | 740 | } |
739 | db->nextOut += db->fragsize; | 741 | db->nextOut += db->fragsize; |
@@ -777,7 +779,8 @@ static void adc_dma_interrupt(int irq, void *dev_id) | |||
777 | 779 | ||
778 | /* Put a new empty buffer on the destination DMA. | 780 | /* Put a new empty buffer on the destination DMA. |
779 | */ | 781 | */ |
780 | au1xxx_dbdma_put_dest(dp->dmanr, dp->nextIn, dp->dma_fragsize); | 782 | au1xxx_dbdma_put_dest(dp->dmanr, virt_to_phys(dp->nextIn), |
783 | dp->dma_fragsize, DDMA_FLAGS_IE); | ||
781 | 784 | ||
782 | dp->nextIn += dp->dma_fragsize; | 785 | dp->nextIn += dp->dma_fragsize; |
783 | if (dp->nextIn >= dp->rawbuf + dp->dmasize) | 786 | if (dp->nextIn >= dp->rawbuf + dp->dmasize) |
@@ -1177,8 +1180,9 @@ au1550_write(struct file *file, const char *buffer, size_t count, loff_t * ppos) | |||
1177 | * we know the dma has stopped. | 1180 | * we know the dma has stopped. |
1178 | */ | 1181 | */ |
1179 | while ((db->dma_qcount < 2) && (db->count >= db->fragsize)) { | 1182 | while ((db->dma_qcount < 2) && (db->count >= db->fragsize)) { |
1180 | if (au1xxx_dbdma_put_source(db->dmanr, db->nextOut, | 1183 | if (au1xxx_dbdma_put_source(db->dmanr, |
1181 | db->fragsize) == 0) { | 1184 | virt_to_phys(db->nextOut), db->fragsize, |
1185 | DDMA_FLAGS_IE) == 0) { | ||
1182 | err("qcount < 2 and no ring room!"); | 1186 | err("qcount < 2 and no ring room!"); |
1183 | } | 1187 | } |
1184 | db->nextOut += db->fragsize; | 1188 | db->nextOut += db->fragsize; |
diff --git a/sound/oss/kahlua.c b/sound/oss/kahlua.c index 89466b056be7..24d152ccf80d 100644 --- a/sound/oss/kahlua.c +++ b/sound/oss/kahlua.c | |||
@@ -198,7 +198,7 @@ MODULE_LICENSE("GPL"); | |||
198 | * 5530 only. The 5510/5520 decode is different. | 198 | * 5530 only. The 5510/5520 decode is different. |
199 | */ | 199 | */ |
200 | 200 | ||
201 | static struct pci_device_id id_tbl[] = { | 201 | static DEFINE_PCI_DEVICE_TABLE(id_tbl) = { |
202 | { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5530_AUDIO), 0 }, | 202 | { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5530_AUDIO), 0 }, |
203 | { } | 203 | { } |
204 | }; | 204 | }; |
diff --git a/sound/oss/soundcard.c b/sound/oss/soundcard.c index c62530943888..fde7c12fe5da 100644 --- a/sound/oss/soundcard.c +++ b/sound/oss/soundcard.c | |||
@@ -328,11 +328,11 @@ static int sound_mixer_ioctl(int mixdev, unsigned int cmd, void __user *arg) | |||
328 | return mixer_devs[mixdev]->ioctl(mixdev, cmd, arg); | 328 | return mixer_devs[mixdev]->ioctl(mixdev, cmd, arg); |
329 | } | 329 | } |
330 | 330 | ||
331 | static int sound_ioctl(struct inode *inode, struct file *file, | 331 | static long sound_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
332 | unsigned int cmd, unsigned long arg) | ||
333 | { | 332 | { |
334 | int len = 0, dtype; | 333 | int len = 0, dtype; |
335 | int dev = iminor(inode); | 334 | int dev = iminor(file->f_dentry->d_inode); |
335 | long ret = -EINVAL; | ||
336 | void __user *p = (void __user *)arg; | 336 | void __user *p = (void __user *)arg; |
337 | 337 | ||
338 | if (_SIOC_DIR(cmd) != _SIOC_NONE && _SIOC_DIR(cmd) != 0) { | 338 | if (_SIOC_DIR(cmd) != _SIOC_NONE && _SIOC_DIR(cmd) != 0) { |
@@ -353,6 +353,7 @@ static int sound_ioctl(struct inode *inode, struct file *file, | |||
353 | if (cmd == OSS_GETVERSION) | 353 | if (cmd == OSS_GETVERSION) |
354 | return __put_user(SOUND_VERSION, (int __user *)p); | 354 | return __put_user(SOUND_VERSION, (int __user *)p); |
355 | 355 | ||
356 | lock_kernel(); | ||
356 | if (_IOC_TYPE(cmd) == 'M' && num_mixers > 0 && /* Mixer ioctl */ | 357 | if (_IOC_TYPE(cmd) == 'M' && num_mixers > 0 && /* Mixer ioctl */ |
357 | (dev & 0x0f) != SND_DEV_CTL) { | 358 | (dev & 0x0f) != SND_DEV_CTL) { |
358 | dtype = dev & 0x0f; | 359 | dtype = dev & 0x0f; |
@@ -360,24 +361,31 @@ static int sound_ioctl(struct inode *inode, struct file *file, | |||
360 | case SND_DEV_DSP: | 361 | case SND_DEV_DSP: |
361 | case SND_DEV_DSP16: | 362 | case SND_DEV_DSP16: |
362 | case SND_DEV_AUDIO: | 363 | case SND_DEV_AUDIO: |
363 | return sound_mixer_ioctl(audio_devs[dev >> 4]->mixer_dev, | 364 | ret = sound_mixer_ioctl(audio_devs[dev >> 4]->mixer_dev, |
364 | cmd, p); | 365 | cmd, p); |
365 | 366 | break; | |
366 | default: | 367 | default: |
367 | return sound_mixer_ioctl(dev >> 4, cmd, p); | 368 | ret = sound_mixer_ioctl(dev >> 4, cmd, p); |
369 | break; | ||
368 | } | 370 | } |
371 | unlock_kernel(); | ||
372 | return ret; | ||
369 | } | 373 | } |
374 | |||
370 | switch (dev & 0x0f) { | 375 | switch (dev & 0x0f) { |
371 | case SND_DEV_CTL: | 376 | case SND_DEV_CTL: |
372 | if (cmd == SOUND_MIXER_GETLEVELS) | 377 | if (cmd == SOUND_MIXER_GETLEVELS) |
373 | return get_mixer_levels(p); | 378 | ret = get_mixer_levels(p); |
374 | if (cmd == SOUND_MIXER_SETLEVELS) | 379 | else if (cmd == SOUND_MIXER_SETLEVELS) |
375 | return set_mixer_levels(p); | 380 | ret = set_mixer_levels(p); |
376 | return sound_mixer_ioctl(dev >> 4, cmd, p); | 381 | else |
382 | ret = sound_mixer_ioctl(dev >> 4, cmd, p); | ||
383 | break; | ||
377 | 384 | ||
378 | case SND_DEV_SEQ: | 385 | case SND_DEV_SEQ: |
379 | case SND_DEV_SEQ2: | 386 | case SND_DEV_SEQ2: |
380 | return sequencer_ioctl(dev, file, cmd, p); | 387 | ret = sequencer_ioctl(dev, file, cmd, p); |
388 | break; | ||
381 | 389 | ||
382 | case SND_DEV_DSP: | 390 | case SND_DEV_DSP: |
383 | case SND_DEV_DSP16: | 391 | case SND_DEV_DSP16: |
@@ -390,7 +398,8 @@ static int sound_ioctl(struct inode *inode, struct file *file, | |||
390 | break; | 398 | break; |
391 | 399 | ||
392 | } | 400 | } |
393 | return -EINVAL; | 401 | unlock_kernel(); |
402 | return ret; | ||
394 | } | 403 | } |
395 | 404 | ||
396 | static unsigned int sound_poll(struct file *file, poll_table * wait) | 405 | static unsigned int sound_poll(struct file *file, poll_table * wait) |
@@ -490,7 +499,7 @@ const struct file_operations oss_sound_fops = { | |||
490 | .read = sound_read, | 499 | .read = sound_read, |
491 | .write = sound_write, | 500 | .write = sound_write, |
492 | .poll = sound_poll, | 501 | .poll = sound_poll, |
493 | .ioctl = sound_ioctl, | 502 | .unlocked_ioctl = sound_ioctl, |
494 | .mmap = sound_mmap, | 503 | .mmap = sound_mmap, |
495 | .open = sound_open, | 504 | .open = sound_open, |
496 | .release = sound_release, | 505 | .release = sound_release, |
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 351654cf7b09..1298c68d6bf0 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig | |||
@@ -789,6 +789,7 @@ config SND_VIRTUOSO | |||
789 | Say Y here to include support for sound cards based on the | 789 | Say Y here to include support for sound cards based on the |
790 | Asus AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X, | 790 | Asus AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X, |
791 | Essence ST (Deluxe), and Essence STX. | 791 | Essence ST (Deluxe), and Essence STX. |
792 | Support for the DS is experimental. | ||
792 | Support for the HDAV1.3 (Deluxe) is very experimental. | 793 | Support for the HDAV1.3 (Deluxe) is very experimental. |
793 | 794 | ||
794 | To compile this driver as a module, choose M here: the module | 795 | To compile this driver as a module, choose M here: the module |
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index d9266bae2849..1caf5e3c1f6a 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c | |||
@@ -544,25 +544,10 @@ static int patch_wolfson04(struct snd_ac97 * ac97) | |||
544 | return 0; | 544 | return 0; |
545 | } | 545 | } |
546 | 546 | ||
547 | static int patch_wolfson_wm9705_specific(struct snd_ac97 * ac97) | ||
548 | { | ||
549 | int err, i; | ||
550 | for (i = 0; i < ARRAY_SIZE(wm97xx_snd_ac97_controls); i++) { | ||
551 | if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm97xx_snd_ac97_controls[i], ac97))) < 0) | ||
552 | return err; | ||
553 | } | ||
554 | snd_ac97_write_cache(ac97, 0x72, 0x0808); | ||
555 | return 0; | ||
556 | } | ||
557 | |||
558 | static struct snd_ac97_build_ops patch_wolfson_wm9705_ops = { | ||
559 | .build_specific = patch_wolfson_wm9705_specific, | ||
560 | }; | ||
561 | |||
562 | static int patch_wolfson05(struct snd_ac97 * ac97) | 547 | static int patch_wolfson05(struct snd_ac97 * ac97) |
563 | { | 548 | { |
564 | /* WM9705, WM9710 */ | 549 | /* WM9705, WM9710 */ |
565 | ac97->build_ops = &patch_wolfson_wm9705_ops; | 550 | ac97->build_ops = &patch_wolfson_wm9703_ops; |
566 | #ifdef CONFIG_TOUCHSCREEN_WM9705 | 551 | #ifdef CONFIG_TOUCHSCREEN_WM9705 |
567 | /* WM9705 touchscreen uses AUX and VIDEO for touch */ | 552 | /* WM9705 touchscreen uses AUX and VIDEO for touch */ |
568 | ac97->flags |= AC97_HAS_NO_VIDEO | AC97_HAS_NO_AUX; | 553 | ac97->flags |= AC97_HAS_NO_VIDEO | AC97_HAS_NO_AUX; |
diff --git a/sound/pci/ad1889.c b/sound/pci/ad1889.c index 8f5098f92c37..4382d0fa6b9a 100644 --- a/sound/pci/ad1889.c +++ b/sound/pci/ad1889.c | |||
@@ -1048,7 +1048,7 @@ snd_ad1889_remove(struct pci_dev *pci) | |||
1048 | pci_set_drvdata(pci, NULL); | 1048 | pci_set_drvdata(pci, NULL); |
1049 | } | 1049 | } |
1050 | 1050 | ||
1051 | static struct pci_device_id snd_ad1889_ids[] = { | 1051 | static DEFINE_PCI_DEVICE_TABLE(snd_ad1889_ids) = { |
1052 | { PCI_DEVICE(PCI_VENDOR_ID_ANALOG_DEVICES, PCI_DEVICE_ID_AD1889JS) }, | 1052 | { PCI_DEVICE(PCI_VENDOR_ID_ANALOG_DEVICES, PCI_DEVICE_ID_AD1889JS) }, |
1053 | { 0, }, | 1053 | { 0, }, |
1054 | }; | 1054 | }; |
diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c index aaf4da68969c..5c6e322a48f0 100644 --- a/sound/pci/ali5451/ali5451.c +++ b/sound/pci/ali5451/ali5451.c | |||
@@ -275,7 +275,7 @@ struct snd_ali { | |||
275 | #endif | 275 | #endif |
276 | }; | 276 | }; |
277 | 277 | ||
278 | static struct pci_device_id snd_ali_ids[] = { | 278 | static DEFINE_PCI_DEVICE_TABLE(snd_ali_ids) = { |
279 | {PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5451), 0, 0, 0}, | 279 | {PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5451), 0, 0, 0}, |
280 | {0, } | 280 | {0, } |
281 | }; | 281 | }; |
diff --git a/sound/pci/als300.c b/sound/pci/als300.c index 3aa35af7ca91..d7653cb7ac60 100644 --- a/sound/pci/als300.c +++ b/sound/pci/als300.c | |||
@@ -145,7 +145,7 @@ struct snd_als300_substream_data { | |||
145 | int block_counter_register; | 145 | int block_counter_register; |
146 | }; | 146 | }; |
147 | 147 | ||
148 | static struct pci_device_id snd_als300_ids[] = { | 148 | static DEFINE_PCI_DEVICE_TABLE(snd_als300_ids) = { |
149 | { 0x4005, 0x0300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_ALS300 }, | 149 | { 0x4005, 0x0300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_ALS300 }, |
150 | { 0x4005, 0x0308, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_ALS300_PLUS }, | 150 | { 0x4005, 0x0308, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_ALS300_PLUS }, |
151 | { 0, } | 151 | { 0, } |
diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c index 3dbacde1a5af..d75cf7b06426 100644 --- a/sound/pci/als4000.c +++ b/sound/pci/als4000.c | |||
@@ -117,7 +117,7 @@ struct snd_card_als4000 { | |||
117 | #endif | 117 | #endif |
118 | }; | 118 | }; |
119 | 119 | ||
120 | static struct pci_device_id snd_als4000_ids[] = { | 120 | static DEFINE_PCI_DEVICE_TABLE(snd_als4000_ids) = { |
121 | { 0x4005, 0x4000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* ALS4000 */ | 121 | { 0x4005, 0x4000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* ALS4000 */ |
122 | { 0, } | 122 | { 0, } |
123 | }; | 123 | }; |
diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c index 42b4fbbd8e2b..49d572a7b235 100644 --- a/sound/pci/atiixp.c +++ b/sound/pci/atiixp.c | |||
@@ -286,7 +286,7 @@ struct atiixp { | |||
286 | 286 | ||
287 | /* | 287 | /* |
288 | */ | 288 | */ |
289 | static struct pci_device_id snd_atiixp_ids[] = { | 289 | static DEFINE_PCI_DEVICE_TABLE(snd_atiixp_ids) = { |
290 | { PCI_VDEVICE(ATI, 0x4341), 0 }, /* SB200 */ | 290 | { PCI_VDEVICE(ATI, 0x4341), 0 }, /* SB200 */ |
291 | { PCI_VDEVICE(ATI, 0x4361), 0 }, /* SB300 */ | 291 | { PCI_VDEVICE(ATI, 0x4361), 0 }, /* SB300 */ |
292 | { PCI_VDEVICE(ATI, 0x4370), 0 }, /* SB400 */ | 292 | { PCI_VDEVICE(ATI, 0x4370), 0 }, /* SB400 */ |
diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c index e7e147bf8eb2..91d7036b6411 100644 --- a/sound/pci/atiixp_modem.c +++ b/sound/pci/atiixp_modem.c | |||
@@ -261,7 +261,7 @@ struct atiixp_modem { | |||
261 | 261 | ||
262 | /* | 262 | /* |
263 | */ | 263 | */ |
264 | static struct pci_device_id snd_atiixp_ids[] = { | 264 | static DEFINE_PCI_DEVICE_TABLE(snd_atiixp_ids) = { |
265 | { PCI_VDEVICE(ATI, 0x434d), 0 }, /* SB200 */ | 265 | { PCI_VDEVICE(ATI, 0x434d), 0 }, /* SB200 */ |
266 | { PCI_VDEVICE(ATI, 0x4378), 0 }, /* SB400 */ | 266 | { PCI_VDEVICE(ATI, 0x4378), 0 }, /* SB400 */ |
267 | { 0, } | 267 | { 0, } |
diff --git a/sound/pci/au88x0/au8810.c b/sound/pci/au88x0/au8810.c index c0e8c6b295cb..aa51cc7771dd 100644 --- a/sound/pci/au88x0/au8810.c +++ b/sound/pci/au88x0/au8810.c | |||
@@ -1,6 +1,6 @@ | |||
1 | #include "au8810.h" | 1 | #include "au8810.h" |
2 | #include "au88x0.h" | 2 | #include "au88x0.h" |
3 | static struct pci_device_id snd_vortex_ids[] = { | 3 | static DEFINE_PCI_DEVICE_TABLE(snd_vortex_ids) = { |
4 | {PCI_VDEVICE(AUREAL, PCI_DEVICE_ID_AUREAL_ADVANTAGE), 1,}, | 4 | {PCI_VDEVICE(AUREAL, PCI_DEVICE_ID_AUREAL_ADVANTAGE), 1,}, |
5 | {0,} | 5 | {0,} |
6 | }; | 6 | }; |
diff --git a/sound/pci/au88x0/au8820.c b/sound/pci/au88x0/au8820.c index a6527330df58..2f321e7306cd 100644 --- a/sound/pci/au88x0/au8820.c +++ b/sound/pci/au88x0/au8820.c | |||
@@ -1,6 +1,6 @@ | |||
1 | #include "au8820.h" | 1 | #include "au8820.h" |
2 | #include "au88x0.h" | 2 | #include "au88x0.h" |
3 | static struct pci_device_id snd_vortex_ids[] = { | 3 | static DEFINE_PCI_DEVICE_TABLE(snd_vortex_ids) = { |
4 | {PCI_VDEVICE(AUREAL, PCI_DEVICE_ID_AUREAL_VORTEX_1), 0,}, | 4 | {PCI_VDEVICE(AUREAL, PCI_DEVICE_ID_AUREAL_VORTEX_1), 0,}, |
5 | {0,} | 5 | {0,} |
6 | }; | 6 | }; |
diff --git a/sound/pci/au88x0/au8830.c b/sound/pci/au88x0/au8830.c index 6c702ad4352a..279b78f06d22 100644 --- a/sound/pci/au88x0/au8830.c +++ b/sound/pci/au88x0/au8830.c | |||
@@ -1,6 +1,6 @@ | |||
1 | #include "au8830.h" | 1 | #include "au8830.h" |
2 | #include "au88x0.h" | 2 | #include "au88x0.h" |
3 | static struct pci_device_id snd_vortex_ids[] = { | 3 | static DEFINE_PCI_DEVICE_TABLE(snd_vortex_ids) = { |
4 | {PCI_VDEVICE(AUREAL, PCI_DEVICE_ID_AUREAL_VORTEX_2), 0,}, | 4 | {PCI_VDEVICE(AUREAL, PCI_DEVICE_ID_AUREAL_VORTEX_2), 0,}, |
5 | {0,} | 5 | {0,} |
6 | }; | 6 | }; |
diff --git a/sound/pci/aw2/aw2-alsa.c b/sound/pci/aw2/aw2-alsa.c index 4d34bb0d99d3..67921f93a41e 100644 --- a/sound/pci/aw2/aw2-alsa.c +++ b/sound/pci/aw2/aw2-alsa.c | |||
@@ -164,7 +164,7 @@ MODULE_PARM_DESC(id, "ID string for the Audiowerk2 soundcard."); | |||
164 | module_param_array(enable, bool, NULL, 0444); | 164 | module_param_array(enable, bool, NULL, 0444); |
165 | MODULE_PARM_DESC(enable, "Enable Audiowerk2 soundcard."); | 165 | MODULE_PARM_DESC(enable, "Enable Audiowerk2 soundcard."); |
166 | 166 | ||
167 | static struct pci_device_id snd_aw2_ids[] = { | 167 | static DEFINE_PCI_DEVICE_TABLE(snd_aw2_ids) = { |
168 | {PCI_VENDOR_ID_SAA7146, PCI_DEVICE_ID_SAA7146, 0, 0, | 168 | {PCI_VENDOR_ID_SAA7146, PCI_DEVICE_ID_SAA7146, 0, 0, |
169 | 0, 0, 0}, | 169 | 0, 0, 0}, |
170 | {0} | 170 | {0} |
diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c index 69867ace7860..4679ed83a43b 100644 --- a/sound/pci/azt3328.c +++ b/sound/pci/azt3328.c | |||
@@ -350,7 +350,7 @@ struct snd_azf3328 { | |||
350 | #endif | 350 | #endif |
351 | }; | 351 | }; |
352 | 352 | ||
353 | static const struct pci_device_id snd_azf3328_ids[] = { | 353 | static DEFINE_PCI_DEVICE_TABLE(snd_azf3328_ids) = { |
354 | { 0x122D, 0x50DC, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* PCI168/3328 */ | 354 | { 0x122D, 0x50DC, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* PCI168/3328 */ |
355 | { 0x122D, 0x80DA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* 3328 */ | 355 | { 0x122D, 0x80DA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* 3328 */ |
356 | { 0, } | 356 | { 0, } |
diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c index 4e2b925a94cc..37e1b5df5ab8 100644 --- a/sound/pci/bt87x.c +++ b/sound/pci/bt87x.c | |||
@@ -795,7 +795,7 @@ fail: | |||
795 | .driver_data = SND_BT87X_BOARD_ ## id } | 795 | .driver_data = SND_BT87X_BOARD_ ## id } |
796 | /* driver_data is the card id for that device */ | 796 | /* driver_data is the card id for that device */ |
797 | 797 | ||
798 | static struct pci_device_id snd_bt87x_ids[] = { | 798 | static DEFINE_PCI_DEVICE_TABLE(snd_bt87x_ids) = { |
799 | /* Hauppauge WinTV series */ | 799 | /* Hauppauge WinTV series */ |
800 | BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x0070, 0x13eb, GENERIC), | 800 | BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x0070, 0x13eb, GENERIC), |
801 | /* Hauppauge WinTV series */ | 801 | /* Hauppauge WinTV series */ |
@@ -964,7 +964,7 @@ static void __devexit snd_bt87x_remove(struct pci_dev *pci) | |||
964 | 964 | ||
965 | /* default entries for all Bt87x cards - it's not exported */ | 965 | /* default entries for all Bt87x cards - it's not exported */ |
966 | /* driver_data is set to 0 to call detection */ | 966 | /* driver_data is set to 0 to call detection */ |
967 | static struct pci_device_id snd_bt87x_default_ids[] __devinitdata = { | 967 | static DEFINE_PCI_DEVICE_TABLE(snd_bt87x_default_ids) = { |
968 | BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, PCI_ANY_ID, PCI_ANY_ID, UNKNOWN), | 968 | BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, PCI_ANY_ID, PCI_ANY_ID, UNKNOWN), |
969 | BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_879, PCI_ANY_ID, PCI_ANY_ID, UNKNOWN), | 969 | BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_879, PCI_ANY_ID, PCI_ANY_ID, UNKNOWN), |
970 | { } | 970 | { } |
diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 15e4138bce17..0a3d3d6e77b4 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c | |||
@@ -1875,7 +1875,7 @@ static int snd_ca0106_resume(struct pci_dev *pci) | |||
1875 | #endif | 1875 | #endif |
1876 | 1876 | ||
1877 | // PCI IDs | 1877 | // PCI IDs |
1878 | static struct pci_device_id snd_ca0106_ids[] = { | 1878 | static DEFINE_PCI_DEVICE_TABLE(snd_ca0106_ids) = { |
1879 | { PCI_VDEVICE(CREATIVE, 0x0007), 0 }, /* Audigy LS or Live 24bit */ | 1879 | { PCI_VDEVICE(CREATIVE, 0x0007), 0 }, /* Audigy LS or Live 24bit */ |
1880 | { 0, } | 1880 | { 0, } |
1881 | }; | 1881 | }; |
diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c index a312bae08f52..1ded64e05643 100644 --- a/sound/pci/cmipci.c +++ b/sound/pci/cmipci.c | |||
@@ -2796,7 +2796,7 @@ static inline void snd_cmipci_proc_init(struct cmipci *cm) {} | |||
2796 | #endif | 2796 | #endif |
2797 | 2797 | ||
2798 | 2798 | ||
2799 | static struct pci_device_id snd_cmipci_ids[] = { | 2799 | static DEFINE_PCI_DEVICE_TABLE(snd_cmipci_ids) = { |
2800 | {PCI_VDEVICE(CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338A), 0}, | 2800 | {PCI_VDEVICE(CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338A), 0}, |
2801 | {PCI_VDEVICE(CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338B), 0}, | 2801 | {PCI_VDEVICE(CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338B), 0}, |
2802 | {PCI_VDEVICE(CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8738), 0}, | 2802 | {PCI_VDEVICE(CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8738), 0}, |
@@ -3018,7 +3018,7 @@ static int __devinit snd_cmipci_create(struct snd_card *card, struct pci_dev *pc | |||
3018 | int integrated_midi = 0; | 3018 | int integrated_midi = 0; |
3019 | char modelstr[16]; | 3019 | char modelstr[16]; |
3020 | int pcm_index, pcm_spdif_index; | 3020 | int pcm_index, pcm_spdif_index; |
3021 | static struct pci_device_id intel_82437vx[] = { | 3021 | static DEFINE_PCI_DEVICE_TABLE(intel_82437vx) = { |
3022 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437VX) }, | 3022 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437VX) }, |
3023 | { }, | 3023 | { }, |
3024 | }; | 3024 | }; |
diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c index e2e0359bb056..9edc65059e3e 100644 --- a/sound/pci/cs4281.c +++ b/sound/pci/cs4281.c | |||
@@ -494,7 +494,7 @@ struct cs4281 { | |||
494 | 494 | ||
495 | static irqreturn_t snd_cs4281_interrupt(int irq, void *dev_id); | 495 | static irqreturn_t snd_cs4281_interrupt(int irq, void *dev_id); |
496 | 496 | ||
497 | static struct pci_device_id snd_cs4281_ids[] = { | 497 | static DEFINE_PCI_DEVICE_TABLE(snd_cs4281_ids) = { |
498 | { PCI_VDEVICE(CIRRUS, 0x6005), 0, }, /* CS4281 */ | 498 | { PCI_VDEVICE(CIRRUS, 0x6005), 0, }, /* CS4281 */ |
499 | { 0, } | 499 | { 0, } |
500 | }; | 500 | }; |
diff --git a/sound/pci/cs46xx/cs46xx.c b/sound/pci/cs46xx/cs46xx.c index 033aec430117..767fa7f06cd0 100644 --- a/sound/pci/cs46xx/cs46xx.c +++ b/sound/pci/cs46xx/cs46xx.c | |||
@@ -64,7 +64,7 @@ MODULE_PARM_DESC(thinkpad, "Force to enable Thinkpad's CLKRUN control."); | |||
64 | module_param_array(mmap_valid, bool, NULL, 0444); | 64 | module_param_array(mmap_valid, bool, NULL, 0444); |
65 | MODULE_PARM_DESC(mmap_valid, "Support OSS mmap."); | 65 | MODULE_PARM_DESC(mmap_valid, "Support OSS mmap."); |
66 | 66 | ||
67 | static struct pci_device_id snd_cs46xx_ids[] = { | 67 | static DEFINE_PCI_DEVICE_TABLE(snd_cs46xx_ids) = { |
68 | { PCI_VDEVICE(CIRRUS, 0x6001), 0, }, /* CS4280 */ | 68 | { PCI_VDEVICE(CIRRUS, 0x6001), 0, }, /* CS4280 */ |
69 | { PCI_VDEVICE(CIRRUS, 0x6003), 0, }, /* CS4612 */ | 69 | { PCI_VDEVICE(CIRRUS, 0x6003), 0, }, /* CS4612 */ |
70 | { PCI_VDEVICE(CIRRUS, 0x6004), 0, }, /* CS4615 */ | 70 | { PCI_VDEVICE(CIRRUS, 0x6004), 0, }, /* CS4615 */ |
diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c index 1be96ead4244..3f99a5e8528c 100644 --- a/sound/pci/cs46xx/cs46xx_lib.c +++ b/sound/pci/cs46xx/cs46xx_lib.c | |||
@@ -2238,11 +2238,11 @@ static void snd_cs46xx_codec_reset (struct snd_ac97 * ac97) | |||
2238 | 2238 | ||
2239 | /* set the desired CODEC mode */ | 2239 | /* set the desired CODEC mode */ |
2240 | if (ac97->num == CS46XX_PRIMARY_CODEC_INDEX) { | 2240 | if (ac97->num == CS46XX_PRIMARY_CODEC_INDEX) { |
2241 | snd_printdd("cs46xx: CODOEC1 mode %04x\n",0x0); | 2241 | snd_printdd("cs46xx: CODEC1 mode %04x\n", 0x0); |
2242 | snd_cs46xx_ac97_write(ac97,AC97_CSR_ACMODE,0x0); | 2242 | snd_cs46xx_ac97_write(ac97, AC97_CSR_ACMODE, 0x0); |
2243 | } else if (ac97->num == CS46XX_SECONDARY_CODEC_INDEX) { | 2243 | } else if (ac97->num == CS46XX_SECONDARY_CODEC_INDEX) { |
2244 | snd_printdd("cs46xx: CODOEC2 mode %04x\n",0x3); | 2244 | snd_printdd("cs46xx: CODEC2 mode %04x\n", 0x3); |
2245 | snd_cs46xx_ac97_write(ac97,AC97_CSR_ACMODE,0x3); | 2245 | snd_cs46xx_ac97_write(ac97, AC97_CSR_ACMODE, 0x3); |
2246 | } else { | 2246 | } else { |
2247 | snd_BUG(); /* should never happen ... */ | 2247 | snd_BUG(); /* should never happen ... */ |
2248 | } | 2248 | } |
@@ -2266,7 +2266,7 @@ static void snd_cs46xx_codec_reset (struct snd_ac97 * ac97) | |||
2266 | return; | 2266 | return; |
2267 | 2267 | ||
2268 | /* test if we can write to the record gain volume register */ | 2268 | /* test if we can write to the record gain volume register */ |
2269 | snd_ac97_write_cache(ac97, AC97_REC_GAIN, 0x8a05); | 2269 | snd_ac97_write(ac97, AC97_REC_GAIN, 0x8a05); |
2270 | if ((err = snd_ac97_read(ac97, AC97_REC_GAIN)) == 0x8a05) | 2270 | if ((err = snd_ac97_read(ac97, AC97_REC_GAIN)) == 0x8a05) |
2271 | return; | 2271 | return; |
2272 | 2272 | ||
@@ -3597,7 +3597,7 @@ static struct cs_card_type __devinitdata cards[] = { | |||
3597 | #ifdef CONFIG_PM | 3597 | #ifdef CONFIG_PM |
3598 | static unsigned int saved_regs[] = { | 3598 | static unsigned int saved_regs[] = { |
3599 | BA0_ACOSV, | 3599 | BA0_ACOSV, |
3600 | BA0_ASER_FADDR, | 3600 | /*BA0_ASER_FADDR,*/ |
3601 | BA0_ASER_MASTER, | 3601 | BA0_ASER_MASTER, |
3602 | BA1_PVOL, | 3602 | BA1_PVOL, |
3603 | BA1_CVOL, | 3603 | BA1_CVOL, |
@@ -3644,6 +3644,7 @@ int snd_cs46xx_resume(struct pci_dev *pci) | |||
3644 | #ifdef CONFIG_SND_CS46XX_NEW_DSP | 3644 | #ifdef CONFIG_SND_CS46XX_NEW_DSP |
3645 | int i; | 3645 | int i; |
3646 | #endif | 3646 | #endif |
3647 | unsigned int tmp; | ||
3647 | 3648 | ||
3648 | pci_set_power_state(pci, PCI_D0); | 3649 | pci_set_power_state(pci, PCI_D0); |
3649 | pci_restore_state(pci); | 3650 | pci_restore_state(pci); |
@@ -3685,6 +3686,15 @@ int snd_cs46xx_resume(struct pci_dev *pci) | |||
3685 | snd_ac97_resume(chip->ac97[CS46XX_PRIMARY_CODEC_INDEX]); | 3686 | snd_ac97_resume(chip->ac97[CS46XX_PRIMARY_CODEC_INDEX]); |
3686 | snd_ac97_resume(chip->ac97[CS46XX_SECONDARY_CODEC_INDEX]); | 3687 | snd_ac97_resume(chip->ac97[CS46XX_SECONDARY_CODEC_INDEX]); |
3687 | 3688 | ||
3689 | /* | ||
3690 | * Stop capture DMA. | ||
3691 | */ | ||
3692 | tmp = snd_cs46xx_peek(chip, BA1_CCTL); | ||
3693 | chip->capt.ctl = tmp & 0x0000ffff; | ||
3694 | snd_cs46xx_poke(chip, BA1_CCTL, tmp & 0xffff0000); | ||
3695 | |||
3696 | mdelay(5); | ||
3697 | |||
3688 | /* reset playback/capture */ | 3698 | /* reset playback/capture */ |
3689 | snd_cs46xx_set_play_sample_rate(chip, 8000); | 3699 | snd_cs46xx_set_play_sample_rate(chip, 8000); |
3690 | snd_cs46xx_set_capture_sample_rate(chip, 8000); | 3700 | snd_cs46xx_set_capture_sample_rate(chip, 8000); |
diff --git a/sound/pci/cs46xx/dsp_spos.c b/sound/pci/cs46xx/dsp_spos.c index f4f0c8f5dad7..3e5ca8fb519f 100644 --- a/sound/pci/cs46xx/dsp_spos.c +++ b/sound/pci/cs46xx/dsp_spos.c | |||
@@ -298,6 +298,9 @@ void cs46xx_dsp_spos_destroy (struct snd_cs46xx * chip) | |||
298 | if (ins->scbs[i].deleted) continue; | 298 | if (ins->scbs[i].deleted) continue; |
299 | 299 | ||
300 | cs46xx_dsp_proc_free_scb_desc ( (ins->scbs + i) ); | 300 | cs46xx_dsp_proc_free_scb_desc ( (ins->scbs + i) ); |
301 | #ifdef CONFIG_PM | ||
302 | kfree(ins->scbs[i].data); | ||
303 | #endif | ||
301 | } | 304 | } |
302 | 305 | ||
303 | kfree(ins->code.data); | 306 | kfree(ins->code.data); |
@@ -974,13 +977,11 @@ static struct dsp_scb_descriptor * _map_scb (struct snd_cs46xx *chip, char * nam | |||
974 | 977 | ||
975 | index = find_free_scb_index (ins); | 978 | index = find_free_scb_index (ins); |
976 | 979 | ||
980 | memset(&ins->scbs[index], 0, sizeof(ins->scbs[index])); | ||
977 | strcpy(ins->scbs[index].scb_name, name); | 981 | strcpy(ins->scbs[index].scb_name, name); |
978 | ins->scbs[index].address = dest; | 982 | ins->scbs[index].address = dest; |
979 | ins->scbs[index].index = index; | 983 | ins->scbs[index].index = index; |
980 | ins->scbs[index].proc_info = NULL; | ||
981 | ins->scbs[index].ref_count = 1; | 984 | ins->scbs[index].ref_count = 1; |
982 | ins->scbs[index].deleted = 0; | ||
983 | spin_lock_init(&ins->scbs[index].lock); | ||
984 | 985 | ||
985 | desc = (ins->scbs + index); | 986 | desc = (ins->scbs + index); |
986 | ins->scbs[index].scb_symbol = add_symbol (chip, name, dest, SYMBOL_PARAMETER); | 987 | ins->scbs[index].scb_symbol = add_symbol (chip, name, dest, SYMBOL_PARAMETER); |
@@ -1022,17 +1023,29 @@ _map_task_tree (struct snd_cs46xx *chip, char * name, u32 dest, u32 size) | |||
1022 | return desc; | 1023 | return desc; |
1023 | } | 1024 | } |
1024 | 1025 | ||
1026 | #define SCB_BYTES (0x10 * 4) | ||
1027 | |||
1025 | struct dsp_scb_descriptor * | 1028 | struct dsp_scb_descriptor * |
1026 | cs46xx_dsp_create_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data, u32 dest) | 1029 | cs46xx_dsp_create_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data, u32 dest) |
1027 | { | 1030 | { |
1028 | struct dsp_scb_descriptor * desc; | 1031 | struct dsp_scb_descriptor * desc; |
1029 | 1032 | ||
1033 | #ifdef CONFIG_PM | ||
1034 | /* copy the data for resume */ | ||
1035 | scb_data = kmemdup(scb_data, SCB_BYTES, GFP_KERNEL); | ||
1036 | if (!scb_data) | ||
1037 | return NULL; | ||
1038 | #endif | ||
1039 | |||
1030 | desc = _map_scb (chip,name,dest); | 1040 | desc = _map_scb (chip,name,dest); |
1031 | if (desc) { | 1041 | if (desc) { |
1032 | desc->data = scb_data; | 1042 | desc->data = scb_data; |
1033 | _dsp_create_scb(chip,scb_data,dest); | 1043 | _dsp_create_scb(chip,scb_data,dest); |
1034 | } else { | 1044 | } else { |
1035 | snd_printk(KERN_ERR "dsp_spos: failed to map SCB\n"); | 1045 | snd_printk(KERN_ERR "dsp_spos: failed to map SCB\n"); |
1046 | #ifdef CONFIG_PM | ||
1047 | kfree(scb_data); | ||
1048 | #endif | ||
1036 | } | 1049 | } |
1037 | 1050 | ||
1038 | return desc; | 1051 | return desc; |
@@ -1988,7 +2001,28 @@ int cs46xx_dsp_resume(struct snd_cs46xx * chip) | |||
1988 | continue; | 2001 | continue; |
1989 | _dsp_create_scb(chip, s->data, s->address); | 2002 | _dsp_create_scb(chip, s->data, s->address); |
1990 | } | 2003 | } |
1991 | 2004 | for (i = 0; i < ins->nscb; i++) { | |
2005 | struct dsp_scb_descriptor *s = &ins->scbs[i]; | ||
2006 | if (s->deleted) | ||
2007 | continue; | ||
2008 | if (s->updated) | ||
2009 | cs46xx_dsp_spos_update_scb(chip, s); | ||
2010 | if (s->volume_set) | ||
2011 | cs46xx_dsp_scb_set_volume(chip, s, | ||
2012 | s->volume[0], s->volume[1]); | ||
2013 | } | ||
2014 | if (ins->spdif_status_out & DSP_SPDIF_STATUS_HW_ENABLED) { | ||
2015 | cs46xx_dsp_enable_spdif_hw(chip); | ||
2016 | snd_cs46xx_poke(chip, (ins->ref_snoop_scb->address + 2) << 2, | ||
2017 | (OUTPUT_SNOOP_BUFFER + 0x10) << 0x10); | ||
2018 | if (ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN) | ||
2019 | cs46xx_poke_via_dsp(chip, SP_SPDOUT_CSUV, | ||
2020 | ins->spdif_csuv_stream); | ||
2021 | } | ||
2022 | if (chip->dsp_spos_instance->spdif_status_in) { | ||
2023 | cs46xx_poke_via_dsp(chip, SP_ASER_COUNTDOWN, 0x80000005); | ||
2024 | cs46xx_poke_via_dsp(chip, SP_SPDIN_CONTROL, 0x800003ff); | ||
2025 | } | ||
1992 | return 0; | 2026 | return 0; |
1993 | } | 2027 | } |
1994 | #endif | 2028 | #endif |
diff --git a/sound/pci/cs46xx/dsp_spos.h b/sound/pci/cs46xx/dsp_spos.h index f9e169d33c03..ca47a8114c7f 100644 --- a/sound/pci/cs46xx/dsp_spos.h +++ b/sound/pci/cs46xx/dsp_spos.h | |||
@@ -212,6 +212,7 @@ static inline void cs46xx_dsp_spos_update_scb (struct snd_cs46xx * chip, | |||
212 | (scb->address + SCBsubListPtr) << 2, | 212 | (scb->address + SCBsubListPtr) << 2, |
213 | (scb->sub_list_ptr->address << 0x10) | | 213 | (scb->sub_list_ptr->address << 0x10) | |
214 | (scb->next_scb_ptr->address)); | 214 | (scb->next_scb_ptr->address)); |
215 | scb->updated = 1; | ||
215 | } | 216 | } |
216 | 217 | ||
217 | static inline void cs46xx_dsp_scb_set_volume (struct snd_cs46xx * chip, | 218 | static inline void cs46xx_dsp_scb_set_volume (struct snd_cs46xx * chip, |
@@ -222,6 +223,9 @@ static inline void cs46xx_dsp_scb_set_volume (struct snd_cs46xx * chip, | |||
222 | 223 | ||
223 | snd_cs46xx_poke(chip, (scb->address + SCBVolumeCtrl) << 2, val); | 224 | snd_cs46xx_poke(chip, (scb->address + SCBVolumeCtrl) << 2, val); |
224 | snd_cs46xx_poke(chip, (scb->address + SCBVolumeCtrl + 1) << 2, val); | 225 | snd_cs46xx_poke(chip, (scb->address + SCBVolumeCtrl + 1) << 2, val); |
226 | scb->volume_set = 1; | ||
227 | scb->volume[0] = left; | ||
228 | scb->volume[1] = right; | ||
225 | } | 229 | } |
226 | #endif /* __DSP_SPOS_H__ */ | 230 | #endif /* __DSP_SPOS_H__ */ |
227 | #endif /* CONFIG_SND_CS46XX_NEW_DSP */ | 231 | #endif /* CONFIG_SND_CS46XX_NEW_DSP */ |
diff --git a/sound/pci/cs46xx/dsp_spos_scb_lib.c b/sound/pci/cs46xx/dsp_spos_scb_lib.c index dd7c41b037b4..00b148a10239 100644 --- a/sound/pci/cs46xx/dsp_spos_scb_lib.c +++ b/sound/pci/cs46xx/dsp_spos_scb_lib.c | |||
@@ -115,7 +115,6 @@ static void cs46xx_dsp_proc_scb_info_read (struct snd_info_entry *entry, | |||
115 | static void _dsp_unlink_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor * scb) | 115 | static void _dsp_unlink_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor * scb) |
116 | { | 116 | { |
117 | struct dsp_spos_instance * ins = chip->dsp_spos_instance; | 117 | struct dsp_spos_instance * ins = chip->dsp_spos_instance; |
118 | unsigned long flags; | ||
119 | 118 | ||
120 | if ( scb->parent_scb_ptr ) { | 119 | if ( scb->parent_scb_ptr ) { |
121 | /* unlink parent SCB */ | 120 | /* unlink parent SCB */ |
@@ -153,8 +152,6 @@ static void _dsp_unlink_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor | |||
153 | scb->next_scb_ptr = ins->the_null_scb; | 152 | scb->next_scb_ptr = ins->the_null_scb; |
154 | } | 153 | } |
155 | 154 | ||
156 | spin_lock_irqsave(&chip->reg_lock, flags); | ||
157 | |||
158 | /* update parent first entry in DSP RAM */ | 155 | /* update parent first entry in DSP RAM */ |
159 | cs46xx_dsp_spos_update_scb(chip,scb->parent_scb_ptr); | 156 | cs46xx_dsp_spos_update_scb(chip,scb->parent_scb_ptr); |
160 | 157 | ||
@@ -162,7 +159,6 @@ static void _dsp_unlink_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor | |||
162 | cs46xx_dsp_spos_update_scb(chip,scb); | 159 | cs46xx_dsp_spos_update_scb(chip,scb); |
163 | 160 | ||
164 | scb->parent_scb_ptr = NULL; | 161 | scb->parent_scb_ptr = NULL; |
165 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
166 | } | 162 | } |
167 | } | 163 | } |
168 | 164 | ||
@@ -197,9 +193,9 @@ void cs46xx_dsp_remove_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor * | |||
197 | goto _end; | 193 | goto _end; |
198 | #endif | 194 | #endif |
199 | 195 | ||
200 | spin_lock_irqsave(&scb->lock, flags); | 196 | spin_lock_irqsave(&chip->reg_lock, flags); |
201 | _dsp_unlink_scb (chip,scb); | 197 | _dsp_unlink_scb (chip,scb); |
202 | spin_unlock_irqrestore(&scb->lock, flags); | 198 | spin_unlock_irqrestore(&chip->reg_lock, flags); |
203 | 199 | ||
204 | cs46xx_dsp_proc_free_scb_desc(scb); | 200 | cs46xx_dsp_proc_free_scb_desc(scb); |
205 | if (snd_BUG_ON(!scb->scb_symbol)) | 201 | if (snd_BUG_ON(!scb->scb_symbol)) |
@@ -207,6 +203,10 @@ void cs46xx_dsp_remove_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor * | |||
207 | remove_symbol (chip,scb->scb_symbol); | 203 | remove_symbol (chip,scb->scb_symbol); |
208 | 204 | ||
209 | ins->scbs[scb->index].deleted = 1; | 205 | ins->scbs[scb->index].deleted = 1; |
206 | #ifdef CONFIG_PM | ||
207 | kfree(ins->scbs[scb->index].data); | ||
208 | ins->scbs[scb->index].data = NULL; | ||
209 | #endif | ||
210 | 210 | ||
211 | if (scb->index < ins->scb_highest_frag_index) | 211 | if (scb->index < ins->scb_highest_frag_index) |
212 | ins->scb_highest_frag_index = scb->index; | 212 | ins->scb_highest_frag_index = scb->index; |
@@ -1508,20 +1508,17 @@ int cs46xx_dsp_pcm_unlink (struct snd_cs46xx * chip, | |||
1508 | chip->dsp_spos_instance->npcm_channels <= 0)) | 1508 | chip->dsp_spos_instance->npcm_channels <= 0)) |
1509 | return -EIO; | 1509 | return -EIO; |
1510 | 1510 | ||
1511 | spin_lock(&pcm_channel->src_scb->lock); | 1511 | spin_lock_irqsave(&chip->reg_lock, flags); |
1512 | |||
1513 | if (pcm_channel->unlinked) { | 1512 | if (pcm_channel->unlinked) { |
1514 | spin_unlock(&pcm_channel->src_scb->lock); | 1513 | spin_unlock_irqrestore(&chip->reg_lock, flags); |
1515 | return -EIO; | 1514 | return -EIO; |
1516 | } | 1515 | } |
1517 | 1516 | ||
1518 | spin_lock_irqsave(&chip->reg_lock, flags); | ||
1519 | pcm_channel->unlinked = 1; | 1517 | pcm_channel->unlinked = 1; |
1520 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
1521 | 1518 | ||
1522 | _dsp_unlink_scb (chip,pcm_channel->pcm_reader_scb); | 1519 | _dsp_unlink_scb (chip,pcm_channel->pcm_reader_scb); |
1520 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
1523 | 1521 | ||
1524 | spin_unlock(&pcm_channel->src_scb->lock); | ||
1525 | return 0; | 1522 | return 0; |
1526 | } | 1523 | } |
1527 | 1524 | ||
@@ -1533,10 +1530,10 @@ int cs46xx_dsp_pcm_link (struct snd_cs46xx * chip, | |||
1533 | struct dsp_scb_descriptor * src_scb = pcm_channel->src_scb; | 1530 | struct dsp_scb_descriptor * src_scb = pcm_channel->src_scb; |
1534 | unsigned long flags; | 1531 | unsigned long flags; |
1535 | 1532 | ||
1536 | spin_lock(&pcm_channel->src_scb->lock); | 1533 | spin_lock_irqsave(&chip->reg_lock, flags); |
1537 | 1534 | ||
1538 | if (pcm_channel->unlinked == 0) { | 1535 | if (pcm_channel->unlinked == 0) { |
1539 | spin_unlock(&pcm_channel->src_scb->lock); | 1536 | spin_unlock_irqrestore(&chip->reg_lock, flags); |
1540 | return -EIO; | 1537 | return -EIO; |
1541 | } | 1538 | } |
1542 | 1539 | ||
@@ -1552,8 +1549,6 @@ int cs46xx_dsp_pcm_link (struct snd_cs46xx * chip, | |||
1552 | snd_BUG_ON(pcm_channel->pcm_reader_scb->parent_scb_ptr); | 1549 | snd_BUG_ON(pcm_channel->pcm_reader_scb->parent_scb_ptr); |
1553 | pcm_channel->pcm_reader_scb->parent_scb_ptr = parent_scb; | 1550 | pcm_channel->pcm_reader_scb->parent_scb_ptr = parent_scb; |
1554 | 1551 | ||
1555 | spin_lock_irqsave(&chip->reg_lock, flags); | ||
1556 | |||
1557 | /* update SCB entry in DSP RAM */ | 1552 | /* update SCB entry in DSP RAM */ |
1558 | cs46xx_dsp_spos_update_scb(chip,pcm_channel->pcm_reader_scb); | 1553 | cs46xx_dsp_spos_update_scb(chip,pcm_channel->pcm_reader_scb); |
1559 | 1554 | ||
@@ -1562,8 +1557,6 @@ int cs46xx_dsp_pcm_link (struct snd_cs46xx * chip, | |||
1562 | 1557 | ||
1563 | pcm_channel->unlinked = 0; | 1558 | pcm_channel->unlinked = 0; |
1564 | spin_unlock_irqrestore(&chip->reg_lock, flags); | 1559 | spin_unlock_irqrestore(&chip->reg_lock, flags); |
1565 | |||
1566 | spin_unlock(&pcm_channel->src_scb->lock); | ||
1567 | return 0; | 1560 | return 0; |
1568 | } | 1561 | } |
1569 | 1562 | ||
@@ -1596,13 +1589,17 @@ cs46xx_add_record_source (struct snd_cs46xx *chip, struct dsp_scb_descriptor * s | |||
1596 | 1589 | ||
1597 | int cs46xx_src_unlink(struct snd_cs46xx *chip, struct dsp_scb_descriptor * src) | 1590 | int cs46xx_src_unlink(struct snd_cs46xx *chip, struct dsp_scb_descriptor * src) |
1598 | { | 1591 | { |
1592 | unsigned long flags; | ||
1593 | |||
1599 | if (snd_BUG_ON(!src->parent_scb_ptr)) | 1594 | if (snd_BUG_ON(!src->parent_scb_ptr)) |
1600 | return -EINVAL; | 1595 | return -EINVAL; |
1601 | 1596 | ||
1602 | /* mute SCB */ | 1597 | /* mute SCB */ |
1603 | cs46xx_dsp_scb_set_volume (chip,src,0,0); | 1598 | cs46xx_dsp_scb_set_volume (chip,src,0,0); |
1604 | 1599 | ||
1600 | spin_lock_irqsave(&chip->reg_lock, flags); | ||
1605 | _dsp_unlink_scb (chip,src); | 1601 | _dsp_unlink_scb (chip,src); |
1602 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
1606 | 1603 | ||
1607 | return 0; | 1604 | return 0; |
1608 | } | 1605 | } |
diff --git a/sound/pci/cs5530.c b/sound/pci/cs5530.c index dc464321d0f3..207479a641cf 100644 --- a/sound/pci/cs5530.c +++ b/sound/pci/cs5530.c | |||
@@ -58,7 +58,7 @@ struct snd_cs5530 { | |||
58 | unsigned long pci_base; | 58 | unsigned long pci_base; |
59 | }; | 59 | }; |
60 | 60 | ||
61 | static struct pci_device_id snd_cs5530_ids[] = { | 61 | static DEFINE_PCI_DEVICE_TABLE(snd_cs5530_ids) = { |
62 | {PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_AUDIO, PCI_ANY_ID, | 62 | {PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_AUDIO, PCI_ANY_ID, |
63 | PCI_ANY_ID, 0, 0}, | 63 | PCI_ANY_ID, 0, 0}, |
64 | {0,} | 64 | {0,} |
diff --git a/sound/pci/cs5535audio/cs5535audio.c b/sound/pci/cs5535audio/cs5535audio.c index 91e7faf69bbb..afb803708416 100644 --- a/sound/pci/cs5535audio/cs5535audio.c +++ b/sound/pci/cs5535audio/cs5535audio.c | |||
@@ -66,7 +66,7 @@ MODULE_PARM_DESC(id, "ID string for " DRIVER_NAME); | |||
66 | module_param_array(enable, bool, NULL, 0444); | 66 | module_param_array(enable, bool, NULL, 0444); |
67 | MODULE_PARM_DESC(enable, "Enable " DRIVER_NAME); | 67 | MODULE_PARM_DESC(enable, "Enable " DRIVER_NAME); |
68 | 68 | ||
69 | static struct pci_device_id snd_cs5535audio_ids[] = { | 69 | static DEFINE_PCI_DEVICE_TABLE(snd_cs5535audio_ids) = { |
70 | { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_AUDIO) }, | 70 | { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_AUDIO) }, |
71 | { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_AUDIO) }, | 71 | { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_AUDIO) }, |
72 | {} | 72 | {} |
diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c index cb65bd0dd35b..480cb1e905b6 100644 --- a/sound/pci/ctxfi/ctatc.c +++ b/sound/pci/ctxfi/ctatc.c | |||
@@ -166,18 +166,7 @@ static void ct_unmap_audio_buffer(struct ct_atc *atc, struct ct_atc_pcm *apcm) | |||
166 | 166 | ||
167 | static unsigned long atc_get_ptp_phys(struct ct_atc *atc, int index) | 167 | static unsigned long atc_get_ptp_phys(struct ct_atc *atc, int index) |
168 | { | 168 | { |
169 | struct ct_vm *vm; | 169 | return atc->vm->get_ptp_phys(atc->vm, index); |
170 | void *kvirt_addr; | ||
171 | unsigned long phys_addr; | ||
172 | |||
173 | vm = atc->vm; | ||
174 | kvirt_addr = vm->get_ptp_virt(vm, index); | ||
175 | if (kvirt_addr == NULL) | ||
176 | phys_addr = (~0UL); | ||
177 | else | ||
178 | phys_addr = virt_to_phys(kvirt_addr); | ||
179 | |||
180 | return phys_addr; | ||
181 | } | 170 | } |
182 | 171 | ||
183 | static unsigned int convert_format(snd_pcm_format_t snd_format) | 172 | static unsigned int convert_format(snd_pcm_format_t snd_format) |
@@ -1225,10 +1214,11 @@ static int atc_dev_free(struct snd_device *dev) | |||
1225 | return ct_atc_destroy(atc); | 1214 | return ct_atc_destroy(atc); |
1226 | } | 1215 | } |
1227 | 1216 | ||
1228 | static int __devinit atc_identify_card(struct ct_atc *atc) | 1217 | static int __devinit atc_identify_card(struct ct_atc *atc, unsigned int ssid) |
1229 | { | 1218 | { |
1230 | const struct snd_pci_quirk *p; | 1219 | const struct snd_pci_quirk *p; |
1231 | const struct snd_pci_quirk *list; | 1220 | const struct snd_pci_quirk *list; |
1221 | u16 vendor_id, device_id; | ||
1232 | 1222 | ||
1233 | switch (atc->chip_type) { | 1223 | switch (atc->chip_type) { |
1234 | case ATC20K1: | 1224 | case ATC20K1: |
@@ -1242,13 +1232,19 @@ static int __devinit atc_identify_card(struct ct_atc *atc) | |||
1242 | default: | 1232 | default: |
1243 | return -ENOENT; | 1233 | return -ENOENT; |
1244 | } | 1234 | } |
1245 | p = snd_pci_quirk_lookup(atc->pci, list); | 1235 | if (ssid) { |
1236 | vendor_id = ssid >> 16; | ||
1237 | device_id = ssid & 0xffff; | ||
1238 | } else { | ||
1239 | vendor_id = atc->pci->subsystem_vendor; | ||
1240 | device_id = atc->pci->subsystem_device; | ||
1241 | } | ||
1242 | p = snd_pci_quirk_lookup_id(vendor_id, device_id, list); | ||
1246 | if (p) { | 1243 | if (p) { |
1247 | if (p->value < 0) { | 1244 | if (p->value < 0) { |
1248 | printk(KERN_ERR "ctxfi: " | 1245 | printk(KERN_ERR "ctxfi: " |
1249 | "Device %04x:%04x is black-listed\n", | 1246 | "Device %04x:%04x is black-listed\n", |
1250 | atc->pci->subsystem_vendor, | 1247 | vendor_id, device_id); |
1251 | atc->pci->subsystem_device); | ||
1252 | return -ENOENT; | 1248 | return -ENOENT; |
1253 | } | 1249 | } |
1254 | atc->model = p->value; | 1250 | atc->model = p->value; |
@@ -1261,8 +1257,7 @@ static int __devinit atc_identify_card(struct ct_atc *atc) | |||
1261 | atc->model_name = ct_subsys_name[atc->model]; | 1257 | atc->model_name = ct_subsys_name[atc->model]; |
1262 | snd_printd("ctxfi: chip %s model %s (%04x:%04x) is found\n", | 1258 | snd_printd("ctxfi: chip %s model %s (%04x:%04x) is found\n", |
1263 | atc->chip_name, atc->model_name, | 1259 | atc->chip_name, atc->model_name, |
1264 | atc->pci->subsystem_vendor, | 1260 | vendor_id, device_id); |
1265 | atc->pci->subsystem_device); | ||
1266 | return 0; | 1261 | return 0; |
1267 | } | 1262 | } |
1268 | 1263 | ||
@@ -1636,7 +1631,8 @@ static struct ct_atc atc_preset __devinitdata = { | |||
1636 | 1631 | ||
1637 | int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci, | 1632 | int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci, |
1638 | unsigned int rsr, unsigned int msr, | 1633 | unsigned int rsr, unsigned int msr, |
1639 | int chip_type, struct ct_atc **ratc) | 1634 | int chip_type, unsigned int ssid, |
1635 | struct ct_atc **ratc) | ||
1640 | { | 1636 | { |
1641 | struct ct_atc *atc; | 1637 | struct ct_atc *atc; |
1642 | static struct snd_device_ops ops = { | 1638 | static struct snd_device_ops ops = { |
@@ -1662,14 +1658,14 @@ int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci, | |||
1662 | mutex_init(&atc->atc_mutex); | 1658 | mutex_init(&atc->atc_mutex); |
1663 | 1659 | ||
1664 | /* Find card model */ | 1660 | /* Find card model */ |
1665 | err = atc_identify_card(atc); | 1661 | err = atc_identify_card(atc, ssid); |
1666 | if (err < 0) { | 1662 | if (err < 0) { |
1667 | printk(KERN_ERR "ctatc: Card not recognised\n"); | 1663 | printk(KERN_ERR "ctatc: Card not recognised\n"); |
1668 | goto error1; | 1664 | goto error1; |
1669 | } | 1665 | } |
1670 | 1666 | ||
1671 | /* Set up device virtual memory management object */ | 1667 | /* Set up device virtual memory management object */ |
1672 | err = ct_vm_create(&atc->vm); | 1668 | err = ct_vm_create(&atc->vm, pci); |
1673 | if (err < 0) | 1669 | if (err < 0) |
1674 | goto error1; | 1670 | goto error1; |
1675 | 1671 | ||
diff --git a/sound/pci/ctxfi/ctatc.h b/sound/pci/ctxfi/ctatc.h index 9fd8a5708943..7167c0185d52 100644 --- a/sound/pci/ctxfi/ctatc.h +++ b/sound/pci/ctxfi/ctatc.h | |||
@@ -148,7 +148,7 @@ struct ct_atc { | |||
148 | 148 | ||
149 | int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci, | 149 | int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci, |
150 | unsigned int rsr, unsigned int msr, int chip_type, | 150 | unsigned int rsr, unsigned int msr, int chip_type, |
151 | struct ct_atc **ratc); | 151 | unsigned int subsysid, struct ct_atc **ratc); |
152 | int __devinit ct_atc_create_alsa_devs(struct ct_atc *atc); | 152 | int __devinit ct_atc_create_alsa_devs(struct ct_atc *atc); |
153 | 153 | ||
154 | #endif /* CTATC_H */ | 154 | #endif /* CTATC_H */ |
diff --git a/sound/pci/ctxfi/ctvmem.c b/sound/pci/ctxfi/ctvmem.c index 6b78752e9503..65da6e466f80 100644 --- a/sound/pci/ctxfi/ctvmem.c +++ b/sound/pci/ctxfi/ctvmem.c | |||
@@ -138,7 +138,7 @@ ct_vm_map(struct ct_vm *vm, struct snd_pcm_substream *substream, int size) | |||
138 | return NULL; | 138 | return NULL; |
139 | } | 139 | } |
140 | 140 | ||
141 | ptp = vm->ptp[0]; | 141 | ptp = (unsigned long *)vm->ptp[0].area; |
142 | pte_start = (block->addr >> CT_PAGE_SHIFT); | 142 | pte_start = (block->addr >> CT_PAGE_SHIFT); |
143 | pages = block->size >> CT_PAGE_SHIFT; | 143 | pages = block->size >> CT_PAGE_SHIFT; |
144 | for (i = 0; i < pages; i++) { | 144 | for (i = 0; i < pages; i++) { |
@@ -158,25 +158,25 @@ static void ct_vm_unmap(struct ct_vm *vm, struct ct_vm_block *block) | |||
158 | } | 158 | } |
159 | 159 | ||
160 | /* * | 160 | /* * |
161 | * return the host (kmalloced) addr of the @index-th device | 161 | * return the host physical addr of the @index-th device |
162 | * page talbe page on success, or NULL on failure. | 162 | * page table page on success, or ~0UL on failure. |
163 | * The first returned NULL indicates the termination. | 163 | * The first returned ~0UL indicates the termination. |
164 | * */ | 164 | * */ |
165 | static void * | 165 | static dma_addr_t |
166 | ct_get_ptp_virt(struct ct_vm *vm, int index) | 166 | ct_get_ptp_phys(struct ct_vm *vm, int index) |
167 | { | 167 | { |
168 | void *addr; | 168 | dma_addr_t addr; |
169 | 169 | ||
170 | addr = (index >= CT_PTP_NUM) ? NULL : vm->ptp[index]; | 170 | addr = (index >= CT_PTP_NUM) ? ~0UL : vm->ptp[index].addr; |
171 | 171 | ||
172 | return addr; | 172 | return addr; |
173 | } | 173 | } |
174 | 174 | ||
175 | int ct_vm_create(struct ct_vm **rvm) | 175 | int ct_vm_create(struct ct_vm **rvm, struct pci_dev *pci) |
176 | { | 176 | { |
177 | struct ct_vm *vm; | 177 | struct ct_vm *vm; |
178 | struct ct_vm_block *block; | 178 | struct ct_vm_block *block; |
179 | int i; | 179 | int i, err = 0; |
180 | 180 | ||
181 | *rvm = NULL; | 181 | *rvm = NULL; |
182 | 182 | ||
@@ -188,23 +188,21 @@ int ct_vm_create(struct ct_vm **rvm) | |||
188 | 188 | ||
189 | /* Allocate page table pages */ | 189 | /* Allocate page table pages */ |
190 | for (i = 0; i < CT_PTP_NUM; i++) { | 190 | for (i = 0; i < CT_PTP_NUM; i++) { |
191 | vm->ptp[i] = kmalloc(PAGE_SIZE, GFP_KERNEL); | 191 | err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, |
192 | if (!vm->ptp[i]) | 192 | snd_dma_pci_data(pci), |
193 | PAGE_SIZE, &vm->ptp[i]); | ||
194 | if (err < 0) | ||
193 | break; | 195 | break; |
194 | } | 196 | } |
195 | if (!i) { | 197 | if (err < 0) { |
196 | /* no page table pages are allocated */ | 198 | /* no page table pages are allocated */ |
197 | kfree(vm); | 199 | ct_vm_destroy(vm); |
198 | return -ENOMEM; | 200 | return -ENOMEM; |
199 | } | 201 | } |
200 | vm->size = CT_ADDRS_PER_PAGE * i; | 202 | vm->size = CT_ADDRS_PER_PAGE * i; |
201 | /* Initialise remaining ptps */ | ||
202 | for (; i < CT_PTP_NUM; i++) | ||
203 | vm->ptp[i] = NULL; | ||
204 | |||
205 | vm->map = ct_vm_map; | 203 | vm->map = ct_vm_map; |
206 | vm->unmap = ct_vm_unmap; | 204 | vm->unmap = ct_vm_unmap; |
207 | vm->get_ptp_virt = ct_get_ptp_virt; | 205 | vm->get_ptp_phys = ct_get_ptp_phys; |
208 | INIT_LIST_HEAD(&vm->unused); | 206 | INIT_LIST_HEAD(&vm->unused); |
209 | INIT_LIST_HEAD(&vm->used); | 207 | INIT_LIST_HEAD(&vm->used); |
210 | block = kzalloc(sizeof(*block), GFP_KERNEL); | 208 | block = kzalloc(sizeof(*block), GFP_KERNEL); |
@@ -242,7 +240,7 @@ void ct_vm_destroy(struct ct_vm *vm) | |||
242 | 240 | ||
243 | /* free allocated page table pages */ | 241 | /* free allocated page table pages */ |
244 | for (i = 0; i < CT_PTP_NUM; i++) | 242 | for (i = 0; i < CT_PTP_NUM; i++) |
245 | kfree(vm->ptp[i]); | 243 | snd_dma_free_pages(&vm->ptp[i]); |
246 | 244 | ||
247 | vm->size = 0; | 245 | vm->size = 0; |
248 | 246 | ||
diff --git a/sound/pci/ctxfi/ctvmem.h b/sound/pci/ctxfi/ctvmem.h index 01e4fd0386a3..b23adfca4de6 100644 --- a/sound/pci/ctxfi/ctvmem.h +++ b/sound/pci/ctxfi/ctvmem.h | |||
@@ -22,6 +22,8 @@ | |||
22 | 22 | ||
23 | #include <linux/mutex.h> | 23 | #include <linux/mutex.h> |
24 | #include <linux/list.h> | 24 | #include <linux/list.h> |
25 | #include <linux/pci.h> | ||
26 | #include <sound/memalloc.h> | ||
25 | 27 | ||
26 | /* The chip can handle the page table of 4k pages | 28 | /* The chip can handle the page table of 4k pages |
27 | * (emu20k1 can handle even 8k pages, but we don't use it right now) | 29 | * (emu20k1 can handle even 8k pages, but we don't use it right now) |
@@ -41,7 +43,7 @@ struct snd_pcm_substream; | |||
41 | 43 | ||
42 | /* Virtual memory management object for card device */ | 44 | /* Virtual memory management object for card device */ |
43 | struct ct_vm { | 45 | struct ct_vm { |
44 | void *ptp[CT_PTP_NUM]; /* Device page table pages */ | 46 | struct snd_dma_buffer ptp[CT_PTP_NUM]; /* Device page table pages */ |
45 | unsigned int size; /* Available addr space in bytes */ | 47 | unsigned int size; /* Available addr space in bytes */ |
46 | struct list_head unused; /* List of unused blocks */ | 48 | struct list_head unused; /* List of unused blocks */ |
47 | struct list_head used; /* List of used blocks */ | 49 | struct list_head used; /* List of used blocks */ |
@@ -52,10 +54,10 @@ struct ct_vm { | |||
52 | int size); | 54 | int size); |
53 | /* Unmap device logical addr area. */ | 55 | /* Unmap device logical addr area. */ |
54 | void (*unmap)(struct ct_vm *, struct ct_vm_block *block); | 56 | void (*unmap)(struct ct_vm *, struct ct_vm_block *block); |
55 | void *(*get_ptp_virt)(struct ct_vm *vm, int index); | 57 | dma_addr_t (*get_ptp_phys)(struct ct_vm *vm, int index); |
56 | }; | 58 | }; |
57 | 59 | ||
58 | int ct_vm_create(struct ct_vm **rvm); | 60 | int ct_vm_create(struct ct_vm **rvm, struct pci_dev *pci); |
59 | void ct_vm_destroy(struct ct_vm *vm); | 61 | void ct_vm_destroy(struct ct_vm *vm); |
60 | 62 | ||
61 | #endif /* CTVMEM_H */ | 63 | #endif /* CTVMEM_H */ |
diff --git a/sound/pci/ctxfi/xfi.c b/sound/pci/ctxfi/xfi.c index 76541748e7bc..f42e7e1a1074 100644 --- a/sound/pci/ctxfi/xfi.c +++ b/sound/pci/ctxfi/xfi.c | |||
@@ -32,6 +32,7 @@ module_param(multiple, uint, S_IRUGO); | |||
32 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; | 32 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; |
33 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; | 33 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; |
34 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; | 34 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; |
35 | static unsigned int subsystem[SNDRV_CARDS]; | ||
35 | 36 | ||
36 | module_param_array(index, int, NULL, 0444); | 37 | module_param_array(index, int, NULL, 0444); |
37 | MODULE_PARM_DESC(index, "Index value for Creative X-Fi driver"); | 38 | MODULE_PARM_DESC(index, "Index value for Creative X-Fi driver"); |
@@ -39,8 +40,10 @@ module_param_array(id, charp, NULL, 0444); | |||
39 | MODULE_PARM_DESC(id, "ID string for Creative X-Fi driver"); | 40 | MODULE_PARM_DESC(id, "ID string for Creative X-Fi driver"); |
40 | module_param_array(enable, bool, NULL, 0444); | 41 | module_param_array(enable, bool, NULL, 0444); |
41 | MODULE_PARM_DESC(enable, "Enable Creative X-Fi driver"); | 42 | MODULE_PARM_DESC(enable, "Enable Creative X-Fi driver"); |
43 | module_param_array(subsystem, int, NULL, 0444); | ||
44 | MODULE_PARM_DESC(subsystem, "Override subsystem ID for Creative X-Fi driver"); | ||
42 | 45 | ||
43 | static struct pci_device_id ct_pci_dev_ids[] = { | 46 | static DEFINE_PCI_DEVICE_TABLE(ct_pci_dev_ids) = { |
44 | /* only X-Fi is supported, so... */ | 47 | /* only X-Fi is supported, so... */ |
45 | { PCI_DEVICE(PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_20K1), | 48 | { PCI_DEVICE(PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_20K1), |
46 | .driver_data = ATC20K1, | 49 | .driver_data = ATC20K1, |
@@ -85,7 +88,7 @@ ct_card_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) | |||
85 | multiple = 2; | 88 | multiple = 2; |
86 | } | 89 | } |
87 | err = ct_atc_create(card, pci, reference_rate, multiple, | 90 | err = ct_atc_create(card, pci, reference_rate, multiple, |
88 | pci_id->driver_data, &atc); | 91 | pci_id->driver_data, subsystem[dev], &atc); |
89 | if (err < 0) | 92 | if (err < 0) |
90 | goto error; | 93 | goto error; |
91 | 94 | ||
diff --git a/sound/pci/echoaudio/darla20.c b/sound/pci/echoaudio/darla20.c index 8c6db3aa3c1a..a65bafe0800f 100644 --- a/sound/pci/echoaudio/darla20.c +++ b/sound/pci/echoaudio/darla20.c | |||
@@ -63,7 +63,7 @@ static const struct firmware card_fw[] = { | |||
63 | {0, "darla20_dsp.fw"} | 63 | {0, "darla20_dsp.fw"} |
64 | }; | 64 | }; |
65 | 65 | ||
66 | static struct pci_device_id snd_echo_ids[] = { | 66 | static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { |
67 | {0x1057, 0x1801, 0xECC0, 0x0010, 0, 0, 0}, /* DSP 56301 Darla20 rev.0 */ | 67 | {0x1057, 0x1801, 0xECC0, 0x0010, 0, 0, 0}, /* DSP 56301 Darla20 rev.0 */ |
68 | {0,} | 68 | {0,} |
69 | }; | 69 | }; |
diff --git a/sound/pci/echoaudio/darla20_dsp.c b/sound/pci/echoaudio/darla20_dsp.c index 29043301ebb8..20c7cbc89bb3 100644 --- a/sound/pci/echoaudio/darla20_dsp.c +++ b/sound/pci/echoaudio/darla20_dsp.c | |||
@@ -45,7 +45,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
45 | chip->device_id = device_id; | 45 | chip->device_id = device_id; |
46 | chip->subdevice_id = subdevice_id; | 46 | chip->subdevice_id = subdevice_id; |
47 | chip->bad_board = TRUE; | 47 | chip->bad_board = TRUE; |
48 | chip->dsp_code_to_load = &card_fw[FW_DARLA20_DSP]; | 48 | chip->dsp_code_to_load = FW_DARLA20_DSP; |
49 | chip->spdif_status = GD_SPDIF_STATUS_UNDEF; | 49 | chip->spdif_status = GD_SPDIF_STATUS_UNDEF; |
50 | chip->clock_state = GD_CLOCK_UNDEF; | 50 | chip->clock_state = GD_CLOCK_UNDEF; |
51 | /* Since this card has no ASIC, mark it as loaded so everything | 51 | /* Since this card has no ASIC, mark it as loaded so everything |
@@ -57,15 +57,19 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
57 | return err; | 57 | return err; |
58 | chip->bad_board = FALSE; | 58 | chip->bad_board = FALSE; |
59 | 59 | ||
60 | if ((err = init_line_levels(chip)) < 0) | ||
61 | return err; | ||
62 | |||
63 | DE_INIT(("init_hw done\n")); | 60 | DE_INIT(("init_hw done\n")); |
64 | return err; | 61 | return err; |
65 | } | 62 | } |
66 | 63 | ||
67 | 64 | ||
68 | 65 | ||
66 | static int set_mixer_defaults(struct echoaudio *chip) | ||
67 | { | ||
68 | return init_line_levels(chip); | ||
69 | } | ||
70 | |||
71 | |||
72 | |||
69 | /* The Darla20 has no external clock sources */ | 73 | /* The Darla20 has no external clock sources */ |
70 | static u32 detect_input_clocks(const struct echoaudio *chip) | 74 | static u32 detect_input_clocks(const struct echoaudio *chip) |
71 | { | 75 | { |
diff --git a/sound/pci/echoaudio/darla24.c b/sound/pci/echoaudio/darla24.c index 04cbf3eaf05a..0a6c50bcd758 100644 --- a/sound/pci/echoaudio/darla24.c +++ b/sound/pci/echoaudio/darla24.c | |||
@@ -67,7 +67,7 @@ static const struct firmware card_fw[] = { | |||
67 | {0, "darla24_dsp.fw"} | 67 | {0, "darla24_dsp.fw"} |
68 | }; | 68 | }; |
69 | 69 | ||
70 | static struct pci_device_id snd_echo_ids[] = { | 70 | static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { |
71 | {0x1057, 0x1801, 0xECC0, 0x0040, 0, 0, 0}, /* DSP 56301 Darla24 rev.0 */ | 71 | {0x1057, 0x1801, 0xECC0, 0x0040, 0, 0, 0}, /* DSP 56301 Darla24 rev.0 */ |
72 | {0x1057, 0x1801, 0xECC0, 0x0041, 0, 0, 0}, /* DSP 56301 Darla24 rev.1 */ | 72 | {0x1057, 0x1801, 0xECC0, 0x0041, 0, 0, 0}, /* DSP 56301 Darla24 rev.1 */ |
73 | {0,} | 73 | {0,} |
diff --git a/sound/pci/echoaudio/darla24_dsp.c b/sound/pci/echoaudio/darla24_dsp.c index 60228731841f..6da6663e9176 100644 --- a/sound/pci/echoaudio/darla24_dsp.c +++ b/sound/pci/echoaudio/darla24_dsp.c | |||
@@ -45,7 +45,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
45 | chip->device_id = device_id; | 45 | chip->device_id = device_id; |
46 | chip->subdevice_id = subdevice_id; | 46 | chip->subdevice_id = subdevice_id; |
47 | chip->bad_board = TRUE; | 47 | chip->bad_board = TRUE; |
48 | chip->dsp_code_to_load = &card_fw[FW_DARLA24_DSP]; | 48 | chip->dsp_code_to_load = FW_DARLA24_DSP; |
49 | /* Since this card has no ASIC, mark it as loaded so everything | 49 | /* Since this card has no ASIC, mark it as loaded so everything |
50 | works OK */ | 50 | works OK */ |
51 | chip->asic_loaded = TRUE; | 51 | chip->asic_loaded = TRUE; |
@@ -56,15 +56,19 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
56 | return err; | 56 | return err; |
57 | chip->bad_board = FALSE; | 57 | chip->bad_board = FALSE; |
58 | 58 | ||
59 | if ((err = init_line_levels(chip)) < 0) | ||
60 | return err; | ||
61 | |||
62 | DE_INIT(("init_hw done\n")); | 59 | DE_INIT(("init_hw done\n")); |
63 | return err; | 60 | return err; |
64 | } | 61 | } |
65 | 62 | ||
66 | 63 | ||
67 | 64 | ||
65 | static int set_mixer_defaults(struct echoaudio *chip) | ||
66 | { | ||
67 | return init_line_levels(chip); | ||
68 | } | ||
69 | |||
70 | |||
71 | |||
68 | static u32 detect_input_clocks(const struct echoaudio *chip) | 72 | static u32 detect_input_clocks(const struct echoaudio *chip) |
69 | { | 73 | { |
70 | u32 clocks_from_dsp, clock_bits; | 74 | u32 clocks_from_dsp, clock_bits; |
diff --git a/sound/pci/echoaudio/echo3g.c b/sound/pci/echoaudio/echo3g.c index 4022e43a0053..f5142796989b 100644 --- a/sound/pci/echoaudio/echo3g.c +++ b/sound/pci/echoaudio/echo3g.c | |||
@@ -81,7 +81,7 @@ static const struct firmware card_fw[] = { | |||
81 | {0, "3g_asic.fw"} | 81 | {0, "3g_asic.fw"} |
82 | }; | 82 | }; |
83 | 83 | ||
84 | static struct pci_device_id snd_echo_ids[] = { | 84 | static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { |
85 | {0x1057, 0x3410, 0xECC0, 0x0100, 0, 0, 0}, /* Echo 3G */ | 85 | {0x1057, 0x3410, 0xECC0, 0x0100, 0, 0, 0}, /* Echo 3G */ |
86 | {0,} | 86 | {0,} |
87 | }; | 87 | }; |
diff --git a/sound/pci/echoaudio/echo3g_dsp.c b/sound/pci/echoaudio/echo3g_dsp.c index 57967e580571..3cdc2ee2d1dd 100644 --- a/sound/pci/echoaudio/echo3g_dsp.c +++ b/sound/pci/echoaudio/echo3g_dsp.c | |||
@@ -61,7 +61,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
61 | chip->subdevice_id = subdevice_id; | 61 | chip->subdevice_id = subdevice_id; |
62 | chip->bad_board = TRUE; | 62 | chip->bad_board = TRUE; |
63 | chip->has_midi = TRUE; | 63 | chip->has_midi = TRUE; |
64 | chip->dsp_code_to_load = &card_fw[FW_ECHO3G_DSP]; | 64 | chip->dsp_code_to_load = FW_ECHO3G_DSP; |
65 | 65 | ||
66 | /* Load the DSP code and the ASIC on the PCI card and get | 66 | /* Load the DSP code and the ASIC on the PCI card and get |
67 | what type of external box is attached */ | 67 | what type of external box is attached */ |
@@ -97,20 +97,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
97 | chip->digital_modes = ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_RCA | | 97 | chip->digital_modes = ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_RCA | |
98 | ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_OPTICAL | | 98 | ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_OPTICAL | |
99 | ECHOCAPS_HAS_DIGITAL_MODE_ADAT; | 99 | ECHOCAPS_HAS_DIGITAL_MODE_ADAT; |
100 | chip->digital_mode = DIGITAL_MODE_SPDIF_RCA; | ||
101 | chip->professional_spdif = FALSE; | ||
102 | chip->non_audio_spdif = FALSE; | ||
103 | chip->bad_board = FALSE; | ||
104 | |||
105 | if ((err = init_line_levels(chip)) < 0) | ||
106 | return err; | ||
107 | err = set_digital_mode(chip, DIGITAL_MODE_SPDIF_RCA); | ||
108 | if (err < 0) | ||
109 | return err; | ||
110 | err = set_phantom_power(chip, 0); | ||
111 | if (err < 0) | ||
112 | return err; | ||
113 | err = set_professional_spdif(chip, TRUE); | ||
114 | 100 | ||
115 | DE_INIT(("init_hw done\n")); | 101 | DE_INIT(("init_hw done\n")); |
116 | return err; | 102 | return err; |
@@ -118,6 +104,18 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
118 | 104 | ||
119 | 105 | ||
120 | 106 | ||
107 | static int set_mixer_defaults(struct echoaudio *chip) | ||
108 | { | ||
109 | chip->digital_mode = DIGITAL_MODE_SPDIF_RCA; | ||
110 | chip->professional_spdif = FALSE; | ||
111 | chip->non_audio_spdif = FALSE; | ||
112 | chip->bad_board = FALSE; | ||
113 | chip->phantom_power = FALSE; | ||
114 | return init_line_levels(chip); | ||
115 | } | ||
116 | |||
117 | |||
118 | |||
121 | static int set_phantom_power(struct echoaudio *chip, char on) | 119 | static int set_phantom_power(struct echoaudio *chip, char on) |
122 | { | 120 | { |
123 | u32 control_reg = le32_to_cpu(chip->comm_page->control_register); | 121 | u32 control_reg = le32_to_cpu(chip->comm_page->control_register); |
diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c index 1305f7ca02c3..8dab82d7d19d 100644 --- a/sound/pci/echoaudio/echoaudio.c +++ b/sound/pci/echoaudio/echoaudio.c | |||
@@ -36,22 +36,61 @@ MODULE_PARM_DESC(enable, "Enable " ECHOCARD_NAME " soundcard."); | |||
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 | static const DECLARE_TLV_DB_SCALE(db_scale_output_gain, -12800, 100, 1); |
38 | 38 | ||
39 | |||
40 | |||
39 | static int get_firmware(const struct firmware **fw_entry, | 41 | static int get_firmware(const struct firmware **fw_entry, |
40 | const struct firmware *frm, struct echoaudio *chip) | 42 | struct echoaudio *chip, const short fw_index) |
41 | { | 43 | { |
42 | int err; | 44 | int err; |
43 | char name[30]; | 45 | char name[30]; |
44 | DE_ACT(("firmware requested: %s\n", frm->data)); | 46 | |
45 | snprintf(name, sizeof(name), "ea/%s", frm->data); | 47 | #ifdef CONFIG_PM |
46 | if ((err = request_firmware(fw_entry, name, pci_device(chip))) < 0) | 48 | if (chip->fw_cache[fw_index]) { |
49 | DE_ACT(("firmware requested: %s is cached\n", card_fw[fw_index].data)); | ||
50 | *fw_entry = chip->fw_cache[fw_index]; | ||
51 | return 0; | ||
52 | } | ||
53 | #endif | ||
54 | |||
55 | DE_ACT(("firmware requested: %s\n", card_fw[fw_index].data)); | ||
56 | snprintf(name, sizeof(name), "ea/%s", card_fw[fw_index].data); | ||
57 | err = request_firmware(fw_entry, name, pci_device(chip)); | ||
58 | if (err < 0) | ||
47 | snd_printk(KERN_ERR "get_firmware(): Firmware not available (%d)\n", err); | 59 | snd_printk(KERN_ERR "get_firmware(): Firmware not available (%d)\n", err); |
60 | #ifdef CONFIG_PM | ||
61 | else | ||
62 | chip->fw_cache[fw_index] = *fw_entry; | ||
63 | #endif | ||
48 | return err; | 64 | return err; |
49 | } | 65 | } |
50 | 66 | ||
67 | |||
68 | |||
51 | static void free_firmware(const struct firmware *fw_entry) | 69 | static void free_firmware(const struct firmware *fw_entry) |
52 | { | 70 | { |
71 | #ifdef CONFIG_PM | ||
72 | DE_ACT(("firmware not released (kept in cache)\n")); | ||
73 | #else | ||
53 | release_firmware(fw_entry); | 74 | release_firmware(fw_entry); |
54 | DE_ACT(("firmware released\n")); | 75 | DE_ACT(("firmware released\n")); |
76 | #endif | ||
77 | } | ||
78 | |||
79 | |||
80 | |||
81 | static void free_firmware_cache(struct echoaudio *chip) | ||
82 | { | ||
83 | #ifdef CONFIG_PM | ||
84 | int i; | ||
85 | |||
86 | for (i = 0; i < 8 ; i++) | ||
87 | if (chip->fw_cache[i]) { | ||
88 | release_firmware(chip->fw_cache[i]); | ||
89 | DE_ACT(("release_firmware(%d)\n", i)); | ||
90 | } | ||
91 | |||
92 | DE_ACT(("firmware_cache released\n")); | ||
93 | #endif | ||
55 | } | 94 | } |
56 | 95 | ||
57 | 96 | ||
@@ -714,6 +753,8 @@ static int pcm_trigger(struct snd_pcm_substream *substream, int cmd) | |||
714 | 753 | ||
715 | spin_lock(&chip->lock); | 754 | spin_lock(&chip->lock); |
716 | switch (cmd) { | 755 | switch (cmd) { |
756 | case SNDRV_PCM_TRIGGER_RESUME: | ||
757 | DE_ACT(("pcm_trigger resume\n")); | ||
717 | case SNDRV_PCM_TRIGGER_START: | 758 | case SNDRV_PCM_TRIGGER_START: |
718 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 759 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
719 | DE_ACT(("pcm_trigger start\n")); | 760 | DE_ACT(("pcm_trigger start\n")); |
@@ -737,6 +778,8 @@ static int pcm_trigger(struct snd_pcm_substream *substream, int cmd) | |||
737 | err = start_transport(chip, channelmask, | 778 | err = start_transport(chip, channelmask, |
738 | chip->pipe_cyclic_mask); | 779 | chip->pipe_cyclic_mask); |
739 | break; | 780 | break; |
781 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
782 | DE_ACT(("pcm_trigger suspend\n")); | ||
740 | case SNDRV_PCM_TRIGGER_STOP: | 783 | case SNDRV_PCM_TRIGGER_STOP: |
741 | DE_ACT(("pcm_trigger stop\n")); | 784 | DE_ACT(("pcm_trigger stop\n")); |
742 | for (i = 0; i < DSP_MAXPIPES; i++) { | 785 | for (i = 0; i < DSP_MAXPIPES; i++) { |
@@ -1821,7 +1864,9 @@ static irqreturn_t snd_echo_interrupt(int irq, void *dev_id) | |||
1821 | /* The hardware doesn't tell us which substream caused the irq, | 1864 | /* The hardware doesn't tell us which substream caused the irq, |
1822 | thus we have to check all running substreams. */ | 1865 | thus we have to check all running substreams. */ |
1823 | for (ss = 0; ss < DSP_MAXPIPES; ss++) { | 1866 | for (ss = 0; ss < DSP_MAXPIPES; ss++) { |
1824 | if ((substream = chip->substream[ss])) { | 1867 | substream = chip->substream[ss]; |
1868 | if (substream && ((struct audiopipe *)substream->runtime-> | ||
1869 | private_data)->state == PIPE_STATE_STARTED) { | ||
1825 | period = pcm_pointer(substream) / | 1870 | period = pcm_pointer(substream) / |
1826 | substream->runtime->period_size; | 1871 | substream->runtime->period_size; |
1827 | if (period != chip->last_period[ss]) { | 1872 | if (period != chip->last_period[ss]) { |
@@ -1874,6 +1919,7 @@ static int snd_echo_free(struct echoaudio *chip) | |||
1874 | pci_disable_device(chip->pci); | 1919 | pci_disable_device(chip->pci); |
1875 | 1920 | ||
1876 | /* release chip data */ | 1921 | /* release chip data */ |
1922 | free_firmware_cache(chip); | ||
1877 | kfree(chip); | 1923 | kfree(chip); |
1878 | DE_INIT(("Chip freed.\n")); | 1924 | DE_INIT(("Chip freed.\n")); |
1879 | return 0; | 1925 | return 0; |
@@ -1911,18 +1957,27 @@ static __devinit int snd_echo_create(struct snd_card *card, | |||
1911 | return err; | 1957 | return err; |
1912 | pci_set_master(pci); | 1958 | pci_set_master(pci); |
1913 | 1959 | ||
1914 | /* allocate a chip-specific data */ | 1960 | /* Allocate chip if needed */ |
1915 | chip = kzalloc(sizeof(*chip), GFP_KERNEL); | 1961 | if (!*rchip) { |
1916 | if (!chip) { | 1962 | chip = kzalloc(sizeof(*chip), GFP_KERNEL); |
1917 | pci_disable_device(pci); | 1963 | if (!chip) { |
1918 | return -ENOMEM; | 1964 | pci_disable_device(pci); |
1965 | return -ENOMEM; | ||
1966 | } | ||
1967 | DE_INIT(("chip=%p\n", chip)); | ||
1968 | spin_lock_init(&chip->lock); | ||
1969 | chip->card = card; | ||
1970 | chip->pci = pci; | ||
1971 | chip->irq = -1; | ||
1972 | atomic_set(&chip->opencount, 0); | ||
1973 | mutex_init(&chip->mode_mutex); | ||
1974 | chip->can_set_rate = 1; | ||
1975 | } else { | ||
1976 | /* If this was called from the resume function, chip is | ||
1977 | * already allocated and it contains current card settings. | ||
1978 | */ | ||
1979 | chip = *rchip; | ||
1919 | } | 1980 | } |
1920 | DE_INIT(("chip=%p\n", chip)); | ||
1921 | |||
1922 | spin_lock_init(&chip->lock); | ||
1923 | chip->card = card; | ||
1924 | chip->pci = pci; | ||
1925 | chip->irq = -1; | ||
1926 | 1981 | ||
1927 | /* PCI resource allocation */ | 1982 | /* PCI resource allocation */ |
1928 | chip->dsp_registers_phys = pci_resource_start(pci, 0); | 1983 | chip->dsp_registers_phys = pci_resource_start(pci, 0); |
@@ -1962,7 +2017,9 @@ static __devinit int snd_echo_create(struct snd_card *card, | |||
1962 | chip->comm_page = (struct comm_page *)chip->commpage_dma_buf.area; | 2017 | chip->comm_page = (struct comm_page *)chip->commpage_dma_buf.area; |
1963 | 2018 | ||
1964 | err = init_hw(chip, chip->pci->device, chip->pci->subsystem_device); | 2019 | err = init_hw(chip, chip->pci->device, chip->pci->subsystem_device); |
1965 | if (err) { | 2020 | if (err >= 0) |
2021 | err = set_mixer_defaults(chip); | ||
2022 | if (err < 0) { | ||
1966 | DE_INIT(("init_hw err=%d\n", err)); | 2023 | DE_INIT(("init_hw err=%d\n", err)); |
1967 | snd_echo_free(chip); | 2024 | snd_echo_free(chip); |
1968 | return err; | 2025 | return err; |
@@ -1973,9 +2030,6 @@ static __devinit int snd_echo_create(struct snd_card *card, | |||
1973 | snd_echo_free(chip); | 2030 | snd_echo_free(chip); |
1974 | return err; | 2031 | return err; |
1975 | } | 2032 | } |
1976 | atomic_set(&chip->opencount, 0); | ||
1977 | mutex_init(&chip->mode_mutex); | ||
1978 | chip->can_set_rate = 1; | ||
1979 | *rchip = chip; | 2033 | *rchip = chip; |
1980 | /* Init done ! */ | 2034 | /* Init done ! */ |
1981 | return 0; | 2035 | return 0; |
@@ -2008,6 +2062,7 @@ static int __devinit snd_echo_probe(struct pci_dev *pci, | |||
2008 | 2062 | ||
2009 | snd_card_set_dev(card, &pci->dev); | 2063 | snd_card_set_dev(card, &pci->dev); |
2010 | 2064 | ||
2065 | chip = NULL; /* Tells snd_echo_create to allocate chip */ | ||
2011 | if ((err = snd_echo_create(card, pci, &chip)) < 0) { | 2066 | if ((err = snd_echo_create(card, pci, &chip)) < 0) { |
2012 | snd_card_free(card); | 2067 | snd_card_free(card); |
2013 | return err; | 2068 | return err; |
@@ -2147,6 +2202,112 @@ ctl_error: | |||
2147 | 2202 | ||
2148 | 2203 | ||
2149 | 2204 | ||
2205 | #if defined(CONFIG_PM) | ||
2206 | |||
2207 | static int snd_echo_suspend(struct pci_dev *pci, pm_message_t state) | ||
2208 | { | ||
2209 | struct echoaudio *chip = pci_get_drvdata(pci); | ||
2210 | |||
2211 | DE_INIT(("suspend start\n")); | ||
2212 | snd_pcm_suspend_all(chip->analog_pcm); | ||
2213 | snd_pcm_suspend_all(chip->digital_pcm); | ||
2214 | |||
2215 | #ifdef ECHOCARD_HAS_MIDI | ||
2216 | /* This call can sleep */ | ||
2217 | if (chip->midi_out) | ||
2218 | snd_echo_midi_output_trigger(chip->midi_out, 0); | ||
2219 | #endif | ||
2220 | spin_lock_irq(&chip->lock); | ||
2221 | if (wait_handshake(chip)) { | ||
2222 | spin_unlock_irq(&chip->lock); | ||
2223 | return -EIO; | ||
2224 | } | ||
2225 | clear_handshake(chip); | ||
2226 | if (send_vector(chip, DSP_VC_GO_COMATOSE) < 0) { | ||
2227 | spin_unlock_irq(&chip->lock); | ||
2228 | return -EIO; | ||
2229 | } | ||
2230 | spin_unlock_irq(&chip->lock); | ||
2231 | |||
2232 | chip->dsp_code = NULL; | ||
2233 | free_irq(chip->irq, chip); | ||
2234 | chip->irq = -1; | ||
2235 | pci_save_state(pci); | ||
2236 | pci_disable_device(pci); | ||
2237 | |||
2238 | DE_INIT(("suspend done\n")); | ||
2239 | return 0; | ||
2240 | } | ||
2241 | |||
2242 | |||
2243 | |||
2244 | static int snd_echo_resume(struct pci_dev *pci) | ||
2245 | { | ||
2246 | struct echoaudio *chip = pci_get_drvdata(pci); | ||
2247 | struct comm_page *commpage, *commpage_bak; | ||
2248 | u32 pipe_alloc_mask; | ||
2249 | int err; | ||
2250 | |||
2251 | DE_INIT(("resume start\n")); | ||
2252 | pci_restore_state(pci); | ||
2253 | commpage_bak = kmalloc(sizeof(struct echoaudio), GFP_KERNEL); | ||
2254 | commpage = chip->comm_page; | ||
2255 | memcpy(commpage_bak, commpage, sizeof(struct comm_page)); | ||
2256 | |||
2257 | err = init_hw(chip, chip->pci->device, chip->pci->subsystem_device); | ||
2258 | if (err < 0) { | ||
2259 | kfree(commpage_bak); | ||
2260 | DE_INIT(("resume init_hw err=%d\n", err)); | ||
2261 | snd_echo_free(chip); | ||
2262 | return err; | ||
2263 | } | ||
2264 | DE_INIT(("resume init OK\n")); | ||
2265 | |||
2266 | /* Temporarily set chip->pipe_alloc_mask=0 otherwise | ||
2267 | * restore_dsp_settings() fails. | ||
2268 | */ | ||
2269 | pipe_alloc_mask = chip->pipe_alloc_mask; | ||
2270 | chip->pipe_alloc_mask = 0; | ||
2271 | err = restore_dsp_rettings(chip); | ||
2272 | chip->pipe_alloc_mask = pipe_alloc_mask; | ||
2273 | if (err < 0) { | ||
2274 | kfree(commpage_bak); | ||
2275 | return err; | ||
2276 | } | ||
2277 | DE_INIT(("resume restore OK\n")); | ||
2278 | |||
2279 | memcpy(&commpage->audio_format, &commpage_bak->audio_format, | ||
2280 | sizeof(commpage->audio_format)); | ||
2281 | memcpy(&commpage->sglist_addr, &commpage_bak->sglist_addr, | ||
2282 | sizeof(commpage->sglist_addr)); | ||
2283 | memcpy(&commpage->midi_output, &commpage_bak->midi_output, | ||
2284 | sizeof(commpage->midi_output)); | ||
2285 | kfree(commpage_bak); | ||
2286 | |||
2287 | if (request_irq(pci->irq, snd_echo_interrupt, IRQF_SHARED, | ||
2288 | ECHOCARD_NAME, chip)) { | ||
2289 | snd_echo_free(chip); | ||
2290 | snd_printk(KERN_ERR "cannot grab irq\n"); | ||
2291 | return -EBUSY; | ||
2292 | } | ||
2293 | chip->irq = pci->irq; | ||
2294 | DE_INIT(("resume irq=%d\n", chip->irq)); | ||
2295 | |||
2296 | #ifdef ECHOCARD_HAS_MIDI | ||
2297 | if (chip->midi_input_enabled) | ||
2298 | enable_midi_input(chip, TRUE); | ||
2299 | if (chip->midi_out) | ||
2300 | snd_echo_midi_output_trigger(chip->midi_out, 1); | ||
2301 | #endif | ||
2302 | |||
2303 | DE_INIT(("resume done\n")); | ||
2304 | return 0; | ||
2305 | } | ||
2306 | |||
2307 | #endif /* CONFIG_PM */ | ||
2308 | |||
2309 | |||
2310 | |||
2150 | static void __devexit snd_echo_remove(struct pci_dev *pci) | 2311 | static void __devexit snd_echo_remove(struct pci_dev *pci) |
2151 | { | 2312 | { |
2152 | struct echoaudio *chip; | 2313 | struct echoaudio *chip; |
@@ -2169,6 +2330,10 @@ static struct pci_driver driver = { | |||
2169 | .id_table = snd_echo_ids, | 2330 | .id_table = snd_echo_ids, |
2170 | .probe = snd_echo_probe, | 2331 | .probe = snd_echo_probe, |
2171 | .remove = __devexit_p(snd_echo_remove), | 2332 | .remove = __devexit_p(snd_echo_remove), |
2333 | #ifdef CONFIG_PM | ||
2334 | .suspend = snd_echo_suspend, | ||
2335 | .resume = snd_echo_resume, | ||
2336 | #endif /* CONFIG_PM */ | ||
2172 | }; | 2337 | }; |
2173 | 2338 | ||
2174 | 2339 | ||
diff --git a/sound/pci/echoaudio/echoaudio.h b/sound/pci/echoaudio/echoaudio.h index f9490ae36c2e..1df974dcb5f4 100644 --- a/sound/pci/echoaudio/echoaudio.h +++ b/sound/pci/echoaudio/echoaudio.h | |||
@@ -442,13 +442,16 @@ struct echoaudio { | |||
442 | u16 device_id, subdevice_id; | 442 | u16 device_id, subdevice_id; |
443 | u16 *dsp_code; /* Current DSP code loaded, | 443 | u16 *dsp_code; /* Current DSP code loaded, |
444 | * NULL if nothing loaded */ | 444 | * NULL if nothing loaded */ |
445 | const struct firmware *dsp_code_to_load;/* DSP code to load */ | 445 | short dsp_code_to_load; /* DSP code to load */ |
446 | const struct firmware *asic_code; /* Current ASIC code */ | 446 | short asic_code; /* Current ASIC code */ |
447 | u32 comm_page_phys; /* Physical address of the | 447 | u32 comm_page_phys; /* Physical address of the |
448 | * memory seen by DSP */ | 448 | * memory seen by DSP */ |
449 | volatile u32 __iomem *dsp_registers; /* DSP's register base */ | 449 | volatile u32 __iomem *dsp_registers; /* DSP's register base */ |
450 | u32 active_mask; /* Chs. active mask or | 450 | u32 active_mask; /* Chs. active mask or |
451 | * punks out */ | 451 | * punks out */ |
452 | #ifdef CONFIG_PM | ||
453 | const struct firmware *fw_cache[8]; /* Cached firmwares */ | ||
454 | #endif | ||
452 | 455 | ||
453 | #ifdef ECHOCARD_HAS_MIDI | 456 | #ifdef ECHOCARD_HAS_MIDI |
454 | u16 mtc_state; /* State for MIDI input parsing state machine */ | 457 | u16 mtc_state; /* State for MIDI input parsing state machine */ |
@@ -464,11 +467,13 @@ static int load_firmware(struct echoaudio *chip); | |||
464 | static int wait_handshake(struct echoaudio *chip); | 467 | static int wait_handshake(struct echoaudio *chip); |
465 | static int send_vector(struct echoaudio *chip, u32 command); | 468 | static int send_vector(struct echoaudio *chip, u32 command); |
466 | static int get_firmware(const struct firmware **fw_entry, | 469 | static int get_firmware(const struct firmware **fw_entry, |
467 | const struct firmware *frm, struct echoaudio *chip); | 470 | struct echoaudio *chip, const short fw_index); |
468 | static void free_firmware(const struct firmware *fw_entry); | 471 | static void free_firmware(const struct firmware *fw_entry); |
469 | 472 | ||
470 | #ifdef ECHOCARD_HAS_MIDI | 473 | #ifdef ECHOCARD_HAS_MIDI |
471 | static int enable_midi_input(struct echoaudio *chip, char enable); | 474 | static int enable_midi_input(struct echoaudio *chip, char enable); |
475 | static void snd_echo_midi_output_trigger( | ||
476 | struct snd_rawmidi_substream *substream, int up); | ||
472 | static int midi_service_irq(struct echoaudio *chip); | 477 | static int midi_service_irq(struct echoaudio *chip); |
473 | static int __devinit snd_echo_midi_create(struct snd_card *card, | 478 | static int __devinit snd_echo_midi_create(struct snd_card *card, |
474 | struct echoaudio *chip); | 479 | struct echoaudio *chip); |
diff --git a/sound/pci/echoaudio/echoaudio_3g.c b/sound/pci/echoaudio/echoaudio_3g.c index e32a74897921..658db44ef746 100644 --- a/sound/pci/echoaudio/echoaudio_3g.c +++ b/sound/pci/echoaudio/echoaudio_3g.c | |||
@@ -227,12 +227,11 @@ static int load_asic(struct echoaudio *chip) | |||
227 | /* Give the DSP a few milliseconds to settle down */ | 227 | /* Give the DSP a few milliseconds to settle down */ |
228 | mdelay(2); | 228 | mdelay(2); |
229 | 229 | ||
230 | err = load_asic_generic(chip, DSP_FNC_LOAD_3G_ASIC, | 230 | err = load_asic_generic(chip, DSP_FNC_LOAD_3G_ASIC, FW_3G_ASIC); |
231 | &card_fw[FW_3G_ASIC]); | ||
232 | if (err < 0) | 231 | if (err < 0) |
233 | return err; | 232 | return err; |
234 | 233 | ||
235 | chip->asic_code = &card_fw[FW_3G_ASIC]; | 234 | chip->asic_code = FW_3G_ASIC; |
236 | 235 | ||
237 | /* Now give the new ASIC some time to set up */ | 236 | /* Now give the new ASIC some time to set up */ |
238 | msleep(1000); | 237 | msleep(1000); |
diff --git a/sound/pci/echoaudio/echoaudio_dsp.c b/sound/pci/echoaudio/echoaudio_dsp.c index 4df51ef5e095..64417a733220 100644 --- a/sound/pci/echoaudio/echoaudio_dsp.c +++ b/sound/pci/echoaudio/echoaudio_dsp.c | |||
@@ -175,15 +175,15 @@ static inline int check_asic_status(struct echoaudio *chip) | |||
175 | #ifdef ECHOCARD_HAS_ASIC | 175 | #ifdef ECHOCARD_HAS_ASIC |
176 | 176 | ||
177 | /* Load ASIC code - done after the DSP is loaded */ | 177 | /* Load ASIC code - done after the DSP is loaded */ |
178 | static int load_asic_generic(struct echoaudio *chip, u32 cmd, | 178 | static int load_asic_generic(struct echoaudio *chip, u32 cmd, short asic) |
179 | const struct firmware *asic) | ||
180 | { | 179 | { |
181 | const struct firmware *fw; | 180 | const struct firmware *fw; |
182 | int err; | 181 | int err; |
183 | u32 i, size; | 182 | u32 i, size; |
184 | u8 *code; | 183 | u8 *code; |
185 | 184 | ||
186 | if ((err = get_firmware(&fw, asic, chip)) < 0) { | 185 | err = get_firmware(&fw, chip, asic); |
186 | if (err < 0) { | ||
187 | snd_printk(KERN_WARNING "Firmware not found !\n"); | 187 | snd_printk(KERN_WARNING "Firmware not found !\n"); |
188 | return err; | 188 | return err; |
189 | } | 189 | } |
@@ -245,7 +245,8 @@ static int install_resident_loader(struct echoaudio *chip) | |||
245 | return 0; | 245 | return 0; |
246 | } | 246 | } |
247 | 247 | ||
248 | if ((i = get_firmware(&fw, &card_fw[FW_361_LOADER], chip)) < 0) { | 248 | i = get_firmware(&fw, chip, FW_361_LOADER); |
249 | if (i < 0) { | ||
249 | snd_printk(KERN_WARNING "Firmware not found !\n"); | 250 | snd_printk(KERN_WARNING "Firmware not found !\n"); |
250 | return i; | 251 | return i; |
251 | } | 252 | } |
@@ -485,7 +486,8 @@ static int load_firmware(struct echoaudio *chip) | |||
485 | chip->dsp_code = NULL; | 486 | chip->dsp_code = NULL; |
486 | } | 487 | } |
487 | 488 | ||
488 | if ((err = get_firmware(&fw, chip->dsp_code_to_load, chip)) < 0) | 489 | err = get_firmware(&fw, chip, chip->dsp_code_to_load); |
490 | if (err < 0) | ||
489 | return err; | 491 | return err; |
490 | err = load_dsp(chip, (u16 *)fw->data); | 492 | err = load_dsp(chip, (u16 *)fw->data); |
491 | free_firmware(fw); | 493 | free_firmware(fw); |
@@ -495,9 +497,6 @@ static int load_firmware(struct echoaudio *chip) | |||
495 | if ((box_type = load_asic(chip)) < 0) | 497 | if ((box_type = load_asic(chip)) < 0) |
496 | return box_type; /* error */ | 498 | return box_type; /* error */ |
497 | 499 | ||
498 | if ((err = restore_dsp_rettings(chip)) < 0) | ||
499 | return err; | ||
500 | |||
501 | return box_type; | 500 | return box_type; |
502 | } | 501 | } |
503 | 502 | ||
@@ -657,51 +656,106 @@ static void get_audio_meters(struct echoaudio *chip, long *meters) | |||
657 | 656 | ||
658 | static int restore_dsp_rettings(struct echoaudio *chip) | 657 | static int restore_dsp_rettings(struct echoaudio *chip) |
659 | { | 658 | { |
660 | int err; | 659 | int i, o, err; |
661 | DE_INIT(("restore_dsp_settings\n")); | 660 | DE_INIT(("restore_dsp_settings\n")); |
662 | 661 | ||
663 | if ((err = check_asic_status(chip)) < 0) | 662 | if ((err = check_asic_status(chip)) < 0) |
664 | return err; | 663 | return err; |
665 | 664 | ||
666 | /* @ Gina20/Darla20 only. Should be harmless for other cards. */ | 665 | /* Gina20/Darla20 only. Should be harmless for other cards. */ |
667 | chip->comm_page->gd_clock_state = GD_CLOCK_UNDEF; | 666 | chip->comm_page->gd_clock_state = GD_CLOCK_UNDEF; |
668 | chip->comm_page->gd_spdif_status = GD_SPDIF_STATUS_UNDEF; | 667 | chip->comm_page->gd_spdif_status = GD_SPDIF_STATUS_UNDEF; |
669 | chip->comm_page->handshake = 0xffffffff; | 668 | chip->comm_page->handshake = 0xffffffff; |
670 | 669 | ||
671 | if ((err = set_sample_rate(chip, chip->sample_rate)) < 0) | 670 | /* Restore output busses */ |
671 | for (i = 0; i < num_busses_out(chip); i++) { | ||
672 | err = set_output_gain(chip, i, chip->output_gain[i]); | ||
673 | if (err < 0) | ||
674 | return err; | ||
675 | } | ||
676 | |||
677 | #ifdef ECHOCARD_HAS_VMIXER | ||
678 | for (i = 0; i < num_pipes_out(chip); i++) | ||
679 | for (o = 0; o < num_busses_out(chip); o++) { | ||
680 | err = set_vmixer_gain(chip, o, i, | ||
681 | chip->vmixer_gain[o][i]); | ||
682 | if (err < 0) | ||
683 | return err; | ||
684 | } | ||
685 | if (update_vmixer_level(chip) < 0) | ||
686 | return -EIO; | ||
687 | #endif /* ECHOCARD_HAS_VMIXER */ | ||
688 | |||
689 | #ifdef ECHOCARD_HAS_MONITOR | ||
690 | for (o = 0; o < num_busses_out(chip); o++) | ||
691 | for (i = 0; i < num_busses_in(chip); i++) { | ||
692 | err = set_monitor_gain(chip, o, i, | ||
693 | chip->monitor_gain[o][i]); | ||
694 | if (err < 0) | ||
695 | return err; | ||
696 | } | ||
697 | #endif /* ECHOCARD_HAS_MONITOR */ | ||
698 | |||
699 | #ifdef ECHOCARD_HAS_INPUT_GAIN | ||
700 | for (i = 0; i < num_busses_in(chip); i++) { | ||
701 | err = set_input_gain(chip, i, chip->input_gain[i]); | ||
702 | if (err < 0) | ||
703 | return err; | ||
704 | } | ||
705 | #endif /* ECHOCARD_HAS_INPUT_GAIN */ | ||
706 | |||
707 | err = update_output_line_level(chip); | ||
708 | if (err < 0) | ||
672 | return err; | 709 | return err; |
673 | 710 | ||
674 | if (chip->meters_enabled) | 711 | err = update_input_line_level(chip); |
675 | if (send_vector(chip, DSP_VC_METERS_ON) < 0) | 712 | if (err < 0) |
676 | return -EIO; | 713 | return err; |
677 | 714 | ||
678 | #ifdef ECHOCARD_HAS_EXTERNAL_CLOCK | 715 | err = set_sample_rate(chip, chip->sample_rate); |
679 | if (set_input_clock(chip, chip->input_clock) < 0) | 716 | if (err < 0) |
717 | return err; | ||
718 | |||
719 | if (chip->meters_enabled) { | ||
720 | err = send_vector(chip, DSP_VC_METERS_ON); | ||
721 | if (err < 0) | ||
722 | return err; | ||
723 | } | ||
724 | |||
725 | #ifdef ECHOCARD_HAS_DIGITAL_MODE_SWITCH | ||
726 | if (set_digital_mode(chip, chip->digital_mode) < 0) | ||
680 | return -EIO; | 727 | return -EIO; |
681 | #endif | 728 | #endif |
682 | 729 | ||
683 | #ifdef ECHOCARD_HAS_OUTPUT_CLOCK_SWITCH | 730 | #ifdef ECHOCARD_HAS_DIGITAL_IO |
684 | if (set_output_clock(chip, chip->output_clock) < 0) | 731 | if (set_professional_spdif(chip, chip->professional_spdif) < 0) |
685 | return -EIO; | 732 | return -EIO; |
686 | #endif | 733 | #endif |
687 | 734 | ||
688 | if (update_output_line_level(chip) < 0) | 735 | #ifdef ECHOCARD_HAS_PHANTOM_POWER |
736 | if (set_phantom_power(chip, chip->phantom_power) < 0) | ||
689 | return -EIO; | 737 | return -EIO; |
738 | #endif | ||
690 | 739 | ||
691 | if (update_input_line_level(chip) < 0) | 740 | #ifdef ECHOCARD_HAS_EXTERNAL_CLOCK |
741 | /* set_input_clock() also restores automute setting */ | ||
742 | if (set_input_clock(chip, chip->input_clock) < 0) | ||
692 | return -EIO; | 743 | return -EIO; |
744 | #endif | ||
693 | 745 | ||
694 | #ifdef ECHOCARD_HAS_VMIXER | 746 | #ifdef ECHOCARD_HAS_OUTPUT_CLOCK_SWITCH |
695 | if (update_vmixer_level(chip) < 0) | 747 | if (set_output_clock(chip, chip->output_clock) < 0) |
696 | return -EIO; | 748 | return -EIO; |
697 | #endif | 749 | #endif |
698 | 750 | ||
699 | if (wait_handshake(chip) < 0) | 751 | if (wait_handshake(chip) < 0) |
700 | return -EIO; | 752 | return -EIO; |
701 | clear_handshake(chip); | 753 | clear_handshake(chip); |
754 | if (send_vector(chip, DSP_VC_UPDATE_FLAGS) < 0) | ||
755 | return -EIO; | ||
702 | 756 | ||
703 | DE_INIT(("restore_dsp_rettings done\n")); | 757 | DE_INIT(("restore_dsp_rettings done\n")); |
704 | return send_vector(chip, DSP_VC_UPDATE_FLAGS); | 758 | return 0; |
705 | } | 759 | } |
706 | 760 | ||
707 | 761 | ||
@@ -918,9 +972,6 @@ static int init_dsp_comm_page(struct echoaudio *chip) | |||
918 | chip->card_name = ECHOCARD_NAME; | 972 | chip->card_name = ECHOCARD_NAME; |
919 | chip->bad_board = TRUE; /* Set TRUE until DSP loaded */ | 973 | chip->bad_board = TRUE; /* Set TRUE until DSP loaded */ |
920 | chip->dsp_code = NULL; /* Current DSP code not loaded */ | 974 | chip->dsp_code = NULL; /* Current DSP code not loaded */ |
921 | chip->digital_mode = DIGITAL_MODE_NONE; | ||
922 | chip->input_clock = ECHO_CLOCK_INTERNAL; | ||
923 | chip->output_clock = ECHO_CLOCK_WORD; | ||
924 | chip->asic_loaded = FALSE; | 975 | chip->asic_loaded = FALSE; |
925 | memset(chip->comm_page, 0, sizeof(struct comm_page)); | 976 | memset(chip->comm_page, 0, sizeof(struct comm_page)); |
926 | 977 | ||
@@ -931,7 +982,6 @@ static int init_dsp_comm_page(struct echoaudio *chip) | |||
931 | chip->comm_page->midi_out_free_count = | 982 | chip->comm_page->midi_out_free_count = |
932 | cpu_to_le32(DSP_MIDI_OUT_FIFO_SIZE); | 983 | cpu_to_le32(DSP_MIDI_OUT_FIFO_SIZE); |
933 | chip->comm_page->sample_rate = cpu_to_le32(44100); | 984 | chip->comm_page->sample_rate = cpu_to_le32(44100); |
934 | chip->sample_rate = 44100; | ||
935 | 985 | ||
936 | /* Set line levels so we don't blast any inputs on startup */ | 986 | /* Set line levels so we don't blast any inputs on startup */ |
937 | memset(chip->comm_page->monitors, ECHOGAIN_MUTED, MONITOR_ARRAY_SIZE); | 987 | memset(chip->comm_page->monitors, ECHOGAIN_MUTED, MONITOR_ARRAY_SIZE); |
@@ -942,50 +992,21 @@ static int init_dsp_comm_page(struct echoaudio *chip) | |||
942 | 992 | ||
943 | 993 | ||
944 | 994 | ||
945 | /* This function initializes the several volume controls for busses and pipes. | 995 | /* This function initializes the chip structure with default values, ie. all |
946 | This MUST be called after the DSP is up and running ! */ | 996 | * muted and internal clock source. Then it copies the settings to the DSP. |
997 | * This MUST be called after the DSP is up and running ! | ||
998 | */ | ||
947 | static int init_line_levels(struct echoaudio *chip) | 999 | static int init_line_levels(struct echoaudio *chip) |
948 | { | 1000 | { |
949 | int st, i, o; | ||
950 | |||
951 | DE_INIT(("init_line_levels\n")); | 1001 | DE_INIT(("init_line_levels\n")); |
952 | 1002 | memset(chip->output_gain, ECHOGAIN_MUTED, sizeof(chip->output_gain)); | |
953 | /* Mute output busses */ | 1003 | memset(chip->input_gain, ECHOGAIN_MUTED, sizeof(chip->input_gain)); |
954 | for (i = 0; i < num_busses_out(chip); i++) | 1004 | memset(chip->monitor_gain, ECHOGAIN_MUTED, sizeof(chip->monitor_gain)); |
955 | if ((st = set_output_gain(chip, i, ECHOGAIN_MUTED))) | 1005 | memset(chip->vmixer_gain, ECHOGAIN_MUTED, sizeof(chip->vmixer_gain)); |
956 | return st; | 1006 | chip->input_clock = ECHO_CLOCK_INTERNAL; |
957 | if ((st = update_output_line_level(chip))) | 1007 | chip->output_clock = ECHO_CLOCK_WORD; |
958 | return st; | 1008 | chip->sample_rate = 44100; |
959 | 1009 | return restore_dsp_rettings(chip); | |
960 | #ifdef ECHOCARD_HAS_VMIXER | ||
961 | /* Mute the Vmixer */ | ||
962 | for (i = 0; i < num_pipes_out(chip); i++) | ||
963 | for (o = 0; o < num_busses_out(chip); o++) | ||
964 | if ((st = set_vmixer_gain(chip, o, i, ECHOGAIN_MUTED))) | ||
965 | return st; | ||
966 | if ((st = update_vmixer_level(chip))) | ||
967 | return st; | ||
968 | #endif /* ECHOCARD_HAS_VMIXER */ | ||
969 | |||
970 | #ifdef ECHOCARD_HAS_MONITOR | ||
971 | /* Mute the monitor mixer */ | ||
972 | for (o = 0; o < num_busses_out(chip); o++) | ||
973 | for (i = 0; i < num_busses_in(chip); i++) | ||
974 | if ((st = set_monitor_gain(chip, o, i, ECHOGAIN_MUTED))) | ||
975 | return st; | ||
976 | if ((st = update_output_line_level(chip))) | ||
977 | return st; | ||
978 | #endif /* ECHOCARD_HAS_MONITOR */ | ||
979 | |||
980 | #ifdef ECHOCARD_HAS_INPUT_GAIN | ||
981 | for (i = 0; i < num_busses_in(chip); i++) | ||
982 | if ((st = set_input_gain(chip, i, ECHOGAIN_MUTED))) | ||
983 | return st; | ||
984 | if ((st = update_input_line_level(chip))) | ||
985 | return st; | ||
986 | #endif /* ECHOCARD_HAS_INPUT_GAIN */ | ||
987 | |||
988 | return 0; | ||
989 | } | 1010 | } |
990 | 1011 | ||
991 | 1012 | ||
diff --git a/sound/pci/echoaudio/gina20.c b/sound/pci/echoaudio/gina20.c index c0e64b8f52a4..2364f8a1bc21 100644 --- a/sound/pci/echoaudio/gina20.c +++ b/sound/pci/echoaudio/gina20.c | |||
@@ -67,7 +67,7 @@ static const struct firmware card_fw[] = { | |||
67 | {0, "gina20_dsp.fw"} | 67 | {0, "gina20_dsp.fw"} |
68 | }; | 68 | }; |
69 | 69 | ||
70 | static struct pci_device_id snd_echo_ids[] = { | 70 | static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { |
71 | {0x1057, 0x1801, 0xECC0, 0x0020, 0, 0, 0}, /* DSP 56301 Gina20 rev.0 */ | 71 | {0x1057, 0x1801, 0xECC0, 0x0020, 0, 0, 0}, /* DSP 56301 Gina20 rev.0 */ |
72 | {0,} | 72 | {0,} |
73 | }; | 73 | }; |
diff --git a/sound/pci/echoaudio/gina20_dsp.c b/sound/pci/echoaudio/gina20_dsp.c index 3f1e7475faea..d1615a0579d1 100644 --- a/sound/pci/echoaudio/gina20_dsp.c +++ b/sound/pci/echoaudio/gina20_dsp.c | |||
@@ -49,7 +49,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
49 | chip->device_id = device_id; | 49 | chip->device_id = device_id; |
50 | chip->subdevice_id = subdevice_id; | 50 | chip->subdevice_id = subdevice_id; |
51 | chip->bad_board = TRUE; | 51 | chip->bad_board = TRUE; |
52 | chip->dsp_code_to_load = &card_fw[FW_GINA20_DSP]; | 52 | chip->dsp_code_to_load = FW_GINA20_DSP; |
53 | chip->spdif_status = GD_SPDIF_STATUS_UNDEF; | 53 | chip->spdif_status = GD_SPDIF_STATUS_UNDEF; |
54 | chip->clock_state = GD_CLOCK_UNDEF; | 54 | chip->clock_state = GD_CLOCK_UNDEF; |
55 | /* Since this card has no ASIC, mark it as loaded so everything | 55 | /* Since this card has no ASIC, mark it as loaded so everything |
@@ -62,17 +62,20 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
62 | return err; | 62 | return err; |
63 | chip->bad_board = FALSE; | 63 | chip->bad_board = FALSE; |
64 | 64 | ||
65 | if ((err = init_line_levels(chip)) < 0) | ||
66 | return err; | ||
67 | |||
68 | err = set_professional_spdif(chip, TRUE); | ||
69 | |||
70 | DE_INIT(("init_hw done\n")); | 65 | DE_INIT(("init_hw done\n")); |
71 | return err; | 66 | return err; |
72 | } | 67 | } |
73 | 68 | ||
74 | 69 | ||
75 | 70 | ||
71 | static int set_mixer_defaults(struct echoaudio *chip) | ||
72 | { | ||
73 | chip->professional_spdif = FALSE; | ||
74 | return init_line_levels(chip); | ||
75 | } | ||
76 | |||
77 | |||
78 | |||
76 | static u32 detect_input_clocks(const struct echoaudio *chip) | 79 | static u32 detect_input_clocks(const struct echoaudio *chip) |
77 | { | 80 | { |
78 | u32 clocks_from_dsp, clock_bits; | 81 | u32 clocks_from_dsp, clock_bits; |
diff --git a/sound/pci/echoaudio/gina24.c b/sound/pci/echoaudio/gina24.c index c36a78dd0b5e..616b55825a19 100644 --- a/sound/pci/echoaudio/gina24.c +++ b/sound/pci/echoaudio/gina24.c | |||
@@ -85,7 +85,7 @@ static const struct firmware card_fw[] = { | |||
85 | {0, "gina24_361_asic.fw"} | 85 | {0, "gina24_361_asic.fw"} |
86 | }; | 86 | }; |
87 | 87 | ||
88 | static struct pci_device_id snd_echo_ids[] = { | 88 | static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { |
89 | {0x1057, 0x1801, 0xECC0, 0x0050, 0, 0, 0}, /* DSP 56301 Gina24 rev.0 */ | 89 | {0x1057, 0x1801, 0xECC0, 0x0050, 0, 0, 0}, /* DSP 56301 Gina24 rev.0 */ |
90 | {0x1057, 0x1801, 0xECC0, 0x0051, 0, 0, 0}, /* DSP 56301 Gina24 rev.1 */ | 90 | {0x1057, 0x1801, 0xECC0, 0x0051, 0, 0, 0}, /* DSP 56301 Gina24 rev.1 */ |
91 | {0x1057, 0x3410, 0xECC0, 0x0050, 0, 0, 0}, /* DSP 56361 Gina24 rev.0 */ | 91 | {0x1057, 0x3410, 0xECC0, 0x0050, 0, 0, 0}, /* DSP 56361 Gina24 rev.0 */ |
diff --git a/sound/pci/echoaudio/gina24_dsp.c b/sound/pci/echoaudio/gina24_dsp.c index 2fef37a2a5b9..98f7cfa81b5f 100644 --- a/sound/pci/echoaudio/gina24_dsp.c +++ b/sound/pci/echoaudio/gina24_dsp.c | |||
@@ -33,8 +33,7 @@ static int write_control_reg(struct echoaudio *chip, u32 value, char force); | |||
33 | static int set_input_clock(struct echoaudio *chip, u16 clock); | 33 | static int set_input_clock(struct echoaudio *chip, u16 clock); |
34 | static int set_professional_spdif(struct echoaudio *chip, char prof); | 34 | static int set_professional_spdif(struct echoaudio *chip, char prof); |
35 | static int set_digital_mode(struct echoaudio *chip, u8 mode); | 35 | static int set_digital_mode(struct echoaudio *chip, u8 mode); |
36 | static int load_asic_generic(struct echoaudio *chip, u32 cmd, | 36 | static int load_asic_generic(struct echoaudio *chip, u32 cmd, short asic); |
37 | const struct firmware *asic); | ||
38 | static int check_asic_status(struct echoaudio *chip); | 37 | static int check_asic_status(struct echoaudio *chip); |
39 | 38 | ||
40 | 39 | ||
@@ -58,19 +57,16 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
58 | ECHO_CLOCK_BIT_INTERNAL | ECHO_CLOCK_BIT_SPDIF | | 57 | ECHO_CLOCK_BIT_INTERNAL | ECHO_CLOCK_BIT_SPDIF | |
59 | ECHO_CLOCK_BIT_ESYNC | ECHO_CLOCK_BIT_ESYNC96 | | 58 | ECHO_CLOCK_BIT_ESYNC | ECHO_CLOCK_BIT_ESYNC96 | |
60 | ECHO_CLOCK_BIT_ADAT; | 59 | ECHO_CLOCK_BIT_ADAT; |
61 | chip->professional_spdif = FALSE; | ||
62 | chip->digital_in_automute = TRUE; | ||
63 | chip->digital_mode = DIGITAL_MODE_SPDIF_RCA; | ||
64 | 60 | ||
65 | /* Gina24 comes in both '301 and '361 flavors */ | 61 | /* Gina24 comes in both '301 and '361 flavors */ |
66 | if (chip->device_id == DEVICE_ID_56361) { | 62 | if (chip->device_id == DEVICE_ID_56361) { |
67 | chip->dsp_code_to_load = &card_fw[FW_GINA24_361_DSP]; | 63 | chip->dsp_code_to_load = FW_GINA24_361_DSP; |
68 | chip->digital_modes = | 64 | chip->digital_modes = |
69 | ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_RCA | | 65 | ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_RCA | |
70 | ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_OPTICAL | | 66 | ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_OPTICAL | |
71 | ECHOCAPS_HAS_DIGITAL_MODE_ADAT; | 67 | ECHOCAPS_HAS_DIGITAL_MODE_ADAT; |
72 | } else { | 68 | } else { |
73 | chip->dsp_code_to_load = &card_fw[FW_GINA24_301_DSP]; | 69 | chip->dsp_code_to_load = FW_GINA24_301_DSP; |
74 | chip->digital_modes = | 70 | chip->digital_modes = |
75 | ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_RCA | | 71 | ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_RCA | |
76 | ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_OPTICAL | | 72 | ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_OPTICAL | |
@@ -82,19 +78,22 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
82 | return err; | 78 | return err; |
83 | chip->bad_board = FALSE; | 79 | chip->bad_board = FALSE; |
84 | 80 | ||
85 | if ((err = init_line_levels(chip)) < 0) | ||
86 | return err; | ||
87 | err = set_digital_mode(chip, DIGITAL_MODE_SPDIF_RCA); | ||
88 | if (err < 0) | ||
89 | return err; | ||
90 | err = set_professional_spdif(chip, TRUE); | ||
91 | |||
92 | DE_INIT(("init_hw done\n")); | 81 | DE_INIT(("init_hw done\n")); |
93 | return err; | 82 | return err; |
94 | } | 83 | } |
95 | 84 | ||
96 | 85 | ||
97 | 86 | ||
87 | static int set_mixer_defaults(struct echoaudio *chip) | ||
88 | { | ||
89 | chip->digital_mode = DIGITAL_MODE_SPDIF_RCA; | ||
90 | chip->professional_spdif = FALSE; | ||
91 | chip->digital_in_automute = TRUE; | ||
92 | return init_line_levels(chip); | ||
93 | } | ||
94 | |||
95 | |||
96 | |||
98 | static u32 detect_input_clocks(const struct echoaudio *chip) | 97 | static u32 detect_input_clocks(const struct echoaudio *chip) |
99 | { | 98 | { |
100 | u32 clocks_from_dsp, clock_bits; | 99 | u32 clocks_from_dsp, clock_bits; |
@@ -125,7 +124,7 @@ static int load_asic(struct echoaudio *chip) | |||
125 | { | 124 | { |
126 | u32 control_reg; | 125 | u32 control_reg; |
127 | int err; | 126 | int err; |
128 | const struct firmware *fw; | 127 | short asic; |
129 | 128 | ||
130 | if (chip->asic_loaded) | 129 | if (chip->asic_loaded) |
131 | return 1; | 130 | return 1; |
@@ -135,14 +134,15 @@ static int load_asic(struct echoaudio *chip) | |||
135 | 134 | ||
136 | /* Pick the correct ASIC for '301 or '361 Gina24 */ | 135 | /* Pick the correct ASIC for '301 or '361 Gina24 */ |
137 | if (chip->device_id == DEVICE_ID_56361) | 136 | if (chip->device_id == DEVICE_ID_56361) |
138 | fw = &card_fw[FW_GINA24_361_ASIC]; | 137 | asic = FW_GINA24_361_ASIC; |
139 | else | 138 | else |
140 | fw = &card_fw[FW_GINA24_301_ASIC]; | 139 | asic = FW_GINA24_301_ASIC; |
141 | 140 | ||
142 | if ((err = load_asic_generic(chip, DSP_FNC_LOAD_GINA24_ASIC, fw)) < 0) | 141 | err = load_asic_generic(chip, DSP_FNC_LOAD_GINA24_ASIC, asic); |
142 | if (err < 0) | ||
143 | return err; | 143 | return err; |
144 | 144 | ||
145 | chip->asic_code = fw; | 145 | chip->asic_code = asic; |
146 | 146 | ||
147 | /* Now give the new ASIC a little time to set up */ | 147 | /* Now give the new ASIC a little time to set up */ |
148 | mdelay(10); | 148 | mdelay(10); |
diff --git a/sound/pci/echoaudio/indigo.c b/sound/pci/echoaudio/indigo.c index 0a58a7c1fd7c..776175c0bdad 100644 --- a/sound/pci/echoaudio/indigo.c +++ b/sound/pci/echoaudio/indigo.c | |||
@@ -68,7 +68,7 @@ static const struct firmware card_fw[] = { | |||
68 | {0, "indigo_dsp.fw"} | 68 | {0, "indigo_dsp.fw"} |
69 | }; | 69 | }; |
70 | 70 | ||
71 | static struct pci_device_id snd_echo_ids[] = { | 71 | static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { |
72 | {0x1057, 0x3410, 0xECC0, 0x0090, 0, 0, 0}, /* Indigo */ | 72 | {0x1057, 0x3410, 0xECC0, 0x0090, 0, 0, 0}, /* Indigo */ |
73 | {0,} | 73 | {0,} |
74 | }; | 74 | }; |
diff --git a/sound/pci/echoaudio/indigo_dsp.c b/sound/pci/echoaudio/indigo_dsp.c index 0b2cd9c86277..5e85f14fe5a8 100644 --- a/sound/pci/echoaudio/indigo_dsp.c +++ b/sound/pci/echoaudio/indigo_dsp.c | |||
@@ -50,7 +50,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
50 | chip->device_id = device_id; | 50 | chip->device_id = device_id; |
51 | chip->subdevice_id = subdevice_id; | 51 | chip->subdevice_id = subdevice_id; |
52 | chip->bad_board = TRUE; | 52 | chip->bad_board = TRUE; |
53 | chip->dsp_code_to_load = &card_fw[FW_INDIGO_DSP]; | 53 | chip->dsp_code_to_load = FW_INDIGO_DSP; |
54 | /* Since this card has no ASIC, mark it as loaded so everything | 54 | /* Since this card has no ASIC, mark it as loaded so everything |
55 | works OK */ | 55 | works OK */ |
56 | chip->asic_loaded = TRUE; | 56 | chip->asic_loaded = TRUE; |
@@ -60,15 +60,19 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
60 | return err; | 60 | return err; |
61 | chip->bad_board = FALSE; | 61 | chip->bad_board = FALSE; |
62 | 62 | ||
63 | if ((err = init_line_levels(chip)) < 0) | ||
64 | return err; | ||
65 | |||
66 | DE_INIT(("init_hw done\n")); | 63 | DE_INIT(("init_hw done\n")); |
67 | return err; | 64 | return err; |
68 | } | 65 | } |
69 | 66 | ||
70 | 67 | ||
71 | 68 | ||
69 | static int set_mixer_defaults(struct echoaudio *chip) | ||
70 | { | ||
71 | return init_line_levels(chip); | ||
72 | } | ||
73 | |||
74 | |||
75 | |||
72 | static u32 detect_input_clocks(const struct echoaudio *chip) | 76 | static u32 detect_input_clocks(const struct echoaudio *chip) |
73 | { | 77 | { |
74 | return ECHO_CLOCK_BIT_INTERNAL; | 78 | return ECHO_CLOCK_BIT_INTERNAL; |
diff --git a/sound/pci/echoaudio/indigo_express_dsp.c b/sound/pci/echoaudio/indigo_express_dsp.c index 9ab625e15652..2e4ab3e34a74 100644 --- a/sound/pci/echoaudio/indigo_express_dsp.c +++ b/sound/pci/echoaudio/indigo_express_dsp.c | |||
@@ -61,6 +61,7 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate) | |||
61 | 61 | ||
62 | control_reg |= clock; | 62 | control_reg |= clock; |
63 | if (control_reg != old_control_reg) { | 63 | if (control_reg != old_control_reg) { |
64 | DE_ACT(("set_sample_rate: %d clock %d\n", rate, clock)); | ||
64 | chip->comm_page->control_register = cpu_to_le32(control_reg); | 65 | chip->comm_page->control_register = cpu_to_le32(control_reg); |
65 | chip->sample_rate = rate; | 66 | chip->sample_rate = rate; |
66 | clear_handshake(chip); | 67 | clear_handshake(chip); |
diff --git a/sound/pci/echoaudio/indigodj.c b/sound/pci/echoaudio/indigodj.c index 2db24d29332b..8816b0bd2ba6 100644 --- a/sound/pci/echoaudio/indigodj.c +++ b/sound/pci/echoaudio/indigodj.c | |||
@@ -68,7 +68,7 @@ static const struct firmware card_fw[] = { | |||
68 | {0, "indigo_dj_dsp.fw"} | 68 | {0, "indigo_dj_dsp.fw"} |
69 | }; | 69 | }; |
70 | 70 | ||
71 | static struct pci_device_id snd_echo_ids[] = { | 71 | static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { |
72 | {0x1057, 0x3410, 0xECC0, 0x00B0, 0, 0, 0}, /* Indigo DJ*/ | 72 | {0x1057, 0x3410, 0xECC0, 0x00B0, 0, 0, 0}, /* Indigo DJ*/ |
73 | {0,} | 73 | {0,} |
74 | }; | 74 | }; |
diff --git a/sound/pci/echoaudio/indigodj_dsp.c b/sound/pci/echoaudio/indigodj_dsp.c index 08392916691e..68f3c8ccc1bf 100644 --- a/sound/pci/echoaudio/indigodj_dsp.c +++ b/sound/pci/echoaudio/indigodj_dsp.c | |||
@@ -50,7 +50,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
50 | chip->device_id = device_id; | 50 | chip->device_id = device_id; |
51 | chip->subdevice_id = subdevice_id; | 51 | chip->subdevice_id = subdevice_id; |
52 | chip->bad_board = TRUE; | 52 | chip->bad_board = TRUE; |
53 | chip->dsp_code_to_load = &card_fw[FW_INDIGO_DJ_DSP]; | 53 | chip->dsp_code_to_load = FW_INDIGO_DJ_DSP; |
54 | /* Since this card has no ASIC, mark it as loaded so everything | 54 | /* Since this card has no ASIC, mark it as loaded so everything |
55 | works OK */ | 55 | works OK */ |
56 | chip->asic_loaded = TRUE; | 56 | chip->asic_loaded = TRUE; |
@@ -60,15 +60,19 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
60 | return err; | 60 | return err; |
61 | chip->bad_board = FALSE; | 61 | chip->bad_board = FALSE; |
62 | 62 | ||
63 | if ((err = init_line_levels(chip)) < 0) | ||
64 | return err; | ||
65 | |||
66 | DE_INIT(("init_hw done\n")); | 63 | DE_INIT(("init_hw done\n")); |
67 | return err; | 64 | return err; |
68 | } | 65 | } |
69 | 66 | ||
70 | 67 | ||
71 | 68 | ||
69 | static int set_mixer_defaults(struct echoaudio *chip) | ||
70 | { | ||
71 | return init_line_levels(chip); | ||
72 | } | ||
73 | |||
74 | |||
75 | |||
72 | static u32 detect_input_clocks(const struct echoaudio *chip) | 76 | static u32 detect_input_clocks(const struct echoaudio *chip) |
73 | { | 77 | { |
74 | return ECHO_CLOCK_BIT_INTERNAL; | 78 | return ECHO_CLOCK_BIT_INTERNAL; |
diff --git a/sound/pci/echoaudio/indigodjx.c b/sound/pci/echoaudio/indigodjx.c index 2e44316530a2..b1e3652f2f48 100644 --- a/sound/pci/echoaudio/indigodjx.c +++ b/sound/pci/echoaudio/indigodjx.c | |||
@@ -68,7 +68,7 @@ static const struct firmware card_fw[] = { | |||
68 | {0, "indigo_djx_dsp.fw"} | 68 | {0, "indigo_djx_dsp.fw"} |
69 | }; | 69 | }; |
70 | 70 | ||
71 | static struct pci_device_id snd_echo_ids[] = { | 71 | static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { |
72 | {0x1057, 0x3410, 0xECC0, 0x00E0, 0, 0, 0}, /* Indigo DJx*/ | 72 | {0x1057, 0x3410, 0xECC0, 0x00E0, 0, 0, 0}, /* Indigo DJx*/ |
73 | {0,} | 73 | {0,} |
74 | }; | 74 | }; |
diff --git a/sound/pci/echoaudio/indigodjx_dsp.c b/sound/pci/echoaudio/indigodjx_dsp.c index f591fc2ed960..bb9632c752a9 100644 --- a/sound/pci/echoaudio/indigodjx_dsp.c +++ b/sound/pci/echoaudio/indigodjx_dsp.c | |||
@@ -48,7 +48,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
48 | chip->device_id = device_id; | 48 | chip->device_id = device_id; |
49 | chip->subdevice_id = subdevice_id; | 49 | chip->subdevice_id = subdevice_id; |
50 | chip->bad_board = TRUE; | 50 | chip->bad_board = TRUE; |
51 | chip->dsp_code_to_load = &card_fw[FW_INDIGO_DJX_DSP]; | 51 | chip->dsp_code_to_load = FW_INDIGO_DJX_DSP; |
52 | /* Since this card has no ASIC, mark it as loaded so everything | 52 | /* Since this card has no ASIC, mark it as loaded so everything |
53 | works OK */ | 53 | works OK */ |
54 | chip->asic_loaded = TRUE; | 54 | chip->asic_loaded = TRUE; |
@@ -59,10 +59,13 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
59 | return err; | 59 | return err; |
60 | chip->bad_board = FALSE; | 60 | chip->bad_board = FALSE; |
61 | 61 | ||
62 | err = init_line_levels(chip); | ||
63 | if (err < 0) | ||
64 | return err; | ||
65 | |||
66 | DE_INIT(("init_hw done\n")); | 62 | DE_INIT(("init_hw done\n")); |
67 | return err; | 63 | return err; |
68 | } | 64 | } |
65 | |||
66 | |||
67 | |||
68 | static int set_mixer_defaults(struct echoaudio *chip) | ||
69 | { | ||
70 | return init_line_levels(chip); | ||
71 | } | ||
diff --git a/sound/pci/echoaudio/indigoio.c b/sound/pci/echoaudio/indigoio.c index a60c0a0a89b7..1035125336d6 100644 --- a/sound/pci/echoaudio/indigoio.c +++ b/sound/pci/echoaudio/indigoio.c | |||
@@ -69,7 +69,7 @@ static const struct firmware card_fw[] = { | |||
69 | {0, "indigo_io_dsp.fw"} | 69 | {0, "indigo_io_dsp.fw"} |
70 | }; | 70 | }; |
71 | 71 | ||
72 | static struct pci_device_id snd_echo_ids[] = { | 72 | static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { |
73 | {0x1057, 0x3410, 0xECC0, 0x00A0, 0, 0, 0}, /* Indigo IO*/ | 73 | {0x1057, 0x3410, 0xECC0, 0x00A0, 0, 0, 0}, /* Indigo IO*/ |
74 | {0,} | 74 | {0,} |
75 | }; | 75 | }; |
diff --git a/sound/pci/echoaudio/indigoio_dsp.c b/sound/pci/echoaudio/indigoio_dsp.c index 0604c8a85223..beb9a5b69892 100644 --- a/sound/pci/echoaudio/indigoio_dsp.c +++ b/sound/pci/echoaudio/indigoio_dsp.c | |||
@@ -50,7 +50,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
50 | chip->device_id = device_id; | 50 | chip->device_id = device_id; |
51 | chip->subdevice_id = subdevice_id; | 51 | chip->subdevice_id = subdevice_id; |
52 | chip->bad_board = TRUE; | 52 | chip->bad_board = TRUE; |
53 | chip->dsp_code_to_load = &card_fw[FW_INDIGO_IO_DSP]; | 53 | chip->dsp_code_to_load = FW_INDIGO_IO_DSP; |
54 | /* Since this card has no ASIC, mark it as loaded so everything | 54 | /* Since this card has no ASIC, mark it as loaded so everything |
55 | works OK */ | 55 | works OK */ |
56 | chip->asic_loaded = TRUE; | 56 | chip->asic_loaded = TRUE; |
@@ -60,15 +60,19 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
60 | return err; | 60 | return err; |
61 | chip->bad_board = FALSE; | 61 | chip->bad_board = FALSE; |
62 | 62 | ||
63 | if ((err = init_line_levels(chip)) < 0) | ||
64 | return err; | ||
65 | |||
66 | DE_INIT(("init_hw done\n")); | 63 | DE_INIT(("init_hw done\n")); |
67 | return err; | 64 | return err; |
68 | } | 65 | } |
69 | 66 | ||
70 | 67 | ||
71 | 68 | ||
69 | static int set_mixer_defaults(struct echoaudio *chip) | ||
70 | { | ||
71 | return init_line_levels(chip); | ||
72 | } | ||
73 | |||
74 | |||
75 | |||
72 | static u32 detect_input_clocks(const struct echoaudio *chip) | 76 | static u32 detect_input_clocks(const struct echoaudio *chip) |
73 | { | 77 | { |
74 | return ECHO_CLOCK_BIT_INTERNAL; | 78 | return ECHO_CLOCK_BIT_INTERNAL; |
diff --git a/sound/pci/echoaudio/indigoiox.c b/sound/pci/echoaudio/indigoiox.c index eb3819f9654a..60b7cb2753cf 100644 --- a/sound/pci/echoaudio/indigoiox.c +++ b/sound/pci/echoaudio/indigoiox.c | |||
@@ -69,7 +69,7 @@ static const struct firmware card_fw[] = { | |||
69 | {0, "indigo_iox_dsp.fw"} | 69 | {0, "indigo_iox_dsp.fw"} |
70 | }; | 70 | }; |
71 | 71 | ||
72 | static struct pci_device_id snd_echo_ids[] = { | 72 | static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { |
73 | {0x1057, 0x3410, 0xECC0, 0x00D0, 0, 0, 0}, /* Indigo IOx */ | 73 | {0x1057, 0x3410, 0xECC0, 0x00D0, 0, 0, 0}, /* Indigo IOx */ |
74 | {0,} | 74 | {0,} |
75 | }; | 75 | }; |
diff --git a/sound/pci/echoaudio/indigoiox_dsp.c b/sound/pci/echoaudio/indigoiox_dsp.c index f357521c79e6..394c6e76bcbc 100644 --- a/sound/pci/echoaudio/indigoiox_dsp.c +++ b/sound/pci/echoaudio/indigoiox_dsp.c | |||
@@ -48,7 +48,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
48 | chip->device_id = device_id; | 48 | chip->device_id = device_id; |
49 | chip->subdevice_id = subdevice_id; | 49 | chip->subdevice_id = subdevice_id; |
50 | chip->bad_board = TRUE; | 50 | chip->bad_board = TRUE; |
51 | chip->dsp_code_to_load = &card_fw[FW_INDIGO_IOX_DSP]; | 51 | chip->dsp_code_to_load = FW_INDIGO_IOX_DSP; |
52 | /* Since this card has no ASIC, mark it as loaded so everything | 52 | /* Since this card has no ASIC, mark it as loaded so everything |
53 | works OK */ | 53 | works OK */ |
54 | chip->asic_loaded = TRUE; | 54 | chip->asic_loaded = TRUE; |
@@ -59,10 +59,13 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
59 | return err; | 59 | return err; |
60 | chip->bad_board = FALSE; | 60 | chip->bad_board = FALSE; |
61 | 61 | ||
62 | err = init_line_levels(chip); | ||
63 | if (err < 0) | ||
64 | return err; | ||
65 | |||
66 | DE_INIT(("init_hw done\n")); | 62 | DE_INIT(("init_hw done\n")); |
67 | return err; | 63 | return err; |
68 | } | 64 | } |
65 | |||
66 | |||
67 | |||
68 | static int set_mixer_defaults(struct echoaudio *chip) | ||
69 | { | ||
70 | return init_line_levels(chip); | ||
71 | } | ||
diff --git a/sound/pci/echoaudio/layla20.c b/sound/pci/echoaudio/layla20.c index 506194688995..8c3f5c5b5301 100644 --- a/sound/pci/echoaudio/layla20.c +++ b/sound/pci/echoaudio/layla20.c | |||
@@ -76,7 +76,7 @@ static const struct firmware card_fw[] = { | |||
76 | {0, "layla20_asic.fw"} | 76 | {0, "layla20_asic.fw"} |
77 | }; | 77 | }; |
78 | 78 | ||
79 | static struct pci_device_id snd_echo_ids[] = { | 79 | static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { |
80 | {0x1057, 0x1801, 0xECC0, 0x0030, 0, 0, 0}, /* DSP 56301 Layla20 rev.0 */ | 80 | {0x1057, 0x1801, 0xECC0, 0x0030, 0, 0, 0}, /* DSP 56301 Layla20 rev.0 */ |
81 | {0x1057, 0x1801, 0xECC0, 0x0031, 0, 0, 0}, /* DSP 56301 Layla20 rev.1 */ | 81 | {0x1057, 0x1801, 0xECC0, 0x0031, 0, 0, 0}, /* DSP 56301 Layla20 rev.1 */ |
82 | {0,} | 82 | {0,} |
diff --git a/sound/pci/echoaudio/layla20_dsp.c b/sound/pci/echoaudio/layla20_dsp.c index 83750e9fd7b4..53ce94605044 100644 --- a/sound/pci/echoaudio/layla20_dsp.c +++ b/sound/pci/echoaudio/layla20_dsp.c | |||
@@ -31,8 +31,7 @@ | |||
31 | 31 | ||
32 | static int read_dsp(struct echoaudio *chip, u32 *data); | 32 | static int read_dsp(struct echoaudio *chip, u32 *data); |
33 | static int set_professional_spdif(struct echoaudio *chip, char prof); | 33 | static int set_professional_spdif(struct echoaudio *chip, char prof); |
34 | static int load_asic_generic(struct echoaudio *chip, u32 cmd, | 34 | static int load_asic_generic(struct echoaudio *chip, u32 cmd, short asic); |
35 | const struct firmware *asic); | ||
36 | static int check_asic_status(struct echoaudio *chip); | 35 | static int check_asic_status(struct echoaudio *chip); |
37 | static int update_flags(struct echoaudio *chip); | 36 | static int update_flags(struct echoaudio *chip); |
38 | 37 | ||
@@ -54,7 +53,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
54 | chip->subdevice_id = subdevice_id; | 53 | chip->subdevice_id = subdevice_id; |
55 | chip->bad_board = TRUE; | 54 | chip->bad_board = TRUE; |
56 | chip->has_midi = TRUE; | 55 | chip->has_midi = TRUE; |
57 | chip->dsp_code_to_load = &card_fw[FW_LAYLA20_DSP]; | 56 | chip->dsp_code_to_load = FW_LAYLA20_DSP; |
58 | chip->input_clock_types = | 57 | chip->input_clock_types = |
59 | ECHO_CLOCK_BIT_INTERNAL | ECHO_CLOCK_BIT_SPDIF | | 58 | ECHO_CLOCK_BIT_INTERNAL | ECHO_CLOCK_BIT_SPDIF | |
60 | ECHO_CLOCK_BIT_WORD | ECHO_CLOCK_BIT_SUPER; | 59 | ECHO_CLOCK_BIT_WORD | ECHO_CLOCK_BIT_SUPER; |
@@ -65,17 +64,20 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
65 | return err; | 64 | return err; |
66 | chip->bad_board = FALSE; | 65 | chip->bad_board = FALSE; |
67 | 66 | ||
68 | if ((err = init_line_levels(chip)) < 0) | ||
69 | return err; | ||
70 | |||
71 | err = set_professional_spdif(chip, TRUE); | ||
72 | |||
73 | DE_INIT(("init_hw done\n")); | 67 | DE_INIT(("init_hw done\n")); |
74 | return err; | 68 | return err; |
75 | } | 69 | } |
76 | 70 | ||
77 | 71 | ||
78 | 72 | ||
73 | static int set_mixer_defaults(struct echoaudio *chip) | ||
74 | { | ||
75 | chip->professional_spdif = FALSE; | ||
76 | return init_line_levels(chip); | ||
77 | } | ||
78 | |||
79 | |||
80 | |||
79 | static u32 detect_input_clocks(const struct echoaudio *chip) | 81 | static u32 detect_input_clocks(const struct echoaudio *chip) |
80 | { | 82 | { |
81 | u32 clocks_from_dsp, clock_bits; | 83 | u32 clocks_from_dsp, clock_bits; |
@@ -144,7 +146,7 @@ static int load_asic(struct echoaudio *chip) | |||
144 | return 0; | 146 | return 0; |
145 | 147 | ||
146 | err = load_asic_generic(chip, DSP_FNC_LOAD_LAYLA_ASIC, | 148 | err = load_asic_generic(chip, DSP_FNC_LOAD_LAYLA_ASIC, |
147 | &card_fw[FW_LAYLA20_ASIC]); | 149 | FW_LAYLA20_ASIC); |
148 | if (err < 0) | 150 | if (err < 0) |
149 | return err; | 151 | return err; |
150 | 152 | ||
diff --git a/sound/pci/echoaudio/layla24.c b/sound/pci/echoaudio/layla24.c index e09e3ea7781e..ed1cc0abc2b8 100644 --- a/sound/pci/echoaudio/layla24.c +++ b/sound/pci/echoaudio/layla24.c | |||
@@ -87,7 +87,7 @@ static const struct firmware card_fw[] = { | |||
87 | {0, "layla24_2S_asic.fw"} | 87 | {0, "layla24_2S_asic.fw"} |
88 | }; | 88 | }; |
89 | 89 | ||
90 | static struct pci_device_id snd_echo_ids[] = { | 90 | static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { |
91 | {0x1057, 0x3410, 0xECC0, 0x0060, 0, 0, 0}, /* DSP 56361 Layla24 rev.0 */ | 91 | {0x1057, 0x3410, 0xECC0, 0x0060, 0, 0, 0}, /* DSP 56361 Layla24 rev.0 */ |
92 | {0,} | 92 | {0,} |
93 | }; | 93 | }; |
diff --git a/sound/pci/echoaudio/layla24_dsp.c b/sound/pci/echoaudio/layla24_dsp.c index d61b5cbcccad..8c041647f285 100644 --- a/sound/pci/echoaudio/layla24_dsp.c +++ b/sound/pci/echoaudio/layla24_dsp.c | |||
@@ -32,8 +32,7 @@ static int write_control_reg(struct echoaudio *chip, u32 value, char force); | |||
32 | static int set_input_clock(struct echoaudio *chip, u16 clock); | 32 | static int set_input_clock(struct echoaudio *chip, u16 clock); |
33 | static int set_professional_spdif(struct echoaudio *chip, char prof); | 33 | static int set_professional_spdif(struct echoaudio *chip, char prof); |
34 | static int set_digital_mode(struct echoaudio *chip, u8 mode); | 34 | static int set_digital_mode(struct echoaudio *chip, u8 mode); |
35 | static int load_asic_generic(struct echoaudio *chip, u32 cmd, | 35 | static int load_asic_generic(struct echoaudio *chip, u32 cmd, short asic); |
36 | const struct firmware *asic); | ||
37 | static int check_asic_status(struct echoaudio *chip); | 36 | static int check_asic_status(struct echoaudio *chip); |
38 | 37 | ||
39 | 38 | ||
@@ -54,7 +53,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
54 | chip->subdevice_id = subdevice_id; | 53 | chip->subdevice_id = subdevice_id; |
55 | chip->bad_board = TRUE; | 54 | chip->bad_board = TRUE; |
56 | chip->has_midi = TRUE; | 55 | chip->has_midi = TRUE; |
57 | chip->dsp_code_to_load = &card_fw[FW_LAYLA24_DSP]; | 56 | chip->dsp_code_to_load = FW_LAYLA24_DSP; |
58 | chip->input_clock_types = | 57 | chip->input_clock_types = |
59 | ECHO_CLOCK_BIT_INTERNAL | ECHO_CLOCK_BIT_SPDIF | | 58 | ECHO_CLOCK_BIT_INTERNAL | ECHO_CLOCK_BIT_SPDIF | |
60 | ECHO_CLOCK_BIT_WORD | ECHO_CLOCK_BIT_ADAT; | 59 | ECHO_CLOCK_BIT_WORD | ECHO_CLOCK_BIT_ADAT; |
@@ -62,9 +61,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
62 | ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_RCA | | 61 | ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_RCA | |
63 | ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_OPTICAL | | 62 | ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_OPTICAL | |
64 | ECHOCAPS_HAS_DIGITAL_MODE_ADAT; | 63 | ECHOCAPS_HAS_DIGITAL_MODE_ADAT; |
65 | chip->digital_mode = DIGITAL_MODE_SPDIF_RCA; | ||
66 | chip->professional_spdif = FALSE; | ||
67 | chip->digital_in_automute = TRUE; | ||
68 | 64 | ||
69 | if ((err = load_firmware(chip)) < 0) | 65 | if ((err = load_firmware(chip)) < 0) |
70 | return err; | 66 | return err; |
@@ -73,17 +69,22 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
73 | if ((err = init_line_levels(chip)) < 0) | 69 | if ((err = init_line_levels(chip)) < 0) |
74 | return err; | 70 | return err; |
75 | 71 | ||
76 | err = set_digital_mode(chip, DIGITAL_MODE_SPDIF_RCA); | ||
77 | if (err < 0) | ||
78 | return err; | ||
79 | err = set_professional_spdif(chip, TRUE); | ||
80 | |||
81 | DE_INIT(("init_hw done\n")); | 72 | DE_INIT(("init_hw done\n")); |
82 | return err; | 73 | return err; |
83 | } | 74 | } |
84 | 75 | ||
85 | 76 | ||
86 | 77 | ||
78 | static int set_mixer_defaults(struct echoaudio *chip) | ||
79 | { | ||
80 | chip->digital_mode = DIGITAL_MODE_SPDIF_RCA; | ||
81 | chip->professional_spdif = FALSE; | ||
82 | chip->digital_in_automute = TRUE; | ||
83 | return init_line_levels(chip); | ||
84 | } | ||
85 | |||
86 | |||
87 | |||
87 | static u32 detect_input_clocks(const struct echoaudio *chip) | 88 | static u32 detect_input_clocks(const struct echoaudio *chip) |
88 | { | 89 | { |
89 | u32 clocks_from_dsp, clock_bits; | 90 | u32 clocks_from_dsp, clock_bits; |
@@ -123,18 +124,18 @@ static int load_asic(struct echoaudio *chip) | |||
123 | 124 | ||
124 | /* Load the ASIC for the PCI card */ | 125 | /* Load the ASIC for the PCI card */ |
125 | err = load_asic_generic(chip, DSP_FNC_LOAD_LAYLA24_PCI_CARD_ASIC, | 126 | err = load_asic_generic(chip, DSP_FNC_LOAD_LAYLA24_PCI_CARD_ASIC, |
126 | &card_fw[FW_LAYLA24_1_ASIC]); | 127 | FW_LAYLA24_1_ASIC); |
127 | if (err < 0) | 128 | if (err < 0) |
128 | return err; | 129 | return err; |
129 | 130 | ||
130 | chip->asic_code = &card_fw[FW_LAYLA24_2S_ASIC]; | 131 | chip->asic_code = FW_LAYLA24_2S_ASIC; |
131 | 132 | ||
132 | /* Now give the new ASIC a little time to set up */ | 133 | /* Now give the new ASIC a little time to set up */ |
133 | mdelay(10); | 134 | mdelay(10); |
134 | 135 | ||
135 | /* Do the external one */ | 136 | /* Do the external one */ |
136 | err = load_asic_generic(chip, DSP_FNC_LOAD_LAYLA24_EXTERNAL_ASIC, | 137 | err = load_asic_generic(chip, DSP_FNC_LOAD_LAYLA24_EXTERNAL_ASIC, |
137 | &card_fw[FW_LAYLA24_2S_ASIC]); | 138 | FW_LAYLA24_2S_ASIC); |
138 | if (err < 0) | 139 | if (err < 0) |
139 | return FALSE; | 140 | return FALSE; |
140 | 141 | ||
@@ -299,7 +300,7 @@ static int set_input_clock(struct echoaudio *chip, u16 clock) | |||
299 | /* Depending on what digital mode you want, Layla24 needs different ASICs | 300 | /* Depending on what digital mode you want, Layla24 needs different ASICs |
300 | loaded. This function checks the ASIC needed for the new mode and sees | 301 | loaded. This function checks the ASIC needed for the new mode and sees |
301 | if it matches the one already loaded. */ | 302 | if it matches the one already loaded. */ |
302 | static int switch_asic(struct echoaudio *chip, const struct firmware *asic) | 303 | static int switch_asic(struct echoaudio *chip, short asic) |
303 | { | 304 | { |
304 | s8 *monitors; | 305 | s8 *monitors; |
305 | 306 | ||
@@ -335,7 +336,7 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode) | |||
335 | { | 336 | { |
336 | u32 control_reg; | 337 | u32 control_reg; |
337 | int err, incompatible_clock; | 338 | int err, incompatible_clock; |
338 | const struct firmware *asic; | 339 | short asic; |
339 | 340 | ||
340 | /* Set clock to "internal" if it's not compatible with the new mode */ | 341 | /* Set clock to "internal" if it's not compatible with the new mode */ |
341 | incompatible_clock = FALSE; | 342 | incompatible_clock = FALSE; |
@@ -344,12 +345,12 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode) | |||
344 | case DIGITAL_MODE_SPDIF_RCA: | 345 | case DIGITAL_MODE_SPDIF_RCA: |
345 | if (chip->input_clock == ECHO_CLOCK_ADAT) | 346 | if (chip->input_clock == ECHO_CLOCK_ADAT) |
346 | incompatible_clock = TRUE; | 347 | incompatible_clock = TRUE; |
347 | asic = &card_fw[FW_LAYLA24_2S_ASIC]; | 348 | asic = FW_LAYLA24_2S_ASIC; |
348 | break; | 349 | break; |
349 | case DIGITAL_MODE_ADAT: | 350 | case DIGITAL_MODE_ADAT: |
350 | if (chip->input_clock == ECHO_CLOCK_SPDIF) | 351 | if (chip->input_clock == ECHO_CLOCK_SPDIF) |
351 | incompatible_clock = TRUE; | 352 | incompatible_clock = TRUE; |
352 | asic = &card_fw[FW_LAYLA24_2A_ASIC]; | 353 | asic = FW_LAYLA24_2A_ASIC; |
353 | break; | 354 | break; |
354 | default: | 355 | default: |
355 | DE_ACT(("Digital mode not supported: %d\n", mode)); | 356 | DE_ACT(("Digital mode not supported: %d\n", mode)); |
diff --git a/sound/pci/echoaudio/mia.c b/sound/pci/echoaudio/mia.c index f05c8c097aa8..cc2bbfc65327 100644 --- a/sound/pci/echoaudio/mia.c +++ b/sound/pci/echoaudio/mia.c | |||
@@ -77,7 +77,7 @@ static const struct firmware card_fw[] = { | |||
77 | {0, "mia_dsp.fw"} | 77 | {0, "mia_dsp.fw"} |
78 | }; | 78 | }; |
79 | 79 | ||
80 | static struct pci_device_id snd_echo_ids[] = { | 80 | static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { |
81 | {0x1057, 0x3410, 0xECC0, 0x0080, 0, 0, 0}, /* DSP 56361 Mia rev.0 */ | 81 | {0x1057, 0x3410, 0xECC0, 0x0080, 0, 0, 0}, /* DSP 56361 Mia rev.0 */ |
82 | {0x1057, 0x3410, 0xECC0, 0x0081, 0, 0, 0}, /* DSP 56361 Mia rev.1 */ | 82 | {0x1057, 0x3410, 0xECC0, 0x0081, 0, 0, 0}, /* DSP 56361 Mia rev.1 */ |
83 | {0,} | 83 | {0,} |
diff --git a/sound/pci/echoaudio/mia_dsp.c b/sound/pci/echoaudio/mia_dsp.c index 551405114cbc..6ebfa6e7ab9e 100644 --- a/sound/pci/echoaudio/mia_dsp.c +++ b/sound/pci/echoaudio/mia_dsp.c | |||
@@ -53,7 +53,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
53 | chip->device_id = device_id; | 53 | chip->device_id = device_id; |
54 | chip->subdevice_id = subdevice_id; | 54 | chip->subdevice_id = subdevice_id; |
55 | chip->bad_board = TRUE; | 55 | chip->bad_board = TRUE; |
56 | chip->dsp_code_to_load = &card_fw[FW_MIA_DSP]; | 56 | chip->dsp_code_to_load = FW_MIA_DSP; |
57 | /* Since this card has no ASIC, mark it as loaded so everything | 57 | /* Since this card has no ASIC, mark it as loaded so everything |
58 | works OK */ | 58 | works OK */ |
59 | chip->asic_loaded = TRUE; | 59 | chip->asic_loaded = TRUE; |
@@ -66,15 +66,19 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
66 | return err; | 66 | return err; |
67 | chip->bad_board = FALSE; | 67 | chip->bad_board = FALSE; |
68 | 68 | ||
69 | if ((err = init_line_levels(chip))) | ||
70 | return err; | ||
71 | |||
72 | DE_INIT(("init_hw done\n")); | 69 | DE_INIT(("init_hw done\n")); |
73 | return err; | 70 | return err; |
74 | } | 71 | } |
75 | 72 | ||
76 | 73 | ||
77 | 74 | ||
75 | static int set_mixer_defaults(struct echoaudio *chip) | ||
76 | { | ||
77 | return init_line_levels(chip); | ||
78 | } | ||
79 | |||
80 | |||
81 | |||
78 | static u32 detect_input_clocks(const struct echoaudio *chip) | 82 | static u32 detect_input_clocks(const struct echoaudio *chip) |
79 | { | 83 | { |
80 | u32 clocks_from_dsp, clock_bits; | 84 | u32 clocks_from_dsp, clock_bits; |
diff --git a/sound/pci/echoaudio/mona.c b/sound/pci/echoaudio/mona.c index b05bad944901..3e7e01824b40 100644 --- a/sound/pci/echoaudio/mona.c +++ b/sound/pci/echoaudio/mona.c | |||
@@ -92,7 +92,7 @@ static const struct firmware card_fw[] = { | |||
92 | {0, "mona_2_asic.fw"} | 92 | {0, "mona_2_asic.fw"} |
93 | }; | 93 | }; |
94 | 94 | ||
95 | static struct pci_device_id snd_echo_ids[] = { | 95 | static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { |
96 | {0x1057, 0x1801, 0xECC0, 0x0070, 0, 0, 0}, /* DSP 56301 Mona rev.0 */ | 96 | {0x1057, 0x1801, 0xECC0, 0x0070, 0, 0, 0}, /* DSP 56301 Mona rev.0 */ |
97 | {0x1057, 0x1801, 0xECC0, 0x0071, 0, 0, 0}, /* DSP 56301 Mona rev.1 */ | 97 | {0x1057, 0x1801, 0xECC0, 0x0071, 0, 0, 0}, /* DSP 56301 Mona rev.1 */ |
98 | {0x1057, 0x1801, 0xECC0, 0x0072, 0, 0, 0}, /* DSP 56301 Mona rev.2 */ | 98 | {0x1057, 0x1801, 0xECC0, 0x0072, 0, 0, 0}, /* DSP 56301 Mona rev.2 */ |
diff --git a/sound/pci/echoaudio/mona_dsp.c b/sound/pci/echoaudio/mona_dsp.c index eaa619bd2a03..6e6a7eb555b8 100644 --- a/sound/pci/echoaudio/mona_dsp.c +++ b/sound/pci/echoaudio/mona_dsp.c | |||
@@ -33,8 +33,7 @@ static int write_control_reg(struct echoaudio *chip, u32 value, char force); | |||
33 | static int set_input_clock(struct echoaudio *chip, u16 clock); | 33 | static int set_input_clock(struct echoaudio *chip, u16 clock); |
34 | static int set_professional_spdif(struct echoaudio *chip, char prof); | 34 | static int set_professional_spdif(struct echoaudio *chip, char prof); |
35 | static int set_digital_mode(struct echoaudio *chip, u8 mode); | 35 | static int set_digital_mode(struct echoaudio *chip, u8 mode); |
36 | static int load_asic_generic(struct echoaudio *chip, u32 cmd, | 36 | static int load_asic_generic(struct echoaudio *chip, u32 cmd, short asic); |
37 | const struct firmware *asic); | ||
38 | static int check_asic_status(struct echoaudio *chip); | 37 | static int check_asic_status(struct echoaudio *chip); |
39 | 38 | ||
40 | 39 | ||
@@ -64,32 +63,30 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
64 | 63 | ||
65 | /* Mona comes in both '301 and '361 flavors */ | 64 | /* Mona comes in both '301 and '361 flavors */ |
66 | if (chip->device_id == DEVICE_ID_56361) | 65 | if (chip->device_id == DEVICE_ID_56361) |
67 | chip->dsp_code_to_load = &card_fw[FW_MONA_361_DSP]; | 66 | chip->dsp_code_to_load = FW_MONA_361_DSP; |
68 | else | 67 | else |
69 | chip->dsp_code_to_load = &card_fw[FW_MONA_301_DSP]; | 68 | chip->dsp_code_to_load = FW_MONA_301_DSP; |
70 | |||
71 | chip->digital_mode = DIGITAL_MODE_SPDIF_RCA; | ||
72 | chip->professional_spdif = FALSE; | ||
73 | chip->digital_in_automute = TRUE; | ||
74 | 69 | ||
75 | if ((err = load_firmware(chip)) < 0) | 70 | if ((err = load_firmware(chip)) < 0) |
76 | return err; | 71 | return err; |
77 | chip->bad_board = FALSE; | 72 | chip->bad_board = FALSE; |
78 | 73 | ||
79 | if ((err = init_line_levels(chip)) < 0) | ||
80 | return err; | ||
81 | |||
82 | err = set_digital_mode(chip, DIGITAL_MODE_SPDIF_RCA); | ||
83 | if (err < 0) | ||
84 | return err; | ||
85 | err = set_professional_spdif(chip, TRUE); | ||
86 | |||
87 | DE_INIT(("init_hw done\n")); | 74 | DE_INIT(("init_hw done\n")); |
88 | return err; | 75 | return err; |
89 | } | 76 | } |
90 | 77 | ||
91 | 78 | ||
92 | 79 | ||
80 | static int set_mixer_defaults(struct echoaudio *chip) | ||
81 | { | ||
82 | chip->digital_mode = DIGITAL_MODE_SPDIF_RCA; | ||
83 | chip->professional_spdif = FALSE; | ||
84 | chip->digital_in_automute = TRUE; | ||
85 | return init_line_levels(chip); | ||
86 | } | ||
87 | |||
88 | |||
89 | |||
93 | static u32 detect_input_clocks(const struct echoaudio *chip) | 90 | static u32 detect_input_clocks(const struct echoaudio *chip) |
94 | { | 91 | { |
95 | u32 clocks_from_dsp, clock_bits; | 92 | u32 clocks_from_dsp, clock_bits; |
@@ -120,7 +117,7 @@ static int load_asic(struct echoaudio *chip) | |||
120 | { | 117 | { |
121 | u32 control_reg; | 118 | u32 control_reg; |
122 | int err; | 119 | int err; |
123 | const struct firmware *asic; | 120 | short asic; |
124 | 121 | ||
125 | if (chip->asic_loaded) | 122 | if (chip->asic_loaded) |
126 | return 0; | 123 | return 0; |
@@ -128,9 +125,9 @@ static int load_asic(struct echoaudio *chip) | |||
128 | mdelay(10); | 125 | mdelay(10); |
129 | 126 | ||
130 | if (chip->device_id == DEVICE_ID_56361) | 127 | if (chip->device_id == DEVICE_ID_56361) |
131 | asic = &card_fw[FW_MONA_361_1_ASIC48]; | 128 | asic = FW_MONA_361_1_ASIC48; |
132 | else | 129 | else |
133 | asic = &card_fw[FW_MONA_301_1_ASIC48]; | 130 | asic = FW_MONA_301_1_ASIC48; |
134 | 131 | ||
135 | err = load_asic_generic(chip, DSP_FNC_LOAD_MONA_PCI_CARD_ASIC, asic); | 132 | err = load_asic_generic(chip, DSP_FNC_LOAD_MONA_PCI_CARD_ASIC, asic); |
136 | if (err < 0) | 133 | if (err < 0) |
@@ -141,7 +138,7 @@ static int load_asic(struct echoaudio *chip) | |||
141 | 138 | ||
142 | /* Do the external one */ | 139 | /* Do the external one */ |
143 | err = load_asic_generic(chip, DSP_FNC_LOAD_MONA_EXTERNAL_ASIC, | 140 | err = load_asic_generic(chip, DSP_FNC_LOAD_MONA_EXTERNAL_ASIC, |
144 | &card_fw[FW_MONA_2_ASIC]); | 141 | FW_MONA_2_ASIC); |
145 | if (err < 0) | 142 | if (err < 0) |
146 | return err; | 143 | return err; |
147 | 144 | ||
@@ -165,22 +162,22 @@ loaded. This function checks the ASIC needed for the new mode and sees | |||
165 | if it matches the one already loaded. */ | 162 | if it matches the one already loaded. */ |
166 | static int switch_asic(struct echoaudio *chip, char double_speed) | 163 | static int switch_asic(struct echoaudio *chip, char double_speed) |
167 | { | 164 | { |
168 | const struct firmware *asic; | ||
169 | int err; | 165 | int err; |
166 | short asic; | ||
170 | 167 | ||
171 | /* Check the clock detect bits to see if this is | 168 | /* Check the clock detect bits to see if this is |
172 | a single-speed clock or a double-speed clock; load | 169 | a single-speed clock or a double-speed clock; load |
173 | a new ASIC if necessary. */ | 170 | a new ASIC if necessary. */ |
174 | if (chip->device_id == DEVICE_ID_56361) { | 171 | if (chip->device_id == DEVICE_ID_56361) { |
175 | if (double_speed) | 172 | if (double_speed) |
176 | asic = &card_fw[FW_MONA_361_1_ASIC96]; | 173 | asic = FW_MONA_361_1_ASIC96; |
177 | else | 174 | else |
178 | asic = &card_fw[FW_MONA_361_1_ASIC48]; | 175 | asic = FW_MONA_361_1_ASIC48; |
179 | } else { | 176 | } else { |
180 | if (double_speed) | 177 | if (double_speed) |
181 | asic = &card_fw[FW_MONA_301_1_ASIC96]; | 178 | asic = FW_MONA_301_1_ASIC96; |
182 | else | 179 | else |
183 | asic = &card_fw[FW_MONA_301_1_ASIC48]; | 180 | asic = FW_MONA_301_1_ASIC48; |
184 | } | 181 | } |
185 | 182 | ||
186 | if (asic != chip->asic_code) { | 183 | if (asic != chip->asic_code) { |
@@ -200,7 +197,7 @@ static int switch_asic(struct echoaudio *chip, char double_speed) | |||
200 | static int set_sample_rate(struct echoaudio *chip, u32 rate) | 197 | static int set_sample_rate(struct echoaudio *chip, u32 rate) |
201 | { | 198 | { |
202 | u32 control_reg, clock; | 199 | u32 control_reg, clock; |
203 | const struct firmware *asic; | 200 | short asic; |
204 | char force_write; | 201 | char force_write; |
205 | 202 | ||
206 | /* Only set the clock for internal mode. */ | 203 | /* Only set the clock for internal mode. */ |
@@ -218,14 +215,14 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate) | |||
218 | if (chip->digital_mode == DIGITAL_MODE_ADAT) | 215 | if (chip->digital_mode == DIGITAL_MODE_ADAT) |
219 | return -EINVAL; | 216 | return -EINVAL; |
220 | if (chip->device_id == DEVICE_ID_56361) | 217 | if (chip->device_id == DEVICE_ID_56361) |
221 | asic = &card_fw[FW_MONA_361_1_ASIC96]; | 218 | asic = FW_MONA_361_1_ASIC96; |
222 | else | 219 | else |
223 | asic = &card_fw[FW_MONA_301_1_ASIC96]; | 220 | asic = FW_MONA_301_1_ASIC96; |
224 | } else { | 221 | } else { |
225 | if (chip->device_id == DEVICE_ID_56361) | 222 | if (chip->device_id == DEVICE_ID_56361) |
226 | asic = &card_fw[FW_MONA_361_1_ASIC48]; | 223 | asic = FW_MONA_361_1_ASIC48; |
227 | else | 224 | else |
228 | asic = &card_fw[FW_MONA_301_1_ASIC48]; | 225 | asic = FW_MONA_301_1_ASIC48; |
229 | } | 226 | } |
230 | 227 | ||
231 | force_write = 0; | 228 | force_write = 0; |
@@ -410,8 +407,8 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode) | |||
410 | case DIGITAL_MODE_ADAT: | 407 | case DIGITAL_MODE_ADAT: |
411 | /* If the current ASIC is the 96KHz ASIC, switch the ASIC | 408 | /* If the current ASIC is the 96KHz ASIC, switch the ASIC |
412 | and set to 48 KHz */ | 409 | and set to 48 KHz */ |
413 | if (chip->asic_code == &card_fw[FW_MONA_361_1_ASIC96] || | 410 | if (chip->asic_code == FW_MONA_361_1_ASIC96 || |
414 | chip->asic_code == &card_fw[FW_MONA_301_1_ASIC96]) { | 411 | chip->asic_code == FW_MONA_301_1_ASIC96) { |
415 | set_sample_rate(chip, 48000); | 412 | set_sample_rate(chip, 48000); |
416 | } | 413 | } |
417 | control_reg |= GML_ADAT_MODE; | 414 | control_reg |= GML_ADAT_MODE; |
diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c index 168af67d938e..4203782d7cb7 100644 --- a/sound/pci/emu10k1/emu10k1.c +++ b/sound/pci/emu10k1/emu10k1.c | |||
@@ -76,7 +76,7 @@ MODULE_PARM_DESC(subsystem, "Force card subsystem model."); | |||
76 | /* | 76 | /* |
77 | * Class 0401: 1102:0008 (rev 00) Subsystem: 1102:1001 -> Audigy2 Value Model:SB0400 | 77 | * Class 0401: 1102:0008 (rev 00) Subsystem: 1102:1001 -> Audigy2 Value Model:SB0400 |
78 | */ | 78 | */ |
79 | static struct pci_device_id snd_emu10k1_ids[] = { | 79 | static DEFINE_PCI_DEVICE_TABLE(snd_emu10k1_ids) = { |
80 | { PCI_VDEVICE(CREATIVE, 0x0002), 0 }, /* EMU10K1 */ | 80 | { PCI_VDEVICE(CREATIVE, 0x0002), 0 }, /* EMU10K1 */ |
81 | { PCI_VDEVICE(CREATIVE, 0x0004), 1 }, /* Audigy */ | 81 | { PCI_VDEVICE(CREATIVE, 0x0004), 1 }, /* Audigy */ |
82 | { PCI_VDEVICE(CREATIVE, 0x0008), 1 }, /* Audigy 2 Value SB0400 */ | 82 | { PCI_VDEVICE(CREATIVE, 0x0008), 1 }, /* Audigy 2 Value SB0400 */ |
diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c index 1d369ff73805..df47f738098d 100644 --- a/sound/pci/emu10k1/emu10k1x.c +++ b/sound/pci/emu10k1/emu10k1x.c | |||
@@ -1605,7 +1605,7 @@ static void __devexit snd_emu10k1x_remove(struct pci_dev *pci) | |||
1605 | } | 1605 | } |
1606 | 1606 | ||
1607 | // PCI IDs | 1607 | // PCI IDs |
1608 | static struct pci_device_id snd_emu10k1x_ids[] = { | 1608 | static DEFINE_PCI_DEVICE_TABLE(snd_emu10k1x_ids) = { |
1609 | { PCI_VDEVICE(CREATIVE, 0x0006), 0 }, /* Dell OEM version (EMU10K1) */ | 1609 | { PCI_VDEVICE(CREATIVE, 0x0006), 0 }, /* Dell OEM version (EMU10K1) */ |
1610 | { 0, } | 1610 | { 0, } |
1611 | }; | 1611 | }; |
diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c index 2b82c5c723e1..c7fba5379813 100644 --- a/sound/pci/ens1370.c +++ b/sound/pci/ens1370.c | |||
@@ -443,7 +443,7 @@ struct ensoniq { | |||
443 | 443 | ||
444 | static irqreturn_t snd_audiopci_interrupt(int irq, void *dev_id); | 444 | static irqreturn_t snd_audiopci_interrupt(int irq, void *dev_id); |
445 | 445 | ||
446 | static struct pci_device_id snd_audiopci_ids[] = { | 446 | static DEFINE_PCI_DEVICE_TABLE(snd_audiopci_ids) = { |
447 | #ifdef CHIP1370 | 447 | #ifdef CHIP1370 |
448 | { PCI_VDEVICE(ENSONIQ, 0x5000), 0, }, /* ES1370 */ | 448 | { PCI_VDEVICE(ENSONIQ, 0x5000), 0, }, /* ES1370 */ |
449 | #endif | 449 | #endif |
diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c index fb83e1ffa5cb..553b75217259 100644 --- a/sound/pci/es1938.c +++ b/sound/pci/es1938.c | |||
@@ -243,7 +243,7 @@ struct es1938 { | |||
243 | 243 | ||
244 | static irqreturn_t snd_es1938_interrupt(int irq, void *dev_id); | 244 | static irqreturn_t snd_es1938_interrupt(int irq, void *dev_id); |
245 | 245 | ||
246 | static struct pci_device_id snd_es1938_ids[] = { | 246 | static DEFINE_PCI_DEVICE_TABLE(snd_es1938_ids) = { |
247 | { PCI_VDEVICE(ESS, 0x1969), 0, }, /* Solo-1 */ | 247 | { PCI_VDEVICE(ESS, 0x1969), 0, }, /* Solo-1 */ |
248 | { 0, } | 248 | { 0, } |
249 | }; | 249 | }; |
diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c index a11f453a6b6d..ecaea9fb48ec 100644 --- a/sound/pci/es1968.c +++ b/sound/pci/es1968.c | |||
@@ -551,7 +551,7 @@ struct es1968 { | |||
551 | 551 | ||
552 | static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id); | 552 | static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id); |
553 | 553 | ||
554 | static struct pci_device_id snd_es1968_ids[] = { | 554 | static DEFINE_PCI_DEVICE_TABLE(snd_es1968_ids) = { |
555 | /* Maestro 1 */ | 555 | /* Maestro 1 */ |
556 | { 0x1285, 0x0100, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, TYPE_MAESTRO }, | 556 | { 0x1285, 0x0100, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, TYPE_MAESTRO }, |
557 | /* Maestro 2 */ | 557 | /* Maestro 2 */ |
diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index 83508b3964fb..e1baad74ea4b 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c | |||
@@ -205,7 +205,7 @@ struct fm801 { | |||
205 | #endif | 205 | #endif |
206 | }; | 206 | }; |
207 | 207 | ||
208 | static struct pci_device_id snd_fm801_ids[] = { | 208 | static DEFINE_PCI_DEVICE_TABLE(snd_fm801_ids) = { |
209 | { 0x1319, 0x0801, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0, }, /* FM801 */ | 209 | { 0x1319, 0x0801, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0, }, /* FM801 */ |
210 | { 0x5213, 0x0510, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0, }, /* Gallant Odyssey Sound 4 */ | 210 | { 0x5213, 0x0510, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0, }, /* Gallant Odyssey Sound 4 */ |
211 | { 0, } | 211 | { 0, } |
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index f98b47cd6cfb..76d3c4c049db 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c | |||
@@ -824,6 +824,9 @@ int snd_hda_add_pincfg(struct hda_codec *codec, struct snd_array *list, | |||
824 | struct hda_pincfg *pin; | 824 | struct hda_pincfg *pin; |
825 | unsigned int oldcfg; | 825 | unsigned int oldcfg; |
826 | 826 | ||
827 | if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN) | ||
828 | return -EINVAL; | ||
829 | |||
827 | oldcfg = snd_hda_codec_get_pincfg(codec, nid); | 830 | oldcfg = snd_hda_codec_get_pincfg(codec, nid); |
828 | pin = look_up_pincfg(codec, list, nid); | 831 | pin = look_up_pincfg(codec, list, nid); |
829 | if (!pin) { | 832 | if (!pin) { |
@@ -899,6 +902,25 @@ static void restore_pincfgs(struct hda_codec *codec) | |||
899 | } | 902 | } |
900 | } | 903 | } |
901 | 904 | ||
905 | /** | ||
906 | * snd_hda_shutup_pins - Shut up all pins | ||
907 | * @codec: the HDA codec | ||
908 | * | ||
909 | * Clear all pin controls to shup up before suspend for avoiding click noise. | ||
910 | * The controls aren't cached so that they can be resumed properly. | ||
911 | */ | ||
912 | void snd_hda_shutup_pins(struct hda_codec *codec) | ||
913 | { | ||
914 | int i; | ||
915 | for (i = 0; i < codec->init_pins.used; i++) { | ||
916 | struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i); | ||
917 | /* use read here for syncing after issuing each verb */ | ||
918 | snd_hda_codec_read(codec, pin->nid, 0, | ||
919 | AC_VERB_SET_PIN_WIDGET_CONTROL, 0); | ||
920 | } | ||
921 | } | ||
922 | EXPORT_SYMBOL_HDA(snd_hda_shutup_pins); | ||
923 | |||
902 | static void init_hda_cache(struct hda_cache_rec *cache, | 924 | static void init_hda_cache(struct hda_cache_rec *cache, |
903 | unsigned int record_size); | 925 | unsigned int record_size); |
904 | static void free_hda_cache(struct hda_cache_rec *cache); | 926 | static void free_hda_cache(struct hda_cache_rec *cache); |
@@ -931,6 +953,7 @@ static void snd_hda_codec_free(struct hda_codec *codec) | |||
931 | #endif | 953 | #endif |
932 | list_del(&codec->list); | 954 | list_del(&codec->list); |
933 | snd_array_free(&codec->mixers); | 955 | snd_array_free(&codec->mixers); |
956 | snd_array_free(&codec->nids); | ||
934 | codec->bus->caddr_tbl[codec->addr] = NULL; | 957 | codec->bus->caddr_tbl[codec->addr] = NULL; |
935 | if (codec->patch_ops.free) | 958 | if (codec->patch_ops.free) |
936 | codec->patch_ops.free(codec); | 959 | codec->patch_ops.free(codec); |
@@ -985,7 +1008,8 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr | |||
985 | mutex_init(&codec->control_mutex); | 1008 | mutex_init(&codec->control_mutex); |
986 | init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info)); | 1009 | init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info)); |
987 | init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head)); | 1010 | init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head)); |
988 | snd_array_init(&codec->mixers, sizeof(struct hda_nid_item), 60); | 1011 | snd_array_init(&codec->mixers, sizeof(struct hda_nid_item), 32); |
1012 | snd_array_init(&codec->nids, sizeof(struct hda_nid_item), 32); | ||
989 | snd_array_init(&codec->init_pins, sizeof(struct hda_pincfg), 16); | 1013 | snd_array_init(&codec->init_pins, sizeof(struct hda_pincfg), 16); |
990 | snd_array_init(&codec->driver_pins, sizeof(struct hda_pincfg), 16); | 1014 | snd_array_init(&codec->driver_pins, sizeof(struct hda_pincfg), 16); |
991 | if (codec->bus->modelname) { | 1015 | if (codec->bus->modelname) { |
@@ -1708,7 +1732,7 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec, | |||
1708 | EXPORT_SYMBOL_HDA(snd_hda_find_mixer_ctl); | 1732 | EXPORT_SYMBOL_HDA(snd_hda_find_mixer_ctl); |
1709 | 1733 | ||
1710 | /** | 1734 | /** |
1711 | * snd_hda_ctl-add - Add a control element and assign to the codec | 1735 | * snd_hda_ctl_add - Add a control element and assign to the codec |
1712 | * @codec: HD-audio codec | 1736 | * @codec: HD-audio codec |
1713 | * @nid: corresponding NID (optional) | 1737 | * @nid: corresponding NID (optional) |
1714 | * @kctl: the control element to assign | 1738 | * @kctl: the control element to assign |
@@ -1723,19 +1747,25 @@ EXPORT_SYMBOL_HDA(snd_hda_find_mixer_ctl); | |||
1723 | * | 1747 | * |
1724 | * snd_hda_ctl_add() checks the control subdev id field whether | 1748 | * snd_hda_ctl_add() checks the control subdev id field whether |
1725 | * #HDA_SUBDEV_NID_FLAG bit is set. If set (and @nid is zero), the lower | 1749 | * #HDA_SUBDEV_NID_FLAG bit is set. If set (and @nid is zero), the lower |
1726 | * bits value is taken as the NID to assign. | 1750 | * bits value is taken as the NID to assign. The #HDA_NID_ITEM_AMP bit |
1751 | * specifies if kctl->private_value is a HDA amplifier value. | ||
1727 | */ | 1752 | */ |
1728 | int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid, | 1753 | int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid, |
1729 | struct snd_kcontrol *kctl) | 1754 | struct snd_kcontrol *kctl) |
1730 | { | 1755 | { |
1731 | int err; | 1756 | int err; |
1757 | unsigned short flags = 0; | ||
1732 | struct hda_nid_item *item; | 1758 | struct hda_nid_item *item; |
1733 | 1759 | ||
1734 | if (kctl->id.subdevice & HDA_SUBDEV_NID_FLAG) { | 1760 | if (kctl->id.subdevice & HDA_SUBDEV_AMP_FLAG) { |
1761 | flags |= HDA_NID_ITEM_AMP; | ||
1735 | if (nid == 0) | 1762 | if (nid == 0) |
1736 | nid = kctl->id.subdevice & 0xffff; | 1763 | nid = get_amp_nid_(kctl->private_value); |
1737 | kctl->id.subdevice = 0; | ||
1738 | } | 1764 | } |
1765 | if ((kctl->id.subdevice & HDA_SUBDEV_NID_FLAG) != 0 && nid == 0) | ||
1766 | nid = kctl->id.subdevice & 0xffff; | ||
1767 | if (kctl->id.subdevice & (HDA_SUBDEV_NID_FLAG|HDA_SUBDEV_AMP_FLAG)) | ||
1768 | kctl->id.subdevice = 0; | ||
1739 | err = snd_ctl_add(codec->bus->card, kctl); | 1769 | err = snd_ctl_add(codec->bus->card, kctl); |
1740 | if (err < 0) | 1770 | if (err < 0) |
1741 | return err; | 1771 | return err; |
@@ -1744,11 +1774,41 @@ int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid, | |||
1744 | return -ENOMEM; | 1774 | return -ENOMEM; |
1745 | item->kctl = kctl; | 1775 | item->kctl = kctl; |
1746 | item->nid = nid; | 1776 | item->nid = nid; |
1777 | item->flags = flags; | ||
1747 | return 0; | 1778 | return 0; |
1748 | } | 1779 | } |
1749 | EXPORT_SYMBOL_HDA(snd_hda_ctl_add); | 1780 | EXPORT_SYMBOL_HDA(snd_hda_ctl_add); |
1750 | 1781 | ||
1751 | /** | 1782 | /** |
1783 | * snd_hda_add_nid - Assign a NID to a control element | ||
1784 | * @codec: HD-audio codec | ||
1785 | * @nid: corresponding NID (optional) | ||
1786 | * @kctl: the control element to assign | ||
1787 | * @index: index to kctl | ||
1788 | * | ||
1789 | * Add the given control element to an array inside the codec instance. | ||
1790 | * This function is used when #snd_hda_ctl_add cannot be used for 1:1 | ||
1791 | * NID:KCTL mapping - for example "Capture Source" selector. | ||
1792 | */ | ||
1793 | int snd_hda_add_nid(struct hda_codec *codec, struct snd_kcontrol *kctl, | ||
1794 | unsigned int index, hda_nid_t nid) | ||
1795 | { | ||
1796 | struct hda_nid_item *item; | ||
1797 | |||
1798 | if (nid > 0) { | ||
1799 | item = snd_array_new(&codec->nids); | ||
1800 | if (!item) | ||
1801 | return -ENOMEM; | ||
1802 | item->kctl = kctl; | ||
1803 | item->index = index; | ||
1804 | item->nid = nid; | ||
1805 | return 0; | ||
1806 | } | ||
1807 | return -EINVAL; | ||
1808 | } | ||
1809 | EXPORT_SYMBOL_HDA(snd_hda_add_nid); | ||
1810 | |||
1811 | /** | ||
1752 | * snd_hda_ctls_clear - Clear all controls assigned to the given codec | 1812 | * snd_hda_ctls_clear - Clear all controls assigned to the given codec |
1753 | * @codec: HD-audio codec | 1813 | * @codec: HD-audio codec |
1754 | */ | 1814 | */ |
@@ -1759,6 +1819,7 @@ void snd_hda_ctls_clear(struct hda_codec *codec) | |||
1759 | for (i = 0; i < codec->mixers.used; i++) | 1819 | for (i = 0; i < codec->mixers.used; i++) |
1760 | snd_ctl_remove(codec->bus->card, items[i].kctl); | 1820 | snd_ctl_remove(codec->bus->card, items[i].kctl); |
1761 | snd_array_free(&codec->mixers); | 1821 | snd_array_free(&codec->mixers); |
1822 | snd_array_free(&codec->nids); | ||
1762 | } | 1823 | } |
1763 | 1824 | ||
1764 | /* pseudo device locking | 1825 | /* pseudo device locking |
@@ -2706,7 +2767,8 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, | |||
2706 | snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE, | 2767 | snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE, |
2707 | power_state); | 2768 | power_state); |
2708 | /* partial workaround for "azx_get_response timeout" */ | 2769 | /* partial workaround for "azx_get_response timeout" */ |
2709 | if (power_state == AC_PWRST_D0) | 2770 | if (power_state == AC_PWRST_D0 && |
2771 | (codec->vendor_id & 0xffff0000) == 0x14f10000) | ||
2710 | msleep(10); | 2772 | msleep(10); |
2711 | 2773 | ||
2712 | nid = codec->start_nid; | 2774 | nid = codec->start_nid; |
@@ -2740,7 +2802,6 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, | |||
2740 | if (power_state == AC_PWRST_D0) { | 2802 | if (power_state == AC_PWRST_D0) { |
2741 | unsigned long end_time; | 2803 | unsigned long end_time; |
2742 | int state; | 2804 | int state; |
2743 | msleep(10); | ||
2744 | /* wait until the codec reachs to D0 */ | 2805 | /* wait until the codec reachs to D0 */ |
2745 | end_time = jiffies + msecs_to_jiffies(500); | 2806 | end_time = jiffies + msecs_to_jiffies(500); |
2746 | do { | 2807 | do { |
@@ -3214,6 +3275,8 @@ const char *snd_hda_pcm_type_name[HDA_PCM_NTYPES] = { | |||
3214 | 3275 | ||
3215 | /* | 3276 | /* |
3216 | * get the empty PCM device number to assign | 3277 | * get the empty PCM device number to assign |
3278 | * | ||
3279 | * note the max device number is limited by HDA_MAX_PCMS, currently 10 | ||
3217 | */ | 3280 | */ |
3218 | static int get_empty_pcm_device(struct hda_bus *bus, int type) | 3281 | static int get_empty_pcm_device(struct hda_bus *bus, int type) |
3219 | { | 3282 | { |
@@ -3478,6 +3541,8 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew) | |||
3478 | 3541 | ||
3479 | for (; knew->name; knew++) { | 3542 | for (; knew->name; knew++) { |
3480 | struct snd_kcontrol *kctl; | 3543 | struct snd_kcontrol *kctl; |
3544 | if (knew->iface == -1) /* skip this codec private value */ | ||
3545 | continue; | ||
3481 | kctl = snd_ctl_new1(knew, codec); | 3546 | kctl = snd_ctl_new1(knew, codec); |
3482 | if (!kctl) | 3547 | if (!kctl) |
3483 | return -ENOMEM; | 3548 | return -ENOMEM; |
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 0a770a28e71f..b75da47571e6 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h | |||
@@ -527,6 +527,9 @@ enum { | |||
527 | /* max. codec address */ | 527 | /* max. codec address */ |
528 | #define HDA_MAX_CODEC_ADDRESS 0x0f | 528 | #define HDA_MAX_CODEC_ADDRESS 0x0f |
529 | 529 | ||
530 | /* max number of PCM devics per card */ | ||
531 | #define HDA_MAX_PCMS 10 | ||
532 | |||
530 | /* | 533 | /* |
531 | * generic arrays | 534 | * generic arrays |
532 | */ | 535 | */ |
@@ -789,6 +792,7 @@ struct hda_codec { | |||
789 | u32 *wcaps; | 792 | u32 *wcaps; |
790 | 793 | ||
791 | struct snd_array mixers; /* list of assigned mixer elements */ | 794 | struct snd_array mixers; /* list of assigned mixer elements */ |
795 | struct snd_array nids; /* list of mapped mixer elements */ | ||
792 | 796 | ||
793 | struct hda_cache_rec amp_cache; /* cache for amp access */ | 797 | struct hda_cache_rec amp_cache; /* cache for amp access */ |
794 | struct hda_cache_rec cmd_cache; /* cache for other commands */ | 798 | struct hda_cache_rec cmd_cache; /* cache for other commands */ |
@@ -898,6 +902,7 @@ int snd_hda_codec_set_pincfg(struct hda_codec *codec, hda_nid_t nid, | |||
898 | unsigned int cfg); | 902 | unsigned int cfg); |
899 | int snd_hda_add_pincfg(struct hda_codec *codec, struct snd_array *list, | 903 | int snd_hda_add_pincfg(struct hda_codec *codec, struct snd_array *list, |
900 | hda_nid_t nid, unsigned int cfg); /* for hwdep */ | 904 | hda_nid_t nid, unsigned int cfg); /* for hwdep */ |
905 | void snd_hda_shutup_pins(struct hda_codec *codec); | ||
901 | 906 | ||
902 | /* | 907 | /* |
903 | * Mixer | 908 | * Mixer |
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 092c6a7c2ff3..5ea21285ee1f 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c | |||
@@ -861,7 +861,8 @@ static int build_input_controls(struct hda_codec *codec) | |||
861 | } | 861 | } |
862 | 862 | ||
863 | /* create input MUX if multiple sources are available */ | 863 | /* create input MUX if multiple sources are available */ |
864 | err = snd_hda_ctl_add(codec, 0, snd_ctl_new1(&cap_sel, codec)); | 864 | err = snd_hda_ctl_add(codec, spec->adc_node->nid, |
865 | snd_ctl_new1(&cap_sel, codec)); | ||
865 | if (err < 0) | 866 | if (err < 0) |
866 | return err; | 867 | return err; |
867 | 868 | ||
diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index 40ccb419b6e9..a1fc83753cc6 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/sound/pci/hda/hda_hwdep.c | |||
@@ -293,8 +293,11 @@ static ssize_t type##_store(struct device *dev, \ | |||
293 | { \ | 293 | { \ |
294 | struct snd_hwdep *hwdep = dev_get_drvdata(dev); \ | 294 | struct snd_hwdep *hwdep = dev_get_drvdata(dev); \ |
295 | struct hda_codec *codec = hwdep->private_data; \ | 295 | struct hda_codec *codec = hwdep->private_data; \ |
296 | char *after; \ | 296 | unsigned long val; \ |
297 | codec->type = simple_strtoul(buf, &after, 0); \ | 297 | int err = strict_strtoul(buf, 0, &val); \ |
298 | if (err < 0) \ | ||
299 | return err; \ | ||
300 | codec->type = val; \ | ||
298 | return count; \ | 301 | return count; \ |
299 | } | 302 | } |
300 | 303 | ||
@@ -622,6 +625,10 @@ enum { | |||
622 | LINE_MODE_PINCFG, | 625 | LINE_MODE_PINCFG, |
623 | LINE_MODE_VERB, | 626 | LINE_MODE_VERB, |
624 | LINE_MODE_HINT, | 627 | LINE_MODE_HINT, |
628 | LINE_MODE_VENDOR_ID, | ||
629 | LINE_MODE_SUBSYSTEM_ID, | ||
630 | LINE_MODE_REVISION_ID, | ||
631 | LINE_MODE_CHIP_NAME, | ||
625 | NUM_LINE_MODES, | 632 | NUM_LINE_MODES, |
626 | }; | 633 | }; |
627 | 634 | ||
@@ -651,53 +658,71 @@ static void parse_codec_mode(char *buf, struct hda_bus *bus, | |||
651 | } | 658 | } |
652 | 659 | ||
653 | /* parse the contents after the other command tags, [pincfg], [verb], | 660 | /* parse the contents after the other command tags, [pincfg], [verb], |
654 | * [hint] and [model] | 661 | * [vendor_id], [subsystem_id], [revision_id], [chip_name], [hint] and [model] |
655 | * just pass to the sysfs helper (only when any codec was specified) | 662 | * just pass to the sysfs helper (only when any codec was specified) |
656 | */ | 663 | */ |
657 | static void parse_pincfg_mode(char *buf, struct hda_bus *bus, | 664 | static void parse_pincfg_mode(char *buf, struct hda_bus *bus, |
658 | struct hda_codec **codecp) | 665 | struct hda_codec **codecp) |
659 | { | 666 | { |
660 | if (!*codecp) | ||
661 | return; | ||
662 | parse_user_pin_configs(*codecp, buf); | 667 | parse_user_pin_configs(*codecp, buf); |
663 | } | 668 | } |
664 | 669 | ||
665 | static void parse_verb_mode(char *buf, struct hda_bus *bus, | 670 | static void parse_verb_mode(char *buf, struct hda_bus *bus, |
666 | struct hda_codec **codecp) | 671 | struct hda_codec **codecp) |
667 | { | 672 | { |
668 | if (!*codecp) | ||
669 | return; | ||
670 | parse_init_verbs(*codecp, buf); | 673 | parse_init_verbs(*codecp, buf); |
671 | } | 674 | } |
672 | 675 | ||
673 | static void parse_hint_mode(char *buf, struct hda_bus *bus, | 676 | static void parse_hint_mode(char *buf, struct hda_bus *bus, |
674 | struct hda_codec **codecp) | 677 | struct hda_codec **codecp) |
675 | { | 678 | { |
676 | if (!*codecp) | ||
677 | return; | ||
678 | parse_hints(*codecp, buf); | 679 | parse_hints(*codecp, buf); |
679 | } | 680 | } |
680 | 681 | ||
681 | static void parse_model_mode(char *buf, struct hda_bus *bus, | 682 | static void parse_model_mode(char *buf, struct hda_bus *bus, |
682 | struct hda_codec **codecp) | 683 | struct hda_codec **codecp) |
683 | { | 684 | { |
684 | if (!*codecp) | ||
685 | return; | ||
686 | kfree((*codecp)->modelname); | 685 | kfree((*codecp)->modelname); |
687 | (*codecp)->modelname = kstrdup(buf, GFP_KERNEL); | 686 | (*codecp)->modelname = kstrdup(buf, GFP_KERNEL); |
688 | } | 687 | } |
689 | 688 | ||
689 | static void parse_chip_name_mode(char *buf, struct hda_bus *bus, | ||
690 | struct hda_codec **codecp) | ||
691 | { | ||
692 | kfree((*codecp)->chip_name); | ||
693 | (*codecp)->chip_name = kstrdup(buf, GFP_KERNEL); | ||
694 | } | ||
695 | |||
696 | #define DEFINE_PARSE_ID_MODE(name) \ | ||
697 | static void parse_##name##_mode(char *buf, struct hda_bus *bus, \ | ||
698 | struct hda_codec **codecp) \ | ||
699 | { \ | ||
700 | unsigned long val; \ | ||
701 | if (!strict_strtoul(buf, 0, &val)) \ | ||
702 | (*codecp)->name = val; \ | ||
703 | } | ||
704 | |||
705 | DEFINE_PARSE_ID_MODE(vendor_id); | ||
706 | DEFINE_PARSE_ID_MODE(subsystem_id); | ||
707 | DEFINE_PARSE_ID_MODE(revision_id); | ||
708 | |||
709 | |||
690 | struct hda_patch_item { | 710 | struct hda_patch_item { |
691 | const char *tag; | 711 | const char *tag; |
692 | void (*parser)(char *buf, struct hda_bus *bus, struct hda_codec **retc); | 712 | void (*parser)(char *buf, struct hda_bus *bus, struct hda_codec **retc); |
713 | int need_codec; | ||
693 | }; | 714 | }; |
694 | 715 | ||
695 | static struct hda_patch_item patch_items[NUM_LINE_MODES] = { | 716 | static struct hda_patch_item patch_items[NUM_LINE_MODES] = { |
696 | [LINE_MODE_CODEC] = { "[codec]", parse_codec_mode }, | 717 | [LINE_MODE_CODEC] = { "[codec]", parse_codec_mode, 0 }, |
697 | [LINE_MODE_MODEL] = { "[model]", parse_model_mode }, | 718 | [LINE_MODE_MODEL] = { "[model]", parse_model_mode, 1 }, |
698 | [LINE_MODE_VERB] = { "[verb]", parse_verb_mode }, | 719 | [LINE_MODE_VERB] = { "[verb]", parse_verb_mode, 1 }, |
699 | [LINE_MODE_PINCFG] = { "[pincfg]", parse_pincfg_mode }, | 720 | [LINE_MODE_PINCFG] = { "[pincfg]", parse_pincfg_mode, 1 }, |
700 | [LINE_MODE_HINT] = { "[hint]", parse_hint_mode }, | 721 | [LINE_MODE_HINT] = { "[hint]", parse_hint_mode, 1 }, |
722 | [LINE_MODE_VENDOR_ID] = { "[vendor_id]", parse_vendor_id_mode, 1 }, | ||
723 | [LINE_MODE_SUBSYSTEM_ID] = { "[subsystem_id]", parse_subsystem_id_mode, 1 }, | ||
724 | [LINE_MODE_REVISION_ID] = { "[revision_id]", parse_revision_id_mode, 1 }, | ||
725 | [LINE_MODE_CHIP_NAME] = { "[chip_name]", parse_chip_name_mode, 1 }, | ||
701 | }; | 726 | }; |
702 | 727 | ||
703 | /* check the line starting with '[' -- change the parser mode accodingly */ | 728 | /* check the line starting with '[' -- change the parser mode accodingly */ |
@@ -780,7 +805,8 @@ int snd_hda_load_patch(struct hda_bus *bus, const char *patch) | |||
780 | continue; | 805 | continue; |
781 | if (*buf == '[') | 806 | if (*buf == '[') |
782 | line_mode = parse_line_mode(buf, bus); | 807 | line_mode = parse_line_mode(buf, bus); |
783 | else if (patch_items[line_mode].parser) | 808 | else if (patch_items[line_mode].parser && |
809 | (codec || !patch_items[line_mode].need_codec)) | ||
784 | patch_items[line_mode].parser(buf, bus, &codec); | 810 | patch_items[line_mode].parser(buf, bus, &codec); |
785 | } | 811 | } |
786 | release_firmware(fw); | 812 | release_firmware(fw); |
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 565de38a3fc7..d5c93ad852ee 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c | |||
@@ -125,6 +125,7 @@ MODULE_SUPPORTED_DEVICE("{{Intel, ICH6}," | |||
125 | "{Intel, ICH9}," | 125 | "{Intel, ICH9}," |
126 | "{Intel, ICH10}," | 126 | "{Intel, ICH10}," |
127 | "{Intel, PCH}," | 127 | "{Intel, PCH}," |
128 | "{Intel, CPT}," | ||
128 | "{Intel, SCH}," | 129 | "{Intel, SCH}," |
129 | "{ATI, SB450}," | 130 | "{ATI, SB450}," |
130 | "{ATI, SB600}," | 131 | "{ATI, SB600}," |
@@ -259,8 +260,6 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; | |||
259 | #define AZX_MAX_FRAG 32 | 260 | #define AZX_MAX_FRAG 32 |
260 | /* max buffer size - no h/w limit, you can increase as you like */ | 261 | /* max buffer size - no h/w limit, you can increase as you like */ |
261 | #define AZX_MAX_BUF_SIZE (1024*1024*1024) | 262 | #define AZX_MAX_BUF_SIZE (1024*1024*1024) |
262 | /* max number of PCM devics per card */ | ||
263 | #define AZX_MAX_PCMS 8 | ||
264 | 263 | ||
265 | /* RIRB int mask: overrun[2], response[0] */ | 264 | /* RIRB int mask: overrun[2], response[0] */ |
266 | #define RIRB_INT_RESPONSE 0x01 | 265 | #define RIRB_INT_RESPONSE 0x01 |
@@ -408,7 +407,7 @@ struct azx { | |||
408 | struct azx_dev *azx_dev; | 407 | struct azx_dev *azx_dev; |
409 | 408 | ||
410 | /* PCM */ | 409 | /* PCM */ |
411 | struct snd_pcm *pcm[AZX_MAX_PCMS]; | 410 | struct snd_pcm *pcm[HDA_MAX_PCMS]; |
412 | 411 | ||
413 | /* HD codec */ | 412 | /* HD codec */ |
414 | unsigned short codec_mask; | 413 | unsigned short codec_mask; |
@@ -426,6 +425,7 @@ struct azx { | |||
426 | 425 | ||
427 | /* flags */ | 426 | /* flags */ |
428 | int position_fix; | 427 | int position_fix; |
428 | int poll_count; | ||
429 | unsigned int running :1; | 429 | unsigned int running :1; |
430 | unsigned int initialized :1; | 430 | unsigned int initialized :1; |
431 | unsigned int single_cmd :1; | 431 | unsigned int single_cmd :1; |
@@ -448,6 +448,7 @@ struct azx { | |||
448 | /* driver types */ | 448 | /* driver types */ |
449 | enum { | 449 | enum { |
450 | AZX_DRIVER_ICH, | 450 | AZX_DRIVER_ICH, |
451 | AZX_DRIVER_PCH, | ||
451 | AZX_DRIVER_SCH, | 452 | AZX_DRIVER_SCH, |
452 | AZX_DRIVER_ATI, | 453 | AZX_DRIVER_ATI, |
453 | AZX_DRIVER_ATIHDMI, | 454 | AZX_DRIVER_ATIHDMI, |
@@ -462,6 +463,7 @@ enum { | |||
462 | 463 | ||
463 | static char *driver_short_names[] __devinitdata = { | 464 | static char *driver_short_names[] __devinitdata = { |
464 | [AZX_DRIVER_ICH] = "HDA Intel", | 465 | [AZX_DRIVER_ICH] = "HDA Intel", |
466 | [AZX_DRIVER_PCH] = "HDA Intel PCH", | ||
465 | [AZX_DRIVER_SCH] = "HDA Intel MID", | 467 | [AZX_DRIVER_SCH] = "HDA Intel MID", |
466 | [AZX_DRIVER_ATI] = "HDA ATI SB", | 468 | [AZX_DRIVER_ATI] = "HDA ATI SB", |
467 | [AZX_DRIVER_ATIHDMI] = "HDA ATI HDMI", | 469 | [AZX_DRIVER_ATIHDMI] = "HDA ATI HDMI", |
@@ -506,7 +508,7 @@ static char *driver_short_names[] __devinitdata = { | |||
506 | #define get_azx_dev(substream) (substream->runtime->private_data) | 508 | #define get_azx_dev(substream) (substream->runtime->private_data) |
507 | 509 | ||
508 | static int azx_acquire_irq(struct azx *chip, int do_disconnect); | 510 | static int azx_acquire_irq(struct azx *chip, int do_disconnect); |
509 | 511 | static int azx_send_cmd(struct hda_bus *bus, unsigned int val); | |
510 | /* | 512 | /* |
511 | * Interface for HD codec | 513 | * Interface for HD codec |
512 | */ | 514 | */ |
@@ -664,11 +666,12 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus, | |||
664 | { | 666 | { |
665 | struct azx *chip = bus->private_data; | 667 | struct azx *chip = bus->private_data; |
666 | unsigned long timeout; | 668 | unsigned long timeout; |
669 | int do_poll = 0; | ||
667 | 670 | ||
668 | again: | 671 | again: |
669 | timeout = jiffies + msecs_to_jiffies(1000); | 672 | timeout = jiffies + msecs_to_jiffies(1000); |
670 | for (;;) { | 673 | for (;;) { |
671 | if (chip->polling_mode) { | 674 | if (chip->polling_mode || do_poll) { |
672 | spin_lock_irq(&chip->reg_lock); | 675 | spin_lock_irq(&chip->reg_lock); |
673 | azx_update_rirb(chip); | 676 | azx_update_rirb(chip); |
674 | spin_unlock_irq(&chip->reg_lock); | 677 | spin_unlock_irq(&chip->reg_lock); |
@@ -676,6 +679,9 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus, | |||
676 | if (!chip->rirb.cmds[addr]) { | 679 | if (!chip->rirb.cmds[addr]) { |
677 | smp_rmb(); | 680 | smp_rmb(); |
678 | bus->rirb_error = 0; | 681 | bus->rirb_error = 0; |
682 | |||
683 | if (!do_poll) | ||
684 | chip->poll_count = 0; | ||
679 | return chip->rirb.res[addr]; /* the last value */ | 685 | return chip->rirb.res[addr]; /* the last value */ |
680 | } | 686 | } |
681 | if (time_after(jiffies, timeout)) | 687 | if (time_after(jiffies, timeout)) |
@@ -688,6 +694,16 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus, | |||
688 | } | 694 | } |
689 | } | 695 | } |
690 | 696 | ||
697 | if (!chip->polling_mode && chip->poll_count < 2) { | ||
698 | snd_printdd(SFX "azx_get_response timeout, " | ||
699 | "polling the codec once: last cmd=0x%08x\n", | ||
700 | chip->last_cmd[addr]); | ||
701 | do_poll = 1; | ||
702 | chip->poll_count++; | ||
703 | goto again; | ||
704 | } | ||
705 | |||
706 | |||
691 | if (!chip->polling_mode) { | 707 | if (!chip->polling_mode) { |
692 | snd_printk(KERN_WARNING SFX "azx_get_response timeout, " | 708 | snd_printk(KERN_WARNING SFX "azx_get_response timeout, " |
693 | "switching to polling mode: last cmd=0x%08x\n", | 709 | "switching to polling mode: last cmd=0x%08x\n", |
@@ -953,8 +969,8 @@ static void azx_stream_start(struct azx *chip, struct azx_dev *azx_dev) | |||
953 | azx_dev->insufficient = 1; | 969 | azx_dev->insufficient = 1; |
954 | 970 | ||
955 | /* enable SIE */ | 971 | /* enable SIE */ |
956 | azx_writeb(chip, INTCTL, | 972 | azx_writel(chip, INTCTL, |
957 | azx_readb(chip, INTCTL) | (1 << azx_dev->index)); | 973 | azx_readl(chip, INTCTL) | (1 << azx_dev->index)); |
958 | /* set DMA start and interrupt mask */ | 974 | /* set DMA start and interrupt mask */ |
959 | azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) | | 975 | azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) | |
960 | SD_CTL_DMA_START | SD_INT_MASK); | 976 | SD_CTL_DMA_START | SD_INT_MASK); |
@@ -973,8 +989,8 @@ static void azx_stream_stop(struct azx *chip, struct azx_dev *azx_dev) | |||
973 | { | 989 | { |
974 | azx_stream_clear(chip, azx_dev); | 990 | azx_stream_clear(chip, azx_dev); |
975 | /* disable SIE */ | 991 | /* disable SIE */ |
976 | azx_writeb(chip, INTCTL, | 992 | azx_writel(chip, INTCTL, |
977 | azx_readb(chip, INTCTL) & ~(1 << azx_dev->index)); | 993 | azx_readl(chip, INTCTL) & ~(1 << azx_dev->index)); |
978 | } | 994 | } |
979 | 995 | ||
980 | 996 | ||
@@ -1050,6 +1066,7 @@ static void azx_init_pci(struct azx *chip) | |||
1050 | 0x01, NVIDIA_HDA_ENABLE_COHBIT); | 1066 | 0x01, NVIDIA_HDA_ENABLE_COHBIT); |
1051 | break; | 1067 | break; |
1052 | case AZX_DRIVER_SCH: | 1068 | case AZX_DRIVER_SCH: |
1069 | case AZX_DRIVER_PCH: | ||
1053 | pci_read_config_word(chip->pci, INTEL_SCH_HDA_DEVC, &snoop); | 1070 | pci_read_config_word(chip->pci, INTEL_SCH_HDA_DEVC, &snoop); |
1054 | if (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP) { | 1071 | if (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP) { |
1055 | pci_write_config_word(chip->pci, INTEL_SCH_HDA_DEVC, | 1072 | pci_write_config_word(chip->pci, INTEL_SCH_HDA_DEVC, |
@@ -1335,7 +1352,7 @@ static void azx_bus_reset(struct hda_bus *bus) | |||
1335 | if (chip->initialized) { | 1352 | if (chip->initialized) { |
1336 | int i; | 1353 | int i; |
1337 | 1354 | ||
1338 | for (i = 0; i < AZX_MAX_PCMS; i++) | 1355 | for (i = 0; i < HDA_MAX_PCMS; i++) |
1339 | snd_pcm_suspend_all(chip->pcm[i]); | 1356 | snd_pcm_suspend_all(chip->pcm[i]); |
1340 | snd_hda_suspend(chip->bus); | 1357 | snd_hda_suspend(chip->bus); |
1341 | snd_hda_resume(chip->bus); | 1358 | snd_hda_resume(chip->bus); |
@@ -1397,7 +1414,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model) | |||
1397 | chip->codec_mask &= ~(1 << c); | 1414 | chip->codec_mask &= ~(1 << c); |
1398 | /* More badly, accessing to a non-existing | 1415 | /* More badly, accessing to a non-existing |
1399 | * codec often screws up the controller chip, | 1416 | * codec often screws up the controller chip, |
1400 | * and distrubs the further communications. | 1417 | * and disturbs the further communications. |
1401 | * Thus if an error occurs during probing, | 1418 | * Thus if an error occurs during probing, |
1402 | * better to reset the controller chip to | 1419 | * better to reset the controller chip to |
1403 | * get back to the sanity state. | 1420 | * get back to the sanity state. |
@@ -1878,6 +1895,9 @@ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev) | |||
1878 | 1895 | ||
1879 | if (!bdl_pos_adj[chip->dev_index]) | 1896 | if (!bdl_pos_adj[chip->dev_index]) |
1880 | return 1; /* no delayed ack */ | 1897 | return 1; /* no delayed ack */ |
1898 | if (WARN_ONCE(!azx_dev->period_bytes, | ||
1899 | "hda-intel: zero azx_dev->period_bytes")) | ||
1900 | return 0; /* this shouldn't happen! */ | ||
1881 | if (pos % azx_dev->period_bytes > azx_dev->period_bytes / 2) | 1901 | if (pos % azx_dev->period_bytes > azx_dev->period_bytes / 2) |
1882 | return 0; /* NG - it's below the period boundary */ | 1902 | return 0; /* NG - it's below the period boundary */ |
1883 | return 1; /* OK, it's fine */ | 1903 | return 1; /* OK, it's fine */ |
@@ -1965,7 +1985,7 @@ azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec, | |||
1965 | int pcm_dev = cpcm->device; | 1985 | int pcm_dev = cpcm->device; |
1966 | int s, err; | 1986 | int s, err; |
1967 | 1987 | ||
1968 | if (pcm_dev >= AZX_MAX_PCMS) { | 1988 | if (pcm_dev >= HDA_MAX_PCMS) { |
1969 | snd_printk(KERN_ERR SFX "Invalid PCM device number %d\n", | 1989 | snd_printk(KERN_ERR SFX "Invalid PCM device number %d\n", |
1970 | pcm_dev); | 1990 | pcm_dev); |
1971 | return -EINVAL; | 1991 | return -EINVAL; |
@@ -2043,7 +2063,7 @@ static int azx_acquire_irq(struct azx *chip, int do_disconnect) | |||
2043 | { | 2063 | { |
2044 | if (request_irq(chip->pci->irq, azx_interrupt, | 2064 | if (request_irq(chip->pci->irq, azx_interrupt, |
2045 | chip->msi ? 0 : IRQF_SHARED, | 2065 | chip->msi ? 0 : IRQF_SHARED, |
2046 | "HDA Intel", chip)) { | 2066 | "hda_intel", chip)) { |
2047 | printk(KERN_ERR "hda-intel: unable to grab IRQ %d, " | 2067 | printk(KERN_ERR "hda-intel: unable to grab IRQ %d, " |
2048 | "disabling device\n", chip->pci->irq); | 2068 | "disabling device\n", chip->pci->irq); |
2049 | if (do_disconnect) | 2069 | if (do_disconnect) |
@@ -2121,7 +2141,7 @@ static int azx_suspend(struct pci_dev *pci, pm_message_t state) | |||
2121 | 2141 | ||
2122 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); | 2142 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); |
2123 | azx_clear_irq_pending(chip); | 2143 | azx_clear_irq_pending(chip); |
2124 | for (i = 0; i < AZX_MAX_PCMS; i++) | 2144 | for (i = 0; i < HDA_MAX_PCMS; i++) |
2125 | snd_pcm_suspend_all(chip->pcm[i]); | 2145 | snd_pcm_suspend_all(chip->pcm[i]); |
2126 | if (chip->initialized) | 2146 | if (chip->initialized) |
2127 | snd_hda_suspend(chip->bus); | 2147 | snd_hda_suspend(chip->bus); |
@@ -2244,6 +2264,7 @@ static struct snd_pci_quirk position_fix_list[] __devinitdata = { | |||
2244 | SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_LPIB), | 2264 | SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_LPIB), |
2245 | SND_PCI_QUIRK(0x1028, 0x01de, "Dell Precision 390", POS_FIX_LPIB), | 2265 | SND_PCI_QUIRK(0x1028, 0x01de, "Dell Precision 390", POS_FIX_LPIB), |
2246 | SND_PCI_QUIRK(0x103c, 0x306d, "HP dv3", POS_FIX_LPIB), | 2266 | SND_PCI_QUIRK(0x103c, 0x306d, "HP dv3", POS_FIX_LPIB), |
2267 | SND_PCI_QUIRK(0x1106, 0x3288, "ASUS M2V-MX SE", POS_FIX_LPIB), | ||
2247 | SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_LPIB), | 2268 | SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_LPIB), |
2248 | SND_PCI_QUIRK(0x1462, 0x1002, "MSI Wind U115", POS_FIX_LPIB), | 2269 | SND_PCI_QUIRK(0x1462, 0x1002, "MSI Wind U115", POS_FIX_LPIB), |
2249 | {} | 2270 | {} |
@@ -2332,7 +2353,7 @@ static void __devinit check_probe_mask(struct azx *chip, int dev) | |||
2332 | */ | 2353 | */ |
2333 | static struct snd_pci_quirk msi_black_list[] __devinitdata = { | 2354 | static struct snd_pci_quirk msi_black_list[] __devinitdata = { |
2334 | SND_PCI_QUIRK(0x1043, 0x81f2, "ASUS", 0), /* Athlon64 X2 + nvidia */ | 2355 | SND_PCI_QUIRK(0x1043, 0x81f2, "ASUS", 0), /* Athlon64 X2 + nvidia */ |
2335 | SND_PCI_QUIRK(0x1043, 0x829c, "ASUS", 0), /* nvidia */ | 2356 | SND_PCI_QUIRK(0x1043, 0x81f6, "ASUS", 0), /* nvidia */ |
2336 | {} | 2357 | {} |
2337 | }; | 2358 | }; |
2338 | 2359 | ||
@@ -2400,6 +2421,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, | |||
2400 | if (bdl_pos_adj[dev] < 0) { | 2421 | if (bdl_pos_adj[dev] < 0) { |
2401 | switch (chip->driver_type) { | 2422 | switch (chip->driver_type) { |
2402 | case AZX_DRIVER_ICH: | 2423 | case AZX_DRIVER_ICH: |
2424 | case AZX_DRIVER_PCH: | ||
2403 | bdl_pos_adj[dev] = 1; | 2425 | bdl_pos_adj[dev] = 1; |
2404 | break; | 2426 | break; |
2405 | default: | 2427 | default: |
@@ -2665,7 +2687,7 @@ static void __devexit azx_remove(struct pci_dev *pci) | |||
2665 | } | 2687 | } |
2666 | 2688 | ||
2667 | /* PCI IDs */ | 2689 | /* PCI IDs */ |
2668 | static struct pci_device_id azx_ids[] = { | 2690 | static DEFINE_PCI_DEVICE_TABLE(azx_ids) = { |
2669 | /* ICH 6..10 */ | 2691 | /* ICH 6..10 */ |
2670 | { PCI_DEVICE(0x8086, 0x2668), .driver_data = AZX_DRIVER_ICH }, | 2692 | { PCI_DEVICE(0x8086, 0x2668), .driver_data = AZX_DRIVER_ICH }, |
2671 | { PCI_DEVICE(0x8086, 0x27d8), .driver_data = AZX_DRIVER_ICH }, | 2693 | { PCI_DEVICE(0x8086, 0x27d8), .driver_data = AZX_DRIVER_ICH }, |
@@ -2678,6 +2700,8 @@ static struct pci_device_id azx_ids[] = { | |||
2678 | { PCI_DEVICE(0x8086, 0x3a6e), .driver_data = AZX_DRIVER_ICH }, | 2700 | { PCI_DEVICE(0x8086, 0x3a6e), .driver_data = AZX_DRIVER_ICH }, |
2679 | /* PCH */ | 2701 | /* PCH */ |
2680 | { PCI_DEVICE(0x8086, 0x3b56), .driver_data = AZX_DRIVER_ICH }, | 2702 | { PCI_DEVICE(0x8086, 0x3b56), .driver_data = AZX_DRIVER_ICH }, |
2703 | /* CPT */ | ||
2704 | { PCI_DEVICE(0x8086, 0x1c20), .driver_data = AZX_DRIVER_PCH }, | ||
2681 | /* SCH */ | 2705 | /* SCH */ |
2682 | { PCI_DEVICE(0x8086, 0x811b), .driver_data = AZX_DRIVER_SCH }, | 2706 | { PCI_DEVICE(0x8086, 0x811b), .driver_data = AZX_DRIVER_SCH }, |
2683 | /* ATI SB 450/600 */ | 2707 | /* ATI SB 450/600 */ |
@@ -2705,32 +2729,10 @@ static struct pci_device_id azx_ids[] = { | |||
2705 | /* ULI M5461 */ | 2729 | /* ULI M5461 */ |
2706 | { PCI_DEVICE(0x10b9, 0x5461), .driver_data = AZX_DRIVER_ULI }, | 2730 | { PCI_DEVICE(0x10b9, 0x5461), .driver_data = AZX_DRIVER_ULI }, |
2707 | /* NVIDIA MCP */ | 2731 | /* NVIDIA MCP */ |
2708 | { PCI_DEVICE(0x10de, 0x026c), .driver_data = AZX_DRIVER_NVIDIA }, | 2732 | { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID), |
2709 | { PCI_DEVICE(0x10de, 0x0371), .driver_data = AZX_DRIVER_NVIDIA }, | 2733 | .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8, |
2710 | { PCI_DEVICE(0x10de, 0x03e4), .driver_data = AZX_DRIVER_NVIDIA }, | 2734 | .class_mask = 0xffffff, |
2711 | { PCI_DEVICE(0x10de, 0x03f0), .driver_data = AZX_DRIVER_NVIDIA }, | 2735 | .driver_data = AZX_DRIVER_NVIDIA }, |
2712 | { PCI_DEVICE(0x10de, 0x044a), .driver_data = AZX_DRIVER_NVIDIA }, | ||
2713 | { PCI_DEVICE(0x10de, 0x044b), .driver_data = AZX_DRIVER_NVIDIA }, | ||
2714 | { PCI_DEVICE(0x10de, 0x055c), .driver_data = AZX_DRIVER_NVIDIA }, | ||
2715 | { PCI_DEVICE(0x10de, 0x055d), .driver_data = AZX_DRIVER_NVIDIA }, | ||
2716 | { PCI_DEVICE(0x10de, 0x0590), .driver_data = AZX_DRIVER_NVIDIA }, | ||
2717 | { PCI_DEVICE(0x10de, 0x0774), .driver_data = AZX_DRIVER_NVIDIA }, | ||
2718 | { PCI_DEVICE(0x10de, 0x0775), .driver_data = AZX_DRIVER_NVIDIA }, | ||
2719 | { PCI_DEVICE(0x10de, 0x0776), .driver_data = AZX_DRIVER_NVIDIA }, | ||
2720 | { PCI_DEVICE(0x10de, 0x0777), .driver_data = AZX_DRIVER_NVIDIA }, | ||
2721 | { PCI_DEVICE(0x10de, 0x07fc), .driver_data = AZX_DRIVER_NVIDIA }, | ||
2722 | { PCI_DEVICE(0x10de, 0x07fd), .driver_data = AZX_DRIVER_NVIDIA }, | ||
2723 | { PCI_DEVICE(0x10de, 0x0ac0), .driver_data = AZX_DRIVER_NVIDIA }, | ||
2724 | { PCI_DEVICE(0x10de, 0x0ac1), .driver_data = AZX_DRIVER_NVIDIA }, | ||
2725 | { PCI_DEVICE(0x10de, 0x0ac2), .driver_data = AZX_DRIVER_NVIDIA }, | ||
2726 | { PCI_DEVICE(0x10de, 0x0ac3), .driver_data = AZX_DRIVER_NVIDIA }, | ||
2727 | { PCI_DEVICE(0x10de, 0x0be2), .driver_data = AZX_DRIVER_NVIDIA }, | ||
2728 | { PCI_DEVICE(0x10de, 0x0be3), .driver_data = AZX_DRIVER_NVIDIA }, | ||
2729 | { PCI_DEVICE(0x10de, 0x0be4), .driver_data = AZX_DRIVER_NVIDIA }, | ||
2730 | { PCI_DEVICE(0x10de, 0x0d94), .driver_data = AZX_DRIVER_NVIDIA }, | ||
2731 | { PCI_DEVICE(0x10de, 0x0d95), .driver_data = AZX_DRIVER_NVIDIA }, | ||
2732 | { PCI_DEVICE(0x10de, 0x0d96), .driver_data = AZX_DRIVER_NVIDIA }, | ||
2733 | { PCI_DEVICE(0x10de, 0x0d97), .driver_data = AZX_DRIVER_NVIDIA }, | ||
2734 | /* Teradici */ | 2736 | /* Teradici */ |
2735 | { PCI_DEVICE(0x6549, 0x1200), .driver_data = AZX_DRIVER_TERA }, | 2737 | { PCI_DEVICE(0x6549, 0x1200), .driver_data = AZX_DRIVER_TERA }, |
2736 | /* Creative X-Fi (CA0110-IBG) */ | 2738 | /* Creative X-Fi (CA0110-IBG) */ |
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 5778ae882b83..7cee364976ff 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h | |||
@@ -31,6 +31,7 @@ | |||
31 | * in snd_hda_ctl_add(), so that this value won't appear in the outside. | 31 | * in snd_hda_ctl_add(), so that this value won't appear in the outside. |
32 | */ | 32 | */ |
33 | #define HDA_SUBDEV_NID_FLAG (1U << 31) | 33 | #define HDA_SUBDEV_NID_FLAG (1U << 31) |
34 | #define HDA_SUBDEV_AMP_FLAG (1U << 30) | ||
34 | 35 | ||
35 | /* | 36 | /* |
36 | * for mixer controls | 37 | * for mixer controls |
@@ -42,7 +43,7 @@ | |||
42 | /* mono volume with index (index=0,1,...) (channel=1,2) */ | 43 | /* mono volume with index (index=0,1,...) (channel=1,2) */ |
43 | #define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ | 44 | #define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ |
44 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \ | 45 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \ |
45 | .subdevice = HDA_SUBDEV_NID_FLAG | (nid), \ | 46 | .subdevice = HDA_SUBDEV_AMP_FLAG, \ |
46 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ | 47 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ |
47 | SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ | 48 | SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ |
48 | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, \ | 49 | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, \ |
@@ -63,7 +64,7 @@ | |||
63 | /* mono mute switch with index (index=0,1,...) (channel=1,2) */ | 64 | /* mono mute switch with index (index=0,1,...) (channel=1,2) */ |
64 | #define HDA_CODEC_MUTE_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ | 65 | #define HDA_CODEC_MUTE_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ |
65 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \ | 66 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \ |
66 | .subdevice = HDA_SUBDEV_NID_FLAG | (nid), \ | 67 | .subdevice = HDA_SUBDEV_AMP_FLAG, \ |
67 | .info = snd_hda_mixer_amp_switch_info, \ | 68 | .info = snd_hda_mixer_amp_switch_info, \ |
68 | .get = snd_hda_mixer_amp_switch_get, \ | 69 | .get = snd_hda_mixer_amp_switch_get, \ |
69 | .put = snd_hda_mixer_amp_switch_put, \ | 70 | .put = snd_hda_mixer_amp_switch_put, \ |
@@ -81,7 +82,7 @@ | |||
81 | /* special beep mono mute switch with index (index=0,1,...) (channel=1,2) */ | 82 | /* special beep mono mute switch with index (index=0,1,...) (channel=1,2) */ |
82 | #define HDA_CODEC_MUTE_BEEP_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ | 83 | #define HDA_CODEC_MUTE_BEEP_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ |
83 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \ | 84 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \ |
84 | .subdevice = HDA_SUBDEV_NID_FLAG | (nid), \ | 85 | .subdevice = HDA_SUBDEV_AMP_FLAG, \ |
85 | .info = snd_hda_mixer_amp_switch_info, \ | 86 | .info = snd_hda_mixer_amp_switch_info, \ |
86 | .get = snd_hda_mixer_amp_switch_get, \ | 87 | .get = snd_hda_mixer_amp_switch_get, \ |
87 | .put = snd_hda_mixer_amp_switch_put_beep, \ | 88 | .put = snd_hda_mixer_amp_switch_put_beep, \ |
@@ -464,13 +465,20 @@ u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid); | |||
464 | u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid); | 465 | u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid); |
465 | int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid); | 466 | int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid); |
466 | 467 | ||
468 | /* flags for hda_nid_item */ | ||
469 | #define HDA_NID_ITEM_AMP (1<<0) | ||
470 | |||
467 | struct hda_nid_item { | 471 | struct hda_nid_item { |
468 | struct snd_kcontrol *kctl; | 472 | struct snd_kcontrol *kctl; |
473 | unsigned int index; | ||
469 | hda_nid_t nid; | 474 | hda_nid_t nid; |
475 | unsigned short flags; | ||
470 | }; | 476 | }; |
471 | 477 | ||
472 | int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid, | 478 | int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid, |
473 | struct snd_kcontrol *kctl); | 479 | struct snd_kcontrol *kctl); |
480 | int snd_hda_add_nid(struct hda_codec *codec, struct snd_kcontrol *kctl, | ||
481 | unsigned int index, hda_nid_t nid); | ||
474 | void snd_hda_ctls_clear(struct hda_codec *codec); | 482 | void snd_hda_ctls_clear(struct hda_codec *codec); |
475 | 483 | ||
476 | /* | 484 | /* |
diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index c9afc04adac8..f97d35de66c4 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c | |||
@@ -61,18 +61,29 @@ static const char *get_wid_type_name(unsigned int wid_value) | |||
61 | return "UNKNOWN Widget"; | 61 | return "UNKNOWN Widget"; |
62 | } | 62 | } |
63 | 63 | ||
64 | static void print_nid_mixers(struct snd_info_buffer *buffer, | 64 | static void print_nid_array(struct snd_info_buffer *buffer, |
65 | struct hda_codec *codec, hda_nid_t nid) | 65 | struct hda_codec *codec, hda_nid_t nid, |
66 | struct snd_array *array) | ||
66 | { | 67 | { |
67 | int i; | 68 | int i; |
68 | struct hda_nid_item *items = codec->mixers.list; | 69 | struct hda_nid_item *items = array->list, *item; |
69 | struct snd_kcontrol *kctl; | 70 | struct snd_kcontrol *kctl; |
70 | for (i = 0; i < codec->mixers.used; i++) { | 71 | for (i = 0; i < array->used; i++) { |
71 | if (items[i].nid == nid) { | 72 | item = &items[i]; |
72 | kctl = items[i].kctl; | 73 | if (item->nid == nid) { |
74 | kctl = item->kctl; | ||
73 | snd_iprintf(buffer, | 75 | snd_iprintf(buffer, |
74 | " Control: name=\"%s\", index=%i, device=%i\n", | 76 | " Control: name=\"%s\", index=%i, device=%i\n", |
75 | kctl->id.name, kctl->id.index, kctl->id.device); | 77 | kctl->id.name, kctl->id.index + item->index, |
78 | kctl->id.device); | ||
79 | if (item->flags & HDA_NID_ITEM_AMP) | ||
80 | snd_iprintf(buffer, | ||
81 | " ControlAmp: chs=%lu, dir=%s, " | ||
82 | "idx=%lu, ofs=%lu\n", | ||
83 | get_amp_channels(kctl), | ||
84 | get_amp_direction(kctl) ? "Out" : "In", | ||
85 | get_amp_index(kctl), | ||
86 | get_amp_offset(kctl)); | ||
76 | } | 87 | } |
77 | } | 88 | } |
78 | } | 89 | } |
@@ -528,7 +539,8 @@ static void print_gpio(struct snd_info_buffer *buffer, | |||
528 | (data & (1<<i)) ? 1 : 0, | 539 | (data & (1<<i)) ? 1 : 0, |
529 | (unsol & (1<<i)) ? 1 : 0); | 540 | (unsol & (1<<i)) ? 1 : 0); |
530 | /* FIXME: add GPO and GPI pin information */ | 541 | /* FIXME: add GPO and GPI pin information */ |
531 | print_nid_mixers(buffer, codec, nid); | 542 | print_nid_array(buffer, codec, nid, &codec->mixers); |
543 | print_nid_array(buffer, codec, nid, &codec->nids); | ||
532 | } | 544 | } |
533 | 545 | ||
534 | static void print_codec_info(struct snd_info_entry *entry, | 546 | static void print_codec_info(struct snd_info_entry *entry, |
@@ -608,7 +620,8 @@ static void print_codec_info(struct snd_info_entry *entry, | |||
608 | snd_iprintf(buffer, " CP"); | 620 | snd_iprintf(buffer, " CP"); |
609 | snd_iprintf(buffer, "\n"); | 621 | snd_iprintf(buffer, "\n"); |
610 | 622 | ||
611 | print_nid_mixers(buffer, codec, nid); | 623 | print_nid_array(buffer, codec, nid, &codec->mixers); |
624 | print_nid_array(buffer, codec, nid, &codec->nids); | ||
612 | print_nid_pcms(buffer, codec, nid); | 625 | print_nid_pcms(buffer, codec, nid); |
613 | 626 | ||
614 | /* volume knob is a special widget that always have connection | 627 | /* volume knob is a special widget that always have connection |
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 69a941c7b158..e6d1bdff1b6e 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c | |||
@@ -174,6 +174,7 @@ static struct snd_kcontrol_new ad_beep_mixer[] = { | |||
174 | static int ad198x_build_controls(struct hda_codec *codec) | 174 | static int ad198x_build_controls(struct hda_codec *codec) |
175 | { | 175 | { |
176 | struct ad198x_spec *spec = codec->spec; | 176 | struct ad198x_spec *spec = codec->spec; |
177 | struct snd_kcontrol *kctl; | ||
177 | unsigned int i; | 178 | unsigned int i; |
178 | int err; | 179 | int err; |
179 | 180 | ||
@@ -208,9 +209,7 @@ static int ad198x_build_controls(struct hda_codec *codec) | |||
208 | if (!kctl) | 209 | if (!kctl) |
209 | return -ENOMEM; | 210 | return -ENOMEM; |
210 | kctl->private_value = spec->beep_amp; | 211 | kctl->private_value = spec->beep_amp; |
211 | err = snd_hda_ctl_add(codec, | 212 | err = snd_hda_ctl_add(codec, 0, kctl); |
212 | get_amp_nid_(spec->beep_amp), | ||
213 | kctl); | ||
214 | if (err < 0) | 213 | if (err < 0) |
215 | return err; | 214 | return err; |
216 | } | 215 | } |
@@ -239,6 +238,27 @@ static int ad198x_build_controls(struct hda_codec *codec) | |||
239 | } | 238 | } |
240 | 239 | ||
241 | ad198x_free_kctls(codec); /* no longer needed */ | 240 | ad198x_free_kctls(codec); /* no longer needed */ |
241 | |||
242 | /* assign Capture Source enums to NID */ | ||
243 | kctl = snd_hda_find_mixer_ctl(codec, "Capture Source"); | ||
244 | if (!kctl) | ||
245 | kctl = snd_hda_find_mixer_ctl(codec, "Input Source"); | ||
246 | for (i = 0; kctl && i < kctl->count; i++) { | ||
247 | err = snd_hda_add_nid(codec, kctl, i, spec->capsrc_nids[i]); | ||
248 | if (err < 0) | ||
249 | return err; | ||
250 | } | ||
251 | |||
252 | /* assign IEC958 enums to NID */ | ||
253 | kctl = snd_hda_find_mixer_ctl(codec, | ||
254 | SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source"); | ||
255 | if (kctl) { | ||
256 | err = snd_hda_add_nid(codec, kctl, 0, | ||
257 | spec->multiout.dig_out_nid); | ||
258 | if (err < 0) | ||
259 | return err; | ||
260 | } | ||
261 | |||
242 | return 0; | 262 | return 0; |
243 | } | 263 | } |
244 | 264 | ||
@@ -421,6 +441,11 @@ static int ad198x_build_pcms(struct hda_codec *codec) | |||
421 | return 0; | 441 | return 0; |
422 | } | 442 | } |
423 | 443 | ||
444 | static inline void ad198x_shutup(struct hda_codec *codec) | ||
445 | { | ||
446 | snd_hda_shutup_pins(codec); | ||
447 | } | ||
448 | |||
424 | static void ad198x_free_kctls(struct hda_codec *codec) | 449 | static void ad198x_free_kctls(struct hda_codec *codec) |
425 | { | 450 | { |
426 | struct ad198x_spec *spec = codec->spec; | 451 | struct ad198x_spec *spec = codec->spec; |
@@ -434,6 +459,46 @@ static void ad198x_free_kctls(struct hda_codec *codec) | |||
434 | snd_array_free(&spec->kctls); | 459 | snd_array_free(&spec->kctls); |
435 | } | 460 | } |
436 | 461 | ||
462 | static void ad198x_power_eapd_write(struct hda_codec *codec, hda_nid_t front, | ||
463 | hda_nid_t hp) | ||
464 | { | ||
465 | struct ad198x_spec *spec = codec->spec; | ||
466 | snd_hda_codec_write(codec, front, 0, AC_VERB_SET_EAPD_BTLENABLE, | ||
467 | !spec->inv_eapd ? 0x00 : 0x02); | ||
468 | snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_EAPD_BTLENABLE, | ||
469 | !spec->inv_eapd ? 0x00 : 0x02); | ||
470 | } | ||
471 | |||
472 | static void ad198x_power_eapd(struct hda_codec *codec) | ||
473 | { | ||
474 | /* We currently only handle front, HP */ | ||
475 | switch (codec->vendor_id) { | ||
476 | case 0x11d41882: | ||
477 | case 0x11d4882a: | ||
478 | case 0x11d41884: | ||
479 | case 0x11d41984: | ||
480 | case 0x11d41883: | ||
481 | case 0x11d4184a: | ||
482 | case 0x11d4194a: | ||
483 | case 0x11d4194b: | ||
484 | ad198x_power_eapd_write(codec, 0x12, 0x11); | ||
485 | break; | ||
486 | case 0x11d41981: | ||
487 | case 0x11d41983: | ||
488 | ad198x_power_eapd_write(codec, 0x05, 0x06); | ||
489 | break; | ||
490 | case 0x11d41986: | ||
491 | ad198x_power_eapd_write(codec, 0x1b, 0x1a); | ||
492 | break; | ||
493 | case 0x11d41988: | ||
494 | case 0x11d4198b: | ||
495 | case 0x11d4989a: | ||
496 | case 0x11d4989b: | ||
497 | ad198x_power_eapd_write(codec, 0x29, 0x22); | ||
498 | break; | ||
499 | } | ||
500 | } | ||
501 | |||
437 | static void ad198x_free(struct hda_codec *codec) | 502 | static void ad198x_free(struct hda_codec *codec) |
438 | { | 503 | { |
439 | struct ad198x_spec *spec = codec->spec; | 504 | struct ad198x_spec *spec = codec->spec; |
@@ -441,11 +506,29 @@ static void ad198x_free(struct hda_codec *codec) | |||
441 | if (!spec) | 506 | if (!spec) |
442 | return; | 507 | return; |
443 | 508 | ||
509 | ad198x_shutup(codec); | ||
444 | ad198x_free_kctls(codec); | 510 | ad198x_free_kctls(codec); |
445 | kfree(spec); | 511 | kfree(spec); |
446 | snd_hda_detach_beep_device(codec); | 512 | snd_hda_detach_beep_device(codec); |
447 | } | 513 | } |
448 | 514 | ||
515 | #ifdef SND_HDA_NEEDS_RESUME | ||
516 | static int ad198x_suspend(struct hda_codec *codec, pm_message_t state) | ||
517 | { | ||
518 | ad198x_shutup(codec); | ||
519 | ad198x_power_eapd(codec); | ||
520 | return 0; | ||
521 | } | ||
522 | |||
523 | static int ad198x_resume(struct hda_codec *codec) | ||
524 | { | ||
525 | ad198x_init(codec); | ||
526 | snd_hda_codec_resume_amp(codec); | ||
527 | snd_hda_codec_resume_cache(codec); | ||
528 | return 0; | ||
529 | } | ||
530 | #endif | ||
531 | |||
449 | static struct hda_codec_ops ad198x_patch_ops = { | 532 | static struct hda_codec_ops ad198x_patch_ops = { |
450 | .build_controls = ad198x_build_controls, | 533 | .build_controls = ad198x_build_controls, |
451 | .build_pcms = ad198x_build_pcms, | 534 | .build_pcms = ad198x_build_pcms, |
@@ -454,6 +537,11 @@ static struct hda_codec_ops ad198x_patch_ops = { | |||
454 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 537 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
455 | .check_power_status = ad198x_check_power_status, | 538 | .check_power_status = ad198x_check_power_status, |
456 | #endif | 539 | #endif |
540 | #ifdef SND_HDA_NEEDS_RESUME | ||
541 | .suspend = ad198x_suspend, | ||
542 | .resume = ad198x_resume, | ||
543 | #endif | ||
544 | .reboot_notify = ad198x_shutup, | ||
457 | }; | 545 | }; |
458 | 546 | ||
459 | 547 | ||
@@ -701,6 +789,7 @@ static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = { | |||
701 | { | 789 | { |
702 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 790 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
703 | .name = "External Amplifier", | 791 | .name = "External Amplifier", |
792 | .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b, | ||
704 | .info = ad198x_eapd_info, | 793 | .info = ad198x_eapd_info, |
705 | .get = ad198x_eapd_get, | 794 | .get = ad198x_eapd_get, |
706 | .put = ad198x_eapd_put, | 795 | .put = ad198x_eapd_put, |
@@ -808,6 +897,7 @@ static struct snd_kcontrol_new ad1986a_automute_master_mixers[] = { | |||
808 | { | 897 | { |
809 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 898 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
810 | .name = "Master Playback Switch", | 899 | .name = "Master Playback Switch", |
900 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
811 | .info = snd_hda_mixer_amp_switch_info, | 901 | .info = snd_hda_mixer_amp_switch_info, |
812 | .get = snd_hda_mixer_amp_switch_get, | 902 | .get = snd_hda_mixer_amp_switch_get, |
813 | .put = ad1986a_hp_master_sw_put, | 903 | .put = ad1986a_hp_master_sw_put, |
@@ -1008,7 +1098,7 @@ static struct snd_pci_quirk ad1986a_cfg_tbl[] = { | |||
1008 | SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS M2N", AD1986A_3STACK), | 1098 | SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS M2N", AD1986A_3STACK), |
1009 | SND_PCI_QUIRK(0x1043, 0x8234, "ASUS M2N", AD1986A_3STACK), | 1099 | SND_PCI_QUIRK(0x1043, 0x8234, "ASUS M2N", AD1986A_3STACK), |
1010 | SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_3STACK), | 1100 | SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_3STACK), |
1011 | SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba", AD1986A_LAPTOP_EAPD), | 1101 | SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba Satellite L40-10Q", AD1986A_3STACK), |
1012 | SND_PCI_QUIRK(0x144d, 0xb03c, "Samsung R55", AD1986A_3STACK), | 1102 | SND_PCI_QUIRK(0x144d, 0xb03c, "Samsung R55", AD1986A_3STACK), |
1013 | SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP), | 1103 | SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP), |
1014 | SND_PCI_QUIRK(0x144d, 0xc024, "Samsung P50", AD1986A_SAMSUNG_P50), | 1104 | SND_PCI_QUIRK(0x144d, 0xc024, "Samsung P50", AD1986A_SAMSUNG_P50), |
@@ -1612,6 +1702,7 @@ static struct snd_kcontrol_new ad1981_hp_mixers[] = { | |||
1612 | HDA_BIND_VOL("Master Playback Volume", &ad1981_hp_bind_master_vol), | 1702 | HDA_BIND_VOL("Master Playback Volume", &ad1981_hp_bind_master_vol), |
1613 | { | 1703 | { |
1614 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1704 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1705 | .subdevice = HDA_SUBDEV_NID_FLAG | 0x05, | ||
1615 | .name = "Master Playback Switch", | 1706 | .name = "Master Playback Switch", |
1616 | .info = ad198x_eapd_info, | 1707 | .info = ad198x_eapd_info, |
1617 | .get = ad198x_eapd_get, | 1708 | .get = ad198x_eapd_get, |
@@ -2136,6 +2227,7 @@ static struct snd_kcontrol_new ad1988_laptop_mixers[] = { | |||
2136 | { | 2227 | { |
2137 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2228 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
2138 | .name = "External Amplifier", | 2229 | .name = "External Amplifier", |
2230 | .subdevice = HDA_SUBDEV_NID_FLAG | 0x12, | ||
2139 | .info = ad198x_eapd_info, | 2231 | .info = ad198x_eapd_info, |
2140 | .get = ad198x_eapd_get, | 2232 | .get = ad198x_eapd_get, |
2141 | .put = ad198x_eapd_put, | 2233 | .put = ad198x_eapd_put, |
@@ -2257,6 +2349,7 @@ static struct snd_kcontrol_new ad1988_spdif_out_mixers[] = { | |||
2257 | { | 2349 | { |
2258 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2350 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
2259 | .name = "IEC958 Playback Source", | 2351 | .name = "IEC958 Playback Source", |
2352 | .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b, | ||
2260 | .info = ad1988_spdif_playback_source_info, | 2353 | .info = ad1988_spdif_playback_source_info, |
2261 | .get = ad1988_spdif_playback_source_get, | 2354 | .get = ad1988_spdif_playback_source_get, |
2262 | .put = ad1988_spdif_playback_source_put, | 2355 | .put = ad1988_spdif_playback_source_put, |
@@ -2372,6 +2465,12 @@ static struct hda_verb ad1988_spdif_init_verbs[] = { | |||
2372 | { } | 2465 | { } |
2373 | }; | 2466 | }; |
2374 | 2467 | ||
2468 | static struct hda_verb ad1988_spdif_in_init_verbs[] = { | ||
2469 | /* unmute SPDIF input pin */ | ||
2470 | {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
2471 | { } | ||
2472 | }; | ||
2473 | |||
2375 | /* AD1989 has no ADC -> SPDIF route */ | 2474 | /* AD1989 has no ADC -> SPDIF route */ |
2376 | static struct hda_verb ad1989_spdif_init_verbs[] = { | 2475 | static struct hda_verb ad1989_spdif_init_verbs[] = { |
2377 | /* SPDIF-1 out pin */ | 2476 | /* SPDIF-1 out pin */ |
@@ -2589,7 +2688,7 @@ static int add_control(struct ad198x_spec *spec, int type, const char *name, | |||
2589 | if (! knew->name) | 2688 | if (! knew->name) |
2590 | return -ENOMEM; | 2689 | return -ENOMEM; |
2591 | if (get_amp_nid_(val)) | 2690 | if (get_amp_nid_(val)) |
2592 | knew->subdevice = HDA_SUBDEV_NID_FLAG | get_amp_nid_(val); | 2691 | knew->subdevice = HDA_SUBDEV_AMP_FLAG; |
2593 | knew->private_value = val; | 2692 | knew->private_value = val; |
2594 | return 0; | 2693 | return 0; |
2595 | } | 2694 | } |
@@ -3107,8 +3206,11 @@ static int patch_ad1988(struct hda_codec *codec) | |||
3107 | ad1988_spdif_init_verbs; | 3206 | ad1988_spdif_init_verbs; |
3108 | } | 3207 | } |
3109 | } | 3208 | } |
3110 | if (spec->dig_in_nid && codec->vendor_id < 0x11d4989a) | 3209 | if (spec->dig_in_nid && codec->vendor_id < 0x11d4989a) { |
3111 | spec->mixers[spec->num_mixers++] = ad1988_spdif_in_mixers; | 3210 | spec->mixers[spec->num_mixers++] = ad1988_spdif_in_mixers; |
3211 | spec->init_verbs[spec->num_init_verbs++] = | ||
3212 | ad1988_spdif_in_init_verbs; | ||
3213 | } | ||
3112 | 3214 | ||
3113 | codec->patch_ops = ad198x_patch_ops; | 3215 | codec->patch_ops = ad198x_patch_ops; |
3114 | switch (board_config) { | 3216 | switch (board_config) { |
@@ -3747,6 +3849,7 @@ static struct snd_kcontrol_new ad1884a_laptop_mixers[] = { | |||
3747 | { | 3849 | { |
3748 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 3850 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
3749 | .name = "Master Playback Switch", | 3851 | .name = "Master Playback Switch", |
3852 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
3750 | .info = snd_hda_mixer_amp_switch_info, | 3853 | .info = snd_hda_mixer_amp_switch_info, |
3751 | .get = snd_hda_mixer_amp_switch_get, | 3854 | .get = snd_hda_mixer_amp_switch_get, |
3752 | .put = ad1884a_mobile_master_sw_put, | 3855 | .put = ad1884a_mobile_master_sw_put, |
@@ -3775,6 +3878,7 @@ static struct snd_kcontrol_new ad1884a_mobile_mixers[] = { | |||
3775 | { | 3878 | { |
3776 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 3879 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
3777 | .name = "Master Playback Switch", | 3880 | .name = "Master Playback Switch", |
3881 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
3778 | .info = snd_hda_mixer_amp_switch_info, | 3882 | .info = snd_hda_mixer_amp_switch_info, |
3779 | .get = snd_hda_mixer_amp_switch_get, | 3883 | .get = snd_hda_mixer_amp_switch_get, |
3780 | .put = ad1884a_mobile_master_sw_put, | 3884 | .put = ad1884a_mobile_master_sw_put, |
@@ -4116,6 +4220,7 @@ static struct snd_kcontrol_new ad1984a_touchsmart_mixers[] = { | |||
4116 | /* HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/ | 4220 | /* HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/ |
4117 | { | 4221 | { |
4118 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 4222 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
4223 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
4119 | .name = "Master Playback Switch", | 4224 | .name = "Master Playback Switch", |
4120 | .info = snd_hda_mixer_amp_switch_info, | 4225 | .info = snd_hda_mixer_amp_switch_info, |
4121 | .get = snd_hda_mixer_amp_switch_get, | 4226 | .get = snd_hda_mixer_amp_switch_get, |
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index fe0423c39598..7de782a5b8f4 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c | |||
@@ -501,7 +501,8 @@ static int add_mute(struct hda_codec *codec, const char *name, int index, | |||
501 | knew.private_value = pval; | 501 | knew.private_value = pval; |
502 | snprintf(tmp, sizeof(tmp), "%s %s Switch", name, dir_sfx[dir]); | 502 | snprintf(tmp, sizeof(tmp), "%s %s Switch", name, dir_sfx[dir]); |
503 | *kctlp = snd_ctl_new1(&knew, codec); | 503 | *kctlp = snd_ctl_new1(&knew, codec); |
504 | return snd_hda_ctl_add(codec, get_amp_nid_(pval), *kctlp); | 504 | (*kctlp)->id.subdevice = HDA_SUBDEV_AMP_FLAG; |
505 | return snd_hda_ctl_add(codec, 0, *kctlp); | ||
505 | } | 506 | } |
506 | 507 | ||
507 | static int add_volume(struct hda_codec *codec, const char *name, | 508 | static int add_volume(struct hda_codec *codec, const char *name, |
@@ -514,7 +515,8 @@ static int add_volume(struct hda_codec *codec, const char *name, | |||
514 | knew.private_value = pval; | 515 | knew.private_value = pval; |
515 | snprintf(tmp, sizeof(tmp), "%s %s Volume", name, dir_sfx[dir]); | 516 | snprintf(tmp, sizeof(tmp), "%s %s Volume", name, dir_sfx[dir]); |
516 | *kctlp = snd_ctl_new1(&knew, codec); | 517 | *kctlp = snd_ctl_new1(&knew, codec); |
517 | return snd_hda_ctl_add(codec, get_amp_nid_(pval), *kctlp); | 518 | (*kctlp)->id.subdevice = HDA_SUBDEV_AMP_FLAG; |
519 | return snd_hda_ctl_add(codec, 0, *kctlp); | ||
518 | } | 520 | } |
519 | 521 | ||
520 | static void fix_volume_caps(struct hda_codec *codec, hda_nid_t dac) | 522 | static void fix_volume_caps(struct hda_codec *codec, hda_nid_t dac) |
@@ -751,6 +753,7 @@ static int build_input(struct hda_codec *codec) | |||
751 | spec->capture_bind[1] = make_bind_capture(codec, &snd_hda_bind_vol); | 753 | spec->capture_bind[1] = make_bind_capture(codec, &snd_hda_bind_vol); |
752 | for (i = 0; i < 2; i++) { | 754 | for (i = 0; i < 2; i++) { |
753 | struct snd_kcontrol *kctl; | 755 | struct snd_kcontrol *kctl; |
756 | int n; | ||
754 | if (!spec->capture_bind[i]) | 757 | if (!spec->capture_bind[i]) |
755 | return -ENOMEM; | 758 | return -ENOMEM; |
756 | kctl = snd_ctl_new1(&cs_capture_ctls[i], codec); | 759 | kctl = snd_ctl_new1(&cs_capture_ctls[i], codec); |
@@ -760,6 +763,13 @@ static int build_input(struct hda_codec *codec) | |||
760 | err = snd_hda_ctl_add(codec, 0, kctl); | 763 | err = snd_hda_ctl_add(codec, 0, kctl); |
761 | if (err < 0) | 764 | if (err < 0) |
762 | return err; | 765 | return err; |
766 | for (n = 0; n < AUTO_PIN_LAST; n++) { | ||
767 | if (!spec->adc_nid[n]) | ||
768 | continue; | ||
769 | err = snd_hda_add_nid(codec, kctl, 0, spec->adc_nid[i]); | ||
770 | if (err < 0) | ||
771 | return err; | ||
772 | } | ||
763 | } | 773 | } |
764 | 774 | ||
765 | if (spec->num_inputs > 1 && !spec->mic_detect) { | 775 | if (spec->num_inputs > 1 && !spec->mic_detect) { |
diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c index a45c1169762b..ff60908f4554 100644 --- a/sound/pci/hda/patch_cmedia.c +++ b/sound/pci/hda/patch_cmedia.c | |||
@@ -315,7 +315,8 @@ static struct hda_verb cmi9880_allout_init[] = { | |||
315 | static int cmi9880_build_controls(struct hda_codec *codec) | 315 | static int cmi9880_build_controls(struct hda_codec *codec) |
316 | { | 316 | { |
317 | struct cmi_spec *spec = codec->spec; | 317 | struct cmi_spec *spec = codec->spec; |
318 | int err; | 318 | struct snd_kcontrol *kctl; |
319 | int i, err; | ||
319 | 320 | ||
320 | err = snd_hda_add_new_ctls(codec, cmi9880_basic_mixer); | 321 | err = snd_hda_add_new_ctls(codec, cmi9880_basic_mixer); |
321 | if (err < 0) | 322 | if (err < 0) |
@@ -340,6 +341,14 @@ static int cmi9880_build_controls(struct hda_codec *codec) | |||
340 | if (err < 0) | 341 | if (err < 0) |
341 | return err; | 342 | return err; |
342 | } | 343 | } |
344 | |||
345 | /* assign Capture Source enums to NID */ | ||
346 | kctl = snd_hda_find_mixer_ctl(codec, "Capture Source"); | ||
347 | for (i = 0; kctl && i < kctl->count; i++) { | ||
348 | err = snd_hda_add_nid(codec, kctl, i, spec->adc_nids[i]); | ||
349 | if (err < 0) | ||
350 | return err; | ||
351 | } | ||
343 | return 0; | 352 | return 0; |
344 | } | 353 | } |
345 | 354 | ||
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index c578c28f368e..194a28c54992 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c | |||
@@ -42,10 +42,12 @@ | |||
42 | 42 | ||
43 | /* Conexant 5051 specific */ | 43 | /* Conexant 5051 specific */ |
44 | 44 | ||
45 | #define CXT5051_SPDIF_OUT 0x1C | 45 | #define CXT5051_SPDIF_OUT 0x12 |
46 | #define CXT5051_PORTB_EVENT 0x38 | 46 | #define CXT5051_PORTB_EVENT 0x38 |
47 | #define CXT5051_PORTC_EVENT 0x39 | 47 | #define CXT5051_PORTC_EVENT 0x39 |
48 | 48 | ||
49 | #define AUTO_MIC_PORTB (1 << 1) | ||
50 | #define AUTO_MIC_PORTC (1 << 2) | ||
49 | 51 | ||
50 | struct conexant_jack { | 52 | struct conexant_jack { |
51 | 53 | ||
@@ -74,7 +76,7 @@ struct conexant_spec { | |||
74 | */ | 76 | */ |
75 | unsigned int cur_eapd; | 77 | unsigned int cur_eapd; |
76 | unsigned int hp_present; | 78 | unsigned int hp_present; |
77 | unsigned int no_auto_mic; | 79 | unsigned int auto_mic; |
78 | unsigned int need_dac_fix; | 80 | unsigned int need_dac_fix; |
79 | 81 | ||
80 | /* capture */ | 82 | /* capture */ |
@@ -111,8 +113,23 @@ struct conexant_spec { | |||
111 | 113 | ||
112 | unsigned int dell_automute; | 114 | unsigned int dell_automute; |
113 | unsigned int port_d_mode; | 115 | unsigned int port_d_mode; |
114 | unsigned char ext_mic_bias; | 116 | unsigned int dell_vostro:1; |
115 | unsigned int dell_vostro; | 117 | unsigned int ideapad:1; |
118 | |||
119 | unsigned int ext_mic_present; | ||
120 | unsigned int recording; | ||
121 | void (*capture_prepare)(struct hda_codec *codec); | ||
122 | void (*capture_cleanup)(struct hda_codec *codec); | ||
123 | |||
124 | /* OLPC XO-1.5 supports DC input mode (e.g. for use with analog sensors) | ||
125 | * through the microphone jack. | ||
126 | * When the user enables this through a mixer switch, both internal and | ||
127 | * external microphones are disabled. Gain is fixed at 0dB. In this mode, | ||
128 | * we also allow the bias to be configured through a separate mixer | ||
129 | * control. */ | ||
130 | unsigned int dc_enable; | ||
131 | unsigned int dc_input_bias; /* offset into cxt5066_olpc_dc_bias */ | ||
132 | unsigned int mic_boost; /* offset into cxt5066_analog_mic_boost */ | ||
116 | }; | 133 | }; |
117 | 134 | ||
118 | static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo, | 135 | static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo, |
@@ -185,6 +202,8 @@ static int conexant_capture_pcm_prepare(struct hda_pcm_stream *hinfo, | |||
185 | struct snd_pcm_substream *substream) | 202 | struct snd_pcm_substream *substream) |
186 | { | 203 | { |
187 | struct conexant_spec *spec = codec->spec; | 204 | struct conexant_spec *spec = codec->spec; |
205 | if (spec->capture_prepare) | ||
206 | spec->capture_prepare(codec); | ||
188 | snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], | 207 | snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], |
189 | stream_tag, 0, format); | 208 | stream_tag, 0, format); |
190 | return 0; | 209 | return 0; |
@@ -196,6 +215,8 @@ static int conexant_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, | |||
196 | { | 215 | { |
197 | struct conexant_spec *spec = codec->spec; | 216 | struct conexant_spec *spec = codec->spec; |
198 | snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]); | 217 | snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]); |
218 | if (spec->capture_cleanup) | ||
219 | spec->capture_cleanup(codec); | ||
199 | return 0; | 220 | return 0; |
200 | } | 221 | } |
201 | 222 | ||
@@ -1585,6 +1606,11 @@ static void cxt5051_update_speaker(struct hda_codec *codec) | |||
1585 | { | 1606 | { |
1586 | struct conexant_spec *spec = codec->spec; | 1607 | struct conexant_spec *spec = codec->spec; |
1587 | unsigned int pinctl; | 1608 | unsigned int pinctl; |
1609 | /* headphone pin */ | ||
1610 | pinctl = (spec->hp_present && spec->cur_eapd) ? PIN_HP : 0; | ||
1611 | snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
1612 | pinctl); | ||
1613 | /* speaker pin */ | ||
1588 | pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0; | 1614 | pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0; |
1589 | snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, | 1615 | snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, |
1590 | pinctl); | 1616 | pinctl); |
@@ -1608,7 +1634,7 @@ static void cxt5051_portb_automic(struct hda_codec *codec) | |||
1608 | struct conexant_spec *spec = codec->spec; | 1634 | struct conexant_spec *spec = codec->spec; |
1609 | unsigned int present; | 1635 | unsigned int present; |
1610 | 1636 | ||
1611 | if (spec->no_auto_mic) | 1637 | if (!(spec->auto_mic & AUTO_MIC_PORTB)) |
1612 | return; | 1638 | return; |
1613 | present = snd_hda_jack_detect(codec, 0x17); | 1639 | present = snd_hda_jack_detect(codec, 0x17); |
1614 | snd_hda_codec_write(codec, 0x14, 0, | 1640 | snd_hda_codec_write(codec, 0x14, 0, |
@@ -1623,7 +1649,7 @@ static void cxt5051_portc_automic(struct hda_codec *codec) | |||
1623 | unsigned int present; | 1649 | unsigned int present; |
1624 | hda_nid_t new_adc; | 1650 | hda_nid_t new_adc; |
1625 | 1651 | ||
1626 | if (spec->no_auto_mic) | 1652 | if (!(spec->auto_mic & AUTO_MIC_PORTC)) |
1627 | return; | 1653 | return; |
1628 | present = snd_hda_jack_detect(codec, 0x18); | 1654 | present = snd_hda_jack_detect(codec, 0x18); |
1629 | if (present) | 1655 | if (present) |
@@ -1669,13 +1695,7 @@ static void cxt5051_hp_unsol_event(struct hda_codec *codec, | |||
1669 | conexant_report_jack(codec, nid); | 1695 | conexant_report_jack(codec, nid); |
1670 | } | 1696 | } |
1671 | 1697 | ||
1672 | static struct snd_kcontrol_new cxt5051_mixers[] = { | 1698 | static struct snd_kcontrol_new cxt5051_playback_mixers[] = { |
1673 | HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT), | ||
1674 | HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT), | ||
1675 | HDA_CODEC_VOLUME("External Mic Volume", 0x14, 0x01, HDA_INPUT), | ||
1676 | HDA_CODEC_MUTE("External Mic Switch", 0x14, 0x01, HDA_INPUT), | ||
1677 | HDA_CODEC_VOLUME("Docking Mic Volume", 0x15, 0x00, HDA_INPUT), | ||
1678 | HDA_CODEC_MUTE("Docking Mic Switch", 0x15, 0x00, HDA_INPUT), | ||
1679 | HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT), | 1699 | HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT), |
1680 | { | 1700 | { |
1681 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1701 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -1685,7 +1705,16 @@ static struct snd_kcontrol_new cxt5051_mixers[] = { | |||
1685 | .put = cxt5051_hp_master_sw_put, | 1705 | .put = cxt5051_hp_master_sw_put, |
1686 | .private_value = 0x1a, | 1706 | .private_value = 0x1a, |
1687 | }, | 1707 | }, |
1708 | {} | ||
1709 | }; | ||
1688 | 1710 | ||
1711 | static struct snd_kcontrol_new cxt5051_capture_mixers[] = { | ||
1712 | HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT), | ||
1713 | HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT), | ||
1714 | HDA_CODEC_VOLUME("External Mic Volume", 0x14, 0x01, HDA_INPUT), | ||
1715 | HDA_CODEC_MUTE("External Mic Switch", 0x14, 0x01, HDA_INPUT), | ||
1716 | HDA_CODEC_VOLUME("Docking Mic Volume", 0x15, 0x00, HDA_INPUT), | ||
1717 | HDA_CODEC_MUTE("Docking Mic Switch", 0x15, 0x00, HDA_INPUT), | ||
1689 | {} | 1718 | {} |
1690 | }; | 1719 | }; |
1691 | 1720 | ||
@@ -1694,32 +1723,26 @@ static struct snd_kcontrol_new cxt5051_hp_mixers[] = { | |||
1694 | HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT), | 1723 | HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT), |
1695 | HDA_CODEC_VOLUME("External Mic Volume", 0x15, 0x00, HDA_INPUT), | 1724 | HDA_CODEC_VOLUME("External Mic Volume", 0x15, 0x00, HDA_INPUT), |
1696 | HDA_CODEC_MUTE("External Mic Switch", 0x15, 0x00, HDA_INPUT), | 1725 | HDA_CODEC_MUTE("External Mic Switch", 0x15, 0x00, HDA_INPUT), |
1697 | HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT), | ||
1698 | { | ||
1699 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1700 | .name = "Master Playback Switch", | ||
1701 | .info = cxt_eapd_info, | ||
1702 | .get = cxt_eapd_get, | ||
1703 | .put = cxt5051_hp_master_sw_put, | ||
1704 | .private_value = 0x1a, | ||
1705 | }, | ||
1706 | |||
1707 | {} | 1726 | {} |
1708 | }; | 1727 | }; |
1709 | 1728 | ||
1710 | static struct snd_kcontrol_new cxt5051_hp_dv6736_mixers[] = { | 1729 | static struct snd_kcontrol_new cxt5051_hp_dv6736_mixers[] = { |
1711 | HDA_CODEC_VOLUME("Mic Volume", 0x14, 0x00, HDA_INPUT), | 1730 | HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x00, HDA_INPUT), |
1712 | HDA_CODEC_MUTE("Mic Switch", 0x14, 0x00, HDA_INPUT), | 1731 | HDA_CODEC_MUTE("Capture Switch", 0x14, 0x00, HDA_INPUT), |
1713 | HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT), | 1732 | {} |
1714 | { | 1733 | }; |
1715 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1716 | .name = "Master Playback Switch", | ||
1717 | .info = cxt_eapd_info, | ||
1718 | .get = cxt_eapd_get, | ||
1719 | .put = cxt5051_hp_master_sw_put, | ||
1720 | .private_value = 0x1a, | ||
1721 | }, | ||
1722 | 1734 | ||
1735 | static struct snd_kcontrol_new cxt5051_f700_mixers[] = { | ||
1736 | HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x01, HDA_INPUT), | ||
1737 | HDA_CODEC_MUTE("Capture Switch", 0x14, 0x01, HDA_INPUT), | ||
1738 | {} | ||
1739 | }; | ||
1740 | |||
1741 | static struct snd_kcontrol_new cxt5051_toshiba_mixers[] = { | ||
1742 | HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT), | ||
1743 | HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT), | ||
1744 | HDA_CODEC_VOLUME("External Mic Volume", 0x14, 0x01, HDA_INPUT), | ||
1745 | HDA_CODEC_MUTE("External Mic Switch", 0x14, 0x01, HDA_INPUT), | ||
1723 | {} | 1746 | {} |
1724 | }; | 1747 | }; |
1725 | 1748 | ||
@@ -1748,8 +1771,6 @@ static struct hda_verb cxt5051_init_verbs[] = { | |||
1748 | /* EAPD */ | 1771 | /* EAPD */ |
1749 | {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ | 1772 | {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ |
1750 | {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT}, | 1773 | {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT}, |
1751 | {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTB_EVENT}, | ||
1752 | {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTC_EVENT}, | ||
1753 | { } /* end */ | 1774 | { } /* end */ |
1754 | }; | 1775 | }; |
1755 | 1776 | ||
@@ -1775,7 +1796,6 @@ static struct hda_verb cxt5051_hp_dv6736_init_verbs[] = { | |||
1775 | /* EAPD */ | 1796 | /* EAPD */ |
1776 | {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ | 1797 | {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ |
1777 | {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT}, | 1798 | {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT}, |
1778 | {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTB_EVENT}, | ||
1779 | { } /* end */ | 1799 | { } /* end */ |
1780 | }; | 1800 | }; |
1781 | 1801 | ||
@@ -1807,17 +1827,60 @@ static struct hda_verb cxt5051_lenovo_x200_init_verbs[] = { | |||
1807 | /* EAPD */ | 1827 | /* EAPD */ |
1808 | {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ | 1828 | {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ |
1809 | {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT}, | 1829 | {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT}, |
1810 | {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTB_EVENT}, | ||
1811 | {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTC_EVENT}, | ||
1812 | {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT}, | 1830 | {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT}, |
1813 | { } /* end */ | 1831 | { } /* end */ |
1814 | }; | 1832 | }; |
1815 | 1833 | ||
1834 | static struct hda_verb cxt5051_f700_init_verbs[] = { | ||
1835 | /* Line in, Mic */ | ||
1836 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, | ||
1837 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
1838 | {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0}, | ||
1839 | {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0}, | ||
1840 | /* SPK */ | ||
1841 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
1842 | {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
1843 | /* HP, Amp */ | ||
1844 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
1845 | {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
1846 | /* DAC1 */ | ||
1847 | {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
1848 | /* Record selector: Int mic */ | ||
1849 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44}, | ||
1850 | {0x14, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
1851 | /* SPDIF route: PCM */ | ||
1852 | {0x1c, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
1853 | /* EAPD */ | ||
1854 | {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ | ||
1855 | {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT}, | ||
1856 | { } /* end */ | ||
1857 | }; | ||
1858 | |||
1859 | static void cxt5051_init_mic_port(struct hda_codec *codec, hda_nid_t nid, | ||
1860 | unsigned int event) | ||
1861 | { | ||
1862 | snd_hda_codec_write(codec, nid, 0, | ||
1863 | AC_VERB_SET_UNSOLICITED_ENABLE, | ||
1864 | AC_USRSP_EN | event); | ||
1865 | #ifdef CONFIG_SND_HDA_INPUT_JACK | ||
1866 | conexant_add_jack(codec, nid, SND_JACK_MICROPHONE); | ||
1867 | conexant_report_jack(codec, nid); | ||
1868 | #endif | ||
1869 | } | ||
1870 | |||
1816 | /* initialize jack-sensing, too */ | 1871 | /* initialize jack-sensing, too */ |
1817 | static int cxt5051_init(struct hda_codec *codec) | 1872 | static int cxt5051_init(struct hda_codec *codec) |
1818 | { | 1873 | { |
1874 | struct conexant_spec *spec = codec->spec; | ||
1875 | |||
1819 | conexant_init(codec); | 1876 | conexant_init(codec); |
1820 | conexant_init_jacks(codec); | 1877 | conexant_init_jacks(codec); |
1878 | |||
1879 | if (spec->auto_mic & AUTO_MIC_PORTB) | ||
1880 | cxt5051_init_mic_port(codec, 0x17, CXT5051_PORTB_EVENT); | ||
1881 | if (spec->auto_mic & AUTO_MIC_PORTC) | ||
1882 | cxt5051_init_mic_port(codec, 0x18, CXT5051_PORTC_EVENT); | ||
1883 | |||
1821 | if (codec->patch_ops.unsol_event) { | 1884 | if (codec->patch_ops.unsol_event) { |
1822 | cxt5051_hp_automute(codec); | 1885 | cxt5051_hp_automute(codec); |
1823 | cxt5051_portb_automic(codec); | 1886 | cxt5051_portb_automic(codec); |
@@ -1832,6 +1895,8 @@ enum { | |||
1832 | CXT5051_HP, /* no docking */ | 1895 | CXT5051_HP, /* no docking */ |
1833 | CXT5051_HP_DV6736, /* HP without mic switch */ | 1896 | CXT5051_HP_DV6736, /* HP without mic switch */ |
1834 | CXT5051_LENOVO_X200, /* Lenovo X200 laptop */ | 1897 | CXT5051_LENOVO_X200, /* Lenovo X200 laptop */ |
1898 | CXT5051_F700, /* HP Compaq Presario F700 */ | ||
1899 | CXT5051_TOSHIBA, /* Toshiba M300 & co */ | ||
1835 | CXT5051_MODELS | 1900 | CXT5051_MODELS |
1836 | }; | 1901 | }; |
1837 | 1902 | ||
@@ -1840,11 +1905,15 @@ static const char *cxt5051_models[CXT5051_MODELS] = { | |||
1840 | [CXT5051_HP] = "hp", | 1905 | [CXT5051_HP] = "hp", |
1841 | [CXT5051_HP_DV6736] = "hp-dv6736", | 1906 | [CXT5051_HP_DV6736] = "hp-dv6736", |
1842 | [CXT5051_LENOVO_X200] = "lenovo-x200", | 1907 | [CXT5051_LENOVO_X200] = "lenovo-x200", |
1908 | [CXT5051_F700] = "hp-700", | ||
1909 | [CXT5051_TOSHIBA] = "toshiba", | ||
1843 | }; | 1910 | }; |
1844 | 1911 | ||
1845 | static struct snd_pci_quirk cxt5051_cfg_tbl[] = { | 1912 | static struct snd_pci_quirk cxt5051_cfg_tbl[] = { |
1846 | SND_PCI_QUIRK(0x103c, 0x30cf, "HP DV6736", CXT5051_HP_DV6736), | 1913 | SND_PCI_QUIRK(0x103c, 0x30cf, "HP DV6736", CXT5051_HP_DV6736), |
1847 | SND_PCI_QUIRK(0x103c, 0x360b, "Compaq Presario CQ60", CXT5051_HP), | 1914 | SND_PCI_QUIRK(0x103c, 0x360b, "Compaq Presario CQ60", CXT5051_HP), |
1915 | SND_PCI_QUIRK(0x103c, 0x30ea, "Compaq Presario F700", CXT5051_F700), | ||
1916 | SND_PCI_QUIRK(0x1179, 0xff50, "Toshiba M30x", CXT5051_TOSHIBA), | ||
1848 | SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board", | 1917 | SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board", |
1849 | CXT5051_LAPTOP), | 1918 | CXT5051_LAPTOP), |
1850 | SND_PCI_QUIRK(0x14f1, 0x5051, "HP Spartan 1.1", CXT5051_HP), | 1919 | SND_PCI_QUIRK(0x14f1, 0x5051, "HP Spartan 1.1", CXT5051_HP), |
@@ -1872,8 +1941,9 @@ static int patch_cxt5051(struct hda_codec *codec) | |||
1872 | spec->multiout.dig_out_nid = CXT5051_SPDIF_OUT; | 1941 | spec->multiout.dig_out_nid = CXT5051_SPDIF_OUT; |
1873 | spec->num_adc_nids = 1; /* not 2; via auto-mic switch */ | 1942 | spec->num_adc_nids = 1; /* not 2; via auto-mic switch */ |
1874 | spec->adc_nids = cxt5051_adc_nids; | 1943 | spec->adc_nids = cxt5051_adc_nids; |
1875 | spec->num_mixers = 1; | 1944 | spec->num_mixers = 2; |
1876 | spec->mixers[0] = cxt5051_mixers; | 1945 | spec->mixers[0] = cxt5051_capture_mixers; |
1946 | spec->mixers[1] = cxt5051_playback_mixers; | ||
1877 | spec->num_init_verbs = 1; | 1947 | spec->num_init_verbs = 1; |
1878 | spec->init_verbs[0] = cxt5051_init_verbs; | 1948 | spec->init_verbs[0] = cxt5051_init_verbs; |
1879 | spec->spdif_route = 0; | 1949 | spec->spdif_route = 0; |
@@ -1887,6 +1957,7 @@ static int patch_cxt5051(struct hda_codec *codec) | |||
1887 | board_config = snd_hda_check_board_config(codec, CXT5051_MODELS, | 1957 | board_config = snd_hda_check_board_config(codec, CXT5051_MODELS, |
1888 | cxt5051_models, | 1958 | cxt5051_models, |
1889 | cxt5051_cfg_tbl); | 1959 | cxt5051_cfg_tbl); |
1960 | spec->auto_mic = AUTO_MIC_PORTB | AUTO_MIC_PORTC; | ||
1890 | switch (board_config) { | 1961 | switch (board_config) { |
1891 | case CXT5051_HP: | 1962 | case CXT5051_HP: |
1892 | spec->mixers[0] = cxt5051_hp_mixers; | 1963 | spec->mixers[0] = cxt5051_hp_mixers; |
@@ -1894,11 +1965,20 @@ static int patch_cxt5051(struct hda_codec *codec) | |||
1894 | case CXT5051_HP_DV6736: | 1965 | case CXT5051_HP_DV6736: |
1895 | spec->init_verbs[0] = cxt5051_hp_dv6736_init_verbs; | 1966 | spec->init_verbs[0] = cxt5051_hp_dv6736_init_verbs; |
1896 | spec->mixers[0] = cxt5051_hp_dv6736_mixers; | 1967 | spec->mixers[0] = cxt5051_hp_dv6736_mixers; |
1897 | spec->no_auto_mic = 1; | 1968 | spec->auto_mic = 0; |
1898 | break; | 1969 | break; |
1899 | case CXT5051_LENOVO_X200: | 1970 | case CXT5051_LENOVO_X200: |
1900 | spec->init_verbs[0] = cxt5051_lenovo_x200_init_verbs; | 1971 | spec->init_verbs[0] = cxt5051_lenovo_x200_init_verbs; |
1901 | break; | 1972 | break; |
1973 | case CXT5051_F700: | ||
1974 | spec->init_verbs[0] = cxt5051_f700_init_verbs; | ||
1975 | spec->mixers[0] = cxt5051_f700_mixers; | ||
1976 | spec->auto_mic = 0; | ||
1977 | break; | ||
1978 | case CXT5051_TOSHIBA: | ||
1979 | spec->mixers[0] = cxt5051_toshiba_mixers; | ||
1980 | spec->auto_mic = AUTO_MIC_PORTB; | ||
1981 | break; | ||
1902 | } | 1982 | } |
1903 | 1983 | ||
1904 | return 0; | 1984 | return 0; |
@@ -1966,33 +2046,117 @@ static int cxt5066_hp_master_sw_put(struct snd_kcontrol *kcontrol, | |||
1966 | return 1; | 2046 | return 1; |
1967 | } | 2047 | } |
1968 | 2048 | ||
2049 | static const struct hda_input_mux cxt5066_olpc_dc_bias = { | ||
2050 | .num_items = 3, | ||
2051 | .items = { | ||
2052 | { "Off", PIN_IN }, | ||
2053 | { "50%", PIN_VREF50 }, | ||
2054 | { "80%", PIN_VREF80 }, | ||
2055 | }, | ||
2056 | }; | ||
2057 | |||
2058 | static int cxt5066_set_olpc_dc_bias(struct hda_codec *codec) | ||
2059 | { | ||
2060 | struct conexant_spec *spec = codec->spec; | ||
2061 | /* Even though port F is the DC input, the bias is controlled on port B. | ||
2062 | * we also leave that port as an active input (but unselected) in DC mode | ||
2063 | * just in case that is necessary to make the bias setting take effect. */ | ||
2064 | return snd_hda_codec_write_cache(codec, 0x1a, 0, | ||
2065 | AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
2066 | cxt5066_olpc_dc_bias.items[spec->dc_input_bias].index); | ||
2067 | } | ||
2068 | |||
2069 | /* OLPC defers mic widget control until when capture is started because the | ||
2070 | * microphone LED comes on as soon as these settings are put in place. if we | ||
2071 | * did this before recording, it would give the false indication that recording | ||
2072 | * is happening when it is not. */ | ||
2073 | static void cxt5066_olpc_select_mic(struct hda_codec *codec) | ||
2074 | { | ||
2075 | struct conexant_spec *spec = codec->spec; | ||
2076 | if (!spec->recording) | ||
2077 | return; | ||
2078 | |||
2079 | if (spec->dc_enable) { | ||
2080 | /* in DC mode we ignore presence detection and just use the jack | ||
2081 | * through our special DC port */ | ||
2082 | const struct hda_verb enable_dc_mode[] = { | ||
2083 | /* disble internal mic, port C */ | ||
2084 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | ||
2085 | |||
2086 | /* enable DC capture, port F */ | ||
2087 | {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
2088 | {}, | ||
2089 | }; | ||
2090 | |||
2091 | snd_hda_sequence_write(codec, enable_dc_mode); | ||
2092 | /* port B input disabled (and bias set) through the following call */ | ||
2093 | cxt5066_set_olpc_dc_bias(codec); | ||
2094 | return; | ||
2095 | } | ||
2096 | |||
2097 | /* disable DC (port F) */ | ||
2098 | snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0); | ||
2099 | |||
2100 | /* external mic, port B */ | ||
2101 | snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
2102 | spec->ext_mic_present ? CXT5066_OLPC_EXT_MIC_BIAS : 0); | ||
2103 | |||
2104 | /* internal mic, port C */ | ||
2105 | snd_hda_codec_write(codec, 0x1b, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
2106 | spec->ext_mic_present ? 0 : PIN_VREF80); | ||
2107 | } | ||
2108 | |||
1969 | /* toggle input of built-in and mic jack appropriately */ | 2109 | /* toggle input of built-in and mic jack appropriately */ |
1970 | static void cxt5066_automic(struct hda_codec *codec) | 2110 | static void cxt5066_olpc_automic(struct hda_codec *codec) |
1971 | { | 2111 | { |
1972 | struct conexant_spec *spec = codec->spec; | 2112 | struct conexant_spec *spec = codec->spec; |
2113 | unsigned int present; | ||
2114 | |||
2115 | if (spec->dc_enable) /* don't do presence detection in DC mode */ | ||
2116 | return; | ||
2117 | |||
2118 | present = snd_hda_codec_read(codec, 0x1a, 0, | ||
2119 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
2120 | if (present) | ||
2121 | snd_printdd("CXT5066: external microphone detected\n"); | ||
2122 | else | ||
2123 | snd_printdd("CXT5066: external microphone absent\n"); | ||
2124 | |||
2125 | snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_CONNECT_SEL, | ||
2126 | present ? 0 : 1); | ||
2127 | spec->ext_mic_present = !!present; | ||
2128 | |||
2129 | cxt5066_olpc_select_mic(codec); | ||
2130 | } | ||
2131 | |||
2132 | /* toggle input of built-in digital mic and mic jack appropriately */ | ||
2133 | static void cxt5066_vostro_automic(struct hda_codec *codec) | ||
2134 | { | ||
2135 | unsigned int present; | ||
2136 | |||
1973 | struct hda_verb ext_mic_present[] = { | 2137 | struct hda_verb ext_mic_present[] = { |
1974 | /* enable external mic, port B */ | 2138 | /* enable external mic, port B */ |
1975 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, spec->ext_mic_bias}, | 2139 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, |
1976 | 2140 | ||
1977 | /* switch to external mic input */ | 2141 | /* switch to external mic input */ |
1978 | {0x17, AC_VERB_SET_CONNECT_SEL, 0}, | 2142 | {0x17, AC_VERB_SET_CONNECT_SEL, 0}, |
2143 | {0x14, AC_VERB_SET_CONNECT_SEL, 0}, | ||
1979 | 2144 | ||
1980 | /* disable internal mic, port C */ | 2145 | /* disable internal digital mic */ |
1981 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | 2146 | {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, |
1982 | {} | 2147 | {} |
1983 | }; | 2148 | }; |
1984 | static struct hda_verb ext_mic_absent[] = { | 2149 | static struct hda_verb ext_mic_absent[] = { |
1985 | /* enable internal mic, port C */ | 2150 | /* enable internal mic, port C */ |
1986 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | 2151 | {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, |
1987 | 2152 | ||
1988 | /* switch to internal mic input */ | 2153 | /* switch to internal mic input */ |
1989 | {0x17, AC_VERB_SET_CONNECT_SEL, 1}, | 2154 | {0x14, AC_VERB_SET_CONNECT_SEL, 2}, |
1990 | 2155 | ||
1991 | /* disable external mic, port B */ | 2156 | /* disable external mic, port B */ |
1992 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | 2157 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, |
1993 | {} | 2158 | {} |
1994 | }; | 2159 | }; |
1995 | unsigned int present; | ||
1996 | 2160 | ||
1997 | present = snd_hda_jack_detect(codec, 0x1a); | 2161 | present = snd_hda_jack_detect(codec, 0x1a); |
1998 | if (present) { | 2162 | if (present) { |
@@ -2005,36 +2169,24 @@ static void cxt5066_automic(struct hda_codec *codec) | |||
2005 | } | 2169 | } |
2006 | 2170 | ||
2007 | /* toggle input of built-in digital mic and mic jack appropriately */ | 2171 | /* toggle input of built-in digital mic and mic jack appropriately */ |
2008 | static void cxt5066_vostro_automic(struct hda_codec *codec) | 2172 | static void cxt5066_ideapad_automic(struct hda_codec *codec) |
2009 | { | 2173 | { |
2010 | struct conexant_spec *spec = codec->spec; | ||
2011 | unsigned int present; | 2174 | unsigned int present; |
2012 | 2175 | ||
2013 | struct hda_verb ext_mic_present[] = { | 2176 | struct hda_verb ext_mic_present[] = { |
2014 | /* enable external mic, port B */ | ||
2015 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, spec->ext_mic_bias}, | ||
2016 | |||
2017 | /* switch to external mic input */ | ||
2018 | {0x17, AC_VERB_SET_CONNECT_SEL, 0}, | ||
2019 | {0x14, AC_VERB_SET_CONNECT_SEL, 0}, | 2177 | {0x14, AC_VERB_SET_CONNECT_SEL, 0}, |
2020 | 2178 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | |
2021 | /* disable internal digital mic */ | ||
2022 | {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | 2179 | {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, |
2023 | {} | 2180 | {} |
2024 | }; | 2181 | }; |
2025 | static struct hda_verb ext_mic_absent[] = { | 2182 | static struct hda_verb ext_mic_absent[] = { |
2026 | /* enable internal mic, port C */ | ||
2027 | {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
2028 | |||
2029 | /* switch to internal mic input */ | ||
2030 | {0x14, AC_VERB_SET_CONNECT_SEL, 2}, | 2183 | {0x14, AC_VERB_SET_CONNECT_SEL, 2}, |
2031 | 2184 | {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | |
2032 | /* disable external mic, port B */ | 2185 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, |
2033 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | ||
2034 | {} | 2186 | {} |
2035 | }; | 2187 | }; |
2036 | 2188 | ||
2037 | present = snd_hda_jack_detect(codec, 0x1a); | 2189 | present = snd_hda_jack_detect(codec, 0x1b); |
2038 | if (present) { | 2190 | if (present) { |
2039 | snd_printdd("CXT5066: external microphone detected\n"); | 2191 | snd_printdd("CXT5066: external microphone detected\n"); |
2040 | snd_hda_sequence_write(codec, ext_mic_present); | 2192 | snd_hda_sequence_write(codec, ext_mic_present); |
@@ -2063,15 +2215,18 @@ static void cxt5066_hp_automute(struct hda_codec *codec) | |||
2063 | } | 2215 | } |
2064 | 2216 | ||
2065 | /* unsolicited event for jack sensing */ | 2217 | /* unsolicited event for jack sensing */ |
2066 | static void cxt5066_unsol_event(struct hda_codec *codec, unsigned int res) | 2218 | static void cxt5066_olpc_unsol_event(struct hda_codec *codec, unsigned int res) |
2067 | { | 2219 | { |
2220 | struct conexant_spec *spec = codec->spec; | ||
2068 | snd_printdd("CXT5066: unsol event %x (%x)\n", res, res >> 26); | 2221 | snd_printdd("CXT5066: unsol event %x (%x)\n", res, res >> 26); |
2069 | switch (res >> 26) { | 2222 | switch (res >> 26) { |
2070 | case CONEXANT_HP_EVENT: | 2223 | case CONEXANT_HP_EVENT: |
2071 | cxt5066_hp_automute(codec); | 2224 | cxt5066_hp_automute(codec); |
2072 | break; | 2225 | break; |
2073 | case CONEXANT_MIC_EVENT: | 2226 | case CONEXANT_MIC_EVENT: |
2074 | cxt5066_automic(codec); | 2227 | /* ignore mic events in DC mode; we're always using the jack */ |
2228 | if (!spec->dc_enable) | ||
2229 | cxt5066_olpc_automic(codec); | ||
2075 | break; | 2230 | break; |
2076 | } | 2231 | } |
2077 | } | 2232 | } |
@@ -2090,6 +2245,20 @@ static void cxt5066_vostro_event(struct hda_codec *codec, unsigned int res) | |||
2090 | } | 2245 | } |
2091 | } | 2246 | } |
2092 | 2247 | ||
2248 | /* unsolicited event for jack sensing */ | ||
2249 | static void cxt5066_ideapad_event(struct hda_codec *codec, unsigned int res) | ||
2250 | { | ||
2251 | snd_printdd("CXT5066_ideapad: unsol event %x (%x)\n", res, res >> 26); | ||
2252 | switch (res >> 26) { | ||
2253 | case CONEXANT_HP_EVENT: | ||
2254 | cxt5066_hp_automute(codec); | ||
2255 | break; | ||
2256 | case CONEXANT_MIC_EVENT: | ||
2257 | cxt5066_ideapad_automic(codec); | ||
2258 | break; | ||
2259 | } | ||
2260 | } | ||
2261 | |||
2093 | static const struct hda_input_mux cxt5066_analog_mic_boost = { | 2262 | static const struct hda_input_mux cxt5066_analog_mic_boost = { |
2094 | .num_items = 5, | 2263 | .num_items = 5, |
2095 | .items = { | 2264 | .items = { |
@@ -2101,6 +2270,23 @@ static const struct hda_input_mux cxt5066_analog_mic_boost = { | |||
2101 | }, | 2270 | }, |
2102 | }; | 2271 | }; |
2103 | 2272 | ||
2273 | static void cxt5066_set_mic_boost(struct hda_codec *codec) | ||
2274 | { | ||
2275 | struct conexant_spec *spec = codec->spec; | ||
2276 | snd_hda_codec_write_cache(codec, 0x17, 0, | ||
2277 | AC_VERB_SET_AMP_GAIN_MUTE, | ||
2278 | AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | AC_AMP_SET_OUTPUT | | ||
2279 | cxt5066_analog_mic_boost.items[spec->mic_boost].index); | ||
2280 | if (spec->ideapad) { | ||
2281 | /* adjust the internal mic as well...it is not through 0x17 */ | ||
2282 | snd_hda_codec_write_cache(codec, 0x23, 0, | ||
2283 | AC_VERB_SET_AMP_GAIN_MUTE, | ||
2284 | AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | AC_AMP_SET_INPUT | | ||
2285 | cxt5066_analog_mic_boost. | ||
2286 | items[spec->mic_boost].index); | ||
2287 | } | ||
2288 | } | ||
2289 | |||
2104 | static int cxt5066_mic_boost_mux_enum_info(struct snd_kcontrol *kcontrol, | 2290 | static int cxt5066_mic_boost_mux_enum_info(struct snd_kcontrol *kcontrol, |
2105 | struct snd_ctl_elem_info *uinfo) | 2291 | struct snd_ctl_elem_info *uinfo) |
2106 | { | 2292 | { |
@@ -2111,15 +2297,8 @@ static int cxt5066_mic_boost_mux_enum_get(struct snd_kcontrol *kcontrol, | |||
2111 | struct snd_ctl_elem_value *ucontrol) | 2297 | struct snd_ctl_elem_value *ucontrol) |
2112 | { | 2298 | { |
2113 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 2299 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
2114 | int val; | 2300 | struct conexant_spec *spec = codec->spec; |
2115 | hda_nid_t nid = kcontrol->private_value & 0xff; | 2301 | ucontrol->value.enumerated.item[0] = spec->mic_boost; |
2116 | int inout = (kcontrol->private_value & 0x100) ? | ||
2117 | AC_AMP_GET_INPUT : AC_AMP_GET_OUTPUT; | ||
2118 | |||
2119 | val = snd_hda_codec_read(codec, nid, 0, | ||
2120 | AC_VERB_GET_AMP_GAIN_MUTE, inout); | ||
2121 | |||
2122 | ucontrol->value.enumerated.item[0] = val & AC_AMP_GAIN; | ||
2123 | return 0; | 2302 | return 0; |
2124 | } | 2303 | } |
2125 | 2304 | ||
@@ -2127,26 +2306,132 @@ static int cxt5066_mic_boost_mux_enum_put(struct snd_kcontrol *kcontrol, | |||
2127 | struct snd_ctl_elem_value *ucontrol) | 2306 | struct snd_ctl_elem_value *ucontrol) |
2128 | { | 2307 | { |
2129 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 2308 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
2309 | struct conexant_spec *spec = codec->spec; | ||
2130 | const struct hda_input_mux *imux = &cxt5066_analog_mic_boost; | 2310 | const struct hda_input_mux *imux = &cxt5066_analog_mic_boost; |
2131 | unsigned int idx; | 2311 | unsigned int idx; |
2132 | hda_nid_t nid = kcontrol->private_value & 0xff; | 2312 | idx = ucontrol->value.enumerated.item[0]; |
2133 | int inout = (kcontrol->private_value & 0x100) ? | 2313 | if (idx >= imux->num_items) |
2134 | AC_AMP_SET_INPUT : AC_AMP_SET_OUTPUT; | 2314 | idx = imux->num_items - 1; |
2315 | |||
2316 | spec->mic_boost = idx; | ||
2317 | if (!spec->dc_enable) | ||
2318 | cxt5066_set_mic_boost(codec); | ||
2319 | return 1; | ||
2320 | } | ||
2321 | |||
2322 | static void cxt5066_enable_dc(struct hda_codec *codec) | ||
2323 | { | ||
2324 | const struct hda_verb enable_dc_mode[] = { | ||
2325 | /* disable gain */ | ||
2326 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2327 | |||
2328 | /* switch to DC input */ | ||
2329 | {0x17, AC_VERB_SET_CONNECT_SEL, 3}, | ||
2330 | {} | ||
2331 | }; | ||
2332 | |||
2333 | /* configure as input source */ | ||
2334 | snd_hda_sequence_write(codec, enable_dc_mode); | ||
2335 | cxt5066_olpc_select_mic(codec); /* also sets configured bias */ | ||
2336 | } | ||
2337 | |||
2338 | static void cxt5066_disable_dc(struct hda_codec *codec) | ||
2339 | { | ||
2340 | /* reconfigure input source */ | ||
2341 | cxt5066_set_mic_boost(codec); | ||
2342 | /* automic also selects the right mic if we're recording */ | ||
2343 | cxt5066_olpc_automic(codec); | ||
2344 | } | ||
2345 | |||
2346 | static int cxt5066_olpc_dc_get(struct snd_kcontrol *kcontrol, | ||
2347 | struct snd_ctl_elem_value *ucontrol) | ||
2348 | { | ||
2349 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
2350 | struct conexant_spec *spec = codec->spec; | ||
2351 | ucontrol->value.integer.value[0] = spec->dc_enable; | ||
2352 | return 0; | ||
2353 | } | ||
2135 | 2354 | ||
2136 | if (!imux->num_items) | 2355 | static int cxt5066_olpc_dc_put(struct snd_kcontrol *kcontrol, |
2356 | struct snd_ctl_elem_value *ucontrol) | ||
2357 | { | ||
2358 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
2359 | struct conexant_spec *spec = codec->spec; | ||
2360 | int dc_enable = !!ucontrol->value.integer.value[0]; | ||
2361 | |||
2362 | if (dc_enable == spec->dc_enable) | ||
2137 | return 0; | 2363 | return 0; |
2364 | |||
2365 | spec->dc_enable = dc_enable; | ||
2366 | if (dc_enable) | ||
2367 | cxt5066_enable_dc(codec); | ||
2368 | else | ||
2369 | cxt5066_disable_dc(codec); | ||
2370 | |||
2371 | return 1; | ||
2372 | } | ||
2373 | |||
2374 | static int cxt5066_olpc_dc_bias_enum_info(struct snd_kcontrol *kcontrol, | ||
2375 | struct snd_ctl_elem_info *uinfo) | ||
2376 | { | ||
2377 | return snd_hda_input_mux_info(&cxt5066_olpc_dc_bias, uinfo); | ||
2378 | } | ||
2379 | |||
2380 | static int cxt5066_olpc_dc_bias_enum_get(struct snd_kcontrol *kcontrol, | ||
2381 | struct snd_ctl_elem_value *ucontrol) | ||
2382 | { | ||
2383 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
2384 | struct conexant_spec *spec = codec->spec; | ||
2385 | ucontrol->value.enumerated.item[0] = spec->dc_input_bias; | ||
2386 | return 0; | ||
2387 | } | ||
2388 | |||
2389 | static int cxt5066_olpc_dc_bias_enum_put(struct snd_kcontrol *kcontrol, | ||
2390 | struct snd_ctl_elem_value *ucontrol) | ||
2391 | { | ||
2392 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
2393 | struct conexant_spec *spec = codec->spec; | ||
2394 | const struct hda_input_mux *imux = &cxt5066_analog_mic_boost; | ||
2395 | unsigned int idx; | ||
2396 | |||
2138 | idx = ucontrol->value.enumerated.item[0]; | 2397 | idx = ucontrol->value.enumerated.item[0]; |
2139 | if (idx >= imux->num_items) | 2398 | if (idx >= imux->num_items) |
2140 | idx = imux->num_items - 1; | 2399 | idx = imux->num_items - 1; |
2141 | 2400 | ||
2142 | snd_hda_codec_write_cache(codec, nid, 0, | 2401 | spec->dc_input_bias = idx; |
2143 | AC_VERB_SET_AMP_GAIN_MUTE, | 2402 | if (spec->dc_enable) |
2144 | AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | inout | | 2403 | cxt5066_set_olpc_dc_bias(codec); |
2145 | imux->items[idx].index); | ||
2146 | |||
2147 | return 1; | 2404 | return 1; |
2148 | } | 2405 | } |
2149 | 2406 | ||
2407 | static void cxt5066_olpc_capture_prepare(struct hda_codec *codec) | ||
2408 | { | ||
2409 | struct conexant_spec *spec = codec->spec; | ||
2410 | /* mark as recording and configure the microphone widget so that the | ||
2411 | * recording LED comes on. */ | ||
2412 | spec->recording = 1; | ||
2413 | cxt5066_olpc_select_mic(codec); | ||
2414 | } | ||
2415 | |||
2416 | static void cxt5066_olpc_capture_cleanup(struct hda_codec *codec) | ||
2417 | { | ||
2418 | struct conexant_spec *spec = codec->spec; | ||
2419 | const struct hda_verb disable_mics[] = { | ||
2420 | /* disable external mic, port B */ | ||
2421 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | ||
2422 | |||
2423 | /* disble internal mic, port C */ | ||
2424 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | ||
2425 | |||
2426 | /* disable DC capture, port F */ | ||
2427 | {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | ||
2428 | {}, | ||
2429 | }; | ||
2430 | |||
2431 | snd_hda_sequence_write(codec, disable_mics); | ||
2432 | spec->recording = 0; | ||
2433 | } | ||
2434 | |||
2150 | static struct hda_input_mux cxt5066_capture_source = { | 2435 | static struct hda_input_mux cxt5066_capture_source = { |
2151 | .num_items = 4, | 2436 | .num_items = 4, |
2152 | .items = { | 2437 | .items = { |
@@ -2187,6 +2472,7 @@ static struct snd_kcontrol_new cxt5066_mixer_master_olpc[] = { | |||
2187 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | 2472 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | |
2188 | SNDRV_CTL_ELEM_ACCESS_TLV_READ | | 2473 | SNDRV_CTL_ELEM_ACCESS_TLV_READ | |
2189 | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, | 2474 | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, |
2475 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
2190 | .info = snd_hda_mixer_amp_volume_info, | 2476 | .info = snd_hda_mixer_amp_volume_info, |
2191 | .get = snd_hda_mixer_amp_volume_get, | 2477 | .get = snd_hda_mixer_amp_volume_get, |
2192 | .put = snd_hda_mixer_amp_volume_put, | 2478 | .put = snd_hda_mixer_amp_volume_put, |
@@ -2198,6 +2484,24 @@ static struct snd_kcontrol_new cxt5066_mixer_master_olpc[] = { | |||
2198 | {} | 2484 | {} |
2199 | }; | 2485 | }; |
2200 | 2486 | ||
2487 | static struct snd_kcontrol_new cxt5066_mixer_olpc_dc[] = { | ||
2488 | { | ||
2489 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2490 | .name = "DC Mode Enable Switch", | ||
2491 | .info = snd_ctl_boolean_mono_info, | ||
2492 | .get = cxt5066_olpc_dc_get, | ||
2493 | .put = cxt5066_olpc_dc_put, | ||
2494 | }, | ||
2495 | { | ||
2496 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2497 | .name = "DC Input Bias Enum", | ||
2498 | .info = cxt5066_olpc_dc_bias_enum_info, | ||
2499 | .get = cxt5066_olpc_dc_bias_enum_get, | ||
2500 | .put = cxt5066_olpc_dc_bias_enum_put, | ||
2501 | }, | ||
2502 | {} | ||
2503 | }; | ||
2504 | |||
2201 | static struct snd_kcontrol_new cxt5066_mixers[] = { | 2505 | static struct snd_kcontrol_new cxt5066_mixers[] = { |
2202 | { | 2506 | { |
2203 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2507 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -2210,11 +2514,10 @@ static struct snd_kcontrol_new cxt5066_mixers[] = { | |||
2210 | 2514 | ||
2211 | { | 2515 | { |
2212 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2516 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
2213 | .name = "Ext Mic Boost Capture Enum", | 2517 | .name = "Analog Mic Boost Capture Enum", |
2214 | .info = cxt5066_mic_boost_mux_enum_info, | 2518 | .info = cxt5066_mic_boost_mux_enum_info, |
2215 | .get = cxt5066_mic_boost_mux_enum_get, | 2519 | .get = cxt5066_mic_boost_mux_enum_get, |
2216 | .put = cxt5066_mic_boost_mux_enum_put, | 2520 | .put = cxt5066_mic_boost_mux_enum_put, |
2217 | .private_value = 0x17, | ||
2218 | }, | 2521 | }, |
2219 | 2522 | ||
2220 | HDA_BIND_VOL("Capture Volume", &cxt5066_bind_capture_vol_others), | 2523 | HDA_BIND_VOL("Capture Volume", &cxt5066_bind_capture_vol_others), |
@@ -2296,10 +2599,10 @@ static struct hda_verb cxt5066_init_verbs_olpc[] = { | |||
2296 | {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ | 2599 | {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ |
2297 | 2600 | ||
2298 | /* Port B: external microphone */ | 2601 | /* Port B: external microphone */ |
2299 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, CXT5066_OLPC_EXT_MIC_BIAS}, | 2602 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, |
2300 | 2603 | ||
2301 | /* Port C: internal microphone */ | 2604 | /* Port C: internal microphone */ |
2302 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | 2605 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, |
2303 | 2606 | ||
2304 | /* Port D: unused */ | 2607 | /* Port D: unused */ |
2305 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | 2608 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, |
@@ -2308,7 +2611,7 @@ static struct hda_verb cxt5066_init_verbs_olpc[] = { | |||
2308 | {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | 2611 | {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, |
2309 | {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ | 2612 | {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ |
2310 | 2613 | ||
2311 | /* Port F: unused */ | 2614 | /* Port F: external DC input through microphone port */ |
2312 | {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | 2615 | {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, |
2313 | 2616 | ||
2314 | /* Port G: internal speakers */ | 2617 | /* Port G: internal speakers */ |
@@ -2412,6 +2715,56 @@ static struct hda_verb cxt5066_init_verbs_vostro[] = { | |||
2412 | { } /* end */ | 2715 | { } /* end */ |
2413 | }; | 2716 | }; |
2414 | 2717 | ||
2718 | static struct hda_verb cxt5066_init_verbs_ideapad[] = { | ||
2719 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port B */ | ||
2720 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port C */ | ||
2721 | {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port F */ | ||
2722 | {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port E */ | ||
2723 | |||
2724 | /* Speakers */ | ||
2725 | {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
2726 | {0x1f, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ | ||
2727 | |||
2728 | /* HP, Amp */ | ||
2729 | {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
2730 | {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ | ||
2731 | |||
2732 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
2733 | {0x1c, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ | ||
2734 | |||
2735 | /* DAC1 */ | ||
2736 | {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2737 | |||
2738 | /* Node 14 connections: 0x17 0x18 0x23 0x24 0x27 */ | ||
2739 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x50}, | ||
2740 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
2741 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2) | 0x50}, | ||
2742 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
2743 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
2744 | {0x14, AC_VERB_SET_CONNECT_SEL, 2}, /* default to internal mic */ | ||
2745 | |||
2746 | /* Audio input selector */ | ||
2747 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x2}, | ||
2748 | {0x17, AC_VERB_SET_CONNECT_SEL, 1}, /* route ext mic */ | ||
2749 | |||
2750 | /* SPDIF route: PCM */ | ||
2751 | {0x20, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
2752 | {0x22, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
2753 | |||
2754 | {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
2755 | {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
2756 | |||
2757 | /* internal microphone */ | ||
2758 | {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* enable int mic */ | ||
2759 | |||
2760 | /* EAPD */ | ||
2761 | {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ | ||
2762 | |||
2763 | {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, | ||
2764 | {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, | ||
2765 | { } /* end */ | ||
2766 | }; | ||
2767 | |||
2415 | static struct hda_verb cxt5066_init_verbs_portd_lo[] = { | 2768 | static struct hda_verb cxt5066_init_verbs_portd_lo[] = { |
2416 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | 2769 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, |
2417 | { } /* end */ | 2770 | { } /* end */ |
@@ -2428,8 +2781,24 @@ static int cxt5066_init(struct hda_codec *codec) | |||
2428 | cxt5066_hp_automute(codec); | 2781 | cxt5066_hp_automute(codec); |
2429 | if (spec->dell_vostro) | 2782 | if (spec->dell_vostro) |
2430 | cxt5066_vostro_automic(codec); | 2783 | cxt5066_vostro_automic(codec); |
2431 | else | 2784 | else if (spec->ideapad) |
2432 | cxt5066_automic(codec); | 2785 | cxt5066_ideapad_automic(codec); |
2786 | } | ||
2787 | cxt5066_set_mic_boost(codec); | ||
2788 | return 0; | ||
2789 | } | ||
2790 | |||
2791 | static int cxt5066_olpc_init(struct hda_codec *codec) | ||
2792 | { | ||
2793 | struct conexant_spec *spec = codec->spec; | ||
2794 | snd_printdd("CXT5066: init\n"); | ||
2795 | conexant_init(codec); | ||
2796 | cxt5066_hp_automute(codec); | ||
2797 | if (!spec->dc_enable) { | ||
2798 | cxt5066_set_mic_boost(codec); | ||
2799 | cxt5066_olpc_automic(codec); | ||
2800 | } else { | ||
2801 | cxt5066_enable_dc(codec); | ||
2433 | } | 2802 | } |
2434 | return 0; | 2803 | return 0; |
2435 | } | 2804 | } |
@@ -2439,6 +2808,7 @@ enum { | |||
2439 | CXT5066_DELL_LAPTOP, /* Dell Laptop */ | 2808 | CXT5066_DELL_LAPTOP, /* Dell Laptop */ |
2440 | CXT5066_OLPC_XO_1_5, /* OLPC XO 1.5 */ | 2809 | CXT5066_OLPC_XO_1_5, /* OLPC XO 1.5 */ |
2441 | CXT5066_DELL_VOSTO, /* Dell Vostro 1015i */ | 2810 | CXT5066_DELL_VOSTO, /* Dell Vostro 1015i */ |
2811 | CXT5066_IDEAPAD, /* Lenovo IdeaPad U150 */ | ||
2442 | CXT5066_MODELS | 2812 | CXT5066_MODELS |
2443 | }; | 2813 | }; |
2444 | 2814 | ||
@@ -2446,7 +2816,8 @@ static const char *cxt5066_models[CXT5066_MODELS] = { | |||
2446 | [CXT5066_LAPTOP] = "laptop", | 2816 | [CXT5066_LAPTOP] = "laptop", |
2447 | [CXT5066_DELL_LAPTOP] = "dell-laptop", | 2817 | [CXT5066_DELL_LAPTOP] = "dell-laptop", |
2448 | [CXT5066_OLPC_XO_1_5] = "olpc-xo-1_5", | 2818 | [CXT5066_OLPC_XO_1_5] = "olpc-xo-1_5", |
2449 | [CXT5066_DELL_VOSTO] = "dell-vostro" | 2819 | [CXT5066_DELL_VOSTO] = "dell-vostro", |
2820 | [CXT5066_IDEAPAD] = "ideapad", | ||
2450 | }; | 2821 | }; |
2451 | 2822 | ||
2452 | static struct snd_pci_quirk cxt5066_cfg_tbl[] = { | 2823 | static struct snd_pci_quirk cxt5066_cfg_tbl[] = { |
@@ -2456,6 +2827,7 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = { | |||
2456 | CXT5066_DELL_LAPTOP), | 2827 | CXT5066_DELL_LAPTOP), |
2457 | SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5), | 2828 | SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5), |
2458 | SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTO), | 2829 | SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTO), |
2830 | SND_PCI_QUIRK(0x17aa, 0x3a0d, "ideapad", CXT5066_IDEAPAD), | ||
2459 | {} | 2831 | {} |
2460 | }; | 2832 | }; |
2461 | 2833 | ||
@@ -2470,7 +2842,7 @@ static int patch_cxt5066(struct hda_codec *codec) | |||
2470 | codec->spec = spec; | 2842 | codec->spec = spec; |
2471 | 2843 | ||
2472 | codec->patch_ops = conexant_patch_ops; | 2844 | codec->patch_ops = conexant_patch_ops; |
2473 | codec->patch_ops.init = cxt5066_init; | 2845 | codec->patch_ops.init = conexant_init; |
2474 | 2846 | ||
2475 | spec->dell_automute = 0; | 2847 | spec->dell_automute = 0; |
2476 | spec->multiout.max_channels = 2; | 2848 | spec->multiout.max_channels = 2; |
@@ -2483,7 +2855,6 @@ static int patch_cxt5066(struct hda_codec *codec) | |||
2483 | spec->input_mux = &cxt5066_capture_source; | 2855 | spec->input_mux = &cxt5066_capture_source; |
2484 | 2856 | ||
2485 | spec->port_d_mode = PIN_HP; | 2857 | spec->port_d_mode = PIN_HP; |
2486 | spec->ext_mic_bias = PIN_VREF80; | ||
2487 | 2858 | ||
2488 | spec->num_init_verbs = 1; | 2859 | spec->num_init_verbs = 1; |
2489 | spec->init_verbs[0] = cxt5066_init_verbs; | 2860 | spec->init_verbs[0] = cxt5066_init_verbs; |
@@ -2510,20 +2881,28 @@ static int patch_cxt5066(struct hda_codec *codec) | |||
2510 | spec->dell_automute = 1; | 2881 | spec->dell_automute = 1; |
2511 | break; | 2882 | break; |
2512 | case CXT5066_OLPC_XO_1_5: | 2883 | case CXT5066_OLPC_XO_1_5: |
2513 | codec->patch_ops.unsol_event = cxt5066_unsol_event; | 2884 | codec->patch_ops.init = cxt5066_olpc_init; |
2885 | codec->patch_ops.unsol_event = cxt5066_olpc_unsol_event; | ||
2514 | spec->init_verbs[0] = cxt5066_init_verbs_olpc; | 2886 | spec->init_verbs[0] = cxt5066_init_verbs_olpc; |
2515 | spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc; | 2887 | spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc; |
2888 | spec->mixers[spec->num_mixers++] = cxt5066_mixer_olpc_dc; | ||
2516 | spec->mixers[spec->num_mixers++] = cxt5066_mixers; | 2889 | spec->mixers[spec->num_mixers++] = cxt5066_mixers; |
2517 | spec->port_d_mode = 0; | 2890 | spec->port_d_mode = 0; |
2518 | spec->ext_mic_bias = CXT5066_OLPC_EXT_MIC_BIAS; | 2891 | spec->mic_boost = 3; /* default 30dB gain */ |
2519 | 2892 | ||
2520 | /* no S/PDIF out */ | 2893 | /* no S/PDIF out */ |
2521 | spec->multiout.dig_out_nid = 0; | 2894 | spec->multiout.dig_out_nid = 0; |
2522 | 2895 | ||
2523 | /* input source automatically selected */ | 2896 | /* input source automatically selected */ |
2524 | spec->input_mux = NULL; | 2897 | spec->input_mux = NULL; |
2898 | |||
2899 | /* our capture hooks which allow us to turn on the microphone LED | ||
2900 | * at the right time */ | ||
2901 | spec->capture_prepare = cxt5066_olpc_capture_prepare; | ||
2902 | spec->capture_cleanup = cxt5066_olpc_capture_cleanup; | ||
2525 | break; | 2903 | break; |
2526 | case CXT5066_DELL_VOSTO: | 2904 | case CXT5066_DELL_VOSTO: |
2905 | codec->patch_ops.init = cxt5066_init; | ||
2527 | codec->patch_ops.unsol_event = cxt5066_vostro_event; | 2906 | codec->patch_ops.unsol_event = cxt5066_vostro_event; |
2528 | spec->init_verbs[0] = cxt5066_init_verbs_vostro; | 2907 | spec->init_verbs[0] = cxt5066_init_verbs_vostro; |
2529 | spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc; | 2908 | spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc; |
@@ -2531,6 +2910,7 @@ static int patch_cxt5066(struct hda_codec *codec) | |||
2531 | spec->mixers[spec->num_mixers++] = cxt5066_vostro_mixers; | 2910 | spec->mixers[spec->num_mixers++] = cxt5066_vostro_mixers; |
2532 | spec->port_d_mode = 0; | 2911 | spec->port_d_mode = 0; |
2533 | spec->dell_vostro = 1; | 2912 | spec->dell_vostro = 1; |
2913 | spec->mic_boost = 3; /* default 30dB gain */ | ||
2534 | snd_hda_attach_beep_device(codec, 0x13); | 2914 | snd_hda_attach_beep_device(codec, 0x13); |
2535 | 2915 | ||
2536 | /* no S/PDIF out */ | 2916 | /* no S/PDIF out */ |
@@ -2539,6 +2919,22 @@ static int patch_cxt5066(struct hda_codec *codec) | |||
2539 | /* input source automatically selected */ | 2919 | /* input source automatically selected */ |
2540 | spec->input_mux = NULL; | 2920 | spec->input_mux = NULL; |
2541 | break; | 2921 | break; |
2922 | case CXT5066_IDEAPAD: | ||
2923 | codec->patch_ops.init = cxt5066_init; | ||
2924 | codec->patch_ops.unsol_event = cxt5066_ideapad_event; | ||
2925 | spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; | ||
2926 | spec->mixers[spec->num_mixers++] = cxt5066_mixers; | ||
2927 | spec->init_verbs[0] = cxt5066_init_verbs_ideapad; | ||
2928 | spec->port_d_mode = 0; | ||
2929 | spec->ideapad = 1; | ||
2930 | spec->mic_boost = 2; /* default 20dB gain */ | ||
2931 | |||
2932 | /* no S/PDIF out */ | ||
2933 | spec->multiout.dig_out_nid = 0; | ||
2934 | |||
2935 | /* input source automatically selected */ | ||
2936 | spec->input_mux = NULL; | ||
2937 | break; | ||
2542 | } | 2938 | } |
2543 | 2939 | ||
2544 | return 0; | 2940 | return 0; |
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index da34095c707f..e8cbe216e912 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c | |||
@@ -131,8 +131,10 @@ enum { | |||
131 | enum { | 131 | enum { |
132 | ALC269_BASIC, | 132 | ALC269_BASIC, |
133 | ALC269_QUANTA_FL1, | 133 | ALC269_QUANTA_FL1, |
134 | ALC269_ASUS_AMIC, | 134 | ALC269_AMIC, |
135 | ALC269_ASUS_DMIC, | 135 | ALC269_DMIC, |
136 | ALC269VB_AMIC, | ||
137 | ALC269VB_DMIC, | ||
136 | ALC269_FUJITSU, | 138 | ALC269_FUJITSU, |
137 | ALC269_LIFEBOOK, | 139 | ALC269_LIFEBOOK, |
138 | ALC269_AUTO, | 140 | ALC269_AUTO, |
@@ -207,8 +209,10 @@ enum { | |||
207 | ALC882_ASUS_A7J, | 209 | ALC882_ASUS_A7J, |
208 | ALC882_ASUS_A7M, | 210 | ALC882_ASUS_A7M, |
209 | ALC885_MACPRO, | 211 | ALC885_MACPRO, |
212 | ALC885_MBA21, | ||
210 | ALC885_MBP3, | 213 | ALC885_MBP3, |
211 | ALC885_MB5, | 214 | ALC885_MB5, |
215 | ALC885_MACMINI3, | ||
212 | ALC885_IMAC24, | 216 | ALC885_IMAC24, |
213 | ALC885_IMAC91, | 217 | ALC885_IMAC91, |
214 | ALC883_3ST_2ch_DIG, | 218 | ALC883_3ST_2ch_DIG, |
@@ -338,7 +342,7 @@ struct alc_spec { | |||
338 | void (*init_hook)(struct hda_codec *codec); | 342 | void (*init_hook)(struct hda_codec *codec); |
339 | void (*unsol_event)(struct hda_codec *codec, unsigned int res); | 343 | void (*unsol_event)(struct hda_codec *codec, unsigned int res); |
340 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 344 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
341 | void (*power_hook)(struct hda_codec *codec, int power); | 345 | void (*power_hook)(struct hda_codec *codec); |
342 | #endif | 346 | #endif |
343 | 347 | ||
344 | /* for pin sensing */ | 348 | /* for pin sensing */ |
@@ -391,7 +395,7 @@ struct alc_config_preset { | |||
391 | void (*init_hook)(struct hda_codec *); | 395 | void (*init_hook)(struct hda_codec *); |
392 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 396 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
393 | struct hda_amp_list *loopbacks; | 397 | struct hda_amp_list *loopbacks; |
394 | void (*power_hook)(struct hda_codec *codec, int power); | 398 | void (*power_hook)(struct hda_codec *codec); |
395 | #endif | 399 | #endif |
396 | }; | 400 | }; |
397 | 401 | ||
@@ -633,6 +637,7 @@ static int alc_pin_mode_put(struct snd_kcontrol *kcontrol, | |||
633 | 637 | ||
634 | #define ALC_PIN_MODE(xname, nid, dir) \ | 638 | #define ALC_PIN_MODE(xname, nid, dir) \ |
635 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ | 639 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ |
640 | .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ | ||
636 | .info = alc_pin_mode_info, \ | 641 | .info = alc_pin_mode_info, \ |
637 | .get = alc_pin_mode_get, \ | 642 | .get = alc_pin_mode_get, \ |
638 | .put = alc_pin_mode_put, \ | 643 | .put = alc_pin_mode_put, \ |
@@ -684,6 +689,7 @@ static int alc_gpio_data_put(struct snd_kcontrol *kcontrol, | |||
684 | } | 689 | } |
685 | #define ALC_GPIO_DATA_SWITCH(xname, nid, mask) \ | 690 | #define ALC_GPIO_DATA_SWITCH(xname, nid, mask) \ |
686 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ | 691 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ |
692 | .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ | ||
687 | .info = alc_gpio_data_info, \ | 693 | .info = alc_gpio_data_info, \ |
688 | .get = alc_gpio_data_get, \ | 694 | .get = alc_gpio_data_get, \ |
689 | .put = alc_gpio_data_put, \ | 695 | .put = alc_gpio_data_put, \ |
@@ -738,6 +744,7 @@ static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol, | |||
738 | } | 744 | } |
739 | #define ALC_SPDIF_CTRL_SWITCH(xname, nid, mask) \ | 745 | #define ALC_SPDIF_CTRL_SWITCH(xname, nid, mask) \ |
740 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ | 746 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ |
747 | .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ | ||
741 | .info = alc_spdif_ctrl_info, \ | 748 | .info = alc_spdif_ctrl_info, \ |
742 | .get = alc_spdif_ctrl_get, \ | 749 | .get = alc_spdif_ctrl_get, \ |
743 | .put = alc_spdif_ctrl_put, \ | 750 | .put = alc_spdif_ctrl_put, \ |
@@ -791,6 +798,7 @@ static int alc_eapd_ctrl_put(struct snd_kcontrol *kcontrol, | |||
791 | 798 | ||
792 | #define ALC_EAPD_CTRL_SWITCH(xname, nid, mask) \ | 799 | #define ALC_EAPD_CTRL_SWITCH(xname, nid, mask) \ |
793 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ | 800 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ |
801 | .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ | ||
794 | .info = alc_eapd_ctrl_info, \ | 802 | .info = alc_eapd_ctrl_info, \ |
795 | .get = alc_eapd_ctrl_get, \ | 803 | .get = alc_eapd_ctrl_get, \ |
796 | .put = alc_eapd_ctrl_put, \ | 804 | .put = alc_eapd_ctrl_put, \ |
@@ -837,27 +845,6 @@ static void add_verb(struct alc_spec *spec, const struct hda_verb *verb) | |||
837 | spec->init_verbs[spec->num_init_verbs++] = verb; | 845 | spec->init_verbs[spec->num_init_verbs++] = verb; |
838 | } | 846 | } |
839 | 847 | ||
840 | #ifdef CONFIG_PROC_FS | ||
841 | /* | ||
842 | * hook for proc | ||
843 | */ | ||
844 | static void print_realtek_coef(struct snd_info_buffer *buffer, | ||
845 | struct hda_codec *codec, hda_nid_t nid) | ||
846 | { | ||
847 | int coeff; | ||
848 | |||
849 | if (nid != 0x20) | ||
850 | return; | ||
851 | coeff = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PROC_COEF, 0); | ||
852 | snd_iprintf(buffer, " Processing Coefficient: 0x%02x\n", coeff); | ||
853 | coeff = snd_hda_codec_read(codec, nid, 0, | ||
854 | AC_VERB_GET_COEF_INDEX, 0); | ||
855 | snd_iprintf(buffer, " Coefficient Index: 0x%02x\n", coeff); | ||
856 | } | ||
857 | #else | ||
858 | #define print_realtek_coef NULL | ||
859 | #endif | ||
860 | |||
861 | /* | 848 | /* |
862 | * set up from the preset table | 849 | * set up from the preset table |
863 | */ | 850 | */ |
@@ -1162,6 +1149,7 @@ static void alc_auto_init_amp(struct hda_codec *codec, int type) | |||
1162 | case 0x10ec0888: | 1149 | case 0x10ec0888: |
1163 | alc888_coef_init(codec); | 1150 | alc888_coef_init(codec); |
1164 | break; | 1151 | break; |
1152 | #if 0 /* XXX: This may cause the silent output on speaker on some machines */ | ||
1165 | case 0x10ec0267: | 1153 | case 0x10ec0267: |
1166 | case 0x10ec0268: | 1154 | case 0x10ec0268: |
1167 | snd_hda_codec_write(codec, 0x20, 0, | 1155 | snd_hda_codec_write(codec, 0x20, 0, |
@@ -1174,6 +1162,7 @@ static void alc_auto_init_amp(struct hda_codec *codec, int type) | |||
1174 | AC_VERB_SET_PROC_COEF, | 1162 | AC_VERB_SET_PROC_COEF, |
1175 | tmp | 0x3000); | 1163 | tmp | 0x3000); |
1176 | break; | 1164 | break; |
1165 | #endif /* XXX */ | ||
1177 | } | 1166 | } |
1178 | break; | 1167 | break; |
1179 | } | 1168 | } |
@@ -1265,7 +1254,7 @@ static void alc_init_auto_mic(struct hda_codec *codec) | |||
1265 | */ | 1254 | */ |
1266 | static int alc_subsystem_id(struct hda_codec *codec, | 1255 | static int alc_subsystem_id(struct hda_codec *codec, |
1267 | hda_nid_t porta, hda_nid_t porte, | 1256 | hda_nid_t porta, hda_nid_t porte, |
1268 | hda_nid_t portd) | 1257 | hda_nid_t portd, hda_nid_t porti) |
1269 | { | 1258 | { |
1270 | unsigned int ass, tmp, i; | 1259 | unsigned int ass, tmp, i; |
1271 | unsigned nid; | 1260 | unsigned nid; |
@@ -1291,7 +1280,7 @@ static int alc_subsystem_id(struct hda_codec *codec, | |||
1291 | snd_printd("realtek: No valid SSID, " | 1280 | snd_printd("realtek: No valid SSID, " |
1292 | "checking pincfg 0x%08x for NID 0x%x\n", | 1281 | "checking pincfg 0x%08x for NID 0x%x\n", |
1293 | ass, nid); | 1282 | ass, nid); |
1294 | if (!(ass & 1) && !(ass & 0x100000)) | 1283 | if (!(ass & 1)) |
1295 | return 0; | 1284 | return 0; |
1296 | if ((ass >> 30) != 1) /* no physical connection */ | 1285 | if ((ass >> 30) != 1) /* no physical connection */ |
1297 | return 0; | 1286 | return 0; |
@@ -1351,6 +1340,8 @@ do_sku: | |||
1351 | nid = porte; | 1340 | nid = porte; |
1352 | else if (tmp == 2) | 1341 | else if (tmp == 2) |
1353 | nid = portd; | 1342 | nid = portd; |
1343 | else if (tmp == 3) | ||
1344 | nid = porti; | ||
1354 | else | 1345 | else |
1355 | return 1; | 1346 | return 1; |
1356 | for (i = 0; i < spec->autocfg.line_outs; i++) | 1347 | for (i = 0; i < spec->autocfg.line_outs; i++) |
@@ -1365,9 +1356,10 @@ do_sku: | |||
1365 | } | 1356 | } |
1366 | 1357 | ||
1367 | static void alc_ssid_check(struct hda_codec *codec, | 1358 | static void alc_ssid_check(struct hda_codec *codec, |
1368 | hda_nid_t porta, hda_nid_t porte, hda_nid_t portd) | 1359 | hda_nid_t porta, hda_nid_t porte, |
1360 | hda_nid_t portd, hda_nid_t porti) | ||
1369 | { | 1361 | { |
1370 | if (!alc_subsystem_id(codec, porta, porte, portd)) { | 1362 | if (!alc_subsystem_id(codec, porta, porte, portd, porti)) { |
1371 | struct alc_spec *spec = codec->spec; | 1363 | struct alc_spec *spec = codec->spec; |
1372 | snd_printd("realtek: " | 1364 | snd_printd("realtek: " |
1373 | "Enable default setup for auto mode as fallback\n"); | 1365 | "Enable default setup for auto mode as fallback\n"); |
@@ -1840,14 +1832,6 @@ static void alc889_acer_aspire_8930g_setup(struct hda_codec *codec) | |||
1840 | spec->autocfg.speaker_pins[2] = 0x1b; | 1832 | spec->autocfg.speaker_pins[2] = 0x1b; |
1841 | } | 1833 | } |
1842 | 1834 | ||
1843 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
1844 | static void alc889_power_eapd(struct hda_codec *codec, int power) | ||
1845 | { | ||
1846 | set_eapd(codec, 0x14, power); | ||
1847 | set_eapd(codec, 0x15, power); | ||
1848 | } | ||
1849 | #endif | ||
1850 | |||
1851 | /* | 1835 | /* |
1852 | * ALC880 3-stack model | 1836 | * ALC880 3-stack model |
1853 | * | 1837 | * |
@@ -2450,6 +2434,15 @@ static const char *alc_slave_sws[] = { | |||
2450 | * build control elements | 2434 | * build control elements |
2451 | */ | 2435 | */ |
2452 | 2436 | ||
2437 | #define NID_MAPPING (-1) | ||
2438 | |||
2439 | #define SUBDEV_SPEAKER_ (0 << 6) | ||
2440 | #define SUBDEV_HP_ (1 << 6) | ||
2441 | #define SUBDEV_LINE_ (2 << 6) | ||
2442 | #define SUBDEV_SPEAKER(x) (SUBDEV_SPEAKER_ | ((x) & 0x3f)) | ||
2443 | #define SUBDEV_HP(x) (SUBDEV_HP_ | ((x) & 0x3f)) | ||
2444 | #define SUBDEV_LINE(x) (SUBDEV_LINE_ | ((x) & 0x3f)) | ||
2445 | |||
2453 | static void alc_free_kctls(struct hda_codec *codec); | 2446 | static void alc_free_kctls(struct hda_codec *codec); |
2454 | 2447 | ||
2455 | #ifdef CONFIG_SND_HDA_INPUT_BEEP | 2448 | #ifdef CONFIG_SND_HDA_INPUT_BEEP |
@@ -2464,8 +2457,11 @@ static struct snd_kcontrol_new alc_beep_mixer[] = { | |||
2464 | static int alc_build_controls(struct hda_codec *codec) | 2457 | static int alc_build_controls(struct hda_codec *codec) |
2465 | { | 2458 | { |
2466 | struct alc_spec *spec = codec->spec; | 2459 | struct alc_spec *spec = codec->spec; |
2467 | int err; | 2460 | struct snd_kcontrol *kctl; |
2468 | int i; | 2461 | struct snd_kcontrol_new *knew; |
2462 | int i, j, err; | ||
2463 | unsigned int u; | ||
2464 | hda_nid_t nid; | ||
2469 | 2465 | ||
2470 | for (i = 0; i < spec->num_mixers; i++) { | 2466 | for (i = 0; i < spec->num_mixers; i++) { |
2471 | err = snd_hda_add_new_ctls(codec, spec->mixers[i]); | 2467 | err = snd_hda_add_new_ctls(codec, spec->mixers[i]); |
@@ -2506,8 +2502,7 @@ static int alc_build_controls(struct hda_codec *codec) | |||
2506 | if (!kctl) | 2502 | if (!kctl) |
2507 | return -ENOMEM; | 2503 | return -ENOMEM; |
2508 | kctl->private_value = spec->beep_amp; | 2504 | kctl->private_value = spec->beep_amp; |
2509 | err = snd_hda_ctl_add(codec, | 2505 | err = snd_hda_ctl_add(codec, 0, kctl); |
2510 | get_amp_nid_(spec->beep_amp), kctl); | ||
2511 | if (err < 0) | 2506 | if (err < 0) |
2512 | return err; | 2507 | return err; |
2513 | } | 2508 | } |
@@ -2534,6 +2529,75 @@ static int alc_build_controls(struct hda_codec *codec) | |||
2534 | } | 2529 | } |
2535 | 2530 | ||
2536 | alc_free_kctls(codec); /* no longer needed */ | 2531 | alc_free_kctls(codec); /* no longer needed */ |
2532 | |||
2533 | /* assign Capture Source enums to NID */ | ||
2534 | kctl = snd_hda_find_mixer_ctl(codec, "Capture Source"); | ||
2535 | if (!kctl) | ||
2536 | kctl = snd_hda_find_mixer_ctl(codec, "Input Source"); | ||
2537 | for (i = 0; kctl && i < kctl->count; i++) { | ||
2538 | hda_nid_t *nids = spec->capsrc_nids; | ||
2539 | if (!nids) | ||
2540 | nids = spec->adc_nids; | ||
2541 | err = snd_hda_add_nid(codec, kctl, i, nids[i]); | ||
2542 | if (err < 0) | ||
2543 | return err; | ||
2544 | } | ||
2545 | if (spec->cap_mixer) { | ||
2546 | const char *kname = kctl ? kctl->id.name : NULL; | ||
2547 | for (knew = spec->cap_mixer; knew->name; knew++) { | ||
2548 | if (kname && strcmp(knew->name, kname) == 0) | ||
2549 | continue; | ||
2550 | kctl = snd_hda_find_mixer_ctl(codec, knew->name); | ||
2551 | for (i = 0; kctl && i < kctl->count; i++) { | ||
2552 | err = snd_hda_add_nid(codec, kctl, i, | ||
2553 | spec->adc_nids[i]); | ||
2554 | if (err < 0) | ||
2555 | return err; | ||
2556 | } | ||
2557 | } | ||
2558 | } | ||
2559 | |||
2560 | /* other nid->control mapping */ | ||
2561 | for (i = 0; i < spec->num_mixers; i++) { | ||
2562 | for (knew = spec->mixers[i]; knew->name; knew++) { | ||
2563 | if (knew->iface != NID_MAPPING) | ||
2564 | continue; | ||
2565 | kctl = snd_hda_find_mixer_ctl(codec, knew->name); | ||
2566 | if (kctl == NULL) | ||
2567 | continue; | ||
2568 | u = knew->subdevice; | ||
2569 | for (j = 0; j < 4; j++, u >>= 8) { | ||
2570 | nid = u & 0x3f; | ||
2571 | if (nid == 0) | ||
2572 | continue; | ||
2573 | switch (u & 0xc0) { | ||
2574 | case SUBDEV_SPEAKER_: | ||
2575 | nid = spec->autocfg.speaker_pins[nid]; | ||
2576 | break; | ||
2577 | case SUBDEV_LINE_: | ||
2578 | nid = spec->autocfg.line_out_pins[nid]; | ||
2579 | break; | ||
2580 | case SUBDEV_HP_: | ||
2581 | nid = spec->autocfg.hp_pins[nid]; | ||
2582 | break; | ||
2583 | default: | ||
2584 | continue; | ||
2585 | } | ||
2586 | err = snd_hda_add_nid(codec, kctl, 0, nid); | ||
2587 | if (err < 0) | ||
2588 | return err; | ||
2589 | } | ||
2590 | u = knew->private_value; | ||
2591 | for (j = 0; j < 4; j++, u >>= 8) { | ||
2592 | nid = u & 0xff; | ||
2593 | if (nid == 0) | ||
2594 | continue; | ||
2595 | err = snd_hda_add_nid(codec, kctl, 0, nid); | ||
2596 | if (err < 0) | ||
2597 | return err; | ||
2598 | } | ||
2599 | } | ||
2600 | } | ||
2537 | return 0; | 2601 | return 0; |
2538 | } | 2602 | } |
2539 | 2603 | ||
@@ -3616,6 +3680,11 @@ static int alc_build_pcms(struct hda_codec *codec) | |||
3616 | return 0; | 3680 | return 0; |
3617 | } | 3681 | } |
3618 | 3682 | ||
3683 | static inline void alc_shutup(struct hda_codec *codec) | ||
3684 | { | ||
3685 | snd_hda_shutup_pins(codec); | ||
3686 | } | ||
3687 | |||
3619 | static void alc_free_kctls(struct hda_codec *codec) | 3688 | static void alc_free_kctls(struct hda_codec *codec) |
3620 | { | 3689 | { |
3621 | struct alc_spec *spec = codec->spec; | 3690 | struct alc_spec *spec = codec->spec; |
@@ -3636,17 +3705,44 @@ static void alc_free(struct hda_codec *codec) | |||
3636 | if (!spec) | 3705 | if (!spec) |
3637 | return; | 3706 | return; |
3638 | 3707 | ||
3708 | alc_shutup(codec); | ||
3639 | alc_free_kctls(codec); | 3709 | alc_free_kctls(codec); |
3640 | kfree(spec); | 3710 | kfree(spec); |
3641 | snd_hda_detach_beep_device(codec); | 3711 | snd_hda_detach_beep_device(codec); |
3642 | } | 3712 | } |
3643 | 3713 | ||
3644 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 3714 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
3715 | static void alc_power_eapd(struct hda_codec *codec) | ||
3716 | { | ||
3717 | /* We currently only handle front, HP */ | ||
3718 | switch (codec->vendor_id) { | ||
3719 | case 0x10ec0260: | ||
3720 | set_eapd(codec, 0x0f, 0); | ||
3721 | set_eapd(codec, 0x10, 0); | ||
3722 | break; | ||
3723 | case 0x10ec0262: | ||
3724 | case 0x10ec0267: | ||
3725 | case 0x10ec0268: | ||
3726 | case 0x10ec0269: | ||
3727 | case 0x10ec0270: | ||
3728 | case 0x10ec0272: | ||
3729 | case 0x10ec0660: | ||
3730 | case 0x10ec0662: | ||
3731 | case 0x10ec0663: | ||
3732 | case 0x10ec0862: | ||
3733 | case 0x10ec0889: | ||
3734 | set_eapd(codec, 0x14, 0); | ||
3735 | set_eapd(codec, 0x15, 0); | ||
3736 | break; | ||
3737 | } | ||
3738 | } | ||
3739 | |||
3645 | static int alc_suspend(struct hda_codec *codec, pm_message_t state) | 3740 | static int alc_suspend(struct hda_codec *codec, pm_message_t state) |
3646 | { | 3741 | { |
3647 | struct alc_spec *spec = codec->spec; | 3742 | struct alc_spec *spec = codec->spec; |
3743 | alc_shutup(codec); | ||
3648 | if (spec && spec->power_hook) | 3744 | if (spec && spec->power_hook) |
3649 | spec->power_hook(codec, 0); | 3745 | spec->power_hook(codec); |
3650 | return 0; | 3746 | return 0; |
3651 | } | 3747 | } |
3652 | #endif | 3748 | #endif |
@@ -3654,16 +3750,9 @@ static int alc_suspend(struct hda_codec *codec, pm_message_t state) | |||
3654 | #ifdef SND_HDA_NEEDS_RESUME | 3750 | #ifdef SND_HDA_NEEDS_RESUME |
3655 | static int alc_resume(struct hda_codec *codec) | 3751 | static int alc_resume(struct hda_codec *codec) |
3656 | { | 3752 | { |
3657 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
3658 | struct alc_spec *spec = codec->spec; | ||
3659 | #endif | ||
3660 | codec->patch_ops.init(codec); | 3753 | codec->patch_ops.init(codec); |
3661 | snd_hda_codec_resume_amp(codec); | 3754 | snd_hda_codec_resume_amp(codec); |
3662 | snd_hda_codec_resume_cache(codec); | 3755 | snd_hda_codec_resume_cache(codec); |
3663 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
3664 | if (spec && spec->power_hook) | ||
3665 | spec->power_hook(codec, 1); | ||
3666 | #endif | ||
3667 | return 0; | 3756 | return 0; |
3668 | } | 3757 | } |
3669 | #endif | 3758 | #endif |
@@ -3683,6 +3772,7 @@ static struct hda_codec_ops alc_patch_ops = { | |||
3683 | .suspend = alc_suspend, | 3772 | .suspend = alc_suspend, |
3684 | .check_power_status = alc_check_power_status, | 3773 | .check_power_status = alc_check_power_status, |
3685 | #endif | 3774 | #endif |
3775 | .reboot_notify = alc_shutup, | ||
3686 | }; | 3776 | }; |
3687 | 3777 | ||
3688 | 3778 | ||
@@ -3839,6 +3929,7 @@ static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol, | |||
3839 | #define PIN_CTL_TEST(xname,nid) { \ | 3929 | #define PIN_CTL_TEST(xname,nid) { \ |
3840 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | 3930 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ |
3841 | .name = xname, \ | 3931 | .name = xname, \ |
3932 | .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ | ||
3842 | .info = alc_test_pin_ctl_info, \ | 3933 | .info = alc_test_pin_ctl_info, \ |
3843 | .get = alc_test_pin_ctl_get, \ | 3934 | .get = alc_test_pin_ctl_get, \ |
3844 | .put = alc_test_pin_ctl_put, \ | 3935 | .put = alc_test_pin_ctl_put, \ |
@@ -3848,6 +3939,7 @@ static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol, | |||
3848 | #define PIN_SRC_TEST(xname,nid) { \ | 3939 | #define PIN_SRC_TEST(xname,nid) { \ |
3849 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | 3940 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ |
3850 | .name = xname, \ | 3941 | .name = xname, \ |
3942 | .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ | ||
3851 | .info = alc_test_pin_src_info, \ | 3943 | .info = alc_test_pin_src_info, \ |
3852 | .get = alc_test_pin_src_get, \ | 3944 | .get = alc_test_pin_src_get, \ |
3853 | .put = alc_test_pin_src_put, \ | 3945 | .put = alc_test_pin_src_put, \ |
@@ -4387,7 +4479,7 @@ static int add_control(struct alc_spec *spec, int type, const char *name, | |||
4387 | if (!knew->name) | 4479 | if (!knew->name) |
4388 | return -ENOMEM; | 4480 | return -ENOMEM; |
4389 | if (get_amp_nid_(val)) | 4481 | if (get_amp_nid_(val)) |
4390 | knew->subdevice = HDA_SUBDEV_NID_FLAG | get_amp_nid_(val); | 4482 | knew->subdevice = HDA_SUBDEV_AMP_FLAG; |
4391 | knew->private_value = val; | 4483 | knew->private_value = val; |
4392 | return 0; | 4484 | return 0; |
4393 | } | 4485 | } |
@@ -4770,7 +4862,7 @@ static int alc880_parse_auto_config(struct hda_codec *codec) | |||
4770 | spec->num_mux_defs = 1; | 4862 | spec->num_mux_defs = 1; |
4771 | spec->input_mux = &spec->private_imux[0]; | 4863 | spec->input_mux = &spec->private_imux[0]; |
4772 | 4864 | ||
4773 | alc_ssid_check(codec, 0x15, 0x1b, 0x14); | 4865 | alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0); |
4774 | 4866 | ||
4775 | return 1; | 4867 | return 1; |
4776 | } | 4868 | } |
@@ -4974,7 +5066,6 @@ static int patch_alc880(struct hda_codec *codec) | |||
4974 | if (!spec->loopback.amplist) | 5066 | if (!spec->loopback.amplist) |
4975 | spec->loopback.amplist = alc880_loopbacks; | 5067 | spec->loopback.amplist = alc880_loopbacks; |
4976 | #endif | 5068 | #endif |
4977 | codec->proc_widget_hook = print_realtek_coef; | ||
4978 | 5069 | ||
4979 | return 0; | 5070 | return 0; |
4980 | } | 5071 | } |
@@ -5182,6 +5273,7 @@ static struct snd_kcontrol_new alc260_hp_output_mixer[] = { | |||
5182 | { | 5273 | { |
5183 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 5274 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
5184 | .name = "Master Playback Switch", | 5275 | .name = "Master Playback Switch", |
5276 | .subdevice = HDA_SUBDEV_NID_FLAG | 0x11, | ||
5185 | .info = snd_ctl_boolean_mono_info, | 5277 | .info = snd_ctl_boolean_mono_info, |
5186 | .get = alc260_hp_master_sw_get, | 5278 | .get = alc260_hp_master_sw_get, |
5187 | .put = alc260_hp_master_sw_put, | 5279 | .put = alc260_hp_master_sw_put, |
@@ -5220,6 +5312,7 @@ static struct snd_kcontrol_new alc260_hp_3013_mixer[] = { | |||
5220 | { | 5312 | { |
5221 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 5313 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
5222 | .name = "Master Playback Switch", | 5314 | .name = "Master Playback Switch", |
5315 | .subdevice = HDA_SUBDEV_NID_FLAG | 0x11, | ||
5223 | .info = snd_ctl_boolean_mono_info, | 5316 | .info = snd_ctl_boolean_mono_info, |
5224 | .get = alc260_hp_master_sw_get, | 5317 | .get = alc260_hp_master_sw_get, |
5225 | .put = alc260_hp_master_sw_put, | 5318 | .put = alc260_hp_master_sw_put, |
@@ -6303,7 +6396,7 @@ static int alc260_parse_auto_config(struct hda_codec *codec) | |||
6303 | spec->num_mux_defs = 1; | 6396 | spec->num_mux_defs = 1; |
6304 | spec->input_mux = &spec->private_imux[0]; | 6397 | spec->input_mux = &spec->private_imux[0]; |
6305 | 6398 | ||
6306 | alc_ssid_check(codec, 0x10, 0x15, 0x0f); | 6399 | alc_ssid_check(codec, 0x10, 0x15, 0x0f, 0); |
6307 | 6400 | ||
6308 | return 1; | 6401 | return 1; |
6309 | } | 6402 | } |
@@ -6582,7 +6675,6 @@ static int patch_alc260(struct hda_codec *codec) | |||
6582 | if (!spec->loopback.amplist) | 6675 | if (!spec->loopback.amplist) |
6583 | spec->loopback.amplist = alc260_loopbacks; | 6676 | spec->loopback.amplist = alc260_loopbacks; |
6584 | #endif | 6677 | #endif |
6585 | codec->proc_widget_hook = print_realtek_coef; | ||
6586 | 6678 | ||
6587 | return 0; | 6679 | return 0; |
6588 | } | 6680 | } |
@@ -6664,6 +6756,14 @@ static struct hda_input_mux mb5_capture_source = { | |||
6664 | }, | 6756 | }, |
6665 | }; | 6757 | }; |
6666 | 6758 | ||
6759 | static struct hda_input_mux macmini3_capture_source = { | ||
6760 | .num_items = 2, | ||
6761 | .items = { | ||
6762 | { "Line", 0x2 }, | ||
6763 | { "CD", 0x4 }, | ||
6764 | }, | ||
6765 | }; | ||
6766 | |||
6667 | static struct hda_input_mux alc883_3stack_6ch_intel = { | 6767 | static struct hda_input_mux alc883_3stack_6ch_intel = { |
6668 | .num_items = 4, | 6768 | .num_items = 4, |
6669 | .items = { | 6769 | .items = { |
@@ -6852,6 +6952,13 @@ static struct hda_channel_mode alc882_sixstack_modes[2] = { | |||
6852 | { 8, alc882_sixstack_ch8_init }, | 6952 | { 8, alc882_sixstack_ch8_init }, |
6853 | }; | 6953 | }; |
6854 | 6954 | ||
6955 | |||
6956 | /* Macbook Air 2,1 */ | ||
6957 | |||
6958 | static struct hda_channel_mode alc885_mba21_ch_modes[1] = { | ||
6959 | { 2, NULL }, | ||
6960 | }; | ||
6961 | |||
6855 | /* | 6962 | /* |
6856 | * macbook pro ALC885 can switch LineIn to LineOut without losing Mic | 6963 | * macbook pro ALC885 can switch LineIn to LineOut without losing Mic |
6857 | */ | 6964 | */ |
@@ -6912,6 +7019,7 @@ static struct hda_channel_mode alc885_mb5_6ch_modes[2] = { | |||
6912 | { 6, alc885_mb5_ch6_init }, | 7019 | { 6, alc885_mb5_ch6_init }, |
6913 | }; | 7020 | }; |
6914 | 7021 | ||
7022 | #define alc885_macmini3_6ch_modes alc885_mb5_6ch_modes | ||
6915 | 7023 | ||
6916 | /* | 7024 | /* |
6917 | * 2ch mode | 7025 | * 2ch mode |
@@ -7123,6 +7231,15 @@ static struct snd_kcontrol_new alc882_base_mixer[] = { | |||
7123 | { } /* end */ | 7231 | { } /* end */ |
7124 | }; | 7232 | }; |
7125 | 7233 | ||
7234 | /* Macbook Air 2,1 same control for HP and internal Speaker */ | ||
7235 | |||
7236 | static struct snd_kcontrol_new alc885_mba21_mixer[] = { | ||
7237 | HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT), | ||
7238 | HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_OUTPUT), | ||
7239 | { } | ||
7240 | }; | ||
7241 | |||
7242 | |||
7126 | static struct snd_kcontrol_new alc885_mbp3_mixer[] = { | 7243 | static struct snd_kcontrol_new alc885_mbp3_mixer[] = { |
7127 | HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT), | 7244 | HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT), |
7128 | HDA_BIND_MUTE ("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT), | 7245 | HDA_BIND_MUTE ("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT), |
@@ -7156,6 +7273,21 @@ static struct snd_kcontrol_new alc885_mb5_mixer[] = { | |||
7156 | { } /* end */ | 7273 | { } /* end */ |
7157 | }; | 7274 | }; |
7158 | 7275 | ||
7276 | static struct snd_kcontrol_new alc885_macmini3_mixer[] = { | ||
7277 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT), | ||
7278 | HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT), | ||
7279 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT), | ||
7280 | HDA_BIND_MUTE ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT), | ||
7281 | HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT), | ||
7282 | HDA_BIND_MUTE ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT), | ||
7283 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0f, 0x00, HDA_OUTPUT), | ||
7284 | HDA_BIND_MUTE ("Headphone Playback Switch", 0x0f, 0x02, HDA_INPUT), | ||
7285 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x07, HDA_INPUT), | ||
7286 | HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x07, HDA_INPUT), | ||
7287 | HDA_CODEC_VOLUME("Line Boost", 0x15, 0x00, HDA_INPUT), | ||
7288 | { } /* end */ | ||
7289 | }; | ||
7290 | |||
7159 | static struct snd_kcontrol_new alc885_imac91_mixer[] = { | 7291 | static struct snd_kcontrol_new alc885_imac91_mixer[] = { |
7160 | HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x0c, 0x00, HDA_OUTPUT), | 7292 | HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x0c, 0x00, HDA_OUTPUT), |
7161 | HDA_BIND_MUTE ("Line-Out Playback Switch", 0x0c, 0x02, HDA_INPUT), | 7293 | HDA_BIND_MUTE ("Line-Out Playback Switch", 0x0c, 0x02, HDA_INPUT), |
@@ -7247,29 +7379,18 @@ static struct snd_kcontrol_new alc882_chmode_mixer[] = { | |||
7247 | 7379 | ||
7248 | static struct hda_verb alc882_base_init_verbs[] = { | 7380 | static struct hda_verb alc882_base_init_verbs[] = { |
7249 | /* Front mixer: unmute input/output amp left and right (volume = 0) */ | 7381 | /* Front mixer: unmute input/output amp left and right (volume = 0) */ |
7250 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
7251 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | 7382 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, |
7252 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | 7383 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, |
7253 | /* Rear mixer */ | 7384 | /* Rear mixer */ |
7254 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
7255 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | 7385 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, |
7256 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | 7386 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, |
7257 | /* CLFE mixer */ | 7387 | /* CLFE mixer */ |
7258 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
7259 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | 7388 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, |
7260 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | 7389 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, |
7261 | /* Side mixer */ | 7390 | /* Side mixer */ |
7262 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
7263 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | 7391 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, |
7264 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | 7392 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, |
7265 | 7393 | ||
7266 | /* mute analog input loopbacks */ | ||
7267 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
7268 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
7269 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
7270 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
7271 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
7272 | |||
7273 | /* Front Pin: output 0 (0x0c) */ | 7394 | /* Front Pin: output 0 (0x0c) */ |
7274 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | 7395 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, |
7275 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | 7396 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, |
@@ -7306,14 +7427,8 @@ static struct hda_verb alc882_base_init_verbs[] = { | |||
7306 | /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ | 7427 | /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ |
7307 | /* Input mixer2 */ | 7428 | /* Input mixer2 */ |
7308 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 7429 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
7309 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
7310 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
7311 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
7312 | /* Input mixer3 */ | 7430 | /* Input mixer3 */ |
7313 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 7431 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
7314 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
7315 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
7316 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
7317 | /* ADC2: mute amp left and right */ | 7432 | /* ADC2: mute amp left and right */ |
7318 | {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | 7433 | {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, |
7319 | {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, | 7434 | {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, |
@@ -7357,26 +7472,17 @@ static struct hda_verb alc_hp15_unsol_verbs[] = { | |||
7357 | 7472 | ||
7358 | static struct hda_verb alc885_init_verbs[] = { | 7473 | static struct hda_verb alc885_init_verbs[] = { |
7359 | /* Front mixer: unmute input/output amp left and right (volume = 0) */ | 7474 | /* Front mixer: unmute input/output amp left and right (volume = 0) */ |
7360 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | 7475 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
7361 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | 7476 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, |
7362 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
7363 | /* Rear mixer */ | 7477 | /* Rear mixer */ |
7364 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | 7478 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
7365 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | 7479 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, |
7366 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
7367 | /* CLFE mixer */ | 7480 | /* CLFE mixer */ |
7368 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | 7481 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
7369 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | 7482 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, |
7370 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
7371 | /* Side mixer */ | 7483 | /* Side mixer */ |
7372 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | 7484 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
7373 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | 7485 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, |
7374 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
7375 | |||
7376 | /* mute analog input loopbacks */ | ||
7377 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
7378 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
7379 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
7380 | 7486 | ||
7381 | /* Front HP Pin: output 0 (0x0c) */ | 7487 | /* Front HP Pin: output 0 (0x0c) */ |
7382 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | 7488 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, |
@@ -7410,17 +7516,11 @@ static struct hda_verb alc885_init_verbs[] = { | |||
7410 | 7516 | ||
7411 | /* Mixer elements: 0x18, , 0x1a, 0x1b */ | 7517 | /* Mixer elements: 0x18, , 0x1a, 0x1b */ |
7412 | /* Input mixer1 */ | 7518 | /* Input mixer1 */ |
7413 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, | 7519 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
7414 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
7415 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
7416 | /* Input mixer2 */ | 7520 | /* Input mixer2 */ |
7417 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 7521 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
7418 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
7419 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
7420 | /* Input mixer3 */ | 7522 | /* Input mixer3 */ |
7421 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, | 7523 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
7422 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
7423 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
7424 | /* ADC2: mute amp left and right */ | 7524 | /* ADC2: mute amp left and right */ |
7425 | {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | 7525 | {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, |
7426 | /* ADC3: mute amp left and right */ | 7526 | /* ADC3: mute amp left and right */ |
@@ -7562,6 +7662,76 @@ static struct hda_verb alc885_mb5_init_verbs[] = { | |||
7562 | { } | 7662 | { } |
7563 | }; | 7663 | }; |
7564 | 7664 | ||
7665 | /* Macmini 3,1 */ | ||
7666 | static struct hda_verb alc885_macmini3_init_verbs[] = { | ||
7667 | /* DACs */ | ||
7668 | {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
7669 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
7670 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
7671 | {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
7672 | /* Front mixer */ | ||
7673 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
7674 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
7675 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
7676 | /* Surround mixer */ | ||
7677 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
7678 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
7679 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
7680 | /* LFE mixer */ | ||
7681 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
7682 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
7683 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
7684 | /* HP mixer */ | ||
7685 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
7686 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
7687 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
7688 | /* Front Pin (0x0c) */ | ||
7689 | {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01}, | ||
7690 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
7691 | {0x18, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
7692 | /* LFE Pin (0x0e) */ | ||
7693 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01}, | ||
7694 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
7695 | {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02}, | ||
7696 | /* HP Pin (0x0f) */ | ||
7697 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
7698 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
7699 | {0x14, AC_VERB_SET_CONNECT_SEL, 0x03}, | ||
7700 | {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, | ||
7701 | /* Line In pin */ | ||
7702 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
7703 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
7704 | |||
7705 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
7706 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
7707 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
7708 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
7709 | { } | ||
7710 | }; | ||
7711 | |||
7712 | |||
7713 | static struct hda_verb alc885_mba21_init_verbs[] = { | ||
7714 | /*Internal and HP Speaker Mixer*/ | ||
7715 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
7716 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
7717 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
7718 | /*Internal Speaker Pin (0x0c)*/ | ||
7719 | {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) }, | ||
7720 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
7721 | {0x18, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
7722 | /* HP Pin: output 0 (0x0e) */ | ||
7723 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4}, | ||
7724 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
7725 | {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
7726 | {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, (ALC880_HP_EVENT | AC_USRSP_EN)}, | ||
7727 | /* Line in (is hp when jack connected)*/ | ||
7728 | {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_VREF_50}, | ||
7729 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
7730 | |||
7731 | { } | ||
7732 | }; | ||
7733 | |||
7734 | |||
7565 | /* Macbook Pro rev3 */ | 7735 | /* Macbook Pro rev3 */ |
7566 | static struct hda_verb alc885_mbp3_init_verbs[] = { | 7736 | static struct hda_verb alc885_mbp3_init_verbs[] = { |
7567 | /* Front mixer: unmute input/output amp left and right (volume = 0) */ | 7737 | /* Front mixer: unmute input/output amp left and right (volume = 0) */ |
@@ -7724,54 +7894,35 @@ static void alc885_imac24_setup(struct hda_codec *codec) | |||
7724 | spec->autocfg.speaker_pins[1] = 0x1a; | 7894 | spec->autocfg.speaker_pins[1] = 0x1a; |
7725 | } | 7895 | } |
7726 | 7896 | ||
7727 | static void alc885_mbp3_setup(struct hda_codec *codec) | 7897 | #define alc885_mb5_setup alc885_imac24_setup |
7728 | { | 7898 | #define alc885_macmini3_setup alc885_imac24_setup |
7729 | struct alc_spec *spec = codec->spec; | ||
7730 | |||
7731 | spec->autocfg.hp_pins[0] = 0x15; | ||
7732 | spec->autocfg.speaker_pins[0] = 0x14; | ||
7733 | } | ||
7734 | 7899 | ||
7735 | static void alc885_mb5_automute(struct hda_codec *codec) | 7900 | /* Macbook Air 2,1 */ |
7901 | static void alc885_mba21_setup(struct hda_codec *codec) | ||
7736 | { | 7902 | { |
7737 | unsigned int present; | 7903 | struct alc_spec *spec = codec->spec; |
7738 | |||
7739 | present = snd_hda_codec_read(codec, 0x14, 0, | ||
7740 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
7741 | snd_hda_codec_amp_stereo(codec, 0x18, HDA_OUTPUT, 0, | ||
7742 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
7743 | snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0, | ||
7744 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
7745 | 7904 | ||
7905 | spec->autocfg.hp_pins[0] = 0x14; | ||
7906 | spec->autocfg.speaker_pins[0] = 0x18; | ||
7746 | } | 7907 | } |
7747 | 7908 | ||
7748 | static void alc885_mb5_unsol_event(struct hda_codec *codec, | ||
7749 | unsigned int res) | ||
7750 | { | ||
7751 | /* Headphone insertion or removal. */ | ||
7752 | if ((res >> 26) == ALC880_HP_EVENT) | ||
7753 | alc885_mb5_automute(codec); | ||
7754 | } | ||
7755 | 7909 | ||
7756 | static void alc885_imac91_automute(struct hda_codec *codec) | ||
7757 | { | ||
7758 | unsigned int present; | ||
7759 | 7910 | ||
7760 | present = snd_hda_codec_read(codec, 0x14, 0, | 7911 | static void alc885_mbp3_setup(struct hda_codec *codec) |
7761 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | 7912 | { |
7762 | snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, | 7913 | struct alc_spec *spec = codec->spec; |
7763 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
7764 | snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0, | ||
7765 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
7766 | 7914 | ||
7915 | spec->autocfg.hp_pins[0] = 0x15; | ||
7916 | spec->autocfg.speaker_pins[0] = 0x14; | ||
7767 | } | 7917 | } |
7768 | 7918 | ||
7769 | static void alc885_imac91_unsol_event(struct hda_codec *codec, | 7919 | static void alc885_imac91_setup(struct hda_codec *codec) |
7770 | unsigned int res) | ||
7771 | { | 7920 | { |
7772 | /* Headphone insertion or removal. */ | 7921 | struct alc_spec *spec = codec->spec; |
7773 | if ((res >> 26) == ALC880_HP_EVENT) | 7922 | |
7774 | alc885_imac91_automute(codec); | 7923 | spec->autocfg.hp_pins[0] = 0x14; |
7924 | spec->autocfg.speaker_pins[0] = 0x15; | ||
7925 | spec->autocfg.speaker_pins[1] = 0x1a; | ||
7775 | } | 7926 | } |
7776 | 7927 | ||
7777 | static struct hda_verb alc882_targa_verbs[] = { | 7928 | static struct hda_verb alc882_targa_verbs[] = { |
@@ -7906,18 +8057,6 @@ static struct hda_verb alc883_auto_init_verbs[] = { | |||
7906 | {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, | 8057 | {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, |
7907 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 8058 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
7908 | 8059 | ||
7909 | /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback | ||
7910 | * mixer widget | ||
7911 | * Note: PASD motherboards uses the Line In 2 as the input for | ||
7912 | * front panel mic (mic 2) | ||
7913 | */ | ||
7914 | /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ | ||
7915 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
7916 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
7917 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
7918 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
7919 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
7920 | |||
7921 | /* | 8060 | /* |
7922 | * Set up output mixers (0x0c - 0x0f) | 8061 | * Set up output mixers (0x0c - 0x0f) |
7923 | */ | 8062 | */ |
@@ -7942,16 +8081,9 @@ static struct hda_verb alc883_auto_init_verbs[] = { | |||
7942 | /* FIXME: use matrix-type input source selection */ | 8081 | /* FIXME: use matrix-type input source selection */ |
7943 | /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ | 8082 | /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ |
7944 | /* Input mixer2 */ | 8083 | /* Input mixer2 */ |
7945 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | 8084 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
7946 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, | ||
7947 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, | ||
7948 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, | ||
7949 | /* Input mixer3 */ | 8085 | /* Input mixer3 */ |
7950 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | 8086 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
7951 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, | ||
7952 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, | ||
7953 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, | ||
7954 | |||
7955 | { } | 8087 | { } |
7956 | }; | 8088 | }; |
7957 | 8089 | ||
@@ -8938,6 +9070,8 @@ static const char *alc882_models[ALC882_MODEL_LAST] = { | |||
8938 | [ALC882_ASUS_A7M] = "asus-a7m", | 9070 | [ALC882_ASUS_A7M] = "asus-a7m", |
8939 | [ALC885_MACPRO] = "macpro", | 9071 | [ALC885_MACPRO] = "macpro", |
8940 | [ALC885_MB5] = "mb5", | 9072 | [ALC885_MB5] = "mb5", |
9073 | [ALC885_MACMINI3] = "macmini3", | ||
9074 | [ALC885_MBA21] = "mba21", | ||
8941 | [ALC885_MBP3] = "mbp3", | 9075 | [ALC885_MBP3] = "mbp3", |
8942 | [ALC885_IMAC24] = "imac24", | 9076 | [ALC885_IMAC24] = "imac24", |
8943 | [ALC885_IMAC91] = "imac91", | 9077 | [ALC885_IMAC91] = "imac91", |
@@ -9121,6 +9255,7 @@ static struct snd_pci_quirk alc882_ssid_cfg_tbl[] = { | |||
9121 | */ | 9255 | */ |
9122 | SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC885_MB5), | 9256 | SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC885_MB5), |
9123 | SND_PCI_QUIRK(0x106b, 0x4600, "MacbookPro 5,2", ALC885_MB5), | 9257 | SND_PCI_QUIRK(0x106b, 0x4600, "MacbookPro 5,2", ALC885_MB5), |
9258 | SND_PCI_QUIRK(0x106b, 0x4100, "Macmini 3,1", ALC885_MACMINI3), | ||
9124 | {} /* terminator */ | 9259 | {} /* terminator */ |
9125 | }; | 9260 | }; |
9126 | 9261 | ||
@@ -9172,6 +9307,18 @@ static struct alc_config_preset alc882_presets[] = { | |||
9172 | .input_mux = &alc882_capture_source, | 9307 | .input_mux = &alc882_capture_source, |
9173 | .dig_out_nid = ALC882_DIGOUT_NID, | 9308 | .dig_out_nid = ALC882_DIGOUT_NID, |
9174 | }, | 9309 | }, |
9310 | [ALC885_MBA21] = { | ||
9311 | .mixers = { alc885_mba21_mixer }, | ||
9312 | .init_verbs = { alc885_mba21_init_verbs, alc880_gpio1_init_verbs }, | ||
9313 | .num_dacs = 2, | ||
9314 | .dac_nids = alc882_dac_nids, | ||
9315 | .channel_mode = alc885_mba21_ch_modes, | ||
9316 | .num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes), | ||
9317 | .input_mux = &alc882_capture_source, | ||
9318 | .unsol_event = alc_automute_amp_unsol_event, | ||
9319 | .setup = alc885_mba21_setup, | ||
9320 | .init_hook = alc_automute_amp, | ||
9321 | }, | ||
9175 | [ALC885_MBP3] = { | 9322 | [ALC885_MBP3] = { |
9176 | .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer }, | 9323 | .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer }, |
9177 | .init_verbs = { alc885_mbp3_init_verbs, | 9324 | .init_verbs = { alc885_mbp3_init_verbs, |
@@ -9199,8 +9346,24 @@ static struct alc_config_preset alc882_presets[] = { | |||
9199 | .input_mux = &mb5_capture_source, | 9346 | .input_mux = &mb5_capture_source, |
9200 | .dig_out_nid = ALC882_DIGOUT_NID, | 9347 | .dig_out_nid = ALC882_DIGOUT_NID, |
9201 | .dig_in_nid = ALC882_DIGIN_NID, | 9348 | .dig_in_nid = ALC882_DIGIN_NID, |
9202 | .unsol_event = alc885_mb5_unsol_event, | 9349 | .unsol_event = alc_automute_amp_unsol_event, |
9203 | .init_hook = alc885_mb5_automute, | 9350 | .setup = alc885_mb5_setup, |
9351 | .init_hook = alc_automute_amp, | ||
9352 | }, | ||
9353 | [ALC885_MACMINI3] = { | ||
9354 | .mixers = { alc885_macmini3_mixer, alc882_chmode_mixer }, | ||
9355 | .init_verbs = { alc885_macmini3_init_verbs, | ||
9356 | alc880_gpio1_init_verbs }, | ||
9357 | .num_dacs = ARRAY_SIZE(alc882_dac_nids), | ||
9358 | .dac_nids = alc882_dac_nids, | ||
9359 | .channel_mode = alc885_macmini3_6ch_modes, | ||
9360 | .num_channel_mode = ARRAY_SIZE(alc885_macmini3_6ch_modes), | ||
9361 | .input_mux = &macmini3_capture_source, | ||
9362 | .dig_out_nid = ALC882_DIGOUT_NID, | ||
9363 | .dig_in_nid = ALC882_DIGIN_NID, | ||
9364 | .unsol_event = alc_automute_amp_unsol_event, | ||
9365 | .setup = alc885_macmini3_setup, | ||
9366 | .init_hook = alc_automute_amp, | ||
9204 | }, | 9367 | }, |
9205 | [ALC885_MACPRO] = { | 9368 | [ALC885_MACPRO] = { |
9206 | .mixers = { alc882_macpro_mixer }, | 9369 | .mixers = { alc882_macpro_mixer }, |
@@ -9239,8 +9402,9 @@ static struct alc_config_preset alc882_presets[] = { | |||
9239 | .input_mux = &alc882_capture_source, | 9402 | .input_mux = &alc882_capture_source, |
9240 | .dig_out_nid = ALC882_DIGOUT_NID, | 9403 | .dig_out_nid = ALC882_DIGOUT_NID, |
9241 | .dig_in_nid = ALC882_DIGIN_NID, | 9404 | .dig_in_nid = ALC882_DIGIN_NID, |
9242 | .unsol_event = alc885_imac91_unsol_event, | 9405 | .unsol_event = alc_automute_amp_unsol_event, |
9243 | .init_hook = alc885_imac91_automute, | 9406 | .setup = alc885_imac91_setup, |
9407 | .init_hook = alc_automute_amp, | ||
9244 | }, | 9408 | }, |
9245 | [ALC882_TARGA] = { | 9409 | [ALC882_TARGA] = { |
9246 | .mixers = { alc882_targa_mixer, alc882_chmode_mixer }, | 9410 | .mixers = { alc882_targa_mixer, alc882_chmode_mixer }, |
@@ -9528,7 +9692,7 @@ static struct alc_config_preset alc882_presets[] = { | |||
9528 | .setup = alc889_acer_aspire_8930g_setup, | 9692 | .setup = alc889_acer_aspire_8930g_setup, |
9529 | .init_hook = alc_automute_amp, | 9693 | .init_hook = alc_automute_amp, |
9530 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 9694 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
9531 | .power_hook = alc889_power_eapd, | 9695 | .power_hook = alc_power_eapd, |
9532 | #endif | 9696 | #endif |
9533 | }, | 9697 | }, |
9534 | [ALC888_ACER_ASPIRE_7730G] = { | 9698 | [ALC888_ACER_ASPIRE_7730G] = { |
@@ -10063,7 +10227,7 @@ static int alc882_parse_auto_config(struct hda_codec *codec) | |||
10063 | spec->num_mux_defs = 1; | 10227 | spec->num_mux_defs = 1; |
10064 | spec->input_mux = &spec->private_imux[0]; | 10228 | spec->input_mux = &spec->private_imux[0]; |
10065 | 10229 | ||
10066 | alc_ssid_check(codec, 0x15, 0x1b, 0x14); | 10230 | alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0); |
10067 | 10231 | ||
10068 | err = alc_auto_add_mic_boost(codec); | 10232 | err = alc_auto_add_mic_boost(codec); |
10069 | if (err < 0) | 10233 | if (err < 0) |
@@ -10201,7 +10365,6 @@ static int patch_alc882(struct hda_codec *codec) | |||
10201 | if (!spec->loopback.amplist) | 10365 | if (!spec->loopback.amplist) |
10202 | spec->loopback.amplist = alc882_loopbacks; | 10366 | spec->loopback.amplist = alc882_loopbacks; |
10203 | #endif | 10367 | #endif |
10204 | codec->proc_widget_hook = print_realtek_coef; | ||
10205 | 10368 | ||
10206 | return 0; | 10369 | return 0; |
10207 | } | 10370 | } |
@@ -10324,8 +10487,14 @@ static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol, | |||
10324 | .info = snd_ctl_boolean_mono_info, \ | 10487 | .info = snd_ctl_boolean_mono_info, \ |
10325 | .get = alc262_hp_master_sw_get, \ | 10488 | .get = alc262_hp_master_sw_get, \ |
10326 | .put = alc262_hp_master_sw_put, \ | 10489 | .put = alc262_hp_master_sw_put, \ |
10490 | }, \ | ||
10491 | { \ | ||
10492 | .iface = NID_MAPPING, \ | ||
10493 | .name = "Master Playback Switch", \ | ||
10494 | .private_value = 0x15 | (0x16 << 8) | (0x1b << 16), \ | ||
10327 | } | 10495 | } |
10328 | 10496 | ||
10497 | |||
10329 | static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = { | 10498 | static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = { |
10330 | ALC262_HP_MASTER_SWITCH, | 10499 | ALC262_HP_MASTER_SWITCH, |
10331 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | 10500 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), |
@@ -10483,6 +10652,12 @@ static int alc262_hippo_master_sw_put(struct snd_kcontrol *kcontrol, | |||
10483 | .info = snd_ctl_boolean_mono_info, \ | 10652 | .info = snd_ctl_boolean_mono_info, \ |
10484 | .get = alc262_hippo_master_sw_get, \ | 10653 | .get = alc262_hippo_master_sw_get, \ |
10485 | .put = alc262_hippo_master_sw_put, \ | 10654 | .put = alc262_hippo_master_sw_put, \ |
10655 | }, \ | ||
10656 | { \ | ||
10657 | .iface = NID_MAPPING, \ | ||
10658 | .name = "Master Playback Switch", \ | ||
10659 | .subdevice = SUBDEV_HP(0) | (SUBDEV_LINE(0) << 8) | \ | ||
10660 | (SUBDEV_SPEAKER(0) << 16), \ | ||
10486 | } | 10661 | } |
10487 | 10662 | ||
10488 | static struct snd_kcontrol_new alc262_hippo_mixer[] = { | 10663 | static struct snd_kcontrol_new alc262_hippo_mixer[] = { |
@@ -10963,11 +11138,17 @@ static struct snd_kcontrol_new alc262_fujitsu_mixer[] = { | |||
10963 | { | 11138 | { |
10964 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 11139 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
10965 | .name = "Master Playback Switch", | 11140 | .name = "Master Playback Switch", |
11141 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
10966 | .info = snd_hda_mixer_amp_switch_info, | 11142 | .info = snd_hda_mixer_amp_switch_info, |
10967 | .get = snd_hda_mixer_amp_switch_get, | 11143 | .get = snd_hda_mixer_amp_switch_get, |
10968 | .put = alc262_fujitsu_master_sw_put, | 11144 | .put = alc262_fujitsu_master_sw_put, |
10969 | .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), | 11145 | .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), |
10970 | }, | 11146 | }, |
11147 | { | ||
11148 | .iface = NID_MAPPING, | ||
11149 | .name = "Master Playback Switch", | ||
11150 | .private_value = 0x1b, | ||
11151 | }, | ||
10971 | HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), | 11152 | HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), |
10972 | HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), | 11153 | HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), |
10973 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), | 11154 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), |
@@ -10998,6 +11179,7 @@ static struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = { | |||
10998 | { | 11179 | { |
10999 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 11180 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
11000 | .name = "Master Playback Switch", | 11181 | .name = "Master Playback Switch", |
11182 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
11001 | .info = snd_hda_mixer_amp_switch_info, | 11183 | .info = snd_hda_mixer_amp_switch_info, |
11002 | .get = snd_hda_mixer_amp_switch_get, | 11184 | .get = snd_hda_mixer_amp_switch_get, |
11003 | .put = alc262_lenovo_3000_master_sw_put, | 11185 | .put = alc262_lenovo_3000_master_sw_put, |
@@ -11152,6 +11334,11 @@ static struct snd_kcontrol_new alc262_ultra_capture_mixer[] = { | |||
11152 | .get = alc_mux_enum_get, | 11334 | .get = alc_mux_enum_get, |
11153 | .put = alc262_ultra_mux_enum_put, | 11335 | .put = alc262_ultra_mux_enum_put, |
11154 | }, | 11336 | }, |
11337 | { | ||
11338 | .iface = NID_MAPPING, | ||
11339 | .name = "Capture Source", | ||
11340 | .private_value = 0x15, | ||
11341 | }, | ||
11155 | { } /* end */ | 11342 | { } /* end */ |
11156 | }; | 11343 | }; |
11157 | 11344 | ||
@@ -11598,7 +11785,7 @@ static int alc262_parse_auto_config(struct hda_codec *codec) | |||
11598 | if (err < 0) | 11785 | if (err < 0) |
11599 | return err; | 11786 | return err; |
11600 | 11787 | ||
11601 | alc_ssid_check(codec, 0x15, 0x14, 0x1b); | 11788 | alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0); |
11602 | 11789 | ||
11603 | return 1; | 11790 | return 1; |
11604 | } | 11791 | } |
@@ -12041,7 +12228,6 @@ static int patch_alc262(struct hda_codec *codec) | |||
12041 | if (!spec->loopback.amplist) | 12228 | if (!spec->loopback.amplist) |
12042 | spec->loopback.amplist = alc262_loopbacks; | 12229 | spec->loopback.amplist = alc262_loopbacks; |
12043 | #endif | 12230 | #endif |
12044 | codec->proc_widget_hook = print_realtek_coef; | ||
12045 | 12231 | ||
12046 | return 0; | 12232 | return 0; |
12047 | } | 12233 | } |
@@ -12170,6 +12356,7 @@ static struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = { | |||
12170 | { | 12356 | { |
12171 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 12357 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
12172 | .name = "Master Playback Switch", | 12358 | .name = "Master Playback Switch", |
12359 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
12173 | .info = snd_hda_mixer_amp_switch_info, | 12360 | .info = snd_hda_mixer_amp_switch_info, |
12174 | .get = snd_hda_mixer_amp_switch_get, | 12361 | .get = snd_hda_mixer_amp_switch_get, |
12175 | .put = alc268_acer_master_sw_put, | 12362 | .put = alc268_acer_master_sw_put, |
@@ -12185,6 +12372,7 @@ static struct snd_kcontrol_new alc268_acer_mixer[] = { | |||
12185 | { | 12372 | { |
12186 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 12373 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
12187 | .name = "Master Playback Switch", | 12374 | .name = "Master Playback Switch", |
12375 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
12188 | .info = snd_hda_mixer_amp_switch_info, | 12376 | .info = snd_hda_mixer_amp_switch_info, |
12189 | .get = snd_hda_mixer_amp_switch_get, | 12377 | .get = snd_hda_mixer_amp_switch_get, |
12190 | .put = alc268_acer_master_sw_put, | 12378 | .put = alc268_acer_master_sw_put, |
@@ -12202,6 +12390,7 @@ static struct snd_kcontrol_new alc268_acer_dmic_mixer[] = { | |||
12202 | { | 12390 | { |
12203 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 12391 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
12204 | .name = "Master Playback Switch", | 12392 | .name = "Master Playback Switch", |
12393 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
12205 | .info = snd_hda_mixer_amp_switch_info, | 12394 | .info = snd_hda_mixer_amp_switch_info, |
12206 | .get = snd_hda_mixer_amp_switch_get, | 12395 | .get = snd_hda_mixer_amp_switch_get, |
12207 | .put = alc268_acer_master_sw_put, | 12396 | .put = alc268_acer_master_sw_put, |
@@ -12547,7 +12736,6 @@ static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid, | |||
12547 | dac = 0x02; | 12736 | dac = 0x02; |
12548 | break; | 12737 | break; |
12549 | case 0x15: | 12738 | case 0x15: |
12550 | case 0x21: | ||
12551 | dac = 0x03; | 12739 | dac = 0x03; |
12552 | break; | 12740 | break; |
12553 | default: | 12741 | default: |
@@ -12768,7 +12956,7 @@ static int alc268_parse_auto_config(struct hda_codec *codec) | |||
12768 | if (err < 0) | 12956 | if (err < 0) |
12769 | return err; | 12957 | return err; |
12770 | 12958 | ||
12771 | alc_ssid_check(codec, 0x15, 0x1b, 0x14); | 12959 | alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0); |
12772 | 12960 | ||
12773 | return 1; | 12961 | return 1; |
12774 | } | 12962 | } |
@@ -13105,8 +13293,6 @@ static int patch_alc268(struct hda_codec *codec) | |||
13105 | if (board_config == ALC268_AUTO) | 13293 | if (board_config == ALC268_AUTO) |
13106 | spec->init_hook = alc268_auto_init; | 13294 | spec->init_hook = alc268_auto_init; |
13107 | 13295 | ||
13108 | codec->proc_widget_hook = print_realtek_coef; | ||
13109 | |||
13110 | return 0; | 13296 | return 0; |
13111 | } | 13297 | } |
13112 | 13298 | ||
@@ -13126,6 +13312,15 @@ static hda_nid_t alc269_capsrc_nids[1] = { | |||
13126 | 0x23, | 13312 | 0x23, |
13127 | }; | 13313 | }; |
13128 | 13314 | ||
13315 | static hda_nid_t alc269vb_adc_nids[1] = { | ||
13316 | /* ADC1 */ | ||
13317 | 0x09, | ||
13318 | }; | ||
13319 | |||
13320 | static hda_nid_t alc269vb_capsrc_nids[1] = { | ||
13321 | 0x22, | ||
13322 | }; | ||
13323 | |||
13129 | /* NOTE: ADC2 (0x07) is connected from a recording *MIXER* (0x24), | 13324 | /* NOTE: ADC2 (0x07) is connected from a recording *MIXER* (0x24), |
13130 | * not a mux! | 13325 | * not a mux! |
13131 | */ | 13326 | */ |
@@ -13155,6 +13350,7 @@ static struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = { | |||
13155 | { | 13350 | { |
13156 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 13351 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
13157 | .name = "Master Playback Switch", | 13352 | .name = "Master Playback Switch", |
13353 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
13158 | .info = snd_hda_mixer_amp_switch_info, | 13354 | .info = snd_hda_mixer_amp_switch_info, |
13159 | .get = snd_hda_mixer_amp_switch_get, | 13355 | .get = snd_hda_mixer_amp_switch_get, |
13160 | .put = alc268_acer_master_sw_put, | 13356 | .put = alc268_acer_master_sw_put, |
@@ -13175,6 +13371,7 @@ static struct snd_kcontrol_new alc269_lifebook_mixer[] = { | |||
13175 | { | 13371 | { |
13176 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 13372 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
13177 | .name = "Master Playback Switch", | 13373 | .name = "Master Playback Switch", |
13374 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
13178 | .info = snd_hda_mixer_amp_switch_info, | 13375 | .info = snd_hda_mixer_amp_switch_info, |
13179 | .get = snd_hda_mixer_amp_switch_get, | 13376 | .get = snd_hda_mixer_amp_switch_get, |
13180 | .put = alc268_acer_master_sw_put, | 13377 | .put = alc268_acer_master_sw_put, |
@@ -13192,7 +13389,7 @@ static struct snd_kcontrol_new alc269_lifebook_mixer[] = { | |||
13192 | { } | 13389 | { } |
13193 | }; | 13390 | }; |
13194 | 13391 | ||
13195 | static struct snd_kcontrol_new alc269_eeepc_mixer[] = { | 13392 | static struct snd_kcontrol_new alc269_laptop_mixer[] = { |
13196 | HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), | 13393 | HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), |
13197 | HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), | 13394 | HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), |
13198 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), | 13395 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), |
@@ -13200,16 +13397,47 @@ static struct snd_kcontrol_new alc269_eeepc_mixer[] = { | |||
13200 | { } /* end */ | 13397 | { } /* end */ |
13201 | }; | 13398 | }; |
13202 | 13399 | ||
13400 | static struct snd_kcontrol_new alc269vb_laptop_mixer[] = { | ||
13401 | HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), | ||
13402 | HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), | ||
13403 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT), | ||
13404 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), | ||
13405 | { } /* end */ | ||
13406 | }; | ||
13407 | |||
13203 | /* capture mixer elements */ | 13408 | /* capture mixer elements */ |
13204 | static struct snd_kcontrol_new alc269_epc_capture_mixer[] = { | 13409 | static struct snd_kcontrol_new alc269_laptop_analog_capture_mixer[] = { |
13410 | HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), | ||
13411 | HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), | ||
13412 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), | ||
13413 | HDA_CODEC_VOLUME("IntMic Boost", 0x19, 0, HDA_INPUT), | ||
13414 | { } /* end */ | ||
13415 | }; | ||
13416 | |||
13417 | static struct snd_kcontrol_new alc269_laptop_digital_capture_mixer[] = { | ||
13205 | HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), | 13418 | HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), |
13206 | HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), | 13419 | HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), |
13207 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), | 13420 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), |
13208 | { } /* end */ | 13421 | { } /* end */ |
13209 | }; | 13422 | }; |
13210 | 13423 | ||
13424 | static struct snd_kcontrol_new alc269vb_laptop_analog_capture_mixer[] = { | ||
13425 | HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), | ||
13426 | HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), | ||
13427 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), | ||
13428 | HDA_CODEC_VOLUME("IntMic Boost", 0x19, 0, HDA_INPUT), | ||
13429 | { } /* end */ | ||
13430 | }; | ||
13431 | |||
13432 | static struct snd_kcontrol_new alc269vb_laptop_digital_capture_mixer[] = { | ||
13433 | HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), | ||
13434 | HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), | ||
13435 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), | ||
13436 | { } /* end */ | ||
13437 | }; | ||
13438 | |||
13211 | /* FSC amilo */ | 13439 | /* FSC amilo */ |
13212 | #define alc269_fujitsu_mixer alc269_eeepc_mixer | 13440 | #define alc269_fujitsu_mixer alc269_laptop_mixer |
13213 | 13441 | ||
13214 | static struct hda_verb alc269_quanta_fl1_verbs[] = { | 13442 | static struct hda_verb alc269_quanta_fl1_verbs[] = { |
13215 | {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, | 13443 | {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, |
@@ -13352,7 +13580,7 @@ static void alc269_lifebook_init_hook(struct hda_codec *codec) | |||
13352 | alc269_lifebook_mic_autoswitch(codec); | 13580 | alc269_lifebook_mic_autoswitch(codec); |
13353 | } | 13581 | } |
13354 | 13582 | ||
13355 | static struct hda_verb alc269_eeepc_dmic_init_verbs[] = { | 13583 | static struct hda_verb alc269_laptop_dmic_init_verbs[] = { |
13356 | {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, | 13584 | {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, |
13357 | {0x23, AC_VERB_SET_CONNECT_SEL, 0x05}, | 13585 | {0x23, AC_VERB_SET_CONNECT_SEL, 0x05}, |
13358 | {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 }, | 13586 | {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 }, |
@@ -13363,7 +13591,7 @@ static struct hda_verb alc269_eeepc_dmic_init_verbs[] = { | |||
13363 | {} | 13591 | {} |
13364 | }; | 13592 | }; |
13365 | 13593 | ||
13366 | static struct hda_verb alc269_eeepc_amic_init_verbs[] = { | 13594 | static struct hda_verb alc269_laptop_amic_init_verbs[] = { |
13367 | {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, | 13595 | {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, |
13368 | {0x23, AC_VERB_SET_CONNECT_SEL, 0x01}, | 13596 | {0x23, AC_VERB_SET_CONNECT_SEL, 0x01}, |
13369 | {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 }, | 13597 | {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 }, |
@@ -13373,6 +13601,28 @@ static struct hda_verb alc269_eeepc_amic_init_verbs[] = { | |||
13373 | {} | 13601 | {} |
13374 | }; | 13602 | }; |
13375 | 13603 | ||
13604 | static struct hda_verb alc269vb_laptop_dmic_init_verbs[] = { | ||
13605 | {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
13606 | {0x22, AC_VERB_SET_CONNECT_SEL, 0x06}, | ||
13607 | {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 }, | ||
13608 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))}, | ||
13609 | {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
13610 | {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, | ||
13611 | {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, | ||
13612 | {} | ||
13613 | }; | ||
13614 | |||
13615 | static struct hda_verb alc269vb_laptop_amic_init_verbs[] = { | ||
13616 | {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
13617 | {0x22, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
13618 | {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 }, | ||
13619 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))}, | ||
13620 | {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
13621 | {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, | ||
13622 | {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, | ||
13623 | {} | ||
13624 | }; | ||
13625 | |||
13376 | /* toggle speaker-output according to the hp-jack state */ | 13626 | /* toggle speaker-output according to the hp-jack state */ |
13377 | static void alc269_speaker_automute(struct hda_codec *codec) | 13627 | static void alc269_speaker_automute(struct hda_codec *codec) |
13378 | { | 13628 | { |
@@ -13390,7 +13640,7 @@ static void alc269_speaker_automute(struct hda_codec *codec) | |||
13390 | } | 13640 | } |
13391 | 13641 | ||
13392 | /* unsolicited event for HP jack sensing */ | 13642 | /* unsolicited event for HP jack sensing */ |
13393 | static void alc269_eeepc_unsol_event(struct hda_codec *codec, | 13643 | static void alc269_laptop_unsol_event(struct hda_codec *codec, |
13394 | unsigned int res) | 13644 | unsigned int res) |
13395 | { | 13645 | { |
13396 | switch (res >> 26) { | 13646 | switch (res >> 26) { |
@@ -13403,7 +13653,7 @@ static void alc269_eeepc_unsol_event(struct hda_codec *codec, | |||
13403 | } | 13653 | } |
13404 | } | 13654 | } |
13405 | 13655 | ||
13406 | static void alc269_eeepc_dmic_setup(struct hda_codec *codec) | 13656 | static void alc269_laptop_dmic_setup(struct hda_codec *codec) |
13407 | { | 13657 | { |
13408 | struct alc_spec *spec = codec->spec; | 13658 | struct alc_spec *spec = codec->spec; |
13409 | spec->ext_mic.pin = 0x18; | 13659 | spec->ext_mic.pin = 0x18; |
@@ -13413,7 +13663,17 @@ static void alc269_eeepc_dmic_setup(struct hda_codec *codec) | |||
13413 | spec->auto_mic = 1; | 13663 | spec->auto_mic = 1; |
13414 | } | 13664 | } |
13415 | 13665 | ||
13416 | static void alc269_eeepc_amic_setup(struct hda_codec *codec) | 13666 | static void alc269vb_laptop_dmic_setup(struct hda_codec *codec) |
13667 | { | ||
13668 | struct alc_spec *spec = codec->spec; | ||
13669 | spec->ext_mic.pin = 0x18; | ||
13670 | spec->ext_mic.mux_idx = 0; | ||
13671 | spec->int_mic.pin = 0x12; | ||
13672 | spec->int_mic.mux_idx = 6; | ||
13673 | spec->auto_mic = 1; | ||
13674 | } | ||
13675 | |||
13676 | static void alc269_laptop_amic_setup(struct hda_codec *codec) | ||
13417 | { | 13677 | { |
13418 | struct alc_spec *spec = codec->spec; | 13678 | struct alc_spec *spec = codec->spec; |
13419 | spec->ext_mic.pin = 0x18; | 13679 | spec->ext_mic.pin = 0x18; |
@@ -13423,7 +13683,7 @@ static void alc269_eeepc_amic_setup(struct hda_codec *codec) | |||
13423 | spec->auto_mic = 1; | 13683 | spec->auto_mic = 1; |
13424 | } | 13684 | } |
13425 | 13685 | ||
13426 | static void alc269_eeepc_inithook(struct hda_codec *codec) | 13686 | static void alc269_laptop_inithook(struct hda_codec *codec) |
13427 | { | 13687 | { |
13428 | alc269_speaker_automute(codec); | 13688 | alc269_speaker_automute(codec); |
13429 | alc_mic_automute(codec); | 13689 | alc_mic_automute(codec); |
@@ -13436,22 +13696,10 @@ static struct hda_verb alc269_init_verbs[] = { | |||
13436 | /* | 13696 | /* |
13437 | * Unmute ADC0 and set the default input to mic-in | 13697 | * Unmute ADC0 and set the default input to mic-in |
13438 | */ | 13698 | */ |
13439 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 13699 | {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
13440 | |||
13441 | /* Mute input amps (PCBeep, Line In, Mic 1 & Mic 2) of the | ||
13442 | * analog-loopback mixer widget | ||
13443 | * Note: PASD motherboards uses the Line In 2 as the input for | ||
13444 | * front panel mic (mic 2) | ||
13445 | */ | ||
13446 | /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ | ||
13447 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
13448 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
13449 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
13450 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
13451 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
13452 | 13700 | ||
13453 | /* | 13701 | /* |
13454 | * Set up output mixers (0x0c - 0x0e) | 13702 | * Set up output mixers (0x02 - 0x03) |
13455 | */ | 13703 | */ |
13456 | /* set vol=0 to output mixers */ | 13704 | /* set vol=0 to output mixers */ |
13457 | {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | 13705 | {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, |
@@ -13476,26 +13724,57 @@ static struct hda_verb alc269_init_verbs[] = { | |||
13476 | 13724 | ||
13477 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | 13725 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, |
13478 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | 13726 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, |
13479 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
13480 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
13481 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
13482 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
13483 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
13484 | 13727 | ||
13485 | {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, | 13728 | /* FIXME: use Mux-type input source selection */ |
13486 | {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, | 13729 | /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */ |
13730 | /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ | ||
13731 | {0x23, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
13487 | 13732 | ||
13488 | /* FIXME: use matrix-type input source selection */ | 13733 | /* set EAPD */ |
13734 | {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, | ||
13735 | { } | ||
13736 | }; | ||
13737 | |||
13738 | static struct hda_verb alc269vb_init_verbs[] = { | ||
13739 | /* | ||
13740 | * Unmute ADC0 and set the default input to mic-in | ||
13741 | */ | ||
13742 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
13743 | |||
13744 | /* | ||
13745 | * Set up output mixers (0x02 - 0x03) | ||
13746 | */ | ||
13747 | /* set vol=0 to output mixers */ | ||
13748 | {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
13749 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
13750 | |||
13751 | /* set up input amps for analog loopback */ | ||
13752 | /* Amp Indices: DAC = 0, mixer = 1 */ | ||
13753 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
13754 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
13755 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
13756 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
13757 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
13758 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
13759 | |||
13760 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
13761 | {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
13762 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
13763 | {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
13764 | {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
13765 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
13766 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
13767 | |||
13768 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
13769 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
13770 | |||
13771 | /* FIXME: use Mux-type input source selection */ | ||
13489 | /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */ | 13772 | /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */ |
13490 | /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ | 13773 | /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ |
13491 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | 13774 | {0x22, AC_VERB_SET_CONNECT_SEL, 0x00}, |
13492 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
13493 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
13494 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
13495 | 13775 | ||
13496 | /* set EAPD */ | 13776 | /* set EAPD */ |
13497 | {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, | 13777 | {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, |
13498 | {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, | ||
13499 | { } | 13778 | { } |
13500 | }; | 13779 | }; |
13501 | 13780 | ||
@@ -13543,6 +13822,7 @@ static int alc269_parse_auto_config(struct hda_codec *codec) | |||
13543 | struct alc_spec *spec = codec->spec; | 13822 | struct alc_spec *spec = codec->spec; |
13544 | int err; | 13823 | int err; |
13545 | static hda_nid_t alc269_ignore[] = { 0x1d, 0 }; | 13824 | static hda_nid_t alc269_ignore[] = { 0x1d, 0 }; |
13825 | hda_nid_t real_capsrc_nids; | ||
13546 | 13826 | ||
13547 | err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, | 13827 | err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, |
13548 | alc269_ignore); | 13828 | alc269_ignore); |
@@ -13564,11 +13844,20 @@ static int alc269_parse_auto_config(struct hda_codec *codec) | |||
13564 | if (spec->kctls.list) | 13844 | if (spec->kctls.list) |
13565 | add_mixer(spec, spec->kctls.list); | 13845 | add_mixer(spec, spec->kctls.list); |
13566 | 13846 | ||
13567 | add_verb(spec, alc269_init_verbs); | 13847 | if ((alc_read_coef_idx(codec, 0) & 0x00f0) == 0x0010) { |
13848 | add_verb(spec, alc269vb_init_verbs); | ||
13849 | real_capsrc_nids = alc269vb_capsrc_nids[0]; | ||
13850 | alc_ssid_check(codec, 0, 0x1b, 0x14, 0x21); | ||
13851 | } else { | ||
13852 | add_verb(spec, alc269_init_verbs); | ||
13853 | real_capsrc_nids = alc269_capsrc_nids[0]; | ||
13854 | alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0); | ||
13855 | } | ||
13856 | |||
13568 | spec->num_mux_defs = 1; | 13857 | spec->num_mux_defs = 1; |
13569 | spec->input_mux = &spec->private_imux[0]; | 13858 | spec->input_mux = &spec->private_imux[0]; |
13570 | /* set default input source */ | 13859 | /* set default input source */ |
13571 | snd_hda_codec_write_cache(codec, alc269_capsrc_nids[0], | 13860 | snd_hda_codec_write_cache(codec, real_capsrc_nids, |
13572 | 0, AC_VERB_SET_CONNECT_SEL, | 13861 | 0, AC_VERB_SET_CONNECT_SEL, |
13573 | spec->input_mux->items[0].index); | 13862 | spec->input_mux->items[0].index); |
13574 | 13863 | ||
@@ -13579,8 +13868,6 @@ static int alc269_parse_auto_config(struct hda_codec *codec) | |||
13579 | if (!spec->cap_mixer && !spec->no_analog) | 13868 | if (!spec->cap_mixer && !spec->no_analog) |
13580 | set_capture_mixer(codec); | 13869 | set_capture_mixer(codec); |
13581 | 13870 | ||
13582 | alc_ssid_check(codec, 0x15, 0x1b, 0x14); | ||
13583 | |||
13584 | return 1; | 13871 | return 1; |
13585 | } | 13872 | } |
13586 | 13873 | ||
@@ -13606,8 +13893,8 @@ static void alc269_auto_init(struct hda_codec *codec) | |||
13606 | static const char *alc269_models[ALC269_MODEL_LAST] = { | 13893 | static const char *alc269_models[ALC269_MODEL_LAST] = { |
13607 | [ALC269_BASIC] = "basic", | 13894 | [ALC269_BASIC] = "basic", |
13608 | [ALC269_QUANTA_FL1] = "quanta", | 13895 | [ALC269_QUANTA_FL1] = "quanta", |
13609 | [ALC269_ASUS_AMIC] = "asus-amic", | 13896 | [ALC269_AMIC] = "laptop-amic", |
13610 | [ALC269_ASUS_DMIC] = "asus-dmic", | 13897 | [ALC269_DMIC] = "laptop-dmic", |
13611 | [ALC269_FUJITSU] = "fujitsu", | 13898 | [ALC269_FUJITSU] = "fujitsu", |
13612 | [ALC269_LIFEBOOK] = "lifebook", | 13899 | [ALC269_LIFEBOOK] = "lifebook", |
13613 | [ALC269_AUTO] = "auto", | 13900 | [ALC269_AUTO] = "auto", |
@@ -13616,43 +13903,57 @@ static const char *alc269_models[ALC269_MODEL_LAST] = { | |||
13616 | static struct snd_pci_quirk alc269_cfg_tbl[] = { | 13903 | static struct snd_pci_quirk alc269_cfg_tbl[] = { |
13617 | SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_QUANTA_FL1), | 13904 | SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_QUANTA_FL1), |
13618 | SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A", | 13905 | SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A", |
13619 | ALC269_ASUS_AMIC), | 13906 | ALC269_AMIC), |
13620 | SND_PCI_QUIRK(0x1043, 0x1133, "ASUS UJ20ft", ALC269_ASUS_AMIC), | 13907 | SND_PCI_QUIRK(0x1043, 0x1013, "ASUS N61Da", ALC269VB_AMIC), |
13621 | SND_PCI_QUIRK(0x1043, 0x1273, "ASUS UL80JT", ALC269_ASUS_AMIC), | 13908 | SND_PCI_QUIRK(0x1043, 0x1113, "ASUS N63Jn", ALC269VB_AMIC), |
13622 | SND_PCI_QUIRK(0x1043, 0x1283, "ASUS U53Jc", ALC269_ASUS_AMIC), | 13909 | SND_PCI_QUIRK(0x1043, 0x1143, "ASUS B53f", ALC269VB_AMIC), |
13623 | SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS N82Jv", ALC269_ASUS_AMIC), | 13910 | SND_PCI_QUIRK(0x1043, 0x1133, "ASUS UJ20ft", ALC269_AMIC), |
13624 | SND_PCI_QUIRK(0x1043, 0x13a3, "ASUS UL30Vt", ALC269_ASUS_AMIC), | 13911 | SND_PCI_QUIRK(0x1043, 0x1183, "ASUS K72DR", ALC269VB_AMIC), |
13625 | SND_PCI_QUIRK(0x1043, 0x1373, "ASUS G73JX", ALC269_ASUS_AMIC), | 13912 | SND_PCI_QUIRK(0x1043, 0x11b3, "ASUS K52DR", ALC269VB_AMIC), |
13626 | SND_PCI_QUIRK(0x1043, 0x1383, "ASUS UJ30Jc", ALC269_ASUS_AMIC), | 13913 | SND_PCI_QUIRK(0x1043, 0x11e3, "ASUS U33Jc", ALC269VB_AMIC), |
13627 | SND_PCI_QUIRK(0x1043, 0x13d3, "ASUS N61JA", ALC269_ASUS_AMIC), | 13914 | SND_PCI_QUIRK(0x1043, 0x1273, "ASUS UL80Jt", ALC269VB_AMIC), |
13628 | SND_PCI_QUIRK(0x1043, 0x1413, "ASUS UL50", ALC269_ASUS_AMIC), | 13915 | SND_PCI_QUIRK(0x1043, 0x1283, "ASUS U53Jc", ALC269_AMIC), |
13629 | SND_PCI_QUIRK(0x1043, 0x1443, "ASUS UL30", ALC269_ASUS_AMIC), | 13916 | SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS N82Jv", ALC269_AMIC), |
13630 | SND_PCI_QUIRK(0x1043, 0x1453, "ASUS M60Jv", ALC269_ASUS_AMIC), | 13917 | SND_PCI_QUIRK(0x1043, 0x12d3, "ASUS N61Jv", ALC269_AMIC), |
13631 | SND_PCI_QUIRK(0x1043, 0x1483, "ASUS UL80", ALC269_ASUS_AMIC), | 13918 | SND_PCI_QUIRK(0x1043, 0x13a3, "ASUS UL30Vt", ALC269_AMIC), |
13632 | SND_PCI_QUIRK(0x1043, 0x14f3, "ASUS F83Vf", ALC269_ASUS_AMIC), | 13919 | SND_PCI_QUIRK(0x1043, 0x1373, "ASUS G73JX", ALC269_AMIC), |
13633 | SND_PCI_QUIRK(0x1043, 0x14e3, "ASUS UL20", ALC269_ASUS_AMIC), | 13920 | SND_PCI_QUIRK(0x1043, 0x1383, "ASUS UJ30Jc", ALC269_AMIC), |
13634 | SND_PCI_QUIRK(0x1043, 0x1513, "ASUS UX30", ALC269_ASUS_AMIC), | 13921 | SND_PCI_QUIRK(0x1043, 0x13d3, "ASUS N61JA", ALC269_AMIC), |
13635 | SND_PCI_QUIRK(0x1043, 0x15a3, "ASUS N60Jv", ALC269_ASUS_AMIC), | 13922 | SND_PCI_QUIRK(0x1043, 0x1413, "ASUS UL50", ALC269_AMIC), |
13636 | SND_PCI_QUIRK(0x1043, 0x15b3, "ASUS N60Dp", ALC269_ASUS_AMIC), | 13923 | SND_PCI_QUIRK(0x1043, 0x1443, "ASUS UL30", ALC269_AMIC), |
13637 | SND_PCI_QUIRK(0x1043, 0x15c3, "ASUS N70De", ALC269_ASUS_AMIC), | 13924 | SND_PCI_QUIRK(0x1043, 0x1453, "ASUS M60Jv", ALC269_AMIC), |
13638 | SND_PCI_QUIRK(0x1043, 0x15e3, "ASUS F83T", ALC269_ASUS_AMIC), | 13925 | SND_PCI_QUIRK(0x1043, 0x1483, "ASUS UL80", ALC269_AMIC), |
13639 | SND_PCI_QUIRK(0x1043, 0x1643, "ASUS M60J", ALC269_ASUS_AMIC), | 13926 | SND_PCI_QUIRK(0x1043, 0x14f3, "ASUS F83Vf", ALC269_AMIC), |
13640 | SND_PCI_QUIRK(0x1043, 0x1653, "ASUS U50", ALC269_ASUS_AMIC), | 13927 | SND_PCI_QUIRK(0x1043, 0x14e3, "ASUS UL20", ALC269_AMIC), |
13641 | SND_PCI_QUIRK(0x1043, 0x1693, "ASUS F50N", ALC269_ASUS_AMIC), | 13928 | SND_PCI_QUIRK(0x1043, 0x1513, "ASUS UX30", ALC269_AMIC), |
13642 | SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS F5Q", ALC269_ASUS_AMIC), | 13929 | SND_PCI_QUIRK(0x1043, 0x1593, "ASUS N51Vn", ALC269_AMIC), |
13643 | SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_ASUS_DMIC), | 13930 | SND_PCI_QUIRK(0x1043, 0x15a3, "ASUS N60Jv", ALC269_AMIC), |
13644 | SND_PCI_QUIRK(0x1043, 0x1723, "ASUS P80", ALC269_ASUS_AMIC), | 13931 | SND_PCI_QUIRK(0x1043, 0x15b3, "ASUS N60Dp", ALC269_AMIC), |
13645 | SND_PCI_QUIRK(0x1043, 0x1743, "ASUS U80", ALC269_ASUS_AMIC), | 13932 | SND_PCI_QUIRK(0x1043, 0x15c3, "ASUS N70De", ALC269_AMIC), |
13646 | SND_PCI_QUIRK(0x1043, 0x1773, "ASUS U20A", ALC269_ASUS_AMIC), | 13933 | SND_PCI_QUIRK(0x1043, 0x15e3, "ASUS F83T", ALC269_AMIC), |
13647 | SND_PCI_QUIRK(0x1043, 0x1883, "ASUS F81Se", ALC269_ASUS_AMIC), | 13934 | SND_PCI_QUIRK(0x1043, 0x1643, "ASUS M60J", ALC269_AMIC), |
13935 | SND_PCI_QUIRK(0x1043, 0x1653, "ASUS U50", ALC269_AMIC), | ||
13936 | SND_PCI_QUIRK(0x1043, 0x1693, "ASUS F50N", ALC269_AMIC), | ||
13937 | SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS F5Q", ALC269_AMIC), | ||
13938 | SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_DMIC), | ||
13939 | SND_PCI_QUIRK(0x1043, 0x1723, "ASUS P80", ALC269_AMIC), | ||
13940 | SND_PCI_QUIRK(0x1043, 0x1743, "ASUS U80", ALC269_AMIC), | ||
13941 | SND_PCI_QUIRK(0x1043, 0x1773, "ASUS U20A", ALC269_AMIC), | ||
13942 | SND_PCI_QUIRK(0x1043, 0x1883, "ASUS F81Se", ALC269_AMIC), | ||
13648 | SND_PCI_QUIRK(0x1043, 0x831a, "ASUS Eeepc P901", | 13943 | SND_PCI_QUIRK(0x1043, 0x831a, "ASUS Eeepc P901", |
13649 | ALC269_ASUS_DMIC), | 13944 | ALC269_DMIC), |
13650 | SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101", | 13945 | SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101", |
13651 | ALC269_ASUS_DMIC), | 13946 | ALC269_DMIC), |
13652 | SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005HA", ALC269_ASUS_DMIC), | 13947 | SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005HA", ALC269_DMIC), |
13653 | SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005HA", ALC269_ASUS_DMIC), | 13948 | SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005HA", ALC269_DMIC), |
13654 | SND_PCI_QUIRK(0x1734, 0x115d, "FSC Amilo", ALC269_FUJITSU), | 13949 | SND_PCI_QUIRK(0x104d, 0x9071, "SONY XTB", ALC269_DMIC), |
13655 | SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook ICH9M-based", ALC269_LIFEBOOK), | 13950 | SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook ICH9M-based", ALC269_LIFEBOOK), |
13951 | SND_PCI_QUIRK(0x152d, 0x1778, "Quanta ON1", ALC269_DMIC), | ||
13952 | SND_PCI_QUIRK(0x1734, 0x115d, "FSC Amilo", ALC269_FUJITSU), | ||
13953 | SND_PCI_QUIRK(0x17aa, 0x3be9, "Quanta Wistron", ALC269_AMIC), | ||
13954 | SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_AMIC), | ||
13955 | SND_PCI_QUIRK(0x17ff, 0x059a, "Quanta EL3", ALC269_DMIC), | ||
13956 | SND_PCI_QUIRK(0x17ff, 0x059b, "Quanta JR1", ALC269_DMIC), | ||
13656 | {} | 13957 | {} |
13657 | }; | 13958 | }; |
13658 | 13959 | ||
@@ -13680,47 +13981,75 @@ static struct alc_config_preset alc269_presets[] = { | |||
13680 | .setup = alc269_quanta_fl1_setup, | 13981 | .setup = alc269_quanta_fl1_setup, |
13681 | .init_hook = alc269_quanta_fl1_init_hook, | 13982 | .init_hook = alc269_quanta_fl1_init_hook, |
13682 | }, | 13983 | }, |
13683 | [ALC269_ASUS_AMIC] = { | 13984 | [ALC269_AMIC] = { |
13684 | .mixers = { alc269_eeepc_mixer }, | 13985 | .mixers = { alc269_laptop_mixer }, |
13685 | .cap_mixer = alc269_epc_capture_mixer, | 13986 | .cap_mixer = alc269_laptop_analog_capture_mixer, |
13686 | .init_verbs = { alc269_init_verbs, | 13987 | .init_verbs = { alc269_init_verbs, |
13687 | alc269_eeepc_amic_init_verbs }, | 13988 | alc269_laptop_amic_init_verbs }, |
13688 | .num_dacs = ARRAY_SIZE(alc269_dac_nids), | 13989 | .num_dacs = ARRAY_SIZE(alc269_dac_nids), |
13689 | .dac_nids = alc269_dac_nids, | 13990 | .dac_nids = alc269_dac_nids, |
13690 | .hp_nid = 0x03, | 13991 | .hp_nid = 0x03, |
13691 | .num_channel_mode = ARRAY_SIZE(alc269_modes), | 13992 | .num_channel_mode = ARRAY_SIZE(alc269_modes), |
13692 | .channel_mode = alc269_modes, | 13993 | .channel_mode = alc269_modes, |
13693 | .unsol_event = alc269_eeepc_unsol_event, | 13994 | .unsol_event = alc269_laptop_unsol_event, |
13694 | .setup = alc269_eeepc_amic_setup, | 13995 | .setup = alc269_laptop_amic_setup, |
13695 | .init_hook = alc269_eeepc_inithook, | 13996 | .init_hook = alc269_laptop_inithook, |
13696 | }, | 13997 | }, |
13697 | [ALC269_ASUS_DMIC] = { | 13998 | [ALC269_DMIC] = { |
13698 | .mixers = { alc269_eeepc_mixer }, | 13999 | .mixers = { alc269_laptop_mixer }, |
13699 | .cap_mixer = alc269_epc_capture_mixer, | 14000 | .cap_mixer = alc269_laptop_digital_capture_mixer, |
13700 | .init_verbs = { alc269_init_verbs, | 14001 | .init_verbs = { alc269_init_verbs, |
13701 | alc269_eeepc_dmic_init_verbs }, | 14002 | alc269_laptop_dmic_init_verbs }, |
14003 | .num_dacs = ARRAY_SIZE(alc269_dac_nids), | ||
14004 | .dac_nids = alc269_dac_nids, | ||
14005 | .hp_nid = 0x03, | ||
14006 | .num_channel_mode = ARRAY_SIZE(alc269_modes), | ||
14007 | .channel_mode = alc269_modes, | ||
14008 | .unsol_event = alc269_laptop_unsol_event, | ||
14009 | .setup = alc269_laptop_dmic_setup, | ||
14010 | .init_hook = alc269_laptop_inithook, | ||
14011 | }, | ||
14012 | [ALC269VB_AMIC] = { | ||
14013 | .mixers = { alc269vb_laptop_mixer }, | ||
14014 | .cap_mixer = alc269vb_laptop_analog_capture_mixer, | ||
14015 | .init_verbs = { alc269vb_init_verbs, | ||
14016 | alc269vb_laptop_amic_init_verbs }, | ||
14017 | .num_dacs = ARRAY_SIZE(alc269_dac_nids), | ||
14018 | .dac_nids = alc269_dac_nids, | ||
14019 | .hp_nid = 0x03, | ||
14020 | .num_channel_mode = ARRAY_SIZE(alc269_modes), | ||
14021 | .channel_mode = alc269_modes, | ||
14022 | .unsol_event = alc269_laptop_unsol_event, | ||
14023 | .setup = alc269_laptop_amic_setup, | ||
14024 | .init_hook = alc269_laptop_inithook, | ||
14025 | }, | ||
14026 | [ALC269VB_DMIC] = { | ||
14027 | .mixers = { alc269vb_laptop_mixer }, | ||
14028 | .cap_mixer = alc269vb_laptop_digital_capture_mixer, | ||
14029 | .init_verbs = { alc269vb_init_verbs, | ||
14030 | alc269vb_laptop_dmic_init_verbs }, | ||
13702 | .num_dacs = ARRAY_SIZE(alc269_dac_nids), | 14031 | .num_dacs = ARRAY_SIZE(alc269_dac_nids), |
13703 | .dac_nids = alc269_dac_nids, | 14032 | .dac_nids = alc269_dac_nids, |
13704 | .hp_nid = 0x03, | 14033 | .hp_nid = 0x03, |
13705 | .num_channel_mode = ARRAY_SIZE(alc269_modes), | 14034 | .num_channel_mode = ARRAY_SIZE(alc269_modes), |
13706 | .channel_mode = alc269_modes, | 14035 | .channel_mode = alc269_modes, |
13707 | .unsol_event = alc269_eeepc_unsol_event, | 14036 | .unsol_event = alc269_laptop_unsol_event, |
13708 | .setup = alc269_eeepc_dmic_setup, | 14037 | .setup = alc269vb_laptop_dmic_setup, |
13709 | .init_hook = alc269_eeepc_inithook, | 14038 | .init_hook = alc269_laptop_inithook, |
13710 | }, | 14039 | }, |
13711 | [ALC269_FUJITSU] = { | 14040 | [ALC269_FUJITSU] = { |
13712 | .mixers = { alc269_fujitsu_mixer }, | 14041 | .mixers = { alc269_fujitsu_mixer }, |
13713 | .cap_mixer = alc269_epc_capture_mixer, | 14042 | .cap_mixer = alc269_laptop_digital_capture_mixer, |
13714 | .init_verbs = { alc269_init_verbs, | 14043 | .init_verbs = { alc269_init_verbs, |
13715 | alc269_eeepc_dmic_init_verbs }, | 14044 | alc269_laptop_dmic_init_verbs }, |
13716 | .num_dacs = ARRAY_SIZE(alc269_dac_nids), | 14045 | .num_dacs = ARRAY_SIZE(alc269_dac_nids), |
13717 | .dac_nids = alc269_dac_nids, | 14046 | .dac_nids = alc269_dac_nids, |
13718 | .hp_nid = 0x03, | 14047 | .hp_nid = 0x03, |
13719 | .num_channel_mode = ARRAY_SIZE(alc269_modes), | 14048 | .num_channel_mode = ARRAY_SIZE(alc269_modes), |
13720 | .channel_mode = alc269_modes, | 14049 | .channel_mode = alc269_modes, |
13721 | .unsol_event = alc269_eeepc_unsol_event, | 14050 | .unsol_event = alc269_laptop_unsol_event, |
13722 | .setup = alc269_eeepc_dmic_setup, | 14051 | .setup = alc269_laptop_dmic_setup, |
13723 | .init_hook = alc269_eeepc_inithook, | 14052 | .init_hook = alc269_laptop_inithook, |
13724 | }, | 14053 | }, |
13725 | [ALC269_LIFEBOOK] = { | 14054 | [ALC269_LIFEBOOK] = { |
13726 | .mixers = { alc269_lifebook_mixer }, | 14055 | .mixers = { alc269_lifebook_mixer }, |
@@ -13741,6 +14070,7 @@ static int patch_alc269(struct hda_codec *codec) | |||
13741 | struct alc_spec *spec; | 14070 | struct alc_spec *spec; |
13742 | int board_config; | 14071 | int board_config; |
13743 | int err; | 14072 | int err; |
14073 | int is_alc269vb = 0; | ||
13744 | 14074 | ||
13745 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 14075 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); |
13746 | if (spec == NULL) | 14076 | if (spec == NULL) |
@@ -13757,6 +14087,7 @@ static int patch_alc269(struct hda_codec *codec) | |||
13757 | alc_free(codec); | 14087 | alc_free(codec); |
13758 | return -ENOMEM; | 14088 | return -ENOMEM; |
13759 | } | 14089 | } |
14090 | is_alc269vb = 1; | ||
13760 | } | 14091 | } |
13761 | 14092 | ||
13762 | board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST, | 14093 | board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST, |
@@ -13792,7 +14123,7 @@ static int patch_alc269(struct hda_codec *codec) | |||
13792 | if (board_config != ALC269_AUTO) | 14123 | if (board_config != ALC269_AUTO) |
13793 | setup_preset(codec, &alc269_presets[board_config]); | 14124 | setup_preset(codec, &alc269_presets[board_config]); |
13794 | 14125 | ||
13795 | if (codec->subsystem_id == 0x17aa3bf8) { | 14126 | if (board_config == ALC269_QUANTA_FL1) { |
13796 | /* Due to a hardware problem on Lenovo Ideadpad, we need to | 14127 | /* Due to a hardware problem on Lenovo Ideadpad, we need to |
13797 | * fix the sample rate of analog I/O to 44.1kHz | 14128 | * fix the sample rate of analog I/O to 44.1kHz |
13798 | */ | 14129 | */ |
@@ -13805,9 +14136,16 @@ static int patch_alc269(struct hda_codec *codec) | |||
13805 | spec->stream_digital_playback = &alc269_pcm_digital_playback; | 14136 | spec->stream_digital_playback = &alc269_pcm_digital_playback; |
13806 | spec->stream_digital_capture = &alc269_pcm_digital_capture; | 14137 | spec->stream_digital_capture = &alc269_pcm_digital_capture; |
13807 | 14138 | ||
13808 | spec->adc_nids = alc269_adc_nids; | 14139 | if (!is_alc269vb) { |
13809 | spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids); | 14140 | spec->adc_nids = alc269_adc_nids; |
13810 | spec->capsrc_nids = alc269_capsrc_nids; | 14141 | spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids); |
14142 | spec->capsrc_nids = alc269_capsrc_nids; | ||
14143 | } else { | ||
14144 | spec->adc_nids = alc269vb_adc_nids; | ||
14145 | spec->num_adc_nids = ARRAY_SIZE(alc269vb_adc_nids); | ||
14146 | spec->capsrc_nids = alc269vb_capsrc_nids; | ||
14147 | } | ||
14148 | |||
13811 | if (!spec->cap_mixer) | 14149 | if (!spec->cap_mixer) |
13812 | set_capture_mixer(codec); | 14150 | set_capture_mixer(codec); |
13813 | set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT); | 14151 | set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT); |
@@ -13821,7 +14159,6 @@ static int patch_alc269(struct hda_codec *codec) | |||
13821 | if (!spec->loopback.amplist) | 14159 | if (!spec->loopback.amplist) |
13822 | spec->loopback.amplist = alc269_loopbacks; | 14160 | spec->loopback.amplist = alc269_loopbacks; |
13823 | #endif | 14161 | #endif |
13824 | codec->proc_widget_hook = print_realtek_coef; | ||
13825 | 14162 | ||
13826 | return 0; | 14163 | return 0; |
13827 | } | 14164 | } |
@@ -14684,7 +15021,7 @@ static int alc861_parse_auto_config(struct hda_codec *codec) | |||
14684 | spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids); | 15021 | spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids); |
14685 | set_capture_mixer(codec); | 15022 | set_capture_mixer(codec); |
14686 | 15023 | ||
14687 | alc_ssid_check(codec, 0x0e, 0x0f, 0x0b); | 15024 | alc_ssid_check(codec, 0x0e, 0x0f, 0x0b, 0); |
14688 | 15025 | ||
14689 | return 1; | 15026 | return 1; |
14690 | } | 15027 | } |
@@ -14939,13 +15276,16 @@ static int patch_alc861(struct hda_codec *codec) | |||
14939 | spec->vmaster_nid = 0x03; | 15276 | spec->vmaster_nid = 0x03; |
14940 | 15277 | ||
14941 | codec->patch_ops = alc_patch_ops; | 15278 | codec->patch_ops = alc_patch_ops; |
14942 | if (board_config == ALC861_AUTO) | 15279 | if (board_config == ALC861_AUTO) { |
14943 | spec->init_hook = alc861_auto_init; | 15280 | spec->init_hook = alc861_auto_init; |
14944 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 15281 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
15282 | spec->power_hook = alc_power_eapd; | ||
15283 | #endif | ||
15284 | } | ||
15285 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
14945 | if (!spec->loopback.amplist) | 15286 | if (!spec->loopback.amplist) |
14946 | spec->loopback.amplist = alc861_loopbacks; | 15287 | spec->loopback.amplist = alc861_loopbacks; |
14947 | #endif | 15288 | #endif |
14948 | codec->proc_widget_hook = print_realtek_coef; | ||
14949 | 15289 | ||
14950 | return 0; | 15290 | return 0; |
14951 | } | 15291 | } |
@@ -15572,7 +15912,7 @@ static struct alc_config_preset alc861vd_presets[] = { | |||
15572 | static int alc861vd_auto_create_input_ctls(struct hda_codec *codec, | 15912 | static int alc861vd_auto_create_input_ctls(struct hda_codec *codec, |
15573 | const struct auto_pin_cfg *cfg) | 15913 | const struct auto_pin_cfg *cfg) |
15574 | { | 15914 | { |
15575 | return alc_auto_create_input_ctls(codec, cfg, 0x15, 0x22, 0); | 15915 | return alc_auto_create_input_ctls(codec, cfg, 0x15, 0x09, 0); |
15576 | } | 15916 | } |
15577 | 15917 | ||
15578 | 15918 | ||
@@ -15808,7 +16148,7 @@ static int alc861vd_parse_auto_config(struct hda_codec *codec) | |||
15808 | if (err < 0) | 16148 | if (err < 0) |
15809 | return err; | 16149 | return err; |
15810 | 16150 | ||
15811 | alc_ssid_check(codec, 0x15, 0x1b, 0x14); | 16151 | alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0); |
15812 | 16152 | ||
15813 | return 1; | 16153 | return 1; |
15814 | } | 16154 | } |
@@ -15925,7 +16265,6 @@ static int patch_alc861vd(struct hda_codec *codec) | |||
15925 | if (!spec->loopback.amplist) | 16265 | if (!spec->loopback.amplist) |
15926 | spec->loopback.amplist = alc861vd_loopbacks; | 16266 | spec->loopback.amplist = alc861vd_loopbacks; |
15927 | #endif | 16267 | #endif |
15928 | codec->proc_widget_hook = print_realtek_coef; | ||
15929 | 16268 | ||
15930 | return 0; | 16269 | return 0; |
15931 | } | 16270 | } |
@@ -16392,13 +16731,6 @@ static struct hda_verb alc662_init_verbs[] = { | |||
16392 | /* ADC: mute amp left and right */ | 16731 | /* ADC: mute amp left and right */ |
16393 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | 16732 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, |
16394 | {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, | 16733 | {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, |
16395 | /* Front mixer: unmute input/output amp left and right (volume = 0) */ | ||
16396 | |||
16397 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
16398 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
16399 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
16400 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
16401 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
16402 | 16734 | ||
16403 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 16735 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
16404 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | 16736 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, |
@@ -16448,6 +16780,28 @@ static struct hda_verb alc662_init_verbs[] = { | |||
16448 | { } | 16780 | { } |
16449 | }; | 16781 | }; |
16450 | 16782 | ||
16783 | static struct hda_verb alc663_init_verbs[] = { | ||
16784 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
16785 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
16786 | {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
16787 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
16788 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
16789 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
16790 | { } | ||
16791 | }; | ||
16792 | |||
16793 | static struct hda_verb alc272_init_verbs[] = { | ||
16794 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
16795 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
16796 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
16797 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
16798 | {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
16799 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
16800 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
16801 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
16802 | { } | ||
16803 | }; | ||
16804 | |||
16451 | static struct hda_verb alc662_sue_init_verbs[] = { | 16805 | static struct hda_verb alc662_sue_init_verbs[] = { |
16452 | {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT}, | 16806 | {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT}, |
16453 | {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT}, | 16807 | {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT}, |
@@ -16467,61 +16821,6 @@ static struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = { | |||
16467 | {} | 16821 | {} |
16468 | }; | 16822 | }; |
16469 | 16823 | ||
16470 | /* | ||
16471 | * generic initialization of ADC, input mixers and output mixers | ||
16472 | */ | ||
16473 | static struct hda_verb alc662_auto_init_verbs[] = { | ||
16474 | /* | ||
16475 | * Unmute ADC and set the default input to mic-in | ||
16476 | */ | ||
16477 | {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
16478 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
16479 | |||
16480 | /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback | ||
16481 | * mixer widget | ||
16482 | * Note: PASD motherboards uses the Line In 2 as the input for front | ||
16483 | * panel mic (mic 2) | ||
16484 | */ | ||
16485 | /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ | ||
16486 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
16487 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
16488 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
16489 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
16490 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
16491 | |||
16492 | /* | ||
16493 | * Set up output mixers (0x0c - 0x0f) | ||
16494 | */ | ||
16495 | /* set vol=0 to output mixers */ | ||
16496 | {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
16497 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
16498 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
16499 | |||
16500 | /* set up input amps for analog loopback */ | ||
16501 | /* Amp Indices: DAC = 0, mixer = 1 */ | ||
16502 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
16503 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
16504 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
16505 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
16506 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
16507 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
16508 | |||
16509 | |||
16510 | /* FIXME: use matrix-type input source selection */ | ||
16511 | /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ | ||
16512 | /* Input mixer */ | ||
16513 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
16514 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
16515 | { } | ||
16516 | }; | ||
16517 | |||
16518 | /* additional verbs for ALC663 */ | ||
16519 | static struct hda_verb alc663_auto_init_verbs[] = { | ||
16520 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
16521 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
16522 | { } | ||
16523 | }; | ||
16524 | |||
16525 | static struct hda_verb alc663_m51va_init_verbs[] = { | 16824 | static struct hda_verb alc663_m51va_init_verbs[] = { |
16526 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | 16825 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, |
16527 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | 16826 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, |
@@ -17272,6 +17571,7 @@ static struct snd_pci_quirk alc662_cfg_tbl[] = { | |||
17272 | SND_PCI_QUIRK(0x1028, 0x02f4, "DELL ZM1", ALC272_DELL_ZM1), | 17571 | SND_PCI_QUIRK(0x1028, 0x02f4, "DELL ZM1", ALC272_DELL_ZM1), |
17273 | SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC663_ASUS_MODE1), | 17572 | SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC663_ASUS_MODE1), |
17274 | SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC663_ASUS_MODE3), | 17573 | SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC663_ASUS_MODE3), |
17574 | SND_PCI_QUIRK(0x1043, 0x1173, "ASUS K73Jn", ALC663_ASUS_MODE1), | ||
17275 | SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC663_ASUS_MODE3), | 17575 | SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC663_ASUS_MODE3), |
17276 | SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC663_ASUS_MODE1), | 17576 | SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC663_ASUS_MODE1), |
17277 | SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_ASUS_MODE2), | 17577 | SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_ASUS_MODE2), |
@@ -17307,6 +17607,7 @@ static struct snd_pci_quirk alc662_cfg_tbl[] = { | |||
17307 | SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC663_ASUS_MODE3), | 17607 | SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC663_ASUS_MODE3), |
17308 | SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC663_ASUS_MODE3), | 17608 | SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC663_ASUS_MODE3), |
17309 | SND_PCI_QUIRK(0x1043, 0x18b3, "ASUS N80Vc", ALC663_ASUS_MODE1), | 17609 | SND_PCI_QUIRK(0x1043, 0x18b3, "ASUS N80Vc", ALC663_ASUS_MODE1), |
17610 | SND_PCI_QUIRK(0x1043, 0x18c3, "ASUS VX5", ALC663_ASUS_MODE1), | ||
17310 | SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS N81Te", ALC663_ASUS_MODE1), | 17611 | SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS N81Te", ALC663_ASUS_MODE1), |
17311 | SND_PCI_QUIRK(0x1043, 0x18f3, "ASUS N505Tp", ALC663_ASUS_MODE1), | 17612 | SND_PCI_QUIRK(0x1043, 0x18f3, "ASUS N505Tp", ALC663_ASUS_MODE1), |
17312 | SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC663_ASUS_MODE1), | 17613 | SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC663_ASUS_MODE1), |
@@ -17334,6 +17635,7 @@ static struct snd_pci_quirk alc662_cfg_tbl[] = { | |||
17334 | SND_PCI_QUIRK(0x144d, 0xca00, "Samsung NC10", ALC272_SAMSUNG_NC10), | 17635 | SND_PCI_QUIRK(0x144d, 0xca00, "Samsung NC10", ALC272_SAMSUNG_NC10), |
17335 | SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L", | 17636 | SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L", |
17336 | ALC662_3ST_6ch_DIG), | 17637 | ALC662_3ST_6ch_DIG), |
17638 | SND_PCI_QUIRK(0x152d, 0x2304, "Quanta WH1", ALC663_ASUS_H13), | ||
17337 | SND_PCI_QUIRK(0x1565, 0x820f, "Biostar TA780G M2+", ALC662_3ST_6ch_DIG), | 17639 | SND_PCI_QUIRK(0x1565, 0x820f, "Biostar TA780G M2+", ALC662_3ST_6ch_DIG), |
17338 | SND_PCI_QUIRK(0x1631, 0xc10c, "PB RS65", ALC663_ASUS_M51VA), | 17640 | SND_PCI_QUIRK(0x1631, 0xc10c, "PB RS65", ALC663_ASUS_M51VA), |
17339 | SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E), | 17641 | SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E), |
@@ -17952,15 +18254,23 @@ static int alc662_parse_auto_config(struct hda_codec *codec) | |||
17952 | spec->num_mux_defs = 1; | 18254 | spec->num_mux_defs = 1; |
17953 | spec->input_mux = &spec->private_imux[0]; | 18255 | spec->input_mux = &spec->private_imux[0]; |
17954 | 18256 | ||
17955 | add_verb(spec, alc662_auto_init_verbs); | 18257 | add_verb(spec, alc662_init_verbs); |
17956 | if (codec->vendor_id == 0x10ec0663) | 18258 | if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 || |
17957 | add_verb(spec, alc663_auto_init_verbs); | 18259 | codec->vendor_id == 0x10ec0665) |
18260 | add_verb(spec, alc663_init_verbs); | ||
18261 | |||
18262 | if (codec->vendor_id == 0x10ec0272) | ||
18263 | add_verb(spec, alc272_init_verbs); | ||
17958 | 18264 | ||
17959 | err = alc_auto_add_mic_boost(codec); | 18265 | err = alc_auto_add_mic_boost(codec); |
17960 | if (err < 0) | 18266 | if (err < 0) |
17961 | return err; | 18267 | return err; |
17962 | 18268 | ||
17963 | alc_ssid_check(codec, 0x15, 0x1b, 0x14); | 18269 | if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 || |
18270 | codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670) | ||
18271 | alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0x21); | ||
18272 | else | ||
18273 | alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0); | ||
17964 | 18274 | ||
17965 | return 1; | 18275 | return 1; |
17966 | } | 18276 | } |
@@ -18046,11 +18356,20 @@ static int patch_alc662(struct hda_codec *codec) | |||
18046 | 18356 | ||
18047 | if (!spec->cap_mixer) | 18357 | if (!spec->cap_mixer) |
18048 | set_capture_mixer(codec); | 18358 | set_capture_mixer(codec); |
18049 | if (codec->vendor_id == 0x10ec0662) | 18359 | |
18360 | switch (codec->vendor_id) { | ||
18361 | case 0x10ec0662: | ||
18050 | set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); | 18362 | set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); |
18051 | else | 18363 | break; |
18364 | case 0x10ec0272: | ||
18365 | case 0x10ec0663: | ||
18366 | case 0x10ec0665: | ||
18052 | set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT); | 18367 | set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT); |
18053 | 18368 | break; | |
18369 | case 0x10ec0273: | ||
18370 | set_beep_amp(spec, 0x0b, 0x03, HDA_INPUT); | ||
18371 | break; | ||
18372 | } | ||
18054 | spec->vmaster_nid = 0x02; | 18373 | spec->vmaster_nid = 0x02; |
18055 | 18374 | ||
18056 | codec->patch_ops = alc_patch_ops; | 18375 | codec->patch_ops = alc_patch_ops; |
@@ -18060,7 +18379,6 @@ static int patch_alc662(struct hda_codec *codec) | |||
18060 | if (!spec->loopback.amplist) | 18379 | if (!spec->loopback.amplist) |
18061 | spec->loopback.amplist = alc662_loopbacks; | 18380 | spec->loopback.amplist = alc662_loopbacks; |
18062 | #endif | 18381 | #endif |
18063 | codec->proc_widget_hook = print_realtek_coef; | ||
18064 | 18382 | ||
18065 | return 0; | 18383 | return 0; |
18066 | } | 18384 | } |
@@ -18101,6 +18419,8 @@ static struct hda_codec_preset snd_hda_preset_realtek[] = { | |||
18101 | { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1", | 18419 | { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1", |
18102 | .patch = patch_alc662 }, | 18420 | .patch = patch_alc662 }, |
18103 | { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 }, | 18421 | { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 }, |
18422 | { .id = 0x10ec0665, .name = "ALC665", .patch = patch_alc662 }, | ||
18423 | { .id = 0x10ec0670, .name = "ALC670", .patch = patch_alc662 }, | ||
18104 | { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 }, | 18424 | { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 }, |
18105 | { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 }, | 18425 | { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 }, |
18106 | { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc882 }, | 18426 | { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc882 }, |
diff --git a/sound/pci/hda/patch_si3054.c b/sound/pci/hda/patch_si3054.c index 43b436c5d01b..f419ee8d75f0 100644 --- a/sound/pci/hda/patch_si3054.c +++ b/sound/pci/hda/patch_si3054.c | |||
@@ -122,6 +122,7 @@ static int si3054_switch_put(struct snd_kcontrol *kcontrol, | |||
122 | #define SI3054_KCONTROL(kname,reg,mask) { \ | 122 | #define SI3054_KCONTROL(kname,reg,mask) { \ |
123 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | 123 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ |
124 | .name = kname, \ | 124 | .name = kname, \ |
125 | .subdevice = HDA_SUBDEV_NID_FLAG | reg, \ | ||
125 | .info = si3054_switch_info, \ | 126 | .info = si3054_switch_info, \ |
126 | .get = si3054_switch_get, \ | 127 | .get = si3054_switch_get, \ |
127 | .put = si3054_switch_put, \ | 128 | .put = si3054_switch_put, \ |
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 799ba2570902..8c416bb18a57 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c | |||
@@ -568,6 +568,11 @@ static hda_nid_t stac92hd83xxx_pin_nids[10] = { | |||
568 | 0x0f, 0x10, 0x11, 0x1f, 0x20, | 568 | 0x0f, 0x10, 0x11, 0x1f, 0x20, |
569 | }; | 569 | }; |
570 | 570 | ||
571 | static hda_nid_t stac92hd88xxx_pin_nids[10] = { | ||
572 | 0x0a, 0x0b, 0x0c, 0x0d, | ||
573 | 0x0f, 0x11, 0x1f, 0x20, | ||
574 | }; | ||
575 | |||
571 | #define STAC92HD71BXX_NUM_PINS 13 | 576 | #define STAC92HD71BXX_NUM_PINS 13 |
572 | static hda_nid_t stac92hd71bxx_pin_nids_4port[STAC92HD71BXX_NUM_PINS] = { | 577 | static hda_nid_t stac92hd71bxx_pin_nids_4port[STAC92HD71BXX_NUM_PINS] = { |
573 | 0x0a, 0x0b, 0x0c, 0x0d, 0x00, | 578 | 0x0a, 0x0b, 0x0c, 0x0d, 0x00, |
@@ -2688,7 +2693,7 @@ static struct snd_kcontrol_new * | |||
2688 | stac_control_new(struct sigmatel_spec *spec, | 2693 | stac_control_new(struct sigmatel_spec *spec, |
2689 | struct snd_kcontrol_new *ktemp, | 2694 | struct snd_kcontrol_new *ktemp, |
2690 | const char *name, | 2695 | const char *name, |
2691 | hda_nid_t nid) | 2696 | unsigned int subdev) |
2692 | { | 2697 | { |
2693 | struct snd_kcontrol_new *knew; | 2698 | struct snd_kcontrol_new *knew; |
2694 | 2699 | ||
@@ -2704,8 +2709,7 @@ stac_control_new(struct sigmatel_spec *spec, | |||
2704 | spec->kctls.alloced--; | 2709 | spec->kctls.alloced--; |
2705 | return NULL; | 2710 | return NULL; |
2706 | } | 2711 | } |
2707 | if (nid) | 2712 | knew->subdevice = subdev; |
2708 | knew->subdevice = HDA_SUBDEV_NID_FLAG | nid; | ||
2709 | return knew; | 2713 | return knew; |
2710 | } | 2714 | } |
2711 | 2715 | ||
@@ -2715,7 +2719,7 @@ static int stac92xx_add_control_temp(struct sigmatel_spec *spec, | |||
2715 | unsigned long val) | 2719 | unsigned long val) |
2716 | { | 2720 | { |
2717 | struct snd_kcontrol_new *knew = stac_control_new(spec, ktemp, name, | 2721 | struct snd_kcontrol_new *knew = stac_control_new(spec, ktemp, name, |
2718 | get_amp_nid_(val)); | 2722 | HDA_SUBDEV_AMP_FLAG); |
2719 | if (!knew) | 2723 | if (!knew) |
2720 | return -ENOMEM; | 2724 | return -ENOMEM; |
2721 | knew->index = idx; | 2725 | knew->index = idx; |
@@ -2874,6 +2878,13 @@ static hda_nid_t get_unassigned_dac(struct hda_codec *codec, hda_nid_t nid) | |||
2874 | 2878 | ||
2875 | conn_len = snd_hda_get_connections(codec, nid, conn, | 2879 | conn_len = snd_hda_get_connections(codec, nid, conn, |
2876 | HDA_MAX_CONNECTIONS); | 2880 | HDA_MAX_CONNECTIONS); |
2881 | /* 92HD88: trace back up the link of nids to find the DAC */ | ||
2882 | while (conn_len == 1 && (get_wcaps_type(get_wcaps(codec, conn[0])) | ||
2883 | != AC_WID_AUD_OUT)) { | ||
2884 | nid = conn[0]; | ||
2885 | conn_len = snd_hda_get_connections(codec, nid, conn, | ||
2886 | HDA_MAX_CONNECTIONS); | ||
2887 | } | ||
2877 | for (j = 0; j < conn_len; j++) { | 2888 | for (j = 0; j < conn_len; j++) { |
2878 | wcaps = get_wcaps(codec, conn[j]); | 2889 | wcaps = get_wcaps(codec, conn[j]); |
2879 | wtype = get_wcaps_type(wcaps); | 2890 | wtype = get_wcaps_type(wcaps); |
@@ -4160,34 +4171,52 @@ static void stac92xx_power_down(struct hda_codec *codec) | |||
4160 | static void stac_toggle_power_map(struct hda_codec *codec, hda_nid_t nid, | 4171 | static void stac_toggle_power_map(struct hda_codec *codec, hda_nid_t nid, |
4161 | int enable); | 4172 | int enable); |
4162 | 4173 | ||
4174 | static inline int get_int_hint(struct hda_codec *codec, const char *key, | ||
4175 | int *valp) | ||
4176 | { | ||
4177 | const char *p; | ||
4178 | p = snd_hda_get_hint(codec, key); | ||
4179 | if (p) { | ||
4180 | unsigned long val; | ||
4181 | if (!strict_strtoul(p, 0, &val)) { | ||
4182 | *valp = val; | ||
4183 | return 1; | ||
4184 | } | ||
4185 | } | ||
4186 | return 0; | ||
4187 | } | ||
4188 | |||
4163 | /* override some hints from the hwdep entry */ | 4189 | /* override some hints from the hwdep entry */ |
4164 | static void stac_store_hints(struct hda_codec *codec) | 4190 | static void stac_store_hints(struct hda_codec *codec) |
4165 | { | 4191 | { |
4166 | struct sigmatel_spec *spec = codec->spec; | 4192 | struct sigmatel_spec *spec = codec->spec; |
4167 | const char *p; | ||
4168 | int val; | 4193 | int val; |
4169 | 4194 | ||
4170 | val = snd_hda_get_bool_hint(codec, "hp_detect"); | 4195 | val = snd_hda_get_bool_hint(codec, "hp_detect"); |
4171 | if (val >= 0) | 4196 | if (val >= 0) |
4172 | spec->hp_detect = val; | 4197 | spec->hp_detect = val; |
4173 | p = snd_hda_get_hint(codec, "gpio_mask"); | 4198 | if (get_int_hint(codec, "gpio_mask", &spec->gpio_mask)) { |
4174 | if (p) { | ||
4175 | spec->gpio_mask = simple_strtoul(p, NULL, 0); | ||
4176 | spec->eapd_mask = spec->gpio_dir = spec->gpio_data = | 4199 | spec->eapd_mask = spec->gpio_dir = spec->gpio_data = |
4177 | spec->gpio_mask; | 4200 | spec->gpio_mask; |
4178 | } | 4201 | } |
4179 | p = snd_hda_get_hint(codec, "gpio_dir"); | 4202 | if (get_int_hint(codec, "gpio_dir", &spec->gpio_dir)) |
4180 | if (p) | 4203 | spec->gpio_mask &= spec->gpio_mask; |
4181 | spec->gpio_dir = simple_strtoul(p, NULL, 0) & spec->gpio_mask; | 4204 | if (get_int_hint(codec, "gpio_data", &spec->gpio_data)) |
4182 | p = snd_hda_get_hint(codec, "gpio_data"); | 4205 | spec->gpio_dir &= spec->gpio_mask; |
4183 | if (p) | 4206 | if (get_int_hint(codec, "eapd_mask", &spec->eapd_mask)) |
4184 | spec->gpio_data = simple_strtoul(p, NULL, 0) & spec->gpio_mask; | 4207 | spec->eapd_mask &= spec->gpio_mask; |
4185 | p = snd_hda_get_hint(codec, "eapd_mask"); | 4208 | if (get_int_hint(codec, "gpio_mute", &spec->gpio_mute)) |
4186 | if (p) | 4209 | spec->gpio_mute &= spec->gpio_mask; |
4187 | spec->eapd_mask = simple_strtoul(p, NULL, 0) & spec->gpio_mask; | ||
4188 | val = snd_hda_get_bool_hint(codec, "eapd_switch"); | 4210 | val = snd_hda_get_bool_hint(codec, "eapd_switch"); |
4189 | if (val >= 0) | 4211 | if (val >= 0) |
4190 | spec->eapd_switch = val; | 4212 | spec->eapd_switch = val; |
4213 | get_int_hint(codec, "gpio_led_polarity", &spec->gpio_led_polarity); | ||
4214 | if (get_int_hint(codec, "gpio_led", &spec->gpio_led)) { | ||
4215 | spec->gpio_mask |= spec->gpio_led; | ||
4216 | spec->gpio_dir |= spec->gpio_led; | ||
4217 | if (spec->gpio_led_polarity) | ||
4218 | spec->gpio_data |= spec->gpio_led; | ||
4219 | } | ||
4191 | } | 4220 | } |
4192 | 4221 | ||
4193 | static int stac92xx_init(struct hda_codec *codec) | 4222 | static int stac92xx_init(struct hda_codec *codec) |
@@ -4334,6 +4363,12 @@ static int stac92xx_init(struct hda_codec *codec) | |||
4334 | if (enable_pin_detect(codec, nid, STAC_PWR_EVENT)) | 4363 | if (enable_pin_detect(codec, nid, STAC_PWR_EVENT)) |
4335 | stac_issue_unsol_event(codec, nid); | 4364 | stac_issue_unsol_event(codec, nid); |
4336 | } | 4365 | } |
4366 | |||
4367 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
4368 | /* sync mute LED */ | ||
4369 | if (spec->gpio_led && codec->patch_ops.check_power_status) | ||
4370 | codec->patch_ops.check_power_status(codec, 0x01); | ||
4371 | #endif | ||
4337 | if (spec->dac_list) | 4372 | if (spec->dac_list) |
4338 | stac92xx_power_down(codec); | 4373 | stac92xx_power_down(codec); |
4339 | return 0; | 4374 | return 0; |
@@ -4372,18 +4407,8 @@ static void stac92xx_free_kctls(struct hda_codec *codec) | |||
4372 | static void stac92xx_shutup(struct hda_codec *codec) | 4407 | static void stac92xx_shutup(struct hda_codec *codec) |
4373 | { | 4408 | { |
4374 | struct sigmatel_spec *spec = codec->spec; | 4409 | struct sigmatel_spec *spec = codec->spec; |
4375 | int i; | ||
4376 | hda_nid_t nid; | ||
4377 | 4410 | ||
4378 | /* reset each pin before powering down DAC/ADC to avoid click noise */ | 4411 | snd_hda_shutup_pins(codec); |
4379 | nid = codec->start_nid; | ||
4380 | for (i = 0; i < codec->num_nodes; i++, nid++) { | ||
4381 | unsigned int wcaps = get_wcaps(codec, nid); | ||
4382 | unsigned int wid_type = get_wcaps_type(wcaps); | ||
4383 | if (wid_type == AC_WID_PIN) | ||
4384 | snd_hda_codec_read(codec, nid, 0, | ||
4385 | AC_VERB_SET_PIN_WIDGET_CONTROL, 0); | ||
4386 | } | ||
4387 | 4412 | ||
4388 | if (spec->eapd_mask) | 4413 | if (spec->eapd_mask) |
4389 | stac_gpio_set(codec, spec->gpio_mask, | 4414 | stac_gpio_set(codec, spec->gpio_mask, |
@@ -4735,19 +4760,14 @@ static int hp_blike_system(u32 subsystem_id); | |||
4735 | static void set_hp_led_gpio(struct hda_codec *codec) | 4760 | static void set_hp_led_gpio(struct hda_codec *codec) |
4736 | { | 4761 | { |
4737 | struct sigmatel_spec *spec = codec->spec; | 4762 | struct sigmatel_spec *spec = codec->spec; |
4738 | switch (codec->vendor_id) { | 4763 | unsigned int gpio; |
4739 | case 0x111d7608: | 4764 | |
4740 | /* GPIO 0 */ | 4765 | gpio = snd_hda_param_read(codec, codec->afg, AC_PAR_GPIO_CAP); |
4741 | spec->gpio_led = 0x01; | 4766 | gpio &= AC_GPIO_IO_COUNT; |
4742 | break; | 4767 | if (gpio > 3) |
4743 | case 0x111d7600: | 4768 | spec->gpio_led = 0x08; /* GPIO 3 */ |
4744 | case 0x111d7601: | 4769 | else |
4745 | case 0x111d7602: | 4770 | spec->gpio_led = 0x01; /* GPIO 0 */ |
4746 | case 0x111d7603: | ||
4747 | /* GPIO 3 */ | ||
4748 | spec->gpio_led = 0x08; | ||
4749 | break; | ||
4750 | } | ||
4751 | } | 4771 | } |
4752 | 4772 | ||
4753 | /* | 4773 | /* |
@@ -4770,7 +4790,7 @@ static void set_hp_led_gpio(struct hda_codec *codec) | |||
4770 | * Need more information on whether it is true across the entire series. | 4790 | * Need more information on whether it is true across the entire series. |
4771 | * -- kunal | 4791 | * -- kunal |
4772 | */ | 4792 | */ |
4773 | static int find_mute_led_gpio(struct hda_codec *codec) | 4793 | static int find_mute_led_gpio(struct hda_codec *codec, int default_polarity) |
4774 | { | 4794 | { |
4775 | struct sigmatel_spec *spec = codec->spec; | 4795 | struct sigmatel_spec *spec = codec->spec; |
4776 | const struct dmi_device *dev = NULL; | 4796 | const struct dmi_device *dev = NULL; |
@@ -4797,7 +4817,7 @@ static int find_mute_led_gpio(struct hda_codec *codec) | |||
4797 | */ | 4817 | */ |
4798 | if (!hp_blike_system(codec->subsystem_id)) { | 4818 | if (!hp_blike_system(codec->subsystem_id)) { |
4799 | set_hp_led_gpio(codec); | 4819 | set_hp_led_gpio(codec); |
4800 | spec->gpio_led_polarity = 1; | 4820 | spec->gpio_led_polarity = default_polarity; |
4801 | return 1; | 4821 | return 1; |
4802 | } | 4822 | } |
4803 | } | 4823 | } |
@@ -4895,6 +4915,11 @@ static int stac92xx_resume(struct hda_codec *codec) | |||
4895 | stac_issue_unsol_event(codec, | 4915 | stac_issue_unsol_event(codec, |
4896 | spec->autocfg.line_out_pins[0]); | 4916 | spec->autocfg.line_out_pins[0]); |
4897 | } | 4917 | } |
4918 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
4919 | /* sync mute LED */ | ||
4920 | if (spec->gpio_led && codec->patch_ops.check_power_status) | ||
4921 | codec->patch_ops.check_power_status(codec, 0x01); | ||
4922 | #endif | ||
4898 | return 0; | 4923 | return 0; |
4899 | } | 4924 | } |
4900 | 4925 | ||
@@ -4914,43 +4939,29 @@ static int stac92xx_hp_check_power_status(struct hda_codec *codec, | |||
4914 | hda_nid_t nid) | 4939 | hda_nid_t nid) |
4915 | { | 4940 | { |
4916 | struct sigmatel_spec *spec = codec->spec; | 4941 | struct sigmatel_spec *spec = codec->spec; |
4942 | int i, muted = 1; | ||
4917 | 4943 | ||
4918 | if (nid == 0x10) { | 4944 | for (i = 0; i < spec->multiout.num_dacs; i++) { |
4919 | if (snd_hda_codec_amp_read(codec, nid, 0, HDA_OUTPUT, 0) & | 4945 | nid = spec->multiout.dac_nids[i]; |
4920 | HDA_AMP_MUTE) | 4946 | if (!(snd_hda_codec_amp_read(codec, nid, 0, HDA_OUTPUT, 0) & |
4921 | spec->gpio_data &= ~spec->gpio_led; /* orange */ | 4947 | HDA_AMP_MUTE)) { |
4922 | else | 4948 | muted = 0; /* something heard */ |
4923 | spec->gpio_data |= spec->gpio_led; /* white */ | 4949 | break; |
4924 | |||
4925 | if (!spec->gpio_led_polarity) { | ||
4926 | /* LED state is inverted on these systems */ | ||
4927 | spec->gpio_data ^= spec->gpio_led; | ||
4928 | } | 4950 | } |
4929 | |||
4930 | stac_gpio_set(codec, spec->gpio_mask, | ||
4931 | spec->gpio_dir, | ||
4932 | spec->gpio_data); | ||
4933 | } | 4951 | } |
4952 | if (muted) | ||
4953 | spec->gpio_data &= ~spec->gpio_led; /* orange */ | ||
4954 | else | ||
4955 | spec->gpio_data |= spec->gpio_led; /* white */ | ||
4934 | 4956 | ||
4935 | return 0; | 4957 | if (!spec->gpio_led_polarity) { |
4936 | } | 4958 | /* LED state is inverted on these systems */ |
4937 | 4959 | spec->gpio_data ^= spec->gpio_led; | |
4938 | static int idt92hd83xxx_hp_check_power_status(struct hda_codec *codec, | 4960 | } |
4939 | hda_nid_t nid) | ||
4940 | { | ||
4941 | struct sigmatel_spec *spec = codec->spec; | ||
4942 | 4961 | ||
4943 | if (nid != 0x13) | ||
4944 | return 0; | ||
4945 | if (snd_hda_codec_amp_read(codec, nid, 0, HDA_OUTPUT, 0) & HDA_AMP_MUTE) | ||
4946 | spec->gpio_data |= spec->gpio_led; /* mute LED on */ | ||
4947 | else | ||
4948 | spec->gpio_data &= ~spec->gpio_led; /* mute LED off */ | ||
4949 | stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, spec->gpio_data); | 4962 | stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, spec->gpio_data); |
4950 | |||
4951 | return 0; | 4963 | return 0; |
4952 | } | 4964 | } |
4953 | |||
4954 | #endif | 4965 | #endif |
4955 | 4966 | ||
4956 | static int stac92xx_suspend(struct hda_codec *codec, pm_message_t state) | 4967 | static int stac92xx_suspend(struct hda_codec *codec, pm_message_t state) |
@@ -5272,7 +5283,6 @@ static int patch_stac92hd83xxx(struct hda_codec *codec) | |||
5272 | hda_nid_t conn[STAC92HD83_DAC_COUNT + 1]; | 5283 | hda_nid_t conn[STAC92HD83_DAC_COUNT + 1]; |
5273 | int err; | 5284 | int err; |
5274 | int num_dacs; | 5285 | int num_dacs; |
5275 | hda_nid_t nid; | ||
5276 | 5286 | ||
5277 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 5287 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); |
5278 | if (spec == NULL) | 5288 | if (spec == NULL) |
@@ -5311,7 +5321,18 @@ again: | |||
5311 | stac92hd83xxx_brd_tbl[spec->board_config]); | 5321 | stac92hd83xxx_brd_tbl[spec->board_config]); |
5312 | 5322 | ||
5313 | switch (codec->vendor_id) { | 5323 | switch (codec->vendor_id) { |
5324 | case 0x111d7666: | ||
5325 | case 0x111d7667: | ||
5326 | case 0x111d7668: | ||
5327 | case 0x111d7669: | ||
5328 | spec->num_pins = ARRAY_SIZE(stac92hd88xxx_pin_nids); | ||
5329 | spec->pin_nids = stac92hd88xxx_pin_nids; | ||
5330 | spec->mono_nid = 0; | ||
5331 | spec->digbeep_nid = 0; | ||
5332 | spec->num_pwrs = 0; | ||
5333 | break; | ||
5314 | case 0x111d7604: | 5334 | case 0x111d7604: |
5335 | case 0x111d76d4: | ||
5315 | case 0x111d7605: | 5336 | case 0x111d7605: |
5316 | case 0x111d76d5: | 5337 | case 0x111d76d5: |
5317 | if (spec->board_config == STAC_92HD83XXX_PWR_REF) | 5338 | if (spec->board_config == STAC_92HD83XXX_PWR_REF) |
@@ -5322,8 +5343,10 @@ again: | |||
5322 | 5343 | ||
5323 | codec->patch_ops = stac92xx_patch_ops; | 5344 | codec->patch_ops = stac92xx_patch_ops; |
5324 | 5345 | ||
5325 | if (spec->board_config == STAC_92HD83XXX_HP) | 5346 | if (find_mute_led_gpio(codec, 0)) |
5326 | spec->gpio_led = 0x01; | 5347 | snd_printd("mute LED gpio %d polarity %d\n", |
5348 | spec->gpio_led, | ||
5349 | spec->gpio_led_polarity); | ||
5327 | 5350 | ||
5328 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 5351 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
5329 | if (spec->gpio_led) { | 5352 | if (spec->gpio_led) { |
@@ -5332,7 +5355,7 @@ again: | |||
5332 | spec->gpio_data |= spec->gpio_led; | 5355 | spec->gpio_data |= spec->gpio_led; |
5333 | /* register check_power_status callback. */ | 5356 | /* register check_power_status callback. */ |
5334 | codec->patch_ops.check_power_status = | 5357 | codec->patch_ops.check_power_status = |
5335 | idt92hd83xxx_hp_check_power_status; | 5358 | stac92xx_hp_check_power_status; |
5336 | } | 5359 | } |
5337 | #endif | 5360 | #endif |
5338 | 5361 | ||
@@ -5352,24 +5375,21 @@ again: | |||
5352 | return err; | 5375 | return err; |
5353 | } | 5376 | } |
5354 | 5377 | ||
5355 | switch (spec->board_config) { | 5378 | /* docking output support */ |
5356 | case STAC_DELL_S14: | 5379 | num_dacs = snd_hda_get_connections(codec, 0xF, |
5357 | nid = 0xf; | ||
5358 | break; | ||
5359 | default: | ||
5360 | nid = 0xe; | ||
5361 | break; | ||
5362 | } | ||
5363 | |||
5364 | num_dacs = snd_hda_get_connections(codec, nid, | ||
5365 | conn, STAC92HD83_DAC_COUNT + 1) - 1; | 5380 | conn, STAC92HD83_DAC_COUNT + 1) - 1; |
5366 | if (num_dacs < 0) | 5381 | /* skip non-DAC connections */ |
5367 | num_dacs = STAC92HD83_DAC_COUNT; | 5382 | while (num_dacs >= 0 && |
5368 | 5383 | (get_wcaps_type(get_wcaps(codec, conn[num_dacs])) | |
5369 | /* set port X to select the last DAC | 5384 | != AC_WID_AUD_OUT)) |
5370 | */ | 5385 | num_dacs--; |
5371 | snd_hda_codec_write_cache(codec, nid, 0, | 5386 | /* set port E and F to select the last DAC */ |
5387 | if (num_dacs >= 0) { | ||
5388 | snd_hda_codec_write_cache(codec, 0xE, 0, | ||
5389 | AC_VERB_SET_CONNECT_SEL, num_dacs); | ||
5390 | snd_hda_codec_write_cache(codec, 0xF, 0, | ||
5372 | AC_VERB_SET_CONNECT_SEL, num_dacs); | 5391 | AC_VERB_SET_CONNECT_SEL, num_dacs); |
5392 | } | ||
5373 | 5393 | ||
5374 | codec->proc_widget_hook = stac92hd_proc_hook; | 5394 | codec->proc_widget_hook = stac92hd_proc_hook; |
5375 | 5395 | ||
@@ -5431,6 +5451,54 @@ static int stac92hd71bxx_connected_smuxes(struct hda_codec *codec, | |||
5431 | return 0; | 5451 | return 0; |
5432 | } | 5452 | } |
5433 | 5453 | ||
5454 | /* HP dv7 bass switch - GPIO5 */ | ||
5455 | #define stac_hp_bass_gpio_info snd_ctl_boolean_mono_info | ||
5456 | static int stac_hp_bass_gpio_get(struct snd_kcontrol *kcontrol, | ||
5457 | struct snd_ctl_elem_value *ucontrol) | ||
5458 | { | ||
5459 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
5460 | struct sigmatel_spec *spec = codec->spec; | ||
5461 | ucontrol->value.integer.value[0] = !!(spec->gpio_data & 0x20); | ||
5462 | return 0; | ||
5463 | } | ||
5464 | |||
5465 | static int stac_hp_bass_gpio_put(struct snd_kcontrol *kcontrol, | ||
5466 | struct snd_ctl_elem_value *ucontrol) | ||
5467 | { | ||
5468 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
5469 | struct sigmatel_spec *spec = codec->spec; | ||
5470 | unsigned int gpio_data; | ||
5471 | |||
5472 | gpio_data = (spec->gpio_data & ~0x20) | | ||
5473 | (ucontrol->value.integer.value[0] ? 0x20 : 0); | ||
5474 | if (gpio_data == spec->gpio_data) | ||
5475 | return 0; | ||
5476 | spec->gpio_data = gpio_data; | ||
5477 | stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, spec->gpio_data); | ||
5478 | return 1; | ||
5479 | } | ||
5480 | |||
5481 | static struct snd_kcontrol_new stac_hp_bass_sw_ctrl = { | ||
5482 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
5483 | .info = stac_hp_bass_gpio_info, | ||
5484 | .get = stac_hp_bass_gpio_get, | ||
5485 | .put = stac_hp_bass_gpio_put, | ||
5486 | }; | ||
5487 | |||
5488 | static int stac_add_hp_bass_switch(struct hda_codec *codec) | ||
5489 | { | ||
5490 | struct sigmatel_spec *spec = codec->spec; | ||
5491 | |||
5492 | if (!stac_control_new(spec, &stac_hp_bass_sw_ctrl, | ||
5493 | "Bass Speaker Playback Switch", 0)) | ||
5494 | return -ENOMEM; | ||
5495 | |||
5496 | spec->gpio_mask |= 0x20; | ||
5497 | spec->gpio_dir |= 0x20; | ||
5498 | spec->gpio_data |= 0x20; | ||
5499 | return 0; | ||
5500 | } | ||
5501 | |||
5434 | static int patch_stac92hd71bxx(struct hda_codec *codec) | 5502 | static int patch_stac92hd71bxx(struct hda_codec *codec) |
5435 | { | 5503 | { |
5436 | struct sigmatel_spec *spec; | 5504 | struct sigmatel_spec *spec; |
@@ -5602,7 +5670,6 @@ again: | |||
5602 | */ | 5670 | */ |
5603 | spec->num_smuxes = 1; | 5671 | spec->num_smuxes = 1; |
5604 | spec->num_dmuxes = 1; | 5672 | spec->num_dmuxes = 1; |
5605 | spec->gpio_led = 0x01; | ||
5606 | /* fallthrough */ | 5673 | /* fallthrough */ |
5607 | case STAC_HP_DV5: | 5674 | case STAC_HP_DV5: |
5608 | snd_hda_codec_set_pincfg(codec, 0x0d, 0x90170010); | 5675 | snd_hda_codec_set_pincfg(codec, 0x0d, 0x90170010); |
@@ -5617,8 +5684,6 @@ again: | |||
5617 | spec->num_dmics = 1; | 5684 | spec->num_dmics = 1; |
5618 | spec->num_dmuxes = 1; | 5685 | spec->num_dmuxes = 1; |
5619 | spec->num_smuxes = 1; | 5686 | spec->num_smuxes = 1; |
5620 | /* orange/white mute led on GPIO3, orange=0, white=1 */ | ||
5621 | spec->gpio_led = 0x08; | ||
5622 | break; | 5687 | break; |
5623 | } | 5688 | } |
5624 | 5689 | ||
@@ -5640,7 +5705,7 @@ again: | |||
5640 | } | 5705 | } |
5641 | } | 5706 | } |
5642 | 5707 | ||
5643 | if (find_mute_led_gpio(codec)) | 5708 | if (find_mute_led_gpio(codec, 1)) |
5644 | snd_printd("mute LED gpio %d polarity %d\n", | 5709 | snd_printd("mute LED gpio %d polarity %d\n", |
5645 | spec->gpio_led, | 5710 | spec->gpio_led, |
5646 | spec->gpio_led_polarity); | 5711 | spec->gpio_led_polarity); |
@@ -5674,6 +5739,15 @@ again: | |||
5674 | return err; | 5739 | return err; |
5675 | } | 5740 | } |
5676 | 5741 | ||
5742 | /* enable bass on HP dv7 */ | ||
5743 | if (spec->board_config == STAC_HP_DV5) { | ||
5744 | unsigned int cap; | ||
5745 | cap = snd_hda_param_read(codec, 0x1, AC_PAR_GPIO_CAP); | ||
5746 | cap &= AC_GPIO_IO_COUNT; | ||
5747 | if (cap >= 6) | ||
5748 | stac_add_hp_bass_switch(codec); | ||
5749 | } | ||
5750 | |||
5677 | codec->proc_widget_hook = stac92hd7x_proc_hook; | 5751 | codec->proc_widget_hook = stac92hd7x_proc_hook; |
5678 | 5752 | ||
5679 | return 0; | 5753 | return 0; |
@@ -6172,8 +6246,13 @@ static struct hda_codec_preset snd_hda_preset_sigmatel[] = { | |||
6172 | { .id = 0x838476a7, .name = "STAC9254D", .patch = patch_stac9205 }, | 6246 | { .id = 0x838476a7, .name = "STAC9254D", .patch = patch_stac9205 }, |
6173 | { .id = 0x111d7603, .name = "92HD75B3X5", .patch = patch_stac92hd71bxx}, | 6247 | { .id = 0x111d7603, .name = "92HD75B3X5", .patch = patch_stac92hd71bxx}, |
6174 | { .id = 0x111d7604, .name = "92HD83C1X5", .patch = patch_stac92hd83xxx}, | 6248 | { .id = 0x111d7604, .name = "92HD83C1X5", .patch = patch_stac92hd83xxx}, |
6249 | { .id = 0x111d76d4, .name = "92HD83C1C5", .patch = patch_stac92hd83xxx}, | ||
6175 | { .id = 0x111d7605, .name = "92HD81B1X5", .patch = patch_stac92hd83xxx}, | 6250 | { .id = 0x111d7605, .name = "92HD81B1X5", .patch = patch_stac92hd83xxx}, |
6176 | { .id = 0x111d76d5, .name = "92HD81B1C5", .patch = patch_stac92hd83xxx}, | 6251 | { .id = 0x111d76d5, .name = "92HD81B1C5", .patch = patch_stac92hd83xxx}, |
6252 | { .id = 0x111d7666, .name = "92HD88B3", .patch = patch_stac92hd83xxx}, | ||
6253 | { .id = 0x111d7667, .name = "92HD88B1", .patch = patch_stac92hd83xxx}, | ||
6254 | { .id = 0x111d7668, .name = "92HD88B2", .patch = patch_stac92hd83xxx}, | ||
6255 | { .id = 0x111d7669, .name = "92HD88B4", .patch = patch_stac92hd83xxx}, | ||
6177 | { .id = 0x111d7608, .name = "92HD75B2X5", .patch = patch_stac92hd71bxx}, | 6256 | { .id = 0x111d7608, .name = "92HD75B2X5", .patch = patch_stac92hd71bxx}, |
6178 | { .id = 0x111d7674, .name = "92HD73D1X5", .patch = patch_stac92hd73xx }, | 6257 | { .id = 0x111d7674, .name = "92HD73D1X5", .patch = patch_stac92hd73xx }, |
6179 | { .id = 0x111d7675, .name = "92HD73C1X5", .patch = patch_stac92hd73xx }, | 6258 | { .id = 0x111d7675, .name = "92HD73C1X5", .patch = patch_stac92hd73xx }, |
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index b70e26ad263f..9ddc37300f6b 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c | |||
@@ -54,6 +54,8 @@ | |||
54 | #include "hda_codec.h" | 54 | #include "hda_codec.h" |
55 | #include "hda_local.h" | 55 | #include "hda_local.h" |
56 | 56 | ||
57 | #define NID_MAPPING (-1) | ||
58 | |||
57 | /* amp values */ | 59 | /* amp values */ |
58 | #define AMP_VAL_IDX_SHIFT 19 | 60 | #define AMP_VAL_IDX_SHIFT 19 |
59 | #define AMP_VAL_IDX_MASK (0x0f<<19) | 61 | #define AMP_VAL_IDX_MASK (0x0f<<19) |
@@ -157,6 +159,19 @@ struct via_spec { | |||
157 | #endif | 159 | #endif |
158 | }; | 160 | }; |
159 | 161 | ||
162 | static struct via_spec * via_new_spec(struct hda_codec *codec) | ||
163 | { | ||
164 | struct via_spec *spec; | ||
165 | |||
166 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
167 | if (spec == NULL) | ||
168 | return NULL; | ||
169 | |||
170 | codec->spec = spec; | ||
171 | spec->codec = codec; | ||
172 | return spec; | ||
173 | } | ||
174 | |||
160 | static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec) | 175 | static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec) |
161 | { | 176 | { |
162 | u32 vendor_id = codec->vendor_id; | 177 | u32 vendor_id = codec->vendor_id; |
@@ -443,11 +458,27 @@ static int via_add_control(struct via_spec *spec, int type, const char *name, | |||
443 | if (!knew->name) | 458 | if (!knew->name) |
444 | return -ENOMEM; | 459 | return -ENOMEM; |
445 | if (get_amp_nid_(val)) | 460 | if (get_amp_nid_(val)) |
446 | knew->subdevice = HDA_SUBDEV_NID_FLAG | get_amp_nid_(val); | 461 | knew->subdevice = HDA_SUBDEV_AMP_FLAG; |
447 | knew->private_value = val; | 462 | knew->private_value = val; |
448 | return 0; | 463 | return 0; |
449 | } | 464 | } |
450 | 465 | ||
466 | static struct snd_kcontrol_new *via_clone_control(struct via_spec *spec, | ||
467 | struct snd_kcontrol_new *tmpl) | ||
468 | { | ||
469 | struct snd_kcontrol_new *knew; | ||
470 | |||
471 | snd_array_init(&spec->kctls, sizeof(*knew), 32); | ||
472 | knew = snd_array_new(&spec->kctls); | ||
473 | if (!knew) | ||
474 | return NULL; | ||
475 | *knew = *tmpl; | ||
476 | knew->name = kstrdup(tmpl->name, GFP_KERNEL); | ||
477 | if (!knew->name) | ||
478 | return NULL; | ||
479 | return 0; | ||
480 | } | ||
481 | |||
451 | static void via_free_kctls(struct hda_codec *codec) | 482 | static void via_free_kctls(struct hda_codec *codec) |
452 | { | 483 | { |
453 | struct via_spec *spec = codec->spec; | 484 | struct via_spec *spec = codec->spec; |
@@ -1088,24 +1119,9 @@ static int via_independent_hp_get(struct snd_kcontrol *kcontrol, | |||
1088 | struct snd_ctl_elem_value *ucontrol) | 1119 | struct snd_ctl_elem_value *ucontrol) |
1089 | { | 1120 | { |
1090 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 1121 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
1091 | struct via_spec *spec = codec->spec; | 1122 | hda_nid_t nid = kcontrol->private_value; |
1092 | hda_nid_t nid; | ||
1093 | unsigned int pinsel; | 1123 | unsigned int pinsel; |
1094 | 1124 | ||
1095 | switch (spec->codec_type) { | ||
1096 | case VT1718S: | ||
1097 | nid = 0x34; | ||
1098 | break; | ||
1099 | case VT2002P: | ||
1100 | nid = 0x35; | ||
1101 | break; | ||
1102 | case VT1812: | ||
1103 | nid = 0x3d; | ||
1104 | break; | ||
1105 | default: | ||
1106 | nid = spec->autocfg.hp_pins[0]; | ||
1107 | break; | ||
1108 | } | ||
1109 | /* use !! to translate conn sel 2 for VT1718S */ | 1125 | /* use !! to translate conn sel 2 for VT1718S */ |
1110 | pinsel = !!snd_hda_codec_read(codec, nid, 0, | 1126 | pinsel = !!snd_hda_codec_read(codec, nid, 0, |
1111 | AC_VERB_GET_CONNECT_SEL, | 1127 | AC_VERB_GET_CONNECT_SEL, |
@@ -1127,29 +1143,24 @@ static void activate_ctl(struct hda_codec *codec, const char *name, int active) | |||
1127 | } | 1143 | } |
1128 | } | 1144 | } |
1129 | 1145 | ||
1146 | static hda_nid_t side_mute_channel(struct via_spec *spec) | ||
1147 | { | ||
1148 | switch (spec->codec_type) { | ||
1149 | case VT1708: return 0x1b; | ||
1150 | case VT1709_10CH: return 0x29; | ||
1151 | case VT1708B_8CH: /* fall thru */ | ||
1152 | case VT1708S: return 0x27; | ||
1153 | default: return 0; | ||
1154 | } | ||
1155 | } | ||
1156 | |||
1130 | static int update_side_mute_status(struct hda_codec *codec) | 1157 | static int update_side_mute_status(struct hda_codec *codec) |
1131 | { | 1158 | { |
1132 | /* mute side channel */ | 1159 | /* mute side channel */ |
1133 | struct via_spec *spec = codec->spec; | 1160 | struct via_spec *spec = codec->spec; |
1134 | unsigned int parm = spec->hp_independent_mode | 1161 | unsigned int parm = spec->hp_independent_mode |
1135 | ? AMP_OUT_MUTE : AMP_OUT_UNMUTE; | 1162 | ? AMP_OUT_MUTE : AMP_OUT_UNMUTE; |
1136 | hda_nid_t sw3; | 1163 | hda_nid_t sw3 = side_mute_channel(spec); |
1137 | |||
1138 | switch (spec->codec_type) { | ||
1139 | case VT1708: | ||
1140 | sw3 = 0x1b; | ||
1141 | break; | ||
1142 | case VT1709_10CH: | ||
1143 | sw3 = 0x29; | ||
1144 | break; | ||
1145 | case VT1708B_8CH: | ||
1146 | case VT1708S: | ||
1147 | sw3 = 0x27; | ||
1148 | break; | ||
1149 | default: | ||
1150 | sw3 = 0; | ||
1151 | break; | ||
1152 | } | ||
1153 | 1164 | ||
1154 | if (sw3) | 1165 | if (sw3) |
1155 | snd_hda_codec_write(codec, sw3, 0, AC_VERB_SET_AMP_GAIN_MUTE, | 1166 | snd_hda_codec_write(codec, sw3, 0, AC_VERB_SET_AMP_GAIN_MUTE, |
@@ -1162,28 +1173,11 @@ static int via_independent_hp_put(struct snd_kcontrol *kcontrol, | |||
1162 | { | 1173 | { |
1163 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 1174 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
1164 | struct via_spec *spec = codec->spec; | 1175 | struct via_spec *spec = codec->spec; |
1165 | hda_nid_t nid = spec->autocfg.hp_pins[0]; | 1176 | hda_nid_t nid = kcontrol->private_value; |
1166 | unsigned int pinsel = ucontrol->value.enumerated.item[0]; | 1177 | unsigned int pinsel = ucontrol->value.enumerated.item[0]; |
1167 | /* Get Independent Mode index of headphone pin widget */ | 1178 | /* Get Independent Mode index of headphone pin widget */ |
1168 | spec->hp_independent_mode = spec->hp_independent_mode_index == pinsel | 1179 | spec->hp_independent_mode = spec->hp_independent_mode_index == pinsel |
1169 | ? 1 : 0; | 1180 | ? 1 : 0; |
1170 | |||
1171 | switch (spec->codec_type) { | ||
1172 | case VT1718S: | ||
1173 | nid = 0x34; | ||
1174 | pinsel = pinsel ? 2 : 0; /* indep HP use AOW4 (index 2) */ | ||
1175 | spec->multiout.num_dacs = 4; | ||
1176 | break; | ||
1177 | case VT2002P: | ||
1178 | nid = 0x35; | ||
1179 | break; | ||
1180 | case VT1812: | ||
1181 | nid = 0x3d; | ||
1182 | break; | ||
1183 | default: | ||
1184 | nid = spec->autocfg.hp_pins[0]; | ||
1185 | break; | ||
1186 | } | ||
1187 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, pinsel); | 1181 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, pinsel); |
1188 | 1182 | ||
1189 | if (spec->multiout.hp_nid && spec->multiout.hp_nid | 1183 | if (spec->multiout.hp_nid && spec->multiout.hp_nid |
@@ -1207,18 +1201,55 @@ static int via_independent_hp_put(struct snd_kcontrol *kcontrol, | |||
1207 | return 0; | 1201 | return 0; |
1208 | } | 1202 | } |
1209 | 1203 | ||
1210 | static struct snd_kcontrol_new via_hp_mixer[] = { | 1204 | static struct snd_kcontrol_new via_hp_mixer[2] = { |
1211 | { | 1205 | { |
1212 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1206 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1213 | .name = "Independent HP", | 1207 | .name = "Independent HP", |
1214 | .count = 1, | ||
1215 | .info = via_independent_hp_info, | 1208 | .info = via_independent_hp_info, |
1216 | .get = via_independent_hp_get, | 1209 | .get = via_independent_hp_get, |
1217 | .put = via_independent_hp_put, | 1210 | .put = via_independent_hp_put, |
1218 | }, | 1211 | }, |
1219 | { } /* end */ | 1212 | { |
1213 | .iface = NID_MAPPING, | ||
1214 | .name = "Independent HP", | ||
1215 | }, | ||
1220 | }; | 1216 | }; |
1221 | 1217 | ||
1218 | static int via_hp_build(struct via_spec *spec) | ||
1219 | { | ||
1220 | struct snd_kcontrol_new *knew; | ||
1221 | hda_nid_t nid; | ||
1222 | |||
1223 | knew = via_clone_control(spec, &via_hp_mixer[0]); | ||
1224 | if (knew == NULL) | ||
1225 | return -ENOMEM; | ||
1226 | |||
1227 | switch (spec->codec_type) { | ||
1228 | case VT1718S: | ||
1229 | nid = 0x34; | ||
1230 | break; | ||
1231 | case VT2002P: | ||
1232 | nid = 0x35; | ||
1233 | break; | ||
1234 | case VT1812: | ||
1235 | nid = 0x3d; | ||
1236 | break; | ||
1237 | default: | ||
1238 | nid = spec->autocfg.hp_pins[0]; | ||
1239 | break; | ||
1240 | } | ||
1241 | |||
1242 | knew->subdevice = HDA_SUBDEV_NID_FLAG | nid; | ||
1243 | knew->private_value = nid; | ||
1244 | |||
1245 | knew = via_clone_control(spec, &via_hp_mixer[1]); | ||
1246 | if (knew == NULL) | ||
1247 | return -ENOMEM; | ||
1248 | knew->subdevice = side_mute_channel(spec); | ||
1249 | |||
1250 | return 0; | ||
1251 | } | ||
1252 | |||
1222 | static void notify_aa_path_ctls(struct hda_codec *codec) | 1253 | static void notify_aa_path_ctls(struct hda_codec *codec) |
1223 | { | 1254 | { |
1224 | int i; | 1255 | int i; |
@@ -1376,7 +1407,7 @@ static int via_smart51_put(struct snd_kcontrol *kcontrol, | |||
1376 | return 1; | 1407 | return 1; |
1377 | } | 1408 | } |
1378 | 1409 | ||
1379 | static struct snd_kcontrol_new via_smart51_mixer[] = { | 1410 | static struct snd_kcontrol_new via_smart51_mixer[2] = { |
1380 | { | 1411 | { |
1381 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1412 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1382 | .name = "Smart 5.1", | 1413 | .name = "Smart 5.1", |
@@ -1385,9 +1416,36 @@ static struct snd_kcontrol_new via_smart51_mixer[] = { | |||
1385 | .get = via_smart51_get, | 1416 | .get = via_smart51_get, |
1386 | .put = via_smart51_put, | 1417 | .put = via_smart51_put, |
1387 | }, | 1418 | }, |
1388 | {} /* end */ | 1419 | { |
1420 | .iface = NID_MAPPING, | ||
1421 | .name = "Smart 5.1", | ||
1422 | } | ||
1389 | }; | 1423 | }; |
1390 | 1424 | ||
1425 | static int via_smart51_build(struct via_spec *spec) | ||
1426 | { | ||
1427 | struct snd_kcontrol_new *knew; | ||
1428 | int index[] = { AUTO_PIN_MIC, AUTO_PIN_FRONT_MIC, AUTO_PIN_LINE }; | ||
1429 | hda_nid_t nid; | ||
1430 | int i; | ||
1431 | |||
1432 | knew = via_clone_control(spec, &via_smart51_mixer[0]); | ||
1433 | if (knew == NULL) | ||
1434 | return -ENOMEM; | ||
1435 | |||
1436 | for (i = 0; i < ARRAY_SIZE(index); i++) { | ||
1437 | nid = spec->autocfg.input_pins[index[i]]; | ||
1438 | if (nid) { | ||
1439 | knew = via_clone_control(spec, &via_smart51_mixer[1]); | ||
1440 | if (knew == NULL) | ||
1441 | return -ENOMEM; | ||
1442 | knew->subdevice = nid; | ||
1443 | } | ||
1444 | } | ||
1445 | |||
1446 | return 0; | ||
1447 | } | ||
1448 | |||
1391 | /* capture mixer elements */ | 1449 | /* capture mixer elements */ |
1392 | static struct snd_kcontrol_new vt1708_capture_mixer[] = { | 1450 | static struct snd_kcontrol_new vt1708_capture_mixer[] = { |
1393 | HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_INPUT), | 1451 | HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_INPUT), |
@@ -1819,8 +1877,9 @@ static struct hda_pcm_stream vt1708_pcm_digital_capture = { | |||
1819 | static int via_build_controls(struct hda_codec *codec) | 1877 | static int via_build_controls(struct hda_codec *codec) |
1820 | { | 1878 | { |
1821 | struct via_spec *spec = codec->spec; | 1879 | struct via_spec *spec = codec->spec; |
1822 | int err; | 1880 | struct snd_kcontrol *kctl; |
1823 | int i; | 1881 | struct snd_kcontrol_new *knew; |
1882 | int err, i; | ||
1824 | 1883 | ||
1825 | for (i = 0; i < spec->num_mixers; i++) { | 1884 | for (i = 0; i < spec->num_mixers; i++) { |
1826 | err = snd_hda_add_new_ctls(codec, spec->mixers[i]); | 1885 | err = snd_hda_add_new_ctls(codec, spec->mixers[i]); |
@@ -1845,6 +1904,27 @@ static int via_build_controls(struct hda_codec *codec) | |||
1845 | return err; | 1904 | return err; |
1846 | } | 1905 | } |
1847 | 1906 | ||
1907 | /* assign Capture Source enums to NID */ | ||
1908 | kctl = snd_hda_find_mixer_ctl(codec, "Input Source"); | ||
1909 | for (i = 0; kctl && i < kctl->count; i++) { | ||
1910 | err = snd_hda_add_nid(codec, kctl, i, spec->mux_nids[i]); | ||
1911 | if (err < 0) | ||
1912 | return err; | ||
1913 | } | ||
1914 | |||
1915 | /* other nid->control mapping */ | ||
1916 | for (i = 0; i < spec->num_mixers; i++) { | ||
1917 | for (knew = spec->mixers[i]; knew->name; knew++) { | ||
1918 | if (knew->iface != NID_MAPPING) | ||
1919 | continue; | ||
1920 | kctl = snd_hda_find_mixer_ctl(codec, knew->name); | ||
1921 | if (kctl == NULL) | ||
1922 | continue; | ||
1923 | err = snd_hda_add_nid(codec, kctl, 0, | ||
1924 | knew->subdevice); | ||
1925 | } | ||
1926 | } | ||
1927 | |||
1848 | /* init power states */ | 1928 | /* init power states */ |
1849 | set_jack_power_state(codec); | 1929 | set_jack_power_state(codec); |
1850 | analog_low_current_mode(codec, 1); | 1930 | analog_low_current_mode(codec, 1); |
@@ -2481,9 +2561,9 @@ static int vt1708_parse_auto_config(struct hda_codec *codec) | |||
2481 | spec->input_mux = &spec->private_imux[0]; | 2561 | spec->input_mux = &spec->private_imux[0]; |
2482 | 2562 | ||
2483 | if (spec->hp_mux) | 2563 | if (spec->hp_mux) |
2484 | spec->mixers[spec->num_mixers++] = via_hp_mixer; | 2564 | via_hp_build(spec); |
2485 | 2565 | ||
2486 | spec->mixers[spec->num_mixers++] = via_smart51_mixer; | 2566 | via_smart51_build(spec); |
2487 | return 1; | 2567 | return 1; |
2488 | } | 2568 | } |
2489 | 2569 | ||
@@ -2554,12 +2634,10 @@ static int patch_vt1708(struct hda_codec *codec) | |||
2554 | int err; | 2634 | int err; |
2555 | 2635 | ||
2556 | /* create a codec specific record */ | 2636 | /* create a codec specific record */ |
2557 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 2637 | spec = via_new_spec(codec); |
2558 | if (spec == NULL) | 2638 | if (spec == NULL) |
2559 | return -ENOMEM; | 2639 | return -ENOMEM; |
2560 | 2640 | ||
2561 | codec->spec = spec; | ||
2562 | |||
2563 | /* automatic parse from the BIOS config */ | 2641 | /* automatic parse from the BIOS config */ |
2564 | err = vt1708_parse_auto_config(codec); | 2642 | err = vt1708_parse_auto_config(codec); |
2565 | if (err < 0) { | 2643 | if (err < 0) { |
@@ -2597,7 +2675,6 @@ static int patch_vt1708(struct hda_codec *codec) | |||
2597 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 2675 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
2598 | spec->loopback.amplist = vt1708_loopbacks; | 2676 | spec->loopback.amplist = vt1708_loopbacks; |
2599 | #endif | 2677 | #endif |
2600 | spec->codec = codec; | ||
2601 | INIT_DELAYED_WORK(&spec->vt1708_hp_work, vt1708_update_hp_jack_state); | 2678 | INIT_DELAYED_WORK(&spec->vt1708_hp_work, vt1708_update_hp_jack_state); |
2602 | return 0; | 2679 | return 0; |
2603 | } | 2680 | } |
@@ -3010,9 +3087,9 @@ static int vt1709_parse_auto_config(struct hda_codec *codec) | |||
3010 | spec->input_mux = &spec->private_imux[0]; | 3087 | spec->input_mux = &spec->private_imux[0]; |
3011 | 3088 | ||
3012 | if (spec->hp_mux) | 3089 | if (spec->hp_mux) |
3013 | spec->mixers[spec->num_mixers++] = via_hp_mixer; | 3090 | via_hp_build(spec); |
3014 | 3091 | ||
3015 | spec->mixers[spec->num_mixers++] = via_smart51_mixer; | 3092 | via_smart51_build(spec); |
3016 | return 1; | 3093 | return 1; |
3017 | } | 3094 | } |
3018 | 3095 | ||
@@ -3032,12 +3109,10 @@ static int patch_vt1709_10ch(struct hda_codec *codec) | |||
3032 | int err; | 3109 | int err; |
3033 | 3110 | ||
3034 | /* create a codec specific record */ | 3111 | /* create a codec specific record */ |
3035 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 3112 | spec = via_new_spec(codec); |
3036 | if (spec == NULL) | 3113 | if (spec == NULL) |
3037 | return -ENOMEM; | 3114 | return -ENOMEM; |
3038 | 3115 | ||
3039 | codec->spec = spec; | ||
3040 | |||
3041 | err = vt1709_parse_auto_config(codec); | 3116 | err = vt1709_parse_auto_config(codec); |
3042 | if (err < 0) { | 3117 | if (err < 0) { |
3043 | via_free(codec); | 3118 | via_free(codec); |
@@ -3126,12 +3201,10 @@ static int patch_vt1709_6ch(struct hda_codec *codec) | |||
3126 | int err; | 3201 | int err; |
3127 | 3202 | ||
3128 | /* create a codec specific record */ | 3203 | /* create a codec specific record */ |
3129 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 3204 | spec = via_new_spec(codec); |
3130 | if (spec == NULL) | 3205 | if (spec == NULL) |
3131 | return -ENOMEM; | 3206 | return -ENOMEM; |
3132 | 3207 | ||
3133 | codec->spec = spec; | ||
3134 | |||
3135 | err = vt1709_parse_auto_config(codec); | 3208 | err = vt1709_parse_auto_config(codec); |
3136 | if (err < 0) { | 3209 | if (err < 0) { |
3137 | via_free(codec); | 3210 | via_free(codec); |
@@ -3581,9 +3654,9 @@ static int vt1708B_parse_auto_config(struct hda_codec *codec) | |||
3581 | spec->input_mux = &spec->private_imux[0]; | 3654 | spec->input_mux = &spec->private_imux[0]; |
3582 | 3655 | ||
3583 | if (spec->hp_mux) | 3656 | if (spec->hp_mux) |
3584 | spec->mixers[spec->num_mixers++] = via_hp_mixer; | 3657 | via_hp_build(spec); |
3585 | 3658 | ||
3586 | spec->mixers[spec->num_mixers++] = via_smart51_mixer; | 3659 | via_smart51_build(spec); |
3587 | return 1; | 3660 | return 1; |
3588 | } | 3661 | } |
3589 | 3662 | ||
@@ -3605,12 +3678,10 @@ static int patch_vt1708B_8ch(struct hda_codec *codec) | |||
3605 | if (get_codec_type(codec) == VT1708BCE) | 3678 | if (get_codec_type(codec) == VT1708BCE) |
3606 | return patch_vt1708S(codec); | 3679 | return patch_vt1708S(codec); |
3607 | /* create a codec specific record */ | 3680 | /* create a codec specific record */ |
3608 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 3681 | spec = via_new_spec(codec); |
3609 | if (spec == NULL) | 3682 | if (spec == NULL) |
3610 | return -ENOMEM; | 3683 | return -ENOMEM; |
3611 | 3684 | ||
3612 | codec->spec = spec; | ||
3613 | |||
3614 | /* automatic parse from the BIOS config */ | 3685 | /* automatic parse from the BIOS config */ |
3615 | err = vt1708B_parse_auto_config(codec); | 3686 | err = vt1708B_parse_auto_config(codec); |
3616 | if (err < 0) { | 3687 | if (err < 0) { |
@@ -3657,12 +3728,10 @@ static int patch_vt1708B_4ch(struct hda_codec *codec) | |||
3657 | int err; | 3728 | int err; |
3658 | 3729 | ||
3659 | /* create a codec specific record */ | 3730 | /* create a codec specific record */ |
3660 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 3731 | spec = via_new_spec(codec); |
3661 | if (spec == NULL) | 3732 | if (spec == NULL) |
3662 | return -ENOMEM; | 3733 | return -ENOMEM; |
3663 | 3734 | ||
3664 | codec->spec = spec; | ||
3665 | |||
3666 | /* automatic parse from the BIOS config */ | 3735 | /* automatic parse from the BIOS config */ |
3667 | err = vt1708B_parse_auto_config(codec); | 3736 | err = vt1708B_parse_auto_config(codec); |
3668 | if (err < 0) { | 3737 | if (err < 0) { |
@@ -4071,9 +4140,9 @@ static int vt1708S_parse_auto_config(struct hda_codec *codec) | |||
4071 | spec->input_mux = &spec->private_imux[0]; | 4140 | spec->input_mux = &spec->private_imux[0]; |
4072 | 4141 | ||
4073 | if (spec->hp_mux) | 4142 | if (spec->hp_mux) |
4074 | spec->mixers[spec->num_mixers++] = via_hp_mixer; | 4143 | via_hp_build(spec); |
4075 | 4144 | ||
4076 | spec->mixers[spec->num_mixers++] = via_smart51_mixer; | 4145 | via_smart51_build(spec); |
4077 | return 1; | 4146 | return 1; |
4078 | } | 4147 | } |
4079 | 4148 | ||
@@ -4103,12 +4172,10 @@ static int patch_vt1708S(struct hda_codec *codec) | |||
4103 | int err; | 4172 | int err; |
4104 | 4173 | ||
4105 | /* create a codec specific record */ | 4174 | /* create a codec specific record */ |
4106 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 4175 | spec = via_new_spec(codec); |
4107 | if (spec == NULL) | 4176 | if (spec == NULL) |
4108 | return -ENOMEM; | 4177 | return -ENOMEM; |
4109 | 4178 | ||
4110 | codec->spec = spec; | ||
4111 | |||
4112 | /* automatic parse from the BIOS config */ | 4179 | /* automatic parse from the BIOS config */ |
4113 | err = vt1708S_parse_auto_config(codec); | 4180 | err = vt1708S_parse_auto_config(codec); |
4114 | if (err < 0) { | 4181 | if (err < 0) { |
@@ -4443,7 +4510,7 @@ static int vt1702_parse_auto_config(struct hda_codec *codec) | |||
4443 | spec->input_mux = &spec->private_imux[0]; | 4510 | spec->input_mux = &spec->private_imux[0]; |
4444 | 4511 | ||
4445 | if (spec->hp_mux) | 4512 | if (spec->hp_mux) |
4446 | spec->mixers[spec->num_mixers++] = via_hp_mixer; | 4513 | via_hp_build(spec); |
4447 | 4514 | ||
4448 | return 1; | 4515 | return 1; |
4449 | } | 4516 | } |
@@ -4464,12 +4531,10 @@ static int patch_vt1702(struct hda_codec *codec) | |||
4464 | int err; | 4531 | int err; |
4465 | 4532 | ||
4466 | /* create a codec specific record */ | 4533 | /* create a codec specific record */ |
4467 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 4534 | spec = via_new_spec(codec); |
4468 | if (spec == NULL) | 4535 | if (spec == NULL) |
4469 | return -ENOMEM; | 4536 | return -ENOMEM; |
4470 | 4537 | ||
4471 | codec->spec = spec; | ||
4472 | |||
4473 | /* automatic parse from the BIOS config */ | 4538 | /* automatic parse from the BIOS config */ |
4474 | err = vt1702_parse_auto_config(codec); | 4539 | err = vt1702_parse_auto_config(codec); |
4475 | if (err < 0) { | 4540 | if (err < 0) { |
@@ -4865,9 +4930,9 @@ static int vt1718S_parse_auto_config(struct hda_codec *codec) | |||
4865 | spec->input_mux = &spec->private_imux[0]; | 4930 | spec->input_mux = &spec->private_imux[0]; |
4866 | 4931 | ||
4867 | if (spec->hp_mux) | 4932 | if (spec->hp_mux) |
4868 | spec->mixers[spec->num_mixers++] = via_hp_mixer; | 4933 | via_hp_build(spec); |
4869 | 4934 | ||
4870 | spec->mixers[spec->num_mixers++] = via_smart51_mixer; | 4935 | via_smart51_build(spec); |
4871 | 4936 | ||
4872 | return 1; | 4937 | return 1; |
4873 | } | 4938 | } |
@@ -4888,12 +4953,10 @@ static int patch_vt1718S(struct hda_codec *codec) | |||
4888 | int err; | 4953 | int err; |
4889 | 4954 | ||
4890 | /* create a codec specific record */ | 4955 | /* create a codec specific record */ |
4891 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 4956 | spec = via_new_spec(codec); |
4892 | if (spec == NULL) | 4957 | if (spec == NULL) |
4893 | return -ENOMEM; | 4958 | return -ENOMEM; |
4894 | 4959 | ||
4895 | codec->spec = spec; | ||
4896 | |||
4897 | /* automatic parse from the BIOS config */ | 4960 | /* automatic parse from the BIOS config */ |
4898 | err = vt1718S_parse_auto_config(codec); | 4961 | err = vt1718S_parse_auto_config(codec); |
4899 | if (err < 0) { | 4962 | if (err < 0) { |
@@ -5014,6 +5077,7 @@ static struct snd_kcontrol_new vt1716s_dmic_mixer[] = { | |||
5014 | { | 5077 | { |
5015 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 5078 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
5016 | .name = "Digital Mic Capture Switch", | 5079 | .name = "Digital Mic Capture Switch", |
5080 | .subdevice = HDA_SUBDEV_NID_FLAG | 0x26, | ||
5017 | .count = 1, | 5081 | .count = 1, |
5018 | .info = vt1716s_dmic_info, | 5082 | .info = vt1716s_dmic_info, |
5019 | .get = vt1716s_dmic_get, | 5083 | .get = vt1716s_dmic_get, |
@@ -5361,9 +5425,9 @@ static int vt1716S_parse_auto_config(struct hda_codec *codec) | |||
5361 | spec->input_mux = &spec->private_imux[0]; | 5425 | spec->input_mux = &spec->private_imux[0]; |
5362 | 5426 | ||
5363 | if (spec->hp_mux) | 5427 | if (spec->hp_mux) |
5364 | spec->mixers[spec->num_mixers++] = via_hp_mixer; | 5428 | via_hp_build(spec); |
5365 | 5429 | ||
5366 | spec->mixers[spec->num_mixers++] = via_smart51_mixer; | 5430 | via_smart51_build(spec); |
5367 | 5431 | ||
5368 | return 1; | 5432 | return 1; |
5369 | } | 5433 | } |
@@ -5384,12 +5448,10 @@ static int patch_vt1716S(struct hda_codec *codec) | |||
5384 | int err; | 5448 | int err; |
5385 | 5449 | ||
5386 | /* create a codec specific record */ | 5450 | /* create a codec specific record */ |
5387 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 5451 | spec = via_new_spec(codec); |
5388 | if (spec == NULL) | 5452 | if (spec == NULL) |
5389 | return -ENOMEM; | 5453 | return -ENOMEM; |
5390 | 5454 | ||
5391 | codec->spec = spec; | ||
5392 | |||
5393 | /* automatic parse from the BIOS config */ | 5455 | /* automatic parse from the BIOS config */ |
5394 | err = vt1716S_parse_auto_config(codec); | 5456 | err = vt1716S_parse_auto_config(codec); |
5395 | if (err < 0) { | 5457 | if (err < 0) { |
@@ -5719,7 +5781,7 @@ static int vt2002P_parse_auto_config(struct hda_codec *codec) | |||
5719 | spec->input_mux = &spec->private_imux[0]; | 5781 | spec->input_mux = &spec->private_imux[0]; |
5720 | 5782 | ||
5721 | if (spec->hp_mux) | 5783 | if (spec->hp_mux) |
5722 | spec->mixers[spec->num_mixers++] = via_hp_mixer; | 5784 | via_hp_build(spec); |
5723 | 5785 | ||
5724 | return 1; | 5786 | return 1; |
5725 | } | 5787 | } |
@@ -5741,12 +5803,10 @@ static int patch_vt2002P(struct hda_codec *codec) | |||
5741 | int err; | 5803 | int err; |
5742 | 5804 | ||
5743 | /* create a codec specific record */ | 5805 | /* create a codec specific record */ |
5744 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 5806 | spec = via_new_spec(codec); |
5745 | if (spec == NULL) | 5807 | if (spec == NULL) |
5746 | return -ENOMEM; | 5808 | return -ENOMEM; |
5747 | 5809 | ||
5748 | codec->spec = spec; | ||
5749 | |||
5750 | /* automatic parse from the BIOS config */ | 5810 | /* automatic parse from the BIOS config */ |
5751 | err = vt2002P_parse_auto_config(codec); | 5811 | err = vt2002P_parse_auto_config(codec); |
5752 | if (err < 0) { | 5812 | if (err < 0) { |
@@ -6070,7 +6130,7 @@ static int vt1812_parse_auto_config(struct hda_codec *codec) | |||
6070 | spec->input_mux = &spec->private_imux[0]; | 6130 | spec->input_mux = &spec->private_imux[0]; |
6071 | 6131 | ||
6072 | if (spec->hp_mux) | 6132 | if (spec->hp_mux) |
6073 | spec->mixers[spec->num_mixers++] = via_hp_mixer; | 6133 | via_hp_build(spec); |
6074 | 6134 | ||
6075 | return 1; | 6135 | return 1; |
6076 | } | 6136 | } |
@@ -6092,12 +6152,10 @@ static int patch_vt1812(struct hda_codec *codec) | |||
6092 | int err; | 6152 | int err; |
6093 | 6153 | ||
6094 | /* create a codec specific record */ | 6154 | /* create a codec specific record */ |
6095 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 6155 | spec = via_new_spec(codec); |
6096 | if (spec == NULL) | 6156 | if (spec == NULL) |
6097 | return -ENOMEM; | 6157 | return -ENOMEM; |
6098 | 6158 | ||
6099 | codec->spec = spec; | ||
6100 | |||
6101 | /* automatic parse from the BIOS config */ | 6159 | /* automatic parse from the BIOS config */ |
6102 | err = vt1812_parse_auto_config(codec); | 6160 | err = vt1812_parse_auto_config(codec); |
6103 | if (err < 0) { | 6161 | if (err < 0) { |
diff --git a/sound/pci/ice1712/aureon.c b/sound/pci/ice1712/aureon.c index 765d7bd4c3d4..9e66f6d306f8 100644 --- a/sound/pci/ice1712/aureon.c +++ b/sound/pci/ice1712/aureon.c | |||
@@ -703,11 +703,13 @@ static void wm_set_vol(struct snd_ice1712 *ice, unsigned int index, unsigned sho | |||
703 | { | 703 | { |
704 | unsigned char nvol; | 704 | unsigned char nvol; |
705 | 705 | ||
706 | if ((master & WM_VOL_MUTE) || (vol & WM_VOL_MUTE)) | 706 | if ((master & WM_VOL_MUTE) || (vol & WM_VOL_MUTE)) { |
707 | nvol = 0; | 707 | nvol = 0; |
708 | else | 708 | } else { |
709 | nvol = ((vol % WM_VOL_CNT) * (master % WM_VOL_CNT)) / | 709 | nvol = ((vol % WM_VOL_CNT) * (master % WM_VOL_CNT)) / |
710 | WM_VOL_MAX; | 710 | WM_VOL_MAX; |
711 | nvol += 0x1b; | ||
712 | } | ||
711 | 713 | ||
712 | wm_put(ice, index, nvol); | 714 | wm_put(ice, index, nvol); |
713 | wm_put_nocache(ice, index, 0x180 | nvol); | 715 | wm_put_nocache(ice, index, 0x180 | nvol); |
@@ -778,7 +780,7 @@ static int wm_master_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_ | |||
778 | for (ch = 0; ch < 2; ch++) { | 780 | for (ch = 0; ch < 2; ch++) { |
779 | unsigned int vol = ucontrol->value.integer.value[ch]; | 781 | unsigned int vol = ucontrol->value.integer.value[ch]; |
780 | if (vol > WM_VOL_MAX) | 782 | if (vol > WM_VOL_MAX) |
781 | continue; | 783 | vol = WM_VOL_MAX; |
782 | vol |= spec->master[ch] & WM_VOL_MUTE; | 784 | vol |= spec->master[ch] & WM_VOL_MUTE; |
783 | if (vol != spec->master[ch]) { | 785 | if (vol != spec->master[ch]) { |
784 | int dac; | 786 | int dac; |
@@ -834,8 +836,8 @@ static int wm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value * | |||
834 | for (i = 0; i < voices; i++) { | 836 | for (i = 0; i < voices; i++) { |
835 | unsigned int vol = ucontrol->value.integer.value[i]; | 837 | unsigned int vol = ucontrol->value.integer.value[i]; |
836 | if (vol > WM_VOL_MAX) | 838 | if (vol > WM_VOL_MAX) |
837 | continue; | 839 | vol = WM_VOL_MAX; |
838 | vol |= spec->vol[ofs+i]; | 840 | vol |= spec->vol[ofs+i] & WM_VOL_MUTE; |
839 | if (vol != spec->vol[ofs+i]) { | 841 | if (vol != spec->vol[ofs+i]) { |
840 | spec->vol[ofs+i] = vol; | 842 | spec->vol[ofs+i] = vol; |
841 | idx = WM_DAC_ATTEN + ofs + i; | 843 | idx = WM_DAC_ATTEN + ofs + i; |
diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c index c7cff6f8168a..4fc6d8bc637e 100644 --- a/sound/pci/ice1712/ice1712.c +++ b/sound/pci/ice1712/ice1712.c | |||
@@ -106,7 +106,7 @@ module_param_array(dxr_enable, int, NULL, 0444); | |||
106 | MODULE_PARM_DESC(dxr_enable, "Enable DXR support for Terratec DMX6FIRE."); | 106 | MODULE_PARM_DESC(dxr_enable, "Enable DXR support for Terratec DMX6FIRE."); |
107 | 107 | ||
108 | 108 | ||
109 | static const struct pci_device_id snd_ice1712_ids[] = { | 109 | static DEFINE_PCI_DEVICE_TABLE(snd_ice1712_ids) = { |
110 | { PCI_VDEVICE(ICE, PCI_DEVICE_ID_ICE_1712), 0 }, /* ICE1712 */ | 110 | { PCI_VDEVICE(ICE, PCI_DEVICE_ID_ICE_1712), 0 }, /* ICE1712 */ |
111 | { 0, } | 111 | { 0, } |
112 | }; | 112 | }; |
@@ -1180,6 +1180,10 @@ static int snd_ice1712_playback_pro_open(struct snd_pcm_substream *substream) | |||
1180 | snd_pcm_set_sync(substream); | 1180 | snd_pcm_set_sync(substream); |
1181 | snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); | 1181 | snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); |
1182 | snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates); | 1182 | snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates); |
1183 | if (is_pro_rate_locked(ice)) { | ||
1184 | runtime->hw.rate_min = PRO_RATE_DEFAULT; | ||
1185 | runtime->hw.rate_max = PRO_RATE_DEFAULT; | ||
1186 | } | ||
1183 | 1187 | ||
1184 | if (ice->spdif.ops.open) | 1188 | if (ice->spdif.ops.open) |
1185 | ice->spdif.ops.open(ice, substream); | 1189 | ice->spdif.ops.open(ice, substream); |
@@ -1197,6 +1201,11 @@ static int snd_ice1712_capture_pro_open(struct snd_pcm_substream *substream) | |||
1197 | snd_pcm_set_sync(substream); | 1201 | snd_pcm_set_sync(substream); |
1198 | snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); | 1202 | snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); |
1199 | snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates); | 1203 | snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates); |
1204 | if (is_pro_rate_locked(ice)) { | ||
1205 | runtime->hw.rate_min = PRO_RATE_DEFAULT; | ||
1206 | runtime->hw.rate_max = PRO_RATE_DEFAULT; | ||
1207 | } | ||
1208 | |||
1200 | return 0; | 1209 | return 0; |
1201 | } | 1210 | } |
1202 | 1211 | ||
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index ae29073eea93..c1498fa5545f 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c | |||
@@ -94,7 +94,7 @@ MODULE_PARM_DESC(model, "Use the given board model."); | |||
94 | 94 | ||
95 | 95 | ||
96 | /* Both VT1720 and VT1724 have the same PCI IDs */ | 96 | /* Both VT1720 and VT1724 have the same PCI IDs */ |
97 | static const struct pci_device_id snd_vt1724_ids[] = { | 97 | static DEFINE_PCI_DEVICE_TABLE(snd_vt1724_ids) = { |
98 | { PCI_VDEVICE(ICE, PCI_DEVICE_ID_VT1724), 0 }, | 98 | { PCI_VDEVICE(ICE, PCI_DEVICE_ID_VT1724), 0 }, |
99 | { 0, } | 99 | { 0, } |
100 | }; | 100 | }; |
diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index b990143636f1..6433e65c9507 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c | |||
@@ -420,7 +420,7 @@ struct intel8x0 { | |||
420 | u32 int_sta_mask; /* interrupt status mask */ | 420 | u32 int_sta_mask; /* interrupt status mask */ |
421 | }; | 421 | }; |
422 | 422 | ||
423 | static struct pci_device_id snd_intel8x0_ids[] = { | 423 | static DEFINE_PCI_DEVICE_TABLE(snd_intel8x0_ids) = { |
424 | { PCI_VDEVICE(INTEL, 0x2415), DEVICE_INTEL }, /* 82801AA */ | 424 | { PCI_VDEVICE(INTEL, 0x2415), DEVICE_INTEL }, /* 82801AA */ |
425 | { PCI_VDEVICE(INTEL, 0x2425), DEVICE_INTEL }, /* 82901AB */ | 425 | { PCI_VDEVICE(INTEL, 0x2425), DEVICE_INTEL }, /* 82901AB */ |
426 | { PCI_VDEVICE(INTEL, 0x2445), DEVICE_INTEL }, /* 82801BA */ | 426 | { PCI_VDEVICE(INTEL, 0x2445), DEVICE_INTEL }, /* 82801BA */ |
diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c index 9e7d12e7673f..13cec1e5ced9 100644 --- a/sound/pci/intel8x0m.c +++ b/sound/pci/intel8x0m.c | |||
@@ -219,7 +219,7 @@ struct intel8x0m { | |||
219 | unsigned int pcm_pos_shift; | 219 | unsigned int pcm_pos_shift; |
220 | }; | 220 | }; |
221 | 221 | ||
222 | static struct pci_device_id snd_intel8x0m_ids[] = { | 222 | static DEFINE_PCI_DEVICE_TABLE(snd_intel8x0m_ids) = { |
223 | { PCI_VDEVICE(INTEL, 0x2416), DEVICE_INTEL }, /* 82801AA */ | 223 | { PCI_VDEVICE(INTEL, 0x2416), DEVICE_INTEL }, /* 82801AA */ |
224 | { PCI_VDEVICE(INTEL, 0x2426), DEVICE_INTEL }, /* 82901AB */ | 224 | { PCI_VDEVICE(INTEL, 0x2426), DEVICE_INTEL }, /* 82901AB */ |
225 | { PCI_VDEVICE(INTEL, 0x2446), DEVICE_INTEL }, /* 82801BA */ | 225 | { PCI_VDEVICE(INTEL, 0x2446), DEVICE_INTEL }, /* 82801BA */ |
diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c index 7cc38a11e997..6d795700be79 100644 --- a/sound/pci/korg1212/korg1212.c +++ b/sound/pci/korg1212/korg1212.c | |||
@@ -418,7 +418,7 @@ module_param_array(enable, bool, NULL, 0444); | |||
418 | MODULE_PARM_DESC(enable, "Enable Korg 1212 soundcard."); | 418 | MODULE_PARM_DESC(enable, "Enable Korg 1212 soundcard."); |
419 | MODULE_AUTHOR("Haroldo Gamal <gamal@alternex.com.br>"); | 419 | MODULE_AUTHOR("Haroldo Gamal <gamal@alternex.com.br>"); |
420 | 420 | ||
421 | static struct pci_device_id snd_korg1212_ids[] = { | 421 | static DEFINE_PCI_DEVICE_TABLE(snd_korg1212_ids) = { |
422 | { | 422 | { |
423 | .vendor = 0x10b5, | 423 | .vendor = 0x10b5, |
424 | .device = 0x906d, | 424 | .device = 0x906d, |
diff --git a/sound/pci/lx6464es/lx6464es.c b/sound/pci/lx6464es/lx6464es.c index 11b8c6514b3d..0cca56038cd9 100644 --- a/sound/pci/lx6464es/lx6464es.c +++ b/sound/pci/lx6464es/lx6464es.c | |||
@@ -55,7 +55,7 @@ static const char card_name[] = "LX6464ES"; | |||
55 | 55 | ||
56 | #define PCI_DEVICE_ID_PLX_LX6464ES PCI_DEVICE_ID_PLX_9056 | 56 | #define PCI_DEVICE_ID_PLX_LX6464ES PCI_DEVICE_ID_PLX_9056 |
57 | 57 | ||
58 | static struct pci_device_id snd_lx6464es_ids[] = { | 58 | static DEFINE_PCI_DEVICE_TABLE(snd_lx6464es_ids) = { |
59 | { PCI_DEVICE(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_LX6464ES), | 59 | { PCI_DEVICE(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_LX6464ES), |
60 | .subvendor = PCI_VENDOR_ID_DIGIGRAM, | 60 | .subvendor = PCI_VENDOR_ID_DIGIGRAM, |
61 | .subdevice = PCI_SUBDEVICE_ID_DIGIGRAM_LX6464ES_SERIAL_SUBSYSTEM | 61 | .subdevice = PCI_SUBDEVICE_ID_DIGIGRAM_LX6464ES_SERIAL_SUBSYSTEM |
diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index 75283fbb4b3f..b64e78139d63 100644 --- a/sound/pci/maestro3.c +++ b/sound/pci/maestro3.c | |||
@@ -861,7 +861,7 @@ struct snd_m3 { | |||
861 | /* | 861 | /* |
862 | * pci ids | 862 | * pci ids |
863 | */ | 863 | */ |
864 | static struct pci_device_id snd_m3_ids[] = { | 864 | static DEFINE_PCI_DEVICE_TABLE(snd_m3_ids) = { |
865 | {PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_ALLEGRO_1, PCI_ANY_ID, PCI_ANY_ID, | 865 | {PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_ALLEGRO_1, PCI_ANY_ID, PCI_ANY_ID, |
866 | PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0}, | 866 | PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0}, |
867 | {PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_ALLEGRO, PCI_ANY_ID, PCI_ANY_ID, | 867 | {PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_ALLEGRO, PCI_ANY_ID, PCI_ANY_ID, |
diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c index a83d1968a845..7e8e7da592a9 100644 --- a/sound/pci/mixart/mixart.c +++ b/sound/pci/mixart/mixart.c | |||
@@ -60,7 +60,7 @@ MODULE_PARM_DESC(enable, "Enable Digigram " CARD_NAME " soundcard."); | |||
60 | /* | 60 | /* |
61 | */ | 61 | */ |
62 | 62 | ||
63 | static struct pci_device_id snd_mixart_ids[] = { | 63 | static DEFINE_PCI_DEVICE_TABLE(snd_mixart_ids) = { |
64 | { PCI_VDEVICE(MOTOROLA, 0x0003), 0, }, /* MC8240 */ | 64 | { PCI_VDEVICE(MOTOROLA, 0x0003), 0, }, /* MC8240 */ |
65 | { 0, } | 65 | { 0, } |
66 | }; | 66 | }; |
diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c index 97a0731331a1..5a60492ac7b3 100644 --- a/sound/pci/nm256/nm256.c +++ b/sound/pci/nm256/nm256.c | |||
@@ -262,7 +262,7 @@ struct nm256 { | |||
262 | /* | 262 | /* |
263 | * PCI ids | 263 | * PCI ids |
264 | */ | 264 | */ |
265 | static struct pci_device_id snd_nm256_ids[] = { | 265 | static DEFINE_PCI_DEVICE_TABLE(snd_nm256_ids) = { |
266 | {PCI_VDEVICE(NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO), 0}, | 266 | {PCI_VDEVICE(NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO), 0}, |
267 | {PCI_VDEVICE(NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO), 0}, | 267 | {PCI_VDEVICE(NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO), 0}, |
268 | {PCI_VDEVICE(NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256XL_PLUS_AUDIO), 0}, | 268 | {PCI_VDEVICE(NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256XL_PLUS_AUDIO), 0}, |
diff --git a/sound/pci/oxygen/Makefile b/sound/pci/oxygen/Makefile index 389941cf6100..acd8f15f7bff 100644 --- a/sound/pci/oxygen/Makefile +++ b/sound/pci/oxygen/Makefile | |||
@@ -2,7 +2,7 @@ snd-oxygen-lib-objs := oxygen_io.o oxygen_lib.o oxygen_mixer.o oxygen_pcm.o | |||
2 | snd-hifier-objs := hifier.o | 2 | snd-hifier-objs := hifier.o |
3 | snd-oxygen-objs := oxygen.o | 3 | snd-oxygen-objs := oxygen.o |
4 | snd-virtuoso-objs := virtuoso.o xonar_lib.o \ | 4 | snd-virtuoso-objs := virtuoso.o xonar_lib.o \ |
5 | xonar_pcm179x.o xonar_cs43xx.o xonar_hdmi.o | 5 | xonar_pcm179x.o xonar_cs43xx.o xonar_wm87x6.o xonar_hdmi.o |
6 | 6 | ||
7 | obj-$(CONFIG_SND_OXYGEN_LIB) += snd-oxygen-lib.o | 7 | obj-$(CONFIG_SND_OXYGEN_LIB) += snd-oxygen-lib.o |
8 | obj-$(CONFIG_SND_HIFIER) += snd-hifier.o | 8 | obj-$(CONFIG_SND_HIFIER) += snd-hifier.o |
diff --git a/sound/pci/oxygen/hifier.c b/sound/pci/oxygen/hifier.c index e3c229b63311..5a87d683691f 100644 --- a/sound/pci/oxygen/hifier.c +++ b/sound/pci/oxygen/hifier.c | |||
@@ -48,7 +48,7 @@ MODULE_PARM_DESC(id, "ID string"); | |||
48 | module_param_array(enable, bool, NULL, 0444); | 48 | module_param_array(enable, bool, NULL, 0444); |
49 | MODULE_PARM_DESC(enable, "enable card"); | 49 | MODULE_PARM_DESC(enable, "enable card"); |
50 | 50 | ||
51 | static struct pci_device_id hifier_ids[] __devinitdata = { | 51 | static DEFINE_PCI_DEVICE_TABLE(hifier_ids) = { |
52 | { OXYGEN_PCI_SUBID(0x14c3, 0x1710) }, | 52 | { OXYGEN_PCI_SUBID(0x14c3, 0x1710) }, |
53 | { OXYGEN_PCI_SUBID(0x14c3, 0x1711) }, | 53 | { OXYGEN_PCI_SUBID(0x14c3, 0x1711) }, |
54 | { OXYGEN_PCI_SUBID_BROKEN_EEPROM }, | 54 | { OXYGEN_PCI_SUBID_BROKEN_EEPROM }, |
diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index acbedebcffd9..289cb4dacfc7 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c | |||
@@ -72,7 +72,7 @@ enum { | |||
72 | MODEL_CLARO_HALO, /* HT-Omega Claro halo */ | 72 | MODEL_CLARO_HALO, /* HT-Omega Claro halo */ |
73 | }; | 73 | }; |
74 | 74 | ||
75 | static struct pci_device_id oxygen_ids[] __devinitdata = { | 75 | static DEFINE_PCI_DEVICE_TABLE(oxygen_ids) = { |
76 | { OXYGEN_PCI_SUBID(0x10b0, 0x0216), .driver_data = MODEL_CMEDIA_REF }, | 76 | { OXYGEN_PCI_SUBID(0x10b0, 0x0216), .driver_data = MODEL_CMEDIA_REF }, |
77 | { OXYGEN_PCI_SUBID(0x10b0, 0x0218), .driver_data = MODEL_CMEDIA_REF }, | 77 | { OXYGEN_PCI_SUBID(0x10b0, 0x0218), .driver_data = MODEL_CMEDIA_REF }, |
78 | { OXYGEN_PCI_SUBID(0x10b0, 0x0219), .driver_data = MODEL_CMEDIA_REF }, | 78 | { OXYGEN_PCI_SUBID(0x10b0, 0x0219), .driver_data = MODEL_CMEDIA_REF }, |
diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c index 6accaf9580b2..f03a2f2cffee 100644 --- a/sound/pci/oxygen/virtuoso.c +++ b/sound/pci/oxygen/virtuoso.c | |||
@@ -40,7 +40,7 @@ MODULE_PARM_DESC(id, "ID string"); | |||
40 | module_param_array(enable, bool, NULL, 0444); | 40 | module_param_array(enable, bool, NULL, 0444); |
41 | MODULE_PARM_DESC(enable, "enable card"); | 41 | MODULE_PARM_DESC(enable, "enable card"); |
42 | 42 | ||
43 | static struct pci_device_id xonar_ids[] __devinitdata = { | 43 | static DEFINE_PCI_DEVICE_TABLE(xonar_ids) = { |
44 | { OXYGEN_PCI_SUBID(0x1043, 0x8269) }, | 44 | { OXYGEN_PCI_SUBID(0x1043, 0x8269) }, |
45 | { OXYGEN_PCI_SUBID(0x1043, 0x8275) }, | 45 | { OXYGEN_PCI_SUBID(0x1043, 0x8275) }, |
46 | { OXYGEN_PCI_SUBID(0x1043, 0x82b7) }, | 46 | { OXYGEN_PCI_SUBID(0x1043, 0x82b7) }, |
@@ -49,6 +49,7 @@ static struct pci_device_id xonar_ids[] __devinitdata = { | |||
49 | { OXYGEN_PCI_SUBID(0x1043, 0x834f) }, | 49 | { OXYGEN_PCI_SUBID(0x1043, 0x834f) }, |
50 | { OXYGEN_PCI_SUBID(0x1043, 0x835c) }, | 50 | { OXYGEN_PCI_SUBID(0x1043, 0x835c) }, |
51 | { OXYGEN_PCI_SUBID(0x1043, 0x835d) }, | 51 | { OXYGEN_PCI_SUBID(0x1043, 0x835d) }, |
52 | { OXYGEN_PCI_SUBID(0x1043, 0x838e) }, | ||
52 | { OXYGEN_PCI_SUBID_BROKEN_EEPROM }, | 53 | { OXYGEN_PCI_SUBID_BROKEN_EEPROM }, |
53 | { } | 54 | { } |
54 | }; | 55 | }; |
@@ -61,6 +62,8 @@ static int __devinit get_xonar_model(struct oxygen *chip, | |||
61 | return 0; | 62 | return 0; |
62 | if (get_xonar_cs43xx_model(chip, id) >= 0) | 63 | if (get_xonar_cs43xx_model(chip, id) >= 0) |
63 | return 0; | 64 | return 0; |
65 | if (get_xonar_wm87x6_model(chip, id) >= 0) | ||
66 | return 0; | ||
64 | return -EINVAL; | 67 | return -EINVAL; |
65 | } | 68 | } |
66 | 69 | ||
diff --git a/sound/pci/oxygen/wm8766.h b/sound/pci/oxygen/wm8766.h new file mode 100644 index 000000000000..e0e849a7eaeb --- /dev/null +++ b/sound/pci/oxygen/wm8766.h | |||
@@ -0,0 +1,73 @@ | |||
1 | #ifndef WM8766_H_INCLUDED | ||
2 | #define WM8766_H_INCLUDED | ||
3 | |||
4 | #define WM8766_LDA1 0x00 | ||
5 | #define WM8766_RDA1 0x01 | ||
6 | #define WM8766_DAC_CTRL 0x02 | ||
7 | #define WM8766_INT_CTRL 0x03 | ||
8 | #define WM8766_LDA2 0x04 | ||
9 | #define WM8766_RDA2 0x05 | ||
10 | #define WM8766_LDA3 0x06 | ||
11 | #define WM8766_RDA3 0x07 | ||
12 | #define WM8766_MASTDA 0x08 | ||
13 | #define WM8766_DAC_CTRL2 0x09 | ||
14 | #define WM8766_DAC_CTRL3 0x0a | ||
15 | #define WM8766_MUTE1 0x0c | ||
16 | #define WM8766_MUTE2 0x0f | ||
17 | #define WM8766_RESET 0x1f | ||
18 | |||
19 | /* LDAx/RDAx/MASTDA */ | ||
20 | #define WM8766_ATT_MASK 0x0ff | ||
21 | #define WM8766_UPDATE 0x100 | ||
22 | /* DAC_CTRL */ | ||
23 | #define WM8766_MUTEALL 0x001 | ||
24 | #define WM8766_DEEMPALL 0x002 | ||
25 | #define WM8766_PWDN 0x004 | ||
26 | #define WM8766_ATC 0x008 | ||
27 | #define WM8766_IZD 0x010 | ||
28 | #define WM8766_PL_LEFT_MASK 0x060 | ||
29 | #define WM8766_PL_LEFT_MUTE 0x000 | ||
30 | #define WM8766_PL_LEFT_LEFT 0x020 | ||
31 | #define WM8766_PL_LEFT_RIGHT 0x040 | ||
32 | #define WM8766_PL_LEFT_LRMIX 0x060 | ||
33 | #define WM8766_PL_RIGHT_MASK 0x180 | ||
34 | #define WM8766_PL_RIGHT_MUTE 0x000 | ||
35 | #define WM8766_PL_RIGHT_LEFT 0x080 | ||
36 | #define WM8766_PL_RIGHT_RIGHT 0x100 | ||
37 | #define WM8766_PL_RIGHT_LRMIX 0x180 | ||
38 | /* INT_CTRL */ | ||
39 | #define WM8766_FMT_MASK 0x003 | ||
40 | #define WM8766_FMT_RJUST 0x000 | ||
41 | #define WM8766_FMT_LJUST 0x001 | ||
42 | #define WM8766_FMT_I2S 0x002 | ||
43 | #define WM8766_FMT_DSP 0x003 | ||
44 | #define WM8766_LRP 0x004 | ||
45 | #define WM8766_BCP 0x008 | ||
46 | #define WM8766_IWL_MASK 0x030 | ||
47 | #define WM8766_IWL_16 0x000 | ||
48 | #define WM8766_IWL_20 0x010 | ||
49 | #define WM8766_IWL_24 0x020 | ||
50 | #define WM8766_IWL_32 0x030 | ||
51 | #define WM8766_PHASE_MASK 0x1c0 | ||
52 | /* DAC_CTRL2 */ | ||
53 | #define WM8766_ZCD 0x001 | ||
54 | #define WM8766_DZFM_MASK 0x006 | ||
55 | #define WM8766_DMUTE_MASK 0x038 | ||
56 | #define WM8766_DEEMP_MASK 0x1c0 | ||
57 | /* DAC_CTRL3 */ | ||
58 | #define WM8766_DACPD_MASK 0x00e | ||
59 | #define WM8766_PWRDNALL 0x010 | ||
60 | #define WM8766_MS 0x020 | ||
61 | #define WM8766_RATE_MASK 0x1c0 | ||
62 | #define WM8766_RATE_128 0x000 | ||
63 | #define WM8766_RATE_192 0x040 | ||
64 | #define WM8766_RATE_256 0x080 | ||
65 | #define WM8766_RATE_384 0x0c0 | ||
66 | #define WM8766_RATE_512 0x100 | ||
67 | #define WM8766_RATE_768 0x140 | ||
68 | /* MUTE1 */ | ||
69 | #define WM8766_MPD1 0x040 | ||
70 | /* MUTE2 */ | ||
71 | #define WM8766_MPD2 0x020 | ||
72 | |||
73 | #endif | ||
diff --git a/sound/pci/oxygen/wm8776.h b/sound/pci/oxygen/wm8776.h new file mode 100644 index 000000000000..1a96f5615727 --- /dev/null +++ b/sound/pci/oxygen/wm8776.h | |||
@@ -0,0 +1,177 @@ | |||
1 | #ifndef WM8776_H_INCLUDED | ||
2 | #define WM8776_H_INCLUDED | ||
3 | |||
4 | /* | ||
5 | * the following register names are from: | ||
6 | * wm8776.h -- WM8776 ASoC driver | ||
7 | * | ||
8 | * Copyright 2009 Wolfson Microelectronics plc | ||
9 | * | ||
10 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License version 2 as | ||
14 | * published by the Free Software Foundation. | ||
15 | */ | ||
16 | |||
17 | #define WM8776_HPLVOL 0x00 | ||
18 | #define WM8776_HPRVOL 0x01 | ||
19 | #define WM8776_HPMASTER 0x02 | ||
20 | #define WM8776_DACLVOL 0x03 | ||
21 | #define WM8776_DACRVOL 0x04 | ||
22 | #define WM8776_DACMASTER 0x05 | ||
23 | #define WM8776_PHASESWAP 0x06 | ||
24 | #define WM8776_DACCTRL1 0x07 | ||
25 | #define WM8776_DACMUTE 0x08 | ||
26 | #define WM8776_DACCTRL2 0x09 | ||
27 | #define WM8776_DACIFCTRL 0x0a | ||
28 | #define WM8776_ADCIFCTRL 0x0b | ||
29 | #define WM8776_MSTRCTRL 0x0c | ||
30 | #define WM8776_PWRDOWN 0x0d | ||
31 | #define WM8776_ADCLVOL 0x0e | ||
32 | #define WM8776_ADCRVOL 0x0f | ||
33 | #define WM8776_ALCCTRL1 0x10 | ||
34 | #define WM8776_ALCCTRL2 0x11 | ||
35 | #define WM8776_ALCCTRL3 0x12 | ||
36 | #define WM8776_NOISEGATE 0x13 | ||
37 | #define WM8776_LIMITER 0x14 | ||
38 | #define WM8776_ADCMUX 0x15 | ||
39 | #define WM8776_OUTMUX 0x16 | ||
40 | #define WM8776_RESET 0x17 | ||
41 | |||
42 | |||
43 | /* HPLVOL/HPRVOL/HPMASTER */ | ||
44 | #define WM8776_HPATT_MASK 0x07f | ||
45 | #define WM8776_HPZCEN 0x080 | ||
46 | #define WM8776_UPDATE 0x100 | ||
47 | |||
48 | /* DACLVOL/DACRVOL/DACMASTER */ | ||
49 | #define WM8776_DATT_MASK 0x0ff | ||
50 | /*#define WM8776_UPDATE 0x100*/ | ||
51 | |||
52 | /* PHASESWAP */ | ||
53 | #define WM8776_PH_MASK 0x003 | ||
54 | |||
55 | /* DACCTRL1 */ | ||
56 | #define WM8776_DZCEN 0x001 | ||
57 | #define WM8776_ATC 0x002 | ||
58 | #define WM8776_IZD 0x004 | ||
59 | #define WM8776_TOD 0x008 | ||
60 | #define WM8776_PL_LEFT_MASK 0x030 | ||
61 | #define WM8776_PL_LEFT_MUTE 0x000 | ||
62 | #define WM8776_PL_LEFT_LEFT 0x010 | ||
63 | #define WM8776_PL_LEFT_RIGHT 0x020 | ||
64 | #define WM8776_PL_LEFT_LRMIX 0x030 | ||
65 | #define WM8776_PL_RIGHT_MASK 0x0c0 | ||
66 | #define WM8776_PL_RIGHT_MUTE 0x000 | ||
67 | #define WM8776_PL_RIGHT_LEFT 0x040 | ||
68 | #define WM8776_PL_RIGHT_RIGHT 0x080 | ||
69 | #define WM8776_PL_RIGHT_LRMIX 0x0c0 | ||
70 | |||
71 | /* DACMUTE */ | ||
72 | #define WM8776_DMUTE 0x001 | ||
73 | |||
74 | /* DACCTRL2 */ | ||
75 | #define WM8776_DEEMPH 0x001 | ||
76 | #define WM8776_DZFM_MASK 0x006 | ||
77 | #define WM8776_DZFM_NONE 0x000 | ||
78 | #define WM8776_DZFM_LR 0x002 | ||
79 | #define WM8776_DZFM_BOTH 0x004 | ||
80 | #define WM8776_DZFM_EITHER 0x006 | ||
81 | |||
82 | /* DACIFCTRL */ | ||
83 | #define WM8776_DACFMT_MASK 0x003 | ||
84 | #define WM8776_DACFMT_RJUST 0x000 | ||
85 | #define WM8776_DACFMT_LJUST 0x001 | ||
86 | #define WM8776_DACFMT_I2S 0x002 | ||
87 | #define WM8776_DACFMT_DSP 0x003 | ||
88 | #define WM8776_DACLRP 0x004 | ||
89 | #define WM8776_DACBCP 0x008 | ||
90 | #define WM8776_DACWL_MASK 0x030 | ||
91 | #define WM8776_DACWL_16 0x000 | ||
92 | #define WM8776_DACWL_20 0x010 | ||
93 | #define WM8776_DACWL_24 0x020 | ||
94 | #define WM8776_DACWL_32 0x030 | ||
95 | |||
96 | /* ADCIFCTRL */ | ||
97 | #define WM8776_ADCFMT_MASK 0x003 | ||
98 | #define WM8776_ADCFMT_RJUST 0x000 | ||
99 | #define WM8776_ADCFMT_LJUST 0x001 | ||
100 | #define WM8776_ADCFMT_I2S 0x002 | ||
101 | #define WM8776_ADCFMT_DSP 0x003 | ||
102 | #define WM8776_ADCLRP 0x004 | ||
103 | #define WM8776_ADCBCP 0x008 | ||
104 | #define WM8776_ADCWL_MASK 0x030 | ||
105 | #define WM8776_ADCWL_16 0x000 | ||
106 | #define WM8776_ADCWL_20 0x010 | ||
107 | #define WM8776_ADCWL_24 0x020 | ||
108 | #define WM8776_ADCWL_32 0x030 | ||
109 | #define WM8776_ADCMCLK 0x040 | ||
110 | #define WM8776_ADCHPD 0x100 | ||
111 | |||
112 | /* MSTRCTRL */ | ||
113 | #define WM8776_ADCRATE_MASK 0x007 | ||
114 | #define WM8776_ADCRATE_256 0x002 | ||
115 | #define WM8776_ADCRATE_384 0x003 | ||
116 | #define WM8776_ADCRATE_512 0x004 | ||
117 | #define WM8776_ADCRATE_768 0x005 | ||
118 | #define WM8776_ADCOSR 0x008 | ||
119 | #define WM8776_DACRATE_MASK 0x070 | ||
120 | #define WM8776_DACRATE_128 0x000 | ||
121 | #define WM8776_DACRATE_192 0x010 | ||
122 | #define WM8776_DACRATE_256 0x020 | ||
123 | #define WM8776_DACRATE_384 0x030 | ||
124 | #define WM8776_DACRATE_512 0x040 | ||
125 | #define WM8776_DACRATE_768 0x050 | ||
126 | #define WM8776_DACMS 0x080 | ||
127 | #define WM8776_ADCMS 0x100 | ||
128 | |||
129 | /* PWRDOWN */ | ||
130 | #define WM8776_PDWN 0x001 | ||
131 | #define WM8776_ADCPD 0x002 | ||
132 | #define WM8776_DACPD 0x004 | ||
133 | #define WM8776_HPPD 0x008 | ||
134 | #define WM8776_AINPD 0x040 | ||
135 | |||
136 | /* ADCLVOL/ADCRVOL */ | ||
137 | #define WM8776_AGMASK 0x0ff | ||
138 | #define WM8776_ZCA 0x100 | ||
139 | |||
140 | /* ALCCTRL1 */ | ||
141 | #define WM8776_LCT_MASK 0x00f | ||
142 | #define WM8776_MAXGAIN_MASK 0x070 | ||
143 | #define WM8776_LCSEL_MASK 0x180 | ||
144 | #define WM8776_LCSEL_LIMITER 0x000 | ||
145 | #define WM8776_LCSEL_ALC_RIGHT 0x080 | ||
146 | #define WM8776_LCSEL_ALC_LEFT 0x100 | ||
147 | #define WM8776_LCSEL_ALC_STEREO 0x180 | ||
148 | |||
149 | /* ALCCTRL2 */ | ||
150 | #define WM8776_HLD_MASK 0x00f | ||
151 | #define WM8776_ALCZC 0x080 | ||
152 | #define WM8776_LCEN 0x100 | ||
153 | |||
154 | /* ALCCTRL3 */ | ||
155 | #define WM8776_ATK_MASK 0x00f | ||
156 | #define WM8776_DCY_MASK 0x0f0 | ||
157 | |||
158 | /* NOISEGATE */ | ||
159 | #define WM8776_NGAT 0x001 | ||
160 | #define WM8776_NGTH_MASK 0x01c | ||
161 | |||
162 | /* LIMITER */ | ||
163 | #define WM8776_MAXATTEN_MASK 0x00f | ||
164 | #define WM8776_TRANWIN_MASK 0x070 | ||
165 | |||
166 | /* ADCMUX */ | ||
167 | #define WM8776_AMX_MASK 0x01f | ||
168 | #define WM8776_MUTERA 0x040 | ||
169 | #define WM8776_MUTELA 0x080 | ||
170 | #define WM8776_LRBOTH 0x100 | ||
171 | |||
172 | /* OUTMUX */ | ||
173 | #define WM8776_MX_DAC 0x001 | ||
174 | #define WM8776_MX_AUX 0x002 | ||
175 | #define WM8776_MX_BYPASS 0x004 | ||
176 | |||
177 | #endif | ||
diff --git a/sound/pci/oxygen/xonar.h b/sound/pci/oxygen/xonar.h index 89b3ed814d64..b35343b0a9a5 100644 --- a/sound/pci/oxygen/xonar.h +++ b/sound/pci/oxygen/xonar.h | |||
@@ -35,6 +35,8 @@ int get_xonar_pcm179x_model(struct oxygen *chip, | |||
35 | const struct pci_device_id *id); | 35 | const struct pci_device_id *id); |
36 | int get_xonar_cs43xx_model(struct oxygen *chip, | 36 | int get_xonar_cs43xx_model(struct oxygen *chip, |
37 | const struct pci_device_id *id); | 37 | const struct pci_device_id *id); |
38 | int get_xonar_wm87x6_model(struct oxygen *chip, | ||
39 | const struct pci_device_id *id); | ||
38 | 40 | ||
39 | /* HDMI helper functions */ | 41 | /* HDMI helper functions */ |
40 | 42 | ||
diff --git a/sound/pci/oxygen/xonar_wm87x6.c b/sound/pci/oxygen/xonar_wm87x6.c new file mode 100644 index 000000000000..7754db166d9e --- /dev/null +++ b/sound/pci/oxygen/xonar_wm87x6.c | |||
@@ -0,0 +1,1021 @@ | |||
1 | /* | ||
2 | * card driver for models with WM8776/WM8766 DACs (Xonar DS) | ||
3 | * | ||
4 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> | ||
5 | * | ||
6 | * | ||
7 | * This driver is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License, version 2. | ||
9 | * | ||
10 | * This driver is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this driver; if not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | |||
19 | /* | ||
20 | * Xonar DS | ||
21 | * -------- | ||
22 | * | ||
23 | * CMI8788: | ||
24 | * | ||
25 | * SPI 0 -> WM8766 (surround, center/LFE, back) | ||
26 | * SPI 1 -> WM8776 (front, input) | ||
27 | * | ||
28 | * GPIO 4 <- headphone detect | ||
29 | * GPIO 6 -> route input jack to input 1/2 (1/0) | ||
30 | * GPIO 7 -> enable output to speakers | ||
31 | * GPIO 8 -> enable output to speakers | ||
32 | */ | ||
33 | |||
34 | #include <linux/pci.h> | ||
35 | #include <linux/delay.h> | ||
36 | #include <sound/control.h> | ||
37 | #include <sound/core.h> | ||
38 | #include <sound/pcm.h> | ||
39 | #include <sound/pcm_params.h> | ||
40 | #include <sound/tlv.h> | ||
41 | #include "xonar.h" | ||
42 | #include "wm8776.h" | ||
43 | #include "wm8766.h" | ||
44 | |||
45 | #define GPIO_DS_HP_DETECT 0x0010 | ||
46 | #define GPIO_DS_INPUT_ROUTE 0x0040 | ||
47 | #define GPIO_DS_OUTPUT_ENABLE 0x0180 | ||
48 | |||
49 | #define LC_CONTROL_LIMITER 0x40000000 | ||
50 | #define LC_CONTROL_ALC 0x20000000 | ||
51 | |||
52 | struct xonar_wm87x6 { | ||
53 | struct xonar_generic generic; | ||
54 | u16 wm8776_regs[0x17]; | ||
55 | u16 wm8766_regs[0x10]; | ||
56 | struct snd_kcontrol *lc_controls[13]; | ||
57 | }; | ||
58 | |||
59 | static void wm8776_write(struct oxygen *chip, | ||
60 | unsigned int reg, unsigned int value) | ||
61 | { | ||
62 | struct xonar_wm87x6 *data = chip->model_data; | ||
63 | |||
64 | oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER | | ||
65 | OXYGEN_SPI_DATA_LENGTH_2 | | ||
66 | OXYGEN_SPI_CLOCK_160 | | ||
67 | (1 << OXYGEN_SPI_CODEC_SHIFT) | | ||
68 | OXYGEN_SPI_CEN_LATCH_CLOCK_LO, | ||
69 | (reg << 9) | value); | ||
70 | if (reg < ARRAY_SIZE(data->wm8776_regs)) { | ||
71 | if (reg >= WM8776_HPLVOL || reg <= WM8776_DACMASTER) | ||
72 | value &= ~WM8776_UPDATE; | ||
73 | data->wm8776_regs[reg] = value; | ||
74 | } | ||
75 | } | ||
76 | |||
77 | static void wm8776_write_cached(struct oxygen *chip, | ||
78 | unsigned int reg, unsigned int value) | ||
79 | { | ||
80 | struct xonar_wm87x6 *data = chip->model_data; | ||
81 | |||
82 | if (reg >= ARRAY_SIZE(data->wm8776_regs) || | ||
83 | value != data->wm8776_regs[reg]) | ||
84 | wm8776_write(chip, reg, value); | ||
85 | } | ||
86 | |||
87 | static void wm8766_write(struct oxygen *chip, | ||
88 | unsigned int reg, unsigned int value) | ||
89 | { | ||
90 | struct xonar_wm87x6 *data = chip->model_data; | ||
91 | |||
92 | oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER | | ||
93 | OXYGEN_SPI_DATA_LENGTH_2 | | ||
94 | OXYGEN_SPI_CLOCK_160 | | ||
95 | (0 << OXYGEN_SPI_CODEC_SHIFT) | | ||
96 | OXYGEN_SPI_CEN_LATCH_CLOCK_LO, | ||
97 | (reg << 9) | value); | ||
98 | if (reg < ARRAY_SIZE(data->wm8766_regs)) | ||
99 | data->wm8766_regs[reg] = value; | ||
100 | } | ||
101 | |||
102 | static void wm8766_write_cached(struct oxygen *chip, | ||
103 | unsigned int reg, unsigned int value) | ||
104 | { | ||
105 | struct xonar_wm87x6 *data = chip->model_data; | ||
106 | |||
107 | if (reg >= ARRAY_SIZE(data->wm8766_regs) || | ||
108 | value != data->wm8766_regs[reg]) { | ||
109 | if ((reg >= WM8766_LDA1 && reg <= WM8766_RDA1) || | ||
110 | (reg >= WM8766_LDA2 && reg <= WM8766_MASTDA)) | ||
111 | value &= ~WM8766_UPDATE; | ||
112 | wm8766_write(chip, reg, value); | ||
113 | } | ||
114 | } | ||
115 | |||
116 | static void wm8776_registers_init(struct oxygen *chip) | ||
117 | { | ||
118 | struct xonar_wm87x6 *data = chip->model_data; | ||
119 | |||
120 | wm8776_write(chip, WM8776_RESET, 0); | ||
121 | wm8776_write(chip, WM8776_DACCTRL1, WM8776_DZCEN | | ||
122 | WM8776_PL_LEFT_LEFT | WM8776_PL_RIGHT_RIGHT); | ||
123 | wm8776_write(chip, WM8776_DACMUTE, chip->dac_mute ? WM8776_DMUTE : 0); | ||
124 | wm8776_write(chip, WM8776_DACIFCTRL, | ||
125 | WM8776_DACFMT_LJUST | WM8776_DACWL_24); | ||
126 | wm8776_write(chip, WM8776_ADCIFCTRL, | ||
127 | data->wm8776_regs[WM8776_ADCIFCTRL]); | ||
128 | wm8776_write(chip, WM8776_MSTRCTRL, data->wm8776_regs[WM8776_MSTRCTRL]); | ||
129 | wm8776_write(chip, WM8776_PWRDOWN, data->wm8776_regs[WM8776_PWRDOWN]); | ||
130 | wm8776_write(chip, WM8776_HPLVOL, data->wm8776_regs[WM8776_HPLVOL]); | ||
131 | wm8776_write(chip, WM8776_HPRVOL, data->wm8776_regs[WM8776_HPRVOL] | | ||
132 | WM8776_UPDATE); | ||
133 | wm8776_write(chip, WM8776_ADCLVOL, data->wm8776_regs[WM8776_ADCLVOL]); | ||
134 | wm8776_write(chip, WM8776_ADCRVOL, data->wm8776_regs[WM8776_ADCRVOL]); | ||
135 | wm8776_write(chip, WM8776_ADCMUX, data->wm8776_regs[WM8776_ADCMUX]); | ||
136 | wm8776_write(chip, WM8776_DACLVOL, chip->dac_volume[0]); | ||
137 | wm8776_write(chip, WM8776_DACRVOL, chip->dac_volume[1] | WM8776_UPDATE); | ||
138 | } | ||
139 | |||
140 | static void wm8766_registers_init(struct oxygen *chip) | ||
141 | { | ||
142 | wm8766_write(chip, WM8766_RESET, 0); | ||
143 | wm8766_write(chip, WM8766_INT_CTRL, WM8766_FMT_LJUST | WM8766_IWL_24); | ||
144 | wm8766_write(chip, WM8766_DAC_CTRL2, | ||
145 | WM8766_ZCD | (chip->dac_mute ? WM8766_DMUTE_MASK : 0)); | ||
146 | wm8766_write(chip, WM8766_LDA1, chip->dac_volume[2]); | ||
147 | wm8766_write(chip, WM8766_RDA1, chip->dac_volume[3]); | ||
148 | wm8766_write(chip, WM8766_LDA2, chip->dac_volume[4]); | ||
149 | wm8766_write(chip, WM8766_RDA2, chip->dac_volume[5]); | ||
150 | wm8766_write(chip, WM8766_LDA3, chip->dac_volume[6]); | ||
151 | wm8766_write(chip, WM8766_RDA3, chip->dac_volume[7] | WM8766_UPDATE); | ||
152 | } | ||
153 | |||
154 | static void wm8776_init(struct oxygen *chip) | ||
155 | { | ||
156 | struct xonar_wm87x6 *data = chip->model_data; | ||
157 | |||
158 | data->wm8776_regs[WM8776_HPLVOL] = (0x79 - 60) | WM8776_HPZCEN; | ||
159 | data->wm8776_regs[WM8776_HPRVOL] = (0x79 - 60) | WM8776_HPZCEN; | ||
160 | data->wm8776_regs[WM8776_ADCIFCTRL] = | ||
161 | WM8776_ADCFMT_LJUST | WM8776_ADCWL_24 | WM8776_ADCMCLK; | ||
162 | data->wm8776_regs[WM8776_MSTRCTRL] = | ||
163 | WM8776_ADCRATE_256 | WM8776_DACRATE_256; | ||
164 | data->wm8776_regs[WM8776_PWRDOWN] = WM8776_HPPD; | ||
165 | data->wm8776_regs[WM8776_ADCLVOL] = 0xa5 | WM8776_ZCA; | ||
166 | data->wm8776_regs[WM8776_ADCRVOL] = 0xa5 | WM8776_ZCA; | ||
167 | data->wm8776_regs[WM8776_ADCMUX] = 0x001; | ||
168 | wm8776_registers_init(chip); | ||
169 | } | ||
170 | |||
171 | static void xonar_ds_init(struct oxygen *chip) | ||
172 | { | ||
173 | struct xonar_wm87x6 *data = chip->model_data; | ||
174 | |||
175 | data->generic.anti_pop_delay = 300; | ||
176 | data->generic.output_enable_bit = GPIO_DS_OUTPUT_ENABLE; | ||
177 | |||
178 | wm8776_init(chip); | ||
179 | wm8766_registers_init(chip); | ||
180 | |||
181 | oxygen_write16_masked(chip, OXYGEN_GPIO_CONTROL, GPIO_DS_INPUT_ROUTE, | ||
182 | GPIO_DS_HP_DETECT | GPIO_DS_INPUT_ROUTE); | ||
183 | oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_DS_INPUT_ROUTE); | ||
184 | oxygen_set_bits16(chip, OXYGEN_GPIO_INTERRUPT_MASK, GPIO_DS_HP_DETECT); | ||
185 | chip->interrupt_mask |= OXYGEN_INT_GPIO; | ||
186 | |||
187 | xonar_enable_output(chip); | ||
188 | |||
189 | snd_component_add(chip->card, "WM8776"); | ||
190 | snd_component_add(chip->card, "WM8766"); | ||
191 | } | ||
192 | |||
193 | static void xonar_ds_cleanup(struct oxygen *chip) | ||
194 | { | ||
195 | xonar_disable_output(chip); | ||
196 | } | ||
197 | |||
198 | static void xonar_ds_suspend(struct oxygen *chip) | ||
199 | { | ||
200 | xonar_ds_cleanup(chip); | ||
201 | } | ||
202 | |||
203 | static void xonar_ds_resume(struct oxygen *chip) | ||
204 | { | ||
205 | wm8776_registers_init(chip); | ||
206 | wm8766_registers_init(chip); | ||
207 | xonar_enable_output(chip); | ||
208 | } | ||
209 | |||
210 | static void wm8776_adc_hardware_filter(unsigned int channel, | ||
211 | struct snd_pcm_hardware *hardware) | ||
212 | { | ||
213 | if (channel == PCM_A) { | ||
214 | hardware->rates = SNDRV_PCM_RATE_32000 | | ||
215 | SNDRV_PCM_RATE_44100 | | ||
216 | SNDRV_PCM_RATE_48000 | | ||
217 | SNDRV_PCM_RATE_64000 | | ||
218 | SNDRV_PCM_RATE_88200 | | ||
219 | SNDRV_PCM_RATE_96000; | ||
220 | hardware->rate_max = 96000; | ||
221 | } | ||
222 | } | ||
223 | |||
224 | static void set_wm87x6_dac_params(struct oxygen *chip, | ||
225 | struct snd_pcm_hw_params *params) | ||
226 | { | ||
227 | } | ||
228 | |||
229 | static void set_wm8776_adc_params(struct oxygen *chip, | ||
230 | struct snd_pcm_hw_params *params) | ||
231 | { | ||
232 | u16 reg; | ||
233 | |||
234 | reg = WM8776_ADCRATE_256 | WM8776_DACRATE_256; | ||
235 | if (params_rate(params) > 48000) | ||
236 | reg |= WM8776_ADCOSR; | ||
237 | wm8776_write_cached(chip, WM8776_MSTRCTRL, reg); | ||
238 | } | ||
239 | |||
240 | static void update_wm8776_volume(struct oxygen *chip) | ||
241 | { | ||
242 | struct xonar_wm87x6 *data = chip->model_data; | ||
243 | u8 to_change; | ||
244 | |||
245 | if (chip->dac_volume[0] == chip->dac_volume[1]) { | ||
246 | if (chip->dac_volume[0] != data->wm8776_regs[WM8776_DACLVOL] || | ||
247 | chip->dac_volume[1] != data->wm8776_regs[WM8776_DACRVOL]) { | ||
248 | wm8776_write(chip, WM8776_DACMASTER, | ||
249 | chip->dac_volume[0] | WM8776_UPDATE); | ||
250 | data->wm8776_regs[WM8776_DACLVOL] = chip->dac_volume[0]; | ||
251 | data->wm8776_regs[WM8776_DACRVOL] = chip->dac_volume[0]; | ||
252 | } | ||
253 | } else { | ||
254 | to_change = (chip->dac_volume[0] != | ||
255 | data->wm8776_regs[WM8776_DACLVOL]) << 0; | ||
256 | to_change |= (chip->dac_volume[1] != | ||
257 | data->wm8776_regs[WM8776_DACLVOL]) << 1; | ||
258 | if (to_change & 1) | ||
259 | wm8776_write(chip, WM8776_DACLVOL, chip->dac_volume[0] | | ||
260 | ((to_change & 2) ? 0 : WM8776_UPDATE)); | ||
261 | if (to_change & 2) | ||
262 | wm8776_write(chip, WM8776_DACRVOL, | ||
263 | chip->dac_volume[1] | WM8776_UPDATE); | ||
264 | } | ||
265 | } | ||
266 | |||
267 | static void update_wm87x6_volume(struct oxygen *chip) | ||
268 | { | ||
269 | static const u8 wm8766_regs[6] = { | ||
270 | WM8766_LDA1, WM8766_RDA1, | ||
271 | WM8766_LDA2, WM8766_RDA2, | ||
272 | WM8766_LDA3, WM8766_RDA3, | ||
273 | }; | ||
274 | struct xonar_wm87x6 *data = chip->model_data; | ||
275 | unsigned int i; | ||
276 | u8 to_change; | ||
277 | |||
278 | update_wm8776_volume(chip); | ||
279 | if (chip->dac_volume[2] == chip->dac_volume[3] && | ||
280 | chip->dac_volume[2] == chip->dac_volume[4] && | ||
281 | chip->dac_volume[2] == chip->dac_volume[5] && | ||
282 | chip->dac_volume[2] == chip->dac_volume[6] && | ||
283 | chip->dac_volume[2] == chip->dac_volume[7]) { | ||
284 | to_change = 0; | ||
285 | for (i = 0; i < 6; ++i) | ||
286 | if (chip->dac_volume[2] != | ||
287 | data->wm8766_regs[wm8766_regs[i]]) | ||
288 | to_change = 1; | ||
289 | if (to_change) { | ||
290 | wm8766_write(chip, WM8766_MASTDA, | ||
291 | chip->dac_volume[2] | WM8766_UPDATE); | ||
292 | for (i = 0; i < 6; ++i) | ||
293 | data->wm8766_regs[wm8766_regs[i]] = | ||
294 | chip->dac_volume[2]; | ||
295 | } | ||
296 | } else { | ||
297 | to_change = 0; | ||
298 | for (i = 0; i < 6; ++i) | ||
299 | to_change |= (chip->dac_volume[2 + i] != | ||
300 | data->wm8766_regs[wm8766_regs[i]]) << i; | ||
301 | for (i = 0; i < 6; ++i) | ||
302 | if (to_change & (1 << i)) | ||
303 | wm8766_write(chip, wm8766_regs[i], | ||
304 | chip->dac_volume[2 + i] | | ||
305 | ((to_change & (0x3e << i)) | ||
306 | ? 0 : WM8766_UPDATE)); | ||
307 | } | ||
308 | } | ||
309 | |||
310 | static void update_wm8776_mute(struct oxygen *chip) | ||
311 | { | ||
312 | wm8776_write_cached(chip, WM8776_DACMUTE, | ||
313 | chip->dac_mute ? WM8776_DMUTE : 0); | ||
314 | } | ||
315 | |||
316 | static void update_wm87x6_mute(struct oxygen *chip) | ||
317 | { | ||
318 | update_wm8776_mute(chip); | ||
319 | wm8766_write_cached(chip, WM8766_DAC_CTRL2, WM8766_ZCD | | ||
320 | (chip->dac_mute ? WM8766_DMUTE_MASK : 0)); | ||
321 | } | ||
322 | |||
323 | static void xonar_ds_gpio_changed(struct oxygen *chip) | ||
324 | { | ||
325 | u16 bits; | ||
326 | |||
327 | bits = oxygen_read16(chip, OXYGEN_GPIO_DATA); | ||
328 | snd_printk(KERN_INFO "HP detect: %d\n", !!(bits & GPIO_DS_HP_DETECT)); | ||
329 | } | ||
330 | |||
331 | static int wm8776_bit_switch_get(struct snd_kcontrol *ctl, | ||
332 | struct snd_ctl_elem_value *value) | ||
333 | { | ||
334 | struct oxygen *chip = ctl->private_data; | ||
335 | struct xonar_wm87x6 *data = chip->model_data; | ||
336 | u16 bit = ctl->private_value & 0xffff; | ||
337 | unsigned int reg_index = (ctl->private_value >> 16) & 0xff; | ||
338 | bool invert = (ctl->private_value >> 24) & 1; | ||
339 | |||
340 | value->value.integer.value[0] = | ||
341 | ((data->wm8776_regs[reg_index] & bit) != 0) ^ invert; | ||
342 | return 0; | ||
343 | } | ||
344 | |||
345 | static int wm8776_bit_switch_put(struct snd_kcontrol *ctl, | ||
346 | struct snd_ctl_elem_value *value) | ||
347 | { | ||
348 | struct oxygen *chip = ctl->private_data; | ||
349 | struct xonar_wm87x6 *data = chip->model_data; | ||
350 | u16 bit = ctl->private_value & 0xffff; | ||
351 | u16 reg_value; | ||
352 | unsigned int reg_index = (ctl->private_value >> 16) & 0xff; | ||
353 | bool invert = (ctl->private_value >> 24) & 1; | ||
354 | int changed; | ||
355 | |||
356 | mutex_lock(&chip->mutex); | ||
357 | reg_value = data->wm8776_regs[reg_index] & ~bit; | ||
358 | if (value->value.integer.value[0] ^ invert) | ||
359 | reg_value |= bit; | ||
360 | changed = reg_value != data->wm8776_regs[reg_index]; | ||
361 | if (changed) | ||
362 | wm8776_write(chip, reg_index, reg_value); | ||
363 | mutex_unlock(&chip->mutex); | ||
364 | return changed; | ||
365 | } | ||
366 | |||
367 | static int wm8776_field_enum_info(struct snd_kcontrol *ctl, | ||
368 | struct snd_ctl_elem_info *info) | ||
369 | { | ||
370 | static const char *const hld[16] = { | ||
371 | "0 ms", "2.67 ms", "5.33 ms", "10.6 ms", | ||
372 | "21.3 ms", "42.7 ms", "85.3 ms", "171 ms", | ||
373 | "341 ms", "683 ms", "1.37 s", "2.73 s", | ||
374 | "5.46 s", "10.9 s", "21.8 s", "43.7 s", | ||
375 | }; | ||
376 | static const char *const atk_lim[11] = { | ||
377 | "0.25 ms", "0.5 ms", "1 ms", "2 ms", | ||
378 | "4 ms", "8 ms", "16 ms", "32 ms", | ||
379 | "64 ms", "128 ms", "256 ms", | ||
380 | }; | ||
381 | static const char *const atk_alc[11] = { | ||
382 | "8.40 ms", "16.8 ms", "33.6 ms", "67.2 ms", | ||
383 | "134 ms", "269 ms", "538 ms", "1.08 s", | ||
384 | "2.15 s", "4.3 s", "8.6 s", | ||
385 | }; | ||
386 | static const char *const dcy_lim[11] = { | ||
387 | "1.2 ms", "2.4 ms", "4.8 ms", "9.6 ms", | ||
388 | "19.2 ms", "38.4 ms", "76.8 ms", "154 ms", | ||
389 | "307 ms", "614 ms", "1.23 s", | ||
390 | }; | ||
391 | static const char *const dcy_alc[11] = { | ||
392 | "33.5 ms", "67.0 ms", "134 ms", "268 ms", | ||
393 | "536 ms", "1.07 s", "2.14 s", "4.29 s", | ||
394 | "8.58 s", "17.2 s", "34.3 s", | ||
395 | }; | ||
396 | static const char *const tranwin[8] = { | ||
397 | "0 us", "62.5 us", "125 us", "250 us", | ||
398 | "500 us", "1 ms", "2 ms", "4 ms", | ||
399 | }; | ||
400 | u8 max; | ||
401 | const char *const *names; | ||
402 | |||
403 | max = (ctl->private_value >> 12) & 0xf; | ||
404 | info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
405 | info->count = 1; | ||
406 | info->value.enumerated.items = max + 1; | ||
407 | if (info->value.enumerated.item > max) | ||
408 | info->value.enumerated.item = max; | ||
409 | switch ((ctl->private_value >> 24) & 0x1f) { | ||
410 | case WM8776_ALCCTRL2: | ||
411 | names = hld; | ||
412 | break; | ||
413 | case WM8776_ALCCTRL3: | ||
414 | if (((ctl->private_value >> 20) & 0xf) == 0) { | ||
415 | if (ctl->private_value & LC_CONTROL_LIMITER) | ||
416 | names = atk_lim; | ||
417 | else | ||
418 | names = atk_alc; | ||
419 | } else { | ||
420 | if (ctl->private_value & LC_CONTROL_LIMITER) | ||
421 | names = dcy_lim; | ||
422 | else | ||
423 | names = dcy_alc; | ||
424 | } | ||
425 | break; | ||
426 | case WM8776_LIMITER: | ||
427 | names = tranwin; | ||
428 | break; | ||
429 | default: | ||
430 | return -ENXIO; | ||
431 | } | ||
432 | strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); | ||
433 | return 0; | ||
434 | } | ||
435 | |||
436 | static int wm8776_field_volume_info(struct snd_kcontrol *ctl, | ||
437 | struct snd_ctl_elem_info *info) | ||
438 | { | ||
439 | info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
440 | info->count = 1; | ||
441 | info->value.integer.min = (ctl->private_value >> 8) & 0xf; | ||
442 | info->value.integer.max = (ctl->private_value >> 12) & 0xf; | ||
443 | return 0; | ||
444 | } | ||
445 | |||
446 | static void wm8776_field_set_from_ctl(struct snd_kcontrol *ctl) | ||
447 | { | ||
448 | struct oxygen *chip = ctl->private_data; | ||
449 | struct xonar_wm87x6 *data = chip->model_data; | ||
450 | unsigned int value, reg_index, mode; | ||
451 | u8 min, max, shift; | ||
452 | u16 mask, reg_value; | ||
453 | bool invert; | ||
454 | |||
455 | if ((data->wm8776_regs[WM8776_ALCCTRL1] & WM8776_LCSEL_MASK) == | ||
456 | WM8776_LCSEL_LIMITER) | ||
457 | mode = LC_CONTROL_LIMITER; | ||
458 | else | ||
459 | mode = LC_CONTROL_ALC; | ||
460 | if (!(ctl->private_value & mode)) | ||
461 | return; | ||
462 | |||
463 | value = ctl->private_value & 0xf; | ||
464 | min = (ctl->private_value >> 8) & 0xf; | ||
465 | max = (ctl->private_value >> 12) & 0xf; | ||
466 | mask = (ctl->private_value >> 16) & 0xf; | ||
467 | shift = (ctl->private_value >> 20) & 0xf; | ||
468 | reg_index = (ctl->private_value >> 24) & 0x1f; | ||
469 | invert = (ctl->private_value >> 29) & 0x1; | ||
470 | |||
471 | if (invert) | ||
472 | value = max - (value - min); | ||
473 | reg_value = data->wm8776_regs[reg_index]; | ||
474 | reg_value &= ~(mask << shift); | ||
475 | reg_value |= value << shift; | ||
476 | wm8776_write_cached(chip, reg_index, reg_value); | ||
477 | } | ||
478 | |||
479 | static int wm8776_field_set(struct snd_kcontrol *ctl, unsigned int value) | ||
480 | { | ||
481 | struct oxygen *chip = ctl->private_data; | ||
482 | u8 min, max; | ||
483 | int changed; | ||
484 | |||
485 | min = (ctl->private_value >> 8) & 0xf; | ||
486 | max = (ctl->private_value >> 12) & 0xf; | ||
487 | if (value < min || value > max) | ||
488 | return -EINVAL; | ||
489 | mutex_lock(&chip->mutex); | ||
490 | changed = value != (ctl->private_value & 0xf); | ||
491 | if (changed) { | ||
492 | ctl->private_value = (ctl->private_value & ~0xf) | value; | ||
493 | wm8776_field_set_from_ctl(ctl); | ||
494 | } | ||
495 | mutex_unlock(&chip->mutex); | ||
496 | return changed; | ||
497 | } | ||
498 | |||
499 | static int wm8776_field_enum_get(struct snd_kcontrol *ctl, | ||
500 | struct snd_ctl_elem_value *value) | ||
501 | { | ||
502 | value->value.enumerated.item[0] = ctl->private_value & 0xf; | ||
503 | return 0; | ||
504 | } | ||
505 | |||
506 | static int wm8776_field_volume_get(struct snd_kcontrol *ctl, | ||
507 | struct snd_ctl_elem_value *value) | ||
508 | { | ||
509 | value->value.integer.value[0] = ctl->private_value & 0xf; | ||
510 | return 0; | ||
511 | } | ||
512 | |||
513 | static int wm8776_field_enum_put(struct snd_kcontrol *ctl, | ||
514 | struct snd_ctl_elem_value *value) | ||
515 | { | ||
516 | return wm8776_field_set(ctl, value->value.enumerated.item[0]); | ||
517 | } | ||
518 | |||
519 | static int wm8776_field_volume_put(struct snd_kcontrol *ctl, | ||
520 | struct snd_ctl_elem_value *value) | ||
521 | { | ||
522 | return wm8776_field_set(ctl, value->value.integer.value[0]); | ||
523 | } | ||
524 | |||
525 | static int wm8776_hp_vol_info(struct snd_kcontrol *ctl, | ||
526 | struct snd_ctl_elem_info *info) | ||
527 | { | ||
528 | info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
529 | info->count = 2; | ||
530 | info->value.integer.min = 0x79 - 60; | ||
531 | info->value.integer.max = 0x7f; | ||
532 | return 0; | ||
533 | } | ||
534 | |||
535 | static int wm8776_hp_vol_get(struct snd_kcontrol *ctl, | ||
536 | struct snd_ctl_elem_value *value) | ||
537 | { | ||
538 | struct oxygen *chip = ctl->private_data; | ||
539 | struct xonar_wm87x6 *data = chip->model_data; | ||
540 | |||
541 | mutex_lock(&chip->mutex); | ||
542 | value->value.integer.value[0] = | ||
543 | data->wm8776_regs[WM8776_HPLVOL] & WM8776_HPATT_MASK; | ||
544 | value->value.integer.value[1] = | ||
545 | data->wm8776_regs[WM8776_HPRVOL] & WM8776_HPATT_MASK; | ||
546 | mutex_unlock(&chip->mutex); | ||
547 | return 0; | ||
548 | } | ||
549 | |||
550 | static int wm8776_hp_vol_put(struct snd_kcontrol *ctl, | ||
551 | struct snd_ctl_elem_value *value) | ||
552 | { | ||
553 | struct oxygen *chip = ctl->private_data; | ||
554 | struct xonar_wm87x6 *data = chip->model_data; | ||
555 | u8 to_update; | ||
556 | |||
557 | mutex_lock(&chip->mutex); | ||
558 | to_update = (value->value.integer.value[0] != | ||
559 | (data->wm8776_regs[WM8776_HPLVOL] & WM8776_HPATT_MASK)) | ||
560 | << 0; | ||
561 | to_update |= (value->value.integer.value[1] != | ||
562 | (data->wm8776_regs[WM8776_HPRVOL] & WM8776_HPATT_MASK)) | ||
563 | << 1; | ||
564 | if (value->value.integer.value[0] == value->value.integer.value[1]) { | ||
565 | if (to_update) { | ||
566 | wm8776_write(chip, WM8776_HPMASTER, | ||
567 | value->value.integer.value[0] | | ||
568 | WM8776_HPZCEN | WM8776_UPDATE); | ||
569 | data->wm8776_regs[WM8776_HPLVOL] = | ||
570 | value->value.integer.value[0] | WM8776_HPZCEN; | ||
571 | data->wm8776_regs[WM8776_HPRVOL] = | ||
572 | value->value.integer.value[0] | WM8776_HPZCEN; | ||
573 | } | ||
574 | } else { | ||
575 | if (to_update & 1) | ||
576 | wm8776_write(chip, WM8776_HPLVOL, | ||
577 | value->value.integer.value[0] | | ||
578 | WM8776_HPZCEN | | ||
579 | ((to_update & 2) ? 0 : WM8776_UPDATE)); | ||
580 | if (to_update & 2) | ||
581 | wm8776_write(chip, WM8776_HPRVOL, | ||
582 | value->value.integer.value[1] | | ||
583 | WM8776_HPZCEN | WM8776_UPDATE); | ||
584 | } | ||
585 | mutex_unlock(&chip->mutex); | ||
586 | return to_update != 0; | ||
587 | } | ||
588 | |||
589 | static int wm8776_input_mux_get(struct snd_kcontrol *ctl, | ||
590 | struct snd_ctl_elem_value *value) | ||
591 | { | ||
592 | struct oxygen *chip = ctl->private_data; | ||
593 | struct xonar_wm87x6 *data = chip->model_data; | ||
594 | unsigned int mux_bit = ctl->private_value; | ||
595 | |||
596 | value->value.integer.value[0] = | ||
597 | !!(data->wm8776_regs[WM8776_ADCMUX] & mux_bit); | ||
598 | return 0; | ||
599 | } | ||
600 | |||
601 | static int wm8776_input_mux_put(struct snd_kcontrol *ctl, | ||
602 | struct snd_ctl_elem_value *value) | ||
603 | { | ||
604 | struct oxygen *chip = ctl->private_data; | ||
605 | struct xonar_wm87x6 *data = chip->model_data; | ||
606 | unsigned int mux_bit = ctl->private_value; | ||
607 | u16 reg; | ||
608 | int changed; | ||
609 | |||
610 | mutex_lock(&chip->mutex); | ||
611 | reg = data->wm8776_regs[WM8776_ADCMUX]; | ||
612 | if (value->value.integer.value[0]) { | ||
613 | reg &= ~0x003; | ||
614 | reg |= mux_bit; | ||
615 | } else | ||
616 | reg &= ~mux_bit; | ||
617 | changed = reg != data->wm8776_regs[WM8776_ADCMUX]; | ||
618 | if (changed) { | ||
619 | oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, | ||
620 | reg & 1 ? GPIO_DS_INPUT_ROUTE : 0, | ||
621 | GPIO_DS_INPUT_ROUTE); | ||
622 | wm8776_write(chip, WM8776_ADCMUX, reg); | ||
623 | } | ||
624 | mutex_unlock(&chip->mutex); | ||
625 | return changed; | ||
626 | } | ||
627 | |||
628 | static int wm8776_input_vol_info(struct snd_kcontrol *ctl, | ||
629 | struct snd_ctl_elem_info *info) | ||
630 | { | ||
631 | info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
632 | info->count = 2; | ||
633 | info->value.integer.min = 0xa5; | ||
634 | info->value.integer.max = 0xff; | ||
635 | return 0; | ||
636 | } | ||
637 | |||
638 | static int wm8776_input_vol_get(struct snd_kcontrol *ctl, | ||
639 | struct snd_ctl_elem_value *value) | ||
640 | { | ||
641 | struct oxygen *chip = ctl->private_data; | ||
642 | struct xonar_wm87x6 *data = chip->model_data; | ||
643 | |||
644 | mutex_lock(&chip->mutex); | ||
645 | value->value.integer.value[0] = | ||
646 | data->wm8776_regs[WM8776_ADCLVOL] & WM8776_AGMASK; | ||
647 | value->value.integer.value[1] = | ||
648 | data->wm8776_regs[WM8776_ADCRVOL] & WM8776_AGMASK; | ||
649 | mutex_unlock(&chip->mutex); | ||
650 | return 0; | ||
651 | } | ||
652 | |||
653 | static int wm8776_input_vol_put(struct snd_kcontrol *ctl, | ||
654 | struct snd_ctl_elem_value *value) | ||
655 | { | ||
656 | struct oxygen *chip = ctl->private_data; | ||
657 | struct xonar_wm87x6 *data = chip->model_data; | ||
658 | int changed = 0; | ||
659 | |||
660 | mutex_lock(&chip->mutex); | ||
661 | changed = (value->value.integer.value[0] != | ||
662 | (data->wm8776_regs[WM8776_ADCLVOL] & WM8776_AGMASK)) || | ||
663 | (value->value.integer.value[1] != | ||
664 | (data->wm8776_regs[WM8776_ADCRVOL] & WM8776_AGMASK)); | ||
665 | wm8776_write_cached(chip, WM8776_ADCLVOL, | ||
666 | value->value.integer.value[0] | WM8776_ZCA); | ||
667 | wm8776_write_cached(chip, WM8776_ADCRVOL, | ||
668 | value->value.integer.value[1] | WM8776_ZCA); | ||
669 | mutex_unlock(&chip->mutex); | ||
670 | return changed; | ||
671 | } | ||
672 | |||
673 | static int wm8776_level_control_info(struct snd_kcontrol *ctl, | ||
674 | struct snd_ctl_elem_info *info) | ||
675 | { | ||
676 | static const char *const names[3] = { | ||
677 | "None", "Peak Limiter", "Automatic Level Control" | ||
678 | }; | ||
679 | info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
680 | info->count = 1; | ||
681 | info->value.enumerated.items = 3; | ||
682 | if (info->value.enumerated.item >= 3) | ||
683 | info->value.enumerated.item = 2; | ||
684 | strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); | ||
685 | return 0; | ||
686 | } | ||
687 | |||
688 | static int wm8776_level_control_get(struct snd_kcontrol *ctl, | ||
689 | struct snd_ctl_elem_value *value) | ||
690 | { | ||
691 | struct oxygen *chip = ctl->private_data; | ||
692 | struct xonar_wm87x6 *data = chip->model_data; | ||
693 | |||
694 | if (!(data->wm8776_regs[WM8776_ALCCTRL2] & WM8776_LCEN)) | ||
695 | value->value.enumerated.item[0] = 0; | ||
696 | else if ((data->wm8776_regs[WM8776_ALCCTRL1] & WM8776_LCSEL_MASK) == | ||
697 | WM8776_LCSEL_LIMITER) | ||
698 | value->value.enumerated.item[0] = 1; | ||
699 | else | ||
700 | value->value.enumerated.item[0] = 2; | ||
701 | return 0; | ||
702 | } | ||
703 | |||
704 | static void activate_control(struct oxygen *chip, | ||
705 | struct snd_kcontrol *ctl, unsigned int mode) | ||
706 | { | ||
707 | unsigned int access; | ||
708 | |||
709 | if (ctl->private_value & mode) | ||
710 | access = 0; | ||
711 | else | ||
712 | access = SNDRV_CTL_ELEM_ACCESS_INACTIVE; | ||
713 | if ((ctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_INACTIVE) != access) { | ||
714 | ctl->vd[0].access ^= SNDRV_CTL_ELEM_ACCESS_INACTIVE; | ||
715 | snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_INFO, &ctl->id); | ||
716 | } | ||
717 | } | ||
718 | |||
719 | static int wm8776_level_control_put(struct snd_kcontrol *ctl, | ||
720 | struct snd_ctl_elem_value *value) | ||
721 | { | ||
722 | struct oxygen *chip = ctl->private_data; | ||
723 | struct xonar_wm87x6 *data = chip->model_data; | ||
724 | unsigned int mode = 0, i; | ||
725 | u16 ctrl1, ctrl2; | ||
726 | int changed; | ||
727 | |||
728 | if (value->value.enumerated.item[0] >= 3) | ||
729 | return -EINVAL; | ||
730 | mutex_lock(&chip->mutex); | ||
731 | changed = value->value.enumerated.item[0] != ctl->private_value; | ||
732 | if (changed) { | ||
733 | ctl->private_value = value->value.enumerated.item[0]; | ||
734 | ctrl1 = data->wm8776_regs[WM8776_ALCCTRL1]; | ||
735 | ctrl2 = data->wm8776_regs[WM8776_ALCCTRL2]; | ||
736 | switch (value->value.enumerated.item[0]) { | ||
737 | default: | ||
738 | wm8776_write_cached(chip, WM8776_ALCCTRL2, | ||
739 | ctrl2 & ~WM8776_LCEN); | ||
740 | break; | ||
741 | case 1: | ||
742 | wm8776_write_cached(chip, WM8776_ALCCTRL1, | ||
743 | (ctrl1 & ~WM8776_LCSEL_MASK) | | ||
744 | WM8776_LCSEL_LIMITER); | ||
745 | wm8776_write_cached(chip, WM8776_ALCCTRL2, | ||
746 | ctrl2 | WM8776_LCEN); | ||
747 | mode = LC_CONTROL_LIMITER; | ||
748 | break; | ||
749 | case 2: | ||
750 | wm8776_write_cached(chip, WM8776_ALCCTRL1, | ||
751 | (ctrl1 & ~WM8776_LCSEL_MASK) | | ||
752 | WM8776_LCSEL_ALC_STEREO); | ||
753 | wm8776_write_cached(chip, WM8776_ALCCTRL2, | ||
754 | ctrl2 | WM8776_LCEN); | ||
755 | mode = LC_CONTROL_ALC; | ||
756 | break; | ||
757 | } | ||
758 | for (i = 0; i < ARRAY_SIZE(data->lc_controls); ++i) | ||
759 | activate_control(chip, data->lc_controls[i], mode); | ||
760 | } | ||
761 | mutex_unlock(&chip->mutex); | ||
762 | return changed; | ||
763 | } | ||
764 | |||
765 | static int hpf_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) | ||
766 | { | ||
767 | static const char *const names[2] = { | ||
768 | "None", "High-pass Filter" | ||
769 | }; | ||
770 | |||
771 | info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
772 | info->count = 1; | ||
773 | info->value.enumerated.items = 2; | ||
774 | if (info->value.enumerated.item >= 2) | ||
775 | info->value.enumerated.item = 1; | ||
776 | strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); | ||
777 | return 0; | ||
778 | } | ||
779 | |||
780 | static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) | ||
781 | { | ||
782 | struct oxygen *chip = ctl->private_data; | ||
783 | struct xonar_wm87x6 *data = chip->model_data; | ||
784 | |||
785 | value->value.enumerated.item[0] = | ||
786 | !(data->wm8776_regs[WM8776_ADCIFCTRL] & WM8776_ADCHPD); | ||
787 | return 0; | ||
788 | } | ||
789 | |||
790 | static int hpf_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) | ||
791 | { | ||
792 | struct oxygen *chip = ctl->private_data; | ||
793 | struct xonar_wm87x6 *data = chip->model_data; | ||
794 | unsigned int reg; | ||
795 | int changed; | ||
796 | |||
797 | mutex_lock(&chip->mutex); | ||
798 | reg = data->wm8776_regs[WM8776_ADCIFCTRL] & ~WM8776_ADCHPD; | ||
799 | if (!value->value.enumerated.item[0]) | ||
800 | reg |= WM8776_ADCHPD; | ||
801 | changed = reg != data->wm8776_regs[WM8776_ADCIFCTRL]; | ||
802 | if (changed) | ||
803 | wm8776_write(chip, WM8776_ADCIFCTRL, reg); | ||
804 | mutex_unlock(&chip->mutex); | ||
805 | return changed; | ||
806 | } | ||
807 | |||
808 | #define WM8776_BIT_SWITCH(xname, reg, bit, invert, flags) { \ | ||
809 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
810 | .name = xname, \ | ||
811 | .info = snd_ctl_boolean_mono_info, \ | ||
812 | .get = wm8776_bit_switch_get, \ | ||
813 | .put = wm8776_bit_switch_put, \ | ||
814 | .private_value = ((reg) << 16) | (bit) | ((invert) << 24) | (flags), \ | ||
815 | } | ||
816 | #define _WM8776_FIELD_CTL(xname, reg, shift, initval, min, max, mask, flags) \ | ||
817 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
818 | .name = xname, \ | ||
819 | .private_value = (initval) | ((min) << 8) | ((max) << 12) | \ | ||
820 | ((mask) << 16) | ((shift) << 20) | ((reg) << 24) | (flags) | ||
821 | #define WM8776_FIELD_CTL_ENUM(xname, reg, shift, init, min, max, mask, flags) {\ | ||
822 | _WM8776_FIELD_CTL(xname " Capture Enum", \ | ||
823 | reg, shift, init, min, max, mask, flags), \ | ||
824 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ | ||
825 | SNDRV_CTL_ELEM_ACCESS_INACTIVE, \ | ||
826 | .info = wm8776_field_enum_info, \ | ||
827 | .get = wm8776_field_enum_get, \ | ||
828 | .put = wm8776_field_enum_put, \ | ||
829 | } | ||
830 | #define WM8776_FIELD_CTL_VOLUME(a, b, c, d, e, f, g, h, tlv_p) { \ | ||
831 | _WM8776_FIELD_CTL(a " Capture Volume", b, c, d, e, f, g, h), \ | ||
832 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ | ||
833 | SNDRV_CTL_ELEM_ACCESS_INACTIVE | \ | ||
834 | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ | ||
835 | .info = wm8776_field_volume_info, \ | ||
836 | .get = wm8776_field_volume_get, \ | ||
837 | .put = wm8776_field_volume_put, \ | ||
838 | .tlv = { .p = tlv_p }, \ | ||
839 | } | ||
840 | |||
841 | static const DECLARE_TLV_DB_SCALE(wm87x6_dac_db_scale, -6000, 50, 0); | ||
842 | static const DECLARE_TLV_DB_SCALE(wm8776_adc_db_scale, -2100, 50, 0); | ||
843 | static const DECLARE_TLV_DB_SCALE(wm8776_hp_db_scale, -6000, 100, 0); | ||
844 | static const DECLARE_TLV_DB_SCALE(wm8776_lct_db_scale, -1600, 100, 0); | ||
845 | static const DECLARE_TLV_DB_SCALE(wm8776_maxgain_db_scale, 0, 400, 0); | ||
846 | static const DECLARE_TLV_DB_SCALE(wm8776_ngth_db_scale, -7800, 600, 0); | ||
847 | static const DECLARE_TLV_DB_SCALE(wm8776_maxatten_lim_db_scale, -1200, 100, 0); | ||
848 | static const DECLARE_TLV_DB_SCALE(wm8776_maxatten_alc_db_scale, -2100, 400, 0); | ||
849 | |||
850 | static const struct snd_kcontrol_new ds_controls[] = { | ||
851 | { | ||
852 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
853 | .name = "Headphone Playback Volume", | ||
854 | .info = wm8776_hp_vol_info, | ||
855 | .get = wm8776_hp_vol_get, | ||
856 | .put = wm8776_hp_vol_put, | ||
857 | .tlv = { .p = wm8776_hp_db_scale }, | ||
858 | }, | ||
859 | WM8776_BIT_SWITCH("Headphone Playback Switch", | ||
860 | WM8776_PWRDOWN, WM8776_HPPD, 1, 0), | ||
861 | { | ||
862 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
863 | .name = "Input Capture Volume", | ||
864 | .info = wm8776_input_vol_info, | ||
865 | .get = wm8776_input_vol_get, | ||
866 | .put = wm8776_input_vol_put, | ||
867 | .tlv = { .p = wm8776_adc_db_scale }, | ||
868 | }, | ||
869 | { | ||
870 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
871 | .name = "Line Capture Switch", | ||
872 | .info = snd_ctl_boolean_mono_info, | ||
873 | .get = wm8776_input_mux_get, | ||
874 | .put = wm8776_input_mux_put, | ||
875 | .private_value = 1 << 0, | ||
876 | }, | ||
877 | { | ||
878 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
879 | .name = "Mic Capture Switch", | ||
880 | .info = snd_ctl_boolean_mono_info, | ||
881 | .get = wm8776_input_mux_get, | ||
882 | .put = wm8776_input_mux_put, | ||
883 | .private_value = 1 << 1, | ||
884 | }, | ||
885 | WM8776_BIT_SWITCH("Aux", WM8776_ADCMUX, 1 << 2, 0, 0), | ||
886 | { | ||
887 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
888 | .name = "ADC Filter Capture Enum", | ||
889 | .info = hpf_info, | ||
890 | .get = hpf_get, | ||
891 | .put = hpf_put, | ||
892 | }, | ||
893 | { | ||
894 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
895 | .name = "Level Control Capture Enum", | ||
896 | .info = wm8776_level_control_info, | ||
897 | .get = wm8776_level_control_get, | ||
898 | .put = wm8776_level_control_put, | ||
899 | .private_value = 0, | ||
900 | }, | ||
901 | }; | ||
902 | static const struct snd_kcontrol_new lc_controls[] = { | ||
903 | WM8776_FIELD_CTL_VOLUME("Limiter Threshold", | ||
904 | WM8776_ALCCTRL1, 0, 11, 0, 15, 0xf, | ||
905 | LC_CONTROL_LIMITER, wm8776_lct_db_scale), | ||
906 | WM8776_FIELD_CTL_ENUM("Limiter Attack Time", | ||
907 | WM8776_ALCCTRL3, 0, 2, 0, 10, 0xf, | ||
908 | LC_CONTROL_LIMITER), | ||
909 | WM8776_FIELD_CTL_ENUM("Limiter Decay Time", | ||
910 | WM8776_ALCCTRL3, 4, 3, 0, 10, 0xf, | ||
911 | LC_CONTROL_LIMITER), | ||
912 | WM8776_FIELD_CTL_ENUM("Limiter Transient Window", | ||
913 | WM8776_LIMITER, 4, 2, 0, 7, 0x7, | ||
914 | LC_CONTROL_LIMITER), | ||
915 | WM8776_FIELD_CTL_VOLUME("Limiter Maximum Attenuation", | ||
916 | WM8776_LIMITER, 0, 6, 3, 12, 0xf, | ||
917 | LC_CONTROL_LIMITER, | ||
918 | wm8776_maxatten_lim_db_scale), | ||
919 | WM8776_FIELD_CTL_VOLUME("ALC Target Level", | ||
920 | WM8776_ALCCTRL1, 0, 11, 0, 15, 0xf, | ||
921 | LC_CONTROL_ALC, wm8776_lct_db_scale), | ||
922 | WM8776_FIELD_CTL_ENUM("ALC Attack Time", | ||
923 | WM8776_ALCCTRL3, 0, 2, 0, 10, 0xf, | ||
924 | LC_CONTROL_ALC), | ||
925 | WM8776_FIELD_CTL_ENUM("ALC Decay Time", | ||
926 | WM8776_ALCCTRL3, 4, 3, 0, 10, 0xf, | ||
927 | LC_CONTROL_ALC), | ||
928 | WM8776_FIELD_CTL_VOLUME("ALC Maximum Gain", | ||
929 | WM8776_ALCCTRL1, 4, 7, 1, 7, 0x7, | ||
930 | LC_CONTROL_ALC, wm8776_maxgain_db_scale), | ||
931 | WM8776_FIELD_CTL_VOLUME("ALC Maximum Attenuation", | ||
932 | WM8776_LIMITER, 0, 10, 10, 15, 0xf, | ||
933 | LC_CONTROL_ALC, wm8776_maxatten_alc_db_scale), | ||
934 | WM8776_FIELD_CTL_ENUM("ALC Hold Time", | ||
935 | WM8776_ALCCTRL2, 0, 0, 0, 15, 0xf, | ||
936 | LC_CONTROL_ALC), | ||
937 | WM8776_BIT_SWITCH("Noise Gate Capture Switch", | ||
938 | WM8776_NOISEGATE, WM8776_NGAT, 0, | ||
939 | LC_CONTROL_ALC), | ||
940 | WM8776_FIELD_CTL_VOLUME("Noise Gate Threshold", | ||
941 | WM8776_NOISEGATE, 2, 0, 0, 7, 0x7, | ||
942 | LC_CONTROL_ALC, wm8776_ngth_db_scale), | ||
943 | }; | ||
944 | |||
945 | static int xonar_ds_control_filter(struct snd_kcontrol_new *template) | ||
946 | { | ||
947 | if (!strncmp(template->name, "CD Capture ", 11)) | ||
948 | return 1; /* no CD input */ | ||
949 | return 0; | ||
950 | } | ||
951 | |||
952 | static int xonar_ds_mixer_init(struct oxygen *chip) | ||
953 | { | ||
954 | struct xonar_wm87x6 *data = chip->model_data; | ||
955 | unsigned int i; | ||
956 | struct snd_kcontrol *ctl; | ||
957 | int err; | ||
958 | |||
959 | for (i = 0; i < ARRAY_SIZE(ds_controls); ++i) { | ||
960 | ctl = snd_ctl_new1(&ds_controls[i], chip); | ||
961 | if (!ctl) | ||
962 | return -ENOMEM; | ||
963 | err = snd_ctl_add(chip->card, ctl); | ||
964 | if (err < 0) | ||
965 | return err; | ||
966 | } | ||
967 | BUILD_BUG_ON(ARRAY_SIZE(lc_controls) != ARRAY_SIZE(data->lc_controls)); | ||
968 | for (i = 0; i < ARRAY_SIZE(lc_controls); ++i) { | ||
969 | ctl = snd_ctl_new1(&lc_controls[i], chip); | ||
970 | if (!ctl) | ||
971 | return -ENOMEM; | ||
972 | err = snd_ctl_add(chip->card, ctl); | ||
973 | if (err < 0) | ||
974 | return err; | ||
975 | data->lc_controls[i] = ctl; | ||
976 | } | ||
977 | return 0; | ||
978 | } | ||
979 | |||
980 | static const struct oxygen_model model_xonar_ds = { | ||
981 | .shortname = "Xonar DS", | ||
982 | .longname = "Asus Virtuoso 200", | ||
983 | .chip = "AV200", | ||
984 | .init = xonar_ds_init, | ||
985 | .control_filter = xonar_ds_control_filter, | ||
986 | .mixer_init = xonar_ds_mixer_init, | ||
987 | .cleanup = xonar_ds_cleanup, | ||
988 | .suspend = xonar_ds_suspend, | ||
989 | .resume = xonar_ds_resume, | ||
990 | .pcm_hardware_filter = wm8776_adc_hardware_filter, | ||
991 | .get_i2s_mclk = oxygen_default_i2s_mclk, | ||
992 | .set_dac_params = set_wm87x6_dac_params, | ||
993 | .set_adc_params = set_wm8776_adc_params, | ||
994 | .update_dac_volume = update_wm87x6_volume, | ||
995 | .update_dac_mute = update_wm87x6_mute, | ||
996 | .gpio_changed = xonar_ds_gpio_changed, | ||
997 | .dac_tlv = wm87x6_dac_db_scale, | ||
998 | .model_data_size = sizeof(struct xonar_wm87x6), | ||
999 | .device_config = PLAYBACK_0_TO_I2S | | ||
1000 | PLAYBACK_1_TO_SPDIF | | ||
1001 | CAPTURE_0_FROM_I2S_1, | ||
1002 | .dac_channels = 8, | ||
1003 | .dac_volume_min = 255 - 2*60, | ||
1004 | .dac_volume_max = 255, | ||
1005 | .function_flags = OXYGEN_FUNCTION_SPI, | ||
1006 | .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | ||
1007 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | ||
1008 | }; | ||
1009 | |||
1010 | int __devinit get_xonar_wm87x6_model(struct oxygen *chip, | ||
1011 | const struct pci_device_id *id) | ||
1012 | { | ||
1013 | switch (id->subdevice) { | ||
1014 | case 0x838e: | ||
1015 | chip->model = model_xonar_ds; | ||
1016 | break; | ||
1017 | default: | ||
1018 | return -EINVAL; | ||
1019 | } | ||
1020 | return 0; | ||
1021 | } | ||
diff --git a/sound/pci/pcxhr/pcxhr.c b/sound/pci/pcxhr/pcxhr.c index 833e9c7b27c7..95cfde27d25c 100644 --- a/sound/pci/pcxhr/pcxhr.c +++ b/sound/pci/pcxhr/pcxhr.c | |||
@@ -94,7 +94,7 @@ enum { | |||
94 | PCI_ID_LAST | 94 | PCI_ID_LAST |
95 | }; | 95 | }; |
96 | 96 | ||
97 | static struct pci_device_id pcxhr_ids[] = { | 97 | static DEFINE_PCI_DEVICE_TABLE(pcxhr_ids) = { |
98 | { 0x10b5, 0x9656, 0x1369, 0xb001, 0, 0, PCI_ID_VX882HR, }, | 98 | { 0x10b5, 0x9656, 0x1369, 0xb001, 0, 0, PCI_ID_VX882HR, }, |
99 | { 0x10b5, 0x9656, 0x1369, 0xb101, 0, 0, PCI_ID_PCX882HR, }, | 99 | { 0x10b5, 0x9656, 0x1369, 0xb101, 0, 0, PCI_ID_PCX882HR, }, |
100 | { 0x10b5, 0x9656, 0x1369, 0xb201, 0, 0, PCI_ID_VX881HR, }, | 100 | { 0x10b5, 0x9656, 0x1369, 0xb201, 0, 0, PCI_ID_VX881HR, }, |
diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c index e66ef2b69b5d..960a227eb653 100644 --- a/sound/pci/riptide/riptide.c +++ b/sound/pci/riptide/riptide.c | |||
@@ -506,7 +506,7 @@ static int riptide_reset(struct cmdif *cif, struct snd_riptide *chip); | |||
506 | /* | 506 | /* |
507 | */ | 507 | */ |
508 | 508 | ||
509 | static struct pci_device_id snd_riptide_ids[] = { | 509 | static DEFINE_PCI_DEVICE_TABLE(snd_riptide_ids) = { |
510 | { PCI_DEVICE(0x127a, 0x4310) }, | 510 | { PCI_DEVICE(0x127a, 0x4310) }, |
511 | { PCI_DEVICE(0x127a, 0x4320) }, | 511 | { PCI_DEVICE(0x127a, 0x4320) }, |
512 | { PCI_DEVICE(0x127a, 0x4330) }, | 512 | { PCI_DEVICE(0x127a, 0x4330) }, |
@@ -515,7 +515,7 @@ static struct pci_device_id snd_riptide_ids[] = { | |||
515 | }; | 515 | }; |
516 | 516 | ||
517 | #ifdef SUPPORT_JOYSTICK | 517 | #ifdef SUPPORT_JOYSTICK |
518 | static struct pci_device_id snd_riptide_joystick_ids[] __devinitdata = { | 518 | static DEFINE_PCI_DEVICE_TABLE(snd_riptide_joystick_ids) = { |
519 | { PCI_DEVICE(0x127a, 0x4312) }, | 519 | { PCI_DEVICE(0x127a, 0x4312) }, |
520 | { PCI_DEVICE(0x127a, 0x4322) }, | 520 | { PCI_DEVICE(0x127a, 0x4322) }, |
521 | { PCI_DEVICE(0x127a, 0x4332) }, | 521 | { PCI_DEVICE(0x127a, 0x4332) }, |
diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c index f977dba7cbd0..d5e1c6eb7b7b 100644 --- a/sound/pci/rme32.c +++ b/sound/pci/rme32.c | |||
@@ -226,7 +226,7 @@ struct rme32 { | |||
226 | struct snd_kcontrol *spdif_ctl; | 226 | struct snd_kcontrol *spdif_ctl; |
227 | }; | 227 | }; |
228 | 228 | ||
229 | static struct pci_device_id snd_rme32_ids[] = { | 229 | static DEFINE_PCI_DEVICE_TABLE(snd_rme32_ids) = { |
230 | {PCI_VDEVICE(XILINX_RME, PCI_DEVICE_ID_RME_DIGI32), 0,}, | 230 | {PCI_VDEVICE(XILINX_RME, PCI_DEVICE_ID_RME_DIGI32), 0,}, |
231 | {PCI_VDEVICE(XILINX_RME, PCI_DEVICE_ID_RME_DIGI32_8), 0,}, | 231 | {PCI_VDEVICE(XILINX_RME, PCI_DEVICE_ID_RME_DIGI32_8), 0,}, |
232 | {PCI_VDEVICE(XILINX_RME, PCI_DEVICE_ID_RME_DIGI32_PRO), 0,}, | 232 | {PCI_VDEVICE(XILINX_RME, PCI_DEVICE_ID_RME_DIGI32_PRO), 0,}, |
diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c index 2ba5c0fd55db..9d5252bc870c 100644 --- a/sound/pci/rme96.c +++ b/sound/pci/rme96.c | |||
@@ -231,7 +231,7 @@ struct rme96 { | |||
231 | struct snd_kcontrol *spdif_ctl; | 231 | struct snd_kcontrol *spdif_ctl; |
232 | }; | 232 | }; |
233 | 233 | ||
234 | static struct pci_device_id snd_rme96_ids[] = { | 234 | static DEFINE_PCI_DEVICE_TABLE(snd_rme96_ids) = { |
235 | { PCI_VDEVICE(XILINX, PCI_DEVICE_ID_RME_DIGI96), 0, }, | 235 | { PCI_VDEVICE(XILINX, PCI_DEVICE_ID_RME_DIGI96), 0, }, |
236 | { PCI_VDEVICE(XILINX, PCI_DEVICE_ID_RME_DIGI96_8), 0, }, | 236 | { PCI_VDEVICE(XILINX, PCI_DEVICE_ID_RME_DIGI96_8), 0, }, |
237 | { PCI_VDEVICE(XILINX, PCI_DEVICE_ID_RME_DIGI96_8_PRO), 0, }, | 237 | { PCI_VDEVICE(XILINX, PCI_DEVICE_ID_RME_DIGI96_8_PRO), 0, }, |
diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index 7bb827c7d806..52c6eb57cc3f 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c | |||
@@ -585,7 +585,7 @@ static void snd_hammerfall_free_buffer(struct snd_dma_buffer *dmab, struct pci_d | |||
585 | } | 585 | } |
586 | 586 | ||
587 | 587 | ||
588 | static struct pci_device_id snd_hdsp_ids[] = { | 588 | static DEFINE_PCI_DEVICE_TABLE(snd_hdsp_ids) = { |
589 | { | 589 | { |
590 | .vendor = PCI_VENDOR_ID_XILINX, | 590 | .vendor = PCI_VENDOR_ID_XILINX, |
591 | .device = PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP, | 591 | .device = PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP, |
diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index db0ed1cbd982..547b713d7204 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c | |||
@@ -512,7 +512,7 @@ static char channel_map_madi_ss[HDSPM_MAX_CHANNELS] = { | |||
512 | }; | 512 | }; |
513 | 513 | ||
514 | 514 | ||
515 | static struct pci_device_id snd_hdspm_ids[] __devinitdata = { | 515 | static DEFINE_PCI_DEVICE_TABLE(snd_hdspm_ids) = { |
516 | { | 516 | { |
517 | .vendor = PCI_VENDOR_ID_XILINX, | 517 | .vendor = PCI_VENDOR_ID_XILINX, |
518 | .device = PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP_MADI, | 518 | .device = PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP_MADI, |
diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c index bc539abb2105..44a3e2d8c556 100644 --- a/sound/pci/rme9652/rme9652.c +++ b/sound/pci/rme9652/rme9652.c | |||
@@ -314,7 +314,7 @@ static void snd_hammerfall_free_buffer(struct snd_dma_buffer *dmab, struct pci_d | |||
314 | } | 314 | } |
315 | 315 | ||
316 | 316 | ||
317 | static struct pci_device_id snd_rme9652_ids[] = { | 317 | static DEFINE_PCI_DEVICE_TABLE(snd_rme9652_ids) = { |
318 | { | 318 | { |
319 | .vendor = 0x10ee, | 319 | .vendor = 0x10ee, |
320 | .device = 0x3fc4, | 320 | .device = 0x3fc4, |
diff --git a/sound/pci/sis7019.c b/sound/pci/sis7019.c index 1a5ff0611072..7e3e8fbc90fe 100644 --- a/sound/pci/sis7019.c +++ b/sound/pci/sis7019.c | |||
@@ -48,7 +48,7 @@ MODULE_PARM_DESC(id, "ID string for SiS7019 Audio Accelerator."); | |||
48 | module_param(enable, bool, 0444); | 48 | module_param(enable, bool, 0444); |
49 | MODULE_PARM_DESC(enable, "Enable SiS7019 Audio Accelerator."); | 49 | MODULE_PARM_DESC(enable, "Enable SiS7019 Audio Accelerator."); |
50 | 50 | ||
51 | static struct pci_device_id snd_sis7019_ids[] = { | 51 | static DEFINE_PCI_DEVICE_TABLE(snd_sis7019_ids) = { |
52 | { PCI_DEVICE(PCI_VENDOR_ID_SI, 0x7019) }, | 52 | { PCI_DEVICE(PCI_VENDOR_ID_SI, 0x7019) }, |
53 | { 0, } | 53 | { 0, } |
54 | }; | 54 | }; |
diff --git a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c index 1f6406c4534d..337b9facadfd 100644 --- a/sound/pci/sonicvibes.c +++ b/sound/pci/sonicvibes.c | |||
@@ -242,7 +242,7 @@ struct sonicvibes { | |||
242 | #endif | 242 | #endif |
243 | }; | 243 | }; |
244 | 244 | ||
245 | static struct pci_device_id snd_sonic_ids[] = { | 245 | static DEFINE_PCI_DEVICE_TABLE(snd_sonic_ids) = { |
246 | { PCI_VDEVICE(S3, 0xca00), 0, }, | 246 | { PCI_VDEVICE(S3, 0xca00), 0, }, |
247 | { 0, } | 247 | { 0, } |
248 | }; | 248 | }; |
diff --git a/sound/pci/trident/trident.c b/sound/pci/trident/trident.c index 21cef97d478d..6d0581841d7a 100644 --- a/sound/pci/trident/trident.c +++ b/sound/pci/trident/trident.c | |||
@@ -62,7 +62,7 @@ MODULE_PARM_DESC(pcm_channels, "Number of hardware channels assigned for PCM."); | |||
62 | module_param_array(wavetable_size, int, NULL, 0444); | 62 | module_param_array(wavetable_size, int, NULL, 0444); |
63 | MODULE_PARM_DESC(wavetable_size, "Maximum memory size in kB for wavetable synth."); | 63 | MODULE_PARM_DESC(wavetable_size, "Maximum memory size in kB for wavetable synth."); |
64 | 64 | ||
65 | static struct pci_device_id snd_trident_ids[] = { | 65 | static DEFINE_PCI_DEVICE_TABLE(snd_trident_ids) = { |
66 | {PCI_DEVICE(PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_DX), | 66 | {PCI_DEVICE(PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_DX), |
67 | PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0}, | 67 | PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0}, |
68 | {PCI_DEVICE(PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_NX), | 68 | {PCI_DEVICE(PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_NX), |
diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index 8a332d2f615c..7e494b6a1d0e 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c | |||
@@ -401,7 +401,7 @@ struct via82xx { | |||
401 | #endif | 401 | #endif |
402 | }; | 402 | }; |
403 | 403 | ||
404 | static struct pci_device_id snd_via82xx_ids[] = { | 404 | static DEFINE_PCI_DEVICE_TABLE(snd_via82xx_ids) = { |
405 | /* 0x1106, 0x3058 */ | 405 | /* 0x1106, 0x3058 */ |
406 | { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_82C686_5), TYPE_CARD_VIA686, }, /* 686A */ | 406 | { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_82C686_5), TYPE_CARD_VIA686, }, /* 686A */ |
407 | /* 0x1106, 0x3059 */ | 407 | /* 0x1106, 0x3059 */ |
@@ -1791,6 +1791,12 @@ static struct ac97_quirk ac97_quirks[] = { | |||
1791 | .type = AC97_TUNE_HP_ONLY | 1791 | .type = AC97_TUNE_HP_ONLY |
1792 | }, | 1792 | }, |
1793 | { | 1793 | { |
1794 | .subvendor = 0x110a, | ||
1795 | .subdevice = 0x0079, | ||
1796 | .name = "Fujitsu Siemens D1289", | ||
1797 | .type = AC97_TUNE_HP_ONLY | ||
1798 | }, | ||
1799 | { | ||
1794 | .subvendor = 0x1019, | 1800 | .subvendor = 0x1019, |
1795 | .subdevice = 0x0a81, | 1801 | .subdevice = 0x0a81, |
1796 | .name = "ECS K7VTA3", | 1802 | .name = "ECS K7VTA3", |
diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c index 47eb61561dfc..f7e8bbbe3953 100644 --- a/sound/pci/via82xx_modem.c +++ b/sound/pci/via82xx_modem.c | |||
@@ -260,7 +260,7 @@ struct via82xx_modem { | |||
260 | struct snd_info_entry *proc_entry; | 260 | struct snd_info_entry *proc_entry; |
261 | }; | 261 | }; |
262 | 262 | ||
263 | static struct pci_device_id snd_via82xx_modem_ids[] = { | 263 | static DEFINE_PCI_DEVICE_TABLE(snd_via82xx_modem_ids) = { |
264 | { PCI_VDEVICE(VIA, 0x3068), TYPE_CARD_VIA82XX_MODEM, }, | 264 | { PCI_VDEVICE(VIA, 0x3068), TYPE_CARD_VIA82XX_MODEM, }, |
265 | { 0, } | 265 | { 0, } |
266 | }; | 266 | }; |
diff --git a/sound/pci/vx222/vx222.c b/sound/pci/vx222/vx222.c index fc9136c3e0d7..99a9a814be0b 100644 --- a/sound/pci/vx222/vx222.c +++ b/sound/pci/vx222/vx222.c | |||
@@ -60,7 +60,7 @@ enum { | |||
60 | VX_PCI_VX222_NEW | 60 | VX_PCI_VX222_NEW |
61 | }; | 61 | }; |
62 | 62 | ||
63 | static struct pci_device_id snd_vx222_ids[] = { | 63 | static DEFINE_PCI_DEVICE_TABLE(snd_vx222_ids) = { |
64 | { 0x10b5, 0x9050, 0x1369, PCI_ANY_ID, 0, 0, VX_PCI_VX222_OLD, }, /* PLX */ | 64 | { 0x10b5, 0x9050, 0x1369, PCI_ANY_ID, 0, 0, VX_PCI_VX222_OLD, }, /* PLX */ |
65 | { 0x10b5, 0x9030, 0x1369, PCI_ANY_ID, 0, 0, VX_PCI_VX222_NEW, }, /* PLX */ | 65 | { 0x10b5, 0x9030, 0x1369, PCI_ANY_ID, 0, 0, VX_PCI_VX222_NEW, }, /* PLX */ |
66 | { 0, } | 66 | { 0, } |
diff --git a/sound/pci/ymfpci/ymfpci.c b/sound/pci/ymfpci/ymfpci.c index e6b18b90d451..80c682113381 100644 --- a/sound/pci/ymfpci/ymfpci.c +++ b/sound/pci/ymfpci/ymfpci.c | |||
@@ -66,7 +66,7 @@ MODULE_PARM_DESC(joystick_port, "Joystick port address"); | |||
66 | module_param_array(rear_switch, bool, NULL, 0444); | 66 | module_param_array(rear_switch, bool, NULL, 0444); |
67 | MODULE_PARM_DESC(rear_switch, "Enable shared rear/line-in switch"); | 67 | MODULE_PARM_DESC(rear_switch, "Enable shared rear/line-in switch"); |
68 | 68 | ||
69 | static struct pci_device_id snd_ymfpci_ids[] = { | 69 | static DEFINE_PCI_DEVICE_TABLE(snd_ymfpci_ids) = { |
70 | { PCI_VDEVICE(YAMAHA, 0x0004), 0, }, /* YMF724 */ | 70 | { PCI_VDEVICE(YAMAHA, 0x0004), 0, }, /* YMF724 */ |
71 | { PCI_VDEVICE(YAMAHA, 0x000d), 0, }, /* YMF724F */ | 71 | { PCI_VDEVICE(YAMAHA, 0x000d), 0, }, /* YMF724F */ |
72 | { PCI_VDEVICE(YAMAHA, 0x000a), 0, }, /* YMF740 */ | 72 | { PCI_VDEVICE(YAMAHA, 0x000a), 0, }, /* YMF740 */ |
diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c b/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c index 5cfa608823f7..0d668f471620 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c | |||
@@ -21,7 +21,6 @@ | |||
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
24 | #include <linux/vmalloc.h> | ||
25 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
26 | #include <sound/core.h> | 25 | #include <sound/core.h> |
27 | #include <sound/asoundef.h> | 26 | #include <sound/asoundef.h> |
@@ -29,49 +28,6 @@ | |||
29 | 28 | ||
30 | 29 | ||
31 | /* | 30 | /* |
32 | * we use a vmalloc'ed (sg-)buffer | ||
33 | */ | ||
34 | |||
35 | /* get the physical page pointer on the given offset */ | ||
36 | static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs, unsigned long offset) | ||
37 | { | ||
38 | void *pageptr = subs->runtime->dma_area + offset; | ||
39 | return vmalloc_to_page(pageptr); | ||
40 | } | ||
41 | |||
42 | /* | ||
43 | * hw_params callback | ||
44 | * NOTE: this may be called not only once per pcm open! | ||
45 | */ | ||
46 | static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, size_t size) | ||
47 | { | ||
48 | struct snd_pcm_runtime *runtime = subs->runtime; | ||
49 | if (runtime->dma_area) { | ||
50 | if (runtime->dma_bytes >= size) | ||
51 | return 0; /* already enough large */ | ||
52 | vfree(runtime->dma_area); | ||
53 | } | ||
54 | runtime->dma_area = vmalloc_32_user(size); | ||
55 | if (! runtime->dma_area) | ||
56 | return -ENOMEM; | ||
57 | runtime->dma_bytes = size; | ||
58 | return 0; | ||
59 | } | ||
60 | |||
61 | /* | ||
62 | * hw_free callback | ||
63 | * NOTE: this may be called not only once per pcm open! | ||
64 | */ | ||
65 | static int snd_pcm_free_vmalloc_buffer(struct snd_pcm_substream *subs) | ||
66 | { | ||
67 | struct snd_pcm_runtime *runtime = subs->runtime; | ||
68 | |||
69 | vfree(runtime->dma_area); | ||
70 | runtime->dma_area = NULL; | ||
71 | return 0; | ||
72 | } | ||
73 | |||
74 | /* | ||
75 | * clear the SRAM contents | 31 | * clear the SRAM contents |
76 | */ | 32 | */ |
77 | static int pdacf_pcm_clear_sram(struct snd_pdacf *chip) | 33 | static int pdacf_pcm_clear_sram(struct snd_pdacf *chip) |
@@ -147,7 +103,8 @@ static int pdacf_pcm_trigger(struct snd_pcm_substream *subs, int cmd) | |||
147 | static int pdacf_pcm_hw_params(struct snd_pcm_substream *subs, | 103 | static int pdacf_pcm_hw_params(struct snd_pcm_substream *subs, |
148 | struct snd_pcm_hw_params *hw_params) | 104 | struct snd_pcm_hw_params *hw_params) |
149 | { | 105 | { |
150 | return snd_pcm_alloc_vmalloc_buffer(subs, params_buffer_bytes(hw_params)); | 106 | return snd_pcm_lib_alloc_vmalloc_32_buffer |
107 | (subs, params_buffer_bytes(hw_params)); | ||
151 | } | 108 | } |
152 | 109 | ||
153 | /* | 110 | /* |
@@ -155,7 +112,7 @@ static int pdacf_pcm_hw_params(struct snd_pcm_substream *subs, | |||
155 | */ | 112 | */ |
156 | static int pdacf_pcm_hw_free(struct snd_pcm_substream *subs) | 113 | static int pdacf_pcm_hw_free(struct snd_pcm_substream *subs) |
157 | { | 114 | { |
158 | return snd_pcm_free_vmalloc_buffer(subs); | 115 | return snd_pcm_lib_free_vmalloc_buffer(subs); |
159 | } | 116 | } |
160 | 117 | ||
161 | /* | 118 | /* |
@@ -319,7 +276,8 @@ static struct snd_pcm_ops pdacf_pcm_capture_ops = { | |||
319 | .prepare = pdacf_pcm_prepare, | 276 | .prepare = pdacf_pcm_prepare, |
320 | .trigger = pdacf_pcm_trigger, | 277 | .trigger = pdacf_pcm_trigger, |
321 | .pointer = pdacf_pcm_capture_pointer, | 278 | .pointer = pdacf_pcm_capture_pointer, |
322 | .page = snd_pcm_get_vmalloc_page, | 279 | .page = snd_pcm_lib_get_vmalloc_page, |
280 | .mmap = snd_pcm_lib_mmap_vmalloc, | ||
323 | }; | 281 | }; |
324 | 282 | ||
325 | 283 | ||
diff --git a/sound/ppc/awacs.c b/sound/ppc/awacs.c index 2e156467b814..b36679384b27 100644 --- a/sound/ppc/awacs.c +++ b/sound/ppc/awacs.c | |||
@@ -751,8 +751,8 @@ static void snd_pmac_awacs_suspend(struct snd_pmac *chip) | |||
751 | 751 | ||
752 | static void snd_pmac_awacs_resume(struct snd_pmac *chip) | 752 | static void snd_pmac_awacs_resume(struct snd_pmac *chip) |
753 | { | 753 | { |
754 | if (machine_is_compatible("PowerBook3,1") | 754 | if (of_machine_is_compatible("PowerBook3,1") |
755 | || machine_is_compatible("PowerBook3,2")) { | 755 | || of_machine_is_compatible("PowerBook3,2")) { |
756 | msleep(100); | 756 | msleep(100); |
757 | snd_pmac_awacs_write_reg(chip, 1, | 757 | snd_pmac_awacs_write_reg(chip, 1, |
758 | chip->awacs_reg[1] & ~MASK_PAROUT); | 758 | chip->awacs_reg[1] & ~MASK_PAROUT); |
@@ -780,16 +780,16 @@ static void snd_pmac_awacs_resume(struct snd_pmac *chip) | |||
780 | } | 780 | } |
781 | #endif /* CONFIG_PM */ | 781 | #endif /* CONFIG_PM */ |
782 | 782 | ||
783 | #define IS_PM7500 (machine_is_compatible("AAPL,7500") \ | 783 | #define IS_PM7500 (of_machine_is_compatible("AAPL,7500") \ |
784 | || machine_is_compatible("AAPL,8500") \ | 784 | || of_machine_is_compatible("AAPL,8500") \ |
785 | || machine_is_compatible("AAPL,9500")) | 785 | || of_machine_is_compatible("AAPL,9500")) |
786 | #define IS_PM5500 (machine_is_compatible("AAPL,e411")) | 786 | #define IS_PM5500 (of_machine_is_compatible("AAPL,e411")) |
787 | #define IS_BEIGE (machine_is_compatible("AAPL,Gossamer")) | 787 | #define IS_BEIGE (of_machine_is_compatible("AAPL,Gossamer")) |
788 | #define IS_IMAC1 (machine_is_compatible("PowerMac2,1")) | 788 | #define IS_IMAC1 (of_machine_is_compatible("PowerMac2,1")) |
789 | #define IS_IMAC2 (machine_is_compatible("PowerMac2,2") \ | 789 | #define IS_IMAC2 (of_machine_is_compatible("PowerMac2,2") \ |
790 | || machine_is_compatible("PowerMac4,1")) | 790 | || of_machine_is_compatible("PowerMac4,1")) |
791 | #define IS_G4AGP (machine_is_compatible("PowerMac3,1")) | 791 | #define IS_G4AGP (of_machine_is_compatible("PowerMac3,1")) |
792 | #define IS_LOMBARD (machine_is_compatible("PowerBook1,1")) | 792 | #define IS_LOMBARD (of_machine_is_compatible("PowerBook1,1")) |
793 | 793 | ||
794 | static int imac1, imac2; | 794 | static int imac1, imac2; |
795 | 795 | ||
diff --git a/sound/ppc/burgundy.c b/sound/ppc/burgundy.c index 0accfe49735b..1f72e1c786bf 100644 --- a/sound/ppc/burgundy.c +++ b/sound/ppc/burgundy.c | |||
@@ -582,7 +582,7 @@ static int snd_pmac_burgundy_detect_headphone(struct snd_pmac *chip) | |||
582 | static void snd_pmac_burgundy_update_automute(struct snd_pmac *chip, int do_notify) | 582 | static void snd_pmac_burgundy_update_automute(struct snd_pmac *chip, int do_notify) |
583 | { | 583 | { |
584 | if (chip->auto_mute) { | 584 | if (chip->auto_mute) { |
585 | int imac = machine_is_compatible("iMac"); | 585 | int imac = of_machine_is_compatible("iMac"); |
586 | int reg, oreg; | 586 | int reg, oreg; |
587 | reg = oreg = snd_pmac_burgundy_rcb(chip, | 587 | reg = oreg = snd_pmac_burgundy_rcb(chip, |
588 | MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES); | 588 | MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES); |
@@ -620,7 +620,7 @@ static void snd_pmac_burgundy_update_automute(struct snd_pmac *chip, int do_noti | |||
620 | */ | 620 | */ |
621 | int __devinit snd_pmac_burgundy_init(struct snd_pmac *chip) | 621 | int __devinit snd_pmac_burgundy_init(struct snd_pmac *chip) |
622 | { | 622 | { |
623 | int imac = machine_is_compatible("iMac"); | 623 | int imac = of_machine_is_compatible("iMac"); |
624 | int i, err; | 624 | int i, err; |
625 | 625 | ||
626 | /* Checks to see the chip is alive and kicking */ | 626 | /* Checks to see the chip is alive and kicking */ |
diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c index 7bc492ee77ec..85081172403f 100644 --- a/sound/ppc/pmac.c +++ b/sound/ppc/pmac.c | |||
@@ -922,11 +922,11 @@ static void __devinit detect_byte_swap(struct snd_pmac *chip) | |||
922 | } | 922 | } |
923 | 923 | ||
924 | /* it seems the Pismo & iBook can't byte-swap in hardware. */ | 924 | /* it seems the Pismo & iBook can't byte-swap in hardware. */ |
925 | if (machine_is_compatible("PowerBook3,1") || | 925 | if (of_machine_is_compatible("PowerBook3,1") || |
926 | machine_is_compatible("PowerBook2,1")) | 926 | of_machine_is_compatible("PowerBook2,1")) |
927 | chip->can_byte_swap = 0 ; | 927 | chip->can_byte_swap = 0 ; |
928 | 928 | ||
929 | if (machine_is_compatible("PowerBook2,1")) | 929 | if (of_machine_is_compatible("PowerBook2,1")) |
930 | chip->can_duplex = 0; | 930 | chip->can_duplex = 0; |
931 | } | 931 | } |
932 | 932 | ||
@@ -959,11 +959,11 @@ static int __devinit snd_pmac_detect(struct snd_pmac *chip) | |||
959 | chip->control_mask = MASK_IEPC | MASK_IEE | 0x11; /* default */ | 959 | chip->control_mask = MASK_IEPC | MASK_IEE | 0x11; /* default */ |
960 | 960 | ||
961 | /* check machine type */ | 961 | /* check machine type */ |
962 | if (machine_is_compatible("AAPL,3400/2400") | 962 | if (of_machine_is_compatible("AAPL,3400/2400") |
963 | || machine_is_compatible("AAPL,3500")) | 963 | || of_machine_is_compatible("AAPL,3500")) |
964 | chip->is_pbook_3400 = 1; | 964 | chip->is_pbook_3400 = 1; |
965 | else if (machine_is_compatible("PowerBook1,1") | 965 | else if (of_machine_is_compatible("PowerBook1,1") |
966 | || machine_is_compatible("AAPL,PowerBook1998")) | 966 | || of_machine_is_compatible("AAPL,PowerBook1998")) |
967 | chip->is_pbook_G3 = 1; | 967 | chip->is_pbook_G3 = 1; |
968 | chip->node = of_find_node_by_name(NULL, "awacs"); | 968 | chip->node = of_find_node_by_name(NULL, "awacs"); |
969 | sound = of_node_get(chip->node); | 969 | sound = of_node_get(chip->node); |
@@ -1033,8 +1033,8 @@ static int __devinit snd_pmac_detect(struct snd_pmac *chip) | |||
1033 | } | 1033 | } |
1034 | if (of_device_is_compatible(sound, "tumbler")) { | 1034 | if (of_device_is_compatible(sound, "tumbler")) { |
1035 | chip->model = PMAC_TUMBLER; | 1035 | chip->model = PMAC_TUMBLER; |
1036 | chip->can_capture = machine_is_compatible("PowerMac4,2") | 1036 | chip->can_capture = of_machine_is_compatible("PowerMac4,2") |
1037 | || machine_is_compatible("PowerBook4,1"); | 1037 | || of_machine_is_compatible("PowerBook4,1"); |
1038 | chip->can_duplex = 0; | 1038 | chip->can_duplex = 0; |
1039 | // chip->can_byte_swap = 0; /* FIXME: check this */ | 1039 | // chip->can_byte_swap = 0; /* FIXME: check this */ |
1040 | chip->num_freqs = ARRAY_SIZE(tumbler_freqs); | 1040 | chip->num_freqs = ARRAY_SIZE(tumbler_freqs); |
diff --git a/sound/soc/au1x/Kconfig b/sound/soc/au1x/Kconfig index 410a893aa66b..4b67140fdec3 100644 --- a/sound/soc/au1x/Kconfig +++ b/sound/soc/au1x/Kconfig | |||
@@ -22,11 +22,13 @@ config SND_SOC_AU1XPSC_AC97 | |||
22 | ## | 22 | ## |
23 | ## Boards | 23 | ## Boards |
24 | ## | 24 | ## |
25 | config SND_SOC_SAMPLE_PSC_AC97 | 25 | config SND_SOC_DB1200 |
26 | tristate "Sample Au12x0/Au1550 PSC AC97 sound machine" | 26 | tristate "DB1200 AC97+I2S audio support" |
27 | depends on SND_SOC_AU1XPSC | 27 | depends on SND_SOC_AU1XPSC |
28 | select SND_SOC_AU1XPSC_AC97 | 28 | select SND_SOC_AU1XPSC_AC97 |
29 | select SND_SOC_AC97_CODEC | 29 | select SND_SOC_AC97_CODEC |
30 | select SND_SOC_AU1XPSC_I2S | ||
31 | select SND_SOC_WM8731 | ||
30 | help | 32 | help |
31 | This is a sample AC97 sound machine for use in Au12x0/Au1550 | 33 | Select this option to enable audio (AC97 or I2S) on the |
32 | based systems which have audio on PSC1 (e.g. Db1200 demoboard). | 34 | Alchemy/AMD/RMI DB1200 demoboard. |
diff --git a/sound/soc/au1x/Makefile b/sound/soc/au1x/Makefile index 6c6950b8003a..16873076e8c4 100644 --- a/sound/soc/au1x/Makefile +++ b/sound/soc/au1x/Makefile | |||
@@ -8,6 +8,6 @@ obj-$(CONFIG_SND_SOC_AU1XPSC_I2S) += snd-soc-au1xpsc-i2s.o | |||
8 | obj-$(CONFIG_SND_SOC_AU1XPSC_AC97) += snd-soc-au1xpsc-ac97.o | 8 | obj-$(CONFIG_SND_SOC_AU1XPSC_AC97) += snd-soc-au1xpsc-ac97.o |
9 | 9 | ||
10 | # Boards | 10 | # Boards |
11 | snd-soc-sample-ac97-objs := sample-ac97.o | 11 | snd-soc-db1200-objs := db1200.o |
12 | 12 | ||
13 | obj-$(CONFIG_SND_SOC_SAMPLE_PSC_AC97) += snd-soc-sample-ac97.o | 13 | obj-$(CONFIG_SND_SOC_DB1200) += snd-soc-db1200.o |
diff --git a/sound/soc/au1x/db1200.c b/sound/soc/au1x/db1200.c new file mode 100644 index 000000000000..cdf7be1b9b91 --- /dev/null +++ b/sound/soc/au1x/db1200.c | |||
@@ -0,0 +1,141 @@ | |||
1 | /* | ||
2 | * DB1200 ASoC audio fabric support code. | ||
3 | * | ||
4 | * (c) 2008-9 Manuel Lauss <manuel.lauss@gmail.com> | ||
5 | * | ||
6 | */ | ||
7 | |||
8 | #include <linux/module.h> | ||
9 | #include <linux/moduleparam.h> | ||
10 | #include <linux/timer.h> | ||
11 | #include <linux/interrupt.h> | ||
12 | #include <linux/platform_device.h> | ||
13 | #include <sound/core.h> | ||
14 | #include <sound/pcm.h> | ||
15 | #include <sound/soc.h> | ||
16 | #include <sound/soc-dapm.h> | ||
17 | #include <asm/mach-au1x00/au1000.h> | ||
18 | #include <asm/mach-au1x00/au1xxx_psc.h> | ||
19 | #include <asm/mach-au1x00/au1xxx_dbdma.h> | ||
20 | #include <asm/mach-db1x00/bcsr.h> | ||
21 | |||
22 | #include "../codecs/ac97.h" | ||
23 | #include "../codecs/wm8731.h" | ||
24 | #include "psc.h" | ||
25 | |||
26 | /*------------------------- AC97 PART ---------------------------*/ | ||
27 | |||
28 | static struct snd_soc_dai_link db1200_ac97_dai = { | ||
29 | .name = "AC97", | ||
30 | .stream_name = "AC97 HiFi", | ||
31 | .cpu_dai = &au1xpsc_ac97_dai, | ||
32 | .codec_dai = &ac97_dai, | ||
33 | }; | ||
34 | |||
35 | static struct snd_soc_card db1200_ac97_machine = { | ||
36 | .name = "DB1200_AC97", | ||
37 | .dai_link = &db1200_ac97_dai, | ||
38 | .num_links = 1, | ||
39 | .platform = &au1xpsc_soc_platform, | ||
40 | }; | ||
41 | |||
42 | static struct snd_soc_device db1200_ac97_devdata = { | ||
43 | .card = &db1200_ac97_machine, | ||
44 | .codec_dev = &soc_codec_dev_ac97, | ||
45 | }; | ||
46 | |||
47 | /*------------------------- I2S PART ---------------------------*/ | ||
48 | |||
49 | static int db1200_i2s_startup(struct snd_pcm_substream *substream) | ||
50 | { | ||
51 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
52 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; | ||
53 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | ||
54 | int ret; | ||
55 | |||
56 | /* WM8731 has its own 12MHz crystal */ | ||
57 | snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK, | ||
58 | 12000000, SND_SOC_CLOCK_IN); | ||
59 | |||
60 | /* codec is bitclock and lrclk master */ | ||
61 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_LEFT_J | | ||
62 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); | ||
63 | if (ret < 0) | ||
64 | goto out; | ||
65 | |||
66 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_LEFT_J | | ||
67 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); | ||
68 | if (ret < 0) | ||
69 | goto out; | ||
70 | |||
71 | ret = 0; | ||
72 | out: | ||
73 | return ret; | ||
74 | } | ||
75 | |||
76 | static struct snd_soc_ops db1200_i2s_wm8731_ops = { | ||
77 | .startup = db1200_i2s_startup, | ||
78 | }; | ||
79 | |||
80 | static struct snd_soc_dai_link db1200_i2s_dai = { | ||
81 | .name = "WM8731", | ||
82 | .stream_name = "WM8731 PCM", | ||
83 | .cpu_dai = &au1xpsc_i2s_dai, | ||
84 | .codec_dai = &wm8731_dai, | ||
85 | .ops = &db1200_i2s_wm8731_ops, | ||
86 | }; | ||
87 | |||
88 | static struct snd_soc_card db1200_i2s_machine = { | ||
89 | .name = "DB1200_I2S", | ||
90 | .dai_link = &db1200_i2s_dai, | ||
91 | .num_links = 1, | ||
92 | .platform = &au1xpsc_soc_platform, | ||
93 | }; | ||
94 | |||
95 | static struct snd_soc_device db1200_i2s_devdata = { | ||
96 | .card = &db1200_i2s_machine, | ||
97 | .codec_dev = &soc_codec_dev_wm8731, | ||
98 | }; | ||
99 | |||
100 | /*------------------------- COMMON PART ---------------------------*/ | ||
101 | |||
102 | static struct platform_device *db1200_asoc_dev; | ||
103 | |||
104 | static int __init db1200_audio_load(void) | ||
105 | { | ||
106 | int ret; | ||
107 | |||
108 | ret = -ENOMEM; | ||
109 | db1200_asoc_dev = platform_device_alloc("soc-audio", -1); | ||
110 | if (!db1200_asoc_dev) | ||
111 | goto out; | ||
112 | |||
113 | /* DB1200 board setup set PSC1MUX to preferred audio device */ | ||
114 | if (bcsr_read(BCSR_RESETS) & BCSR_RESETS_PSC1MUX) | ||
115 | platform_set_drvdata(db1200_asoc_dev, &db1200_i2s_devdata); | ||
116 | else | ||
117 | platform_set_drvdata(db1200_asoc_dev, &db1200_ac97_devdata); | ||
118 | |||
119 | db1200_ac97_devdata.dev = &db1200_asoc_dev->dev; | ||
120 | db1200_i2s_devdata.dev = &db1200_asoc_dev->dev; | ||
121 | ret = platform_device_add(db1200_asoc_dev); | ||
122 | |||
123 | if (ret) { | ||
124 | platform_device_put(db1200_asoc_dev); | ||
125 | db1200_asoc_dev = NULL; | ||
126 | } | ||
127 | out: | ||
128 | return ret; | ||
129 | } | ||
130 | |||
131 | static void __exit db1200_audio_unload(void) | ||
132 | { | ||
133 | platform_device_unregister(db1200_asoc_dev); | ||
134 | } | ||
135 | |||
136 | module_init(db1200_audio_load); | ||
137 | module_exit(db1200_audio_unload); | ||
138 | |||
139 | MODULE_LICENSE("GPL"); | ||
140 | MODULE_DESCRIPTION("DB1200 ASoC audio support"); | ||
141 | MODULE_AUTHOR("Manuel Lauss"); | ||
diff --git a/sound/soc/au1x/dbdma2.c b/sound/soc/au1x/dbdma2.c index 19e4d37eba1c..6d9f4c624949 100644 --- a/sound/soc/au1x/dbdma2.c +++ b/sound/soc/au1x/dbdma2.c | |||
@@ -51,8 +51,8 @@ struct au1xpsc_audio_dmadata { | |||
51 | struct snd_pcm_substream *substream; | 51 | struct snd_pcm_substream *substream; |
52 | unsigned long curr_period; /* current segment DDMA is working on */ | 52 | unsigned long curr_period; /* current segment DDMA is working on */ |
53 | unsigned long q_period; /* queue period(s) */ | 53 | unsigned long q_period; /* queue period(s) */ |
54 | unsigned long dma_area; /* address of queued DMA area */ | 54 | dma_addr_t dma_area; /* address of queued DMA area */ |
55 | unsigned long dma_area_s; /* start address of DMA area */ | 55 | dma_addr_t dma_area_s; /* start address of DMA area */ |
56 | unsigned long pos; /* current byte position being played */ | 56 | unsigned long pos; /* current byte position being played */ |
57 | unsigned long periods; /* number of SG segments in total */ | 57 | unsigned long periods; /* number of SG segments in total */ |
58 | unsigned long period_bytes; /* size in bytes of one SG segment */ | 58 | unsigned long period_bytes; /* size in bytes of one SG segment */ |
@@ -94,8 +94,7 @@ static const struct snd_pcm_hardware au1xpsc_pcm_hardware = { | |||
94 | 94 | ||
95 | static void au1x_pcm_queue_tx(struct au1xpsc_audio_dmadata *cd) | 95 | static void au1x_pcm_queue_tx(struct au1xpsc_audio_dmadata *cd) |
96 | { | 96 | { |
97 | au1xxx_dbdma_put_source_flags(cd->ddma_chan, | 97 | au1xxx_dbdma_put_source(cd->ddma_chan, cd->dma_area, |
98 | (void *)phys_to_virt(cd->dma_area), | ||
99 | cd->period_bytes, DDMA_FLAGS_IE); | 98 | cd->period_bytes, DDMA_FLAGS_IE); |
100 | 99 | ||
101 | /* update next-to-queue period */ | 100 | /* update next-to-queue period */ |
@@ -109,9 +108,8 @@ static void au1x_pcm_queue_tx(struct au1xpsc_audio_dmadata *cd) | |||
109 | 108 | ||
110 | static void au1x_pcm_queue_rx(struct au1xpsc_audio_dmadata *cd) | 109 | static void au1x_pcm_queue_rx(struct au1xpsc_audio_dmadata *cd) |
111 | { | 110 | { |
112 | au1xxx_dbdma_put_dest_flags(cd->ddma_chan, | 111 | au1xxx_dbdma_put_dest(cd->ddma_chan, cd->dma_area, |
113 | (void *)phys_to_virt(cd->dma_area), | 112 | cd->period_bytes, DDMA_FLAGS_IE); |
114 | cd->period_bytes, DDMA_FLAGS_IE); | ||
115 | 113 | ||
116 | /* update next-to-queue period */ | 114 | /* update next-to-queue period */ |
117 | ++cd->q_period; | 115 | ++cd->q_period; |
@@ -233,7 +231,7 @@ static int au1xpsc_pcm_hw_params(struct snd_pcm_substream *substream, | |||
233 | pcd->substream = substream; | 231 | pcd->substream = substream; |
234 | pcd->period_bytes = params_period_bytes(params); | 232 | pcd->period_bytes = params_period_bytes(params); |
235 | pcd->periods = params_periods(params); | 233 | pcd->periods = params_periods(params); |
236 | pcd->dma_area_s = pcd->dma_area = (unsigned long)runtime->dma_addr; | 234 | pcd->dma_area_s = pcd->dma_area = runtime->dma_addr; |
237 | pcd->q_period = 0; | 235 | pcd->q_period = 0; |
238 | pcd->curr_period = 0; | 236 | pcd->curr_period = 0; |
239 | pcd->pos = 0; | 237 | pcd->pos = 0; |
diff --git a/sound/soc/au1x/sample-ac97.c b/sound/soc/au1x/sample-ac97.c deleted file mode 100644 index 27683eb7905e..000000000000 --- a/sound/soc/au1x/sample-ac97.c +++ /dev/null | |||
@@ -1,144 +0,0 @@ | |||
1 | /* | ||
2 | * Sample Au12x0/Au1550 PSC AC97 sound machine. | ||
3 | * | ||
4 | * Copyright (c) 2007-2008 Manuel Lauss <mano@roarinelk.homelinux.net> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms outlined in the file COPYING at the root of this | ||
8 | * source archive. | ||
9 | * | ||
10 | * This is a very generic AC97 sound machine driver for boards which | ||
11 | * have (AC97) audio at PSC1 (e.g. DB1200 demoboards). | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/moduleparam.h> | ||
16 | #include <linux/timer.h> | ||
17 | #include <linux/interrupt.h> | ||
18 | #include <linux/platform_device.h> | ||
19 | #include <sound/core.h> | ||
20 | #include <sound/pcm.h> | ||
21 | #include <sound/soc.h> | ||
22 | #include <sound/soc-dapm.h> | ||
23 | #include <asm/mach-au1x00/au1000.h> | ||
24 | #include <asm/mach-au1x00/au1xxx_psc.h> | ||
25 | #include <asm/mach-au1x00/au1xxx_dbdma.h> | ||
26 | |||
27 | #include "../codecs/ac97.h" | ||
28 | #include "psc.h" | ||
29 | |||
30 | static int au1xpsc_sample_ac97_init(struct snd_soc_codec *codec) | ||
31 | { | ||
32 | snd_soc_dapm_sync(codec); | ||
33 | return 0; | ||
34 | } | ||
35 | |||
36 | static struct snd_soc_dai_link au1xpsc_sample_ac97_dai = { | ||
37 | .name = "AC97", | ||
38 | .stream_name = "AC97 HiFi", | ||
39 | .cpu_dai = &au1xpsc_ac97_dai, /* see psc-ac97.c */ | ||
40 | .codec_dai = &ac97_dai, /* see codecs/ac97.c */ | ||
41 | .init = au1xpsc_sample_ac97_init, | ||
42 | .ops = NULL, | ||
43 | }; | ||
44 | |||
45 | static struct snd_soc_card au1xpsc_sample_ac97_machine = { | ||
46 | .name = "Au1xxx PSC AC97 Audio", | ||
47 | .dai_link = &au1xpsc_sample_ac97_dai, | ||
48 | .num_links = 1, | ||
49 | }; | ||
50 | |||
51 | static struct snd_soc_device au1xpsc_sample_ac97_devdata = { | ||
52 | .card = &au1xpsc_sample_ac97_machine, | ||
53 | .platform = &au1xpsc_soc_platform, /* see dbdma2.c */ | ||
54 | .codec_dev = &soc_codec_dev_ac97, | ||
55 | }; | ||
56 | |||
57 | static struct resource au1xpsc_psc1_res[] = { | ||
58 | [0] = { | ||
59 | .start = CPHYSADDR(PSC1_BASE_ADDR), | ||
60 | .end = CPHYSADDR(PSC1_BASE_ADDR) + 0x000fffff, | ||
61 | .flags = IORESOURCE_MEM, | ||
62 | }, | ||
63 | [1] = { | ||
64 | #ifdef CONFIG_SOC_AU1200 | ||
65 | .start = AU1200_PSC1_INT, | ||
66 | .end = AU1200_PSC1_INT, | ||
67 | #elif defined(CONFIG_SOC_AU1550) | ||
68 | .start = AU1550_PSC1_INT, | ||
69 | .end = AU1550_PSC1_INT, | ||
70 | #endif | ||
71 | .flags = IORESOURCE_IRQ, | ||
72 | }, | ||
73 | [2] = { | ||
74 | .start = DSCR_CMD0_PSC1_TX, | ||
75 | .end = DSCR_CMD0_PSC1_TX, | ||
76 | .flags = IORESOURCE_DMA, | ||
77 | }, | ||
78 | [3] = { | ||
79 | .start = DSCR_CMD0_PSC1_RX, | ||
80 | .end = DSCR_CMD0_PSC1_RX, | ||
81 | .flags = IORESOURCE_DMA, | ||
82 | }, | ||
83 | }; | ||
84 | |||
85 | static struct platform_device *au1xpsc_sample_ac97_dev; | ||
86 | |||
87 | static int __init au1xpsc_sample_ac97_load(void) | ||
88 | { | ||
89 | int ret; | ||
90 | |||
91 | #ifdef CONFIG_SOC_AU1200 | ||
92 | unsigned long io; | ||
93 | |||
94 | /* modify sys_pinfunc for AC97 on PSC1 */ | ||
95 | io = au_readl(SYS_PINFUNC); | ||
96 | io |= SYS_PINFUNC_P1C; | ||
97 | io &= ~(SYS_PINFUNC_P1A | SYS_PINFUNC_P1B); | ||
98 | au_writel(io, SYS_PINFUNC); | ||
99 | au_sync(); | ||
100 | #endif | ||
101 | |||
102 | ret = -ENOMEM; | ||
103 | |||
104 | /* setup PSC clock source for AC97 part: external clock provided | ||
105 | * by codec. The psc-ac97.c driver depends on this setting! | ||
106 | */ | ||
107 | au_writel(PSC_SEL_CLK_SERCLK, PSC1_BASE_ADDR + PSC_SEL_OFFSET); | ||
108 | au_sync(); | ||
109 | |||
110 | au1xpsc_sample_ac97_dev = platform_device_alloc("soc-audio", -1); | ||
111 | if (!au1xpsc_sample_ac97_dev) | ||
112 | goto out; | ||
113 | |||
114 | au1xpsc_sample_ac97_dev->resource = | ||
115 | kmemdup(au1xpsc_psc1_res, sizeof(struct resource) * | ||
116 | ARRAY_SIZE(au1xpsc_psc1_res), GFP_KERNEL); | ||
117 | au1xpsc_sample_ac97_dev->num_resources = ARRAY_SIZE(au1xpsc_psc1_res); | ||
118 | au1xpsc_sample_ac97_dev->id = 1; | ||
119 | |||
120 | platform_set_drvdata(au1xpsc_sample_ac97_dev, | ||
121 | &au1xpsc_sample_ac97_devdata); | ||
122 | au1xpsc_sample_ac97_devdata.dev = &au1xpsc_sample_ac97_dev->dev; | ||
123 | ret = platform_device_add(au1xpsc_sample_ac97_dev); | ||
124 | |||
125 | if (ret) { | ||
126 | platform_device_put(au1xpsc_sample_ac97_dev); | ||
127 | au1xpsc_sample_ac97_dev = NULL; | ||
128 | } | ||
129 | |||
130 | out: | ||
131 | return ret; | ||
132 | } | ||
133 | |||
134 | static void __exit au1xpsc_sample_ac97_exit(void) | ||
135 | { | ||
136 | platform_device_unregister(au1xpsc_sample_ac97_dev); | ||
137 | } | ||
138 | |||
139 | module_init(au1xpsc_sample_ac97_load); | ||
140 | module_exit(au1xpsc_sample_ac97_exit); | ||
141 | |||
142 | MODULE_LICENSE("GPL"); | ||
143 | MODULE_DESCRIPTION("Au1xxx PSC sample AC97 machine"); | ||
144 | MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>"); | ||
diff --git a/sound/soc/blackfin/bf5xx-ac97-pcm.c b/sound/soc/blackfin/bf5xx-ac97-pcm.c index cf0dfb7ca221..67cbfe7283da 100644 --- a/sound/soc/blackfin/bf5xx-ac97-pcm.c +++ b/sound/soc/blackfin/bf5xx-ac97-pcm.c | |||
@@ -349,9 +349,7 @@ static int bf5xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) | |||
349 | sport_handle->tx_dma_buf = dma_alloc_coherent(NULL, \ | 349 | sport_handle->tx_dma_buf = dma_alloc_coherent(NULL, \ |
350 | size, &sport_handle->tx_dma_phy, GFP_KERNEL); | 350 | size, &sport_handle->tx_dma_phy, GFP_KERNEL); |
351 | if (!sport_handle->tx_dma_buf) { | 351 | if (!sport_handle->tx_dma_buf) { |
352 | pr_err("Failed to allocate memory for tx dma \ | 352 | pr_err("Failed to allocate memory for tx dma buf - Please increase uncached DMA memory region\n"); |
353 | buf - Please increase uncached DMA \ | ||
354 | memory region\n"); | ||
355 | return -ENOMEM; | 353 | return -ENOMEM; |
356 | } else | 354 | } else |
357 | memset(sport_handle->tx_dma_buf, 0, size); | 355 | memset(sport_handle->tx_dma_buf, 0, size); |
@@ -362,9 +360,7 @@ static int bf5xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) | |||
362 | sport_handle->rx_dma_buf = dma_alloc_coherent(NULL, \ | 360 | sport_handle->rx_dma_buf = dma_alloc_coherent(NULL, \ |
363 | size, &sport_handle->rx_dma_phy, GFP_KERNEL); | 361 | size, &sport_handle->rx_dma_phy, GFP_KERNEL); |
364 | if (!sport_handle->rx_dma_buf) { | 362 | if (!sport_handle->rx_dma_buf) { |
365 | pr_err("Failed to allocate memory for rx dma \ | 363 | pr_err("Failed to allocate memory for rx dma buf - Please increase uncached DMA memory region\n"); |
366 | buf - Please increase uncached DMA \ | ||
367 | memory region\n"); | ||
368 | return -ENOMEM; | 364 | return -ENOMEM; |
369 | } else | 365 | } else |
370 | memset(sport_handle->rx_dma_buf, 0, size); | 366 | memset(sport_handle->rx_dma_buf, 0, size); |
diff --git a/sound/soc/blackfin/bf5xx-i2s-pcm.c b/sound/soc/blackfin/bf5xx-i2s-pcm.c index 62fbb8459569..c6c6a4a7d948 100644 --- a/sound/soc/blackfin/bf5xx-i2s-pcm.c +++ b/sound/soc/blackfin/bf5xx-i2s-pcm.c | |||
@@ -207,8 +207,7 @@ static int bf5xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) | |||
207 | buf->area = dma_alloc_coherent(pcm->card->dev, size, | 207 | buf->area = dma_alloc_coherent(pcm->card->dev, size, |
208 | &buf->addr, GFP_KERNEL); | 208 | &buf->addr, GFP_KERNEL); |
209 | if (!buf->area) { | 209 | if (!buf->area) { |
210 | pr_err("Failed to allocate dma memory \ | 210 | pr_err("Failed to allocate dma memory - Please increase uncached DMA memory region\n"); |
211 | Please increase uncached DMA memory region\n"); | ||
212 | return -ENOMEM; | 211 | return -ENOMEM; |
213 | } | 212 | } |
214 | buf->bytes = size; | 213 | buf->bytes = size; |
diff --git a/sound/soc/blackfin/bf5xx-tdm-pcm.c b/sound/soc/blackfin/bf5xx-tdm-pcm.c index a8c73cbbd685..5e03bb2f3cd7 100644 --- a/sound/soc/blackfin/bf5xx-tdm-pcm.c +++ b/sound/soc/blackfin/bf5xx-tdm-pcm.c | |||
@@ -244,8 +244,7 @@ static int bf5xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) | |||
244 | buf->area = dma_alloc_coherent(pcm->card->dev, size * 4, | 244 | buf->area = dma_alloc_coherent(pcm->card->dev, size * 4, |
245 | &buf->addr, GFP_KERNEL); | 245 | &buf->addr, GFP_KERNEL); |
246 | if (!buf->area) { | 246 | if (!buf->area) { |
247 | pr_err("Failed to allocate dma memory \ | 247 | pr_err("Failed to allocate dma memory - Please increase uncached DMA memory region\n"); |
248 | Please increase uncached DMA memory region\n"); | ||
249 | return -ENOMEM; | 248 | return -ENOMEM; |
250 | } | 249 | } |
251 | buf->bytes = size; | 250 | buf->bytes = size; |
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 52b005f8fed4..1743d565e996 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig | |||
@@ -23,6 +23,7 @@ config SND_SOC_ALL_CODECS | |||
23 | select SND_SOC_AK4671 if I2C | 23 | select SND_SOC_AK4671 if I2C |
24 | select SND_SOC_CS4270 if I2C | 24 | select SND_SOC_CS4270 if I2C |
25 | select SND_SOC_MAX9877 if I2C | 25 | select SND_SOC_MAX9877 if I2C |
26 | select SND_SOC_DA7210 if I2C | ||
26 | select SND_SOC_PCM3008 | 27 | select SND_SOC_PCM3008 |
27 | select SND_SOC_SPDIF | 28 | select SND_SOC_SPDIF |
28 | select SND_SOC_SSM2602 if I2C | 29 | select SND_SOC_SSM2602 if I2C |
@@ -35,6 +36,7 @@ config SND_SOC_ALL_CODECS | |||
35 | select SND_SOC_TWL4030 if TWL4030_CORE | 36 | select SND_SOC_TWL4030 if TWL4030_CORE |
36 | select SND_SOC_UDA134X | 37 | select SND_SOC_UDA134X |
37 | select SND_SOC_UDA1380 if I2C | 38 | select SND_SOC_UDA1380 if I2C |
39 | select SND_SOC_WM2000 if I2C | ||
38 | select SND_SOC_WM8350 if MFD_WM8350 | 40 | select SND_SOC_WM8350 if MFD_WM8350 |
39 | select SND_SOC_WM8400 if MFD_WM8400 | 41 | select SND_SOC_WM8400 if MFD_WM8400 |
40 | select SND_SOC_WM8510 if SND_SOC_I2C_AND_SPI | 42 | select SND_SOC_WM8510 if SND_SOC_I2C_AND_SPI |
@@ -49,14 +51,18 @@ config SND_SOC_ALL_CODECS | |||
49 | select SND_SOC_WM8776 if SND_SOC_I2C_AND_SPI | 51 | select SND_SOC_WM8776 if SND_SOC_I2C_AND_SPI |
50 | select SND_SOC_WM8900 if I2C | 52 | select SND_SOC_WM8900 if I2C |
51 | select SND_SOC_WM8903 if I2C | 53 | select SND_SOC_WM8903 if I2C |
54 | select SND_SOC_WM8904 if I2C | ||
52 | select SND_SOC_WM8940 if I2C | 55 | select SND_SOC_WM8940 if I2C |
56 | select SND_SOC_WM8955 if I2C | ||
53 | select SND_SOC_WM8960 if I2C | 57 | select SND_SOC_WM8960 if I2C |
54 | select SND_SOC_WM8961 if I2C | 58 | select SND_SOC_WM8961 if I2C |
55 | select SND_SOC_WM8971 if I2C | 59 | select SND_SOC_WM8971 if I2C |
56 | select SND_SOC_WM8974 if I2C | 60 | select SND_SOC_WM8974 if I2C |
61 | select SND_SOC_WM8978 if I2C | ||
57 | select SND_SOC_WM8988 if SND_SOC_I2C_AND_SPI | 62 | select SND_SOC_WM8988 if SND_SOC_I2C_AND_SPI |
58 | select SND_SOC_WM8990 if I2C | 63 | select SND_SOC_WM8990 if I2C |
59 | select SND_SOC_WM8993 if I2C | 64 | select SND_SOC_WM8993 if I2C |
65 | select SND_SOC_WM8994 if MFD_WM8994 | ||
60 | select SND_SOC_WM9081 if I2C | 66 | select SND_SOC_WM9081 if I2C |
61 | select SND_SOC_WM9705 if SND_SOC_AC97_BUS | 67 | select SND_SOC_WM9705 if SND_SOC_AC97_BUS |
62 | select SND_SOC_WM9712 if SND_SOC_AC97_BUS | 68 | select SND_SOC_WM9712 if SND_SOC_AC97_BUS |
@@ -112,6 +118,9 @@ config SND_SOC_AK4671 | |||
112 | config SND_SOC_CS4270 | 118 | config SND_SOC_CS4270 |
113 | tristate | 119 | tristate |
114 | 120 | ||
121 | config SND_SOC_DA7210 | ||
122 | tristate | ||
123 | |||
115 | # Cirrus Logic CS4270 Codec VD = 3.3V Errata | 124 | # Cirrus Logic CS4270 Codec VD = 3.3V Errata |
116 | # Select if you are affected by the errata where the part will not function | 125 | # Select if you are affected by the errata where the part will not function |
117 | # if MCLK divide-by-1.5 is selected and VD is set to 3.3V. The driver will | 126 | # if MCLK divide-by-1.5 is selected and VD is set to 3.3V. The driver will |
@@ -203,9 +212,15 @@ config SND_SOC_WM8900 | |||
203 | config SND_SOC_WM8903 | 212 | config SND_SOC_WM8903 |
204 | tristate | 213 | tristate |
205 | 214 | ||
215 | config SND_SOC_WM8904 | ||
216 | tristate | ||
217 | |||
206 | config SND_SOC_WM8940 | 218 | config SND_SOC_WM8940 |
207 | tristate | 219 | tristate |
208 | 220 | ||
221 | config SND_SOC_WM8955 | ||
222 | tristate | ||
223 | |||
209 | config SND_SOC_WM8960 | 224 | config SND_SOC_WM8960 |
210 | tristate | 225 | tristate |
211 | 226 | ||
@@ -218,6 +233,9 @@ config SND_SOC_WM8971 | |||
218 | config SND_SOC_WM8974 | 233 | config SND_SOC_WM8974 |
219 | tristate | 234 | tristate |
220 | 235 | ||
236 | config SND_SOC_WM8978 | ||
237 | tristate | ||
238 | |||
221 | config SND_SOC_WM8988 | 239 | config SND_SOC_WM8988 |
222 | tristate | 240 | tristate |
223 | 241 | ||
@@ -227,6 +245,9 @@ config SND_SOC_WM8990 | |||
227 | config SND_SOC_WM8993 | 245 | config SND_SOC_WM8993 |
228 | tristate | 246 | tristate |
229 | 247 | ||
248 | config SND_SOC_WM8994 | ||
249 | tristate | ||
250 | |||
230 | config SND_SOC_WM9081 | 251 | config SND_SOC_WM9081 |
231 | tristate | 252 | tristate |
232 | 253 | ||
@@ -245,3 +266,6 @@ config SND_SOC_MAX9877 | |||
245 | 266 | ||
246 | config SND_SOC_TPA6130A2 | 267 | config SND_SOC_TPA6130A2 |
247 | tristate | 268 | tristate |
269 | |||
270 | config SND_SOC_WM2000 | ||
271 | tristate | ||
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index dbaecb133ac7..dd5ce6df6292 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile | |||
@@ -10,6 +10,7 @@ snd-soc-ak4642-objs := ak4642.o | |||
10 | snd-soc-ak4671-objs := ak4671.o | 10 | snd-soc-ak4671-objs := ak4671.o |
11 | snd-soc-cs4270-objs := cs4270.o | 11 | snd-soc-cs4270-objs := cs4270.o |
12 | snd-soc-cx20442-objs := cx20442.o | 12 | snd-soc-cx20442-objs := cx20442.o |
13 | snd-soc-da7210-objs := da7210.o | ||
13 | snd-soc-l3-objs := l3.o | 14 | snd-soc-l3-objs := l3.o |
14 | snd-soc-pcm3008-objs := pcm3008.o | 15 | snd-soc-pcm3008-objs := pcm3008.o |
15 | snd-soc-spdif-objs := spdif_transciever.o | 16 | snd-soc-spdif-objs := spdif_transciever.o |
@@ -36,14 +37,18 @@ snd-soc-wm8753-objs := wm8753.o | |||
36 | snd-soc-wm8776-objs := wm8776.o | 37 | snd-soc-wm8776-objs := wm8776.o |
37 | snd-soc-wm8900-objs := wm8900.o | 38 | snd-soc-wm8900-objs := wm8900.o |
38 | snd-soc-wm8903-objs := wm8903.o | 39 | snd-soc-wm8903-objs := wm8903.o |
40 | snd-soc-wm8904-objs := wm8904.o | ||
39 | snd-soc-wm8940-objs := wm8940.o | 41 | snd-soc-wm8940-objs := wm8940.o |
42 | snd-soc-wm8955-objs := wm8955.o | ||
40 | snd-soc-wm8960-objs := wm8960.o | 43 | snd-soc-wm8960-objs := wm8960.o |
41 | snd-soc-wm8961-objs := wm8961.o | 44 | snd-soc-wm8961-objs := wm8961.o |
42 | snd-soc-wm8971-objs := wm8971.o | 45 | snd-soc-wm8971-objs := wm8971.o |
43 | snd-soc-wm8974-objs := wm8974.o | 46 | snd-soc-wm8974-objs := wm8974.o |
47 | snd-soc-wm8978-objs := wm8978.o | ||
44 | snd-soc-wm8988-objs := wm8988.o | 48 | snd-soc-wm8988-objs := wm8988.o |
45 | snd-soc-wm8990-objs := wm8990.o | 49 | snd-soc-wm8990-objs := wm8990.o |
46 | snd-soc-wm8993-objs := wm8993.o | 50 | snd-soc-wm8993-objs := wm8993.o |
51 | snd-soc-wm8994-objs := wm8994.o | ||
47 | snd-soc-wm9081-objs := wm9081.o | 52 | snd-soc-wm9081-objs := wm9081.o |
48 | snd-soc-wm9705-objs := wm9705.o | 53 | snd-soc-wm9705-objs := wm9705.o |
49 | snd-soc-wm9712-objs := wm9712.o | 54 | snd-soc-wm9712-objs := wm9712.o |
@@ -53,6 +58,7 @@ snd-soc-wm-hubs-objs := wm_hubs.o | |||
53 | # Amp | 58 | # Amp |
54 | snd-soc-max9877-objs := max9877.o | 59 | snd-soc-max9877-objs := max9877.o |
55 | snd-soc-tpa6130a2-objs := tpa6130a2.o | 60 | snd-soc-tpa6130a2-objs := tpa6130a2.o |
61 | snd-soc-wm2000-objs := wm2000.o | ||
56 | 62 | ||
57 | obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o | 63 | obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o |
58 | obj-$(CONFIG_SND_SOC_AD1836) += snd-soc-ad1836.o | 64 | obj-$(CONFIG_SND_SOC_AD1836) += snd-soc-ad1836.o |
@@ -66,6 +72,7 @@ obj-$(CONFIG_SND_SOC_AK4642) += snd-soc-ak4642.o | |||
66 | obj-$(CONFIG_SND_SOC_AK4671) += snd-soc-ak4671.o | 72 | obj-$(CONFIG_SND_SOC_AK4671) += snd-soc-ak4671.o |
67 | obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o | 73 | obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o |
68 | obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o | 74 | obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o |
75 | obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o | ||
69 | obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o | 76 | obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o |
70 | obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o | 77 | obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o |
71 | obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif.o | 78 | obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif.o |
@@ -92,14 +99,18 @@ obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o | |||
92 | obj-$(CONFIG_SND_SOC_WM8776) += snd-soc-wm8776.o | 99 | obj-$(CONFIG_SND_SOC_WM8776) += snd-soc-wm8776.o |
93 | obj-$(CONFIG_SND_SOC_WM8900) += snd-soc-wm8900.o | 100 | obj-$(CONFIG_SND_SOC_WM8900) += snd-soc-wm8900.o |
94 | obj-$(CONFIG_SND_SOC_WM8903) += snd-soc-wm8903.o | 101 | obj-$(CONFIG_SND_SOC_WM8903) += snd-soc-wm8903.o |
95 | obj-$(CONFIG_SND_SOC_WM8971) += snd-soc-wm8971.o | 102 | obj-$(CONFIG_SND_SOC_WM8904) += snd-soc-wm8904.o |
96 | obj-$(CONFIG_SND_SOC_WM8974) += snd-soc-wm8974.o | ||
97 | obj-$(CONFIG_SND_SOC_WM8940) += snd-soc-wm8940.o | 103 | obj-$(CONFIG_SND_SOC_WM8940) += snd-soc-wm8940.o |
104 | obj-$(CONFIG_SND_SOC_WM8955) += snd-soc-wm8955.o | ||
98 | obj-$(CONFIG_SND_SOC_WM8960) += snd-soc-wm8960.o | 105 | obj-$(CONFIG_SND_SOC_WM8960) += snd-soc-wm8960.o |
99 | obj-$(CONFIG_SND_SOC_WM8961) += snd-soc-wm8961.o | 106 | obj-$(CONFIG_SND_SOC_WM8961) += snd-soc-wm8961.o |
107 | obj-$(CONFIG_SND_SOC_WM8971) += snd-soc-wm8971.o | ||
108 | obj-$(CONFIG_SND_SOC_WM8974) += snd-soc-wm8974.o | ||
109 | obj-$(CONFIG_SND_SOC_WM8978) += snd-soc-wm8978.o | ||
100 | obj-$(CONFIG_SND_SOC_WM8988) += snd-soc-wm8988.o | 110 | obj-$(CONFIG_SND_SOC_WM8988) += snd-soc-wm8988.o |
101 | obj-$(CONFIG_SND_SOC_WM8990) += snd-soc-wm8990.o | 111 | obj-$(CONFIG_SND_SOC_WM8990) += snd-soc-wm8990.o |
102 | obj-$(CONFIG_SND_SOC_WM8993) += snd-soc-wm8993.o | 112 | obj-$(CONFIG_SND_SOC_WM8993) += snd-soc-wm8993.o |
113 | obj-$(CONFIG_SND_SOC_WM8994) += snd-soc-wm8994.o | ||
103 | obj-$(CONFIG_SND_SOC_WM9081) += snd-soc-wm9081.o | 114 | obj-$(CONFIG_SND_SOC_WM9081) += snd-soc-wm9081.o |
104 | obj-$(CONFIG_SND_SOC_WM9705) += snd-soc-wm9705.o | 115 | obj-$(CONFIG_SND_SOC_WM9705) += snd-soc-wm9705.o |
105 | obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o | 116 | obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o |
@@ -109,3 +120,4 @@ obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o | |||
109 | # Amp | 120 | # Amp |
110 | obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o | 121 | obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o |
111 | obj-$(CONFIG_SND_SOC_TPA6130A2) += snd-soc-tpa6130a2.o | 122 | obj-$(CONFIG_SND_SOC_TPA6130A2) += snd-soc-tpa6130a2.o |
123 | obj-$(CONFIG_SND_SOC_WM2000) += snd-soc-wm2000.o | ||
diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c index 2c18e3d1b71e..3c80137d5938 100644 --- a/sound/soc/codecs/ad1836.c +++ b/sound/soc/codecs/ad1836.c | |||
@@ -171,57 +171,35 @@ static int ad1836_hw_params(struct snd_pcm_substream *substream, | |||
171 | return 0; | 171 | return 0; |
172 | } | 172 | } |
173 | 173 | ||
174 | 174 | #ifdef CONFIG_PM | |
175 | /* | 175 | static int ad1836_soc_suspend(struct platform_device *pdev, |
176 | * interface to read/write ad1836 register | 176 | pm_message_t state) |
177 | */ | ||
178 | #define AD1836_SPI_REG_SHFT 12 | ||
179 | #define AD1836_SPI_READ (1 << 11) | ||
180 | #define AD1836_SPI_VAL_MSK 0x3FF | ||
181 | |||
182 | /* | ||
183 | * write to the ad1836 register space | ||
184 | */ | ||
185 | |||
186 | static int ad1836_write_reg(struct snd_soc_codec *codec, unsigned int reg, | ||
187 | unsigned int value) | ||
188 | { | 177 | { |
189 | u16 *reg_cache = codec->reg_cache; | 178 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
190 | int ret = 0; | 179 | struct snd_soc_codec *codec = socdev->card->codec; |
191 | 180 | ||
192 | if (value != reg_cache[reg]) { | 181 | /* reset clock control mode */ |
193 | unsigned short buf; | 182 | u16 adc_ctrl2 = snd_soc_read(codec, AD1836_ADC_CTRL2); |
194 | struct spi_transfer t = { | 183 | adc_ctrl2 &= ~AD1836_ADC_SERFMT_MASK; |
195 | .tx_buf = &buf, | ||
196 | .len = 2, | ||
197 | }; | ||
198 | struct spi_message m; | ||
199 | |||
200 | buf = (reg << AD1836_SPI_REG_SHFT) | | ||
201 | (value & AD1836_SPI_VAL_MSK); | ||
202 | spi_message_init(&m); | ||
203 | spi_message_add_tail(&t, &m); | ||
204 | ret = spi_sync(codec->control_data, &m); | ||
205 | if (ret == 0) | ||
206 | reg_cache[reg] = value; | ||
207 | } | ||
208 | 184 | ||
209 | return ret; | 185 | return snd_soc_write(codec, AD1836_ADC_CTRL2, adc_ctrl2); |
210 | } | 186 | } |
211 | 187 | ||
212 | /* | 188 | static int ad1836_soc_resume(struct platform_device *pdev) |
213 | * read from the ad1836 register space cache | ||
214 | */ | ||
215 | static unsigned int ad1836_read_reg_cache(struct snd_soc_codec *codec, | ||
216 | unsigned int reg) | ||
217 | { | 189 | { |
218 | u16 *reg_cache = codec->reg_cache; | 190 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
191 | struct snd_soc_codec *codec = socdev->card->codec; | ||
219 | 192 | ||
220 | if (reg >= codec->reg_cache_size) | 193 | /* restore clock control mode */ |
221 | return -EINVAL; | 194 | u16 adc_ctrl2 = snd_soc_read(codec, AD1836_ADC_CTRL2); |
195 | adc_ctrl2 |= AD1836_ADC_AUX; | ||
222 | 196 | ||
223 | return reg_cache[reg]; | 197 | return snd_soc_write(codec, AD1836_ADC_CTRL2, adc_ctrl2); |
224 | } | 198 | } |
199 | #else | ||
200 | #define ad1836_soc_suspend NULL | ||
201 | #define ad1836_soc_resume NULL | ||
202 | #endif | ||
225 | 203 | ||
226 | static int __devinit ad1836_spi_probe(struct spi_device *spi) | 204 | static int __devinit ad1836_spi_probe(struct spi_device *spi) |
227 | { | 205 | { |
@@ -306,32 +284,38 @@ static int ad1836_register(struct ad1836_priv *ad1836) | |||
306 | codec->owner = THIS_MODULE; | 284 | codec->owner = THIS_MODULE; |
307 | codec->dai = &ad1836_dai; | 285 | codec->dai = &ad1836_dai; |
308 | codec->num_dai = 1; | 286 | codec->num_dai = 1; |
309 | codec->write = ad1836_write_reg; | ||
310 | codec->read = ad1836_read_reg_cache; | ||
311 | INIT_LIST_HEAD(&codec->dapm_widgets); | 287 | INIT_LIST_HEAD(&codec->dapm_widgets); |
312 | INIT_LIST_HEAD(&codec->dapm_paths); | 288 | INIT_LIST_HEAD(&codec->dapm_paths); |
313 | 289 | ||
314 | ad1836_dai.dev = codec->dev; | 290 | ad1836_dai.dev = codec->dev; |
315 | ad1836_codec = codec; | 291 | ad1836_codec = codec; |
316 | 292 | ||
293 | ret = snd_soc_codec_set_cache_io(codec, 4, 12, SND_SOC_SPI); | ||
294 | if (ret < 0) { | ||
295 | dev_err(codec->dev, "failed to set cache I/O: %d\n", | ||
296 | ret); | ||
297 | kfree(ad1836); | ||
298 | return ret; | ||
299 | } | ||
300 | |||
317 | /* default setting for ad1836 */ | 301 | /* default setting for ad1836 */ |
318 | /* de-emphasis: 48kHz, power-on dac */ | 302 | /* de-emphasis: 48kHz, power-on dac */ |
319 | codec->write(codec, AD1836_DAC_CTRL1, 0x300); | 303 | snd_soc_write(codec, AD1836_DAC_CTRL1, 0x300); |
320 | /* unmute dac channels */ | 304 | /* unmute dac channels */ |
321 | codec->write(codec, AD1836_DAC_CTRL2, 0x0); | 305 | snd_soc_write(codec, AD1836_DAC_CTRL2, 0x0); |
322 | /* high-pass filter enable, power-on adc */ | 306 | /* high-pass filter enable, power-on adc */ |
323 | codec->write(codec, AD1836_ADC_CTRL1, 0x100); | 307 | snd_soc_write(codec, AD1836_ADC_CTRL1, 0x100); |
324 | /* unmute adc channles, adc aux mode */ | 308 | /* unmute adc channles, adc aux mode */ |
325 | codec->write(codec, AD1836_ADC_CTRL2, 0x180); | 309 | snd_soc_write(codec, AD1836_ADC_CTRL2, 0x180); |
326 | /* left/right diff:PGA/MUX */ | 310 | /* left/right diff:PGA/MUX */ |
327 | codec->write(codec, AD1836_ADC_CTRL3, 0x3A); | 311 | snd_soc_write(codec, AD1836_ADC_CTRL3, 0x3A); |
328 | /* volume */ | 312 | /* volume */ |
329 | codec->write(codec, AD1836_DAC_L1_VOL, 0x3FF); | 313 | snd_soc_write(codec, AD1836_DAC_L1_VOL, 0x3FF); |
330 | codec->write(codec, AD1836_DAC_R1_VOL, 0x3FF); | 314 | snd_soc_write(codec, AD1836_DAC_R1_VOL, 0x3FF); |
331 | codec->write(codec, AD1836_DAC_L2_VOL, 0x3FF); | 315 | snd_soc_write(codec, AD1836_DAC_L2_VOL, 0x3FF); |
332 | codec->write(codec, AD1836_DAC_R2_VOL, 0x3FF); | 316 | snd_soc_write(codec, AD1836_DAC_R2_VOL, 0x3FF); |
333 | codec->write(codec, AD1836_DAC_L3_VOL, 0x3FF); | 317 | snd_soc_write(codec, AD1836_DAC_L3_VOL, 0x3FF); |
334 | codec->write(codec, AD1836_DAC_R3_VOL, 0x3FF); | 318 | snd_soc_write(codec, AD1836_DAC_R3_VOL, 0x3FF); |
335 | 319 | ||
336 | ret = snd_soc_register_codec(codec); | 320 | ret = snd_soc_register_codec(codec); |
337 | if (ret != 0) { | 321 | if (ret != 0) { |
@@ -404,6 +388,8 @@ static int ad1836_remove(struct platform_device *pdev) | |||
404 | struct snd_soc_codec_device soc_codec_dev_ad1836 = { | 388 | struct snd_soc_codec_device soc_codec_dev_ad1836 = { |
405 | .probe = ad1836_probe, | 389 | .probe = ad1836_probe, |
406 | .remove = ad1836_remove, | 390 | .remove = ad1836_remove, |
391 | .suspend = ad1836_soc_suspend, | ||
392 | .resume = ad1836_soc_resume, | ||
407 | }; | 393 | }; |
408 | EXPORT_SYMBOL_GPL(soc_codec_dev_ad1836); | 394 | EXPORT_SYMBOL_GPL(soc_codec_dev_ad1836); |
409 | 395 | ||
diff --git a/sound/soc/codecs/ad1836.h b/sound/soc/codecs/ad1836.h index 7660ee6973c0..e9d90d3951c5 100644 --- a/sound/soc/codecs/ad1836.h +++ b/sound/soc/codecs/ad1836.h | |||
@@ -54,6 +54,7 @@ | |||
54 | #define AD1836_ADC_SERFMT_MASK (7 << 6) | 54 | #define AD1836_ADC_SERFMT_MASK (7 << 6) |
55 | #define AD1836_ADC_SERFMT_PCK256 (0x4 << 6) | 55 | #define AD1836_ADC_SERFMT_PCK256 (0x4 << 6) |
56 | #define AD1836_ADC_SERFMT_PCK128 (0x5 << 6) | 56 | #define AD1836_ADC_SERFMT_PCK128 (0x5 << 6) |
57 | #define AD1836_ADC_AUX (0x6 << 6) | ||
57 | 58 | ||
58 | #define AD1836_ADC_CTRL3 14 | 59 | #define AD1836_ADC_CTRL3 14 |
59 | 60 | ||
diff --git a/sound/soc/codecs/ad1938.c b/sound/soc/codecs/ad1938.c index 5d489186c05b..c233810d463d 100644 --- a/sound/soc/codecs/ad1938.c +++ b/sound/soc/codecs/ad1938.c | |||
@@ -46,6 +46,11 @@ struct ad1938_priv { | |||
46 | u8 reg_cache[AD1938_NUM_REGS]; | 46 | u8 reg_cache[AD1938_NUM_REGS]; |
47 | }; | 47 | }; |
48 | 48 | ||
49 | /* ad1938 register cache & default register settings */ | ||
50 | static const u8 ad1938_reg[AD1938_NUM_REGS] = { | ||
51 | 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 0, | ||
52 | }; | ||
53 | |||
49 | static struct snd_soc_codec *ad1938_codec; | 54 | static struct snd_soc_codec *ad1938_codec; |
50 | struct snd_soc_codec_device soc_codec_dev_ad1938; | 55 | struct snd_soc_codec_device soc_codec_dev_ad1938; |
51 | static int ad1938_register(struct ad1938_priv *ad1938); | 56 | static int ad1938_register(struct ad1938_priv *ad1938); |
@@ -97,6 +102,7 @@ static const struct snd_kcontrol_new ad1938_snd_controls[] = { | |||
97 | static const struct snd_soc_dapm_widget ad1938_dapm_widgets[] = { | 102 | static const struct snd_soc_dapm_widget ad1938_dapm_widgets[] = { |
98 | SND_SOC_DAPM_DAC("DAC", "Playback", AD1938_DAC_CTRL0, 0, 1), | 103 | SND_SOC_DAPM_DAC("DAC", "Playback", AD1938_DAC_CTRL0, 0, 1), |
99 | SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0), | 104 | SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0), |
105 | SND_SOC_DAPM_SUPPLY("PLL_PWR", AD1938_PLL_CLK_CTRL0, 0, 1, NULL, 0), | ||
100 | SND_SOC_DAPM_SUPPLY("ADC_PWR", AD1938_ADC_CTRL0, 0, 1, NULL, 0), | 106 | SND_SOC_DAPM_SUPPLY("ADC_PWR", AD1938_ADC_CTRL0, 0, 1, NULL, 0), |
101 | SND_SOC_DAPM_OUTPUT("DAC1OUT"), | 107 | SND_SOC_DAPM_OUTPUT("DAC1OUT"), |
102 | SND_SOC_DAPM_OUTPUT("DAC2OUT"), | 108 | SND_SOC_DAPM_OUTPUT("DAC2OUT"), |
@@ -107,6 +113,8 @@ static const struct snd_soc_dapm_widget ad1938_dapm_widgets[] = { | |||
107 | }; | 113 | }; |
108 | 114 | ||
109 | static const struct snd_soc_dapm_route audio_paths[] = { | 115 | static const struct snd_soc_dapm_route audio_paths[] = { |
116 | { "DAC", NULL, "PLL_PWR" }, | ||
117 | { "ADC", NULL, "PLL_PWR" }, | ||
110 | { "DAC", NULL, "ADC_PWR" }, | 118 | { "DAC", NULL, "ADC_PWR" }, |
111 | { "ADC", NULL, "ADC_PWR" }, | 119 | { "ADC", NULL, "ADC_PWR" }, |
112 | { "DAC1OUT", "DAC1 Switch", "DAC" }, | 120 | { "DAC1OUT", "DAC1 Switch", "DAC" }, |
@@ -126,30 +134,20 @@ static int ad1938_mute(struct snd_soc_dai *dai, int mute) | |||
126 | struct snd_soc_codec *codec = dai->codec; | 134 | struct snd_soc_codec *codec = dai->codec; |
127 | int reg; | 135 | int reg; |
128 | 136 | ||
129 | reg = codec->read(codec, AD1938_DAC_CTRL2); | 137 | reg = snd_soc_read(codec, AD1938_DAC_CTRL2); |
130 | reg = (mute > 0) ? reg | AD1938_DAC_MASTER_MUTE : reg & | 138 | reg = (mute > 0) ? reg | AD1938_DAC_MASTER_MUTE : reg & |
131 | (~AD1938_DAC_MASTER_MUTE); | 139 | (~AD1938_DAC_MASTER_MUTE); |
132 | codec->write(codec, AD1938_DAC_CTRL2, reg); | 140 | snd_soc_write(codec, AD1938_DAC_CTRL2, reg); |
133 | |||
134 | return 0; | ||
135 | } | ||
136 | |||
137 | static inline int ad1938_pll_powerctrl(struct snd_soc_codec *codec, int cmd) | ||
138 | { | ||
139 | int reg = codec->read(codec, AD1938_PLL_CLK_CTRL0); | ||
140 | reg = (cmd > 0) ? reg & (~AD1938_PLL_POWERDOWN) : reg | | ||
141 | AD1938_PLL_POWERDOWN; | ||
142 | codec->write(codec, AD1938_PLL_CLK_CTRL0, reg); | ||
143 | 141 | ||
144 | return 0; | 142 | return 0; |
145 | } | 143 | } |
146 | 144 | ||
147 | static int ad1938_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, | 145 | static int ad1938_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, |
148 | unsigned int mask, int slots, int width) | 146 | unsigned int rx_mask, int slots, int width) |
149 | { | 147 | { |
150 | struct snd_soc_codec *codec = dai->codec; | 148 | struct snd_soc_codec *codec = dai->codec; |
151 | int dac_reg = codec->read(codec, AD1938_DAC_CTRL1); | 149 | int dac_reg = snd_soc_read(codec, AD1938_DAC_CTRL1); |
152 | int adc_reg = codec->read(codec, AD1938_ADC_CTRL2); | 150 | int adc_reg = snd_soc_read(codec, AD1938_ADC_CTRL2); |
153 | 151 | ||
154 | dac_reg &= ~AD1938_DAC_CHAN_MASK; | 152 | dac_reg &= ~AD1938_DAC_CHAN_MASK; |
155 | adc_reg &= ~AD1938_ADC_CHAN_MASK; | 153 | adc_reg &= ~AD1938_ADC_CHAN_MASK; |
@@ -175,8 +173,8 @@ static int ad1938_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, | |||
175 | return -EINVAL; | 173 | return -EINVAL; |
176 | } | 174 | } |
177 | 175 | ||
178 | codec->write(codec, AD1938_DAC_CTRL1, dac_reg); | 176 | snd_soc_write(codec, AD1938_DAC_CTRL1, dac_reg); |
179 | codec->write(codec, AD1938_ADC_CTRL2, adc_reg); | 177 | snd_soc_write(codec, AD1938_ADC_CTRL2, adc_reg); |
180 | 178 | ||
181 | return 0; | 179 | return 0; |
182 | } | 180 | } |
@@ -187,8 +185,8 @@ static int ad1938_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
187 | struct snd_soc_codec *codec = codec_dai->codec; | 185 | struct snd_soc_codec *codec = codec_dai->codec; |
188 | int adc_reg, dac_reg; | 186 | int adc_reg, dac_reg; |
189 | 187 | ||
190 | adc_reg = codec->read(codec, AD1938_ADC_CTRL2); | 188 | adc_reg = snd_soc_read(codec, AD1938_ADC_CTRL2); |
191 | dac_reg = codec->read(codec, AD1938_DAC_CTRL1); | 189 | dac_reg = snd_soc_read(codec, AD1938_DAC_CTRL1); |
192 | 190 | ||
193 | /* At present, the driver only support AUX ADC mode(SND_SOC_DAIFMT_I2S | 191 | /* At present, the driver only support AUX ADC mode(SND_SOC_DAIFMT_I2S |
194 | * with TDM) and ADC&DAC TDM mode(SND_SOC_DAIFMT_DSP_A) | 192 | * with TDM) and ADC&DAC TDM mode(SND_SOC_DAIFMT_DSP_A) |
@@ -265,8 +263,8 @@ static int ad1938_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
265 | return -EINVAL; | 263 | return -EINVAL; |
266 | } | 264 | } |
267 | 265 | ||
268 | codec->write(codec, AD1938_ADC_CTRL2, adc_reg); | 266 | snd_soc_write(codec, AD1938_ADC_CTRL2, adc_reg); |
269 | codec->write(codec, AD1938_DAC_CTRL1, dac_reg); | 267 | snd_soc_write(codec, AD1938_DAC_CTRL1, dac_reg); |
270 | 268 | ||
271 | return 0; | 269 | return 0; |
272 | } | 270 | } |
@@ -295,134 +293,13 @@ static int ad1938_hw_params(struct snd_pcm_substream *substream, | |||
295 | break; | 293 | break; |
296 | } | 294 | } |
297 | 295 | ||
298 | reg = codec->read(codec, AD1938_DAC_CTRL2); | 296 | reg = snd_soc_read(codec, AD1938_DAC_CTRL2); |
299 | reg = (reg & (~AD1938_DAC_WORD_LEN_MASK)) | word_len; | 297 | reg = (reg & (~AD1938_DAC_WORD_LEN_MASK)) | word_len; |
300 | codec->write(codec, AD1938_DAC_CTRL2, reg); | 298 | snd_soc_write(codec, AD1938_DAC_CTRL2, reg); |
301 | 299 | ||
302 | reg = codec->read(codec, AD1938_ADC_CTRL1); | 300 | reg = snd_soc_read(codec, AD1938_ADC_CTRL1); |
303 | reg = (reg & (~AD1938_ADC_WORD_LEN_MASK)) | word_len; | 301 | reg = (reg & (~AD1938_ADC_WORD_LEN_MASK)) | word_len; |
304 | codec->write(codec, AD1938_ADC_CTRL1, reg); | 302 | snd_soc_write(codec, AD1938_ADC_CTRL1, reg); |
305 | |||
306 | return 0; | ||
307 | } | ||
308 | |||
309 | static int ad1938_set_bias_level(struct snd_soc_codec *codec, | ||
310 | enum snd_soc_bias_level level) | ||
311 | { | ||
312 | switch (level) { | ||
313 | case SND_SOC_BIAS_ON: | ||
314 | ad1938_pll_powerctrl(codec, 1); | ||
315 | break; | ||
316 | case SND_SOC_BIAS_PREPARE: | ||
317 | break; | ||
318 | case SND_SOC_BIAS_STANDBY: | ||
319 | case SND_SOC_BIAS_OFF: | ||
320 | ad1938_pll_powerctrl(codec, 0); | ||
321 | break; | ||
322 | } | ||
323 | codec->bias_level = level; | ||
324 | return 0; | ||
325 | } | ||
326 | |||
327 | /* | ||
328 | * interface to read/write ad1938 register | ||
329 | */ | ||
330 | |||
331 | #define AD1938_SPI_ADDR 0x4 | ||
332 | #define AD1938_SPI_READ 0x1 | ||
333 | #define AD1938_SPI_BUFLEN 3 | ||
334 | |||
335 | /* | ||
336 | * write to the ad1938 register space | ||
337 | */ | ||
338 | |||
339 | static int ad1938_write_reg(struct snd_soc_codec *codec, unsigned int reg, | ||
340 | unsigned int value) | ||
341 | { | ||
342 | u8 *reg_cache = codec->reg_cache; | ||
343 | int ret = 0; | ||
344 | |||
345 | if (value != reg_cache[reg]) { | ||
346 | uint8_t buf[AD1938_SPI_BUFLEN]; | ||
347 | struct spi_transfer t = { | ||
348 | .tx_buf = buf, | ||
349 | .len = AD1938_SPI_BUFLEN, | ||
350 | }; | ||
351 | struct spi_message m; | ||
352 | |||
353 | buf[0] = AD1938_SPI_ADDR << 1; | ||
354 | buf[1] = reg; | ||
355 | buf[2] = value; | ||
356 | spi_message_init(&m); | ||
357 | spi_message_add_tail(&t, &m); | ||
358 | ret = spi_sync(codec->control_data, &m); | ||
359 | if (ret == 0) | ||
360 | reg_cache[reg] = value; | ||
361 | } | ||
362 | |||
363 | return ret; | ||
364 | } | ||
365 | |||
366 | /* | ||
367 | * read from the ad1938 register space cache | ||
368 | */ | ||
369 | |||
370 | static unsigned int ad1938_read_reg_cache(struct snd_soc_codec *codec, | ||
371 | unsigned int reg) | ||
372 | { | ||
373 | u8 *reg_cache = codec->reg_cache; | ||
374 | |||
375 | if (reg >= codec->reg_cache_size) | ||
376 | return -EINVAL; | ||
377 | |||
378 | return reg_cache[reg]; | ||
379 | } | ||
380 | |||
381 | /* | ||
382 | * read from the ad1938 register space | ||
383 | */ | ||
384 | |||
385 | static unsigned int ad1938_read_reg(struct snd_soc_codec *codec, | ||
386 | unsigned int reg) | ||
387 | { | ||
388 | char w_buf[AD1938_SPI_BUFLEN]; | ||
389 | char r_buf[AD1938_SPI_BUFLEN]; | ||
390 | int ret; | ||
391 | |||
392 | struct spi_transfer t = { | ||
393 | .tx_buf = w_buf, | ||
394 | .rx_buf = r_buf, | ||
395 | .len = AD1938_SPI_BUFLEN, | ||
396 | }; | ||
397 | struct spi_message m; | ||
398 | |||
399 | w_buf[0] = (AD1938_SPI_ADDR << 1) | AD1938_SPI_READ; | ||
400 | w_buf[1] = reg; | ||
401 | w_buf[2] = 0; | ||
402 | |||
403 | spi_message_init(&m); | ||
404 | spi_message_add_tail(&t, &m); | ||
405 | ret = spi_sync(codec->control_data, &m); | ||
406 | if (ret == 0) | ||
407 | return r_buf[2]; | ||
408 | else | ||
409 | return -EIO; | ||
410 | } | ||
411 | |||
412 | static int ad1938_fill_cache(struct snd_soc_codec *codec) | ||
413 | { | ||
414 | int i; | ||
415 | u8 *reg_cache = codec->reg_cache; | ||
416 | struct spi_device *spi = codec->control_data; | ||
417 | |||
418 | for (i = 0; i < codec->reg_cache_size; i++) { | ||
419 | int ret = ad1938_read_reg(codec, i); | ||
420 | if (ret == -EIO) { | ||
421 | dev_err(&spi->dev, "AD1938 SPI read failure\n"); | ||
422 | return ret; | ||
423 | } | ||
424 | reg_cache[i] = ret; | ||
425 | } | ||
426 | 303 | ||
427 | return 0; | 304 | return 0; |
428 | } | 305 | } |
@@ -512,32 +389,37 @@ static int ad1938_register(struct ad1938_priv *ad1938) | |||
512 | codec->owner = THIS_MODULE; | 389 | codec->owner = THIS_MODULE; |
513 | codec->dai = &ad1938_dai; | 390 | codec->dai = &ad1938_dai; |
514 | codec->num_dai = 1; | 391 | codec->num_dai = 1; |
515 | codec->write = ad1938_write_reg; | ||
516 | codec->read = ad1938_read_reg_cache; | ||
517 | codec->set_bias_level = ad1938_set_bias_level; | ||
518 | INIT_LIST_HEAD(&codec->dapm_widgets); | 392 | INIT_LIST_HEAD(&codec->dapm_widgets); |
519 | INIT_LIST_HEAD(&codec->dapm_paths); | 393 | INIT_LIST_HEAD(&codec->dapm_paths); |
520 | 394 | ||
521 | ad1938_dai.dev = codec->dev; | 395 | ad1938_dai.dev = codec->dev; |
522 | ad1938_codec = codec; | 396 | ad1938_codec = codec; |
523 | 397 | ||
398 | memcpy(codec->reg_cache, ad1938_reg, AD1938_NUM_REGS); | ||
399 | |||
400 | ret = snd_soc_codec_set_cache_io(codec, 16, 8, SND_SOC_SPI); | ||
401 | if (ret < 0) { | ||
402 | dev_err(codec->dev, "failed to set cache I/O: %d\n", | ||
403 | ret); | ||
404 | kfree(ad1938); | ||
405 | return ret; | ||
406 | } | ||
407 | |||
524 | /* default setting for ad1938 */ | 408 | /* default setting for ad1938 */ |
525 | 409 | ||
526 | /* unmute dac channels */ | 410 | /* unmute dac channels */ |
527 | codec->write(codec, AD1938_DAC_CHNL_MUTE, 0x0); | 411 | snd_soc_write(codec, AD1938_DAC_CHNL_MUTE, 0x0); |
528 | /* de-emphasis: 48kHz, powedown dac */ | 412 | /* de-emphasis: 48kHz, powedown dac */ |
529 | codec->write(codec, AD1938_DAC_CTRL2, 0x1A); | 413 | snd_soc_write(codec, AD1938_DAC_CTRL2, 0x1A); |
530 | /* powerdown dac, dac in tdm mode */ | 414 | /* powerdown dac, dac in tdm mode */ |
531 | codec->write(codec, AD1938_DAC_CTRL0, 0x41); | 415 | snd_soc_write(codec, AD1938_DAC_CTRL0, 0x41); |
532 | /* high-pass filter enable */ | 416 | /* high-pass filter enable */ |
533 | codec->write(codec, AD1938_ADC_CTRL0, 0x3); | 417 | snd_soc_write(codec, AD1938_ADC_CTRL0, 0x3); |
534 | /* sata delay=1, adc aux mode */ | 418 | /* sata delay=1, adc aux mode */ |
535 | codec->write(codec, AD1938_ADC_CTRL1, 0x43); | 419 | snd_soc_write(codec, AD1938_ADC_CTRL1, 0x43); |
536 | /* pll input: mclki/xi */ | 420 | /* pll input: mclki/xi */ |
537 | codec->write(codec, AD1938_PLL_CLK_CTRL0, 0x9D); | 421 | snd_soc_write(codec, AD1938_PLL_CLK_CTRL0, 0x9D); |
538 | codec->write(codec, AD1938_PLL_CLK_CTRL1, 0x04); | 422 | snd_soc_write(codec, AD1938_PLL_CLK_CTRL1, 0x04); |
539 | |||
540 | ad1938_fill_cache(codec); | ||
541 | 423 | ||
542 | ret = snd_soc_register_codec(codec); | 424 | ret = snd_soc_register_codec(codec); |
543 | if (ret != 0) { | 425 | if (ret != 0) { |
@@ -559,7 +441,6 @@ static int ad1938_register(struct ad1938_priv *ad1938) | |||
559 | 441 | ||
560 | static void ad1938_unregister(struct ad1938_priv *ad1938) | 442 | static void ad1938_unregister(struct ad1938_priv *ad1938) |
561 | { | 443 | { |
562 | ad1938_set_bias_level(&ad1938->codec, SND_SOC_BIAS_OFF); | ||
563 | snd_soc_unregister_dai(&ad1938_dai); | 444 | snd_soc_unregister_dai(&ad1938_dai); |
564 | snd_soc_unregister_codec(&ad1938->codec); | 445 | snd_soc_unregister_codec(&ad1938->codec); |
565 | kfree(ad1938); | 446 | kfree(ad1938); |
@@ -593,7 +474,6 @@ static int ad1938_probe(struct platform_device *pdev) | |||
593 | ARRAY_SIZE(ad1938_dapm_widgets)); | 474 | ARRAY_SIZE(ad1938_dapm_widgets)); |
594 | snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths)); | 475 | snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths)); |
595 | 476 | ||
596 | ad1938_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
597 | 477 | ||
598 | pcm_err: | 478 | pcm_err: |
599 | return ret; | 479 | return ret; |
@@ -610,37 +490,9 @@ static int ad1938_remove(struct platform_device *pdev) | |||
610 | return 0; | 490 | return 0; |
611 | } | 491 | } |
612 | 492 | ||
613 | #ifdef CONFIG_PM | ||
614 | static int ad1938_suspend(struct platform_device *pdev, | ||
615 | pm_message_t state) | ||
616 | { | ||
617 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
618 | struct snd_soc_codec *codec = socdev->card->codec; | ||
619 | |||
620 | ad1938_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
621 | return 0; | ||
622 | } | ||
623 | |||
624 | static int ad1938_resume(struct platform_device *pdev) | ||
625 | { | ||
626 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
627 | struct snd_soc_codec *codec = socdev->card->codec; | ||
628 | |||
629 | if (codec->suspend_bias_level == SND_SOC_BIAS_ON) | ||
630 | ad1938_set_bias_level(codec, SND_SOC_BIAS_ON); | ||
631 | |||
632 | return 0; | ||
633 | } | ||
634 | #else | ||
635 | #define ad1938_suspend NULL | ||
636 | #define ad1938_resume NULL | ||
637 | #endif | ||
638 | |||
639 | struct snd_soc_codec_device soc_codec_dev_ad1938 = { | 493 | struct snd_soc_codec_device soc_codec_dev_ad1938 = { |
640 | .probe = ad1938_probe, | 494 | .probe = ad1938_probe, |
641 | .remove = ad1938_remove, | 495 | .remove = ad1938_remove, |
642 | .suspend = ad1938_suspend, | ||
643 | .resume = ad1938_resume, | ||
644 | }; | 496 | }; |
645 | EXPORT_SYMBOL_GPL(soc_codec_dev_ad1938); | 497 | EXPORT_SYMBOL_GPL(soc_codec_dev_ad1938); |
646 | 498 | ||
diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c index 3a14c6fc4f5e..b9ef7e45891d 100644 --- a/sound/soc/codecs/ak4104.c +++ b/sound/soc/codecs/ak4104.c | |||
@@ -185,9 +185,7 @@ struct snd_soc_dai ak4104_dai = { | |||
185 | .stream_name = "Playback", | 185 | .stream_name = "Playback", |
186 | .channels_min = 2, | 186 | .channels_min = 2, |
187 | .channels_max = 2, | 187 | .channels_max = 2, |
188 | .rates = SNDRV_PCM_RATE_44100 | | 188 | .rates = SNDRV_PCM_RATE_8000_192000, |
189 | SNDRV_PCM_RATE_48000 | | ||
190 | SNDRV_PCM_RATE_32000, | ||
191 | .formats = SNDRV_PCM_FMTBIT_S16_LE | | 189 | .formats = SNDRV_PCM_FMTBIT_S16_LE | |
192 | SNDRV_PCM_FMTBIT_S24_3LE | | 190 | SNDRV_PCM_FMTBIT_S24_3LE | |
193 | SNDRV_PCM_FMTBIT_S24_LE | 191 | SNDRV_PCM_FMTBIT_S24_LE |
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index ffe122d1cd76..dfbeb2db61b3 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <sound/initval.h> | 28 | #include <sound/initval.h> |
29 | #include <linux/i2c.h> | 29 | #include <linux/i2c.h> |
30 | #include <linux/delay.h> | 30 | #include <linux/delay.h> |
31 | #include <linux/regulator/consumer.h> | ||
31 | 32 | ||
32 | #include "cs4270.h" | 33 | #include "cs4270.h" |
33 | 34 | ||
@@ -106,6 +107,10 @@ | |||
106 | #define CS4270_MUTE_DAC_A 0x01 | 107 | #define CS4270_MUTE_DAC_A 0x01 |
107 | #define CS4270_MUTE_DAC_B 0x02 | 108 | #define CS4270_MUTE_DAC_B 0x02 |
108 | 109 | ||
110 | static const char *supply_names[] = { | ||
111 | "va", "vd", "vlc" | ||
112 | }; | ||
113 | |||
109 | /* Private data for the CS4270 */ | 114 | /* Private data for the CS4270 */ |
110 | struct cs4270_private { | 115 | struct cs4270_private { |
111 | struct snd_soc_codec codec; | 116 | struct snd_soc_codec codec; |
@@ -114,6 +119,9 @@ struct cs4270_private { | |||
114 | unsigned int mode; /* The mode (I2S or left-justified) */ | 119 | unsigned int mode; /* The mode (I2S or left-justified) */ |
115 | unsigned int slave_mode; | 120 | unsigned int slave_mode; |
116 | unsigned int manual_mute; | 121 | unsigned int manual_mute; |
122 | |||
123 | /* power domain regulators */ | ||
124 | struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)]; | ||
117 | }; | 125 | }; |
118 | 126 | ||
119 | /** | 127 | /** |
@@ -192,6 +200,11 @@ static struct cs4270_mode_ratios cs4270_mode_ratios[] = { | |||
192 | * This function must be called by the machine driver's 'startup' function, | 200 | * This function must be called by the machine driver's 'startup' function, |
193 | * otherwise the list of supported sample rates will not be available in | 201 | * otherwise the list of supported sample rates will not be available in |
194 | * time for ALSA. | 202 | * time for ALSA. |
203 | * | ||
204 | * For setups with variable MCLKs, pass 0 as 'freq' argument. This will cause | ||
205 | * theoretically possible sample rates to be enabled. Call it again with a | ||
206 | * proper value set one the external clock is set (most probably you would do | ||
207 | * that from a machine's driver 'hw_param' hook. | ||
195 | */ | 208 | */ |
196 | static int cs4270_set_dai_sysclk(struct snd_soc_dai *codec_dai, | 209 | static int cs4270_set_dai_sysclk(struct snd_soc_dai *codec_dai, |
197 | int clk_id, unsigned int freq, int dir) | 210 | int clk_id, unsigned int freq, int dir) |
@@ -205,20 +218,27 @@ static int cs4270_set_dai_sysclk(struct snd_soc_dai *codec_dai, | |||
205 | 218 | ||
206 | cs4270->mclk = freq; | 219 | cs4270->mclk = freq; |
207 | 220 | ||
208 | for (i = 0; i < NUM_MCLK_RATIOS; i++) { | 221 | if (cs4270->mclk) { |
209 | unsigned int rate = freq / cs4270_mode_ratios[i].ratio; | 222 | for (i = 0; i < NUM_MCLK_RATIOS; i++) { |
210 | rates |= snd_pcm_rate_to_rate_bit(rate); | 223 | unsigned int rate = freq / cs4270_mode_ratios[i].ratio; |
211 | if (rate < rate_min) | 224 | rates |= snd_pcm_rate_to_rate_bit(rate); |
212 | rate_min = rate; | 225 | if (rate < rate_min) |
213 | if (rate > rate_max) | 226 | rate_min = rate; |
214 | rate_max = rate; | 227 | if (rate > rate_max) |
215 | } | 228 | rate_max = rate; |
216 | /* FIXME: soc should support a rate list */ | 229 | } |
217 | rates &= ~SNDRV_PCM_RATE_KNOT; | 230 | /* FIXME: soc should support a rate list */ |
231 | rates &= ~SNDRV_PCM_RATE_KNOT; | ||
218 | 232 | ||
219 | if (!rates) { | 233 | if (!rates) { |
220 | dev_err(codec->dev, "could not find a valid sample rate\n"); | 234 | dev_err(codec->dev, "could not find a valid sample rate\n"); |
221 | return -EINVAL; | 235 | return -EINVAL; |
236 | } | ||
237 | } else { | ||
238 | /* enable all possible rates */ | ||
239 | rates = SNDRV_PCM_RATE_8000_192000; | ||
240 | rate_min = 8000; | ||
241 | rate_max = 192000; | ||
222 | } | 242 | } |
223 | 243 | ||
224 | codec_dai->playback.rates = rates; | 244 | codec_dai->playback.rates = rates; |
@@ -579,7 +599,8 @@ static int cs4270_probe(struct platform_device *pdev) | |||
579 | { | 599 | { |
580 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 600 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
581 | struct snd_soc_codec *codec = cs4270_codec; | 601 | struct snd_soc_codec *codec = cs4270_codec; |
582 | int ret; | 602 | struct cs4270_private *cs4270 = codec->private_data; |
603 | int i, ret; | ||
583 | 604 | ||
584 | /* Connect the codec to the socdev. snd_soc_new_pcms() needs this. */ | 605 | /* Connect the codec to the socdev. snd_soc_new_pcms() needs this. */ |
585 | socdev->card->codec = codec; | 606 | socdev->card->codec = codec; |
@@ -599,8 +620,26 @@ static int cs4270_probe(struct platform_device *pdev) | |||
599 | goto error_free_pcms; | 620 | goto error_free_pcms; |
600 | } | 621 | } |
601 | 622 | ||
623 | /* get the power supply regulators */ | ||
624 | for (i = 0; i < ARRAY_SIZE(supply_names); i++) | ||
625 | cs4270->supplies[i].supply = supply_names[i]; | ||
626 | |||
627 | ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(cs4270->supplies), | ||
628 | cs4270->supplies); | ||
629 | if (ret < 0) | ||
630 | goto error_free_pcms; | ||
631 | |||
632 | ret = regulator_bulk_enable(ARRAY_SIZE(cs4270->supplies), | ||
633 | cs4270->supplies); | ||
634 | if (ret < 0) | ||
635 | goto error_free_regulators; | ||
636 | |||
602 | return 0; | 637 | return 0; |
603 | 638 | ||
639 | error_free_regulators: | ||
640 | regulator_bulk_free(ARRAY_SIZE(cs4270->supplies), | ||
641 | cs4270->supplies); | ||
642 | |||
604 | error_free_pcms: | 643 | error_free_pcms: |
605 | snd_soc_free_pcms(socdev); | 644 | snd_soc_free_pcms(socdev); |
606 | 645 | ||
@@ -616,8 +655,12 @@ error_free_pcms: | |||
616 | static int cs4270_remove(struct platform_device *pdev) | 655 | static int cs4270_remove(struct platform_device *pdev) |
617 | { | 656 | { |
618 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 657 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
658 | struct snd_soc_codec *codec = cs4270_codec; | ||
659 | struct cs4270_private *cs4270 = codec->private_data; | ||
619 | 660 | ||
620 | snd_soc_free_pcms(socdev); | 661 | snd_soc_free_pcms(socdev); |
662 | regulator_bulk_disable(ARRAY_SIZE(cs4270->supplies), cs4270->supplies); | ||
663 | regulator_bulk_free(ARRAY_SIZE(cs4270->supplies), cs4270->supplies); | ||
621 | 664 | ||
622 | return 0; | 665 | return 0; |
623 | }; | 666 | }; |
@@ -799,17 +842,33 @@ MODULE_DEVICE_TABLE(i2c, cs4270_id); | |||
799 | static int cs4270_soc_suspend(struct platform_device *pdev, pm_message_t mesg) | 842 | static int cs4270_soc_suspend(struct platform_device *pdev, pm_message_t mesg) |
800 | { | 843 | { |
801 | struct snd_soc_codec *codec = cs4270_codec; | 844 | struct snd_soc_codec *codec = cs4270_codec; |
802 | int reg = snd_soc_read(codec, CS4270_PWRCTL) | CS4270_PWRCTL_PDN_ALL; | 845 | struct cs4270_private *cs4270 = codec->private_data; |
846 | int reg, ret; | ||
803 | 847 | ||
804 | return snd_soc_write(codec, CS4270_PWRCTL, reg); | 848 | reg = snd_soc_read(codec, CS4270_PWRCTL) | CS4270_PWRCTL_PDN_ALL; |
849 | if (reg < 0) | ||
850 | return reg; | ||
851 | |||
852 | ret = snd_soc_write(codec, CS4270_PWRCTL, reg); | ||
853 | if (ret < 0) | ||
854 | return ret; | ||
855 | |||
856 | regulator_bulk_disable(ARRAY_SIZE(cs4270->supplies), | ||
857 | cs4270->supplies); | ||
858 | |||
859 | return 0; | ||
805 | } | 860 | } |
806 | 861 | ||
807 | static int cs4270_soc_resume(struct platform_device *pdev) | 862 | static int cs4270_soc_resume(struct platform_device *pdev) |
808 | { | 863 | { |
809 | struct snd_soc_codec *codec = cs4270_codec; | 864 | struct snd_soc_codec *codec = cs4270_codec; |
865 | struct cs4270_private *cs4270 = codec->private_data; | ||
810 | struct i2c_client *i2c_client = codec->control_data; | 866 | struct i2c_client *i2c_client = codec->control_data; |
811 | int reg; | 867 | int reg; |
812 | 868 | ||
869 | regulator_bulk_enable(ARRAY_SIZE(cs4270->supplies), | ||
870 | cs4270->supplies); | ||
871 | |||
813 | /* In case the device was put to hard reset during sleep, we need to | 872 | /* In case the device was put to hard reset during sleep, we need to |
814 | * wait 500ns here before any I2C communication. */ | 873 | * wait 500ns here before any I2C communication. */ |
815 | ndelay(500); | 874 | ndelay(500); |
diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c new file mode 100644 index 000000000000..cf2975a7294a --- /dev/null +++ b/sound/soc/codecs/da7210.c | |||
@@ -0,0 +1,589 @@ | |||
1 | /* | ||
2 | * DA7210 ALSA Soc codec driver | ||
3 | * | ||
4 | * Copyright (c) 2009 Dialog Semiconductor | ||
5 | * Written by David Chen <Dajun.chen@diasemi.com> | ||
6 | * | ||
7 | * Copyright (C) 2009 Renesas Solutions Corp. | ||
8 | * Cleanups by Kuninori Morimoto <morimoto.kuninori@renesas.com> | ||
9 | * | ||
10 | * Tested on SuperH Ecovec24 board with S16/S24 LE in 48KHz using I2S | ||
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 | |||
18 | #include <linux/module.h> | ||
19 | #include <linux/moduleparam.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/init.h> | ||
22 | #include <linux/delay.h> | ||
23 | #include <linux/pm.h> | ||
24 | #include <linux/i2c.h> | ||
25 | #include <linux/platform_device.h> | ||
26 | #include <sound/core.h> | ||
27 | #include <sound/pcm.h> | ||
28 | #include <sound/pcm_params.h> | ||
29 | #include <sound/soc.h> | ||
30 | #include <sound/soc-dapm.h> | ||
31 | #include <sound/tlv.h> | ||
32 | #include <sound/initval.h> | ||
33 | #include <asm/div64.h> | ||
34 | |||
35 | #include "da7210.h" | ||
36 | |||
37 | /* DA7210 register space */ | ||
38 | #define DA7210_STATUS 0x02 | ||
39 | #define DA7210_STARTUP1 0x03 | ||
40 | #define DA7210_MIC_L 0x07 | ||
41 | #define DA7210_MIC_R 0x08 | ||
42 | #define DA7210_INMIX_L 0x0D | ||
43 | #define DA7210_INMIX_R 0x0E | ||
44 | #define DA7210_ADC_HPF 0x0F | ||
45 | #define DA7210_ADC 0x10 | ||
46 | #define DA7210_DAC_HPF 0x14 | ||
47 | #define DA7210_DAC_L 0x15 | ||
48 | #define DA7210_DAC_R 0x16 | ||
49 | #define DA7210_DAC_SEL 0x17 | ||
50 | #define DA7210_OUTMIX_L 0x1C | ||
51 | #define DA7210_OUTMIX_R 0x1D | ||
52 | #define DA7210_HP_L_VOL 0x21 | ||
53 | #define DA7210_HP_R_VOL 0x22 | ||
54 | #define DA7210_HP_CFG 0x23 | ||
55 | #define DA7210_DAI_SRC_SEL 0x25 | ||
56 | #define DA7210_DAI_CFG1 0x26 | ||
57 | #define DA7210_DAI_CFG3 0x28 | ||
58 | #define DA7210_PLL_DIV3 0x2B | ||
59 | #define DA7210_PLL 0x2C | ||
60 | |||
61 | /* STARTUP1 bit fields */ | ||
62 | #define DA7210_SC_MST_EN (1 << 0) | ||
63 | |||
64 | /* MIC_L bit fields */ | ||
65 | #define DA7210_MICBIAS_EN (1 << 6) | ||
66 | #define DA7210_MIC_L_EN (1 << 7) | ||
67 | |||
68 | /* MIC_R bit fields */ | ||
69 | #define DA7210_MIC_R_EN (1 << 7) | ||
70 | |||
71 | /* INMIX_L bit fields */ | ||
72 | #define DA7210_IN_L_EN (1 << 7) | ||
73 | |||
74 | /* INMIX_R bit fields */ | ||
75 | #define DA7210_IN_R_EN (1 << 7) | ||
76 | |||
77 | /* ADC_HPF bit fields */ | ||
78 | #define DA7210_ADC_VOICE_EN (1 << 7) | ||
79 | |||
80 | /* ADC bit fields */ | ||
81 | #define DA7210_ADC_L_EN (1 << 3) | ||
82 | #define DA7210_ADC_R_EN (1 << 7) | ||
83 | |||
84 | /* DAC_HPF fields */ | ||
85 | #define DA7210_DAC_VOICE_EN (1 << 7) | ||
86 | |||
87 | /* DAC_SEL bit fields */ | ||
88 | #define DA7210_DAC_L_SRC_DAI_L (4 << 0) | ||
89 | #define DA7210_DAC_L_EN (1 << 3) | ||
90 | #define DA7210_DAC_R_SRC_DAI_R (5 << 4) | ||
91 | #define DA7210_DAC_R_EN (1 << 7) | ||
92 | |||
93 | /* OUTMIX_L bit fields */ | ||
94 | #define DA7210_OUT_L_EN (1 << 7) | ||
95 | |||
96 | /* OUTMIX_R bit fields */ | ||
97 | #define DA7210_OUT_R_EN (1 << 7) | ||
98 | |||
99 | /* HP_CFG bit fields */ | ||
100 | #define DA7210_HP_2CAP_MODE (1 << 1) | ||
101 | #define DA7210_HP_SENSE_EN (1 << 2) | ||
102 | #define DA7210_HP_L_EN (1 << 3) | ||
103 | #define DA7210_HP_MODE (1 << 6) | ||
104 | #define DA7210_HP_R_EN (1 << 7) | ||
105 | |||
106 | /* DAI_SRC_SEL bit fields */ | ||
107 | #define DA7210_DAI_OUT_L_SRC (6 << 0) | ||
108 | #define DA7210_DAI_OUT_R_SRC (7 << 4) | ||
109 | |||
110 | /* DAI_CFG1 bit fields */ | ||
111 | #define DA7210_DAI_WORD_S16_LE (0 << 0) | ||
112 | #define DA7210_DAI_WORD_S24_LE (2 << 0) | ||
113 | #define DA7210_DAI_FLEN_64BIT (1 << 2) | ||
114 | #define DA7210_DAI_MODE_MASTER (1 << 7) | ||
115 | |||
116 | /* DAI_CFG3 bit fields */ | ||
117 | #define DA7210_DAI_FORMAT_I2SMODE (0 << 0) | ||
118 | #define DA7210_DAI_OE (1 << 3) | ||
119 | #define DA7210_DAI_EN (1 << 7) | ||
120 | |||
121 | /*PLL_DIV3 bit fields */ | ||
122 | #define DA7210_MCLK_RANGE_10_20_MHZ (1 << 4) | ||
123 | #define DA7210_PLL_BYP (1 << 6) | ||
124 | |||
125 | /* PLL bit fields */ | ||
126 | #define DA7210_PLL_FS_48000 (11 << 0) | ||
127 | |||
128 | #define DA7210_VERSION "0.0.1" | ||
129 | |||
130 | /* Codec private data */ | ||
131 | struct da7210_priv { | ||
132 | struct snd_soc_codec codec; | ||
133 | }; | ||
134 | |||
135 | static struct snd_soc_codec *da7210_codec; | ||
136 | |||
137 | /* | ||
138 | * Register cache | ||
139 | */ | ||
140 | static const u8 da7210_reg[] = { | ||
141 | 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* R0 - R7 */ | ||
142 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, /* R8 - RF */ | ||
143 | 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x10, 0x54, /* R10 - R17 */ | ||
144 | 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* R18 - R1F */ | ||
145 | 0x00, 0x00, 0x00, 0x02, 0x00, 0x76, 0x00, 0x00, /* R20 - R27 */ | ||
146 | 0x04, 0x00, 0x00, 0x30, 0x2A, 0x00, 0x40, 0x00, /* R28 - R2F */ | ||
147 | 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, /* R30 - R37 */ | ||
148 | 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, /* R38 - R3F */ | ||
149 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* R40 - R4F */ | ||
150 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* R48 - R4F */ | ||
151 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* R50 - R57 */ | ||
152 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* R58 - R5F */ | ||
153 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* R60 - R67 */ | ||
154 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* R68 - R6F */ | ||
155 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* R70 - R77 */ | ||
156 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x54, 0x00, /* R78 - R7F */ | ||
157 | 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, /* R80 - R87 */ | ||
158 | 0x00, /* R88 */ | ||
159 | }; | ||
160 | |||
161 | /* | ||
162 | * Read da7210 register cache | ||
163 | */ | ||
164 | static inline u32 da7210_read_reg_cache(struct snd_soc_codec *codec, u32 reg) | ||
165 | { | ||
166 | u8 *cache = codec->reg_cache; | ||
167 | BUG_ON(reg > ARRAY_SIZE(da7210_reg)); | ||
168 | return cache[reg]; | ||
169 | } | ||
170 | |||
171 | /* | ||
172 | * Write to the da7210 register space | ||
173 | */ | ||
174 | static int da7210_write(struct snd_soc_codec *codec, u32 reg, u32 value) | ||
175 | { | ||
176 | u8 *cache = codec->reg_cache; | ||
177 | u8 data[2]; | ||
178 | |||
179 | BUG_ON(codec->volatile_register); | ||
180 | |||
181 | data[0] = reg & 0xff; | ||
182 | data[1] = value & 0xff; | ||
183 | |||
184 | if (reg >= codec->reg_cache_size) | ||
185 | return -EIO; | ||
186 | |||
187 | if (2 != codec->hw_write(codec->control_data, data, 2)) | ||
188 | return -EIO; | ||
189 | |||
190 | cache[reg] = value; | ||
191 | return 0; | ||
192 | } | ||
193 | |||
194 | /* | ||
195 | * Read from the da7210 register space. | ||
196 | */ | ||
197 | static inline u32 da7210_read(struct snd_soc_codec *codec, u32 reg) | ||
198 | { | ||
199 | if (DA7210_STATUS == reg) | ||
200 | return i2c_smbus_read_byte_data(codec->control_data, reg); | ||
201 | |||
202 | return da7210_read_reg_cache(codec, reg); | ||
203 | } | ||
204 | |||
205 | static int da7210_startup(struct snd_pcm_substream *substream, | ||
206 | struct snd_soc_dai *dai) | ||
207 | { | ||
208 | int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; | ||
209 | struct snd_soc_codec *codec = dai->codec; | ||
210 | |||
211 | if (is_play) { | ||
212 | /* PlayBack Volume 40 */ | ||
213 | snd_soc_update_bits(codec, DA7210_HP_L_VOL, 0x3F, 40); | ||
214 | snd_soc_update_bits(codec, DA7210_HP_R_VOL, 0x3F, 40); | ||
215 | |||
216 | /* Enable Out */ | ||
217 | snd_soc_update_bits(codec, DA7210_OUTMIX_L, 0x1F, 0x10); | ||
218 | snd_soc_update_bits(codec, DA7210_OUTMIX_R, 0x1F, 0x10); | ||
219 | |||
220 | } else { | ||
221 | /* Volume 7 */ | ||
222 | snd_soc_update_bits(codec, DA7210_MIC_L, 0x7, 0x7); | ||
223 | snd_soc_update_bits(codec, DA7210_MIC_R, 0x7, 0x7); | ||
224 | |||
225 | /* Enable Mic */ | ||
226 | snd_soc_update_bits(codec, DA7210_INMIX_L, 0x1F, 0x1); | ||
227 | snd_soc_update_bits(codec, DA7210_INMIX_R, 0x1F, 0x1); | ||
228 | } | ||
229 | |||
230 | return 0; | ||
231 | } | ||
232 | |||
233 | /* | ||
234 | * Set PCM DAI word length. | ||
235 | */ | ||
236 | static int da7210_hw_params(struct snd_pcm_substream *substream, | ||
237 | struct snd_pcm_hw_params *params, | ||
238 | struct snd_soc_dai *dai) | ||
239 | { | ||
240 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
241 | struct snd_soc_device *socdev = rtd->socdev; | ||
242 | struct snd_soc_codec *codec = socdev->card->codec; | ||
243 | u32 dai_cfg1; | ||
244 | u32 reg, mask; | ||
245 | |||
246 | /* set DAI source to Left and Right ADC */ | ||
247 | da7210_write(codec, DA7210_DAI_SRC_SEL, | ||
248 | DA7210_DAI_OUT_R_SRC | DA7210_DAI_OUT_L_SRC); | ||
249 | |||
250 | /* Enable DAI */ | ||
251 | da7210_write(codec, DA7210_DAI_CFG3, DA7210_DAI_OE | DA7210_DAI_EN); | ||
252 | |||
253 | dai_cfg1 = 0xFC & da7210_read(codec, DA7210_DAI_CFG1); | ||
254 | |||
255 | switch (params_format(params)) { | ||
256 | case SNDRV_PCM_FORMAT_S16_LE: | ||
257 | dai_cfg1 |= DA7210_DAI_WORD_S16_LE; | ||
258 | break; | ||
259 | case SNDRV_PCM_FORMAT_S24_LE: | ||
260 | dai_cfg1 |= DA7210_DAI_WORD_S24_LE; | ||
261 | break; | ||
262 | default: | ||
263 | return -EINVAL; | ||
264 | } | ||
265 | |||
266 | da7210_write(codec, DA7210_DAI_CFG1, dai_cfg1); | ||
267 | |||
268 | /* FIXME | ||
269 | * | ||
270 | * It support 48K only now | ||
271 | */ | ||
272 | switch (params_rate(params)) { | ||
273 | case 48000: | ||
274 | if (SNDRV_PCM_STREAM_PLAYBACK == substream->stream) { | ||
275 | reg = DA7210_DAC_HPF; | ||
276 | mask = DA7210_DAC_VOICE_EN; | ||
277 | } else { | ||
278 | reg = DA7210_ADC_HPF; | ||
279 | mask = DA7210_ADC_VOICE_EN; | ||
280 | } | ||
281 | break; | ||
282 | default: | ||
283 | return -EINVAL; | ||
284 | } | ||
285 | |||
286 | snd_soc_update_bits(codec, reg, mask, 0); | ||
287 | |||
288 | return 0; | ||
289 | } | ||
290 | |||
291 | /* | ||
292 | * Set DAI mode and Format | ||
293 | */ | ||
294 | static int da7210_set_dai_fmt(struct snd_soc_dai *codec_dai, u32 fmt) | ||
295 | { | ||
296 | struct snd_soc_codec *codec = codec_dai->codec; | ||
297 | u32 dai_cfg1; | ||
298 | u32 dai_cfg3; | ||
299 | |||
300 | dai_cfg1 = 0x7f & da7210_read(codec, DA7210_DAI_CFG1); | ||
301 | dai_cfg3 = 0xfc & da7210_read(codec, DA7210_DAI_CFG3); | ||
302 | |||
303 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
304 | case SND_SOC_DAIFMT_CBM_CFM: | ||
305 | dai_cfg1 |= DA7210_DAI_MODE_MASTER; | ||
306 | break; | ||
307 | default: | ||
308 | return -EINVAL; | ||
309 | } | ||
310 | |||
311 | /* FIXME | ||
312 | * | ||
313 | * It support I2S only now | ||
314 | */ | ||
315 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
316 | case SND_SOC_DAIFMT_I2S: | ||
317 | dai_cfg3 |= DA7210_DAI_FORMAT_I2SMODE; | ||
318 | break; | ||
319 | default: | ||
320 | return -EINVAL; | ||
321 | } | ||
322 | |||
323 | /* FIXME | ||
324 | * | ||
325 | * It support 64bit data transmission only now | ||
326 | */ | ||
327 | dai_cfg1 |= DA7210_DAI_FLEN_64BIT; | ||
328 | |||
329 | da7210_write(codec, DA7210_DAI_CFG1, dai_cfg1); | ||
330 | da7210_write(codec, DA7210_DAI_CFG3, dai_cfg3); | ||
331 | |||
332 | return 0; | ||
333 | } | ||
334 | |||
335 | #define DA7210_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE) | ||
336 | |||
337 | /* DAI operations */ | ||
338 | static struct snd_soc_dai_ops da7210_dai_ops = { | ||
339 | .startup = da7210_startup, | ||
340 | .hw_params = da7210_hw_params, | ||
341 | .set_fmt = da7210_set_dai_fmt, | ||
342 | }; | ||
343 | |||
344 | struct snd_soc_dai da7210_dai = { | ||
345 | .name = "DA7210 IIS", | ||
346 | .id = 0, | ||
347 | /* playback capabilities */ | ||
348 | .playback = { | ||
349 | .stream_name = "Playback", | ||
350 | .channels_min = 1, | ||
351 | .channels_max = 2, | ||
352 | .rates = SNDRV_PCM_RATE_8000_96000, | ||
353 | .formats = DA7210_FORMATS, | ||
354 | }, | ||
355 | /* capture capabilities */ | ||
356 | .capture = { | ||
357 | .stream_name = "Capture", | ||
358 | .channels_min = 1, | ||
359 | .channels_max = 2, | ||
360 | .rates = SNDRV_PCM_RATE_8000_96000, | ||
361 | .formats = DA7210_FORMATS, | ||
362 | }, | ||
363 | .ops = &da7210_dai_ops, | ||
364 | }; | ||
365 | EXPORT_SYMBOL_GPL(da7210_dai); | ||
366 | |||
367 | /* | ||
368 | * Initialize the DA7210 driver | ||
369 | * register the mixer and dsp interfaces with the kernel | ||
370 | */ | ||
371 | static int da7210_init(struct da7210_priv *da7210) | ||
372 | { | ||
373 | struct snd_soc_codec *codec = &da7210->codec; | ||
374 | int ret = 0; | ||
375 | |||
376 | if (da7210_codec) { | ||
377 | dev_err(codec->dev, "Another da7210 is registered\n"); | ||
378 | return -EINVAL; | ||
379 | } | ||
380 | |||
381 | mutex_init(&codec->mutex); | ||
382 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
383 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
384 | |||
385 | codec->private_data = da7210; | ||
386 | codec->name = "DA7210"; | ||
387 | codec->owner = THIS_MODULE; | ||
388 | codec->read = da7210_read; | ||
389 | codec->write = da7210_write; | ||
390 | codec->dai = &da7210_dai; | ||
391 | codec->num_dai = 1; | ||
392 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
393 | codec->reg_cache_size = ARRAY_SIZE(da7210_reg); | ||
394 | codec->reg_cache = kmemdup(da7210_reg, | ||
395 | sizeof(da7210_reg), GFP_KERNEL); | ||
396 | |||
397 | if (!codec->reg_cache) | ||
398 | return -ENOMEM; | ||
399 | |||
400 | da7210_dai.dev = codec->dev; | ||
401 | da7210_codec = codec; | ||
402 | |||
403 | ret = snd_soc_register_codec(codec); | ||
404 | if (ret) { | ||
405 | dev_err(codec->dev, "Failed to register CODEC: %d\n", ret); | ||
406 | goto init_err; | ||
407 | } | ||
408 | |||
409 | ret = snd_soc_register_dai(&da7210_dai); | ||
410 | if (ret) { | ||
411 | dev_err(codec->dev, "Failed to register DAI: %d\n", ret); | ||
412 | goto init_err; | ||
413 | } | ||
414 | |||
415 | /* FIXME | ||
416 | * | ||
417 | * This driver use fixed value here | ||
418 | */ | ||
419 | |||
420 | /* | ||
421 | * ADC settings | ||
422 | */ | ||
423 | |||
424 | /* Enable Left & Right MIC PGA and Mic Bias */ | ||
425 | da7210_write(codec, DA7210_MIC_L, DA7210_MIC_L_EN | DA7210_MICBIAS_EN); | ||
426 | da7210_write(codec, DA7210_MIC_R, DA7210_MIC_R_EN); | ||
427 | |||
428 | /* Enable Left and Right input PGA */ | ||
429 | da7210_write(codec, DA7210_INMIX_L, DA7210_IN_L_EN); | ||
430 | da7210_write(codec, DA7210_INMIX_R, DA7210_IN_R_EN); | ||
431 | |||
432 | /* Enable Left and Right ADC */ | ||
433 | da7210_write(codec, DA7210_ADC, DA7210_ADC_L_EN | DA7210_ADC_R_EN); | ||
434 | |||
435 | /* | ||
436 | * DAC settings | ||
437 | */ | ||
438 | |||
439 | /* Enable Left and Right DAC */ | ||
440 | da7210_write(codec, DA7210_DAC_SEL, | ||
441 | DA7210_DAC_L_SRC_DAI_L | DA7210_DAC_L_EN | | ||
442 | DA7210_DAC_R_SRC_DAI_R | DA7210_DAC_R_EN); | ||
443 | |||
444 | /* Enable Left and Right out PGA */ | ||
445 | da7210_write(codec, DA7210_OUTMIX_L, DA7210_OUT_L_EN); | ||
446 | da7210_write(codec, DA7210_OUTMIX_R, DA7210_OUT_R_EN); | ||
447 | |||
448 | /* Enable Left and Right HeadPhone PGA */ | ||
449 | da7210_write(codec, DA7210_HP_CFG, | ||
450 | DA7210_HP_2CAP_MODE | DA7210_HP_SENSE_EN | | ||
451 | DA7210_HP_L_EN | DA7210_HP_MODE | DA7210_HP_R_EN); | ||
452 | |||
453 | /* Diable PLL and bypass it */ | ||
454 | da7210_write(codec, DA7210_PLL, DA7210_PLL_FS_48000); | ||
455 | |||
456 | /* Bypass PLL and set MCLK freq rang to 10-20MHz */ | ||
457 | da7210_write(codec, DA7210_PLL_DIV3, | ||
458 | DA7210_MCLK_RANGE_10_20_MHZ | DA7210_PLL_BYP); | ||
459 | |||
460 | /* Activate all enabled subsystem */ | ||
461 | da7210_write(codec, DA7210_STARTUP1, DA7210_SC_MST_EN); | ||
462 | |||
463 | return ret; | ||
464 | |||
465 | init_err: | ||
466 | kfree(codec->reg_cache); | ||
467 | codec->reg_cache = NULL; | ||
468 | |||
469 | return ret; | ||
470 | |||
471 | } | ||
472 | |||
473 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
474 | static int __devinit da7210_i2c_probe(struct i2c_client *i2c, | ||
475 | const struct i2c_device_id *id) | ||
476 | { | ||
477 | struct da7210_priv *da7210; | ||
478 | struct snd_soc_codec *codec; | ||
479 | int ret; | ||
480 | |||
481 | da7210 = kzalloc(sizeof(struct da7210_priv), GFP_KERNEL); | ||
482 | if (!da7210) | ||
483 | return -ENOMEM; | ||
484 | |||
485 | codec = &da7210->codec; | ||
486 | codec->dev = &i2c->dev; | ||
487 | |||
488 | i2c_set_clientdata(i2c, da7210); | ||
489 | codec->control_data = i2c; | ||
490 | |||
491 | ret = da7210_init(da7210); | ||
492 | if (ret < 0) | ||
493 | pr_err("Failed to initialise da7210 audio codec\n"); | ||
494 | |||
495 | return ret; | ||
496 | } | ||
497 | |||
498 | static int __devexit da7210_i2c_remove(struct i2c_client *client) | ||
499 | { | ||
500 | struct da7210_priv *da7210 = i2c_get_clientdata(client); | ||
501 | |||
502 | snd_soc_unregister_dai(&da7210_dai); | ||
503 | kfree(da7210->codec.reg_cache); | ||
504 | kfree(da7210); | ||
505 | da7210_codec = NULL; | ||
506 | |||
507 | return 0; | ||
508 | } | ||
509 | |||
510 | static const struct i2c_device_id da7210_i2c_id[] = { | ||
511 | { "da7210", 0 }, | ||
512 | { } | ||
513 | }; | ||
514 | MODULE_DEVICE_TABLE(i2c, da7210_i2c_id); | ||
515 | |||
516 | /* I2C codec control layer */ | ||
517 | static struct i2c_driver da7210_i2c_driver = { | ||
518 | .driver = { | ||
519 | .name = "DA7210 I2C Codec", | ||
520 | .owner = THIS_MODULE, | ||
521 | }, | ||
522 | .probe = da7210_i2c_probe, | ||
523 | .remove = __devexit_p(da7210_i2c_remove), | ||
524 | .id_table = da7210_i2c_id, | ||
525 | }; | ||
526 | #endif | ||
527 | |||
528 | static int da7210_probe(struct platform_device *pdev) | ||
529 | { | ||
530 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
531 | struct snd_soc_codec *codec; | ||
532 | int ret; | ||
533 | |||
534 | if (!da7210_codec) { | ||
535 | dev_err(&pdev->dev, "Codec device not registered\n"); | ||
536 | return -ENODEV; | ||
537 | } | ||
538 | |||
539 | socdev->card->codec = da7210_codec; | ||
540 | codec = da7210_codec; | ||
541 | |||
542 | /* Register pcms */ | ||
543 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
544 | if (ret < 0) | ||
545 | goto pcm_err; | ||
546 | |||
547 | dev_info(&pdev->dev, "DA7210 Audio Codec %s\n", DA7210_VERSION); | ||
548 | |||
549 | pcm_err: | ||
550 | return ret; | ||
551 | } | ||
552 | |||
553 | static int da7210_remove(struct platform_device *pdev) | ||
554 | { | ||
555 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
556 | |||
557 | snd_soc_free_pcms(socdev); | ||
558 | snd_soc_dapm_free(socdev); | ||
559 | |||
560 | return 0; | ||
561 | } | ||
562 | |||
563 | struct snd_soc_codec_device soc_codec_dev_da7210 = { | ||
564 | .probe = da7210_probe, | ||
565 | .remove = da7210_remove, | ||
566 | }; | ||
567 | EXPORT_SYMBOL_GPL(soc_codec_dev_da7210); | ||
568 | |||
569 | static int __init da7210_modinit(void) | ||
570 | { | ||
571 | int ret = 0; | ||
572 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
573 | ret = i2c_add_driver(&da7210_i2c_driver); | ||
574 | #endif | ||
575 | return ret; | ||
576 | } | ||
577 | module_init(da7210_modinit); | ||
578 | |||
579 | static void __exit da7210_exit(void) | ||
580 | { | ||
581 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
582 | i2c_del_driver(&da7210_i2c_driver); | ||
583 | #endif | ||
584 | } | ||
585 | module_exit(da7210_exit); | ||
586 | |||
587 | MODULE_DESCRIPTION("ASoC DA7210 driver"); | ||
588 | MODULE_AUTHOR("David Chen, Kuninori Morimoto"); | ||
589 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/da7210.h b/sound/soc/codecs/da7210.h new file mode 100644 index 000000000000..390d621eb742 --- /dev/null +++ b/sound/soc/codecs/da7210.h | |||
@@ -0,0 +1,24 @@ | |||
1 | /* | ||
2 | * da7210.h -- audio driver for da7210 | ||
3 | * | ||
4 | * Copyright (c) 2009 Dialog Semiconductor | ||
5 | * Written by David Chen <Dajun.chen@diasemi.com> | ||
6 | * | ||
7 | * Copyright (C) 2009 Renesas Solutions Corp. | ||
8 | * Cleanups by Kuninori Morimoto <morimoto.kuninori@renesas.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 | #ifndef _DA7210_H | ||
18 | #define _DA7210_H | ||
19 | |||
20 | extern struct snd_soc_dai da7210_dai; | ||
21 | extern struct snd_soc_codec_device soc_codec_dev_da7210; | ||
22 | |||
23 | #endif | ||
24 | |||
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 2b4dc2b0b017..e4b946a19ea3 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c | |||
@@ -765,9 +765,10 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream, | |||
765 | struct snd_soc_codec *codec = socdev->card->codec; | 765 | struct snd_soc_codec *codec = socdev->card->codec; |
766 | struct aic3x_priv *aic3x = codec->private_data; | 766 | struct aic3x_priv *aic3x = codec->private_data; |
767 | int codec_clk = 0, bypass_pll = 0, fsref, last_clk = 0; | 767 | int codec_clk = 0, bypass_pll = 0, fsref, last_clk = 0; |
768 | u8 data, r, p, pll_q, pll_p = 1, pll_r = 1, pll_j = 1; | 768 | u8 data, j, r, p, pll_q, pll_p = 1, pll_r = 1, pll_j = 1; |
769 | u16 pll_d = 1; | 769 | u16 d, pll_d = 1; |
770 | u8 reg; | 770 | u8 reg; |
771 | int clk; | ||
771 | 772 | ||
772 | /* select data word length */ | 773 | /* select data word length */ |
773 | data = | 774 | data = |
@@ -833,48 +834,70 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream, | |||
833 | if (bypass_pll) | 834 | if (bypass_pll) |
834 | return 0; | 835 | return 0; |
835 | 836 | ||
836 | /* Use PLL | 837 | /* Use PLL, compute apropriate setup for j, d, r and p, the closest |
837 | * find an apropriate setup for j, d, r and p by iterating over | 838 | * one wins the game. Try with d==0 first, next with d!=0. |
838 | * p and r - j and d are calculated for each fraction. | 839 | * Constraints for j are according to the datasheet. |
839 | * Up to 128 values are probed, the closest one wins the game. | ||
840 | * The sysclk is divided by 1000 to prevent integer overflows. | 840 | * The sysclk is divided by 1000 to prevent integer overflows. |
841 | */ | 841 | */ |
842 | |||
842 | codec_clk = (2048 * fsref) / (aic3x->sysclk / 1000); | 843 | codec_clk = (2048 * fsref) / (aic3x->sysclk / 1000); |
843 | 844 | ||
844 | for (r = 1; r <= 16; r++) | 845 | for (r = 1; r <= 16; r++) |
845 | for (p = 1; p <= 8; p++) { | 846 | for (p = 1; p <= 8; p++) { |
846 | int clk, tmp = (codec_clk * pll_r * 10) / pll_p; | 847 | for (j = 4; j <= 55; j++) { |
847 | u8 j = tmp / 10000; | 848 | /* This is actually 1000*((j+(d/10000))*r)/p |
848 | u16 d = tmp % 10000; | 849 | * The term had to be converted to get |
850 | * rid of the division by 10000; d = 0 here | ||
851 | */ | ||
852 | int tmp_clk = (1000 * j * r) / p; | ||
853 | |||
854 | /* Check whether this values get closer than | ||
855 | * the best ones we had before | ||
856 | */ | ||
857 | if (abs(codec_clk - tmp_clk) < | ||
858 | abs(codec_clk - last_clk)) { | ||
859 | pll_j = j; pll_d = 0; | ||
860 | pll_r = r; pll_p = p; | ||
861 | last_clk = tmp_clk; | ||
862 | } | ||
863 | |||
864 | /* Early exit for exact matches */ | ||
865 | if (tmp_clk == codec_clk) | ||
866 | goto found; | ||
867 | } | ||
868 | } | ||
849 | 869 | ||
850 | if (j > 63) | 870 | /* try with d != 0 */ |
851 | continue; | 871 | for (p = 1; p <= 8; p++) { |
872 | j = codec_clk * p / 1000; | ||
852 | 873 | ||
853 | if (d != 0 && aic3x->sysclk < 10000000) | 874 | if (j < 4 || j > 11) |
854 | continue; | 875 | continue; |
855 | 876 | ||
856 | /* This is actually 1000 * ((j + (d/10000)) * r) / p | 877 | /* do not use codec_clk here since we'd loose precision */ |
857 | * The term had to be converted to get rid of the | 878 | d = ((2048 * p * fsref) - j * aic3x->sysclk) |
858 | * division by 10000 */ | 879 | * 100 / (aic3x->sysclk/100); |
859 | clk = ((10000 * j * r) + (d * r)) / (10 * p); | ||
860 | 880 | ||
861 | /* check whether this values get closer than the best | 881 | clk = (10000 * j + d) / (10 * p); |
862 | * ones we had before */ | ||
863 | if (abs(codec_clk - clk) < abs(codec_clk - last_clk)) { | ||
864 | pll_j = j; pll_d = d; pll_r = r; pll_p = p; | ||
865 | last_clk = clk; | ||
866 | } | ||
867 | 882 | ||
868 | /* Early exit for exact matches */ | 883 | /* check whether this values get closer than the best |
869 | if (clk == codec_clk) | 884 | * ones we had before */ |
870 | break; | 885 | if (abs(codec_clk - clk) < abs(codec_clk - last_clk)) { |
886 | pll_j = j; pll_d = d; pll_r = 1; pll_p = p; | ||
887 | last_clk = clk; | ||
871 | } | 888 | } |
872 | 889 | ||
890 | /* Early exit for exact matches */ | ||
891 | if (clk == codec_clk) | ||
892 | goto found; | ||
893 | } | ||
894 | |||
873 | if (last_clk == 0) { | 895 | if (last_clk == 0) { |
874 | printk(KERN_ERR "%s(): unable to setup PLL\n", __func__); | 896 | printk(KERN_ERR "%s(): unable to setup PLL\n", __func__); |
875 | return -EINVAL; | 897 | return -EINVAL; |
876 | } | 898 | } |
877 | 899 | ||
900 | found: | ||
878 | data = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); | 901 | data = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); |
879 | aic3x_write(codec, AIC3X_PLL_PROGA_REG, data | (pll_p << PLLP_SHIFT)); | 902 | aic3x_write(codec, AIC3X_PLL_PROGA_REG, data | (pll_p << PLLP_SHIFT)); |
880 | aic3x_write(codec, AIC3X_OVRF_STATUS_AND_PLLR_REG, pll_r << PLLR_SHIFT); | 903 | aic3x_write(codec, AIC3X_OVRF_STATUS_AND_PLLR_REG, pll_r << PLLR_SHIFT); |
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index 9c8903dbe647..f9f367d29a90 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <linux/platform_device.h> | 30 | #include <linux/platform_device.h> |
31 | #include <linux/interrupt.h> | 31 | #include <linux/interrupt.h> |
32 | #include <linux/gpio.h> | 32 | #include <linux/gpio.h> |
33 | #include <linux/regulator/consumer.h> | ||
33 | #include <sound/core.h> | 34 | #include <sound/core.h> |
34 | #include <sound/pcm.h> | 35 | #include <sound/pcm.h> |
35 | #include <sound/pcm_params.h> | 36 | #include <sound/pcm_params.h> |
@@ -58,11 +59,26 @@ enum dac33_state { | |||
58 | DAC33_FLUSH, | 59 | DAC33_FLUSH, |
59 | }; | 60 | }; |
60 | 61 | ||
62 | enum dac33_fifo_modes { | ||
63 | DAC33_FIFO_BYPASS = 0, | ||
64 | DAC33_FIFO_MODE1, | ||
65 | DAC33_FIFO_MODE7, | ||
66 | DAC33_FIFO_LAST_MODE, | ||
67 | }; | ||
68 | |||
69 | #define DAC33_NUM_SUPPLIES 3 | ||
70 | static const char *dac33_supply_names[DAC33_NUM_SUPPLIES] = { | ||
71 | "AVDD", | ||
72 | "DVDD", | ||
73 | "IOVDD", | ||
74 | }; | ||
75 | |||
61 | struct tlv320dac33_priv { | 76 | struct tlv320dac33_priv { |
62 | struct mutex mutex; | 77 | struct mutex mutex; |
63 | struct workqueue_struct *dac33_wq; | 78 | struct workqueue_struct *dac33_wq; |
64 | struct work_struct work; | 79 | struct work_struct work; |
65 | struct snd_soc_codec codec; | 80 | struct snd_soc_codec codec; |
81 | struct regulator_bulk_data supplies[DAC33_NUM_SUPPLIES]; | ||
66 | int power_gpio; | 82 | int power_gpio; |
67 | int chip_power; | 83 | int chip_power; |
68 | int irq; | 84 | int irq; |
@@ -73,8 +89,9 @@ struct tlv320dac33_priv { | |||
73 | * this */ | 89 | * this */ |
74 | unsigned int nsample_max; /* nsample should not be higher than | 90 | unsigned int nsample_max; /* nsample should not be higher than |
75 | * this */ | 91 | * this */ |
76 | unsigned int nsample_switch; /* Use FIFO or bypass FIFO switch */ | 92 | enum dac33_fifo_modes fifo_mode;/* FIFO mode selection */ |
77 | unsigned int nsample; /* burst read amount from host */ | 93 | unsigned int nsample; /* burst read amount from host */ |
94 | u8 burst_bclkdiv; /* BCLK divider value in burst mode */ | ||
78 | 95 | ||
79 | enum dac33_state state; | 96 | enum dac33_state state; |
80 | }; | 97 | }; |
@@ -297,28 +314,49 @@ static inline void dac33_soft_power(struct snd_soc_codec *codec, int power) | |||
297 | dac33_write(codec, DAC33_PWR_CTRL, reg); | 314 | dac33_write(codec, DAC33_PWR_CTRL, reg); |
298 | } | 315 | } |
299 | 316 | ||
300 | static void dac33_hard_power(struct snd_soc_codec *codec, int power) | 317 | static int dac33_hard_power(struct snd_soc_codec *codec, int power) |
301 | { | 318 | { |
302 | struct tlv320dac33_priv *dac33 = codec->private_data; | 319 | struct tlv320dac33_priv *dac33 = codec->private_data; |
320 | int ret; | ||
303 | 321 | ||
304 | mutex_lock(&dac33->mutex); | 322 | mutex_lock(&dac33->mutex); |
305 | if (power) { | 323 | if (power) { |
306 | if (dac33->power_gpio >= 0) { | 324 | ret = regulator_bulk_enable(ARRAY_SIZE(dac33->supplies), |
307 | gpio_set_value(dac33->power_gpio, 1); | 325 | dac33->supplies); |
308 | dac33->chip_power = 1; | 326 | if (ret != 0) { |
309 | /* Restore registers */ | 327 | dev_err(codec->dev, |
310 | dac33_restore_regs(codec); | 328 | "Failed to enable supplies: %d\n", ret); |
329 | goto exit; | ||
311 | } | 330 | } |
331 | |||
332 | if (dac33->power_gpio >= 0) | ||
333 | gpio_set_value(dac33->power_gpio, 1); | ||
334 | |||
335 | dac33->chip_power = 1; | ||
336 | |||
337 | /* Restore registers */ | ||
338 | dac33_restore_regs(codec); | ||
339 | |||
312 | dac33_soft_power(codec, 1); | 340 | dac33_soft_power(codec, 1); |
313 | } else { | 341 | } else { |
314 | dac33_soft_power(codec, 0); | 342 | dac33_soft_power(codec, 0); |
315 | if (dac33->power_gpio >= 0) { | 343 | if (dac33->power_gpio >= 0) |
316 | gpio_set_value(dac33->power_gpio, 0); | 344 | gpio_set_value(dac33->power_gpio, 0); |
317 | dac33->chip_power = 0; | 345 | |
346 | ret = regulator_bulk_disable(ARRAY_SIZE(dac33->supplies), | ||
347 | dac33->supplies); | ||
348 | if (ret != 0) { | ||
349 | dev_err(codec->dev, | ||
350 | "Failed to disable supplies: %d\n", ret); | ||
351 | goto exit; | ||
318 | } | 352 | } |
353 | |||
354 | dac33->chip_power = 0; | ||
319 | } | 355 | } |
320 | mutex_unlock(&dac33->mutex); | ||
321 | 356 | ||
357 | exit: | ||
358 | mutex_unlock(&dac33->mutex); | ||
359 | return ret; | ||
322 | } | 360 | } |
323 | 361 | ||
324 | static int dac33_get_nsample(struct snd_kcontrol *kcontrol, | 362 | static int dac33_get_nsample(struct snd_kcontrol *kcontrol, |
@@ -351,39 +389,48 @@ static int dac33_set_nsample(struct snd_kcontrol *kcontrol, | |||
351 | return ret; | 389 | return ret; |
352 | } | 390 | } |
353 | 391 | ||
354 | static int dac33_get_nsample_switch(struct snd_kcontrol *kcontrol, | 392 | static int dac33_get_fifo_mode(struct snd_kcontrol *kcontrol, |
355 | struct snd_ctl_elem_value *ucontrol) | 393 | struct snd_ctl_elem_value *ucontrol) |
356 | { | 394 | { |
357 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 395 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
358 | struct tlv320dac33_priv *dac33 = codec->private_data; | 396 | struct tlv320dac33_priv *dac33 = codec->private_data; |
359 | 397 | ||
360 | ucontrol->value.integer.value[0] = dac33->nsample_switch; | 398 | ucontrol->value.integer.value[0] = dac33->fifo_mode; |
361 | 399 | ||
362 | return 0; | 400 | return 0; |
363 | } | 401 | } |
364 | 402 | ||
365 | static int dac33_set_nsample_switch(struct snd_kcontrol *kcontrol, | 403 | static int dac33_set_fifo_mode(struct snd_kcontrol *kcontrol, |
366 | struct snd_ctl_elem_value *ucontrol) | 404 | struct snd_ctl_elem_value *ucontrol) |
367 | { | 405 | { |
368 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 406 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
369 | struct tlv320dac33_priv *dac33 = codec->private_data; | 407 | struct tlv320dac33_priv *dac33 = codec->private_data; |
370 | int ret = 0; | 408 | int ret = 0; |
371 | 409 | ||
372 | if (dac33->nsample_switch == ucontrol->value.integer.value[0]) | 410 | if (dac33->fifo_mode == ucontrol->value.integer.value[0]) |
373 | return 0; | 411 | return 0; |
374 | /* Do not allow changes while stream is running*/ | 412 | /* Do not allow changes while stream is running*/ |
375 | if (codec->active) | 413 | if (codec->active) |
376 | return -EPERM; | 414 | return -EPERM; |
377 | 415 | ||
378 | if (ucontrol->value.integer.value[0] < 0 || | 416 | if (ucontrol->value.integer.value[0] < 0 || |
379 | ucontrol->value.integer.value[0] > 1) | 417 | ucontrol->value.integer.value[0] >= DAC33_FIFO_LAST_MODE) |
380 | ret = -EINVAL; | 418 | ret = -EINVAL; |
381 | else | 419 | else |
382 | dac33->nsample_switch = ucontrol->value.integer.value[0]; | 420 | dac33->fifo_mode = ucontrol->value.integer.value[0]; |
383 | 421 | ||
384 | return ret; | 422 | return ret; |
385 | } | 423 | } |
386 | 424 | ||
425 | /* Codec operation modes */ | ||
426 | static const char *dac33_fifo_mode_texts[] = { | ||
427 | "Bypass", "Mode 1", "Mode 7" | ||
428 | }; | ||
429 | |||
430 | static const struct soc_enum dac33_fifo_mode_enum = | ||
431 | SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(dac33_fifo_mode_texts), | ||
432 | dac33_fifo_mode_texts); | ||
433 | |||
387 | /* | 434 | /* |
388 | * DACL/R digital volume control: | 435 | * DACL/R digital volume control: |
389 | * from 0 dB to -63.5 in 0.5 dB steps | 436 | * from 0 dB to -63.5 in 0.5 dB steps |
@@ -406,8 +453,8 @@ static const struct snd_kcontrol_new dac33_snd_controls[] = { | |||
406 | static const struct snd_kcontrol_new dac33_nsample_snd_controls[] = { | 453 | static const struct snd_kcontrol_new dac33_nsample_snd_controls[] = { |
407 | SOC_SINGLE_EXT("nSample", 0, 0, 5900, 0, | 454 | SOC_SINGLE_EXT("nSample", 0, 0, 5900, 0, |
408 | dac33_get_nsample, dac33_set_nsample), | 455 | dac33_get_nsample, dac33_set_nsample), |
409 | SOC_SINGLE_EXT("nSample Switch", 0, 0, 1, 0, | 456 | SOC_ENUM_EXT("FIFO Mode", dac33_fifo_mode_enum, |
410 | dac33_get_nsample_switch, dac33_set_nsample_switch), | 457 | dac33_get_fifo_mode, dac33_set_fifo_mode), |
411 | }; | 458 | }; |
412 | 459 | ||
413 | /* Analog bypass */ | 460 | /* Analog bypass */ |
@@ -469,6 +516,8 @@ static int dac33_add_widgets(struct snd_soc_codec *codec) | |||
469 | static int dac33_set_bias_level(struct snd_soc_codec *codec, | 516 | static int dac33_set_bias_level(struct snd_soc_codec *codec, |
470 | enum snd_soc_bias_level level) | 517 | enum snd_soc_bias_level level) |
471 | { | 518 | { |
519 | int ret; | ||
520 | |||
472 | switch (level) { | 521 | switch (level) { |
473 | case SND_SOC_BIAS_ON: | 522 | case SND_SOC_BIAS_ON: |
474 | dac33_soft_power(codec, 1); | 523 | dac33_soft_power(codec, 1); |
@@ -476,12 +525,19 @@ static int dac33_set_bias_level(struct snd_soc_codec *codec, | |||
476 | case SND_SOC_BIAS_PREPARE: | 525 | case SND_SOC_BIAS_PREPARE: |
477 | break; | 526 | break; |
478 | case SND_SOC_BIAS_STANDBY: | 527 | case SND_SOC_BIAS_STANDBY: |
479 | if (codec->bias_level == SND_SOC_BIAS_OFF) | 528 | if (codec->bias_level == SND_SOC_BIAS_OFF) { |
480 | dac33_hard_power(codec, 1); | 529 | ret = dac33_hard_power(codec, 1); |
530 | if (ret != 0) | ||
531 | return ret; | ||
532 | } | ||
533 | |||
481 | dac33_soft_power(codec, 0); | 534 | dac33_soft_power(codec, 0); |
482 | break; | 535 | break; |
483 | case SND_SOC_BIAS_OFF: | 536 | case SND_SOC_BIAS_OFF: |
484 | dac33_hard_power(codec, 0); | 537 | ret = dac33_hard_power(codec, 0); |
538 | if (ret != 0) | ||
539 | return ret; | ||
540 | |||
485 | break; | 541 | break; |
486 | } | 542 | } |
487 | codec->bias_level = level; | 543 | codec->bias_level = level; |
@@ -489,6 +545,51 @@ static int dac33_set_bias_level(struct snd_soc_codec *codec, | |||
489 | return 0; | 545 | return 0; |
490 | } | 546 | } |
491 | 547 | ||
548 | static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33) | ||
549 | { | ||
550 | struct snd_soc_codec *codec; | ||
551 | |||
552 | codec = &dac33->codec; | ||
553 | |||
554 | switch (dac33->fifo_mode) { | ||
555 | case DAC33_FIFO_MODE1: | ||
556 | dac33_write16(codec, DAC33_NSAMPLE_MSB, | ||
557 | DAC33_THRREG(dac33->nsample)); | ||
558 | dac33_write16(codec, DAC33_PREFILL_MSB, | ||
559 | DAC33_THRREG(dac33->alarm_threshold)); | ||
560 | break; | ||
561 | case DAC33_FIFO_MODE7: | ||
562 | dac33_write16(codec, DAC33_PREFILL_MSB, | ||
563 | DAC33_THRREG(10)); | ||
564 | break; | ||
565 | default: | ||
566 | dev_warn(codec->dev, "Unhandled FIFO mode: %d\n", | ||
567 | dac33->fifo_mode); | ||
568 | break; | ||
569 | } | ||
570 | } | ||
571 | |||
572 | static inline void dac33_playback_handler(struct tlv320dac33_priv *dac33) | ||
573 | { | ||
574 | struct snd_soc_codec *codec; | ||
575 | |||
576 | codec = &dac33->codec; | ||
577 | |||
578 | switch (dac33->fifo_mode) { | ||
579 | case DAC33_FIFO_MODE1: | ||
580 | dac33_write16(codec, DAC33_NSAMPLE_MSB, | ||
581 | DAC33_THRREG(dac33->nsample)); | ||
582 | break; | ||
583 | case DAC33_FIFO_MODE7: | ||
584 | /* At the moment we are not using interrupts in mode7 */ | ||
585 | break; | ||
586 | default: | ||
587 | dev_warn(codec->dev, "Unhandled FIFO mode: %d\n", | ||
588 | dac33->fifo_mode); | ||
589 | break; | ||
590 | } | ||
591 | } | ||
592 | |||
492 | static void dac33_work(struct work_struct *work) | 593 | static void dac33_work(struct work_struct *work) |
493 | { | 594 | { |
494 | struct snd_soc_codec *codec; | 595 | struct snd_soc_codec *codec; |
@@ -502,14 +603,10 @@ static void dac33_work(struct work_struct *work) | |||
502 | switch (dac33->state) { | 603 | switch (dac33->state) { |
503 | case DAC33_PREFILL: | 604 | case DAC33_PREFILL: |
504 | dac33->state = DAC33_PLAYBACK; | 605 | dac33->state = DAC33_PLAYBACK; |
505 | dac33_write16(codec, DAC33_NSAMPLE_MSB, | 606 | dac33_prefill_handler(dac33); |
506 | DAC33_THRREG(dac33->nsample)); | ||
507 | dac33_write16(codec, DAC33_PREFILL_MSB, | ||
508 | DAC33_THRREG(dac33->alarm_threshold)); | ||
509 | break; | 607 | break; |
510 | case DAC33_PLAYBACK: | 608 | case DAC33_PLAYBACK: |
511 | dac33_write16(codec, DAC33_NSAMPLE_MSB, | 609 | dac33_playback_handler(dac33); |
512 | DAC33_THRREG(dac33->nsample)); | ||
513 | break; | 610 | break; |
514 | case DAC33_IDLE: | 611 | case DAC33_IDLE: |
515 | break; | 612 | break; |
@@ -547,7 +644,7 @@ static void dac33_shutdown(struct snd_pcm_substream *substream, | |||
547 | unsigned int pwr_ctrl; | 644 | unsigned int pwr_ctrl; |
548 | 645 | ||
549 | /* Stop pending workqueue */ | 646 | /* Stop pending workqueue */ |
550 | if (dac33->nsample_switch) | 647 | if (dac33->fifo_mode) |
551 | cancel_work_sync(&dac33->work); | 648 | cancel_work_sync(&dac33->work); |
552 | 649 | ||
553 | mutex_lock(&dac33->mutex); | 650 | mutex_lock(&dac33->mutex); |
@@ -603,7 +700,7 @@ static int dac33_hw_params(struct snd_pcm_substream *substream, | |||
603 | } | 700 | } |
604 | 701 | ||
605 | #define CALC_OSCSET(rate, refclk) ( \ | 702 | #define CALC_OSCSET(rate, refclk) ( \ |
606 | ((((rate * 10000) / refclk) * 4096) + 5000) / 10000) | 703 | ((((rate * 10000) / refclk) * 4096) + 7000) / 10000) |
607 | #define CALC_RATIOSET(rate, refclk) ( \ | 704 | #define CALC_RATIOSET(rate, refclk) ( \ |
608 | ((((refclk * 100000) / rate) * 16384) + 50000) / 100000) | 705 | ((((refclk * 100000) / rate) * 16384) + 50000) / 100000) |
609 | 706 | ||
@@ -619,7 +716,7 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream) | |||
619 | struct snd_soc_codec *codec = socdev->card->codec; | 716 | struct snd_soc_codec *codec = socdev->card->codec; |
620 | struct tlv320dac33_priv *dac33 = codec->private_data; | 717 | struct tlv320dac33_priv *dac33 = codec->private_data; |
621 | unsigned int oscset, ratioset, pwr_ctrl, reg_tmp; | 718 | unsigned int oscset, ratioset, pwr_ctrl, reg_tmp; |
622 | u8 aictrl_a, fifoctrl_a; | 719 | u8 aictrl_a, aictrl_b, fifoctrl_a; |
623 | 720 | ||
624 | switch (substream->runtime->rate) { | 721 | switch (substream->runtime->rate) { |
625 | case 44100: | 722 | case 44100: |
@@ -637,7 +734,10 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream) | |||
637 | 734 | ||
638 | aictrl_a = dac33_read_reg_cache(codec, DAC33_SER_AUDIOIF_CTRL_A); | 735 | aictrl_a = dac33_read_reg_cache(codec, DAC33_SER_AUDIOIF_CTRL_A); |
639 | aictrl_a &= ~(DAC33_NCYCL_MASK | DAC33_WLEN_MASK); | 736 | aictrl_a &= ~(DAC33_NCYCL_MASK | DAC33_WLEN_MASK); |
737 | /* Read FIFO control A, and clear FIFO flush bit */ | ||
640 | fifoctrl_a = dac33_read_reg_cache(codec, DAC33_FIFO_CTRL_A); | 738 | fifoctrl_a = dac33_read_reg_cache(codec, DAC33_FIFO_CTRL_A); |
739 | fifoctrl_a &= ~DAC33_FIFOFLUSH; | ||
740 | |||
641 | fifoctrl_a &= ~DAC33_WIDTH; | 741 | fifoctrl_a &= ~DAC33_WIDTH; |
642 | switch (substream->runtime->format) { | 742 | switch (substream->runtime->format) { |
643 | case SNDRV_PCM_FORMAT_S16_LE: | 743 | case SNDRV_PCM_FORMAT_S16_LE: |
@@ -675,7 +775,8 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream) | |||
675 | 775 | ||
676 | dac33_oscwait(codec); | 776 | dac33_oscwait(codec); |
677 | 777 | ||
678 | if (dac33->nsample_switch) { | 778 | if (dac33->fifo_mode) { |
779 | /* Generic for all FIFO modes */ | ||
679 | /* 50-51 : ASRC Control registers */ | 780 | /* 50-51 : ASRC Control registers */ |
680 | dac33_write(codec, DAC33_ASRC_CTRL_A, (1 << 4)); /* div=2 */ | 781 | dac33_write(codec, DAC33_ASRC_CTRL_A, (1 << 4)); /* div=2 */ |
681 | dac33_write(codec, DAC33_ASRC_CTRL_B, 1); /* ??? */ | 782 | dac33_write(codec, DAC33_ASRC_CTRL_B, 1); /* ??? */ |
@@ -685,38 +786,101 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream) | |||
685 | 786 | ||
686 | /* Set interrupts to high active */ | 787 | /* Set interrupts to high active */ |
687 | dac33_write(codec, DAC33_INTP_CTRL_A, DAC33_INTPM_AHIGH); | 788 | dac33_write(codec, DAC33_INTP_CTRL_A, DAC33_INTPM_AHIGH); |
688 | |||
689 | dac33_write(codec, DAC33_FIFO_IRQ_MODE_B, | ||
690 | DAC33_ATM(DAC33_FIFO_IRQ_MODE_LEVEL)); | ||
691 | dac33_write(codec, DAC33_FIFO_IRQ_MASK, DAC33_MAT); | ||
692 | } else { | 789 | } else { |
790 | /* FIFO bypass mode */ | ||
693 | /* 50-51 : ASRC Control registers */ | 791 | /* 50-51 : ASRC Control registers */ |
694 | dac33_write(codec, DAC33_ASRC_CTRL_A, DAC33_SRCBYP); | 792 | dac33_write(codec, DAC33_ASRC_CTRL_A, DAC33_SRCBYP); |
695 | dac33_write(codec, DAC33_ASRC_CTRL_B, 0); /* ??? */ | 793 | dac33_write(codec, DAC33_ASRC_CTRL_B, 0); /* ??? */ |
696 | } | 794 | } |
697 | 795 | ||
698 | if (dac33->nsample_switch) | 796 | /* Interrupt behaviour configuration */ |
797 | switch (dac33->fifo_mode) { | ||
798 | case DAC33_FIFO_MODE1: | ||
799 | dac33_write(codec, DAC33_FIFO_IRQ_MODE_B, | ||
800 | DAC33_ATM(DAC33_FIFO_IRQ_MODE_LEVEL)); | ||
801 | dac33_write(codec, DAC33_FIFO_IRQ_MASK, DAC33_MAT); | ||
802 | break; | ||
803 | case DAC33_FIFO_MODE7: | ||
804 | /* Disable all interrupts */ | ||
805 | dac33_write(codec, DAC33_FIFO_IRQ_MASK, 0); | ||
806 | break; | ||
807 | default: | ||
808 | /* in FIFO bypass mode, the interrupts are not used */ | ||
809 | break; | ||
810 | } | ||
811 | |||
812 | aictrl_b = dac33_read_reg_cache(codec, DAC33_SER_AUDIOIF_CTRL_B); | ||
813 | |||
814 | switch (dac33->fifo_mode) { | ||
815 | case DAC33_FIFO_MODE1: | ||
816 | /* | ||
817 | * For mode1: | ||
818 | * Disable the FIFO bypass (Enable the use of FIFO) | ||
819 | * Select nSample mode | ||
820 | * BCLK is only running when data is needed by DAC33 | ||
821 | */ | ||
699 | fifoctrl_a &= ~DAC33_FBYPAS; | 822 | fifoctrl_a &= ~DAC33_FBYPAS; |
700 | else | 823 | fifoctrl_a &= ~DAC33_FAUTO; |
824 | aictrl_b &= ~DAC33_BCLKON; | ||
825 | break; | ||
826 | case DAC33_FIFO_MODE7: | ||
827 | /* | ||
828 | * For mode1: | ||
829 | * Disable the FIFO bypass (Enable the use of FIFO) | ||
830 | * Select Threshold mode | ||
831 | * BCLK is only running when data is needed by DAC33 | ||
832 | */ | ||
833 | fifoctrl_a &= ~DAC33_FBYPAS; | ||
834 | fifoctrl_a |= DAC33_FAUTO; | ||
835 | aictrl_b &= ~DAC33_BCLKON; | ||
836 | break; | ||
837 | default: | ||
838 | /* | ||
839 | * For FIFO bypass mode: | ||
840 | * Enable the FIFO bypass (Disable the FIFO use) | ||
841 | * Set the BCLK as continous | ||
842 | */ | ||
701 | fifoctrl_a |= DAC33_FBYPAS; | 843 | fifoctrl_a |= DAC33_FBYPAS; |
702 | dac33_write(codec, DAC33_FIFO_CTRL_A, fifoctrl_a); | 844 | aictrl_b |= DAC33_BCLKON; |
845 | break; | ||
846 | } | ||
703 | 847 | ||
848 | dac33_write(codec, DAC33_FIFO_CTRL_A, fifoctrl_a); | ||
704 | dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_A, aictrl_a); | 849 | dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_A, aictrl_a); |
705 | reg_tmp = dac33_read_reg_cache(codec, DAC33_SER_AUDIOIF_CTRL_B); | 850 | dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_B, aictrl_b); |
706 | if (dac33->nsample_switch) | ||
707 | reg_tmp &= ~DAC33_BCLKON; | ||
708 | else | ||
709 | reg_tmp |= DAC33_BCLKON; | ||
710 | dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_B, reg_tmp); | ||
711 | 851 | ||
712 | if (dac33->nsample_switch) { | 852 | /* |
713 | /* 20: BCLK divide ratio */ | 853 | * BCLK divide ratio |
714 | dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_C, 3); | 854 | * 0: 1.5 |
855 | * 1: 1 | ||
856 | * 2: 2 | ||
857 | * ... | ||
858 | * 254: 254 | ||
859 | * 255: 255 | ||
860 | */ | ||
861 | if (dac33->fifo_mode) | ||
862 | dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_C, | ||
863 | dac33->burst_bclkdiv); | ||
864 | else | ||
865 | dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_C, 32); | ||
715 | 866 | ||
867 | switch (dac33->fifo_mode) { | ||
868 | case DAC33_FIFO_MODE1: | ||
716 | dac33_write16(codec, DAC33_ATHR_MSB, | 869 | dac33_write16(codec, DAC33_ATHR_MSB, |
717 | DAC33_THRREG(dac33->alarm_threshold)); | 870 | DAC33_THRREG(dac33->alarm_threshold)); |
718 | } else { | 871 | break; |
719 | dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_C, 32); | 872 | case DAC33_FIFO_MODE7: |
873 | /* | ||
874 | * Configure the threshold levels, and leave 10 sample space | ||
875 | * at the bottom, and also at the top of the FIFO | ||
876 | */ | ||
877 | dac33_write16(codec, DAC33_UTHR_MSB, | ||
878 | DAC33_THRREG(DAC33_BUFFER_SIZE_SAMPLES - 10)); | ||
879 | dac33_write16(codec, DAC33_LTHR_MSB, | ||
880 | DAC33_THRREG(10)); | ||
881 | break; | ||
882 | default: | ||
883 | break; | ||
720 | } | 884 | } |
721 | 885 | ||
722 | mutex_unlock(&dac33->mutex); | 886 | mutex_unlock(&dac33->mutex); |
@@ -789,7 +953,7 @@ static int dac33_pcm_trigger(struct snd_pcm_substream *substream, int cmd, | |||
789 | case SNDRV_PCM_TRIGGER_START: | 953 | case SNDRV_PCM_TRIGGER_START: |
790 | case SNDRV_PCM_TRIGGER_RESUME: | 954 | case SNDRV_PCM_TRIGGER_RESUME: |
791 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 955 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
792 | if (dac33->nsample_switch) { | 956 | if (dac33->fifo_mode) { |
793 | dac33->state = DAC33_PREFILL; | 957 | dac33->state = DAC33_PREFILL; |
794 | queue_work(dac33->dac33_wq, &dac33->work); | 958 | queue_work(dac33->dac33_wq, &dac33->work); |
795 | } | 959 | } |
@@ -797,7 +961,7 @@ static int dac33_pcm_trigger(struct snd_pcm_substream *substream, int cmd, | |||
797 | case SNDRV_PCM_TRIGGER_STOP: | 961 | case SNDRV_PCM_TRIGGER_STOP: |
798 | case SNDRV_PCM_TRIGGER_SUSPEND: | 962 | case SNDRV_PCM_TRIGGER_SUSPEND: |
799 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 963 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
800 | if (dac33->nsample_switch) { | 964 | if (dac33->fifo_mode) { |
801 | dac33->state = DAC33_FLUSH; | 965 | dac33->state = DAC33_FLUSH; |
802 | queue_work(dac33->dac33_wq, &dac33->work); | 966 | queue_work(dac33->dac33_wq, &dac33->work); |
803 | } | 967 | } |
@@ -843,6 +1007,7 @@ static int dac33_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
843 | unsigned int fmt) | 1007 | unsigned int fmt) |
844 | { | 1008 | { |
845 | struct snd_soc_codec *codec = codec_dai->codec; | 1009 | struct snd_soc_codec *codec = codec_dai->codec; |
1010 | struct tlv320dac33_priv *dac33 = codec->private_data; | ||
846 | u8 aictrl_a, aictrl_b; | 1011 | u8 aictrl_a, aictrl_b; |
847 | 1012 | ||
848 | aictrl_a = dac33_read_reg_cache(codec, DAC33_SER_AUDIOIF_CTRL_A); | 1013 | aictrl_a = dac33_read_reg_cache(codec, DAC33_SER_AUDIOIF_CTRL_A); |
@@ -855,7 +1020,11 @@ static int dac33_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
855 | break; | 1020 | break; |
856 | case SND_SOC_DAIFMT_CBS_CFS: | 1021 | case SND_SOC_DAIFMT_CBS_CFS: |
857 | /* Codec Slave */ | 1022 | /* Codec Slave */ |
858 | aictrl_a &= ~(DAC33_MSBCLK | DAC33_MSWCLK); | 1023 | if (dac33->fifo_mode) { |
1024 | dev_err(codec->dev, "FIFO mode requires master mode\n"); | ||
1025 | return -EINVAL; | ||
1026 | } else | ||
1027 | aictrl_a &= ~(DAC33_MSBCLK | DAC33_MSWCLK); | ||
859 | break; | 1028 | break; |
860 | default: | 1029 | default: |
861 | return -EINVAL; | 1030 | return -EINVAL; |
@@ -959,6 +1128,9 @@ static int dac33_soc_probe(struct platform_device *pdev) | |||
959 | /* power on device */ | 1128 | /* power on device */ |
960 | dac33_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 1129 | dac33_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
961 | 1130 | ||
1131 | /* Bias level configuration has enabled regulator an extra time */ | ||
1132 | regulator_bulk_disable(ARRAY_SIZE(dac33->supplies), dac33->supplies); | ||
1133 | |||
962 | return 0; | 1134 | return 0; |
963 | 1135 | ||
964 | pcm_err: | 1136 | pcm_err: |
@@ -1033,13 +1205,13 @@ struct snd_soc_dai dac33_dai = { | |||
1033 | }; | 1205 | }; |
1034 | EXPORT_SYMBOL_GPL(dac33_dai); | 1206 | EXPORT_SYMBOL_GPL(dac33_dai); |
1035 | 1207 | ||
1036 | static int dac33_i2c_probe(struct i2c_client *client, | 1208 | static int __devinit dac33_i2c_probe(struct i2c_client *client, |
1037 | const struct i2c_device_id *id) | 1209 | const struct i2c_device_id *id) |
1038 | { | 1210 | { |
1039 | struct tlv320dac33_platform_data *pdata; | 1211 | struct tlv320dac33_platform_data *pdata; |
1040 | struct tlv320dac33_priv *dac33; | 1212 | struct tlv320dac33_priv *dac33; |
1041 | struct snd_soc_codec *codec; | 1213 | struct snd_soc_codec *codec; |
1042 | int ret = 0; | 1214 | int ret, i; |
1043 | 1215 | ||
1044 | if (client->dev.platform_data == NULL) { | 1216 | if (client->dev.platform_data == NULL) { |
1045 | dev_err(&client->dev, "Platform data not set\n"); | 1217 | dev_err(&client->dev, "Platform data not set\n"); |
@@ -1080,10 +1252,11 @@ static int dac33_i2c_probe(struct i2c_client *client, | |||
1080 | i2c_set_clientdata(client, dac33); | 1252 | i2c_set_clientdata(client, dac33); |
1081 | 1253 | ||
1082 | dac33->power_gpio = pdata->power_gpio; | 1254 | dac33->power_gpio = pdata->power_gpio; |
1255 | dac33->burst_bclkdiv = pdata->burst_bclkdiv; | ||
1083 | dac33->irq = client->irq; | 1256 | dac33->irq = client->irq; |
1084 | dac33->nsample = NSAMPLE_MAX; | 1257 | dac33->nsample = NSAMPLE_MAX; |
1085 | /* Disable FIFO use by default */ | 1258 | /* Disable FIFO use by default */ |
1086 | dac33->nsample_switch = 0; | 1259 | dac33->fifo_mode = DAC33_FIFO_BYPASS; |
1087 | 1260 | ||
1088 | tlv320dac33_codec = codec; | 1261 | tlv320dac33_codec = codec; |
1089 | 1262 | ||
@@ -1130,6 +1303,24 @@ static int dac33_i2c_probe(struct i2c_client *client, | |||
1130 | } | 1303 | } |
1131 | } | 1304 | } |
1132 | 1305 | ||
1306 | for (i = 0; i < ARRAY_SIZE(dac33->supplies); i++) | ||
1307 | dac33->supplies[i].supply = dac33_supply_names[i]; | ||
1308 | |||
1309 | ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(dac33->supplies), | ||
1310 | dac33->supplies); | ||
1311 | |||
1312 | if (ret != 0) { | ||
1313 | dev_err(codec->dev, "Failed to request supplies: %d\n", ret); | ||
1314 | goto err_get; | ||
1315 | } | ||
1316 | |||
1317 | ret = regulator_bulk_enable(ARRAY_SIZE(dac33->supplies), | ||
1318 | dac33->supplies); | ||
1319 | if (ret != 0) { | ||
1320 | dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); | ||
1321 | goto err_enable; | ||
1322 | } | ||
1323 | |||
1133 | ret = snd_soc_register_codec(codec); | 1324 | ret = snd_soc_register_codec(codec); |
1134 | if (ret != 0) { | 1325 | if (ret != 0) { |
1135 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); | 1326 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); |
@@ -1149,6 +1340,10 @@ static int dac33_i2c_probe(struct i2c_client *client, | |||
1149 | return ret; | 1340 | return ret; |
1150 | 1341 | ||
1151 | error_codec: | 1342 | error_codec: |
1343 | regulator_bulk_disable(ARRAY_SIZE(dac33->supplies), dac33->supplies); | ||
1344 | err_enable: | ||
1345 | regulator_bulk_free(ARRAY_SIZE(dac33->supplies), dac33->supplies); | ||
1346 | err_get: | ||
1152 | if (dac33->irq >= 0) { | 1347 | if (dac33->irq >= 0) { |
1153 | free_irq(dac33->irq, &dac33->codec); | 1348 | free_irq(dac33->irq, &dac33->codec); |
1154 | destroy_workqueue(dac33->dac33_wq); | 1349 | destroy_workqueue(dac33->dac33_wq); |
@@ -1165,7 +1360,7 @@ error_reg: | |||
1165 | return ret; | 1360 | return ret; |
1166 | } | 1361 | } |
1167 | 1362 | ||
1168 | static int dac33_i2c_remove(struct i2c_client *client) | 1363 | static int __devexit dac33_i2c_remove(struct i2c_client *client) |
1169 | { | 1364 | { |
1170 | struct tlv320dac33_priv *dac33; | 1365 | struct tlv320dac33_priv *dac33; |
1171 | 1366 | ||
@@ -1177,6 +1372,8 @@ static int dac33_i2c_remove(struct i2c_client *client) | |||
1177 | if (dac33->irq >= 0) | 1372 | if (dac33->irq >= 0) |
1178 | free_irq(dac33->irq, &dac33->codec); | 1373 | free_irq(dac33->irq, &dac33->codec); |
1179 | 1374 | ||
1375 | regulator_bulk_free(ARRAY_SIZE(dac33->supplies), dac33->supplies); | ||
1376 | |||
1180 | destroy_workqueue(dac33->dac33_wq); | 1377 | destroy_workqueue(dac33->dac33_wq); |
1181 | snd_soc_unregister_dai(&dac33_dai); | 1378 | snd_soc_unregister_dai(&dac33_dai); |
1182 | snd_soc_unregister_codec(&dac33->codec); | 1379 | snd_soc_unregister_codec(&dac33->codec); |
diff --git a/sound/soc/codecs/tpa6130a2.c b/sound/soc/codecs/tpa6130a2.c index 6b650c1aa3d1..958d49c969ac 100644 --- a/sound/soc/codecs/tpa6130a2.c +++ b/sound/soc/codecs/tpa6130a2.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/device.h> | 25 | #include <linux/device.h> |
26 | #include <linux/i2c.h> | 26 | #include <linux/i2c.h> |
27 | #include <linux/gpio.h> | 27 | #include <linux/gpio.h> |
28 | #include <linux/regulator/consumer.h> | ||
28 | #include <sound/tpa6130a2-plat.h> | 29 | #include <sound/tpa6130a2-plat.h> |
29 | #include <sound/soc.h> | 30 | #include <sound/soc.h> |
30 | #include <sound/soc-dapm.h> | 31 | #include <sound/soc-dapm.h> |
@@ -34,10 +35,22 @@ | |||
34 | 35 | ||
35 | static struct i2c_client *tpa6130a2_client; | 36 | static struct i2c_client *tpa6130a2_client; |
36 | 37 | ||
38 | #define TPA6130A2_NUM_SUPPLIES 2 | ||
39 | static const char *tpa6130a2_supply_names[TPA6130A2_NUM_SUPPLIES] = { | ||
40 | "CPVSS", | ||
41 | "Vdd", | ||
42 | }; | ||
43 | |||
44 | static const char *tpa6140a2_supply_names[TPA6130A2_NUM_SUPPLIES] = { | ||
45 | "HPVdd", | ||
46 | "AVdd", | ||
47 | }; | ||
48 | |||
37 | /* This struct is used to save the context */ | 49 | /* This struct is used to save the context */ |
38 | struct tpa6130a2_data { | 50 | struct tpa6130a2_data { |
39 | struct mutex mutex; | 51 | struct mutex mutex; |
40 | unsigned char regs[TPA6130A2_CACHEREGNUM]; | 52 | unsigned char regs[TPA6130A2_CACHEREGNUM]; |
53 | struct regulator_bulk_data supplies[TPA6130A2_NUM_SUPPLIES]; | ||
41 | int power_gpio; | 54 | int power_gpio; |
42 | unsigned char power_state; | 55 | unsigned char power_state; |
43 | }; | 56 | }; |
@@ -106,10 +119,11 @@ static void tpa6130a2_initialize(void) | |||
106 | tpa6130a2_i2c_write(i, data->regs[i]); | 119 | tpa6130a2_i2c_write(i, data->regs[i]); |
107 | } | 120 | } |
108 | 121 | ||
109 | static void tpa6130a2_power(int power) | 122 | static int tpa6130a2_power(int power) |
110 | { | 123 | { |
111 | struct tpa6130a2_data *data; | 124 | struct tpa6130a2_data *data; |
112 | u8 val; | 125 | u8 val; |
126 | int ret; | ||
113 | 127 | ||
114 | BUG_ON(tpa6130a2_client == NULL); | 128 | BUG_ON(tpa6130a2_client == NULL); |
115 | data = i2c_get_clientdata(tpa6130a2_client); | 129 | data = i2c_get_clientdata(tpa6130a2_client); |
@@ -117,11 +131,20 @@ static void tpa6130a2_power(int power) | |||
117 | mutex_lock(&data->mutex); | 131 | mutex_lock(&data->mutex); |
118 | if (power) { | 132 | if (power) { |
119 | /* Power on */ | 133 | /* Power on */ |
120 | if (data->power_gpio >= 0) { | 134 | if (data->power_gpio >= 0) |
121 | gpio_set_value(data->power_gpio, 1); | 135 | gpio_set_value(data->power_gpio, 1); |
122 | data->power_state = 1; | 136 | |
123 | tpa6130a2_initialize(); | 137 | ret = regulator_bulk_enable(ARRAY_SIZE(data->supplies), |
138 | data->supplies); | ||
139 | if (ret != 0) { | ||
140 | dev_err(&tpa6130a2_client->dev, | ||
141 | "Failed to enable supplies: %d\n", ret); | ||
142 | goto exit; | ||
124 | } | 143 | } |
144 | |||
145 | data->power_state = 1; | ||
146 | tpa6130a2_initialize(); | ||
147 | |||
125 | /* Clear SWS */ | 148 | /* Clear SWS */ |
126 | val = tpa6130a2_read(TPA6130A2_REG_CONTROL); | 149 | val = tpa6130a2_read(TPA6130A2_REG_CONTROL); |
127 | val &= ~TPA6130A2_SWS; | 150 | val &= ~TPA6130A2_SWS; |
@@ -131,13 +154,25 @@ static void tpa6130a2_power(int power) | |||
131 | val = tpa6130a2_read(TPA6130A2_REG_CONTROL); | 154 | val = tpa6130a2_read(TPA6130A2_REG_CONTROL); |
132 | val |= TPA6130A2_SWS; | 155 | val |= TPA6130A2_SWS; |
133 | tpa6130a2_i2c_write(TPA6130A2_REG_CONTROL, val); | 156 | tpa6130a2_i2c_write(TPA6130A2_REG_CONTROL, val); |
157 | |||
134 | /* Power off */ | 158 | /* Power off */ |
135 | if (data->power_gpio >= 0) { | 159 | if (data->power_gpio >= 0) |
136 | gpio_set_value(data->power_gpio, 0); | 160 | gpio_set_value(data->power_gpio, 0); |
137 | data->power_state = 0; | 161 | |
162 | ret = regulator_bulk_disable(ARRAY_SIZE(data->supplies), | ||
163 | data->supplies); | ||
164 | if (ret != 0) { | ||
165 | dev_err(&tpa6130a2_client->dev, | ||
166 | "Failed to disable supplies: %d\n", ret); | ||
167 | goto exit; | ||
138 | } | 168 | } |
169 | |||
170 | data->power_state = 0; | ||
139 | } | 171 | } |
172 | |||
173 | exit: | ||
140 | mutex_unlock(&data->mutex); | 174 | mutex_unlock(&data->mutex); |
175 | return ret; | ||
141 | } | 176 | } |
142 | 177 | ||
143 | static int tpa6130a2_get_reg(struct snd_kcontrol *kcontrol, | 178 | static int tpa6130a2_get_reg(struct snd_kcontrol *kcontrol, |
@@ -237,12 +272,8 @@ static const struct snd_kcontrol_new tpa6130a2_controls[] = { | |||
237 | */ | 272 | */ |
238 | static void tpa6130a2_channel_enable(u8 channel, int enable) | 273 | static void tpa6130a2_channel_enable(u8 channel, int enable) |
239 | { | 274 | { |
240 | struct tpa6130a2_data *data; | ||
241 | u8 val; | 275 | u8 val; |
242 | 276 | ||
243 | BUG_ON(tpa6130a2_client == NULL); | ||
244 | data = i2c_get_clientdata(tpa6130a2_client); | ||
245 | |||
246 | if (enable) { | 277 | if (enable) { |
247 | /* Enable channel */ | 278 | /* Enable channel */ |
248 | /* Enable amplifier */ | 279 | /* Enable amplifier */ |
@@ -299,15 +330,17 @@ static int tpa6130a2_right_event(struct snd_soc_dapm_widget *w, | |||
299 | static int tpa6130a2_supply_event(struct snd_soc_dapm_widget *w, | 330 | static int tpa6130a2_supply_event(struct snd_soc_dapm_widget *w, |
300 | struct snd_kcontrol *kcontrol, int event) | 331 | struct snd_kcontrol *kcontrol, int event) |
301 | { | 332 | { |
333 | int ret = 0; | ||
334 | |||
302 | switch (event) { | 335 | switch (event) { |
303 | case SND_SOC_DAPM_POST_PMU: | 336 | case SND_SOC_DAPM_POST_PMU: |
304 | tpa6130a2_power(1); | 337 | ret = tpa6130a2_power(1); |
305 | break; | 338 | break; |
306 | case SND_SOC_DAPM_POST_PMD: | 339 | case SND_SOC_DAPM_POST_PMD: |
307 | tpa6130a2_power(0); | 340 | ret = tpa6130a2_power(0); |
308 | break; | 341 | break; |
309 | } | 342 | } |
310 | return 0; | 343 | return ret; |
311 | } | 344 | } |
312 | 345 | ||
313 | static const struct snd_soc_dapm_widget tpa6130a2_dapm_widgets[] = { | 346 | static const struct snd_soc_dapm_widget tpa6130a2_dapm_widgets[] = { |
@@ -346,13 +379,13 @@ int tpa6130a2_add_controls(struct snd_soc_codec *codec) | |||
346 | } | 379 | } |
347 | EXPORT_SYMBOL_GPL(tpa6130a2_add_controls); | 380 | EXPORT_SYMBOL_GPL(tpa6130a2_add_controls); |
348 | 381 | ||
349 | static int tpa6130a2_probe(struct i2c_client *client, | 382 | static int __devinit tpa6130a2_probe(struct i2c_client *client, |
350 | const struct i2c_device_id *id) | 383 | const struct i2c_device_id *id) |
351 | { | 384 | { |
352 | struct device *dev; | 385 | struct device *dev; |
353 | struct tpa6130a2_data *data; | 386 | struct tpa6130a2_data *data; |
354 | struct tpa6130a2_platform_data *pdata; | 387 | struct tpa6130a2_platform_data *pdata; |
355 | int ret; | 388 | int i, ret; |
356 | 389 | ||
357 | dev = &client->dev; | 390 | dev = &client->dev; |
358 | 391 | ||
@@ -387,15 +420,38 @@ static int tpa6130a2_probe(struct i2c_client *client, | |||
387 | if (ret < 0) { | 420 | if (ret < 0) { |
388 | dev_err(dev, "Failed to request power GPIO (%d)\n", | 421 | dev_err(dev, "Failed to request power GPIO (%d)\n", |
389 | data->power_gpio); | 422 | data->power_gpio); |
390 | goto fail; | 423 | goto err_gpio; |
391 | } | 424 | } |
392 | gpio_direction_output(data->power_gpio, 0); | 425 | gpio_direction_output(data->power_gpio, 0); |
393 | } else { | ||
394 | data->power_state = 1; | ||
395 | tpa6130a2_initialize(); | ||
396 | } | 426 | } |
397 | 427 | ||
398 | tpa6130a2_power(1); | 428 | switch (pdata->id) { |
429 | case TPA6130A2: | ||
430 | for (i = 0; i < ARRAY_SIZE(data->supplies); i++) | ||
431 | data->supplies[i].supply = tpa6130a2_supply_names[i]; | ||
432 | break; | ||
433 | case TPA6140A2: | ||
434 | for (i = 0; i < ARRAY_SIZE(data->supplies); i++) | ||
435 | data->supplies[i].supply = tpa6140a2_supply_names[i];; | ||
436 | break; | ||
437 | default: | ||
438 | dev_warn(dev, "Unknown TPA model (%d). Assuming 6130A2\n", | ||
439 | pdata->id); | ||
440 | for (i = 0; i < ARRAY_SIZE(data->supplies); i++) | ||
441 | data->supplies[i].supply = tpa6130a2_supply_names[i]; | ||
442 | } | ||
443 | |||
444 | ret = regulator_bulk_get(dev, ARRAY_SIZE(data->supplies), | ||
445 | data->supplies); | ||
446 | if (ret != 0) { | ||
447 | dev_err(dev, "Failed to request supplies: %d\n", ret); | ||
448 | goto err_regulator; | ||
449 | } | ||
450 | |||
451 | ret = tpa6130a2_power(1); | ||
452 | if (ret != 0) | ||
453 | goto err_power; | ||
454 | |||
399 | 455 | ||
400 | /* Read version */ | 456 | /* Read version */ |
401 | ret = tpa6130a2_i2c_read(TPA6130A2_REG_VERSION) & | 457 | ret = tpa6130a2_i2c_read(TPA6130A2_REG_VERSION) & |
@@ -404,10 +460,18 @@ static int tpa6130a2_probe(struct i2c_client *client, | |||
404 | dev_warn(dev, "UNTESTED version detected (%d)\n", ret); | 460 | dev_warn(dev, "UNTESTED version detected (%d)\n", ret); |
405 | 461 | ||
406 | /* Disable the chip */ | 462 | /* Disable the chip */ |
407 | tpa6130a2_power(0); | 463 | ret = tpa6130a2_power(0); |
464 | if (ret != 0) | ||
465 | goto err_power; | ||
408 | 466 | ||
409 | return 0; | 467 | return 0; |
410 | fail: | 468 | |
469 | err_power: | ||
470 | regulator_bulk_free(ARRAY_SIZE(data->supplies), data->supplies); | ||
471 | err_regulator: | ||
472 | if (data->power_gpio >= 0) | ||
473 | gpio_free(data->power_gpio); | ||
474 | err_gpio: | ||
411 | kfree(data); | 475 | kfree(data); |
412 | i2c_set_clientdata(tpa6130a2_client, NULL); | 476 | i2c_set_clientdata(tpa6130a2_client, NULL); |
413 | tpa6130a2_client = NULL; | 477 | tpa6130a2_client = NULL; |
@@ -415,7 +479,7 @@ fail: | |||
415 | return ret; | 479 | return ret; |
416 | } | 480 | } |
417 | 481 | ||
418 | static int tpa6130a2_remove(struct i2c_client *client) | 482 | static int __devexit tpa6130a2_remove(struct i2c_client *client) |
419 | { | 483 | { |
420 | struct tpa6130a2_data *data = i2c_get_clientdata(client); | 484 | struct tpa6130a2_data *data = i2c_get_clientdata(client); |
421 | 485 | ||
@@ -423,6 +487,9 @@ static int tpa6130a2_remove(struct i2c_client *client) | |||
423 | 487 | ||
424 | if (data->power_gpio >= 0) | 488 | if (data->power_gpio >= 0) |
425 | gpio_free(data->power_gpio); | 489 | gpio_free(data->power_gpio); |
490 | |||
491 | regulator_bulk_free(ARRAY_SIZE(data->supplies), data->supplies); | ||
492 | |||
426 | kfree(data); | 493 | kfree(data); |
427 | tpa6130a2_client = NULL; | 494 | tpa6130a2_client = NULL; |
428 | 495 | ||
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 2a27f7b56726..6f5d4af20052 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c | |||
@@ -55,7 +55,7 @@ static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = { | |||
55 | 0x0c, /* REG_ATXR1PGA (0xB) */ | 55 | 0x0c, /* REG_ATXR1PGA (0xB) */ |
56 | 0x00, /* REG_AVTXL2PGA (0xC) */ | 56 | 0x00, /* REG_AVTXL2PGA (0xC) */ |
57 | 0x00, /* REG_AVTXR2PGA (0xD) */ | 57 | 0x00, /* REG_AVTXR2PGA (0xD) */ |
58 | 0x01, /* REG_AUDIO_IF (0xE) */ | 58 | 0x00, /* REG_AUDIO_IF (0xE) */ |
59 | 0x00, /* REG_VOICE_IF (0xF) */ | 59 | 0x00, /* REG_VOICE_IF (0xF) */ |
60 | 0x00, /* REG_ARXR1PGA (0x10) */ | 60 | 0x00, /* REG_ARXR1PGA (0x10) */ |
61 | 0x00, /* REG_ARXL1PGA (0x11) */ | 61 | 0x00, /* REG_ARXL1PGA (0x11) */ |
@@ -64,19 +64,19 @@ static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = { | |||
64 | 0x00, /* REG_VRXPGA (0x14) */ | 64 | 0x00, /* REG_VRXPGA (0x14) */ |
65 | 0x00, /* REG_VSTPGA (0x15) */ | 65 | 0x00, /* REG_VSTPGA (0x15) */ |
66 | 0x00, /* REG_VRX2ARXPGA (0x16) */ | 66 | 0x00, /* REG_VRX2ARXPGA (0x16) */ |
67 | 0x0c, /* REG_AVDAC_CTL (0x17) */ | 67 | 0x00, /* REG_AVDAC_CTL (0x17) */ |
68 | 0x00, /* REG_ARX2VTXPGA (0x18) */ | 68 | 0x00, /* REG_ARX2VTXPGA (0x18) */ |
69 | 0x00, /* REG_ARXL1_APGA_CTL (0x19) */ | 69 | 0x00, /* REG_ARXL1_APGA_CTL (0x19) */ |
70 | 0x00, /* REG_ARXR1_APGA_CTL (0x1A) */ | 70 | 0x00, /* REG_ARXR1_APGA_CTL (0x1A) */ |
71 | 0x4b, /* REG_ARXL2_APGA_CTL (0x1B) */ | 71 | 0x4a, /* REG_ARXL2_APGA_CTL (0x1B) */ |
72 | 0x4b, /* REG_ARXR2_APGA_CTL (0x1C) */ | 72 | 0x4a, /* REG_ARXR2_APGA_CTL (0x1C) */ |
73 | 0x00, /* REG_ATX2ARXPGA (0x1D) */ | 73 | 0x00, /* REG_ATX2ARXPGA (0x1D) */ |
74 | 0x00, /* REG_BT_IF (0x1E) */ | 74 | 0x00, /* REG_BT_IF (0x1E) */ |
75 | 0x00, /* REG_BTPGA (0x1F) */ | 75 | 0x00, /* REG_BTPGA (0x1F) */ |
76 | 0x00, /* REG_BTSTPGA (0x20) */ | 76 | 0x00, /* REG_BTSTPGA (0x20) */ |
77 | 0x00, /* REG_EAR_CTL (0x21) */ | 77 | 0x00, /* REG_EAR_CTL (0x21) */ |
78 | 0x24, /* REG_HS_SEL (0x22) */ | 78 | 0x00, /* REG_HS_SEL (0x22) */ |
79 | 0x0a, /* REG_HS_GAIN_SET (0x23) */ | 79 | 0x00, /* REG_HS_GAIN_SET (0x23) */ |
80 | 0x00, /* REG_HS_POPN_SET (0x24) */ | 80 | 0x00, /* REG_HS_POPN_SET (0x24) */ |
81 | 0x00, /* REG_PREDL_CTL (0x25) */ | 81 | 0x00, /* REG_PREDL_CTL (0x25) */ |
82 | 0x00, /* REG_PREDR_CTL (0x26) */ | 82 | 0x00, /* REG_PREDR_CTL (0x26) */ |
@@ -99,7 +99,7 @@ static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = { | |||
99 | 0x00, /* REG_I2S_RX_SCRAMBLE_H (0x37) */ | 99 | 0x00, /* REG_I2S_RX_SCRAMBLE_H (0x37) */ |
100 | 0x00, /* REG_I2S_RX_SCRAMBLE_M (0x38) */ | 100 | 0x00, /* REG_I2S_RX_SCRAMBLE_M (0x38) */ |
101 | 0x00, /* REG_I2S_RX_SCRAMBLE_L (0x39) */ | 101 | 0x00, /* REG_I2S_RX_SCRAMBLE_L (0x39) */ |
102 | 0x16, /* REG_APLL_CTL (0x3A) */ | 102 | 0x06, /* REG_APLL_CTL (0x3A) */ |
103 | 0x00, /* REG_DTMF_CTL (0x3B) */ | 103 | 0x00, /* REG_DTMF_CTL (0x3B) */ |
104 | 0x00, /* REG_DTMF_PGA_CTL2 (0x3C) */ | 104 | 0x00, /* REG_DTMF_PGA_CTL2 (0x3C) */ |
105 | 0x00, /* REG_DTMF_PGA_CTL1 (0x3D) */ | 105 | 0x00, /* REG_DTMF_PGA_CTL1 (0x3D) */ |
@@ -1203,6 +1203,8 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { | |||
1203 | SND_SOC_DAPM_SUPPLY("APLL Enable", SND_SOC_NOPM, 0, 0, apll_event, | 1203 | SND_SOC_DAPM_SUPPLY("APLL Enable", SND_SOC_NOPM, 0, 0, apll_event, |
1204 | SND_SOC_DAPM_PRE_PMU|SND_SOC_DAPM_POST_PMD), | 1204 | SND_SOC_DAPM_PRE_PMU|SND_SOC_DAPM_POST_PMD), |
1205 | 1205 | ||
1206 | SND_SOC_DAPM_SUPPLY("AIF Enable", TWL4030_REG_AUDIO_IF, 0, 0, NULL, 0), | ||
1207 | |||
1206 | /* Output MIXER controls */ | 1208 | /* Output MIXER controls */ |
1207 | /* Earpiece */ | 1209 | /* Earpiece */ |
1208 | SND_SOC_DAPM_MIXER("Earpiece Mixer", SND_SOC_NOPM, 0, 0, | 1210 | SND_SOC_DAPM_MIXER("Earpiece Mixer", SND_SOC_NOPM, 0, 0, |
@@ -1337,6 +1339,11 @@ static const struct snd_soc_dapm_route intercon[] = { | |||
1337 | {"Digital L2 Playback Mixer", NULL, "APLL Enable"}, | 1339 | {"Digital L2 Playback Mixer", NULL, "APLL Enable"}, |
1338 | {"Digital Voice Playback Mixer", NULL, "APLL Enable"}, | 1340 | {"Digital Voice Playback Mixer", NULL, "APLL Enable"}, |
1339 | 1341 | ||
1342 | {"Digital R1 Playback Mixer", NULL, "AIF Enable"}, | ||
1343 | {"Digital L1 Playback Mixer", NULL, "AIF Enable"}, | ||
1344 | {"Digital R2 Playback Mixer", NULL, "AIF Enable"}, | ||
1345 | {"Digital L2 Playback Mixer", NULL, "AIF Enable"}, | ||
1346 | |||
1340 | {"Analog L1 Playback Mixer", NULL, "Digital L1 Playback Mixer"}, | 1347 | {"Analog L1 Playback Mixer", NULL, "Digital L1 Playback Mixer"}, |
1341 | {"Analog R1 Playback Mixer", NULL, "Digital R1 Playback Mixer"}, | 1348 | {"Analog R1 Playback Mixer", NULL, "Digital R1 Playback Mixer"}, |
1342 | {"Analog L2 Playback Mixer", NULL, "Digital L2 Playback Mixer"}, | 1349 | {"Analog L2 Playback Mixer", NULL, "Digital L2 Playback Mixer"}, |
@@ -1455,6 +1462,11 @@ static const struct snd_soc_dapm_route intercon[] = { | |||
1455 | {"ADC Virtual Left2", NULL, "APLL Enable"}, | 1462 | {"ADC Virtual Left2", NULL, "APLL Enable"}, |
1456 | {"ADC Virtual Right2", NULL, "APLL Enable"}, | 1463 | {"ADC Virtual Right2", NULL, "APLL Enable"}, |
1457 | 1464 | ||
1465 | {"ADC Virtual Left1", NULL, "AIF Enable"}, | ||
1466 | {"ADC Virtual Right1", NULL, "AIF Enable"}, | ||
1467 | {"ADC Virtual Left2", NULL, "AIF Enable"}, | ||
1468 | {"ADC Virtual Right2", NULL, "AIF Enable"}, | ||
1469 | |||
1458 | /* Analog bypass routes */ | 1470 | /* Analog bypass routes */ |
1459 | {"Right1 Analog Loopback", "Switch", "Analog Right"}, | 1471 | {"Right1 Analog Loopback", "Switch", "Analog Right"}, |
1460 | {"Left1 Analog Loopback", "Switch", "Analog Left"}, | 1472 | {"Left1 Analog Loopback", "Switch", "Analog Left"}, |
@@ -2152,8 +2164,6 @@ static int twl4030_soc_remove(struct platform_device *pdev) | |||
2152 | twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF); | 2164 | twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF); |
2153 | snd_soc_free_pcms(socdev); | 2165 | snd_soc_free_pcms(socdev); |
2154 | snd_soc_dapm_free(socdev); | 2166 | snd_soc_dapm_free(socdev); |
2155 | kfree(codec->private_data); | ||
2156 | kfree(codec); | ||
2157 | 2167 | ||
2158 | return 0; | 2168 | return 0; |
2159 | } | 2169 | } |
@@ -2192,7 +2202,7 @@ static int __devinit twl4030_codec_probe(struct platform_device *pdev) | |||
2192 | codec->write = twl4030_write; | 2202 | codec->write = twl4030_write; |
2193 | codec->set_bias_level = twl4030_set_bias_level; | 2203 | codec->set_bias_level = twl4030_set_bias_level; |
2194 | codec->dai = twl4030_dai; | 2204 | codec->dai = twl4030_dai; |
2195 | codec->num_dai = ARRAY_SIZE(twl4030_dai), | 2205 | codec->num_dai = ARRAY_SIZE(twl4030_dai); |
2196 | codec->reg_cache_size = sizeof(twl4030_reg); | 2206 | codec->reg_cache_size = sizeof(twl4030_reg); |
2197 | codec->reg_cache = kmemdup(twl4030_reg, sizeof(twl4030_reg), | 2207 | codec->reg_cache = kmemdup(twl4030_reg, sizeof(twl4030_reg), |
2198 | GFP_KERNEL); | 2208 | GFP_KERNEL); |
@@ -2237,6 +2247,9 @@ static int __devexit twl4030_codec_remove(struct platform_device *pdev) | |||
2237 | { | 2247 | { |
2238 | struct twl4030_priv *twl4030 = platform_get_drvdata(pdev); | 2248 | struct twl4030_priv *twl4030 = platform_get_drvdata(pdev); |
2239 | 2249 | ||
2250 | snd_soc_unregister_dais(&twl4030_dai[0], ARRAY_SIZE(twl4030_dai)); | ||
2251 | snd_soc_unregister_codec(&twl4030->codec); | ||
2252 | kfree(twl4030->codec.reg_cache); | ||
2240 | kfree(twl4030); | 2253 | kfree(twl4030); |
2241 | 2254 | ||
2242 | twl4030_codec = NULL; | 2255 | twl4030_codec = NULL; |
diff --git a/sound/soc/codecs/twl4030.h b/sound/soc/codecs/twl4030.h index dd6396ec9c79..f206d242ca31 100644 --- a/sound/soc/codecs/twl4030.h +++ b/sound/soc/codecs/twl4030.h | |||
@@ -25,7 +25,7 @@ | |||
25 | /* Register descriptions are here */ | 25 | /* Register descriptions are here */ |
26 | #include <linux/mfd/twl4030-codec.h> | 26 | #include <linux/mfd/twl4030-codec.h> |
27 | 27 | ||
28 | /* Sgadow register used by the audio driver */ | 28 | /* Shadow register used by the audio driver */ |
29 | #define TWL4030_REG_SW_SHADOW 0x4A | 29 | #define TWL4030_REG_SW_SHADOW 0x4A |
30 | #define TWL4030_CACHEREGNUM (TWL4030_REG_SW_SHADOW + 1) | 30 | #define TWL4030_CACHEREGNUM (TWL4030_REG_SW_SHADOW + 1) |
31 | 31 | ||
diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c index a2763c2e7348..9cd0a66b7663 100644 --- a/sound/soc/codecs/uda1380.c +++ b/sound/soc/codecs/uda1380.c | |||
@@ -137,7 +137,7 @@ static void uda1380_flush_work(struct work_struct *work) | |||
137 | { | 137 | { |
138 | int bit, reg; | 138 | int bit, reg; |
139 | 139 | ||
140 | for_each_bit(bit, &uda1380_cache_dirty, UDA1380_CACHEREGNUM - 0x10) { | 140 | for_each_set_bit(bit, &uda1380_cache_dirty, UDA1380_CACHEREGNUM - 0x10) { |
141 | reg = 0x10 + bit; | 141 | reg = 0x10 + bit; |
142 | pr_debug("uda1380: flush reg %x val %x:\n", reg, | 142 | pr_debug("uda1380: flush reg %x val %x:\n", reg, |
143 | uda1380_read_reg_cache(uda1380_codec, reg)); | 143 | uda1380_read_reg_cache(uda1380_codec, reg)); |
diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c new file mode 100644 index 000000000000..217b02680597 --- /dev/null +++ b/sound/soc/codecs/wm2000.c | |||
@@ -0,0 +1,888 @@ | |||
1 | /* | ||
2 | * wm2000.c -- WM2000 ALSA Soc Audio driver | ||
3 | * | ||
4 | * Copyright 2008-2010 Wolfson Microelectronics PLC. | ||
5 | * | ||
6 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | ||
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 | * The download image for the WM2000 will be requested as | ||
13 | * 'wm2000_anc.bin' by default (overridable via platform data) at | ||
14 | * runtime and is expected to be in flat binary format. This is | ||
15 | * generated by Wolfson configuration tools and includes | ||
16 | * system-specific callibration information. If supplied as a | ||
17 | * sequence of ASCII-encoded hexidecimal bytes this can be converted | ||
18 | * into a flat binary with a command such as this on the command line: | ||
19 | * | ||
20 | * perl -e 'while (<>) { s/[\r\n]+// ; printf("%c", hex($_)); }' | ||
21 | * < file > wm2000_anc.bin | ||
22 | */ | ||
23 | |||
24 | #include <linux/module.h> | ||
25 | #include <linux/moduleparam.h> | ||
26 | #include <linux/version.h> | ||
27 | #include <linux/kernel.h> | ||
28 | #include <linux/init.h> | ||
29 | #include <linux/firmware.h> | ||
30 | #include <linux/delay.h> | ||
31 | #include <linux/pm.h> | ||
32 | #include <linux/i2c.h> | ||
33 | #include <linux/platform_device.h> | ||
34 | #include <linux/debugfs.h> | ||
35 | #include <sound/core.h> | ||
36 | #include <sound/pcm.h> | ||
37 | #include <sound/pcm_params.h> | ||
38 | #include <sound/soc.h> | ||
39 | #include <sound/soc-dapm.h> | ||
40 | #include <sound/initval.h> | ||
41 | #include <sound/tlv.h> | ||
42 | |||
43 | #include <sound/wm2000.h> | ||
44 | |||
45 | #include "wm2000.h" | ||
46 | |||
47 | enum wm2000_anc_mode { | ||
48 | ANC_ACTIVE = 0, | ||
49 | ANC_BYPASS = 1, | ||
50 | ANC_STANDBY = 2, | ||
51 | ANC_OFF = 3, | ||
52 | }; | ||
53 | |||
54 | struct wm2000_priv { | ||
55 | struct i2c_client *i2c; | ||
56 | |||
57 | enum wm2000_anc_mode anc_mode; | ||
58 | |||
59 | unsigned int anc_active:1; | ||
60 | unsigned int anc_eng_ena:1; | ||
61 | unsigned int spk_ena:1; | ||
62 | |||
63 | unsigned int mclk_div:1; | ||
64 | unsigned int speech_clarity:1; | ||
65 | |||
66 | int anc_download_size; | ||
67 | char *anc_download; | ||
68 | }; | ||
69 | |||
70 | static struct i2c_client *wm2000_i2c; | ||
71 | |||
72 | static int wm2000_write(struct i2c_client *i2c, unsigned int reg, | ||
73 | unsigned int value) | ||
74 | { | ||
75 | u8 data[3]; | ||
76 | int ret; | ||
77 | |||
78 | data[0] = (reg >> 8) & 0xff; | ||
79 | data[1] = reg & 0xff; | ||
80 | data[2] = value & 0xff; | ||
81 | |||
82 | dev_vdbg(&i2c->dev, "write %x = %x\n", reg, value); | ||
83 | |||
84 | ret = i2c_master_send(i2c, data, 3); | ||
85 | if (ret == 3) | ||
86 | return 0; | ||
87 | if (ret < 0) | ||
88 | return ret; | ||
89 | else | ||
90 | return -EIO; | ||
91 | } | ||
92 | |||
93 | static unsigned int wm2000_read(struct i2c_client *i2c, unsigned int r) | ||
94 | { | ||
95 | struct i2c_msg xfer[2]; | ||
96 | u8 reg[2]; | ||
97 | u8 data; | ||
98 | int ret; | ||
99 | |||
100 | /* Write register */ | ||
101 | reg[0] = (r >> 8) & 0xff; | ||
102 | reg[1] = r & 0xff; | ||
103 | xfer[0].addr = i2c->addr; | ||
104 | xfer[0].flags = 0; | ||
105 | xfer[0].len = sizeof(reg); | ||
106 | xfer[0].buf = ®[0]; | ||
107 | |||
108 | /* Read data */ | ||
109 | xfer[1].addr = i2c->addr; | ||
110 | xfer[1].flags = I2C_M_RD; | ||
111 | xfer[1].len = 1; | ||
112 | xfer[1].buf = &data; | ||
113 | |||
114 | ret = i2c_transfer(i2c->adapter, xfer, 2); | ||
115 | if (ret != 2) { | ||
116 | dev_err(&i2c->dev, "i2c_transfer() returned %d\n", ret); | ||
117 | return 0; | ||
118 | } | ||
119 | |||
120 | dev_vdbg(&i2c->dev, "read %x from %x\n", data, r); | ||
121 | |||
122 | return data; | ||
123 | } | ||
124 | |||
125 | static void wm2000_reset(struct wm2000_priv *wm2000) | ||
126 | { | ||
127 | struct i2c_client *i2c = wm2000->i2c; | ||
128 | |||
129 | wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_ANC_ENG_CLR); | ||
130 | wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_RAM_CLR); | ||
131 | wm2000_write(i2c, WM2000_REG_ID1, 0); | ||
132 | |||
133 | wm2000->anc_mode = ANC_OFF; | ||
134 | } | ||
135 | |||
136 | static int wm2000_poll_bit(struct i2c_client *i2c, | ||
137 | unsigned int reg, u8 mask, int timeout) | ||
138 | { | ||
139 | int val; | ||
140 | |||
141 | val = wm2000_read(i2c, reg); | ||
142 | |||
143 | while (!(val & mask) && --timeout) { | ||
144 | msleep(1); | ||
145 | val = wm2000_read(i2c, reg); | ||
146 | } | ||
147 | |||
148 | if (timeout == 0) | ||
149 | return 0; | ||
150 | else | ||
151 | return 1; | ||
152 | } | ||
153 | |||
154 | static int wm2000_power_up(struct i2c_client *i2c, int analogue) | ||
155 | { | ||
156 | struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev); | ||
157 | int ret, timeout; | ||
158 | |||
159 | BUG_ON(wm2000->anc_mode != ANC_OFF); | ||
160 | |||
161 | dev_dbg(&i2c->dev, "Beginning power up\n"); | ||
162 | |||
163 | if (!wm2000->mclk_div) { | ||
164 | dev_dbg(&i2c->dev, "Disabling MCLK divider\n"); | ||
165 | wm2000_write(i2c, WM2000_REG_SYS_CTL2, | ||
166 | WM2000_MCLK_DIV2_ENA_CLR); | ||
167 | } else { | ||
168 | dev_dbg(&i2c->dev, "Enabling MCLK divider\n"); | ||
169 | wm2000_write(i2c, WM2000_REG_SYS_CTL2, | ||
170 | WM2000_MCLK_DIV2_ENA_SET); | ||
171 | } | ||
172 | |||
173 | wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_ANC_ENG_CLR); | ||
174 | wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_ANC_ENG_SET); | ||
175 | |||
176 | /* Wait for ANC engine to become ready */ | ||
177 | if (!wm2000_poll_bit(i2c, WM2000_REG_ANC_STAT, | ||
178 | WM2000_ANC_ENG_IDLE, 1)) { | ||
179 | dev_err(&i2c->dev, "ANC engine failed to reset\n"); | ||
180 | return -ETIMEDOUT; | ||
181 | } | ||
182 | |||
183 | if (!wm2000_poll_bit(i2c, WM2000_REG_SYS_STATUS, | ||
184 | WM2000_STATUS_BOOT_COMPLETE, 1)) { | ||
185 | dev_err(&i2c->dev, "ANC engine failed to initialise\n"); | ||
186 | return -ETIMEDOUT; | ||
187 | } | ||
188 | |||
189 | wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_RAM_SET); | ||
190 | |||
191 | /* Open code download of the data since it is the only bulk | ||
192 | * write we do. */ | ||
193 | dev_dbg(&i2c->dev, "Downloading %d bytes\n", | ||
194 | wm2000->anc_download_size - 2); | ||
195 | |||
196 | ret = i2c_master_send(i2c, wm2000->anc_download, | ||
197 | wm2000->anc_download_size); | ||
198 | if (ret < 0) { | ||
199 | dev_err(&i2c->dev, "i2c_transfer() failed: %d\n", ret); | ||
200 | return ret; | ||
201 | } | ||
202 | if (ret != wm2000->anc_download_size) { | ||
203 | dev_err(&i2c->dev, "i2c_transfer() failed, %d != %d\n", | ||
204 | ret, wm2000->anc_download_size); | ||
205 | return -EIO; | ||
206 | } | ||
207 | |||
208 | dev_dbg(&i2c->dev, "Download complete\n"); | ||
209 | |||
210 | if (analogue) { | ||
211 | timeout = 248; | ||
212 | wm2000_write(i2c, WM2000_REG_ANA_VMID_PU_TIME, timeout / 4); | ||
213 | |||
214 | wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL, | ||
215 | WM2000_MODE_ANA_SEQ_INCLUDE | | ||
216 | WM2000_MODE_MOUSE_ENABLE | | ||
217 | WM2000_MODE_THERMAL_ENABLE); | ||
218 | } else { | ||
219 | timeout = 10; | ||
220 | |||
221 | wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL, | ||
222 | WM2000_MODE_MOUSE_ENABLE | | ||
223 | WM2000_MODE_THERMAL_ENABLE); | ||
224 | } | ||
225 | |||
226 | ret = wm2000_read(i2c, WM2000_REG_SPEECH_CLARITY); | ||
227 | if (wm2000->speech_clarity) | ||
228 | ret &= ~WM2000_SPEECH_CLARITY; | ||
229 | else | ||
230 | ret |= WM2000_SPEECH_CLARITY; | ||
231 | wm2000_write(i2c, WM2000_REG_SPEECH_CLARITY, ret); | ||
232 | |||
233 | wm2000_write(i2c, WM2000_REG_SYS_START0, 0x33); | ||
234 | wm2000_write(i2c, WM2000_REG_SYS_START1, 0x02); | ||
235 | |||
236 | wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_ANC_INT_N_CLR); | ||
237 | |||
238 | if (!wm2000_poll_bit(i2c, WM2000_REG_SYS_STATUS, | ||
239 | WM2000_STATUS_MOUSE_ACTIVE, timeout)) { | ||
240 | dev_err(&i2c->dev, "Timed out waiting for device after %dms\n", | ||
241 | timeout * 10); | ||
242 | return -ETIMEDOUT; | ||
243 | } | ||
244 | |||
245 | dev_dbg(&i2c->dev, "ANC active\n"); | ||
246 | if (analogue) | ||
247 | dev_dbg(&i2c->dev, "Analogue active\n"); | ||
248 | wm2000->anc_mode = ANC_ACTIVE; | ||
249 | |||
250 | return 0; | ||
251 | } | ||
252 | |||
253 | static int wm2000_power_down(struct i2c_client *i2c, int analogue) | ||
254 | { | ||
255 | struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev); | ||
256 | int timeout; | ||
257 | |||
258 | if (analogue) { | ||
259 | timeout = 248; | ||
260 | wm2000_write(i2c, WM2000_REG_ANA_VMID_PD_TIME, timeout / 4); | ||
261 | wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL, | ||
262 | WM2000_MODE_ANA_SEQ_INCLUDE | | ||
263 | WM2000_MODE_POWER_DOWN); | ||
264 | } else { | ||
265 | timeout = 10; | ||
266 | wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL, | ||
267 | WM2000_MODE_POWER_DOWN); | ||
268 | } | ||
269 | |||
270 | if (!wm2000_poll_bit(i2c, WM2000_REG_SYS_STATUS, | ||
271 | WM2000_STATUS_POWER_DOWN_COMPLETE, timeout)) { | ||
272 | dev_err(&i2c->dev, "Timeout waiting for ANC power down\n"); | ||
273 | return -ETIMEDOUT; | ||
274 | } | ||
275 | |||
276 | if (!wm2000_poll_bit(i2c, WM2000_REG_ANC_STAT, | ||
277 | WM2000_ANC_ENG_IDLE, 1)) { | ||
278 | dev_err(&i2c->dev, "Timeout waiting for ANC engine idle\n"); | ||
279 | return -ETIMEDOUT; | ||
280 | } | ||
281 | |||
282 | dev_dbg(&i2c->dev, "powered off\n"); | ||
283 | wm2000->anc_mode = ANC_OFF; | ||
284 | |||
285 | return 0; | ||
286 | } | ||
287 | |||
288 | static int wm2000_enter_bypass(struct i2c_client *i2c, int analogue) | ||
289 | { | ||
290 | struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev); | ||
291 | |||
292 | BUG_ON(wm2000->anc_mode != ANC_ACTIVE); | ||
293 | |||
294 | if (analogue) { | ||
295 | wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL, | ||
296 | WM2000_MODE_ANA_SEQ_INCLUDE | | ||
297 | WM2000_MODE_THERMAL_ENABLE | | ||
298 | WM2000_MODE_BYPASS_ENTRY); | ||
299 | } else { | ||
300 | wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL, | ||
301 | WM2000_MODE_THERMAL_ENABLE | | ||
302 | WM2000_MODE_BYPASS_ENTRY); | ||
303 | } | ||
304 | |||
305 | if (!wm2000_poll_bit(i2c, WM2000_REG_SYS_STATUS, | ||
306 | WM2000_STATUS_ANC_DISABLED, 10)) { | ||
307 | dev_err(&i2c->dev, "Timeout waiting for ANC disable\n"); | ||
308 | return -ETIMEDOUT; | ||
309 | } | ||
310 | |||
311 | if (!wm2000_poll_bit(i2c, WM2000_REG_ANC_STAT, | ||
312 | WM2000_ANC_ENG_IDLE, 1)) { | ||
313 | dev_err(&i2c->dev, "Timeout waiting for ANC engine idle\n"); | ||
314 | return -ETIMEDOUT; | ||
315 | } | ||
316 | |||
317 | wm2000_write(i2c, WM2000_REG_SYS_CTL1, WM2000_SYS_STBY); | ||
318 | wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_RAM_CLR); | ||
319 | |||
320 | wm2000->anc_mode = ANC_BYPASS; | ||
321 | dev_dbg(&i2c->dev, "bypass enabled\n"); | ||
322 | |||
323 | return 0; | ||
324 | } | ||
325 | |||
326 | static int wm2000_exit_bypass(struct i2c_client *i2c, int analogue) | ||
327 | { | ||
328 | struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev); | ||
329 | |||
330 | BUG_ON(wm2000->anc_mode != ANC_BYPASS); | ||
331 | |||
332 | wm2000_write(i2c, WM2000_REG_SYS_CTL1, 0); | ||
333 | |||
334 | if (analogue) { | ||
335 | wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL, | ||
336 | WM2000_MODE_ANA_SEQ_INCLUDE | | ||
337 | WM2000_MODE_MOUSE_ENABLE | | ||
338 | WM2000_MODE_THERMAL_ENABLE); | ||
339 | } else { | ||
340 | wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL, | ||
341 | WM2000_MODE_MOUSE_ENABLE | | ||
342 | WM2000_MODE_THERMAL_ENABLE); | ||
343 | } | ||
344 | |||
345 | wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_RAM_SET); | ||
346 | wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_ANC_INT_N_CLR); | ||
347 | |||
348 | if (!wm2000_poll_bit(i2c, WM2000_REG_SYS_STATUS, | ||
349 | WM2000_STATUS_MOUSE_ACTIVE, 10)) { | ||
350 | dev_err(&i2c->dev, "Timed out waiting for MOUSE\n"); | ||
351 | return -ETIMEDOUT; | ||
352 | } | ||
353 | |||
354 | wm2000->anc_mode = ANC_ACTIVE; | ||
355 | dev_dbg(&i2c->dev, "MOUSE active\n"); | ||
356 | |||
357 | return 0; | ||
358 | } | ||
359 | |||
360 | static int wm2000_enter_standby(struct i2c_client *i2c, int analogue) | ||
361 | { | ||
362 | struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev); | ||
363 | int timeout; | ||
364 | |||
365 | BUG_ON(wm2000->anc_mode != ANC_ACTIVE); | ||
366 | |||
367 | if (analogue) { | ||
368 | timeout = 248; | ||
369 | wm2000_write(i2c, WM2000_REG_ANA_VMID_PD_TIME, timeout / 4); | ||
370 | |||
371 | wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL, | ||
372 | WM2000_MODE_ANA_SEQ_INCLUDE | | ||
373 | WM2000_MODE_THERMAL_ENABLE | | ||
374 | WM2000_MODE_STANDBY_ENTRY); | ||
375 | } else { | ||
376 | timeout = 10; | ||
377 | |||
378 | wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL, | ||
379 | WM2000_MODE_THERMAL_ENABLE | | ||
380 | WM2000_MODE_STANDBY_ENTRY); | ||
381 | } | ||
382 | |||
383 | if (!wm2000_poll_bit(i2c, WM2000_REG_SYS_STATUS, | ||
384 | WM2000_STATUS_ANC_DISABLED, timeout)) { | ||
385 | dev_err(&i2c->dev, | ||
386 | "Timed out waiting for ANC disable after 1ms\n"); | ||
387 | return -ETIMEDOUT; | ||
388 | } | ||
389 | |||
390 | if (!wm2000_poll_bit(i2c, WM2000_REG_ANC_STAT, WM2000_ANC_ENG_IDLE, | ||
391 | 1)) { | ||
392 | dev_err(&i2c->dev, | ||
393 | "Timed out waiting for standby after %dms\n", | ||
394 | timeout * 10); | ||
395 | return -ETIMEDOUT; | ||
396 | } | ||
397 | |||
398 | wm2000_write(i2c, WM2000_REG_SYS_CTL1, WM2000_SYS_STBY); | ||
399 | wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_RAM_CLR); | ||
400 | |||
401 | wm2000->anc_mode = ANC_STANDBY; | ||
402 | dev_dbg(&i2c->dev, "standby\n"); | ||
403 | if (analogue) | ||
404 | dev_dbg(&i2c->dev, "Analogue disabled\n"); | ||
405 | |||
406 | return 0; | ||
407 | } | ||
408 | |||
409 | static int wm2000_exit_standby(struct i2c_client *i2c, int analogue) | ||
410 | { | ||
411 | struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev); | ||
412 | int timeout; | ||
413 | |||
414 | BUG_ON(wm2000->anc_mode != ANC_STANDBY); | ||
415 | |||
416 | wm2000_write(i2c, WM2000_REG_SYS_CTL1, 0); | ||
417 | |||
418 | if (analogue) { | ||
419 | timeout = 248; | ||
420 | wm2000_write(i2c, WM2000_REG_ANA_VMID_PU_TIME, timeout / 4); | ||
421 | |||
422 | wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL, | ||
423 | WM2000_MODE_ANA_SEQ_INCLUDE | | ||
424 | WM2000_MODE_THERMAL_ENABLE | | ||
425 | WM2000_MODE_MOUSE_ENABLE); | ||
426 | } else { | ||
427 | timeout = 10; | ||
428 | |||
429 | wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL, | ||
430 | WM2000_MODE_THERMAL_ENABLE | | ||
431 | WM2000_MODE_MOUSE_ENABLE); | ||
432 | } | ||
433 | |||
434 | wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_RAM_SET); | ||
435 | wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_ANC_INT_N_CLR); | ||
436 | |||
437 | if (!wm2000_poll_bit(i2c, WM2000_REG_SYS_STATUS, | ||
438 | WM2000_STATUS_MOUSE_ACTIVE, timeout)) { | ||
439 | dev_err(&i2c->dev, "Timed out waiting for MOUSE after %dms\n", | ||
440 | timeout * 10); | ||
441 | return -ETIMEDOUT; | ||
442 | } | ||
443 | |||
444 | wm2000->anc_mode = ANC_ACTIVE; | ||
445 | dev_dbg(&i2c->dev, "MOUSE active\n"); | ||
446 | if (analogue) | ||
447 | dev_dbg(&i2c->dev, "Analogue enabled\n"); | ||
448 | |||
449 | return 0; | ||
450 | } | ||
451 | |||
452 | typedef int (*wm2000_mode_fn)(struct i2c_client *i2c, int analogue); | ||
453 | |||
454 | static struct { | ||
455 | enum wm2000_anc_mode source; | ||
456 | enum wm2000_anc_mode dest; | ||
457 | int analogue; | ||
458 | wm2000_mode_fn step[2]; | ||
459 | } anc_transitions[] = { | ||
460 | { | ||
461 | .source = ANC_OFF, | ||
462 | .dest = ANC_ACTIVE, | ||
463 | .analogue = 1, | ||
464 | .step = { | ||
465 | wm2000_power_up, | ||
466 | }, | ||
467 | }, | ||
468 | { | ||
469 | .source = ANC_OFF, | ||
470 | .dest = ANC_STANDBY, | ||
471 | .step = { | ||
472 | wm2000_power_up, | ||
473 | wm2000_enter_standby, | ||
474 | }, | ||
475 | }, | ||
476 | { | ||
477 | .source = ANC_OFF, | ||
478 | .dest = ANC_BYPASS, | ||
479 | .analogue = 1, | ||
480 | .step = { | ||
481 | wm2000_power_up, | ||
482 | wm2000_enter_bypass, | ||
483 | }, | ||
484 | }, | ||
485 | { | ||
486 | .source = ANC_ACTIVE, | ||
487 | .dest = ANC_BYPASS, | ||
488 | .analogue = 1, | ||
489 | .step = { | ||
490 | wm2000_enter_bypass, | ||
491 | }, | ||
492 | }, | ||
493 | { | ||
494 | .source = ANC_ACTIVE, | ||
495 | .dest = ANC_STANDBY, | ||
496 | .analogue = 1, | ||
497 | .step = { | ||
498 | wm2000_enter_standby, | ||
499 | }, | ||
500 | }, | ||
501 | { | ||
502 | .source = ANC_ACTIVE, | ||
503 | .dest = ANC_OFF, | ||
504 | .analogue = 1, | ||
505 | .step = { | ||
506 | wm2000_power_down, | ||
507 | }, | ||
508 | }, | ||
509 | { | ||
510 | .source = ANC_BYPASS, | ||
511 | .dest = ANC_ACTIVE, | ||
512 | .analogue = 1, | ||
513 | .step = { | ||
514 | wm2000_exit_bypass, | ||
515 | }, | ||
516 | }, | ||
517 | { | ||
518 | .source = ANC_BYPASS, | ||
519 | .dest = ANC_STANDBY, | ||
520 | .analogue = 1, | ||
521 | .step = { | ||
522 | wm2000_exit_bypass, | ||
523 | wm2000_enter_standby, | ||
524 | }, | ||
525 | }, | ||
526 | { | ||
527 | .source = ANC_BYPASS, | ||
528 | .dest = ANC_OFF, | ||
529 | .step = { | ||
530 | wm2000_exit_bypass, | ||
531 | wm2000_power_down, | ||
532 | }, | ||
533 | }, | ||
534 | { | ||
535 | .source = ANC_STANDBY, | ||
536 | .dest = ANC_ACTIVE, | ||
537 | .analogue = 1, | ||
538 | .step = { | ||
539 | wm2000_exit_standby, | ||
540 | }, | ||
541 | }, | ||
542 | { | ||
543 | .source = ANC_STANDBY, | ||
544 | .dest = ANC_BYPASS, | ||
545 | .analogue = 1, | ||
546 | .step = { | ||
547 | wm2000_exit_standby, | ||
548 | wm2000_enter_bypass, | ||
549 | }, | ||
550 | }, | ||
551 | { | ||
552 | .source = ANC_STANDBY, | ||
553 | .dest = ANC_OFF, | ||
554 | .step = { | ||
555 | wm2000_exit_standby, | ||
556 | wm2000_power_down, | ||
557 | }, | ||
558 | }, | ||
559 | }; | ||
560 | |||
561 | static int wm2000_anc_transition(struct wm2000_priv *wm2000, | ||
562 | enum wm2000_anc_mode mode) | ||
563 | { | ||
564 | struct i2c_client *i2c = wm2000->i2c; | ||
565 | int i, j; | ||
566 | int ret; | ||
567 | |||
568 | if (wm2000->anc_mode == mode) | ||
569 | return 0; | ||
570 | |||
571 | for (i = 0; i < ARRAY_SIZE(anc_transitions); i++) | ||
572 | if (anc_transitions[i].source == wm2000->anc_mode && | ||
573 | anc_transitions[i].dest == mode) | ||
574 | break; | ||
575 | if (i == ARRAY_SIZE(anc_transitions)) { | ||
576 | dev_err(&i2c->dev, "No transition for %d->%d\n", | ||
577 | wm2000->anc_mode, mode); | ||
578 | return -EINVAL; | ||
579 | } | ||
580 | |||
581 | for (j = 0; j < ARRAY_SIZE(anc_transitions[j].step); j++) { | ||
582 | if (!anc_transitions[i].step[j]) | ||
583 | break; | ||
584 | ret = anc_transitions[i].step[j](i2c, | ||
585 | anc_transitions[i].analogue); | ||
586 | if (ret != 0) | ||
587 | return ret; | ||
588 | } | ||
589 | |||
590 | return 0; | ||
591 | } | ||
592 | |||
593 | static int wm2000_anc_set_mode(struct wm2000_priv *wm2000) | ||
594 | { | ||
595 | struct i2c_client *i2c = wm2000->i2c; | ||
596 | enum wm2000_anc_mode mode; | ||
597 | |||
598 | if (wm2000->anc_eng_ena && wm2000->spk_ena) | ||
599 | if (wm2000->anc_active) | ||
600 | mode = ANC_ACTIVE; | ||
601 | else | ||
602 | mode = ANC_BYPASS; | ||
603 | else | ||
604 | mode = ANC_STANDBY; | ||
605 | |||
606 | dev_dbg(&i2c->dev, "Set mode %d (enabled %d, mute %d, active %d)\n", | ||
607 | mode, wm2000->anc_eng_ena, !wm2000->spk_ena, | ||
608 | wm2000->anc_active); | ||
609 | |||
610 | return wm2000_anc_transition(wm2000, mode); | ||
611 | } | ||
612 | |||
613 | static int wm2000_anc_mode_get(struct snd_kcontrol *kcontrol, | ||
614 | struct snd_ctl_elem_value *ucontrol) | ||
615 | { | ||
616 | struct wm2000_priv *wm2000 = dev_get_drvdata(&wm2000_i2c->dev); | ||
617 | |||
618 | ucontrol->value.enumerated.item[0] = wm2000->anc_active; | ||
619 | |||
620 | return 0; | ||
621 | } | ||
622 | |||
623 | static int wm2000_anc_mode_put(struct snd_kcontrol *kcontrol, | ||
624 | struct snd_ctl_elem_value *ucontrol) | ||
625 | { | ||
626 | struct wm2000_priv *wm2000 = dev_get_drvdata(&wm2000_i2c->dev); | ||
627 | int anc_active = ucontrol->value.enumerated.item[0]; | ||
628 | |||
629 | if (anc_active > 1) | ||
630 | return -EINVAL; | ||
631 | |||
632 | wm2000->anc_active = anc_active; | ||
633 | |||
634 | return wm2000_anc_set_mode(wm2000); | ||
635 | } | ||
636 | |||
637 | static int wm2000_speaker_get(struct snd_kcontrol *kcontrol, | ||
638 | struct snd_ctl_elem_value *ucontrol) | ||
639 | { | ||
640 | struct wm2000_priv *wm2000 = dev_get_drvdata(&wm2000_i2c->dev); | ||
641 | |||
642 | ucontrol->value.enumerated.item[0] = wm2000->spk_ena; | ||
643 | |||
644 | return 0; | ||
645 | } | ||
646 | |||
647 | static int wm2000_speaker_put(struct snd_kcontrol *kcontrol, | ||
648 | struct snd_ctl_elem_value *ucontrol) | ||
649 | { | ||
650 | struct wm2000_priv *wm2000 = dev_get_drvdata(&wm2000_i2c->dev); | ||
651 | int val = ucontrol->value.enumerated.item[0]; | ||
652 | |||
653 | if (val > 1) | ||
654 | return -EINVAL; | ||
655 | |||
656 | wm2000->spk_ena = val; | ||
657 | |||
658 | return wm2000_anc_set_mode(wm2000); | ||
659 | } | ||
660 | |||
661 | static const struct snd_kcontrol_new wm2000_controls[] = { | ||
662 | SOC_SINGLE_BOOL_EXT("WM2000 ANC Switch", 0, | ||
663 | wm2000_anc_mode_get, | ||
664 | wm2000_anc_mode_put), | ||
665 | SOC_SINGLE_BOOL_EXT("WM2000 Switch", 0, | ||
666 | wm2000_speaker_get, | ||
667 | wm2000_speaker_put), | ||
668 | }; | ||
669 | |||
670 | static int wm2000_anc_power_event(struct snd_soc_dapm_widget *w, | ||
671 | struct snd_kcontrol *kcontrol, int event) | ||
672 | { | ||
673 | struct wm2000_priv *wm2000 = dev_get_drvdata(&wm2000_i2c->dev); | ||
674 | |||
675 | if (SND_SOC_DAPM_EVENT_ON(event)) | ||
676 | wm2000->anc_eng_ena = 1; | ||
677 | |||
678 | if (SND_SOC_DAPM_EVENT_OFF(event)) | ||
679 | wm2000->anc_eng_ena = 0; | ||
680 | |||
681 | return wm2000_anc_set_mode(wm2000); | ||
682 | } | ||
683 | |||
684 | static const struct snd_soc_dapm_widget wm2000_dapm_widgets[] = { | ||
685 | /* Externally visible pins */ | ||
686 | SND_SOC_DAPM_OUTPUT("WM2000 SPKN"), | ||
687 | SND_SOC_DAPM_OUTPUT("WM2000 SPKP"), | ||
688 | |||
689 | SND_SOC_DAPM_INPUT("WM2000 LINN"), | ||
690 | SND_SOC_DAPM_INPUT("WM2000 LINP"), | ||
691 | |||
692 | SND_SOC_DAPM_PGA_E("ANC Engine", SND_SOC_NOPM, 0, 0, NULL, 0, | ||
693 | wm2000_anc_power_event, | ||
694 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), | ||
695 | }; | ||
696 | |||
697 | /* Target, Path, Source */ | ||
698 | static const struct snd_soc_dapm_route audio_map[] = { | ||
699 | { "WM2000 SPKN", NULL, "ANC Engine" }, | ||
700 | { "WM2000 SPKP", NULL, "ANC Engine" }, | ||
701 | { "ANC Engine", NULL, "WM2000 LINN" }, | ||
702 | { "ANC Engine", NULL, "WM2000 LINP" }, | ||
703 | }; | ||
704 | |||
705 | /* Called from the machine driver */ | ||
706 | int wm2000_add_controls(struct snd_soc_codec *codec) | ||
707 | { | ||
708 | int ret; | ||
709 | |||
710 | if (!wm2000_i2c) { | ||
711 | pr_err("WM2000 not yet probed\n"); | ||
712 | return -ENODEV; | ||
713 | } | ||
714 | |||
715 | ret = snd_soc_dapm_new_controls(codec, wm2000_dapm_widgets, | ||
716 | ARRAY_SIZE(wm2000_dapm_widgets)); | ||
717 | if (ret < 0) | ||
718 | return ret; | ||
719 | |||
720 | ret = snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | ||
721 | if (ret < 0) | ||
722 | return ret; | ||
723 | |||
724 | return snd_soc_add_controls(codec, wm2000_controls, | ||
725 | ARRAY_SIZE(wm2000_controls)); | ||
726 | } | ||
727 | EXPORT_SYMBOL_GPL(wm2000_add_controls); | ||
728 | |||
729 | static int __devinit wm2000_i2c_probe(struct i2c_client *i2c, | ||
730 | const struct i2c_device_id *i2c_id) | ||
731 | { | ||
732 | struct wm2000_priv *wm2000; | ||
733 | struct wm2000_platform_data *pdata; | ||
734 | const char *filename; | ||
735 | const struct firmware *fw; | ||
736 | int reg, ret; | ||
737 | u16 id; | ||
738 | |||
739 | if (wm2000_i2c) { | ||
740 | dev_err(&i2c->dev, "Another WM2000 is already registered\n"); | ||
741 | return -EINVAL; | ||
742 | } | ||
743 | |||
744 | wm2000 = kzalloc(sizeof(struct wm2000_priv), GFP_KERNEL); | ||
745 | if (wm2000 == NULL) { | ||
746 | dev_err(&i2c->dev, "Unable to allocate private data\n"); | ||
747 | return -ENOMEM; | ||
748 | } | ||
749 | |||
750 | /* Verify that this is a WM2000 */ | ||
751 | reg = wm2000_read(i2c, WM2000_REG_ID1); | ||
752 | id = reg << 8; | ||
753 | reg = wm2000_read(i2c, WM2000_REG_ID2); | ||
754 | id |= reg & 0xff; | ||
755 | |||
756 | if (id != 0x2000) { | ||
757 | dev_err(&i2c->dev, "Device is not a WM2000 - ID %x\n", id); | ||
758 | ret = -ENODEV; | ||
759 | goto err; | ||
760 | } | ||
761 | |||
762 | reg = wm2000_read(i2c, WM2000_REG_REVISON); | ||
763 | dev_info(&i2c->dev, "revision %c\n", reg + 'A'); | ||
764 | |||
765 | filename = "wm2000_anc.bin"; | ||
766 | pdata = dev_get_platdata(&i2c->dev); | ||
767 | if (pdata) { | ||
768 | wm2000->mclk_div = pdata->mclkdiv2; | ||
769 | wm2000->speech_clarity = !pdata->speech_enh_disable; | ||
770 | |||
771 | if (pdata->download_file) | ||
772 | filename = pdata->download_file; | ||
773 | } | ||
774 | |||
775 | ret = request_firmware(&fw, filename, &i2c->dev); | ||
776 | if (ret != 0) { | ||
777 | dev_err(&i2c->dev, "Failed to acquire ANC data: %d\n", ret); | ||
778 | goto err; | ||
779 | } | ||
780 | |||
781 | /* Pre-cook the concatenation of the register address onto the image */ | ||
782 | wm2000->anc_download_size = fw->size + 2; | ||
783 | wm2000->anc_download = kmalloc(wm2000->anc_download_size, GFP_KERNEL); | ||
784 | if (wm2000->anc_download == NULL) { | ||
785 | dev_err(&i2c->dev, "Out of memory\n"); | ||
786 | ret = -ENOMEM; | ||
787 | goto err_fw; | ||
788 | } | ||
789 | |||
790 | wm2000->anc_download[0] = 0x80; | ||
791 | wm2000->anc_download[1] = 0x00; | ||
792 | memcpy(wm2000->anc_download + 2, fw->data, fw->size); | ||
793 | |||
794 | release_firmware(fw); | ||
795 | |||
796 | dev_set_drvdata(&i2c->dev, wm2000); | ||
797 | wm2000->anc_eng_ena = 1; | ||
798 | wm2000->i2c = i2c; | ||
799 | |||
800 | wm2000_reset(wm2000); | ||
801 | |||
802 | /* This will trigger a transition to standby mode by default */ | ||
803 | wm2000_anc_set_mode(wm2000); | ||
804 | |||
805 | wm2000_i2c = i2c; | ||
806 | |||
807 | return 0; | ||
808 | |||
809 | err_fw: | ||
810 | release_firmware(fw); | ||
811 | err: | ||
812 | kfree(wm2000); | ||
813 | return ret; | ||
814 | } | ||
815 | |||
816 | static __devexit int wm2000_i2c_remove(struct i2c_client *i2c) | ||
817 | { | ||
818 | struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev); | ||
819 | |||
820 | wm2000_anc_transition(wm2000, ANC_OFF); | ||
821 | |||
822 | wm2000_i2c = NULL; | ||
823 | kfree(wm2000->anc_download); | ||
824 | kfree(wm2000); | ||
825 | |||
826 | return 0; | ||
827 | } | ||
828 | |||
829 | static void wm2000_i2c_shutdown(struct i2c_client *i2c) | ||
830 | { | ||
831 | struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev); | ||
832 | |||
833 | wm2000_anc_transition(wm2000, ANC_OFF); | ||
834 | } | ||
835 | |||
836 | #ifdef CONFIG_PM | ||
837 | static int wm2000_i2c_suspend(struct i2c_client *i2c, pm_message_t mesg) | ||
838 | { | ||
839 | struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev); | ||
840 | |||
841 | return wm2000_anc_transition(wm2000, ANC_OFF); | ||
842 | } | ||
843 | |||
844 | static int wm2000_i2c_resume(struct i2c_client *i2c) | ||
845 | { | ||
846 | struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev); | ||
847 | |||
848 | return wm2000_anc_set_mode(wm2000); | ||
849 | } | ||
850 | #else | ||
851 | #define wm2000_i2c_suspend NULL | ||
852 | #define wm2000_i2c_resume NULL | ||
853 | #endif | ||
854 | |||
855 | static const struct i2c_device_id wm2000_i2c_id[] = { | ||
856 | { "wm2000", 0 }, | ||
857 | { } | ||
858 | }; | ||
859 | MODULE_DEVICE_TABLE(i2c, wm2000_i2c_id); | ||
860 | |||
861 | static struct i2c_driver wm2000_i2c_driver = { | ||
862 | .driver = { | ||
863 | .name = "wm2000", | ||
864 | .owner = THIS_MODULE, | ||
865 | }, | ||
866 | .probe = wm2000_i2c_probe, | ||
867 | .remove = __devexit_p(wm2000_i2c_remove), | ||
868 | .suspend = wm2000_i2c_suspend, | ||
869 | .resume = wm2000_i2c_resume, | ||
870 | .shutdown = wm2000_i2c_shutdown, | ||
871 | .id_table = wm2000_i2c_id, | ||
872 | }; | ||
873 | |||
874 | static int __init wm2000_init(void) | ||
875 | { | ||
876 | return i2c_add_driver(&wm2000_i2c_driver); | ||
877 | } | ||
878 | module_init(wm2000_init); | ||
879 | |||
880 | static void __exit wm2000_exit(void) | ||
881 | { | ||
882 | i2c_del_driver(&wm2000_i2c_driver); | ||
883 | } | ||
884 | module_exit(wm2000_exit); | ||
885 | |||
886 | MODULE_DESCRIPTION("ASoC WM2000 driver"); | ||
887 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfonmicro.com>"); | ||
888 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/wm2000.h b/sound/soc/codecs/wm2000.h new file mode 100644 index 000000000000..c18e261c3c7f --- /dev/null +++ b/sound/soc/codecs/wm2000.h | |||
@@ -0,0 +1,79 @@ | |||
1 | /* | ||
2 | * wm2000.h -- WM2000 Soc Audio driver | ||
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 _WM2000_H | ||
10 | #define _WM2000_H | ||
11 | |||
12 | struct wm2000_setup_data { | ||
13 | unsigned short i2c_address; | ||
14 | int mclk_div; /* Set to a non-zero value if MCLK_DIV_2 required */ | ||
15 | }; | ||
16 | |||
17 | extern int wm2000_add_controls(struct snd_soc_codec *codec); | ||
18 | |||
19 | extern struct snd_soc_dai wm2000_dai; | ||
20 | extern struct snd_soc_codec_device soc_codec_dev_wm2000; | ||
21 | |||
22 | #define WM2000_REG_SYS_START 0x8000 | ||
23 | #define WM2000_REG_SPEECH_CLARITY 0x8fef | ||
24 | #define WM2000_REG_SYS_WATCHDOG 0x8ff6 | ||
25 | #define WM2000_REG_ANA_VMID_PD_TIME 0x8ff7 | ||
26 | #define WM2000_REG_ANA_VMID_PU_TIME 0x8ff8 | ||
27 | #define WM2000_REG_CAT_FLTR_INDX 0x8ff9 | ||
28 | #define WM2000_REG_CAT_GAIN_0 0x8ffa | ||
29 | #define WM2000_REG_SYS_STATUS 0x8ffc | ||
30 | #define WM2000_REG_SYS_MODE_CNTRL 0x8ffd | ||
31 | #define WM2000_REG_SYS_START0 0x8ffe | ||
32 | #define WM2000_REG_SYS_START1 0x8fff | ||
33 | #define WM2000_REG_ID1 0xf000 | ||
34 | #define WM2000_REG_ID2 0xf001 | ||
35 | #define WM2000_REG_REVISON 0xf002 | ||
36 | #define WM2000_REG_SYS_CTL1 0xf003 | ||
37 | #define WM2000_REG_SYS_CTL2 0xf004 | ||
38 | #define WM2000_REG_ANC_STAT 0xf005 | ||
39 | #define WM2000_REG_IF_CTL 0xf006 | ||
40 | |||
41 | /* SPEECH_CLARITY */ | ||
42 | #define WM2000_SPEECH_CLARITY 0x01 | ||
43 | |||
44 | /* SYS_STATUS */ | ||
45 | #define WM2000_STATUS_MOUSE_ACTIVE 0x40 | ||
46 | #define WM2000_STATUS_CAT_FREQ_COMPLETE 0x20 | ||
47 | #define WM2000_STATUS_CAT_GAIN_COMPLETE 0x10 | ||
48 | #define WM2000_STATUS_THERMAL_SHUTDOWN_COMPLETE 0x08 | ||
49 | #define WM2000_STATUS_ANC_DISABLED 0x04 | ||
50 | #define WM2000_STATUS_POWER_DOWN_COMPLETE 0x02 | ||
51 | #define WM2000_STATUS_BOOT_COMPLETE 0x01 | ||
52 | |||
53 | /* SYS_MODE_CNTRL */ | ||
54 | #define WM2000_MODE_ANA_SEQ_INCLUDE 0x80 | ||
55 | #define WM2000_MODE_MOUSE_ENABLE 0x40 | ||
56 | #define WM2000_MODE_CAT_FREQ_ENABLE 0x20 | ||
57 | #define WM2000_MODE_CAT_GAIN_ENABLE 0x10 | ||
58 | #define WM2000_MODE_BYPASS_ENTRY 0x08 | ||
59 | #define WM2000_MODE_STANDBY_ENTRY 0x04 | ||
60 | #define WM2000_MODE_THERMAL_ENABLE 0x02 | ||
61 | #define WM2000_MODE_POWER_DOWN 0x01 | ||
62 | |||
63 | /* SYS_CTL1 */ | ||
64 | #define WM2000_SYS_STBY 0x01 | ||
65 | |||
66 | /* SYS_CTL2 */ | ||
67 | #define WM2000_MCLK_DIV2_ENA_CLR 0x80 | ||
68 | #define WM2000_MCLK_DIV2_ENA_SET 0x40 | ||
69 | #define WM2000_ANC_ENG_CLR 0x20 | ||
70 | #define WM2000_ANC_ENG_SET 0x10 | ||
71 | #define WM2000_ANC_INT_N_CLR 0x08 | ||
72 | #define WM2000_ANC_INT_N_SET 0x04 | ||
73 | #define WM2000_RAM_CLR 0x02 | ||
74 | #define WM2000_RAM_SET 0x01 | ||
75 | |||
76 | /* ANC_STAT */ | ||
77 | #define WM2000_ANC_ENG_IDLE 0x01 | ||
78 | |||
79 | #endif | ||
diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index 718ef912e758..df2c6d9617fb 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c | |||
@@ -1349,7 +1349,7 @@ static irqreturn_t wm8350_hp_jack_handler(int irq, void *data) | |||
1349 | int mask; | 1349 | int mask; |
1350 | struct wm8350_jack_data *jack = NULL; | 1350 | struct wm8350_jack_data *jack = NULL; |
1351 | 1351 | ||
1352 | switch (irq) { | 1352 | switch (irq - wm8350->irq_base) { |
1353 | case WM8350_IRQ_CODEC_JCK_DET_L: | 1353 | case WM8350_IRQ_CODEC_JCK_DET_L: |
1354 | jack = &priv->hpl; | 1354 | jack = &priv->hpl; |
1355 | mask = WM8350_JACK_L_LVL; | 1355 | mask = WM8350_JACK_L_LVL; |
@@ -1424,7 +1424,7 @@ int wm8350_hp_jack_detect(struct snd_soc_codec *codec, enum wm8350_jack which, | |||
1424 | wm8350_set_bits(wm8350, WM8350_JACK_DETECT, ena); | 1424 | wm8350_set_bits(wm8350, WM8350_JACK_DETECT, ena); |
1425 | 1425 | ||
1426 | /* Sync status */ | 1426 | /* Sync status */ |
1427 | wm8350_hp_jack_handler(irq, priv); | 1427 | wm8350_hp_jack_handler(irq + wm8350->irq_base, priv); |
1428 | 1428 | ||
1429 | return 0; | 1429 | return 0; |
1430 | } | 1430 | } |
@@ -1521,8 +1521,8 @@ static int wm8350_remove(struct platform_device *pdev) | |||
1521 | WM8350_JDL_ENA | WM8350_JDR_ENA); | 1521 | WM8350_JDL_ENA | WM8350_JDR_ENA); |
1522 | wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_TOCLK_ENA); | 1522 | wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_TOCLK_ENA); |
1523 | 1523 | ||
1524 | wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L); | 1524 | wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L, priv); |
1525 | wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R); | 1525 | wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R, priv); |
1526 | 1526 | ||
1527 | priv->hpl.jack = NULL; | 1527 | priv->hpl.jack = NULL; |
1528 | priv->hpr.jack = NULL; | 1528 | priv->hpr.jack = NULL; |
diff --git a/sound/soc/codecs/wm8727.c b/sound/soc/codecs/wm8727.c index d8ffbd641d71..63a254e293ca 100644 --- a/sound/soc/codecs/wm8727.c +++ b/sound/soc/codecs/wm8727.c | |||
@@ -44,23 +44,16 @@ struct snd_soc_dai wm8727_dai = { | |||
44 | }; | 44 | }; |
45 | EXPORT_SYMBOL_GPL(wm8727_dai); | 45 | EXPORT_SYMBOL_GPL(wm8727_dai); |
46 | 46 | ||
47 | static struct snd_soc_codec *wm8727_codec; | ||
48 | |||
47 | static int wm8727_soc_probe(struct platform_device *pdev) | 49 | static int wm8727_soc_probe(struct platform_device *pdev) |
48 | { | 50 | { |
49 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 51 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
50 | struct snd_soc_codec *codec; | ||
51 | int ret = 0; | 52 | int ret = 0; |
52 | 53 | ||
53 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | 54 | BUG_ON(!wm8727_codec); |
54 | if (codec == NULL) | 55 | |
55 | return -ENOMEM; | 56 | socdev->card->codec = wm8727_codec; |
56 | mutex_init(&codec->mutex); | ||
57 | codec->name = "WM8727"; | ||
58 | codec->owner = THIS_MODULE; | ||
59 | codec->dai = &wm8727_dai; | ||
60 | codec->num_dai = 1; | ||
61 | socdev->card->codec = codec; | ||
62 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
63 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
64 | 57 | ||
65 | /* register pcms */ | 58 | /* register pcms */ |
66 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | 59 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); |
@@ -80,12 +73,9 @@ pcm_err: | |||
80 | static int wm8727_soc_remove(struct platform_device *pdev) | 73 | static int wm8727_soc_remove(struct platform_device *pdev) |
81 | { | 74 | { |
82 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 75 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
83 | struct snd_soc_codec *codec = socdev->card->codec; | ||
84 | 76 | ||
85 | if (codec == NULL) | ||
86 | return 0; | ||
87 | snd_soc_free_pcms(socdev); | 77 | snd_soc_free_pcms(socdev); |
88 | kfree(codec); | 78 | |
89 | return 0; | 79 | return 0; |
90 | } | 80 | } |
91 | 81 | ||
@@ -98,13 +88,55 @@ EXPORT_SYMBOL_GPL(soc_codec_dev_wm8727); | |||
98 | 88 | ||
99 | static __devinit int wm8727_platform_probe(struct platform_device *pdev) | 89 | static __devinit int wm8727_platform_probe(struct platform_device *pdev) |
100 | { | 90 | { |
91 | struct snd_soc_codec *codec; | ||
92 | int ret; | ||
93 | |||
94 | if (wm8727_codec) { | ||
95 | dev_err(&pdev->dev, "Another WM8727 is registered\n"); | ||
96 | return -EBUSY; | ||
97 | } | ||
98 | |||
99 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | ||
100 | if (codec == NULL) | ||
101 | return -ENOMEM; | ||
102 | wm8727_codec = codec; | ||
103 | |||
104 | platform_set_drvdata(pdev, codec); | ||
105 | |||
106 | mutex_init(&codec->mutex); | ||
107 | codec->dev = &pdev->dev; | ||
108 | codec->name = "WM8727"; | ||
109 | codec->owner = THIS_MODULE; | ||
110 | codec->dai = &wm8727_dai; | ||
111 | codec->num_dai = 1; | ||
112 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
113 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
114 | |||
101 | wm8727_dai.dev = &pdev->dev; | 115 | wm8727_dai.dev = &pdev->dev; |
102 | return snd_soc_register_dai(&wm8727_dai); | 116 | |
117 | ret = snd_soc_register_codec(codec); | ||
118 | if (ret != 0) { | ||
119 | dev_err(&pdev->dev, "Failed to register CODEC: %d\n", ret); | ||
120 | goto err; | ||
121 | } | ||
122 | |||
123 | ret = snd_soc_register_dai(&wm8727_dai); | ||
124 | if (ret != 0) { | ||
125 | dev_err(&pdev->dev, "Failed to register DAI: %d\n", ret); | ||
126 | goto err_codec; | ||
127 | } | ||
128 | |||
129 | err_codec: | ||
130 | snd_soc_unregister_codec(codec); | ||
131 | err: | ||
132 | kfree(codec); | ||
133 | return ret; | ||
103 | } | 134 | } |
104 | 135 | ||
105 | static int __devexit wm8727_platform_remove(struct platform_device *pdev) | 136 | static int __devexit wm8727_platform_remove(struct platform_device *pdev) |
106 | { | 137 | { |
107 | snd_soc_unregister_dai(&wm8727_dai); | 138 | snd_soc_unregister_dai(&wm8727_dai); |
139 | snd_soc_unregister_codec(platform_get_drvdata(pdev)); | ||
108 | return 0; | 140 | return 0; |
109 | } | 141 | } |
110 | 142 | ||
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 3a497810f939..5a2619dbf283 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c | |||
@@ -456,6 +456,9 @@ static int wm8731_resume(struct platform_device *pdev) | |||
456 | 456 | ||
457 | /* Sync reg_cache with the hardware */ | 457 | /* Sync reg_cache with the hardware */ |
458 | for (i = 0; i < ARRAY_SIZE(wm8731_reg); i++) { | 458 | for (i = 0; i < ARRAY_SIZE(wm8731_reg); i++) { |
459 | if (cache[i] == wm8731_reg[i]) | ||
460 | continue; | ||
461 | |||
459 | data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001); | 462 | data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001); |
460 | data[1] = cache[i] & 0x00ff; | 463 | data[1] = cache[i] & 0x00ff; |
461 | codec->hw_write(codec->control_data, data, 2); | 464 | codec->hw_write(codec->control_data, data, 2); |
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index d6850dacda29..c2444e7c8480 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c | |||
@@ -1507,10 +1507,6 @@ static int wm8753_suspend(struct platform_device *pdev, pm_message_t state) | |||
1507 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1507 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
1508 | struct snd_soc_codec *codec = socdev->card->codec; | 1508 | struct snd_soc_codec *codec = socdev->card->codec; |
1509 | 1509 | ||
1510 | /* we only need to suspend if we are a valid card */ | ||
1511 | if (!codec->card) | ||
1512 | return 0; | ||
1513 | |||
1514 | wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF); | 1510 | wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF); |
1515 | return 0; | 1511 | return 0; |
1516 | } | 1512 | } |
@@ -1523,10 +1519,6 @@ static int wm8753_resume(struct platform_device *pdev) | |||
1523 | u8 data[2]; | 1519 | u8 data[2]; |
1524 | u16 *cache = codec->reg_cache; | 1520 | u16 *cache = codec->reg_cache; |
1525 | 1521 | ||
1526 | /* we only need to resume if we are a valid card */ | ||
1527 | if (!codec->card) | ||
1528 | return 0; | ||
1529 | |||
1530 | /* Sync reg_cache with the hardware */ | 1522 | /* Sync reg_cache with the hardware */ |
1531 | for (i = 0; i < ARRAY_SIZE(wm8753_reg); i++) { | 1523 | for (i = 0; i < ARRAY_SIZE(wm8753_reg); i++) { |
1532 | if (i + 1 == WM8753_RESET) | 1524 | if (i + 1 == WM8753_RESET) |
diff --git a/sound/soc/codecs/wm8776.c b/sound/soc/codecs/wm8776.c index ab2c0da18091..44e7d9d82f87 100644 --- a/sound/soc/codecs/wm8776.c +++ b/sound/soc/codecs/wm8776.c | |||
@@ -406,6 +406,8 @@ static int wm8776_resume(struct platform_device *pdev) | |||
406 | 406 | ||
407 | /* Sync reg_cache with the hardware */ | 407 | /* Sync reg_cache with the hardware */ |
408 | for (i = 0; i < ARRAY_SIZE(wm8776_reg); i++) { | 408 | for (i = 0; i < ARRAY_SIZE(wm8776_reg); i++) { |
409 | if (cache[i] == wm8776_reg[i]) | ||
410 | continue; | ||
409 | data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001); | 411 | data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001); |
410 | data[1] = cache[i] & 0x00ff; | 412 | data[1] = cache[i] & 0x00ff; |
411 | codec->hw_write(codec->control_data, data, 2); | 413 | codec->hw_write(codec->control_data, data, 2); |
diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c new file mode 100644 index 000000000000..593e47d0e0eb --- /dev/null +++ b/sound/soc/codecs/wm8904.c | |||
@@ -0,0 +1,2656 @@ | |||
1 | /* | ||
2 | * wm8904.c -- WM8904 ALSA SoC Audio driver | ||
3 | * | ||
4 | * Copyright 2009 Wolfson Microelectronics plc | ||
5 | * | ||
6 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | ||
7 | * | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/moduleparam.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/delay.h> | ||
18 | #include <linux/pm.h> | ||
19 | #include <linux/i2c.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <linux/regulator/consumer.h> | ||
22 | #include <sound/core.h> | ||
23 | #include <sound/pcm.h> | ||
24 | #include <sound/pcm_params.h> | ||
25 | #include <sound/soc.h> | ||
26 | #include <sound/soc-dapm.h> | ||
27 | #include <sound/initval.h> | ||
28 | #include <sound/tlv.h> | ||
29 | #include <sound/wm8904.h> | ||
30 | |||
31 | #include "wm8904.h" | ||
32 | |||
33 | static struct snd_soc_codec *wm8904_codec; | ||
34 | struct snd_soc_codec_device soc_codec_dev_wm8904; | ||
35 | |||
36 | enum wm8904_type { | ||
37 | WM8904, | ||
38 | WM8912, | ||
39 | }; | ||
40 | |||
41 | #define WM8904_NUM_DCS_CHANNELS 4 | ||
42 | |||
43 | #define WM8904_NUM_SUPPLIES 5 | ||
44 | static const char *wm8904_supply_names[WM8904_NUM_SUPPLIES] = { | ||
45 | "DCVDD", | ||
46 | "DBVDD", | ||
47 | "AVDD", | ||
48 | "CPVDD", | ||
49 | "MICVDD", | ||
50 | }; | ||
51 | |||
52 | /* codec private data */ | ||
53 | struct wm8904_priv { | ||
54 | struct snd_soc_codec codec; | ||
55 | u16 reg_cache[WM8904_MAX_REGISTER + 1]; | ||
56 | |||
57 | enum wm8904_type devtype; | ||
58 | |||
59 | struct regulator_bulk_data supplies[WM8904_NUM_SUPPLIES]; | ||
60 | |||
61 | struct wm8904_pdata *pdata; | ||
62 | |||
63 | int deemph; | ||
64 | |||
65 | /* Platform provided DRC configuration */ | ||
66 | const char **drc_texts; | ||
67 | int drc_cfg; | ||
68 | struct soc_enum drc_enum; | ||
69 | |||
70 | /* Platform provided ReTune mobile configuration */ | ||
71 | int num_retune_mobile_texts; | ||
72 | const char **retune_mobile_texts; | ||
73 | int retune_mobile_cfg; | ||
74 | struct soc_enum retune_mobile_enum; | ||
75 | |||
76 | /* FLL setup */ | ||
77 | int fll_src; | ||
78 | int fll_fref; | ||
79 | int fll_fout; | ||
80 | |||
81 | /* Clocking configuration */ | ||
82 | unsigned int mclk_rate; | ||
83 | int sysclk_src; | ||
84 | unsigned int sysclk_rate; | ||
85 | |||
86 | int tdm_width; | ||
87 | int tdm_slots; | ||
88 | int bclk; | ||
89 | int fs; | ||
90 | |||
91 | /* DC servo configuration - cached offset values */ | ||
92 | int dcs_state[WM8904_NUM_DCS_CHANNELS]; | ||
93 | }; | ||
94 | |||
95 | static const u16 wm8904_reg[WM8904_MAX_REGISTER + 1] = { | ||
96 | 0x8904, /* R0 - SW Reset and ID */ | ||
97 | 0x0000, /* R1 - Revision */ | ||
98 | 0x0000, /* R2 */ | ||
99 | 0x0000, /* R3 */ | ||
100 | 0x0018, /* R4 - Bias Control 0 */ | ||
101 | 0x0000, /* R5 - VMID Control 0 */ | ||
102 | 0x0000, /* R6 - Mic Bias Control 0 */ | ||
103 | 0x0000, /* R7 - Mic Bias Control 1 */ | ||
104 | 0x0001, /* R8 - Analogue DAC 0 */ | ||
105 | 0x9696, /* R9 - mic Filter Control */ | ||
106 | 0x0001, /* R10 - Analogue ADC 0 */ | ||
107 | 0x0000, /* R11 */ | ||
108 | 0x0000, /* R12 - Power Management 0 */ | ||
109 | 0x0000, /* R13 */ | ||
110 | 0x0000, /* R14 - Power Management 2 */ | ||
111 | 0x0000, /* R15 - Power Management 3 */ | ||
112 | 0x0000, /* R16 */ | ||
113 | 0x0000, /* R17 */ | ||
114 | 0x0000, /* R18 - Power Management 6 */ | ||
115 | 0x0000, /* R19 */ | ||
116 | 0x945E, /* R20 - Clock Rates 0 */ | ||
117 | 0x0C05, /* R21 - Clock Rates 1 */ | ||
118 | 0x0006, /* R22 - Clock Rates 2 */ | ||
119 | 0x0000, /* R23 */ | ||
120 | 0x0050, /* R24 - Audio Interface 0 */ | ||
121 | 0x000A, /* R25 - Audio Interface 1 */ | ||
122 | 0x00E4, /* R26 - Audio Interface 2 */ | ||
123 | 0x0040, /* R27 - Audio Interface 3 */ | ||
124 | 0x0000, /* R28 */ | ||
125 | 0x0000, /* R29 */ | ||
126 | 0x00C0, /* R30 - DAC Digital Volume Left */ | ||
127 | 0x00C0, /* R31 - DAC Digital Volume Right */ | ||
128 | 0x0000, /* R32 - DAC Digital 0 */ | ||
129 | 0x0008, /* R33 - DAC Digital 1 */ | ||
130 | 0x0000, /* R34 */ | ||
131 | 0x0000, /* R35 */ | ||
132 | 0x00C0, /* R36 - ADC Digital Volume Left */ | ||
133 | 0x00C0, /* R37 - ADC Digital Volume Right */ | ||
134 | 0x0010, /* R38 - ADC Digital 0 */ | ||
135 | 0x0000, /* R39 - Digital Microphone 0 */ | ||
136 | 0x01AF, /* R40 - DRC 0 */ | ||
137 | 0x3248, /* R41 - DRC 1 */ | ||
138 | 0x0000, /* R42 - DRC 2 */ | ||
139 | 0x0000, /* R43 - DRC 3 */ | ||
140 | 0x0085, /* R44 - Analogue Left Input 0 */ | ||
141 | 0x0085, /* R45 - Analogue Right Input 0 */ | ||
142 | 0x0044, /* R46 - Analogue Left Input 1 */ | ||
143 | 0x0044, /* R47 - Analogue Right Input 1 */ | ||
144 | 0x0000, /* R48 */ | ||
145 | 0x0000, /* R49 */ | ||
146 | 0x0000, /* R50 */ | ||
147 | 0x0000, /* R51 */ | ||
148 | 0x0000, /* R52 */ | ||
149 | 0x0000, /* R53 */ | ||
150 | 0x0000, /* R54 */ | ||
151 | 0x0000, /* R55 */ | ||
152 | 0x0000, /* R56 */ | ||
153 | 0x002D, /* R57 - Analogue OUT1 Left */ | ||
154 | 0x002D, /* R58 - Analogue OUT1 Right */ | ||
155 | 0x0039, /* R59 - Analogue OUT2 Left */ | ||
156 | 0x0039, /* R60 - Analogue OUT2 Right */ | ||
157 | 0x0000, /* R61 - Analogue OUT12 ZC */ | ||
158 | 0x0000, /* R62 */ | ||
159 | 0x0000, /* R63 */ | ||
160 | 0x0000, /* R64 */ | ||
161 | 0x0000, /* R65 */ | ||
162 | 0x0000, /* R66 */ | ||
163 | 0x0000, /* R67 - DC Servo 0 */ | ||
164 | 0x0000, /* R68 - DC Servo 1 */ | ||
165 | 0xAAAA, /* R69 - DC Servo 2 */ | ||
166 | 0x0000, /* R70 */ | ||
167 | 0xAAAA, /* R71 - DC Servo 4 */ | ||
168 | 0xAAAA, /* R72 - DC Servo 5 */ | ||
169 | 0x0000, /* R73 - DC Servo 6 */ | ||
170 | 0x0000, /* R74 - DC Servo 7 */ | ||
171 | 0x0000, /* R75 - DC Servo 8 */ | ||
172 | 0x0000, /* R76 - DC Servo 9 */ | ||
173 | 0x0000, /* R77 - DC Servo Readback 0 */ | ||
174 | 0x0000, /* R78 */ | ||
175 | 0x0000, /* R79 */ | ||
176 | 0x0000, /* R80 */ | ||
177 | 0x0000, /* R81 */ | ||
178 | 0x0000, /* R82 */ | ||
179 | 0x0000, /* R83 */ | ||
180 | 0x0000, /* R84 */ | ||
181 | 0x0000, /* R85 */ | ||
182 | 0x0000, /* R86 */ | ||
183 | 0x0000, /* R87 */ | ||
184 | 0x0000, /* R88 */ | ||
185 | 0x0000, /* R89 */ | ||
186 | 0x0000, /* R90 - Analogue HP 0 */ | ||
187 | 0x0000, /* R91 */ | ||
188 | 0x0000, /* R92 */ | ||
189 | 0x0000, /* R93 */ | ||
190 | 0x0000, /* R94 - Analogue Lineout 0 */ | ||
191 | 0x0000, /* R95 */ | ||
192 | 0x0000, /* R96 */ | ||
193 | 0x0000, /* R97 */ | ||
194 | 0x0000, /* R98 - Charge Pump 0 */ | ||
195 | 0x0000, /* R99 */ | ||
196 | 0x0000, /* R100 */ | ||
197 | 0x0000, /* R101 */ | ||
198 | 0x0000, /* R102 */ | ||
199 | 0x0000, /* R103 */ | ||
200 | 0x0004, /* R104 - Class W 0 */ | ||
201 | 0x0000, /* R105 */ | ||
202 | 0x0000, /* R106 */ | ||
203 | 0x0000, /* R107 */ | ||
204 | 0x0000, /* R108 - Write Sequencer 0 */ | ||
205 | 0x0000, /* R109 - Write Sequencer 1 */ | ||
206 | 0x0000, /* R110 - Write Sequencer 2 */ | ||
207 | 0x0000, /* R111 - Write Sequencer 3 */ | ||
208 | 0x0000, /* R112 - Write Sequencer 4 */ | ||
209 | 0x0000, /* R113 */ | ||
210 | 0x0000, /* R114 */ | ||
211 | 0x0000, /* R115 */ | ||
212 | 0x0000, /* R116 - FLL Control 1 */ | ||
213 | 0x0007, /* R117 - FLL Control 2 */ | ||
214 | 0x0000, /* R118 - FLL Control 3 */ | ||
215 | 0x2EE0, /* R119 - FLL Control 4 */ | ||
216 | 0x0004, /* R120 - FLL Control 5 */ | ||
217 | 0x0014, /* R121 - GPIO Control 1 */ | ||
218 | 0x0010, /* R122 - GPIO Control 2 */ | ||
219 | 0x0010, /* R123 - GPIO Control 3 */ | ||
220 | 0x0000, /* R124 - GPIO Control 4 */ | ||
221 | 0x0000, /* R125 */ | ||
222 | 0x0000, /* R126 - Digital Pulls */ | ||
223 | 0x0000, /* R127 - Interrupt Status */ | ||
224 | 0xFFFF, /* R128 - Interrupt Status Mask */ | ||
225 | 0x0000, /* R129 - Interrupt Polarity */ | ||
226 | 0x0000, /* R130 - Interrupt Debounce */ | ||
227 | 0x0000, /* R131 */ | ||
228 | 0x0000, /* R132 */ | ||
229 | 0x0000, /* R133 */ | ||
230 | 0x0000, /* R134 - EQ1 */ | ||
231 | 0x000C, /* R135 - EQ2 */ | ||
232 | 0x000C, /* R136 - EQ3 */ | ||
233 | 0x000C, /* R137 - EQ4 */ | ||
234 | 0x000C, /* R138 - EQ5 */ | ||
235 | 0x000C, /* R139 - EQ6 */ | ||
236 | 0x0FCA, /* R140 - EQ7 */ | ||
237 | 0x0400, /* R141 - EQ8 */ | ||
238 | 0x00D8, /* R142 - EQ9 */ | ||
239 | 0x1EB5, /* R143 - EQ10 */ | ||
240 | 0xF145, /* R144 - EQ11 */ | ||
241 | 0x0B75, /* R145 - EQ12 */ | ||
242 | 0x01C5, /* R146 - EQ13 */ | ||
243 | 0x1C58, /* R147 - EQ14 */ | ||
244 | 0xF373, /* R148 - EQ15 */ | ||
245 | 0x0A54, /* R149 - EQ16 */ | ||
246 | 0x0558, /* R150 - EQ17 */ | ||
247 | 0x168E, /* R151 - EQ18 */ | ||
248 | 0xF829, /* R152 - EQ19 */ | ||
249 | 0x07AD, /* R153 - EQ20 */ | ||
250 | 0x1103, /* R154 - EQ21 */ | ||
251 | 0x0564, /* R155 - EQ22 */ | ||
252 | 0x0559, /* R156 - EQ23 */ | ||
253 | 0x4000, /* R157 - EQ24 */ | ||
254 | 0x0000, /* R158 */ | ||
255 | 0x0000, /* R159 */ | ||
256 | 0x0000, /* R160 */ | ||
257 | 0x0000, /* R161 - Control Interface Test 1 */ | ||
258 | 0x0000, /* R162 */ | ||
259 | 0x0000, /* R163 */ | ||
260 | 0x0000, /* R164 */ | ||
261 | 0x0000, /* R165 */ | ||
262 | 0x0000, /* R166 */ | ||
263 | 0x0000, /* R167 */ | ||
264 | 0x0000, /* R168 */ | ||
265 | 0x0000, /* R169 */ | ||
266 | 0x0000, /* R170 */ | ||
267 | 0x0000, /* R171 */ | ||
268 | 0x0000, /* R172 */ | ||
269 | 0x0000, /* R173 */ | ||
270 | 0x0000, /* R174 */ | ||
271 | 0x0000, /* R175 */ | ||
272 | 0x0000, /* R176 */ | ||
273 | 0x0000, /* R177 */ | ||
274 | 0x0000, /* R178 */ | ||
275 | 0x0000, /* R179 */ | ||
276 | 0x0000, /* R180 */ | ||
277 | 0x0000, /* R181 */ | ||
278 | 0x0000, /* R182 */ | ||
279 | 0x0000, /* R183 */ | ||
280 | 0x0000, /* R184 */ | ||
281 | 0x0000, /* R185 */ | ||
282 | 0x0000, /* R186 */ | ||
283 | 0x0000, /* R187 */ | ||
284 | 0x0000, /* R188 */ | ||
285 | 0x0000, /* R189 */ | ||
286 | 0x0000, /* R190 */ | ||
287 | 0x0000, /* R191 */ | ||
288 | 0x0000, /* R192 */ | ||
289 | 0x0000, /* R193 */ | ||
290 | 0x0000, /* R194 */ | ||
291 | 0x0000, /* R195 */ | ||
292 | 0x0000, /* R196 */ | ||
293 | 0x0000, /* R197 */ | ||
294 | 0x0000, /* R198 */ | ||
295 | 0x0000, /* R199 */ | ||
296 | 0x0000, /* R200 */ | ||
297 | 0x0000, /* R201 */ | ||
298 | 0x0000, /* R202 */ | ||
299 | 0x0000, /* R203 */ | ||
300 | 0x0000, /* R204 - Analogue Output Bias 0 */ | ||
301 | 0x0000, /* R205 */ | ||
302 | 0x0000, /* R206 */ | ||
303 | 0x0000, /* R207 */ | ||
304 | 0x0000, /* R208 */ | ||
305 | 0x0000, /* R209 */ | ||
306 | 0x0000, /* R210 */ | ||
307 | 0x0000, /* R211 */ | ||
308 | 0x0000, /* R212 */ | ||
309 | 0x0000, /* R213 */ | ||
310 | 0x0000, /* R214 */ | ||
311 | 0x0000, /* R215 */ | ||
312 | 0x0000, /* R216 */ | ||
313 | 0x0000, /* R217 */ | ||
314 | 0x0000, /* R218 */ | ||
315 | 0x0000, /* R219 */ | ||
316 | 0x0000, /* R220 */ | ||
317 | 0x0000, /* R221 */ | ||
318 | 0x0000, /* R222 */ | ||
319 | 0x0000, /* R223 */ | ||
320 | 0x0000, /* R224 */ | ||
321 | 0x0000, /* R225 */ | ||
322 | 0x0000, /* R226 */ | ||
323 | 0x0000, /* R227 */ | ||
324 | 0x0000, /* R228 */ | ||
325 | 0x0000, /* R229 */ | ||
326 | 0x0000, /* R230 */ | ||
327 | 0x0000, /* R231 */ | ||
328 | 0x0000, /* R232 */ | ||
329 | 0x0000, /* R233 */ | ||
330 | 0x0000, /* R234 */ | ||
331 | 0x0000, /* R235 */ | ||
332 | 0x0000, /* R236 */ | ||
333 | 0x0000, /* R237 */ | ||
334 | 0x0000, /* R238 */ | ||
335 | 0x0000, /* R239 */ | ||
336 | 0x0000, /* R240 */ | ||
337 | 0x0000, /* R241 */ | ||
338 | 0x0000, /* R242 */ | ||
339 | 0x0000, /* R243 */ | ||
340 | 0x0000, /* R244 */ | ||
341 | 0x0000, /* R245 */ | ||
342 | 0x0000, /* R246 */ | ||
343 | 0x0000, /* R247 - FLL NCO Test 0 */ | ||
344 | 0x0019, /* R248 - FLL NCO Test 1 */ | ||
345 | }; | ||
346 | |||
347 | static struct { | ||
348 | int readable; | ||
349 | int writable; | ||
350 | int vol; | ||
351 | } wm8904_access[] = { | ||
352 | { 0xFFFF, 0xFFFF, 1 }, /* R0 - SW Reset and ID */ | ||
353 | { 0x0000, 0x0000, 0 }, /* R1 - Revision */ | ||
354 | { 0x0000, 0x0000, 0 }, /* R2 */ | ||
355 | { 0x0000, 0x0000, 0 }, /* R3 */ | ||
356 | { 0x001F, 0x001F, 0 }, /* R4 - Bias Control 0 */ | ||
357 | { 0x0047, 0x0047, 0 }, /* R5 - VMID Control 0 */ | ||
358 | { 0x007F, 0x007F, 0 }, /* R6 - Mic Bias Control 0 */ | ||
359 | { 0xC007, 0xC007, 0 }, /* R7 - Mic Bias Control 1 */ | ||
360 | { 0x001E, 0x001E, 0 }, /* R8 - Analogue DAC 0 */ | ||
361 | { 0xFFFF, 0xFFFF, 0 }, /* R9 - mic Filter Control */ | ||
362 | { 0x0001, 0x0001, 0 }, /* R10 - Analogue ADC 0 */ | ||
363 | { 0x0000, 0x0000, 0 }, /* R11 */ | ||
364 | { 0x0003, 0x0003, 0 }, /* R12 - Power Management 0 */ | ||
365 | { 0x0000, 0x0000, 0 }, /* R13 */ | ||
366 | { 0x0003, 0x0003, 0 }, /* R14 - Power Management 2 */ | ||
367 | { 0x0003, 0x0003, 0 }, /* R15 - Power Management 3 */ | ||
368 | { 0x0000, 0x0000, 0 }, /* R16 */ | ||
369 | { 0x0000, 0x0000, 0 }, /* R17 */ | ||
370 | { 0x000F, 0x000F, 0 }, /* R18 - Power Management 6 */ | ||
371 | { 0x0000, 0x0000, 0 }, /* R19 */ | ||
372 | { 0x7001, 0x7001, 0 }, /* R20 - Clock Rates 0 */ | ||
373 | { 0x3C07, 0x3C07, 0 }, /* R21 - Clock Rates 1 */ | ||
374 | { 0xD00F, 0xD00F, 0 }, /* R22 - Clock Rates 2 */ | ||
375 | { 0x0000, 0x0000, 0 }, /* R23 */ | ||
376 | { 0x1FFF, 0x1FFF, 0 }, /* R24 - Audio Interface 0 */ | ||
377 | { 0x3DDF, 0x3DDF, 0 }, /* R25 - Audio Interface 1 */ | ||
378 | { 0x0F1F, 0x0F1F, 0 }, /* R26 - Audio Interface 2 */ | ||
379 | { 0x0FFF, 0x0FFF, 0 }, /* R27 - Audio Interface 3 */ | ||
380 | { 0x0000, 0x0000, 0 }, /* R28 */ | ||
381 | { 0x0000, 0x0000, 0 }, /* R29 */ | ||
382 | { 0x00FF, 0x01FF, 0 }, /* R30 - DAC Digital Volume Left */ | ||
383 | { 0x00FF, 0x01FF, 0 }, /* R31 - DAC Digital Volume Right */ | ||
384 | { 0x0FFF, 0x0FFF, 0 }, /* R32 - DAC Digital 0 */ | ||
385 | { 0x1E4E, 0x1E4E, 0 }, /* R33 - DAC Digital 1 */ | ||
386 | { 0x0000, 0x0000, 0 }, /* R34 */ | ||
387 | { 0x0000, 0x0000, 0 }, /* R35 */ | ||
388 | { 0x00FF, 0x01FF, 0 }, /* R36 - ADC Digital Volume Left */ | ||
389 | { 0x00FF, 0x01FF, 0 }, /* R37 - ADC Digital Volume Right */ | ||
390 | { 0x0073, 0x0073, 0 }, /* R38 - ADC Digital 0 */ | ||
391 | { 0x1800, 0x1800, 0 }, /* R39 - Digital Microphone 0 */ | ||
392 | { 0xDFEF, 0xDFEF, 0 }, /* R40 - DRC 0 */ | ||
393 | { 0xFFFF, 0xFFFF, 0 }, /* R41 - DRC 1 */ | ||
394 | { 0x003F, 0x003F, 0 }, /* R42 - DRC 2 */ | ||
395 | { 0x07FF, 0x07FF, 0 }, /* R43 - DRC 3 */ | ||
396 | { 0x009F, 0x009F, 0 }, /* R44 - Analogue Left Input 0 */ | ||
397 | { 0x009F, 0x009F, 0 }, /* R45 - Analogue Right Input 0 */ | ||
398 | { 0x007F, 0x007F, 0 }, /* R46 - Analogue Left Input 1 */ | ||
399 | { 0x007F, 0x007F, 0 }, /* R47 - Analogue Right Input 1 */ | ||
400 | { 0x0000, 0x0000, 0 }, /* R48 */ | ||
401 | { 0x0000, 0x0000, 0 }, /* R49 */ | ||
402 | { 0x0000, 0x0000, 0 }, /* R50 */ | ||
403 | { 0x0000, 0x0000, 0 }, /* R51 */ | ||
404 | { 0x0000, 0x0000, 0 }, /* R52 */ | ||
405 | { 0x0000, 0x0000, 0 }, /* R53 */ | ||
406 | { 0x0000, 0x0000, 0 }, /* R54 */ | ||
407 | { 0x0000, 0x0000, 0 }, /* R55 */ | ||
408 | { 0x0000, 0x0000, 0 }, /* R56 */ | ||
409 | { 0x017F, 0x01FF, 0 }, /* R57 - Analogue OUT1 Left */ | ||
410 | { 0x017F, 0x01FF, 0 }, /* R58 - Analogue OUT1 Right */ | ||
411 | { 0x017F, 0x01FF, 0 }, /* R59 - Analogue OUT2 Left */ | ||
412 | { 0x017F, 0x01FF, 0 }, /* R60 - Analogue OUT2 Right */ | ||
413 | { 0x000F, 0x000F, 0 }, /* R61 - Analogue OUT12 ZC */ | ||
414 | { 0x0000, 0x0000, 0 }, /* R62 */ | ||
415 | { 0x0000, 0x0000, 0 }, /* R63 */ | ||
416 | { 0x0000, 0x0000, 0 }, /* R64 */ | ||
417 | { 0x0000, 0x0000, 0 }, /* R65 */ | ||
418 | { 0x0000, 0x0000, 0 }, /* R66 */ | ||
419 | { 0x000F, 0x000F, 0 }, /* R67 - DC Servo 0 */ | ||
420 | { 0xFFFF, 0xFFFF, 1 }, /* R68 - DC Servo 1 */ | ||
421 | { 0x0F0F, 0x0F0F, 0 }, /* R69 - DC Servo 2 */ | ||
422 | { 0x0000, 0x0000, 0 }, /* R70 */ | ||
423 | { 0x007F, 0x007F, 0 }, /* R71 - DC Servo 4 */ | ||
424 | { 0x007F, 0x007F, 0 }, /* R72 - DC Servo 5 */ | ||
425 | { 0x00FF, 0x00FF, 1 }, /* R73 - DC Servo 6 */ | ||
426 | { 0x00FF, 0x00FF, 1 }, /* R74 - DC Servo 7 */ | ||
427 | { 0x00FF, 0x00FF, 1 }, /* R75 - DC Servo 8 */ | ||
428 | { 0x00FF, 0x00FF, 1 }, /* R76 - DC Servo 9 */ | ||
429 | { 0x0FFF, 0x0000, 1 }, /* R77 - DC Servo Readback 0 */ | ||
430 | { 0x0000, 0x0000, 0 }, /* R78 */ | ||
431 | { 0x0000, 0x0000, 0 }, /* R79 */ | ||
432 | { 0x0000, 0x0000, 0 }, /* R80 */ | ||
433 | { 0x0000, 0x0000, 0 }, /* R81 */ | ||
434 | { 0x0000, 0x0000, 0 }, /* R82 */ | ||
435 | { 0x0000, 0x0000, 0 }, /* R83 */ | ||
436 | { 0x0000, 0x0000, 0 }, /* R84 */ | ||
437 | { 0x0000, 0x0000, 0 }, /* R85 */ | ||
438 | { 0x0000, 0x0000, 0 }, /* R86 */ | ||
439 | { 0x0000, 0x0000, 0 }, /* R87 */ | ||
440 | { 0x0000, 0x0000, 0 }, /* R88 */ | ||
441 | { 0x0000, 0x0000, 0 }, /* R89 */ | ||
442 | { 0x00FF, 0x00FF, 0 }, /* R90 - Analogue HP 0 */ | ||
443 | { 0x0000, 0x0000, 0 }, /* R91 */ | ||
444 | { 0x0000, 0x0000, 0 }, /* R92 */ | ||
445 | { 0x0000, 0x0000, 0 }, /* R93 */ | ||
446 | { 0x00FF, 0x00FF, 0 }, /* R94 - Analogue Lineout 0 */ | ||
447 | { 0x0000, 0x0000, 0 }, /* R95 */ | ||
448 | { 0x0000, 0x0000, 0 }, /* R96 */ | ||
449 | { 0x0000, 0x0000, 0 }, /* R97 */ | ||
450 | { 0x0001, 0x0001, 0 }, /* R98 - Charge Pump 0 */ | ||
451 | { 0x0000, 0x0000, 0 }, /* R99 */ | ||
452 | { 0x0000, 0x0000, 0 }, /* R100 */ | ||
453 | { 0x0000, 0x0000, 0 }, /* R101 */ | ||
454 | { 0x0000, 0x0000, 0 }, /* R102 */ | ||
455 | { 0x0000, 0x0000, 0 }, /* R103 */ | ||
456 | { 0x0001, 0x0001, 0 }, /* R104 - Class W 0 */ | ||
457 | { 0x0000, 0x0000, 0 }, /* R105 */ | ||
458 | { 0x0000, 0x0000, 0 }, /* R106 */ | ||
459 | { 0x0000, 0x0000, 0 }, /* R107 */ | ||
460 | { 0x011F, 0x011F, 0 }, /* R108 - Write Sequencer 0 */ | ||
461 | { 0x7FFF, 0x7FFF, 0 }, /* R109 - Write Sequencer 1 */ | ||
462 | { 0x4FFF, 0x4FFF, 0 }, /* R110 - Write Sequencer 2 */ | ||
463 | { 0x003F, 0x033F, 0 }, /* R111 - Write Sequencer 3 */ | ||
464 | { 0x03F1, 0x0000, 0 }, /* R112 - Write Sequencer 4 */ | ||
465 | { 0x0000, 0x0000, 0 }, /* R113 */ | ||
466 | { 0x0000, 0x0000, 0 }, /* R114 */ | ||
467 | { 0x0000, 0x0000, 0 }, /* R115 */ | ||
468 | { 0x0007, 0x0007, 0 }, /* R116 - FLL Control 1 */ | ||
469 | { 0x3F77, 0x3F77, 0 }, /* R117 - FLL Control 2 */ | ||
470 | { 0xFFFF, 0xFFFF, 0 }, /* R118 - FLL Control 3 */ | ||
471 | { 0x7FEF, 0x7FEF, 0 }, /* R119 - FLL Control 4 */ | ||
472 | { 0x001B, 0x001B, 0 }, /* R120 - FLL Control 5 */ | ||
473 | { 0x003F, 0x003F, 0 }, /* R121 - GPIO Control 1 */ | ||
474 | { 0x003F, 0x003F, 0 }, /* R122 - GPIO Control 2 */ | ||
475 | { 0x003F, 0x003F, 0 }, /* R123 - GPIO Control 3 */ | ||
476 | { 0x038F, 0x038F, 0 }, /* R124 - GPIO Control 4 */ | ||
477 | { 0x0000, 0x0000, 0 }, /* R125 */ | ||
478 | { 0x00FF, 0x00FF, 0 }, /* R126 - Digital Pulls */ | ||
479 | { 0x07FF, 0x03FF, 1 }, /* R127 - Interrupt Status */ | ||
480 | { 0x03FF, 0x03FF, 0 }, /* R128 - Interrupt Status Mask */ | ||
481 | { 0x03FF, 0x03FF, 0 }, /* R129 - Interrupt Polarity */ | ||
482 | { 0x03FF, 0x03FF, 0 }, /* R130 - Interrupt Debounce */ | ||
483 | { 0x0000, 0x0000, 0 }, /* R131 */ | ||
484 | { 0x0000, 0x0000, 0 }, /* R132 */ | ||
485 | { 0x0000, 0x0000, 0 }, /* R133 */ | ||
486 | { 0x0001, 0x0001, 0 }, /* R134 - EQ1 */ | ||
487 | { 0x001F, 0x001F, 0 }, /* R135 - EQ2 */ | ||
488 | { 0x001F, 0x001F, 0 }, /* R136 - EQ3 */ | ||
489 | { 0x001F, 0x001F, 0 }, /* R137 - EQ4 */ | ||
490 | { 0x001F, 0x001F, 0 }, /* R138 - EQ5 */ | ||
491 | { 0x001F, 0x001F, 0 }, /* R139 - EQ6 */ | ||
492 | { 0xFFFF, 0xFFFF, 0 }, /* R140 - EQ7 */ | ||
493 | { 0xFFFF, 0xFFFF, 0 }, /* R141 - EQ8 */ | ||
494 | { 0xFFFF, 0xFFFF, 0 }, /* R142 - EQ9 */ | ||
495 | { 0xFFFF, 0xFFFF, 0 }, /* R143 - EQ10 */ | ||
496 | { 0xFFFF, 0xFFFF, 0 }, /* R144 - EQ11 */ | ||
497 | { 0xFFFF, 0xFFFF, 0 }, /* R145 - EQ12 */ | ||
498 | { 0xFFFF, 0xFFFF, 0 }, /* R146 - EQ13 */ | ||
499 | { 0xFFFF, 0xFFFF, 0 }, /* R147 - EQ14 */ | ||
500 | { 0xFFFF, 0xFFFF, 0 }, /* R148 - EQ15 */ | ||
501 | { 0xFFFF, 0xFFFF, 0 }, /* R149 - EQ16 */ | ||
502 | { 0xFFFF, 0xFFFF, 0 }, /* R150 - EQ17 */ | ||
503 | { 0xFFFF, 0xFFFF, 0 }, /* R151wm8523_dai - EQ18 */ | ||
504 | { 0xFFFF, 0xFFFF, 0 }, /* R152 - EQ19 */ | ||
505 | { 0xFFFF, 0xFFFF, 0 }, /* R153 - EQ20 */ | ||
506 | { 0xFFFF, 0xFFFF, 0 }, /* R154 - EQ21 */ | ||
507 | { 0xFFFF, 0xFFFF, 0 }, /* R155 - EQ22 */ | ||
508 | { 0xFFFF, 0xFFFF, 0 }, /* R156 - EQ23 */ | ||
509 | { 0xFFFF, 0xFFFF, 0 }, /* R157 - EQ24 */ | ||
510 | { 0x0000, 0x0000, 0 }, /* R158 */ | ||
511 | { 0x0000, 0x0000, 0 }, /* R159 */ | ||
512 | { 0x0000, 0x0000, 0 }, /* R160 */ | ||
513 | { 0x0002, 0x0002, 0 }, /* R161 - Control Interface Test 1 */ | ||
514 | { 0x0000, 0x0000, 0 }, /* R162 */ | ||
515 | { 0x0000, 0x0000, 0 }, /* R163 */ | ||
516 | { 0x0000, 0x0000, 0 }, /* R164 */ | ||
517 | { 0x0000, 0x0000, 0 }, /* R165 */ | ||
518 | { 0x0000, 0x0000, 0 }, /* R166 */ | ||
519 | { 0x0000, 0x0000, 0 }, /* R167 */ | ||
520 | { 0x0000, 0x0000, 0 }, /* R168 */ | ||
521 | { 0x0000, 0x0000, 0 }, /* R169 */ | ||
522 | { 0x0000, 0x0000, 0 }, /* R170 */ | ||
523 | { 0x0000, 0x0000, 0 }, /* R171 */ | ||
524 | { 0x0000, 0x0000, 0 }, /* R172 */ | ||
525 | { 0x0000, 0x0000, 0 }, /* R173 */ | ||
526 | { 0x0000, 0x0000, 0 }, /* R174 */ | ||
527 | { 0x0000, 0x0000, 0 }, /* R175 */ | ||
528 | { 0x0000, 0x0000, 0 }, /* R176 */ | ||
529 | { 0x0000, 0x0000, 0 }, /* R177 */ | ||
530 | { 0x0000, 0x0000, 0 }, /* R178 */ | ||
531 | { 0x0000, 0x0000, 0 }, /* R179 */ | ||
532 | { 0x0000, 0x0000, 0 }, /* R180 */ | ||
533 | { 0x0000, 0x0000, 0 }, /* R181 */ | ||
534 | { 0x0000, 0x0000, 0 }, /* R182 */ | ||
535 | { 0x0000, 0x0000, 0 }, /* R183 */ | ||
536 | { 0x0000, 0x0000, 0 }, /* R184 */ | ||
537 | { 0x0000, 0x0000, 0 }, /* R185 */ | ||
538 | { 0x0000, 0x0000, 0 }, /* R186 */ | ||
539 | { 0x0000, 0x0000, 0 }, /* R187 */ | ||
540 | { 0x0000, 0x0000, 0 }, /* R188 */ | ||
541 | { 0x0000, 0x0000, 0 }, /* R189 */ | ||
542 | { 0x0000, 0x0000, 0 }, /* R190 */ | ||
543 | { 0x0000, 0x0000, 0 }, /* R191 */ | ||
544 | { 0x0000, 0x0000, 0 }, /* R192 */ | ||
545 | { 0x0000, 0x0000, 0 }, /* R193 */ | ||
546 | { 0x0000, 0x0000, 0 }, /* R194 */ | ||
547 | { 0x0000, 0x0000, 0 }, /* R195 */ | ||
548 | { 0x0000, 0x0000, 0 }, /* R196 */ | ||
549 | { 0x0000, 0x0000, 0 }, /* R197 */ | ||
550 | { 0x0000, 0x0000, 0 }, /* R198 */ | ||
551 | { 0x0000, 0x0000, 0 }, /* R199 */ | ||
552 | { 0x0000, 0x0000, 0 }, /* R200 */ | ||
553 | { 0x0000, 0x0000, 0 }, /* R201 */ | ||
554 | { 0x0000, 0x0000, 0 }, /* R202 */ | ||
555 | { 0x0000, 0x0000, 0 }, /* R203 */ | ||
556 | { 0x0070, 0x0070, 0 }, /* R204 - Analogue Output Bias 0 */ | ||
557 | { 0x0000, 0x0000, 0 }, /* R205 */ | ||
558 | { 0x0000, 0x0000, 0 }, /* R206 */ | ||
559 | { 0x0000, 0x0000, 0 }, /* R207 */ | ||
560 | { 0x0000, 0x0000, 0 }, /* R208 */ | ||
561 | { 0x0000, 0x0000, 0 }, /* R209 */ | ||
562 | { 0x0000, 0x0000, 0 }, /* R210 */ | ||
563 | { 0x0000, 0x0000, 0 }, /* R211 */ | ||
564 | { 0x0000, 0x0000, 0 }, /* R212 */ | ||
565 | { 0x0000, 0x0000, 0 }, /* R213 */ | ||
566 | { 0x0000, 0x0000, 0 }, /* R214 */ | ||
567 | { 0x0000, 0x0000, 0 }, /* R215 */ | ||
568 | { 0x0000, 0x0000, 0 }, /* R216 */ | ||
569 | { 0x0000, 0x0000, 0 }, /* R217 */ | ||
570 | { 0x0000, 0x0000, 0 }, /* R218 */ | ||
571 | { 0x0000, 0x0000, 0 }, /* R219 */ | ||
572 | { 0x0000, 0x0000, 0 }, /* R220 */ | ||
573 | { 0x0000, 0x0000, 0 }, /* R221 */ | ||
574 | { 0x0000, 0x0000, 0 }, /* R222 */ | ||
575 | { 0x0000, 0x0000, 0 }, /* R223 */ | ||
576 | { 0x0000, 0x0000, 0 }, /* R224 */ | ||
577 | { 0x0000, 0x0000, 0 }, /* R225 */ | ||
578 | { 0x0000, 0x0000, 0 }, /* R226 */ | ||
579 | { 0x0000, 0x0000, 0 }, /* R227 */ | ||
580 | { 0x0000, 0x0000, 0 }, /* R228 */ | ||
581 | { 0x0000, 0x0000, 0 }, /* R229 */ | ||
582 | { 0x0000, 0x0000, 0 }, /* R230 */ | ||
583 | { 0x0000, 0x0000, 0 }, /* R231 */ | ||
584 | { 0x0000, 0x0000, 0 }, /* R232 */ | ||
585 | { 0x0000, 0x0000, 0 }, /* R233 */ | ||
586 | { 0x0000, 0x0000, 0 }, /* R234 */ | ||
587 | { 0x0000, 0x0000, 0 }, /* R235 */ | ||
588 | { 0x0000, 0x0000, 0 }, /* R236 */ | ||
589 | { 0x0000, 0x0000, 0 }, /* R237 */ | ||
590 | { 0x0000, 0x0000, 0 }, /* R238 */ | ||
591 | { 0x0000, 0x0000, 0 }, /* R239 */ | ||
592 | { 0x0000, 0x0000, 0 }, /* R240 */ | ||
593 | { 0x0000, 0x0000, 0 }, /* R241 */ | ||
594 | { 0x0000, 0x0000, 0 }, /* R242 */ | ||
595 | { 0x0000, 0x0000, 0 }, /* R243 */ | ||
596 | { 0x0000, 0x0000, 0 }, /* R244 */ | ||
597 | { 0x0000, 0x0000, 0 }, /* R245 */ | ||
598 | { 0x0000, 0x0000, 0 }, /* R246 */ | ||
599 | { 0x0001, 0x0001, 0 }, /* R247 - FLL NCO Test 0 */ | ||
600 | { 0x003F, 0x003F, 0 }, /* R248 - FLL NCO Test 1 */ | ||
601 | }; | ||
602 | |||
603 | static int wm8904_volatile_register(unsigned int reg) | ||
604 | { | ||
605 | return wm8904_access[reg].vol; | ||
606 | } | ||
607 | |||
608 | static int wm8904_reset(struct snd_soc_codec *codec) | ||
609 | { | ||
610 | return snd_soc_write(codec, WM8904_SW_RESET_AND_ID, 0); | ||
611 | } | ||
612 | |||
613 | static int wm8904_configure_clocking(struct snd_soc_codec *codec) | ||
614 | { | ||
615 | struct wm8904_priv *wm8904 = codec->private_data; | ||
616 | unsigned int clock0, clock2, rate; | ||
617 | |||
618 | /* Gate the clock while we're updating to avoid misclocking */ | ||
619 | clock2 = snd_soc_read(codec, WM8904_CLOCK_RATES_2); | ||
620 | snd_soc_update_bits(codec, WM8904_CLOCK_RATES_2, | ||
621 | WM8904_SYSCLK_SRC, 0); | ||
622 | |||
623 | /* This should be done on init() for bypass paths */ | ||
624 | switch (wm8904->sysclk_src) { | ||
625 | case WM8904_CLK_MCLK: | ||
626 | dev_dbg(codec->dev, "Using %dHz MCLK\n", wm8904->mclk_rate); | ||
627 | |||
628 | clock2 &= ~WM8904_SYSCLK_SRC; | ||
629 | rate = wm8904->mclk_rate; | ||
630 | |||
631 | /* Ensure the FLL is stopped */ | ||
632 | snd_soc_update_bits(codec, WM8904_FLL_CONTROL_1, | ||
633 | WM8904_FLL_OSC_ENA | WM8904_FLL_ENA, 0); | ||
634 | break; | ||
635 | |||
636 | case WM8904_CLK_FLL: | ||
637 | dev_dbg(codec->dev, "Using %dHz FLL clock\n", | ||
638 | wm8904->fll_fout); | ||
639 | |||
640 | clock2 |= WM8904_SYSCLK_SRC; | ||
641 | rate = wm8904->fll_fout; | ||
642 | break; | ||
643 | |||
644 | default: | ||
645 | dev_err(codec->dev, "System clock not configured\n"); | ||
646 | return -EINVAL; | ||
647 | } | ||
648 | |||
649 | /* SYSCLK shouldn't be over 13.5MHz */ | ||
650 | if (rate > 13500000) { | ||
651 | clock0 = WM8904_MCLK_DIV; | ||
652 | wm8904->sysclk_rate = rate / 2; | ||
653 | } else { | ||
654 | clock0 = 0; | ||
655 | wm8904->sysclk_rate = rate; | ||
656 | } | ||
657 | |||
658 | snd_soc_update_bits(codec, WM8904_CLOCK_RATES_0, WM8904_MCLK_DIV, | ||
659 | clock0); | ||
660 | |||
661 | snd_soc_update_bits(codec, WM8904_CLOCK_RATES_2, | ||
662 | WM8904_CLK_SYS_ENA | WM8904_SYSCLK_SRC, clock2); | ||
663 | |||
664 | dev_dbg(codec->dev, "CLK_SYS is %dHz\n", wm8904->sysclk_rate); | ||
665 | |||
666 | return 0; | ||
667 | } | ||
668 | |||
669 | static void wm8904_set_drc(struct snd_soc_codec *codec) | ||
670 | { | ||
671 | struct wm8904_priv *wm8904 = codec->private_data; | ||
672 | struct wm8904_pdata *pdata = wm8904->pdata; | ||
673 | int save, i; | ||
674 | |||
675 | /* Save any enables; the configuration should clear them. */ | ||
676 | save = snd_soc_read(codec, WM8904_DRC_0); | ||
677 | |||
678 | for (i = 0; i < WM8904_DRC_REGS; i++) | ||
679 | snd_soc_update_bits(codec, WM8904_DRC_0 + i, 0xffff, | ||
680 | pdata->drc_cfgs[wm8904->drc_cfg].regs[i]); | ||
681 | |||
682 | /* Reenable the DRC */ | ||
683 | snd_soc_update_bits(codec, WM8904_DRC_0, | ||
684 | WM8904_DRC_ENA | WM8904_DRC_DAC_PATH, save); | ||
685 | } | ||
686 | |||
687 | static int wm8904_put_drc_enum(struct snd_kcontrol *kcontrol, | ||
688 | struct snd_ctl_elem_value *ucontrol) | ||
689 | { | ||
690 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
691 | struct wm8904_priv *wm8904 = codec->private_data; | ||
692 | struct wm8904_pdata *pdata = wm8904->pdata; | ||
693 | int value = ucontrol->value.integer.value[0]; | ||
694 | |||
695 | if (value >= pdata->num_drc_cfgs) | ||
696 | return -EINVAL; | ||
697 | |||
698 | wm8904->drc_cfg = value; | ||
699 | |||
700 | wm8904_set_drc(codec); | ||
701 | |||
702 | return 0; | ||
703 | } | ||
704 | |||
705 | static int wm8904_get_drc_enum(struct snd_kcontrol *kcontrol, | ||
706 | struct snd_ctl_elem_value *ucontrol) | ||
707 | { | ||
708 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
709 | struct wm8904_priv *wm8904 = codec->private_data; | ||
710 | |||
711 | ucontrol->value.enumerated.item[0] = wm8904->drc_cfg; | ||
712 | |||
713 | return 0; | ||
714 | } | ||
715 | |||
716 | static void wm8904_set_retune_mobile(struct snd_soc_codec *codec) | ||
717 | { | ||
718 | struct wm8904_priv *wm8904 = codec->private_data; | ||
719 | struct wm8904_pdata *pdata = wm8904->pdata; | ||
720 | int best, best_val, save, i, cfg; | ||
721 | |||
722 | if (!pdata || !wm8904->num_retune_mobile_texts) | ||
723 | return; | ||
724 | |||
725 | /* Find the version of the currently selected configuration | ||
726 | * with the nearest sample rate. */ | ||
727 | cfg = wm8904->retune_mobile_cfg; | ||
728 | best = 0; | ||
729 | best_val = INT_MAX; | ||
730 | for (i = 0; i < pdata->num_retune_mobile_cfgs; i++) { | ||
731 | if (strcmp(pdata->retune_mobile_cfgs[i].name, | ||
732 | wm8904->retune_mobile_texts[cfg]) == 0 && | ||
733 | abs(pdata->retune_mobile_cfgs[i].rate | ||
734 | - wm8904->fs) < best_val) { | ||
735 | best = i; | ||
736 | best_val = abs(pdata->retune_mobile_cfgs[i].rate | ||
737 | - wm8904->fs); | ||
738 | } | ||
739 | } | ||
740 | |||
741 | dev_dbg(codec->dev, "ReTune Mobile %s/%dHz for %dHz sample rate\n", | ||
742 | pdata->retune_mobile_cfgs[best].name, | ||
743 | pdata->retune_mobile_cfgs[best].rate, | ||
744 | wm8904->fs); | ||
745 | |||
746 | /* The EQ will be disabled while reconfiguring it, remember the | ||
747 | * current configuration. | ||
748 | */ | ||
749 | save = snd_soc_read(codec, WM8904_EQ1); | ||
750 | |||
751 | for (i = 0; i < WM8904_EQ_REGS; i++) | ||
752 | snd_soc_update_bits(codec, WM8904_EQ1 + i, 0xffff, | ||
753 | pdata->retune_mobile_cfgs[best].regs[i]); | ||
754 | |||
755 | snd_soc_update_bits(codec, WM8904_EQ1, WM8904_EQ_ENA, save); | ||
756 | } | ||
757 | |||
758 | static int wm8904_put_retune_mobile_enum(struct snd_kcontrol *kcontrol, | ||
759 | struct snd_ctl_elem_value *ucontrol) | ||
760 | { | ||
761 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
762 | struct wm8904_priv *wm8904 = codec->private_data; | ||
763 | struct wm8904_pdata *pdata = wm8904->pdata; | ||
764 | int value = ucontrol->value.integer.value[0]; | ||
765 | |||
766 | if (value >= pdata->num_retune_mobile_cfgs) | ||
767 | return -EINVAL; | ||
768 | |||
769 | wm8904->retune_mobile_cfg = value; | ||
770 | |||
771 | wm8904_set_retune_mobile(codec); | ||
772 | |||
773 | return 0; | ||
774 | } | ||
775 | |||
776 | static int wm8904_get_retune_mobile_enum(struct snd_kcontrol *kcontrol, | ||
777 | struct snd_ctl_elem_value *ucontrol) | ||
778 | { | ||
779 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
780 | struct wm8904_priv *wm8904 = codec->private_data; | ||
781 | |||
782 | ucontrol->value.enumerated.item[0] = wm8904->retune_mobile_cfg; | ||
783 | |||
784 | return 0; | ||
785 | } | ||
786 | |||
787 | static int deemph_settings[] = { 0, 32000, 44100, 48000 }; | ||
788 | |||
789 | static int wm8904_set_deemph(struct snd_soc_codec *codec) | ||
790 | { | ||
791 | struct wm8904_priv *wm8904 = codec->private_data; | ||
792 | int val, i, best; | ||
793 | |||
794 | /* If we're using deemphasis select the nearest available sample | ||
795 | * rate. | ||
796 | */ | ||
797 | if (wm8904->deemph) { | ||
798 | best = 1; | ||
799 | for (i = 2; i < ARRAY_SIZE(deemph_settings); i++) { | ||
800 | if (abs(deemph_settings[i] - wm8904->fs) < | ||
801 | abs(deemph_settings[best] - wm8904->fs)) | ||
802 | best = i; | ||
803 | } | ||
804 | |||
805 | val = best << WM8904_DEEMPH_SHIFT; | ||
806 | } else { | ||
807 | val = 0; | ||
808 | } | ||
809 | |||
810 | dev_dbg(codec->dev, "Set deemphasis %d\n", val); | ||
811 | |||
812 | return snd_soc_update_bits(codec, WM8904_DAC_DIGITAL_1, | ||
813 | WM8904_DEEMPH_MASK, val); | ||
814 | } | ||
815 | |||
816 | static int wm8904_get_deemph(struct snd_kcontrol *kcontrol, | ||
817 | struct snd_ctl_elem_value *ucontrol) | ||
818 | { | ||
819 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
820 | struct wm8904_priv *wm8904 = codec->private_data; | ||
821 | |||
822 | return wm8904->deemph; | ||
823 | } | ||
824 | |||
825 | static int wm8904_put_deemph(struct snd_kcontrol *kcontrol, | ||
826 | struct snd_ctl_elem_value *ucontrol) | ||
827 | { | ||
828 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
829 | struct wm8904_priv *wm8904 = codec->private_data; | ||
830 | int deemph = ucontrol->value.enumerated.item[0]; | ||
831 | |||
832 | if (deemph > 1) | ||
833 | return -EINVAL; | ||
834 | |||
835 | wm8904->deemph = deemph; | ||
836 | |||
837 | return wm8904_set_deemph(codec); | ||
838 | } | ||
839 | |||
840 | static const DECLARE_TLV_DB_SCALE(dac_boost_tlv, 0, 600, 0); | ||
841 | static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1); | ||
842 | static const DECLARE_TLV_DB_SCALE(out_tlv, -5700, 100, 0); | ||
843 | static const DECLARE_TLV_DB_SCALE(sidetone_tlv, -3600, 300, 0); | ||
844 | static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); | ||
845 | |||
846 | static const char *input_mode_text[] = { | ||
847 | "Single-Ended", "Differential Line", "Differential Mic" | ||
848 | }; | ||
849 | |||
850 | static const struct soc_enum lin_mode = | ||
851 | SOC_ENUM_SINGLE(WM8904_ANALOGUE_LEFT_INPUT_1, 0, 3, input_mode_text); | ||
852 | |||
853 | static const struct soc_enum rin_mode = | ||
854 | SOC_ENUM_SINGLE(WM8904_ANALOGUE_RIGHT_INPUT_1, 0, 3, input_mode_text); | ||
855 | |||
856 | static const char *hpf_mode_text[] = { | ||
857 | "Hi-fi", "Voice 1", "Voice 2", "Voice 3" | ||
858 | }; | ||
859 | |||
860 | static const struct soc_enum hpf_mode = | ||
861 | SOC_ENUM_SINGLE(WM8904_ADC_DIGITAL_0, 5, 4, hpf_mode_text); | ||
862 | |||
863 | static const struct snd_kcontrol_new wm8904_adc_snd_controls[] = { | ||
864 | SOC_DOUBLE_R_TLV("Digital Capture Volume", WM8904_ADC_DIGITAL_VOLUME_LEFT, | ||
865 | WM8904_ADC_DIGITAL_VOLUME_RIGHT, 1, 119, 0, digital_tlv), | ||
866 | |||
867 | SOC_ENUM("Left Caputure Mode", lin_mode), | ||
868 | SOC_ENUM("Right Capture Mode", rin_mode), | ||
869 | |||
870 | /* No TLV since it depends on mode */ | ||
871 | SOC_DOUBLE_R("Capture Volume", WM8904_ANALOGUE_LEFT_INPUT_0, | ||
872 | WM8904_ANALOGUE_RIGHT_INPUT_0, 0, 31, 0), | ||
873 | SOC_DOUBLE_R("Capture Switch", WM8904_ANALOGUE_LEFT_INPUT_0, | ||
874 | WM8904_ANALOGUE_RIGHT_INPUT_0, 7, 1, 0), | ||
875 | |||
876 | SOC_SINGLE("High Pass Filter Switch", WM8904_ADC_DIGITAL_0, 4, 1, 0), | ||
877 | SOC_ENUM("High Pass Filter Mode", hpf_mode), | ||
878 | |||
879 | SOC_SINGLE("ADC 128x OSR Switch", WM8904_ANALOGUE_ADC_0, 0, 1, 0), | ||
880 | }; | ||
881 | |||
882 | static const char *drc_path_text[] = { | ||
883 | "ADC", "DAC" | ||
884 | }; | ||
885 | |||
886 | static const struct soc_enum drc_path = | ||
887 | SOC_ENUM_SINGLE(WM8904_DRC_0, 14, 2, drc_path_text); | ||
888 | |||
889 | static const struct snd_kcontrol_new wm8904_dac_snd_controls[] = { | ||
890 | SOC_SINGLE_TLV("Digital Playback Boost Volume", | ||
891 | WM8904_AUDIO_INTERFACE_0, 9, 3, 0, dac_boost_tlv), | ||
892 | SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8904_DAC_DIGITAL_VOLUME_LEFT, | ||
893 | WM8904_DAC_DIGITAL_VOLUME_RIGHT, 1, 96, 0, digital_tlv), | ||
894 | |||
895 | SOC_DOUBLE_R_TLV("Headphone Volume", WM8904_ANALOGUE_OUT1_LEFT, | ||
896 | WM8904_ANALOGUE_OUT1_RIGHT, 0, 63, 0, out_tlv), | ||
897 | SOC_DOUBLE_R("Headphone Switch", WM8904_ANALOGUE_OUT1_LEFT, | ||
898 | WM8904_ANALOGUE_OUT1_RIGHT, 8, 1, 1), | ||
899 | SOC_DOUBLE_R("Headphone ZC Switch", WM8904_ANALOGUE_OUT1_LEFT, | ||
900 | WM8904_ANALOGUE_OUT1_RIGHT, 6, 1, 0), | ||
901 | |||
902 | SOC_DOUBLE_R_TLV("Line Output Volume", WM8904_ANALOGUE_OUT2_LEFT, | ||
903 | WM8904_ANALOGUE_OUT2_RIGHT, 0, 63, 0, out_tlv), | ||
904 | SOC_DOUBLE_R("Line Output Switch", WM8904_ANALOGUE_OUT2_LEFT, | ||
905 | WM8904_ANALOGUE_OUT2_RIGHT, 8, 1, 1), | ||
906 | SOC_DOUBLE_R("Line Output ZC Switch", WM8904_ANALOGUE_OUT2_LEFT, | ||
907 | WM8904_ANALOGUE_OUT2_RIGHT, 6, 1, 0), | ||
908 | |||
909 | SOC_SINGLE("EQ Switch", WM8904_EQ1, 0, 1, 0), | ||
910 | SOC_SINGLE("DRC Switch", WM8904_DRC_0, 15, 1, 0), | ||
911 | SOC_ENUM("DRC Path", drc_path), | ||
912 | SOC_SINGLE("DAC OSRx2 Switch", WM8904_DAC_DIGITAL_1, 6, 1, 0), | ||
913 | SOC_SINGLE_BOOL_EXT("DAC Deemphasis Switch", 0, | ||
914 | wm8904_get_deemph, wm8904_put_deemph), | ||
915 | }; | ||
916 | |||
917 | static const struct snd_kcontrol_new wm8904_snd_controls[] = { | ||
918 | SOC_DOUBLE_TLV("Digital Sidetone Volume", WM8904_DAC_DIGITAL_0, 4, 8, 15, 0, | ||
919 | sidetone_tlv), | ||
920 | }; | ||
921 | |||
922 | static const struct snd_kcontrol_new wm8904_eq_controls[] = { | ||
923 | SOC_SINGLE_TLV("EQ1 Volume", WM8904_EQ2, 0, 24, 0, eq_tlv), | ||
924 | SOC_SINGLE_TLV("EQ2 Volume", WM8904_EQ3, 0, 24, 0, eq_tlv), | ||
925 | SOC_SINGLE_TLV("EQ3 Volume", WM8904_EQ4, 0, 24, 0, eq_tlv), | ||
926 | SOC_SINGLE_TLV("EQ4 Volume", WM8904_EQ5, 0, 24, 0, eq_tlv), | ||
927 | SOC_SINGLE_TLV("EQ5 Volume", WM8904_EQ6, 0, 24, 0, eq_tlv), | ||
928 | }; | ||
929 | |||
930 | static int cp_event(struct snd_soc_dapm_widget *w, | ||
931 | struct snd_kcontrol *kcontrol, int event) | ||
932 | { | ||
933 | BUG_ON(event != SND_SOC_DAPM_POST_PMU); | ||
934 | |||
935 | /* Maximum startup time */ | ||
936 | udelay(500); | ||
937 | |||
938 | return 0; | ||
939 | } | ||
940 | |||
941 | static int sysclk_event(struct snd_soc_dapm_widget *w, | ||
942 | struct snd_kcontrol *kcontrol, int event) | ||
943 | { | ||
944 | struct snd_soc_codec *codec = w->codec; | ||
945 | struct wm8904_priv *wm8904 = codec->private_data; | ||
946 | |||
947 | switch (event) { | ||
948 | case SND_SOC_DAPM_PRE_PMU: | ||
949 | /* If we're using the FLL then we only start it when | ||
950 | * required; we assume that the configuration has been | ||
951 | * done previously and all we need to do is kick it | ||
952 | * off. | ||
953 | */ | ||
954 | switch (wm8904->sysclk_src) { | ||
955 | case WM8904_CLK_FLL: | ||
956 | snd_soc_update_bits(codec, WM8904_FLL_CONTROL_1, | ||
957 | WM8904_FLL_OSC_ENA, | ||
958 | WM8904_FLL_OSC_ENA); | ||
959 | |||
960 | snd_soc_update_bits(codec, WM8904_FLL_CONTROL_1, | ||
961 | WM8904_FLL_ENA, | ||
962 | WM8904_FLL_ENA); | ||
963 | break; | ||
964 | |||
965 | default: | ||
966 | break; | ||
967 | } | ||
968 | break; | ||
969 | |||
970 | case SND_SOC_DAPM_POST_PMD: | ||
971 | snd_soc_update_bits(codec, WM8904_FLL_CONTROL_1, | ||
972 | WM8904_FLL_OSC_ENA | WM8904_FLL_ENA, 0); | ||
973 | break; | ||
974 | } | ||
975 | |||
976 | return 0; | ||
977 | } | ||
978 | |||
979 | static int out_pga_event(struct snd_soc_dapm_widget *w, | ||
980 | struct snd_kcontrol *kcontrol, int event) | ||
981 | { | ||
982 | struct snd_soc_codec *codec = w->codec; | ||
983 | struct wm8904_priv *wm8904 = codec->private_data; | ||
984 | int reg, val; | ||
985 | int dcs_mask; | ||
986 | int dcs_l, dcs_r; | ||
987 | int dcs_l_reg, dcs_r_reg; | ||
988 | int timeout; | ||
989 | int pwr_reg; | ||
990 | |||
991 | /* This code is shared between HP and LINEOUT; we do all our | ||
992 | * power management in stereo pairs to avoid latency issues so | ||
993 | * we reuse shift to identify which rather than strcmp() the | ||
994 | * name. */ | ||
995 | reg = w->shift; | ||
996 | |||
997 | switch (reg) { | ||
998 | case WM8904_ANALOGUE_HP_0: | ||
999 | pwr_reg = WM8904_POWER_MANAGEMENT_2; | ||
1000 | dcs_mask = WM8904_DCS_ENA_CHAN_0 | WM8904_DCS_ENA_CHAN_1; | ||
1001 | dcs_r_reg = WM8904_DC_SERVO_8; | ||
1002 | dcs_l_reg = WM8904_DC_SERVO_9; | ||
1003 | dcs_l = 0; | ||
1004 | dcs_r = 1; | ||
1005 | break; | ||
1006 | case WM8904_ANALOGUE_LINEOUT_0: | ||
1007 | pwr_reg = WM8904_POWER_MANAGEMENT_3; | ||
1008 | dcs_mask = WM8904_DCS_ENA_CHAN_2 | WM8904_DCS_ENA_CHAN_3; | ||
1009 | dcs_r_reg = WM8904_DC_SERVO_6; | ||
1010 | dcs_l_reg = WM8904_DC_SERVO_7; | ||
1011 | dcs_l = 2; | ||
1012 | dcs_r = 3; | ||
1013 | break; | ||
1014 | default: | ||
1015 | BUG(); | ||
1016 | return -EINVAL; | ||
1017 | } | ||
1018 | |||
1019 | switch (event) { | ||
1020 | case SND_SOC_DAPM_PRE_PMU: | ||
1021 | /* Power on the PGAs */ | ||
1022 | snd_soc_update_bits(codec, pwr_reg, | ||
1023 | WM8904_HPL_PGA_ENA | WM8904_HPR_PGA_ENA, | ||
1024 | WM8904_HPL_PGA_ENA | WM8904_HPR_PGA_ENA); | ||
1025 | |||
1026 | /* Power on the amplifier */ | ||
1027 | snd_soc_update_bits(codec, reg, | ||
1028 | WM8904_HPL_ENA | WM8904_HPR_ENA, | ||
1029 | WM8904_HPL_ENA | WM8904_HPR_ENA); | ||
1030 | |||
1031 | |||
1032 | /* Enable the first stage */ | ||
1033 | snd_soc_update_bits(codec, reg, | ||
1034 | WM8904_HPL_ENA_DLY | WM8904_HPR_ENA_DLY, | ||
1035 | WM8904_HPL_ENA_DLY | WM8904_HPR_ENA_DLY); | ||
1036 | |||
1037 | /* Power up the DC servo */ | ||
1038 | snd_soc_update_bits(codec, WM8904_DC_SERVO_0, | ||
1039 | dcs_mask, dcs_mask); | ||
1040 | |||
1041 | /* Either calibrate the DC servo or restore cached state | ||
1042 | * if we have that. | ||
1043 | */ | ||
1044 | if (wm8904->dcs_state[dcs_l] || wm8904->dcs_state[dcs_r]) { | ||
1045 | dev_dbg(codec->dev, "Restoring DC servo state\n"); | ||
1046 | |||
1047 | snd_soc_write(codec, dcs_l_reg, | ||
1048 | wm8904->dcs_state[dcs_l]); | ||
1049 | snd_soc_write(codec, dcs_r_reg, | ||
1050 | wm8904->dcs_state[dcs_r]); | ||
1051 | |||
1052 | snd_soc_write(codec, WM8904_DC_SERVO_1, dcs_mask); | ||
1053 | |||
1054 | timeout = 20; | ||
1055 | } else { | ||
1056 | dev_dbg(codec->dev, "Calibrating DC servo\n"); | ||
1057 | |||
1058 | snd_soc_write(codec, WM8904_DC_SERVO_1, | ||
1059 | dcs_mask << WM8904_DCS_TRIG_STARTUP_0_SHIFT); | ||
1060 | |||
1061 | timeout = 500; | ||
1062 | } | ||
1063 | |||
1064 | /* Wait for DC servo to complete */ | ||
1065 | dcs_mask <<= WM8904_DCS_CAL_COMPLETE_SHIFT; | ||
1066 | do { | ||
1067 | val = snd_soc_read(codec, WM8904_DC_SERVO_READBACK_0); | ||
1068 | if ((val & dcs_mask) == dcs_mask) | ||
1069 | break; | ||
1070 | |||
1071 | msleep(1); | ||
1072 | } while (--timeout); | ||
1073 | |||
1074 | if ((val & dcs_mask) != dcs_mask) | ||
1075 | dev_warn(codec->dev, "DC servo timed out\n"); | ||
1076 | else | ||
1077 | dev_dbg(codec->dev, "DC servo ready\n"); | ||
1078 | |||
1079 | /* Enable the output stage */ | ||
1080 | snd_soc_update_bits(codec, reg, | ||
1081 | WM8904_HPL_ENA_OUTP | WM8904_HPR_ENA_OUTP, | ||
1082 | WM8904_HPL_ENA_OUTP | WM8904_HPR_ENA_OUTP); | ||
1083 | break; | ||
1084 | |||
1085 | case SND_SOC_DAPM_POST_PMU: | ||
1086 | /* Unshort the output itself */ | ||
1087 | snd_soc_update_bits(codec, reg, | ||
1088 | WM8904_HPL_RMV_SHORT | | ||
1089 | WM8904_HPR_RMV_SHORT, | ||
1090 | WM8904_HPL_RMV_SHORT | | ||
1091 | WM8904_HPR_RMV_SHORT); | ||
1092 | |||
1093 | break; | ||
1094 | |||
1095 | case SND_SOC_DAPM_PRE_PMD: | ||
1096 | /* Short the output */ | ||
1097 | snd_soc_update_bits(codec, reg, | ||
1098 | WM8904_HPL_RMV_SHORT | | ||
1099 | WM8904_HPR_RMV_SHORT, 0); | ||
1100 | break; | ||
1101 | |||
1102 | case SND_SOC_DAPM_POST_PMD: | ||
1103 | /* Cache the DC servo configuration; this will be | ||
1104 | * invalidated if we change the configuration. */ | ||
1105 | wm8904->dcs_state[dcs_l] = snd_soc_read(codec, dcs_l_reg); | ||
1106 | wm8904->dcs_state[dcs_r] = snd_soc_read(codec, dcs_r_reg); | ||
1107 | |||
1108 | snd_soc_update_bits(codec, WM8904_DC_SERVO_0, | ||
1109 | dcs_mask, 0); | ||
1110 | |||
1111 | /* Disable the amplifier input and output stages */ | ||
1112 | snd_soc_update_bits(codec, reg, | ||
1113 | WM8904_HPL_ENA | WM8904_HPR_ENA | | ||
1114 | WM8904_HPL_ENA_DLY | WM8904_HPR_ENA_DLY | | ||
1115 | WM8904_HPL_ENA_OUTP | WM8904_HPR_ENA_OUTP, | ||
1116 | 0); | ||
1117 | |||
1118 | /* PGAs too */ | ||
1119 | snd_soc_update_bits(codec, pwr_reg, | ||
1120 | WM8904_HPL_PGA_ENA | WM8904_HPR_PGA_ENA, | ||
1121 | 0); | ||
1122 | break; | ||
1123 | } | ||
1124 | |||
1125 | return 0; | ||
1126 | } | ||
1127 | |||
1128 | static const char *lin_text[] = { | ||
1129 | "IN1L", "IN2L", "IN3L" | ||
1130 | }; | ||
1131 | |||
1132 | static const struct soc_enum lin_enum = | ||
1133 | SOC_ENUM_SINGLE(WM8904_ANALOGUE_LEFT_INPUT_1, 2, 3, lin_text); | ||
1134 | |||
1135 | static const struct snd_kcontrol_new lin_mux = | ||
1136 | SOC_DAPM_ENUM("Left Capture Mux", lin_enum); | ||
1137 | |||
1138 | static const struct soc_enum lin_inv_enum = | ||
1139 | SOC_ENUM_SINGLE(WM8904_ANALOGUE_LEFT_INPUT_1, 4, 3, lin_text); | ||
1140 | |||
1141 | static const struct snd_kcontrol_new lin_inv_mux = | ||
1142 | SOC_DAPM_ENUM("Left Capture Inveting Mux", lin_inv_enum); | ||
1143 | |||
1144 | static const char *rin_text[] = { | ||
1145 | "IN1R", "IN2R", "IN3R" | ||
1146 | }; | ||
1147 | |||
1148 | static const struct soc_enum rin_enum = | ||
1149 | SOC_ENUM_SINGLE(WM8904_ANALOGUE_RIGHT_INPUT_1, 2, 3, rin_text); | ||
1150 | |||
1151 | static const struct snd_kcontrol_new rin_mux = | ||
1152 | SOC_DAPM_ENUM("Right Capture Mux", rin_enum); | ||
1153 | |||
1154 | static const struct soc_enum rin_inv_enum = | ||
1155 | SOC_ENUM_SINGLE(WM8904_ANALOGUE_RIGHT_INPUT_1, 4, 3, rin_text); | ||
1156 | |||
1157 | static const struct snd_kcontrol_new rin_inv_mux = | ||
1158 | SOC_DAPM_ENUM("Right Capture Inveting Mux", rin_inv_enum); | ||
1159 | |||
1160 | static const char *aif_text[] = { | ||
1161 | "Left", "Right" | ||
1162 | }; | ||
1163 | |||
1164 | static const struct soc_enum aifoutl_enum = | ||
1165 | SOC_ENUM_SINGLE(WM8904_AUDIO_INTERFACE_0, 7, 2, aif_text); | ||
1166 | |||
1167 | static const struct snd_kcontrol_new aifoutl_mux = | ||
1168 | SOC_DAPM_ENUM("AIFOUTL Mux", aifoutl_enum); | ||
1169 | |||
1170 | static const struct soc_enum aifoutr_enum = | ||
1171 | SOC_ENUM_SINGLE(WM8904_AUDIO_INTERFACE_0, 6, 2, aif_text); | ||
1172 | |||
1173 | static const struct snd_kcontrol_new aifoutr_mux = | ||
1174 | SOC_DAPM_ENUM("AIFOUTR Mux", aifoutr_enum); | ||
1175 | |||
1176 | static const struct soc_enum aifinl_enum = | ||
1177 | SOC_ENUM_SINGLE(WM8904_AUDIO_INTERFACE_0, 5, 2, aif_text); | ||
1178 | |||
1179 | static const struct snd_kcontrol_new aifinl_mux = | ||
1180 | SOC_DAPM_ENUM("AIFINL Mux", aifinl_enum); | ||
1181 | |||
1182 | static const struct soc_enum aifinr_enum = | ||
1183 | SOC_ENUM_SINGLE(WM8904_AUDIO_INTERFACE_0, 4, 2, aif_text); | ||
1184 | |||
1185 | static const struct snd_kcontrol_new aifinr_mux = | ||
1186 | SOC_DAPM_ENUM("AIFINR Mux", aifinr_enum); | ||
1187 | |||
1188 | static const struct snd_soc_dapm_widget wm8904_core_dapm_widgets[] = { | ||
1189 | SND_SOC_DAPM_SUPPLY("SYSCLK", WM8904_CLOCK_RATES_2, 2, 0, sysclk_event, | ||
1190 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), | ||
1191 | SND_SOC_DAPM_SUPPLY("CLK_DSP", WM8904_CLOCK_RATES_2, 1, 0, NULL, 0), | ||
1192 | SND_SOC_DAPM_SUPPLY("TOCLK", WM8904_CLOCK_RATES_2, 0, 0, NULL, 0), | ||
1193 | }; | ||
1194 | |||
1195 | static const struct snd_soc_dapm_widget wm8904_adc_dapm_widgets[] = { | ||
1196 | SND_SOC_DAPM_INPUT("IN1L"), | ||
1197 | SND_SOC_DAPM_INPUT("IN1R"), | ||
1198 | SND_SOC_DAPM_INPUT("IN2L"), | ||
1199 | SND_SOC_DAPM_INPUT("IN2R"), | ||
1200 | SND_SOC_DAPM_INPUT("IN3L"), | ||
1201 | SND_SOC_DAPM_INPUT("IN3R"), | ||
1202 | |||
1203 | SND_SOC_DAPM_MICBIAS("MICBIAS", WM8904_MIC_BIAS_CONTROL_0, 0, 0), | ||
1204 | |||
1205 | SND_SOC_DAPM_MUX("Left Capture Mux", SND_SOC_NOPM, 0, 0, &lin_mux), | ||
1206 | SND_SOC_DAPM_MUX("Left Capture Inverting Mux", SND_SOC_NOPM, 0, 0, | ||
1207 | &lin_inv_mux), | ||
1208 | SND_SOC_DAPM_MUX("Right Capture Mux", SND_SOC_NOPM, 0, 0, &rin_mux), | ||
1209 | SND_SOC_DAPM_MUX("Right Capture Inverting Mux", SND_SOC_NOPM, 0, 0, | ||
1210 | &rin_inv_mux), | ||
1211 | |||
1212 | SND_SOC_DAPM_PGA("Left Capture PGA", WM8904_POWER_MANAGEMENT_0, 1, 0, | ||
1213 | NULL, 0), | ||
1214 | SND_SOC_DAPM_PGA("Right Capture PGA", WM8904_POWER_MANAGEMENT_0, 0, 0, | ||
1215 | NULL, 0), | ||
1216 | |||
1217 | SND_SOC_DAPM_ADC("ADCL", NULL, WM8904_POWER_MANAGEMENT_6, 1, 0), | ||
1218 | SND_SOC_DAPM_ADC("ADCR", NULL, WM8904_POWER_MANAGEMENT_6, 0, 0), | ||
1219 | |||
1220 | SND_SOC_DAPM_MUX("AIFOUTL Mux", SND_SOC_NOPM, 0, 0, &aifoutl_mux), | ||
1221 | SND_SOC_DAPM_MUX("AIFOUTR Mux", SND_SOC_NOPM, 0, 0, &aifoutr_mux), | ||
1222 | |||
1223 | SND_SOC_DAPM_AIF_OUT("AIFOUTL", "Capture", 0, SND_SOC_NOPM, 0, 0), | ||
1224 | SND_SOC_DAPM_AIF_OUT("AIFOUTR", "Capture", 1, SND_SOC_NOPM, 0, 0), | ||
1225 | }; | ||
1226 | |||
1227 | static const struct snd_soc_dapm_widget wm8904_dac_dapm_widgets[] = { | ||
1228 | SND_SOC_DAPM_AIF_IN("AIFINL", "Playback", 0, SND_SOC_NOPM, 0, 0), | ||
1229 | SND_SOC_DAPM_AIF_IN("AIFINR", "Playback", 1, SND_SOC_NOPM, 0, 0), | ||
1230 | |||
1231 | SND_SOC_DAPM_MUX("DACL Mux", SND_SOC_NOPM, 0, 0, &aifinl_mux), | ||
1232 | SND_SOC_DAPM_MUX("DACR Mux", SND_SOC_NOPM, 0, 0, &aifinr_mux), | ||
1233 | |||
1234 | SND_SOC_DAPM_DAC("DACL", NULL, WM8904_POWER_MANAGEMENT_6, 3, 0), | ||
1235 | SND_SOC_DAPM_DAC("DACR", NULL, WM8904_POWER_MANAGEMENT_6, 2, 0), | ||
1236 | |||
1237 | SND_SOC_DAPM_SUPPLY("Charge pump", WM8904_CHARGE_PUMP_0, 0, 0, cp_event, | ||
1238 | SND_SOC_DAPM_POST_PMU), | ||
1239 | |||
1240 | SND_SOC_DAPM_PGA("HPL PGA", SND_SOC_NOPM, 1, 0, NULL, 0), | ||
1241 | SND_SOC_DAPM_PGA("HPR PGA", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
1242 | |||
1243 | SND_SOC_DAPM_PGA("LINEL PGA", SND_SOC_NOPM, 1, 0, NULL, 0), | ||
1244 | SND_SOC_DAPM_PGA("LINER PGA", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
1245 | |||
1246 | SND_SOC_DAPM_PGA_E("Headphone Output", SND_SOC_NOPM, WM8904_ANALOGUE_HP_0, | ||
1247 | 0, NULL, 0, out_pga_event, | ||
1248 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | | ||
1249 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), | ||
1250 | SND_SOC_DAPM_PGA_E("Line Output", SND_SOC_NOPM, WM8904_ANALOGUE_LINEOUT_0, | ||
1251 | 0, NULL, 0, out_pga_event, | ||
1252 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | | ||
1253 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), | ||
1254 | |||
1255 | SND_SOC_DAPM_OUTPUT("HPOUTL"), | ||
1256 | SND_SOC_DAPM_OUTPUT("HPOUTR"), | ||
1257 | SND_SOC_DAPM_OUTPUT("LINEOUTL"), | ||
1258 | SND_SOC_DAPM_OUTPUT("LINEOUTR"), | ||
1259 | }; | ||
1260 | |||
1261 | static const char *out_mux_text[] = { | ||
1262 | "DAC", "Bypass" | ||
1263 | }; | ||
1264 | |||
1265 | static const struct soc_enum hpl_enum = | ||
1266 | SOC_ENUM_SINGLE(WM8904_ANALOGUE_OUT12_ZC, 3, 2, out_mux_text); | ||
1267 | |||
1268 | static const struct snd_kcontrol_new hpl_mux = | ||
1269 | SOC_DAPM_ENUM("HPL Mux", hpl_enum); | ||
1270 | |||
1271 | static const struct soc_enum hpr_enum = | ||
1272 | SOC_ENUM_SINGLE(WM8904_ANALOGUE_OUT12_ZC, 2, 2, out_mux_text); | ||
1273 | |||
1274 | static const struct snd_kcontrol_new hpr_mux = | ||
1275 | SOC_DAPM_ENUM("HPR Mux", hpr_enum); | ||
1276 | |||
1277 | static const struct soc_enum linel_enum = | ||
1278 | SOC_ENUM_SINGLE(WM8904_ANALOGUE_OUT12_ZC, 1, 2, out_mux_text); | ||
1279 | |||
1280 | static const struct snd_kcontrol_new linel_mux = | ||
1281 | SOC_DAPM_ENUM("LINEL Mux", linel_enum); | ||
1282 | |||
1283 | static const struct soc_enum liner_enum = | ||
1284 | SOC_ENUM_SINGLE(WM8904_ANALOGUE_OUT12_ZC, 0, 2, out_mux_text); | ||
1285 | |||
1286 | static const struct snd_kcontrol_new liner_mux = | ||
1287 | SOC_DAPM_ENUM("LINEL Mux", liner_enum); | ||
1288 | |||
1289 | static const char *sidetone_text[] = { | ||
1290 | "None", "Left", "Right" | ||
1291 | }; | ||
1292 | |||
1293 | static const struct soc_enum dacl_sidetone_enum = | ||
1294 | SOC_ENUM_SINGLE(WM8904_DAC_DIGITAL_0, 2, 3, sidetone_text); | ||
1295 | |||
1296 | static const struct snd_kcontrol_new dacl_sidetone_mux = | ||
1297 | SOC_DAPM_ENUM("Left Sidetone Mux", dacl_sidetone_enum); | ||
1298 | |||
1299 | static const struct soc_enum dacr_sidetone_enum = | ||
1300 | SOC_ENUM_SINGLE(WM8904_DAC_DIGITAL_0, 0, 3, sidetone_text); | ||
1301 | |||
1302 | static const struct snd_kcontrol_new dacr_sidetone_mux = | ||
1303 | SOC_DAPM_ENUM("Right Sidetone Mux", dacr_sidetone_enum); | ||
1304 | |||
1305 | static const struct snd_soc_dapm_widget wm8904_dapm_widgets[] = { | ||
1306 | SND_SOC_DAPM_SUPPLY("Class G", WM8904_CLASS_W_0, 0, 1, NULL, 0), | ||
1307 | SND_SOC_DAPM_PGA("Left Bypass", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
1308 | SND_SOC_DAPM_PGA("Right Bypass", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
1309 | |||
1310 | SND_SOC_DAPM_MUX("Left Sidetone", SND_SOC_NOPM, 0, 0, &dacl_sidetone_mux), | ||
1311 | SND_SOC_DAPM_MUX("Right Sidetone", SND_SOC_NOPM, 0, 0, &dacr_sidetone_mux), | ||
1312 | |||
1313 | SND_SOC_DAPM_MUX("HPL Mux", SND_SOC_NOPM, 0, 0, &hpl_mux), | ||
1314 | SND_SOC_DAPM_MUX("HPR Mux", SND_SOC_NOPM, 0, 0, &hpr_mux), | ||
1315 | SND_SOC_DAPM_MUX("LINEL Mux", SND_SOC_NOPM, 0, 0, &linel_mux), | ||
1316 | SND_SOC_DAPM_MUX("LINER Mux", SND_SOC_NOPM, 0, 0, &liner_mux), | ||
1317 | }; | ||
1318 | |||
1319 | static const struct snd_soc_dapm_route core_intercon[] = { | ||
1320 | { "CLK_DSP", NULL, "SYSCLK" }, | ||
1321 | { "TOCLK", NULL, "SYSCLK" }, | ||
1322 | }; | ||
1323 | |||
1324 | static const struct snd_soc_dapm_route adc_intercon[] = { | ||
1325 | { "Left Capture Mux", "IN1L", "IN1L" }, | ||
1326 | { "Left Capture Mux", "IN2L", "IN2L" }, | ||
1327 | { "Left Capture Mux", "IN3L", "IN3L" }, | ||
1328 | |||
1329 | { "Left Capture Inverting Mux", "IN1L", "IN1L" }, | ||
1330 | { "Left Capture Inverting Mux", "IN2L", "IN2L" }, | ||
1331 | { "Left Capture Inverting Mux", "IN3L", "IN3L" }, | ||
1332 | |||
1333 | { "Right Capture Mux", "IN1R", "IN1R" }, | ||
1334 | { "Right Capture Mux", "IN2R", "IN2R" }, | ||
1335 | { "Right Capture Mux", "IN3R", "IN3R" }, | ||
1336 | |||
1337 | { "Right Capture Inverting Mux", "IN1R", "IN1R" }, | ||
1338 | { "Right Capture Inverting Mux", "IN2R", "IN2R" }, | ||
1339 | { "Right Capture Inverting Mux", "IN3R", "IN3R" }, | ||
1340 | |||
1341 | { "Left Capture PGA", NULL, "Left Capture Mux" }, | ||
1342 | { "Left Capture PGA", NULL, "Left Capture Inverting Mux" }, | ||
1343 | |||
1344 | { "Right Capture PGA", NULL, "Right Capture Mux" }, | ||
1345 | { "Right Capture PGA", NULL, "Right Capture Inverting Mux" }, | ||
1346 | |||
1347 | { "AIFOUTL", "Left", "ADCL" }, | ||
1348 | { "AIFOUTL", "Right", "ADCR" }, | ||
1349 | { "AIFOUTR", "Left", "ADCL" }, | ||
1350 | { "AIFOUTR", "Right", "ADCR" }, | ||
1351 | |||
1352 | { "ADCL", NULL, "CLK_DSP" }, | ||
1353 | { "ADCL", NULL, "Left Capture PGA" }, | ||
1354 | |||
1355 | { "ADCR", NULL, "CLK_DSP" }, | ||
1356 | { "ADCR", NULL, "Right Capture PGA" }, | ||
1357 | }; | ||
1358 | |||
1359 | static const struct snd_soc_dapm_route dac_intercon[] = { | ||
1360 | { "DACL", "Right", "AIFINR" }, | ||
1361 | { "DACL", "Left", "AIFINL" }, | ||
1362 | { "DACL", NULL, "CLK_DSP" }, | ||
1363 | |||
1364 | { "DACR", "Right", "AIFINR" }, | ||
1365 | { "DACR", "Left", "AIFINL" }, | ||
1366 | { "DACR", NULL, "CLK_DSP" }, | ||
1367 | |||
1368 | { "Charge pump", NULL, "SYSCLK" }, | ||
1369 | |||
1370 | { "Headphone Output", NULL, "HPL PGA" }, | ||
1371 | { "Headphone Output", NULL, "HPR PGA" }, | ||
1372 | { "Headphone Output", NULL, "Charge pump" }, | ||
1373 | { "Headphone Output", NULL, "TOCLK" }, | ||
1374 | |||
1375 | { "Line Output", NULL, "LINEL PGA" }, | ||
1376 | { "Line Output", NULL, "LINER PGA" }, | ||
1377 | { "Line Output", NULL, "Charge pump" }, | ||
1378 | { "Line Output", NULL, "TOCLK" }, | ||
1379 | |||
1380 | { "HPOUTL", NULL, "Headphone Output" }, | ||
1381 | { "HPOUTR", NULL, "Headphone Output" }, | ||
1382 | |||
1383 | { "LINEOUTL", NULL, "Line Output" }, | ||
1384 | { "LINEOUTR", NULL, "Line Output" }, | ||
1385 | }; | ||
1386 | |||
1387 | static const struct snd_soc_dapm_route wm8904_intercon[] = { | ||
1388 | { "Left Sidetone", "Left", "ADCL" }, | ||
1389 | { "Left Sidetone", "Right", "ADCR" }, | ||
1390 | { "DACL", NULL, "Left Sidetone" }, | ||
1391 | |||
1392 | { "Right Sidetone", "Left", "ADCL" }, | ||
1393 | { "Right Sidetone", "Right", "ADCR" }, | ||
1394 | { "DACR", NULL, "Right Sidetone" }, | ||
1395 | |||
1396 | { "Left Bypass", NULL, "Class G" }, | ||
1397 | { "Left Bypass", NULL, "Left Capture PGA" }, | ||
1398 | |||
1399 | { "Right Bypass", NULL, "Class G" }, | ||
1400 | { "Right Bypass", NULL, "Right Capture PGA" }, | ||
1401 | |||
1402 | { "HPL Mux", "DAC", "DACL" }, | ||
1403 | { "HPL Mux", "Bypass", "Left Bypass" }, | ||
1404 | |||
1405 | { "HPR Mux", "DAC", "DACR" }, | ||
1406 | { "HPR Mux", "Bypass", "Right Bypass" }, | ||
1407 | |||
1408 | { "LINEL Mux", "DAC", "DACL" }, | ||
1409 | { "LINEL Mux", "Bypass", "Left Bypass" }, | ||
1410 | |||
1411 | { "LINER Mux", "DAC", "DACR" }, | ||
1412 | { "LINER Mux", "Bypass", "Right Bypass" }, | ||
1413 | |||
1414 | { "HPL PGA", NULL, "HPL Mux" }, | ||
1415 | { "HPR PGA", NULL, "HPR Mux" }, | ||
1416 | |||
1417 | { "LINEL PGA", NULL, "LINEL Mux" }, | ||
1418 | { "LINER PGA", NULL, "LINER Mux" }, | ||
1419 | }; | ||
1420 | |||
1421 | static const struct snd_soc_dapm_route wm8912_intercon[] = { | ||
1422 | { "HPL PGA", NULL, "DACL" }, | ||
1423 | { "HPR PGA", NULL, "DACR" }, | ||
1424 | |||
1425 | { "LINEL PGA", NULL, "DACL" }, | ||
1426 | { "LINER PGA", NULL, "DACR" }, | ||
1427 | }; | ||
1428 | |||
1429 | static int wm8904_add_widgets(struct snd_soc_codec *codec) | ||
1430 | { | ||
1431 | struct wm8904_priv *wm8904 = codec->private_data; | ||
1432 | |||
1433 | snd_soc_dapm_new_controls(codec, wm8904_core_dapm_widgets, | ||
1434 | ARRAY_SIZE(wm8904_core_dapm_widgets)); | ||
1435 | snd_soc_dapm_add_routes(codec, core_intercon, | ||
1436 | ARRAY_SIZE(core_intercon)); | ||
1437 | |||
1438 | switch (wm8904->devtype) { | ||
1439 | case WM8904: | ||
1440 | snd_soc_add_controls(codec, wm8904_adc_snd_controls, | ||
1441 | ARRAY_SIZE(wm8904_adc_snd_controls)); | ||
1442 | snd_soc_add_controls(codec, wm8904_dac_snd_controls, | ||
1443 | ARRAY_SIZE(wm8904_dac_snd_controls)); | ||
1444 | snd_soc_add_controls(codec, wm8904_snd_controls, | ||
1445 | ARRAY_SIZE(wm8904_snd_controls)); | ||
1446 | |||
1447 | snd_soc_dapm_new_controls(codec, wm8904_adc_dapm_widgets, | ||
1448 | ARRAY_SIZE(wm8904_adc_dapm_widgets)); | ||
1449 | snd_soc_dapm_new_controls(codec, wm8904_dac_dapm_widgets, | ||
1450 | ARRAY_SIZE(wm8904_dac_dapm_widgets)); | ||
1451 | snd_soc_dapm_new_controls(codec, wm8904_dapm_widgets, | ||
1452 | ARRAY_SIZE(wm8904_dapm_widgets)); | ||
1453 | |||
1454 | snd_soc_dapm_add_routes(codec, core_intercon, | ||
1455 | ARRAY_SIZE(core_intercon)); | ||
1456 | snd_soc_dapm_add_routes(codec, adc_intercon, | ||
1457 | ARRAY_SIZE(adc_intercon)); | ||
1458 | snd_soc_dapm_add_routes(codec, dac_intercon, | ||
1459 | ARRAY_SIZE(dac_intercon)); | ||
1460 | snd_soc_dapm_add_routes(codec, wm8904_intercon, | ||
1461 | ARRAY_SIZE(wm8904_intercon)); | ||
1462 | break; | ||
1463 | |||
1464 | case WM8912: | ||
1465 | snd_soc_add_controls(codec, wm8904_dac_snd_controls, | ||
1466 | ARRAY_SIZE(wm8904_dac_snd_controls)); | ||
1467 | |||
1468 | snd_soc_dapm_new_controls(codec, wm8904_dac_dapm_widgets, | ||
1469 | ARRAY_SIZE(wm8904_dac_dapm_widgets)); | ||
1470 | |||
1471 | snd_soc_dapm_add_routes(codec, dac_intercon, | ||
1472 | ARRAY_SIZE(dac_intercon)); | ||
1473 | snd_soc_dapm_add_routes(codec, wm8912_intercon, | ||
1474 | ARRAY_SIZE(wm8912_intercon)); | ||
1475 | break; | ||
1476 | } | ||
1477 | |||
1478 | snd_soc_dapm_new_widgets(codec); | ||
1479 | return 0; | ||
1480 | } | ||
1481 | |||
1482 | static struct { | ||
1483 | int ratio; | ||
1484 | unsigned int clk_sys_rate; | ||
1485 | } clk_sys_rates[] = { | ||
1486 | { 64, 0 }, | ||
1487 | { 128, 1 }, | ||
1488 | { 192, 2 }, | ||
1489 | { 256, 3 }, | ||
1490 | { 384, 4 }, | ||
1491 | { 512, 5 }, | ||
1492 | { 786, 6 }, | ||
1493 | { 1024, 7 }, | ||
1494 | { 1408, 8 }, | ||
1495 | { 1536, 9 }, | ||
1496 | }; | ||
1497 | |||
1498 | static struct { | ||
1499 | int rate; | ||
1500 | int sample_rate; | ||
1501 | } sample_rates[] = { | ||
1502 | { 8000, 0 }, | ||
1503 | { 11025, 1 }, | ||
1504 | { 12000, 1 }, | ||
1505 | { 16000, 2 }, | ||
1506 | { 22050, 3 }, | ||
1507 | { 24000, 3 }, | ||
1508 | { 32000, 4 }, | ||
1509 | { 44100, 5 }, | ||
1510 | { 48000, 5 }, | ||
1511 | }; | ||
1512 | |||
1513 | static struct { | ||
1514 | int div; /* *10 due to .5s */ | ||
1515 | int bclk_div; | ||
1516 | } bclk_divs[] = { | ||
1517 | { 10, 0 }, | ||
1518 | { 15, 1 }, | ||
1519 | { 20, 2 }, | ||
1520 | { 30, 3 }, | ||
1521 | { 40, 4 }, | ||
1522 | { 50, 5 }, | ||
1523 | { 55, 6 }, | ||
1524 | { 60, 7 }, | ||
1525 | { 80, 8 }, | ||
1526 | { 100, 9 }, | ||
1527 | { 110, 10 }, | ||
1528 | { 120, 11 }, | ||
1529 | { 160, 12 }, | ||
1530 | { 200, 13 }, | ||
1531 | { 220, 14 }, | ||
1532 | { 240, 16 }, | ||
1533 | { 200, 17 }, | ||
1534 | { 320, 18 }, | ||
1535 | { 440, 19 }, | ||
1536 | { 480, 20 }, | ||
1537 | }; | ||
1538 | |||
1539 | |||
1540 | static int wm8904_hw_params(struct snd_pcm_substream *substream, | ||
1541 | struct snd_pcm_hw_params *params, | ||
1542 | struct snd_soc_dai *dai) | ||
1543 | { | ||
1544 | struct snd_soc_codec *codec = dai->codec; | ||
1545 | struct wm8904_priv *wm8904 = codec->private_data; | ||
1546 | int ret, i, best, best_val, cur_val; | ||
1547 | unsigned int aif1 = 0; | ||
1548 | unsigned int aif2 = 0; | ||
1549 | unsigned int aif3 = 0; | ||
1550 | unsigned int clock1 = 0; | ||
1551 | unsigned int dac_digital1 = 0; | ||
1552 | |||
1553 | /* What BCLK do we need? */ | ||
1554 | wm8904->fs = params_rate(params); | ||
1555 | if (wm8904->tdm_slots) { | ||
1556 | dev_dbg(codec->dev, "Configuring for %d %d bit TDM slots\n", | ||
1557 | wm8904->tdm_slots, wm8904->tdm_width); | ||
1558 | wm8904->bclk = snd_soc_calc_bclk(wm8904->fs, | ||
1559 | wm8904->tdm_width, 2, | ||
1560 | wm8904->tdm_slots); | ||
1561 | } else { | ||
1562 | wm8904->bclk = snd_soc_params_to_bclk(params); | ||
1563 | } | ||
1564 | |||
1565 | switch (params_format(params)) { | ||
1566 | case SNDRV_PCM_FORMAT_S16_LE: | ||
1567 | break; | ||
1568 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
1569 | aif1 |= 0x40; | ||
1570 | break; | ||
1571 | case SNDRV_PCM_FORMAT_S24_LE: | ||
1572 | aif1 |= 0x80; | ||
1573 | break; | ||
1574 | case SNDRV_PCM_FORMAT_S32_LE: | ||
1575 | aif1 |= 0xc0; | ||
1576 | break; | ||
1577 | default: | ||
1578 | return -EINVAL; | ||
1579 | } | ||
1580 | |||
1581 | |||
1582 | dev_dbg(codec->dev, "Target BCLK is %dHz\n", wm8904->bclk); | ||
1583 | |||
1584 | ret = wm8904_configure_clocking(codec); | ||
1585 | if (ret != 0) | ||
1586 | return ret; | ||
1587 | |||
1588 | /* Select nearest CLK_SYS_RATE */ | ||
1589 | best = 0; | ||
1590 | best_val = abs((wm8904->sysclk_rate / clk_sys_rates[0].ratio) | ||
1591 | - wm8904->fs); | ||
1592 | for (i = 1; i < ARRAY_SIZE(clk_sys_rates); i++) { | ||
1593 | cur_val = abs((wm8904->sysclk_rate / | ||
1594 | clk_sys_rates[i].ratio) - wm8904->fs);; | ||
1595 | if (cur_val < best_val) { | ||
1596 | best = i; | ||
1597 | best_val = cur_val; | ||
1598 | } | ||
1599 | } | ||
1600 | dev_dbg(codec->dev, "Selected CLK_SYS_RATIO of %d\n", | ||
1601 | clk_sys_rates[best].ratio); | ||
1602 | clock1 |= (clk_sys_rates[best].clk_sys_rate | ||
1603 | << WM8904_CLK_SYS_RATE_SHIFT); | ||
1604 | |||
1605 | /* SAMPLE_RATE */ | ||
1606 | best = 0; | ||
1607 | best_val = abs(wm8904->fs - sample_rates[0].rate); | ||
1608 | for (i = 1; i < ARRAY_SIZE(sample_rates); i++) { | ||
1609 | /* Closest match */ | ||
1610 | cur_val = abs(wm8904->fs - sample_rates[i].rate); | ||
1611 | if (cur_val < best_val) { | ||
1612 | best = i; | ||
1613 | best_val = cur_val; | ||
1614 | } | ||
1615 | } | ||
1616 | dev_dbg(codec->dev, "Selected SAMPLE_RATE of %dHz\n", | ||
1617 | sample_rates[best].rate); | ||
1618 | clock1 |= (sample_rates[best].sample_rate | ||
1619 | << WM8904_SAMPLE_RATE_SHIFT); | ||
1620 | |||
1621 | /* Enable sloping stopband filter for low sample rates */ | ||
1622 | if (wm8904->fs <= 24000) | ||
1623 | dac_digital1 |= WM8904_DAC_SB_FILT; | ||
1624 | |||
1625 | /* BCLK_DIV */ | ||
1626 | best = 0; | ||
1627 | best_val = INT_MAX; | ||
1628 | for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) { | ||
1629 | cur_val = ((wm8904->sysclk_rate * 10) / bclk_divs[i].div) | ||
1630 | - wm8904->bclk; | ||
1631 | if (cur_val < 0) /* Table is sorted */ | ||
1632 | break; | ||
1633 | if (cur_val < best_val) { | ||
1634 | best = i; | ||
1635 | best_val = cur_val; | ||
1636 | } | ||
1637 | } | ||
1638 | wm8904->bclk = (wm8904->sysclk_rate * 10) / bclk_divs[best].div; | ||
1639 | dev_dbg(codec->dev, "Selected BCLK_DIV of %d for %dHz BCLK\n", | ||
1640 | bclk_divs[best].div, wm8904->bclk); | ||
1641 | aif2 |= bclk_divs[best].bclk_div; | ||
1642 | |||
1643 | /* LRCLK is a simple fraction of BCLK */ | ||
1644 | dev_dbg(codec->dev, "LRCLK_RATE is %d\n", wm8904->bclk / wm8904->fs); | ||
1645 | aif3 |= wm8904->bclk / wm8904->fs; | ||
1646 | |||
1647 | /* Apply the settings */ | ||
1648 | snd_soc_update_bits(codec, WM8904_DAC_DIGITAL_1, | ||
1649 | WM8904_DAC_SB_FILT, dac_digital1); | ||
1650 | snd_soc_update_bits(codec, WM8904_AUDIO_INTERFACE_1, | ||
1651 | WM8904_AIF_WL_MASK, aif1); | ||
1652 | snd_soc_update_bits(codec, WM8904_AUDIO_INTERFACE_2, | ||
1653 | WM8904_BCLK_DIV_MASK, aif2); | ||
1654 | snd_soc_update_bits(codec, WM8904_AUDIO_INTERFACE_3, | ||
1655 | WM8904_LRCLK_RATE_MASK, aif3); | ||
1656 | snd_soc_update_bits(codec, WM8904_CLOCK_RATES_1, | ||
1657 | WM8904_SAMPLE_RATE_MASK | | ||
1658 | WM8904_CLK_SYS_RATE_MASK, clock1); | ||
1659 | |||
1660 | /* Update filters for the new settings */ | ||
1661 | wm8904_set_retune_mobile(codec); | ||
1662 | wm8904_set_deemph(codec); | ||
1663 | |||
1664 | return 0; | ||
1665 | } | ||
1666 | |||
1667 | |||
1668 | static int wm8904_set_sysclk(struct snd_soc_dai *dai, int clk_id, | ||
1669 | unsigned int freq, int dir) | ||
1670 | { | ||
1671 | struct snd_soc_codec *codec = dai->codec; | ||
1672 | struct wm8904_priv *priv = codec->private_data; | ||
1673 | |||
1674 | switch (clk_id) { | ||
1675 | case WM8904_CLK_MCLK: | ||
1676 | priv->sysclk_src = clk_id; | ||
1677 | priv->mclk_rate = freq; | ||
1678 | break; | ||
1679 | |||
1680 | case WM8904_CLK_FLL: | ||
1681 | priv->sysclk_src = clk_id; | ||
1682 | break; | ||
1683 | |||
1684 | default: | ||
1685 | return -EINVAL; | ||
1686 | } | ||
1687 | |||
1688 | dev_dbg(dai->dev, "Clock source is %d at %uHz\n", clk_id, freq); | ||
1689 | |||
1690 | wm8904_configure_clocking(codec); | ||
1691 | |||
1692 | return 0; | ||
1693 | } | ||
1694 | |||
1695 | static int wm8904_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) | ||
1696 | { | ||
1697 | struct snd_soc_codec *codec = dai->codec; | ||
1698 | unsigned int aif1 = 0; | ||
1699 | unsigned int aif3 = 0; | ||
1700 | |||
1701 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
1702 | case SND_SOC_DAIFMT_CBS_CFS: | ||
1703 | break; | ||
1704 | case SND_SOC_DAIFMT_CBS_CFM: | ||
1705 | aif3 |= WM8904_LRCLK_DIR; | ||
1706 | break; | ||
1707 | case SND_SOC_DAIFMT_CBM_CFS: | ||
1708 | aif1 |= WM8904_BCLK_DIR; | ||
1709 | break; | ||
1710 | case SND_SOC_DAIFMT_CBM_CFM: | ||
1711 | aif1 |= WM8904_BCLK_DIR; | ||
1712 | aif3 |= WM8904_LRCLK_DIR; | ||
1713 | break; | ||
1714 | default: | ||
1715 | return -EINVAL; | ||
1716 | } | ||
1717 | |||
1718 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
1719 | case SND_SOC_DAIFMT_DSP_B: | ||
1720 | aif1 |= WM8904_AIF_LRCLK_INV; | ||
1721 | case SND_SOC_DAIFMT_DSP_A: | ||
1722 | aif1 |= 0x3; | ||
1723 | break; | ||
1724 | case SND_SOC_DAIFMT_I2S: | ||
1725 | aif1 |= 0x2; | ||
1726 | break; | ||
1727 | case SND_SOC_DAIFMT_RIGHT_J: | ||
1728 | break; | ||
1729 | case SND_SOC_DAIFMT_LEFT_J: | ||
1730 | aif1 |= 0x1; | ||
1731 | break; | ||
1732 | default: | ||
1733 | return -EINVAL; | ||
1734 | } | ||
1735 | |||
1736 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
1737 | case SND_SOC_DAIFMT_DSP_A: | ||
1738 | case SND_SOC_DAIFMT_DSP_B: | ||
1739 | /* frame inversion not valid for DSP modes */ | ||
1740 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
1741 | case SND_SOC_DAIFMT_NB_NF: | ||
1742 | break; | ||
1743 | case SND_SOC_DAIFMT_IB_NF: | ||
1744 | aif1 |= WM8904_AIF_BCLK_INV; | ||
1745 | break; | ||
1746 | default: | ||
1747 | return -EINVAL; | ||
1748 | } | ||
1749 | break; | ||
1750 | |||
1751 | case SND_SOC_DAIFMT_I2S: | ||
1752 | case SND_SOC_DAIFMT_RIGHT_J: | ||
1753 | case SND_SOC_DAIFMT_LEFT_J: | ||
1754 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
1755 | case SND_SOC_DAIFMT_NB_NF: | ||
1756 | break; | ||
1757 | case SND_SOC_DAIFMT_IB_IF: | ||
1758 | aif1 |= WM8904_AIF_BCLK_INV | WM8904_AIF_LRCLK_INV; | ||
1759 | break; | ||
1760 | case SND_SOC_DAIFMT_IB_NF: | ||
1761 | aif1 |= WM8904_AIF_BCLK_INV; | ||
1762 | break; | ||
1763 | case SND_SOC_DAIFMT_NB_IF: | ||
1764 | aif1 |= WM8904_AIF_LRCLK_INV; | ||
1765 | break; | ||
1766 | default: | ||
1767 | return -EINVAL; | ||
1768 | } | ||
1769 | break; | ||
1770 | default: | ||
1771 | return -EINVAL; | ||
1772 | } | ||
1773 | |||
1774 | snd_soc_update_bits(codec, WM8904_AUDIO_INTERFACE_1, | ||
1775 | WM8904_AIF_BCLK_INV | WM8904_AIF_LRCLK_INV | | ||
1776 | WM8904_AIF_FMT_MASK | WM8904_BCLK_DIR, aif1); | ||
1777 | snd_soc_update_bits(codec, WM8904_AUDIO_INTERFACE_3, | ||
1778 | WM8904_LRCLK_DIR, aif3); | ||
1779 | |||
1780 | return 0; | ||
1781 | } | ||
1782 | |||
1783 | |||
1784 | static int wm8904_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, | ||
1785 | unsigned int rx_mask, int slots, int slot_width) | ||
1786 | { | ||
1787 | struct snd_soc_codec *codec = dai->codec; | ||
1788 | struct wm8904_priv *wm8904 = codec->private_data; | ||
1789 | int aif1 = 0; | ||
1790 | |||
1791 | /* Don't need to validate anything if we're turning off TDM */ | ||
1792 | if (slots == 0) | ||
1793 | goto out; | ||
1794 | |||
1795 | /* Note that we allow configurations we can't handle ourselves - | ||
1796 | * for example, we can generate clocks for slots 2 and up even if | ||
1797 | * we can't use those slots ourselves. | ||
1798 | */ | ||
1799 | aif1 |= WM8904_AIFADC_TDM | WM8904_AIFDAC_TDM; | ||
1800 | |||
1801 | switch (rx_mask) { | ||
1802 | case 3: | ||
1803 | break; | ||
1804 | case 0xc: | ||
1805 | aif1 |= WM8904_AIFADC_TDM_CHAN; | ||
1806 | break; | ||
1807 | default: | ||
1808 | return -EINVAL; | ||
1809 | } | ||
1810 | |||
1811 | |||
1812 | switch (tx_mask) { | ||
1813 | case 3: | ||
1814 | break; | ||
1815 | case 0xc: | ||
1816 | aif1 |= WM8904_AIFDAC_TDM_CHAN; | ||
1817 | break; | ||
1818 | default: | ||
1819 | return -EINVAL; | ||
1820 | } | ||
1821 | |||
1822 | out: | ||
1823 | wm8904->tdm_width = slot_width; | ||
1824 | wm8904->tdm_slots = slots / 2; | ||
1825 | |||
1826 | snd_soc_update_bits(codec, WM8904_AUDIO_INTERFACE_1, | ||
1827 | WM8904_AIFADC_TDM | WM8904_AIFADC_TDM_CHAN | | ||
1828 | WM8904_AIFDAC_TDM | WM8904_AIFDAC_TDM_CHAN, aif1); | ||
1829 | |||
1830 | return 0; | ||
1831 | } | ||
1832 | |||
1833 | struct _fll_div { | ||
1834 | u16 fll_fratio; | ||
1835 | u16 fll_outdiv; | ||
1836 | u16 fll_clk_ref_div; | ||
1837 | u16 n; | ||
1838 | u16 k; | ||
1839 | }; | ||
1840 | |||
1841 | /* The size in bits of the FLL divide multiplied by 10 | ||
1842 | * to allow rounding later */ | ||
1843 | #define FIXED_FLL_SIZE ((1 << 16) * 10) | ||
1844 | |||
1845 | static struct { | ||
1846 | unsigned int min; | ||
1847 | unsigned int max; | ||
1848 | u16 fll_fratio; | ||
1849 | int ratio; | ||
1850 | } fll_fratios[] = { | ||
1851 | { 0, 64000, 4, 16 }, | ||
1852 | { 64000, 128000, 3, 8 }, | ||
1853 | { 128000, 256000, 2, 4 }, | ||
1854 | { 256000, 1000000, 1, 2 }, | ||
1855 | { 1000000, 13500000, 0, 1 }, | ||
1856 | }; | ||
1857 | |||
1858 | static int fll_factors(struct _fll_div *fll_div, unsigned int Fref, | ||
1859 | unsigned int Fout) | ||
1860 | { | ||
1861 | u64 Kpart; | ||
1862 | unsigned int K, Ndiv, Nmod, target; | ||
1863 | unsigned int div; | ||
1864 | int i; | ||
1865 | |||
1866 | /* Fref must be <=13.5MHz */ | ||
1867 | div = 1; | ||
1868 | fll_div->fll_clk_ref_div = 0; | ||
1869 | while ((Fref / div) > 13500000) { | ||
1870 | div *= 2; | ||
1871 | fll_div->fll_clk_ref_div++; | ||
1872 | |||
1873 | if (div > 8) { | ||
1874 | pr_err("Can't scale %dMHz input down to <=13.5MHz\n", | ||
1875 | Fref); | ||
1876 | return -EINVAL; | ||
1877 | } | ||
1878 | } | ||
1879 | |||
1880 | pr_debug("Fref=%u Fout=%u\n", Fref, Fout); | ||
1881 | |||
1882 | /* Apply the division for our remaining calculations */ | ||
1883 | Fref /= div; | ||
1884 | |||
1885 | /* Fvco should be 90-100MHz; don't check the upper bound */ | ||
1886 | div = 4; | ||
1887 | while (Fout * div < 90000000) { | ||
1888 | div++; | ||
1889 | if (div > 64) { | ||
1890 | pr_err("Unable to find FLL_OUTDIV for Fout=%uHz\n", | ||
1891 | Fout); | ||
1892 | return -EINVAL; | ||
1893 | } | ||
1894 | } | ||
1895 | target = Fout * div; | ||
1896 | fll_div->fll_outdiv = div - 1; | ||
1897 | |||
1898 | pr_debug("Fvco=%dHz\n", target); | ||
1899 | |||
1900 | /* Find an appropraite FLL_FRATIO and factor it out of the target */ | ||
1901 | for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) { | ||
1902 | if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) { | ||
1903 | fll_div->fll_fratio = fll_fratios[i].fll_fratio; | ||
1904 | target /= fll_fratios[i].ratio; | ||
1905 | break; | ||
1906 | } | ||
1907 | } | ||
1908 | if (i == ARRAY_SIZE(fll_fratios)) { | ||
1909 | pr_err("Unable to find FLL_FRATIO for Fref=%uHz\n", Fref); | ||
1910 | return -EINVAL; | ||
1911 | } | ||
1912 | |||
1913 | /* Now, calculate N.K */ | ||
1914 | Ndiv = target / Fref; | ||
1915 | |||
1916 | fll_div->n = Ndiv; | ||
1917 | Nmod = target % Fref; | ||
1918 | pr_debug("Nmod=%d\n", Nmod); | ||
1919 | |||
1920 | /* Calculate fractional part - scale up so we can round. */ | ||
1921 | Kpart = FIXED_FLL_SIZE * (long long)Nmod; | ||
1922 | |||
1923 | do_div(Kpart, Fref); | ||
1924 | |||
1925 | K = Kpart & 0xFFFFFFFF; | ||
1926 | |||
1927 | if ((K % 10) >= 5) | ||
1928 | K += 5; | ||
1929 | |||
1930 | /* Move down to proper range now rounding is done */ | ||
1931 | fll_div->k = K / 10; | ||
1932 | |||
1933 | pr_debug("N=%x K=%x FLL_FRATIO=%x FLL_OUTDIV=%x FLL_CLK_REF_DIV=%x\n", | ||
1934 | fll_div->n, fll_div->k, | ||
1935 | fll_div->fll_fratio, fll_div->fll_outdiv, | ||
1936 | fll_div->fll_clk_ref_div); | ||
1937 | |||
1938 | return 0; | ||
1939 | } | ||
1940 | |||
1941 | static int wm8904_set_fll(struct snd_soc_dai *dai, int fll_id, int source, | ||
1942 | unsigned int Fref, unsigned int Fout) | ||
1943 | { | ||
1944 | struct snd_soc_codec *codec = dai->codec; | ||
1945 | struct wm8904_priv *wm8904 = codec->private_data; | ||
1946 | struct _fll_div fll_div; | ||
1947 | int ret, val; | ||
1948 | int clock2, fll1; | ||
1949 | |||
1950 | /* Any change? */ | ||
1951 | if (source == wm8904->fll_src && Fref == wm8904->fll_fref && | ||
1952 | Fout == wm8904->fll_fout) | ||
1953 | return 0; | ||
1954 | |||
1955 | clock2 = snd_soc_read(codec, WM8904_CLOCK_RATES_2); | ||
1956 | |||
1957 | if (Fout == 0) { | ||
1958 | dev_dbg(codec->dev, "FLL disabled\n"); | ||
1959 | |||
1960 | wm8904->fll_fref = 0; | ||
1961 | wm8904->fll_fout = 0; | ||
1962 | |||
1963 | /* Gate SYSCLK to avoid glitches */ | ||
1964 | snd_soc_update_bits(codec, WM8904_CLOCK_RATES_2, | ||
1965 | WM8904_CLK_SYS_ENA, 0); | ||
1966 | |||
1967 | snd_soc_update_bits(codec, WM8904_FLL_CONTROL_1, | ||
1968 | WM8904_FLL_OSC_ENA | WM8904_FLL_ENA, 0); | ||
1969 | |||
1970 | goto out; | ||
1971 | } | ||
1972 | |||
1973 | /* Validate the FLL ID */ | ||
1974 | switch (source) { | ||
1975 | case WM8904_FLL_MCLK: | ||
1976 | case WM8904_FLL_LRCLK: | ||
1977 | case WM8904_FLL_BCLK: | ||
1978 | ret = fll_factors(&fll_div, Fref, Fout); | ||
1979 | if (ret != 0) | ||
1980 | return ret; | ||
1981 | break; | ||
1982 | |||
1983 | case WM8904_FLL_FREE_RUNNING: | ||
1984 | dev_dbg(codec->dev, "Using free running FLL\n"); | ||
1985 | /* Force 12MHz and output/4 for now */ | ||
1986 | Fout = 12000000; | ||
1987 | Fref = 12000000; | ||
1988 | |||
1989 | memset(&fll_div, 0, sizeof(fll_div)); | ||
1990 | fll_div.fll_outdiv = 3; | ||
1991 | break; | ||
1992 | |||
1993 | default: | ||
1994 | dev_err(codec->dev, "Unknown FLL ID %d\n", fll_id); | ||
1995 | return -EINVAL; | ||
1996 | } | ||
1997 | |||
1998 | /* Save current state then disable the FLL and SYSCLK to avoid | ||
1999 | * misclocking */ | ||
2000 | fll1 = snd_soc_read(codec, WM8904_FLL_CONTROL_1); | ||
2001 | snd_soc_update_bits(codec, WM8904_CLOCK_RATES_2, | ||
2002 | WM8904_CLK_SYS_ENA, 0); | ||
2003 | snd_soc_update_bits(codec, WM8904_FLL_CONTROL_1, | ||
2004 | WM8904_FLL_OSC_ENA | WM8904_FLL_ENA, 0); | ||
2005 | |||
2006 | /* Unlock forced oscilator control to switch it on/off */ | ||
2007 | snd_soc_update_bits(codec, WM8904_CONTROL_INTERFACE_TEST_1, | ||
2008 | WM8904_USER_KEY, WM8904_USER_KEY); | ||
2009 | |||
2010 | if (fll_id == WM8904_FLL_FREE_RUNNING) { | ||
2011 | val = WM8904_FLL_FRC_NCO; | ||
2012 | } else { | ||
2013 | val = 0; | ||
2014 | } | ||
2015 | |||
2016 | snd_soc_update_bits(codec, WM8904_FLL_NCO_TEST_1, WM8904_FLL_FRC_NCO, | ||
2017 | val); | ||
2018 | snd_soc_update_bits(codec, WM8904_CONTROL_INTERFACE_TEST_1, | ||
2019 | WM8904_USER_KEY, 0); | ||
2020 | |||
2021 | switch (fll_id) { | ||
2022 | case WM8904_FLL_MCLK: | ||
2023 | snd_soc_update_bits(codec, WM8904_FLL_CONTROL_5, | ||
2024 | WM8904_FLL_CLK_REF_SRC_MASK, 0); | ||
2025 | break; | ||
2026 | |||
2027 | case WM8904_FLL_LRCLK: | ||
2028 | snd_soc_update_bits(codec, WM8904_FLL_CONTROL_5, | ||
2029 | WM8904_FLL_CLK_REF_SRC_MASK, 1); | ||
2030 | break; | ||
2031 | |||
2032 | case WM8904_FLL_BCLK: | ||
2033 | snd_soc_update_bits(codec, WM8904_FLL_CONTROL_5, | ||
2034 | WM8904_FLL_CLK_REF_SRC_MASK, 2); | ||
2035 | break; | ||
2036 | } | ||
2037 | |||
2038 | if (fll_div.k) | ||
2039 | val = WM8904_FLL_FRACN_ENA; | ||
2040 | else | ||
2041 | val = 0; | ||
2042 | snd_soc_update_bits(codec, WM8904_FLL_CONTROL_1, | ||
2043 | WM8904_FLL_FRACN_ENA, val); | ||
2044 | |||
2045 | snd_soc_update_bits(codec, WM8904_FLL_CONTROL_2, | ||
2046 | WM8904_FLL_OUTDIV_MASK | WM8904_FLL_FRATIO_MASK, | ||
2047 | (fll_div.fll_outdiv << WM8904_FLL_OUTDIV_SHIFT) | | ||
2048 | (fll_div.fll_fratio << WM8904_FLL_FRATIO_SHIFT)); | ||
2049 | |||
2050 | snd_soc_write(codec, WM8904_FLL_CONTROL_3, fll_div.k); | ||
2051 | |||
2052 | snd_soc_update_bits(codec, WM8904_FLL_CONTROL_4, WM8904_FLL_N_MASK, | ||
2053 | fll_div.n << WM8904_FLL_N_SHIFT); | ||
2054 | |||
2055 | snd_soc_update_bits(codec, WM8904_FLL_CONTROL_5, | ||
2056 | WM8904_FLL_CLK_REF_DIV_MASK, | ||
2057 | fll_div.fll_clk_ref_div | ||
2058 | << WM8904_FLL_CLK_REF_DIV_SHIFT); | ||
2059 | |||
2060 | dev_dbg(codec->dev, "FLL configured for %dHz->%dHz\n", Fref, Fout); | ||
2061 | |||
2062 | wm8904->fll_fref = Fref; | ||
2063 | wm8904->fll_fout = Fout; | ||
2064 | wm8904->fll_src = source; | ||
2065 | |||
2066 | /* Enable the FLL if it was previously active */ | ||
2067 | snd_soc_update_bits(codec, WM8904_FLL_CONTROL_1, | ||
2068 | WM8904_FLL_OSC_ENA, fll1); | ||
2069 | snd_soc_update_bits(codec, WM8904_FLL_CONTROL_1, | ||
2070 | WM8904_FLL_ENA, fll1); | ||
2071 | |||
2072 | out: | ||
2073 | /* Reenable SYSCLK if it was previously active */ | ||
2074 | snd_soc_update_bits(codec, WM8904_CLOCK_RATES_2, | ||
2075 | WM8904_CLK_SYS_ENA, clock2); | ||
2076 | |||
2077 | return 0; | ||
2078 | } | ||
2079 | |||
2080 | static int wm8904_digital_mute(struct snd_soc_dai *codec_dai, int mute) | ||
2081 | { | ||
2082 | struct snd_soc_codec *codec = codec_dai->codec; | ||
2083 | int val; | ||
2084 | |||
2085 | if (mute) | ||
2086 | val = WM8904_DAC_MUTE; | ||
2087 | else | ||
2088 | val = 0; | ||
2089 | |||
2090 | snd_soc_update_bits(codec, WM8904_DAC_DIGITAL_1, WM8904_DAC_MUTE, val); | ||
2091 | |||
2092 | return 0; | ||
2093 | } | ||
2094 | |||
2095 | static void wm8904_sync_cache(struct snd_soc_codec *codec) | ||
2096 | { | ||
2097 | struct wm8904_priv *wm8904 = codec->private_data; | ||
2098 | int i; | ||
2099 | |||
2100 | if (!codec->cache_sync) | ||
2101 | return; | ||
2102 | |||
2103 | codec->cache_only = 0; | ||
2104 | |||
2105 | /* Sync back cached values if they're different from the | ||
2106 | * hardware default. | ||
2107 | */ | ||
2108 | for (i = 1; i < ARRAY_SIZE(wm8904->reg_cache); i++) { | ||
2109 | if (!wm8904_access[i].writable) | ||
2110 | continue; | ||
2111 | |||
2112 | if (wm8904->reg_cache[i] == wm8904_reg[i]) | ||
2113 | continue; | ||
2114 | |||
2115 | snd_soc_write(codec, i, wm8904->reg_cache[i]); | ||
2116 | } | ||
2117 | |||
2118 | codec->cache_sync = 0; | ||
2119 | } | ||
2120 | |||
2121 | static int wm8904_set_bias_level(struct snd_soc_codec *codec, | ||
2122 | enum snd_soc_bias_level level) | ||
2123 | { | ||
2124 | struct wm8904_priv *wm8904 = codec->private_data; | ||
2125 | int ret; | ||
2126 | |||
2127 | switch (level) { | ||
2128 | case SND_SOC_BIAS_ON: | ||
2129 | break; | ||
2130 | |||
2131 | case SND_SOC_BIAS_PREPARE: | ||
2132 | /* VMID resistance 2*50k */ | ||
2133 | snd_soc_update_bits(codec, WM8904_VMID_CONTROL_0, | ||
2134 | WM8904_VMID_RES_MASK, | ||
2135 | 0x1 << WM8904_VMID_RES_SHIFT); | ||
2136 | |||
2137 | /* Normal bias current */ | ||
2138 | snd_soc_update_bits(codec, WM8904_BIAS_CONTROL_0, | ||
2139 | WM8904_ISEL_MASK, 2 << WM8904_ISEL_SHIFT); | ||
2140 | break; | ||
2141 | |||
2142 | case SND_SOC_BIAS_STANDBY: | ||
2143 | if (codec->bias_level == SND_SOC_BIAS_OFF) { | ||
2144 | ret = regulator_bulk_enable(ARRAY_SIZE(wm8904->supplies), | ||
2145 | wm8904->supplies); | ||
2146 | if (ret != 0) { | ||
2147 | dev_err(codec->dev, | ||
2148 | "Failed to enable supplies: %d\n", | ||
2149 | ret); | ||
2150 | return ret; | ||
2151 | } | ||
2152 | |||
2153 | wm8904_sync_cache(codec); | ||
2154 | |||
2155 | /* Enable bias */ | ||
2156 | snd_soc_update_bits(codec, WM8904_BIAS_CONTROL_0, | ||
2157 | WM8904_BIAS_ENA, WM8904_BIAS_ENA); | ||
2158 | |||
2159 | /* Enable VMID, VMID buffering, 2*5k resistance */ | ||
2160 | snd_soc_update_bits(codec, WM8904_VMID_CONTROL_0, | ||
2161 | WM8904_VMID_ENA | | ||
2162 | WM8904_VMID_RES_MASK, | ||
2163 | WM8904_VMID_ENA | | ||
2164 | 0x3 << WM8904_VMID_RES_SHIFT); | ||
2165 | |||
2166 | /* Let VMID ramp */ | ||
2167 | msleep(1); | ||
2168 | } | ||
2169 | |||
2170 | /* Maintain VMID with 2*250k */ | ||
2171 | snd_soc_update_bits(codec, WM8904_VMID_CONTROL_0, | ||
2172 | WM8904_VMID_RES_MASK, | ||
2173 | 0x2 << WM8904_VMID_RES_SHIFT); | ||
2174 | |||
2175 | /* Bias current *0.5 */ | ||
2176 | snd_soc_update_bits(codec, WM8904_BIAS_CONTROL_0, | ||
2177 | WM8904_ISEL_MASK, 0); | ||
2178 | break; | ||
2179 | |||
2180 | case SND_SOC_BIAS_OFF: | ||
2181 | /* Turn off VMID */ | ||
2182 | snd_soc_update_bits(codec, WM8904_VMID_CONTROL_0, | ||
2183 | WM8904_VMID_RES_MASK | WM8904_VMID_ENA, 0); | ||
2184 | |||
2185 | /* Stop bias generation */ | ||
2186 | snd_soc_update_bits(codec, WM8904_BIAS_CONTROL_0, | ||
2187 | WM8904_BIAS_ENA, 0); | ||
2188 | |||
2189 | #ifdef CONFIG_REGULATOR | ||
2190 | /* Post 2.6.34 we will be able to get a callback when | ||
2191 | * the regulators are disabled which we can use but | ||
2192 | * for now just assume that the power will be cut if | ||
2193 | * the regulator API is in use. | ||
2194 | */ | ||
2195 | codec->cache_sync = 1; | ||
2196 | #endif | ||
2197 | |||
2198 | regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies), | ||
2199 | wm8904->supplies); | ||
2200 | break; | ||
2201 | } | ||
2202 | codec->bias_level = level; | ||
2203 | return 0; | ||
2204 | } | ||
2205 | |||
2206 | #define WM8904_RATES SNDRV_PCM_RATE_8000_96000 | ||
2207 | |||
2208 | #define WM8904_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | ||
2209 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) | ||
2210 | |||
2211 | static struct snd_soc_dai_ops wm8904_dai_ops = { | ||
2212 | .set_sysclk = wm8904_set_sysclk, | ||
2213 | .set_fmt = wm8904_set_fmt, | ||
2214 | .set_tdm_slot = wm8904_set_tdm_slot, | ||
2215 | .set_pll = wm8904_set_fll, | ||
2216 | .hw_params = wm8904_hw_params, | ||
2217 | .digital_mute = wm8904_digital_mute, | ||
2218 | }; | ||
2219 | |||
2220 | struct snd_soc_dai wm8904_dai = { | ||
2221 | .name = "WM8904", | ||
2222 | .playback = { | ||
2223 | .stream_name = "Playback", | ||
2224 | .channels_min = 2, | ||
2225 | .channels_max = 2, | ||
2226 | .rates = WM8904_RATES, | ||
2227 | .formats = WM8904_FORMATS, | ||
2228 | }, | ||
2229 | .capture = { | ||
2230 | .stream_name = "Capture", | ||
2231 | .channels_min = 2, | ||
2232 | .channels_max = 2, | ||
2233 | .rates = WM8904_RATES, | ||
2234 | .formats = WM8904_FORMATS, | ||
2235 | }, | ||
2236 | .ops = &wm8904_dai_ops, | ||
2237 | .symmetric_rates = 1, | ||
2238 | }; | ||
2239 | EXPORT_SYMBOL_GPL(wm8904_dai); | ||
2240 | |||
2241 | #ifdef CONFIG_PM | ||
2242 | static int wm8904_suspend(struct platform_device *pdev, pm_message_t state) | ||
2243 | { | ||
2244 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
2245 | struct snd_soc_codec *codec = socdev->card->codec; | ||
2246 | |||
2247 | wm8904_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
2248 | |||
2249 | return 0; | ||
2250 | } | ||
2251 | |||
2252 | static int wm8904_resume(struct platform_device *pdev) | ||
2253 | { | ||
2254 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
2255 | struct snd_soc_codec *codec = socdev->card->codec; | ||
2256 | |||
2257 | wm8904_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
2258 | |||
2259 | return 0; | ||
2260 | } | ||
2261 | #else | ||
2262 | #define wm8904_suspend NULL | ||
2263 | #define wm8904_resume NULL | ||
2264 | #endif | ||
2265 | |||
2266 | static void wm8904_handle_retune_mobile_pdata(struct wm8904_priv *wm8904) | ||
2267 | { | ||
2268 | struct snd_soc_codec *codec = &wm8904->codec; | ||
2269 | struct wm8904_pdata *pdata = wm8904->pdata; | ||
2270 | struct snd_kcontrol_new control = | ||
2271 | SOC_ENUM_EXT("EQ Mode", | ||
2272 | wm8904->retune_mobile_enum, | ||
2273 | wm8904_get_retune_mobile_enum, | ||
2274 | wm8904_put_retune_mobile_enum); | ||
2275 | int ret, i, j; | ||
2276 | const char **t; | ||
2277 | |||
2278 | /* We need an array of texts for the enum API but the number | ||
2279 | * of texts is likely to be less than the number of | ||
2280 | * configurations due to the sample rate dependency of the | ||
2281 | * configurations. */ | ||
2282 | wm8904->num_retune_mobile_texts = 0; | ||
2283 | wm8904->retune_mobile_texts = NULL; | ||
2284 | for (i = 0; i < pdata->num_retune_mobile_cfgs; i++) { | ||
2285 | for (j = 0; j < wm8904->num_retune_mobile_texts; j++) { | ||
2286 | if (strcmp(pdata->retune_mobile_cfgs[i].name, | ||
2287 | wm8904->retune_mobile_texts[j]) == 0) | ||
2288 | break; | ||
2289 | } | ||
2290 | |||
2291 | if (j != wm8904->num_retune_mobile_texts) | ||
2292 | continue; | ||
2293 | |||
2294 | /* Expand the array... */ | ||
2295 | t = krealloc(wm8904->retune_mobile_texts, | ||
2296 | sizeof(char *) * | ||
2297 | (wm8904->num_retune_mobile_texts + 1), | ||
2298 | GFP_KERNEL); | ||
2299 | if (t == NULL) | ||
2300 | continue; | ||
2301 | |||
2302 | /* ...store the new entry... */ | ||
2303 | t[wm8904->num_retune_mobile_texts] = | ||
2304 | pdata->retune_mobile_cfgs[i].name; | ||
2305 | |||
2306 | /* ...and remember the new version. */ | ||
2307 | wm8904->num_retune_mobile_texts++; | ||
2308 | wm8904->retune_mobile_texts = t; | ||
2309 | } | ||
2310 | |||
2311 | dev_dbg(codec->dev, "Allocated %d unique ReTune Mobile names\n", | ||
2312 | wm8904->num_retune_mobile_texts); | ||
2313 | |||
2314 | wm8904->retune_mobile_enum.max = wm8904->num_retune_mobile_texts; | ||
2315 | wm8904->retune_mobile_enum.texts = wm8904->retune_mobile_texts; | ||
2316 | |||
2317 | ret = snd_soc_add_controls(&wm8904->codec, &control, 1); | ||
2318 | if (ret != 0) | ||
2319 | dev_err(wm8904->codec.dev, | ||
2320 | "Failed to add ReTune Mobile control: %d\n", ret); | ||
2321 | } | ||
2322 | |||
2323 | static void wm8904_handle_pdata(struct wm8904_priv *wm8904) | ||
2324 | { | ||
2325 | struct snd_soc_codec *codec = &wm8904->codec; | ||
2326 | struct wm8904_pdata *pdata = wm8904->pdata; | ||
2327 | int ret, i; | ||
2328 | |||
2329 | if (!pdata) { | ||
2330 | snd_soc_add_controls(&wm8904->codec, wm8904_eq_controls, | ||
2331 | ARRAY_SIZE(wm8904_eq_controls)); | ||
2332 | return; | ||
2333 | } | ||
2334 | |||
2335 | dev_dbg(codec->dev, "%d DRC configurations\n", pdata->num_drc_cfgs); | ||
2336 | |||
2337 | if (pdata->num_drc_cfgs) { | ||
2338 | struct snd_kcontrol_new control = | ||
2339 | SOC_ENUM_EXT("DRC Mode", wm8904->drc_enum, | ||
2340 | wm8904_get_drc_enum, wm8904_put_drc_enum); | ||
2341 | |||
2342 | /* We need an array of texts for the enum API */ | ||
2343 | wm8904->drc_texts = kmalloc(sizeof(char *) | ||
2344 | * pdata->num_drc_cfgs, GFP_KERNEL); | ||
2345 | if (!wm8904->drc_texts) { | ||
2346 | dev_err(wm8904->codec.dev, | ||
2347 | "Failed to allocate %d DRC config texts\n", | ||
2348 | pdata->num_drc_cfgs); | ||
2349 | return; | ||
2350 | } | ||
2351 | |||
2352 | for (i = 0; i < pdata->num_drc_cfgs; i++) | ||
2353 | wm8904->drc_texts[i] = pdata->drc_cfgs[i].name; | ||
2354 | |||
2355 | wm8904->drc_enum.max = pdata->num_drc_cfgs; | ||
2356 | wm8904->drc_enum.texts = wm8904->drc_texts; | ||
2357 | |||
2358 | ret = snd_soc_add_controls(&wm8904->codec, &control, 1); | ||
2359 | if (ret != 0) | ||
2360 | dev_err(wm8904->codec.dev, | ||
2361 | "Failed to add DRC mode control: %d\n", ret); | ||
2362 | |||
2363 | wm8904_set_drc(codec); | ||
2364 | } | ||
2365 | |||
2366 | dev_dbg(codec->dev, "%d ReTune Mobile configurations\n", | ||
2367 | pdata->num_retune_mobile_cfgs); | ||
2368 | |||
2369 | if (pdata->num_retune_mobile_cfgs) | ||
2370 | wm8904_handle_retune_mobile_pdata(wm8904); | ||
2371 | else | ||
2372 | snd_soc_add_controls(&wm8904->codec, wm8904_eq_controls, | ||
2373 | ARRAY_SIZE(wm8904_eq_controls)); | ||
2374 | } | ||
2375 | |||
2376 | static int wm8904_probe(struct platform_device *pdev) | ||
2377 | { | ||
2378 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
2379 | struct snd_soc_codec *codec; | ||
2380 | int ret = 0; | ||
2381 | |||
2382 | if (wm8904_codec == NULL) { | ||
2383 | dev_err(&pdev->dev, "Codec device not registered\n"); | ||
2384 | return -ENODEV; | ||
2385 | } | ||
2386 | |||
2387 | socdev->card->codec = wm8904_codec; | ||
2388 | codec = wm8904_codec; | ||
2389 | |||
2390 | /* register pcms */ | ||
2391 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
2392 | if (ret < 0) { | ||
2393 | dev_err(codec->dev, "failed to create pcms: %d\n", ret); | ||
2394 | goto pcm_err; | ||
2395 | } | ||
2396 | |||
2397 | wm8904_handle_pdata(codec->private_data); | ||
2398 | |||
2399 | wm8904_add_widgets(codec); | ||
2400 | |||
2401 | return ret; | ||
2402 | |||
2403 | pcm_err: | ||
2404 | return ret; | ||
2405 | } | ||
2406 | |||
2407 | static int wm8904_remove(struct platform_device *pdev) | ||
2408 | { | ||
2409 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
2410 | |||
2411 | snd_soc_free_pcms(socdev); | ||
2412 | snd_soc_dapm_free(socdev); | ||
2413 | |||
2414 | return 0; | ||
2415 | } | ||
2416 | |||
2417 | struct snd_soc_codec_device soc_codec_dev_wm8904 = { | ||
2418 | .probe = wm8904_probe, | ||
2419 | .remove = wm8904_remove, | ||
2420 | .suspend = wm8904_suspend, | ||
2421 | .resume = wm8904_resume, | ||
2422 | }; | ||
2423 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8904); | ||
2424 | |||
2425 | static int wm8904_register(struct wm8904_priv *wm8904, | ||
2426 | enum snd_soc_control_type control) | ||
2427 | { | ||
2428 | int ret; | ||
2429 | struct snd_soc_codec *codec = &wm8904->codec; | ||
2430 | int i; | ||
2431 | |||
2432 | if (wm8904_codec) { | ||
2433 | dev_err(codec->dev, "Another WM8904 is registered\n"); | ||
2434 | return -EINVAL; | ||
2435 | } | ||
2436 | |||
2437 | mutex_init(&codec->mutex); | ||
2438 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
2439 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
2440 | |||
2441 | codec->private_data = wm8904; | ||
2442 | codec->name = "WM8904"; | ||
2443 | codec->owner = THIS_MODULE; | ||
2444 | codec->bias_level = SND_SOC_BIAS_OFF; | ||
2445 | codec->set_bias_level = wm8904_set_bias_level; | ||
2446 | codec->dai = &wm8904_dai; | ||
2447 | codec->num_dai = 1; | ||
2448 | codec->reg_cache_size = WM8904_MAX_REGISTER; | ||
2449 | codec->reg_cache = &wm8904->reg_cache; | ||
2450 | codec->volatile_register = wm8904_volatile_register; | ||
2451 | codec->cache_sync = 1; | ||
2452 | codec->idle_bias_off = 1; | ||
2453 | |||
2454 | switch (wm8904->devtype) { | ||
2455 | case WM8904: | ||
2456 | break; | ||
2457 | case WM8912: | ||
2458 | memset(&wm8904_dai.capture, 0, sizeof(wm8904_dai.capture)); | ||
2459 | break; | ||
2460 | default: | ||
2461 | dev_err(codec->dev, "Unknown device type %d\n", | ||
2462 | wm8904->devtype); | ||
2463 | return -EINVAL; | ||
2464 | } | ||
2465 | |||
2466 | memcpy(codec->reg_cache, wm8904_reg, sizeof(wm8904_reg)); | ||
2467 | |||
2468 | ret = snd_soc_codec_set_cache_io(codec, 8, 16, control); | ||
2469 | if (ret != 0) { | ||
2470 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); | ||
2471 | goto err; | ||
2472 | } | ||
2473 | |||
2474 | for (i = 0; i < ARRAY_SIZE(wm8904->supplies); i++) | ||
2475 | wm8904->supplies[i].supply = wm8904_supply_names[i]; | ||
2476 | |||
2477 | ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8904->supplies), | ||
2478 | wm8904->supplies); | ||
2479 | if (ret != 0) { | ||
2480 | dev_err(codec->dev, "Failed to request supplies: %d\n", ret); | ||
2481 | goto err; | ||
2482 | } | ||
2483 | |||
2484 | ret = regulator_bulk_enable(ARRAY_SIZE(wm8904->supplies), | ||
2485 | wm8904->supplies); | ||
2486 | if (ret != 0) { | ||
2487 | dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); | ||
2488 | goto err_get; | ||
2489 | } | ||
2490 | |||
2491 | ret = snd_soc_read(codec, WM8904_SW_RESET_AND_ID); | ||
2492 | if (ret < 0) { | ||
2493 | dev_err(codec->dev, "Failed to read ID register\n"); | ||
2494 | goto err_enable; | ||
2495 | } | ||
2496 | if (ret != wm8904_reg[WM8904_SW_RESET_AND_ID]) { | ||
2497 | dev_err(codec->dev, "Device is not a WM8904, ID is %x\n", ret); | ||
2498 | ret = -EINVAL; | ||
2499 | goto err_enable; | ||
2500 | } | ||
2501 | |||
2502 | ret = snd_soc_read(codec, WM8904_REVISION); | ||
2503 | if (ret < 0) { | ||
2504 | dev_err(codec->dev, "Failed to read device revision: %d\n", | ||
2505 | ret); | ||
2506 | goto err_enable; | ||
2507 | } | ||
2508 | dev_info(codec->dev, "revision %c\n", ret + 'A'); | ||
2509 | |||
2510 | ret = wm8904_reset(codec); | ||
2511 | if (ret < 0) { | ||
2512 | dev_err(codec->dev, "Failed to issue reset\n"); | ||
2513 | goto err_enable; | ||
2514 | } | ||
2515 | |||
2516 | wm8904_dai.dev = codec->dev; | ||
2517 | |||
2518 | /* Change some default settings - latch VU and enable ZC */ | ||
2519 | wm8904->reg_cache[WM8904_ADC_DIGITAL_VOLUME_LEFT] |= WM8904_ADC_VU; | ||
2520 | wm8904->reg_cache[WM8904_ADC_DIGITAL_VOLUME_RIGHT] |= WM8904_ADC_VU; | ||
2521 | wm8904->reg_cache[WM8904_DAC_DIGITAL_VOLUME_LEFT] |= WM8904_DAC_VU; | ||
2522 | wm8904->reg_cache[WM8904_DAC_DIGITAL_VOLUME_RIGHT] |= WM8904_DAC_VU; | ||
2523 | wm8904->reg_cache[WM8904_ANALOGUE_OUT1_LEFT] |= WM8904_HPOUT_VU | | ||
2524 | WM8904_HPOUTLZC; | ||
2525 | wm8904->reg_cache[WM8904_ANALOGUE_OUT1_RIGHT] |= WM8904_HPOUT_VU | | ||
2526 | WM8904_HPOUTRZC; | ||
2527 | wm8904->reg_cache[WM8904_ANALOGUE_OUT2_LEFT] |= WM8904_LINEOUT_VU | | ||
2528 | WM8904_LINEOUTLZC; | ||
2529 | wm8904->reg_cache[WM8904_ANALOGUE_OUT2_RIGHT] |= WM8904_LINEOUT_VU | | ||
2530 | WM8904_LINEOUTRZC; | ||
2531 | wm8904->reg_cache[WM8904_CLOCK_RATES_0] &= ~WM8904_SR_MODE; | ||
2532 | |||
2533 | /* Set Class W by default - this will be managed by the Class | ||
2534 | * G widget at runtime where bypass paths are available. | ||
2535 | */ | ||
2536 | wm8904->reg_cache[WM8904_CLASS_W_0] |= WM8904_CP_DYN_PWR; | ||
2537 | |||
2538 | /* Use normal bias source */ | ||
2539 | wm8904->reg_cache[WM8904_BIAS_CONTROL_0] &= ~WM8904_POBCTRL; | ||
2540 | |||
2541 | wm8904_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
2542 | |||
2543 | /* Bias level configuration will have done an extra enable */ | ||
2544 | regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies), wm8904->supplies); | ||
2545 | |||
2546 | wm8904_codec = codec; | ||
2547 | |||
2548 | ret = snd_soc_register_codec(codec); | ||
2549 | if (ret != 0) { | ||
2550 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); | ||
2551 | return ret; | ||
2552 | } | ||
2553 | |||
2554 | ret = snd_soc_register_dai(&wm8904_dai); | ||
2555 | if (ret != 0) { | ||
2556 | dev_err(codec->dev, "Failed to register DAI: %d\n", ret); | ||
2557 | snd_soc_unregister_codec(codec); | ||
2558 | return ret; | ||
2559 | } | ||
2560 | |||
2561 | return 0; | ||
2562 | |||
2563 | err_enable: | ||
2564 | regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies), wm8904->supplies); | ||
2565 | err_get: | ||
2566 | regulator_bulk_free(ARRAY_SIZE(wm8904->supplies), wm8904->supplies); | ||
2567 | err: | ||
2568 | kfree(wm8904); | ||
2569 | return ret; | ||
2570 | } | ||
2571 | |||
2572 | static void wm8904_unregister(struct wm8904_priv *wm8904) | ||
2573 | { | ||
2574 | wm8904_set_bias_level(&wm8904->codec, SND_SOC_BIAS_OFF); | ||
2575 | regulator_bulk_free(ARRAY_SIZE(wm8904->supplies), wm8904->supplies); | ||
2576 | snd_soc_unregister_dai(&wm8904_dai); | ||
2577 | snd_soc_unregister_codec(&wm8904->codec); | ||
2578 | kfree(wm8904); | ||
2579 | wm8904_codec = NULL; | ||
2580 | } | ||
2581 | |||
2582 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
2583 | static __devinit int wm8904_i2c_probe(struct i2c_client *i2c, | ||
2584 | const struct i2c_device_id *id) | ||
2585 | { | ||
2586 | struct wm8904_priv *wm8904; | ||
2587 | struct snd_soc_codec *codec; | ||
2588 | |||
2589 | wm8904 = kzalloc(sizeof(struct wm8904_priv), GFP_KERNEL); | ||
2590 | if (wm8904 == NULL) | ||
2591 | return -ENOMEM; | ||
2592 | |||
2593 | codec = &wm8904->codec; | ||
2594 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
2595 | |||
2596 | wm8904->devtype = id->driver_data; | ||
2597 | |||
2598 | i2c_set_clientdata(i2c, wm8904); | ||
2599 | codec->control_data = i2c; | ||
2600 | wm8904->pdata = i2c->dev.platform_data; | ||
2601 | |||
2602 | codec->dev = &i2c->dev; | ||
2603 | |||
2604 | return wm8904_register(wm8904, SND_SOC_I2C); | ||
2605 | } | ||
2606 | |||
2607 | static __devexit int wm8904_i2c_remove(struct i2c_client *client) | ||
2608 | { | ||
2609 | struct wm8904_priv *wm8904 = i2c_get_clientdata(client); | ||
2610 | wm8904_unregister(wm8904); | ||
2611 | return 0; | ||
2612 | } | ||
2613 | |||
2614 | static const struct i2c_device_id wm8904_i2c_id[] = { | ||
2615 | { "wm8904", WM8904 }, | ||
2616 | { "wm8912", WM8912 }, | ||
2617 | { } | ||
2618 | }; | ||
2619 | MODULE_DEVICE_TABLE(i2c, wm8904_i2c_id); | ||
2620 | |||
2621 | static struct i2c_driver wm8904_i2c_driver = { | ||
2622 | .driver = { | ||
2623 | .name = "WM8904", | ||
2624 | .owner = THIS_MODULE, | ||
2625 | }, | ||
2626 | .probe = wm8904_i2c_probe, | ||
2627 | .remove = __devexit_p(wm8904_i2c_remove), | ||
2628 | .id_table = wm8904_i2c_id, | ||
2629 | }; | ||
2630 | #endif | ||
2631 | |||
2632 | static int __init wm8904_modinit(void) | ||
2633 | { | ||
2634 | int ret; | ||
2635 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
2636 | ret = i2c_add_driver(&wm8904_i2c_driver); | ||
2637 | if (ret != 0) { | ||
2638 | printk(KERN_ERR "Failed to register WM8904 I2C driver: %d\n", | ||
2639 | ret); | ||
2640 | } | ||
2641 | #endif | ||
2642 | return 0; | ||
2643 | } | ||
2644 | module_init(wm8904_modinit); | ||
2645 | |||
2646 | static void __exit wm8904_exit(void) | ||
2647 | { | ||
2648 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
2649 | i2c_del_driver(&wm8904_i2c_driver); | ||
2650 | #endif | ||
2651 | } | ||
2652 | module_exit(wm8904_exit); | ||
2653 | |||
2654 | MODULE_DESCRIPTION("ASoC WM8904 driver"); | ||
2655 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); | ||
2656 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/wm8904.h b/sound/soc/codecs/wm8904.h new file mode 100644 index 000000000000..b68886df34e4 --- /dev/null +++ b/sound/soc/codecs/wm8904.h | |||
@@ -0,0 +1,1681 @@ | |||
1 | /* | ||
2 | * wm8904.h -- WM8904 ASoC driver | ||
3 | * | ||
4 | * Copyright 2009 Wolfson Microelectronics, plc | ||
5 | * | ||
6 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | ||
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 _WM8904_H | ||
14 | #define _WM8904_H | ||
15 | |||
16 | #define WM8904_CLK_MCLK 1 | ||
17 | #define WM8904_CLK_FLL 2 | ||
18 | |||
19 | #define WM8904_FLL_MCLK 1 | ||
20 | #define WM8904_FLL_BCLK 2 | ||
21 | #define WM8904_FLL_LRCLK 3 | ||
22 | #define WM8904_FLL_FREE_RUNNING 4 | ||
23 | |||
24 | extern struct snd_soc_dai wm8904_dai; | ||
25 | extern struct snd_soc_codec_device soc_codec_dev_wm8904; | ||
26 | |||
27 | /* | ||
28 | * Register values. | ||
29 | */ | ||
30 | #define WM8904_SW_RESET_AND_ID 0x00 | ||
31 | #define WM8904_REVISION 0x01 | ||
32 | #define WM8904_BIAS_CONTROL_0 0x04 | ||
33 | #define WM8904_VMID_CONTROL_0 0x05 | ||
34 | #define WM8904_MIC_BIAS_CONTROL_0 0x06 | ||
35 | #define WM8904_MIC_BIAS_CONTROL_1 0x07 | ||
36 | #define WM8904_ANALOGUE_DAC_0 0x08 | ||
37 | #define WM8904_MIC_FILTER_CONTROL 0x09 | ||
38 | #define WM8904_ANALOGUE_ADC_0 0x0A | ||
39 | #define WM8904_POWER_MANAGEMENT_0 0x0C | ||
40 | #define WM8904_POWER_MANAGEMENT_2 0x0E | ||
41 | #define WM8904_POWER_MANAGEMENT_3 0x0F | ||
42 | #define WM8904_POWER_MANAGEMENT_6 0x12 | ||
43 | #define WM8904_CLOCK_RATES_0 0x14 | ||
44 | #define WM8904_CLOCK_RATES_1 0x15 | ||
45 | #define WM8904_CLOCK_RATES_2 0x16 | ||
46 | #define WM8904_AUDIO_INTERFACE_0 0x18 | ||
47 | #define WM8904_AUDIO_INTERFACE_1 0x19 | ||
48 | #define WM8904_AUDIO_INTERFACE_2 0x1A | ||
49 | #define WM8904_AUDIO_INTERFACE_3 0x1B | ||
50 | #define WM8904_DAC_DIGITAL_VOLUME_LEFT 0x1E | ||
51 | #define WM8904_DAC_DIGITAL_VOLUME_RIGHT 0x1F | ||
52 | #define WM8904_DAC_DIGITAL_0 0x20 | ||
53 | #define WM8904_DAC_DIGITAL_1 0x21 | ||
54 | #define WM8904_ADC_DIGITAL_VOLUME_LEFT 0x24 | ||
55 | #define WM8904_ADC_DIGITAL_VOLUME_RIGHT 0x25 | ||
56 | #define WM8904_ADC_DIGITAL_0 0x26 | ||
57 | #define WM8904_DIGITAL_MICROPHONE_0 0x27 | ||
58 | #define WM8904_DRC_0 0x28 | ||
59 | #define WM8904_DRC_1 0x29 | ||
60 | #define WM8904_DRC_2 0x2A | ||
61 | #define WM8904_DRC_3 0x2B | ||
62 | #define WM8904_ANALOGUE_LEFT_INPUT_0 0x2C | ||
63 | #define WM8904_ANALOGUE_RIGHT_INPUT_0 0x2D | ||
64 | #define WM8904_ANALOGUE_LEFT_INPUT_1 0x2E | ||
65 | #define WM8904_ANALOGUE_RIGHT_INPUT_1 0x2F | ||
66 | #define WM8904_ANALOGUE_OUT1_LEFT 0x39 | ||
67 | #define WM8904_ANALOGUE_OUT1_RIGHT 0x3A | ||
68 | #define WM8904_ANALOGUE_OUT2_LEFT 0x3B | ||
69 | #define WM8904_ANALOGUE_OUT2_RIGHT 0x3C | ||
70 | #define WM8904_ANALOGUE_OUT12_ZC 0x3D | ||
71 | #define WM8904_DC_SERVO_0 0x43 | ||
72 | #define WM8904_DC_SERVO_1 0x44 | ||
73 | #define WM8904_DC_SERVO_2 0x45 | ||
74 | #define WM8904_DC_SERVO_4 0x47 | ||
75 | #define WM8904_DC_SERVO_5 0x48 | ||
76 | #define WM8904_DC_SERVO_6 0x49 | ||
77 | #define WM8904_DC_SERVO_7 0x4A | ||
78 | #define WM8904_DC_SERVO_8 0x4B | ||
79 | #define WM8904_DC_SERVO_9 0x4C | ||
80 | #define WM8904_DC_SERVO_READBACK_0 0x4D | ||
81 | #define WM8904_ANALOGUE_HP_0 0x5A | ||
82 | #define WM8904_ANALOGUE_LINEOUT_0 0x5E | ||
83 | #define WM8904_CHARGE_PUMP_0 0x62 | ||
84 | #define WM8904_CLASS_W_0 0x68 | ||
85 | #define WM8904_WRITE_SEQUENCER_0 0x6C | ||
86 | #define WM8904_WRITE_SEQUENCER_1 0x6D | ||
87 | #define WM8904_WRITE_SEQUENCER_2 0x6E | ||
88 | #define WM8904_WRITE_SEQUENCER_3 0x6F | ||
89 | #define WM8904_WRITE_SEQUENCER_4 0x70 | ||
90 | #define WM8904_FLL_CONTROL_1 0x74 | ||
91 | #define WM8904_FLL_CONTROL_2 0x75 | ||
92 | #define WM8904_FLL_CONTROL_3 0x76 | ||
93 | #define WM8904_FLL_CONTROL_4 0x77 | ||
94 | #define WM8904_FLL_CONTROL_5 0x78 | ||
95 | #define WM8904_GPIO_CONTROL_1 0x79 | ||
96 | #define WM8904_GPIO_CONTROL_2 0x7A | ||
97 | #define WM8904_GPIO_CONTROL_3 0x7B | ||
98 | #define WM8904_GPIO_CONTROL_4 0x7C | ||
99 | #define WM8904_DIGITAL_PULLS 0x7E | ||
100 | #define WM8904_INTERRUPT_STATUS 0x7F | ||
101 | #define WM8904_INTERRUPT_STATUS_MASK 0x80 | ||
102 | #define WM8904_INTERRUPT_POLARITY 0x81 | ||
103 | #define WM8904_INTERRUPT_DEBOUNCE 0x82 | ||
104 | #define WM8904_EQ1 0x86 | ||
105 | #define WM8904_EQ2 0x87 | ||
106 | #define WM8904_EQ3 0x88 | ||
107 | #define WM8904_EQ4 0x89 | ||
108 | #define WM8904_EQ5 0x8A | ||
109 | #define WM8904_EQ6 0x8B | ||
110 | #define WM8904_EQ7 0x8C | ||
111 | #define WM8904_EQ8 0x8D | ||
112 | #define WM8904_EQ9 0x8E | ||
113 | #define WM8904_EQ10 0x8F | ||
114 | #define WM8904_EQ11 0x90 | ||
115 | #define WM8904_EQ12 0x91 | ||
116 | #define WM8904_EQ13 0x92 | ||
117 | #define WM8904_EQ14 0x93 | ||
118 | #define WM8904_EQ15 0x94 | ||
119 | #define WM8904_EQ16 0x95 | ||
120 | #define WM8904_EQ17 0x96 | ||
121 | #define WM8904_EQ18 0x97 | ||
122 | #define WM8904_EQ19 0x98 | ||
123 | #define WM8904_EQ20 0x99 | ||
124 | #define WM8904_EQ21 0x9A | ||
125 | #define WM8904_EQ22 0x9B | ||
126 | #define WM8904_EQ23 0x9C | ||
127 | #define WM8904_EQ24 0x9D | ||
128 | #define WM8904_CONTROL_INTERFACE_TEST_1 0xA1 | ||
129 | #define WM8904_ANALOGUE_OUTPUT_BIAS_0 0xCC | ||
130 | #define WM8904_FLL_NCO_TEST_0 0xF7 | ||
131 | #define WM8904_FLL_NCO_TEST_1 0xF8 | ||
132 | |||
133 | #define WM8904_REGISTER_COUNT 101 | ||
134 | #define WM8904_MAX_REGISTER 0xF8 | ||
135 | |||
136 | /* | ||
137 | * Field Definitions. | ||
138 | */ | ||
139 | |||
140 | /* | ||
141 | * R0 (0x00) - SW Reset and ID | ||
142 | */ | ||
143 | #define WM8904_SW_RST_DEV_ID1_MASK 0xFFFF /* SW_RST_DEV_ID1 - [15:0] */ | ||
144 | #define WM8904_SW_RST_DEV_ID1_SHIFT 0 /* SW_RST_DEV_ID1 - [15:0] */ | ||
145 | #define WM8904_SW_RST_DEV_ID1_WIDTH 16 /* SW_RST_DEV_ID1 - [15:0] */ | ||
146 | |||
147 | /* | ||
148 | * R1 (0x01) - Revision | ||
149 | */ | ||
150 | #define WM8904_REVISION_MASK 0x000F /* REVISION - [3:0] */ | ||
151 | #define WM8904_REVISION_SHIFT 0 /* REVISION - [3:0] */ | ||
152 | #define WM8904_REVISION_WIDTH 16 /* REVISION - [3:0] */ | ||
153 | |||
154 | /* | ||
155 | * R4 (0x04) - Bias Control 0 | ||
156 | */ | ||
157 | #define WM8904_POBCTRL 0x0010 /* POBCTRL */ | ||
158 | #define WM8904_POBCTRL_MASK 0x0010 /* POBCTRL */ | ||
159 | #define WM8904_POBCTRL_SHIFT 4 /* POBCTRL */ | ||
160 | #define WM8904_POBCTRL_WIDTH 1 /* POBCTRL */ | ||
161 | #define WM8904_ISEL_MASK 0x000C /* ISEL - [3:2] */ | ||
162 | #define WM8904_ISEL_SHIFT 2 /* ISEL - [3:2] */ | ||
163 | #define WM8904_ISEL_WIDTH 2 /* ISEL - [3:2] */ | ||
164 | #define WM8904_STARTUP_BIAS_ENA 0x0002 /* STARTUP_BIAS_ENA */ | ||
165 | #define WM8904_STARTUP_BIAS_ENA_MASK 0x0002 /* STARTUP_BIAS_ENA */ | ||
166 | #define WM8904_STARTUP_BIAS_ENA_SHIFT 1 /* STARTUP_BIAS_ENA */ | ||
167 | #define WM8904_STARTUP_BIAS_ENA_WIDTH 1 /* STARTUP_BIAS_ENA */ | ||
168 | #define WM8904_BIAS_ENA 0x0001 /* BIAS_ENA */ | ||
169 | #define WM8904_BIAS_ENA_MASK 0x0001 /* BIAS_ENA */ | ||
170 | #define WM8904_BIAS_ENA_SHIFT 0 /* BIAS_ENA */ | ||
171 | #define WM8904_BIAS_ENA_WIDTH 1 /* BIAS_ENA */ | ||
172 | |||
173 | /* | ||
174 | * R5 (0x05) - VMID Control 0 | ||
175 | */ | ||
176 | #define WM8904_VMID_BUF_ENA 0x0040 /* VMID_BUF_ENA */ | ||
177 | #define WM8904_VMID_BUF_ENA_MASK 0x0040 /* VMID_BUF_ENA */ | ||
178 | #define WM8904_VMID_BUF_ENA_SHIFT 6 /* VMID_BUF_ENA */ | ||
179 | #define WM8904_VMID_BUF_ENA_WIDTH 1 /* VMID_BUF_ENA */ | ||
180 | #define WM8904_VMID_RES_MASK 0x0006 /* VMID_RES - [2:1] */ | ||
181 | #define WM8904_VMID_RES_SHIFT 1 /* VMID_RES - [2:1] */ | ||
182 | #define WM8904_VMID_RES_WIDTH 2 /* VMID_RES - [2:1] */ | ||
183 | #define WM8904_VMID_ENA 0x0001 /* VMID_ENA */ | ||
184 | #define WM8904_VMID_ENA_MASK 0x0001 /* VMID_ENA */ | ||
185 | #define WM8904_VMID_ENA_SHIFT 0 /* VMID_ENA */ | ||
186 | #define WM8904_VMID_ENA_WIDTH 1 /* VMID_ENA */ | ||
187 | |||
188 | /* | ||
189 | * R6 (0x06) - Mic Bias Control 0 | ||
190 | */ | ||
191 | #define WM8904_MICDET_THR_MASK 0x0070 /* MICDET_THR - [6:4] */ | ||
192 | #define WM8904_MICDET_THR_SHIFT 4 /* MICDET_THR - [6:4] */ | ||
193 | #define WM8904_MICDET_THR_WIDTH 3 /* MICDET_THR - [6:4] */ | ||
194 | #define WM8904_MICSHORT_THR_MASK 0x000C /* MICSHORT_THR - [3:2] */ | ||
195 | #define WM8904_MICSHORT_THR_SHIFT 2 /* MICSHORT_THR - [3:2] */ | ||
196 | #define WM8904_MICSHORT_THR_WIDTH 2 /* MICSHORT_THR - [3:2] */ | ||
197 | #define WM8904_MICDET_ENA 0x0002 /* MICDET_ENA */ | ||
198 | #define WM8904_MICDET_ENA_MASK 0x0002 /* MICDET_ENA */ | ||
199 | #define WM8904_MICDET_ENA_SHIFT 1 /* MICDET_ENA */ | ||
200 | #define WM8904_MICDET_ENA_WIDTH 1 /* MICDET_ENA */ | ||
201 | #define WM8904_MICBIAS_ENA 0x0001 /* MICBIAS_ENA */ | ||
202 | #define WM8904_MICBIAS_ENA_MASK 0x0001 /* MICBIAS_ENA */ | ||
203 | #define WM8904_MICBIAS_ENA_SHIFT 0 /* MICBIAS_ENA */ | ||
204 | #define WM8904_MICBIAS_ENA_WIDTH 1 /* MICBIAS_ENA */ | ||
205 | |||
206 | /* | ||
207 | * R7 (0x07) - Mic Bias Control 1 | ||
208 | */ | ||
209 | #define WM8904_MIC_DET_FILTER_ENA 0x8000 /* MIC_DET_FILTER_ENA */ | ||
210 | #define WM8904_MIC_DET_FILTER_ENA_MASK 0x8000 /* MIC_DET_FILTER_ENA */ | ||
211 | #define WM8904_MIC_DET_FILTER_ENA_SHIFT 15 /* MIC_DET_FILTER_ENA */ | ||
212 | #define WM8904_MIC_DET_FILTER_ENA_WIDTH 1 /* MIC_DET_FILTER_ENA */ | ||
213 | #define WM8904_MIC_SHORT_FILTER_ENA 0x4000 /* MIC_SHORT_FILTER_ENA */ | ||
214 | #define WM8904_MIC_SHORT_FILTER_ENA_MASK 0x4000 /* MIC_SHORT_FILTER_ENA */ | ||
215 | #define WM8904_MIC_SHORT_FILTER_ENA_SHIFT 14 /* MIC_SHORT_FILTER_ENA */ | ||
216 | #define WM8904_MIC_SHORT_FILTER_ENA_WIDTH 1 /* MIC_SHORT_FILTER_ENA */ | ||
217 | #define WM8904_MICBIAS_SEL_MASK 0x0007 /* MICBIAS_SEL - [2:0] */ | ||
218 | #define WM8904_MICBIAS_SEL_SHIFT 0 /* MICBIAS_SEL - [2:0] */ | ||
219 | #define WM8904_MICBIAS_SEL_WIDTH 3 /* MICBIAS_SEL - [2:0] */ | ||
220 | |||
221 | /* | ||
222 | * R8 (0x08) - Analogue DAC 0 | ||
223 | */ | ||
224 | #define WM8904_DAC_BIAS_SEL_MASK 0x0018 /* DAC_BIAS_SEL - [4:3] */ | ||
225 | #define WM8904_DAC_BIAS_SEL_SHIFT 3 /* DAC_BIAS_SEL - [4:3] */ | ||
226 | #define WM8904_DAC_BIAS_SEL_WIDTH 2 /* DAC_BIAS_SEL - [4:3] */ | ||
227 | #define WM8904_DAC_VMID_BIAS_SEL_MASK 0x0006 /* DAC_VMID_BIAS_SEL - [2:1] */ | ||
228 | #define WM8904_DAC_VMID_BIAS_SEL_SHIFT 1 /* DAC_VMID_BIAS_SEL - [2:1] */ | ||
229 | #define WM8904_DAC_VMID_BIAS_SEL_WIDTH 2 /* DAC_VMID_BIAS_SEL - [2:1] */ | ||
230 | |||
231 | /* | ||
232 | * R9 (0x09) - mic Filter Control | ||
233 | */ | ||
234 | #define WM8904_MIC_DET_SET_THRESHOLD_MASK 0xF000 /* MIC_DET_SET_THRESHOLD - [15:12] */ | ||
235 | #define WM8904_MIC_DET_SET_THRESHOLD_SHIFT 12 /* MIC_DET_SET_THRESHOLD - [15:12] */ | ||
236 | #define WM8904_MIC_DET_SET_THRESHOLD_WIDTH 4 /* MIC_DET_SET_THRESHOLD - [15:12] */ | ||
237 | #define WM8904_MIC_DET_RESET_THRESHOLD_MASK 0x0F00 /* MIC_DET_RESET_THRESHOLD - [11:8] */ | ||
238 | #define WM8904_MIC_DET_RESET_THRESHOLD_SHIFT 8 /* MIC_DET_RESET_THRESHOLD - [11:8] */ | ||
239 | #define WM8904_MIC_DET_RESET_THRESHOLD_WIDTH 4 /* MIC_DET_RESET_THRESHOLD - [11:8] */ | ||
240 | #define WM8904_MIC_SHORT_SET_THRESHOLD_MASK 0x00F0 /* MIC_SHORT_SET_THRESHOLD - [7:4] */ | ||
241 | #define WM8904_MIC_SHORT_SET_THRESHOLD_SHIFT 4 /* MIC_SHORT_SET_THRESHOLD - [7:4] */ | ||
242 | #define WM8904_MIC_SHORT_SET_THRESHOLD_WIDTH 4 /* MIC_SHORT_SET_THRESHOLD - [7:4] */ | ||
243 | #define WM8904_MIC_SHORT_RESET_THRESHOLD_MASK 0x000F /* MIC_SHORT_RESET_THRESHOLD - [3:0] */ | ||
244 | #define WM8904_MIC_SHORT_RESET_THRESHOLD_SHIFT 0 /* MIC_SHORT_RESET_THRESHOLD - [3:0] */ | ||
245 | #define WM8904_MIC_SHORT_RESET_THRESHOLD_WIDTH 4 /* MIC_SHORT_RESET_THRESHOLD - [3:0] */ | ||
246 | |||
247 | /* | ||
248 | * R10 (0x0A) - Analogue ADC 0 | ||
249 | */ | ||
250 | #define WM8904_ADC_OSR128 0x0001 /* ADC_OSR128 */ | ||
251 | #define WM8904_ADC_OSR128_MASK 0x0001 /* ADC_OSR128 */ | ||
252 | #define WM8904_ADC_OSR128_SHIFT 0 /* ADC_OSR128 */ | ||
253 | #define WM8904_ADC_OSR128_WIDTH 1 /* ADC_OSR128 */ | ||
254 | |||
255 | /* | ||
256 | * R12 (0x0C) - Power Management 0 | ||
257 | */ | ||
258 | #define WM8904_INL_ENA 0x0002 /* INL_ENA */ | ||
259 | #define WM8904_INL_ENA_MASK 0x0002 /* INL_ENA */ | ||
260 | #define WM8904_INL_ENA_SHIFT 1 /* INL_ENA */ | ||
261 | #define WM8904_INL_ENA_WIDTH 1 /* INL_ENA */ | ||
262 | #define WM8904_INR_ENA 0x0001 /* INR_ENA */ | ||
263 | #define WM8904_INR_ENA_MASK 0x0001 /* INR_ENA */ | ||
264 | #define WM8904_INR_ENA_SHIFT 0 /* INR_ENA */ | ||
265 | #define WM8904_INR_ENA_WIDTH 1 /* INR_ENA */ | ||
266 | |||
267 | /* | ||
268 | * R14 (0x0E) - Power Management 2 | ||
269 | */ | ||
270 | #define WM8904_HPL_PGA_ENA 0x0002 /* HPL_PGA_ENA */ | ||
271 | #define WM8904_HPL_PGA_ENA_MASK 0x0002 /* HPL_PGA_ENA */ | ||
272 | #define WM8904_HPL_PGA_ENA_SHIFT 1 /* HPL_PGA_ENA */ | ||
273 | #define WM8904_HPL_PGA_ENA_WIDTH 1 /* HPL_PGA_ENA */ | ||
274 | #define WM8904_HPR_PGA_ENA 0x0001 /* HPR_PGA_ENA */ | ||
275 | #define WM8904_HPR_PGA_ENA_MASK 0x0001 /* HPR_PGA_ENA */ | ||
276 | #define WM8904_HPR_PGA_ENA_SHIFT 0 /* HPR_PGA_ENA */ | ||
277 | #define WM8904_HPR_PGA_ENA_WIDTH 1 /* HPR_PGA_ENA */ | ||
278 | |||
279 | /* | ||
280 | * R15 (0x0F) - Power Management 3 | ||
281 | */ | ||
282 | #define WM8904_LINEOUTL_PGA_ENA 0x0002 /* LINEOUTL_PGA_ENA */ | ||
283 | #define WM8904_LINEOUTL_PGA_ENA_MASK 0x0002 /* LINEOUTL_PGA_ENA */ | ||
284 | #define WM8904_LINEOUTL_PGA_ENA_SHIFT 1 /* LINEOUTL_PGA_ENA */ | ||
285 | #define WM8904_LINEOUTL_PGA_ENA_WIDTH 1 /* LINEOUTL_PGA_ENA */ | ||
286 | #define WM8904_LINEOUTR_PGA_ENA 0x0001 /* LINEOUTR_PGA_ENA */ | ||
287 | #define WM8904_LINEOUTR_PGA_ENA_MASK 0x0001 /* LINEOUTR_PGA_ENA */ | ||
288 | #define WM8904_LINEOUTR_PGA_ENA_SHIFT 0 /* LINEOUTR_PGA_ENA */ | ||
289 | #define WM8904_LINEOUTR_PGA_ENA_WIDTH 1 /* LINEOUTR_PGA_ENA */ | ||
290 | |||
291 | /* | ||
292 | * R18 (0x12) - Power Management 6 | ||
293 | */ | ||
294 | #define WM8904_DACL_ENA 0x0008 /* DACL_ENA */ | ||
295 | #define WM8904_DACL_ENA_MASK 0x0008 /* DACL_ENA */ | ||
296 | #define WM8904_DACL_ENA_SHIFT 3 /* DACL_ENA */ | ||
297 | #define WM8904_DACL_ENA_WIDTH 1 /* DACL_ENA */ | ||
298 | #define WM8904_DACR_ENA 0x0004 /* DACR_ENA */ | ||
299 | #define WM8904_DACR_ENA_MASK 0x0004 /* DACR_ENA */ | ||
300 | #define WM8904_DACR_ENA_SHIFT 2 /* DACR_ENA */ | ||
301 | #define WM8904_DACR_ENA_WIDTH 1 /* DACR_ENA */ | ||
302 | #define WM8904_ADCL_ENA 0x0002 /* ADCL_ENA */ | ||
303 | #define WM8904_ADCL_ENA_MASK 0x0002 /* ADCL_ENA */ | ||
304 | #define WM8904_ADCL_ENA_SHIFT 1 /* ADCL_ENA */ | ||
305 | #define WM8904_ADCL_ENA_WIDTH 1 /* ADCL_ENA */ | ||
306 | #define WM8904_ADCR_ENA 0x0001 /* ADCR_ENA */ | ||
307 | #define WM8904_ADCR_ENA_MASK 0x0001 /* ADCR_ENA */ | ||
308 | #define WM8904_ADCR_ENA_SHIFT 0 /* ADCR_ENA */ | ||
309 | #define WM8904_ADCR_ENA_WIDTH 1 /* ADCR_ENA */ | ||
310 | |||
311 | /* | ||
312 | * R20 (0x14) - Clock Rates 0 | ||
313 | */ | ||
314 | #define WM8904_TOCLK_RATE_DIV16 0x4000 /* TOCLK_RATE_DIV16 */ | ||
315 | #define WM8904_TOCLK_RATE_DIV16_MASK 0x4000 /* TOCLK_RATE_DIV16 */ | ||
316 | #define WM8904_TOCLK_RATE_DIV16_SHIFT 14 /* TOCLK_RATE_DIV16 */ | ||
317 | #define WM8904_TOCLK_RATE_DIV16_WIDTH 1 /* TOCLK_RATE_DIV16 */ | ||
318 | #define WM8904_TOCLK_RATE_X4 0x2000 /* TOCLK_RATE_X4 */ | ||
319 | #define WM8904_TOCLK_RATE_X4_MASK 0x2000 /* TOCLK_RATE_X4 */ | ||
320 | #define WM8904_TOCLK_RATE_X4_SHIFT 13 /* TOCLK_RATE_X4 */ | ||
321 | #define WM8904_TOCLK_RATE_X4_WIDTH 1 /* TOCLK_RATE_X4 */ | ||
322 | #define WM8904_SR_MODE 0x1000 /* SR_MODE */ | ||
323 | #define WM8904_SR_MODE_MASK 0x1000 /* SR_MODE */ | ||
324 | #define WM8904_SR_MODE_SHIFT 12 /* SR_MODE */ | ||
325 | #define WM8904_SR_MODE_WIDTH 1 /* SR_MODE */ | ||
326 | #define WM8904_MCLK_DIV 0x0001 /* MCLK_DIV */ | ||
327 | #define WM8904_MCLK_DIV_MASK 0x0001 /* MCLK_DIV */ | ||
328 | #define WM8904_MCLK_DIV_SHIFT 0 /* MCLK_DIV */ | ||
329 | #define WM8904_MCLK_DIV_WIDTH 1 /* MCLK_DIV */ | ||
330 | |||
331 | /* | ||
332 | * R21 (0x15) - Clock Rates 1 | ||
333 | */ | ||
334 | #define WM8904_CLK_SYS_RATE_MASK 0x3C00 /* CLK_SYS_RATE - [13:10] */ | ||
335 | #define WM8904_CLK_SYS_RATE_SHIFT 10 /* CLK_SYS_RATE - [13:10] */ | ||
336 | #define WM8904_CLK_SYS_RATE_WIDTH 4 /* CLK_SYS_RATE - [13:10] */ | ||
337 | #define WM8904_SAMPLE_RATE_MASK 0x0007 /* SAMPLE_RATE - [2:0] */ | ||
338 | #define WM8904_SAMPLE_RATE_SHIFT 0 /* SAMPLE_RATE - [2:0] */ | ||
339 | #define WM8904_SAMPLE_RATE_WIDTH 3 /* SAMPLE_RATE - [2:0] */ | ||
340 | |||
341 | /* | ||
342 | * R22 (0x16) - Clock Rates 2 | ||
343 | */ | ||
344 | #define WM8904_MCLK_INV 0x8000 /* MCLK_INV */ | ||
345 | #define WM8904_MCLK_INV_MASK 0x8000 /* MCLK_INV */ | ||
346 | #define WM8904_MCLK_INV_SHIFT 15 /* MCLK_INV */ | ||
347 | #define WM8904_MCLK_INV_WIDTH 1 /* MCLK_INV */ | ||
348 | #define WM8904_SYSCLK_SRC 0x4000 /* SYSCLK_SRC */ | ||
349 | #define WM8904_SYSCLK_SRC_MASK 0x4000 /* SYSCLK_SRC */ | ||
350 | #define WM8904_SYSCLK_SRC_SHIFT 14 /* SYSCLK_SRC */ | ||
351 | #define WM8904_SYSCLK_SRC_WIDTH 1 /* SYSCLK_SRC */ | ||
352 | #define WM8904_TOCLK_RATE 0x1000 /* TOCLK_RATE */ | ||
353 | #define WM8904_TOCLK_RATE_MASK 0x1000 /* TOCLK_RATE */ | ||
354 | #define WM8904_TOCLK_RATE_SHIFT 12 /* TOCLK_RATE */ | ||
355 | #define WM8904_TOCLK_RATE_WIDTH 1 /* TOCLK_RATE */ | ||
356 | #define WM8904_OPCLK_ENA 0x0008 /* OPCLK_ENA */ | ||
357 | #define WM8904_OPCLK_ENA_MASK 0x0008 /* OPCLK_ENA */ | ||
358 | #define WM8904_OPCLK_ENA_SHIFT 3 /* OPCLK_ENA */ | ||
359 | #define WM8904_OPCLK_ENA_WIDTH 1 /* OPCLK_ENA */ | ||
360 | #define WM8904_CLK_SYS_ENA 0x0004 /* CLK_SYS_ENA */ | ||
361 | #define WM8904_CLK_SYS_ENA_MASK 0x0004 /* CLK_SYS_ENA */ | ||
362 | #define WM8904_CLK_SYS_ENA_SHIFT 2 /* CLK_SYS_ENA */ | ||
363 | #define WM8904_CLK_SYS_ENA_WIDTH 1 /* CLK_SYS_ENA */ | ||
364 | #define WM8904_CLK_DSP_ENA 0x0002 /* CLK_DSP_ENA */ | ||
365 | #define WM8904_CLK_DSP_ENA_MASK 0x0002 /* CLK_DSP_ENA */ | ||
366 | #define WM8904_CLK_DSP_ENA_SHIFT 1 /* CLK_DSP_ENA */ | ||
367 | #define WM8904_CLK_DSP_ENA_WIDTH 1 /* CLK_DSP_ENA */ | ||
368 | #define WM8904_TOCLK_ENA 0x0001 /* TOCLK_ENA */ | ||
369 | #define WM8904_TOCLK_ENA_MASK 0x0001 /* TOCLK_ENA */ | ||
370 | #define WM8904_TOCLK_ENA_SHIFT 0 /* TOCLK_ENA */ | ||
371 | #define WM8904_TOCLK_ENA_WIDTH 1 /* TOCLK_ENA */ | ||
372 | |||
373 | /* | ||
374 | * R24 (0x18) - Audio Interface 0 | ||
375 | */ | ||
376 | #define WM8904_DACL_DATINV 0x1000 /* DACL_DATINV */ | ||
377 | #define WM8904_DACL_DATINV_MASK 0x1000 /* DACL_DATINV */ | ||
378 | #define WM8904_DACL_DATINV_SHIFT 12 /* DACL_DATINV */ | ||
379 | #define WM8904_DACL_DATINV_WIDTH 1 /* DACL_DATINV */ | ||
380 | #define WM8904_DACR_DATINV 0x0800 /* DACR_DATINV */ | ||
381 | #define WM8904_DACR_DATINV_MASK 0x0800 /* DACR_DATINV */ | ||
382 | #define WM8904_DACR_DATINV_SHIFT 11 /* DACR_DATINV */ | ||
383 | #define WM8904_DACR_DATINV_WIDTH 1 /* DACR_DATINV */ | ||
384 | #define WM8904_DAC_BOOST_MASK 0x0600 /* DAC_BOOST - [10:9] */ | ||
385 | #define WM8904_DAC_BOOST_SHIFT 9 /* DAC_BOOST - [10:9] */ | ||
386 | #define WM8904_DAC_BOOST_WIDTH 2 /* DAC_BOOST - [10:9] */ | ||
387 | #define WM8904_LOOPBACK 0x0100 /* LOOPBACK */ | ||
388 | #define WM8904_LOOPBACK_MASK 0x0100 /* LOOPBACK */ | ||
389 | #define WM8904_LOOPBACK_SHIFT 8 /* LOOPBACK */ | ||
390 | #define WM8904_LOOPBACK_WIDTH 1 /* LOOPBACK */ | ||
391 | #define WM8904_AIFADCL_SRC 0x0080 /* AIFADCL_SRC */ | ||
392 | #define WM8904_AIFADCL_SRC_MASK 0x0080 /* AIFADCL_SRC */ | ||
393 | #define WM8904_AIFADCL_SRC_SHIFT 7 /* AIFADCL_SRC */ | ||
394 | #define WM8904_AIFADCL_SRC_WIDTH 1 /* AIFADCL_SRC */ | ||
395 | #define WM8904_AIFADCR_SRC 0x0040 /* AIFADCR_SRC */ | ||
396 | #define WM8904_AIFADCR_SRC_MASK 0x0040 /* AIFADCR_SRC */ | ||
397 | #define WM8904_AIFADCR_SRC_SHIFT 6 /* AIFADCR_SRC */ | ||
398 | #define WM8904_AIFADCR_SRC_WIDTH 1 /* AIFADCR_SRC */ | ||
399 | #define WM8904_AIFDACL_SRC 0x0020 /* AIFDACL_SRC */ | ||
400 | #define WM8904_AIFDACL_SRC_MASK 0x0020 /* AIFDACL_SRC */ | ||
401 | #define WM8904_AIFDACL_SRC_SHIFT 5 /* AIFDACL_SRC */ | ||
402 | #define WM8904_AIFDACL_SRC_WIDTH 1 /* AIFDACL_SRC */ | ||
403 | #define WM8904_AIFDACR_SRC 0x0010 /* AIFDACR_SRC */ | ||
404 | #define WM8904_AIFDACR_SRC_MASK 0x0010 /* AIFDACR_SRC */ | ||
405 | #define WM8904_AIFDACR_SRC_SHIFT 4 /* AIFDACR_SRC */ | ||
406 | #define WM8904_AIFDACR_SRC_WIDTH 1 /* AIFDACR_SRC */ | ||
407 | #define WM8904_ADC_COMP 0x0008 /* ADC_COMP */ | ||
408 | #define WM8904_ADC_COMP_MASK 0x0008 /* ADC_COMP */ | ||
409 | #define WM8904_ADC_COMP_SHIFT 3 /* ADC_COMP */ | ||
410 | #define WM8904_ADC_COMP_WIDTH 1 /* ADC_COMP */ | ||
411 | #define WM8904_ADC_COMPMODE 0x0004 /* ADC_COMPMODE */ | ||
412 | #define WM8904_ADC_COMPMODE_MASK 0x0004 /* ADC_COMPMODE */ | ||
413 | #define WM8904_ADC_COMPMODE_SHIFT 2 /* ADC_COMPMODE */ | ||
414 | #define WM8904_ADC_COMPMODE_WIDTH 1 /* ADC_COMPMODE */ | ||
415 | #define WM8904_DAC_COMP 0x0002 /* DAC_COMP */ | ||
416 | #define WM8904_DAC_COMP_MASK 0x0002 /* DAC_COMP */ | ||
417 | #define WM8904_DAC_COMP_SHIFT 1 /* DAC_COMP */ | ||
418 | #define WM8904_DAC_COMP_WIDTH 1 /* DAC_COMP */ | ||
419 | #define WM8904_DAC_COMPMODE 0x0001 /* DAC_COMPMODE */ | ||
420 | #define WM8904_DAC_COMPMODE_MASK 0x0001 /* DAC_COMPMODE */ | ||
421 | #define WM8904_DAC_COMPMODE_SHIFT 0 /* DAC_COMPMODE */ | ||
422 | #define WM8904_DAC_COMPMODE_WIDTH 1 /* DAC_COMPMODE */ | ||
423 | |||
424 | /* | ||
425 | * R25 (0x19) - Audio Interface 1 | ||
426 | */ | ||
427 | #define WM8904_AIFDAC_TDM 0x2000 /* AIFDAC_TDM */ | ||
428 | #define WM8904_AIFDAC_TDM_MASK 0x2000 /* AIFDAC_TDM */ | ||
429 | #define WM8904_AIFDAC_TDM_SHIFT 13 /* AIFDAC_TDM */ | ||
430 | #define WM8904_AIFDAC_TDM_WIDTH 1 /* AIFDAC_TDM */ | ||
431 | #define WM8904_AIFDAC_TDM_CHAN 0x1000 /* AIFDAC_TDM_CHAN */ | ||
432 | #define WM8904_AIFDAC_TDM_CHAN_MASK 0x1000 /* AIFDAC_TDM_CHAN */ | ||
433 | #define WM8904_AIFDAC_TDM_CHAN_SHIFT 12 /* AIFDAC_TDM_CHAN */ | ||
434 | #define WM8904_AIFDAC_TDM_CHAN_WIDTH 1 /* AIFDAC_TDM_CHAN */ | ||
435 | #define WM8904_AIFADC_TDM 0x0800 /* AIFADC_TDM */ | ||
436 | #define WM8904_AIFADC_TDM_MASK 0x0800 /* AIFADC_TDM */ | ||
437 | #define WM8904_AIFADC_TDM_SHIFT 11 /* AIFADC_TDM */ | ||
438 | #define WM8904_AIFADC_TDM_WIDTH 1 /* AIFADC_TDM */ | ||
439 | #define WM8904_AIFADC_TDM_CHAN 0x0400 /* AIFADC_TDM_CHAN */ | ||
440 | #define WM8904_AIFADC_TDM_CHAN_MASK 0x0400 /* AIFADC_TDM_CHAN */ | ||
441 | #define WM8904_AIFADC_TDM_CHAN_SHIFT 10 /* AIFADC_TDM_CHAN */ | ||
442 | #define WM8904_AIFADC_TDM_CHAN_WIDTH 1 /* AIFADC_TDM_CHAN */ | ||
443 | #define WM8904_AIF_TRIS 0x0100 /* AIF_TRIS */ | ||
444 | #define WM8904_AIF_TRIS_MASK 0x0100 /* AIF_TRIS */ | ||
445 | #define WM8904_AIF_TRIS_SHIFT 8 /* AIF_TRIS */ | ||
446 | #define WM8904_AIF_TRIS_WIDTH 1 /* AIF_TRIS */ | ||
447 | #define WM8904_AIF_BCLK_INV 0x0080 /* AIF_BCLK_INV */ | ||
448 | #define WM8904_AIF_BCLK_INV_MASK 0x0080 /* AIF_BCLK_INV */ | ||
449 | #define WM8904_AIF_BCLK_INV_SHIFT 7 /* AIF_BCLK_INV */ | ||
450 | #define WM8904_AIF_BCLK_INV_WIDTH 1 /* AIF_BCLK_INV */ | ||
451 | #define WM8904_BCLK_DIR 0x0040 /* BCLK_DIR */ | ||
452 | #define WM8904_BCLK_DIR_MASK 0x0040 /* BCLK_DIR */ | ||
453 | #define WM8904_BCLK_DIR_SHIFT 6 /* BCLK_DIR */ | ||
454 | #define WM8904_BCLK_DIR_WIDTH 1 /* BCLK_DIR */ | ||
455 | #define WM8904_AIF_LRCLK_INV 0x0010 /* AIF_LRCLK_INV */ | ||
456 | #define WM8904_AIF_LRCLK_INV_MASK 0x0010 /* AIF_LRCLK_INV */ | ||
457 | #define WM8904_AIF_LRCLK_INV_SHIFT 4 /* AIF_LRCLK_INV */ | ||
458 | #define WM8904_AIF_LRCLK_INV_WIDTH 1 /* AIF_LRCLK_INV */ | ||
459 | #define WM8904_AIF_WL_MASK 0x000C /* AIF_WL - [3:2] */ | ||
460 | #define WM8904_AIF_WL_SHIFT 2 /* AIF_WL - [3:2] */ | ||
461 | #define WM8904_AIF_WL_WIDTH 2 /* AIF_WL - [3:2] */ | ||
462 | #define WM8904_AIF_FMT_MASK 0x0003 /* AIF_FMT - [1:0] */ | ||
463 | #define WM8904_AIF_FMT_SHIFT 0 /* AIF_FMT - [1:0] */ | ||
464 | #define WM8904_AIF_FMT_WIDTH 2 /* AIF_FMT - [1:0] */ | ||
465 | |||
466 | /* | ||
467 | * R26 (0x1A) - Audio Interface 2 | ||
468 | */ | ||
469 | #define WM8904_OPCLK_DIV_MASK 0x0F00 /* OPCLK_DIV - [11:8] */ | ||
470 | #define WM8904_OPCLK_DIV_SHIFT 8 /* OPCLK_DIV - [11:8] */ | ||
471 | #define WM8904_OPCLK_DIV_WIDTH 4 /* OPCLK_DIV - [11:8] */ | ||
472 | #define WM8904_BCLK_DIV_MASK 0x001F /* BCLK_DIV - [4:0] */ | ||
473 | #define WM8904_BCLK_DIV_SHIFT 0 /* BCLK_DIV - [4:0] */ | ||
474 | #define WM8904_BCLK_DIV_WIDTH 5 /* BCLK_DIV - [4:0] */ | ||
475 | |||
476 | /* | ||
477 | * R27 (0x1B) - Audio Interface 3 | ||
478 | */ | ||
479 | #define WM8904_LRCLK_DIR 0x0800 /* LRCLK_DIR */ | ||
480 | #define WM8904_LRCLK_DIR_MASK 0x0800 /* LRCLK_DIR */ | ||
481 | #define WM8904_LRCLK_DIR_SHIFT 11 /* LRCLK_DIR */ | ||
482 | #define WM8904_LRCLK_DIR_WIDTH 1 /* LRCLK_DIR */ | ||
483 | #define WM8904_LRCLK_RATE_MASK 0x07FF /* LRCLK_RATE - [10:0] */ | ||
484 | #define WM8904_LRCLK_RATE_SHIFT 0 /* LRCLK_RATE - [10:0] */ | ||
485 | #define WM8904_LRCLK_RATE_WIDTH 11 /* LRCLK_RATE - [10:0] */ | ||
486 | |||
487 | /* | ||
488 | * R30 (0x1E) - DAC Digital Volume Left | ||
489 | */ | ||
490 | #define WM8904_DAC_VU 0x0100 /* DAC_VU */ | ||
491 | #define WM8904_DAC_VU_MASK 0x0100 /* DAC_VU */ | ||
492 | #define WM8904_DAC_VU_SHIFT 8 /* DAC_VU */ | ||
493 | #define WM8904_DAC_VU_WIDTH 1 /* DAC_VU */ | ||
494 | #define WM8904_DACL_VOL_MASK 0x00FF /* DACL_VOL - [7:0] */ | ||
495 | #define WM8904_DACL_VOL_SHIFT 0 /* DACL_VOL - [7:0] */ | ||
496 | #define WM8904_DACL_VOL_WIDTH 8 /* DACL_VOL - [7:0] */ | ||
497 | |||
498 | /* | ||
499 | * R31 (0x1F) - DAC Digital Volume Right | ||
500 | */ | ||
501 | #define WM8904_DAC_VU 0x0100 /* DAC_VU */ | ||
502 | #define WM8904_DAC_VU_MASK 0x0100 /* DAC_VU */ | ||
503 | #define WM8904_DAC_VU_SHIFT 8 /* DAC_VU */ | ||
504 | #define WM8904_DAC_VU_WIDTH 1 /* DAC_VU */ | ||
505 | #define WM8904_DACR_VOL_MASK 0x00FF /* DACR_VOL - [7:0] */ | ||
506 | #define WM8904_DACR_VOL_SHIFT 0 /* DACR_VOL - [7:0] */ | ||
507 | #define WM8904_DACR_VOL_WIDTH 8 /* DACR_VOL - [7:0] */ | ||
508 | |||
509 | /* | ||
510 | * R32 (0x20) - DAC Digital 0 | ||
511 | */ | ||
512 | #define WM8904_ADCL_DAC_SVOL_MASK 0x0F00 /* ADCL_DAC_SVOL - [11:8] */ | ||
513 | #define WM8904_ADCL_DAC_SVOL_SHIFT 8 /* ADCL_DAC_SVOL - [11:8] */ | ||
514 | #define WM8904_ADCL_DAC_SVOL_WIDTH 4 /* ADCL_DAC_SVOL - [11:8] */ | ||
515 | #define WM8904_ADCR_DAC_SVOL_MASK 0x00F0 /* ADCR_DAC_SVOL - [7:4] */ | ||
516 | #define WM8904_ADCR_DAC_SVOL_SHIFT 4 /* ADCR_DAC_SVOL - [7:4] */ | ||
517 | #define WM8904_ADCR_DAC_SVOL_WIDTH 4 /* ADCR_DAC_SVOL - [7:4] */ | ||
518 | #define WM8904_ADC_TO_DACL_MASK 0x000C /* ADC_TO_DACL - [3:2] */ | ||
519 | #define WM8904_ADC_TO_DACL_SHIFT 2 /* ADC_TO_DACL - [3:2] */ | ||
520 | #define WM8904_ADC_TO_DACL_WIDTH 2 /* ADC_TO_DACL - [3:2] */ | ||
521 | #define WM8904_ADC_TO_DACR_MASK 0x0003 /* ADC_TO_DACR - [1:0] */ | ||
522 | #define WM8904_ADC_TO_DACR_SHIFT 0 /* ADC_TO_DACR - [1:0] */ | ||
523 | #define WM8904_ADC_TO_DACR_WIDTH 2 /* ADC_TO_DACR - [1:0] */ | ||
524 | |||
525 | /* | ||
526 | * R33 (0x21) - DAC Digital 1 | ||
527 | */ | ||
528 | #define WM8904_DAC_MONO 0x1000 /* DAC_MONO */ | ||
529 | #define WM8904_DAC_MONO_MASK 0x1000 /* DAC_MONO */ | ||
530 | #define WM8904_DAC_MONO_SHIFT 12 /* DAC_MONO */ | ||
531 | #define WM8904_DAC_MONO_WIDTH 1 /* DAC_MONO */ | ||
532 | #define WM8904_DAC_SB_FILT 0x0800 /* DAC_SB_FILT */ | ||
533 | #define WM8904_DAC_SB_FILT_MASK 0x0800 /* DAC_SB_FILT */ | ||
534 | #define WM8904_DAC_SB_FILT_SHIFT 11 /* DAC_SB_FILT */ | ||
535 | #define WM8904_DAC_SB_FILT_WIDTH 1 /* DAC_SB_FILT */ | ||
536 | #define WM8904_DAC_MUTERATE 0x0400 /* DAC_MUTERATE */ | ||
537 | #define WM8904_DAC_MUTERATE_MASK 0x0400 /* DAC_MUTERATE */ | ||
538 | #define WM8904_DAC_MUTERATE_SHIFT 10 /* DAC_MUTERATE */ | ||
539 | #define WM8904_DAC_MUTERATE_WIDTH 1 /* DAC_MUTERATE */ | ||
540 | #define WM8904_DAC_UNMUTE_RAMP 0x0200 /* DAC_UNMUTE_RAMP */ | ||
541 | #define WM8904_DAC_UNMUTE_RAMP_MASK 0x0200 /* DAC_UNMUTE_RAMP */ | ||
542 | #define WM8904_DAC_UNMUTE_RAMP_SHIFT 9 /* DAC_UNMUTE_RAMP */ | ||
543 | #define WM8904_DAC_UNMUTE_RAMP_WIDTH 1 /* DAC_UNMUTE_RAMP */ | ||
544 | #define WM8904_DAC_OSR128 0x0040 /* DAC_OSR128 */ | ||
545 | #define WM8904_DAC_OSR128_MASK 0x0040 /* DAC_OSR128 */ | ||
546 | #define WM8904_DAC_OSR128_SHIFT 6 /* DAC_OSR128 */ | ||
547 | #define WM8904_DAC_OSR128_WIDTH 1 /* DAC_OSR128 */ | ||
548 | #define WM8904_DAC_MUTE 0x0008 /* DAC_MUTE */ | ||
549 | #define WM8904_DAC_MUTE_MASK 0x0008 /* DAC_MUTE */ | ||
550 | #define WM8904_DAC_MUTE_SHIFT 3 /* DAC_MUTE */ | ||
551 | #define WM8904_DAC_MUTE_WIDTH 1 /* DAC_MUTE */ | ||
552 | #define WM8904_DEEMPH_MASK 0x0006 /* DEEMPH - [2:1] */ | ||
553 | #define WM8904_DEEMPH_SHIFT 1 /* DEEMPH - [2:1] */ | ||
554 | #define WM8904_DEEMPH_WIDTH 2 /* DEEMPH - [2:1] */ | ||
555 | |||
556 | /* | ||
557 | * R36 (0x24) - ADC Digital Volume Left | ||
558 | */ | ||
559 | #define WM8904_ADC_VU 0x0100 /* ADC_VU */ | ||
560 | #define WM8904_ADC_VU_MASK 0x0100 /* ADC_VU */ | ||
561 | #define WM8904_ADC_VU_SHIFT 8 /* ADC_VU */ | ||
562 | #define WM8904_ADC_VU_WIDTH 1 /* ADC_VU */ | ||
563 | #define WM8904_ADCL_VOL_MASK 0x00FF /* ADCL_VOL - [7:0] */ | ||
564 | #define WM8904_ADCL_VOL_SHIFT 0 /* ADCL_VOL - [7:0] */ | ||
565 | #define WM8904_ADCL_VOL_WIDTH 8 /* ADCL_VOL - [7:0] */ | ||
566 | |||
567 | /* | ||
568 | * R37 (0x25) - ADC Digital Volume Right | ||
569 | */ | ||
570 | #define WM8904_ADC_VU 0x0100 /* ADC_VU */ | ||
571 | #define WM8904_ADC_VU_MASK 0x0100 /* ADC_VU */ | ||
572 | #define WM8904_ADC_VU_SHIFT 8 /* ADC_VU */ | ||
573 | #define WM8904_ADC_VU_WIDTH 1 /* ADC_VU */ | ||
574 | #define WM8904_ADCR_VOL_MASK 0x00FF /* ADCR_VOL - [7:0] */ | ||
575 | #define WM8904_ADCR_VOL_SHIFT 0 /* ADCR_VOL - [7:0] */ | ||
576 | #define WM8904_ADCR_VOL_WIDTH 8 /* ADCR_VOL - [7:0] */ | ||
577 | |||
578 | /* | ||
579 | * R38 (0x26) - ADC Digital 0 | ||
580 | */ | ||
581 | #define WM8904_ADC_HPF_CUT_MASK 0x0060 /* ADC_HPF_CUT - [6:5] */ | ||
582 | #define WM8904_ADC_HPF_CUT_SHIFT 5 /* ADC_HPF_CUT - [6:5] */ | ||
583 | #define WM8904_ADC_HPF_CUT_WIDTH 2 /* ADC_HPF_CUT - [6:5] */ | ||
584 | #define WM8904_ADC_HPF 0x0010 /* ADC_HPF */ | ||
585 | #define WM8904_ADC_HPF_MASK 0x0010 /* ADC_HPF */ | ||
586 | #define WM8904_ADC_HPF_SHIFT 4 /* ADC_HPF */ | ||
587 | #define WM8904_ADC_HPF_WIDTH 1 /* ADC_HPF */ | ||
588 | #define WM8904_ADCL_DATINV 0x0002 /* ADCL_DATINV */ | ||
589 | #define WM8904_ADCL_DATINV_MASK 0x0002 /* ADCL_DATINV */ | ||
590 | #define WM8904_ADCL_DATINV_SHIFT 1 /* ADCL_DATINV */ | ||
591 | #define WM8904_ADCL_DATINV_WIDTH 1 /* ADCL_DATINV */ | ||
592 | #define WM8904_ADCR_DATINV 0x0001 /* ADCR_DATINV */ | ||
593 | #define WM8904_ADCR_DATINV_MASK 0x0001 /* ADCR_DATINV */ | ||
594 | #define WM8904_ADCR_DATINV_SHIFT 0 /* ADCR_DATINV */ | ||
595 | #define WM8904_ADCR_DATINV_WIDTH 1 /* ADCR_DATINV */ | ||
596 | |||
597 | /* | ||
598 | * R39 (0x27) - Digital Microphone 0 | ||
599 | */ | ||
600 | #define WM8904_DMIC_ENA 0x1000 /* DMIC_ENA */ | ||
601 | #define WM8904_DMIC_ENA_MASK 0x1000 /* DMIC_ENA */ | ||
602 | #define WM8904_DMIC_ENA_SHIFT 12 /* DMIC_ENA */ | ||
603 | #define WM8904_DMIC_ENA_WIDTH 1 /* DMIC_ENA */ | ||
604 | #define WM8904_DMIC_SRC 0x0800 /* DMIC_SRC */ | ||
605 | #define WM8904_DMIC_SRC_MASK 0x0800 /* DMIC_SRC */ | ||
606 | #define WM8904_DMIC_SRC_SHIFT 11 /* DMIC_SRC */ | ||
607 | #define WM8904_DMIC_SRC_WIDTH 1 /* DMIC_SRC */ | ||
608 | |||
609 | /* | ||
610 | * R40 (0x28) - DRC 0 | ||
611 | */ | ||
612 | #define WM8904_DRC_ENA 0x8000 /* DRC_ENA */ | ||
613 | #define WM8904_DRC_ENA_MASK 0x8000 /* DRC_ENA */ | ||
614 | #define WM8904_DRC_ENA_SHIFT 15 /* DRC_ENA */ | ||
615 | #define WM8904_DRC_ENA_WIDTH 1 /* DRC_ENA */ | ||
616 | #define WM8904_DRC_DAC_PATH 0x4000 /* DRC_DAC_PATH */ | ||
617 | #define WM8904_DRC_DAC_PATH_MASK 0x4000 /* DRC_DAC_PATH */ | ||
618 | #define WM8904_DRC_DAC_PATH_SHIFT 14 /* DRC_DAC_PATH */ | ||
619 | #define WM8904_DRC_DAC_PATH_WIDTH 1 /* DRC_DAC_PATH */ | ||
620 | #define WM8904_DRC_GS_HYST_LVL_MASK 0x1800 /* DRC_GS_HYST_LVL - [12:11] */ | ||
621 | #define WM8904_DRC_GS_HYST_LVL_SHIFT 11 /* DRC_GS_HYST_LVL - [12:11] */ | ||
622 | #define WM8904_DRC_GS_HYST_LVL_WIDTH 2 /* DRC_GS_HYST_LVL - [12:11] */ | ||
623 | #define WM8904_DRC_STARTUP_GAIN_MASK 0x07C0 /* DRC_STARTUP_GAIN - [10:6] */ | ||
624 | #define WM8904_DRC_STARTUP_GAIN_SHIFT 6 /* DRC_STARTUP_GAIN - [10:6] */ | ||
625 | #define WM8904_DRC_STARTUP_GAIN_WIDTH 5 /* DRC_STARTUP_GAIN - [10:6] */ | ||
626 | #define WM8904_DRC_FF_DELAY 0x0020 /* DRC_FF_DELAY */ | ||
627 | #define WM8904_DRC_FF_DELAY_MASK 0x0020 /* DRC_FF_DELAY */ | ||
628 | #define WM8904_DRC_FF_DELAY_SHIFT 5 /* DRC_FF_DELAY */ | ||
629 | #define WM8904_DRC_FF_DELAY_WIDTH 1 /* DRC_FF_DELAY */ | ||
630 | #define WM8904_DRC_GS_ENA 0x0008 /* DRC_GS_ENA */ | ||
631 | #define WM8904_DRC_GS_ENA_MASK 0x0008 /* DRC_GS_ENA */ | ||
632 | #define WM8904_DRC_GS_ENA_SHIFT 3 /* DRC_GS_ENA */ | ||
633 | #define WM8904_DRC_GS_ENA_WIDTH 1 /* DRC_GS_ENA */ | ||
634 | #define WM8904_DRC_QR 0x0004 /* DRC_QR */ | ||
635 | #define WM8904_DRC_QR_MASK 0x0004 /* DRC_QR */ | ||
636 | #define WM8904_DRC_QR_SHIFT 2 /* DRC_QR */ | ||
637 | #define WM8904_DRC_QR_WIDTH 1 /* DRC_QR */ | ||
638 | #define WM8904_DRC_ANTICLIP 0x0002 /* DRC_ANTICLIP */ | ||
639 | #define WM8904_DRC_ANTICLIP_MASK 0x0002 /* DRC_ANTICLIP */ | ||
640 | #define WM8904_DRC_ANTICLIP_SHIFT 1 /* DRC_ANTICLIP */ | ||
641 | #define WM8904_DRC_ANTICLIP_WIDTH 1 /* DRC_ANTICLIP */ | ||
642 | #define WM8904_DRC_GS_HYST 0x0001 /* DRC_GS_HYST */ | ||
643 | #define WM8904_DRC_GS_HYST_MASK 0x0001 /* DRC_GS_HYST */ | ||
644 | #define WM8904_DRC_GS_HYST_SHIFT 0 /* DRC_GS_HYST */ | ||
645 | #define WM8904_DRC_GS_HYST_WIDTH 1 /* DRC_GS_HYST */ | ||
646 | |||
647 | /* | ||
648 | * R41 (0x29) - DRC 1 | ||
649 | */ | ||
650 | #define WM8904_DRC_ATK_MASK 0xF000 /* DRC_ATK - [15:12] */ | ||
651 | #define WM8904_DRC_ATK_SHIFT 12 /* DRC_ATK - [15:12] */ | ||
652 | #define WM8904_DRC_ATK_WIDTH 4 /* DRC_ATK - [15:12] */ | ||
653 | #define WM8904_DRC_DCY_MASK 0x0F00 /* DRC_DCY - [11:8] */ | ||
654 | #define WM8904_DRC_DCY_SHIFT 8 /* DRC_DCY - [11:8] */ | ||
655 | #define WM8904_DRC_DCY_WIDTH 4 /* DRC_DCY - [11:8] */ | ||
656 | #define WM8904_DRC_QR_THR_MASK 0x00C0 /* DRC_QR_THR - [7:6] */ | ||
657 | #define WM8904_DRC_QR_THR_SHIFT 6 /* DRC_QR_THR - [7:6] */ | ||
658 | #define WM8904_DRC_QR_THR_WIDTH 2 /* DRC_QR_THR - [7:6] */ | ||
659 | #define WM8904_DRC_QR_DCY_MASK 0x0030 /* DRC_QR_DCY - [5:4] */ | ||
660 | #define WM8904_DRC_QR_DCY_SHIFT 4 /* DRC_QR_DCY - [5:4] */ | ||
661 | #define WM8904_DRC_QR_DCY_WIDTH 2 /* DRC_QR_DCY - [5:4] */ | ||
662 | #define WM8904_DRC_MINGAIN_MASK 0x000C /* DRC_MINGAIN - [3:2] */ | ||
663 | #define WM8904_DRC_MINGAIN_SHIFT 2 /* DRC_MINGAIN - [3:2] */ | ||
664 | #define WM8904_DRC_MINGAIN_WIDTH 2 /* DRC_MINGAIN - [3:2] */ | ||
665 | #define WM8904_DRC_MAXGAIN_MASK 0x0003 /* DRC_MAXGAIN - [1:0] */ | ||
666 | #define WM8904_DRC_MAXGAIN_SHIFT 0 /* DRC_MAXGAIN - [1:0] */ | ||
667 | #define WM8904_DRC_MAXGAIN_WIDTH 2 /* DRC_MAXGAIN - [1:0] */ | ||
668 | |||
669 | /* | ||
670 | * R42 (0x2A) - DRC 2 | ||
671 | */ | ||
672 | #define WM8904_DRC_HI_COMP_MASK 0x0038 /* DRC_HI_COMP - [5:3] */ | ||
673 | #define WM8904_DRC_HI_COMP_SHIFT 3 /* DRC_HI_COMP - [5:3] */ | ||
674 | #define WM8904_DRC_HI_COMP_WIDTH 3 /* DRC_HI_COMP - [5:3] */ | ||
675 | #define WM8904_DRC_LO_COMP_MASK 0x0007 /* DRC_LO_COMP - [2:0] */ | ||
676 | #define WM8904_DRC_LO_COMP_SHIFT 0 /* DRC_LO_COMP - [2:0] */ | ||
677 | #define WM8904_DRC_LO_COMP_WIDTH 3 /* DRC_LO_COMP - [2:0] */ | ||
678 | |||
679 | /* | ||
680 | * R43 (0x2B) - DRC 3 | ||
681 | */ | ||
682 | #define WM8904_DRC_KNEE_IP_MASK 0x07E0 /* DRC_KNEE_IP - [10:5] */ | ||
683 | #define WM8904_DRC_KNEE_IP_SHIFT 5 /* DRC_KNEE_IP - [10:5] */ | ||
684 | #define WM8904_DRC_KNEE_IP_WIDTH 6 /* DRC_KNEE_IP - [10:5] */ | ||
685 | #define WM8904_DRC_KNEE_OP_MASK 0x001F /* DRC_KNEE_OP - [4:0] */ | ||
686 | #define WM8904_DRC_KNEE_OP_SHIFT 0 /* DRC_KNEE_OP - [4:0] */ | ||
687 | #define WM8904_DRC_KNEE_OP_WIDTH 5 /* DRC_KNEE_OP - [4:0] */ | ||
688 | |||
689 | /* | ||
690 | * R44 (0x2C) - Analogue Left Input 0 | ||
691 | */ | ||
692 | #define WM8904_LINMUTE 0x0080 /* LINMUTE */ | ||
693 | #define WM8904_LINMUTE_MASK 0x0080 /* LINMUTE */ | ||
694 | #define WM8904_LINMUTE_SHIFT 7 /* LINMUTE */ | ||
695 | #define WM8904_LINMUTE_WIDTH 1 /* LINMUTE */ | ||
696 | #define WM8904_LIN_VOL_MASK 0x001F /* LIN_VOL - [4:0] */ | ||
697 | #define WM8904_LIN_VOL_SHIFT 0 /* LIN_VOL - [4:0] */ | ||
698 | #define WM8904_LIN_VOL_WIDTH 5 /* LIN_VOL - [4:0] */ | ||
699 | |||
700 | /* | ||
701 | * R45 (0x2D) - Analogue Right Input 0 | ||
702 | */ | ||
703 | #define WM8904_RINMUTE 0x0080 /* RINMUTE */ | ||
704 | #define WM8904_RINMUTE_MASK 0x0080 /* RINMUTE */ | ||
705 | #define WM8904_RINMUTE_SHIFT 7 /* RINMUTE */ | ||
706 | #define WM8904_RINMUTE_WIDTH 1 /* RINMUTE */ | ||
707 | #define WM8904_RIN_VOL_MASK 0x001F /* RIN_VOL - [4:0] */ | ||
708 | #define WM8904_RIN_VOL_SHIFT 0 /* RIN_VOL - [4:0] */ | ||
709 | #define WM8904_RIN_VOL_WIDTH 5 /* RIN_VOL - [4:0] */ | ||
710 | |||
711 | /* | ||
712 | * R46 (0x2E) - Analogue Left Input 1 | ||
713 | */ | ||
714 | #define WM8904_INL_CM_ENA 0x0040 /* INL_CM_ENA */ | ||
715 | #define WM8904_INL_CM_ENA_MASK 0x0040 /* INL_CM_ENA */ | ||
716 | #define WM8904_INL_CM_ENA_SHIFT 6 /* INL_CM_ENA */ | ||
717 | #define WM8904_INL_CM_ENA_WIDTH 1 /* INL_CM_ENA */ | ||
718 | #define WM8904_L_IP_SEL_N_MASK 0x0030 /* L_IP_SEL_N - [5:4] */ | ||
719 | #define WM8904_L_IP_SEL_N_SHIFT 4 /* L_IP_SEL_N - [5:4] */ | ||
720 | #define WM8904_L_IP_SEL_N_WIDTH 2 /* L_IP_SEL_N - [5:4] */ | ||
721 | #define WM8904_L_IP_SEL_P_MASK 0x000C /* L_IP_SEL_P - [3:2] */ | ||
722 | #define WM8904_L_IP_SEL_P_SHIFT 2 /* L_IP_SEL_P - [3:2] */ | ||
723 | #define WM8904_L_IP_SEL_P_WIDTH 2 /* L_IP_SEL_P - [3:2] */ | ||
724 | #define WM8904_L_MODE_MASK 0x0003 /* L_MODE - [1:0] */ | ||
725 | #define WM8904_L_MODE_SHIFT 0 /* L_MODE - [1:0] */ | ||
726 | #define WM8904_L_MODE_WIDTH 2 /* L_MODE - [1:0] */ | ||
727 | |||
728 | /* | ||
729 | * R47 (0x2F) - Analogue Right Input 1 | ||
730 | */ | ||
731 | #define WM8904_INR_CM_ENA 0x0040 /* INR_CM_ENA */ | ||
732 | #define WM8904_INR_CM_ENA_MASK 0x0040 /* INR_CM_ENA */ | ||
733 | #define WM8904_INR_CM_ENA_SHIFT 6 /* INR_CM_ENA */ | ||
734 | #define WM8904_INR_CM_ENA_WIDTH 1 /* INR_CM_ENA */ | ||
735 | #define WM8904_R_IP_SEL_N_MASK 0x0030 /* R_IP_SEL_N - [5:4] */ | ||
736 | #define WM8904_R_IP_SEL_N_SHIFT 4 /* R_IP_SEL_N - [5:4] */ | ||
737 | #define WM8904_R_IP_SEL_N_WIDTH 2 /* R_IP_SEL_N - [5:4] */ | ||
738 | #define WM8904_R_IP_SEL_P_MASK 0x000C /* R_IP_SEL_P - [3:2] */ | ||
739 | #define WM8904_R_IP_SEL_P_SHIFT 2 /* R_IP_SEL_P - [3:2] */ | ||
740 | #define WM8904_R_IP_SEL_P_WIDTH 2 /* R_IP_SEL_P - [3:2] */ | ||
741 | #define WM8904_R_MODE_MASK 0x0003 /* R_MODE - [1:0] */ | ||
742 | #define WM8904_R_MODE_SHIFT 0 /* R_MODE - [1:0] */ | ||
743 | #define WM8904_R_MODE_WIDTH 2 /* R_MODE - [1:0] */ | ||
744 | |||
745 | /* | ||
746 | * R57 (0x39) - Analogue OUT1 Left | ||
747 | */ | ||
748 | #define WM8904_HPOUTL_MUTE 0x0100 /* HPOUTL_MUTE */ | ||
749 | #define WM8904_HPOUTL_MUTE_MASK 0x0100 /* HPOUTL_MUTE */ | ||
750 | #define WM8904_HPOUTL_MUTE_SHIFT 8 /* HPOUTL_MUTE */ | ||
751 | #define WM8904_HPOUTL_MUTE_WIDTH 1 /* HPOUTL_MUTE */ | ||
752 | #define WM8904_HPOUT_VU 0x0080 /* HPOUT_VU */ | ||
753 | #define WM8904_HPOUT_VU_MASK 0x0080 /* HPOUT_VU */ | ||
754 | #define WM8904_HPOUT_VU_SHIFT 7 /* HPOUT_VU */ | ||
755 | #define WM8904_HPOUT_VU_WIDTH 1 /* HPOUT_VU */ | ||
756 | #define WM8904_HPOUTLZC 0x0040 /* HPOUTLZC */ | ||
757 | #define WM8904_HPOUTLZC_MASK 0x0040 /* HPOUTLZC */ | ||
758 | #define WM8904_HPOUTLZC_SHIFT 6 /* HPOUTLZC */ | ||
759 | #define WM8904_HPOUTLZC_WIDTH 1 /* HPOUTLZC */ | ||
760 | #define WM8904_HPOUTL_VOL_MASK 0x003F /* HPOUTL_VOL - [5:0] */ | ||
761 | #define WM8904_HPOUTL_VOL_SHIFT 0 /* HPOUTL_VOL - [5:0] */ | ||
762 | #define WM8904_HPOUTL_VOL_WIDTH 6 /* HPOUTL_VOL - [5:0] */ | ||
763 | |||
764 | /* | ||
765 | * R58 (0x3A) - Analogue OUT1 Right | ||
766 | */ | ||
767 | #define WM8904_HPOUTR_MUTE 0x0100 /* HPOUTR_MUTE */ | ||
768 | #define WM8904_HPOUTR_MUTE_MASK 0x0100 /* HPOUTR_MUTE */ | ||
769 | #define WM8904_HPOUTR_MUTE_SHIFT 8 /* HPOUTR_MUTE */ | ||
770 | #define WM8904_HPOUTR_MUTE_WIDTH 1 /* HPOUTR_MUTE */ | ||
771 | #define WM8904_HPOUT_VU 0x0080 /* HPOUT_VU */ | ||
772 | #define WM8904_HPOUT_VU_MASK 0x0080 /* HPOUT_VU */ | ||
773 | #define WM8904_HPOUT_VU_SHIFT 7 /* HPOUT_VU */ | ||
774 | #define WM8904_HPOUT_VU_WIDTH 1 /* HPOUT_VU */ | ||
775 | #define WM8904_HPOUTRZC 0x0040 /* HPOUTRZC */ | ||
776 | #define WM8904_HPOUTRZC_MASK 0x0040 /* HPOUTRZC */ | ||
777 | #define WM8904_HPOUTRZC_SHIFT 6 /* HPOUTRZC */ | ||
778 | #define WM8904_HPOUTRZC_WIDTH 1 /* HPOUTRZC */ | ||
779 | #define WM8904_HPOUTR_VOL_MASK 0x003F /* HPOUTR_VOL - [5:0] */ | ||
780 | #define WM8904_HPOUTR_VOL_SHIFT 0 /* HPOUTR_VOL - [5:0] */ | ||
781 | #define WM8904_HPOUTR_VOL_WIDTH 6 /* HPOUTR_VOL - [5:0] */ | ||
782 | |||
783 | /* | ||
784 | * R59 (0x3B) - Analogue OUT2 Left | ||
785 | */ | ||
786 | #define WM8904_LINEOUTL_MUTE 0x0100 /* LINEOUTL_MUTE */ | ||
787 | #define WM8904_LINEOUTL_MUTE_MASK 0x0100 /* LINEOUTL_MUTE */ | ||
788 | #define WM8904_LINEOUTL_MUTE_SHIFT 8 /* LINEOUTL_MUTE */ | ||
789 | #define WM8904_LINEOUTL_MUTE_WIDTH 1 /* LINEOUTL_MUTE */ | ||
790 | #define WM8904_LINEOUT_VU 0x0080 /* LINEOUT_VU */ | ||
791 | #define WM8904_LINEOUT_VU_MASK 0x0080 /* LINEOUT_VU */ | ||
792 | #define WM8904_LINEOUT_VU_SHIFT 7 /* LINEOUT_VU */ | ||
793 | #define WM8904_LINEOUT_VU_WIDTH 1 /* LINEOUT_VU */ | ||
794 | #define WM8904_LINEOUTLZC 0x0040 /* LINEOUTLZC */ | ||
795 | #define WM8904_LINEOUTLZC_MASK 0x0040 /* LINEOUTLZC */ | ||
796 | #define WM8904_LINEOUTLZC_SHIFT 6 /* LINEOUTLZC */ | ||
797 | #define WM8904_LINEOUTLZC_WIDTH 1 /* LINEOUTLZC */ | ||
798 | #define WM8904_LINEOUTL_VOL_MASK 0x003F /* LINEOUTL_VOL - [5:0] */ | ||
799 | #define WM8904_LINEOUTL_VOL_SHIFT 0 /* LINEOUTL_VOL - [5:0] */ | ||
800 | #define WM8904_LINEOUTL_VOL_WIDTH 6 /* LINEOUTL_VOL - [5:0] */ | ||
801 | |||
802 | /* | ||
803 | * R60 (0x3C) - Analogue OUT2 Right | ||
804 | */ | ||
805 | #define WM8904_LINEOUTR_MUTE 0x0100 /* LINEOUTR_MUTE */ | ||
806 | #define WM8904_LINEOUTR_MUTE_MASK 0x0100 /* LINEOUTR_MUTE */ | ||
807 | #define WM8904_LINEOUTR_MUTE_SHIFT 8 /* LINEOUTR_MUTE */ | ||
808 | #define WM8904_LINEOUTR_MUTE_WIDTH 1 /* LINEOUTR_MUTE */ | ||
809 | #define WM8904_LINEOUT_VU 0x0080 /* LINEOUT_VU */ | ||
810 | #define WM8904_LINEOUT_VU_MASK 0x0080 /* LINEOUT_VU */ | ||
811 | #define WM8904_LINEOUT_VU_SHIFT 7 /* LINEOUT_VU */ | ||
812 | #define WM8904_LINEOUT_VU_WIDTH 1 /* LINEOUT_VU */ | ||
813 | #define WM8904_LINEOUTRZC 0x0040 /* LINEOUTRZC */ | ||
814 | #define WM8904_LINEOUTRZC_MASK 0x0040 /* LINEOUTRZC */ | ||
815 | #define WM8904_LINEOUTRZC_SHIFT 6 /* LINEOUTRZC */ | ||
816 | #define WM8904_LINEOUTRZC_WIDTH 1 /* LINEOUTRZC */ | ||
817 | #define WM8904_LINEOUTR_VOL_MASK 0x003F /* LINEOUTR_VOL - [5:0] */ | ||
818 | #define WM8904_LINEOUTR_VOL_SHIFT 0 /* LINEOUTR_VOL - [5:0] */ | ||
819 | #define WM8904_LINEOUTR_VOL_WIDTH 6 /* LINEOUTR_VOL - [5:0] */ | ||
820 | |||
821 | /* | ||
822 | * R61 (0x3D) - Analogue OUT12 ZC | ||
823 | */ | ||
824 | #define WM8904_HPL_BYP_ENA 0x0008 /* HPL_BYP_ENA */ | ||
825 | #define WM8904_HPL_BYP_ENA_MASK 0x0008 /* HPL_BYP_ENA */ | ||
826 | #define WM8904_HPL_BYP_ENA_SHIFT 3 /* HPL_BYP_ENA */ | ||
827 | #define WM8904_HPL_BYP_ENA_WIDTH 1 /* HPL_BYP_ENA */ | ||
828 | #define WM8904_HPR_BYP_ENA 0x0004 /* HPR_BYP_ENA */ | ||
829 | #define WM8904_HPR_BYP_ENA_MASK 0x0004 /* HPR_BYP_ENA */ | ||
830 | #define WM8904_HPR_BYP_ENA_SHIFT 2 /* HPR_BYP_ENA */ | ||
831 | #define WM8904_HPR_BYP_ENA_WIDTH 1 /* HPR_BYP_ENA */ | ||
832 | #define WM8904_LINEOUTL_BYP_ENA 0x0002 /* LINEOUTL_BYP_ENA */ | ||
833 | #define WM8904_LINEOUTL_BYP_ENA_MASK 0x0002 /* LINEOUTL_BYP_ENA */ | ||
834 | #define WM8904_LINEOUTL_BYP_ENA_SHIFT 1 /* LINEOUTL_BYP_ENA */ | ||
835 | #define WM8904_LINEOUTL_BYP_ENA_WIDTH 1 /* LINEOUTL_BYP_ENA */ | ||
836 | #define WM8904_LINEOUTR_BYP_ENA 0x0001 /* LINEOUTR_BYP_ENA */ | ||
837 | #define WM8904_LINEOUTR_BYP_ENA_MASK 0x0001 /* LINEOUTR_BYP_ENA */ | ||
838 | #define WM8904_LINEOUTR_BYP_ENA_SHIFT 0 /* LINEOUTR_BYP_ENA */ | ||
839 | #define WM8904_LINEOUTR_BYP_ENA_WIDTH 1 /* LINEOUTR_BYP_ENA */ | ||
840 | |||
841 | /* | ||
842 | * R67 (0x43) - DC Servo 0 | ||
843 | */ | ||
844 | #define WM8904_DCS_ENA_CHAN_3 0x0008 /* DCS_ENA_CHAN_3 */ | ||
845 | #define WM8904_DCS_ENA_CHAN_3_MASK 0x0008 /* DCS_ENA_CHAN_3 */ | ||
846 | #define WM8904_DCS_ENA_CHAN_3_SHIFT 3 /* DCS_ENA_CHAN_3 */ | ||
847 | #define WM8904_DCS_ENA_CHAN_3_WIDTH 1 /* DCS_ENA_CHAN_3 */ | ||
848 | #define WM8904_DCS_ENA_CHAN_2 0x0004 /* DCS_ENA_CHAN_2 */ | ||
849 | #define WM8904_DCS_ENA_CHAN_2_MASK 0x0004 /* DCS_ENA_CHAN_2 */ | ||
850 | #define WM8904_DCS_ENA_CHAN_2_SHIFT 2 /* DCS_ENA_CHAN_2 */ | ||
851 | #define WM8904_DCS_ENA_CHAN_2_WIDTH 1 /* DCS_ENA_CHAN_2 */ | ||
852 | #define WM8904_DCS_ENA_CHAN_1 0x0002 /* DCS_ENA_CHAN_1 */ | ||
853 | #define WM8904_DCS_ENA_CHAN_1_MASK 0x0002 /* DCS_ENA_CHAN_1 */ | ||
854 | #define WM8904_DCS_ENA_CHAN_1_SHIFT 1 /* DCS_ENA_CHAN_1 */ | ||
855 | #define WM8904_DCS_ENA_CHAN_1_WIDTH 1 /* DCS_ENA_CHAN_1 */ | ||
856 | #define WM8904_DCS_ENA_CHAN_0 0x0001 /* DCS_ENA_CHAN_0 */ | ||
857 | #define WM8904_DCS_ENA_CHAN_0_MASK 0x0001 /* DCS_ENA_CHAN_0 */ | ||
858 | #define WM8904_DCS_ENA_CHAN_0_SHIFT 0 /* DCS_ENA_CHAN_0 */ | ||
859 | #define WM8904_DCS_ENA_CHAN_0_WIDTH 1 /* DCS_ENA_CHAN_0 */ | ||
860 | |||
861 | /* | ||
862 | * R68 (0x44) - DC Servo 1 | ||
863 | */ | ||
864 | #define WM8904_DCS_TRIG_SINGLE_3 0x8000 /* DCS_TRIG_SINGLE_3 */ | ||
865 | #define WM8904_DCS_TRIG_SINGLE_3_MASK 0x8000 /* DCS_TRIG_SINGLE_3 */ | ||
866 | #define WM8904_DCS_TRIG_SINGLE_3_SHIFT 15 /* DCS_TRIG_SINGLE_3 */ | ||
867 | #define WM8904_DCS_TRIG_SINGLE_3_WIDTH 1 /* DCS_TRIG_SINGLE_3 */ | ||
868 | #define WM8904_DCS_TRIG_SINGLE_2 0x4000 /* DCS_TRIG_SINGLE_2 */ | ||
869 | #define WM8904_DCS_TRIG_SINGLE_2_MASK 0x4000 /* DCS_TRIG_SINGLE_2 */ | ||
870 | #define WM8904_DCS_TRIG_SINGLE_2_SHIFT 14 /* DCS_TRIG_SINGLE_2 */ | ||
871 | #define WM8904_DCS_TRIG_SINGLE_2_WIDTH 1 /* DCS_TRIG_SINGLE_2 */ | ||
872 | #define WM8904_DCS_TRIG_SINGLE_1 0x2000 /* DCS_TRIG_SINGLE_1 */ | ||
873 | #define WM8904_DCS_TRIG_SINGLE_1_MASK 0x2000 /* DCS_TRIG_SINGLE_1 */ | ||
874 | #define WM8904_DCS_TRIG_SINGLE_1_SHIFT 13 /* DCS_TRIG_SINGLE_1 */ | ||
875 | #define WM8904_DCS_TRIG_SINGLE_1_WIDTH 1 /* DCS_TRIG_SINGLE_1 */ | ||
876 | #define WM8904_DCS_TRIG_SINGLE_0 0x1000 /* DCS_TRIG_SINGLE_0 */ | ||
877 | #define WM8904_DCS_TRIG_SINGLE_0_MASK 0x1000 /* DCS_TRIG_SINGLE_0 */ | ||
878 | #define WM8904_DCS_TRIG_SINGLE_0_SHIFT 12 /* DCS_TRIG_SINGLE_0 */ | ||
879 | #define WM8904_DCS_TRIG_SINGLE_0_WIDTH 1 /* DCS_TRIG_SINGLE_0 */ | ||
880 | #define WM8904_DCS_TRIG_SERIES_3 0x0800 /* DCS_TRIG_SERIES_3 */ | ||
881 | #define WM8904_DCS_TRIG_SERIES_3_MASK 0x0800 /* DCS_TRIG_SERIES_3 */ | ||
882 | #define WM8904_DCS_TRIG_SERIES_3_SHIFT 11 /* DCS_TRIG_SERIES_3 */ | ||
883 | #define WM8904_DCS_TRIG_SERIES_3_WIDTH 1 /* DCS_TRIG_SERIES_3 */ | ||
884 | #define WM8904_DCS_TRIG_SERIES_2 0x0400 /* DCS_TRIG_SERIES_2 */ | ||
885 | #define WM8904_DCS_TRIG_SERIES_2_MASK 0x0400 /* DCS_TRIG_SERIES_2 */ | ||
886 | #define WM8904_DCS_TRIG_SERIES_2_SHIFT 10 /* DCS_TRIG_SERIES_2 */ | ||
887 | #define WM8904_DCS_TRIG_SERIES_2_WIDTH 1 /* DCS_TRIG_SERIES_2 */ | ||
888 | #define WM8904_DCS_TRIG_SERIES_1 0x0200 /* DCS_TRIG_SERIES_1 */ | ||
889 | #define WM8904_DCS_TRIG_SERIES_1_MASK 0x0200 /* DCS_TRIG_SERIES_1 */ | ||
890 | #define WM8904_DCS_TRIG_SERIES_1_SHIFT 9 /* DCS_TRIG_SERIES_1 */ | ||
891 | #define WM8904_DCS_TRIG_SERIES_1_WIDTH 1 /* DCS_TRIG_SERIES_1 */ | ||
892 | #define WM8904_DCS_TRIG_SERIES_0 0x0100 /* DCS_TRIG_SERIES_0 */ | ||
893 | #define WM8904_DCS_TRIG_SERIES_0_MASK 0x0100 /* DCS_TRIG_SERIES_0 */ | ||
894 | #define WM8904_DCS_TRIG_SERIES_0_SHIFT 8 /* DCS_TRIG_SERIES_0 */ | ||
895 | #define WM8904_DCS_TRIG_SERIES_0_WIDTH 1 /* DCS_TRIG_SERIES_0 */ | ||
896 | #define WM8904_DCS_TRIG_STARTUP_3 0x0080 /* DCS_TRIG_STARTUP_3 */ | ||
897 | #define WM8904_DCS_TRIG_STARTUP_3_MASK 0x0080 /* DCS_TRIG_STARTUP_3 */ | ||
898 | #define WM8904_DCS_TRIG_STARTUP_3_SHIFT 7 /* DCS_TRIG_STARTUP_3 */ | ||
899 | #define WM8904_DCS_TRIG_STARTUP_3_WIDTH 1 /* DCS_TRIG_STARTUP_3 */ | ||
900 | #define WM8904_DCS_TRIG_STARTUP_2 0x0040 /* DCS_TRIG_STARTUP_2 */ | ||
901 | #define WM8904_DCS_TRIG_STARTUP_2_MASK 0x0040 /* DCS_TRIG_STARTUP_2 */ | ||
902 | #define WM8904_DCS_TRIG_STARTUP_2_SHIFT 6 /* DCS_TRIG_STARTUP_2 */ | ||
903 | #define WM8904_DCS_TRIG_STARTUP_2_WIDTH 1 /* DCS_TRIG_STARTUP_2 */ | ||
904 | #define WM8904_DCS_TRIG_STARTUP_1 0x0020 /* DCS_TRIG_STARTUP_1 */ | ||
905 | #define WM8904_DCS_TRIG_STARTUP_1_MASK 0x0020 /* DCS_TRIG_STARTUP_1 */ | ||
906 | #define WM8904_DCS_TRIG_STARTUP_1_SHIFT 5 /* DCS_TRIG_STARTUP_1 */ | ||
907 | #define WM8904_DCS_TRIG_STARTUP_1_WIDTH 1 /* DCS_TRIG_STARTUP_1 */ | ||
908 | #define WM8904_DCS_TRIG_STARTUP_0 0x0010 /* DCS_TRIG_STARTUP_0 */ | ||
909 | #define WM8904_DCS_TRIG_STARTUP_0_MASK 0x0010 /* DCS_TRIG_STARTUP_0 */ | ||
910 | #define WM8904_DCS_TRIG_STARTUP_0_SHIFT 4 /* DCS_TRIG_STARTUP_0 */ | ||
911 | #define WM8904_DCS_TRIG_STARTUP_0_WIDTH 1 /* DCS_TRIG_STARTUP_0 */ | ||
912 | #define WM8904_DCS_TRIG_DAC_WR_3 0x0008 /* DCS_TRIG_DAC_WR_3 */ | ||
913 | #define WM8904_DCS_TRIG_DAC_WR_3_MASK 0x0008 /* DCS_TRIG_DAC_WR_3 */ | ||
914 | #define WM8904_DCS_TRIG_DAC_WR_3_SHIFT 3 /* DCS_TRIG_DAC_WR_3 */ | ||
915 | #define WM8904_DCS_TRIG_DAC_WR_3_WIDTH 1 /* DCS_TRIG_DAC_WR_3 */ | ||
916 | #define WM8904_DCS_TRIG_DAC_WR_2 0x0004 /* DCS_TRIG_DAC_WR_2 */ | ||
917 | #define WM8904_DCS_TRIG_DAC_WR_2_MASK 0x0004 /* DCS_TRIG_DAC_WR_2 */ | ||
918 | #define WM8904_DCS_TRIG_DAC_WR_2_SHIFT 2 /* DCS_TRIG_DAC_WR_2 */ | ||
919 | #define WM8904_DCS_TRIG_DAC_WR_2_WIDTH 1 /* DCS_TRIG_DAC_WR_2 */ | ||
920 | #define WM8904_DCS_TRIG_DAC_WR_1 0x0002 /* DCS_TRIG_DAC_WR_1 */ | ||
921 | #define WM8904_DCS_TRIG_DAC_WR_1_MASK 0x0002 /* DCS_TRIG_DAC_WR_1 */ | ||
922 | #define WM8904_DCS_TRIG_DAC_WR_1_SHIFT 1 /* DCS_TRIG_DAC_WR_1 */ | ||
923 | #define WM8904_DCS_TRIG_DAC_WR_1_WIDTH 1 /* DCS_TRIG_DAC_WR_1 */ | ||
924 | #define WM8904_DCS_TRIG_DAC_WR_0 0x0001 /* DCS_TRIG_DAC_WR_0 */ | ||
925 | #define WM8904_DCS_TRIG_DAC_WR_0_MASK 0x0001 /* DCS_TRIG_DAC_WR_0 */ | ||
926 | #define WM8904_DCS_TRIG_DAC_WR_0_SHIFT 0 /* DCS_TRIG_DAC_WR_0 */ | ||
927 | #define WM8904_DCS_TRIG_DAC_WR_0_WIDTH 1 /* DCS_TRIG_DAC_WR_0 */ | ||
928 | |||
929 | /* | ||
930 | * R69 (0x45) - DC Servo 2 | ||
931 | */ | ||
932 | #define WM8904_DCS_TIMER_PERIOD_23_MASK 0x0F00 /* DCS_TIMER_PERIOD_23 - [11:8] */ | ||
933 | #define WM8904_DCS_TIMER_PERIOD_23_SHIFT 8 /* DCS_TIMER_PERIOD_23 - [11:8] */ | ||
934 | #define WM8904_DCS_TIMER_PERIOD_23_WIDTH 4 /* DCS_TIMER_PERIOD_23 - [11:8] */ | ||
935 | #define WM8904_DCS_TIMER_PERIOD_01_MASK 0x000F /* DCS_TIMER_PERIOD_01 - [3:0] */ | ||
936 | #define WM8904_DCS_TIMER_PERIOD_01_SHIFT 0 /* DCS_TIMER_PERIOD_01 - [3:0] */ | ||
937 | #define WM8904_DCS_TIMER_PERIOD_01_WIDTH 4 /* DCS_TIMER_PERIOD_01 - [3:0] */ | ||
938 | |||
939 | /* | ||
940 | * R71 (0x47) - DC Servo 4 | ||
941 | */ | ||
942 | #define WM8904_DCS_SERIES_NO_23_MASK 0x007F /* DCS_SERIES_NO_23 - [6:0] */ | ||
943 | #define WM8904_DCS_SERIES_NO_23_SHIFT 0 /* DCS_SERIES_NO_23 - [6:0] */ | ||
944 | #define WM8904_DCS_SERIES_NO_23_WIDTH 7 /* DCS_SERIES_NO_23 - [6:0] */ | ||
945 | |||
946 | /* | ||
947 | * R72 (0x48) - DC Servo 5 | ||
948 | */ | ||
949 | #define WM8904_DCS_SERIES_NO_01_MASK 0x007F /* DCS_SERIES_NO_01 - [6:0] */ | ||
950 | #define WM8904_DCS_SERIES_NO_01_SHIFT 0 /* DCS_SERIES_NO_01 - [6:0] */ | ||
951 | #define WM8904_DCS_SERIES_NO_01_WIDTH 7 /* DCS_SERIES_NO_01 - [6:0] */ | ||
952 | |||
953 | /* | ||
954 | * R73 (0x49) - DC Servo 6 | ||
955 | */ | ||
956 | #define WM8904_DCS_DAC_WR_VAL_3_MASK 0x00FF /* DCS_DAC_WR_VAL_3 - [7:0] */ | ||
957 | #define WM8904_DCS_DAC_WR_VAL_3_SHIFT 0 /* DCS_DAC_WR_VAL_3 - [7:0] */ | ||
958 | #define WM8904_DCS_DAC_WR_VAL_3_WIDTH 8 /* DCS_DAC_WR_VAL_3 - [7:0] */ | ||
959 | |||
960 | /* | ||
961 | * R74 (0x4A) - DC Servo 7 | ||
962 | */ | ||
963 | #define WM8904_DCS_DAC_WR_VAL_2_MASK 0x00FF /* DCS_DAC_WR_VAL_2 - [7:0] */ | ||
964 | #define WM8904_DCS_DAC_WR_VAL_2_SHIFT 0 /* DCS_DAC_WR_VAL_2 - [7:0] */ | ||
965 | #define WM8904_DCS_DAC_WR_VAL_2_WIDTH 8 /* DCS_DAC_WR_VAL_2 - [7:0] */ | ||
966 | |||
967 | /* | ||
968 | * R75 (0x4B) - DC Servo 8 | ||
969 | */ | ||
970 | #define WM8904_DCS_DAC_WR_VAL_1_MASK 0x00FF /* DCS_DAC_WR_VAL_1 - [7:0] */ | ||
971 | #define WM8904_DCS_DAC_WR_VAL_1_SHIFT 0 /* DCS_DAC_WR_VAL_1 - [7:0] */ | ||
972 | #define WM8904_DCS_DAC_WR_VAL_1_WIDTH 8 /* DCS_DAC_WR_VAL_1 - [7:0] */ | ||
973 | |||
974 | /* | ||
975 | * R76 (0x4C) - DC Servo 9 | ||
976 | */ | ||
977 | #define WM8904_DCS_DAC_WR_VAL_0_MASK 0x00FF /* DCS_DAC_WR_VAL_0 - [7:0] */ | ||
978 | #define WM8904_DCS_DAC_WR_VAL_0_SHIFT 0 /* DCS_DAC_WR_VAL_0 - [7:0] */ | ||
979 | #define WM8904_DCS_DAC_WR_VAL_0_WIDTH 8 /* DCS_DAC_WR_VAL_0 - [7:0] */ | ||
980 | |||
981 | /* | ||
982 | * R77 (0x4D) - DC Servo Readback 0 | ||
983 | */ | ||
984 | #define WM8904_DCS_CAL_COMPLETE_MASK 0x0F00 /* DCS_CAL_COMPLETE - [11:8] */ | ||
985 | #define WM8904_DCS_CAL_COMPLETE_SHIFT 8 /* DCS_CAL_COMPLETE - [11:8] */ | ||
986 | #define WM8904_DCS_CAL_COMPLETE_WIDTH 4 /* DCS_CAL_COMPLETE - [11:8] */ | ||
987 | #define WM8904_DCS_DAC_WR_COMPLETE_MASK 0x00F0 /* DCS_DAC_WR_COMPLETE - [7:4] */ | ||
988 | #define WM8904_DCS_DAC_WR_COMPLETE_SHIFT 4 /* DCS_DAC_WR_COMPLETE - [7:4] */ | ||
989 | #define WM8904_DCS_DAC_WR_COMPLETE_WIDTH 4 /* DCS_DAC_WR_COMPLETE - [7:4] */ | ||
990 | #define WM8904_DCS_STARTUP_COMPLETE_MASK 0x000F /* DCS_STARTUP_COMPLETE - [3:0] */ | ||
991 | #define WM8904_DCS_STARTUP_COMPLETE_SHIFT 0 /* DCS_STARTUP_COMPLETE - [3:0] */ | ||
992 | #define WM8904_DCS_STARTUP_COMPLETE_WIDTH 4 /* DCS_STARTUP_COMPLETE - [3:0] */ | ||
993 | |||
994 | /* | ||
995 | * R90 (0x5A) - Analogue HP 0 | ||
996 | */ | ||
997 | #define WM8904_HPL_RMV_SHORT 0x0080 /* HPL_RMV_SHORT */ | ||
998 | #define WM8904_HPL_RMV_SHORT_MASK 0x0080 /* HPL_RMV_SHORT */ | ||
999 | #define WM8904_HPL_RMV_SHORT_SHIFT 7 /* HPL_RMV_SHORT */ | ||
1000 | #define WM8904_HPL_RMV_SHORT_WIDTH 1 /* HPL_RMV_SHORT */ | ||
1001 | #define WM8904_HPL_ENA_OUTP 0x0040 /* HPL_ENA_OUTP */ | ||
1002 | #define WM8904_HPL_ENA_OUTP_MASK 0x0040 /* HPL_ENA_OUTP */ | ||
1003 | #define WM8904_HPL_ENA_OUTP_SHIFT 6 /* HPL_ENA_OUTP */ | ||
1004 | #define WM8904_HPL_ENA_OUTP_WIDTH 1 /* HPL_ENA_OUTP */ | ||
1005 | #define WM8904_HPL_ENA_DLY 0x0020 /* HPL_ENA_DLY */ | ||
1006 | #define WM8904_HPL_ENA_DLY_MASK 0x0020 /* HPL_ENA_DLY */ | ||
1007 | #define WM8904_HPL_ENA_DLY_SHIFT 5 /* HPL_ENA_DLY */ | ||
1008 | #define WM8904_HPL_ENA_DLY_WIDTH 1 /* HPL_ENA_DLY */ | ||
1009 | #define WM8904_HPL_ENA 0x0010 /* HPL_ENA */ | ||
1010 | #define WM8904_HPL_ENA_MASK 0x0010 /* HPL_ENA */ | ||
1011 | #define WM8904_HPL_ENA_SHIFT 4 /* HPL_ENA */ | ||
1012 | #define WM8904_HPL_ENA_WIDTH 1 /* HPL_ENA */ | ||
1013 | #define WM8904_HPR_RMV_SHORT 0x0008 /* HPR_RMV_SHORT */ | ||
1014 | #define WM8904_HPR_RMV_SHORT_MASK 0x0008 /* HPR_RMV_SHORT */ | ||
1015 | #define WM8904_HPR_RMV_SHORT_SHIFT 3 /* HPR_RMV_SHORT */ | ||
1016 | #define WM8904_HPR_RMV_SHORT_WIDTH 1 /* HPR_RMV_SHORT */ | ||
1017 | #define WM8904_HPR_ENA_OUTP 0x0004 /* HPR_ENA_OUTP */ | ||
1018 | #define WM8904_HPR_ENA_OUTP_MASK 0x0004 /* HPR_ENA_OUTP */ | ||
1019 | #define WM8904_HPR_ENA_OUTP_SHIFT 2 /* HPR_ENA_OUTP */ | ||
1020 | #define WM8904_HPR_ENA_OUTP_WIDTH 1 /* HPR_ENA_OUTP */ | ||
1021 | #define WM8904_HPR_ENA_DLY 0x0002 /* HPR_ENA_DLY */ | ||
1022 | #define WM8904_HPR_ENA_DLY_MASK 0x0002 /* HPR_ENA_DLY */ | ||
1023 | #define WM8904_HPR_ENA_DLY_SHIFT 1 /* HPR_ENA_DLY */ | ||
1024 | #define WM8904_HPR_ENA_DLY_WIDTH 1 /* HPR_ENA_DLY */ | ||
1025 | #define WM8904_HPR_ENA 0x0001 /* HPR_ENA */ | ||
1026 | #define WM8904_HPR_ENA_MASK 0x0001 /* HPR_ENA */ | ||
1027 | #define WM8904_HPR_ENA_SHIFT 0 /* HPR_ENA */ | ||
1028 | #define WM8904_HPR_ENA_WIDTH 1 /* HPR_ENA */ | ||
1029 | |||
1030 | /* | ||
1031 | * R94 (0x5E) - Analogue Lineout 0 | ||
1032 | */ | ||
1033 | #define WM8904_LINEOUTL_RMV_SHORT 0x0080 /* LINEOUTL_RMV_SHORT */ | ||
1034 | #define WM8904_LINEOUTL_RMV_SHORT_MASK 0x0080 /* LINEOUTL_RMV_SHORT */ | ||
1035 | #define WM8904_LINEOUTL_RMV_SHORT_SHIFT 7 /* LINEOUTL_RMV_SHORT */ | ||
1036 | #define WM8904_LINEOUTL_RMV_SHORT_WIDTH 1 /* LINEOUTL_RMV_SHORT */ | ||
1037 | #define WM8904_LINEOUTL_ENA_OUTP 0x0040 /* LINEOUTL_ENA_OUTP */ | ||
1038 | #define WM8904_LINEOUTL_ENA_OUTP_MASK 0x0040 /* LINEOUTL_ENA_OUTP */ | ||
1039 | #define WM8904_LINEOUTL_ENA_OUTP_SHIFT 6 /* LINEOUTL_ENA_OUTP */ | ||
1040 | #define WM8904_LINEOUTL_ENA_OUTP_WIDTH 1 /* LINEOUTL_ENA_OUTP */ | ||
1041 | #define WM8904_LINEOUTL_ENA_DLY 0x0020 /* LINEOUTL_ENA_DLY */ | ||
1042 | #define WM8904_LINEOUTL_ENA_DLY_MASK 0x0020 /* LINEOUTL_ENA_DLY */ | ||
1043 | #define WM8904_LINEOUTL_ENA_DLY_SHIFT 5 /* LINEOUTL_ENA_DLY */ | ||
1044 | #define WM8904_LINEOUTL_ENA_DLY_WIDTH 1 /* LINEOUTL_ENA_DLY */ | ||
1045 | #define WM8904_LINEOUTL_ENA 0x0010 /* LINEOUTL_ENA */ | ||
1046 | #define WM8904_LINEOUTL_ENA_MASK 0x0010 /* LINEOUTL_ENA */ | ||
1047 | #define WM8904_LINEOUTL_ENA_SHIFT 4 /* LINEOUTL_ENA */ | ||
1048 | #define WM8904_LINEOUTL_ENA_WIDTH 1 /* LINEOUTL_ENA */ | ||
1049 | #define WM8904_LINEOUTR_RMV_SHORT 0x0008 /* LINEOUTR_RMV_SHORT */ | ||
1050 | #define WM8904_LINEOUTR_RMV_SHORT_MASK 0x0008 /* LINEOUTR_RMV_SHORT */ | ||
1051 | #define WM8904_LINEOUTR_RMV_SHORT_SHIFT 3 /* LINEOUTR_RMV_SHORT */ | ||
1052 | #define WM8904_LINEOUTR_RMV_SHORT_WIDTH 1 /* LINEOUTR_RMV_SHORT */ | ||
1053 | #define WM8904_LINEOUTR_ENA_OUTP 0x0004 /* LINEOUTR_ENA_OUTP */ | ||
1054 | #define WM8904_LINEOUTR_ENA_OUTP_MASK 0x0004 /* LINEOUTR_ENA_OUTP */ | ||
1055 | #define WM8904_LINEOUTR_ENA_OUTP_SHIFT 2 /* LINEOUTR_ENA_OUTP */ | ||
1056 | #define WM8904_LINEOUTR_ENA_OUTP_WIDTH 1 /* LINEOUTR_ENA_OUTP */ | ||
1057 | #define WM8904_LINEOUTR_ENA_DLY 0x0002 /* LINEOUTR_ENA_DLY */ | ||
1058 | #define WM8904_LINEOUTR_ENA_DLY_MASK 0x0002 /* LINEOUTR_ENA_DLY */ | ||
1059 | #define WM8904_LINEOUTR_ENA_DLY_SHIFT 1 /* LINEOUTR_ENA_DLY */ | ||
1060 | #define WM8904_LINEOUTR_ENA_DLY_WIDTH 1 /* LINEOUTR_ENA_DLY */ | ||
1061 | #define WM8904_LINEOUTR_ENA 0x0001 /* LINEOUTR_ENA */ | ||
1062 | #define WM8904_LINEOUTR_ENA_MASK 0x0001 /* LINEOUTR_ENA */ | ||
1063 | #define WM8904_LINEOUTR_ENA_SHIFT 0 /* LINEOUTR_ENA */ | ||
1064 | #define WM8904_LINEOUTR_ENA_WIDTH 1 /* LINEOUTR_ENA */ | ||
1065 | |||
1066 | /* | ||
1067 | * R98 (0x62) - Charge Pump 0 | ||
1068 | */ | ||
1069 | #define WM8904_CP_ENA 0x0001 /* CP_ENA */ | ||
1070 | #define WM8904_CP_ENA_MASK 0x0001 /* CP_ENA */ | ||
1071 | #define WM8904_CP_ENA_SHIFT 0 /* CP_ENA */ | ||
1072 | #define WM8904_CP_ENA_WIDTH 1 /* CP_ENA */ | ||
1073 | |||
1074 | /* | ||
1075 | * R104 (0x68) - Class W 0 | ||
1076 | */ | ||
1077 | #define WM8904_CP_DYN_PWR 0x0001 /* CP_DYN_PWR */ | ||
1078 | #define WM8904_CP_DYN_PWR_MASK 0x0001 /* CP_DYN_PWR */ | ||
1079 | #define WM8904_CP_DYN_PWR_SHIFT 0 /* CP_DYN_PWR */ | ||
1080 | #define WM8904_CP_DYN_PWR_WIDTH 1 /* CP_DYN_PWR */ | ||
1081 | |||
1082 | /* | ||
1083 | * R108 (0x6C) - Write Sequencer 0 | ||
1084 | */ | ||
1085 | #define WM8904_WSEQ_ENA 0x0100 /* WSEQ_ENA */ | ||
1086 | #define WM8904_WSEQ_ENA_MASK 0x0100 /* WSEQ_ENA */ | ||
1087 | #define WM8904_WSEQ_ENA_SHIFT 8 /* WSEQ_ENA */ | ||
1088 | #define WM8904_WSEQ_ENA_WIDTH 1 /* WSEQ_ENA */ | ||
1089 | #define WM8904_WSEQ_WRITE_INDEX_MASK 0x001F /* WSEQ_WRITE_INDEX - [4:0] */ | ||
1090 | #define WM8904_WSEQ_WRITE_INDEX_SHIFT 0 /* WSEQ_WRITE_INDEX - [4:0] */ | ||
1091 | #define WM8904_WSEQ_WRITE_INDEX_WIDTH 5 /* WSEQ_WRITE_INDEX - [4:0] */ | ||
1092 | |||
1093 | /* | ||
1094 | * R109 (0x6D) - Write Sequencer 1 | ||
1095 | */ | ||
1096 | #define WM8904_WSEQ_DATA_WIDTH_MASK 0x7000 /* WSEQ_DATA_WIDTH - [14:12] */ | ||
1097 | #define WM8904_WSEQ_DATA_WIDTH_SHIFT 12 /* WSEQ_DATA_WIDTH - [14:12] */ | ||
1098 | #define WM8904_WSEQ_DATA_WIDTH_WIDTH 3 /* WSEQ_DATA_WIDTH - [14:12] */ | ||
1099 | #define WM8904_WSEQ_DATA_START_MASK 0x0F00 /* WSEQ_DATA_START - [11:8] */ | ||
1100 | #define WM8904_WSEQ_DATA_START_SHIFT 8 /* WSEQ_DATA_START - [11:8] */ | ||
1101 | #define WM8904_WSEQ_DATA_START_WIDTH 4 /* WSEQ_DATA_START - [11:8] */ | ||
1102 | #define WM8904_WSEQ_ADDR_MASK 0x00FF /* WSEQ_ADDR - [7:0] */ | ||
1103 | #define WM8904_WSEQ_ADDR_SHIFT 0 /* WSEQ_ADDR - [7:0] */ | ||
1104 | #define WM8904_WSEQ_ADDR_WIDTH 8 /* WSEQ_ADDR - [7:0] */ | ||
1105 | |||
1106 | /* | ||
1107 | * R110 (0x6E) - Write Sequencer 2 | ||
1108 | */ | ||
1109 | #define WM8904_WSEQ_EOS 0x4000 /* WSEQ_EOS */ | ||
1110 | #define WM8904_WSEQ_EOS_MASK 0x4000 /* WSEQ_EOS */ | ||
1111 | #define WM8904_WSEQ_EOS_SHIFT 14 /* WSEQ_EOS */ | ||
1112 | #define WM8904_WSEQ_EOS_WIDTH 1 /* WSEQ_EOS */ | ||
1113 | #define WM8904_WSEQ_DELAY_MASK 0x0F00 /* WSEQ_DELAY - [11:8] */ | ||
1114 | #define WM8904_WSEQ_DELAY_SHIFT 8 /* WSEQ_DELAY - [11:8] */ | ||
1115 | #define WM8904_WSEQ_DELAY_WIDTH 4 /* WSEQ_DELAY - [11:8] */ | ||
1116 | #define WM8904_WSEQ_DATA_MASK 0x00FF /* WSEQ_DATA - [7:0] */ | ||
1117 | #define WM8904_WSEQ_DATA_SHIFT 0 /* WSEQ_DATA - [7:0] */ | ||
1118 | #define WM8904_WSEQ_DATA_WIDTH 8 /* WSEQ_DATA - [7:0] */ | ||
1119 | |||
1120 | /* | ||
1121 | * R111 (0x6F) - Write Sequencer 3 | ||
1122 | */ | ||
1123 | #define WM8904_WSEQ_ABORT 0x0200 /* WSEQ_ABORT */ | ||
1124 | #define WM8904_WSEQ_ABORT_MASK 0x0200 /* WSEQ_ABORT */ | ||
1125 | #define WM8904_WSEQ_ABORT_SHIFT 9 /* WSEQ_ABORT */ | ||
1126 | #define WM8904_WSEQ_ABORT_WIDTH 1 /* WSEQ_ABORT */ | ||
1127 | #define WM8904_WSEQ_START 0x0100 /* WSEQ_START */ | ||
1128 | #define WM8904_WSEQ_START_MASK 0x0100 /* WSEQ_START */ | ||
1129 | #define WM8904_WSEQ_START_SHIFT 8 /* WSEQ_START */ | ||
1130 | #define WM8904_WSEQ_START_WIDTH 1 /* WSEQ_START */ | ||
1131 | #define WM8904_WSEQ_START_INDEX_MASK 0x003F /* WSEQ_START_INDEX - [5:0] */ | ||
1132 | #define WM8904_WSEQ_START_INDEX_SHIFT 0 /* WSEQ_START_INDEX - [5:0] */ | ||
1133 | #define WM8904_WSEQ_START_INDEX_WIDTH 6 /* WSEQ_START_INDEX - [5:0] */ | ||
1134 | |||
1135 | /* | ||
1136 | * R112 (0x70) - Write Sequencer 4 | ||
1137 | */ | ||
1138 | #define WM8904_WSEQ_CURRENT_INDEX_MASK 0x03F0 /* WSEQ_CURRENT_INDEX - [9:4] */ | ||
1139 | #define WM8904_WSEQ_CURRENT_INDEX_SHIFT 4 /* WSEQ_CURRENT_INDEX - [9:4] */ | ||
1140 | #define WM8904_WSEQ_CURRENT_INDEX_WIDTH 6 /* WSEQ_CURRENT_INDEX - [9:4] */ | ||
1141 | #define WM8904_WSEQ_BUSY 0x0001 /* WSEQ_BUSY */ | ||
1142 | #define WM8904_WSEQ_BUSY_MASK 0x0001 /* WSEQ_BUSY */ | ||
1143 | #define WM8904_WSEQ_BUSY_SHIFT 0 /* WSEQ_BUSY */ | ||
1144 | #define WM8904_WSEQ_BUSY_WIDTH 1 /* WSEQ_BUSY */ | ||
1145 | |||
1146 | /* | ||
1147 | * R116 (0x74) - FLL Control 1 | ||
1148 | */ | ||
1149 | #define WM8904_FLL_FRACN_ENA 0x0004 /* FLL_FRACN_ENA */ | ||
1150 | #define WM8904_FLL_FRACN_ENA_MASK 0x0004 /* FLL_FRACN_ENA */ | ||
1151 | #define WM8904_FLL_FRACN_ENA_SHIFT 2 /* FLL_FRACN_ENA */ | ||
1152 | #define WM8904_FLL_FRACN_ENA_WIDTH 1 /* FLL_FRACN_ENA */ | ||
1153 | #define WM8904_FLL_OSC_ENA 0x0002 /* FLL_OSC_ENA */ | ||
1154 | #define WM8904_FLL_OSC_ENA_MASK 0x0002 /* FLL_OSC_ENA */ | ||
1155 | #define WM8904_FLL_OSC_ENA_SHIFT 1 /* FLL_OSC_ENA */ | ||
1156 | #define WM8904_FLL_OSC_ENA_WIDTH 1 /* FLL_OSC_ENA */ | ||
1157 | #define WM8904_FLL_ENA 0x0001 /* FLL_ENA */ | ||
1158 | #define WM8904_FLL_ENA_MASK 0x0001 /* FLL_ENA */ | ||
1159 | #define WM8904_FLL_ENA_SHIFT 0 /* FLL_ENA */ | ||
1160 | #define WM8904_FLL_ENA_WIDTH 1 /* FLL_ENA */ | ||
1161 | |||
1162 | /* | ||
1163 | * R117 (0x75) - FLL Control 2 | ||
1164 | */ | ||
1165 | #define WM8904_FLL_OUTDIV_MASK 0x3F00 /* FLL_OUTDIV - [13:8] */ | ||
1166 | #define WM8904_FLL_OUTDIV_SHIFT 8 /* FLL_OUTDIV - [13:8] */ | ||
1167 | #define WM8904_FLL_OUTDIV_WIDTH 6 /* FLL_OUTDIV - [13:8] */ | ||
1168 | #define WM8904_FLL_CTRL_RATE_MASK 0x0070 /* FLL_CTRL_RATE - [6:4] */ | ||
1169 | #define WM8904_FLL_CTRL_RATE_SHIFT 4 /* FLL_CTRL_RATE - [6:4] */ | ||
1170 | #define WM8904_FLL_CTRL_RATE_WIDTH 3 /* FLL_CTRL_RATE - [6:4] */ | ||
1171 | #define WM8904_FLL_FRATIO_MASK 0x0007 /* FLL_FRATIO - [2:0] */ | ||
1172 | #define WM8904_FLL_FRATIO_SHIFT 0 /* FLL_FRATIO - [2:0] */ | ||
1173 | #define WM8904_FLL_FRATIO_WIDTH 3 /* FLL_FRATIO - [2:0] */ | ||
1174 | |||
1175 | /* | ||
1176 | * R118 (0x76) - FLL Control 3 | ||
1177 | */ | ||
1178 | #define WM8904_FLL_K_MASK 0xFFFF /* FLL_K - [15:0] */ | ||
1179 | #define WM8904_FLL_K_SHIFT 0 /* FLL_K - [15:0] */ | ||
1180 | #define WM8904_FLL_K_WIDTH 16 /* FLL_K - [15:0] */ | ||
1181 | |||
1182 | /* | ||
1183 | * R119 (0x77) - FLL Control 4 | ||
1184 | */ | ||
1185 | #define WM8904_FLL_N_MASK 0x7FE0 /* FLL_N - [14:5] */ | ||
1186 | #define WM8904_FLL_N_SHIFT 5 /* FLL_N - [14:5] */ | ||
1187 | #define WM8904_FLL_N_WIDTH 10 /* FLL_N - [14:5] */ | ||
1188 | #define WM8904_FLL_GAIN_MASK 0x000F /* FLL_GAIN - [3:0] */ | ||
1189 | #define WM8904_FLL_GAIN_SHIFT 0 /* FLL_GAIN - [3:0] */ | ||
1190 | #define WM8904_FLL_GAIN_WIDTH 4 /* FLL_GAIN - [3:0] */ | ||
1191 | |||
1192 | /* | ||
1193 | * R120 (0x78) - FLL Control 5 | ||
1194 | */ | ||
1195 | #define WM8904_FLL_CLK_REF_DIV_MASK 0x0018 /* FLL_CLK_REF_DIV - [4:3] */ | ||
1196 | #define WM8904_FLL_CLK_REF_DIV_SHIFT 3 /* FLL_CLK_REF_DIV - [4:3] */ | ||
1197 | #define WM8904_FLL_CLK_REF_DIV_WIDTH 2 /* FLL_CLK_REF_DIV - [4:3] */ | ||
1198 | #define WM8904_FLL_CLK_REF_SRC_MASK 0x0003 /* FLL_CLK_REF_SRC - [1:0] */ | ||
1199 | #define WM8904_FLL_CLK_REF_SRC_SHIFT 0 /* FLL_CLK_REF_SRC - [1:0] */ | ||
1200 | #define WM8904_FLL_CLK_REF_SRC_WIDTH 2 /* FLL_CLK_REF_SRC - [1:0] */ | ||
1201 | |||
1202 | /* | ||
1203 | * R121 (0x79) - GPIO Control 1 | ||
1204 | */ | ||
1205 | #define WM8904_GPIO1_PU 0x0020 /* GPIO1_PU */ | ||
1206 | #define WM8904_GPIO1_PU_MASK 0x0020 /* GPIO1_PU */ | ||
1207 | #define WM8904_GPIO1_PU_SHIFT 5 /* GPIO1_PU */ | ||
1208 | #define WM8904_GPIO1_PU_WIDTH 1 /* GPIO1_PU */ | ||
1209 | #define WM8904_GPIO1_PD 0x0010 /* GPIO1_PD */ | ||
1210 | #define WM8904_GPIO1_PD_MASK 0x0010 /* GPIO1_PD */ | ||
1211 | #define WM8904_GPIO1_PD_SHIFT 4 /* GPIO1_PD */ | ||
1212 | #define WM8904_GPIO1_PD_WIDTH 1 /* GPIO1_PD */ | ||
1213 | #define WM8904_GPIO1_SEL_MASK 0x000F /* GPIO1_SEL - [3:0] */ | ||
1214 | #define WM8904_GPIO1_SEL_SHIFT 0 /* GPIO1_SEL - [3:0] */ | ||
1215 | #define WM8904_GPIO1_SEL_WIDTH 4 /* GPIO1_SEL - [3:0] */ | ||
1216 | |||
1217 | /* | ||
1218 | * R122 (0x7A) - GPIO Control 2 | ||
1219 | */ | ||
1220 | #define WM8904_GPIO2_PU 0x0020 /* GPIO2_PU */ | ||
1221 | #define WM8904_GPIO2_PU_MASK 0x0020 /* GPIO2_PU */ | ||
1222 | #define WM8904_GPIO2_PU_SHIFT 5 /* GPIO2_PU */ | ||
1223 | #define WM8904_GPIO2_PU_WIDTH 1 /* GPIO2_PU */ | ||
1224 | #define WM8904_GPIO2_PD 0x0010 /* GPIO2_PD */ | ||
1225 | #define WM8904_GPIO2_PD_MASK 0x0010 /* GPIO2_PD */ | ||
1226 | #define WM8904_GPIO2_PD_SHIFT 4 /* GPIO2_PD */ | ||
1227 | #define WM8904_GPIO2_PD_WIDTH 1 /* GPIO2_PD */ | ||
1228 | #define WM8904_GPIO2_SEL_MASK 0x000F /* GPIO2_SEL - [3:0] */ | ||
1229 | #define WM8904_GPIO2_SEL_SHIFT 0 /* GPIO2_SEL - [3:0] */ | ||
1230 | #define WM8904_GPIO2_SEL_WIDTH 4 /* GPIO2_SEL - [3:0] */ | ||
1231 | |||
1232 | /* | ||
1233 | * R123 (0x7B) - GPIO Control 3 | ||
1234 | */ | ||
1235 | #define WM8904_GPIO3_PU 0x0020 /* GPIO3_PU */ | ||
1236 | #define WM8904_GPIO3_PU_MASK 0x0020 /* GPIO3_PU */ | ||
1237 | #define WM8904_GPIO3_PU_SHIFT 5 /* GPIO3_PU */ | ||
1238 | #define WM8904_GPIO3_PU_WIDTH 1 /* GPIO3_PU */ | ||
1239 | #define WM8904_GPIO3_PD 0x0010 /* GPIO3_PD */ | ||
1240 | #define WM8904_GPIO3_PD_MASK 0x0010 /* GPIO3_PD */ | ||
1241 | #define WM8904_GPIO3_PD_SHIFT 4 /* GPIO3_PD */ | ||
1242 | #define WM8904_GPIO3_PD_WIDTH 1 /* GPIO3_PD */ | ||
1243 | #define WM8904_GPIO3_SEL_MASK 0x000F /* GPIO3_SEL - [3:0] */ | ||
1244 | #define WM8904_GPIO3_SEL_SHIFT 0 /* GPIO3_SEL - [3:0] */ | ||
1245 | #define WM8904_GPIO3_SEL_WIDTH 4 /* GPIO3_SEL - [3:0] */ | ||
1246 | |||
1247 | /* | ||
1248 | * R124 (0x7C) - GPIO Control 4 | ||
1249 | */ | ||
1250 | #define WM8904_GPI7_ENA 0x0200 /* GPI7_ENA */ | ||
1251 | #define WM8904_GPI7_ENA_MASK 0x0200 /* GPI7_ENA */ | ||
1252 | #define WM8904_GPI7_ENA_SHIFT 9 /* GPI7_ENA */ | ||
1253 | #define WM8904_GPI7_ENA_WIDTH 1 /* GPI7_ENA */ | ||
1254 | #define WM8904_GPI8_ENA 0x0100 /* GPI8_ENA */ | ||
1255 | #define WM8904_GPI8_ENA_MASK 0x0100 /* GPI8_ENA */ | ||
1256 | #define WM8904_GPI8_ENA_SHIFT 8 /* GPI8_ENA */ | ||
1257 | #define WM8904_GPI8_ENA_WIDTH 1 /* GPI8_ENA */ | ||
1258 | #define WM8904_GPIO_BCLK_MODE_ENA 0x0080 /* GPIO_BCLK_MODE_ENA */ | ||
1259 | #define WM8904_GPIO_BCLK_MODE_ENA_MASK 0x0080 /* GPIO_BCLK_MODE_ENA */ | ||
1260 | #define WM8904_GPIO_BCLK_MODE_ENA_SHIFT 7 /* GPIO_BCLK_MODE_ENA */ | ||
1261 | #define WM8904_GPIO_BCLK_MODE_ENA_WIDTH 1 /* GPIO_BCLK_MODE_ENA */ | ||
1262 | #define WM8904_GPIO_BCLK_SEL_MASK 0x000F /* GPIO_BCLK_SEL - [3:0] */ | ||
1263 | #define WM8904_GPIO_BCLK_SEL_SHIFT 0 /* GPIO_BCLK_SEL - [3:0] */ | ||
1264 | #define WM8904_GPIO_BCLK_SEL_WIDTH 4 /* GPIO_BCLK_SEL - [3:0] */ | ||
1265 | |||
1266 | /* | ||
1267 | * R126 (0x7E) - Digital Pulls | ||
1268 | */ | ||
1269 | #define WM8904_MCLK_PU 0x0080 /* MCLK_PU */ | ||
1270 | #define WM8904_MCLK_PU_MASK 0x0080 /* MCLK_PU */ | ||
1271 | #define WM8904_MCLK_PU_SHIFT 7 /* MCLK_PU */ | ||
1272 | #define WM8904_MCLK_PU_WIDTH 1 /* MCLK_PU */ | ||
1273 | #define WM8904_MCLK_PD 0x0040 /* MCLK_PD */ | ||
1274 | #define WM8904_MCLK_PD_MASK 0x0040 /* MCLK_PD */ | ||
1275 | #define WM8904_MCLK_PD_SHIFT 6 /* MCLK_PD */ | ||
1276 | #define WM8904_MCLK_PD_WIDTH 1 /* MCLK_PD */ | ||
1277 | #define WM8904_DACDAT_PU 0x0020 /* DACDAT_PU */ | ||
1278 | #define WM8904_DACDAT_PU_MASK 0x0020 /* DACDAT_PU */ | ||
1279 | #define WM8904_DACDAT_PU_SHIFT 5 /* DACDAT_PU */ | ||
1280 | #define WM8904_DACDAT_PU_WIDTH 1 /* DACDAT_PU */ | ||
1281 | #define WM8904_DACDAT_PD 0x0010 /* DACDAT_PD */ | ||
1282 | #define WM8904_DACDAT_PD_MASK 0x0010 /* DACDAT_PD */ | ||
1283 | #define WM8904_DACDAT_PD_SHIFT 4 /* DACDAT_PD */ | ||
1284 | #define WM8904_DACDAT_PD_WIDTH 1 /* DACDAT_PD */ | ||
1285 | #define WM8904_LRCLK_PU 0x0008 /* LRCLK_PU */ | ||
1286 | #define WM8904_LRCLK_PU_MASK 0x0008 /* LRCLK_PU */ | ||
1287 | #define WM8904_LRCLK_PU_SHIFT 3 /* LRCLK_PU */ | ||
1288 | #define WM8904_LRCLK_PU_WIDTH 1 /* LRCLK_PU */ | ||
1289 | #define WM8904_LRCLK_PD 0x0004 /* LRCLK_PD */ | ||
1290 | #define WM8904_LRCLK_PD_MASK 0x0004 /* LRCLK_PD */ | ||
1291 | #define WM8904_LRCLK_PD_SHIFT 2 /* LRCLK_PD */ | ||
1292 | #define WM8904_LRCLK_PD_WIDTH 1 /* LRCLK_PD */ | ||
1293 | #define WM8904_BCLK_PU 0x0002 /* BCLK_PU */ | ||
1294 | #define WM8904_BCLK_PU_MASK 0x0002 /* BCLK_PU */ | ||
1295 | #define WM8904_BCLK_PU_SHIFT 1 /* BCLK_PU */ | ||
1296 | #define WM8904_BCLK_PU_WIDTH 1 /* BCLK_PU */ | ||
1297 | #define WM8904_BCLK_PD 0x0001 /* BCLK_PD */ | ||
1298 | #define WM8904_BCLK_PD_MASK 0x0001 /* BCLK_PD */ | ||
1299 | #define WM8904_BCLK_PD_SHIFT 0 /* BCLK_PD */ | ||
1300 | #define WM8904_BCLK_PD_WIDTH 1 /* BCLK_PD */ | ||
1301 | |||
1302 | /* | ||
1303 | * R127 (0x7F) - Interrupt Status | ||
1304 | */ | ||
1305 | #define WM8904_IRQ 0x0400 /* IRQ */ | ||
1306 | #define WM8904_IRQ_MASK 0x0400 /* IRQ */ | ||
1307 | #define WM8904_IRQ_SHIFT 10 /* IRQ */ | ||
1308 | #define WM8904_IRQ_WIDTH 1 /* IRQ */ | ||
1309 | #define WM8904_GPIO_BCLK_EINT 0x0200 /* GPIO_BCLK_EINT */ | ||
1310 | #define WM8904_GPIO_BCLK_EINT_MASK 0x0200 /* GPIO_BCLK_EINT */ | ||
1311 | #define WM8904_GPIO_BCLK_EINT_SHIFT 9 /* GPIO_BCLK_EINT */ | ||
1312 | #define WM8904_GPIO_BCLK_EINT_WIDTH 1 /* GPIO_BCLK_EINT */ | ||
1313 | #define WM8904_WSEQ_EINT 0x0100 /* WSEQ_EINT */ | ||
1314 | #define WM8904_WSEQ_EINT_MASK 0x0100 /* WSEQ_EINT */ | ||
1315 | #define WM8904_WSEQ_EINT_SHIFT 8 /* WSEQ_EINT */ | ||
1316 | #define WM8904_WSEQ_EINT_WIDTH 1 /* WSEQ_EINT */ | ||
1317 | #define WM8904_GPIO3_EINT 0x0080 /* GPIO3_EINT */ | ||
1318 | #define WM8904_GPIO3_EINT_MASK 0x0080 /* GPIO3_EINT */ | ||
1319 | #define WM8904_GPIO3_EINT_SHIFT 7 /* GPIO3_EINT */ | ||
1320 | #define WM8904_GPIO3_EINT_WIDTH 1 /* GPIO3_EINT */ | ||
1321 | #define WM8904_GPIO2_EINT 0x0040 /* GPIO2_EINT */ | ||
1322 | #define WM8904_GPIO2_EINT_MASK 0x0040 /* GPIO2_EINT */ | ||
1323 | #define WM8904_GPIO2_EINT_SHIFT 6 /* GPIO2_EINT */ | ||
1324 | #define WM8904_GPIO2_EINT_WIDTH 1 /* GPIO2_EINT */ | ||
1325 | #define WM8904_GPIO1_EINT 0x0020 /* GPIO1_EINT */ | ||
1326 | #define WM8904_GPIO1_EINT_MASK 0x0020 /* GPIO1_EINT */ | ||
1327 | #define WM8904_GPIO1_EINT_SHIFT 5 /* GPIO1_EINT */ | ||
1328 | #define WM8904_GPIO1_EINT_WIDTH 1 /* GPIO1_EINT */ | ||
1329 | #define WM8904_GPI8_EINT 0x0010 /* GPI8_EINT */ | ||
1330 | #define WM8904_GPI8_EINT_MASK 0x0010 /* GPI8_EINT */ | ||
1331 | #define WM8904_GPI8_EINT_SHIFT 4 /* GPI8_EINT */ | ||
1332 | #define WM8904_GPI8_EINT_WIDTH 1 /* GPI8_EINT */ | ||
1333 | #define WM8904_GPI7_EINT 0x0008 /* GPI7_EINT */ | ||
1334 | #define WM8904_GPI7_EINT_MASK 0x0008 /* GPI7_EINT */ | ||
1335 | #define WM8904_GPI7_EINT_SHIFT 3 /* GPI7_EINT */ | ||
1336 | #define WM8904_GPI7_EINT_WIDTH 1 /* GPI7_EINT */ | ||
1337 | #define WM8904_FLL_LOCK_EINT 0x0004 /* FLL_LOCK_EINT */ | ||
1338 | #define WM8904_FLL_LOCK_EINT_MASK 0x0004 /* FLL_LOCK_EINT */ | ||
1339 | #define WM8904_FLL_LOCK_EINT_SHIFT 2 /* FLL_LOCK_EINT */ | ||
1340 | #define WM8904_FLL_LOCK_EINT_WIDTH 1 /* FLL_LOCK_EINT */ | ||
1341 | #define WM8904_MIC_SHRT_EINT 0x0002 /* MIC_SHRT_EINT */ | ||
1342 | #define WM8904_MIC_SHRT_EINT_MASK 0x0002 /* MIC_SHRT_EINT */ | ||
1343 | #define WM8904_MIC_SHRT_EINT_SHIFT 1 /* MIC_SHRT_EINT */ | ||
1344 | #define WM8904_MIC_SHRT_EINT_WIDTH 1 /* MIC_SHRT_EINT */ | ||
1345 | #define WM8904_MIC_DET_EINT 0x0001 /* MIC_DET_EINT */ | ||
1346 | #define WM8904_MIC_DET_EINT_MASK 0x0001 /* MIC_DET_EINT */ | ||
1347 | #define WM8904_MIC_DET_EINT_SHIFT 0 /* MIC_DET_EINT */ | ||
1348 | #define WM8904_MIC_DET_EINT_WIDTH 1 /* MIC_DET_EINT */ | ||
1349 | |||
1350 | /* | ||
1351 | * R128 (0x80) - Interrupt Status Mask | ||
1352 | */ | ||
1353 | #define WM8904_IM_GPIO_BCLK_EINT 0x0200 /* IM_GPIO_BCLK_EINT */ | ||
1354 | #define WM8904_IM_GPIO_BCLK_EINT_MASK 0x0200 /* IM_GPIO_BCLK_EINT */ | ||
1355 | #define WM8904_IM_GPIO_BCLK_EINT_SHIFT 9 /* IM_GPIO_BCLK_EINT */ | ||
1356 | #define WM8904_IM_GPIO_BCLK_EINT_WIDTH 1 /* IM_GPIO_BCLK_EINT */ | ||
1357 | #define WM8904_IM_WSEQ_EINT 0x0100 /* IM_WSEQ_EINT */ | ||
1358 | #define WM8904_IM_WSEQ_EINT_MASK 0x0100 /* IM_WSEQ_EINT */ | ||
1359 | #define WM8904_IM_WSEQ_EINT_SHIFT 8 /* IM_WSEQ_EINT */ | ||
1360 | #define WM8904_IM_WSEQ_EINT_WIDTH 1 /* IM_WSEQ_EINT */ | ||
1361 | #define WM8904_IM_GPIO3_EINT 0x0080 /* IM_GPIO3_EINT */ | ||
1362 | #define WM8904_IM_GPIO3_EINT_MASK 0x0080 /* IM_GPIO3_EINT */ | ||
1363 | #define WM8904_IM_GPIO3_EINT_SHIFT 7 /* IM_GPIO3_EINT */ | ||
1364 | #define WM8904_IM_GPIO3_EINT_WIDTH 1 /* IM_GPIO3_EINT */ | ||
1365 | #define WM8904_IM_GPIO2_EINT 0x0040 /* IM_GPIO2_EINT */ | ||
1366 | #define WM8904_IM_GPIO2_EINT_MASK 0x0040 /* IM_GPIO2_EINT */ | ||
1367 | #define WM8904_IM_GPIO2_EINT_SHIFT 6 /* IM_GPIO2_EINT */ | ||
1368 | #define WM8904_IM_GPIO2_EINT_WIDTH 1 /* IM_GPIO2_EINT */ | ||
1369 | #define WM8904_IM_GPIO1_EINT 0x0020 /* IM_GPIO1_EINT */ | ||
1370 | #define WM8904_IM_GPIO1_EINT_MASK 0x0020 /* IM_GPIO1_EINT */ | ||
1371 | #define WM8904_IM_GPIO1_EINT_SHIFT 5 /* IM_GPIO1_EINT */ | ||
1372 | #define WM8904_IM_GPIO1_EINT_WIDTH 1 /* IM_GPIO1_EINT */ | ||
1373 | #define WM8904_IM_GPI8_EINT 0x0010 /* IM_GPI8_EINT */ | ||
1374 | #define WM8904_IM_GPI8_EINT_MASK 0x0010 /* IM_GPI8_EINT */ | ||
1375 | #define WM8904_IM_GPI8_EINT_SHIFT 4 /* IM_GPI8_EINT */ | ||
1376 | #define WM8904_IM_GPI8_EINT_WIDTH 1 /* IM_GPI8_EINT */ | ||
1377 | #define WM8904_IM_GPI7_EINT 0x0008 /* IM_GPI7_EINT */ | ||
1378 | #define WM8904_IM_GPI7_EINT_MASK 0x0008 /* IM_GPI7_EINT */ | ||
1379 | #define WM8904_IM_GPI7_EINT_SHIFT 3 /* IM_GPI7_EINT */ | ||
1380 | #define WM8904_IM_GPI7_EINT_WIDTH 1 /* IM_GPI7_EINT */ | ||
1381 | #define WM8904_IM_FLL_LOCK_EINT 0x0004 /* IM_FLL_LOCK_EINT */ | ||
1382 | #define WM8904_IM_FLL_LOCK_EINT_MASK 0x0004 /* IM_FLL_LOCK_EINT */ | ||
1383 | #define WM8904_IM_FLL_LOCK_EINT_SHIFT 2 /* IM_FLL_LOCK_EINT */ | ||
1384 | #define WM8904_IM_FLL_LOCK_EINT_WIDTH 1 /* IM_FLL_LOCK_EINT */ | ||
1385 | #define WM8904_IM_MIC_SHRT_EINT 0x0002 /* IM_MIC_SHRT_EINT */ | ||
1386 | #define WM8904_IM_MIC_SHRT_EINT_MASK 0x0002 /* IM_MIC_SHRT_EINT */ | ||
1387 | #define WM8904_IM_MIC_SHRT_EINT_SHIFT 1 /* IM_MIC_SHRT_EINT */ | ||
1388 | #define WM8904_IM_MIC_SHRT_EINT_WIDTH 1 /* IM_MIC_SHRT_EINT */ | ||
1389 | #define WM8904_IM_MIC_DET_EINT 0x0001 /* IM_MIC_DET_EINT */ | ||
1390 | #define WM8904_IM_MIC_DET_EINT_MASK 0x0001 /* IM_MIC_DET_EINT */ | ||
1391 | #define WM8904_IM_MIC_DET_EINT_SHIFT 0 /* IM_MIC_DET_EINT */ | ||
1392 | #define WM8904_IM_MIC_DET_EINT_WIDTH 1 /* IM_MIC_DET_EINT */ | ||
1393 | |||
1394 | /* | ||
1395 | * R129 (0x81) - Interrupt Polarity | ||
1396 | */ | ||
1397 | #define WM8904_GPIO_BCLK_EINT_POL 0x0200 /* GPIO_BCLK_EINT_POL */ | ||
1398 | #define WM8904_GPIO_BCLK_EINT_POL_MASK 0x0200 /* GPIO_BCLK_EINT_POL */ | ||
1399 | #define WM8904_GPIO_BCLK_EINT_POL_SHIFT 9 /* GPIO_BCLK_EINT_POL */ | ||
1400 | #define WM8904_GPIO_BCLK_EINT_POL_WIDTH 1 /* GPIO_BCLK_EINT_POL */ | ||
1401 | #define WM8904_WSEQ_EINT_POL 0x0100 /* WSEQ_EINT_POL */ | ||
1402 | #define WM8904_WSEQ_EINT_POL_MASK 0x0100 /* WSEQ_EINT_POL */ | ||
1403 | #define WM8904_WSEQ_EINT_POL_SHIFT 8 /* WSEQ_EINT_POL */ | ||
1404 | #define WM8904_WSEQ_EINT_POL_WIDTH 1 /* WSEQ_EINT_POL */ | ||
1405 | #define WM8904_GPIO3_EINT_POL 0x0080 /* GPIO3_EINT_POL */ | ||
1406 | #define WM8904_GPIO3_EINT_POL_MASK 0x0080 /* GPIO3_EINT_POL */ | ||
1407 | #define WM8904_GPIO3_EINT_POL_SHIFT 7 /* GPIO3_EINT_POL */ | ||
1408 | #define WM8904_GPIO3_EINT_POL_WIDTH 1 /* GPIO3_EINT_POL */ | ||
1409 | #define WM8904_GPIO2_EINT_POL 0x0040 /* GPIO2_EINT_POL */ | ||
1410 | #define WM8904_GPIO2_EINT_POL_MASK 0x0040 /* GPIO2_EINT_POL */ | ||
1411 | #define WM8904_GPIO2_EINT_POL_SHIFT 6 /* GPIO2_EINT_POL */ | ||
1412 | #define WM8904_GPIO2_EINT_POL_WIDTH 1 /* GPIO2_EINT_POL */ | ||
1413 | #define WM8904_GPIO1_EINT_POL 0x0020 /* GPIO1_EINT_POL */ | ||
1414 | #define WM8904_GPIO1_EINT_POL_MASK 0x0020 /* GPIO1_EINT_POL */ | ||
1415 | #define WM8904_GPIO1_EINT_POL_SHIFT 5 /* GPIO1_EINT_POL */ | ||
1416 | #define WM8904_GPIO1_EINT_POL_WIDTH 1 /* GPIO1_EINT_POL */ | ||
1417 | #define WM8904_GPI8_EINT_POL 0x0010 /* GPI8_EINT_POL */ | ||
1418 | #define WM8904_GPI8_EINT_POL_MASK 0x0010 /* GPI8_EINT_POL */ | ||
1419 | #define WM8904_GPI8_EINT_POL_SHIFT 4 /* GPI8_EINT_POL */ | ||
1420 | #define WM8904_GPI8_EINT_POL_WIDTH 1 /* GPI8_EINT_POL */ | ||
1421 | #define WM8904_GPI7_EINT_POL 0x0008 /* GPI7_EINT_POL */ | ||
1422 | #define WM8904_GPI7_EINT_POL_MASK 0x0008 /* GPI7_EINT_POL */ | ||
1423 | #define WM8904_GPI7_EINT_POL_SHIFT 3 /* GPI7_EINT_POL */ | ||
1424 | #define WM8904_GPI7_EINT_POL_WIDTH 1 /* GPI7_EINT_POL */ | ||
1425 | #define WM8904_FLL_LOCK_EINT_POL 0x0004 /* FLL_LOCK_EINT_POL */ | ||
1426 | #define WM8904_FLL_LOCK_EINT_POL_MASK 0x0004 /* FLL_LOCK_EINT_POL */ | ||
1427 | #define WM8904_FLL_LOCK_EINT_POL_SHIFT 2 /* FLL_LOCK_EINT_POL */ | ||
1428 | #define WM8904_FLL_LOCK_EINT_POL_WIDTH 1 /* FLL_LOCK_EINT_POL */ | ||
1429 | #define WM8904_MIC_SHRT_EINT_POL 0x0002 /* MIC_SHRT_EINT_POL */ | ||
1430 | #define WM8904_MIC_SHRT_EINT_POL_MASK 0x0002 /* MIC_SHRT_EINT_POL */ | ||
1431 | #define WM8904_MIC_SHRT_EINT_POL_SHIFT 1 /* MIC_SHRT_EINT_POL */ | ||
1432 | #define WM8904_MIC_SHRT_EINT_POL_WIDTH 1 /* MIC_SHRT_EINT_POL */ | ||
1433 | #define WM8904_MIC_DET_EINT_POL 0x0001 /* MIC_DET_EINT_POL */ | ||
1434 | #define WM8904_MIC_DET_EINT_POL_MASK 0x0001 /* MIC_DET_EINT_POL */ | ||
1435 | #define WM8904_MIC_DET_EINT_POL_SHIFT 0 /* MIC_DET_EINT_POL */ | ||
1436 | #define WM8904_MIC_DET_EINT_POL_WIDTH 1 /* MIC_DET_EINT_POL */ | ||
1437 | |||
1438 | /* | ||
1439 | * R130 (0x82) - Interrupt Debounce | ||
1440 | */ | ||
1441 | #define WM8904_GPIO_BCLK_EINT_DB 0x0200 /* GPIO_BCLK_EINT_DB */ | ||
1442 | #define WM8904_GPIO_BCLK_EINT_DB_MASK 0x0200 /* GPIO_BCLK_EINT_DB */ | ||
1443 | #define WM8904_GPIO_BCLK_EINT_DB_SHIFT 9 /* GPIO_BCLK_EINT_DB */ | ||
1444 | #define WM8904_GPIO_BCLK_EINT_DB_WIDTH 1 /* GPIO_BCLK_EINT_DB */ | ||
1445 | #define WM8904_WSEQ_EINT_DB 0x0100 /* WSEQ_EINT_DB */ | ||
1446 | #define WM8904_WSEQ_EINT_DB_MASK 0x0100 /* WSEQ_EINT_DB */ | ||
1447 | #define WM8904_WSEQ_EINT_DB_SHIFT 8 /* WSEQ_EINT_DB */ | ||
1448 | #define WM8904_WSEQ_EINT_DB_WIDTH 1 /* WSEQ_EINT_DB */ | ||
1449 | #define WM8904_GPIO3_EINT_DB 0x0080 /* GPIO3_EINT_DB */ | ||
1450 | #define WM8904_GPIO3_EINT_DB_MASK 0x0080 /* GPIO3_EINT_DB */ | ||
1451 | #define WM8904_GPIO3_EINT_DB_SHIFT 7 /* GPIO3_EINT_DB */ | ||
1452 | #define WM8904_GPIO3_EINT_DB_WIDTH 1 /* GPIO3_EINT_DB */ | ||
1453 | #define WM8904_GPIO2_EINT_DB 0x0040 /* GPIO2_EINT_DB */ | ||
1454 | #define WM8904_GPIO2_EINT_DB_MASK 0x0040 /* GPIO2_EINT_DB */ | ||
1455 | #define WM8904_GPIO2_EINT_DB_SHIFT 6 /* GPIO2_EINT_DB */ | ||
1456 | #define WM8904_GPIO2_EINT_DB_WIDTH 1 /* GPIO2_EINT_DB */ | ||
1457 | #define WM8904_GPIO1_EINT_DB 0x0020 /* GPIO1_EINT_DB */ | ||
1458 | #define WM8904_GPIO1_EINT_DB_MASK 0x0020 /* GPIO1_EINT_DB */ | ||
1459 | #define WM8904_GPIO1_EINT_DB_SHIFT 5 /* GPIO1_EINT_DB */ | ||
1460 | #define WM8904_GPIO1_EINT_DB_WIDTH 1 /* GPIO1_EINT_DB */ | ||
1461 | #define WM8904_GPI8_EINT_DB 0x0010 /* GPI8_EINT_DB */ | ||
1462 | #define WM8904_GPI8_EINT_DB_MASK 0x0010 /* GPI8_EINT_DB */ | ||
1463 | #define WM8904_GPI8_EINT_DB_SHIFT 4 /* GPI8_EINT_DB */ | ||
1464 | #define WM8904_GPI8_EINT_DB_WIDTH 1 /* GPI8_EINT_DB */ | ||
1465 | #define WM8904_GPI7_EINT_DB 0x0008 /* GPI7_EINT_DB */ | ||
1466 | #define WM8904_GPI7_EINT_DB_MASK 0x0008 /* GPI7_EINT_DB */ | ||
1467 | #define WM8904_GPI7_EINT_DB_SHIFT 3 /* GPI7_EINT_DB */ | ||
1468 | #define WM8904_GPI7_EINT_DB_WIDTH 1 /* GPI7_EINT_DB */ | ||
1469 | #define WM8904_FLL_LOCK_EINT_DB 0x0004 /* FLL_LOCK_EINT_DB */ | ||
1470 | #define WM8904_FLL_LOCK_EINT_DB_MASK 0x0004 /* FLL_LOCK_EINT_DB */ | ||
1471 | #define WM8904_FLL_LOCK_EINT_DB_SHIFT 2 /* FLL_LOCK_EINT_DB */ | ||
1472 | #define WM8904_FLL_LOCK_EINT_DB_WIDTH 1 /* FLL_LOCK_EINT_DB */ | ||
1473 | #define WM8904_MIC_SHRT_EINT_DB 0x0002 /* MIC_SHRT_EINT_DB */ | ||
1474 | #define WM8904_MIC_SHRT_EINT_DB_MASK 0x0002 /* MIC_SHRT_EINT_DB */ | ||
1475 | #define WM8904_MIC_SHRT_EINT_DB_SHIFT 1 /* MIC_SHRT_EINT_DB */ | ||
1476 | #define WM8904_MIC_SHRT_EINT_DB_WIDTH 1 /* MIC_SHRT_EINT_DB */ | ||
1477 | #define WM8904_MIC_DET_EINT_DB 0x0001 /* MIC_DET_EINT_DB */ | ||
1478 | #define WM8904_MIC_DET_EINT_DB_MASK 0x0001 /* MIC_DET_EINT_DB */ | ||
1479 | #define WM8904_MIC_DET_EINT_DB_SHIFT 0 /* MIC_DET_EINT_DB */ | ||
1480 | #define WM8904_MIC_DET_EINT_DB_WIDTH 1 /* MIC_DET_EINT_DB */ | ||
1481 | |||
1482 | /* | ||
1483 | * R134 (0x86) - EQ1 | ||
1484 | */ | ||
1485 | #define WM8904_EQ_ENA 0x0001 /* EQ_ENA */ | ||
1486 | #define WM8904_EQ_ENA_MASK 0x0001 /* EQ_ENA */ | ||
1487 | #define WM8904_EQ_ENA_SHIFT 0 /* EQ_ENA */ | ||
1488 | #define WM8904_EQ_ENA_WIDTH 1 /* EQ_ENA */ | ||
1489 | |||
1490 | /* | ||
1491 | * R135 (0x87) - EQ2 | ||
1492 | */ | ||
1493 | #define WM8904_EQ_B1_GAIN_MASK 0x001F /* EQ_B1_GAIN - [4:0] */ | ||
1494 | #define WM8904_EQ_B1_GAIN_SHIFT 0 /* EQ_B1_GAIN - [4:0] */ | ||
1495 | #define WM8904_EQ_B1_GAIN_WIDTH 5 /* EQ_B1_GAIN - [4:0] */ | ||
1496 | |||
1497 | /* | ||
1498 | * R136 (0x88) - EQ3 | ||
1499 | */ | ||
1500 | #define WM8904_EQ_B2_GAIN_MASK 0x001F /* EQ_B2_GAIN - [4:0] */ | ||
1501 | #define WM8904_EQ_B2_GAIN_SHIFT 0 /* EQ_B2_GAIN - [4:0] */ | ||
1502 | #define WM8904_EQ_B2_GAIN_WIDTH 5 /* EQ_B2_GAIN - [4:0] */ | ||
1503 | |||
1504 | /* | ||
1505 | * R137 (0x89) - EQ4 | ||
1506 | */ | ||
1507 | #define WM8904_EQ_B3_GAIN_MASK 0x001F /* EQ_B3_GAIN - [4:0] */ | ||
1508 | #define WM8904_EQ_B3_GAIN_SHIFT 0 /* EQ_B3_GAIN - [4:0] */ | ||
1509 | #define WM8904_EQ_B3_GAIN_WIDTH 5 /* EQ_B3_GAIN - [4:0] */ | ||
1510 | |||
1511 | /* | ||
1512 | * R138 (0x8A) - EQ5 | ||
1513 | */ | ||
1514 | #define WM8904_EQ_B4_GAIN_MASK 0x001F /* EQ_B4_GAIN - [4:0] */ | ||
1515 | #define WM8904_EQ_B4_GAIN_SHIFT 0 /* EQ_B4_GAIN - [4:0] */ | ||
1516 | #define WM8904_EQ_B4_GAIN_WIDTH 5 /* EQ_B4_GAIN - [4:0] */ | ||
1517 | |||
1518 | /* | ||
1519 | * R139 (0x8B) - EQ6 | ||
1520 | */ | ||
1521 | #define WM8904_EQ_B5_GAIN_MASK 0x001F /* EQ_B5_GAIN - [4:0] */ | ||
1522 | #define WM8904_EQ_B5_GAIN_SHIFT 0 /* EQ_B5_GAIN - [4:0] */ | ||
1523 | #define WM8904_EQ_B5_GAIN_WIDTH 5 /* EQ_B5_GAIN - [4:0] */ | ||
1524 | |||
1525 | /* | ||
1526 | * R140 (0x8C) - EQ7 | ||
1527 | */ | ||
1528 | #define WM8904_EQ_B1_A_MASK 0xFFFF /* EQ_B1_A - [15:0] */ | ||
1529 | #define WM8904_EQ_B1_A_SHIFT 0 /* EQ_B1_A - [15:0] */ | ||
1530 | #define WM8904_EQ_B1_A_WIDTH 16 /* EQ_B1_A - [15:0] */ | ||
1531 | |||
1532 | /* | ||
1533 | * R141 (0x8D) - EQ8 | ||
1534 | */ | ||
1535 | #define WM8904_EQ_B1_B_MASK 0xFFFF /* EQ_B1_B - [15:0] */ | ||
1536 | #define WM8904_EQ_B1_B_SHIFT 0 /* EQ_B1_B - [15:0] */ | ||
1537 | #define WM8904_EQ_B1_B_WIDTH 16 /* EQ_B1_B - [15:0] */ | ||
1538 | |||
1539 | /* | ||
1540 | * R142 (0x8E) - EQ9 | ||
1541 | */ | ||
1542 | #define WM8904_EQ_B1_PG_MASK 0xFFFF /* EQ_B1_PG - [15:0] */ | ||
1543 | #define WM8904_EQ_B1_PG_SHIFT 0 /* EQ_B1_PG - [15:0] */ | ||
1544 | #define WM8904_EQ_B1_PG_WIDTH 16 /* EQ_B1_PG - [15:0] */ | ||
1545 | |||
1546 | /* | ||
1547 | * R143 (0x8F) - EQ10 | ||
1548 | */ | ||
1549 | #define WM8904_EQ_B2_A_MASK 0xFFFF /* EQ_B2_A - [15:0] */ | ||
1550 | #define WM8904_EQ_B2_A_SHIFT 0 /* EQ_B2_A - [15:0] */ | ||
1551 | #define WM8904_EQ_B2_A_WIDTH 16 /* EQ_B2_A - [15:0] */ | ||
1552 | |||
1553 | /* | ||
1554 | * R144 (0x90) - EQ11 | ||
1555 | */ | ||
1556 | #define WM8904_EQ_B2_B_MASK 0xFFFF /* EQ_B2_B - [15:0] */ | ||
1557 | #define WM8904_EQ_B2_B_SHIFT 0 /* EQ_B2_B - [15:0] */ | ||
1558 | #define WM8904_EQ_B2_B_WIDTH 16 /* EQ_B2_B - [15:0] */ | ||
1559 | |||
1560 | /* | ||
1561 | * R145 (0x91) - EQ12 | ||
1562 | */ | ||
1563 | #define WM8904_EQ_B2_C_MASK 0xFFFF /* EQ_B2_C - [15:0] */ | ||
1564 | #define WM8904_EQ_B2_C_SHIFT 0 /* EQ_B2_C - [15:0] */ | ||
1565 | #define WM8904_EQ_B2_C_WIDTH 16 /* EQ_B2_C - [15:0] */ | ||
1566 | |||
1567 | /* | ||
1568 | * R146 (0x92) - EQ13 | ||
1569 | */ | ||
1570 | #define WM8904_EQ_B2_PG_MASK 0xFFFF /* EQ_B2_PG - [15:0] */ | ||
1571 | #define WM8904_EQ_B2_PG_SHIFT 0 /* EQ_B2_PG - [15:0] */ | ||
1572 | #define WM8904_EQ_B2_PG_WIDTH 16 /* EQ_B2_PG - [15:0] */ | ||
1573 | |||
1574 | /* | ||
1575 | * R147 (0x93) - EQ14 | ||
1576 | */ | ||
1577 | #define WM8904_EQ_B3_A_MASK 0xFFFF /* EQ_B3_A - [15:0] */ | ||
1578 | #define WM8904_EQ_B3_A_SHIFT 0 /* EQ_B3_A - [15:0] */ | ||
1579 | #define WM8904_EQ_B3_A_WIDTH 16 /* EQ_B3_A - [15:0] */ | ||
1580 | |||
1581 | /* | ||
1582 | * R148 (0x94) - EQ15 | ||
1583 | */ | ||
1584 | #define WM8904_EQ_B3_B_MASK 0xFFFF /* EQ_B3_B - [15:0] */ | ||
1585 | #define WM8904_EQ_B3_B_SHIFT 0 /* EQ_B3_B - [15:0] */ | ||
1586 | #define WM8904_EQ_B3_B_WIDTH 16 /* EQ_B3_B - [15:0] */ | ||
1587 | |||
1588 | /* | ||
1589 | * R149 (0x95) - EQ16 | ||
1590 | */ | ||
1591 | #define WM8904_EQ_B3_C_MASK 0xFFFF /* EQ_B3_C - [15:0] */ | ||
1592 | #define WM8904_EQ_B3_C_SHIFT 0 /* EQ_B3_C - [15:0] */ | ||
1593 | #define WM8904_EQ_B3_C_WIDTH 16 /* EQ_B3_C - [15:0] */ | ||
1594 | |||
1595 | /* | ||
1596 | * R150 (0x96) - EQ17 | ||
1597 | */ | ||
1598 | #define WM8904_EQ_B3_PG_MASK 0xFFFF /* EQ_B3_PG - [15:0] */ | ||
1599 | #define WM8904_EQ_B3_PG_SHIFT 0 /* EQ_B3_PG - [15:0] */ | ||
1600 | #define WM8904_EQ_B3_PG_WIDTH 16 /* EQ_B3_PG - [15:0] */ | ||
1601 | |||
1602 | /* | ||
1603 | * R151 (0x97) - EQ18 | ||
1604 | */ | ||
1605 | #define WM8904_EQ_B4_A_MASK 0xFFFF /* EQ_B4_A - [15:0] */ | ||
1606 | #define WM8904_EQ_B4_A_SHIFT 0 /* EQ_B4_A - [15:0] */ | ||
1607 | #define WM8904_EQ_B4_A_WIDTH 16 /* EQ_B4_A - [15:0] */ | ||
1608 | |||
1609 | /* | ||
1610 | * R152 (0x98) - EQ19 | ||
1611 | */ | ||
1612 | #define WM8904_EQ_B4_B_MASK 0xFFFF /* EQ_B4_B - [15:0] */ | ||
1613 | #define WM8904_EQ_B4_B_SHIFT 0 /* EQ_B4_B - [15:0] */ | ||
1614 | #define WM8904_EQ_B4_B_WIDTH 16 /* EQ_B4_B - [15:0] */ | ||
1615 | |||
1616 | /* | ||
1617 | * R153 (0x99) - EQ20 | ||
1618 | */ | ||
1619 | #define WM8904_EQ_B4_C_MASK 0xFFFF /* EQ_B4_C - [15:0] */ | ||
1620 | #define WM8904_EQ_B4_C_SHIFT 0 /* EQ_B4_C - [15:0] */ | ||
1621 | #define WM8904_EQ_B4_C_WIDTH 16 /* EQ_B4_C - [15:0] */ | ||
1622 | |||
1623 | /* | ||
1624 | * R154 (0x9A) - EQ21 | ||
1625 | */ | ||
1626 | #define WM8904_EQ_B4_PG_MASK 0xFFFF /* EQ_B4_PG - [15:0] */ | ||
1627 | #define WM8904_EQ_B4_PG_SHIFT 0 /* EQ_B4_PG - [15:0] */ | ||
1628 | #define WM8904_EQ_B4_PG_WIDTH 16 /* EQ_B4_PG - [15:0] */ | ||
1629 | |||
1630 | /* | ||
1631 | * R155 (0x9B) - EQ22 | ||
1632 | */ | ||
1633 | #define WM8904_EQ_B5_A_MASK 0xFFFF /* EQ_B5_A - [15:0] */ | ||
1634 | #define WM8904_EQ_B5_A_SHIFT 0 /* EQ_B5_A - [15:0] */ | ||
1635 | #define WM8904_EQ_B5_A_WIDTH 16 /* EQ_B5_A - [15:0] */ | ||
1636 | |||
1637 | /* | ||
1638 | * R156 (0x9C) - EQ23 | ||
1639 | */ | ||
1640 | #define WM8904_EQ_B5_B_MASK 0xFFFF /* EQ_B5_B - [15:0] */ | ||
1641 | #define WM8904_EQ_B5_B_SHIFT 0 /* EQ_B5_B - [15:0] */ | ||
1642 | #define WM8904_EQ_B5_B_WIDTH 16 /* EQ_B5_B - [15:0] */ | ||
1643 | |||
1644 | /* | ||
1645 | * R157 (0x9D) - EQ24 | ||
1646 | */ | ||
1647 | #define WM8904_EQ_B5_PG_MASK 0xFFFF /* EQ_B5_PG - [15:0] */ | ||
1648 | #define WM8904_EQ_B5_PG_SHIFT 0 /* EQ_B5_PG - [15:0] */ | ||
1649 | #define WM8904_EQ_B5_PG_WIDTH 16 /* EQ_B5_PG - [15:0] */ | ||
1650 | |||
1651 | /* | ||
1652 | * R161 (0xA1) - Control Interface Test 1 | ||
1653 | */ | ||
1654 | #define WM8904_USER_KEY 0x0002 /* USER_KEY */ | ||
1655 | #define WM8904_USER_KEY_MASK 0x0002 /* USER_KEY */ | ||
1656 | #define WM8904_USER_KEY_SHIFT 1 /* USER_KEY */ | ||
1657 | #define WM8904_USER_KEY_WIDTH 1 /* USER_KEY */ | ||
1658 | |||
1659 | /* | ||
1660 | * R204 (0xCC) - Analogue Output Bias 0 | ||
1661 | */ | ||
1662 | #define WM8904_PGA_BIAS_MASK 0x0070 /* PGA_BIAS - [6:4] */ | ||
1663 | #define WM8904_PGA_BIAS_SHIFT 4 /* PGA_BIAS - [6:4] */ | ||
1664 | #define WM8904_PGA_BIAS_WIDTH 3 /* PGA_BIAS - [6:4] */ | ||
1665 | |||
1666 | /* | ||
1667 | * R247 (0xF7) - FLL NCO Test 0 | ||
1668 | */ | ||
1669 | #define WM8904_FLL_FRC_NCO 0x0001 /* FLL_FRC_NCO */ | ||
1670 | #define WM8904_FLL_FRC_NCO_MASK 0x0001 /* FLL_FRC_NCO */ | ||
1671 | #define WM8904_FLL_FRC_NCO_SHIFT 0 /* FLL_FRC_NCO */ | ||
1672 | #define WM8904_FLL_FRC_NCO_WIDTH 1 /* FLL_FRC_NCO */ | ||
1673 | |||
1674 | /* | ||
1675 | * R248 (0xF8) - FLL NCO Test 1 | ||
1676 | */ | ||
1677 | #define WM8904_FLL_FRC_NCO_VAL_MASK 0x003F /* FLL_FRC_NCO_VAL - [5:0] */ | ||
1678 | #define WM8904_FLL_FRC_NCO_VAL_SHIFT 0 /* FLL_FRC_NCO_VAL - [5:0] */ | ||
1679 | #define WM8904_FLL_FRC_NCO_VAL_WIDTH 6 /* FLL_FRC_NCO_VAL - [5:0] */ | ||
1680 | |||
1681 | #endif | ||
diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c new file mode 100644 index 000000000000..615dab2b62ef --- /dev/null +++ b/sound/soc/codecs/wm8955.c | |||
@@ -0,0 +1,1151 @@ | |||
1 | /* | ||
2 | * wm8955.c -- WM8955 ALSA SoC Audio driver | ||
3 | * | ||
4 | * Copyright 2009 Wolfson Microelectronics plc | ||
5 | * | ||
6 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | ||
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/moduleparam.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/delay.h> | ||
17 | #include <linux/pm.h> | ||
18 | #include <linux/i2c.h> | ||
19 | #include <linux/platform_device.h> | ||
20 | #include <linux/regulator/consumer.h> | ||
21 | #include <sound/core.h> | ||
22 | #include <sound/pcm.h> | ||
23 | #include <sound/pcm_params.h> | ||
24 | #include <sound/soc.h> | ||
25 | #include <sound/soc-dapm.h> | ||
26 | #include <sound/initval.h> | ||
27 | #include <sound/tlv.h> | ||
28 | #include <sound/wm8955.h> | ||
29 | |||
30 | #include "wm8955.h" | ||
31 | |||
32 | static struct snd_soc_codec *wm8955_codec; | ||
33 | struct snd_soc_codec_device soc_codec_dev_wm8955; | ||
34 | |||
35 | #define WM8955_NUM_SUPPLIES 4 | ||
36 | static const char *wm8955_supply_names[WM8955_NUM_SUPPLIES] = { | ||
37 | "DCVDD", | ||
38 | "DBVDD", | ||
39 | "HPVDD", | ||
40 | "AVDD", | ||
41 | }; | ||
42 | |||
43 | /* codec private data */ | ||
44 | struct wm8955_priv { | ||
45 | struct snd_soc_codec codec; | ||
46 | u16 reg_cache[WM8955_MAX_REGISTER + 1]; | ||
47 | |||
48 | unsigned int mclk_rate; | ||
49 | |||
50 | int deemph; | ||
51 | int fs; | ||
52 | |||
53 | struct regulator_bulk_data supplies[WM8955_NUM_SUPPLIES]; | ||
54 | |||
55 | struct wm8955_pdata *pdata; | ||
56 | }; | ||
57 | |||
58 | static const u16 wm8955_reg[WM8955_MAX_REGISTER + 1] = { | ||
59 | 0x0000, /* R0 */ | ||
60 | 0x0000, /* R1 */ | ||
61 | 0x0079, /* R2 - LOUT1 volume */ | ||
62 | 0x0079, /* R3 - ROUT1 volume */ | ||
63 | 0x0000, /* R4 */ | ||
64 | 0x0008, /* R5 - DAC Control */ | ||
65 | 0x0000, /* R6 */ | ||
66 | 0x000A, /* R7 - Audio Interface */ | ||
67 | 0x0000, /* R8 - Sample Rate */ | ||
68 | 0x0000, /* R9 */ | ||
69 | 0x00FF, /* R10 - Left DAC volume */ | ||
70 | 0x00FF, /* R11 - Right DAC volume */ | ||
71 | 0x000F, /* R12 - Bass control */ | ||
72 | 0x000F, /* R13 - Treble control */ | ||
73 | 0x0000, /* R14 */ | ||
74 | 0x0000, /* R15 - Reset */ | ||
75 | 0x0000, /* R16 */ | ||
76 | 0x0000, /* R17 */ | ||
77 | 0x0000, /* R18 */ | ||
78 | 0x0000, /* R19 */ | ||
79 | 0x0000, /* R20 */ | ||
80 | 0x0000, /* R21 */ | ||
81 | 0x0000, /* R22 */ | ||
82 | 0x00C1, /* R23 - Additional control (1) */ | ||
83 | 0x0000, /* R24 - Additional control (2) */ | ||
84 | 0x0000, /* R25 - Power Management (1) */ | ||
85 | 0x0000, /* R26 - Power Management (2) */ | ||
86 | 0x0000, /* R27 - Additional Control (3) */ | ||
87 | 0x0000, /* R28 */ | ||
88 | 0x0000, /* R29 */ | ||
89 | 0x0000, /* R30 */ | ||
90 | 0x0000, /* R31 */ | ||
91 | 0x0000, /* R32 */ | ||
92 | 0x0000, /* R33 */ | ||
93 | 0x0050, /* R34 - Left out Mix (1) */ | ||
94 | 0x0050, /* R35 - Left out Mix (2) */ | ||
95 | 0x0050, /* R36 - Right out Mix (1) */ | ||
96 | 0x0050, /* R37 - Right Out Mix (2) */ | ||
97 | 0x0050, /* R38 - Mono out Mix (1) */ | ||
98 | 0x0050, /* R39 - Mono out Mix (2) */ | ||
99 | 0x0079, /* R40 - LOUT2 volume */ | ||
100 | 0x0079, /* R41 - ROUT2 volume */ | ||
101 | 0x0079, /* R42 - MONOOUT volume */ | ||
102 | 0x0000, /* R43 - Clocking / PLL */ | ||
103 | 0x0103, /* R44 - PLL Control 1 */ | ||
104 | 0x0024, /* R45 - PLL Control 2 */ | ||
105 | 0x01BA, /* R46 - PLL Control 3 */ | ||
106 | 0x0000, /* R47 */ | ||
107 | 0x0000, /* R48 */ | ||
108 | 0x0000, /* R49 */ | ||
109 | 0x0000, /* R50 */ | ||
110 | 0x0000, /* R51 */ | ||
111 | 0x0000, /* R52 */ | ||
112 | 0x0000, /* R53 */ | ||
113 | 0x0000, /* R54 */ | ||
114 | 0x0000, /* R55 */ | ||
115 | 0x0000, /* R56 */ | ||
116 | 0x0000, /* R57 */ | ||
117 | 0x0000, /* R58 */ | ||
118 | 0x0000, /* R59 - PLL Control 4 */ | ||
119 | }; | ||
120 | |||
121 | static int wm8955_reset(struct snd_soc_codec *codec) | ||
122 | { | ||
123 | return snd_soc_write(codec, WM8955_RESET, 0); | ||
124 | } | ||
125 | |||
126 | struct pll_factors { | ||
127 | int n; | ||
128 | int k; | ||
129 | int outdiv; | ||
130 | }; | ||
131 | |||
132 | /* The size in bits of the FLL divide multiplied by 10 | ||
133 | * to allow rounding later */ | ||
134 | #define FIXED_FLL_SIZE ((1 << 22) * 10) | ||
135 | |||
136 | static int wm8995_pll_factors(struct device *dev, | ||
137 | int Fref, int Fout, struct pll_factors *pll) | ||
138 | { | ||
139 | u64 Kpart; | ||
140 | unsigned int K, Ndiv, Nmod, target; | ||
141 | |||
142 | dev_dbg(dev, "Fref=%u Fout=%u\n", Fref, Fout); | ||
143 | |||
144 | /* The oscilator should run at should be 90-100MHz, and | ||
145 | * there's a divide by 4 plus an optional divide by 2 in the | ||
146 | * output path to generate the system clock. The clock table | ||
147 | * is sortd so we should always generate a suitable target. */ | ||
148 | target = Fout * 4; | ||
149 | if (target < 90000000) { | ||
150 | pll->outdiv = 1; | ||
151 | target *= 2; | ||
152 | } else { | ||
153 | pll->outdiv = 0; | ||
154 | } | ||
155 | |||
156 | WARN_ON(target < 90000000 || target > 100000000); | ||
157 | |||
158 | dev_dbg(dev, "Fvco=%dHz\n", target); | ||
159 | |||
160 | /* Now, calculate N.K */ | ||
161 | Ndiv = target / Fref; | ||
162 | |||
163 | pll->n = Ndiv; | ||
164 | Nmod = target % Fref; | ||
165 | dev_dbg(dev, "Nmod=%d\n", Nmod); | ||
166 | |||
167 | /* Calculate fractional part - scale up so we can round. */ | ||
168 | Kpart = FIXED_FLL_SIZE * (long long)Nmod; | ||
169 | |||
170 | do_div(Kpart, Fref); | ||
171 | |||
172 | K = Kpart & 0xFFFFFFFF; | ||
173 | |||
174 | if ((K % 10) >= 5) | ||
175 | K += 5; | ||
176 | |||
177 | /* Move down to proper range now rounding is done */ | ||
178 | pll->k = K / 10; | ||
179 | |||
180 | dev_dbg(dev, "N=%x K=%x OUTDIV=%x\n", pll->n, pll->k, pll->outdiv); | ||
181 | |||
182 | return 0; | ||
183 | } | ||
184 | |||
185 | /* Lookup table specifiying SRATE (table 25 in datasheet); some of the | ||
186 | * output frequencies have been rounded to the standard frequencies | ||
187 | * they are intended to match where the error is slight. */ | ||
188 | static struct { | ||
189 | int mclk; | ||
190 | int fs; | ||
191 | int usb; | ||
192 | int sr; | ||
193 | } clock_cfgs[] = { | ||
194 | { 18432000, 8000, 0, 3, }, | ||
195 | { 18432000, 12000, 0, 9, }, | ||
196 | { 18432000, 16000, 0, 11, }, | ||
197 | { 18432000, 24000, 0, 29, }, | ||
198 | { 18432000, 32000, 0, 13, }, | ||
199 | { 18432000, 48000, 0, 1, }, | ||
200 | { 18432000, 96000, 0, 15, }, | ||
201 | |||
202 | { 16934400, 8018, 0, 19, }, | ||
203 | { 16934400, 11025, 0, 25, }, | ||
204 | { 16934400, 22050, 0, 27, }, | ||
205 | { 16934400, 44100, 0, 17, }, | ||
206 | { 16934400, 88200, 0, 31, }, | ||
207 | |||
208 | { 12000000, 8000, 1, 2, }, | ||
209 | { 12000000, 11025, 1, 25, }, | ||
210 | { 12000000, 12000, 1, 8, }, | ||
211 | { 12000000, 16000, 1, 10, }, | ||
212 | { 12000000, 22050, 1, 27, }, | ||
213 | { 12000000, 24000, 1, 28, }, | ||
214 | { 12000000, 32000, 1, 12, }, | ||
215 | { 12000000, 44100, 1, 17, }, | ||
216 | { 12000000, 48000, 1, 0, }, | ||
217 | { 12000000, 88200, 1, 31, }, | ||
218 | { 12000000, 96000, 1, 14, }, | ||
219 | |||
220 | { 12288000, 8000, 0, 2, }, | ||
221 | { 12288000, 12000, 0, 8, }, | ||
222 | { 12288000, 16000, 0, 10, }, | ||
223 | { 12288000, 24000, 0, 28, }, | ||
224 | { 12288000, 32000, 0, 12, }, | ||
225 | { 12288000, 48000, 0, 0, }, | ||
226 | { 12288000, 96000, 0, 14, }, | ||
227 | |||
228 | { 12289600, 8018, 0, 18, }, | ||
229 | { 12289600, 11025, 0, 24, }, | ||
230 | { 12289600, 22050, 0, 26, }, | ||
231 | { 11289600, 44100, 0, 16, }, | ||
232 | { 11289600, 88200, 0, 31, }, | ||
233 | }; | ||
234 | |||
235 | static int wm8955_configure_clocking(struct snd_soc_codec *codec) | ||
236 | { | ||
237 | struct wm8955_priv *wm8955 = codec->private_data; | ||
238 | int i, ret, val; | ||
239 | int clocking = 0; | ||
240 | int srate = 0; | ||
241 | int sr = -1; | ||
242 | struct pll_factors pll; | ||
243 | |||
244 | /* If we're not running a sample rate currently just pick one */ | ||
245 | if (wm8955->fs == 0) | ||
246 | wm8955->fs = 8000; | ||
247 | |||
248 | /* Can we generate an exact output? */ | ||
249 | for (i = 0; i < ARRAY_SIZE(clock_cfgs); i++) { | ||
250 | if (wm8955->fs != clock_cfgs[i].fs) | ||
251 | continue; | ||
252 | sr = i; | ||
253 | |||
254 | if (wm8955->mclk_rate == clock_cfgs[i].mclk) | ||
255 | break; | ||
256 | } | ||
257 | |||
258 | /* We should never get here with an unsupported sample rate */ | ||
259 | if (sr == -1) { | ||
260 | dev_err(codec->dev, "Sample rate %dHz unsupported\n", | ||
261 | wm8955->fs); | ||
262 | WARN_ON(sr == -1); | ||
263 | return -EINVAL; | ||
264 | } | ||
265 | |||
266 | if (i == ARRAY_SIZE(clock_cfgs)) { | ||
267 | /* If we can't generate the right clock from MCLK then | ||
268 | * we should configure the PLL to supply us with an | ||
269 | * appropriate clock. | ||
270 | */ | ||
271 | clocking |= WM8955_MCLKSEL; | ||
272 | |||
273 | /* Use the last divider configuration we saw for the | ||
274 | * sample rate. */ | ||
275 | ret = wm8995_pll_factors(codec->dev, wm8955->mclk_rate, | ||
276 | clock_cfgs[sr].mclk, &pll); | ||
277 | if (ret != 0) { | ||
278 | dev_err(codec->dev, | ||
279 | "Unable to generate %dHz from %dHz MCLK\n", | ||
280 | wm8955->fs, wm8955->mclk_rate); | ||
281 | return -EINVAL; | ||
282 | } | ||
283 | |||
284 | snd_soc_update_bits(codec, WM8955_PLL_CONTROL_1, | ||
285 | WM8955_N_MASK | WM8955_K_21_18_MASK, | ||
286 | (pll.n << WM8955_N_SHIFT) | | ||
287 | pll.k >> 18); | ||
288 | snd_soc_update_bits(codec, WM8955_PLL_CONTROL_2, | ||
289 | WM8955_K_17_9_MASK, | ||
290 | (pll.k >> 9) & WM8955_K_17_9_MASK); | ||
291 | snd_soc_update_bits(codec, WM8955_PLL_CONTROL_2, | ||
292 | WM8955_K_8_0_MASK, | ||
293 | pll.k & WM8955_K_8_0_MASK); | ||
294 | if (pll.k) | ||
295 | snd_soc_update_bits(codec, WM8955_PLL_CONTROL_4, | ||
296 | WM8955_KEN, WM8955_KEN); | ||
297 | else | ||
298 | snd_soc_update_bits(codec, WM8955_PLL_CONTROL_4, | ||
299 | WM8955_KEN, 0); | ||
300 | |||
301 | if (pll.outdiv) | ||
302 | val = WM8955_PLL_RB | WM8955_PLLOUTDIV2; | ||
303 | else | ||
304 | val = WM8955_PLL_RB; | ||
305 | |||
306 | /* Now start the PLL running */ | ||
307 | snd_soc_update_bits(codec, WM8955_CLOCKING_PLL, | ||
308 | WM8955_PLL_RB | WM8955_PLLOUTDIV2, val); | ||
309 | snd_soc_update_bits(codec, WM8955_CLOCKING_PLL, | ||
310 | WM8955_PLLEN, WM8955_PLLEN); | ||
311 | } | ||
312 | |||
313 | srate = clock_cfgs[sr].usb | (clock_cfgs[sr].sr << WM8955_SR_SHIFT); | ||
314 | |||
315 | snd_soc_update_bits(codec, WM8955_SAMPLE_RATE, | ||
316 | WM8955_USB | WM8955_SR_MASK, srate); | ||
317 | snd_soc_update_bits(codec, WM8955_CLOCKING_PLL, | ||
318 | WM8955_MCLKSEL, clocking); | ||
319 | |||
320 | return 0; | ||
321 | } | ||
322 | |||
323 | static int wm8955_sysclk(struct snd_soc_dapm_widget *w, | ||
324 | struct snd_kcontrol *kcontrol, int event) | ||
325 | { | ||
326 | struct snd_soc_codec *codec = w->codec; | ||
327 | int ret = 0; | ||
328 | |||
329 | /* Always disable the clocks - if we're doing reconfiguration this | ||
330 | * avoids misclocking. | ||
331 | */ | ||
332 | snd_soc_update_bits(codec, WM8955_POWER_MANAGEMENT_1, | ||
333 | WM8955_DIGENB, 0); | ||
334 | snd_soc_update_bits(codec, WM8955_CLOCKING_PLL, | ||
335 | WM8955_PLL_RB | WM8955_PLLEN, 0); | ||
336 | |||
337 | switch (event) { | ||
338 | case SND_SOC_DAPM_POST_PMD: | ||
339 | break; | ||
340 | case SND_SOC_DAPM_PRE_PMU: | ||
341 | ret = wm8955_configure_clocking(codec); | ||
342 | break; | ||
343 | default: | ||
344 | ret = -EINVAL; | ||
345 | break; | ||
346 | } | ||
347 | |||
348 | return ret; | ||
349 | } | ||
350 | |||
351 | static int deemph_settings[] = { 0, 32000, 44100, 48000 }; | ||
352 | |||
353 | static int wm8955_set_deemph(struct snd_soc_codec *codec) | ||
354 | { | ||
355 | struct wm8955_priv *wm8955 = codec->private_data; | ||
356 | int val, i, best; | ||
357 | |||
358 | /* If we're using deemphasis select the nearest available sample | ||
359 | * rate. | ||
360 | */ | ||
361 | if (wm8955->deemph) { | ||
362 | best = 1; | ||
363 | for (i = 2; i < ARRAY_SIZE(deemph_settings); i++) { | ||
364 | if (abs(deemph_settings[i] - wm8955->fs) < | ||
365 | abs(deemph_settings[best] - wm8955->fs)) | ||
366 | best = i; | ||
367 | } | ||
368 | |||
369 | val = best << WM8955_DEEMPH_SHIFT; | ||
370 | } else { | ||
371 | val = 0; | ||
372 | } | ||
373 | |||
374 | dev_dbg(codec->dev, "Set deemphasis %d\n", val); | ||
375 | |||
376 | return snd_soc_update_bits(codec, WM8955_DAC_CONTROL, | ||
377 | WM8955_DEEMPH_MASK, val); | ||
378 | } | ||
379 | |||
380 | static int wm8955_get_deemph(struct snd_kcontrol *kcontrol, | ||
381 | struct snd_ctl_elem_value *ucontrol) | ||
382 | { | ||
383 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
384 | struct wm8955_priv *wm8955 = codec->private_data; | ||
385 | |||
386 | return wm8955->deemph; | ||
387 | } | ||
388 | |||
389 | static int wm8955_put_deemph(struct snd_kcontrol *kcontrol, | ||
390 | struct snd_ctl_elem_value *ucontrol) | ||
391 | { | ||
392 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
393 | struct wm8955_priv *wm8955 = codec->private_data; | ||
394 | int deemph = ucontrol->value.enumerated.item[0]; | ||
395 | |||
396 | if (deemph > 1) | ||
397 | return -EINVAL; | ||
398 | |||
399 | wm8955->deemph = deemph; | ||
400 | |||
401 | return wm8955_set_deemph(codec); | ||
402 | } | ||
403 | |||
404 | static const char *bass_mode_text[] = { | ||
405 | "Linear", "Adaptive", | ||
406 | }; | ||
407 | |||
408 | static const struct soc_enum bass_mode = | ||
409 | SOC_ENUM_SINGLE(WM8955_BASS_CONTROL, 7, 2, bass_mode_text); | ||
410 | |||
411 | static const char *bass_cutoff_text[] = { | ||
412 | "Low", "High" | ||
413 | }; | ||
414 | |||
415 | static const struct soc_enum bass_cutoff = | ||
416 | SOC_ENUM_SINGLE(WM8955_BASS_CONTROL, 6, 2, bass_cutoff_text); | ||
417 | |||
418 | static const char *treble_cutoff_text[] = { | ||
419 | "High", "Low" | ||
420 | }; | ||
421 | |||
422 | static const struct soc_enum treble_cutoff = | ||
423 | SOC_ENUM_SINGLE(WM8955_TREBLE_CONTROL, 6, 2, treble_cutoff_text); | ||
424 | |||
425 | static const DECLARE_TLV_DB_SCALE(digital_tlv, -12750, 50, 1); | ||
426 | static const DECLARE_TLV_DB_SCALE(atten_tlv, -600, 600, 0); | ||
427 | static const DECLARE_TLV_DB_SCALE(bypass_tlv, -1500, 300, 0); | ||
428 | static const DECLARE_TLV_DB_SCALE(mono_tlv, -2100, 300, 0); | ||
429 | static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1); | ||
430 | static const DECLARE_TLV_DB_SCALE(treble_tlv, -1200, 150, 1); | ||
431 | |||
432 | static const struct snd_kcontrol_new wm8955_snd_controls[] = { | ||
433 | SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8955_LEFT_DAC_VOLUME, | ||
434 | WM8955_RIGHT_DAC_VOLUME, 0, 255, 0, digital_tlv), | ||
435 | SOC_SINGLE_TLV("Playback Attenuation Volume", WM8955_DAC_CONTROL, 7, 1, 1, | ||
436 | atten_tlv), | ||
437 | SOC_SINGLE_BOOL_EXT("DAC Deemphasis Switch", 0, | ||
438 | wm8955_get_deemph, wm8955_put_deemph), | ||
439 | |||
440 | SOC_ENUM("Bass Mode", bass_mode), | ||
441 | SOC_ENUM("Bass Cutoff", bass_cutoff), | ||
442 | SOC_SINGLE("Bass Volume", WM8955_BASS_CONTROL, 0, 15, 1), | ||
443 | |||
444 | SOC_ENUM("Treble Cutoff", treble_cutoff), | ||
445 | SOC_SINGLE_TLV("Treble Volume", WM8955_TREBLE_CONTROL, 0, 14, 1, treble_tlv), | ||
446 | |||
447 | SOC_SINGLE_TLV("Left Bypass Volume", WM8955_LEFT_OUT_MIX_1, 4, 7, 1, | ||
448 | bypass_tlv), | ||
449 | SOC_SINGLE_TLV("Left Mono Volume", WM8955_LEFT_OUT_MIX_2, 4, 7, 1, | ||
450 | bypass_tlv), | ||
451 | |||
452 | SOC_SINGLE_TLV("Right Mono Volume", WM8955_RIGHT_OUT_MIX_1, 4, 7, 1, | ||
453 | bypass_tlv), | ||
454 | SOC_SINGLE_TLV("Right Bypass Volume", WM8955_RIGHT_OUT_MIX_2, 4, 7, 1, | ||
455 | bypass_tlv), | ||
456 | |||
457 | /* Not a stereo pair so they line up with the DAPM switches */ | ||
458 | SOC_SINGLE_TLV("Mono Left Bypass Volume", WM8955_MONO_OUT_MIX_1, 4, 7, 1, | ||
459 | mono_tlv), | ||
460 | SOC_SINGLE_TLV("Mono Right Bypass Volume", WM8955_MONO_OUT_MIX_2, 4, 7, 1, | ||
461 | mono_tlv), | ||
462 | |||
463 | SOC_DOUBLE_R_TLV("Headphone Volume", WM8955_LOUT1_VOLUME, | ||
464 | WM8955_ROUT1_VOLUME, 0, 127, 0, out_tlv), | ||
465 | SOC_DOUBLE_R("Headphone ZC Switch", WM8955_LOUT1_VOLUME, | ||
466 | WM8955_ROUT1_VOLUME, 7, 1, 0), | ||
467 | |||
468 | SOC_DOUBLE_R_TLV("Speaker Volume", WM8955_LOUT2_VOLUME, | ||
469 | WM8955_ROUT2_VOLUME, 0, 127, 0, out_tlv), | ||
470 | SOC_DOUBLE_R("Speaker ZC Switch", WM8955_LOUT2_VOLUME, | ||
471 | WM8955_ROUT2_VOLUME, 7, 1, 0), | ||
472 | |||
473 | SOC_SINGLE_TLV("Mono Volume", WM8955_MONOOUT_VOLUME, 0, 127, 0, out_tlv), | ||
474 | SOC_SINGLE("Mono ZC Switch", WM8955_MONOOUT_VOLUME, 7, 1, 0), | ||
475 | }; | ||
476 | |||
477 | static const struct snd_kcontrol_new lmixer[] = { | ||
478 | SOC_DAPM_SINGLE("Playback Switch", WM8955_LEFT_OUT_MIX_1, 8, 1, 0), | ||
479 | SOC_DAPM_SINGLE("Bypass Switch", WM8955_LEFT_OUT_MIX_1, 7, 1, 0), | ||
480 | SOC_DAPM_SINGLE("Right Playback Switch", WM8955_LEFT_OUT_MIX_2, 8, 1, 0), | ||
481 | SOC_DAPM_SINGLE("Mono Switch", WM8955_LEFT_OUT_MIX_2, 7, 1, 0), | ||
482 | }; | ||
483 | |||
484 | static const struct snd_kcontrol_new rmixer[] = { | ||
485 | SOC_DAPM_SINGLE("Left Playback Switch", WM8955_RIGHT_OUT_MIX_1, 8, 1, 0), | ||
486 | SOC_DAPM_SINGLE("Mono Switch", WM8955_RIGHT_OUT_MIX_1, 7, 1, 0), | ||
487 | SOC_DAPM_SINGLE("Playback Switch", WM8955_RIGHT_OUT_MIX_2, 8, 1, 0), | ||
488 | SOC_DAPM_SINGLE("Bypass Switch", WM8955_RIGHT_OUT_MIX_2, 7, 1, 0), | ||
489 | }; | ||
490 | |||
491 | static const struct snd_kcontrol_new mmixer[] = { | ||
492 | SOC_DAPM_SINGLE("Left Playback Switch", WM8955_MONO_OUT_MIX_1, 8, 1, 0), | ||
493 | SOC_DAPM_SINGLE("Left Bypass Switch", WM8955_MONO_OUT_MIX_1, 7, 1, 0), | ||
494 | SOC_DAPM_SINGLE("Right Playback Switch", WM8955_MONO_OUT_MIX_2, 8, 1, 0), | ||
495 | SOC_DAPM_SINGLE("Right Bypass Switch", WM8955_MONO_OUT_MIX_2, 7, 1, 0), | ||
496 | }; | ||
497 | |||
498 | static const struct snd_soc_dapm_widget wm8955_dapm_widgets[] = { | ||
499 | SND_SOC_DAPM_INPUT("MONOIN-"), | ||
500 | SND_SOC_DAPM_INPUT("MONOIN+"), | ||
501 | SND_SOC_DAPM_INPUT("LINEINR"), | ||
502 | SND_SOC_DAPM_INPUT("LINEINL"), | ||
503 | |||
504 | SND_SOC_DAPM_PGA("Mono Input", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
505 | |||
506 | SND_SOC_DAPM_SUPPLY("SYSCLK", WM8955_POWER_MANAGEMENT_1, 0, 1, wm8955_sysclk, | ||
507 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), | ||
508 | SND_SOC_DAPM_SUPPLY("TSDEN", WM8955_ADDITIONAL_CONTROL_1, 8, 0, NULL, 0), | ||
509 | |||
510 | SND_SOC_DAPM_DAC("DACL", "Playback", WM8955_POWER_MANAGEMENT_2, 8, 0), | ||
511 | SND_SOC_DAPM_DAC("DACR", "Playback", WM8955_POWER_MANAGEMENT_2, 7, 0), | ||
512 | |||
513 | SND_SOC_DAPM_PGA("LOUT1 PGA", WM8955_POWER_MANAGEMENT_2, 6, 0, NULL, 0), | ||
514 | SND_SOC_DAPM_PGA("ROUT1 PGA", WM8955_POWER_MANAGEMENT_2, 5, 0, NULL, 0), | ||
515 | SND_SOC_DAPM_PGA("LOUT2 PGA", WM8955_POWER_MANAGEMENT_2, 4, 0, NULL, 0), | ||
516 | SND_SOC_DAPM_PGA("ROUT2 PGA", WM8955_POWER_MANAGEMENT_2, 3, 0, NULL, 0), | ||
517 | SND_SOC_DAPM_PGA("MOUT PGA", WM8955_POWER_MANAGEMENT_2, 2, 0, NULL, 0), | ||
518 | SND_SOC_DAPM_PGA("OUT3 PGA", WM8955_POWER_MANAGEMENT_2, 1, 0, NULL, 0), | ||
519 | |||
520 | /* The names are chosen to make the control names nice */ | ||
521 | SND_SOC_DAPM_MIXER("Left", SND_SOC_NOPM, 0, 0, | ||
522 | lmixer, ARRAY_SIZE(lmixer)), | ||
523 | SND_SOC_DAPM_MIXER("Right", SND_SOC_NOPM, 0, 0, | ||
524 | rmixer, ARRAY_SIZE(rmixer)), | ||
525 | SND_SOC_DAPM_MIXER("Mono", SND_SOC_NOPM, 0, 0, | ||
526 | mmixer, ARRAY_SIZE(mmixer)), | ||
527 | |||
528 | SND_SOC_DAPM_OUTPUT("LOUT1"), | ||
529 | SND_SOC_DAPM_OUTPUT("ROUT1"), | ||
530 | SND_SOC_DAPM_OUTPUT("LOUT2"), | ||
531 | SND_SOC_DAPM_OUTPUT("ROUT2"), | ||
532 | SND_SOC_DAPM_OUTPUT("MONOOUT"), | ||
533 | SND_SOC_DAPM_OUTPUT("OUT3"), | ||
534 | }; | ||
535 | |||
536 | static const struct snd_soc_dapm_route wm8955_intercon[] = { | ||
537 | { "DACL", NULL, "SYSCLK" }, | ||
538 | { "DACR", NULL, "SYSCLK" }, | ||
539 | |||
540 | { "Mono Input", NULL, "MONOIN-" }, | ||
541 | { "Mono Input", NULL, "MONOIN+" }, | ||
542 | |||
543 | { "Left", "Playback Switch", "DACL" }, | ||
544 | { "Left", "Right Playback Switch", "DACR" }, | ||
545 | { "Left", "Bypass Switch", "LINEINL" }, | ||
546 | { "Left", "Mono Switch", "Mono Input" }, | ||
547 | |||
548 | { "Right", "Playback Switch", "DACR" }, | ||
549 | { "Right", "Left Playback Switch", "DACL" }, | ||
550 | { "Right", "Bypass Switch", "LINEINR" }, | ||
551 | { "Right", "Mono Switch", "Mono Input" }, | ||
552 | |||
553 | { "Mono", "Left Playback Switch", "DACL" }, | ||
554 | { "Mono", "Right Playback Switch", "DACR" }, | ||
555 | { "Mono", "Left Bypass Switch", "LINEINL" }, | ||
556 | { "Mono", "Right Bypass Switch", "LINEINR" }, | ||
557 | |||
558 | { "LOUT1 PGA", NULL, "Left" }, | ||
559 | { "LOUT1", NULL, "TSDEN" }, | ||
560 | { "LOUT1", NULL, "LOUT1 PGA" }, | ||
561 | |||
562 | { "ROUT1 PGA", NULL, "Right" }, | ||
563 | { "ROUT1", NULL, "TSDEN" }, | ||
564 | { "ROUT1", NULL, "ROUT1 PGA" }, | ||
565 | |||
566 | { "LOUT2 PGA", NULL, "Left" }, | ||
567 | { "LOUT2", NULL, "TSDEN" }, | ||
568 | { "LOUT2", NULL, "LOUT2 PGA" }, | ||
569 | |||
570 | { "ROUT2 PGA", NULL, "Right" }, | ||
571 | { "ROUT2", NULL, "TSDEN" }, | ||
572 | { "ROUT2", NULL, "ROUT2 PGA" }, | ||
573 | |||
574 | { "MOUT PGA", NULL, "Mono" }, | ||
575 | { "MONOOUT", NULL, "MOUT PGA" }, | ||
576 | |||
577 | /* OUT3 not currently implemented */ | ||
578 | { "OUT3", NULL, "OUT3 PGA" }, | ||
579 | }; | ||
580 | |||
581 | static int wm8955_add_widgets(struct snd_soc_codec *codec) | ||
582 | { | ||
583 | snd_soc_add_controls(codec, wm8955_snd_controls, | ||
584 | ARRAY_SIZE(wm8955_snd_controls)); | ||
585 | |||
586 | snd_soc_dapm_new_controls(codec, wm8955_dapm_widgets, | ||
587 | ARRAY_SIZE(wm8955_dapm_widgets)); | ||
588 | |||
589 | snd_soc_dapm_add_routes(codec, wm8955_intercon, | ||
590 | ARRAY_SIZE(wm8955_intercon)); | ||
591 | |||
592 | return 0; | ||
593 | } | ||
594 | |||
595 | static int wm8955_hw_params(struct snd_pcm_substream *substream, | ||
596 | struct snd_pcm_hw_params *params, | ||
597 | struct snd_soc_dai *dai) | ||
598 | { | ||
599 | struct snd_soc_codec *codec = dai->codec; | ||
600 | struct wm8955_priv *wm8955 = codec->private_data; | ||
601 | int ret; | ||
602 | int wl; | ||
603 | |||
604 | switch (params_format(params)) { | ||
605 | case SNDRV_PCM_FORMAT_S16_LE: | ||
606 | wl = 0; | ||
607 | break; | ||
608 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
609 | wl = 0x4; | ||
610 | break; | ||
611 | case SNDRV_PCM_FORMAT_S24_LE: | ||
612 | wl = 0x8; | ||
613 | break; | ||
614 | case SNDRV_PCM_FORMAT_S32_LE: | ||
615 | wl = 0xc; | ||
616 | break; | ||
617 | default: | ||
618 | return -EINVAL; | ||
619 | } | ||
620 | snd_soc_update_bits(codec, WM8955_AUDIO_INTERFACE, | ||
621 | WM8955_WL_MASK, wl); | ||
622 | |||
623 | wm8955->fs = params_rate(params); | ||
624 | wm8955_set_deemph(codec); | ||
625 | |||
626 | /* If the chip is clocked then disable the clocks and force a | ||
627 | * reconfiguration, otherwise DAPM will power up the | ||
628 | * clocks for us later. */ | ||
629 | ret = snd_soc_read(codec, WM8955_POWER_MANAGEMENT_1); | ||
630 | if (ret < 0) | ||
631 | return ret; | ||
632 | if (ret & WM8955_DIGENB) { | ||
633 | snd_soc_update_bits(codec, WM8955_POWER_MANAGEMENT_1, | ||
634 | WM8955_DIGENB, 0); | ||
635 | snd_soc_update_bits(codec, WM8955_CLOCKING_PLL, | ||
636 | WM8955_PLL_RB | WM8955_PLLEN, 0); | ||
637 | |||
638 | wm8955_configure_clocking(codec); | ||
639 | } | ||
640 | |||
641 | return 0; | ||
642 | } | ||
643 | |||
644 | |||
645 | static int wm8955_set_sysclk(struct snd_soc_dai *dai, int clk_id, | ||
646 | unsigned int freq, int dir) | ||
647 | { | ||
648 | struct snd_soc_codec *codec = dai->codec; | ||
649 | struct wm8955_priv *priv = codec->private_data; | ||
650 | int div; | ||
651 | |||
652 | switch (clk_id) { | ||
653 | case WM8955_CLK_MCLK: | ||
654 | if (freq > 15000000) { | ||
655 | priv->mclk_rate = freq /= 2; | ||
656 | div = WM8955_MCLKDIV2; | ||
657 | } else { | ||
658 | priv->mclk_rate = freq; | ||
659 | div = 0; | ||
660 | } | ||
661 | |||
662 | snd_soc_update_bits(codec, WM8955_SAMPLE_RATE, | ||
663 | WM8955_MCLKDIV2, div); | ||
664 | break; | ||
665 | |||
666 | default: | ||
667 | return -EINVAL; | ||
668 | } | ||
669 | |||
670 | dev_dbg(dai->dev, "Clock source is %d at %uHz\n", clk_id, freq); | ||
671 | |||
672 | return 0; | ||
673 | } | ||
674 | |||
675 | static int wm8955_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) | ||
676 | { | ||
677 | struct snd_soc_codec *codec = dai->codec; | ||
678 | u16 aif = 0; | ||
679 | |||
680 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
681 | case SND_SOC_DAIFMT_CBS_CFS: | ||
682 | break; | ||
683 | case SND_SOC_DAIFMT_CBM_CFM: | ||
684 | aif |= WM8955_MS; | ||
685 | break; | ||
686 | default: | ||
687 | return -EINVAL; | ||
688 | } | ||
689 | |||
690 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
691 | case SND_SOC_DAIFMT_DSP_B: | ||
692 | aif |= WM8955_LRP; | ||
693 | case SND_SOC_DAIFMT_DSP_A: | ||
694 | aif |= 0x3; | ||
695 | break; | ||
696 | case SND_SOC_DAIFMT_I2S: | ||
697 | aif |= 0x2; | ||
698 | break; | ||
699 | case SND_SOC_DAIFMT_RIGHT_J: | ||
700 | break; | ||
701 | case SND_SOC_DAIFMT_LEFT_J: | ||
702 | aif |= 0x1; | ||
703 | break; | ||
704 | default: | ||
705 | return -EINVAL; | ||
706 | } | ||
707 | |||
708 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
709 | case SND_SOC_DAIFMT_DSP_A: | ||
710 | case SND_SOC_DAIFMT_DSP_B: | ||
711 | /* frame inversion not valid for DSP modes */ | ||
712 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
713 | case SND_SOC_DAIFMT_NB_NF: | ||
714 | break; | ||
715 | case SND_SOC_DAIFMT_IB_NF: | ||
716 | aif |= WM8955_BCLKINV; | ||
717 | break; | ||
718 | default: | ||
719 | return -EINVAL; | ||
720 | } | ||
721 | break; | ||
722 | |||
723 | case SND_SOC_DAIFMT_I2S: | ||
724 | case SND_SOC_DAIFMT_RIGHT_J: | ||
725 | case SND_SOC_DAIFMT_LEFT_J: | ||
726 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
727 | case SND_SOC_DAIFMT_NB_NF: | ||
728 | break; | ||
729 | case SND_SOC_DAIFMT_IB_IF: | ||
730 | aif |= WM8955_BCLKINV | WM8955_LRP; | ||
731 | break; | ||
732 | case SND_SOC_DAIFMT_IB_NF: | ||
733 | aif |= WM8955_BCLKINV; | ||
734 | break; | ||
735 | case SND_SOC_DAIFMT_NB_IF: | ||
736 | aif |= WM8955_LRP; | ||
737 | break; | ||
738 | default: | ||
739 | return -EINVAL; | ||
740 | } | ||
741 | break; | ||
742 | default: | ||
743 | return -EINVAL; | ||
744 | } | ||
745 | |||
746 | snd_soc_update_bits(codec, WM8955_AUDIO_INTERFACE, | ||
747 | WM8955_MS | WM8955_FORMAT_MASK | WM8955_BCLKINV | | ||
748 | WM8955_LRP, aif); | ||
749 | |||
750 | return 0; | ||
751 | } | ||
752 | |||
753 | |||
754 | static int wm8955_digital_mute(struct snd_soc_dai *codec_dai, int mute) | ||
755 | { | ||
756 | struct snd_soc_codec *codec = codec_dai->codec; | ||
757 | int val; | ||
758 | |||
759 | if (mute) | ||
760 | val = WM8955_DACMU; | ||
761 | else | ||
762 | val = 0; | ||
763 | |||
764 | snd_soc_update_bits(codec, WM8955_DAC_CONTROL, WM8955_DACMU, val); | ||
765 | |||
766 | return 0; | ||
767 | } | ||
768 | |||
769 | static int wm8955_set_bias_level(struct snd_soc_codec *codec, | ||
770 | enum snd_soc_bias_level level) | ||
771 | { | ||
772 | struct wm8955_priv *wm8955 = codec->private_data; | ||
773 | int ret, i; | ||
774 | |||
775 | switch (level) { | ||
776 | case SND_SOC_BIAS_ON: | ||
777 | break; | ||
778 | |||
779 | case SND_SOC_BIAS_PREPARE: | ||
780 | /* VMID resistance 2*50k */ | ||
781 | snd_soc_update_bits(codec, WM8955_POWER_MANAGEMENT_1, | ||
782 | WM8955_VMIDSEL_MASK, | ||
783 | 0x1 << WM8955_VMIDSEL_SHIFT); | ||
784 | |||
785 | /* Default bias current */ | ||
786 | snd_soc_update_bits(codec, WM8955_ADDITIONAL_CONTROL_1, | ||
787 | WM8955_VSEL_MASK, | ||
788 | 0x2 << WM8955_VSEL_SHIFT); | ||
789 | break; | ||
790 | |||
791 | case SND_SOC_BIAS_STANDBY: | ||
792 | if (codec->bias_level == SND_SOC_BIAS_OFF) { | ||
793 | ret = regulator_bulk_enable(ARRAY_SIZE(wm8955->supplies), | ||
794 | wm8955->supplies); | ||
795 | if (ret != 0) { | ||
796 | dev_err(codec->dev, | ||
797 | "Failed to enable supplies: %d\n", | ||
798 | ret); | ||
799 | return ret; | ||
800 | } | ||
801 | |||
802 | /* Sync back cached values if they're | ||
803 | * different from the hardware default. | ||
804 | */ | ||
805 | for (i = 0; i < ARRAY_SIZE(wm8955->reg_cache); i++) { | ||
806 | if (i == WM8955_RESET) | ||
807 | continue; | ||
808 | |||
809 | if (wm8955->reg_cache[i] == wm8955_reg[i]) | ||
810 | continue; | ||
811 | |||
812 | snd_soc_write(codec, i, wm8955->reg_cache[i]); | ||
813 | } | ||
814 | |||
815 | /* Enable VREF and VMID */ | ||
816 | snd_soc_update_bits(codec, WM8955_POWER_MANAGEMENT_1, | ||
817 | WM8955_VREF | | ||
818 | WM8955_VMIDSEL_MASK, | ||
819 | WM8955_VREF | | ||
820 | 0x3 << WM8955_VREF_SHIFT); | ||
821 | |||
822 | /* Let VMID ramp */ | ||
823 | msleep(500); | ||
824 | |||
825 | /* High resistance VROI to maintain outputs */ | ||
826 | snd_soc_update_bits(codec, | ||
827 | WM8955_ADDITIONAL_CONTROL_3, | ||
828 | WM8955_VROI, WM8955_VROI); | ||
829 | } | ||
830 | |||
831 | /* Maintain VMID with 2*250k */ | ||
832 | snd_soc_update_bits(codec, WM8955_POWER_MANAGEMENT_1, | ||
833 | WM8955_VMIDSEL_MASK, | ||
834 | 0x2 << WM8955_VMIDSEL_SHIFT); | ||
835 | |||
836 | /* Minimum bias current */ | ||
837 | snd_soc_update_bits(codec, WM8955_ADDITIONAL_CONTROL_1, | ||
838 | WM8955_VSEL_MASK, 0); | ||
839 | break; | ||
840 | |||
841 | case SND_SOC_BIAS_OFF: | ||
842 | /* Low resistance VROI to help discharge */ | ||
843 | snd_soc_update_bits(codec, | ||
844 | WM8955_ADDITIONAL_CONTROL_3, | ||
845 | WM8955_VROI, 0); | ||
846 | |||
847 | /* Turn off VMID and VREF */ | ||
848 | snd_soc_update_bits(codec, WM8955_POWER_MANAGEMENT_1, | ||
849 | WM8955_VREF | | ||
850 | WM8955_VMIDSEL_MASK, 0); | ||
851 | |||
852 | regulator_bulk_disable(ARRAY_SIZE(wm8955->supplies), | ||
853 | wm8955->supplies); | ||
854 | break; | ||
855 | } | ||
856 | codec->bias_level = level; | ||
857 | return 0; | ||
858 | } | ||
859 | |||
860 | #define WM8955_RATES SNDRV_PCM_RATE_8000_96000 | ||
861 | |||
862 | #define WM8955_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | ||
863 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) | ||
864 | |||
865 | static struct snd_soc_dai_ops wm8955_dai_ops = { | ||
866 | .set_sysclk = wm8955_set_sysclk, | ||
867 | .set_fmt = wm8955_set_fmt, | ||
868 | .hw_params = wm8955_hw_params, | ||
869 | .digital_mute = wm8955_digital_mute, | ||
870 | }; | ||
871 | |||
872 | struct snd_soc_dai wm8955_dai = { | ||
873 | .name = "WM8955", | ||
874 | .playback = { | ||
875 | .stream_name = "Playback", | ||
876 | .channels_min = 2, | ||
877 | .channels_max = 2, | ||
878 | .rates = WM8955_RATES, | ||
879 | .formats = WM8955_FORMATS, | ||
880 | }, | ||
881 | .ops = &wm8955_dai_ops, | ||
882 | }; | ||
883 | EXPORT_SYMBOL_GPL(wm8955_dai); | ||
884 | |||
885 | #ifdef CONFIG_PM | ||
886 | static int wm8955_suspend(struct platform_device *pdev, pm_message_t state) | ||
887 | { | ||
888 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
889 | struct snd_soc_codec *codec = socdev->card->codec; | ||
890 | |||
891 | wm8955_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
892 | |||
893 | return 0; | ||
894 | } | ||
895 | |||
896 | static int wm8955_resume(struct platform_device *pdev) | ||
897 | { | ||
898 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
899 | struct snd_soc_codec *codec = socdev->card->codec; | ||
900 | |||
901 | wm8955_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
902 | |||
903 | return 0; | ||
904 | } | ||
905 | #else | ||
906 | #define wm8955_suspend NULL | ||
907 | #define wm8955_resume NULL | ||
908 | #endif | ||
909 | |||
910 | static int wm8955_probe(struct platform_device *pdev) | ||
911 | { | ||
912 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
913 | struct snd_soc_codec *codec; | ||
914 | int ret = 0; | ||
915 | |||
916 | if (wm8955_codec == NULL) { | ||
917 | dev_err(&pdev->dev, "Codec device not registered\n"); | ||
918 | return -ENODEV; | ||
919 | } | ||
920 | |||
921 | socdev->card->codec = wm8955_codec; | ||
922 | codec = wm8955_codec; | ||
923 | |||
924 | /* register pcms */ | ||
925 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
926 | if (ret < 0) { | ||
927 | dev_err(codec->dev, "failed to create pcms: %d\n", ret); | ||
928 | goto pcm_err; | ||
929 | } | ||
930 | |||
931 | wm8955_add_widgets(codec); | ||
932 | |||
933 | return ret; | ||
934 | |||
935 | pcm_err: | ||
936 | return ret; | ||
937 | } | ||
938 | |||
939 | static int wm8955_remove(struct platform_device *pdev) | ||
940 | { | ||
941 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
942 | |||
943 | snd_soc_free_pcms(socdev); | ||
944 | snd_soc_dapm_free(socdev); | ||
945 | |||
946 | return 0; | ||
947 | } | ||
948 | |||
949 | struct snd_soc_codec_device soc_codec_dev_wm8955 = { | ||
950 | .probe = wm8955_probe, | ||
951 | .remove = wm8955_remove, | ||
952 | .suspend = wm8955_suspend, | ||
953 | .resume = wm8955_resume, | ||
954 | }; | ||
955 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8955); | ||
956 | |||
957 | static int wm8955_register(struct wm8955_priv *wm8955, | ||
958 | enum snd_soc_control_type control) | ||
959 | { | ||
960 | int ret; | ||
961 | struct snd_soc_codec *codec = &wm8955->codec; | ||
962 | int i; | ||
963 | |||
964 | if (wm8955_codec) { | ||
965 | dev_err(codec->dev, "Another WM8955 is registered\n"); | ||
966 | return -EINVAL; | ||
967 | } | ||
968 | |||
969 | mutex_init(&codec->mutex); | ||
970 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
971 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
972 | |||
973 | codec->private_data = wm8955; | ||
974 | codec->name = "WM8955"; | ||
975 | codec->owner = THIS_MODULE; | ||
976 | codec->bias_level = SND_SOC_BIAS_OFF; | ||
977 | codec->set_bias_level = wm8955_set_bias_level; | ||
978 | codec->dai = &wm8955_dai; | ||
979 | codec->num_dai = 1; | ||
980 | codec->reg_cache_size = WM8955_MAX_REGISTER; | ||
981 | codec->reg_cache = &wm8955->reg_cache; | ||
982 | |||
983 | memcpy(codec->reg_cache, wm8955_reg, sizeof(wm8955_reg)); | ||
984 | |||
985 | ret = snd_soc_codec_set_cache_io(codec, 7, 9, control); | ||
986 | if (ret != 0) { | ||
987 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); | ||
988 | goto err; | ||
989 | } | ||
990 | |||
991 | for (i = 0; i < ARRAY_SIZE(wm8955->supplies); i++) | ||
992 | wm8955->supplies[i].supply = wm8955_supply_names[i]; | ||
993 | |||
994 | ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8955->supplies), | ||
995 | wm8955->supplies); | ||
996 | if (ret != 0) { | ||
997 | dev_err(codec->dev, "Failed to request supplies: %d\n", ret); | ||
998 | goto err; | ||
999 | } | ||
1000 | |||
1001 | ret = regulator_bulk_enable(ARRAY_SIZE(wm8955->supplies), | ||
1002 | wm8955->supplies); | ||
1003 | if (ret != 0) { | ||
1004 | dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); | ||
1005 | goto err_get; | ||
1006 | } | ||
1007 | |||
1008 | ret = wm8955_reset(codec); | ||
1009 | if (ret < 0) { | ||
1010 | dev_err(codec->dev, "Failed to issue reset: %d\n", ret); | ||
1011 | goto err_enable; | ||
1012 | } | ||
1013 | |||
1014 | wm8955_dai.dev = codec->dev; | ||
1015 | |||
1016 | /* Change some default settings - latch VU and enable ZC */ | ||
1017 | wm8955->reg_cache[WM8955_LEFT_DAC_VOLUME] |= WM8955_LDVU; | ||
1018 | wm8955->reg_cache[WM8955_RIGHT_DAC_VOLUME] |= WM8955_RDVU; | ||
1019 | wm8955->reg_cache[WM8955_LOUT1_VOLUME] |= WM8955_LO1VU | WM8955_LO1ZC; | ||
1020 | wm8955->reg_cache[WM8955_ROUT1_VOLUME] |= WM8955_RO1VU | WM8955_RO1ZC; | ||
1021 | wm8955->reg_cache[WM8955_LOUT2_VOLUME] |= WM8955_LO2VU | WM8955_LO2ZC; | ||
1022 | wm8955->reg_cache[WM8955_ROUT2_VOLUME] |= WM8955_RO2VU | WM8955_RO2ZC; | ||
1023 | wm8955->reg_cache[WM8955_MONOOUT_VOLUME] |= WM8955_MOZC; | ||
1024 | |||
1025 | /* Also enable adaptive bass boost by default */ | ||
1026 | wm8955->reg_cache[WM8955_BASS_CONTROL] |= WM8955_BB; | ||
1027 | |||
1028 | /* Set platform data values */ | ||
1029 | if (wm8955->pdata) { | ||
1030 | if (wm8955->pdata->out2_speaker) | ||
1031 | wm8955->reg_cache[WM8955_ADDITIONAL_CONTROL_2] | ||
1032 | |= WM8955_ROUT2INV; | ||
1033 | |||
1034 | if (wm8955->pdata->monoin_diff) | ||
1035 | wm8955->reg_cache[WM8955_MONO_OUT_MIX_1] | ||
1036 | |= WM8955_DMEN; | ||
1037 | } | ||
1038 | |||
1039 | wm8955_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1040 | |||
1041 | /* Bias level configuration will have done an extra enable */ | ||
1042 | regulator_bulk_disable(ARRAY_SIZE(wm8955->supplies), wm8955->supplies); | ||
1043 | |||
1044 | wm8955_codec = codec; | ||
1045 | |||
1046 | ret = snd_soc_register_codec(codec); | ||
1047 | if (ret != 0) { | ||
1048 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); | ||
1049 | return ret; | ||
1050 | } | ||
1051 | |||
1052 | ret = snd_soc_register_dai(&wm8955_dai); | ||
1053 | if (ret != 0) { | ||
1054 | dev_err(codec->dev, "Failed to register DAI: %d\n", ret); | ||
1055 | snd_soc_unregister_codec(codec); | ||
1056 | return ret; | ||
1057 | } | ||
1058 | |||
1059 | return 0; | ||
1060 | |||
1061 | err_enable: | ||
1062 | regulator_bulk_disable(ARRAY_SIZE(wm8955->supplies), wm8955->supplies); | ||
1063 | err_get: | ||
1064 | regulator_bulk_free(ARRAY_SIZE(wm8955->supplies), wm8955->supplies); | ||
1065 | err: | ||
1066 | kfree(wm8955); | ||
1067 | return ret; | ||
1068 | } | ||
1069 | |||
1070 | static void wm8955_unregister(struct wm8955_priv *wm8955) | ||
1071 | { | ||
1072 | wm8955_set_bias_level(&wm8955->codec, SND_SOC_BIAS_OFF); | ||
1073 | regulator_bulk_free(ARRAY_SIZE(wm8955->supplies), wm8955->supplies); | ||
1074 | snd_soc_unregister_dai(&wm8955_dai); | ||
1075 | snd_soc_unregister_codec(&wm8955->codec); | ||
1076 | kfree(wm8955); | ||
1077 | wm8955_codec = NULL; | ||
1078 | } | ||
1079 | |||
1080 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
1081 | static __devinit int wm8955_i2c_probe(struct i2c_client *i2c, | ||
1082 | const struct i2c_device_id *id) | ||
1083 | { | ||
1084 | struct wm8955_priv *wm8955; | ||
1085 | struct snd_soc_codec *codec; | ||
1086 | |||
1087 | wm8955 = kzalloc(sizeof(struct wm8955_priv), GFP_KERNEL); | ||
1088 | if (wm8955 == NULL) | ||
1089 | return -ENOMEM; | ||
1090 | |||
1091 | codec = &wm8955->codec; | ||
1092 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
1093 | |||
1094 | i2c_set_clientdata(i2c, wm8955); | ||
1095 | codec->control_data = i2c; | ||
1096 | wm8955->pdata = i2c->dev.platform_data; | ||
1097 | |||
1098 | codec->dev = &i2c->dev; | ||
1099 | |||
1100 | return wm8955_register(wm8955, SND_SOC_I2C); | ||
1101 | } | ||
1102 | |||
1103 | static __devexit int wm8955_i2c_remove(struct i2c_client *client) | ||
1104 | { | ||
1105 | struct wm8955_priv *wm8955 = i2c_get_clientdata(client); | ||
1106 | wm8955_unregister(wm8955); | ||
1107 | return 0; | ||
1108 | } | ||
1109 | |||
1110 | static const struct i2c_device_id wm8955_i2c_id[] = { | ||
1111 | { "wm8955", 0 }, | ||
1112 | { } | ||
1113 | }; | ||
1114 | MODULE_DEVICE_TABLE(i2c, wm8955_i2c_id); | ||
1115 | |||
1116 | static struct i2c_driver wm8955_i2c_driver = { | ||
1117 | .driver = { | ||
1118 | .name = "wm8955", | ||
1119 | .owner = THIS_MODULE, | ||
1120 | }, | ||
1121 | .probe = wm8955_i2c_probe, | ||
1122 | .remove = __devexit_p(wm8955_i2c_remove), | ||
1123 | .id_table = wm8955_i2c_id, | ||
1124 | }; | ||
1125 | #endif | ||
1126 | |||
1127 | static int __init wm8955_modinit(void) | ||
1128 | { | ||
1129 | int ret; | ||
1130 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
1131 | ret = i2c_add_driver(&wm8955_i2c_driver); | ||
1132 | if (ret != 0) { | ||
1133 | printk(KERN_ERR "Failed to register WM8955 I2C driver: %d\n", | ||
1134 | ret); | ||
1135 | } | ||
1136 | #endif | ||
1137 | return 0; | ||
1138 | } | ||
1139 | module_init(wm8955_modinit); | ||
1140 | |||
1141 | static void __exit wm8955_exit(void) | ||
1142 | { | ||
1143 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
1144 | i2c_del_driver(&wm8955_i2c_driver); | ||
1145 | #endif | ||
1146 | } | ||
1147 | module_exit(wm8955_exit); | ||
1148 | |||
1149 | MODULE_DESCRIPTION("ASoC WM8955 driver"); | ||
1150 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); | ||
1151 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/wm8955.h b/sound/soc/codecs/wm8955.h new file mode 100644 index 000000000000..ae349c8531f6 --- /dev/null +++ b/sound/soc/codecs/wm8955.h | |||
@@ -0,0 +1,489 @@ | |||
1 | /* | ||
2 | * wm8955.h -- WM8904 ASoC driver | ||
3 | * | ||
4 | * Copyright 2009 Wolfson Microelectronics, plc | ||
5 | * | ||
6 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | ||
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 _WM8955_H | ||
14 | #define _WM8955_H | ||
15 | |||
16 | #define WM8955_CLK_MCLK 1 | ||
17 | |||
18 | extern struct snd_soc_dai wm8955_dai; | ||
19 | extern struct snd_soc_codec_device soc_codec_dev_wm8955; | ||
20 | |||
21 | /* | ||
22 | * Register values. | ||
23 | */ | ||
24 | #define WM8955_LOUT1_VOLUME 0x02 | ||
25 | #define WM8955_ROUT1_VOLUME 0x03 | ||
26 | #define WM8955_DAC_CONTROL 0x05 | ||
27 | #define WM8955_AUDIO_INTERFACE 0x07 | ||
28 | #define WM8955_SAMPLE_RATE 0x08 | ||
29 | #define WM8955_LEFT_DAC_VOLUME 0x0A | ||
30 | #define WM8955_RIGHT_DAC_VOLUME 0x0B | ||
31 | #define WM8955_BASS_CONTROL 0x0C | ||
32 | #define WM8955_TREBLE_CONTROL 0x0D | ||
33 | #define WM8955_RESET 0x0F | ||
34 | #define WM8955_ADDITIONAL_CONTROL_1 0x17 | ||
35 | #define WM8955_ADDITIONAL_CONTROL_2 0x18 | ||
36 | #define WM8955_POWER_MANAGEMENT_1 0x19 | ||
37 | #define WM8955_POWER_MANAGEMENT_2 0x1A | ||
38 | #define WM8955_ADDITIONAL_CONTROL_3 0x1B | ||
39 | #define WM8955_LEFT_OUT_MIX_1 0x22 | ||
40 | #define WM8955_LEFT_OUT_MIX_2 0x23 | ||
41 | #define WM8955_RIGHT_OUT_MIX_1 0x24 | ||
42 | #define WM8955_RIGHT_OUT_MIX_2 0x25 | ||
43 | #define WM8955_MONO_OUT_MIX_1 0x26 | ||
44 | #define WM8955_MONO_OUT_MIX_2 0x27 | ||
45 | #define WM8955_LOUT2_VOLUME 0x28 | ||
46 | #define WM8955_ROUT2_VOLUME 0x29 | ||
47 | #define WM8955_MONOOUT_VOLUME 0x2A | ||
48 | #define WM8955_CLOCKING_PLL 0x2B | ||
49 | #define WM8955_PLL_CONTROL_1 0x2C | ||
50 | #define WM8955_PLL_CONTROL_2 0x2D | ||
51 | #define WM8955_PLL_CONTROL_3 0x2E | ||
52 | #define WM8955_PLL_CONTROL_4 0x3B | ||
53 | |||
54 | #define WM8955_REGISTER_COUNT 29 | ||
55 | #define WM8955_MAX_REGISTER 0x3B | ||
56 | |||
57 | /* | ||
58 | * Field Definitions. | ||
59 | */ | ||
60 | |||
61 | /* | ||
62 | * R2 (0x02) - LOUT1 volume | ||
63 | */ | ||
64 | #define WM8955_LO1VU 0x0100 /* LO1VU */ | ||
65 | #define WM8955_LO1VU_MASK 0x0100 /* LO1VU */ | ||
66 | #define WM8955_LO1VU_SHIFT 8 /* LO1VU */ | ||
67 | #define WM8955_LO1VU_WIDTH 1 /* LO1VU */ | ||
68 | #define WM8955_LO1ZC 0x0080 /* LO1ZC */ | ||
69 | #define WM8955_LO1ZC_MASK 0x0080 /* LO1ZC */ | ||
70 | #define WM8955_LO1ZC_SHIFT 7 /* LO1ZC */ | ||
71 | #define WM8955_LO1ZC_WIDTH 1 /* LO1ZC */ | ||
72 | #define WM8955_LOUTVOL_MASK 0x007F /* LOUTVOL - [6:0] */ | ||
73 | #define WM8955_LOUTVOL_SHIFT 0 /* LOUTVOL - [6:0] */ | ||
74 | #define WM8955_LOUTVOL_WIDTH 7 /* LOUTVOL - [6:0] */ | ||
75 | |||
76 | /* | ||
77 | * R3 (0x03) - ROUT1 volume | ||
78 | */ | ||
79 | #define WM8955_RO1VU 0x0100 /* RO1VU */ | ||
80 | #define WM8955_RO1VU_MASK 0x0100 /* RO1VU */ | ||
81 | #define WM8955_RO1VU_SHIFT 8 /* RO1VU */ | ||
82 | #define WM8955_RO1VU_WIDTH 1 /* RO1VU */ | ||
83 | #define WM8955_RO1ZC 0x0080 /* RO1ZC */ | ||
84 | #define WM8955_RO1ZC_MASK 0x0080 /* RO1ZC */ | ||
85 | #define WM8955_RO1ZC_SHIFT 7 /* RO1ZC */ | ||
86 | #define WM8955_RO1ZC_WIDTH 1 /* RO1ZC */ | ||
87 | #define WM8955_ROUTVOL_MASK 0x007F /* ROUTVOL - [6:0] */ | ||
88 | #define WM8955_ROUTVOL_SHIFT 0 /* ROUTVOL - [6:0] */ | ||
89 | #define WM8955_ROUTVOL_WIDTH 7 /* ROUTVOL - [6:0] */ | ||
90 | |||
91 | /* | ||
92 | * R5 (0x05) - DAC Control | ||
93 | */ | ||
94 | #define WM8955_DAT 0x0080 /* DAT */ | ||
95 | #define WM8955_DAT_MASK 0x0080 /* DAT */ | ||
96 | #define WM8955_DAT_SHIFT 7 /* DAT */ | ||
97 | #define WM8955_DAT_WIDTH 1 /* DAT */ | ||
98 | #define WM8955_DACMU 0x0008 /* DACMU */ | ||
99 | #define WM8955_DACMU_MASK 0x0008 /* DACMU */ | ||
100 | #define WM8955_DACMU_SHIFT 3 /* DACMU */ | ||
101 | #define WM8955_DACMU_WIDTH 1 /* DACMU */ | ||
102 | #define WM8955_DEEMPH_MASK 0x0006 /* DEEMPH - [2:1] */ | ||
103 | #define WM8955_DEEMPH_SHIFT 1 /* DEEMPH - [2:1] */ | ||
104 | #define WM8955_DEEMPH_WIDTH 2 /* DEEMPH - [2:1] */ | ||
105 | |||
106 | /* | ||
107 | * R7 (0x07) - Audio Interface | ||
108 | */ | ||
109 | #define WM8955_BCLKINV 0x0080 /* BCLKINV */ | ||
110 | #define WM8955_BCLKINV_MASK 0x0080 /* BCLKINV */ | ||
111 | #define WM8955_BCLKINV_SHIFT 7 /* BCLKINV */ | ||
112 | #define WM8955_BCLKINV_WIDTH 1 /* BCLKINV */ | ||
113 | #define WM8955_MS 0x0040 /* MS */ | ||
114 | #define WM8955_MS_MASK 0x0040 /* MS */ | ||
115 | #define WM8955_MS_SHIFT 6 /* MS */ | ||
116 | #define WM8955_MS_WIDTH 1 /* MS */ | ||
117 | #define WM8955_LRSWAP 0x0020 /* LRSWAP */ | ||
118 | #define WM8955_LRSWAP_MASK 0x0020 /* LRSWAP */ | ||
119 | #define WM8955_LRSWAP_SHIFT 5 /* LRSWAP */ | ||
120 | #define WM8955_LRSWAP_WIDTH 1 /* LRSWAP */ | ||
121 | #define WM8955_LRP 0x0010 /* LRP */ | ||
122 | #define WM8955_LRP_MASK 0x0010 /* LRP */ | ||
123 | #define WM8955_LRP_SHIFT 4 /* LRP */ | ||
124 | #define WM8955_LRP_WIDTH 1 /* LRP */ | ||
125 | #define WM8955_WL_MASK 0x000C /* WL - [3:2] */ | ||
126 | #define WM8955_WL_SHIFT 2 /* WL - [3:2] */ | ||
127 | #define WM8955_WL_WIDTH 2 /* WL - [3:2] */ | ||
128 | #define WM8955_FORMAT_MASK 0x0003 /* FORMAT - [1:0] */ | ||
129 | #define WM8955_FORMAT_SHIFT 0 /* FORMAT - [1:0] */ | ||
130 | #define WM8955_FORMAT_WIDTH 2 /* FORMAT - [1:0] */ | ||
131 | |||
132 | /* | ||
133 | * R8 (0x08) - Sample Rate | ||
134 | */ | ||
135 | #define WM8955_BCLKDIV2 0x0080 /* BCLKDIV2 */ | ||
136 | #define WM8955_BCLKDIV2_MASK 0x0080 /* BCLKDIV2 */ | ||
137 | #define WM8955_BCLKDIV2_SHIFT 7 /* BCLKDIV2 */ | ||
138 | #define WM8955_BCLKDIV2_WIDTH 1 /* BCLKDIV2 */ | ||
139 | #define WM8955_MCLKDIV2 0x0040 /* MCLKDIV2 */ | ||
140 | #define WM8955_MCLKDIV2_MASK 0x0040 /* MCLKDIV2 */ | ||
141 | #define WM8955_MCLKDIV2_SHIFT 6 /* MCLKDIV2 */ | ||
142 | #define WM8955_MCLKDIV2_WIDTH 1 /* MCLKDIV2 */ | ||
143 | #define WM8955_SR_MASK 0x003E /* SR - [5:1] */ | ||
144 | #define WM8955_SR_SHIFT 1 /* SR - [5:1] */ | ||
145 | #define WM8955_SR_WIDTH 5 /* SR - [5:1] */ | ||
146 | #define WM8955_USB 0x0001 /* USB */ | ||
147 | #define WM8955_USB_MASK 0x0001 /* USB */ | ||
148 | #define WM8955_USB_SHIFT 0 /* USB */ | ||
149 | #define WM8955_USB_WIDTH 1 /* USB */ | ||
150 | |||
151 | /* | ||
152 | * R10 (0x0A) - Left DAC volume | ||
153 | */ | ||
154 | #define WM8955_LDVU 0x0100 /* LDVU */ | ||
155 | #define WM8955_LDVU_MASK 0x0100 /* LDVU */ | ||
156 | #define WM8955_LDVU_SHIFT 8 /* LDVU */ | ||
157 | #define WM8955_LDVU_WIDTH 1 /* LDVU */ | ||
158 | #define WM8955_LDACVOL_MASK 0x00FF /* LDACVOL - [7:0] */ | ||
159 | #define WM8955_LDACVOL_SHIFT 0 /* LDACVOL - [7:0] */ | ||
160 | #define WM8955_LDACVOL_WIDTH 8 /* LDACVOL - [7:0] */ | ||
161 | |||
162 | /* | ||
163 | * R11 (0x0B) - Right DAC volume | ||
164 | */ | ||
165 | #define WM8955_RDVU 0x0100 /* RDVU */ | ||
166 | #define WM8955_RDVU_MASK 0x0100 /* RDVU */ | ||
167 | #define WM8955_RDVU_SHIFT 8 /* RDVU */ | ||
168 | #define WM8955_RDVU_WIDTH 1 /* RDVU */ | ||
169 | #define WM8955_RDACVOL_MASK 0x00FF /* RDACVOL - [7:0] */ | ||
170 | #define WM8955_RDACVOL_SHIFT 0 /* RDACVOL - [7:0] */ | ||
171 | #define WM8955_RDACVOL_WIDTH 8 /* RDACVOL - [7:0] */ | ||
172 | |||
173 | /* | ||
174 | * R12 (0x0C) - Bass control | ||
175 | */ | ||
176 | #define WM8955_BB 0x0080 /* BB */ | ||
177 | #define WM8955_BB_MASK 0x0080 /* BB */ | ||
178 | #define WM8955_BB_SHIFT 7 /* BB */ | ||
179 | #define WM8955_BB_WIDTH 1 /* BB */ | ||
180 | #define WM8955_BC 0x0040 /* BC */ | ||
181 | #define WM8955_BC_MASK 0x0040 /* BC */ | ||
182 | #define WM8955_BC_SHIFT 6 /* BC */ | ||
183 | #define WM8955_BC_WIDTH 1 /* BC */ | ||
184 | #define WM8955_BASS_MASK 0x000F /* BASS - [3:0] */ | ||
185 | #define WM8955_BASS_SHIFT 0 /* BASS - [3:0] */ | ||
186 | #define WM8955_BASS_WIDTH 4 /* BASS - [3:0] */ | ||
187 | |||
188 | /* | ||
189 | * R13 (0x0D) - Treble control | ||
190 | */ | ||
191 | #define WM8955_TC 0x0040 /* TC */ | ||
192 | #define WM8955_TC_MASK 0x0040 /* TC */ | ||
193 | #define WM8955_TC_SHIFT 6 /* TC */ | ||
194 | #define WM8955_TC_WIDTH 1 /* TC */ | ||
195 | #define WM8955_TRBL_MASK 0x000F /* TRBL - [3:0] */ | ||
196 | #define WM8955_TRBL_SHIFT 0 /* TRBL - [3:0] */ | ||
197 | #define WM8955_TRBL_WIDTH 4 /* TRBL - [3:0] */ | ||
198 | |||
199 | /* | ||
200 | * R15 (0x0F) - Reset | ||
201 | */ | ||
202 | #define WM8955_RESET_MASK 0x01FF /* RESET - [8:0] */ | ||
203 | #define WM8955_RESET_SHIFT 0 /* RESET - [8:0] */ | ||
204 | #define WM8955_RESET_WIDTH 9 /* RESET - [8:0] */ | ||
205 | |||
206 | /* | ||
207 | * R23 (0x17) - Additional control (1) | ||
208 | */ | ||
209 | #define WM8955_TSDEN 0x0100 /* TSDEN */ | ||
210 | #define WM8955_TSDEN_MASK 0x0100 /* TSDEN */ | ||
211 | #define WM8955_TSDEN_SHIFT 8 /* TSDEN */ | ||
212 | #define WM8955_TSDEN_WIDTH 1 /* TSDEN */ | ||
213 | #define WM8955_VSEL_MASK 0x00C0 /* VSEL - [7:6] */ | ||
214 | #define WM8955_VSEL_SHIFT 6 /* VSEL - [7:6] */ | ||
215 | #define WM8955_VSEL_WIDTH 2 /* VSEL - [7:6] */ | ||
216 | #define WM8955_DMONOMIX_MASK 0x0030 /* DMONOMIX - [5:4] */ | ||
217 | #define WM8955_DMONOMIX_SHIFT 4 /* DMONOMIX - [5:4] */ | ||
218 | #define WM8955_DMONOMIX_WIDTH 2 /* DMONOMIX - [5:4] */ | ||
219 | #define WM8955_DACINV 0x0002 /* DACINV */ | ||
220 | #define WM8955_DACINV_MASK 0x0002 /* DACINV */ | ||
221 | #define WM8955_DACINV_SHIFT 1 /* DACINV */ | ||
222 | #define WM8955_DACINV_WIDTH 1 /* DACINV */ | ||
223 | #define WM8955_TOEN 0x0001 /* TOEN */ | ||
224 | #define WM8955_TOEN_MASK 0x0001 /* TOEN */ | ||
225 | #define WM8955_TOEN_SHIFT 0 /* TOEN */ | ||
226 | #define WM8955_TOEN_WIDTH 1 /* TOEN */ | ||
227 | |||
228 | /* | ||
229 | * R24 (0x18) - Additional control (2) | ||
230 | */ | ||
231 | #define WM8955_OUT3SW_MASK 0x0180 /* OUT3SW - [8:7] */ | ||
232 | #define WM8955_OUT3SW_SHIFT 7 /* OUT3SW - [8:7] */ | ||
233 | #define WM8955_OUT3SW_WIDTH 2 /* OUT3SW - [8:7] */ | ||
234 | #define WM8955_ROUT2INV 0x0010 /* ROUT2INV */ | ||
235 | #define WM8955_ROUT2INV_MASK 0x0010 /* ROUT2INV */ | ||
236 | #define WM8955_ROUT2INV_SHIFT 4 /* ROUT2INV */ | ||
237 | #define WM8955_ROUT2INV_WIDTH 1 /* ROUT2INV */ | ||
238 | #define WM8955_DACOSR 0x0001 /* DACOSR */ | ||
239 | #define WM8955_DACOSR_MASK 0x0001 /* DACOSR */ | ||
240 | #define WM8955_DACOSR_SHIFT 0 /* DACOSR */ | ||
241 | #define WM8955_DACOSR_WIDTH 1 /* DACOSR */ | ||
242 | |||
243 | /* | ||
244 | * R25 (0x19) - Power Management (1) | ||
245 | */ | ||
246 | #define WM8955_VMIDSEL_MASK 0x0180 /* VMIDSEL - [8:7] */ | ||
247 | #define WM8955_VMIDSEL_SHIFT 7 /* VMIDSEL - [8:7] */ | ||
248 | #define WM8955_VMIDSEL_WIDTH 2 /* VMIDSEL - [8:7] */ | ||
249 | #define WM8955_VREF 0x0040 /* VREF */ | ||
250 | #define WM8955_VREF_MASK 0x0040 /* VREF */ | ||
251 | #define WM8955_VREF_SHIFT 6 /* VREF */ | ||
252 | #define WM8955_VREF_WIDTH 1 /* VREF */ | ||
253 | #define WM8955_DIGENB 0x0001 /* DIGENB */ | ||
254 | #define WM8955_DIGENB_MASK 0x0001 /* DIGENB */ | ||
255 | #define WM8955_DIGENB_SHIFT 0 /* DIGENB */ | ||
256 | #define WM8955_DIGENB_WIDTH 1 /* DIGENB */ | ||
257 | |||
258 | /* | ||
259 | * R26 (0x1A) - Power Management (2) | ||
260 | */ | ||
261 | #define WM8955_DACL 0x0100 /* DACL */ | ||
262 | #define WM8955_DACL_MASK 0x0100 /* DACL */ | ||
263 | #define WM8955_DACL_SHIFT 8 /* DACL */ | ||
264 | #define WM8955_DACL_WIDTH 1 /* DACL */ | ||
265 | #define WM8955_DACR 0x0080 /* DACR */ | ||
266 | #define WM8955_DACR_MASK 0x0080 /* DACR */ | ||
267 | #define WM8955_DACR_SHIFT 7 /* DACR */ | ||
268 | #define WM8955_DACR_WIDTH 1 /* DACR */ | ||
269 | #define WM8955_LOUT1 0x0040 /* LOUT1 */ | ||
270 | #define WM8955_LOUT1_MASK 0x0040 /* LOUT1 */ | ||
271 | #define WM8955_LOUT1_SHIFT 6 /* LOUT1 */ | ||
272 | #define WM8955_LOUT1_WIDTH 1 /* LOUT1 */ | ||
273 | #define WM8955_ROUT1 0x0020 /* ROUT1 */ | ||
274 | #define WM8955_ROUT1_MASK 0x0020 /* ROUT1 */ | ||
275 | #define WM8955_ROUT1_SHIFT 5 /* ROUT1 */ | ||
276 | #define WM8955_ROUT1_WIDTH 1 /* ROUT1 */ | ||
277 | #define WM8955_LOUT2 0x0010 /* LOUT2 */ | ||
278 | #define WM8955_LOUT2_MASK 0x0010 /* LOUT2 */ | ||
279 | #define WM8955_LOUT2_SHIFT 4 /* LOUT2 */ | ||
280 | #define WM8955_LOUT2_WIDTH 1 /* LOUT2 */ | ||
281 | #define WM8955_ROUT2 0x0008 /* ROUT2 */ | ||
282 | #define WM8955_ROUT2_MASK 0x0008 /* ROUT2 */ | ||
283 | #define WM8955_ROUT2_SHIFT 3 /* ROUT2 */ | ||
284 | #define WM8955_ROUT2_WIDTH 1 /* ROUT2 */ | ||
285 | #define WM8955_MONO 0x0004 /* MONO */ | ||
286 | #define WM8955_MONO_MASK 0x0004 /* MONO */ | ||
287 | #define WM8955_MONO_SHIFT 2 /* MONO */ | ||
288 | #define WM8955_MONO_WIDTH 1 /* MONO */ | ||
289 | #define WM8955_OUT3 0x0002 /* OUT3 */ | ||
290 | #define WM8955_OUT3_MASK 0x0002 /* OUT3 */ | ||
291 | #define WM8955_OUT3_SHIFT 1 /* OUT3 */ | ||
292 | #define WM8955_OUT3_WIDTH 1 /* OUT3 */ | ||
293 | |||
294 | /* | ||
295 | * R27 (0x1B) - Additional Control (3) | ||
296 | */ | ||
297 | #define WM8955_VROI 0x0040 /* VROI */ | ||
298 | #define WM8955_VROI_MASK 0x0040 /* VROI */ | ||
299 | #define WM8955_VROI_SHIFT 6 /* VROI */ | ||
300 | #define WM8955_VROI_WIDTH 1 /* VROI */ | ||
301 | |||
302 | /* | ||
303 | * R34 (0x22) - Left out Mix (1) | ||
304 | */ | ||
305 | #define WM8955_LD2LO 0x0100 /* LD2LO */ | ||
306 | #define WM8955_LD2LO_MASK 0x0100 /* LD2LO */ | ||
307 | #define WM8955_LD2LO_SHIFT 8 /* LD2LO */ | ||
308 | #define WM8955_LD2LO_WIDTH 1 /* LD2LO */ | ||
309 | #define WM8955_LI2LO 0x0080 /* LI2LO */ | ||
310 | #define WM8955_LI2LO_MASK 0x0080 /* LI2LO */ | ||
311 | #define WM8955_LI2LO_SHIFT 7 /* LI2LO */ | ||
312 | #define WM8955_LI2LO_WIDTH 1 /* LI2LO */ | ||
313 | #define WM8955_LI2LOVOL_MASK 0x0070 /* LI2LOVOL - [6:4] */ | ||
314 | #define WM8955_LI2LOVOL_SHIFT 4 /* LI2LOVOL - [6:4] */ | ||
315 | #define WM8955_LI2LOVOL_WIDTH 3 /* LI2LOVOL - [6:4] */ | ||
316 | |||
317 | /* | ||
318 | * R35 (0x23) - Left out Mix (2) | ||
319 | */ | ||
320 | #define WM8955_RD2LO 0x0100 /* RD2LO */ | ||
321 | #define WM8955_RD2LO_MASK 0x0100 /* RD2LO */ | ||
322 | #define WM8955_RD2LO_SHIFT 8 /* RD2LO */ | ||
323 | #define WM8955_RD2LO_WIDTH 1 /* RD2LO */ | ||
324 | #define WM8955_RI2LO 0x0080 /* RI2LO */ | ||
325 | #define WM8955_RI2LO_MASK 0x0080 /* RI2LO */ | ||
326 | #define WM8955_RI2LO_SHIFT 7 /* RI2LO */ | ||
327 | #define WM8955_RI2LO_WIDTH 1 /* RI2LO */ | ||
328 | #define WM8955_RI2LOVOL_MASK 0x0070 /* RI2LOVOL - [6:4] */ | ||
329 | #define WM8955_RI2LOVOL_SHIFT 4 /* RI2LOVOL - [6:4] */ | ||
330 | #define WM8955_RI2LOVOL_WIDTH 3 /* RI2LOVOL - [6:4] */ | ||
331 | |||
332 | /* | ||
333 | * R36 (0x24) - Right out Mix (1) | ||
334 | */ | ||
335 | #define WM8955_LD2RO 0x0100 /* LD2RO */ | ||
336 | #define WM8955_LD2RO_MASK 0x0100 /* LD2RO */ | ||
337 | #define WM8955_LD2RO_SHIFT 8 /* LD2RO */ | ||
338 | #define WM8955_LD2RO_WIDTH 1 /* LD2RO */ | ||
339 | #define WM8955_LI2RO 0x0080 /* LI2RO */ | ||
340 | #define WM8955_LI2RO_MASK 0x0080 /* LI2RO */ | ||
341 | #define WM8955_LI2RO_SHIFT 7 /* LI2RO */ | ||
342 | #define WM8955_LI2RO_WIDTH 1 /* LI2RO */ | ||
343 | #define WM8955_LI2ROVOL_MASK 0x0070 /* LI2ROVOL - [6:4] */ | ||
344 | #define WM8955_LI2ROVOL_SHIFT 4 /* LI2ROVOL - [6:4] */ | ||
345 | #define WM8955_LI2ROVOL_WIDTH 3 /* LI2ROVOL - [6:4] */ | ||
346 | |||
347 | /* | ||
348 | * R37 (0x25) - Right Out Mix (2) | ||
349 | */ | ||
350 | #define WM8955_RD2RO 0x0100 /* RD2RO */ | ||
351 | #define WM8955_RD2RO_MASK 0x0100 /* RD2RO */ | ||
352 | #define WM8955_RD2RO_SHIFT 8 /* RD2RO */ | ||
353 | #define WM8955_RD2RO_WIDTH 1 /* RD2RO */ | ||
354 | #define WM8955_RI2RO 0x0080 /* RI2RO */ | ||
355 | #define WM8955_RI2RO_MASK 0x0080 /* RI2RO */ | ||
356 | #define WM8955_RI2RO_SHIFT 7 /* RI2RO */ | ||
357 | #define WM8955_RI2RO_WIDTH 1 /* RI2RO */ | ||
358 | #define WM8955_RI2ROVOL_MASK 0x0070 /* RI2ROVOL - [6:4] */ | ||
359 | #define WM8955_RI2ROVOL_SHIFT 4 /* RI2ROVOL - [6:4] */ | ||
360 | #define WM8955_RI2ROVOL_WIDTH 3 /* RI2ROVOL - [6:4] */ | ||
361 | |||
362 | /* | ||
363 | * R38 (0x26) - Mono out Mix (1) | ||
364 | */ | ||
365 | #define WM8955_LD2MO 0x0100 /* LD2MO */ | ||
366 | #define WM8955_LD2MO_MASK 0x0100 /* LD2MO */ | ||
367 | #define WM8955_LD2MO_SHIFT 8 /* LD2MO */ | ||
368 | #define WM8955_LD2MO_WIDTH 1 /* LD2MO */ | ||
369 | #define WM8955_LI2MO 0x0080 /* LI2MO */ | ||
370 | #define WM8955_LI2MO_MASK 0x0080 /* LI2MO */ | ||
371 | #define WM8955_LI2MO_SHIFT 7 /* LI2MO */ | ||
372 | #define WM8955_LI2MO_WIDTH 1 /* LI2MO */ | ||
373 | #define WM8955_LI2MOVOL_MASK 0x0070 /* LI2MOVOL - [6:4] */ | ||
374 | #define WM8955_LI2MOVOL_SHIFT 4 /* LI2MOVOL - [6:4] */ | ||
375 | #define WM8955_LI2MOVOL_WIDTH 3 /* LI2MOVOL - [6:4] */ | ||
376 | #define WM8955_DMEN 0x0001 /* DMEN */ | ||
377 | #define WM8955_DMEN_MASK 0x0001 /* DMEN */ | ||
378 | #define WM8955_DMEN_SHIFT 0 /* DMEN */ | ||
379 | #define WM8955_DMEN_WIDTH 1 /* DMEN */ | ||
380 | |||
381 | /* | ||
382 | * R39 (0x27) - Mono out Mix (2) | ||
383 | */ | ||
384 | #define WM8955_RD2MO 0x0100 /* RD2MO */ | ||
385 | #define WM8955_RD2MO_MASK 0x0100 /* RD2MO */ | ||
386 | #define WM8955_RD2MO_SHIFT 8 /* RD2MO */ | ||
387 | #define WM8955_RD2MO_WIDTH 1 /* RD2MO */ | ||
388 | #define WM8955_RI2MO 0x0080 /* RI2MO */ | ||
389 | #define WM8955_RI2MO_MASK 0x0080 /* RI2MO */ | ||
390 | #define WM8955_RI2MO_SHIFT 7 /* RI2MO */ | ||
391 | #define WM8955_RI2MO_WIDTH 1 /* RI2MO */ | ||
392 | #define WM8955_RI2MOVOL_MASK 0x0070 /* RI2MOVOL - [6:4] */ | ||
393 | #define WM8955_RI2MOVOL_SHIFT 4 /* RI2MOVOL - [6:4] */ | ||
394 | #define WM8955_RI2MOVOL_WIDTH 3 /* RI2MOVOL - [6:4] */ | ||
395 | |||
396 | /* | ||
397 | * R40 (0x28) - LOUT2 volume | ||
398 | */ | ||
399 | #define WM8955_LO2VU 0x0100 /* LO2VU */ | ||
400 | #define WM8955_LO2VU_MASK 0x0100 /* LO2VU */ | ||
401 | #define WM8955_LO2VU_SHIFT 8 /* LO2VU */ | ||
402 | #define WM8955_LO2VU_WIDTH 1 /* LO2VU */ | ||
403 | #define WM8955_LO2ZC 0x0080 /* LO2ZC */ | ||
404 | #define WM8955_LO2ZC_MASK 0x0080 /* LO2ZC */ | ||
405 | #define WM8955_LO2ZC_SHIFT 7 /* LO2ZC */ | ||
406 | #define WM8955_LO2ZC_WIDTH 1 /* LO2ZC */ | ||
407 | #define WM8955_LOUT2VOL_MASK 0x007F /* LOUT2VOL - [6:0] */ | ||
408 | #define WM8955_LOUT2VOL_SHIFT 0 /* LOUT2VOL - [6:0] */ | ||
409 | #define WM8955_LOUT2VOL_WIDTH 7 /* LOUT2VOL - [6:0] */ | ||
410 | |||
411 | /* | ||
412 | * R41 (0x29) - ROUT2 volume | ||
413 | */ | ||
414 | #define WM8955_RO2VU 0x0100 /* RO2VU */ | ||
415 | #define WM8955_RO2VU_MASK 0x0100 /* RO2VU */ | ||
416 | #define WM8955_RO2VU_SHIFT 8 /* RO2VU */ | ||
417 | #define WM8955_RO2VU_WIDTH 1 /* RO2VU */ | ||
418 | #define WM8955_RO2ZC 0x0080 /* RO2ZC */ | ||
419 | #define WM8955_RO2ZC_MASK 0x0080 /* RO2ZC */ | ||
420 | #define WM8955_RO2ZC_SHIFT 7 /* RO2ZC */ | ||
421 | #define WM8955_RO2ZC_WIDTH 1 /* RO2ZC */ | ||
422 | #define WM8955_ROUT2VOL_MASK 0x007F /* ROUT2VOL - [6:0] */ | ||
423 | #define WM8955_ROUT2VOL_SHIFT 0 /* ROUT2VOL - [6:0] */ | ||
424 | #define WM8955_ROUT2VOL_WIDTH 7 /* ROUT2VOL - [6:0] */ | ||
425 | |||
426 | /* | ||
427 | * R42 (0x2A) - MONOOUT volume | ||
428 | */ | ||
429 | #define WM8955_MOZC 0x0080 /* MOZC */ | ||
430 | #define WM8955_MOZC_MASK 0x0080 /* MOZC */ | ||
431 | #define WM8955_MOZC_SHIFT 7 /* MOZC */ | ||
432 | #define WM8955_MOZC_WIDTH 1 /* MOZC */ | ||
433 | #define WM8955_MOUTVOL_MASK 0x007F /* MOUTVOL - [6:0] */ | ||
434 | #define WM8955_MOUTVOL_SHIFT 0 /* MOUTVOL - [6:0] */ | ||
435 | #define WM8955_MOUTVOL_WIDTH 7 /* MOUTVOL - [6:0] */ | ||
436 | |||
437 | /* | ||
438 | * R43 (0x2B) - Clocking / PLL | ||
439 | */ | ||
440 | #define WM8955_MCLKSEL 0x0100 /* MCLKSEL */ | ||
441 | #define WM8955_MCLKSEL_MASK 0x0100 /* MCLKSEL */ | ||
442 | #define WM8955_MCLKSEL_SHIFT 8 /* MCLKSEL */ | ||
443 | #define WM8955_MCLKSEL_WIDTH 1 /* MCLKSEL */ | ||
444 | #define WM8955_PLLOUTDIV2 0x0020 /* PLLOUTDIV2 */ | ||
445 | #define WM8955_PLLOUTDIV2_MASK 0x0020 /* PLLOUTDIV2 */ | ||
446 | #define WM8955_PLLOUTDIV2_SHIFT 5 /* PLLOUTDIV2 */ | ||
447 | #define WM8955_PLLOUTDIV2_WIDTH 1 /* PLLOUTDIV2 */ | ||
448 | #define WM8955_PLL_RB 0x0010 /* PLL_RB */ | ||
449 | #define WM8955_PLL_RB_MASK 0x0010 /* PLL_RB */ | ||
450 | #define WM8955_PLL_RB_SHIFT 4 /* PLL_RB */ | ||
451 | #define WM8955_PLL_RB_WIDTH 1 /* PLL_RB */ | ||
452 | #define WM8955_PLLEN 0x0008 /* PLLEN */ | ||
453 | #define WM8955_PLLEN_MASK 0x0008 /* PLLEN */ | ||
454 | #define WM8955_PLLEN_SHIFT 3 /* PLLEN */ | ||
455 | #define WM8955_PLLEN_WIDTH 1 /* PLLEN */ | ||
456 | |||
457 | /* | ||
458 | * R44 (0x2C) - PLL Control 1 | ||
459 | */ | ||
460 | #define WM8955_N_MASK 0x01E0 /* N - [8:5] */ | ||
461 | #define WM8955_N_SHIFT 5 /* N - [8:5] */ | ||
462 | #define WM8955_N_WIDTH 4 /* N - [8:5] */ | ||
463 | #define WM8955_K_21_18_MASK 0x000F /* K(21:18) - [3:0] */ | ||
464 | #define WM8955_K_21_18_SHIFT 0 /* K(21:18) - [3:0] */ | ||
465 | #define WM8955_K_21_18_WIDTH 4 /* K(21:18) - [3:0] */ | ||
466 | |||
467 | /* | ||
468 | * R45 (0x2D) - PLL Control 2 | ||
469 | */ | ||
470 | #define WM8955_K_17_9_MASK 0x01FF /* K(17:9) - [8:0] */ | ||
471 | #define WM8955_K_17_9_SHIFT 0 /* K(17:9) - [8:0] */ | ||
472 | #define WM8955_K_17_9_WIDTH 9 /* K(17:9) - [8:0] */ | ||
473 | |||
474 | /* | ||
475 | * R46 (0x2E) - PLL Control 3 | ||
476 | */ | ||
477 | #define WM8955_K_8_0_MASK 0x01FF /* K(8:0) - [8:0] */ | ||
478 | #define WM8955_K_8_0_SHIFT 0 /* K(8:0) - [8:0] */ | ||
479 | #define WM8955_K_8_0_WIDTH 9 /* K(8:0) - [8:0] */ | ||
480 | |||
481 | /* | ||
482 | * R59 (0x3B) - PLL Control 4 | ||
483 | */ | ||
484 | #define WM8955_KEN 0x0080 /* KEN */ | ||
485 | #define WM8955_KEN_MASK 0x0080 /* KEN */ | ||
486 | #define WM8955_KEN_SHIFT 7 /* KEN */ | ||
487 | #define WM8955_KEN_WIDTH 1 /* KEN */ | ||
488 | |||
489 | #endif | ||
diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c index a8007d58813f..d2342c5e0425 100644 --- a/sound/soc/codecs/wm8961.c +++ b/sound/soc/codecs/wm8961.c | |||
@@ -1022,6 +1022,9 @@ static int wm8961_resume(struct platform_device *pdev) | |||
1022 | int i; | 1022 | int i; |
1023 | 1023 | ||
1024 | for (i = 0; i < codec->reg_cache_size; i++) { | 1024 | for (i = 0; i < codec->reg_cache_size; i++) { |
1025 | if (reg_cache[i] == wm8961_reg_defaults[i]) | ||
1026 | continue; | ||
1027 | |||
1025 | if (i == WM8961_SOFTWARE_RESET) | 1028 | if (i == WM8961_SOFTWARE_RESET) |
1026 | continue; | 1029 | continue; |
1027 | 1030 | ||
diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c index 8812751da8c9..ee637af4737a 100644 --- a/sound/soc/codecs/wm8974.c +++ b/sound/soc/codecs/wm8974.c | |||
@@ -170,6 +170,10 @@ SOC_ENUM("Aux Mode", wm8974_auxmode), | |||
170 | 170 | ||
171 | SOC_SINGLE("Capture Boost(+20dB)", WM8974_ADCBOOST, 8, 1, 0), | 171 | SOC_SINGLE("Capture Boost(+20dB)", WM8974_ADCBOOST, 8, 1, 0), |
172 | SOC_SINGLE("Mono Playback Switch", WM8974_MONOMIX, 6, 1, 1), | 172 | SOC_SINGLE("Mono Playback Switch", WM8974_MONOMIX, 6, 1, 1), |
173 | |||
174 | /* DAC / ADC oversampling */ | ||
175 | SOC_SINGLE("DAC 128x Oversampling Switch", WM8974_DAC, 8, 1, 0), | ||
176 | SOC_SINGLE("ADC 128x Oversampling Switch", WM8974_ADC, 8, 1, 0), | ||
173 | }; | 177 | }; |
174 | 178 | ||
175 | /* Speaker Output Mixer */ | 179 | /* Speaker Output Mixer */ |
@@ -381,14 +385,6 @@ static int wm8974_set_dai_clkdiv(struct snd_soc_dai *codec_dai, | |||
381 | reg = snd_soc_read(codec, WM8974_CLOCK) & 0x11f; | 385 | reg = snd_soc_read(codec, WM8974_CLOCK) & 0x11f; |
382 | snd_soc_write(codec, WM8974_CLOCK, reg | div); | 386 | snd_soc_write(codec, WM8974_CLOCK, reg | div); |
383 | break; | 387 | break; |
384 | case WM8974_ADCCLK: | ||
385 | reg = snd_soc_read(codec, WM8974_ADC) & 0x1f7; | ||
386 | snd_soc_write(codec, WM8974_ADC, reg | div); | ||
387 | break; | ||
388 | case WM8974_DACCLK: | ||
389 | reg = snd_soc_read(codec, WM8974_DAC) & 0x1f7; | ||
390 | snd_soc_write(codec, WM8974_DAC, reg | div); | ||
391 | break; | ||
392 | case WM8974_BCLKDIV: | 388 | case WM8974_BCLKDIV: |
393 | reg = snd_soc_read(codec, WM8974_CLOCK) & 0x1e3; | 389 | reg = snd_soc_read(codec, WM8974_CLOCK) & 0x1e3; |
394 | snd_soc_write(codec, WM8974_CLOCK, reg | div); | 390 | snd_soc_write(codec, WM8974_CLOCK, reg | div); |
diff --git a/sound/soc/codecs/wm8974.h b/sound/soc/codecs/wm8974.h index 98de9562d4d2..896a7f0f3fc4 100644 --- a/sound/soc/codecs/wm8974.h +++ b/sound/soc/codecs/wm8974.h | |||
@@ -57,17 +57,7 @@ | |||
57 | /* Clock divider Id's */ | 57 | /* Clock divider Id's */ |
58 | #define WM8974_OPCLKDIV 0 | 58 | #define WM8974_OPCLKDIV 0 |
59 | #define WM8974_MCLKDIV 1 | 59 | #define WM8974_MCLKDIV 1 |
60 | #define WM8974_ADCCLK 2 | 60 | #define WM8974_BCLKDIV 2 |
61 | #define WM8974_DACCLK 3 | ||
62 | #define WM8974_BCLKDIV 4 | ||
63 | |||
64 | /* DAC clock dividers */ | ||
65 | #define WM8974_DACCLK_F2 (1 << 3) | ||
66 | #define WM8974_DACCLK_F4 (0 << 3) | ||
67 | |||
68 | /* ADC clock dividers */ | ||
69 | #define WM8974_ADCCLK_F2 (1 << 3) | ||
70 | #define WM8974_ADCCLK_F4 (0 << 3) | ||
71 | 61 | ||
72 | /* PLL Out dividers */ | 62 | /* PLL Out dividers */ |
73 | #define WM8974_OPCLKDIV_1 (0 << 4) | 63 | #define WM8974_OPCLKDIV_1 (0 << 4) |
diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c new file mode 100644 index 000000000000..28bb59ea6ea1 --- /dev/null +++ b/sound/soc/codecs/wm8978.c | |||
@@ -0,0 +1,1149 @@ | |||
1 | /* | ||
2 | * wm8978.c -- WM8978 ALSA SoC Audio Codec driver | ||
3 | * | ||
4 | * Copyright (C) 2009-2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de> | ||
5 | * Copyright (C) 2007 Carlos Munoz <carlos@kenati.com> | ||
6 | * Copyright 2006-2009 Wolfson Microelectronics PLC. | ||
7 | * Based on wm8974 and wm8990 by Liam Girdwood <lrg@slimlogic.co.uk> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/moduleparam.h> | ||
16 | #include <linux/kernel.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/core.h> | ||
23 | #include <sound/pcm.h> | ||
24 | #include <sound/pcm_params.h> | ||
25 | #include <sound/soc.h> | ||
26 | #include <sound/soc-dapm.h> | ||
27 | #include <sound/initval.h> | ||
28 | #include <sound/tlv.h> | ||
29 | #include <asm/div64.h> | ||
30 | |||
31 | #include "wm8978.h" | ||
32 | |||
33 | static struct snd_soc_codec *wm8978_codec; | ||
34 | |||
35 | /* wm8978 register cache. Note that register 0 is not included in the cache. */ | ||
36 | static const u16 wm8978_reg[WM8978_CACHEREGNUM] = { | ||
37 | 0x0000, 0x0000, 0x0000, 0x0000, /* 0x00...0x03 */ | ||
38 | 0x0050, 0x0000, 0x0140, 0x0000, /* 0x04...0x07 */ | ||
39 | 0x0000, 0x0000, 0x0000, 0x00ff, /* 0x08...0x0b */ | ||
40 | 0x00ff, 0x0000, 0x0100, 0x00ff, /* 0x0c...0x0f */ | ||
41 | 0x00ff, 0x0000, 0x012c, 0x002c, /* 0x10...0x13 */ | ||
42 | 0x002c, 0x002c, 0x002c, 0x0000, /* 0x14...0x17 */ | ||
43 | 0x0032, 0x0000, 0x0000, 0x0000, /* 0x18...0x1b */ | ||
44 | 0x0000, 0x0000, 0x0000, 0x0000, /* 0x1c...0x1f */ | ||
45 | 0x0038, 0x000b, 0x0032, 0x0000, /* 0x20...0x23 */ | ||
46 | 0x0008, 0x000c, 0x0093, 0x00e9, /* 0x24...0x27 */ | ||
47 | 0x0000, 0x0000, 0x0000, 0x0000, /* 0x28...0x2b */ | ||
48 | 0x0033, 0x0010, 0x0010, 0x0100, /* 0x2c...0x2f */ | ||
49 | 0x0100, 0x0002, 0x0001, 0x0001, /* 0x30...0x33 */ | ||
50 | 0x0039, 0x0039, 0x0039, 0x0039, /* 0x34...0x37 */ | ||
51 | 0x0001, 0x0001, /* 0x38...0x3b */ | ||
52 | }; | ||
53 | |||
54 | /* codec private data */ | ||
55 | struct wm8978_priv { | ||
56 | struct snd_soc_codec codec; | ||
57 | unsigned int f_pllout; | ||
58 | unsigned int f_mclk; | ||
59 | unsigned int f_256fs; | ||
60 | unsigned int f_opclk; | ||
61 | int mclk_idx; | ||
62 | enum wm8978_sysclk_src sysclk; | ||
63 | u16 reg_cache[WM8978_CACHEREGNUM]; | ||
64 | }; | ||
65 | |||
66 | static const char *wm8978_companding[] = {"Off", "NC", "u-law", "A-law"}; | ||
67 | static const char *wm8978_eqmode[] = {"Capture", "Playback"}; | ||
68 | static const char *wm8978_bw[] = {"Narrow", "Wide"}; | ||
69 | static const char *wm8978_eq1[] = {"80Hz", "105Hz", "135Hz", "175Hz"}; | ||
70 | static const char *wm8978_eq2[] = {"230Hz", "300Hz", "385Hz", "500Hz"}; | ||
71 | static const char *wm8978_eq3[] = {"650Hz", "850Hz", "1.1kHz", "1.4kHz"}; | ||
72 | static const char *wm8978_eq4[] = {"1.8kHz", "2.4kHz", "3.2kHz", "4.1kHz"}; | ||
73 | static const char *wm8978_eq5[] = {"5.3kHz", "6.9kHz", "9kHz", "11.7kHz"}; | ||
74 | static const char *wm8978_alc3[] = {"ALC", "Limiter"}; | ||
75 | static const char *wm8978_alc1[] = {"Off", "Right", "Left", "Both"}; | ||
76 | |||
77 | static const SOC_ENUM_SINGLE_DECL(adc_compand, WM8978_COMPANDING_CONTROL, 1, | ||
78 | wm8978_companding); | ||
79 | static const SOC_ENUM_SINGLE_DECL(dac_compand, WM8978_COMPANDING_CONTROL, 3, | ||
80 | wm8978_companding); | ||
81 | static const SOC_ENUM_SINGLE_DECL(eqmode, WM8978_EQ1, 8, wm8978_eqmode); | ||
82 | static const SOC_ENUM_SINGLE_DECL(eq1, WM8978_EQ1, 5, wm8978_eq1); | ||
83 | static const SOC_ENUM_SINGLE_DECL(eq2bw, WM8978_EQ2, 8, wm8978_bw); | ||
84 | static const SOC_ENUM_SINGLE_DECL(eq2, WM8978_EQ2, 5, wm8978_eq2); | ||
85 | static const SOC_ENUM_SINGLE_DECL(eq3bw, WM8978_EQ3, 8, wm8978_bw); | ||
86 | static const SOC_ENUM_SINGLE_DECL(eq3, WM8978_EQ3, 5, wm8978_eq3); | ||
87 | static const SOC_ENUM_SINGLE_DECL(eq4bw, WM8978_EQ4, 8, wm8978_bw); | ||
88 | static const SOC_ENUM_SINGLE_DECL(eq4, WM8978_EQ4, 5, wm8978_eq4); | ||
89 | static const SOC_ENUM_SINGLE_DECL(eq5, WM8978_EQ5, 5, wm8978_eq5); | ||
90 | static const SOC_ENUM_SINGLE_DECL(alc3, WM8978_ALC_CONTROL_3, 8, wm8978_alc3); | ||
91 | static const SOC_ENUM_SINGLE_DECL(alc1, WM8978_ALC_CONTROL_1, 7, wm8978_alc1); | ||
92 | |||
93 | static const DECLARE_TLV_DB_SCALE(digital_tlv, -12750, 50, 1); | ||
94 | static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); | ||
95 | static const DECLARE_TLV_DB_SCALE(inpga_tlv, -1200, 75, 0); | ||
96 | static const DECLARE_TLV_DB_SCALE(spk_tlv, -5700, 100, 0); | ||
97 | static const DECLARE_TLV_DB_SCALE(boost_tlv, -1500, 300, 1); | ||
98 | |||
99 | static const struct snd_kcontrol_new wm8978_snd_controls[] = { | ||
100 | |||
101 | SOC_SINGLE("Digital Loopback Switch", | ||
102 | WM8978_COMPANDING_CONTROL, 0, 1, 0), | ||
103 | |||
104 | SOC_ENUM("ADC Companding", adc_compand), | ||
105 | SOC_ENUM("DAC Companding", dac_compand), | ||
106 | |||
107 | SOC_DOUBLE("DAC Inversion Switch", WM8978_DAC_CONTROL, 0, 1, 1, 0), | ||
108 | |||
109 | SOC_DOUBLE_R_TLV("PCM Volume", | ||
110 | WM8978_LEFT_DAC_DIGITAL_VOLUME, WM8978_RIGHT_DAC_DIGITAL_VOLUME, | ||
111 | 0, 255, 0, digital_tlv), | ||
112 | |||
113 | SOC_SINGLE("High Pass Filter Switch", WM8978_ADC_CONTROL, 8, 1, 0), | ||
114 | SOC_SINGLE("High Pass Cut Off", WM8978_ADC_CONTROL, 4, 7, 0), | ||
115 | SOC_DOUBLE("ADC Inversion Switch", WM8978_ADC_CONTROL, 0, 1, 1, 0), | ||
116 | |||
117 | SOC_DOUBLE_R_TLV("ADC Volume", | ||
118 | WM8978_LEFT_ADC_DIGITAL_VOLUME, WM8978_RIGHT_ADC_DIGITAL_VOLUME, | ||
119 | 0, 255, 0, digital_tlv), | ||
120 | |||
121 | SOC_ENUM("Equaliser Function", eqmode), | ||
122 | SOC_ENUM("EQ1 Cut Off", eq1), | ||
123 | SOC_SINGLE_TLV("EQ1 Volume", WM8978_EQ1, 0, 24, 1, eq_tlv), | ||
124 | |||
125 | SOC_ENUM("Equaliser EQ2 Bandwith", eq2bw), | ||
126 | SOC_ENUM("EQ2 Cut Off", eq2), | ||
127 | SOC_SINGLE_TLV("EQ2 Volume", WM8978_EQ2, 0, 24, 1, eq_tlv), | ||
128 | |||
129 | SOC_ENUM("Equaliser EQ3 Bandwith", eq3bw), | ||
130 | SOC_ENUM("EQ3 Cut Off", eq3), | ||
131 | SOC_SINGLE_TLV("EQ3 Volume", WM8978_EQ3, 0, 24, 1, eq_tlv), | ||
132 | |||
133 | SOC_ENUM("Equaliser EQ4 Bandwith", eq4bw), | ||
134 | SOC_ENUM("EQ4 Cut Off", eq4), | ||
135 | SOC_SINGLE_TLV("EQ4 Volume", WM8978_EQ4, 0, 24, 1, eq_tlv), | ||
136 | |||
137 | SOC_ENUM("EQ5 Cut Off", eq5), | ||
138 | SOC_SINGLE_TLV("EQ5 Volume", WM8978_EQ5, 0, 24, 1, eq_tlv), | ||
139 | |||
140 | SOC_SINGLE("DAC Playback Limiter Switch", | ||
141 | WM8978_DAC_LIMITER_1, 8, 1, 0), | ||
142 | SOC_SINGLE("DAC Playback Limiter Decay", | ||
143 | WM8978_DAC_LIMITER_1, 4, 15, 0), | ||
144 | SOC_SINGLE("DAC Playback Limiter Attack", | ||
145 | WM8978_DAC_LIMITER_1, 0, 15, 0), | ||
146 | |||
147 | SOC_SINGLE("DAC Playback Limiter Threshold", | ||
148 | WM8978_DAC_LIMITER_2, 4, 7, 0), | ||
149 | SOC_SINGLE("DAC Playback Limiter Boost", | ||
150 | WM8978_DAC_LIMITER_2, 0, 15, 0), | ||
151 | |||
152 | SOC_ENUM("ALC Enable Switch", alc1), | ||
153 | SOC_SINGLE("ALC Capture Min Gain", WM8978_ALC_CONTROL_1, 0, 7, 0), | ||
154 | SOC_SINGLE("ALC Capture Max Gain", WM8978_ALC_CONTROL_1, 3, 7, 0), | ||
155 | |||
156 | SOC_SINGLE("ALC Capture Hold", WM8978_ALC_CONTROL_2, 4, 7, 0), | ||
157 | SOC_SINGLE("ALC Capture Target", WM8978_ALC_CONTROL_2, 0, 15, 0), | ||
158 | |||
159 | SOC_ENUM("ALC Capture Mode", alc3), | ||
160 | SOC_SINGLE("ALC Capture Decay", WM8978_ALC_CONTROL_3, 4, 15, 0), | ||
161 | SOC_SINGLE("ALC Capture Attack", WM8978_ALC_CONTROL_3, 0, 15, 0), | ||
162 | |||
163 | SOC_SINGLE("ALC Capture Noise Gate Switch", WM8978_NOISE_GATE, 3, 1, 0), | ||
164 | SOC_SINGLE("ALC Capture Noise Gate Threshold", | ||
165 | WM8978_NOISE_GATE, 0, 7, 0), | ||
166 | |||
167 | SOC_DOUBLE_R("Capture PGA ZC Switch", | ||
168 | WM8978_LEFT_INP_PGA_CONTROL, WM8978_RIGHT_INP_PGA_CONTROL, | ||
169 | 7, 1, 0), | ||
170 | |||
171 | /* OUT1 - Headphones */ | ||
172 | SOC_DOUBLE_R("Headphone Playback ZC Switch", | ||
173 | WM8978_LOUT1_HP_CONTROL, WM8978_ROUT1_HP_CONTROL, 7, 1, 0), | ||
174 | |||
175 | SOC_DOUBLE_R_TLV("Headphone Playback Volume", | ||
176 | WM8978_LOUT1_HP_CONTROL, WM8978_ROUT1_HP_CONTROL, | ||
177 | 0, 63, 0, spk_tlv), | ||
178 | |||
179 | /* OUT2 - Speakers */ | ||
180 | SOC_DOUBLE_R("Speaker Playback ZC Switch", | ||
181 | WM8978_LOUT2_SPK_CONTROL, WM8978_ROUT2_SPK_CONTROL, 7, 1, 0), | ||
182 | |||
183 | SOC_DOUBLE_R_TLV("Speaker Playback Volume", | ||
184 | WM8978_LOUT2_SPK_CONTROL, WM8978_ROUT2_SPK_CONTROL, | ||
185 | 0, 63, 0, spk_tlv), | ||
186 | |||
187 | /* OUT3/4 - Line Output */ | ||
188 | SOC_DOUBLE_R("Line Playback Switch", | ||
189 | WM8978_OUT3_MIXER_CONTROL, WM8978_OUT4_MIXER_CONTROL, 6, 1, 1), | ||
190 | |||
191 | /* Mixer #3: Boost (Input) mixer */ | ||
192 | SOC_DOUBLE_R("PGA Boost (+20dB)", | ||
193 | WM8978_LEFT_ADC_BOOST_CONTROL, WM8978_RIGHT_ADC_BOOST_CONTROL, | ||
194 | 8, 1, 0), | ||
195 | SOC_DOUBLE_R_TLV("L2/R2 Boost Volume", | ||
196 | WM8978_LEFT_ADC_BOOST_CONTROL, WM8978_RIGHT_ADC_BOOST_CONTROL, | ||
197 | 4, 7, 0, boost_tlv), | ||
198 | SOC_DOUBLE_R_TLV("Aux Boost Volume", | ||
199 | WM8978_LEFT_ADC_BOOST_CONTROL, WM8978_RIGHT_ADC_BOOST_CONTROL, | ||
200 | 0, 7, 0, boost_tlv), | ||
201 | |||
202 | /* Input PGA volume */ | ||
203 | SOC_DOUBLE_R_TLV("Input PGA Volume", | ||
204 | WM8978_LEFT_INP_PGA_CONTROL, WM8978_RIGHT_INP_PGA_CONTROL, | ||
205 | 0, 63, 0, inpga_tlv), | ||
206 | |||
207 | /* Headphone */ | ||
208 | SOC_DOUBLE_R("Headphone Switch", | ||
209 | WM8978_LOUT1_HP_CONTROL, WM8978_ROUT1_HP_CONTROL, 6, 1, 1), | ||
210 | |||
211 | /* Speaker */ | ||
212 | SOC_DOUBLE_R("Speaker Switch", | ||
213 | WM8978_LOUT2_SPK_CONTROL, WM8978_ROUT2_SPK_CONTROL, 6, 1, 1), | ||
214 | |||
215 | /* DAC / ADC oversampling */ | ||
216 | SOC_SINGLE("DAC 128x Oversampling Switch", WM8978_DAC_CONTROL, 8, 1, 0), | ||
217 | SOC_SINGLE("ADC 128x Oversampling Switch", WM8978_ADC_CONTROL, 8, 1, 0), | ||
218 | }; | ||
219 | |||
220 | /* Mixer #1: Output (OUT1, OUT2) Mixer: mix AUX, Input mixer output and DAC */ | ||
221 | static const struct snd_kcontrol_new wm8978_left_out_mixer[] = { | ||
222 | SOC_DAPM_SINGLE("Line Bypass Switch", WM8978_LEFT_MIXER_CONTROL, 1, 1, 0), | ||
223 | SOC_DAPM_SINGLE("Aux Playback Switch", WM8978_LEFT_MIXER_CONTROL, 5, 1, 0), | ||
224 | SOC_DAPM_SINGLE("PCM Playback Switch", WM8978_LEFT_MIXER_CONTROL, 0, 1, 0), | ||
225 | }; | ||
226 | |||
227 | static const struct snd_kcontrol_new wm8978_right_out_mixer[] = { | ||
228 | SOC_DAPM_SINGLE("Line Bypass Switch", WM8978_RIGHT_MIXER_CONTROL, 1, 1, 0), | ||
229 | SOC_DAPM_SINGLE("Aux Playback Switch", WM8978_RIGHT_MIXER_CONTROL, 5, 1, 0), | ||
230 | SOC_DAPM_SINGLE("PCM Playback Switch", WM8978_RIGHT_MIXER_CONTROL, 0, 1, 0), | ||
231 | }; | ||
232 | |||
233 | /* OUT3/OUT4 Mixer not implemented */ | ||
234 | |||
235 | /* Mixer #2: Input PGA Mute */ | ||
236 | static const struct snd_kcontrol_new wm8978_left_input_mixer[] = { | ||
237 | SOC_DAPM_SINGLE("L2 Switch", WM8978_INPUT_CONTROL, 2, 1, 0), | ||
238 | SOC_DAPM_SINGLE("MicN Switch", WM8978_INPUT_CONTROL, 1, 1, 0), | ||
239 | SOC_DAPM_SINGLE("MicP Switch", WM8978_INPUT_CONTROL, 0, 1, 0), | ||
240 | }; | ||
241 | static const struct snd_kcontrol_new wm8978_right_input_mixer[] = { | ||
242 | SOC_DAPM_SINGLE("R2 Switch", WM8978_INPUT_CONTROL, 6, 1, 0), | ||
243 | SOC_DAPM_SINGLE("MicN Switch", WM8978_INPUT_CONTROL, 5, 1, 0), | ||
244 | SOC_DAPM_SINGLE("MicP Switch", WM8978_INPUT_CONTROL, 4, 1, 0), | ||
245 | }; | ||
246 | |||
247 | static const struct snd_soc_dapm_widget wm8978_dapm_widgets[] = { | ||
248 | SND_SOC_DAPM_DAC("Left DAC", "Left HiFi Playback", | ||
249 | WM8978_POWER_MANAGEMENT_3, 0, 0), | ||
250 | SND_SOC_DAPM_DAC("Right DAC", "Right HiFi Playback", | ||
251 | WM8978_POWER_MANAGEMENT_3, 1, 0), | ||
252 | SND_SOC_DAPM_ADC("Left ADC", "Left HiFi Capture", | ||
253 | WM8978_POWER_MANAGEMENT_2, 0, 0), | ||
254 | SND_SOC_DAPM_ADC("Right ADC", "Right HiFi Capture", | ||
255 | WM8978_POWER_MANAGEMENT_2, 1, 0), | ||
256 | |||
257 | /* Mixer #1: OUT1,2 */ | ||
258 | SOC_MIXER_ARRAY("Left Output Mixer", WM8978_POWER_MANAGEMENT_3, | ||
259 | 2, 0, wm8978_left_out_mixer), | ||
260 | SOC_MIXER_ARRAY("Right Output Mixer", WM8978_POWER_MANAGEMENT_3, | ||
261 | 3, 0, wm8978_right_out_mixer), | ||
262 | |||
263 | SOC_MIXER_ARRAY("Left Input Mixer", WM8978_POWER_MANAGEMENT_2, | ||
264 | 2, 0, wm8978_left_input_mixer), | ||
265 | SOC_MIXER_ARRAY("Right Input Mixer", WM8978_POWER_MANAGEMENT_2, | ||
266 | 3, 0, wm8978_right_input_mixer), | ||
267 | |||
268 | SND_SOC_DAPM_PGA("Left Boost Mixer", WM8978_POWER_MANAGEMENT_2, | ||
269 | 4, 0, NULL, 0), | ||
270 | SND_SOC_DAPM_PGA("Right Boost Mixer", WM8978_POWER_MANAGEMENT_2, | ||
271 | 5, 0, NULL, 0), | ||
272 | |||
273 | SND_SOC_DAPM_PGA("Left Capture PGA", WM8978_LEFT_INP_PGA_CONTROL, | ||
274 | 6, 1, NULL, 0), | ||
275 | SND_SOC_DAPM_PGA("Right Capture PGA", WM8978_RIGHT_INP_PGA_CONTROL, | ||
276 | 6, 1, NULL, 0), | ||
277 | |||
278 | SND_SOC_DAPM_PGA("Left Headphone Out", WM8978_POWER_MANAGEMENT_2, | ||
279 | 7, 0, NULL, 0), | ||
280 | SND_SOC_DAPM_PGA("Right Headphone Out", WM8978_POWER_MANAGEMENT_2, | ||
281 | 8, 0, NULL, 0), | ||
282 | |||
283 | SND_SOC_DAPM_PGA("Left Speaker Out", WM8978_POWER_MANAGEMENT_3, | ||
284 | 6, 0, NULL, 0), | ||
285 | SND_SOC_DAPM_PGA("Right Speaker Out", WM8978_POWER_MANAGEMENT_3, | ||
286 | 5, 0, NULL, 0), | ||
287 | |||
288 | SND_SOC_DAPM_MIXER("OUT4 VMID", WM8978_POWER_MANAGEMENT_3, | ||
289 | 8, 0, NULL, 0), | ||
290 | |||
291 | SND_SOC_DAPM_MICBIAS("Mic Bias", WM8978_POWER_MANAGEMENT_1, 4, 0), | ||
292 | |||
293 | SND_SOC_DAPM_INPUT("LMICN"), | ||
294 | SND_SOC_DAPM_INPUT("LMICP"), | ||
295 | SND_SOC_DAPM_INPUT("RMICN"), | ||
296 | SND_SOC_DAPM_INPUT("RMICP"), | ||
297 | SND_SOC_DAPM_INPUT("LAUX"), | ||
298 | SND_SOC_DAPM_INPUT("RAUX"), | ||
299 | SND_SOC_DAPM_INPUT("L2"), | ||
300 | SND_SOC_DAPM_INPUT("R2"), | ||
301 | SND_SOC_DAPM_OUTPUT("LHP"), | ||
302 | SND_SOC_DAPM_OUTPUT("RHP"), | ||
303 | SND_SOC_DAPM_OUTPUT("LSPK"), | ||
304 | SND_SOC_DAPM_OUTPUT("RSPK"), | ||
305 | }; | ||
306 | |||
307 | static const struct snd_soc_dapm_route audio_map[] = { | ||
308 | /* Output mixer */ | ||
309 | {"Right Output Mixer", "PCM Playback Switch", "Right DAC"}, | ||
310 | {"Right Output Mixer", "Aux Playback Switch", "RAUX"}, | ||
311 | {"Right Output Mixer", "Line Bypass Switch", "Right Boost Mixer"}, | ||
312 | |||
313 | {"Left Output Mixer", "PCM Playback Switch", "Left DAC"}, | ||
314 | {"Left Output Mixer", "Aux Playback Switch", "LAUX"}, | ||
315 | {"Left Output Mixer", "Line Bypass Switch", "Left Boost Mixer"}, | ||
316 | |||
317 | /* Outputs */ | ||
318 | {"Right Headphone Out", NULL, "Right Output Mixer"}, | ||
319 | {"RHP", NULL, "Right Headphone Out"}, | ||
320 | |||
321 | {"Left Headphone Out", NULL, "Left Output Mixer"}, | ||
322 | {"LHP", NULL, "Left Headphone Out"}, | ||
323 | |||
324 | {"Right Speaker Out", NULL, "Right Output Mixer"}, | ||
325 | {"RSPK", NULL, "Right Speaker Out"}, | ||
326 | |||
327 | {"Left Speaker Out", NULL, "Left Output Mixer"}, | ||
328 | {"LSPK", NULL, "Left Speaker Out"}, | ||
329 | |||
330 | /* Boost Mixer */ | ||
331 | {"Right ADC", NULL, "Right Boost Mixer"}, | ||
332 | |||
333 | {"Right Boost Mixer", NULL, "RAUX"}, | ||
334 | {"Right Boost Mixer", NULL, "Right Capture PGA"}, | ||
335 | {"Right Boost Mixer", NULL, "R2"}, | ||
336 | |||
337 | {"Left ADC", NULL, "Left Boost Mixer"}, | ||
338 | |||
339 | {"Left Boost Mixer", NULL, "LAUX"}, | ||
340 | {"Left Boost Mixer", NULL, "Left Capture PGA"}, | ||
341 | {"Left Boost Mixer", NULL, "L2"}, | ||
342 | |||
343 | /* Input PGA */ | ||
344 | {"Right Capture PGA", NULL, "Right Input Mixer"}, | ||
345 | {"Left Capture PGA", NULL, "Left Input Mixer"}, | ||
346 | |||
347 | {"Right Input Mixer", "R2 Switch", "R2"}, | ||
348 | {"Right Input Mixer", "MicN Switch", "RMICN"}, | ||
349 | {"Right Input Mixer", "MicP Switch", "RMICP"}, | ||
350 | |||
351 | {"Left Input Mixer", "L2 Switch", "L2"}, | ||
352 | {"Left Input Mixer", "MicN Switch", "LMICN"}, | ||
353 | {"Left Input Mixer", "MicP Switch", "LMICP"}, | ||
354 | }; | ||
355 | |||
356 | static int wm8978_add_widgets(struct snd_soc_codec *codec) | ||
357 | { | ||
358 | snd_soc_dapm_new_controls(codec, wm8978_dapm_widgets, | ||
359 | ARRAY_SIZE(wm8978_dapm_widgets)); | ||
360 | |||
361 | /* set up the WM8978 audio map */ | ||
362 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | ||
363 | |||
364 | return 0; | ||
365 | } | ||
366 | |||
367 | /* PLL divisors */ | ||
368 | struct wm8978_pll_div { | ||
369 | u32 k; | ||
370 | u8 n; | ||
371 | u8 div2; | ||
372 | }; | ||
373 | |||
374 | #define FIXED_PLL_SIZE (1 << 24) | ||
375 | |||
376 | static void pll_factors(struct wm8978_pll_div *pll_div, unsigned int target, | ||
377 | unsigned int source) | ||
378 | { | ||
379 | u64 k_part; | ||
380 | unsigned int k, n_div, n_mod; | ||
381 | |||
382 | n_div = target / source; | ||
383 | if (n_div < 6) { | ||
384 | source >>= 1; | ||
385 | pll_div->div2 = 1; | ||
386 | n_div = target / source; | ||
387 | } else { | ||
388 | pll_div->div2 = 0; | ||
389 | } | ||
390 | |||
391 | if (n_div < 6 || n_div > 12) | ||
392 | dev_warn(wm8978_codec->dev, | ||
393 | "WM8978 N value exceeds recommended range! N = %u\n", | ||
394 | n_div); | ||
395 | |||
396 | pll_div->n = n_div; | ||
397 | n_mod = target - source * n_div; | ||
398 | k_part = FIXED_PLL_SIZE * (long long)n_mod + source / 2; | ||
399 | |||
400 | do_div(k_part, source); | ||
401 | |||
402 | k = k_part & 0xFFFFFFFF; | ||
403 | |||
404 | pll_div->k = k; | ||
405 | } | ||
406 | |||
407 | /* MCLK dividers */ | ||
408 | static const int mclk_numerator[] = {1, 3, 2, 3, 4, 6, 8, 12}; | ||
409 | static const int mclk_denominator[] = {1, 2, 1, 1, 1, 1, 1, 1}; | ||
410 | |||
411 | /* | ||
412 | * find index >= idx, such that, for a given f_out, | ||
413 | * 3 * f_mclk / 4 <= f_PLLOUT < 13 * f_mclk / 4 | ||
414 | * f_out can be f_256fs or f_opclk, currently only used for f_256fs. Can be | ||
415 | * generalised for f_opclk with suitable coefficient arrays, but currently | ||
416 | * the OPCLK divisor is calculated directly, not iteratively. | ||
417 | */ | ||
418 | static int wm8978_enum_mclk(unsigned int f_out, unsigned int f_mclk, | ||
419 | unsigned int *f_pllout) | ||
420 | { | ||
421 | int i; | ||
422 | |||
423 | for (i = 0; i < ARRAY_SIZE(mclk_numerator); i++) { | ||
424 | unsigned int f_pllout_x4 = 4 * f_out * mclk_numerator[i] / | ||
425 | mclk_denominator[i]; | ||
426 | if (3 * f_mclk <= f_pllout_x4 && f_pllout_x4 < 13 * f_mclk) { | ||
427 | *f_pllout = f_pllout_x4 / 4; | ||
428 | return i; | ||
429 | } | ||
430 | } | ||
431 | |||
432 | return -EINVAL; | ||
433 | } | ||
434 | |||
435 | /* | ||
436 | * Calculate internal frequencies and dividers, according to Figure 40 | ||
437 | * "PLL and Clock Select Circuit" in WM8978 datasheet Rev. 2.6 | ||
438 | */ | ||
439 | static int wm8978_configure_pll(struct snd_soc_codec *codec) | ||
440 | { | ||
441 | struct wm8978_priv *wm8978 = codec->private_data; | ||
442 | struct wm8978_pll_div pll_div; | ||
443 | unsigned int f_opclk = wm8978->f_opclk, f_mclk = wm8978->f_mclk, | ||
444 | f_256fs = wm8978->f_256fs; | ||
445 | unsigned int f2; | ||
446 | |||
447 | if (!f_mclk) | ||
448 | return -EINVAL; | ||
449 | |||
450 | if (f_opclk) { | ||
451 | unsigned int opclk_div; | ||
452 | /* Cannot set up MCLK divider now, do later */ | ||
453 | wm8978->mclk_idx = -1; | ||
454 | |||
455 | /* | ||
456 | * The user needs OPCLK. Choose OPCLKDIV to put | ||
457 | * 6 <= R = f2 / f1 < 13, 1 <= OPCLKDIV <= 4. | ||
458 | * f_opclk = f_mclk * prescale * R / 4 / OPCLKDIV, where | ||
459 | * prescale = 1, or prescale = 2. Prescale is calculated inside | ||
460 | * pll_factors(). We have to select f_PLLOUT, such that | ||
461 | * f_mclk * 3 / 4 <= f_PLLOUT < f_mclk * 13 / 4. Must be | ||
462 | * f_mclk * 3 / 16 <= f_opclk < f_mclk * 13 / 4. | ||
463 | */ | ||
464 | if (16 * f_opclk < 3 * f_mclk || 4 * f_opclk >= 13 * f_mclk) | ||
465 | return -EINVAL; | ||
466 | |||
467 | if (4 * f_opclk < 3 * f_mclk) | ||
468 | /* Have to use OPCLKDIV */ | ||
469 | opclk_div = (3 * f_mclk / 4 + f_opclk - 1) / f_opclk; | ||
470 | else | ||
471 | opclk_div = 1; | ||
472 | |||
473 | dev_dbg(codec->dev, "%s: OPCLKDIV=%d\n", __func__, opclk_div); | ||
474 | |||
475 | snd_soc_update_bits(codec, WM8978_GPIO_CONTROL, 0x30, | ||
476 | (opclk_div - 1) << 4); | ||
477 | |||
478 | wm8978->f_pllout = f_opclk * opclk_div; | ||
479 | } else if (f_256fs) { | ||
480 | /* | ||
481 | * Not using OPCLK, but PLL is used for the codec, choose R: | ||
482 | * 6 <= R = f2 / f1 < 13, to put 1 <= MCLKDIV <= 12. | ||
483 | * f_256fs = f_mclk * prescale * R / 4 / MCLKDIV, where | ||
484 | * prescale = 1, or prescale = 2. Prescale is calculated inside | ||
485 | * pll_factors(). We have to select f_PLLOUT, such that | ||
486 | * f_mclk * 3 / 4 <= f_PLLOUT < f_mclk * 13 / 4. Must be | ||
487 | * f_mclk * 3 / 48 <= f_256fs < f_mclk * 13 / 4. This means MCLK | ||
488 | * must be 3.781MHz <= f_MCLK <= 32.768MHz | ||
489 | */ | ||
490 | int idx = wm8978_enum_mclk(f_256fs, f_mclk, &wm8978->f_pllout); | ||
491 | if (idx < 0) | ||
492 | return idx; | ||
493 | |||
494 | wm8978->mclk_idx = idx; | ||
495 | |||
496 | /* GPIO1 into default mode as input - before configuring PLL */ | ||
497 | snd_soc_update_bits(codec, WM8978_GPIO_CONTROL, 7, 0); | ||
498 | } else { | ||
499 | return -EINVAL; | ||
500 | } | ||
501 | |||
502 | f2 = wm8978->f_pllout * 4; | ||
503 | |||
504 | dev_dbg(codec->dev, "%s: f_MCLK=%uHz, f_PLLOUT=%uHz\n", __func__, | ||
505 | wm8978->f_mclk, wm8978->f_pllout); | ||
506 | |||
507 | pll_factors(&pll_div, f2, wm8978->f_mclk); | ||
508 | |||
509 | dev_dbg(codec->dev, "%s: calculated PLL N=0x%x, K=0x%x, div2=%d\n", | ||
510 | __func__, pll_div.n, pll_div.k, pll_div.div2); | ||
511 | |||
512 | /* Turn PLL off for configuration... */ | ||
513 | snd_soc_update_bits(codec, WM8978_POWER_MANAGEMENT_1, 0x20, 0); | ||
514 | |||
515 | snd_soc_write(codec, WM8978_PLL_N, (pll_div.div2 << 4) | pll_div.n); | ||
516 | snd_soc_write(codec, WM8978_PLL_K1, pll_div.k >> 18); | ||
517 | snd_soc_write(codec, WM8978_PLL_K2, (pll_div.k >> 9) & 0x1ff); | ||
518 | snd_soc_write(codec, WM8978_PLL_K3, pll_div.k & 0x1ff); | ||
519 | |||
520 | /* ...and on again */ | ||
521 | snd_soc_update_bits(codec, WM8978_POWER_MANAGEMENT_1, 0x20, 0x20); | ||
522 | |||
523 | if (f_opclk) | ||
524 | /* Output PLL (OPCLK) to GPIO1 */ | ||
525 | snd_soc_update_bits(codec, WM8978_GPIO_CONTROL, 7, 4); | ||
526 | |||
527 | return 0; | ||
528 | } | ||
529 | |||
530 | /* | ||
531 | * Configure WM8978 clock dividers. | ||
532 | */ | ||
533 | static int wm8978_set_dai_clkdiv(struct snd_soc_dai *codec_dai, | ||
534 | int div_id, int div) | ||
535 | { | ||
536 | struct snd_soc_codec *codec = codec_dai->codec; | ||
537 | struct wm8978_priv *wm8978 = codec->private_data; | ||
538 | int ret = 0; | ||
539 | |||
540 | switch (div_id) { | ||
541 | case WM8978_OPCLKRATE: | ||
542 | wm8978->f_opclk = div; | ||
543 | |||
544 | if (wm8978->f_mclk) | ||
545 | /* | ||
546 | * We know the MCLK frequency, the user has requested | ||
547 | * OPCLK, configure the PLL based on that and start it | ||
548 | * and OPCLK immediately. We will configure PLL to match | ||
549 | * user-requested OPCLK frquency as good as possible. | ||
550 | * In fact, it is likely, that matching the sampling | ||
551 | * rate, when it becomes known, is more important, and | ||
552 | * we will not be reconfiguring PLL then, because we | ||
553 | * must not interrupt OPCLK. But it should be fine, | ||
554 | * because typically the user will request OPCLK to run | ||
555 | * at 256fs or 512fs, and for these cases we will also | ||
556 | * find an exact MCLK divider configuration - it will | ||
557 | * be equal to or double the OPCLK divisor. | ||
558 | */ | ||
559 | ret = wm8978_configure_pll(codec); | ||
560 | break; | ||
561 | case WM8978_BCLKDIV: | ||
562 | if (div & ~0x1c) | ||
563 | return -EINVAL; | ||
564 | snd_soc_update_bits(codec, WM8978_CLOCKING, 0x1c, div); | ||
565 | break; | ||
566 | default: | ||
567 | return -EINVAL; | ||
568 | } | ||
569 | |||
570 | dev_dbg(codec->dev, "%s: ID %d, value %u\n", __func__, div_id, div); | ||
571 | |||
572 | return ret; | ||
573 | } | ||
574 | |||
575 | /* | ||
576 | * @freq: when .set_pll() us not used, freq is codec MCLK input frequency | ||
577 | */ | ||
578 | static int wm8978_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id, | ||
579 | unsigned int freq, int dir) | ||
580 | { | ||
581 | struct snd_soc_codec *codec = codec_dai->codec; | ||
582 | struct wm8978_priv *wm8978 = codec->private_data; | ||
583 | int ret = 0; | ||
584 | |||
585 | dev_dbg(codec->dev, "%s: ID %d, freq %u\n", __func__, clk_id, freq); | ||
586 | |||
587 | if (freq) { | ||
588 | wm8978->f_mclk = freq; | ||
589 | |||
590 | /* Even if MCLK is used for system clock, might have to drive OPCLK */ | ||
591 | if (wm8978->f_opclk) | ||
592 | ret = wm8978_configure_pll(codec); | ||
593 | |||
594 | /* Our sysclk is fixed to 256 * fs, will configure in .hw_params() */ | ||
595 | |||
596 | if (!ret) | ||
597 | wm8978->sysclk = clk_id; | ||
598 | } | ||
599 | |||
600 | if (wm8978->sysclk == WM8978_PLL && (!freq || clk_id == WM8978_MCLK)) { | ||
601 | /* Clock CODEC directly from MCLK */ | ||
602 | snd_soc_update_bits(codec, WM8978_CLOCKING, 0x100, 0); | ||
603 | |||
604 | /* GPIO1 into default mode as input - before configuring PLL */ | ||
605 | snd_soc_update_bits(codec, WM8978_GPIO_CONTROL, 7, 0); | ||
606 | |||
607 | /* Turn off PLL */ | ||
608 | snd_soc_update_bits(codec, WM8978_POWER_MANAGEMENT_1, 0x20, 0); | ||
609 | wm8978->sysclk = WM8978_MCLK; | ||
610 | wm8978->f_pllout = 0; | ||
611 | wm8978->f_opclk = 0; | ||
612 | } | ||
613 | |||
614 | return ret; | ||
615 | } | ||
616 | |||
617 | /* | ||
618 | * Set ADC and Voice DAC format. | ||
619 | */ | ||
620 | static int wm8978_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) | ||
621 | { | ||
622 | struct snd_soc_codec *codec = codec_dai->codec; | ||
623 | /* | ||
624 | * BCLK polarity mask = 0x100, LRC clock polarity mask = 0x80, | ||
625 | * Data Format mask = 0x18: all will be calculated anew | ||
626 | */ | ||
627 | u16 iface = snd_soc_read(codec, WM8978_AUDIO_INTERFACE) & ~0x198; | ||
628 | u16 clk = snd_soc_read(codec, WM8978_CLOCKING); | ||
629 | |||
630 | dev_dbg(codec->dev, "%s\n", __func__); | ||
631 | |||
632 | /* set master/slave audio interface */ | ||
633 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
634 | case SND_SOC_DAIFMT_CBM_CFM: | ||
635 | clk |= 1; | ||
636 | break; | ||
637 | case SND_SOC_DAIFMT_CBS_CFS: | ||
638 | clk &= ~1; | ||
639 | break; | ||
640 | default: | ||
641 | return -EINVAL; | ||
642 | } | ||
643 | |||
644 | /* interface format */ | ||
645 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
646 | case SND_SOC_DAIFMT_I2S: | ||
647 | iface |= 0x10; | ||
648 | break; | ||
649 | case SND_SOC_DAIFMT_RIGHT_J: | ||
650 | break; | ||
651 | case SND_SOC_DAIFMT_LEFT_J: | ||
652 | iface |= 0x8; | ||
653 | break; | ||
654 | case SND_SOC_DAIFMT_DSP_A: | ||
655 | iface |= 0x18; | ||
656 | break; | ||
657 | default: | ||
658 | return -EINVAL; | ||
659 | } | ||
660 | |||
661 | /* clock inversion */ | ||
662 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
663 | case SND_SOC_DAIFMT_NB_NF: | ||
664 | break; | ||
665 | case SND_SOC_DAIFMT_IB_IF: | ||
666 | iface |= 0x180; | ||
667 | break; | ||
668 | case SND_SOC_DAIFMT_IB_NF: | ||
669 | iface |= 0x100; | ||
670 | break; | ||
671 | case SND_SOC_DAIFMT_NB_IF: | ||
672 | iface |= 0x80; | ||
673 | break; | ||
674 | default: | ||
675 | return -EINVAL; | ||
676 | } | ||
677 | |||
678 | snd_soc_write(codec, WM8978_AUDIO_INTERFACE, iface); | ||
679 | snd_soc_write(codec, WM8978_CLOCKING, clk); | ||
680 | |||
681 | return 0; | ||
682 | } | ||
683 | |||
684 | /* | ||
685 | * Set PCM DAI bit size and sample rate. | ||
686 | */ | ||
687 | static int wm8978_hw_params(struct snd_pcm_substream *substream, | ||
688 | struct snd_pcm_hw_params *params, | ||
689 | struct snd_soc_dai *dai) | ||
690 | { | ||
691 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
692 | struct snd_soc_device *socdev = rtd->socdev; | ||
693 | struct snd_soc_codec *codec = socdev->card->codec; | ||
694 | struct wm8978_priv *wm8978 = codec->private_data; | ||
695 | /* Word length mask = 0x60 */ | ||
696 | u16 iface_ctl = snd_soc_read(codec, WM8978_AUDIO_INTERFACE) & ~0x60; | ||
697 | /* Sampling rate mask = 0xe (for filters) */ | ||
698 | u16 add_ctl = snd_soc_read(codec, WM8978_ADDITIONAL_CONTROL) & ~0xe; | ||
699 | u16 clking = snd_soc_read(codec, WM8978_CLOCKING); | ||
700 | enum wm8978_sysclk_src current_clk_id = clking & 0x100 ? | ||
701 | WM8978_PLL : WM8978_MCLK; | ||
702 | unsigned int f_sel, diff, diff_best = INT_MAX; | ||
703 | int i, best = 0; | ||
704 | |||
705 | if (!wm8978->f_mclk) | ||
706 | return -EINVAL; | ||
707 | |||
708 | /* bit size */ | ||
709 | switch (params_format(params)) { | ||
710 | case SNDRV_PCM_FORMAT_S16_LE: | ||
711 | break; | ||
712 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
713 | iface_ctl |= 0x20; | ||
714 | break; | ||
715 | case SNDRV_PCM_FORMAT_S24_LE: | ||
716 | iface_ctl |= 0x40; | ||
717 | break; | ||
718 | case SNDRV_PCM_FORMAT_S32_LE: | ||
719 | iface_ctl |= 0x60; | ||
720 | break; | ||
721 | } | ||
722 | |||
723 | /* filter coefficient */ | ||
724 | switch (params_rate(params)) { | ||
725 | case 8000: | ||
726 | add_ctl |= 0x5 << 1; | ||
727 | break; | ||
728 | case 11025: | ||
729 | add_ctl |= 0x4 << 1; | ||
730 | break; | ||
731 | case 16000: | ||
732 | add_ctl |= 0x3 << 1; | ||
733 | break; | ||
734 | case 22050: | ||
735 | add_ctl |= 0x2 << 1; | ||
736 | break; | ||
737 | case 32000: | ||
738 | add_ctl |= 0x1 << 1; | ||
739 | break; | ||
740 | case 44100: | ||
741 | case 48000: | ||
742 | break; | ||
743 | } | ||
744 | |||
745 | /* Sampling rate is known now, can configure the MCLK divider */ | ||
746 | wm8978->f_256fs = params_rate(params) * 256; | ||
747 | |||
748 | if (wm8978->sysclk == WM8978_MCLK) { | ||
749 | wm8978->mclk_idx = -1; | ||
750 | f_sel = wm8978->f_mclk; | ||
751 | } else { | ||
752 | if (!wm8978->f_pllout) { | ||
753 | /* We only enter here, if OPCLK is not used */ | ||
754 | int ret = wm8978_configure_pll(codec); | ||
755 | if (ret < 0) | ||
756 | return ret; | ||
757 | } | ||
758 | f_sel = wm8978->f_pllout; | ||
759 | } | ||
760 | |||
761 | if (wm8978->mclk_idx < 0) { | ||
762 | /* Either MCLK is used directly, or OPCLK is used */ | ||
763 | if (f_sel < wm8978->f_256fs || f_sel > 12 * wm8978->f_256fs) | ||
764 | return -EINVAL; | ||
765 | |||
766 | for (i = 0; i < ARRAY_SIZE(mclk_numerator); i++) { | ||
767 | diff = abs(wm8978->f_256fs * 3 - | ||
768 | f_sel * 3 * mclk_denominator[i] / mclk_numerator[i]); | ||
769 | |||
770 | if (diff < diff_best) { | ||
771 | diff_best = diff; | ||
772 | best = i; | ||
773 | } | ||
774 | |||
775 | if (!diff) | ||
776 | break; | ||
777 | } | ||
778 | } else { | ||
779 | /* OPCLK not used, codec driven by PLL */ | ||
780 | best = wm8978->mclk_idx; | ||
781 | diff = 0; | ||
782 | } | ||
783 | |||
784 | if (diff) | ||
785 | dev_warn(codec->dev, "Imprecise sampling rate: %uHz%s\n", | ||
786 | f_sel * mclk_denominator[best] / mclk_numerator[best] / 256, | ||
787 | wm8978->sysclk == WM8978_MCLK ? | ||
788 | ", consider using PLL" : ""); | ||
789 | |||
790 | dev_dbg(codec->dev, "%s: fmt %d, rate %u, MCLK divisor #%d\n", __func__, | ||
791 | params_format(params), params_rate(params), best); | ||
792 | |||
793 | /* MCLK divisor mask = 0xe0 */ | ||
794 | snd_soc_update_bits(codec, WM8978_CLOCKING, 0xe0, best << 5); | ||
795 | |||
796 | snd_soc_write(codec, WM8978_AUDIO_INTERFACE, iface_ctl); | ||
797 | snd_soc_write(codec, WM8978_ADDITIONAL_CONTROL, add_ctl); | ||
798 | |||
799 | if (wm8978->sysclk != current_clk_id) { | ||
800 | if (wm8978->sysclk == WM8978_PLL) | ||
801 | /* Run CODEC from PLL instead of MCLK */ | ||
802 | snd_soc_update_bits(codec, WM8978_CLOCKING, | ||
803 | 0x100, 0x100); | ||
804 | else | ||
805 | /* Clock CODEC directly from MCLK */ | ||
806 | snd_soc_update_bits(codec, WM8978_CLOCKING, 0x100, 0); | ||
807 | } | ||
808 | |||
809 | return 0; | ||
810 | } | ||
811 | |||
812 | static int wm8978_mute(struct snd_soc_dai *dai, int mute) | ||
813 | { | ||
814 | struct snd_soc_codec *codec = dai->codec; | ||
815 | |||
816 | dev_dbg(codec->dev, "%s: %d\n", __func__, mute); | ||
817 | |||
818 | if (mute) | ||
819 | snd_soc_update_bits(codec, WM8978_DAC_CONTROL, 0x40, 0x40); | ||
820 | else | ||
821 | snd_soc_update_bits(codec, WM8978_DAC_CONTROL, 0x40, 0); | ||
822 | |||
823 | return 0; | ||
824 | } | ||
825 | |||
826 | static int wm8978_set_bias_level(struct snd_soc_codec *codec, | ||
827 | enum snd_soc_bias_level level) | ||
828 | { | ||
829 | u16 power1 = snd_soc_read(codec, WM8978_POWER_MANAGEMENT_1) & ~3; | ||
830 | |||
831 | switch (level) { | ||
832 | case SND_SOC_BIAS_ON: | ||
833 | case SND_SOC_BIAS_PREPARE: | ||
834 | power1 |= 1; /* VMID 75k */ | ||
835 | snd_soc_write(codec, WM8978_POWER_MANAGEMENT_1, power1); | ||
836 | break; | ||
837 | case SND_SOC_BIAS_STANDBY: | ||
838 | /* bit 3: enable bias, bit 2: enable I/O tie off buffer */ | ||
839 | power1 |= 0xc; | ||
840 | |||
841 | if (codec->bias_level == SND_SOC_BIAS_OFF) { | ||
842 | /* Initial cap charge at VMID 5k */ | ||
843 | snd_soc_write(codec, WM8978_POWER_MANAGEMENT_1, | ||
844 | power1 | 0x3); | ||
845 | mdelay(100); | ||
846 | } | ||
847 | |||
848 | power1 |= 0x2; /* VMID 500k */ | ||
849 | snd_soc_write(codec, WM8978_POWER_MANAGEMENT_1, power1); | ||
850 | break; | ||
851 | case SND_SOC_BIAS_OFF: | ||
852 | /* Preserve PLL - OPCLK may be used by someone */ | ||
853 | snd_soc_update_bits(codec, WM8978_POWER_MANAGEMENT_1, ~0x20, 0); | ||
854 | snd_soc_write(codec, WM8978_POWER_MANAGEMENT_2, 0); | ||
855 | snd_soc_write(codec, WM8978_POWER_MANAGEMENT_3, 0); | ||
856 | break; | ||
857 | } | ||
858 | |||
859 | dev_dbg(codec->dev, "%s: %d, %x\n", __func__, level, power1); | ||
860 | |||
861 | codec->bias_level = level; | ||
862 | return 0; | ||
863 | } | ||
864 | |||
865 | #define WM8978_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ | ||
866 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) | ||
867 | |||
868 | static struct snd_soc_dai_ops wm8978_dai_ops = { | ||
869 | .hw_params = wm8978_hw_params, | ||
870 | .digital_mute = wm8978_mute, | ||
871 | .set_fmt = wm8978_set_dai_fmt, | ||
872 | .set_clkdiv = wm8978_set_dai_clkdiv, | ||
873 | .set_sysclk = wm8978_set_dai_sysclk, | ||
874 | }; | ||
875 | |||
876 | /* Also supports 12kHz */ | ||
877 | struct snd_soc_dai wm8978_dai = { | ||
878 | .name = "WM8978 HiFi", | ||
879 | .id = 1, | ||
880 | .playback = { | ||
881 | .stream_name = "Playback", | ||
882 | .channels_min = 1, | ||
883 | .channels_max = 2, | ||
884 | .rates = SNDRV_PCM_RATE_8000_48000, | ||
885 | .formats = WM8978_FORMATS, | ||
886 | }, | ||
887 | .capture = { | ||
888 | .stream_name = "Capture", | ||
889 | .channels_min = 1, | ||
890 | .channels_max = 2, | ||
891 | .rates = SNDRV_PCM_RATE_8000_48000, | ||
892 | .formats = WM8978_FORMATS, | ||
893 | }, | ||
894 | .ops = &wm8978_dai_ops, | ||
895 | }; | ||
896 | EXPORT_SYMBOL_GPL(wm8978_dai); | ||
897 | |||
898 | static int wm8978_suspend(struct platform_device *pdev, pm_message_t state) | ||
899 | { | ||
900 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
901 | struct snd_soc_codec *codec = socdev->card->codec; | ||
902 | |||
903 | wm8978_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
904 | /* Also switch PLL off */ | ||
905 | snd_soc_write(codec, WM8978_POWER_MANAGEMENT_1, 0); | ||
906 | |||
907 | return 0; | ||
908 | } | ||
909 | |||
910 | static int wm8978_resume(struct platform_device *pdev) | ||
911 | { | ||
912 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
913 | struct snd_soc_codec *codec = socdev->card->codec; | ||
914 | struct wm8978_priv *wm8978 = codec->private_data; | ||
915 | int i; | ||
916 | u16 *cache = codec->reg_cache; | ||
917 | |||
918 | /* Sync reg_cache with the hardware */ | ||
919 | for (i = 0; i < ARRAY_SIZE(wm8978_reg); i++) { | ||
920 | if (i == WM8978_RESET) | ||
921 | continue; | ||
922 | if (cache[i] != wm8978_reg[i]) | ||
923 | snd_soc_write(codec, i, cache[i]); | ||
924 | } | ||
925 | |||
926 | wm8978_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
927 | |||
928 | if (wm8978->f_pllout) | ||
929 | /* Switch PLL on */ | ||
930 | snd_soc_update_bits(codec, WM8978_POWER_MANAGEMENT_1, 0x20, 0x20); | ||
931 | |||
932 | return 0; | ||
933 | } | ||
934 | |||
935 | static int wm8978_probe(struct platform_device *pdev) | ||
936 | { | ||
937 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
938 | struct snd_soc_codec *codec; | ||
939 | int ret = 0; | ||
940 | |||
941 | if (wm8978_codec == NULL) { | ||
942 | dev_err(&pdev->dev, "Codec device not registered\n"); | ||
943 | return -ENODEV; | ||
944 | } | ||
945 | |||
946 | socdev->card->codec = wm8978_codec; | ||
947 | codec = wm8978_codec; | ||
948 | |||
949 | /* register pcms */ | ||
950 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
951 | if (ret < 0) { | ||
952 | dev_err(codec->dev, "failed to create pcms: %d\n", ret); | ||
953 | goto pcm_err; | ||
954 | } | ||
955 | |||
956 | snd_soc_add_controls(codec, wm8978_snd_controls, | ||
957 | ARRAY_SIZE(wm8978_snd_controls)); | ||
958 | wm8978_add_widgets(codec); | ||
959 | |||
960 | pcm_err: | ||
961 | return ret; | ||
962 | } | ||
963 | |||
964 | /* power down chip */ | ||
965 | static int wm8978_remove(struct platform_device *pdev) | ||
966 | { | ||
967 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
968 | |||
969 | snd_soc_free_pcms(socdev); | ||
970 | snd_soc_dapm_free(socdev); | ||
971 | |||
972 | return 0; | ||
973 | } | ||
974 | |||
975 | struct snd_soc_codec_device soc_codec_dev_wm8978 = { | ||
976 | .probe = wm8978_probe, | ||
977 | .remove = wm8978_remove, | ||
978 | .suspend = wm8978_suspend, | ||
979 | .resume = wm8978_resume, | ||
980 | }; | ||
981 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8978); | ||
982 | |||
983 | /* | ||
984 | * These registers contain an "update" bit - bit 8. This means, for example, | ||
985 | * that one can write new DAC digital volume for both channels, but only when | ||
986 | * the update bit is set, will also the volume be updated - simultaneously for | ||
987 | * both channels. | ||
988 | */ | ||
989 | static const int update_reg[] = { | ||
990 | WM8978_LEFT_DAC_DIGITAL_VOLUME, | ||
991 | WM8978_RIGHT_DAC_DIGITAL_VOLUME, | ||
992 | WM8978_LEFT_ADC_DIGITAL_VOLUME, | ||
993 | WM8978_RIGHT_ADC_DIGITAL_VOLUME, | ||
994 | WM8978_LEFT_INP_PGA_CONTROL, | ||
995 | WM8978_RIGHT_INP_PGA_CONTROL, | ||
996 | WM8978_LOUT1_HP_CONTROL, | ||
997 | WM8978_ROUT1_HP_CONTROL, | ||
998 | WM8978_LOUT2_SPK_CONTROL, | ||
999 | WM8978_ROUT2_SPK_CONTROL, | ||
1000 | }; | ||
1001 | |||
1002 | static __devinit int wm8978_register(struct wm8978_priv *wm8978) | ||
1003 | { | ||
1004 | int ret, i; | ||
1005 | struct snd_soc_codec *codec = &wm8978->codec; | ||
1006 | |||
1007 | if (wm8978_codec) { | ||
1008 | dev_err(codec->dev, "Another WM8978 is registered\n"); | ||
1009 | return -EINVAL; | ||
1010 | } | ||
1011 | |||
1012 | /* | ||
1013 | * Set default system clock to PLL, it is more precise, this is also the | ||
1014 | * default hardware setting | ||
1015 | */ | ||
1016 | wm8978->sysclk = WM8978_PLL; | ||
1017 | |||
1018 | mutex_init(&codec->mutex); | ||
1019 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
1020 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
1021 | |||
1022 | codec->private_data = wm8978; | ||
1023 | codec->name = "WM8978"; | ||
1024 | codec->owner = THIS_MODULE; | ||
1025 | codec->bias_level = SND_SOC_BIAS_OFF; | ||
1026 | codec->set_bias_level = wm8978_set_bias_level; | ||
1027 | codec->dai = &wm8978_dai; | ||
1028 | codec->num_dai = 1; | ||
1029 | codec->reg_cache_size = WM8978_CACHEREGNUM; | ||
1030 | codec->reg_cache = &wm8978->reg_cache; | ||
1031 | |||
1032 | ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_I2C); | ||
1033 | if (ret < 0) { | ||
1034 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); | ||
1035 | goto err; | ||
1036 | } | ||
1037 | |||
1038 | memcpy(codec->reg_cache, wm8978_reg, sizeof(wm8978_reg)); | ||
1039 | |||
1040 | /* | ||
1041 | * Set the update bit in all registers, that have one. This way all | ||
1042 | * writes to those registers will also cause the update bit to be | ||
1043 | * written. | ||
1044 | */ | ||
1045 | for (i = 0; i < ARRAY_SIZE(update_reg); i++) | ||
1046 | ((u16 *)codec->reg_cache)[update_reg[i]] |= 0x100; | ||
1047 | |||
1048 | /* Reset the codec */ | ||
1049 | ret = snd_soc_write(codec, WM8978_RESET, 0); | ||
1050 | if (ret < 0) { | ||
1051 | dev_err(codec->dev, "Failed to issue reset\n"); | ||
1052 | goto err; | ||
1053 | } | ||
1054 | |||
1055 | wm8978_dai.dev = codec->dev; | ||
1056 | |||
1057 | wm8978_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1058 | |||
1059 | wm8978_codec = codec; | ||
1060 | |||
1061 | ret = snd_soc_register_codec(codec); | ||
1062 | if (ret != 0) { | ||
1063 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); | ||
1064 | goto err; | ||
1065 | } | ||
1066 | |||
1067 | ret = snd_soc_register_dai(&wm8978_dai); | ||
1068 | if (ret != 0) { | ||
1069 | dev_err(codec->dev, "Failed to register DAI: %d\n", ret); | ||
1070 | goto err_codec; | ||
1071 | } | ||
1072 | |||
1073 | return 0; | ||
1074 | |||
1075 | err_codec: | ||
1076 | snd_soc_unregister_codec(codec); | ||
1077 | err: | ||
1078 | kfree(wm8978); | ||
1079 | return ret; | ||
1080 | } | ||
1081 | |||
1082 | static __devexit void wm8978_unregister(struct wm8978_priv *wm8978) | ||
1083 | { | ||
1084 | wm8978_set_bias_level(&wm8978->codec, SND_SOC_BIAS_OFF); | ||
1085 | snd_soc_unregister_dai(&wm8978_dai); | ||
1086 | snd_soc_unregister_codec(&wm8978->codec); | ||
1087 | kfree(wm8978); | ||
1088 | wm8978_codec = NULL; | ||
1089 | } | ||
1090 | |||
1091 | static __devinit int wm8978_i2c_probe(struct i2c_client *i2c, | ||
1092 | const struct i2c_device_id *id) | ||
1093 | { | ||
1094 | struct wm8978_priv *wm8978; | ||
1095 | struct snd_soc_codec *codec; | ||
1096 | |||
1097 | wm8978 = kzalloc(sizeof(struct wm8978_priv), GFP_KERNEL); | ||
1098 | if (wm8978 == NULL) | ||
1099 | return -ENOMEM; | ||
1100 | |||
1101 | codec = &wm8978->codec; | ||
1102 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
1103 | |||
1104 | i2c_set_clientdata(i2c, wm8978); | ||
1105 | codec->control_data = i2c; | ||
1106 | |||
1107 | codec->dev = &i2c->dev; | ||
1108 | |||
1109 | return wm8978_register(wm8978); | ||
1110 | } | ||
1111 | |||
1112 | static __devexit int wm8978_i2c_remove(struct i2c_client *client) | ||
1113 | { | ||
1114 | struct wm8978_priv *wm8978 = i2c_get_clientdata(client); | ||
1115 | wm8978_unregister(wm8978); | ||
1116 | return 0; | ||
1117 | } | ||
1118 | |||
1119 | static const struct i2c_device_id wm8978_i2c_id[] = { | ||
1120 | { "wm8978", 0 }, | ||
1121 | { } | ||
1122 | }; | ||
1123 | MODULE_DEVICE_TABLE(i2c, wm8978_i2c_id); | ||
1124 | |||
1125 | static struct i2c_driver wm8978_i2c_driver = { | ||
1126 | .driver = { | ||
1127 | .name = "WM8978", | ||
1128 | .owner = THIS_MODULE, | ||
1129 | }, | ||
1130 | .probe = wm8978_i2c_probe, | ||
1131 | .remove = __devexit_p(wm8978_i2c_remove), | ||
1132 | .id_table = wm8978_i2c_id, | ||
1133 | }; | ||
1134 | |||
1135 | static int __init wm8978_modinit(void) | ||
1136 | { | ||
1137 | return i2c_add_driver(&wm8978_i2c_driver); | ||
1138 | } | ||
1139 | module_init(wm8978_modinit); | ||
1140 | |||
1141 | static void __exit wm8978_exit(void) | ||
1142 | { | ||
1143 | i2c_del_driver(&wm8978_i2c_driver); | ||
1144 | } | ||
1145 | module_exit(wm8978_exit); | ||
1146 | |||
1147 | MODULE_DESCRIPTION("ASoC WM8978 codec driver"); | ||
1148 | MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>"); | ||
1149 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/wm8978.h b/sound/soc/codecs/wm8978.h new file mode 100644 index 000000000000..56ec83270917 --- /dev/null +++ b/sound/soc/codecs/wm8978.h | |||
@@ -0,0 +1,86 @@ | |||
1 | /* | ||
2 | * wm8978.h -- codec driver for WM8978 | ||
3 | * | ||
4 | * Copyright 2009 Guennadi Liakhovetski <g.liakhovetski@gmx.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 version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #ifndef __WM8978_H__ | ||
12 | #define __WM8978_H__ | ||
13 | |||
14 | /* | ||
15 | * Register values. | ||
16 | */ | ||
17 | #define WM8978_RESET 0x00 | ||
18 | #define WM8978_POWER_MANAGEMENT_1 0x01 | ||
19 | #define WM8978_POWER_MANAGEMENT_2 0x02 | ||
20 | #define WM8978_POWER_MANAGEMENT_3 0x03 | ||
21 | #define WM8978_AUDIO_INTERFACE 0x04 | ||
22 | #define WM8978_COMPANDING_CONTROL 0x05 | ||
23 | #define WM8978_CLOCKING 0x06 | ||
24 | #define WM8978_ADDITIONAL_CONTROL 0x07 | ||
25 | #define WM8978_GPIO_CONTROL 0x08 | ||
26 | #define WM8978_JACK_DETECT_CONTROL_1 0x09 | ||
27 | #define WM8978_DAC_CONTROL 0x0A | ||
28 | #define WM8978_LEFT_DAC_DIGITAL_VOLUME 0x0B | ||
29 | #define WM8978_RIGHT_DAC_DIGITAL_VOLUME 0x0C | ||
30 | #define WM8978_JACK_DETECT_CONTROL_2 0x0D | ||
31 | #define WM8978_ADC_CONTROL 0x0E | ||
32 | #define WM8978_LEFT_ADC_DIGITAL_VOLUME 0x0F | ||
33 | #define WM8978_RIGHT_ADC_DIGITAL_VOLUME 0x10 | ||
34 | #define WM8978_EQ1 0x12 | ||
35 | #define WM8978_EQ2 0x13 | ||
36 | #define WM8978_EQ3 0x14 | ||
37 | #define WM8978_EQ4 0x15 | ||
38 | #define WM8978_EQ5 0x16 | ||
39 | #define WM8978_DAC_LIMITER_1 0x18 | ||
40 | #define WM8978_DAC_LIMITER_2 0x19 | ||
41 | #define WM8978_NOTCH_FILTER_1 0x1b | ||
42 | #define WM8978_NOTCH_FILTER_2 0x1c | ||
43 | #define WM8978_NOTCH_FILTER_3 0x1d | ||
44 | #define WM8978_NOTCH_FILTER_4 0x1e | ||
45 | #define WM8978_ALC_CONTROL_1 0x20 | ||
46 | #define WM8978_ALC_CONTROL_2 0x21 | ||
47 | #define WM8978_ALC_CONTROL_3 0x22 | ||
48 | #define WM8978_NOISE_GATE 0x23 | ||
49 | #define WM8978_PLL_N 0x24 | ||
50 | #define WM8978_PLL_K1 0x25 | ||
51 | #define WM8978_PLL_K2 0x26 | ||
52 | #define WM8978_PLL_K3 0x27 | ||
53 | #define WM8978_3D_CONTROL 0x29 | ||
54 | #define WM8978_BEEP_CONTROL 0x2b | ||
55 | #define WM8978_INPUT_CONTROL 0x2c | ||
56 | #define WM8978_LEFT_INP_PGA_CONTROL 0x2d | ||
57 | #define WM8978_RIGHT_INP_PGA_CONTROL 0x2e | ||
58 | #define WM8978_LEFT_ADC_BOOST_CONTROL 0x2f | ||
59 | #define WM8978_RIGHT_ADC_BOOST_CONTROL 0x30 | ||
60 | #define WM8978_OUTPUT_CONTROL 0x31 | ||
61 | #define WM8978_LEFT_MIXER_CONTROL 0x32 | ||
62 | #define WM8978_RIGHT_MIXER_CONTROL 0x33 | ||
63 | #define WM8978_LOUT1_HP_CONTROL 0x34 | ||
64 | #define WM8978_ROUT1_HP_CONTROL 0x35 | ||
65 | #define WM8978_LOUT2_SPK_CONTROL 0x36 | ||
66 | #define WM8978_ROUT2_SPK_CONTROL 0x37 | ||
67 | #define WM8978_OUT3_MIXER_CONTROL 0x38 | ||
68 | #define WM8978_OUT4_MIXER_CONTROL 0x39 | ||
69 | |||
70 | #define WM8978_CACHEREGNUM 58 | ||
71 | |||
72 | /* Clock divider Id's */ | ||
73 | enum wm8978_clk_id { | ||
74 | WM8978_OPCLKRATE, | ||
75 | WM8978_BCLKDIV, | ||
76 | }; | ||
77 | |||
78 | enum wm8978_sysclk_src { | ||
79 | WM8978_PLL, | ||
80 | WM8978_MCLK | ||
81 | }; | ||
82 | |||
83 | extern struct snd_soc_dai wm8978_dai; | ||
84 | extern struct snd_soc_codec_device soc_codec_dev_wm8978; | ||
85 | |||
86 | #endif /* __WM8978_H__ */ | ||
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index 427614a2762b..056b787b6ee0 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c | |||
@@ -1319,10 +1319,6 @@ static int wm8990_suspend(struct platform_device *pdev, pm_message_t state) | |||
1319 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1319 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
1320 | struct snd_soc_codec *codec = socdev->card->codec; | 1320 | struct snd_soc_codec *codec = socdev->card->codec; |
1321 | 1321 | ||
1322 | /* we only need to suspend if we are a valid card */ | ||
1323 | if (!codec->card) | ||
1324 | return 0; | ||
1325 | |||
1326 | wm8990_set_bias_level(codec, SND_SOC_BIAS_OFF); | 1322 | wm8990_set_bias_level(codec, SND_SOC_BIAS_OFF); |
1327 | return 0; | 1323 | return 0; |
1328 | } | 1324 | } |
@@ -1335,10 +1331,6 @@ static int wm8990_resume(struct platform_device *pdev) | |||
1335 | u8 data[2]; | 1331 | u8 data[2]; |
1336 | u16 *cache = codec->reg_cache; | 1332 | u16 *cache = codec->reg_cache; |
1337 | 1333 | ||
1338 | /* we only need to resume if we are a valid card */ | ||
1339 | if (!codec->card) | ||
1340 | return 0; | ||
1341 | |||
1342 | /* Sync reg_cache with the hardware */ | 1334 | /* Sync reg_cache with the hardware */ |
1343 | for (i = 0; i < ARRAY_SIZE(wm8990_reg); i++) { | 1335 | for (i = 0; i < ARRAY_SIZE(wm8990_reg); i++) { |
1344 | if (i + 1 == WM8990_RESET) | 1336 | if (i + 1 == WM8990_RESET) |
diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c index 2981afae842c..bf022f68b84f 100644 --- a/sound/soc/codecs/wm8993.c +++ b/sound/soc/codecs/wm8993.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * wm8993.c -- WM8993 ALSA SoC audio driver | 2 | * wm8993.c -- WM8993 ALSA SoC audio driver |
3 | * | 3 | * |
4 | * Copyright 2009 Wolfson Microelectronics plc | 4 | * Copyright 2009, 2010 Wolfson Microelectronics plc |
5 | * | 5 | * |
6 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | 6 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> |
7 | * | 7 | * |
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/delay.h> | 16 | #include <linux/delay.h> |
17 | #include <linux/pm.h> | 17 | #include <linux/pm.h> |
18 | #include <linux/i2c.h> | 18 | #include <linux/i2c.h> |
19 | #include <linux/regulator/consumer.h> | ||
19 | #include <linux/spi/spi.h> | 20 | #include <linux/spi/spi.h> |
20 | #include <sound/core.h> | 21 | #include <sound/core.h> |
21 | #include <sound/pcm.h> | 22 | #include <sound/pcm.h> |
@@ -29,6 +30,16 @@ | |||
29 | #include "wm8993.h" | 30 | #include "wm8993.h" |
30 | #include "wm_hubs.h" | 31 | #include "wm_hubs.h" |
31 | 32 | ||
33 | #define WM8993_NUM_SUPPLIES 6 | ||
34 | static const char *wm8993_supply_names[WM8993_NUM_SUPPLIES] = { | ||
35 | "DCVDD", | ||
36 | "DBVDD", | ||
37 | "AVDD1", | ||
38 | "AVDD2", | ||
39 | "CPVDD", | ||
40 | "SPKVDD", | ||
41 | }; | ||
42 | |||
32 | static u16 wm8993_reg_defaults[WM8993_REGISTER_COUNT] = { | 43 | static u16 wm8993_reg_defaults[WM8993_REGISTER_COUNT] = { |
33 | 0x8993, /* R0 - Software Reset */ | 44 | 0x8993, /* R0 - Software Reset */ |
34 | 0x0000, /* R1 - Power Management (1) */ | 45 | 0x0000, /* R1 - Power Management (1) */ |
@@ -213,7 +224,9 @@ static struct { | |||
213 | }; | 224 | }; |
214 | 225 | ||
215 | struct wm8993_priv { | 226 | struct wm8993_priv { |
227 | struct wm_hubs_data hubs_data; | ||
216 | u16 reg_cache[WM8993_REGISTER_COUNT]; | 228 | u16 reg_cache[WM8993_REGISTER_COUNT]; |
229 | struct regulator_bulk_data supplies[WM8993_NUM_SUPPLIES]; | ||
217 | struct wm8993_platform_data pdata; | 230 | struct wm8993_platform_data pdata; |
218 | struct snd_soc_codec codec; | 231 | struct snd_soc_codec codec; |
219 | int master; | 232 | int master; |
@@ -227,36 +240,9 @@ struct wm8993_priv { | |||
227 | int class_w_users; | 240 | int class_w_users; |
228 | unsigned int fll_fref; | 241 | unsigned int fll_fref; |
229 | unsigned int fll_fout; | 242 | unsigned int fll_fout; |
243 | int fll_src; | ||
230 | }; | 244 | }; |
231 | 245 | ||
232 | static unsigned int wm8993_read_hw(struct snd_soc_codec *codec, u8 reg) | ||
233 | { | ||
234 | struct i2c_msg xfer[2]; | ||
235 | u16 data; | ||
236 | int ret; | ||
237 | struct i2c_client *i2c = codec->control_data; | ||
238 | |||
239 | /* Write register */ | ||
240 | xfer[0].addr = i2c->addr; | ||
241 | xfer[0].flags = 0; | ||
242 | xfer[0].len = 1; | ||
243 | xfer[0].buf = ® | ||
244 | |||
245 | /* Read data */ | ||
246 | xfer[1].addr = i2c->addr; | ||
247 | xfer[1].flags = I2C_M_RD; | ||
248 | xfer[1].len = 2; | ||
249 | xfer[1].buf = (u8 *)&data; | ||
250 | |||
251 | ret = i2c_transfer(i2c->adapter, xfer, 2); | ||
252 | if (ret != 2) { | ||
253 | dev_err(codec->dev, "Failed to read 0x%x: %d\n", reg, ret); | ||
254 | return 0; | ||
255 | } | ||
256 | |||
257 | return (data >> 8) | ((data & 0xff) << 8); | ||
258 | } | ||
259 | |||
260 | static int wm8993_volatile(unsigned int reg) | 246 | static int wm8993_volatile(unsigned int reg) |
261 | { | 247 | { |
262 | switch (reg) { | 248 | switch (reg) { |
@@ -271,48 +257,6 @@ static int wm8993_volatile(unsigned int reg) | |||
271 | } | 257 | } |
272 | } | 258 | } |
273 | 259 | ||
274 | static unsigned int wm8993_read(struct snd_soc_codec *codec, | ||
275 | unsigned int reg) | ||
276 | { | ||
277 | u16 *reg_cache = codec->reg_cache; | ||
278 | |||
279 | BUG_ON(reg > WM8993_MAX_REGISTER); | ||
280 | |||
281 | if (wm8993_volatile(reg)) | ||
282 | return wm8993_read_hw(codec, reg); | ||
283 | else | ||
284 | return reg_cache[reg]; | ||
285 | } | ||
286 | |||
287 | static int wm8993_write(struct snd_soc_codec *codec, unsigned int reg, | ||
288 | unsigned int value) | ||
289 | { | ||
290 | u16 *reg_cache = codec->reg_cache; | ||
291 | u8 data[3]; | ||
292 | int ret; | ||
293 | |||
294 | BUG_ON(reg > WM8993_MAX_REGISTER); | ||
295 | |||
296 | /* data is | ||
297 | * D15..D9 WM8993 register offset | ||
298 | * D8...D0 register data | ||
299 | */ | ||
300 | data[0] = reg; | ||
301 | data[1] = value >> 8; | ||
302 | data[2] = value & 0x00ff; | ||
303 | |||
304 | if (!wm8993_volatile(reg)) | ||
305 | reg_cache[reg] = value; | ||
306 | |||
307 | ret = codec->hw_write(codec->control_data, data, 3); | ||
308 | |||
309 | if (ret == 3) | ||
310 | return 0; | ||
311 | if (ret < 0) | ||
312 | return ret; | ||
313 | return -EIO; | ||
314 | } | ||
315 | |||
316 | struct _fll_div { | 260 | struct _fll_div { |
317 | u16 fll_fratio; | 261 | u16 fll_fratio; |
318 | u16 fll_outdiv; | 262 | u16 fll_outdiv; |
@@ -441,9 +385,9 @@ static int wm8993_set_fll(struct snd_soc_dai *dai, int fll_id, int source, | |||
441 | wm8993->fll_fref = 0; | 385 | wm8993->fll_fref = 0; |
442 | wm8993->fll_fout = 0; | 386 | wm8993->fll_fout = 0; |
443 | 387 | ||
444 | reg1 = wm8993_read(codec, WM8993_FLL_CONTROL_1); | 388 | reg1 = snd_soc_read(codec, WM8993_FLL_CONTROL_1); |
445 | reg1 &= ~WM8993_FLL_ENA; | 389 | reg1 &= ~WM8993_FLL_ENA; |
446 | wm8993_write(codec, WM8993_FLL_CONTROL_1, reg1); | 390 | snd_soc_write(codec, WM8993_FLL_CONTROL_1, reg1); |
447 | 391 | ||
448 | return 0; | 392 | return 0; |
449 | } | 393 | } |
@@ -452,7 +396,7 @@ static int wm8993_set_fll(struct snd_soc_dai *dai, int fll_id, int source, | |||
452 | if (ret != 0) | 396 | if (ret != 0) |
453 | return ret; | 397 | return ret; |
454 | 398 | ||
455 | reg5 = wm8993_read(codec, WM8993_FLL_CONTROL_5); | 399 | reg5 = snd_soc_read(codec, WM8993_FLL_CONTROL_5); |
456 | reg5 &= ~WM8993_FLL_CLK_SRC_MASK; | 400 | reg5 &= ~WM8993_FLL_CLK_SRC_MASK; |
457 | 401 | ||
458 | switch (fll_id) { | 402 | switch (fll_id) { |
@@ -474,38 +418,39 @@ static int wm8993_set_fll(struct snd_soc_dai *dai, int fll_id, int source, | |||
474 | 418 | ||
475 | /* Any FLL configuration change requires that the FLL be | 419 | /* Any FLL configuration change requires that the FLL be |
476 | * disabled first. */ | 420 | * disabled first. */ |
477 | reg1 = wm8993_read(codec, WM8993_FLL_CONTROL_1); | 421 | reg1 = snd_soc_read(codec, WM8993_FLL_CONTROL_1); |
478 | reg1 &= ~WM8993_FLL_ENA; | 422 | reg1 &= ~WM8993_FLL_ENA; |
479 | wm8993_write(codec, WM8993_FLL_CONTROL_1, reg1); | 423 | snd_soc_write(codec, WM8993_FLL_CONTROL_1, reg1); |
480 | 424 | ||
481 | /* Apply the configuration */ | 425 | /* Apply the configuration */ |
482 | if (fll_div.k) | 426 | if (fll_div.k) |
483 | reg1 |= WM8993_FLL_FRAC_MASK; | 427 | reg1 |= WM8993_FLL_FRAC_MASK; |
484 | else | 428 | else |
485 | reg1 &= ~WM8993_FLL_FRAC_MASK; | 429 | reg1 &= ~WM8993_FLL_FRAC_MASK; |
486 | wm8993_write(codec, WM8993_FLL_CONTROL_1, reg1); | 430 | snd_soc_write(codec, WM8993_FLL_CONTROL_1, reg1); |
487 | 431 | ||
488 | wm8993_write(codec, WM8993_FLL_CONTROL_2, | 432 | snd_soc_write(codec, WM8993_FLL_CONTROL_2, |
489 | (fll_div.fll_outdiv << WM8993_FLL_OUTDIV_SHIFT) | | 433 | (fll_div.fll_outdiv << WM8993_FLL_OUTDIV_SHIFT) | |
490 | (fll_div.fll_fratio << WM8993_FLL_FRATIO_SHIFT)); | 434 | (fll_div.fll_fratio << WM8993_FLL_FRATIO_SHIFT)); |
491 | wm8993_write(codec, WM8993_FLL_CONTROL_3, fll_div.k); | 435 | snd_soc_write(codec, WM8993_FLL_CONTROL_3, fll_div.k); |
492 | 436 | ||
493 | reg4 = wm8993_read(codec, WM8993_FLL_CONTROL_4); | 437 | reg4 = snd_soc_read(codec, WM8993_FLL_CONTROL_4); |
494 | reg4 &= ~WM8993_FLL_N_MASK; | 438 | reg4 &= ~WM8993_FLL_N_MASK; |
495 | reg4 |= fll_div.n << WM8993_FLL_N_SHIFT; | 439 | reg4 |= fll_div.n << WM8993_FLL_N_SHIFT; |
496 | wm8993_write(codec, WM8993_FLL_CONTROL_4, reg4); | 440 | snd_soc_write(codec, WM8993_FLL_CONTROL_4, reg4); |
497 | 441 | ||
498 | reg5 &= ~WM8993_FLL_CLK_REF_DIV_MASK; | 442 | reg5 &= ~WM8993_FLL_CLK_REF_DIV_MASK; |
499 | reg5 |= fll_div.fll_clk_ref_div << WM8993_FLL_CLK_REF_DIV_SHIFT; | 443 | reg5 |= fll_div.fll_clk_ref_div << WM8993_FLL_CLK_REF_DIV_SHIFT; |
500 | wm8993_write(codec, WM8993_FLL_CONTROL_5, reg5); | 444 | snd_soc_write(codec, WM8993_FLL_CONTROL_5, reg5); |
501 | 445 | ||
502 | /* Enable the FLL */ | 446 | /* Enable the FLL */ |
503 | wm8993_write(codec, WM8993_FLL_CONTROL_1, reg1 | WM8993_FLL_ENA); | 447 | snd_soc_write(codec, WM8993_FLL_CONTROL_1, reg1 | WM8993_FLL_ENA); |
504 | 448 | ||
505 | dev_dbg(codec->dev, "FLL enabled at %dHz->%dHz\n", Fref, Fout); | 449 | dev_dbg(codec->dev, "FLL enabled at %dHz->%dHz\n", Fref, Fout); |
506 | 450 | ||
507 | wm8993->fll_fref = Fref; | 451 | wm8993->fll_fref = Fref; |
508 | wm8993->fll_fout = Fout; | 452 | wm8993->fll_fout = Fout; |
453 | wm8993->fll_src = source; | ||
509 | 454 | ||
510 | return 0; | 455 | return 0; |
511 | } | 456 | } |
@@ -520,7 +465,7 @@ static int configure_clock(struct snd_soc_codec *codec) | |||
520 | case WM8993_SYSCLK_MCLK: | 465 | case WM8993_SYSCLK_MCLK: |
521 | dev_dbg(codec->dev, "Using %dHz MCLK\n", wm8993->mclk_rate); | 466 | dev_dbg(codec->dev, "Using %dHz MCLK\n", wm8993->mclk_rate); |
522 | 467 | ||
523 | reg = wm8993_read(codec, WM8993_CLOCKING_2); | 468 | reg = snd_soc_read(codec, WM8993_CLOCKING_2); |
524 | reg &= ~(WM8993_MCLK_DIV | WM8993_SYSCLK_SRC); | 469 | reg &= ~(WM8993_MCLK_DIV | WM8993_SYSCLK_SRC); |
525 | if (wm8993->mclk_rate > 13500000) { | 470 | if (wm8993->mclk_rate > 13500000) { |
526 | reg |= WM8993_MCLK_DIV; | 471 | reg |= WM8993_MCLK_DIV; |
@@ -529,14 +474,14 @@ static int configure_clock(struct snd_soc_codec *codec) | |||
529 | reg &= ~WM8993_MCLK_DIV; | 474 | reg &= ~WM8993_MCLK_DIV; |
530 | wm8993->sysclk_rate = wm8993->mclk_rate; | 475 | wm8993->sysclk_rate = wm8993->mclk_rate; |
531 | } | 476 | } |
532 | wm8993_write(codec, WM8993_CLOCKING_2, reg); | 477 | snd_soc_write(codec, WM8993_CLOCKING_2, reg); |
533 | break; | 478 | break; |
534 | 479 | ||
535 | case WM8993_SYSCLK_FLL: | 480 | case WM8993_SYSCLK_FLL: |
536 | dev_dbg(codec->dev, "Using %dHz FLL clock\n", | 481 | dev_dbg(codec->dev, "Using %dHz FLL clock\n", |
537 | wm8993->fll_fout); | 482 | wm8993->fll_fout); |
538 | 483 | ||
539 | reg = wm8993_read(codec, WM8993_CLOCKING_2); | 484 | reg = snd_soc_read(codec, WM8993_CLOCKING_2); |
540 | reg |= WM8993_SYSCLK_SRC; | 485 | reg |= WM8993_SYSCLK_SRC; |
541 | if (wm8993->fll_fout > 13500000) { | 486 | if (wm8993->fll_fout > 13500000) { |
542 | reg |= WM8993_MCLK_DIV; | 487 | reg |= WM8993_MCLK_DIV; |
@@ -545,7 +490,7 @@ static int configure_clock(struct snd_soc_codec *codec) | |||
545 | reg &= ~WM8993_MCLK_DIV; | 490 | reg &= ~WM8993_MCLK_DIV; |
546 | wm8993->sysclk_rate = wm8993->fll_fout; | 491 | wm8993->sysclk_rate = wm8993->fll_fout; |
547 | } | 492 | } |
548 | wm8993_write(codec, WM8993_CLOCKING_2, reg); | 493 | snd_soc_write(codec, WM8993_CLOCKING_2, reg); |
549 | break; | 494 | break; |
550 | 495 | ||
551 | default: | 496 | default: |
@@ -978,10 +923,33 @@ static const struct snd_soc_dapm_route routes[] = { | |||
978 | { "Right Headphone Mux", "DAC", "DACR" }, | 923 | { "Right Headphone Mux", "DAC", "DACR" }, |
979 | }; | 924 | }; |
980 | 925 | ||
926 | static void wm8993_cache_restore(struct snd_soc_codec *codec) | ||
927 | { | ||
928 | u16 *cache = codec->reg_cache; | ||
929 | int i; | ||
930 | |||
931 | if (!codec->cache_sync) | ||
932 | return; | ||
933 | |||
934 | /* Reenable hardware writes */ | ||
935 | codec->cache_only = 0; | ||
936 | |||
937 | /* Restore the register settings */ | ||
938 | for (i = 1; i < WM8993_MAX_REGISTER; i++) { | ||
939 | if (cache[i] == wm8993_reg_defaults[i]) | ||
940 | continue; | ||
941 | snd_soc_write(codec, i, cache[i]); | ||
942 | } | ||
943 | |||
944 | /* We're in sync again */ | ||
945 | codec->cache_sync = 0; | ||
946 | } | ||
947 | |||
981 | static int wm8993_set_bias_level(struct snd_soc_codec *codec, | 948 | static int wm8993_set_bias_level(struct snd_soc_codec *codec, |
982 | enum snd_soc_bias_level level) | 949 | enum snd_soc_bias_level level) |
983 | { | 950 | { |
984 | struct wm8993_priv *wm8993 = codec->private_data; | 951 | struct wm8993_priv *wm8993 = codec->private_data; |
952 | int ret; | ||
985 | 953 | ||
986 | switch (level) { | 954 | switch (level) { |
987 | case SND_SOC_BIAS_ON: | 955 | case SND_SOC_BIAS_ON: |
@@ -995,6 +963,18 @@ static int wm8993_set_bias_level(struct snd_soc_codec *codec, | |||
995 | 963 | ||
996 | case SND_SOC_BIAS_STANDBY: | 964 | case SND_SOC_BIAS_STANDBY: |
997 | if (codec->bias_level == SND_SOC_BIAS_OFF) { | 965 | if (codec->bias_level == SND_SOC_BIAS_OFF) { |
966 | ret = regulator_bulk_enable(ARRAY_SIZE(wm8993->supplies), | ||
967 | wm8993->supplies); | ||
968 | if (ret != 0) | ||
969 | return ret; | ||
970 | |||
971 | wm8993_cache_restore(codec); | ||
972 | |||
973 | /* Tune DC servo configuration */ | ||
974 | snd_soc_write(codec, 0x44, 3); | ||
975 | snd_soc_write(codec, 0x56, 3); | ||
976 | snd_soc_write(codec, 0x44, 0); | ||
977 | |||
998 | /* Bring up VMID with fast soft start */ | 978 | /* Bring up VMID with fast soft start */ |
999 | snd_soc_update_bits(codec, WM8993_ANTIPOP2, | 979 | snd_soc_update_bits(codec, WM8993_ANTIPOP2, |
1000 | WM8993_STARTUP_BIAS_ENA | | 980 | WM8993_STARTUP_BIAS_ENA | |
@@ -1042,6 +1022,18 @@ static int wm8993_set_bias_level(struct snd_soc_codec *codec, | |||
1042 | snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1, | 1022 | snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1, |
1043 | WM8993_VMID_SEL_MASK | WM8993_BIAS_ENA, | 1023 | WM8993_VMID_SEL_MASK | WM8993_BIAS_ENA, |
1044 | 0); | 1024 | 0); |
1025 | |||
1026 | #ifdef CONFIG_REGULATOR | ||
1027 | /* Post 2.6.34 we will be able to get a callback when | ||
1028 | * the regulators are disabled which we can use but | ||
1029 | * for now just assume that the power will be cut if | ||
1030 | * the regulator API is in use. | ||
1031 | */ | ||
1032 | codec->cache_sync = 1; | ||
1033 | #endif | ||
1034 | |||
1035 | regulator_bulk_disable(ARRAY_SIZE(wm8993->supplies), | ||
1036 | wm8993->supplies); | ||
1045 | break; | 1037 | break; |
1046 | } | 1038 | } |
1047 | 1039 | ||
@@ -1075,8 +1067,8 @@ static int wm8993_set_dai_fmt(struct snd_soc_dai *dai, | |||
1075 | { | 1067 | { |
1076 | struct snd_soc_codec *codec = dai->codec; | 1068 | struct snd_soc_codec *codec = dai->codec; |
1077 | struct wm8993_priv *wm8993 = codec->private_data; | 1069 | struct wm8993_priv *wm8993 = codec->private_data; |
1078 | unsigned int aif1 = wm8993_read(codec, WM8993_AUDIO_INTERFACE_1); | 1070 | unsigned int aif1 = snd_soc_read(codec, WM8993_AUDIO_INTERFACE_1); |
1079 | unsigned int aif4 = wm8993_read(codec, WM8993_AUDIO_INTERFACE_4); | 1071 | unsigned int aif4 = snd_soc_read(codec, WM8993_AUDIO_INTERFACE_4); |
1080 | 1072 | ||
1081 | aif1 &= ~(WM8993_BCLK_DIR | WM8993_AIF_BCLK_INV | | 1073 | aif1 &= ~(WM8993_BCLK_DIR | WM8993_AIF_BCLK_INV | |
1082 | WM8993_AIF_LRCLK_INV | WM8993_AIF_FMT_MASK); | 1074 | WM8993_AIF_LRCLK_INV | WM8993_AIF_FMT_MASK); |
@@ -1159,8 +1151,8 @@ static int wm8993_set_dai_fmt(struct snd_soc_dai *dai, | |||
1159 | return -EINVAL; | 1151 | return -EINVAL; |
1160 | } | 1152 | } |
1161 | 1153 | ||
1162 | wm8993_write(codec, WM8993_AUDIO_INTERFACE_1, aif1); | 1154 | snd_soc_write(codec, WM8993_AUDIO_INTERFACE_1, aif1); |
1163 | wm8993_write(codec, WM8993_AUDIO_INTERFACE_4, aif4); | 1155 | snd_soc_write(codec, WM8993_AUDIO_INTERFACE_4, aif4); |
1164 | 1156 | ||
1165 | return 0; | 1157 | return 0; |
1166 | } | 1158 | } |
@@ -1174,16 +1166,16 @@ static int wm8993_hw_params(struct snd_pcm_substream *substream, | |||
1174 | int ret, i, best, best_val, cur_val; | 1166 | int ret, i, best, best_val, cur_val; |
1175 | unsigned int clocking1, clocking3, aif1, aif4; | 1167 | unsigned int clocking1, clocking3, aif1, aif4; |
1176 | 1168 | ||
1177 | clocking1 = wm8993_read(codec, WM8993_CLOCKING_1); | 1169 | clocking1 = snd_soc_read(codec, WM8993_CLOCKING_1); |
1178 | clocking1 &= ~WM8993_BCLK_DIV_MASK; | 1170 | clocking1 &= ~WM8993_BCLK_DIV_MASK; |
1179 | 1171 | ||
1180 | clocking3 = wm8993_read(codec, WM8993_CLOCKING_3); | 1172 | clocking3 = snd_soc_read(codec, WM8993_CLOCKING_3); |
1181 | clocking3 &= ~(WM8993_CLK_SYS_RATE_MASK | WM8993_SAMPLE_RATE_MASK); | 1173 | clocking3 &= ~(WM8993_CLK_SYS_RATE_MASK | WM8993_SAMPLE_RATE_MASK); |
1182 | 1174 | ||
1183 | aif1 = wm8993_read(codec, WM8993_AUDIO_INTERFACE_1); | 1175 | aif1 = snd_soc_read(codec, WM8993_AUDIO_INTERFACE_1); |
1184 | aif1 &= ~WM8993_AIF_WL_MASK; | 1176 | aif1 &= ~WM8993_AIF_WL_MASK; |
1185 | 1177 | ||
1186 | aif4 = wm8993_read(codec, WM8993_AUDIO_INTERFACE_4); | 1178 | aif4 = snd_soc_read(codec, WM8993_AUDIO_INTERFACE_4); |
1187 | aif4 &= ~WM8993_LRCLK_RATE_MASK; | 1179 | aif4 &= ~WM8993_LRCLK_RATE_MASK; |
1188 | 1180 | ||
1189 | /* What BCLK do we need? */ | 1181 | /* What BCLK do we need? */ |
@@ -1276,14 +1268,14 @@ static int wm8993_hw_params(struct snd_pcm_substream *substream, | |||
1276 | dev_dbg(codec->dev, "LRCLK_RATE is %d\n", wm8993->bclk / wm8993->fs); | 1268 | dev_dbg(codec->dev, "LRCLK_RATE is %d\n", wm8993->bclk / wm8993->fs); |
1277 | aif4 |= wm8993->bclk / wm8993->fs; | 1269 | aif4 |= wm8993->bclk / wm8993->fs; |
1278 | 1270 | ||
1279 | wm8993_write(codec, WM8993_CLOCKING_1, clocking1); | 1271 | snd_soc_write(codec, WM8993_CLOCKING_1, clocking1); |
1280 | wm8993_write(codec, WM8993_CLOCKING_3, clocking3); | 1272 | snd_soc_write(codec, WM8993_CLOCKING_3, clocking3); |
1281 | wm8993_write(codec, WM8993_AUDIO_INTERFACE_1, aif1); | 1273 | snd_soc_write(codec, WM8993_AUDIO_INTERFACE_1, aif1); |
1282 | wm8993_write(codec, WM8993_AUDIO_INTERFACE_4, aif4); | 1274 | snd_soc_write(codec, WM8993_AUDIO_INTERFACE_4, aif4); |
1283 | 1275 | ||
1284 | /* ReTune Mobile? */ | 1276 | /* ReTune Mobile? */ |
1285 | if (wm8993->pdata.num_retune_configs) { | 1277 | if (wm8993->pdata.num_retune_configs) { |
1286 | u16 eq1 = wm8993_read(codec, WM8993_EQ1); | 1278 | u16 eq1 = snd_soc_read(codec, WM8993_EQ1); |
1287 | struct wm8993_retune_mobile_setting *s; | 1279 | struct wm8993_retune_mobile_setting *s; |
1288 | 1280 | ||
1289 | best = 0; | 1281 | best = 0; |
@@ -1306,7 +1298,7 @@ static int wm8993_hw_params(struct snd_pcm_substream *substream, | |||
1306 | snd_soc_update_bits(codec, WM8993_EQ1, WM8993_EQ_ENA, 0); | 1298 | snd_soc_update_bits(codec, WM8993_EQ1, WM8993_EQ_ENA, 0); |
1307 | 1299 | ||
1308 | for (i = 1; i < ARRAY_SIZE(s->config); i++) | 1300 | for (i = 1; i < ARRAY_SIZE(s->config); i++) |
1309 | wm8993_write(codec, WM8993_EQ1 + i, s->config[i]); | 1301 | snd_soc_write(codec, WM8993_EQ1 + i, s->config[i]); |
1310 | 1302 | ||
1311 | snd_soc_update_bits(codec, WM8993_EQ1, WM8993_EQ_ENA, eq1); | 1303 | snd_soc_update_bits(codec, WM8993_EQ1, WM8993_EQ_ENA, eq1); |
1312 | } | 1304 | } |
@@ -1319,14 +1311,14 @@ static int wm8993_digital_mute(struct snd_soc_dai *codec_dai, int mute) | |||
1319 | struct snd_soc_codec *codec = codec_dai->codec; | 1311 | struct snd_soc_codec *codec = codec_dai->codec; |
1320 | unsigned int reg; | 1312 | unsigned int reg; |
1321 | 1313 | ||
1322 | reg = wm8993_read(codec, WM8993_DAC_CTRL); | 1314 | reg = snd_soc_read(codec, WM8993_DAC_CTRL); |
1323 | 1315 | ||
1324 | if (mute) | 1316 | if (mute) |
1325 | reg |= WM8993_DAC_MUTE; | 1317 | reg |= WM8993_DAC_MUTE; |
1326 | else | 1318 | else |
1327 | reg &= ~WM8993_DAC_MUTE; | 1319 | reg &= ~WM8993_DAC_MUTE; |
1328 | 1320 | ||
1329 | wm8993_write(codec, WM8993_DAC_CTRL, reg); | 1321 | snd_soc_write(codec, WM8993_DAC_CTRL, reg); |
1330 | 1322 | ||
1331 | return 0; | 1323 | return 0; |
1332 | } | 1324 | } |
@@ -1480,9 +1472,66 @@ static int wm8993_remove(struct platform_device *pdev) | |||
1480 | return 0; | 1472 | return 0; |
1481 | } | 1473 | } |
1482 | 1474 | ||
1475 | #ifdef CONFIG_PM | ||
1476 | static int wm8993_suspend(struct platform_device *pdev, pm_message_t state) | ||
1477 | { | ||
1478 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1479 | struct snd_soc_codec *codec = socdev->card->codec; | ||
1480 | struct wm8993_priv *wm8993 = codec->private_data; | ||
1481 | int fll_fout = wm8993->fll_fout; | ||
1482 | int fll_fref = wm8993->fll_fref; | ||
1483 | int ret; | ||
1484 | |||
1485 | /* Stop the FLL in an orderly fashion */ | ||
1486 | ret = wm8993_set_fll(codec->dai, 0, 0, 0, 0); | ||
1487 | if (ret != 0) { | ||
1488 | dev_err(&pdev->dev, "Failed to stop FLL\n"); | ||
1489 | return ret; | ||
1490 | } | ||
1491 | |||
1492 | wm8993->fll_fout = fll_fout; | ||
1493 | wm8993->fll_fref = fll_fref; | ||
1494 | |||
1495 | wm8993_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1496 | |||
1497 | return 0; | ||
1498 | } | ||
1499 | |||
1500 | static int wm8993_resume(struct platform_device *pdev) | ||
1501 | { | ||
1502 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1503 | struct snd_soc_codec *codec = socdev->card->codec; | ||
1504 | struct wm8993_priv *wm8993 = codec->private_data; | ||
1505 | int ret; | ||
1506 | |||
1507 | wm8993_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1508 | |||
1509 | /* Restart the FLL? */ | ||
1510 | if (wm8993->fll_fout) { | ||
1511 | int fll_fout = wm8993->fll_fout; | ||
1512 | int fll_fref = wm8993->fll_fref; | ||
1513 | |||
1514 | wm8993->fll_fref = 0; | ||
1515 | wm8993->fll_fout = 0; | ||
1516 | |||
1517 | ret = wm8993_set_fll(codec->dai, 0, wm8993->fll_src, | ||
1518 | fll_fref, fll_fout); | ||
1519 | if (ret != 0) | ||
1520 | dev_err(codec->dev, "Failed to restart FLL\n"); | ||
1521 | } | ||
1522 | |||
1523 | return 0; | ||
1524 | } | ||
1525 | #else | ||
1526 | #define wm8993_suspend NULL | ||
1527 | #define wm8993_resume NULL | ||
1528 | #endif | ||
1529 | |||
1483 | struct snd_soc_codec_device soc_codec_dev_wm8993 = { | 1530 | struct snd_soc_codec_device soc_codec_dev_wm8993 = { |
1484 | .probe = wm8993_probe, | 1531 | .probe = wm8993_probe, |
1485 | .remove = wm8993_remove, | 1532 | .remove = wm8993_remove, |
1533 | .suspend = wm8993_suspend, | ||
1534 | .resume = wm8993_resume, | ||
1486 | }; | 1535 | }; |
1487 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8993); | 1536 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8993); |
1488 | 1537 | ||
@@ -1493,6 +1542,7 @@ static int wm8993_i2c_probe(struct i2c_client *i2c, | |||
1493 | struct snd_soc_codec *codec; | 1542 | struct snd_soc_codec *codec; |
1494 | unsigned int val; | 1543 | unsigned int val; |
1495 | int ret; | 1544 | int ret; |
1545 | int i; | ||
1496 | 1546 | ||
1497 | if (wm8993_codec) { | 1547 | if (wm8993_codec) { |
1498 | dev_err(&i2c->dev, "A WM8993 is already registered\n"); | 1548 | dev_err(&i2c->dev, "A WM8993 is already registered\n"); |
@@ -1513,9 +1563,7 @@ static int wm8993_i2c_probe(struct i2c_client *i2c, | |||
1513 | INIT_LIST_HEAD(&codec->dapm_paths); | 1563 | INIT_LIST_HEAD(&codec->dapm_paths); |
1514 | 1564 | ||
1515 | codec->name = "WM8993"; | 1565 | codec->name = "WM8993"; |
1516 | codec->read = wm8993_read; | 1566 | codec->volatile_register = wm8993_volatile; |
1517 | codec->write = wm8993_write; | ||
1518 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
1519 | codec->reg_cache = wm8993->reg_cache; | 1567 | codec->reg_cache = wm8993->reg_cache; |
1520 | codec->reg_cache_size = ARRAY_SIZE(wm8993->reg_cache); | 1568 | codec->reg_cache_size = ARRAY_SIZE(wm8993->reg_cache); |
1521 | codec->bias_level = SND_SOC_BIAS_OFF; | 1569 | codec->bias_level = SND_SOC_BIAS_OFF; |
@@ -1524,25 +1572,53 @@ static int wm8993_i2c_probe(struct i2c_client *i2c, | |||
1524 | codec->num_dai = 1; | 1572 | codec->num_dai = 1; |
1525 | codec->private_data = wm8993; | 1573 | codec->private_data = wm8993; |
1526 | 1574 | ||
1575 | wm8993->hubs_data.hp_startup_mode = 1; | ||
1576 | wm8993->hubs_data.dcs_codes = -2; | ||
1577 | |||
1527 | memcpy(wm8993->reg_cache, wm8993_reg_defaults, | 1578 | memcpy(wm8993->reg_cache, wm8993_reg_defaults, |
1528 | sizeof(wm8993->reg_cache)); | 1579 | sizeof(wm8993->reg_cache)); |
1529 | 1580 | ||
1581 | ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C); | ||
1582 | if (ret != 0) { | ||
1583 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); | ||
1584 | goto err; | ||
1585 | } | ||
1586 | |||
1530 | i2c_set_clientdata(i2c, wm8993); | 1587 | i2c_set_clientdata(i2c, wm8993); |
1531 | codec->control_data = i2c; | 1588 | codec->control_data = i2c; |
1532 | wm8993_codec = codec; | 1589 | wm8993_codec = codec; |
1533 | 1590 | ||
1534 | codec->dev = &i2c->dev; | 1591 | codec->dev = &i2c->dev; |
1535 | 1592 | ||
1536 | val = wm8993_read_hw(codec, WM8993_SOFTWARE_RESET); | 1593 | for (i = 0; i < ARRAY_SIZE(wm8993->supplies); i++) |
1594 | wm8993->supplies[i].supply = wm8993_supply_names[i]; | ||
1595 | |||
1596 | ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8993->supplies), | ||
1597 | wm8993->supplies); | ||
1598 | if (ret != 0) { | ||
1599 | dev_err(codec->dev, "Failed to request supplies: %d\n", ret); | ||
1600 | goto err; | ||
1601 | } | ||
1602 | |||
1603 | ret = regulator_bulk_enable(ARRAY_SIZE(wm8993->supplies), | ||
1604 | wm8993->supplies); | ||
1605 | if (ret != 0) { | ||
1606 | dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); | ||
1607 | goto err_get; | ||
1608 | } | ||
1609 | |||
1610 | val = snd_soc_read(codec, WM8993_SOFTWARE_RESET); | ||
1537 | if (val != wm8993_reg_defaults[WM8993_SOFTWARE_RESET]) { | 1611 | if (val != wm8993_reg_defaults[WM8993_SOFTWARE_RESET]) { |
1538 | dev_err(codec->dev, "Invalid ID register value %x\n", val); | 1612 | dev_err(codec->dev, "Invalid ID register value %x\n", val); |
1539 | ret = -EINVAL; | 1613 | ret = -EINVAL; |
1540 | goto err; | 1614 | goto err_enable; |
1541 | } | 1615 | } |
1542 | 1616 | ||
1543 | ret = wm8993_write(codec, WM8993_SOFTWARE_RESET, 0xffff); | 1617 | ret = snd_soc_write(codec, WM8993_SOFTWARE_RESET, 0xffff); |
1544 | if (ret != 0) | 1618 | if (ret != 0) |
1545 | goto err; | 1619 | goto err_enable; |
1620 | |||
1621 | codec->cache_only = 1; | ||
1546 | 1622 | ||
1547 | /* By default we're using the output mixers */ | 1623 | /* By default we're using the output mixers */ |
1548 | wm8993->class_w_users = 2; | 1624 | wm8993->class_w_users = 2; |
@@ -1572,7 +1648,7 @@ static int wm8993_i2c_probe(struct i2c_client *i2c, | |||
1572 | 1648 | ||
1573 | ret = wm8993_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 1649 | ret = wm8993_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
1574 | if (ret != 0) | 1650 | if (ret != 0) |
1575 | goto err; | 1651 | goto err_enable; |
1576 | 1652 | ||
1577 | wm8993_dai.dev = codec->dev; | 1653 | wm8993_dai.dev = codec->dev; |
1578 | 1654 | ||
@@ -1586,6 +1662,10 @@ static int wm8993_i2c_probe(struct i2c_client *i2c, | |||
1586 | 1662 | ||
1587 | err_bias: | 1663 | err_bias: |
1588 | wm8993_set_bias_level(codec, SND_SOC_BIAS_OFF); | 1664 | wm8993_set_bias_level(codec, SND_SOC_BIAS_OFF); |
1665 | err_enable: | ||
1666 | regulator_bulk_disable(ARRAY_SIZE(wm8993->supplies), wm8993->supplies); | ||
1667 | err_get: | ||
1668 | regulator_bulk_free(ARRAY_SIZE(wm8993->supplies), wm8993->supplies); | ||
1589 | err: | 1669 | err: |
1590 | wm8993_codec = NULL; | 1670 | wm8993_codec = NULL; |
1591 | kfree(wm8993); | 1671 | kfree(wm8993); |
@@ -1600,6 +1680,7 @@ static int wm8993_i2c_remove(struct i2c_client *client) | |||
1600 | snd_soc_unregister_dai(&wm8993_dai); | 1680 | snd_soc_unregister_dai(&wm8993_dai); |
1601 | 1681 | ||
1602 | wm8993_set_bias_level(&wm8993->codec, SND_SOC_BIAS_OFF); | 1682 | wm8993_set_bias_level(&wm8993->codec, SND_SOC_BIAS_OFF); |
1683 | regulator_bulk_free(ARRAY_SIZE(wm8993->supplies), wm8993->supplies); | ||
1603 | kfree(wm8993); | 1684 | kfree(wm8993); |
1604 | 1685 | ||
1605 | return 0; | 1686 | return 0; |
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c new file mode 100644 index 000000000000..29f3771c33a4 --- /dev/null +++ b/sound/soc/codecs/wm8994.c | |||
@@ -0,0 +1,3867 @@ | |||
1 | /* | ||
2 | * wm8994.c -- WM8994 ALSA SoC Audio driver | ||
3 | * | ||
4 | * Copyright 2009 Wolfson Microelectronics plc | ||
5 | * | ||
6 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | ||
7 | * | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/moduleparam.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/delay.h> | ||
18 | #include <linux/pm.h> | ||
19 | #include <linux/i2c.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <linux/regulator/consumer.h> | ||
22 | #include <sound/core.h> | ||
23 | #include <sound/pcm.h> | ||
24 | #include <sound/pcm_params.h> | ||
25 | #include <sound/soc.h> | ||
26 | #include <sound/soc-dapm.h> | ||
27 | #include <sound/initval.h> | ||
28 | #include <sound/tlv.h> | ||
29 | |||
30 | #include <linux/mfd/wm8994/core.h> | ||
31 | #include <linux/mfd/wm8994/registers.h> | ||
32 | #include <linux/mfd/wm8994/pdata.h> | ||
33 | #include <linux/mfd/wm8994/gpio.h> | ||
34 | |||
35 | #include "wm8994.h" | ||
36 | #include "wm_hubs.h" | ||
37 | |||
38 | static struct snd_soc_codec *wm8994_codec; | ||
39 | struct snd_soc_codec_device soc_codec_dev_wm8994; | ||
40 | |||
41 | struct fll_config { | ||
42 | int src; | ||
43 | int in; | ||
44 | int out; | ||
45 | }; | ||
46 | |||
47 | #define WM8994_NUM_DRC 3 | ||
48 | #define WM8994_NUM_EQ 3 | ||
49 | |||
50 | static int wm8994_drc_base[] = { | ||
51 | WM8994_AIF1_DRC1_1, | ||
52 | WM8994_AIF1_DRC2_1, | ||
53 | WM8994_AIF2_DRC_1, | ||
54 | }; | ||
55 | |||
56 | static int wm8994_retune_mobile_base[] = { | ||
57 | WM8994_AIF1_DAC1_EQ_GAINS_1, | ||
58 | WM8994_AIF1_DAC2_EQ_GAINS_1, | ||
59 | WM8994_AIF2_EQ_GAINS_1, | ||
60 | }; | ||
61 | |||
62 | #define WM8994_REG_CACHE_SIZE 0x621 | ||
63 | |||
64 | /* codec private data */ | ||
65 | struct wm8994_priv { | ||
66 | struct wm_hubs_data hubs; | ||
67 | struct snd_soc_codec codec; | ||
68 | u16 reg_cache[WM8994_REG_CACHE_SIZE + 1]; | ||
69 | int sysclk[2]; | ||
70 | int sysclk_rate[2]; | ||
71 | int mclk[2]; | ||
72 | int aifclk[2]; | ||
73 | struct fll_config fll[2], fll_suspend[2]; | ||
74 | |||
75 | int dac_rates[2]; | ||
76 | int lrclk_shared[2]; | ||
77 | |||
78 | /* Platform dependant DRC configuration */ | ||
79 | const char **drc_texts; | ||
80 | int drc_cfg[WM8994_NUM_DRC]; | ||
81 | struct soc_enum drc_enum; | ||
82 | |||
83 | /* Platform dependant ReTune mobile configuration */ | ||
84 | int num_retune_mobile_texts; | ||
85 | const char **retune_mobile_texts; | ||
86 | int retune_mobile_cfg[WM8994_NUM_EQ]; | ||
87 | struct soc_enum retune_mobile_enum; | ||
88 | |||
89 | struct wm8994_pdata *pdata; | ||
90 | }; | ||
91 | |||
92 | static struct { | ||
93 | unsigned short readable; /* Mask of readable bits */ | ||
94 | unsigned short writable; /* Mask of writable bits */ | ||
95 | unsigned short vol; /* Mask of volatile bits */ | ||
96 | } access_masks[] = { | ||
97 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R0 - Software Reset */ | ||
98 | { 0x3B37, 0x3B37, 0x0000 }, /* R1 - Power Management (1) */ | ||
99 | { 0x6BF0, 0x6BF0, 0x0000 }, /* R2 - Power Management (2) */ | ||
100 | { 0x3FF0, 0x3FF0, 0x0000 }, /* R3 - Power Management (3) */ | ||
101 | { 0x3F3F, 0x3F3F, 0x0000 }, /* R4 - Power Management (4) */ | ||
102 | { 0x3F0F, 0x3F0F, 0x0000 }, /* R5 - Power Management (5) */ | ||
103 | { 0x003F, 0x003F, 0x0000 }, /* R6 - Power Management (6) */ | ||
104 | { 0x0000, 0x0000, 0x0000 }, /* R7 */ | ||
105 | { 0x0000, 0x0000, 0x0000 }, /* R8 */ | ||
106 | { 0x0000, 0x0000, 0x0000 }, /* R9 */ | ||
107 | { 0x0000, 0x0000, 0x0000 }, /* R10 */ | ||
108 | { 0x0000, 0x0000, 0x0000 }, /* R11 */ | ||
109 | { 0x0000, 0x0000, 0x0000 }, /* R12 */ | ||
110 | { 0x0000, 0x0000, 0x0000 }, /* R13 */ | ||
111 | { 0x0000, 0x0000, 0x0000 }, /* R14 */ | ||
112 | { 0x0000, 0x0000, 0x0000 }, /* R15 */ | ||
113 | { 0x0000, 0x0000, 0x0000 }, /* R16 */ | ||
114 | { 0x0000, 0x0000, 0x0000 }, /* R17 */ | ||
115 | { 0x0000, 0x0000, 0x0000 }, /* R18 */ | ||
116 | { 0x0000, 0x0000, 0x0000 }, /* R19 */ | ||
117 | { 0x0000, 0x0000, 0x0000 }, /* R20 */ | ||
118 | { 0x01C0, 0x01C0, 0x0000 }, /* R21 - Input Mixer (1) */ | ||
119 | { 0x0000, 0x0000, 0x0000 }, /* R22 */ | ||
120 | { 0x0000, 0x0000, 0x0000 }, /* R23 */ | ||
121 | { 0x00DF, 0x01DF, 0x0000 }, /* R24 - Left Line Input 1&2 Volume */ | ||
122 | { 0x00DF, 0x01DF, 0x0000 }, /* R25 - Left Line Input 3&4 Volume */ | ||
123 | { 0x00DF, 0x01DF, 0x0000 }, /* R26 - Right Line Input 1&2 Volume */ | ||
124 | { 0x00DF, 0x01DF, 0x0000 }, /* R27 - Right Line Input 3&4 Volume */ | ||
125 | { 0x00FF, 0x01FF, 0x0000 }, /* R28 - Left Output Volume */ | ||
126 | { 0x00FF, 0x01FF, 0x0000 }, /* R29 - Right Output Volume */ | ||
127 | { 0x0077, 0x0077, 0x0000 }, /* R30 - Line Outputs Volume */ | ||
128 | { 0x0030, 0x0030, 0x0000 }, /* R31 - HPOUT2 Volume */ | ||
129 | { 0x00FF, 0x01FF, 0x0000 }, /* R32 - Left OPGA Volume */ | ||
130 | { 0x00FF, 0x01FF, 0x0000 }, /* R33 - Right OPGA Volume */ | ||
131 | { 0x007F, 0x007F, 0x0000 }, /* R34 - SPKMIXL Attenuation */ | ||
132 | { 0x017F, 0x017F, 0x0000 }, /* R35 - SPKMIXR Attenuation */ | ||
133 | { 0x003F, 0x003F, 0x0000 }, /* R36 - SPKOUT Mixers */ | ||
134 | { 0x003F, 0x003F, 0x0000 }, /* R37 - ClassD */ | ||
135 | { 0x00FF, 0x01FF, 0x0000 }, /* R38 - Speaker Volume Left */ | ||
136 | { 0x00FF, 0x01FF, 0x0000 }, /* R39 - Speaker Volume Right */ | ||
137 | { 0x00FF, 0x00FF, 0x0000 }, /* R40 - Input Mixer (2) */ | ||
138 | { 0x01B7, 0x01B7, 0x0000 }, /* R41 - Input Mixer (3) */ | ||
139 | { 0x01B7, 0x01B7, 0x0000 }, /* R42 - Input Mixer (4) */ | ||
140 | { 0x01C7, 0x01C7, 0x0000 }, /* R43 - Input Mixer (5) */ | ||
141 | { 0x01C7, 0x01C7, 0x0000 }, /* R44 - Input Mixer (6) */ | ||
142 | { 0x01FF, 0x01FF, 0x0000 }, /* R45 - Output Mixer (1) */ | ||
143 | { 0x01FF, 0x01FF, 0x0000 }, /* R46 - Output Mixer (2) */ | ||
144 | { 0x0FFF, 0x0FFF, 0x0000 }, /* R47 - Output Mixer (3) */ | ||
145 | { 0x0FFF, 0x0FFF, 0x0000 }, /* R48 - Output Mixer (4) */ | ||
146 | { 0x0FFF, 0x0FFF, 0x0000 }, /* R49 - Output Mixer (5) */ | ||
147 | { 0x0FFF, 0x0FFF, 0x0000 }, /* R50 - Output Mixer (6) */ | ||
148 | { 0x0038, 0x0038, 0x0000 }, /* R51 - HPOUT2 Mixer */ | ||
149 | { 0x0077, 0x0077, 0x0000 }, /* R52 - Line Mixer (1) */ | ||
150 | { 0x0077, 0x0077, 0x0000 }, /* R53 - Line Mixer (2) */ | ||
151 | { 0x03FF, 0x03FF, 0x0000 }, /* R54 - Speaker Mixer */ | ||
152 | { 0x00C1, 0x00C1, 0x0000 }, /* R55 - Additional Control */ | ||
153 | { 0x00F0, 0x00F0, 0x0000 }, /* R56 - AntiPOP (1) */ | ||
154 | { 0x01EF, 0x01EF, 0x0000 }, /* R57 - AntiPOP (2) */ | ||
155 | { 0x00FF, 0x00FF, 0x0000 }, /* R58 - MICBIAS */ | ||
156 | { 0x000F, 0x000F, 0x0000 }, /* R59 - LDO 1 */ | ||
157 | { 0x0007, 0x0007, 0x0000 }, /* R60 - LDO 2 */ | ||
158 | { 0x0000, 0x0000, 0x0000 }, /* R61 */ | ||
159 | { 0x0000, 0x0000, 0x0000 }, /* R62 */ | ||
160 | { 0x0000, 0x0000, 0x0000 }, /* R63 */ | ||
161 | { 0x0000, 0x0000, 0x0000 }, /* R64 */ | ||
162 | { 0x0000, 0x0000, 0x0000 }, /* R65 */ | ||
163 | { 0x0000, 0x0000, 0x0000 }, /* R66 */ | ||
164 | { 0x0000, 0x0000, 0x0000 }, /* R67 */ | ||
165 | { 0x0000, 0x0000, 0x0000 }, /* R68 */ | ||
166 | { 0x0000, 0x0000, 0x0000 }, /* R69 */ | ||
167 | { 0x0000, 0x0000, 0x0000 }, /* R70 */ | ||
168 | { 0x0000, 0x0000, 0x0000 }, /* R71 */ | ||
169 | { 0x0000, 0x0000, 0x0000 }, /* R72 */ | ||
170 | { 0x0000, 0x0000, 0x0000 }, /* R73 */ | ||
171 | { 0x0000, 0x0000, 0x0000 }, /* R74 */ | ||
172 | { 0x0000, 0x0000, 0x0000 }, /* R75 */ | ||
173 | { 0x8000, 0x8000, 0x0000 }, /* R76 - Charge Pump (1) */ | ||
174 | { 0x0000, 0x0000, 0x0000 }, /* R77 */ | ||
175 | { 0x0000, 0x0000, 0x0000 }, /* R78 */ | ||
176 | { 0x0000, 0x0000, 0x0000 }, /* R79 */ | ||
177 | { 0x0000, 0x0000, 0x0000 }, /* R80 */ | ||
178 | { 0x0301, 0x0301, 0x0000 }, /* R81 - Class W (1) */ | ||
179 | { 0x0000, 0x0000, 0x0000 }, /* R82 */ | ||
180 | { 0x0000, 0x0000, 0x0000 }, /* R83 */ | ||
181 | { 0x333F, 0x333F, 0x0000 }, /* R84 - DC Servo (1) */ | ||
182 | { 0x0FEF, 0x0FEF, 0x0000 }, /* R85 - DC Servo (2) */ | ||
183 | { 0x0000, 0x0000, 0x0000 }, /* R86 */ | ||
184 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R87 - DC Servo (4) */ | ||
185 | { 0x0333, 0x0000, 0x0000 }, /* R88 - DC Servo Readback */ | ||
186 | { 0x0000, 0x0000, 0x0000 }, /* R89 */ | ||
187 | { 0x0000, 0x0000, 0x0000 }, /* R90 */ | ||
188 | { 0x0000, 0x0000, 0x0000 }, /* R91 */ | ||
189 | { 0x0000, 0x0000, 0x0000 }, /* R92 */ | ||
190 | { 0x0000, 0x0000, 0x0000 }, /* R93 */ | ||
191 | { 0x0000, 0x0000, 0x0000 }, /* R94 */ | ||
192 | { 0x0000, 0x0000, 0x0000 }, /* R95 */ | ||
193 | { 0x00EE, 0x00EE, 0x0000 }, /* R96 - Analogue HP (1) */ | ||
194 | { 0x0000, 0x0000, 0x0000 }, /* R97 */ | ||
195 | { 0x0000, 0x0000, 0x0000 }, /* R98 */ | ||
196 | { 0x0000, 0x0000, 0x0000 }, /* R99 */ | ||
197 | { 0x0000, 0x0000, 0x0000 }, /* R100 */ | ||
198 | { 0x0000, 0x0000, 0x0000 }, /* R101 */ | ||
199 | { 0x0000, 0x0000, 0x0000 }, /* R102 */ | ||
200 | { 0x0000, 0x0000, 0x0000 }, /* R103 */ | ||
201 | { 0x0000, 0x0000, 0x0000 }, /* R104 */ | ||
202 | { 0x0000, 0x0000, 0x0000 }, /* R105 */ | ||
203 | { 0x0000, 0x0000, 0x0000 }, /* R106 */ | ||
204 | { 0x0000, 0x0000, 0x0000 }, /* R107 */ | ||
205 | { 0x0000, 0x0000, 0x0000 }, /* R108 */ | ||
206 | { 0x0000, 0x0000, 0x0000 }, /* R109 */ | ||
207 | { 0x0000, 0x0000, 0x0000 }, /* R110 */ | ||
208 | { 0x0000, 0x0000, 0x0000 }, /* R111 */ | ||
209 | { 0x0000, 0x0000, 0x0000 }, /* R112 */ | ||
210 | { 0x0000, 0x0000, 0x0000 }, /* R113 */ | ||
211 | { 0x0000, 0x0000, 0x0000 }, /* R114 */ | ||
212 | { 0x0000, 0x0000, 0x0000 }, /* R115 */ | ||
213 | { 0x0000, 0x0000, 0x0000 }, /* R116 */ | ||
214 | { 0x0000, 0x0000, 0x0000 }, /* R117 */ | ||
215 | { 0x0000, 0x0000, 0x0000 }, /* R118 */ | ||
216 | { 0x0000, 0x0000, 0x0000 }, /* R119 */ | ||
217 | { 0x0000, 0x0000, 0x0000 }, /* R120 */ | ||
218 | { 0x0000, 0x0000, 0x0000 }, /* R121 */ | ||
219 | { 0x0000, 0x0000, 0x0000 }, /* R122 */ | ||
220 | { 0x0000, 0x0000, 0x0000 }, /* R123 */ | ||
221 | { 0x0000, 0x0000, 0x0000 }, /* R124 */ | ||
222 | { 0x0000, 0x0000, 0x0000 }, /* R125 */ | ||
223 | { 0x0000, 0x0000, 0x0000 }, /* R126 */ | ||
224 | { 0x0000, 0x0000, 0x0000 }, /* R127 */ | ||
225 | { 0x0000, 0x0000, 0x0000 }, /* R128 */ | ||
226 | { 0x0000, 0x0000, 0x0000 }, /* R129 */ | ||
227 | { 0x0000, 0x0000, 0x0000 }, /* R130 */ | ||
228 | { 0x0000, 0x0000, 0x0000 }, /* R131 */ | ||
229 | { 0x0000, 0x0000, 0x0000 }, /* R132 */ | ||
230 | { 0x0000, 0x0000, 0x0000 }, /* R133 */ | ||
231 | { 0x0000, 0x0000, 0x0000 }, /* R134 */ | ||
232 | { 0x0000, 0x0000, 0x0000 }, /* R135 */ | ||
233 | { 0x0000, 0x0000, 0x0000 }, /* R136 */ | ||
234 | { 0x0000, 0x0000, 0x0000 }, /* R137 */ | ||
235 | { 0x0000, 0x0000, 0x0000 }, /* R138 */ | ||
236 | { 0x0000, 0x0000, 0x0000 }, /* R139 */ | ||
237 | { 0x0000, 0x0000, 0x0000 }, /* R140 */ | ||
238 | { 0x0000, 0x0000, 0x0000 }, /* R141 */ | ||
239 | { 0x0000, 0x0000, 0x0000 }, /* R142 */ | ||
240 | { 0x0000, 0x0000, 0x0000 }, /* R143 */ | ||
241 | { 0x0000, 0x0000, 0x0000 }, /* R144 */ | ||
242 | { 0x0000, 0x0000, 0x0000 }, /* R145 */ | ||
243 | { 0x0000, 0x0000, 0x0000 }, /* R146 */ | ||
244 | { 0x0000, 0x0000, 0x0000 }, /* R147 */ | ||
245 | { 0x0000, 0x0000, 0x0000 }, /* R148 */ | ||
246 | { 0x0000, 0x0000, 0x0000 }, /* R149 */ | ||
247 | { 0x0000, 0x0000, 0x0000 }, /* R150 */ | ||
248 | { 0x0000, 0x0000, 0x0000 }, /* R151 */ | ||
249 | { 0x0000, 0x0000, 0x0000 }, /* R152 */ | ||
250 | { 0x0000, 0x0000, 0x0000 }, /* R153 */ | ||
251 | { 0x0000, 0x0000, 0x0000 }, /* R154 */ | ||
252 | { 0x0000, 0x0000, 0x0000 }, /* R155 */ | ||
253 | { 0x0000, 0x0000, 0x0000 }, /* R156 */ | ||
254 | { 0x0000, 0x0000, 0x0000 }, /* R157 */ | ||
255 | { 0x0000, 0x0000, 0x0000 }, /* R158 */ | ||
256 | { 0x0000, 0x0000, 0x0000 }, /* R159 */ | ||
257 | { 0x0000, 0x0000, 0x0000 }, /* R160 */ | ||
258 | { 0x0000, 0x0000, 0x0000 }, /* R161 */ | ||
259 | { 0x0000, 0x0000, 0x0000 }, /* R162 */ | ||
260 | { 0x0000, 0x0000, 0x0000 }, /* R163 */ | ||
261 | { 0x0000, 0x0000, 0x0000 }, /* R164 */ | ||
262 | { 0x0000, 0x0000, 0x0000 }, /* R165 */ | ||
263 | { 0x0000, 0x0000, 0x0000 }, /* R166 */ | ||
264 | { 0x0000, 0x0000, 0x0000 }, /* R167 */ | ||
265 | { 0x0000, 0x0000, 0x0000 }, /* R168 */ | ||
266 | { 0x0000, 0x0000, 0x0000 }, /* R169 */ | ||
267 | { 0x0000, 0x0000, 0x0000 }, /* R170 */ | ||
268 | { 0x0000, 0x0000, 0x0000 }, /* R171 */ | ||
269 | { 0x0000, 0x0000, 0x0000 }, /* R172 */ | ||
270 | { 0x0000, 0x0000, 0x0000 }, /* R173 */ | ||
271 | { 0x0000, 0x0000, 0x0000 }, /* R174 */ | ||
272 | { 0x0000, 0x0000, 0x0000 }, /* R175 */ | ||
273 | { 0x0000, 0x0000, 0x0000 }, /* R176 */ | ||
274 | { 0x0000, 0x0000, 0x0000 }, /* R177 */ | ||
275 | { 0x0000, 0x0000, 0x0000 }, /* R178 */ | ||
276 | { 0x0000, 0x0000, 0x0000 }, /* R179 */ | ||
277 | { 0x0000, 0x0000, 0x0000 }, /* R180 */ | ||
278 | { 0x0000, 0x0000, 0x0000 }, /* R181 */ | ||
279 | { 0x0000, 0x0000, 0x0000 }, /* R182 */ | ||
280 | { 0x0000, 0x0000, 0x0000 }, /* R183 */ | ||
281 | { 0x0000, 0x0000, 0x0000 }, /* R184 */ | ||
282 | { 0x0000, 0x0000, 0x0000 }, /* R185 */ | ||
283 | { 0x0000, 0x0000, 0x0000 }, /* R186 */ | ||
284 | { 0x0000, 0x0000, 0x0000 }, /* R187 */ | ||
285 | { 0x0000, 0x0000, 0x0000 }, /* R188 */ | ||
286 | { 0x0000, 0x0000, 0x0000 }, /* R189 */ | ||
287 | { 0x0000, 0x0000, 0x0000 }, /* R190 */ | ||
288 | { 0x0000, 0x0000, 0x0000 }, /* R191 */ | ||
289 | { 0x0000, 0x0000, 0x0000 }, /* R192 */ | ||
290 | { 0x0000, 0x0000, 0x0000 }, /* R193 */ | ||
291 | { 0x0000, 0x0000, 0x0000 }, /* R194 */ | ||
292 | { 0x0000, 0x0000, 0x0000 }, /* R195 */ | ||
293 | { 0x0000, 0x0000, 0x0000 }, /* R196 */ | ||
294 | { 0x0000, 0x0000, 0x0000 }, /* R197 */ | ||
295 | { 0x0000, 0x0000, 0x0000 }, /* R198 */ | ||
296 | { 0x0000, 0x0000, 0x0000 }, /* R199 */ | ||
297 | { 0x0000, 0x0000, 0x0000 }, /* R200 */ | ||
298 | { 0x0000, 0x0000, 0x0000 }, /* R201 */ | ||
299 | { 0x0000, 0x0000, 0x0000 }, /* R202 */ | ||
300 | { 0x0000, 0x0000, 0x0000 }, /* R203 */ | ||
301 | { 0x0000, 0x0000, 0x0000 }, /* R204 */ | ||
302 | { 0x0000, 0x0000, 0x0000 }, /* R205 */ | ||
303 | { 0x0000, 0x0000, 0x0000 }, /* R206 */ | ||
304 | { 0x0000, 0x0000, 0x0000 }, /* R207 */ | ||
305 | { 0x0000, 0x0000, 0x0000 }, /* R208 */ | ||
306 | { 0x0000, 0x0000, 0x0000 }, /* R209 */ | ||
307 | { 0x0000, 0x0000, 0x0000 }, /* R210 */ | ||
308 | { 0x0000, 0x0000, 0x0000 }, /* R211 */ | ||
309 | { 0x0000, 0x0000, 0x0000 }, /* R212 */ | ||
310 | { 0x0000, 0x0000, 0x0000 }, /* R213 */ | ||
311 | { 0x0000, 0x0000, 0x0000 }, /* R214 */ | ||
312 | { 0x0000, 0x0000, 0x0000 }, /* R215 */ | ||
313 | { 0x0000, 0x0000, 0x0000 }, /* R216 */ | ||
314 | { 0x0000, 0x0000, 0x0000 }, /* R217 */ | ||
315 | { 0x0000, 0x0000, 0x0000 }, /* R218 */ | ||
316 | { 0x0000, 0x0000, 0x0000 }, /* R219 */ | ||
317 | { 0x0000, 0x0000, 0x0000 }, /* R220 */ | ||
318 | { 0x0000, 0x0000, 0x0000 }, /* R221 */ | ||
319 | { 0x0000, 0x0000, 0x0000 }, /* R222 */ | ||
320 | { 0x0000, 0x0000, 0x0000 }, /* R223 */ | ||
321 | { 0x0000, 0x0000, 0x0000 }, /* R224 */ | ||
322 | { 0x0000, 0x0000, 0x0000 }, /* R225 */ | ||
323 | { 0x0000, 0x0000, 0x0000 }, /* R226 */ | ||
324 | { 0x0000, 0x0000, 0x0000 }, /* R227 */ | ||
325 | { 0x0000, 0x0000, 0x0000 }, /* R228 */ | ||
326 | { 0x0000, 0x0000, 0x0000 }, /* R229 */ | ||
327 | { 0x0000, 0x0000, 0x0000 }, /* R230 */ | ||
328 | { 0x0000, 0x0000, 0x0000 }, /* R231 */ | ||
329 | { 0x0000, 0x0000, 0x0000 }, /* R232 */ | ||
330 | { 0x0000, 0x0000, 0x0000 }, /* R233 */ | ||
331 | { 0x0000, 0x0000, 0x0000 }, /* R234 */ | ||
332 | { 0x0000, 0x0000, 0x0000 }, /* R235 */ | ||
333 | { 0x0000, 0x0000, 0x0000 }, /* R236 */ | ||
334 | { 0x0000, 0x0000, 0x0000 }, /* R237 */ | ||
335 | { 0x0000, 0x0000, 0x0000 }, /* R238 */ | ||
336 | { 0x0000, 0x0000, 0x0000 }, /* R239 */ | ||
337 | { 0x0000, 0x0000, 0x0000 }, /* R240 */ | ||
338 | { 0x0000, 0x0000, 0x0000 }, /* R241 */ | ||
339 | { 0x0000, 0x0000, 0x0000 }, /* R242 */ | ||
340 | { 0x0000, 0x0000, 0x0000 }, /* R243 */ | ||
341 | { 0x0000, 0x0000, 0x0000 }, /* R244 */ | ||
342 | { 0x0000, 0x0000, 0x0000 }, /* R245 */ | ||
343 | { 0x0000, 0x0000, 0x0000 }, /* R246 */ | ||
344 | { 0x0000, 0x0000, 0x0000 }, /* R247 */ | ||
345 | { 0x0000, 0x0000, 0x0000 }, /* R248 */ | ||
346 | { 0x0000, 0x0000, 0x0000 }, /* R249 */ | ||
347 | { 0x0000, 0x0000, 0x0000 }, /* R250 */ | ||
348 | { 0x0000, 0x0000, 0x0000 }, /* R251 */ | ||
349 | { 0x0000, 0x0000, 0x0000 }, /* R252 */ | ||
350 | { 0x0000, 0x0000, 0x0000 }, /* R253 */ | ||
351 | { 0x0000, 0x0000, 0x0000 }, /* R254 */ | ||
352 | { 0x0000, 0x0000, 0x0000 }, /* R255 */ | ||
353 | { 0x000F, 0x0000, 0x0000 }, /* R256 - Chip Revision */ | ||
354 | { 0x0074, 0x0074, 0x0000 }, /* R257 - Control Interface */ | ||
355 | { 0x0000, 0x0000, 0x0000 }, /* R258 */ | ||
356 | { 0x0000, 0x0000, 0x0000 }, /* R259 */ | ||
357 | { 0x0000, 0x0000, 0x0000 }, /* R260 */ | ||
358 | { 0x0000, 0x0000, 0x0000 }, /* R261 */ | ||
359 | { 0x0000, 0x0000, 0x0000 }, /* R262 */ | ||
360 | { 0x0000, 0x0000, 0x0000 }, /* R263 */ | ||
361 | { 0x0000, 0x0000, 0x0000 }, /* R264 */ | ||
362 | { 0x0000, 0x0000, 0x0000 }, /* R265 */ | ||
363 | { 0x0000, 0x0000, 0x0000 }, /* R266 */ | ||
364 | { 0x0000, 0x0000, 0x0000 }, /* R267 */ | ||
365 | { 0x0000, 0x0000, 0x0000 }, /* R268 */ | ||
366 | { 0x0000, 0x0000, 0x0000 }, /* R269 */ | ||
367 | { 0x0000, 0x0000, 0x0000 }, /* R270 */ | ||
368 | { 0x0000, 0x0000, 0x0000 }, /* R271 */ | ||
369 | { 0x807F, 0x837F, 0x0000 }, /* R272 - Write Sequencer Ctrl (1) */ | ||
370 | { 0x017F, 0x0000, 0x0000 }, /* R273 - Write Sequencer Ctrl (2) */ | ||
371 | { 0x0000, 0x0000, 0x0000 }, /* R274 */ | ||
372 | { 0x0000, 0x0000, 0x0000 }, /* R275 */ | ||
373 | { 0x0000, 0x0000, 0x0000 }, /* R276 */ | ||
374 | { 0x0000, 0x0000, 0x0000 }, /* R277 */ | ||
375 | { 0x0000, 0x0000, 0x0000 }, /* R278 */ | ||
376 | { 0x0000, 0x0000, 0x0000 }, /* R279 */ | ||
377 | { 0x0000, 0x0000, 0x0000 }, /* R280 */ | ||
378 | { 0x0000, 0x0000, 0x0000 }, /* R281 */ | ||
379 | { 0x0000, 0x0000, 0x0000 }, /* R282 */ | ||
380 | { 0x0000, 0x0000, 0x0000 }, /* R283 */ | ||
381 | { 0x0000, 0x0000, 0x0000 }, /* R284 */ | ||
382 | { 0x0000, 0x0000, 0x0000 }, /* R285 */ | ||
383 | { 0x0000, 0x0000, 0x0000 }, /* R286 */ | ||
384 | { 0x0000, 0x0000, 0x0000 }, /* R287 */ | ||
385 | { 0x0000, 0x0000, 0x0000 }, /* R288 */ | ||
386 | { 0x0000, 0x0000, 0x0000 }, /* R289 */ | ||
387 | { 0x0000, 0x0000, 0x0000 }, /* R290 */ | ||
388 | { 0x0000, 0x0000, 0x0000 }, /* R291 */ | ||
389 | { 0x0000, 0x0000, 0x0000 }, /* R292 */ | ||
390 | { 0x0000, 0x0000, 0x0000 }, /* R293 */ | ||
391 | { 0x0000, 0x0000, 0x0000 }, /* R294 */ | ||
392 | { 0x0000, 0x0000, 0x0000 }, /* R295 */ | ||
393 | { 0x0000, 0x0000, 0x0000 }, /* R296 */ | ||
394 | { 0x0000, 0x0000, 0x0000 }, /* R297 */ | ||
395 | { 0x0000, 0x0000, 0x0000 }, /* R298 */ | ||
396 | { 0x0000, 0x0000, 0x0000 }, /* R299 */ | ||
397 | { 0x0000, 0x0000, 0x0000 }, /* R300 */ | ||
398 | { 0x0000, 0x0000, 0x0000 }, /* R301 */ | ||
399 | { 0x0000, 0x0000, 0x0000 }, /* R302 */ | ||
400 | { 0x0000, 0x0000, 0x0000 }, /* R303 */ | ||
401 | { 0x0000, 0x0000, 0x0000 }, /* R304 */ | ||
402 | { 0x0000, 0x0000, 0x0000 }, /* R305 */ | ||
403 | { 0x0000, 0x0000, 0x0000 }, /* R306 */ | ||
404 | { 0x0000, 0x0000, 0x0000 }, /* R307 */ | ||
405 | { 0x0000, 0x0000, 0x0000 }, /* R308 */ | ||
406 | { 0x0000, 0x0000, 0x0000 }, /* R309 */ | ||
407 | { 0x0000, 0x0000, 0x0000 }, /* R310 */ | ||
408 | { 0x0000, 0x0000, 0x0000 }, /* R311 */ | ||
409 | { 0x0000, 0x0000, 0x0000 }, /* R312 */ | ||
410 | { 0x0000, 0x0000, 0x0000 }, /* R313 */ | ||
411 | { 0x0000, 0x0000, 0x0000 }, /* R314 */ | ||
412 | { 0x0000, 0x0000, 0x0000 }, /* R315 */ | ||
413 | { 0x0000, 0x0000, 0x0000 }, /* R316 */ | ||
414 | { 0x0000, 0x0000, 0x0000 }, /* R317 */ | ||
415 | { 0x0000, 0x0000, 0x0000 }, /* R318 */ | ||
416 | { 0x0000, 0x0000, 0x0000 }, /* R319 */ | ||
417 | { 0x0000, 0x0000, 0x0000 }, /* R320 */ | ||
418 | { 0x0000, 0x0000, 0x0000 }, /* R321 */ | ||
419 | { 0x0000, 0x0000, 0x0000 }, /* R322 */ | ||
420 | { 0x0000, 0x0000, 0x0000 }, /* R323 */ | ||
421 | { 0x0000, 0x0000, 0x0000 }, /* R324 */ | ||
422 | { 0x0000, 0x0000, 0x0000 }, /* R325 */ | ||
423 | { 0x0000, 0x0000, 0x0000 }, /* R326 */ | ||
424 | { 0x0000, 0x0000, 0x0000 }, /* R327 */ | ||
425 | { 0x0000, 0x0000, 0x0000 }, /* R328 */ | ||
426 | { 0x0000, 0x0000, 0x0000 }, /* R329 */ | ||
427 | { 0x0000, 0x0000, 0x0000 }, /* R330 */ | ||
428 | { 0x0000, 0x0000, 0x0000 }, /* R331 */ | ||
429 | { 0x0000, 0x0000, 0x0000 }, /* R332 */ | ||
430 | { 0x0000, 0x0000, 0x0000 }, /* R333 */ | ||
431 | { 0x0000, 0x0000, 0x0000 }, /* R334 */ | ||
432 | { 0x0000, 0x0000, 0x0000 }, /* R335 */ | ||
433 | { 0x0000, 0x0000, 0x0000 }, /* R336 */ | ||
434 | { 0x0000, 0x0000, 0x0000 }, /* R337 */ | ||
435 | { 0x0000, 0x0000, 0x0000 }, /* R338 */ | ||
436 | { 0x0000, 0x0000, 0x0000 }, /* R339 */ | ||
437 | { 0x0000, 0x0000, 0x0000 }, /* R340 */ | ||
438 | { 0x0000, 0x0000, 0x0000 }, /* R341 */ | ||
439 | { 0x0000, 0x0000, 0x0000 }, /* R342 */ | ||
440 | { 0x0000, 0x0000, 0x0000 }, /* R343 */ | ||
441 | { 0x0000, 0x0000, 0x0000 }, /* R344 */ | ||
442 | { 0x0000, 0x0000, 0x0000 }, /* R345 */ | ||
443 | { 0x0000, 0x0000, 0x0000 }, /* R346 */ | ||
444 | { 0x0000, 0x0000, 0x0000 }, /* R347 */ | ||
445 | { 0x0000, 0x0000, 0x0000 }, /* R348 */ | ||
446 | { 0x0000, 0x0000, 0x0000 }, /* R349 */ | ||
447 | { 0x0000, 0x0000, 0x0000 }, /* R350 */ | ||
448 | { 0x0000, 0x0000, 0x0000 }, /* R351 */ | ||
449 | { 0x0000, 0x0000, 0x0000 }, /* R352 */ | ||
450 | { 0x0000, 0x0000, 0x0000 }, /* R353 */ | ||
451 | { 0x0000, 0x0000, 0x0000 }, /* R354 */ | ||
452 | { 0x0000, 0x0000, 0x0000 }, /* R355 */ | ||
453 | { 0x0000, 0x0000, 0x0000 }, /* R356 */ | ||
454 | { 0x0000, 0x0000, 0x0000 }, /* R357 */ | ||
455 | { 0x0000, 0x0000, 0x0000 }, /* R358 */ | ||
456 | { 0x0000, 0x0000, 0x0000 }, /* R359 */ | ||
457 | { 0x0000, 0x0000, 0x0000 }, /* R360 */ | ||
458 | { 0x0000, 0x0000, 0x0000 }, /* R361 */ | ||
459 | { 0x0000, 0x0000, 0x0000 }, /* R362 */ | ||
460 | { 0x0000, 0x0000, 0x0000 }, /* R363 */ | ||
461 | { 0x0000, 0x0000, 0x0000 }, /* R364 */ | ||
462 | { 0x0000, 0x0000, 0x0000 }, /* R365 */ | ||
463 | { 0x0000, 0x0000, 0x0000 }, /* R366 */ | ||
464 | { 0x0000, 0x0000, 0x0000 }, /* R367 */ | ||
465 | { 0x0000, 0x0000, 0x0000 }, /* R368 */ | ||
466 | { 0x0000, 0x0000, 0x0000 }, /* R369 */ | ||
467 | { 0x0000, 0x0000, 0x0000 }, /* R370 */ | ||
468 | { 0x0000, 0x0000, 0x0000 }, /* R371 */ | ||
469 | { 0x0000, 0x0000, 0x0000 }, /* R372 */ | ||
470 | { 0x0000, 0x0000, 0x0000 }, /* R373 */ | ||
471 | { 0x0000, 0x0000, 0x0000 }, /* R374 */ | ||
472 | { 0x0000, 0x0000, 0x0000 }, /* R375 */ | ||
473 | { 0x0000, 0x0000, 0x0000 }, /* R376 */ | ||
474 | { 0x0000, 0x0000, 0x0000 }, /* R377 */ | ||
475 | { 0x0000, 0x0000, 0x0000 }, /* R378 */ | ||
476 | { 0x0000, 0x0000, 0x0000 }, /* R379 */ | ||
477 | { 0x0000, 0x0000, 0x0000 }, /* R380 */ | ||
478 | { 0x0000, 0x0000, 0x0000 }, /* R381 */ | ||
479 | { 0x0000, 0x0000, 0x0000 }, /* R382 */ | ||
480 | { 0x0000, 0x0000, 0x0000 }, /* R383 */ | ||
481 | { 0x0000, 0x0000, 0x0000 }, /* R384 */ | ||
482 | { 0x0000, 0x0000, 0x0000 }, /* R385 */ | ||
483 | { 0x0000, 0x0000, 0x0000 }, /* R386 */ | ||
484 | { 0x0000, 0x0000, 0x0000 }, /* R387 */ | ||
485 | { 0x0000, 0x0000, 0x0000 }, /* R388 */ | ||
486 | { 0x0000, 0x0000, 0x0000 }, /* R389 */ | ||
487 | { 0x0000, 0x0000, 0x0000 }, /* R390 */ | ||
488 | { 0x0000, 0x0000, 0x0000 }, /* R391 */ | ||
489 | { 0x0000, 0x0000, 0x0000 }, /* R392 */ | ||
490 | { 0x0000, 0x0000, 0x0000 }, /* R393 */ | ||
491 | { 0x0000, 0x0000, 0x0000 }, /* R394 */ | ||
492 | { 0x0000, 0x0000, 0x0000 }, /* R395 */ | ||
493 | { 0x0000, 0x0000, 0x0000 }, /* R396 */ | ||
494 | { 0x0000, 0x0000, 0x0000 }, /* R397 */ | ||
495 | { 0x0000, 0x0000, 0x0000 }, /* R398 */ | ||
496 | { 0x0000, 0x0000, 0x0000 }, /* R399 */ | ||
497 | { 0x0000, 0x0000, 0x0000 }, /* R400 */ | ||
498 | { 0x0000, 0x0000, 0x0000 }, /* R401 */ | ||
499 | { 0x0000, 0x0000, 0x0000 }, /* R402 */ | ||
500 | { 0x0000, 0x0000, 0x0000 }, /* R403 */ | ||
501 | { 0x0000, 0x0000, 0x0000 }, /* R404 */ | ||
502 | { 0x0000, 0x0000, 0x0000 }, /* R405 */ | ||
503 | { 0x0000, 0x0000, 0x0000 }, /* R406 */ | ||
504 | { 0x0000, 0x0000, 0x0000 }, /* R407 */ | ||
505 | { 0x0000, 0x0000, 0x0000 }, /* R408 */ | ||
506 | { 0x0000, 0x0000, 0x0000 }, /* R409 */ | ||
507 | { 0x0000, 0x0000, 0x0000 }, /* R410 */ | ||
508 | { 0x0000, 0x0000, 0x0000 }, /* R411 */ | ||
509 | { 0x0000, 0x0000, 0x0000 }, /* R412 */ | ||
510 | { 0x0000, 0x0000, 0x0000 }, /* R413 */ | ||
511 | { 0x0000, 0x0000, 0x0000 }, /* R414 */ | ||
512 | { 0x0000, 0x0000, 0x0000 }, /* R415 */ | ||
513 | { 0x0000, 0x0000, 0x0000 }, /* R416 */ | ||
514 | { 0x0000, 0x0000, 0x0000 }, /* R417 */ | ||
515 | { 0x0000, 0x0000, 0x0000 }, /* R418 */ | ||
516 | { 0x0000, 0x0000, 0x0000 }, /* R419 */ | ||
517 | { 0x0000, 0x0000, 0x0000 }, /* R420 */ | ||
518 | { 0x0000, 0x0000, 0x0000 }, /* R421 */ | ||
519 | { 0x0000, 0x0000, 0x0000 }, /* R422 */ | ||
520 | { 0x0000, 0x0000, 0x0000 }, /* R423 */ | ||
521 | { 0x0000, 0x0000, 0x0000 }, /* R424 */ | ||
522 | { 0x0000, 0x0000, 0x0000 }, /* R425 */ | ||
523 | { 0x0000, 0x0000, 0x0000 }, /* R426 */ | ||
524 | { 0x0000, 0x0000, 0x0000 }, /* R427 */ | ||
525 | { 0x0000, 0x0000, 0x0000 }, /* R428 */ | ||
526 | { 0x0000, 0x0000, 0x0000 }, /* R429 */ | ||
527 | { 0x0000, 0x0000, 0x0000 }, /* R430 */ | ||
528 | { 0x0000, 0x0000, 0x0000 }, /* R431 */ | ||
529 | { 0x0000, 0x0000, 0x0000 }, /* R432 */ | ||
530 | { 0x0000, 0x0000, 0x0000 }, /* R433 */ | ||
531 | { 0x0000, 0x0000, 0x0000 }, /* R434 */ | ||
532 | { 0x0000, 0x0000, 0x0000 }, /* R435 */ | ||
533 | { 0x0000, 0x0000, 0x0000 }, /* R436 */ | ||
534 | { 0x0000, 0x0000, 0x0000 }, /* R437 */ | ||
535 | { 0x0000, 0x0000, 0x0000 }, /* R438 */ | ||
536 | { 0x0000, 0x0000, 0x0000 }, /* R439 */ | ||
537 | { 0x0000, 0x0000, 0x0000 }, /* R440 */ | ||
538 | { 0x0000, 0x0000, 0x0000 }, /* R441 */ | ||
539 | { 0x0000, 0x0000, 0x0000 }, /* R442 */ | ||
540 | { 0x0000, 0x0000, 0x0000 }, /* R443 */ | ||
541 | { 0x0000, 0x0000, 0x0000 }, /* R444 */ | ||
542 | { 0x0000, 0x0000, 0x0000 }, /* R445 */ | ||
543 | { 0x0000, 0x0000, 0x0000 }, /* R446 */ | ||
544 | { 0x0000, 0x0000, 0x0000 }, /* R447 */ | ||
545 | { 0x0000, 0x0000, 0x0000 }, /* R448 */ | ||
546 | { 0x0000, 0x0000, 0x0000 }, /* R449 */ | ||
547 | { 0x0000, 0x0000, 0x0000 }, /* R450 */ | ||
548 | { 0x0000, 0x0000, 0x0000 }, /* R451 */ | ||
549 | { 0x0000, 0x0000, 0x0000 }, /* R452 */ | ||
550 | { 0x0000, 0x0000, 0x0000 }, /* R453 */ | ||
551 | { 0x0000, 0x0000, 0x0000 }, /* R454 */ | ||
552 | { 0x0000, 0x0000, 0x0000 }, /* R455 */ | ||
553 | { 0x0000, 0x0000, 0x0000 }, /* R456 */ | ||
554 | { 0x0000, 0x0000, 0x0000 }, /* R457 */ | ||
555 | { 0x0000, 0x0000, 0x0000 }, /* R458 */ | ||
556 | { 0x0000, 0x0000, 0x0000 }, /* R459 */ | ||
557 | { 0x0000, 0x0000, 0x0000 }, /* R460 */ | ||
558 | { 0x0000, 0x0000, 0x0000 }, /* R461 */ | ||
559 | { 0x0000, 0x0000, 0x0000 }, /* R462 */ | ||
560 | { 0x0000, 0x0000, 0x0000 }, /* R463 */ | ||
561 | { 0x0000, 0x0000, 0x0000 }, /* R464 */ | ||
562 | { 0x0000, 0x0000, 0x0000 }, /* R465 */ | ||
563 | { 0x0000, 0x0000, 0x0000 }, /* R466 */ | ||
564 | { 0x0000, 0x0000, 0x0000 }, /* R467 */ | ||
565 | { 0x0000, 0x0000, 0x0000 }, /* R468 */ | ||
566 | { 0x0000, 0x0000, 0x0000 }, /* R469 */ | ||
567 | { 0x0000, 0x0000, 0x0000 }, /* R470 */ | ||
568 | { 0x0000, 0x0000, 0x0000 }, /* R471 */ | ||
569 | { 0x0000, 0x0000, 0x0000 }, /* R472 */ | ||
570 | { 0x0000, 0x0000, 0x0000 }, /* R473 */ | ||
571 | { 0x0000, 0x0000, 0x0000 }, /* R474 */ | ||
572 | { 0x0000, 0x0000, 0x0000 }, /* R475 */ | ||
573 | { 0x0000, 0x0000, 0x0000 }, /* R476 */ | ||
574 | { 0x0000, 0x0000, 0x0000 }, /* R477 */ | ||
575 | { 0x0000, 0x0000, 0x0000 }, /* R478 */ | ||
576 | { 0x0000, 0x0000, 0x0000 }, /* R479 */ | ||
577 | { 0x0000, 0x0000, 0x0000 }, /* R480 */ | ||
578 | { 0x0000, 0x0000, 0x0000 }, /* R481 */ | ||
579 | { 0x0000, 0x0000, 0x0000 }, /* R482 */ | ||
580 | { 0x0000, 0x0000, 0x0000 }, /* R483 */ | ||
581 | { 0x0000, 0x0000, 0x0000 }, /* R484 */ | ||
582 | { 0x0000, 0x0000, 0x0000 }, /* R485 */ | ||
583 | { 0x0000, 0x0000, 0x0000 }, /* R486 */ | ||
584 | { 0x0000, 0x0000, 0x0000 }, /* R487 */ | ||
585 | { 0x0000, 0x0000, 0x0000 }, /* R488 */ | ||
586 | { 0x0000, 0x0000, 0x0000 }, /* R489 */ | ||
587 | { 0x0000, 0x0000, 0x0000 }, /* R490 */ | ||
588 | { 0x0000, 0x0000, 0x0000 }, /* R491 */ | ||
589 | { 0x0000, 0x0000, 0x0000 }, /* R492 */ | ||
590 | { 0x0000, 0x0000, 0x0000 }, /* R493 */ | ||
591 | { 0x0000, 0x0000, 0x0000 }, /* R494 */ | ||
592 | { 0x0000, 0x0000, 0x0000 }, /* R495 */ | ||
593 | { 0x0000, 0x0000, 0x0000 }, /* R496 */ | ||
594 | { 0x0000, 0x0000, 0x0000 }, /* R497 */ | ||
595 | { 0x0000, 0x0000, 0x0000 }, /* R498 */ | ||
596 | { 0x0000, 0x0000, 0x0000 }, /* R499 */ | ||
597 | { 0x0000, 0x0000, 0x0000 }, /* R500 */ | ||
598 | { 0x0000, 0x0000, 0x0000 }, /* R501 */ | ||
599 | { 0x0000, 0x0000, 0x0000 }, /* R502 */ | ||
600 | { 0x0000, 0x0000, 0x0000 }, /* R503 */ | ||
601 | { 0x0000, 0x0000, 0x0000 }, /* R504 */ | ||
602 | { 0x0000, 0x0000, 0x0000 }, /* R505 */ | ||
603 | { 0x0000, 0x0000, 0x0000 }, /* R506 */ | ||
604 | { 0x0000, 0x0000, 0x0000 }, /* R507 */ | ||
605 | { 0x0000, 0x0000, 0x0000 }, /* R508 */ | ||
606 | { 0x0000, 0x0000, 0x0000 }, /* R509 */ | ||
607 | { 0x0000, 0x0000, 0x0000 }, /* R510 */ | ||
608 | { 0x0000, 0x0000, 0x0000 }, /* R511 */ | ||
609 | { 0x001F, 0x001F, 0x0000 }, /* R512 - AIF1 Clocking (1) */ | ||
610 | { 0x003F, 0x003F, 0x0000 }, /* R513 - AIF1 Clocking (2) */ | ||
611 | { 0x0000, 0x0000, 0x0000 }, /* R514 */ | ||
612 | { 0x0000, 0x0000, 0x0000 }, /* R515 */ | ||
613 | { 0x001F, 0x001F, 0x0000 }, /* R516 - AIF2 Clocking (1) */ | ||
614 | { 0x003F, 0x003F, 0x0000 }, /* R517 - AIF2 Clocking (2) */ | ||
615 | { 0x0000, 0x0000, 0x0000 }, /* R518 */ | ||
616 | { 0x0000, 0x0000, 0x0000 }, /* R519 */ | ||
617 | { 0x001F, 0x001F, 0x0000 }, /* R520 - Clocking (1) */ | ||
618 | { 0x0777, 0x0777, 0x0000 }, /* R521 - Clocking (2) */ | ||
619 | { 0x0000, 0x0000, 0x0000 }, /* R522 */ | ||
620 | { 0x0000, 0x0000, 0x0000 }, /* R523 */ | ||
621 | { 0x0000, 0x0000, 0x0000 }, /* R524 */ | ||
622 | { 0x0000, 0x0000, 0x0000 }, /* R525 */ | ||
623 | { 0x0000, 0x0000, 0x0000 }, /* R526 */ | ||
624 | { 0x0000, 0x0000, 0x0000 }, /* R527 */ | ||
625 | { 0x00FF, 0x00FF, 0x0000 }, /* R528 - AIF1 Rate */ | ||
626 | { 0x00FF, 0x00FF, 0x0000 }, /* R529 - AIF2 Rate */ | ||
627 | { 0x000F, 0x0000, 0x0000 }, /* R530 - Rate Status */ | ||
628 | { 0x0000, 0x0000, 0x0000 }, /* R531 */ | ||
629 | { 0x0000, 0x0000, 0x0000 }, /* R532 */ | ||
630 | { 0x0000, 0x0000, 0x0000 }, /* R533 */ | ||
631 | { 0x0000, 0x0000, 0x0000 }, /* R534 */ | ||
632 | { 0x0000, 0x0000, 0x0000 }, /* R535 */ | ||
633 | { 0x0000, 0x0000, 0x0000 }, /* R536 */ | ||
634 | { 0x0000, 0x0000, 0x0000 }, /* R537 */ | ||
635 | { 0x0000, 0x0000, 0x0000 }, /* R538 */ | ||
636 | { 0x0000, 0x0000, 0x0000 }, /* R539 */ | ||
637 | { 0x0000, 0x0000, 0x0000 }, /* R540 */ | ||
638 | { 0x0000, 0x0000, 0x0000 }, /* R541 */ | ||
639 | { 0x0000, 0x0000, 0x0000 }, /* R542 */ | ||
640 | { 0x0000, 0x0000, 0x0000 }, /* R543 */ | ||
641 | { 0x0007, 0x0007, 0x0000 }, /* R544 - FLL1 Control (1) */ | ||
642 | { 0x3F77, 0x3F77, 0x0000 }, /* R545 - FLL1 Control (2) */ | ||
643 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R546 - FLL1 Control (3) */ | ||
644 | { 0x7FEF, 0x7FEF, 0x0000 }, /* R547 - FLL1 Control (4) */ | ||
645 | { 0x1FDB, 0x1FDB, 0x0000 }, /* R548 - FLL1 Control (5) */ | ||
646 | { 0x0000, 0x0000, 0x0000 }, /* R549 */ | ||
647 | { 0x0000, 0x0000, 0x0000 }, /* R550 */ | ||
648 | { 0x0000, 0x0000, 0x0000 }, /* R551 */ | ||
649 | { 0x0000, 0x0000, 0x0000 }, /* R552 */ | ||
650 | { 0x0000, 0x0000, 0x0000 }, /* R553 */ | ||
651 | { 0x0000, 0x0000, 0x0000 }, /* R554 */ | ||
652 | { 0x0000, 0x0000, 0x0000 }, /* R555 */ | ||
653 | { 0x0000, 0x0000, 0x0000 }, /* R556 */ | ||
654 | { 0x0000, 0x0000, 0x0000 }, /* R557 */ | ||
655 | { 0x0000, 0x0000, 0x0000 }, /* R558 */ | ||
656 | { 0x0000, 0x0000, 0x0000 }, /* R559 */ | ||
657 | { 0x0000, 0x0000, 0x0000 }, /* R560 */ | ||
658 | { 0x0000, 0x0000, 0x0000 }, /* R561 */ | ||
659 | { 0x0000, 0x0000, 0x0000 }, /* R562 */ | ||
660 | { 0x0000, 0x0000, 0x0000 }, /* R563 */ | ||
661 | { 0x0000, 0x0000, 0x0000 }, /* R564 */ | ||
662 | { 0x0000, 0x0000, 0x0000 }, /* R565 */ | ||
663 | { 0x0000, 0x0000, 0x0000 }, /* R566 */ | ||
664 | { 0x0000, 0x0000, 0x0000 }, /* R567 */ | ||
665 | { 0x0000, 0x0000, 0x0000 }, /* R568 */ | ||
666 | { 0x0000, 0x0000, 0x0000 }, /* R569 */ | ||
667 | { 0x0000, 0x0000, 0x0000 }, /* R570 */ | ||
668 | { 0x0000, 0x0000, 0x0000 }, /* R571 */ | ||
669 | { 0x0000, 0x0000, 0x0000 }, /* R572 */ | ||
670 | { 0x0000, 0x0000, 0x0000 }, /* R573 */ | ||
671 | { 0x0000, 0x0000, 0x0000 }, /* R574 */ | ||
672 | { 0x0000, 0x0000, 0x0000 }, /* R575 */ | ||
673 | { 0x0007, 0x0007, 0x0000 }, /* R576 - FLL2 Control (1) */ | ||
674 | { 0x3F77, 0x3F77, 0x0000 }, /* R577 - FLL2 Control (2) */ | ||
675 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R578 - FLL2 Control (3) */ | ||
676 | { 0x7FEF, 0x7FEF, 0x0000 }, /* R579 - FLL2 Control (4) */ | ||
677 | { 0x1FDB, 0x1FDB, 0x0000 }, /* R580 - FLL2 Control (5) */ | ||
678 | { 0x0000, 0x0000, 0x0000 }, /* R581 */ | ||
679 | { 0x0000, 0x0000, 0x0000 }, /* R582 */ | ||
680 | { 0x0000, 0x0000, 0x0000 }, /* R583 */ | ||
681 | { 0x0000, 0x0000, 0x0000 }, /* R584 */ | ||
682 | { 0x0000, 0x0000, 0x0000 }, /* R585 */ | ||
683 | { 0x0000, 0x0000, 0x0000 }, /* R586 */ | ||
684 | { 0x0000, 0x0000, 0x0000 }, /* R587 */ | ||
685 | { 0x0000, 0x0000, 0x0000 }, /* R588 */ | ||
686 | { 0x0000, 0x0000, 0x0000 }, /* R589 */ | ||
687 | { 0x0000, 0x0000, 0x0000 }, /* R590 */ | ||
688 | { 0x0000, 0x0000, 0x0000 }, /* R591 */ | ||
689 | { 0x0000, 0x0000, 0x0000 }, /* R592 */ | ||
690 | { 0x0000, 0x0000, 0x0000 }, /* R593 */ | ||
691 | { 0x0000, 0x0000, 0x0000 }, /* R594 */ | ||
692 | { 0x0000, 0x0000, 0x0000 }, /* R595 */ | ||
693 | { 0x0000, 0x0000, 0x0000 }, /* R596 */ | ||
694 | { 0x0000, 0x0000, 0x0000 }, /* R597 */ | ||
695 | { 0x0000, 0x0000, 0x0000 }, /* R598 */ | ||
696 | { 0x0000, 0x0000, 0x0000 }, /* R599 */ | ||
697 | { 0x0000, 0x0000, 0x0000 }, /* R600 */ | ||
698 | { 0x0000, 0x0000, 0x0000 }, /* R601 */ | ||
699 | { 0x0000, 0x0000, 0x0000 }, /* R602 */ | ||
700 | { 0x0000, 0x0000, 0x0000 }, /* R603 */ | ||
701 | { 0x0000, 0x0000, 0x0000 }, /* R604 */ | ||
702 | { 0x0000, 0x0000, 0x0000 }, /* R605 */ | ||
703 | { 0x0000, 0x0000, 0x0000 }, /* R606 */ | ||
704 | { 0x0000, 0x0000, 0x0000 }, /* R607 */ | ||
705 | { 0x0000, 0x0000, 0x0000 }, /* R608 */ | ||
706 | { 0x0000, 0x0000, 0x0000 }, /* R609 */ | ||
707 | { 0x0000, 0x0000, 0x0000 }, /* R610 */ | ||
708 | { 0x0000, 0x0000, 0x0000 }, /* R611 */ | ||
709 | { 0x0000, 0x0000, 0x0000 }, /* R612 */ | ||
710 | { 0x0000, 0x0000, 0x0000 }, /* R613 */ | ||
711 | { 0x0000, 0x0000, 0x0000 }, /* R614 */ | ||
712 | { 0x0000, 0x0000, 0x0000 }, /* R615 */ | ||
713 | { 0x0000, 0x0000, 0x0000 }, /* R616 */ | ||
714 | { 0x0000, 0x0000, 0x0000 }, /* R617 */ | ||
715 | { 0x0000, 0x0000, 0x0000 }, /* R618 */ | ||
716 | { 0x0000, 0x0000, 0x0000 }, /* R619 */ | ||
717 | { 0x0000, 0x0000, 0x0000 }, /* R620 */ | ||
718 | { 0x0000, 0x0000, 0x0000 }, /* R621 */ | ||
719 | { 0x0000, 0x0000, 0x0000 }, /* R622 */ | ||
720 | { 0x0000, 0x0000, 0x0000 }, /* R623 */ | ||
721 | { 0x0000, 0x0000, 0x0000 }, /* R624 */ | ||
722 | { 0x0000, 0x0000, 0x0000 }, /* R625 */ | ||
723 | { 0x0000, 0x0000, 0x0000 }, /* R626 */ | ||
724 | { 0x0000, 0x0000, 0x0000 }, /* R627 */ | ||
725 | { 0x0000, 0x0000, 0x0000 }, /* R628 */ | ||
726 | { 0x0000, 0x0000, 0x0000 }, /* R629 */ | ||
727 | { 0x0000, 0x0000, 0x0000 }, /* R630 */ | ||
728 | { 0x0000, 0x0000, 0x0000 }, /* R631 */ | ||
729 | { 0x0000, 0x0000, 0x0000 }, /* R632 */ | ||
730 | { 0x0000, 0x0000, 0x0000 }, /* R633 */ | ||
731 | { 0x0000, 0x0000, 0x0000 }, /* R634 */ | ||
732 | { 0x0000, 0x0000, 0x0000 }, /* R635 */ | ||
733 | { 0x0000, 0x0000, 0x0000 }, /* R636 */ | ||
734 | { 0x0000, 0x0000, 0x0000 }, /* R637 */ | ||
735 | { 0x0000, 0x0000, 0x0000 }, /* R638 */ | ||
736 | { 0x0000, 0x0000, 0x0000 }, /* R639 */ | ||
737 | { 0x0000, 0x0000, 0x0000 }, /* R640 */ | ||
738 | { 0x0000, 0x0000, 0x0000 }, /* R641 */ | ||
739 | { 0x0000, 0x0000, 0x0000 }, /* R642 */ | ||
740 | { 0x0000, 0x0000, 0x0000 }, /* R643 */ | ||
741 | { 0x0000, 0x0000, 0x0000 }, /* R644 */ | ||
742 | { 0x0000, 0x0000, 0x0000 }, /* R645 */ | ||
743 | { 0x0000, 0x0000, 0x0000 }, /* R646 */ | ||
744 | { 0x0000, 0x0000, 0x0000 }, /* R647 */ | ||
745 | { 0x0000, 0x0000, 0x0000 }, /* R648 */ | ||
746 | { 0x0000, 0x0000, 0x0000 }, /* R649 */ | ||
747 | { 0x0000, 0x0000, 0x0000 }, /* R650 */ | ||
748 | { 0x0000, 0x0000, 0x0000 }, /* R651 */ | ||
749 | { 0x0000, 0x0000, 0x0000 }, /* R652 */ | ||
750 | { 0x0000, 0x0000, 0x0000 }, /* R653 */ | ||
751 | { 0x0000, 0x0000, 0x0000 }, /* R654 */ | ||
752 | { 0x0000, 0x0000, 0x0000 }, /* R655 */ | ||
753 | { 0x0000, 0x0000, 0x0000 }, /* R656 */ | ||
754 | { 0x0000, 0x0000, 0x0000 }, /* R657 */ | ||
755 | { 0x0000, 0x0000, 0x0000 }, /* R658 */ | ||
756 | { 0x0000, 0x0000, 0x0000 }, /* R659 */ | ||
757 | { 0x0000, 0x0000, 0x0000 }, /* R660 */ | ||
758 | { 0x0000, 0x0000, 0x0000 }, /* R661 */ | ||
759 | { 0x0000, 0x0000, 0x0000 }, /* R662 */ | ||
760 | { 0x0000, 0x0000, 0x0000 }, /* R663 */ | ||
761 | { 0x0000, 0x0000, 0x0000 }, /* R664 */ | ||
762 | { 0x0000, 0x0000, 0x0000 }, /* R665 */ | ||
763 | { 0x0000, 0x0000, 0x0000 }, /* R666 */ | ||
764 | { 0x0000, 0x0000, 0x0000 }, /* R667 */ | ||
765 | { 0x0000, 0x0000, 0x0000 }, /* R668 */ | ||
766 | { 0x0000, 0x0000, 0x0000 }, /* R669 */ | ||
767 | { 0x0000, 0x0000, 0x0000 }, /* R670 */ | ||
768 | { 0x0000, 0x0000, 0x0000 }, /* R671 */ | ||
769 | { 0x0000, 0x0000, 0x0000 }, /* R672 */ | ||
770 | { 0x0000, 0x0000, 0x0000 }, /* R673 */ | ||
771 | { 0x0000, 0x0000, 0x0000 }, /* R674 */ | ||
772 | { 0x0000, 0x0000, 0x0000 }, /* R675 */ | ||
773 | { 0x0000, 0x0000, 0x0000 }, /* R676 */ | ||
774 | { 0x0000, 0x0000, 0x0000 }, /* R677 */ | ||
775 | { 0x0000, 0x0000, 0x0000 }, /* R678 */ | ||
776 | { 0x0000, 0x0000, 0x0000 }, /* R679 */ | ||
777 | { 0x0000, 0x0000, 0x0000 }, /* R680 */ | ||
778 | { 0x0000, 0x0000, 0x0000 }, /* R681 */ | ||
779 | { 0x0000, 0x0000, 0x0000 }, /* R682 */ | ||
780 | { 0x0000, 0x0000, 0x0000 }, /* R683 */ | ||
781 | { 0x0000, 0x0000, 0x0000 }, /* R684 */ | ||
782 | { 0x0000, 0x0000, 0x0000 }, /* R685 */ | ||
783 | { 0x0000, 0x0000, 0x0000 }, /* R686 */ | ||
784 | { 0x0000, 0x0000, 0x0000 }, /* R687 */ | ||
785 | { 0x0000, 0x0000, 0x0000 }, /* R688 */ | ||
786 | { 0x0000, 0x0000, 0x0000 }, /* R689 */ | ||
787 | { 0x0000, 0x0000, 0x0000 }, /* R690 */ | ||
788 | { 0x0000, 0x0000, 0x0000 }, /* R691 */ | ||
789 | { 0x0000, 0x0000, 0x0000 }, /* R692 */ | ||
790 | { 0x0000, 0x0000, 0x0000 }, /* R693 */ | ||
791 | { 0x0000, 0x0000, 0x0000 }, /* R694 */ | ||
792 | { 0x0000, 0x0000, 0x0000 }, /* R695 */ | ||
793 | { 0x0000, 0x0000, 0x0000 }, /* R696 */ | ||
794 | { 0x0000, 0x0000, 0x0000 }, /* R697 */ | ||
795 | { 0x0000, 0x0000, 0x0000 }, /* R698 */ | ||
796 | { 0x0000, 0x0000, 0x0000 }, /* R699 */ | ||
797 | { 0x0000, 0x0000, 0x0000 }, /* R700 */ | ||
798 | { 0x0000, 0x0000, 0x0000 }, /* R701 */ | ||
799 | { 0x0000, 0x0000, 0x0000 }, /* R702 */ | ||
800 | { 0x0000, 0x0000, 0x0000 }, /* R703 */ | ||
801 | { 0x0000, 0x0000, 0x0000 }, /* R704 */ | ||
802 | { 0x0000, 0x0000, 0x0000 }, /* R705 */ | ||
803 | { 0x0000, 0x0000, 0x0000 }, /* R706 */ | ||
804 | { 0x0000, 0x0000, 0x0000 }, /* R707 */ | ||
805 | { 0x0000, 0x0000, 0x0000 }, /* R708 */ | ||
806 | { 0x0000, 0x0000, 0x0000 }, /* R709 */ | ||
807 | { 0x0000, 0x0000, 0x0000 }, /* R710 */ | ||
808 | { 0x0000, 0x0000, 0x0000 }, /* R711 */ | ||
809 | { 0x0000, 0x0000, 0x0000 }, /* R712 */ | ||
810 | { 0x0000, 0x0000, 0x0000 }, /* R713 */ | ||
811 | { 0x0000, 0x0000, 0x0000 }, /* R714 */ | ||
812 | { 0x0000, 0x0000, 0x0000 }, /* R715 */ | ||
813 | { 0x0000, 0x0000, 0x0000 }, /* R716 */ | ||
814 | { 0x0000, 0x0000, 0x0000 }, /* R717 */ | ||
815 | { 0x0000, 0x0000, 0x0000 }, /* R718 */ | ||
816 | { 0x0000, 0x0000, 0x0000 }, /* R719 */ | ||
817 | { 0x0000, 0x0000, 0x0000 }, /* R720 */ | ||
818 | { 0x0000, 0x0000, 0x0000 }, /* R721 */ | ||
819 | { 0x0000, 0x0000, 0x0000 }, /* R722 */ | ||
820 | { 0x0000, 0x0000, 0x0000 }, /* R723 */ | ||
821 | { 0x0000, 0x0000, 0x0000 }, /* R724 */ | ||
822 | { 0x0000, 0x0000, 0x0000 }, /* R725 */ | ||
823 | { 0x0000, 0x0000, 0x0000 }, /* R726 */ | ||
824 | { 0x0000, 0x0000, 0x0000 }, /* R727 */ | ||
825 | { 0x0000, 0x0000, 0x0000 }, /* R728 */ | ||
826 | { 0x0000, 0x0000, 0x0000 }, /* R729 */ | ||
827 | { 0x0000, 0x0000, 0x0000 }, /* R730 */ | ||
828 | { 0x0000, 0x0000, 0x0000 }, /* R731 */ | ||
829 | { 0x0000, 0x0000, 0x0000 }, /* R732 */ | ||
830 | { 0x0000, 0x0000, 0x0000 }, /* R733 */ | ||
831 | { 0x0000, 0x0000, 0x0000 }, /* R734 */ | ||
832 | { 0x0000, 0x0000, 0x0000 }, /* R735 */ | ||
833 | { 0x0000, 0x0000, 0x0000 }, /* R736 */ | ||
834 | { 0x0000, 0x0000, 0x0000 }, /* R737 */ | ||
835 | { 0x0000, 0x0000, 0x0000 }, /* R738 */ | ||
836 | { 0x0000, 0x0000, 0x0000 }, /* R739 */ | ||
837 | { 0x0000, 0x0000, 0x0000 }, /* R740 */ | ||
838 | { 0x0000, 0x0000, 0x0000 }, /* R741 */ | ||
839 | { 0x0000, 0x0000, 0x0000 }, /* R742 */ | ||
840 | { 0x0000, 0x0000, 0x0000 }, /* R743 */ | ||
841 | { 0x0000, 0x0000, 0x0000 }, /* R744 */ | ||
842 | { 0x0000, 0x0000, 0x0000 }, /* R745 */ | ||
843 | { 0x0000, 0x0000, 0x0000 }, /* R746 */ | ||
844 | { 0x0000, 0x0000, 0x0000 }, /* R747 */ | ||
845 | { 0x0000, 0x0000, 0x0000 }, /* R748 */ | ||
846 | { 0x0000, 0x0000, 0x0000 }, /* R749 */ | ||
847 | { 0x0000, 0x0000, 0x0000 }, /* R750 */ | ||
848 | { 0x0000, 0x0000, 0x0000 }, /* R751 */ | ||
849 | { 0x0000, 0x0000, 0x0000 }, /* R752 */ | ||
850 | { 0x0000, 0x0000, 0x0000 }, /* R753 */ | ||
851 | { 0x0000, 0x0000, 0x0000 }, /* R754 */ | ||
852 | { 0x0000, 0x0000, 0x0000 }, /* R755 */ | ||
853 | { 0x0000, 0x0000, 0x0000 }, /* R756 */ | ||
854 | { 0x0000, 0x0000, 0x0000 }, /* R757 */ | ||
855 | { 0x0000, 0x0000, 0x0000 }, /* R758 */ | ||
856 | { 0x0000, 0x0000, 0x0000 }, /* R759 */ | ||
857 | { 0x0000, 0x0000, 0x0000 }, /* R760 */ | ||
858 | { 0x0000, 0x0000, 0x0000 }, /* R761 */ | ||
859 | { 0x0000, 0x0000, 0x0000 }, /* R762 */ | ||
860 | { 0x0000, 0x0000, 0x0000 }, /* R763 */ | ||
861 | { 0x0000, 0x0000, 0x0000 }, /* R764 */ | ||
862 | { 0x0000, 0x0000, 0x0000 }, /* R765 */ | ||
863 | { 0x0000, 0x0000, 0x0000 }, /* R766 */ | ||
864 | { 0x0000, 0x0000, 0x0000 }, /* R767 */ | ||
865 | { 0xE1F8, 0xE1F8, 0x0000 }, /* R768 - AIF1 Control (1) */ | ||
866 | { 0xCD1F, 0xCD1F, 0x0000 }, /* R769 - AIF1 Control (2) */ | ||
867 | { 0xF000, 0xF000, 0x0000 }, /* R770 - AIF1 Master/Slave */ | ||
868 | { 0x01F0, 0x01F0, 0x0000 }, /* R771 - AIF1 BCLK */ | ||
869 | { 0x0FFF, 0x0FFF, 0x0000 }, /* R772 - AIF1ADC LRCLK */ | ||
870 | { 0x0FFF, 0x0FFF, 0x0000 }, /* R773 - AIF1DAC LRCLK */ | ||
871 | { 0x0003, 0x0003, 0x0000 }, /* R774 - AIF1DAC Data */ | ||
872 | { 0x0003, 0x0003, 0x0000 }, /* R775 - AIF1ADC Data */ | ||
873 | { 0x0000, 0x0000, 0x0000 }, /* R776 */ | ||
874 | { 0x0000, 0x0000, 0x0000 }, /* R777 */ | ||
875 | { 0x0000, 0x0000, 0x0000 }, /* R778 */ | ||
876 | { 0x0000, 0x0000, 0x0000 }, /* R779 */ | ||
877 | { 0x0000, 0x0000, 0x0000 }, /* R780 */ | ||
878 | { 0x0000, 0x0000, 0x0000 }, /* R781 */ | ||
879 | { 0x0000, 0x0000, 0x0000 }, /* R782 */ | ||
880 | { 0x0000, 0x0000, 0x0000 }, /* R783 */ | ||
881 | { 0xF1F8, 0xF1F8, 0x0000 }, /* R784 - AIF2 Control (1) */ | ||
882 | { 0xFD1F, 0xFD1F, 0x0000 }, /* R785 - AIF2 Control (2) */ | ||
883 | { 0xF000, 0xF000, 0x0000 }, /* R786 - AIF2 Master/Slave */ | ||
884 | { 0x01F0, 0x01F0, 0x0000 }, /* R787 - AIF2 BCLK */ | ||
885 | { 0x0FFF, 0x0FFF, 0x0000 }, /* R788 - AIF2ADC LRCLK */ | ||
886 | { 0x0FFF, 0x0FFF, 0x0000 }, /* R789 - AIF2DAC LRCLK */ | ||
887 | { 0x0003, 0x0003, 0x0000 }, /* R790 - AIF2DAC Data */ | ||
888 | { 0x0003, 0x0003, 0x0000 }, /* R791 - AIF2ADC Data */ | ||
889 | { 0x0000, 0x0000, 0x0000 }, /* R792 */ | ||
890 | { 0x0000, 0x0000, 0x0000 }, /* R793 */ | ||
891 | { 0x0000, 0x0000, 0x0000 }, /* R794 */ | ||
892 | { 0x0000, 0x0000, 0x0000 }, /* R795 */ | ||
893 | { 0x0000, 0x0000, 0x0000 }, /* R796 */ | ||
894 | { 0x0000, 0x0000, 0x0000 }, /* R797 */ | ||
895 | { 0x0000, 0x0000, 0x0000 }, /* R798 */ | ||
896 | { 0x0000, 0x0000, 0x0000 }, /* R799 */ | ||
897 | { 0x0000, 0x0000, 0x0000 }, /* R800 */ | ||
898 | { 0x0000, 0x0000, 0x0000 }, /* R801 */ | ||
899 | { 0x0000, 0x0000, 0x0000 }, /* R802 */ | ||
900 | { 0x0000, 0x0000, 0x0000 }, /* R803 */ | ||
901 | { 0x0000, 0x0000, 0x0000 }, /* R804 */ | ||
902 | { 0x0000, 0x0000, 0x0000 }, /* R805 */ | ||
903 | { 0x0000, 0x0000, 0x0000 }, /* R806 */ | ||
904 | { 0x0000, 0x0000, 0x0000 }, /* R807 */ | ||
905 | { 0x0000, 0x0000, 0x0000 }, /* R808 */ | ||
906 | { 0x0000, 0x0000, 0x0000 }, /* R809 */ | ||
907 | { 0x0000, 0x0000, 0x0000 }, /* R810 */ | ||
908 | { 0x0000, 0x0000, 0x0000 }, /* R811 */ | ||
909 | { 0x0000, 0x0000, 0x0000 }, /* R812 */ | ||
910 | { 0x0000, 0x0000, 0x0000 }, /* R813 */ | ||
911 | { 0x0000, 0x0000, 0x0000 }, /* R814 */ | ||
912 | { 0x0000, 0x0000, 0x0000 }, /* R815 */ | ||
913 | { 0x0000, 0x0000, 0x0000 }, /* R816 */ | ||
914 | { 0x0000, 0x0000, 0x0000 }, /* R817 */ | ||
915 | { 0x0000, 0x0000, 0x0000 }, /* R818 */ | ||
916 | { 0x0000, 0x0000, 0x0000 }, /* R819 */ | ||
917 | { 0x0000, 0x0000, 0x0000 }, /* R820 */ | ||
918 | { 0x0000, 0x0000, 0x0000 }, /* R821 */ | ||
919 | { 0x0000, 0x0000, 0x0000 }, /* R822 */ | ||
920 | { 0x0000, 0x0000, 0x0000 }, /* R823 */ | ||
921 | { 0x0000, 0x0000, 0x0000 }, /* R824 */ | ||
922 | { 0x0000, 0x0000, 0x0000 }, /* R825 */ | ||
923 | { 0x0000, 0x0000, 0x0000 }, /* R826 */ | ||
924 | { 0x0000, 0x0000, 0x0000 }, /* R827 */ | ||
925 | { 0x0000, 0x0000, 0x0000 }, /* R828 */ | ||
926 | { 0x0000, 0x0000, 0x0000 }, /* R829 */ | ||
927 | { 0x0000, 0x0000, 0x0000 }, /* R830 */ | ||
928 | { 0x0000, 0x0000, 0x0000 }, /* R831 */ | ||
929 | { 0x0000, 0x0000, 0x0000 }, /* R832 */ | ||
930 | { 0x0000, 0x0000, 0x0000 }, /* R833 */ | ||
931 | { 0x0000, 0x0000, 0x0000 }, /* R834 */ | ||
932 | { 0x0000, 0x0000, 0x0000 }, /* R835 */ | ||
933 | { 0x0000, 0x0000, 0x0000 }, /* R836 */ | ||
934 | { 0x0000, 0x0000, 0x0000 }, /* R837 */ | ||
935 | { 0x0000, 0x0000, 0x0000 }, /* R838 */ | ||
936 | { 0x0000, 0x0000, 0x0000 }, /* R839 */ | ||
937 | { 0x0000, 0x0000, 0x0000 }, /* R840 */ | ||
938 | { 0x0000, 0x0000, 0x0000 }, /* R841 */ | ||
939 | { 0x0000, 0x0000, 0x0000 }, /* R842 */ | ||
940 | { 0x0000, 0x0000, 0x0000 }, /* R843 */ | ||
941 | { 0x0000, 0x0000, 0x0000 }, /* R844 */ | ||
942 | { 0x0000, 0x0000, 0x0000 }, /* R845 */ | ||
943 | { 0x0000, 0x0000, 0x0000 }, /* R846 */ | ||
944 | { 0x0000, 0x0000, 0x0000 }, /* R847 */ | ||
945 | { 0x0000, 0x0000, 0x0000 }, /* R848 */ | ||
946 | { 0x0000, 0x0000, 0x0000 }, /* R849 */ | ||
947 | { 0x0000, 0x0000, 0x0000 }, /* R850 */ | ||
948 | { 0x0000, 0x0000, 0x0000 }, /* R851 */ | ||
949 | { 0x0000, 0x0000, 0x0000 }, /* R852 */ | ||
950 | { 0x0000, 0x0000, 0x0000 }, /* R853 */ | ||
951 | { 0x0000, 0x0000, 0x0000 }, /* R854 */ | ||
952 | { 0x0000, 0x0000, 0x0000 }, /* R855 */ | ||
953 | { 0x0000, 0x0000, 0x0000 }, /* R856 */ | ||
954 | { 0x0000, 0x0000, 0x0000 }, /* R857 */ | ||
955 | { 0x0000, 0x0000, 0x0000 }, /* R858 */ | ||
956 | { 0x0000, 0x0000, 0x0000 }, /* R859 */ | ||
957 | { 0x0000, 0x0000, 0x0000 }, /* R860 */ | ||
958 | { 0x0000, 0x0000, 0x0000 }, /* R861 */ | ||
959 | { 0x0000, 0x0000, 0x0000 }, /* R862 */ | ||
960 | { 0x0000, 0x0000, 0x0000 }, /* R863 */ | ||
961 | { 0x0000, 0x0000, 0x0000 }, /* R864 */ | ||
962 | { 0x0000, 0x0000, 0x0000 }, /* R865 */ | ||
963 | { 0x0000, 0x0000, 0x0000 }, /* R866 */ | ||
964 | { 0x0000, 0x0000, 0x0000 }, /* R867 */ | ||
965 | { 0x0000, 0x0000, 0x0000 }, /* R868 */ | ||
966 | { 0x0000, 0x0000, 0x0000 }, /* R869 */ | ||
967 | { 0x0000, 0x0000, 0x0000 }, /* R870 */ | ||
968 | { 0x0000, 0x0000, 0x0000 }, /* R871 */ | ||
969 | { 0x0000, 0x0000, 0x0000 }, /* R872 */ | ||
970 | { 0x0000, 0x0000, 0x0000 }, /* R873 */ | ||
971 | { 0x0000, 0x0000, 0x0000 }, /* R874 */ | ||
972 | { 0x0000, 0x0000, 0x0000 }, /* R875 */ | ||
973 | { 0x0000, 0x0000, 0x0000 }, /* R876 */ | ||
974 | { 0x0000, 0x0000, 0x0000 }, /* R877 */ | ||
975 | { 0x0000, 0x0000, 0x0000 }, /* R878 */ | ||
976 | { 0x0000, 0x0000, 0x0000 }, /* R879 */ | ||
977 | { 0x0000, 0x0000, 0x0000 }, /* R880 */ | ||
978 | { 0x0000, 0x0000, 0x0000 }, /* R881 */ | ||
979 | { 0x0000, 0x0000, 0x0000 }, /* R882 */ | ||
980 | { 0x0000, 0x0000, 0x0000 }, /* R883 */ | ||
981 | { 0x0000, 0x0000, 0x0000 }, /* R884 */ | ||
982 | { 0x0000, 0x0000, 0x0000 }, /* R885 */ | ||
983 | { 0x0000, 0x0000, 0x0000 }, /* R886 */ | ||
984 | { 0x0000, 0x0000, 0x0000 }, /* R887 */ | ||
985 | { 0x0000, 0x0000, 0x0000 }, /* R888 */ | ||
986 | { 0x0000, 0x0000, 0x0000 }, /* R889 */ | ||
987 | { 0x0000, 0x0000, 0x0000 }, /* R890 */ | ||
988 | { 0x0000, 0x0000, 0x0000 }, /* R891 */ | ||
989 | { 0x0000, 0x0000, 0x0000 }, /* R892 */ | ||
990 | { 0x0000, 0x0000, 0x0000 }, /* R893 */ | ||
991 | { 0x0000, 0x0000, 0x0000 }, /* R894 */ | ||
992 | { 0x0000, 0x0000, 0x0000 }, /* R895 */ | ||
993 | { 0x0000, 0x0000, 0x0000 }, /* R896 */ | ||
994 | { 0x0000, 0x0000, 0x0000 }, /* R897 */ | ||
995 | { 0x0000, 0x0000, 0x0000 }, /* R898 */ | ||
996 | { 0x0000, 0x0000, 0x0000 }, /* R899 */ | ||
997 | { 0x0000, 0x0000, 0x0000 }, /* R900 */ | ||
998 | { 0x0000, 0x0000, 0x0000 }, /* R901 */ | ||
999 | { 0x0000, 0x0000, 0x0000 }, /* R902 */ | ||
1000 | { 0x0000, 0x0000, 0x0000 }, /* R903 */ | ||
1001 | { 0x0000, 0x0000, 0x0000 }, /* R904 */ | ||
1002 | { 0x0000, 0x0000, 0x0000 }, /* R905 */ | ||
1003 | { 0x0000, 0x0000, 0x0000 }, /* R906 */ | ||
1004 | { 0x0000, 0x0000, 0x0000 }, /* R907 */ | ||
1005 | { 0x0000, 0x0000, 0x0000 }, /* R908 */ | ||
1006 | { 0x0000, 0x0000, 0x0000 }, /* R909 */ | ||
1007 | { 0x0000, 0x0000, 0x0000 }, /* R910 */ | ||
1008 | { 0x0000, 0x0000, 0x0000 }, /* R911 */ | ||
1009 | { 0x0000, 0x0000, 0x0000 }, /* R912 */ | ||
1010 | { 0x0000, 0x0000, 0x0000 }, /* R913 */ | ||
1011 | { 0x0000, 0x0000, 0x0000 }, /* R914 */ | ||
1012 | { 0x0000, 0x0000, 0x0000 }, /* R915 */ | ||
1013 | { 0x0000, 0x0000, 0x0000 }, /* R916 */ | ||
1014 | { 0x0000, 0x0000, 0x0000 }, /* R917 */ | ||
1015 | { 0x0000, 0x0000, 0x0000 }, /* R918 */ | ||
1016 | { 0x0000, 0x0000, 0x0000 }, /* R919 */ | ||
1017 | { 0x0000, 0x0000, 0x0000 }, /* R920 */ | ||
1018 | { 0x0000, 0x0000, 0x0000 }, /* R921 */ | ||
1019 | { 0x0000, 0x0000, 0x0000 }, /* R922 */ | ||
1020 | { 0x0000, 0x0000, 0x0000 }, /* R923 */ | ||
1021 | { 0x0000, 0x0000, 0x0000 }, /* R924 */ | ||
1022 | { 0x0000, 0x0000, 0x0000 }, /* R925 */ | ||
1023 | { 0x0000, 0x0000, 0x0000 }, /* R926 */ | ||
1024 | { 0x0000, 0x0000, 0x0000 }, /* R927 */ | ||
1025 | { 0x0000, 0x0000, 0x0000 }, /* R928 */ | ||
1026 | { 0x0000, 0x0000, 0x0000 }, /* R929 */ | ||
1027 | { 0x0000, 0x0000, 0x0000 }, /* R930 */ | ||
1028 | { 0x0000, 0x0000, 0x0000 }, /* R931 */ | ||
1029 | { 0x0000, 0x0000, 0x0000 }, /* R932 */ | ||
1030 | { 0x0000, 0x0000, 0x0000 }, /* R933 */ | ||
1031 | { 0x0000, 0x0000, 0x0000 }, /* R934 */ | ||
1032 | { 0x0000, 0x0000, 0x0000 }, /* R935 */ | ||
1033 | { 0x0000, 0x0000, 0x0000 }, /* R936 */ | ||
1034 | { 0x0000, 0x0000, 0x0000 }, /* R937 */ | ||
1035 | { 0x0000, 0x0000, 0x0000 }, /* R938 */ | ||
1036 | { 0x0000, 0x0000, 0x0000 }, /* R939 */ | ||
1037 | { 0x0000, 0x0000, 0x0000 }, /* R940 */ | ||
1038 | { 0x0000, 0x0000, 0x0000 }, /* R941 */ | ||
1039 | { 0x0000, 0x0000, 0x0000 }, /* R942 */ | ||
1040 | { 0x0000, 0x0000, 0x0000 }, /* R943 */ | ||
1041 | { 0x0000, 0x0000, 0x0000 }, /* R944 */ | ||
1042 | { 0x0000, 0x0000, 0x0000 }, /* R945 */ | ||
1043 | { 0x0000, 0x0000, 0x0000 }, /* R946 */ | ||
1044 | { 0x0000, 0x0000, 0x0000 }, /* R947 */ | ||
1045 | { 0x0000, 0x0000, 0x0000 }, /* R948 */ | ||
1046 | { 0x0000, 0x0000, 0x0000 }, /* R949 */ | ||
1047 | { 0x0000, 0x0000, 0x0000 }, /* R950 */ | ||
1048 | { 0x0000, 0x0000, 0x0000 }, /* R951 */ | ||
1049 | { 0x0000, 0x0000, 0x0000 }, /* R952 */ | ||
1050 | { 0x0000, 0x0000, 0x0000 }, /* R953 */ | ||
1051 | { 0x0000, 0x0000, 0x0000 }, /* R954 */ | ||
1052 | { 0x0000, 0x0000, 0x0000 }, /* R955 */ | ||
1053 | { 0x0000, 0x0000, 0x0000 }, /* R956 */ | ||
1054 | { 0x0000, 0x0000, 0x0000 }, /* R957 */ | ||
1055 | { 0x0000, 0x0000, 0x0000 }, /* R958 */ | ||
1056 | { 0x0000, 0x0000, 0x0000 }, /* R959 */ | ||
1057 | { 0x0000, 0x0000, 0x0000 }, /* R960 */ | ||
1058 | { 0x0000, 0x0000, 0x0000 }, /* R961 */ | ||
1059 | { 0x0000, 0x0000, 0x0000 }, /* R962 */ | ||
1060 | { 0x0000, 0x0000, 0x0000 }, /* R963 */ | ||
1061 | { 0x0000, 0x0000, 0x0000 }, /* R964 */ | ||
1062 | { 0x0000, 0x0000, 0x0000 }, /* R965 */ | ||
1063 | { 0x0000, 0x0000, 0x0000 }, /* R966 */ | ||
1064 | { 0x0000, 0x0000, 0x0000 }, /* R967 */ | ||
1065 | { 0x0000, 0x0000, 0x0000 }, /* R968 */ | ||
1066 | { 0x0000, 0x0000, 0x0000 }, /* R969 */ | ||
1067 | { 0x0000, 0x0000, 0x0000 }, /* R970 */ | ||
1068 | { 0x0000, 0x0000, 0x0000 }, /* R971 */ | ||
1069 | { 0x0000, 0x0000, 0x0000 }, /* R972 */ | ||
1070 | { 0x0000, 0x0000, 0x0000 }, /* R973 */ | ||
1071 | { 0x0000, 0x0000, 0x0000 }, /* R974 */ | ||
1072 | { 0x0000, 0x0000, 0x0000 }, /* R975 */ | ||
1073 | { 0x0000, 0x0000, 0x0000 }, /* R976 */ | ||
1074 | { 0x0000, 0x0000, 0x0000 }, /* R977 */ | ||
1075 | { 0x0000, 0x0000, 0x0000 }, /* R978 */ | ||
1076 | { 0x0000, 0x0000, 0x0000 }, /* R979 */ | ||
1077 | { 0x0000, 0x0000, 0x0000 }, /* R980 */ | ||
1078 | { 0x0000, 0x0000, 0x0000 }, /* R981 */ | ||
1079 | { 0x0000, 0x0000, 0x0000 }, /* R982 */ | ||
1080 | { 0x0000, 0x0000, 0x0000 }, /* R983 */ | ||
1081 | { 0x0000, 0x0000, 0x0000 }, /* R984 */ | ||
1082 | { 0x0000, 0x0000, 0x0000 }, /* R985 */ | ||
1083 | { 0x0000, 0x0000, 0x0000 }, /* R986 */ | ||
1084 | { 0x0000, 0x0000, 0x0000 }, /* R987 */ | ||
1085 | { 0x0000, 0x0000, 0x0000 }, /* R988 */ | ||
1086 | { 0x0000, 0x0000, 0x0000 }, /* R989 */ | ||
1087 | { 0x0000, 0x0000, 0x0000 }, /* R990 */ | ||
1088 | { 0x0000, 0x0000, 0x0000 }, /* R991 */ | ||
1089 | { 0x0000, 0x0000, 0x0000 }, /* R992 */ | ||
1090 | { 0x0000, 0x0000, 0x0000 }, /* R993 */ | ||
1091 | { 0x0000, 0x0000, 0x0000 }, /* R994 */ | ||
1092 | { 0x0000, 0x0000, 0x0000 }, /* R995 */ | ||
1093 | { 0x0000, 0x0000, 0x0000 }, /* R996 */ | ||
1094 | { 0x0000, 0x0000, 0x0000 }, /* R997 */ | ||
1095 | { 0x0000, 0x0000, 0x0000 }, /* R998 */ | ||
1096 | { 0x0000, 0x0000, 0x0000 }, /* R999 */ | ||
1097 | { 0x0000, 0x0000, 0x0000 }, /* R1000 */ | ||
1098 | { 0x0000, 0x0000, 0x0000 }, /* R1001 */ | ||
1099 | { 0x0000, 0x0000, 0x0000 }, /* R1002 */ | ||
1100 | { 0x0000, 0x0000, 0x0000 }, /* R1003 */ | ||
1101 | { 0x0000, 0x0000, 0x0000 }, /* R1004 */ | ||
1102 | { 0x0000, 0x0000, 0x0000 }, /* R1005 */ | ||
1103 | { 0x0000, 0x0000, 0x0000 }, /* R1006 */ | ||
1104 | { 0x0000, 0x0000, 0x0000 }, /* R1007 */ | ||
1105 | { 0x0000, 0x0000, 0x0000 }, /* R1008 */ | ||
1106 | { 0x0000, 0x0000, 0x0000 }, /* R1009 */ | ||
1107 | { 0x0000, 0x0000, 0x0000 }, /* R1010 */ | ||
1108 | { 0x0000, 0x0000, 0x0000 }, /* R1011 */ | ||
1109 | { 0x0000, 0x0000, 0x0000 }, /* R1012 */ | ||
1110 | { 0x0000, 0x0000, 0x0000 }, /* R1013 */ | ||
1111 | { 0x0000, 0x0000, 0x0000 }, /* R1014 */ | ||
1112 | { 0x0000, 0x0000, 0x0000 }, /* R1015 */ | ||
1113 | { 0x0000, 0x0000, 0x0000 }, /* R1016 */ | ||
1114 | { 0x0000, 0x0000, 0x0000 }, /* R1017 */ | ||
1115 | { 0x0000, 0x0000, 0x0000 }, /* R1018 */ | ||
1116 | { 0x0000, 0x0000, 0x0000 }, /* R1019 */ | ||
1117 | { 0x0000, 0x0000, 0x0000 }, /* R1020 */ | ||
1118 | { 0x0000, 0x0000, 0x0000 }, /* R1021 */ | ||
1119 | { 0x0000, 0x0000, 0x0000 }, /* R1022 */ | ||
1120 | { 0x0000, 0x0000, 0x0000 }, /* R1023 */ | ||
1121 | { 0x00FF, 0x01FF, 0x0000 }, /* R1024 - AIF1 ADC1 Left Volume */ | ||
1122 | { 0x00FF, 0x01FF, 0x0000 }, /* R1025 - AIF1 ADC1 Right Volume */ | ||
1123 | { 0x00FF, 0x01FF, 0x0000 }, /* R1026 - AIF1 DAC1 Left Volume */ | ||
1124 | { 0x00FF, 0x01FF, 0x0000 }, /* R1027 - AIF1 DAC1 Right Volume */ | ||
1125 | { 0x00FF, 0x01FF, 0x0000 }, /* R1028 - AIF1 ADC2 Left Volume */ | ||
1126 | { 0x00FF, 0x01FF, 0x0000 }, /* R1029 - AIF1 ADC2 Right Volume */ | ||
1127 | { 0x00FF, 0x01FF, 0x0000 }, /* R1030 - AIF1 DAC2 Left Volume */ | ||
1128 | { 0x00FF, 0x01FF, 0x0000 }, /* R1031 - AIF1 DAC2 Right Volume */ | ||
1129 | { 0x0000, 0x0000, 0x0000 }, /* R1032 */ | ||
1130 | { 0x0000, 0x0000, 0x0000 }, /* R1033 */ | ||
1131 | { 0x0000, 0x0000, 0x0000 }, /* R1034 */ | ||
1132 | { 0x0000, 0x0000, 0x0000 }, /* R1035 */ | ||
1133 | { 0x0000, 0x0000, 0x0000 }, /* R1036 */ | ||
1134 | { 0x0000, 0x0000, 0x0000 }, /* R1037 */ | ||
1135 | { 0x0000, 0x0000, 0x0000 }, /* R1038 */ | ||
1136 | { 0x0000, 0x0000, 0x0000 }, /* R1039 */ | ||
1137 | { 0xF800, 0xF800, 0x0000 }, /* R1040 - AIF1 ADC1 Filters */ | ||
1138 | { 0x7800, 0x7800, 0x0000 }, /* R1041 - AIF1 ADC2 Filters */ | ||
1139 | { 0x0000, 0x0000, 0x0000 }, /* R1042 */ | ||
1140 | { 0x0000, 0x0000, 0x0000 }, /* R1043 */ | ||
1141 | { 0x0000, 0x0000, 0x0000 }, /* R1044 */ | ||
1142 | { 0x0000, 0x0000, 0x0000 }, /* R1045 */ | ||
1143 | { 0x0000, 0x0000, 0x0000 }, /* R1046 */ | ||
1144 | { 0x0000, 0x0000, 0x0000 }, /* R1047 */ | ||
1145 | { 0x0000, 0x0000, 0x0000 }, /* R1048 */ | ||
1146 | { 0x0000, 0x0000, 0x0000 }, /* R1049 */ | ||
1147 | { 0x0000, 0x0000, 0x0000 }, /* R1050 */ | ||
1148 | { 0x0000, 0x0000, 0x0000 }, /* R1051 */ | ||
1149 | { 0x0000, 0x0000, 0x0000 }, /* R1052 */ | ||
1150 | { 0x0000, 0x0000, 0x0000 }, /* R1053 */ | ||
1151 | { 0x0000, 0x0000, 0x0000 }, /* R1054 */ | ||
1152 | { 0x0000, 0x0000, 0x0000 }, /* R1055 */ | ||
1153 | { 0x02B6, 0x02B6, 0x0000 }, /* R1056 - AIF1 DAC1 Filters (1) */ | ||
1154 | { 0x3F00, 0x3F00, 0x0000 }, /* R1057 - AIF1 DAC1 Filters (2) */ | ||
1155 | { 0x02B6, 0x02B6, 0x0000 }, /* R1058 - AIF1 DAC2 Filters (1) */ | ||
1156 | { 0x3F00, 0x3F00, 0x0000 }, /* R1059 - AIF1 DAC2 Filters (2) */ | ||
1157 | { 0x0000, 0x0000, 0x0000 }, /* R1060 */ | ||
1158 | { 0x0000, 0x0000, 0x0000 }, /* R1061 */ | ||
1159 | { 0x0000, 0x0000, 0x0000 }, /* R1062 */ | ||
1160 | { 0x0000, 0x0000, 0x0000 }, /* R1063 */ | ||
1161 | { 0x0000, 0x0000, 0x0000 }, /* R1064 */ | ||
1162 | { 0x0000, 0x0000, 0x0000 }, /* R1065 */ | ||
1163 | { 0x0000, 0x0000, 0x0000 }, /* R1066 */ | ||
1164 | { 0x0000, 0x0000, 0x0000 }, /* R1067 */ | ||
1165 | { 0x0000, 0x0000, 0x0000 }, /* R1068 */ | ||
1166 | { 0x0000, 0x0000, 0x0000 }, /* R1069 */ | ||
1167 | { 0x0000, 0x0000, 0x0000 }, /* R1070 */ | ||
1168 | { 0x0000, 0x0000, 0x0000 }, /* R1071 */ | ||
1169 | { 0x0000, 0x0000, 0x0000 }, /* R1072 */ | ||
1170 | { 0x0000, 0x0000, 0x0000 }, /* R1073 */ | ||
1171 | { 0x0000, 0x0000, 0x0000 }, /* R1074 */ | ||
1172 | { 0x0000, 0x0000, 0x0000 }, /* R1075 */ | ||
1173 | { 0x0000, 0x0000, 0x0000 }, /* R1076 */ | ||
1174 | { 0x0000, 0x0000, 0x0000 }, /* R1077 */ | ||
1175 | { 0x0000, 0x0000, 0x0000 }, /* R1078 */ | ||
1176 | { 0x0000, 0x0000, 0x0000 }, /* R1079 */ | ||
1177 | { 0x0000, 0x0000, 0x0000 }, /* R1080 */ | ||
1178 | { 0x0000, 0x0000, 0x0000 }, /* R1081 */ | ||
1179 | { 0x0000, 0x0000, 0x0000 }, /* R1082 */ | ||
1180 | { 0x0000, 0x0000, 0x0000 }, /* R1083 */ | ||
1181 | { 0x0000, 0x0000, 0x0000 }, /* R1084 */ | ||
1182 | { 0x0000, 0x0000, 0x0000 }, /* R1085 */ | ||
1183 | { 0x0000, 0x0000, 0x0000 }, /* R1086 */ | ||
1184 | { 0x0000, 0x0000, 0x0000 }, /* R1087 */ | ||
1185 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1088 - AIF1 DRC1 (1) */ | ||
1186 | { 0x1FFF, 0x1FFF, 0x0000 }, /* R1089 - AIF1 DRC1 (2) */ | ||
1187 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1090 - AIF1 DRC1 (3) */ | ||
1188 | { 0x07FF, 0x07FF, 0x0000 }, /* R1091 - AIF1 DRC1 (4) */ | ||
1189 | { 0x03FF, 0x03FF, 0x0000 }, /* R1092 - AIF1 DRC1 (5) */ | ||
1190 | { 0x0000, 0x0000, 0x0000 }, /* R1093 */ | ||
1191 | { 0x0000, 0x0000, 0x0000 }, /* R1094 */ | ||
1192 | { 0x0000, 0x0000, 0x0000 }, /* R1095 */ | ||
1193 | { 0x0000, 0x0000, 0x0000 }, /* R1096 */ | ||
1194 | { 0x0000, 0x0000, 0x0000 }, /* R1097 */ | ||
1195 | { 0x0000, 0x0000, 0x0000 }, /* R1098 */ | ||
1196 | { 0x0000, 0x0000, 0x0000 }, /* R1099 */ | ||
1197 | { 0x0000, 0x0000, 0x0000 }, /* R1100 */ | ||
1198 | { 0x0000, 0x0000, 0x0000 }, /* R1101 */ | ||
1199 | { 0x0000, 0x0000, 0x0000 }, /* R1102 */ | ||
1200 | { 0x0000, 0x0000, 0x0000 }, /* R1103 */ | ||
1201 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1104 - AIF1 DRC2 (1) */ | ||
1202 | { 0x1FFF, 0x1FFF, 0x0000 }, /* R1105 - AIF1 DRC2 (2) */ | ||
1203 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1106 - AIF1 DRC2 (3) */ | ||
1204 | { 0x07FF, 0x07FF, 0x0000 }, /* R1107 - AIF1 DRC2 (4) */ | ||
1205 | { 0x03FF, 0x03FF, 0x0000 }, /* R1108 - AIF1 DRC2 (5) */ | ||
1206 | { 0x0000, 0x0000, 0x0000 }, /* R1109 */ | ||
1207 | { 0x0000, 0x0000, 0x0000 }, /* R1110 */ | ||
1208 | { 0x0000, 0x0000, 0x0000 }, /* R1111 */ | ||
1209 | { 0x0000, 0x0000, 0x0000 }, /* R1112 */ | ||
1210 | { 0x0000, 0x0000, 0x0000 }, /* R1113 */ | ||
1211 | { 0x0000, 0x0000, 0x0000 }, /* R1114 */ | ||
1212 | { 0x0000, 0x0000, 0x0000 }, /* R1115 */ | ||
1213 | { 0x0000, 0x0000, 0x0000 }, /* R1116 */ | ||
1214 | { 0x0000, 0x0000, 0x0000 }, /* R1117 */ | ||
1215 | { 0x0000, 0x0000, 0x0000 }, /* R1118 */ | ||
1216 | { 0x0000, 0x0000, 0x0000 }, /* R1119 */ | ||
1217 | { 0x0000, 0x0000, 0x0000 }, /* R1120 */ | ||
1218 | { 0x0000, 0x0000, 0x0000 }, /* R1121 */ | ||
1219 | { 0x0000, 0x0000, 0x0000 }, /* R1122 */ | ||
1220 | { 0x0000, 0x0000, 0x0000 }, /* R1123 */ | ||
1221 | { 0x0000, 0x0000, 0x0000 }, /* R1124 */ | ||
1222 | { 0x0000, 0x0000, 0x0000 }, /* R1125 */ | ||
1223 | { 0x0000, 0x0000, 0x0000 }, /* R1126 */ | ||
1224 | { 0x0000, 0x0000, 0x0000 }, /* R1127 */ | ||
1225 | { 0x0000, 0x0000, 0x0000 }, /* R1128 */ | ||
1226 | { 0x0000, 0x0000, 0x0000 }, /* R1129 */ | ||
1227 | { 0x0000, 0x0000, 0x0000 }, /* R1130 */ | ||
1228 | { 0x0000, 0x0000, 0x0000 }, /* R1131 */ | ||
1229 | { 0x0000, 0x0000, 0x0000 }, /* R1132 */ | ||
1230 | { 0x0000, 0x0000, 0x0000 }, /* R1133 */ | ||
1231 | { 0x0000, 0x0000, 0x0000 }, /* R1134 */ | ||
1232 | { 0x0000, 0x0000, 0x0000 }, /* R1135 */ | ||
1233 | { 0x0000, 0x0000, 0x0000 }, /* R1136 */ | ||
1234 | { 0x0000, 0x0000, 0x0000 }, /* R1137 */ | ||
1235 | { 0x0000, 0x0000, 0x0000 }, /* R1138 */ | ||
1236 | { 0x0000, 0x0000, 0x0000 }, /* R1139 */ | ||
1237 | { 0x0000, 0x0000, 0x0000 }, /* R1140 */ | ||
1238 | { 0x0000, 0x0000, 0x0000 }, /* R1141 */ | ||
1239 | { 0x0000, 0x0000, 0x0000 }, /* R1142 */ | ||
1240 | { 0x0000, 0x0000, 0x0000 }, /* R1143 */ | ||
1241 | { 0x0000, 0x0000, 0x0000 }, /* R1144 */ | ||
1242 | { 0x0000, 0x0000, 0x0000 }, /* R1145 */ | ||
1243 | { 0x0000, 0x0000, 0x0000 }, /* R1146 */ | ||
1244 | { 0x0000, 0x0000, 0x0000 }, /* R1147 */ | ||
1245 | { 0x0000, 0x0000, 0x0000 }, /* R1148 */ | ||
1246 | { 0x0000, 0x0000, 0x0000 }, /* R1149 */ | ||
1247 | { 0x0000, 0x0000, 0x0000 }, /* R1150 */ | ||
1248 | { 0x0000, 0x0000, 0x0000 }, /* R1151 */ | ||
1249 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1152 - AIF1 DAC1 EQ Gains (1) */ | ||
1250 | { 0xFFC0, 0xFFC0, 0x0000 }, /* R1153 - AIF1 DAC1 EQ Gains (2) */ | ||
1251 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1154 - AIF1 DAC1 EQ Band 1 A */ | ||
1252 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1155 - AIF1 DAC1 EQ Band 1 B */ | ||
1253 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1156 - AIF1 DAC1 EQ Band 1 PG */ | ||
1254 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1157 - AIF1 DAC1 EQ Band 2 A */ | ||
1255 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1158 - AIF1 DAC1 EQ Band 2 B */ | ||
1256 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1159 - AIF1 DAC1 EQ Band 2 C */ | ||
1257 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1160 - AIF1 DAC1 EQ Band 2 PG */ | ||
1258 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1161 - AIF1 DAC1 EQ Band 3 A */ | ||
1259 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1162 - AIF1 DAC1 EQ Band 3 B */ | ||
1260 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1163 - AIF1 DAC1 EQ Band 3 C */ | ||
1261 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1164 - AIF1 DAC1 EQ Band 3 PG */ | ||
1262 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1165 - AIF1 DAC1 EQ Band 4 A */ | ||
1263 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1166 - AIF1 DAC1 EQ Band 4 B */ | ||
1264 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1167 - AIF1 DAC1 EQ Band 4 C */ | ||
1265 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1168 - AIF1 DAC1 EQ Band 4 PG */ | ||
1266 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1169 - AIF1 DAC1 EQ Band 5 A */ | ||
1267 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1170 - AIF1 DAC1 EQ Band 5 B */ | ||
1268 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1171 - AIF1 DAC1 EQ Band 5 PG */ | ||
1269 | { 0x0000, 0x0000, 0x0000 }, /* R1172 */ | ||
1270 | { 0x0000, 0x0000, 0x0000 }, /* R1173 */ | ||
1271 | { 0x0000, 0x0000, 0x0000 }, /* R1174 */ | ||
1272 | { 0x0000, 0x0000, 0x0000 }, /* R1175 */ | ||
1273 | { 0x0000, 0x0000, 0x0000 }, /* R1176 */ | ||
1274 | { 0x0000, 0x0000, 0x0000 }, /* R1177 */ | ||
1275 | { 0x0000, 0x0000, 0x0000 }, /* R1178 */ | ||
1276 | { 0x0000, 0x0000, 0x0000 }, /* R1179 */ | ||
1277 | { 0x0000, 0x0000, 0x0000 }, /* R1180 */ | ||
1278 | { 0x0000, 0x0000, 0x0000 }, /* R1181 */ | ||
1279 | { 0x0000, 0x0000, 0x0000 }, /* R1182 */ | ||
1280 | { 0x0000, 0x0000, 0x0000 }, /* R1183 */ | ||
1281 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1184 - AIF1 DAC2 EQ Gains (1) */ | ||
1282 | { 0xFFC0, 0xFFC0, 0x0000 }, /* R1185 - AIF1 DAC2 EQ Gains (2) */ | ||
1283 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1186 - AIF1 DAC2 EQ Band 1 A */ | ||
1284 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1187 - AIF1 DAC2 EQ Band 1 B */ | ||
1285 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1188 - AIF1 DAC2 EQ Band 1 PG */ | ||
1286 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1189 - AIF1 DAC2 EQ Band 2 A */ | ||
1287 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1190 - AIF1 DAC2 EQ Band 2 B */ | ||
1288 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1191 - AIF1 DAC2 EQ Band 2 C */ | ||
1289 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1192 - AIF1 DAC2 EQ Band 2 PG */ | ||
1290 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1193 - AIF1 DAC2 EQ Band 3 A */ | ||
1291 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1194 - AIF1 DAC2 EQ Band 3 B */ | ||
1292 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1195 - AIF1 DAC2 EQ Band 3 C */ | ||
1293 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1196 - AIF1 DAC2 EQ Band 3 PG */ | ||
1294 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1197 - AIF1 DAC2 EQ Band 4 A */ | ||
1295 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1198 - AIF1 DAC2 EQ Band 4 B */ | ||
1296 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1199 - AIF1 DAC2 EQ Band 4 C */ | ||
1297 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1200 - AIF1 DAC2 EQ Band 4 PG */ | ||
1298 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1201 - AIF1 DAC2 EQ Band 5 A */ | ||
1299 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1202 - AIF1 DAC2 EQ Band 5 B */ | ||
1300 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1203 - AIF1 DAC2 EQ Band 5 PG */ | ||
1301 | { 0x0000, 0x0000, 0x0000 }, /* R1204 */ | ||
1302 | { 0x0000, 0x0000, 0x0000 }, /* R1205 */ | ||
1303 | { 0x0000, 0x0000, 0x0000 }, /* R1206 */ | ||
1304 | { 0x0000, 0x0000, 0x0000 }, /* R1207 */ | ||
1305 | { 0x0000, 0x0000, 0x0000 }, /* R1208 */ | ||
1306 | { 0x0000, 0x0000, 0x0000 }, /* R1209 */ | ||
1307 | { 0x0000, 0x0000, 0x0000 }, /* R1210 */ | ||
1308 | { 0x0000, 0x0000, 0x0000 }, /* R1211 */ | ||
1309 | { 0x0000, 0x0000, 0x0000 }, /* R1212 */ | ||
1310 | { 0x0000, 0x0000, 0x0000 }, /* R1213 */ | ||
1311 | { 0x0000, 0x0000, 0x0000 }, /* R1214 */ | ||
1312 | { 0x0000, 0x0000, 0x0000 }, /* R1215 */ | ||
1313 | { 0x0000, 0x0000, 0x0000 }, /* R1216 */ | ||
1314 | { 0x0000, 0x0000, 0x0000 }, /* R1217 */ | ||
1315 | { 0x0000, 0x0000, 0x0000 }, /* R1218 */ | ||
1316 | { 0x0000, 0x0000, 0x0000 }, /* R1219 */ | ||
1317 | { 0x0000, 0x0000, 0x0000 }, /* R1220 */ | ||
1318 | { 0x0000, 0x0000, 0x0000 }, /* R1221 */ | ||
1319 | { 0x0000, 0x0000, 0x0000 }, /* R1222 */ | ||
1320 | { 0x0000, 0x0000, 0x0000 }, /* R1223 */ | ||
1321 | { 0x0000, 0x0000, 0x0000 }, /* R1224 */ | ||
1322 | { 0x0000, 0x0000, 0x0000 }, /* R1225 */ | ||
1323 | { 0x0000, 0x0000, 0x0000 }, /* R1226 */ | ||
1324 | { 0x0000, 0x0000, 0x0000 }, /* R1227 */ | ||
1325 | { 0x0000, 0x0000, 0x0000 }, /* R1228 */ | ||
1326 | { 0x0000, 0x0000, 0x0000 }, /* R1229 */ | ||
1327 | { 0x0000, 0x0000, 0x0000 }, /* R1230 */ | ||
1328 | { 0x0000, 0x0000, 0x0000 }, /* R1231 */ | ||
1329 | { 0x0000, 0x0000, 0x0000 }, /* R1232 */ | ||
1330 | { 0x0000, 0x0000, 0x0000 }, /* R1233 */ | ||
1331 | { 0x0000, 0x0000, 0x0000 }, /* R1234 */ | ||
1332 | { 0x0000, 0x0000, 0x0000 }, /* R1235 */ | ||
1333 | { 0x0000, 0x0000, 0x0000 }, /* R1236 */ | ||
1334 | { 0x0000, 0x0000, 0x0000 }, /* R1237 */ | ||
1335 | { 0x0000, 0x0000, 0x0000 }, /* R1238 */ | ||
1336 | { 0x0000, 0x0000, 0x0000 }, /* R1239 */ | ||
1337 | { 0x0000, 0x0000, 0x0000 }, /* R1240 */ | ||
1338 | { 0x0000, 0x0000, 0x0000 }, /* R1241 */ | ||
1339 | { 0x0000, 0x0000, 0x0000 }, /* R1242 */ | ||
1340 | { 0x0000, 0x0000, 0x0000 }, /* R1243 */ | ||
1341 | { 0x0000, 0x0000, 0x0000 }, /* R1244 */ | ||
1342 | { 0x0000, 0x0000, 0x0000 }, /* R1245 */ | ||
1343 | { 0x0000, 0x0000, 0x0000 }, /* R1246 */ | ||
1344 | { 0x0000, 0x0000, 0x0000 }, /* R1247 */ | ||
1345 | { 0x0000, 0x0000, 0x0000 }, /* R1248 */ | ||
1346 | { 0x0000, 0x0000, 0x0000 }, /* R1249 */ | ||
1347 | { 0x0000, 0x0000, 0x0000 }, /* R1250 */ | ||
1348 | { 0x0000, 0x0000, 0x0000 }, /* R1251 */ | ||
1349 | { 0x0000, 0x0000, 0x0000 }, /* R1252 */ | ||
1350 | { 0x0000, 0x0000, 0x0000 }, /* R1253 */ | ||
1351 | { 0x0000, 0x0000, 0x0000 }, /* R1254 */ | ||
1352 | { 0x0000, 0x0000, 0x0000 }, /* R1255 */ | ||
1353 | { 0x0000, 0x0000, 0x0000 }, /* R1256 */ | ||
1354 | { 0x0000, 0x0000, 0x0000 }, /* R1257 */ | ||
1355 | { 0x0000, 0x0000, 0x0000 }, /* R1258 */ | ||
1356 | { 0x0000, 0x0000, 0x0000 }, /* R1259 */ | ||
1357 | { 0x0000, 0x0000, 0x0000 }, /* R1260 */ | ||
1358 | { 0x0000, 0x0000, 0x0000 }, /* R1261 */ | ||
1359 | { 0x0000, 0x0000, 0x0000 }, /* R1262 */ | ||
1360 | { 0x0000, 0x0000, 0x0000 }, /* R1263 */ | ||
1361 | { 0x0000, 0x0000, 0x0000 }, /* R1264 */ | ||
1362 | { 0x0000, 0x0000, 0x0000 }, /* R1265 */ | ||
1363 | { 0x0000, 0x0000, 0x0000 }, /* R1266 */ | ||
1364 | { 0x0000, 0x0000, 0x0000 }, /* R1267 */ | ||
1365 | { 0x0000, 0x0000, 0x0000 }, /* R1268 */ | ||
1366 | { 0x0000, 0x0000, 0x0000 }, /* R1269 */ | ||
1367 | { 0x0000, 0x0000, 0x0000 }, /* R1270 */ | ||
1368 | { 0x0000, 0x0000, 0x0000 }, /* R1271 */ | ||
1369 | { 0x0000, 0x0000, 0x0000 }, /* R1272 */ | ||
1370 | { 0x0000, 0x0000, 0x0000 }, /* R1273 */ | ||
1371 | { 0x0000, 0x0000, 0x0000 }, /* R1274 */ | ||
1372 | { 0x0000, 0x0000, 0x0000 }, /* R1275 */ | ||
1373 | { 0x0000, 0x0000, 0x0000 }, /* R1276 */ | ||
1374 | { 0x0000, 0x0000, 0x0000 }, /* R1277 */ | ||
1375 | { 0x0000, 0x0000, 0x0000 }, /* R1278 */ | ||
1376 | { 0x0000, 0x0000, 0x0000 }, /* R1279 */ | ||
1377 | { 0x00FF, 0x01FF, 0x0000 }, /* R1280 - AIF2 ADC Left Volume */ | ||
1378 | { 0x00FF, 0x01FF, 0x0000 }, /* R1281 - AIF2 ADC Right Volume */ | ||
1379 | { 0x00FF, 0x01FF, 0x0000 }, /* R1282 - AIF2 DAC Left Volume */ | ||
1380 | { 0x00FF, 0x01FF, 0x0000 }, /* R1283 - AIF2 DAC Right Volume */ | ||
1381 | { 0x0000, 0x0000, 0x0000 }, /* R1284 */ | ||
1382 | { 0x0000, 0x0000, 0x0000 }, /* R1285 */ | ||
1383 | { 0x0000, 0x0000, 0x0000 }, /* R1286 */ | ||
1384 | { 0x0000, 0x0000, 0x0000 }, /* R1287 */ | ||
1385 | { 0x0000, 0x0000, 0x0000 }, /* R1288 */ | ||
1386 | { 0x0000, 0x0000, 0x0000 }, /* R1289 */ | ||
1387 | { 0x0000, 0x0000, 0x0000 }, /* R1290 */ | ||
1388 | { 0x0000, 0x0000, 0x0000 }, /* R1291 */ | ||
1389 | { 0x0000, 0x0000, 0x0000 }, /* R1292 */ | ||
1390 | { 0x0000, 0x0000, 0x0000 }, /* R1293 */ | ||
1391 | { 0x0000, 0x0000, 0x0000 }, /* R1294 */ | ||
1392 | { 0x0000, 0x0000, 0x0000 }, /* R1295 */ | ||
1393 | { 0xF800, 0xF800, 0x0000 }, /* R1296 - AIF2 ADC Filters */ | ||
1394 | { 0x0000, 0x0000, 0x0000 }, /* R1297 */ | ||
1395 | { 0x0000, 0x0000, 0x0000 }, /* R1298 */ | ||
1396 | { 0x0000, 0x0000, 0x0000 }, /* R1299 */ | ||
1397 | { 0x0000, 0x0000, 0x0000 }, /* R1300 */ | ||
1398 | { 0x0000, 0x0000, 0x0000 }, /* R1301 */ | ||
1399 | { 0x0000, 0x0000, 0x0000 }, /* R1302 */ | ||
1400 | { 0x0000, 0x0000, 0x0000 }, /* R1303 */ | ||
1401 | { 0x0000, 0x0000, 0x0000 }, /* R1304 */ | ||
1402 | { 0x0000, 0x0000, 0x0000 }, /* R1305 */ | ||
1403 | { 0x0000, 0x0000, 0x0000 }, /* R1306 */ | ||
1404 | { 0x0000, 0x0000, 0x0000 }, /* R1307 */ | ||
1405 | { 0x0000, 0x0000, 0x0000 }, /* R1308 */ | ||
1406 | { 0x0000, 0x0000, 0x0000 }, /* R1309 */ | ||
1407 | { 0x0000, 0x0000, 0x0000 }, /* R1310 */ | ||
1408 | { 0x0000, 0x0000, 0x0000 }, /* R1311 */ | ||
1409 | { 0x02B6, 0x02B6, 0x0000 }, /* R1312 - AIF2 DAC Filters (1) */ | ||
1410 | { 0x3F00, 0x3F00, 0x0000 }, /* R1313 - AIF2 DAC Filters (2) */ | ||
1411 | { 0x0000, 0x0000, 0x0000 }, /* R1314 */ | ||
1412 | { 0x0000, 0x0000, 0x0000 }, /* R1315 */ | ||
1413 | { 0x0000, 0x0000, 0x0000 }, /* R1316 */ | ||
1414 | { 0x0000, 0x0000, 0x0000 }, /* R1317 */ | ||
1415 | { 0x0000, 0x0000, 0x0000 }, /* R1318 */ | ||
1416 | { 0x0000, 0x0000, 0x0000 }, /* R1319 */ | ||
1417 | { 0x0000, 0x0000, 0x0000 }, /* R1320 */ | ||
1418 | { 0x0000, 0x0000, 0x0000 }, /* R1321 */ | ||
1419 | { 0x0000, 0x0000, 0x0000 }, /* R1322 */ | ||
1420 | { 0x0000, 0x0000, 0x0000 }, /* R1323 */ | ||
1421 | { 0x0000, 0x0000, 0x0000 }, /* R1324 */ | ||
1422 | { 0x0000, 0x0000, 0x0000 }, /* R1325 */ | ||
1423 | { 0x0000, 0x0000, 0x0000 }, /* R1326 */ | ||
1424 | { 0x0000, 0x0000, 0x0000 }, /* R1327 */ | ||
1425 | { 0x0000, 0x0000, 0x0000 }, /* R1328 */ | ||
1426 | { 0x0000, 0x0000, 0x0000 }, /* R1329 */ | ||
1427 | { 0x0000, 0x0000, 0x0000 }, /* R1330 */ | ||
1428 | { 0x0000, 0x0000, 0x0000 }, /* R1331 */ | ||
1429 | { 0x0000, 0x0000, 0x0000 }, /* R1332 */ | ||
1430 | { 0x0000, 0x0000, 0x0000 }, /* R1333 */ | ||
1431 | { 0x0000, 0x0000, 0x0000 }, /* R1334 */ | ||
1432 | { 0x0000, 0x0000, 0x0000 }, /* R1335 */ | ||
1433 | { 0x0000, 0x0000, 0x0000 }, /* R1336 */ | ||
1434 | { 0x0000, 0x0000, 0x0000 }, /* R1337 */ | ||
1435 | { 0x0000, 0x0000, 0x0000 }, /* R1338 */ | ||
1436 | { 0x0000, 0x0000, 0x0000 }, /* R1339 */ | ||
1437 | { 0x0000, 0x0000, 0x0000 }, /* R1340 */ | ||
1438 | { 0x0000, 0x0000, 0x0000 }, /* R1341 */ | ||
1439 | { 0x0000, 0x0000, 0x0000 }, /* R1342 */ | ||
1440 | { 0x0000, 0x0000, 0x0000 }, /* R1343 */ | ||
1441 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1344 - AIF2 DRC (1) */ | ||
1442 | { 0x1FFF, 0x1FFF, 0x0000 }, /* R1345 - AIF2 DRC (2) */ | ||
1443 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1346 - AIF2 DRC (3) */ | ||
1444 | { 0x07FF, 0x07FF, 0x0000 }, /* R1347 - AIF2 DRC (4) */ | ||
1445 | { 0x03FF, 0x03FF, 0x0000 }, /* R1348 - AIF2 DRC (5) */ | ||
1446 | { 0x0000, 0x0000, 0x0000 }, /* R1349 */ | ||
1447 | { 0x0000, 0x0000, 0x0000 }, /* R1350 */ | ||
1448 | { 0x0000, 0x0000, 0x0000 }, /* R1351 */ | ||
1449 | { 0x0000, 0x0000, 0x0000 }, /* R1352 */ | ||
1450 | { 0x0000, 0x0000, 0x0000 }, /* R1353 */ | ||
1451 | { 0x0000, 0x0000, 0x0000 }, /* R1354 */ | ||
1452 | { 0x0000, 0x0000, 0x0000 }, /* R1355 */ | ||
1453 | { 0x0000, 0x0000, 0x0000 }, /* R1356 */ | ||
1454 | { 0x0000, 0x0000, 0x0000 }, /* R1357 */ | ||
1455 | { 0x0000, 0x0000, 0x0000 }, /* R1358 */ | ||
1456 | { 0x0000, 0x0000, 0x0000 }, /* R1359 */ | ||
1457 | { 0x0000, 0x0000, 0x0000 }, /* R1360 */ | ||
1458 | { 0x0000, 0x0000, 0x0000 }, /* R1361 */ | ||
1459 | { 0x0000, 0x0000, 0x0000 }, /* R1362 */ | ||
1460 | { 0x0000, 0x0000, 0x0000 }, /* R1363 */ | ||
1461 | { 0x0000, 0x0000, 0x0000 }, /* R1364 */ | ||
1462 | { 0x0000, 0x0000, 0x0000 }, /* R1365 */ | ||
1463 | { 0x0000, 0x0000, 0x0000 }, /* R1366 */ | ||
1464 | { 0x0000, 0x0000, 0x0000 }, /* R1367 */ | ||
1465 | { 0x0000, 0x0000, 0x0000 }, /* R1368 */ | ||
1466 | { 0x0000, 0x0000, 0x0000 }, /* R1369 */ | ||
1467 | { 0x0000, 0x0000, 0x0000 }, /* R1370 */ | ||
1468 | { 0x0000, 0x0000, 0x0000 }, /* R1371 */ | ||
1469 | { 0x0000, 0x0000, 0x0000 }, /* R1372 */ | ||
1470 | { 0x0000, 0x0000, 0x0000 }, /* R1373 */ | ||
1471 | { 0x0000, 0x0000, 0x0000 }, /* R1374 */ | ||
1472 | { 0x0000, 0x0000, 0x0000 }, /* R1375 */ | ||
1473 | { 0x0000, 0x0000, 0x0000 }, /* R1376 */ | ||
1474 | { 0x0000, 0x0000, 0x0000 }, /* R1377 */ | ||
1475 | { 0x0000, 0x0000, 0x0000 }, /* R1378 */ | ||
1476 | { 0x0000, 0x0000, 0x0000 }, /* R1379 */ | ||
1477 | { 0x0000, 0x0000, 0x0000 }, /* R1380 */ | ||
1478 | { 0x0000, 0x0000, 0x0000 }, /* R1381 */ | ||
1479 | { 0x0000, 0x0000, 0x0000 }, /* R1382 */ | ||
1480 | { 0x0000, 0x0000, 0x0000 }, /* R1383 */ | ||
1481 | { 0x0000, 0x0000, 0x0000 }, /* R1384 */ | ||
1482 | { 0x0000, 0x0000, 0x0000 }, /* R1385 */ | ||
1483 | { 0x0000, 0x0000, 0x0000 }, /* R1386 */ | ||
1484 | { 0x0000, 0x0000, 0x0000 }, /* R1387 */ | ||
1485 | { 0x0000, 0x0000, 0x0000 }, /* R1388 */ | ||
1486 | { 0x0000, 0x0000, 0x0000 }, /* R1389 */ | ||
1487 | { 0x0000, 0x0000, 0x0000 }, /* R1390 */ | ||
1488 | { 0x0000, 0x0000, 0x0000 }, /* R1391 */ | ||
1489 | { 0x0000, 0x0000, 0x0000 }, /* R1392 */ | ||
1490 | { 0x0000, 0x0000, 0x0000 }, /* R1393 */ | ||
1491 | { 0x0000, 0x0000, 0x0000 }, /* R1394 */ | ||
1492 | { 0x0000, 0x0000, 0x0000 }, /* R1395 */ | ||
1493 | { 0x0000, 0x0000, 0x0000 }, /* R1396 */ | ||
1494 | { 0x0000, 0x0000, 0x0000 }, /* R1397 */ | ||
1495 | { 0x0000, 0x0000, 0x0000 }, /* R1398 */ | ||
1496 | { 0x0000, 0x0000, 0x0000 }, /* R1399 */ | ||
1497 | { 0x0000, 0x0000, 0x0000 }, /* R1400 */ | ||
1498 | { 0x0000, 0x0000, 0x0000 }, /* R1401 */ | ||
1499 | { 0x0000, 0x0000, 0x0000 }, /* R1402 */ | ||
1500 | { 0x0000, 0x0000, 0x0000 }, /* R1403 */ | ||
1501 | { 0x0000, 0x0000, 0x0000 }, /* R1404 */ | ||
1502 | { 0x0000, 0x0000, 0x0000 }, /* R1405 */ | ||
1503 | { 0x0000, 0x0000, 0x0000 }, /* R1406 */ | ||
1504 | { 0x0000, 0x0000, 0x0000 }, /* R1407 */ | ||
1505 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1408 - AIF2 EQ Gains (1) */ | ||
1506 | { 0xFFC0, 0xFFC0, 0x0000 }, /* R1409 - AIF2 EQ Gains (2) */ | ||
1507 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1410 - AIF2 EQ Band 1 A */ | ||
1508 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1411 - AIF2 EQ Band 1 B */ | ||
1509 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1412 - AIF2 EQ Band 1 PG */ | ||
1510 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1413 - AIF2 EQ Band 2 A */ | ||
1511 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1414 - AIF2 EQ Band 2 B */ | ||
1512 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1415 - AIF2 EQ Band 2 C */ | ||
1513 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1416 - AIF2 EQ Band 2 PG */ | ||
1514 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1417 - AIF2 EQ Band 3 A */ | ||
1515 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1418 - AIF2 EQ Band 3 B */ | ||
1516 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1419 - AIF2 EQ Band 3 C */ | ||
1517 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1420 - AIF2 EQ Band 3 PG */ | ||
1518 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1421 - AIF2 EQ Band 4 A */ | ||
1519 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1422 - AIF2 EQ Band 4 B */ | ||
1520 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1423 - AIF2 EQ Band 4 C */ | ||
1521 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1424 - AIF2 EQ Band 4 PG */ | ||
1522 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1425 - AIF2 EQ Band 5 A */ | ||
1523 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1426 - AIF2 EQ Band 5 B */ | ||
1524 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R1427 - AIF2 EQ Band 5 PG */ | ||
1525 | { 0x0000, 0x0000, 0x0000 }, /* R1428 */ | ||
1526 | { 0x0000, 0x0000, 0x0000 }, /* R1429 */ | ||
1527 | { 0x0000, 0x0000, 0x0000 }, /* R1430 */ | ||
1528 | { 0x0000, 0x0000, 0x0000 }, /* R1431 */ | ||
1529 | { 0x0000, 0x0000, 0x0000 }, /* R1432 */ | ||
1530 | { 0x0000, 0x0000, 0x0000 }, /* R1433 */ | ||
1531 | { 0x0000, 0x0000, 0x0000 }, /* R1434 */ | ||
1532 | { 0x0000, 0x0000, 0x0000 }, /* R1435 */ | ||
1533 | { 0x0000, 0x0000, 0x0000 }, /* R1436 */ | ||
1534 | { 0x0000, 0x0000, 0x0000 }, /* R1437 */ | ||
1535 | { 0x0000, 0x0000, 0x0000 }, /* R1438 */ | ||
1536 | { 0x0000, 0x0000, 0x0000 }, /* R1439 */ | ||
1537 | { 0x0000, 0x0000, 0x0000 }, /* R1440 */ | ||
1538 | { 0x0000, 0x0000, 0x0000 }, /* R1441 */ | ||
1539 | { 0x0000, 0x0000, 0x0000 }, /* R1442 */ | ||
1540 | { 0x0000, 0x0000, 0x0000 }, /* R1443 */ | ||
1541 | { 0x0000, 0x0000, 0x0000 }, /* R1444 */ | ||
1542 | { 0x0000, 0x0000, 0x0000 }, /* R1445 */ | ||
1543 | { 0x0000, 0x0000, 0x0000 }, /* R1446 */ | ||
1544 | { 0x0000, 0x0000, 0x0000 }, /* R1447 */ | ||
1545 | { 0x0000, 0x0000, 0x0000 }, /* R1448 */ | ||
1546 | { 0x0000, 0x0000, 0x0000 }, /* R1449 */ | ||
1547 | { 0x0000, 0x0000, 0x0000 }, /* R1450 */ | ||
1548 | { 0x0000, 0x0000, 0x0000 }, /* R1451 */ | ||
1549 | { 0x0000, 0x0000, 0x0000 }, /* R1452 */ | ||
1550 | { 0x0000, 0x0000, 0x0000 }, /* R1453 */ | ||
1551 | { 0x0000, 0x0000, 0x0000 }, /* R1454 */ | ||
1552 | { 0x0000, 0x0000, 0x0000 }, /* R1455 */ | ||
1553 | { 0x0000, 0x0000, 0x0000 }, /* R1456 */ | ||
1554 | { 0x0000, 0x0000, 0x0000 }, /* R1457 */ | ||
1555 | { 0x0000, 0x0000, 0x0000 }, /* R1458 */ | ||
1556 | { 0x0000, 0x0000, 0x0000 }, /* R1459 */ | ||
1557 | { 0x0000, 0x0000, 0x0000 }, /* R1460 */ | ||
1558 | { 0x0000, 0x0000, 0x0000 }, /* R1461 */ | ||
1559 | { 0x0000, 0x0000, 0x0000 }, /* R1462 */ | ||
1560 | { 0x0000, 0x0000, 0x0000 }, /* R1463 */ | ||
1561 | { 0x0000, 0x0000, 0x0000 }, /* R1464 */ | ||
1562 | { 0x0000, 0x0000, 0x0000 }, /* R1465 */ | ||
1563 | { 0x0000, 0x0000, 0x0000 }, /* R1466 */ | ||
1564 | { 0x0000, 0x0000, 0x0000 }, /* R1467 */ | ||
1565 | { 0x0000, 0x0000, 0x0000 }, /* R1468 */ | ||
1566 | { 0x0000, 0x0000, 0x0000 }, /* R1469 */ | ||
1567 | { 0x0000, 0x0000, 0x0000 }, /* R1470 */ | ||
1568 | { 0x0000, 0x0000, 0x0000 }, /* R1471 */ | ||
1569 | { 0x0000, 0x0000, 0x0000 }, /* R1472 */ | ||
1570 | { 0x0000, 0x0000, 0x0000 }, /* R1473 */ | ||
1571 | { 0x0000, 0x0000, 0x0000 }, /* R1474 */ | ||
1572 | { 0x0000, 0x0000, 0x0000 }, /* R1475 */ | ||
1573 | { 0x0000, 0x0000, 0x0000 }, /* R1476 */ | ||
1574 | { 0x0000, 0x0000, 0x0000 }, /* R1477 */ | ||
1575 | { 0x0000, 0x0000, 0x0000 }, /* R1478 */ | ||
1576 | { 0x0000, 0x0000, 0x0000 }, /* R1479 */ | ||
1577 | { 0x0000, 0x0000, 0x0000 }, /* R1480 */ | ||
1578 | { 0x0000, 0x0000, 0x0000 }, /* R1481 */ | ||
1579 | { 0x0000, 0x0000, 0x0000 }, /* R1482 */ | ||
1580 | { 0x0000, 0x0000, 0x0000 }, /* R1483 */ | ||
1581 | { 0x0000, 0x0000, 0x0000 }, /* R1484 */ | ||
1582 | { 0x0000, 0x0000, 0x0000 }, /* R1485 */ | ||
1583 | { 0x0000, 0x0000, 0x0000 }, /* R1486 */ | ||
1584 | { 0x0000, 0x0000, 0x0000 }, /* R1487 */ | ||
1585 | { 0x0000, 0x0000, 0x0000 }, /* R1488 */ | ||
1586 | { 0x0000, 0x0000, 0x0000 }, /* R1489 */ | ||
1587 | { 0x0000, 0x0000, 0x0000 }, /* R1490 */ | ||
1588 | { 0x0000, 0x0000, 0x0000 }, /* R1491 */ | ||
1589 | { 0x0000, 0x0000, 0x0000 }, /* R1492 */ | ||
1590 | { 0x0000, 0x0000, 0x0000 }, /* R1493 */ | ||
1591 | { 0x0000, 0x0000, 0x0000 }, /* R1494 */ | ||
1592 | { 0x0000, 0x0000, 0x0000 }, /* R1495 */ | ||
1593 | { 0x0000, 0x0000, 0x0000 }, /* R1496 */ | ||
1594 | { 0x0000, 0x0000, 0x0000 }, /* R1497 */ | ||
1595 | { 0x0000, 0x0000, 0x0000 }, /* R1498 */ | ||
1596 | { 0x0000, 0x0000, 0x0000 }, /* R1499 */ | ||
1597 | { 0x0000, 0x0000, 0x0000 }, /* R1500 */ | ||
1598 | { 0x0000, 0x0000, 0x0000 }, /* R1501 */ | ||
1599 | { 0x0000, 0x0000, 0x0000 }, /* R1502 */ | ||
1600 | { 0x0000, 0x0000, 0x0000 }, /* R1503 */ | ||
1601 | { 0x0000, 0x0000, 0x0000 }, /* R1504 */ | ||
1602 | { 0x0000, 0x0000, 0x0000 }, /* R1505 */ | ||
1603 | { 0x0000, 0x0000, 0x0000 }, /* R1506 */ | ||
1604 | { 0x0000, 0x0000, 0x0000 }, /* R1507 */ | ||
1605 | { 0x0000, 0x0000, 0x0000 }, /* R1508 */ | ||
1606 | { 0x0000, 0x0000, 0x0000 }, /* R1509 */ | ||
1607 | { 0x0000, 0x0000, 0x0000 }, /* R1510 */ | ||
1608 | { 0x0000, 0x0000, 0x0000 }, /* R1511 */ | ||
1609 | { 0x0000, 0x0000, 0x0000 }, /* R1512 */ | ||
1610 | { 0x0000, 0x0000, 0x0000 }, /* R1513 */ | ||
1611 | { 0x0000, 0x0000, 0x0000 }, /* R1514 */ | ||
1612 | { 0x0000, 0x0000, 0x0000 }, /* R1515 */ | ||
1613 | { 0x0000, 0x0000, 0x0000 }, /* R1516 */ | ||
1614 | { 0x0000, 0x0000, 0x0000 }, /* R1517 */ | ||
1615 | { 0x0000, 0x0000, 0x0000 }, /* R1518 */ | ||
1616 | { 0x0000, 0x0000, 0x0000 }, /* R1519 */ | ||
1617 | { 0x0000, 0x0000, 0x0000 }, /* R1520 */ | ||
1618 | { 0x0000, 0x0000, 0x0000 }, /* R1521 */ | ||
1619 | { 0x0000, 0x0000, 0x0000 }, /* R1522 */ | ||
1620 | { 0x0000, 0x0000, 0x0000 }, /* R1523 */ | ||
1621 | { 0x0000, 0x0000, 0x0000 }, /* R1524 */ | ||
1622 | { 0x0000, 0x0000, 0x0000 }, /* R1525 */ | ||
1623 | { 0x0000, 0x0000, 0x0000 }, /* R1526 */ | ||
1624 | { 0x0000, 0x0000, 0x0000 }, /* R1527 */ | ||
1625 | { 0x0000, 0x0000, 0x0000 }, /* R1528 */ | ||
1626 | { 0x0000, 0x0000, 0x0000 }, /* R1529 */ | ||
1627 | { 0x0000, 0x0000, 0x0000 }, /* R1530 */ | ||
1628 | { 0x0000, 0x0000, 0x0000 }, /* R1531 */ | ||
1629 | { 0x0000, 0x0000, 0x0000 }, /* R1532 */ | ||
1630 | { 0x0000, 0x0000, 0x0000 }, /* R1533 */ | ||
1631 | { 0x0000, 0x0000, 0x0000 }, /* R1534 */ | ||
1632 | { 0x0000, 0x0000, 0x0000 }, /* R1535 */ | ||
1633 | { 0x01EF, 0x01EF, 0x0000 }, /* R1536 - DAC1 Mixer Volumes */ | ||
1634 | { 0x0037, 0x0037, 0x0000 }, /* R1537 - DAC1 Left Mixer Routing */ | ||
1635 | { 0x0037, 0x0037, 0x0000 }, /* R1538 - DAC1 Right Mixer Routing */ | ||
1636 | { 0x01EF, 0x01EF, 0x0000 }, /* R1539 - DAC2 Mixer Volumes */ | ||
1637 | { 0x0037, 0x0037, 0x0000 }, /* R1540 - DAC2 Left Mixer Routing */ | ||
1638 | { 0x0037, 0x0037, 0x0000 }, /* R1541 - DAC2 Right Mixer Routing */ | ||
1639 | { 0x0003, 0x0003, 0x0000 }, /* R1542 - AIF1 ADC1 Left Mixer Routing */ | ||
1640 | { 0x0003, 0x0003, 0x0000 }, /* R1543 - AIF1 ADC1 Right Mixer Routing */ | ||
1641 | { 0x0003, 0x0003, 0x0000 }, /* R1544 - AIF1 ADC2 Left Mixer Routing */ | ||
1642 | { 0x0003, 0x0003, 0x0000 }, /* R1545 - AIF1 ADC2 Right mixer Routing */ | ||
1643 | { 0x0000, 0x0000, 0x0000 }, /* R1546 */ | ||
1644 | { 0x0000, 0x0000, 0x0000 }, /* R1547 */ | ||
1645 | { 0x0000, 0x0000, 0x0000 }, /* R1548 */ | ||
1646 | { 0x0000, 0x0000, 0x0000 }, /* R1549 */ | ||
1647 | { 0x0000, 0x0000, 0x0000 }, /* R1550 */ | ||
1648 | { 0x0000, 0x0000, 0x0000 }, /* R1551 */ | ||
1649 | { 0x02FF, 0x03FF, 0x0000 }, /* R1552 - DAC1 Left Volume */ | ||
1650 | { 0x02FF, 0x03FF, 0x0000 }, /* R1553 - DAC1 Right Volume */ | ||
1651 | { 0x02FF, 0x03FF, 0x0000 }, /* R1554 - DAC2 Left Volume */ | ||
1652 | { 0x02FF, 0x03FF, 0x0000 }, /* R1555 - DAC2 Right Volume */ | ||
1653 | { 0x0003, 0x0003, 0x0000 }, /* R1556 - DAC Softmute */ | ||
1654 | { 0x0000, 0x0000, 0x0000 }, /* R1557 */ | ||
1655 | { 0x0000, 0x0000, 0x0000 }, /* R1558 */ | ||
1656 | { 0x0000, 0x0000, 0x0000 }, /* R1559 */ | ||
1657 | { 0x0000, 0x0000, 0x0000 }, /* R1560 */ | ||
1658 | { 0x0000, 0x0000, 0x0000 }, /* R1561 */ | ||
1659 | { 0x0000, 0x0000, 0x0000 }, /* R1562 */ | ||
1660 | { 0x0000, 0x0000, 0x0000 }, /* R1563 */ | ||
1661 | { 0x0000, 0x0000, 0x0000 }, /* R1564 */ | ||
1662 | { 0x0000, 0x0000, 0x0000 }, /* R1565 */ | ||
1663 | { 0x0000, 0x0000, 0x0000 }, /* R1566 */ | ||
1664 | { 0x0000, 0x0000, 0x0000 }, /* R1567 */ | ||
1665 | { 0x0003, 0x0003, 0x0000 }, /* R1568 - Oversampling */ | ||
1666 | { 0x03C3, 0x03C3, 0x0000 }, /* R1569 - Sidetone */ | ||
1667 | }; | ||
1668 | |||
1669 | static int wm8994_readable(unsigned int reg) | ||
1670 | { | ||
1671 | if (reg >= ARRAY_SIZE(access_masks)) | ||
1672 | return 0; | ||
1673 | return access_masks[reg].readable != 0; | ||
1674 | } | ||
1675 | |||
1676 | static int wm8994_volatile(unsigned int reg) | ||
1677 | { | ||
1678 | if (reg >= WM8994_REG_CACHE_SIZE) | ||
1679 | return 1; | ||
1680 | |||
1681 | switch (reg) { | ||
1682 | case WM8994_SOFTWARE_RESET: | ||
1683 | case WM8994_CHIP_REVISION: | ||
1684 | case WM8994_DC_SERVO_1: | ||
1685 | case WM8994_DC_SERVO_READBACK: | ||
1686 | case WM8994_RATE_STATUS: | ||
1687 | case WM8994_LDO_1: | ||
1688 | case WM8994_LDO_2: | ||
1689 | return 1; | ||
1690 | default: | ||
1691 | return 0; | ||
1692 | } | ||
1693 | } | ||
1694 | |||
1695 | static int wm8994_write(struct snd_soc_codec *codec, unsigned int reg, | ||
1696 | unsigned int value) | ||
1697 | { | ||
1698 | struct wm8994_priv *wm8994 = codec->private_data; | ||
1699 | |||
1700 | BUG_ON(reg > WM8994_MAX_REGISTER); | ||
1701 | |||
1702 | if (!wm8994_volatile(reg)) | ||
1703 | wm8994->reg_cache[reg] = value; | ||
1704 | |||
1705 | return wm8994_reg_write(codec->control_data, reg, value); | ||
1706 | } | ||
1707 | |||
1708 | static unsigned int wm8994_read(struct snd_soc_codec *codec, | ||
1709 | unsigned int reg) | ||
1710 | { | ||
1711 | u16 *reg_cache = codec->reg_cache; | ||
1712 | |||
1713 | BUG_ON(reg > WM8994_MAX_REGISTER); | ||
1714 | |||
1715 | if (wm8994_volatile(reg)) | ||
1716 | return wm8994_reg_read(codec->control_data, reg); | ||
1717 | else | ||
1718 | return reg_cache[reg]; | ||
1719 | } | ||
1720 | |||
1721 | static int configure_aif_clock(struct snd_soc_codec *codec, int aif) | ||
1722 | { | ||
1723 | struct wm8994_priv *wm8994 = codec->private_data; | ||
1724 | int rate; | ||
1725 | int reg1 = 0; | ||
1726 | int offset; | ||
1727 | |||
1728 | if (aif) | ||
1729 | offset = 4; | ||
1730 | else | ||
1731 | offset = 0; | ||
1732 | |||
1733 | switch (wm8994->sysclk[aif]) { | ||
1734 | case WM8994_SYSCLK_MCLK1: | ||
1735 | rate = wm8994->mclk[0]; | ||
1736 | break; | ||
1737 | |||
1738 | case WM8994_SYSCLK_MCLK2: | ||
1739 | reg1 |= 0x8; | ||
1740 | rate = wm8994->mclk[1]; | ||
1741 | break; | ||
1742 | |||
1743 | case WM8994_SYSCLK_FLL1: | ||
1744 | reg1 |= 0x10; | ||
1745 | rate = wm8994->fll[0].out; | ||
1746 | break; | ||
1747 | |||
1748 | case WM8994_SYSCLK_FLL2: | ||
1749 | reg1 |= 0x18; | ||
1750 | rate = wm8994->fll[1].out; | ||
1751 | break; | ||
1752 | |||
1753 | default: | ||
1754 | return -EINVAL; | ||
1755 | } | ||
1756 | |||
1757 | if (rate >= 13500000) { | ||
1758 | rate /= 2; | ||
1759 | reg1 |= WM8994_AIF1CLK_DIV; | ||
1760 | |||
1761 | dev_dbg(codec->dev, "Dividing AIF%d clock to %dHz\n", | ||
1762 | aif + 1, rate); | ||
1763 | } | ||
1764 | wm8994->aifclk[aif] = rate; | ||
1765 | |||
1766 | snd_soc_update_bits(codec, WM8994_AIF1_CLOCKING_1 + offset, | ||
1767 | WM8994_AIF1CLK_SRC_MASK | WM8994_AIF1CLK_DIV, | ||
1768 | reg1); | ||
1769 | |||
1770 | return 0; | ||
1771 | } | ||
1772 | |||
1773 | static int configure_clock(struct snd_soc_codec *codec) | ||
1774 | { | ||
1775 | struct wm8994_priv *wm8994 = codec->private_data; | ||
1776 | int old, new; | ||
1777 | |||
1778 | /* Bring up the AIF clocks first */ | ||
1779 | configure_aif_clock(codec, 0); | ||
1780 | configure_aif_clock(codec, 1); | ||
1781 | |||
1782 | /* Then switch CLK_SYS over to the higher of them; a change | ||
1783 | * can only happen as a result of a clocking change which can | ||
1784 | * only be made outside of DAPM so we can safely redo the | ||
1785 | * clocking. | ||
1786 | */ | ||
1787 | |||
1788 | /* If they're equal it doesn't matter which is used */ | ||
1789 | if (wm8994->aifclk[0] == wm8994->aifclk[1]) | ||
1790 | return 0; | ||
1791 | |||
1792 | if (wm8994->aifclk[0] < wm8994->aifclk[1]) | ||
1793 | new = WM8994_SYSCLK_SRC; | ||
1794 | else | ||
1795 | new = 0; | ||
1796 | |||
1797 | old = snd_soc_read(codec, WM8994_CLOCKING_1) & WM8994_SYSCLK_SRC; | ||
1798 | |||
1799 | /* If there's no change then we're done. */ | ||
1800 | if (old == new) | ||
1801 | return 0; | ||
1802 | |||
1803 | snd_soc_update_bits(codec, WM8994_CLOCKING_1, WM8994_SYSCLK_SRC, new); | ||
1804 | |||
1805 | snd_soc_dapm_sync(codec); | ||
1806 | |||
1807 | return 0; | ||
1808 | } | ||
1809 | |||
1810 | static int check_clk_sys(struct snd_soc_dapm_widget *source, | ||
1811 | struct snd_soc_dapm_widget *sink) | ||
1812 | { | ||
1813 | int reg = snd_soc_read(source->codec, WM8994_CLOCKING_1); | ||
1814 | const char *clk; | ||
1815 | |||
1816 | /* Check what we're currently using for CLK_SYS */ | ||
1817 | if (reg & WM8994_SYSCLK_SRC) | ||
1818 | clk = "AIF2CLK"; | ||
1819 | else | ||
1820 | clk = "AIF1CLK"; | ||
1821 | |||
1822 | return strcmp(source->name, clk) == 0; | ||
1823 | } | ||
1824 | |||
1825 | static const char *sidetone_hpf_text[] = { | ||
1826 | "2.7kHz", "1.35kHz", "675Hz", "370Hz", "180Hz", "90Hz", "45Hz" | ||
1827 | }; | ||
1828 | |||
1829 | static const struct soc_enum sidetone_hpf = | ||
1830 | SOC_ENUM_SINGLE(WM8994_SIDETONE, 7, 7, sidetone_hpf_text); | ||
1831 | |||
1832 | static const DECLARE_TLV_DB_SCALE(aif_tlv, 0, 600, 0); | ||
1833 | static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1); | ||
1834 | static const DECLARE_TLV_DB_SCALE(st_tlv, -3600, 300, 0); | ||
1835 | static const DECLARE_TLV_DB_SCALE(wm8994_3d_tlv, -1600, 183, 0); | ||
1836 | static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); | ||
1837 | |||
1838 | #define WM8994_DRC_SWITCH(xname, reg, shift) \ | ||
1839 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | ||
1840 | .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\ | ||
1841 | .put = wm8994_put_drc_sw, \ | ||
1842 | .private_value = SOC_SINGLE_VALUE(reg, shift, 1, 0) } | ||
1843 | |||
1844 | static int wm8994_put_drc_sw(struct snd_kcontrol *kcontrol, | ||
1845 | struct snd_ctl_elem_value *ucontrol) | ||
1846 | { | ||
1847 | struct soc_mixer_control *mc = | ||
1848 | (struct soc_mixer_control *)kcontrol->private_value; | ||
1849 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1850 | int mask, ret; | ||
1851 | |||
1852 | /* Can't enable both ADC and DAC paths simultaneously */ | ||
1853 | if (mc->shift == WM8994_AIF1DAC1_DRC_ENA_SHIFT) | ||
1854 | mask = WM8994_AIF1ADC1L_DRC_ENA_MASK | | ||
1855 | WM8994_AIF1ADC1R_DRC_ENA_MASK; | ||
1856 | else | ||
1857 | mask = WM8994_AIF1DAC1_DRC_ENA_MASK; | ||
1858 | |||
1859 | ret = snd_soc_read(codec, mc->reg); | ||
1860 | if (ret < 0) | ||
1861 | return ret; | ||
1862 | if (ret & mask) | ||
1863 | return -EINVAL; | ||
1864 | |||
1865 | return snd_soc_put_volsw(kcontrol, ucontrol); | ||
1866 | } | ||
1867 | |||
1868 | |||
1869 | |||
1870 | static void wm8994_set_drc(struct snd_soc_codec *codec, int drc) | ||
1871 | { | ||
1872 | struct wm8994_priv *wm8994 = codec->private_data; | ||
1873 | struct wm8994_pdata *pdata = wm8994->pdata; | ||
1874 | int base = wm8994_drc_base[drc]; | ||
1875 | int cfg = wm8994->drc_cfg[drc]; | ||
1876 | int save, i; | ||
1877 | |||
1878 | /* Save any enables; the configuration should clear them. */ | ||
1879 | save = snd_soc_read(codec, base); | ||
1880 | save &= WM8994_AIF1DAC1_DRC_ENA | WM8994_AIF1ADC1L_DRC_ENA | | ||
1881 | WM8994_AIF1ADC1R_DRC_ENA; | ||
1882 | |||
1883 | for (i = 0; i < WM8994_DRC_REGS; i++) | ||
1884 | snd_soc_update_bits(codec, base + i, 0xffff, | ||
1885 | pdata->drc_cfgs[cfg].regs[i]); | ||
1886 | |||
1887 | snd_soc_update_bits(codec, base, WM8994_AIF1DAC1_DRC_ENA | | ||
1888 | WM8994_AIF1ADC1L_DRC_ENA | | ||
1889 | WM8994_AIF1ADC1R_DRC_ENA, save); | ||
1890 | } | ||
1891 | |||
1892 | /* Icky as hell but saves code duplication */ | ||
1893 | static int wm8994_get_drc(const char *name) | ||
1894 | { | ||
1895 | if (strcmp(name, "AIF1DRC1 Mode") == 0) | ||
1896 | return 0; | ||
1897 | if (strcmp(name, "AIF1DRC2 Mode") == 0) | ||
1898 | return 1; | ||
1899 | if (strcmp(name, "AIF2DRC Mode") == 0) | ||
1900 | return 2; | ||
1901 | return -EINVAL; | ||
1902 | } | ||
1903 | |||
1904 | static int wm8994_put_drc_enum(struct snd_kcontrol *kcontrol, | ||
1905 | struct snd_ctl_elem_value *ucontrol) | ||
1906 | { | ||
1907 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1908 | struct wm8994_priv *wm8994 = codec->private_data; | ||
1909 | struct wm8994_pdata *pdata = wm8994->pdata; | ||
1910 | int drc = wm8994_get_drc(kcontrol->id.name); | ||
1911 | int value = ucontrol->value.integer.value[0]; | ||
1912 | |||
1913 | if (drc < 0) | ||
1914 | return drc; | ||
1915 | |||
1916 | if (value >= pdata->num_drc_cfgs) | ||
1917 | return -EINVAL; | ||
1918 | |||
1919 | wm8994->drc_cfg[drc] = value; | ||
1920 | |||
1921 | wm8994_set_drc(codec, drc); | ||
1922 | |||
1923 | return 0; | ||
1924 | } | ||
1925 | |||
1926 | static int wm8994_get_drc_enum(struct snd_kcontrol *kcontrol, | ||
1927 | struct snd_ctl_elem_value *ucontrol) | ||
1928 | { | ||
1929 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1930 | struct wm8994_priv *wm8994 = codec->private_data; | ||
1931 | int drc = wm8994_get_drc(kcontrol->id.name); | ||
1932 | |||
1933 | ucontrol->value.enumerated.item[0] = wm8994->drc_cfg[drc]; | ||
1934 | |||
1935 | return 0; | ||
1936 | } | ||
1937 | |||
1938 | static void wm8994_set_retune_mobile(struct snd_soc_codec *codec, int block) | ||
1939 | { | ||
1940 | struct wm8994_priv *wm8994 = codec->private_data; | ||
1941 | struct wm8994_pdata *pdata = wm8994->pdata; | ||
1942 | int base = wm8994_retune_mobile_base[block]; | ||
1943 | int iface, best, best_val, save, i, cfg; | ||
1944 | |||
1945 | if (!pdata || !wm8994->num_retune_mobile_texts) | ||
1946 | return; | ||
1947 | |||
1948 | switch (block) { | ||
1949 | case 0: | ||
1950 | case 1: | ||
1951 | iface = 0; | ||
1952 | break; | ||
1953 | case 2: | ||
1954 | iface = 1; | ||
1955 | break; | ||
1956 | default: | ||
1957 | return; | ||
1958 | } | ||
1959 | |||
1960 | /* Find the version of the currently selected configuration | ||
1961 | * with the nearest sample rate. */ | ||
1962 | cfg = wm8994->retune_mobile_cfg[block]; | ||
1963 | best = 0; | ||
1964 | best_val = INT_MAX; | ||
1965 | for (i = 0; i < pdata->num_retune_mobile_cfgs; i++) { | ||
1966 | if (strcmp(pdata->retune_mobile_cfgs[i].name, | ||
1967 | wm8994->retune_mobile_texts[cfg]) == 0 && | ||
1968 | abs(pdata->retune_mobile_cfgs[i].rate | ||
1969 | - wm8994->dac_rates[iface]) < best_val) { | ||
1970 | best = i; | ||
1971 | best_val = abs(pdata->retune_mobile_cfgs[i].rate | ||
1972 | - wm8994->dac_rates[iface]); | ||
1973 | } | ||
1974 | } | ||
1975 | |||
1976 | dev_dbg(codec->dev, "ReTune Mobile %d %s/%dHz for %dHz sample rate\n", | ||
1977 | block, | ||
1978 | pdata->retune_mobile_cfgs[best].name, | ||
1979 | pdata->retune_mobile_cfgs[best].rate, | ||
1980 | wm8994->dac_rates[iface]); | ||
1981 | |||
1982 | /* The EQ will be disabled while reconfiguring it, remember the | ||
1983 | * current configuration. | ||
1984 | */ | ||
1985 | save = snd_soc_read(codec, base); | ||
1986 | save &= WM8994_AIF1DAC1_EQ_ENA; | ||
1987 | |||
1988 | for (i = 0; i < WM8994_EQ_REGS; i++) | ||
1989 | snd_soc_update_bits(codec, base + i, 0xffff, | ||
1990 | pdata->retune_mobile_cfgs[best].regs[i]); | ||
1991 | |||
1992 | snd_soc_update_bits(codec, base, WM8994_AIF1DAC1_EQ_ENA, save); | ||
1993 | } | ||
1994 | |||
1995 | /* Icky as hell but saves code duplication */ | ||
1996 | static int wm8994_get_retune_mobile_block(const char *name) | ||
1997 | { | ||
1998 | if (strcmp(name, "AIF1.1 EQ Mode") == 0) | ||
1999 | return 0; | ||
2000 | if (strcmp(name, "AIF1.2 EQ Mode") == 0) | ||
2001 | return 1; | ||
2002 | if (strcmp(name, "AIF2 EQ Mode") == 0) | ||
2003 | return 2; | ||
2004 | return -EINVAL; | ||
2005 | } | ||
2006 | |||
2007 | static int wm8994_put_retune_mobile_enum(struct snd_kcontrol *kcontrol, | ||
2008 | struct snd_ctl_elem_value *ucontrol) | ||
2009 | { | ||
2010 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
2011 | struct wm8994_priv *wm8994 = codec->private_data; | ||
2012 | struct wm8994_pdata *pdata = wm8994->pdata; | ||
2013 | int block = wm8994_get_retune_mobile_block(kcontrol->id.name); | ||
2014 | int value = ucontrol->value.integer.value[0]; | ||
2015 | |||
2016 | if (block < 0) | ||
2017 | return block; | ||
2018 | |||
2019 | if (value >= pdata->num_retune_mobile_cfgs) | ||
2020 | return -EINVAL; | ||
2021 | |||
2022 | wm8994->retune_mobile_cfg[block] = value; | ||
2023 | |||
2024 | wm8994_set_retune_mobile(codec, block); | ||
2025 | |||
2026 | return 0; | ||
2027 | } | ||
2028 | |||
2029 | static int wm8994_get_retune_mobile_enum(struct snd_kcontrol *kcontrol, | ||
2030 | struct snd_ctl_elem_value *ucontrol) | ||
2031 | { | ||
2032 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
2033 | struct wm8994_priv *wm8994 = codec->private_data; | ||
2034 | int block = wm8994_get_retune_mobile_block(kcontrol->id.name); | ||
2035 | |||
2036 | ucontrol->value.enumerated.item[0] = wm8994->retune_mobile_cfg[block]; | ||
2037 | |||
2038 | return 0; | ||
2039 | } | ||
2040 | |||
2041 | static const struct snd_kcontrol_new wm8994_snd_controls[] = { | ||
2042 | SOC_DOUBLE_R_TLV("AIF1ADC1 Volume", WM8994_AIF1_ADC1_LEFT_VOLUME, | ||
2043 | WM8994_AIF1_ADC1_RIGHT_VOLUME, | ||
2044 | 1, 119, 0, digital_tlv), | ||
2045 | SOC_DOUBLE_R_TLV("AIF1ADC2 Volume", WM8994_AIF1_ADC2_LEFT_VOLUME, | ||
2046 | WM8994_AIF1_ADC2_RIGHT_VOLUME, | ||
2047 | 1, 119, 0, digital_tlv), | ||
2048 | SOC_DOUBLE_R_TLV("AIF2ADC Volume", WM8994_AIF2_ADC_LEFT_VOLUME, | ||
2049 | WM8994_AIF2_ADC_RIGHT_VOLUME, | ||
2050 | 1, 119, 0, digital_tlv), | ||
2051 | |||
2052 | SOC_DOUBLE_R_TLV("AIF1DAC1 Volume", WM8994_AIF1_DAC1_LEFT_VOLUME, | ||
2053 | WM8994_AIF1_DAC1_RIGHT_VOLUME, 1, 96, 0, digital_tlv), | ||
2054 | SOC_DOUBLE_R_TLV("AIF1DAC2 Volume", WM8994_AIF1_DAC2_LEFT_VOLUME, | ||
2055 | WM8994_AIF1_DAC2_RIGHT_VOLUME, 1, 96, 0, digital_tlv), | ||
2056 | SOC_DOUBLE_R_TLV("AIF2DAC Volume", WM8994_AIF2_DAC_LEFT_VOLUME, | ||
2057 | WM8994_AIF2_DAC_RIGHT_VOLUME, 1, 96, 0, digital_tlv), | ||
2058 | |||
2059 | SOC_SINGLE_TLV("AIF1 Boost Volume", WM8994_AIF1_CONTROL_2, 10, 3, 0, aif_tlv), | ||
2060 | SOC_SINGLE_TLV("AIF2 Boost Volume", WM8994_AIF2_CONTROL_2, 10, 3, 0, aif_tlv), | ||
2061 | |||
2062 | SOC_SINGLE("AIF1DAC1 EQ Switch", WM8994_AIF1_DAC1_EQ_GAINS_1, 0, 1, 0), | ||
2063 | SOC_SINGLE("AIF1DAC2 EQ Switch", WM8994_AIF1_DAC2_EQ_GAINS_1, 0, 1, 0), | ||
2064 | SOC_SINGLE("AIF2 EQ Switch", WM8994_AIF2_EQ_GAINS_1, 0, 1, 0), | ||
2065 | |||
2066 | WM8994_DRC_SWITCH("AIF1DAC1 DRC Switch", WM8994_AIF1_DRC1_1, 2), | ||
2067 | WM8994_DRC_SWITCH("AIF1ADC1L DRC Switch", WM8994_AIF1_DRC1_1, 1), | ||
2068 | WM8994_DRC_SWITCH("AIF1ADC1R DRC Switch", WM8994_AIF1_DRC1_1, 0), | ||
2069 | |||
2070 | WM8994_DRC_SWITCH("AIF1DAC2 DRC Switch", WM8994_AIF1_DRC2_1, 2), | ||
2071 | WM8994_DRC_SWITCH("AIF1ADC2L DRC Switch", WM8994_AIF1_DRC2_1, 1), | ||
2072 | WM8994_DRC_SWITCH("AIF1ADC2R DRC Switch", WM8994_AIF1_DRC2_1, 0), | ||
2073 | |||
2074 | WM8994_DRC_SWITCH("AIF2DAC DRC Switch", WM8994_AIF2_DRC_1, 2), | ||
2075 | WM8994_DRC_SWITCH("AIF2ADCL DRC Switch", WM8994_AIF2_DRC_1, 1), | ||
2076 | WM8994_DRC_SWITCH("AIF2ADCR DRC Switch", WM8994_AIF2_DRC_1, 0), | ||
2077 | |||
2078 | SOC_SINGLE_TLV("DAC1 Right Sidetone Volume", WM8994_DAC1_MIXER_VOLUMES, | ||
2079 | 5, 12, 0, st_tlv), | ||
2080 | SOC_SINGLE_TLV("DAC1 Left Sidetone Volume", WM8994_DAC1_MIXER_VOLUMES, | ||
2081 | 0, 12, 0, st_tlv), | ||
2082 | SOC_SINGLE_TLV("DAC2 Right Sidetone Volume", WM8994_DAC2_MIXER_VOLUMES, | ||
2083 | 5, 12, 0, st_tlv), | ||
2084 | SOC_SINGLE_TLV("DAC2 Left Sidetone Volume", WM8994_DAC2_MIXER_VOLUMES, | ||
2085 | 0, 12, 0, st_tlv), | ||
2086 | SOC_ENUM("Sidetone HPF Mux", sidetone_hpf), | ||
2087 | SOC_SINGLE("Sidetone HPF Switch", WM8994_SIDETONE, 6, 1, 0), | ||
2088 | |||
2089 | SOC_DOUBLE_R_TLV("DAC1 Volume", WM8994_DAC1_LEFT_VOLUME, | ||
2090 | WM8994_DAC1_RIGHT_VOLUME, 1, 96, 0, digital_tlv), | ||
2091 | SOC_DOUBLE_R("DAC1 Switch", WM8994_DAC1_LEFT_VOLUME, | ||
2092 | WM8994_DAC1_RIGHT_VOLUME, 9, 1, 1), | ||
2093 | |||
2094 | SOC_DOUBLE_R_TLV("DAC2 Volume", WM8994_DAC2_LEFT_VOLUME, | ||
2095 | WM8994_DAC2_RIGHT_VOLUME, 1, 96, 0, digital_tlv), | ||
2096 | SOC_DOUBLE_R("DAC2 Switch", WM8994_DAC2_LEFT_VOLUME, | ||
2097 | WM8994_DAC2_RIGHT_VOLUME, 9, 1, 1), | ||
2098 | |||
2099 | SOC_SINGLE_TLV("SPKL DAC2 Volume", WM8994_SPKMIXL_ATTENUATION, | ||
2100 | 6, 1, 1, wm_hubs_spkmix_tlv), | ||
2101 | SOC_SINGLE_TLV("SPKL DAC1 Volume", WM8994_SPKMIXL_ATTENUATION, | ||
2102 | 2, 1, 1, wm_hubs_spkmix_tlv), | ||
2103 | |||
2104 | SOC_SINGLE_TLV("SPKR DAC2 Volume", WM8994_SPKMIXR_ATTENUATION, | ||
2105 | 6, 1, 1, wm_hubs_spkmix_tlv), | ||
2106 | SOC_SINGLE_TLV("SPKR DAC1 Volume", WM8994_SPKMIXR_ATTENUATION, | ||
2107 | 2, 1, 1, wm_hubs_spkmix_tlv), | ||
2108 | |||
2109 | SOC_SINGLE_TLV("AIF1DAC1 3D Stereo Volume", WM8994_AIF1_DAC1_FILTERS_2, | ||
2110 | 10, 15, 0, wm8994_3d_tlv), | ||
2111 | SOC_SINGLE("AIF1DAC1 3D Stereo Switch", WM8994_AIF1_DAC2_FILTERS_2, | ||
2112 | 8, 1, 0), | ||
2113 | SOC_SINGLE_TLV("AIF1DAC2 3D Stereo Volume", WM8994_AIF1_DAC2_FILTERS_2, | ||
2114 | 10, 15, 0, wm8994_3d_tlv), | ||
2115 | SOC_SINGLE("AIF1DAC2 3D Stereo Switch", WM8994_AIF1_DAC2_FILTERS_2, | ||
2116 | 8, 1, 0), | ||
2117 | SOC_SINGLE_TLV("AIF2DAC 3D Stereo Volume", WM8994_AIF1_DAC1_FILTERS_2, | ||
2118 | 10, 15, 0, wm8994_3d_tlv), | ||
2119 | SOC_SINGLE("AIF2DAC 3D Stereo Switch", WM8994_AIF1_DAC2_FILTERS_2, | ||
2120 | 8, 1, 0), | ||
2121 | }; | ||
2122 | |||
2123 | static const struct snd_kcontrol_new wm8994_eq_controls[] = { | ||
2124 | SOC_SINGLE_TLV("AIF1DAC1 EQ1 Volume", WM8994_AIF1_DAC1_EQ_GAINS_1, 11, 31, 0, | ||
2125 | eq_tlv), | ||
2126 | SOC_SINGLE_TLV("AIF1DAC1 EQ2 Volume", WM8994_AIF1_DAC1_EQ_GAINS_1, 6, 31, 0, | ||
2127 | eq_tlv), | ||
2128 | SOC_SINGLE_TLV("AIF1DAC1 EQ3 Volume", WM8994_AIF1_DAC1_EQ_GAINS_1, 1, 31, 0, | ||
2129 | eq_tlv), | ||
2130 | SOC_SINGLE_TLV("AIF1DAC1 EQ4 Volume", WM8994_AIF1_DAC1_EQ_GAINS_2, 11, 31, 0, | ||
2131 | eq_tlv), | ||
2132 | SOC_SINGLE_TLV("AIF1DAC1 EQ5 Volume", WM8994_AIF1_DAC1_EQ_GAINS_2, 6, 31, 0, | ||
2133 | eq_tlv), | ||
2134 | |||
2135 | SOC_SINGLE_TLV("AIF1DAC2 EQ1 Volume", WM8994_AIF1_DAC2_EQ_GAINS_1, 11, 31, 0, | ||
2136 | eq_tlv), | ||
2137 | SOC_SINGLE_TLV("AIF1DAC2 EQ2 Volume", WM8994_AIF1_DAC2_EQ_GAINS_1, 6, 31, 0, | ||
2138 | eq_tlv), | ||
2139 | SOC_SINGLE_TLV("AIF1DAC2 EQ3 Volume", WM8994_AIF1_DAC2_EQ_GAINS_1, 1, 31, 0, | ||
2140 | eq_tlv), | ||
2141 | SOC_SINGLE_TLV("AIF1DAC2 EQ4 Volume", WM8994_AIF1_DAC2_EQ_GAINS_2, 11, 31, 0, | ||
2142 | eq_tlv), | ||
2143 | SOC_SINGLE_TLV("AIF1DAC2 EQ5 Volume", WM8994_AIF1_DAC2_EQ_GAINS_2, 6, 31, 0, | ||
2144 | eq_tlv), | ||
2145 | |||
2146 | SOC_SINGLE_TLV("AIF2 EQ1 Volume", WM8994_AIF2_EQ_GAINS_1, 11, 31, 0, | ||
2147 | eq_tlv), | ||
2148 | SOC_SINGLE_TLV("AIF2 EQ2 Volume", WM8994_AIF2_EQ_GAINS_1, 6, 31, 0, | ||
2149 | eq_tlv), | ||
2150 | SOC_SINGLE_TLV("AIF2 EQ3 Volume", WM8994_AIF2_EQ_GAINS_1, 1, 31, 0, | ||
2151 | eq_tlv), | ||
2152 | SOC_SINGLE_TLV("AIF2 EQ4 Volume", WM8994_AIF2_EQ_GAINS_2, 11, 31, 0, | ||
2153 | eq_tlv), | ||
2154 | SOC_SINGLE_TLV("AIF2 EQ5 Volume", WM8994_AIF2_EQ_GAINS_2, 6, 31, 0, | ||
2155 | eq_tlv), | ||
2156 | }; | ||
2157 | |||
2158 | static int clk_sys_event(struct snd_soc_dapm_widget *w, | ||
2159 | struct snd_kcontrol *kcontrol, int event) | ||
2160 | { | ||
2161 | struct snd_soc_codec *codec = w->codec; | ||
2162 | |||
2163 | switch (event) { | ||
2164 | case SND_SOC_DAPM_PRE_PMU: | ||
2165 | return configure_clock(codec); | ||
2166 | |||
2167 | case SND_SOC_DAPM_POST_PMD: | ||
2168 | configure_clock(codec); | ||
2169 | break; | ||
2170 | } | ||
2171 | |||
2172 | return 0; | ||
2173 | } | ||
2174 | |||
2175 | static void wm8994_update_class_w(struct snd_soc_codec *codec) | ||
2176 | { | ||
2177 | int enable = 1; | ||
2178 | int source = 0; /* GCC flow analysis can't track enable */ | ||
2179 | int reg, reg_r; | ||
2180 | |||
2181 | /* Only support direct DAC->headphone paths */ | ||
2182 | reg = snd_soc_read(codec, WM8994_OUTPUT_MIXER_1); | ||
2183 | if (!(reg & WM8994_DAC1L_TO_HPOUT1L)) { | ||
2184 | dev_dbg(codec->dev, "HPL connected to output mixer\n"); | ||
2185 | enable = 0; | ||
2186 | } | ||
2187 | |||
2188 | reg = snd_soc_read(codec, WM8994_OUTPUT_MIXER_2); | ||
2189 | if (!(reg & WM8994_DAC1R_TO_HPOUT1R)) { | ||
2190 | dev_dbg(codec->dev, "HPR connected to output mixer\n"); | ||
2191 | enable = 0; | ||
2192 | } | ||
2193 | |||
2194 | /* We also need the same setting for L/R and only one path */ | ||
2195 | reg = snd_soc_read(codec, WM8994_DAC1_LEFT_MIXER_ROUTING); | ||
2196 | switch (reg) { | ||
2197 | case WM8994_AIF2DACL_TO_DAC1L: | ||
2198 | dev_dbg(codec->dev, "Class W source AIF2DAC\n"); | ||
2199 | source = 2 << WM8994_CP_DYN_SRC_SEL_SHIFT; | ||
2200 | break; | ||
2201 | case WM8994_AIF1DAC2L_TO_DAC1L: | ||
2202 | dev_dbg(codec->dev, "Class W source AIF1DAC2\n"); | ||
2203 | source = 1 << WM8994_CP_DYN_SRC_SEL_SHIFT; | ||
2204 | break; | ||
2205 | case WM8994_AIF1DAC1L_TO_DAC1L: | ||
2206 | dev_dbg(codec->dev, "Class W source AIF1DAC1\n"); | ||
2207 | source = 0 << WM8994_CP_DYN_SRC_SEL_SHIFT; | ||
2208 | break; | ||
2209 | default: | ||
2210 | dev_dbg(codec->dev, "DAC mixer setting: %x\n", reg); | ||
2211 | enable = 0; | ||
2212 | break; | ||
2213 | } | ||
2214 | |||
2215 | reg_r = snd_soc_read(codec, WM8994_DAC1_RIGHT_MIXER_ROUTING); | ||
2216 | if (reg_r != reg) { | ||
2217 | dev_dbg(codec->dev, "Left and right DAC mixers different\n"); | ||
2218 | enable = 0; | ||
2219 | } | ||
2220 | |||
2221 | if (enable) { | ||
2222 | dev_dbg(codec->dev, "Class W enabled\n"); | ||
2223 | snd_soc_update_bits(codec, WM8994_CLASS_W_1, | ||
2224 | WM8994_CP_DYN_PWR | | ||
2225 | WM8994_CP_DYN_SRC_SEL_MASK, | ||
2226 | source | WM8994_CP_DYN_PWR); | ||
2227 | |||
2228 | } else { | ||
2229 | dev_dbg(codec->dev, "Class W disabled\n"); | ||
2230 | snd_soc_update_bits(codec, WM8994_CLASS_W_1, | ||
2231 | WM8994_CP_DYN_PWR, 0); | ||
2232 | } | ||
2233 | } | ||
2234 | |||
2235 | static const char *hp_mux_text[] = { | ||
2236 | "Mixer", | ||
2237 | "DAC", | ||
2238 | }; | ||
2239 | |||
2240 | #define WM8994_HP_ENUM(xname, xenum) \ | ||
2241 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | ||
2242 | .info = snd_soc_info_enum_double, \ | ||
2243 | .get = snd_soc_dapm_get_enum_double, \ | ||
2244 | .put = wm8994_put_hp_enum, \ | ||
2245 | .private_value = (unsigned long)&xenum } | ||
2246 | |||
2247 | static int wm8994_put_hp_enum(struct snd_kcontrol *kcontrol, | ||
2248 | struct snd_ctl_elem_value *ucontrol) | ||
2249 | { | ||
2250 | struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol); | ||
2251 | struct snd_soc_codec *codec = w->codec; | ||
2252 | int ret; | ||
2253 | |||
2254 | ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol); | ||
2255 | |||
2256 | wm8994_update_class_w(codec); | ||
2257 | |||
2258 | return ret; | ||
2259 | } | ||
2260 | |||
2261 | static const struct soc_enum hpl_enum = | ||
2262 | SOC_ENUM_SINGLE(WM8994_OUTPUT_MIXER_1, 8, 2, hp_mux_text); | ||
2263 | |||
2264 | static const struct snd_kcontrol_new hpl_mux = | ||
2265 | WM8994_HP_ENUM("Left Headphone Mux", hpl_enum); | ||
2266 | |||
2267 | static const struct soc_enum hpr_enum = | ||
2268 | SOC_ENUM_SINGLE(WM8994_OUTPUT_MIXER_2, 8, 2, hp_mux_text); | ||
2269 | |||
2270 | static const struct snd_kcontrol_new hpr_mux = | ||
2271 | WM8994_HP_ENUM("Right Headphone Mux", hpr_enum); | ||
2272 | |||
2273 | static const char *adc_mux_text[] = { | ||
2274 | "ADC", | ||
2275 | "DMIC", | ||
2276 | }; | ||
2277 | |||
2278 | static const struct soc_enum adc_enum = | ||
2279 | SOC_ENUM_SINGLE(0, 0, 2, adc_mux_text); | ||
2280 | |||
2281 | static const struct snd_kcontrol_new adcl_mux = | ||
2282 | SOC_DAPM_ENUM_VIRT("ADCL Mux", adc_enum); | ||
2283 | |||
2284 | static const struct snd_kcontrol_new adcr_mux = | ||
2285 | SOC_DAPM_ENUM_VIRT("ADCR Mux", adc_enum); | ||
2286 | |||
2287 | static const struct snd_kcontrol_new left_speaker_mixer[] = { | ||
2288 | SOC_DAPM_SINGLE("DAC2 Switch", WM8994_SPEAKER_MIXER, 9, 1, 0), | ||
2289 | SOC_DAPM_SINGLE("Input Switch", WM8994_SPEAKER_MIXER, 7, 1, 0), | ||
2290 | SOC_DAPM_SINGLE("IN1LP Switch", WM8994_SPEAKER_MIXER, 5, 1, 0), | ||
2291 | SOC_DAPM_SINGLE("Output Switch", WM8994_SPEAKER_MIXER, 3, 1, 0), | ||
2292 | SOC_DAPM_SINGLE("DAC1 Switch", WM8994_SPEAKER_MIXER, 1, 1, 0), | ||
2293 | }; | ||
2294 | |||
2295 | static const struct snd_kcontrol_new right_speaker_mixer[] = { | ||
2296 | SOC_DAPM_SINGLE("DAC2 Switch", WM8994_SPEAKER_MIXER, 8, 1, 0), | ||
2297 | SOC_DAPM_SINGLE("Input Switch", WM8994_SPEAKER_MIXER, 6, 1, 0), | ||
2298 | SOC_DAPM_SINGLE("IN1RP Switch", WM8994_SPEAKER_MIXER, 4, 1, 0), | ||
2299 | SOC_DAPM_SINGLE("Output Switch", WM8994_SPEAKER_MIXER, 2, 1, 0), | ||
2300 | SOC_DAPM_SINGLE("DAC1 Switch", WM8994_SPEAKER_MIXER, 0, 1, 0), | ||
2301 | }; | ||
2302 | |||
2303 | /* Debugging; dump chip status after DAPM transitions */ | ||
2304 | static int post_ev(struct snd_soc_dapm_widget *w, | ||
2305 | struct snd_kcontrol *kcontrol, int event) | ||
2306 | { | ||
2307 | struct snd_soc_codec *codec = w->codec; | ||
2308 | dev_dbg(codec->dev, "SRC status: %x\n", | ||
2309 | snd_soc_read(codec, | ||
2310 | WM8994_RATE_STATUS)); | ||
2311 | return 0; | ||
2312 | } | ||
2313 | |||
2314 | static const struct snd_kcontrol_new aif1adc1l_mix[] = { | ||
2315 | SOC_DAPM_SINGLE("ADC/DMIC Switch", WM8994_AIF1_ADC1_LEFT_MIXER_ROUTING, | ||
2316 | 1, 1, 0), | ||
2317 | SOC_DAPM_SINGLE("AIF2 Switch", WM8994_AIF1_ADC1_LEFT_MIXER_ROUTING, | ||
2318 | 0, 1, 0), | ||
2319 | }; | ||
2320 | |||
2321 | static const struct snd_kcontrol_new aif1adc1r_mix[] = { | ||
2322 | SOC_DAPM_SINGLE("ADC/DMIC Switch", WM8994_AIF1_ADC1_RIGHT_MIXER_ROUTING, | ||
2323 | 1, 1, 0), | ||
2324 | SOC_DAPM_SINGLE("AIF2 Switch", WM8994_AIF1_ADC1_RIGHT_MIXER_ROUTING, | ||
2325 | 0, 1, 0), | ||
2326 | }; | ||
2327 | |||
2328 | static const struct snd_kcontrol_new aif2dac2l_mix[] = { | ||
2329 | SOC_DAPM_SINGLE("Right Sidetone Switch", WM8994_DAC2_LEFT_MIXER_ROUTING, | ||
2330 | 5, 1, 0), | ||
2331 | SOC_DAPM_SINGLE("Left Sidetone Switch", WM8994_DAC2_LEFT_MIXER_ROUTING, | ||
2332 | 4, 1, 0), | ||
2333 | SOC_DAPM_SINGLE("AIF2 Switch", WM8994_DAC2_LEFT_MIXER_ROUTING, | ||
2334 | 2, 1, 0), | ||
2335 | SOC_DAPM_SINGLE("AIF1.2 Switch", WM8994_DAC2_LEFT_MIXER_ROUTING, | ||
2336 | 1, 1, 0), | ||
2337 | SOC_DAPM_SINGLE("AIF1.1 Switch", WM8994_DAC2_LEFT_MIXER_ROUTING, | ||
2338 | 0, 1, 0), | ||
2339 | }; | ||
2340 | |||
2341 | static const struct snd_kcontrol_new aif2dac2r_mix[] = { | ||
2342 | SOC_DAPM_SINGLE("Right Sidetone Switch", WM8994_DAC2_RIGHT_MIXER_ROUTING, | ||
2343 | 5, 1, 0), | ||
2344 | SOC_DAPM_SINGLE("Left Sidetone Switch", WM8994_DAC2_RIGHT_MIXER_ROUTING, | ||
2345 | 4, 1, 0), | ||
2346 | SOC_DAPM_SINGLE("AIF2 Switch", WM8994_DAC2_RIGHT_MIXER_ROUTING, | ||
2347 | 2, 1, 0), | ||
2348 | SOC_DAPM_SINGLE("AIF1.2 Switch", WM8994_DAC2_RIGHT_MIXER_ROUTING, | ||
2349 | 1, 1, 0), | ||
2350 | SOC_DAPM_SINGLE("AIF1.1 Switch", WM8994_DAC2_RIGHT_MIXER_ROUTING, | ||
2351 | 0, 1, 0), | ||
2352 | }; | ||
2353 | |||
2354 | #define WM8994_CLASS_W_SWITCH(xname, reg, shift, max, invert) \ | ||
2355 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | ||
2356 | .info = snd_soc_info_volsw, \ | ||
2357 | .get = snd_soc_dapm_get_volsw, .put = wm8994_put_class_w, \ | ||
2358 | .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) } | ||
2359 | |||
2360 | static int wm8994_put_class_w(struct snd_kcontrol *kcontrol, | ||
2361 | struct snd_ctl_elem_value *ucontrol) | ||
2362 | { | ||
2363 | struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol); | ||
2364 | struct snd_soc_codec *codec = w->codec; | ||
2365 | int ret; | ||
2366 | |||
2367 | ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol); | ||
2368 | |||
2369 | wm8994_update_class_w(codec); | ||
2370 | |||
2371 | return ret; | ||
2372 | } | ||
2373 | |||
2374 | static const struct snd_kcontrol_new dac1l_mix[] = { | ||
2375 | WM8994_CLASS_W_SWITCH("Right Sidetone Switch", WM8994_DAC1_LEFT_MIXER_ROUTING, | ||
2376 | 5, 1, 0), | ||
2377 | WM8994_CLASS_W_SWITCH("Left Sidetone Switch", WM8994_DAC1_LEFT_MIXER_ROUTING, | ||
2378 | 4, 1, 0), | ||
2379 | WM8994_CLASS_W_SWITCH("AIF2 Switch", WM8994_DAC1_LEFT_MIXER_ROUTING, | ||
2380 | 2, 1, 0), | ||
2381 | WM8994_CLASS_W_SWITCH("AIF1.2 Switch", WM8994_DAC1_LEFT_MIXER_ROUTING, | ||
2382 | 1, 1, 0), | ||
2383 | WM8994_CLASS_W_SWITCH("AIF1.1 Switch", WM8994_DAC1_LEFT_MIXER_ROUTING, | ||
2384 | 0, 1, 0), | ||
2385 | }; | ||
2386 | |||
2387 | static const struct snd_kcontrol_new dac1r_mix[] = { | ||
2388 | WM8994_CLASS_W_SWITCH("Right Sidetone Switch", WM8994_DAC1_RIGHT_MIXER_ROUTING, | ||
2389 | 5, 1, 0), | ||
2390 | WM8994_CLASS_W_SWITCH("Left Sidetone Switch", WM8994_DAC1_RIGHT_MIXER_ROUTING, | ||
2391 | 4, 1, 0), | ||
2392 | WM8994_CLASS_W_SWITCH("AIF2 Switch", WM8994_DAC1_RIGHT_MIXER_ROUTING, | ||
2393 | 2, 1, 0), | ||
2394 | WM8994_CLASS_W_SWITCH("AIF1.2 Switch", WM8994_DAC1_RIGHT_MIXER_ROUTING, | ||
2395 | 1, 1, 0), | ||
2396 | WM8994_CLASS_W_SWITCH("AIF1.1 Switch", WM8994_DAC1_RIGHT_MIXER_ROUTING, | ||
2397 | 0, 1, 0), | ||
2398 | }; | ||
2399 | |||
2400 | static const char *sidetone_text[] = { | ||
2401 | "ADC/DMIC1", "DMIC2", | ||
2402 | }; | ||
2403 | |||
2404 | static const struct soc_enum sidetone1_enum = | ||
2405 | SOC_ENUM_SINGLE(WM8994_SIDETONE, 0, 2, sidetone_text); | ||
2406 | |||
2407 | static const struct snd_kcontrol_new sidetone1_mux = | ||
2408 | SOC_DAPM_ENUM("Left Sidetone Mux", sidetone1_enum); | ||
2409 | |||
2410 | static const struct soc_enum sidetone2_enum = | ||
2411 | SOC_ENUM_SINGLE(WM8994_SIDETONE, 1, 2, sidetone_text); | ||
2412 | |||
2413 | static const struct snd_kcontrol_new sidetone2_mux = | ||
2414 | SOC_DAPM_ENUM("Right Sidetone Mux", sidetone2_enum); | ||
2415 | |||
2416 | static const char *aif1dac_text[] = { | ||
2417 | "AIF1DACDAT", "AIF3DACDAT", | ||
2418 | }; | ||
2419 | |||
2420 | static const struct soc_enum aif1dac_enum = | ||
2421 | SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 0, 2, aif1dac_text); | ||
2422 | |||
2423 | static const struct snd_kcontrol_new aif1dac_mux = | ||
2424 | SOC_DAPM_ENUM("AIF1DAC Mux", aif1dac_enum); | ||
2425 | |||
2426 | static const char *aif2dac_text[] = { | ||
2427 | "AIF2DACDAT", "AIF3DACDAT", | ||
2428 | }; | ||
2429 | |||
2430 | static const struct soc_enum aif2dac_enum = | ||
2431 | SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 1, 2, aif2dac_text); | ||
2432 | |||
2433 | static const struct snd_kcontrol_new aif2dac_mux = | ||
2434 | SOC_DAPM_ENUM("AIF2DAC Mux", aif2dac_enum); | ||
2435 | |||
2436 | static const char *aif2adc_text[] = { | ||
2437 | "AIF2ADCDAT", "AIF3DACDAT", | ||
2438 | }; | ||
2439 | |||
2440 | static const struct soc_enum aif2adc_enum = | ||
2441 | SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 2, 2, aif2adc_text); | ||
2442 | |||
2443 | static const struct snd_kcontrol_new aif2adc_mux = | ||
2444 | SOC_DAPM_ENUM("AIF2ADC Mux", aif2adc_enum); | ||
2445 | |||
2446 | static const char *aif3adc_text[] = { | ||
2447 | "AIF1ADCDAT", "AIF2ADCDAT", "AIF2DACDAT", | ||
2448 | }; | ||
2449 | |||
2450 | static const struct soc_enum aif3adc_enum = | ||
2451 | SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 3, 3, aif3adc_text); | ||
2452 | |||
2453 | static const struct snd_kcontrol_new aif3adc_mux = | ||
2454 | SOC_DAPM_ENUM("AIF3ADC Mux", aif3adc_enum); | ||
2455 | |||
2456 | static const struct snd_soc_dapm_widget wm8994_dapm_widgets[] = { | ||
2457 | SND_SOC_DAPM_INPUT("DMIC1DAT"), | ||
2458 | SND_SOC_DAPM_INPUT("DMIC2DAT"), | ||
2459 | |||
2460 | SND_SOC_DAPM_SUPPLY("CLK_SYS", SND_SOC_NOPM, 0, 0, clk_sys_event, | ||
2461 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), | ||
2462 | |||
2463 | SND_SOC_DAPM_SUPPLY("DSP1CLK", WM8994_CLOCKING_1, 3, 0, NULL, 0), | ||
2464 | SND_SOC_DAPM_SUPPLY("DSP2CLK", WM8994_CLOCKING_1, 2, 0, NULL, 0), | ||
2465 | SND_SOC_DAPM_SUPPLY("DSPINTCLK", WM8994_CLOCKING_1, 1, 0, NULL, 0), | ||
2466 | |||
2467 | SND_SOC_DAPM_SUPPLY("AIF1CLK", WM8994_AIF1_CLOCKING_1, 0, 0, NULL, 0), | ||
2468 | SND_SOC_DAPM_SUPPLY("AIF2CLK", WM8994_AIF2_CLOCKING_1, 0, 0, NULL, 0), | ||
2469 | |||
2470 | SND_SOC_DAPM_AIF_OUT("AIF1ADC1L", "AIF1 Capture", | ||
2471 | 0, WM8994_POWER_MANAGEMENT_4, 9, 0), | ||
2472 | SND_SOC_DAPM_AIF_OUT("AIF1ADC1R", "AIF1 Capture", | ||
2473 | 0, WM8994_POWER_MANAGEMENT_4, 8, 0), | ||
2474 | SND_SOC_DAPM_AIF_IN("AIF1DAC1L", NULL, 0, | ||
2475 | WM8994_POWER_MANAGEMENT_5, 9, 0), | ||
2476 | SND_SOC_DAPM_AIF_IN("AIF1DAC1R", NULL, 0, | ||
2477 | WM8994_POWER_MANAGEMENT_5, 8, 0), | ||
2478 | |||
2479 | SND_SOC_DAPM_AIF_OUT("AIF1ADC2L", "AIF1 Capture", | ||
2480 | 0, WM8994_POWER_MANAGEMENT_4, 11, 0), | ||
2481 | SND_SOC_DAPM_AIF_OUT("AIF1ADC2R", "AIF1 Capture", | ||
2482 | 0, WM8994_POWER_MANAGEMENT_4, 10, 0), | ||
2483 | SND_SOC_DAPM_AIF_IN("AIF1DAC2L", NULL, 0, | ||
2484 | WM8994_POWER_MANAGEMENT_5, 11, 0), | ||
2485 | SND_SOC_DAPM_AIF_IN("AIF1DAC2R", NULL, 0, | ||
2486 | WM8994_POWER_MANAGEMENT_5, 10, 0), | ||
2487 | |||
2488 | SND_SOC_DAPM_MIXER("AIF1ADC1L Mixer", SND_SOC_NOPM, 0, 0, | ||
2489 | aif1adc1l_mix, ARRAY_SIZE(aif1adc1l_mix)), | ||
2490 | SND_SOC_DAPM_MIXER("AIF1ADC1R Mixer", SND_SOC_NOPM, 0, 0, | ||
2491 | aif1adc1r_mix, ARRAY_SIZE(aif1adc1r_mix)), | ||
2492 | |||
2493 | SND_SOC_DAPM_MIXER("AIF2DAC2L Mixer", SND_SOC_NOPM, 0, 0, | ||
2494 | aif2dac2l_mix, ARRAY_SIZE(aif2dac2l_mix)), | ||
2495 | SND_SOC_DAPM_MIXER("AIF2DAC2R Mixer", SND_SOC_NOPM, 0, 0, | ||
2496 | aif2dac2r_mix, ARRAY_SIZE(aif2dac2r_mix)), | ||
2497 | |||
2498 | SND_SOC_DAPM_MUX("Left Sidetone", SND_SOC_NOPM, 0, 0, &sidetone1_mux), | ||
2499 | SND_SOC_DAPM_MUX("Right Sidetone", SND_SOC_NOPM, 0, 0, &sidetone2_mux), | ||
2500 | |||
2501 | SND_SOC_DAPM_MIXER("DAC1L Mixer", SND_SOC_NOPM, 0, 0, | ||
2502 | dac1l_mix, ARRAY_SIZE(dac1l_mix)), | ||
2503 | SND_SOC_DAPM_MIXER("DAC1R Mixer", SND_SOC_NOPM, 0, 0, | ||
2504 | dac1r_mix, ARRAY_SIZE(dac1r_mix)), | ||
2505 | |||
2506 | SND_SOC_DAPM_AIF_OUT("AIF2ADCL", NULL, 0, | ||
2507 | WM8994_POWER_MANAGEMENT_4, 13, 0), | ||
2508 | SND_SOC_DAPM_AIF_OUT("AIF2ADCR", NULL, 0, | ||
2509 | WM8994_POWER_MANAGEMENT_4, 12, 0), | ||
2510 | SND_SOC_DAPM_AIF_IN("AIF2DACL", NULL, 0, | ||
2511 | WM8994_POWER_MANAGEMENT_5, 13, 0), | ||
2512 | SND_SOC_DAPM_AIF_IN("AIF2DACR", NULL, 0, | ||
2513 | WM8994_POWER_MANAGEMENT_5, 12, 0), | ||
2514 | |||
2515 | SND_SOC_DAPM_AIF_IN("AIF1DACDAT", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0), | ||
2516 | SND_SOC_DAPM_AIF_IN("AIF2DACDAT", "AIF2 Playback", 0, SND_SOC_NOPM, 0, 0), | ||
2517 | SND_SOC_DAPM_AIF_OUT("AIF2ADCDAT", "AIF2 Capture", 0, SND_SOC_NOPM, 0, 0), | ||
2518 | |||
2519 | SND_SOC_DAPM_MUX("AIF1DAC Mux", SND_SOC_NOPM, 0, 0, &aif1dac_mux), | ||
2520 | SND_SOC_DAPM_MUX("AIF2DAC Mux", SND_SOC_NOPM, 0, 0, &aif2dac_mux), | ||
2521 | SND_SOC_DAPM_MUX("AIF2ADC Mux", SND_SOC_NOPM, 0, 0, &aif2adc_mux), | ||
2522 | SND_SOC_DAPM_MUX("AIF3ADC Mux", SND_SOC_NOPM, 0, 0, &aif3adc_mux), | ||
2523 | |||
2524 | SND_SOC_DAPM_AIF_IN("AIF3DACDAT", "AIF3 Playback", 0, SND_SOC_NOPM, 0, 0), | ||
2525 | SND_SOC_DAPM_AIF_IN("AIF3ADCDAT", "AIF3 Capture", 0, SND_SOC_NOPM, 0, 0), | ||
2526 | |||
2527 | SND_SOC_DAPM_SUPPLY("TOCLK", WM8994_CLOCKING_1, 4, 0, NULL, 0), | ||
2528 | |||
2529 | SND_SOC_DAPM_ADC("DMIC2L", NULL, WM8994_POWER_MANAGEMENT_4, 5, 0), | ||
2530 | SND_SOC_DAPM_ADC("DMIC2R", NULL, WM8994_POWER_MANAGEMENT_4, 4, 0), | ||
2531 | SND_SOC_DAPM_ADC("DMIC1L", NULL, WM8994_POWER_MANAGEMENT_4, 3, 0), | ||
2532 | SND_SOC_DAPM_ADC("DMIC1R", NULL, WM8994_POWER_MANAGEMENT_4, 2, 0), | ||
2533 | |||
2534 | /* Power is done with the muxes since the ADC power also controls the | ||
2535 | * downsampling chain, the chip will automatically manage the analogue | ||
2536 | * specific portions. | ||
2537 | */ | ||
2538 | SND_SOC_DAPM_ADC("ADCL", NULL, SND_SOC_NOPM, 1, 0), | ||
2539 | SND_SOC_DAPM_ADC("ADCR", NULL, SND_SOC_NOPM, 0, 0), | ||
2540 | |||
2541 | SND_SOC_DAPM_MUX("ADCL Mux", WM8994_POWER_MANAGEMENT_4, 1, 0, &adcl_mux), | ||
2542 | SND_SOC_DAPM_MUX("ADCR Mux", WM8994_POWER_MANAGEMENT_4, 0, 0, &adcr_mux), | ||
2543 | |||
2544 | SND_SOC_DAPM_DAC("DAC2L", NULL, WM8994_POWER_MANAGEMENT_5, 3, 0), | ||
2545 | SND_SOC_DAPM_DAC("DAC2R", NULL, WM8994_POWER_MANAGEMENT_5, 2, 0), | ||
2546 | SND_SOC_DAPM_DAC("DAC1L", NULL, WM8994_POWER_MANAGEMENT_5, 1, 0), | ||
2547 | SND_SOC_DAPM_DAC("DAC1R", NULL, WM8994_POWER_MANAGEMENT_5, 0, 0), | ||
2548 | |||
2549 | SND_SOC_DAPM_MUX("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &hpl_mux), | ||
2550 | SND_SOC_DAPM_MUX("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &hpr_mux), | ||
2551 | |||
2552 | SND_SOC_DAPM_MIXER("SPKL", WM8994_POWER_MANAGEMENT_3, 8, 0, | ||
2553 | left_speaker_mixer, ARRAY_SIZE(left_speaker_mixer)), | ||
2554 | SND_SOC_DAPM_MIXER("SPKR", WM8994_POWER_MANAGEMENT_3, 9, 0, | ||
2555 | right_speaker_mixer, ARRAY_SIZE(right_speaker_mixer)), | ||
2556 | |||
2557 | SND_SOC_DAPM_POST("Debug log", post_ev), | ||
2558 | }; | ||
2559 | |||
2560 | static const struct snd_soc_dapm_route intercon[] = { | ||
2561 | |||
2562 | { "CLK_SYS", NULL, "AIF1CLK", check_clk_sys }, | ||
2563 | { "CLK_SYS", NULL, "AIF2CLK", check_clk_sys }, | ||
2564 | |||
2565 | { "DSP1CLK", NULL, "CLK_SYS" }, | ||
2566 | { "DSP2CLK", NULL, "CLK_SYS" }, | ||
2567 | { "DSPINTCLK", NULL, "CLK_SYS" }, | ||
2568 | |||
2569 | { "AIF1ADC1L", NULL, "AIF1CLK" }, | ||
2570 | { "AIF1ADC1L", NULL, "DSP1CLK" }, | ||
2571 | { "AIF1ADC1R", NULL, "AIF1CLK" }, | ||
2572 | { "AIF1ADC1R", NULL, "DSP1CLK" }, | ||
2573 | { "AIF1ADC1R", NULL, "DSPINTCLK" }, | ||
2574 | |||
2575 | { "AIF1DAC1L", NULL, "AIF1CLK" }, | ||
2576 | { "AIF1DAC1L", NULL, "DSP1CLK" }, | ||
2577 | { "AIF1DAC1R", NULL, "AIF1CLK" }, | ||
2578 | { "AIF1DAC1R", NULL, "DSP1CLK" }, | ||
2579 | { "AIF1DAC1R", NULL, "DSPINTCLK" }, | ||
2580 | |||
2581 | { "AIF1ADC2L", NULL, "AIF1CLK" }, | ||
2582 | { "AIF1ADC2L", NULL, "DSP1CLK" }, | ||
2583 | { "AIF1ADC2R", NULL, "AIF1CLK" }, | ||
2584 | { "AIF1ADC2R", NULL, "DSP1CLK" }, | ||
2585 | { "AIF1ADC2R", NULL, "DSPINTCLK" }, | ||
2586 | |||
2587 | { "AIF1DAC2L", NULL, "AIF1CLK" }, | ||
2588 | { "AIF1DAC2L", NULL, "DSP1CLK" }, | ||
2589 | { "AIF1DAC2R", NULL, "AIF1CLK" }, | ||
2590 | { "AIF1DAC2R", NULL, "DSP1CLK" }, | ||
2591 | { "AIF1DAC2R", NULL, "DSPINTCLK" }, | ||
2592 | |||
2593 | { "AIF2ADCL", NULL, "AIF2CLK" }, | ||
2594 | { "AIF2ADCL", NULL, "DSP2CLK" }, | ||
2595 | { "AIF2ADCR", NULL, "AIF2CLK" }, | ||
2596 | { "AIF2ADCR", NULL, "DSP2CLK" }, | ||
2597 | { "AIF2ADCR", NULL, "DSPINTCLK" }, | ||
2598 | |||
2599 | { "AIF2DACL", NULL, "AIF2CLK" }, | ||
2600 | { "AIF2DACL", NULL, "DSP2CLK" }, | ||
2601 | { "AIF2DACR", NULL, "AIF2CLK" }, | ||
2602 | { "AIF2DACR", NULL, "DSP2CLK" }, | ||
2603 | { "AIF2DACR", NULL, "DSPINTCLK" }, | ||
2604 | |||
2605 | { "DMIC1L", NULL, "DMIC1DAT" }, | ||
2606 | { "DMIC1L", NULL, "CLK_SYS" }, | ||
2607 | { "DMIC1R", NULL, "DMIC1DAT" }, | ||
2608 | { "DMIC1R", NULL, "CLK_SYS" }, | ||
2609 | { "DMIC2L", NULL, "DMIC2DAT" }, | ||
2610 | { "DMIC2L", NULL, "CLK_SYS" }, | ||
2611 | { "DMIC2R", NULL, "DMIC2DAT" }, | ||
2612 | { "DMIC2R", NULL, "CLK_SYS" }, | ||
2613 | |||
2614 | { "ADCL", NULL, "AIF1CLK" }, | ||
2615 | { "ADCL", NULL, "DSP1CLK" }, | ||
2616 | { "ADCL", NULL, "DSPINTCLK" }, | ||
2617 | |||
2618 | { "ADCR", NULL, "AIF1CLK" }, | ||
2619 | { "ADCR", NULL, "DSP1CLK" }, | ||
2620 | { "ADCR", NULL, "DSPINTCLK" }, | ||
2621 | |||
2622 | { "ADCL Mux", "ADC", "ADCL" }, | ||
2623 | { "ADCL Mux", "DMIC", "DMIC1L" }, | ||
2624 | { "ADCR Mux", "ADC", "ADCR" }, | ||
2625 | { "ADCR Mux", "DMIC", "DMIC1R" }, | ||
2626 | |||
2627 | { "DAC1L", NULL, "AIF1CLK" }, | ||
2628 | { "DAC1L", NULL, "DSP1CLK" }, | ||
2629 | { "DAC1L", NULL, "DSPINTCLK" }, | ||
2630 | |||
2631 | { "DAC1R", NULL, "AIF1CLK" }, | ||
2632 | { "DAC1R", NULL, "DSP1CLK" }, | ||
2633 | { "DAC1R", NULL, "DSPINTCLK" }, | ||
2634 | |||
2635 | { "DAC2L", NULL, "AIF2CLK" }, | ||
2636 | { "DAC2L", NULL, "DSP2CLK" }, | ||
2637 | { "DAC2L", NULL, "DSPINTCLK" }, | ||
2638 | |||
2639 | { "DAC2R", NULL, "AIF2DACR" }, | ||
2640 | { "DAC2R", NULL, "AIF2CLK" }, | ||
2641 | { "DAC2R", NULL, "DSP2CLK" }, | ||
2642 | { "DAC2R", NULL, "DSPINTCLK" }, | ||
2643 | |||
2644 | { "TOCLK", NULL, "CLK_SYS" }, | ||
2645 | |||
2646 | /* AIF1 outputs */ | ||
2647 | { "AIF1ADC1L", NULL, "AIF1ADC1L Mixer" }, | ||
2648 | { "AIF1ADC1L Mixer", "ADC/DMIC Switch", "ADCL Mux" }, | ||
2649 | { "AIF1ADC1L Mixer", "AIF2 Switch", "AIF2DACL" }, | ||
2650 | |||
2651 | { "AIF1ADC1R", NULL, "AIF1ADC1R Mixer" }, | ||
2652 | { "AIF1ADC1R Mixer", "ADC/DMIC Switch", "ADCR Mux" }, | ||
2653 | { "AIF1ADC1R Mixer", "AIF2 Switch", "AIF2DACR" }, | ||
2654 | |||
2655 | /* Pin level routing for AIF3 */ | ||
2656 | { "AIF1DAC1L", NULL, "AIF1DAC Mux" }, | ||
2657 | { "AIF1DAC1R", NULL, "AIF1DAC Mux" }, | ||
2658 | { "AIF1DAC2L", NULL, "AIF1DAC Mux" }, | ||
2659 | { "AIF1DAC2R", NULL, "AIF1DAC Mux" }, | ||
2660 | |||
2661 | { "AIF2DACL", NULL, "AIF2DAC Mux" }, | ||
2662 | { "AIF2DACR", NULL, "AIF2DAC Mux" }, | ||
2663 | |||
2664 | { "AIF1DAC Mux", "AIF1DACDAT", "AIF1DACDAT" }, | ||
2665 | { "AIF1DAC Mux", "AIF3DACDAT", "AIF3DACDAT" }, | ||
2666 | { "AIF2DAC Mux", "AIF2DACDAT", "AIF2DACDAT" }, | ||
2667 | { "AIF2DAC Mux", "AIF3DACDAT", "AIF3DACDAT" }, | ||
2668 | { "AIF2ADC Mux", "AIF2ADCDAT", "AIF2ADCL" }, | ||
2669 | { "AIF2ADC Mux", "AIF2ADCDAT", "AIF2ADCR" }, | ||
2670 | { "AIF2ADC Mux", "AIF3DACDAT", "AIF3ADCDAT" }, | ||
2671 | |||
2672 | /* DAC1 inputs */ | ||
2673 | { "DAC1L", NULL, "DAC1L Mixer" }, | ||
2674 | { "DAC1L Mixer", "AIF2 Switch", "AIF2DACL" }, | ||
2675 | { "DAC1L Mixer", "AIF1.2 Switch", "AIF1DAC2L" }, | ||
2676 | { "DAC1L Mixer", "AIF1.1 Switch", "AIF1DAC1L" }, | ||
2677 | { "DAC1L Mixer", "Left Sidetone Switch", "Left Sidetone" }, | ||
2678 | { "DAC1L Mixer", "Right Sidetone Switch", "Right Sidetone" }, | ||
2679 | |||
2680 | { "DAC1R", NULL, "DAC1R Mixer" }, | ||
2681 | { "DAC1R Mixer", "AIF2 Switch", "AIF2DACR" }, | ||
2682 | { "DAC1R Mixer", "AIF1.2 Switch", "AIF1DAC2R" }, | ||
2683 | { "DAC1R Mixer", "AIF1.1 Switch", "AIF1DAC1R" }, | ||
2684 | { "DAC1R Mixer", "Left Sidetone Switch", "Left Sidetone" }, | ||
2685 | { "DAC1R Mixer", "Right Sidetone Switch", "Right Sidetone" }, | ||
2686 | |||
2687 | /* DAC2/AIF2 outputs */ | ||
2688 | { "AIF2ADCL", NULL, "AIF2DAC2L Mixer" }, | ||
2689 | { "DAC2L", NULL, "AIF2DAC2L Mixer" }, | ||
2690 | { "AIF2DAC2L Mixer", "AIF2 Switch", "AIF2DACL" }, | ||
2691 | { "AIF2DAC2L Mixer", "AIF1.2 Switch", "AIF1DAC2L" }, | ||
2692 | { "AIF2DAC2L Mixer", "AIF1.1 Switch", "AIF1DAC1L" }, | ||
2693 | { "AIF2DAC2L Mixer", "Left Sidetone Switch", "Left Sidetone" }, | ||
2694 | { "AIF2DAC2L Mixer", "Right Sidetone Switch", "Right Sidetone" }, | ||
2695 | |||
2696 | { "AIF2ADCR", NULL, "AIF2DAC2R Mixer" }, | ||
2697 | { "DAC2R", NULL, "AIF2DAC2R Mixer" }, | ||
2698 | { "AIF2DAC2R Mixer", "AIF2 Switch", "AIF2DACR" }, | ||
2699 | { "AIF2DAC2R Mixer", "AIF1.2 Switch", "AIF1DAC2R" }, | ||
2700 | { "AIF2DAC2R Mixer", "AIF1.1 Switch", "AIF1DAC1R" }, | ||
2701 | { "AIF2DAC2R Mixer", "Left Sidetone Switch", "Left Sidetone" }, | ||
2702 | { "AIF2DAC2R Mixer", "Right Sidetone Switch", "Right Sidetone" }, | ||
2703 | |||
2704 | { "AIF2ADCDAT", NULL, "AIF2ADC Mux" }, | ||
2705 | |||
2706 | /* AIF3 output */ | ||
2707 | { "AIF3ADCDAT", "AIF1ADCDAT", "AIF1ADC1L" }, | ||
2708 | { "AIF3ADCDAT", "AIF1ADCDAT", "AIF1ADC1R" }, | ||
2709 | { "AIF3ADCDAT", "AIF1ADCDAT", "AIF1ADC2L" }, | ||
2710 | { "AIF3ADCDAT", "AIF1ADCDAT", "AIF1ADC2R" }, | ||
2711 | { "AIF3ADCDAT", "AIF2ADCDAT", "AIF2ADCL" }, | ||
2712 | { "AIF3ADCDAT", "AIF2ADCDAT", "AIF2ADCR" }, | ||
2713 | { "AIF3ADCDAT", "AIF2DACDAT", "AIF2DACL" }, | ||
2714 | { "AIF3ADCDAT", "AIF2DACDAT", "AIF2DACR" }, | ||
2715 | |||
2716 | /* Sidetone */ | ||
2717 | { "Left Sidetone", "ADC/DMIC1", "ADCL Mux" }, | ||
2718 | { "Left Sidetone", "DMIC2", "DMIC2L" }, | ||
2719 | { "Right Sidetone", "ADC/DMIC1", "ADCR Mux" }, | ||
2720 | { "Right Sidetone", "DMIC2", "DMIC2R" }, | ||
2721 | |||
2722 | /* Output stages */ | ||
2723 | { "Left Output Mixer", "DAC Switch", "DAC1L" }, | ||
2724 | { "Right Output Mixer", "DAC Switch", "DAC1R" }, | ||
2725 | |||
2726 | { "SPKL", "DAC1 Switch", "DAC1L" }, | ||
2727 | { "SPKL", "DAC2 Switch", "DAC2L" }, | ||
2728 | |||
2729 | { "SPKR", "DAC1 Switch", "DAC1R" }, | ||
2730 | { "SPKR", "DAC2 Switch", "DAC2R" }, | ||
2731 | |||
2732 | { "Left Headphone Mux", "DAC", "DAC1L" }, | ||
2733 | { "Right Headphone Mux", "DAC", "DAC1R" }, | ||
2734 | }; | ||
2735 | |||
2736 | /* The size in bits of the FLL divide multiplied by 10 | ||
2737 | * to allow rounding later */ | ||
2738 | #define FIXED_FLL_SIZE ((1 << 16) * 10) | ||
2739 | |||
2740 | struct fll_div { | ||
2741 | u16 outdiv; | ||
2742 | u16 n; | ||
2743 | u16 k; | ||
2744 | u16 clk_ref_div; | ||
2745 | u16 fll_fratio; | ||
2746 | }; | ||
2747 | |||
2748 | static int wm8994_get_fll_config(struct fll_div *fll, | ||
2749 | int freq_in, int freq_out) | ||
2750 | { | ||
2751 | u64 Kpart; | ||
2752 | unsigned int K, Ndiv, Nmod; | ||
2753 | |||
2754 | pr_debug("FLL input=%dHz, output=%dHz\n", freq_in, freq_out); | ||
2755 | |||
2756 | /* Scale the input frequency down to <= 13.5MHz */ | ||
2757 | fll->clk_ref_div = 0; | ||
2758 | while (freq_in > 13500000) { | ||
2759 | fll->clk_ref_div++; | ||
2760 | freq_in /= 2; | ||
2761 | |||
2762 | if (fll->clk_ref_div > 3) | ||
2763 | return -EINVAL; | ||
2764 | } | ||
2765 | pr_debug("CLK_REF_DIV=%d, Fref=%dHz\n", fll->clk_ref_div, freq_in); | ||
2766 | |||
2767 | /* Scale the output to give 90MHz<=Fvco<=100MHz */ | ||
2768 | fll->outdiv = 3; | ||
2769 | while (freq_out * (fll->outdiv + 1) < 90000000) { | ||
2770 | fll->outdiv++; | ||
2771 | if (fll->outdiv > 63) | ||
2772 | return -EINVAL; | ||
2773 | } | ||
2774 | freq_out *= fll->outdiv + 1; | ||
2775 | pr_debug("OUTDIV=%d, Fvco=%dHz\n", fll->outdiv, freq_out); | ||
2776 | |||
2777 | if (freq_in > 1000000) { | ||
2778 | fll->fll_fratio = 0; | ||
2779 | } else { | ||
2780 | fll->fll_fratio = 3; | ||
2781 | freq_in *= 8; | ||
2782 | } | ||
2783 | pr_debug("FLL_FRATIO=%d, Fref=%dHz\n", fll->fll_fratio, freq_in); | ||
2784 | |||
2785 | /* Now, calculate N.K */ | ||
2786 | Ndiv = freq_out / freq_in; | ||
2787 | |||
2788 | fll->n = Ndiv; | ||
2789 | Nmod = freq_out % freq_in; | ||
2790 | pr_debug("Nmod=%d\n", Nmod); | ||
2791 | |||
2792 | /* Calculate fractional part - scale up so we can round. */ | ||
2793 | Kpart = FIXED_FLL_SIZE * (long long)Nmod; | ||
2794 | |||
2795 | do_div(Kpart, freq_in); | ||
2796 | |||
2797 | K = Kpart & 0xFFFFFFFF; | ||
2798 | |||
2799 | if ((K % 10) >= 5) | ||
2800 | K += 5; | ||
2801 | |||
2802 | /* Move down to proper range now rounding is done */ | ||
2803 | fll->k = K / 10; | ||
2804 | |||
2805 | pr_debug("N=%x K=%x\n", fll->n, fll->k); | ||
2806 | |||
2807 | return 0; | ||
2808 | } | ||
2809 | |||
2810 | static int wm8994_set_fll(struct snd_soc_dai *dai, int id, int src, | ||
2811 | unsigned int freq_in, unsigned int freq_out) | ||
2812 | { | ||
2813 | struct snd_soc_codec *codec = dai->codec; | ||
2814 | struct wm8994_priv *wm8994 = codec->private_data; | ||
2815 | int reg_offset, ret; | ||
2816 | struct fll_div fll; | ||
2817 | u16 reg, aif1, aif2; | ||
2818 | |||
2819 | aif1 = snd_soc_read(codec, WM8994_AIF1_CLOCKING_1) | ||
2820 | & WM8994_AIF1CLK_ENA; | ||
2821 | |||
2822 | aif2 = snd_soc_read(codec, WM8994_AIF2_CLOCKING_1) | ||
2823 | & WM8994_AIF2CLK_ENA; | ||
2824 | |||
2825 | switch (id) { | ||
2826 | case WM8994_FLL1: | ||
2827 | reg_offset = 0; | ||
2828 | id = 0; | ||
2829 | break; | ||
2830 | case WM8994_FLL2: | ||
2831 | reg_offset = 0x20; | ||
2832 | id = 1; | ||
2833 | break; | ||
2834 | default: | ||
2835 | return -EINVAL; | ||
2836 | } | ||
2837 | |||
2838 | /* Are we changing anything? */ | ||
2839 | if (wm8994->fll[id].src == src && | ||
2840 | wm8994->fll[id].in == freq_in && wm8994->fll[id].out == freq_out) | ||
2841 | return 0; | ||
2842 | |||
2843 | /* If we're stopping the FLL redo the old config - no | ||
2844 | * registers will actually be written but we avoid GCC flow | ||
2845 | * analysis bugs spewing warnings. | ||
2846 | */ | ||
2847 | if (freq_out) | ||
2848 | ret = wm8994_get_fll_config(&fll, freq_in, freq_out); | ||
2849 | else | ||
2850 | ret = wm8994_get_fll_config(&fll, wm8994->fll[id].in, | ||
2851 | wm8994->fll[id].out); | ||
2852 | if (ret < 0) | ||
2853 | return ret; | ||
2854 | |||
2855 | /* Gate the AIF clocks while we reclock */ | ||
2856 | snd_soc_update_bits(codec, WM8994_AIF1_CLOCKING_1, | ||
2857 | WM8994_AIF1CLK_ENA, 0); | ||
2858 | snd_soc_update_bits(codec, WM8994_AIF2_CLOCKING_1, | ||
2859 | WM8994_AIF2CLK_ENA, 0); | ||
2860 | |||
2861 | /* We always need to disable the FLL while reconfiguring */ | ||
2862 | snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_1 + reg_offset, | ||
2863 | WM8994_FLL1_ENA, 0); | ||
2864 | |||
2865 | reg = (fll.outdiv << WM8994_FLL1_OUTDIV_SHIFT) | | ||
2866 | (fll.fll_fratio << WM8994_FLL1_FRATIO_SHIFT); | ||
2867 | snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_2 + reg_offset, | ||
2868 | WM8994_FLL1_OUTDIV_MASK | | ||
2869 | WM8994_FLL1_FRATIO_MASK, reg); | ||
2870 | |||
2871 | snd_soc_write(codec, WM8994_FLL1_CONTROL_3 + reg_offset, fll.k); | ||
2872 | |||
2873 | snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_4 + reg_offset, | ||
2874 | WM8994_FLL1_N_MASK, | ||
2875 | fll.n << WM8994_FLL1_N_SHIFT); | ||
2876 | |||
2877 | snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_5 + reg_offset, | ||
2878 | WM8994_FLL1_REFCLK_DIV_MASK, | ||
2879 | fll.clk_ref_div << WM8994_FLL1_REFCLK_DIV_SHIFT); | ||
2880 | |||
2881 | /* Enable (with fractional mode if required) */ | ||
2882 | if (freq_out) { | ||
2883 | if (fll.k) | ||
2884 | reg = WM8994_FLL1_ENA | WM8994_FLL1_FRAC; | ||
2885 | else | ||
2886 | reg = WM8994_FLL1_ENA; | ||
2887 | snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_1 + reg_offset, | ||
2888 | WM8994_FLL1_ENA | WM8994_FLL1_FRAC, | ||
2889 | reg); | ||
2890 | } | ||
2891 | |||
2892 | wm8994->fll[id].in = freq_in; | ||
2893 | wm8994->fll[id].out = freq_out; | ||
2894 | |||
2895 | /* Enable any gated AIF clocks */ | ||
2896 | snd_soc_update_bits(codec, WM8994_AIF1_CLOCKING_1, | ||
2897 | WM8994_AIF1CLK_ENA, aif1); | ||
2898 | snd_soc_update_bits(codec, WM8994_AIF2_CLOCKING_1, | ||
2899 | WM8994_AIF2CLK_ENA, aif2); | ||
2900 | |||
2901 | configure_clock(codec); | ||
2902 | |||
2903 | return 0; | ||
2904 | } | ||
2905 | |||
2906 | static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai, | ||
2907 | int clk_id, unsigned int freq, int dir) | ||
2908 | { | ||
2909 | struct snd_soc_codec *codec = dai->codec; | ||
2910 | struct wm8994_priv *wm8994 = codec->private_data; | ||
2911 | |||
2912 | switch (dai->id) { | ||
2913 | case 1: | ||
2914 | case 2: | ||
2915 | break; | ||
2916 | |||
2917 | default: | ||
2918 | /* AIF3 shares clocking with AIF1/2 */ | ||
2919 | return -EINVAL; | ||
2920 | } | ||
2921 | |||
2922 | switch (clk_id) { | ||
2923 | case WM8994_SYSCLK_MCLK1: | ||
2924 | wm8994->sysclk[dai->id - 1] = WM8994_SYSCLK_MCLK1; | ||
2925 | wm8994->mclk[0] = freq; | ||
2926 | dev_dbg(dai->dev, "AIF%d using MCLK1 at %uHz\n", | ||
2927 | dai->id, freq); | ||
2928 | break; | ||
2929 | |||
2930 | case WM8994_SYSCLK_MCLK2: | ||
2931 | /* TODO: Set GPIO AF */ | ||
2932 | wm8994->sysclk[dai->id - 1] = WM8994_SYSCLK_MCLK2; | ||
2933 | wm8994->mclk[1] = freq; | ||
2934 | dev_dbg(dai->dev, "AIF%d using MCLK2 at %uHz\n", | ||
2935 | dai->id, freq); | ||
2936 | break; | ||
2937 | |||
2938 | case WM8994_SYSCLK_FLL1: | ||
2939 | wm8994->sysclk[dai->id - 1] = WM8994_SYSCLK_FLL1; | ||
2940 | dev_dbg(dai->dev, "AIF%d using FLL1\n", dai->id); | ||
2941 | break; | ||
2942 | |||
2943 | case WM8994_SYSCLK_FLL2: | ||
2944 | wm8994->sysclk[dai->id - 1] = WM8994_SYSCLK_FLL2; | ||
2945 | dev_dbg(dai->dev, "AIF%d using FLL2\n", dai->id); | ||
2946 | break; | ||
2947 | |||
2948 | default: | ||
2949 | return -EINVAL; | ||
2950 | } | ||
2951 | |||
2952 | configure_clock(codec); | ||
2953 | |||
2954 | return 0; | ||
2955 | } | ||
2956 | |||
2957 | static int wm8994_set_bias_level(struct snd_soc_codec *codec, | ||
2958 | enum snd_soc_bias_level level) | ||
2959 | { | ||
2960 | switch (level) { | ||
2961 | case SND_SOC_BIAS_ON: | ||
2962 | break; | ||
2963 | |||
2964 | case SND_SOC_BIAS_PREPARE: | ||
2965 | /* VMID=2x40k */ | ||
2966 | snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1, | ||
2967 | WM8994_VMID_SEL_MASK, 0x2); | ||
2968 | break; | ||
2969 | |||
2970 | case SND_SOC_BIAS_STANDBY: | ||
2971 | if (codec->bias_level == SND_SOC_BIAS_OFF) { | ||
2972 | /* Tweak DC servo configuration for improved | ||
2973 | * performance. */ | ||
2974 | snd_soc_write(codec, 0x102, 0x3); | ||
2975 | snd_soc_write(codec, 0x56, 0x3); | ||
2976 | snd_soc_write(codec, 0x102, 0); | ||
2977 | |||
2978 | /* Discharge LINEOUT1 & 2 */ | ||
2979 | snd_soc_update_bits(codec, WM8994_ANTIPOP_1, | ||
2980 | WM8994_LINEOUT1_DISCH | | ||
2981 | WM8994_LINEOUT2_DISCH, | ||
2982 | WM8994_LINEOUT1_DISCH | | ||
2983 | WM8994_LINEOUT2_DISCH); | ||
2984 | |||
2985 | /* Startup bias, VMID ramp & buffer */ | ||
2986 | snd_soc_update_bits(codec, WM8994_ANTIPOP_2, | ||
2987 | WM8994_STARTUP_BIAS_ENA | | ||
2988 | WM8994_VMID_BUF_ENA | | ||
2989 | WM8994_VMID_RAMP_MASK, | ||
2990 | WM8994_STARTUP_BIAS_ENA | | ||
2991 | WM8994_VMID_BUF_ENA | | ||
2992 | (0x11 << WM8994_VMID_RAMP_SHIFT)); | ||
2993 | |||
2994 | /* Main bias enable, VMID=2x40k */ | ||
2995 | snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1, | ||
2996 | WM8994_BIAS_ENA | | ||
2997 | WM8994_VMID_SEL_MASK, | ||
2998 | WM8994_BIAS_ENA | 0x2); | ||
2999 | |||
3000 | msleep(20); | ||
3001 | } | ||
3002 | |||
3003 | /* VMID=2x500k */ | ||
3004 | snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1, | ||
3005 | WM8994_VMID_SEL_MASK, 0x4); | ||
3006 | |||
3007 | break; | ||
3008 | |||
3009 | case SND_SOC_BIAS_OFF: | ||
3010 | /* Switch over to startup biases */ | ||
3011 | snd_soc_update_bits(codec, WM8994_ANTIPOP_2, | ||
3012 | WM8994_BIAS_SRC | WM8994_STARTUP_BIAS_ENA | | ||
3013 | WM8994_VMID_BUF_ENA | | ||
3014 | WM8994_VMID_RAMP_MASK, | ||
3015 | WM8994_BIAS_SRC | WM8994_STARTUP_BIAS_ENA | | ||
3016 | WM8994_VMID_BUF_ENA | | ||
3017 | (1 << WM8994_VMID_RAMP_SHIFT)); | ||
3018 | |||
3019 | /* Disable main biases */ | ||
3020 | snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1, | ||
3021 | WM8994_BIAS_ENA | WM8994_VMID_SEL_MASK, 0); | ||
3022 | |||
3023 | /* Discharge line */ | ||
3024 | snd_soc_update_bits(codec, WM8994_ANTIPOP_1, | ||
3025 | WM8994_LINEOUT1_DISCH | | ||
3026 | WM8994_LINEOUT2_DISCH, | ||
3027 | WM8994_LINEOUT1_DISCH | | ||
3028 | WM8994_LINEOUT2_DISCH); | ||
3029 | |||
3030 | msleep(5); | ||
3031 | |||
3032 | /* Switch off startup biases */ | ||
3033 | snd_soc_update_bits(codec, WM8994_ANTIPOP_2, | ||
3034 | WM8994_BIAS_SRC | WM8994_STARTUP_BIAS_ENA | | ||
3035 | WM8994_VMID_BUF_ENA | | ||
3036 | WM8994_VMID_RAMP_MASK, 0); | ||
3037 | |||
3038 | break; | ||
3039 | } | ||
3040 | codec->bias_level = level; | ||
3041 | return 0; | ||
3042 | } | ||
3043 | |||
3044 | static int wm8994_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) | ||
3045 | { | ||
3046 | struct snd_soc_codec *codec = dai->codec; | ||
3047 | int ms_reg; | ||
3048 | int aif1_reg; | ||
3049 | int ms = 0; | ||
3050 | int aif1 = 0; | ||
3051 | |||
3052 | switch (dai->id) { | ||
3053 | case 1: | ||
3054 | ms_reg = WM8994_AIF1_MASTER_SLAVE; | ||
3055 | aif1_reg = WM8994_AIF1_CONTROL_1; | ||
3056 | break; | ||
3057 | case 2: | ||
3058 | ms_reg = WM8994_AIF2_MASTER_SLAVE; | ||
3059 | aif1_reg = WM8994_AIF2_CONTROL_1; | ||
3060 | break; | ||
3061 | default: | ||
3062 | return -EINVAL; | ||
3063 | } | ||
3064 | |||
3065 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
3066 | case SND_SOC_DAIFMT_CBS_CFS: | ||
3067 | break; | ||
3068 | case SND_SOC_DAIFMT_CBM_CFM: | ||
3069 | ms = WM8994_AIF1_MSTR; | ||
3070 | break; | ||
3071 | default: | ||
3072 | return -EINVAL; | ||
3073 | } | ||
3074 | |||
3075 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
3076 | case SND_SOC_DAIFMT_DSP_B: | ||
3077 | aif1 |= WM8994_AIF1_LRCLK_INV; | ||
3078 | case SND_SOC_DAIFMT_DSP_A: | ||
3079 | aif1 |= 0x18; | ||
3080 | break; | ||
3081 | case SND_SOC_DAIFMT_I2S: | ||
3082 | aif1 |= 0x10; | ||
3083 | break; | ||
3084 | case SND_SOC_DAIFMT_RIGHT_J: | ||
3085 | break; | ||
3086 | case SND_SOC_DAIFMT_LEFT_J: | ||
3087 | aif1 |= 0x8; | ||
3088 | break; | ||
3089 | default: | ||
3090 | return -EINVAL; | ||
3091 | } | ||
3092 | |||
3093 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
3094 | case SND_SOC_DAIFMT_DSP_A: | ||
3095 | case SND_SOC_DAIFMT_DSP_B: | ||
3096 | /* frame inversion not valid for DSP modes */ | ||
3097 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
3098 | case SND_SOC_DAIFMT_NB_NF: | ||
3099 | break; | ||
3100 | case SND_SOC_DAIFMT_IB_NF: | ||
3101 | aif1 |= WM8994_AIF1_BCLK_INV; | ||
3102 | break; | ||
3103 | default: | ||
3104 | return -EINVAL; | ||
3105 | } | ||
3106 | break; | ||
3107 | |||
3108 | case SND_SOC_DAIFMT_I2S: | ||
3109 | case SND_SOC_DAIFMT_RIGHT_J: | ||
3110 | case SND_SOC_DAIFMT_LEFT_J: | ||
3111 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
3112 | case SND_SOC_DAIFMT_NB_NF: | ||
3113 | break; | ||
3114 | case SND_SOC_DAIFMT_IB_IF: | ||
3115 | aif1 |= WM8994_AIF1_BCLK_INV | WM8994_AIF1_LRCLK_INV; | ||
3116 | break; | ||
3117 | case SND_SOC_DAIFMT_IB_NF: | ||
3118 | aif1 |= WM8994_AIF1_BCLK_INV; | ||
3119 | break; | ||
3120 | case SND_SOC_DAIFMT_NB_IF: | ||
3121 | aif1 |= WM8994_AIF1_LRCLK_INV; | ||
3122 | break; | ||
3123 | default: | ||
3124 | return -EINVAL; | ||
3125 | } | ||
3126 | break; | ||
3127 | default: | ||
3128 | return -EINVAL; | ||
3129 | } | ||
3130 | |||
3131 | snd_soc_update_bits(codec, aif1_reg, | ||
3132 | WM8994_AIF1_BCLK_INV | WM8994_AIF1_LRCLK_INV | | ||
3133 | WM8994_AIF1_FMT_MASK, | ||
3134 | aif1); | ||
3135 | snd_soc_update_bits(codec, ms_reg, WM8994_AIF1_MSTR, | ||
3136 | ms); | ||
3137 | |||
3138 | return 0; | ||
3139 | } | ||
3140 | |||
3141 | static struct { | ||
3142 | int val, rate; | ||
3143 | } srs[] = { | ||
3144 | { 0, 8000 }, | ||
3145 | { 1, 11025 }, | ||
3146 | { 2, 12000 }, | ||
3147 | { 3, 16000 }, | ||
3148 | { 4, 22050 }, | ||
3149 | { 5, 24000 }, | ||
3150 | { 6, 32000 }, | ||
3151 | { 7, 44100 }, | ||
3152 | { 8, 48000 }, | ||
3153 | { 9, 88200 }, | ||
3154 | { 10, 96000 }, | ||
3155 | }; | ||
3156 | |||
3157 | static int fs_ratios[] = { | ||
3158 | 64, 128, 192, 256, 348, 512, 768, 1024, 1408, 1536 | ||
3159 | }; | ||
3160 | |||
3161 | static int bclk_divs[] = { | ||
3162 | 10, 15, 20, 30, 40, 50, 60, 80, 110, 120, 160, 220, 240, 320, 440, 480, | ||
3163 | 640, 880, 960, 1280, 1760, 1920 | ||
3164 | }; | ||
3165 | |||
3166 | static int wm8994_hw_params(struct snd_pcm_substream *substream, | ||
3167 | struct snd_pcm_hw_params *params, | ||
3168 | struct snd_soc_dai *dai) | ||
3169 | { | ||
3170 | struct snd_soc_codec *codec = dai->codec; | ||
3171 | struct wm8994_priv *wm8994 = codec->private_data; | ||
3172 | int aif1_reg; | ||
3173 | int bclk_reg; | ||
3174 | int lrclk_reg; | ||
3175 | int rate_reg; | ||
3176 | int aif1 = 0; | ||
3177 | int bclk = 0; | ||
3178 | int lrclk = 0; | ||
3179 | int rate_val = 0; | ||
3180 | int id = dai->id - 1; | ||
3181 | |||
3182 | int i, cur_val, best_val, bclk_rate, best; | ||
3183 | |||
3184 | switch (dai->id) { | ||
3185 | case 1: | ||
3186 | aif1_reg = WM8994_AIF1_CONTROL_1; | ||
3187 | bclk_reg = WM8994_AIF1_BCLK; | ||
3188 | rate_reg = WM8994_AIF1_RATE; | ||
3189 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK || | ||
3190 | wm8994->lrclk_shared[0]) | ||
3191 | lrclk_reg = WM8994_AIF1DAC_LRCLK; | ||
3192 | else | ||
3193 | lrclk_reg = WM8994_AIF1ADC_LRCLK; | ||
3194 | break; | ||
3195 | case 2: | ||
3196 | aif1_reg = WM8994_AIF2_CONTROL_1; | ||
3197 | bclk_reg = WM8994_AIF2_BCLK; | ||
3198 | rate_reg = WM8994_AIF2_RATE; | ||
3199 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK || | ||
3200 | wm8994->lrclk_shared[1]) | ||
3201 | lrclk_reg = WM8994_AIF2DAC_LRCLK; | ||
3202 | else | ||
3203 | lrclk_reg = WM8994_AIF2ADC_LRCLK; | ||
3204 | break; | ||
3205 | default: | ||
3206 | return -EINVAL; | ||
3207 | } | ||
3208 | |||
3209 | bclk_rate = params_rate(params) * 2; | ||
3210 | switch (params_format(params)) { | ||
3211 | case SNDRV_PCM_FORMAT_S16_LE: | ||
3212 | bclk_rate *= 16; | ||
3213 | break; | ||
3214 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
3215 | bclk_rate *= 20; | ||
3216 | aif1 |= 0x20; | ||
3217 | break; | ||
3218 | case SNDRV_PCM_FORMAT_S24_LE: | ||
3219 | bclk_rate *= 24; | ||
3220 | aif1 |= 0x40; | ||
3221 | break; | ||
3222 | case SNDRV_PCM_FORMAT_S32_LE: | ||
3223 | bclk_rate *= 32; | ||
3224 | aif1 |= 0x60; | ||
3225 | break; | ||
3226 | default: | ||
3227 | return -EINVAL; | ||
3228 | } | ||
3229 | |||
3230 | /* Try to find an appropriate sample rate; look for an exact match. */ | ||
3231 | for (i = 0; i < ARRAY_SIZE(srs); i++) | ||
3232 | if (srs[i].rate == params_rate(params)) | ||
3233 | break; | ||
3234 | if (i == ARRAY_SIZE(srs)) | ||
3235 | return -EINVAL; | ||
3236 | rate_val |= srs[i].val << WM8994_AIF1_SR_SHIFT; | ||
3237 | |||
3238 | dev_dbg(dai->dev, "Sample rate is %dHz\n", srs[i].rate); | ||
3239 | dev_dbg(dai->dev, "AIF%dCLK is %dHz, target BCLK %dHz\n", | ||
3240 | dai->id, wm8994->aifclk[id], bclk_rate); | ||
3241 | |||
3242 | if (wm8994->aifclk[id] == 0) { | ||
3243 | dev_err(dai->dev, "AIF%dCLK not configured\n", dai->id); | ||
3244 | return -EINVAL; | ||
3245 | } | ||
3246 | |||
3247 | /* AIFCLK/fs ratio; look for a close match in either direction */ | ||
3248 | best = 0; | ||
3249 | best_val = abs((fs_ratios[0] * params_rate(params)) | ||
3250 | - wm8994->aifclk[id]); | ||
3251 | for (i = 1; i < ARRAY_SIZE(fs_ratios); i++) { | ||
3252 | cur_val = abs((fs_ratios[i] * params_rate(params)) | ||
3253 | - wm8994->aifclk[id]); | ||
3254 | if (cur_val >= best_val) | ||
3255 | continue; | ||
3256 | best = i; | ||
3257 | best_val = cur_val; | ||
3258 | } | ||
3259 | dev_dbg(dai->dev, "Selected AIF%dCLK/fs = %d\n", | ||
3260 | dai->id, fs_ratios[best]); | ||
3261 | rate_val |= best; | ||
3262 | |||
3263 | /* We may not get quite the right frequency if using | ||
3264 | * approximate clocks so look for the closest match that is | ||
3265 | * higher than the target (we need to ensure that there enough | ||
3266 | * BCLKs to clock out the samples). | ||
3267 | */ | ||
3268 | best = 0; | ||
3269 | for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) { | ||
3270 | cur_val = (wm8994->aifclk[id] * 10 / bclk_divs[i]) - bclk_rate; | ||
3271 | if (cur_val < 0) /* BCLK table is sorted */ | ||
3272 | break; | ||
3273 | best = i; | ||
3274 | } | ||
3275 | bclk_rate = wm8994->aifclk[id] * 10 / bclk_divs[best]; | ||
3276 | dev_dbg(dai->dev, "Using BCLK_DIV %d for actual BCLK %dHz\n", | ||
3277 | bclk_divs[best], bclk_rate); | ||
3278 | bclk |= best << WM8994_AIF1_BCLK_DIV_SHIFT; | ||
3279 | |||
3280 | lrclk = bclk_rate / params_rate(params); | ||
3281 | dev_dbg(dai->dev, "Using LRCLK rate %d for actual LRCLK %dHz\n", | ||
3282 | lrclk, bclk_rate / lrclk); | ||
3283 | |||
3284 | snd_soc_update_bits(codec, aif1_reg, WM8994_AIF1_WL_MASK, aif1); | ||
3285 | snd_soc_update_bits(codec, bclk_reg, WM8994_AIF1_BCLK_DIV_MASK, bclk); | ||
3286 | snd_soc_update_bits(codec, lrclk_reg, WM8994_AIF1DAC_RATE_MASK, | ||
3287 | lrclk); | ||
3288 | snd_soc_update_bits(codec, rate_reg, WM8994_AIF1_SR_MASK | | ||
3289 | WM8994_AIF1CLK_RATE_MASK, rate_val); | ||
3290 | |||
3291 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
3292 | switch (dai->id) { | ||
3293 | case 1: | ||
3294 | wm8994->dac_rates[0] = params_rate(params); | ||
3295 | wm8994_set_retune_mobile(codec, 0); | ||
3296 | wm8994_set_retune_mobile(codec, 1); | ||
3297 | break; | ||
3298 | case 2: | ||
3299 | wm8994->dac_rates[1] = params_rate(params); | ||
3300 | wm8994_set_retune_mobile(codec, 2); | ||
3301 | break; | ||
3302 | } | ||
3303 | } | ||
3304 | |||
3305 | return 0; | ||
3306 | } | ||
3307 | |||
3308 | static int wm8994_aif_mute(struct snd_soc_dai *codec_dai, int mute) | ||
3309 | { | ||
3310 | struct snd_soc_codec *codec = codec_dai->codec; | ||
3311 | int mute_reg; | ||
3312 | int reg; | ||
3313 | |||
3314 | switch (codec_dai->id) { | ||
3315 | case 1: | ||
3316 | mute_reg = WM8994_AIF1_DAC1_FILTERS_1; | ||
3317 | break; | ||
3318 | case 2: | ||
3319 | mute_reg = WM8994_AIF2_DAC_FILTERS_1; | ||
3320 | break; | ||
3321 | default: | ||
3322 | return -EINVAL; | ||
3323 | } | ||
3324 | |||
3325 | if (mute) | ||
3326 | reg = WM8994_AIF1DAC1_MUTE; | ||
3327 | else | ||
3328 | reg = 0; | ||
3329 | |||
3330 | snd_soc_update_bits(codec, mute_reg, WM8994_AIF1DAC1_MUTE, reg); | ||
3331 | |||
3332 | return 0; | ||
3333 | } | ||
3334 | |||
3335 | #define WM8994_RATES SNDRV_PCM_RATE_8000_96000 | ||
3336 | |||
3337 | #define WM8994_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | ||
3338 | SNDRV_PCM_FMTBIT_S24_LE) | ||
3339 | |||
3340 | static struct snd_soc_dai_ops wm8994_aif1_dai_ops = { | ||
3341 | .set_sysclk = wm8994_set_dai_sysclk, | ||
3342 | .set_fmt = wm8994_set_dai_fmt, | ||
3343 | .hw_params = wm8994_hw_params, | ||
3344 | .digital_mute = wm8994_aif_mute, | ||
3345 | .set_pll = wm8994_set_fll, | ||
3346 | }; | ||
3347 | |||
3348 | static struct snd_soc_dai_ops wm8994_aif2_dai_ops = { | ||
3349 | .set_sysclk = wm8994_set_dai_sysclk, | ||
3350 | .set_fmt = wm8994_set_dai_fmt, | ||
3351 | .hw_params = wm8994_hw_params, | ||
3352 | .digital_mute = wm8994_aif_mute, | ||
3353 | .set_pll = wm8994_set_fll, | ||
3354 | }; | ||
3355 | |||
3356 | struct snd_soc_dai wm8994_dai[] = { | ||
3357 | { | ||
3358 | .name = "WM8994 AIF1", | ||
3359 | .id = 1, | ||
3360 | .playback = { | ||
3361 | .stream_name = "AIF1 Playback", | ||
3362 | .channels_min = 2, | ||
3363 | .channels_max = 2, | ||
3364 | .rates = WM8994_RATES, | ||
3365 | .formats = WM8994_FORMATS, | ||
3366 | }, | ||
3367 | .capture = { | ||
3368 | .stream_name = "AIF1 Capture", | ||
3369 | .channels_min = 2, | ||
3370 | .channels_max = 2, | ||
3371 | .rates = WM8994_RATES, | ||
3372 | .formats = WM8994_FORMATS, | ||
3373 | }, | ||
3374 | .ops = &wm8994_aif1_dai_ops, | ||
3375 | }, | ||
3376 | { | ||
3377 | .name = "WM8994 AIF2", | ||
3378 | .id = 2, | ||
3379 | .playback = { | ||
3380 | .stream_name = "AIF2 Playback", | ||
3381 | .channels_min = 2, | ||
3382 | .channels_max = 2, | ||
3383 | .rates = WM8994_RATES, | ||
3384 | .formats = WM8994_FORMATS, | ||
3385 | }, | ||
3386 | .capture = { | ||
3387 | .stream_name = "AIF2 Capture", | ||
3388 | .channels_min = 2, | ||
3389 | .channels_max = 2, | ||
3390 | .rates = WM8994_RATES, | ||
3391 | .formats = WM8994_FORMATS, | ||
3392 | }, | ||
3393 | .ops = &wm8994_aif2_dai_ops, | ||
3394 | }, | ||
3395 | { | ||
3396 | .name = "WM8994 AIF3", | ||
3397 | .playback = { | ||
3398 | .stream_name = "AIF3 Playback", | ||
3399 | .channels_min = 2, | ||
3400 | .channels_max = 2, | ||
3401 | .rates = WM8994_RATES, | ||
3402 | .formats = WM8994_FORMATS, | ||
3403 | }, | ||
3404 | .playback = { | ||
3405 | .stream_name = "AIF3 Capture", | ||
3406 | .channels_min = 2, | ||
3407 | .channels_max = 2, | ||
3408 | .rates = WM8994_RATES, | ||
3409 | .formats = WM8994_FORMATS, | ||
3410 | }, | ||
3411 | } | ||
3412 | }; | ||
3413 | EXPORT_SYMBOL_GPL(wm8994_dai); | ||
3414 | |||
3415 | #ifdef CONFIG_PM | ||
3416 | static int wm8994_suspend(struct platform_device *pdev, pm_message_t state) | ||
3417 | { | ||
3418 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
3419 | struct snd_soc_codec *codec = socdev->card->codec; | ||
3420 | struct wm8994_priv *wm8994 = codec->private_data; | ||
3421 | int i, ret; | ||
3422 | |||
3423 | for (i = 0; i < ARRAY_SIZE(wm8994->fll); i++) { | ||
3424 | memcpy(&wm8994->fll_suspend[i], &wm8994->fll[i], | ||
3425 | sizeof(struct fll_config)); | ||
3426 | ret = wm8994_set_fll(&codec->dai[0], i + 1, 0, 0, 0); | ||
3427 | if (ret < 0) | ||
3428 | dev_warn(codec->dev, "Failed to stop FLL%d: %d\n", | ||
3429 | i + 1, ret); | ||
3430 | } | ||
3431 | |||
3432 | wm8994_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
3433 | |||
3434 | return 0; | ||
3435 | } | ||
3436 | |||
3437 | static int wm8994_resume(struct platform_device *pdev) | ||
3438 | { | ||
3439 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
3440 | struct snd_soc_codec *codec = socdev->card->codec; | ||
3441 | struct wm8994_priv *wm8994 = codec->private_data; | ||
3442 | u16 *reg_cache = codec->reg_cache; | ||
3443 | int i, ret; | ||
3444 | |||
3445 | /* Restore the registers */ | ||
3446 | for (i = 1; i < ARRAY_SIZE(wm8994->reg_cache); i++) { | ||
3447 | switch (i) { | ||
3448 | case WM8994_LDO_1: | ||
3449 | case WM8994_LDO_2: | ||
3450 | case WM8994_SOFTWARE_RESET: | ||
3451 | /* Handled by other MFD drivers */ | ||
3452 | continue; | ||
3453 | default: | ||
3454 | break; | ||
3455 | } | ||
3456 | |||
3457 | if (!access_masks[i].writable) | ||
3458 | continue; | ||
3459 | |||
3460 | wm8994_reg_write(codec->control_data, i, reg_cache[i]); | ||
3461 | } | ||
3462 | |||
3463 | wm8994_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
3464 | |||
3465 | for (i = 0; i < ARRAY_SIZE(wm8994->fll); i++) { | ||
3466 | ret = wm8994_set_fll(&codec->dai[0], i + 1, | ||
3467 | wm8994->fll_suspend[i].src, | ||
3468 | wm8994->fll_suspend[i].in, | ||
3469 | wm8994->fll_suspend[i].out); | ||
3470 | if (ret < 0) | ||
3471 | dev_warn(codec->dev, "Failed to restore FLL%d: %d\n", | ||
3472 | i + 1, ret); | ||
3473 | } | ||
3474 | |||
3475 | return 0; | ||
3476 | } | ||
3477 | #else | ||
3478 | #define wm8994_suspend NULL | ||
3479 | #define wm8994_resume NULL | ||
3480 | #endif | ||
3481 | |||
3482 | static void wm8994_handle_retune_mobile_pdata(struct wm8994_priv *wm8994) | ||
3483 | { | ||
3484 | struct snd_soc_codec *codec = &wm8994->codec; | ||
3485 | struct wm8994_pdata *pdata = wm8994->pdata; | ||
3486 | struct snd_kcontrol_new controls[] = { | ||
3487 | SOC_ENUM_EXT("AIF1.1 EQ Mode", | ||
3488 | wm8994->retune_mobile_enum, | ||
3489 | wm8994_get_retune_mobile_enum, | ||
3490 | wm8994_put_retune_mobile_enum), | ||
3491 | SOC_ENUM_EXT("AIF1.2 EQ Mode", | ||
3492 | wm8994->retune_mobile_enum, | ||
3493 | wm8994_get_retune_mobile_enum, | ||
3494 | wm8994_put_retune_mobile_enum), | ||
3495 | SOC_ENUM_EXT("AIF2 EQ Mode", | ||
3496 | wm8994->retune_mobile_enum, | ||
3497 | wm8994_get_retune_mobile_enum, | ||
3498 | wm8994_put_retune_mobile_enum), | ||
3499 | }; | ||
3500 | int ret, i, j; | ||
3501 | const char **t; | ||
3502 | |||
3503 | /* We need an array of texts for the enum API but the number | ||
3504 | * of texts is likely to be less than the number of | ||
3505 | * configurations due to the sample rate dependency of the | ||
3506 | * configurations. */ | ||
3507 | wm8994->num_retune_mobile_texts = 0; | ||
3508 | wm8994->retune_mobile_texts = NULL; | ||
3509 | for (i = 0; i < pdata->num_retune_mobile_cfgs; i++) { | ||
3510 | for (j = 0; j < wm8994->num_retune_mobile_texts; j++) { | ||
3511 | if (strcmp(pdata->retune_mobile_cfgs[i].name, | ||
3512 | wm8994->retune_mobile_texts[j]) == 0) | ||
3513 | break; | ||
3514 | } | ||
3515 | |||
3516 | if (j != wm8994->num_retune_mobile_texts) | ||
3517 | continue; | ||
3518 | |||
3519 | /* Expand the array... */ | ||
3520 | t = krealloc(wm8994->retune_mobile_texts, | ||
3521 | sizeof(char *) * | ||
3522 | (wm8994->num_retune_mobile_texts + 1), | ||
3523 | GFP_KERNEL); | ||
3524 | if (t == NULL) | ||
3525 | continue; | ||
3526 | |||
3527 | /* ...store the new entry... */ | ||
3528 | t[wm8994->num_retune_mobile_texts] = | ||
3529 | pdata->retune_mobile_cfgs[i].name; | ||
3530 | |||
3531 | /* ...and remember the new version. */ | ||
3532 | wm8994->num_retune_mobile_texts++; | ||
3533 | wm8994->retune_mobile_texts = t; | ||
3534 | } | ||
3535 | |||
3536 | dev_dbg(codec->dev, "Allocated %d unique ReTune Mobile names\n", | ||
3537 | wm8994->num_retune_mobile_texts); | ||
3538 | |||
3539 | wm8994->retune_mobile_enum.max = wm8994->num_retune_mobile_texts; | ||
3540 | wm8994->retune_mobile_enum.texts = wm8994->retune_mobile_texts; | ||
3541 | |||
3542 | ret = snd_soc_add_controls(&wm8994->codec, controls, | ||
3543 | ARRAY_SIZE(controls)); | ||
3544 | if (ret != 0) | ||
3545 | dev_err(wm8994->codec.dev, | ||
3546 | "Failed to add ReTune Mobile controls: %d\n", ret); | ||
3547 | } | ||
3548 | |||
3549 | static void wm8994_handle_pdata(struct wm8994_priv *wm8994) | ||
3550 | { | ||
3551 | struct snd_soc_codec *codec = &wm8994->codec; | ||
3552 | struct wm8994_pdata *pdata = wm8994->pdata; | ||
3553 | int ret, i; | ||
3554 | |||
3555 | if (!pdata) | ||
3556 | return; | ||
3557 | |||
3558 | wm_hubs_handle_analogue_pdata(codec, pdata->lineout1_diff, | ||
3559 | pdata->lineout2_diff, | ||
3560 | pdata->lineout1fb, | ||
3561 | pdata->lineout2fb, | ||
3562 | pdata->jd_scthr, | ||
3563 | pdata->jd_thr, | ||
3564 | pdata->micbias1_lvl, | ||
3565 | pdata->micbias2_lvl); | ||
3566 | |||
3567 | dev_dbg(codec->dev, "%d DRC configurations\n", pdata->num_drc_cfgs); | ||
3568 | |||
3569 | if (pdata->num_drc_cfgs) { | ||
3570 | struct snd_kcontrol_new controls[] = { | ||
3571 | SOC_ENUM_EXT("AIF1DRC1 Mode", wm8994->drc_enum, | ||
3572 | wm8994_get_drc_enum, wm8994_put_drc_enum), | ||
3573 | SOC_ENUM_EXT("AIF1DRC2 Mode", wm8994->drc_enum, | ||
3574 | wm8994_get_drc_enum, wm8994_put_drc_enum), | ||
3575 | SOC_ENUM_EXT("AIF2DRC Mode", wm8994->drc_enum, | ||
3576 | wm8994_get_drc_enum, wm8994_put_drc_enum), | ||
3577 | }; | ||
3578 | |||
3579 | /* We need an array of texts for the enum API */ | ||
3580 | wm8994->drc_texts = kmalloc(sizeof(char *) | ||
3581 | * pdata->num_drc_cfgs, GFP_KERNEL); | ||
3582 | if (!wm8994->drc_texts) { | ||
3583 | dev_err(wm8994->codec.dev, | ||
3584 | "Failed to allocate %d DRC config texts\n", | ||
3585 | pdata->num_drc_cfgs); | ||
3586 | return; | ||
3587 | } | ||
3588 | |||
3589 | for (i = 0; i < pdata->num_drc_cfgs; i++) | ||
3590 | wm8994->drc_texts[i] = pdata->drc_cfgs[i].name; | ||
3591 | |||
3592 | wm8994->drc_enum.max = pdata->num_drc_cfgs; | ||
3593 | wm8994->drc_enum.texts = wm8994->drc_texts; | ||
3594 | |||
3595 | ret = snd_soc_add_controls(&wm8994->codec, controls, | ||
3596 | ARRAY_SIZE(controls)); | ||
3597 | if (ret != 0) | ||
3598 | dev_err(wm8994->codec.dev, | ||
3599 | "Failed to add DRC mode controls: %d\n", ret); | ||
3600 | |||
3601 | for (i = 0; i < WM8994_NUM_DRC; i++) | ||
3602 | wm8994_set_drc(codec, i); | ||
3603 | } | ||
3604 | |||
3605 | dev_dbg(codec->dev, "%d ReTune Mobile configurations\n", | ||
3606 | pdata->num_retune_mobile_cfgs); | ||
3607 | |||
3608 | if (pdata->num_retune_mobile_cfgs) | ||
3609 | wm8994_handle_retune_mobile_pdata(wm8994); | ||
3610 | else | ||
3611 | snd_soc_add_controls(&wm8994->codec, wm8994_eq_controls, | ||
3612 | ARRAY_SIZE(wm8994_eq_controls)); | ||
3613 | } | ||
3614 | |||
3615 | static int wm8994_probe(struct platform_device *pdev) | ||
3616 | { | ||
3617 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
3618 | struct snd_soc_codec *codec; | ||
3619 | int ret = 0; | ||
3620 | |||
3621 | if (wm8994_codec == NULL) { | ||
3622 | dev_err(&pdev->dev, "Codec device not registered\n"); | ||
3623 | return -ENODEV; | ||
3624 | } | ||
3625 | |||
3626 | socdev->card->codec = wm8994_codec; | ||
3627 | codec = wm8994_codec; | ||
3628 | |||
3629 | /* register pcms */ | ||
3630 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
3631 | if (ret < 0) { | ||
3632 | dev_err(codec->dev, "failed to create pcms: %d\n", ret); | ||
3633 | return ret; | ||
3634 | } | ||
3635 | |||
3636 | wm8994_handle_pdata(codec->private_data); | ||
3637 | |||
3638 | wm_hubs_add_analogue_controls(codec); | ||
3639 | snd_soc_add_controls(codec, wm8994_snd_controls, | ||
3640 | ARRAY_SIZE(wm8994_snd_controls)); | ||
3641 | snd_soc_dapm_new_controls(codec, wm8994_dapm_widgets, | ||
3642 | ARRAY_SIZE(wm8994_dapm_widgets)); | ||
3643 | wm_hubs_add_analogue_routes(codec, 0, 0); | ||
3644 | snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); | ||
3645 | |||
3646 | return 0; | ||
3647 | } | ||
3648 | |||
3649 | static int wm8994_remove(struct platform_device *pdev) | ||
3650 | { | ||
3651 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
3652 | |||
3653 | snd_soc_free_pcms(socdev); | ||
3654 | snd_soc_dapm_free(socdev); | ||
3655 | |||
3656 | return 0; | ||
3657 | } | ||
3658 | |||
3659 | struct snd_soc_codec_device soc_codec_dev_wm8994 = { | ||
3660 | .probe = wm8994_probe, | ||
3661 | .remove = wm8994_remove, | ||
3662 | .suspend = wm8994_suspend, | ||
3663 | .resume = wm8994_resume, | ||
3664 | }; | ||
3665 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8994); | ||
3666 | |||
3667 | static int wm8994_codec_probe(struct platform_device *pdev) | ||
3668 | { | ||
3669 | int ret; | ||
3670 | struct wm8994_priv *wm8994; | ||
3671 | struct snd_soc_codec *codec; | ||
3672 | int i; | ||
3673 | u16 rev; | ||
3674 | |||
3675 | if (wm8994_codec) { | ||
3676 | dev_err(&pdev->dev, "Another WM8994 is registered\n"); | ||
3677 | return -EINVAL; | ||
3678 | } | ||
3679 | |||
3680 | wm8994 = kzalloc(sizeof(struct wm8994_priv), GFP_KERNEL); | ||
3681 | if (!wm8994) { | ||
3682 | dev_err(&pdev->dev, "Failed to allocate private data\n"); | ||
3683 | return -ENOMEM; | ||
3684 | } | ||
3685 | |||
3686 | codec = &wm8994->codec; | ||
3687 | |||
3688 | mutex_init(&codec->mutex); | ||
3689 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
3690 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
3691 | |||
3692 | codec->private_data = wm8994; | ||
3693 | codec->control_data = dev_get_drvdata(pdev->dev.parent); | ||
3694 | codec->name = "WM8994"; | ||
3695 | codec->owner = THIS_MODULE; | ||
3696 | codec->read = wm8994_read; | ||
3697 | codec->write = wm8994_write; | ||
3698 | codec->readable_register = wm8994_readable; | ||
3699 | codec->bias_level = SND_SOC_BIAS_OFF; | ||
3700 | codec->set_bias_level = wm8994_set_bias_level; | ||
3701 | codec->dai = &wm8994_dai[0]; | ||
3702 | codec->num_dai = 3; | ||
3703 | codec->reg_cache_size = WM8994_MAX_REGISTER; | ||
3704 | codec->reg_cache = &wm8994->reg_cache; | ||
3705 | codec->dev = &pdev->dev; | ||
3706 | |||
3707 | wm8994->pdata = pdev->dev.parent->platform_data; | ||
3708 | |||
3709 | /* Fill the cache with physical values we inherited; don't reset */ | ||
3710 | ret = wm8994_bulk_read(codec->control_data, 0, | ||
3711 | ARRAY_SIZE(wm8994->reg_cache) - 1, | ||
3712 | codec->reg_cache); | ||
3713 | if (ret < 0) { | ||
3714 | dev_err(codec->dev, "Failed to fill register cache: %d\n", | ||
3715 | ret); | ||
3716 | goto err; | ||
3717 | } | ||
3718 | |||
3719 | /* Clear the cached values for unreadable/volatile registers to | ||
3720 | * avoid potential confusion. | ||
3721 | */ | ||
3722 | for (i = 0; i < ARRAY_SIZE(wm8994->reg_cache); i++) | ||
3723 | if (wm8994_volatile(i) || !wm8994_readable(i)) | ||
3724 | wm8994->reg_cache[i] = 0; | ||
3725 | |||
3726 | /* Set revision-specific configuration */ | ||
3727 | rev = snd_soc_read(codec, WM8994_CHIP_REVISION); | ||
3728 | switch (rev) { | ||
3729 | case 2: | ||
3730 | case 3: | ||
3731 | wm8994->hubs.dcs_codes = -5; | ||
3732 | wm8994->hubs.hp_startup_mode = 1; | ||
3733 | break; | ||
3734 | default: | ||
3735 | break; | ||
3736 | } | ||
3737 | |||
3738 | |||
3739 | /* Remember if AIFnLRCLK is configured as a GPIO. This should be | ||
3740 | * configured on init - if a system wants to do this dynamically | ||
3741 | * at runtime we can deal with that then. | ||
3742 | */ | ||
3743 | ret = wm8994_reg_read(codec->control_data, WM8994_GPIO_1); | ||
3744 | if (ret < 0) { | ||
3745 | dev_err(codec->dev, "Failed to read GPIO1 state: %d\n", ret); | ||
3746 | goto err; | ||
3747 | } | ||
3748 | if ((ret & WM8994_GPN_FN_MASK) != WM8994_GP_FN_PIN_SPECIFIC) { | ||
3749 | wm8994->lrclk_shared[0] = 1; | ||
3750 | wm8994_dai[0].symmetric_rates = 1; | ||
3751 | } else { | ||
3752 | wm8994->lrclk_shared[0] = 0; | ||
3753 | } | ||
3754 | |||
3755 | ret = wm8994_reg_read(codec->control_data, WM8994_GPIO_6); | ||
3756 | if (ret < 0) { | ||
3757 | dev_err(codec->dev, "Failed to read GPIO6 state: %d\n", ret); | ||
3758 | goto err; | ||
3759 | } | ||
3760 | if ((ret & WM8994_GPN_FN_MASK) != WM8994_GP_FN_PIN_SPECIFIC) { | ||
3761 | wm8994->lrclk_shared[1] = 1; | ||
3762 | wm8994_dai[1].symmetric_rates = 1; | ||
3763 | } else { | ||
3764 | wm8994->lrclk_shared[1] = 0; | ||
3765 | } | ||
3766 | |||
3767 | for (i = 0; i < ARRAY_SIZE(wm8994_dai); i++) | ||
3768 | wm8994_dai[i].dev = codec->dev; | ||
3769 | |||
3770 | wm8994_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
3771 | |||
3772 | wm8994_codec = codec; | ||
3773 | |||
3774 | /* Latch volume updates (right only; we always do left then right). */ | ||
3775 | snd_soc_update_bits(codec, WM8994_AIF1_DAC1_RIGHT_VOLUME, | ||
3776 | WM8994_AIF1DAC1_VU, WM8994_AIF1DAC1_VU); | ||
3777 | snd_soc_update_bits(codec, WM8994_AIF1_DAC2_RIGHT_VOLUME, | ||
3778 | WM8994_AIF1DAC2_VU, WM8994_AIF1DAC2_VU); | ||
3779 | snd_soc_update_bits(codec, WM8994_AIF2_DAC_RIGHT_VOLUME, | ||
3780 | WM8994_AIF2DAC_VU, WM8994_AIF2DAC_VU); | ||
3781 | snd_soc_update_bits(codec, WM8994_AIF1_ADC1_RIGHT_VOLUME, | ||
3782 | WM8994_AIF1ADC1_VU, WM8994_AIF1ADC1_VU); | ||
3783 | snd_soc_update_bits(codec, WM8994_AIF1_ADC2_RIGHT_VOLUME, | ||
3784 | WM8994_AIF1ADC2_VU, WM8994_AIF1ADC2_VU); | ||
3785 | snd_soc_update_bits(codec, WM8994_AIF2_ADC_RIGHT_VOLUME, | ||
3786 | WM8994_AIF2ADC_VU, WM8994_AIF1ADC2_VU); | ||
3787 | snd_soc_update_bits(codec, WM8994_DAC1_RIGHT_VOLUME, | ||
3788 | WM8994_DAC1_VU, WM8994_DAC1_VU); | ||
3789 | snd_soc_update_bits(codec, WM8994_DAC2_RIGHT_VOLUME, | ||
3790 | WM8994_DAC2_VU, WM8994_DAC2_VU); | ||
3791 | |||
3792 | /* Set the low bit of the 3D stereo depth so TLV matches */ | ||
3793 | snd_soc_update_bits(codec, WM8994_AIF1_DAC1_FILTERS_2, | ||
3794 | 1 << WM8994_AIF1DAC1_3D_GAIN_SHIFT, | ||
3795 | 1 << WM8994_AIF1DAC1_3D_GAIN_SHIFT); | ||
3796 | snd_soc_update_bits(codec, WM8994_AIF1_DAC2_FILTERS_2, | ||
3797 | 1 << WM8994_AIF1DAC2_3D_GAIN_SHIFT, | ||
3798 | 1 << WM8994_AIF1DAC2_3D_GAIN_SHIFT); | ||
3799 | snd_soc_update_bits(codec, WM8994_AIF2_DAC_FILTERS_2, | ||
3800 | 1 << WM8994_AIF2DAC_3D_GAIN_SHIFT, | ||
3801 | 1 << WM8994_AIF2DAC_3D_GAIN_SHIFT); | ||
3802 | |||
3803 | wm8994_update_class_w(codec); | ||
3804 | |||
3805 | ret = snd_soc_register_codec(codec); | ||
3806 | if (ret != 0) { | ||
3807 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); | ||
3808 | goto err; | ||
3809 | } | ||
3810 | |||
3811 | ret = snd_soc_register_dais(wm8994_dai, ARRAY_SIZE(wm8994_dai)); | ||
3812 | if (ret != 0) { | ||
3813 | dev_err(codec->dev, "Failed to register DAIs: %d\n", ret); | ||
3814 | goto err_codec; | ||
3815 | } | ||
3816 | |||
3817 | platform_set_drvdata(pdev, wm8994); | ||
3818 | |||
3819 | return 0; | ||
3820 | |||
3821 | err_codec: | ||
3822 | snd_soc_unregister_codec(codec); | ||
3823 | err: | ||
3824 | kfree(wm8994); | ||
3825 | return ret; | ||
3826 | } | ||
3827 | |||
3828 | static int __devexit wm8994_codec_remove(struct platform_device *pdev) | ||
3829 | { | ||
3830 | struct wm8994_priv *wm8994 = platform_get_drvdata(pdev); | ||
3831 | struct snd_soc_codec *codec = &wm8994->codec; | ||
3832 | |||
3833 | wm8994_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
3834 | snd_soc_unregister_dais(wm8994_dai, ARRAY_SIZE(wm8994_dai)); | ||
3835 | snd_soc_unregister_codec(&wm8994->codec); | ||
3836 | kfree(wm8994); | ||
3837 | wm8994_codec = NULL; | ||
3838 | |||
3839 | return 0; | ||
3840 | } | ||
3841 | |||
3842 | static struct platform_driver wm8994_codec_driver = { | ||
3843 | .driver = { | ||
3844 | .name = "wm8994-codec", | ||
3845 | .owner = THIS_MODULE, | ||
3846 | }, | ||
3847 | .probe = wm8994_codec_probe, | ||
3848 | .remove = __devexit_p(wm8994_codec_remove), | ||
3849 | }; | ||
3850 | |||
3851 | static __init int wm8994_init(void) | ||
3852 | { | ||
3853 | return platform_driver_register(&wm8994_codec_driver); | ||
3854 | } | ||
3855 | module_init(wm8994_init); | ||
3856 | |||
3857 | static __exit void wm8994_exit(void) | ||
3858 | { | ||
3859 | platform_driver_unregister(&wm8994_codec_driver); | ||
3860 | } | ||
3861 | module_exit(wm8994_exit); | ||
3862 | |||
3863 | |||
3864 | MODULE_DESCRIPTION("ASoC WM8994 driver"); | ||
3865 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); | ||
3866 | MODULE_LICENSE("GPL"); | ||
3867 | MODULE_ALIAS("platform:wm8994-codec"); | ||
diff --git a/sound/soc/codecs/wm8994.h b/sound/soc/codecs/wm8994.h new file mode 100644 index 000000000000..0a5e1424dea0 --- /dev/null +++ b/sound/soc/codecs/wm8994.h | |||
@@ -0,0 +1,26 @@ | |||
1 | /* | ||
2 | * wm8994.h -- WM8994 Soc Audio driver | ||
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 _WM8994_H | ||
10 | #define _WM8994_H | ||
11 | |||
12 | #include <sound/soc.h> | ||
13 | |||
14 | extern struct snd_soc_codec_device soc_codec_dev_wm8994; | ||
15 | extern struct snd_soc_dai wm8994_dai[]; | ||
16 | |||
17 | /* Sources for AIF1/2 SYSCLK - use with set_dai_sysclk() */ | ||
18 | #define WM8994_SYSCLK_MCLK1 1 | ||
19 | #define WM8994_SYSCLK_MCLK2 2 | ||
20 | #define WM8994_SYSCLK_FLL1 3 | ||
21 | #define WM8994_SYSCLK_FLL2 4 | ||
22 | |||
23 | #define WM8994_FLL1 1 | ||
24 | #define WM8994_FLL2 2 | ||
25 | |||
26 | #endif | ||
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index c58aab375edb..ceb86b4ddb25 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c | |||
@@ -23,13 +23,12 @@ | |||
23 | #include <sound/ac97_codec.h> | 23 | #include <sound/ac97_codec.h> |
24 | #include <sound/initval.h> | 24 | #include <sound/initval.h> |
25 | #include <sound/pcm_params.h> | 25 | #include <sound/pcm_params.h> |
26 | #include <sound/tlv.h> | ||
26 | #include <sound/soc.h> | 27 | #include <sound/soc.h> |
27 | #include <sound/soc-dapm.h> | 28 | #include <sound/soc-dapm.h> |
28 | 29 | ||
29 | #include "wm9713.h" | 30 | #include "wm9713.h" |
30 | 31 | ||
31 | #define WM9713_VERSION "0.15" | ||
32 | |||
33 | struct wm9713_priv { | 32 | struct wm9713_priv { |
34 | u32 pll_in; /* PLL input frequency */ | 33 | u32 pll_in; /* PLL input frequency */ |
35 | }; | 34 | }; |
@@ -115,15 +114,27 @@ SOC_ENUM_SINGLE(AC97_3D_CONTROL, 12, 3, wm9713_mic_select), /* mic selection 18 | |||
115 | SOC_ENUM_SINGLE(MICB_MUX, 0, 2, wm9713_micb_select), /* mic selection 19 */ | 114 | SOC_ENUM_SINGLE(MICB_MUX, 0, 2, wm9713_micb_select), /* mic selection 19 */ |
116 | }; | 115 | }; |
117 | 116 | ||
117 | static const DECLARE_TLV_DB_SCALE(out_tlv, -4650, 150, 0); | ||
118 | static const DECLARE_TLV_DB_SCALE(main_tlv, -3450, 150, 0); | ||
119 | static const DECLARE_TLV_DB_SCALE(misc_tlv, -1500, 300, 0); | ||
120 | static unsigned int mic_tlv[] = { | ||
121 | TLV_DB_RANGE_HEAD(2), | ||
122 | 0, 2, TLV_DB_SCALE_ITEM(1200, 600, 0), | ||
123 | 3, 3, TLV_DB_SCALE_ITEM(3000, 0, 0), | ||
124 | }; | ||
125 | |||
118 | static const struct snd_kcontrol_new wm9713_snd_ac97_controls[] = { | 126 | static const struct snd_kcontrol_new wm9713_snd_ac97_controls[] = { |
119 | SOC_DOUBLE("Speaker Playback Volume", AC97_MASTER, 8, 0, 31, 1), | 127 | SOC_DOUBLE_TLV("Speaker Playback Volume", AC97_MASTER, 8, 0, 31, 1, out_tlv), |
120 | SOC_DOUBLE("Speaker Playback Switch", AC97_MASTER, 15, 7, 1, 1), | 128 | SOC_DOUBLE("Speaker Playback Switch", AC97_MASTER, 15, 7, 1, 1), |
121 | SOC_DOUBLE("Headphone Playback Volume", AC97_HEADPHONE, 8, 0, 31, 1), | 129 | SOC_DOUBLE_TLV("Headphone Playback Volume", AC97_HEADPHONE, 8, 0, 31, 1, |
130 | out_tlv), | ||
122 | SOC_DOUBLE("Headphone Playback Switch", AC97_HEADPHONE, 15, 7, 1, 1), | 131 | SOC_DOUBLE("Headphone Playback Switch", AC97_HEADPHONE, 15, 7, 1, 1), |
123 | SOC_DOUBLE("Line In Volume", AC97_PC_BEEP, 8, 0, 31, 1), | 132 | SOC_DOUBLE_TLV("Line In Volume", AC97_PC_BEEP, 8, 0, 31, 1, main_tlv), |
124 | SOC_DOUBLE("PCM Playback Volume", AC97_PHONE, 8, 0, 31, 1), | 133 | SOC_DOUBLE_TLV("PCM Playback Volume", AC97_PHONE, 8, 0, 31, 1, main_tlv), |
125 | SOC_SINGLE("Mic 1 Volume", AC97_MIC, 8, 31, 1), | 134 | SOC_SINGLE_TLV("Mic 1 Volume", AC97_MIC, 8, 31, 1, main_tlv), |
126 | SOC_SINGLE("Mic 2 Volume", AC97_MIC, 0, 31, 1), | 135 | SOC_SINGLE_TLV("Mic 2 Volume", AC97_MIC, 0, 31, 1, main_tlv), |
136 | SOC_SINGLE_TLV("Mic 1 Preamp Volume", AC97_3D_CONTROL, 10, 3, 0, mic_tlv), | ||
137 | SOC_SINGLE_TLV("Mic 2 Preamp Volume", AC97_3D_CONTROL, 12, 3, 0, mic_tlv), | ||
127 | 138 | ||
128 | SOC_SINGLE("Mic Boost (+20dB) Switch", AC97_LINE, 5, 1, 0), | 139 | SOC_SINGLE("Mic Boost (+20dB) Switch", AC97_LINE, 5, 1, 0), |
129 | SOC_SINGLE("Mic Headphone Mixer Volume", AC97_LINE, 0, 7, 1), | 140 | SOC_SINGLE("Mic Headphone Mixer Volume", AC97_LINE, 0, 7, 1), |
@@ -133,7 +144,7 @@ SOC_ENUM("Capture Volume Steps", wm9713_enum[5]), | |||
133 | SOC_DOUBLE("Capture Volume", AC97_CD, 8, 0, 31, 0), | 144 | SOC_DOUBLE("Capture Volume", AC97_CD, 8, 0, 31, 0), |
134 | SOC_SINGLE("Capture ZC Switch", AC97_CD, 7, 1, 0), | 145 | SOC_SINGLE("Capture ZC Switch", AC97_CD, 7, 1, 0), |
135 | 146 | ||
136 | SOC_SINGLE("Capture to Headphone Volume", AC97_VIDEO, 11, 7, 1), | 147 | SOC_SINGLE_TLV("Capture to Headphone Volume", AC97_VIDEO, 11, 7, 1, misc_tlv), |
137 | SOC_SINGLE("Capture to Mono Boost (+20dB) Switch", AC97_VIDEO, 8, 1, 0), | 148 | SOC_SINGLE("Capture to Mono Boost (+20dB) Switch", AC97_VIDEO, 8, 1, 0), |
138 | SOC_SINGLE("Capture ADC Boost (+20dB) Switch", AC97_VIDEO, 6, 1, 0), | 149 | SOC_SINGLE("Capture ADC Boost (+20dB) Switch", AC97_VIDEO, 6, 1, 0), |
139 | 150 | ||
@@ -154,28 +165,43 @@ SOC_DOUBLE("Headphone Playback ZC Switch", AC97_HEADPHONE, 14, 6, 1, 0), | |||
154 | 165 | ||
155 | SOC_SINGLE("Out4 Playback Switch", AC97_MASTER_MONO, 15, 1, 1), | 166 | SOC_SINGLE("Out4 Playback Switch", AC97_MASTER_MONO, 15, 1, 1), |
156 | SOC_SINGLE("Out4 Playback ZC Switch", AC97_MASTER_MONO, 14, 1, 0), | 167 | SOC_SINGLE("Out4 Playback ZC Switch", AC97_MASTER_MONO, 14, 1, 0), |
157 | SOC_SINGLE("Out4 Playback Volume", AC97_MASTER_MONO, 8, 63, 1), | 168 | SOC_SINGLE_TLV("Out4 Playback Volume", AC97_MASTER_MONO, 8, 31, 1, out_tlv), |
158 | 169 | ||
159 | SOC_SINGLE("Out3 Playback Switch", AC97_MASTER_MONO, 7, 1, 1), | 170 | SOC_SINGLE("Out3 Playback Switch", AC97_MASTER_MONO, 7, 1, 1), |
160 | SOC_SINGLE("Out3 Playback ZC Switch", AC97_MASTER_MONO, 6, 1, 0), | 171 | SOC_SINGLE("Out3 Playback ZC Switch", AC97_MASTER_MONO, 6, 1, 0), |
161 | SOC_SINGLE("Out3 Playback Volume", AC97_MASTER_MONO, 0, 63, 1), | 172 | SOC_SINGLE_TLV("Out3 Playback Volume", AC97_MASTER_MONO, 0, 31, 1, out_tlv), |
162 | 173 | ||
163 | SOC_SINGLE("Mono Capture Volume", AC97_MASTER_TONE, 8, 31, 1), | 174 | SOC_SINGLE_TLV("Mono Capture Volume", AC97_MASTER_TONE, 8, 31, 1, main_tlv), |
164 | SOC_SINGLE("Mono Playback Switch", AC97_MASTER_TONE, 7, 1, 1), | 175 | SOC_SINGLE("Mono Playback Switch", AC97_MASTER_TONE, 7, 1, 1), |
165 | SOC_SINGLE("Mono Playback ZC Switch", AC97_MASTER_TONE, 6, 1, 0), | 176 | SOC_SINGLE("Mono Playback ZC Switch", AC97_MASTER_TONE, 6, 1, 0), |
166 | SOC_SINGLE("Mono Playback Volume", AC97_MASTER_TONE, 0, 31, 1), | 177 | SOC_SINGLE_TLV("Mono Playback Volume", AC97_MASTER_TONE, 0, 31, 1, out_tlv), |
167 | 178 | ||
168 | SOC_SINGLE("Beep Playback Headphone Volume", AC97_AUX, 12, 7, 1), | 179 | SOC_SINGLE_TLV("Headphone Mixer Beep Playback Volume", AC97_AUX, 12, 7, 1, |
169 | SOC_SINGLE("Beep Playback Speaker Volume", AC97_AUX, 8, 7, 1), | 180 | misc_tlv), |
170 | SOC_SINGLE("Beep Playback Mono Volume", AC97_AUX, 4, 7, 1), | 181 | SOC_SINGLE_TLV("Speaker Mixer Beep Playback Volume", AC97_AUX, 8, 7, 1, |
182 | misc_tlv), | ||
183 | SOC_SINGLE_TLV("Mono Mixer Beep Playback Volume", AC97_AUX, 4, 7, 1, misc_tlv), | ||
171 | 184 | ||
172 | SOC_SINGLE("Voice Playback Headphone Volume", AC97_PCM, 12, 7, 1), | 185 | SOC_SINGLE_TLV("Voice Playback Headphone Volume", AC97_PCM, 12, 7, 1, |
186 | misc_tlv), | ||
173 | SOC_SINGLE("Voice Playback Master Volume", AC97_PCM, 8, 7, 1), | 187 | SOC_SINGLE("Voice Playback Master Volume", AC97_PCM, 8, 7, 1), |
174 | SOC_SINGLE("Voice Playback Mono Volume", AC97_PCM, 4, 7, 1), | 188 | SOC_SINGLE("Voice Playback Mono Volume", AC97_PCM, 4, 7, 1), |
175 | 189 | ||
190 | SOC_SINGLE_TLV("Headphone Mixer Aux Playback Volume", AC97_REC_SEL, 12, 7, 1, | ||
191 | misc_tlv), | ||
192 | |||
193 | SOC_SINGLE_TLV("Speaker Mixer Voice Playback Volume", AC97_PCM, 8, 7, 1, | ||
194 | misc_tlv), | ||
195 | SOC_SINGLE_TLV("Speaker Mixer Aux Playback Volume", AC97_REC_SEL, 8, 7, 1, | ||
196 | misc_tlv), | ||
197 | |||
198 | SOC_SINGLE_TLV("Mono Mixer Voice Playback Volume", AC97_PCM, 4, 7, 1, | ||
199 | misc_tlv), | ||
200 | SOC_SINGLE_TLV("Mono Mixer Aux Playback Volume", AC97_REC_SEL, 4, 7, 1, | ||
201 | misc_tlv), | ||
202 | |||
176 | SOC_SINGLE("Aux Playback Headphone Volume", AC97_REC_SEL, 12, 7, 1), | 203 | SOC_SINGLE("Aux Playback Headphone Volume", AC97_REC_SEL, 12, 7, 1), |
177 | SOC_SINGLE("Aux Playback Master Volume", AC97_REC_SEL, 8, 7, 1), | 204 | SOC_SINGLE("Aux Playback Master Volume", AC97_REC_SEL, 8, 7, 1), |
178 | SOC_SINGLE("Aux Playback Mono Volume", AC97_REC_SEL, 4, 7, 1), | ||
179 | 205 | ||
180 | SOC_ENUM("Bass Control", wm9713_enum[16]), | 206 | SOC_ENUM("Bass Control", wm9713_enum[16]), |
181 | SOC_SINGLE("Bass Cut-off Switch", AC97_GENERAL_PURPOSE, 12, 1, 1), | 207 | SOC_SINGLE("Bass Cut-off Switch", AC97_GENERAL_PURPOSE, 12, 1, 1), |
@@ -1186,8 +1212,6 @@ static int wm9713_soc_probe(struct platform_device *pdev) | |||
1186 | struct snd_soc_codec *codec; | 1212 | struct snd_soc_codec *codec; |
1187 | int ret = 0, reg; | 1213 | int ret = 0, reg; |
1188 | 1214 | ||
1189 | printk(KERN_INFO "WM9713/WM9714 SoC Audio Codec %s\n", WM9713_VERSION); | ||
1190 | |||
1191 | socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), | 1215 | socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), |
1192 | GFP_KERNEL); | 1216 | GFP_KERNEL); |
1193 | if (socdev->card->codec == NULL) | 1217 | if (socdev->card->codec == NULL) |
diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c index d73c30536a2c..0ad9f5d536c6 100644 --- a/sound/soc/codecs/wm_hubs.c +++ b/sound/soc/codecs/wm_hubs.c | |||
@@ -68,24 +68,77 @@ static void wait_for_dc_servo(struct snd_soc_codec *codec) | |||
68 | int count = 0; | 68 | int count = 0; |
69 | 69 | ||
70 | dev_dbg(codec->dev, "Waiting for DC servo...\n"); | 70 | dev_dbg(codec->dev, "Waiting for DC servo...\n"); |
71 | |||
71 | do { | 72 | do { |
72 | count++; | 73 | count++; |
73 | msleep(1); | 74 | msleep(1); |
74 | reg = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_0); | 75 | reg = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_0); |
75 | dev_dbg(codec->dev, "DC servo status: %x\n", reg); | 76 | dev_dbg(codec->dev, "DC servo: %x\n", reg); |
76 | } while ((reg & WM8993_DCS_CAL_COMPLETE_MASK) | 77 | } while (reg & WM8993_DCS_DATAPATH_BUSY); |
77 | != WM8993_DCS_CAL_COMPLETE_MASK && count < 1000); | ||
78 | 78 | ||
79 | if ((reg & WM8993_DCS_CAL_COMPLETE_MASK) | 79 | if (reg & WM8993_DCS_DATAPATH_BUSY) |
80 | != WM8993_DCS_CAL_COMPLETE_MASK) | ||
81 | dev_err(codec->dev, "Timed out waiting for DC Servo\n"); | 80 | dev_err(codec->dev, "Timed out waiting for DC Servo\n"); |
82 | } | 81 | } |
83 | 82 | ||
84 | /* | 83 | /* |
84 | * Startup calibration of the DC servo | ||
85 | */ | ||
86 | static void calibrate_dc_servo(struct snd_soc_codec *codec) | ||
87 | { | ||
88 | struct wm_hubs_data *hubs = codec->private_data; | ||
89 | u16 reg, dcs_cfg; | ||
90 | |||
91 | /* Set for 32 series updates */ | ||
92 | snd_soc_update_bits(codec, WM8993_DC_SERVO_1, | ||
93 | WM8993_DCS_SERIES_NO_01_MASK, | ||
94 | 32 << WM8993_DCS_SERIES_NO_01_SHIFT); | ||
95 | |||
96 | /* Enable the DC servo. Write all bits to avoid triggering startup | ||
97 | * or write calibration. | ||
98 | */ | ||
99 | snd_soc_update_bits(codec, WM8993_DC_SERVO_0, | ||
100 | 0xFFFF, | ||
101 | WM8993_DCS_ENA_CHAN_0 | | ||
102 | WM8993_DCS_ENA_CHAN_1 | | ||
103 | WM8993_DCS_TRIG_SERIES_1 | | ||
104 | WM8993_DCS_TRIG_SERIES_0); | ||
105 | |||
106 | wait_for_dc_servo(codec); | ||
107 | |||
108 | /* Apply correction to DC servo result */ | ||
109 | if (hubs->dcs_codes) { | ||
110 | dev_dbg(codec->dev, "Applying %d code DC servo correction\n", | ||
111 | hubs->dcs_codes); | ||
112 | |||
113 | /* HPOUT1L */ | ||
114 | reg = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_1) & | ||
115 | WM8993_DCS_INTEG_CHAN_0_MASK;; | ||
116 | reg += hubs->dcs_codes; | ||
117 | dcs_cfg = reg << WM8993_DCS_DAC_WR_VAL_1_SHIFT; | ||
118 | |||
119 | /* HPOUT1R */ | ||
120 | reg = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_2) & | ||
121 | WM8993_DCS_INTEG_CHAN_1_MASK; | ||
122 | reg += hubs->dcs_codes; | ||
123 | dcs_cfg |= reg; | ||
124 | |||
125 | /* Do it */ | ||
126 | snd_soc_write(codec, WM8993_DC_SERVO_3, dcs_cfg); | ||
127 | snd_soc_update_bits(codec, WM8993_DC_SERVO_0, | ||
128 | WM8993_DCS_TRIG_DAC_WR_0 | | ||
129 | WM8993_DCS_TRIG_DAC_WR_1, | ||
130 | WM8993_DCS_TRIG_DAC_WR_0 | | ||
131 | WM8993_DCS_TRIG_DAC_WR_1); | ||
132 | |||
133 | wait_for_dc_servo(codec); | ||
134 | } | ||
135 | } | ||
136 | |||
137 | /* | ||
85 | * Update the DC servo calibration on gain changes | 138 | * Update the DC servo calibration on gain changes |
86 | */ | 139 | */ |
87 | static int wm8993_put_dc_servo(struct snd_kcontrol *kcontrol, | 140 | static int wm8993_put_dc_servo(struct snd_kcontrol *kcontrol, |
88 | struct snd_ctl_elem_value *ucontrol) | 141 | struct snd_ctl_elem_value *ucontrol) |
89 | { | 142 | { |
90 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 143 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
91 | int ret; | 144 | int ret; |
@@ -251,6 +304,47 @@ SOC_SINGLE_TLV("LINEOUT2 Volume", WM8993_LINE_OUTPUTS_VOLUME, 0, 1, 1, | |||
251 | line_tlv), | 304 | line_tlv), |
252 | }; | 305 | }; |
253 | 306 | ||
307 | static int hp_supply_event(struct snd_soc_dapm_widget *w, | ||
308 | struct snd_kcontrol *kcontrol, int event) | ||
309 | { | ||
310 | struct snd_soc_codec *codec = w->codec; | ||
311 | struct wm_hubs_data *hubs = codec->private_data; | ||
312 | |||
313 | switch (event) { | ||
314 | case SND_SOC_DAPM_PRE_PMU: | ||
315 | switch (hubs->hp_startup_mode) { | ||
316 | case 0: | ||
317 | break; | ||
318 | case 1: | ||
319 | /* Enable the headphone amp */ | ||
320 | snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1, | ||
321 | WM8993_HPOUT1L_ENA | | ||
322 | WM8993_HPOUT1R_ENA, | ||
323 | WM8993_HPOUT1L_ENA | | ||
324 | WM8993_HPOUT1R_ENA); | ||
325 | |||
326 | /* Enable the second stage */ | ||
327 | snd_soc_update_bits(codec, WM8993_ANALOGUE_HP_0, | ||
328 | WM8993_HPOUT1L_DLY | | ||
329 | WM8993_HPOUT1R_DLY, | ||
330 | WM8993_HPOUT1L_DLY | | ||
331 | WM8993_HPOUT1R_DLY); | ||
332 | break; | ||
333 | default: | ||
334 | dev_err(codec->dev, "Unknown HP startup mode %d\n", | ||
335 | hubs->hp_startup_mode); | ||
336 | break; | ||
337 | } | ||
338 | |||
339 | case SND_SOC_DAPM_PRE_PMD: | ||
340 | snd_soc_update_bits(codec, WM8993_CHARGE_PUMP_1, | ||
341 | WM8993_CP_ENA, 0); | ||
342 | break; | ||
343 | } | ||
344 | |||
345 | return 0; | ||
346 | } | ||
347 | |||
254 | static int hp_event(struct snd_soc_dapm_widget *w, | 348 | static int hp_event(struct snd_soc_dapm_widget *w, |
255 | struct snd_kcontrol *kcontrol, int event) | 349 | struct snd_kcontrol *kcontrol, int event) |
256 | { | 350 | { |
@@ -271,14 +365,11 @@ static int hp_event(struct snd_soc_dapm_widget *w, | |||
271 | reg |= WM8993_HPOUT1L_DLY | WM8993_HPOUT1R_DLY; | 365 | reg |= WM8993_HPOUT1L_DLY | WM8993_HPOUT1R_DLY; |
272 | snd_soc_write(codec, WM8993_ANALOGUE_HP_0, reg); | 366 | snd_soc_write(codec, WM8993_ANALOGUE_HP_0, reg); |
273 | 367 | ||
274 | /* Start the DC servo */ | 368 | /* Smallest supported update interval */ |
275 | snd_soc_update_bits(codec, WM8993_DC_SERVO_0, | 369 | snd_soc_update_bits(codec, WM8993_DC_SERVO_1, |
276 | 0xFFFF, | 370 | WM8993_DCS_TIMER_PERIOD_01_MASK, 1); |
277 | WM8993_DCS_ENA_CHAN_0 | | 371 | |
278 | WM8993_DCS_ENA_CHAN_1 | | 372 | calibrate_dc_servo(codec); |
279 | WM8993_DCS_TRIG_STARTUP_1 | | ||
280 | WM8993_DCS_TRIG_STARTUP_0); | ||
281 | wait_for_dc_servo(codec); | ||
282 | 373 | ||
283 | reg |= WM8993_HPOUT1R_OUTP | WM8993_HPOUT1R_RMV_SHORT | | 374 | reg |= WM8993_HPOUT1R_OUTP | WM8993_HPOUT1R_RMV_SHORT | |
284 | WM8993_HPOUT1L_OUTP | WM8993_HPOUT1L_RMV_SHORT; | 375 | WM8993_HPOUT1L_OUTP | WM8993_HPOUT1L_RMV_SHORT; |
@@ -286,23 +377,19 @@ static int hp_event(struct snd_soc_dapm_widget *w, | |||
286 | break; | 377 | break; |
287 | 378 | ||
288 | case SND_SOC_DAPM_PRE_PMD: | 379 | case SND_SOC_DAPM_PRE_PMD: |
289 | reg &= ~(WM8993_HPOUT1L_RMV_SHORT | | 380 | snd_soc_update_bits(codec, WM8993_ANALOGUE_HP_0, |
290 | WM8993_HPOUT1L_DLY | | 381 | WM8993_HPOUT1L_DLY | |
291 | WM8993_HPOUT1L_OUTP | | 382 | WM8993_HPOUT1R_DLY | |
292 | WM8993_HPOUT1R_RMV_SHORT | | 383 | WM8993_HPOUT1L_RMV_SHORT | |
293 | WM8993_HPOUT1R_DLY | | 384 | WM8993_HPOUT1R_RMV_SHORT, 0); |
294 | WM8993_HPOUT1R_OUTP); | ||
295 | 385 | ||
296 | snd_soc_update_bits(codec, WM8993_DC_SERVO_0, | 386 | snd_soc_update_bits(codec, WM8993_ANALOGUE_HP_0, |
297 | 0xffff, 0); | 387 | WM8993_HPOUT1L_OUTP | |
388 | WM8993_HPOUT1R_OUTP, 0); | ||
298 | 389 | ||
299 | snd_soc_write(codec, WM8993_ANALOGUE_HP_0, reg); | ||
300 | snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1, | 390 | snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1, |
301 | WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA, | 391 | WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA, |
302 | 0); | 392 | 0); |
303 | |||
304 | snd_soc_update_bits(codec, WM8993_CHARGE_PUMP_1, | ||
305 | WM8993_CP_ENA, 0); | ||
306 | break; | 393 | break; |
307 | } | 394 | } |
308 | 395 | ||
@@ -473,6 +560,8 @@ SND_SOC_DAPM_MIXER("Right Output Mixer", WM8993_POWER_MANAGEMENT_3, 4, 0, | |||
473 | SND_SOC_DAPM_PGA("Left Output PGA", WM8993_POWER_MANAGEMENT_3, 7, 0, NULL, 0), | 560 | SND_SOC_DAPM_PGA("Left Output PGA", WM8993_POWER_MANAGEMENT_3, 7, 0, NULL, 0), |
474 | SND_SOC_DAPM_PGA("Right Output PGA", WM8993_POWER_MANAGEMENT_3, 6, 0, NULL, 0), | 561 | SND_SOC_DAPM_PGA("Right Output PGA", WM8993_POWER_MANAGEMENT_3, 6, 0, NULL, 0), |
475 | 562 | ||
563 | SND_SOC_DAPM_SUPPLY("Headphone Supply", SND_SOC_NOPM, 0, 0, hp_supply_event, | ||
564 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), | ||
476 | SND_SOC_DAPM_PGA_E("Headphone PGA", SND_SOC_NOPM, 0, 0, | 565 | SND_SOC_DAPM_PGA_E("Headphone PGA", SND_SOC_NOPM, 0, 0, |
477 | NULL, 0, | 566 | NULL, 0, |
478 | hp_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), | 567 | hp_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), |
@@ -626,6 +715,7 @@ static const struct snd_soc_dapm_route analogue_routes[] = { | |||
626 | { "Headphone PGA", NULL, "Left Headphone Mux" }, | 715 | { "Headphone PGA", NULL, "Left Headphone Mux" }, |
627 | { "Headphone PGA", NULL, "Right Headphone Mux" }, | 716 | { "Headphone PGA", NULL, "Right Headphone Mux" }, |
628 | { "Headphone PGA", NULL, "CLK_SYS" }, | 717 | { "Headphone PGA", NULL, "CLK_SYS" }, |
718 | { "Headphone PGA", NULL, "Headphone Supply" }, | ||
629 | 719 | ||
630 | { "HPOUT1L", NULL, "Headphone PGA" }, | 720 | { "HPOUT1L", NULL, "Headphone PGA" }, |
631 | { "HPOUT1R", NULL, "Headphone PGA" }, | 721 | { "HPOUT1R", NULL, "Headphone PGA" }, |
@@ -753,6 +843,12 @@ int wm_hubs_handle_analogue_pdata(struct snd_soc_codec *codec, | |||
753 | WM8993_LINEOUT2_MODE, | 843 | WM8993_LINEOUT2_MODE, |
754 | WM8993_LINEOUT2_MODE); | 844 | WM8993_LINEOUT2_MODE); |
755 | 845 | ||
846 | /* If the line outputs are differential then we aren't presenting | ||
847 | * VMID as an output and can disable it. | ||
848 | */ | ||
849 | if (lineout1_diff && lineout2_diff) | ||
850 | codec->idle_bias_off = 1; | ||
851 | |||
756 | if (lineout1fb) | 852 | if (lineout1fb) |
757 | snd_soc_update_bits(codec, WM8993_ADDITIONAL_CONTROL, | 853 | snd_soc_update_bits(codec, WM8993_ADDITIONAL_CONTROL, |
758 | WM8993_LINEOUT1_FB, WM8993_LINEOUT1_FB); | 854 | WM8993_LINEOUT1_FB, WM8993_LINEOUT1_FB); |
diff --git a/sound/soc/codecs/wm_hubs.h b/sound/soc/codecs/wm_hubs.h index 36d3fba1de8b..420104fe9c90 100644 --- a/sound/soc/codecs/wm_hubs.h +++ b/sound/soc/codecs/wm_hubs.h | |||
@@ -18,6 +18,12 @@ struct snd_soc_codec; | |||
18 | 18 | ||
19 | extern const unsigned int wm_hubs_spkmix_tlv[]; | 19 | extern const unsigned int wm_hubs_spkmix_tlv[]; |
20 | 20 | ||
21 | /* This *must* be the first element of the codec->private_data struct */ | ||
22 | struct wm_hubs_data { | ||
23 | int dcs_codes; | ||
24 | int hp_startup_mode; | ||
25 | }; | ||
26 | |||
21 | extern int wm_hubs_add_analogue_controls(struct snd_soc_codec *); | 27 | extern int wm_hubs_add_analogue_controls(struct snd_soc_codec *); |
22 | extern int wm_hubs_add_analogue_routes(struct snd_soc_codec *, int, int); | 28 | extern int wm_hubs_add_analogue_routes(struct snd_soc_codec *, int, int); |
23 | extern int wm_hubs_handle_analogue_pdata(struct snd_soc_codec *, | 29 | extern int wm_hubs_handle_analogue_pdata(struct snd_soc_codec *, |
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index 0a302e1080d9..ab6518d86f18 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c | |||
@@ -767,14 +767,26 @@ static int davinci_mcasp_trigger(struct snd_pcm_substream *substream, | |||
767 | int ret = 0; | 767 | int ret = 0; |
768 | 768 | ||
769 | switch (cmd) { | 769 | switch (cmd) { |
770 | case SNDRV_PCM_TRIGGER_START: | ||
771 | case SNDRV_PCM_TRIGGER_RESUME: | 770 | case SNDRV_PCM_TRIGGER_RESUME: |
771 | case SNDRV_PCM_TRIGGER_START: | ||
772 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 772 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
773 | if (!dev->clk_active) { | ||
774 | clk_enable(dev->clk); | ||
775 | dev->clk_active = 1; | ||
776 | } | ||
773 | davinci_mcasp_start(dev, substream->stream); | 777 | davinci_mcasp_start(dev, substream->stream); |
774 | break; | 778 | break; |
775 | 779 | ||
776 | case SNDRV_PCM_TRIGGER_STOP: | ||
777 | case SNDRV_PCM_TRIGGER_SUSPEND: | 780 | case SNDRV_PCM_TRIGGER_SUSPEND: |
781 | davinci_mcasp_stop(dev, substream->stream); | ||
782 | if (dev->clk_active) { | ||
783 | clk_disable(dev->clk); | ||
784 | dev->clk_active = 0; | ||
785 | } | ||
786 | |||
787 | break; | ||
788 | |||
789 | case SNDRV_PCM_TRIGGER_STOP: | ||
778 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 790 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
779 | davinci_mcasp_stop(dev, substream->stream); | 791 | davinci_mcasp_stop(dev, substream->stream); |
780 | break; | 792 | break; |
@@ -866,6 +878,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev) | |||
866 | } | 878 | } |
867 | 879 | ||
868 | clk_enable(dev->clk); | 880 | clk_enable(dev->clk); |
881 | dev->clk_active = 1; | ||
869 | 882 | ||
870 | dev->base = (void __iomem *)IO_ADDRESS(mem->start); | 883 | dev->base = (void __iomem *)IO_ADDRESS(mem->start); |
871 | dev->op_mode = pdata->op_mode; | 884 | dev->op_mode = pdata->op_mode; |
diff --git a/sound/soc/davinci/davinci-mcasp.h b/sound/soc/davinci/davinci-mcasp.h index 582c9249ef09..e755b5121ec7 100644 --- a/sound/soc/davinci/davinci-mcasp.h +++ b/sound/soc/davinci/davinci-mcasp.h | |||
@@ -44,6 +44,7 @@ struct davinci_audio_dev { | |||
44 | int sample_rate; | 44 | int sample_rate; |
45 | struct clk *clk; | 45 | struct clk *clk; |
46 | unsigned int codec_fmt; | 46 | unsigned int codec_fmt; |
47 | u8 clk_active; | ||
47 | 48 | ||
48 | /* McASP specific data */ | 49 | /* McASP specific data */ |
49 | int tdm_slots; | 50 | int tdm_slots; |
diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c index ad4d7f47a86b..80c7fdf2f521 100644 --- a/sound/soc/davinci/davinci-pcm.c +++ b/sound/soc/davinci/davinci-pcm.c | |||
@@ -49,7 +49,7 @@ static void print_buf_info(int slot, char *name) | |||
49 | static struct snd_pcm_hardware pcm_hardware_playback = { | 49 | static struct snd_pcm_hardware pcm_hardware_playback = { |
50 | .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | | 50 | .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | |
51 | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | | 51 | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | |
52 | SNDRV_PCM_INFO_PAUSE), | 52 | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME), |
53 | .formats = (SNDRV_PCM_FMTBIT_S16_LE), | 53 | .formats = (SNDRV_PCM_FMTBIT_S16_LE), |
54 | .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | | 54 | .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | |
55 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | | 55 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | |
diff --git a/sound/soc/fsl/efika-audio-fabric.c b/sound/soc/fsl/efika-audio-fabric.c index 3326e2a1e863..1a5b8e0d6a34 100644 --- a/sound/soc/fsl/efika-audio-fabric.c +++ b/sound/soc/fsl/efika-audio-fabric.c | |||
@@ -55,7 +55,7 @@ static __init int efika_fabric_init(void) | |||
55 | struct platform_device *pdev; | 55 | struct platform_device *pdev; |
56 | int rc; | 56 | int rc; |
57 | 57 | ||
58 | if (!machine_is_compatible("bplan,efika")) | 58 | if (!of_machine_is_compatible("bplan,efika")) |
59 | return -ENODEV; | 59 | return -ENODEV; |
60 | 60 | ||
61 | card.platform = &mpc5200_audio_dma_platform; | 61 | card.platform = &mpc5200_audio_dma_platform; |
diff --git a/sound/soc/fsl/pcm030-audio-fabric.c b/sound/soc/fsl/pcm030-audio-fabric.c index b928ef7d28eb..6644cba7cbf2 100644 --- a/sound/soc/fsl/pcm030-audio-fabric.c +++ b/sound/soc/fsl/pcm030-audio-fabric.c | |||
@@ -55,7 +55,7 @@ static __init int pcm030_fabric_init(void) | |||
55 | struct platform_device *pdev; | 55 | struct platform_device *pdev; |
56 | int rc; | 56 | int rc; |
57 | 57 | ||
58 | if (!machine_is_compatible("phytec,pcm030")) | 58 | if (!of_machine_is_compatible("phytec,pcm030")) |
59 | return -ENODEV; | 59 | return -ENODEV; |
60 | 60 | ||
61 | card.platform = &mpc5200_audio_dma_platform; | 61 | card.platform = &mpc5200_audio_dma_platform; |
diff --git a/sound/soc/imx/Kconfig b/sound/soc/imx/Kconfig index a700562e8692..c7d0fd9b7de8 100644 --- a/sound/soc/imx/Kconfig +++ b/sound/soc/imx/Kconfig | |||
@@ -1,21 +1,13 @@ | |||
1 | config SND_MX1_MX2_SOC | 1 | config SND_IMX_SOC |
2 | tristate "SoC Audio for Freecale i.MX1x i.MX2x CPUs" | 2 | tristate "SoC Audio for Freescale i.MX CPUs" |
3 | depends on ARCH_MX2 || ARCH_MX1 | 3 | depends on ARCH_MXC && BROKEN |
4 | select SND_PCM | 4 | select SND_PCM |
5 | select FIQ | ||
6 | select SND_SOC_AC97_BUS | ||
5 | help | 7 | help |
6 | Say Y or M if you want to add support for codecs attached to | 8 | Say Y or M if you want to add support for codecs attached to |
7 | the MX1 or MX2 SSI interface. | 9 | the i.MX SSI interface. |
8 | 10 | ||
9 | config SND_MXC_SOC_SSI | 11 | config SND_MXC_SOC_SSI |
10 | tristate | 12 | tristate |
11 | 13 | ||
12 | config SND_SOC_MX27VIS_WM8974 | ||
13 | tristate "SoC Audio support for MX27 - WM8974 Visstrim_sm10 board" | ||
14 | depends on SND_MX1_MX2_SOC && MACH_MX27 && MACH_IMX27_VISSTRIM_M10 | ||
15 | select SND_MXC_SOC_SSI | ||
16 | select SND_SOC_WM8974 | ||
17 | help | ||
18 | Say Y if you want to add support for SoC audio on Visstrim SM10 | ||
19 | board with WM8974. | ||
20 | |||
21 | |||
diff --git a/sound/soc/imx/Makefile b/sound/soc/imx/Makefile index c2ffd2c8df5a..9f8bb92ddfcc 100644 --- a/sound/soc/imx/Makefile +++ b/sound/soc/imx/Makefile | |||
@@ -1,10 +1,12 @@ | |||
1 | # i.MX Platform Support | 1 | # i.MX Platform Support |
2 | snd-soc-mx1_mx2-objs := mx1_mx2-pcm.o | 2 | snd-soc-imx-objs := imx-ssi.o imx-pcm-fiq.o |
3 | snd-soc-mxc-ssi-objs := mxc-ssi.o | ||
4 | 3 | ||
5 | obj-$(CONFIG_SND_MX1_MX2_SOC) += snd-soc-mx1_mx2.o | 4 | ifdef CONFIG_MACH_MX27 |
6 | obj-$(CONFIG_SND_MXC_SOC_SSI) += snd-soc-mxc-ssi.o | 5 | snd-soc-imx-objs += imx-pcm-dma-mx2.o |
6 | endif | ||
7 | |||
8 | obj-$(CONFIG_SND_IMX_SOC) += snd-soc-imx.o | ||
7 | 9 | ||
8 | # i.MX Machine Support | 10 | # i.MX Machine Support |
9 | snd-soc-mx27vis-wm8974-objs := mx27vis_wm8974.o | 11 | snd-soc-phycore-ac97-objs := phycore-ac97.o |
10 | obj-$(CONFIG_SND_SOC_MX27VIS_WM8974) += snd-soc-mx27vis-wm8974.o | 12 | obj-$(CONFIG_SND_SOC_PHYCORE_AC97) += snd-soc-phycore-ac97.o |
diff --git a/sound/soc/imx/imx-pcm-dma-mx2.c b/sound/soc/imx/imx-pcm-dma-mx2.c new file mode 100644 index 000000000000..19452e44afdc --- /dev/null +++ b/sound/soc/imx/imx-pcm-dma-mx2.c | |||
@@ -0,0 +1,313 @@ | |||
1 | /* | ||
2 | * imx-pcm-dma-mx2.c -- ALSA Soc Audio Layer | ||
3 | * | ||
4 | * Copyright 2009 Sascha Hauer <s.hauer@pengutronix.de> | ||
5 | * | ||
6 | * This code is based on code copyrighted by Freescale, | ||
7 | * Liam Girdwood, Javier Martin and probably others. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License as published by the | ||
11 | * Free Software Foundation; either version 2 of the License, or (at your | ||
12 | * option) any later version. | ||
13 | */ | ||
14 | #include <linux/clk.h> | ||
15 | #include <linux/delay.h> | ||
16 | #include <linux/device.h> | ||
17 | #include <linux/dma-mapping.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/interrupt.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | |||
23 | #include <sound/core.h> | ||
24 | #include <sound/initval.h> | ||
25 | #include <sound/pcm.h> | ||
26 | #include <sound/pcm_params.h> | ||
27 | #include <sound/soc.h> | ||
28 | |||
29 | #include <mach/dma-mx1-mx2.h> | ||
30 | |||
31 | #include "imx-ssi.h" | ||
32 | |||
33 | struct imx_pcm_runtime_data { | ||
34 | int sg_count; | ||
35 | struct scatterlist *sg_list; | ||
36 | int period; | ||
37 | int periods; | ||
38 | unsigned long dma_addr; | ||
39 | int dma; | ||
40 | struct snd_pcm_substream *substream; | ||
41 | unsigned long offset; | ||
42 | unsigned long size; | ||
43 | unsigned long period_cnt; | ||
44 | void *buf; | ||
45 | int period_time; | ||
46 | }; | ||
47 | |||
48 | /* Called by the DMA framework when a period has elapsed */ | ||
49 | static void imx_ssi_dma_progression(int channel, void *data, | ||
50 | struct scatterlist *sg) | ||
51 | { | ||
52 | struct snd_pcm_substream *substream = data; | ||
53 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
54 | struct imx_pcm_runtime_data *iprtd = runtime->private_data; | ||
55 | |||
56 | if (!sg) | ||
57 | return; | ||
58 | |||
59 | runtime = iprtd->substream->runtime; | ||
60 | |||
61 | iprtd->offset = sg->dma_address - runtime->dma_addr; | ||
62 | |||
63 | snd_pcm_period_elapsed(iprtd->substream); | ||
64 | } | ||
65 | |||
66 | static void imx_ssi_dma_callback(int channel, void *data) | ||
67 | { | ||
68 | pr_err("%s shouldn't be called\n", __func__); | ||
69 | } | ||
70 | |||
71 | static void snd_imx_dma_err_callback(int channel, void *data, int err) | ||
72 | { | ||
73 | pr_err("DMA error callback called\n"); | ||
74 | |||
75 | pr_err("DMA timeout on channel %d -%s%s%s%s\n", | ||
76 | channel, | ||
77 | err & IMX_DMA_ERR_BURST ? " burst" : "", | ||
78 | err & IMX_DMA_ERR_REQUEST ? " request" : "", | ||
79 | err & IMX_DMA_ERR_TRANSFER ? " transfer" : "", | ||
80 | err & IMX_DMA_ERR_BUFFER ? " buffer" : ""); | ||
81 | } | ||
82 | |||
83 | static int imx_ssi_dma_alloc(struct snd_pcm_substream *substream) | ||
84 | { | ||
85 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
86 | struct imx_pcm_dma_params *dma_params = rtd->dai->cpu_dai->dma_data; | ||
87 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
88 | struct imx_pcm_runtime_data *iprtd = runtime->private_data; | ||
89 | int ret; | ||
90 | |||
91 | iprtd->dma = imx_dma_request_by_prio(DRV_NAME, DMA_PRIO_HIGH); | ||
92 | if (iprtd->dma < 0) { | ||
93 | pr_err("Failed to claim the audio DMA\n"); | ||
94 | return -ENODEV; | ||
95 | } | ||
96 | |||
97 | ret = imx_dma_setup_handlers(iprtd->dma, | ||
98 | imx_ssi_dma_callback, | ||
99 | snd_imx_dma_err_callback, substream); | ||
100 | if (ret) | ||
101 | goto out; | ||
102 | |||
103 | ret = imx_dma_setup_progression_handler(iprtd->dma, | ||
104 | imx_ssi_dma_progression); | ||
105 | if (ret) { | ||
106 | pr_err("Failed to setup the DMA handler\n"); | ||
107 | goto out; | ||
108 | } | ||
109 | |||
110 | ret = imx_dma_config_channel(iprtd->dma, | ||
111 | IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO, | ||
112 | IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR, | ||
113 | dma_params->dma, 1); | ||
114 | if (ret < 0) { | ||
115 | pr_err("Cannot configure DMA channel: %d\n", ret); | ||
116 | goto out; | ||
117 | } | ||
118 | |||
119 | imx_dma_config_burstlen(iprtd->dma, dma_params->burstsize * 2); | ||
120 | |||
121 | return 0; | ||
122 | out: | ||
123 | imx_dma_free(iprtd->dma); | ||
124 | return ret; | ||
125 | } | ||
126 | |||
127 | static int snd_imx_pcm_hw_params(struct snd_pcm_substream *substream, | ||
128 | struct snd_pcm_hw_params *params) | ||
129 | { | ||
130 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
131 | struct imx_pcm_runtime_data *iprtd = runtime->private_data; | ||
132 | int i; | ||
133 | unsigned long dma_addr; | ||
134 | |||
135 | imx_ssi_dma_alloc(substream); | ||
136 | |||
137 | iprtd->size = params_buffer_bytes(params); | ||
138 | iprtd->periods = params_periods(params); | ||
139 | iprtd->period = params_period_bytes(params); | ||
140 | iprtd->offset = 0; | ||
141 | iprtd->period_time = HZ / (params_rate(params) / | ||
142 | params_period_size(params)); | ||
143 | |||
144 | snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); | ||
145 | |||
146 | if (iprtd->sg_count != iprtd->periods) { | ||
147 | kfree(iprtd->sg_list); | ||
148 | |||
149 | iprtd->sg_list = kcalloc(iprtd->periods + 1, | ||
150 | sizeof(struct scatterlist), GFP_KERNEL); | ||
151 | if (!iprtd->sg_list) | ||
152 | return -ENOMEM; | ||
153 | iprtd->sg_count = iprtd->periods + 1; | ||
154 | } | ||
155 | |||
156 | sg_init_table(iprtd->sg_list, iprtd->sg_count); | ||
157 | dma_addr = runtime->dma_addr; | ||
158 | |||
159 | for (i = 0; i < iprtd->periods; i++) { | ||
160 | iprtd->sg_list[i].page_link = 0; | ||
161 | iprtd->sg_list[i].offset = 0; | ||
162 | iprtd->sg_list[i].dma_address = dma_addr; | ||
163 | iprtd->sg_list[i].length = iprtd->period; | ||
164 | dma_addr += iprtd->period; | ||
165 | } | ||
166 | |||
167 | /* close the loop */ | ||
168 | iprtd->sg_list[iprtd->sg_count - 1].offset = 0; | ||
169 | iprtd->sg_list[iprtd->sg_count - 1].length = 0; | ||
170 | iprtd->sg_list[iprtd->sg_count - 1].page_link = | ||
171 | ((unsigned long) iprtd->sg_list | 0x01) & ~0x02; | ||
172 | return 0; | ||
173 | } | ||
174 | |||
175 | static int snd_imx_pcm_hw_free(struct snd_pcm_substream *substream) | ||
176 | { | ||
177 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
178 | struct imx_pcm_runtime_data *iprtd = runtime->private_data; | ||
179 | |||
180 | if (iprtd->dma >= 0) { | ||
181 | imx_dma_free(iprtd->dma); | ||
182 | iprtd->dma = -EINVAL; | ||
183 | } | ||
184 | |||
185 | kfree(iprtd->sg_list); | ||
186 | iprtd->sg_list = NULL; | ||
187 | |||
188 | return 0; | ||
189 | } | ||
190 | |||
191 | static int snd_imx_pcm_prepare(struct snd_pcm_substream *substream) | ||
192 | { | ||
193 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
194 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
195 | struct imx_pcm_dma_params *dma_params = rtd->dai->cpu_dai->dma_data; | ||
196 | struct imx_pcm_runtime_data *iprtd = runtime->private_data; | ||
197 | int err; | ||
198 | |||
199 | iprtd->substream = substream; | ||
200 | iprtd->buf = (unsigned int *)substream->dma_buffer.area; | ||
201 | iprtd->period_cnt = 0; | ||
202 | |||
203 | pr_debug("%s: buf: %p period: %d periods: %d\n", | ||
204 | __func__, iprtd->buf, iprtd->period, iprtd->periods); | ||
205 | |||
206 | err = imx_dma_setup_sg(iprtd->dma, iprtd->sg_list, iprtd->sg_count, | ||
207 | IMX_DMA_LENGTH_LOOP, dma_params->dma_addr, | ||
208 | substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? | ||
209 | DMA_MODE_WRITE : DMA_MODE_READ); | ||
210 | if (err) | ||
211 | return err; | ||
212 | |||
213 | return 0; | ||
214 | } | ||
215 | |||
216 | static int snd_imx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | ||
217 | { | ||
218 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
219 | struct imx_pcm_runtime_data *iprtd = runtime->private_data; | ||
220 | |||
221 | switch (cmd) { | ||
222 | case SNDRV_PCM_TRIGGER_START: | ||
223 | case SNDRV_PCM_TRIGGER_RESUME: | ||
224 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
225 | imx_dma_enable(iprtd->dma); | ||
226 | |||
227 | break; | ||
228 | |||
229 | case SNDRV_PCM_TRIGGER_STOP: | ||
230 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
231 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
232 | imx_dma_disable(iprtd->dma); | ||
233 | |||
234 | break; | ||
235 | default: | ||
236 | return -EINVAL; | ||
237 | } | ||
238 | |||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | static snd_pcm_uframes_t snd_imx_pcm_pointer(struct snd_pcm_substream *substream) | ||
243 | { | ||
244 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
245 | struct imx_pcm_runtime_data *iprtd = runtime->private_data; | ||
246 | |||
247 | return bytes_to_frames(substream->runtime, iprtd->offset); | ||
248 | } | ||
249 | |||
250 | static struct snd_pcm_hardware snd_imx_hardware = { | ||
251 | .info = SNDRV_PCM_INFO_INTERLEAVED | | ||
252 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | ||
253 | SNDRV_PCM_INFO_MMAP | | ||
254 | SNDRV_PCM_INFO_MMAP_VALID | | ||
255 | SNDRV_PCM_INFO_PAUSE | | ||
256 | SNDRV_PCM_INFO_RESUME, | ||
257 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
258 | .rate_min = 8000, | ||
259 | .channels_min = 2, | ||
260 | .channels_max = 2, | ||
261 | .buffer_bytes_max = IMX_SSI_DMABUF_SIZE, | ||
262 | .period_bytes_min = 128, | ||
263 | .period_bytes_max = 16 * 1024, | ||
264 | .periods_min = 2, | ||
265 | .periods_max = 255, | ||
266 | .fifo_size = 0, | ||
267 | }; | ||
268 | |||
269 | static int snd_imx_open(struct snd_pcm_substream *substream) | ||
270 | { | ||
271 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
272 | struct imx_pcm_runtime_data *iprtd; | ||
273 | int ret; | ||
274 | |||
275 | iprtd = kzalloc(sizeof(*iprtd), GFP_KERNEL); | ||
276 | runtime->private_data = iprtd; | ||
277 | |||
278 | ret = snd_pcm_hw_constraint_integer(substream->runtime, | ||
279 | SNDRV_PCM_HW_PARAM_PERIODS); | ||
280 | if (ret < 0) | ||
281 | return ret; | ||
282 | |||
283 | snd_soc_set_runtime_hwparams(substream, &snd_imx_hardware); | ||
284 | return 0; | ||
285 | } | ||
286 | |||
287 | static struct snd_pcm_ops imx_pcm_ops = { | ||
288 | .open = snd_imx_open, | ||
289 | .ioctl = snd_pcm_lib_ioctl, | ||
290 | .hw_params = snd_imx_pcm_hw_params, | ||
291 | .hw_free = snd_imx_pcm_hw_free, | ||
292 | .prepare = snd_imx_pcm_prepare, | ||
293 | .trigger = snd_imx_pcm_trigger, | ||
294 | .pointer = snd_imx_pcm_pointer, | ||
295 | .mmap = snd_imx_pcm_mmap, | ||
296 | }; | ||
297 | |||
298 | static struct snd_soc_platform imx_soc_platform_dma = { | ||
299 | .name = "imx-audio", | ||
300 | .pcm_ops = &imx_pcm_ops, | ||
301 | .pcm_new = imx_pcm_new, | ||
302 | .pcm_free = imx_pcm_free, | ||
303 | }; | ||
304 | |||
305 | struct snd_soc_platform *imx_ssi_dma_mx2_init(struct platform_device *pdev, | ||
306 | struct imx_ssi *ssi) | ||
307 | { | ||
308 | ssi->dma_params_tx.burstsize = DMA_TXFIFO_BURST; | ||
309 | ssi->dma_params_rx.burstsize = DMA_RXFIFO_BURST; | ||
310 | |||
311 | return &imx_soc_platform_dma; | ||
312 | } | ||
313 | |||
diff --git a/sound/soc/imx/imx-pcm-fiq.c b/sound/soc/imx/imx-pcm-fiq.c new file mode 100644 index 000000000000..d9cb9849b033 --- /dev/null +++ b/sound/soc/imx/imx-pcm-fiq.c | |||
@@ -0,0 +1,297 @@ | |||
1 | /* | ||
2 | * imx-pcm-fiq.c -- ALSA Soc Audio Layer | ||
3 | * | ||
4 | * Copyright 2009 Sascha Hauer <s.hauer@pengutronix.de> | ||
5 | * | ||
6 | * This code is based on code copyrighted by Freescale, | ||
7 | * Liam Girdwood, Javier Martin and probably others. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License as published by the | ||
11 | * Free Software Foundation; either version 2 of the License, or (at your | ||
12 | * option) any later version. | ||
13 | */ | ||
14 | #include <linux/clk.h> | ||
15 | #include <linux/delay.h> | ||
16 | #include <linux/device.h> | ||
17 | #include <linux/dma-mapping.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/interrupt.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | |||
23 | #include <sound/core.h> | ||
24 | #include <sound/initval.h> | ||
25 | #include <sound/pcm.h> | ||
26 | #include <sound/pcm_params.h> | ||
27 | #include <sound/soc.h> | ||
28 | |||
29 | #include <asm/fiq.h> | ||
30 | |||
31 | #include <mach/ssi.h> | ||
32 | |||
33 | #include "imx-ssi.h" | ||
34 | |||
35 | struct imx_pcm_runtime_data { | ||
36 | int period; | ||
37 | int periods; | ||
38 | unsigned long offset; | ||
39 | unsigned long last_offset; | ||
40 | unsigned long size; | ||
41 | struct timer_list timer; | ||
42 | int poll_time; | ||
43 | }; | ||
44 | |||
45 | static inline void imx_ssi_set_next_poll(struct imx_pcm_runtime_data *iprtd) | ||
46 | { | ||
47 | iprtd->timer.expires = jiffies + iprtd->poll_time; | ||
48 | } | ||
49 | |||
50 | static void imx_ssi_timer_callback(unsigned long data) | ||
51 | { | ||
52 | struct snd_pcm_substream *substream = (void *)data; | ||
53 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
54 | struct imx_pcm_runtime_data *iprtd = runtime->private_data; | ||
55 | struct pt_regs regs; | ||
56 | unsigned long delta; | ||
57 | |||
58 | get_fiq_regs(®s); | ||
59 | |||
60 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
61 | iprtd->offset = regs.ARM_r8 & 0xffff; | ||
62 | else | ||
63 | iprtd->offset = regs.ARM_r9 & 0xffff; | ||
64 | |||
65 | /* How much data have we transferred since the last period report? */ | ||
66 | if (iprtd->offset >= iprtd->last_offset) | ||
67 | delta = iprtd->offset - iprtd->last_offset; | ||
68 | else | ||
69 | delta = runtime->buffer_size + iprtd->offset | ||
70 | - iprtd->last_offset; | ||
71 | |||
72 | /* If we've transferred at least a period then report it and | ||
73 | * reset our poll time */ | ||
74 | if (delta >= runtime->period_size) { | ||
75 | snd_pcm_period_elapsed(substream); | ||
76 | iprtd->last_offset = iprtd->offset; | ||
77 | |||
78 | imx_ssi_set_next_poll(iprtd); | ||
79 | } | ||
80 | |||
81 | /* Restart the timer; if we didn't report we'll run on the next tick */ | ||
82 | add_timer(&iprtd->timer); | ||
83 | |||
84 | } | ||
85 | |||
86 | static struct fiq_handler fh = { | ||
87 | .name = DRV_NAME, | ||
88 | }; | ||
89 | |||
90 | static int snd_imx_pcm_hw_params(struct snd_pcm_substream *substream, | ||
91 | struct snd_pcm_hw_params *params) | ||
92 | { | ||
93 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
94 | struct imx_pcm_runtime_data *iprtd = runtime->private_data; | ||
95 | |||
96 | iprtd->size = params_buffer_bytes(params); | ||
97 | iprtd->periods = params_periods(params); | ||
98 | iprtd->period = params_period_bytes(params) ; | ||
99 | iprtd->offset = 0; | ||
100 | iprtd->last_offset = 0; | ||
101 | iprtd->poll_time = HZ / (params_rate(params) / params_period_size(params)); | ||
102 | |||
103 | snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); | ||
104 | |||
105 | return 0; | ||
106 | } | ||
107 | |||
108 | static int snd_imx_pcm_prepare(struct snd_pcm_substream *substream) | ||
109 | { | ||
110 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
111 | struct imx_pcm_runtime_data *iprtd = runtime->private_data; | ||
112 | struct pt_regs regs; | ||
113 | |||
114 | get_fiq_regs(®s); | ||
115 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
116 | regs.ARM_r8 = (iprtd->period * iprtd->periods - 1) << 16; | ||
117 | else | ||
118 | regs.ARM_r9 = (iprtd->period * iprtd->periods - 1) << 16; | ||
119 | |||
120 | set_fiq_regs(®s); | ||
121 | |||
122 | return 0; | ||
123 | } | ||
124 | |||
125 | static int fiq_enable; | ||
126 | static int imx_pcm_fiq; | ||
127 | |||
128 | static int snd_imx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | ||
129 | { | ||
130 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
131 | struct imx_pcm_runtime_data *iprtd = runtime->private_data; | ||
132 | |||
133 | switch (cmd) { | ||
134 | case SNDRV_PCM_TRIGGER_START: | ||
135 | case SNDRV_PCM_TRIGGER_RESUME: | ||
136 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
137 | imx_ssi_set_next_poll(iprtd); | ||
138 | add_timer(&iprtd->timer); | ||
139 | if (++fiq_enable == 1) | ||
140 | enable_fiq(imx_pcm_fiq); | ||
141 | |||
142 | break; | ||
143 | |||
144 | case SNDRV_PCM_TRIGGER_STOP: | ||
145 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
146 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
147 | del_timer(&iprtd->timer); | ||
148 | if (--fiq_enable == 0) | ||
149 | disable_fiq(imx_pcm_fiq); | ||
150 | |||
151 | |||
152 | break; | ||
153 | default: | ||
154 | return -EINVAL; | ||
155 | } | ||
156 | |||
157 | return 0; | ||
158 | } | ||
159 | |||
160 | static snd_pcm_uframes_t snd_imx_pcm_pointer(struct snd_pcm_substream *substream) | ||
161 | { | ||
162 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
163 | struct imx_pcm_runtime_data *iprtd = runtime->private_data; | ||
164 | |||
165 | return bytes_to_frames(substream->runtime, iprtd->offset); | ||
166 | } | ||
167 | |||
168 | static struct snd_pcm_hardware snd_imx_hardware = { | ||
169 | .info = SNDRV_PCM_INFO_INTERLEAVED | | ||
170 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | ||
171 | SNDRV_PCM_INFO_MMAP | | ||
172 | SNDRV_PCM_INFO_MMAP_VALID | | ||
173 | SNDRV_PCM_INFO_PAUSE | | ||
174 | SNDRV_PCM_INFO_RESUME, | ||
175 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
176 | .rate_min = 8000, | ||
177 | .channels_min = 2, | ||
178 | .channels_max = 2, | ||
179 | .buffer_bytes_max = IMX_SSI_DMABUF_SIZE, | ||
180 | .period_bytes_min = 128, | ||
181 | .period_bytes_max = 16 * 1024, | ||
182 | .periods_min = 2, | ||
183 | .periods_max = 255, | ||
184 | .fifo_size = 0, | ||
185 | }; | ||
186 | |||
187 | static int snd_imx_open(struct snd_pcm_substream *substream) | ||
188 | { | ||
189 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
190 | struct imx_pcm_runtime_data *iprtd; | ||
191 | int ret; | ||
192 | |||
193 | iprtd = kzalloc(sizeof(*iprtd), GFP_KERNEL); | ||
194 | runtime->private_data = iprtd; | ||
195 | |||
196 | init_timer(&iprtd->timer); | ||
197 | iprtd->timer.data = (unsigned long)substream; | ||
198 | iprtd->timer.function = imx_ssi_timer_callback; | ||
199 | |||
200 | ret = snd_pcm_hw_constraint_integer(substream->runtime, | ||
201 | SNDRV_PCM_HW_PARAM_PERIODS); | ||
202 | if (ret < 0) | ||
203 | return ret; | ||
204 | |||
205 | snd_soc_set_runtime_hwparams(substream, &snd_imx_hardware); | ||
206 | return 0; | ||
207 | } | ||
208 | |||
209 | static int snd_imx_close(struct snd_pcm_substream *substream) | ||
210 | { | ||
211 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
212 | struct imx_pcm_runtime_data *iprtd = runtime->private_data; | ||
213 | |||
214 | del_timer_sync(&iprtd->timer); | ||
215 | kfree(iprtd); | ||
216 | |||
217 | return 0; | ||
218 | } | ||
219 | |||
220 | static struct snd_pcm_ops imx_pcm_ops = { | ||
221 | .open = snd_imx_open, | ||
222 | .close = snd_imx_close, | ||
223 | .ioctl = snd_pcm_lib_ioctl, | ||
224 | .hw_params = snd_imx_pcm_hw_params, | ||
225 | .prepare = snd_imx_pcm_prepare, | ||
226 | .trigger = snd_imx_pcm_trigger, | ||
227 | .pointer = snd_imx_pcm_pointer, | ||
228 | .mmap = snd_imx_pcm_mmap, | ||
229 | }; | ||
230 | |||
231 | static int imx_pcm_fiq_new(struct snd_card *card, struct snd_soc_dai *dai, | ||
232 | struct snd_pcm *pcm) | ||
233 | { | ||
234 | int ret; | ||
235 | |||
236 | ret = imx_pcm_new(card, dai, pcm); | ||
237 | if (ret) | ||
238 | return ret; | ||
239 | |||
240 | if (dai->playback.channels_min) { | ||
241 | struct snd_pcm_substream *substream = | ||
242 | pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; | ||
243 | struct snd_dma_buffer *buf = &substream->dma_buffer; | ||
244 | |||
245 | imx_ssi_fiq_tx_buffer = (unsigned long)buf->area; | ||
246 | } | ||
247 | |||
248 | if (dai->capture.channels_min) { | ||
249 | struct snd_pcm_substream *substream = | ||
250 | pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; | ||
251 | struct snd_dma_buffer *buf = &substream->dma_buffer; | ||
252 | |||
253 | imx_ssi_fiq_rx_buffer = (unsigned long)buf->area; | ||
254 | } | ||
255 | |||
256 | set_fiq_handler(&imx_ssi_fiq_start, | ||
257 | &imx_ssi_fiq_end - &imx_ssi_fiq_start); | ||
258 | |||
259 | return 0; | ||
260 | } | ||
261 | |||
262 | static struct snd_soc_platform imx_soc_platform_fiq = { | ||
263 | .pcm_ops = &imx_pcm_ops, | ||
264 | .pcm_new = imx_pcm_fiq_new, | ||
265 | .pcm_free = imx_pcm_free, | ||
266 | }; | ||
267 | |||
268 | struct snd_soc_platform *imx_ssi_fiq_init(struct platform_device *pdev, | ||
269 | struct imx_ssi *ssi) | ||
270 | { | ||
271 | int ret = 0; | ||
272 | |||
273 | ret = claim_fiq(&fh); | ||
274 | if (ret) { | ||
275 | dev_err(&pdev->dev, "failed to claim fiq: %d", ret); | ||
276 | return ERR_PTR(ret); | ||
277 | } | ||
278 | |||
279 | mxc_set_irq_fiq(ssi->irq, 1); | ||
280 | |||
281 | imx_pcm_fiq = ssi->irq; | ||
282 | |||
283 | imx_ssi_fiq_base = (unsigned long)ssi->base; | ||
284 | |||
285 | ssi->dma_params_tx.burstsize = 4; | ||
286 | ssi->dma_params_rx.burstsize = 6; | ||
287 | |||
288 | return &imx_soc_platform_fiq; | ||
289 | } | ||
290 | |||
291 | void imx_ssi_fiq_exit(struct platform_device *pdev, | ||
292 | struct imx_ssi *ssi) | ||
293 | { | ||
294 | mxc_set_irq_fiq(ssi->irq, 0); | ||
295 | release_fiq(&fh); | ||
296 | } | ||
297 | |||
diff --git a/sound/soc/imx/imx-ssi.c b/sound/soc/imx/imx-ssi.c new file mode 100644 index 000000000000..56f46a75d297 --- /dev/null +++ b/sound/soc/imx/imx-ssi.c | |||
@@ -0,0 +1,758 @@ | |||
1 | /* | ||
2 | * imx-ssi.c -- ALSA Soc Audio Layer | ||
3 | * | ||
4 | * Copyright 2009 Sascha Hauer <s.hauer@pengutronix.de> | ||
5 | * | ||
6 | * This code is based on code copyrighted by Freescale, | ||
7 | * Liam Girdwood, Javier Martin and probably others. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License as published by the | ||
11 | * Free Software Foundation; either version 2 of the License, or (at your | ||
12 | * option) any later version. | ||
13 | * | ||
14 | * | ||
15 | * The i.MX SSI core has some nasty limitations in AC97 mode. While most | ||
16 | * sane processor vendors have a FIFO per AC97 slot, the i.MX has only | ||
17 | * one FIFO which combines all valid receive slots. We cannot even select | ||
18 | * which slots we want to receive. The WM9712 with which this driver | ||
19 | * was developped with always sends GPIO status data in slot 12 which | ||
20 | * we receive in our (PCM-) data stream. The only chance we have is to | ||
21 | * manually skip this data in the FIQ handler. With sampling rates different | ||
22 | * from 48000Hz not every frame has valid receive data, so the ratio | ||
23 | * between pcm data and GPIO status data changes. Our FIQ handler is not | ||
24 | * able to handle this, hence this driver only works with 48000Hz sampling | ||
25 | * rate. | ||
26 | * Reading and writing AC97 registers is another challange. The core | ||
27 | * provides us status bits when the read register is updated with *another* | ||
28 | * value. When we read the same register two times (and the register still | ||
29 | * contains the same value) these status bits are not set. We work | ||
30 | * around this by not polling these bits but only wait a fixed delay. | ||
31 | * | ||
32 | */ | ||
33 | |||
34 | #include <linux/clk.h> | ||
35 | #include <linux/delay.h> | ||
36 | #include <linux/device.h> | ||
37 | #include <linux/dma-mapping.h> | ||
38 | #include <linux/init.h> | ||
39 | #include <linux/interrupt.h> | ||
40 | #include <linux/module.h> | ||
41 | #include <linux/platform_device.h> | ||
42 | |||
43 | #include <sound/core.h> | ||
44 | #include <sound/initval.h> | ||
45 | #include <sound/pcm.h> | ||
46 | #include <sound/pcm_params.h> | ||
47 | #include <sound/soc.h> | ||
48 | |||
49 | #include <mach/ssi.h> | ||
50 | #include <mach/hardware.h> | ||
51 | |||
52 | #include "imx-ssi.h" | ||
53 | |||
54 | #define SSI_SACNT_DEFAULT (SSI_SACNT_AC97EN | SSI_SACNT_FV) | ||
55 | |||
56 | /* | ||
57 | * SSI Network Mode or TDM slots configuration. | ||
58 | * Should only be called when port is inactive (i.e. SSIEN = 0). | ||
59 | */ | ||
60 | static int imx_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, | ||
61 | unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width) | ||
62 | { | ||
63 | struct imx_ssi *ssi = cpu_dai->private_data; | ||
64 | u32 sccr; | ||
65 | |||
66 | sccr = readl(ssi->base + SSI_STCCR); | ||
67 | sccr &= ~SSI_STCCR_DC_MASK; | ||
68 | sccr |= SSI_STCCR_DC(slots - 1); | ||
69 | writel(sccr, ssi->base + SSI_STCCR); | ||
70 | |||
71 | sccr = readl(ssi->base + SSI_SRCCR); | ||
72 | sccr &= ~SSI_STCCR_DC_MASK; | ||
73 | sccr |= SSI_STCCR_DC(slots - 1); | ||
74 | writel(sccr, ssi->base + SSI_SRCCR); | ||
75 | |||
76 | writel(tx_mask, ssi->base + SSI_STMSK); | ||
77 | writel(rx_mask, ssi->base + SSI_SRMSK); | ||
78 | |||
79 | return 0; | ||
80 | } | ||
81 | |||
82 | /* | ||
83 | * SSI DAI format configuration. | ||
84 | * Should only be called when port is inactive (i.e. SSIEN = 0). | ||
85 | * Note: We don't use the I2S modes but instead manually configure the | ||
86 | * SSI for I2S because the I2S mode is only a register preset. | ||
87 | */ | ||
88 | static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) | ||
89 | { | ||
90 | struct imx_ssi *ssi = cpu_dai->private_data; | ||
91 | u32 strcr = 0, scr; | ||
92 | |||
93 | scr = readl(ssi->base + SSI_SCR) & ~(SSI_SCR_SYN | SSI_SCR_NET); | ||
94 | |||
95 | /* DAI mode */ | ||
96 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
97 | case SND_SOC_DAIFMT_I2S: | ||
98 | /* data on rising edge of bclk, frame low 1clk before data */ | ||
99 | strcr |= SSI_STCR_TFSI | SSI_STCR_TEFS | SSI_STCR_TXBIT0; | ||
100 | scr |= SSI_SCR_NET; | ||
101 | break; | ||
102 | case SND_SOC_DAIFMT_LEFT_J: | ||
103 | /* data on rising edge of bclk, frame high with data */ | ||
104 | strcr |= SSI_STCR_TXBIT0; | ||
105 | break; | ||
106 | case SND_SOC_DAIFMT_DSP_B: | ||
107 | /* data on rising edge of bclk, frame high with data */ | ||
108 | strcr |= SSI_STCR_TFSL; | ||
109 | break; | ||
110 | case SND_SOC_DAIFMT_DSP_A: | ||
111 | /* data on rising edge of bclk, frame high 1clk before data */ | ||
112 | strcr |= SSI_STCR_TFSL | SSI_STCR_TEFS; | ||
113 | break; | ||
114 | } | ||
115 | |||
116 | /* DAI clock inversion */ | ||
117 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
118 | case SND_SOC_DAIFMT_IB_IF: | ||
119 | strcr |= SSI_STCR_TFSI; | ||
120 | strcr &= ~SSI_STCR_TSCKP; | ||
121 | break; | ||
122 | case SND_SOC_DAIFMT_IB_NF: | ||
123 | strcr &= ~(SSI_STCR_TSCKP | SSI_STCR_TFSI); | ||
124 | break; | ||
125 | case SND_SOC_DAIFMT_NB_IF: | ||
126 | strcr |= SSI_STCR_TFSI | SSI_STCR_TSCKP; | ||
127 | break; | ||
128 | case SND_SOC_DAIFMT_NB_NF: | ||
129 | strcr &= ~SSI_STCR_TFSI; | ||
130 | strcr |= SSI_STCR_TSCKP; | ||
131 | break; | ||
132 | } | ||
133 | |||
134 | /* DAI clock master masks */ | ||
135 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
136 | case SND_SOC_DAIFMT_CBM_CFM: | ||
137 | break; | ||
138 | default: | ||
139 | /* Master mode not implemented, needs handling of clocks. */ | ||
140 | return -EINVAL; | ||
141 | } | ||
142 | |||
143 | strcr |= SSI_STCR_TFEN0; | ||
144 | |||
145 | writel(strcr, ssi->base + SSI_STCR); | ||
146 | writel(strcr, ssi->base + SSI_SRCR); | ||
147 | writel(scr, ssi->base + SSI_SCR); | ||
148 | |||
149 | return 0; | ||
150 | } | ||
151 | |||
152 | /* | ||
153 | * SSI system clock configuration. | ||
154 | * Should only be called when port is inactive (i.e. SSIEN = 0). | ||
155 | */ | ||
156 | static int imx_ssi_set_dai_sysclk(struct snd_soc_dai *cpu_dai, | ||
157 | int clk_id, unsigned int freq, int dir) | ||
158 | { | ||
159 | struct imx_ssi *ssi = cpu_dai->private_data; | ||
160 | u32 scr; | ||
161 | |||
162 | scr = readl(ssi->base + SSI_SCR); | ||
163 | |||
164 | switch (clk_id) { | ||
165 | case IMX_SSP_SYS_CLK: | ||
166 | if (dir == SND_SOC_CLOCK_OUT) | ||
167 | scr |= SSI_SCR_SYS_CLK_EN; | ||
168 | else | ||
169 | scr &= ~SSI_SCR_SYS_CLK_EN; | ||
170 | break; | ||
171 | default: | ||
172 | return -EINVAL; | ||
173 | } | ||
174 | |||
175 | writel(scr, ssi->base + SSI_SCR); | ||
176 | |||
177 | return 0; | ||
178 | } | ||
179 | |||
180 | /* | ||
181 | * SSI Clock dividers | ||
182 | * Should only be called when port is inactive (i.e. SSIEN = 0). | ||
183 | */ | ||
184 | static int imx_ssi_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, | ||
185 | int div_id, int div) | ||
186 | { | ||
187 | struct imx_ssi *ssi = cpu_dai->private_data; | ||
188 | u32 stccr, srccr; | ||
189 | |||
190 | stccr = readl(ssi->base + SSI_STCCR); | ||
191 | srccr = readl(ssi->base + SSI_SRCCR); | ||
192 | |||
193 | switch (div_id) { | ||
194 | case IMX_SSI_TX_DIV_2: | ||
195 | stccr &= ~SSI_STCCR_DIV2; | ||
196 | stccr |= div; | ||
197 | break; | ||
198 | case IMX_SSI_TX_DIV_PSR: | ||
199 | stccr &= ~SSI_STCCR_PSR; | ||
200 | stccr |= div; | ||
201 | break; | ||
202 | case IMX_SSI_TX_DIV_PM: | ||
203 | stccr &= ~0xff; | ||
204 | stccr |= SSI_STCCR_PM(div); | ||
205 | break; | ||
206 | case IMX_SSI_RX_DIV_2: | ||
207 | stccr &= ~SSI_STCCR_DIV2; | ||
208 | stccr |= div; | ||
209 | break; | ||
210 | case IMX_SSI_RX_DIV_PSR: | ||
211 | stccr &= ~SSI_STCCR_PSR; | ||
212 | stccr |= div; | ||
213 | break; | ||
214 | case IMX_SSI_RX_DIV_PM: | ||
215 | stccr &= ~0xff; | ||
216 | stccr |= SSI_STCCR_PM(div); | ||
217 | break; | ||
218 | default: | ||
219 | return -EINVAL; | ||
220 | } | ||
221 | |||
222 | writel(stccr, ssi->base + SSI_STCCR); | ||
223 | writel(srccr, ssi->base + SSI_SRCCR); | ||
224 | |||
225 | return 0; | ||
226 | } | ||
227 | |||
228 | /* | ||
229 | * Should only be called when port is inactive (i.e. SSIEN = 0), | ||
230 | * although can be called multiple times by upper layers. | ||
231 | */ | ||
232 | static int imx_ssi_hw_params(struct snd_pcm_substream *substream, | ||
233 | struct snd_pcm_hw_params *params, | ||
234 | struct snd_soc_dai *cpu_dai) | ||
235 | { | ||
236 | struct imx_ssi *ssi = cpu_dai->private_data; | ||
237 | u32 reg, sccr; | ||
238 | |||
239 | /* Tx/Rx config */ | ||
240 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
241 | reg = SSI_STCCR; | ||
242 | cpu_dai->dma_data = &ssi->dma_params_tx; | ||
243 | } else { | ||
244 | reg = SSI_SRCCR; | ||
245 | cpu_dai->dma_data = &ssi->dma_params_rx; | ||
246 | } | ||
247 | |||
248 | sccr = readl(ssi->base + reg) & ~SSI_STCCR_WL_MASK; | ||
249 | |||
250 | /* DAI data (word) size */ | ||
251 | switch (params_format(params)) { | ||
252 | case SNDRV_PCM_FORMAT_S16_LE: | ||
253 | sccr |= SSI_SRCCR_WL(16); | ||
254 | break; | ||
255 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
256 | sccr |= SSI_SRCCR_WL(20); | ||
257 | break; | ||
258 | case SNDRV_PCM_FORMAT_S24_LE: | ||
259 | sccr |= SSI_SRCCR_WL(24); | ||
260 | break; | ||
261 | } | ||
262 | |||
263 | writel(sccr, ssi->base + reg); | ||
264 | |||
265 | return 0; | ||
266 | } | ||
267 | |||
268 | static int imx_ssi_trigger(struct snd_pcm_substream *substream, int cmd, | ||
269 | struct snd_soc_dai *dai) | ||
270 | { | ||
271 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
272 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | ||
273 | struct imx_ssi *ssi = cpu_dai->private_data; | ||
274 | unsigned int sier_bits, sier; | ||
275 | unsigned int scr; | ||
276 | |||
277 | scr = readl(ssi->base + SSI_SCR); | ||
278 | sier = readl(ssi->base + SSI_SIER); | ||
279 | |||
280 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
281 | if (ssi->flags & IMX_SSI_DMA) | ||
282 | sier_bits = SSI_SIER_TDMAE; | ||
283 | else | ||
284 | sier_bits = SSI_SIER_TIE | SSI_SIER_TFE0_EN; | ||
285 | } else { | ||
286 | if (ssi->flags & IMX_SSI_DMA) | ||
287 | sier_bits = SSI_SIER_RDMAE; | ||
288 | else | ||
289 | sier_bits = SSI_SIER_RIE | SSI_SIER_RFF0_EN; | ||
290 | } | ||
291 | |||
292 | switch (cmd) { | ||
293 | case SNDRV_PCM_TRIGGER_START: | ||
294 | case SNDRV_PCM_TRIGGER_RESUME: | ||
295 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
296 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
297 | scr |= SSI_SCR_TE; | ||
298 | else | ||
299 | scr |= SSI_SCR_RE; | ||
300 | sier |= sier_bits; | ||
301 | |||
302 | if (++ssi->enabled == 1) | ||
303 | scr |= SSI_SCR_SSIEN; | ||
304 | |||
305 | break; | ||
306 | |||
307 | case SNDRV_PCM_TRIGGER_STOP: | ||
308 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
309 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
310 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
311 | scr &= ~SSI_SCR_TE; | ||
312 | else | ||
313 | scr &= ~SSI_SCR_RE; | ||
314 | sier &= ~sier_bits; | ||
315 | |||
316 | if (--ssi->enabled == 0) | ||
317 | scr &= ~SSI_SCR_SSIEN; | ||
318 | |||
319 | break; | ||
320 | default: | ||
321 | return -EINVAL; | ||
322 | } | ||
323 | |||
324 | if (!(ssi->flags & IMX_SSI_USE_AC97)) | ||
325 | /* rx/tx are always enabled to access ac97 registers */ | ||
326 | writel(scr, ssi->base + SSI_SCR); | ||
327 | |||
328 | writel(sier, ssi->base + SSI_SIER); | ||
329 | |||
330 | return 0; | ||
331 | } | ||
332 | |||
333 | static struct snd_soc_dai_ops imx_ssi_pcm_dai_ops = { | ||
334 | .hw_params = imx_ssi_hw_params, | ||
335 | .set_fmt = imx_ssi_set_dai_fmt, | ||
336 | .set_clkdiv = imx_ssi_set_dai_clkdiv, | ||
337 | .set_sysclk = imx_ssi_set_dai_sysclk, | ||
338 | .set_tdm_slot = imx_ssi_set_dai_tdm_slot, | ||
339 | .trigger = imx_ssi_trigger, | ||
340 | }; | ||
341 | |||
342 | static struct snd_soc_dai imx_ssi_dai = { | ||
343 | .playback = { | ||
344 | .channels_min = 2, | ||
345 | .channels_max = 2, | ||
346 | .rates = SNDRV_PCM_RATE_8000_96000, | ||
347 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
348 | }, | ||
349 | .capture = { | ||
350 | .channels_min = 2, | ||
351 | .channels_max = 2, | ||
352 | .rates = SNDRV_PCM_RATE_8000_96000, | ||
353 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
354 | }, | ||
355 | .ops = &imx_ssi_pcm_dai_ops, | ||
356 | }; | ||
357 | |||
358 | int snd_imx_pcm_mmap(struct snd_pcm_substream *substream, | ||
359 | struct vm_area_struct *vma) | ||
360 | { | ||
361 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
362 | int ret; | ||
363 | |||
364 | ret = dma_mmap_coherent(NULL, vma, runtime->dma_area, | ||
365 | runtime->dma_addr, runtime->dma_bytes); | ||
366 | |||
367 | pr_debug("%s: ret: %d %p 0x%08x 0x%08x\n", __func__, ret, | ||
368 | runtime->dma_area, | ||
369 | runtime->dma_addr, | ||
370 | runtime->dma_bytes); | ||
371 | return ret; | ||
372 | } | ||
373 | |||
374 | static int imx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) | ||
375 | { | ||
376 | struct snd_pcm_substream *substream = pcm->streams[stream].substream; | ||
377 | struct snd_dma_buffer *buf = &substream->dma_buffer; | ||
378 | size_t size = IMX_SSI_DMABUF_SIZE; | ||
379 | |||
380 | buf->dev.type = SNDRV_DMA_TYPE_DEV; | ||
381 | buf->dev.dev = pcm->card->dev; | ||
382 | buf->private_data = NULL; | ||
383 | buf->area = dma_alloc_writecombine(pcm->card->dev, size, | ||
384 | &buf->addr, GFP_KERNEL); | ||
385 | if (!buf->area) | ||
386 | return -ENOMEM; | ||
387 | buf->bytes = size; | ||
388 | |||
389 | return 0; | ||
390 | } | ||
391 | |||
392 | static u64 imx_pcm_dmamask = DMA_BIT_MASK(32); | ||
393 | |||
394 | int imx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, | ||
395 | struct snd_pcm *pcm) | ||
396 | { | ||
397 | |||
398 | int ret = 0; | ||
399 | |||
400 | if (!card->dev->dma_mask) | ||
401 | card->dev->dma_mask = &imx_pcm_dmamask; | ||
402 | if (!card->dev->coherent_dma_mask) | ||
403 | card->dev->coherent_dma_mask = DMA_BIT_MASK(32); | ||
404 | if (dai->playback.channels_min) { | ||
405 | ret = imx_pcm_preallocate_dma_buffer(pcm, | ||
406 | SNDRV_PCM_STREAM_PLAYBACK); | ||
407 | if (ret) | ||
408 | goto out; | ||
409 | } | ||
410 | |||
411 | if (dai->capture.channels_min) { | ||
412 | ret = imx_pcm_preallocate_dma_buffer(pcm, | ||
413 | SNDRV_PCM_STREAM_CAPTURE); | ||
414 | if (ret) | ||
415 | goto out; | ||
416 | } | ||
417 | |||
418 | out: | ||
419 | return ret; | ||
420 | } | ||
421 | |||
422 | void imx_pcm_free(struct snd_pcm *pcm) | ||
423 | { | ||
424 | struct snd_pcm_substream *substream; | ||
425 | struct snd_dma_buffer *buf; | ||
426 | int stream; | ||
427 | |||
428 | for (stream = 0; stream < 2; stream++) { | ||
429 | substream = pcm->streams[stream].substream; | ||
430 | if (!substream) | ||
431 | continue; | ||
432 | |||
433 | buf = &substream->dma_buffer; | ||
434 | if (!buf->area) | ||
435 | continue; | ||
436 | |||
437 | dma_free_writecombine(pcm->card->dev, buf->bytes, | ||
438 | buf->area, buf->addr); | ||
439 | buf->area = NULL; | ||
440 | } | ||
441 | } | ||
442 | |||
443 | struct snd_soc_platform imx_soc_platform = { | ||
444 | .name = "imx-audio", | ||
445 | }; | ||
446 | EXPORT_SYMBOL_GPL(imx_soc_platform); | ||
447 | |||
448 | static struct snd_soc_dai imx_ac97_dai = { | ||
449 | .name = "AC97", | ||
450 | .ac97_control = 1, | ||
451 | .playback = { | ||
452 | .stream_name = "AC97 Playback", | ||
453 | .channels_min = 2, | ||
454 | .channels_max = 2, | ||
455 | .rates = SNDRV_PCM_RATE_48000, | ||
456 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
457 | }, | ||
458 | .capture = { | ||
459 | .stream_name = "AC97 Capture", | ||
460 | .channels_min = 2, | ||
461 | .channels_max = 2, | ||
462 | .rates = SNDRV_PCM_RATE_48000, | ||
463 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
464 | }, | ||
465 | .ops = &imx_ssi_pcm_dai_ops, | ||
466 | }; | ||
467 | |||
468 | static void setup_channel_to_ac97(struct imx_ssi *imx_ssi) | ||
469 | { | ||
470 | void __iomem *base = imx_ssi->base; | ||
471 | |||
472 | writel(0x0, base + SSI_SCR); | ||
473 | writel(0x0, base + SSI_STCR); | ||
474 | writel(0x0, base + SSI_SRCR); | ||
475 | |||
476 | writel(SSI_SCR_SYN | SSI_SCR_NET, base + SSI_SCR); | ||
477 | |||
478 | writel(SSI_SFCSR_RFWM0(8) | | ||
479 | SSI_SFCSR_TFWM0(8) | | ||
480 | SSI_SFCSR_RFWM1(8) | | ||
481 | SSI_SFCSR_TFWM1(8), base + SSI_SFCSR); | ||
482 | |||
483 | writel(SSI_STCCR_WL(16) | SSI_STCCR_DC(12), base + SSI_STCCR); | ||
484 | writel(SSI_STCCR_WL(16) | SSI_STCCR_DC(12), base + SSI_SRCCR); | ||
485 | |||
486 | writel(SSI_SCR_SYN | SSI_SCR_NET | SSI_SCR_SSIEN, base + SSI_SCR); | ||
487 | writel(SSI_SOR_WAIT(3), base + SSI_SOR); | ||
488 | |||
489 | writel(SSI_SCR_SYN | SSI_SCR_NET | SSI_SCR_SSIEN | | ||
490 | SSI_SCR_TE | SSI_SCR_RE, | ||
491 | base + SSI_SCR); | ||
492 | |||
493 | writel(SSI_SACNT_DEFAULT, base + SSI_SACNT); | ||
494 | writel(0xff, base + SSI_SACCDIS); | ||
495 | writel(0x300, base + SSI_SACCEN); | ||
496 | } | ||
497 | |||
498 | static struct imx_ssi *ac97_ssi; | ||
499 | |||
500 | static void imx_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg, | ||
501 | unsigned short val) | ||
502 | { | ||
503 | struct imx_ssi *imx_ssi = ac97_ssi; | ||
504 | void __iomem *base = imx_ssi->base; | ||
505 | unsigned int lreg; | ||
506 | unsigned int lval; | ||
507 | |||
508 | if (reg > 0x7f) | ||
509 | return; | ||
510 | |||
511 | pr_debug("%s: 0x%02x 0x%04x\n", __func__, reg, val); | ||
512 | |||
513 | lreg = reg << 12; | ||
514 | writel(lreg, base + SSI_SACADD); | ||
515 | |||
516 | lval = val << 4; | ||
517 | writel(lval , base + SSI_SACDAT); | ||
518 | |||
519 | writel(SSI_SACNT_DEFAULT | SSI_SACNT_WR, base + SSI_SACNT); | ||
520 | udelay(100); | ||
521 | } | ||
522 | |||
523 | static unsigned short imx_ssi_ac97_read(struct snd_ac97 *ac97, | ||
524 | unsigned short reg) | ||
525 | { | ||
526 | struct imx_ssi *imx_ssi = ac97_ssi; | ||
527 | void __iomem *base = imx_ssi->base; | ||
528 | |||
529 | unsigned short val = -1; | ||
530 | unsigned int lreg; | ||
531 | |||
532 | lreg = (reg & 0x7f) << 12 ; | ||
533 | writel(lreg, base + SSI_SACADD); | ||
534 | writel(SSI_SACNT_DEFAULT | SSI_SACNT_RD, base + SSI_SACNT); | ||
535 | |||
536 | udelay(100); | ||
537 | |||
538 | val = (readl(base + SSI_SACDAT) >> 4) & 0xffff; | ||
539 | |||
540 | pr_debug("%s: 0x%02x 0x%04x\n", __func__, reg, val); | ||
541 | |||
542 | return val; | ||
543 | } | ||
544 | |||
545 | static void imx_ssi_ac97_reset(struct snd_ac97 *ac97) | ||
546 | { | ||
547 | struct imx_ssi *imx_ssi = ac97_ssi; | ||
548 | |||
549 | if (imx_ssi->ac97_reset) | ||
550 | imx_ssi->ac97_reset(ac97); | ||
551 | } | ||
552 | |||
553 | static void imx_ssi_ac97_warm_reset(struct snd_ac97 *ac97) | ||
554 | { | ||
555 | struct imx_ssi *imx_ssi = ac97_ssi; | ||
556 | |||
557 | if (imx_ssi->ac97_warm_reset) | ||
558 | imx_ssi->ac97_warm_reset(ac97); | ||
559 | } | ||
560 | |||
561 | struct snd_ac97_bus_ops soc_ac97_ops = { | ||
562 | .read = imx_ssi_ac97_read, | ||
563 | .write = imx_ssi_ac97_write, | ||
564 | .reset = imx_ssi_ac97_reset, | ||
565 | .warm_reset = imx_ssi_ac97_warm_reset | ||
566 | }; | ||
567 | EXPORT_SYMBOL_GPL(soc_ac97_ops); | ||
568 | |||
569 | struct snd_soc_dai imx_ssi_pcm_dai[2]; | ||
570 | EXPORT_SYMBOL_GPL(imx_ssi_pcm_dai); | ||
571 | |||
572 | static int imx_ssi_probe(struct platform_device *pdev) | ||
573 | { | ||
574 | struct resource *res; | ||
575 | struct imx_ssi *ssi; | ||
576 | struct imx_ssi_platform_data *pdata = pdev->dev.platform_data; | ||
577 | struct snd_soc_platform *platform; | ||
578 | int ret = 0; | ||
579 | unsigned int val; | ||
580 | struct snd_soc_dai *dai = &imx_ssi_pcm_dai[pdev->id]; | ||
581 | |||
582 | if (dai->id >= ARRAY_SIZE(imx_ssi_pcm_dai)) | ||
583 | return -EINVAL; | ||
584 | |||
585 | ssi = kzalloc(sizeof(*ssi), GFP_KERNEL); | ||
586 | if (!ssi) | ||
587 | return -ENOMEM; | ||
588 | |||
589 | if (pdata) { | ||
590 | ssi->ac97_reset = pdata->ac97_reset; | ||
591 | ssi->ac97_warm_reset = pdata->ac97_warm_reset; | ||
592 | ssi->flags = pdata->flags; | ||
593 | } | ||
594 | |||
595 | ssi->irq = platform_get_irq(pdev, 0); | ||
596 | |||
597 | ssi->clk = clk_get(&pdev->dev, NULL); | ||
598 | if (IS_ERR(ssi->clk)) { | ||
599 | ret = PTR_ERR(ssi->clk); | ||
600 | dev_err(&pdev->dev, "Cannot get the clock: %d\n", | ||
601 | ret); | ||
602 | goto failed_clk; | ||
603 | } | ||
604 | clk_enable(ssi->clk); | ||
605 | |||
606 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
607 | if (!res) { | ||
608 | ret = -ENODEV; | ||
609 | goto failed_get_resource; | ||
610 | } | ||
611 | |||
612 | if (!request_mem_region(res->start, resource_size(res), DRV_NAME)) { | ||
613 | dev_err(&pdev->dev, "request_mem_region failed\n"); | ||
614 | ret = -EBUSY; | ||
615 | goto failed_get_resource; | ||
616 | } | ||
617 | |||
618 | ssi->base = ioremap(res->start, resource_size(res)); | ||
619 | if (!ssi->base) { | ||
620 | dev_err(&pdev->dev, "ioremap failed\n"); | ||
621 | ret = -ENODEV; | ||
622 | goto failed_ioremap; | ||
623 | } | ||
624 | |||
625 | if (ssi->flags & IMX_SSI_USE_AC97) { | ||
626 | if (ac97_ssi) { | ||
627 | ret = -EBUSY; | ||
628 | goto failed_ac97; | ||
629 | } | ||
630 | ac97_ssi = ssi; | ||
631 | setup_channel_to_ac97(ssi); | ||
632 | memcpy(dai, &imx_ac97_dai, sizeof(imx_ac97_dai)); | ||
633 | } else | ||
634 | memcpy(dai, &imx_ssi_dai, sizeof(imx_ssi_dai)); | ||
635 | |||
636 | writel(0x0, ssi->base + SSI_SIER); | ||
637 | |||
638 | ssi->dma_params_rx.dma_addr = res->start + SSI_SRX0; | ||
639 | ssi->dma_params_tx.dma_addr = res->start + SSI_STX0; | ||
640 | |||
641 | res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx0"); | ||
642 | if (res) | ||
643 | ssi->dma_params_tx.dma = res->start; | ||
644 | |||
645 | res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx0"); | ||
646 | if (res) | ||
647 | ssi->dma_params_rx.dma = res->start; | ||
648 | |||
649 | dai->id = pdev->id; | ||
650 | dai->dev = &pdev->dev; | ||
651 | dai->name = kasprintf(GFP_KERNEL, "imx-ssi.%d", pdev->id); | ||
652 | dai->private_data = ssi; | ||
653 | |||
654 | if ((cpu_is_mx27() || cpu_is_mx21()) && | ||
655 | !(ssi->flags & IMX_SSI_USE_AC97)) { | ||
656 | ssi->flags |= IMX_SSI_DMA; | ||
657 | platform = imx_ssi_dma_mx2_init(pdev, ssi); | ||
658 | } else | ||
659 | platform = imx_ssi_fiq_init(pdev, ssi); | ||
660 | |||
661 | imx_soc_platform.pcm_ops = platform->pcm_ops; | ||
662 | imx_soc_platform.pcm_new = platform->pcm_new; | ||
663 | imx_soc_platform.pcm_free = platform->pcm_free; | ||
664 | |||
665 | val = SSI_SFCSR_TFWM0(ssi->dma_params_tx.burstsize) | | ||
666 | SSI_SFCSR_RFWM0(ssi->dma_params_rx.burstsize); | ||
667 | writel(val, ssi->base + SSI_SFCSR); | ||
668 | |||
669 | ret = snd_soc_register_dai(dai); | ||
670 | if (ret) { | ||
671 | dev_err(&pdev->dev, "register DAI failed\n"); | ||
672 | goto failed_register; | ||
673 | } | ||
674 | |||
675 | platform_set_drvdata(pdev, ssi); | ||
676 | |||
677 | return 0; | ||
678 | |||
679 | failed_register: | ||
680 | failed_ac97: | ||
681 | iounmap(ssi->base); | ||
682 | failed_ioremap: | ||
683 | release_mem_region(res->start, resource_size(res)); | ||
684 | failed_get_resource: | ||
685 | clk_disable(ssi->clk); | ||
686 | clk_put(ssi->clk); | ||
687 | failed_clk: | ||
688 | kfree(ssi); | ||
689 | |||
690 | return ret; | ||
691 | } | ||
692 | |||
693 | static int __devexit imx_ssi_remove(struct platform_device *pdev) | ||
694 | { | ||
695 | struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
696 | struct imx_ssi *ssi = platform_get_drvdata(pdev); | ||
697 | struct snd_soc_dai *dai = &imx_ssi_pcm_dai[pdev->id]; | ||
698 | |||
699 | snd_soc_unregister_dai(dai); | ||
700 | |||
701 | if (ssi->flags & IMX_SSI_USE_AC97) | ||
702 | ac97_ssi = NULL; | ||
703 | |||
704 | if (!(ssi->flags & IMX_SSI_DMA)) | ||
705 | imx_ssi_fiq_exit(pdev, ssi); | ||
706 | |||
707 | iounmap(ssi->base); | ||
708 | release_mem_region(res->start, resource_size(res)); | ||
709 | clk_disable(ssi->clk); | ||
710 | clk_put(ssi->clk); | ||
711 | kfree(ssi); | ||
712 | |||
713 | return 0; | ||
714 | } | ||
715 | |||
716 | static struct platform_driver imx_ssi_driver = { | ||
717 | .probe = imx_ssi_probe, | ||
718 | .remove = __devexit_p(imx_ssi_remove), | ||
719 | |||
720 | .driver = { | ||
721 | .name = DRV_NAME, | ||
722 | .owner = THIS_MODULE, | ||
723 | }, | ||
724 | }; | ||
725 | |||
726 | static int __init imx_ssi_init(void) | ||
727 | { | ||
728 | int ret; | ||
729 | |||
730 | ret = snd_soc_register_platform(&imx_soc_platform); | ||
731 | if (ret) { | ||
732 | pr_err("failed to register soc platform: %d\n", ret); | ||
733 | return ret; | ||
734 | } | ||
735 | |||
736 | ret = platform_driver_register(&imx_ssi_driver); | ||
737 | if (ret) { | ||
738 | snd_soc_unregister_platform(&imx_soc_platform); | ||
739 | return ret; | ||
740 | } | ||
741 | |||
742 | return 0; | ||
743 | } | ||
744 | |||
745 | static void __exit imx_ssi_exit(void) | ||
746 | { | ||
747 | platform_driver_unregister(&imx_ssi_driver); | ||
748 | snd_soc_unregister_platform(&imx_soc_platform); | ||
749 | } | ||
750 | |||
751 | module_init(imx_ssi_init); | ||
752 | module_exit(imx_ssi_exit); | ||
753 | |||
754 | /* Module information */ | ||
755 | MODULE_AUTHOR("Sascha Hauer, <s.hauer@pengutronix.de>"); | ||
756 | MODULE_DESCRIPTION("i.MX I2S/ac97 SoC Interface"); | ||
757 | MODULE_LICENSE("GPL"); | ||
758 | |||
diff --git a/sound/soc/imx/imx-ssi.h b/sound/soc/imx/imx-ssi.h new file mode 100644 index 000000000000..55f26ebcd8c2 --- /dev/null +++ b/sound/soc/imx/imx-ssi.h | |||
@@ -0,0 +1,237 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License version 2 as | ||
4 | * published by the Free Software Foundation. | ||
5 | */ | ||
6 | |||
7 | #ifndef _IMX_SSI_H | ||
8 | #define _IMX_SSI_H | ||
9 | |||
10 | #define SSI_STX0 0x00 | ||
11 | #define SSI_STX1 0x04 | ||
12 | #define SSI_SRX0 0x08 | ||
13 | #define SSI_SRX1 0x0c | ||
14 | |||
15 | #define SSI_SCR 0x10 | ||
16 | #define SSI_SCR_CLK_IST (1 << 9) | ||
17 | #define SSI_SCR_CLK_IST_SHIFT 9 | ||
18 | #define SSI_SCR_TCH_EN (1 << 8) | ||
19 | #define SSI_SCR_SYS_CLK_EN (1 << 7) | ||
20 | #define SSI_SCR_I2S_MODE_NORM (0 << 5) | ||
21 | #define SSI_SCR_I2S_MODE_MSTR (1 << 5) | ||
22 | #define SSI_SCR_I2S_MODE_SLAVE (2 << 5) | ||
23 | #define SSI_I2S_MODE_MASK (3 << 5) | ||
24 | #define SSI_SCR_SYN (1 << 4) | ||
25 | #define SSI_SCR_NET (1 << 3) | ||
26 | #define SSI_SCR_RE (1 << 2) | ||
27 | #define SSI_SCR_TE (1 << 1) | ||
28 | #define SSI_SCR_SSIEN (1 << 0) | ||
29 | |||
30 | #define SSI_SISR 0x14 | ||
31 | #define SSI_SISR_MASK ((1 << 19) - 1) | ||
32 | #define SSI_SISR_CMDAU (1 << 18) | ||
33 | #define SSI_SISR_CMDDU (1 << 17) | ||
34 | #define SSI_SISR_RXT (1 << 16) | ||
35 | #define SSI_SISR_RDR1 (1 << 15) | ||
36 | #define SSI_SISR_RDR0 (1 << 14) | ||
37 | #define SSI_SISR_TDE1 (1 << 13) | ||
38 | #define SSI_SISR_TDE0 (1 << 12) | ||
39 | #define SSI_SISR_ROE1 (1 << 11) | ||
40 | #define SSI_SISR_ROE0 (1 << 10) | ||
41 | #define SSI_SISR_TUE1 (1 << 9) | ||
42 | #define SSI_SISR_TUE0 (1 << 8) | ||
43 | #define SSI_SISR_TFS (1 << 7) | ||
44 | #define SSI_SISR_RFS (1 << 6) | ||
45 | #define SSI_SISR_TLS (1 << 5) | ||
46 | #define SSI_SISR_RLS (1 << 4) | ||
47 | #define SSI_SISR_RFF1 (1 << 3) | ||
48 | #define SSI_SISR_RFF0 (1 << 2) | ||
49 | #define SSI_SISR_TFE1 (1 << 1) | ||
50 | #define SSI_SISR_TFE0 (1 << 0) | ||
51 | |||
52 | #define SSI_SIER 0x18 | ||
53 | #define SSI_SIER_RDMAE (1 << 22) | ||
54 | #define SSI_SIER_RIE (1 << 21) | ||
55 | #define SSI_SIER_TDMAE (1 << 20) | ||
56 | #define SSI_SIER_TIE (1 << 19) | ||
57 | #define SSI_SIER_CMDAU_EN (1 << 18) | ||
58 | #define SSI_SIER_CMDDU_EN (1 << 17) | ||
59 | #define SSI_SIER_RXT_EN (1 << 16) | ||
60 | #define SSI_SIER_RDR1_EN (1 << 15) | ||
61 | #define SSI_SIER_RDR0_EN (1 << 14) | ||
62 | #define SSI_SIER_TDE1_EN (1 << 13) | ||
63 | #define SSI_SIER_TDE0_EN (1 << 12) | ||
64 | #define SSI_SIER_ROE1_EN (1 << 11) | ||
65 | #define SSI_SIER_ROE0_EN (1 << 10) | ||
66 | #define SSI_SIER_TUE1_EN (1 << 9) | ||
67 | #define SSI_SIER_TUE0_EN (1 << 8) | ||
68 | #define SSI_SIER_TFS_EN (1 << 7) | ||
69 | #define SSI_SIER_RFS_EN (1 << 6) | ||
70 | #define SSI_SIER_TLS_EN (1 << 5) | ||
71 | #define SSI_SIER_RLS_EN (1 << 4) | ||
72 | #define SSI_SIER_RFF1_EN (1 << 3) | ||
73 | #define SSI_SIER_RFF0_EN (1 << 2) | ||
74 | #define SSI_SIER_TFE1_EN (1 << 1) | ||
75 | #define SSI_SIER_TFE0_EN (1 << 0) | ||
76 | |||
77 | #define SSI_STCR 0x1c | ||
78 | #define SSI_STCR_TXBIT0 (1 << 9) | ||
79 | #define SSI_STCR_TFEN1 (1 << 8) | ||
80 | #define SSI_STCR_TFEN0 (1 << 7) | ||
81 | #define SSI_FIFO_ENABLE_0_SHIFT 7 | ||
82 | #define SSI_STCR_TFDIR (1 << 6) | ||
83 | #define SSI_STCR_TXDIR (1 << 5) | ||
84 | #define SSI_STCR_TSHFD (1 << 4) | ||
85 | #define SSI_STCR_TSCKP (1 << 3) | ||
86 | #define SSI_STCR_TFSI (1 << 2) | ||
87 | #define SSI_STCR_TFSL (1 << 1) | ||
88 | #define SSI_STCR_TEFS (1 << 0) | ||
89 | |||
90 | #define SSI_SRCR 0x20 | ||
91 | #define SSI_SRCR_RXBIT0 (1 << 9) | ||
92 | #define SSI_SRCR_RFEN1 (1 << 8) | ||
93 | #define SSI_SRCR_RFEN0 (1 << 7) | ||
94 | #define SSI_FIFO_ENABLE_0_SHIFT 7 | ||
95 | #define SSI_SRCR_RFDIR (1 << 6) | ||
96 | #define SSI_SRCR_RXDIR (1 << 5) | ||
97 | #define SSI_SRCR_RSHFD (1 << 4) | ||
98 | #define SSI_SRCR_RSCKP (1 << 3) | ||
99 | #define SSI_SRCR_RFSI (1 << 2) | ||
100 | #define SSI_SRCR_RFSL (1 << 1) | ||
101 | #define SSI_SRCR_REFS (1 << 0) | ||
102 | |||
103 | #define SSI_SRCCR 0x28 | ||
104 | #define SSI_SRCCR_DIV2 (1 << 18) | ||
105 | #define SSI_SRCCR_PSR (1 << 17) | ||
106 | #define SSI_SRCCR_WL(x) ((((x) - 2) >> 1) << 13) | ||
107 | #define SSI_SRCCR_DC(x) (((x) & 0x1f) << 8) | ||
108 | #define SSI_SRCCR_PM(x) (((x) & 0xff) << 0) | ||
109 | #define SSI_SRCCR_WL_MASK (0xf << 13) | ||
110 | #define SSI_SRCCR_DC_MASK (0x1f << 8) | ||
111 | #define SSI_SRCCR_PM_MASK (0xff << 0) | ||
112 | |||
113 | #define SSI_STCCR 0x24 | ||
114 | #define SSI_STCCR_DIV2 (1 << 18) | ||
115 | #define SSI_STCCR_PSR (1 << 17) | ||
116 | #define SSI_STCCR_WL(x) ((((x) - 2) >> 1) << 13) | ||
117 | #define SSI_STCCR_DC(x) (((x) & 0x1f) << 8) | ||
118 | #define SSI_STCCR_PM(x) (((x) & 0xff) << 0) | ||
119 | #define SSI_STCCR_WL_MASK (0xf << 13) | ||
120 | #define SSI_STCCR_DC_MASK (0x1f << 8) | ||
121 | #define SSI_STCCR_PM_MASK (0xff << 0) | ||
122 | |||
123 | #define SSI_SFCSR 0x2c | ||
124 | #define SSI_SFCSR_RFCNT1(x) (((x) & 0xf) << 28) | ||
125 | #define SSI_RX_FIFO_1_COUNT_SHIFT 28 | ||
126 | #define SSI_SFCSR_TFCNT1(x) (((x) & 0xf) << 24) | ||
127 | #define SSI_TX_FIFO_1_COUNT_SHIFT 24 | ||
128 | #define SSI_SFCSR_RFWM1(x) (((x) & 0xf) << 20) | ||
129 | #define SSI_SFCSR_TFWM1(x) (((x) & 0xf) << 16) | ||
130 | #define SSI_SFCSR_RFCNT0(x) (((x) & 0xf) << 12) | ||
131 | #define SSI_RX_FIFO_0_COUNT_SHIFT 12 | ||
132 | #define SSI_SFCSR_TFCNT0(x) (((x) & 0xf) << 8) | ||
133 | #define SSI_TX_FIFO_0_COUNT_SHIFT 8 | ||
134 | #define SSI_SFCSR_RFWM0(x) (((x) & 0xf) << 4) | ||
135 | #define SSI_SFCSR_TFWM0(x) (((x) & 0xf) << 0) | ||
136 | #define SSI_SFCSR_RFWM0_MASK (0xf << 4) | ||
137 | #define SSI_SFCSR_TFWM0_MASK (0xf << 0) | ||
138 | |||
139 | #define SSI_STR 0x30 | ||
140 | #define SSI_STR_TEST (1 << 15) | ||
141 | #define SSI_STR_RCK2TCK (1 << 14) | ||
142 | #define SSI_STR_RFS2TFS (1 << 13) | ||
143 | #define SSI_STR_RXSTATE(x) (((x) & 0xf) << 8) | ||
144 | #define SSI_STR_TXD2RXD (1 << 7) | ||
145 | #define SSI_STR_TCK2RCK (1 << 6) | ||
146 | #define SSI_STR_TFS2RFS (1 << 5) | ||
147 | #define SSI_STR_TXSTATE(x) (((x) & 0xf) << 0) | ||
148 | |||
149 | #define SSI_SOR 0x34 | ||
150 | #define SSI_SOR_CLKOFF (1 << 6) | ||
151 | #define SSI_SOR_RX_CLR (1 << 5) | ||
152 | #define SSI_SOR_TX_CLR (1 << 4) | ||
153 | #define SSI_SOR_INIT (1 << 3) | ||
154 | #define SSI_SOR_WAIT(x) (((x) & 0x3) << 1) | ||
155 | #define SSI_SOR_WAIT_MASK (0x3 << 1) | ||
156 | #define SSI_SOR_SYNRST (1 << 0) | ||
157 | |||
158 | #define SSI_SACNT 0x38 | ||
159 | #define SSI_SACNT_FRDIV(x) (((x) & 0x3f) << 5) | ||
160 | #define SSI_SACNT_WR (1 << 4) | ||
161 | #define SSI_SACNT_RD (1 << 3) | ||
162 | #define SSI_SACNT_TIF (1 << 2) | ||
163 | #define SSI_SACNT_FV (1 << 1) | ||
164 | #define SSI_SACNT_AC97EN (1 << 0) | ||
165 | |||
166 | #define SSI_SACADD 0x3c | ||
167 | #define SSI_SACDAT 0x40 | ||
168 | #define SSI_SATAG 0x44 | ||
169 | #define SSI_STMSK 0x48 | ||
170 | #define SSI_SRMSK 0x4c | ||
171 | #define SSI_SACCST 0x50 | ||
172 | #define SSI_SACCEN 0x54 | ||
173 | #define SSI_SACCDIS 0x58 | ||
174 | |||
175 | /* SSI clock sources */ | ||
176 | #define IMX_SSP_SYS_CLK 0 | ||
177 | |||
178 | /* SSI audio dividers */ | ||
179 | #define IMX_SSI_TX_DIV_2 0 | ||
180 | #define IMX_SSI_TX_DIV_PSR 1 | ||
181 | #define IMX_SSI_TX_DIV_PM 2 | ||
182 | #define IMX_SSI_RX_DIV_2 3 | ||
183 | #define IMX_SSI_RX_DIV_PSR 4 | ||
184 | #define IMX_SSI_RX_DIV_PM 5 | ||
185 | |||
186 | extern struct snd_soc_dai imx_ssi_pcm_dai[2]; | ||
187 | extern struct snd_soc_platform imx_soc_platform; | ||
188 | |||
189 | #define DRV_NAME "imx-ssi" | ||
190 | |||
191 | struct imx_pcm_dma_params { | ||
192 | int dma; | ||
193 | unsigned long dma_addr; | ||
194 | int burstsize; | ||
195 | }; | ||
196 | |||
197 | struct imx_ssi { | ||
198 | struct platform_device *ac97_dev; | ||
199 | |||
200 | struct snd_soc_device imx_ac97; | ||
201 | struct clk *clk; | ||
202 | void __iomem *base; | ||
203 | int irq; | ||
204 | int fiq_enable; | ||
205 | unsigned int offset; | ||
206 | |||
207 | unsigned int flags; | ||
208 | |||
209 | void (*ac97_reset) (struct snd_ac97 *ac97); | ||
210 | void (*ac97_warm_reset)(struct snd_ac97 *ac97); | ||
211 | |||
212 | struct imx_pcm_dma_params dma_params_rx; | ||
213 | struct imx_pcm_dma_params dma_params_tx; | ||
214 | |||
215 | int enabled; | ||
216 | }; | ||
217 | |||
218 | struct snd_soc_platform *imx_ssi_fiq_init(struct platform_device *pdev, | ||
219 | struct imx_ssi *ssi); | ||
220 | void imx_ssi_fiq_exit(struct platform_device *pdev, struct imx_ssi *ssi); | ||
221 | struct snd_soc_platform *imx_ssi_dma_mx2_init(struct platform_device *pdev, | ||
222 | struct imx_ssi *ssi); | ||
223 | |||
224 | int snd_imx_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma); | ||
225 | int imx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, | ||
226 | struct snd_pcm *pcm); | ||
227 | void imx_pcm_free(struct snd_pcm *pcm); | ||
228 | |||
229 | /* | ||
230 | * Do not change this as the FIQ handler depends on this size | ||
231 | */ | ||
232 | #define IMX_SSI_DMABUF_SIZE (64 * 1024) | ||
233 | |||
234 | #define DMA_RXFIFO_BURST 0x4 | ||
235 | #define DMA_TXFIFO_BURST 0x6 | ||
236 | |||
237 | #endif /* _IMX_SSI_H */ | ||
diff --git a/sound/soc/imx/mx1_mx2-pcm.c b/sound/soc/imx/mx1_mx2-pcm.c deleted file mode 100644 index bffffcd5ff34..000000000000 --- a/sound/soc/imx/mx1_mx2-pcm.c +++ /dev/null | |||
@@ -1,488 +0,0 @@ | |||
1 | /* | ||
2 | * mx1_mx2-pcm.c -- ALSA SoC interface for Freescale i.MX1x, i.MX2x CPUs | ||
3 | * | ||
4 | * Copyright 2009 Vista Silicon S.L. | ||
5 | * Author: Javier Martin | ||
6 | * javier.martin@vista-silicon.com | ||
7 | * | ||
8 | * Based on mxc-pcm.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 | */ | ||
16 | |||
17 | #include <linux/module.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/platform_device.h> | ||
20 | #include <linux/slab.h> | ||
21 | #include <linux/dma-mapping.h> | ||
22 | #include <sound/core.h> | ||
23 | #include <sound/pcm.h> | ||
24 | #include <sound/pcm_params.h> | ||
25 | #include <sound/soc.h> | ||
26 | #include <asm/dma.h> | ||
27 | #include <mach/hardware.h> | ||
28 | #include <mach/dma-mx1-mx2.h> | ||
29 | |||
30 | #include "mx1_mx2-pcm.h" | ||
31 | |||
32 | |||
33 | static const struct snd_pcm_hardware mx1_mx2_pcm_hardware = { | ||
34 | .info = (SNDRV_PCM_INFO_INTERLEAVED | | ||
35 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | ||
36 | SNDRV_PCM_INFO_MMAP | | ||
37 | SNDRV_PCM_INFO_MMAP_VALID), | ||
38 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
39 | .buffer_bytes_max = 32 * 1024, | ||
40 | .period_bytes_min = 64, | ||
41 | .period_bytes_max = 8 * 1024, | ||
42 | .periods_min = 2, | ||
43 | .periods_max = 255, | ||
44 | .fifo_size = 0, | ||
45 | }; | ||
46 | |||
47 | struct mx1_mx2_runtime_data { | ||
48 | int dma_ch; | ||
49 | int active; | ||
50 | unsigned int period; | ||
51 | unsigned int periods; | ||
52 | int tx_spin; | ||
53 | spinlock_t dma_lock; | ||
54 | struct mx1_mx2_pcm_dma_params *dma_params; | ||
55 | }; | ||
56 | |||
57 | |||
58 | /** | ||
59 | * This function stops the current dma transfer for playback | ||
60 | * and clears the dma pointers. | ||
61 | * | ||
62 | * @param substream pointer to the structure of the current stream. | ||
63 | * | ||
64 | */ | ||
65 | static int audio_stop_dma(struct snd_pcm_substream *substream) | ||
66 | { | ||
67 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
68 | struct mx1_mx2_runtime_data *prtd = runtime->private_data; | ||
69 | unsigned long flags; | ||
70 | |||
71 | spin_lock_irqsave(&prtd->dma_lock, flags); | ||
72 | |||
73 | pr_debug("%s\n", __func__); | ||
74 | |||
75 | prtd->active = 0; | ||
76 | prtd->period = 0; | ||
77 | prtd->periods = 0; | ||
78 | |||
79 | /* this stops the dma channel and clears the buffer ptrs */ | ||
80 | |||
81 | imx_dma_disable(prtd->dma_ch); | ||
82 | |||
83 | spin_unlock_irqrestore(&prtd->dma_lock, flags); | ||
84 | |||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | /** | ||
89 | * This function is called whenever a new audio block needs to be | ||
90 | * transferred to the codec. The function receives the address and the size | ||
91 | * of the new block and start a new DMA transfer. | ||
92 | * | ||
93 | * @param substream pointer to the structure of the current stream. | ||
94 | * | ||
95 | */ | ||
96 | static int dma_new_period(struct snd_pcm_substream *substream) | ||
97 | { | ||
98 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
99 | struct mx1_mx2_runtime_data *prtd = runtime->private_data; | ||
100 | unsigned int dma_size; | ||
101 | unsigned int offset; | ||
102 | int ret = 0; | ||
103 | dma_addr_t mem_addr; | ||
104 | unsigned int dev_addr; | ||
105 | |||
106 | if (prtd->active) { | ||
107 | dma_size = frames_to_bytes(runtime, runtime->period_size); | ||
108 | offset = dma_size * prtd->period; | ||
109 | |||
110 | pr_debug("%s: period (%d) out of (%d)\n", __func__, | ||
111 | prtd->period, | ||
112 | runtime->periods); | ||
113 | pr_debug("period_size %d frames\n offset %d bytes\n", | ||
114 | (unsigned int)runtime->period_size, | ||
115 | offset); | ||
116 | pr_debug("dma_size %d bytes\n", dma_size); | ||
117 | |||
118 | snd_BUG_ON(dma_size > mx1_mx2_pcm_hardware.period_bytes_max); | ||
119 | |||
120 | mem_addr = (dma_addr_t)(runtime->dma_addr + offset); | ||
121 | dev_addr = prtd->dma_params->per_address; | ||
122 | pr_debug("%s: mem_addr is %x\n dev_addr is %x\n", | ||
123 | __func__, mem_addr, dev_addr); | ||
124 | |||
125 | ret = imx_dma_setup_single(prtd->dma_ch, mem_addr, | ||
126 | dma_size, dev_addr, | ||
127 | prtd->dma_params->transfer_type); | ||
128 | if (ret < 0) { | ||
129 | printk(KERN_ERR "Error %d configuring DMA\n", ret); | ||
130 | return ret; | ||
131 | } | ||
132 | imx_dma_enable(prtd->dma_ch); | ||
133 | |||
134 | pr_debug("%s: transfer enabled\nmem_addr = %x\n", | ||
135 | __func__, (unsigned int) mem_addr); | ||
136 | pr_debug("dev_addr = %x\ndma_size = %d\n", | ||
137 | (unsigned int) dev_addr, dma_size); | ||
138 | |||
139 | prtd->tx_spin = 1; /* FGA little trick to retrieve DMA pos */ | ||
140 | prtd->period++; | ||
141 | prtd->period %= runtime->periods; | ||
142 | } | ||
143 | return ret; | ||
144 | } | ||
145 | |||
146 | |||
147 | /** | ||
148 | * This is a callback which will be called | ||
149 | * when a TX transfer finishes. The call occurs | ||
150 | * in interrupt context. | ||
151 | * | ||
152 | * @param dat pointer to the structure of the current stream. | ||
153 | * | ||
154 | */ | ||
155 | static void audio_dma_irq(int channel, void *data) | ||
156 | { | ||
157 | struct snd_pcm_substream *substream; | ||
158 | struct snd_pcm_runtime *runtime; | ||
159 | struct mx1_mx2_runtime_data *prtd; | ||
160 | unsigned int dma_size; | ||
161 | unsigned int previous_period; | ||
162 | unsigned int offset; | ||
163 | |||
164 | substream = data; | ||
165 | runtime = substream->runtime; | ||
166 | prtd = runtime->private_data; | ||
167 | previous_period = prtd->periods; | ||
168 | dma_size = frames_to_bytes(runtime, runtime->period_size); | ||
169 | offset = dma_size * previous_period; | ||
170 | |||
171 | prtd->tx_spin = 0; | ||
172 | prtd->periods++; | ||
173 | prtd->periods %= runtime->periods; | ||
174 | |||
175 | pr_debug("%s: irq per %d offset %x\n", __func__, prtd->periods, offset); | ||
176 | |||
177 | /* | ||
178 | * If we are getting a callback for an active stream then we inform | ||
179 | * the PCM middle layer we've finished a period | ||
180 | */ | ||
181 | if (prtd->active) | ||
182 | snd_pcm_period_elapsed(substream); | ||
183 | |||
184 | /* | ||
185 | * Trig next DMA transfer | ||
186 | */ | ||
187 | dma_new_period(substream); | ||
188 | } | ||
189 | |||
190 | /** | ||
191 | * This function configures the hardware to allow audio | ||
192 | * playback operations. It is called by ALSA framework. | ||
193 | * | ||
194 | * @param substream pointer to the structure of the current stream. | ||
195 | * | ||
196 | * @return 0 on success, -1 otherwise. | ||
197 | */ | ||
198 | static int | ||
199 | snd_mx1_mx2_prepare(struct snd_pcm_substream *substream) | ||
200 | { | ||
201 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
202 | struct mx1_mx2_runtime_data *prtd = runtime->private_data; | ||
203 | |||
204 | prtd->period = 0; | ||
205 | prtd->periods = 0; | ||
206 | |||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | static int mx1_mx2_pcm_hw_params(struct snd_pcm_substream *substream, | ||
211 | struct snd_pcm_hw_params *hw_params) | ||
212 | { | ||
213 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
214 | int ret; | ||
215 | |||
216 | ret = snd_pcm_lib_malloc_pages(substream, | ||
217 | params_buffer_bytes(hw_params)); | ||
218 | if (ret < 0) { | ||
219 | printk(KERN_ERR "%s: Error %d failed to malloc pcm pages \n", | ||
220 | __func__, ret); | ||
221 | return ret; | ||
222 | } | ||
223 | |||
224 | pr_debug("%s: snd_imx1_mx2_audio_hw_params runtime->dma_addr 0x(%x)\n", | ||
225 | __func__, (unsigned int)runtime->dma_addr); | ||
226 | pr_debug("%s: snd_imx1_mx2_audio_hw_params runtime->dma_area 0x(%x)\n", | ||
227 | __func__, (unsigned int)runtime->dma_area); | ||
228 | pr_debug("%s: snd_imx1_mx2_audio_hw_params runtime->dma_bytes 0x(%x)\n", | ||
229 | __func__, (unsigned int)runtime->dma_bytes); | ||
230 | |||
231 | return ret; | ||
232 | } | ||
233 | |||
234 | static int mx1_mx2_pcm_hw_free(struct snd_pcm_substream *substream) | ||
235 | { | ||
236 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
237 | struct mx1_mx2_runtime_data *prtd = runtime->private_data; | ||
238 | |||
239 | imx_dma_free(prtd->dma_ch); | ||
240 | |||
241 | snd_pcm_lib_free_pages(substream); | ||
242 | |||
243 | return 0; | ||
244 | } | ||
245 | |||
246 | static int mx1_mx2_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | ||
247 | { | ||
248 | struct mx1_mx2_runtime_data *prtd = substream->runtime->private_data; | ||
249 | int ret = 0; | ||
250 | |||
251 | switch (cmd) { | ||
252 | case SNDRV_PCM_TRIGGER_START: | ||
253 | prtd->tx_spin = 0; | ||
254 | /* requested stream startup */ | ||
255 | prtd->active = 1; | ||
256 | pr_debug("%s: starting dma_new_period\n", __func__); | ||
257 | ret = dma_new_period(substream); | ||
258 | break; | ||
259 | case SNDRV_PCM_TRIGGER_STOP: | ||
260 | /* requested stream shutdown */ | ||
261 | pr_debug("%s: stopping dma transfer\n", __func__); | ||
262 | ret = audio_stop_dma(substream); | ||
263 | break; | ||
264 | default: | ||
265 | ret = -EINVAL; | ||
266 | break; | ||
267 | } | ||
268 | |||
269 | return ret; | ||
270 | } | ||
271 | |||
272 | static snd_pcm_uframes_t | ||
273 | mx1_mx2_pcm_pointer(struct snd_pcm_substream *substream) | ||
274 | { | ||
275 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
276 | struct mx1_mx2_runtime_data *prtd = runtime->private_data; | ||
277 | unsigned int offset = 0; | ||
278 | |||
279 | /* tx_spin value is used here to check if a transfer is active */ | ||
280 | if (prtd->tx_spin) { | ||
281 | offset = (runtime->period_size * (prtd->periods)) + | ||
282 | (runtime->period_size >> 1); | ||
283 | if (offset >= runtime->buffer_size) | ||
284 | offset = runtime->period_size >> 1; | ||
285 | } else { | ||
286 | offset = (runtime->period_size * (prtd->periods)); | ||
287 | if (offset >= runtime->buffer_size) | ||
288 | offset = 0; | ||
289 | } | ||
290 | pr_debug("%s: pointer offset %x\n", __func__, offset); | ||
291 | |||
292 | return offset; | ||
293 | } | ||
294 | |||
295 | static int mx1_mx2_pcm_open(struct snd_pcm_substream *substream) | ||
296 | { | ||
297 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
298 | struct mx1_mx2_runtime_data *prtd; | ||
299 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
300 | struct mx1_mx2_pcm_dma_params *dma_data = rtd->dai->cpu_dai->dma_data; | ||
301 | int ret; | ||
302 | |||
303 | snd_soc_set_runtime_hwparams(substream, &mx1_mx2_pcm_hardware); | ||
304 | |||
305 | ret = snd_pcm_hw_constraint_integer(runtime, | ||
306 | SNDRV_PCM_HW_PARAM_PERIODS); | ||
307 | if (ret < 0) | ||
308 | return ret; | ||
309 | |||
310 | prtd = kzalloc(sizeof(struct mx1_mx2_runtime_data), GFP_KERNEL); | ||
311 | if (prtd == NULL) { | ||
312 | ret = -ENOMEM; | ||
313 | goto out; | ||
314 | } | ||
315 | |||
316 | runtime->private_data = prtd; | ||
317 | |||
318 | if (!dma_data) | ||
319 | return -ENODEV; | ||
320 | |||
321 | prtd->dma_params = dma_data; | ||
322 | |||
323 | pr_debug("%s: Requesting dma channel (%s)\n", __func__, | ||
324 | prtd->dma_params->name); | ||
325 | ret = imx_dma_request_by_prio(prtd->dma_params->name, DMA_PRIO_HIGH); | ||
326 | if (ret < 0) { | ||
327 | printk(KERN_ERR "Error %d requesting dma channel\n", ret); | ||
328 | return ret; | ||
329 | } | ||
330 | prtd->dma_ch = ret; | ||
331 | imx_dma_config_burstlen(prtd->dma_ch, | ||
332 | prtd->dma_params->watermark_level); | ||
333 | |||
334 | ret = imx_dma_config_channel(prtd->dma_ch, | ||
335 | prtd->dma_params->per_config, | ||
336 | prtd->dma_params->mem_config, | ||
337 | prtd->dma_params->event_id, 0); | ||
338 | |||
339 | if (ret) { | ||
340 | pr_debug(KERN_ERR "Error %d configuring dma channel %d\n", | ||
341 | ret, prtd->dma_ch); | ||
342 | return ret; | ||
343 | } | ||
344 | |||
345 | pr_debug("%s: Setting tx dma callback function\n", __func__); | ||
346 | ret = imx_dma_setup_handlers(prtd->dma_ch, | ||
347 | audio_dma_irq, NULL, | ||
348 | (void *)substream); | ||
349 | if (ret < 0) { | ||
350 | printk(KERN_ERR "Error %d setting dma callback function\n", ret); | ||
351 | return ret; | ||
352 | } | ||
353 | return 0; | ||
354 | |||
355 | out: | ||
356 | return ret; | ||
357 | } | ||
358 | |||
359 | static int mx1_mx2_pcm_close(struct snd_pcm_substream *substream) | ||
360 | { | ||
361 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
362 | struct mx1_mx2_runtime_data *prtd = runtime->private_data; | ||
363 | |||
364 | kfree(prtd); | ||
365 | |||
366 | return 0; | ||
367 | } | ||
368 | |||
369 | static int mx1_mx2_pcm_mmap(struct snd_pcm_substream *substream, | ||
370 | struct vm_area_struct *vma) | ||
371 | { | ||
372 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
373 | return dma_mmap_writecombine(substream->pcm->card->dev, vma, | ||
374 | runtime->dma_area, | ||
375 | runtime->dma_addr, | ||
376 | runtime->dma_bytes); | ||
377 | } | ||
378 | |||
379 | static struct snd_pcm_ops mx1_mx2_pcm_ops = { | ||
380 | .open = mx1_mx2_pcm_open, | ||
381 | .close = mx1_mx2_pcm_close, | ||
382 | .ioctl = snd_pcm_lib_ioctl, | ||
383 | .hw_params = mx1_mx2_pcm_hw_params, | ||
384 | .hw_free = mx1_mx2_pcm_hw_free, | ||
385 | .prepare = snd_mx1_mx2_prepare, | ||
386 | .trigger = mx1_mx2_pcm_trigger, | ||
387 | .pointer = mx1_mx2_pcm_pointer, | ||
388 | .mmap = mx1_mx2_pcm_mmap, | ||
389 | }; | ||
390 | |||
391 | static u64 mx1_mx2_pcm_dmamask = 0xffffffff; | ||
392 | |||
393 | static int mx1_mx2_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) | ||
394 | { | ||
395 | struct snd_pcm_substream *substream = pcm->streams[stream].substream; | ||
396 | struct snd_dma_buffer *buf = &substream->dma_buffer; | ||
397 | size_t size = mx1_mx2_pcm_hardware.buffer_bytes_max; | ||
398 | buf->dev.type = SNDRV_DMA_TYPE_DEV; | ||
399 | buf->dev.dev = pcm->card->dev; | ||
400 | buf->private_data = NULL; | ||
401 | |||
402 | /* Reserve uncached-buffered memory area for DMA */ | ||
403 | buf->area = dma_alloc_writecombine(pcm->card->dev, size, | ||
404 | &buf->addr, GFP_KERNEL); | ||
405 | |||
406 | pr_debug("%s: preallocate_dma_buffer: area=%p, addr=%p, size=%d\n", | ||
407 | __func__, (void *) buf->area, (void *) buf->addr, size); | ||
408 | |||
409 | if (!buf->area) | ||
410 | return -ENOMEM; | ||
411 | |||
412 | buf->bytes = size; | ||
413 | return 0; | ||
414 | } | ||
415 | |||
416 | static void mx1_mx2_pcm_free_dma_buffers(struct snd_pcm *pcm) | ||
417 | { | ||
418 | struct snd_pcm_substream *substream; | ||
419 | struct snd_dma_buffer *buf; | ||
420 | int stream; | ||
421 | |||
422 | for (stream = 0; stream < 2; stream++) { | ||
423 | substream = pcm->streams[stream].substream; | ||
424 | if (!substream) | ||
425 | continue; | ||
426 | |||
427 | buf = &substream->dma_buffer; | ||
428 | if (!buf->area) | ||
429 | continue; | ||
430 | |||
431 | dma_free_writecombine(pcm->card->dev, buf->bytes, | ||
432 | buf->area, buf->addr); | ||
433 | buf->area = NULL; | ||
434 | } | ||
435 | } | ||
436 | |||
437 | static int mx1_mx2_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, | ||
438 | struct snd_pcm *pcm) | ||
439 | { | ||
440 | int ret = 0; | ||
441 | |||
442 | if (!card->dev->dma_mask) | ||
443 | card->dev->dma_mask = &mx1_mx2_pcm_dmamask; | ||
444 | if (!card->dev->coherent_dma_mask) | ||
445 | card->dev->coherent_dma_mask = 0xffffffff; | ||
446 | |||
447 | if (dai->playback.channels_min) { | ||
448 | ret = mx1_mx2_pcm_preallocate_dma_buffer(pcm, | ||
449 | SNDRV_PCM_STREAM_PLAYBACK); | ||
450 | pr_debug("%s: preallocate playback buffer\n", __func__); | ||
451 | if (ret) | ||
452 | goto out; | ||
453 | } | ||
454 | |||
455 | if (dai->capture.channels_min) { | ||
456 | ret = mx1_mx2_pcm_preallocate_dma_buffer(pcm, | ||
457 | SNDRV_PCM_STREAM_CAPTURE); | ||
458 | pr_debug("%s: preallocate capture buffer\n", __func__); | ||
459 | if (ret) | ||
460 | goto out; | ||
461 | } | ||
462 | out: | ||
463 | return ret; | ||
464 | } | ||
465 | |||
466 | struct snd_soc_platform mx1_mx2_soc_platform = { | ||
467 | .name = "mx1_mx2-audio", | ||
468 | .pcm_ops = &mx1_mx2_pcm_ops, | ||
469 | .pcm_new = mx1_mx2_pcm_new, | ||
470 | .pcm_free = mx1_mx2_pcm_free_dma_buffers, | ||
471 | }; | ||
472 | EXPORT_SYMBOL_GPL(mx1_mx2_soc_platform); | ||
473 | |||
474 | static int __init mx1_mx2_soc_platform_init(void) | ||
475 | { | ||
476 | return snd_soc_register_platform(&mx1_mx2_soc_platform); | ||
477 | } | ||
478 | module_init(mx1_mx2_soc_platform_init); | ||
479 | |||
480 | static void __exit mx1_mx2_soc_platform_exit(void) | ||
481 | { | ||
482 | snd_soc_unregister_platform(&mx1_mx2_soc_platform); | ||
483 | } | ||
484 | module_exit(mx1_mx2_soc_platform_exit); | ||
485 | |||
486 | MODULE_AUTHOR("Javier Martin, javier.martin@vista-silicon.com"); | ||
487 | MODULE_DESCRIPTION("Freescale i.MX2x, i.MX1x PCM DMA module"); | ||
488 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/imx/mx1_mx2-pcm.h b/sound/soc/imx/mx1_mx2-pcm.h deleted file mode 100644 index 2e528106570b..000000000000 --- a/sound/soc/imx/mx1_mx2-pcm.h +++ /dev/null | |||
@@ -1,26 +0,0 @@ | |||
1 | /* | ||
2 | * mx1_mx2-pcm.h :- ASoC platform header for Freescale i.MX1x, i.MX2x | ||
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 _MX1_MX2_PCM_H | ||
10 | #define _MX1_MX2_PCM_H | ||
11 | |||
12 | /* DMA information for mx1_mx2 platforms */ | ||
13 | struct mx1_mx2_pcm_dma_params { | ||
14 | char *name; /* stream identifier */ | ||
15 | unsigned int transfer_type; /* READ or WRITE DMA transfer */ | ||
16 | dma_addr_t per_address; /* physical address of SSI fifo */ | ||
17 | int event_id; /* fixed DMA number for SSI fifo */ | ||
18 | int watermark_level; /* SSI fifo watermark level */ | ||
19 | int per_config; /* DMA Config flags for peripheral */ | ||
20 | int mem_config; /* DMA Config flags for RAM */ | ||
21 | }; | ||
22 | |||
23 | /* platform data */ | ||
24 | extern struct snd_soc_platform mx1_mx2_soc_platform; | ||
25 | |||
26 | #endif | ||
diff --git a/sound/soc/imx/mx27vis_wm8974.c b/sound/soc/imx/mx27vis_wm8974.c deleted file mode 100644 index 07d2a248438c..000000000000 --- a/sound/soc/imx/mx27vis_wm8974.c +++ /dev/null | |||
@@ -1,318 +0,0 @@ | |||
1 | /* | ||
2 | * mx27vis_wm8974.c -- SoC audio for mx27vis | ||
3 | * | ||
4 | * Copyright 2009 Vista Silicon S.L. | ||
5 | * Author: Javier Martin | ||
6 | * javier.martin@vista-silicon.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 | */ | ||
14 | |||
15 | #include <linux/module.h> | ||
16 | #include <linux/moduleparam.h> | ||
17 | #include <linux/device.h> | ||
18 | #include <linux/i2c.h> | ||
19 | #include <sound/core.h> | ||
20 | #include <sound/pcm.h> | ||
21 | #include <sound/soc.h> | ||
22 | #include <sound/soc-dapm.h> | ||
23 | |||
24 | |||
25 | #include "../codecs/wm8974.h" | ||
26 | #include "mx1_mx2-pcm.h" | ||
27 | #include "mxc-ssi.h" | ||
28 | #include <mach/gpio.h> | ||
29 | #include <mach/iomux.h> | ||
30 | |||
31 | #define IGNORED_ARG 0 | ||
32 | |||
33 | |||
34 | static struct snd_soc_card mx27vis; | ||
35 | |||
36 | /** | ||
37 | * This function connects SSI1 (HPCR1) as slave to | ||
38 | * SSI1 external signals (PPCR1) | ||
39 | * As slave, HPCR1 must set TFSDIR and TCLKDIR as inputs from | ||
40 | * port 4 | ||
41 | */ | ||
42 | void audmux_connect_1_4(void) | ||
43 | { | ||
44 | pr_debug("AUDMUX: normal operation mode\n"); | ||
45 | /* Reset HPCR1 and PPCR1 */ | ||
46 | |||
47 | DAM_HPCR1 = 0x00000000; | ||
48 | DAM_PPCR1 = 0x00000000; | ||
49 | |||
50 | /* set to synchronous */ | ||
51 | DAM_HPCR1 |= AUDMUX_HPCR_SYN; | ||
52 | DAM_PPCR1 |= AUDMUX_PPCR_SYN; | ||
53 | |||
54 | |||
55 | /* set Rx sources 1 <--> 4 */ | ||
56 | DAM_HPCR1 |= AUDMUX_HPCR_RXDSEL(3); /* port 4 */ | ||
57 | DAM_PPCR1 |= AUDMUX_PPCR_RXDSEL(0); /* port 1 */ | ||
58 | |||
59 | /* set Tx frame and Clock direction and source 4 --> 1 output */ | ||
60 | DAM_HPCR1 |= AUDMUX_HPCR_TFSDIR | AUDMUX_HPCR_TCLKDIR; | ||
61 | DAM_HPCR1 |= AUDMUX_HPCR_TFCSEL(3); /* TxDS and TxCclk from port 4 */ | ||
62 | |||
63 | return; | ||
64 | } | ||
65 | |||
66 | static int mx27vis_hifi_hw_params(struct snd_pcm_substream *substream, | ||
67 | struct snd_pcm_hw_params *params) | ||
68 | { | ||
69 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
70 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; | ||
71 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | ||
72 | unsigned int pll_out = 0, bclk = 0, fmt = 0, mclk = 0; | ||
73 | int ret = 0; | ||
74 | |||
75 | /* | ||
76 | * The WM8974 is better at generating accurate audio clocks than the | ||
77 | * MX27 SSI controller, so we will use it as master when we can. | ||
78 | */ | ||
79 | switch (params_rate(params)) { | ||
80 | case 8000: | ||
81 | fmt = SND_SOC_DAIFMT_CBM_CFM; | ||
82 | mclk = WM8974_MCLKDIV_12; | ||
83 | pll_out = 24576000; | ||
84 | break; | ||
85 | case 16000: | ||
86 | fmt = SND_SOC_DAIFMT_CBM_CFM; | ||
87 | pll_out = 12288000; | ||
88 | break; | ||
89 | case 48000: | ||
90 | fmt = SND_SOC_DAIFMT_CBM_CFM; | ||
91 | bclk = WM8974_BCLKDIV_4; | ||
92 | pll_out = 12288000; | ||
93 | break; | ||
94 | case 96000: | ||
95 | fmt = SND_SOC_DAIFMT_CBM_CFM; | ||
96 | bclk = WM8974_BCLKDIV_2; | ||
97 | pll_out = 12288000; | ||
98 | break; | ||
99 | case 11025: | ||
100 | fmt = SND_SOC_DAIFMT_CBM_CFM; | ||
101 | bclk = WM8974_BCLKDIV_16; | ||
102 | pll_out = 11289600; | ||
103 | break; | ||
104 | case 22050: | ||
105 | fmt = SND_SOC_DAIFMT_CBM_CFM; | ||
106 | bclk = WM8974_BCLKDIV_8; | ||
107 | pll_out = 11289600; | ||
108 | break; | ||
109 | case 44100: | ||
110 | fmt = SND_SOC_DAIFMT_CBM_CFM; | ||
111 | bclk = WM8974_BCLKDIV_4; | ||
112 | mclk = WM8974_MCLKDIV_2; | ||
113 | pll_out = 11289600; | ||
114 | break; | ||
115 | case 88200: | ||
116 | fmt = SND_SOC_DAIFMT_CBM_CFM; | ||
117 | bclk = WM8974_BCLKDIV_2; | ||
118 | pll_out = 11289600; | ||
119 | break; | ||
120 | } | ||
121 | |||
122 | /* set codec DAI configuration */ | ||
123 | ret = codec_dai->ops->set_fmt(codec_dai, | ||
124 | SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_IF | | ||
125 | SND_SOC_DAIFMT_SYNC | fmt); | ||
126 | if (ret < 0) { | ||
127 | printk(KERN_ERR "Error from codec DAI configuration\n"); | ||
128 | return ret; | ||
129 | } | ||
130 | |||
131 | /* set cpu DAI configuration */ | ||
132 | ret = cpu_dai->ops->set_fmt(cpu_dai, | ||
133 | SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | | ||
134 | SND_SOC_DAIFMT_SYNC | fmt); | ||
135 | if (ret < 0) { | ||
136 | printk(KERN_ERR "Error from cpu DAI configuration\n"); | ||
137 | return ret; | ||
138 | } | ||
139 | |||
140 | /* Put DC field of STCCR to 1 (not zero) */ | ||
141 | ret = cpu_dai->ops->set_tdm_slot(cpu_dai, 0, 2); | ||
142 | |||
143 | /* set the SSI system clock as input */ | ||
144 | ret = cpu_dai->ops->set_sysclk(cpu_dai, IMX_SSP_SYS_CLK, 0, | ||
145 | SND_SOC_CLOCK_IN); | ||
146 | if (ret < 0) { | ||
147 | printk(KERN_ERR "Error when setting system SSI clk\n"); | ||
148 | return ret; | ||
149 | } | ||
150 | |||
151 | /* set codec BCLK division for sample rate */ | ||
152 | ret = codec_dai->ops->set_clkdiv(codec_dai, WM8974_BCLKDIV, bclk); | ||
153 | if (ret < 0) { | ||
154 | printk(KERN_ERR "Error when setting BCLK division\n"); | ||
155 | return ret; | ||
156 | } | ||
157 | |||
158 | |||
159 | /* codec PLL input is 25 MHz */ | ||
160 | ret = codec_dai->ops->set_pll(codec_dai, IGNORED_ARG, IGNORED_ARG, | ||
161 | 25000000, pll_out); | ||
162 | if (ret < 0) { | ||
163 | printk(KERN_ERR "Error when setting PLL input\n"); | ||
164 | return ret; | ||
165 | } | ||
166 | |||
167 | /*set codec MCLK division for sample rate */ | ||
168 | ret = codec_dai->ops->set_clkdiv(codec_dai, WM8974_MCLKDIV, mclk); | ||
169 | if (ret < 0) { | ||
170 | printk(KERN_ERR "Error when setting MCLK division\n"); | ||
171 | return ret; | ||
172 | } | ||
173 | |||
174 | return 0; | ||
175 | } | ||
176 | |||
177 | static int mx27vis_hifi_hw_free(struct snd_pcm_substream *substream) | ||
178 | { | ||
179 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
180 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; | ||
181 | |||
182 | /* disable the PLL */ | ||
183 | return codec_dai->ops->set_pll(codec_dai, IGNORED_ARG, IGNORED_ARG, | ||
184 | 0, 0); | ||
185 | } | ||
186 | |||
187 | /* | ||
188 | * mx27vis WM8974 HiFi DAI opserations. | ||
189 | */ | ||
190 | static struct snd_soc_ops mx27vis_hifi_ops = { | ||
191 | .hw_params = mx27vis_hifi_hw_params, | ||
192 | .hw_free = mx27vis_hifi_hw_free, | ||
193 | }; | ||
194 | |||
195 | |||
196 | static int mx27vis_suspend(struct platform_device *pdev, pm_message_t state) | ||
197 | { | ||
198 | return 0; | ||
199 | } | ||
200 | |||
201 | static int mx27vis_resume(struct platform_device *pdev) | ||
202 | { | ||
203 | return 0; | ||
204 | } | ||
205 | |||
206 | static int mx27vis_probe(struct platform_device *pdev) | ||
207 | { | ||
208 | int ret = 0; | ||
209 | |||
210 | ret = get_ssi_clk(0, &pdev->dev); | ||
211 | |||
212 | if (ret < 0) { | ||
213 | printk(KERN_ERR "%s: cant get ssi clock\n", __func__); | ||
214 | return ret; | ||
215 | } | ||
216 | |||
217 | |||
218 | return 0; | ||
219 | } | ||
220 | |||
221 | static int mx27vis_remove(struct platform_device *pdev) | ||
222 | { | ||
223 | put_ssi_clk(0); | ||
224 | return 0; | ||
225 | } | ||
226 | |||
227 | static struct snd_soc_dai_link mx27vis_dai[] = { | ||
228 | { /* Hifi Playback*/ | ||
229 | .name = "WM8974", | ||
230 | .stream_name = "WM8974 HiFi", | ||
231 | .cpu_dai = &imx_ssi_pcm_dai[0], | ||
232 | .codec_dai = &wm8974_dai, | ||
233 | .ops = &mx27vis_hifi_ops, | ||
234 | }, | ||
235 | }; | ||
236 | |||
237 | static struct snd_soc_card mx27vis = { | ||
238 | .name = "mx27vis", | ||
239 | .platform = &mx1_mx2_soc_platform, | ||
240 | .probe = mx27vis_probe, | ||
241 | .remove = mx27vis_remove, | ||
242 | .suspend_pre = mx27vis_suspend, | ||
243 | .resume_post = mx27vis_resume, | ||
244 | .dai_link = mx27vis_dai, | ||
245 | .num_links = ARRAY_SIZE(mx27vis_dai), | ||
246 | }; | ||
247 | |||
248 | static struct snd_soc_device mx27vis_snd_devdata = { | ||
249 | .card = &mx27vis, | ||
250 | .codec_dev = &soc_codec_dev_wm8974, | ||
251 | }; | ||
252 | |||
253 | static struct platform_device *mx27vis_snd_device; | ||
254 | |||
255 | /* Temporal definition of board specific behaviour */ | ||
256 | void gpio_ssi_active(int ssi_num) | ||
257 | { | ||
258 | int ret = 0; | ||
259 | |||
260 | unsigned int ssi1_pins[] = { | ||
261 | PC20_PF_SSI1_FS, | ||
262 | PC21_PF_SSI1_RXD, | ||
263 | PC22_PF_SSI1_TXD, | ||
264 | PC23_PF_SSI1_CLK, | ||
265 | }; | ||
266 | unsigned int ssi2_pins[] = { | ||
267 | PC24_PF_SSI2_FS, | ||
268 | PC25_PF_SSI2_RXD, | ||
269 | PC26_PF_SSI2_TXD, | ||
270 | PC27_PF_SSI2_CLK, | ||
271 | }; | ||
272 | if (ssi_num == 0) | ||
273 | ret = mxc_gpio_setup_multiple_pins(ssi1_pins, | ||
274 | ARRAY_SIZE(ssi1_pins), "USB OTG"); | ||
275 | else | ||
276 | ret = mxc_gpio_setup_multiple_pins(ssi2_pins, | ||
277 | ARRAY_SIZE(ssi2_pins), "USB OTG"); | ||
278 | if (ret) | ||
279 | printk(KERN_ERR "Error requesting ssi %x pins\n", ssi_num); | ||
280 | } | ||
281 | |||
282 | |||
283 | static int __init mx27vis_init(void) | ||
284 | { | ||
285 | int ret; | ||
286 | |||
287 | mx27vis_snd_device = platform_device_alloc("soc-audio", -1); | ||
288 | if (!mx27vis_snd_device) | ||
289 | return -ENOMEM; | ||
290 | |||
291 | platform_set_drvdata(mx27vis_snd_device, &mx27vis_snd_devdata); | ||
292 | mx27vis_snd_devdata.dev = &mx27vis_snd_device->dev; | ||
293 | ret = platform_device_add(mx27vis_snd_device); | ||
294 | |||
295 | if (ret) { | ||
296 | printk(KERN_ERR "ASoC: Platform device allocation failed\n"); | ||
297 | platform_device_put(mx27vis_snd_device); | ||
298 | } | ||
299 | |||
300 | /* WM8974 uses SSI1 (HPCR1) via AUDMUX port 4 for audio (PPCR1) */ | ||
301 | gpio_ssi_active(0); | ||
302 | audmux_connect_1_4(); | ||
303 | |||
304 | return ret; | ||
305 | } | ||
306 | |||
307 | static void __exit mx27vis_exit(void) | ||
308 | { | ||
309 | /* We should call some "ssi_gpio_inactive()" properly */ | ||
310 | } | ||
311 | |||
312 | module_init(mx27vis_init); | ||
313 | module_exit(mx27vis_exit); | ||
314 | |||
315 | |||
316 | MODULE_AUTHOR("Javier Martin, javier.martin@vista-silicon.com"); | ||
317 | MODULE_DESCRIPTION("ALSA SoC WM8974 mx27vis"); | ||
318 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/imx/mxc-ssi.c b/sound/soc/imx/mxc-ssi.c deleted file mode 100644 index ccdefe60e752..000000000000 --- a/sound/soc/imx/mxc-ssi.c +++ /dev/null | |||
@@ -1,860 +0,0 @@ | |||
1 | /* | ||
2 | * mxc-ssi.c -- SSI driver for Freescale IMX | ||
3 | * | ||
4 | * Copyright 2006 Wolfson Microelectronics PLC. | ||
5 | * Author: Liam Girdwood | ||
6 | * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com | ||
7 | * | ||
8 | * Based on mxc-alsa-mc13783 (C) 2006 Freescale. | ||
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 | * TODO: | ||
16 | * Need to rework SSI register defs when new defs go into mainline. | ||
17 | * Add support for TDM and FIFO 1. | ||
18 | * Add support for i.mx3x DMA interface. | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/platform_device.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <linux/dma-mapping.h> | ||
28 | #include <linux/clk.h> | ||
29 | #include <sound/core.h> | ||
30 | #include <sound/pcm.h> | ||
31 | #include <sound/pcm_params.h> | ||
32 | #include <sound/soc.h> | ||
33 | #include <mach/dma-mx1-mx2.h> | ||
34 | #include <asm/mach-types.h> | ||
35 | |||
36 | #include "mxc-ssi.h" | ||
37 | #include "mx1_mx2-pcm.h" | ||
38 | |||
39 | #define SSI1_PORT 0 | ||
40 | #define SSI2_PORT 1 | ||
41 | |||
42 | static int ssi_active[2] = {0, 0}; | ||
43 | |||
44 | /* DMA information for mx1_mx2 platforms */ | ||
45 | static struct mx1_mx2_pcm_dma_params imx_ssi1_pcm_stereo_out0 = { | ||
46 | .name = "SSI1 PCM Stereo out 0", | ||
47 | .transfer_type = DMA_MODE_WRITE, | ||
48 | .per_address = SSI1_BASE_ADDR + STX0, | ||
49 | .event_id = DMA_REQ_SSI1_TX0, | ||
50 | .watermark_level = TXFIFO_WATERMARK, | ||
51 | .per_config = IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO, | ||
52 | .mem_config = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR, | ||
53 | }; | ||
54 | |||
55 | static struct mx1_mx2_pcm_dma_params imx_ssi1_pcm_stereo_out1 = { | ||
56 | .name = "SSI1 PCM Stereo out 1", | ||
57 | .transfer_type = DMA_MODE_WRITE, | ||
58 | .per_address = SSI1_BASE_ADDR + STX1, | ||
59 | .event_id = DMA_REQ_SSI1_TX1, | ||
60 | .watermark_level = TXFIFO_WATERMARK, | ||
61 | .per_config = IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO, | ||
62 | .mem_config = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR, | ||
63 | }; | ||
64 | |||
65 | static struct mx1_mx2_pcm_dma_params imx_ssi1_pcm_stereo_in0 = { | ||
66 | .name = "SSI1 PCM Stereo in 0", | ||
67 | .transfer_type = DMA_MODE_READ, | ||
68 | .per_address = SSI1_BASE_ADDR + SRX0, | ||
69 | .event_id = DMA_REQ_SSI1_RX0, | ||
70 | .watermark_level = RXFIFO_WATERMARK, | ||
71 | .per_config = IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO, | ||
72 | .mem_config = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR, | ||
73 | }; | ||
74 | |||
75 | static struct mx1_mx2_pcm_dma_params imx_ssi1_pcm_stereo_in1 = { | ||
76 | .name = "SSI1 PCM Stereo in 1", | ||
77 | .transfer_type = DMA_MODE_READ, | ||
78 | .per_address = SSI1_BASE_ADDR + SRX1, | ||
79 | .event_id = DMA_REQ_SSI1_RX1, | ||
80 | .watermark_level = RXFIFO_WATERMARK, | ||
81 | .per_config = IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO, | ||
82 | .mem_config = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR, | ||
83 | }; | ||
84 | |||
85 | static struct mx1_mx2_pcm_dma_params imx_ssi2_pcm_stereo_out0 = { | ||
86 | .name = "SSI2 PCM Stereo out 0", | ||
87 | .transfer_type = DMA_MODE_WRITE, | ||
88 | .per_address = SSI2_BASE_ADDR + STX0, | ||
89 | .event_id = DMA_REQ_SSI2_TX0, | ||
90 | .watermark_level = TXFIFO_WATERMARK, | ||
91 | .per_config = IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO, | ||
92 | .mem_config = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR, | ||
93 | }; | ||
94 | |||
95 | static struct mx1_mx2_pcm_dma_params imx_ssi2_pcm_stereo_out1 = { | ||
96 | .name = "SSI2 PCM Stereo out 1", | ||
97 | .transfer_type = DMA_MODE_WRITE, | ||
98 | .per_address = SSI2_BASE_ADDR + STX1, | ||
99 | .event_id = DMA_REQ_SSI2_TX1, | ||
100 | .watermark_level = TXFIFO_WATERMARK, | ||
101 | .per_config = IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO, | ||
102 | .mem_config = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR, | ||
103 | }; | ||
104 | |||
105 | static struct mx1_mx2_pcm_dma_params imx_ssi2_pcm_stereo_in0 = { | ||
106 | .name = "SSI2 PCM Stereo in 0", | ||
107 | .transfer_type = DMA_MODE_READ, | ||
108 | .per_address = SSI2_BASE_ADDR + SRX0, | ||
109 | .event_id = DMA_REQ_SSI2_RX0, | ||
110 | .watermark_level = RXFIFO_WATERMARK, | ||
111 | .per_config = IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO, | ||
112 | .mem_config = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR, | ||
113 | }; | ||
114 | |||
115 | static struct mx1_mx2_pcm_dma_params imx_ssi2_pcm_stereo_in1 = { | ||
116 | .name = "SSI2 PCM Stereo in 1", | ||
117 | .transfer_type = DMA_MODE_READ, | ||
118 | .per_address = SSI2_BASE_ADDR + SRX1, | ||
119 | .event_id = DMA_REQ_SSI2_RX1, | ||
120 | .watermark_level = RXFIFO_WATERMARK, | ||
121 | .per_config = IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO, | ||
122 | .mem_config = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR, | ||
123 | }; | ||
124 | |||
125 | static struct clk *ssi_clk0, *ssi_clk1; | ||
126 | |||
127 | int get_ssi_clk(int ssi, struct device *dev) | ||
128 | { | ||
129 | switch (ssi) { | ||
130 | case 0: | ||
131 | ssi_clk0 = clk_get(dev, "ssi1"); | ||
132 | if (IS_ERR(ssi_clk0)) | ||
133 | return PTR_ERR(ssi_clk0); | ||
134 | return 0; | ||
135 | case 1: | ||
136 | ssi_clk1 = clk_get(dev, "ssi2"); | ||
137 | if (IS_ERR(ssi_clk1)) | ||
138 | return PTR_ERR(ssi_clk1); | ||
139 | return 0; | ||
140 | default: | ||
141 | return -EINVAL; | ||
142 | } | ||
143 | } | ||
144 | EXPORT_SYMBOL(get_ssi_clk); | ||
145 | |||
146 | void put_ssi_clk(int ssi) | ||
147 | { | ||
148 | switch (ssi) { | ||
149 | case 0: | ||
150 | clk_put(ssi_clk0); | ||
151 | ssi_clk0 = NULL; | ||
152 | break; | ||
153 | case 1: | ||
154 | clk_put(ssi_clk1); | ||
155 | ssi_clk1 = NULL; | ||
156 | break; | ||
157 | } | ||
158 | } | ||
159 | EXPORT_SYMBOL(put_ssi_clk); | ||
160 | |||
161 | /* | ||
162 | * SSI system clock configuration. | ||
163 | * Should only be called when port is inactive (i.e. SSIEN = 0). | ||
164 | */ | ||
165 | static int imx_ssi_set_dai_sysclk(struct snd_soc_dai *cpu_dai, | ||
166 | int clk_id, unsigned int freq, int dir) | ||
167 | { | ||
168 | u32 scr; | ||
169 | |||
170 | if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) { | ||
171 | scr = SSI1_SCR; | ||
172 | pr_debug("%s: SCR for SSI1 is %x\n", __func__, scr); | ||
173 | } else { | ||
174 | scr = SSI2_SCR; | ||
175 | pr_debug("%s: SCR for SSI2 is %x\n", __func__, scr); | ||
176 | } | ||
177 | |||
178 | if (scr & SSI_SCR_SSIEN) { | ||
179 | printk(KERN_WARNING "Warning ssi already enabled\n"); | ||
180 | return 0; | ||
181 | } | ||
182 | |||
183 | switch (clk_id) { | ||
184 | case IMX_SSP_SYS_CLK: | ||
185 | if (dir == SND_SOC_CLOCK_OUT) { | ||
186 | scr |= SSI_SCR_SYS_CLK_EN; | ||
187 | pr_debug("%s: clk of is output\n", __func__); | ||
188 | } else { | ||
189 | scr &= ~SSI_SCR_SYS_CLK_EN; | ||
190 | pr_debug("%s: clk of is input\n", __func__); | ||
191 | } | ||
192 | break; | ||
193 | default: | ||
194 | return -EINVAL; | ||
195 | } | ||
196 | |||
197 | if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) { | ||
198 | pr_debug("%s: writeback of SSI1_SCR\n", __func__); | ||
199 | SSI1_SCR = scr; | ||
200 | } else { | ||
201 | pr_debug("%s: writeback of SSI2_SCR\n", __func__); | ||
202 | SSI2_SCR = scr; | ||
203 | } | ||
204 | |||
205 | return 0; | ||
206 | } | ||
207 | |||
208 | /* | ||
209 | * SSI Clock dividers | ||
210 | * Should only be called when port is inactive (i.e. SSIEN = 0). | ||
211 | */ | ||
212 | static int imx_ssi_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, | ||
213 | int div_id, int div) | ||
214 | { | ||
215 | u32 stccr, srccr; | ||
216 | |||
217 | pr_debug("%s\n", __func__); | ||
218 | if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) { | ||
219 | if (SSI1_SCR & SSI_SCR_SSIEN) | ||
220 | return 0; | ||
221 | srccr = SSI1_STCCR; | ||
222 | stccr = SSI1_STCCR; | ||
223 | } else { | ||
224 | if (SSI2_SCR & SSI_SCR_SSIEN) | ||
225 | return 0; | ||
226 | srccr = SSI2_STCCR; | ||
227 | stccr = SSI2_STCCR; | ||
228 | } | ||
229 | |||
230 | switch (div_id) { | ||
231 | case IMX_SSI_TX_DIV_2: | ||
232 | stccr &= ~SSI_STCCR_DIV2; | ||
233 | stccr |= div; | ||
234 | break; | ||
235 | case IMX_SSI_TX_DIV_PSR: | ||
236 | stccr &= ~SSI_STCCR_PSR; | ||
237 | stccr |= div; | ||
238 | break; | ||
239 | case IMX_SSI_TX_DIV_PM: | ||
240 | stccr &= ~0xff; | ||
241 | stccr |= SSI_STCCR_PM(div); | ||
242 | break; | ||
243 | case IMX_SSI_RX_DIV_2: | ||
244 | stccr &= ~SSI_STCCR_DIV2; | ||
245 | stccr |= div; | ||
246 | break; | ||
247 | case IMX_SSI_RX_DIV_PSR: | ||
248 | stccr &= ~SSI_STCCR_PSR; | ||
249 | stccr |= div; | ||
250 | break; | ||
251 | case IMX_SSI_RX_DIV_PM: | ||
252 | stccr &= ~0xff; | ||
253 | stccr |= SSI_STCCR_PM(div); | ||
254 | break; | ||
255 | default: | ||
256 | return -EINVAL; | ||
257 | } | ||
258 | |||
259 | if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) { | ||
260 | SSI1_STCCR = stccr; | ||
261 | SSI1_SRCCR = srccr; | ||
262 | } else { | ||
263 | SSI2_STCCR = stccr; | ||
264 | SSI2_SRCCR = srccr; | ||
265 | } | ||
266 | return 0; | ||
267 | } | ||
268 | |||
269 | /* | ||
270 | * SSI Network Mode or TDM slots configuration. | ||
271 | * Should only be called when port is inactive (i.e. SSIEN = 0). | ||
272 | */ | ||
273 | static int imx_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, | ||
274 | unsigned int mask, int slots) | ||
275 | { | ||
276 | u32 stmsk, srmsk, stccr; | ||
277 | |||
278 | if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) { | ||
279 | if (SSI1_SCR & SSI_SCR_SSIEN) { | ||
280 | printk(KERN_WARNING "Warning ssi already enabled\n"); | ||
281 | return 0; | ||
282 | } | ||
283 | stccr = SSI1_STCCR; | ||
284 | } else { | ||
285 | if (SSI2_SCR & SSI_SCR_SSIEN) { | ||
286 | printk(KERN_WARNING "Warning ssi already enabled\n"); | ||
287 | return 0; | ||
288 | } | ||
289 | stccr = SSI2_STCCR; | ||
290 | } | ||
291 | |||
292 | stmsk = srmsk = mask; | ||
293 | stccr &= ~SSI_STCCR_DC_MASK; | ||
294 | stccr |= SSI_STCCR_DC(slots - 1); | ||
295 | |||
296 | if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) { | ||
297 | SSI1_STMSK = stmsk; | ||
298 | SSI1_SRMSK = srmsk; | ||
299 | SSI1_SRCCR = SSI1_STCCR = stccr; | ||
300 | } else { | ||
301 | SSI2_STMSK = stmsk; | ||
302 | SSI2_SRMSK = srmsk; | ||
303 | SSI2_SRCCR = SSI2_STCCR = stccr; | ||
304 | } | ||
305 | |||
306 | return 0; | ||
307 | } | ||
308 | |||
309 | /* | ||
310 | * SSI DAI format configuration. | ||
311 | * Should only be called when port is inactive (i.e. SSIEN = 0). | ||
312 | * Note: We don't use the I2S modes but instead manually configure the | ||
313 | * SSI for I2S. | ||
314 | */ | ||
315 | static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, | ||
316 | unsigned int fmt) | ||
317 | { | ||
318 | u32 stcr = 0, srcr = 0, scr; | ||
319 | |||
320 | /* | ||
321 | * This is done to avoid this function to modify | ||
322 | * previous set values in stcr | ||
323 | */ | ||
324 | stcr = SSI1_STCR; | ||
325 | |||
326 | if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) | ||
327 | scr = SSI1_SCR & ~(SSI_SCR_SYN | SSI_SCR_NET); | ||
328 | else | ||
329 | scr = SSI2_SCR & ~(SSI_SCR_SYN | SSI_SCR_NET); | ||
330 | |||
331 | if (scr & SSI_SCR_SSIEN) { | ||
332 | printk(KERN_WARNING "Warning ssi already enabled\n"); | ||
333 | return 0; | ||
334 | } | ||
335 | |||
336 | /* DAI mode */ | ||
337 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
338 | case SND_SOC_DAIFMT_I2S: | ||
339 | /* data on rising edge of bclk, frame low 1clk before data */ | ||
340 | stcr |= SSI_STCR_TFSI | SSI_STCR_TEFS | SSI_STCR_TXBIT0; | ||
341 | srcr |= SSI_SRCR_RFSI | SSI_SRCR_REFS | SSI_SRCR_RXBIT0; | ||
342 | break; | ||
343 | case SND_SOC_DAIFMT_LEFT_J: | ||
344 | /* data on rising edge of bclk, frame high with data */ | ||
345 | stcr |= SSI_STCR_TXBIT0; | ||
346 | srcr |= SSI_SRCR_RXBIT0; | ||
347 | break; | ||
348 | case SND_SOC_DAIFMT_DSP_B: | ||
349 | /* data on rising edge of bclk, frame high with data */ | ||
350 | stcr |= SSI_STCR_TFSL; | ||
351 | srcr |= SSI_SRCR_RFSL; | ||
352 | break; | ||
353 | case SND_SOC_DAIFMT_DSP_A: | ||
354 | /* data on rising edge of bclk, frame high 1clk before data */ | ||
355 | stcr |= SSI_STCR_TFSL | SSI_STCR_TEFS; | ||
356 | srcr |= SSI_SRCR_RFSL | SSI_SRCR_REFS; | ||
357 | break; | ||
358 | } | ||
359 | |||
360 | /* DAI clock inversion */ | ||
361 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
362 | case SND_SOC_DAIFMT_IB_IF: | ||
363 | stcr |= SSI_STCR_TFSI; | ||
364 | stcr &= ~SSI_STCR_TSCKP; | ||
365 | srcr |= SSI_SRCR_RFSI; | ||
366 | srcr &= ~SSI_SRCR_RSCKP; | ||
367 | break; | ||
368 | case SND_SOC_DAIFMT_IB_NF: | ||
369 | stcr &= ~(SSI_STCR_TSCKP | SSI_STCR_TFSI); | ||
370 | srcr &= ~(SSI_SRCR_RSCKP | SSI_SRCR_RFSI); | ||
371 | break; | ||
372 | case SND_SOC_DAIFMT_NB_IF: | ||
373 | stcr |= SSI_STCR_TFSI | SSI_STCR_TSCKP; | ||
374 | srcr |= SSI_SRCR_RFSI | SSI_SRCR_RSCKP; | ||
375 | break; | ||
376 | case SND_SOC_DAIFMT_NB_NF: | ||
377 | stcr &= ~SSI_STCR_TFSI; | ||
378 | stcr |= SSI_STCR_TSCKP; | ||
379 | srcr &= ~SSI_SRCR_RFSI; | ||
380 | srcr |= SSI_SRCR_RSCKP; | ||
381 | break; | ||
382 | } | ||
383 | |||
384 | /* DAI clock master masks */ | ||
385 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
386 | case SND_SOC_DAIFMT_CBS_CFS: | ||
387 | stcr |= SSI_STCR_TFDIR | SSI_STCR_TXDIR; | ||
388 | srcr |= SSI_SRCR_RFDIR | SSI_SRCR_RXDIR; | ||
389 | break; | ||
390 | case SND_SOC_DAIFMT_CBM_CFS: | ||
391 | stcr |= SSI_STCR_TFDIR; | ||
392 | srcr |= SSI_SRCR_RFDIR; | ||
393 | break; | ||
394 | case SND_SOC_DAIFMT_CBS_CFM: | ||
395 | stcr |= SSI_STCR_TXDIR; | ||
396 | srcr |= SSI_SRCR_RXDIR; | ||
397 | break; | ||
398 | } | ||
399 | |||
400 | if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) { | ||
401 | SSI1_STCR = stcr; | ||
402 | SSI1_SRCR = srcr; | ||
403 | SSI1_SCR = scr; | ||
404 | } else { | ||
405 | SSI2_STCR = stcr; | ||
406 | SSI2_SRCR = srcr; | ||
407 | SSI2_SCR = scr; | ||
408 | } | ||
409 | |||
410 | return 0; | ||
411 | } | ||
412 | |||
413 | static int imx_ssi_startup(struct snd_pcm_substream *substream, | ||
414 | struct snd_soc_dai *dai) | ||
415 | { | ||
416 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
417 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | ||
418 | |||
419 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
420 | /* set up TX DMA params */ | ||
421 | switch (cpu_dai->id) { | ||
422 | case IMX_DAI_SSI0: | ||
423 | cpu_dai->dma_data = &imx_ssi1_pcm_stereo_out0; | ||
424 | break; | ||
425 | case IMX_DAI_SSI1: | ||
426 | cpu_dai->dma_data = &imx_ssi1_pcm_stereo_out1; | ||
427 | break; | ||
428 | case IMX_DAI_SSI2: | ||
429 | cpu_dai->dma_data = &imx_ssi2_pcm_stereo_out0; | ||
430 | break; | ||
431 | case IMX_DAI_SSI3: | ||
432 | cpu_dai->dma_data = &imx_ssi2_pcm_stereo_out1; | ||
433 | } | ||
434 | pr_debug("%s: (playback)\n", __func__); | ||
435 | } else { | ||
436 | /* set up RX DMA params */ | ||
437 | switch (cpu_dai->id) { | ||
438 | case IMX_DAI_SSI0: | ||
439 | cpu_dai->dma_data = &imx_ssi1_pcm_stereo_in0; | ||
440 | break; | ||
441 | case IMX_DAI_SSI1: | ||
442 | cpu_dai->dma_data = &imx_ssi1_pcm_stereo_in1; | ||
443 | break; | ||
444 | case IMX_DAI_SSI2: | ||
445 | cpu_dai->dma_data = &imx_ssi2_pcm_stereo_in0; | ||
446 | break; | ||
447 | case IMX_DAI_SSI3: | ||
448 | cpu_dai->dma_data = &imx_ssi2_pcm_stereo_in1; | ||
449 | } | ||
450 | pr_debug("%s: (capture)\n", __func__); | ||
451 | } | ||
452 | |||
453 | /* | ||
454 | * we cant really change any SSI values after SSI is enabled | ||
455 | * need to fix in software for max flexibility - lrg | ||
456 | */ | ||
457 | if (cpu_dai->active) { | ||
458 | printk(KERN_WARNING "Warning ssi already enabled\n"); | ||
459 | return 0; | ||
460 | } | ||
461 | |||
462 | /* reset the SSI port - Sect 45.4.4 */ | ||
463 | if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) { | ||
464 | |||
465 | if (!ssi_clk0) | ||
466 | return -EINVAL; | ||
467 | |||
468 | if (ssi_active[SSI1_PORT]++) { | ||
469 | pr_debug("%s: exit before reset\n", __func__); | ||
470 | return 0; | ||
471 | } | ||
472 | |||
473 | /* SSI1 Reset */ | ||
474 | SSI1_SCR = 0; | ||
475 | |||
476 | SSI1_SFCSR = SSI_SFCSR_RFWM1(RXFIFO_WATERMARK) | | ||
477 | SSI_SFCSR_RFWM0(RXFIFO_WATERMARK) | | ||
478 | SSI_SFCSR_TFWM1(TXFIFO_WATERMARK) | | ||
479 | SSI_SFCSR_TFWM0(TXFIFO_WATERMARK); | ||
480 | } else { | ||
481 | |||
482 | if (!ssi_clk1) | ||
483 | return -EINVAL; | ||
484 | |||
485 | if (ssi_active[SSI2_PORT]++) { | ||
486 | pr_debug("%s: exit before reset\n", __func__); | ||
487 | return 0; | ||
488 | } | ||
489 | |||
490 | /* SSI2 Reset */ | ||
491 | SSI2_SCR = 0; | ||
492 | |||
493 | SSI2_SFCSR = SSI_SFCSR_RFWM1(RXFIFO_WATERMARK) | | ||
494 | SSI_SFCSR_RFWM0(RXFIFO_WATERMARK) | | ||
495 | SSI_SFCSR_TFWM1(TXFIFO_WATERMARK) | | ||
496 | SSI_SFCSR_TFWM0(TXFIFO_WATERMARK); | ||
497 | } | ||
498 | |||
499 | return 0; | ||
500 | } | ||
501 | |||
502 | int imx_ssi_hw_tx_params(struct snd_pcm_substream *substream, | ||
503 | struct snd_pcm_hw_params *params) | ||
504 | { | ||
505 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
506 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | ||
507 | u32 stccr, stcr, sier; | ||
508 | |||
509 | pr_debug("%s\n", __func__); | ||
510 | |||
511 | if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) { | ||
512 | stccr = SSI1_STCCR & ~SSI_STCCR_WL_MASK; | ||
513 | stcr = SSI1_STCR; | ||
514 | sier = SSI1_SIER; | ||
515 | } else { | ||
516 | stccr = SSI2_STCCR & ~SSI_STCCR_WL_MASK; | ||
517 | stcr = SSI2_STCR; | ||
518 | sier = SSI2_SIER; | ||
519 | } | ||
520 | |||
521 | /* DAI data (word) size */ | ||
522 | switch (params_format(params)) { | ||
523 | case SNDRV_PCM_FORMAT_S16_LE: | ||
524 | stccr |= SSI_STCCR_WL(16); | ||
525 | break; | ||
526 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
527 | stccr |= SSI_STCCR_WL(20); | ||
528 | break; | ||
529 | case SNDRV_PCM_FORMAT_S24_LE: | ||
530 | stccr |= SSI_STCCR_WL(24); | ||
531 | break; | ||
532 | } | ||
533 | |||
534 | /* enable interrupts */ | ||
535 | if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) | ||
536 | stcr |= SSI_STCR_TFEN0; | ||
537 | else | ||
538 | stcr |= SSI_STCR_TFEN1; | ||
539 | sier |= SSI_SIER_TDMAE; | ||
540 | |||
541 | if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) { | ||
542 | SSI1_STCR = stcr; | ||
543 | SSI1_STCCR = stccr; | ||
544 | SSI1_SIER = sier; | ||
545 | } else { | ||
546 | SSI2_STCR = stcr; | ||
547 | SSI2_STCCR = stccr; | ||
548 | SSI2_SIER = sier; | ||
549 | } | ||
550 | |||
551 | return 0; | ||
552 | } | ||
553 | |||
554 | int imx_ssi_hw_rx_params(struct snd_pcm_substream *substream, | ||
555 | struct snd_pcm_hw_params *params) | ||
556 | { | ||
557 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
558 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | ||
559 | u32 srccr, srcr, sier; | ||
560 | |||
561 | pr_debug("%s\n", __func__); | ||
562 | |||
563 | if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) { | ||
564 | srccr = SSI1_SRCCR & ~SSI_SRCCR_WL_MASK; | ||
565 | srcr = SSI1_SRCR; | ||
566 | sier = SSI1_SIER; | ||
567 | } else { | ||
568 | srccr = SSI2_SRCCR & ~SSI_SRCCR_WL_MASK; | ||
569 | srcr = SSI2_SRCR; | ||
570 | sier = SSI2_SIER; | ||
571 | } | ||
572 | |||
573 | /* DAI data (word) size */ | ||
574 | switch (params_format(params)) { | ||
575 | case SNDRV_PCM_FORMAT_S16_LE: | ||
576 | srccr |= SSI_SRCCR_WL(16); | ||
577 | break; | ||
578 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
579 | srccr |= SSI_SRCCR_WL(20); | ||
580 | break; | ||
581 | case SNDRV_PCM_FORMAT_S24_LE: | ||
582 | srccr |= SSI_SRCCR_WL(24); | ||
583 | break; | ||
584 | } | ||
585 | |||
586 | /* enable interrupts */ | ||
587 | if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) | ||
588 | srcr |= SSI_SRCR_RFEN0; | ||
589 | else | ||
590 | srcr |= SSI_SRCR_RFEN1; | ||
591 | sier |= SSI_SIER_RDMAE; | ||
592 | |||
593 | if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) { | ||
594 | SSI1_SRCR = srcr; | ||
595 | SSI1_SRCCR = srccr; | ||
596 | SSI1_SIER = sier; | ||
597 | } else { | ||
598 | SSI2_SRCR = srcr; | ||
599 | SSI2_SRCCR = srccr; | ||
600 | SSI2_SIER = sier; | ||
601 | } | ||
602 | |||
603 | return 0; | ||
604 | } | ||
605 | |||
606 | /* | ||
607 | * Should only be called when port is inactive (i.e. SSIEN = 0), | ||
608 | * although can be called multiple times by upper layers. | ||
609 | */ | ||
610 | int imx_ssi_hw_params(struct snd_pcm_substream *substream, | ||
611 | struct snd_pcm_hw_params *params, | ||
612 | struct snd_soc_dai *dai) | ||
613 | { | ||
614 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
615 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | ||
616 | |||
617 | int ret; | ||
618 | |||
619 | /* cant change any parameters when SSI is running */ | ||
620 | if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) { | ||
621 | if (SSI1_SCR & SSI_SCR_SSIEN) { | ||
622 | printk(KERN_WARNING "Warning ssi already enabled\n"); | ||
623 | return 0; | ||
624 | } | ||
625 | } else { | ||
626 | if (SSI2_SCR & SSI_SCR_SSIEN) { | ||
627 | printk(KERN_WARNING "Warning ssi already enabled\n"); | ||
628 | return 0; | ||
629 | } | ||
630 | } | ||
631 | |||
632 | /* | ||
633 | * Configure both tx and rx params with the same settings. This is | ||
634 | * really a harware restriction because SSI must be disabled until | ||
635 | * we can change those values. If there is an active audio stream in | ||
636 | * one direction, enabling the other direction with different | ||
637 | * settings would mean disturbing the running one. | ||
638 | */ | ||
639 | ret = imx_ssi_hw_tx_params(substream, params); | ||
640 | if (ret < 0) | ||
641 | return ret; | ||
642 | return imx_ssi_hw_rx_params(substream, params); | ||
643 | } | ||
644 | |||
645 | int imx_ssi_prepare(struct snd_pcm_substream *substream, | ||
646 | struct snd_soc_dai *dai) | ||
647 | { | ||
648 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
649 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | ||
650 | int ret; | ||
651 | |||
652 | pr_debug("%s\n", __func__); | ||
653 | |||
654 | /* Enable clks here to follow SSI recommended init sequence */ | ||
655 | if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) { | ||
656 | ret = clk_enable(ssi_clk0); | ||
657 | if (ret < 0) | ||
658 | printk(KERN_ERR "Unable to enable ssi_clk0\n"); | ||
659 | } else { | ||
660 | ret = clk_enable(ssi_clk1); | ||
661 | if (ret < 0) | ||
662 | printk(KERN_ERR "Unable to enable ssi_clk1\n"); | ||
663 | } | ||
664 | |||
665 | return 0; | ||
666 | } | ||
667 | |||
668 | static int imx_ssi_trigger(struct snd_pcm_substream *substream, int cmd, | ||
669 | struct snd_soc_dai *dai) | ||
670 | { | ||
671 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
672 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | ||
673 | u32 scr; | ||
674 | |||
675 | if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) | ||
676 | scr = SSI1_SCR; | ||
677 | else | ||
678 | scr = SSI2_SCR; | ||
679 | |||
680 | switch (cmd) { | ||
681 | case SNDRV_PCM_TRIGGER_START: | ||
682 | case SNDRV_PCM_TRIGGER_RESUME: | ||
683 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
684 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
685 | scr |= SSI_SCR_TE | SSI_SCR_SSIEN; | ||
686 | else | ||
687 | scr |= SSI_SCR_RE | SSI_SCR_SSIEN; | ||
688 | break; | ||
689 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
690 | case SNDRV_PCM_TRIGGER_STOP: | ||
691 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
692 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
693 | scr &= ~SSI_SCR_TE; | ||
694 | else | ||
695 | scr &= ~SSI_SCR_RE; | ||
696 | break; | ||
697 | default: | ||
698 | return -EINVAL; | ||
699 | } | ||
700 | |||
701 | if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) | ||
702 | SSI1_SCR = scr; | ||
703 | else | ||
704 | SSI2_SCR = scr; | ||
705 | |||
706 | return 0; | ||
707 | } | ||
708 | |||
709 | static void imx_ssi_shutdown(struct snd_pcm_substream *substream, | ||
710 | struct snd_soc_dai *dai) | ||
711 | { | ||
712 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
713 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | ||
714 | |||
715 | /* shutdown SSI if neither Tx or Rx is active */ | ||
716 | if (!cpu_dai->active) { | ||
717 | |||
718 | if (cpu_dai->id == IMX_DAI_SSI0 || | ||
719 | cpu_dai->id == IMX_DAI_SSI2) { | ||
720 | |||
721 | if (--ssi_active[SSI1_PORT] > 1) | ||
722 | return; | ||
723 | |||
724 | SSI1_SCR = 0; | ||
725 | clk_disable(ssi_clk0); | ||
726 | } else { | ||
727 | if (--ssi_active[SSI2_PORT]) | ||
728 | return; | ||
729 | SSI2_SCR = 0; | ||
730 | clk_disable(ssi_clk1); | ||
731 | } | ||
732 | } | ||
733 | } | ||
734 | |||
735 | #ifdef CONFIG_PM | ||
736 | static int imx_ssi_suspend(struct platform_device *dev, | ||
737 | struct snd_soc_dai *dai) | ||
738 | { | ||
739 | return 0; | ||
740 | } | ||
741 | |||
742 | static int imx_ssi_resume(struct platform_device *pdev, | ||
743 | struct snd_soc_dai *dai) | ||
744 | { | ||
745 | return 0; | ||
746 | } | ||
747 | |||
748 | #else | ||
749 | #define imx_ssi_suspend NULL | ||
750 | #define imx_ssi_resume NULL | ||
751 | #endif | ||
752 | |||
753 | #define IMX_SSI_RATES \ | ||
754 | (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | \ | ||
755 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \ | ||
756 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ | ||
757 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | \ | ||
758 | SNDRV_PCM_RATE_96000) | ||
759 | |||
760 | #define IMX_SSI_BITS \ | ||
761 | (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ | ||
762 | SNDRV_PCM_FMTBIT_S24_LE) | ||
763 | |||
764 | static struct snd_soc_dai_ops imx_ssi_pcm_dai_ops = { | ||
765 | .startup = imx_ssi_startup, | ||
766 | .shutdown = imx_ssi_shutdown, | ||
767 | .trigger = imx_ssi_trigger, | ||
768 | .prepare = imx_ssi_prepare, | ||
769 | .hw_params = imx_ssi_hw_params, | ||
770 | .set_sysclk = imx_ssi_set_dai_sysclk, | ||
771 | .set_clkdiv = imx_ssi_set_dai_clkdiv, | ||
772 | .set_fmt = imx_ssi_set_dai_fmt, | ||
773 | .set_tdm_slot = imx_ssi_set_dai_tdm_slot, | ||
774 | }; | ||
775 | |||
776 | struct snd_soc_dai imx_ssi_pcm_dai[] = { | ||
777 | { | ||
778 | .name = "imx-i2s-1-0", | ||
779 | .id = IMX_DAI_SSI0, | ||
780 | .suspend = imx_ssi_suspend, | ||
781 | .resume = imx_ssi_resume, | ||
782 | .playback = { | ||
783 | .channels_min = 1, | ||
784 | .channels_max = 2, | ||
785 | .formats = IMX_SSI_BITS, | ||
786 | .rates = IMX_SSI_RATES,}, | ||
787 | .capture = { | ||
788 | .channels_min = 1, | ||
789 | .channels_max = 2, | ||
790 | .formats = IMX_SSI_BITS, | ||
791 | .rates = IMX_SSI_RATES,}, | ||
792 | .ops = &imx_ssi_pcm_dai_ops, | ||
793 | }, | ||
794 | { | ||
795 | .name = "imx-i2s-2-0", | ||
796 | .id = IMX_DAI_SSI1, | ||
797 | .playback = { | ||
798 | .channels_min = 1, | ||
799 | .channels_max = 2, | ||
800 | .formats = IMX_SSI_BITS, | ||
801 | .rates = IMX_SSI_RATES,}, | ||
802 | .capture = { | ||
803 | .channels_min = 1, | ||
804 | .channels_max = 2, | ||
805 | .formats = IMX_SSI_BITS, | ||
806 | .rates = IMX_SSI_RATES,}, | ||
807 | .ops = &imx_ssi_pcm_dai_ops, | ||
808 | }, | ||
809 | { | ||
810 | .name = "imx-i2s-1-1", | ||
811 | .id = IMX_DAI_SSI2, | ||
812 | .suspend = imx_ssi_suspend, | ||
813 | .resume = imx_ssi_resume, | ||
814 | .playback = { | ||
815 | .channels_min = 1, | ||
816 | .channels_max = 2, | ||
817 | .formats = IMX_SSI_BITS, | ||
818 | .rates = IMX_SSI_RATES,}, | ||
819 | .capture = { | ||
820 | .channels_min = 1, | ||
821 | .channels_max = 2, | ||
822 | .formats = IMX_SSI_BITS, | ||
823 | .rates = IMX_SSI_RATES,}, | ||
824 | .ops = &imx_ssi_pcm_dai_ops, | ||
825 | }, | ||
826 | { | ||
827 | .name = "imx-i2s-2-1", | ||
828 | .id = IMX_DAI_SSI3, | ||
829 | .playback = { | ||
830 | .channels_min = 1, | ||
831 | .channels_max = 2, | ||
832 | .formats = IMX_SSI_BITS, | ||
833 | .rates = IMX_SSI_RATES,}, | ||
834 | .capture = { | ||
835 | .channels_min = 1, | ||
836 | .channels_max = 2, | ||
837 | .formats = IMX_SSI_BITS, | ||
838 | .rates = IMX_SSI_RATES,}, | ||
839 | .ops = &imx_ssi_pcm_dai_ops, | ||
840 | }, | ||
841 | }; | ||
842 | EXPORT_SYMBOL_GPL(imx_ssi_pcm_dai); | ||
843 | |||
844 | static int __init imx_ssi_init(void) | ||
845 | { | ||
846 | return snd_soc_register_dais(imx_ssi_pcm_dai, | ||
847 | ARRAY_SIZE(imx_ssi_pcm_dai)); | ||
848 | } | ||
849 | |||
850 | static void __exit imx_ssi_exit(void) | ||
851 | { | ||
852 | snd_soc_unregister_dais(imx_ssi_pcm_dai, | ||
853 | ARRAY_SIZE(imx_ssi_pcm_dai)); | ||
854 | } | ||
855 | |||
856 | module_init(imx_ssi_init); | ||
857 | module_exit(imx_ssi_exit); | ||
858 | MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com"); | ||
859 | MODULE_DESCRIPTION("i.MX ASoC I2S driver"); | ||
860 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/imx/mxc-ssi.h b/sound/soc/imx/mxc-ssi.h deleted file mode 100644 index 12bbdc9c7ecd..000000000000 --- a/sound/soc/imx/mxc-ssi.h +++ /dev/null | |||
@@ -1,238 +0,0 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License version 2 as | ||
4 | * published by the Free Software Foundation. | ||
5 | */ | ||
6 | |||
7 | #ifndef _IMX_SSI_H | ||
8 | #define _IMX_SSI_H | ||
9 | |||
10 | #include <mach/hardware.h> | ||
11 | |||
12 | /* SSI regs definition - MOVE to /arch/arm/plat-mxc/include/mach/ when stable */ | ||
13 | #define SSI1_IO_BASE_ADDR IO_ADDRESS(SSI1_BASE_ADDR) | ||
14 | #define SSI2_IO_BASE_ADDR IO_ADDRESS(SSI2_BASE_ADDR) | ||
15 | |||
16 | #define STX0 0x00 | ||
17 | #define STX1 0x04 | ||
18 | #define SRX0 0x08 | ||
19 | #define SRX1 0x0c | ||
20 | #define SCR 0x10 | ||
21 | #define SISR 0x14 | ||
22 | #define SIER 0x18 | ||
23 | #define STCR 0x1c | ||
24 | #define SRCR 0x20 | ||
25 | #define STCCR 0x24 | ||
26 | #define SRCCR 0x28 | ||
27 | #define SFCSR 0x2c | ||
28 | #define STR 0x30 | ||
29 | #define SOR 0x34 | ||
30 | #define SACNT 0x38 | ||
31 | #define SACADD 0x3c | ||
32 | #define SACDAT 0x40 | ||
33 | #define SATAG 0x44 | ||
34 | #define STMSK 0x48 | ||
35 | #define SRMSK 0x4c | ||
36 | |||
37 | #define SSI1_STX0 (*((volatile u32 *)(SSI1_IO_BASE_ADDR + STX0))) | ||
38 | #define SSI1_STX1 (*((volatile u32 *)(SSI1_IO_BASE_ADDR + STX1))) | ||
39 | #define SSI1_SRX0 (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SRX0))) | ||
40 | #define SSI1_SRX1 (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SRX1))) | ||
41 | #define SSI1_SCR (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SCR))) | ||
42 | #define SSI1_SISR (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SISR))) | ||
43 | #define SSI1_SIER (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SIER))) | ||
44 | #define SSI1_STCR (*((volatile u32 *)(SSI1_IO_BASE_ADDR + STCR))) | ||
45 | #define SSI1_SRCR (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SRCR))) | ||
46 | #define SSI1_STCCR (*((volatile u32 *)(SSI1_IO_BASE_ADDR + STCCR))) | ||
47 | #define SSI1_SRCCR (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SRCCR))) | ||
48 | #define SSI1_SFCSR (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SFCSR))) | ||
49 | #define SSI1_STR (*((volatile u32 *)(SSI1_IO_BASE_ADDR + STR))) | ||
50 | #define SSI1_SOR (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SOR))) | ||
51 | #define SSI1_SACNT (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SACNT))) | ||
52 | #define SSI1_SACADD (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SACADD))) | ||
53 | #define SSI1_SACDAT (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SACDAT))) | ||
54 | #define SSI1_SATAG (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SATAG))) | ||
55 | #define SSI1_STMSK (*((volatile u32 *)(SSI1_IO_BASE_ADDR + STMSK))) | ||
56 | #define SSI1_SRMSK (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SRMSK))) | ||
57 | |||
58 | |||
59 | #define SSI2_STX0 (*((volatile u32 *)(SSI2_IO_BASE_ADDR + STX0))) | ||
60 | #define SSI2_STX1 (*((volatile u32 *)(SSI2_IO_BASE_ADDR + STX1))) | ||
61 | #define SSI2_SRX0 (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SRX0))) | ||
62 | #define SSI2_SRX1 (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SRX1))) | ||
63 | #define SSI2_SCR (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SCR))) | ||
64 | #define SSI2_SISR (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SISR))) | ||
65 | #define SSI2_SIER (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SIER))) | ||
66 | #define SSI2_STCR (*((volatile u32 *)(SSI2_IO_BASE_ADDR + STCR))) | ||
67 | #define SSI2_SRCR (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SRCR))) | ||
68 | #define SSI2_STCCR (*((volatile u32 *)(SSI2_IO_BASE_ADDR + STCCR))) | ||
69 | #define SSI2_SRCCR (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SRCCR))) | ||
70 | #define SSI2_SFCSR (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SFCSR))) | ||
71 | #define SSI2_STR (*((volatile u32 *)(SSI2_IO_BASE_ADDR + STR))) | ||
72 | #define SSI2_SOR (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SOR))) | ||
73 | #define SSI2_SACNT (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SACNT))) | ||
74 | #define SSI2_SACADD (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SACADD))) | ||
75 | #define SSI2_SACDAT (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SACDAT))) | ||
76 | #define SSI2_SATAG (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SATAG))) | ||
77 | #define SSI2_STMSK (*((volatile u32 *)(SSI2_IO_BASE_ADDR + STMSK))) | ||
78 | #define SSI2_SRMSK (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SRMSK))) | ||
79 | |||
80 | #define SSI_SCR_CLK_IST (1 << 9) | ||
81 | #define SSI_SCR_TCH_EN (1 << 8) | ||
82 | #define SSI_SCR_SYS_CLK_EN (1 << 7) | ||
83 | #define SSI_SCR_I2S_MODE_NORM (0 << 5) | ||
84 | #define SSI_SCR_I2S_MODE_MSTR (1 << 5) | ||
85 | #define SSI_SCR_I2S_MODE_SLAVE (2 << 5) | ||
86 | #define SSI_SCR_SYN (1 << 4) | ||
87 | #define SSI_SCR_NET (1 << 3) | ||
88 | #define SSI_SCR_RE (1 << 2) | ||
89 | #define SSI_SCR_TE (1 << 1) | ||
90 | #define SSI_SCR_SSIEN (1 << 0) | ||
91 | |||
92 | #define SSI_SISR_CMDAU (1 << 18) | ||
93 | #define SSI_SISR_CMDDU (1 << 17) | ||
94 | #define SSI_SISR_RXT (1 << 16) | ||
95 | #define SSI_SISR_RDR1 (1 << 15) | ||
96 | #define SSI_SISR_RDR0 (1 << 14) | ||
97 | #define SSI_SISR_TDE1 (1 << 13) | ||
98 | #define SSI_SISR_TDE0 (1 << 12) | ||
99 | #define SSI_SISR_ROE1 (1 << 11) | ||
100 | #define SSI_SISR_ROE0 (1 << 10) | ||
101 | #define SSI_SISR_TUE1 (1 << 9) | ||
102 | #define SSI_SISR_TUE0 (1 << 8) | ||
103 | #define SSI_SISR_TFS (1 << 7) | ||
104 | #define SSI_SISR_RFS (1 << 6) | ||
105 | #define SSI_SISR_TLS (1 << 5) | ||
106 | #define SSI_SISR_RLS (1 << 4) | ||
107 | #define SSI_SISR_RFF1 (1 << 3) | ||
108 | #define SSI_SISR_RFF0 (1 << 2) | ||
109 | #define SSI_SISR_TFE1 (1 << 1) | ||
110 | #define SSI_SISR_TFE0 (1 << 0) | ||
111 | |||
112 | #define SSI_SIER_RDMAE (1 << 22) | ||
113 | #define SSI_SIER_RIE (1 << 21) | ||
114 | #define SSI_SIER_TDMAE (1 << 20) | ||
115 | #define SSI_SIER_TIE (1 << 19) | ||
116 | #define SSI_SIER_CMDAU_EN (1 << 18) | ||
117 | #define SSI_SIER_CMDDU_EN (1 << 17) | ||
118 | #define SSI_SIER_RXT_EN (1 << 16) | ||
119 | #define SSI_SIER_RDR1_EN (1 << 15) | ||
120 | #define SSI_SIER_RDR0_EN (1 << 14) | ||
121 | #define SSI_SIER_TDE1_EN (1 << 13) | ||
122 | #define SSI_SIER_TDE0_EN (1 << 12) | ||
123 | #define SSI_SIER_ROE1_EN (1 << 11) | ||
124 | #define SSI_SIER_ROE0_EN (1 << 10) | ||
125 | #define SSI_SIER_TUE1_EN (1 << 9) | ||
126 | #define SSI_SIER_TUE0_EN (1 << 8) | ||
127 | #define SSI_SIER_TFS_EN (1 << 7) | ||
128 | #define SSI_SIER_RFS_EN (1 << 6) | ||
129 | #define SSI_SIER_TLS_EN (1 << 5) | ||
130 | #define SSI_SIER_RLS_EN (1 << 4) | ||
131 | #define SSI_SIER_RFF1_EN (1 << 3) | ||
132 | #define SSI_SIER_RFF0_EN (1 << 2) | ||
133 | #define SSI_SIER_TFE1_EN (1 << 1) | ||
134 | #define SSI_SIER_TFE0_EN (1 << 0) | ||
135 | |||
136 | #define SSI_STCR_TXBIT0 (1 << 9) | ||
137 | #define SSI_STCR_TFEN1 (1 << 8) | ||
138 | #define SSI_STCR_TFEN0 (1 << 7) | ||
139 | #define SSI_STCR_TFDIR (1 << 6) | ||
140 | #define SSI_STCR_TXDIR (1 << 5) | ||
141 | #define SSI_STCR_TSHFD (1 << 4) | ||
142 | #define SSI_STCR_TSCKP (1 << 3) | ||
143 | #define SSI_STCR_TFSI (1 << 2) | ||
144 | #define SSI_STCR_TFSL (1 << 1) | ||
145 | #define SSI_STCR_TEFS (1 << 0) | ||
146 | |||
147 | #define SSI_SRCR_RXBIT0 (1 << 9) | ||
148 | #define SSI_SRCR_RFEN1 (1 << 8) | ||
149 | #define SSI_SRCR_RFEN0 (1 << 7) | ||
150 | #define SSI_SRCR_RFDIR (1 << 6) | ||
151 | #define SSI_SRCR_RXDIR (1 << 5) | ||
152 | #define SSI_SRCR_RSHFD (1 << 4) | ||
153 | #define SSI_SRCR_RSCKP (1 << 3) | ||
154 | #define SSI_SRCR_RFSI (1 << 2) | ||
155 | #define SSI_SRCR_RFSL (1 << 1) | ||
156 | #define SSI_SRCR_REFS (1 << 0) | ||
157 | |||
158 | #define SSI_STCCR_DIV2 (1 << 18) | ||
159 | #define SSI_STCCR_PSR (1 << 15) | ||
160 | #define SSI_STCCR_WL(x) ((((x) - 2) >> 1) << 13) | ||
161 | #define SSI_STCCR_DC(x) (((x) & 0x1f) << 8) | ||
162 | #define SSI_STCCR_PM(x) (((x) & 0xff) << 0) | ||
163 | #define SSI_STCCR_WL_MASK (0xf << 13) | ||
164 | #define SSI_STCCR_DC_MASK (0x1f << 8) | ||
165 | #define SSI_STCCR_PM_MASK (0xff << 0) | ||
166 | |||
167 | #define SSI_SRCCR_DIV2 (1 << 18) | ||
168 | #define SSI_SRCCR_PSR (1 << 15) | ||
169 | #define SSI_SRCCR_WL(x) ((((x) - 2) >> 1) << 13) | ||
170 | #define SSI_SRCCR_DC(x) (((x) & 0x1f) << 8) | ||
171 | #define SSI_SRCCR_PM(x) (((x) & 0xff) << 0) | ||
172 | #define SSI_SRCCR_WL_MASK (0xf << 13) | ||
173 | #define SSI_SRCCR_DC_MASK (0x1f << 8) | ||
174 | #define SSI_SRCCR_PM_MASK (0xff << 0) | ||
175 | |||
176 | |||
177 | #define SSI_SFCSR_RFCNT1(x) (((x) & 0xf) << 28) | ||
178 | #define SSI_SFCSR_TFCNT1(x) (((x) & 0xf) << 24) | ||
179 | #define SSI_SFCSR_RFWM1(x) (((x) & 0xf) << 20) | ||
180 | #define SSI_SFCSR_TFWM1(x) (((x) & 0xf) << 16) | ||
181 | #define SSI_SFCSR_RFCNT0(x) (((x) & 0xf) << 12) | ||
182 | #define SSI_SFCSR_TFCNT0(x) (((x) & 0xf) << 8) | ||
183 | #define SSI_SFCSR_RFWM0(x) (((x) & 0xf) << 4) | ||
184 | #define SSI_SFCSR_TFWM0(x) (((x) & 0xf) << 0) | ||
185 | |||
186 | #define SSI_STR_TEST (1 << 15) | ||
187 | #define SSI_STR_RCK2TCK (1 << 14) | ||
188 | #define SSI_STR_RFS2TFS (1 << 13) | ||
189 | #define SSI_STR_RXSTATE(x) (((x) & 0xf) << 8) | ||
190 | #define SSI_STR_TXD2RXD (1 << 7) | ||
191 | #define SSI_STR_TCK2RCK (1 << 6) | ||
192 | #define SSI_STR_TFS2RFS (1 << 5) | ||
193 | #define SSI_STR_TXSTATE(x) (((x) & 0xf) << 0) | ||
194 | |||
195 | #define SSI_SOR_CLKOFF (1 << 6) | ||
196 | #define SSI_SOR_RX_CLR (1 << 5) | ||
197 | #define SSI_SOR_TX_CLR (1 << 4) | ||
198 | #define SSI_SOR_INIT (1 << 3) | ||
199 | #define SSI_SOR_WAIT(x) (((x) & 0x3) << 1) | ||
200 | #define SSI_SOR_SYNRST (1 << 0) | ||
201 | |||
202 | #define SSI_SACNT_FRDIV(x) (((x) & 0x3f) << 5) | ||
203 | #define SSI_SACNT_WR (x << 4) | ||
204 | #define SSI_SACNT_RD (x << 3) | ||
205 | #define SSI_SACNT_TIF (x << 2) | ||
206 | #define SSI_SACNT_FV (x << 1) | ||
207 | #define SSI_SACNT_AC97EN (x << 0) | ||
208 | |||
209 | /* Watermarks for FIFO's */ | ||
210 | #define TXFIFO_WATERMARK 0x4 | ||
211 | #define RXFIFO_WATERMARK 0x4 | ||
212 | |||
213 | /* i.MX DAI SSP ID's */ | ||
214 | #define IMX_DAI_SSI0 0 /* SSI1 FIFO 0 */ | ||
215 | #define IMX_DAI_SSI1 1 /* SSI1 FIFO 1 */ | ||
216 | #define IMX_DAI_SSI2 2 /* SSI2 FIFO 0 */ | ||
217 | #define IMX_DAI_SSI3 3 /* SSI2 FIFO 1 */ | ||
218 | |||
219 | /* SSI clock sources */ | ||
220 | #define IMX_SSP_SYS_CLK 0 | ||
221 | |||
222 | /* SSI audio dividers */ | ||
223 | #define IMX_SSI_TX_DIV_2 0 | ||
224 | #define IMX_SSI_TX_DIV_PSR 1 | ||
225 | #define IMX_SSI_TX_DIV_PM 2 | ||
226 | #define IMX_SSI_RX_DIV_2 3 | ||
227 | #define IMX_SSI_RX_DIV_PSR 4 | ||
228 | #define IMX_SSI_RX_DIV_PM 5 | ||
229 | |||
230 | |||
231 | /* SSI Div 2 */ | ||
232 | #define IMX_SSI_DIV_2_OFF (~SSI_STCCR_DIV2) | ||
233 | #define IMX_SSI_DIV_2_ON SSI_STCCR_DIV2 | ||
234 | |||
235 | extern struct snd_soc_dai imx_ssi_pcm_dai[4]; | ||
236 | extern int get_ssi_clk(int ssi, struct device *dev); | ||
237 | extern void put_ssi_clk(int ssi); | ||
238 | #endif | ||
diff --git a/sound/soc/imx/phycore-ac97.c b/sound/soc/imx/phycore-ac97.c new file mode 100644 index 000000000000..a8307d55c70e --- /dev/null +++ b/sound/soc/imx/phycore-ac97.c | |||
@@ -0,0 +1,90 @@ | |||
1 | /* | ||
2 | * phycore-ac97.c -- SoC audio for imx_phycore in AC97 mode | ||
3 | * | ||
4 | * Copyright 2009 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License as published by the | ||
8 | * Free Software Foundation; either version 2 of the License, or (at your | ||
9 | * option) any later version. | ||
10 | * | ||
11 | */ | ||
12 | |||
13 | #include <linux/module.h> | ||
14 | #include <linux/moduleparam.h> | ||
15 | #include <linux/device.h> | ||
16 | #include <linux/i2c.h> | ||
17 | #include <sound/core.h> | ||
18 | #include <sound/pcm.h> | ||
19 | #include <sound/soc.h> | ||
20 | #include <sound/soc-dapm.h> | ||
21 | #include <asm/mach-types.h> | ||
22 | |||
23 | #include "../codecs/wm9712.h" | ||
24 | #include "imx-ssi.h" | ||
25 | |||
26 | static struct snd_soc_card imx_phycore; | ||
27 | |||
28 | static struct snd_soc_ops imx_phycore_hifi_ops = { | ||
29 | }; | ||
30 | |||
31 | static struct snd_soc_dai_link imx_phycore_dai_ac97[] = { | ||
32 | { | ||
33 | .name = "HiFi", | ||
34 | .stream_name = "HiFi", | ||
35 | .codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI], | ||
36 | .ops = &imx_phycore_hifi_ops, | ||
37 | }, | ||
38 | }; | ||
39 | |||
40 | static struct snd_soc_card imx_phycore = { | ||
41 | .name = "PhyCORE-audio", | ||
42 | .platform = &imx_soc_platform, | ||
43 | .dai_link = imx_phycore_dai_ac97, | ||
44 | .num_links = ARRAY_SIZE(imx_phycore_dai_ac97), | ||
45 | }; | ||
46 | |||
47 | static struct snd_soc_device imx_phycore_snd_devdata = { | ||
48 | .card = &imx_phycore, | ||
49 | .codec_dev = &soc_codec_dev_wm9712, | ||
50 | }; | ||
51 | |||
52 | static struct platform_device *imx_phycore_snd_device; | ||
53 | |||
54 | static int __init imx_phycore_init(void) | ||
55 | { | ||
56 | int ret; | ||
57 | |||
58 | if (!machine_is_pcm043() && !machine_is_pca100()) | ||
59 | /* return happy. We might run on a totally different machine */ | ||
60 | return 0; | ||
61 | |||
62 | imx_phycore_snd_device = platform_device_alloc("soc-audio", -1); | ||
63 | if (!imx_phycore_snd_device) | ||
64 | return -ENOMEM; | ||
65 | |||
66 | imx_phycore_dai_ac97[0].cpu_dai = &imx_ssi_pcm_dai[0]; | ||
67 | |||
68 | platform_set_drvdata(imx_phycore_snd_device, &imx_phycore_snd_devdata); | ||
69 | imx_phycore_snd_devdata.dev = &imx_phycore_snd_device->dev; | ||
70 | ret = platform_device_add(imx_phycore_snd_device); | ||
71 | |||
72 | if (ret) { | ||
73 | printk(KERN_ERR "ASoC: Platform device allocation failed\n"); | ||
74 | platform_device_put(imx_phycore_snd_device); | ||
75 | } | ||
76 | |||
77 | return ret; | ||
78 | } | ||
79 | |||
80 | static void __exit imx_phycore_exit(void) | ||
81 | { | ||
82 | platform_device_unregister(imx_phycore_snd_device); | ||
83 | } | ||
84 | |||
85 | late_initcall(imx_phycore_init); | ||
86 | module_exit(imx_phycore_exit); | ||
87 | |||
88 | MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>"); | ||
89 | MODULE_DESCRIPTION("PhyCORE ALSA SoC driver"); | ||
90 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index 61952aa6cd5a..f11963c21873 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig | |||
@@ -6,6 +6,9 @@ config SND_OMAP_SOC_MCBSP | |||
6 | tristate | 6 | tristate |
7 | select OMAP_MCBSP | 7 | select OMAP_MCBSP |
8 | 8 | ||
9 | config SND_OMAP_SOC_MCPDM | ||
10 | tristate | ||
11 | |||
9 | config SND_OMAP_SOC_N810 | 12 | config SND_OMAP_SOC_N810 |
10 | tristate "SoC Audio support for Nokia N810" | 13 | tristate "SoC Audio support for Nokia N810" |
11 | depends on SND_OMAP_SOC && MACH_NOKIA_N810 && I2C | 14 | depends on SND_OMAP_SOC && MACH_NOKIA_N810 && I2C |
@@ -94,12 +97,14 @@ config SND_OMAP_SOC_OMAP3_PANDORA | |||
94 | Say Y if you want to add support for SoC audio on the OMAP3 Pandora. | 97 | Say Y if you want to add support for SoC audio on the OMAP3 Pandora. |
95 | 98 | ||
96 | config SND_OMAP_SOC_OMAP3_BEAGLE | 99 | config SND_OMAP_SOC_OMAP3_BEAGLE |
97 | tristate "SoC Audio support for OMAP3 Beagle" | 100 | tristate "SoC Audio support for OMAP3 Beagle and Devkit8000" |
98 | depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP3_BEAGLE | 101 | depends on TWL4030_CORE && SND_OMAP_SOC |
102 | depends on (MACH_OMAP3_BEAGLE || MACH_DEVKIT8000) | ||
99 | select SND_OMAP_SOC_MCBSP | 103 | select SND_OMAP_SOC_MCBSP |
100 | select SND_SOC_TWL4030 | 104 | select SND_SOC_TWL4030 |
101 | help | 105 | help |
102 | Say Y if you want to add support for SoC audio on the Beagleboard. | 106 | Say Y if you want to add support for SoC audio on the Beagleboard or |
107 | the clone Devkit8000. | ||
103 | 108 | ||
104 | config SND_OMAP_SOC_ZOOM2 | 109 | config SND_OMAP_SOC_ZOOM2 |
105 | tristate "SoC Audio support for Zoom2" | 110 | tristate "SoC Audio support for Zoom2" |
diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile index 19283e5edfbf..0bc00ca14b37 100644 --- a/sound/soc/omap/Makefile +++ b/sound/soc/omap/Makefile | |||
@@ -1,9 +1,11 @@ | |||
1 | # OMAP Platform Support | 1 | # OMAP Platform Support |
2 | snd-soc-omap-objs := omap-pcm.o | 2 | snd-soc-omap-objs := omap-pcm.o |
3 | snd-soc-omap-mcbsp-objs := omap-mcbsp.o | 3 | snd-soc-omap-mcbsp-objs := omap-mcbsp.o |
4 | snd-soc-omap-mcpdm-objs := omap-mcpdm.o mcpdm.o | ||
4 | 5 | ||
5 | obj-$(CONFIG_SND_OMAP_SOC) += snd-soc-omap.o | 6 | obj-$(CONFIG_SND_OMAP_SOC) += snd-soc-omap.o |
6 | obj-$(CONFIG_SND_OMAP_SOC_MCBSP) += snd-soc-omap-mcbsp.o | 7 | obj-$(CONFIG_SND_OMAP_SOC_MCBSP) += snd-soc-omap-mcbsp.o |
8 | obj-$(CONFIG_SND_OMAP_SOC_MCPDM) += snd-soc-omap-mcpdm.o | ||
7 | 9 | ||
8 | # OMAP Machine Support | 10 | # OMAP Machine Support |
9 | snd-soc-n810-objs := n810.o | 11 | snd-soc-n810-objs := n810.o |
diff --git a/sound/soc/omap/mcpdm.c b/sound/soc/omap/mcpdm.c new file mode 100644 index 000000000000..ad8df6cfae88 --- /dev/null +++ b/sound/soc/omap/mcpdm.c | |||
@@ -0,0 +1,484 @@ | |||
1 | /* | ||
2 | * mcpdm.c -- McPDM interface driver | ||
3 | * | ||
4 | * Author: Jorge Eduardo Candelaria <x0107209@ti.com> | ||
5 | * Copyright (C) 2009 - Texas Instruments, Inc. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * version 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but | ||
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | * 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., 51 Franklin St, Fifth Floor, Boston, MA | ||
19 | * 02110-1301 USA | ||
20 | * | ||
21 | */ | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/device.h> | ||
26 | #include <linux/platform_device.h> | ||
27 | #include <linux/wait.h> | ||
28 | #include <linux/interrupt.h> | ||
29 | #include <linux/err.h> | ||
30 | #include <linux/clk.h> | ||
31 | #include <linux/delay.h> | ||
32 | #include <linux/io.h> | ||
33 | #include <linux/irq.h> | ||
34 | |||
35 | #include "mcpdm.h" | ||
36 | |||
37 | static struct omap_mcpdm *mcpdm; | ||
38 | |||
39 | static inline void omap_mcpdm_write(u16 reg, u32 val) | ||
40 | { | ||
41 | __raw_writel(val, mcpdm->io_base + reg); | ||
42 | } | ||
43 | |||
44 | static inline int omap_mcpdm_read(u16 reg) | ||
45 | { | ||
46 | return __raw_readl(mcpdm->io_base + reg); | ||
47 | } | ||
48 | |||
49 | static void omap_mcpdm_reg_dump(void) | ||
50 | { | ||
51 | dev_dbg(mcpdm->dev, "***********************\n"); | ||
52 | dev_dbg(mcpdm->dev, "IRQSTATUS_RAW: 0x%04x\n", | ||
53 | omap_mcpdm_read(MCPDM_IRQSTATUS_RAW)); | ||
54 | dev_dbg(mcpdm->dev, "IRQSTATUS: 0x%04x\n", | ||
55 | omap_mcpdm_read(MCPDM_IRQSTATUS)); | ||
56 | dev_dbg(mcpdm->dev, "IRQENABLE_SET: 0x%04x\n", | ||
57 | omap_mcpdm_read(MCPDM_IRQENABLE_SET)); | ||
58 | dev_dbg(mcpdm->dev, "IRQENABLE_CLR: 0x%04x\n", | ||
59 | omap_mcpdm_read(MCPDM_IRQENABLE_CLR)); | ||
60 | dev_dbg(mcpdm->dev, "IRQWAKE_EN: 0x%04x\n", | ||
61 | omap_mcpdm_read(MCPDM_IRQWAKE_EN)); | ||
62 | dev_dbg(mcpdm->dev, "DMAENABLE_SET: 0x%04x\n", | ||
63 | omap_mcpdm_read(MCPDM_DMAENABLE_SET)); | ||
64 | dev_dbg(mcpdm->dev, "DMAENABLE_CLR: 0x%04x\n", | ||
65 | omap_mcpdm_read(MCPDM_DMAENABLE_CLR)); | ||
66 | dev_dbg(mcpdm->dev, "DMAWAKEEN: 0x%04x\n", | ||
67 | omap_mcpdm_read(MCPDM_DMAWAKEEN)); | ||
68 | dev_dbg(mcpdm->dev, "CTRL: 0x%04x\n", | ||
69 | omap_mcpdm_read(MCPDM_CTRL)); | ||
70 | dev_dbg(mcpdm->dev, "DN_DATA: 0x%04x\n", | ||
71 | omap_mcpdm_read(MCPDM_DN_DATA)); | ||
72 | dev_dbg(mcpdm->dev, "UP_DATA: 0x%04x\n", | ||
73 | omap_mcpdm_read(MCPDM_UP_DATA)); | ||
74 | dev_dbg(mcpdm->dev, "FIFO_CTRL_DN: 0x%04x\n", | ||
75 | omap_mcpdm_read(MCPDM_FIFO_CTRL_DN)); | ||
76 | dev_dbg(mcpdm->dev, "FIFO_CTRL_UP: 0x%04x\n", | ||
77 | omap_mcpdm_read(MCPDM_FIFO_CTRL_UP)); | ||
78 | dev_dbg(mcpdm->dev, "DN_OFFSET: 0x%04x\n", | ||
79 | omap_mcpdm_read(MCPDM_DN_OFFSET)); | ||
80 | dev_dbg(mcpdm->dev, "***********************\n"); | ||
81 | } | ||
82 | |||
83 | /* | ||
84 | * Takes the McPDM module in and out of reset state. | ||
85 | * Uplink and downlink can be reset individually. | ||
86 | */ | ||
87 | static void omap_mcpdm_reset_capture(int reset) | ||
88 | { | ||
89 | int ctrl = omap_mcpdm_read(MCPDM_CTRL); | ||
90 | |||
91 | if (reset) | ||
92 | ctrl |= SW_UP_RST; | ||
93 | else | ||
94 | ctrl &= ~SW_UP_RST; | ||
95 | |||
96 | omap_mcpdm_write(MCPDM_CTRL, ctrl); | ||
97 | } | ||
98 | |||
99 | static void omap_mcpdm_reset_playback(int reset) | ||
100 | { | ||
101 | int ctrl = omap_mcpdm_read(MCPDM_CTRL); | ||
102 | |||
103 | if (reset) | ||
104 | ctrl |= SW_DN_RST; | ||
105 | else | ||
106 | ctrl &= ~SW_DN_RST; | ||
107 | |||
108 | omap_mcpdm_write(MCPDM_CTRL, ctrl); | ||
109 | } | ||
110 | |||
111 | /* | ||
112 | * Enables the transfer through the PDM interface to/from the Phoenix | ||
113 | * codec by enabling the corresponding UP or DN channels. | ||
114 | */ | ||
115 | void omap_mcpdm_start(int stream) | ||
116 | { | ||
117 | int ctrl = omap_mcpdm_read(MCPDM_CTRL); | ||
118 | |||
119 | if (stream) | ||
120 | ctrl |= mcpdm->up_channels; | ||
121 | else | ||
122 | ctrl |= mcpdm->dn_channels; | ||
123 | |||
124 | omap_mcpdm_write(MCPDM_CTRL, ctrl); | ||
125 | } | ||
126 | |||
127 | /* | ||
128 | * Disables the transfer through the PDM interface to/from the Phoenix | ||
129 | * codec by disabling the corresponding UP or DN channels. | ||
130 | */ | ||
131 | void omap_mcpdm_stop(int stream) | ||
132 | { | ||
133 | int ctrl = omap_mcpdm_read(MCPDM_CTRL); | ||
134 | |||
135 | if (stream) | ||
136 | ctrl &= ~mcpdm->up_channels; | ||
137 | else | ||
138 | ctrl &= ~mcpdm->dn_channels; | ||
139 | |||
140 | omap_mcpdm_write(MCPDM_CTRL, ctrl); | ||
141 | } | ||
142 | |||
143 | /* | ||
144 | * Configures McPDM uplink for audio recording. | ||
145 | * This function should be called before omap_mcpdm_start. | ||
146 | */ | ||
147 | int omap_mcpdm_capture_open(struct omap_mcpdm_link *uplink) | ||
148 | { | ||
149 | int irq_mask = 0; | ||
150 | int ctrl; | ||
151 | |||
152 | if (!uplink) | ||
153 | return -EINVAL; | ||
154 | |||
155 | mcpdm->uplink = uplink; | ||
156 | |||
157 | /* Enable irq request generation */ | ||
158 | irq_mask |= uplink->irq_mask & MCPDM_UPLINK_IRQ_MASK; | ||
159 | omap_mcpdm_write(MCPDM_IRQENABLE_SET, irq_mask); | ||
160 | |||
161 | /* Configure uplink threshold */ | ||
162 | if (uplink->threshold > UP_THRES_MAX) | ||
163 | uplink->threshold = UP_THRES_MAX; | ||
164 | |||
165 | omap_mcpdm_write(MCPDM_FIFO_CTRL_UP, uplink->threshold); | ||
166 | |||
167 | /* Configure DMA controller */ | ||
168 | omap_mcpdm_write(MCPDM_DMAENABLE_SET, DMA_UP_ENABLE); | ||
169 | |||
170 | /* Set pdm out format */ | ||
171 | ctrl = omap_mcpdm_read(MCPDM_CTRL); | ||
172 | ctrl &= ~PDMOUTFORMAT; | ||
173 | ctrl |= uplink->format & PDMOUTFORMAT; | ||
174 | |||
175 | /* Uplink channels */ | ||
176 | mcpdm->up_channels = uplink->channels & (PDM_UP_MASK | PDM_STATUS_MASK); | ||
177 | |||
178 | omap_mcpdm_write(MCPDM_CTRL, ctrl); | ||
179 | |||
180 | return 0; | ||
181 | } | ||
182 | |||
183 | /* | ||
184 | * Configures McPDM downlink for audio playback. | ||
185 | * This function should be called before omap_mcpdm_start. | ||
186 | */ | ||
187 | int omap_mcpdm_playback_open(struct omap_mcpdm_link *downlink) | ||
188 | { | ||
189 | int irq_mask = 0; | ||
190 | int ctrl; | ||
191 | |||
192 | if (!downlink) | ||
193 | return -EINVAL; | ||
194 | |||
195 | mcpdm->downlink = downlink; | ||
196 | |||
197 | /* Enable irq request generation */ | ||
198 | irq_mask |= downlink->irq_mask & MCPDM_DOWNLINK_IRQ_MASK; | ||
199 | omap_mcpdm_write(MCPDM_IRQENABLE_SET, irq_mask); | ||
200 | |||
201 | /* Configure uplink threshold */ | ||
202 | if (downlink->threshold > DN_THRES_MAX) | ||
203 | downlink->threshold = DN_THRES_MAX; | ||
204 | |||
205 | omap_mcpdm_write(MCPDM_FIFO_CTRL_DN, downlink->threshold); | ||
206 | |||
207 | /* Enable DMA request generation */ | ||
208 | omap_mcpdm_write(MCPDM_DMAENABLE_SET, DMA_DN_ENABLE); | ||
209 | |||
210 | /* Set pdm out format */ | ||
211 | ctrl = omap_mcpdm_read(MCPDM_CTRL); | ||
212 | ctrl &= ~PDMOUTFORMAT; | ||
213 | ctrl |= downlink->format & PDMOUTFORMAT; | ||
214 | |||
215 | /* Downlink channels */ | ||
216 | mcpdm->dn_channels = downlink->channels & (PDM_DN_MASK | PDM_CMD_MASK); | ||
217 | |||
218 | omap_mcpdm_write(MCPDM_CTRL, ctrl); | ||
219 | |||
220 | return 0; | ||
221 | } | ||
222 | |||
223 | /* | ||
224 | * Cleans McPDM uplink configuration. | ||
225 | * This function should be called when the stream is closed. | ||
226 | */ | ||
227 | int omap_mcpdm_capture_close(struct omap_mcpdm_link *uplink) | ||
228 | { | ||
229 | int irq_mask = 0; | ||
230 | |||
231 | if (!uplink) | ||
232 | return -EINVAL; | ||
233 | |||
234 | /* Disable irq request generation */ | ||
235 | irq_mask |= uplink->irq_mask & MCPDM_UPLINK_IRQ_MASK; | ||
236 | omap_mcpdm_write(MCPDM_IRQENABLE_CLR, irq_mask); | ||
237 | |||
238 | /* Disable DMA request generation */ | ||
239 | omap_mcpdm_write(MCPDM_DMAENABLE_CLR, DMA_UP_ENABLE); | ||
240 | |||
241 | /* Clear Downlink channels */ | ||
242 | mcpdm->up_channels = 0; | ||
243 | |||
244 | mcpdm->uplink = NULL; | ||
245 | |||
246 | return 0; | ||
247 | } | ||
248 | |||
249 | /* | ||
250 | * Cleans McPDM downlink configuration. | ||
251 | * This function should be called when the stream is closed. | ||
252 | */ | ||
253 | int omap_mcpdm_playback_close(struct omap_mcpdm_link *downlink) | ||
254 | { | ||
255 | int irq_mask = 0; | ||
256 | |||
257 | if (!downlink) | ||
258 | return -EINVAL; | ||
259 | |||
260 | /* Disable irq request generation */ | ||
261 | irq_mask |= downlink->irq_mask & MCPDM_DOWNLINK_IRQ_MASK; | ||
262 | omap_mcpdm_write(MCPDM_IRQENABLE_CLR, irq_mask); | ||
263 | |||
264 | /* Disable DMA request generation */ | ||
265 | omap_mcpdm_write(MCPDM_DMAENABLE_CLR, DMA_DN_ENABLE); | ||
266 | |||
267 | /* clear Downlink channels */ | ||
268 | mcpdm->dn_channels = 0; | ||
269 | |||
270 | mcpdm->downlink = NULL; | ||
271 | |||
272 | return 0; | ||
273 | } | ||
274 | |||
275 | static irqreturn_t omap_mcpdm_irq_handler(int irq, void *dev_id) | ||
276 | { | ||
277 | struct omap_mcpdm *mcpdm_irq = dev_id; | ||
278 | int irq_status; | ||
279 | |||
280 | irq_status = omap_mcpdm_read(MCPDM_IRQSTATUS); | ||
281 | |||
282 | /* Acknowledge irq event */ | ||
283 | omap_mcpdm_write(MCPDM_IRQSTATUS, irq_status); | ||
284 | |||
285 | if (irq & MCPDM_DN_IRQ_FULL) { | ||
286 | dev_err(mcpdm_irq->dev, "DN FIFO error %x\n", irq_status); | ||
287 | omap_mcpdm_reset_playback(1); | ||
288 | omap_mcpdm_playback_open(mcpdm_irq->downlink); | ||
289 | omap_mcpdm_reset_playback(0); | ||
290 | } | ||
291 | |||
292 | if (irq & MCPDM_DN_IRQ_EMPTY) { | ||
293 | dev_err(mcpdm_irq->dev, "DN FIFO error %x\n", irq_status); | ||
294 | omap_mcpdm_reset_playback(1); | ||
295 | omap_mcpdm_playback_open(mcpdm_irq->downlink); | ||
296 | omap_mcpdm_reset_playback(0); | ||
297 | } | ||
298 | |||
299 | if (irq & MCPDM_DN_IRQ) { | ||
300 | dev_dbg(mcpdm_irq->dev, "DN write request\n"); | ||
301 | } | ||
302 | |||
303 | if (irq & MCPDM_UP_IRQ_FULL) { | ||
304 | dev_err(mcpdm_irq->dev, "UP FIFO error %x\n", irq_status); | ||
305 | omap_mcpdm_reset_capture(1); | ||
306 | omap_mcpdm_capture_open(mcpdm_irq->uplink); | ||
307 | omap_mcpdm_reset_capture(0); | ||
308 | } | ||
309 | |||
310 | if (irq & MCPDM_UP_IRQ_EMPTY) { | ||
311 | dev_err(mcpdm_irq->dev, "UP FIFO error %x\n", irq_status); | ||
312 | omap_mcpdm_reset_capture(1); | ||
313 | omap_mcpdm_capture_open(mcpdm_irq->uplink); | ||
314 | omap_mcpdm_reset_capture(0); | ||
315 | } | ||
316 | |||
317 | if (irq & MCPDM_UP_IRQ) { | ||
318 | dev_dbg(mcpdm_irq->dev, "UP write request\n"); | ||
319 | } | ||
320 | |||
321 | return IRQ_HANDLED; | ||
322 | } | ||
323 | |||
324 | int omap_mcpdm_request(void) | ||
325 | { | ||
326 | int ret; | ||
327 | |||
328 | clk_enable(mcpdm->clk); | ||
329 | |||
330 | spin_lock(&mcpdm->lock); | ||
331 | |||
332 | if (!mcpdm->free) { | ||
333 | dev_err(mcpdm->dev, "McPDM interface is in use\n"); | ||
334 | spin_unlock(&mcpdm->lock); | ||
335 | ret = -EBUSY; | ||
336 | goto err; | ||
337 | } | ||
338 | mcpdm->free = 0; | ||
339 | |||
340 | spin_unlock(&mcpdm->lock); | ||
341 | |||
342 | /* Disable lines while request is ongoing */ | ||
343 | omap_mcpdm_write(MCPDM_CTRL, 0x00); | ||
344 | |||
345 | ret = request_irq(mcpdm->irq, omap_mcpdm_irq_handler, | ||
346 | 0, "McPDM", (void *)mcpdm); | ||
347 | if (ret) { | ||
348 | dev_err(mcpdm->dev, "Request for McPDM IRQ failed\n"); | ||
349 | goto err; | ||
350 | } | ||
351 | |||
352 | return 0; | ||
353 | |||
354 | err: | ||
355 | clk_disable(mcpdm->clk); | ||
356 | return ret; | ||
357 | } | ||
358 | |||
359 | void omap_mcpdm_free(void) | ||
360 | { | ||
361 | spin_lock(&mcpdm->lock); | ||
362 | if (mcpdm->free) { | ||
363 | dev_err(mcpdm->dev, "McPDM interface is already free\n"); | ||
364 | spin_unlock(&mcpdm->lock); | ||
365 | return; | ||
366 | } | ||
367 | mcpdm->free = 1; | ||
368 | spin_unlock(&mcpdm->lock); | ||
369 | |||
370 | clk_disable(mcpdm->clk); | ||
371 | |||
372 | free_irq(mcpdm->irq, (void *)mcpdm); | ||
373 | } | ||
374 | |||
375 | /* Enable/disable DC offset cancelation for the analog | ||
376 | * headset path (PDM channels 1 and 2). | ||
377 | */ | ||
378 | int omap_mcpdm_set_offset(int offset1, int offset2) | ||
379 | { | ||
380 | int offset; | ||
381 | |||
382 | if ((offset1 > DN_OFST_MAX) || (offset2 > DN_OFST_MAX)) | ||
383 | return -EINVAL; | ||
384 | |||
385 | offset = (offset1 << DN_OFST_RX1) | (offset2 << DN_OFST_RX2); | ||
386 | |||
387 | /* offset cancellation for channel 1 */ | ||
388 | if (offset1) | ||
389 | offset |= DN_OFST_RX1_EN; | ||
390 | else | ||
391 | offset &= ~DN_OFST_RX1_EN; | ||
392 | |||
393 | /* offset cancellation for channel 2 */ | ||
394 | if (offset2) | ||
395 | offset |= DN_OFST_RX2_EN; | ||
396 | else | ||
397 | offset &= ~DN_OFST_RX2_EN; | ||
398 | |||
399 | omap_mcpdm_write(MCPDM_DN_OFFSET, offset); | ||
400 | |||
401 | return 0; | ||
402 | } | ||
403 | |||
404 | static int __devinit omap_mcpdm_probe(struct platform_device *pdev) | ||
405 | { | ||
406 | struct resource *res; | ||
407 | int ret = 0; | ||
408 | |||
409 | mcpdm = kzalloc(sizeof(struct omap_mcpdm), GFP_KERNEL); | ||
410 | if (!mcpdm) { | ||
411 | ret = -ENOMEM; | ||
412 | goto exit; | ||
413 | } | ||
414 | |||
415 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
416 | if (res == NULL) { | ||
417 | dev_err(&pdev->dev, "no resource\n"); | ||
418 | goto err_resource; | ||
419 | } | ||
420 | |||
421 | spin_lock_init(&mcpdm->lock); | ||
422 | mcpdm->free = 1; | ||
423 | mcpdm->io_base = ioremap(res->start, resource_size(res)); | ||
424 | if (!mcpdm->io_base) { | ||
425 | ret = -ENOMEM; | ||
426 | goto err_resource; | ||
427 | } | ||
428 | |||
429 | mcpdm->irq = platform_get_irq(pdev, 0); | ||
430 | |||
431 | mcpdm->clk = clk_get(&pdev->dev, "pdm_ck"); | ||
432 | if (IS_ERR(mcpdm->clk)) { | ||
433 | ret = PTR_ERR(mcpdm->clk); | ||
434 | dev_err(&pdev->dev, "unable to get pdm_ck: %d\n", ret); | ||
435 | goto err_clk; | ||
436 | } | ||
437 | |||
438 | mcpdm->dev = &pdev->dev; | ||
439 | platform_set_drvdata(pdev, mcpdm); | ||
440 | |||
441 | return 0; | ||
442 | |||
443 | err_clk: | ||
444 | iounmap(mcpdm->io_base); | ||
445 | err_resource: | ||
446 | kfree(mcpdm); | ||
447 | exit: | ||
448 | return ret; | ||
449 | } | ||
450 | |||
451 | static int __devexit omap_mcpdm_remove(struct platform_device *pdev) | ||
452 | { | ||
453 | struct omap_mcpdm *mcpdm_ptr = platform_get_drvdata(pdev); | ||
454 | |||
455 | platform_set_drvdata(pdev, NULL); | ||
456 | |||
457 | clk_put(mcpdm_ptr->clk); | ||
458 | |||
459 | iounmap(mcpdm_ptr->io_base); | ||
460 | |||
461 | mcpdm_ptr->clk = NULL; | ||
462 | mcpdm_ptr->free = 0; | ||
463 | mcpdm_ptr->dev = NULL; | ||
464 | |||
465 | kfree(mcpdm_ptr); | ||
466 | |||
467 | return 0; | ||
468 | } | ||
469 | |||
470 | static struct platform_driver omap_mcpdm_driver = { | ||
471 | .probe = omap_mcpdm_probe, | ||
472 | .remove = __devexit_p(omap_mcpdm_remove), | ||
473 | .driver = { | ||
474 | .name = "omap-mcpdm", | ||
475 | }, | ||
476 | }; | ||
477 | |||
478 | static struct platform_device *omap_mcpdm_device; | ||
479 | |||
480 | static int __init omap_mcpdm_init(void) | ||
481 | { | ||
482 | return platform_driver_register(&omap_mcpdm_driver); | ||
483 | } | ||
484 | arch_initcall(omap_mcpdm_init); | ||
diff --git a/sound/soc/omap/mcpdm.h b/sound/soc/omap/mcpdm.h new file mode 100644 index 000000000000..7bb326ef0886 --- /dev/null +++ b/sound/soc/omap/mcpdm.h | |||
@@ -0,0 +1,151 @@ | |||
1 | /* | ||
2 | * mcpdm.h -- Defines for McPDM driver | ||
3 | * | ||
4 | * Author: Jorge Eduardo Candelaria <x0107209@ti.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * version 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
18 | * 02110-1301 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | /* McPDM registers */ | ||
23 | |||
24 | #define MCPDM_REVISION 0x00 | ||
25 | #define MCPDM_SYSCONFIG 0x10 | ||
26 | #define MCPDM_IRQSTATUS_RAW 0x24 | ||
27 | #define MCPDM_IRQSTATUS 0x28 | ||
28 | #define MCPDM_IRQENABLE_SET 0x2C | ||
29 | #define MCPDM_IRQENABLE_CLR 0x30 | ||
30 | #define MCPDM_IRQWAKE_EN 0x34 | ||
31 | #define MCPDM_DMAENABLE_SET 0x38 | ||
32 | #define MCPDM_DMAENABLE_CLR 0x3C | ||
33 | #define MCPDM_DMAWAKEEN 0x40 | ||
34 | #define MCPDM_CTRL 0x44 | ||
35 | #define MCPDM_DN_DATA 0x48 | ||
36 | #define MCPDM_UP_DATA 0x4C | ||
37 | #define MCPDM_FIFO_CTRL_DN 0x50 | ||
38 | #define MCPDM_FIFO_CTRL_UP 0x54 | ||
39 | #define MCPDM_DN_OFFSET 0x58 | ||
40 | |||
41 | /* | ||
42 | * MCPDM_IRQ bit fields | ||
43 | * IRQSTATUS_RAW, IRQSTATUS, IRQENABLE_SET, IRQENABLE_CLR | ||
44 | */ | ||
45 | |||
46 | #define MCPDM_DN_IRQ (1 << 0) | ||
47 | #define MCPDM_DN_IRQ_EMPTY (1 << 1) | ||
48 | #define MCPDM_DN_IRQ_ALMST_EMPTY (1 << 2) | ||
49 | #define MCPDM_DN_IRQ_FULL (1 << 3) | ||
50 | |||
51 | #define MCPDM_UP_IRQ (1 << 8) | ||
52 | #define MCPDM_UP_IRQ_EMPTY (1 << 9) | ||
53 | #define MCPDM_UP_IRQ_ALMST_FULL (1 << 10) | ||
54 | #define MCPDM_UP_IRQ_FULL (1 << 11) | ||
55 | |||
56 | #define MCPDM_DOWNLINK_IRQ_MASK 0x00F | ||
57 | #define MCPDM_UPLINK_IRQ_MASK 0xF00 | ||
58 | |||
59 | /* | ||
60 | * MCPDM_DMAENABLE bit fields | ||
61 | */ | ||
62 | |||
63 | #define DMA_DN_ENABLE 0x1 | ||
64 | #define DMA_UP_ENABLE 0x2 | ||
65 | |||
66 | /* | ||
67 | * MCPDM_CTRL bit fields | ||
68 | */ | ||
69 | |||
70 | #define PDM_UP1_EN 0x0001 | ||
71 | #define PDM_UP2_EN 0x0002 | ||
72 | #define PDM_UP3_EN 0x0004 | ||
73 | #define PDM_DN1_EN 0x0008 | ||
74 | #define PDM_DN2_EN 0x0010 | ||
75 | #define PDM_DN3_EN 0x0020 | ||
76 | #define PDM_DN4_EN 0x0040 | ||
77 | #define PDM_DN5_EN 0x0080 | ||
78 | #define PDMOUTFORMAT 0x0100 | ||
79 | #define CMD_INT 0x0200 | ||
80 | #define STATUS_INT 0x0400 | ||
81 | #define SW_UP_RST 0x0800 | ||
82 | #define SW_DN_RST 0x1000 | ||
83 | #define PDM_UP_MASK 0x007 | ||
84 | #define PDM_DN_MASK 0x0F8 | ||
85 | #define PDM_CMD_MASK 0x200 | ||
86 | #define PDM_STATUS_MASK 0x400 | ||
87 | |||
88 | |||
89 | #define PDMOUTFORMAT_LJUST (0 << 8) | ||
90 | #define PDMOUTFORMAT_RJUST (1 << 8) | ||
91 | |||
92 | /* | ||
93 | * MCPDM_FIFO_CTRL bit fields | ||
94 | */ | ||
95 | |||
96 | #define UP_THRES_MAX 0xF | ||
97 | #define DN_THRES_MAX 0xF | ||
98 | |||
99 | /* | ||
100 | * MCPDM_DN_OFFSET bit fields | ||
101 | */ | ||
102 | |||
103 | #define DN_OFST_RX1_EN 0x0001 | ||
104 | #define DN_OFST_RX2_EN 0x0100 | ||
105 | |||
106 | #define DN_OFST_RX1 1 | ||
107 | #define DN_OFST_RX2 9 | ||
108 | #define DN_OFST_MAX 0x1F | ||
109 | |||
110 | #define MCPDM_UPLINK 1 | ||
111 | #define MCPDM_DOWNLINK 2 | ||
112 | |||
113 | struct omap_mcpdm_link { | ||
114 | int irq_mask; | ||
115 | int threshold; | ||
116 | int format; | ||
117 | int channels; | ||
118 | }; | ||
119 | |||
120 | struct omap_mcpdm_platform_data { | ||
121 | unsigned long phys_base; | ||
122 | u16 irq; | ||
123 | }; | ||
124 | |||
125 | struct omap_mcpdm { | ||
126 | struct device *dev; | ||
127 | unsigned long phys_base; | ||
128 | void __iomem *io_base; | ||
129 | u8 free; | ||
130 | int irq; | ||
131 | |||
132 | spinlock_t lock; | ||
133 | struct omap_mcpdm_platform_data *pdata; | ||
134 | struct clk *clk; | ||
135 | struct omap_mcpdm_link *downlink; | ||
136 | struct omap_mcpdm_link *uplink; | ||
137 | struct completion irq_completion; | ||
138 | |||
139 | int dn_channels; | ||
140 | int up_channels; | ||
141 | }; | ||
142 | |||
143 | extern void omap_mcpdm_start(int stream); | ||
144 | extern void omap_mcpdm_stop(int stream); | ||
145 | extern int omap_mcpdm_capture_open(struct omap_mcpdm_link *uplink); | ||
146 | extern int omap_mcpdm_playback_open(struct omap_mcpdm_link *downlink); | ||
147 | extern int omap_mcpdm_capture_close(struct omap_mcpdm_link *uplink); | ||
148 | extern int omap_mcpdm_playback_close(struct omap_mcpdm_link *downlink); | ||
149 | extern int omap_mcpdm_request(void); | ||
150 | extern void omap_mcpdm_free(void); | ||
151 | extern int omap_mcpdm_set_offset(int offset1, int offset2); | ||
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index 6bbbd2ab0ee7..e814a9591f78 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c | |||
@@ -39,6 +39,14 @@ | |||
39 | 39 | ||
40 | #define OMAP_MCBSP_RATES (SNDRV_PCM_RATE_8000_96000) | 40 | #define OMAP_MCBSP_RATES (SNDRV_PCM_RATE_8000_96000) |
41 | 41 | ||
42 | #define OMAP_MCBSP_SOC_SINGLE_S16_EXT(xname, xmin, xmax, \ | ||
43 | xhandler_get, xhandler_put) \ | ||
44 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | ||
45 | .info = omap_mcbsp_st_info_volsw, \ | ||
46 | .get = xhandler_get, .put = xhandler_put, \ | ||
47 | .private_value = (unsigned long) &(struct soc_mixer_control) \ | ||
48 | {.min = xmin, .max = xmax} } | ||
49 | |||
42 | struct omap_mcbsp_data { | 50 | struct omap_mcbsp_data { |
43 | unsigned int bus_id; | 51 | unsigned int bus_id; |
44 | struct omap_mcbsp_reg_cfg regs; | 52 | struct omap_mcbsp_reg_cfg regs; |
@@ -82,11 +90,11 @@ static const int omap1_dma_reqs[][2] = {}; | |||
82 | static const unsigned long omap1_mcbsp_port[][2] = {}; | 90 | static const unsigned long omap1_mcbsp_port[][2] = {}; |
83 | #endif | 91 | #endif |
84 | 92 | ||
85 | #if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) | 93 | #if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) |
86 | static const int omap24xx_dma_reqs[][2] = { | 94 | static const int omap24xx_dma_reqs[][2] = { |
87 | { OMAP24XX_DMA_MCBSP1_TX, OMAP24XX_DMA_MCBSP1_RX }, | 95 | { OMAP24XX_DMA_MCBSP1_TX, OMAP24XX_DMA_MCBSP1_RX }, |
88 | { OMAP24XX_DMA_MCBSP2_TX, OMAP24XX_DMA_MCBSP2_RX }, | 96 | { OMAP24XX_DMA_MCBSP2_TX, OMAP24XX_DMA_MCBSP2_RX }, |
89 | #if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP34XX) | 97 | #if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) |
90 | { OMAP24XX_DMA_MCBSP3_TX, OMAP24XX_DMA_MCBSP3_RX }, | 98 | { OMAP24XX_DMA_MCBSP3_TX, OMAP24XX_DMA_MCBSP3_RX }, |
91 | { OMAP24XX_DMA_MCBSP4_TX, OMAP24XX_DMA_MCBSP4_RX }, | 99 | { OMAP24XX_DMA_MCBSP4_TX, OMAP24XX_DMA_MCBSP4_RX }, |
92 | { OMAP24XX_DMA_MCBSP5_TX, OMAP24XX_DMA_MCBSP5_RX }, | 100 | { OMAP24XX_DMA_MCBSP5_TX, OMAP24XX_DMA_MCBSP5_RX }, |
@@ -124,7 +132,7 @@ static const unsigned long omap2430_mcbsp_port[][2] = { | |||
124 | static const unsigned long omap2430_mcbsp_port[][2] = {}; | 132 | static const unsigned long omap2430_mcbsp_port[][2] = {}; |
125 | #endif | 133 | #endif |
126 | 134 | ||
127 | #if defined(CONFIG_ARCH_OMAP34XX) | 135 | #if defined(CONFIG_ARCH_OMAP3) |
128 | static const unsigned long omap34xx_mcbsp_port[][2] = { | 136 | static const unsigned long omap34xx_mcbsp_port[][2] = { |
129 | { OMAP34XX_MCBSP1_BASE + OMAP_MCBSP_REG_DXR, | 137 | { OMAP34XX_MCBSP1_BASE + OMAP_MCBSP_REG_DXR, |
130 | OMAP34XX_MCBSP1_BASE + OMAP_MCBSP_REG_DRR }, | 138 | OMAP34XX_MCBSP1_BASE + OMAP_MCBSP_REG_DRR }, |
@@ -287,6 +295,8 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, | |||
287 | omap_mcbsp_dai_dma_params[id][substream->stream].dma_req = dma; | 295 | omap_mcbsp_dai_dma_params[id][substream->stream].dma_req = dma; |
288 | omap_mcbsp_dai_dma_params[id][substream->stream].port_addr = port; | 296 | omap_mcbsp_dai_dma_params[id][substream->stream].port_addr = port; |
289 | omap_mcbsp_dai_dma_params[id][substream->stream].sync_mode = sync_mode; | 297 | omap_mcbsp_dai_dma_params[id][substream->stream].sync_mode = sync_mode; |
298 | omap_mcbsp_dai_dma_params[id][substream->stream].data_type = | ||
299 | OMAP_DMA_DATA_TYPE_S16; | ||
290 | cpu_dai->dma_data = &omap_mcbsp_dai_dma_params[id][substream->stream]; | 300 | cpu_dai->dma_data = &omap_mcbsp_dai_dma_params[id][substream->stream]; |
291 | 301 | ||
292 | if (mcbsp_data->configured) { | 302 | if (mcbsp_data->configured) { |
@@ -637,6 +647,136 @@ struct snd_soc_dai omap_mcbsp_dai[] = { | |||
637 | 647 | ||
638 | EXPORT_SYMBOL_GPL(omap_mcbsp_dai); | 648 | EXPORT_SYMBOL_GPL(omap_mcbsp_dai); |
639 | 649 | ||
650 | int omap_mcbsp_st_info_volsw(struct snd_kcontrol *kcontrol, | ||
651 | struct snd_ctl_elem_info *uinfo) | ||
652 | { | ||
653 | struct soc_mixer_control *mc = | ||
654 | (struct soc_mixer_control *)kcontrol->private_value; | ||
655 | int max = mc->max; | ||
656 | int min = mc->min; | ||
657 | |||
658 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
659 | uinfo->count = 1; | ||
660 | uinfo->value.integer.min = min; | ||
661 | uinfo->value.integer.max = max; | ||
662 | return 0; | ||
663 | } | ||
664 | |||
665 | #define OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(id, channel) \ | ||
666 | static int \ | ||
667 | omap_mcbsp##id##_set_st_ch##channel##_volume(struct snd_kcontrol *kc, \ | ||
668 | struct snd_ctl_elem_value *uc) \ | ||
669 | { \ | ||
670 | struct soc_mixer_control *mc = \ | ||
671 | (struct soc_mixer_control *)kc->private_value; \ | ||
672 | int max = mc->max; \ | ||
673 | int min = mc->min; \ | ||
674 | int val = uc->value.integer.value[0]; \ | ||
675 | \ | ||
676 | if (val < min || val > max) \ | ||
677 | return -EINVAL; \ | ||
678 | \ | ||
679 | /* OMAP McBSP implementation uses index values 0..4 */ \ | ||
680 | return omap_st_set_chgain((id)-1, channel, val); \ | ||
681 | } | ||
682 | |||
683 | #define OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(id, channel) \ | ||
684 | static int \ | ||
685 | omap_mcbsp##id##_get_st_ch##channel##_volume(struct snd_kcontrol *kc, \ | ||
686 | struct snd_ctl_elem_value *uc) \ | ||
687 | { \ | ||
688 | s16 chgain; \ | ||
689 | \ | ||
690 | if (omap_st_get_chgain((id)-1, channel, &chgain)) \ | ||
691 | return -EAGAIN; \ | ||
692 | \ | ||
693 | uc->value.integer.value[0] = chgain; \ | ||
694 | return 0; \ | ||
695 | } | ||
696 | |||
697 | OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(2, 0) | ||
698 | OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(2, 1) | ||
699 | OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(3, 0) | ||
700 | OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(3, 1) | ||
701 | OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(2, 0) | ||
702 | OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(2, 1) | ||
703 | OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(3, 0) | ||
704 | OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(3, 1) | ||
705 | |||
706 | static int omap_mcbsp_st_put_mode(struct snd_kcontrol *kcontrol, | ||
707 | struct snd_ctl_elem_value *ucontrol) | ||
708 | { | ||
709 | struct soc_mixer_control *mc = | ||
710 | (struct soc_mixer_control *)kcontrol->private_value; | ||
711 | u8 value = ucontrol->value.integer.value[0]; | ||
712 | |||
713 | if (value == omap_st_is_enabled(mc->reg)) | ||
714 | return 0; | ||
715 | |||
716 | if (value) | ||
717 | omap_st_enable(mc->reg); | ||
718 | else | ||
719 | omap_st_disable(mc->reg); | ||
720 | |||
721 | return 1; | ||
722 | } | ||
723 | |||
724 | static int omap_mcbsp_st_get_mode(struct snd_kcontrol *kcontrol, | ||
725 | struct snd_ctl_elem_value *ucontrol) | ||
726 | { | ||
727 | struct soc_mixer_control *mc = | ||
728 | (struct soc_mixer_control *)kcontrol->private_value; | ||
729 | |||
730 | ucontrol->value.integer.value[0] = omap_st_is_enabled(mc->reg); | ||
731 | return 0; | ||
732 | } | ||
733 | |||
734 | static const struct snd_kcontrol_new omap_mcbsp2_st_controls[] = { | ||
735 | SOC_SINGLE_EXT("McBSP2 Sidetone Switch", 1, 0, 1, 0, | ||
736 | omap_mcbsp_st_get_mode, omap_mcbsp_st_put_mode), | ||
737 | OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP2 Sidetone Channel 0 Volume", | ||
738 | -32768, 32767, | ||
739 | omap_mcbsp2_get_st_ch0_volume, | ||
740 | omap_mcbsp2_set_st_ch0_volume), | ||
741 | OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP2 Sidetone Channel 1 Volume", | ||
742 | -32768, 32767, | ||
743 | omap_mcbsp2_get_st_ch1_volume, | ||
744 | omap_mcbsp2_set_st_ch1_volume), | ||
745 | }; | ||
746 | |||
747 | static const struct snd_kcontrol_new omap_mcbsp3_st_controls[] = { | ||
748 | SOC_SINGLE_EXT("McBSP3 Sidetone Switch", 2, 0, 1, 0, | ||
749 | omap_mcbsp_st_get_mode, omap_mcbsp_st_put_mode), | ||
750 | OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP3 Sidetone Channel 0 Volume", | ||
751 | -32768, 32767, | ||
752 | omap_mcbsp3_get_st_ch0_volume, | ||
753 | omap_mcbsp3_set_st_ch0_volume), | ||
754 | OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP3 Sidetone Channel 1 Volume", | ||
755 | -32768, 32767, | ||
756 | omap_mcbsp3_get_st_ch1_volume, | ||
757 | omap_mcbsp3_set_st_ch1_volume), | ||
758 | }; | ||
759 | |||
760 | int omap_mcbsp_st_add_controls(struct snd_soc_codec *codec, int mcbsp_id) | ||
761 | { | ||
762 | if (!cpu_is_omap34xx()) | ||
763 | return -ENODEV; | ||
764 | |||
765 | switch (mcbsp_id) { | ||
766 | case 1: /* McBSP 2 */ | ||
767 | return snd_soc_add_controls(codec, omap_mcbsp2_st_controls, | ||
768 | ARRAY_SIZE(omap_mcbsp2_st_controls)); | ||
769 | case 2: /* McBSP 3 */ | ||
770 | return snd_soc_add_controls(codec, omap_mcbsp3_st_controls, | ||
771 | ARRAY_SIZE(omap_mcbsp3_st_controls)); | ||
772 | default: | ||
773 | break; | ||
774 | } | ||
775 | |||
776 | return -EINVAL; | ||
777 | } | ||
778 | EXPORT_SYMBOL_GPL(omap_mcbsp_st_add_controls); | ||
779 | |||
640 | static int __init snd_omap_mcbsp_init(void) | 780 | static int __init snd_omap_mcbsp_init(void) |
641 | { | 781 | { |
642 | return snd_soc_register_dais(omap_mcbsp_dai, | 782 | return snd_soc_register_dais(omap_mcbsp_dai, |
diff --git a/sound/soc/omap/omap-mcbsp.h b/sound/soc/omap/omap-mcbsp.h index 647d2f981ab0..6c363e5f4387 100644 --- a/sound/soc/omap/omap-mcbsp.h +++ b/sound/soc/omap/omap-mcbsp.h | |||
@@ -50,11 +50,13 @@ enum omap_mcbsp_div { | |||
50 | #undef NUM_LINKS | 50 | #undef NUM_LINKS |
51 | #define NUM_LINKS 3 | 51 | #define NUM_LINKS 3 |
52 | #endif | 52 | #endif |
53 | #if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP34XX) | 53 | #if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) |
54 | #undef NUM_LINKS | 54 | #undef NUM_LINKS |
55 | #define NUM_LINKS 5 | 55 | #define NUM_LINKS 5 |
56 | #endif | 56 | #endif |
57 | 57 | ||
58 | extern struct snd_soc_dai omap_mcbsp_dai[NUM_LINKS]; | 58 | extern struct snd_soc_dai omap_mcbsp_dai[NUM_LINKS]; |
59 | 59 | ||
60 | int omap_mcbsp_st_add_controls(struct snd_soc_codec *codec, int mcbsp_id); | ||
61 | |||
60 | #endif | 62 | #endif |
diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/omap/omap-mcpdm.c new file mode 100644 index 000000000000..25f19e4728bf --- /dev/null +++ b/sound/soc/omap/omap-mcpdm.c | |||
@@ -0,0 +1,251 @@ | |||
1 | /* | ||
2 | * omap-mcpdm.c -- OMAP ALSA SoC DAI driver using McPDM port | ||
3 | * | ||
4 | * Copyright (C) 2009 Texas Instruments | ||
5 | * | ||
6 | * Author: Misael Lopez Cruz <x0052729@ti.com> | ||
7 | * Contact: Jorge Eduardo Candelaria <x0107209@ti.com> | ||
8 | * Margarita Olaya <magi.olaya@ti.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or | ||
11 | * modify it under the terms of the GNU General Public License | ||
12 | * version 2 as published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * 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., 51 Franklin St, Fifth Floor, Boston, MA | ||
22 | * 02110-1301 USA | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | #include <linux/init.h> | ||
27 | #include <linux/module.h> | ||
28 | #include <linux/device.h> | ||
29 | #include <sound/core.h> | ||
30 | #include <sound/pcm.h> | ||
31 | #include <sound/pcm_params.h> | ||
32 | #include <sound/initval.h> | ||
33 | #include <sound/soc.h> | ||
34 | |||
35 | #include <plat/control.h> | ||
36 | #include <plat/dma.h> | ||
37 | #include <plat/mcbsp.h> | ||
38 | #include "mcpdm.h" | ||
39 | #include "omap-mcpdm.h" | ||
40 | #include "omap-pcm.h" | ||
41 | |||
42 | struct omap_mcpdm_data { | ||
43 | struct omap_mcpdm_link *links; | ||
44 | int active; | ||
45 | }; | ||
46 | |||
47 | static struct omap_mcpdm_link omap_mcpdm_links[] = { | ||
48 | /* downlink */ | ||
49 | { | ||
50 | .irq_mask = MCPDM_DN_IRQ_EMPTY | MCPDM_DN_IRQ_FULL, | ||
51 | .threshold = 1, | ||
52 | .format = PDMOUTFORMAT_LJUST, | ||
53 | }, | ||
54 | /* uplink */ | ||
55 | { | ||
56 | .irq_mask = MCPDM_UP_IRQ_EMPTY | MCPDM_UP_IRQ_FULL, | ||
57 | .threshold = 1, | ||
58 | .format = PDMOUTFORMAT_LJUST, | ||
59 | }, | ||
60 | }; | ||
61 | |||
62 | static struct omap_mcpdm_data mcpdm_data = { | ||
63 | .links = omap_mcpdm_links, | ||
64 | .active = 0, | ||
65 | }; | ||
66 | |||
67 | /* | ||
68 | * Stream DMA parameters | ||
69 | */ | ||
70 | static struct omap_pcm_dma_data omap_mcpdm_dai_dma_params[] = { | ||
71 | { | ||
72 | .name = "Audio playback", | ||
73 | .dma_req = OMAP44XX_DMA_MCPDM_DL, | ||
74 | .data_type = OMAP_DMA_DATA_TYPE_S32, | ||
75 | .sync_mode = OMAP_DMA_SYNC_PACKET, | ||
76 | .packet_size = 16, | ||
77 | .port_addr = OMAP44XX_MCPDM_L3_BASE + MCPDM_DN_DATA, | ||
78 | }, | ||
79 | { | ||
80 | .name = "Audio capture", | ||
81 | .dma_req = OMAP44XX_DMA_MCPDM_UP, | ||
82 | .data_type = OMAP_DMA_DATA_TYPE_S32, | ||
83 | .sync_mode = OMAP_DMA_SYNC_PACKET, | ||
84 | .packet_size = 16, | ||
85 | .port_addr = OMAP44XX_MCPDM_L3_BASE + MCPDM_UP_DATA, | ||
86 | }, | ||
87 | }; | ||
88 | |||
89 | static int omap_mcpdm_dai_startup(struct snd_pcm_substream *substream, | ||
90 | struct snd_soc_dai *dai) | ||
91 | { | ||
92 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
93 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | ||
94 | int err = 0; | ||
95 | |||
96 | if (!cpu_dai->active) | ||
97 | err = omap_mcpdm_request(); | ||
98 | |||
99 | return err; | ||
100 | } | ||
101 | |||
102 | static void omap_mcpdm_dai_shutdown(struct snd_pcm_substream *substream, | ||
103 | struct snd_soc_dai *dai) | ||
104 | { | ||
105 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
106 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | ||
107 | |||
108 | if (!cpu_dai->active) | ||
109 | omap_mcpdm_free(); | ||
110 | } | ||
111 | |||
112 | static int omap_mcpdm_dai_trigger(struct snd_pcm_substream *substream, int cmd, | ||
113 | struct snd_soc_dai *dai) | ||
114 | { | ||
115 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
116 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | ||
117 | struct omap_mcpdm_data *mcpdm_priv = cpu_dai->private_data; | ||
118 | int stream = substream->stream; | ||
119 | int err = 0; | ||
120 | |||
121 | switch (cmd) { | ||
122 | case SNDRV_PCM_TRIGGER_START: | ||
123 | case SNDRV_PCM_TRIGGER_RESUME: | ||
124 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
125 | if (!mcpdm_priv->active++) | ||
126 | omap_mcpdm_start(stream); | ||
127 | break; | ||
128 | |||
129 | case SNDRV_PCM_TRIGGER_STOP: | ||
130 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
131 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
132 | if (!--mcpdm_priv->active) | ||
133 | omap_mcpdm_stop(stream); | ||
134 | break; | ||
135 | default: | ||
136 | err = -EINVAL; | ||
137 | } | ||
138 | |||
139 | return err; | ||
140 | } | ||
141 | |||
142 | static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream, | ||
143 | struct snd_pcm_hw_params *params, | ||
144 | struct snd_soc_dai *dai) | ||
145 | { | ||
146 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
147 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | ||
148 | struct omap_mcpdm_data *mcpdm_priv = cpu_dai->private_data; | ||
149 | struct omap_mcpdm_link *mcpdm_links = mcpdm_priv->links; | ||
150 | int stream = substream->stream; | ||
151 | int channels, err, link_mask = 0; | ||
152 | |||
153 | cpu_dai->dma_data = &omap_mcpdm_dai_dma_params[stream]; | ||
154 | |||
155 | channels = params_channels(params); | ||
156 | switch (channels) { | ||
157 | case 4: | ||
158 | if (stream == SNDRV_PCM_STREAM_CAPTURE) | ||
159 | /* up to 2 channels for capture */ | ||
160 | return -EINVAL; | ||
161 | link_mask |= 1 << 3; | ||
162 | case 3: | ||
163 | if (stream == SNDRV_PCM_STREAM_CAPTURE) | ||
164 | /* up to 2 channels for capture */ | ||
165 | return -EINVAL; | ||
166 | link_mask |= 1 << 2; | ||
167 | case 2: | ||
168 | link_mask |= 1 << 1; | ||
169 | case 1: | ||
170 | link_mask |= 1 << 0; | ||
171 | break; | ||
172 | default: | ||
173 | /* unsupported number of channels */ | ||
174 | return -EINVAL; | ||
175 | } | ||
176 | |||
177 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
178 | mcpdm_links[stream].channels = link_mask << 3; | ||
179 | err = omap_mcpdm_playback_open(&mcpdm_links[stream]); | ||
180 | } else { | ||
181 | mcpdm_links[stream].channels = link_mask << 0; | ||
182 | err = omap_mcpdm_capture_open(&mcpdm_links[stream]); | ||
183 | } | ||
184 | |||
185 | return err; | ||
186 | } | ||
187 | |||
188 | static int omap_mcpdm_dai_hw_free(struct snd_pcm_substream *substream, | ||
189 | struct snd_soc_dai *dai) | ||
190 | { | ||
191 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
192 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | ||
193 | struct omap_mcpdm_data *mcpdm_priv = cpu_dai->private_data; | ||
194 | struct omap_mcpdm_link *mcpdm_links = mcpdm_priv->links; | ||
195 | int stream = substream->stream; | ||
196 | int err; | ||
197 | |||
198 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
199 | err = omap_mcpdm_playback_close(&mcpdm_links[stream]); | ||
200 | else | ||
201 | err = omap_mcpdm_capture_close(&mcpdm_links[stream]); | ||
202 | |||
203 | return err; | ||
204 | } | ||
205 | |||
206 | static struct snd_soc_dai_ops omap_mcpdm_dai_ops = { | ||
207 | .startup = omap_mcpdm_dai_startup, | ||
208 | .shutdown = omap_mcpdm_dai_shutdown, | ||
209 | .trigger = omap_mcpdm_dai_trigger, | ||
210 | .hw_params = omap_mcpdm_dai_hw_params, | ||
211 | .hw_free = omap_mcpdm_dai_hw_free, | ||
212 | }; | ||
213 | |||
214 | #define OMAP_MCPDM_RATES (SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) | ||
215 | #define OMAP_MCPDM_FORMATS (SNDRV_PCM_FMTBIT_S32_LE) | ||
216 | |||
217 | struct snd_soc_dai omap_mcpdm_dai = { | ||
218 | .name = "omap-mcpdm", | ||
219 | .id = -1, | ||
220 | .playback = { | ||
221 | .channels_min = 1, | ||
222 | .channels_max = 4, | ||
223 | .rates = OMAP_MCPDM_RATES, | ||
224 | .formats = OMAP_MCPDM_FORMATS, | ||
225 | }, | ||
226 | .capture = { | ||
227 | .channels_min = 1, | ||
228 | .channels_max = 2, | ||
229 | .rates = OMAP_MCPDM_RATES, | ||
230 | .formats = OMAP_MCPDM_FORMATS, | ||
231 | }, | ||
232 | .ops = &omap_mcpdm_dai_ops, | ||
233 | .private_data = &mcpdm_data, | ||
234 | }; | ||
235 | EXPORT_SYMBOL_GPL(omap_mcpdm_dai); | ||
236 | |||
237 | static int __init snd_omap_mcpdm_init(void) | ||
238 | { | ||
239 | return snd_soc_register_dai(&omap_mcpdm_dai); | ||
240 | } | ||
241 | module_init(snd_omap_mcpdm_init); | ||
242 | |||
243 | static void __exit snd_omap_mcpdm_exit(void) | ||
244 | { | ||
245 | snd_soc_unregister_dai(&omap_mcpdm_dai); | ||
246 | } | ||
247 | module_exit(snd_omap_mcpdm_exit); | ||
248 | |||
249 | MODULE_AUTHOR("Misael Lopez Cruz <x0052729@ti.com>"); | ||
250 | MODULE_DESCRIPTION("OMAP PDM SoC Interface"); | ||
251 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/omap/omap-mcpdm.h b/sound/soc/omap/omap-mcpdm.h new file mode 100644 index 000000000000..73b80d559345 --- /dev/null +++ b/sound/soc/omap/omap-mcpdm.h | |||
@@ -0,0 +1,29 @@ | |||
1 | /* | ||
2 | * omap-mcpdm.h | ||
3 | * | ||
4 | * Copyright (C) 2009 Texas Instruments | ||
5 | * | ||
6 | * Contact: Misael Lopez Cruz <x0052729@ti.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #ifndef __OMAP_MCPDM_H__ | ||
25 | #define __OMAP_MCPDM_H__ | ||
26 | |||
27 | extern struct snd_soc_dai omap_mcpdm_dai; | ||
28 | |||
29 | #endif /* End of __OMAP_MCPDM_H__ */ | ||
diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c index 9db2770e9640..825db385f01f 100644 --- a/sound/soc/omap/omap-pcm.c +++ b/sound/soc/omap/omap-pcm.c | |||
@@ -37,7 +37,8 @@ static const struct snd_pcm_hardware omap_pcm_hardware = { | |||
37 | SNDRV_PCM_INFO_INTERLEAVED | | 37 | SNDRV_PCM_INFO_INTERLEAVED | |
38 | SNDRV_PCM_INFO_PAUSE | | 38 | SNDRV_PCM_INFO_PAUSE | |
39 | SNDRV_PCM_INFO_RESUME, | 39 | SNDRV_PCM_INFO_RESUME, |
40 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | 40 | .formats = SNDRV_PCM_FMTBIT_S16_LE | |
41 | SNDRV_PCM_FMTBIT_S32_LE, | ||
41 | .period_bytes_min = 32, | 42 | .period_bytes_min = 32, |
42 | .period_bytes_max = 64 * 1024, | 43 | .period_bytes_max = 64 * 1024, |
43 | .periods_min = 2, | 44 | .periods_min = 2, |
@@ -149,6 +150,7 @@ static int omap_pcm_prepare(struct snd_pcm_substream *substream) | |||
149 | struct omap_runtime_data *prtd = runtime->private_data; | 150 | struct omap_runtime_data *prtd = runtime->private_data; |
150 | struct omap_pcm_dma_data *dma_data = prtd->dma_data; | 151 | struct omap_pcm_dma_data *dma_data = prtd->dma_data; |
151 | struct omap_dma_channel_params dma_params; | 152 | struct omap_dma_channel_params dma_params; |
153 | int bytes; | ||
152 | 154 | ||
153 | /* return if this is a bufferless transfer e.g. | 155 | /* return if this is a bufferless transfer e.g. |
154 | * codec <--> BT codec or GSM modem -- lg FIXME */ | 156 | * codec <--> BT codec or GSM modem -- lg FIXME */ |
@@ -156,11 +158,7 @@ static int omap_pcm_prepare(struct snd_pcm_substream *substream) | |||
156 | return 0; | 158 | return 0; |
157 | 159 | ||
158 | memset(&dma_params, 0, sizeof(dma_params)); | 160 | memset(&dma_params, 0, sizeof(dma_params)); |
159 | /* | 161 | dma_params.data_type = dma_data->data_type; |
160 | * Note: Regardless of interface data formats supported by OMAP McBSP | ||
161 | * or EAC blocks, internal representation is always fixed 16-bit/sample | ||
162 | */ | ||
163 | dma_params.data_type = OMAP_DMA_DATA_TYPE_S16; | ||
164 | dma_params.trigger = dma_data->dma_req; | 162 | dma_params.trigger = dma_data->dma_req; |
165 | dma_params.sync_mode = dma_data->sync_mode; | 163 | dma_params.sync_mode = dma_data->sync_mode; |
166 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 164 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
@@ -170,6 +168,7 @@ static int omap_pcm_prepare(struct snd_pcm_substream *substream) | |||
170 | dma_params.src_start = runtime->dma_addr; | 168 | dma_params.src_start = runtime->dma_addr; |
171 | dma_params.dst_start = dma_data->port_addr; | 169 | dma_params.dst_start = dma_data->port_addr; |
172 | dma_params.dst_port = OMAP_DMA_PORT_MPUI; | 170 | dma_params.dst_port = OMAP_DMA_PORT_MPUI; |
171 | dma_params.dst_fi = dma_data->packet_size; | ||
173 | } else { | 172 | } else { |
174 | dma_params.src_amode = OMAP_DMA_AMODE_CONSTANT; | 173 | dma_params.src_amode = OMAP_DMA_AMODE_CONSTANT; |
175 | dma_params.dst_amode = OMAP_DMA_AMODE_POST_INC; | 174 | dma_params.dst_amode = OMAP_DMA_AMODE_POST_INC; |
@@ -177,6 +176,7 @@ static int omap_pcm_prepare(struct snd_pcm_substream *substream) | |||
177 | dma_params.src_start = dma_data->port_addr; | 176 | dma_params.src_start = dma_data->port_addr; |
178 | dma_params.dst_start = runtime->dma_addr; | 177 | dma_params.dst_start = runtime->dma_addr; |
179 | dma_params.src_port = OMAP_DMA_PORT_MPUI; | 178 | dma_params.src_port = OMAP_DMA_PORT_MPUI; |
179 | dma_params.src_fi = dma_data->packet_size; | ||
180 | } | 180 | } |
181 | /* | 181 | /* |
182 | * Set DMA transfer frame size equal to ALSA period size and frame | 182 | * Set DMA transfer frame size equal to ALSA period size and frame |
@@ -184,7 +184,8 @@ static int omap_pcm_prepare(struct snd_pcm_substream *substream) | |||
184 | * we can transfer the whole ALSA buffer with single DMA transfer but | 184 | * we can transfer the whole ALSA buffer with single DMA transfer but |
185 | * still can get an interrupt at each period bounary | 185 | * still can get an interrupt at each period bounary |
186 | */ | 186 | */ |
187 | dma_params.elem_count = snd_pcm_lib_period_bytes(substream) / 2; | 187 | bytes = snd_pcm_lib_period_bytes(substream); |
188 | dma_params.elem_count = bytes >> dma_data->data_type; | ||
188 | dma_params.frame_count = runtime->periods; | 189 | dma_params.frame_count = runtime->periods; |
189 | omap_set_dma_params(prtd->dma_ch, &dma_params); | 190 | omap_set_dma_params(prtd->dma_ch, &dma_params); |
190 | 191 | ||
diff --git a/sound/soc/omap/omap-pcm.h b/sound/soc/omap/omap-pcm.h index 38a821dd4118..b19975d26907 100644 --- a/sound/soc/omap/omap-pcm.h +++ b/sound/soc/omap/omap-pcm.h | |||
@@ -29,8 +29,10 @@ struct omap_pcm_dma_data { | |||
29 | char *name; /* stream identifier */ | 29 | char *name; /* stream identifier */ |
30 | int dma_req; /* DMA request line */ | 30 | int dma_req; /* DMA request line */ |
31 | unsigned long port_addr; /* transmit/receive register */ | 31 | unsigned long port_addr; /* transmit/receive register */ |
32 | int sync_mode; /* DMA sync mode */ | ||
33 | void (*set_threshold)(struct snd_pcm_substream *substream); | 32 | void (*set_threshold)(struct snd_pcm_substream *substream); |
33 | int data_type; /* data type 8,16,32 */ | ||
34 | int sync_mode; /* DMA sync mode */ | ||
35 | int packet_size; /* packet size only in PACKET mode */ | ||
34 | }; | 36 | }; |
35 | 37 | ||
36 | extern struct snd_soc_platform omap_soc_platform; | 38 | extern struct snd_soc_platform omap_soc_platform; |
diff --git a/sound/soc/omap/omap3beagle.c b/sound/soc/omap/omap3beagle.c index d88ad5ca526c..240e0975dd6a 100644 --- a/sound/soc/omap/omap3beagle.c +++ b/sound/soc/omap/omap3beagle.c | |||
@@ -117,11 +117,11 @@ static int __init omap3beagle_soc_init(void) | |||
117 | { | 117 | { |
118 | int ret; | 118 | int ret; |
119 | 119 | ||
120 | if (!machine_is_omap3_beagle()) { | 120 | if (!(machine_is_omap3_beagle() || machine_is_devkit8000())) { |
121 | pr_debug("Not OMAP3 Beagle!\n"); | 121 | pr_debug("Not OMAP3 Beagle or Devkit8000!\n"); |
122 | return -ENODEV; | 122 | return -ENODEV; |
123 | } | 123 | } |
124 | pr_info("OMAP3 Beagle SoC init\n"); | 124 | pr_info("OMAP3 Beagle/Devkit8000 SoC init\n"); |
125 | 125 | ||
126 | omap3beagle_snd_device = platform_device_alloc("soc-audio", -1); | 126 | omap3beagle_snd_device = platform_device_alloc("soc-audio", -1); |
127 | if (!omap3beagle_snd_device) { | 127 | if (!omap3beagle_snd_device) { |
diff --git a/sound/soc/omap/omap3pandora.c b/sound/soc/omap/omap3pandora.c index 71b2c161158d..de10f76baded 100644 --- a/sound/soc/omap/omap3pandora.c +++ b/sound/soc/omap/omap3pandora.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/platform_device.h> | 23 | #include <linux/platform_device.h> |
24 | #include <linux/gpio.h> | 24 | #include <linux/gpio.h> |
25 | #include <linux/delay.h> | 25 | #include <linux/delay.h> |
26 | #include <linux/regulator/consumer.h> | ||
26 | 27 | ||
27 | #include <sound/core.h> | 28 | #include <sound/core.h> |
28 | #include <sound/pcm.h> | 29 | #include <sound/pcm.h> |
@@ -40,6 +41,8 @@ | |||
40 | 41 | ||
41 | #define PREFIX "ASoC omap3pandora: " | 42 | #define PREFIX "ASoC omap3pandora: " |
42 | 43 | ||
44 | static struct regulator *omap3pandora_dac_reg; | ||
45 | |||
43 | static int omap3pandora_cmn_hw_params(struct snd_pcm_substream *substream, | 46 | static int omap3pandora_cmn_hw_params(struct snd_pcm_substream *substream, |
44 | struct snd_pcm_hw_params *params, unsigned int fmt) | 47 | struct snd_pcm_hw_params *params, unsigned int fmt) |
45 | { | 48 | { |
@@ -106,21 +109,37 @@ static int omap3pandora_in_hw_params(struct snd_pcm_substream *substream, | |||
106 | SND_SOC_DAIFMT_CBS_CFS); | 109 | SND_SOC_DAIFMT_CBS_CFS); |
107 | } | 110 | } |
108 | 111 | ||
109 | static int omap3pandora_hp_event(struct snd_soc_dapm_widget *w, | 112 | static int omap3pandora_dac_event(struct snd_soc_dapm_widget *w, |
110 | struct snd_kcontrol *k, int event) | 113 | struct snd_kcontrol *k, int event) |
111 | { | 114 | { |
115 | /* | ||
116 | * The PCM1773 DAC datasheet requires 1ms delay between switching | ||
117 | * VCC power on/off and /PD pin high/low | ||
118 | */ | ||
112 | if (SND_SOC_DAPM_EVENT_ON(event)) { | 119 | if (SND_SOC_DAPM_EVENT_ON(event)) { |
120 | regulator_enable(omap3pandora_dac_reg); | ||
121 | mdelay(1); | ||
113 | gpio_set_value(OMAP3_PANDORA_DAC_POWER_GPIO, 1); | 122 | gpio_set_value(OMAP3_PANDORA_DAC_POWER_GPIO, 1); |
114 | gpio_set_value(OMAP3_PANDORA_AMP_POWER_GPIO, 1); | ||
115 | } else { | 123 | } else { |
116 | gpio_set_value(OMAP3_PANDORA_AMP_POWER_GPIO, 0); | ||
117 | mdelay(1); | ||
118 | gpio_set_value(OMAP3_PANDORA_DAC_POWER_GPIO, 0); | 124 | gpio_set_value(OMAP3_PANDORA_DAC_POWER_GPIO, 0); |
125 | mdelay(1); | ||
126 | regulator_disable(omap3pandora_dac_reg); | ||
119 | } | 127 | } |
120 | 128 | ||
121 | return 0; | 129 | return 0; |
122 | } | 130 | } |
123 | 131 | ||
132 | static int omap3pandora_hp_event(struct snd_soc_dapm_widget *w, | ||
133 | struct snd_kcontrol *k, int event) | ||
134 | { | ||
135 | if (SND_SOC_DAPM_EVENT_ON(event)) | ||
136 | gpio_set_value(OMAP3_PANDORA_AMP_POWER_GPIO, 1); | ||
137 | else | ||
138 | gpio_set_value(OMAP3_PANDORA_AMP_POWER_GPIO, 0); | ||
139 | |||
140 | return 0; | ||
141 | } | ||
142 | |||
124 | /* | 143 | /* |
125 | * Audio paths on Pandora board: | 144 | * Audio paths on Pandora board: |
126 | * | 145 | * |
@@ -130,7 +149,9 @@ static int omap3pandora_hp_event(struct snd_soc_dapm_widget *w, | |||
130 | * |P| <--- TWL4030 <--------- Line In and MICs | 149 | * |P| <--- TWL4030 <--------- Line In and MICs |
131 | */ | 150 | */ |
132 | static const struct snd_soc_dapm_widget omap3pandora_out_dapm_widgets[] = { | 151 | static const struct snd_soc_dapm_widget omap3pandora_out_dapm_widgets[] = { |
133 | SND_SOC_DAPM_DAC("PCM DAC", "HiFi Playback", SND_SOC_NOPM, 0, 0), | 152 | SND_SOC_DAPM_DAC_E("PCM DAC", "HiFi Playback", SND_SOC_NOPM, |
153 | 0, 0, omap3pandora_dac_event, | ||
154 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), | ||
134 | SND_SOC_DAPM_PGA_E("Headphone Amplifier", SND_SOC_NOPM, | 155 | SND_SOC_DAPM_PGA_E("Headphone Amplifier", SND_SOC_NOPM, |
135 | 0, 0, NULL, 0, omap3pandora_hp_event, | 156 | 0, 0, NULL, 0, omap3pandora_hp_event, |
136 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), | 157 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), |
@@ -145,6 +166,7 @@ static const struct snd_soc_dapm_widget omap3pandora_in_dapm_widgets[] = { | |||
145 | }; | 166 | }; |
146 | 167 | ||
147 | static const struct snd_soc_dapm_route omap3pandora_out_map[] = { | 168 | static const struct snd_soc_dapm_route omap3pandora_out_map[] = { |
169 | {"PCM DAC", NULL, "APLL Enable"}, | ||
148 | {"Headphone Amplifier", NULL, "PCM DAC"}, | 170 | {"Headphone Amplifier", NULL, "PCM DAC"}, |
149 | {"Line Out", NULL, "PCM DAC"}, | 171 | {"Line Out", NULL, "PCM DAC"}, |
150 | {"Headphone Jack", NULL, "Headphone Amplifier"}, | 172 | {"Headphone Jack", NULL, "Headphone Amplifier"}, |
@@ -305,8 +327,18 @@ static int __init omap3pandora_soc_init(void) | |||
305 | goto fail2; | 327 | goto fail2; |
306 | } | 328 | } |
307 | 329 | ||
330 | omap3pandora_dac_reg = regulator_get(&omap3pandora_snd_device->dev, "vcc"); | ||
331 | if (IS_ERR(omap3pandora_dac_reg)) { | ||
332 | pr_err(PREFIX "Failed to get DAC regulator from %s: %ld\n", | ||
333 | dev_name(&omap3pandora_snd_device->dev), | ||
334 | PTR_ERR(omap3pandora_dac_reg)); | ||
335 | goto fail3; | ||
336 | } | ||
337 | |||
308 | return 0; | 338 | return 0; |
309 | 339 | ||
340 | fail3: | ||
341 | platform_device_del(omap3pandora_snd_device); | ||
310 | fail2: | 342 | fail2: |
311 | platform_device_put(omap3pandora_snd_device); | 343 | platform_device_put(omap3pandora_snd_device); |
312 | fail1: | 344 | fail1: |
@@ -319,6 +351,7 @@ module_init(omap3pandora_soc_init); | |||
319 | 351 | ||
320 | static void __exit omap3pandora_soc_exit(void) | 352 | static void __exit omap3pandora_soc_exit(void) |
321 | { | 353 | { |
354 | regulator_put(omap3pandora_dac_reg); | ||
322 | platform_device_unregister(omap3pandora_snd_device); | 355 | platform_device_unregister(omap3pandora_snd_device); |
323 | gpio_free(OMAP3_PANDORA_AMP_POWER_GPIO); | 356 | gpio_free(OMAP3_PANDORA_AMP_POWER_GPIO); |
324 | gpio_free(OMAP3_PANDORA_DAC_POWER_GPIO); | 357 | gpio_free(OMAP3_PANDORA_DAC_POWER_GPIO); |
diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index 3bd7712f029b..e69397f40f72 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c | |||
@@ -135,10 +135,11 @@ static int pxa_ssp_suspend(struct snd_soc_dai *cpu_dai) | |||
135 | struct ssp_priv *priv = cpu_dai->private_data; | 135 | struct ssp_priv *priv = cpu_dai->private_data; |
136 | 136 | ||
137 | if (!cpu_dai->active) | 137 | if (!cpu_dai->active) |
138 | return 0; | 138 | clk_enable(priv->dev.ssp->clk); |
139 | 139 | ||
140 | ssp_save_state(&priv->dev, &priv->state); | 140 | ssp_save_state(&priv->dev, &priv->state); |
141 | clk_disable(priv->dev.ssp->clk); | 141 | clk_disable(priv->dev.ssp->clk); |
142 | |||
142 | return 0; | 143 | return 0; |
143 | } | 144 | } |
144 | 145 | ||
@@ -146,12 +147,13 @@ static int pxa_ssp_resume(struct snd_soc_dai *cpu_dai) | |||
146 | { | 147 | { |
147 | struct ssp_priv *priv = cpu_dai->private_data; | 148 | struct ssp_priv *priv = cpu_dai->private_data; |
148 | 149 | ||
149 | if (!cpu_dai->active) | ||
150 | return 0; | ||
151 | |||
152 | clk_enable(priv->dev.ssp->clk); | 150 | clk_enable(priv->dev.ssp->clk); |
153 | ssp_restore_state(&priv->dev, &priv->state); | 151 | ssp_restore_state(&priv->dev, &priv->state); |
154 | ssp_enable(&priv->dev); | 152 | |
153 | if (cpu_dai->active) | ||
154 | ssp_enable(&priv->dev); | ||
155 | else | ||
156 | clk_disable(priv->dev.ssp->clk); | ||
155 | 157 | ||
156 | return 0; | 158 | return 0; |
157 | } | 159 | } |
diff --git a/sound/soc/pxa/raumfeld.c b/sound/soc/pxa/raumfeld.c index acfce1c0f1c9..7e3f41696c41 100644 --- a/sound/soc/pxa/raumfeld.c +++ b/sound/soc/pxa/raumfeld.c | |||
@@ -41,7 +41,9 @@ static struct i2c_board_info max9486_hwmon_info = { | |||
41 | }; | 41 | }; |
42 | 42 | ||
43 | #define MAX9485_MCLK_FREQ_112896 0x22 | 43 | #define MAX9485_MCLK_FREQ_112896 0x22 |
44 | #define MAX9485_MCLK_FREQ_122880 0x23 | 44 | #define MAX9485_MCLK_FREQ_122880 0x23 |
45 | #define MAX9485_MCLK_FREQ_225792 0x32 | ||
46 | #define MAX9485_MCLK_FREQ_245760 0x33 | ||
45 | 47 | ||
46 | static void set_max9485_clk(char clk) | 48 | static void set_max9485_clk(char clk) |
47 | { | 49 | { |
@@ -71,9 +73,17 @@ static int raumfeld_cs4270_startup(struct snd_pcm_substream *substream) | |||
71 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 73 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
72 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; | 74 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; |
73 | 75 | ||
74 | set_max9485_clk(MAX9485_MCLK_FREQ_112896); | 76 | /* set freq to 0 to enable all possible codec sample rates */ |
77 | return snd_soc_dai_set_sysclk(codec_dai, 0, 0, 0); | ||
78 | } | ||
75 | 79 | ||
76 | return snd_soc_dai_set_sysclk(codec_dai, 0, 11289600, 0); | 80 | static void raumfeld_cs4270_shutdown(struct snd_pcm_substream *substream) |
81 | { | ||
82 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
83 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; | ||
84 | |||
85 | /* set freq to 0 to enable all possible codec sample rates */ | ||
86 | snd_soc_dai_set_sysclk(codec_dai, 0, 0, 0); | ||
77 | } | 87 | } |
78 | 88 | ||
79 | static int raumfeld_cs4270_hw_params(struct snd_pcm_substream *substream, | 89 | static int raumfeld_cs4270_hw_params(struct snd_pcm_substream *substream, |
@@ -86,20 +96,24 @@ static int raumfeld_cs4270_hw_params(struct snd_pcm_substream *substream, | |||
86 | int ret = 0; | 96 | int ret = 0; |
87 | 97 | ||
88 | switch (params_rate(params)) { | 98 | switch (params_rate(params)) { |
89 | case 8000: | 99 | case 44100: |
90 | case 16000: | 100 | set_max9485_clk(MAX9485_MCLK_FREQ_112896); |
101 | clk = 11289600; | ||
102 | break; | ||
91 | case 48000: | 103 | case 48000: |
92 | case 96000: | ||
93 | set_max9485_clk(MAX9485_MCLK_FREQ_122880); | 104 | set_max9485_clk(MAX9485_MCLK_FREQ_122880); |
94 | clk = 12288000; | 105 | clk = 12288000; |
95 | break; | 106 | break; |
96 | case 11025: | ||
97 | case 22050: | ||
98 | case 44100: | ||
99 | case 88200: | 107 | case 88200: |
100 | set_max9485_clk(MAX9485_MCLK_FREQ_112896); | 108 | set_max9485_clk(MAX9485_MCLK_FREQ_225792); |
101 | clk = 11289600; | 109 | clk = 22579200; |
102 | break; | 110 | break; |
111 | case 96000: | ||
112 | set_max9485_clk(MAX9485_MCLK_FREQ_245760); | ||
113 | clk = 24576000; | ||
114 | break; | ||
115 | default: | ||
116 | return -EINVAL; | ||
103 | } | 117 | } |
104 | 118 | ||
105 | fmt = SND_SOC_DAIFMT_I2S | | 119 | fmt = SND_SOC_DAIFMT_I2S | |
@@ -128,7 +142,7 @@ static int raumfeld_cs4270_hw_params(struct snd_pcm_substream *substream, | |||
128 | if (ret < 0) | 142 | if (ret < 0) |
129 | return ret; | 143 | return ret; |
130 | 144 | ||
131 | ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_EXT, 0, 1); | 145 | ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_EXT, clk, 1); |
132 | if (ret < 0) | 146 | if (ret < 0) |
133 | return ret; | 147 | return ret; |
134 | 148 | ||
@@ -137,6 +151,7 @@ static int raumfeld_cs4270_hw_params(struct snd_pcm_substream *substream, | |||
137 | 151 | ||
138 | static struct snd_soc_ops raumfeld_cs4270_ops = { | 152 | static struct snd_soc_ops raumfeld_cs4270_ops = { |
139 | .startup = raumfeld_cs4270_startup, | 153 | .startup = raumfeld_cs4270_startup, |
154 | .shutdown = raumfeld_cs4270_shutdown, | ||
140 | .hw_params = raumfeld_cs4270_hw_params, | 155 | .hw_params = raumfeld_cs4270_hw_params, |
141 | }; | 156 | }; |
142 | 157 | ||
@@ -181,20 +196,24 @@ static int raumfeld_ak4104_hw_params(struct snd_pcm_substream *substream, | |||
181 | int fmt, ret = 0, clk = 0; | 196 | int fmt, ret = 0, clk = 0; |
182 | 197 | ||
183 | switch (params_rate(params)) { | 198 | switch (params_rate(params)) { |
184 | case 8000: | 199 | case 44100: |
185 | case 16000: | 200 | set_max9485_clk(MAX9485_MCLK_FREQ_112896); |
201 | clk = 11289600; | ||
202 | break; | ||
186 | case 48000: | 203 | case 48000: |
187 | case 96000: | ||
188 | set_max9485_clk(MAX9485_MCLK_FREQ_122880); | 204 | set_max9485_clk(MAX9485_MCLK_FREQ_122880); |
189 | clk = 12288000; | 205 | clk = 12288000; |
190 | break; | 206 | break; |
191 | case 11025: | ||
192 | case 22050: | ||
193 | case 44100: | ||
194 | case 88200: | 207 | case 88200: |
195 | set_max9485_clk(MAX9485_MCLK_FREQ_112896); | 208 | set_max9485_clk(MAX9485_MCLK_FREQ_225792); |
196 | clk = 11289600; | 209 | clk = 22579200; |
210 | break; | ||
211 | case 96000: | ||
212 | set_max9485_clk(MAX9485_MCLK_FREQ_245760); | ||
213 | clk = 24576000; | ||
197 | break; | 214 | break; |
215 | default: | ||
216 | return -EINVAL; | ||
198 | } | 217 | } |
199 | 218 | ||
200 | fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF; | 219 | fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF; |
@@ -217,7 +236,7 @@ static int raumfeld_ak4104_hw_params(struct snd_pcm_substream *substream, | |||
217 | if (ret < 0) | 236 | if (ret < 0) |
218 | return ret; | 237 | return ret; |
219 | 238 | ||
220 | ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_EXT, 0, 1); | 239 | ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_EXT, clk, 1); |
221 | if (ret < 0) | 240 | if (ret < 0) |
222 | return ret; | 241 | return ret; |
223 | 242 | ||
diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig index b489f1ae103d..15fe57e5a232 100644 --- a/sound/soc/s3c24xx/Kconfig +++ b/sound/soc/s3c24xx/Kconfig | |||
@@ -27,12 +27,10 @@ config SND_S3C64XX_SOC_I2S | |||
27 | config SND_S3C_SOC_PCM | 27 | config SND_S3C_SOC_PCM |
28 | tristate | 28 | tristate |
29 | 29 | ||
30 | config SND_S3C2443_SOC_AC97 | 30 | config SND_S3C_SOC_AC97 |
31 | tristate | 31 | tristate |
32 | select S3C2410_DMA | ||
33 | select AC97_BUS | ||
34 | select SND_SOC_AC97_BUS | 32 | select SND_SOC_AC97_BUS |
35 | 33 | ||
36 | config SND_S3C24XX_SOC_NEO1973_WM8753 | 34 | config SND_S3C24XX_SOC_NEO1973_WM8753 |
37 | tristate "SoC I2S Audio support for NEO1973 - WM8753" | 35 | tristate "SoC I2S Audio support for NEO1973 - WM8753" |
38 | depends on SND_S3C24XX_SOC && MACH_NEO1973_GTA01 | 36 | depends on SND_S3C24XX_SOC && MACH_NEO1973_GTA01 |
@@ -71,8 +69,10 @@ config SND_S3C64XX_SOC_WM8580 | |||
71 | config SND_S3C24XX_SOC_SMDK2443_WM9710 | 69 | config SND_S3C24XX_SOC_SMDK2443_WM9710 |
72 | tristate "SoC AC97 Audio support for SMDK2443 - WM9710" | 70 | tristate "SoC AC97 Audio support for SMDK2443 - WM9710" |
73 | depends on SND_S3C24XX_SOC && MACH_SMDK2443 | 71 | depends on SND_S3C24XX_SOC && MACH_SMDK2443 |
74 | select SND_S3C2443_SOC_AC97 | 72 | select S3C2410_DMA |
73 | select AC97_BUS | ||
75 | select SND_SOC_AC97_CODEC | 74 | select SND_SOC_AC97_CODEC |
75 | select SND_S3C_SOC_AC97 | ||
76 | help | 76 | help |
77 | Say Y if you want to add support for SoC audio on smdk2443 | 77 | Say Y if you want to add support for SoC audio on smdk2443 |
78 | with the WM9710. | 78 | with the WM9710. |
@@ -80,8 +80,10 @@ config SND_S3C24XX_SOC_SMDK2443_WM9710 | |||
80 | config SND_S3C24XX_SOC_LN2440SBC_ALC650 | 80 | config SND_S3C24XX_SOC_LN2440SBC_ALC650 |
81 | tristate "SoC AC97 Audio support for LN2440SBC - ALC650" | 81 | tristate "SoC AC97 Audio support for LN2440SBC - ALC650" |
82 | depends on SND_S3C24XX_SOC && ARCH_S3C2410 | 82 | depends on SND_S3C24XX_SOC && ARCH_S3C2410 |
83 | select SND_S3C2443_SOC_AC97 | 83 | select S3C2410_DMA |
84 | select AC97_BUS | ||
84 | select SND_SOC_AC97_CODEC | 85 | select SND_SOC_AC97_CODEC |
86 | select SND_S3C_SOC_AC97 | ||
85 | help | 87 | help |
86 | Say Y if you want to add support for SoC audio on ln2440sbc | 88 | Say Y if you want to add support for SoC audio on ln2440sbc |
87 | with the ALC650. | 89 | with the ALC650. |
@@ -111,3 +113,11 @@ config SND_S3C24XX_SOC_SIMTEC_HERMES | |||
111 | select SND_S3C24XX_SOC_I2S | 113 | select SND_S3C24XX_SOC_I2S |
112 | select SND_SOC_TLV320AIC3X | 114 | select SND_SOC_TLV320AIC3X |
113 | select SND_S3C24XX_SOC_SIMTEC | 115 | select SND_S3C24XX_SOC_SIMTEC |
116 | |||
117 | config SND_SOC_SMDK_WM9713 | ||
118 | tristate "SoC AC97 Audio support for SMDK with WM9713" | ||
119 | depends on SND_S3C24XX_SOC && MACH_SMDK6410 | ||
120 | select SND_SOC_WM9713 | ||
121 | select SND_S3C_SOC_AC97 | ||
122 | help | ||
123 | Sat Y if you want to add support for SoC audio on the SMDK. | ||
diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile index b744657733d7..df071a376fa2 100644 --- a/sound/soc/s3c24xx/Makefile +++ b/sound/soc/s3c24xx/Makefile | |||
@@ -3,13 +3,13 @@ snd-soc-s3c24xx-objs := s3c-dma.o | |||
3 | snd-soc-s3c24xx-i2s-objs := s3c24xx-i2s.o | 3 | snd-soc-s3c24xx-i2s-objs := s3c24xx-i2s.o |
4 | snd-soc-s3c2412-i2s-objs := s3c2412-i2s.o | 4 | snd-soc-s3c2412-i2s-objs := s3c2412-i2s.o |
5 | snd-soc-s3c64xx-i2s-objs := s3c64xx-i2s.o | 5 | snd-soc-s3c64xx-i2s-objs := s3c64xx-i2s.o |
6 | snd-soc-s3c2443-ac97-objs := s3c2443-ac97.o | 6 | snd-soc-s3c-ac97-objs := s3c-ac97.o |
7 | snd-soc-s3c-i2s-v2-objs := s3c-i2s-v2.o | 7 | snd-soc-s3c-i2s-v2-objs := s3c-i2s-v2.o |
8 | snd-soc-s3c-pcm-objs := s3c-pcm.o | 8 | snd-soc-s3c-pcm-objs := s3c-pcm.o |
9 | 9 | ||
10 | obj-$(CONFIG_SND_S3C24XX_SOC) += snd-soc-s3c24xx.o | 10 | obj-$(CONFIG_SND_S3C24XX_SOC) += snd-soc-s3c24xx.o |
11 | obj-$(CONFIG_SND_S3C24XX_SOC_I2S) += snd-soc-s3c24xx-i2s.o | 11 | obj-$(CONFIG_SND_S3C24XX_SOC_I2S) += snd-soc-s3c24xx-i2s.o |
12 | obj-$(CONFIG_SND_S3C2443_SOC_AC97) += snd-soc-s3c2443-ac97.o | 12 | obj-$(CONFIG_SND_S3C_SOC_AC97) += snd-soc-s3c-ac97.o |
13 | obj-$(CONFIG_SND_S3C2412_SOC_I2S) += snd-soc-s3c2412-i2s.o | 13 | obj-$(CONFIG_SND_S3C2412_SOC_I2S) += snd-soc-s3c2412-i2s.o |
14 | obj-$(CONFIG_SND_S3C64XX_SOC_I2S) += snd-soc-s3c64xx-i2s.o | 14 | obj-$(CONFIG_SND_S3C64XX_SOC_I2S) += snd-soc-s3c64xx-i2s.o |
15 | obj-$(CONFIG_SND_S3C_I2SV2_SOC) += snd-soc-s3c-i2s-v2.o | 15 | obj-$(CONFIG_SND_S3C_I2SV2_SOC) += snd-soc-s3c-i2s-v2.o |
@@ -26,6 +26,7 @@ snd-soc-s3c24xx-simtec-objs := s3c24xx_simtec.o | |||
26 | snd-soc-s3c24xx-simtec-hermes-objs := s3c24xx_simtec_hermes.o | 26 | snd-soc-s3c24xx-simtec-hermes-objs := s3c24xx_simtec_hermes.o |
27 | snd-soc-s3c24xx-simtec-tlv320aic23-objs := s3c24xx_simtec_tlv320aic23.o | 27 | snd-soc-s3c24xx-simtec-tlv320aic23-objs := s3c24xx_simtec_tlv320aic23.o |
28 | snd-soc-smdk64xx-wm8580-objs := smdk64xx_wm8580.o | 28 | snd-soc-smdk64xx-wm8580-objs := smdk64xx_wm8580.o |
29 | snd-soc-smdk-wm9713-objs := smdk_wm9713.o | ||
29 | 30 | ||
30 | obj-$(CONFIG_SND_S3C24XX_SOC_JIVE_WM8750) += snd-soc-jive-wm8750.o | 31 | obj-$(CONFIG_SND_S3C24XX_SOC_JIVE_WM8750) += snd-soc-jive-wm8750.o |
31 | obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o | 32 | obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o |
@@ -37,4 +38,4 @@ obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC) += snd-soc-s3c24xx-simtec.o | |||
37 | obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC_HERMES) += snd-soc-s3c24xx-simtec-hermes.o | 38 | obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC_HERMES) += snd-soc-s3c24xx-simtec-hermes.o |
38 | obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC_TLV320AIC23) += snd-soc-s3c24xx-simtec-tlv320aic23.o | 39 | obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC_TLV320AIC23) += snd-soc-s3c24xx-simtec-tlv320aic23.o |
39 | obj-$(CONFIG_SND_S3C64XX_SOC_WM8580) += snd-soc-smdk64xx-wm8580.o | 40 | obj-$(CONFIG_SND_S3C64XX_SOC_WM8580) += snd-soc-smdk64xx-wm8580.o |
40 | 41 | obj-$(CONFIG_SND_SOC_SMDK_WM9713) += snd-soc-smdk-wm9713.o | |
diff --git a/sound/soc/s3c24xx/ln2440sbc_alc650.c b/sound/soc/s3c24xx/ln2440sbc_alc650.c index d00d359a03e6..ffa954fe6931 100644 --- a/sound/soc/s3c24xx/ln2440sbc_alc650.c +++ b/sound/soc/s3c24xx/ln2440sbc_alc650.c | |||
@@ -25,7 +25,7 @@ | |||
25 | 25 | ||
26 | #include "../codecs/ac97.h" | 26 | #include "../codecs/ac97.h" |
27 | #include "s3c-dma.h" | 27 | #include "s3c-dma.h" |
28 | #include "s3c24xx-ac97.h" | 28 | #include "s3c-ac97.h" |
29 | 29 | ||
30 | static struct snd_soc_card ln2440sbc; | 30 | static struct snd_soc_card ln2440sbc; |
31 | 31 | ||
@@ -33,7 +33,7 @@ static struct snd_soc_dai_link ln2440sbc_dai[] = { | |||
33 | { | 33 | { |
34 | .name = "AC97", | 34 | .name = "AC97", |
35 | .stream_name = "AC97 HiFi", | 35 | .stream_name = "AC97 HiFi", |
36 | .cpu_dai = &s3c2443_ac97_dai[0], | 36 | .cpu_dai = &s3c_ac97_dai[S3C_AC97_DAI_PCM], |
37 | .codec_dai = &ac97_dai, | 37 | .codec_dai = &ac97_dai, |
38 | }, | 38 | }, |
39 | }; | 39 | }; |
diff --git a/sound/soc/s3c24xx/s3c-ac97.c b/sound/soc/s3c24xx/s3c-ac97.c new file mode 100644 index 000000000000..ee8ed9d7e703 --- /dev/null +++ b/sound/soc/s3c24xx/s3c-ac97.c | |||
@@ -0,0 +1,518 @@ | |||
1 | /* sound/soc/s3c24xx/s3c-ac97.c | ||
2 | * | ||
3 | * ALSA SoC Audio Layer - S3C AC97 Controller driver | ||
4 | * Evolved from s3c2443-ac97.c | ||
5 | * | ||
6 | * Copyright (c) 2010 Samsung Electronics Co. Ltd | ||
7 | * Author: Jaswinder Singh <jassi.brar@samsung.com> | ||
8 | * Credits: Graeme Gregory, Sean Choi | ||
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/init.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/io.h> | ||
18 | #include <linux/delay.h> | ||
19 | #include <linux/clk.h> | ||
20 | |||
21 | #include <sound/soc.h> | ||
22 | |||
23 | #include <plat/regs-ac97.h> | ||
24 | #include <mach/dma.h> | ||
25 | #include <plat/audio.h> | ||
26 | |||
27 | #include "s3c-dma.h" | ||
28 | #include "s3c-ac97.h" | ||
29 | |||
30 | #define AC_CMD_ADDR(x) (x << 16) | ||
31 | #define AC_CMD_DATA(x) (x & 0xffff) | ||
32 | |||
33 | struct s3c_ac97_info { | ||
34 | unsigned state; | ||
35 | struct clk *ac97_clk; | ||
36 | void __iomem *regs; | ||
37 | struct mutex lock; | ||
38 | struct completion done; | ||
39 | }; | ||
40 | static struct s3c_ac97_info s3c_ac97; | ||
41 | |||
42 | static struct s3c2410_dma_client s3c_dma_client_out = { | ||
43 | .name = "AC97 PCMOut" | ||
44 | }; | ||
45 | |||
46 | static struct s3c2410_dma_client s3c_dma_client_in = { | ||
47 | .name = "AC97 PCMIn" | ||
48 | }; | ||
49 | |||
50 | static struct s3c2410_dma_client s3c_dma_client_micin = { | ||
51 | .name = "AC97 MicIn" | ||
52 | }; | ||
53 | |||
54 | static struct s3c_dma_params s3c_ac97_pcm_out = { | ||
55 | .client = &s3c_dma_client_out, | ||
56 | .dma_size = 4, | ||
57 | }; | ||
58 | |||
59 | static struct s3c_dma_params s3c_ac97_pcm_in = { | ||
60 | .client = &s3c_dma_client_in, | ||
61 | .dma_size = 4, | ||
62 | }; | ||
63 | |||
64 | static struct s3c_dma_params s3c_ac97_mic_in = { | ||
65 | .client = &s3c_dma_client_micin, | ||
66 | .dma_size = 4, | ||
67 | }; | ||
68 | |||
69 | static void s3c_ac97_activate(struct snd_ac97 *ac97) | ||
70 | { | ||
71 | u32 ac_glbctrl, stat; | ||
72 | |||
73 | stat = readl(s3c_ac97.regs + S3C_AC97_GLBSTAT) & 0x7; | ||
74 | if (stat == S3C_AC97_GLBSTAT_MAINSTATE_ACTIVE) | ||
75 | return; /* Return if already active */ | ||
76 | |||
77 | INIT_COMPLETION(s3c_ac97.done); | ||
78 | |||
79 | ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL); | ||
80 | ac_glbctrl = S3C_AC97_GLBCTRL_ACLINKON; | ||
81 | writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); | ||
82 | msleep(1); | ||
83 | |||
84 | ac_glbctrl |= S3C_AC97_GLBCTRL_TRANSFERDATAENABLE; | ||
85 | writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); | ||
86 | msleep(1); | ||
87 | |||
88 | ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL); | ||
89 | ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE; | ||
90 | writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); | ||
91 | |||
92 | if (!wait_for_completion_timeout(&s3c_ac97.done, HZ)) | ||
93 | printk(KERN_ERR "AC97: Unable to activate!"); | ||
94 | } | ||
95 | |||
96 | static unsigned short s3c_ac97_read(struct snd_ac97 *ac97, | ||
97 | unsigned short reg) | ||
98 | { | ||
99 | u32 ac_glbctrl, ac_codec_cmd; | ||
100 | u32 stat, addr, data; | ||
101 | |||
102 | mutex_lock(&s3c_ac97.lock); | ||
103 | |||
104 | s3c_ac97_activate(ac97); | ||
105 | |||
106 | INIT_COMPLETION(s3c_ac97.done); | ||
107 | |||
108 | ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD); | ||
109 | ac_codec_cmd = S3C_AC97_CODEC_CMD_READ | AC_CMD_ADDR(reg); | ||
110 | writel(ac_codec_cmd, s3c_ac97.regs + S3C_AC97_CODEC_CMD); | ||
111 | |||
112 | udelay(50); | ||
113 | |||
114 | ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL); | ||
115 | ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE; | ||
116 | writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); | ||
117 | |||
118 | if (!wait_for_completion_timeout(&s3c_ac97.done, HZ)) | ||
119 | printk(KERN_ERR "AC97: Unable to read!"); | ||
120 | |||
121 | stat = readl(s3c_ac97.regs + S3C_AC97_STAT); | ||
122 | addr = (stat >> 16) & 0x7f; | ||
123 | data = (stat & 0xffff); | ||
124 | |||
125 | if (addr != reg) | ||
126 | printk(KERN_ERR "s3c-ac97: req addr = %02x, rep addr = %02x\n", reg, addr); | ||
127 | |||
128 | mutex_unlock(&s3c_ac97.lock); | ||
129 | |||
130 | return (unsigned short)data; | ||
131 | } | ||
132 | |||
133 | static void s3c_ac97_write(struct snd_ac97 *ac97, unsigned short reg, | ||
134 | unsigned short val) | ||
135 | { | ||
136 | u32 ac_glbctrl, ac_codec_cmd; | ||
137 | |||
138 | mutex_lock(&s3c_ac97.lock); | ||
139 | |||
140 | s3c_ac97_activate(ac97); | ||
141 | |||
142 | INIT_COMPLETION(s3c_ac97.done); | ||
143 | |||
144 | ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD); | ||
145 | ac_codec_cmd = AC_CMD_ADDR(reg) | AC_CMD_DATA(val); | ||
146 | writel(ac_codec_cmd, s3c_ac97.regs + S3C_AC97_CODEC_CMD); | ||
147 | |||
148 | udelay(50); | ||
149 | |||
150 | ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL); | ||
151 | ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE; | ||
152 | writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); | ||
153 | |||
154 | if (!wait_for_completion_timeout(&s3c_ac97.done, HZ)) | ||
155 | printk(KERN_ERR "AC97: Unable to write!"); | ||
156 | |||
157 | ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD); | ||
158 | ac_codec_cmd |= S3C_AC97_CODEC_CMD_READ; | ||
159 | writel(ac_codec_cmd, s3c_ac97.regs + S3C_AC97_CODEC_CMD); | ||
160 | |||
161 | mutex_unlock(&s3c_ac97.lock); | ||
162 | } | ||
163 | |||
164 | static void s3c_ac97_cold_reset(struct snd_ac97 *ac97) | ||
165 | { | ||
166 | writel(S3C_AC97_GLBCTRL_COLDRESET, | ||
167 | s3c_ac97.regs + S3C_AC97_GLBCTRL); | ||
168 | msleep(1); | ||
169 | |||
170 | writel(0, s3c_ac97.regs + S3C_AC97_GLBCTRL); | ||
171 | msleep(1); | ||
172 | } | ||
173 | |||
174 | static void s3c_ac97_warm_reset(struct snd_ac97 *ac97) | ||
175 | { | ||
176 | u32 stat; | ||
177 | |||
178 | stat = readl(s3c_ac97.regs + S3C_AC97_GLBSTAT) & 0x7; | ||
179 | if (stat == S3C_AC97_GLBSTAT_MAINSTATE_ACTIVE) | ||
180 | return; /* Return if already active */ | ||
181 | |||
182 | writel(S3C_AC97_GLBCTRL_WARMRESET, s3c_ac97.regs + S3C_AC97_GLBCTRL); | ||
183 | msleep(1); | ||
184 | |||
185 | writel(0, s3c_ac97.regs + S3C_AC97_GLBCTRL); | ||
186 | msleep(1); | ||
187 | |||
188 | s3c_ac97_activate(ac97); | ||
189 | } | ||
190 | |||
191 | static irqreturn_t s3c_ac97_irq(int irq, void *dev_id) | ||
192 | { | ||
193 | u32 ac_glbctrl, ac_glbstat; | ||
194 | |||
195 | ac_glbstat = readl(s3c_ac97.regs + S3C_AC97_GLBSTAT); | ||
196 | |||
197 | if (ac_glbstat & S3C_AC97_GLBSTAT_CODECREADY) { | ||
198 | |||
199 | ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL); | ||
200 | ac_glbctrl &= ~S3C_AC97_GLBCTRL_CODECREADYIE; | ||
201 | writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); | ||
202 | |||
203 | complete(&s3c_ac97.done); | ||
204 | } | ||
205 | |||
206 | ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL); | ||
207 | ac_glbctrl |= (1<<30); /* Clear interrupt */ | ||
208 | writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); | ||
209 | |||
210 | return IRQ_HANDLED; | ||
211 | } | ||
212 | |||
213 | struct snd_ac97_bus_ops soc_ac97_ops = { | ||
214 | .read = s3c_ac97_read, | ||
215 | .write = s3c_ac97_write, | ||
216 | .warm_reset = s3c_ac97_warm_reset, | ||
217 | .reset = s3c_ac97_cold_reset, | ||
218 | }; | ||
219 | EXPORT_SYMBOL_GPL(soc_ac97_ops); | ||
220 | |||
221 | static int s3c_ac97_hw_params(struct snd_pcm_substream *substream, | ||
222 | struct snd_pcm_hw_params *params, | ||
223 | struct snd_soc_dai *dai) | ||
224 | { | ||
225 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
226 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | ||
227 | |||
228 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
229 | cpu_dai->dma_data = &s3c_ac97_pcm_out; | ||
230 | else | ||
231 | cpu_dai->dma_data = &s3c_ac97_pcm_in; | ||
232 | |||
233 | return 0; | ||
234 | } | ||
235 | |||
236 | static int s3c_ac97_trigger(struct snd_pcm_substream *substream, int cmd, | ||
237 | struct snd_soc_dai *dai) | ||
238 | { | ||
239 | u32 ac_glbctrl; | ||
240 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
241 | int channel = ((struct s3c_dma_params *) | ||
242 | rtd->dai->cpu_dai->dma_data)->channel; | ||
243 | |||
244 | ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL); | ||
245 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) | ||
246 | ac_glbctrl &= ~S3C_AC97_GLBCTRL_PCMINTM_MASK; | ||
247 | else | ||
248 | ac_glbctrl &= ~S3C_AC97_GLBCTRL_PCMOUTTM_MASK; | ||
249 | |||
250 | switch (cmd) { | ||
251 | case SNDRV_PCM_TRIGGER_START: | ||
252 | case SNDRV_PCM_TRIGGER_RESUME: | ||
253 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
254 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) | ||
255 | ac_glbctrl |= S3C_AC97_GLBCTRL_PCMINTM_DMA; | ||
256 | else | ||
257 | ac_glbctrl |= S3C_AC97_GLBCTRL_PCMOUTTM_DMA; | ||
258 | break; | ||
259 | |||
260 | case SNDRV_PCM_TRIGGER_STOP: | ||
261 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
262 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
263 | break; | ||
264 | } | ||
265 | |||
266 | writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); | ||
267 | |||
268 | s3c2410_dma_ctrl(channel, S3C2410_DMAOP_STARTED); | ||
269 | |||
270 | return 0; | ||
271 | } | ||
272 | |||
273 | static int s3c_ac97_hw_mic_params(struct snd_pcm_substream *substream, | ||
274 | struct snd_pcm_hw_params *params, | ||
275 | struct snd_soc_dai *dai) | ||
276 | { | ||
277 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
278 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | ||
279 | |||
280 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
281 | return -ENODEV; | ||
282 | else | ||
283 | cpu_dai->dma_data = &s3c_ac97_mic_in; | ||
284 | |||
285 | return 0; | ||
286 | } | ||
287 | |||
288 | static int s3c_ac97_mic_trigger(struct snd_pcm_substream *substream, | ||
289 | int cmd, struct snd_soc_dai *dai) | ||
290 | { | ||
291 | u32 ac_glbctrl; | ||
292 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
293 | int channel = ((struct s3c_dma_params *) | ||
294 | rtd->dai->cpu_dai->dma_data)->channel; | ||
295 | |||
296 | ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL); | ||
297 | ac_glbctrl &= ~S3C_AC97_GLBCTRL_MICINTM_MASK; | ||
298 | |||
299 | switch (cmd) { | ||
300 | case SNDRV_PCM_TRIGGER_START: | ||
301 | case SNDRV_PCM_TRIGGER_RESUME: | ||
302 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
303 | ac_glbctrl |= S3C_AC97_GLBCTRL_MICINTM_DMA; | ||
304 | break; | ||
305 | |||
306 | case SNDRV_PCM_TRIGGER_STOP: | ||
307 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
308 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
309 | break; | ||
310 | } | ||
311 | |||
312 | writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); | ||
313 | |||
314 | s3c2410_dma_ctrl(channel, S3C2410_DMAOP_STARTED); | ||
315 | |||
316 | return 0; | ||
317 | } | ||
318 | |||
319 | static struct snd_soc_dai_ops s3c_ac97_dai_ops = { | ||
320 | .hw_params = s3c_ac97_hw_params, | ||
321 | .trigger = s3c_ac97_trigger, | ||
322 | }; | ||
323 | |||
324 | static struct snd_soc_dai_ops s3c_ac97_mic_dai_ops = { | ||
325 | .hw_params = s3c_ac97_hw_mic_params, | ||
326 | .trigger = s3c_ac97_mic_trigger, | ||
327 | }; | ||
328 | |||
329 | struct snd_soc_dai s3c_ac97_dai[] = { | ||
330 | [S3C_AC97_DAI_PCM] = { | ||
331 | .name = "s3c-ac97", | ||
332 | .id = S3C_AC97_DAI_PCM, | ||
333 | .ac97_control = 1, | ||
334 | .playback = { | ||
335 | .stream_name = "AC97 Playback", | ||
336 | .channels_min = 2, | ||
337 | .channels_max = 2, | ||
338 | .rates = SNDRV_PCM_RATE_8000_48000, | ||
339 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | ||
340 | .capture = { | ||
341 | .stream_name = "AC97 Capture", | ||
342 | .channels_min = 2, | ||
343 | .channels_max = 2, | ||
344 | .rates = SNDRV_PCM_RATE_8000_48000, | ||
345 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | ||
346 | .ops = &s3c_ac97_dai_ops, | ||
347 | }, | ||
348 | [S3C_AC97_DAI_MIC] = { | ||
349 | .name = "s3c-ac97-mic", | ||
350 | .id = S3C_AC97_DAI_MIC, | ||
351 | .ac97_control = 1, | ||
352 | .capture = { | ||
353 | .stream_name = "AC97 Mic Capture", | ||
354 | .channels_min = 1, | ||
355 | .channels_max = 1, | ||
356 | .rates = SNDRV_PCM_RATE_8000_48000, | ||
357 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | ||
358 | .ops = &s3c_ac97_mic_dai_ops, | ||
359 | }, | ||
360 | }; | ||
361 | EXPORT_SYMBOL_GPL(s3c_ac97_dai); | ||
362 | |||
363 | static __devinit int s3c_ac97_probe(struct platform_device *pdev) | ||
364 | { | ||
365 | struct resource *mem_res, *dmatx_res, *dmarx_res, *dmamic_res, *irq_res; | ||
366 | struct s3c_audio_pdata *ac97_pdata; | ||
367 | int ret; | ||
368 | |||
369 | ac97_pdata = pdev->dev.platform_data; | ||
370 | if (!ac97_pdata || !ac97_pdata->cfg_gpio) { | ||
371 | dev_err(&pdev->dev, "cfg_gpio callback not provided!\n"); | ||
372 | return -EINVAL; | ||
373 | } | ||
374 | |||
375 | /* Check for availability of necessary resource */ | ||
376 | dmatx_res = platform_get_resource(pdev, IORESOURCE_DMA, 0); | ||
377 | if (!dmatx_res) { | ||
378 | dev_err(&pdev->dev, "Unable to get AC97-TX dma resource\n"); | ||
379 | return -ENXIO; | ||
380 | } | ||
381 | |||
382 | dmarx_res = platform_get_resource(pdev, IORESOURCE_DMA, 1); | ||
383 | if (!dmarx_res) { | ||
384 | dev_err(&pdev->dev, "Unable to get AC97-RX dma resource\n"); | ||
385 | return -ENXIO; | ||
386 | } | ||
387 | |||
388 | dmamic_res = platform_get_resource(pdev, IORESOURCE_DMA, 2); | ||
389 | if (!dmamic_res) { | ||
390 | dev_err(&pdev->dev, "Unable to get AC97-MIC dma resource\n"); | ||
391 | return -ENXIO; | ||
392 | } | ||
393 | |||
394 | mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
395 | if (!mem_res) { | ||
396 | dev_err(&pdev->dev, "Unable to get register resource\n"); | ||
397 | return -ENXIO; | ||
398 | } | ||
399 | |||
400 | irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | ||
401 | if (!irq_res) { | ||
402 | dev_err(&pdev->dev, "AC97 IRQ not provided!\n"); | ||
403 | return -ENXIO; | ||
404 | } | ||
405 | |||
406 | if (!request_mem_region(mem_res->start, | ||
407 | resource_size(mem_res), "s3c-ac97")) { | ||
408 | dev_err(&pdev->dev, "Unable to request register region\n"); | ||
409 | return -EBUSY; | ||
410 | } | ||
411 | |||
412 | s3c_ac97_pcm_out.channel = dmatx_res->start; | ||
413 | s3c_ac97_pcm_out.dma_addr = mem_res->start + S3C_AC97_PCM_DATA; | ||
414 | s3c_ac97_pcm_in.channel = dmarx_res->start; | ||
415 | s3c_ac97_pcm_in.dma_addr = mem_res->start + S3C_AC97_PCM_DATA; | ||
416 | s3c_ac97_mic_in.channel = dmamic_res->start; | ||
417 | s3c_ac97_mic_in.dma_addr = mem_res->start + S3C_AC97_MIC_DATA; | ||
418 | |||
419 | init_completion(&s3c_ac97.done); | ||
420 | mutex_init(&s3c_ac97.lock); | ||
421 | |||
422 | s3c_ac97.regs = ioremap(mem_res->start, resource_size(mem_res)); | ||
423 | if (s3c_ac97.regs == NULL) { | ||
424 | dev_err(&pdev->dev, "Unable to ioremap register region\n"); | ||
425 | ret = -ENXIO; | ||
426 | goto err1; | ||
427 | } | ||
428 | |||
429 | s3c_ac97.ac97_clk = clk_get(&pdev->dev, "ac97"); | ||
430 | if (IS_ERR(s3c_ac97.ac97_clk)) { | ||
431 | dev_err(&pdev->dev, "s3c-ac97 failed to get ac97_clock\n"); | ||
432 | ret = -ENODEV; | ||
433 | goto err2; | ||
434 | } | ||
435 | clk_enable(s3c_ac97.ac97_clk); | ||
436 | |||
437 | if (ac97_pdata->cfg_gpio(pdev)) { | ||
438 | dev_err(&pdev->dev, "Unable to configure gpio\n"); | ||
439 | ret = -EINVAL; | ||
440 | goto err3; | ||
441 | } | ||
442 | |||
443 | ret = request_irq(irq_res->start, s3c_ac97_irq, | ||
444 | IRQF_DISABLED, "AC97", NULL); | ||
445 | if (ret < 0) { | ||
446 | printk(KERN_ERR "s3c-ac97: interrupt request failed.\n"); | ||
447 | goto err4; | ||
448 | } | ||
449 | |||
450 | s3c_ac97_dai[S3C_AC97_DAI_PCM].dev = &pdev->dev; | ||
451 | s3c_ac97_dai[S3C_AC97_DAI_MIC].dev = &pdev->dev; | ||
452 | |||
453 | ret = snd_soc_register_dais(s3c_ac97_dai, ARRAY_SIZE(s3c_ac97_dai)); | ||
454 | if (ret) | ||
455 | goto err5; | ||
456 | |||
457 | return 0; | ||
458 | |||
459 | err5: | ||
460 | free_irq(irq_res->start, NULL); | ||
461 | err4: | ||
462 | err3: | ||
463 | clk_disable(s3c_ac97.ac97_clk); | ||
464 | clk_put(s3c_ac97.ac97_clk); | ||
465 | err2: | ||
466 | iounmap(s3c_ac97.regs); | ||
467 | err1: | ||
468 | release_mem_region(mem_res->start, resource_size(mem_res)); | ||
469 | |||
470 | return ret; | ||
471 | } | ||
472 | |||
473 | static __devexit int s3c_ac97_remove(struct platform_device *pdev) | ||
474 | { | ||
475 | struct resource *mem_res, *irq_res; | ||
476 | |||
477 | snd_soc_unregister_dais(s3c_ac97_dai, ARRAY_SIZE(s3c_ac97_dai)); | ||
478 | |||
479 | irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | ||
480 | if (irq_res) | ||
481 | free_irq(irq_res->start, NULL); | ||
482 | |||
483 | clk_disable(s3c_ac97.ac97_clk); | ||
484 | clk_put(s3c_ac97.ac97_clk); | ||
485 | |||
486 | iounmap(s3c_ac97.regs); | ||
487 | |||
488 | mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
489 | if (mem_res) | ||
490 | release_mem_region(mem_res->start, resource_size(mem_res)); | ||
491 | |||
492 | return 0; | ||
493 | } | ||
494 | |||
495 | static struct platform_driver s3c_ac97_driver = { | ||
496 | .probe = s3c_ac97_probe, | ||
497 | .remove = s3c_ac97_remove, | ||
498 | .driver = { | ||
499 | .name = "s3c-ac97", | ||
500 | .owner = THIS_MODULE, | ||
501 | }, | ||
502 | }; | ||
503 | |||
504 | static int __init s3c_ac97_init(void) | ||
505 | { | ||
506 | return platform_driver_register(&s3c_ac97_driver); | ||
507 | } | ||
508 | module_init(s3c_ac97_init); | ||
509 | |||
510 | static void __exit s3c_ac97_exit(void) | ||
511 | { | ||
512 | platform_driver_unregister(&s3c_ac97_driver); | ||
513 | } | ||
514 | module_exit(s3c_ac97_exit); | ||
515 | |||
516 | MODULE_AUTHOR("Jaswinder Singh, <jassi.brar@samsung.com>"); | ||
517 | MODULE_DESCRIPTION("AC97 driver for the Samsung SoC"); | ||
518 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/s3c24xx/s3c-ac97.h b/sound/soc/s3c24xx/s3c-ac97.h new file mode 100644 index 000000000000..278198379def --- /dev/null +++ b/sound/soc/s3c24xx/s3c-ac97.h | |||
@@ -0,0 +1,23 @@ | |||
1 | /* sound/soc/s3c24xx/s3c-ac97.h | ||
2 | * | ||
3 | * ALSA SoC Audio Layer - S3C AC97 Controller driver | ||
4 | * Evolved from s3c2443-ac97.h | ||
5 | * | ||
6 | * Copyright (c) 2010 Samsung Electronics Co. Ltd | ||
7 | * Author: Jaswinder Singh <jassi.brar@samsung.com> | ||
8 | * Credits: Graeme Gregory, Sean Choi | ||
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 __S3C_AC97_H_ | ||
16 | #define __S3C_AC97_H_ | ||
17 | |||
18 | #define S3C_AC97_DAI_PCM 0 | ||
19 | #define S3C_AC97_DAI_MIC 1 | ||
20 | |||
21 | extern struct snd_soc_dai s3c_ac97_dai[]; | ||
22 | |||
23 | #endif /* __S3C_AC97_H_ */ | ||
diff --git a/sound/soc/s3c24xx/s3c-pcm.c b/sound/soc/s3c24xx/s3c-pcm.c index 9e61a7c2d9ac..a98f40c3cd29 100644 --- a/sound/soc/s3c24xx/s3c-pcm.c +++ b/sound/soc/s3c24xx/s3c-pcm.c | |||
@@ -229,8 +229,7 @@ static int s3c_pcm_hw_params(struct snd_pcm_substream *substream, | |||
229 | 229 | ||
230 | spin_unlock_irqrestore(&pcm->lock, flags); | 230 | spin_unlock_irqrestore(&pcm->lock, flags); |
231 | 231 | ||
232 | dev_dbg(pcm->dev, "PCMSOURCE_CLK-%lu SCLK=%ufs \ | 232 | dev_dbg(pcm->dev, "PCMSOURCE_CLK-%lu SCLK=%ufs SCLK_DIV=%d SYNC_DIV=%d\n", |
233 | SCLK_DIV=%d SYNC_DIV=%d\n", | ||
234 | clk_get_rate(clk), pcm->sclk_per_fs, | 233 | clk_get_rate(clk), pcm->sclk_per_fs, |
235 | sclk_div, sync_div); | 234 | sclk_div, sync_div); |
236 | 235 | ||
diff --git a/sound/soc/s3c24xx/s3c2443-ac97.c b/sound/soc/s3c24xx/s3c2443-ac97.c deleted file mode 100644 index 0191e3acb0b4..000000000000 --- a/sound/soc/s3c24xx/s3c2443-ac97.c +++ /dev/null | |||
@@ -1,432 +0,0 @@ | |||
1 | /* | ||
2 | * s3c2443-ac97.c -- ALSA Soc Audio Layer | ||
3 | * | ||
4 | * (c) 2007 Wolfson Microelectronics PLC. | ||
5 | * Graeme Gregory graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com | ||
6 | * | ||
7 | * Copyright (C) 2005, Sean Choi <sh428.choi@samsung.com> | ||
8 | * All rights reserved. | ||
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/init.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/platform_device.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/io.h> | ||
20 | #include <linux/wait.h> | ||
21 | #include <linux/delay.h> | ||
22 | #include <linux/gpio.h> | ||
23 | #include <linux/clk.h> | ||
24 | |||
25 | #include <sound/core.h> | ||
26 | #include <sound/pcm.h> | ||
27 | #include <sound/ac97_codec.h> | ||
28 | #include <sound/initval.h> | ||
29 | #include <sound/soc.h> | ||
30 | |||
31 | #include <mach/hardware.h> | ||
32 | #include <plat/regs-ac97.h> | ||
33 | #include <mach/regs-gpio.h> | ||
34 | #include <mach/regs-clock.h> | ||
35 | #include <asm/dma.h> | ||
36 | #include <mach/dma.h> | ||
37 | |||
38 | #include "s3c-dma.h" | ||
39 | #include "s3c24xx-ac97.h" | ||
40 | |||
41 | struct s3c24xx_ac97_info { | ||
42 | void __iomem *regs; | ||
43 | struct clk *ac97_clk; | ||
44 | }; | ||
45 | static struct s3c24xx_ac97_info s3c24xx_ac97; | ||
46 | |||
47 | static DECLARE_COMPLETION(ac97_completion); | ||
48 | static u32 codec_ready; | ||
49 | static DEFINE_MUTEX(ac97_mutex); | ||
50 | |||
51 | static unsigned short s3c2443_ac97_read(struct snd_ac97 *ac97, | ||
52 | unsigned short reg) | ||
53 | { | ||
54 | u32 ac_glbctrl; | ||
55 | u32 ac_codec_cmd; | ||
56 | u32 stat, addr, data; | ||
57 | |||
58 | mutex_lock(&ac97_mutex); | ||
59 | |||
60 | codec_ready = S3C_AC97_GLBSTAT_CODECREADY; | ||
61 | ac_codec_cmd = readl(s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD); | ||
62 | ac_codec_cmd = S3C_AC97_CODEC_CMD_READ | AC_CMD_ADDR(reg); | ||
63 | writel(ac_codec_cmd, s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD); | ||
64 | |||
65 | udelay(50); | ||
66 | |||
67 | ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); | ||
68 | ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE; | ||
69 | writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); | ||
70 | |||
71 | wait_for_completion(&ac97_completion); | ||
72 | |||
73 | stat = readl(s3c24xx_ac97.regs + S3C_AC97_STAT); | ||
74 | addr = (stat >> 16) & 0x7f; | ||
75 | data = (stat & 0xffff); | ||
76 | |||
77 | if (addr != reg) | ||
78 | printk(KERN_ERR "s3c24xx-ac97: req addr = %02x," | ||
79 | " rep addr = %02x\n", reg, addr); | ||
80 | |||
81 | mutex_unlock(&ac97_mutex); | ||
82 | |||
83 | return (unsigned short)data; | ||
84 | } | ||
85 | |||
86 | static void s3c2443_ac97_write(struct snd_ac97 *ac97, unsigned short reg, | ||
87 | unsigned short val) | ||
88 | { | ||
89 | u32 ac_glbctrl; | ||
90 | u32 ac_codec_cmd; | ||
91 | |||
92 | mutex_lock(&ac97_mutex); | ||
93 | |||
94 | codec_ready = S3C_AC97_GLBSTAT_CODECREADY; | ||
95 | ac_codec_cmd = readl(s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD); | ||
96 | ac_codec_cmd = AC_CMD_ADDR(reg) | AC_CMD_DATA(val); | ||
97 | writel(ac_codec_cmd, s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD); | ||
98 | |||
99 | udelay(50); | ||
100 | |||
101 | ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); | ||
102 | ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE; | ||
103 | writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); | ||
104 | |||
105 | wait_for_completion(&ac97_completion); | ||
106 | |||
107 | ac_codec_cmd = readl(s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD); | ||
108 | ac_codec_cmd |= S3C_AC97_CODEC_CMD_READ; | ||
109 | writel(ac_codec_cmd, s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD); | ||
110 | |||
111 | mutex_unlock(&ac97_mutex); | ||
112 | |||
113 | } | ||
114 | |||
115 | static void s3c2443_ac97_warm_reset(struct snd_ac97 *ac97) | ||
116 | { | ||
117 | u32 ac_glbctrl; | ||
118 | |||
119 | ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); | ||
120 | ac_glbctrl = S3C_AC97_GLBCTRL_WARMRESET; | ||
121 | writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); | ||
122 | msleep(1); | ||
123 | |||
124 | ac_glbctrl = 0; | ||
125 | writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); | ||
126 | msleep(1); | ||
127 | } | ||
128 | |||
129 | static void s3c2443_ac97_cold_reset(struct snd_ac97 *ac97) | ||
130 | { | ||
131 | u32 ac_glbctrl; | ||
132 | |||
133 | ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); | ||
134 | ac_glbctrl = S3C_AC97_GLBCTRL_COLDRESET; | ||
135 | writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); | ||
136 | msleep(1); | ||
137 | |||
138 | ac_glbctrl = 0; | ||
139 | writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); | ||
140 | msleep(1); | ||
141 | |||
142 | ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); | ||
143 | ac_glbctrl = S3C_AC97_GLBCTRL_ACLINKON; | ||
144 | writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); | ||
145 | msleep(1); | ||
146 | |||
147 | ac_glbctrl |= S3C_AC97_GLBCTRL_TRANSFERDATAENABLE; | ||
148 | writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); | ||
149 | msleep(1); | ||
150 | |||
151 | ac_glbctrl |= S3C_AC97_GLBCTRL_PCMOUTTM_DMA | | ||
152 | S3C_AC97_GLBCTRL_PCMINTM_DMA | S3C_AC97_GLBCTRL_MICINTM_DMA; | ||
153 | writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); | ||
154 | } | ||
155 | |||
156 | static irqreturn_t s3c2443_ac97_irq(int irq, void *dev_id) | ||
157 | { | ||
158 | int status; | ||
159 | u32 ac_glbctrl; | ||
160 | |||
161 | status = readl(s3c24xx_ac97.regs + S3C_AC97_GLBSTAT) & codec_ready; | ||
162 | |||
163 | if (status) { | ||
164 | ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); | ||
165 | ac_glbctrl &= ~S3C_AC97_GLBCTRL_CODECREADYIE; | ||
166 | writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); | ||
167 | complete(&ac97_completion); | ||
168 | } | ||
169 | return IRQ_HANDLED; | ||
170 | } | ||
171 | |||
172 | struct snd_ac97_bus_ops soc_ac97_ops = { | ||
173 | .read = s3c2443_ac97_read, | ||
174 | .write = s3c2443_ac97_write, | ||
175 | .warm_reset = s3c2443_ac97_warm_reset, | ||
176 | .reset = s3c2443_ac97_cold_reset, | ||
177 | }; | ||
178 | |||
179 | static struct s3c2410_dma_client s3c2443_dma_client_out = { | ||
180 | .name = "AC97 PCM Stereo out" | ||
181 | }; | ||
182 | |||
183 | static struct s3c2410_dma_client s3c2443_dma_client_in = { | ||
184 | .name = "AC97 PCM Stereo in" | ||
185 | }; | ||
186 | |||
187 | static struct s3c2410_dma_client s3c2443_dma_client_micin = { | ||
188 | .name = "AC97 Mic Mono in" | ||
189 | }; | ||
190 | |||
191 | static struct s3c_dma_params s3c2443_ac97_pcm_stereo_out = { | ||
192 | .client = &s3c2443_dma_client_out, | ||
193 | .channel = DMACH_PCM_OUT, | ||
194 | .dma_addr = S3C2440_PA_AC97 + S3C_AC97_PCM_DATA, | ||
195 | .dma_size = 4, | ||
196 | }; | ||
197 | |||
198 | static struct s3c_dma_params s3c2443_ac97_pcm_stereo_in = { | ||
199 | .client = &s3c2443_dma_client_in, | ||
200 | .channel = DMACH_PCM_IN, | ||
201 | .dma_addr = S3C2440_PA_AC97 + S3C_AC97_PCM_DATA, | ||
202 | .dma_size = 4, | ||
203 | }; | ||
204 | |||
205 | static struct s3c_dma_params s3c2443_ac97_mic_mono_in = { | ||
206 | .client = &s3c2443_dma_client_micin, | ||
207 | .channel = DMACH_MIC_IN, | ||
208 | .dma_addr = S3C2440_PA_AC97 + S3C_AC97_MIC_DATA, | ||
209 | .dma_size = 4, | ||
210 | }; | ||
211 | |||
212 | static int s3c2443_ac97_probe(struct platform_device *pdev, | ||
213 | struct snd_soc_dai *dai) | ||
214 | { | ||
215 | int ret; | ||
216 | u32 ac_glbctrl; | ||
217 | |||
218 | s3c24xx_ac97.regs = ioremap(S3C2440_PA_AC97, 0x100); | ||
219 | if (s3c24xx_ac97.regs == NULL) | ||
220 | return -ENXIO; | ||
221 | |||
222 | s3c24xx_ac97.ac97_clk = clk_get(&pdev->dev, "ac97"); | ||
223 | if (s3c24xx_ac97.ac97_clk == NULL) { | ||
224 | printk(KERN_ERR "s3c2443-ac97 failed to get ac97_clock\n"); | ||
225 | iounmap(s3c24xx_ac97.regs); | ||
226 | return -ENODEV; | ||
227 | } | ||
228 | clk_enable(s3c24xx_ac97.ac97_clk); | ||
229 | |||
230 | s3c2410_gpio_cfgpin(S3C2410_GPE0, S3C2443_GPE0_AC_nRESET); | ||
231 | s3c2410_gpio_cfgpin(S3C2410_GPE1, S3C2443_GPE1_AC_SYNC); | ||
232 | s3c2410_gpio_cfgpin(S3C2410_GPE2, S3C2443_GPE2_AC_BITCLK); | ||
233 | s3c2410_gpio_cfgpin(S3C2410_GPE3, S3C2443_GPE3_AC_SDI); | ||
234 | s3c2410_gpio_cfgpin(S3C2410_GPE4, S3C2443_GPE4_AC_SDO); | ||
235 | |||
236 | ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); | ||
237 | ac_glbctrl = S3C_AC97_GLBCTRL_COLDRESET; | ||
238 | writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); | ||
239 | msleep(1); | ||
240 | |||
241 | ac_glbctrl = 0; | ||
242 | writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); | ||
243 | msleep(1); | ||
244 | |||
245 | ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); | ||
246 | ac_glbctrl = S3C_AC97_GLBCTRL_ACLINKON; | ||
247 | writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); | ||
248 | msleep(1); | ||
249 | |||
250 | ac_glbctrl |= S3C_AC97_GLBCTRL_TRANSFERDATAENABLE; | ||
251 | writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); | ||
252 | |||
253 | ret = request_irq(IRQ_S3C244x_AC97, s3c2443_ac97_irq, | ||
254 | IRQF_DISABLED, "AC97", NULL); | ||
255 | if (ret < 0) { | ||
256 | printk(KERN_ERR "s3c24xx-ac97: interrupt request failed.\n"); | ||
257 | clk_disable(s3c24xx_ac97.ac97_clk); | ||
258 | clk_put(s3c24xx_ac97.ac97_clk); | ||
259 | iounmap(s3c24xx_ac97.regs); | ||
260 | } | ||
261 | return ret; | ||
262 | } | ||
263 | |||
264 | static void s3c2443_ac97_remove(struct platform_device *pdev, | ||
265 | struct snd_soc_dai *dai) | ||
266 | { | ||
267 | free_irq(IRQ_S3C244x_AC97, NULL); | ||
268 | clk_disable(s3c24xx_ac97.ac97_clk); | ||
269 | clk_put(s3c24xx_ac97.ac97_clk); | ||
270 | iounmap(s3c24xx_ac97.regs); | ||
271 | } | ||
272 | |||
273 | static int s3c2443_ac97_hw_params(struct snd_pcm_substream *substream, | ||
274 | struct snd_pcm_hw_params *params, | ||
275 | struct snd_soc_dai *dai) | ||
276 | { | ||
277 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
278 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | ||
279 | |||
280 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
281 | cpu_dai->dma_data = &s3c2443_ac97_pcm_stereo_out; | ||
282 | else | ||
283 | cpu_dai->dma_data = &s3c2443_ac97_pcm_stereo_in; | ||
284 | |||
285 | return 0; | ||
286 | } | ||
287 | |||
288 | static int s3c2443_ac97_trigger(struct snd_pcm_substream *substream, int cmd, | ||
289 | struct snd_soc_dai *dai) | ||
290 | { | ||
291 | u32 ac_glbctrl; | ||
292 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
293 | int channel = ((struct s3c_dma_params *) | ||
294 | rtd->dai->cpu_dai->dma_data)->channel; | ||
295 | |||
296 | ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); | ||
297 | switch (cmd) { | ||
298 | case SNDRV_PCM_TRIGGER_START: | ||
299 | case SNDRV_PCM_TRIGGER_RESUME: | ||
300 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
301 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) | ||
302 | ac_glbctrl |= S3C_AC97_GLBCTRL_PCMINTM_DMA; | ||
303 | else | ||
304 | ac_glbctrl |= S3C_AC97_GLBCTRL_PCMOUTTM_DMA; | ||
305 | break; | ||
306 | case SNDRV_PCM_TRIGGER_STOP: | ||
307 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
308 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
309 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) | ||
310 | ac_glbctrl &= ~S3C_AC97_GLBCTRL_PCMINTM_MASK; | ||
311 | else | ||
312 | ac_glbctrl &= ~S3C_AC97_GLBCTRL_PCMOUTTM_MASK; | ||
313 | break; | ||
314 | } | ||
315 | writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); | ||
316 | |||
317 | s3c2410_dma_ctrl(channel, S3C2410_DMAOP_STARTED); | ||
318 | |||
319 | return 0; | ||
320 | } | ||
321 | |||
322 | static int s3c2443_ac97_hw_mic_params(struct snd_pcm_substream *substream, | ||
323 | struct snd_pcm_hw_params *params, | ||
324 | struct snd_soc_dai *dai) | ||
325 | { | ||
326 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
327 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | ||
328 | |||
329 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
330 | return -ENODEV; | ||
331 | else | ||
332 | cpu_dai->dma_data = &s3c2443_ac97_mic_mono_in; | ||
333 | |||
334 | return 0; | ||
335 | } | ||
336 | |||
337 | static int s3c2443_ac97_mic_trigger(struct snd_pcm_substream *substream, | ||
338 | int cmd, struct snd_soc_dai *dai) | ||
339 | { | ||
340 | u32 ac_glbctrl; | ||
341 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
342 | int channel = ((struct s3c_dma_params *) | ||
343 | rtd->dai->cpu_dai->dma_data)->channel; | ||
344 | |||
345 | ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); | ||
346 | switch (cmd) { | ||
347 | case SNDRV_PCM_TRIGGER_START: | ||
348 | case SNDRV_PCM_TRIGGER_RESUME: | ||
349 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
350 | ac_glbctrl |= S3C_AC97_GLBCTRL_PCMINTM_DMA; | ||
351 | break; | ||
352 | case SNDRV_PCM_TRIGGER_STOP: | ||
353 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
354 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
355 | ac_glbctrl &= ~S3C_AC97_GLBCTRL_PCMINTM_MASK; | ||
356 | } | ||
357 | writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); | ||
358 | |||
359 | s3c2410_dma_ctrl(channel, S3C2410_DMAOP_STARTED); | ||
360 | |||
361 | return 0; | ||
362 | } | ||
363 | |||
364 | #define s3c2443_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ | ||
365 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \ | ||
366 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) | ||
367 | |||
368 | static struct snd_soc_dai_ops s3c2443_ac97_dai_ops = { | ||
369 | .hw_params = s3c2443_ac97_hw_params, | ||
370 | .trigger = s3c2443_ac97_trigger, | ||
371 | }; | ||
372 | |||
373 | static struct snd_soc_dai_ops s3c2443_ac97_mic_dai_ops = { | ||
374 | .hw_params = s3c2443_ac97_hw_mic_params, | ||
375 | .trigger = s3c2443_ac97_mic_trigger, | ||
376 | }; | ||
377 | |||
378 | struct snd_soc_dai s3c2443_ac97_dai[] = { | ||
379 | { | ||
380 | .name = "s3c2443-ac97", | ||
381 | .id = 0, | ||
382 | .ac97_control = 1, | ||
383 | .probe = s3c2443_ac97_probe, | ||
384 | .remove = s3c2443_ac97_remove, | ||
385 | .playback = { | ||
386 | .stream_name = "AC97 Playback", | ||
387 | .channels_min = 2, | ||
388 | .channels_max = 2, | ||
389 | .rates = s3c2443_AC97_RATES, | ||
390 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | ||
391 | .capture = { | ||
392 | .stream_name = "AC97 Capture", | ||
393 | .channels_min = 2, | ||
394 | .channels_max = 2, | ||
395 | .rates = s3c2443_AC97_RATES, | ||
396 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | ||
397 | .ops = &s3c2443_ac97_dai_ops, | ||
398 | }, | ||
399 | { | ||
400 | .name = "pxa2xx-ac97-mic", | ||
401 | .id = 1, | ||
402 | .ac97_control = 1, | ||
403 | .capture = { | ||
404 | .stream_name = "AC97 Mic Capture", | ||
405 | .channels_min = 1, | ||
406 | .channels_max = 1, | ||
407 | .rates = s3c2443_AC97_RATES, | ||
408 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | ||
409 | .ops = &s3c2443_ac97_mic_dai_ops, | ||
410 | }, | ||
411 | }; | ||
412 | EXPORT_SYMBOL_GPL(s3c2443_ac97_dai); | ||
413 | EXPORT_SYMBOL_GPL(soc_ac97_ops); | ||
414 | |||
415 | static int __init s3c2443_ac97_init(void) | ||
416 | { | ||
417 | return snd_soc_register_dais(s3c2443_ac97_dai, | ||
418 | ARRAY_SIZE(s3c2443_ac97_dai)); | ||
419 | } | ||
420 | module_init(s3c2443_ac97_init); | ||
421 | |||
422 | static void __exit s3c2443_ac97_exit(void) | ||
423 | { | ||
424 | snd_soc_unregister_dais(s3c2443_ac97_dai, | ||
425 | ARRAY_SIZE(s3c2443_ac97_dai)); | ||
426 | } | ||
427 | module_exit(s3c2443_ac97_exit); | ||
428 | |||
429 | |||
430 | MODULE_AUTHOR("Graeme Gregory"); | ||
431 | MODULE_DESCRIPTION("AC97 driver for the Samsung s3c2443 chip"); | ||
432 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/s3c24xx/s3c24xx-ac97.h b/sound/soc/s3c24xx/s3c24xx-ac97.h deleted file mode 100644 index e96f941a810b..000000000000 --- a/sound/soc/s3c24xx/s3c24xx-ac97.h +++ /dev/null | |||
@@ -1,25 +0,0 @@ | |||
1 | /* | ||
2 | * s3c24xx-ac97.c -- ALSA Soc Audio Layer | ||
3 | * | ||
4 | * (c) 2007 Wolfson Microelectronics PLC. | ||
5 | * Author: Graeme Gregory | ||
6 | * graeme.gregory@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 | * 10th Nov 2006 Initial version. | ||
15 | */ | ||
16 | |||
17 | #ifndef S3C24XXAC97_H_ | ||
18 | #define S3C24XXAC97_H_ | ||
19 | |||
20 | #define AC_CMD_ADDR(x) (x << 16) | ||
21 | #define AC_CMD_DATA(x) (x & 0xffff) | ||
22 | |||
23 | extern struct snd_soc_dai s3c2443_ac97_dai[]; | ||
24 | |||
25 | #endif /*S3C24XXAC97_H_*/ | ||
diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.c b/sound/soc/s3c24xx/s3c64xx-i2s.c index cc7edb5f792d..93ed3aad1631 100644 --- a/sound/soc/s3c24xx/s3c64xx-i2s.c +++ b/sound/soc/s3c24xx/s3c64xx-i2s.c | |||
@@ -15,16 +15,10 @@ | |||
15 | #include <linux/init.h> | 15 | #include <linux/init.h> |
16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
17 | #include <linux/device.h> | 17 | #include <linux/device.h> |
18 | #include <linux/delay.h> | ||
19 | #include <linux/clk.h> | 18 | #include <linux/clk.h> |
20 | #include <linux/kernel.h> | ||
21 | #include <linux/gpio.h> | 19 | #include <linux/gpio.h> |
22 | #include <linux/io.h> | 20 | #include <linux/io.h> |
23 | 21 | ||
24 | #include <sound/core.h> | ||
25 | #include <sound/pcm.h> | ||
26 | #include <sound/pcm_params.h> | ||
27 | #include <sound/initval.h> | ||
28 | #include <sound/soc.h> | 22 | #include <sound/soc.h> |
29 | 23 | ||
30 | #include <plat/regs-s3c2412-iis.h> | 24 | #include <plat/regs-s3c2412-iis.h> |
@@ -38,6 +32,11 @@ | |||
38 | #include "s3c-dma.h" | 32 | #include "s3c-dma.h" |
39 | #include "s3c64xx-i2s.h" | 33 | #include "s3c64xx-i2s.h" |
40 | 34 | ||
35 | /* The value should be set to maximum of the total number | ||
36 | * of I2Sv3 controllers that any supported SoC has. | ||
37 | */ | ||
38 | #define MAX_I2SV3 2 | ||
39 | |||
41 | static struct s3c2410_dma_client s3c64xx_dma_client_out = { | 40 | static struct s3c2410_dma_client s3c64xx_dma_client_out = { |
42 | .name = "I2S PCM Stereo out" | 41 | .name = "I2S PCM Stereo out" |
43 | }; | 42 | }; |
@@ -46,37 +45,12 @@ static struct s3c2410_dma_client s3c64xx_dma_client_in = { | |||
46 | .name = "I2S PCM Stereo in" | 45 | .name = "I2S PCM Stereo in" |
47 | }; | 46 | }; |
48 | 47 | ||
49 | static struct s3c_dma_params s3c64xx_i2s_pcm_stereo_out[2] = { | 48 | static struct s3c_dma_params s3c64xx_i2s_pcm_stereo_out[MAX_I2SV3]; |
50 | [0] = { | 49 | static struct s3c_dma_params s3c64xx_i2s_pcm_stereo_in[MAX_I2SV3]; |
51 | .channel = DMACH_I2S0_OUT, | 50 | static struct s3c_i2sv2_info s3c64xx_i2s[MAX_I2SV3]; |
52 | .client = &s3c64xx_dma_client_out, | ||
53 | .dma_addr = S3C64XX_PA_IIS0 + S3C2412_IISTXD, | ||
54 | .dma_size = 4, | ||
55 | }, | ||
56 | [1] = { | ||
57 | .channel = DMACH_I2S1_OUT, | ||
58 | .client = &s3c64xx_dma_client_out, | ||
59 | .dma_addr = S3C64XX_PA_IIS1 + S3C2412_IISTXD, | ||
60 | .dma_size = 4, | ||
61 | }, | ||
62 | }; | ||
63 | |||
64 | static struct s3c_dma_params s3c64xx_i2s_pcm_stereo_in[2] = { | ||
65 | [0] = { | ||
66 | .channel = DMACH_I2S0_IN, | ||
67 | .client = &s3c64xx_dma_client_in, | ||
68 | .dma_addr = S3C64XX_PA_IIS0 + S3C2412_IISRXD, | ||
69 | .dma_size = 4, | ||
70 | }, | ||
71 | [1] = { | ||
72 | .channel = DMACH_I2S1_IN, | ||
73 | .client = &s3c64xx_dma_client_in, | ||
74 | .dma_addr = S3C64XX_PA_IIS1 + S3C2412_IISRXD, | ||
75 | .dma_size = 4, | ||
76 | }, | ||
77 | }; | ||
78 | 51 | ||
79 | static struct s3c_i2sv2_info s3c64xx_i2s[2]; | 52 | struct snd_soc_dai s3c64xx_i2s_dai[MAX_I2SV3]; |
53 | EXPORT_SYMBOL_GPL(s3c64xx_i2s_dai); | ||
80 | 54 | ||
81 | static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai) | 55 | static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai) |
82 | { | 56 | { |
@@ -169,55 +143,13 @@ static struct snd_soc_dai_ops s3c64xx_i2s_dai_ops = { | |||
169 | .set_sysclk = s3c64xx_i2s_set_sysclk, | 143 | .set_sysclk = s3c64xx_i2s_set_sysclk, |
170 | }; | 144 | }; |
171 | 145 | ||
172 | struct snd_soc_dai s3c64xx_i2s_dai[] = { | ||
173 | { | ||
174 | .name = "s3c64xx-i2s", | ||
175 | .id = 0, | ||
176 | .probe = s3c64xx_i2s_probe, | ||
177 | .playback = { | ||
178 | .channels_min = 2, | ||
179 | .channels_max = 2, | ||
180 | .rates = S3C64XX_I2S_RATES, | ||
181 | .formats = S3C64XX_I2S_FMTS, | ||
182 | }, | ||
183 | .capture = { | ||
184 | .channels_min = 2, | ||
185 | .channels_max = 2, | ||
186 | .rates = S3C64XX_I2S_RATES, | ||
187 | .formats = S3C64XX_I2S_FMTS, | ||
188 | }, | ||
189 | .ops = &s3c64xx_i2s_dai_ops, | ||
190 | .symmetric_rates = 1, | ||
191 | }, | ||
192 | { | ||
193 | .name = "s3c64xx-i2s", | ||
194 | .id = 1, | ||
195 | .probe = s3c64xx_i2s_probe, | ||
196 | .playback = { | ||
197 | .channels_min = 2, | ||
198 | .channels_max = 2, | ||
199 | .rates = S3C64XX_I2S_RATES, | ||
200 | .formats = S3C64XX_I2S_FMTS, | ||
201 | }, | ||
202 | .capture = { | ||
203 | .channels_min = 2, | ||
204 | .channels_max = 2, | ||
205 | .rates = S3C64XX_I2S_RATES, | ||
206 | .formats = S3C64XX_I2S_FMTS, | ||
207 | }, | ||
208 | .ops = &s3c64xx_i2s_dai_ops, | ||
209 | .symmetric_rates = 1, | ||
210 | }, | ||
211 | }; | ||
212 | EXPORT_SYMBOL_GPL(s3c64xx_i2s_dai); | ||
213 | |||
214 | static __devinit int s3c64xx_iis_dev_probe(struct platform_device *pdev) | 146 | static __devinit int s3c64xx_iis_dev_probe(struct platform_device *pdev) |
215 | { | 147 | { |
216 | struct s3c_i2sv2_info *i2s; | 148 | struct s3c_i2sv2_info *i2s; |
217 | struct snd_soc_dai *dai; | 149 | struct snd_soc_dai *dai; |
218 | int ret; | 150 | int ret; |
219 | 151 | ||
220 | if (pdev->id >= ARRAY_SIZE(s3c64xx_i2s)) { | 152 | if (pdev->id >= MAX_I2SV3) { |
221 | dev_err(&pdev->dev, "id %d out of range\n", pdev->id); | 153 | dev_err(&pdev->dev, "id %d out of range\n", pdev->id); |
222 | return -EINVAL; | 154 | return -EINVAL; |
223 | } | 155 | } |
@@ -225,10 +157,40 @@ static __devinit int s3c64xx_iis_dev_probe(struct platform_device *pdev) | |||
225 | i2s = &s3c64xx_i2s[pdev->id]; | 157 | i2s = &s3c64xx_i2s[pdev->id]; |
226 | dai = &s3c64xx_i2s_dai[pdev->id]; | 158 | dai = &s3c64xx_i2s_dai[pdev->id]; |
227 | dai->dev = &pdev->dev; | 159 | dai->dev = &pdev->dev; |
160 | dai->name = "s3c64xx-i2s"; | ||
161 | dai->id = pdev->id; | ||
162 | dai->symmetric_rates = 1; | ||
163 | dai->playback.channels_min = 2; | ||
164 | dai->playback.channels_max = 2; | ||
165 | dai->playback.rates = S3C64XX_I2S_RATES; | ||
166 | dai->playback.formats = S3C64XX_I2S_FMTS; | ||
167 | dai->capture.channels_min = 2; | ||
168 | dai->capture.channels_max = 2; | ||
169 | dai->capture.rates = S3C64XX_I2S_RATES; | ||
170 | dai->capture.formats = S3C64XX_I2S_FMTS; | ||
171 | dai->probe = s3c64xx_i2s_probe; | ||
172 | dai->ops = &s3c64xx_i2s_dai_ops; | ||
228 | 173 | ||
229 | i2s->dma_capture = &s3c64xx_i2s_pcm_stereo_in[pdev->id]; | 174 | i2s->dma_capture = &s3c64xx_i2s_pcm_stereo_in[pdev->id]; |
230 | i2s->dma_playback = &s3c64xx_i2s_pcm_stereo_out[pdev->id]; | 175 | i2s->dma_playback = &s3c64xx_i2s_pcm_stereo_out[pdev->id]; |
231 | 176 | ||
177 | if (pdev->id == 0) { | ||
178 | i2s->dma_capture->channel = DMACH_I2S0_IN; | ||
179 | i2s->dma_capture->dma_addr = S3C64XX_PA_IIS0 + S3C2412_IISRXD; | ||
180 | i2s->dma_playback->channel = DMACH_I2S0_OUT; | ||
181 | i2s->dma_playback->dma_addr = S3C64XX_PA_IIS0 + S3C2412_IISTXD; | ||
182 | } else { | ||
183 | i2s->dma_capture->channel = DMACH_I2S1_IN; | ||
184 | i2s->dma_capture->dma_addr = S3C64XX_PA_IIS1 + S3C2412_IISRXD; | ||
185 | i2s->dma_playback->channel = DMACH_I2S1_OUT; | ||
186 | i2s->dma_playback->dma_addr = S3C64XX_PA_IIS1 + S3C2412_IISTXD; | ||
187 | } | ||
188 | |||
189 | i2s->dma_capture->client = &s3c64xx_dma_client_in; | ||
190 | i2s->dma_capture->dma_size = 4; | ||
191 | i2s->dma_playback->client = &s3c64xx_dma_client_out; | ||
192 | i2s->dma_playback->dma_size = 4; | ||
193 | |||
232 | i2s->iis_cclk = clk_get(&pdev->dev, "audio-bus"); | 194 | i2s->iis_cclk = clk_get(&pdev->dev, "audio-bus"); |
233 | if (IS_ERR(i2s->iis_cclk)) { | 195 | if (IS_ERR(i2s->iis_cclk)) { |
234 | dev_err(&pdev->dev, "failed to get audio-bus\n"); | 196 | dev_err(&pdev->dev, "failed to get audio-bus\n"); |
diff --git a/sound/soc/s3c24xx/smdk2443_wm9710.c b/sound/soc/s3c24xx/smdk2443_wm9710.c index 12b783b12fcb..362258835e8d 100644 --- a/sound/soc/s3c24xx/smdk2443_wm9710.c +++ b/sound/soc/s3c24xx/smdk2443_wm9710.c | |||
@@ -21,7 +21,7 @@ | |||
21 | 21 | ||
22 | #include "../codecs/ac97.h" | 22 | #include "../codecs/ac97.h" |
23 | #include "s3c-dma.h" | 23 | #include "s3c-dma.h" |
24 | #include "s3c24xx-ac97.h" | 24 | #include "s3c-ac97.h" |
25 | 25 | ||
26 | static struct snd_soc_card smdk2443; | 26 | static struct snd_soc_card smdk2443; |
27 | 27 | ||
@@ -29,7 +29,7 @@ static struct snd_soc_dai_link smdk2443_dai[] = { | |||
29 | { | 29 | { |
30 | .name = "AC97", | 30 | .name = "AC97", |
31 | .stream_name = "AC97 HiFi", | 31 | .stream_name = "AC97 HiFi", |
32 | .cpu_dai = &s3c2443_ac97_dai[0], | 32 | .cpu_dai = &s3c_ac97_dai[S3C_AC97_DAI_PCM], |
33 | .codec_dai = &ac97_dai, | 33 | .codec_dai = &ac97_dai, |
34 | }, | 34 | }, |
35 | }; | 35 | }; |
diff --git a/sound/soc/s3c24xx/smdk_wm9713.c b/sound/soc/s3c24xx/smdk_wm9713.c new file mode 100644 index 000000000000..24fd39f38ccb --- /dev/null +++ b/sound/soc/s3c24xx/smdk_wm9713.c | |||
@@ -0,0 +1,94 @@ | |||
1 | /* | ||
2 | * smdk_wm9713.c -- SoC audio for SMDK | ||
3 | * | ||
4 | * Copyright 2010 Samsung Electronics Co. Ltd. | ||
5 | * Author: Jaswinder Singh Brar <jassi.brar@samsung.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License as | ||
9 | * published by the Free Software Foundation; either version 2 of the | ||
10 | * License, or (at your option) any later version. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/device.h> | ||
16 | #include <sound/soc.h> | ||
17 | |||
18 | #include "../codecs/wm9713.h" | ||
19 | #include "s3c-dma.h" | ||
20 | #include "s3c-ac97.h" | ||
21 | |||
22 | static struct snd_soc_card smdk; | ||
23 | |||
24 | /* | ||
25 | * Default CFG switch settings to use this driver: | ||
26 | * | ||
27 | * SMDK6410: Set CFG1 1-3 On, CFG2 1-4 Off | ||
28 | */ | ||
29 | |||
30 | /* | ||
31 | Playback (HeadPhone):- | ||
32 | $ amixer sset 'Headphone' unmute | ||
33 | $ amixer sset 'Right Headphone Out Mux' 'Headphone' | ||
34 | $ amixer sset 'Left Headphone Out Mux' 'Headphone' | ||
35 | $ amixer sset 'Right HP Mixer PCM' unmute | ||
36 | $ amixer sset 'Left HP Mixer PCM' unmute | ||
37 | |||
38 | Capture (LineIn):- | ||
39 | $ amixer sset 'Right Capture Source' 'Line' | ||
40 | $ amixer sset 'Left Capture Source' 'Line' | ||
41 | */ | ||
42 | |||
43 | static struct snd_soc_dai_link smdk_dai = { | ||
44 | .name = "AC97", | ||
45 | .stream_name = "AC97 PCM", | ||
46 | .cpu_dai = &s3c_ac97_dai[S3C_AC97_DAI_PCM], | ||
47 | .codec_dai = &wm9713_dai[WM9713_DAI_AC97_HIFI], | ||
48 | }; | ||
49 | |||
50 | static struct snd_soc_card smdk = { | ||
51 | .name = "SMDK", | ||
52 | .platform = &s3c24xx_soc_platform, | ||
53 | .dai_link = &smdk_dai, | ||
54 | .num_links = 1, | ||
55 | }; | ||
56 | |||
57 | static struct snd_soc_device smdk_snd_ac97_devdata = { | ||
58 | .card = &smdk, | ||
59 | .codec_dev = &soc_codec_dev_wm9713, | ||
60 | }; | ||
61 | |||
62 | static struct platform_device *smdk_snd_ac97_device; | ||
63 | |||
64 | static int __init smdk_init(void) | ||
65 | { | ||
66 | int ret; | ||
67 | |||
68 | smdk_snd_ac97_device = platform_device_alloc("soc-audio", -1); | ||
69 | if (!smdk_snd_ac97_device) | ||
70 | return -ENOMEM; | ||
71 | |||
72 | platform_set_drvdata(smdk_snd_ac97_device, | ||
73 | &smdk_snd_ac97_devdata); | ||
74 | smdk_snd_ac97_devdata.dev = &smdk_snd_ac97_device->dev; | ||
75 | |||
76 | ret = platform_device_add(smdk_snd_ac97_device); | ||
77 | if (ret) | ||
78 | platform_device_put(smdk_snd_ac97_device); | ||
79 | |||
80 | return ret; | ||
81 | } | ||
82 | |||
83 | static void __exit smdk_exit(void) | ||
84 | { | ||
85 | platform_device_unregister(smdk_snd_ac97_device); | ||
86 | } | ||
87 | |||
88 | module_init(smdk_init); | ||
89 | module_exit(smdk_exit); | ||
90 | |||
91 | /* Module information */ | ||
92 | MODULE_AUTHOR("Jaswinder Singh Brar, jassi.brar@samsung.com"); | ||
93 | MODULE_DESCRIPTION("ALSA SoC SMDK+WM9713"); | ||
94 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig index 9e6976586554..106674979b53 100644 --- a/sound/soc/sh/Kconfig +++ b/sound/soc/sh/Kconfig | |||
@@ -26,6 +26,13 @@ config SND_SOC_SH4_FSI | |||
26 | help | 26 | help |
27 | This option enables FSI sound support | 27 | This option enables FSI sound support |
28 | 28 | ||
29 | config SND_SOC_SH4_SIU | ||
30 | tristate | ||
31 | depends on (SUPERH || ARCH_SHMOBILE) && HAVE_CLK | ||
32 | select DMA_ENGINE | ||
33 | select DMADEVICES | ||
34 | select SH_DMAE | ||
35 | |||
29 | ## | 36 | ## |
30 | ## Boards | 37 | ## Boards |
31 | ## | 38 | ## |
@@ -47,4 +54,20 @@ config SND_FSI_AK4642 | |||
47 | This option enables generic sound support for the | 54 | This option enables generic sound support for the |
48 | FSI - AK4642 unit | 55 | FSI - AK4642 unit |
49 | 56 | ||
57 | config SND_FSI_DA7210 | ||
58 | bool "FSI-DA7210 sound support" | ||
59 | depends on SND_SOC_SH4_FSI | ||
60 | select SND_SOC_DA7210 | ||
61 | help | ||
62 | This option enables generic sound support for the | ||
63 | FSI - DA7210 unit | ||
64 | |||
65 | config SND_SIU_MIGOR | ||
66 | tristate "SIU sound support on Migo-R" | ||
67 | depends on SH_MIGOR | ||
68 | select SND_SOC_SH4_SIU | ||
69 | select SND_SOC_WM8978 | ||
70 | help | ||
71 | This option enables sound support for the SH7722 Migo-R board | ||
72 | |||
50 | endmenu | 73 | endmenu |
diff --git a/sound/soc/sh/Makefile b/sound/soc/sh/Makefile index a6997872f24e..8a5a19293bda 100644 --- a/sound/soc/sh/Makefile +++ b/sound/soc/sh/Makefile | |||
@@ -6,13 +6,19 @@ obj-$(CONFIG_SND_SOC_PCM_SH7760) += snd-soc-dma-sh7760.o | |||
6 | snd-soc-hac-objs := hac.o | 6 | snd-soc-hac-objs := hac.o |
7 | snd-soc-ssi-objs := ssi.o | 7 | snd-soc-ssi-objs := ssi.o |
8 | snd-soc-fsi-objs := fsi.o | 8 | snd-soc-fsi-objs := fsi.o |
9 | snd-soc-siu-objs := siu_pcm.o siu_dai.o | ||
9 | obj-$(CONFIG_SND_SOC_SH4_HAC) += snd-soc-hac.o | 10 | obj-$(CONFIG_SND_SOC_SH4_HAC) += snd-soc-hac.o |
10 | obj-$(CONFIG_SND_SOC_SH4_SSI) += snd-soc-ssi.o | 11 | obj-$(CONFIG_SND_SOC_SH4_SSI) += snd-soc-ssi.o |
11 | obj-$(CONFIG_SND_SOC_SH4_FSI) += snd-soc-fsi.o | 12 | obj-$(CONFIG_SND_SOC_SH4_FSI) += snd-soc-fsi.o |
13 | obj-$(CONFIG_SND_SOC_SH4_SIU) += snd-soc-siu.o | ||
12 | 14 | ||
13 | ## boards | 15 | ## boards |
14 | snd-soc-sh7760-ac97-objs := sh7760-ac97.o | 16 | snd-soc-sh7760-ac97-objs := sh7760-ac97.o |
15 | snd-soc-fsi-ak4642-objs := fsi-ak4642.o | 17 | snd-soc-fsi-ak4642-objs := fsi-ak4642.o |
18 | snd-soc-fsi-da7210-objs := fsi-da7210.o | ||
19 | snd-soc-migor-objs := migor.o | ||
16 | 20 | ||
17 | obj-$(CONFIG_SND_SH7760_AC97) += snd-soc-sh7760-ac97.o | 21 | obj-$(CONFIG_SND_SH7760_AC97) += snd-soc-sh7760-ac97.o |
18 | obj-$(CONFIG_SND_FSI_AK4642) += snd-soc-fsi-ak4642.o | 22 | obj-$(CONFIG_SND_FSI_AK4642) += snd-soc-fsi-ak4642.o |
23 | obj-$(CONFIG_SND_FSI_DA7210) += snd-soc-fsi-da7210.o | ||
24 | obj-$(CONFIG_SND_SIU_MIGOR) += snd-soc-migor.o | ||
diff --git a/sound/soc/sh/fsi-da7210.c b/sound/soc/sh/fsi-da7210.c new file mode 100644 index 000000000000..33b4d177f466 --- /dev/null +++ b/sound/soc/sh/fsi-da7210.c | |||
@@ -0,0 +1,83 @@ | |||
1 | /* | ||
2 | * fsi-da7210.c | ||
3 | * | ||
4 | * Copyright (C) 2009 Renesas Solutions Corp. | ||
5 | * Kuninori Morimoto <morimoto.kuninori@renesas.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | */ | ||
12 | |||
13 | #include <linux/interrupt.h> | ||
14 | #include <linux/platform_device.h> | ||
15 | #include <linux/io.h> | ||
16 | #include <linux/i2c.h> | ||
17 | #include <sound/core.h> | ||
18 | #include <sound/pcm.h> | ||
19 | #include <sound/pcm_params.h> | ||
20 | #include <sound/soc.h> | ||
21 | #include <sound/soc-dapm.h> | ||
22 | |||
23 | #include <sound/sh_fsi.h> | ||
24 | #include "../codecs/da7210.h" | ||
25 | |||
26 | static int fsi_da7210_init(struct snd_soc_codec *codec) | ||
27 | { | ||
28 | return snd_soc_dai_set_fmt(&da7210_dai, | ||
29 | SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | | ||
30 | SND_SOC_DAIFMT_CBM_CFM); | ||
31 | } | ||
32 | |||
33 | static struct snd_soc_dai_link fsi_da7210_dai = { | ||
34 | .name = "DA7210", | ||
35 | .stream_name = "DA7210", | ||
36 | .cpu_dai = &fsi_soc_dai[1], /* FSI B */ | ||
37 | .codec_dai = &da7210_dai, | ||
38 | .init = fsi_da7210_init, | ||
39 | }; | ||
40 | |||
41 | static struct snd_soc_card fsi_soc_card = { | ||
42 | .name = "FSI", | ||
43 | .platform = &fsi_soc_platform, | ||
44 | .dai_link = &fsi_da7210_dai, | ||
45 | .num_links = 1, | ||
46 | }; | ||
47 | |||
48 | static struct snd_soc_device fsi_da7210_snd_devdata = { | ||
49 | .card = &fsi_soc_card, | ||
50 | .codec_dev = &soc_codec_dev_da7210, | ||
51 | }; | ||
52 | |||
53 | static struct platform_device *fsi_da7210_snd_device; | ||
54 | |||
55 | static int __init fsi_da7210_sound_init(void) | ||
56 | { | ||
57 | int ret; | ||
58 | |||
59 | fsi_da7210_snd_device = platform_device_alloc("soc-audio", -1); | ||
60 | if (!fsi_da7210_snd_device) | ||
61 | return -ENOMEM; | ||
62 | |||
63 | platform_set_drvdata(fsi_da7210_snd_device, &fsi_da7210_snd_devdata); | ||
64 | fsi_da7210_snd_devdata.dev = &fsi_da7210_snd_device->dev; | ||
65 | ret = platform_device_add(fsi_da7210_snd_device); | ||
66 | if (ret) | ||
67 | platform_device_put(fsi_da7210_snd_device); | ||
68 | |||
69 | return ret; | ||
70 | } | ||
71 | |||
72 | static void __exit fsi_da7210_sound_exit(void) | ||
73 | { | ||
74 | platform_device_unregister(fsi_da7210_snd_device); | ||
75 | } | ||
76 | |||
77 | module_init(fsi_da7210_sound_init); | ||
78 | module_exit(fsi_da7210_sound_exit); | ||
79 | |||
80 | /* Module information */ | ||
81 | MODULE_DESCRIPTION("ALSA SoC FSI DA2710"); | ||
82 | MODULE_AUTHOR("Kuninori Morimoto <morimoto.kuninori@renesas.com>"); | ||
83 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 42813b808389..993abb730dfa 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c | |||
@@ -67,6 +67,7 @@ | |||
67 | /* DOFF_ST */ | 67 | /* DOFF_ST */ |
68 | #define ERR_OVER 0x00000010 | 68 | #define ERR_OVER 0x00000010 |
69 | #define ERR_UNDER 0x00000001 | 69 | #define ERR_UNDER 0x00000001 |
70 | #define ST_ERR (ERR_OVER | ERR_UNDER) | ||
70 | 71 | ||
71 | /* CLK_RST */ | 72 | /* CLK_RST */ |
72 | #define B_CLK 0x00000010 | 73 | #define B_CLK 0x00000010 |
@@ -92,6 +93,7 @@ | |||
92 | struct fsi_priv { | 93 | struct fsi_priv { |
93 | void __iomem *base; | 94 | void __iomem *base; |
94 | struct snd_pcm_substream *substream; | 95 | struct snd_pcm_substream *substream; |
96 | struct fsi_master *master; | ||
95 | 97 | ||
96 | int fifo_max; | 98 | int fifo_max; |
97 | int chan; | 99 | int chan; |
@@ -108,10 +110,9 @@ struct fsi_master { | |||
108 | struct fsi_priv fsia; | 110 | struct fsi_priv fsia; |
109 | struct fsi_priv fsib; | 111 | struct fsi_priv fsib; |
110 | struct sh_fsi_platform_info *info; | 112 | struct sh_fsi_platform_info *info; |
113 | spinlock_t lock; | ||
111 | }; | 114 | }; |
112 | 115 | ||
113 | static struct fsi_master *master; | ||
114 | |||
115 | /************************************************************************ | 116 | /************************************************************************ |
116 | 117 | ||
117 | 118 | ||
@@ -119,35 +120,35 @@ static struct fsi_master *master; | |||
119 | 120 | ||
120 | 121 | ||
121 | ************************************************************************/ | 122 | ************************************************************************/ |
122 | static int __fsi_reg_write(u32 reg, u32 data) | 123 | static void __fsi_reg_write(u32 reg, u32 data) |
123 | { | 124 | { |
124 | /* valid data area is 24bit */ | 125 | /* valid data area is 24bit */ |
125 | data &= 0x00ffffff; | 126 | data &= 0x00ffffff; |
126 | 127 | ||
127 | return ctrl_outl(data, reg); | 128 | __raw_writel(data, reg); |
128 | } | 129 | } |
129 | 130 | ||
130 | static u32 __fsi_reg_read(u32 reg) | 131 | static u32 __fsi_reg_read(u32 reg) |
131 | { | 132 | { |
132 | return ctrl_inl(reg); | 133 | return __raw_readl(reg); |
133 | } | 134 | } |
134 | 135 | ||
135 | static int __fsi_reg_mask_set(u32 reg, u32 mask, u32 data) | 136 | static void __fsi_reg_mask_set(u32 reg, u32 mask, u32 data) |
136 | { | 137 | { |
137 | u32 val = __fsi_reg_read(reg); | 138 | u32 val = __fsi_reg_read(reg); |
138 | 139 | ||
139 | val &= ~mask; | 140 | val &= ~mask; |
140 | val |= data & mask; | 141 | val |= data & mask; |
141 | 142 | ||
142 | return __fsi_reg_write(reg, val); | 143 | __fsi_reg_write(reg, val); |
143 | } | 144 | } |
144 | 145 | ||
145 | static int fsi_reg_write(struct fsi_priv *fsi, u32 reg, u32 data) | 146 | static void fsi_reg_write(struct fsi_priv *fsi, u32 reg, u32 data) |
146 | { | 147 | { |
147 | if (reg > REG_END) | 148 | if (reg > REG_END) |
148 | return -1; | 149 | return; |
149 | 150 | ||
150 | return __fsi_reg_write((u32)(fsi->base + reg), data); | 151 | __fsi_reg_write((u32)(fsi->base + reg), data); |
151 | } | 152 | } |
152 | 153 | ||
153 | static u32 fsi_reg_read(struct fsi_priv *fsi, u32 reg) | 154 | static u32 fsi_reg_read(struct fsi_priv *fsi, u32 reg) |
@@ -158,39 +159,55 @@ static u32 fsi_reg_read(struct fsi_priv *fsi, u32 reg) | |||
158 | return __fsi_reg_read((u32)(fsi->base + reg)); | 159 | return __fsi_reg_read((u32)(fsi->base + reg)); |
159 | } | 160 | } |
160 | 161 | ||
161 | static int fsi_reg_mask_set(struct fsi_priv *fsi, u32 reg, u32 mask, u32 data) | 162 | static void fsi_reg_mask_set(struct fsi_priv *fsi, u32 reg, u32 mask, u32 data) |
162 | { | 163 | { |
163 | if (reg > REG_END) | 164 | if (reg > REG_END) |
164 | return -1; | 165 | return; |
165 | 166 | ||
166 | return __fsi_reg_mask_set((u32)(fsi->base + reg), mask, data); | 167 | __fsi_reg_mask_set((u32)(fsi->base + reg), mask, data); |
167 | } | 168 | } |
168 | 169 | ||
169 | static int fsi_master_write(u32 reg, u32 data) | 170 | static void fsi_master_write(struct fsi_master *master, u32 reg, u32 data) |
170 | { | 171 | { |
172 | unsigned long flags; | ||
173 | |||
171 | if ((reg < MREG_START) || | 174 | if ((reg < MREG_START) || |
172 | (reg > MREG_END)) | 175 | (reg > MREG_END)) |
173 | return -1; | 176 | return; |
174 | 177 | ||
175 | return __fsi_reg_write((u32)(master->base + reg), data); | 178 | spin_lock_irqsave(&master->lock, flags); |
179 | __fsi_reg_write((u32)(master->base + reg), data); | ||
180 | spin_unlock_irqrestore(&master->lock, flags); | ||
176 | } | 181 | } |
177 | 182 | ||
178 | static u32 fsi_master_read(u32 reg) | 183 | static u32 fsi_master_read(struct fsi_master *master, u32 reg) |
179 | { | 184 | { |
185 | u32 ret; | ||
186 | unsigned long flags; | ||
187 | |||
180 | if ((reg < MREG_START) || | 188 | if ((reg < MREG_START) || |
181 | (reg > MREG_END)) | 189 | (reg > MREG_END)) |
182 | return 0; | 190 | return 0; |
183 | 191 | ||
184 | return __fsi_reg_read((u32)(master->base + reg)); | 192 | spin_lock_irqsave(&master->lock, flags); |
193 | ret = __fsi_reg_read((u32)(master->base + reg)); | ||
194 | spin_unlock_irqrestore(&master->lock, flags); | ||
195 | |||
196 | return ret; | ||
185 | } | 197 | } |
186 | 198 | ||
187 | static int fsi_master_mask_set(u32 reg, u32 mask, u32 data) | 199 | static void fsi_master_mask_set(struct fsi_master *master, |
200 | u32 reg, u32 mask, u32 data) | ||
188 | { | 201 | { |
202 | unsigned long flags; | ||
203 | |||
189 | if ((reg < MREG_START) || | 204 | if ((reg < MREG_START) || |
190 | (reg > MREG_END)) | 205 | (reg > MREG_END)) |
191 | return -1; | 206 | return; |
192 | 207 | ||
193 | return __fsi_reg_mask_set((u32)(master->base + reg), mask, data); | 208 | spin_lock_irqsave(&master->lock, flags); |
209 | __fsi_reg_mask_set((u32)(master->base + reg), mask, data); | ||
210 | spin_unlock_irqrestore(&master->lock, flags); | ||
194 | } | 211 | } |
195 | 212 | ||
196 | /************************************************************************ | 213 | /************************************************************************ |
@@ -200,43 +217,35 @@ static int fsi_master_mask_set(u32 reg, u32 mask, u32 data) | |||
200 | 217 | ||
201 | 218 | ||
202 | ************************************************************************/ | 219 | ************************************************************************/ |
203 | static struct fsi_priv *fsi_get(struct snd_pcm_substream *substream) | 220 | static struct fsi_master *fsi_get_master(struct fsi_priv *fsi) |
204 | { | 221 | { |
205 | struct snd_soc_pcm_runtime *rtd; | 222 | return fsi->master; |
206 | struct fsi_priv *fsi = NULL; | 223 | } |
207 | 224 | ||
208 | if (!substream || !master) | 225 | static int fsi_is_port_a(struct fsi_priv *fsi) |
209 | return NULL; | 226 | { |
227 | return fsi->master->base == fsi->base; | ||
228 | } | ||
210 | 229 | ||
211 | rtd = substream->private_data; | 230 | static struct snd_soc_dai *fsi_get_dai(struct snd_pcm_substream *substream) |
212 | switch (rtd->dai->cpu_dai->id) { | 231 | { |
213 | case 0: | 232 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
214 | fsi = &master->fsia; | 233 | struct snd_soc_dai_link *machine = rtd->dai; |
215 | break; | ||
216 | case 1: | ||
217 | fsi = &master->fsib; | ||
218 | break; | ||
219 | } | ||
220 | 234 | ||
221 | return fsi; | 235 | return machine->cpu_dai; |
222 | } | 236 | } |
223 | 237 | ||
224 | static int fsi_is_port_a(struct fsi_priv *fsi) | 238 | static struct fsi_priv *fsi_get_priv(struct snd_pcm_substream *substream) |
225 | { | 239 | { |
226 | /* return | 240 | struct snd_soc_dai *dai = fsi_get_dai(substream); |
227 | * 1 : port a | ||
228 | * 0 : port b | ||
229 | */ | ||
230 | 241 | ||
231 | if (fsi == &master->fsia) | 242 | return dai->private_data; |
232 | return 1; | ||
233 | |||
234 | return 0; | ||
235 | } | 243 | } |
236 | 244 | ||
237 | static u32 fsi_get_info_flags(struct fsi_priv *fsi) | 245 | static u32 fsi_get_info_flags(struct fsi_priv *fsi) |
238 | { | 246 | { |
239 | int is_porta = fsi_is_port_a(fsi); | 247 | int is_porta = fsi_is_port_a(fsi); |
248 | struct fsi_master *master = fsi_get_master(fsi); | ||
240 | 249 | ||
241 | return is_porta ? master->info->porta_flags : | 250 | return is_porta ? master->info->porta_flags : |
242 | master->info->portb_flags; | 251 | master->info->portb_flags; |
@@ -314,27 +323,30 @@ static int fsi_get_fifo_residue(struct fsi_priv *fsi, int is_play) | |||
314 | static void fsi_irq_enable(struct fsi_priv *fsi, int is_play) | 323 | static void fsi_irq_enable(struct fsi_priv *fsi, int is_play) |
315 | { | 324 | { |
316 | u32 data = fsi_port_ab_io_bit(fsi, is_play); | 325 | u32 data = fsi_port_ab_io_bit(fsi, is_play); |
326 | struct fsi_master *master = fsi_get_master(fsi); | ||
317 | 327 | ||
318 | fsi_master_mask_set(IMSK, data, data); | 328 | fsi_master_mask_set(master, IMSK, data, data); |
319 | fsi_master_mask_set(IEMSK, data, data); | 329 | fsi_master_mask_set(master, IEMSK, data, data); |
320 | } | 330 | } |
321 | 331 | ||
322 | static void fsi_irq_disable(struct fsi_priv *fsi, int is_play) | 332 | static void fsi_irq_disable(struct fsi_priv *fsi, int is_play) |
323 | { | 333 | { |
324 | u32 data = fsi_port_ab_io_bit(fsi, is_play); | 334 | u32 data = fsi_port_ab_io_bit(fsi, is_play); |
335 | struct fsi_master *master = fsi_get_master(fsi); | ||
325 | 336 | ||
326 | fsi_master_mask_set(IMSK, data, 0); | 337 | fsi_master_mask_set(master, IMSK, data, 0); |
327 | fsi_master_mask_set(IEMSK, data, 0); | 338 | fsi_master_mask_set(master, IEMSK, data, 0); |
328 | } | 339 | } |
329 | 340 | ||
330 | static void fsi_clk_ctrl(struct fsi_priv *fsi, int enable) | 341 | static void fsi_clk_ctrl(struct fsi_priv *fsi, int enable) |
331 | { | 342 | { |
332 | u32 val = fsi_is_port_a(fsi) ? (1 << 0) : (1 << 4); | 343 | u32 val = fsi_is_port_a(fsi) ? (1 << 0) : (1 << 4); |
344 | struct fsi_master *master = fsi_get_master(fsi); | ||
333 | 345 | ||
334 | if (enable) | 346 | if (enable) |
335 | fsi_master_mask_set(CLK_RST, val, val); | 347 | fsi_master_mask_set(master, CLK_RST, val, val); |
336 | else | 348 | else |
337 | fsi_master_mask_set(CLK_RST, val, 0); | 349 | fsi_master_mask_set(master, CLK_RST, val, 0); |
338 | } | 350 | } |
339 | 351 | ||
340 | static void fsi_irq_init(struct fsi_priv *fsi, int is_play) | 352 | static void fsi_irq_init(struct fsi_priv *fsi, int is_play) |
@@ -355,43 +367,46 @@ static void fsi_irq_init(struct fsi_priv *fsi, int is_play) | |||
355 | fsi_reg_mask_set(fsi, ctrl, FIFO_CLR, FIFO_CLR); | 367 | fsi_reg_mask_set(fsi, ctrl, FIFO_CLR, FIFO_CLR); |
356 | 368 | ||
357 | /* clear interrupt factor */ | 369 | /* clear interrupt factor */ |
358 | fsi_master_mask_set(INT_ST, data, 0); | 370 | fsi_master_mask_set(fsi_get_master(fsi), INT_ST, data, 0); |
359 | } | 371 | } |
360 | 372 | ||
361 | static void fsi_soft_all_reset(void) | 373 | static void fsi_soft_all_reset(struct fsi_master *master) |
362 | { | 374 | { |
363 | u32 status = fsi_master_read(SOFT_RST); | 375 | u32 status = fsi_master_read(master, SOFT_RST); |
364 | 376 | ||
365 | /* port AB reset */ | 377 | /* port AB reset */ |
366 | status &= 0x000000ff; | 378 | status &= 0x000000ff; |
367 | fsi_master_write(SOFT_RST, status); | 379 | fsi_master_write(master, SOFT_RST, status); |
368 | mdelay(10); | 380 | mdelay(10); |
369 | 381 | ||
370 | /* soft reset */ | 382 | /* soft reset */ |
371 | status &= 0x000000f0; | 383 | status &= 0x000000f0; |
372 | fsi_master_write(SOFT_RST, status); | 384 | fsi_master_write(master, SOFT_RST, status); |
373 | status |= 0x00000001; | 385 | status |= 0x00000001; |
374 | fsi_master_write(SOFT_RST, status); | 386 | fsi_master_write(master, SOFT_RST, status); |
375 | mdelay(10); | 387 | mdelay(10); |
376 | } | 388 | } |
377 | 389 | ||
378 | /* playback interrupt */ | 390 | /* playback interrupt */ |
379 | static int fsi_data_push(struct fsi_priv *fsi) | 391 | static int fsi_data_push(struct fsi_priv *fsi, int startup) |
380 | { | 392 | { |
381 | struct snd_pcm_runtime *runtime; | 393 | struct snd_pcm_runtime *runtime; |
382 | struct snd_pcm_substream *substream = NULL; | 394 | struct snd_pcm_substream *substream = NULL; |
395 | u32 status; | ||
383 | int send; | 396 | int send; |
384 | int fifo_free; | 397 | int fifo_free; |
385 | int width; | 398 | int width; |
386 | u8 *start; | 399 | u8 *start; |
387 | int i; | 400 | int i, over_period; |
388 | 401 | ||
389 | if (!fsi || | 402 | if (!fsi || |
390 | !fsi->substream || | 403 | !fsi->substream || |
391 | !fsi->substream->runtime) | 404 | !fsi->substream->runtime) |
392 | return -EINVAL; | 405 | return -EINVAL; |
393 | 406 | ||
394 | runtime = fsi->substream->runtime; | 407 | over_period = 0; |
408 | substream = fsi->substream; | ||
409 | runtime = substream->runtime; | ||
395 | 410 | ||
396 | /* FSI FIFO has limit. | 411 | /* FSI FIFO has limit. |
397 | * So, this driver can not send periods data at a time | 412 | * So, this driver can not send periods data at a time |
@@ -399,7 +414,7 @@ static int fsi_data_push(struct fsi_priv *fsi) | |||
399 | if (fsi->byte_offset >= | 414 | if (fsi->byte_offset >= |
400 | fsi->period_len * (fsi->periods + 1)) { | 415 | fsi->period_len * (fsi->periods + 1)) { |
401 | 416 | ||
402 | substream = fsi->substream; | 417 | over_period = 1; |
403 | fsi->periods = (fsi->periods + 1) % runtime->periods; | 418 | fsi->periods = (fsi->periods + 1) % runtime->periods; |
404 | 419 | ||
405 | if (0 == fsi->periods) | 420 | if (0 == fsi->periods) |
@@ -438,30 +453,44 @@ static int fsi_data_push(struct fsi_priv *fsi) | |||
438 | 453 | ||
439 | fsi->byte_offset += send * width; | 454 | fsi->byte_offset += send * width; |
440 | 455 | ||
456 | status = fsi_reg_read(fsi, DOFF_ST); | ||
457 | if (!startup) { | ||
458 | struct snd_soc_dai *dai = fsi_get_dai(substream); | ||
459 | |||
460 | if (status & ERR_OVER) | ||
461 | dev_err(dai->dev, "over run\n"); | ||
462 | if (status & ERR_UNDER) | ||
463 | dev_err(dai->dev, "under run\n"); | ||
464 | } | ||
465 | fsi_reg_write(fsi, DOFF_ST, 0); | ||
466 | |||
441 | fsi_irq_enable(fsi, 1); | 467 | fsi_irq_enable(fsi, 1); |
442 | 468 | ||
443 | if (substream) | 469 | if (over_period) |
444 | snd_pcm_period_elapsed(substream); | 470 | snd_pcm_period_elapsed(substream); |
445 | 471 | ||
446 | return 0; | 472 | return 0; |
447 | } | 473 | } |
448 | 474 | ||
449 | static int fsi_data_pop(struct fsi_priv *fsi) | 475 | static int fsi_data_pop(struct fsi_priv *fsi, int startup) |
450 | { | 476 | { |
451 | struct snd_pcm_runtime *runtime; | 477 | struct snd_pcm_runtime *runtime; |
452 | struct snd_pcm_substream *substream = NULL; | 478 | struct snd_pcm_substream *substream = NULL; |
479 | u32 status; | ||
453 | int free; | 480 | int free; |
454 | int fifo_fill; | 481 | int fifo_fill; |
455 | int width; | 482 | int width; |
456 | u8 *start; | 483 | u8 *start; |
457 | int i; | 484 | int i, over_period; |
458 | 485 | ||
459 | if (!fsi || | 486 | if (!fsi || |
460 | !fsi->substream || | 487 | !fsi->substream || |
461 | !fsi->substream->runtime) | 488 | !fsi->substream->runtime) |
462 | return -EINVAL; | 489 | return -EINVAL; |
463 | 490 | ||
464 | runtime = fsi->substream->runtime; | 491 | over_period = 0; |
492 | substream = fsi->substream; | ||
493 | runtime = substream->runtime; | ||
465 | 494 | ||
466 | /* FSI FIFO has limit. | 495 | /* FSI FIFO has limit. |
467 | * So, this driver can not send periods data at a time | 496 | * So, this driver can not send periods data at a time |
@@ -469,7 +498,7 @@ static int fsi_data_pop(struct fsi_priv *fsi) | |||
469 | if (fsi->byte_offset >= | 498 | if (fsi->byte_offset >= |
470 | fsi->period_len * (fsi->periods + 1)) { | 499 | fsi->period_len * (fsi->periods + 1)) { |
471 | 500 | ||
472 | substream = fsi->substream; | 501 | over_period = 1; |
473 | fsi->periods = (fsi->periods + 1) % runtime->periods; | 502 | fsi->periods = (fsi->periods + 1) % runtime->periods; |
474 | 503 | ||
475 | if (0 == fsi->periods) | 504 | if (0 == fsi->periods) |
@@ -507,9 +536,20 @@ static int fsi_data_pop(struct fsi_priv *fsi) | |||
507 | 536 | ||
508 | fsi->byte_offset += fifo_fill * width; | 537 | fsi->byte_offset += fifo_fill * width; |
509 | 538 | ||
539 | status = fsi_reg_read(fsi, DIFF_ST); | ||
540 | if (!startup) { | ||
541 | struct snd_soc_dai *dai = fsi_get_dai(substream); | ||
542 | |||
543 | if (status & ERR_OVER) | ||
544 | dev_err(dai->dev, "over run\n"); | ||
545 | if (status & ERR_UNDER) | ||
546 | dev_err(dai->dev, "under run\n"); | ||
547 | } | ||
548 | fsi_reg_write(fsi, DIFF_ST, 0); | ||
549 | |||
510 | fsi_irq_enable(fsi, 0); | 550 | fsi_irq_enable(fsi, 0); |
511 | 551 | ||
512 | if (substream) | 552 | if (over_period) |
513 | snd_pcm_period_elapsed(substream); | 553 | snd_pcm_period_elapsed(substream); |
514 | 554 | ||
515 | return 0; | 555 | return 0; |
@@ -517,23 +557,24 @@ static int fsi_data_pop(struct fsi_priv *fsi) | |||
517 | 557 | ||
518 | static irqreturn_t fsi_interrupt(int irq, void *data) | 558 | static irqreturn_t fsi_interrupt(int irq, void *data) |
519 | { | 559 | { |
520 | u32 status = fsi_master_read(SOFT_RST) & ~0x00000010; | 560 | struct fsi_master *master = data; |
521 | u32 int_st = fsi_master_read(INT_ST); | 561 | u32 status = fsi_master_read(master, SOFT_RST) & ~0x00000010; |
562 | u32 int_st = fsi_master_read(master, INT_ST); | ||
522 | 563 | ||
523 | /* clear irq status */ | 564 | /* clear irq status */ |
524 | fsi_master_write(SOFT_RST, status); | 565 | fsi_master_write(master, SOFT_RST, status); |
525 | fsi_master_write(SOFT_RST, status | 0x00000010); | 566 | fsi_master_write(master, SOFT_RST, status | 0x00000010); |
526 | 567 | ||
527 | if (int_st & INT_A_OUT) | 568 | if (int_st & INT_A_OUT) |
528 | fsi_data_push(&master->fsia); | 569 | fsi_data_push(&master->fsia, 0); |
529 | if (int_st & INT_B_OUT) | 570 | if (int_st & INT_B_OUT) |
530 | fsi_data_push(&master->fsib); | 571 | fsi_data_push(&master->fsib, 0); |
531 | if (int_st & INT_A_IN) | 572 | if (int_st & INT_A_IN) |
532 | fsi_data_pop(&master->fsia); | 573 | fsi_data_pop(&master->fsia, 0); |
533 | if (int_st & INT_B_IN) | 574 | if (int_st & INT_B_IN) |
534 | fsi_data_pop(&master->fsib); | 575 | fsi_data_pop(&master->fsib, 0); |
535 | 576 | ||
536 | fsi_master_write(INT_ST, 0x0000000); | 577 | fsi_master_write(master, INT_ST, 0x0000000); |
537 | 578 | ||
538 | return IRQ_HANDLED; | 579 | return IRQ_HANDLED; |
539 | } | 580 | } |
@@ -548,7 +589,7 @@ static irqreturn_t fsi_interrupt(int irq, void *data) | |||
548 | static int fsi_dai_startup(struct snd_pcm_substream *substream, | 589 | static int fsi_dai_startup(struct snd_pcm_substream *substream, |
549 | struct snd_soc_dai *dai) | 590 | struct snd_soc_dai *dai) |
550 | { | 591 | { |
551 | struct fsi_priv *fsi = fsi_get(substream); | 592 | struct fsi_priv *fsi = fsi_get_priv(substream); |
552 | const char *msg; | 593 | const char *msg; |
553 | u32 flags = fsi_get_info_flags(fsi); | 594 | u32 flags = fsi_get_info_flags(fsi); |
554 | u32 fmt; | 595 | u32 fmt; |
@@ -667,7 +708,7 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream, | |||
667 | static void fsi_dai_shutdown(struct snd_pcm_substream *substream, | 708 | static void fsi_dai_shutdown(struct snd_pcm_substream *substream, |
668 | struct snd_soc_dai *dai) | 709 | struct snd_soc_dai *dai) |
669 | { | 710 | { |
670 | struct fsi_priv *fsi = fsi_get(substream); | 711 | struct fsi_priv *fsi = fsi_get_priv(substream); |
671 | int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; | 712 | int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; |
672 | 713 | ||
673 | fsi_irq_disable(fsi, is_play); | 714 | fsi_irq_disable(fsi, is_play); |
@@ -679,7 +720,7 @@ static void fsi_dai_shutdown(struct snd_pcm_substream *substream, | |||
679 | static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd, | 720 | static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd, |
680 | struct snd_soc_dai *dai) | 721 | struct snd_soc_dai *dai) |
681 | { | 722 | { |
682 | struct fsi_priv *fsi = fsi_get(substream); | 723 | struct fsi_priv *fsi = fsi_get_priv(substream); |
683 | struct snd_pcm_runtime *runtime = substream->runtime; | 724 | struct snd_pcm_runtime *runtime = substream->runtime; |
684 | int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; | 725 | int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; |
685 | int ret = 0; | 726 | int ret = 0; |
@@ -689,7 +730,7 @@ static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd, | |||
689 | fsi_stream_push(fsi, substream, | 730 | fsi_stream_push(fsi, substream, |
690 | frames_to_bytes(runtime, runtime->buffer_size), | 731 | frames_to_bytes(runtime, runtime->buffer_size), |
691 | frames_to_bytes(runtime, runtime->period_size)); | 732 | frames_to_bytes(runtime, runtime->period_size)); |
692 | ret = is_play ? fsi_data_push(fsi) : fsi_data_pop(fsi); | 733 | ret = is_play ? fsi_data_push(fsi, 1) : fsi_data_pop(fsi, 1); |
693 | break; | 734 | break; |
694 | case SNDRV_PCM_TRIGGER_STOP: | 735 | case SNDRV_PCM_TRIGGER_STOP: |
695 | fsi_irq_disable(fsi, is_play); | 736 | fsi_irq_disable(fsi, is_play); |
@@ -760,7 +801,7 @@ static int fsi_hw_free(struct snd_pcm_substream *substream) | |||
760 | static snd_pcm_uframes_t fsi_pointer(struct snd_pcm_substream *substream) | 801 | static snd_pcm_uframes_t fsi_pointer(struct snd_pcm_substream *substream) |
761 | { | 802 | { |
762 | struct snd_pcm_runtime *runtime = substream->runtime; | 803 | struct snd_pcm_runtime *runtime = substream->runtime; |
763 | struct fsi_priv *fsi = fsi_get(substream); | 804 | struct fsi_priv *fsi = fsi_get_priv(substream); |
764 | long location; | 805 | long location; |
765 | 806 | ||
766 | location = (fsi->byte_offset - 1); | 807 | location = (fsi->byte_offset - 1); |
@@ -870,10 +911,16 @@ EXPORT_SYMBOL_GPL(fsi_soc_platform); | |||
870 | ************************************************************************/ | 911 | ************************************************************************/ |
871 | static int fsi_probe(struct platform_device *pdev) | 912 | static int fsi_probe(struct platform_device *pdev) |
872 | { | 913 | { |
914 | struct fsi_master *master; | ||
873 | struct resource *res; | 915 | struct resource *res; |
874 | unsigned int irq; | 916 | unsigned int irq; |
875 | int ret; | 917 | int ret; |
876 | 918 | ||
919 | if (0 != pdev->id) { | ||
920 | dev_err(&pdev->dev, "current fsi support id 0 only now\n"); | ||
921 | return -ENODEV; | ||
922 | } | ||
923 | |||
877 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 924 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
878 | irq = platform_get_irq(pdev, 0); | 925 | irq = platform_get_irq(pdev, 0); |
879 | if (!res || (int)irq <= 0) { | 926 | if (!res || (int)irq <= 0) { |
@@ -899,15 +946,20 @@ static int fsi_probe(struct platform_device *pdev) | |||
899 | master->irq = irq; | 946 | master->irq = irq; |
900 | master->info = pdev->dev.platform_data; | 947 | master->info = pdev->dev.platform_data; |
901 | master->fsia.base = master->base; | 948 | master->fsia.base = master->base; |
949 | master->fsia.master = master; | ||
902 | master->fsib.base = master->base + 0x40; | 950 | master->fsib.base = master->base + 0x40; |
951 | master->fsib.master = master; | ||
952 | spin_lock_init(&master->lock); | ||
903 | 953 | ||
904 | pm_runtime_enable(&pdev->dev); | 954 | pm_runtime_enable(&pdev->dev); |
905 | pm_runtime_resume(&pdev->dev); | 955 | pm_runtime_resume(&pdev->dev); |
906 | 956 | ||
907 | fsi_soc_dai[0].dev = &pdev->dev; | 957 | fsi_soc_dai[0].dev = &pdev->dev; |
958 | fsi_soc_dai[0].private_data = &master->fsia; | ||
908 | fsi_soc_dai[1].dev = &pdev->dev; | 959 | fsi_soc_dai[1].dev = &pdev->dev; |
960 | fsi_soc_dai[1].private_data = &master->fsib; | ||
909 | 961 | ||
910 | fsi_soft_all_reset(); | 962 | fsi_soft_all_reset(master); |
911 | 963 | ||
912 | ret = request_irq(irq, &fsi_interrupt, IRQF_DISABLED, "fsi", master); | 964 | ret = request_irq(irq, &fsi_interrupt, IRQF_DISABLED, "fsi", master); |
913 | if (ret) { | 965 | if (ret) { |
@@ -937,6 +989,10 @@ exit: | |||
937 | 989 | ||
938 | static int fsi_remove(struct platform_device *pdev) | 990 | static int fsi_remove(struct platform_device *pdev) |
939 | { | 991 | { |
992 | struct fsi_master *master; | ||
993 | |||
994 | master = fsi_get_master(fsi_soc_dai[0].private_data); | ||
995 | |||
940 | snd_soc_unregister_dais(fsi_soc_dai, ARRAY_SIZE(fsi_soc_dai)); | 996 | snd_soc_unregister_dais(fsi_soc_dai, ARRAY_SIZE(fsi_soc_dai)); |
941 | snd_soc_unregister_platform(&fsi_soc_platform); | 997 | snd_soc_unregister_platform(&fsi_soc_platform); |
942 | 998 | ||
@@ -946,7 +1002,12 @@ static int fsi_remove(struct platform_device *pdev) | |||
946 | 1002 | ||
947 | iounmap(master->base); | 1003 | iounmap(master->base); |
948 | kfree(master); | 1004 | kfree(master); |
949 | master = NULL; | 1005 | |
1006 | fsi_soc_dai[0].dev = NULL; | ||
1007 | fsi_soc_dai[0].private_data = NULL; | ||
1008 | fsi_soc_dai[1].dev = NULL; | ||
1009 | fsi_soc_dai[1].private_data = NULL; | ||
1010 | |||
950 | return 0; | 1011 | return 0; |
951 | } | 1012 | } |
952 | 1013 | ||
diff --git a/sound/soc/sh/migor.c b/sound/soc/sh/migor.c new file mode 100644 index 000000000000..b823a5c9b9bc --- /dev/null +++ b/sound/soc/sh/migor.c | |||
@@ -0,0 +1,218 @@ | |||
1 | /* | ||
2 | * ALSA SoC driver for Migo-R | ||
3 | * | ||
4 | * Copyright (C) 2009-2010 Guennadi Liakhovetski <g.liakhovetski@gmx.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 version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include <linux/device.h> | ||
12 | #include <linux/firmware.h> | ||
13 | #include <linux/module.h> | ||
14 | |||
15 | #include <asm/clock.h> | ||
16 | |||
17 | #include <cpu/sh7722.h> | ||
18 | |||
19 | #include <sound/core.h> | ||
20 | #include <sound/pcm.h> | ||
21 | #include <sound/soc.h> | ||
22 | #include <sound/soc-dapm.h> | ||
23 | |||
24 | #include "../codecs/wm8978.h" | ||
25 | #include "siu.h" | ||
26 | |||
27 | /* Default 8000Hz sampling frequency */ | ||
28 | static unsigned long codec_freq = 8000 * 512; | ||
29 | |||
30 | static unsigned int use_count; | ||
31 | |||
32 | /* External clock, sourced from the codec at the SIUMCKB pin */ | ||
33 | static unsigned long siumckb_recalc(struct clk *clk) | ||
34 | { | ||
35 | return codec_freq; | ||
36 | } | ||
37 | |||
38 | static struct clk_ops siumckb_clk_ops = { | ||
39 | .recalc = siumckb_recalc, | ||
40 | }; | ||
41 | |||
42 | static struct clk siumckb_clk = { | ||
43 | .name = "siumckb_clk", | ||
44 | .id = -1, | ||
45 | .ops = &siumckb_clk_ops, | ||
46 | .rate = 0, /* initialised at run-time */ | ||
47 | }; | ||
48 | |||
49 | static int migor_hw_params(struct snd_pcm_substream *substream, | ||
50 | struct snd_pcm_hw_params *params) | ||
51 | { | ||
52 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
53 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; | ||
54 | int ret; | ||
55 | unsigned int rate = params_rate(params); | ||
56 | |||
57 | ret = snd_soc_dai_set_sysclk(codec_dai, WM8978_PLL, 13000000, | ||
58 | SND_SOC_CLOCK_IN); | ||
59 | if (ret < 0) | ||
60 | return ret; | ||
61 | |||
62 | ret = snd_soc_dai_set_clkdiv(codec_dai, WM8978_OPCLKRATE, rate * 512); | ||
63 | if (ret < 0) | ||
64 | return ret; | ||
65 | |||
66 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_NB_IF | | ||
67 | SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS); | ||
68 | if (ret < 0) | ||
69 | return ret; | ||
70 | |||
71 | ret = snd_soc_dai_set_fmt(rtd->dai->cpu_dai, SND_SOC_DAIFMT_NB_IF | | ||
72 | SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS); | ||
73 | if (ret < 0) | ||
74 | return ret; | ||
75 | |||
76 | codec_freq = rate * 512; | ||
77 | /* | ||
78 | * This propagates the parent frequency change to children and | ||
79 | * recalculates the frequency table | ||
80 | */ | ||
81 | clk_set_rate(&siumckb_clk, codec_freq); | ||
82 | dev_dbg(codec_dai->dev, "%s: configure %luHz\n", __func__, codec_freq); | ||
83 | |||
84 | ret = snd_soc_dai_set_sysclk(rtd->dai->cpu_dai, SIU_CLKB_EXT, | ||
85 | codec_freq / 2, SND_SOC_CLOCK_IN); | ||
86 | |||
87 | if (!ret) | ||
88 | use_count++; | ||
89 | |||
90 | return ret; | ||
91 | } | ||
92 | |||
93 | static int migor_hw_free(struct snd_pcm_substream *substream) | ||
94 | { | ||
95 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
96 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; | ||
97 | |||
98 | if (use_count) { | ||
99 | use_count--; | ||
100 | |||
101 | if (!use_count) | ||
102 | snd_soc_dai_set_sysclk(codec_dai, WM8978_PLL, 0, | ||
103 | SND_SOC_CLOCK_IN); | ||
104 | } else { | ||
105 | dev_dbg(codec_dai->dev, "Unbalanced hw_free!\n"); | ||
106 | } | ||
107 | |||
108 | return 0; | ||
109 | } | ||
110 | |||
111 | static struct snd_soc_ops migor_dai_ops = { | ||
112 | .hw_params = migor_hw_params, | ||
113 | .hw_free = migor_hw_free, | ||
114 | }; | ||
115 | |||
116 | static const struct snd_soc_dapm_widget migor_dapm_widgets[] = { | ||
117 | SND_SOC_DAPM_HP("Headphone", NULL), | ||
118 | SND_SOC_DAPM_MIC("Onboard Microphone", NULL), | ||
119 | SND_SOC_DAPM_MIC("External Microphone", NULL), | ||
120 | }; | ||
121 | |||
122 | static const struct snd_soc_dapm_route audio_map[] = { | ||
123 | /* Headphone output connected to LHP/RHP, enable OUT4 for VMID */ | ||
124 | { "Headphone", NULL, "OUT4 VMID" }, | ||
125 | { "OUT4 VMID", NULL, "LHP" }, | ||
126 | { "OUT4 VMID", NULL, "RHP" }, | ||
127 | |||
128 | /* On-board microphone */ | ||
129 | { "RMICN", NULL, "Mic Bias" }, | ||
130 | { "RMICP", NULL, "Mic Bias" }, | ||
131 | { "Mic Bias", NULL, "Onboard Microphone" }, | ||
132 | |||
133 | /* External microphone */ | ||
134 | { "LMICN", NULL, "Mic Bias" }, | ||
135 | { "LMICP", NULL, "Mic Bias" }, | ||
136 | { "Mic Bias", NULL, "External Microphone" }, | ||
137 | }; | ||
138 | |||
139 | static int migor_dai_init(struct snd_soc_codec *codec) | ||
140 | { | ||
141 | snd_soc_dapm_new_controls(codec, migor_dapm_widgets, | ||
142 | ARRAY_SIZE(migor_dapm_widgets)); | ||
143 | |||
144 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | ||
145 | |||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | /* migor digital audio interface glue - connects codec <--> CPU */ | ||
150 | static struct snd_soc_dai_link migor_dai = { | ||
151 | .name = "wm8978", | ||
152 | .stream_name = "WM8978", | ||
153 | .cpu_dai = &siu_i2s_dai, | ||
154 | .codec_dai = &wm8978_dai, | ||
155 | .ops = &migor_dai_ops, | ||
156 | .init = migor_dai_init, | ||
157 | }; | ||
158 | |||
159 | /* migor audio machine driver */ | ||
160 | static struct snd_soc_card snd_soc_migor = { | ||
161 | .name = "Migo-R", | ||
162 | .platform = &siu_platform, | ||
163 | .dai_link = &migor_dai, | ||
164 | .num_links = 1, | ||
165 | }; | ||
166 | |||
167 | /* migor audio subsystem */ | ||
168 | static struct snd_soc_device migor_snd_devdata = { | ||
169 | .card = &snd_soc_migor, | ||
170 | .codec_dev = &soc_codec_dev_wm8978, | ||
171 | }; | ||
172 | |||
173 | static struct platform_device *migor_snd_device; | ||
174 | |||
175 | static int __init migor_init(void) | ||
176 | { | ||
177 | int ret; | ||
178 | |||
179 | ret = clk_register(&siumckb_clk); | ||
180 | if (ret < 0) | ||
181 | return ret; | ||
182 | |||
183 | /* Port number used on this machine: port B */ | ||
184 | migor_snd_device = platform_device_alloc("soc-audio", 1); | ||
185 | if (!migor_snd_device) { | ||
186 | ret = -ENOMEM; | ||
187 | goto epdevalloc; | ||
188 | } | ||
189 | |||
190 | platform_set_drvdata(migor_snd_device, &migor_snd_devdata); | ||
191 | |||
192 | migor_snd_devdata.dev = &migor_snd_device->dev; | ||
193 | |||
194 | ret = platform_device_add(migor_snd_device); | ||
195 | if (ret) | ||
196 | goto epdevadd; | ||
197 | |||
198 | return 0; | ||
199 | |||
200 | epdevadd: | ||
201 | platform_device_put(migor_snd_device); | ||
202 | epdevalloc: | ||
203 | clk_unregister(&siumckb_clk); | ||
204 | return ret; | ||
205 | } | ||
206 | |||
207 | static void __exit migor_exit(void) | ||
208 | { | ||
209 | clk_unregister(&siumckb_clk); | ||
210 | platform_device_unregister(migor_snd_device); | ||
211 | } | ||
212 | |||
213 | module_init(migor_init); | ||
214 | module_exit(migor_exit); | ||
215 | |||
216 | MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>"); | ||
217 | MODULE_DESCRIPTION("ALSA SoC Migor"); | ||
218 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/soc/sh/siu.h b/sound/soc/sh/siu.h new file mode 100644 index 000000000000..c0bfab8fed3d --- /dev/null +++ b/sound/soc/sh/siu.h | |||
@@ -0,0 +1,193 @@ | |||
1 | /* | ||
2 | * siu.h - ALSA SoC driver for Renesas SH7343, SH7722 SIU peripheral. | ||
3 | * | ||
4 | * Copyright (C) 2009-2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de> | ||
5 | * Copyright (C) 2006 Carlos Munoz <carlos@kenati.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | ||
21 | |||
22 | #ifndef SIU_H | ||
23 | #define SIU_H | ||
24 | |||
25 | /* Common kernel and user-space firmware-building defines and types */ | ||
26 | |||
27 | #define YRAM0_SIZE (0x0040 / 4) /* 16 */ | ||
28 | #define YRAM1_SIZE (0x0080 / 4) /* 32 */ | ||
29 | #define YRAM2_SIZE (0x0040 / 4) /* 16 */ | ||
30 | #define YRAM3_SIZE (0x0080 / 4) /* 32 */ | ||
31 | #define YRAM4_SIZE (0x0080 / 4) /* 32 */ | ||
32 | #define YRAM_DEF_SIZE (YRAM0_SIZE + YRAM1_SIZE + YRAM2_SIZE + \ | ||
33 | YRAM3_SIZE + YRAM4_SIZE) | ||
34 | #define YRAM_FIR_SIZE (0x0400 / 4) /* 256 */ | ||
35 | #define YRAM_IIR_SIZE (0x0200 / 4) /* 128 */ | ||
36 | |||
37 | #define XRAM0_SIZE (0x0400 / 4) /* 256 */ | ||
38 | #define XRAM1_SIZE (0x0200 / 4) /* 128 */ | ||
39 | #define XRAM2_SIZE (0x0200 / 4) /* 128 */ | ||
40 | |||
41 | /* PRAM program array size */ | ||
42 | #define PRAM0_SIZE (0x0100 / 4) /* 64 */ | ||
43 | #define PRAM1_SIZE ((0x2000 - 0x0100) / 4) /* 1984 */ | ||
44 | |||
45 | #include <linux/types.h> | ||
46 | |||
47 | struct siu_spb_param { | ||
48 | __u32 ab1a; /* input FIFO address */ | ||
49 | __u32 ab0a; /* output FIFO address */ | ||
50 | __u32 dir; /* 0=the ather except CPUOUTPUT, 1=CPUINPUT */ | ||
51 | __u32 event; /* SPB program starting conditions */ | ||
52 | __u32 stfifo; /* STFIFO register setting value */ | ||
53 | __u32 trdat; /* TRDAT register setting value */ | ||
54 | }; | ||
55 | |||
56 | struct siu_firmware { | ||
57 | __u32 yram_fir_coeff[YRAM_FIR_SIZE]; | ||
58 | __u32 pram0[PRAM0_SIZE]; | ||
59 | __u32 pram1[PRAM1_SIZE]; | ||
60 | __u32 yram0[YRAM0_SIZE]; | ||
61 | __u32 yram1[YRAM1_SIZE]; | ||
62 | __u32 yram2[YRAM2_SIZE]; | ||
63 | __u32 yram3[YRAM3_SIZE]; | ||
64 | __u32 yram4[YRAM4_SIZE]; | ||
65 | __u32 spbpar_num; | ||
66 | struct siu_spb_param spbpar[32]; | ||
67 | }; | ||
68 | |||
69 | #ifdef __KERNEL__ | ||
70 | |||
71 | #include <linux/dmaengine.h> | ||
72 | #include <linux/interrupt.h> | ||
73 | #include <linux/io.h> | ||
74 | |||
75 | #include <asm/dmaengine.h> | ||
76 | |||
77 | #include <sound/core.h> | ||
78 | #include <sound/pcm.h> | ||
79 | #include <sound/soc-dai.h> | ||
80 | |||
81 | #define SIU_PERIOD_BYTES_MAX 8192 /* DMA transfer/period size */ | ||
82 | #define SIU_PERIOD_BYTES_MIN 256 /* DMA transfer/period size */ | ||
83 | #define SIU_PERIODS_MAX 64 /* Max periods in buffer */ | ||
84 | #define SIU_PERIODS_MIN 4 /* Min periods in buffer */ | ||
85 | #define SIU_BUFFER_BYTES_MAX (SIU_PERIOD_BYTES_MAX * SIU_PERIODS_MAX) | ||
86 | |||
87 | /* SIU ports: only one can be used at a time */ | ||
88 | enum { | ||
89 | SIU_PORT_A, | ||
90 | SIU_PORT_B, | ||
91 | SIU_PORT_NUM, | ||
92 | }; | ||
93 | |||
94 | /* SIU clock configuration */ | ||
95 | enum { | ||
96 | SIU_CLKA_PLL, | ||
97 | SIU_CLKA_EXT, | ||
98 | SIU_CLKB_PLL, | ||
99 | SIU_CLKB_EXT | ||
100 | }; | ||
101 | |||
102 | struct siu_info { | ||
103 | int port_id; | ||
104 | u32 __iomem *pram; | ||
105 | u32 __iomem *xram; | ||
106 | u32 __iomem *yram; | ||
107 | u32 __iomem *reg; | ||
108 | struct siu_firmware fw; | ||
109 | }; | ||
110 | |||
111 | struct siu_stream { | ||
112 | struct tasklet_struct tasklet; | ||
113 | struct snd_pcm_substream *substream; | ||
114 | snd_pcm_format_t format; | ||
115 | size_t buf_bytes; | ||
116 | size_t period_bytes; | ||
117 | int cur_period; /* Period currently in dma */ | ||
118 | u32 volume; | ||
119 | snd_pcm_sframes_t xfer_cnt; /* Number of frames */ | ||
120 | u8 rw_flg; /* transfer status */ | ||
121 | /* DMA status */ | ||
122 | struct dma_chan *chan; /* DMA channel */ | ||
123 | struct dma_async_tx_descriptor *tx_desc; | ||
124 | dma_cookie_t cookie; | ||
125 | struct sh_dmae_slave param; | ||
126 | }; | ||
127 | |||
128 | struct siu_port { | ||
129 | unsigned long play_cap; /* Used to track full duplex */ | ||
130 | struct snd_pcm *pcm; | ||
131 | struct siu_stream playback; | ||
132 | struct siu_stream capture; | ||
133 | u32 stfifo; /* STFIFO value from firmware */ | ||
134 | u32 trdat; /* TRDAT value from firmware */ | ||
135 | }; | ||
136 | |||
137 | extern struct siu_port *siu_ports[SIU_PORT_NUM]; | ||
138 | |||
139 | static inline struct siu_port *siu_port_info(struct snd_pcm_substream *substream) | ||
140 | { | ||
141 | struct platform_device *pdev = | ||
142 | to_platform_device(substream->pcm->card->dev); | ||
143 | return siu_ports[pdev->id]; | ||
144 | } | ||
145 | |||
146 | /* Register access */ | ||
147 | static inline void siu_write32(u32 __iomem *addr, u32 val) | ||
148 | { | ||
149 | __raw_writel(val, addr); | ||
150 | } | ||
151 | |||
152 | static inline u32 siu_read32(u32 __iomem *addr) | ||
153 | { | ||
154 | return __raw_readl(addr); | ||
155 | } | ||
156 | |||
157 | /* SIU registers */ | ||
158 | #define SIU_IFCTL (0x000 / sizeof(u32)) | ||
159 | #define SIU_SRCTL (0x004 / sizeof(u32)) | ||
160 | #define SIU_SFORM (0x008 / sizeof(u32)) | ||
161 | #define SIU_CKCTL (0x00c / sizeof(u32)) | ||
162 | #define SIU_TRDAT (0x010 / sizeof(u32)) | ||
163 | #define SIU_STFIFO (0x014 / sizeof(u32)) | ||
164 | #define SIU_DPAK (0x01c / sizeof(u32)) | ||
165 | #define SIU_CKREV (0x020 / sizeof(u32)) | ||
166 | #define SIU_EVNTC (0x028 / sizeof(u32)) | ||
167 | #define SIU_SBCTL (0x040 / sizeof(u32)) | ||
168 | #define SIU_SBPSET (0x044 / sizeof(u32)) | ||
169 | #define SIU_SBFSTS (0x068 / sizeof(u32)) | ||
170 | #define SIU_SBDVCA (0x06c / sizeof(u32)) | ||
171 | #define SIU_SBDVCB (0x070 / sizeof(u32)) | ||
172 | #define SIU_SBACTIV (0x074 / sizeof(u32)) | ||
173 | #define SIU_DMAIA (0x090 / sizeof(u32)) | ||
174 | #define SIU_DMAIB (0x094 / sizeof(u32)) | ||
175 | #define SIU_DMAOA (0x098 / sizeof(u32)) | ||
176 | #define SIU_DMAOB (0x09c / sizeof(u32)) | ||
177 | #define SIU_DMAML (0x0a0 / sizeof(u32)) | ||
178 | #define SIU_SPSTS (0x0cc / sizeof(u32)) | ||
179 | #define SIU_SPCTL (0x0d0 / sizeof(u32)) | ||
180 | #define SIU_BRGASEL (0x100 / sizeof(u32)) | ||
181 | #define SIU_BRRA (0x104 / sizeof(u32)) | ||
182 | #define SIU_BRGBSEL (0x108 / sizeof(u32)) | ||
183 | #define SIU_BRRB (0x10c / sizeof(u32)) | ||
184 | |||
185 | extern struct snd_soc_platform siu_platform; | ||
186 | extern struct snd_soc_dai siu_i2s_dai; | ||
187 | |||
188 | int siu_init_port(int port, struct siu_port **port_info, struct snd_card *card); | ||
189 | void siu_free_port(struct siu_port *port_info); | ||
190 | |||
191 | #endif | ||
192 | |||
193 | #endif /* SIU_H */ | ||
diff --git a/sound/soc/sh/siu_dai.c b/sound/soc/sh/siu_dai.c new file mode 100644 index 000000000000..5452d19607e1 --- /dev/null +++ b/sound/soc/sh/siu_dai.c | |||
@@ -0,0 +1,847 @@ | |||
1 | /* | ||
2 | * siu_dai.c - ALSA SoC driver for Renesas SH7343, SH7722 SIU peripheral. | ||
3 | * | ||
4 | * Copyright (C) 2009-2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de> | ||
5 | * Copyright (C) 2006 Carlos Munoz <carlos@kenati.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | ||
21 | |||
22 | #include <linux/delay.h> | ||
23 | #include <linux/firmware.h> | ||
24 | #include <linux/pm_runtime.h> | ||
25 | |||
26 | #include <asm/clock.h> | ||
27 | #include <asm/siu.h> | ||
28 | |||
29 | #include <sound/control.h> | ||
30 | #include <sound/soc-dai.h> | ||
31 | |||
32 | #include "siu.h" | ||
33 | |||
34 | /* Board specifics */ | ||
35 | #if defined(CONFIG_CPU_SUBTYPE_SH7722) | ||
36 | # define SIU_MAX_VOLUME 0x1000 | ||
37 | #else | ||
38 | # define SIU_MAX_VOLUME 0x7fff | ||
39 | #endif | ||
40 | |||
41 | #define PRAM_SIZE 0x2000 | ||
42 | #define XRAM_SIZE 0x800 | ||
43 | #define YRAM_SIZE 0x800 | ||
44 | |||
45 | #define XRAM_OFFSET 0x4000 | ||
46 | #define YRAM_OFFSET 0x6000 | ||
47 | #define REG_OFFSET 0xc000 | ||
48 | |||
49 | #define PLAYBACK_ENABLED 1 | ||
50 | #define CAPTURE_ENABLED 2 | ||
51 | |||
52 | #define VOLUME_CAPTURE 0 | ||
53 | #define VOLUME_PLAYBACK 1 | ||
54 | #define DFLT_VOLUME_LEVEL 0x08000800 | ||
55 | |||
56 | /* | ||
57 | * SPDIF is only available on port A and on some SIU implementations it is only | ||
58 | * available for input. Due to the lack of hardware to test it, SPDIF is left | ||
59 | * disabled in this driver version | ||
60 | */ | ||
61 | struct format_flag { | ||
62 | u32 i2s; | ||
63 | u32 pcm; | ||
64 | u32 spdif; | ||
65 | u32 mask; | ||
66 | }; | ||
67 | |||
68 | struct port_flag { | ||
69 | struct format_flag playback; | ||
70 | struct format_flag capture; | ||
71 | }; | ||
72 | |||
73 | static struct port_flag siu_flags[SIU_PORT_NUM] = { | ||
74 | [SIU_PORT_A] = { | ||
75 | .playback = { | ||
76 | .i2s = 0x50000000, | ||
77 | .pcm = 0x40000000, | ||
78 | .spdif = 0x80000000, /* not on all SIU versions */ | ||
79 | .mask = 0xd0000000, | ||
80 | }, | ||
81 | .capture = { | ||
82 | .i2s = 0x05000000, | ||
83 | .pcm = 0x04000000, | ||
84 | .spdif = 0x08000000, | ||
85 | .mask = 0x0d000000, | ||
86 | }, | ||
87 | }, | ||
88 | [SIU_PORT_B] = { | ||
89 | .playback = { | ||
90 | .i2s = 0x00500000, | ||
91 | .pcm = 0x00400000, | ||
92 | .spdif = 0, /* impossible - turn off */ | ||
93 | .mask = 0x00500000, | ||
94 | }, | ||
95 | .capture = { | ||
96 | .i2s = 0x00050000, | ||
97 | .pcm = 0x00040000, | ||
98 | .spdif = 0, /* impossible - turn off */ | ||
99 | .mask = 0x00050000, | ||
100 | }, | ||
101 | }, | ||
102 | }; | ||
103 | |||
104 | static void siu_dai_start(struct siu_port *port_info) | ||
105 | { | ||
106 | struct siu_info *info = siu_i2s_dai.private_data; | ||
107 | u32 __iomem *base = info->reg; | ||
108 | |||
109 | dev_dbg(port_info->pcm->card->dev, "%s\n", __func__); | ||
110 | |||
111 | /* Turn on SIU clock */ | ||
112 | pm_runtime_get_sync(siu_i2s_dai.dev); | ||
113 | |||
114 | /* Issue software reset to siu */ | ||
115 | siu_write32(base + SIU_SRCTL, 0); | ||
116 | |||
117 | /* Wait for the reset to take effect */ | ||
118 | udelay(1); | ||
119 | |||
120 | port_info->stfifo = 0; | ||
121 | port_info->trdat = 0; | ||
122 | |||
123 | /* portA, portB, SIU operate */ | ||
124 | siu_write32(base + SIU_SRCTL, 0x301); | ||
125 | |||
126 | /* portA=256fs, portB=256fs */ | ||
127 | siu_write32(base + SIU_CKCTL, 0x40400000); | ||
128 | |||
129 | /* portA's BRG does not divide SIUCKA */ | ||
130 | siu_write32(base + SIU_BRGASEL, 0); | ||
131 | siu_write32(base + SIU_BRRA, 0); | ||
132 | |||
133 | /* portB's BRG divides SIUCKB by half */ | ||
134 | siu_write32(base + SIU_BRGBSEL, 1); | ||
135 | siu_write32(base + SIU_BRRB, 0); | ||
136 | |||
137 | siu_write32(base + SIU_IFCTL, 0x44440000); | ||
138 | |||
139 | /* portA: 32 bit/fs, master; portB: 32 bit/fs, master */ | ||
140 | siu_write32(base + SIU_SFORM, 0x0c0c0000); | ||
141 | |||
142 | /* | ||
143 | * Volume levels: looks like the DSP firmware implements volume controls | ||
144 | * differently from what's described in the datasheet | ||
145 | */ | ||
146 | siu_write32(base + SIU_SBDVCA, port_info->playback.volume); | ||
147 | siu_write32(base + SIU_SBDVCB, port_info->capture.volume); | ||
148 | } | ||
149 | |||
150 | static void siu_dai_stop(void) | ||
151 | { | ||
152 | struct siu_info *info = siu_i2s_dai.private_data; | ||
153 | u32 __iomem *base = info->reg; | ||
154 | |||
155 | /* SIU software reset */ | ||
156 | siu_write32(base + SIU_SRCTL, 0); | ||
157 | |||
158 | /* Turn off SIU clock */ | ||
159 | pm_runtime_put_sync(siu_i2s_dai.dev); | ||
160 | } | ||
161 | |||
162 | static void siu_dai_spbAselect(struct siu_port *port_info) | ||
163 | { | ||
164 | struct siu_info *info = siu_i2s_dai.private_data; | ||
165 | struct siu_firmware *fw = &info->fw; | ||
166 | u32 *ydef = fw->yram0; | ||
167 | u32 idx; | ||
168 | |||
169 | /* path A use */ | ||
170 | if (!info->port_id) | ||
171 | idx = 1; /* portA */ | ||
172 | else | ||
173 | idx = 2; /* portB */ | ||
174 | |||
175 | ydef[0] = (fw->spbpar[idx].ab1a << 16) | | ||
176 | (fw->spbpar[idx].ab0a << 8) | | ||
177 | (fw->spbpar[idx].dir << 7) | 3; | ||
178 | ydef[1] = fw->yram0[1]; /* 0x03000300 */ | ||
179 | ydef[2] = (16 / 2) << 24; | ||
180 | ydef[3] = fw->yram0[3]; /* 0 */ | ||
181 | ydef[4] = fw->yram0[4]; /* 0 */ | ||
182 | ydef[7] = fw->spbpar[idx].event; | ||
183 | port_info->stfifo |= fw->spbpar[idx].stfifo; | ||
184 | port_info->trdat |= fw->spbpar[idx].trdat; | ||
185 | } | ||
186 | |||
187 | static void siu_dai_spbBselect(struct siu_port *port_info) | ||
188 | { | ||
189 | struct siu_info *info = siu_i2s_dai.private_data; | ||
190 | struct siu_firmware *fw = &info->fw; | ||
191 | u32 *ydef = fw->yram0; | ||
192 | u32 idx; | ||
193 | |||
194 | /* path B use */ | ||
195 | if (!info->port_id) | ||
196 | idx = 7; /* portA */ | ||
197 | else | ||
198 | idx = 8; /* portB */ | ||
199 | |||
200 | ydef[5] = (fw->spbpar[idx].ab1a << 16) | | ||
201 | (fw->spbpar[idx].ab0a << 8) | 1; | ||
202 | ydef[6] = fw->spbpar[idx].event; | ||
203 | port_info->stfifo |= fw->spbpar[idx].stfifo; | ||
204 | port_info->trdat |= fw->spbpar[idx].trdat; | ||
205 | } | ||
206 | |||
207 | static void siu_dai_open(struct siu_stream *siu_stream) | ||
208 | { | ||
209 | struct siu_info *info = siu_i2s_dai.private_data; | ||
210 | u32 __iomem *base = info->reg; | ||
211 | u32 srctl, ifctl; | ||
212 | |||
213 | srctl = siu_read32(base + SIU_SRCTL); | ||
214 | ifctl = siu_read32(base + SIU_IFCTL); | ||
215 | |||
216 | switch (info->port_id) { | ||
217 | case SIU_PORT_A: | ||
218 | /* portA operates */ | ||
219 | srctl |= 0x200; | ||
220 | ifctl &= ~0xc2; | ||
221 | break; | ||
222 | case SIU_PORT_B: | ||
223 | /* portB operates */ | ||
224 | srctl |= 0x100; | ||
225 | ifctl &= ~0x31; | ||
226 | break; | ||
227 | } | ||
228 | |||
229 | siu_write32(base + SIU_SRCTL, srctl); | ||
230 | /* Unmute and configure portA */ | ||
231 | siu_write32(base + SIU_IFCTL, ifctl); | ||
232 | } | ||
233 | |||
234 | /* | ||
235 | * At the moment only fixed Left-upper, Left-lower, Right-upper, Right-lower | ||
236 | * packing is supported | ||
237 | */ | ||
238 | static void siu_dai_pcmdatapack(struct siu_stream *siu_stream) | ||
239 | { | ||
240 | struct siu_info *info = siu_i2s_dai.private_data; | ||
241 | u32 __iomem *base = info->reg; | ||
242 | u32 dpak; | ||
243 | |||
244 | dpak = siu_read32(base + SIU_DPAK); | ||
245 | |||
246 | switch (info->port_id) { | ||
247 | case SIU_PORT_A: | ||
248 | dpak &= ~0xc0000000; | ||
249 | break; | ||
250 | case SIU_PORT_B: | ||
251 | dpak &= ~0x00c00000; | ||
252 | break; | ||
253 | } | ||
254 | |||
255 | siu_write32(base + SIU_DPAK, dpak); | ||
256 | } | ||
257 | |||
258 | static int siu_dai_spbstart(struct siu_port *port_info) | ||
259 | { | ||
260 | struct siu_info *info = siu_i2s_dai.private_data; | ||
261 | u32 __iomem *base = info->reg; | ||
262 | struct siu_firmware *fw = &info->fw; | ||
263 | u32 *ydef = fw->yram0; | ||
264 | int cnt; | ||
265 | u32 __iomem *add; | ||
266 | u32 *ptr; | ||
267 | |||
268 | /* Load SPB Program in PRAM */ | ||
269 | ptr = fw->pram0; | ||
270 | add = info->pram; | ||
271 | for (cnt = 0; cnt < PRAM0_SIZE; cnt++, add++, ptr++) | ||
272 | siu_write32(add, *ptr); | ||
273 | |||
274 | ptr = fw->pram1; | ||
275 | add = info->pram + (0x0100 / sizeof(u32)); | ||
276 | for (cnt = 0; cnt < PRAM1_SIZE; cnt++, add++, ptr++) | ||
277 | siu_write32(add, *ptr); | ||
278 | |||
279 | /* XRAM initialization */ | ||
280 | add = info->xram; | ||
281 | for (cnt = 0; cnt < XRAM0_SIZE + XRAM1_SIZE + XRAM2_SIZE; cnt++, add++) | ||
282 | siu_write32(add, 0); | ||
283 | |||
284 | /* YRAM variable area initialization */ | ||
285 | add = info->yram; | ||
286 | for (cnt = 0; cnt < YRAM_DEF_SIZE; cnt++, add++) | ||
287 | siu_write32(add, ydef[cnt]); | ||
288 | |||
289 | /* YRAM FIR coefficient area initialization */ | ||
290 | add = info->yram + (0x0200 / sizeof(u32)); | ||
291 | for (cnt = 0; cnt < YRAM_FIR_SIZE; cnt++, add++) | ||
292 | siu_write32(add, fw->yram_fir_coeff[cnt]); | ||
293 | |||
294 | /* YRAM IIR coefficient area initialization */ | ||
295 | add = info->yram + (0x0600 / sizeof(u32)); | ||
296 | for (cnt = 0; cnt < YRAM_IIR_SIZE; cnt++, add++) | ||
297 | siu_write32(add, 0); | ||
298 | |||
299 | siu_write32(base + SIU_TRDAT, port_info->trdat); | ||
300 | port_info->trdat = 0x0; | ||
301 | |||
302 | |||
303 | /* SPB start condition: software */ | ||
304 | siu_write32(base + SIU_SBACTIV, 0); | ||
305 | /* Start SPB */ | ||
306 | siu_write32(base + SIU_SBCTL, 0xc0000000); | ||
307 | /* Wait for program to halt */ | ||
308 | cnt = 0x10000; | ||
309 | while (--cnt && siu_read32(base + SIU_SBCTL) != 0x80000000) | ||
310 | cpu_relax(); | ||
311 | |||
312 | if (!cnt) | ||
313 | return -EBUSY; | ||
314 | |||
315 | /* SPB program start address setting */ | ||
316 | siu_write32(base + SIU_SBPSET, 0x00400000); | ||
317 | /* SPB hardware start(FIFOCTL source) */ | ||
318 | siu_write32(base + SIU_SBACTIV, 0xc0000000); | ||
319 | |||
320 | return 0; | ||
321 | } | ||
322 | |||
323 | static void siu_dai_spbstop(struct siu_port *port_info) | ||
324 | { | ||
325 | struct siu_info *info = siu_i2s_dai.private_data; | ||
326 | u32 __iomem *base = info->reg; | ||
327 | |||
328 | siu_write32(base + SIU_SBACTIV, 0); | ||
329 | /* SPB stop */ | ||
330 | siu_write32(base + SIU_SBCTL, 0); | ||
331 | |||
332 | port_info->stfifo = 0; | ||
333 | } | ||
334 | |||
335 | /* API functions */ | ||
336 | |||
337 | /* Playback and capture hardware properties are identical */ | ||
338 | static struct snd_pcm_hardware siu_dai_pcm_hw = { | ||
339 | .info = SNDRV_PCM_INFO_INTERLEAVED, | ||
340 | .formats = SNDRV_PCM_FMTBIT_S16, | ||
341 | .rates = SNDRV_PCM_RATE_8000_48000, | ||
342 | .rate_min = 8000, | ||
343 | .rate_max = 48000, | ||
344 | .channels_min = 2, | ||
345 | .channels_max = 2, | ||
346 | .buffer_bytes_max = SIU_BUFFER_BYTES_MAX, | ||
347 | .period_bytes_min = SIU_PERIOD_BYTES_MIN, | ||
348 | .period_bytes_max = SIU_PERIOD_BYTES_MAX, | ||
349 | .periods_min = SIU_PERIODS_MIN, | ||
350 | .periods_max = SIU_PERIODS_MAX, | ||
351 | }; | ||
352 | |||
353 | static int siu_dai_info_volume(struct snd_kcontrol *kctrl, | ||
354 | struct snd_ctl_elem_info *uinfo) | ||
355 | { | ||
356 | struct siu_port *port_info = snd_kcontrol_chip(kctrl); | ||
357 | |||
358 | dev_dbg(port_info->pcm->card->dev, "%s\n", __func__); | ||
359 | |||
360 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
361 | uinfo->count = 2; | ||
362 | uinfo->value.integer.min = 0; | ||
363 | uinfo->value.integer.max = SIU_MAX_VOLUME; | ||
364 | |||
365 | return 0; | ||
366 | } | ||
367 | |||
368 | static int siu_dai_get_volume(struct snd_kcontrol *kctrl, | ||
369 | struct snd_ctl_elem_value *ucontrol) | ||
370 | { | ||
371 | struct siu_port *port_info = snd_kcontrol_chip(kctrl); | ||
372 | struct device *dev = port_info->pcm->card->dev; | ||
373 | u32 vol; | ||
374 | |||
375 | dev_dbg(dev, "%s\n", __func__); | ||
376 | |||
377 | switch (kctrl->private_value) { | ||
378 | case VOLUME_PLAYBACK: | ||
379 | /* Playback is always on port 0 */ | ||
380 | vol = port_info->playback.volume; | ||
381 | ucontrol->value.integer.value[0] = vol & 0xffff; | ||
382 | ucontrol->value.integer.value[1] = vol >> 16 & 0xffff; | ||
383 | break; | ||
384 | case VOLUME_CAPTURE: | ||
385 | /* Capture is always on port 1 */ | ||
386 | vol = port_info->capture.volume; | ||
387 | ucontrol->value.integer.value[0] = vol & 0xffff; | ||
388 | ucontrol->value.integer.value[1] = vol >> 16 & 0xffff; | ||
389 | break; | ||
390 | default: | ||
391 | dev_err(dev, "%s() invalid private_value=%ld\n", | ||
392 | __func__, kctrl->private_value); | ||
393 | return -EINVAL; | ||
394 | } | ||
395 | |||
396 | return 0; | ||
397 | } | ||
398 | |||
399 | static int siu_dai_put_volume(struct snd_kcontrol *kctrl, | ||
400 | struct snd_ctl_elem_value *ucontrol) | ||
401 | { | ||
402 | struct siu_port *port_info = snd_kcontrol_chip(kctrl); | ||
403 | struct device *dev = port_info->pcm->card->dev; | ||
404 | struct siu_info *info = siu_i2s_dai.private_data; | ||
405 | u32 __iomem *base = info->reg; | ||
406 | u32 new_vol; | ||
407 | u32 cur_vol; | ||
408 | |||
409 | dev_dbg(dev, "%s\n", __func__); | ||
410 | |||
411 | if (ucontrol->value.integer.value[0] < 0 || | ||
412 | ucontrol->value.integer.value[0] > SIU_MAX_VOLUME || | ||
413 | ucontrol->value.integer.value[1] < 0 || | ||
414 | ucontrol->value.integer.value[1] > SIU_MAX_VOLUME) | ||
415 | return -EINVAL; | ||
416 | |||
417 | new_vol = ucontrol->value.integer.value[0] | | ||
418 | ucontrol->value.integer.value[1] << 16; | ||
419 | |||
420 | /* See comment above - DSP firmware implementation */ | ||
421 | switch (kctrl->private_value) { | ||
422 | case VOLUME_PLAYBACK: | ||
423 | /* Playback is always on port 0 */ | ||
424 | cur_vol = port_info->playback.volume; | ||
425 | siu_write32(base + SIU_SBDVCA, new_vol); | ||
426 | port_info->playback.volume = new_vol; | ||
427 | break; | ||
428 | case VOLUME_CAPTURE: | ||
429 | /* Capture is always on port 1 */ | ||
430 | cur_vol = port_info->capture.volume; | ||
431 | siu_write32(base + SIU_SBDVCB, new_vol); | ||
432 | port_info->capture.volume = new_vol; | ||
433 | break; | ||
434 | default: | ||
435 | dev_err(dev, "%s() invalid private_value=%ld\n", | ||
436 | __func__, kctrl->private_value); | ||
437 | return -EINVAL; | ||
438 | } | ||
439 | |||
440 | if (cur_vol != new_vol) | ||
441 | return 1; | ||
442 | |||
443 | return 0; | ||
444 | } | ||
445 | |||
446 | static struct snd_kcontrol_new playback_controls = { | ||
447 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
448 | .name = "PCM Playback Volume", | ||
449 | .index = 0, | ||
450 | .info = siu_dai_info_volume, | ||
451 | .get = siu_dai_get_volume, | ||
452 | .put = siu_dai_put_volume, | ||
453 | .private_value = VOLUME_PLAYBACK, | ||
454 | }; | ||
455 | |||
456 | static struct snd_kcontrol_new capture_controls = { | ||
457 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
458 | .name = "PCM Capture Volume", | ||
459 | .index = 0, | ||
460 | .info = siu_dai_info_volume, | ||
461 | .get = siu_dai_get_volume, | ||
462 | .put = siu_dai_put_volume, | ||
463 | .private_value = VOLUME_CAPTURE, | ||
464 | }; | ||
465 | |||
466 | int siu_init_port(int port, struct siu_port **port_info, struct snd_card *card) | ||
467 | { | ||
468 | struct device *dev = card->dev; | ||
469 | struct snd_kcontrol *kctrl; | ||
470 | int ret; | ||
471 | |||
472 | *port_info = kzalloc(sizeof(**port_info), GFP_KERNEL); | ||
473 | if (!*port_info) | ||
474 | return -ENOMEM; | ||
475 | |||
476 | dev_dbg(dev, "%s: port #%d@%p\n", __func__, port, *port_info); | ||
477 | |||
478 | (*port_info)->playback.volume = DFLT_VOLUME_LEVEL; | ||
479 | (*port_info)->capture.volume = DFLT_VOLUME_LEVEL; | ||
480 | |||
481 | /* | ||
482 | * Add mixer support. The SPB is used to change the volume. Both | ||
483 | * ports use the same SPB. Therefore, we only register one | ||
484 | * control instance since it will be used by both channels. | ||
485 | * In error case we continue without controls. | ||
486 | */ | ||
487 | kctrl = snd_ctl_new1(&playback_controls, *port_info); | ||
488 | ret = snd_ctl_add(card, kctrl); | ||
489 | if (ret < 0) | ||
490 | dev_err(dev, | ||
491 | "failed to add playback controls %p port=%d err=%d\n", | ||
492 | kctrl, port, ret); | ||
493 | |||
494 | kctrl = snd_ctl_new1(&capture_controls, *port_info); | ||
495 | ret = snd_ctl_add(card, kctrl); | ||
496 | if (ret < 0) | ||
497 | dev_err(dev, | ||
498 | "failed to add capture controls %p port=%d err=%d\n", | ||
499 | kctrl, port, ret); | ||
500 | |||
501 | return 0; | ||
502 | } | ||
503 | |||
504 | void siu_free_port(struct siu_port *port_info) | ||
505 | { | ||
506 | kfree(port_info); | ||
507 | } | ||
508 | |||
509 | static int siu_dai_startup(struct snd_pcm_substream *substream, | ||
510 | struct snd_soc_dai *dai) | ||
511 | { | ||
512 | struct siu_info *info = siu_i2s_dai.private_data; | ||
513 | struct snd_pcm_runtime *rt = substream->runtime; | ||
514 | struct siu_port *port_info = siu_port_info(substream); | ||
515 | int ret; | ||
516 | |||
517 | dev_dbg(substream->pcm->card->dev, "%s: port=%d@%p\n", __func__, | ||
518 | info->port_id, port_info); | ||
519 | |||
520 | snd_soc_set_runtime_hwparams(substream, &siu_dai_pcm_hw); | ||
521 | |||
522 | ret = snd_pcm_hw_constraint_integer(rt, SNDRV_PCM_HW_PARAM_PERIODS); | ||
523 | if (unlikely(ret < 0)) | ||
524 | return ret; | ||
525 | |||
526 | siu_dai_start(port_info); | ||
527 | |||
528 | return 0; | ||
529 | } | ||
530 | |||
531 | static void siu_dai_shutdown(struct snd_pcm_substream *substream, | ||
532 | struct snd_soc_dai *dai) | ||
533 | { | ||
534 | struct siu_info *info = siu_i2s_dai.private_data; | ||
535 | struct siu_port *port_info = siu_port_info(substream); | ||
536 | |||
537 | dev_dbg(substream->pcm->card->dev, "%s: port=%d@%p\n", __func__, | ||
538 | info->port_id, port_info); | ||
539 | |||
540 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
541 | port_info->play_cap &= ~PLAYBACK_ENABLED; | ||
542 | else | ||
543 | port_info->play_cap &= ~CAPTURE_ENABLED; | ||
544 | |||
545 | /* Stop the siu if the other stream is not using it */ | ||
546 | if (!port_info->play_cap) { | ||
547 | /* during stmread or stmwrite ? */ | ||
548 | BUG_ON(port_info->playback.rw_flg || port_info->capture.rw_flg); | ||
549 | siu_dai_spbstop(port_info); | ||
550 | siu_dai_stop(); | ||
551 | } | ||
552 | } | ||
553 | |||
554 | /* PCM part of siu_dai_playback_prepare() / siu_dai_capture_prepare() */ | ||
555 | static int siu_dai_prepare(struct snd_pcm_substream *substream, | ||
556 | struct snd_soc_dai *dai) | ||
557 | { | ||
558 | struct siu_info *info = siu_i2s_dai.private_data; | ||
559 | struct snd_pcm_runtime *rt = substream->runtime; | ||
560 | struct siu_port *port_info = siu_port_info(substream); | ||
561 | struct siu_stream *siu_stream; | ||
562 | int self, ret; | ||
563 | |||
564 | dev_dbg(substream->pcm->card->dev, | ||
565 | "%s: port %d, active streams %lx, %d channels\n", | ||
566 | __func__, info->port_id, port_info->play_cap, rt->channels); | ||
567 | |||
568 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
569 | self = PLAYBACK_ENABLED; | ||
570 | siu_stream = &port_info->playback; | ||
571 | } else { | ||
572 | self = CAPTURE_ENABLED; | ||
573 | siu_stream = &port_info->capture; | ||
574 | } | ||
575 | |||
576 | /* Set up the siu if not already done */ | ||
577 | if (!port_info->play_cap) { | ||
578 | siu_stream->rw_flg = 0; /* stream-data transfer flag */ | ||
579 | |||
580 | siu_dai_spbAselect(port_info); | ||
581 | siu_dai_spbBselect(port_info); | ||
582 | |||
583 | siu_dai_open(siu_stream); | ||
584 | |||
585 | siu_dai_pcmdatapack(siu_stream); | ||
586 | |||
587 | ret = siu_dai_spbstart(port_info); | ||
588 | if (ret < 0) | ||
589 | goto fail; | ||
590 | } | ||
591 | |||
592 | port_info->play_cap |= self; | ||
593 | |||
594 | fail: | ||
595 | return ret; | ||
596 | } | ||
597 | |||
598 | /* | ||
599 | * SIU can set bus format to I2S / PCM / SPDIF independently for playback and | ||
600 | * capture, however, the current API sets the bus format globally for a DAI. | ||
601 | */ | ||
602 | static int siu_dai_set_fmt(struct snd_soc_dai *dai, | ||
603 | unsigned int fmt) | ||
604 | { | ||
605 | struct siu_info *info = siu_i2s_dai.private_data; | ||
606 | u32 __iomem *base = info->reg; | ||
607 | u32 ifctl; | ||
608 | |||
609 | dev_dbg(dai->dev, "%s: fmt 0x%x on port %d\n", | ||
610 | __func__, fmt, info->port_id); | ||
611 | |||
612 | if (info->port_id < 0) | ||
613 | return -ENODEV; | ||
614 | |||
615 | /* Here select between I2S / PCM / SPDIF */ | ||
616 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
617 | case SND_SOC_DAIFMT_I2S: | ||
618 | ifctl = siu_flags[info->port_id].playback.i2s | | ||
619 | siu_flags[info->port_id].capture.i2s; | ||
620 | break; | ||
621 | case SND_SOC_DAIFMT_LEFT_J: | ||
622 | ifctl = siu_flags[info->port_id].playback.pcm | | ||
623 | siu_flags[info->port_id].capture.pcm; | ||
624 | break; | ||
625 | /* SPDIF disabled - see comment at the top */ | ||
626 | default: | ||
627 | return -EINVAL; | ||
628 | } | ||
629 | |||
630 | ifctl |= ~(siu_flags[info->port_id].playback.mask | | ||
631 | siu_flags[info->port_id].capture.mask) & | ||
632 | siu_read32(base + SIU_IFCTL); | ||
633 | siu_write32(base + SIU_IFCTL, ifctl); | ||
634 | |||
635 | return 0; | ||
636 | } | ||
637 | |||
638 | static int siu_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id, | ||
639 | unsigned int freq, int dir) | ||
640 | { | ||
641 | struct clk *siu_clk, *parent_clk; | ||
642 | char *siu_name, *parent_name; | ||
643 | int ret; | ||
644 | |||
645 | if (dir != SND_SOC_CLOCK_IN) | ||
646 | return -EINVAL; | ||
647 | |||
648 | dev_dbg(dai->dev, "%s: using clock %d\n", __func__, clk_id); | ||
649 | |||
650 | switch (clk_id) { | ||
651 | case SIU_CLKA_PLL: | ||
652 | siu_name = "siua_clk"; | ||
653 | parent_name = "pll_clk"; | ||
654 | break; | ||
655 | case SIU_CLKA_EXT: | ||
656 | siu_name = "siua_clk"; | ||
657 | parent_name = "siumcka_clk"; | ||
658 | break; | ||
659 | case SIU_CLKB_PLL: | ||
660 | siu_name = "siub_clk"; | ||
661 | parent_name = "pll_clk"; | ||
662 | break; | ||
663 | case SIU_CLKB_EXT: | ||
664 | siu_name = "siub_clk"; | ||
665 | parent_name = "siumckb_clk"; | ||
666 | break; | ||
667 | default: | ||
668 | return -EINVAL; | ||
669 | } | ||
670 | |||
671 | siu_clk = clk_get(siu_i2s_dai.dev, siu_name); | ||
672 | if (IS_ERR(siu_clk)) | ||
673 | return PTR_ERR(siu_clk); | ||
674 | |||
675 | parent_clk = clk_get(siu_i2s_dai.dev, parent_name); | ||
676 | if (!IS_ERR(parent_clk)) { | ||
677 | ret = clk_set_parent(siu_clk, parent_clk); | ||
678 | if (!ret) | ||
679 | clk_set_rate(siu_clk, freq); | ||
680 | clk_put(parent_clk); | ||
681 | } | ||
682 | |||
683 | clk_put(siu_clk); | ||
684 | |||
685 | return 0; | ||
686 | } | ||
687 | |||
688 | static struct snd_soc_dai_ops siu_dai_ops = { | ||
689 | .startup = siu_dai_startup, | ||
690 | .shutdown = siu_dai_shutdown, | ||
691 | .prepare = siu_dai_prepare, | ||
692 | .set_sysclk = siu_dai_set_sysclk, | ||
693 | .set_fmt = siu_dai_set_fmt, | ||
694 | }; | ||
695 | |||
696 | struct snd_soc_dai siu_i2s_dai = { | ||
697 | .name = "sh-siu", | ||
698 | .id = 0, | ||
699 | .playback = { | ||
700 | .channels_min = 2, | ||
701 | .channels_max = 2, | ||
702 | .formats = SNDRV_PCM_FMTBIT_S16, | ||
703 | .rates = SNDRV_PCM_RATE_8000_48000, | ||
704 | }, | ||
705 | .capture = { | ||
706 | .channels_min = 2, | ||
707 | .channels_max = 2, | ||
708 | .formats = SNDRV_PCM_FMTBIT_S16, | ||
709 | .rates = SNDRV_PCM_RATE_8000_48000, | ||
710 | }, | ||
711 | .ops = &siu_dai_ops, | ||
712 | }; | ||
713 | EXPORT_SYMBOL_GPL(siu_i2s_dai); | ||
714 | |||
715 | static int __devinit siu_probe(struct platform_device *pdev) | ||
716 | { | ||
717 | const struct firmware *fw_entry; | ||
718 | struct resource *res, *region; | ||
719 | struct siu_info *info; | ||
720 | int ret; | ||
721 | |||
722 | info = kmalloc(sizeof(*info), GFP_KERNEL); | ||
723 | if (!info) | ||
724 | return -ENOMEM; | ||
725 | |||
726 | ret = request_firmware(&fw_entry, "siu_spb.bin", &pdev->dev); | ||
727 | if (ret) | ||
728 | goto ereqfw; | ||
729 | |||
730 | /* | ||
731 | * Loaded firmware is "const" - read only, but we have to modify it in | ||
732 | * snd_siu_sh7343_spbAselect() and snd_siu_sh7343_spbBselect() | ||
733 | */ | ||
734 | memcpy(&info->fw, fw_entry->data, fw_entry->size); | ||
735 | |||
736 | release_firmware(fw_entry); | ||
737 | |||
738 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
739 | if (!res) { | ||
740 | ret = -ENODEV; | ||
741 | goto egetres; | ||
742 | } | ||
743 | |||
744 | region = request_mem_region(res->start, resource_size(res), | ||
745 | pdev->name); | ||
746 | if (!region) { | ||
747 | dev_err(&pdev->dev, "SIU region already claimed\n"); | ||
748 | ret = -EBUSY; | ||
749 | goto ereqmemreg; | ||
750 | } | ||
751 | |||
752 | ret = -ENOMEM; | ||
753 | info->pram = ioremap(res->start, PRAM_SIZE); | ||
754 | if (!info->pram) | ||
755 | goto emappram; | ||
756 | info->xram = ioremap(res->start + XRAM_OFFSET, XRAM_SIZE); | ||
757 | if (!info->xram) | ||
758 | goto emapxram; | ||
759 | info->yram = ioremap(res->start + YRAM_OFFSET, YRAM_SIZE); | ||
760 | if (!info->yram) | ||
761 | goto emapyram; | ||
762 | info->reg = ioremap(res->start + REG_OFFSET, resource_size(res) - | ||
763 | REG_OFFSET); | ||
764 | if (!info->reg) | ||
765 | goto emapreg; | ||
766 | |||
767 | siu_i2s_dai.dev = &pdev->dev; | ||
768 | siu_i2s_dai.private_data = info; | ||
769 | |||
770 | ret = snd_soc_register_dais(&siu_i2s_dai, 1); | ||
771 | if (ret < 0) | ||
772 | goto edaiinit; | ||
773 | |||
774 | ret = snd_soc_register_platform(&siu_platform); | ||
775 | if (ret < 0) | ||
776 | goto esocregp; | ||
777 | |||
778 | pm_runtime_enable(&pdev->dev); | ||
779 | |||
780 | return ret; | ||
781 | |||
782 | esocregp: | ||
783 | snd_soc_unregister_dais(&siu_i2s_dai, 1); | ||
784 | edaiinit: | ||
785 | iounmap(info->reg); | ||
786 | emapreg: | ||
787 | iounmap(info->yram); | ||
788 | emapyram: | ||
789 | iounmap(info->xram); | ||
790 | emapxram: | ||
791 | iounmap(info->pram); | ||
792 | emappram: | ||
793 | release_mem_region(res->start, resource_size(res)); | ||
794 | ereqmemreg: | ||
795 | egetres: | ||
796 | ereqfw: | ||
797 | kfree(info); | ||
798 | |||
799 | return ret; | ||
800 | } | ||
801 | |||
802 | static int __devexit siu_remove(struct platform_device *pdev) | ||
803 | { | ||
804 | struct siu_info *info = siu_i2s_dai.private_data; | ||
805 | struct resource *res; | ||
806 | |||
807 | pm_runtime_disable(&pdev->dev); | ||
808 | |||
809 | snd_soc_unregister_platform(&siu_platform); | ||
810 | snd_soc_unregister_dais(&siu_i2s_dai, 1); | ||
811 | |||
812 | iounmap(info->reg); | ||
813 | iounmap(info->yram); | ||
814 | iounmap(info->xram); | ||
815 | iounmap(info->pram); | ||
816 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
817 | if (res) | ||
818 | release_mem_region(res->start, resource_size(res)); | ||
819 | kfree(info); | ||
820 | |||
821 | return 0; | ||
822 | } | ||
823 | |||
824 | static struct platform_driver siu_driver = { | ||
825 | .driver = { | ||
826 | .name = "sh_siu", | ||
827 | }, | ||
828 | .probe = siu_probe, | ||
829 | .remove = __devexit_p(siu_remove), | ||
830 | }; | ||
831 | |||
832 | static int __init siu_init(void) | ||
833 | { | ||
834 | return platform_driver_register(&siu_driver); | ||
835 | } | ||
836 | |||
837 | static void __exit siu_exit(void) | ||
838 | { | ||
839 | platform_driver_unregister(&siu_driver); | ||
840 | } | ||
841 | |||
842 | module_init(siu_init) | ||
843 | module_exit(siu_exit) | ||
844 | |||
845 | MODULE_AUTHOR("Carlos Munoz <carlos@kenati.com>"); | ||
846 | MODULE_DESCRIPTION("ALSA SoC SH7722 SIU driver"); | ||
847 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/sh/siu_pcm.c b/sound/soc/sh/siu_pcm.c new file mode 100644 index 000000000000..ba7f8d05d977 --- /dev/null +++ b/sound/soc/sh/siu_pcm.c | |||
@@ -0,0 +1,616 @@ | |||
1 | /* | ||
2 | * siu_pcm.c - ALSA driver for Renesas SH7343, SH7722 SIU peripheral. | ||
3 | * | ||
4 | * Copyright (C) 2009-2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de> | ||
5 | * Copyright (C) 2006 Carlos Munoz <carlos@kenati.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | ||
21 | #include <linux/delay.h> | ||
22 | #include <linux/dma-mapping.h> | ||
23 | #include <linux/dmaengine.h> | ||
24 | #include <linux/interrupt.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/platform_device.h> | ||
27 | #include <linux/slab.h> | ||
28 | |||
29 | #include <sound/control.h> | ||
30 | #include <sound/core.h> | ||
31 | #include <sound/pcm.h> | ||
32 | #include <sound/pcm_params.h> | ||
33 | #include <sound/soc-dai.h> | ||
34 | |||
35 | #include <asm/dmaengine.h> | ||
36 | #include <asm/siu.h> | ||
37 | |||
38 | #include "siu.h" | ||
39 | |||
40 | #define GET_MAX_PERIODS(buf_bytes, period_bytes) \ | ||
41 | ((buf_bytes) / (period_bytes)) | ||
42 | #define PERIOD_OFFSET(buf_addr, period_num, period_bytes) \ | ||
43 | ((buf_addr) + ((period_num) * (period_bytes))) | ||
44 | |||
45 | #define RWF_STM_RD 0x01 /* Read in progress */ | ||
46 | #define RWF_STM_WT 0x02 /* Write in progress */ | ||
47 | |||
48 | struct siu_port *siu_ports[SIU_PORT_NUM]; | ||
49 | |||
50 | /* transfersize is number of u32 dma transfers per period */ | ||
51 | static int siu_pcm_stmwrite_stop(struct siu_port *port_info) | ||
52 | { | ||
53 | struct siu_info *info = siu_i2s_dai.private_data; | ||
54 | u32 __iomem *base = info->reg; | ||
55 | struct siu_stream *siu_stream = &port_info->playback; | ||
56 | u32 stfifo; | ||
57 | |||
58 | if (!siu_stream->rw_flg) | ||
59 | return -EPERM; | ||
60 | |||
61 | /* output FIFO disable */ | ||
62 | stfifo = siu_read32(base + SIU_STFIFO); | ||
63 | siu_write32(base + SIU_STFIFO, stfifo & ~0x0c180c18); | ||
64 | pr_debug("%s: STFIFO %x -> %x\n", __func__, | ||
65 | stfifo, stfifo & ~0x0c180c18); | ||
66 | |||
67 | /* during stmwrite clear */ | ||
68 | siu_stream->rw_flg = 0; | ||
69 | |||
70 | return 0; | ||
71 | } | ||
72 | |||
73 | static int siu_pcm_stmwrite_start(struct siu_port *port_info) | ||
74 | { | ||
75 | struct siu_stream *siu_stream = &port_info->playback; | ||
76 | |||
77 | if (siu_stream->rw_flg) | ||
78 | return -EPERM; | ||
79 | |||
80 | /* Current period in buffer */ | ||
81 | port_info->playback.cur_period = 0; | ||
82 | |||
83 | /* during stmwrite flag set */ | ||
84 | siu_stream->rw_flg = RWF_STM_WT; | ||
85 | |||
86 | /* DMA transfer start */ | ||
87 | tasklet_schedule(&siu_stream->tasklet); | ||
88 | |||
89 | return 0; | ||
90 | } | ||
91 | |||
92 | static void siu_dma_tx_complete(void *arg) | ||
93 | { | ||
94 | struct siu_stream *siu_stream = arg; | ||
95 | |||
96 | if (!siu_stream->rw_flg) | ||
97 | return; | ||
98 | |||
99 | /* Update completed period count */ | ||
100 | if (++siu_stream->cur_period >= | ||
101 | GET_MAX_PERIODS(siu_stream->buf_bytes, | ||
102 | siu_stream->period_bytes)) | ||
103 | siu_stream->cur_period = 0; | ||
104 | |||
105 | pr_debug("%s: done period #%d (%u/%u bytes), cookie %d\n", | ||
106 | __func__, siu_stream->cur_period, | ||
107 | siu_stream->cur_period * siu_stream->period_bytes, | ||
108 | siu_stream->buf_bytes, siu_stream->cookie); | ||
109 | |||
110 | tasklet_schedule(&siu_stream->tasklet); | ||
111 | |||
112 | /* Notify alsa: a period is done */ | ||
113 | snd_pcm_period_elapsed(siu_stream->substream); | ||
114 | } | ||
115 | |||
116 | static int siu_pcm_wr_set(struct siu_port *port_info, | ||
117 | dma_addr_t buff, u32 size) | ||
118 | { | ||
119 | struct siu_info *info = siu_i2s_dai.private_data; | ||
120 | u32 __iomem *base = info->reg; | ||
121 | struct siu_stream *siu_stream = &port_info->playback; | ||
122 | struct snd_pcm_substream *substream = siu_stream->substream; | ||
123 | struct device *dev = substream->pcm->card->dev; | ||
124 | struct dma_async_tx_descriptor *desc; | ||
125 | dma_cookie_t cookie; | ||
126 | struct scatterlist sg; | ||
127 | u32 stfifo; | ||
128 | |||
129 | sg_init_table(&sg, 1); | ||
130 | sg_set_page(&sg, pfn_to_page(PFN_DOWN(buff)), | ||
131 | size, offset_in_page(buff)); | ||
132 | sg_dma_address(&sg) = buff; | ||
133 | |||
134 | desc = siu_stream->chan->device->device_prep_slave_sg(siu_stream->chan, | ||
135 | &sg, 1, DMA_TO_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); | ||
136 | if (!desc) { | ||
137 | dev_err(dev, "Failed to allocate a dma descriptor\n"); | ||
138 | return -ENOMEM; | ||
139 | } | ||
140 | |||
141 | desc->callback = siu_dma_tx_complete; | ||
142 | desc->callback_param = siu_stream; | ||
143 | cookie = desc->tx_submit(desc); | ||
144 | if (cookie < 0) { | ||
145 | dev_err(dev, "Failed to submit a dma transfer\n"); | ||
146 | return cookie; | ||
147 | } | ||
148 | |||
149 | siu_stream->tx_desc = desc; | ||
150 | siu_stream->cookie = cookie; | ||
151 | |||
152 | dma_async_issue_pending(siu_stream->chan); | ||
153 | |||
154 | /* only output FIFO enable */ | ||
155 | stfifo = siu_read32(base + SIU_STFIFO); | ||
156 | siu_write32(base + SIU_STFIFO, stfifo | (port_info->stfifo & 0x0c180c18)); | ||
157 | dev_dbg(dev, "%s: STFIFO %x -> %x\n", __func__, | ||
158 | stfifo, stfifo | (port_info->stfifo & 0x0c180c18)); | ||
159 | |||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | static int siu_pcm_rd_set(struct siu_port *port_info, | ||
164 | dma_addr_t buff, size_t size) | ||
165 | { | ||
166 | struct siu_info *info = siu_i2s_dai.private_data; | ||
167 | u32 __iomem *base = info->reg; | ||
168 | struct siu_stream *siu_stream = &port_info->capture; | ||
169 | struct snd_pcm_substream *substream = siu_stream->substream; | ||
170 | struct device *dev = substream->pcm->card->dev; | ||
171 | struct dma_async_tx_descriptor *desc; | ||
172 | dma_cookie_t cookie; | ||
173 | struct scatterlist sg; | ||
174 | u32 stfifo; | ||
175 | |||
176 | dev_dbg(dev, "%s: %u@%llx\n", __func__, size, (unsigned long long)buff); | ||
177 | |||
178 | sg_init_table(&sg, 1); | ||
179 | sg_set_page(&sg, pfn_to_page(PFN_DOWN(buff)), | ||
180 | size, offset_in_page(buff)); | ||
181 | sg_dma_address(&sg) = buff; | ||
182 | |||
183 | desc = siu_stream->chan->device->device_prep_slave_sg(siu_stream->chan, | ||
184 | &sg, 1, DMA_FROM_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); | ||
185 | if (!desc) { | ||
186 | dev_err(dev, "Failed to allocate dma descriptor\n"); | ||
187 | return -ENOMEM; | ||
188 | } | ||
189 | |||
190 | desc->callback = siu_dma_tx_complete; | ||
191 | desc->callback_param = siu_stream; | ||
192 | cookie = desc->tx_submit(desc); | ||
193 | if (cookie < 0) { | ||
194 | dev_err(dev, "Failed to submit dma descriptor\n"); | ||
195 | return cookie; | ||
196 | } | ||
197 | |||
198 | siu_stream->tx_desc = desc; | ||
199 | siu_stream->cookie = cookie; | ||
200 | |||
201 | dma_async_issue_pending(siu_stream->chan); | ||
202 | |||
203 | /* only input FIFO enable */ | ||
204 | stfifo = siu_read32(base + SIU_STFIFO); | ||
205 | siu_write32(base + SIU_STFIFO, siu_read32(base + SIU_STFIFO) | | ||
206 | (port_info->stfifo & 0x13071307)); | ||
207 | dev_dbg(dev, "%s: STFIFO %x -> %x\n", __func__, | ||
208 | stfifo, stfifo | (port_info->stfifo & 0x13071307)); | ||
209 | |||
210 | return 0; | ||
211 | } | ||
212 | |||
213 | static void siu_io_tasklet(unsigned long data) | ||
214 | { | ||
215 | struct siu_stream *siu_stream = (struct siu_stream *)data; | ||
216 | struct snd_pcm_substream *substream = siu_stream->substream; | ||
217 | struct device *dev = substream->pcm->card->dev; | ||
218 | struct snd_pcm_runtime *rt = substream->runtime; | ||
219 | struct siu_port *port_info = siu_port_info(substream); | ||
220 | |||
221 | dev_dbg(dev, "%s: flags %x\n", __func__, siu_stream->rw_flg); | ||
222 | |||
223 | if (!siu_stream->rw_flg) { | ||
224 | dev_dbg(dev, "%s: stream inactive\n", __func__); | ||
225 | return; | ||
226 | } | ||
227 | |||
228 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { | ||
229 | dma_addr_t buff; | ||
230 | size_t count; | ||
231 | u8 *virt; | ||
232 | |||
233 | buff = (dma_addr_t)PERIOD_OFFSET(rt->dma_addr, | ||
234 | siu_stream->cur_period, | ||
235 | siu_stream->period_bytes); | ||
236 | virt = PERIOD_OFFSET(rt->dma_area, | ||
237 | siu_stream->cur_period, | ||
238 | siu_stream->period_bytes); | ||
239 | count = siu_stream->period_bytes; | ||
240 | |||
241 | /* DMA transfer start */ | ||
242 | siu_pcm_rd_set(port_info, buff, count); | ||
243 | } else { | ||
244 | siu_pcm_wr_set(port_info, | ||
245 | (dma_addr_t)PERIOD_OFFSET(rt->dma_addr, | ||
246 | siu_stream->cur_period, | ||
247 | siu_stream->period_bytes), | ||
248 | siu_stream->period_bytes); | ||
249 | } | ||
250 | } | ||
251 | |||
252 | /* Capture */ | ||
253 | static int siu_pcm_stmread_start(struct siu_port *port_info) | ||
254 | { | ||
255 | struct siu_stream *siu_stream = &port_info->capture; | ||
256 | |||
257 | if (siu_stream->xfer_cnt > 0x1000000) | ||
258 | return -EINVAL; | ||
259 | if (siu_stream->rw_flg) | ||
260 | return -EPERM; | ||
261 | |||
262 | /* Current period in buffer */ | ||
263 | siu_stream->cur_period = 0; | ||
264 | |||
265 | /* during stmread flag set */ | ||
266 | siu_stream->rw_flg = RWF_STM_RD; | ||
267 | |||
268 | tasklet_schedule(&siu_stream->tasklet); | ||
269 | |||
270 | return 0; | ||
271 | } | ||
272 | |||
273 | static int siu_pcm_stmread_stop(struct siu_port *port_info) | ||
274 | { | ||
275 | struct siu_info *info = siu_i2s_dai.private_data; | ||
276 | u32 __iomem *base = info->reg; | ||
277 | struct siu_stream *siu_stream = &port_info->capture; | ||
278 | struct device *dev = siu_stream->substream->pcm->card->dev; | ||
279 | u32 stfifo; | ||
280 | |||
281 | if (!siu_stream->rw_flg) | ||
282 | return -EPERM; | ||
283 | |||
284 | /* input FIFO disable */ | ||
285 | stfifo = siu_read32(base + SIU_STFIFO); | ||
286 | siu_write32(base + SIU_STFIFO, stfifo & ~0x13071307); | ||
287 | dev_dbg(dev, "%s: STFIFO %x -> %x\n", __func__, | ||
288 | stfifo, stfifo & ~0x13071307); | ||
289 | |||
290 | /* during stmread flag clear */ | ||
291 | siu_stream->rw_flg = 0; | ||
292 | |||
293 | return 0; | ||
294 | } | ||
295 | |||
296 | static int siu_pcm_hw_params(struct snd_pcm_substream *ss, | ||
297 | struct snd_pcm_hw_params *hw_params) | ||
298 | { | ||
299 | struct siu_info *info = siu_i2s_dai.private_data; | ||
300 | struct device *dev = ss->pcm->card->dev; | ||
301 | int ret; | ||
302 | |||
303 | dev_dbg(dev, "%s: port=%d\n", __func__, info->port_id); | ||
304 | |||
305 | ret = snd_pcm_lib_malloc_pages(ss, params_buffer_bytes(hw_params)); | ||
306 | if (ret < 0) | ||
307 | dev_err(dev, "snd_pcm_lib_malloc_pages() failed\n"); | ||
308 | |||
309 | return ret; | ||
310 | } | ||
311 | |||
312 | static int siu_pcm_hw_free(struct snd_pcm_substream *ss) | ||
313 | { | ||
314 | struct siu_info *info = siu_i2s_dai.private_data; | ||
315 | struct siu_port *port_info = siu_port_info(ss); | ||
316 | struct device *dev = ss->pcm->card->dev; | ||
317 | struct siu_stream *siu_stream; | ||
318 | |||
319 | if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
320 | siu_stream = &port_info->playback; | ||
321 | else | ||
322 | siu_stream = &port_info->capture; | ||
323 | |||
324 | dev_dbg(dev, "%s: port=%d\n", __func__, info->port_id); | ||
325 | |||
326 | return snd_pcm_lib_free_pages(ss); | ||
327 | } | ||
328 | |||
329 | static bool filter(struct dma_chan *chan, void *slave) | ||
330 | { | ||
331 | struct sh_dmae_slave *param = slave; | ||
332 | |||
333 | pr_debug("%s: slave ID %d\n", __func__, param->slave_id); | ||
334 | |||
335 | if (unlikely(param->dma_dev != chan->device->dev)) | ||
336 | return false; | ||
337 | |||
338 | chan->private = param; | ||
339 | return true; | ||
340 | } | ||
341 | |||
342 | static int siu_pcm_open(struct snd_pcm_substream *ss) | ||
343 | { | ||
344 | /* Playback / Capture */ | ||
345 | struct siu_info *info = siu_i2s_dai.private_data; | ||
346 | struct siu_port *port_info = siu_port_info(ss); | ||
347 | struct siu_stream *siu_stream; | ||
348 | u32 port = info->port_id; | ||
349 | struct siu_platform *pdata = siu_i2s_dai.dev->platform_data; | ||
350 | struct device *dev = ss->pcm->card->dev; | ||
351 | dma_cap_mask_t mask; | ||
352 | struct sh_dmae_slave *param; | ||
353 | |||
354 | dma_cap_zero(mask); | ||
355 | dma_cap_set(DMA_SLAVE, mask); | ||
356 | |||
357 | dev_dbg(dev, "%s, port=%d@%p\n", __func__, port, port_info); | ||
358 | |||
359 | if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
360 | siu_stream = &port_info->playback; | ||
361 | param = &siu_stream->param; | ||
362 | param->slave_id = port ? SHDMA_SLAVE_SIUB_TX : | ||
363 | SHDMA_SLAVE_SIUA_TX; | ||
364 | } else { | ||
365 | siu_stream = &port_info->capture; | ||
366 | param = &siu_stream->param; | ||
367 | param->slave_id = port ? SHDMA_SLAVE_SIUB_RX : | ||
368 | SHDMA_SLAVE_SIUA_RX; | ||
369 | } | ||
370 | |||
371 | param->dma_dev = pdata->dma_dev; | ||
372 | /* Get DMA channel */ | ||
373 | siu_stream->chan = dma_request_channel(mask, filter, param); | ||
374 | if (!siu_stream->chan) { | ||
375 | dev_err(dev, "DMA channel allocation failed!\n"); | ||
376 | return -EBUSY; | ||
377 | } | ||
378 | |||
379 | siu_stream->substream = ss; | ||
380 | |||
381 | return 0; | ||
382 | } | ||
383 | |||
384 | static int siu_pcm_close(struct snd_pcm_substream *ss) | ||
385 | { | ||
386 | struct siu_info *info = siu_i2s_dai.private_data; | ||
387 | struct device *dev = ss->pcm->card->dev; | ||
388 | struct siu_port *port_info = siu_port_info(ss); | ||
389 | struct siu_stream *siu_stream; | ||
390 | |||
391 | dev_dbg(dev, "%s: port=%d\n", __func__, info->port_id); | ||
392 | |||
393 | if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
394 | siu_stream = &port_info->playback; | ||
395 | else | ||
396 | siu_stream = &port_info->capture; | ||
397 | |||
398 | dma_release_channel(siu_stream->chan); | ||
399 | siu_stream->chan = NULL; | ||
400 | |||
401 | siu_stream->substream = NULL; | ||
402 | |||
403 | return 0; | ||
404 | } | ||
405 | |||
406 | static int siu_pcm_prepare(struct snd_pcm_substream *ss) | ||
407 | { | ||
408 | struct siu_info *info = siu_i2s_dai.private_data; | ||
409 | struct siu_port *port_info = siu_port_info(ss); | ||
410 | struct device *dev = ss->pcm->card->dev; | ||
411 | struct snd_pcm_runtime *rt = ss->runtime; | ||
412 | struct siu_stream *siu_stream; | ||
413 | snd_pcm_sframes_t xfer_cnt; | ||
414 | |||
415 | if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
416 | siu_stream = &port_info->playback; | ||
417 | else | ||
418 | siu_stream = &port_info->capture; | ||
419 | |||
420 | rt = siu_stream->substream->runtime; | ||
421 | |||
422 | siu_stream->buf_bytes = snd_pcm_lib_buffer_bytes(ss); | ||
423 | siu_stream->period_bytes = snd_pcm_lib_period_bytes(ss); | ||
424 | |||
425 | dev_dbg(dev, "%s: port=%d, %d channels, period=%u bytes\n", __func__, | ||
426 | info->port_id, rt->channels, siu_stream->period_bytes); | ||
427 | |||
428 | /* We only support buffers that are multiples of the period */ | ||
429 | if (siu_stream->buf_bytes % siu_stream->period_bytes) { | ||
430 | dev_err(dev, "%s() - buffer=%d not multiple of period=%d\n", | ||
431 | __func__, siu_stream->buf_bytes, | ||
432 | siu_stream->period_bytes); | ||
433 | return -EINVAL; | ||
434 | } | ||
435 | |||
436 | xfer_cnt = bytes_to_frames(rt, siu_stream->period_bytes); | ||
437 | if (!xfer_cnt || xfer_cnt > 0x1000000) | ||
438 | return -EINVAL; | ||
439 | |||
440 | siu_stream->format = rt->format; | ||
441 | siu_stream->xfer_cnt = xfer_cnt; | ||
442 | |||
443 | dev_dbg(dev, "port=%d buf=%lx buf_bytes=%d period_bytes=%d " | ||
444 | "format=%d channels=%d xfer_cnt=%d\n", info->port_id, | ||
445 | (unsigned long)rt->dma_addr, siu_stream->buf_bytes, | ||
446 | siu_stream->period_bytes, | ||
447 | siu_stream->format, rt->channels, (int)xfer_cnt); | ||
448 | |||
449 | return 0; | ||
450 | } | ||
451 | |||
452 | static int siu_pcm_trigger(struct snd_pcm_substream *ss, int cmd) | ||
453 | { | ||
454 | struct siu_info *info = siu_i2s_dai.private_data; | ||
455 | struct device *dev = ss->pcm->card->dev; | ||
456 | struct siu_port *port_info = siu_port_info(ss); | ||
457 | int ret; | ||
458 | |||
459 | dev_dbg(dev, "%s: port=%d@%p, cmd=%d\n", __func__, | ||
460 | info->port_id, port_info, cmd); | ||
461 | |||
462 | switch (cmd) { | ||
463 | case SNDRV_PCM_TRIGGER_START: | ||
464 | if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
465 | ret = siu_pcm_stmwrite_start(port_info); | ||
466 | else | ||
467 | ret = siu_pcm_stmread_start(port_info); | ||
468 | |||
469 | if (ret < 0) | ||
470 | dev_warn(dev, "%s: start failed on port=%d\n", | ||
471 | __func__, info->port_id); | ||
472 | |||
473 | break; | ||
474 | case SNDRV_PCM_TRIGGER_STOP: | ||
475 | if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
476 | siu_pcm_stmwrite_stop(port_info); | ||
477 | else | ||
478 | siu_pcm_stmread_stop(port_info); | ||
479 | ret = 0; | ||
480 | |||
481 | break; | ||
482 | default: | ||
483 | dev_err(dev, "%s() unsupported cmd=%d\n", __func__, cmd); | ||
484 | ret = -EINVAL; | ||
485 | } | ||
486 | |||
487 | return ret; | ||
488 | } | ||
489 | |||
490 | /* | ||
491 | * So far only resolution of one period is supported, subject to extending the | ||
492 | * dmangine API | ||
493 | */ | ||
494 | static snd_pcm_uframes_t siu_pcm_pointer_dma(struct snd_pcm_substream *ss) | ||
495 | { | ||
496 | struct device *dev = ss->pcm->card->dev; | ||
497 | struct siu_info *info = siu_i2s_dai.private_data; | ||
498 | u32 __iomem *base = info->reg; | ||
499 | struct siu_port *port_info = siu_port_info(ss); | ||
500 | struct snd_pcm_runtime *rt = ss->runtime; | ||
501 | size_t ptr; | ||
502 | struct siu_stream *siu_stream; | ||
503 | |||
504 | if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
505 | siu_stream = &port_info->playback; | ||
506 | else | ||
507 | siu_stream = &port_info->capture; | ||
508 | |||
509 | /* | ||
510 | * ptr is the offset into the buffer where the dma is currently at. We | ||
511 | * check if the dma buffer has just wrapped. | ||
512 | */ | ||
513 | ptr = PERIOD_OFFSET(rt->dma_addr, | ||
514 | siu_stream->cur_period, | ||
515 | siu_stream->period_bytes) - rt->dma_addr; | ||
516 | |||
517 | dev_dbg(dev, | ||
518 | "%s: port=%d, events %x, FSTS %x, xferred %u/%u, cookie %d\n", | ||
519 | __func__, info->port_id, siu_read32(base + SIU_EVNTC), | ||
520 | siu_read32(base + SIU_SBFSTS), ptr, siu_stream->buf_bytes, | ||
521 | siu_stream->cookie); | ||
522 | |||
523 | if (ptr >= siu_stream->buf_bytes) | ||
524 | ptr = 0; | ||
525 | |||
526 | return bytes_to_frames(ss->runtime, ptr); | ||
527 | } | ||
528 | |||
529 | static int siu_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, | ||
530 | struct snd_pcm *pcm) | ||
531 | { | ||
532 | /* card->dev == socdev->dev, see snd_soc_new_pcms() */ | ||
533 | struct siu_info *info = siu_i2s_dai.private_data; | ||
534 | struct platform_device *pdev = to_platform_device(card->dev); | ||
535 | int ret; | ||
536 | int i; | ||
537 | |||
538 | /* pdev->id selects between SIUA and SIUB */ | ||
539 | if (pdev->id < 0 || pdev->id >= SIU_PORT_NUM) | ||
540 | return -EINVAL; | ||
541 | |||
542 | info->port_id = pdev->id; | ||
543 | |||
544 | /* | ||
545 | * While the siu has 2 ports, only one port can be on at a time (only 1 | ||
546 | * SPB). So far all the boards using the siu had only one of the ports | ||
547 | * wired to a codec. To simplify things, we only register one port with | ||
548 | * alsa. In case both ports are needed, it should be changed here | ||
549 | */ | ||
550 | for (i = pdev->id; i < pdev->id + 1; i++) { | ||
551 | struct siu_port **port_info = &siu_ports[i]; | ||
552 | |||
553 | ret = siu_init_port(i, port_info, card); | ||
554 | if (ret < 0) | ||
555 | return ret; | ||
556 | |||
557 | ret = snd_pcm_lib_preallocate_pages_for_all(pcm, | ||
558 | SNDRV_DMA_TYPE_DEV, NULL, | ||
559 | SIU_BUFFER_BYTES_MAX, SIU_BUFFER_BYTES_MAX); | ||
560 | if (ret < 0) { | ||
561 | dev_err(card->dev, | ||
562 | "snd_pcm_lib_preallocate_pages_for_all() err=%d", | ||
563 | ret); | ||
564 | goto fail; | ||
565 | } | ||
566 | |||
567 | (*port_info)->pcm = pcm; | ||
568 | |||
569 | /* IO tasklets */ | ||
570 | tasklet_init(&(*port_info)->playback.tasklet, siu_io_tasklet, | ||
571 | (unsigned long)&(*port_info)->playback); | ||
572 | tasklet_init(&(*port_info)->capture.tasklet, siu_io_tasklet, | ||
573 | (unsigned long)&(*port_info)->capture); | ||
574 | } | ||
575 | |||
576 | dev_info(card->dev, "SuperH SIU driver initialized.\n"); | ||
577 | return 0; | ||
578 | |||
579 | fail: | ||
580 | siu_free_port(siu_ports[pdev->id]); | ||
581 | dev_err(card->dev, "SIU: failed to initialize.\n"); | ||
582 | return ret; | ||
583 | } | ||
584 | |||
585 | static void siu_pcm_free(struct snd_pcm *pcm) | ||
586 | { | ||
587 | struct platform_device *pdev = to_platform_device(pcm->card->dev); | ||
588 | struct siu_port *port_info = siu_ports[pdev->id]; | ||
589 | |||
590 | tasklet_kill(&port_info->capture.tasklet); | ||
591 | tasklet_kill(&port_info->playback.tasklet); | ||
592 | |||
593 | siu_free_port(port_info); | ||
594 | snd_pcm_lib_preallocate_free_for_all(pcm); | ||
595 | |||
596 | dev_dbg(pcm->card->dev, "%s\n", __func__); | ||
597 | } | ||
598 | |||
599 | static struct snd_pcm_ops siu_pcm_ops = { | ||
600 | .open = siu_pcm_open, | ||
601 | .close = siu_pcm_close, | ||
602 | .ioctl = snd_pcm_lib_ioctl, | ||
603 | .hw_params = siu_pcm_hw_params, | ||
604 | .hw_free = siu_pcm_hw_free, | ||
605 | .prepare = siu_pcm_prepare, | ||
606 | .trigger = siu_pcm_trigger, | ||
607 | .pointer = siu_pcm_pointer_dma, | ||
608 | }; | ||
609 | |||
610 | struct snd_soc_platform siu_platform = { | ||
611 | .name = "siu-audio", | ||
612 | .pcm_ops = &siu_pcm_ops, | ||
613 | .pcm_new = siu_pcm_new, | ||
614 | .pcm_free = siu_pcm_free, | ||
615 | }; | ||
616 | EXPORT_SYMBOL_GPL(siu_platform); | ||
diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c index d2505e8b06c9..5869dc3be781 100644 --- a/sound/soc/soc-cache.c +++ b/sound/soc/soc-cache.c | |||
@@ -15,6 +15,74 @@ | |||
15 | #include <linux/spi/spi.h> | 15 | #include <linux/spi/spi.h> |
16 | #include <sound/soc.h> | 16 | #include <sound/soc.h> |
17 | 17 | ||
18 | static unsigned int snd_soc_4_12_read(struct snd_soc_codec *codec, | ||
19 | unsigned int reg) | ||
20 | { | ||
21 | u16 *cache = codec->reg_cache; | ||
22 | if (reg >= codec->reg_cache_size) | ||
23 | return -1; | ||
24 | return cache[reg]; | ||
25 | } | ||
26 | |||
27 | static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg, | ||
28 | unsigned int value) | ||
29 | { | ||
30 | u16 *cache = codec->reg_cache; | ||
31 | u8 data[2]; | ||
32 | int ret; | ||
33 | |||
34 | BUG_ON(codec->volatile_register); | ||
35 | |||
36 | data[0] = (reg << 4) | ((value >> 8) & 0x000f); | ||
37 | data[1] = value & 0x00ff; | ||
38 | |||
39 | if (reg < codec->reg_cache_size) | ||
40 | cache[reg] = value; | ||
41 | |||
42 | if (codec->cache_only) { | ||
43 | codec->cache_sync = 1; | ||
44 | return 0; | ||
45 | } | ||
46 | |||
47 | ret = codec->hw_write(codec->control_data, data, 2); | ||
48 | if (ret == 2) | ||
49 | return 0; | ||
50 | if (ret < 0) | ||
51 | return ret; | ||
52 | else | ||
53 | return -EIO; | ||
54 | } | ||
55 | |||
56 | #if defined(CONFIG_SPI_MASTER) | ||
57 | static int snd_soc_4_12_spi_write(void *control_data, const char *data, | ||
58 | int len) | ||
59 | { | ||
60 | struct spi_device *spi = control_data; | ||
61 | struct spi_transfer t; | ||
62 | struct spi_message m; | ||
63 | u8 msg[2]; | ||
64 | |||
65 | if (len <= 0) | ||
66 | return 0; | ||
67 | |||
68 | msg[0] = data[1]; | ||
69 | msg[1] = data[0]; | ||
70 | |||
71 | spi_message_init(&m); | ||
72 | memset(&t, 0, (sizeof t)); | ||
73 | |||
74 | t.tx_buf = &msg[0]; | ||
75 | t.len = len; | ||
76 | |||
77 | spi_message_add_tail(&t, &m); | ||
78 | spi_sync(spi, &m); | ||
79 | |||
80 | return len; | ||
81 | } | ||
82 | #else | ||
83 | #define snd_soc_4_12_spi_write NULL | ||
84 | #endif | ||
85 | |||
18 | static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec, | 86 | static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec, |
19 | unsigned int reg) | 87 | unsigned int reg) |
20 | { | 88 | { |
@@ -38,6 +106,12 @@ static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg, | |||
38 | 106 | ||
39 | if (reg < codec->reg_cache_size) | 107 | if (reg < codec->reg_cache_size) |
40 | cache[reg] = value; | 108 | cache[reg] = value; |
109 | |||
110 | if (codec->cache_only) { | ||
111 | codec->cache_sync = 1; | ||
112 | return 0; | ||
113 | } | ||
114 | |||
41 | ret = codec->hw_write(codec->control_data, data, 2); | 115 | ret = codec->hw_write(codec->control_data, data, 2); |
42 | if (ret == 2) | 116 | if (ret == 2) |
43 | return 0; | 117 | return 0; |
@@ -91,6 +165,11 @@ static int snd_soc_8_8_write(struct snd_soc_codec *codec, unsigned int reg, | |||
91 | if (reg < codec->reg_cache_size) | 165 | if (reg < codec->reg_cache_size) |
92 | cache[reg] = value; | 166 | cache[reg] = value; |
93 | 167 | ||
168 | if (codec->cache_only) { | ||
169 | codec->cache_sync = 1; | ||
170 | return 0; | ||
171 | } | ||
172 | |||
94 | if (codec->hw_write(codec->control_data, data, 2) == 2) | 173 | if (codec->hw_write(codec->control_data, data, 2) == 2) |
95 | return 0; | 174 | return 0; |
96 | else | 175 | else |
@@ -119,6 +198,11 @@ static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg, | |||
119 | if (!snd_soc_codec_volatile_register(codec, reg)) | 198 | if (!snd_soc_codec_volatile_register(codec, reg)) |
120 | reg_cache[reg] = value; | 199 | reg_cache[reg] = value; |
121 | 200 | ||
201 | if (codec->cache_only) { | ||
202 | codec->cache_sync = 1; | ||
203 | return 0; | ||
204 | } | ||
205 | |||
122 | if (codec->hw_write(codec->control_data, data, 3) == 3) | 206 | if (codec->hw_write(codec->control_data, data, 3) == 3) |
123 | return 0; | 207 | return 0; |
124 | else | 208 | else |
@@ -131,10 +215,14 @@ static unsigned int snd_soc_8_16_read(struct snd_soc_codec *codec, | |||
131 | u16 *cache = codec->reg_cache; | 215 | u16 *cache = codec->reg_cache; |
132 | 216 | ||
133 | if (reg >= codec->reg_cache_size || | 217 | if (reg >= codec->reg_cache_size || |
134 | snd_soc_codec_volatile_register(codec, reg)) | 218 | snd_soc_codec_volatile_register(codec, reg)) { |
219 | if (codec->cache_only) | ||
220 | return -EINVAL; | ||
221 | |||
135 | return codec->hw_read(codec, reg); | 222 | return codec->hw_read(codec, reg); |
136 | else | 223 | } else { |
137 | return cache[reg]; | 224 | return cache[reg]; |
225 | } | ||
138 | } | 226 | } |
139 | 227 | ||
140 | #if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) | 228 | #if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) |
@@ -171,6 +259,114 @@ static unsigned int snd_soc_8_16_read_i2c(struct snd_soc_codec *codec, | |||
171 | #define snd_soc_8_16_read_i2c NULL | 259 | #define snd_soc_8_16_read_i2c NULL |
172 | #endif | 260 | #endif |
173 | 261 | ||
262 | #if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) | ||
263 | static unsigned int snd_soc_16_8_read_i2c(struct snd_soc_codec *codec, | ||
264 | unsigned int r) | ||
265 | { | ||
266 | struct i2c_msg xfer[2]; | ||
267 | u16 reg = r; | ||
268 | u8 data; | ||
269 | int ret; | ||
270 | struct i2c_client *client = codec->control_data; | ||
271 | |||
272 | /* Write register */ | ||
273 | xfer[0].addr = client->addr; | ||
274 | xfer[0].flags = 0; | ||
275 | xfer[0].len = 2; | ||
276 | xfer[0].buf = (u8 *)® | ||
277 | |||
278 | /* Read data */ | ||
279 | xfer[1].addr = client->addr; | ||
280 | xfer[1].flags = I2C_M_RD; | ||
281 | xfer[1].len = 1; | ||
282 | xfer[1].buf = &data; | ||
283 | |||
284 | ret = i2c_transfer(client->adapter, xfer, 2); | ||
285 | if (ret != 2) { | ||
286 | dev_err(&client->dev, "i2c_transfer() returned %d\n", ret); | ||
287 | return 0; | ||
288 | } | ||
289 | |||
290 | return data; | ||
291 | } | ||
292 | #else | ||
293 | #define snd_soc_16_8_read_i2c NULL | ||
294 | #endif | ||
295 | |||
296 | static unsigned int snd_soc_16_8_read(struct snd_soc_codec *codec, | ||
297 | unsigned int reg) | ||
298 | { | ||
299 | u16 *cache = codec->reg_cache; | ||
300 | |||
301 | reg &= 0xff; | ||
302 | if (reg >= codec->reg_cache_size) | ||
303 | return -1; | ||
304 | return cache[reg]; | ||
305 | } | ||
306 | |||
307 | static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg, | ||
308 | unsigned int value) | ||
309 | { | ||
310 | u16 *cache = codec->reg_cache; | ||
311 | u8 data[3]; | ||
312 | int ret; | ||
313 | |||
314 | BUG_ON(codec->volatile_register); | ||
315 | |||
316 | data[0] = (reg >> 8) & 0xff; | ||
317 | data[1] = reg & 0xff; | ||
318 | data[2] = value; | ||
319 | |||
320 | reg &= 0xff; | ||
321 | if (reg < codec->reg_cache_size) | ||
322 | cache[reg] = value; | ||
323 | |||
324 | if (codec->cache_only) { | ||
325 | codec->cache_sync = 1; | ||
326 | return 0; | ||
327 | } | ||
328 | |||
329 | ret = codec->hw_write(codec->control_data, data, 3); | ||
330 | if (ret == 3) | ||
331 | return 0; | ||
332 | if (ret < 0) | ||
333 | return ret; | ||
334 | else | ||
335 | return -EIO; | ||
336 | } | ||
337 | |||
338 | #if defined(CONFIG_SPI_MASTER) | ||
339 | static int snd_soc_16_8_spi_write(void *control_data, const char *data, | ||
340 | int len) | ||
341 | { | ||
342 | struct spi_device *spi = control_data; | ||
343 | struct spi_transfer t; | ||
344 | struct spi_message m; | ||
345 | u8 msg[3]; | ||
346 | |||
347 | if (len <= 0) | ||
348 | return 0; | ||
349 | |||
350 | msg[0] = data[0]; | ||
351 | msg[1] = data[1]; | ||
352 | msg[2] = data[2]; | ||
353 | |||
354 | spi_message_init(&m); | ||
355 | memset(&t, 0, (sizeof t)); | ||
356 | |||
357 | t.tx_buf = &msg[0]; | ||
358 | t.len = len; | ||
359 | |||
360 | spi_message_add_tail(&t, &m); | ||
361 | spi_sync(spi, &m); | ||
362 | |||
363 | return len; | ||
364 | } | ||
365 | #else | ||
366 | #define snd_soc_16_8_spi_write NULL | ||
367 | #endif | ||
368 | |||
369 | |||
174 | static struct { | 370 | static struct { |
175 | int addr_bits; | 371 | int addr_bits; |
176 | int data_bits; | 372 | int data_bits; |
@@ -180,9 +376,14 @@ static struct { | |||
180 | unsigned int (*i2c_read)(struct snd_soc_codec *, unsigned int); | 376 | unsigned int (*i2c_read)(struct snd_soc_codec *, unsigned int); |
181 | } io_types[] = { | 377 | } io_types[] = { |
182 | { | 378 | { |
379 | .addr_bits = 4, .data_bits = 12, | ||
380 | .write = snd_soc_4_12_write, .read = snd_soc_4_12_read, | ||
381 | .spi_write = snd_soc_4_12_spi_write, | ||
382 | }, | ||
383 | { | ||
183 | .addr_bits = 7, .data_bits = 9, | 384 | .addr_bits = 7, .data_bits = 9, |
184 | .write = snd_soc_7_9_write, .read = snd_soc_7_9_read, | 385 | .write = snd_soc_7_9_write, .read = snd_soc_7_9_read, |
185 | .spi_write = snd_soc_7_9_spi_write | 386 | .spi_write = snd_soc_7_9_spi_write, |
186 | }, | 387 | }, |
187 | { | 388 | { |
188 | .addr_bits = 8, .data_bits = 8, | 389 | .addr_bits = 8, .data_bits = 8, |
@@ -193,6 +394,12 @@ static struct { | |||
193 | .write = snd_soc_8_16_write, .read = snd_soc_8_16_read, | 394 | .write = snd_soc_8_16_write, .read = snd_soc_8_16_read, |
194 | .i2c_read = snd_soc_8_16_read_i2c, | 395 | .i2c_read = snd_soc_8_16_read_i2c, |
195 | }, | 396 | }, |
397 | { | ||
398 | .addr_bits = 16, .data_bits = 8, | ||
399 | .write = snd_soc_16_8_write, .read = snd_soc_16_8_read, | ||
400 | .i2c_read = snd_soc_16_8_read_i2c, | ||
401 | .spi_write = snd_soc_16_8_spi_write, | ||
402 | }, | ||
196 | }; | 403 | }; |
197 | 404 | ||
198 | /** | 405 | /** |
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 0a6440c6f54a..a03bac943aaf 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c | |||
@@ -130,6 +130,29 @@ static ssize_t codec_reg_show(struct device *dev, | |||
130 | 130 | ||
131 | static DEVICE_ATTR(codec_reg, 0444, codec_reg_show, NULL); | 131 | static DEVICE_ATTR(codec_reg, 0444, codec_reg_show, NULL); |
132 | 132 | ||
133 | static ssize_t pmdown_time_show(struct device *dev, | ||
134 | struct device_attribute *attr, char *buf) | ||
135 | { | ||
136 | struct snd_soc_device *socdev = dev_get_drvdata(dev); | ||
137 | struct snd_soc_card *card = socdev->card; | ||
138 | |||
139 | return sprintf(buf, "%ld\n", card->pmdown_time); | ||
140 | } | ||
141 | |||
142 | static ssize_t pmdown_time_set(struct device *dev, | ||
143 | struct device_attribute *attr, | ||
144 | const char *buf, size_t count) | ||
145 | { | ||
146 | struct snd_soc_device *socdev = dev_get_drvdata(dev); | ||
147 | struct snd_soc_card *card = socdev->card; | ||
148 | |||
149 | strict_strtol(buf, 10, &card->pmdown_time); | ||
150 | |||
151 | return count; | ||
152 | } | ||
153 | |||
154 | static DEVICE_ATTR(pmdown_time, 0644, pmdown_time_show, pmdown_time_set); | ||
155 | |||
133 | #ifdef CONFIG_DEBUG_FS | 156 | #ifdef CONFIG_DEBUG_FS |
134 | static int codec_reg_open_file(struct inode *inode, struct file *file) | 157 | static int codec_reg_open_file(struct inode *inode, struct file *file) |
135 | { | 158 | { |
@@ -542,7 +565,7 @@ static int soc_codec_close(struct snd_pcm_substream *substream) | |||
542 | /* start delayed pop wq here for playback streams */ | 565 | /* start delayed pop wq here for playback streams */ |
543 | codec_dai->pop_wait = 1; | 566 | codec_dai->pop_wait = 1; |
544 | schedule_delayed_work(&card->delayed_work, | 567 | schedule_delayed_work(&card->delayed_work, |
545 | msecs_to_jiffies(pmdown_time)); | 568 | msecs_to_jiffies(card->pmdown_time)); |
546 | } else { | 569 | } else { |
547 | /* capture streams can be powered down now */ | 570 | /* capture streams can be powered down now */ |
548 | snd_soc_dapm_stream_event(codec, | 571 | snd_soc_dapm_stream_event(codec, |
@@ -940,6 +963,12 @@ static int soc_resume(struct device *dev) | |||
940 | struct snd_soc_card *card = socdev->card; | 963 | struct snd_soc_card *card = socdev->card; |
941 | struct snd_soc_dai *cpu_dai = card->dai_link[0].cpu_dai; | 964 | struct snd_soc_dai *cpu_dai = card->dai_link[0].cpu_dai; |
942 | 965 | ||
966 | /* If the initialization of this soc device failed, there is no codec | ||
967 | * associated with it. Just bail out in this case. | ||
968 | */ | ||
969 | if (!card->codec) | ||
970 | return 0; | ||
971 | |||
943 | /* AC97 devices might have other drivers hanging off them so | 972 | /* AC97 devices might have other drivers hanging off them so |
944 | * need to resume immediately. Other drivers don't have that | 973 | * need to resume immediately. Other drivers don't have that |
945 | * problem and may take a substantial amount of time to resume | 974 | * problem and may take a substantial amount of time to resume |
@@ -1039,6 +1068,8 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card) | |||
1039 | dev_dbg(card->dev, "All components present, instantiating\n"); | 1068 | dev_dbg(card->dev, "All components present, instantiating\n"); |
1040 | 1069 | ||
1041 | /* Found everything, bring it up */ | 1070 | /* Found everything, bring it up */ |
1071 | card->pmdown_time = pmdown_time; | ||
1072 | |||
1042 | if (card->probe) { | 1073 | if (card->probe) { |
1043 | ret = card->probe(pdev); | 1074 | ret = card->probe(pdev); |
1044 | if (ret < 0) | 1075 | if (ret < 0) |
@@ -1122,6 +1153,10 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card) | |||
1122 | if (ret < 0) | 1153 | if (ret < 0) |
1123 | printk(KERN_WARNING "asoc: failed to add dapm sysfs entries\n"); | 1154 | printk(KERN_WARNING "asoc: failed to add dapm sysfs entries\n"); |
1124 | 1155 | ||
1156 | ret = device_create_file(card->socdev->dev, &dev_attr_pmdown_time); | ||
1157 | if (ret < 0) | ||
1158 | printk(KERN_WARNING "asoc: failed to add pmdown_time sysfs\n"); | ||
1159 | |||
1125 | ret = device_create_file(card->socdev->dev, &dev_attr_codec_reg); | 1160 | ret = device_create_file(card->socdev->dev, &dev_attr_codec_reg); |
1126 | if (ret < 0) | 1161 | if (ret < 0) |
1127 | printk(KERN_WARNING "asoc: failed to add codec sysfs files\n"); | 1162 | printk(KERN_WARNING "asoc: failed to add codec sysfs files\n"); |
@@ -1276,8 +1311,8 @@ static int soc_new_pcm(struct snd_soc_device *socdev, | |||
1276 | codec_dai->codec = card->codec; | 1311 | codec_dai->codec = card->codec; |
1277 | 1312 | ||
1278 | /* check client and interface hw capabilities */ | 1313 | /* check client and interface hw capabilities */ |
1279 | sprintf(new_name, "%s %s-%d", dai_link->stream_name, codec_dai->name, | 1314 | snprintf(new_name, sizeof(new_name), "%s %s-%d", |
1280 | num); | 1315 | dai_link->stream_name, codec_dai->name, num); |
1281 | 1316 | ||
1282 | if (codec_dai->playback.channels_min) | 1317 | if (codec_dai->playback.channels_min) |
1283 | playback = 1; | 1318 | playback = 1; |
@@ -1368,6 +1403,7 @@ int snd_soc_new_ac97_codec(struct snd_soc_codec *codec, | |||
1368 | 1403 | ||
1369 | codec->ac97->bus->ops = ops; | 1404 | codec->ac97->bus->ops = ops; |
1370 | codec->ac97->num = num; | 1405 | codec->ac97->num = num; |
1406 | codec->dev = &codec->ac97->dev; | ||
1371 | mutex_unlock(&codec->mutex); | 1407 | mutex_unlock(&codec->mutex); |
1372 | return 0; | 1408 | return 0; |
1373 | } | 1409 | } |
@@ -1427,9 +1463,9 @@ EXPORT_SYMBOL_GPL(snd_soc_update_bits); | |||
1427 | * | 1463 | * |
1428 | * Returns 1 for change else 0. | 1464 | * Returns 1 for change else 0. |
1429 | */ | 1465 | */ |
1430 | static int snd_soc_update_bits_locked(struct snd_soc_codec *codec, | 1466 | int snd_soc_update_bits_locked(struct snd_soc_codec *codec, |
1431 | unsigned short reg, unsigned int mask, | 1467 | unsigned short reg, unsigned int mask, |
1432 | unsigned int value) | 1468 | unsigned int value) |
1433 | { | 1469 | { |
1434 | int change; | 1470 | int change; |
1435 | 1471 | ||
@@ -1439,6 +1475,7 @@ static int snd_soc_update_bits_locked(struct snd_soc_codec *codec, | |||
1439 | 1475 | ||
1440 | return change; | 1476 | return change; |
1441 | } | 1477 | } |
1478 | EXPORT_SYMBOL_GPL(snd_soc_update_bits_locked); | ||
1442 | 1479 | ||
1443 | /** | 1480 | /** |
1444 | * snd_soc_test_bits - test register for change | 1481 | * snd_soc_test_bits - test register for change |
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 0d294ef72590..6c3351095786 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c | |||
@@ -44,13 +44,6 @@ | |||
44 | #include <sound/soc-dapm.h> | 44 | #include <sound/soc-dapm.h> |
45 | #include <sound/initval.h> | 45 | #include <sound/initval.h> |
46 | 46 | ||
47 | /* debug */ | ||
48 | #ifdef DEBUG | ||
49 | #define dump_dapm(codec, action) dbg_dump_dapm(codec, action) | ||
50 | #else | ||
51 | #define dump_dapm(codec, action) | ||
52 | #endif | ||
53 | |||
54 | /* dapm power sequences - make this per codec in the future */ | 47 | /* dapm power sequences - make this per codec in the future */ |
55 | static int dapm_up_seq[] = { | 48 | static int dapm_up_seq[] = { |
56 | [snd_soc_dapm_pre] = 0, | 49 | [snd_soc_dapm_pre] = 0, |
@@ -739,6 +732,8 @@ static int dapm_seq_compare(struct snd_soc_dapm_widget *a, | |||
739 | struct snd_soc_dapm_widget *b, | 732 | struct snd_soc_dapm_widget *b, |
740 | int sort[]) | 733 | int sort[]) |
741 | { | 734 | { |
735 | if (a->codec != b->codec) | ||
736 | return (unsigned long)a - (unsigned long)b; | ||
742 | if (sort[a->id] != sort[b->id]) | 737 | if (sort[a->id] != sort[b->id]) |
743 | return sort[a->id] - sort[b->id]; | 738 | return sort[a->id] - sort[b->id]; |
744 | if (a->reg != b->reg) | 739 | if (a->reg != b->reg) |
@@ -1017,13 +1012,28 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event) | |||
1017 | sys_power = 0; | 1012 | sys_power = 0; |
1018 | break; | 1013 | break; |
1019 | case SND_SOC_DAPM_STREAM_NOP: | 1014 | case SND_SOC_DAPM_STREAM_NOP: |
1020 | sys_power = codec->bias_level != SND_SOC_BIAS_STANDBY; | 1015 | switch (codec->bias_level) { |
1016 | case SND_SOC_BIAS_STANDBY: | ||
1017 | case SND_SOC_BIAS_OFF: | ||
1018 | sys_power = 0; | ||
1019 | break; | ||
1020 | default: | ||
1021 | sys_power = 1; | ||
1022 | break; | ||
1023 | } | ||
1021 | break; | 1024 | break; |
1022 | default: | 1025 | default: |
1023 | break; | 1026 | break; |
1024 | } | 1027 | } |
1025 | } | 1028 | } |
1026 | 1029 | ||
1030 | if (sys_power && codec->bias_level == SND_SOC_BIAS_OFF) { | ||
1031 | ret = snd_soc_dapm_set_bias_level(socdev, | ||
1032 | SND_SOC_BIAS_STANDBY); | ||
1033 | if (ret != 0) | ||
1034 | pr_err("Failed to turn on bias: %d\n", ret); | ||
1035 | } | ||
1036 | |||
1027 | /* If we're changing to all on or all off then prepare */ | 1037 | /* If we're changing to all on or all off then prepare */ |
1028 | if ((sys_power && codec->bias_level == SND_SOC_BIAS_STANDBY) || | 1038 | if ((sys_power && codec->bias_level == SND_SOC_BIAS_STANDBY) || |
1029 | (!sys_power && codec->bias_level == SND_SOC_BIAS_ON)) { | 1039 | (!sys_power && codec->bias_level == SND_SOC_BIAS_ON)) { |
@@ -1047,6 +1057,14 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event) | |||
1047 | pr_err("Failed to apply standby bias: %d\n", ret); | 1057 | pr_err("Failed to apply standby bias: %d\n", ret); |
1048 | } | 1058 | } |
1049 | 1059 | ||
1060 | /* If we're in standby and can support bias off then do that */ | ||
1061 | if (codec->bias_level == SND_SOC_BIAS_STANDBY && | ||
1062 | codec->idle_bias_off) { | ||
1063 | ret = snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_OFF); | ||
1064 | if (ret != 0) | ||
1065 | pr_err("Failed to turn off bias: %d\n", ret); | ||
1066 | } | ||
1067 | |||
1050 | /* If we just powered up then move to active bias */ | 1068 | /* If we just powered up then move to active bias */ |
1051 | if (codec->bias_level == SND_SOC_BIAS_PREPARE && sys_power) { | 1069 | if (codec->bias_level == SND_SOC_BIAS_PREPARE && sys_power) { |
1052 | ret = snd_soc_dapm_set_bias_level(socdev, | 1070 | ret = snd_soc_dapm_set_bias_level(socdev, |
@@ -1061,66 +1079,6 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event) | |||
1061 | return 0; | 1079 | return 0; |
1062 | } | 1080 | } |
1063 | 1081 | ||
1064 | #ifdef DEBUG | ||
1065 | static void dbg_dump_dapm(struct snd_soc_codec* codec, const char *action) | ||
1066 | { | ||
1067 | struct snd_soc_dapm_widget *w; | ||
1068 | struct snd_soc_dapm_path *p = NULL; | ||
1069 | int in, out; | ||
1070 | |||
1071 | printk("DAPM %s %s\n", codec->name, action); | ||
1072 | |||
1073 | list_for_each_entry(w, &codec->dapm_widgets, list) { | ||
1074 | |||
1075 | /* only display widgets that effect routing */ | ||
1076 | switch (w->id) { | ||
1077 | case snd_soc_dapm_pre: | ||
1078 | case snd_soc_dapm_post: | ||
1079 | case snd_soc_dapm_vmid: | ||
1080 | continue; | ||
1081 | case snd_soc_dapm_mux: | ||
1082 | case snd_soc_dapm_value_mux: | ||
1083 | case snd_soc_dapm_output: | ||
1084 | case snd_soc_dapm_input: | ||
1085 | case snd_soc_dapm_switch: | ||
1086 | case snd_soc_dapm_hp: | ||
1087 | case snd_soc_dapm_mic: | ||
1088 | case snd_soc_dapm_spk: | ||
1089 | case snd_soc_dapm_line: | ||
1090 | case snd_soc_dapm_micbias: | ||
1091 | case snd_soc_dapm_dac: | ||
1092 | case snd_soc_dapm_adc: | ||
1093 | case snd_soc_dapm_pga: | ||
1094 | case snd_soc_dapm_mixer: | ||
1095 | case snd_soc_dapm_mixer_named_ctl: | ||
1096 | case snd_soc_dapm_supply: | ||
1097 | case snd_soc_dapm_aif_in: | ||
1098 | case snd_soc_dapm_aif_out: | ||
1099 | if (w->name) { | ||
1100 | in = is_connected_input_ep(w); | ||
1101 | dapm_clear_walk(w->codec); | ||
1102 | out = is_connected_output_ep(w); | ||
1103 | dapm_clear_walk(w->codec); | ||
1104 | printk("%s: %s in %d out %d\n", w->name, | ||
1105 | w->power ? "On":"Off",in, out); | ||
1106 | |||
1107 | list_for_each_entry(p, &w->sources, list_sink) { | ||
1108 | if (p->connect) | ||
1109 | printk(" in %s %s\n", p->name ? p->name : "static", | ||
1110 | p->source->name); | ||
1111 | } | ||
1112 | list_for_each_entry(p, &w->sinks, list_source) { | ||
1113 | if (p->connect) | ||
1114 | printk(" out %s %s\n", p->name ? p->name : "static", | ||
1115 | p->sink->name); | ||
1116 | } | ||
1117 | } | ||
1118 | break; | ||
1119 | } | ||
1120 | } | ||
1121 | } | ||
1122 | #endif | ||
1123 | |||
1124 | #ifdef CONFIG_DEBUG_FS | 1082 | #ifdef CONFIG_DEBUG_FS |
1125 | static int dapm_widget_power_open_file(struct inode *inode, struct file *file) | 1083 | static int dapm_widget_power_open_file(struct inode *inode, struct file *file) |
1126 | { | 1084 | { |
@@ -1147,9 +1105,16 @@ static ssize_t dapm_widget_power_read_file(struct file *file, | |||
1147 | out = is_connected_output_ep(w); | 1105 | out = is_connected_output_ep(w); |
1148 | dapm_clear_walk(w->codec); | 1106 | dapm_clear_walk(w->codec); |
1149 | 1107 | ||
1150 | ret = snprintf(buf, PAGE_SIZE, "%s: %s in %d out %d\n", | 1108 | ret = snprintf(buf, PAGE_SIZE, "%s: %s in %d out %d", |
1151 | w->name, w->power ? "On" : "Off", in, out); | 1109 | w->name, w->power ? "On" : "Off", in, out); |
1152 | 1110 | ||
1111 | if (w->reg >= 0) | ||
1112 | ret += snprintf(buf + ret, PAGE_SIZE - ret, | ||
1113 | " - R%d(0x%x) bit %d", | ||
1114 | w->reg, w->reg, w->shift); | ||
1115 | |||
1116 | ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n"); | ||
1117 | |||
1153 | if (w->sname) | 1118 | if (w->sname) |
1154 | ret += snprintf(buf + ret, PAGE_SIZE - ret, " stream %s %s\n", | 1119 | ret += snprintf(buf + ret, PAGE_SIZE - ret, " stream %s %s\n", |
1155 | w->sname, | 1120 | w->sname, |
@@ -1245,18 +1210,15 @@ static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, | |||
1245 | path->connect = 0; /* old connection must be powered down */ | 1210 | path->connect = 0; /* old connection must be powered down */ |
1246 | } | 1211 | } |
1247 | 1212 | ||
1248 | if (found) { | 1213 | if (found) |
1249 | dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP); | 1214 | dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP); |
1250 | dump_dapm(widget->codec, "mux power update"); | ||
1251 | } | ||
1252 | 1215 | ||
1253 | return 0; | 1216 | return 0; |
1254 | } | 1217 | } |
1255 | 1218 | ||
1256 | /* test and update the power status of a mixer or switch widget */ | 1219 | /* test and update the power status of a mixer or switch widget */ |
1257 | static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, | 1220 | static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, |
1258 | struct snd_kcontrol *kcontrol, int reg, | 1221 | struct snd_kcontrol *kcontrol, int connect) |
1259 | int val_mask, int val, int invert) | ||
1260 | { | 1222 | { |
1261 | struct snd_soc_dapm_path *path; | 1223 | struct snd_soc_dapm_path *path; |
1262 | int found = 0; | 1224 | int found = 0; |
@@ -1266,9 +1228,6 @@ static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, | |||
1266 | widget->id != snd_soc_dapm_switch) | 1228 | widget->id != snd_soc_dapm_switch) |
1267 | return -ENODEV; | 1229 | return -ENODEV; |
1268 | 1230 | ||
1269 | if (!snd_soc_test_bits(widget->codec, reg, val_mask, val)) | ||
1270 | return 0; | ||
1271 | |||
1272 | /* find dapm widget path assoc with kcontrol */ | 1231 | /* find dapm widget path assoc with kcontrol */ |
1273 | list_for_each_entry(path, &widget->codec->dapm_paths, list) { | 1232 | list_for_each_entry(path, &widget->codec->dapm_paths, list) { |
1274 | if (path->kcontrol != kcontrol) | 1233 | if (path->kcontrol != kcontrol) |
@@ -1276,19 +1235,12 @@ static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, | |||
1276 | 1235 | ||
1277 | /* found, now check type */ | 1236 | /* found, now check type */ |
1278 | found = 1; | 1237 | found = 1; |
1279 | if (val) | 1238 | path->connect = connect; |
1280 | /* new connection */ | ||
1281 | path->connect = invert ? 0:1; | ||
1282 | else | ||
1283 | /* old connection must be powered down */ | ||
1284 | path->connect = invert ? 1:0; | ||
1285 | break; | 1239 | break; |
1286 | } | 1240 | } |
1287 | 1241 | ||
1288 | if (found) { | 1242 | if (found) |
1289 | dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP); | 1243 | dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP); |
1290 | dump_dapm(widget->codec, "mixer power update"); | ||
1291 | } | ||
1292 | 1244 | ||
1293 | return 0; | 1245 | return 0; |
1294 | } | 1246 | } |
@@ -1404,9 +1356,7 @@ static int snd_soc_dapm_set_pin(struct snd_soc_codec *codec, | |||
1404 | */ | 1356 | */ |
1405 | int snd_soc_dapm_sync(struct snd_soc_codec *codec) | 1357 | int snd_soc_dapm_sync(struct snd_soc_codec *codec) |
1406 | { | 1358 | { |
1407 | int ret = dapm_power_widgets(codec, SND_SOC_DAPM_STREAM_NOP); | 1359 | return dapm_power_widgets(codec, SND_SOC_DAPM_STREAM_NOP); |
1408 | dump_dapm(codec, "sync"); | ||
1409 | return ret; | ||
1410 | } | 1360 | } |
1411 | EXPORT_SYMBOL_GPL(snd_soc_dapm_sync); | 1361 | EXPORT_SYMBOL_GPL(snd_soc_dapm_sync); |
1412 | 1362 | ||
@@ -1688,6 +1638,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, | |||
1688 | unsigned int mask = (1 << fls(max)) - 1; | 1638 | unsigned int mask = (1 << fls(max)) - 1; |
1689 | unsigned int invert = mc->invert; | 1639 | unsigned int invert = mc->invert; |
1690 | unsigned int val, val2, val_mask; | 1640 | unsigned int val, val2, val_mask; |
1641 | int connect; | ||
1691 | int ret; | 1642 | int ret; |
1692 | 1643 | ||
1693 | val = (ucontrol->value.integer.value[0] & mask); | 1644 | val = (ucontrol->value.integer.value[0] & mask); |
@@ -1714,7 +1665,17 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, | |||
1714 | return 1; | 1665 | return 1; |
1715 | } | 1666 | } |
1716 | 1667 | ||
1717 | dapm_mixer_update_power(widget, kcontrol, reg, val_mask, val, invert); | 1668 | if (snd_soc_test_bits(widget->codec, reg, val_mask, val)) { |
1669 | if (val) | ||
1670 | /* new connection */ | ||
1671 | connect = invert ? 0:1; | ||
1672 | else | ||
1673 | /* old connection must be powered down */ | ||
1674 | connect = invert ? 1:0; | ||
1675 | |||
1676 | dapm_mixer_update_power(widget, kcontrol, connect); | ||
1677 | } | ||
1678 | |||
1718 | if (widget->event) { | 1679 | if (widget->event) { |
1719 | if (widget->event_flags & SND_SOC_DAPM_PRE_REG) { | 1680 | if (widget->event_flags & SND_SOC_DAPM_PRE_REG) { |
1720 | ret = widget->event(widget, kcontrol, | 1681 | ret = widget->event(widget, kcontrol, |
@@ -2152,7 +2113,6 @@ int snd_soc_dapm_stream_event(struct snd_soc_codec *codec, | |||
2152 | 2113 | ||
2153 | dapm_power_widgets(codec, event); | 2114 | dapm_power_widgets(codec, event); |
2154 | mutex_unlock(&codec->mutex); | 2115 | mutex_unlock(&codec->mutex); |
2155 | dump_dapm(codec, __func__); | ||
2156 | return 0; | 2116 | return 0; |
2157 | } | 2117 | } |
2158 | EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_event); | 2118 | EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_event); |
diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig index 73525c048e7f..8c2925814ce4 100644 --- a/sound/usb/Kconfig +++ b/sound/usb/Kconfig | |||
@@ -21,6 +21,18 @@ config SND_USB_AUDIO | |||
21 | To compile this driver as a module, choose M here: the module | 21 | To compile this driver as a module, choose M here: the module |
22 | will be called snd-usb-audio. | 22 | will be called snd-usb-audio. |
23 | 23 | ||
24 | config SND_USB_UA101 | ||
25 | tristate "Edirol UA-101 driver (EXPERIMENTAL)" | ||
26 | depends on EXPERIMENTAL | ||
27 | select SND_PCM | ||
28 | select SND_RAWMIDI | ||
29 | help | ||
30 | Say Y here to include support for the Edirol UA-101 audio/MIDI | ||
31 | interface. | ||
32 | |||
33 | To compile this driver as a module, choose M here: the module | ||
34 | will be called snd-ua101. | ||
35 | |||
24 | config SND_USB_USX2Y | 36 | config SND_USB_USX2Y |
25 | tristate "Tascam US-122, US-224 and US-428 USB driver" | 37 | tristate "Tascam US-122, US-224 and US-428 USB driver" |
26 | depends on X86 || PPC || ALPHA | 38 | depends on X86 || PPC || ALPHA |
diff --git a/sound/usb/Makefile b/sound/usb/Makefile index abb288bfe35d..5bf64aef9558 100644 --- a/sound/usb/Makefile +++ b/sound/usb/Makefile | |||
@@ -4,9 +4,11 @@ | |||
4 | 4 | ||
5 | snd-usb-audio-objs := usbaudio.o usbmixer.o | 5 | snd-usb-audio-objs := usbaudio.o usbmixer.o |
6 | snd-usb-lib-objs := usbmidi.o | 6 | snd-usb-lib-objs := usbmidi.o |
7 | snd-ua101-objs := ua101.o | ||
7 | 8 | ||
8 | # Toplevel Module Dependency | 9 | # Toplevel Module Dependency |
9 | obj-$(CONFIG_SND_USB_AUDIO) += snd-usb-audio.o snd-usb-lib.o | 10 | obj-$(CONFIG_SND_USB_AUDIO) += snd-usb-audio.o snd-usb-lib.o |
11 | obj-$(CONFIG_SND_USB_UA101) += snd-ua101.o snd-usb-lib.o | ||
10 | obj-$(CONFIG_SND_USB_USX2Y) += snd-usb-lib.o | 12 | obj-$(CONFIG_SND_USB_USX2Y) += snd-usb-lib.o |
11 | obj-$(CONFIG_SND_USB_US122L) += snd-usb-lib.o | 13 | obj-$(CONFIG_SND_USB_US122L) += snd-usb-lib.o |
12 | 14 | ||
diff --git a/sound/usb/ua101.c b/sound/usb/ua101.c new file mode 100644 index 000000000000..4f4ccdf70dd0 --- /dev/null +++ b/sound/usb/ua101.c | |||
@@ -0,0 +1,1421 @@ | |||
1 | /* | ||
2 | * Edirol UA-101 driver | ||
3 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> | ||
4 | * | ||
5 | * This driver is free software: you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License, version 2. | ||
7 | * | ||
8 | * This driver is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this driver. If not, see <http://www.gnu.org/licenses/>. | ||
15 | */ | ||
16 | |||
17 | #include <linux/init.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/usb.h> | ||
21 | #include <linux/usb/audio.h> | ||
22 | #include <sound/core.h> | ||
23 | #include <sound/initval.h> | ||
24 | #include <sound/pcm.h> | ||
25 | #include <sound/pcm_params.h> | ||
26 | #include "usbaudio.h" | ||
27 | |||
28 | MODULE_DESCRIPTION("Edirol UA-101 driver"); | ||
29 | MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); | ||
30 | MODULE_LICENSE("GPL v2"); | ||
31 | MODULE_SUPPORTED_DEVICE("{{Edirol,UA-101}}"); | ||
32 | |||
33 | /* I use my UA-1A for testing because I don't have a UA-101 ... */ | ||
34 | #define UA1A_HACK | ||
35 | |||
36 | /* | ||
37 | * Should not be lower than the minimum scheduling delay of the host | ||
38 | * controller. Some Intel controllers need more than one frame; as long as | ||
39 | * that driver doesn't tell us about this, use 1.5 frames just to be sure. | ||
40 | */ | ||
41 | #define MIN_QUEUE_LENGTH 12 | ||
42 | /* Somewhat random. */ | ||
43 | #define MAX_QUEUE_LENGTH 30 | ||
44 | /* | ||
45 | * This magic value optimizes memory usage efficiency for the UA-101's packet | ||
46 | * sizes at all sample rates, taking into account the stupid cache pool sizes | ||
47 | * that usb_buffer_alloc() uses. | ||
48 | */ | ||
49 | #define DEFAULT_QUEUE_LENGTH 21 | ||
50 | |||
51 | #define MAX_PACKET_SIZE 672 /* hardware specific */ | ||
52 | #define MAX_MEMORY_BUFFERS DIV_ROUND_UP(MAX_QUEUE_LENGTH, \ | ||
53 | PAGE_SIZE / MAX_PACKET_SIZE) | ||
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 | static unsigned int queue_length = 21; | ||
59 | |||
60 | module_param_array(index, int, NULL, 0444); | ||
61 | MODULE_PARM_DESC(index, "card index"); | ||
62 | module_param_array(id, charp, NULL, 0444); | ||
63 | MODULE_PARM_DESC(id, "ID string"); | ||
64 | module_param_array(enable, bool, NULL, 0444); | ||
65 | MODULE_PARM_DESC(enable, "enable card"); | ||
66 | module_param(queue_length, uint, 0644); | ||
67 | MODULE_PARM_DESC(queue_length, "USB queue length in microframes, " | ||
68 | __stringify(MIN_QUEUE_LENGTH)"-"__stringify(MAX_QUEUE_LENGTH)); | ||
69 | |||
70 | enum { | ||
71 | INTF_PLAYBACK, | ||
72 | INTF_CAPTURE, | ||
73 | INTF_MIDI, | ||
74 | |||
75 | INTF_COUNT | ||
76 | }; | ||
77 | |||
78 | /* bits in struct ua101::states */ | ||
79 | enum { | ||
80 | USB_CAPTURE_RUNNING, | ||
81 | USB_PLAYBACK_RUNNING, | ||
82 | ALSA_CAPTURE_OPEN, | ||
83 | ALSA_PLAYBACK_OPEN, | ||
84 | ALSA_CAPTURE_RUNNING, | ||
85 | ALSA_PLAYBACK_RUNNING, | ||
86 | CAPTURE_URB_COMPLETED, | ||
87 | PLAYBACK_URB_COMPLETED, | ||
88 | DISCONNECTED, | ||
89 | }; | ||
90 | |||
91 | struct ua101 { | ||
92 | struct usb_device *dev; | ||
93 | struct snd_card *card; | ||
94 | struct usb_interface *intf[INTF_COUNT]; | ||
95 | int card_index; | ||
96 | struct snd_pcm *pcm; | ||
97 | struct list_head midi_list; | ||
98 | u64 format_bit; | ||
99 | unsigned int rate; | ||
100 | unsigned int packets_per_second; | ||
101 | spinlock_t lock; | ||
102 | struct mutex mutex; | ||
103 | unsigned long states; | ||
104 | |||
105 | /* FIFO to synchronize playback rate to capture rate */ | ||
106 | unsigned int rate_feedback_start; | ||
107 | unsigned int rate_feedback_count; | ||
108 | u8 rate_feedback[MAX_QUEUE_LENGTH]; | ||
109 | |||
110 | struct list_head ready_playback_urbs; | ||
111 | struct tasklet_struct playback_tasklet; | ||
112 | wait_queue_head_t alsa_capture_wait; | ||
113 | wait_queue_head_t rate_feedback_wait; | ||
114 | wait_queue_head_t alsa_playback_wait; | ||
115 | struct ua101_stream { | ||
116 | struct snd_pcm_substream *substream; | ||
117 | unsigned int usb_pipe; | ||
118 | unsigned int channels; | ||
119 | unsigned int frame_bytes; | ||
120 | unsigned int max_packet_bytes; | ||
121 | unsigned int period_pos; | ||
122 | unsigned int buffer_pos; | ||
123 | unsigned int queue_length; | ||
124 | struct ua101_urb { | ||
125 | struct urb urb; | ||
126 | struct usb_iso_packet_descriptor iso_frame_desc[1]; | ||
127 | struct list_head ready_list; | ||
128 | } *urbs[MAX_QUEUE_LENGTH]; | ||
129 | struct { | ||
130 | unsigned int size; | ||
131 | void *addr; | ||
132 | dma_addr_t dma; | ||
133 | } buffers[MAX_MEMORY_BUFFERS]; | ||
134 | } capture, playback; | ||
135 | |||
136 | unsigned int fps[10]; | ||
137 | unsigned int frame_counter; | ||
138 | }; | ||
139 | |||
140 | static DEFINE_MUTEX(devices_mutex); | ||
141 | static unsigned int devices_used; | ||
142 | static struct usb_driver ua101_driver; | ||
143 | |||
144 | static void abort_alsa_playback(struct ua101 *ua); | ||
145 | static void abort_alsa_capture(struct ua101 *ua); | ||
146 | |||
147 | static const char *usb_error_string(int err) | ||
148 | { | ||
149 | switch (err) { | ||
150 | case -ENODEV: | ||
151 | return "no device"; | ||
152 | case -ENOENT: | ||
153 | return "endpoint not enabled"; | ||
154 | case -EPIPE: | ||
155 | return "endpoint stalled"; | ||
156 | case -ENOSPC: | ||
157 | return "not enough bandwidth"; | ||
158 | case -ESHUTDOWN: | ||
159 | return "device disabled"; | ||
160 | case -EHOSTUNREACH: | ||
161 | return "device suspended"; | ||
162 | case -EINVAL: | ||
163 | case -EAGAIN: | ||
164 | case -EFBIG: | ||
165 | case -EMSGSIZE: | ||
166 | return "internal error"; | ||
167 | default: | ||
168 | return "unknown error"; | ||
169 | } | ||
170 | } | ||
171 | |||
172 | static void abort_usb_capture(struct ua101 *ua) | ||
173 | { | ||
174 | if (test_and_clear_bit(USB_CAPTURE_RUNNING, &ua->states)) { | ||
175 | wake_up(&ua->alsa_capture_wait); | ||
176 | wake_up(&ua->rate_feedback_wait); | ||
177 | } | ||
178 | } | ||
179 | |||
180 | static void abort_usb_playback(struct ua101 *ua) | ||
181 | { | ||
182 | if (test_and_clear_bit(USB_PLAYBACK_RUNNING, &ua->states)) | ||
183 | wake_up(&ua->alsa_playback_wait); | ||
184 | } | ||
185 | |||
186 | static void playback_urb_complete(struct urb *usb_urb) | ||
187 | { | ||
188 | struct ua101_urb *urb = (struct ua101_urb *)usb_urb; | ||
189 | struct ua101 *ua = urb->urb.context; | ||
190 | unsigned long flags; | ||
191 | |||
192 | if (unlikely(urb->urb.status == -ENOENT || /* unlinked */ | ||
193 | urb->urb.status == -ENODEV || /* device removed */ | ||
194 | urb->urb.status == -ECONNRESET || /* unlinked */ | ||
195 | urb->urb.status == -ESHUTDOWN)) { /* device disabled */ | ||
196 | abort_usb_playback(ua); | ||
197 | abort_alsa_playback(ua); | ||
198 | return; | ||
199 | } | ||
200 | |||
201 | if (test_bit(USB_PLAYBACK_RUNNING, &ua->states)) { | ||
202 | /* append URB to FIFO */ | ||
203 | spin_lock_irqsave(&ua->lock, flags); | ||
204 | list_add_tail(&urb->ready_list, &ua->ready_playback_urbs); | ||
205 | if (ua->rate_feedback_count > 0) | ||
206 | tasklet_schedule(&ua->playback_tasklet); | ||
207 | ua->playback.substream->runtime->delay -= | ||
208 | urb->urb.iso_frame_desc[0].length / | ||
209 | ua->playback.frame_bytes; | ||
210 | spin_unlock_irqrestore(&ua->lock, flags); | ||
211 | } | ||
212 | } | ||
213 | |||
214 | static void first_playback_urb_complete(struct urb *urb) | ||
215 | { | ||
216 | struct ua101 *ua = urb->context; | ||
217 | |||
218 | urb->complete = playback_urb_complete; | ||
219 | playback_urb_complete(urb); | ||
220 | |||
221 | set_bit(PLAYBACK_URB_COMPLETED, &ua->states); | ||
222 | wake_up(&ua->alsa_playback_wait); | ||
223 | } | ||
224 | |||
225 | /* copy data from the ALSA ring buffer into the URB buffer */ | ||
226 | static bool copy_playback_data(struct ua101_stream *stream, struct urb *urb, | ||
227 | unsigned int frames) | ||
228 | { | ||
229 | struct snd_pcm_runtime *runtime; | ||
230 | unsigned int frame_bytes, frames1; | ||
231 | const u8 *source; | ||
232 | |||
233 | runtime = stream->substream->runtime; | ||
234 | frame_bytes = stream->frame_bytes; | ||
235 | source = runtime->dma_area + stream->buffer_pos * frame_bytes; | ||
236 | if (stream->buffer_pos + frames <= runtime->buffer_size) { | ||
237 | memcpy(urb->transfer_buffer, source, frames * frame_bytes); | ||
238 | } else { | ||
239 | /* wrap around at end of ring buffer */ | ||
240 | frames1 = runtime->buffer_size - stream->buffer_pos; | ||
241 | memcpy(urb->transfer_buffer, source, frames1 * frame_bytes); | ||
242 | memcpy(urb->transfer_buffer + frames1 * frame_bytes, | ||
243 | runtime->dma_area, (frames - frames1) * frame_bytes); | ||
244 | } | ||
245 | |||
246 | stream->buffer_pos += frames; | ||
247 | if (stream->buffer_pos >= runtime->buffer_size) | ||
248 | stream->buffer_pos -= runtime->buffer_size; | ||
249 | stream->period_pos += frames; | ||
250 | if (stream->period_pos >= runtime->period_size) { | ||
251 | stream->period_pos -= runtime->period_size; | ||
252 | return true; | ||
253 | } | ||
254 | return false; | ||
255 | } | ||
256 | |||
257 | static inline void add_with_wraparound(struct ua101 *ua, | ||
258 | unsigned int *value, unsigned int add) | ||
259 | { | ||
260 | *value += add; | ||
261 | if (*value >= ua->playback.queue_length) | ||
262 | *value -= ua->playback.queue_length; | ||
263 | } | ||
264 | |||
265 | static void playback_tasklet(unsigned long data) | ||
266 | { | ||
267 | struct ua101 *ua = (void *)data; | ||
268 | unsigned long flags; | ||
269 | unsigned int frames; | ||
270 | struct ua101_urb *urb; | ||
271 | bool do_period_elapsed = false; | ||
272 | int err; | ||
273 | |||
274 | if (unlikely(!test_bit(USB_PLAYBACK_RUNNING, &ua->states))) | ||
275 | return; | ||
276 | |||
277 | /* | ||
278 | * Synchronizing the playback rate to the capture rate is done by using | ||
279 | * the same sequence of packet sizes for both streams. | ||
280 | * Submitting a playback URB therefore requires both a ready URB and | ||
281 | * the size of the corresponding capture packet, i.e., both playback | ||
282 | * and capture URBs must have been completed. Since the USB core does | ||
283 | * not guarantee that playback and capture complete callbacks are | ||
284 | * called alternately, we use two FIFOs for packet sizes and read URBs; | ||
285 | * submitting playback URBs is possible as long as both FIFOs are | ||
286 | * nonempty. | ||
287 | */ | ||
288 | spin_lock_irqsave(&ua->lock, flags); | ||
289 | while (ua->rate_feedback_count > 0 && | ||
290 | !list_empty(&ua->ready_playback_urbs)) { | ||
291 | /* take packet size out of FIFO */ | ||
292 | frames = ua->rate_feedback[ua->rate_feedback_start]; | ||
293 | add_with_wraparound(ua, &ua->rate_feedback_start, 1); | ||
294 | ua->rate_feedback_count--; | ||
295 | |||
296 | /* take URB out of FIFO */ | ||
297 | urb = list_first_entry(&ua->ready_playback_urbs, | ||
298 | struct ua101_urb, ready_list); | ||
299 | list_del(&urb->ready_list); | ||
300 | |||
301 | /* fill packet with data or silence */ | ||
302 | urb->urb.iso_frame_desc[0].length = | ||
303 | frames * ua->playback.frame_bytes; | ||
304 | if (test_bit(ALSA_PLAYBACK_RUNNING, &ua->states)) | ||
305 | do_period_elapsed |= copy_playback_data(&ua->playback, | ||
306 | &urb->urb, | ||
307 | frames); | ||
308 | else | ||
309 | memset(urb->urb.transfer_buffer, 0, | ||
310 | urb->urb.iso_frame_desc[0].length); | ||
311 | |||
312 | /* and off you go ... */ | ||
313 | err = usb_submit_urb(&urb->urb, GFP_ATOMIC); | ||
314 | if (unlikely(err < 0)) { | ||
315 | spin_unlock_irqrestore(&ua->lock, flags); | ||
316 | abort_usb_playback(ua); | ||
317 | abort_alsa_playback(ua); | ||
318 | dev_err(&ua->dev->dev, "USB request error %d: %s\n", | ||
319 | err, usb_error_string(err)); | ||
320 | return; | ||
321 | } | ||
322 | ua->playback.substream->runtime->delay += frames; | ||
323 | } | ||
324 | spin_unlock_irqrestore(&ua->lock, flags); | ||
325 | if (do_period_elapsed) | ||
326 | snd_pcm_period_elapsed(ua->playback.substream); | ||
327 | } | ||
328 | |||
329 | /* copy data from the URB buffer into the ALSA ring buffer */ | ||
330 | static bool copy_capture_data(struct ua101_stream *stream, struct urb *urb, | ||
331 | unsigned int frames) | ||
332 | { | ||
333 | struct snd_pcm_runtime *runtime; | ||
334 | unsigned int frame_bytes, frames1; | ||
335 | u8 *dest; | ||
336 | |||
337 | runtime = stream->substream->runtime; | ||
338 | frame_bytes = stream->frame_bytes; | ||
339 | dest = runtime->dma_area + stream->buffer_pos * frame_bytes; | ||
340 | if (stream->buffer_pos + frames <= runtime->buffer_size) { | ||
341 | memcpy(dest, urb->transfer_buffer, frames * frame_bytes); | ||
342 | } else { | ||
343 | /* wrap around at end of ring buffer */ | ||
344 | frames1 = runtime->buffer_size - stream->buffer_pos; | ||
345 | memcpy(dest, urb->transfer_buffer, frames1 * frame_bytes); | ||
346 | memcpy(runtime->dma_area, | ||
347 | urb->transfer_buffer + frames1 * frame_bytes, | ||
348 | (frames - frames1) * frame_bytes); | ||
349 | } | ||
350 | |||
351 | stream->buffer_pos += frames; | ||
352 | if (stream->buffer_pos >= runtime->buffer_size) | ||
353 | stream->buffer_pos -= runtime->buffer_size; | ||
354 | stream->period_pos += frames; | ||
355 | if (stream->period_pos >= runtime->period_size) { | ||
356 | stream->period_pos -= runtime->period_size; | ||
357 | return true; | ||
358 | } | ||
359 | return false; | ||
360 | } | ||
361 | |||
362 | static void capture_urb_complete(struct urb *urb) | ||
363 | { | ||
364 | struct ua101 *ua = urb->context; | ||
365 | struct ua101_stream *stream = &ua->capture; | ||
366 | unsigned long flags; | ||
367 | unsigned int frames, write_ptr; | ||
368 | bool do_period_elapsed; | ||
369 | int err; | ||
370 | |||
371 | if (unlikely(urb->status == -ENOENT || /* unlinked */ | ||
372 | urb->status == -ENODEV || /* device removed */ | ||
373 | urb->status == -ECONNRESET || /* unlinked */ | ||
374 | urb->status == -ESHUTDOWN)) /* device disabled */ | ||
375 | goto stream_stopped; | ||
376 | |||
377 | if (urb->status >= 0 && urb->iso_frame_desc[0].status >= 0) | ||
378 | frames = urb->iso_frame_desc[0].actual_length / | ||
379 | stream->frame_bytes; | ||
380 | else | ||
381 | frames = 0; | ||
382 | |||
383 | spin_lock_irqsave(&ua->lock, flags); | ||
384 | |||
385 | if (frames > 0 && test_bit(ALSA_CAPTURE_RUNNING, &ua->states)) | ||
386 | do_period_elapsed = copy_capture_data(stream, urb, frames); | ||
387 | else | ||
388 | do_period_elapsed = false; | ||
389 | |||
390 | if (test_bit(USB_CAPTURE_RUNNING, &ua->states)) { | ||
391 | err = usb_submit_urb(urb, GFP_ATOMIC); | ||
392 | if (unlikely(err < 0)) { | ||
393 | spin_unlock_irqrestore(&ua->lock, flags); | ||
394 | dev_err(&ua->dev->dev, "USB request error %d: %s\n", | ||
395 | err, usb_error_string(err)); | ||
396 | goto stream_stopped; | ||
397 | } | ||
398 | |||
399 | /* append packet size to FIFO */ | ||
400 | write_ptr = ua->rate_feedback_start; | ||
401 | add_with_wraparound(ua, &write_ptr, ua->rate_feedback_count); | ||
402 | ua->rate_feedback[write_ptr] = frames; | ||
403 | if (ua->rate_feedback_count < ua->playback.queue_length) { | ||
404 | ua->rate_feedback_count++; | ||
405 | if (ua->rate_feedback_count == | ||
406 | ua->playback.queue_length) | ||
407 | wake_up(&ua->rate_feedback_wait); | ||
408 | } else { | ||
409 | /* | ||
410 | * Ring buffer overflow; this happens when the playback | ||
411 | * stream is not running. Throw away the oldest entry, | ||
412 | * so that the playback stream, when it starts, sees | ||
413 | * the most recent packet sizes. | ||
414 | */ | ||
415 | add_with_wraparound(ua, &ua->rate_feedback_start, 1); | ||
416 | } | ||
417 | if (test_bit(USB_PLAYBACK_RUNNING, &ua->states) && | ||
418 | !list_empty(&ua->ready_playback_urbs)) | ||
419 | tasklet_schedule(&ua->playback_tasklet); | ||
420 | } | ||
421 | |||
422 | spin_unlock_irqrestore(&ua->lock, flags); | ||
423 | |||
424 | if (do_period_elapsed) | ||
425 | snd_pcm_period_elapsed(stream->substream); | ||
426 | |||
427 | /* for debugging: measure the sample rate relative to the USB clock */ | ||
428 | ua->fps[ua->frame_counter++ / ua->packets_per_second] += frames; | ||
429 | if (ua->frame_counter >= ARRAY_SIZE(ua->fps) * ua->packets_per_second) { | ||
430 | printk(KERN_DEBUG "capture rate:"); | ||
431 | for (frames = 0; frames < ARRAY_SIZE(ua->fps); ++frames) | ||
432 | printk(KERN_CONT " %u", ua->fps[frames]); | ||
433 | printk(KERN_CONT "\n"); | ||
434 | memset(ua->fps, 0, sizeof(ua->fps)); | ||
435 | ua->frame_counter = 0; | ||
436 | } | ||
437 | return; | ||
438 | |||
439 | stream_stopped: | ||
440 | abort_usb_playback(ua); | ||
441 | abort_usb_capture(ua); | ||
442 | abort_alsa_playback(ua); | ||
443 | abort_alsa_capture(ua); | ||
444 | } | ||
445 | |||
446 | static void first_capture_urb_complete(struct urb *urb) | ||
447 | { | ||
448 | struct ua101 *ua = urb->context; | ||
449 | |||
450 | urb->complete = capture_urb_complete; | ||
451 | capture_urb_complete(urb); | ||
452 | |||
453 | set_bit(CAPTURE_URB_COMPLETED, &ua->states); | ||
454 | wake_up(&ua->alsa_capture_wait); | ||
455 | } | ||
456 | |||
457 | static int submit_stream_urbs(struct ua101 *ua, struct ua101_stream *stream) | ||
458 | { | ||
459 | unsigned int i; | ||
460 | |||
461 | for (i = 0; i < stream->queue_length; ++i) { | ||
462 | int err = usb_submit_urb(&stream->urbs[i]->urb, GFP_KERNEL); | ||
463 | if (err < 0) { | ||
464 | dev_err(&ua->dev->dev, "USB request error %d: %s\n", | ||
465 | err, usb_error_string(err)); | ||
466 | return err; | ||
467 | } | ||
468 | } | ||
469 | return 0; | ||
470 | } | ||
471 | |||
472 | static void kill_stream_urbs(struct ua101_stream *stream) | ||
473 | { | ||
474 | unsigned int i; | ||
475 | |||
476 | for (i = 0; i < stream->queue_length; ++i) | ||
477 | usb_kill_urb(&stream->urbs[i]->urb); | ||
478 | } | ||
479 | |||
480 | static int enable_iso_interface(struct ua101 *ua, unsigned int intf_index) | ||
481 | { | ||
482 | struct usb_host_interface *alts; | ||
483 | |||
484 | alts = ua->intf[intf_index]->cur_altsetting; | ||
485 | if (alts->desc.bAlternateSetting != 1) { | ||
486 | int err = usb_set_interface(ua->dev, | ||
487 | alts->desc.bInterfaceNumber, 1); | ||
488 | if (err < 0) { | ||
489 | dev_err(&ua->dev->dev, | ||
490 | "cannot initialize interface; error %d: %s\n", | ||
491 | err, usb_error_string(err)); | ||
492 | return err; | ||
493 | } | ||
494 | } | ||
495 | return 0; | ||
496 | } | ||
497 | |||
498 | static void disable_iso_interface(struct ua101 *ua, unsigned int intf_index) | ||
499 | { | ||
500 | struct usb_host_interface *alts; | ||
501 | |||
502 | alts = ua->intf[intf_index]->cur_altsetting; | ||
503 | if (alts->desc.bAlternateSetting != 0) { | ||
504 | int err = usb_set_interface(ua->dev, | ||
505 | alts->desc.bInterfaceNumber, 0); | ||
506 | if (err < 0 && !test_bit(DISCONNECTED, &ua->states)) | ||
507 | dev_warn(&ua->dev->dev, | ||
508 | "interface reset failed; error %d: %s\n", | ||
509 | err, usb_error_string(err)); | ||
510 | } | ||
511 | } | ||
512 | |||
513 | static void stop_usb_capture(struct ua101 *ua) | ||
514 | { | ||
515 | clear_bit(USB_CAPTURE_RUNNING, &ua->states); | ||
516 | |||
517 | kill_stream_urbs(&ua->capture); | ||
518 | |||
519 | disable_iso_interface(ua, INTF_CAPTURE); | ||
520 | } | ||
521 | |||
522 | static int start_usb_capture(struct ua101 *ua) | ||
523 | { | ||
524 | int err; | ||
525 | |||
526 | if (test_bit(DISCONNECTED, &ua->states)) | ||
527 | return -ENODEV; | ||
528 | |||
529 | if (test_bit(USB_CAPTURE_RUNNING, &ua->states)) | ||
530 | return 0; | ||
531 | |||
532 | kill_stream_urbs(&ua->capture); | ||
533 | |||
534 | err = enable_iso_interface(ua, INTF_CAPTURE); | ||
535 | if (err < 0) | ||
536 | return err; | ||
537 | |||
538 | clear_bit(CAPTURE_URB_COMPLETED, &ua->states); | ||
539 | ua->capture.urbs[0]->urb.complete = first_capture_urb_complete; | ||
540 | ua->rate_feedback_start = 0; | ||
541 | ua->rate_feedback_count = 0; | ||
542 | |||
543 | set_bit(USB_CAPTURE_RUNNING, &ua->states); | ||
544 | err = submit_stream_urbs(ua, &ua->capture); | ||
545 | if (err < 0) | ||
546 | stop_usb_capture(ua); | ||
547 | return err; | ||
548 | } | ||
549 | |||
550 | static void stop_usb_playback(struct ua101 *ua) | ||
551 | { | ||
552 | clear_bit(USB_PLAYBACK_RUNNING, &ua->states); | ||
553 | |||
554 | kill_stream_urbs(&ua->playback); | ||
555 | |||
556 | tasklet_kill(&ua->playback_tasklet); | ||
557 | |||
558 | disable_iso_interface(ua, INTF_PLAYBACK); | ||
559 | } | ||
560 | |||
561 | static int start_usb_playback(struct ua101 *ua) | ||
562 | { | ||
563 | unsigned int i, frames; | ||
564 | struct urb *urb; | ||
565 | int err = 0; | ||
566 | |||
567 | if (test_bit(DISCONNECTED, &ua->states)) | ||
568 | return -ENODEV; | ||
569 | |||
570 | if (test_bit(USB_PLAYBACK_RUNNING, &ua->states)) | ||
571 | return 0; | ||
572 | |||
573 | kill_stream_urbs(&ua->playback); | ||
574 | tasklet_kill(&ua->playback_tasklet); | ||
575 | |||
576 | err = enable_iso_interface(ua, INTF_PLAYBACK); | ||
577 | if (err < 0) | ||
578 | return err; | ||
579 | |||
580 | clear_bit(PLAYBACK_URB_COMPLETED, &ua->states); | ||
581 | ua->playback.urbs[0]->urb.complete = | ||
582 | first_playback_urb_complete; | ||
583 | spin_lock_irq(&ua->lock); | ||
584 | INIT_LIST_HEAD(&ua->ready_playback_urbs); | ||
585 | spin_unlock_irq(&ua->lock); | ||
586 | |||
587 | /* | ||
588 | * We submit the initial URBs all at once, so we have to wait for the | ||
589 | * packet size FIFO to be full. | ||
590 | */ | ||
591 | wait_event(ua->rate_feedback_wait, | ||
592 | ua->rate_feedback_count >= ua->playback.queue_length || | ||
593 | !test_bit(USB_CAPTURE_RUNNING, &ua->states) || | ||
594 | test_bit(DISCONNECTED, &ua->states)); | ||
595 | if (test_bit(DISCONNECTED, &ua->states)) { | ||
596 | stop_usb_playback(ua); | ||
597 | return -ENODEV; | ||
598 | } | ||
599 | if (!test_bit(USB_CAPTURE_RUNNING, &ua->states)) { | ||
600 | stop_usb_playback(ua); | ||
601 | return -EIO; | ||
602 | } | ||
603 | |||
604 | for (i = 0; i < ua->playback.queue_length; ++i) { | ||
605 | /* all initial URBs contain silence */ | ||
606 | spin_lock_irq(&ua->lock); | ||
607 | frames = ua->rate_feedback[ua->rate_feedback_start]; | ||
608 | add_with_wraparound(ua, &ua->rate_feedback_start, 1); | ||
609 | ua->rate_feedback_count--; | ||
610 | spin_unlock_irq(&ua->lock); | ||
611 | urb = &ua->playback.urbs[i]->urb; | ||
612 | urb->iso_frame_desc[0].length = | ||
613 | frames * ua->playback.frame_bytes; | ||
614 | memset(urb->transfer_buffer, 0, | ||
615 | urb->iso_frame_desc[0].length); | ||
616 | } | ||
617 | |||
618 | set_bit(USB_PLAYBACK_RUNNING, &ua->states); | ||
619 | err = submit_stream_urbs(ua, &ua->playback); | ||
620 | if (err < 0) | ||
621 | stop_usb_playback(ua); | ||
622 | return err; | ||
623 | } | ||
624 | |||
625 | static void abort_alsa_capture(struct ua101 *ua) | ||
626 | { | ||
627 | if (test_bit(ALSA_CAPTURE_RUNNING, &ua->states)) | ||
628 | snd_pcm_stop(ua->capture.substream, SNDRV_PCM_STATE_XRUN); | ||
629 | } | ||
630 | |||
631 | static void abort_alsa_playback(struct ua101 *ua) | ||
632 | { | ||
633 | if (test_bit(ALSA_PLAYBACK_RUNNING, &ua->states)) | ||
634 | snd_pcm_stop(ua->playback.substream, SNDRV_PCM_STATE_XRUN); | ||
635 | } | ||
636 | |||
637 | static int set_stream_hw(struct ua101 *ua, struct snd_pcm_substream *substream, | ||
638 | unsigned int channels) | ||
639 | { | ||
640 | int err; | ||
641 | |||
642 | substream->runtime->hw.info = | ||
643 | SNDRV_PCM_INFO_MMAP | | ||
644 | SNDRV_PCM_INFO_MMAP_VALID | | ||
645 | SNDRV_PCM_INFO_BATCH | | ||
646 | SNDRV_PCM_INFO_INTERLEAVED | | ||
647 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | ||
648 | SNDRV_PCM_INFO_FIFO_IN_FRAMES; | ||
649 | substream->runtime->hw.formats = ua->format_bit; | ||
650 | substream->runtime->hw.rates = snd_pcm_rate_to_rate_bit(ua->rate); | ||
651 | substream->runtime->hw.rate_min = ua->rate; | ||
652 | substream->runtime->hw.rate_max = ua->rate; | ||
653 | substream->runtime->hw.channels_min = channels; | ||
654 | substream->runtime->hw.channels_max = channels; | ||
655 | substream->runtime->hw.buffer_bytes_max = 45000 * 1024; | ||
656 | substream->runtime->hw.period_bytes_min = 1; | ||
657 | substream->runtime->hw.period_bytes_max = UINT_MAX; | ||
658 | substream->runtime->hw.periods_min = 2; | ||
659 | substream->runtime->hw.periods_max = UINT_MAX; | ||
660 | err = snd_pcm_hw_constraint_minmax(substream->runtime, | ||
661 | SNDRV_PCM_HW_PARAM_PERIOD_TIME, | ||
662 | 1500000 / ua->packets_per_second, | ||
663 | 8192000); | ||
664 | if (err < 0) | ||
665 | return err; | ||
666 | err = snd_pcm_hw_constraint_msbits(substream->runtime, 0, 32, 24); | ||
667 | return err; | ||
668 | } | ||
669 | |||
670 | static int capture_pcm_open(struct snd_pcm_substream *substream) | ||
671 | { | ||
672 | struct ua101 *ua = substream->private_data; | ||
673 | int err; | ||
674 | |||
675 | ua->capture.substream = substream; | ||
676 | err = set_stream_hw(ua, substream, ua->capture.channels); | ||
677 | if (err < 0) | ||
678 | return err; | ||
679 | substream->runtime->hw.fifo_size = | ||
680 | DIV_ROUND_CLOSEST(ua->rate, ua->packets_per_second); | ||
681 | substream->runtime->delay = substream->runtime->hw.fifo_size; | ||
682 | |||
683 | mutex_lock(&ua->mutex); | ||
684 | err = start_usb_capture(ua); | ||
685 | if (err >= 0) | ||
686 | set_bit(ALSA_CAPTURE_OPEN, &ua->states); | ||
687 | mutex_unlock(&ua->mutex); | ||
688 | return err; | ||
689 | } | ||
690 | |||
691 | static int playback_pcm_open(struct snd_pcm_substream *substream) | ||
692 | { | ||
693 | struct ua101 *ua = substream->private_data; | ||
694 | int err; | ||
695 | |||
696 | ua->playback.substream = substream; | ||
697 | err = set_stream_hw(ua, substream, ua->playback.channels); | ||
698 | if (err < 0) | ||
699 | return err; | ||
700 | substream->runtime->hw.fifo_size = | ||
701 | DIV_ROUND_CLOSEST(ua->rate * ua->playback.queue_length, | ||
702 | ua->packets_per_second); | ||
703 | |||
704 | mutex_lock(&ua->mutex); | ||
705 | err = start_usb_capture(ua); | ||
706 | if (err < 0) | ||
707 | goto error; | ||
708 | err = start_usb_playback(ua); | ||
709 | if (err < 0) { | ||
710 | if (!test_bit(ALSA_CAPTURE_OPEN, &ua->states)) | ||
711 | stop_usb_capture(ua); | ||
712 | goto error; | ||
713 | } | ||
714 | set_bit(ALSA_PLAYBACK_OPEN, &ua->states); | ||
715 | error: | ||
716 | mutex_unlock(&ua->mutex); | ||
717 | return err; | ||
718 | } | ||
719 | |||
720 | static int capture_pcm_close(struct snd_pcm_substream *substream) | ||
721 | { | ||
722 | struct ua101 *ua = substream->private_data; | ||
723 | |||
724 | mutex_lock(&ua->mutex); | ||
725 | clear_bit(ALSA_CAPTURE_OPEN, &ua->states); | ||
726 | if (!test_bit(ALSA_PLAYBACK_OPEN, &ua->states)) | ||
727 | stop_usb_capture(ua); | ||
728 | mutex_unlock(&ua->mutex); | ||
729 | return 0; | ||
730 | } | ||
731 | |||
732 | static int playback_pcm_close(struct snd_pcm_substream *substream) | ||
733 | { | ||
734 | struct ua101 *ua = substream->private_data; | ||
735 | |||
736 | mutex_lock(&ua->mutex); | ||
737 | stop_usb_playback(ua); | ||
738 | clear_bit(ALSA_PLAYBACK_OPEN, &ua->states); | ||
739 | if (!test_bit(ALSA_CAPTURE_OPEN, &ua->states)) | ||
740 | stop_usb_capture(ua); | ||
741 | mutex_unlock(&ua->mutex); | ||
742 | return 0; | ||
743 | } | ||
744 | |||
745 | static int capture_pcm_hw_params(struct snd_pcm_substream *substream, | ||
746 | struct snd_pcm_hw_params *hw_params) | ||
747 | { | ||
748 | struct ua101 *ua = substream->private_data; | ||
749 | int err; | ||
750 | |||
751 | mutex_lock(&ua->mutex); | ||
752 | err = start_usb_capture(ua); | ||
753 | mutex_unlock(&ua->mutex); | ||
754 | if (err < 0) | ||
755 | return err; | ||
756 | |||
757 | return snd_pcm_lib_alloc_vmalloc_buffer(substream, | ||
758 | params_buffer_bytes(hw_params)); | ||
759 | } | ||
760 | |||
761 | static int playback_pcm_hw_params(struct snd_pcm_substream *substream, | ||
762 | struct snd_pcm_hw_params *hw_params) | ||
763 | { | ||
764 | struct ua101 *ua = substream->private_data; | ||
765 | int err; | ||
766 | |||
767 | mutex_lock(&ua->mutex); | ||
768 | err = start_usb_capture(ua); | ||
769 | if (err >= 0) | ||
770 | err = start_usb_playback(ua); | ||
771 | mutex_unlock(&ua->mutex); | ||
772 | if (err < 0) | ||
773 | return err; | ||
774 | |||
775 | return snd_pcm_lib_alloc_vmalloc_buffer(substream, | ||
776 | params_buffer_bytes(hw_params)); | ||
777 | } | ||
778 | |||
779 | static int ua101_pcm_hw_free(struct snd_pcm_substream *substream) | ||
780 | { | ||
781 | return snd_pcm_lib_free_vmalloc_buffer(substream); | ||
782 | } | ||
783 | |||
784 | static int capture_pcm_prepare(struct snd_pcm_substream *substream) | ||
785 | { | ||
786 | struct ua101 *ua = substream->private_data; | ||
787 | int err; | ||
788 | |||
789 | mutex_lock(&ua->mutex); | ||
790 | err = start_usb_capture(ua); | ||
791 | mutex_unlock(&ua->mutex); | ||
792 | if (err < 0) | ||
793 | return err; | ||
794 | |||
795 | /* | ||
796 | * The EHCI driver schedules the first packet of an iso stream at 10 ms | ||
797 | * in the future, i.e., no data is actually captured for that long. | ||
798 | * Take the wait here so that the stream is known to be actually | ||
799 | * running when the start trigger has been called. | ||
800 | */ | ||
801 | wait_event(ua->alsa_capture_wait, | ||
802 | test_bit(CAPTURE_URB_COMPLETED, &ua->states) || | ||
803 | !test_bit(USB_CAPTURE_RUNNING, &ua->states)); | ||
804 | if (test_bit(DISCONNECTED, &ua->states)) | ||
805 | return -ENODEV; | ||
806 | if (!test_bit(USB_CAPTURE_RUNNING, &ua->states)) | ||
807 | return -EIO; | ||
808 | |||
809 | ua->capture.period_pos = 0; | ||
810 | ua->capture.buffer_pos = 0; | ||
811 | return 0; | ||
812 | } | ||
813 | |||
814 | static int playback_pcm_prepare(struct snd_pcm_substream *substream) | ||
815 | { | ||
816 | struct ua101 *ua = substream->private_data; | ||
817 | int err; | ||
818 | |||
819 | mutex_lock(&ua->mutex); | ||
820 | err = start_usb_capture(ua); | ||
821 | if (err >= 0) | ||
822 | err = start_usb_playback(ua); | ||
823 | mutex_unlock(&ua->mutex); | ||
824 | if (err < 0) | ||
825 | return err; | ||
826 | |||
827 | /* see the comment in capture_pcm_prepare() */ | ||
828 | wait_event(ua->alsa_playback_wait, | ||
829 | test_bit(PLAYBACK_URB_COMPLETED, &ua->states) || | ||
830 | !test_bit(USB_PLAYBACK_RUNNING, &ua->states)); | ||
831 | if (test_bit(DISCONNECTED, &ua->states)) | ||
832 | return -ENODEV; | ||
833 | if (!test_bit(USB_PLAYBACK_RUNNING, &ua->states)) | ||
834 | return -EIO; | ||
835 | |||
836 | substream->runtime->delay = 0; | ||
837 | ua->playback.period_pos = 0; | ||
838 | ua->playback.buffer_pos = 0; | ||
839 | return 0; | ||
840 | } | ||
841 | |||
842 | static int capture_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | ||
843 | { | ||
844 | struct ua101 *ua = substream->private_data; | ||
845 | |||
846 | switch (cmd) { | ||
847 | case SNDRV_PCM_TRIGGER_START: | ||
848 | if (!test_bit(USB_CAPTURE_RUNNING, &ua->states)) | ||
849 | return -EIO; | ||
850 | set_bit(ALSA_CAPTURE_RUNNING, &ua->states); | ||
851 | return 0; | ||
852 | case SNDRV_PCM_TRIGGER_STOP: | ||
853 | clear_bit(ALSA_CAPTURE_RUNNING, &ua->states); | ||
854 | return 0; | ||
855 | default: | ||
856 | return -EINVAL; | ||
857 | } | ||
858 | } | ||
859 | |||
860 | static int playback_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | ||
861 | { | ||
862 | struct ua101 *ua = substream->private_data; | ||
863 | |||
864 | switch (cmd) { | ||
865 | case SNDRV_PCM_TRIGGER_START: | ||
866 | if (!test_bit(USB_PLAYBACK_RUNNING, &ua->states)) | ||
867 | return -EIO; | ||
868 | set_bit(ALSA_PLAYBACK_RUNNING, &ua->states); | ||
869 | return 0; | ||
870 | case SNDRV_PCM_TRIGGER_STOP: | ||
871 | clear_bit(ALSA_PLAYBACK_RUNNING, &ua->states); | ||
872 | return 0; | ||
873 | default: | ||
874 | return -EINVAL; | ||
875 | } | ||
876 | } | ||
877 | |||
878 | static inline snd_pcm_uframes_t ua101_pcm_pointer(struct ua101 *ua, | ||
879 | struct ua101_stream *stream) | ||
880 | { | ||
881 | unsigned long flags; | ||
882 | unsigned int pos; | ||
883 | |||
884 | spin_lock_irqsave(&ua->lock, flags); | ||
885 | pos = stream->buffer_pos; | ||
886 | spin_unlock_irqrestore(&ua->lock, flags); | ||
887 | return pos; | ||
888 | } | ||
889 | |||
890 | static snd_pcm_uframes_t capture_pcm_pointer(struct snd_pcm_substream *subs) | ||
891 | { | ||
892 | struct ua101 *ua = subs->private_data; | ||
893 | |||
894 | return ua101_pcm_pointer(ua, &ua->capture); | ||
895 | } | ||
896 | |||
897 | static snd_pcm_uframes_t playback_pcm_pointer(struct snd_pcm_substream *subs) | ||
898 | { | ||
899 | struct ua101 *ua = subs->private_data; | ||
900 | |||
901 | return ua101_pcm_pointer(ua, &ua->playback); | ||
902 | } | ||
903 | |||
904 | static struct snd_pcm_ops capture_pcm_ops = { | ||
905 | .open = capture_pcm_open, | ||
906 | .close = capture_pcm_close, | ||
907 | .ioctl = snd_pcm_lib_ioctl, | ||
908 | .hw_params = capture_pcm_hw_params, | ||
909 | .hw_free = ua101_pcm_hw_free, | ||
910 | .prepare = capture_pcm_prepare, | ||
911 | .trigger = capture_pcm_trigger, | ||
912 | .pointer = capture_pcm_pointer, | ||
913 | .page = snd_pcm_lib_get_vmalloc_page, | ||
914 | .mmap = snd_pcm_lib_mmap_vmalloc, | ||
915 | }; | ||
916 | |||
917 | static struct snd_pcm_ops playback_pcm_ops = { | ||
918 | .open = playback_pcm_open, | ||
919 | .close = playback_pcm_close, | ||
920 | .ioctl = snd_pcm_lib_ioctl, | ||
921 | .hw_params = playback_pcm_hw_params, | ||
922 | .hw_free = ua101_pcm_hw_free, | ||
923 | .prepare = playback_pcm_prepare, | ||
924 | .trigger = playback_pcm_trigger, | ||
925 | .pointer = playback_pcm_pointer, | ||
926 | .page = snd_pcm_lib_get_vmalloc_page, | ||
927 | .mmap = snd_pcm_lib_mmap_vmalloc, | ||
928 | }; | ||
929 | |||
930 | static const struct uac_format_type_i_discrete_descriptor * | ||
931 | find_format_descriptor(struct usb_interface *interface) | ||
932 | { | ||
933 | struct usb_host_interface *alt; | ||
934 | u8 *extra; | ||
935 | int extralen; | ||
936 | |||
937 | if (interface->num_altsetting != 2) { | ||
938 | dev_err(&interface->dev, "invalid num_altsetting\n"); | ||
939 | return NULL; | ||
940 | } | ||
941 | |||
942 | alt = &interface->altsetting[0]; | ||
943 | if (alt->desc.bNumEndpoints != 0) { | ||
944 | dev_err(&interface->dev, "invalid bNumEndpoints\n"); | ||
945 | return NULL; | ||
946 | } | ||
947 | |||
948 | alt = &interface->altsetting[1]; | ||
949 | if (alt->desc.bNumEndpoints != 1) { | ||
950 | dev_err(&interface->dev, "invalid bNumEndpoints\n"); | ||
951 | return NULL; | ||
952 | } | ||
953 | |||
954 | extra = alt->extra; | ||
955 | extralen = alt->extralen; | ||
956 | while (extralen >= sizeof(struct usb_descriptor_header)) { | ||
957 | struct uac_format_type_i_discrete_descriptor *desc; | ||
958 | |||
959 | desc = (struct uac_format_type_i_discrete_descriptor *)extra; | ||
960 | if (desc->bLength > extralen) { | ||
961 | dev_err(&interface->dev, "descriptor overflow\n"); | ||
962 | return NULL; | ||
963 | } | ||
964 | if (desc->bLength == UAC_FORMAT_TYPE_I_DISCRETE_DESC_SIZE(1) && | ||
965 | desc->bDescriptorType == USB_DT_CS_INTERFACE && | ||
966 | desc->bDescriptorSubtype == UAC_FORMAT_TYPE) { | ||
967 | if (desc->bFormatType != UAC_FORMAT_TYPE_I_PCM || | ||
968 | desc->bSamFreqType != 1) { | ||
969 | dev_err(&interface->dev, | ||
970 | "invalid format type\n"); | ||
971 | return NULL; | ||
972 | } | ||
973 | return desc; | ||
974 | } | ||
975 | extralen -= desc->bLength; | ||
976 | extra += desc->bLength; | ||
977 | } | ||
978 | dev_err(&interface->dev, "sample format descriptor not found\n"); | ||
979 | return NULL; | ||
980 | } | ||
981 | |||
982 | static int detect_usb_format(struct ua101 *ua) | ||
983 | { | ||
984 | const struct uac_format_type_i_discrete_descriptor *fmt_capture; | ||
985 | const struct uac_format_type_i_discrete_descriptor *fmt_playback; | ||
986 | const struct usb_endpoint_descriptor *epd; | ||
987 | unsigned int rate2; | ||
988 | |||
989 | fmt_capture = find_format_descriptor(ua->intf[INTF_CAPTURE]); | ||
990 | fmt_playback = find_format_descriptor(ua->intf[INTF_PLAYBACK]); | ||
991 | if (!fmt_capture || !fmt_playback) | ||
992 | return -ENXIO; | ||
993 | |||
994 | switch (fmt_capture->bSubframeSize) { | ||
995 | case 3: | ||
996 | ua->format_bit = SNDRV_PCM_FMTBIT_S24_3LE; | ||
997 | break; | ||
998 | case 4: | ||
999 | ua->format_bit = SNDRV_PCM_FMTBIT_S32_LE; | ||
1000 | break; | ||
1001 | default: | ||
1002 | dev_err(&ua->dev->dev, "sample width is not 24 or 32 bits\n"); | ||
1003 | return -ENXIO; | ||
1004 | } | ||
1005 | if (fmt_capture->bSubframeSize != fmt_playback->bSubframeSize) { | ||
1006 | dev_err(&ua->dev->dev, | ||
1007 | "playback/capture sample widths do not match\n"); | ||
1008 | return -ENXIO; | ||
1009 | } | ||
1010 | |||
1011 | if (fmt_capture->bBitResolution != 24 || | ||
1012 | fmt_playback->bBitResolution != 24) { | ||
1013 | dev_err(&ua->dev->dev, "sample width is not 24 bits\n"); | ||
1014 | return -ENXIO; | ||
1015 | } | ||
1016 | |||
1017 | ua->rate = combine_triple(fmt_capture->tSamFreq[0]); | ||
1018 | rate2 = combine_triple(fmt_playback->tSamFreq[0]); | ||
1019 | if (ua->rate != rate2) { | ||
1020 | dev_err(&ua->dev->dev, | ||
1021 | "playback/capture rates do not match: %u/%u\n", | ||
1022 | rate2, ua->rate); | ||
1023 | return -ENXIO; | ||
1024 | } | ||
1025 | |||
1026 | switch (ua->dev->speed) { | ||
1027 | case USB_SPEED_FULL: | ||
1028 | ua->packets_per_second = 1000; | ||
1029 | break; | ||
1030 | case USB_SPEED_HIGH: | ||
1031 | ua->packets_per_second = 8000; | ||
1032 | break; | ||
1033 | default: | ||
1034 | dev_err(&ua->dev->dev, "unknown device speed\n"); | ||
1035 | return -ENXIO; | ||
1036 | } | ||
1037 | |||
1038 | ua->capture.channels = fmt_capture->bNrChannels; | ||
1039 | ua->playback.channels = fmt_playback->bNrChannels; | ||
1040 | ua->capture.frame_bytes = | ||
1041 | fmt_capture->bSubframeSize * ua->capture.channels; | ||
1042 | ua->playback.frame_bytes = | ||
1043 | fmt_playback->bSubframeSize * ua->playback.channels; | ||
1044 | |||
1045 | epd = &ua->intf[INTF_CAPTURE]->altsetting[1].endpoint[0].desc; | ||
1046 | if (!usb_endpoint_is_isoc_in(epd)) { | ||
1047 | dev_err(&ua->dev->dev, "invalid capture endpoint\n"); | ||
1048 | return -ENXIO; | ||
1049 | } | ||
1050 | ua->capture.usb_pipe = usb_rcvisocpipe(ua->dev, usb_endpoint_num(epd)); | ||
1051 | ua->capture.max_packet_bytes = le16_to_cpu(epd->wMaxPacketSize); | ||
1052 | |||
1053 | epd = &ua->intf[INTF_PLAYBACK]->altsetting[1].endpoint[0].desc; | ||
1054 | if (!usb_endpoint_is_isoc_out(epd)) { | ||
1055 | dev_err(&ua->dev->dev, "invalid playback endpoint\n"); | ||
1056 | return -ENXIO; | ||
1057 | } | ||
1058 | ua->playback.usb_pipe = usb_sndisocpipe(ua->dev, usb_endpoint_num(epd)); | ||
1059 | ua->playback.max_packet_bytes = le16_to_cpu(epd->wMaxPacketSize); | ||
1060 | return 0; | ||
1061 | } | ||
1062 | |||
1063 | static int alloc_stream_buffers(struct ua101 *ua, struct ua101_stream *stream) | ||
1064 | { | ||
1065 | unsigned int remaining_packets, packets, packets_per_page, i; | ||
1066 | size_t size; | ||
1067 | |||
1068 | stream->queue_length = queue_length; | ||
1069 | stream->queue_length = max(stream->queue_length, | ||
1070 | (unsigned int)MIN_QUEUE_LENGTH); | ||
1071 | stream->queue_length = min(stream->queue_length, | ||
1072 | (unsigned int)MAX_QUEUE_LENGTH); | ||
1073 | |||
1074 | /* | ||
1075 | * The cache pool sizes used by usb_buffer_alloc() (128, 512, 2048) are | ||
1076 | * quite bad when used with the packet sizes of this device (e.g. 280, | ||
1077 | * 520, 624). Therefore, we allocate and subdivide entire pages, using | ||
1078 | * a smaller buffer only for the last chunk. | ||
1079 | */ | ||
1080 | remaining_packets = stream->queue_length; | ||
1081 | packets_per_page = PAGE_SIZE / stream->max_packet_bytes; | ||
1082 | for (i = 0; i < ARRAY_SIZE(stream->buffers); ++i) { | ||
1083 | packets = min(remaining_packets, packets_per_page); | ||
1084 | size = packets * stream->max_packet_bytes; | ||
1085 | stream->buffers[i].addr = | ||
1086 | usb_buffer_alloc(ua->dev, size, GFP_KERNEL, | ||
1087 | &stream->buffers[i].dma); | ||
1088 | if (!stream->buffers[i].addr) | ||
1089 | return -ENOMEM; | ||
1090 | stream->buffers[i].size = size; | ||
1091 | remaining_packets -= packets; | ||
1092 | if (!remaining_packets) | ||
1093 | break; | ||
1094 | } | ||
1095 | if (remaining_packets) { | ||
1096 | dev_err(&ua->dev->dev, "too many packets\n"); | ||
1097 | return -ENXIO; | ||
1098 | } | ||
1099 | return 0; | ||
1100 | } | ||
1101 | |||
1102 | static void free_stream_buffers(struct ua101 *ua, struct ua101_stream *stream) | ||
1103 | { | ||
1104 | unsigned int i; | ||
1105 | |||
1106 | for (i = 0; i < ARRAY_SIZE(stream->buffers); ++i) | ||
1107 | usb_buffer_free(ua->dev, | ||
1108 | stream->buffers[i].size, | ||
1109 | stream->buffers[i].addr, | ||
1110 | stream->buffers[i].dma); | ||
1111 | } | ||
1112 | |||
1113 | static int alloc_stream_urbs(struct ua101 *ua, struct ua101_stream *stream, | ||
1114 | void (*urb_complete)(struct urb *)) | ||
1115 | { | ||
1116 | unsigned max_packet_size = stream->max_packet_bytes; | ||
1117 | struct ua101_urb *urb; | ||
1118 | unsigned int b, u = 0; | ||
1119 | |||
1120 | for (b = 0; b < ARRAY_SIZE(stream->buffers); ++b) { | ||
1121 | unsigned int size = stream->buffers[b].size; | ||
1122 | u8 *addr = stream->buffers[b].addr; | ||
1123 | dma_addr_t dma = stream->buffers[b].dma; | ||
1124 | |||
1125 | while (size >= max_packet_size) { | ||
1126 | if (u >= stream->queue_length) | ||
1127 | goto bufsize_error; | ||
1128 | urb = kmalloc(sizeof(*urb), GFP_KERNEL); | ||
1129 | if (!urb) | ||
1130 | return -ENOMEM; | ||
1131 | usb_init_urb(&urb->urb); | ||
1132 | urb->urb.dev = ua->dev; | ||
1133 | urb->urb.pipe = stream->usb_pipe; | ||
1134 | urb->urb.transfer_flags = URB_ISO_ASAP | | ||
1135 | URB_NO_TRANSFER_DMA_MAP; | ||
1136 | urb->urb.transfer_buffer = addr; | ||
1137 | urb->urb.transfer_dma = dma; | ||
1138 | urb->urb.transfer_buffer_length = max_packet_size; | ||
1139 | urb->urb.number_of_packets = 1; | ||
1140 | urb->urb.interval = 1; | ||
1141 | urb->urb.context = ua; | ||
1142 | urb->urb.complete = urb_complete; | ||
1143 | urb->urb.iso_frame_desc[0].offset = 0; | ||
1144 | urb->urb.iso_frame_desc[0].length = max_packet_size; | ||
1145 | stream->urbs[u++] = urb; | ||
1146 | size -= max_packet_size; | ||
1147 | addr += max_packet_size; | ||
1148 | dma += max_packet_size; | ||
1149 | } | ||
1150 | } | ||
1151 | if (u == stream->queue_length) | ||
1152 | return 0; | ||
1153 | bufsize_error: | ||
1154 | dev_err(&ua->dev->dev, "internal buffer size error\n"); | ||
1155 | return -ENXIO; | ||
1156 | } | ||
1157 | |||
1158 | static void free_stream_urbs(struct ua101_stream *stream) | ||
1159 | { | ||
1160 | unsigned int i; | ||
1161 | |||
1162 | for (i = 0; i < stream->queue_length; ++i) | ||
1163 | kfree(stream->urbs[i]); | ||
1164 | } | ||
1165 | |||
1166 | static void free_usb_related_resources(struct ua101 *ua, | ||
1167 | struct usb_interface *interface) | ||
1168 | { | ||
1169 | unsigned int i; | ||
1170 | |||
1171 | free_stream_urbs(&ua->capture); | ||
1172 | free_stream_urbs(&ua->playback); | ||
1173 | free_stream_buffers(ua, &ua->capture); | ||
1174 | free_stream_buffers(ua, &ua->playback); | ||
1175 | |||
1176 | for (i = 0; i < ARRAY_SIZE(ua->intf); ++i) | ||
1177 | if (ua->intf[i]) { | ||
1178 | usb_set_intfdata(ua->intf[i], NULL); | ||
1179 | if (ua->intf[i] != interface) | ||
1180 | usb_driver_release_interface(&ua101_driver, | ||
1181 | ua->intf[i]); | ||
1182 | } | ||
1183 | } | ||
1184 | |||
1185 | static void ua101_card_free(struct snd_card *card) | ||
1186 | { | ||
1187 | struct ua101 *ua = card->private_data; | ||
1188 | |||
1189 | mutex_destroy(&ua->mutex); | ||
1190 | } | ||
1191 | |||
1192 | static int ua101_probe(struct usb_interface *interface, | ||
1193 | const struct usb_device_id *usb_id) | ||
1194 | { | ||
1195 | static const struct snd_usb_midi_endpoint_info midi_ep = { | ||
1196 | .out_cables = 0x0001, | ||
1197 | .in_cables = 0x0001 | ||
1198 | }; | ||
1199 | static const struct snd_usb_audio_quirk midi_quirk = { | ||
1200 | .type = QUIRK_MIDI_FIXED_ENDPOINT, | ||
1201 | .data = &midi_ep | ||
1202 | }; | ||
1203 | struct snd_card *card; | ||
1204 | struct ua101 *ua; | ||
1205 | unsigned int card_index, i; | ||
1206 | char usb_path[32]; | ||
1207 | int err; | ||
1208 | |||
1209 | if (interface->altsetting->desc.bInterfaceNumber != 0) | ||
1210 | return -ENODEV; | ||
1211 | |||
1212 | mutex_lock(&devices_mutex); | ||
1213 | |||
1214 | for (card_index = 0; card_index < SNDRV_CARDS; ++card_index) | ||
1215 | if (enable[card_index] && !(devices_used & (1 << card_index))) | ||
1216 | break; | ||
1217 | if (card_index >= SNDRV_CARDS) { | ||
1218 | mutex_unlock(&devices_mutex); | ||
1219 | return -ENOENT; | ||
1220 | } | ||
1221 | err = snd_card_create(index[card_index], id[card_index], THIS_MODULE, | ||
1222 | sizeof(*ua), &card); | ||
1223 | if (err < 0) { | ||
1224 | mutex_unlock(&devices_mutex); | ||
1225 | return err; | ||
1226 | } | ||
1227 | card->private_free = ua101_card_free; | ||
1228 | ua = card->private_data; | ||
1229 | ua->dev = interface_to_usbdev(interface); | ||
1230 | ua->card = card; | ||
1231 | ua->card_index = card_index; | ||
1232 | INIT_LIST_HEAD(&ua->midi_list); | ||
1233 | spin_lock_init(&ua->lock); | ||
1234 | mutex_init(&ua->mutex); | ||
1235 | INIT_LIST_HEAD(&ua->ready_playback_urbs); | ||
1236 | tasklet_init(&ua->playback_tasklet, | ||
1237 | playback_tasklet, (unsigned long)ua); | ||
1238 | init_waitqueue_head(&ua->alsa_capture_wait); | ||
1239 | init_waitqueue_head(&ua->rate_feedback_wait); | ||
1240 | init_waitqueue_head(&ua->alsa_playback_wait); | ||
1241 | |||
1242 | #ifdef UA1A_HACK | ||
1243 | if (ua->dev->descriptor.idProduct == cpu_to_le16(0x0018)) { | ||
1244 | ua->intf[2] = interface; | ||
1245 | ua->intf[0] = usb_ifnum_to_if(ua->dev, 1); | ||
1246 | ua->intf[1] = usb_ifnum_to_if(ua->dev, 2); | ||
1247 | usb_driver_claim_interface(&ua101_driver, ua->intf[0], ua); | ||
1248 | usb_driver_claim_interface(&ua101_driver, ua->intf[1], ua); | ||
1249 | } else { | ||
1250 | #endif | ||
1251 | ua->intf[0] = interface; | ||
1252 | for (i = 1; i < ARRAY_SIZE(ua->intf); ++i) { | ||
1253 | ua->intf[i] = usb_ifnum_to_if(ua->dev, i); | ||
1254 | if (!ua->intf[i]) { | ||
1255 | dev_err(&ua->dev->dev, "interface %u not found\n", i); | ||
1256 | err = -ENXIO; | ||
1257 | goto probe_error; | ||
1258 | } | ||
1259 | err = usb_driver_claim_interface(&ua101_driver, | ||
1260 | ua->intf[i], ua); | ||
1261 | if (err < 0) { | ||
1262 | ua->intf[i] = NULL; | ||
1263 | err = -EBUSY; | ||
1264 | goto probe_error; | ||
1265 | } | ||
1266 | } | ||
1267 | #ifdef UA1A_HACK | ||
1268 | } | ||
1269 | #endif | ||
1270 | |||
1271 | snd_card_set_dev(card, &interface->dev); | ||
1272 | |||
1273 | #ifdef UA1A_HACK | ||
1274 | if (ua->dev->descriptor.idProduct == cpu_to_le16(0x0018)) { | ||
1275 | ua->format_bit = SNDRV_PCM_FMTBIT_S16_LE; | ||
1276 | ua->rate = 44100; | ||
1277 | ua->packets_per_second = 1000; | ||
1278 | ua->capture.channels = 2; | ||
1279 | ua->playback.channels = 2; | ||
1280 | ua->capture.frame_bytes = 4; | ||
1281 | ua->playback.frame_bytes = 4; | ||
1282 | ua->capture.usb_pipe = usb_rcvisocpipe(ua->dev, 2); | ||
1283 | ua->playback.usb_pipe = usb_sndisocpipe(ua->dev, 1); | ||
1284 | ua->capture.max_packet_bytes = 192; | ||
1285 | ua->playback.max_packet_bytes = 192; | ||
1286 | } else { | ||
1287 | #endif | ||
1288 | err = detect_usb_format(ua); | ||
1289 | if (err < 0) | ||
1290 | goto probe_error; | ||
1291 | #ifdef UA1A_HACK | ||
1292 | } | ||
1293 | #endif | ||
1294 | |||
1295 | strcpy(card->driver, "UA-101"); | ||
1296 | strcpy(card->shortname, "UA-101"); | ||
1297 | usb_make_path(ua->dev, usb_path, sizeof(usb_path)); | ||
1298 | snprintf(ua->card->longname, sizeof(ua->card->longname), | ||
1299 | "EDIROL UA-101 (serial %s), %u Hz at %s, %s speed", | ||
1300 | ua->dev->serial ? ua->dev->serial : "?", ua->rate, usb_path, | ||
1301 | ua->dev->speed == USB_SPEED_HIGH ? "high" : "full"); | ||
1302 | |||
1303 | err = alloc_stream_buffers(ua, &ua->capture); | ||
1304 | if (err < 0) | ||
1305 | goto probe_error; | ||
1306 | err = alloc_stream_buffers(ua, &ua->playback); | ||
1307 | if (err < 0) | ||
1308 | goto probe_error; | ||
1309 | |||
1310 | err = alloc_stream_urbs(ua, &ua->capture, capture_urb_complete); | ||
1311 | if (err < 0) | ||
1312 | goto probe_error; | ||
1313 | err = alloc_stream_urbs(ua, &ua->playback, playback_urb_complete); | ||
1314 | if (err < 0) | ||
1315 | goto probe_error; | ||
1316 | |||
1317 | err = snd_pcm_new(card, "UA-101", 0, 1, 1, &ua->pcm); | ||
1318 | if (err < 0) | ||
1319 | goto probe_error; | ||
1320 | ua->pcm->private_data = ua; | ||
1321 | strcpy(ua->pcm->name, "UA-101"); | ||
1322 | snd_pcm_set_ops(ua->pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_pcm_ops); | ||
1323 | snd_pcm_set_ops(ua->pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_pcm_ops); | ||
1324 | |||
1325 | #ifdef UA1A_HACK | ||
1326 | if (ua->dev->descriptor.idProduct != cpu_to_le16(0x0018)) { | ||
1327 | #endif | ||
1328 | err = snd_usbmidi_create(card, ua->intf[INTF_MIDI], | ||
1329 | &ua->midi_list, &midi_quirk); | ||
1330 | if (err < 0) | ||
1331 | goto probe_error; | ||
1332 | #ifdef UA1A_HACK | ||
1333 | } | ||
1334 | #endif | ||
1335 | |||
1336 | err = snd_card_register(card); | ||
1337 | if (err < 0) | ||
1338 | goto probe_error; | ||
1339 | |||
1340 | usb_set_intfdata(interface, ua); | ||
1341 | devices_used |= 1 << card_index; | ||
1342 | |||
1343 | mutex_unlock(&devices_mutex); | ||
1344 | return 0; | ||
1345 | |||
1346 | probe_error: | ||
1347 | free_usb_related_resources(ua, interface); | ||
1348 | snd_card_free(card); | ||
1349 | mutex_unlock(&devices_mutex); | ||
1350 | return err; | ||
1351 | } | ||
1352 | |||
1353 | static void ua101_disconnect(struct usb_interface *interface) | ||
1354 | { | ||
1355 | struct ua101 *ua = usb_get_intfdata(interface); | ||
1356 | struct list_head *midi; | ||
1357 | |||
1358 | if (!ua) | ||
1359 | return; | ||
1360 | |||
1361 | mutex_lock(&devices_mutex); | ||
1362 | |||
1363 | set_bit(DISCONNECTED, &ua->states); | ||
1364 | wake_up(&ua->rate_feedback_wait); | ||
1365 | |||
1366 | /* make sure that userspace cannot create new requests */ | ||
1367 | snd_card_disconnect(ua->card); | ||
1368 | |||
1369 | /* make sure that there are no pending USB requests */ | ||
1370 | __list_for_each(midi, &ua->midi_list) | ||
1371 | snd_usbmidi_disconnect(midi); | ||
1372 | abort_alsa_playback(ua); | ||
1373 | abort_alsa_capture(ua); | ||
1374 | mutex_lock(&ua->mutex); | ||
1375 | stop_usb_playback(ua); | ||
1376 | stop_usb_capture(ua); | ||
1377 | mutex_unlock(&ua->mutex); | ||
1378 | |||
1379 | free_usb_related_resources(ua, interface); | ||
1380 | |||
1381 | devices_used &= ~(1 << ua->card_index); | ||
1382 | |||
1383 | snd_card_free_when_closed(ua->card); | ||
1384 | |||
1385 | mutex_unlock(&devices_mutex); | ||
1386 | } | ||
1387 | |||
1388 | static struct usb_device_id ua101_ids[] = { | ||
1389 | #ifdef UA1A_HACK | ||
1390 | { USB_DEVICE(0x0582, 0x0018) }, | ||
1391 | #endif | ||
1392 | { USB_DEVICE(0x0582, 0x007d) }, | ||
1393 | { USB_DEVICE(0x0582, 0x008d) }, | ||
1394 | { } | ||
1395 | }; | ||
1396 | MODULE_DEVICE_TABLE(usb, ua101_ids); | ||
1397 | |||
1398 | static struct usb_driver ua101_driver = { | ||
1399 | .name = "snd-ua101", | ||
1400 | .id_table = ua101_ids, | ||
1401 | .probe = ua101_probe, | ||
1402 | .disconnect = ua101_disconnect, | ||
1403 | #if 0 | ||
1404 | .suspend = ua101_suspend, | ||
1405 | .resume = ua101_resume, | ||
1406 | #endif | ||
1407 | }; | ||
1408 | |||
1409 | static int __init alsa_card_ua101_init(void) | ||
1410 | { | ||
1411 | return usb_register(&ua101_driver); | ||
1412 | } | ||
1413 | |||
1414 | static void __exit alsa_card_ua101_exit(void) | ||
1415 | { | ||
1416 | usb_deregister(&ua101_driver); | ||
1417 | mutex_destroy(&devices_mutex); | ||
1418 | } | ||
1419 | |||
1420 | module_init(alsa_card_ua101_init); | ||
1421 | module_exit(alsa_card_ua101_exit); | ||
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 9edef4684978..c539f7fe292f 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c | |||
@@ -44,9 +44,11 @@ | |||
44 | #include <linux/slab.h> | 44 | #include <linux/slab.h> |
45 | #include <linux/string.h> | 45 | #include <linux/string.h> |
46 | #include <linux/usb.h> | 46 | #include <linux/usb.h> |
47 | #include <linux/vmalloc.h> | ||
48 | #include <linux/moduleparam.h> | 47 | #include <linux/moduleparam.h> |
49 | #include <linux/mutex.h> | 48 | #include <linux/mutex.h> |
49 | #include <linux/usb/audio.h> | ||
50 | #include <linux/usb/ch9.h> | ||
51 | |||
50 | #include <sound/core.h> | 52 | #include <sound/core.h> |
51 | #include <sound/info.h> | 53 | #include <sound/info.h> |
52 | #include <sound/pcm.h> | 54 | #include <sound/pcm.h> |
@@ -170,11 +172,12 @@ struct snd_usb_substream { | |||
170 | unsigned int curpacksize; /* current packet size in bytes (for capture) */ | 172 | unsigned int curpacksize; /* current packet size in bytes (for capture) */ |
171 | unsigned int curframesize; /* current packet size in frames (for capture) */ | 173 | unsigned int curframesize; /* current packet size in frames (for capture) */ |
172 | unsigned int fill_max: 1; /* fill max packet size always */ | 174 | unsigned int fill_max: 1; /* fill max packet size always */ |
175 | unsigned int txfr_quirk:1; /* allow sub-frame alignment */ | ||
173 | unsigned int fmt_type; /* USB audio format type (1-3) */ | 176 | unsigned int fmt_type; /* USB audio format type (1-3) */ |
174 | 177 | ||
175 | unsigned int running: 1; /* running status */ | 178 | unsigned int running: 1; /* running status */ |
176 | 179 | ||
177 | unsigned int hwptr_done; /* processed frame position in the buffer */ | 180 | unsigned int hwptr_done; /* processed byte position in the buffer */ |
178 | unsigned int transfer_done; /* processed frames since last period update */ | 181 | unsigned int transfer_done; /* processed frames since last period update */ |
179 | unsigned long active_mask; /* bitmask of active urbs */ | 182 | unsigned long active_mask; /* bitmask of active urbs */ |
180 | unsigned long unlink_mask; /* bitmask of unlinked urbs */ | 183 | unsigned long unlink_mask; /* bitmask of unlinked urbs */ |
@@ -343,7 +346,7 @@ static int retire_capture_urb(struct snd_usb_substream *subs, | |||
343 | unsigned long flags; | 346 | unsigned long flags; |
344 | unsigned char *cp; | 347 | unsigned char *cp; |
345 | int i; | 348 | int i; |
346 | unsigned int stride, len, oldptr; | 349 | unsigned int stride, frames, bytes, oldptr; |
347 | int period_elapsed = 0; | 350 | int period_elapsed = 0; |
348 | 351 | ||
349 | stride = runtime->frame_bits >> 3; | 352 | stride = runtime->frame_bits >> 3; |
@@ -354,29 +357,39 @@ static int retire_capture_urb(struct snd_usb_substream *subs, | |||
354 | snd_printd(KERN_ERR "frame %d active: %d\n", i, urb->iso_frame_desc[i].status); | 357 | snd_printd(KERN_ERR "frame %d active: %d\n", i, urb->iso_frame_desc[i].status); |
355 | // continue; | 358 | // continue; |
356 | } | 359 | } |
357 | len = urb->iso_frame_desc[i].actual_length / stride; | 360 | bytes = urb->iso_frame_desc[i].actual_length; |
358 | if (! len) | 361 | frames = bytes / stride; |
359 | continue; | 362 | if (!subs->txfr_quirk) |
363 | bytes = frames * stride; | ||
364 | if (bytes % (runtime->sample_bits >> 3) != 0) { | ||
365 | #ifdef CONFIG_SND_DEBUG_VERBOSE | ||
366 | int oldbytes = bytes; | ||
367 | #endif | ||
368 | bytes = frames * stride; | ||
369 | snd_printdd(KERN_ERR "Corrected urb data len. %d->%d\n", | ||
370 | oldbytes, bytes); | ||
371 | } | ||
360 | /* update the current pointer */ | 372 | /* update the current pointer */ |
361 | spin_lock_irqsave(&subs->lock, flags); | 373 | spin_lock_irqsave(&subs->lock, flags); |
362 | oldptr = subs->hwptr_done; | 374 | oldptr = subs->hwptr_done; |
363 | subs->hwptr_done += len; | 375 | subs->hwptr_done += bytes; |
364 | if (subs->hwptr_done >= runtime->buffer_size) | 376 | if (subs->hwptr_done >= runtime->buffer_size * stride) |
365 | subs->hwptr_done -= runtime->buffer_size; | 377 | subs->hwptr_done -= runtime->buffer_size * stride; |
366 | subs->transfer_done += len; | 378 | frames = (bytes + (oldptr % stride)) / stride; |
379 | subs->transfer_done += frames; | ||
367 | if (subs->transfer_done >= runtime->period_size) { | 380 | if (subs->transfer_done >= runtime->period_size) { |
368 | subs->transfer_done -= runtime->period_size; | 381 | subs->transfer_done -= runtime->period_size; |
369 | period_elapsed = 1; | 382 | period_elapsed = 1; |
370 | } | 383 | } |
371 | spin_unlock_irqrestore(&subs->lock, flags); | 384 | spin_unlock_irqrestore(&subs->lock, flags); |
372 | /* copy a data chunk */ | 385 | /* copy a data chunk */ |
373 | if (oldptr + len > runtime->buffer_size) { | 386 | if (oldptr + bytes > runtime->buffer_size * stride) { |
374 | unsigned int cnt = runtime->buffer_size - oldptr; | 387 | unsigned int bytes1 = |
375 | unsigned int blen = cnt * stride; | 388 | runtime->buffer_size * stride - oldptr; |
376 | memcpy(runtime->dma_area + oldptr * stride, cp, blen); | 389 | memcpy(runtime->dma_area + oldptr, cp, bytes1); |
377 | memcpy(runtime->dma_area, cp + blen, len * stride - blen); | 390 | memcpy(runtime->dma_area, cp + bytes1, bytes - bytes1); |
378 | } else { | 391 | } else { |
379 | memcpy(runtime->dma_area + oldptr * stride, cp, len * stride); | 392 | memcpy(runtime->dma_area + oldptr, cp, bytes); |
380 | } | 393 | } |
381 | } | 394 | } |
382 | if (period_elapsed) | 395 | if (period_elapsed) |
@@ -563,34 +576,34 @@ static int prepare_playback_urb(struct snd_usb_substream *subs, | |||
563 | struct snd_pcm_runtime *runtime, | 576 | struct snd_pcm_runtime *runtime, |
564 | struct urb *urb) | 577 | struct urb *urb) |
565 | { | 578 | { |
566 | int i, stride, offs; | 579 | int i, stride; |
567 | unsigned int counts; | 580 | unsigned int counts, frames, bytes; |
568 | unsigned long flags; | 581 | unsigned long flags; |
569 | int period_elapsed = 0; | 582 | int period_elapsed = 0; |
570 | struct snd_urb_ctx *ctx = urb->context; | 583 | struct snd_urb_ctx *ctx = urb->context; |
571 | 584 | ||
572 | stride = runtime->frame_bits >> 3; | 585 | stride = runtime->frame_bits >> 3; |
573 | 586 | ||
574 | offs = 0; | 587 | frames = 0; |
575 | urb->dev = ctx->subs->dev; /* we need to set this at each time */ | 588 | urb->dev = ctx->subs->dev; /* we need to set this at each time */ |
576 | urb->number_of_packets = 0; | 589 | urb->number_of_packets = 0; |
577 | spin_lock_irqsave(&subs->lock, flags); | 590 | spin_lock_irqsave(&subs->lock, flags); |
578 | for (i = 0; i < ctx->packets; i++) { | 591 | for (i = 0; i < ctx->packets; i++) { |
579 | counts = snd_usb_audio_next_packet_size(subs); | 592 | counts = snd_usb_audio_next_packet_size(subs); |
580 | /* set up descriptor */ | 593 | /* set up descriptor */ |
581 | urb->iso_frame_desc[i].offset = offs * stride; | 594 | urb->iso_frame_desc[i].offset = frames * stride; |
582 | urb->iso_frame_desc[i].length = counts * stride; | 595 | urb->iso_frame_desc[i].length = counts * stride; |
583 | offs += counts; | 596 | frames += counts; |
584 | urb->number_of_packets++; | 597 | urb->number_of_packets++; |
585 | subs->transfer_done += counts; | 598 | subs->transfer_done += counts; |
586 | if (subs->transfer_done >= runtime->period_size) { | 599 | if (subs->transfer_done >= runtime->period_size) { |
587 | subs->transfer_done -= runtime->period_size; | 600 | subs->transfer_done -= runtime->period_size; |
588 | period_elapsed = 1; | 601 | period_elapsed = 1; |
589 | if (subs->fmt_type == USB_FORMAT_TYPE_II) { | 602 | if (subs->fmt_type == UAC_FORMAT_TYPE_II) { |
590 | if (subs->transfer_done > 0) { | 603 | if (subs->transfer_done > 0) { |
591 | /* FIXME: fill-max mode is not | 604 | /* FIXME: fill-max mode is not |
592 | * supported yet */ | 605 | * supported yet */ |
593 | offs -= subs->transfer_done; | 606 | frames -= subs->transfer_done; |
594 | counts -= subs->transfer_done; | 607 | counts -= subs->transfer_done; |
595 | urb->iso_frame_desc[i].length = | 608 | urb->iso_frame_desc[i].length = |
596 | counts * stride; | 609 | counts * stride; |
@@ -600,7 +613,7 @@ static int prepare_playback_urb(struct snd_usb_substream *subs, | |||
600 | if (i < ctx->packets) { | 613 | if (i < ctx->packets) { |
601 | /* add a transfer delimiter */ | 614 | /* add a transfer delimiter */ |
602 | urb->iso_frame_desc[i].offset = | 615 | urb->iso_frame_desc[i].offset = |
603 | offs * stride; | 616 | frames * stride; |
604 | urb->iso_frame_desc[i].length = 0; | 617 | urb->iso_frame_desc[i].length = 0; |
605 | urb->number_of_packets++; | 618 | urb->number_of_packets++; |
606 | } | 619 | } |
@@ -610,26 +623,25 @@ static int prepare_playback_urb(struct snd_usb_substream *subs, | |||
610 | if (period_elapsed) /* finish at the period boundary */ | 623 | if (period_elapsed) /* finish at the period boundary */ |
611 | break; | 624 | break; |
612 | } | 625 | } |
613 | if (subs->hwptr_done + offs > runtime->buffer_size) { | 626 | bytes = frames * stride; |
627 | if (subs->hwptr_done + bytes > runtime->buffer_size * stride) { | ||
614 | /* err, the transferred area goes over buffer boundary. */ | 628 | /* err, the transferred area goes over buffer boundary. */ |
615 | unsigned int len = runtime->buffer_size - subs->hwptr_done; | 629 | unsigned int bytes1 = |
630 | runtime->buffer_size * stride - subs->hwptr_done; | ||
616 | memcpy(urb->transfer_buffer, | 631 | memcpy(urb->transfer_buffer, |
617 | runtime->dma_area + subs->hwptr_done * stride, | 632 | runtime->dma_area + subs->hwptr_done, bytes1); |
618 | len * stride); | 633 | memcpy(urb->transfer_buffer + bytes1, |
619 | memcpy(urb->transfer_buffer + len * stride, | 634 | runtime->dma_area, bytes - bytes1); |
620 | runtime->dma_area, | ||
621 | (offs - len) * stride); | ||
622 | } else { | 635 | } else { |
623 | memcpy(urb->transfer_buffer, | 636 | memcpy(urb->transfer_buffer, |
624 | runtime->dma_area + subs->hwptr_done * stride, | 637 | runtime->dma_area + subs->hwptr_done, bytes); |
625 | offs * stride); | ||
626 | } | 638 | } |
627 | subs->hwptr_done += offs; | 639 | subs->hwptr_done += bytes; |
628 | if (subs->hwptr_done >= runtime->buffer_size) | 640 | if (subs->hwptr_done >= runtime->buffer_size * stride) |
629 | subs->hwptr_done -= runtime->buffer_size; | 641 | subs->hwptr_done -= runtime->buffer_size * stride; |
630 | runtime->delay += offs; | 642 | runtime->delay += frames; |
631 | spin_unlock_irqrestore(&subs->lock, flags); | 643 | spin_unlock_irqrestore(&subs->lock, flags); |
632 | urb->transfer_buffer_length = offs * stride; | 644 | urb->transfer_buffer_length = bytes; |
633 | if (period_elapsed) | 645 | if (period_elapsed) |
634 | snd_pcm_period_elapsed(subs->pcm_substream); | 646 | snd_pcm_period_elapsed(subs->pcm_substream); |
635 | return 0; | 647 | return 0; |
@@ -735,41 +747,6 @@ static void snd_complete_sync_urb(struct urb *urb) | |||
735 | } | 747 | } |
736 | 748 | ||
737 | 749 | ||
738 | /* get the physical page pointer at the given offset */ | ||
739 | static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs, | ||
740 | unsigned long offset) | ||
741 | { | ||
742 | void *pageptr = subs->runtime->dma_area + offset; | ||
743 | return vmalloc_to_page(pageptr); | ||
744 | } | ||
745 | |||
746 | /* allocate virtual buffer; may be called more than once */ | ||
747 | static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, size_t size) | ||
748 | { | ||
749 | struct snd_pcm_runtime *runtime = subs->runtime; | ||
750 | if (runtime->dma_area) { | ||
751 | if (runtime->dma_bytes >= size) | ||
752 | return 0; /* already large enough */ | ||
753 | vfree(runtime->dma_area); | ||
754 | } | ||
755 | runtime->dma_area = vmalloc_user(size); | ||
756 | if (!runtime->dma_area) | ||
757 | return -ENOMEM; | ||
758 | runtime->dma_bytes = size; | ||
759 | return 0; | ||
760 | } | ||
761 | |||
762 | /* free virtual buffer; may be called more than once */ | ||
763 | static int snd_pcm_free_vmalloc_buffer(struct snd_pcm_substream *subs) | ||
764 | { | ||
765 | struct snd_pcm_runtime *runtime = subs->runtime; | ||
766 | |||
767 | vfree(runtime->dma_area); | ||
768 | runtime->dma_area = NULL; | ||
769 | return 0; | ||
770 | } | ||
771 | |||
772 | |||
773 | /* | 750 | /* |
774 | * unlink active urbs. | 751 | * unlink active urbs. |
775 | */ | 752 | */ |
@@ -937,18 +914,18 @@ static int wait_clear_urbs(struct snd_usb_substream *subs) | |||
937 | 914 | ||
938 | 915 | ||
939 | /* | 916 | /* |
940 | * return the current pcm pointer. just return the hwptr_done value. | 917 | * return the current pcm pointer. just based on the hwptr_done value. |
941 | */ | 918 | */ |
942 | static snd_pcm_uframes_t snd_usb_pcm_pointer(struct snd_pcm_substream *substream) | 919 | static snd_pcm_uframes_t snd_usb_pcm_pointer(struct snd_pcm_substream *substream) |
943 | { | 920 | { |
944 | struct snd_usb_substream *subs; | 921 | struct snd_usb_substream *subs; |
945 | snd_pcm_uframes_t hwptr_done; | 922 | unsigned int hwptr_done; |
946 | 923 | ||
947 | subs = (struct snd_usb_substream *)substream->runtime->private_data; | 924 | subs = (struct snd_usb_substream *)substream->runtime->private_data; |
948 | spin_lock(&subs->lock); | 925 | spin_lock(&subs->lock); |
949 | hwptr_done = subs->hwptr_done; | 926 | hwptr_done = subs->hwptr_done; |
950 | spin_unlock(&subs->lock); | 927 | spin_unlock(&subs->lock); |
951 | return hwptr_done; | 928 | return hwptr_done / (substream->runtime->frame_bits >> 3); |
952 | } | 929 | } |
953 | 930 | ||
954 | 931 | ||
@@ -1130,7 +1107,7 @@ static int init_substream_urbs(struct snd_usb_substream *subs, unsigned int peri | |||
1130 | u->packets = (i + 1) * total_packs / subs->nurbs | 1107 | u->packets = (i + 1) * total_packs / subs->nurbs |
1131 | - i * total_packs / subs->nurbs; | 1108 | - i * total_packs / subs->nurbs; |
1132 | u->buffer_size = maxsize * u->packets; | 1109 | u->buffer_size = maxsize * u->packets; |
1133 | if (subs->fmt_type == USB_FORMAT_TYPE_II) | 1110 | if (subs->fmt_type == UAC_FORMAT_TYPE_II) |
1134 | u->packets++; /* for transfer delimiter */ | 1111 | u->packets++; /* for transfer delimiter */ |
1135 | u->urb = usb_alloc_urb(u->packets, GFP_KERNEL); | 1112 | u->urb = usb_alloc_urb(u->packets, GFP_KERNEL); |
1136 | if (!u->urb) | 1113 | if (!u->urb) |
@@ -1206,7 +1183,7 @@ static struct audioformat *find_format(struct snd_usb_substream *subs, unsigned | |||
1206 | if (i >= fp->nr_rates) | 1183 | if (i >= fp->nr_rates) |
1207 | continue; | 1184 | continue; |
1208 | } | 1185 | } |
1209 | attr = fp->ep_attr & EP_ATTR_MASK; | 1186 | attr = fp->ep_attr & USB_ENDPOINT_SYNCTYPE; |
1210 | if (! found) { | 1187 | if (! found) { |
1211 | found = fp; | 1188 | found = fp; |
1212 | cur_attr = attr; | 1189 | cur_attr = attr; |
@@ -1218,14 +1195,14 @@ static struct audioformat *find_format(struct snd_usb_substream *subs, unsigned | |||
1218 | * M-audio audiophile USB. | 1195 | * M-audio audiophile USB. |
1219 | */ | 1196 | */ |
1220 | if (attr != cur_attr) { | 1197 | if (attr != cur_attr) { |
1221 | if ((attr == EP_ATTR_ASYNC && | 1198 | if ((attr == USB_ENDPOINT_SYNC_ASYNC && |
1222 | subs->direction == SNDRV_PCM_STREAM_PLAYBACK) || | 1199 | subs->direction == SNDRV_PCM_STREAM_PLAYBACK) || |
1223 | (attr == EP_ATTR_ADAPTIVE && | 1200 | (attr == USB_ENDPOINT_SYNC_ADAPTIVE && |
1224 | subs->direction == SNDRV_PCM_STREAM_CAPTURE)) | 1201 | subs->direction == SNDRV_PCM_STREAM_CAPTURE)) |
1225 | continue; | 1202 | continue; |
1226 | if ((cur_attr == EP_ATTR_ASYNC && | 1203 | if ((cur_attr == USB_ENDPOINT_SYNC_ASYNC && |
1227 | subs->direction == SNDRV_PCM_STREAM_PLAYBACK) || | 1204 | subs->direction == SNDRV_PCM_STREAM_PLAYBACK) || |
1228 | (cur_attr == EP_ATTR_ADAPTIVE && | 1205 | (cur_attr == USB_ENDPOINT_SYNC_ADAPTIVE && |
1229 | subs->direction == SNDRV_PCM_STREAM_CAPTURE)) { | 1206 | subs->direction == SNDRV_PCM_STREAM_CAPTURE)) { |
1230 | found = fp; | 1207 | found = fp; |
1231 | cur_attr = attr; | 1208 | cur_attr = attr; |
@@ -1255,11 +1232,11 @@ static int init_usb_pitch(struct usb_device *dev, int iface, | |||
1255 | 1232 | ||
1256 | ep = get_endpoint(alts, 0)->bEndpointAddress; | 1233 | ep = get_endpoint(alts, 0)->bEndpointAddress; |
1257 | /* if endpoint has pitch control, enable it */ | 1234 | /* if endpoint has pitch control, enable it */ |
1258 | if (fmt->attributes & EP_CS_ATTR_PITCH_CONTROL) { | 1235 | if (fmt->attributes & UAC_EP_CS_ATTR_PITCH_CONTROL) { |
1259 | data[0] = 1; | 1236 | data[0] = 1; |
1260 | if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, | 1237 | if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, |
1261 | USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, | 1238 | USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, |
1262 | PITCH_CONTROL << 8, ep, data, 1, 1000)) < 0) { | 1239 | UAC_EP_CS_ATTR_PITCH_CONTROL << 8, ep, data, 1, 1000)) < 0) { |
1263 | snd_printk(KERN_ERR "%d:%d:%d: cannot set enable PITCH\n", | 1240 | snd_printk(KERN_ERR "%d:%d:%d: cannot set enable PITCH\n", |
1264 | dev->devnum, iface, ep); | 1241 | dev->devnum, iface, ep); |
1265 | return err; | 1242 | return err; |
@@ -1278,21 +1255,21 @@ static int init_usb_sample_rate(struct usb_device *dev, int iface, | |||
1278 | 1255 | ||
1279 | ep = get_endpoint(alts, 0)->bEndpointAddress; | 1256 | ep = get_endpoint(alts, 0)->bEndpointAddress; |
1280 | /* if endpoint has sampling rate control, set it */ | 1257 | /* if endpoint has sampling rate control, set it */ |
1281 | if (fmt->attributes & EP_CS_ATTR_SAMPLE_RATE) { | 1258 | if (fmt->attributes & UAC_EP_CS_ATTR_SAMPLE_RATE) { |
1282 | int crate; | 1259 | int crate; |
1283 | data[0] = rate; | 1260 | data[0] = rate; |
1284 | data[1] = rate >> 8; | 1261 | data[1] = rate >> 8; |
1285 | data[2] = rate >> 16; | 1262 | data[2] = rate >> 16; |
1286 | if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, | 1263 | if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, |
1287 | USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, | 1264 | USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, |
1288 | SAMPLING_FREQ_CONTROL << 8, ep, data, 3, 1000)) < 0) { | 1265 | UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, data, 3, 1000)) < 0) { |
1289 | snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d to ep %#x\n", | 1266 | snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d to ep %#x\n", |
1290 | dev->devnum, iface, fmt->altsetting, rate, ep); | 1267 | dev->devnum, iface, fmt->altsetting, rate, ep); |
1291 | return err; | 1268 | return err; |
1292 | } | 1269 | } |
1293 | if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, | 1270 | if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR, |
1294 | USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_IN, | 1271 | USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_IN, |
1295 | SAMPLING_FREQ_CONTROL << 8, ep, data, 3, 1000)) < 0) { | 1272 | UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, data, 3, 1000)) < 0) { |
1296 | snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq at ep %#x\n", | 1273 | snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq at ep %#x\n", |
1297 | dev->devnum, iface, fmt->altsetting, ep); | 1274 | dev->devnum, iface, fmt->altsetting, ep); |
1298 | return 0; /* some devices don't support reading */ | 1275 | return 0; /* some devices don't support reading */ |
@@ -1307,6 +1284,47 @@ static int init_usb_sample_rate(struct usb_device *dev, int iface, | |||
1307 | } | 1284 | } |
1308 | 1285 | ||
1309 | /* | 1286 | /* |
1287 | * For E-Mu 0404USB/0202USB/TrackerPre sample rate should be set for device, | ||
1288 | * not for interface. | ||
1289 | */ | ||
1290 | static void set_format_emu_quirk(struct snd_usb_substream *subs, | ||
1291 | struct audioformat *fmt) | ||
1292 | { | ||
1293 | unsigned char emu_samplerate_id = 0; | ||
1294 | |||
1295 | /* When capture is active | ||
1296 | * sample rate shouldn't be changed | ||
1297 | * by playback substream | ||
1298 | */ | ||
1299 | if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) { | ||
1300 | if (subs->stream->substream[SNDRV_PCM_STREAM_CAPTURE].interface != -1) | ||
1301 | return; | ||
1302 | } | ||
1303 | |||
1304 | switch (fmt->rate_min) { | ||
1305 | case 48000: | ||
1306 | emu_samplerate_id = EMU_QUIRK_SR_48000HZ; | ||
1307 | break; | ||
1308 | case 88200: | ||
1309 | emu_samplerate_id = EMU_QUIRK_SR_88200HZ; | ||
1310 | break; | ||
1311 | case 96000: | ||
1312 | emu_samplerate_id = EMU_QUIRK_SR_96000HZ; | ||
1313 | break; | ||
1314 | case 176400: | ||
1315 | emu_samplerate_id = EMU_QUIRK_SR_176400HZ; | ||
1316 | break; | ||
1317 | case 192000: | ||
1318 | emu_samplerate_id = EMU_QUIRK_SR_192000HZ; | ||
1319 | break; | ||
1320 | default: | ||
1321 | emu_samplerate_id = EMU_QUIRK_SR_44100HZ; | ||
1322 | break; | ||
1323 | } | ||
1324 | snd_emuusb_set_samplerate(subs->stream->chip, emu_samplerate_id); | ||
1325 | } | ||
1326 | |||
1327 | /* | ||
1310 | * find a matching format and set up the interface | 1328 | * find a matching format and set up the interface |
1311 | */ | 1329 | */ |
1312 | static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) | 1330 | static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) |
@@ -1369,9 +1387,9 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) | |||
1369 | * descriptors which fool us. if it has only one EP, | 1387 | * descriptors which fool us. if it has only one EP, |
1370 | * assume it as adaptive-out or sync-in. | 1388 | * assume it as adaptive-out or sync-in. |
1371 | */ | 1389 | */ |
1372 | attr = fmt->ep_attr & EP_ATTR_MASK; | 1390 | attr = fmt->ep_attr & USB_ENDPOINT_SYNCTYPE; |
1373 | if (((is_playback && attr == EP_ATTR_ASYNC) || | 1391 | if (((is_playback && attr == USB_ENDPOINT_SYNC_ASYNC) || |
1374 | (! is_playback && attr == EP_ATTR_ADAPTIVE)) && | 1392 | (! is_playback && attr == USB_ENDPOINT_SYNC_ADAPTIVE)) && |
1375 | altsd->bNumEndpoints >= 2) { | 1393 | altsd->bNumEndpoints >= 2) { |
1376 | /* check sync-pipe endpoint */ | 1394 | /* check sync-pipe endpoint */ |
1377 | /* ... and check descriptor size before accessing bSynchAddress | 1395 | /* ... and check descriptor size before accessing bSynchAddress |
@@ -1411,7 +1429,7 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) | |||
1411 | } | 1429 | } |
1412 | 1430 | ||
1413 | /* always fill max packet size */ | 1431 | /* always fill max packet size */ |
1414 | if (fmt->attributes & EP_CS_ATTR_FILL_MAX) | 1432 | if (fmt->attributes & UAC_EP_CS_ATTR_FILL_MAX) |
1415 | subs->fill_max = 1; | 1433 | subs->fill_max = 1; |
1416 | 1434 | ||
1417 | if ((err = init_usb_pitch(dev, subs->interface, alts, fmt)) < 0) | 1435 | if ((err = init_usb_pitch(dev, subs->interface, alts, fmt)) < 0) |
@@ -1419,6 +1437,14 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) | |||
1419 | 1437 | ||
1420 | subs->cur_audiofmt = fmt; | 1438 | subs->cur_audiofmt = fmt; |
1421 | 1439 | ||
1440 | switch (subs->stream->chip->usb_id) { | ||
1441 | case USB_ID(0x041e, 0x3f02): /* E-Mu 0202 USB */ | ||
1442 | case USB_ID(0x041e, 0x3f04): /* E-Mu 0404 USB */ | ||
1443 | case USB_ID(0x041e, 0x3f0a): /* E-Mu Tracker Pre */ | ||
1444 | set_format_emu_quirk(subs, fmt); | ||
1445 | break; | ||
1446 | } | ||
1447 | |||
1422 | #if 0 | 1448 | #if 0 |
1423 | printk(KERN_DEBUG | 1449 | printk(KERN_DEBUG |
1424 | "setting done: format = %d, rate = %d..%d, channels = %d\n", | 1450 | "setting done: format = %d, rate = %d..%d, channels = %d\n", |
@@ -1449,8 +1475,8 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, | |||
1449 | unsigned int channels, rate, format; | 1475 | unsigned int channels, rate, format; |
1450 | int ret, changed; | 1476 | int ret, changed; |
1451 | 1477 | ||
1452 | ret = snd_pcm_alloc_vmalloc_buffer(substream, | 1478 | ret = snd_pcm_lib_alloc_vmalloc_buffer(substream, |
1453 | params_buffer_bytes(hw_params)); | 1479 | params_buffer_bytes(hw_params)); |
1454 | if (ret < 0) | 1480 | if (ret < 0) |
1455 | return ret; | 1481 | return ret; |
1456 | 1482 | ||
@@ -1507,7 +1533,7 @@ static int snd_usb_hw_free(struct snd_pcm_substream *substream) | |||
1507 | subs->period_bytes = 0; | 1533 | subs->period_bytes = 0; |
1508 | if (!subs->stream->chip->shutdown) | 1534 | if (!subs->stream->chip->shutdown) |
1509 | release_substream_urbs(subs, 0); | 1535 | release_substream_urbs(subs, 0); |
1510 | return snd_pcm_free_vmalloc_buffer(substream); | 1536 | return snd_pcm_lib_free_vmalloc_buffer(substream); |
1511 | } | 1537 | } |
1512 | 1538 | ||
1513 | /* | 1539 | /* |
@@ -1861,7 +1887,7 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre | |||
1861 | runtime->hw.channels_min = fp->channels; | 1887 | runtime->hw.channels_min = fp->channels; |
1862 | if (runtime->hw.channels_max < fp->channels) | 1888 | if (runtime->hw.channels_max < fp->channels) |
1863 | runtime->hw.channels_max = fp->channels; | 1889 | runtime->hw.channels_max = fp->channels; |
1864 | if (fp->fmt_type == USB_FORMAT_TYPE_II && fp->frame_size > 0) { | 1890 | if (fp->fmt_type == UAC_FORMAT_TYPE_II && fp->frame_size > 0) { |
1865 | /* FIXME: there might be more than one audio formats... */ | 1891 | /* FIXME: there might be more than one audio formats... */ |
1866 | runtime->hw.period_bytes_min = runtime->hw.period_bytes_max = | 1892 | runtime->hw.period_bytes_min = runtime->hw.period_bytes_max = |
1867 | fp->frame_size; | 1893 | fp->frame_size; |
@@ -1973,7 +1999,8 @@ static struct snd_pcm_ops snd_usb_playback_ops = { | |||
1973 | .prepare = snd_usb_pcm_prepare, | 1999 | .prepare = snd_usb_pcm_prepare, |
1974 | .trigger = snd_usb_pcm_playback_trigger, | 2000 | .trigger = snd_usb_pcm_playback_trigger, |
1975 | .pointer = snd_usb_pcm_pointer, | 2001 | .pointer = snd_usb_pcm_pointer, |
1976 | .page = snd_pcm_get_vmalloc_page, | 2002 | .page = snd_pcm_lib_get_vmalloc_page, |
2003 | .mmap = snd_pcm_lib_mmap_vmalloc, | ||
1977 | }; | 2004 | }; |
1978 | 2005 | ||
1979 | static struct snd_pcm_ops snd_usb_capture_ops = { | 2006 | static struct snd_pcm_ops snd_usb_capture_ops = { |
@@ -1985,7 +2012,8 @@ static struct snd_pcm_ops snd_usb_capture_ops = { | |||
1985 | .prepare = snd_usb_pcm_prepare, | 2012 | .prepare = snd_usb_pcm_prepare, |
1986 | .trigger = snd_usb_pcm_capture_trigger, | 2013 | .trigger = snd_usb_pcm_capture_trigger, |
1987 | .pointer = snd_usb_pcm_pointer, | 2014 | .pointer = snd_usb_pcm_pointer, |
1988 | .page = snd_pcm_get_vmalloc_page, | 2015 | .page = snd_pcm_lib_get_vmalloc_page, |
2016 | .mmap = snd_pcm_lib_mmap_vmalloc, | ||
1989 | }; | 2017 | }; |
1990 | 2018 | ||
1991 | 2019 | ||
@@ -2093,7 +2121,7 @@ static struct usb_device_id usb_audio_ids [] = { | |||
2093 | #include "usbquirks.h" | 2121 | #include "usbquirks.h" |
2094 | { .match_flags = (USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS), | 2122 | { .match_flags = (USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS), |
2095 | .bInterfaceClass = USB_CLASS_AUDIO, | 2123 | .bInterfaceClass = USB_CLASS_AUDIO, |
2096 | .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL }, | 2124 | .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL }, |
2097 | { } /* Terminating entry */ | 2125 | { } /* Terminating entry */ |
2098 | }; | 2126 | }; |
2099 | 2127 | ||
@@ -2132,7 +2160,7 @@ static void proc_dump_substream_formats(struct snd_usb_substream *subs, struct s | |||
2132 | snd_iprintf(buffer, " Endpoint: %d %s (%s)\n", | 2160 | snd_iprintf(buffer, " Endpoint: %d %s (%s)\n", |
2133 | fp->endpoint & USB_ENDPOINT_NUMBER_MASK, | 2161 | fp->endpoint & USB_ENDPOINT_NUMBER_MASK, |
2134 | fp->endpoint & USB_DIR_IN ? "IN" : "OUT", | 2162 | fp->endpoint & USB_DIR_IN ? "IN" : "OUT", |
2135 | sync_types[(fp->ep_attr & EP_ATTR_MASK) >> 2]); | 2163 | sync_types[(fp->ep_attr & USB_ENDPOINT_SYNCTYPE) >> 2]); |
2136 | if (fp->rates & SNDRV_PCM_RATE_CONTINUOUS) { | 2164 | if (fp->rates & SNDRV_PCM_RATE_CONTINUOUS) { |
2137 | snd_iprintf(buffer, " Rates: %d - %d (continuous)\n", | 2165 | snd_iprintf(buffer, " Rates: %d - %d (continuous)\n", |
2138 | fp->rate_min, fp->rate_max); | 2166 | fp->rate_min, fp->rate_max); |
@@ -2227,6 +2255,7 @@ static void init_substream(struct snd_usb_stream *as, int stream, struct audiofo | |||
2227 | subs->stream = as; | 2255 | subs->stream = as; |
2228 | subs->direction = stream; | 2256 | subs->direction = stream; |
2229 | subs->dev = as->chip->dev; | 2257 | subs->dev = as->chip->dev; |
2258 | subs->txfr_quirk = as->chip->txfr_quirk; | ||
2230 | if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL) { | 2259 | if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL) { |
2231 | subs->ops = audio_urb_ops[stream]; | 2260 | subs->ops = audio_urb_ops[stream]; |
2232 | } else { | 2261 | } else { |
@@ -2394,29 +2423,68 @@ static int is_big_endian_format(struct snd_usb_audio *chip, struct audioformat * | |||
2394 | * @format: the format tag (wFormatTag) | 2423 | * @format: the format tag (wFormatTag) |
2395 | * @fmt: the format type descriptor | 2424 | * @fmt: the format type descriptor |
2396 | */ | 2425 | */ |
2397 | static int parse_audio_format_i_type(struct snd_usb_audio *chip, struct audioformat *fp, | 2426 | static int parse_audio_format_i_type(struct snd_usb_audio *chip, |
2398 | int format, unsigned char *fmt) | 2427 | struct audioformat *fp, |
2428 | int format, void *_fmt, | ||
2429 | int protocol) | ||
2399 | { | 2430 | { |
2400 | int pcm_format; | 2431 | int pcm_format, i; |
2401 | int sample_width, sample_bytes; | 2432 | int sample_width, sample_bytes; |
2402 | 2433 | ||
2434 | switch (protocol) { | ||
2435 | case UAC_VERSION_1: { | ||
2436 | struct uac_format_type_i_discrete_descriptor *fmt = _fmt; | ||
2437 | sample_width = fmt->bBitResolution; | ||
2438 | sample_bytes = fmt->bSubframeSize; | ||
2439 | break; | ||
2440 | } | ||
2441 | |||
2442 | case UAC_VERSION_2: { | ||
2443 | struct uac_format_type_i_ext_descriptor *fmt = _fmt; | ||
2444 | sample_width = fmt->bBitResolution; | ||
2445 | sample_bytes = fmt->bSubslotSize; | ||
2446 | |||
2447 | /* | ||
2448 | * FIXME | ||
2449 | * USB audio class v2 devices specify a bitmap of possible | ||
2450 | * audio formats rather than one fix value. For now, we just | ||
2451 | * pick one of them and report that as the only possible | ||
2452 | * value for this setting. | ||
2453 | * The bit allocation map is in fact compatible to the | ||
2454 | * wFormatTag of the v1 AS streaming descriptors, which is why | ||
2455 | * we can simply map the matrix. | ||
2456 | */ | ||
2457 | |||
2458 | for (i = 0; i < 5; i++) | ||
2459 | if (format & (1UL << i)) { | ||
2460 | format = i + 1; | ||
2461 | break; | ||
2462 | } | ||
2463 | |||
2464 | break; | ||
2465 | } | ||
2466 | |||
2467 | default: | ||
2468 | return -EINVAL; | ||
2469 | } | ||
2470 | |||
2403 | /* FIXME: correct endianess and sign? */ | 2471 | /* FIXME: correct endianess and sign? */ |
2404 | pcm_format = -1; | 2472 | pcm_format = -1; |
2405 | sample_width = fmt[6]; | 2473 | |
2406 | sample_bytes = fmt[5]; | ||
2407 | switch (format) { | 2474 | switch (format) { |
2408 | case 0: /* some devices don't define this correctly... */ | 2475 | case UAC_FORMAT_TYPE_I_UNDEFINED: /* some devices don't define this correctly... */ |
2409 | snd_printdd(KERN_INFO "%d:%u:%d : format type 0 is detected, processed as PCM\n", | 2476 | snd_printdd(KERN_INFO "%d:%u:%d : format type 0 is detected, processed as PCM\n", |
2410 | chip->dev->devnum, fp->iface, fp->altsetting); | 2477 | chip->dev->devnum, fp->iface, fp->altsetting); |
2411 | /* fall-through */ | 2478 | /* fall-through */ |
2412 | case USB_AUDIO_FORMAT_PCM: | 2479 | case UAC_FORMAT_TYPE_I_PCM: |
2413 | if (sample_width > sample_bytes * 8) { | 2480 | if (sample_width > sample_bytes * 8) { |
2414 | snd_printk(KERN_INFO "%d:%u:%d : sample bitwidth %d in over sample bytes %d\n", | 2481 | snd_printk(KERN_INFO "%d:%u:%d : sample bitwidth %d in over sample bytes %d\n", |
2415 | chip->dev->devnum, fp->iface, fp->altsetting, | 2482 | chip->dev->devnum, fp->iface, fp->altsetting, |
2416 | sample_width, sample_bytes); | 2483 | sample_width, sample_bytes); |
2417 | } | 2484 | } |
2418 | /* check the format byte size */ | 2485 | /* check the format byte size */ |
2419 | switch (fmt[5]) { | 2486 | printk(" XXXXX SAMPLE BYTES %d\n", sample_bytes); |
2487 | switch (sample_bytes) { | ||
2420 | case 1: | 2488 | case 1: |
2421 | pcm_format = SNDRV_PCM_FORMAT_S8; | 2489 | pcm_format = SNDRV_PCM_FORMAT_S8; |
2422 | break; | 2490 | break; |
@@ -2437,12 +2505,12 @@ static int parse_audio_format_i_type(struct snd_usb_audio *chip, struct audiofor | |||
2437 | break; | 2505 | break; |
2438 | default: | 2506 | default: |
2439 | snd_printk(KERN_INFO "%d:%u:%d : unsupported sample bitwidth %d in %d bytes\n", | 2507 | snd_printk(KERN_INFO "%d:%u:%d : unsupported sample bitwidth %d in %d bytes\n", |
2440 | chip->dev->devnum, fp->iface, | 2508 | chip->dev->devnum, fp->iface, fp->altsetting, |
2441 | fp->altsetting, sample_width, sample_bytes); | 2509 | sample_width, sample_bytes); |
2442 | break; | 2510 | break; |
2443 | } | 2511 | } |
2444 | break; | 2512 | break; |
2445 | case USB_AUDIO_FORMAT_PCM8: | 2513 | case UAC_FORMAT_TYPE_I_PCM8: |
2446 | pcm_format = SNDRV_PCM_FORMAT_U8; | 2514 | pcm_format = SNDRV_PCM_FORMAT_U8; |
2447 | 2515 | ||
2448 | /* Dallas DS4201 workaround: it advertises U8 format, but really | 2516 | /* Dallas DS4201 workaround: it advertises U8 format, but really |
@@ -2450,13 +2518,13 @@ static int parse_audio_format_i_type(struct snd_usb_audio *chip, struct audiofor | |||
2450 | if (chip->usb_id == USB_ID(0x04fa, 0x4201)) | 2518 | if (chip->usb_id == USB_ID(0x04fa, 0x4201)) |
2451 | pcm_format = SNDRV_PCM_FORMAT_S8; | 2519 | pcm_format = SNDRV_PCM_FORMAT_S8; |
2452 | break; | 2520 | break; |
2453 | case USB_AUDIO_FORMAT_IEEE_FLOAT: | 2521 | case UAC_FORMAT_TYPE_I_IEEE_FLOAT: |
2454 | pcm_format = SNDRV_PCM_FORMAT_FLOAT_LE; | 2522 | pcm_format = SNDRV_PCM_FORMAT_FLOAT_LE; |
2455 | break; | 2523 | break; |
2456 | case USB_AUDIO_FORMAT_ALAW: | 2524 | case UAC_FORMAT_TYPE_I_ALAW: |
2457 | pcm_format = SNDRV_PCM_FORMAT_A_LAW; | 2525 | pcm_format = SNDRV_PCM_FORMAT_A_LAW; |
2458 | break; | 2526 | break; |
2459 | case USB_AUDIO_FORMAT_MU_LAW: | 2527 | case UAC_FORMAT_TYPE_I_MULAW: |
2460 | pcm_format = SNDRV_PCM_FORMAT_MU_LAW; | 2528 | pcm_format = SNDRV_PCM_FORMAT_MU_LAW; |
2461 | break; | 2529 | break; |
2462 | default: | 2530 | default: |
@@ -2470,7 +2538,7 @@ static int parse_audio_format_i_type(struct snd_usb_audio *chip, struct audiofor | |||
2470 | 2538 | ||
2471 | /* | 2539 | /* |
2472 | * parse the format descriptor and stores the possible sample rates | 2540 | * parse the format descriptor and stores the possible sample rates |
2473 | * on the audioformat table. | 2541 | * on the audioformat table (audio class v1). |
2474 | * | 2542 | * |
2475 | * @dev: usb device | 2543 | * @dev: usb device |
2476 | * @fp: audioformat record | 2544 | * @fp: audioformat record |
@@ -2478,13 +2546,13 @@ static int parse_audio_format_i_type(struct snd_usb_audio *chip, struct audiofor | |||
2478 | * @offset: the start offset of descriptor pointing the rate type | 2546 | * @offset: the start offset of descriptor pointing the rate type |
2479 | * (7 for type I and II, 8 for type II) | 2547 | * (7 for type I and II, 8 for type II) |
2480 | */ | 2548 | */ |
2481 | static int parse_audio_format_rates(struct snd_usb_audio *chip, struct audioformat *fp, | 2549 | static int parse_audio_format_rates_v1(struct snd_usb_audio *chip, struct audioformat *fp, |
2482 | unsigned char *fmt, int offset) | 2550 | unsigned char *fmt, int offset) |
2483 | { | 2551 | { |
2484 | int nr_rates = fmt[offset]; | 2552 | int nr_rates = fmt[offset]; |
2485 | 2553 | ||
2486 | if (fmt[0] < offset + 1 + 3 * (nr_rates ? nr_rates : 2)) { | 2554 | if (fmt[0] < offset + 1 + 3 * (nr_rates ? nr_rates : 2)) { |
2487 | snd_printk(KERN_ERR "%d:%u:%d : invalid FORMAT_TYPE desc\n", | 2555 | snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_FORMAT_TYPE desc\n", |
2488 | chip->dev->devnum, fp->iface, fp->altsetting); | 2556 | chip->dev->devnum, fp->iface, fp->altsetting); |
2489 | return -1; | 2557 | return -1; |
2490 | } | 2558 | } |
@@ -2535,14 +2603,87 @@ static int parse_audio_format_rates(struct snd_usb_audio *chip, struct audioform | |||
2535 | } | 2603 | } |
2536 | 2604 | ||
2537 | /* | 2605 | /* |
2606 | * parse the format descriptor and stores the possible sample rates | ||
2607 | * on the audioformat table (audio class v2). | ||
2608 | */ | ||
2609 | static int parse_audio_format_rates_v2(struct snd_usb_audio *chip, | ||
2610 | struct audioformat *fp, | ||
2611 | struct usb_host_interface *iface) | ||
2612 | { | ||
2613 | struct usb_device *dev = chip->dev; | ||
2614 | unsigned char tmp[2], *data; | ||
2615 | int i, nr_rates, data_size, ret = 0; | ||
2616 | |||
2617 | /* get the number of sample rates first by only fetching 2 bytes */ | ||
2618 | ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_RANGE, | ||
2619 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, | ||
2620 | 0x0100, chip->clock_id << 8, tmp, sizeof(tmp), 1000); | ||
2621 | |||
2622 | if (ret < 0) { | ||
2623 | snd_printk(KERN_ERR "unable to retrieve number of sample rates\n"); | ||
2624 | goto err; | ||
2625 | } | ||
2626 | |||
2627 | nr_rates = (tmp[1] << 8) | tmp[0]; | ||
2628 | data_size = 2 + 12 * nr_rates; | ||
2629 | data = kzalloc(data_size, GFP_KERNEL); | ||
2630 | if (!data) { | ||
2631 | ret = -ENOMEM; | ||
2632 | goto err; | ||
2633 | } | ||
2634 | |||
2635 | /* now get the full information */ | ||
2636 | ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_RANGE, | ||
2637 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, | ||
2638 | 0x0100, chip->clock_id << 8, data, data_size, 1000); | ||
2639 | |||
2640 | if (ret < 0) { | ||
2641 | snd_printk(KERN_ERR "unable to retrieve sample rate range\n"); | ||
2642 | ret = -EINVAL; | ||
2643 | goto err_free; | ||
2644 | } | ||
2645 | |||
2646 | fp->rate_table = kmalloc(sizeof(int) * nr_rates, GFP_KERNEL); | ||
2647 | if (!fp->rate_table) { | ||
2648 | ret = -ENOMEM; | ||
2649 | goto err_free; | ||
2650 | } | ||
2651 | |||
2652 | fp->nr_rates = 0; | ||
2653 | fp->rate_min = fp->rate_max = 0; | ||
2654 | |||
2655 | for (i = 0; i < nr_rates; i++) { | ||
2656 | int rate = combine_quad(&data[2 + 12 * i]); | ||
2657 | |||
2658 | fp->rate_table[fp->nr_rates] = rate; | ||
2659 | if (!fp->rate_min || rate < fp->rate_min) | ||
2660 | fp->rate_min = rate; | ||
2661 | if (!fp->rate_max || rate > fp->rate_max) | ||
2662 | fp->rate_max = rate; | ||
2663 | fp->rates |= snd_pcm_rate_to_rate_bit(rate); | ||
2664 | fp->nr_rates++; | ||
2665 | } | ||
2666 | |||
2667 | err_free: | ||
2668 | kfree(data); | ||
2669 | err: | ||
2670 | return ret; | ||
2671 | } | ||
2672 | |||
2673 | /* | ||
2538 | * parse the format type I and III descriptors | 2674 | * parse the format type I and III descriptors |
2539 | */ | 2675 | */ |
2540 | static int parse_audio_format_i(struct snd_usb_audio *chip, struct audioformat *fp, | 2676 | static int parse_audio_format_i(struct snd_usb_audio *chip, |
2541 | int format, unsigned char *fmt) | 2677 | struct audioformat *fp, |
2678 | int format, void *_fmt, | ||
2679 | struct usb_host_interface *iface) | ||
2542 | { | 2680 | { |
2543 | int pcm_format; | 2681 | struct usb_interface_descriptor *altsd = get_iface_desc(iface); |
2682 | struct uac_format_type_i_discrete_descriptor *fmt = _fmt; | ||
2683 | int protocol = altsd->bInterfaceProtocol; | ||
2684 | int pcm_format, ret; | ||
2544 | 2685 | ||
2545 | if (fmt[3] == USB_FORMAT_TYPE_III) { | 2686 | if (fmt->bFormatType == UAC_FORMAT_TYPE_III) { |
2546 | /* FIXME: the format type is really IECxxx | 2687 | /* FIXME: the format type is really IECxxx |
2547 | * but we give normal PCM format to get the existing | 2688 | * but we give normal PCM format to get the existing |
2548 | * apps working... | 2689 | * apps working... |
@@ -2560,34 +2701,57 @@ static int parse_audio_format_i(struct snd_usb_audio *chip, struct audioformat * | |||
2560 | pcm_format = SNDRV_PCM_FORMAT_S16_LE; | 2701 | pcm_format = SNDRV_PCM_FORMAT_S16_LE; |
2561 | } | 2702 | } |
2562 | } else { | 2703 | } else { |
2563 | pcm_format = parse_audio_format_i_type(chip, fp, format, fmt); | 2704 | pcm_format = parse_audio_format_i_type(chip, fp, format, fmt, protocol); |
2564 | if (pcm_format < 0) | 2705 | if (pcm_format < 0) |
2565 | return -1; | 2706 | return -1; |
2566 | } | 2707 | } |
2708 | |||
2567 | fp->format = pcm_format; | 2709 | fp->format = pcm_format; |
2568 | fp->channels = fmt[4]; | 2710 | |
2711 | /* gather possible sample rates */ | ||
2712 | /* audio class v1 reports possible sample rates as part of the | ||
2713 | * proprietary class specific descriptor. | ||
2714 | * audio class v2 uses class specific EP0 range requests for that. | ||
2715 | */ | ||
2716 | switch (protocol) { | ||
2717 | case UAC_VERSION_1: | ||
2718 | fp->channels = fmt->bNrChannels; | ||
2719 | ret = parse_audio_format_rates_v1(chip, fp, _fmt, 7); | ||
2720 | break; | ||
2721 | case UAC_VERSION_2: | ||
2722 | /* fp->channels is already set in this case */ | ||
2723 | ret = parse_audio_format_rates_v2(chip, fp, iface); | ||
2724 | break; | ||
2725 | } | ||
2726 | |||
2569 | if (fp->channels < 1) { | 2727 | if (fp->channels < 1) { |
2570 | snd_printk(KERN_ERR "%d:%u:%d : invalid channels %d\n", | 2728 | snd_printk(KERN_ERR "%d:%u:%d : invalid channels %d\n", |
2571 | chip->dev->devnum, fp->iface, fp->altsetting, fp->channels); | 2729 | chip->dev->devnum, fp->iface, fp->altsetting, fp->channels); |
2572 | return -1; | 2730 | return -1; |
2573 | } | 2731 | } |
2574 | return parse_audio_format_rates(chip, fp, fmt, 7); | 2732 | |
2733 | return ret; | ||
2575 | } | 2734 | } |
2576 | 2735 | ||
2577 | /* | 2736 | /* |
2578 | * prase the format type II descriptor | 2737 | * parse the format type II descriptor |
2579 | */ | 2738 | */ |
2580 | static int parse_audio_format_ii(struct snd_usb_audio *chip, struct audioformat *fp, | 2739 | static int parse_audio_format_ii(struct snd_usb_audio *chip, |
2581 | int format, unsigned char *fmt) | 2740 | struct audioformat *fp, |
2741 | int format, void *_fmt, | ||
2742 | struct usb_host_interface *iface) | ||
2582 | { | 2743 | { |
2583 | int brate, framesize; | 2744 | int brate, framesize, ret; |
2745 | struct usb_interface_descriptor *altsd = get_iface_desc(iface); | ||
2746 | int protocol = altsd->bInterfaceProtocol; | ||
2747 | |||
2584 | switch (format) { | 2748 | switch (format) { |
2585 | case USB_AUDIO_FORMAT_AC3: | 2749 | case UAC_FORMAT_TYPE_II_AC3: |
2586 | /* FIXME: there is no AC3 format defined yet */ | 2750 | /* FIXME: there is no AC3 format defined yet */ |
2587 | // fp->format = SNDRV_PCM_FORMAT_AC3; | 2751 | // fp->format = SNDRV_PCM_FORMAT_AC3; |
2588 | fp->format = SNDRV_PCM_FORMAT_U8; /* temporarily hack to receive byte streams */ | 2752 | fp->format = SNDRV_PCM_FORMAT_U8; /* temporarily hack to receive byte streams */ |
2589 | break; | 2753 | break; |
2590 | case USB_AUDIO_FORMAT_MPEG: | 2754 | case UAC_FORMAT_TYPE_II_MPEG: |
2591 | fp->format = SNDRV_PCM_FORMAT_MPEG; | 2755 | fp->format = SNDRV_PCM_FORMAT_MPEG; |
2592 | break; | 2756 | break; |
2593 | default: | 2757 | default: |
@@ -2596,26 +2760,46 @@ static int parse_audio_format_ii(struct snd_usb_audio *chip, struct audioformat | |||
2596 | fp->format = SNDRV_PCM_FORMAT_MPEG; | 2760 | fp->format = SNDRV_PCM_FORMAT_MPEG; |
2597 | break; | 2761 | break; |
2598 | } | 2762 | } |
2763 | |||
2599 | fp->channels = 1; | 2764 | fp->channels = 1; |
2600 | brate = combine_word(&fmt[4]); /* fmt[4,5] : wMaxBitRate (in kbps) */ | 2765 | |
2601 | framesize = combine_word(&fmt[6]); /* fmt[6,7]: wSamplesPerFrame */ | 2766 | switch (protocol) { |
2602 | snd_printd(KERN_INFO "found format II with max.bitrate = %d, frame size=%d\n", brate, framesize); | 2767 | case UAC_VERSION_1: { |
2603 | fp->frame_size = framesize; | 2768 | struct uac_format_type_ii_discrete_descriptor *fmt = _fmt; |
2604 | return parse_audio_format_rates(chip, fp, fmt, 8); /* fmt[8..] sample rates */ | 2769 | brate = le16_to_cpu(fmt->wMaxBitRate); |
2770 | framesize = le16_to_cpu(fmt->wSamplesPerFrame); | ||
2771 | snd_printd(KERN_INFO "found format II with max.bitrate = %d, frame size=%d\n", brate, framesize); | ||
2772 | fp->frame_size = framesize; | ||
2773 | ret = parse_audio_format_rates_v1(chip, fp, _fmt, 8); /* fmt[8..] sample rates */ | ||
2774 | break; | ||
2775 | } | ||
2776 | case UAC_VERSION_2: { | ||
2777 | struct uac_format_type_ii_ext_descriptor *fmt = _fmt; | ||
2778 | brate = le16_to_cpu(fmt->wMaxBitRate); | ||
2779 | framesize = le16_to_cpu(fmt->wSamplesPerFrame); | ||
2780 | snd_printd(KERN_INFO "found format II with max.bitrate = %d, frame size=%d\n", brate, framesize); | ||
2781 | fp->frame_size = framesize; | ||
2782 | ret = parse_audio_format_rates_v2(chip, fp, iface); | ||
2783 | break; | ||
2784 | } | ||
2785 | } | ||
2786 | |||
2787 | return ret; | ||
2605 | } | 2788 | } |
2606 | 2789 | ||
2607 | static int parse_audio_format(struct snd_usb_audio *chip, struct audioformat *fp, | 2790 | static int parse_audio_format(struct snd_usb_audio *chip, struct audioformat *fp, |
2608 | int format, unsigned char *fmt, int stream) | 2791 | int format, unsigned char *fmt, int stream, |
2792 | struct usb_host_interface *iface) | ||
2609 | { | 2793 | { |
2610 | int err; | 2794 | int err; |
2611 | 2795 | ||
2612 | switch (fmt[3]) { | 2796 | switch (fmt[3]) { |
2613 | case USB_FORMAT_TYPE_I: | 2797 | case UAC_FORMAT_TYPE_I: |
2614 | case USB_FORMAT_TYPE_III: | 2798 | case UAC_FORMAT_TYPE_III: |
2615 | err = parse_audio_format_i(chip, fp, format, fmt); | 2799 | err = parse_audio_format_i(chip, fp, format, fmt, iface); |
2616 | break; | 2800 | break; |
2617 | case USB_FORMAT_TYPE_II: | 2801 | case UAC_FORMAT_TYPE_II: |
2618 | err = parse_audio_format_ii(chip, fp, format, fmt); | 2802 | err = parse_audio_format_ii(chip, fp, format, fmt, iface); |
2619 | break; | 2803 | break; |
2620 | default: | 2804 | default: |
2621 | snd_printd(KERN_INFO "%d:%u:%d : format type %d is not supported yet\n", | 2805 | snd_printd(KERN_INFO "%d:%u:%d : format type %d is not supported yet\n", |
@@ -2633,7 +2817,7 @@ static int parse_audio_format(struct snd_usb_audio *chip, struct audioformat *fp | |||
2633 | if (chip->usb_id == USB_ID(0x041e, 0x3000) || | 2817 | if (chip->usb_id == USB_ID(0x041e, 0x3000) || |
2634 | chip->usb_id == USB_ID(0x041e, 0x3020) || | 2818 | chip->usb_id == USB_ID(0x041e, 0x3020) || |
2635 | chip->usb_id == USB_ID(0x041e, 0x3061)) { | 2819 | chip->usb_id == USB_ID(0x041e, 0x3061)) { |
2636 | if (fmt[3] == USB_FORMAT_TYPE_I && | 2820 | if (fmt[3] == UAC_FORMAT_TYPE_I && |
2637 | fp->rates != SNDRV_PCM_RATE_48000 && | 2821 | fp->rates != SNDRV_PCM_RATE_48000 && |
2638 | fp->rates != SNDRV_PCM_RATE_96000) | 2822 | fp->rates != SNDRV_PCM_RATE_96000) |
2639 | return -1; | 2823 | return -1; |
@@ -2662,10 +2846,10 @@ static int parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) | |||
2662 | struct usb_host_interface *alts; | 2846 | struct usb_host_interface *alts; |
2663 | struct usb_interface_descriptor *altsd; | 2847 | struct usb_interface_descriptor *altsd; |
2664 | int i, altno, err, stream; | 2848 | int i, altno, err, stream; |
2665 | int format; | 2849 | int format = 0, num_channels = 0; |
2666 | struct audioformat *fp = NULL; | 2850 | struct audioformat *fp = NULL; |
2667 | unsigned char *fmt, *csep; | 2851 | unsigned char *fmt, *csep; |
2668 | int num; | 2852 | int num, protocol; |
2669 | 2853 | ||
2670 | dev = chip->dev; | 2854 | dev = chip->dev; |
2671 | 2855 | ||
@@ -2684,10 +2868,11 @@ static int parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) | |||
2684 | for (i = 0; i < num; i++) { | 2868 | for (i = 0; i < num; i++) { |
2685 | alts = &iface->altsetting[i]; | 2869 | alts = &iface->altsetting[i]; |
2686 | altsd = get_iface_desc(alts); | 2870 | altsd = get_iface_desc(alts); |
2871 | protocol = altsd->bInterfaceProtocol; | ||
2687 | /* skip invalid one */ | 2872 | /* skip invalid one */ |
2688 | if ((altsd->bInterfaceClass != USB_CLASS_AUDIO && | 2873 | if ((altsd->bInterfaceClass != USB_CLASS_AUDIO && |
2689 | altsd->bInterfaceClass != USB_CLASS_VENDOR_SPEC) || | 2874 | altsd->bInterfaceClass != USB_CLASS_VENDOR_SPEC) || |
2690 | (altsd->bInterfaceSubClass != USB_SUBCLASS_AUDIO_STREAMING && | 2875 | (altsd->bInterfaceSubClass != USB_SUBCLASS_AUDIOSTREAMING && |
2691 | altsd->bInterfaceSubClass != USB_SUBCLASS_VENDOR_SPEC) || | 2876 | altsd->bInterfaceSubClass != USB_SUBCLASS_VENDOR_SPEC) || |
2692 | altsd->bNumEndpoints < 1 || | 2877 | altsd->bNumEndpoints < 1 || |
2693 | le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize) == 0) | 2878 | le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize) == 0) |
@@ -2708,30 +2893,65 @@ static int parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) | |||
2708 | continue; | 2893 | continue; |
2709 | 2894 | ||
2710 | /* get audio formats */ | 2895 | /* get audio formats */ |
2711 | fmt = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, AS_GENERAL); | 2896 | switch (protocol) { |
2712 | if (!fmt) { | 2897 | case UAC_VERSION_1: { |
2713 | snd_printk(KERN_ERR "%d:%u:%d : AS_GENERAL descriptor not found\n", | 2898 | struct uac_as_header_descriptor_v1 *as = |
2714 | dev->devnum, iface_no, altno); | 2899 | snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL); |
2715 | continue; | 2900 | |
2901 | if (!as) { | ||
2902 | snd_printk(KERN_ERR "%d:%u:%d : UAC_AS_GENERAL descriptor not found\n", | ||
2903 | dev->devnum, iface_no, altno); | ||
2904 | continue; | ||
2905 | } | ||
2906 | |||
2907 | if (as->bLength < sizeof(*as)) { | ||
2908 | snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_AS_GENERAL desc\n", | ||
2909 | dev->devnum, iface_no, altno); | ||
2910 | continue; | ||
2911 | } | ||
2912 | |||
2913 | format = le16_to_cpu(as->wFormatTag); /* remember the format value */ | ||
2914 | break; | ||
2716 | } | 2915 | } |
2717 | 2916 | ||
2718 | if (fmt[0] < 7) { | 2917 | case UAC_VERSION_2: { |
2719 | snd_printk(KERN_ERR "%d:%u:%d : invalid AS_GENERAL desc\n", | 2918 | struct uac_as_header_descriptor_v2 *as = |
2720 | dev->devnum, iface_no, altno); | 2919 | snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL); |
2721 | continue; | 2920 | |
2921 | if (!as) { | ||
2922 | snd_printk(KERN_ERR "%d:%u:%d : UAC_AS_GENERAL descriptor not found\n", | ||
2923 | dev->devnum, iface_no, altno); | ||
2924 | continue; | ||
2925 | } | ||
2926 | |||
2927 | if (as->bLength < sizeof(*as)) { | ||
2928 | snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_AS_GENERAL desc\n", | ||
2929 | dev->devnum, iface_no, altno); | ||
2930 | continue; | ||
2931 | } | ||
2932 | |||
2933 | num_channels = as->bNrChannels; | ||
2934 | format = le32_to_cpu(as->bmFormats); | ||
2935 | |||
2936 | break; | ||
2722 | } | 2937 | } |
2723 | 2938 | ||
2724 | format = (fmt[6] << 8) | fmt[5]; /* remember the format value */ | 2939 | default: |
2940 | snd_printk(KERN_ERR "%d:%u:%d : unknown interface protocol %04x\n", | ||
2941 | dev->devnum, iface_no, altno, protocol); | ||
2942 | continue; | ||
2943 | } | ||
2725 | 2944 | ||
2726 | /* get format type */ | 2945 | /* get format type */ |
2727 | fmt = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, FORMAT_TYPE); | 2946 | fmt = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_FORMAT_TYPE); |
2728 | if (!fmt) { | 2947 | if (!fmt) { |
2729 | snd_printk(KERN_ERR "%d:%u:%d : no FORMAT_TYPE desc\n", | 2948 | snd_printk(KERN_ERR "%d:%u:%d : no UAC_FORMAT_TYPE desc\n", |
2730 | dev->devnum, iface_no, altno); | 2949 | dev->devnum, iface_no, altno); |
2731 | continue; | 2950 | continue; |
2732 | } | 2951 | } |
2733 | if (fmt[0] < 8) { | 2952 | if (((protocol == UAC_VERSION_1) && (fmt[0] < 8)) || |
2734 | snd_printk(KERN_ERR "%d:%u:%d : invalid FORMAT_TYPE desc\n", | 2953 | ((protocol == UAC_VERSION_2) && (fmt[0] != 6))) { |
2954 | snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_FORMAT_TYPE desc\n", | ||
2735 | dev->devnum, iface_no, altno); | 2955 | dev->devnum, iface_no, altno); |
2736 | continue; | 2956 | continue; |
2737 | } | 2957 | } |
@@ -2744,6 +2964,7 @@ static int parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) | |||
2744 | if (fmt[4] == 1 && fmt[5] == 2 && altno == 2 && num == 3 && | 2964 | if (fmt[4] == 1 && fmt[5] == 2 && altno == 2 && num == 3 && |
2745 | fp && fp->altsetting == 1 && fp->channels == 1 && | 2965 | fp && fp->altsetting == 1 && fp->channels == 1 && |
2746 | fp->format == SNDRV_PCM_FORMAT_S16_LE && | 2966 | fp->format == SNDRV_PCM_FORMAT_S16_LE && |
2967 | protocol == UAC_VERSION_1 && | ||
2747 | le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize) == | 2968 | le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize) == |
2748 | fp->maxpacksize * 2) | 2969 | fp->maxpacksize * 2) |
2749 | continue; | 2970 | continue; |
@@ -2752,7 +2973,7 @@ static int parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) | |||
2752 | /* Creamware Noah has this descriptor after the 2nd endpoint */ | 2973 | /* Creamware Noah has this descriptor after the 2nd endpoint */ |
2753 | if (!csep && altsd->bNumEndpoints >= 2) | 2974 | if (!csep && altsd->bNumEndpoints >= 2) |
2754 | csep = snd_usb_find_desc(alts->endpoint[1].extra, alts->endpoint[1].extralen, NULL, USB_DT_CS_ENDPOINT); | 2975 | csep = snd_usb_find_desc(alts->endpoint[1].extra, alts->endpoint[1].extralen, NULL, USB_DT_CS_ENDPOINT); |
2755 | if (!csep || csep[0] < 7 || csep[2] != EP_GENERAL) { | 2976 | if (!csep || csep[0] < 7 || csep[2] != UAC_EP_GENERAL) { |
2756 | snd_printk(KERN_WARNING "%d:%u:%d : no or invalid" | 2977 | snd_printk(KERN_WARNING "%d:%u:%d : no or invalid" |
2757 | " class specific endpoint descriptor\n", | 2978 | " class specific endpoint descriptor\n", |
2758 | dev->devnum, iface_no, altno); | 2979 | dev->devnum, iface_no, altno); |
@@ -2772,6 +2993,8 @@ static int parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) | |||
2772 | fp->ep_attr = get_endpoint(alts, 0)->bmAttributes; | 2993 | fp->ep_attr = get_endpoint(alts, 0)->bmAttributes; |
2773 | fp->datainterval = parse_datainterval(chip, alts); | 2994 | fp->datainterval = parse_datainterval(chip, alts); |
2774 | fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize); | 2995 | fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize); |
2996 | /* num_channels is only set for v2 interfaces */ | ||
2997 | fp->channels = num_channels; | ||
2775 | if (snd_usb_get_speed(dev) == USB_SPEED_HIGH) | 2998 | if (snd_usb_get_speed(dev) == USB_SPEED_HIGH) |
2776 | fp->maxpacksize = (((fp->maxpacksize >> 11) & 3) + 1) | 2999 | fp->maxpacksize = (((fp->maxpacksize >> 11) & 3) + 1) |
2777 | * (fp->maxpacksize & 0x7ff); | 3000 | * (fp->maxpacksize & 0x7ff); |
@@ -2784,12 +3007,12 @@ static int parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) | |||
2784 | /* Optoplay sets the sample rate attribute although | 3007 | /* Optoplay sets the sample rate attribute although |
2785 | * it seems not supporting it in fact. | 3008 | * it seems not supporting it in fact. |
2786 | */ | 3009 | */ |
2787 | fp->attributes &= ~EP_CS_ATTR_SAMPLE_RATE; | 3010 | fp->attributes &= ~UAC_EP_CS_ATTR_SAMPLE_RATE; |
2788 | break; | 3011 | break; |
2789 | case USB_ID(0x041e, 0x3020): /* Creative SB Audigy 2 NX */ | 3012 | case USB_ID(0x041e, 0x3020): /* Creative SB Audigy 2 NX */ |
2790 | case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */ | 3013 | case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */ |
2791 | /* doesn't set the sample rate attribute, but supports it */ | 3014 | /* doesn't set the sample rate attribute, but supports it */ |
2792 | fp->attributes |= EP_CS_ATTR_SAMPLE_RATE; | 3015 | fp->attributes |= UAC_EP_CS_ATTR_SAMPLE_RATE; |
2793 | break; | 3016 | break; |
2794 | case USB_ID(0x047f, 0x0ca1): /* plantronics headset */ | 3017 | case USB_ID(0x047f, 0x0ca1): /* plantronics headset */ |
2795 | case USB_ID(0x077d, 0x07af): /* Griffin iMic (note that there is | 3018 | case USB_ID(0x077d, 0x07af): /* Griffin iMic (note that there is |
@@ -2798,16 +3021,16 @@ static int parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) | |||
2798 | * plantronics headset and Griffin iMic have set adaptive-in | 3021 | * plantronics headset and Griffin iMic have set adaptive-in |
2799 | * although it's really not... | 3022 | * although it's really not... |
2800 | */ | 3023 | */ |
2801 | fp->ep_attr &= ~EP_ATTR_MASK; | 3024 | fp->ep_attr &= ~USB_ENDPOINT_SYNCTYPE; |
2802 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) | 3025 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) |
2803 | fp->ep_attr |= EP_ATTR_ADAPTIVE; | 3026 | fp->ep_attr |= USB_ENDPOINT_SYNC_ADAPTIVE; |
2804 | else | 3027 | else |
2805 | fp->ep_attr |= EP_ATTR_SYNC; | 3028 | fp->ep_attr |= USB_ENDPOINT_SYNC_SYNC; |
2806 | break; | 3029 | break; |
2807 | } | 3030 | } |
2808 | 3031 | ||
2809 | /* ok, let's parse further... */ | 3032 | /* ok, let's parse further... */ |
2810 | if (parse_audio_format(chip, fp, format, fmt, stream) < 0) { | 3033 | if (parse_audio_format(chip, fp, format, fmt, stream, alts) < 0) { |
2811 | kfree(fp->rate_table); | 3034 | kfree(fp->rate_table); |
2812 | kfree(fp); | 3035 | kfree(fp); |
2813 | continue; | 3036 | continue; |
@@ -2849,6 +3072,65 @@ static void snd_usb_stream_disconnect(struct list_head *head) | |||
2849 | } | 3072 | } |
2850 | } | 3073 | } |
2851 | 3074 | ||
3075 | static int snd_usb_create_stream(struct snd_usb_audio *chip, int ctrlif, int interface) | ||
3076 | { | ||
3077 | struct usb_device *dev = chip->dev; | ||
3078 | struct usb_host_interface *alts; | ||
3079 | struct usb_interface_descriptor *altsd; | ||
3080 | struct usb_interface *iface = usb_ifnum_to_if(dev, interface); | ||
3081 | |||
3082 | if (!iface) { | ||
3083 | snd_printk(KERN_ERR "%d:%u:%d : does not exist\n", | ||
3084 | dev->devnum, ctrlif, interface); | ||
3085 | return -EINVAL; | ||
3086 | } | ||
3087 | |||
3088 | if (usb_interface_claimed(iface)) { | ||
3089 | snd_printdd(KERN_INFO "%d:%d:%d: skipping, already claimed\n", | ||
3090 | dev->devnum, ctrlif, interface); | ||
3091 | return -EINVAL; | ||
3092 | } | ||
3093 | |||
3094 | alts = &iface->altsetting[0]; | ||
3095 | altsd = get_iface_desc(alts); | ||
3096 | if ((altsd->bInterfaceClass == USB_CLASS_AUDIO || | ||
3097 | altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC) && | ||
3098 | altsd->bInterfaceSubClass == USB_SUBCLASS_MIDISTREAMING) { | ||
3099 | int err = snd_usbmidi_create(chip->card, iface, | ||
3100 | &chip->midi_list, NULL); | ||
3101 | if (err < 0) { | ||
3102 | snd_printk(KERN_ERR "%d:%u:%d: cannot create sequencer device\n", | ||
3103 | dev->devnum, ctrlif, interface); | ||
3104 | return -EINVAL; | ||
3105 | } | ||
3106 | usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1L); | ||
3107 | |||
3108 | return 0; | ||
3109 | } | ||
3110 | |||
3111 | if ((altsd->bInterfaceClass != USB_CLASS_AUDIO && | ||
3112 | altsd->bInterfaceClass != USB_CLASS_VENDOR_SPEC) || | ||
3113 | altsd->bInterfaceSubClass != USB_SUBCLASS_AUDIOSTREAMING) { | ||
3114 | snd_printdd(KERN_ERR "%d:%u:%d: skipping non-supported interface %d\n", | ||
3115 | dev->devnum, ctrlif, interface, altsd->bInterfaceClass); | ||
3116 | /* skip non-supported classes */ | ||
3117 | return -EINVAL; | ||
3118 | } | ||
3119 | |||
3120 | if (snd_usb_get_speed(dev) == USB_SPEED_LOW) { | ||
3121 | snd_printk(KERN_ERR "low speed audio streaming not supported\n"); | ||
3122 | return -EINVAL; | ||
3123 | } | ||
3124 | |||
3125 | if (! parse_audio_endpoints(chip, interface)) { | ||
3126 | usb_set_interface(dev, interface, 0); /* reset the current interface */ | ||
3127 | usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1L); | ||
3128 | return -EINVAL; | ||
3129 | } | ||
3130 | |||
3131 | return 0; | ||
3132 | } | ||
3133 | |||
2852 | /* | 3134 | /* |
2853 | * parse audio control descriptor and create pcm/midi streams | 3135 | * parse audio control descriptor and create pcm/midi streams |
2854 | */ | 3136 | */ |
@@ -2856,67 +3138,81 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif) | |||
2856 | { | 3138 | { |
2857 | struct usb_device *dev = chip->dev; | 3139 | struct usb_device *dev = chip->dev; |
2858 | struct usb_host_interface *host_iface; | 3140 | struct usb_host_interface *host_iface; |
2859 | struct usb_interface *iface; | 3141 | struct usb_interface_descriptor *altsd; |
2860 | unsigned char *p1; | 3142 | void *control_header; |
2861 | int i, j; | 3143 | int i, protocol; |
2862 | 3144 | ||
2863 | /* find audiocontrol interface */ | 3145 | /* find audiocontrol interface */ |
2864 | host_iface = &usb_ifnum_to_if(dev, ctrlif)->altsetting[0]; | 3146 | host_iface = &usb_ifnum_to_if(dev, ctrlif)->altsetting[0]; |
2865 | if (!(p1 = snd_usb_find_csint_desc(host_iface->extra, host_iface->extralen, NULL, HEADER))) { | 3147 | control_header = snd_usb_find_csint_desc(host_iface->extra, |
2866 | snd_printk(KERN_ERR "cannot find HEADER\n"); | 3148 | host_iface->extralen, |
2867 | return -EINVAL; | 3149 | NULL, UAC_HEADER); |
2868 | } | 3150 | altsd = get_iface_desc(host_iface); |
2869 | if (! p1[7] || p1[0] < 8 + p1[7]) { | 3151 | protocol = altsd->bInterfaceProtocol; |
2870 | snd_printk(KERN_ERR "invalid HEADER\n"); | 3152 | |
3153 | if (!control_header) { | ||
3154 | snd_printk(KERN_ERR "cannot find UAC_HEADER\n"); | ||
2871 | return -EINVAL; | 3155 | return -EINVAL; |
2872 | } | 3156 | } |
2873 | 3157 | ||
2874 | /* | 3158 | switch (protocol) { |
2875 | * parse all USB audio streaming interfaces | 3159 | case UAC_VERSION_1: { |
2876 | */ | 3160 | struct uac_ac_header_descriptor_v1 *h1 = control_header; |
2877 | for (i = 0; i < p1[7]; i++) { | 3161 | |
2878 | struct usb_host_interface *alts; | 3162 | if (!h1->bInCollection) { |
2879 | struct usb_interface_descriptor *altsd; | 3163 | snd_printk(KERN_INFO "skipping empty audio interface (v1)\n"); |
2880 | j = p1[8 + i]; | 3164 | return -EINVAL; |
2881 | iface = usb_ifnum_to_if(dev, j); | ||
2882 | if (!iface) { | ||
2883 | snd_printk(KERN_ERR "%d:%u:%d : does not exist\n", | ||
2884 | dev->devnum, ctrlif, j); | ||
2885 | continue; | ||
2886 | } | ||
2887 | if (usb_interface_claimed(iface)) { | ||
2888 | snd_printdd(KERN_INFO "%d:%d:%d: skipping, already claimed\n", dev->devnum, ctrlif, j); | ||
2889 | continue; | ||
2890 | } | 3165 | } |
2891 | alts = &iface->altsetting[0]; | 3166 | |
2892 | altsd = get_iface_desc(alts); | 3167 | if (h1->bLength < sizeof(*h1) + h1->bInCollection) { |
2893 | if ((altsd->bInterfaceClass == USB_CLASS_AUDIO || | 3168 | snd_printk(KERN_ERR "invalid UAC_HEADER (v1)\n"); |
2894 | altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC) && | 3169 | return -EINVAL; |
2895 | altsd->bInterfaceSubClass == USB_SUBCLASS_MIDI_STREAMING) { | ||
2896 | int err = snd_usbmidi_create(chip->card, iface, | ||
2897 | &chip->midi_list, NULL); | ||
2898 | if (err < 0) { | ||
2899 | snd_printk(KERN_ERR "%d:%u:%d: cannot create sequencer device\n", dev->devnum, ctrlif, j); | ||
2900 | continue; | ||
2901 | } | ||
2902 | usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1L); | ||
2903 | continue; | ||
2904 | } | 3170 | } |
2905 | if ((altsd->bInterfaceClass != USB_CLASS_AUDIO && | 3171 | |
2906 | altsd->bInterfaceClass != USB_CLASS_VENDOR_SPEC) || | 3172 | for (i = 0; i < h1->bInCollection; i++) |
2907 | altsd->bInterfaceSubClass != USB_SUBCLASS_AUDIO_STREAMING) { | 3173 | snd_usb_create_stream(chip, ctrlif, h1->baInterfaceNr[i]); |
2908 | snd_printdd(KERN_ERR "%d:%u:%d: skipping non-supported interface %d\n", dev->devnum, ctrlif, j, altsd->bInterfaceClass); | 3174 | |
2909 | /* skip non-supported classes */ | 3175 | break; |
2910 | continue; | 3176 | } |
3177 | |||
3178 | case UAC_VERSION_2: { | ||
3179 | struct uac_clock_source_descriptor *cs; | ||
3180 | struct usb_interface_assoc_descriptor *assoc = | ||
3181 | usb_ifnum_to_if(dev, ctrlif)->intf_assoc; | ||
3182 | |||
3183 | if (!assoc) { | ||
3184 | snd_printk(KERN_ERR "Audio class v2 interfaces need an interface association\n"); | ||
3185 | return -EINVAL; | ||
2911 | } | 3186 | } |
2912 | if (snd_usb_get_speed(dev) == USB_SPEED_LOW) { | 3187 | |
2913 | snd_printk(KERN_ERR "low speed audio streaming not supported\n"); | 3188 | /* FIXME: for now, we expect there is at least one clock source |
2914 | continue; | 3189 | * descriptor and we always take the first one. |
3190 | * We should properly support devices with multiple clock sources, | ||
3191 | * clock selectors and sample rate conversion units. */ | ||
3192 | |||
3193 | cs = snd_usb_find_csint_desc(host_iface->extra, host_iface->extralen, | ||
3194 | NULL, UAC_CLOCK_SOURCE); | ||
3195 | |||
3196 | if (!cs) { | ||
3197 | snd_printk(KERN_ERR "CLOCK_SOURCE descriptor not found\n"); | ||
3198 | return -EINVAL; | ||
2915 | } | 3199 | } |
2916 | if (! parse_audio_endpoints(chip, j)) { | 3200 | |
2917 | usb_set_interface(dev, j, 0); /* reset the current interface */ | 3201 | chip->clock_id = cs->bClockID; |
2918 | usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1L); | 3202 | |
3203 | for (i = 0; i < assoc->bInterfaceCount; i++) { | ||
3204 | int intf = assoc->bFirstInterface + i; | ||
3205 | |||
3206 | if (intf != ctrlif) | ||
3207 | snd_usb_create_stream(chip, ctrlif, intf); | ||
2919 | } | 3208 | } |
3209 | |||
3210 | break; | ||
3211 | } | ||
3212 | |||
3213 | default: | ||
3214 | snd_printk(KERN_ERR "unknown protocol version 0x%02x\n", protocol); | ||
3215 | return -EINVAL; | ||
2920 | } | 3216 | } |
2921 | 3217 | ||
2922 | return 0; | 3218 | return 0; |
@@ -3007,7 +3303,7 @@ static int create_uaxx_quirk(struct snd_usb_audio *chip, | |||
3007 | static const struct audioformat ua_format = { | 3303 | static const struct audioformat ua_format = { |
3008 | .format = SNDRV_PCM_FORMAT_S24_3LE, | 3304 | .format = SNDRV_PCM_FORMAT_S24_3LE, |
3009 | .channels = 2, | 3305 | .channels = 2, |
3010 | .fmt_type = USB_FORMAT_TYPE_I, | 3306 | .fmt_type = UAC_FORMAT_TYPE_I, |
3011 | .altsetting = 1, | 3307 | .altsetting = 1, |
3012 | .altset_idx = 1, | 3308 | .altset_idx = 1, |
3013 | .rates = SNDRV_PCM_RATE_CONTINUOUS, | 3309 | .rates = SNDRV_PCM_RATE_CONTINUOUS, |
@@ -3099,7 +3395,7 @@ static int create_ua1000_quirk(struct snd_usb_audio *chip, | |||
3099 | { | 3395 | { |
3100 | static const struct audioformat ua1000_format = { | 3396 | static const struct audioformat ua1000_format = { |
3101 | .format = SNDRV_PCM_FORMAT_S32_LE, | 3397 | .format = SNDRV_PCM_FORMAT_S32_LE, |
3102 | .fmt_type = USB_FORMAT_TYPE_I, | 3398 | .fmt_type = UAC_FORMAT_TYPE_I, |
3103 | .altsetting = 1, | 3399 | .altsetting = 1, |
3104 | .altset_idx = 1, | 3400 | .altset_idx = 1, |
3105 | .attributes = 0, | 3401 | .attributes = 0, |
@@ -3142,59 +3438,6 @@ static int create_ua1000_quirk(struct snd_usb_audio *chip, | |||
3142 | return 0; | 3438 | return 0; |
3143 | } | 3439 | } |
3144 | 3440 | ||
3145 | /* | ||
3146 | * Create a stream for an Edirol UA-101 interface. | ||
3147 | * Copy, paste and modify from Edirol UA-1000 | ||
3148 | */ | ||
3149 | static int create_ua101_quirk(struct snd_usb_audio *chip, | ||
3150 | struct usb_interface *iface, | ||
3151 | const struct snd_usb_audio_quirk *quirk) | ||
3152 | { | ||
3153 | static const struct audioformat ua101_format = { | ||
3154 | .format = SNDRV_PCM_FORMAT_S32_LE, | ||
3155 | .fmt_type = USB_FORMAT_TYPE_I, | ||
3156 | .altsetting = 1, | ||
3157 | .altset_idx = 1, | ||
3158 | .attributes = 0, | ||
3159 | .rates = SNDRV_PCM_RATE_CONTINUOUS, | ||
3160 | }; | ||
3161 | struct usb_host_interface *alts; | ||
3162 | struct usb_interface_descriptor *altsd; | ||
3163 | struct audioformat *fp; | ||
3164 | int stream, err; | ||
3165 | |||
3166 | if (iface->num_altsetting != 2) | ||
3167 | return -ENXIO; | ||
3168 | alts = &iface->altsetting[1]; | ||
3169 | altsd = get_iface_desc(alts); | ||
3170 | if (alts->extralen != 18 || alts->extra[1] != USB_DT_CS_INTERFACE || | ||
3171 | altsd->bNumEndpoints != 1) | ||
3172 | return -ENXIO; | ||
3173 | |||
3174 | fp = kmemdup(&ua101_format, sizeof(*fp), GFP_KERNEL); | ||
3175 | if (!fp) | ||
3176 | return -ENOMEM; | ||
3177 | |||
3178 | fp->channels = alts->extra[11]; | ||
3179 | fp->iface = altsd->bInterfaceNumber; | ||
3180 | fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress; | ||
3181 | fp->ep_attr = get_endpoint(alts, 0)->bmAttributes; | ||
3182 | fp->datainterval = parse_datainterval(chip, alts); | ||
3183 | fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize); | ||
3184 | fp->rate_max = fp->rate_min = combine_triple(&alts->extra[15]); | ||
3185 | |||
3186 | stream = (fp->endpoint & USB_DIR_IN) | ||
3187 | ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK; | ||
3188 | err = add_audio_endpoint(chip, stream, fp); | ||
3189 | if (err < 0) { | ||
3190 | kfree(fp); | ||
3191 | return err; | ||
3192 | } | ||
3193 | /* FIXME: playback must be synchronized to capture */ | ||
3194 | usb_set_interface(chip->dev, fp->iface, 0); | ||
3195 | return 0; | ||
3196 | } | ||
3197 | |||
3198 | static int snd_usb_create_quirk(struct snd_usb_audio *chip, | 3441 | static int snd_usb_create_quirk(struct snd_usb_audio *chip, |
3199 | struct usb_interface *iface, | 3442 | struct usb_interface *iface, |
3200 | const struct snd_usb_audio_quirk *quirk); | 3443 | const struct snd_usb_audio_quirk *quirk); |
@@ -3232,6 +3475,18 @@ static int ignore_interface_quirk(struct snd_usb_audio *chip, | |||
3232 | return 0; | 3475 | return 0; |
3233 | } | 3476 | } |
3234 | 3477 | ||
3478 | /* | ||
3479 | * Allow alignment on audio sub-slot (channel samples) rather than | ||
3480 | * on audio slots (audio frames) | ||
3481 | */ | ||
3482 | static int create_align_transfer_quirk(struct snd_usb_audio *chip, | ||
3483 | struct usb_interface *iface, | ||
3484 | const struct snd_usb_audio_quirk *quirk) | ||
3485 | { | ||
3486 | chip->txfr_quirk = 1; | ||
3487 | return 1; /* Continue with creating streams and mixer */ | ||
3488 | } | ||
3489 | |||
3235 | 3490 | ||
3236 | /* | 3491 | /* |
3237 | * boot quirks | 3492 | * boot quirks |
@@ -3327,6 +3582,32 @@ static int snd_usb_cm6206_boot_quirk(struct usb_device *dev) | |||
3327 | } | 3582 | } |
3328 | 3583 | ||
3329 | /* | 3584 | /* |
3585 | * This call will put the synth in "USB send" mode, i.e it will send MIDI | ||
3586 | * messages through USB (this is disabled at startup). The synth will | ||
3587 | * acknowledge by sending a sysex on endpoint 0x85 and by displaying a USB | ||
3588 | * sign on its LCD. Values here are chosen based on sniffing USB traffic | ||
3589 | * under Windows. | ||
3590 | */ | ||
3591 | static int snd_usb_accessmusic_boot_quirk(struct usb_device *dev) | ||
3592 | { | ||
3593 | int err, actual_length; | ||
3594 | |||
3595 | /* "midi send" enable */ | ||
3596 | static const u8 seq[] = { 0x4e, 0x73, 0x52, 0x01 }; | ||
3597 | |||
3598 | void *buf = kmemdup(seq, ARRAY_SIZE(seq), GFP_KERNEL); | ||
3599 | if (!buf) | ||
3600 | return -ENOMEM; | ||
3601 | err = usb_interrupt_msg(dev, usb_sndintpipe(dev, 0x05), buf, | ||
3602 | ARRAY_SIZE(seq), &actual_length, 1000); | ||
3603 | kfree(buf); | ||
3604 | if (err < 0) | ||
3605 | return err; | ||
3606 | |||
3607 | return 0; | ||
3608 | } | ||
3609 | |||
3610 | /* | ||
3330 | * Setup quirks | 3611 | * Setup quirks |
3331 | */ | 3612 | */ |
3332 | #define AUDIOPHILE_SET 0x01 /* if set, parse device_setup */ | 3613 | #define AUDIOPHILE_SET 0x01 /* if set, parse device_setup */ |
@@ -3406,8 +3687,8 @@ static int snd_usb_create_quirk(struct snd_usb_audio *chip, | |||
3406 | [QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk, | 3687 | [QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk, |
3407 | [QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk, | 3688 | [QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk, |
3408 | [QUIRK_AUDIO_EDIROL_UA1000] = create_ua1000_quirk, | 3689 | [QUIRK_AUDIO_EDIROL_UA1000] = create_ua1000_quirk, |
3409 | [QUIRK_AUDIO_EDIROL_UA101] = create_ua101_quirk, | 3690 | [QUIRK_AUDIO_EDIROL_UAXX] = create_uaxx_quirk, |
3410 | [QUIRK_AUDIO_EDIROL_UAXX] = create_uaxx_quirk | 3691 | [QUIRK_AUDIO_ALIGN_TRANSFER] = create_align_transfer_quirk |
3411 | }; | 3692 | }; |
3412 | 3693 | ||
3413 | if (quirk->type < QUIRK_TYPE_COUNT) { | 3694 | if (quirk->type < QUIRK_TYPE_COUNT) { |
@@ -3596,7 +3877,6 @@ static void *snd_usb_audio_probe(struct usb_device *dev, | |||
3596 | ifnum = get_iface_desc(alts)->bInterfaceNumber; | 3877 | ifnum = get_iface_desc(alts)->bInterfaceNumber; |
3597 | id = USB_ID(le16_to_cpu(dev->descriptor.idVendor), | 3878 | id = USB_ID(le16_to_cpu(dev->descriptor.idVendor), |
3598 | le16_to_cpu(dev->descriptor.idProduct)); | 3879 | le16_to_cpu(dev->descriptor.idProduct)); |
3599 | |||
3600 | if (quirk && quirk->ifnum >= 0 && ifnum != quirk->ifnum) | 3880 | if (quirk && quirk->ifnum >= 0 && ifnum != quirk->ifnum) |
3601 | goto __err_val; | 3881 | goto __err_val; |
3602 | 3882 | ||
@@ -3624,6 +3904,12 @@ static void *snd_usb_audio_probe(struct usb_device *dev, | |||
3624 | goto __err_val; | 3904 | goto __err_val; |
3625 | } | 3905 | } |
3626 | 3906 | ||
3907 | /* Access Music VirusTI Desktop */ | ||
3908 | if (id == USB_ID(0x133e, 0x0815)) { | ||
3909 | if (snd_usb_accessmusic_boot_quirk(dev) < 0) | ||
3910 | goto __err_val; | ||
3911 | } | ||
3912 | |||
3627 | /* | 3913 | /* |
3628 | * found a config. now register to ALSA | 3914 | * found a config. now register to ALSA |
3629 | */ | 3915 | */ |
@@ -3661,6 +3947,7 @@ static void *snd_usb_audio_probe(struct usb_device *dev, | |||
3661 | } | 3947 | } |
3662 | } | 3948 | } |
3663 | 3949 | ||
3950 | chip->txfr_quirk = 0; | ||
3664 | err = 1; /* continue */ | 3951 | err = 1; /* continue */ |
3665 | if (quirk && quirk->ifnum != QUIRK_NO_INTERFACE) { | 3952 | if (quirk && quirk->ifnum != QUIRK_NO_INTERFACE) { |
3666 | /* need some special handlings */ | 3953 | /* need some special handlings */ |
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 40ba8115fb81..6b016d4aac6b 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h | |||
@@ -21,93 +21,6 @@ | |||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
22 | */ | 22 | */ |
23 | 23 | ||
24 | |||
25 | /* | ||
26 | */ | ||
27 | |||
28 | #define USB_SUBCLASS_AUDIO_CONTROL 0x01 | ||
29 | #define USB_SUBCLASS_AUDIO_STREAMING 0x02 | ||
30 | #define USB_SUBCLASS_MIDI_STREAMING 0x03 | ||
31 | #define USB_SUBCLASS_VENDOR_SPEC 0xff | ||
32 | |||
33 | #define HEADER 0x01 | ||
34 | #define INPUT_TERMINAL 0x02 | ||
35 | #define OUTPUT_TERMINAL 0x03 | ||
36 | #define MIXER_UNIT 0x04 | ||
37 | #define SELECTOR_UNIT 0x05 | ||
38 | #define FEATURE_UNIT 0x06 | ||
39 | #define PROCESSING_UNIT 0x07 | ||
40 | #define EXTENSION_UNIT 0x08 | ||
41 | |||
42 | #define AS_GENERAL 0x01 | ||
43 | #define FORMAT_TYPE 0x02 | ||
44 | #define FORMAT_SPECIFIC 0x03 | ||
45 | |||
46 | #define EP_GENERAL 0x01 | ||
47 | |||
48 | #define MS_GENERAL 0x01 | ||
49 | #define MIDI_IN_JACK 0x02 | ||
50 | #define MIDI_OUT_JACK 0x03 | ||
51 | |||
52 | /* endpoint attributes */ | ||
53 | #define EP_ATTR_MASK 0x0c | ||
54 | #define EP_ATTR_ASYNC 0x04 | ||
55 | #define EP_ATTR_ADAPTIVE 0x08 | ||
56 | #define EP_ATTR_SYNC 0x0c | ||
57 | |||
58 | /* cs endpoint attributes */ | ||
59 | #define EP_CS_ATTR_SAMPLE_RATE 0x01 | ||
60 | #define EP_CS_ATTR_PITCH_CONTROL 0x02 | ||
61 | #define EP_CS_ATTR_FILL_MAX 0x80 | ||
62 | |||
63 | /* Audio Class specific Request Codes */ | ||
64 | |||
65 | #define SET_CUR 0x01 | ||
66 | #define GET_CUR 0x81 | ||
67 | #define SET_MIN 0x02 | ||
68 | #define GET_MIN 0x82 | ||
69 | #define SET_MAX 0x03 | ||
70 | #define GET_MAX 0x83 | ||
71 | #define SET_RES 0x04 | ||
72 | #define GET_RES 0x84 | ||
73 | #define SET_MEM 0x05 | ||
74 | #define GET_MEM 0x85 | ||
75 | #define GET_STAT 0xff | ||
76 | |||
77 | /* Terminal Control Selectors */ | ||
78 | |||
79 | #define COPY_PROTECT_CONTROL 0x01 | ||
80 | |||
81 | /* Endpoint Control Selectors */ | ||
82 | |||
83 | #define SAMPLING_FREQ_CONTROL 0x01 | ||
84 | #define PITCH_CONTROL 0x02 | ||
85 | |||
86 | /* Format Types */ | ||
87 | #define USB_FORMAT_TYPE_I 0x01 | ||
88 | #define USB_FORMAT_TYPE_II 0x02 | ||
89 | #define USB_FORMAT_TYPE_III 0x03 | ||
90 | |||
91 | /* type I */ | ||
92 | #define USB_AUDIO_FORMAT_PCM 0x01 | ||
93 | #define USB_AUDIO_FORMAT_PCM8 0x02 | ||
94 | #define USB_AUDIO_FORMAT_IEEE_FLOAT 0x03 | ||
95 | #define USB_AUDIO_FORMAT_ALAW 0x04 | ||
96 | #define USB_AUDIO_FORMAT_MU_LAW 0x05 | ||
97 | |||
98 | /* type II */ | ||
99 | #define USB_AUDIO_FORMAT_MPEG 0x1001 | ||
100 | #define USB_AUDIO_FORMAT_AC3 0x1002 | ||
101 | |||
102 | /* type III */ | ||
103 | #define USB_AUDIO_FORMAT_IEC1937_AC3 0x2001 | ||
104 | #define USB_AUDIO_FORMAT_IEC1937_MPEG1_LAYER1 0x2002 | ||
105 | #define USB_AUDIO_FORMAT_IEC1937_MPEG2_NOEXT 0x2003 | ||
106 | #define USB_AUDIO_FORMAT_IEC1937_MPEG2_EXT 0x2004 | ||
107 | #define USB_AUDIO_FORMAT_IEC1937_MPEG2_LAYER1_LS 0x2005 | ||
108 | #define USB_AUDIO_FORMAT_IEC1937_MPEG2_LAYER23_LS 0x2006 | ||
109 | |||
110 | |||
111 | /* maximum number of endpoints per interface */ | 24 | /* maximum number of endpoints per interface */ |
112 | #define MIDI_MAX_ENDPOINTS 2 | 25 | #define MIDI_MAX_ENDPOINTS 2 |
113 | 26 | ||
@@ -125,9 +38,13 @@ struct snd_usb_audio { | |||
125 | struct snd_card *card; | 38 | struct snd_card *card; |
126 | u32 usb_id; | 39 | u32 usb_id; |
127 | int shutdown; | 40 | int shutdown; |
41 | unsigned int txfr_quirk:1; /* Subframe boundaries on transfers */ | ||
128 | int num_interfaces; | 42 | int num_interfaces; |
129 | int num_suspended_intf; | 43 | int num_suspended_intf; |
130 | 44 | ||
45 | /* for audio class v2 */ | ||
46 | int clock_id; | ||
47 | |||
131 | struct list_head pcm_list; /* list of pcm streams */ | 48 | struct list_head pcm_list; /* list of pcm streams */ |
132 | int pcm_devs; | 49 | int pcm_devs; |
133 | 50 | ||
@@ -159,8 +76,8 @@ enum quirk_type { | |||
159 | QUIRK_AUDIO_STANDARD_INTERFACE, | 76 | QUIRK_AUDIO_STANDARD_INTERFACE, |
160 | QUIRK_AUDIO_FIXED_ENDPOINT, | 77 | QUIRK_AUDIO_FIXED_ENDPOINT, |
161 | QUIRK_AUDIO_EDIROL_UA1000, | 78 | QUIRK_AUDIO_EDIROL_UA1000, |
162 | QUIRK_AUDIO_EDIROL_UA101, | ||
163 | QUIRK_AUDIO_EDIROL_UAXX, | 79 | QUIRK_AUDIO_EDIROL_UAXX, |
80 | QUIRK_AUDIO_ALIGN_TRANSFER, | ||
164 | 81 | ||
165 | QUIRK_TYPE_COUNT | 82 | QUIRK_TYPE_COUNT |
166 | }; | 83 | }; |
@@ -209,6 +126,16 @@ struct snd_usb_midi_endpoint_info { | |||
209 | /* | 126 | /* |
210 | */ | 127 | */ |
211 | 128 | ||
129 | /*E-mu USB samplerate control quirk*/ | ||
130 | enum { | ||
131 | EMU_QUIRK_SR_44100HZ = 0, | ||
132 | EMU_QUIRK_SR_48000HZ, | ||
133 | EMU_QUIRK_SR_88200HZ, | ||
134 | EMU_QUIRK_SR_96000HZ, | ||
135 | EMU_QUIRK_SR_176400HZ, | ||
136 | EMU_QUIRK_SR_192000HZ | ||
137 | }; | ||
138 | |||
212 | #define combine_word(s) ((*(s)) | ((unsigned int)(s)[1] << 8)) | 139 | #define combine_word(s) ((*(s)) | ((unsigned int)(s)[1] << 8)) |
213 | #define combine_triple(s) (combine_word(s) | ((unsigned int)(s)[2] << 16)) | 140 | #define combine_triple(s) (combine_word(s) | ((unsigned int)(s)[2] << 16)) |
214 | #define combine_quad(s) (combine_triple(s) | ((unsigned int)(s)[3] << 24)) | 141 | #define combine_quad(s) (combine_triple(s) | ((unsigned int)(s)[3] << 24)) |
@@ -234,6 +161,9 @@ void snd_usbmidi_input_stop(struct list_head* p); | |||
234 | void snd_usbmidi_input_start(struct list_head* p); | 161 | void snd_usbmidi_input_start(struct list_head* p); |
235 | void snd_usbmidi_disconnect(struct list_head *p); | 162 | void snd_usbmidi_disconnect(struct list_head *p); |
236 | 163 | ||
164 | void snd_emuusb_set_samplerate(struct snd_usb_audio *chip, | ||
165 | unsigned char samplerate_id); | ||
166 | |||
237 | /* | 167 | /* |
238 | * retrieve usb_interface descriptor from the host interface | 168 | * retrieve usb_interface descriptor from the host interface |
239 | * (conditional for compatibility with the older API) | 169 | * (conditional for compatibility with the older API) |
diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c index 6e89b8368d9a..2c59afd99611 100644 --- a/sound/usb/usbmidi.c +++ b/sound/usb/usbmidi.c | |||
@@ -46,6 +46,8 @@ | |||
46 | #include <linux/timer.h> | 46 | #include <linux/timer.h> |
47 | #include <linux/usb.h> | 47 | #include <linux/usb.h> |
48 | #include <linux/wait.h> | 48 | #include <linux/wait.h> |
49 | #include <linux/usb/audio.h> | ||
50 | |||
49 | #include <sound/core.h> | 51 | #include <sound/core.h> |
50 | #include <sound/control.h> | 52 | #include <sound/control.h> |
51 | #include <sound/rawmidi.h> | 53 | #include <sound/rawmidi.h> |
@@ -1162,10 +1164,22 @@ static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi* umidi, | |||
1162 | pipe = usb_sndintpipe(umidi->dev, ep_info->out_ep); | 1164 | pipe = usb_sndintpipe(umidi->dev, ep_info->out_ep); |
1163 | else | 1165 | else |
1164 | pipe = usb_sndbulkpipe(umidi->dev, ep_info->out_ep); | 1166 | pipe = usb_sndbulkpipe(umidi->dev, ep_info->out_ep); |
1165 | if (umidi->usb_id == USB_ID(0x0a92, 0x1020)) /* ESI M4U */ | 1167 | switch (umidi->usb_id) { |
1166 | ep->max_transfer = 4; | 1168 | default: |
1167 | else | ||
1168 | ep->max_transfer = usb_maxpacket(umidi->dev, pipe, 1); | 1169 | ep->max_transfer = usb_maxpacket(umidi->dev, pipe, 1); |
1170 | break; | ||
1171 | /* | ||
1172 | * Various chips declare a packet size larger than 4 bytes, but | ||
1173 | * do not actually work with larger packets: | ||
1174 | */ | ||
1175 | case USB_ID(0x0a92, 0x1020): /* ESI M4U */ | ||
1176 | case USB_ID(0x1430, 0x474b): /* RedOctane GH MIDI INTERFACE */ | ||
1177 | case USB_ID(0x15ca, 0x0101): /* Textech USB Midi Cable */ | ||
1178 | case USB_ID(0x15ca, 0x1806): /* Textech USB Midi Cable */ | ||
1179 | case USB_ID(0x1a86, 0x752d): /* QinHeng CH345 "USB2.0-MIDI" */ | ||
1180 | ep->max_transfer = 4; | ||
1181 | break; | ||
1182 | } | ||
1169 | for (i = 0; i < OUTPUT_URBS; ++i) { | 1183 | for (i = 0; i < OUTPUT_URBS; ++i) { |
1170 | buffer = usb_buffer_alloc(umidi->dev, | 1184 | buffer = usb_buffer_alloc(umidi->dev, |
1171 | ep->max_transfer, GFP_KERNEL, | 1185 | ep->max_transfer, GFP_KERNEL, |
@@ -1407,6 +1421,12 @@ static struct port_info { | |||
1407 | EXTERNAL_PORT(0x086a, 0x0001, 8, "%s Broadcast"), | 1421 | EXTERNAL_PORT(0x086a, 0x0001, 8, "%s Broadcast"), |
1408 | EXTERNAL_PORT(0x086a, 0x0002, 8, "%s Broadcast"), | 1422 | EXTERNAL_PORT(0x086a, 0x0002, 8, "%s Broadcast"), |
1409 | EXTERNAL_PORT(0x086a, 0x0003, 4, "%s Broadcast"), | 1423 | EXTERNAL_PORT(0x086a, 0x0003, 4, "%s Broadcast"), |
1424 | /* Access Music Virus TI */ | ||
1425 | EXTERNAL_PORT(0x133e, 0x0815, 0, "%s MIDI"), | ||
1426 | PORT_INFO(0x133e, 0x0815, 1, "%s Synth", 0, | ||
1427 | SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | | ||
1428 | SNDRV_SEQ_PORT_TYPE_HARDWARE | | ||
1429 | SNDRV_SEQ_PORT_TYPE_SYNTHESIZER), | ||
1410 | }; | 1430 | }; |
1411 | 1431 | ||
1412 | static struct port_info *find_port_info(struct snd_usb_midi* umidi, int number) | 1432 | static struct port_info *find_port_info(struct snd_usb_midi* umidi, int number) |
@@ -1522,7 +1542,7 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi* umidi, | |||
1522 | if (hostif->extralen >= 7 && | 1542 | if (hostif->extralen >= 7 && |
1523 | ms_header->bLength >= 7 && | 1543 | ms_header->bLength >= 7 && |
1524 | ms_header->bDescriptorType == USB_DT_CS_INTERFACE && | 1544 | ms_header->bDescriptorType == USB_DT_CS_INTERFACE && |
1525 | ms_header->bDescriptorSubtype == HEADER) | 1545 | ms_header->bDescriptorSubtype == UAC_HEADER) |
1526 | snd_printdd(KERN_INFO "MIDIStreaming version %02x.%02x\n", | 1546 | snd_printdd(KERN_INFO "MIDIStreaming version %02x.%02x\n", |
1527 | ms_header->bcdMSC[1], ms_header->bcdMSC[0]); | 1547 | ms_header->bcdMSC[1], ms_header->bcdMSC[0]); |
1528 | else | 1548 | else |
@@ -1538,7 +1558,7 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi* umidi, | |||
1538 | if (hostep->extralen < 4 || | 1558 | if (hostep->extralen < 4 || |
1539 | ms_ep->bLength < 4 || | 1559 | ms_ep->bLength < 4 || |
1540 | ms_ep->bDescriptorType != USB_DT_CS_ENDPOINT || | 1560 | ms_ep->bDescriptorType != USB_DT_CS_ENDPOINT || |
1541 | ms_ep->bDescriptorSubtype != MS_GENERAL) | 1561 | ms_ep->bDescriptorSubtype != UAC_MS_GENERAL) |
1542 | continue; | 1562 | continue; |
1543 | if (usb_endpoint_dir_out(ep)) { | 1563 | if (usb_endpoint_dir_out(ep)) { |
1544 | if (endpoints[epidx].out_ep) { | 1564 | if (endpoints[epidx].out_ep) { |
@@ -1750,9 +1770,9 @@ static int snd_usbmidi_detect_yamaha(struct snd_usb_midi* umidi, | |||
1750 | cs_desc < hostif->extra + hostif->extralen && cs_desc[0] >= 2; | 1770 | cs_desc < hostif->extra + hostif->extralen && cs_desc[0] >= 2; |
1751 | cs_desc += cs_desc[0]) { | 1771 | cs_desc += cs_desc[0]) { |
1752 | if (cs_desc[1] == USB_DT_CS_INTERFACE) { | 1772 | if (cs_desc[1] == USB_DT_CS_INTERFACE) { |
1753 | if (cs_desc[2] == MIDI_IN_JACK) | 1773 | if (cs_desc[2] == UAC_MIDI_IN_JACK) |
1754 | endpoint->in_cables = (endpoint->in_cables << 1) | 1; | 1774 | endpoint->in_cables = (endpoint->in_cables << 1) | 1; |
1755 | else if (cs_desc[2] == MIDI_OUT_JACK) | 1775 | else if (cs_desc[2] == UAC_MIDI_OUT_JACK) |
1756 | endpoint->out_cables = (endpoint->out_cables << 1) | 1; | 1776 | endpoint->out_cables = (endpoint->out_cables << 1) | 1; |
1757 | } | 1777 | } |
1758 | } | 1778 | } |
diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index c998220b99c6..8e8f871b74ca 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c | |||
@@ -32,6 +32,8 @@ | |||
32 | #include <linux/slab.h> | 32 | #include <linux/slab.h> |
33 | #include <linux/string.h> | 33 | #include <linux/string.h> |
34 | #include <linux/usb.h> | 34 | #include <linux/usb.h> |
35 | #include <linux/usb/audio.h> | ||
36 | |||
35 | #include <sound/core.h> | 37 | #include <sound/core.h> |
36 | #include <sound/control.h> | 38 | #include <sound/control.h> |
37 | #include <sound/hwdep.h> | 39 | #include <sound/hwdep.h> |
@@ -69,13 +71,16 @@ static const struct rc_config { | |||
69 | { USB_ID(0x041e, 0x3048), 2, 2, 6, 6, 2, 0x6e91 }, /* Toshiba SB0500 */ | 71 | { USB_ID(0x041e, 0x3048), 2, 2, 6, 6, 2, 0x6e91 }, /* Toshiba SB0500 */ |
70 | }; | 72 | }; |
71 | 73 | ||
74 | #define MAX_ID_ELEMS 256 | ||
75 | |||
72 | struct usb_mixer_interface { | 76 | struct usb_mixer_interface { |
73 | struct snd_usb_audio *chip; | 77 | struct snd_usb_audio *chip; |
74 | unsigned int ctrlif; | 78 | unsigned int ctrlif; |
75 | struct list_head list; | 79 | struct list_head list; |
76 | unsigned int ignore_ctl_error; | 80 | unsigned int ignore_ctl_error; |
77 | struct urb *urb; | 81 | struct urb *urb; |
78 | struct usb_mixer_elem_info **id_elems; /* array[256], indexed by unit id */ | 82 | /* array[MAX_ID_ELEMS], indexed by unit id */ |
83 | struct usb_mixer_elem_info **id_elems; | ||
79 | 84 | ||
80 | /* Sound Blaster remote control stuff */ | 85 | /* Sound Blaster remote control stuff */ |
81 | const struct rc_config *rc_cfg; | 86 | const struct rc_config *rc_cfg; |
@@ -105,7 +110,7 @@ struct mixer_build { | |||
105 | struct usb_mixer_interface *mixer; | 110 | struct usb_mixer_interface *mixer; |
106 | unsigned char *buffer; | 111 | unsigned char *buffer; |
107 | unsigned int buflen; | 112 | unsigned int buflen; |
108 | DECLARE_BITMAP(unitbitmap, 256); | 113 | DECLARE_BITMAP(unitbitmap, MAX_ID_ELEMS); |
109 | struct usb_audio_term oterm; | 114 | struct usb_audio_term oterm; |
110 | const struct usbmix_name_map *map; | 115 | const struct usbmix_name_map *map; |
111 | const struct usbmix_selector_map *selector_map; | 116 | const struct usbmix_selector_map *selector_map; |
@@ -123,6 +128,7 @@ struct usb_mixer_elem_info { | |||
123 | int channels; | 128 | int channels; |
124 | int val_type; | 129 | int val_type; |
125 | int min, max, res; | 130 | int min, max, res; |
131 | int dBmin, dBmax; | ||
126 | int cached; | 132 | int cached; |
127 | int cache_val[MAX_CHANNELS]; | 133 | int cache_val[MAX_CHANNELS]; |
128 | u8 initialized; | 134 | u8 initialized; |
@@ -186,6 +192,21 @@ enum { | |||
186 | USB_PROC_DCR_RELEASE = 6, | 192 | USB_PROC_DCR_RELEASE = 6, |
187 | }; | 193 | }; |
188 | 194 | ||
195 | /*E-mu 0202(0404) eXtension Unit(XU) control*/ | ||
196 | enum { | ||
197 | USB_XU_CLOCK_RATE = 0xe301, | ||
198 | USB_XU_CLOCK_SOURCE = 0xe302, | ||
199 | USB_XU_DIGITAL_IO_STATUS = 0xe303, | ||
200 | USB_XU_DEVICE_OPTIONS = 0xe304, | ||
201 | USB_XU_DIRECT_MONITORING = 0xe305, | ||
202 | USB_XU_METERING = 0xe306 | ||
203 | }; | ||
204 | enum { | ||
205 | USB_XU_CLOCK_SOURCE_SELECTOR = 0x02, /* clock source*/ | ||
206 | USB_XU_CLOCK_RATE_SELECTOR = 0x03, /* clock rate */ | ||
207 | USB_XU_DIGITAL_FORMAT_SELECTOR = 0x01, /* the spdif format */ | ||
208 | USB_XU_SOFT_LIMIT_SELECTOR = 0x03 /* soft limiter */ | ||
209 | }; | ||
189 | 210 | ||
190 | /* | 211 | /* |
191 | * manual mapping of mixer names | 212 | * manual mapping of mixer names |
@@ -194,42 +215,50 @@ enum { | |||
194 | */ | 215 | */ |
195 | #include "usbmixer_maps.c" | 216 | #include "usbmixer_maps.c" |
196 | 217 | ||
197 | /* get the mapped name if the unit matches */ | 218 | static const struct usbmix_name_map * |
198 | static int check_mapped_name(struct mixer_build *state, int unitid, int control, char *buf, int buflen) | 219 | find_map(struct mixer_build *state, int unitid, int control) |
199 | { | 220 | { |
200 | const struct usbmix_name_map *p; | 221 | const struct usbmix_name_map *p = state->map; |
201 | 222 | ||
202 | if (! state->map) | 223 | if (!p) |
203 | return 0; | 224 | return NULL; |
204 | 225 | ||
205 | for (p = state->map; p->id; p++) { | 226 | for (p = state->map; p->id; p++) { |
206 | if (p->id == unitid && p->name && | 227 | if (p->id == unitid && |
207 | (! control || ! p->control || control == p->control)) { | 228 | (!control || !p->control || control == p->control)) |
208 | buflen--; | 229 | return p; |
209 | return strlcpy(buf, p->name, buflen); | ||
210 | } | ||
211 | } | 230 | } |
212 | return 0; | 231 | return NULL; |
213 | } | 232 | } |
214 | 233 | ||
215 | /* check whether the control should be ignored */ | 234 | /* get the mapped name if the unit matches */ |
216 | static int check_ignored_ctl(struct mixer_build *state, int unitid, int control) | 235 | static int |
236 | check_mapped_name(const struct usbmix_name_map *p, char *buf, int buflen) | ||
217 | { | 237 | { |
218 | const struct usbmix_name_map *p; | 238 | if (!p || !p->name) |
239 | return 0; | ||
240 | |||
241 | buflen--; | ||
242 | return strlcpy(buf, p->name, buflen); | ||
243 | } | ||
219 | 244 | ||
220 | if (! state->map) | 245 | /* check whether the control should be ignored */ |
246 | static inline int | ||
247 | check_ignored_ctl(const struct usbmix_name_map *p) | ||
248 | { | ||
249 | if (!p || p->name || p->dB) | ||
221 | return 0; | 250 | return 0; |
222 | for (p = state->map; p->id; p++) { | 251 | return 1; |
223 | if (p->id == unitid && ! p->name && | 252 | } |
224 | (! control || ! p->control || control == p->control)) { | 253 | |
225 | /* | 254 | /* dB mapping */ |
226 | printk(KERN_DEBUG "ignored control %d:%d\n", | 255 | static inline void check_mapped_dB(const struct usbmix_name_map *p, |
227 | unitid, control); | 256 | struct usb_mixer_elem_info *cval) |
228 | */ | 257 | { |
229 | return 1; | 258 | if (p && p->dB) { |
230 | } | 259 | cval->dBmin = p->dB->min; |
260 | cval->dBmax = p->dB->max; | ||
231 | } | 261 | } |
232 | return 0; | ||
233 | } | 262 | } |
234 | 263 | ||
235 | /* get the mapped selector source name */ | 264 | /* get the mapped selector source name */ |
@@ -257,7 +286,7 @@ static void *find_audio_control_unit(struct mixer_build *state, unsigned char un | |||
257 | p = NULL; | 286 | p = NULL; |
258 | while ((p = snd_usb_find_desc(state->buffer, state->buflen, p, | 287 | while ((p = snd_usb_find_desc(state->buffer, state->buflen, p, |
259 | USB_DT_CS_INTERFACE)) != NULL) { | 288 | USB_DT_CS_INTERFACE)) != NULL) { |
260 | if (p[0] >= 4 && p[2] >= INPUT_TERMINAL && p[2] <= EXTENSION_UNIT && p[3] == unit) | 289 | if (p[0] >= 4 && p[2] >= UAC_INPUT_TERMINAL && p[2] <= UAC_EXTENSION_UNIT_V1 && p[3] == unit) |
261 | return p; | 290 | return p; |
262 | } | 291 | } |
263 | return NULL; | 292 | return NULL; |
@@ -378,14 +407,14 @@ static int get_ctl_value(struct usb_mixer_elem_info *cval, int request, int vali | |||
378 | 407 | ||
379 | static int get_cur_ctl_value(struct usb_mixer_elem_info *cval, int validx, int *value) | 408 | static int get_cur_ctl_value(struct usb_mixer_elem_info *cval, int validx, int *value) |
380 | { | 409 | { |
381 | return get_ctl_value(cval, GET_CUR, validx, value); | 410 | return get_ctl_value(cval, UAC_GET_CUR, validx, value); |
382 | } | 411 | } |
383 | 412 | ||
384 | /* channel = 0: master, 1 = first channel */ | 413 | /* channel = 0: master, 1 = first channel */ |
385 | static inline int get_cur_mix_raw(struct usb_mixer_elem_info *cval, | 414 | static inline int get_cur_mix_raw(struct usb_mixer_elem_info *cval, |
386 | int channel, int *value) | 415 | int channel, int *value) |
387 | { | 416 | { |
388 | return get_ctl_value(cval, GET_CUR, (cval->control << 8) | channel, value); | 417 | return get_ctl_value(cval, UAC_GET_CUR, (cval->control << 8) | channel, value); |
389 | } | 418 | } |
390 | 419 | ||
391 | static int get_cur_mix_value(struct usb_mixer_elem_info *cval, | 420 | static int get_cur_mix_value(struct usb_mixer_elem_info *cval, |
@@ -439,14 +468,14 @@ static int set_ctl_value(struct usb_mixer_elem_info *cval, int request, int vali | |||
439 | 468 | ||
440 | static int set_cur_ctl_value(struct usb_mixer_elem_info *cval, int validx, int value) | 469 | static int set_cur_ctl_value(struct usb_mixer_elem_info *cval, int validx, int value) |
441 | { | 470 | { |
442 | return set_ctl_value(cval, SET_CUR, validx, value); | 471 | return set_ctl_value(cval, UAC_SET_CUR, validx, value); |
443 | } | 472 | } |
444 | 473 | ||
445 | static int set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel, | 474 | static int set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel, |
446 | int index, int value) | 475 | int index, int value) |
447 | { | 476 | { |
448 | int err; | 477 | int err; |
449 | err = set_ctl_value(cval, SET_CUR, (cval->control << 8) | channel, | 478 | err = set_ctl_value(cval, UAC_SET_CUR, (cval->control << 8) | channel, |
450 | value); | 479 | value); |
451 | if (err < 0) | 480 | if (err < 0) |
452 | return err; | 481 | return err; |
@@ -466,20 +495,8 @@ static int mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag, | |||
466 | 495 | ||
467 | if (size < sizeof(scale)) | 496 | if (size < sizeof(scale)) |
468 | return -ENOMEM; | 497 | return -ENOMEM; |
469 | /* USB descriptions contain the dB scale in 1/256 dB unit | 498 | scale[2] = cval->dBmin; |
470 | * while ALSA TLV contains in 1/100 dB unit | 499 | scale[3] = cval->dBmax; |
471 | */ | ||
472 | scale[2] = (convert_signed_value(cval, cval->min) * 100) / 256; | ||
473 | scale[3] = (convert_signed_value(cval, cval->max) * 100) / 256; | ||
474 | if (scale[3] <= scale[2]) { | ||
475 | /* something is wrong; assume it's either from/to 0dB */ | ||
476 | if (scale[2] < 0) | ||
477 | scale[3] = 0; | ||
478 | else if (scale[2] > 0) | ||
479 | scale[2] = 0; | ||
480 | else /* totally crap, return an error */ | ||
481 | return -EINVAL; | ||
482 | } | ||
483 | if (copy_to_user(_tlv, scale, sizeof(scale))) | 500 | if (copy_to_user(_tlv, scale, sizeof(scale))) |
484 | return -EFAULT; | 501 | return -EFAULT; |
485 | return 0; | 502 | return 0; |
@@ -588,13 +605,13 @@ static int get_term_name(struct mixer_build *state, struct usb_audio_term *iterm | |||
588 | if (term_only) | 605 | if (term_only) |
589 | return 0; | 606 | return 0; |
590 | switch (iterm->type >> 16) { | 607 | switch (iterm->type >> 16) { |
591 | case SELECTOR_UNIT: | 608 | case UAC_SELECTOR_UNIT: |
592 | strcpy(name, "Selector"); return 8; | 609 | strcpy(name, "Selector"); return 8; |
593 | case PROCESSING_UNIT: | 610 | case UAC_PROCESSING_UNIT_V1: |
594 | strcpy(name, "Process Unit"); return 12; | 611 | strcpy(name, "Process Unit"); return 12; |
595 | case EXTENSION_UNIT: | 612 | case UAC_EXTENSION_UNIT_V1: |
596 | strcpy(name, "Ext Unit"); return 8; | 613 | strcpy(name, "Ext Unit"); return 8; |
597 | case MIXER_UNIT: | 614 | case UAC_MIXER_UNIT: |
598 | strcpy(name, "Mixer"); return 5; | 615 | strcpy(name, "Mixer"); return 5; |
599 | default: | 616 | default: |
600 | return sprintf(name, "Unit %d", iterm->id); | 617 | return sprintf(name, "Unit %d", iterm->id); |
@@ -633,22 +650,22 @@ static int check_input_term(struct mixer_build *state, int id, struct usb_audio_ | |||
633 | while ((p1 = find_audio_control_unit(state, id)) != NULL) { | 650 | while ((p1 = find_audio_control_unit(state, id)) != NULL) { |
634 | term->id = id; | 651 | term->id = id; |
635 | switch (p1[2]) { | 652 | switch (p1[2]) { |
636 | case INPUT_TERMINAL: | 653 | case UAC_INPUT_TERMINAL: |
637 | term->type = combine_word(p1 + 4); | 654 | term->type = combine_word(p1 + 4); |
638 | term->channels = p1[7]; | 655 | term->channels = p1[7]; |
639 | term->chconfig = combine_word(p1 + 8); | 656 | term->chconfig = combine_word(p1 + 8); |
640 | term->name = p1[11]; | 657 | term->name = p1[11]; |
641 | return 0; | 658 | return 0; |
642 | case FEATURE_UNIT: | 659 | case UAC_FEATURE_UNIT: |
643 | id = p1[4]; | 660 | id = p1[4]; |
644 | break; /* continue to parse */ | 661 | break; /* continue to parse */ |
645 | case MIXER_UNIT: | 662 | case UAC_MIXER_UNIT: |
646 | term->type = p1[2] << 16; /* virtual type */ | 663 | term->type = p1[2] << 16; /* virtual type */ |
647 | term->channels = p1[5 + p1[4]]; | 664 | term->channels = p1[5 + p1[4]]; |
648 | term->chconfig = combine_word(p1 + 6 + p1[4]); | 665 | term->chconfig = combine_word(p1 + 6 + p1[4]); |
649 | term->name = p1[p1[0] - 1]; | 666 | term->name = p1[p1[0] - 1]; |
650 | return 0; | 667 | return 0; |
651 | case SELECTOR_UNIT: | 668 | case UAC_SELECTOR_UNIT: |
652 | /* call recursively to retrieve the channel info */ | 669 | /* call recursively to retrieve the channel info */ |
653 | if (check_input_term(state, p1[5], term) < 0) | 670 | if (check_input_term(state, p1[5], term) < 0) |
654 | return -ENODEV; | 671 | return -ENODEV; |
@@ -656,8 +673,8 @@ static int check_input_term(struct mixer_build *state, int id, struct usb_audio_ | |||
656 | term->id = id; | 673 | term->id = id; |
657 | term->name = p1[9 + p1[0] - 1]; | 674 | term->name = p1[9 + p1[0] - 1]; |
658 | return 0; | 675 | return 0; |
659 | case PROCESSING_UNIT: | 676 | case UAC_PROCESSING_UNIT_V1: |
660 | case EXTENSION_UNIT: | 677 | case UAC_EXTENSION_UNIT_V1: |
661 | if (p1[6] == 1) { | 678 | if (p1[6] == 1) { |
662 | id = p1[7]; | 679 | id = p1[7]; |
663 | break; /* continue to parse */ | 680 | break; /* continue to parse */ |
@@ -720,6 +737,7 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min) | |||
720 | cval->min = default_min; | 737 | cval->min = default_min; |
721 | cval->max = cval->min + 1; | 738 | cval->max = cval->min + 1; |
722 | cval->res = 1; | 739 | cval->res = 1; |
740 | cval->dBmin = cval->dBmax = 0; | ||
723 | 741 | ||
724 | if (cval->val_type == USB_MIXER_BOOLEAN || | 742 | if (cval->val_type == USB_MIXER_BOOLEAN || |
725 | cval->val_type == USB_MIXER_INV_BOOLEAN) { | 743 | cval->val_type == USB_MIXER_INV_BOOLEAN) { |
@@ -734,23 +752,23 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min) | |||
734 | break; | 752 | break; |
735 | } | 753 | } |
736 | } | 754 | } |
737 | if (get_ctl_value(cval, GET_MAX, (cval->control << 8) | minchn, &cval->max) < 0 || | 755 | if (get_ctl_value(cval, UAC_GET_MAX, (cval->control << 8) | minchn, &cval->max) < 0 || |
738 | get_ctl_value(cval, GET_MIN, (cval->control << 8) | minchn, &cval->min) < 0) { | 756 | get_ctl_value(cval, UAC_GET_MIN, (cval->control << 8) | minchn, &cval->min) < 0) { |
739 | snd_printd(KERN_ERR "%d:%d: cannot get min/max values for control %d (id %d)\n", | 757 | snd_printd(KERN_ERR "%d:%d: cannot get min/max values for control %d (id %d)\n", |
740 | cval->id, cval->mixer->ctrlif, cval->control, cval->id); | 758 | cval->id, cval->mixer->ctrlif, cval->control, cval->id); |
741 | return -EINVAL; | 759 | return -EINVAL; |
742 | } | 760 | } |
743 | if (get_ctl_value(cval, GET_RES, (cval->control << 8) | minchn, &cval->res) < 0) { | 761 | if (get_ctl_value(cval, UAC_GET_RES, (cval->control << 8) | minchn, &cval->res) < 0) { |
744 | cval->res = 1; | 762 | cval->res = 1; |
745 | } else { | 763 | } else { |
746 | int last_valid_res = cval->res; | 764 | int last_valid_res = cval->res; |
747 | 765 | ||
748 | while (cval->res > 1) { | 766 | while (cval->res > 1) { |
749 | if (set_ctl_value(cval, SET_RES, (cval->control << 8) | minchn, cval->res / 2) < 0) | 767 | if (set_ctl_value(cval, UAC_SET_RES, (cval->control << 8) | minchn, cval->res / 2) < 0) |
750 | break; | 768 | break; |
751 | cval->res /= 2; | 769 | cval->res /= 2; |
752 | } | 770 | } |
753 | if (get_ctl_value(cval, GET_RES, (cval->control << 8) | minchn, &cval->res) < 0) | 771 | if (get_ctl_value(cval, UAC_GET_RES, (cval->control << 8) | minchn, &cval->res) < 0) |
754 | cval->res = last_valid_res; | 772 | cval->res = last_valid_res; |
755 | } | 773 | } |
756 | if (cval->res == 0) | 774 | if (cval->res == 0) |
@@ -787,6 +805,24 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min) | |||
787 | 805 | ||
788 | cval->initialized = 1; | 806 | cval->initialized = 1; |
789 | } | 807 | } |
808 | |||
809 | /* USB descriptions contain the dB scale in 1/256 dB unit | ||
810 | * while ALSA TLV contains in 1/100 dB unit | ||
811 | */ | ||
812 | cval->dBmin = (convert_signed_value(cval, cval->min) * 100) / 256; | ||
813 | cval->dBmax = (convert_signed_value(cval, cval->max) * 100) / 256; | ||
814 | if (cval->dBmin > cval->dBmax) { | ||
815 | /* something is wrong; assume it's either from/to 0dB */ | ||
816 | if (cval->dBmin < 0) | ||
817 | cval->dBmax = 0; | ||
818 | else if (cval->dBmin > 0) | ||
819 | cval->dBmin = 0; | ||
820 | if (cval->dBmin > cval->dBmax) { | ||
821 | /* totally crap, return an error */ | ||
822 | return -EINVAL; | ||
823 | } | ||
824 | } | ||
825 | |||
790 | return 0; | 826 | return 0; |
791 | } | 827 | } |
792 | 828 | ||
@@ -912,6 +948,7 @@ static void build_feature_ctl(struct mixer_build *state, unsigned char *desc, | |||
912 | int nameid = desc[desc[0] - 1]; | 948 | int nameid = desc[desc[0] - 1]; |
913 | struct snd_kcontrol *kctl; | 949 | struct snd_kcontrol *kctl; |
914 | struct usb_mixer_elem_info *cval; | 950 | struct usb_mixer_elem_info *cval; |
951 | const struct usbmix_name_map *map; | ||
915 | 952 | ||
916 | control++; /* change from zero-based to 1-based value */ | 953 | control++; /* change from zero-based to 1-based value */ |
917 | 954 | ||
@@ -920,7 +957,8 @@ static void build_feature_ctl(struct mixer_build *state, unsigned char *desc, | |||
920 | return; | 957 | return; |
921 | } | 958 | } |
922 | 959 | ||
923 | if (check_ignored_ctl(state, unitid, control)) | 960 | map = find_map(state, unitid, control); |
961 | if (check_ignored_ctl(map)) | ||
924 | return; | 962 | return; |
925 | 963 | ||
926 | cval = kzalloc(sizeof(*cval), GFP_KERNEL); | 964 | cval = kzalloc(sizeof(*cval), GFP_KERNEL); |
@@ -954,10 +992,11 @@ static void build_feature_ctl(struct mixer_build *state, unsigned char *desc, | |||
954 | } | 992 | } |
955 | kctl->private_free = usb_mixer_elem_free; | 993 | kctl->private_free = usb_mixer_elem_free; |
956 | 994 | ||
957 | len = check_mapped_name(state, unitid, control, kctl->id.name, sizeof(kctl->id.name)); | 995 | len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name)); |
958 | mapped_name = len != 0; | 996 | mapped_name = len != 0; |
959 | if (! len && nameid) | 997 | if (! len && nameid) |
960 | len = snd_usb_copy_string_desc(state, nameid, kctl->id.name, sizeof(kctl->id.name)); | 998 | len = snd_usb_copy_string_desc(state, nameid, |
999 | kctl->id.name, sizeof(kctl->id.name)); | ||
961 | 1000 | ||
962 | switch (control) { | 1001 | switch (control) { |
963 | case USB_FEATURE_MUTE: | 1002 | case USB_FEATURE_MUTE: |
@@ -995,6 +1034,7 @@ static void build_feature_ctl(struct mixer_build *state, unsigned char *desc, | |||
995 | kctl->vd[0].access |= | 1034 | kctl->vd[0].access |= |
996 | SNDRV_CTL_ELEM_ACCESS_TLV_READ | | 1035 | SNDRV_CTL_ELEM_ACCESS_TLV_READ | |
997 | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK; | 1036 | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK; |
1037 | check_mapped_dB(map, cval); | ||
998 | } | 1038 | } |
999 | break; | 1039 | break; |
1000 | 1040 | ||
@@ -1048,29 +1088,30 @@ static void build_feature_ctl(struct mixer_build *state, unsigned char *desc, | |||
1048 | * | 1088 | * |
1049 | * most of controlls are defined here. | 1089 | * most of controlls are defined here. |
1050 | */ | 1090 | */ |
1051 | static int parse_audio_feature_unit(struct mixer_build *state, int unitid, unsigned char *ftr) | 1091 | static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void *_ftr) |
1052 | { | 1092 | { |
1053 | int channels, i, j; | 1093 | int channels, i, j; |
1054 | struct usb_audio_term iterm; | 1094 | struct usb_audio_term iterm; |
1055 | unsigned int master_bits, first_ch_bits; | 1095 | unsigned int master_bits, first_ch_bits; |
1056 | int err, csize; | 1096 | int err, csize; |
1097 | struct uac_feature_unit_descriptor *ftr = _ftr; | ||
1057 | 1098 | ||
1058 | if (ftr[0] < 7 || ! (csize = ftr[5]) || ftr[0] < 7 + csize) { | 1099 | if (ftr->bLength < 7 || ! (csize = ftr->bControlSize) || ftr->bLength < 7 + csize) { |
1059 | snd_printk(KERN_ERR "usbaudio: unit %u: invalid FEATURE_UNIT descriptor\n", unitid); | 1100 | snd_printk(KERN_ERR "usbaudio: unit %u: invalid UAC_FEATURE_UNIT descriptor\n", unitid); |
1060 | return -EINVAL; | 1101 | return -EINVAL; |
1061 | } | 1102 | } |
1062 | 1103 | ||
1063 | /* parse the source unit */ | 1104 | /* parse the source unit */ |
1064 | if ((err = parse_audio_unit(state, ftr[4])) < 0) | 1105 | if ((err = parse_audio_unit(state, ftr->bSourceID)) < 0) |
1065 | return err; | 1106 | return err; |
1066 | 1107 | ||
1067 | /* determine the input source type and name */ | 1108 | /* determine the input source type and name */ |
1068 | if (check_input_term(state, ftr[4], &iterm) < 0) | 1109 | if (check_input_term(state, ftr->bSourceID, &iterm) < 0) |
1069 | return -EINVAL; | 1110 | return -EINVAL; |
1070 | 1111 | ||
1071 | channels = (ftr[0] - 7) / csize - 1; | 1112 | channels = (ftr->bLength - 7) / csize - 1; |
1072 | 1113 | ||
1073 | master_bits = snd_usb_combine_bytes(ftr + 6, csize); | 1114 | master_bits = snd_usb_combine_bytes(ftr->controls, csize); |
1074 | /* master configuration quirks */ | 1115 | /* master configuration quirks */ |
1075 | switch (state->chip->usb_id) { | 1116 | switch (state->chip->usb_id) { |
1076 | case USB_ID(0x08bb, 0x2702): | 1117 | case USB_ID(0x08bb, 0x2702): |
@@ -1081,21 +1122,21 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, unsig | |||
1081 | break; | 1122 | break; |
1082 | } | 1123 | } |
1083 | if (channels > 0) | 1124 | if (channels > 0) |
1084 | first_ch_bits = snd_usb_combine_bytes(ftr + 6 + csize, csize); | 1125 | first_ch_bits = snd_usb_combine_bytes(ftr->controls + csize, csize); |
1085 | else | 1126 | else |
1086 | first_ch_bits = 0; | 1127 | first_ch_bits = 0; |
1087 | /* check all control types */ | 1128 | /* check all control types */ |
1088 | for (i = 0; i < 10; i++) { | 1129 | for (i = 0; i < 10; i++) { |
1089 | unsigned int ch_bits = 0; | 1130 | unsigned int ch_bits = 0; |
1090 | for (j = 0; j < channels; j++) { | 1131 | for (j = 0; j < channels; j++) { |
1091 | unsigned int mask = snd_usb_combine_bytes(ftr + 6 + csize * (j+1), csize); | 1132 | unsigned int mask = snd_usb_combine_bytes(ftr->controls + csize * (j+1), csize); |
1092 | if (mask & (1 << i)) | 1133 | if (mask & (1 << i)) |
1093 | ch_bits |= (1 << j); | 1134 | ch_bits |= (1 << j); |
1094 | } | 1135 | } |
1095 | if (ch_bits & 1) /* the first channel must be set (for ease of programming) */ | 1136 | if (ch_bits & 1) /* the first channel must be set (for ease of programming) */ |
1096 | build_feature_ctl(state, ftr, ch_bits, i, &iterm, unitid); | 1137 | build_feature_ctl(state, _ftr, ch_bits, i, &iterm, unitid); |
1097 | if (master_bits & (1 << i)) | 1138 | if (master_bits & (1 << i)) |
1098 | build_feature_ctl(state, ftr, 0, i, &iterm, unitid); | 1139 | build_feature_ctl(state, _ftr, 0, i, &iterm, unitid); |
1099 | } | 1140 | } |
1100 | 1141 | ||
1101 | return 0; | 1142 | return 0; |
@@ -1122,8 +1163,10 @@ static void build_mixer_unit_ctl(struct mixer_build *state, unsigned char *desc, | |||
1122 | unsigned int num_outs = desc[5 + input_pins]; | 1163 | unsigned int num_outs = desc[5 + input_pins]; |
1123 | unsigned int i, len; | 1164 | unsigned int i, len; |
1124 | struct snd_kcontrol *kctl; | 1165 | struct snd_kcontrol *kctl; |
1166 | const struct usbmix_name_map *map; | ||
1125 | 1167 | ||
1126 | if (check_ignored_ctl(state, unitid, 0)) | 1168 | map = find_map(state, unitid, 0); |
1169 | if (check_ignored_ctl(map)) | ||
1127 | return; | 1170 | return; |
1128 | 1171 | ||
1129 | cval = kzalloc(sizeof(*cval), GFP_KERNEL); | 1172 | cval = kzalloc(sizeof(*cval), GFP_KERNEL); |
@@ -1152,7 +1195,7 @@ static void build_mixer_unit_ctl(struct mixer_build *state, unsigned char *desc, | |||
1152 | } | 1195 | } |
1153 | kctl->private_free = usb_mixer_elem_free; | 1196 | kctl->private_free = usb_mixer_elem_free; |
1154 | 1197 | ||
1155 | len = check_mapped_name(state, unitid, 0, kctl->id.name, sizeof(kctl->id.name)); | 1198 | len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name)); |
1156 | if (! len) | 1199 | if (! len) |
1157 | len = get_term_name(state, iterm, kctl->id.name, sizeof(kctl->id.name), 0); | 1200 | len = get_term_name(state, iterm, kctl->id.name, sizeof(kctl->id.name), 0); |
1158 | if (! len) | 1201 | if (! len) |
@@ -1330,7 +1373,32 @@ static struct procunit_info procunits[] = { | |||
1330 | { USB_PROC_DCR, "DCR", dcr_proc_info }, | 1373 | { USB_PROC_DCR, "DCR", dcr_proc_info }, |
1331 | { 0 }, | 1374 | { 0 }, |
1332 | }; | 1375 | }; |
1333 | 1376 | /* | |
1377 | * predefined data for extension units | ||
1378 | */ | ||
1379 | static struct procunit_value_info clock_rate_xu_info[] = { | ||
1380 | { USB_XU_CLOCK_RATE_SELECTOR, "Selector", USB_MIXER_U8, 0 }, | ||
1381 | { 0 } | ||
1382 | }; | ||
1383 | static struct procunit_value_info clock_source_xu_info[] = { | ||
1384 | { USB_XU_CLOCK_SOURCE_SELECTOR, "External", USB_MIXER_BOOLEAN }, | ||
1385 | { 0 } | ||
1386 | }; | ||
1387 | static struct procunit_value_info spdif_format_xu_info[] = { | ||
1388 | { USB_XU_DIGITAL_FORMAT_SELECTOR, "SPDIF/AC3", USB_MIXER_BOOLEAN }, | ||
1389 | { 0 } | ||
1390 | }; | ||
1391 | static struct procunit_value_info soft_limit_xu_info[] = { | ||
1392 | { USB_XU_SOFT_LIMIT_SELECTOR, " ", USB_MIXER_BOOLEAN }, | ||
1393 | { 0 } | ||
1394 | }; | ||
1395 | static struct procunit_info extunits[] = { | ||
1396 | { USB_XU_CLOCK_RATE, "Clock rate", clock_rate_xu_info }, | ||
1397 | { USB_XU_CLOCK_SOURCE, "DigitalIn CLK source", clock_source_xu_info }, | ||
1398 | { USB_XU_DIGITAL_IO_STATUS, "DigitalOut format:", spdif_format_xu_info }, | ||
1399 | { USB_XU_DEVICE_OPTIONS, "AnalogueIn Soft Limit", soft_limit_xu_info }, | ||
1400 | { 0 } | ||
1401 | }; | ||
1334 | /* | 1402 | /* |
1335 | * build a processing/extension unit | 1403 | * build a processing/extension unit |
1336 | */ | 1404 | */ |
@@ -1342,6 +1410,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, unsigned | |||
1342 | int i, err, nameid, type, len; | 1410 | int i, err, nameid, type, len; |
1343 | struct procunit_info *info; | 1411 | struct procunit_info *info; |
1344 | struct procunit_value_info *valinfo; | 1412 | struct procunit_value_info *valinfo; |
1413 | const struct usbmix_name_map *map; | ||
1345 | static struct procunit_value_info default_value_info[] = { | 1414 | static struct procunit_value_info default_value_info[] = { |
1346 | { 0x01, "Switch", USB_MIXER_BOOLEAN }, | 1415 | { 0x01, "Switch", USB_MIXER_BOOLEAN }, |
1347 | { 0 } | 1416 | { 0 } |
@@ -1371,7 +1440,8 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, unsigned | |||
1371 | /* FIXME: bitmap might be longer than 8bit */ | 1440 | /* FIXME: bitmap might be longer than 8bit */ |
1372 | if (! (dsc[12 + num_ins] & (1 << (valinfo->control - 1)))) | 1441 | if (! (dsc[12 + num_ins] & (1 << (valinfo->control - 1)))) |
1373 | continue; | 1442 | continue; |
1374 | if (check_ignored_ctl(state, unitid, valinfo->control)) | 1443 | map = find_map(state, unitid, valinfo->control); |
1444 | if (check_ignored_ctl(map)) | ||
1375 | continue; | 1445 | continue; |
1376 | cval = kzalloc(sizeof(*cval), GFP_KERNEL); | 1446 | cval = kzalloc(sizeof(*cval), GFP_KERNEL); |
1377 | if (! cval) { | 1447 | if (! cval) { |
@@ -1391,8 +1461,18 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, unsigned | |||
1391 | cval->max = dsc[15]; | 1461 | cval->max = dsc[15]; |
1392 | cval->res = 1; | 1462 | cval->res = 1; |
1393 | cval->initialized = 1; | 1463 | cval->initialized = 1; |
1394 | } else | 1464 | } else { |
1395 | get_min_max(cval, valinfo->min_value); | 1465 | if (type == USB_XU_CLOCK_RATE) { |
1466 | /* E-Mu USB 0404/0202/TrackerPre | ||
1467 | * samplerate control quirk | ||
1468 | */ | ||
1469 | cval->min = 0; | ||
1470 | cval->max = 5; | ||
1471 | cval->res = 1; | ||
1472 | cval->initialized = 1; | ||
1473 | } else | ||
1474 | get_min_max(cval, valinfo->min_value); | ||
1475 | } | ||
1396 | 1476 | ||
1397 | kctl = snd_ctl_new1(&mixer_procunit_ctl, cval); | 1477 | kctl = snd_ctl_new1(&mixer_procunit_ctl, cval); |
1398 | if (! kctl) { | 1478 | if (! kctl) { |
@@ -1402,8 +1482,9 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, unsigned | |||
1402 | } | 1482 | } |
1403 | kctl->private_free = usb_mixer_elem_free; | 1483 | kctl->private_free = usb_mixer_elem_free; |
1404 | 1484 | ||
1405 | if (check_mapped_name(state, unitid, cval->control, kctl->id.name, sizeof(kctl->id.name))) | 1485 | if (check_mapped_name(map, kctl->id.name, |
1406 | ; | 1486 | sizeof(kctl->id.name))) |
1487 | /* nothing */ ; | ||
1407 | else if (info->name) | 1488 | else if (info->name) |
1408 | strlcpy(kctl->id.name, info->name, sizeof(kctl->id.name)); | 1489 | strlcpy(kctl->id.name, info->name, sizeof(kctl->id.name)); |
1409 | else { | 1490 | else { |
@@ -1433,7 +1514,7 @@ static int parse_audio_processing_unit(struct mixer_build *state, int unitid, un | |||
1433 | 1514 | ||
1434 | static int parse_audio_extension_unit(struct mixer_build *state, int unitid, unsigned char *desc) | 1515 | static int parse_audio_extension_unit(struct mixer_build *state, int unitid, unsigned char *desc) |
1435 | { | 1516 | { |
1436 | return build_audio_procunit(state, unitid, desc, NULL, "Extension Unit"); | 1517 | return build_audio_procunit(state, unitid, desc, extunits, "Extension Unit"); |
1437 | } | 1518 | } |
1438 | 1519 | ||
1439 | 1520 | ||
@@ -1542,6 +1623,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, unsi | |||
1542 | int err; | 1623 | int err; |
1543 | struct usb_mixer_elem_info *cval; | 1624 | struct usb_mixer_elem_info *cval; |
1544 | struct snd_kcontrol *kctl; | 1625 | struct snd_kcontrol *kctl; |
1626 | const struct usbmix_name_map *map; | ||
1545 | char **namelist; | 1627 | char **namelist; |
1546 | 1628 | ||
1547 | if (! num_ins || desc[0] < 5 + num_ins) { | 1629 | if (! num_ins || desc[0] < 5 + num_ins) { |
@@ -1557,7 +1639,8 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, unsi | |||
1557 | if (num_ins == 1) /* only one ? nonsense! */ | 1639 | if (num_ins == 1) /* only one ? nonsense! */ |
1558 | return 0; | 1640 | return 0; |
1559 | 1641 | ||
1560 | if (check_ignored_ctl(state, unitid, 0)) | 1642 | map = find_map(state, unitid, 0); |
1643 | if (check_ignored_ctl(map)) | ||
1561 | return 0; | 1644 | return 0; |
1562 | 1645 | ||
1563 | cval = kzalloc(sizeof(*cval), GFP_KERNEL); | 1646 | cval = kzalloc(sizeof(*cval), GFP_KERNEL); |
@@ -1612,7 +1695,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, unsi | |||
1612 | kctl->private_free = usb_mixer_selector_elem_free; | 1695 | kctl->private_free = usb_mixer_selector_elem_free; |
1613 | 1696 | ||
1614 | nameid = desc[desc[0] - 1]; | 1697 | nameid = desc[desc[0] - 1]; |
1615 | len = check_mapped_name(state, unitid, 0, kctl->id.name, sizeof(kctl->id.name)); | 1698 | len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name)); |
1616 | if (len) | 1699 | if (len) |
1617 | ; | 1700 | ; |
1618 | else if (nameid) | 1701 | else if (nameid) |
@@ -1656,17 +1739,17 @@ static int parse_audio_unit(struct mixer_build *state, int unitid) | |||
1656 | } | 1739 | } |
1657 | 1740 | ||
1658 | switch (p1[2]) { | 1741 | switch (p1[2]) { |
1659 | case INPUT_TERMINAL: | 1742 | case UAC_INPUT_TERMINAL: |
1660 | return 0; /* NOP */ | 1743 | return 0; /* NOP */ |
1661 | case MIXER_UNIT: | 1744 | case UAC_MIXER_UNIT: |
1662 | return parse_audio_mixer_unit(state, unitid, p1); | 1745 | return parse_audio_mixer_unit(state, unitid, p1); |
1663 | case SELECTOR_UNIT: | 1746 | case UAC_SELECTOR_UNIT: |
1664 | return parse_audio_selector_unit(state, unitid, p1); | 1747 | return parse_audio_selector_unit(state, unitid, p1); |
1665 | case FEATURE_UNIT: | 1748 | case UAC_FEATURE_UNIT: |
1666 | return parse_audio_feature_unit(state, unitid, p1); | 1749 | return parse_audio_feature_unit(state, unitid, p1); |
1667 | case PROCESSING_UNIT: | 1750 | case UAC_PROCESSING_UNIT_V1: |
1668 | return parse_audio_processing_unit(state, unitid, p1); | 1751 | return parse_audio_processing_unit(state, unitid, p1); |
1669 | case EXTENSION_UNIT: | 1752 | case UAC_EXTENSION_UNIT_V1: |
1670 | return parse_audio_extension_unit(state, unitid, p1); | 1753 | return parse_audio_extension_unit(state, unitid, p1); |
1671 | default: | 1754 | default: |
1672 | snd_printk(KERN_ERR "usbaudio: unit %u: unexpected type 0x%02x\n", unitid, p1[2]); | 1755 | snd_printk(KERN_ERR "usbaudio: unit %u: unexpected type 0x%02x\n", unitid, p1[2]); |
@@ -1696,11 +1779,11 @@ static int snd_usb_mixer_dev_free(struct snd_device *device) | |||
1696 | /* | 1779 | /* |
1697 | * create mixer controls | 1780 | * create mixer controls |
1698 | * | 1781 | * |
1699 | * walk through all OUTPUT_TERMINAL descriptors to search for mixers | 1782 | * walk through all UAC_OUTPUT_TERMINAL descriptors to search for mixers |
1700 | */ | 1783 | */ |
1701 | static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer) | 1784 | static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer) |
1702 | { | 1785 | { |
1703 | unsigned char *desc; | 1786 | struct uac_output_terminal_descriptor_v1 *desc; |
1704 | struct mixer_build state; | 1787 | struct mixer_build state; |
1705 | int err; | 1788 | int err; |
1706 | const struct usbmix_ctl_map *map; | 1789 | const struct usbmix_ctl_map *map; |
@@ -1724,14 +1807,14 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer) | |||
1724 | } | 1807 | } |
1725 | 1808 | ||
1726 | desc = NULL; | 1809 | desc = NULL; |
1727 | while ((desc = snd_usb_find_csint_desc(hostif->extra, hostif->extralen, desc, OUTPUT_TERMINAL)) != NULL) { | 1810 | while ((desc = snd_usb_find_csint_desc(hostif->extra, hostif->extralen, desc, UAC_OUTPUT_TERMINAL)) != NULL) { |
1728 | if (desc[0] < 9) | 1811 | if (desc->bLength < 9) |
1729 | continue; /* invalid descriptor? */ | 1812 | continue; /* invalid descriptor? */ |
1730 | set_bit(desc[3], state.unitbitmap); /* mark terminal ID as visited */ | 1813 | set_bit(desc->bTerminalID, state.unitbitmap); /* mark terminal ID as visited */ |
1731 | state.oterm.id = desc[3]; | 1814 | state.oterm.id = desc->bTerminalID; |
1732 | state.oterm.type = combine_word(&desc[4]); | 1815 | state.oterm.type = le16_to_cpu(desc->wTerminalType); |
1733 | state.oterm.name = desc[8]; | 1816 | state.oterm.name = desc->iTerminal; |
1734 | err = parse_audio_unit(&state, desc[7]); | 1817 | err = parse_audio_unit(&state, desc->bSourceID); |
1735 | if (err < 0) | 1818 | if (err < 0) |
1736 | return err; | 1819 | return err; |
1737 | } | 1820 | } |
@@ -1748,6 +1831,46 @@ static void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer, | |||
1748 | info->elem_id); | 1831 | info->elem_id); |
1749 | } | 1832 | } |
1750 | 1833 | ||
1834 | static void snd_usb_mixer_dump_cval(struct snd_info_buffer *buffer, | ||
1835 | int unitid, | ||
1836 | struct usb_mixer_elem_info *cval) | ||
1837 | { | ||
1838 | static char *val_types[] = {"BOOLEAN", "INV_BOOLEAN", | ||
1839 | "S8", "U8", "S16", "U16"}; | ||
1840 | snd_iprintf(buffer, " Unit: %i\n", unitid); | ||
1841 | if (cval->elem_id) | ||
1842 | snd_iprintf(buffer, " Control: name=\"%s\", index=%i\n", | ||
1843 | cval->elem_id->name, cval->elem_id->index); | ||
1844 | snd_iprintf(buffer, " Info: id=%i, control=%i, cmask=0x%x, " | ||
1845 | "channels=%i, type=\"%s\"\n", cval->id, | ||
1846 | cval->control, cval->cmask, cval->channels, | ||
1847 | val_types[cval->val_type]); | ||
1848 | snd_iprintf(buffer, " Volume: min=%i, max=%i, dBmin=%i, dBmax=%i\n", | ||
1849 | cval->min, cval->max, cval->dBmin, cval->dBmax); | ||
1850 | } | ||
1851 | |||
1852 | static void snd_usb_mixer_proc_read(struct snd_info_entry *entry, | ||
1853 | struct snd_info_buffer *buffer) | ||
1854 | { | ||
1855 | struct snd_usb_audio *chip = entry->private_data; | ||
1856 | struct usb_mixer_interface *mixer; | ||
1857 | struct usb_mixer_elem_info *cval; | ||
1858 | int unitid; | ||
1859 | |||
1860 | list_for_each_entry(mixer, &chip->mixer_list, list) { | ||
1861 | snd_iprintf(buffer, | ||
1862 | "USB Mixer: usb_id=0x%08x, ctrlif=%i, ctlerr=%i\n", | ||
1863 | chip->usb_id, mixer->ctrlif, | ||
1864 | mixer->ignore_ctl_error); | ||
1865 | snd_iprintf(buffer, "Card: %s\n", chip->card->longname); | ||
1866 | for (unitid = 0; unitid < MAX_ID_ELEMS; unitid++) { | ||
1867 | for (cval = mixer->id_elems[unitid]; cval; | ||
1868 | cval = cval->next_id_elem) | ||
1869 | snd_usb_mixer_dump_cval(buffer, unitid, cval); | ||
1870 | } | ||
1871 | } | ||
1872 | } | ||
1873 | |||
1751 | static void snd_usb_mixer_memory_change(struct usb_mixer_interface *mixer, | 1874 | static void snd_usb_mixer_memory_change(struct usb_mixer_interface *mixer, |
1752 | int unitid) | 1875 | int unitid) |
1753 | { | 1876 | { |
@@ -1924,7 +2047,7 @@ static int snd_usb_soundblaster_remote_init(struct usb_mixer_interface *mixer) | |||
1924 | } | 2047 | } |
1925 | mixer->rc_setup_packet->bRequestType = | 2048 | mixer->rc_setup_packet->bRequestType = |
1926 | USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE; | 2049 | USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE; |
1927 | mixer->rc_setup_packet->bRequest = GET_MEM; | 2050 | mixer->rc_setup_packet->bRequest = UAC_GET_MEM; |
1928 | mixer->rc_setup_packet->wValue = cpu_to_le16(0); | 2051 | mixer->rc_setup_packet->wValue = cpu_to_le16(0); |
1929 | mixer->rc_setup_packet->wIndex = cpu_to_le16(0); | 2052 | mixer->rc_setup_packet->wIndex = cpu_to_le16(0); |
1930 | mixer->rc_setup_packet->wLength = cpu_to_le16(len); | 2053 | mixer->rc_setup_packet->wLength = cpu_to_le16(len); |
@@ -2047,7 +2170,7 @@ static void snd_audigy2nx_proc_read(struct snd_info_entry *entry, | |||
2047 | snd_iprintf(buffer, "%s: ", jacks[i].name); | 2170 | snd_iprintf(buffer, "%s: ", jacks[i].name); |
2048 | err = snd_usb_ctl_msg(mixer->chip->dev, | 2171 | err = snd_usb_ctl_msg(mixer->chip->dev, |
2049 | usb_rcvctrlpipe(mixer->chip->dev, 0), | 2172 | usb_rcvctrlpipe(mixer->chip->dev, 0), |
2050 | GET_MEM, USB_DIR_IN | USB_TYPE_CLASS | | 2173 | UAC_GET_MEM, USB_DIR_IN | USB_TYPE_CLASS | |
2051 | USB_RECIP_INTERFACE, 0, | 2174 | USB_RECIP_INTERFACE, 0, |
2052 | jacks[i].unitid << 8, buf, 3, 100); | 2175 | jacks[i].unitid << 8, buf, 3, 100); |
2053 | if (err == 3 && (buf[0] == 3 || buf[0] == 6)) | 2176 | if (err == 3 && (buf[0] == 3 || buf[0] == 6)) |
@@ -2109,6 +2232,24 @@ static int snd_xonar_u1_controls_create(struct usb_mixer_interface *mixer) | |||
2109 | return 0; | 2232 | return 0; |
2110 | } | 2233 | } |
2111 | 2234 | ||
2235 | void snd_emuusb_set_samplerate(struct snd_usb_audio *chip, | ||
2236 | unsigned char samplerate_id) | ||
2237 | { | ||
2238 | struct usb_mixer_interface *mixer; | ||
2239 | struct usb_mixer_elem_info *cval; | ||
2240 | int unitid = 12; /* SamleRate ExtensionUnit ID */ | ||
2241 | |||
2242 | list_for_each_entry(mixer, &chip->mixer_list, list) { | ||
2243 | cval = mixer->id_elems[unitid]; | ||
2244 | if (cval) { | ||
2245 | set_cur_ctl_value(cval, cval->control << 8, | ||
2246 | samplerate_id); | ||
2247 | snd_usb_mixer_notify_id(mixer, unitid); | ||
2248 | } | ||
2249 | break; | ||
2250 | } | ||
2251 | } | ||
2252 | |||
2112 | int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, | 2253 | int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, |
2113 | int ignore_error) | 2254 | int ignore_error) |
2114 | { | 2255 | { |
@@ -2116,7 +2257,9 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, | |||
2116 | .dev_free = snd_usb_mixer_dev_free | 2257 | .dev_free = snd_usb_mixer_dev_free |
2117 | }; | 2258 | }; |
2118 | struct usb_mixer_interface *mixer; | 2259 | struct usb_mixer_interface *mixer; |
2119 | int err; | 2260 | struct snd_info_entry *entry; |
2261 | struct usb_host_interface *host_iface; | ||
2262 | int err, protocol; | ||
2120 | 2263 | ||
2121 | strcpy(chip->card->mixername, "USB Mixer"); | 2264 | strcpy(chip->card->mixername, "USB Mixer"); |
2122 | 2265 | ||
@@ -2126,12 +2269,23 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, | |||
2126 | mixer->chip = chip; | 2269 | mixer->chip = chip; |
2127 | mixer->ctrlif = ctrlif; | 2270 | mixer->ctrlif = ctrlif; |
2128 | mixer->ignore_ctl_error = ignore_error; | 2271 | mixer->ignore_ctl_error = ignore_error; |
2129 | mixer->id_elems = kcalloc(256, sizeof(*mixer->id_elems), GFP_KERNEL); | 2272 | mixer->id_elems = kcalloc(MAX_ID_ELEMS, sizeof(*mixer->id_elems), |
2273 | GFP_KERNEL); | ||
2130 | if (!mixer->id_elems) { | 2274 | if (!mixer->id_elems) { |
2131 | kfree(mixer); | 2275 | kfree(mixer); |
2132 | return -ENOMEM; | 2276 | return -ENOMEM; |
2133 | } | 2277 | } |
2134 | 2278 | ||
2279 | host_iface = &usb_ifnum_to_if(chip->dev, ctrlif)->altsetting[0]; | ||
2280 | protocol = host_iface->desc.bInterfaceProtocol; | ||
2281 | |||
2282 | /* FIXME! */ | ||
2283 | if (protocol != UAC_VERSION_1) { | ||
2284 | snd_printk(KERN_WARNING "mixer interface protocol 0x%02x not yet supported\n", | ||
2285 | protocol); | ||
2286 | return 0; | ||
2287 | } | ||
2288 | |||
2135 | if ((err = snd_usb_mixer_controls(mixer)) < 0 || | 2289 | if ((err = snd_usb_mixer_controls(mixer)) < 0 || |
2136 | (err = snd_usb_mixer_status_create(mixer)) < 0) | 2290 | (err = snd_usb_mixer_status_create(mixer)) < 0) |
2137 | goto _error; | 2291 | goto _error; |
@@ -2142,8 +2296,6 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, | |||
2142 | if (mixer->chip->usb_id == USB_ID(0x041e, 0x3020) || | 2296 | if (mixer->chip->usb_id == USB_ID(0x041e, 0x3020) || |
2143 | mixer->chip->usb_id == USB_ID(0x041e, 0x3040) || | 2297 | mixer->chip->usb_id == USB_ID(0x041e, 0x3040) || |
2144 | mixer->chip->usb_id == USB_ID(0x041e, 0x3048)) { | 2298 | mixer->chip->usb_id == USB_ID(0x041e, 0x3048)) { |
2145 | struct snd_info_entry *entry; | ||
2146 | |||
2147 | if ((err = snd_audigy2nx_controls_create(mixer)) < 0) | 2299 | if ((err = snd_audigy2nx_controls_create(mixer)) < 0) |
2148 | goto _error; | 2300 | goto _error; |
2149 | if (!snd_card_proc_new(chip->card, "audigy2nx", &entry)) | 2301 | if (!snd_card_proc_new(chip->card, "audigy2nx", &entry)) |
@@ -2161,6 +2313,11 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, | |||
2161 | err = snd_device_new(chip->card, SNDRV_DEV_LOWLEVEL, mixer, &dev_ops); | 2313 | err = snd_device_new(chip->card, SNDRV_DEV_LOWLEVEL, mixer, &dev_ops); |
2162 | if (err < 0) | 2314 | if (err < 0) |
2163 | goto _error; | 2315 | goto _error; |
2316 | |||
2317 | if (list_empty(&chip->mixer_list) && | ||
2318 | !snd_card_proc_new(chip->card, "usbmixer", &entry)) | ||
2319 | snd_info_set_text_ops(entry, chip, snd_usb_mixer_proc_read); | ||
2320 | |||
2164 | list_add(&mixer->list, &chip->mixer_list); | 2321 | list_add(&mixer->list, &chip->mixer_list); |
2165 | return 0; | 2322 | return 0; |
2166 | 2323 | ||
diff --git a/sound/usb/usbmixer_maps.c b/sound/usb/usbmixer_maps.c index 77c35885e21c..79e903a60862 100644 --- a/sound/usb/usbmixer_maps.c +++ b/sound/usb/usbmixer_maps.c | |||
@@ -19,11 +19,16 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | struct usbmix_dB_map { | ||
23 | u32 min; | ||
24 | u32 max; | ||
25 | }; | ||
22 | 26 | ||
23 | struct usbmix_name_map { | 27 | struct usbmix_name_map { |
24 | int id; | 28 | int id; |
25 | const char *name; | 29 | const char *name; |
26 | int control; | 30 | int control; |
31 | struct usbmix_dB_map *dB; | ||
27 | }; | 32 | }; |
28 | 33 | ||
29 | struct usbmix_selector_map { | 34 | struct usbmix_selector_map { |
@@ -72,7 +77,7 @@ static struct usbmix_name_map extigy_map[] = { | |||
72 | { 8, "Line Playback" }, /* FU */ | 77 | { 8, "Line Playback" }, /* FU */ |
73 | /* 9: IT mic */ | 78 | /* 9: IT mic */ |
74 | { 10, "Mic Playback" }, /* FU */ | 79 | { 10, "Mic Playback" }, /* FU */ |
75 | { 11, "Capture Input Source" }, /* SU */ | 80 | { 11, "Capture Source" }, /* SU */ |
76 | { 12, "Capture" }, /* FU */ | 81 | { 12, "Capture" }, /* FU */ |
77 | /* 13: OT pcm capture */ | 82 | /* 13: OT pcm capture */ |
78 | /* 14: MU (w/o controls) */ | 83 | /* 14: MU (w/o controls) */ |
@@ -102,6 +107,9 @@ static struct usbmix_name_map extigy_map[] = { | |||
102 | * e.g. no Master and fake PCM volume | 107 | * e.g. no Master and fake PCM volume |
103 | * Pavel Mihaylov <bin@bash.info> | 108 | * Pavel Mihaylov <bin@bash.info> |
104 | */ | 109 | */ |
110 | static struct usbmix_dB_map mp3plus_dB_1 = {-4781, 0}; /* just guess */ | ||
111 | static struct usbmix_dB_map mp3plus_dB_2 = {-1781, 618}; /* just guess */ | ||
112 | |||
105 | static struct usbmix_name_map mp3plus_map[] = { | 113 | static struct usbmix_name_map mp3plus_map[] = { |
106 | /* 1: IT pcm */ | 114 | /* 1: IT pcm */ |
107 | /* 2: IT mic */ | 115 | /* 2: IT mic */ |
@@ -110,16 +118,19 @@ static struct usbmix_name_map mp3plus_map[] = { | |||
110 | /* 5: OT digital out */ | 118 | /* 5: OT digital out */ |
111 | /* 6: OT speaker */ | 119 | /* 6: OT speaker */ |
112 | /* 7: OT pcm capture */ | 120 | /* 7: OT pcm capture */ |
113 | { 8, "Capture Input Source" }, /* FU, default PCM Capture Source */ | 121 | { 8, "Capture Source" }, /* FU, default PCM Capture Source */ |
114 | /* (Mic, Input 1 = Line input, Input 2 = Optical input) */ | 122 | /* (Mic, Input 1 = Line input, Input 2 = Optical input) */ |
115 | { 9, "Master Playback" }, /* FU, default Speaker 1 */ | 123 | { 9, "Master Playback" }, /* FU, default Speaker 1 */ |
116 | /* { 10, "Mic Capture", 1 }, */ /* FU, Mic Capture */ | 124 | /* { 10, "Mic Capture", 1 }, */ /* FU, Mic Capture */ |
117 | /* { 10, "Mic Capture", 2 }, */ /* FU, Mic Capture */ | 125 | { 10, /* "Mic Capture", */ NULL, 2, .dB = &mp3plus_dB_2 }, |
126 | /* FU, Mic Capture */ | ||
118 | { 10, "Mic Boost", 7 }, /* FU, default Auto Gain Input */ | 127 | { 10, "Mic Boost", 7 }, /* FU, default Auto Gain Input */ |
119 | { 11, "Line Capture" }, /* FU, default PCM Capture */ | 128 | { 11, "Line Capture", .dB = &mp3plus_dB_2 }, |
129 | /* FU, default PCM Capture */ | ||
120 | { 12, "Digital In Playback" }, /* FU, default PCM 1 */ | 130 | { 12, "Digital In Playback" }, /* FU, default PCM 1 */ |
121 | /* { 13, "Mic Playback" }, */ /* FU, default Mic Playback */ | 131 | { 13, /* "Mic Playback", */ .dB = &mp3plus_dB_1 }, |
122 | { 14, "Line Playback" }, /* FU, default Speaker */ | 132 | /* FU, default Mic Playback */ |
133 | { 14, "Line Playback", .dB = &mp3plus_dB_1 }, /* FU, default Speaker */ | ||
123 | /* 15: MU */ | 134 | /* 15: MU */ |
124 | { 0 } /* terminator */ | 135 | { 0 } /* terminator */ |
125 | }; | 136 | }; |
diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h index a892bda03df9..f06faf7917b9 100644 --- a/sound/usb/usbquirks.h +++ b/sound/usb/usbquirks.h | |||
@@ -91,7 +91,7 @@ | |||
91 | .idVendor = 0x046d, | 91 | .idVendor = 0x046d, |
92 | .idProduct = 0x0850, | 92 | .idProduct = 0x0850, |
93 | .bInterfaceClass = USB_CLASS_AUDIO, | 93 | .bInterfaceClass = USB_CLASS_AUDIO, |
94 | .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL | 94 | .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL |
95 | }, | 95 | }, |
96 | { | 96 | { |
97 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | | 97 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | |
@@ -100,7 +100,7 @@ | |||
100 | .idVendor = 0x046d, | 100 | .idVendor = 0x046d, |
101 | .idProduct = 0x08ae, | 101 | .idProduct = 0x08ae, |
102 | .bInterfaceClass = USB_CLASS_AUDIO, | 102 | .bInterfaceClass = USB_CLASS_AUDIO, |
103 | .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL | 103 | .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL |
104 | }, | 104 | }, |
105 | { | 105 | { |
106 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | | 106 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | |
@@ -109,7 +109,7 @@ | |||
109 | .idVendor = 0x046d, | 109 | .idVendor = 0x046d, |
110 | .idProduct = 0x08c6, | 110 | .idProduct = 0x08c6, |
111 | .bInterfaceClass = USB_CLASS_AUDIO, | 111 | .bInterfaceClass = USB_CLASS_AUDIO, |
112 | .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL | 112 | .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL |
113 | }, | 113 | }, |
114 | { | 114 | { |
115 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | | 115 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | |
@@ -118,7 +118,7 @@ | |||
118 | .idVendor = 0x046d, | 118 | .idVendor = 0x046d, |
119 | .idProduct = 0x08f0, | 119 | .idProduct = 0x08f0, |
120 | .bInterfaceClass = USB_CLASS_AUDIO, | 120 | .bInterfaceClass = USB_CLASS_AUDIO, |
121 | .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL | 121 | .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL |
122 | }, | 122 | }, |
123 | { | 123 | { |
124 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | | 124 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | |
@@ -127,7 +127,7 @@ | |||
127 | .idVendor = 0x046d, | 127 | .idVendor = 0x046d, |
128 | .idProduct = 0x08f5, | 128 | .idProduct = 0x08f5, |
129 | .bInterfaceClass = USB_CLASS_AUDIO, | 129 | .bInterfaceClass = USB_CLASS_AUDIO, |
130 | .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL | 130 | .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL |
131 | }, | 131 | }, |
132 | { | 132 | { |
133 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | | 133 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | |
@@ -136,7 +136,7 @@ | |||
136 | .idVendor = 0x046d, | 136 | .idVendor = 0x046d, |
137 | .idProduct = 0x08f6, | 137 | .idProduct = 0x08f6, |
138 | .bInterfaceClass = USB_CLASS_AUDIO, | 138 | .bInterfaceClass = USB_CLASS_AUDIO, |
139 | .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL | 139 | .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL |
140 | }, | 140 | }, |
141 | { | 141 | { |
142 | USB_DEVICE(0x046d, 0x0990), | 142 | USB_DEVICE(0x046d, 0x0990), |
@@ -301,7 +301,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
301 | .iface = 1, | 301 | .iface = 1, |
302 | .altsetting = 1, | 302 | .altsetting = 1, |
303 | .altset_idx = 1, | 303 | .altset_idx = 1, |
304 | .attributes = EP_CS_ATTR_FILL_MAX, | 304 | .attributes = UAC_EP_CS_ATTR_FILL_MAX, |
305 | .endpoint = 0x81, | 305 | .endpoint = 0x81, |
306 | .ep_attr = 0x05, | 306 | .ep_attr = 0x05, |
307 | .rates = SNDRV_PCM_RATE_CONTINUOUS, | 307 | .rates = SNDRV_PCM_RATE_CONTINUOUS, |
@@ -1266,37 +1266,6 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
1266 | } | 1266 | } |
1267 | } | 1267 | } |
1268 | }, | 1268 | }, |
1269 | /* Roland UA-101 in High-Speed Mode only */ | ||
1270 | { | ||
1271 | USB_DEVICE(0x0582, 0x007d), | ||
1272 | .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { | ||
1273 | .vendor_name = "Roland", | ||
1274 | .product_name = "UA-101", | ||
1275 | .ifnum = QUIRK_ANY_INTERFACE, | ||
1276 | .type = QUIRK_COMPOSITE, | ||
1277 | .data = (const struct snd_usb_audio_quirk[]) { | ||
1278 | { | ||
1279 | .ifnum = 0, | ||
1280 | .type = QUIRK_AUDIO_EDIROL_UA101 | ||
1281 | }, | ||
1282 | { | ||
1283 | .ifnum = 1, | ||
1284 | .type = QUIRK_AUDIO_EDIROL_UA101 | ||
1285 | }, | ||
1286 | { | ||
1287 | .ifnum = 2, | ||
1288 | .type = QUIRK_MIDI_FIXED_ENDPOINT, | ||
1289 | .data = & (const struct snd_usb_midi_endpoint_info) { | ||
1290 | .out_cables = 0x0001, | ||
1291 | .in_cables = 0x0001 | ||
1292 | } | ||
1293 | }, | ||
1294 | { | ||
1295 | .ifnum = -1 | ||
1296 | } | ||
1297 | } | ||
1298 | } | ||
1299 | }, | ||
1300 | { | 1269 | { |
1301 | /* has ID 0x0081 when not in "Advanced Driver" mode */ | 1270 | /* has ID 0x0081 when not in "Advanced Driver" mode */ |
1302 | USB_DEVICE(0x0582, 0x0080), | 1271 | USB_DEVICE(0x0582, 0x0080), |
@@ -2073,6 +2042,33 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
2073 | } | 2042 | } |
2074 | }, | 2043 | }, |
2075 | 2044 | ||
2045 | /* Access Music devices */ | ||
2046 | { | ||
2047 | /* VirusTI Desktop */ | ||
2048 | USB_DEVICE_VENDOR_SPEC(0x133e, 0x0815), | ||
2049 | .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { | ||
2050 | .ifnum = QUIRK_ANY_INTERFACE, | ||
2051 | .type = QUIRK_COMPOSITE, | ||
2052 | .data = &(const struct snd_usb_audio_quirk[]) { | ||
2053 | { | ||
2054 | .ifnum = 3, | ||
2055 | .type = QUIRK_MIDI_FIXED_ENDPOINT, | ||
2056 | .data = &(const struct snd_usb_midi_endpoint_info) { | ||
2057 | .out_cables = 0x0003, | ||
2058 | .in_cables = 0x0003 | ||
2059 | } | ||
2060 | }, | ||
2061 | { | ||
2062 | .ifnum = 4, | ||
2063 | .type = QUIRK_IGNORE_INTERFACE | ||
2064 | }, | ||
2065 | { | ||
2066 | .ifnum = -1 | ||
2067 | } | ||
2068 | } | ||
2069 | } | ||
2070 | }, | ||
2071 | |||
2076 | /* */ | 2072 | /* */ |
2077 | { | 2073 | { |
2078 | /* aka. Serato Scratch Live DJ Box */ | 2074 | /* aka. Serato Scratch Live DJ Box */ |
@@ -2105,6 +2101,165 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
2105 | } | 2101 | } |
2106 | }, | 2102 | }, |
2107 | 2103 | ||
2104 | /* Hauppauge HVR-950Q and HVR-850 */ | ||
2105 | { | ||
2106 | USB_DEVICE_VENDOR_SPEC(0x2040, 0x7200), | ||
2107 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | | ||
2108 | USB_DEVICE_ID_MATCH_INT_CLASS | | ||
2109 | USB_DEVICE_ID_MATCH_INT_SUBCLASS, | ||
2110 | .bInterfaceClass = USB_CLASS_AUDIO, | ||
2111 | .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL, | ||
2112 | .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { | ||
2113 | .vendor_name = "Hauppauge", | ||
2114 | .product_name = "HVR-950Q", | ||
2115 | .ifnum = QUIRK_ANY_INTERFACE, | ||
2116 | .type = QUIRK_AUDIO_ALIGN_TRANSFER, | ||
2117 | } | ||
2118 | }, | ||
2119 | { | ||
2120 | USB_DEVICE_VENDOR_SPEC(0x2040, 0x7201), | ||
2121 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | | ||
2122 | USB_DEVICE_ID_MATCH_INT_CLASS | | ||
2123 | USB_DEVICE_ID_MATCH_INT_SUBCLASS, | ||
2124 | .bInterfaceClass = USB_CLASS_AUDIO, | ||
2125 | .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL, | ||
2126 | .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { | ||
2127 | .vendor_name = "Hauppauge", | ||
2128 | .product_name = "HVR-950Q", | ||
2129 | .ifnum = QUIRK_ANY_INTERFACE, | ||
2130 | .type = QUIRK_AUDIO_ALIGN_TRANSFER, | ||
2131 | } | ||
2132 | }, | ||
2133 | { | ||
2134 | USB_DEVICE_VENDOR_SPEC(0x2040, 0x7202), | ||
2135 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | | ||
2136 | USB_DEVICE_ID_MATCH_INT_CLASS | | ||
2137 | USB_DEVICE_ID_MATCH_INT_SUBCLASS, | ||
2138 | .bInterfaceClass = USB_CLASS_AUDIO, | ||
2139 | .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL, | ||
2140 | .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { | ||
2141 | .vendor_name = "Hauppauge", | ||
2142 | .product_name = "HVR-950Q", | ||
2143 | .ifnum = QUIRK_ANY_INTERFACE, | ||
2144 | .type = QUIRK_AUDIO_ALIGN_TRANSFER, | ||
2145 | } | ||
2146 | }, | ||
2147 | { | ||
2148 | USB_DEVICE_VENDOR_SPEC(0x2040, 0x7203), | ||
2149 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | | ||
2150 | USB_DEVICE_ID_MATCH_INT_CLASS | | ||
2151 | USB_DEVICE_ID_MATCH_INT_SUBCLASS, | ||
2152 | .bInterfaceClass = USB_CLASS_AUDIO, | ||
2153 | .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL, | ||
2154 | .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { | ||
2155 | .vendor_name = "Hauppauge", | ||
2156 | .product_name = "HVR-950Q", | ||
2157 | .ifnum = QUIRK_ANY_INTERFACE, | ||
2158 | .type = QUIRK_AUDIO_ALIGN_TRANSFER, | ||
2159 | } | ||
2160 | }, | ||
2161 | { | ||
2162 | USB_DEVICE_VENDOR_SPEC(0x2040, 0x7204), | ||
2163 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | | ||
2164 | USB_DEVICE_ID_MATCH_INT_CLASS | | ||
2165 | USB_DEVICE_ID_MATCH_INT_SUBCLASS, | ||
2166 | .bInterfaceClass = USB_CLASS_AUDIO, | ||
2167 | .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL, | ||
2168 | .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { | ||
2169 | .vendor_name = "Hauppauge", | ||
2170 | .product_name = "HVR-950Q", | ||
2171 | .ifnum = QUIRK_ANY_INTERFACE, | ||
2172 | .type = QUIRK_AUDIO_ALIGN_TRANSFER, | ||
2173 | } | ||
2174 | }, | ||
2175 | { | ||
2176 | USB_DEVICE_VENDOR_SPEC(0x2040, 0x7205), | ||
2177 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | | ||
2178 | USB_DEVICE_ID_MATCH_INT_CLASS | | ||
2179 | USB_DEVICE_ID_MATCH_INT_SUBCLASS, | ||
2180 | .bInterfaceClass = USB_CLASS_AUDIO, | ||
2181 | .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL, | ||
2182 | .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { | ||
2183 | .vendor_name = "Hauppauge", | ||
2184 | .product_name = "HVR-950Q", | ||
2185 | .ifnum = QUIRK_ANY_INTERFACE, | ||
2186 | .type = QUIRK_AUDIO_ALIGN_TRANSFER, | ||
2187 | } | ||
2188 | }, | ||
2189 | { | ||
2190 | USB_DEVICE_VENDOR_SPEC(0x2040, 0x7250), | ||
2191 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | | ||
2192 | USB_DEVICE_ID_MATCH_INT_CLASS | | ||
2193 | USB_DEVICE_ID_MATCH_INT_SUBCLASS, | ||
2194 | .bInterfaceClass = USB_CLASS_AUDIO, | ||
2195 | .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL, | ||
2196 | .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { | ||
2197 | .vendor_name = "Hauppauge", | ||
2198 | .product_name = "HVR-950Q", | ||
2199 | .ifnum = QUIRK_ANY_INTERFACE, | ||
2200 | .type = QUIRK_AUDIO_ALIGN_TRANSFER, | ||
2201 | } | ||
2202 | }, | ||
2203 | { | ||
2204 | USB_DEVICE_VENDOR_SPEC(0x2040, 0x7230), | ||
2205 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | | ||
2206 | USB_DEVICE_ID_MATCH_INT_CLASS | | ||
2207 | USB_DEVICE_ID_MATCH_INT_SUBCLASS, | ||
2208 | .bInterfaceClass = USB_CLASS_AUDIO, | ||
2209 | .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL, | ||
2210 | .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { | ||
2211 | .vendor_name = "Hauppauge", | ||
2212 | .product_name = "HVR-850", | ||
2213 | .ifnum = QUIRK_ANY_INTERFACE, | ||
2214 | .type = QUIRK_AUDIO_ALIGN_TRANSFER, | ||
2215 | } | ||
2216 | }, | ||
2217 | |||
2218 | /* Digidesign Mbox */ | ||
2219 | { | ||
2220 | /* Thanks to Clemens Ladisch <clemens@ladisch.de> */ | ||
2221 | USB_DEVICE(0x0dba, 0x1000), | ||
2222 | .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { | ||
2223 | .vendor_name = "Digidesign", | ||
2224 | .product_name = "MBox", | ||
2225 | .ifnum = QUIRK_ANY_INTERFACE, | ||
2226 | .type = QUIRK_COMPOSITE, | ||
2227 | .data = (const struct snd_usb_audio_quirk[]){ | ||
2228 | { | ||
2229 | .ifnum = 0, | ||
2230 | .type = QUIRK_IGNORE_INTERFACE, | ||
2231 | }, | ||
2232 | { | ||
2233 | .ifnum = 1, | ||
2234 | .type = QUIRK_AUDIO_FIXED_ENDPOINT, | ||
2235 | .data = &(const struct audioformat) { | ||
2236 | .format = SNDRV_PCM_FORMAT_S24_3BE, | ||
2237 | .channels = 2, | ||
2238 | .iface = 1, | ||
2239 | .altsetting = 1, | ||
2240 | .altset_idx = 1, | ||
2241 | .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE, | ||
2242 | .endpoint = 0x02, | ||
2243 | .ep_attr = 0x01, | ||
2244 | .maxpacksize = 0x130, | ||
2245 | .rates = SNDRV_PCM_RATE_44100 | | ||
2246 | SNDRV_PCM_RATE_48000, | ||
2247 | .rate_min = 44100, | ||
2248 | .rate_max = 48000, | ||
2249 | .nr_rates = 2, | ||
2250 | .rate_table = (unsigned int[]) { | ||
2251 | 44100, 48000 | ||
2252 | } | ||
2253 | } | ||
2254 | }, | ||
2255 | { | ||
2256 | .ifnum = -1 | ||
2257 | } | ||
2258 | } | ||
2259 | |||
2260 | } | ||
2261 | }, | ||
2262 | |||
2108 | { | 2263 | { |
2109 | /* | 2264 | /* |
2110 | * Some USB MIDI devices don't have an audio control interface, | 2265 | * Some USB MIDI devices don't have an audio control interface, |
@@ -2113,7 +2268,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
2113 | .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS | | 2268 | .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS | |
2114 | USB_DEVICE_ID_MATCH_INT_SUBCLASS, | 2269 | USB_DEVICE_ID_MATCH_INT_SUBCLASS, |
2115 | .bInterfaceClass = USB_CLASS_AUDIO, | 2270 | .bInterfaceClass = USB_CLASS_AUDIO, |
2116 | .bInterfaceSubClass = USB_SUBCLASS_MIDI_STREAMING, | 2271 | .bInterfaceSubClass = USB_SUBCLASS_MIDISTREAMING, |
2117 | .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { | 2272 | .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { |
2118 | .ifnum = QUIRK_ANY_INTERFACE, | 2273 | .ifnum = QUIRK_ANY_INTERFACE, |
2119 | .type = QUIRK_MIDI_STANDARD_INTERFACE | 2274 | .type = QUIRK_MIDI_STANDARD_INTERFACE |
diff --git a/sound/usb/usx2y/us122l.c b/sound/usb/usx2y/us122l.c index 91bb29666d26..44deb21b1777 100644 --- a/sound/usb/usx2y/us122l.c +++ b/sound/usb/usx2y/us122l.c | |||
@@ -16,6 +16,8 @@ | |||
16 | * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 16 | * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
17 | */ | 17 | */ |
18 | 18 | ||
19 | #include <linux/usb.h> | ||
20 | #include <linux/usb/audio.h> | ||
19 | #include <sound/core.h> | 21 | #include <sound/core.h> |
20 | #include <sound/hwdep.h> | 22 | #include <sound/hwdep.h> |
21 | #include <sound/pcm.h> | 23 | #include <sound/pcm.h> |
@@ -315,9 +317,9 @@ static int us122l_set_sample_rate(struct usb_device *dev, int rate) | |||
315 | data[0] = rate; | 317 | data[0] = rate; |
316 | data[1] = rate >> 8; | 318 | data[1] = rate >> 8; |
317 | data[2] = rate >> 16; | 319 | data[2] = rate >> 16; |
318 | err = us122l_ctl_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, | 320 | err = us122l_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, |
319 | USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, | 321 | USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, |
320 | SAMPLING_FREQ_CONTROL << 8, ep, data, 3, 1000); | 322 | UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, data, 3, 1000); |
321 | if (err < 0) | 323 | if (err < 0) |
322 | snd_printk(KERN_ERR "%d: cannot set freq %d to ep 0x%x\n", | 324 | snd_printk(KERN_ERR "%d: cannot set freq %d to ep 0x%x\n", |
323 | dev->devnum, rate, ep); | 325 | dev->devnum, rate, ep); |