diff options
Diffstat (limited to 'sound')
239 files changed, 13160 insertions, 2335 deletions
diff --git a/sound/aoa/soundbus/core.c b/sound/aoa/soundbus/core.c index 99ca7120e269..7487eb76e034 100644 --- a/sound/aoa/soundbus/core.c +++ b/sound/aoa/soundbus/core.c | |||
@@ -59,7 +59,7 @@ static int soundbus_probe(struct device *dev) | |||
59 | static int soundbus_uevent(struct device *dev, struct kobj_uevent_env *env) | 59 | static int soundbus_uevent(struct device *dev, struct kobj_uevent_env *env) |
60 | { | 60 | { |
61 | struct soundbus_dev * soundbus_dev; | 61 | struct soundbus_dev * soundbus_dev; |
62 | struct of_device * of; | 62 | struct platform_device * of; |
63 | const char *compat; | 63 | const char *compat; |
64 | int retval = 0; | 64 | int retval = 0; |
65 | int cplen, seen = 0; | 65 | int cplen, seen = 0; |
diff --git a/sound/aoa/soundbus/soundbus.h b/sound/aoa/soundbus/soundbus.h index a0f223c13f66..adecbf36f4f6 100644 --- a/sound/aoa/soundbus/soundbus.h +++ b/sound/aoa/soundbus/soundbus.h | |||
@@ -141,7 +141,7 @@ struct soundbus_dev { | |||
141 | struct list_head onbuslist; | 141 | struct list_head onbuslist; |
142 | 142 | ||
143 | /* the of device it represents */ | 143 | /* the of device it represents */ |
144 | struct of_device ofdev; | 144 | struct platform_device ofdev; |
145 | 145 | ||
146 | /* what modules go by */ | 146 | /* what modules go by */ |
147 | char modalias[32]; | 147 | char modalias[32]; |
diff --git a/sound/aoa/soundbus/sysfs.c b/sound/aoa/soundbus/sysfs.c index 6496e754f00a..e0980b5c2cd8 100644 --- a/sound/aoa/soundbus/sysfs.c +++ b/sound/aoa/soundbus/sysfs.c | |||
@@ -16,7 +16,7 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, | |||
16 | char *buf) | 16 | char *buf) |
17 | { | 17 | { |
18 | struct soundbus_dev *sdev = to_soundbus_device(dev); | 18 | struct soundbus_dev *sdev = to_soundbus_device(dev); |
19 | struct of_device *of = &sdev->ofdev; | 19 | struct platform_device *of = &sdev->ofdev; |
20 | int length; | 20 | int length; |
21 | 21 | ||
22 | if (*sdev->modalias) { | 22 | if (*sdev->modalias) { |
diff --git a/sound/core/init.c b/sound/core/init.c index ec4a50ce5656..2de45fbd70fb 100644 --- a/sound/core/init.c +++ b/sound/core/init.c | |||
@@ -607,11 +607,16 @@ card_id_store_attr(struct device *dev, struct device_attribute *attr, | |||
607 | return -EEXIST; | 607 | return -EEXIST; |
608 | } | 608 | } |
609 | for (idx = 0; idx < snd_ecards_limit; idx++) { | 609 | for (idx = 0; idx < snd_ecards_limit; idx++) { |
610 | if (snd_cards[idx] && !strcmp(snd_cards[idx]->id, buf1)) | 610 | if (snd_cards[idx] && !strcmp(snd_cards[idx]->id, buf1)) { |
611 | goto __exist; | 611 | if (card == snd_cards[idx]) |
612 | goto __ok; | ||
613 | else | ||
614 | goto __exist; | ||
615 | } | ||
612 | } | 616 | } |
613 | strcpy(card->id, buf1); | 617 | strcpy(card->id, buf1); |
614 | snd_info_card_id_change(card); | 618 | snd_info_card_id_change(card); |
619 | __ok: | ||
615 | mutex_unlock(&snd_card_mutex); | 620 | mutex_unlock(&snd_card_mutex); |
616 | 621 | ||
617 | return count; | 622 | return count; |
diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c index f50ebf20df96..86afb13cd240 100644 --- a/sound/core/oss/mixer_oss.c +++ b/sound/core/oss/mixer_oss.c | |||
@@ -77,7 +77,7 @@ static int snd_mixer_oss_release(struct inode *inode, struct file *file) | |||
77 | struct snd_mixer_oss_file *fmixer; | 77 | struct snd_mixer_oss_file *fmixer; |
78 | 78 | ||
79 | if (file->private_data) { | 79 | if (file->private_data) { |
80 | fmixer = (struct snd_mixer_oss_file *) file->private_data; | 80 | fmixer = file->private_data; |
81 | module_put(fmixer->card->module); | 81 | module_put(fmixer->card->module); |
82 | snd_card_file_remove(fmixer->card, file); | 82 | snd_card_file_remove(fmixer->card, file); |
83 | kfree(fmixer); | 83 | kfree(fmixer); |
@@ -368,7 +368,7 @@ static int snd_mixer_oss_ioctl1(struct snd_mixer_oss_file *fmixer, unsigned int | |||
368 | 368 | ||
369 | static long snd_mixer_oss_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | 369 | static long snd_mixer_oss_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
370 | { | 370 | { |
371 | return snd_mixer_oss_ioctl1((struct snd_mixer_oss_file *) file->private_data, cmd, arg); | 371 | return snd_mixer_oss_ioctl1(file->private_data, cmd, arg); |
372 | } | 372 | } |
373 | 373 | ||
374 | int snd_mixer_oss_ioctl_card(struct snd_card *card, unsigned int cmd, unsigned long arg) | 374 | int snd_mixer_oss_ioctl_card(struct snd_card *card, unsigned int cmd, unsigned long arg) |
@@ -582,7 +582,7 @@ static int snd_mixer_oss_get_volume1(struct snd_mixer_oss_file *fmixer, | |||
582 | struct snd_mixer_oss_slot *pslot, | 582 | struct snd_mixer_oss_slot *pslot, |
583 | int *left, int *right) | 583 | int *left, int *right) |
584 | { | 584 | { |
585 | struct slot *slot = (struct slot *)pslot->private_data; | 585 | struct slot *slot = pslot->private_data; |
586 | 586 | ||
587 | *left = *right = 100; | 587 | *left = *right = 100; |
588 | if (slot->present & SNDRV_MIXER_OSS_PRESENT_PVOLUME) { | 588 | if (slot->present & SNDRV_MIXER_OSS_PRESENT_PVOLUME) { |
@@ -691,7 +691,7 @@ static int snd_mixer_oss_put_volume1(struct snd_mixer_oss_file *fmixer, | |||
691 | struct snd_mixer_oss_slot *pslot, | 691 | struct snd_mixer_oss_slot *pslot, |
692 | int left, int right) | 692 | int left, int right) |
693 | { | 693 | { |
694 | struct slot *slot = (struct slot *)pslot->private_data; | 694 | struct slot *slot = pslot->private_data; |
695 | 695 | ||
696 | if (slot->present & SNDRV_MIXER_OSS_PRESENT_PVOLUME) { | 696 | if (slot->present & SNDRV_MIXER_OSS_PRESENT_PVOLUME) { |
697 | snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PVOLUME], left, right); | 697 | snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PVOLUME], left, right); |
@@ -740,7 +740,7 @@ static int snd_mixer_oss_get_recsrc1_sw(struct snd_mixer_oss_file *fmixer, | |||
740 | struct snd_mixer_oss_slot *pslot, | 740 | struct snd_mixer_oss_slot *pslot, |
741 | int *active) | 741 | int *active) |
742 | { | 742 | { |
743 | struct slot *slot = (struct slot *)pslot->private_data; | 743 | struct slot *slot = pslot->private_data; |
744 | int left, right; | 744 | int left, right; |
745 | 745 | ||
746 | left = right = 1; | 746 | left = right = 1; |
@@ -753,7 +753,7 @@ static int snd_mixer_oss_get_recsrc1_route(struct snd_mixer_oss_file *fmixer, | |||
753 | struct snd_mixer_oss_slot *pslot, | 753 | struct snd_mixer_oss_slot *pslot, |
754 | int *active) | 754 | int *active) |
755 | { | 755 | { |
756 | struct slot *slot = (struct slot *)pslot->private_data; | 756 | struct slot *slot = pslot->private_data; |
757 | int left, right; | 757 | int left, right; |
758 | 758 | ||
759 | left = right = 1; | 759 | left = right = 1; |
@@ -766,7 +766,7 @@ static int snd_mixer_oss_put_recsrc1_sw(struct snd_mixer_oss_file *fmixer, | |||
766 | struct snd_mixer_oss_slot *pslot, | 766 | struct snd_mixer_oss_slot *pslot, |
767 | int active) | 767 | int active) |
768 | { | 768 | { |
769 | struct slot *slot = (struct slot *)pslot->private_data; | 769 | struct slot *slot = pslot->private_data; |
770 | 770 | ||
771 | snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CSWITCH], active, active, 0); | 771 | snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CSWITCH], active, active, 0); |
772 | return 0; | 772 | return 0; |
@@ -776,7 +776,7 @@ static int snd_mixer_oss_put_recsrc1_route(struct snd_mixer_oss_file *fmixer, | |||
776 | struct snd_mixer_oss_slot *pslot, | 776 | struct snd_mixer_oss_slot *pslot, |
777 | int active) | 777 | int active) |
778 | { | 778 | { |
779 | struct slot *slot = (struct slot *)pslot->private_data; | 779 | struct slot *slot = pslot->private_data; |
780 | 780 | ||
781 | snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CROUTE], active, active, 1); | 781 | snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CROUTE], active, active, 1); |
782 | return 0; | 782 | return 0; |
@@ -813,7 +813,7 @@ static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned | |||
813 | if (!(mixer->mask_recsrc & (1 << idx))) | 813 | if (!(mixer->mask_recsrc & (1 << idx))) |
814 | continue; | 814 | continue; |
815 | pslot = &mixer->slots[idx]; | 815 | pslot = &mixer->slots[idx]; |
816 | slot = (struct slot *)pslot->private_data; | 816 | slot = pslot->private_data; |
817 | if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE) | 817 | if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE) |
818 | continue; | 818 | continue; |
819 | if (!(slot->present & SNDRV_MIXER_OSS_PRESENT_CAPTURE)) | 819 | if (!(slot->present & SNDRV_MIXER_OSS_PRESENT_CAPTURE)) |
@@ -861,7 +861,7 @@ static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned | |||
861 | if (!(mixer->mask_recsrc & (1 << idx))) | 861 | if (!(mixer->mask_recsrc & (1 << idx))) |
862 | continue; | 862 | continue; |
863 | pslot = &mixer->slots[idx]; | 863 | pslot = &mixer->slots[idx]; |
864 | slot = (struct slot *)pslot->private_data; | 864 | slot = pslot->private_data; |
865 | if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE) | 865 | if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE) |
866 | continue; | 866 | continue; |
867 | if (!(slot->present & SNDRV_MIXER_OSS_PRESENT_CAPTURE)) | 867 | if (!(slot->present & SNDRV_MIXER_OSS_PRESENT_CAPTURE)) |
@@ -925,7 +925,7 @@ static int snd_mixer_oss_build_test(struct snd_mixer_oss *mixer, struct slot *sl | |||
925 | 925 | ||
926 | static void snd_mixer_oss_slot_free(struct snd_mixer_oss_slot *chn) | 926 | static void snd_mixer_oss_slot_free(struct snd_mixer_oss_slot *chn) |
927 | { | 927 | { |
928 | struct slot *p = (struct slot *)chn->private_data; | 928 | struct slot *p = chn->private_data; |
929 | if (p) { | 929 | if (p) { |
930 | if (p->allocated && p->assigned) { | 930 | if (p->allocated && p->assigned) { |
931 | kfree(p->assigned->name); | 931 | kfree(p->assigned->name); |
diff --git a/sound/core/pcm.c b/sound/core/pcm.c index cbe815dfbdc8..88525a958291 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c | |||
@@ -203,10 +203,16 @@ static char *snd_pcm_format_names[] = { | |||
203 | FORMAT(S18_3BE), | 203 | FORMAT(S18_3BE), |
204 | FORMAT(U18_3LE), | 204 | FORMAT(U18_3LE), |
205 | FORMAT(U18_3BE), | 205 | FORMAT(U18_3BE), |
206 | FORMAT(G723_24), | ||
207 | FORMAT(G723_24_1B), | ||
208 | FORMAT(G723_40), | ||
209 | FORMAT(G723_40_1B), | ||
206 | }; | 210 | }; |
207 | 211 | ||
208 | const char *snd_pcm_format_name(snd_pcm_format_t format) | 212 | const char *snd_pcm_format_name(snd_pcm_format_t format) |
209 | { | 213 | { |
214 | if (format >= ARRAY_SIZE(snd_pcm_format_names)) | ||
215 | return "Unknown"; | ||
210 | return snd_pcm_format_names[format]; | 216 | return snd_pcm_format_names[format]; |
211 | } | 217 | } |
212 | EXPORT_SYMBOL_GPL(snd_pcm_format_name); | 218 | EXPORT_SYMBOL_GPL(snd_pcm_format_name); |
@@ -358,8 +364,7 @@ static void snd_pcm_stream_proc_info_read(struct snd_info_entry *entry, | |||
358 | static void snd_pcm_substream_proc_info_read(struct snd_info_entry *entry, | 364 | static void snd_pcm_substream_proc_info_read(struct snd_info_entry *entry, |
359 | struct snd_info_buffer *buffer) | 365 | struct snd_info_buffer *buffer) |
360 | { | 366 | { |
361 | snd_pcm_proc_info_read((struct snd_pcm_substream *)entry->private_data, | 367 | snd_pcm_proc_info_read(entry->private_data, buffer); |
362 | buffer); | ||
363 | } | 368 | } |
364 | 369 | ||
365 | static void snd_pcm_substream_proc_hw_params_read(struct snd_info_entry *entry, | 370 | static void snd_pcm_substream_proc_hw_params_read(struct snd_info_entry *entry, |
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index d6ecca27bb68..a1707cca9c66 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c | |||
@@ -67,6 +67,8 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram | |||
67 | } else { | 67 | } else { |
68 | if (new_hw_ptr == ULONG_MAX) { /* initialization */ | 68 | if (new_hw_ptr == ULONG_MAX) { /* initialization */ |
69 | snd_pcm_sframes_t avail = snd_pcm_playback_hw_avail(runtime); | 69 | snd_pcm_sframes_t avail = snd_pcm_playback_hw_avail(runtime); |
70 | if (avail > runtime->buffer_size) | ||
71 | avail = runtime->buffer_size; | ||
70 | runtime->silence_filled = avail > 0 ? avail : 0; | 72 | runtime->silence_filled = avail > 0 ? avail : 0; |
71 | runtime->silence_start = (runtime->status->hw_ptr + | 73 | runtime->silence_start = (runtime->status->hw_ptr + |
72 | runtime->silence_filled) % | 74 | runtime->silence_filled) % |
@@ -287,8 +289,11 @@ int snd_pcm_update_state(struct snd_pcm_substream *substream, | |||
287 | return -EPIPE; | 289 | return -EPIPE; |
288 | } | 290 | } |
289 | } | 291 | } |
290 | if (avail >= runtime->control->avail_min) | 292 | if (runtime->twake) { |
291 | wake_up(runtime->twake ? &runtime->tsleep : &runtime->sleep); | 293 | if (avail >= runtime->twake) |
294 | wake_up(&runtime->tsleep); | ||
295 | } else if (avail >= runtime->control->avail_min) | ||
296 | wake_up(&runtime->sleep); | ||
292 | return 0; | 297 | return 0; |
293 | } | 298 | } |
294 | 299 | ||
@@ -1711,7 +1716,7 @@ EXPORT_SYMBOL(snd_pcm_period_elapsed); | |||
1711 | * The available space is stored on availp. When err = 0 and avail = 0 | 1716 | * The available space is stored on availp. When err = 0 and avail = 0 |
1712 | * on the capture stream, it indicates the stream is in DRAINING state. | 1717 | * on the capture stream, it indicates the stream is in DRAINING state. |
1713 | */ | 1718 | */ |
1714 | static int wait_for_avail_min(struct snd_pcm_substream *substream, | 1719 | static int wait_for_avail(struct snd_pcm_substream *substream, |
1715 | snd_pcm_uframes_t *availp) | 1720 | snd_pcm_uframes_t *availp) |
1716 | { | 1721 | { |
1717 | struct snd_pcm_runtime *runtime = substream->runtime; | 1722 | struct snd_pcm_runtime *runtime = substream->runtime; |
@@ -1761,7 +1766,7 @@ static int wait_for_avail_min(struct snd_pcm_substream *substream, | |||
1761 | avail = snd_pcm_playback_avail(runtime); | 1766 | avail = snd_pcm_playback_avail(runtime); |
1762 | else | 1767 | else |
1763 | avail = snd_pcm_capture_avail(runtime); | 1768 | avail = snd_pcm_capture_avail(runtime); |
1764 | if (avail >= runtime->control->avail_min) | 1769 | if (avail >= runtime->twake) |
1765 | break; | 1770 | break; |
1766 | } | 1771 | } |
1767 | _endloop: | 1772 | _endloop: |
@@ -1824,7 +1829,7 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream, | |||
1824 | goto _end_unlock; | 1829 | goto _end_unlock; |
1825 | } | 1830 | } |
1826 | 1831 | ||
1827 | runtime->twake = 1; | 1832 | runtime->twake = runtime->control->avail_min ? : 1; |
1828 | while (size > 0) { | 1833 | while (size > 0) { |
1829 | snd_pcm_uframes_t frames, appl_ptr, appl_ofs; | 1834 | snd_pcm_uframes_t frames, appl_ptr, appl_ofs; |
1830 | snd_pcm_uframes_t avail; | 1835 | snd_pcm_uframes_t avail; |
@@ -1837,7 +1842,9 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream, | |||
1837 | err = -EAGAIN; | 1842 | err = -EAGAIN; |
1838 | goto _end_unlock; | 1843 | goto _end_unlock; |
1839 | } | 1844 | } |
1840 | err = wait_for_avail_min(substream, &avail); | 1845 | runtime->twake = min_t(snd_pcm_uframes_t, size, |
1846 | runtime->control->avail_min ? : 1); | ||
1847 | err = wait_for_avail(substream, &avail); | ||
1841 | if (err < 0) | 1848 | if (err < 0) |
1842 | goto _end_unlock; | 1849 | goto _end_unlock; |
1843 | } | 1850 | } |
@@ -2046,7 +2053,7 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream, | |||
2046 | goto _end_unlock; | 2053 | goto _end_unlock; |
2047 | } | 2054 | } |
2048 | 2055 | ||
2049 | runtime->twake = 1; | 2056 | runtime->twake = runtime->control->avail_min ? : 1; |
2050 | while (size > 0) { | 2057 | while (size > 0) { |
2051 | snd_pcm_uframes_t frames, appl_ptr, appl_ofs; | 2058 | snd_pcm_uframes_t frames, appl_ptr, appl_ofs; |
2052 | snd_pcm_uframes_t avail; | 2059 | snd_pcm_uframes_t avail; |
@@ -2064,7 +2071,9 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream, | |||
2064 | err = -EAGAIN; | 2071 | err = -EAGAIN; |
2065 | goto _end_unlock; | 2072 | goto _end_unlock; |
2066 | } | 2073 | } |
2067 | err = wait_for_avail_min(substream, &avail); | 2074 | runtime->twake = min_t(snd_pcm_uframes_t, size, |
2075 | runtime->control->avail_min ? : 1); | ||
2076 | err = wait_for_avail(substream, &avail); | ||
2068 | if (err < 0) | 2077 | if (err < 0) |
2069 | goto _end_unlock; | 2078 | goto _end_unlock; |
2070 | if (!avail) | 2079 | if (!avail) |
diff --git a/sound/core/pcm_misc.c b/sound/core/pcm_misc.c index ea2bf82c9373..434af3c56d52 100644 --- a/sound/core/pcm_misc.c +++ b/sound/core/pcm_misc.c | |||
@@ -128,6 +128,14 @@ static struct pcm_format_data pcm_formats[SNDRV_PCM_FORMAT_LAST+1] = { | |||
128 | .width = 4, .phys = 4, .le = -1, .signd = -1, | 128 | .width = 4, .phys = 4, .le = -1, .signd = -1, |
129 | .silence = {}, | 129 | .silence = {}, |
130 | }, | 130 | }, |
131 | [SNDRV_PCM_FORMAT_G723_24] = { | ||
132 | .width = 3, .phys = 3, .le = -1, .signd = -1, | ||
133 | .silence = {}, | ||
134 | }, | ||
135 | [SNDRV_PCM_FORMAT_G723_40] = { | ||
136 | .width = 5, .phys = 5, .le = -1, .signd = -1, | ||
137 | .silence = {}, | ||
138 | }, | ||
131 | /* FIXME: the following three formats are not defined properly yet */ | 139 | /* FIXME: the following three formats are not defined properly yet */ |
132 | [SNDRV_PCM_FORMAT_MPEG] = { | 140 | [SNDRV_PCM_FORMAT_MPEG] = { |
133 | .le = -1, .signd = -1, | 141 | .le = -1, .signd = -1, |
@@ -186,6 +194,14 @@ static struct pcm_format_data pcm_formats[SNDRV_PCM_FORMAT_LAST+1] = { | |||
186 | .width = 18, .phys = 24, .le = 0, .signd = 0, | 194 | .width = 18, .phys = 24, .le = 0, .signd = 0, |
187 | .silence = { 0x02, 0x00, 0x00 }, | 195 | .silence = { 0x02, 0x00, 0x00 }, |
188 | }, | 196 | }, |
197 | [SNDRV_PCM_FORMAT_G723_24_1B] = { | ||
198 | .width = 3, .phys = 8, .le = -1, .signd = -1, | ||
199 | .silence = {}, | ||
200 | }, | ||
201 | [SNDRV_PCM_FORMAT_G723_40_1B] = { | ||
202 | .width = 5, .phys = 8, .le = -1, .signd = -1, | ||
203 | .silence = {}, | ||
204 | }, | ||
189 | }; | 205 | }; |
190 | 206 | ||
191 | 207 | ||
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 2d2e1b65ee9a..eb4094270a4f 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c | |||
@@ -142,7 +142,7 @@ int snd_pcm_info_user(struct snd_pcm_substream *substream, | |||
142 | 142 | ||
143 | #ifdef RULES_DEBUG | 143 | #ifdef RULES_DEBUG |
144 | #define HW_PARAM(v) [SNDRV_PCM_HW_PARAM_##v] = #v | 144 | #define HW_PARAM(v) [SNDRV_PCM_HW_PARAM_##v] = #v |
145 | char *snd_pcm_hw_param_names[] = { | 145 | static const char * const snd_pcm_hw_param_names[] = { |
146 | HW_PARAM(ACCESS), | 146 | HW_PARAM(ACCESS), |
147 | HW_PARAM(FORMAT), | 147 | HW_PARAM(FORMAT), |
148 | HW_PARAM(SUBFORMAT), | 148 | HW_PARAM(SUBFORMAT), |
@@ -451,13 +451,11 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream, | |||
451 | snd_pcm_timer_resolution_change(substream); | 451 | snd_pcm_timer_resolution_change(substream); |
452 | runtime->status->state = SNDRV_PCM_STATE_SETUP; | 452 | runtime->status->state = SNDRV_PCM_STATE_SETUP; |
453 | 453 | ||
454 | if (substream->latency_pm_qos_req) { | 454 | if (pm_qos_request_active(&substream->latency_pm_qos_req)) |
455 | pm_qos_remove_request(substream->latency_pm_qos_req); | 455 | pm_qos_remove_request(&substream->latency_pm_qos_req); |
456 | substream->latency_pm_qos_req = NULL; | ||
457 | } | ||
458 | if ((usecs = period_to_usecs(runtime)) >= 0) | 456 | if ((usecs = period_to_usecs(runtime)) >= 0) |
459 | substream->latency_pm_qos_req = pm_qos_add_request( | 457 | pm_qos_add_request(&substream->latency_pm_qos_req, |
460 | PM_QOS_CPU_DMA_LATENCY, usecs); | 458 | PM_QOS_CPU_DMA_LATENCY, usecs); |
461 | return 0; | 459 | return 0; |
462 | _error: | 460 | _error: |
463 | /* hardware might be unuseable from this time, | 461 | /* hardware might be unuseable from this time, |
@@ -512,8 +510,7 @@ static int snd_pcm_hw_free(struct snd_pcm_substream *substream) | |||
512 | if (substream->ops->hw_free) | 510 | if (substream->ops->hw_free) |
513 | result = substream->ops->hw_free(substream); | 511 | result = substream->ops->hw_free(substream); |
514 | runtime->status->state = SNDRV_PCM_STATE_OPEN; | 512 | runtime->status->state = SNDRV_PCM_STATE_OPEN; |
515 | pm_qos_remove_request(substream->latency_pm_qos_req); | 513 | pm_qos_remove_request(&substream->latency_pm_qos_req); |
516 | substream->latency_pm_qos_req = NULL; | ||
517 | return result; | 514 | return result; |
518 | } | 515 | } |
519 | 516 | ||
@@ -983,6 +980,10 @@ static int snd_pcm_do_pause(struct snd_pcm_substream *substream, int push) | |||
983 | { | 980 | { |
984 | if (substream->runtime->trigger_master != substream) | 981 | if (substream->runtime->trigger_master != substream) |
985 | return 0; | 982 | return 0; |
983 | /* some drivers might use hw_ptr to recover from the pause - | ||
984 | update the hw_ptr now */ | ||
985 | if (push) | ||
986 | snd_pcm_update_hw_ptr(substream); | ||
986 | /* The jiffies check in snd_pcm_update_hw_ptr*() is done by | 987 | /* The jiffies check in snd_pcm_update_hw_ptr*() is done by |
987 | * a delta betwen the current jiffies, this gives a large enough | 988 | * a delta betwen the current jiffies, this gives a large enough |
988 | * delta, effectively to skip the check once. | 989 | * delta, effectively to skip the check once. |
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index eb68326c37d4..a7868ad4d530 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c | |||
@@ -829,6 +829,8 @@ static int snd_rawmidi_control_ioctl(struct snd_card *card, | |||
829 | 829 | ||
830 | if (get_user(device, (int __user *)argp)) | 830 | if (get_user(device, (int __user *)argp)) |
831 | return -EFAULT; | 831 | return -EFAULT; |
832 | if (device >= SNDRV_RAWMIDI_DEVICES) /* next device is -1 */ | ||
833 | device = SNDRV_RAWMIDI_DEVICES - 1; | ||
832 | mutex_lock(®ister_mutex); | 834 | mutex_lock(®ister_mutex); |
833 | device = device < 0 ? 0 : device + 1; | 835 | device = device < 0 ? 0 : device + 1; |
834 | while (device < SNDRV_RAWMIDI_DEVICES) { | 836 | while (device < SNDRV_RAWMIDI_DEVICES) { |
diff --git a/sound/core/seq/oss/seq_oss_init.c b/sound/core/seq/oss/seq_oss_init.c index 685712276ac9..69cd7b3c362d 100644 --- a/sound/core/seq/oss/seq_oss_init.c +++ b/sound/core/seq/oss/seq_oss_init.c | |||
@@ -281,13 +281,10 @@ snd_seq_oss_open(struct file *file, int level) | |||
281 | return 0; | 281 | return 0; |
282 | 282 | ||
283 | _error: | 283 | _error: |
284 | snd_seq_oss_writeq_delete(dp->writeq); | ||
285 | snd_seq_oss_readq_delete(dp->readq); | ||
286 | snd_seq_oss_synth_cleanup(dp); | 284 | snd_seq_oss_synth_cleanup(dp); |
287 | snd_seq_oss_midi_cleanup(dp); | 285 | snd_seq_oss_midi_cleanup(dp); |
288 | delete_port(dp); | ||
289 | delete_seq_queue(dp->queue); | 286 | delete_seq_queue(dp->queue); |
290 | kfree(dp); | 287 | delete_port(dp); |
291 | 288 | ||
292 | return rc; | 289 | return rc; |
293 | } | 290 | } |
@@ -350,8 +347,10 @@ create_port(struct seq_oss_devinfo *dp) | |||
350 | static int | 347 | static int |
351 | delete_port(struct seq_oss_devinfo *dp) | 348 | delete_port(struct seq_oss_devinfo *dp) |
352 | { | 349 | { |
353 | if (dp->port < 0) | 350 | if (dp->port < 0) { |
351 | kfree(dp); | ||
354 | return 0; | 352 | return 0; |
353 | } | ||
355 | 354 | ||
356 | debug_printk(("delete_port %i\n", dp->port)); | 355 | debug_printk(("delete_port %i\n", dp->port)); |
357 | return snd_seq_event_port_detach(dp->cseq, dp->port); | 356 | return snd_seq_event_port_detach(dp->cseq, dp->port); |
diff --git a/sound/drivers/Kconfig b/sound/drivers/Kconfig index b6ae76285255..c8961165277c 100644 --- a/sound/drivers/Kconfig +++ b/sound/drivers/Kconfig | |||
@@ -174,7 +174,7 @@ config SND_ML403_AC97CR | |||
174 | select SND_AC97_CODEC | 174 | select SND_AC97_CODEC |
175 | help | 175 | help |
176 | Say Y here to include support for the | 176 | Say Y here to include support for the |
177 | opb_ac97_controller_ref_v1_00_a ip core found in Xilinx' ML403 | 177 | opb_ac97_controller_ref_v1_00_a ip core found in Xilinx's ML403 |
178 | reference design. | 178 | reference design. |
179 | 179 | ||
180 | To compile this driver as a module, choose M here: the module | 180 | To compile this driver as a module, choose M here: the module |
@@ -189,9 +189,25 @@ config SND_AC97_POWER_SAVE | |||
189 | AC97 codecs. In this mode, the power-mode is dynamically | 189 | AC97 codecs. In this mode, the power-mode is dynamically |
190 | controlled at each open/close. | 190 | controlled at each open/close. |
191 | 191 | ||
192 | The mode is activated by passing power_save=1 option to | 192 | The mode is activated by passing 'power_save=X' to the |
193 | snd-ac97-codec driver. You can toggle it dynamically over | 193 | snd-ac97-codec driver module, where 'X' is the time-out |
194 | sysfs, too. | 194 | value, a nonnegative integer that specifies how many |
195 | seconds of idle time the driver must count before it may | ||
196 | put the AC97 into power-save mode; a value of 0 (zero) | ||
197 | disables the use of this power-save mode. | ||
198 | |||
199 | After the snd-ac97-codec driver module has been loaded, | ||
200 | the 'power_save' parameter can be set via sysfs as follows: | ||
201 | |||
202 | echo 10 > /sys/module/snd_ac97_codec/parameters/power_save | ||
203 | |||
204 | In this case, the time-out is set to 10 seconds; setting | ||
205 | the time-out to 1 second (the minimum activation value) | ||
206 | isn't recommended because many applications try to reopen | ||
207 | the device frequently. A value of 10 seconds would be a | ||
208 | good choice for normal operations. | ||
209 | |||
210 | See Documentation/sound/alsa/powersave.txt for more details. | ||
195 | 211 | ||
196 | config SND_AC97_POWER_SAVE_DEFAULT | 212 | config SND_AC97_POWER_SAVE_DEFAULT |
197 | int "Default time-out for AC97 power-save mode" | 213 | int "Default time-out for AC97 power-save mode" |
@@ -201,4 +217,6 @@ config SND_AC97_POWER_SAVE_DEFAULT | |||
201 | The default time-out value in seconds for AC97 automatic | 217 | The default time-out value in seconds for AC97 automatic |
202 | power-save mode. 0 means to disable the power-save mode. | 218 | power-save mode. 0 means to disable the power-save mode. |
203 | 219 | ||
220 | See SND_AC97_POWER_SAVE for more details. | ||
221 | |||
204 | endif # SND_DRIVERS | 222 | endif # SND_DRIVERS |
diff --git a/sound/drivers/virmidi.c b/sound/drivers/virmidi.c index 0e631c3221e3..f4cd49336f33 100644 --- a/sound/drivers/virmidi.c +++ b/sound/drivers/virmidi.c | |||
@@ -94,7 +94,7 @@ static int __devinit snd_virmidi_probe(struct platform_device *devptr) | |||
94 | sizeof(struct snd_card_virmidi), &card); | 94 | sizeof(struct snd_card_virmidi), &card); |
95 | if (err < 0) | 95 | if (err < 0) |
96 | return err; | 96 | return err; |
97 | vmidi = (struct snd_card_virmidi *)card->private_data; | 97 | vmidi = card->private_data; |
98 | vmidi->card = card; | 98 | vmidi->card = card; |
99 | 99 | ||
100 | if (midi_devs[dev] > MAX_MIDI_DEVICES) { | 100 | if (midi_devs[dev] > MAX_MIDI_DEVICES) { |
diff --git a/sound/i2c/other/ak4xxx-adda.c b/sound/i2c/other/ak4xxx-adda.c index 1adb8a3c2b62..ebab6c7aaa81 100644 --- a/sound/i2c/other/ak4xxx-adda.c +++ b/sound/i2c/other/ak4xxx-adda.c | |||
@@ -878,7 +878,7 @@ static int build_deemphasis(struct snd_akm4xxx *ak, int num_emphs) | |||
878 | static void proc_regs_read(struct snd_info_entry *entry, | 878 | static void proc_regs_read(struct snd_info_entry *entry, |
879 | struct snd_info_buffer *buffer) | 879 | struct snd_info_buffer *buffer) |
880 | { | 880 | { |
881 | struct snd_akm4xxx *ak = (struct snd_akm4xxx *)entry->private_data; | 881 | struct snd_akm4xxx *ak = entry->private_data; |
882 | int reg, val, chip; | 882 | int reg, val, chip; |
883 | for (chip = 0; chip < ak->num_chips; chip++) { | 883 | for (chip = 0; chip < ak->num_chips; chip++) { |
884 | for (reg = 0; reg < ak->total_regs; reg++) { | 884 | for (reg = 0; reg < ak->total_regs; reg++) { |
diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig index c6990c680796..52064cfa91f3 100644 --- a/sound/isa/Kconfig +++ b/sound/isa/Kconfig | |||
@@ -77,6 +77,32 @@ config SND_ALS100 | |||
77 | 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 |
78 | will be called snd-als100. | 78 | will be called snd-als100. |
79 | 79 | ||
80 | config SND_AZT1605 | ||
81 | tristate "Aztech AZT1605 Driver" | ||
82 | depends on SND | ||
83 | select SND_WSS_LIB | ||
84 | select SND_MPU401_UART | ||
85 | select SND_OPL3_LIB | ||
86 | help | ||
87 | Say Y here to include support for Aztech Sound Galaxy cards | ||
88 | based on the AZT1605 chipset. | ||
89 | |||
90 | To compile this driver as a module, choose M here: the module | ||
91 | will be called snd-azt1605. | ||
92 | |||
93 | config SND_AZT2316 | ||
94 | tristate "Aztech AZT2316 Driver" | ||
95 | depends on SND | ||
96 | select SND_WSS_LIB | ||
97 | select SND_MPU401_UART | ||
98 | select SND_OPL3_LIB | ||
99 | help | ||
100 | Say Y here to include support for Aztech Sound Galaxy cards | ||
101 | based on the AZT2316 chipset. | ||
102 | |||
103 | To compile this driver as a module, choose M here: the module | ||
104 | will be called snd-azt2316. | ||
105 | |||
80 | config SND_AZT2320 | 106 | config SND_AZT2320 |
81 | tristate "Aztech Systems AZT2320" | 107 | tristate "Aztech Systems AZT2320" |
82 | depends on PNP | 108 | depends on PNP |
@@ -351,16 +377,6 @@ config SND_SB16_CSP | |||
351 | coprocessor can do variable tasks like various compression and | 377 | coprocessor can do variable tasks like various compression and |
352 | decompression algorithms. | 378 | decompression algorithms. |
353 | 379 | ||
354 | config SND_SGALAXY | ||
355 | tristate "Aztech Sound Galaxy" | ||
356 | select SND_WSS_LIB | ||
357 | help | ||
358 | Say Y here to include support for Aztech Sound Galaxy | ||
359 | soundcards. | ||
360 | |||
361 | To compile this driver as a module, choose M here: the module | ||
362 | will be called snd-sgalaxy. | ||
363 | |||
364 | config SND_SSCAPE | 380 | config SND_SSCAPE |
365 | tristate "Ensoniq SoundScape driver" | 381 | tristate "Ensoniq SoundScape driver" |
366 | select SND_MPU401_UART | 382 | select SND_MPU401_UART |
diff --git a/sound/isa/Makefile b/sound/isa/Makefile index c73d30c4f462..8d781e419e2e 100644 --- a/sound/isa/Makefile +++ b/sound/isa/Makefile | |||
@@ -10,7 +10,6 @@ snd-cmi8330-objs := cmi8330.o | |||
10 | snd-es18xx-objs := es18xx.o | 10 | snd-es18xx-objs := es18xx.o |
11 | snd-opl3sa2-objs := opl3sa2.o | 11 | snd-opl3sa2-objs := opl3sa2.o |
12 | snd-sc6000-objs := sc6000.o | 12 | snd-sc6000-objs := sc6000.o |
13 | snd-sgalaxy-objs := sgalaxy.o | ||
14 | snd-sscape-objs := sscape.o | 13 | snd-sscape-objs := sscape.o |
15 | 14 | ||
16 | # Toplevel Module Dependency | 15 | # Toplevel Module Dependency |
@@ -21,8 +20,7 @@ obj-$(CONFIG_SND_CMI8330) += snd-cmi8330.o | |||
21 | obj-$(CONFIG_SND_ES18XX) += snd-es18xx.o | 20 | obj-$(CONFIG_SND_ES18XX) += snd-es18xx.o |
22 | obj-$(CONFIG_SND_OPL3SA2) += snd-opl3sa2.o | 21 | obj-$(CONFIG_SND_OPL3SA2) += snd-opl3sa2.o |
23 | obj-$(CONFIG_SND_SC6000) += snd-sc6000.o | 22 | obj-$(CONFIG_SND_SC6000) += snd-sc6000.o |
24 | obj-$(CONFIG_SND_SGALAXY) += snd-sgalaxy.o | ||
25 | obj-$(CONFIG_SND_SSCAPE) += snd-sscape.o | 23 | obj-$(CONFIG_SND_SSCAPE) += snd-sscape.o |
26 | 24 | ||
27 | obj-$(CONFIG_SND) += ad1816a/ ad1848/ cs423x/ es1688/ gus/ msnd/ opti9xx/ \ | 25 | obj-$(CONFIG_SND) += ad1816a/ ad1848/ cs423x/ es1688/ galaxy/ gus/ msnd/ opti9xx/ \ |
28 | sb/ wavefront/ wss/ | 26 | sb/ wavefront/ wss/ |
diff --git a/sound/isa/ad1816a/ad1816a.c b/sound/isa/ad1816a/ad1816a.c index bbcbf92a8ebe..3cb75bc97699 100644 --- a/sound/isa/ad1816a/ad1816a.c +++ b/sound/isa/ad1816a/ad1816a.c | |||
@@ -162,7 +162,7 @@ static int __devinit snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard | |||
162 | sizeof(struct snd_card_ad1816a), &card); | 162 | sizeof(struct snd_card_ad1816a), &card); |
163 | if (error < 0) | 163 | if (error < 0) |
164 | return error; | 164 | return error; |
165 | acard = (struct snd_card_ad1816a *)card->private_data; | 165 | acard = card->private_data; |
166 | 166 | ||
167 | if ((error = snd_card_ad1816a_pnp(dev, acard, pcard, pid))) { | 167 | if ((error = snd_card_ad1816a_pnp(dev, acard, pcard, pid))) { |
168 | snd_card_free(card); | 168 | snd_card_free(card); |
diff --git a/sound/isa/azt2320.c b/sound/isa/azt2320.c index f7aa637b0d18..aac8dc15c2fe 100644 --- a/sound/isa/azt2320.c +++ b/sound/isa/azt2320.c | |||
@@ -188,7 +188,7 @@ static int __devinit snd_card_azt2320_probe(int dev, | |||
188 | sizeof(struct snd_card_azt2320), &card); | 188 | sizeof(struct snd_card_azt2320), &card); |
189 | if (error < 0) | 189 | if (error < 0) |
190 | return error; | 190 | return error; |
191 | acard = (struct snd_card_azt2320 *)card->private_data; | 191 | acard = card->private_data; |
192 | 192 | ||
193 | if ((error = snd_card_azt2320_pnp(dev, acard, pcard, pid))) { | 193 | if ((error = snd_card_azt2320_pnp(dev, acard, pcard, pid))) { |
194 | snd_card_free(card); | 194 | snd_card_free(card); |
diff --git a/sound/isa/galaxy/Makefile b/sound/isa/galaxy/Makefile new file mode 100644 index 000000000000..e307066d4315 --- /dev/null +++ b/sound/isa/galaxy/Makefile | |||
@@ -0,0 +1,10 @@ | |||
1 | # | ||
2 | # Makefile for ALSA | ||
3 | # Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz> | ||
4 | # | ||
5 | |||
6 | snd-azt1605-objs := azt1605.o | ||
7 | snd-azt2316-objs := azt2316.o | ||
8 | |||
9 | obj-$(CONFIG_SND_AZT1605) += snd-azt1605.o | ||
10 | obj-$(CONFIG_SND_AZT2316) += snd-azt2316.o | ||
diff --git a/sound/isa/galaxy/azt1605.c b/sound/isa/galaxy/azt1605.c new file mode 100644 index 000000000000..9a97643cb713 --- /dev/null +++ b/sound/isa/galaxy/azt1605.c | |||
@@ -0,0 +1,91 @@ | |||
1 | /* | ||
2 | * Aztech AZT1605 Driver | ||
3 | * Copyright (C) 2007,2010 Rene Herman | ||
4 | * | ||
5 | * This program is free software: you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation, either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program 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 program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | * | ||
18 | */ | ||
19 | |||
20 | #define AZT1605 | ||
21 | |||
22 | #define CRD_NAME "Aztech AZT1605" | ||
23 | #define DRV_NAME "AZT1605" | ||
24 | #define DEV_NAME "azt1605" | ||
25 | |||
26 | #define GALAXY_DSP_MAJOR 2 | ||
27 | #define GALAXY_DSP_MINOR 1 | ||
28 | |||
29 | #define GALAXY_CONFIG_SIZE 3 | ||
30 | |||
31 | /* | ||
32 | * 24-bit config register | ||
33 | */ | ||
34 | |||
35 | #define GALAXY_CONFIG_SBA_220 (0 << 0) | ||
36 | #define GALAXY_CONFIG_SBA_240 (1 << 0) | ||
37 | #define GALAXY_CONFIG_SBA_260 (2 << 0) | ||
38 | #define GALAXY_CONFIG_SBA_280 (3 << 0) | ||
39 | #define GALAXY_CONFIG_SBA_MASK GALAXY_CONFIG_SBA_280 | ||
40 | |||
41 | #define GALAXY_CONFIG_MPUA_300 (0 << 2) | ||
42 | #define GALAXY_CONFIG_MPUA_330 (1 << 2) | ||
43 | |||
44 | #define GALAXY_CONFIG_MPU_ENABLE (1 << 3) | ||
45 | |||
46 | #define GALAXY_CONFIG_GAME_ENABLE (1 << 4) | ||
47 | |||
48 | #define GALAXY_CONFIG_CD_PANASONIC (1 << 5) | ||
49 | #define GALAXY_CONFIG_CD_MITSUMI (1 << 6) | ||
50 | #define GALAXY_CONFIG_CD_MASK (\ | ||
51 | GALAXY_CONFIG_CD_PANASONIC | GALAXY_CONFIG_CD_MITSUMI) | ||
52 | |||
53 | #define GALAXY_CONFIG_UNUSED (1 << 7) | ||
54 | #define GALAXY_CONFIG_UNUSED_MASK GALAXY_CONFIG_UNUSED | ||
55 | |||
56 | #define GALAXY_CONFIG_SBIRQ_2 (1 << 8) | ||
57 | #define GALAXY_CONFIG_SBIRQ_3 (1 << 9) | ||
58 | #define GALAXY_CONFIG_SBIRQ_5 (1 << 10) | ||
59 | #define GALAXY_CONFIG_SBIRQ_7 (1 << 11) | ||
60 | |||
61 | #define GALAXY_CONFIG_MPUIRQ_2 (1 << 12) | ||
62 | #define GALAXY_CONFIG_MPUIRQ_3 (1 << 13) | ||
63 | #define GALAXY_CONFIG_MPUIRQ_5 (1 << 14) | ||
64 | #define GALAXY_CONFIG_MPUIRQ_7 (1 << 15) | ||
65 | |||
66 | #define GALAXY_CONFIG_WSSA_530 (0 << 16) | ||
67 | #define GALAXY_CONFIG_WSSA_604 (1 << 16) | ||
68 | #define GALAXY_CONFIG_WSSA_E80 (2 << 16) | ||
69 | #define GALAXY_CONFIG_WSSA_F40 (3 << 16) | ||
70 | |||
71 | #define GALAXY_CONFIG_WSS_ENABLE (1 << 18) | ||
72 | |||
73 | #define GALAXY_CONFIG_CDIRQ_11 (1 << 19) | ||
74 | #define GALAXY_CONFIG_CDIRQ_12 (1 << 20) | ||
75 | #define GALAXY_CONFIG_CDIRQ_15 (1 << 21) | ||
76 | #define GALAXY_CONFIG_CDIRQ_MASK (\ | ||
77 | GALAXY_CONFIG_CDIRQ_11 | GALAXY_CONFIG_CDIRQ_12 |\ | ||
78 | GALAXY_CONFIG_CDIRQ_15) | ||
79 | |||
80 | #define GALAXY_CONFIG_CDDMA_DISABLE (0 << 22) | ||
81 | #define GALAXY_CONFIG_CDDMA_0 (1 << 22) | ||
82 | #define GALAXY_CONFIG_CDDMA_1 (2 << 22) | ||
83 | #define GALAXY_CONFIG_CDDMA_3 (3 << 22) | ||
84 | #define GALAXY_CONFIG_CDDMA_MASK GALAXY_CONFIG_CDDMA_3 | ||
85 | |||
86 | #define GALAXY_CONFIG_MASK (\ | ||
87 | GALAXY_CONFIG_SBA_MASK | GALAXY_CONFIG_CD_MASK |\ | ||
88 | GALAXY_CONFIG_UNUSED_MASK | GALAXY_CONFIG_CDIRQ_MASK |\ | ||
89 | GALAXY_CONFIG_CDDMA_MASK) | ||
90 | |||
91 | #include "galaxy.c" | ||
diff --git a/sound/isa/galaxy/azt2316.c b/sound/isa/galaxy/azt2316.c new file mode 100644 index 000000000000..189441141df6 --- /dev/null +++ b/sound/isa/galaxy/azt2316.c | |||
@@ -0,0 +1,111 @@ | |||
1 | /* | ||
2 | * Aztech AZT2316 Driver | ||
3 | * Copyright (C) 2007,2010 Rene Herman | ||
4 | * | ||
5 | * This program is free software: you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation, either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program 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 program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | * | ||
18 | */ | ||
19 | |||
20 | #define AZT2316 | ||
21 | |||
22 | #define CRD_NAME "Aztech AZT2316" | ||
23 | #define DRV_NAME "AZT2316" | ||
24 | #define DEV_NAME "azt2316" | ||
25 | |||
26 | #define GALAXY_DSP_MAJOR 3 | ||
27 | #define GALAXY_DSP_MINOR 1 | ||
28 | |||
29 | #define GALAXY_CONFIG_SIZE 4 | ||
30 | |||
31 | /* | ||
32 | * 32-bit config register | ||
33 | */ | ||
34 | |||
35 | #define GALAXY_CONFIG_SBA_220 (0 << 0) | ||
36 | #define GALAXY_CONFIG_SBA_240 (1 << 0) | ||
37 | #define GALAXY_CONFIG_SBA_260 (2 << 0) | ||
38 | #define GALAXY_CONFIG_SBA_280 (3 << 0) | ||
39 | #define GALAXY_CONFIG_SBA_MASK GALAXY_CONFIG_SBA_280 | ||
40 | |||
41 | #define GALAXY_CONFIG_SBIRQ_2 (1 << 2) | ||
42 | #define GALAXY_CONFIG_SBIRQ_5 (1 << 3) | ||
43 | #define GALAXY_CONFIG_SBIRQ_7 (1 << 4) | ||
44 | #define GALAXY_CONFIG_SBIRQ_10 (1 << 5) | ||
45 | |||
46 | #define GALAXY_CONFIG_SBDMA_DISABLE (0 << 6) | ||
47 | #define GALAXY_CONFIG_SBDMA_0 (1 << 6) | ||
48 | #define GALAXY_CONFIG_SBDMA_1 (2 << 6) | ||
49 | #define GALAXY_CONFIG_SBDMA_3 (3 << 6) | ||
50 | |||
51 | #define GALAXY_CONFIG_WSSA_530 (0 << 8) | ||
52 | #define GALAXY_CONFIG_WSSA_604 (1 << 8) | ||
53 | #define GALAXY_CONFIG_WSSA_E80 (2 << 8) | ||
54 | #define GALAXY_CONFIG_WSSA_F40 (3 << 8) | ||
55 | |||
56 | #define GALAXY_CONFIG_WSS_ENABLE (1 << 10) | ||
57 | |||
58 | #define GALAXY_CONFIG_GAME_ENABLE (1 << 11) | ||
59 | |||
60 | #define GALAXY_CONFIG_MPUA_300 (0 << 12) | ||
61 | #define GALAXY_CONFIG_MPUA_330 (1 << 12) | ||
62 | |||
63 | #define GALAXY_CONFIG_MPU_ENABLE (1 << 13) | ||
64 | |||
65 | #define GALAXY_CONFIG_CDA_310 (0 << 14) | ||
66 | #define GALAXY_CONFIG_CDA_320 (1 << 14) | ||
67 | #define GALAXY_CONFIG_CDA_340 (2 << 14) | ||
68 | #define GALAXY_CONFIG_CDA_350 (3 << 14) | ||
69 | #define GALAXY_CONFIG_CDA_MASK GALAXY_CONFIG_CDA_350 | ||
70 | |||
71 | #define GALAXY_CONFIG_CD_DISABLE (0 << 16) | ||
72 | #define GALAXY_CONFIG_CD_PANASONIC (1 << 16) | ||
73 | #define GALAXY_CONFIG_CD_SONY (2 << 16) | ||
74 | #define GALAXY_CONFIG_CD_MITSUMI (3 << 16) | ||
75 | #define GALAXY_CONFIG_CD_AZTECH (4 << 16) | ||
76 | #define GALAXY_CONFIG_CD_UNUSED_5 (5 << 16) | ||
77 | #define GALAXY_CONFIG_CD_UNUSED_6 (6 << 16) | ||
78 | #define GALAXY_CONFIG_CD_UNUSED_7 (7 << 16) | ||
79 | #define GALAXY_CONFIG_CD_MASK GALAXY_CONFIG_CD_UNUSED_7 | ||
80 | |||
81 | #define GALAXY_CONFIG_CDDMA8_DISABLE (0 << 20) | ||
82 | #define GALAXY_CONFIG_CDDMA8_0 (1 << 20) | ||
83 | #define GALAXY_CONFIG_CDDMA8_1 (2 << 20) | ||
84 | #define GALAXY_CONFIG_CDDMA8_3 (3 << 20) | ||
85 | #define GALAXY_CONFIG_CDDMA8_MASK GALAXY_CONFIG_CDDMA8_3 | ||
86 | |||
87 | #define GALAXY_CONFIG_CDDMA16_DISABLE (0 << 22) | ||
88 | #define GALAXY_CONFIG_CDDMA16_5 (1 << 22) | ||
89 | #define GALAXY_CONFIG_CDDMA16_6 (2 << 22) | ||
90 | #define GALAXY_CONFIG_CDDMA16_7 (3 << 22) | ||
91 | #define GALAXY_CONFIG_CDDMA16_MASK GALAXY_CONFIG_CDDMA16_7 | ||
92 | |||
93 | #define GALAXY_CONFIG_MPUIRQ_2 (1 << 24) | ||
94 | #define GALAXY_CONFIG_MPUIRQ_5 (1 << 25) | ||
95 | #define GALAXY_CONFIG_MPUIRQ_7 (1 << 26) | ||
96 | #define GALAXY_CONFIG_MPUIRQ_10 (1 << 27) | ||
97 | |||
98 | #define GALAXY_CONFIG_CDIRQ_5 (1 << 28) | ||
99 | #define GALAXY_CONFIG_CDIRQ_11 (1 << 29) | ||
100 | #define GALAXY_CONFIG_CDIRQ_12 (1 << 30) | ||
101 | #define GALAXY_CONFIG_CDIRQ_15 (1 << 31) | ||
102 | #define GALAXY_CONFIG_CDIRQ_MASK (\ | ||
103 | GALAXY_CONFIG_CDIRQ_5 | GALAXY_CONFIG_CDIRQ_11 |\ | ||
104 | GALAXY_CONFIG_CDIRQ_12 | GALAXY_CONFIG_CDIRQ_15) | ||
105 | |||
106 | #define GALAXY_CONFIG_MASK (\ | ||
107 | GALAXY_CONFIG_SBA_MASK | GALAXY_CONFIG_CDA_MASK |\ | ||
108 | GALAXY_CONFIG_CD_MASK | GALAXY_CONFIG_CDDMA16_MASK |\ | ||
109 | GALAXY_CONFIG_CDDMA8_MASK | GALAXY_CONFIG_CDIRQ_MASK) | ||
110 | |||
111 | #include "galaxy.c" | ||
diff --git a/sound/isa/galaxy/galaxy.c b/sound/isa/galaxy/galaxy.c new file mode 100644 index 000000000000..ee54df082b9c --- /dev/null +++ b/sound/isa/galaxy/galaxy.c | |||
@@ -0,0 +1,652 @@ | |||
1 | /* | ||
2 | * Aztech AZT1605/AZT2316 Driver | ||
3 | * Copyright (C) 2007,2010 Rene Herman | ||
4 | * | ||
5 | * This program is free software: you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation, either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program 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 program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | * | ||
18 | */ | ||
19 | |||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/isa.h> | ||
23 | #include <linux/delay.h> | ||
24 | #include <linux/io.h> | ||
25 | #include <asm/processor.h> | ||
26 | #include <sound/core.h> | ||
27 | #include <sound/initval.h> | ||
28 | #include <sound/wss.h> | ||
29 | #include <sound/mpu401.h> | ||
30 | #include <sound/opl3.h> | ||
31 | |||
32 | MODULE_DESCRIPTION(CRD_NAME); | ||
33 | MODULE_AUTHOR("Rene Herman"); | ||
34 | MODULE_LICENSE("GPL"); | ||
35 | |||
36 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; | ||
37 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; | ||
38 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; | ||
39 | |||
40 | module_param_array(index, int, NULL, 0444); | ||
41 | MODULE_PARM_DESC(index, "Index value for " CRD_NAME " soundcard."); | ||
42 | module_param_array(id, charp, NULL, 0444); | ||
43 | MODULE_PARM_DESC(id, "ID string for " CRD_NAME " soundcard."); | ||
44 | module_param_array(enable, bool, NULL, 0444); | ||
45 | MODULE_PARM_DESC(enable, "Enable " CRD_NAME " soundcard."); | ||
46 | |||
47 | static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; | ||
48 | static long wss_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; | ||
49 | static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; | ||
50 | static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; | ||
51 | static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; | ||
52 | static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; | ||
53 | static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; | ||
54 | static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; | ||
55 | |||
56 | module_param_array(port, long, NULL, 0444); | ||
57 | MODULE_PARM_DESC(port, "Port # for " CRD_NAME " driver."); | ||
58 | module_param_array(wss_port, long, NULL, 0444); | ||
59 | MODULE_PARM_DESC(wss_port, "WSS port # for " CRD_NAME " driver."); | ||
60 | module_param_array(mpu_port, long, NULL, 0444); | ||
61 | MODULE_PARM_DESC(mpu_port, "MPU-401 port # for " CRD_NAME " driver."); | ||
62 | module_param_array(fm_port, long, NULL, 0444); | ||
63 | MODULE_PARM_DESC(fm_port, "FM port # for " CRD_NAME " driver."); | ||
64 | module_param_array(irq, int, NULL, 0444); | ||
65 | MODULE_PARM_DESC(irq, "IRQ # for " CRD_NAME " driver."); | ||
66 | module_param_array(mpu_irq, int, NULL, 0444); | ||
67 | MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for " CRD_NAME " driver."); | ||
68 | module_param_array(dma1, int, NULL, 0444); | ||
69 | MODULE_PARM_DESC(dma1, "Playback DMA # for " CRD_NAME " driver."); | ||
70 | module_param_array(dma2, int, NULL, 0444); | ||
71 | MODULE_PARM_DESC(dma2, "Capture DMA # for " CRD_NAME " driver."); | ||
72 | |||
73 | /* | ||
74 | * Generic SB DSP support routines | ||
75 | */ | ||
76 | |||
77 | #define DSP_PORT_RESET 0x6 | ||
78 | #define DSP_PORT_READ 0xa | ||
79 | #define DSP_PORT_COMMAND 0xc | ||
80 | #define DSP_PORT_STATUS 0xc | ||
81 | #define DSP_PORT_DATA_AVAIL 0xe | ||
82 | |||
83 | #define DSP_SIGNATURE 0xaa | ||
84 | |||
85 | #define DSP_COMMAND_GET_VERSION 0xe1 | ||
86 | |||
87 | static int __devinit dsp_get_byte(void __iomem *port, u8 *val) | ||
88 | { | ||
89 | int loops = 1000; | ||
90 | |||
91 | while (!(ioread8(port + DSP_PORT_DATA_AVAIL) & 0x80)) { | ||
92 | if (!loops--) | ||
93 | return -EIO; | ||
94 | cpu_relax(); | ||
95 | } | ||
96 | *val = ioread8(port + DSP_PORT_READ); | ||
97 | return 0; | ||
98 | } | ||
99 | |||
100 | static int __devinit dsp_reset(void __iomem *port) | ||
101 | { | ||
102 | u8 val; | ||
103 | |||
104 | iowrite8(1, port + DSP_PORT_RESET); | ||
105 | udelay(10); | ||
106 | iowrite8(0, port + DSP_PORT_RESET); | ||
107 | |||
108 | if (dsp_get_byte(port, &val) < 0 || val != DSP_SIGNATURE) | ||
109 | return -ENODEV; | ||
110 | |||
111 | return 0; | ||
112 | } | ||
113 | |||
114 | static int __devinit dsp_command(void __iomem *port, u8 cmd) | ||
115 | { | ||
116 | int loops = 1000; | ||
117 | |||
118 | while (ioread8(port + DSP_PORT_STATUS) & 0x80) { | ||
119 | if (!loops--) | ||
120 | return -EIO; | ||
121 | cpu_relax(); | ||
122 | } | ||
123 | iowrite8(cmd, port + DSP_PORT_COMMAND); | ||
124 | return 0; | ||
125 | } | ||
126 | |||
127 | static int __devinit dsp_get_version(void __iomem *port, u8 *major, u8 *minor) | ||
128 | { | ||
129 | int err; | ||
130 | |||
131 | err = dsp_command(port, DSP_COMMAND_GET_VERSION); | ||
132 | if (err < 0) | ||
133 | return err; | ||
134 | |||
135 | err = dsp_get_byte(port, major); | ||
136 | if (err < 0) | ||
137 | return err; | ||
138 | |||
139 | err = dsp_get_byte(port, minor); | ||
140 | if (err < 0) | ||
141 | return err; | ||
142 | |||
143 | return 0; | ||
144 | } | ||
145 | |||
146 | /* | ||
147 | * Generic WSS support routines | ||
148 | */ | ||
149 | |||
150 | #define WSS_CONFIG_DMA_0 (1 << 0) | ||
151 | #define WSS_CONFIG_DMA_1 (2 << 0) | ||
152 | #define WSS_CONFIG_DMA_3 (3 << 0) | ||
153 | #define WSS_CONFIG_DUPLEX (1 << 2) | ||
154 | #define WSS_CONFIG_IRQ_7 (1 << 3) | ||
155 | #define WSS_CONFIG_IRQ_9 (2 << 3) | ||
156 | #define WSS_CONFIG_IRQ_10 (3 << 3) | ||
157 | #define WSS_CONFIG_IRQ_11 (4 << 3) | ||
158 | |||
159 | #define WSS_PORT_CONFIG 0 | ||
160 | #define WSS_PORT_SIGNATURE 3 | ||
161 | |||
162 | #define WSS_SIGNATURE 4 | ||
163 | |||
164 | static int __devinit wss_detect(void __iomem *wss_port) | ||
165 | { | ||
166 | if ((ioread8(wss_port + WSS_PORT_SIGNATURE) & 0x3f) != WSS_SIGNATURE) | ||
167 | return -ENODEV; | ||
168 | |||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | static void wss_set_config(void __iomem *wss_port, u8 wss_config) | ||
173 | { | ||
174 | iowrite8(wss_config, wss_port + WSS_PORT_CONFIG); | ||
175 | } | ||
176 | |||
177 | /* | ||
178 | * Aztech Sound Galaxy specifics | ||
179 | */ | ||
180 | |||
181 | #define GALAXY_PORT_CONFIG 1024 | ||
182 | #define CONFIG_PORT_SET 4 | ||
183 | |||
184 | #define DSP_COMMAND_GALAXY_8 8 | ||
185 | #define GALAXY_COMMAND_GET_TYPE 5 | ||
186 | |||
187 | #define DSP_COMMAND_GALAXY_9 9 | ||
188 | #define GALAXY_COMMAND_WSSMODE 0 | ||
189 | #define GALAXY_COMMAND_SB8MODE 1 | ||
190 | |||
191 | #define GALAXY_MODE_WSS GALAXY_COMMAND_WSSMODE | ||
192 | #define GALAXY_MODE_SB8 GALAXY_COMMAND_SB8MODE | ||
193 | |||
194 | struct snd_galaxy { | ||
195 | void __iomem *port; | ||
196 | void __iomem *config_port; | ||
197 | void __iomem *wss_port; | ||
198 | u32 config; | ||
199 | struct resource *res_port; | ||
200 | struct resource *res_config_port; | ||
201 | struct resource *res_wss_port; | ||
202 | }; | ||
203 | |||
204 | static u32 config[SNDRV_CARDS]; | ||
205 | static u8 wss_config[SNDRV_CARDS]; | ||
206 | |||
207 | static int __devinit snd_galaxy_match(struct device *dev, unsigned int n) | ||
208 | { | ||
209 | if (!enable[n]) | ||
210 | return 0; | ||
211 | |||
212 | switch (port[n]) { | ||
213 | case SNDRV_AUTO_PORT: | ||
214 | dev_err(dev, "please specify port\n"); | ||
215 | return 0; | ||
216 | case 0x220: | ||
217 | config[n] |= GALAXY_CONFIG_SBA_220; | ||
218 | break; | ||
219 | case 0x240: | ||
220 | config[n] |= GALAXY_CONFIG_SBA_240; | ||
221 | break; | ||
222 | case 0x260: | ||
223 | config[n] |= GALAXY_CONFIG_SBA_260; | ||
224 | break; | ||
225 | case 0x280: | ||
226 | config[n] |= GALAXY_CONFIG_SBA_280; | ||
227 | break; | ||
228 | default: | ||
229 | dev_err(dev, "invalid port %#lx\n", port[n]); | ||
230 | return 0; | ||
231 | } | ||
232 | |||
233 | switch (wss_port[n]) { | ||
234 | case SNDRV_AUTO_PORT: | ||
235 | dev_err(dev, "please specify wss_port\n"); | ||
236 | return 0; | ||
237 | case 0x530: | ||
238 | config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_530; | ||
239 | break; | ||
240 | case 0x604: | ||
241 | config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_604; | ||
242 | break; | ||
243 | case 0xe80: | ||
244 | config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_E80; | ||
245 | break; | ||
246 | case 0xf40: | ||
247 | config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_F40; | ||
248 | break; | ||
249 | default: | ||
250 | dev_err(dev, "invalid WSS port %#lx\n", wss_port[n]); | ||
251 | return 0; | ||
252 | } | ||
253 | |||
254 | switch (irq[n]) { | ||
255 | case SNDRV_AUTO_IRQ: | ||
256 | dev_err(dev, "please specify irq\n"); | ||
257 | return 0; | ||
258 | case 7: | ||
259 | wss_config[n] |= WSS_CONFIG_IRQ_7; | ||
260 | break; | ||
261 | case 2: | ||
262 | irq[n] = 9; | ||
263 | case 9: | ||
264 | wss_config[n] |= WSS_CONFIG_IRQ_9; | ||
265 | break; | ||
266 | case 10: | ||
267 | wss_config[n] |= WSS_CONFIG_IRQ_10; | ||
268 | break; | ||
269 | case 11: | ||
270 | wss_config[n] |= WSS_CONFIG_IRQ_11; | ||
271 | break; | ||
272 | default: | ||
273 | dev_err(dev, "invalid IRQ %d\n", irq[n]); | ||
274 | return 0; | ||
275 | } | ||
276 | |||
277 | switch (dma1[n]) { | ||
278 | case SNDRV_AUTO_DMA: | ||
279 | dev_err(dev, "please specify dma1\n"); | ||
280 | return 0; | ||
281 | case 0: | ||
282 | wss_config[n] |= WSS_CONFIG_DMA_0; | ||
283 | break; | ||
284 | case 1: | ||
285 | wss_config[n] |= WSS_CONFIG_DMA_1; | ||
286 | break; | ||
287 | case 3: | ||
288 | wss_config[n] |= WSS_CONFIG_DMA_3; | ||
289 | break; | ||
290 | default: | ||
291 | dev_err(dev, "invalid playback DMA %d\n", dma1[n]); | ||
292 | return 0; | ||
293 | } | ||
294 | |||
295 | if (dma2[n] == SNDRV_AUTO_DMA || dma2[n] == dma1[n]) { | ||
296 | dma2[n] = -1; | ||
297 | goto mpu; | ||
298 | } | ||
299 | |||
300 | wss_config[n] |= WSS_CONFIG_DUPLEX; | ||
301 | switch (dma2[n]) { | ||
302 | case 0: | ||
303 | break; | ||
304 | case 1: | ||
305 | if (dma1[n] == 0) | ||
306 | break; | ||
307 | default: | ||
308 | dev_err(dev, "invalid capture DMA %d\n", dma2[n]); | ||
309 | return 0; | ||
310 | } | ||
311 | |||
312 | mpu: | ||
313 | switch (mpu_port[n]) { | ||
314 | case SNDRV_AUTO_PORT: | ||
315 | dev_warn(dev, "mpu_port not specified; not using MPU-401\n"); | ||
316 | mpu_port[n] = -1; | ||
317 | goto fm; | ||
318 | case 0x300: | ||
319 | config[n] |= GALAXY_CONFIG_MPU_ENABLE | GALAXY_CONFIG_MPUA_300; | ||
320 | break; | ||
321 | case 0x330: | ||
322 | config[n] |= GALAXY_CONFIG_MPU_ENABLE | GALAXY_CONFIG_MPUA_330; | ||
323 | break; | ||
324 | default: | ||
325 | dev_err(dev, "invalid MPU port %#lx\n", mpu_port[n]); | ||
326 | return 0; | ||
327 | } | ||
328 | |||
329 | switch (mpu_irq[n]) { | ||
330 | case SNDRV_AUTO_IRQ: | ||
331 | dev_warn(dev, "mpu_irq not specified: using polling mode\n"); | ||
332 | mpu_irq[n] = -1; | ||
333 | break; | ||
334 | case 2: | ||
335 | mpu_irq[n] = 9; | ||
336 | case 9: | ||
337 | config[n] |= GALAXY_CONFIG_MPUIRQ_2; | ||
338 | break; | ||
339 | #ifdef AZT1605 | ||
340 | case 3: | ||
341 | config[n] |= GALAXY_CONFIG_MPUIRQ_3; | ||
342 | break; | ||
343 | #endif | ||
344 | case 5: | ||
345 | config[n] |= GALAXY_CONFIG_MPUIRQ_5; | ||
346 | break; | ||
347 | case 7: | ||
348 | config[n] |= GALAXY_CONFIG_MPUIRQ_7; | ||
349 | break; | ||
350 | #ifdef AZT2316 | ||
351 | case 10: | ||
352 | config[n] |= GALAXY_CONFIG_MPUIRQ_10; | ||
353 | break; | ||
354 | #endif | ||
355 | default: | ||
356 | dev_err(dev, "invalid MPU IRQ %d\n", mpu_irq[n]); | ||
357 | return 0; | ||
358 | } | ||
359 | |||
360 | if (mpu_irq[n] == irq[n]) { | ||
361 | dev_err(dev, "cannot share IRQ between WSS and MPU-401\n"); | ||
362 | return 0; | ||
363 | } | ||
364 | |||
365 | fm: | ||
366 | switch (fm_port[n]) { | ||
367 | case SNDRV_AUTO_PORT: | ||
368 | dev_warn(dev, "fm_port not specified: not using OPL3\n"); | ||
369 | fm_port[n] = -1; | ||
370 | break; | ||
371 | case 0x388: | ||
372 | break; | ||
373 | default: | ||
374 | dev_err(dev, "illegal FM port %#lx\n", fm_port[n]); | ||
375 | return 0; | ||
376 | } | ||
377 | |||
378 | config[n] |= GALAXY_CONFIG_GAME_ENABLE; | ||
379 | return 1; | ||
380 | } | ||
381 | |||
382 | static int __devinit galaxy_init(struct snd_galaxy *galaxy, u8 *type) | ||
383 | { | ||
384 | u8 major; | ||
385 | u8 minor; | ||
386 | int err; | ||
387 | |||
388 | err = dsp_reset(galaxy->port); | ||
389 | if (err < 0) | ||
390 | return err; | ||
391 | |||
392 | err = dsp_get_version(galaxy->port, &major, &minor); | ||
393 | if (err < 0) | ||
394 | return err; | ||
395 | |||
396 | if (major != GALAXY_DSP_MAJOR || minor != GALAXY_DSP_MINOR) | ||
397 | return -ENODEV; | ||
398 | |||
399 | err = dsp_command(galaxy->port, DSP_COMMAND_GALAXY_8); | ||
400 | if (err < 0) | ||
401 | return err; | ||
402 | |||
403 | err = dsp_command(galaxy->port, GALAXY_COMMAND_GET_TYPE); | ||
404 | if (err < 0) | ||
405 | return err; | ||
406 | |||
407 | err = dsp_get_byte(galaxy->port, type); | ||
408 | if (err < 0) | ||
409 | return err; | ||
410 | |||
411 | return 0; | ||
412 | } | ||
413 | |||
414 | static int __devinit galaxy_set_mode(struct snd_galaxy *galaxy, u8 mode) | ||
415 | { | ||
416 | int err; | ||
417 | |||
418 | err = dsp_command(galaxy->port, DSP_COMMAND_GALAXY_9); | ||
419 | if (err < 0) | ||
420 | return err; | ||
421 | |||
422 | err = dsp_command(galaxy->port, mode); | ||
423 | if (err < 0) | ||
424 | return err; | ||
425 | |||
426 | #ifdef AZT1605 | ||
427 | /* | ||
428 | * Needed for MPU IRQ on AZT1605, but AZT2316 loses WSS again | ||
429 | */ | ||
430 | err = dsp_reset(galaxy->port); | ||
431 | if (err < 0) | ||
432 | return err; | ||
433 | #endif | ||
434 | |||
435 | return 0; | ||
436 | } | ||
437 | |||
438 | static void galaxy_set_config(struct snd_galaxy *galaxy, u32 config) | ||
439 | { | ||
440 | u8 tmp = ioread8(galaxy->config_port + CONFIG_PORT_SET); | ||
441 | int i; | ||
442 | |||
443 | iowrite8(tmp | 0x80, galaxy->config_port + CONFIG_PORT_SET); | ||
444 | for (i = 0; i < GALAXY_CONFIG_SIZE; i++) { | ||
445 | iowrite8(config, galaxy->config_port + i); | ||
446 | config >>= 8; | ||
447 | } | ||
448 | iowrite8(tmp & 0x7f, galaxy->config_port + CONFIG_PORT_SET); | ||
449 | msleep(10); | ||
450 | } | ||
451 | |||
452 | static void __devinit galaxy_config(struct snd_galaxy *galaxy, u32 config) | ||
453 | { | ||
454 | int i; | ||
455 | |||
456 | for (i = GALAXY_CONFIG_SIZE; i; i--) { | ||
457 | u8 tmp = ioread8(galaxy->config_port + i - 1); | ||
458 | galaxy->config = (galaxy->config << 8) | tmp; | ||
459 | } | ||
460 | config |= galaxy->config & GALAXY_CONFIG_MASK; | ||
461 | galaxy_set_config(galaxy, config); | ||
462 | } | ||
463 | |||
464 | static int __devinit galaxy_wss_config(struct snd_galaxy *galaxy, u8 wss_config) | ||
465 | { | ||
466 | int err; | ||
467 | |||
468 | err = wss_detect(galaxy->wss_port); | ||
469 | if (err < 0) | ||
470 | return err; | ||
471 | |||
472 | wss_set_config(galaxy->wss_port, wss_config); | ||
473 | |||
474 | err = galaxy_set_mode(galaxy, GALAXY_MODE_WSS); | ||
475 | if (err < 0) | ||
476 | return err; | ||
477 | |||
478 | return 0; | ||
479 | } | ||
480 | |||
481 | static void snd_galaxy_free(struct snd_card *card) | ||
482 | { | ||
483 | struct snd_galaxy *galaxy = card->private_data; | ||
484 | |||
485 | if (galaxy->wss_port) { | ||
486 | wss_set_config(galaxy->wss_port, 0); | ||
487 | ioport_unmap(galaxy->wss_port); | ||
488 | release_and_free_resource(galaxy->res_wss_port); | ||
489 | } | ||
490 | if (galaxy->config_port) { | ||
491 | galaxy_set_config(galaxy, galaxy->config); | ||
492 | ioport_unmap(galaxy->config_port); | ||
493 | release_and_free_resource(galaxy->res_config_port); | ||
494 | } | ||
495 | if (galaxy->port) { | ||
496 | ioport_unmap(galaxy->port); | ||
497 | release_and_free_resource(galaxy->res_port); | ||
498 | } | ||
499 | } | ||
500 | |||
501 | static int __devinit snd_galaxy_probe(struct device *dev, unsigned int n) | ||
502 | { | ||
503 | struct snd_galaxy *galaxy; | ||
504 | struct snd_wss *chip; | ||
505 | struct snd_card *card; | ||
506 | u8 type; | ||
507 | int err; | ||
508 | |||
509 | err = snd_card_create(index[n], id[n], THIS_MODULE, sizeof *galaxy, | ||
510 | &card); | ||
511 | if (err < 0) | ||
512 | return err; | ||
513 | |||
514 | snd_card_set_dev(card, dev); | ||
515 | |||
516 | card->private_free = snd_galaxy_free; | ||
517 | galaxy = card->private_data; | ||
518 | |||
519 | galaxy->res_port = request_region(port[n], 16, DRV_NAME); | ||
520 | if (!galaxy->res_port) { | ||
521 | dev_err(dev, "could not grab ports %#lx-%#lx\n", port[n], | ||
522 | port[n] + 15); | ||
523 | err = -EBUSY; | ||
524 | goto error; | ||
525 | } | ||
526 | galaxy->port = ioport_map(port[n], 16); | ||
527 | |||
528 | err = galaxy_init(galaxy, &type); | ||
529 | if (err < 0) { | ||
530 | dev_err(dev, "did not find a Sound Galaxy at %#lx\n", port[n]); | ||
531 | goto error; | ||
532 | } | ||
533 | dev_info(dev, "Sound Galaxy (type %d) found at %#lx\n", type, port[n]); | ||
534 | |||
535 | galaxy->res_config_port = request_region(port[n] + GALAXY_PORT_CONFIG, | ||
536 | 16, DRV_NAME); | ||
537 | if (!galaxy->res_config_port) { | ||
538 | dev_err(dev, "could not grab ports %#lx-%#lx\n", | ||
539 | port[n] + GALAXY_PORT_CONFIG, | ||
540 | port[n] + GALAXY_PORT_CONFIG + 15); | ||
541 | err = -EBUSY; | ||
542 | goto error; | ||
543 | } | ||
544 | galaxy->config_port = ioport_map(port[n] + GALAXY_PORT_CONFIG, 16); | ||
545 | |||
546 | galaxy_config(galaxy, config[n]); | ||
547 | |||
548 | galaxy->res_wss_port = request_region(wss_port[n], 4, DRV_NAME); | ||
549 | if (!galaxy->res_wss_port) { | ||
550 | dev_err(dev, "could not grab ports %#lx-%#lx\n", wss_port[n], | ||
551 | wss_port[n] + 3); | ||
552 | err = -EBUSY; | ||
553 | goto error; | ||
554 | } | ||
555 | galaxy->wss_port = ioport_map(wss_port[n], 4); | ||
556 | |||
557 | err = galaxy_wss_config(galaxy, wss_config[n]); | ||
558 | if (err < 0) { | ||
559 | dev_err(dev, "could not configure WSS\n"); | ||
560 | goto error; | ||
561 | } | ||
562 | |||
563 | strcpy(card->driver, DRV_NAME); | ||
564 | strcpy(card->shortname, DRV_NAME); | ||
565 | sprintf(card->longname, "%s at %#lx/%#lx, irq %d, dma %d/%d", | ||
566 | card->shortname, port[n], wss_port[n], irq[n], dma1[n], | ||
567 | dma2[n]); | ||
568 | |||
569 | err = snd_wss_create(card, wss_port[n] + 4, -1, irq[n], dma1[n], | ||
570 | dma2[n], WSS_HW_DETECT, 0, &chip); | ||
571 | if (err < 0) | ||
572 | goto error; | ||
573 | |||
574 | err = snd_wss_pcm(chip, 0, NULL); | ||
575 | if (err < 0) | ||
576 | goto error; | ||
577 | |||
578 | err = snd_wss_mixer(chip); | ||
579 | if (err < 0) | ||
580 | goto error; | ||
581 | |||
582 | err = snd_wss_timer(chip, 0, NULL); | ||
583 | if (err < 0) | ||
584 | goto error; | ||
585 | |||
586 | if (mpu_port[n] >= 0) { | ||
587 | err = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, | ||
588 | mpu_port[n], 0, mpu_irq[n], | ||
589 | IRQF_DISABLED, NULL); | ||
590 | if (err < 0) | ||
591 | goto error; | ||
592 | } | ||
593 | |||
594 | if (fm_port[n] >= 0) { | ||
595 | struct snd_opl3 *opl3; | ||
596 | |||
597 | err = snd_opl3_create(card, fm_port[n], fm_port[n] + 2, | ||
598 | OPL3_HW_AUTO, 0, &opl3); | ||
599 | if (err < 0) { | ||
600 | dev_err(dev, "no OPL device at %#lx\n", fm_port[n]); | ||
601 | goto error; | ||
602 | } | ||
603 | err = snd_opl3_timer_new(opl3, 1, 2); | ||
604 | if (err < 0) | ||
605 | goto error; | ||
606 | |||
607 | err = snd_opl3_hwdep_new(opl3, 0, 1, NULL); | ||
608 | if (err < 0) | ||
609 | goto error; | ||
610 | } | ||
611 | |||
612 | err = snd_card_register(card); | ||
613 | if (err < 0) | ||
614 | goto error; | ||
615 | |||
616 | dev_set_drvdata(dev, card); | ||
617 | return 0; | ||
618 | |||
619 | error: | ||
620 | snd_card_free(card); | ||
621 | return err; | ||
622 | } | ||
623 | |||
624 | static int __devexit snd_galaxy_remove(struct device *dev, unsigned int n) | ||
625 | { | ||
626 | snd_card_free(dev_get_drvdata(dev)); | ||
627 | dev_set_drvdata(dev, NULL); | ||
628 | return 0; | ||
629 | } | ||
630 | |||
631 | static struct isa_driver snd_galaxy_driver = { | ||
632 | .match = snd_galaxy_match, | ||
633 | .probe = snd_galaxy_probe, | ||
634 | .remove = __devexit_p(snd_galaxy_remove), | ||
635 | |||
636 | .driver = { | ||
637 | .name = DEV_NAME | ||
638 | } | ||
639 | }; | ||
640 | |||
641 | static int __init alsa_card_galaxy_init(void) | ||
642 | { | ||
643 | return isa_register_driver(&snd_galaxy_driver, SNDRV_CARDS); | ||
644 | } | ||
645 | |||
646 | static void __exit alsa_card_galaxy_exit(void) | ||
647 | { | ||
648 | isa_unregister_driver(&snd_galaxy_driver); | ||
649 | } | ||
650 | |||
651 | module_init(alsa_card_galaxy_init); | ||
652 | module_exit(alsa_card_galaxy_exit); | ||
diff --git a/sound/isa/gus/gusmax.c b/sound/isa/gus/gusmax.c index f26eac8d8110..3e4a58b72913 100644 --- a/sound/isa/gus/gusmax.c +++ b/sound/isa/gus/gusmax.c | |||
@@ -191,7 +191,7 @@ static int __devinit snd_gusmax_mixer(struct snd_wss *chip) | |||
191 | 191 | ||
192 | static void snd_gusmax_free(struct snd_card *card) | 192 | static void snd_gusmax_free(struct snd_card *card) |
193 | { | 193 | { |
194 | struct snd_gusmax *maxcard = (struct snd_gusmax *)card->private_data; | 194 | struct snd_gusmax *maxcard = card->private_data; |
195 | 195 | ||
196 | if (maxcard == NULL) | 196 | if (maxcard == NULL) |
197 | return; | 197 | return; |
@@ -219,7 +219,7 @@ static int __devinit snd_gusmax_probe(struct device *pdev, unsigned int dev) | |||
219 | if (err < 0) | 219 | if (err < 0) |
220 | return err; | 220 | return err; |
221 | card->private_free = snd_gusmax_free; | 221 | card->private_free = snd_gusmax_free; |
222 | maxcard = (struct snd_gusmax *)card->private_data; | 222 | maxcard = card->private_data; |
223 | maxcard->card = card; | 223 | maxcard->card = card; |
224 | maxcard->irq = -1; | 224 | maxcard->irq = -1; |
225 | 225 | ||
diff --git a/sound/isa/msnd/msnd_pinnacle.c b/sound/isa/msnd/msnd_pinnacle.c index 60b6abd71612..91d6023a63e5 100644 --- a/sound/isa/msnd/msnd_pinnacle.c +++ b/sound/isa/msnd/msnd_pinnacle.c | |||
@@ -549,7 +549,10 @@ static int __devinit snd_msnd_attach(struct snd_card *card) | |||
549 | printk(KERN_ERR LOGNAME ": Couldn't grab IRQ %d\n", chip->irq); | 549 | printk(KERN_ERR LOGNAME ": Couldn't grab IRQ %d\n", chip->irq); |
550 | return err; | 550 | return err; |
551 | } | 551 | } |
552 | request_region(chip->io, DSP_NUMIO, card->shortname); | 552 | if (request_region(chip->io, DSP_NUMIO, card->shortname) == NULL) { |
553 | free_irq(chip->irq, chip); | ||
554 | return -EBUSY; | ||
555 | } | ||
553 | 556 | ||
554 | if (!request_mem_region(chip->base, BUFFSIZE, card->shortname)) { | 557 | if (!request_mem_region(chip->base, BUFFSIZE, card->shortname)) { |
555 | printk(KERN_ERR LOGNAME | 558 | printk(KERN_ERR LOGNAME |
@@ -761,9 +764,9 @@ static long io[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; | |||
761 | static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; | 764 | static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; |
762 | static long mem[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; | 765 | static long mem[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; |
763 | 766 | ||
767 | #ifndef MSND_CLASSIC | ||
764 | static long cfg[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; | 768 | static long cfg[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; |
765 | 769 | ||
766 | #ifndef MSND_CLASSIC | ||
767 | /* Extra Peripheral Configuration (Default: Disable) */ | 770 | /* Extra Peripheral Configuration (Default: Disable) */ |
768 | static long ide_io0[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; | 771 | static long ide_io0[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; |
769 | static long ide_io1[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; | 772 | static long ide_io1[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; |
@@ -891,7 +894,11 @@ static int __devinit snd_msnd_isa_probe(struct device *pdev, unsigned int idx) | |||
891 | struct snd_card *card; | 894 | struct snd_card *card; |
892 | struct snd_msnd *chip; | 895 | struct snd_msnd *chip; |
893 | 896 | ||
894 | if (has_isapnp(idx) || cfg[idx] == SNDRV_AUTO_PORT) { | 897 | if (has_isapnp(idx) |
898 | #ifndef MSND_CLASSIC | ||
899 | || cfg[idx] == SNDRV_AUTO_PORT | ||
900 | #endif | ||
901 | ) { | ||
895 | printk(KERN_INFO LOGNAME ": Assuming PnP mode\n"); | 902 | printk(KERN_INFO LOGNAME ": Assuming PnP mode\n"); |
896 | return -ENODEV; | 903 | return -ENODEV; |
897 | } | 904 | } |
diff --git a/sound/isa/sb/emu8000_pcm.c b/sound/isa/sb/emu8000_pcm.c index ccedbfed061a..2f85c66f8e38 100644 --- a/sound/isa/sb/emu8000_pcm.c +++ b/sound/isa/sb/emu8000_pcm.c | |||
@@ -433,7 +433,8 @@ static int emu8k_transfer_block(struct snd_emu8000 *emu, int offset, unsigned sh | |||
433 | while (count > 0) { | 433 | while (count > 0) { |
434 | unsigned short sval; | 434 | unsigned short sval; |
435 | CHECK_SCHEDULER(); | 435 | CHECK_SCHEDULER(); |
436 | get_user(sval, buf); | 436 | if (get_user(sval, buf)) |
437 | return -EFAULT; | ||
437 | EMU8000_SMLD_WRITE(emu, sval); | 438 | EMU8000_SMLD_WRITE(emu, sval); |
438 | buf++; | 439 | buf++; |
439 | count--; | 440 | count--; |
@@ -525,12 +526,14 @@ static int emu8k_pcm_copy(struct snd_pcm_substream *subs, | |||
525 | while (count-- > 0) { | 526 | while (count-- > 0) { |
526 | unsigned short sval; | 527 | unsigned short sval; |
527 | CHECK_SCHEDULER(); | 528 | CHECK_SCHEDULER(); |
528 | get_user(sval, buf); | 529 | if (get_user(sval, buf)) |
530 | return -EFAULT; | ||
529 | EMU8000_SMLD_WRITE(emu, sval); | 531 | EMU8000_SMLD_WRITE(emu, sval); |
530 | buf++; | 532 | buf++; |
531 | if (rec->voices > 1) { | 533 | if (rec->voices > 1) { |
532 | CHECK_SCHEDULER(); | 534 | CHECK_SCHEDULER(); |
533 | get_user(sval, buf); | 535 | if (get_user(sval, buf)) |
536 | return -EFAULT; | ||
534 | EMU8000_SMRD_WRITE(emu, sval); | 537 | EMU8000_SMRD_WRITE(emu, sval); |
535 | buf++; | 538 | buf++; |
536 | } | 539 | } |
diff --git a/sound/isa/sb/sb8.c b/sound/isa/sb/sb8.c index 81284a8fa0ce..2259e3f726a7 100644 --- a/sound/isa/sb/sb8.c +++ b/sound/isa/sb/sb8.c | |||
@@ -72,7 +72,7 @@ static irqreturn_t snd_sb8_interrupt(int irq, void *dev_id) | |||
72 | 72 | ||
73 | static void snd_sb8_free(struct snd_card *card) | 73 | static void snd_sb8_free(struct snd_card *card) |
74 | { | 74 | { |
75 | struct snd_sb8 *acard = (struct snd_sb8 *)card->private_data; | 75 | struct snd_sb8 *acard = card->private_data; |
76 | 76 | ||
77 | if (acard == NULL) | 77 | if (acard == NULL) |
78 | return; | 78 | return; |
diff --git a/sound/isa/sgalaxy.c b/sound/isa/sgalaxy.c deleted file mode 100644 index 6fe27b9d9440..000000000000 --- a/sound/isa/sgalaxy.c +++ /dev/null | |||
@@ -1,369 +0,0 @@ | |||
1 | /* | ||
2 | * Driver for Aztech Sound Galaxy cards | ||
3 | * Copyright (c) by Christopher Butler <chrisb@sandy.force9.co.uk. | ||
4 | * | ||
5 | * I don't have documentation for this card, I based this driver on the | ||
6 | * driver for OSS/Free included in the kernel source (drivers/sound/sgalaxy.c) | ||
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 as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include <linux/init.h> | ||
25 | #include <linux/err.h> | ||
26 | #include <linux/isa.h> | ||
27 | #include <linux/delay.h> | ||
28 | #include <linux/time.h> | ||
29 | #include <linux/interrupt.h> | ||
30 | #include <linux/moduleparam.h> | ||
31 | #include <asm/dma.h> | ||
32 | #include <sound/core.h> | ||
33 | #include <sound/sb.h> | ||
34 | #include <sound/wss.h> | ||
35 | #include <sound/control.h> | ||
36 | #define SNDRV_LEGACY_FIND_FREE_IRQ | ||
37 | #define SNDRV_LEGACY_FIND_FREE_DMA | ||
38 | #include <sound/initval.h> | ||
39 | |||
40 | MODULE_AUTHOR("Christopher Butler <chrisb@sandy.force9.co.uk>"); | ||
41 | MODULE_DESCRIPTION("Aztech Sound Galaxy"); | ||
42 | MODULE_LICENSE("GPL"); | ||
43 | MODULE_SUPPORTED_DEVICE("{{Aztech Systems,Sound Galaxy}}"); | ||
44 | |||
45 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ | ||
46 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ | ||
47 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */ | ||
48 | static long sbport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x220,0x240 */ | ||
49 | static long wssport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x530,0xe80,0xf40,0x604 */ | ||
50 | static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 7,9,10,11 */ | ||
51 | static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0,1,3 */ | ||
52 | |||
53 | module_param_array(index, int, NULL, 0444); | ||
54 | MODULE_PARM_DESC(index, "Index value for Sound Galaxy soundcard."); | ||
55 | module_param_array(id, charp, NULL, 0444); | ||
56 | MODULE_PARM_DESC(id, "ID string for Sound Galaxy soundcard."); | ||
57 | module_param_array(sbport, long, NULL, 0444); | ||
58 | MODULE_PARM_DESC(sbport, "Port # for Sound Galaxy SB driver."); | ||
59 | module_param_array(wssport, long, NULL, 0444); | ||
60 | MODULE_PARM_DESC(wssport, "Port # for Sound Galaxy WSS driver."); | ||
61 | module_param_array(irq, int, NULL, 0444); | ||
62 | MODULE_PARM_DESC(irq, "IRQ # for Sound Galaxy driver."); | ||
63 | module_param_array(dma1, int, NULL, 0444); | ||
64 | MODULE_PARM_DESC(dma1, "DMA1 # for Sound Galaxy driver."); | ||
65 | |||
66 | #define SGALAXY_AUXC_LEFT 18 | ||
67 | #define SGALAXY_AUXC_RIGHT 19 | ||
68 | |||
69 | #define PFX "sgalaxy: " | ||
70 | |||
71 | /* | ||
72 | |||
73 | */ | ||
74 | |||
75 | #define AD1848P1( port, x ) ( port + c_d_c_AD1848##x ) | ||
76 | |||
77 | /* from lowlevel/sb/sb.c - to avoid having to allocate a struct snd_sb for the */ | ||
78 | /* short time we actually need it.. */ | ||
79 | |||
80 | static int snd_sgalaxy_sbdsp_reset(unsigned long port) | ||
81 | { | ||
82 | int i; | ||
83 | |||
84 | outb(1, SBP1(port, RESET)); | ||
85 | udelay(10); | ||
86 | outb(0, SBP1(port, RESET)); | ||
87 | udelay(30); | ||
88 | for (i = 0; i < 1000 && !(inb(SBP1(port, DATA_AVAIL)) & 0x80); i++); | ||
89 | if (inb(SBP1(port, READ)) != 0xaa) { | ||
90 | snd_printd("sb_reset: failed at 0x%lx!!!\n", port); | ||
91 | return -ENODEV; | ||
92 | } | ||
93 | return 0; | ||
94 | } | ||
95 | |||
96 | static int __devinit snd_sgalaxy_sbdsp_command(unsigned long port, | ||
97 | unsigned char val) | ||
98 | { | ||
99 | int i; | ||
100 | |||
101 | for (i = 10000; i; i--) | ||
102 | if ((inb(SBP1(port, STATUS)) & 0x80) == 0) { | ||
103 | outb(val, SBP1(port, COMMAND)); | ||
104 | return 1; | ||
105 | } | ||
106 | |||
107 | return 0; | ||
108 | } | ||
109 | |||
110 | static irqreturn_t snd_sgalaxy_dummy_interrupt(int irq, void *dev_id) | ||
111 | { | ||
112 | return IRQ_NONE; | ||
113 | } | ||
114 | |||
115 | static int __devinit snd_sgalaxy_setup_wss(unsigned long port, int irq, int dma) | ||
116 | { | ||
117 | static int interrupt_bits[] = {-1, -1, -1, -1, -1, -1, -1, 0x08, -1, | ||
118 | 0x10, 0x18, 0x20, -1, -1, -1, -1}; | ||
119 | static int dma_bits[] = {1, 2, 0, 3}; | ||
120 | int tmp, tmp1; | ||
121 | |||
122 | if ((tmp = inb(port + 3)) == 0xff) | ||
123 | { | ||
124 | snd_printdd("I/O address dead (0x%lx)\n", port); | ||
125 | return 0; | ||
126 | } | ||
127 | #if 0 | ||
128 | snd_printdd("WSS signature = 0x%x\n", tmp); | ||
129 | #endif | ||
130 | |||
131 | if ((tmp & 0x3f) != 0x04 && | ||
132 | (tmp & 0x3f) != 0x0f && | ||
133 | (tmp & 0x3f) != 0x00) { | ||
134 | snd_printdd("No WSS signature detected on port 0x%lx\n", | ||
135 | port + 3); | ||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | #if 0 | ||
140 | snd_printdd(PFX "setting up IRQ/DMA for WSS\n"); | ||
141 | #endif | ||
142 | |||
143 | /* initialize IRQ for WSS codec */ | ||
144 | tmp = interrupt_bits[irq % 16]; | ||
145 | if (tmp < 0) | ||
146 | return -EINVAL; | ||
147 | |||
148 | if (request_irq(irq, snd_sgalaxy_dummy_interrupt, IRQF_DISABLED, "sgalaxy", NULL)) { | ||
149 | snd_printk(KERN_ERR "sgalaxy: can't grab irq %d\n", irq); | ||
150 | return -EIO; | ||
151 | } | ||
152 | |||
153 | outb(tmp | 0x40, port); | ||
154 | tmp1 = dma_bits[dma % 4]; | ||
155 | outb(tmp | tmp1, port); | ||
156 | |||
157 | free_irq(irq, NULL); | ||
158 | |||
159 | return 0; | ||
160 | } | ||
161 | |||
162 | static int __devinit snd_sgalaxy_detect(int dev, int irq, int dma) | ||
163 | { | ||
164 | #if 0 | ||
165 | snd_printdd(PFX "switching to WSS mode\n"); | ||
166 | #endif | ||
167 | |||
168 | /* switch to WSS mode */ | ||
169 | snd_sgalaxy_sbdsp_reset(sbport[dev]); | ||
170 | |||
171 | snd_sgalaxy_sbdsp_command(sbport[dev], 9); | ||
172 | snd_sgalaxy_sbdsp_command(sbport[dev], 0); | ||
173 | |||
174 | udelay(400); | ||
175 | return snd_sgalaxy_setup_wss(wssport[dev], irq, dma); | ||
176 | } | ||
177 | |||
178 | static struct snd_kcontrol_new snd_sgalaxy_controls[] = { | ||
179 | WSS_DOUBLE("Aux Playback Switch", 0, | ||
180 | SGALAXY_AUXC_LEFT, SGALAXY_AUXC_RIGHT, 7, 7, 1, 1), | ||
181 | WSS_DOUBLE("Aux Playback Volume", 0, | ||
182 | SGALAXY_AUXC_LEFT, SGALAXY_AUXC_RIGHT, 0, 0, 31, 0) | ||
183 | }; | ||
184 | |||
185 | static int __devinit snd_sgalaxy_mixer(struct snd_wss *chip) | ||
186 | { | ||
187 | struct snd_card *card = chip->card; | ||
188 | struct snd_ctl_elem_id id1, id2; | ||
189 | unsigned int idx; | ||
190 | int err; | ||
191 | |||
192 | memset(&id1, 0, sizeof(id1)); | ||
193 | memset(&id2, 0, sizeof(id2)); | ||
194 | id1.iface = id2.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
195 | /* reassign AUX0 to LINE */ | ||
196 | strcpy(id1.name, "Aux Playback Switch"); | ||
197 | strcpy(id2.name, "Line Playback Switch"); | ||
198 | if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0) | ||
199 | return err; | ||
200 | strcpy(id1.name, "Aux Playback Volume"); | ||
201 | strcpy(id2.name, "Line Playback Volume"); | ||
202 | if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0) | ||
203 | return err; | ||
204 | /* reassign AUX1 to FM */ | ||
205 | strcpy(id1.name, "Aux Playback Switch"); id1.index = 1; | ||
206 | strcpy(id2.name, "FM Playback Switch"); | ||
207 | if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0) | ||
208 | return err; | ||
209 | strcpy(id1.name, "Aux Playback Volume"); | ||
210 | strcpy(id2.name, "FM Playback Volume"); | ||
211 | if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0) | ||
212 | return err; | ||
213 | /* build AUX2 input */ | ||
214 | for (idx = 0; idx < ARRAY_SIZE(snd_sgalaxy_controls); idx++) { | ||
215 | err = snd_ctl_add(card, | ||
216 | snd_ctl_new1(&snd_sgalaxy_controls[idx], chip)); | ||
217 | if (err < 0) | ||
218 | return err; | ||
219 | } | ||
220 | return 0; | ||
221 | } | ||
222 | |||
223 | static int __devinit snd_sgalaxy_match(struct device *devptr, unsigned int dev) | ||
224 | { | ||
225 | if (!enable[dev]) | ||
226 | return 0; | ||
227 | if (sbport[dev] == SNDRV_AUTO_PORT) { | ||
228 | snd_printk(KERN_ERR PFX "specify SB port\n"); | ||
229 | return 0; | ||
230 | } | ||
231 | if (wssport[dev] == SNDRV_AUTO_PORT) { | ||
232 | snd_printk(KERN_ERR PFX "specify WSS port\n"); | ||
233 | return 0; | ||
234 | } | ||
235 | return 1; | ||
236 | } | ||
237 | |||
238 | static int __devinit snd_sgalaxy_probe(struct device *devptr, unsigned int dev) | ||
239 | { | ||
240 | static int possible_irqs[] = {7, 9, 10, 11, -1}; | ||
241 | static int possible_dmas[] = {1, 3, 0, -1}; | ||
242 | int err, xirq, xdma1; | ||
243 | struct snd_card *card; | ||
244 | struct snd_wss *chip; | ||
245 | |||
246 | err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); | ||
247 | if (err < 0) | ||
248 | return err; | ||
249 | |||
250 | xirq = irq[dev]; | ||
251 | if (xirq == SNDRV_AUTO_IRQ) { | ||
252 | if ((xirq = snd_legacy_find_free_irq(possible_irqs)) < 0) { | ||
253 | snd_printk(KERN_ERR PFX "unable to find a free IRQ\n"); | ||
254 | err = -EBUSY; | ||
255 | goto _err; | ||
256 | } | ||
257 | } | ||
258 | xdma1 = dma1[dev]; | ||
259 | if (xdma1 == SNDRV_AUTO_DMA) { | ||
260 | if ((xdma1 = snd_legacy_find_free_dma(possible_dmas)) < 0) { | ||
261 | snd_printk(KERN_ERR PFX "unable to find a free DMA\n"); | ||
262 | err = -EBUSY; | ||
263 | goto _err; | ||
264 | } | ||
265 | } | ||
266 | |||
267 | if ((err = snd_sgalaxy_detect(dev, xirq, xdma1)) < 0) | ||
268 | goto _err; | ||
269 | |||
270 | err = snd_wss_create(card, wssport[dev] + 4, -1, | ||
271 | xirq, xdma1, -1, | ||
272 | WSS_HW_DETECT, 0, &chip); | ||
273 | if (err < 0) | ||
274 | goto _err; | ||
275 | card->private_data = chip; | ||
276 | |||
277 | err = snd_wss_pcm(chip, 0, NULL); | ||
278 | if (err < 0) { | ||
279 | snd_printdd(PFX "error creating new WSS PCM device\n"); | ||
280 | goto _err; | ||
281 | } | ||
282 | err = snd_wss_mixer(chip); | ||
283 | if (err < 0) { | ||
284 | snd_printdd(PFX "error creating new WSS mixer\n"); | ||
285 | goto _err; | ||
286 | } | ||
287 | if ((err = snd_sgalaxy_mixer(chip)) < 0) { | ||
288 | snd_printdd(PFX "the mixer rewrite failed\n"); | ||
289 | goto _err; | ||
290 | } | ||
291 | |||
292 | strcpy(card->driver, "Sound Galaxy"); | ||
293 | strcpy(card->shortname, "Sound Galaxy"); | ||
294 | sprintf(card->longname, "Sound Galaxy at 0x%lx, irq %d, dma %d", | ||
295 | wssport[dev], xirq, xdma1); | ||
296 | |||
297 | snd_card_set_dev(card, devptr); | ||
298 | |||
299 | if ((err = snd_card_register(card)) < 0) | ||
300 | goto _err; | ||
301 | |||
302 | dev_set_drvdata(devptr, card); | ||
303 | return 0; | ||
304 | |||
305 | _err: | ||
306 | snd_card_free(card); | ||
307 | return err; | ||
308 | } | ||
309 | |||
310 | static int __devexit snd_sgalaxy_remove(struct device *devptr, unsigned int dev) | ||
311 | { | ||
312 | snd_card_free(dev_get_drvdata(devptr)); | ||
313 | dev_set_drvdata(devptr, NULL); | ||
314 | return 0; | ||
315 | } | ||
316 | |||
317 | #ifdef CONFIG_PM | ||
318 | static int snd_sgalaxy_suspend(struct device *pdev, unsigned int n, | ||
319 | pm_message_t state) | ||
320 | { | ||
321 | struct snd_card *card = dev_get_drvdata(pdev); | ||
322 | struct snd_wss *chip = card->private_data; | ||
323 | |||
324 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); | ||
325 | chip->suspend(chip); | ||
326 | return 0; | ||
327 | } | ||
328 | |||
329 | static int snd_sgalaxy_resume(struct device *pdev, unsigned int n) | ||
330 | { | ||
331 | struct snd_card *card = dev_get_drvdata(pdev); | ||
332 | struct snd_wss *chip = card->private_data; | ||
333 | |||
334 | chip->resume(chip); | ||
335 | snd_wss_out(chip, SGALAXY_AUXC_LEFT, chip->image[SGALAXY_AUXC_LEFT]); | ||
336 | snd_wss_out(chip, SGALAXY_AUXC_RIGHT, chip->image[SGALAXY_AUXC_RIGHT]); | ||
337 | |||
338 | snd_power_change_state(card, SNDRV_CTL_POWER_D0); | ||
339 | return 0; | ||
340 | } | ||
341 | #endif | ||
342 | |||
343 | #define DEV_NAME "sgalaxy" | ||
344 | |||
345 | static struct isa_driver snd_sgalaxy_driver = { | ||
346 | .match = snd_sgalaxy_match, | ||
347 | .probe = snd_sgalaxy_probe, | ||
348 | .remove = __devexit_p(snd_sgalaxy_remove), | ||
349 | #ifdef CONFIG_PM | ||
350 | .suspend = snd_sgalaxy_suspend, | ||
351 | .resume = snd_sgalaxy_resume, | ||
352 | #endif | ||
353 | .driver = { | ||
354 | .name = DEV_NAME | ||
355 | }, | ||
356 | }; | ||
357 | |||
358 | static int __init alsa_card_sgalaxy_init(void) | ||
359 | { | ||
360 | return isa_register_driver(&snd_sgalaxy_driver, SNDRV_CARDS); | ||
361 | } | ||
362 | |||
363 | static void __exit alsa_card_sgalaxy_exit(void) | ||
364 | { | ||
365 | isa_unregister_driver(&snd_sgalaxy_driver); | ||
366 | } | ||
367 | |||
368 | module_init(alsa_card_sgalaxy_init) | ||
369 | module_exit(alsa_card_sgalaxy_exit) | ||
diff --git a/sound/oss/Kconfig b/sound/oss/Kconfig index a513651fa149..76c090218073 100644 --- a/sound/oss/Kconfig +++ b/sound/oss/Kconfig | |||
@@ -545,11 +545,3 @@ config SOUND_KAHLUA | |||
545 | 545 | ||
546 | endif # SOUND_OSS | 546 | endif # SOUND_OSS |
547 | 547 | ||
548 | config SOUND_SH_DAC_AUDIO | ||
549 | tristate "SuperH DAC audio support" | ||
550 | depends on CPU_SH3 && HIGH_RES_TIMERS | ||
551 | |||
552 | config SOUND_SH_DAC_AUDIO_CHANNEL | ||
553 | int "DAC channel" | ||
554 | default "1" | ||
555 | depends on SOUND_SH_DAC_AUDIO | ||
diff --git a/sound/oss/Makefile b/sound/oss/Makefile index 567b8a74178a..96f14dcd0cd1 100644 --- a/sound/oss/Makefile +++ b/sound/oss/Makefile | |||
@@ -9,7 +9,6 @@ obj-$(CONFIG_SOUND_OSS) += sound.o | |||
9 | 9 | ||
10 | # Please leave it as is, cause the link order is significant ! | 10 | # Please leave it as is, cause the link order is significant ! |
11 | 11 | ||
12 | obj-$(CONFIG_SOUND_SH_DAC_AUDIO) += sh_dac_audio.o | ||
13 | obj-$(CONFIG_SOUND_AEDSP16) += aedsp16.o | 12 | obj-$(CONFIG_SOUND_AEDSP16) += aedsp16.o |
14 | obj-$(CONFIG_SOUND_PSS) += pss.o ad1848.o mpu401.o | 13 | obj-$(CONFIG_SOUND_PSS) += pss.o ad1848.o mpu401.o |
15 | obj-$(CONFIG_SOUND_TRIX) += trix.o ad1848.o sb_lib.o uart401.o | 14 | obj-$(CONFIG_SOUND_TRIX) += trix.o ad1848.o sb_lib.o uart401.o |
diff --git a/sound/oss/ad1848.c b/sound/oss/ad1848.c index 24793c5b65ac..4d2a6ae978f7 100644 --- a/sound/oss/ad1848.c +++ b/sound/oss/ad1848.c | |||
@@ -716,7 +716,7 @@ static int ad1848_mixer_ioctl(int dev, unsigned int cmd, void __user *arg) | |||
716 | 716 | ||
717 | default: | 717 | default: |
718 | if (get_user(val, (int __user *)arg)) | 718 | if (get_user(val, (int __user *)arg)) |
719 | return -EFAULT; | 719 | return -EFAULT; |
720 | val = ad1848_mixer_set(devc, cmd & 0xff, val); | 720 | val = ad1848_mixer_set(devc, cmd & 0xff, val); |
721 | break; | 721 | break; |
722 | } | 722 | } |
diff --git a/sound/oss/au1550_ac97.c b/sound/oss/au1550_ac97.c index c1070e33b32f..a8f626d99c5b 100644 --- a/sound/oss/au1550_ac97.c +++ b/sound/oss/au1550_ac97.c | |||
@@ -49,7 +49,6 @@ | |||
49 | #include <linux/poll.h> | 49 | #include <linux/poll.h> |
50 | #include <linux/bitops.h> | 50 | #include <linux/bitops.h> |
51 | #include <linux/spinlock.h> | 51 | #include <linux/spinlock.h> |
52 | #include <linux/smp_lock.h> | ||
53 | #include <linux/ac97_codec.h> | 52 | #include <linux/ac97_codec.h> |
54 | #include <linux/mutex.h> | 53 | #include <linux/mutex.h> |
55 | 54 | ||
@@ -77,6 +76,7 @@ | |||
77 | /* Boot options | 76 | /* Boot options |
78 | * 0 = no VRA, 1 = use VRA if codec supports it | 77 | * 0 = no VRA, 1 = use VRA if codec supports it |
79 | */ | 78 | */ |
79 | static DEFINE_MUTEX(au1550_ac97_mutex); | ||
80 | static int vra = 1; | 80 | static int vra = 1; |
81 | module_param(vra, bool, 0); | 81 | module_param(vra, bool, 0); |
82 | MODULE_PARM_DESC(vra, "if 1 use VRA if codec supports it"); | 82 | MODULE_PARM_DESC(vra, "if 1 use VRA if codec supports it"); |
@@ -162,25 +162,16 @@ ld2(unsigned int x) | |||
162 | static void | 162 | static void |
163 | au1550_delay(int msec) | 163 | au1550_delay(int msec) |
164 | { | 164 | { |
165 | unsigned long tmo; | ||
166 | signed long tmo2; | ||
167 | |||
168 | if (in_interrupt()) | 165 | if (in_interrupt()) |
169 | return; | 166 | return; |
170 | 167 | ||
171 | tmo = jiffies + (msec * HZ) / 1000; | 168 | schedule_timeout_uninterruptible(msecs_to_jiffies(msec)); |
172 | for (;;) { | ||
173 | tmo2 = tmo - jiffies; | ||
174 | if (tmo2 <= 0) | ||
175 | break; | ||
176 | schedule_timeout(tmo2); | ||
177 | } | ||
178 | } | 169 | } |
179 | 170 | ||
180 | static u16 | 171 | static u16 |
181 | rdcodec(struct ac97_codec *codec, u8 addr) | 172 | rdcodec(struct ac97_codec *codec, u8 addr) |
182 | { | 173 | { |
183 | struct au1550_state *s = (struct au1550_state *)codec->private_data; | 174 | struct au1550_state *s = codec->private_data; |
184 | unsigned long flags; | 175 | unsigned long flags; |
185 | u32 cmd, val; | 176 | u32 cmd, val; |
186 | u16 data; | 177 | u16 data; |
@@ -248,7 +239,7 @@ rdcodec(struct ac97_codec *codec, u8 addr) | |||
248 | static void | 239 | static void |
249 | wrcodec(struct ac97_codec *codec, u8 addr, u16 data) | 240 | wrcodec(struct ac97_codec *codec, u8 addr, u16 data) |
250 | { | 241 | { |
251 | struct au1550_state *s = (struct au1550_state *)codec->private_data; | 242 | struct au1550_state *s = codec->private_data; |
252 | unsigned long flags; | 243 | unsigned long flags; |
253 | u32 cmd, val; | 244 | u32 cmd, val; |
254 | int i; | 245 | int i; |
@@ -807,7 +798,9 @@ au1550_llseek(struct file *file, loff_t offset, int origin) | |||
807 | static int | 798 | static int |
808 | au1550_open_mixdev(struct inode *inode, struct file *file) | 799 | au1550_open_mixdev(struct inode *inode, struct file *file) |
809 | { | 800 | { |
801 | mutex_lock(&au1550_ac97_mutex); | ||
810 | file->private_data = &au1550_state; | 802 | file->private_data = &au1550_state; |
803 | mutex_unlock(&au1550_ac97_mutex); | ||
811 | return 0; | 804 | return 0; |
812 | } | 805 | } |
813 | 806 | ||
@@ -824,22 +817,26 @@ mixdev_ioctl(struct ac97_codec *codec, unsigned int cmd, | |||
824 | return codec->mixer_ioctl(codec, cmd, arg); | 817 | return codec->mixer_ioctl(codec, cmd, arg); |
825 | } | 818 | } |
826 | 819 | ||
827 | static int | 820 | static long |
828 | au1550_ioctl_mixdev(struct inode *inode, struct file *file, | 821 | au1550_ioctl_mixdev(struct file *file, unsigned int cmd, unsigned long arg) |
829 | unsigned int cmd, unsigned long arg) | ||
830 | { | 822 | { |
831 | struct au1550_state *s = (struct au1550_state *)file->private_data; | 823 | struct au1550_state *s = file->private_data; |
832 | struct ac97_codec *codec = s->codec; | 824 | struct ac97_codec *codec = s->codec; |
825 | int ret; | ||
826 | |||
827 | mutex_lock(&au1550_ac97_mutex); | ||
828 | ret = mixdev_ioctl(codec, cmd, arg); | ||
829 | mutex_unlock(&au1550_ac97_mutex); | ||
833 | 830 | ||
834 | return mixdev_ioctl(codec, cmd, arg); | 831 | return ret; |
835 | } | 832 | } |
836 | 833 | ||
837 | static /*const */ struct file_operations au1550_mixer_fops = { | 834 | static /*const */ struct file_operations au1550_mixer_fops = { |
838 | owner:THIS_MODULE, | 835 | .owner = THIS_MODULE, |
839 | llseek:au1550_llseek, | 836 | .llseek = au1550_llseek, |
840 | ioctl:au1550_ioctl_mixdev, | 837 | .unlocked_ioctl = au1550_ioctl_mixdev, |
841 | open:au1550_open_mixdev, | 838 | .open = au1550_open_mixdev, |
842 | release:au1550_release_mixdev, | 839 | .release = au1550_release_mixdev, |
843 | }; | 840 | }; |
844 | 841 | ||
845 | static int | 842 | static int |
@@ -1034,7 +1031,7 @@ copy_dmabuf_user(struct dmabuf *db, char* userbuf, int count, int to_user) | |||
1034 | static ssize_t | 1031 | static ssize_t |
1035 | au1550_read(struct file *file, char *buffer, size_t count, loff_t *ppos) | 1032 | au1550_read(struct file *file, char *buffer, size_t count, loff_t *ppos) |
1036 | { | 1033 | { |
1037 | struct au1550_state *s = (struct au1550_state *)file->private_data; | 1034 | struct au1550_state *s = file->private_data; |
1038 | struct dmabuf *db = &s->dma_adc; | 1035 | struct dmabuf *db = &s->dma_adc; |
1039 | DECLARE_WAITQUEUE(wait, current); | 1036 | DECLARE_WAITQUEUE(wait, current); |
1040 | ssize_t ret; | 1037 | ssize_t ret; |
@@ -1114,7 +1111,7 @@ out2: | |||
1114 | static ssize_t | 1111 | static ssize_t |
1115 | au1550_write(struct file *file, const char *buffer, size_t count, loff_t * ppos) | 1112 | au1550_write(struct file *file, const char *buffer, size_t count, loff_t * ppos) |
1116 | { | 1113 | { |
1117 | struct au1550_state *s = (struct au1550_state *)file->private_data; | 1114 | struct au1550_state *s = file->private_data; |
1118 | struct dmabuf *db = &s->dma_dac; | 1115 | struct dmabuf *db = &s->dma_dac; |
1119 | DECLARE_WAITQUEUE(wait, current); | 1116 | DECLARE_WAITQUEUE(wait, current); |
1120 | ssize_t ret = 0; | 1117 | ssize_t ret = 0; |
@@ -1214,7 +1211,7 @@ out2: | |||
1214 | static unsigned int | 1211 | static unsigned int |
1215 | au1550_poll(struct file *file, struct poll_table_struct *wait) | 1212 | au1550_poll(struct file *file, struct poll_table_struct *wait) |
1216 | { | 1213 | { |
1217 | struct au1550_state *s = (struct au1550_state *)file->private_data; | 1214 | struct au1550_state *s = file->private_data; |
1218 | unsigned long flags; | 1215 | unsigned long flags; |
1219 | unsigned int mask = 0; | 1216 | unsigned int mask = 0; |
1220 | 1217 | ||
@@ -1253,12 +1250,12 @@ au1550_poll(struct file *file, struct poll_table_struct *wait) | |||
1253 | static int | 1250 | static int |
1254 | au1550_mmap(struct file *file, struct vm_area_struct *vma) | 1251 | au1550_mmap(struct file *file, struct vm_area_struct *vma) |
1255 | { | 1252 | { |
1256 | struct au1550_state *s = (struct au1550_state *)file->private_data; | 1253 | struct au1550_state *s = file->private_data; |
1257 | struct dmabuf *db; | 1254 | struct dmabuf *db; |
1258 | unsigned long size; | 1255 | unsigned long size; |
1259 | int ret = 0; | 1256 | int ret = 0; |
1260 | 1257 | ||
1261 | lock_kernel(); | 1258 | mutex_lock(&au1550_ac97_mutex); |
1262 | mutex_lock(&s->sem); | 1259 | mutex_lock(&s->sem); |
1263 | if (vma->vm_flags & VM_WRITE) | 1260 | if (vma->vm_flags & VM_WRITE) |
1264 | db = &s->dma_dac; | 1261 | db = &s->dma_dac; |
@@ -1286,7 +1283,7 @@ au1550_mmap(struct file *file, struct vm_area_struct *vma) | |||
1286 | db->mapped = 1; | 1283 | db->mapped = 1; |
1287 | out: | 1284 | out: |
1288 | mutex_unlock(&s->sem); | 1285 | mutex_unlock(&s->sem); |
1289 | unlock_kernel(); | 1286 | mutex_unlock(&au1550_ac97_mutex); |
1290 | return ret; | 1287 | return ret; |
1291 | } | 1288 | } |
1292 | 1289 | ||
@@ -1343,10 +1340,9 @@ dma_count_done(struct dmabuf *db) | |||
1343 | 1340 | ||
1344 | 1341 | ||
1345 | static int | 1342 | static int |
1346 | au1550_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | 1343 | au1550_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
1347 | unsigned long arg) | ||
1348 | { | 1344 | { |
1349 | struct au1550_state *s = (struct au1550_state *)file->private_data; | 1345 | struct au1550_state *s = file->private_data; |
1350 | unsigned long flags; | 1346 | unsigned long flags; |
1351 | audio_buf_info abinfo; | 1347 | audio_buf_info abinfo; |
1352 | count_info cinfo; | 1348 | count_info cinfo; |
@@ -1780,6 +1776,17 @@ au1550_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | |||
1780 | return mixdev_ioctl(s->codec, cmd, arg); | 1776 | return mixdev_ioctl(s->codec, cmd, arg); |
1781 | } | 1777 | } |
1782 | 1778 | ||
1779 | static long | ||
1780 | au1550_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | ||
1781 | { | ||
1782 | int ret; | ||
1783 | |||
1784 | mutex_lock(&au1550_ac97_mutex); | ||
1785 | ret = au1550_ioctl(file, cmd, arg); | ||
1786 | mutex_unlock(&au1550_ac97_mutex); | ||
1787 | |||
1788 | return ret; | ||
1789 | } | ||
1783 | 1790 | ||
1784 | static int | 1791 | static int |
1785 | au1550_open(struct inode *inode, struct file *file) | 1792 | au1550_open(struct inode *inode, struct file *file) |
@@ -1797,21 +1804,22 @@ au1550_open(struct inode *inode, struct file *file) | |||
1797 | #endif | 1804 | #endif |
1798 | 1805 | ||
1799 | file->private_data = s; | 1806 | file->private_data = s; |
1807 | mutex_lock(&au1550_ac97_mutex); | ||
1800 | /* wait for device to become free */ | 1808 | /* wait for device to become free */ |
1801 | mutex_lock(&s->open_mutex); | 1809 | mutex_lock(&s->open_mutex); |
1802 | while (s->open_mode & file->f_mode) { | 1810 | while (s->open_mode & file->f_mode) { |
1803 | if (file->f_flags & O_NONBLOCK) { | 1811 | ret = -EBUSY; |
1804 | mutex_unlock(&s->open_mutex); | 1812 | if (file->f_flags & O_NONBLOCK) |
1805 | return -EBUSY; | 1813 | goto out; |
1806 | } | ||
1807 | add_wait_queue(&s->open_wait, &wait); | 1814 | add_wait_queue(&s->open_wait, &wait); |
1808 | __set_current_state(TASK_INTERRUPTIBLE); | 1815 | __set_current_state(TASK_INTERRUPTIBLE); |
1809 | mutex_unlock(&s->open_mutex); | 1816 | mutex_unlock(&s->open_mutex); |
1810 | schedule(); | 1817 | schedule(); |
1811 | remove_wait_queue(&s->open_wait, &wait); | 1818 | remove_wait_queue(&s->open_wait, &wait); |
1812 | set_current_state(TASK_RUNNING); | 1819 | set_current_state(TASK_RUNNING); |
1820 | ret = -ERESTARTSYS; | ||
1813 | if (signal_pending(current)) | 1821 | if (signal_pending(current)) |
1814 | return -ERESTARTSYS; | 1822 | goto out2; |
1815 | mutex_lock(&s->open_mutex); | 1823 | mutex_lock(&s->open_mutex); |
1816 | } | 1824 | } |
1817 | 1825 | ||
@@ -1840,30 +1848,34 @@ au1550_open(struct inode *inode, struct file *file) | |||
1840 | 1848 | ||
1841 | if (file->f_mode & FMODE_READ) { | 1849 | if (file->f_mode & FMODE_READ) { |
1842 | if ((ret = prog_dmabuf_adc(s))) | 1850 | if ((ret = prog_dmabuf_adc(s))) |
1843 | return ret; | 1851 | goto out; |
1844 | } | 1852 | } |
1845 | if (file->f_mode & FMODE_WRITE) { | 1853 | if (file->f_mode & FMODE_WRITE) { |
1846 | if ((ret = prog_dmabuf_dac(s))) | 1854 | if ((ret = prog_dmabuf_dac(s))) |
1847 | return ret; | 1855 | goto out; |
1848 | } | 1856 | } |
1849 | 1857 | ||
1850 | s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); | 1858 | s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); |
1851 | mutex_unlock(&s->open_mutex); | ||
1852 | mutex_init(&s->sem); | 1859 | mutex_init(&s->sem); |
1853 | return 0; | 1860 | ret = 0; |
1861 | out: | ||
1862 | mutex_unlock(&s->open_mutex); | ||
1863 | out2: | ||
1864 | mutex_unlock(&au1550_ac97_mutex); | ||
1865 | return ret; | ||
1854 | } | 1866 | } |
1855 | 1867 | ||
1856 | static int | 1868 | static int |
1857 | au1550_release(struct inode *inode, struct file *file) | 1869 | au1550_release(struct inode *inode, struct file *file) |
1858 | { | 1870 | { |
1859 | struct au1550_state *s = (struct au1550_state *)file->private_data; | 1871 | struct au1550_state *s = file->private_data; |
1860 | 1872 | ||
1861 | lock_kernel(); | 1873 | mutex_lock(&au1550_ac97_mutex); |
1862 | 1874 | ||
1863 | if (file->f_mode & FMODE_WRITE) { | 1875 | if (file->f_mode & FMODE_WRITE) { |
1864 | unlock_kernel(); | 1876 | mutex_unlock(&au1550_ac97_mutex); |
1865 | drain_dac(s, file->f_flags & O_NONBLOCK); | 1877 | drain_dac(s, file->f_flags & O_NONBLOCK); |
1866 | lock_kernel(); | 1878 | mutex_lock(&au1550_ac97_mutex); |
1867 | } | 1879 | } |
1868 | 1880 | ||
1869 | mutex_lock(&s->open_mutex); | 1881 | mutex_lock(&s->open_mutex); |
@@ -1880,20 +1892,20 @@ au1550_release(struct inode *inode, struct file *file) | |||
1880 | s->open_mode &= ((~file->f_mode) & (FMODE_READ|FMODE_WRITE)); | 1892 | s->open_mode &= ((~file->f_mode) & (FMODE_READ|FMODE_WRITE)); |
1881 | mutex_unlock(&s->open_mutex); | 1893 | mutex_unlock(&s->open_mutex); |
1882 | wake_up(&s->open_wait); | 1894 | wake_up(&s->open_wait); |
1883 | unlock_kernel(); | 1895 | mutex_unlock(&au1550_ac97_mutex); |
1884 | return 0; | 1896 | return 0; |
1885 | } | 1897 | } |
1886 | 1898 | ||
1887 | static /*const */ struct file_operations au1550_audio_fops = { | 1899 | static /*const */ struct file_operations au1550_audio_fops = { |
1888 | owner: THIS_MODULE, | 1900 | .owner = THIS_MODULE, |
1889 | llseek: au1550_llseek, | 1901 | .llseek = au1550_llseek, |
1890 | read: au1550_read, | 1902 | .read = au1550_read, |
1891 | write: au1550_write, | 1903 | .write = au1550_write, |
1892 | poll: au1550_poll, | 1904 | .poll = au1550_poll, |
1893 | ioctl: au1550_ioctl, | 1905 | .unlocked_ioctl = au1550_unlocked_ioctl, |
1894 | mmap: au1550_mmap, | 1906 | .mmap = au1550_mmap, |
1895 | open: au1550_open, | 1907 | .open = au1550_open, |
1896 | release: au1550_release, | 1908 | .release = au1550_release, |
1897 | }; | 1909 | }; |
1898 | 1910 | ||
1899 | MODULE_AUTHOR("Advanced Micro Devices (AMD), dan@embeddededge.com"); | 1911 | MODULE_AUTHOR("Advanced Micro Devices (AMD), dan@embeddededge.com"); |
diff --git a/sound/oss/dmasound/dmasound_core.c b/sound/oss/dmasound/dmasound_core.c index 3f3c3f71db4b..87e2c72651f5 100644 --- a/sound/oss/dmasound/dmasound_core.c +++ b/sound/oss/dmasound/dmasound_core.c | |||
@@ -181,7 +181,7 @@ | |||
181 | #include <linux/init.h> | 181 | #include <linux/init.h> |
182 | #include <linux/soundcard.h> | 182 | #include <linux/soundcard.h> |
183 | #include <linux/poll.h> | 183 | #include <linux/poll.h> |
184 | #include <linux/smp_lock.h> | 184 | #include <linux/mutex.h> |
185 | 185 | ||
186 | #include <asm/uaccess.h> | 186 | #include <asm/uaccess.h> |
187 | 187 | ||
@@ -194,6 +194,7 @@ | |||
194 | * Declarations | 194 | * Declarations |
195 | */ | 195 | */ |
196 | 196 | ||
197 | static DEFINE_MUTEX(dmasound_core_mutex); | ||
197 | int dmasound_catchRadius = 0; | 198 | int dmasound_catchRadius = 0; |
198 | module_param(dmasound_catchRadius, int, 0); | 199 | module_param(dmasound_catchRadius, int, 0); |
199 | 200 | ||
@@ -323,22 +324,26 @@ static struct { | |||
323 | 324 | ||
324 | static int mixer_open(struct inode *inode, struct file *file) | 325 | static int mixer_open(struct inode *inode, struct file *file) |
325 | { | 326 | { |
326 | if (!try_module_get(dmasound.mach.owner)) | 327 | mutex_lock(&dmasound_core_mutex); |
328 | if (!try_module_get(dmasound.mach.owner)) { | ||
329 | mutex_unlock(&dmasound_core_mutex); | ||
327 | return -ENODEV; | 330 | return -ENODEV; |
331 | } | ||
328 | mixer.busy = 1; | 332 | mixer.busy = 1; |
333 | mutex_unlock(&dmasound_core_mutex); | ||
329 | return 0; | 334 | return 0; |
330 | } | 335 | } |
331 | 336 | ||
332 | static int mixer_release(struct inode *inode, struct file *file) | 337 | static int mixer_release(struct inode *inode, struct file *file) |
333 | { | 338 | { |
334 | lock_kernel(); | 339 | mutex_lock(&dmasound_core_mutex); |
335 | mixer.busy = 0; | 340 | mixer.busy = 0; |
336 | module_put(dmasound.mach.owner); | 341 | module_put(dmasound.mach.owner); |
337 | unlock_kernel(); | 342 | mutex_unlock(&dmasound_core_mutex); |
338 | return 0; | 343 | return 0; |
339 | } | 344 | } |
340 | static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd, | 345 | |
341 | u_long arg) | 346 | static int mixer_ioctl(struct file *file, u_int cmd, u_long arg) |
342 | { | 347 | { |
343 | if (_SIOC_DIR(cmd) & _SIOC_WRITE) | 348 | if (_SIOC_DIR(cmd) & _SIOC_WRITE) |
344 | mixer.modify_counter++; | 349 | mixer.modify_counter++; |
@@ -362,11 +367,22 @@ static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd, | |||
362 | return -EINVAL; | 367 | return -EINVAL; |
363 | } | 368 | } |
364 | 369 | ||
370 | static long mixer_unlocked_ioctl(struct file *file, u_int cmd, u_long arg) | ||
371 | { | ||
372 | int ret; | ||
373 | |||
374 | mutex_lock(&dmasound_core_mutex); | ||
375 | ret = mixer_ioctl(file, cmd, arg); | ||
376 | mutex_unlock(&dmasound_core_mutex); | ||
377 | |||
378 | return ret; | ||
379 | } | ||
380 | |||
365 | static const struct file_operations mixer_fops = | 381 | static const struct file_operations mixer_fops = |
366 | { | 382 | { |
367 | .owner = THIS_MODULE, | 383 | .owner = THIS_MODULE, |
368 | .llseek = no_llseek, | 384 | .llseek = no_llseek, |
369 | .ioctl = mixer_ioctl, | 385 | .unlocked_ioctl = mixer_unlocked_ioctl, |
370 | .open = mixer_open, | 386 | .open = mixer_open, |
371 | .release = mixer_release, | 387 | .release = mixer_release, |
372 | }; | 388 | }; |
@@ -737,8 +753,11 @@ static int sq_open(struct inode *inode, struct file *file) | |||
737 | { | 753 | { |
738 | int rc; | 754 | int rc; |
739 | 755 | ||
740 | if (!try_module_get(dmasound.mach.owner)) | 756 | mutex_lock(&dmasound_core_mutex); |
757 | if (!try_module_get(dmasound.mach.owner)) { | ||
758 | mutex_unlock(&dmasound_core_mutex); | ||
741 | return -ENODEV; | 759 | return -ENODEV; |
760 | } | ||
742 | 761 | ||
743 | rc = write_sq_open(file); /* checks the f_mode */ | 762 | rc = write_sq_open(file); /* checks the f_mode */ |
744 | if (rc) | 763 | if (rc) |
@@ -781,10 +800,11 @@ static int sq_open(struct inode *inode, struct file *file) | |||
781 | sound_set_format(AFMT_MU_LAW); | 800 | sound_set_format(AFMT_MU_LAW); |
782 | } | 801 | } |
783 | #endif | 802 | #endif |
784 | 803 | mutex_unlock(&dmasound_core_mutex); | |
785 | return 0; | 804 | return 0; |
786 | out: | 805 | out: |
787 | module_put(dmasound.mach.owner); | 806 | module_put(dmasound.mach.owner); |
807 | mutex_unlock(&dmasound_core_mutex); | ||
788 | return rc; | 808 | return rc; |
789 | } | 809 | } |
790 | 810 | ||
@@ -850,7 +870,7 @@ static int sq_release(struct inode *inode, struct file *file) | |||
850 | { | 870 | { |
851 | int rc = 0; | 871 | int rc = 0; |
852 | 872 | ||
853 | lock_kernel(); | 873 | mutex_lock(&dmasound_core_mutex); |
854 | 874 | ||
855 | if (file->f_mode & FMODE_WRITE) { | 875 | if (file->f_mode & FMODE_WRITE) { |
856 | if (write_sq.busy) | 876 | if (write_sq.busy) |
@@ -881,7 +901,7 @@ static int sq_release(struct inode *inode, struct file *file) | |||
881 | write_sq_wake_up(file); /* checks f_mode */ | 901 | write_sq_wake_up(file); /* checks f_mode */ |
882 | #endif /* blocking open() */ | 902 | #endif /* blocking open() */ |
883 | 903 | ||
884 | unlock_kernel(); | 904 | mutex_unlock(&dmasound_core_mutex); |
885 | 905 | ||
886 | return rc; | 906 | return rc; |
887 | } | 907 | } |
@@ -955,8 +975,7 @@ printk("dmasound_core: tried to set_queue_frags on a locked queue\n") ; | |||
955 | return 0 ; | 975 | return 0 ; |
956 | } | 976 | } |
957 | 977 | ||
958 | static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd, | 978 | static int sq_ioctl(struct file *file, u_int cmd, u_long arg) |
959 | u_long arg) | ||
960 | { | 979 | { |
961 | int val, result; | 980 | int val, result; |
962 | u_long fmt; | 981 | u_long fmt; |
@@ -1114,18 +1133,29 @@ static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd, | |||
1114 | return IOCTL_OUT(arg,val); | 1133 | return IOCTL_OUT(arg,val); |
1115 | 1134 | ||
1116 | default: | 1135 | default: |
1117 | return mixer_ioctl(inode, file, cmd, arg); | 1136 | return mixer_ioctl(file, cmd, arg); |
1118 | } | 1137 | } |
1119 | return -EINVAL; | 1138 | return -EINVAL; |
1120 | } | 1139 | } |
1121 | 1140 | ||
1141 | static long sq_unlocked_ioctl(struct file *file, u_int cmd, u_long arg) | ||
1142 | { | ||
1143 | int ret; | ||
1144 | |||
1145 | mutex_lock(&dmasound_core_mutex); | ||
1146 | ret = sq_ioctl(file, cmd, arg); | ||
1147 | mutex_unlock(&dmasound_core_mutex); | ||
1148 | |||
1149 | return ret; | ||
1150 | } | ||
1151 | |||
1122 | static const struct file_operations sq_fops = | 1152 | static const struct file_operations sq_fops = |
1123 | { | 1153 | { |
1124 | .owner = THIS_MODULE, | 1154 | .owner = THIS_MODULE, |
1125 | .llseek = no_llseek, | 1155 | .llseek = no_llseek, |
1126 | .write = sq_write, | 1156 | .write = sq_write, |
1127 | .poll = sq_poll, | 1157 | .poll = sq_poll, |
1128 | .ioctl = sq_ioctl, | 1158 | .unlocked_ioctl = sq_unlocked_ioctl, |
1129 | .open = sq_open, | 1159 | .open = sq_open, |
1130 | .release = sq_release, | 1160 | .release = sq_release, |
1131 | }; | 1161 | }; |
@@ -1226,12 +1256,17 @@ static int state_open(struct inode *inode, struct file *file) | |||
1226 | { | 1256 | { |
1227 | char *buffer = state.buf; | 1257 | char *buffer = state.buf; |
1228 | int len = 0; | 1258 | int len = 0; |
1259 | int ret; | ||
1229 | 1260 | ||
1261 | mutex_lock(&dmasound_core_mutex); | ||
1262 | ret = -EBUSY; | ||
1230 | if (state.busy) | 1263 | if (state.busy) |
1231 | return -EBUSY; | 1264 | goto out; |
1232 | 1265 | ||
1266 | ret = -ENODEV; | ||
1233 | if (!try_module_get(dmasound.mach.owner)) | 1267 | if (!try_module_get(dmasound.mach.owner)) |
1234 | return -ENODEV; | 1268 | goto out; |
1269 | |||
1235 | state.ptr = 0; | 1270 | state.ptr = 0; |
1236 | state.busy = 1; | 1271 | state.busy = 1; |
1237 | 1272 | ||
@@ -1293,15 +1328,18 @@ printk("dmasound: stat buffer used %d bytes\n", len) ; | |||
1293 | printk(KERN_ERR "dmasound_core: stat buffer overflowed!\n"); | 1328 | printk(KERN_ERR "dmasound_core: stat buffer overflowed!\n"); |
1294 | 1329 | ||
1295 | state.len = len; | 1330 | state.len = len; |
1296 | return 0; | 1331 | ret = 0; |
1332 | out: | ||
1333 | mutex_unlock(&dmasound_core_mutex); | ||
1334 | return ret; | ||
1297 | } | 1335 | } |
1298 | 1336 | ||
1299 | static int state_release(struct inode *inode, struct file *file) | 1337 | static int state_release(struct inode *inode, struct file *file) |
1300 | { | 1338 | { |
1301 | lock_kernel(); | 1339 | mutex_lock(&dmasound_core_mutex); |
1302 | state.busy = 0; | 1340 | state.busy = 0; |
1303 | module_put(dmasound.mach.owner); | 1341 | module_put(dmasound.mach.owner); |
1304 | unlock_kernel(); | 1342 | mutex_unlock(&dmasound_core_mutex); |
1305 | return 0; | 1343 | return 0; |
1306 | } | 1344 | } |
1307 | 1345 | ||
diff --git a/sound/oss/midi_synth.c b/sound/oss/midi_synth.c index 3bc7104c5379..3c09374ea5bf 100644 --- a/sound/oss/midi_synth.c +++ b/sound/oss/midi_synth.c | |||
@@ -523,7 +523,9 @@ midi_synth_load_patch(int dev, int format, const char __user *addr, | |||
523 | { | 523 | { |
524 | unsigned char data; | 524 | unsigned char data; |
525 | 525 | ||
526 | get_user(*(unsigned char *) &data, (unsigned char __user *) &((addr)[hdr_size + i])); | 526 | if (get_user(data, |
527 | (unsigned char __user *)(addr + hdr_size + i))) | ||
528 | return -EFAULT; | ||
527 | 529 | ||
528 | eox_seen = (i > 0 && data & 0x80); /* End of sysex */ | 530 | eox_seen = (i > 0 && data & 0x80); /* End of sysex */ |
529 | 531 | ||
diff --git a/sound/oss/msnd_pinnacle.c b/sound/oss/msnd_pinnacle.c index a1e3f9671bea..b4c1eb504c22 100644 --- a/sound/oss/msnd_pinnacle.c +++ b/sound/oss/msnd_pinnacle.c | |||
@@ -39,7 +39,7 @@ | |||
39 | #include <linux/delay.h> | 39 | #include <linux/delay.h> |
40 | #include <linux/init.h> | 40 | #include <linux/init.h> |
41 | #include <linux/interrupt.h> | 41 | #include <linux/interrupt.h> |
42 | #include <linux/smp_lock.h> | 42 | #include <linux/mutex.h> |
43 | #include <linux/gfp.h> | 43 | #include <linux/gfp.h> |
44 | #include <asm/irq.h> | 44 | #include <asm/irq.h> |
45 | #include <asm/io.h> | 45 | #include <asm/io.h> |
@@ -79,6 +79,7 @@ | |||
79 | dev.rec_sample_rate / \ | 79 | dev.rec_sample_rate / \ |
80 | dev.rec_channels) | 80 | dev.rec_channels) |
81 | 81 | ||
82 | static DEFINE_MUTEX(msnd_pinnacle_mutex); | ||
82 | static multisound_dev_t dev; | 83 | static multisound_dev_t dev; |
83 | 84 | ||
84 | #ifndef HAVE_DSPCODEH | 85 | #ifndef HAVE_DSPCODEH |
@@ -639,21 +640,26 @@ static int mixer_ioctl(unsigned int cmd, unsigned long arg) | |||
639 | return -EINVAL; | 640 | return -EINVAL; |
640 | } | 641 | } |
641 | 642 | ||
642 | static int dev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) | 643 | static long dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
643 | { | 644 | { |
644 | int minor = iminor(inode); | 645 | int minor = iminor(file->f_path.dentry->d_inode); |
646 | int ret; | ||
645 | 647 | ||
646 | if (cmd == OSS_GETVERSION) { | 648 | if (cmd == OSS_GETVERSION) { |
647 | int sound_version = SOUND_VERSION; | 649 | int sound_version = SOUND_VERSION; |
648 | return put_user(sound_version, (int __user *)arg); | 650 | return put_user(sound_version, (int __user *)arg); |
649 | } | 651 | } |
650 | 652 | ||
653 | ret = -EINVAL; | ||
654 | |||
655 | mutex_lock(&msnd_pinnacle_mutex); | ||
651 | if (minor == dev.dsp_minor) | 656 | if (minor == dev.dsp_minor) |
652 | return dsp_ioctl(file, cmd, arg); | 657 | ret = dsp_ioctl(file, cmd, arg); |
653 | else if (minor == dev.mixer_minor) | 658 | else if (minor == dev.mixer_minor) |
654 | return mixer_ioctl(cmd, arg); | 659 | ret = mixer_ioctl(cmd, arg); |
660 | mutex_unlock(&msnd_pinnacle_mutex); | ||
655 | 661 | ||
656 | return -EINVAL; | 662 | return ret; |
657 | } | 663 | } |
658 | 664 | ||
659 | static void dsp_write_flush(void) | 665 | static void dsp_write_flush(void) |
@@ -756,12 +762,15 @@ static int dev_open(struct inode *inode, struct file *file) | |||
756 | int minor = iminor(inode); | 762 | int minor = iminor(inode); |
757 | int err = 0; | 763 | int err = 0; |
758 | 764 | ||
765 | mutex_lock(&msnd_pinnacle_mutex); | ||
759 | if (minor == dev.dsp_minor) { | 766 | if (minor == dev.dsp_minor) { |
760 | if ((file->f_mode & FMODE_WRITE && | 767 | if ((file->f_mode & FMODE_WRITE && |
761 | test_bit(F_AUDIO_WRITE_INUSE, &dev.flags)) || | 768 | test_bit(F_AUDIO_WRITE_INUSE, &dev.flags)) || |
762 | (file->f_mode & FMODE_READ && | 769 | (file->f_mode & FMODE_READ && |
763 | test_bit(F_AUDIO_READ_INUSE, &dev.flags))) | 770 | test_bit(F_AUDIO_READ_INUSE, &dev.flags))) { |
764 | return -EBUSY; | 771 | err = -EBUSY; |
772 | goto out; | ||
773 | } | ||
765 | 774 | ||
766 | if ((err = dsp_open(file)) >= 0) { | 775 | if ((err = dsp_open(file)) >= 0) { |
767 | dev.nresets = 0; | 776 | dev.nresets = 0; |
@@ -782,7 +791,8 @@ static int dev_open(struct inode *inode, struct file *file) | |||
782 | /* nothing */ | 791 | /* nothing */ |
783 | } else | 792 | } else |
784 | err = -EINVAL; | 793 | err = -EINVAL; |
785 | 794 | out: | |
795 | mutex_unlock(&msnd_pinnacle_mutex); | ||
786 | return err; | 796 | return err; |
787 | } | 797 | } |
788 | 798 | ||
@@ -791,14 +801,14 @@ static int dev_release(struct inode *inode, struct file *file) | |||
791 | int minor = iminor(inode); | 801 | int minor = iminor(inode); |
792 | int err = 0; | 802 | int err = 0; |
793 | 803 | ||
794 | lock_kernel(); | 804 | mutex_lock(&msnd_pinnacle_mutex); |
795 | if (minor == dev.dsp_minor) | 805 | if (minor == dev.dsp_minor) |
796 | err = dsp_release(file); | 806 | err = dsp_release(file); |
797 | else if (minor == dev.mixer_minor) { | 807 | else if (minor == dev.mixer_minor) { |
798 | /* nothing */ | 808 | /* nothing */ |
799 | } else | 809 | } else |
800 | err = -EINVAL; | 810 | err = -EINVAL; |
801 | unlock_kernel(); | 811 | mutex_unlock(&msnd_pinnacle_mutex); |
802 | return err; | 812 | return err; |
803 | } | 813 | } |
804 | 814 | ||
@@ -1105,7 +1115,7 @@ static const struct file_operations dev_fileops = { | |||
1105 | .owner = THIS_MODULE, | 1115 | .owner = THIS_MODULE, |
1106 | .read = dev_read, | 1116 | .read = dev_read, |
1107 | .write = dev_write, | 1117 | .write = dev_write, |
1108 | .ioctl = dev_ioctl, | 1118 | .unlocked_ioctl = dev_ioctl, |
1109 | .open = dev_open, | 1119 | .open = dev_open, |
1110 | .release = dev_release, | 1120 | .release = dev_release, |
1111 | }; | 1121 | }; |
@@ -1391,9 +1401,13 @@ static int __init attach_multisound(void) | |||
1391 | printk(KERN_ERR LOGNAME ": Couldn't grab IRQ %d\n", dev.irq); | 1401 | printk(KERN_ERR LOGNAME ": Couldn't grab IRQ %d\n", dev.irq); |
1392 | return err; | 1402 | return err; |
1393 | } | 1403 | } |
1394 | request_region(dev.io, dev.numio, dev.name); | 1404 | if (request_region(dev.io, dev.numio, dev.name) == NULL) { |
1405 | free_irq(dev.irq, &dev); | ||
1406 | return -EBUSY; | ||
1407 | } | ||
1395 | 1408 | ||
1396 | if ((err = dsp_full_reset()) < 0) { | 1409 | err = dsp_full_reset(); |
1410 | if (err < 0) { | ||
1397 | release_region(dev.io, dev.numio); | 1411 | release_region(dev.io, dev.numio); |
1398 | free_irq(dev.irq, &dev); | 1412 | free_irq(dev.irq, &dev); |
1399 | return err; | 1413 | return err; |
diff --git a/sound/oss/sh_dac_audio.c b/sound/oss/sh_dac_audio.c deleted file mode 100644 index 4153752507e3..000000000000 --- a/sound/oss/sh_dac_audio.c +++ /dev/null | |||
@@ -1,309 +0,0 @@ | |||
1 | /* | ||
2 | * sound/oss/sh_dac_audio.c | ||
3 | * | ||
4 | * SH DAC based sound :( | ||
5 | * | ||
6 | * Copyright (C) 2004,2005 Andriy Skulysh | ||
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 | ||
10 | * for more details. | ||
11 | */ | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/sched.h> | ||
15 | #include <linux/linkage.h> | ||
16 | #include <linux/slab.h> | ||
17 | #include <linux/fs.h> | ||
18 | #include <linux/sound.h> | ||
19 | #include <linux/soundcard.h> | ||
20 | #include <linux/interrupt.h> | ||
21 | #include <linux/hrtimer.h> | ||
22 | #include <asm/io.h> | ||
23 | #include <asm/uaccess.h> | ||
24 | #include <asm/irq.h> | ||
25 | #include <asm/delay.h> | ||
26 | #include <asm/clock.h> | ||
27 | #include <cpu/dac.h> | ||
28 | #include <asm/machvec.h> | ||
29 | #include <mach/hp6xx.h> | ||
30 | #include <asm/hd64461.h> | ||
31 | |||
32 | #define MODNAME "sh_dac_audio" | ||
33 | |||
34 | #define BUFFER_SIZE 48000 | ||
35 | |||
36 | static int rate; | ||
37 | static int empty; | ||
38 | static char *data_buffer, *buffer_begin, *buffer_end; | ||
39 | static int in_use, device_major; | ||
40 | static struct hrtimer hrtimer; | ||
41 | static ktime_t wakeups_per_second; | ||
42 | |||
43 | static void dac_audio_start_timer(void) | ||
44 | { | ||
45 | hrtimer_start(&hrtimer, wakeups_per_second, HRTIMER_MODE_REL); | ||
46 | } | ||
47 | |||
48 | static void dac_audio_stop_timer(void) | ||
49 | { | ||
50 | hrtimer_cancel(&hrtimer); | ||
51 | } | ||
52 | |||
53 | static void dac_audio_reset(void) | ||
54 | { | ||
55 | dac_audio_stop_timer(); | ||
56 | buffer_begin = buffer_end = data_buffer; | ||
57 | empty = 1; | ||
58 | } | ||
59 | |||
60 | static void dac_audio_sync(void) | ||
61 | { | ||
62 | while (!empty) | ||
63 | schedule(); | ||
64 | } | ||
65 | |||
66 | static void dac_audio_start(void) | ||
67 | { | ||
68 | if (mach_is_hp6xx()) { | ||
69 | u16 v = __raw_readw(HD64461_GPADR); | ||
70 | v &= ~HD64461_GPADR_SPEAKER; | ||
71 | __raw_writew(v, HD64461_GPADR); | ||
72 | } | ||
73 | |||
74 | sh_dac_enable(CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL); | ||
75 | } | ||
76 | static void dac_audio_stop(void) | ||
77 | { | ||
78 | dac_audio_stop_timer(); | ||
79 | |||
80 | if (mach_is_hp6xx()) { | ||
81 | u16 v = __raw_readw(HD64461_GPADR); | ||
82 | v |= HD64461_GPADR_SPEAKER; | ||
83 | __raw_writew(v, HD64461_GPADR); | ||
84 | } | ||
85 | |||
86 | sh_dac_output(0, CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL); | ||
87 | sh_dac_disable(CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL); | ||
88 | } | ||
89 | |||
90 | static void dac_audio_set_rate(void) | ||
91 | { | ||
92 | wakeups_per_second = ktime_set(0, 1000000000 / rate); | ||
93 | } | ||
94 | |||
95 | static int dac_audio_ioctl(struct inode *inode, struct file *file, | ||
96 | unsigned int cmd, unsigned long arg) | ||
97 | { | ||
98 | int val; | ||
99 | |||
100 | switch (cmd) { | ||
101 | case OSS_GETVERSION: | ||
102 | return put_user(SOUND_VERSION, (int *)arg); | ||
103 | |||
104 | case SNDCTL_DSP_SYNC: | ||
105 | dac_audio_sync(); | ||
106 | return 0; | ||
107 | |||
108 | case SNDCTL_DSP_RESET: | ||
109 | dac_audio_reset(); | ||
110 | return 0; | ||
111 | |||
112 | case SNDCTL_DSP_GETFMTS: | ||
113 | return put_user(AFMT_U8, (int *)arg); | ||
114 | |||
115 | case SNDCTL_DSP_SETFMT: | ||
116 | return put_user(AFMT_U8, (int *)arg); | ||
117 | |||
118 | case SNDCTL_DSP_NONBLOCK: | ||
119 | spin_lock(&file->f_lock); | ||
120 | file->f_flags |= O_NONBLOCK; | ||
121 | spin_unlock(&file->f_lock); | ||
122 | return 0; | ||
123 | |||
124 | case SNDCTL_DSP_GETCAPS: | ||
125 | return 0; | ||
126 | |||
127 | case SOUND_PCM_WRITE_RATE: | ||
128 | val = *(int *)arg; | ||
129 | if (val > 0) { | ||
130 | rate = val; | ||
131 | dac_audio_set_rate(); | ||
132 | } | ||
133 | return put_user(rate, (int *)arg); | ||
134 | |||
135 | case SNDCTL_DSP_STEREO: | ||
136 | return put_user(0, (int *)arg); | ||
137 | |||
138 | case SOUND_PCM_WRITE_CHANNELS: | ||
139 | return put_user(1, (int *)arg); | ||
140 | |||
141 | case SNDCTL_DSP_SETDUPLEX: | ||
142 | return -EINVAL; | ||
143 | |||
144 | case SNDCTL_DSP_PROFILE: | ||
145 | return -EINVAL; | ||
146 | |||
147 | case SNDCTL_DSP_GETBLKSIZE: | ||
148 | return put_user(BUFFER_SIZE, (int *)arg); | ||
149 | |||
150 | case SNDCTL_DSP_SETFRAGMENT: | ||
151 | return 0; | ||
152 | |||
153 | default: | ||
154 | printk(KERN_ERR "sh_dac_audio: unimplemented ioctl=0x%x\n", | ||
155 | cmd); | ||
156 | return -EINVAL; | ||
157 | } | ||
158 | return -EINVAL; | ||
159 | } | ||
160 | |||
161 | static ssize_t dac_audio_write(struct file *file, const char *buf, size_t count, | ||
162 | loff_t * ppos) | ||
163 | { | ||
164 | int free; | ||
165 | int nbytes; | ||
166 | |||
167 | if (!count) { | ||
168 | dac_audio_sync(); | ||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | free = buffer_begin - buffer_end; | ||
173 | |||
174 | if (free < 0) | ||
175 | free += BUFFER_SIZE; | ||
176 | if ((free == 0) && (empty)) | ||
177 | free = BUFFER_SIZE; | ||
178 | if (count > free) | ||
179 | count = free; | ||
180 | if (buffer_begin > buffer_end) { | ||
181 | if (copy_from_user((void *)buffer_end, buf, count)) | ||
182 | return -EFAULT; | ||
183 | |||
184 | buffer_end += count; | ||
185 | } else { | ||
186 | nbytes = data_buffer + BUFFER_SIZE - buffer_end; | ||
187 | if (nbytes > count) { | ||
188 | if (copy_from_user((void *)buffer_end, buf, count)) | ||
189 | return -EFAULT; | ||
190 | buffer_end += count; | ||
191 | } else { | ||
192 | if (copy_from_user((void *)buffer_end, buf, nbytes)) | ||
193 | return -EFAULT; | ||
194 | if (copy_from_user | ||
195 | ((void *)data_buffer, buf + nbytes, count - nbytes)) | ||
196 | return -EFAULT; | ||
197 | buffer_end = data_buffer + count - nbytes; | ||
198 | } | ||
199 | } | ||
200 | |||
201 | if (empty) { | ||
202 | empty = 0; | ||
203 | dac_audio_start_timer(); | ||
204 | } | ||
205 | |||
206 | return count; | ||
207 | } | ||
208 | |||
209 | static ssize_t dac_audio_read(struct file *file, char *buf, size_t count, | ||
210 | loff_t * ppos) | ||
211 | { | ||
212 | return -EINVAL; | ||
213 | } | ||
214 | |||
215 | static int dac_audio_open(struct inode *inode, struct file *file) | ||
216 | { | ||
217 | if (file->f_mode & FMODE_READ) | ||
218 | return -ENODEV; | ||
219 | if (in_use) | ||
220 | return -EBUSY; | ||
221 | |||
222 | in_use = 1; | ||
223 | |||
224 | dac_audio_start(); | ||
225 | |||
226 | return 0; | ||
227 | } | ||
228 | |||
229 | static int dac_audio_release(struct inode *inode, struct file *file) | ||
230 | { | ||
231 | dac_audio_sync(); | ||
232 | dac_audio_stop(); | ||
233 | in_use = 0; | ||
234 | |||
235 | return 0; | ||
236 | } | ||
237 | |||
238 | const struct file_operations dac_audio_fops = { | ||
239 | .read = dac_audio_read, | ||
240 | .write = dac_audio_write, | ||
241 | .ioctl = dac_audio_ioctl, | ||
242 | .open = dac_audio_open, | ||
243 | .release = dac_audio_release, | ||
244 | }; | ||
245 | |||
246 | static enum hrtimer_restart sh_dac_audio_timer(struct hrtimer *handle) | ||
247 | { | ||
248 | if (!empty) { | ||
249 | sh_dac_output(*buffer_begin, CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL); | ||
250 | buffer_begin++; | ||
251 | |||
252 | if (buffer_begin == data_buffer + BUFFER_SIZE) | ||
253 | buffer_begin = data_buffer; | ||
254 | if (buffer_begin == buffer_end) | ||
255 | empty = 1; | ||
256 | } | ||
257 | |||
258 | if (!empty) | ||
259 | hrtimer_start(&hrtimer, wakeups_per_second, HRTIMER_MODE_REL); | ||
260 | |||
261 | return HRTIMER_NORESTART; | ||
262 | } | ||
263 | |||
264 | static int __init dac_audio_init(void) | ||
265 | { | ||
266 | if ((device_major = register_sound_dsp(&dac_audio_fops, -1)) < 0) { | ||
267 | printk(KERN_ERR "Cannot register dsp device"); | ||
268 | return device_major; | ||
269 | } | ||
270 | |||
271 | in_use = 0; | ||
272 | |||
273 | data_buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL); | ||
274 | if (data_buffer == NULL) | ||
275 | return -ENOMEM; | ||
276 | |||
277 | dac_audio_reset(); | ||
278 | rate = 8000; | ||
279 | dac_audio_set_rate(); | ||
280 | |||
281 | /* Today: High Resolution Timer driven DAC playback. | ||
282 | * The timer callback gets called once per sample. Ouch. | ||
283 | * | ||
284 | * Future: A much better approach would be to use the | ||
285 | * SH7720 CMT+DMAC+DAC hardware combination like this: | ||
286 | * - Program sample rate using CMT0 or CMT1 | ||
287 | * - Program DMAC to use CMT for timing and output to DAC | ||
288 | * - Play sound using DMAC, let CPU sleep. | ||
289 | * - While at it, rewrite this driver to use ALSA. | ||
290 | */ | ||
291 | |||
292 | hrtimer_init(&hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); | ||
293 | hrtimer.function = sh_dac_audio_timer; | ||
294 | |||
295 | return 0; | ||
296 | } | ||
297 | |||
298 | static void __exit dac_audio_exit(void) | ||
299 | { | ||
300 | unregister_sound_dsp(device_major); | ||
301 | kfree((void *)data_buffer); | ||
302 | } | ||
303 | |||
304 | module_init(dac_audio_init); | ||
305 | module_exit(dac_audio_exit); | ||
306 | |||
307 | MODULE_AUTHOR("Andriy Skulysh, askulysh@image.kiev.ua"); | ||
308 | MODULE_DESCRIPTION("SH DAC sound driver"); | ||
309 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/oss/sound_timer.c b/sound/oss/sound_timer.c index f0f0c19fbff7..48cda6c4c257 100644 --- a/sound/oss/sound_timer.c +++ b/sound/oss/sound_timer.c | |||
@@ -26,7 +26,7 @@ static unsigned long prev_event_time; | |||
26 | static volatile unsigned long usecs_per_tmr; /* Length of the current interval */ | 26 | static volatile unsigned long usecs_per_tmr; /* Length of the current interval */ |
27 | 27 | ||
28 | static struct sound_lowlev_timer *tmr; | 28 | static struct sound_lowlev_timer *tmr; |
29 | static spinlock_t lock; | 29 | static DEFINE_SPINLOCK(lock); |
30 | 30 | ||
31 | static unsigned long tmr2ticks(int tmr_value) | 31 | static unsigned long tmr2ticks(int tmr_value) |
32 | { | 32 | { |
diff --git a/sound/oss/soundcard.c b/sound/oss/soundcard.c index 2d9c51312622..938ed94f904f 100644 --- a/sound/oss/soundcard.c +++ b/sound/oss/soundcard.c | |||
@@ -40,7 +40,7 @@ | |||
40 | #include <linux/major.h> | 40 | #include <linux/major.h> |
41 | #include <linux/delay.h> | 41 | #include <linux/delay.h> |
42 | #include <linux/proc_fs.h> | 42 | #include <linux/proc_fs.h> |
43 | #include <linux/smp_lock.h> | 43 | #include <linux/mutex.h> |
44 | #include <linux/module.h> | 44 | #include <linux/module.h> |
45 | #include <linux/mm.h> | 45 | #include <linux/mm.h> |
46 | #include <linux/device.h> | 46 | #include <linux/device.h> |
@@ -56,6 +56,7 @@ | |||
56 | * Table for permanently allocated memory (used when unloading the module) | 56 | * Table for permanently allocated memory (used when unloading the module) |
57 | */ | 57 | */ |
58 | void * sound_mem_blocks[MAX_MEM_BLOCKS]; | 58 | void * sound_mem_blocks[MAX_MEM_BLOCKS]; |
59 | static DEFINE_MUTEX(soundcard_mutex); | ||
59 | int sound_nblocks = 0; | 60 | int sound_nblocks = 0; |
60 | 61 | ||
61 | /* Persistent DMA buffers */ | 62 | /* Persistent DMA buffers */ |
@@ -151,7 +152,7 @@ static ssize_t sound_read(struct file *file, char __user *buf, size_t count, lof | |||
151 | * big one anyway, we might as well bandage here.. | 152 | * big one anyway, we might as well bandage here.. |
152 | */ | 153 | */ |
153 | 154 | ||
154 | lock_kernel(); | 155 | mutex_lock(&soundcard_mutex); |
155 | 156 | ||
156 | DEB(printk("sound_read(dev=%d, count=%d)\n", dev, count)); | 157 | DEB(printk("sound_read(dev=%d, count=%d)\n", dev, count)); |
157 | switch (dev & 0x0f) { | 158 | switch (dev & 0x0f) { |
@@ -169,7 +170,7 @@ static ssize_t sound_read(struct file *file, char __user *buf, size_t count, lof | |||
169 | case SND_DEV_MIDIN: | 170 | case SND_DEV_MIDIN: |
170 | ret = MIDIbuf_read(dev, file, buf, count); | 171 | ret = MIDIbuf_read(dev, file, buf, count); |
171 | } | 172 | } |
172 | unlock_kernel(); | 173 | mutex_unlock(&soundcard_mutex); |
173 | return ret; | 174 | return ret; |
174 | } | 175 | } |
175 | 176 | ||
@@ -178,7 +179,7 @@ static ssize_t sound_write(struct file *file, const char __user *buf, size_t cou | |||
178 | int dev = iminor(file->f_path.dentry->d_inode); | 179 | int dev = iminor(file->f_path.dentry->d_inode); |
179 | int ret = -EINVAL; | 180 | int ret = -EINVAL; |
180 | 181 | ||
181 | lock_kernel(); | 182 | mutex_lock(&soundcard_mutex); |
182 | DEB(printk("sound_write(dev=%d, count=%d)\n", dev, count)); | 183 | DEB(printk("sound_write(dev=%d, count=%d)\n", dev, count)); |
183 | switch (dev & 0x0f) { | 184 | switch (dev & 0x0f) { |
184 | case SND_DEV_SEQ: | 185 | case SND_DEV_SEQ: |
@@ -196,7 +197,7 @@ static ssize_t sound_write(struct file *file, const char __user *buf, size_t cou | |||
196 | ret = MIDIbuf_write(dev, file, buf, count); | 197 | ret = MIDIbuf_write(dev, file, buf, count); |
197 | break; | 198 | break; |
198 | } | 199 | } |
199 | unlock_kernel(); | 200 | mutex_unlock(&soundcard_mutex); |
200 | return ret; | 201 | return ret; |
201 | } | 202 | } |
202 | 203 | ||
@@ -210,42 +211,44 @@ static int sound_open(struct inode *inode, struct file *file) | |||
210 | printk(KERN_ERR "Invalid minor device %d\n", dev); | 211 | printk(KERN_ERR "Invalid minor device %d\n", dev); |
211 | return -ENXIO; | 212 | return -ENXIO; |
212 | } | 213 | } |
214 | mutex_lock(&soundcard_mutex); | ||
213 | switch (dev & 0x0f) { | 215 | switch (dev & 0x0f) { |
214 | case SND_DEV_CTL: | 216 | case SND_DEV_CTL: |
215 | dev >>= 4; | 217 | dev >>= 4; |
216 | if (dev >= 0 && dev < MAX_MIXER_DEV && mixer_devs[dev] == NULL) { | 218 | if (dev >= 0 && dev < MAX_MIXER_DEV && mixer_devs[dev] == NULL) { |
217 | request_module("mixer%d", dev); | 219 | request_module("mixer%d", dev); |
218 | } | 220 | } |
221 | retval = -ENXIO; | ||
219 | if (dev && (dev >= num_mixers || mixer_devs[dev] == NULL)) | 222 | if (dev && (dev >= num_mixers || mixer_devs[dev] == NULL)) |
220 | return -ENXIO; | 223 | break; |
221 | 224 | ||
222 | if (!try_module_get(mixer_devs[dev]->owner)) | 225 | if (!try_module_get(mixer_devs[dev]->owner)) |
223 | return -ENXIO; | 226 | break; |
227 | |||
228 | retval = 0; | ||
224 | break; | 229 | break; |
225 | 230 | ||
226 | case SND_DEV_SEQ: | 231 | case SND_DEV_SEQ: |
227 | case SND_DEV_SEQ2: | 232 | case SND_DEV_SEQ2: |
228 | if ((retval = sequencer_open(dev, file)) < 0) | 233 | retval = sequencer_open(dev, file); |
229 | return retval; | ||
230 | break; | 234 | break; |
231 | 235 | ||
232 | case SND_DEV_MIDIN: | 236 | case SND_DEV_MIDIN: |
233 | if ((retval = MIDIbuf_open(dev, file)) < 0) | 237 | retval = MIDIbuf_open(dev, file); |
234 | return retval; | ||
235 | break; | 238 | break; |
236 | 239 | ||
237 | case SND_DEV_DSP: | 240 | case SND_DEV_DSP: |
238 | case SND_DEV_DSP16: | 241 | case SND_DEV_DSP16: |
239 | case SND_DEV_AUDIO: | 242 | case SND_DEV_AUDIO: |
240 | if ((retval = audio_open(dev, file)) < 0) | 243 | retval = audio_open(dev, file); |
241 | return retval; | ||
242 | break; | 244 | break; |
243 | 245 | ||
244 | default: | 246 | default: |
245 | printk(KERN_ERR "Invalid minor device %d\n", dev); | 247 | printk(KERN_ERR "Invalid minor device %d\n", dev); |
246 | return -ENXIO; | 248 | retval = -ENXIO; |
247 | } | 249 | } |
248 | 250 | ||
251 | mutex_unlock(&soundcard_mutex); | ||
249 | return 0; | 252 | return 0; |
250 | } | 253 | } |
251 | 254 | ||
@@ -253,7 +256,7 @@ static int sound_release(struct inode *inode, struct file *file) | |||
253 | { | 256 | { |
254 | int dev = iminor(inode); | 257 | int dev = iminor(inode); |
255 | 258 | ||
256 | lock_kernel(); | 259 | mutex_lock(&soundcard_mutex); |
257 | DEB(printk("sound_release(dev=%d)\n", dev)); | 260 | DEB(printk("sound_release(dev=%d)\n", dev)); |
258 | switch (dev & 0x0f) { | 261 | switch (dev & 0x0f) { |
259 | case SND_DEV_CTL: | 262 | case SND_DEV_CTL: |
@@ -278,7 +281,7 @@ static int sound_release(struct inode *inode, struct file *file) | |||
278 | default: | 281 | default: |
279 | printk(KERN_ERR "Sound error: Releasing unknown device 0x%02x\n", dev); | 282 | printk(KERN_ERR "Sound error: Releasing unknown device 0x%02x\n", dev); |
280 | } | 283 | } |
281 | unlock_kernel(); | 284 | mutex_unlock(&soundcard_mutex); |
282 | 285 | ||
283 | return 0; | 286 | return 0; |
284 | } | 287 | } |
@@ -352,7 +355,7 @@ static long sound_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
352 | if (cmd == OSS_GETVERSION) | 355 | if (cmd == OSS_GETVERSION) |
353 | return __put_user(SOUND_VERSION, (int __user *)p); | 356 | return __put_user(SOUND_VERSION, (int __user *)p); |
354 | 357 | ||
355 | lock_kernel(); | 358 | mutex_lock(&soundcard_mutex); |
356 | if (_IOC_TYPE(cmd) == 'M' && num_mixers > 0 && /* Mixer ioctl */ | 359 | if (_IOC_TYPE(cmd) == 'M' && num_mixers > 0 && /* Mixer ioctl */ |
357 | (dev & 0x0f) != SND_DEV_CTL) { | 360 | (dev & 0x0f) != SND_DEV_CTL) { |
358 | dtype = dev & 0x0f; | 361 | dtype = dev & 0x0f; |
@@ -367,7 +370,7 @@ static long sound_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
367 | ret = sound_mixer_ioctl(dev >> 4, cmd, p); | 370 | ret = sound_mixer_ioctl(dev >> 4, cmd, p); |
368 | break; | 371 | break; |
369 | } | 372 | } |
370 | unlock_kernel(); | 373 | mutex_unlock(&soundcard_mutex); |
371 | return ret; | 374 | return ret; |
372 | } | 375 | } |
373 | 376 | ||
@@ -397,7 +400,7 @@ static long sound_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
397 | break; | 400 | break; |
398 | 401 | ||
399 | } | 402 | } |
400 | unlock_kernel(); | 403 | mutex_unlock(&soundcard_mutex); |
401 | return ret; | 404 | return ret; |
402 | } | 405 | } |
403 | 406 | ||
@@ -437,35 +440,35 @@ static int sound_mmap(struct file *file, struct vm_area_struct *vma) | |||
437 | printk(KERN_ERR "Sound: mmap() not supported for other than audio devices\n"); | 440 | printk(KERN_ERR "Sound: mmap() not supported for other than audio devices\n"); |
438 | return -EINVAL; | 441 | return -EINVAL; |
439 | } | 442 | } |
440 | lock_kernel(); | 443 | mutex_lock(&soundcard_mutex); |
441 | if (vma->vm_flags & VM_WRITE) /* Map write and read/write to the output buf */ | 444 | if (vma->vm_flags & VM_WRITE) /* Map write and read/write to the output buf */ |
442 | dmap = audio_devs[dev]->dmap_out; | 445 | dmap = audio_devs[dev]->dmap_out; |
443 | else if (vma->vm_flags & VM_READ) | 446 | else if (vma->vm_flags & VM_READ) |
444 | dmap = audio_devs[dev]->dmap_in; | 447 | dmap = audio_devs[dev]->dmap_in; |
445 | else { | 448 | else { |
446 | printk(KERN_ERR "Sound: Undefined mmap() access\n"); | 449 | printk(KERN_ERR "Sound: Undefined mmap() access\n"); |
447 | unlock_kernel(); | 450 | mutex_unlock(&soundcard_mutex); |
448 | return -EINVAL; | 451 | return -EINVAL; |
449 | } | 452 | } |
450 | 453 | ||
451 | if (dmap == NULL) { | 454 | if (dmap == NULL) { |
452 | printk(KERN_ERR "Sound: mmap() error. dmap == NULL\n"); | 455 | printk(KERN_ERR "Sound: mmap() error. dmap == NULL\n"); |
453 | unlock_kernel(); | 456 | mutex_unlock(&soundcard_mutex); |
454 | return -EIO; | 457 | return -EIO; |
455 | } | 458 | } |
456 | if (dmap->raw_buf == NULL) { | 459 | if (dmap->raw_buf == NULL) { |
457 | printk(KERN_ERR "Sound: mmap() called when raw_buf == NULL\n"); | 460 | printk(KERN_ERR "Sound: mmap() called when raw_buf == NULL\n"); |
458 | unlock_kernel(); | 461 | mutex_unlock(&soundcard_mutex); |
459 | return -EIO; | 462 | return -EIO; |
460 | } | 463 | } |
461 | if (dmap->mapping_flags) { | 464 | if (dmap->mapping_flags) { |
462 | printk(KERN_ERR "Sound: mmap() called twice for the same DMA buffer\n"); | 465 | printk(KERN_ERR "Sound: mmap() called twice for the same DMA buffer\n"); |
463 | unlock_kernel(); | 466 | mutex_unlock(&soundcard_mutex); |
464 | return -EIO; | 467 | return -EIO; |
465 | } | 468 | } |
466 | if (vma->vm_pgoff != 0) { | 469 | if (vma->vm_pgoff != 0) { |
467 | printk(KERN_ERR "Sound: mmap() offset must be 0.\n"); | 470 | printk(KERN_ERR "Sound: mmap() offset must be 0.\n"); |
468 | unlock_kernel(); | 471 | mutex_unlock(&soundcard_mutex); |
469 | return -EINVAL; | 472 | return -EINVAL; |
470 | } | 473 | } |
471 | size = vma->vm_end - vma->vm_start; | 474 | size = vma->vm_end - vma->vm_start; |
@@ -476,7 +479,7 @@ static int sound_mmap(struct file *file, struct vm_area_struct *vma) | |||
476 | if (remap_pfn_range(vma, vma->vm_start, | 479 | if (remap_pfn_range(vma, vma->vm_start, |
477 | virt_to_phys(dmap->raw_buf) >> PAGE_SHIFT, | 480 | virt_to_phys(dmap->raw_buf) >> PAGE_SHIFT, |
478 | vma->vm_end - vma->vm_start, vma->vm_page_prot)) { | 481 | vma->vm_end - vma->vm_start, vma->vm_page_prot)) { |
479 | unlock_kernel(); | 482 | mutex_unlock(&soundcard_mutex); |
480 | return -EAGAIN; | 483 | return -EAGAIN; |
481 | } | 484 | } |
482 | 485 | ||
@@ -488,7 +491,7 @@ static int sound_mmap(struct file *file, struct vm_area_struct *vma) | |||
488 | memset(dmap->raw_buf, | 491 | memset(dmap->raw_buf, |
489 | dmap->neutral_byte, | 492 | dmap->neutral_byte, |
490 | dmap->bytes_in_use); | 493 | dmap->bytes_in_use); |
491 | unlock_kernel(); | 494 | mutex_unlock(&soundcard_mutex); |
492 | return 0; | 495 | return 0; |
493 | } | 496 | } |
494 | 497 | ||
diff --git a/sound/oss/swarm_cs4297a.c b/sound/oss/swarm_cs4297a.c index 3136c88eacdf..44357d877a27 100644 --- a/sound/oss/swarm_cs4297a.c +++ b/sound/oss/swarm_cs4297a.c | |||
@@ -93,6 +93,7 @@ | |||
93 | 93 | ||
94 | struct cs4297a_state; | 94 | struct cs4297a_state; |
95 | 95 | ||
96 | static DEFINE_MUTEX(swarm_cs4297a_mutex); | ||
96 | static void stop_dac(struct cs4297a_state *s); | 97 | static void stop_dac(struct cs4297a_state *s); |
97 | static void stop_adc(struct cs4297a_state *s); | 98 | static void stop_adc(struct cs4297a_state *s); |
98 | static void start_dac(struct cs4297a_state *s); | 99 | static void start_dac(struct cs4297a_state *s); |
@@ -1534,6 +1535,7 @@ static int cs4297a_open_mixdev(struct inode *inode, struct file *file) | |||
1534 | CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4, | 1535 | CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4, |
1535 | printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()+\n")); | 1536 | printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()+\n")); |
1536 | 1537 | ||
1538 | mutex_lock(&swarm_cs4297a_mutex); | ||
1537 | list_for_each(entry, &cs4297a_devs) | 1539 | list_for_each(entry, &cs4297a_devs) |
1538 | { | 1540 | { |
1539 | s = list_entry(entry, struct cs4297a_state, list); | 1541 | s = list_entry(entry, struct cs4297a_state, list); |
@@ -1544,6 +1546,8 @@ static int cs4297a_open_mixdev(struct inode *inode, struct file *file) | |||
1544 | { | 1546 | { |
1545 | CS_DBGOUT(CS_FUNCTION | CS_OPEN | CS_ERROR, 2, | 1547 | CS_DBGOUT(CS_FUNCTION | CS_OPEN | CS_ERROR, 2, |
1546 | printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()- -ENODEV\n")); | 1548 | printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()- -ENODEV\n")); |
1549 | |||
1550 | mutex_unlock(&swarm_cs4297a_mutex); | ||
1547 | return -ENODEV; | 1551 | return -ENODEV; |
1548 | } | 1552 | } |
1549 | VALIDATE_STATE(s); | 1553 | VALIDATE_STATE(s); |
@@ -1551,6 +1555,7 @@ static int cs4297a_open_mixdev(struct inode *inode, struct file *file) | |||
1551 | 1555 | ||
1552 | CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4, | 1556 | CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4, |
1553 | printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()- 0\n")); | 1557 | printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()- 0\n")); |
1558 | mutex_unlock(&swarm_cs4297a_mutex); | ||
1554 | 1559 | ||
1555 | return nonseekable_open(inode, file); | 1560 | return nonseekable_open(inode, file); |
1556 | } | 1561 | } |
@@ -1566,11 +1571,15 @@ static int cs4297a_release_mixdev(struct inode *inode, struct file *file) | |||
1566 | } | 1571 | } |
1567 | 1572 | ||
1568 | 1573 | ||
1569 | static int cs4297a_ioctl_mixdev(struct inode *inode, struct file *file, | 1574 | static int cs4297a_ioctl_mixdev(struct file *file, |
1570 | unsigned int cmd, unsigned long arg) | 1575 | unsigned int cmd, unsigned long arg) |
1571 | { | 1576 | { |
1572 | return mixer_ioctl((struct cs4297a_state *) file->private_data, cmd, | 1577 | int ret; |
1578 | mutex_lock(&swarm_cs4297a_mutex); | ||
1579 | ret = mixer_ioctl((struct cs4297a_state *) file->private_data, cmd, | ||
1573 | arg); | 1580 | arg); |
1581 | mutex_unlock(&swarm_cs4297a_mutex); | ||
1582 | return ret; | ||
1574 | } | 1583 | } |
1575 | 1584 | ||
1576 | 1585 | ||
@@ -1580,7 +1589,7 @@ static int cs4297a_ioctl_mixdev(struct inode *inode, struct file *file, | |||
1580 | static const struct file_operations cs4297a_mixer_fops = { | 1589 | static const struct file_operations cs4297a_mixer_fops = { |
1581 | .owner = THIS_MODULE, | 1590 | .owner = THIS_MODULE, |
1582 | .llseek = no_llseek, | 1591 | .llseek = no_llseek, |
1583 | .ioctl = cs4297a_ioctl_mixdev, | 1592 | .unlocked_ioctl = cs4297a_ioctl_mixdev, |
1584 | .open = cs4297a_open_mixdev, | 1593 | .open = cs4297a_open_mixdev, |
1585 | .release = cs4297a_release_mixdev, | 1594 | .release = cs4297a_release_mixdev, |
1586 | }; | 1595 | }; |
@@ -1944,7 +1953,7 @@ static int cs4297a_mmap(struct file *file, struct vm_area_struct *vma) | |||
1944 | } | 1953 | } |
1945 | 1954 | ||
1946 | 1955 | ||
1947 | static int cs4297a_ioctl(struct inode *inode, struct file *file, | 1956 | static int cs4297a_ioctl(struct file *file, |
1948 | unsigned int cmd, unsigned long arg) | 1957 | unsigned int cmd, unsigned long arg) |
1949 | { | 1958 | { |
1950 | struct cs4297a_state *s = | 1959 | struct cs4297a_state *s = |
@@ -2337,6 +2346,16 @@ static int cs4297a_ioctl(struct inode *inode, struct file *file, | |||
2337 | return mixer_ioctl(s, cmd, arg); | 2346 | return mixer_ioctl(s, cmd, arg); |
2338 | } | 2347 | } |
2339 | 2348 | ||
2349 | static long cs4297a_unlocked_ioctl(struct file *file, u_int cmd, u_long arg) | ||
2350 | { | ||
2351 | int ret; | ||
2352 | |||
2353 | mutex_lock(&swarm_cs4297a_mutex); | ||
2354 | ret = cs4297a_ioctl(file, cmd, arg); | ||
2355 | mutex_unlock(&swarm_cs4297a_mutex); | ||
2356 | |||
2357 | return ret; | ||
2358 | } | ||
2340 | 2359 | ||
2341 | static int cs4297a_release(struct inode *inode, struct file *file) | 2360 | static int cs4297a_release(struct inode *inode, struct file *file) |
2342 | { | 2361 | { |
@@ -2369,7 +2388,7 @@ static int cs4297a_release(struct inode *inode, struct file *file) | |||
2369 | return 0; | 2388 | return 0; |
2370 | } | 2389 | } |
2371 | 2390 | ||
2372 | static int cs4297a_open(struct inode *inode, struct file *file) | 2391 | static int cs4297a_locked_open(struct inode *inode, struct file *file) |
2373 | { | 2392 | { |
2374 | int minor = iminor(inode); | 2393 | int minor = iminor(inode); |
2375 | struct cs4297a_state *s=NULL; | 2394 | struct cs4297a_state *s=NULL; |
@@ -2486,6 +2505,16 @@ static int cs4297a_open(struct inode *inode, struct file *file) | |||
2486 | return nonseekable_open(inode, file); | 2505 | return nonseekable_open(inode, file); |
2487 | } | 2506 | } |
2488 | 2507 | ||
2508 | static int cs4297a_open(struct inode *inode, struct file *file) | ||
2509 | { | ||
2510 | int ret; | ||
2511 | |||
2512 | mutex_lock(&swarm_cs4297a_mutex); | ||
2513 | ret = cs4297a_open(inode, file); | ||
2514 | mutex_unlock(&swarm_cs4297a_mutex); | ||
2515 | |||
2516 | return ret; | ||
2517 | } | ||
2489 | 2518 | ||
2490 | // ****************************************************************************************** | 2519 | // ****************************************************************************************** |
2491 | // Wave (audio) file operations struct. | 2520 | // Wave (audio) file operations struct. |
@@ -2496,7 +2525,7 @@ static const struct file_operations cs4297a_audio_fops = { | |||
2496 | .read = cs4297a_read, | 2525 | .read = cs4297a_read, |
2497 | .write = cs4297a_write, | 2526 | .write = cs4297a_write, |
2498 | .poll = cs4297a_poll, | 2527 | .poll = cs4297a_poll, |
2499 | .ioctl = cs4297a_ioctl, | 2528 | .unlocked_ioctl = cs4297a_unlocked_ioctl, |
2500 | .mmap = cs4297a_mmap, | 2529 | .mmap = cs4297a_mmap, |
2501 | .open = cs4297a_open, | 2530 | .open = cs4297a_open, |
2502 | .release = cs4297a_release, | 2531 | .release = cs4297a_release, |
diff --git a/sound/oss/vidc.c b/sound/oss/vidc.c index ac39a531df19..f0e0caa53200 100644 --- a/sound/oss/vidc.c +++ b/sound/oss/vidc.c | |||
@@ -491,9 +491,6 @@ static void __init attach_vidc(struct address_info *hw_config) | |||
491 | vidc_adev = adev; | 491 | vidc_adev = adev; |
492 | vidc_mixer_set(SOUND_MIXER_VOLUME, (85 | 85 << 8)); | 492 | vidc_mixer_set(SOUND_MIXER_VOLUME, (85 | 85 << 8)); |
493 | 493 | ||
494 | #if defined(CONFIG_SOUND_SOFTOSS) || defined(CONFIG_SOUND_SOFTOSS_MODULE) | ||
495 | softoss_dev = adev; | ||
496 | #endif | ||
497 | return; | 494 | return; |
498 | 495 | ||
499 | irq_failed: | 496 | irq_failed: |
diff --git a/sound/oss/vwsnd.c b/sound/oss/vwsnd.c index 20b3b325aa80..643f1113b1d8 100644 --- a/sound/oss/vwsnd.c +++ b/sound/oss/vwsnd.c | |||
@@ -145,7 +145,6 @@ | |||
145 | #include <linux/init.h> | 145 | #include <linux/init.h> |
146 | 146 | ||
147 | #include <linux/spinlock.h> | 147 | #include <linux/spinlock.h> |
148 | #include <linux/smp_lock.h> | ||
149 | #include <linux/wait.h> | 148 | #include <linux/wait.h> |
150 | #include <linux/interrupt.h> | 149 | #include <linux/interrupt.h> |
151 | #include <linux/mutex.h> | 150 | #include <linux/mutex.h> |
@@ -160,6 +159,7 @@ | |||
160 | 159 | ||
161 | #ifdef VWSND_DEBUG | 160 | #ifdef VWSND_DEBUG |
162 | 161 | ||
162 | static DEFINE_MUTEX(vwsnd_mutex); | ||
163 | static int shut_up = 1; | 163 | static int shut_up = 1; |
164 | 164 | ||
165 | /* | 165 | /* |
@@ -2429,8 +2429,7 @@ static unsigned int vwsnd_audio_poll(struct file *file, | |||
2429 | return mask; | 2429 | return mask; |
2430 | } | 2430 | } |
2431 | 2431 | ||
2432 | static int vwsnd_audio_do_ioctl(struct inode *inode, | 2432 | static int vwsnd_audio_do_ioctl(struct file *file, |
2433 | struct file *file, | ||
2434 | unsigned int cmd, | 2433 | unsigned int cmd, |
2435 | unsigned long arg) | 2434 | unsigned long arg) |
2436 | { | 2435 | { |
@@ -2446,8 +2445,8 @@ static int vwsnd_audio_do_ioctl(struct inode *inode, | |||
2446 | int ival; | 2445 | int ival; |
2447 | 2446 | ||
2448 | 2447 | ||
2449 | DBGEV("(inode=0x%p, file=0x%p, cmd=0x%x, arg=0x%lx)\n", | 2448 | DBGEV("(file=0x%p, cmd=0x%x, arg=0x%lx)\n", |
2450 | inode, file, cmd, arg); | 2449 | file, cmd, arg); |
2451 | switch (cmd) { | 2450 | switch (cmd) { |
2452 | case OSS_GETVERSION: /* _SIOR ('M', 118, int) */ | 2451 | case OSS_GETVERSION: /* _SIOR ('M', 118, int) */ |
2453 | DBGX("OSS_GETVERSION\n"); | 2452 | DBGX("OSS_GETVERSION\n"); |
@@ -2885,17 +2884,19 @@ static int vwsnd_audio_do_ioctl(struct inode *inode, | |||
2885 | return -EINVAL; | 2884 | return -EINVAL; |
2886 | } | 2885 | } |
2887 | 2886 | ||
2888 | static int vwsnd_audio_ioctl(struct inode *inode, | 2887 | static long vwsnd_audio_ioctl(struct file *file, |
2889 | struct file *file, | ||
2890 | unsigned int cmd, | 2888 | unsigned int cmd, |
2891 | unsigned long arg) | 2889 | unsigned long arg) |
2892 | { | 2890 | { |
2893 | vwsnd_dev_t *devc = (vwsnd_dev_t *) file->private_data; | 2891 | vwsnd_dev_t *devc = (vwsnd_dev_t *) file->private_data; |
2894 | int ret; | 2892 | int ret; |
2895 | 2893 | ||
2894 | mutex_lock(&vwsnd_mutex); | ||
2896 | mutex_lock(&devc->io_mutex); | 2895 | mutex_lock(&devc->io_mutex); |
2897 | ret = vwsnd_audio_do_ioctl(inode, file, cmd, arg); | 2896 | ret = vwsnd_audio_do_ioctl(file, cmd, arg); |
2898 | mutex_unlock(&devc->io_mutex); | 2897 | mutex_unlock(&devc->io_mutex); |
2898 | mutex_unlock(&vwsnd_mutex); | ||
2899 | |||
2899 | return ret; | 2900 | return ret; |
2900 | } | 2901 | } |
2901 | 2902 | ||
@@ -2921,6 +2922,7 @@ static int vwsnd_audio_open(struct inode *inode, struct file *file) | |||
2921 | 2922 | ||
2922 | DBGE("(inode=0x%p, file=0x%p)\n", inode, file); | 2923 | DBGE("(inode=0x%p, file=0x%p)\n", inode, file); |
2923 | 2924 | ||
2925 | mutex_lock(&vwsnd_mutex); | ||
2924 | INC_USE_COUNT; | 2926 | INC_USE_COUNT; |
2925 | for (devc = vwsnd_dev_list; devc; devc = devc->next_dev) | 2927 | for (devc = vwsnd_dev_list; devc; devc = devc->next_dev) |
2926 | if ((devc->audio_minor & ~0x0F) == (minor & ~0x0F)) | 2928 | if ((devc->audio_minor & ~0x0F) == (minor & ~0x0F)) |
@@ -2928,6 +2930,7 @@ static int vwsnd_audio_open(struct inode *inode, struct file *file) | |||
2928 | 2930 | ||
2929 | if (devc == NULL) { | 2931 | if (devc == NULL) { |
2930 | DEC_USE_COUNT; | 2932 | DEC_USE_COUNT; |
2933 | mutex_unlock(&vwsnd_mutex); | ||
2931 | return -ENODEV; | 2934 | return -ENODEV; |
2932 | } | 2935 | } |
2933 | 2936 | ||
@@ -2936,11 +2939,13 @@ static int vwsnd_audio_open(struct inode *inode, struct file *file) | |||
2936 | mutex_unlock(&devc->open_mutex); | 2939 | mutex_unlock(&devc->open_mutex); |
2937 | if (file->f_flags & O_NONBLOCK) { | 2940 | if (file->f_flags & O_NONBLOCK) { |
2938 | DEC_USE_COUNT; | 2941 | DEC_USE_COUNT; |
2942 | mutex_unlock(&vwsnd_mutex); | ||
2939 | return -EBUSY; | 2943 | return -EBUSY; |
2940 | } | 2944 | } |
2941 | interruptible_sleep_on(&devc->open_wait); | 2945 | interruptible_sleep_on(&devc->open_wait); |
2942 | if (signal_pending(current)) { | 2946 | if (signal_pending(current)) { |
2943 | DEC_USE_COUNT; | 2947 | DEC_USE_COUNT; |
2948 | mutex_unlock(&vwsnd_mutex); | ||
2944 | return -ERESTARTSYS; | 2949 | return -ERESTARTSYS; |
2945 | } | 2950 | } |
2946 | mutex_lock(&devc->open_mutex); | 2951 | mutex_lock(&devc->open_mutex); |
@@ -2993,6 +2998,7 @@ static int vwsnd_audio_open(struct inode *inode, struct file *file) | |||
2993 | 2998 | ||
2994 | file->private_data = devc; | 2999 | file->private_data = devc; |
2995 | DBGRV(); | 3000 | DBGRV(); |
3001 | mutex_unlock(&vwsnd_mutex); | ||
2996 | return 0; | 3002 | return 0; |
2997 | } | 3003 | } |
2998 | 3004 | ||
@@ -3006,7 +3012,7 @@ static int vwsnd_audio_release(struct inode *inode, struct file *file) | |||
3006 | vwsnd_port_t *wport = NULL, *rport = NULL; | 3012 | vwsnd_port_t *wport = NULL, *rport = NULL; |
3007 | int err = 0; | 3013 | int err = 0; |
3008 | 3014 | ||
3009 | lock_kernel(); | 3015 | mutex_lock(&vwsnd_mutex); |
3010 | mutex_lock(&devc->io_mutex); | 3016 | mutex_lock(&devc->io_mutex); |
3011 | { | 3017 | { |
3012 | DBGEV("(inode=0x%p, file=0x%p)\n", inode, file); | 3018 | DBGEV("(inode=0x%p, file=0x%p)\n", inode, file); |
@@ -3034,7 +3040,7 @@ static int vwsnd_audio_release(struct inode *inode, struct file *file) | |||
3034 | wake_up(&devc->open_wait); | 3040 | wake_up(&devc->open_wait); |
3035 | DEC_USE_COUNT; | 3041 | DEC_USE_COUNT; |
3036 | DBGR(); | 3042 | DBGR(); |
3037 | unlock_kernel(); | 3043 | mutex_unlock(&vwsnd_mutex); |
3038 | return err; | 3044 | return err; |
3039 | } | 3045 | } |
3040 | 3046 | ||
@@ -3044,7 +3050,7 @@ static const struct file_operations vwsnd_audio_fops = { | |||
3044 | .read = vwsnd_audio_read, | 3050 | .read = vwsnd_audio_read, |
3045 | .write = vwsnd_audio_write, | 3051 | .write = vwsnd_audio_write, |
3046 | .poll = vwsnd_audio_poll, | 3052 | .poll = vwsnd_audio_poll, |
3047 | .ioctl = vwsnd_audio_ioctl, | 3053 | .unlocked_ioctl = vwsnd_audio_ioctl, |
3048 | .mmap = vwsnd_audio_mmap, | 3054 | .mmap = vwsnd_audio_mmap, |
3049 | .open = vwsnd_audio_open, | 3055 | .open = vwsnd_audio_open, |
3050 | .release = vwsnd_audio_release, | 3056 | .release = vwsnd_audio_release, |
@@ -3062,15 +3068,18 @@ static int vwsnd_mixer_open(struct inode *inode, struct file *file) | |||
3062 | DBGEV("(inode=0x%p, file=0x%p)\n", inode, file); | 3068 | DBGEV("(inode=0x%p, file=0x%p)\n", inode, file); |
3063 | 3069 | ||
3064 | INC_USE_COUNT; | 3070 | INC_USE_COUNT; |
3071 | mutex_lock(&vwsnd_mutex); | ||
3065 | for (devc = vwsnd_dev_list; devc; devc = devc->next_dev) | 3072 | for (devc = vwsnd_dev_list; devc; devc = devc->next_dev) |
3066 | if (devc->mixer_minor == iminor(inode)) | 3073 | if (devc->mixer_minor == iminor(inode)) |
3067 | break; | 3074 | break; |
3068 | 3075 | ||
3069 | if (devc == NULL) { | 3076 | if (devc == NULL) { |
3070 | DEC_USE_COUNT; | 3077 | DEC_USE_COUNT; |
3078 | mutex_unlock(&vwsnd_mutex); | ||
3071 | return -ENODEV; | 3079 | return -ENODEV; |
3072 | } | 3080 | } |
3073 | file->private_data = devc; | 3081 | file->private_data = devc; |
3082 | mutex_unlock(&vwsnd_mutex); | ||
3074 | return 0; | 3083 | return 0; |
3075 | } | 3084 | } |
3076 | 3085 | ||
@@ -3203,8 +3212,7 @@ static int mixer_write_ioctl(vwsnd_dev_t *devc, unsigned int nr, void __user *ar | |||
3203 | 3212 | ||
3204 | /* This is the ioctl entry to the mixer driver. */ | 3213 | /* This is the ioctl entry to the mixer driver. */ |
3205 | 3214 | ||
3206 | static int vwsnd_mixer_ioctl(struct inode *ioctl, | 3215 | static long vwsnd_mixer_ioctl(struct file *file, |
3207 | struct file *file, | ||
3208 | unsigned int cmd, | 3216 | unsigned int cmd, |
3209 | unsigned long arg) | 3217 | unsigned long arg) |
3210 | { | 3218 | { |
@@ -3215,6 +3223,7 @@ static int vwsnd_mixer_ioctl(struct inode *ioctl, | |||
3215 | 3223 | ||
3216 | DBGEV("(devc=0x%p, cmd=0x%x, arg=0x%lx)\n", devc, cmd, arg); | 3224 | DBGEV("(devc=0x%p, cmd=0x%x, arg=0x%lx)\n", devc, cmd, arg); |
3217 | 3225 | ||
3226 | mutex_lock(&vwsnd_mutex); | ||
3218 | mutex_lock(&devc->mix_mutex); | 3227 | mutex_lock(&devc->mix_mutex); |
3219 | { | 3228 | { |
3220 | if ((cmd & ~nrmask) == MIXER_READ(0)) | 3229 | if ((cmd & ~nrmask) == MIXER_READ(0)) |
@@ -3225,13 +3234,14 @@ static int vwsnd_mixer_ioctl(struct inode *ioctl, | |||
3225 | retval = -EINVAL; | 3234 | retval = -EINVAL; |
3226 | } | 3235 | } |
3227 | mutex_unlock(&devc->mix_mutex); | 3236 | mutex_unlock(&devc->mix_mutex); |
3237 | mutex_unlock(&vwsnd_mutex); | ||
3228 | return retval; | 3238 | return retval; |
3229 | } | 3239 | } |
3230 | 3240 | ||
3231 | static const struct file_operations vwsnd_mixer_fops = { | 3241 | static const struct file_operations vwsnd_mixer_fops = { |
3232 | .owner = THIS_MODULE, | 3242 | .owner = THIS_MODULE, |
3233 | .llseek = no_llseek, | 3243 | .llseek = no_llseek, |
3234 | .ioctl = vwsnd_mixer_ioctl, | 3244 | .unlocked_ioctl = vwsnd_mixer_ioctl, |
3235 | .open = vwsnd_mixer_open, | 3245 | .open = vwsnd_mixer_open, |
3236 | .release = vwsnd_mixer_release, | 3246 | .release = vwsnd_mixer_release, |
3237 | }; | 3247 | }; |
diff --git a/sound/oss/waveartist.c b/sound/oss/waveartist.c index e688dde6bbde..52468742d9f2 100644 --- a/sound/oss/waveartist.c +++ b/sound/oss/waveartist.c | |||
@@ -184,14 +184,8 @@ waveartist_iack(wavnc_info *devc) | |||
184 | static inline int | 184 | static inline int |
185 | waveartist_sleep(int timeout_ms) | 185 | waveartist_sleep(int timeout_ms) |
186 | { | 186 | { |
187 | unsigned int timeout = timeout_ms * 10 * HZ / 100; | 187 | unsigned int timeout = msecs_to_jiffies(timeout_ms*100); |
188 | 188 | return schedule_timeout_interruptible(timeout); | |
189 | do { | ||
190 | set_current_state(TASK_INTERRUPTIBLE); | ||
191 | timeout = schedule_timeout(timeout); | ||
192 | } while (timeout); | ||
193 | |||
194 | return 0; | ||
195 | } | 189 | } |
196 | 190 | ||
197 | static int | 191 | static int |
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index e7a8cd058efb..12e34653b8a8 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig | |||
@@ -207,12 +207,12 @@ config SND_CMIPCI | |||
207 | 207 | ||
208 | config SND_OXYGEN_LIB | 208 | config SND_OXYGEN_LIB |
209 | tristate | 209 | tristate |
210 | select SND_PCM | ||
211 | select SND_MPU401_UART | ||
212 | 210 | ||
213 | config SND_OXYGEN | 211 | config SND_OXYGEN |
214 | tristate "C-Media 8788 (Oxygen)" | 212 | tristate "C-Media 8788 (Oxygen)" |
215 | select SND_OXYGEN_LIB | 213 | select SND_OXYGEN_LIB |
214 | select SND_PCM | ||
215 | select SND_MPU401_UART | ||
216 | help | 216 | help |
217 | Say Y here to include support for sound cards based on the | 217 | Say Y here to include support for sound cards based on the |
218 | C-Media CMI8788 (Oxygen HD Audio) chip: | 218 | C-Media CMI8788 (Oxygen HD Audio) chip: |
@@ -581,6 +581,8 @@ config SND_HDSPM | |||
581 | config SND_HIFIER | 581 | config SND_HIFIER |
582 | tristate "TempoTec HiFier Fantasia" | 582 | tristate "TempoTec HiFier Fantasia" |
583 | select SND_OXYGEN_LIB | 583 | select SND_OXYGEN_LIB |
584 | select SND_PCM | ||
585 | select SND_MPU401_UART | ||
584 | help | 586 | help |
585 | Say Y here to include support for the MediaTek/TempoTec HiFier | 587 | Say Y here to include support for the MediaTek/TempoTec HiFier |
586 | Fantasia sound card. | 588 | Fantasia sound card. |
@@ -815,14 +817,17 @@ config SND_VIA82XX_MODEM | |||
815 | will be called snd-via82xx-modem. | 817 | will be called snd-via82xx-modem. |
816 | 818 | ||
817 | config SND_VIRTUOSO | 819 | config SND_VIRTUOSO |
818 | tristate "Asus Virtuoso 100/200 (Xonar)" | 820 | tristate "Asus Virtuoso 66/100/200 (Xonar)" |
819 | select SND_OXYGEN_LIB | 821 | select SND_OXYGEN_LIB |
822 | select SND_PCM | ||
823 | select SND_MPU401_UART | ||
824 | select SND_JACK if INPUT=y || INPUT=SND | ||
820 | help | 825 | help |
821 | Say Y here to include support for sound cards based on the | 826 | Say Y here to include support for sound cards based on the |
822 | Asus AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X, | 827 | Asus AV66/AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X, DS, |
823 | Essence ST (Deluxe), and Essence STX. | 828 | Essence ST (Deluxe), and Essence STX. |
824 | Support for the DS is experimental. | 829 | Support for the HDAV1.3 (Deluxe) is incomplete; for the |
825 | Support for the HDAV1.3 (Deluxe) is very experimental. | 830 | HDAV1.3 Slim and Xense, missing. |
826 | 831 | ||
827 | To compile this driver as a module, choose M here: the module | 832 | To compile this driver as a module, choose M here: the module |
828 | will be called snd-virtuoso. | 833 | will be called snd-virtuoso. |
diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c index 6cf1de8042e8..0e247cb90ecc 100644 --- a/sound/pci/als4000.c +++ b/sound/pci/als4000.c | |||
@@ -763,9 +763,9 @@ static void snd_als4000_configure(struct snd_sb *chip) | |||
763 | /* SPECS_PAGE: 39 */ | 763 | /* SPECS_PAGE: 39 */ |
764 | for (i = ALS4K_GCR91_DMA0_ADDR; i <= ALS4K_GCR96_DMA3_MODE_COUNT; ++i) | 764 | for (i = ALS4K_GCR91_DMA0_ADDR; i <= ALS4K_GCR96_DMA3_MODE_COUNT; ++i) |
765 | snd_als4k_gcr_write(chip, i, 0); | 765 | snd_als4k_gcr_write(chip, i, 0); |
766 | 766 | /* enable burst mode to prevent dropouts during high PCI bus usage */ | |
767 | snd_als4k_gcr_write(chip, ALS4K_GCR99_DMA_EMULATION_CTRL, | 767 | snd_als4k_gcr_write(chip, ALS4K_GCR99_DMA_EMULATION_CTRL, |
768 | snd_als4k_gcr_read(chip, ALS4K_GCR99_DMA_EMULATION_CTRL)); | 768 | (snd_als4k_gcr_read(chip, ALS4K_GCR99_DMA_EMULATION_CTRL) & ~0x07) | 0x04); |
769 | spin_unlock_irq(&chip->reg_lock); | 769 | spin_unlock_irq(&chip->reg_lock); |
770 | } | 770 | } |
771 | 771 | ||
diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c index 1db586af4f9c..c80b0b863c54 100644 --- a/sound/pci/asihpi/asihpi.c +++ b/sound/pci/asihpi/asihpi.c | |||
@@ -460,6 +460,7 @@ static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream, | |||
460 | struct snd_card_asihpi *card = snd_pcm_substream_chip(substream); | 460 | struct snd_card_asihpi *card = snd_pcm_substream_chip(substream); |
461 | int err; | 461 | int err; |
462 | u16 format; | 462 | u16 format; |
463 | int width; | ||
463 | unsigned int bytes_per_sec; | 464 | unsigned int bytes_per_sec; |
464 | 465 | ||
465 | print_hwparams(params); | 466 | print_hwparams(params); |
@@ -512,9 +513,10 @@ static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream, | |||
512 | dpcm->hpi_buffer_attached); | 513 | dpcm->hpi_buffer_attached); |
513 | } | 514 | } |
514 | bytes_per_sec = params_rate(params) * params_channels(params); | 515 | bytes_per_sec = params_rate(params) * params_channels(params); |
515 | bytes_per_sec *= snd_pcm_format_width(params_format(params)); | 516 | width = snd_pcm_format_width(params_format(params)); |
517 | bytes_per_sec *= width; | ||
516 | bytes_per_sec /= 8; | 518 | bytes_per_sec /= 8; |
517 | if (bytes_per_sec <= 0) | 519 | if (width < 0 || bytes_per_sec == 0) |
518 | return -EINVAL; | 520 | return -EINVAL; |
519 | 521 | ||
520 | dpcm->bytes_per_sec = bytes_per_sec; | 522 | dpcm->bytes_per_sec = bytes_per_sec; |
@@ -1383,7 +1385,7 @@ static char *asihpi_src_names[] = | |||
1383 | 1385 | ||
1384 | compile_time_assert( | 1386 | compile_time_assert( |
1385 | (ARRAY_SIZE(asihpi_src_names) == | 1387 | (ARRAY_SIZE(asihpi_src_names) == |
1386 | (HPI_SOURCENODE_LAST_INDEX-HPI_SOURCENODE_BASE+1)), | 1388 | (HPI_SOURCENODE_LAST_INDEX-HPI_SOURCENODE_NONE+1)), |
1387 | assert_src_names_size); | 1389 | assert_src_names_size); |
1388 | 1390 | ||
1389 | #if ASI_STYLE_NAMES | 1391 | #if ASI_STYLE_NAMES |
@@ -1414,7 +1416,7 @@ static char *asihpi_dst_names[] = | |||
1414 | 1416 | ||
1415 | compile_time_assert( | 1417 | compile_time_assert( |
1416 | (ARRAY_SIZE(asihpi_dst_names) == | 1418 | (ARRAY_SIZE(asihpi_dst_names) == |
1417 | (HPI_DESTNODE_LAST_INDEX-HPI_DESTNODE_BASE+1)), | 1419 | (HPI_DESTNODE_LAST_INDEX-HPI_DESTNODE_NONE+1)), |
1418 | assert_dst_names_size); | 1420 | assert_dst_names_size); |
1419 | 1421 | ||
1420 | static inline int ctl_add(struct snd_card *card, struct snd_kcontrol_new *ctl, | 1422 | static inline int ctl_add(struct snd_card *card, struct snd_kcontrol_new *ctl, |
@@ -2171,7 +2173,7 @@ static int snd_asihpi_mux_info(struct snd_kcontrol *kcontrol, | |||
2171 | &src_node_type, &src_node_index); | 2173 | &src_node_type, &src_node_index); |
2172 | 2174 | ||
2173 | sprintf(uinfo->value.enumerated.name, "%s %d", | 2175 | sprintf(uinfo->value.enumerated.name, "%s %d", |
2174 | asihpi_src_names[src_node_type - HPI_SOURCENODE_BASE], | 2176 | asihpi_src_names[src_node_type - HPI_SOURCENODE_NONE], |
2175 | src_node_index); | 2177 | src_node_index); |
2176 | return 0; | 2178 | return 0; |
2177 | } | 2179 | } |
@@ -2603,8 +2605,8 @@ static int __devinit snd_card_asihpi_mixer_new(struct snd_card_asihpi *asihpi) | |||
2603 | 2605 | ||
2604 | } | 2606 | } |
2605 | 2607 | ||
2606 | hpi_ctl.src_node_type -= HPI_SOURCENODE_BASE; | 2608 | hpi_ctl.src_node_type -= HPI_SOURCENODE_NONE; |
2607 | hpi_ctl.dst_node_type -= HPI_DESTNODE_BASE; | 2609 | hpi_ctl.dst_node_type -= HPI_DESTNODE_NONE; |
2608 | 2610 | ||
2609 | /* ASI50xx in SSX mode has multiple meters on the same node. | 2611 | /* ASI50xx in SSX mode has multiple meters on the same node. |
2610 | Use subindex to create distinct ALSA controls | 2612 | Use subindex to create distinct ALSA controls |
diff --git a/sound/pci/asihpi/hpi.h b/sound/pci/asihpi/hpi.h index 0173bbe62b67..23399d02f666 100644 --- a/sound/pci/asihpi/hpi.h +++ b/sound/pci/asihpi/hpi.h | |||
@@ -50,7 +50,8 @@ i.e 3.05.02 is a development version | |||
50 | #define HPI_VER_RELEASE(v) ((int)(v & 0xFF)) | 50 | #define HPI_VER_RELEASE(v) ((int)(v & 0xFF)) |
51 | 51 | ||
52 | /* Use single digits for versions less that 10 to avoid octal. */ | 52 | /* Use single digits for versions less that 10 to avoid octal. */ |
53 | #define HPI_VER HPI_VERSION_CONSTRUCTOR(4L, 3, 25) | 53 | #define HPI_VER HPI_VERSION_CONSTRUCTOR(4L, 4, 1) |
54 | #define HPI_VER_STRING "4.04.01" | ||
54 | 55 | ||
55 | /* Library version as documented in hpi-api-versions.txt */ | 56 | /* Library version as documented in hpi-api-versions.txt */ |
56 | #define HPI_LIB_VER HPI_VERSION_CONSTRUCTOR(9, 0, 0) | 57 | #define HPI_LIB_VER HPI_VERSION_CONSTRUCTOR(9, 0, 0) |
@@ -203,8 +204,6 @@ enum HPI_SOURCENODES { | |||
203 | exists on a destination node can be searched for using a source | 204 | exists on a destination node can be searched for using a source |
204 | node value of either 0, or HPI_SOURCENODE_NONE */ | 205 | node value of either 0, or HPI_SOURCENODE_NONE */ |
205 | HPI_SOURCENODE_NONE = 100, | 206 | HPI_SOURCENODE_NONE = 100, |
206 | /** \deprecated Use HPI_SOURCENODE_NONE instead. */ | ||
207 | HPI_SOURCENODE_BASE = 100, | ||
208 | /** Out Stream (Play) node. */ | 207 | /** Out Stream (Play) node. */ |
209 | HPI_SOURCENODE_OSTREAM = 101, | 208 | HPI_SOURCENODE_OSTREAM = 101, |
210 | /** Line in node - could be analog, AES/EBU or network. */ | 209 | /** Line in node - could be analog, AES/EBU or network. */ |
@@ -235,8 +234,6 @@ enum HPI_DESTNODES { | |||
235 | exists on a source node can be searched for using a destination | 234 | exists on a source node can be searched for using a destination |
236 | node value of either 0, or HPI_DESTNODE_NONE */ | 235 | node value of either 0, or HPI_DESTNODE_NONE */ |
237 | HPI_DESTNODE_NONE = 200, | 236 | HPI_DESTNODE_NONE = 200, |
238 | /** \deprecated Use HPI_DESTNODE_NONE instead. */ | ||
239 | HPI_DESTNODE_BASE = 200, | ||
240 | /** In Stream (Record) node. */ | 237 | /** In Stream (Record) node. */ |
241 | HPI_DESTNODE_ISTREAM = 201, | 238 | HPI_DESTNODE_ISTREAM = 201, |
242 | HPI_DESTNODE_LINEOUT = 202, /**< line out node. */ | 239 | HPI_DESTNODE_LINEOUT = 202, /**< line out node. */ |
@@ -432,7 +429,18 @@ Property 2 - adapter can do stream grouping (supports SSX2) | |||
432 | Property 1 - adapter can do samplerate conversion (MRX) | 429 | Property 1 - adapter can do samplerate conversion (MRX) |
433 | Property 2 - adapter can do timestretch (TSX) | 430 | Property 2 - adapter can do timestretch (TSX) |
434 | */ | 431 | */ |
435 | HPI_ADAPTER_PROPERTY_CAPS2 = 269 | 432 | HPI_ADAPTER_PROPERTY_CAPS2 = 269, |
433 | |||
434 | /** Readonly adapter sync header connection count. | ||
435 | */ | ||
436 | HPI_ADAPTER_PROPERTY_SYNC_HEADER_CONNECTIONS = 270, | ||
437 | /** Readonly supports SSX2 property. | ||
438 | Indicates the adapter supports SSX2 in some mode setting. The | ||
439 | return value is true (1) or false (0). If the current adapter | ||
440 | mode is MONO SSX2 is disabled, even though this property will | ||
441 | return true. | ||
442 | */ | ||
443 | HPI_ADAPTER_PROPERTY_SUPPORTS_SSX2 = 271 | ||
436 | }; | 444 | }; |
437 | 445 | ||
438 | /** Adapter mode commands | 446 | /** Adapter mode commands |
@@ -813,8 +821,6 @@ enum HPI_SAMPLECLOCK_SOURCES { | |||
813 | /** The sampleclock output is derived from its local samplerate generator. | 821 | /** The sampleclock output is derived from its local samplerate generator. |
814 | The local samplerate may be set using HPI_SampleClock_SetLocalRate(). */ | 822 | The local samplerate may be set using HPI_SampleClock_SetLocalRate(). */ |
815 | HPI_SAMPLECLOCK_SOURCE_LOCAL = 1, | 823 | HPI_SAMPLECLOCK_SOURCE_LOCAL = 1, |
816 | /** \deprecated Use HPI_SAMPLECLOCK_SOURCE_LOCAL instead */ | ||
817 | HPI_SAMPLECLOCK_SOURCE_ADAPTER = 1, | ||
818 | /** The adapter is clocked from a dedicated AES/EBU SampleClock input.*/ | 824 | /** The adapter is clocked from a dedicated AES/EBU SampleClock input.*/ |
819 | HPI_SAMPLECLOCK_SOURCE_AESEBU_SYNC = 2, | 825 | HPI_SAMPLECLOCK_SOURCE_AESEBU_SYNC = 2, |
820 | /** From external wordclock connector */ | 826 | /** From external wordclock connector */ |
@@ -825,10 +831,6 @@ enum HPI_SAMPLECLOCK_SOURCES { | |||
825 | HPI_SAMPLECLOCK_SOURCE_SMPTE = 5, | 831 | HPI_SAMPLECLOCK_SOURCE_SMPTE = 5, |
826 | /** One of the aesebu inputs */ | 832 | /** One of the aesebu inputs */ |
827 | HPI_SAMPLECLOCK_SOURCE_AESEBU_INPUT = 6, | 833 | HPI_SAMPLECLOCK_SOURCE_AESEBU_INPUT = 6, |
828 | /** \deprecated The first aesebu input with a valid signal | ||
829 | Superseded by separate Auto enable flag | ||
830 | */ | ||
831 | HPI_SAMPLECLOCK_SOURCE_AESEBU_AUTO = 7, | ||
832 | /** From a network interface e.g. Cobranet or Livewire at either 48 or 96kHz */ | 834 | /** From a network interface e.g. Cobranet or Livewire at either 48 or 96kHz */ |
833 | HPI_SAMPLECLOCK_SOURCE_NETWORK = 8, | 835 | HPI_SAMPLECLOCK_SOURCE_NETWORK = 8, |
834 | /** From previous adjacent module (ASI2416 only)*/ | 836 | /** From previous adjacent module (ASI2416 only)*/ |
@@ -1015,8 +1017,6 @@ enum HPI_ERROR_CODES { | |||
1015 | HPI_ERROR_CONTROL_DISABLED = 404, | 1017 | HPI_ERROR_CONTROL_DISABLED = 404, |
1016 | /** I2C transaction failed due to a missing ACK. */ | 1018 | /** I2C transaction failed due to a missing ACK. */ |
1017 | HPI_ERROR_CONTROL_I2C_MISSING_ACK = 405, | 1019 | HPI_ERROR_CONTROL_I2C_MISSING_ACK = 405, |
1018 | /** Control attribute is valid, but not supported by this hardware. */ | ||
1019 | HPI_ERROR_UNSUPPORTED_CONTROL_ATTRIBUTE = 406, | ||
1020 | /** Control is busy, or coming out of | 1020 | /** Control is busy, or coming out of |
1021 | reset and cannot be accessed at this time. */ | 1021 | reset and cannot be accessed at this time. */ |
1022 | HPI_ERROR_CONTROL_NOT_READY = 407, | 1022 | HPI_ERROR_CONTROL_NOT_READY = 407, |
@@ -1827,13 +1827,41 @@ u16 hpi_parametricEQ__get_coeffs(const struct hpi_hsubsys *ph_subsys, | |||
1827 | Compressor Expander control | 1827 | Compressor Expander control |
1828 | *******************************/ | 1828 | *******************************/ |
1829 | 1829 | ||
1830 | u16 hpi_compander_set(const struct hpi_hsubsys *ph_subsys, u32 h_control, | 1830 | u16 hpi_compander_set_enable(const struct hpi_hsubsys *ph_subsys, |
1831 | u16 attack, u16 decay, short ratio100, short threshold0_01dB, | 1831 | u32 h_control, u32 on); |
1832 | short makeup_gain0_01dB); | 1832 | |
1833 | u16 hpi_compander_get_enable(const struct hpi_hsubsys *ph_subsys, | ||
1834 | u32 h_control, u32 *pon); | ||
1835 | |||
1836 | u16 hpi_compander_set_makeup_gain(const struct hpi_hsubsys *ph_subsys, | ||
1837 | u32 h_control, short makeup_gain0_01dB); | ||
1838 | |||
1839 | u16 hpi_compander_get_makeup_gain(const struct hpi_hsubsys *ph_subsys, | ||
1840 | u32 h_control, short *pn_makeup_gain0_01dB); | ||
1841 | |||
1842 | u16 hpi_compander_set_attack_time_constant(const struct hpi_hsubsys | ||
1843 | *ph_subsys, u32 h_control, u32 index, u32 attack); | ||
1844 | |||
1845 | u16 hpi_compander_get_attack_time_constant(const struct hpi_hsubsys | ||
1846 | *ph_subsys, u32 h_control, u32 index, u32 *pw_attack); | ||
1847 | |||
1848 | u16 hpi_compander_set_decay_time_constant(const struct hpi_hsubsys *ph_subsys, | ||
1849 | u32 h_control, u32 index, u32 decay); | ||
1850 | |||
1851 | u16 hpi_compander_get_decay_time_constant(const struct hpi_hsubsys *ph_subsys, | ||
1852 | u32 h_control, u32 index, u32 *pw_decay); | ||
1853 | |||
1854 | u16 hpi_compander_set_threshold(const struct hpi_hsubsys *ph_subsys, | ||
1855 | u32 h_control, u32 index, short threshold0_01dB); | ||
1856 | |||
1857 | u16 hpi_compander_get_threshold(const struct hpi_hsubsys *ph_subsys, | ||
1858 | u32 h_control, u32 index, short *pn_threshold0_01dB); | ||
1859 | |||
1860 | u16 hpi_compander_set_ratio(const struct hpi_hsubsys *ph_subsys, | ||
1861 | u32 h_control, u32 index, u32 ratio100); | ||
1833 | 1862 | ||
1834 | u16 hpi_compander_get(const struct hpi_hsubsys *ph_subsys, u32 h_control, | 1863 | u16 hpi_compander_get_ratio(const struct hpi_hsubsys *ph_subsys, |
1835 | u16 *pw_attack, u16 *pw_decay, short *pw_ratio100, | 1864 | u32 h_control, u32 index, u32 *pw_ratio100); |
1836 | short *pn_threshold0_01dB, short *pn_makeup_gain0_01dB); | ||
1837 | 1865 | ||
1838 | /******************************* | 1866 | /******************************* |
1839 | Cobranet HMI control | 1867 | Cobranet HMI control |
diff --git a/sound/pci/asihpi/hpi6000.c b/sound/pci/asihpi/hpi6000.c index 12dab5e4892c..f7e374ec4414 100644 --- a/sound/pci/asihpi/hpi6000.c +++ b/sound/pci/asihpi/hpi6000.c | |||
@@ -687,6 +687,7 @@ static short hpi6000_adapter_boot_load_dsp(struct hpi_adapter_obj *pao, | |||
687 | switch (pao->pci.subsys_device_id) { | 687 | switch (pao->pci.subsys_device_id) { |
688 | case 0x5100: | 688 | case 0x5100: |
689 | case 0x5110: /* ASI5100 revB or higher with C6711D */ | 689 | case 0x5110: /* ASI5100 revB or higher with C6711D */ |
690 | case 0x5200: /* ASI5200 PC_ie version of ASI5100 */ | ||
690 | case 0x6100: | 691 | case 0x6100: |
691 | case 0x6200: | 692 | case 0x6200: |
692 | boot_load_family = HPI_ADAPTER_FAMILY_ASI(0x6200); | 693 | boot_load_family = HPI_ADAPTER_FAMILY_ASI(0x6200); |
@@ -1133,6 +1134,12 @@ static short hpi6000_adapter_boot_load_dsp(struct hpi_adapter_obj *pao, | |||
1133 | subsys_device_id) == | 1134 | subsys_device_id) == |
1134 | HPI_ADAPTER_FAMILY_ASI(0x5100)) | 1135 | HPI_ADAPTER_FAMILY_ASI(0x5100)) |
1135 | mask = 0x00000000L; | 1136 | mask = 0x00000000L; |
1137 | /* ASI5200 uses AX6 code, */ | ||
1138 | /* but has no PLD r/w register to test */ | ||
1139 | if (HPI_ADAPTER_FAMILY_ASI(pao->pci. | ||
1140 | subsys_device_id) == | ||
1141 | HPI_ADAPTER_FAMILY_ASI(0x5200)) | ||
1142 | mask = 0x00000000L; | ||
1136 | break; | 1143 | break; |
1137 | case HPI_ADAPTER_FAMILY_ASI(0x8800): | 1144 | case HPI_ADAPTER_FAMILY_ASI(0x8800): |
1138 | /* ASI8800 has 16bit path to FPGA */ | 1145 | /* ASI8800 has 16bit path to FPGA */ |
diff --git a/sound/pci/asihpi/hpi6205.c b/sound/pci/asihpi/hpi6205.c index 3b4413448226..22c5fc625533 100644 --- a/sound/pci/asihpi/hpi6205.c +++ b/sound/pci/asihpi/hpi6205.c | |||
@@ -941,8 +941,7 @@ static void outstream_host_buffer_free(struct hpi_adapter_obj *pao, | |||
941 | 941 | ||
942 | } | 942 | } |
943 | 943 | ||
944 | static u32 outstream_get_space_available(struct hpi_hostbuffer_status | 944 | static u32 outstream_get_space_available(struct hpi_hostbuffer_status *status) |
945 | *status) | ||
946 | { | 945 | { |
947 | return status->size_in_bytes - (status->host_index - | 946 | return status->size_in_bytes - (status->host_index - |
948 | status->dSP_index); | 947 | status->dSP_index); |
@@ -987,6 +986,10 @@ static void outstream_write(struct hpi_adapter_obj *pao, | |||
987 | /* write it */ | 986 | /* write it */ |
988 | phm->function = HPI_OSTREAM_WRITE; | 987 | phm->function = HPI_OSTREAM_WRITE; |
989 | hw_message(pao, phm, phr); | 988 | hw_message(pao, phm, phr); |
989 | |||
990 | if (phr->error) | ||
991 | return; | ||
992 | |||
990 | /* update status information that the DSP would typically | 993 | /* update status information that the DSP would typically |
991 | * update (and will update next time the DSP | 994 | * update (and will update next time the DSP |
992 | * buffer update task reads data from the host BBM buffer) | 995 | * buffer update task reads data from the host BBM buffer) |
diff --git a/sound/pci/asihpi/hpi_internal.h b/sound/pci/asihpi/hpi_internal.h index fdd0ce02aa68..16f502d459de 100644 --- a/sound/pci/asihpi/hpi_internal.h +++ b/sound/pci/asihpi/hpi_internal.h | |||
@@ -104,9 +104,9 @@ typedef void hpi_handler_func(struct hpi_message *, struct hpi_response *); | |||
104 | #define STR_ROLE_FIELD_MAX 255U | 104 | #define STR_ROLE_FIELD_MAX 255U |
105 | 105 | ||
106 | struct hpi_entity_str { | 106 | struct hpi_entity_str { |
107 | uint16_t size; | 107 | u16 size; |
108 | uint8_t type; | 108 | u8 type; |
109 | uint8_t role; | 109 | u8 role; |
110 | }; | 110 | }; |
111 | 111 | ||
112 | #if defined(_MSC_VER) | 112 | #if defined(_MSC_VER) |
@@ -119,11 +119,11 @@ struct hpi_entity { | |||
119 | #if ! defined(HPI_OS_DSP_C6000) || (defined(HPI_OS_DSP_C6000) && (__TI_COMPILER_VERSION__ > 6000008)) | 119 | #if ! defined(HPI_OS_DSP_C6000) || (defined(HPI_OS_DSP_C6000) && (__TI_COMPILER_VERSION__ > 6000008)) |
120 | /* DSP C6000 compiler v6.0.8 and lower | 120 | /* DSP C6000 compiler v6.0.8 and lower |
121 | do not support flexible array member */ | 121 | do not support flexible array member */ |
122 | uint8_t value[]; | 122 | u8 value[]; |
123 | #else | 123 | #else |
124 | /* NOTE! Using sizeof(struct hpi_entity) will give erroneous results */ | 124 | /* NOTE! Using sizeof(struct hpi_entity) will give erroneous results */ |
125 | #define HPI_INTERNAL_WARN_ABOUT_ENTITY_VALUE | 125 | #define HPI_INTERNAL_WARN_ABOUT_ENTITY_VALUE |
126 | uint8_t value[1]; | 126 | u8 value[1]; |
127 | #endif | 127 | #endif |
128 | }; | 128 | }; |
129 | 129 | ||
@@ -142,12 +142,15 @@ enum HPI_BUSES { | |||
142 | /******************************************* CONTROL ATTRIBUTES ****/ | 142 | /******************************************* CONTROL ATTRIBUTES ****/ |
143 | /* (in order of control type ID */ | 143 | /* (in order of control type ID */ |
144 | 144 | ||
145 | /* This allows for 255 control types, 256 unique attributes each */ | 145 | /* This allows for 255 control types, 256 unique attributes each */ |
146 | #define HPI_CTL_ATTR(ctl, ai) (HPI_CONTROL_##ctl * 0x100 + ai) | 146 | #define HPI_CTL_ATTR(ctl, ai) (HPI_CONTROL_##ctl * 0x100 + ai) |
147 | 147 | ||
148 | /* Get the sub-index of the attribute for a control type */ | 148 | /* Get the sub-index of the attribute for a control type */ |
149 | #define HPI_CTL_ATTR_INDEX(i) (i&0xff) | 149 | #define HPI_CTL_ATTR_INDEX(i) (i&0xff) |
150 | 150 | ||
151 | /* Extract the control from the control attribute */ | ||
152 | #define HPI_CTL_ATTR_CONTROL(i) (i>>8) | ||
153 | |||
151 | /* Generic control attributes. */ | 154 | /* Generic control attributes. */ |
152 | 155 | ||
153 | /** Enable a control. | 156 | /** Enable a control. |
@@ -311,8 +314,7 @@ Used for HPI_ChannelModeSet/Get() | |||
311 | /* Microphone control attributes */ | 314 | /* Microphone control attributes */ |
312 | #define HPI_MICROPHONE_PHANTOM_POWER HPI_CTL_ATTR(MICROPHONE, 1) | 315 | #define HPI_MICROPHONE_PHANTOM_POWER HPI_CTL_ATTR(MICROPHONE, 1) |
313 | 316 | ||
314 | /** Equalizer control attributes | 317 | /** Equalizer control attributes */ |
315 | */ | ||
316 | /** Used to get number of filters in an EQ. (Can't set) */ | 318 | /** Used to get number of filters in an EQ. (Can't set) */ |
317 | #define HPI_EQUALIZER_NUM_FILTERS HPI_CTL_ATTR(EQUALIZER, 1) | 319 | #define HPI_EQUALIZER_NUM_FILTERS HPI_CTL_ATTR(EQUALIZER, 1) |
318 | /** Set/get the filter by type, freq, Q, gain */ | 320 | /** Set/get the filter by type, freq, Q, gain */ |
@@ -320,13 +322,15 @@ Used for HPI_ChannelModeSet/Get() | |||
320 | /** Get the biquad coefficients */ | 322 | /** Get the biquad coefficients */ |
321 | #define HPI_EQUALIZER_COEFFICIENTS HPI_CTL_ATTR(EQUALIZER, 3) | 323 | #define HPI_EQUALIZER_COEFFICIENTS HPI_CTL_ATTR(EQUALIZER, 3) |
322 | 324 | ||
323 | #define HPI_COMPANDER_PARAMS HPI_CTL_ATTR(COMPANDER, 1) | 325 | /* Note compander also uses HPI_GENERIC_ENABLE */ |
326 | #define HPI_COMPANDER_PARAMS HPI_CTL_ATTR(COMPANDER, 1) | ||
327 | #define HPI_COMPANDER_MAKEUPGAIN HPI_CTL_ATTR(COMPANDER, 2) | ||
328 | #define HPI_COMPANDER_THRESHOLD HPI_CTL_ATTR(COMPANDER, 3) | ||
329 | #define HPI_COMPANDER_RATIO HPI_CTL_ATTR(COMPANDER, 4) | ||
330 | #define HPI_COMPANDER_ATTACK HPI_CTL_ATTR(COMPANDER, 5) | ||
331 | #define HPI_COMPANDER_DECAY HPI_CTL_ATTR(COMPANDER, 6) | ||
324 | 332 | ||
325 | /* Cobranet control attributes. | 333 | /* Cobranet control attributes. */ |
326 | MUST be distinct from all other control attributes. | ||
327 | This is so that host side processing can easily identify a Cobranet control | ||
328 | and apply additional host side operations (like copying data) as required. | ||
329 | */ | ||
330 | #define HPI_COBRANET_SET HPI_CTL_ATTR(COBRANET, 1) | 334 | #define HPI_COBRANET_SET HPI_CTL_ATTR(COBRANET, 1) |
331 | #define HPI_COBRANET_GET HPI_CTL_ATTR(COBRANET, 2) | 335 | #define HPI_COBRANET_GET HPI_CTL_ATTR(COBRANET, 2) |
332 | #define HPI_COBRANET_SET_DATA HPI_CTL_ATTR(COBRANET, 3) | 336 | #define HPI_COBRANET_SET_DATA HPI_CTL_ATTR(COBRANET, 3) |
@@ -1512,11 +1516,11 @@ struct hpi_control_cache_single { | |||
1512 | struct hpi_control_cache_info i; | 1516 | struct hpi_control_cache_info i; |
1513 | union { | 1517 | union { |
1514 | struct { /* volume */ | 1518 | struct { /* volume */ |
1515 | u16 an_log[2]; | 1519 | short an_log[2]; |
1516 | } v; | 1520 | } v; |
1517 | struct { /* peak meter */ | 1521 | struct { /* peak meter */ |
1518 | u16 an_log_peak[2]; | 1522 | short an_log_peak[2]; |
1519 | u16 an_logRMS[2]; | 1523 | short an_logRMS[2]; |
1520 | } p; | 1524 | } p; |
1521 | struct { /* channel mode */ | 1525 | struct { /* channel mode */ |
1522 | u16 mode; | 1526 | u16 mode; |
@@ -1526,7 +1530,7 @@ struct hpi_control_cache_single { | |||
1526 | u16 source_node_index; | 1530 | u16 source_node_index; |
1527 | } x; | 1531 | } x; |
1528 | struct { /* level/trim */ | 1532 | struct { /* level/trim */ |
1529 | u16 an_log[2]; | 1533 | short an_log[2]; |
1530 | } l; | 1534 | } l; |
1531 | struct { /* tuner - partial caching. | 1535 | struct { /* tuner - partial caching. |
1532 | some attributes go to the DSP. */ | 1536 | some attributes go to the DSP. */ |
diff --git a/sound/pci/asihpi/hpicmn.c b/sound/pci/asihpi/hpicmn.c index fcd64539d9ef..dda4f1c6f658 100644 --- a/sound/pci/asihpi/hpicmn.c +++ b/sound/pci/asihpi/hpicmn.c | |||
@@ -353,7 +353,12 @@ short hpi_check_control_cache(struct hpi_control_cache *p_cache, | |||
353 | phr->u.c.param1 = pC->u.t.band; | 353 | phr->u.c.param1 = pC->u.t.band; |
354 | else if ((phm->u.c.attribute == HPI_TUNER_LEVEL) | 354 | else if ((phm->u.c.attribute == HPI_TUNER_LEVEL) |
355 | && (phm->u.c.param1 == HPI_TUNER_LEVEL_AVERAGE)) | 355 | && (phm->u.c.param1 == HPI_TUNER_LEVEL_AVERAGE)) |
356 | phr->u.c.param1 = pC->u.t.level; | 356 | if (pC->u.t.level == HPI_ERROR_ILLEGAL_CACHE_VALUE) { |
357 | phr->u.c.param1 = 0; | ||
358 | phr->error = | ||
359 | HPI_ERROR_INVALID_CONTROL_ATTRIBUTE; | ||
360 | } else | ||
361 | phr->u.c.param1 = pC->u.t.level; | ||
357 | else | 362 | else |
358 | found = 0; | 363 | found = 0; |
359 | break; | 364 | break; |
@@ -397,7 +402,8 @@ short hpi_check_control_cache(struct hpi_control_cache *p_cache, | |||
397 | if (pC->u.clk.source_index == | 402 | if (pC->u.clk.source_index == |
398 | HPI_ERROR_ILLEGAL_CACHE_VALUE) { | 403 | HPI_ERROR_ILLEGAL_CACHE_VALUE) { |
399 | phr->u.c.param1 = 0; | 404 | phr->u.c.param1 = 0; |
400 | phr->error = HPI_ERROR_INVALID_OPERATION; | 405 | phr->error = |
406 | HPI_ERROR_INVALID_CONTROL_ATTRIBUTE; | ||
401 | } else | 407 | } else |
402 | phr->u.c.param1 = pC->u.clk.source_index; | 408 | phr->u.c.param1 = pC->u.clk.source_index; |
403 | } else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SAMPLERATE) | 409 | } else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SAMPLERATE) |
diff --git a/sound/pci/asihpi/hpidebug.c b/sound/pci/asihpi/hpidebug.c index 4cd85a401b34..949836ec913a 100644 --- a/sound/pci/asihpi/hpidebug.c +++ b/sound/pci/asihpi/hpidebug.c | |||
@@ -111,7 +111,7 @@ make_treenode_from_array(hpi_control_type_strings, HPI_CONTROL_TYPE_STRINGS) | |||
111 | &hpi_profile_strings,\ | 111 | &hpi_profile_strings,\ |
112 | &hpi_control_strings, \ | 112 | &hpi_control_strings, \ |
113 | &hpi_asyncevent_strings \ | 113 | &hpi_asyncevent_strings \ |
114 | }; | 114 | } |
115 | make_treenode_from_array(hpi_function_strings, HPI_FUNCTION_STRINGS) | 115 | make_treenode_from_array(hpi_function_strings, HPI_FUNCTION_STRINGS) |
116 | 116 | ||
117 | compile_time_assert(HPI_OBJ_MAXINDEX == 14, obj_list_doesnt_match); | 117 | compile_time_assert(HPI_OBJ_MAXINDEX == 14, obj_list_doesnt_match); |
diff --git a/sound/pci/asihpi/hpidebug.h b/sound/pci/asihpi/hpidebug.h index 44dccadcc25b..a2f0952a99f0 100644 --- a/sound/pci/asihpi/hpidebug.h +++ b/sound/pci/asihpi/hpidebug.h | |||
@@ -356,7 +356,7 @@ compile_time_assert((HPI_CONTROL_LAST_INDEX + 1 == 27), | |||
356 | "HPI_SOURCENODE_ADAPTER" \ | 356 | "HPI_SOURCENODE_ADAPTER" \ |
357 | } | 357 | } |
358 | 358 | ||
359 | compile_time_assert((HPI_SOURCENODE_LAST_INDEX - HPI_SOURCENODE_BASE + 1) == | 359 | compile_time_assert((HPI_SOURCENODE_LAST_INDEX - HPI_SOURCENODE_NONE + 1) == |
360 | (12), sourcenode_strings_match_defs); | 360 | (12), sourcenode_strings_match_defs); |
361 | 361 | ||
362 | #define HPI_DESTNODE_STRINGS \ | 362 | #define HPI_DESTNODE_STRINGS \ |
@@ -370,7 +370,7 @@ compile_time_assert((HPI_SOURCENODE_LAST_INDEX - HPI_SOURCENODE_BASE + 1) == | |||
370 | "HPI_DESTNODE_COBRANET", \ | 370 | "HPI_DESTNODE_COBRANET", \ |
371 | "HPI_DESTNODE_ANALOG" \ | 371 | "HPI_DESTNODE_ANALOG" \ |
372 | } | 372 | } |
373 | compile_time_assert((HPI_DESTNODE_LAST_INDEX - HPI_DESTNODE_BASE + 1) == (8), | 373 | compile_time_assert((HPI_DESTNODE_LAST_INDEX - HPI_DESTNODE_NONE + 1) == (8), |
374 | destnode_strings_match_defs); | 374 | destnode_strings_match_defs); |
375 | 375 | ||
376 | #define HPI_CONTROL_CHANNEL_MODE_STRINGS \ | 376 | #define HPI_CONTROL_CHANNEL_MODE_STRINGS \ |
diff --git a/sound/pci/asihpi/hpifunc.c b/sound/pci/asihpi/hpifunc.c index 298eef3e20e9..1e92eb6dd509 100644 --- a/sound/pci/asihpi/hpifunc.c +++ b/sound/pci/asihpi/hpifunc.c | |||
@@ -96,8 +96,7 @@ void hpi_stream_response_to_legacy(struct hpi_stream_res *pSR) | |||
96 | 96 | ||
97 | static struct hpi_hsubsys gh_subsys; | 97 | static struct hpi_hsubsys gh_subsys; |
98 | 98 | ||
99 | struct hpi_hsubsys *hpi_subsys_create(void | 99 | struct hpi_hsubsys *hpi_subsys_create(void) |
100 | ) | ||
101 | { | 100 | { |
102 | struct hpi_message hm; | 101 | struct hpi_message hm; |
103 | struct hpi_response hr; | 102 | struct hpi_response hr; |
@@ -302,6 +301,7 @@ u16 hpi_adapter_set_mode_ex(const struct hpi_hsubsys *ph_subsys, | |||
302 | { | 301 | { |
303 | struct hpi_message hm; | 302 | struct hpi_message hm; |
304 | struct hpi_response hr; | 303 | struct hpi_response hr; |
304 | |||
305 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER, | 305 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER, |
306 | HPI_ADAPTER_SET_MODE); | 306 | HPI_ADAPTER_SET_MODE); |
307 | hm.adapter_index = adapter_index; | 307 | hm.adapter_index = adapter_index; |
@@ -510,7 +510,7 @@ u16 hpi_adapter_debug_read(const struct hpi_hsubsys *ph_subsys, | |||
510 | hm.adapter_index = adapter_index; | 510 | hm.adapter_index = adapter_index; |
511 | hm.u.ax.debug_read.dsp_address = dsp_address; | 511 | hm.u.ax.debug_read.dsp_address = dsp_address; |
512 | 512 | ||
513 | if (*count_bytes > sizeof(hr.u.bytes)) | 513 | if (*count_bytes > (int)sizeof(hr.u.bytes)) |
514 | *count_bytes = sizeof(hr.u.bytes); | 514 | *count_bytes = sizeof(hr.u.bytes); |
515 | 515 | ||
516 | hm.u.ax.debug_read.count_bytes = *count_bytes; | 516 | hm.u.ax.debug_read.count_bytes = *count_bytes; |
@@ -976,6 +976,7 @@ u16 hpi_outstream_ancillary_read(const struct hpi_hsubsys *ph_subsys, | |||
976 | { | 976 | { |
977 | struct hpi_message hm; | 977 | struct hpi_message hm; |
978 | struct hpi_response hr; | 978 | struct hpi_response hr; |
979 | |||
979 | hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM, | 980 | hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM, |
980 | HPI_OSTREAM_ANC_READ); | 981 | HPI_OSTREAM_ANC_READ); |
981 | u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index); | 982 | u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index); |
@@ -1581,6 +1582,7 @@ u16 hpi_control_param_set(const struct hpi_hsubsys *ph_subsys, | |||
1581 | { | 1582 | { |
1582 | struct hpi_message hm; | 1583 | struct hpi_message hm; |
1583 | struct hpi_response hr; | 1584 | struct hpi_response hr; |
1585 | |||
1584 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, | 1586 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, |
1585 | HPI_CONTROL_SET_STATE); | 1587 | HPI_CONTROL_SET_STATE); |
1586 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); | 1588 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); |
@@ -1591,6 +1593,22 @@ u16 hpi_control_param_set(const struct hpi_hsubsys *ph_subsys, | |||
1591 | return hr.error; | 1593 | return hr.error; |
1592 | } | 1594 | } |
1593 | 1595 | ||
1596 | static u16 hpi_control_log_set2(u32 h_control, u16 attrib, short sv0, | ||
1597 | short sv1) | ||
1598 | { | ||
1599 | struct hpi_message hm; | ||
1600 | struct hpi_response hr; | ||
1601 | |||
1602 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, | ||
1603 | HPI_CONTROL_SET_STATE); | ||
1604 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); | ||
1605 | hm.u.c.attribute = attrib; | ||
1606 | hm.u.c.an_log_value[0] = sv0; | ||
1607 | hm.u.c.an_log_value[1] = sv1; | ||
1608 | hpi_send_recv(&hm, &hr); | ||
1609 | return hr.error; | ||
1610 | } | ||
1611 | |||
1594 | static | 1612 | static |
1595 | u16 hpi_control_param_get(const struct hpi_hsubsys *ph_subsys, | 1613 | u16 hpi_control_param_get(const struct hpi_hsubsys *ph_subsys, |
1596 | const u32 h_control, const u16 attrib, u32 param1, u32 param2, | 1614 | const u32 h_control, const u16 attrib, u32 param1, u32 param2, |
@@ -1598,6 +1616,7 @@ u16 hpi_control_param_get(const struct hpi_hsubsys *ph_subsys, | |||
1598 | { | 1616 | { |
1599 | struct hpi_message hm; | 1617 | struct hpi_message hm; |
1600 | struct hpi_response hr; | 1618 | struct hpi_response hr; |
1619 | |||
1601 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, | 1620 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, |
1602 | HPI_CONTROL_GET_STATE); | 1621 | HPI_CONTROL_GET_STATE); |
1603 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); | 1622 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); |
@@ -1605,8 +1624,8 @@ u16 hpi_control_param_get(const struct hpi_hsubsys *ph_subsys, | |||
1605 | hm.u.c.param1 = param1; | 1624 | hm.u.c.param1 = param1; |
1606 | hm.u.c.param2 = param2; | 1625 | hm.u.c.param2 = param2; |
1607 | hpi_send_recv(&hm, &hr); | 1626 | hpi_send_recv(&hm, &hr); |
1608 | if (pparam1) | 1627 | |
1609 | *pparam1 = hr.u.c.param1; | 1628 | *pparam1 = hr.u.c.param1; |
1610 | if (pparam2) | 1629 | if (pparam2) |
1611 | *pparam2 = hr.u.c.param2; | 1630 | *pparam2 = hr.u.c.param2; |
1612 | 1631 | ||
@@ -1617,10 +1636,23 @@ u16 hpi_control_param_get(const struct hpi_hsubsys *ph_subsys, | |||
1617 | hpi_control_param_get(s, h, a, 0, 0, p1, NULL) | 1636 | hpi_control_param_get(s, h, a, 0, 0, p1, NULL) |
1618 | #define hpi_control_param2_get(s, h, a, p1, p2) \ | 1637 | #define hpi_control_param2_get(s, h, a, p1, p2) \ |
1619 | hpi_control_param_get(s, h, a, 0, 0, p1, p2) | 1638 | hpi_control_param_get(s, h, a, 0, 0, p1, p2) |
1620 | #define hpi_control_ex_param1_get(s, h, a, p1) \ | 1639 | |
1621 | hpi_control_ex_param_get(s, h, a, 0, 0, p1, NULL) | 1640 | static u16 hpi_control_log_get2(const struct hpi_hsubsys *ph_subsys, |
1622 | #define hpi_control_ex_param2_get(s, h, a, p1, p2) \ | 1641 | u32 h_control, u16 attrib, short *sv0, short *sv1) |
1623 | hpi_control_ex_param_get(s, h, a, 0, 0, p1, p2) | 1642 | { |
1643 | struct hpi_message hm; | ||
1644 | struct hpi_response hr; | ||
1645 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, | ||
1646 | HPI_CONTROL_GET_STATE); | ||
1647 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); | ||
1648 | hm.u.c.attribute = attrib; | ||
1649 | |||
1650 | hpi_send_recv(&hm, &hr); | ||
1651 | *sv0 = hr.u.c.an_log_value[0]; | ||
1652 | if (sv1) | ||
1653 | *sv1 = hr.u.c.an_log_value[1]; | ||
1654 | return hr.error; | ||
1655 | } | ||
1624 | 1656 | ||
1625 | static | 1657 | static |
1626 | u16 hpi_control_query(const struct hpi_hsubsys *ph_subsys, | 1658 | u16 hpi_control_query(const struct hpi_hsubsys *ph_subsys, |
@@ -1629,6 +1661,7 @@ u16 hpi_control_query(const struct hpi_hsubsys *ph_subsys, | |||
1629 | { | 1661 | { |
1630 | struct hpi_message hm; | 1662 | struct hpi_message hm; |
1631 | struct hpi_response hr; | 1663 | struct hpi_response hr; |
1664 | |||
1632 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, | 1665 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, |
1633 | HPI_CONTROL_GET_INFO); | 1666 | HPI_CONTROL_GET_INFO); |
1634 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); | 1667 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); |
@@ -1643,9 +1676,8 @@ u16 hpi_control_query(const struct hpi_hsubsys *ph_subsys, | |||
1643 | return hr.error; | 1676 | return hr.error; |
1644 | } | 1677 | } |
1645 | 1678 | ||
1646 | static u16 hpi_control_get_string(const struct hpi_hsubsys *ph_subsys, | 1679 | static u16 hpi_control_get_string(const u32 h_control, const u16 attribute, |
1647 | const u32 h_control, const u16 attribute, char *psz_string, | 1680 | char *psz_string, const u32 string_length) |
1648 | const u32 string_length) | ||
1649 | { | 1681 | { |
1650 | unsigned int sub_string_index = 0, j = 0; | 1682 | unsigned int sub_string_index = 0, j = 0; |
1651 | char c = 0; | 1683 | char c = 0; |
@@ -1916,6 +1948,7 @@ u16 hpi_cobranet_hmi_write(const struct hpi_hsubsys *ph_subsys, u32 h_control, | |||
1916 | { | 1948 | { |
1917 | struct hpi_message hm; | 1949 | struct hpi_message hm; |
1918 | struct hpi_response hr; | 1950 | struct hpi_response hr; |
1951 | |||
1919 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROLEX, | 1952 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROLEX, |
1920 | HPI_CONTROL_SET_STATE); | 1953 | HPI_CONTROL_SET_STATE); |
1921 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); | 1954 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); |
@@ -1941,6 +1974,7 @@ u16 hpi_cobranet_hmi_read(const struct hpi_hsubsys *ph_subsys, u32 h_control, | |||
1941 | { | 1974 | { |
1942 | struct hpi_message hm; | 1975 | struct hpi_message hm; |
1943 | struct hpi_response hr; | 1976 | struct hpi_response hr; |
1977 | |||
1944 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROLEX, | 1978 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROLEX, |
1945 | HPI_CONTROL_GET_STATE); | 1979 | HPI_CONTROL_GET_STATE); |
1946 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); | 1980 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); |
@@ -1980,6 +2014,7 @@ u16 hpi_cobranet_hmi_get_status(const struct hpi_hsubsys *ph_subsys, | |||
1980 | { | 2014 | { |
1981 | struct hpi_message hm; | 2015 | struct hpi_message hm; |
1982 | struct hpi_response hr; | 2016 | struct hpi_response hr; |
2017 | |||
1983 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROLEX, | 2018 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROLEX, |
1984 | HPI_CONTROL_GET_STATE); | 2019 | HPI_CONTROL_GET_STATE); |
1985 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); | 2020 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); |
@@ -2006,6 +2041,7 @@ u16 hpi_cobranet_getI_paddress(const struct hpi_hsubsys *ph_subsys, | |||
2006 | u32 byte_count; | 2041 | u32 byte_count; |
2007 | u32 iP; | 2042 | u32 iP; |
2008 | u16 error; | 2043 | u16 error; |
2044 | |||
2009 | error = hpi_cobranet_hmi_read(ph_subsys, h_control, | 2045 | error = hpi_cobranet_hmi_read(ph_subsys, h_control, |
2010 | HPI_COBRANET_HMI_cobra_ip_mon_currentIP, 4, &byte_count, | 2046 | HPI_COBRANET_HMI_cobra_ip_mon_currentIP, 4, &byte_count, |
2011 | (u8 *)&iP); | 2047 | (u8 *)&iP); |
@@ -2082,6 +2118,7 @@ u16 hpi_cobranet_getMA_caddress(const struct hpi_hsubsys *ph_subsys, | |||
2082 | u32 byte_count; | 2118 | u32 byte_count; |
2083 | u16 error; | 2119 | u16 error; |
2084 | u32 mAC; | 2120 | u32 mAC; |
2121 | |||
2085 | error = hpi_cobranet_hmi_read(ph_subsys, h_control, | 2122 | error = hpi_cobranet_hmi_read(ph_subsys, h_control, |
2086 | HPI_COBRANET_HMI_cobra_if_phy_address, 4, &byte_count, | 2123 | HPI_COBRANET_HMI_cobra_if_phy_address, 4, &byte_count, |
2087 | (u8 *)&mAC); | 2124 | (u8 *)&mAC); |
@@ -2103,53 +2140,111 @@ u16 hpi_cobranet_getMA_caddress(const struct hpi_hsubsys *ph_subsys, | |||
2103 | return error; | 2140 | return error; |
2104 | } | 2141 | } |
2105 | 2142 | ||
2106 | u16 hpi_compander_set(const struct hpi_hsubsys *ph_subsys, u32 h_control, | 2143 | u16 hpi_compander_set_enable(const struct hpi_hsubsys *ph_subsys, |
2107 | u16 attack, u16 decay, short ratio100, short threshold0_01dB, | 2144 | u32 h_control, u32 enable) |
2108 | short makeup_gain0_01dB) | 2145 | { |
2146 | return hpi_control_param_set(ph_subsys, h_control, HPI_GENERIC_ENABLE, | ||
2147 | enable, 0); | ||
2148 | } | ||
2149 | |||
2150 | u16 hpi_compander_get_enable(const struct hpi_hsubsys *ph_subsys, | ||
2151 | u32 h_control, u32 *enable) | ||
2152 | { | ||
2153 | return hpi_control_param1_get(ph_subsys, h_control, | ||
2154 | HPI_GENERIC_ENABLE, enable); | ||
2155 | } | ||
2156 | |||
2157 | u16 hpi_compander_set_makeup_gain(const struct hpi_hsubsys *ph_subsys, | ||
2158 | u32 h_control, short makeup_gain0_01dB) | ||
2159 | { | ||
2160 | return hpi_control_log_set2(h_control, HPI_COMPANDER_MAKEUPGAIN, | ||
2161 | makeup_gain0_01dB, 0); | ||
2162 | } | ||
2163 | |||
2164 | u16 hpi_compander_get_makeup_gain(const struct hpi_hsubsys *ph_subsys, | ||
2165 | u32 h_control, short *makeup_gain0_01dB) | ||
2166 | { | ||
2167 | return hpi_control_log_get2(ph_subsys, h_control, | ||
2168 | HPI_COMPANDER_MAKEUPGAIN, makeup_gain0_01dB, NULL); | ||
2169 | } | ||
2170 | |||
2171 | u16 hpi_compander_set_attack_time_constant(const struct hpi_hsubsys | ||
2172 | *ph_subsys, u32 h_control, unsigned int index, u32 attack) | ||
2173 | { | ||
2174 | return hpi_control_param_set(ph_subsys, h_control, | ||
2175 | HPI_COMPANDER_ATTACK, attack, index); | ||
2176 | } | ||
2177 | |||
2178 | u16 hpi_compander_get_attack_time_constant(const struct hpi_hsubsys | ||
2179 | *ph_subsys, u32 h_control, unsigned int index, u32 *attack) | ||
2180 | { | ||
2181 | return hpi_control_param_get(ph_subsys, h_control, | ||
2182 | HPI_COMPANDER_ATTACK, 0, index, attack, NULL); | ||
2183 | } | ||
2184 | |||
2185 | u16 hpi_compander_set_decay_time_constant(const struct hpi_hsubsys *ph_subsys, | ||
2186 | u32 h_control, unsigned int index, u32 decay) | ||
2187 | { | ||
2188 | return hpi_control_param_set(ph_subsys, h_control, | ||
2189 | HPI_COMPANDER_DECAY, decay, index); | ||
2190 | } | ||
2191 | |||
2192 | u16 hpi_compander_get_decay_time_constant(const struct hpi_hsubsys *ph_subsys, | ||
2193 | u32 h_control, unsigned int index, u32 *decay) | ||
2194 | { | ||
2195 | return hpi_control_param_get(ph_subsys, h_control, | ||
2196 | HPI_COMPANDER_DECAY, 0, index, decay, NULL); | ||
2197 | |||
2198 | } | ||
2199 | |||
2200 | u16 hpi_compander_set_threshold(const struct hpi_hsubsys *ph_subsys, | ||
2201 | u32 h_control, unsigned int index, short threshold0_01dB) | ||
2109 | { | 2202 | { |
2110 | struct hpi_message hm; | 2203 | struct hpi_message hm; |
2111 | struct hpi_response hr; | 2204 | struct hpi_response hr; |
2205 | |||
2112 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, | 2206 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, |
2113 | HPI_CONTROL_SET_STATE); | 2207 | HPI_CONTROL_SET_STATE); |
2114 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); | 2208 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); |
2115 | 2209 | hm.u.c.attribute = HPI_COMPANDER_THRESHOLD; | |
2116 | hm.u.c.param1 = attack + ((u32)ratio100 << 16); | 2210 | hm.u.c.param2 = index; |
2117 | hm.u.c.param2 = (decay & 0xFFFFL); | ||
2118 | hm.u.c.an_log_value[0] = threshold0_01dB; | 2211 | hm.u.c.an_log_value[0] = threshold0_01dB; |
2119 | hm.u.c.an_log_value[1] = makeup_gain0_01dB; | ||
2120 | hm.u.c.attribute = HPI_COMPANDER_PARAMS; | ||
2121 | 2212 | ||
2122 | hpi_send_recv(&hm, &hr); | 2213 | hpi_send_recv(&hm, &hr); |
2123 | 2214 | ||
2124 | return hr.error; | 2215 | return hr.error; |
2125 | } | 2216 | } |
2126 | 2217 | ||
2127 | u16 hpi_compander_get(const struct hpi_hsubsys *ph_subsys, u32 h_control, | 2218 | u16 hpi_compander_get_threshold(const struct hpi_hsubsys *ph_subsys, |
2128 | u16 *pw_attack, u16 *pw_decay, short *pw_ratio100, | 2219 | u32 h_control, unsigned int index, short *threshold0_01dB) |
2129 | short *pn_threshold0_01dB, short *pn_makeup_gain0_01dB) | ||
2130 | { | 2220 | { |
2131 | struct hpi_message hm; | 2221 | struct hpi_message hm; |
2132 | struct hpi_response hr; | 2222 | struct hpi_response hr; |
2223 | |||
2133 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, | 2224 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, |
2134 | HPI_CONTROL_GET_STATE); | 2225 | HPI_CONTROL_GET_STATE); |
2135 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); | 2226 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); |
2136 | hm.u.c.attribute = HPI_COMPANDER_PARAMS; | 2227 | hm.u.c.attribute = HPI_COMPANDER_THRESHOLD; |
2228 | hm.u.c.param2 = index; | ||
2137 | 2229 | ||
2138 | hpi_send_recv(&hm, &hr); | 2230 | hpi_send_recv(&hm, &hr); |
2231 | *threshold0_01dB = hr.u.c.an_log_value[0]; | ||
2139 | 2232 | ||
2140 | if (pw_attack) | 2233 | return hr.error; |
2141 | *pw_attack = (short)(hr.u.c.param1 & 0xFFFF); | 2234 | } |
2142 | if (pw_decay) | ||
2143 | *pw_decay = (short)(hr.u.c.param2 & 0xFFFF); | ||
2144 | if (pw_ratio100) | ||
2145 | *pw_ratio100 = (short)(hr.u.c.param1 >> 16); | ||
2146 | 2235 | ||
2147 | if (pn_threshold0_01dB) | 2236 | u16 hpi_compander_set_ratio(const struct hpi_hsubsys *ph_subsys, |
2148 | *pn_threshold0_01dB = hr.u.c.an_log_value[0]; | 2237 | u32 h_control, u32 index, u32 ratio100) |
2149 | if (pn_makeup_gain0_01dB) | 2238 | { |
2150 | *pn_makeup_gain0_01dB = hr.u.c.an_log_value[1]; | 2239 | return hpi_control_param_set(ph_subsys, h_control, |
2240 | HPI_COMPANDER_RATIO, ratio100, index); | ||
2241 | } | ||
2151 | 2242 | ||
2152 | return hr.error; | 2243 | u16 hpi_compander_get_ratio(const struct hpi_hsubsys *ph_subsys, |
2244 | u32 h_control, u32 index, u32 *ratio100) | ||
2245 | { | ||
2246 | return hpi_control_param_get(ph_subsys, h_control, | ||
2247 | HPI_COMPANDER_RATIO, 0, index, ratio100, NULL); | ||
2153 | } | 2248 | } |
2154 | 2249 | ||
2155 | u16 hpi_level_query_range(const struct hpi_hsubsys *ph_subsys, u32 h_control, | 2250 | u16 hpi_level_query_range(const struct hpi_hsubsys *ph_subsys, u32 h_control, |
@@ -2157,6 +2252,7 @@ u16 hpi_level_query_range(const struct hpi_hsubsys *ph_subsys, u32 h_control, | |||
2157 | { | 2252 | { |
2158 | struct hpi_message hm; | 2253 | struct hpi_message hm; |
2159 | struct hpi_response hr; | 2254 | struct hpi_response hr; |
2255 | |||
2160 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, | 2256 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, |
2161 | HPI_CONTROL_GET_STATE); | 2257 | HPI_CONTROL_GET_STATE); |
2162 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); | 2258 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); |
@@ -2181,37 +2277,16 @@ u16 hpi_level_set_gain(const struct hpi_hsubsys *ph_subsys, u32 h_control, | |||
2181 | short an_gain0_01dB[HPI_MAX_CHANNELS] | 2277 | short an_gain0_01dB[HPI_MAX_CHANNELS] |
2182 | ) | 2278 | ) |
2183 | { | 2279 | { |
2184 | struct hpi_message hm; | 2280 | return hpi_control_log_set2(h_control, HPI_LEVEL_GAIN, |
2185 | struct hpi_response hr; | 2281 | an_gain0_01dB[0], an_gain0_01dB[1]); |
2186 | |||
2187 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, | ||
2188 | HPI_CONTROL_SET_STATE); | ||
2189 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); | ||
2190 | memcpy(hm.u.c.an_log_value, an_gain0_01dB, | ||
2191 | sizeof(short) * HPI_MAX_CHANNELS); | ||
2192 | hm.u.c.attribute = HPI_LEVEL_GAIN; | ||
2193 | |||
2194 | hpi_send_recv(&hm, &hr); | ||
2195 | |||
2196 | return hr.error; | ||
2197 | } | 2282 | } |
2198 | 2283 | ||
2199 | u16 hpi_level_get_gain(const struct hpi_hsubsys *ph_subsys, u32 h_control, | 2284 | u16 hpi_level_get_gain(const struct hpi_hsubsys *ph_subsys, u32 h_control, |
2200 | short an_gain0_01dB[HPI_MAX_CHANNELS] | 2285 | short an_gain0_01dB[HPI_MAX_CHANNELS] |
2201 | ) | 2286 | ) |
2202 | { | 2287 | { |
2203 | struct hpi_message hm; | 2288 | return hpi_control_log_get2(ph_subsys, h_control, HPI_LEVEL_GAIN, |
2204 | struct hpi_response hr; | 2289 | &an_gain0_01dB[0], &an_gain0_01dB[1]); |
2205 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, | ||
2206 | HPI_CONTROL_GET_STATE); | ||
2207 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); | ||
2208 | hm.u.c.attribute = HPI_LEVEL_GAIN; | ||
2209 | |||
2210 | hpi_send_recv(&hm, &hr); | ||
2211 | |||
2212 | memcpy(an_gain0_01dB, hr.u.c.an_log_value, | ||
2213 | sizeof(short) * HPI_MAX_CHANNELS); | ||
2214 | return hr.error; | ||
2215 | } | 2290 | } |
2216 | 2291 | ||
2217 | u16 hpi_meter_query_channels(const struct hpi_hsubsys *ph_subsys, | 2292 | u16 hpi_meter_query_channels(const struct hpi_hsubsys *ph_subsys, |
@@ -2413,6 +2488,7 @@ u16 hpi_parametricEQ__get_band(const struct hpi_hsubsys *ph_subsys, | |||
2413 | { | 2488 | { |
2414 | struct hpi_message hm; | 2489 | struct hpi_message hm; |
2415 | struct hpi_response hr; | 2490 | struct hpi_response hr; |
2491 | |||
2416 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, | 2492 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, |
2417 | HPI_CONTROL_GET_STATE); | 2493 | HPI_CONTROL_GET_STATE); |
2418 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); | 2494 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); |
@@ -2439,6 +2515,7 @@ u16 hpi_parametricEQ__set_band(const struct hpi_hsubsys *ph_subsys, | |||
2439 | { | 2515 | { |
2440 | struct hpi_message hm; | 2516 | struct hpi_message hm; |
2441 | struct hpi_response hr; | 2517 | struct hpi_response hr; |
2518 | |||
2442 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, | 2519 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, |
2443 | HPI_CONTROL_SET_STATE); | 2520 | HPI_CONTROL_SET_STATE); |
2444 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); | 2521 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); |
@@ -2460,6 +2537,7 @@ u16 hpi_parametricEQ__get_coeffs(const struct hpi_hsubsys *ph_subsys, | |||
2460 | { | 2537 | { |
2461 | struct hpi_message hm; | 2538 | struct hpi_message hm; |
2462 | struct hpi_response hr; | 2539 | struct hpi_response hr; |
2540 | |||
2463 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, | 2541 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, |
2464 | HPI_CONTROL_GET_STATE); | 2542 | HPI_CONTROL_GET_STATE); |
2465 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); | 2543 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); |
@@ -2623,8 +2701,8 @@ u16 hpi_tone_detector_get_frequency(const struct hpi_hsubsys *ph_subsys, | |||
2623 | u16 hpi_tone_detector_get_state(const struct hpi_hsubsys *ph_subsys, | 2701 | u16 hpi_tone_detector_get_state(const struct hpi_hsubsys *ph_subsys, |
2624 | u32 h_control, u32 *state) | 2702 | u32 h_control, u32 *state) |
2625 | { | 2703 | { |
2626 | return hpi_control_param_get(ph_subsys, h_control, | 2704 | return hpi_control_param1_get(ph_subsys, h_control, |
2627 | HPI_TONEDETECTOR_STATE, 0, 0, (u32 *)state, NULL); | 2705 | HPI_TONEDETECTOR_STATE, state); |
2628 | } | 2706 | } |
2629 | 2707 | ||
2630 | u16 hpi_tone_detector_set_enable(const struct hpi_hsubsys *ph_subsys, | 2708 | u16 hpi_tone_detector_set_enable(const struct hpi_hsubsys *ph_subsys, |
@@ -2637,8 +2715,8 @@ u16 hpi_tone_detector_set_enable(const struct hpi_hsubsys *ph_subsys, | |||
2637 | u16 hpi_tone_detector_get_enable(const struct hpi_hsubsys *ph_subsys, | 2715 | u16 hpi_tone_detector_get_enable(const struct hpi_hsubsys *ph_subsys, |
2638 | u32 h_control, u32 *enable) | 2716 | u32 h_control, u32 *enable) |
2639 | { | 2717 | { |
2640 | return hpi_control_param_get(ph_subsys, h_control, HPI_GENERIC_ENABLE, | 2718 | return hpi_control_param1_get(ph_subsys, h_control, |
2641 | 0, 0, (u32 *)enable, NULL); | 2719 | HPI_GENERIC_ENABLE, enable); |
2642 | } | 2720 | } |
2643 | 2721 | ||
2644 | u16 hpi_tone_detector_set_event_enable(const struct hpi_hsubsys *ph_subsys, | 2722 | u16 hpi_tone_detector_set_event_enable(const struct hpi_hsubsys *ph_subsys, |
@@ -2651,8 +2729,8 @@ u16 hpi_tone_detector_set_event_enable(const struct hpi_hsubsys *ph_subsys, | |||
2651 | u16 hpi_tone_detector_get_event_enable(const struct hpi_hsubsys *ph_subsys, | 2729 | u16 hpi_tone_detector_get_event_enable(const struct hpi_hsubsys *ph_subsys, |
2652 | u32 h_control, u32 *event_enable) | 2730 | u32 h_control, u32 *event_enable) |
2653 | { | 2731 | { |
2654 | return hpi_control_param_get(ph_subsys, h_control, | 2732 | return hpi_control_param1_get(ph_subsys, h_control, |
2655 | HPI_GENERIC_EVENT_ENABLE, 0, 0, (u32 *)event_enable, NULL); | 2733 | HPI_GENERIC_EVENT_ENABLE, event_enable); |
2656 | } | 2734 | } |
2657 | 2735 | ||
2658 | u16 hpi_tone_detector_set_threshold(const struct hpi_hsubsys *ph_subsys, | 2736 | u16 hpi_tone_detector_set_threshold(const struct hpi_hsubsys *ph_subsys, |
@@ -2665,15 +2743,15 @@ u16 hpi_tone_detector_set_threshold(const struct hpi_hsubsys *ph_subsys, | |||
2665 | u16 hpi_tone_detector_get_threshold(const struct hpi_hsubsys *ph_subsys, | 2743 | u16 hpi_tone_detector_get_threshold(const struct hpi_hsubsys *ph_subsys, |
2666 | u32 h_control, int *threshold) | 2744 | u32 h_control, int *threshold) |
2667 | { | 2745 | { |
2668 | return hpi_control_param_get(ph_subsys, h_control, | 2746 | return hpi_control_param1_get(ph_subsys, h_control, |
2669 | HPI_TONEDETECTOR_THRESHOLD, 0, 0, (u32 *)threshold, NULL); | 2747 | HPI_TONEDETECTOR_THRESHOLD, (u32 *)threshold); |
2670 | } | 2748 | } |
2671 | 2749 | ||
2672 | u16 hpi_silence_detector_get_state(const struct hpi_hsubsys *ph_subsys, | 2750 | u16 hpi_silence_detector_get_state(const struct hpi_hsubsys *ph_subsys, |
2673 | u32 h_control, u32 *state) | 2751 | u32 h_control, u32 *state) |
2674 | { | 2752 | { |
2675 | return hpi_control_param_get(ph_subsys, h_control, | 2753 | return hpi_control_param1_get(ph_subsys, h_control, |
2676 | HPI_SILENCEDETECTOR_STATE, 0, 0, (u32 *)state, NULL); | 2754 | HPI_SILENCEDETECTOR_STATE, state); |
2677 | } | 2755 | } |
2678 | 2756 | ||
2679 | u16 hpi_silence_detector_set_enable(const struct hpi_hsubsys *ph_subsys, | 2757 | u16 hpi_silence_detector_set_enable(const struct hpi_hsubsys *ph_subsys, |
@@ -2686,50 +2764,50 @@ u16 hpi_silence_detector_set_enable(const struct hpi_hsubsys *ph_subsys, | |||
2686 | u16 hpi_silence_detector_get_enable(const struct hpi_hsubsys *ph_subsys, | 2764 | u16 hpi_silence_detector_get_enable(const struct hpi_hsubsys *ph_subsys, |
2687 | u32 h_control, u32 *enable) | 2765 | u32 h_control, u32 *enable) |
2688 | { | 2766 | { |
2689 | return hpi_control_param_get(ph_subsys, h_control, HPI_GENERIC_ENABLE, | 2767 | return hpi_control_param1_get(ph_subsys, h_control, |
2690 | 0, 0, (u32 *)enable, NULL); | 2768 | HPI_GENERIC_ENABLE, enable); |
2691 | } | 2769 | } |
2692 | 2770 | ||
2693 | u16 hpi_silence_detector_set_event_enable(const struct hpi_hsubsys *ph_subsys, | 2771 | u16 hpi_silence_detector_set_event_enable(const struct hpi_hsubsys *ph_subsys, |
2694 | u32 h_control, u32 event_enable) | 2772 | u32 h_control, u32 event_enable) |
2695 | { | 2773 | { |
2696 | return hpi_control_param_set(ph_subsys, h_control, | 2774 | return hpi_control_param_set(ph_subsys, h_control, |
2697 | HPI_GENERIC_EVENT_ENABLE, (u32)event_enable, 0); | 2775 | HPI_GENERIC_EVENT_ENABLE, event_enable, 0); |
2698 | } | 2776 | } |
2699 | 2777 | ||
2700 | u16 hpi_silence_detector_get_event_enable(const struct hpi_hsubsys *ph_subsys, | 2778 | u16 hpi_silence_detector_get_event_enable(const struct hpi_hsubsys *ph_subsys, |
2701 | u32 h_control, u32 *event_enable) | 2779 | u32 h_control, u32 *event_enable) |
2702 | { | 2780 | { |
2703 | return hpi_control_param_get(ph_subsys, h_control, | 2781 | return hpi_control_param1_get(ph_subsys, h_control, |
2704 | HPI_GENERIC_EVENT_ENABLE, 0, 0, (u32 *)event_enable, NULL); | 2782 | HPI_GENERIC_EVENT_ENABLE, event_enable); |
2705 | } | 2783 | } |
2706 | 2784 | ||
2707 | u16 hpi_silence_detector_set_delay(const struct hpi_hsubsys *ph_subsys, | 2785 | u16 hpi_silence_detector_set_delay(const struct hpi_hsubsys *ph_subsys, |
2708 | u32 h_control, u32 delay) | 2786 | u32 h_control, u32 delay) |
2709 | { | 2787 | { |
2710 | return hpi_control_param_set(ph_subsys, h_control, | 2788 | return hpi_control_param_set(ph_subsys, h_control, |
2711 | HPI_SILENCEDETECTOR_DELAY, (u32)delay, 0); | 2789 | HPI_SILENCEDETECTOR_DELAY, delay, 0); |
2712 | } | 2790 | } |
2713 | 2791 | ||
2714 | u16 hpi_silence_detector_get_delay(const struct hpi_hsubsys *ph_subsys, | 2792 | u16 hpi_silence_detector_get_delay(const struct hpi_hsubsys *ph_subsys, |
2715 | u32 h_control, u32 *delay) | 2793 | u32 h_control, u32 *delay) |
2716 | { | 2794 | { |
2717 | return hpi_control_param_get(ph_subsys, h_control, | 2795 | return hpi_control_param1_get(ph_subsys, h_control, |
2718 | HPI_SILENCEDETECTOR_DELAY, 0, 0, (u32 *)delay, NULL); | 2796 | HPI_SILENCEDETECTOR_DELAY, delay); |
2719 | } | 2797 | } |
2720 | 2798 | ||
2721 | u16 hpi_silence_detector_set_threshold(const struct hpi_hsubsys *ph_subsys, | 2799 | u16 hpi_silence_detector_set_threshold(const struct hpi_hsubsys *ph_subsys, |
2722 | u32 h_control, int threshold) | 2800 | u32 h_control, int threshold) |
2723 | { | 2801 | { |
2724 | return hpi_control_param_set(ph_subsys, h_control, | 2802 | return hpi_control_param_set(ph_subsys, h_control, |
2725 | HPI_SILENCEDETECTOR_THRESHOLD, (u32)threshold, 0); | 2803 | HPI_SILENCEDETECTOR_THRESHOLD, threshold, 0); |
2726 | } | 2804 | } |
2727 | 2805 | ||
2728 | u16 hpi_silence_detector_get_threshold(const struct hpi_hsubsys *ph_subsys, | 2806 | u16 hpi_silence_detector_get_threshold(const struct hpi_hsubsys *ph_subsys, |
2729 | u32 h_control, int *threshold) | 2807 | u32 h_control, int *threshold) |
2730 | { | 2808 | { |
2731 | return hpi_control_param_get(ph_subsys, h_control, | 2809 | return hpi_control_param1_get(ph_subsys, h_control, |
2732 | HPI_SILENCEDETECTOR_THRESHOLD, 0, 0, (u32 *)threshold, NULL); | 2810 | HPI_SILENCEDETECTOR_THRESHOLD, (u32 *)threshold); |
2733 | } | 2811 | } |
2734 | 2812 | ||
2735 | u16 hpi_tuner_query_band(const struct hpi_hsubsys *ph_subsys, | 2813 | u16 hpi_tuner_query_band(const struct hpi_hsubsys *ph_subsys, |
@@ -2822,6 +2900,7 @@ u16 hpi_tuner_getRF_level(const struct hpi_hsubsys *ph_subsys, u32 h_control, | |||
2822 | { | 2900 | { |
2823 | struct hpi_message hm; | 2901 | struct hpi_message hm; |
2824 | struct hpi_response hr; | 2902 | struct hpi_response hr; |
2903 | |||
2825 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, | 2904 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, |
2826 | HPI_CONTROL_GET_STATE); | 2905 | HPI_CONTROL_GET_STATE); |
2827 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); | 2906 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); |
@@ -2838,6 +2917,7 @@ u16 hpi_tuner_get_rawRF_level(const struct hpi_hsubsys *ph_subsys, | |||
2838 | { | 2917 | { |
2839 | struct hpi_message hm; | 2918 | struct hpi_message hm; |
2840 | struct hpi_response hr; | 2919 | struct hpi_response hr; |
2920 | |||
2841 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, | 2921 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, |
2842 | HPI_CONTROL_GET_STATE); | 2922 | HPI_CONTROL_GET_STATE); |
2843 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); | 2923 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); |
@@ -2894,14 +2974,14 @@ u16 hpi_tuner_get_program(const struct hpi_hsubsys *ph_subsys, u32 h_control, | |||
2894 | u16 hpi_tuner_get_hd_radio_dsp_version(const struct hpi_hsubsys *ph_subsys, | 2974 | u16 hpi_tuner_get_hd_radio_dsp_version(const struct hpi_hsubsys *ph_subsys, |
2895 | u32 h_control, char *psz_dsp_version, const u32 string_size) | 2975 | u32 h_control, char *psz_dsp_version, const u32 string_size) |
2896 | { | 2976 | { |
2897 | return hpi_control_get_string(ph_subsys, h_control, | 2977 | return hpi_control_get_string(h_control, |
2898 | HPI_TUNER_HDRADIO_DSP_VERSION, psz_dsp_version, string_size); | 2978 | HPI_TUNER_HDRADIO_DSP_VERSION, psz_dsp_version, string_size); |
2899 | } | 2979 | } |
2900 | 2980 | ||
2901 | u16 hpi_tuner_get_hd_radio_sdk_version(const struct hpi_hsubsys *ph_subsys, | 2981 | u16 hpi_tuner_get_hd_radio_sdk_version(const struct hpi_hsubsys *ph_subsys, |
2902 | u32 h_control, char *psz_sdk_version, const u32 string_size) | 2982 | u32 h_control, char *psz_sdk_version, const u32 string_size) |
2903 | { | 2983 | { |
2904 | return hpi_control_get_string(ph_subsys, h_control, | 2984 | return hpi_control_get_string(h_control, |
2905 | HPI_TUNER_HDRADIO_SDK_VERSION, psz_sdk_version, string_size); | 2985 | HPI_TUNER_HDRADIO_SDK_VERSION, psz_sdk_version, string_size); |
2906 | } | 2986 | } |
2907 | 2987 | ||
@@ -2942,15 +3022,15 @@ u16 hpi_tuner_get_mode(const struct hpi_hsubsys *ph_subsys, u32 h_control, | |||
2942 | u16 hpi_tuner_get_hd_radio_signal_quality(const struct hpi_hsubsys *ph_subsys, | 3022 | u16 hpi_tuner_get_hd_radio_signal_quality(const struct hpi_hsubsys *ph_subsys, |
2943 | u32 h_control, u32 *pquality) | 3023 | u32 h_control, u32 *pquality) |
2944 | { | 3024 | { |
2945 | return hpi_control_param_get(ph_subsys, h_control, | 3025 | return hpi_control_param1_get(ph_subsys, h_control, |
2946 | HPI_TUNER_HDRADIO_SIGNAL_QUALITY, 0, 0, pquality, NULL); | 3026 | HPI_TUNER_HDRADIO_SIGNAL_QUALITY, pquality); |
2947 | } | 3027 | } |
2948 | 3028 | ||
2949 | u16 hpi_tuner_get_hd_radio_signal_blend(const struct hpi_hsubsys *ph_subsys, | 3029 | u16 hpi_tuner_get_hd_radio_signal_blend(const struct hpi_hsubsys *ph_subsys, |
2950 | u32 h_control, u32 *pblend) | 3030 | u32 h_control, u32 *pblend) |
2951 | { | 3031 | { |
2952 | return hpi_control_param_get(ph_subsys, h_control, | 3032 | return hpi_control_param1_get(ph_subsys, h_control, |
2953 | HPI_TUNER_HDRADIO_BLEND, 0, 0, pblend, NULL); | 3033 | HPI_TUNER_HDRADIO_BLEND, pblend); |
2954 | } | 3034 | } |
2955 | 3035 | ||
2956 | u16 hpi_tuner_set_hd_radio_signal_blend(const struct hpi_hsubsys *ph_subsys, | 3036 | u16 hpi_tuner_set_hd_radio_signal_blend(const struct hpi_hsubsys *ph_subsys, |
@@ -2965,6 +3045,7 @@ u16 hpi_tuner_getRDS(const struct hpi_hsubsys *ph_subsys, u32 h_control, | |||
2965 | { | 3045 | { |
2966 | struct hpi_message hm; | 3046 | struct hpi_message hm; |
2967 | struct hpi_response hr; | 3047 | struct hpi_response hr; |
3048 | |||
2968 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, | 3049 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, |
2969 | HPI_CONTROL_GET_STATE); | 3050 | HPI_CONTROL_GET_STATE); |
2970 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); | 3051 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); |
@@ -2981,43 +3062,43 @@ u16 hpi_tuner_getRDS(const struct hpi_hsubsys *ph_subsys, u32 h_control, | |||
2981 | u16 HPI_PAD__get_channel_name(const struct hpi_hsubsys *ph_subsys, | 3062 | u16 HPI_PAD__get_channel_name(const struct hpi_hsubsys *ph_subsys, |
2982 | u32 h_control, char *psz_string, const u32 data_length) | 3063 | u32 h_control, char *psz_string, const u32 data_length) |
2983 | { | 3064 | { |
2984 | return hpi_control_get_string(ph_subsys, h_control, | 3065 | return hpi_control_get_string(h_control, HPI_PAD_CHANNEL_NAME, |
2985 | HPI_PAD_CHANNEL_NAME, psz_string, data_length); | 3066 | psz_string, data_length); |
2986 | } | 3067 | } |
2987 | 3068 | ||
2988 | u16 HPI_PAD__get_artist(const struct hpi_hsubsys *ph_subsys, u32 h_control, | 3069 | u16 HPI_PAD__get_artist(const struct hpi_hsubsys *ph_subsys, u32 h_control, |
2989 | char *psz_string, const u32 data_length) | 3070 | char *psz_string, const u32 data_length) |
2990 | { | 3071 | { |
2991 | return hpi_control_get_string(ph_subsys, h_control, HPI_PAD_ARTIST, | 3072 | return hpi_control_get_string(h_control, HPI_PAD_ARTIST, psz_string, |
2992 | psz_string, data_length); | 3073 | data_length); |
2993 | } | 3074 | } |
2994 | 3075 | ||
2995 | u16 HPI_PAD__get_title(const struct hpi_hsubsys *ph_subsys, u32 h_control, | 3076 | u16 HPI_PAD__get_title(const struct hpi_hsubsys *ph_subsys, u32 h_control, |
2996 | char *psz_string, const u32 data_length) | 3077 | char *psz_string, const u32 data_length) |
2997 | { | 3078 | { |
2998 | return hpi_control_get_string(ph_subsys, h_control, HPI_PAD_TITLE, | 3079 | return hpi_control_get_string(h_control, HPI_PAD_TITLE, psz_string, |
2999 | psz_string, data_length); | 3080 | data_length); |
3000 | } | 3081 | } |
3001 | 3082 | ||
3002 | u16 HPI_PAD__get_comment(const struct hpi_hsubsys *ph_subsys, u32 h_control, | 3083 | u16 HPI_PAD__get_comment(const struct hpi_hsubsys *ph_subsys, u32 h_control, |
3003 | char *psz_string, const u32 data_length) | 3084 | char *psz_string, const u32 data_length) |
3004 | { | 3085 | { |
3005 | return hpi_control_get_string(ph_subsys, h_control, HPI_PAD_COMMENT, | 3086 | return hpi_control_get_string(h_control, HPI_PAD_COMMENT, psz_string, |
3006 | psz_string, data_length); | 3087 | data_length); |
3007 | } | 3088 | } |
3008 | 3089 | ||
3009 | u16 HPI_PAD__get_program_type(const struct hpi_hsubsys *ph_subsys, | 3090 | u16 HPI_PAD__get_program_type(const struct hpi_hsubsys *ph_subsys, |
3010 | u32 h_control, u32 *ppTY) | 3091 | u32 h_control, u32 *ppTY) |
3011 | { | 3092 | { |
3012 | return hpi_control_param_get(ph_subsys, h_control, | 3093 | return hpi_control_param1_get(ph_subsys, h_control, |
3013 | HPI_PAD_PROGRAM_TYPE, 0, 0, ppTY, NULL); | 3094 | HPI_PAD_PROGRAM_TYPE, ppTY); |
3014 | } | 3095 | } |
3015 | 3096 | ||
3016 | u16 HPI_PAD__get_rdsPI(const struct hpi_hsubsys *ph_subsys, u32 h_control, | 3097 | u16 HPI_PAD__get_rdsPI(const struct hpi_hsubsys *ph_subsys, u32 h_control, |
3017 | u32 *ppI) | 3098 | u32 *ppI) |
3018 | { | 3099 | { |
3019 | return hpi_control_param_get(ph_subsys, h_control, HPI_PAD_PROGRAM_ID, | 3100 | return hpi_control_param1_get(ph_subsys, h_control, |
3020 | 0, 0, ppI, NULL); | 3101 | HPI_PAD_PROGRAM_ID, ppI); |
3021 | } | 3102 | } |
3022 | 3103 | ||
3023 | u16 hpi_volume_query_channels(const struct hpi_hsubsys *ph_subsys, | 3104 | u16 hpi_volume_query_channels(const struct hpi_hsubsys *ph_subsys, |
@@ -3031,36 +3112,16 @@ u16 hpi_volume_set_gain(const struct hpi_hsubsys *ph_subsys, u32 h_control, | |||
3031 | short an_log_gain[HPI_MAX_CHANNELS] | 3112 | short an_log_gain[HPI_MAX_CHANNELS] |
3032 | ) | 3113 | ) |
3033 | { | 3114 | { |
3034 | struct hpi_message hm; | 3115 | return hpi_control_log_set2(h_control, HPI_VOLUME_GAIN, |
3035 | struct hpi_response hr; | 3116 | an_log_gain[0], an_log_gain[1]); |
3036 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, | ||
3037 | HPI_CONTROL_SET_STATE); | ||
3038 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); | ||
3039 | memcpy(hm.u.c.an_log_value, an_log_gain, | ||
3040 | sizeof(short) * HPI_MAX_CHANNELS); | ||
3041 | hm.u.c.attribute = HPI_VOLUME_GAIN; | ||
3042 | |||
3043 | hpi_send_recv(&hm, &hr); | ||
3044 | |||
3045 | return hr.error; | ||
3046 | } | 3117 | } |
3047 | 3118 | ||
3048 | u16 hpi_volume_get_gain(const struct hpi_hsubsys *ph_subsys, u32 h_control, | 3119 | u16 hpi_volume_get_gain(const struct hpi_hsubsys *ph_subsys, u32 h_control, |
3049 | short an_log_gain[HPI_MAX_CHANNELS] | 3120 | short an_log_gain[HPI_MAX_CHANNELS] |
3050 | ) | 3121 | ) |
3051 | { | 3122 | { |
3052 | struct hpi_message hm; | 3123 | return hpi_control_log_get2(ph_subsys, h_control, HPI_VOLUME_GAIN, |
3053 | struct hpi_response hr; | 3124 | &an_log_gain[0], &an_log_gain[1]); |
3054 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, | ||
3055 | HPI_CONTROL_GET_STATE); | ||
3056 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); | ||
3057 | hm.u.c.attribute = HPI_VOLUME_GAIN; | ||
3058 | |||
3059 | hpi_send_recv(&hm, &hr); | ||
3060 | |||
3061 | memcpy(an_log_gain, hr.u.c.an_log_value, | ||
3062 | sizeof(short) * HPI_MAX_CHANNELS); | ||
3063 | return hr.error; | ||
3064 | } | 3125 | } |
3065 | 3126 | ||
3066 | u16 hpi_volume_query_range(const struct hpi_hsubsys *ph_subsys, u32 h_control, | 3127 | u16 hpi_volume_query_range(const struct hpi_hsubsys *ph_subsys, u32 h_control, |
@@ -3068,6 +3129,7 @@ u16 hpi_volume_query_range(const struct hpi_hsubsys *ph_subsys, u32 h_control, | |||
3068 | { | 3129 | { |
3069 | struct hpi_message hm; | 3130 | struct hpi_message hm; |
3070 | struct hpi_response hr; | 3131 | struct hpi_response hr; |
3132 | |||
3071 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, | 3133 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, |
3072 | HPI_CONTROL_GET_STATE); | 3134 | HPI_CONTROL_GET_STATE); |
3073 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); | 3135 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); |
@@ -3094,6 +3156,7 @@ u16 hpi_volume_auto_fade_profile(const struct hpi_hsubsys *ph_subsys, | |||
3094 | { | 3156 | { |
3095 | struct hpi_message hm; | 3157 | struct hpi_message hm; |
3096 | struct hpi_response hr; | 3158 | struct hpi_response hr; |
3159 | |||
3097 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, | 3160 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, |
3098 | HPI_CONTROL_SET_STATE); | 3161 | HPI_CONTROL_SET_STATE); |
3099 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); | 3162 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); |
@@ -3170,43 +3233,42 @@ static size_t entity_type_to_size[LAST_ENTITY_TYPE] = { | |||
3170 | 6 * sizeof(char), | 3233 | 6 * sizeof(char), |
3171 | }; | 3234 | }; |
3172 | 3235 | ||
3173 | inline size_t hpi_entity_size(struct hpi_entity *entity_ptr) | 3236 | static inline size_t hpi_entity_size(struct hpi_entity *entity_ptr) |
3174 | { | 3237 | { |
3175 | return entity_ptr->header.size; | 3238 | return entity_ptr->header.size; |
3176 | } | 3239 | } |
3177 | 3240 | ||
3178 | inline size_t hpi_entity_header_size(struct hpi_entity *entity_ptr) | 3241 | static inline size_t hpi_entity_header_size(struct hpi_entity *entity_ptr) |
3179 | { | 3242 | { |
3180 | return sizeof(entity_ptr->header); | 3243 | return sizeof(entity_ptr->header); |
3181 | } | 3244 | } |
3182 | 3245 | ||
3183 | inline size_t hpi_entity_value_size(struct hpi_entity *entity_ptr) | 3246 | static inline size_t hpi_entity_value_size(struct hpi_entity *entity_ptr) |
3184 | { | 3247 | { |
3185 | return hpi_entity_size(entity_ptr) - | 3248 | return hpi_entity_size(entity_ptr) - |
3186 | hpi_entity_header_size(entity_ptr); | 3249 | hpi_entity_header_size(entity_ptr); |
3187 | } | 3250 | } |
3188 | 3251 | ||
3189 | inline size_t hpi_entity_item_count(struct hpi_entity *entity_ptr) | 3252 | static inline size_t hpi_entity_item_count(struct hpi_entity *entity_ptr) |
3190 | { | 3253 | { |
3191 | return hpi_entity_value_size(entity_ptr) / | 3254 | return hpi_entity_value_size(entity_ptr) / |
3192 | entity_type_to_size[entity_ptr->header.type]; | 3255 | entity_type_to_size[entity_ptr->header.type]; |
3193 | } | 3256 | } |
3194 | 3257 | ||
3195 | inline struct hpi_entity *hpi_entity_ptr_to_next(struct hpi_entity | 3258 | static inline struct hpi_entity *hpi_entity_ptr_to_next(struct hpi_entity |
3196 | *entity_ptr) | 3259 | *entity_ptr) |
3197 | { | 3260 | { |
3198 | return (void *)(((uint8_t *) entity_ptr) + | 3261 | return (void *)(((u8 *)entity_ptr) + hpi_entity_size(entity_ptr)); |
3199 | hpi_entity_size(entity_ptr)); | ||
3200 | } | 3262 | } |
3201 | 3263 | ||
3202 | inline u16 hpi_entity_check_type(const enum e_entity_type t) | 3264 | static inline u16 hpi_entity_check_type(const enum e_entity_type t) |
3203 | { | 3265 | { |
3204 | if (t >= 0 && t < STR_TYPE_FIELD_MAX) | 3266 | if (t >= 0 && t < STR_TYPE_FIELD_MAX) |
3205 | return 0; | 3267 | return 0; |
3206 | return HPI_ERROR_ENTITY_TYPE_INVALID; | 3268 | return HPI_ERROR_ENTITY_TYPE_INVALID; |
3207 | } | 3269 | } |
3208 | 3270 | ||
3209 | inline u16 hpi_entity_check_role(const enum e_entity_role r) | 3271 | static inline u16 hpi_entity_check_role(const enum e_entity_role r) |
3210 | { | 3272 | { |
3211 | if (r >= 0 && r < STR_ROLE_FIELD_MAX) | 3273 | if (r >= 0 && r < STR_ROLE_FIELD_MAX) |
3212 | return 0; | 3274 | return 0; |
@@ -3624,6 +3686,7 @@ u16 hpi_async_event_wait(const struct hpi_hsubsys *ph_subsys, u32 h_async, | |||
3624 | u16 maximum_events, struct hpi_async_event *p_events, | 3686 | u16 maximum_events, struct hpi_async_event *p_events, |
3625 | u16 *pw_number_returned) | 3687 | u16 *pw_number_returned) |
3626 | { | 3688 | { |
3689 | |||
3627 | return 0; | 3690 | return 0; |
3628 | } | 3691 | } |
3629 | 3692 | ||
diff --git a/sound/pci/asihpi/hpimsgx.c b/sound/pci/asihpi/hpimsgx.c index 2ee90dc3d897..f01ab964f602 100644 --- a/sound/pci/asihpi/hpimsgx.c +++ b/sound/pci/asihpi/hpimsgx.c | |||
@@ -741,7 +741,7 @@ static void HPIMSGX__reset(u16 adapter_index) | |||
741 | hpi_init_response(&hr, HPI_OBJ_SUBSYSTEM, | 741 | hpi_init_response(&hr, HPI_OBJ_SUBSYSTEM, |
742 | HPI_SUBSYS_FIND_ADAPTERS, 0); | 742 | HPI_SUBSYS_FIND_ADAPTERS, 0); |
743 | memcpy(&gRESP_HPI_SUBSYS_FIND_ADAPTERS, &hr, | 743 | memcpy(&gRESP_HPI_SUBSYS_FIND_ADAPTERS, &hr, |
744 | sizeof(&gRESP_HPI_SUBSYS_FIND_ADAPTERS)); | 744 | sizeof(gRESP_HPI_SUBSYS_FIND_ADAPTERS)); |
745 | 745 | ||
746 | for (adapter = 0; adapter < HPI_MAX_ADAPTERS; adapter++) { | 746 | for (adapter = 0; adapter < HPI_MAX_ADAPTERS; adapter++) { |
747 | 747 | ||
diff --git a/sound/pci/asihpi/hpioctl.c b/sound/pci/asihpi/hpioctl.c index 7396ac54e99f..62895a719fcb 100644 --- a/sound/pci/asihpi/hpioctl.c +++ b/sound/pci/asihpi/hpioctl.c | |||
@@ -121,11 +121,17 @@ long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
121 | phpi_ioctl_data = (struct hpi_ioctl_linux __user *)arg; | 121 | phpi_ioctl_data = (struct hpi_ioctl_linux __user *)arg; |
122 | 122 | ||
123 | /* Read the message and response pointers from user space. */ | 123 | /* Read the message and response pointers from user space. */ |
124 | get_user(puhm, &phpi_ioctl_data->phm); | 124 | if (get_user(puhm, &phpi_ioctl_data->phm) || |
125 | get_user(puhr, &phpi_ioctl_data->phr); | 125 | get_user(puhr, &phpi_ioctl_data->phr)) { |
126 | err = -EFAULT; | ||
127 | goto out; | ||
128 | } | ||
126 | 129 | ||
127 | /* Now read the message size and data from user space. */ | 130 | /* Now read the message size and data from user space. */ |
128 | get_user(hm->h.size, (u16 __user *)puhm); | 131 | if (get_user(hm->h.size, (u16 __user *)puhm)) { |
132 | err = -EFAULT; | ||
133 | goto out; | ||
134 | } | ||
129 | if (hm->h.size > sizeof(*hm)) | 135 | if (hm->h.size > sizeof(*hm)) |
130 | hm->h.size = sizeof(*hm); | 136 | hm->h.size = sizeof(*hm); |
131 | 137 | ||
@@ -138,7 +144,10 @@ long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
138 | goto out; | 144 | goto out; |
139 | } | 145 | } |
140 | 146 | ||
141 | get_user(res_max_size, (u16 __user *)puhr); | 147 | if (get_user(res_max_size, (u16 __user *)puhr)) { |
148 | err = -EFAULT; | ||
149 | goto out; | ||
150 | } | ||
142 | /* printk(KERN_INFO "user response size %d\n", res_max_size); */ | 151 | /* printk(KERN_INFO "user response size %d\n", res_max_size); */ |
143 | if (res_max_size < sizeof(struct hpi_response_header)) { | 152 | if (res_max_size < sizeof(struct hpi_response_header)) { |
144 | HPI_DEBUG_LOG(WARNING, "small res size %d\n", res_max_size); | 153 | HPI_DEBUG_LOG(WARNING, "small res size %d\n", res_max_size); |
@@ -464,9 +473,7 @@ void __init asihpi_init(void) | |||
464 | 473 | ||
465 | memset(adapters, 0, sizeof(adapters)); | 474 | memset(adapters, 0, sizeof(adapters)); |
466 | 475 | ||
467 | printk(KERN_INFO "ASIHPI driver %d.%02d.%02d\n", | 476 | printk(KERN_INFO "ASIHPI driver " HPI_VER_STRING "\n"); |
468 | HPI_VER_MAJOR(HPI_VER), HPI_VER_MINOR(HPI_VER), | ||
469 | HPI_VER_RELEASE(HPI_VER)); | ||
470 | 477 | ||
471 | hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM, | 478 | hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM, |
472 | HPI_SUBSYS_DRIVER_LOAD); | 479 | HPI_SUBSYS_DRIVER_LOAD); |
diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 0a3d3d6e77b4..8e69620da20b 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c | |||
@@ -1002,29 +1002,27 @@ snd_ca0106_pcm_pointer_playback(struct snd_pcm_substream *substream) | |||
1002 | struct snd_ca0106 *emu = snd_pcm_substream_chip(substream); | 1002 | struct snd_ca0106 *emu = snd_pcm_substream_chip(substream); |
1003 | struct snd_pcm_runtime *runtime = substream->runtime; | 1003 | struct snd_pcm_runtime *runtime = substream->runtime; |
1004 | struct snd_ca0106_pcm *epcm = runtime->private_data; | 1004 | struct snd_ca0106_pcm *epcm = runtime->private_data; |
1005 | snd_pcm_uframes_t ptr, ptr1, ptr2,ptr3,ptr4 = 0; | 1005 | unsigned int ptr, prev_ptr; |
1006 | int channel = epcm->channel_id; | 1006 | int channel = epcm->channel_id; |
1007 | int timeout = 10; | ||
1007 | 1008 | ||
1008 | if (!epcm->running) | 1009 | if (!epcm->running) |
1009 | return 0; | 1010 | return 0; |
1010 | 1011 | ||
1011 | ptr3 = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel); | 1012 | prev_ptr = -1; |
1012 | ptr1 = snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel); | 1013 | do { |
1013 | ptr4 = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel); | 1014 | ptr = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel); |
1014 | if (ptr3 != ptr4) ptr1 = snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel); | 1015 | ptr = (ptr >> 3) * runtime->period_size; |
1015 | ptr2 = bytes_to_frames(runtime, ptr1); | 1016 | ptr += bytes_to_frames(runtime, |
1016 | ptr2+= (ptr4 >> 3) * runtime->period_size; | 1017 | snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel)); |
1017 | ptr=ptr2; | 1018 | if (ptr >= runtime->buffer_size) |
1018 | if (ptr >= runtime->buffer_size) | 1019 | ptr -= runtime->buffer_size; |
1019 | ptr -= runtime->buffer_size; | 1020 | if (prev_ptr == ptr) |
1020 | /* | 1021 | return ptr; |
1021 | printk(KERN_DEBUG "ptr1 = 0x%lx, ptr2=0x%lx, ptr=0x%lx, " | 1022 | prev_ptr = ptr; |
1022 | "buffer_size = 0x%x, period_size = 0x%x, bits=%d, rate=%d\n", | 1023 | } while (--timeout); |
1023 | ptr1, ptr2, ptr, (int)runtime->buffer_size, | 1024 | snd_printk(KERN_WARNING "ca0106: unstable DMA pointer!\n"); |
1024 | (int)runtime->period_size, (int)runtime->frame_bits, | 1025 | return 0; |
1025 | (int)runtime->rate); | ||
1026 | */ | ||
1027 | return ptr; | ||
1028 | } | 1026 | } |
1029 | 1027 | ||
1030 | /* pointer_capture callback */ | 1028 | /* pointer_capture callback */ |
diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c index 668a5ec04499..20763dd03fa0 100644 --- a/sound/pci/echoaudio/echoaudio.c +++ b/sound/pci/echoaudio/echoaudio.c | |||
@@ -2250,6 +2250,8 @@ static int snd_echo_resume(struct pci_dev *pci) | |||
2250 | DE_INIT(("resume start\n")); | 2250 | DE_INIT(("resume start\n")); |
2251 | pci_restore_state(pci); | 2251 | pci_restore_state(pci); |
2252 | commpage_bak = kmalloc(sizeof(struct echoaudio), GFP_KERNEL); | 2252 | commpage_bak = kmalloc(sizeof(struct echoaudio), GFP_KERNEL); |
2253 | if (commpage_bak == NULL) | ||
2254 | return -ENOMEM; | ||
2253 | commpage = chip->comm_page; | 2255 | commpage = chip->comm_page; |
2254 | memcpy(commpage_bak, commpage, sizeof(struct comm_page)); | 2256 | memcpy(commpage_bak, commpage, sizeof(struct comm_page)); |
2255 | 2257 | ||
diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c index 4203782d7cb7..aff8387c45cf 100644 --- a/sound/pci/emu10k1/emu10k1.c +++ b/sound/pci/emu10k1/emu10k1.c | |||
@@ -52,6 +52,7 @@ static int max_synth_voices[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 64}; | |||
52 | static int max_buffer_size[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 128}; | 52 | static int max_buffer_size[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 128}; |
53 | static int enable_ir[SNDRV_CARDS]; | 53 | static int enable_ir[SNDRV_CARDS]; |
54 | static uint subsystem[SNDRV_CARDS]; /* Force card subsystem model */ | 54 | static uint subsystem[SNDRV_CARDS]; /* Force card subsystem model */ |
55 | static uint delay_pcm_irq[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2}; | ||
55 | 56 | ||
56 | module_param_array(index, int, NULL, 0444); | 57 | module_param_array(index, int, NULL, 0444); |
57 | MODULE_PARM_DESC(index, "Index value for the EMU10K1 soundcard."); | 58 | MODULE_PARM_DESC(index, "Index value for the EMU10K1 soundcard."); |
@@ -73,6 +74,8 @@ module_param_array(enable_ir, bool, NULL, 0444); | |||
73 | MODULE_PARM_DESC(enable_ir, "Enable IR."); | 74 | MODULE_PARM_DESC(enable_ir, "Enable IR."); |
74 | module_param_array(subsystem, uint, NULL, 0444); | 75 | module_param_array(subsystem, uint, NULL, 0444); |
75 | MODULE_PARM_DESC(subsystem, "Force card subsystem model."); | 76 | MODULE_PARM_DESC(subsystem, "Force card subsystem model."); |
77 | module_param_array(delay_pcm_irq, uint, NULL, 0444); | ||
78 | MODULE_PARM_DESC(delay_pcm_irq, "Delay PCM interrupt by specified number of samples (default 0)."); | ||
76 | /* | 79 | /* |
77 | * Class 0401: 1102:0008 (rev 00) Subsystem: 1102:1001 -> Audigy2 Value Model:SB0400 | 80 | * Class 0401: 1102:0008 (rev 00) Subsystem: 1102:1001 -> Audigy2 Value Model:SB0400 |
78 | */ | 81 | */ |
@@ -127,6 +130,7 @@ static int __devinit snd_card_emu10k1_probe(struct pci_dev *pci, | |||
127 | &emu)) < 0) | 130 | &emu)) < 0) |
128 | goto error; | 131 | goto error; |
129 | card->private_data = emu; | 132 | card->private_data = emu; |
133 | emu->delay_pcm_irq = delay_pcm_irq[dev] & 0x1f; | ||
130 | if ((err = snd_emu10k1_pcm(emu, 0, NULL)) < 0) | 134 | if ((err = snd_emu10k1_pcm(emu, 0, NULL)) < 0) |
131 | goto error; | 135 | goto error; |
132 | if ((err = snd_emu10k1_pcm_mic(emu, 1, NULL)) < 0) | 136 | if ((err = snd_emu10k1_pcm_mic(emu, 1, NULL)) < 0) |
diff --git a/sound/pci/emu10k1/emumpu401.c b/sound/pci/emu10k1/emumpu401.c index 8578c70c61f2..bab564824efe 100644 --- a/sound/pci/emu10k1/emumpu401.c +++ b/sound/pci/emu10k1/emumpu401.c | |||
@@ -321,7 +321,7 @@ static struct snd_rawmidi_ops snd_emu10k1_midi_input = | |||
321 | 321 | ||
322 | static void snd_emu10k1_midi_free(struct snd_rawmidi *rmidi) | 322 | static void snd_emu10k1_midi_free(struct snd_rawmidi *rmidi) |
323 | { | 323 | { |
324 | struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)rmidi->private_data; | 324 | struct snd_emu10k1_midi *midi = rmidi->private_data; |
325 | midi->interrupt = NULL; | 325 | midi->interrupt = NULL; |
326 | midi->rmidi = NULL; | 326 | midi->rmidi = NULL; |
327 | } | 327 | } |
diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index 55b83ef73c63..622bace148e3 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c | |||
@@ -332,7 +332,7 @@ static void snd_emu10k1_pcm_init_voice(struct snd_emu10k1 *emu, | |||
332 | evoice->epcm->ccca_start_addr = start_addr + ccis; | 332 | evoice->epcm->ccca_start_addr = start_addr + ccis; |
333 | if (extra) { | 333 | if (extra) { |
334 | start_addr += ccis; | 334 | start_addr += ccis; |
335 | end_addr += ccis; | 335 | end_addr += ccis + emu->delay_pcm_irq; |
336 | } | 336 | } |
337 | if (stereo && !extra) { | 337 | if (stereo && !extra) { |
338 | snd_emu10k1_ptr_write(emu, CPF, voice, CPF_STEREO_MASK); | 338 | snd_emu10k1_ptr_write(emu, CPF, voice, CPF_STEREO_MASK); |
@@ -360,7 +360,9 @@ static void snd_emu10k1_pcm_init_voice(struct snd_emu10k1 *emu, | |||
360 | /* Assumption that PT is already 0 so no harm overwriting */ | 360 | /* Assumption that PT is already 0 so no harm overwriting */ |
361 | snd_emu10k1_ptr_write(emu, PTRX, voice, (send_amount[0] << 8) | send_amount[1]); | 361 | snd_emu10k1_ptr_write(emu, PTRX, voice, (send_amount[0] << 8) | send_amount[1]); |
362 | snd_emu10k1_ptr_write(emu, DSL, voice, end_addr | (send_amount[3] << 24)); | 362 | snd_emu10k1_ptr_write(emu, DSL, voice, end_addr | (send_amount[3] << 24)); |
363 | snd_emu10k1_ptr_write(emu, PSST, voice, start_addr | (send_amount[2] << 24)); | 363 | snd_emu10k1_ptr_write(emu, PSST, voice, |
364 | (start_addr + (extra ? emu->delay_pcm_irq : 0)) | | ||
365 | (send_amount[2] << 24)); | ||
364 | if (emu->card_capabilities->emu_model) | 366 | if (emu->card_capabilities->emu_model) |
365 | pitch_target = PITCH_48000; /* Disable interpolators on emu1010 card */ | 367 | pitch_target = PITCH_48000; /* Disable interpolators on emu1010 card */ |
366 | else | 368 | else |
@@ -732,6 +734,23 @@ static void snd_emu10k1_playback_stop_voice(struct snd_emu10k1 *emu, struct snd_ | |||
732 | snd_emu10k1_ptr_write(emu, IP, voice, 0); | 734 | snd_emu10k1_ptr_write(emu, IP, voice, 0); |
733 | } | 735 | } |
734 | 736 | ||
737 | static inline void snd_emu10k1_playback_mangle_extra(struct snd_emu10k1 *emu, | ||
738 | struct snd_emu10k1_pcm *epcm, | ||
739 | struct snd_pcm_substream *substream, | ||
740 | struct snd_pcm_runtime *runtime) | ||
741 | { | ||
742 | unsigned int ptr, period_pos; | ||
743 | |||
744 | /* try to sychronize the current position for the interrupt | ||
745 | source voice */ | ||
746 | period_pos = runtime->status->hw_ptr - runtime->hw_ptr_interrupt; | ||
747 | period_pos %= runtime->period_size; | ||
748 | ptr = snd_emu10k1_ptr_read(emu, CCCA, epcm->extra->number); | ||
749 | ptr &= ~0x00ffffff; | ||
750 | ptr |= epcm->ccca_start_addr + period_pos; | ||
751 | snd_emu10k1_ptr_write(emu, CCCA, epcm->extra->number, ptr); | ||
752 | } | ||
753 | |||
735 | static int snd_emu10k1_playback_trigger(struct snd_pcm_substream *substream, | 754 | static int snd_emu10k1_playback_trigger(struct snd_pcm_substream *substream, |
736 | int cmd) | 755 | int cmd) |
737 | { | 756 | { |
@@ -753,6 +772,8 @@ static int snd_emu10k1_playback_trigger(struct snd_pcm_substream *substream, | |||
753 | /* follow thru */ | 772 | /* follow thru */ |
754 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 773 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
755 | case SNDRV_PCM_TRIGGER_RESUME: | 774 | case SNDRV_PCM_TRIGGER_RESUME: |
775 | if (cmd == SNDRV_PCM_TRIGGER_PAUSE_RELEASE) | ||
776 | snd_emu10k1_playback_mangle_extra(emu, epcm, substream, runtime); | ||
756 | mix = &emu->pcm_mixer[substream->number]; | 777 | mix = &emu->pcm_mixer[substream->number]; |
757 | snd_emu10k1_playback_prepare_voice(emu, epcm->voices[0], 1, 0, mix); | 778 | snd_emu10k1_playback_prepare_voice(emu, epcm->voices[0], 1, 0, mix); |
758 | snd_emu10k1_playback_prepare_voice(emu, epcm->voices[1], 0, 0, mix); | 779 | snd_emu10k1_playback_prepare_voice(emu, epcm->voices[1], 0, 0, mix); |
@@ -869,8 +890,9 @@ static snd_pcm_uframes_t snd_emu10k1_playback_pointer(struct snd_pcm_substream * | |||
869 | #endif | 890 | #endif |
870 | /* | 891 | /* |
871 | printk(KERN_DEBUG | 892 | printk(KERN_DEBUG |
872 | "ptr = 0x%x, buffer_size = 0x%x, period_size = 0x%x\n", | 893 | "ptr = 0x%lx, buffer_size = 0x%lx, period_size = 0x%lx\n", |
873 | ptr, runtime->buffer_size, runtime->period_size); | 894 | (long)ptr, (long)runtime->buffer_size, |
895 | (long)runtime->period_size); | ||
874 | */ | 896 | */ |
875 | return ptr; | 897 | return ptr; |
876 | } | 898 | } |
diff --git a/sound/pci/emu10k1/memory.c b/sound/pci/emu10k1/memory.c index ffb1ddb8dc28..957a311514c8 100644 --- a/sound/pci/emu10k1/memory.c +++ b/sound/pci/emu10k1/memory.c | |||
@@ -310,8 +310,10 @@ snd_emu10k1_alloc_pages(struct snd_emu10k1 *emu, struct snd_pcm_substream *subst | |||
310 | if (snd_BUG_ON(!hdr)) | 310 | if (snd_BUG_ON(!hdr)) |
311 | return NULL; | 311 | return NULL; |
312 | 312 | ||
313 | idx = runtime->period_size >= runtime->buffer_size ? | ||
314 | (emu->delay_pcm_irq * 2) : 0; | ||
313 | mutex_lock(&hdr->block_mutex); | 315 | mutex_lock(&hdr->block_mutex); |
314 | blk = search_empty(emu, runtime->dma_bytes); | 316 | blk = search_empty(emu, runtime->dma_bytes + idx); |
315 | if (blk == NULL) { | 317 | if (blk == NULL) { |
316 | mutex_unlock(&hdr->block_mutex); | 318 | mutex_unlock(&hdr->block_mutex); |
317 | return NULL; | 319 | return NULL; |
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index ba2098d20ccc..14829210ef0b 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c | |||
@@ -396,15 +396,18 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid, | |||
396 | } | 396 | } |
397 | for (n = prev_nid + 1; n <= val; n++) { | 397 | for (n = prev_nid + 1; n <= val; n++) { |
398 | if (conns >= max_conns) { | 398 | if (conns >= max_conns) { |
399 | snd_printk(KERN_ERR | 399 | snd_printk(KERN_ERR "hda_codec: " |
400 | "Too many connections\n"); | 400 | "Too many connections %d for NID 0x%x\n", |
401 | conns, nid); | ||
401 | return -EINVAL; | 402 | return -EINVAL; |
402 | } | 403 | } |
403 | conn_list[conns++] = n; | 404 | conn_list[conns++] = n; |
404 | } | 405 | } |
405 | } else { | 406 | } else { |
406 | if (conns >= max_conns) { | 407 | if (conns >= max_conns) { |
407 | snd_printk(KERN_ERR "Too many connections\n"); | 408 | snd_printk(KERN_ERR "hda_codec: " |
409 | "Too many connections %d for NID 0x%x\n", | ||
410 | conns, nid); | ||
408 | return -EINVAL; | 411 | return -EINVAL; |
409 | } | 412 | } |
410 | conn_list[conns++] = val; | 413 | conn_list[conns++] = val; |
@@ -586,6 +589,7 @@ int /*__devinit*/ snd_hda_bus_new(struct snd_card *card, | |||
586 | bus->ops = temp->ops; | 589 | bus->ops = temp->ops; |
587 | 590 | ||
588 | mutex_init(&bus->cmd_mutex); | 591 | mutex_init(&bus->cmd_mutex); |
592 | mutex_init(&bus->prepare_mutex); | ||
589 | INIT_LIST_HEAD(&bus->codec_list); | 593 | INIT_LIST_HEAD(&bus->codec_list); |
590 | 594 | ||
591 | snprintf(bus->workq_name, sizeof(bus->workq_name), | 595 | snprintf(bus->workq_name, sizeof(bus->workq_name), |
@@ -730,15 +734,17 @@ static void /*__devinit*/ setup_fg_nodes(struct hda_codec *codec) | |||
730 | total_nodes = snd_hda_get_sub_nodes(codec, AC_NODE_ROOT, &nid); | 734 | total_nodes = snd_hda_get_sub_nodes(codec, AC_NODE_ROOT, &nid); |
731 | for (i = 0; i < total_nodes; i++, nid++) { | 735 | for (i = 0; i < total_nodes; i++, nid++) { |
732 | function_id = snd_hda_param_read(codec, nid, | 736 | function_id = snd_hda_param_read(codec, nid, |
733 | AC_PAR_FUNCTION_TYPE) & 0xff; | 737 | AC_PAR_FUNCTION_TYPE); |
734 | switch (function_id) { | 738 | switch (function_id & 0xff) { |
735 | case AC_GRP_AUDIO_FUNCTION: | 739 | case AC_GRP_AUDIO_FUNCTION: |
736 | codec->afg = nid; | 740 | codec->afg = nid; |
737 | codec->function_id = function_id; | 741 | codec->afg_function_id = function_id & 0xff; |
742 | codec->afg_unsol = (function_id >> 8) & 1; | ||
738 | break; | 743 | break; |
739 | case AC_GRP_MODEM_FUNCTION: | 744 | case AC_GRP_MODEM_FUNCTION: |
740 | codec->mfg = nid; | 745 | codec->mfg = nid; |
741 | codec->function_id = function_id; | 746 | codec->mfg_function_id = function_id & 0xff; |
747 | codec->mfg_unsol = (function_id >> 8) & 1; | ||
742 | break; | 748 | break; |
743 | default: | 749 | default: |
744 | break; | 750 | break; |
@@ -966,6 +972,36 @@ static void restore_init_pincfgs(struct hda_codec *codec) | |||
966 | } | 972 | } |
967 | 973 | ||
968 | /* | 974 | /* |
975 | * audio-converter setup caches | ||
976 | */ | ||
977 | struct hda_cvt_setup { | ||
978 | hda_nid_t nid; | ||
979 | u8 stream_tag; | ||
980 | u8 channel_id; | ||
981 | u16 format_id; | ||
982 | unsigned char active; /* cvt is currently used */ | ||
983 | unsigned char dirty; /* setups should be cleared */ | ||
984 | }; | ||
985 | |||
986 | /* get or create a cache entry for the given audio converter NID */ | ||
987 | static struct hda_cvt_setup * | ||
988 | get_hda_cvt_setup(struct hda_codec *codec, hda_nid_t nid) | ||
989 | { | ||
990 | struct hda_cvt_setup *p; | ||
991 | int i; | ||
992 | |||
993 | for (i = 0; i < codec->cvt_setups.used; i++) { | ||
994 | p = snd_array_elem(&codec->cvt_setups, i); | ||
995 | if (p->nid == nid) | ||
996 | return p; | ||
997 | } | ||
998 | p = snd_array_new(&codec->cvt_setups); | ||
999 | if (p) | ||
1000 | p->nid = nid; | ||
1001 | return p; | ||
1002 | } | ||
1003 | |||
1004 | /* | ||
969 | * codec destructor | 1005 | * codec destructor |
970 | */ | 1006 | */ |
971 | static void snd_hda_codec_free(struct hda_codec *codec) | 1007 | static void snd_hda_codec_free(struct hda_codec *codec) |
@@ -1039,6 +1075,7 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, | |||
1039 | snd_array_init(&codec->nids, sizeof(struct hda_nid_item), 32); | 1075 | snd_array_init(&codec->nids, sizeof(struct hda_nid_item), 32); |
1040 | snd_array_init(&codec->init_pins, sizeof(struct hda_pincfg), 16); | 1076 | snd_array_init(&codec->init_pins, sizeof(struct hda_pincfg), 16); |
1041 | snd_array_init(&codec->driver_pins, sizeof(struct hda_pincfg), 16); | 1077 | snd_array_init(&codec->driver_pins, sizeof(struct hda_pincfg), 16); |
1078 | snd_array_init(&codec->cvt_setups, sizeof(struct hda_cvt_setup), 8); | ||
1042 | if (codec->bus->modelname) { | 1079 | if (codec->bus->modelname) { |
1043 | codec->modelname = kstrdup(codec->bus->modelname, GFP_KERNEL); | 1080 | codec->modelname = kstrdup(codec->bus->modelname, GFP_KERNEL); |
1044 | if (!codec->modelname) { | 1081 | if (!codec->modelname) { |
@@ -1176,37 +1213,126 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, | |||
1176 | u32 stream_tag, | 1213 | u32 stream_tag, |
1177 | int channel_id, int format) | 1214 | int channel_id, int format) |
1178 | { | 1215 | { |
1216 | struct hda_codec *c; | ||
1217 | struct hda_cvt_setup *p; | ||
1218 | unsigned int oldval, newval; | ||
1219 | int i; | ||
1220 | |||
1179 | if (!nid) | 1221 | if (!nid) |
1180 | return; | 1222 | return; |
1181 | 1223 | ||
1182 | snd_printdd("hda_codec_setup_stream: " | 1224 | snd_printdd("hda_codec_setup_stream: " |
1183 | "NID=0x%x, stream=0x%x, channel=%d, format=0x%x\n", | 1225 | "NID=0x%x, stream=0x%x, channel=%d, format=0x%x\n", |
1184 | nid, stream_tag, channel_id, format); | 1226 | nid, stream_tag, channel_id, format); |
1185 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CHANNEL_STREAMID, | 1227 | p = get_hda_cvt_setup(codec, nid); |
1186 | (stream_tag << 4) | channel_id); | 1228 | if (!p) |
1187 | msleep(1); | 1229 | return; |
1188 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, format); | 1230 | /* update the stream-id if changed */ |
1231 | if (p->stream_tag != stream_tag || p->channel_id != channel_id) { | ||
1232 | oldval = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0); | ||
1233 | newval = (stream_tag << 4) | channel_id; | ||
1234 | if (oldval != newval) | ||
1235 | snd_hda_codec_write(codec, nid, 0, | ||
1236 | AC_VERB_SET_CHANNEL_STREAMID, | ||
1237 | newval); | ||
1238 | p->stream_tag = stream_tag; | ||
1239 | p->channel_id = channel_id; | ||
1240 | } | ||
1241 | /* update the format-id if changed */ | ||
1242 | if (p->format_id != format) { | ||
1243 | oldval = snd_hda_codec_read(codec, nid, 0, | ||
1244 | AC_VERB_GET_STREAM_FORMAT, 0); | ||
1245 | if (oldval != format) { | ||
1246 | msleep(1); | ||
1247 | snd_hda_codec_write(codec, nid, 0, | ||
1248 | AC_VERB_SET_STREAM_FORMAT, | ||
1249 | format); | ||
1250 | } | ||
1251 | p->format_id = format; | ||
1252 | } | ||
1253 | p->active = 1; | ||
1254 | p->dirty = 0; | ||
1255 | |||
1256 | /* make other inactive cvts with the same stream-tag dirty */ | ||
1257 | list_for_each_entry(c, &codec->bus->codec_list, list) { | ||
1258 | for (i = 0; i < c->cvt_setups.used; i++) { | ||
1259 | p = snd_array_elem(&c->cvt_setups, i); | ||
1260 | if (!p->active && p->stream_tag == stream_tag) | ||
1261 | p->dirty = 1; | ||
1262 | } | ||
1263 | } | ||
1189 | } | 1264 | } |
1190 | EXPORT_SYMBOL_HDA(snd_hda_codec_setup_stream); | 1265 | EXPORT_SYMBOL_HDA(snd_hda_codec_setup_stream); |
1191 | 1266 | ||
1267 | static void really_cleanup_stream(struct hda_codec *codec, | ||
1268 | struct hda_cvt_setup *q); | ||
1269 | |||
1192 | /** | 1270 | /** |
1193 | * snd_hda_codec_cleanup_stream - clean up the codec for closing | 1271 | * __snd_hda_codec_cleanup_stream - clean up the codec for closing |
1194 | * @codec: the CODEC to clean up | 1272 | * @codec: the CODEC to clean up |
1195 | * @nid: the NID to clean up | 1273 | * @nid: the NID to clean up |
1274 | * @do_now: really clean up the stream instead of clearing the active flag | ||
1196 | */ | 1275 | */ |
1197 | void snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid) | 1276 | void __snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid, |
1277 | int do_now) | ||
1198 | { | 1278 | { |
1279 | struct hda_cvt_setup *p; | ||
1280 | |||
1199 | if (!nid) | 1281 | if (!nid) |
1200 | return; | 1282 | return; |
1201 | 1283 | ||
1202 | snd_printdd("hda_codec_cleanup_stream: NID=0x%x\n", nid); | 1284 | snd_printdd("hda_codec_cleanup_stream: NID=0x%x\n", nid); |
1285 | p = get_hda_cvt_setup(codec, nid); | ||
1286 | if (p) { | ||
1287 | /* here we just clear the active flag when do_now isn't set; | ||
1288 | * actual clean-ups will be done later in | ||
1289 | * purify_inactive_streams() called from snd_hda_codec_prpapre() | ||
1290 | */ | ||
1291 | if (do_now) | ||
1292 | really_cleanup_stream(codec, p); | ||
1293 | else | ||
1294 | p->active = 0; | ||
1295 | } | ||
1296 | } | ||
1297 | EXPORT_SYMBOL_HDA(__snd_hda_codec_cleanup_stream); | ||
1298 | |||
1299 | static void really_cleanup_stream(struct hda_codec *codec, | ||
1300 | struct hda_cvt_setup *q) | ||
1301 | { | ||
1302 | hda_nid_t nid = q->nid; | ||
1203 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CHANNEL_STREAMID, 0); | 1303 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CHANNEL_STREAMID, 0); |
1204 | #if 0 /* keep the format */ | ||
1205 | msleep(1); | ||
1206 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, 0); | 1304 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, 0); |
1207 | #endif | 1305 | memset(q, 0, sizeof(*q)); |
1306 | q->nid = nid; | ||
1307 | } | ||
1308 | |||
1309 | /* clean up the all conflicting obsolete streams */ | ||
1310 | static void purify_inactive_streams(struct hda_codec *codec) | ||
1311 | { | ||
1312 | struct hda_codec *c; | ||
1313 | int i; | ||
1314 | |||
1315 | list_for_each_entry(c, &codec->bus->codec_list, list) { | ||
1316 | for (i = 0; i < c->cvt_setups.used; i++) { | ||
1317 | struct hda_cvt_setup *p; | ||
1318 | p = snd_array_elem(&c->cvt_setups, i); | ||
1319 | if (p->dirty) | ||
1320 | really_cleanup_stream(c, p); | ||
1321 | } | ||
1322 | } | ||
1323 | } | ||
1324 | |||
1325 | /* clean up all streams; called from suspend */ | ||
1326 | static void hda_cleanup_all_streams(struct hda_codec *codec) | ||
1327 | { | ||
1328 | int i; | ||
1329 | |||
1330 | for (i = 0; i < codec->cvt_setups.used; i++) { | ||
1331 | struct hda_cvt_setup *p = snd_array_elem(&codec->cvt_setups, i); | ||
1332 | if (p->stream_tag) | ||
1333 | really_cleanup_stream(codec, p); | ||
1334 | } | ||
1208 | } | 1335 | } |
1209 | EXPORT_SYMBOL_HDA(snd_hda_codec_cleanup_stream); | ||
1210 | 1336 | ||
1211 | /* | 1337 | /* |
1212 | * amp access functions | 1338 | * amp access functions |
@@ -1565,6 +1691,17 @@ void snd_hda_codec_resume_amp(struct hda_codec *codec) | |||
1565 | EXPORT_SYMBOL_HDA(snd_hda_codec_resume_amp); | 1691 | EXPORT_SYMBOL_HDA(snd_hda_codec_resume_amp); |
1566 | #endif /* SND_HDA_NEEDS_RESUME */ | 1692 | #endif /* SND_HDA_NEEDS_RESUME */ |
1567 | 1693 | ||
1694 | static u32 get_amp_max_value(struct hda_codec *codec, hda_nid_t nid, int dir, | ||
1695 | unsigned int ofs) | ||
1696 | { | ||
1697 | u32 caps = query_amp_caps(codec, nid, dir); | ||
1698 | /* get num steps */ | ||
1699 | caps = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT; | ||
1700 | if (ofs < caps) | ||
1701 | caps -= ofs; | ||
1702 | return caps; | ||
1703 | } | ||
1704 | |||
1568 | /** | 1705 | /** |
1569 | * snd_hda_mixer_amp_volume_info - Info callback for a standard AMP mixer | 1706 | * snd_hda_mixer_amp_volume_info - Info callback for a standard AMP mixer |
1570 | * | 1707 | * |
@@ -1579,23 +1716,17 @@ int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, | |||
1579 | u8 chs = get_amp_channels(kcontrol); | 1716 | u8 chs = get_amp_channels(kcontrol); |
1580 | int dir = get_amp_direction(kcontrol); | 1717 | int dir = get_amp_direction(kcontrol); |
1581 | unsigned int ofs = get_amp_offset(kcontrol); | 1718 | unsigned int ofs = get_amp_offset(kcontrol); |
1582 | u32 caps; | ||
1583 | 1719 | ||
1584 | caps = query_amp_caps(codec, nid, dir); | 1720 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
1585 | /* num steps */ | 1721 | uinfo->count = chs == 3 ? 2 : 1; |
1586 | caps = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT; | 1722 | uinfo->value.integer.min = 0; |
1587 | if (!caps) { | 1723 | uinfo->value.integer.max = get_amp_max_value(codec, nid, dir, ofs); |
1724 | if (!uinfo->value.integer.max) { | ||
1588 | printk(KERN_WARNING "hda_codec: " | 1725 | printk(KERN_WARNING "hda_codec: " |
1589 | "num_steps = 0 for NID=0x%x (ctl = %s)\n", nid, | 1726 | "num_steps = 0 for NID=0x%x (ctl = %s)\n", nid, |
1590 | kcontrol->id.name); | 1727 | kcontrol->id.name); |
1591 | return -EINVAL; | 1728 | return -EINVAL; |
1592 | } | 1729 | } |
1593 | if (ofs < caps) | ||
1594 | caps -= ofs; | ||
1595 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
1596 | uinfo->count = chs == 3 ? 2 : 1; | ||
1597 | uinfo->value.integer.min = 0; | ||
1598 | uinfo->value.integer.max = caps; | ||
1599 | return 0; | 1730 | return 0; |
1600 | } | 1731 | } |
1601 | EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_info); | 1732 | EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_info); |
@@ -1620,8 +1751,14 @@ update_amp_value(struct hda_codec *codec, hda_nid_t nid, | |||
1620 | int ch, int dir, int idx, unsigned int ofs, | 1751 | int ch, int dir, int idx, unsigned int ofs, |
1621 | unsigned int val) | 1752 | unsigned int val) |
1622 | { | 1753 | { |
1754 | unsigned int maxval; | ||
1755 | |||
1623 | if (val > 0) | 1756 | if (val > 0) |
1624 | val += ofs; | 1757 | val += ofs; |
1758 | /* ofs = 0: raw max value */ | ||
1759 | maxval = get_amp_max_value(codec, nid, dir, 0); | ||
1760 | if (val > maxval) | ||
1761 | val = maxval; | ||
1625 | return snd_hda_codec_amp_update(codec, nid, ch, dir, idx, | 1762 | return snd_hda_codec_amp_update(codec, nid, ch, dir, idx, |
1626 | HDA_AMP_VOLMASK, val); | 1763 | HDA_AMP_VOLMASK, val); |
1627 | } | 1764 | } |
@@ -2912,6 +3049,7 @@ static void hda_call_codec_suspend(struct hda_codec *codec) | |||
2912 | { | 3049 | { |
2913 | if (codec->patch_ops.suspend) | 3050 | if (codec->patch_ops.suspend) |
2914 | codec->patch_ops.suspend(codec, PMSG_SUSPEND); | 3051 | codec->patch_ops.suspend(codec, PMSG_SUSPEND); |
3052 | hda_cleanup_all_streams(codec); | ||
2915 | hda_set_power_state(codec, | 3053 | hda_set_power_state(codec, |
2916 | codec->afg ? codec->afg : codec->mfg, | 3054 | codec->afg ? codec->afg : codec->mfg, |
2917 | AC_PWRST_D3); | 3055 | AC_PWRST_D3); |
@@ -2999,26 +3137,31 @@ struct hda_rate_tbl { | |||
2999 | unsigned int hda_fmt; | 3137 | unsigned int hda_fmt; |
3000 | }; | 3138 | }; |
3001 | 3139 | ||
3140 | /* rate = base * mult / div */ | ||
3141 | #define HDA_RATE(base, mult, div) \ | ||
3142 | (AC_FMT_BASE_##base##K | (((mult) - 1) << AC_FMT_MULT_SHIFT) | \ | ||
3143 | (((div) - 1) << AC_FMT_DIV_SHIFT)) | ||
3144 | |||
3002 | static struct hda_rate_tbl rate_bits[] = { | 3145 | static struct hda_rate_tbl rate_bits[] = { |
3003 | /* rate in Hz, ALSA rate bitmask, HDA format value */ | 3146 | /* rate in Hz, ALSA rate bitmask, HDA format value */ |
3004 | 3147 | ||
3005 | /* autodetected value used in snd_hda_query_supported_pcm */ | 3148 | /* autodetected value used in snd_hda_query_supported_pcm */ |
3006 | { 8000, SNDRV_PCM_RATE_8000, 0x0500 }, /* 1/6 x 48 */ | 3149 | { 8000, SNDRV_PCM_RATE_8000, HDA_RATE(48, 1, 6) }, |
3007 | { 11025, SNDRV_PCM_RATE_11025, 0x4300 }, /* 1/4 x 44 */ | 3150 | { 11025, SNDRV_PCM_RATE_11025, HDA_RATE(44, 1, 4) }, |
3008 | { 16000, SNDRV_PCM_RATE_16000, 0x0200 }, /* 1/3 x 48 */ | 3151 | { 16000, SNDRV_PCM_RATE_16000, HDA_RATE(48, 1, 3) }, |
3009 | { 22050, SNDRV_PCM_RATE_22050, 0x4100 }, /* 1/2 x 44 */ | 3152 | { 22050, SNDRV_PCM_RATE_22050, HDA_RATE(44, 1, 2) }, |
3010 | { 32000, SNDRV_PCM_RATE_32000, 0x0a00 }, /* 2/3 x 48 */ | 3153 | { 32000, SNDRV_PCM_RATE_32000, HDA_RATE(48, 2, 3) }, |
3011 | { 44100, SNDRV_PCM_RATE_44100, 0x4000 }, /* 44 */ | 3154 | { 44100, SNDRV_PCM_RATE_44100, HDA_RATE(44, 1, 1) }, |
3012 | { 48000, SNDRV_PCM_RATE_48000, 0x0000 }, /* 48 */ | 3155 | { 48000, SNDRV_PCM_RATE_48000, HDA_RATE(48, 1, 1) }, |
3013 | { 88200, SNDRV_PCM_RATE_88200, 0x4800 }, /* 2 x 44 */ | 3156 | { 88200, SNDRV_PCM_RATE_88200, HDA_RATE(44, 2, 1) }, |
3014 | { 96000, SNDRV_PCM_RATE_96000, 0x0800 }, /* 2 x 48 */ | 3157 | { 96000, SNDRV_PCM_RATE_96000, HDA_RATE(48, 2, 1) }, |
3015 | { 176400, SNDRV_PCM_RATE_176400, 0x5800 },/* 4 x 44 */ | 3158 | { 176400, SNDRV_PCM_RATE_176400, HDA_RATE(44, 4, 1) }, |
3016 | { 192000, SNDRV_PCM_RATE_192000, 0x1800 }, /* 4 x 48 */ | 3159 | { 192000, SNDRV_PCM_RATE_192000, HDA_RATE(48, 4, 1) }, |
3017 | #define AC_PAR_PCM_RATE_BITS 11 | 3160 | #define AC_PAR_PCM_RATE_BITS 11 |
3018 | /* up to bits 10, 384kHZ isn't supported properly */ | 3161 | /* up to bits 10, 384kHZ isn't supported properly */ |
3019 | 3162 | ||
3020 | /* not autodetected value */ | 3163 | /* not autodetected value */ |
3021 | { 9600, SNDRV_PCM_RATE_KNOT, 0x0400 }, /* 1/5 x 48 */ | 3164 | { 9600, SNDRV_PCM_RATE_KNOT, HDA_RATE(48, 1, 5) }, |
3022 | 3165 | ||
3023 | { 0 } /* terminator */ | 3166 | { 0 } /* terminator */ |
3024 | }; | 3167 | }; |
@@ -3037,7 +3180,8 @@ static struct hda_rate_tbl rate_bits[] = { | |||
3037 | unsigned int snd_hda_calc_stream_format(unsigned int rate, | 3180 | unsigned int snd_hda_calc_stream_format(unsigned int rate, |
3038 | unsigned int channels, | 3181 | unsigned int channels, |
3039 | unsigned int format, | 3182 | unsigned int format, |
3040 | unsigned int maxbps) | 3183 | unsigned int maxbps, |
3184 | unsigned short spdif_ctls) | ||
3041 | { | 3185 | { |
3042 | int i; | 3186 | int i; |
3043 | unsigned int val = 0; | 3187 | unsigned int val = 0; |
@@ -3060,20 +3204,20 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate, | |||
3060 | 3204 | ||
3061 | switch (snd_pcm_format_width(format)) { | 3205 | switch (snd_pcm_format_width(format)) { |
3062 | case 8: | 3206 | case 8: |
3063 | val |= 0x00; | 3207 | val |= AC_FMT_BITS_8; |
3064 | break; | 3208 | break; |
3065 | case 16: | 3209 | case 16: |
3066 | val |= 0x10; | 3210 | val |= AC_FMT_BITS_16; |
3067 | break; | 3211 | break; |
3068 | case 20: | 3212 | case 20: |
3069 | case 24: | 3213 | case 24: |
3070 | case 32: | 3214 | case 32: |
3071 | if (maxbps >= 32 || format == SNDRV_PCM_FORMAT_FLOAT_LE) | 3215 | if (maxbps >= 32 || format == SNDRV_PCM_FORMAT_FLOAT_LE) |
3072 | val |= 0x40; | 3216 | val |= AC_FMT_BITS_32; |
3073 | else if (maxbps >= 24) | 3217 | else if (maxbps >= 24) |
3074 | val |= 0x30; | 3218 | val |= AC_FMT_BITS_24; |
3075 | else | 3219 | else |
3076 | val |= 0x20; | 3220 | val |= AC_FMT_BITS_20; |
3077 | break; | 3221 | break; |
3078 | default: | 3222 | default: |
3079 | snd_printdd("invalid format width %d\n", | 3223 | snd_printdd("invalid format width %d\n", |
@@ -3081,6 +3225,9 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate, | |||
3081 | return 0; | 3225 | return 0; |
3082 | } | 3226 | } |
3083 | 3227 | ||
3228 | if (spdif_ctls & AC_DIG1_NONAUDIO) | ||
3229 | val |= AC_FMT_TYPE_NON_PCM; | ||
3230 | |||
3084 | return val; | 3231 | return val; |
3085 | } | 3232 | } |
3086 | EXPORT_SYMBOL_HDA(snd_hda_calc_stream_format); | 3233 | EXPORT_SYMBOL_HDA(snd_hda_calc_stream_format); |
@@ -3352,6 +3499,35 @@ static int set_pcm_default_values(struct hda_codec *codec, | |||
3352 | return 0; | 3499 | return 0; |
3353 | } | 3500 | } |
3354 | 3501 | ||
3502 | /* | ||
3503 | * codec prepare/cleanup entries | ||
3504 | */ | ||
3505 | int snd_hda_codec_prepare(struct hda_codec *codec, | ||
3506 | struct hda_pcm_stream *hinfo, | ||
3507 | unsigned int stream, | ||
3508 | unsigned int format, | ||
3509 | struct snd_pcm_substream *substream) | ||
3510 | { | ||
3511 | int ret; | ||
3512 | mutex_lock(&codec->bus->prepare_mutex); | ||
3513 | ret = hinfo->ops.prepare(hinfo, codec, stream, format, substream); | ||
3514 | if (ret >= 0) | ||
3515 | purify_inactive_streams(codec); | ||
3516 | mutex_unlock(&codec->bus->prepare_mutex); | ||
3517 | return ret; | ||
3518 | } | ||
3519 | EXPORT_SYMBOL_HDA(snd_hda_codec_prepare); | ||
3520 | |||
3521 | void snd_hda_codec_cleanup(struct hda_codec *codec, | ||
3522 | struct hda_pcm_stream *hinfo, | ||
3523 | struct snd_pcm_substream *substream) | ||
3524 | { | ||
3525 | mutex_lock(&codec->bus->prepare_mutex); | ||
3526 | hinfo->ops.cleanup(hinfo, codec, substream); | ||
3527 | mutex_unlock(&codec->bus->prepare_mutex); | ||
3528 | } | ||
3529 | EXPORT_SYMBOL_HDA(snd_hda_codec_cleanup); | ||
3530 | |||
3355 | /* global */ | 3531 | /* global */ |
3356 | const char *snd_hda_pcm_type_name[HDA_PCM_NTYPES] = { | 3532 | const char *snd_hda_pcm_type_name[HDA_PCM_NTYPES] = { |
3357 | "Audio", "SPDIF", "HDMI", "Modem" | 3533 | "Audio", "SPDIF", "HDMI", "Modem" |
@@ -4360,7 +4536,7 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, | |||
4360 | cfg->hp_outs--; | 4536 | cfg->hp_outs--; |
4361 | memmove(cfg->hp_pins + i, cfg->hp_pins + i + 1, | 4537 | memmove(cfg->hp_pins + i, cfg->hp_pins + i + 1, |
4362 | sizeof(cfg->hp_pins[0]) * (cfg->hp_outs - i)); | 4538 | sizeof(cfg->hp_pins[0]) * (cfg->hp_outs - i)); |
4363 | memmove(sequences_hp + i - 1, sequences_hp + i, | 4539 | memmove(sequences_hp + i, sequences_hp + i + 1, |
4364 | sizeof(sequences_hp[0]) * (cfg->hp_outs - i)); | 4540 | sizeof(sequences_hp[0]) * (cfg->hp_outs - i)); |
4365 | } | 4541 | } |
4366 | } | 4542 | } |
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 5991d14e1ec0..62c702240108 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h | |||
@@ -224,6 +224,27 @@ enum { | |||
224 | /* Input converter SDI select */ | 224 | /* Input converter SDI select */ |
225 | #define AC_SDI_SELECT (0xf<<0) | 225 | #define AC_SDI_SELECT (0xf<<0) |
226 | 226 | ||
227 | /* stream format id */ | ||
228 | #define AC_FMT_CHAN_SHIFT 0 | ||
229 | #define AC_FMT_CHAN_MASK (0x0f << 0) | ||
230 | #define AC_FMT_BITS_SHIFT 4 | ||
231 | #define AC_FMT_BITS_MASK (7 << 4) | ||
232 | #define AC_FMT_BITS_8 (0 << 4) | ||
233 | #define AC_FMT_BITS_16 (1 << 4) | ||
234 | #define AC_FMT_BITS_20 (2 << 4) | ||
235 | #define AC_FMT_BITS_24 (3 << 4) | ||
236 | #define AC_FMT_BITS_32 (4 << 4) | ||
237 | #define AC_FMT_DIV_SHIFT 8 | ||
238 | #define AC_FMT_DIV_MASK (7 << 8) | ||
239 | #define AC_FMT_MULT_SHIFT 11 | ||
240 | #define AC_FMT_MULT_MASK (7 << 11) | ||
241 | #define AC_FMT_BASE_SHIFT 14 | ||
242 | #define AC_FMT_BASE_48K (0 << 14) | ||
243 | #define AC_FMT_BASE_44K (1 << 14) | ||
244 | #define AC_FMT_TYPE_SHIFT 15 | ||
245 | #define AC_FMT_TYPE_PCM (0 << 15) | ||
246 | #define AC_FMT_TYPE_NON_PCM (1 << 15) | ||
247 | |||
227 | /* Unsolicited response control */ | 248 | /* Unsolicited response control */ |
228 | #define AC_UNSOL_TAG (0x3f<<0) | 249 | #define AC_UNSOL_TAG (0x3f<<0) |
229 | #define AC_UNSOL_ENABLED (1<<7) | 250 | #define AC_UNSOL_ENABLED (1<<7) |
@@ -364,6 +385,9 @@ enum { | |||
364 | #define AC_DIG2_CC (0x7f<<0) | 385 | #define AC_DIG2_CC (0x7f<<0) |
365 | 386 | ||
366 | /* Pin widget control - 8bit */ | 387 | /* Pin widget control - 8bit */ |
388 | #define AC_PINCTL_EPT (0x3<<0) | ||
389 | #define AC_PINCTL_EPT_NATIVE 0 | ||
390 | #define AC_PINCTL_EPT_HBR 3 | ||
367 | #define AC_PINCTL_VREFEN (0x7<<0) | 391 | #define AC_PINCTL_VREFEN (0x7<<0) |
368 | #define AC_PINCTL_VREF_HIZ 0 /* Hi-Z */ | 392 | #define AC_PINCTL_VREF_HIZ 0 /* Hi-Z */ |
369 | #define AC_PINCTL_VREF_50 1 /* 50% */ | 393 | #define AC_PINCTL_VREF_50 1 /* 50% */ |
@@ -624,6 +648,7 @@ struct hda_bus { | |||
624 | struct hda_codec *caddr_tbl[HDA_MAX_CODEC_ADDRESS + 1]; | 648 | struct hda_codec *caddr_tbl[HDA_MAX_CODEC_ADDRESS + 1]; |
625 | 649 | ||
626 | struct mutex cmd_mutex; | 650 | struct mutex cmd_mutex; |
651 | struct mutex prepare_mutex; | ||
627 | 652 | ||
628 | /* unsolicited event queue */ | 653 | /* unsolicited event queue */ |
629 | struct hda_bus_unsolicited *unsol; | 654 | struct hda_bus_unsolicited *unsol; |
@@ -760,7 +785,10 @@ struct hda_codec { | |||
760 | hda_nid_t mfg; /* MFG node id */ | 785 | hda_nid_t mfg; /* MFG node id */ |
761 | 786 | ||
762 | /* ids */ | 787 | /* ids */ |
763 | u32 function_id; | 788 | u8 afg_function_id; |
789 | u8 mfg_function_id; | ||
790 | u8 afg_unsol; | ||
791 | u8 mfg_unsol; | ||
764 | u32 vendor_id; | 792 | u32 vendor_id; |
765 | u32 subsystem_id; | 793 | u32 subsystem_id; |
766 | u32 revision_id; | 794 | u32 revision_id; |
@@ -805,6 +833,7 @@ struct hda_codec { | |||
805 | hda_nid_t *slave_dig_outs; /* optional digital out slave widgets */ | 833 | hda_nid_t *slave_dig_outs; /* optional digital out slave widgets */ |
806 | struct snd_array init_pins; /* initial (BIOS) pin configurations */ | 834 | struct snd_array init_pins; /* initial (BIOS) pin configurations */ |
807 | struct snd_array driver_pins; /* pin configs set by codec parser */ | 835 | struct snd_array driver_pins; /* pin configs set by codec parser */ |
836 | struct snd_array cvt_setups; /* audio convert setups */ | ||
808 | 837 | ||
809 | #ifdef CONFIG_SND_HDA_HWDEP | 838 | #ifdef CONFIG_SND_HDA_HWDEP |
810 | struct snd_hwdep *hwdep; /* assigned hwdep device */ | 839 | struct snd_hwdep *hwdep; /* assigned hwdep device */ |
@@ -921,14 +950,28 @@ int snd_hda_codec_build_controls(struct hda_codec *codec); | |||
921 | */ | 950 | */ |
922 | int snd_hda_build_pcms(struct hda_bus *bus); | 951 | int snd_hda_build_pcms(struct hda_bus *bus); |
923 | int snd_hda_codec_build_pcms(struct hda_codec *codec); | 952 | int snd_hda_codec_build_pcms(struct hda_codec *codec); |
953 | |||
954 | int snd_hda_codec_prepare(struct hda_codec *codec, | ||
955 | struct hda_pcm_stream *hinfo, | ||
956 | unsigned int stream, | ||
957 | unsigned int format, | ||
958 | struct snd_pcm_substream *substream); | ||
959 | void snd_hda_codec_cleanup(struct hda_codec *codec, | ||
960 | struct hda_pcm_stream *hinfo, | ||
961 | struct snd_pcm_substream *substream); | ||
962 | |||
924 | void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, | 963 | void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, |
925 | u32 stream_tag, | 964 | u32 stream_tag, |
926 | int channel_id, int format); | 965 | int channel_id, int format); |
927 | void snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid); | 966 | void __snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid, |
967 | int do_now); | ||
968 | #define snd_hda_codec_cleanup_stream(codec, nid) \ | ||
969 | __snd_hda_codec_cleanup_stream(codec, nid, 0) | ||
928 | unsigned int snd_hda_calc_stream_format(unsigned int rate, | 970 | unsigned int snd_hda_calc_stream_format(unsigned int rate, |
929 | unsigned int channels, | 971 | unsigned int channels, |
930 | unsigned int format, | 972 | unsigned int format, |
931 | unsigned int maxbps); | 973 | unsigned int maxbps, |
974 | unsigned short spdif_ctls); | ||
932 | int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid, | 975 | int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid, |
933 | unsigned int format); | 976 | unsigned int format); |
934 | 977 | ||
diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index d8da18a9e98b..26c3ade73583 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c | |||
@@ -597,3 +597,52 @@ void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld) | |||
597 | EXPORT_SYMBOL_HDA(snd_hda_eld_proc_free); | 597 | EXPORT_SYMBOL_HDA(snd_hda_eld_proc_free); |
598 | 598 | ||
599 | #endif /* CONFIG_PROC_FS */ | 599 | #endif /* CONFIG_PROC_FS */ |
600 | |||
601 | /* update PCM info based on ELD */ | ||
602 | void hdmi_eld_update_pcm_info(struct hdmi_eld *eld, struct hda_pcm_stream *pcm, | ||
603 | struct hda_pcm_stream *codec_pars) | ||
604 | { | ||
605 | int i; | ||
606 | |||
607 | pcm->rates = 0; | ||
608 | pcm->formats = 0; | ||
609 | pcm->maxbps = 0; | ||
610 | pcm->channels_min = -1; | ||
611 | pcm->channels_max = 0; | ||
612 | for (i = 0; i < eld->sad_count; i++) { | ||
613 | struct cea_sad *a = &eld->sad[i]; | ||
614 | pcm->rates |= a->rates; | ||
615 | if (a->channels < pcm->channels_min) | ||
616 | pcm->channels_min = a->channels; | ||
617 | if (a->channels > pcm->channels_max) | ||
618 | pcm->channels_max = a->channels; | ||
619 | if (a->format == AUDIO_CODING_TYPE_LPCM) { | ||
620 | if (a->sample_bits & AC_SUPPCM_BITS_16) { | ||
621 | pcm->formats |= SNDRV_PCM_FMTBIT_S16_LE; | ||
622 | if (pcm->maxbps < 16) | ||
623 | pcm->maxbps = 16; | ||
624 | } | ||
625 | if (a->sample_bits & AC_SUPPCM_BITS_20) { | ||
626 | pcm->formats |= SNDRV_PCM_FMTBIT_S32_LE; | ||
627 | if (pcm->maxbps < 20) | ||
628 | pcm->maxbps = 20; | ||
629 | } | ||
630 | if (a->sample_bits & AC_SUPPCM_BITS_24) { | ||
631 | pcm->formats |= SNDRV_PCM_FMTBIT_S32_LE; | ||
632 | if (pcm->maxbps < 24) | ||
633 | pcm->maxbps = 24; | ||
634 | } | ||
635 | } | ||
636 | } | ||
637 | |||
638 | if (!codec_pars) | ||
639 | return; | ||
640 | |||
641 | /* restrict the parameters by the values the codec provides */ | ||
642 | pcm->rates &= codec_pars->rates; | ||
643 | pcm->formats &= codec_pars->formats; | ||
644 | pcm->channels_min = max(pcm->channels_min, codec_pars->channels_min); | ||
645 | pcm->channels_max = min(pcm->channels_max, codec_pars->channels_max); | ||
646 | pcm->maxbps = min(pcm->maxbps, codec_pars->maxbps); | ||
647 | } | ||
648 | EXPORT_SYMBOL_HDA(hdmi_eld_update_pcm_info); | ||
diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index a1fc83753cc6..bf3ced51e0f8 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/sound/pci/hda/hda_hwdep.c | |||
@@ -649,7 +649,9 @@ static void parse_codec_mode(char *buf, struct hda_bus *bus, | |||
649 | *codecp = NULL; | 649 | *codecp = NULL; |
650 | if (sscanf(buf, "%i %i %i", &vendorid, &subid, &caddr) == 3) { | 650 | if (sscanf(buf, "%i %i %i", &vendorid, &subid, &caddr) == 3) { |
651 | list_for_each_entry(codec, &bus->codec_list, list) { | 651 | list_for_each_entry(codec, &bus->codec_list, list) { |
652 | if (codec->addr == caddr) { | 652 | if (codec->vendor_id == vendorid && |
653 | codec->subsystem_id == subid && | ||
654 | codec->addr == caddr) { | ||
653 | *codecp = codec; | 655 | *codecp = codec; |
654 | break; | 656 | break; |
655 | } | 657 | } |
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 1df25cf5ce38..1053fff4bd0a 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c | |||
@@ -1634,7 +1634,7 @@ static int azx_pcm_hw_free(struct snd_pcm_substream *substream) | |||
1634 | azx_dev->period_bytes = 0; | 1634 | azx_dev->period_bytes = 0; |
1635 | azx_dev->format_val = 0; | 1635 | azx_dev->format_val = 0; |
1636 | 1636 | ||
1637 | hinfo->ops.cleanup(hinfo, apcm->codec, substream); | 1637 | snd_hda_codec_cleanup(apcm->codec, hinfo, substream); |
1638 | 1638 | ||
1639 | return snd_pcm_lib_free_pages(substream); | 1639 | return snd_pcm_lib_free_pages(substream); |
1640 | } | 1640 | } |
@@ -1653,7 +1653,8 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream) | |||
1653 | format_val = snd_hda_calc_stream_format(runtime->rate, | 1653 | format_val = snd_hda_calc_stream_format(runtime->rate, |
1654 | runtime->channels, | 1654 | runtime->channels, |
1655 | runtime->format, | 1655 | runtime->format, |
1656 | hinfo->maxbps); | 1656 | hinfo->maxbps, |
1657 | apcm->codec->spdif_ctls); | ||
1657 | if (!format_val) { | 1658 | if (!format_val) { |
1658 | snd_printk(KERN_ERR SFX | 1659 | snd_printk(KERN_ERR SFX |
1659 | "invalid format_val, rate=%d, ch=%d, format=%d\n", | 1660 | "invalid format_val, rate=%d, ch=%d, format=%d\n", |
@@ -1687,8 +1688,8 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream) | |||
1687 | else | 1688 | else |
1688 | azx_dev->fifo_size = 0; | 1689 | azx_dev->fifo_size = 0; |
1689 | 1690 | ||
1690 | return hinfo->ops.prepare(hinfo, apcm->codec, azx_dev->stream_tag, | 1691 | return snd_hda_codec_prepare(apcm->codec, hinfo, azx_dev->stream_tag, |
1691 | azx_dev->format_val, substream); | 1692 | azx_dev->format_val, substream); |
1692 | } | 1693 | } |
1693 | 1694 | ||
1694 | static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | 1695 | static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) |
@@ -1960,7 +1961,7 @@ static void azx_irq_pending_work(struct work_struct *work) | |||
1960 | spin_unlock_irq(&chip->reg_lock); | 1961 | spin_unlock_irq(&chip->reg_lock); |
1961 | if (!pending) | 1962 | if (!pending) |
1962 | return; | 1963 | return; |
1963 | cond_resched(); | 1964 | msleep(1); |
1964 | } | 1965 | } |
1965 | } | 1966 | } |
1966 | 1967 | ||
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 7a97f126f6f7..28ab4aead48f 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h | |||
@@ -604,6 +604,8 @@ struct hdmi_eld { | |||
604 | int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid); | 604 | int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid); |
605 | int snd_hdmi_get_eld(struct hdmi_eld *, struct hda_codec *, hda_nid_t); | 605 | int snd_hdmi_get_eld(struct hdmi_eld *, struct hda_codec *, hda_nid_t); |
606 | void snd_hdmi_show_eld(struct hdmi_eld *eld); | 606 | void snd_hdmi_show_eld(struct hdmi_eld *eld); |
607 | void hdmi_eld_update_pcm_info(struct hdmi_eld *eld, struct hda_pcm_stream *pcm, | ||
608 | struct hda_pcm_stream *codec_pars); | ||
607 | 609 | ||
608 | #ifdef CONFIG_PROC_FS | 610 | #ifdef CONFIG_PROC_FS |
609 | int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld, | 611 | int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld, |
diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index f97d35de66c4..f025200f2a62 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c | |||
@@ -557,7 +557,12 @@ static void print_codec_info(struct snd_info_entry *entry, | |||
557 | else | 557 | else |
558 | snd_iprintf(buffer, "Not Set\n"); | 558 | snd_iprintf(buffer, "Not Set\n"); |
559 | snd_iprintf(buffer, "Address: %d\n", codec->addr); | 559 | snd_iprintf(buffer, "Address: %d\n", codec->addr); |
560 | snd_iprintf(buffer, "Function Id: 0x%x\n", codec->function_id); | 560 | if (codec->afg) |
561 | snd_iprintf(buffer, "AFG Function Id: 0x%x (unsol %u)\n", | ||
562 | codec->afg_function_id, codec->afg_unsol); | ||
563 | if (codec->mfg) | ||
564 | snd_iprintf(buffer, "MFG Function Id: 0x%x (unsol %u)\n", | ||
565 | codec->mfg_function_id, codec->mfg_unsol); | ||
561 | snd_iprintf(buffer, "Vendor Id: 0x%08x\n", codec->vendor_id); | 566 | snd_iprintf(buffer, "Vendor Id: 0x%08x\n", codec->vendor_id); |
562 | snd_iprintf(buffer, "Subsystem Id: 0x%08x\n", codec->subsystem_id); | 567 | snd_iprintf(buffer, "Subsystem Id: 0x%08x\n", codec->subsystem_id); |
563 | snd_iprintf(buffer, "Revision Id: 0x%x\n", codec->revision_id); | 568 | snd_iprintf(buffer, "Revision Id: 0x%x\n", codec->revision_id); |
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index afbe314a5bf3..b697fd2a6f8b 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c | |||
@@ -3662,7 +3662,12 @@ static int patch_ad1984(struct hda_codec *codec) | |||
3662 | codec->patch_ops.build_pcms = ad1984_build_pcms; | 3662 | codec->patch_ops.build_pcms = ad1984_build_pcms; |
3663 | break; | 3663 | break; |
3664 | case AD1984_THINKPAD: | 3664 | case AD1984_THINKPAD: |
3665 | spec->multiout.dig_out_nid = AD1884_SPDIF_OUT; | 3665 | if (codec->subsystem_id == 0x17aa20fb) { |
3666 | /* Thinpad X300 does not have the ability to do SPDIF, | ||
3667 | or attach to docking station to use SPDIF */ | ||
3668 | spec->multiout.dig_out_nid = 0; | ||
3669 | } else | ||
3670 | spec->multiout.dig_out_nid = AD1884_SPDIF_OUT; | ||
3666 | spec->input_mux = &ad1984_thinkpad_capture_source; | 3671 | spec->input_mux = &ad1984_thinkpad_capture_source; |
3667 | spec->mixers[0] = ad1984_thinkpad_mixers; | 3672 | spec->mixers[0] = ad1984_thinkpad_mixers; |
3668 | spec->init_verbs[spec->num_init_verbs++] = ad1984_thinkpad_init_verbs; | 3673 | spec->init_verbs[spec->num_init_verbs++] = ad1984_thinkpad_init_verbs; |
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 350ee8ac4153..488fd9ade1ba 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c | |||
@@ -656,7 +656,7 @@ static int change_cur_input(struct hda_codec *codec, unsigned int idx, | |||
656 | return 0; | 656 | return 0; |
657 | if (spec->cur_adc && spec->cur_adc != spec->adc_nid[idx]) { | 657 | if (spec->cur_adc && spec->cur_adc != spec->adc_nid[idx]) { |
658 | /* stream is running, let's swap the current ADC */ | 658 | /* stream is running, let's swap the current ADC */ |
659 | snd_hda_codec_cleanup_stream(codec, spec->cur_adc); | 659 | __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1); |
660 | spec->cur_adc = spec->adc_nid[idx]; | 660 | spec->cur_adc = spec->adc_nid[idx]; |
661 | snd_hda_codec_setup_stream(codec, spec->cur_adc, | 661 | snd_hda_codec_setup_stream(codec, spec->cur_adc, |
662 | spec->cur_adc_stream_tag, 0, | 662 | spec->cur_adc_stream_tag, 0, |
@@ -972,6 +972,53 @@ static struct hda_verb cs_coef_init_verbs[] = { | |||
972 | {} /* terminator */ | 972 | {} /* terminator */ |
973 | }; | 973 | }; |
974 | 974 | ||
975 | /* Errata: CS4207 rev C0/C1/C2 Silicon | ||
976 | * | ||
977 | * http://www.cirrus.com/en/pubs/errata/ER880C3.pdf | ||
978 | * | ||
979 | * 6. At high temperature (TA > +85°C), the digital supply current (IVD) | ||
980 | * may be excessive (up to an additional 200 μA), which is most easily | ||
981 | * observed while the part is being held in reset (RESET# active low). | ||
982 | * | ||
983 | * Root Cause: At initial powerup of the device, the logic that drives | ||
984 | * the clock and write enable to the S/PDIF SRC RAMs is not properly | ||
985 | * initialized. | ||
986 | * Certain random patterns will cause a steady leakage current in those | ||
987 | * RAM cells. The issue will resolve once the SRCs are used (turned on). | ||
988 | * | ||
989 | * Workaround: The following verb sequence briefly turns on the S/PDIF SRC | ||
990 | * blocks, which will alleviate the issue. | ||
991 | */ | ||
992 | |||
993 | static struct hda_verb cs_errata_init_verbs[] = { | ||
994 | {0x01, AC_VERB_SET_POWER_STATE, 0x00}, /* AFG: D0 */ | ||
995 | {0x11, AC_VERB_SET_PROC_STATE, 0x01}, /* VPW: processing on */ | ||
996 | |||
997 | {0x11, AC_VERB_SET_COEF_INDEX, 0x0008}, | ||
998 | {0x11, AC_VERB_SET_PROC_COEF, 0x9999}, | ||
999 | {0x11, AC_VERB_SET_COEF_INDEX, 0x0017}, | ||
1000 | {0x11, AC_VERB_SET_PROC_COEF, 0xa412}, | ||
1001 | {0x11, AC_VERB_SET_COEF_INDEX, 0x0001}, | ||
1002 | {0x11, AC_VERB_SET_PROC_COEF, 0x0009}, | ||
1003 | |||
1004 | {0x07, AC_VERB_SET_POWER_STATE, 0x00}, /* S/PDIF Rx: D0 */ | ||
1005 | {0x08, AC_VERB_SET_POWER_STATE, 0x00}, /* S/PDIF Tx: D0 */ | ||
1006 | |||
1007 | {0x11, AC_VERB_SET_COEF_INDEX, 0x0017}, | ||
1008 | {0x11, AC_VERB_SET_PROC_COEF, 0x2412}, | ||
1009 | {0x11, AC_VERB_SET_COEF_INDEX, 0x0008}, | ||
1010 | {0x11, AC_VERB_SET_PROC_COEF, 0x0000}, | ||
1011 | {0x11, AC_VERB_SET_COEF_INDEX, 0x0001}, | ||
1012 | {0x11, AC_VERB_SET_PROC_COEF, 0x0008}, | ||
1013 | {0x11, AC_VERB_SET_PROC_STATE, 0x00}, | ||
1014 | |||
1015 | {0x07, AC_VERB_SET_POWER_STATE, 0x03}, /* S/PDIF Rx: D3 */ | ||
1016 | {0x08, AC_VERB_SET_POWER_STATE, 0x03}, /* S/PDIF Tx: D3 */ | ||
1017 | /*{0x01, AC_VERB_SET_POWER_STATE, 0x03},*/ /* AFG: D3 This is already handled */ | ||
1018 | |||
1019 | {} /* terminator */ | ||
1020 | }; | ||
1021 | |||
975 | /* SPDIF setup */ | 1022 | /* SPDIF setup */ |
976 | static void init_digital(struct hda_codec *codec) | 1023 | static void init_digital(struct hda_codec *codec) |
977 | { | 1024 | { |
@@ -991,6 +1038,9 @@ static int cs_init(struct hda_codec *codec) | |||
991 | { | 1038 | { |
992 | struct cs_spec *spec = codec->spec; | 1039 | struct cs_spec *spec = codec->spec; |
993 | 1040 | ||
1041 | /* init_verb sequence for C0/C1/C2 errata*/ | ||
1042 | snd_hda_sequence_write(codec, cs_errata_init_verbs); | ||
1043 | |||
994 | snd_hda_sequence_write(codec, cs_coef_init_verbs); | 1044 | snd_hda_sequence_write(codec, cs_coef_init_verbs); |
995 | 1045 | ||
996 | if (spec->gpio_mask) { | 1046 | if (spec->gpio_mask) { |
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 2bf2cb5da956..71f9d6475b09 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c | |||
@@ -116,6 +116,7 @@ struct conexant_spec { | |||
116 | unsigned int dell_vostro:1; | 116 | unsigned int dell_vostro:1; |
117 | unsigned int ideapad:1; | 117 | unsigned int ideapad:1; |
118 | unsigned int thinkpad:1; | 118 | unsigned int thinkpad:1; |
119 | unsigned int hp_laptop:1; | ||
119 | 120 | ||
120 | unsigned int ext_mic_present; | 121 | unsigned int ext_mic_present; |
121 | unsigned int recording; | 122 | unsigned int recording; |
@@ -131,6 +132,8 @@ struct conexant_spec { | |||
131 | unsigned int dc_enable; | 132 | unsigned int dc_enable; |
132 | unsigned int dc_input_bias; /* offset into cxt5066_olpc_dc_bias */ | 133 | unsigned int dc_input_bias; /* offset into cxt5066_olpc_dc_bias */ |
133 | unsigned int mic_boost; /* offset into cxt5066_analog_mic_boost */ | 134 | unsigned int mic_boost; /* offset into cxt5066_analog_mic_boost */ |
135 | |||
136 | unsigned int beep_amp; | ||
134 | }; | 137 | }; |
135 | 138 | ||
136 | static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo, | 139 | static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo, |
@@ -515,6 +518,15 @@ static struct snd_kcontrol_new cxt_capture_mixers[] = { | |||
515 | {} | 518 | {} |
516 | }; | 519 | }; |
517 | 520 | ||
521 | #ifdef CONFIG_SND_HDA_INPUT_BEEP | ||
522 | /* additional beep mixers; the actual parameters are overwritten at build */ | ||
523 | static struct snd_kcontrol_new cxt_beep_mixer[] = { | ||
524 | HDA_CODEC_VOLUME_MONO("Beep Playback Volume", 0, 1, 0, HDA_OUTPUT), | ||
525 | HDA_CODEC_MUTE_BEEP_MONO("Beep Playback Switch", 0, 1, 0, HDA_OUTPUT), | ||
526 | { } /* end */ | ||
527 | }; | ||
528 | #endif | ||
529 | |||
518 | static const char *slave_vols[] = { | 530 | static const char *slave_vols[] = { |
519 | "Headphone Playback Volume", | 531 | "Headphone Playback Volume", |
520 | "Speaker Playback Volume", | 532 | "Speaker Playback Volume", |
@@ -580,16 +592,52 @@ static int conexant_build_controls(struct hda_codec *codec) | |||
580 | return err; | 592 | return err; |
581 | } | 593 | } |
582 | 594 | ||
595 | #ifdef CONFIG_SND_HDA_INPUT_BEEP | ||
596 | /* create beep controls if needed */ | ||
597 | if (spec->beep_amp) { | ||
598 | struct snd_kcontrol_new *knew; | ||
599 | for (knew = cxt_beep_mixer; knew->name; knew++) { | ||
600 | struct snd_kcontrol *kctl; | ||
601 | kctl = snd_ctl_new1(knew, codec); | ||
602 | if (!kctl) | ||
603 | return -ENOMEM; | ||
604 | kctl->private_value = spec->beep_amp; | ||
605 | err = snd_hda_ctl_add(codec, 0, kctl); | ||
606 | if (err < 0) | ||
607 | return err; | ||
608 | } | ||
609 | } | ||
610 | #endif | ||
611 | |||
583 | return 0; | 612 | return 0; |
584 | } | 613 | } |
585 | 614 | ||
615 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
616 | static int conexant_suspend(struct hda_codec *codec, pm_message_t state) | ||
617 | { | ||
618 | snd_hda_shutup_pins(codec); | ||
619 | return 0; | ||
620 | } | ||
621 | #endif | ||
622 | |||
586 | static struct hda_codec_ops conexant_patch_ops = { | 623 | static struct hda_codec_ops conexant_patch_ops = { |
587 | .build_controls = conexant_build_controls, | 624 | .build_controls = conexant_build_controls, |
588 | .build_pcms = conexant_build_pcms, | 625 | .build_pcms = conexant_build_pcms, |
589 | .init = conexant_init, | 626 | .init = conexant_init, |
590 | .free = conexant_free, | 627 | .free = conexant_free, |
628 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
629 | .suspend = conexant_suspend, | ||
630 | #endif | ||
631 | .reboot_notify = snd_hda_shutup_pins, | ||
591 | }; | 632 | }; |
592 | 633 | ||
634 | #ifdef CONFIG_SND_HDA_INPUT_BEEP | ||
635 | #define set_beep_amp(spec, nid, idx, dir) \ | ||
636 | ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir)) | ||
637 | #else | ||
638 | #define set_beep_amp(spec, nid, idx, dir) /* NOP */ | ||
639 | #endif | ||
640 | |||
593 | /* | 641 | /* |
594 | * EAPD control | 642 | * EAPD control |
595 | * the private value = nid | (invert << 8) | 643 | * the private value = nid | (invert << 8) |
@@ -1130,9 +1178,10 @@ static int patch_cxt5045(struct hda_codec *codec) | |||
1130 | spec->num_init_verbs = 1; | 1178 | spec->num_init_verbs = 1; |
1131 | spec->init_verbs[0] = cxt5045_init_verbs; | 1179 | spec->init_verbs[0] = cxt5045_init_verbs; |
1132 | spec->spdif_route = 0; | 1180 | spec->spdif_route = 0; |
1133 | spec->num_channel_mode = ARRAY_SIZE(cxt5045_modes), | 1181 | spec->num_channel_mode = ARRAY_SIZE(cxt5045_modes); |
1134 | spec->channel_mode = cxt5045_modes, | 1182 | spec->channel_mode = cxt5045_modes; |
1135 | 1183 | ||
1184 | set_beep_amp(spec, 0x16, 0, 1); | ||
1136 | 1185 | ||
1137 | codec->patch_ops = conexant_patch_ops; | 1186 | codec->patch_ops = conexant_patch_ops; |
1138 | 1187 | ||
@@ -1211,6 +1260,9 @@ static int patch_cxt5045(struct hda_codec *codec) | |||
1211 | break; | 1260 | break; |
1212 | } | 1261 | } |
1213 | 1262 | ||
1263 | if (spec->beep_amp) | ||
1264 | snd_hda_attach_beep_device(codec, spec->beep_amp); | ||
1265 | |||
1214 | return 0; | 1266 | return 0; |
1215 | } | 1267 | } |
1216 | 1268 | ||
@@ -1632,6 +1684,11 @@ static void cxt5051_update_speaker(struct hda_codec *codec) | |||
1632 | pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0; | 1684 | pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0; |
1633 | snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, | 1685 | snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, |
1634 | pinctl); | 1686 | pinctl); |
1687 | /* on ideapad there is an aditional speaker (subwoofer) to mute */ | ||
1688 | if (spec->ideapad) | ||
1689 | snd_hda_codec_write(codec, 0x1b, 0, | ||
1690 | AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
1691 | pinctl); | ||
1635 | } | 1692 | } |
1636 | 1693 | ||
1637 | /* turn on/off EAPD (+ mute HP) as a master switch */ | 1694 | /* turn on/off EAPD (+ mute HP) as a master switch */ |
@@ -1677,7 +1734,7 @@ static void cxt5051_portc_automic(struct hda_codec *codec) | |||
1677 | new_adc = spec->adc_nids[spec->cur_adc_idx]; | 1734 | new_adc = spec->adc_nids[spec->cur_adc_idx]; |
1678 | if (spec->cur_adc && spec->cur_adc != new_adc) { | 1735 | if (spec->cur_adc && spec->cur_adc != new_adc) { |
1679 | /* stream is running, let's swap the current ADC */ | 1736 | /* stream is running, let's swap the current ADC */ |
1680 | snd_hda_codec_cleanup_stream(codec, spec->cur_adc); | 1737 | __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1); |
1681 | spec->cur_adc = new_adc; | 1738 | spec->cur_adc = new_adc; |
1682 | snd_hda_codec_setup_stream(codec, new_adc, | 1739 | snd_hda_codec_setup_stream(codec, new_adc, |
1683 | spec->cur_adc_stream_tag, 0, | 1740 | spec->cur_adc_stream_tag, 0, |
@@ -1888,6 +1945,13 @@ static void cxt5051_init_mic_port(struct hda_codec *codec, hda_nid_t nid, | |||
1888 | #endif | 1945 | #endif |
1889 | } | 1946 | } |
1890 | 1947 | ||
1948 | static struct hda_verb cxt5051_ideapad_init_verbs[] = { | ||
1949 | /* Subwoofer */ | ||
1950 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
1951 | {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
1952 | { } /* end */ | ||
1953 | }; | ||
1954 | |||
1891 | /* initialize jack-sensing, too */ | 1955 | /* initialize jack-sensing, too */ |
1892 | static int cxt5051_init(struct hda_codec *codec) | 1956 | static int cxt5051_init(struct hda_codec *codec) |
1893 | { | 1957 | { |
@@ -1917,6 +1981,7 @@ enum { | |||
1917 | CXT5051_LENOVO_X200, /* Lenovo X200 laptop, also used for Advanced Mini Dock 250410 */ | 1981 | CXT5051_LENOVO_X200, /* Lenovo X200 laptop, also used for Advanced Mini Dock 250410 */ |
1918 | CXT5051_F700, /* HP Compaq Presario F700 */ | 1982 | CXT5051_F700, /* HP Compaq Presario F700 */ |
1919 | CXT5051_TOSHIBA, /* Toshiba M300 & co */ | 1983 | CXT5051_TOSHIBA, /* Toshiba M300 & co */ |
1984 | CXT5051_IDEAPAD, /* Lenovo IdeaPad Y430 */ | ||
1920 | CXT5051_MODELS | 1985 | CXT5051_MODELS |
1921 | }; | 1986 | }; |
1922 | 1987 | ||
@@ -1927,6 +1992,7 @@ static const char *cxt5051_models[CXT5051_MODELS] = { | |||
1927 | [CXT5051_LENOVO_X200] = "lenovo-x200", | 1992 | [CXT5051_LENOVO_X200] = "lenovo-x200", |
1928 | [CXT5051_F700] = "hp-700", | 1993 | [CXT5051_F700] = "hp-700", |
1929 | [CXT5051_TOSHIBA] = "toshiba", | 1994 | [CXT5051_TOSHIBA] = "toshiba", |
1995 | [CXT5051_IDEAPAD] = "ideapad", | ||
1930 | }; | 1996 | }; |
1931 | 1997 | ||
1932 | static struct snd_pci_quirk cxt5051_cfg_tbl[] = { | 1998 | static struct snd_pci_quirk cxt5051_cfg_tbl[] = { |
@@ -1938,6 +2004,7 @@ static struct snd_pci_quirk cxt5051_cfg_tbl[] = { | |||
1938 | CXT5051_LAPTOP), | 2004 | CXT5051_LAPTOP), |
1939 | SND_PCI_QUIRK(0x14f1, 0x5051, "HP Spartan 1.1", CXT5051_HP), | 2005 | SND_PCI_QUIRK(0x14f1, 0x5051, "HP Spartan 1.1", CXT5051_HP), |
1940 | SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo X200", CXT5051_LENOVO_X200), | 2006 | SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo X200", CXT5051_LENOVO_X200), |
2007 | SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo IdeaPad", CXT5051_IDEAPAD), | ||
1941 | {} | 2008 | {} |
1942 | }; | 2009 | }; |
1943 | 2010 | ||
@@ -1972,6 +2039,8 @@ static int patch_cxt5051(struct hda_codec *codec) | |||
1972 | spec->cur_adc = 0; | 2039 | spec->cur_adc = 0; |
1973 | spec->cur_adc_idx = 0; | 2040 | spec->cur_adc_idx = 0; |
1974 | 2041 | ||
2042 | set_beep_amp(spec, 0x13, 0, HDA_OUTPUT); | ||
2043 | |||
1975 | codec->patch_ops.unsol_event = cxt5051_hp_unsol_event; | 2044 | codec->patch_ops.unsol_event = cxt5051_hp_unsol_event; |
1976 | 2045 | ||
1977 | board_config = snd_hda_check_board_config(codec, CXT5051_MODELS, | 2046 | board_config = snd_hda_check_board_config(codec, CXT5051_MODELS, |
@@ -1989,6 +2058,10 @@ static int patch_cxt5051(struct hda_codec *codec) | |||
1989 | break; | 2058 | break; |
1990 | case CXT5051_LENOVO_X200: | 2059 | case CXT5051_LENOVO_X200: |
1991 | spec->init_verbs[0] = cxt5051_lenovo_x200_init_verbs; | 2060 | spec->init_verbs[0] = cxt5051_lenovo_x200_init_verbs; |
2061 | /* Thinkpad X301 does not have S/PDIF wired and no ability | ||
2062 | to use a docking station. */ | ||
2063 | if (codec->subsystem_id == 0x17aa211f) | ||
2064 | spec->multiout.dig_out_nid = 0; | ||
1992 | break; | 2065 | break; |
1993 | case CXT5051_F700: | 2066 | case CXT5051_F700: |
1994 | spec->init_verbs[0] = cxt5051_f700_init_verbs; | 2067 | spec->init_verbs[0] = cxt5051_f700_init_verbs; |
@@ -1999,8 +2072,16 @@ static int patch_cxt5051(struct hda_codec *codec) | |||
1999 | spec->mixers[0] = cxt5051_toshiba_mixers; | 2072 | spec->mixers[0] = cxt5051_toshiba_mixers; |
2000 | spec->auto_mic = AUTO_MIC_PORTB; | 2073 | spec->auto_mic = AUTO_MIC_PORTB; |
2001 | break; | 2074 | break; |
2075 | case CXT5051_IDEAPAD: | ||
2076 | spec->init_verbs[spec->num_init_verbs++] = | ||
2077 | cxt5051_ideapad_init_verbs; | ||
2078 | spec->ideapad = 1; | ||
2079 | break; | ||
2002 | } | 2080 | } |
2003 | 2081 | ||
2082 | if (spec->beep_amp) | ||
2083 | snd_hda_attach_beep_device(codec, spec->beep_amp); | ||
2084 | |||
2004 | return 0; | 2085 | return 0; |
2005 | } | 2086 | } |
2006 | 2087 | ||
@@ -2219,6 +2300,18 @@ static void cxt5066_ideapad_automic(struct hda_codec *codec) | |||
2219 | } | 2300 | } |
2220 | } | 2301 | } |
2221 | 2302 | ||
2303 | /* toggle input of built-in digital mic and mic jack appropriately */ | ||
2304 | static void cxt5066_hp_laptop_automic(struct hda_codec *codec) | ||
2305 | { | ||
2306 | unsigned int present; | ||
2307 | |||
2308 | present = snd_hda_jack_detect(codec, 0x1b); | ||
2309 | snd_printdd("CXT5066: external microphone present=%d\n", present); | ||
2310 | snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_CONNECT_SEL, | ||
2311 | present ? 1 : 3); | ||
2312 | } | ||
2313 | |||
2314 | |||
2222 | /* toggle input of built-in digital mic and mic jack appropriately | 2315 | /* toggle input of built-in digital mic and mic jack appropriately |
2223 | order is: external mic -> dock mic -> interal mic */ | 2316 | order is: external mic -> dock mic -> interal mic */ |
2224 | static void cxt5066_thinkpad_automic(struct hda_codec *codec) | 2317 | static void cxt5066_thinkpad_automic(struct hda_codec *codec) |
@@ -2328,6 +2421,20 @@ static void cxt5066_ideapad_event(struct hda_codec *codec, unsigned int res) | |||
2328 | } | 2421 | } |
2329 | 2422 | ||
2330 | /* unsolicited event for jack sensing */ | 2423 | /* unsolicited event for jack sensing */ |
2424 | static void cxt5066_hp_laptop_event(struct hda_codec *codec, unsigned int res) | ||
2425 | { | ||
2426 | snd_printdd("CXT5066_hp_laptop: unsol event %x (%x)\n", res, res >> 26); | ||
2427 | switch (res >> 26) { | ||
2428 | case CONEXANT_HP_EVENT: | ||
2429 | cxt5066_hp_automute(codec); | ||
2430 | break; | ||
2431 | case CONEXANT_MIC_EVENT: | ||
2432 | cxt5066_hp_laptop_automic(codec); | ||
2433 | break; | ||
2434 | } | ||
2435 | } | ||
2436 | |||
2437 | /* unsolicited event for jack sensing */ | ||
2331 | static void cxt5066_thinkpad_event(struct hda_codec *codec, unsigned int res) | 2438 | static void cxt5066_thinkpad_event(struct hda_codec *codec, unsigned int res) |
2332 | { | 2439 | { |
2333 | snd_printdd("CXT5066_thinkpad: unsol event %x (%x)\n", res, res >> 26); | 2440 | snd_printdd("CXT5066_thinkpad: unsol event %x (%x)\n", res, res >> 26); |
@@ -2616,7 +2723,6 @@ static struct snd_kcontrol_new cxt5066_vostro_mixers[] = { | |||
2616 | .put = cxt5066_mic_boost_mux_enum_put, | 2723 | .put = cxt5066_mic_boost_mux_enum_put, |
2617 | .private_value = 0x23 | 0x100, | 2724 | .private_value = 0x23 | 0x100, |
2618 | }, | 2725 | }, |
2619 | HDA_CODEC_VOLUME_MONO("Beep Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT), | ||
2620 | {} | 2726 | {} |
2621 | }; | 2727 | }; |
2622 | 2728 | ||
@@ -2910,6 +3016,14 @@ static struct hda_verb cxt5066_init_verbs_portd_lo[] = { | |||
2910 | { } /* end */ | 3016 | { } /* end */ |
2911 | }; | 3017 | }; |
2912 | 3018 | ||
3019 | |||
3020 | static struct hda_verb cxt5066_init_verbs_hp_laptop[] = { | ||
3021 | {0x14, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
3022 | {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, | ||
3023 | {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, | ||
3024 | { } /* end */ | ||
3025 | }; | ||
3026 | |||
2913 | /* initialize jack-sensing, too */ | 3027 | /* initialize jack-sensing, too */ |
2914 | static int cxt5066_init(struct hda_codec *codec) | 3028 | static int cxt5066_init(struct hda_codec *codec) |
2915 | { | 3029 | { |
@@ -2925,6 +3039,8 @@ static int cxt5066_init(struct hda_codec *codec) | |||
2925 | cxt5066_ideapad_automic(codec); | 3039 | cxt5066_ideapad_automic(codec); |
2926 | else if (spec->thinkpad) | 3040 | else if (spec->thinkpad) |
2927 | cxt5066_thinkpad_automic(codec); | 3041 | cxt5066_thinkpad_automic(codec); |
3042 | else if (spec->hp_laptop) | ||
3043 | cxt5066_hp_laptop_automic(codec); | ||
2928 | } | 3044 | } |
2929 | cxt5066_set_mic_boost(codec); | 3045 | cxt5066_set_mic_boost(codec); |
2930 | return 0; | 3046 | return 0; |
@@ -2952,6 +3068,7 @@ enum { | |||
2952 | CXT5066_DELL_VOSTO, /* Dell Vostro 1015i */ | 3068 | CXT5066_DELL_VOSTO, /* Dell Vostro 1015i */ |
2953 | CXT5066_IDEAPAD, /* Lenovo IdeaPad U150 */ | 3069 | CXT5066_IDEAPAD, /* Lenovo IdeaPad U150 */ |
2954 | CXT5066_THINKPAD, /* Lenovo ThinkPad T410s, others? */ | 3070 | CXT5066_THINKPAD, /* Lenovo ThinkPad T410s, others? */ |
3071 | CXT5066_HP_LAPTOP, /* HP Laptop */ | ||
2955 | CXT5066_MODELS | 3072 | CXT5066_MODELS |
2956 | }; | 3073 | }; |
2957 | 3074 | ||
@@ -2962,6 +3079,7 @@ static const char *cxt5066_models[CXT5066_MODELS] = { | |||
2962 | [CXT5066_DELL_VOSTO] = "dell-vostro", | 3079 | [CXT5066_DELL_VOSTO] = "dell-vostro", |
2963 | [CXT5066_IDEAPAD] = "ideapad", | 3080 | [CXT5066_IDEAPAD] = "ideapad", |
2964 | [CXT5066_THINKPAD] = "thinkpad", | 3081 | [CXT5066_THINKPAD] = "thinkpad", |
3082 | [CXT5066_HP_LAPTOP] = "hp-laptop", | ||
2965 | }; | 3083 | }; |
2966 | 3084 | ||
2967 | static struct snd_pci_quirk cxt5066_cfg_tbl[] = { | 3085 | static struct snd_pci_quirk cxt5066_cfg_tbl[] = { |
@@ -2970,15 +3088,21 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = { | |||
2970 | SND_PCI_QUIRK(0x1028, 0x02f5, "Dell", | 3088 | SND_PCI_QUIRK(0x1028, 0x02f5, "Dell", |
2971 | CXT5066_DELL_LAPTOP), | 3089 | CXT5066_DELL_LAPTOP), |
2972 | SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5), | 3090 | SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5), |
3091 | SND_PCI_QUIRK(0x1028, 0x02d8, "Dell Vostro", CXT5066_DELL_VOSTO), | ||
2973 | SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTO), | 3092 | SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTO), |
2974 | SND_PCI_QUIRK(0x1028, 0x0408, "Dell Inspiron One 19T", CXT5066_IDEAPAD), | 3093 | SND_PCI_QUIRK(0x1028, 0x0408, "Dell Inspiron One 19T", CXT5066_IDEAPAD), |
3094 | SND_PCI_QUIRK(0x103c, 0x360b, "HP G60", CXT5066_HP_LAPTOP), | ||
2975 | SND_PCI_QUIRK(0x1179, 0xff50, "Toshiba Satellite P500-PSPGSC-01800T", CXT5066_OLPC_XO_1_5), | 3095 | SND_PCI_QUIRK(0x1179, 0xff50, "Toshiba Satellite P500-PSPGSC-01800T", CXT5066_OLPC_XO_1_5), |
2976 | SND_PCI_QUIRK(0x1179, 0xffe0, "Toshiba Satellite Pro T130-15F", CXT5066_OLPC_XO_1_5), | 3096 | SND_PCI_QUIRK(0x1179, 0xffe0, "Toshiba Satellite Pro T130-15F", CXT5066_OLPC_XO_1_5), |
3097 | SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400s", CXT5066_THINKPAD), | ||
2977 | SND_PCI_QUIRK(0x17aa, 0x21b2, "Thinkpad X100e", CXT5066_IDEAPAD), | 3098 | SND_PCI_QUIRK(0x17aa, 0x21b2, "Thinkpad X100e", CXT5066_IDEAPAD), |
2978 | SND_PCI_QUIRK(0x17aa, 0x21b3, "Thinkpad Edge 13 (197)", CXT5066_IDEAPAD), | 3099 | SND_PCI_QUIRK(0x17aa, 0x21b3, "Thinkpad Edge 13 (197)", CXT5066_IDEAPAD), |
2979 | SND_PCI_QUIRK(0x17aa, 0x21b4, "Thinkpad Edge", CXT5066_IDEAPAD), | 3100 | SND_PCI_QUIRK(0x17aa, 0x21b4, "Thinkpad Edge", CXT5066_IDEAPAD), |
3101 | SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo Thinkpad", CXT5066_THINKPAD), | ||
3102 | SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo G series", CXT5066_IDEAPAD), | ||
3103 | SND_PCI_QUIRK(0x17aa, 0x390a, "Lenovo S10-3t", CXT5066_IDEAPAD), | ||
3104 | SND_PCI_QUIRK(0x17aa, 0x3938, "Lenovo G series (AMD)", CXT5066_IDEAPAD), | ||
2980 | SND_PCI_QUIRK(0x17aa, 0x3a0d, "ideapad", CXT5066_IDEAPAD), | 3105 | SND_PCI_QUIRK(0x17aa, 0x3a0d, "ideapad", CXT5066_IDEAPAD), |
2981 | SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo Thinkpad", CXT5066_THINKPAD), | ||
2982 | {} | 3106 | {} |
2983 | }; | 3107 | }; |
2984 | 3108 | ||
@@ -3014,6 +3138,8 @@ static int patch_cxt5066(struct hda_codec *codec) | |||
3014 | spec->cur_adc = 0; | 3138 | spec->cur_adc = 0; |
3015 | spec->cur_adc_idx = 0; | 3139 | spec->cur_adc_idx = 0; |
3016 | 3140 | ||
3141 | set_beep_amp(spec, 0x13, 0, HDA_OUTPUT); | ||
3142 | |||
3017 | board_config = snd_hda_check_board_config(codec, CXT5066_MODELS, | 3143 | board_config = snd_hda_check_board_config(codec, CXT5066_MODELS, |
3018 | cxt5066_models, cxt5066_cfg_tbl); | 3144 | cxt5066_models, cxt5066_cfg_tbl); |
3019 | switch (board_config) { | 3145 | switch (board_config) { |
@@ -3031,6 +3157,23 @@ static int patch_cxt5066(struct hda_codec *codec) | |||
3031 | spec->num_init_verbs++; | 3157 | spec->num_init_verbs++; |
3032 | spec->dell_automute = 1; | 3158 | spec->dell_automute = 1; |
3033 | break; | 3159 | break; |
3160 | case CXT5066_HP_LAPTOP: | ||
3161 | codec->patch_ops.init = cxt5066_init; | ||
3162 | codec->patch_ops.unsol_event = cxt5066_hp_laptop_event; | ||
3163 | spec->init_verbs[spec->num_init_verbs] = | ||
3164 | cxt5066_init_verbs_hp_laptop; | ||
3165 | spec->num_init_verbs++; | ||
3166 | spec->hp_laptop = 1; | ||
3167 | spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; | ||
3168 | spec->mixers[spec->num_mixers++] = cxt5066_mixers; | ||
3169 | /* no S/PDIF out */ | ||
3170 | spec->multiout.dig_out_nid = 0; | ||
3171 | /* input source automatically selected */ | ||
3172 | spec->input_mux = NULL; | ||
3173 | spec->port_d_mode = 0; | ||
3174 | spec->mic_boost = 3; /* default 30dB gain */ | ||
3175 | break; | ||
3176 | |||
3034 | case CXT5066_OLPC_XO_1_5: | 3177 | case CXT5066_OLPC_XO_1_5: |
3035 | codec->patch_ops.init = cxt5066_olpc_init; | 3178 | codec->patch_ops.init = cxt5066_olpc_init; |
3036 | codec->patch_ops.unsol_event = cxt5066_olpc_unsol_event; | 3179 | codec->patch_ops.unsol_event = cxt5066_olpc_unsol_event; |
@@ -3062,7 +3205,6 @@ static int patch_cxt5066(struct hda_codec *codec) | |||
3062 | spec->port_d_mode = 0; | 3205 | spec->port_d_mode = 0; |
3063 | spec->dell_vostro = 1; | 3206 | spec->dell_vostro = 1; |
3064 | spec->mic_boost = 3; /* default 30dB gain */ | 3207 | spec->mic_boost = 3; /* default 30dB gain */ |
3065 | snd_hda_attach_beep_device(codec, 0x13); | ||
3066 | 3208 | ||
3067 | /* no S/PDIF out */ | 3209 | /* no S/PDIF out */ |
3068 | spec->multiout.dig_out_nid = 0; | 3210 | spec->multiout.dig_out_nid = 0; |
@@ -3104,6 +3246,9 @@ static int patch_cxt5066(struct hda_codec *codec) | |||
3104 | break; | 3246 | break; |
3105 | } | 3247 | } |
3106 | 3248 | ||
3249 | if (spec->beep_amp) | ||
3250 | snd_hda_attach_beep_device(codec, spec->beep_amp); | ||
3251 | |||
3107 | return 0; | 3252 | return 0; |
3108 | } | 3253 | } |
3109 | 3254 | ||
@@ -3121,6 +3266,8 @@ static struct hda_codec_preset snd_hda_preset_conexant[] = { | |||
3121 | .patch = patch_cxt5066 }, | 3266 | .patch = patch_cxt5066 }, |
3122 | { .id = 0x14f15067, .name = "CX20583 (Pebble HSF)", | 3267 | { .id = 0x14f15067, .name = "CX20583 (Pebble HSF)", |
3123 | .patch = patch_cxt5066 }, | 3268 | .patch = patch_cxt5066 }, |
3269 | { .id = 0x14f15068, .name = "CX20584", | ||
3270 | .patch = patch_cxt5066 }, | ||
3124 | { .id = 0x14f15069, .name = "CX20585", | 3271 | { .id = 0x14f15069, .name = "CX20585", |
3125 | .patch = patch_cxt5066 }, | 3272 | .patch = patch_cxt5066 }, |
3126 | {} /* terminator */ | 3273 | {} /* terminator */ |
@@ -3131,6 +3278,7 @@ MODULE_ALIAS("snd-hda-codec-id:14f15047"); | |||
3131 | MODULE_ALIAS("snd-hda-codec-id:14f15051"); | 3278 | MODULE_ALIAS("snd-hda-codec-id:14f15051"); |
3132 | MODULE_ALIAS("snd-hda-codec-id:14f15066"); | 3279 | MODULE_ALIAS("snd-hda-codec-id:14f15066"); |
3133 | MODULE_ALIAS("snd-hda-codec-id:14f15067"); | 3280 | MODULE_ALIAS("snd-hda-codec-id:14f15067"); |
3281 | MODULE_ALIAS("snd-hda-codec-id:14f15068"); | ||
3134 | MODULE_ALIAS("snd-hda-codec-id:14f15069"); | 3282 | MODULE_ALIAS("snd-hda-codec-id:14f15069"); |
3135 | 3283 | ||
3136 | MODULE_LICENSE("GPL"); | 3284 | MODULE_LICENSE("GPL"); |
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 2fc53961054e..afd6022a96a7 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c | |||
@@ -46,6 +46,7 @@ struct hdmi_spec { | |||
46 | * export one pcm per pipe | 46 | * export one pcm per pipe |
47 | */ | 47 | */ |
48 | struct hda_pcm pcm_rec[MAX_HDMI_CVTS]; | 48 | struct hda_pcm pcm_rec[MAX_HDMI_CVTS]; |
49 | struct hda_pcm_stream codec_pcm_pars[MAX_HDMI_CVTS]; | ||
49 | 50 | ||
50 | /* | 51 | /* |
51 | * nvhdmi specific | 52 | * nvhdmi specific |
@@ -698,30 +699,93 @@ static void hdmi_unsol_event(struct hda_codec *codec, unsigned int res) | |||
698 | * Callbacks | 699 | * Callbacks |
699 | */ | 700 | */ |
700 | 701 | ||
701 | static void hdmi_setup_stream(struct hda_codec *codec, hda_nid_t nid, | 702 | /* HBR should be Non-PCM, 8 channels */ |
703 | #define is_hbr_format(format) \ | ||
704 | ((format & AC_FMT_TYPE_NON_PCM) && (format & AC_FMT_CHAN_MASK) == 7) | ||
705 | |||
706 | static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t nid, | ||
702 | u32 stream_tag, int format) | 707 | u32 stream_tag, int format) |
703 | { | 708 | { |
704 | int tag; | 709 | struct hdmi_spec *spec = codec->spec; |
705 | int fmt; | 710 | int pinctl; |
711 | int new_pinctl = 0; | ||
712 | int i; | ||
713 | |||
714 | for (i = 0; i < spec->num_pins; i++) { | ||
715 | if (spec->pin_cvt[i] != nid) | ||
716 | continue; | ||
717 | if (!(snd_hda_query_pin_caps(codec, spec->pin[i]) & AC_PINCAP_HBR)) | ||
718 | continue; | ||
706 | 719 | ||
707 | tag = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0) >> 4; | 720 | pinctl = snd_hda_codec_read(codec, spec->pin[i], 0, |
708 | fmt = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_STREAM_FORMAT, 0); | 721 | AC_VERB_GET_PIN_WIDGET_CONTROL, 0); |
722 | |||
723 | new_pinctl = pinctl & ~AC_PINCTL_EPT; | ||
724 | if (is_hbr_format(format)) | ||
725 | new_pinctl |= AC_PINCTL_EPT_HBR; | ||
726 | else | ||
727 | new_pinctl |= AC_PINCTL_EPT_NATIVE; | ||
728 | |||
729 | snd_printdd("hdmi_setup_stream: " | ||
730 | "NID=0x%x, %spinctl=0x%x\n", | ||
731 | spec->pin[i], | ||
732 | pinctl == new_pinctl ? "" : "new-", | ||
733 | new_pinctl); | ||
734 | |||
735 | if (pinctl != new_pinctl) | ||
736 | snd_hda_codec_write(codec, spec->pin[i], 0, | ||
737 | AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
738 | new_pinctl); | ||
739 | } | ||
709 | 740 | ||
710 | snd_printdd("hdmi_setup_stream: " | 741 | if (is_hbr_format(format) && !new_pinctl) { |
711 | "NID=0x%x, %sstream=0x%x, %sformat=0x%x\n", | 742 | snd_printdd("hdmi_setup_stream: HBR is not supported\n"); |
712 | nid, | 743 | return -EINVAL; |
713 | tag == stream_tag ? "" : "new-", | 744 | } |
714 | stream_tag, | ||
715 | fmt == format ? "" : "new-", | ||
716 | format); | ||
717 | 745 | ||
718 | if (tag != stream_tag) | 746 | snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format); |
719 | snd_hda_codec_write(codec, nid, 0, | 747 | return 0; |
720 | AC_VERB_SET_CHANNEL_STREAMID, | 748 | } |
721 | stream_tag << 4); | 749 | |
722 | if (fmt != format) | 750 | /* |
723 | snd_hda_codec_write(codec, nid, 0, | 751 | * HDA PCM callbacks |
724 | AC_VERB_SET_STREAM_FORMAT, format); | 752 | */ |
753 | static int hdmi_pcm_open(struct hda_pcm_stream *hinfo, | ||
754 | struct hda_codec *codec, | ||
755 | struct snd_pcm_substream *substream) | ||
756 | { | ||
757 | struct hdmi_spec *spec = codec->spec; | ||
758 | struct hdmi_eld *eld; | ||
759 | struct hda_pcm_stream *codec_pars; | ||
760 | unsigned int idx; | ||
761 | |||
762 | for (idx = 0; idx < spec->num_cvts; idx++) | ||
763 | if (hinfo->nid == spec->cvt[idx]) | ||
764 | break; | ||
765 | if (snd_BUG_ON(idx >= spec->num_cvts) || | ||
766 | snd_BUG_ON(idx >= spec->num_pins)) | ||
767 | return -EINVAL; | ||
768 | |||
769 | /* save the PCM info the codec provides */ | ||
770 | codec_pars = &spec->codec_pcm_pars[idx]; | ||
771 | if (!codec_pars->rates) | ||
772 | *codec_pars = *hinfo; | ||
773 | |||
774 | eld = &spec->sink_eld[idx]; | ||
775 | if (eld->sad_count > 0) { | ||
776 | hdmi_eld_update_pcm_info(eld, hinfo, codec_pars); | ||
777 | if (hinfo->channels_min > hinfo->channels_max || | ||
778 | !hinfo->rates || !hinfo->formats) | ||
779 | return -ENODEV; | ||
780 | } else { | ||
781 | /* fallback to the codec default */ | ||
782 | hinfo->channels_min = codec_pars->channels_min; | ||
783 | hinfo->channels_max = codec_pars->channels_max; | ||
784 | hinfo->rates = codec_pars->rates; | ||
785 | hinfo->formats = codec_pars->formats; | ||
786 | hinfo->maxbps = codec_pars->maxbps; | ||
787 | } | ||
788 | return 0; | ||
725 | } | 789 | } |
726 | 790 | ||
727 | /* | 791 | /* |
diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index b81d23e42ace..36a9b83a6174 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c | |||
@@ -66,23 +66,15 @@ static int intel_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, | |||
66 | 66 | ||
67 | hdmi_setup_audio_infoframe(codec, hinfo->nid, substream); | 67 | hdmi_setup_audio_infoframe(codec, hinfo->nid, substream); |
68 | 68 | ||
69 | hdmi_setup_stream(codec, hinfo->nid, stream_tag, format); | 69 | return hdmi_setup_stream(codec, hinfo->nid, stream_tag, format); |
70 | return 0; | ||
71 | } | ||
72 | |||
73 | static int intel_hdmi_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, | ||
74 | struct hda_codec *codec, | ||
75 | struct snd_pcm_substream *substream) | ||
76 | { | ||
77 | return 0; | ||
78 | } | 70 | } |
79 | 71 | ||
80 | static struct hda_pcm_stream intel_hdmi_pcm_playback = { | 72 | static struct hda_pcm_stream intel_hdmi_pcm_playback = { |
81 | .substreams = 1, | 73 | .substreams = 1, |
82 | .channels_min = 2, | 74 | .channels_min = 2, |
83 | .ops = { | 75 | .ops = { |
76 | .open = hdmi_pcm_open, | ||
84 | .prepare = intel_hdmi_playback_pcm_prepare, | 77 | .prepare = intel_hdmi_playback_pcm_prepare, |
85 | .cleanup = intel_hdmi_playback_pcm_cleanup, | ||
86 | }, | 78 | }, |
87 | }; | 79 | }; |
88 | 80 | ||
diff --git a/sound/pci/hda/patch_nvhdmi.c b/sound/pci/hda/patch_nvhdmi.c index b0652acee9b2..69b950d527c3 100644 --- a/sound/pci/hda/patch_nvhdmi.c +++ b/sound/pci/hda/patch_nvhdmi.c | |||
@@ -202,8 +202,7 @@ static int nvhdmi_dig_playback_pcm_prepare_8ch_89(struct hda_pcm_stream *hinfo, | |||
202 | 202 | ||
203 | hdmi_setup_audio_infoframe(codec, hinfo->nid, substream); | 203 | hdmi_setup_audio_infoframe(codec, hinfo->nid, substream); |
204 | 204 | ||
205 | hdmi_setup_stream(codec, hinfo->nid, stream_tag, format); | 205 | return hdmi_setup_stream(codec, hinfo->nid, stream_tag, format); |
206 | return 0; | ||
207 | } | 206 | } |
208 | 207 | ||
209 | static int nvhdmi_dig_playback_pcm_prepare_8ch(struct hda_pcm_stream *hinfo, | 208 | static int nvhdmi_dig_playback_pcm_prepare_8ch(struct hda_pcm_stream *hinfo, |
@@ -327,13 +326,6 @@ static int nvhdmi_dig_playback_pcm_prepare_8ch(struct hda_pcm_stream *hinfo, | |||
327 | return 0; | 326 | return 0; |
328 | } | 327 | } |
329 | 328 | ||
330 | static int nvhdmi_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, | ||
331 | struct hda_codec *codec, | ||
332 | struct snd_pcm_substream *substream) | ||
333 | { | ||
334 | return 0; | ||
335 | } | ||
336 | |||
337 | static int nvhdmi_dig_playback_pcm_prepare_2ch(struct hda_pcm_stream *hinfo, | 329 | static int nvhdmi_dig_playback_pcm_prepare_2ch(struct hda_pcm_stream *hinfo, |
338 | struct hda_codec *codec, | 330 | struct hda_codec *codec, |
339 | unsigned int stream_tag, | 331 | unsigned int stream_tag, |
@@ -348,12 +340,9 @@ static int nvhdmi_dig_playback_pcm_prepare_2ch(struct hda_pcm_stream *hinfo, | |||
348 | static struct hda_pcm_stream nvhdmi_pcm_digital_playback_8ch_89 = { | 340 | static struct hda_pcm_stream nvhdmi_pcm_digital_playback_8ch_89 = { |
349 | .substreams = 1, | 341 | .substreams = 1, |
350 | .channels_min = 2, | 342 | .channels_min = 2, |
351 | .rates = SUPPORTED_RATES, | ||
352 | .maxbps = SUPPORTED_MAXBPS, | ||
353 | .formats = SUPPORTED_FORMATS, | ||
354 | .ops = { | 343 | .ops = { |
344 | .open = hdmi_pcm_open, | ||
355 | .prepare = nvhdmi_dig_playback_pcm_prepare_8ch_89, | 345 | .prepare = nvhdmi_dig_playback_pcm_prepare_8ch_89, |
356 | .cleanup = nvhdmi_playback_pcm_cleanup, | ||
357 | }, | 346 | }, |
358 | }; | 347 | }; |
359 | 348 | ||
@@ -541,26 +530,32 @@ static int patch_nvhdmi_2ch(struct hda_codec *codec) | |||
541 | * patch entries | 530 | * patch entries |
542 | */ | 531 | */ |
543 | static struct hda_codec_preset snd_hda_preset_nvhdmi[] = { | 532 | static struct hda_codec_preset snd_hda_preset_nvhdmi[] = { |
544 | { .id = 0x10de0002, .name = "MCP77/78 HDMI", | 533 | { .id = 0x10de0002, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x }, |
545 | .patch = patch_nvhdmi_8ch_7x }, | 534 | { .id = 0x10de0003, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x }, |
546 | { .id = 0x10de0003, .name = "MCP77/78 HDMI", | 535 | { .id = 0x10de0005, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x }, |
547 | .patch = patch_nvhdmi_8ch_7x }, | 536 | { .id = 0x10de0006, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x }, |
548 | { .id = 0x10de0005, .name = "MCP77/78 HDMI", | 537 | { .id = 0x10de0007, .name = "MCP79/7A HDMI", .patch = patch_nvhdmi_8ch_7x }, |
549 | .patch = patch_nvhdmi_8ch_7x }, | 538 | { .id = 0x10de000a, .name = "GPU 0a HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, |
550 | { .id = 0x10de0006, .name = "MCP77/78 HDMI", | 539 | { .id = 0x10de000b, .name = "GPU 0b HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, |
551 | .patch = patch_nvhdmi_8ch_7x }, | 540 | { .id = 0x10de000c, .name = "MCP89 HDMI", .patch = patch_nvhdmi_8ch_89 }, |
552 | { .id = 0x10de0007, .name = "MCP79/7A HDMI", | 541 | { .id = 0x10de000d, .name = "GPU 0d HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, |
553 | .patch = patch_nvhdmi_8ch_7x }, | 542 | { .id = 0x10de0010, .name = "GPU 10 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, |
554 | { .id = 0x10de000a, .name = "GT220 HDMI", | 543 | { .id = 0x10de0011, .name = "GPU 11 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, |
555 | .patch = patch_nvhdmi_8ch_89 }, | 544 | { .id = 0x10de0012, .name = "GPU 12 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, |
556 | { .id = 0x10de000b, .name = "GT21x HDMI", | 545 | { .id = 0x10de0013, .name = "GPU 13 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, |
557 | .patch = patch_nvhdmi_8ch_89 }, | 546 | { .id = 0x10de0014, .name = "GPU 14 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, |
558 | { .id = 0x10de000c, .name = "MCP89 HDMI", | 547 | { .id = 0x10de0018, .name = "GPU 18 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, |
559 | .patch = patch_nvhdmi_8ch_89 }, | 548 | { .id = 0x10de0019, .name = "GPU 19 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, |
560 | { .id = 0x10de000d, .name = "GT240 HDMI", | 549 | { .id = 0x10de001a, .name = "GPU 1a HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, |
561 | .patch = patch_nvhdmi_8ch_89 }, | 550 | { .id = 0x10de001b, .name = "GPU 1b HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, |
562 | { .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi_2ch }, | 551 | { .id = 0x10de001c, .name = "GPU 1c HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, |
563 | { .id = 0x10de8001, .name = "MCP73 HDMI", .patch = patch_nvhdmi_2ch }, | 552 | { .id = 0x10de0040, .name = "GPU 40 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, |
553 | { .id = 0x10de0041, .name = "GPU 41 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, | ||
554 | { .id = 0x10de0042, .name = "GPU 42 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, | ||
555 | { .id = 0x10de0043, .name = "GPU 43 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, | ||
556 | { .id = 0x10de0044, .name = "GPU 44 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, | ||
557 | { .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi_2ch }, | ||
558 | { .id = 0x10de8001, .name = "MCP73 HDMI", .patch = patch_nvhdmi_2ch }, | ||
564 | {} /* terminator */ | 559 | {} /* terminator */ |
565 | }; | 560 | }; |
566 | 561 | ||
@@ -573,6 +568,21 @@ MODULE_ALIAS("snd-hda-codec-id:10de000a"); | |||
573 | MODULE_ALIAS("snd-hda-codec-id:10de000b"); | 568 | MODULE_ALIAS("snd-hda-codec-id:10de000b"); |
574 | MODULE_ALIAS("snd-hda-codec-id:10de000c"); | 569 | MODULE_ALIAS("snd-hda-codec-id:10de000c"); |
575 | MODULE_ALIAS("snd-hda-codec-id:10de000d"); | 570 | MODULE_ALIAS("snd-hda-codec-id:10de000d"); |
571 | MODULE_ALIAS("snd-hda-codec-id:10de0010"); | ||
572 | MODULE_ALIAS("snd-hda-codec-id:10de0011"); | ||
573 | MODULE_ALIAS("snd-hda-codec-id:10de0012"); | ||
574 | MODULE_ALIAS("snd-hda-codec-id:10de0013"); | ||
575 | MODULE_ALIAS("snd-hda-codec-id:10de0014"); | ||
576 | MODULE_ALIAS("snd-hda-codec-id:10de0018"); | ||
577 | MODULE_ALIAS("snd-hda-codec-id:10de0019"); | ||
578 | MODULE_ALIAS("snd-hda-codec-id:10de001a"); | ||
579 | MODULE_ALIAS("snd-hda-codec-id:10de001b"); | ||
580 | MODULE_ALIAS("snd-hda-codec-id:10de001c"); | ||
581 | MODULE_ALIAS("snd-hda-codec-id:10de0040"); | ||
582 | MODULE_ALIAS("snd-hda-codec-id:10de0041"); | ||
583 | MODULE_ALIAS("snd-hda-codec-id:10de0042"); | ||
584 | MODULE_ALIAS("snd-hda-codec-id:10de0043"); | ||
585 | MODULE_ALIAS("snd-hda-codec-id:10de0044"); | ||
576 | MODULE_ALIAS("snd-hda-codec-id:10de0067"); | 586 | MODULE_ALIAS("snd-hda-codec-id:10de0067"); |
577 | MODULE_ALIAS("snd-hda-codec-id:10de8001"); | 587 | MODULE_ALIAS("snd-hda-codec-id:10de8001"); |
578 | 588 | ||
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 596ea2f12cf6..bcbf9160ed81 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c | |||
@@ -137,6 +137,7 @@ enum { | |||
137 | ALC269VB_DMIC, | 137 | ALC269VB_DMIC, |
138 | ALC269_FUJITSU, | 138 | ALC269_FUJITSU, |
139 | ALC269_LIFEBOOK, | 139 | ALC269_LIFEBOOK, |
140 | ALC271_ACER, | ||
140 | ALC269_AUTO, | 141 | ALC269_AUTO, |
141 | ALC269_MODEL_LAST /* last tag */ | 142 | ALC269_MODEL_LAST /* last tag */ |
142 | }; | 143 | }; |
@@ -256,6 +257,13 @@ enum { | |||
256 | ALC882_MODEL_LAST, | 257 | ALC882_MODEL_LAST, |
257 | }; | 258 | }; |
258 | 259 | ||
260 | /* ALC680 models */ | ||
261 | enum { | ||
262 | ALC680_BASE, | ||
263 | ALC680_AUTO, | ||
264 | ALC680_MODEL_LAST, | ||
265 | }; | ||
266 | |||
259 | /* for GPIO Poll */ | 267 | /* for GPIO Poll */ |
260 | #define GPIO_MASK 0x03 | 268 | #define GPIO_MASK 0x03 |
261 | 269 | ||
@@ -326,6 +334,12 @@ struct alc_spec { | |||
326 | hda_nid_t *capsrc_nids; | 334 | hda_nid_t *capsrc_nids; |
327 | hda_nid_t dig_in_nid; /* digital-in NID; optional */ | 335 | hda_nid_t dig_in_nid; /* digital-in NID; optional */ |
328 | 336 | ||
337 | /* capture setup for dynamic dual-adc switch */ | ||
338 | unsigned int cur_adc_idx; | ||
339 | hda_nid_t cur_adc; | ||
340 | unsigned int cur_adc_stream_tag; | ||
341 | unsigned int cur_adc_format; | ||
342 | |||
329 | /* capture source */ | 343 | /* capture source */ |
330 | unsigned int num_mux_defs; | 344 | unsigned int num_mux_defs; |
331 | const struct hda_input_mux *input_mux; | 345 | const struct hda_input_mux *input_mux; |
@@ -367,6 +381,7 @@ struct alc_spec { | |||
367 | 381 | ||
368 | /* other flags */ | 382 | /* other flags */ |
369 | unsigned int no_analog :1; /* digital I/O only */ | 383 | unsigned int no_analog :1; /* digital I/O only */ |
384 | unsigned int dual_adc_switch:1; /* switch ADCs (for ALC275) */ | ||
370 | int init_amp; | 385 | int init_amp; |
371 | 386 | ||
372 | /* for virtual master */ | 387 | /* for virtual master */ |
@@ -833,9 +848,13 @@ static void alc_set_input_pin(struct hda_codec *codec, hda_nid_t nid, | |||
833 | 848 | ||
834 | if (auto_pin_type <= AUTO_PIN_FRONT_MIC) { | 849 | if (auto_pin_type <= AUTO_PIN_FRONT_MIC) { |
835 | unsigned int pincap; | 850 | unsigned int pincap; |
851 | unsigned int oldval; | ||
852 | oldval = snd_hda_codec_read(codec, nid, 0, | ||
853 | AC_VERB_GET_PIN_WIDGET_CONTROL, 0); | ||
836 | pincap = snd_hda_query_pin_caps(codec, nid); | 854 | pincap = snd_hda_query_pin_caps(codec, nid); |
837 | pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT; | 855 | pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT; |
838 | if (pincap & AC_PINCAP_VREF_80) | 856 | /* if the default pin setup is vref50, we give it priority */ |
857 | if ((pincap & AC_PINCAP_VREF_80) && oldval != PIN_VREF50) | ||
839 | val = PIN_VREF80; | 858 | val = PIN_VREF80; |
840 | else if (pincap & AC_PINCAP_VREF_50) | 859 | else if (pincap & AC_PINCAP_VREF_50) |
841 | val = PIN_VREF50; | 860 | val = PIN_VREF50; |
@@ -1003,6 +1022,29 @@ static int get_connection_index(struct hda_codec *codec, hda_nid_t mux, | |||
1003 | return -1; | 1022 | return -1; |
1004 | } | 1023 | } |
1005 | 1024 | ||
1025 | /* switch the current ADC according to the jack state */ | ||
1026 | static void alc_dual_mic_adc_auto_switch(struct hda_codec *codec) | ||
1027 | { | ||
1028 | struct alc_spec *spec = codec->spec; | ||
1029 | unsigned int present; | ||
1030 | hda_nid_t new_adc; | ||
1031 | |||
1032 | present = snd_hda_jack_detect(codec, spec->ext_mic.pin); | ||
1033 | if (present) | ||
1034 | spec->cur_adc_idx = 1; | ||
1035 | else | ||
1036 | spec->cur_adc_idx = 0; | ||
1037 | new_adc = spec->adc_nids[spec->cur_adc_idx]; | ||
1038 | if (spec->cur_adc && spec->cur_adc != new_adc) { | ||
1039 | /* stream is running, let's swap the current ADC */ | ||
1040 | __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1); | ||
1041 | spec->cur_adc = new_adc; | ||
1042 | snd_hda_codec_setup_stream(codec, new_adc, | ||
1043 | spec->cur_adc_stream_tag, 0, | ||
1044 | spec->cur_adc_format); | ||
1045 | } | ||
1046 | } | ||
1047 | |||
1006 | static void alc_mic_automute(struct hda_codec *codec) | 1048 | static void alc_mic_automute(struct hda_codec *codec) |
1007 | { | 1049 | { |
1008 | struct alc_spec *spec = codec->spec; | 1050 | struct alc_spec *spec = codec->spec; |
@@ -1017,6 +1059,11 @@ static void alc_mic_automute(struct hda_codec *codec) | |||
1017 | if (snd_BUG_ON(!spec->adc_nids)) | 1059 | if (snd_BUG_ON(!spec->adc_nids)) |
1018 | return; | 1060 | return; |
1019 | 1061 | ||
1062 | if (spec->dual_adc_switch) { | ||
1063 | alc_dual_mic_adc_auto_switch(codec); | ||
1064 | return; | ||
1065 | } | ||
1066 | |||
1020 | cap_nid = spec->capsrc_nids ? spec->capsrc_nids[0] : spec->adc_nids[0]; | 1067 | cap_nid = spec->capsrc_nids ? spec->capsrc_nids[0] : spec->adc_nids[0]; |
1021 | 1068 | ||
1022 | present = snd_hda_jack_detect(codec, spec->ext_mic.pin); | 1069 | present = snd_hda_jack_detect(codec, spec->ext_mic.pin); |
@@ -1499,6 +1546,63 @@ static int alc_read_coef_idx(struct hda_codec *codec, | |||
1499 | return val; | 1546 | return val; |
1500 | } | 1547 | } |
1501 | 1548 | ||
1549 | /* set right pin controls for digital I/O */ | ||
1550 | static void alc_auto_init_digital(struct hda_codec *codec) | ||
1551 | { | ||
1552 | struct alc_spec *spec = codec->spec; | ||
1553 | int i; | ||
1554 | hda_nid_t pin; | ||
1555 | |||
1556 | for (i = 0; i < spec->autocfg.dig_outs; i++) { | ||
1557 | pin = spec->autocfg.dig_out_pins[i]; | ||
1558 | if (pin) { | ||
1559 | snd_hda_codec_write(codec, pin, 0, | ||
1560 | AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
1561 | PIN_OUT); | ||
1562 | } | ||
1563 | } | ||
1564 | pin = spec->autocfg.dig_in_pin; | ||
1565 | if (pin) | ||
1566 | snd_hda_codec_write(codec, pin, 0, | ||
1567 | AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
1568 | PIN_IN); | ||
1569 | } | ||
1570 | |||
1571 | /* parse digital I/Os and set up NIDs in BIOS auto-parse mode */ | ||
1572 | static void alc_auto_parse_digital(struct hda_codec *codec) | ||
1573 | { | ||
1574 | struct alc_spec *spec = codec->spec; | ||
1575 | int i, err; | ||
1576 | hda_nid_t dig_nid; | ||
1577 | |||
1578 | /* support multiple SPDIFs; the secondary is set up as a slave */ | ||
1579 | for (i = 0; i < spec->autocfg.dig_outs; i++) { | ||
1580 | err = snd_hda_get_connections(codec, | ||
1581 | spec->autocfg.dig_out_pins[i], | ||
1582 | &dig_nid, 1); | ||
1583 | if (err < 0) | ||
1584 | continue; | ||
1585 | if (!i) { | ||
1586 | spec->multiout.dig_out_nid = dig_nid; | ||
1587 | spec->dig_out_type = spec->autocfg.dig_out_type[0]; | ||
1588 | } else { | ||
1589 | spec->multiout.slave_dig_outs = spec->slave_dig_outs; | ||
1590 | if (i >= ARRAY_SIZE(spec->slave_dig_outs) - 1) | ||
1591 | break; | ||
1592 | spec->slave_dig_outs[i - 1] = dig_nid; | ||
1593 | } | ||
1594 | } | ||
1595 | |||
1596 | if (spec->autocfg.dig_in_pin) { | ||
1597 | hda_nid_t dig_nid; | ||
1598 | err = snd_hda_get_connections(codec, | ||
1599 | spec->autocfg.dig_in_pin, | ||
1600 | &dig_nid, 1); | ||
1601 | if (err > 0) | ||
1602 | spec->dig_in_nid = dig_nid; | ||
1603 | } | ||
1604 | } | ||
1605 | |||
1502 | /* | 1606 | /* |
1503 | * ALC888 | 1607 | * ALC888 |
1504 | */ | 1608 | */ |
@@ -3607,6 +3711,41 @@ static int alc880_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, | |||
3607 | return 0; | 3711 | return 0; |
3608 | } | 3712 | } |
3609 | 3713 | ||
3714 | /* analog capture with dynamic dual-adc changes */ | ||
3715 | static int dualmic_capture_pcm_prepare(struct hda_pcm_stream *hinfo, | ||
3716 | struct hda_codec *codec, | ||
3717 | unsigned int stream_tag, | ||
3718 | unsigned int format, | ||
3719 | struct snd_pcm_substream *substream) | ||
3720 | { | ||
3721 | struct alc_spec *spec = codec->spec; | ||
3722 | spec->cur_adc = spec->adc_nids[spec->cur_adc_idx]; | ||
3723 | spec->cur_adc_stream_tag = stream_tag; | ||
3724 | spec->cur_adc_format = format; | ||
3725 | snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format); | ||
3726 | return 0; | ||
3727 | } | ||
3728 | |||
3729 | static int dualmic_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, | ||
3730 | struct hda_codec *codec, | ||
3731 | struct snd_pcm_substream *substream) | ||
3732 | { | ||
3733 | struct alc_spec *spec = codec->spec; | ||
3734 | snd_hda_codec_cleanup_stream(codec, spec->cur_adc); | ||
3735 | spec->cur_adc = 0; | ||
3736 | return 0; | ||
3737 | } | ||
3738 | |||
3739 | static struct hda_pcm_stream dualmic_pcm_analog_capture = { | ||
3740 | .substreams = 1, | ||
3741 | .channels_min = 2, | ||
3742 | .channels_max = 2, | ||
3743 | .nid = 0, /* fill later */ | ||
3744 | .ops = { | ||
3745 | .prepare = dualmic_capture_pcm_prepare, | ||
3746 | .cleanup = dualmic_capture_pcm_cleanup | ||
3747 | }, | ||
3748 | }; | ||
3610 | 3749 | ||
3611 | /* | 3750 | /* |
3612 | */ | 3751 | */ |
@@ -4936,7 +5075,7 @@ static void alc880_auto_init_input_src(struct hda_codec *codec) | |||
4936 | static int alc880_parse_auto_config(struct hda_codec *codec) | 5075 | static int alc880_parse_auto_config(struct hda_codec *codec) |
4937 | { | 5076 | { |
4938 | struct alc_spec *spec = codec->spec; | 5077 | struct alc_spec *spec = codec->spec; |
4939 | int i, err; | 5078 | int err; |
4940 | static hda_nid_t alc880_ignore[] = { 0x1d, 0 }; | 5079 | static hda_nid_t alc880_ignore[] = { 0x1d, 0 }; |
4941 | 5080 | ||
4942 | err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, | 5081 | err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, |
@@ -4967,25 +5106,7 @@ static int alc880_parse_auto_config(struct hda_codec *codec) | |||
4967 | 5106 | ||
4968 | spec->multiout.max_channels = spec->multiout.num_dacs * 2; | 5107 | spec->multiout.max_channels = spec->multiout.num_dacs * 2; |
4969 | 5108 | ||
4970 | /* check multiple SPDIF-out (for recent codecs) */ | 5109 | alc_auto_parse_digital(codec); |
4971 | for (i = 0; i < spec->autocfg.dig_outs; i++) { | ||
4972 | hda_nid_t dig_nid; | ||
4973 | err = snd_hda_get_connections(codec, | ||
4974 | spec->autocfg.dig_out_pins[i], | ||
4975 | &dig_nid, 1); | ||
4976 | if (err < 0) | ||
4977 | continue; | ||
4978 | if (!i) | ||
4979 | spec->multiout.dig_out_nid = dig_nid; | ||
4980 | else { | ||
4981 | spec->multiout.slave_dig_outs = spec->slave_dig_outs; | ||
4982 | if (i >= ARRAY_SIZE(spec->slave_dig_outs) - 1) | ||
4983 | break; | ||
4984 | spec->slave_dig_outs[i - 1] = dig_nid; | ||
4985 | } | ||
4986 | } | ||
4987 | if (spec->autocfg.dig_in_pin) | ||
4988 | spec->dig_in_nid = ALC880_DIGIN_NID; | ||
4989 | 5110 | ||
4990 | if (spec->kctls.list) | 5111 | if (spec->kctls.list) |
4991 | add_mixer(spec, spec->kctls.list); | 5112 | add_mixer(spec, spec->kctls.list); |
@@ -5008,6 +5129,7 @@ static void alc880_auto_init(struct hda_codec *codec) | |||
5008 | alc880_auto_init_extra_out(codec); | 5129 | alc880_auto_init_extra_out(codec); |
5009 | alc880_auto_init_analog_input(codec); | 5130 | alc880_auto_init_analog_input(codec); |
5010 | alc880_auto_init_input_src(codec); | 5131 | alc880_auto_init_input_src(codec); |
5132 | alc_auto_init_digital(codec); | ||
5011 | if (spec->unsol_event) | 5133 | if (spec->unsol_event) |
5012 | alc_inithook(codec); | 5134 | alc_inithook(codec); |
5013 | } | 5135 | } |
@@ -5045,6 +5167,39 @@ static void fixup_automic_adc(struct hda_codec *codec) | |||
5045 | spec->auto_mic = 0; /* disable auto-mic to be sure */ | 5167 | spec->auto_mic = 0; /* disable auto-mic to be sure */ |
5046 | } | 5168 | } |
5047 | 5169 | ||
5170 | /* select or unmute the given capsrc route */ | ||
5171 | static void select_or_unmute_capsrc(struct hda_codec *codec, hda_nid_t cap, | ||
5172 | int idx) | ||
5173 | { | ||
5174 | if (get_wcaps_type(get_wcaps(codec, cap)) == AC_WID_AUD_MIX) { | ||
5175 | snd_hda_codec_amp_stereo(codec, cap, HDA_INPUT, idx, | ||
5176 | HDA_AMP_MUTE, 0); | ||
5177 | } else { | ||
5178 | snd_hda_codec_write_cache(codec, cap, 0, | ||
5179 | AC_VERB_SET_CONNECT_SEL, idx); | ||
5180 | } | ||
5181 | } | ||
5182 | |||
5183 | /* set the default connection to that pin */ | ||
5184 | static int init_capsrc_for_pin(struct hda_codec *codec, hda_nid_t pin) | ||
5185 | { | ||
5186 | struct alc_spec *spec = codec->spec; | ||
5187 | int i; | ||
5188 | |||
5189 | for (i = 0; i < spec->num_adc_nids; i++) { | ||
5190 | hda_nid_t cap = spec->capsrc_nids ? | ||
5191 | spec->capsrc_nids[i] : spec->adc_nids[i]; | ||
5192 | int idx; | ||
5193 | |||
5194 | idx = get_connection_index(codec, cap, pin); | ||
5195 | if (idx < 0) | ||
5196 | continue; | ||
5197 | select_or_unmute_capsrc(codec, cap, idx); | ||
5198 | return i; /* return the found index */ | ||
5199 | } | ||
5200 | return -1; /* not found */ | ||
5201 | } | ||
5202 | |||
5048 | /* choose the ADC/MUX containing the input pin and initialize the setup */ | 5203 | /* choose the ADC/MUX containing the input pin and initialize the setup */ |
5049 | static void fixup_single_adc(struct hda_codec *codec) | 5204 | static void fixup_single_adc(struct hda_codec *codec) |
5050 | { | 5205 | { |
@@ -5061,33 +5216,24 @@ static void fixup_single_adc(struct hda_codec *codec) | |||
5061 | } | 5216 | } |
5062 | if (!pin) | 5217 | if (!pin) |
5063 | return; | 5218 | return; |
5064 | 5219 | i = init_capsrc_for_pin(codec, pin); | |
5065 | /* set the default connection to that pin */ | 5220 | if (i >= 0) { |
5066 | for (i = 0; i < spec->num_adc_nids; i++) { | ||
5067 | hda_nid_t cap = spec->capsrc_nids ? | ||
5068 | spec->capsrc_nids[i] : spec->adc_nids[i]; | ||
5069 | int idx; | ||
5070 | |||
5071 | idx = get_connection_index(codec, cap, pin); | ||
5072 | if (idx < 0) | ||
5073 | continue; | ||
5074 | /* use only this ADC */ | 5221 | /* use only this ADC */ |
5075 | if (spec->capsrc_nids) | 5222 | if (spec->capsrc_nids) |
5076 | spec->capsrc_nids += i; | 5223 | spec->capsrc_nids += i; |
5077 | spec->adc_nids += i; | 5224 | spec->adc_nids += i; |
5078 | spec->num_adc_nids = 1; | 5225 | spec->num_adc_nids = 1; |
5079 | /* select or unmute this route */ | ||
5080 | if (get_wcaps_type(get_wcaps(codec, cap)) == AC_WID_AUD_MIX) { | ||
5081 | snd_hda_codec_amp_stereo(codec, cap, HDA_INPUT, idx, | ||
5082 | HDA_AMP_MUTE, 0); | ||
5083 | } else { | ||
5084 | snd_hda_codec_write_cache(codec, cap, 0, | ||
5085 | AC_VERB_SET_CONNECT_SEL, idx); | ||
5086 | } | ||
5087 | return; | ||
5088 | } | 5226 | } |
5089 | } | 5227 | } |
5090 | 5228 | ||
5229 | /* initialize dual adcs */ | ||
5230 | static void fixup_dual_adc_switch(struct hda_codec *codec) | ||
5231 | { | ||
5232 | struct alc_spec *spec = codec->spec; | ||
5233 | init_capsrc_for_pin(codec, spec->ext_mic.pin); | ||
5234 | init_capsrc_for_pin(codec, spec->int_mic.pin); | ||
5235 | } | ||
5236 | |||
5091 | static void set_capture_mixer(struct hda_codec *codec) | 5237 | static void set_capture_mixer(struct hda_codec *codec) |
5092 | { | 5238 | { |
5093 | struct alc_spec *spec = codec->spec; | 5239 | struct alc_spec *spec = codec->spec; |
@@ -5101,7 +5247,10 @@ static void set_capture_mixer(struct hda_codec *codec) | |||
5101 | }; | 5247 | }; |
5102 | if (spec->num_adc_nids > 0 && spec->num_adc_nids <= 3) { | 5248 | if (spec->num_adc_nids > 0 && spec->num_adc_nids <= 3) { |
5103 | int mux = 0; | 5249 | int mux = 0; |
5104 | if (spec->auto_mic) | 5250 | int num_adcs = spec->num_adc_nids; |
5251 | if (spec->dual_adc_switch) | ||
5252 | fixup_dual_adc_switch(codec); | ||
5253 | else if (spec->auto_mic) | ||
5105 | fixup_automic_adc(codec); | 5254 | fixup_automic_adc(codec); |
5106 | else if (spec->input_mux) { | 5255 | else if (spec->input_mux) { |
5107 | if (spec->input_mux->num_items > 1) | 5256 | if (spec->input_mux->num_items > 1) |
@@ -5109,7 +5258,9 @@ static void set_capture_mixer(struct hda_codec *codec) | |||
5109 | else if (spec->input_mux->num_items == 1) | 5258 | else if (spec->input_mux->num_items == 1) |
5110 | fixup_single_adc(codec); | 5259 | fixup_single_adc(codec); |
5111 | } | 5260 | } |
5112 | spec->cap_mixer = caps[mux][spec->num_adc_nids - 1]; | 5261 | if (spec->dual_adc_switch) |
5262 | num_adcs = 1; | ||
5263 | spec->cap_mixer = caps[mux][num_adcs - 1]; | ||
5113 | } | 5264 | } |
5114 | } | 5265 | } |
5115 | 5266 | ||
@@ -5183,6 +5334,8 @@ static void fillup_priv_adc_nids(struct hda_codec *codec, hda_nid_t *nids, | |||
5183 | 5334 | ||
5184 | static struct snd_pci_quirk beep_white_list[] = { | 5335 | static struct snd_pci_quirk beep_white_list[] = { |
5185 | SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1), | 5336 | SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1), |
5337 | SND_PCI_QUIRK(0x1043, 0x83ce, "EeePC", 1), | ||
5338 | SND_PCI_QUIRK(0x8086, 0xd613, "Intel", 1), | ||
5186 | {} | 5339 | {} |
5187 | }; | 5340 | }; |
5188 | 5341 | ||
@@ -6624,6 +6777,7 @@ static void alc260_auto_init(struct hda_codec *codec) | |||
6624 | alc260_auto_init_multi_out(codec); | 6777 | alc260_auto_init_multi_out(codec); |
6625 | alc260_auto_init_analog_input(codec); | 6778 | alc260_auto_init_analog_input(codec); |
6626 | alc260_auto_init_input_src(codec); | 6779 | alc260_auto_init_input_src(codec); |
6780 | alc_auto_init_digital(codec); | ||
6627 | if (spec->unsol_event) | 6781 | if (spec->unsol_event) |
6628 | alc_inithook(codec); | 6782 | alc_inithook(codec); |
6629 | } | 6783 | } |
@@ -6640,6 +6794,29 @@ static struct hda_amp_list alc260_loopbacks[] = { | |||
6640 | #endif | 6794 | #endif |
6641 | 6795 | ||
6642 | /* | 6796 | /* |
6797 | * Pin config fixes | ||
6798 | */ | ||
6799 | enum { | ||
6800 | PINFIX_HP_DC5750, | ||
6801 | }; | ||
6802 | |||
6803 | static struct alc_pincfg alc260_hp_dc5750_pinfix[] = { | ||
6804 | { 0x11, 0x90130110 }, /* speaker */ | ||
6805 | { } | ||
6806 | }; | ||
6807 | |||
6808 | static const struct alc_fixup alc260_fixups[] = { | ||
6809 | [PINFIX_HP_DC5750] = { | ||
6810 | .pins = alc260_hp_dc5750_pinfix | ||
6811 | }, | ||
6812 | }; | ||
6813 | |||
6814 | static struct snd_pci_quirk alc260_fixup_tbl[] = { | ||
6815 | SND_PCI_QUIRK(0x103c, 0x280a, "HP dc5750", PINFIX_HP_DC5750), | ||
6816 | {} | ||
6817 | }; | ||
6818 | |||
6819 | /* | ||
6643 | * ALC260 configurations | 6820 | * ALC260 configurations |
6644 | */ | 6821 | */ |
6645 | static const char *alc260_models[ALC260_MODEL_LAST] = { | 6822 | static const char *alc260_models[ALC260_MODEL_LAST] = { |
@@ -6838,6 +7015,9 @@ static int patch_alc260(struct hda_codec *codec) | |||
6838 | board_config = ALC260_AUTO; | 7015 | board_config = ALC260_AUTO; |
6839 | } | 7016 | } |
6840 | 7017 | ||
7018 | if (board_config == ALC260_AUTO) | ||
7019 | alc_pick_fixup(codec, alc260_fixup_tbl, alc260_fixups, 1); | ||
7020 | |||
6841 | if (board_config == ALC260_AUTO) { | 7021 | if (board_config == ALC260_AUTO) { |
6842 | /* automatic parse from the BIOS config */ | 7022 | /* automatic parse from the BIOS config */ |
6843 | err = alc260_parse_auto_config(codec); | 7023 | err = alc260_parse_auto_config(codec); |
@@ -6863,6 +7043,7 @@ static int patch_alc260(struct hda_codec *codec) | |||
6863 | 7043 | ||
6864 | spec->stream_analog_playback = &alc260_pcm_analog_playback; | 7044 | spec->stream_analog_playback = &alc260_pcm_analog_playback; |
6865 | spec->stream_analog_capture = &alc260_pcm_analog_capture; | 7045 | spec->stream_analog_capture = &alc260_pcm_analog_capture; |
7046 | spec->stream_analog_alt_capture = &alc260_pcm_analog_capture; | ||
6866 | 7047 | ||
6867 | spec->stream_digital_playback = &alc260_pcm_digital_playback; | 7048 | spec->stream_digital_playback = &alc260_pcm_digital_playback; |
6868 | spec->stream_digital_capture = &alc260_pcm_digital_capture; | 7049 | spec->stream_digital_capture = &alc260_pcm_digital_capture; |
@@ -6883,6 +7064,9 @@ static int patch_alc260(struct hda_codec *codec) | |||
6883 | set_capture_mixer(codec); | 7064 | set_capture_mixer(codec); |
6884 | set_beep_amp(spec, 0x07, 0x05, HDA_INPUT); | 7065 | set_beep_amp(spec, 0x07, 0x05, HDA_INPUT); |
6885 | 7066 | ||
7067 | if (board_config == ALC260_AUTO) | ||
7068 | alc_pick_fixup(codec, alc260_fixup_tbl, alc260_fixups, 0); | ||
7069 | |||
6886 | spec->vmaster_nid = 0x08; | 7070 | spec->vmaster_nid = 0x08; |
6887 | 7071 | ||
6888 | codec->patch_ops = alc_patch_ops; | 7072 | codec->patch_ops = alc_patch_ops; |
@@ -7003,7 +7187,7 @@ static struct hda_input_mux alc883_lenovo_nb0763_capture_source = { | |||
7003 | .num_items = 4, | 7187 | .num_items = 4, |
7004 | .items = { | 7188 | .items = { |
7005 | { "Mic", 0x0 }, | 7189 | { "Mic", 0x0 }, |
7006 | { "iMic", 0x1 }, | 7190 | { "Int Mic", 0x1 }, |
7007 | { "Line", 0x2 }, | 7191 | { "Line", 0x2 }, |
7008 | { "CD", 0x4 }, | 7192 | { "CD", 0x4 }, |
7009 | }, | 7193 | }, |
@@ -8573,8 +8757,8 @@ static struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = { | |||
8573 | HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), | 8757 | HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), |
8574 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | 8758 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), |
8575 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | 8759 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), |
8576 | HDA_CODEC_VOLUME("iMic Playback Volume", 0x0b, 0x1, HDA_INPUT), | 8760 | HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), |
8577 | HDA_CODEC_MUTE("iMic Playback Switch", 0x0b, 0x1, HDA_INPUT), | 8761 | HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), |
8578 | { } /* end */ | 8762 | { } /* end */ |
8579 | }; | 8763 | }; |
8580 | 8764 | ||
@@ -10265,7 +10449,8 @@ static struct alc_config_preset alc882_presets[] = { | |||
10265 | * Pin config fixes | 10449 | * Pin config fixes |
10266 | */ | 10450 | */ |
10267 | enum { | 10451 | enum { |
10268 | PINFIX_ABIT_AW9D_MAX | 10452 | PINFIX_ABIT_AW9D_MAX, |
10453 | PINFIX_PB_M5210, | ||
10269 | }; | 10454 | }; |
10270 | 10455 | ||
10271 | static struct alc_pincfg alc882_abit_aw9d_pinfix[] = { | 10456 | static struct alc_pincfg alc882_abit_aw9d_pinfix[] = { |
@@ -10275,13 +10460,22 @@ static struct alc_pincfg alc882_abit_aw9d_pinfix[] = { | |||
10275 | { } | 10460 | { } |
10276 | }; | 10461 | }; |
10277 | 10462 | ||
10463 | static const struct hda_verb pb_m5210_verbs[] = { | ||
10464 | { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 }, | ||
10465 | {} | ||
10466 | }; | ||
10467 | |||
10278 | static const struct alc_fixup alc882_fixups[] = { | 10468 | static const struct alc_fixup alc882_fixups[] = { |
10279 | [PINFIX_ABIT_AW9D_MAX] = { | 10469 | [PINFIX_ABIT_AW9D_MAX] = { |
10280 | .pins = alc882_abit_aw9d_pinfix | 10470 | .pins = alc882_abit_aw9d_pinfix |
10281 | }, | 10471 | }, |
10472 | [PINFIX_PB_M5210] = { | ||
10473 | .verbs = pb_m5210_verbs | ||
10474 | }, | ||
10282 | }; | 10475 | }; |
10283 | 10476 | ||
10284 | static struct snd_pci_quirk alc882_fixup_tbl[] = { | 10477 | static struct snd_pci_quirk alc882_fixup_tbl[] = { |
10478 | SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", PINFIX_PB_M5210), | ||
10285 | SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX), | 10479 | SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX), |
10286 | {} | 10480 | {} |
10287 | }; | 10481 | }; |
@@ -10446,7 +10640,7 @@ static int alc882_parse_auto_config(struct hda_codec *codec) | |||
10446 | { | 10640 | { |
10447 | struct alc_spec *spec = codec->spec; | 10641 | struct alc_spec *spec = codec->spec; |
10448 | static hda_nid_t alc882_ignore[] = { 0x1d, 0 }; | 10642 | static hda_nid_t alc882_ignore[] = { 0x1d, 0 }; |
10449 | int i, err; | 10643 | int err; |
10450 | 10644 | ||
10451 | err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, | 10645 | err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, |
10452 | alc882_ignore); | 10646 | alc882_ignore); |
@@ -10476,25 +10670,7 @@ static int alc882_parse_auto_config(struct hda_codec *codec) | |||
10476 | 10670 | ||
10477 | spec->multiout.max_channels = spec->multiout.num_dacs * 2; | 10671 | spec->multiout.max_channels = spec->multiout.num_dacs * 2; |
10478 | 10672 | ||
10479 | /* check multiple SPDIF-out (for recent codecs) */ | 10673 | alc_auto_parse_digital(codec); |
10480 | for (i = 0; i < spec->autocfg.dig_outs; i++) { | ||
10481 | hda_nid_t dig_nid; | ||
10482 | err = snd_hda_get_connections(codec, | ||
10483 | spec->autocfg.dig_out_pins[i], | ||
10484 | &dig_nid, 1); | ||
10485 | if (err < 0) | ||
10486 | continue; | ||
10487 | if (!i) | ||
10488 | spec->multiout.dig_out_nid = dig_nid; | ||
10489 | else { | ||
10490 | spec->multiout.slave_dig_outs = spec->slave_dig_outs; | ||
10491 | if (i >= ARRAY_SIZE(spec->slave_dig_outs) - 1) | ||
10492 | break; | ||
10493 | spec->slave_dig_outs[i - 1] = dig_nid; | ||
10494 | } | ||
10495 | } | ||
10496 | if (spec->autocfg.dig_in_pin) | ||
10497 | spec->dig_in_nid = ALC880_DIGIN_NID; | ||
10498 | 10674 | ||
10499 | if (spec->kctls.list) | 10675 | if (spec->kctls.list) |
10500 | add_mixer(spec, spec->kctls.list); | 10676 | add_mixer(spec, spec->kctls.list); |
@@ -10524,6 +10700,7 @@ static void alc882_auto_init(struct hda_codec *codec) | |||
10524 | alc882_auto_init_hp_out(codec); | 10700 | alc882_auto_init_hp_out(codec); |
10525 | alc882_auto_init_analog_input(codec); | 10701 | alc882_auto_init_analog_input(codec); |
10526 | alc882_auto_init_input_src(codec); | 10702 | alc882_auto_init_input_src(codec); |
10703 | alc_auto_init_digital(codec); | ||
10527 | if (spec->unsol_event) | 10704 | if (spec->unsol_event) |
10528 | alc_inithook(codec); | 10705 | alc_inithook(codec); |
10529 | } | 10706 | } |
@@ -12054,12 +12231,7 @@ static int alc262_parse_auto_config(struct hda_codec *codec) | |||
12054 | spec->multiout.max_channels = spec->multiout.num_dacs * 2; | 12231 | spec->multiout.max_channels = spec->multiout.num_dacs * 2; |
12055 | 12232 | ||
12056 | dig_only: | 12233 | dig_only: |
12057 | if (spec->autocfg.dig_outs) { | 12234 | alc_auto_parse_digital(codec); |
12058 | spec->multiout.dig_out_nid = ALC262_DIGOUT_NID; | ||
12059 | spec->dig_out_type = spec->autocfg.dig_out_type[0]; | ||
12060 | } | ||
12061 | if (spec->autocfg.dig_in_pin) | ||
12062 | spec->dig_in_nid = ALC262_DIGIN_NID; | ||
12063 | 12235 | ||
12064 | if (spec->kctls.list) | 12236 | if (spec->kctls.list) |
12065 | add_mixer(spec, spec->kctls.list); | 12237 | add_mixer(spec, spec->kctls.list); |
@@ -12091,6 +12263,7 @@ static void alc262_auto_init(struct hda_codec *codec) | |||
12091 | alc262_auto_init_hp_out(codec); | 12263 | alc262_auto_init_hp_out(codec); |
12092 | alc262_auto_init_analog_input(codec); | 12264 | alc262_auto_init_analog_input(codec); |
12093 | alc262_auto_init_input_src(codec); | 12265 | alc262_auto_init_input_src(codec); |
12266 | alc_auto_init_digital(codec); | ||
12094 | if (spec->unsol_event) | 12267 | if (spec->unsol_event) |
12095 | alc_inithook(codec); | 12268 | alc_inithook(codec); |
12096 | } | 12269 | } |
@@ -13024,10 +13197,14 @@ static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid, | |||
13024 | dac = 0x02; | 13197 | dac = 0x02; |
13025 | break; | 13198 | break; |
13026 | case 0x15: | 13199 | case 0x15: |
13200 | case 0x1a: /* ALC259/269 only */ | ||
13201 | case 0x1b: /* ALC259/269 only */ | ||
13027 | case 0x21: /* ALC269vb has this pin, too */ | 13202 | case 0x21: /* ALC269vb has this pin, too */ |
13028 | dac = 0x03; | 13203 | dac = 0x03; |
13029 | break; | 13204 | break; |
13030 | default: | 13205 | default: |
13206 | snd_printd(KERN_WARNING "hda_codec: " | ||
13207 | "ignoring pin 0x%x as unknown\n", nid); | ||
13031 | return 0; | 13208 | return 0; |
13032 | } | 13209 | } |
13033 | if (spec->multiout.dac_nids[0] != dac && | 13210 | if (spec->multiout.dac_nids[0] != dac && |
@@ -13078,7 +13255,7 @@ static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec, | |||
13078 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT)); | 13255 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT)); |
13079 | if (err < 0) | 13256 | if (err < 0) |
13080 | return err; | 13257 | return err; |
13081 | } else { | 13258 | } else if (nid) { |
13082 | err = alc268_new_analog_output(spec, nid, "Speaker", 0); | 13259 | err = alc268_new_analog_output(spec, nid, "Speaker", 0); |
13083 | if (err < 0) | 13260 | if (err < 0) |
13084 | return err; | 13261 | return err; |
@@ -13227,10 +13404,7 @@ static int alc268_parse_auto_config(struct hda_codec *codec) | |||
13227 | 13404 | ||
13228 | dig_only: | 13405 | dig_only: |
13229 | /* digital only support output */ | 13406 | /* digital only support output */ |
13230 | if (spec->autocfg.dig_outs) { | 13407 | alc_auto_parse_digital(codec); |
13231 | spec->multiout.dig_out_nid = ALC268_DIGOUT_NID; | ||
13232 | spec->dig_out_type = spec->autocfg.dig_out_type[0]; | ||
13233 | } | ||
13234 | if (spec->kctls.list) | 13408 | if (spec->kctls.list) |
13235 | add_mixer(spec, spec->kctls.list); | 13409 | add_mixer(spec, spec->kctls.list); |
13236 | 13410 | ||
@@ -13260,6 +13434,7 @@ static void alc268_auto_init(struct hda_codec *codec) | |||
13260 | alc268_auto_init_hp_out(codec); | 13434 | alc268_auto_init_hp_out(codec); |
13261 | alc268_auto_init_mono_speaker_out(codec); | 13435 | alc268_auto_init_mono_speaker_out(codec); |
13262 | alc268_auto_init_analog_input(codec); | 13436 | alc268_auto_init_analog_input(codec); |
13437 | alc_auto_init_digital(codec); | ||
13263 | if (spec->unsol_event) | 13438 | if (spec->unsol_event) |
13264 | alc_inithook(codec); | 13439 | alc_inithook(codec); |
13265 | } | 13440 | } |
@@ -13303,7 +13478,6 @@ static struct snd_pci_quirk alc268_cfg_tbl[] = { | |||
13303 | SND_PCI_QUIRK(0x14c0, 0x0025, "COMPAL IFL90/JFL-92", ALC268_TOSHIBA), | 13478 | SND_PCI_QUIRK(0x14c0, 0x0025, "COMPAL IFL90/JFL-92", ALC268_TOSHIBA), |
13304 | SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER), | 13479 | SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER), |
13305 | SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1), | 13480 | SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1), |
13306 | SND_PCI_QUIRK(0x1854, 0x1775, "LG R510", ALC268_DELL), | ||
13307 | {} | 13481 | {} |
13308 | }; | 13482 | }; |
13309 | 13483 | ||
@@ -13694,6 +13868,12 @@ static struct snd_kcontrol_new alc269vb_laptop_mixer[] = { | |||
13694 | { } /* end */ | 13868 | { } /* end */ |
13695 | }; | 13869 | }; |
13696 | 13870 | ||
13871 | static struct snd_kcontrol_new alc269_asus_mixer[] = { | ||
13872 | HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT), | ||
13873 | HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x0, HDA_INPUT), | ||
13874 | { } /* end */ | ||
13875 | }; | ||
13876 | |||
13697 | /* capture mixer elements */ | 13877 | /* capture mixer elements */ |
13698 | static struct snd_kcontrol_new alc269_laptop_analog_capture_mixer[] = { | 13878 | static struct snd_kcontrol_new alc269_laptop_analog_capture_mixer[] = { |
13699 | HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), | 13879 | HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), |
@@ -13914,6 +14094,20 @@ static struct hda_verb alc269vb_laptop_amic_init_verbs[] = { | |||
13914 | {} | 14094 | {} |
13915 | }; | 14095 | }; |
13916 | 14096 | ||
14097 | static struct hda_verb alc271_acer_dmic_verbs[] = { | ||
14098 | {0x20, AC_VERB_SET_COEF_INDEX, 0x0d}, | ||
14099 | {0x20, AC_VERB_SET_PROC_COEF, 0x4000}, | ||
14100 | {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
14101 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
14102 | {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
14103 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
14104 | {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
14105 | {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, | ||
14106 | {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, | ||
14107 | {0x22, AC_VERB_SET_CONNECT_SEL, 6}, | ||
14108 | { } | ||
14109 | }; | ||
14110 | |||
13917 | /* toggle speaker-output according to the hp-jack state */ | 14111 | /* toggle speaker-output according to the hp-jack state */ |
13918 | static void alc269_speaker_automute(struct hda_codec *codec) | 14112 | static void alc269_speaker_automute(struct hda_codec *codec) |
13919 | { | 14113 | { |
@@ -14152,6 +14346,36 @@ static int alc269_mic2_mute_check_ps(struct hda_codec *codec, hda_nid_t nid) | |||
14152 | } | 14346 | } |
14153 | #endif /* CONFIG_SND_HDA_POWER_SAVE */ | 14347 | #endif /* CONFIG_SND_HDA_POWER_SAVE */ |
14154 | 14348 | ||
14349 | static int alc275_setup_dual_adc(struct hda_codec *codec) | ||
14350 | { | ||
14351 | struct alc_spec *spec = codec->spec; | ||
14352 | |||
14353 | if (codec->vendor_id != 0x10ec0275 || !spec->auto_mic) | ||
14354 | return 0; | ||
14355 | if ((spec->ext_mic.pin >= 0x18 && spec->int_mic.pin <= 0x13) || | ||
14356 | (spec->ext_mic.pin <= 0x12 && spec->int_mic.pin >= 0x18)) { | ||
14357 | if (spec->ext_mic.pin <= 0x12) { | ||
14358 | spec->private_adc_nids[0] = 0x08; | ||
14359 | spec->private_adc_nids[1] = 0x11; | ||
14360 | spec->private_capsrc_nids[0] = 0x23; | ||
14361 | spec->private_capsrc_nids[1] = 0x22; | ||
14362 | } else { | ||
14363 | spec->private_adc_nids[0] = 0x11; | ||
14364 | spec->private_adc_nids[1] = 0x08; | ||
14365 | spec->private_capsrc_nids[0] = 0x22; | ||
14366 | spec->private_capsrc_nids[1] = 0x23; | ||
14367 | } | ||
14368 | spec->adc_nids = spec->private_adc_nids; | ||
14369 | spec->capsrc_nids = spec->private_capsrc_nids; | ||
14370 | spec->num_adc_nids = 2; | ||
14371 | spec->dual_adc_switch = 1; | ||
14372 | snd_printdd("realtek: enabling dual ADC switchg (%02x:%02x)\n", | ||
14373 | spec->adc_nids[0], spec->adc_nids[1]); | ||
14374 | return 1; | ||
14375 | } | ||
14376 | return 0; | ||
14377 | } | ||
14378 | |||
14155 | /* | 14379 | /* |
14156 | * BIOS auto configuration | 14380 | * BIOS auto configuration |
14157 | */ | 14381 | */ |
@@ -14175,8 +14399,7 @@ static int alc269_parse_auto_config(struct hda_codec *codec) | |||
14175 | 14399 | ||
14176 | spec->multiout.max_channels = spec->multiout.num_dacs * 2; | 14400 | spec->multiout.max_channels = spec->multiout.num_dacs * 2; |
14177 | 14401 | ||
14178 | if (spec->autocfg.dig_outs) | 14402 | alc_auto_parse_digital(codec); |
14179 | spec->multiout.dig_out_nid = ALC269_DIGOUT_NID; | ||
14180 | 14403 | ||
14181 | if (spec->kctls.list) | 14404 | if (spec->kctls.list) |
14182 | add_mixer(spec, spec->kctls.list); | 14405 | add_mixer(spec, spec->kctls.list); |
@@ -14191,13 +14414,15 @@ static int alc269_parse_auto_config(struct hda_codec *codec) | |||
14191 | 14414 | ||
14192 | spec->num_mux_defs = 1; | 14415 | spec->num_mux_defs = 1; |
14193 | spec->input_mux = &spec->private_imux[0]; | 14416 | spec->input_mux = &spec->private_imux[0]; |
14194 | fillup_priv_adc_nids(codec, alc269_adc_candidates, | 14417 | |
14195 | sizeof(alc269_adc_candidates)); | 14418 | if (!alc275_setup_dual_adc(codec)) |
14419 | fillup_priv_adc_nids(codec, alc269_adc_candidates, | ||
14420 | sizeof(alc269_adc_candidates)); | ||
14196 | 14421 | ||
14197 | /* set default input source */ | 14422 | /* set default input source */ |
14198 | snd_hda_codec_write_cache(codec, spec->capsrc_nids[0], | 14423 | if (!spec->dual_adc_switch) |
14199 | 0, AC_VERB_SET_CONNECT_SEL, | 14424 | select_or_unmute_capsrc(codec, spec->capsrc_nids[0], |
14200 | spec->input_mux->items[0].index); | 14425 | spec->input_mux->items[0].index); |
14201 | 14426 | ||
14202 | err = alc_auto_add_mic_boost(codec); | 14427 | err = alc_auto_add_mic_boost(codec); |
14203 | if (err < 0) | 14428 | if (err < 0) |
@@ -14221,6 +14446,7 @@ static void alc269_auto_init(struct hda_codec *codec) | |||
14221 | alc269_auto_init_multi_out(codec); | 14446 | alc269_auto_init_multi_out(codec); |
14222 | alc269_auto_init_hp_out(codec); | 14447 | alc269_auto_init_hp_out(codec); |
14223 | alc269_auto_init_analog_input(codec); | 14448 | alc269_auto_init_analog_input(codec); |
14449 | alc_auto_init_digital(codec); | ||
14224 | if (spec->unsol_event) | 14450 | if (spec->unsol_event) |
14225 | alc_inithook(codec); | 14451 | alc_inithook(codec); |
14226 | } | 14452 | } |
@@ -14242,6 +14468,7 @@ static const struct alc_fixup alc269_fixups[] = { | |||
14242 | 14468 | ||
14243 | static struct snd_pci_quirk alc269_fixup_tbl[] = { | 14469 | static struct snd_pci_quirk alc269_fixup_tbl[] = { |
14244 | SND_PCI_QUIRK(0x104d, 0x9071, "Sony VAIO", ALC269_FIXUP_SONY_VAIO), | 14470 | SND_PCI_QUIRK(0x104d, 0x9071, "Sony VAIO", ALC269_FIXUP_SONY_VAIO), |
14471 | SND_PCI_QUIRK(0x104d, 0x9077, "Sony VAIO", ALC269_FIXUP_SONY_VAIO), | ||
14245 | {} | 14472 | {} |
14246 | }; | 14473 | }; |
14247 | 14474 | ||
@@ -14261,6 +14488,7 @@ static const char *alc269_models[ALC269_MODEL_LAST] = { | |||
14261 | 14488 | ||
14262 | static struct snd_pci_quirk alc269_cfg_tbl[] = { | 14489 | static struct snd_pci_quirk alc269_cfg_tbl[] = { |
14263 | SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_QUANTA_FL1), | 14490 | SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_QUANTA_FL1), |
14491 | SND_PCI_QUIRK(0x1025, 0x047c, "ACER ZGA", ALC271_ACER), | ||
14264 | SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A", | 14492 | SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A", |
14265 | ALC269_AMIC), | 14493 | ALC269_AMIC), |
14266 | SND_PCI_QUIRK(0x1043, 0x1013, "ASUS N61Da", ALC269VB_AMIC), | 14494 | SND_PCI_QUIRK(0x1043, 0x1013, "ASUS N61Da", ALC269VB_AMIC), |
@@ -14422,6 +14650,23 @@ static struct alc_config_preset alc269_presets[] = { | |||
14422 | .unsol_event = alc269_lifebook_unsol_event, | 14650 | .unsol_event = alc269_lifebook_unsol_event, |
14423 | .init_hook = alc269_lifebook_init_hook, | 14651 | .init_hook = alc269_lifebook_init_hook, |
14424 | }, | 14652 | }, |
14653 | [ALC271_ACER] = { | ||
14654 | .mixers = { alc269_asus_mixer }, | ||
14655 | .cap_mixer = alc269vb_laptop_digital_capture_mixer, | ||
14656 | .init_verbs = { alc269_init_verbs, alc271_acer_dmic_verbs }, | ||
14657 | .num_dacs = ARRAY_SIZE(alc269_dac_nids), | ||
14658 | .dac_nids = alc269_dac_nids, | ||
14659 | .adc_nids = alc262_dmic_adc_nids, | ||
14660 | .num_adc_nids = ARRAY_SIZE(alc262_dmic_adc_nids), | ||
14661 | .capsrc_nids = alc262_dmic_capsrc_nids, | ||
14662 | .num_channel_mode = ARRAY_SIZE(alc269_modes), | ||
14663 | .channel_mode = alc269_modes, | ||
14664 | .input_mux = &alc269_capture_source, | ||
14665 | .dig_out_nid = ALC880_DIGOUT_NID, | ||
14666 | .unsol_event = alc_sku_unsol_event, | ||
14667 | .setup = alc269vb_laptop_dmic_setup, | ||
14668 | .init_hook = alc_inithook, | ||
14669 | }, | ||
14425 | }; | 14670 | }; |
14426 | 14671 | ||
14427 | static int patch_alc269(struct hda_codec *codec) | 14672 | static int patch_alc269(struct hda_codec *codec) |
@@ -14493,6 +14738,10 @@ static int patch_alc269(struct hda_codec *codec) | |||
14493 | */ | 14738 | */ |
14494 | spec->stream_analog_playback = &alc269_44k_pcm_analog_playback; | 14739 | spec->stream_analog_playback = &alc269_44k_pcm_analog_playback; |
14495 | spec->stream_analog_capture = &alc269_44k_pcm_analog_capture; | 14740 | spec->stream_analog_capture = &alc269_44k_pcm_analog_capture; |
14741 | } else if (spec->dual_adc_switch) { | ||
14742 | spec->stream_analog_playback = &alc269_pcm_analog_playback; | ||
14743 | /* switch ADC dynamically */ | ||
14744 | spec->stream_analog_capture = &dualmic_pcm_analog_capture; | ||
14496 | } else { | 14745 | } else { |
14497 | spec->stream_analog_playback = &alc269_pcm_analog_playback; | 14746 | spec->stream_analog_playback = &alc269_pcm_analog_playback; |
14498 | spec->stream_analog_capture = &alc269_pcm_analog_capture; | 14747 | spec->stream_analog_capture = &alc269_pcm_analog_capture; |
@@ -15378,8 +15627,7 @@ static int alc861_parse_auto_config(struct hda_codec *codec) | |||
15378 | 15627 | ||
15379 | spec->multiout.max_channels = spec->multiout.num_dacs * 2; | 15628 | spec->multiout.max_channels = spec->multiout.num_dacs * 2; |
15380 | 15629 | ||
15381 | if (spec->autocfg.dig_outs) | 15630 | alc_auto_parse_digital(codec); |
15382 | spec->multiout.dig_out_nid = ALC861_DIGOUT_NID; | ||
15383 | 15631 | ||
15384 | if (spec->kctls.list) | 15632 | if (spec->kctls.list) |
15385 | add_mixer(spec, spec->kctls.list); | 15633 | add_mixer(spec, spec->kctls.list); |
@@ -15405,6 +15653,7 @@ static void alc861_auto_init(struct hda_codec *codec) | |||
15405 | alc861_auto_init_multi_out(codec); | 15653 | alc861_auto_init_multi_out(codec); |
15406 | alc861_auto_init_hp_out(codec); | 15654 | alc861_auto_init_hp_out(codec); |
15407 | alc861_auto_init_analog_input(codec); | 15655 | alc861_auto_init_analog_input(codec); |
15656 | alc_auto_init_digital(codec); | ||
15408 | if (spec->unsol_event) | 15657 | if (spec->unsol_event) |
15409 | alc_inithook(codec); | 15658 | alc_inithook(codec); |
15410 | } | 15659 | } |
@@ -16509,8 +16758,7 @@ static int alc861vd_parse_auto_config(struct hda_codec *codec) | |||
16509 | 16758 | ||
16510 | spec->multiout.max_channels = spec->multiout.num_dacs * 2; | 16759 | spec->multiout.max_channels = spec->multiout.num_dacs * 2; |
16511 | 16760 | ||
16512 | if (spec->autocfg.dig_outs) | 16761 | alc_auto_parse_digital(codec); |
16513 | spec->multiout.dig_out_nid = ALC861VD_DIGOUT_NID; | ||
16514 | 16762 | ||
16515 | if (spec->kctls.list) | 16763 | if (spec->kctls.list) |
16516 | add_mixer(spec, spec->kctls.list); | 16764 | add_mixer(spec, spec->kctls.list); |
@@ -16537,6 +16785,7 @@ static void alc861vd_auto_init(struct hda_codec *codec) | |||
16537 | alc861vd_auto_init_hp_out(codec); | 16785 | alc861vd_auto_init_hp_out(codec); |
16538 | alc861vd_auto_init_analog_input(codec); | 16786 | alc861vd_auto_init_analog_input(codec); |
16539 | alc861vd_auto_init_input_src(codec); | 16787 | alc861vd_auto_init_input_src(codec); |
16788 | alc_auto_init_digital(codec); | ||
16540 | if (spec->unsol_event) | 16789 | if (spec->unsol_event) |
16541 | alc_inithook(codec); | 16790 | alc_inithook(codec); |
16542 | } | 16791 | } |
@@ -18520,7 +18769,7 @@ static void alc662_auto_set_output_and_unmute(struct hda_codec *codec, | |||
18520 | hda_nid_t dac) | 18769 | hda_nid_t dac) |
18521 | { | 18770 | { |
18522 | int i, num; | 18771 | int i, num; |
18523 | hda_nid_t srcs[4]; | 18772 | hda_nid_t srcs[HDA_MAX_CONNECTIONS]; |
18524 | 18773 | ||
18525 | alc_set_pin_output(codec, nid, pin_type); | 18774 | alc_set_pin_output(codec, nid, pin_type); |
18526 | /* need the manual connection? */ | 18775 | /* need the manual connection? */ |
@@ -18624,8 +18873,7 @@ static int alc662_parse_auto_config(struct hda_codec *codec) | |||
18624 | 18873 | ||
18625 | spec->multiout.max_channels = spec->multiout.num_dacs * 2; | 18874 | spec->multiout.max_channels = spec->multiout.num_dacs * 2; |
18626 | 18875 | ||
18627 | if (spec->autocfg.dig_outs) | 18876 | alc_auto_parse_digital(codec); |
18628 | spec->multiout.dig_out_nid = ALC880_DIGOUT_NID; | ||
18629 | 18877 | ||
18630 | if (spec->kctls.list) | 18878 | if (spec->kctls.list) |
18631 | add_mixer(spec, spec->kctls.list); | 18879 | add_mixer(spec, spec->kctls.list); |
@@ -18635,7 +18883,7 @@ static int alc662_parse_auto_config(struct hda_codec *codec) | |||
18635 | 18883 | ||
18636 | add_verb(spec, alc662_init_verbs); | 18884 | add_verb(spec, alc662_init_verbs); |
18637 | if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 || | 18885 | if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 || |
18638 | codec->vendor_id == 0x10ec0665) | 18886 | codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670) |
18639 | add_verb(spec, alc663_init_verbs); | 18887 | add_verb(spec, alc663_init_verbs); |
18640 | 18888 | ||
18641 | if (codec->vendor_id == 0x10ec0272) | 18889 | if (codec->vendor_id == 0x10ec0272) |
@@ -18662,6 +18910,7 @@ static void alc662_auto_init(struct hda_codec *codec) | |||
18662 | alc662_auto_init_hp_out(codec); | 18910 | alc662_auto_init_hp_out(codec); |
18663 | alc662_auto_init_analog_input(codec); | 18911 | alc662_auto_init_analog_input(codec); |
18664 | alc662_auto_init_input_src(codec); | 18912 | alc662_auto_init_input_src(codec); |
18913 | alc_auto_init_digital(codec); | ||
18665 | if (spec->unsol_event) | 18914 | if (spec->unsol_event) |
18666 | alc_inithook(codec); | 18915 | alc_inithook(codec); |
18667 | } | 18916 | } |
@@ -18781,6 +19030,445 @@ static int patch_alc888(struct hda_codec *codec) | |||
18781 | } | 19030 | } |
18782 | 19031 | ||
18783 | /* | 19032 | /* |
19033 | * ALC680 support | ||
19034 | */ | ||
19035 | #define ALC680_DIGIN_NID ALC880_DIGIN_NID | ||
19036 | #define ALC680_DIGOUT_NID ALC880_DIGOUT_NID | ||
19037 | #define alc680_modes alc260_modes | ||
19038 | |||
19039 | static hda_nid_t alc680_dac_nids[3] = { | ||
19040 | /* Lout1, Lout2, hp */ | ||
19041 | 0x02, 0x03, 0x04 | ||
19042 | }; | ||
19043 | |||
19044 | static hda_nid_t alc680_adc_nids[3] = { | ||
19045 | /* ADC0-2 */ | ||
19046 | /* DMIC, MIC, Line-in*/ | ||
19047 | 0x07, 0x08, 0x09 | ||
19048 | }; | ||
19049 | |||
19050 | /* | ||
19051 | * Analog capture ADC cgange | ||
19052 | */ | ||
19053 | static int alc680_capture_pcm_prepare(struct hda_pcm_stream *hinfo, | ||
19054 | struct hda_codec *codec, | ||
19055 | unsigned int stream_tag, | ||
19056 | unsigned int format, | ||
19057 | struct snd_pcm_substream *substream) | ||
19058 | { | ||
19059 | struct alc_spec *spec = codec->spec; | ||
19060 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
19061 | unsigned int pre_mic, pre_line; | ||
19062 | |||
19063 | pre_mic = snd_hda_jack_detect(codec, cfg->input_pins[AUTO_PIN_MIC]); | ||
19064 | pre_line = snd_hda_jack_detect(codec, cfg->input_pins[AUTO_PIN_LINE]); | ||
19065 | |||
19066 | spec->cur_adc_stream_tag = stream_tag; | ||
19067 | spec->cur_adc_format = format; | ||
19068 | |||
19069 | if (pre_mic || pre_line) { | ||
19070 | if (pre_mic) | ||
19071 | snd_hda_codec_setup_stream(codec, 0x08, stream_tag, 0, | ||
19072 | format); | ||
19073 | else | ||
19074 | snd_hda_codec_setup_stream(codec, 0x09, stream_tag, 0, | ||
19075 | format); | ||
19076 | } else | ||
19077 | snd_hda_codec_setup_stream(codec, 0x07, stream_tag, 0, format); | ||
19078 | return 0; | ||
19079 | } | ||
19080 | |||
19081 | static int alc680_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, | ||
19082 | struct hda_codec *codec, | ||
19083 | struct snd_pcm_substream *substream) | ||
19084 | { | ||
19085 | snd_hda_codec_cleanup_stream(codec, 0x07); | ||
19086 | snd_hda_codec_cleanup_stream(codec, 0x08); | ||
19087 | snd_hda_codec_cleanup_stream(codec, 0x09); | ||
19088 | return 0; | ||
19089 | } | ||
19090 | |||
19091 | static struct hda_pcm_stream alc680_pcm_analog_auto_capture = { | ||
19092 | .substreams = 1, /* can be overridden */ | ||
19093 | .channels_min = 2, | ||
19094 | .channels_max = 2, | ||
19095 | /* NID is set in alc_build_pcms */ | ||
19096 | .ops = { | ||
19097 | .prepare = alc680_capture_pcm_prepare, | ||
19098 | .cleanup = alc680_capture_pcm_cleanup | ||
19099 | }, | ||
19100 | }; | ||
19101 | |||
19102 | static struct snd_kcontrol_new alc680_base_mixer[] = { | ||
19103 | /* output mixer control */ | ||
19104 | HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT), | ||
19105 | HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), | ||
19106 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x4, 0x0, HDA_OUTPUT), | ||
19107 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x16, 0x0, HDA_OUTPUT), | ||
19108 | HDA_CODEC_VOLUME("Int Mic Boost", 0x12, 0, HDA_INPUT), | ||
19109 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), | ||
19110 | HDA_CODEC_VOLUME("Line In Boost", 0x19, 0, HDA_INPUT), | ||
19111 | { } | ||
19112 | }; | ||
19113 | |||
19114 | static struct hda_bind_ctls alc680_bind_cap_vol = { | ||
19115 | .ops = &snd_hda_bind_vol, | ||
19116 | .values = { | ||
19117 | HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT), | ||
19118 | HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT), | ||
19119 | HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT), | ||
19120 | 0 | ||
19121 | }, | ||
19122 | }; | ||
19123 | |||
19124 | static struct hda_bind_ctls alc680_bind_cap_switch = { | ||
19125 | .ops = &snd_hda_bind_sw, | ||
19126 | .values = { | ||
19127 | HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT), | ||
19128 | HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT), | ||
19129 | HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT), | ||
19130 | 0 | ||
19131 | }, | ||
19132 | }; | ||
19133 | |||
19134 | static struct snd_kcontrol_new alc680_master_capture_mixer[] = { | ||
19135 | HDA_BIND_VOL("Capture Volume", &alc680_bind_cap_vol), | ||
19136 | HDA_BIND_SW("Capture Switch", &alc680_bind_cap_switch), | ||
19137 | { } /* end */ | ||
19138 | }; | ||
19139 | |||
19140 | /* | ||
19141 | * generic initialization of ADC, input mixers and output mixers | ||
19142 | */ | ||
19143 | static struct hda_verb alc680_init_verbs[] = { | ||
19144 | {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
19145 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
19146 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
19147 | |||
19148 | {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
19149 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
19150 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
19151 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
19152 | {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
19153 | {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
19154 | |||
19155 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
19156 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
19157 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
19158 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
19159 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
19160 | |||
19161 | {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, | ||
19162 | {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, | ||
19163 | |||
19164 | { } | ||
19165 | }; | ||
19166 | |||
19167 | /* toggle speaker-output according to the hp-jack state */ | ||
19168 | static void alc680_base_setup(struct hda_codec *codec) | ||
19169 | { | ||
19170 | struct alc_spec *spec = codec->spec; | ||
19171 | |||
19172 | spec->autocfg.hp_pins[0] = 0x16; | ||
19173 | spec->autocfg.speaker_pins[0] = 0x14; | ||
19174 | spec->autocfg.speaker_pins[1] = 0x15; | ||
19175 | spec->autocfg.input_pins[AUTO_PIN_MIC] = 0x18; | ||
19176 | spec->autocfg.input_pins[AUTO_PIN_LINE] = 0x19; | ||
19177 | } | ||
19178 | |||
19179 | static void alc680_rec_autoswitch(struct hda_codec *codec) | ||
19180 | { | ||
19181 | struct alc_spec *spec = codec->spec; | ||
19182 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
19183 | unsigned int present; | ||
19184 | hda_nid_t new_adc; | ||
19185 | |||
19186 | present = snd_hda_jack_detect(codec, cfg->input_pins[AUTO_PIN_MIC]); | ||
19187 | |||
19188 | new_adc = present ? 0x8 : 0x7; | ||
19189 | __snd_hda_codec_cleanup_stream(codec, !present ? 0x8 : 0x7, 1); | ||
19190 | snd_hda_codec_setup_stream(codec, new_adc, | ||
19191 | spec->cur_adc_stream_tag, 0, | ||
19192 | spec->cur_adc_format); | ||
19193 | |||
19194 | } | ||
19195 | |||
19196 | static void alc680_unsol_event(struct hda_codec *codec, | ||
19197 | unsigned int res) | ||
19198 | { | ||
19199 | if ((res >> 26) == ALC880_HP_EVENT) | ||
19200 | alc_automute_amp(codec); | ||
19201 | if ((res >> 26) == ALC880_MIC_EVENT) | ||
19202 | alc680_rec_autoswitch(codec); | ||
19203 | } | ||
19204 | |||
19205 | static void alc680_inithook(struct hda_codec *codec) | ||
19206 | { | ||
19207 | alc_automute_amp(codec); | ||
19208 | alc680_rec_autoswitch(codec); | ||
19209 | } | ||
19210 | |||
19211 | /* create input playback/capture controls for the given pin */ | ||
19212 | static int alc680_new_analog_output(struct alc_spec *spec, hda_nid_t nid, | ||
19213 | const char *ctlname, int idx) | ||
19214 | { | ||
19215 | hda_nid_t dac; | ||
19216 | int err; | ||
19217 | |||
19218 | switch (nid) { | ||
19219 | case 0x14: | ||
19220 | dac = 0x02; | ||
19221 | break; | ||
19222 | case 0x15: | ||
19223 | dac = 0x03; | ||
19224 | break; | ||
19225 | case 0x16: | ||
19226 | dac = 0x04; | ||
19227 | break; | ||
19228 | default: | ||
19229 | return 0; | ||
19230 | } | ||
19231 | if (spec->multiout.dac_nids[0] != dac && | ||
19232 | spec->multiout.dac_nids[1] != dac) { | ||
19233 | err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname, | ||
19234 | HDA_COMPOSE_AMP_VAL(dac, 3, idx, | ||
19235 | HDA_OUTPUT)); | ||
19236 | if (err < 0) | ||
19237 | return err; | ||
19238 | |||
19239 | err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname, | ||
19240 | HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT)); | ||
19241 | |||
19242 | if (err < 0) | ||
19243 | return err; | ||
19244 | spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac; | ||
19245 | } | ||
19246 | |||
19247 | return 0; | ||
19248 | } | ||
19249 | |||
19250 | /* add playback controls from the parsed DAC table */ | ||
19251 | static int alc680_auto_create_multi_out_ctls(struct alc_spec *spec, | ||
19252 | const struct auto_pin_cfg *cfg) | ||
19253 | { | ||
19254 | hda_nid_t nid; | ||
19255 | int err; | ||
19256 | |||
19257 | spec->multiout.dac_nids = spec->private_dac_nids; | ||
19258 | |||
19259 | nid = cfg->line_out_pins[0]; | ||
19260 | if (nid) { | ||
19261 | const char *name; | ||
19262 | if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) | ||
19263 | name = "Speaker"; | ||
19264 | else | ||
19265 | name = "Front"; | ||
19266 | err = alc680_new_analog_output(spec, nid, name, 0); | ||
19267 | if (err < 0) | ||
19268 | return err; | ||
19269 | } | ||
19270 | |||
19271 | nid = cfg->speaker_pins[0]; | ||
19272 | if (nid) { | ||
19273 | err = alc680_new_analog_output(spec, nid, "Speaker", 0); | ||
19274 | if (err < 0) | ||
19275 | return err; | ||
19276 | } | ||
19277 | nid = cfg->hp_pins[0]; | ||
19278 | if (nid) { | ||
19279 | err = alc680_new_analog_output(spec, nid, "Headphone", 0); | ||
19280 | if (err < 0) | ||
19281 | return err; | ||
19282 | } | ||
19283 | |||
19284 | return 0; | ||
19285 | } | ||
19286 | |||
19287 | static void alc680_auto_set_output_and_unmute(struct hda_codec *codec, | ||
19288 | hda_nid_t nid, int pin_type) | ||
19289 | { | ||
19290 | alc_set_pin_output(codec, nid, pin_type); | ||
19291 | } | ||
19292 | |||
19293 | static void alc680_auto_init_multi_out(struct hda_codec *codec) | ||
19294 | { | ||
19295 | struct alc_spec *spec = codec->spec; | ||
19296 | hda_nid_t nid = spec->autocfg.line_out_pins[0]; | ||
19297 | if (nid) { | ||
19298 | int pin_type = get_pin_type(spec->autocfg.line_out_type); | ||
19299 | alc680_auto_set_output_and_unmute(codec, nid, pin_type); | ||
19300 | } | ||
19301 | } | ||
19302 | |||
19303 | static void alc680_auto_init_hp_out(struct hda_codec *codec) | ||
19304 | { | ||
19305 | struct alc_spec *spec = codec->spec; | ||
19306 | hda_nid_t pin; | ||
19307 | |||
19308 | pin = spec->autocfg.hp_pins[0]; | ||
19309 | if (pin) | ||
19310 | alc680_auto_set_output_and_unmute(codec, pin, PIN_HP); | ||
19311 | pin = spec->autocfg.speaker_pins[0]; | ||
19312 | if (pin) | ||
19313 | alc680_auto_set_output_and_unmute(codec, pin, PIN_OUT); | ||
19314 | } | ||
19315 | |||
19316 | /* pcm configuration: identical with ALC880 */ | ||
19317 | #define alc680_pcm_analog_playback alc880_pcm_analog_playback | ||
19318 | #define alc680_pcm_analog_capture alc880_pcm_analog_capture | ||
19319 | #define alc680_pcm_analog_alt_capture alc880_pcm_analog_alt_capture | ||
19320 | #define alc680_pcm_digital_playback alc880_pcm_digital_playback | ||
19321 | #define alc680_pcm_digital_capture alc880_pcm_digital_capture | ||
19322 | |||
19323 | /* | ||
19324 | * BIOS auto configuration | ||
19325 | */ | ||
19326 | static int alc680_parse_auto_config(struct hda_codec *codec) | ||
19327 | { | ||
19328 | struct alc_spec *spec = codec->spec; | ||
19329 | int err; | ||
19330 | static hda_nid_t alc680_ignore[] = { 0 }; | ||
19331 | |||
19332 | err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, | ||
19333 | alc680_ignore); | ||
19334 | if (err < 0) | ||
19335 | return err; | ||
19336 | |||
19337 | if (!spec->autocfg.line_outs) { | ||
19338 | if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) { | ||
19339 | spec->multiout.max_channels = 2; | ||
19340 | spec->no_analog = 1; | ||
19341 | goto dig_only; | ||
19342 | } | ||
19343 | return 0; /* can't find valid BIOS pin config */ | ||
19344 | } | ||
19345 | err = alc680_auto_create_multi_out_ctls(spec, &spec->autocfg); | ||
19346 | if (err < 0) | ||
19347 | return err; | ||
19348 | |||
19349 | spec->multiout.max_channels = 2; | ||
19350 | |||
19351 | dig_only: | ||
19352 | /* digital only support output */ | ||
19353 | alc_auto_parse_digital(codec); | ||
19354 | if (spec->kctls.list) | ||
19355 | add_mixer(spec, spec->kctls.list); | ||
19356 | |||
19357 | add_verb(spec, alc680_init_verbs); | ||
19358 | |||
19359 | err = alc_auto_add_mic_boost(codec); | ||
19360 | if (err < 0) | ||
19361 | return err; | ||
19362 | |||
19363 | return 1; | ||
19364 | } | ||
19365 | |||
19366 | #define alc680_auto_init_analog_input alc882_auto_init_analog_input | ||
19367 | |||
19368 | /* init callback for auto-configuration model -- overriding the default init */ | ||
19369 | static void alc680_auto_init(struct hda_codec *codec) | ||
19370 | { | ||
19371 | struct alc_spec *spec = codec->spec; | ||
19372 | alc680_auto_init_multi_out(codec); | ||
19373 | alc680_auto_init_hp_out(codec); | ||
19374 | alc680_auto_init_analog_input(codec); | ||
19375 | alc_auto_init_digital(codec); | ||
19376 | if (spec->unsol_event) | ||
19377 | alc_inithook(codec); | ||
19378 | } | ||
19379 | |||
19380 | /* | ||
19381 | * configuration and preset | ||
19382 | */ | ||
19383 | static const char *alc680_models[ALC680_MODEL_LAST] = { | ||
19384 | [ALC680_BASE] = "base", | ||
19385 | [ALC680_AUTO] = "auto", | ||
19386 | }; | ||
19387 | |||
19388 | static struct snd_pci_quirk alc680_cfg_tbl[] = { | ||
19389 | SND_PCI_QUIRK(0x1043, 0x12f3, "ASUS NX90", ALC680_BASE), | ||
19390 | {} | ||
19391 | }; | ||
19392 | |||
19393 | static struct alc_config_preset alc680_presets[] = { | ||
19394 | [ALC680_BASE] = { | ||
19395 | .mixers = { alc680_base_mixer }, | ||
19396 | .cap_mixer = alc680_master_capture_mixer, | ||
19397 | .init_verbs = { alc680_init_verbs }, | ||
19398 | .num_dacs = ARRAY_SIZE(alc680_dac_nids), | ||
19399 | .dac_nids = alc680_dac_nids, | ||
19400 | .dig_out_nid = ALC680_DIGOUT_NID, | ||
19401 | .num_channel_mode = ARRAY_SIZE(alc680_modes), | ||
19402 | .channel_mode = alc680_modes, | ||
19403 | .unsol_event = alc680_unsol_event, | ||
19404 | .setup = alc680_base_setup, | ||
19405 | .init_hook = alc680_inithook, | ||
19406 | |||
19407 | }, | ||
19408 | }; | ||
19409 | |||
19410 | static int patch_alc680(struct hda_codec *codec) | ||
19411 | { | ||
19412 | struct alc_spec *spec; | ||
19413 | int board_config; | ||
19414 | int err; | ||
19415 | |||
19416 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
19417 | if (spec == NULL) | ||
19418 | return -ENOMEM; | ||
19419 | |||
19420 | codec->spec = spec; | ||
19421 | |||
19422 | board_config = snd_hda_check_board_config(codec, ALC680_MODEL_LAST, | ||
19423 | alc680_models, | ||
19424 | alc680_cfg_tbl); | ||
19425 | |||
19426 | if (board_config < 0 || board_config >= ALC680_MODEL_LAST) { | ||
19427 | printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", | ||
19428 | codec->chip_name); | ||
19429 | board_config = ALC680_AUTO; | ||
19430 | } | ||
19431 | |||
19432 | if (board_config == ALC680_AUTO) { | ||
19433 | /* automatic parse from the BIOS config */ | ||
19434 | err = alc680_parse_auto_config(codec); | ||
19435 | if (err < 0) { | ||
19436 | alc_free(codec); | ||
19437 | return err; | ||
19438 | } else if (!err) { | ||
19439 | printk(KERN_INFO | ||
19440 | "hda_codec: Cannot set up configuration " | ||
19441 | "from BIOS. Using base mode...\n"); | ||
19442 | board_config = ALC680_BASE; | ||
19443 | } | ||
19444 | } | ||
19445 | |||
19446 | if (board_config != ALC680_AUTO) | ||
19447 | setup_preset(codec, &alc680_presets[board_config]); | ||
19448 | |||
19449 | spec->stream_analog_playback = &alc680_pcm_analog_playback; | ||
19450 | spec->stream_analog_capture = &alc680_pcm_analog_auto_capture; | ||
19451 | spec->stream_digital_playback = &alc680_pcm_digital_playback; | ||
19452 | spec->stream_digital_capture = &alc680_pcm_digital_capture; | ||
19453 | |||
19454 | if (!spec->adc_nids) { | ||
19455 | spec->adc_nids = alc680_adc_nids; | ||
19456 | spec->num_adc_nids = ARRAY_SIZE(alc680_adc_nids); | ||
19457 | } | ||
19458 | |||
19459 | if (!spec->cap_mixer) | ||
19460 | set_capture_mixer(codec); | ||
19461 | |||
19462 | spec->vmaster_nid = 0x02; | ||
19463 | |||
19464 | codec->patch_ops = alc_patch_ops; | ||
19465 | if (board_config == ALC680_AUTO) | ||
19466 | spec->init_hook = alc680_auto_init; | ||
19467 | |||
19468 | return 0; | ||
19469 | } | ||
19470 | |||
19471 | /* | ||
18784 | * patch entries | 19472 | * patch entries |
18785 | */ | 19473 | */ |
18786 | static struct hda_codec_preset snd_hda_preset_realtek[] = { | 19474 | static struct hda_codec_preset snd_hda_preset_realtek[] = { |
@@ -18804,6 +19492,7 @@ static struct hda_codec_preset snd_hda_preset_realtek[] = { | |||
18804 | { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 }, | 19492 | { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 }, |
18805 | { .id = 0x10ec0665, .name = "ALC665", .patch = patch_alc662 }, | 19493 | { .id = 0x10ec0665, .name = "ALC665", .patch = patch_alc662 }, |
18806 | { .id = 0x10ec0670, .name = "ALC670", .patch = patch_alc662 }, | 19494 | { .id = 0x10ec0670, .name = "ALC670", .patch = patch_alc662 }, |
19495 | { .id = 0x10ec0680, .name = "ALC680", .patch = patch_alc680 }, | ||
18807 | { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 }, | 19496 | { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 }, |
18808 | { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 }, | 19497 | { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 }, |
18809 | { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc882 }, | 19498 | { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc882 }, |
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index f1e7babd6920..95148e58026c 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c | |||
@@ -94,6 +94,7 @@ enum { | |||
94 | STAC_92HD83XXX_PWR_REF, | 94 | STAC_92HD83XXX_PWR_REF, |
95 | STAC_DELL_S14, | 95 | STAC_DELL_S14, |
96 | STAC_92HD83XXX_HP, | 96 | STAC_92HD83XXX_HP, |
97 | STAC_HP_DV7_4000, | ||
97 | STAC_92HD83XXX_MODELS | 98 | STAC_92HD83XXX_MODELS |
98 | }; | 99 | }; |
99 | 100 | ||
@@ -202,6 +203,7 @@ struct sigmatel_spec { | |||
202 | unsigned int spdif_mute: 1; | 203 | unsigned int spdif_mute: 1; |
203 | unsigned int check_volume_offset:1; | 204 | unsigned int check_volume_offset:1; |
204 | unsigned int auto_mic:1; | 205 | unsigned int auto_mic:1; |
206 | unsigned int linear_tone_beep:1; | ||
205 | 207 | ||
206 | /* gpio lines */ | 208 | /* gpio lines */ |
207 | unsigned int eapd_mask; | 209 | unsigned int eapd_mask; |
@@ -1631,10 +1633,17 @@ static unsigned int dell_s14_pin_configs[10] = { | |||
1631 | 0x40f000f0, 0x40f000f0, | 1633 | 0x40f000f0, 0x40f000f0, |
1632 | }; | 1634 | }; |
1633 | 1635 | ||
1636 | static unsigned int hp_dv7_4000_pin_configs[10] = { | ||
1637 | 0x03a12050, 0x0321201f, 0x40f000f0, 0x90170110, | ||
1638 | 0x40f000f0, 0x40f000f0, 0x90170110, 0xd5a30140, | ||
1639 | 0x40f000f0, 0x40f000f0, | ||
1640 | }; | ||
1641 | |||
1634 | static unsigned int *stac92hd83xxx_brd_tbl[STAC_92HD83XXX_MODELS] = { | 1642 | static unsigned int *stac92hd83xxx_brd_tbl[STAC_92HD83XXX_MODELS] = { |
1635 | [STAC_92HD83XXX_REF] = ref92hd83xxx_pin_configs, | 1643 | [STAC_92HD83XXX_REF] = ref92hd83xxx_pin_configs, |
1636 | [STAC_92HD83XXX_PWR_REF] = ref92hd83xxx_pin_configs, | 1644 | [STAC_92HD83XXX_PWR_REF] = ref92hd83xxx_pin_configs, |
1637 | [STAC_DELL_S14] = dell_s14_pin_configs, | 1645 | [STAC_DELL_S14] = dell_s14_pin_configs, |
1646 | [STAC_HP_DV7_4000] = hp_dv7_4000_pin_configs, | ||
1638 | }; | 1647 | }; |
1639 | 1648 | ||
1640 | static const char *stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = { | 1649 | static const char *stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = { |
@@ -1643,6 +1652,7 @@ static const char *stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = { | |||
1643 | [STAC_92HD83XXX_PWR_REF] = "mic-ref", | 1652 | [STAC_92HD83XXX_PWR_REF] = "mic-ref", |
1644 | [STAC_DELL_S14] = "dell-s14", | 1653 | [STAC_DELL_S14] = "dell-s14", |
1645 | [STAC_92HD83XXX_HP] = "hp", | 1654 | [STAC_92HD83XXX_HP] = "hp", |
1655 | [STAC_HP_DV7_4000] = "hp-dv7-4000", | ||
1646 | }; | 1656 | }; |
1647 | 1657 | ||
1648 | static struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = { | 1658 | static struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = { |
@@ -3802,7 +3812,7 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out | |||
3802 | return err; | 3812 | return err; |
3803 | if (codec->beep) { | 3813 | if (codec->beep) { |
3804 | /* IDT/STAC codecs have linear beep tone parameter */ | 3814 | /* IDT/STAC codecs have linear beep tone parameter */ |
3805 | codec->beep->linear_tone = 1; | 3815 | codec->beep->linear_tone = spec->linear_tone_beep; |
3806 | /* if no beep switch is available, make its own one */ | 3816 | /* if no beep switch is available, make its own one */ |
3807 | caps = query_amp_caps(codec, nid, HDA_OUTPUT); | 3817 | caps = query_amp_caps(codec, nid, HDA_OUTPUT); |
3808 | if (!(caps & AC_AMPCAP_MUTE)) { | 3818 | if (!(caps & AC_AMPCAP_MUTE)) { |
@@ -5005,6 +5015,7 @@ static int patch_stac9200(struct hda_codec *codec) | |||
5005 | 5015 | ||
5006 | codec->no_trigger_sense = 1; | 5016 | codec->no_trigger_sense = 1; |
5007 | codec->spec = spec; | 5017 | codec->spec = spec; |
5018 | spec->linear_tone_beep = 1; | ||
5008 | spec->num_pins = ARRAY_SIZE(stac9200_pin_nids); | 5019 | spec->num_pins = ARRAY_SIZE(stac9200_pin_nids); |
5009 | spec->pin_nids = stac9200_pin_nids; | 5020 | spec->pin_nids = stac9200_pin_nids; |
5010 | spec->board_config = snd_hda_check_board_config(codec, STAC_9200_MODELS, | 5021 | spec->board_config = snd_hda_check_board_config(codec, STAC_9200_MODELS, |
@@ -5068,6 +5079,7 @@ static int patch_stac925x(struct hda_codec *codec) | |||
5068 | 5079 | ||
5069 | codec->no_trigger_sense = 1; | 5080 | codec->no_trigger_sense = 1; |
5070 | codec->spec = spec; | 5081 | codec->spec = spec; |
5082 | spec->linear_tone_beep = 1; | ||
5071 | spec->num_pins = ARRAY_SIZE(stac925x_pin_nids); | 5083 | spec->num_pins = ARRAY_SIZE(stac925x_pin_nids); |
5072 | spec->pin_nids = stac925x_pin_nids; | 5084 | spec->pin_nids = stac925x_pin_nids; |
5073 | 5085 | ||
@@ -5153,6 +5165,7 @@ static int patch_stac92hd73xx(struct hda_codec *codec) | |||
5153 | 5165 | ||
5154 | codec->no_trigger_sense = 1; | 5166 | codec->no_trigger_sense = 1; |
5155 | codec->spec = spec; | 5167 | codec->spec = spec; |
5168 | spec->linear_tone_beep = 0; | ||
5156 | codec->slave_dig_outs = stac92hd73xx_slave_dig_outs; | 5169 | codec->slave_dig_outs = stac92hd73xx_slave_dig_outs; |
5157 | spec->num_pins = ARRAY_SIZE(stac92hd73xx_pin_nids); | 5170 | spec->num_pins = ARRAY_SIZE(stac92hd73xx_pin_nids); |
5158 | spec->pin_nids = stac92hd73xx_pin_nids; | 5171 | spec->pin_nids = stac92hd73xx_pin_nids; |
@@ -5300,6 +5313,7 @@ static int patch_stac92hd83xxx(struct hda_codec *codec) | |||
5300 | 5313 | ||
5301 | codec->no_trigger_sense = 1; | 5314 | codec->no_trigger_sense = 1; |
5302 | codec->spec = spec; | 5315 | codec->spec = spec; |
5316 | spec->linear_tone_beep = 1; | ||
5303 | codec->slave_dig_outs = stac92hd83xxx_slave_dig_outs; | 5317 | codec->slave_dig_outs = stac92hd83xxx_slave_dig_outs; |
5304 | spec->digbeep_nid = 0x21; | 5318 | spec->digbeep_nid = 0x21; |
5305 | spec->mux_nids = stac92hd83xxx_mux_nids; | 5319 | spec->mux_nids = stac92hd83xxx_mux_nids; |
@@ -5335,6 +5349,8 @@ again: | |||
5335 | case 0x111d7667: | 5349 | case 0x111d7667: |
5336 | case 0x111d7668: | 5350 | case 0x111d7668: |
5337 | case 0x111d7669: | 5351 | case 0x111d7669: |
5352 | case 0x111d76d1: | ||
5353 | case 0x111d76d9: | ||
5338 | spec->num_pins = ARRAY_SIZE(stac92hd88xxx_pin_nids); | 5354 | spec->num_pins = ARRAY_SIZE(stac92hd88xxx_pin_nids); |
5339 | spec->pin_nids = stac92hd88xxx_pin_nids; | 5355 | spec->pin_nids = stac92hd88xxx_pin_nids; |
5340 | spec->mono_nid = 0; | 5356 | spec->mono_nid = 0; |
@@ -5522,6 +5538,7 @@ static int patch_stac92hd71bxx(struct hda_codec *codec) | |||
5522 | 5538 | ||
5523 | codec->no_trigger_sense = 1; | 5539 | codec->no_trigger_sense = 1; |
5524 | codec->spec = spec; | 5540 | codec->spec = spec; |
5541 | spec->linear_tone_beep = 0; | ||
5525 | codec->patch_ops = stac92xx_patch_ops; | 5542 | codec->patch_ops = stac92xx_patch_ops; |
5526 | spec->num_pins = STAC92HD71BXX_NUM_PINS; | 5543 | spec->num_pins = STAC92HD71BXX_NUM_PINS; |
5527 | switch (codec->vendor_id) { | 5544 | switch (codec->vendor_id) { |
@@ -5779,6 +5796,7 @@ static int patch_stac922x(struct hda_codec *codec) | |||
5779 | 5796 | ||
5780 | codec->no_trigger_sense = 1; | 5797 | codec->no_trigger_sense = 1; |
5781 | codec->spec = spec; | 5798 | codec->spec = spec; |
5799 | spec->linear_tone_beep = 1; | ||
5782 | spec->num_pins = ARRAY_SIZE(stac922x_pin_nids); | 5800 | spec->num_pins = ARRAY_SIZE(stac922x_pin_nids); |
5783 | spec->pin_nids = stac922x_pin_nids; | 5801 | spec->pin_nids = stac922x_pin_nids; |
5784 | spec->board_config = snd_hda_check_board_config(codec, STAC_922X_MODELS, | 5802 | spec->board_config = snd_hda_check_board_config(codec, STAC_922X_MODELS, |
@@ -5883,6 +5901,7 @@ static int patch_stac927x(struct hda_codec *codec) | |||
5883 | 5901 | ||
5884 | codec->no_trigger_sense = 1; | 5902 | codec->no_trigger_sense = 1; |
5885 | codec->spec = spec; | 5903 | codec->spec = spec; |
5904 | spec->linear_tone_beep = 1; | ||
5886 | codec->slave_dig_outs = stac927x_slave_dig_outs; | 5905 | codec->slave_dig_outs = stac927x_slave_dig_outs; |
5887 | spec->num_pins = ARRAY_SIZE(stac927x_pin_nids); | 5906 | spec->num_pins = ARRAY_SIZE(stac927x_pin_nids); |
5888 | spec->pin_nids = stac927x_pin_nids; | 5907 | spec->pin_nids = stac927x_pin_nids; |
@@ -6018,6 +6037,7 @@ static int patch_stac9205(struct hda_codec *codec) | |||
6018 | 6037 | ||
6019 | codec->no_trigger_sense = 1; | 6038 | codec->no_trigger_sense = 1; |
6020 | codec->spec = spec; | 6039 | codec->spec = spec; |
6040 | spec->linear_tone_beep = 1; | ||
6021 | spec->num_pins = ARRAY_SIZE(stac9205_pin_nids); | 6041 | spec->num_pins = ARRAY_SIZE(stac9205_pin_nids); |
6022 | spec->pin_nids = stac9205_pin_nids; | 6042 | spec->pin_nids = stac9205_pin_nids; |
6023 | spec->board_config = snd_hda_check_board_config(codec, STAC_9205_MODELS, | 6043 | spec->board_config = snd_hda_check_board_config(codec, STAC_9205_MODELS, |
@@ -6174,6 +6194,7 @@ static int patch_stac9872(struct hda_codec *codec) | |||
6174 | return -ENOMEM; | 6194 | return -ENOMEM; |
6175 | codec->no_trigger_sense = 1; | 6195 | codec->no_trigger_sense = 1; |
6176 | codec->spec = spec; | 6196 | codec->spec = spec; |
6197 | spec->linear_tone_beep = 1; | ||
6177 | spec->num_pins = ARRAY_SIZE(stac9872_pin_nids); | 6198 | spec->num_pins = ARRAY_SIZE(stac9872_pin_nids); |
6178 | spec->pin_nids = stac9872_pin_nids; | 6199 | spec->pin_nids = stac9872_pin_nids; |
6179 | 6200 | ||
@@ -6264,6 +6285,8 @@ static struct hda_codec_preset snd_hda_preset_sigmatel[] = { | |||
6264 | { .id = 0x111d76d4, .name = "92HD83C1C5", .patch = patch_stac92hd83xxx}, | 6285 | { .id = 0x111d76d4, .name = "92HD83C1C5", .patch = patch_stac92hd83xxx}, |
6265 | { .id = 0x111d7605, .name = "92HD81B1X5", .patch = patch_stac92hd83xxx}, | 6286 | { .id = 0x111d7605, .name = "92HD81B1X5", .patch = patch_stac92hd83xxx}, |
6266 | { .id = 0x111d76d5, .name = "92HD81B1C5", .patch = patch_stac92hd83xxx}, | 6287 | { .id = 0x111d76d5, .name = "92HD81B1C5", .patch = patch_stac92hd83xxx}, |
6288 | { .id = 0x111d76d1, .name = "92HD87B1/3", .patch = patch_stac92hd83xxx}, | ||
6289 | { .id = 0x111d76d9, .name = "92HD87B2/4", .patch = patch_stac92hd83xxx}, | ||
6267 | { .id = 0x111d7666, .name = "92HD88B3", .patch = patch_stac92hd83xxx}, | 6290 | { .id = 0x111d7666, .name = "92HD88B3", .patch = patch_stac92hd83xxx}, |
6268 | { .id = 0x111d7667, .name = "92HD88B1", .patch = patch_stac92hd83xxx}, | 6291 | { .id = 0x111d7667, .name = "92HD88B1", .patch = patch_stac92hd83xxx}, |
6269 | { .id = 0x111d7668, .name = "92HD88B2", .patch = patch_stac92hd83xxx}, | 6292 | { .id = 0x111d7668, .name = "92HD88B2", .patch = patch_stac92hd83xxx}, |
@@ -6280,6 +6303,21 @@ static struct hda_codec_preset snd_hda_preset_sigmatel[] = { | |||
6280 | { .id = 0x111d76b5, .name = "92HD71B6X", .patch = patch_stac92hd71bxx }, | 6303 | { .id = 0x111d76b5, .name = "92HD71B6X", .patch = patch_stac92hd71bxx }, |
6281 | { .id = 0x111d76b6, .name = "92HD71B5X", .patch = patch_stac92hd71bxx }, | 6304 | { .id = 0x111d76b6, .name = "92HD71B5X", .patch = patch_stac92hd71bxx }, |
6282 | { .id = 0x111d76b7, .name = "92HD71B5X", .patch = patch_stac92hd71bxx }, | 6305 | { .id = 0x111d76b7, .name = "92HD71B5X", .patch = patch_stac92hd71bxx }, |
6306 | { .id = 0x111d76c0, .name = "92HD89C3", .patch = patch_stac92hd73xx }, | ||
6307 | { .id = 0x111d76c1, .name = "92HD89C2", .patch = patch_stac92hd73xx }, | ||
6308 | { .id = 0x111d76c2, .name = "92HD89C1", .patch = patch_stac92hd73xx }, | ||
6309 | { .id = 0x111d76c3, .name = "92HD89B3", .patch = patch_stac92hd73xx }, | ||
6310 | { .id = 0x111d76c4, .name = "92HD89B2", .patch = patch_stac92hd73xx }, | ||
6311 | { .id = 0x111d76c5, .name = "92HD89B1", .patch = patch_stac92hd73xx }, | ||
6312 | { .id = 0x111d76c6, .name = "92HD89E3", .patch = patch_stac92hd73xx }, | ||
6313 | { .id = 0x111d76c7, .name = "92HD89E2", .patch = patch_stac92hd73xx }, | ||
6314 | { .id = 0x111d76c8, .name = "92HD89E1", .patch = patch_stac92hd73xx }, | ||
6315 | { .id = 0x111d76c9, .name = "92HD89D3", .patch = patch_stac92hd73xx }, | ||
6316 | { .id = 0x111d76ca, .name = "92HD89D2", .patch = patch_stac92hd73xx }, | ||
6317 | { .id = 0x111d76cb, .name = "92HD89D1", .patch = patch_stac92hd73xx }, | ||
6318 | { .id = 0x111d76cc, .name = "92HD89F3", .patch = patch_stac92hd73xx }, | ||
6319 | { .id = 0x111d76cd, .name = "92HD89F2", .patch = patch_stac92hd73xx }, | ||
6320 | { .id = 0x111d76ce, .name = "92HD89F1", .patch = patch_stac92hd73xx }, | ||
6283 | {} /* terminator */ | 6321 | {} /* terminator */ |
6284 | }; | 6322 | }; |
6285 | 6323 | ||
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 73453814e098..ae3acb2b42d1 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c | |||
@@ -552,24 +552,30 @@ static void via_auto_init_hp_out(struct hda_codec *codec) | |||
552 | } | 552 | } |
553 | } | 553 | } |
554 | 554 | ||
555 | static int is_smart51_pins(struct via_spec *spec, hda_nid_t pin); | ||
556 | |||
555 | static void via_auto_init_analog_input(struct hda_codec *codec) | 557 | static void via_auto_init_analog_input(struct hda_codec *codec) |
556 | { | 558 | { |
557 | struct via_spec *spec = codec->spec; | 559 | struct via_spec *spec = codec->spec; |
560 | unsigned int ctl; | ||
558 | int i; | 561 | int i; |
559 | 562 | ||
560 | for (i = 0; i < AUTO_PIN_LAST; i++) { | 563 | for (i = 0; i < AUTO_PIN_LAST; i++) { |
561 | hda_nid_t nid = spec->autocfg.input_pins[i]; | 564 | hda_nid_t nid = spec->autocfg.input_pins[i]; |
565 | if (!nid) | ||
566 | continue; | ||
562 | 567 | ||
568 | if (spec->smart51_enabled && is_smart51_pins(spec, nid)) | ||
569 | ctl = PIN_OUT; | ||
570 | else if (i <= AUTO_PIN_FRONT_MIC) | ||
571 | ctl = PIN_VREF50; | ||
572 | else | ||
573 | ctl = PIN_IN; | ||
563 | snd_hda_codec_write(codec, nid, 0, | 574 | snd_hda_codec_write(codec, nid, 0, |
564 | AC_VERB_SET_PIN_WIDGET_CONTROL, | 575 | AC_VERB_SET_PIN_WIDGET_CONTROL, ctl); |
565 | (i <= AUTO_PIN_FRONT_MIC ? | ||
566 | PIN_VREF50 : PIN_IN)); | ||
567 | |||
568 | } | 576 | } |
569 | } | 577 | } |
570 | 578 | ||
571 | static int is_smart51_pins(struct via_spec *spec, hda_nid_t pin); | ||
572 | |||
573 | static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid, | 579 | static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid, |
574 | unsigned int *affected_parm) | 580 | unsigned int *affected_parm) |
575 | { | 581 | { |
@@ -658,6 +664,8 @@ static void set_jack_power_state(struct hda_codec *codec) | |||
658 | /* PW0 (19h), SW1 (18h), AOW1 (11h) */ | 664 | /* PW0 (19h), SW1 (18h), AOW1 (11h) */ |
659 | parm = AC_PWRST_D3; | 665 | parm = AC_PWRST_D3; |
660 | set_pin_power_state(codec, 0x19, &parm); | 666 | set_pin_power_state(codec, 0x19, &parm); |
667 | if (spec->smart51_enabled) | ||
668 | parm = AC_PWRST_D0; | ||
661 | snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE, | 669 | snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE, |
662 | parm); | 670 | parm); |
663 | snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, | 671 | snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, |
@@ -667,6 +675,8 @@ static void set_jack_power_state(struct hda_codec *codec) | |||
667 | if (is_8ch) { | 675 | if (is_8ch) { |
668 | parm = AC_PWRST_D3; | 676 | parm = AC_PWRST_D3; |
669 | set_pin_power_state(codec, 0x22, &parm); | 677 | set_pin_power_state(codec, 0x22, &parm); |
678 | if (spec->smart51_enabled) | ||
679 | parm = AC_PWRST_D0; | ||
670 | snd_hda_codec_write(codec, 0x26, 0, | 680 | snd_hda_codec_write(codec, 0x26, 0, |
671 | AC_VERB_SET_POWER_STATE, parm); | 681 | AC_VERB_SET_POWER_STATE, parm); |
672 | snd_hda_codec_write(codec, 0x24, 0, | 682 | snd_hda_codec_write(codec, 0x24, 0, |
@@ -3915,6 +3925,13 @@ static int vt1708S_auto_fill_dac_nids(struct via_spec *spec, | |||
3915 | } | 3925 | } |
3916 | } | 3926 | } |
3917 | 3927 | ||
3928 | /* for Smart 5.1, line/mic inputs double as output pins */ | ||
3929 | if (cfg->line_outs == 1) { | ||
3930 | spec->multiout.num_dacs = 3; | ||
3931 | spec->multiout.dac_nids[AUTO_SEQ_SURROUND] = 0x11; | ||
3932 | spec->multiout.dac_nids[AUTO_SEQ_CENLFE] = 0x24; | ||
3933 | } | ||
3934 | |||
3918 | return 0; | 3935 | return 0; |
3919 | } | 3936 | } |
3920 | 3937 | ||
@@ -3932,7 +3949,8 @@ static int vt1708S_auto_create_multi_out_ctls(struct via_spec *spec, | |||
3932 | for (i = 0; i <= AUTO_SEQ_SIDE; i++) { | 3949 | for (i = 0; i <= AUTO_SEQ_SIDE; i++) { |
3933 | nid = cfg->line_out_pins[i]; | 3950 | nid = cfg->line_out_pins[i]; |
3934 | 3951 | ||
3935 | if (!nid) | 3952 | /* for Smart 5.1, there are always at least six channels */ |
3953 | if (!nid && i > AUTO_SEQ_CENLFE) | ||
3936 | continue; | 3954 | continue; |
3937 | 3955 | ||
3938 | nid_vol = nid_vols[i]; | 3956 | nid_vol = nid_vols[i]; |
diff --git a/sound/pci/ice1712/delta.c b/sound/pci/ice1712/delta.c index d216362626d0..712c1710f9a2 100644 --- a/sound/pci/ice1712/delta.c +++ b/sound/pci/ice1712/delta.c | |||
@@ -563,6 +563,7 @@ static int __devinit snd_ice1712_delta_init(struct snd_ice1712 *ice) | |||
563 | case ICE1712_SUBDEVICE_DELTA1010E: | 563 | case ICE1712_SUBDEVICE_DELTA1010E: |
564 | case ICE1712_SUBDEVICE_DELTA1010LT: | 564 | case ICE1712_SUBDEVICE_DELTA1010LT: |
565 | case ICE1712_SUBDEVICE_MEDIASTATION: | 565 | case ICE1712_SUBDEVICE_MEDIASTATION: |
566 | case ICE1712_SUBDEVICE_EDIROLDA2496: | ||
566 | ice->num_total_dacs = 8; | 567 | ice->num_total_dacs = 8; |
567 | ice->num_total_adcs = 8; | 568 | ice->num_total_adcs = 8; |
568 | break; | 569 | break; |
@@ -635,6 +636,7 @@ static int __devinit snd_ice1712_delta_init(struct snd_ice1712 *ice) | |||
635 | err = snd_ice1712_akm4xxx_init(ak, &akm_delta410, &akm_delta410_priv, ice); | 636 | err = snd_ice1712_akm4xxx_init(ak, &akm_delta410, &akm_delta410_priv, ice); |
636 | break; | 637 | break; |
637 | case ICE1712_SUBDEVICE_DELTA1010LT: | 638 | case ICE1712_SUBDEVICE_DELTA1010LT: |
639 | case ICE1712_SUBDEVICE_EDIROLDA2496: | ||
638 | err = snd_ice1712_akm4xxx_init(ak, &akm_delta1010lt, &akm_delta1010lt_priv, ice); | 640 | err = snd_ice1712_akm4xxx_init(ak, &akm_delta1010lt, &akm_delta1010lt_priv, ice); |
639 | break; | 641 | break; |
640 | case ICE1712_SUBDEVICE_DELTA66: | 642 | case ICE1712_SUBDEVICE_DELTA66: |
@@ -734,6 +736,7 @@ static int __devinit snd_ice1712_delta_add_controls(struct snd_ice1712 *ice) | |||
734 | case ICE1712_SUBDEVICE_DELTA66: | 736 | case ICE1712_SUBDEVICE_DELTA66: |
735 | case ICE1712_SUBDEVICE_VX442: | 737 | case ICE1712_SUBDEVICE_VX442: |
736 | case ICE1712_SUBDEVICE_DELTA66E: | 738 | case ICE1712_SUBDEVICE_DELTA66E: |
739 | case ICE1712_SUBDEVICE_EDIROLDA2496: | ||
737 | err = snd_ice1712_akm4xxx_build_controls(ice); | 740 | err = snd_ice1712_akm4xxx_build_controls(ice); |
738 | if (err < 0) | 741 | if (err < 0) |
739 | return err; | 742 | return err; |
@@ -813,5 +816,12 @@ struct snd_ice1712_card_info snd_ice1712_delta_cards[] __devinitdata = { | |||
813 | .chip_init = snd_ice1712_delta_init, | 816 | .chip_init = snd_ice1712_delta_init, |
814 | .build_controls = snd_ice1712_delta_add_controls, | 817 | .build_controls = snd_ice1712_delta_add_controls, |
815 | }, | 818 | }, |
819 | { | ||
820 | .subvendor = ICE1712_SUBDEVICE_EDIROLDA2496, | ||
821 | .name = "Edirol DA2496", | ||
822 | .model = "da2496", | ||
823 | .chip_init = snd_ice1712_delta_init, | ||
824 | .build_controls = snd_ice1712_delta_add_controls, | ||
825 | }, | ||
816 | { } /* terminator */ | 826 | { } /* terminator */ |
817 | }; | 827 | }; |
diff --git a/sound/pci/ice1712/delta.h b/sound/pci/ice1712/delta.h index f7f14df81f26..1a0ac6cd6501 100644 --- a/sound/pci/ice1712/delta.h +++ b/sound/pci/ice1712/delta.h | |||
@@ -34,7 +34,8 @@ | |||
34 | "{MidiMan M Audio,Delta 410},"\ | 34 | "{MidiMan M Audio,Delta 410},"\ |
35 | "{MidiMan M Audio,Audiophile 24/96},"\ | 35 | "{MidiMan M Audio,Audiophile 24/96},"\ |
36 | "{Digigram,VX442},"\ | 36 | "{Digigram,VX442},"\ |
37 | "{Lionstracs,Mediastation}," | 37 | "{Lionstracs,Mediastation},"\ |
38 | "{Edirol,DA2496}," | ||
38 | 39 | ||
39 | #define ICE1712_SUBDEVICE_DELTA1010 0x121430d6 | 40 | #define ICE1712_SUBDEVICE_DELTA1010 0x121430d6 |
40 | #define ICE1712_SUBDEVICE_DELTA1010E 0xff1430d6 | 41 | #define ICE1712_SUBDEVICE_DELTA1010E 0xff1430d6 |
@@ -47,6 +48,7 @@ | |||
47 | #define ICE1712_SUBDEVICE_DELTA1010LT 0x12143bd6 | 48 | #define ICE1712_SUBDEVICE_DELTA1010LT 0x12143bd6 |
48 | #define ICE1712_SUBDEVICE_VX442 0x12143cd6 | 49 | #define ICE1712_SUBDEVICE_VX442 0x12143cd6 |
49 | #define ICE1712_SUBDEVICE_MEDIASTATION 0x694c0100 | 50 | #define ICE1712_SUBDEVICE_MEDIASTATION 0x694c0100 |
51 | #define ICE1712_SUBDEVICE_EDIROLDA2496 0xce164010 | ||
50 | 52 | ||
51 | /* entry point */ | 53 | /* entry point */ |
52 | extern struct snd_ice1712_card_info snd_ice1712_delta_cards[]; | 54 | extern struct snd_ice1712_card_info snd_ice1712_delta_cards[]; |
diff --git a/sound/pci/ice1712/pontis.c b/sound/pci/ice1712/pontis.c index 6bc3f91b7281..cdb873f5da50 100644 --- a/sound/pci/ice1712/pontis.c +++ b/sound/pci/ice1712/pontis.c | |||
@@ -638,7 +638,7 @@ static struct snd_kcontrol_new pontis_controls[] __devinitdata = { | |||
638 | */ | 638 | */ |
639 | static void wm_proc_regs_write(struct snd_info_entry *entry, struct snd_info_buffer *buffer) | 639 | static void wm_proc_regs_write(struct snd_info_entry *entry, struct snd_info_buffer *buffer) |
640 | { | 640 | { |
641 | struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data; | 641 | struct snd_ice1712 *ice = entry->private_data; |
642 | char line[64]; | 642 | char line[64]; |
643 | unsigned int reg, val; | 643 | unsigned int reg, val; |
644 | mutex_lock(&ice->gpio_mutex); | 644 | mutex_lock(&ice->gpio_mutex); |
@@ -653,7 +653,7 @@ static void wm_proc_regs_write(struct snd_info_entry *entry, struct snd_info_buf | |||
653 | 653 | ||
654 | static void wm_proc_regs_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) | 654 | static void wm_proc_regs_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) |
655 | { | 655 | { |
656 | struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data; | 656 | struct snd_ice1712 *ice = entry->private_data; |
657 | int reg, val; | 657 | int reg, val; |
658 | 658 | ||
659 | mutex_lock(&ice->gpio_mutex); | 659 | mutex_lock(&ice->gpio_mutex); |
@@ -676,7 +676,7 @@ static void wm_proc_init(struct snd_ice1712 *ice) | |||
676 | 676 | ||
677 | static void cs_proc_regs_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) | 677 | static void cs_proc_regs_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) |
678 | { | 678 | { |
679 | struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data; | 679 | struct snd_ice1712 *ice = entry->private_data; |
680 | int reg, val; | 680 | int reg, val; |
681 | 681 | ||
682 | mutex_lock(&ice->gpio_mutex); | 682 | mutex_lock(&ice->gpio_mutex); |
diff --git a/sound/pci/ice1712/prodigy192.c b/sound/pci/ice1712/prodigy192.c index 2a8e5cd8f2d8..e36ddb94c382 100644 --- a/sound/pci/ice1712/prodigy192.c +++ b/sound/pci/ice1712/prodigy192.c | |||
@@ -654,7 +654,7 @@ static int prodigy192_ak4114_init(struct snd_ice1712 *ice) | |||
654 | static void stac9460_proc_regs_read(struct snd_info_entry *entry, | 654 | static void stac9460_proc_regs_read(struct snd_info_entry *entry, |
655 | struct snd_info_buffer *buffer) | 655 | struct snd_info_buffer *buffer) |
656 | { | 656 | { |
657 | struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data; | 657 | struct snd_ice1712 *ice = entry->private_data; |
658 | int reg, val; | 658 | int reg, val; |
659 | /* registers 0x0 - 0x14 */ | 659 | /* registers 0x0 - 0x14 */ |
660 | for (reg = 0; reg <= 0x15; reg++) { | 660 | for (reg = 0; reg <= 0x15; reg++) { |
diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 6433e65c9507..467749249576 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c | |||
@@ -1776,6 +1776,12 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = { | |||
1776 | }, | 1776 | }, |
1777 | { | 1777 | { |
1778 | .subvendor = 0x1014, | 1778 | .subvendor = 0x1014, |
1779 | .subdevice = 0x0534, | ||
1780 | .name = "ThinkPad X31", | ||
1781 | .type = AC97_TUNE_INV_EAPD | ||
1782 | }, | ||
1783 | { | ||
1784 | .subvendor = 0x1014, | ||
1779 | .subdevice = 0x1f00, | 1785 | .subdevice = 0x1f00, |
1780 | .name = "MS-9128", | 1786 | .name = "MS-9128", |
1781 | .type = AC97_TUNE_ALC_JACK | 1787 | .type = AC97_TUNE_ALC_JACK |
diff --git a/sound/pci/oxygen/oxygen.h b/sound/pci/oxygen/oxygen.h index 6147216af744..a3409edcfb50 100644 --- a/sound/pci/oxygen/oxygen.h +++ b/sound/pci/oxygen/oxygen.h | |||
@@ -155,6 +155,7 @@ void oxygen_pci_remove(struct pci_dev *pci); | |||
155 | int oxygen_pci_suspend(struct pci_dev *pci, pm_message_t state); | 155 | int oxygen_pci_suspend(struct pci_dev *pci, pm_message_t state); |
156 | int oxygen_pci_resume(struct pci_dev *pci); | 156 | int oxygen_pci_resume(struct pci_dev *pci); |
157 | #endif | 157 | #endif |
158 | void oxygen_pci_shutdown(struct pci_dev *pci); | ||
158 | 159 | ||
159 | /* oxygen_mixer.c */ | 160 | /* oxygen_mixer.c */ |
160 | 161 | ||
diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c index fad03d64e3ad..7e93cf884437 100644 --- a/sound/pci/oxygen/oxygen_lib.c +++ b/sound/pci/oxygen/oxygen_lib.c | |||
@@ -519,16 +519,21 @@ static void oxygen_init(struct oxygen *chip) | |||
519 | } | 519 | } |
520 | } | 520 | } |
521 | 521 | ||
522 | static void oxygen_card_free(struct snd_card *card) | 522 | static void oxygen_shutdown(struct oxygen *chip) |
523 | { | 523 | { |
524 | struct oxygen *chip = card->private_data; | ||
525 | |||
526 | spin_lock_irq(&chip->reg_lock); | 524 | spin_lock_irq(&chip->reg_lock); |
527 | chip->interrupt_mask = 0; | 525 | chip->interrupt_mask = 0; |
528 | chip->pcm_running = 0; | 526 | chip->pcm_running = 0; |
529 | oxygen_write16(chip, OXYGEN_DMA_STATUS, 0); | 527 | oxygen_write16(chip, OXYGEN_DMA_STATUS, 0); |
530 | oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, 0); | 528 | oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, 0); |
531 | spin_unlock_irq(&chip->reg_lock); | 529 | spin_unlock_irq(&chip->reg_lock); |
530 | } | ||
531 | |||
532 | static void oxygen_card_free(struct snd_card *card) | ||
533 | { | ||
534 | struct oxygen *chip = card->private_data; | ||
535 | |||
536 | oxygen_shutdown(chip); | ||
532 | if (chip->irq >= 0) | 537 | if (chip->irq >= 0) |
533 | free_irq(chip->irq, chip); | 538 | free_irq(chip->irq, chip); |
534 | flush_scheduled_work(); | 539 | flush_scheduled_work(); |
@@ -778,3 +783,13 @@ int oxygen_pci_resume(struct pci_dev *pci) | |||
778 | } | 783 | } |
779 | EXPORT_SYMBOL(oxygen_pci_resume); | 784 | EXPORT_SYMBOL(oxygen_pci_resume); |
780 | #endif /* CONFIG_PM */ | 785 | #endif /* CONFIG_PM */ |
786 | |||
787 | void oxygen_pci_shutdown(struct pci_dev *pci) | ||
788 | { | ||
789 | struct snd_card *card = pci_get_drvdata(pci); | ||
790 | struct oxygen *chip = card->private_data; | ||
791 | |||
792 | oxygen_shutdown(chip); | ||
793 | chip->model.cleanup(chip); | ||
794 | } | ||
795 | EXPORT_SYMBOL(oxygen_pci_shutdown); | ||
diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c index f03a2f2cffee..06c863e86e3d 100644 --- a/sound/pci/oxygen/virtuoso.c +++ b/sound/pci/oxygen/virtuoso.c | |||
@@ -95,6 +95,7 @@ static struct pci_driver xonar_driver = { | |||
95 | .suspend = oxygen_pci_suspend, | 95 | .suspend = oxygen_pci_suspend, |
96 | .resume = oxygen_pci_resume, | 96 | .resume = oxygen_pci_resume, |
97 | #endif | 97 | #endif |
98 | .shutdown = oxygen_pci_shutdown, | ||
98 | }; | 99 | }; |
99 | 100 | ||
100 | static int __init alsa_card_xonar_init(void) | 101 | static int __init alsa_card_xonar_init(void) |
diff --git a/sound/pci/oxygen/xonar_wm87x6.c b/sound/pci/oxygen/xonar_wm87x6.c index dbc4b89d74e4..aceaaa036da6 100644 --- a/sound/pci/oxygen/xonar_wm87x6.c +++ b/sound/pci/oxygen/xonar_wm87x6.c | |||
@@ -25,16 +25,24 @@ | |||
25 | * SPI 0 -> WM8766 (surround, center/LFE, back) | 25 | * SPI 0 -> WM8766 (surround, center/LFE, back) |
26 | * SPI 1 -> WM8776 (front, input) | 26 | * SPI 1 -> WM8776 (front, input) |
27 | * | 27 | * |
28 | * GPIO 4 <- headphone detect | 28 | * GPIO 4 <- headphone detect, 0 = plugged |
29 | * GPIO 6 -> route input jack to input 1/2 (1/0) | 29 | * GPIO 6 -> route input jack to mic-in (0) or line-in (1) |
30 | * GPIO 7 -> enable output to speakers | 30 | * GPIO 7 -> enable output to front L/R speaker channels |
31 | * GPIO 8 -> enable output to speakers | 31 | * GPIO 8 -> enable output to other speaker channels and front panel headphone |
32 | * | ||
33 | * WM8766: | ||
34 | * | ||
35 | * input 1 <- line | ||
36 | * input 2 <- mic | ||
37 | * input 3 <- front mic | ||
38 | * input 4 <- aux | ||
32 | */ | 39 | */ |
33 | 40 | ||
34 | #include <linux/pci.h> | 41 | #include <linux/pci.h> |
35 | #include <linux/delay.h> | 42 | #include <linux/delay.h> |
36 | #include <sound/control.h> | 43 | #include <sound/control.h> |
37 | #include <sound/core.h> | 44 | #include <sound/core.h> |
45 | #include <sound/jack.h> | ||
38 | #include <sound/pcm.h> | 46 | #include <sound/pcm.h> |
39 | #include <sound/pcm_params.h> | 47 | #include <sound/pcm_params.h> |
40 | #include <sound/tlv.h> | 48 | #include <sound/tlv.h> |
@@ -44,7 +52,8 @@ | |||
44 | 52 | ||
45 | #define GPIO_DS_HP_DETECT 0x0010 | 53 | #define GPIO_DS_HP_DETECT 0x0010 |
46 | #define GPIO_DS_INPUT_ROUTE 0x0040 | 54 | #define GPIO_DS_INPUT_ROUTE 0x0040 |
47 | #define GPIO_DS_OUTPUT_ENABLE 0x0180 | 55 | #define GPIO_DS_OUTPUT_FRONTLR 0x0080 |
56 | #define GPIO_DS_OUTPUT_ENABLE 0x0100 | ||
48 | 57 | ||
49 | #define LC_CONTROL_LIMITER 0x40000000 | 58 | #define LC_CONTROL_LIMITER 0x40000000 |
50 | #define LC_CONTROL_ALC 0x20000000 | 59 | #define LC_CONTROL_ALC 0x20000000 |
@@ -53,7 +62,10 @@ struct xonar_wm87x6 { | |||
53 | struct xonar_generic generic; | 62 | struct xonar_generic generic; |
54 | u16 wm8776_regs[0x17]; | 63 | u16 wm8776_regs[0x17]; |
55 | u16 wm8766_regs[0x10]; | 64 | u16 wm8766_regs[0x10]; |
65 | struct snd_kcontrol *line_adcmux_control; | ||
66 | struct snd_kcontrol *mic_adcmux_control; | ||
56 | struct snd_kcontrol *lc_controls[13]; | 67 | struct snd_kcontrol *lc_controls[13]; |
68 | struct snd_jack *hp_jack; | ||
57 | }; | 69 | }; |
58 | 70 | ||
59 | static void wm8776_write(struct oxygen *chip, | 71 | static void wm8776_write(struct oxygen *chip, |
@@ -95,8 +107,12 @@ static void wm8766_write(struct oxygen *chip, | |||
95 | (0 << OXYGEN_SPI_CODEC_SHIFT) | | 107 | (0 << OXYGEN_SPI_CODEC_SHIFT) | |
96 | OXYGEN_SPI_CEN_LATCH_CLOCK_LO, | 108 | OXYGEN_SPI_CEN_LATCH_CLOCK_LO, |
97 | (reg << 9) | value); | 109 | (reg << 9) | value); |
98 | if (reg < ARRAY_SIZE(data->wm8766_regs)) | 110 | if (reg < ARRAY_SIZE(data->wm8766_regs)) { |
111 | if ((reg >= WM8766_LDA1 && reg <= WM8766_RDA1) || | ||
112 | (reg >= WM8766_LDA2 && reg <= WM8766_MASTDA)) | ||
113 | value &= ~WM8766_UPDATE; | ||
99 | data->wm8766_regs[reg] = value; | 114 | data->wm8766_regs[reg] = value; |
115 | } | ||
100 | } | 116 | } |
101 | 117 | ||
102 | static void wm8766_write_cached(struct oxygen *chip, | 118 | static void wm8766_write_cached(struct oxygen *chip, |
@@ -105,12 +121,8 @@ static void wm8766_write_cached(struct oxygen *chip, | |||
105 | struct xonar_wm87x6 *data = chip->model_data; | 121 | struct xonar_wm87x6 *data = chip->model_data; |
106 | 122 | ||
107 | if (reg >= ARRAY_SIZE(data->wm8766_regs) || | 123 | if (reg >= ARRAY_SIZE(data->wm8766_regs) || |
108 | value != data->wm8766_regs[reg]) { | 124 | 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); | 125 | wm8766_write(chip, reg, value); |
113 | } | ||
114 | } | 126 | } |
115 | 127 | ||
116 | static void wm8776_registers_init(struct oxygen *chip) | 128 | static void wm8776_registers_init(struct oxygen *chip) |
@@ -139,7 +151,10 @@ static void wm8776_registers_init(struct oxygen *chip) | |||
139 | 151 | ||
140 | static void wm8766_registers_init(struct oxygen *chip) | 152 | static void wm8766_registers_init(struct oxygen *chip) |
141 | { | 153 | { |
154 | struct xonar_wm87x6 *data = chip->model_data; | ||
155 | |||
142 | wm8766_write(chip, WM8766_RESET, 0); | 156 | wm8766_write(chip, WM8766_RESET, 0); |
157 | wm8766_write(chip, WM8766_DAC_CTRL, data->wm8766_regs[WM8766_DAC_CTRL]); | ||
143 | wm8766_write(chip, WM8766_INT_CTRL, WM8766_FMT_LJUST | WM8766_IWL_24); | 158 | wm8766_write(chip, WM8766_INT_CTRL, WM8766_FMT_LJUST | WM8766_IWL_24); |
144 | wm8766_write(chip, WM8766_DAC_CTRL2, | 159 | wm8766_write(chip, WM8766_DAC_CTRL2, |
145 | WM8766_ZCD | (chip->dac_mute ? WM8766_DMUTE_MASK : 0)); | 160 | WM8766_ZCD | (chip->dac_mute ? WM8766_DMUTE_MASK : 0)); |
@@ -168,6 +183,40 @@ static void wm8776_init(struct oxygen *chip) | |||
168 | wm8776_registers_init(chip); | 183 | wm8776_registers_init(chip); |
169 | } | 184 | } |
170 | 185 | ||
186 | static void wm8766_init(struct oxygen *chip) | ||
187 | { | ||
188 | struct xonar_wm87x6 *data = chip->model_data; | ||
189 | |||
190 | data->wm8766_regs[WM8766_DAC_CTRL] = | ||
191 | WM8766_PL_LEFT_LEFT | WM8766_PL_RIGHT_RIGHT; | ||
192 | wm8766_registers_init(chip); | ||
193 | } | ||
194 | |||
195 | static void xonar_ds_handle_hp_jack(struct oxygen *chip) | ||
196 | { | ||
197 | struct xonar_wm87x6 *data = chip->model_data; | ||
198 | bool hp_plugged; | ||
199 | unsigned int reg; | ||
200 | |||
201 | mutex_lock(&chip->mutex); | ||
202 | |||
203 | hp_plugged = !(oxygen_read16(chip, OXYGEN_GPIO_DATA) & | ||
204 | GPIO_DS_HP_DETECT); | ||
205 | |||
206 | oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, | ||
207 | hp_plugged ? 0 : GPIO_DS_OUTPUT_FRONTLR, | ||
208 | GPIO_DS_OUTPUT_FRONTLR); | ||
209 | |||
210 | reg = data->wm8766_regs[WM8766_DAC_CTRL] & ~WM8766_MUTEALL; | ||
211 | if (hp_plugged) | ||
212 | reg |= WM8766_MUTEALL; | ||
213 | wm8766_write_cached(chip, WM8766_DAC_CTRL, reg); | ||
214 | |||
215 | snd_jack_report(data->hp_jack, hp_plugged ? SND_JACK_HEADPHONE : 0); | ||
216 | |||
217 | mutex_unlock(&chip->mutex); | ||
218 | } | ||
219 | |||
171 | static void xonar_ds_init(struct oxygen *chip) | 220 | static void xonar_ds_init(struct oxygen *chip) |
172 | { | 221 | { |
173 | struct xonar_wm87x6 *data = chip->model_data; | 222 | struct xonar_wm87x6 *data = chip->model_data; |
@@ -176,16 +225,22 @@ static void xonar_ds_init(struct oxygen *chip) | |||
176 | data->generic.output_enable_bit = GPIO_DS_OUTPUT_ENABLE; | 225 | data->generic.output_enable_bit = GPIO_DS_OUTPUT_ENABLE; |
177 | 226 | ||
178 | wm8776_init(chip); | 227 | wm8776_init(chip); |
179 | wm8766_registers_init(chip); | 228 | wm8766_init(chip); |
180 | 229 | ||
181 | oxygen_write16_masked(chip, OXYGEN_GPIO_CONTROL, GPIO_DS_INPUT_ROUTE, | 230 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, |
182 | GPIO_DS_HP_DETECT | GPIO_DS_INPUT_ROUTE); | 231 | GPIO_DS_INPUT_ROUTE | GPIO_DS_OUTPUT_FRONTLR); |
232 | oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, | ||
233 | GPIO_DS_HP_DETECT); | ||
183 | oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_DS_INPUT_ROUTE); | 234 | oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_DS_INPUT_ROUTE); |
184 | oxygen_set_bits16(chip, OXYGEN_GPIO_INTERRUPT_MASK, GPIO_DS_HP_DETECT); | 235 | oxygen_set_bits16(chip, OXYGEN_GPIO_INTERRUPT_MASK, GPIO_DS_HP_DETECT); |
185 | chip->interrupt_mask |= OXYGEN_INT_GPIO; | 236 | chip->interrupt_mask |= OXYGEN_INT_GPIO; |
186 | 237 | ||
187 | xonar_enable_output(chip); | 238 | xonar_enable_output(chip); |
188 | 239 | ||
240 | snd_jack_new(chip->card, "Headphone", | ||
241 | SND_JACK_HEADPHONE, &data->hp_jack); | ||
242 | xonar_ds_handle_hp_jack(chip); | ||
243 | |||
189 | snd_component_add(chip->card, "WM8776"); | 244 | snd_component_add(chip->card, "WM8776"); |
190 | snd_component_add(chip->card, "WM8766"); | 245 | snd_component_add(chip->card, "WM8766"); |
191 | } | 246 | } |
@@ -193,6 +248,7 @@ static void xonar_ds_init(struct oxygen *chip) | |||
193 | static void xonar_ds_cleanup(struct oxygen *chip) | 248 | static void xonar_ds_cleanup(struct oxygen *chip) |
194 | { | 249 | { |
195 | xonar_disable_output(chip); | 250 | xonar_disable_output(chip); |
251 | wm8776_write(chip, WM8776_RESET, 0); | ||
196 | } | 252 | } |
197 | 253 | ||
198 | static void xonar_ds_suspend(struct oxygen *chip) | 254 | static void xonar_ds_suspend(struct oxygen *chip) |
@@ -205,6 +261,7 @@ static void xonar_ds_resume(struct oxygen *chip) | |||
205 | wm8776_registers_init(chip); | 261 | wm8776_registers_init(chip); |
206 | wm8766_registers_init(chip); | 262 | wm8766_registers_init(chip); |
207 | xonar_enable_output(chip); | 263 | xonar_enable_output(chip); |
264 | xonar_ds_handle_hp_jack(chip); | ||
208 | } | 265 | } |
209 | 266 | ||
210 | static void wm8776_adc_hardware_filter(unsigned int channel, | 267 | static void wm8776_adc_hardware_filter(unsigned int channel, |
@@ -320,12 +377,27 @@ static void update_wm87x6_mute(struct oxygen *chip) | |||
320 | (chip->dac_mute ? WM8766_DMUTE_MASK : 0)); | 377 | (chip->dac_mute ? WM8766_DMUTE_MASK : 0)); |
321 | } | 378 | } |
322 | 379 | ||
323 | static void xonar_ds_gpio_changed(struct oxygen *chip) | 380 | static void update_wm8766_center_lfe_mix(struct oxygen *chip, bool mixed) |
324 | { | 381 | { |
325 | u16 bits; | 382 | struct xonar_wm87x6 *data = chip->model_data; |
383 | unsigned int reg; | ||
326 | 384 | ||
327 | bits = oxygen_read16(chip, OXYGEN_GPIO_DATA); | 385 | /* |
328 | snd_printk(KERN_INFO "HP detect: %d\n", !!(bits & GPIO_DS_HP_DETECT)); | 386 | * The WM8766 can mix left and right channels, but this setting |
387 | * applies to all three stereo pairs. | ||
388 | */ | ||
389 | reg = data->wm8766_regs[WM8766_DAC_CTRL] & | ||
390 | ~(WM8766_PL_LEFT_MASK | WM8766_PL_RIGHT_MASK); | ||
391 | if (mixed) | ||
392 | reg |= WM8766_PL_LEFT_LRMIX | WM8766_PL_RIGHT_LRMIX; | ||
393 | else | ||
394 | reg |= WM8766_PL_LEFT_LEFT | WM8766_PL_RIGHT_RIGHT; | ||
395 | wm8766_write_cached(chip, WM8766_DAC_CTRL, reg); | ||
396 | } | ||
397 | |||
398 | static void xonar_ds_gpio_changed(struct oxygen *chip) | ||
399 | { | ||
400 | xonar_ds_handle_hp_jack(chip); | ||
329 | } | 401 | } |
330 | 402 | ||
331 | static int wm8776_bit_switch_get(struct snd_kcontrol *ctl, | 403 | static int wm8776_bit_switch_get(struct snd_kcontrol *ctl, |
@@ -603,6 +675,7 @@ static int wm8776_input_mux_put(struct snd_kcontrol *ctl, | |||
603 | { | 675 | { |
604 | struct oxygen *chip = ctl->private_data; | 676 | struct oxygen *chip = ctl->private_data; |
605 | struct xonar_wm87x6 *data = chip->model_data; | 677 | struct xonar_wm87x6 *data = chip->model_data; |
678 | struct snd_kcontrol *other_ctl; | ||
606 | unsigned int mux_bit = ctl->private_value; | 679 | unsigned int mux_bit = ctl->private_value; |
607 | u16 reg; | 680 | u16 reg; |
608 | int changed; | 681 | int changed; |
@@ -610,8 +683,18 @@ static int wm8776_input_mux_put(struct snd_kcontrol *ctl, | |||
610 | mutex_lock(&chip->mutex); | 683 | mutex_lock(&chip->mutex); |
611 | reg = data->wm8776_regs[WM8776_ADCMUX]; | 684 | reg = data->wm8776_regs[WM8776_ADCMUX]; |
612 | if (value->value.integer.value[0]) { | 685 | if (value->value.integer.value[0]) { |
613 | reg &= ~0x003; | ||
614 | reg |= mux_bit; | 686 | reg |= mux_bit; |
687 | /* line-in and mic-in are exclusive */ | ||
688 | mux_bit ^= 3; | ||
689 | if (reg & mux_bit) { | ||
690 | reg &= ~mux_bit; | ||
691 | if (mux_bit == 1) | ||
692 | other_ctl = data->line_adcmux_control; | ||
693 | else | ||
694 | other_ctl = data->mic_adcmux_control; | ||
695 | snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, | ||
696 | &other_ctl->id); | ||
697 | } | ||
615 | } else | 698 | } else |
616 | reg &= ~mux_bit; | 699 | reg &= ~mux_bit; |
617 | changed = reg != data->wm8776_regs[WM8776_ADCMUX]; | 700 | changed = reg != data->wm8776_regs[WM8776_ADCMUX]; |
@@ -882,7 +965,10 @@ static const struct snd_kcontrol_new ds_controls[] = { | |||
882 | .put = wm8776_input_mux_put, | 965 | .put = wm8776_input_mux_put, |
883 | .private_value = 1 << 1, | 966 | .private_value = 1 << 1, |
884 | }, | 967 | }, |
885 | WM8776_BIT_SWITCH("Aux", WM8776_ADCMUX, 1 << 2, 0, 0), | 968 | WM8776_BIT_SWITCH("Front Mic Capture Switch", |
969 | WM8776_ADCMUX, 1 << 2, 0, 0), | ||
970 | WM8776_BIT_SWITCH("Aux Capture Switch", | ||
971 | WM8776_ADCMUX, 1 << 3, 0, 0), | ||
886 | { | 972 | { |
887 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 973 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
888 | .name = "ADC Filter Capture Enum", | 974 | .name = "ADC Filter Capture Enum", |
@@ -963,7 +1049,13 @@ static int xonar_ds_mixer_init(struct oxygen *chip) | |||
963 | err = snd_ctl_add(chip->card, ctl); | 1049 | err = snd_ctl_add(chip->card, ctl); |
964 | if (err < 0) | 1050 | if (err < 0) |
965 | return err; | 1051 | return err; |
1052 | if (!strcmp(ctl->id.name, "Line Capture Switch")) | ||
1053 | data->line_adcmux_control = ctl; | ||
1054 | else if (!strcmp(ctl->id.name, "Mic Capture Switch")) | ||
1055 | data->mic_adcmux_control = ctl; | ||
966 | } | 1056 | } |
1057 | if (!data->line_adcmux_control || !data->mic_adcmux_control) | ||
1058 | return -ENXIO; | ||
967 | BUILD_BUG_ON(ARRAY_SIZE(lc_controls) != ARRAY_SIZE(data->lc_controls)); | 1059 | BUILD_BUG_ON(ARRAY_SIZE(lc_controls) != ARRAY_SIZE(data->lc_controls)); |
968 | for (i = 0; i < ARRAY_SIZE(lc_controls); ++i) { | 1060 | for (i = 0; i < ARRAY_SIZE(lc_controls); ++i) { |
969 | ctl = snd_ctl_new1(&lc_controls[i], chip); | 1061 | ctl = snd_ctl_new1(&lc_controls[i], chip); |
@@ -993,6 +1085,7 @@ static const struct oxygen_model model_xonar_ds = { | |||
993 | .set_adc_params = set_wm8776_adc_params, | 1085 | .set_adc_params = set_wm8776_adc_params, |
994 | .update_dac_volume = update_wm87x6_volume, | 1086 | .update_dac_volume = update_wm87x6_volume, |
995 | .update_dac_mute = update_wm87x6_mute, | 1087 | .update_dac_mute = update_wm87x6_mute, |
1088 | .update_center_lfe_mix = update_wm8766_center_lfe_mix, | ||
996 | .gpio_changed = xonar_ds_gpio_changed, | 1089 | .gpio_changed = xonar_ds_gpio_changed, |
997 | .dac_tlv = wm87x6_dac_db_scale, | 1090 | .dac_tlv = wm87x6_dac_db_scale, |
998 | .model_data_size = sizeof(struct xonar_wm87x6), | 1091 | .model_data_size = sizeof(struct xonar_wm87x6), |
diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c index ad4462677615..ad5202efd7a9 100644 --- a/sound/pci/riptide/riptide.c +++ b/sound/pci/riptide/riptide.c | |||
@@ -97,6 +97,7 @@ | |||
97 | #include <linux/gameport.h> | 97 | #include <linux/gameport.h> |
98 | #include <linux/device.h> | 98 | #include <linux/device.h> |
99 | #include <linux/firmware.h> | 99 | #include <linux/firmware.h> |
100 | #include <linux/kernel.h> | ||
100 | #include <asm/io.h> | 101 | #include <asm/io.h> |
101 | #include <sound/core.h> | 102 | #include <sound/core.h> |
102 | #include <sound/info.h> | 103 | #include <sound/info.h> |
@@ -667,13 +668,12 @@ static u32 atoh(const unsigned char *in, unsigned int len) | |||
667 | unsigned char c; | 668 | unsigned char c; |
668 | 669 | ||
669 | while (len) { | 670 | while (len) { |
671 | int value; | ||
672 | |||
670 | c = in[len - 1]; | 673 | c = in[len - 1]; |
671 | if ((c >= '0') && (c <= '9')) | 674 | value = hex_to_bin(c); |
672 | sum += mult * (c - '0'); | 675 | if (value >= 0) |
673 | else if ((c >= 'A') && (c <= 'F')) | 676 | sum += mult * value; |
674 | sum += mult * (c - ('A' - 10)); | ||
675 | else if ((c >= 'a') && (c <= 'f')) | ||
676 | sum += mult * (c - ('a' - 10)); | ||
677 | mult *= 16; | 677 | mult *= 16; |
678 | --len; | 678 | --len; |
679 | } | 679 | } |
@@ -1224,15 +1224,14 @@ static int try_to_load_firmware(struct cmdif *cif, struct snd_riptide *chip) | |||
1224 | firmware.firmware.ASIC, firmware.firmware.CODEC, | 1224 | firmware.firmware.ASIC, firmware.firmware.CODEC, |
1225 | firmware.firmware.AUXDSP, firmware.firmware.PROG); | 1225 | firmware.firmware.AUXDSP, firmware.firmware.PROG); |
1226 | 1226 | ||
1227 | if (!chip) | ||
1228 | return 1; | ||
1229 | |||
1227 | for (i = 0; i < FIRMWARE_VERSIONS; i++) { | 1230 | for (i = 0; i < FIRMWARE_VERSIONS; i++) { |
1228 | if (!memcmp(&firmware_versions[i], &firmware, sizeof(firmware))) | 1231 | if (!memcmp(&firmware_versions[i], &firmware, sizeof(firmware))) |
1229 | break; | 1232 | return 1; /* OK */ |
1230 | } | ||
1231 | if (i >= FIRMWARE_VERSIONS) | ||
1232 | return 0; /* no match */ | ||
1233 | 1233 | ||
1234 | if (!chip) | 1234 | } |
1235 | return 1; /* OK */ | ||
1236 | 1235 | ||
1237 | snd_printdd("Writing Firmware\n"); | 1236 | snd_printdd("Writing Firmware\n"); |
1238 | if (!chip->fw_entry) { | 1237 | if (!chip->fw_entry) { |
@@ -1615,7 +1614,10 @@ static int snd_riptide_playback_open(struct snd_pcm_substream *substream) | |||
1615 | 1614 | ||
1616 | chip->playback_substream[sub_num] = substream; | 1615 | chip->playback_substream[sub_num] = substream; |
1617 | runtime->hw = snd_riptide_playback; | 1616 | runtime->hw = snd_riptide_playback; |
1617 | |||
1618 | data = kzalloc(sizeof(struct pcmhw), GFP_KERNEL); | 1618 | data = kzalloc(sizeof(struct pcmhw), GFP_KERNEL); |
1619 | if (data == NULL) | ||
1620 | return -ENOMEM; | ||
1619 | data->paths = lbus_play_paths[sub_num]; | 1621 | data->paths = lbus_play_paths[sub_num]; |
1620 | data->id = play_ids[sub_num]; | 1622 | data->id = play_ids[sub_num]; |
1621 | data->source = play_sources[sub_num]; | 1623 | data->source = play_sources[sub_num]; |
@@ -1635,7 +1637,10 @@ static int snd_riptide_capture_open(struct snd_pcm_substream *substream) | |||
1635 | 1637 | ||
1636 | chip->capture_substream = substream; | 1638 | chip->capture_substream = substream; |
1637 | runtime->hw = snd_riptide_capture; | 1639 | runtime->hw = snd_riptide_capture; |
1640 | |||
1638 | data = kzalloc(sizeof(struct pcmhw), GFP_KERNEL); | 1641 | data = kzalloc(sizeof(struct pcmhw), GFP_KERNEL); |
1642 | if (data == NULL) | ||
1643 | return -ENOMEM; | ||
1639 | data->paths = lbus_rec_path; | 1644 | data->paths = lbus_rec_path; |
1640 | data->id = PADC; | 1645 | data->id = PADC; |
1641 | data->source = ACLNK2PADC; | 1646 | data->source = ACLNK2PADC; |
diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c index d19dc052c391..d5f5b440fc40 100644 --- a/sound/pci/rme96.c +++ b/sound/pci/rme96.c | |||
@@ -1527,14 +1527,14 @@ snd_rme96_free(void *private_data) | |||
1527 | static void | 1527 | static void |
1528 | snd_rme96_free_spdif_pcm(struct snd_pcm *pcm) | 1528 | snd_rme96_free_spdif_pcm(struct snd_pcm *pcm) |
1529 | { | 1529 | { |
1530 | struct rme96 *rme96 = (struct rme96 *) pcm->private_data; | 1530 | struct rme96 *rme96 = pcm->private_data; |
1531 | rme96->spdif_pcm = NULL; | 1531 | rme96->spdif_pcm = NULL; |
1532 | } | 1532 | } |
1533 | 1533 | ||
1534 | static void | 1534 | static void |
1535 | snd_rme96_free_adat_pcm(struct snd_pcm *pcm) | 1535 | snd_rme96_free_adat_pcm(struct snd_pcm *pcm) |
1536 | { | 1536 | { |
1537 | struct rme96 *rme96 = (struct rme96 *) pcm->private_data; | 1537 | struct rme96 *rme96 = pcm->private_data; |
1538 | rme96->adat_pcm = NULL; | 1538 | rme96->adat_pcm = NULL; |
1539 | } | 1539 | } |
1540 | 1540 | ||
@@ -1661,7 +1661,7 @@ static void | |||
1661 | snd_rme96_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) | 1661 | snd_rme96_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) |
1662 | { | 1662 | { |
1663 | int n; | 1663 | int n; |
1664 | struct rme96 *rme96 = (struct rme96 *)entry->private_data; | 1664 | struct rme96 *rme96 = entry->private_data; |
1665 | 1665 | ||
1666 | rme96->rcreg = readl(rme96->iobase + RME96_IO_CONTROL_REGISTER); | 1666 | rme96->rcreg = readl(rme96->iobase + RME96_IO_CONTROL_REGISTER); |
1667 | 1667 | ||
@@ -2348,7 +2348,7 @@ snd_rme96_probe(struct pci_dev *pci, | |||
2348 | if (err < 0) | 2348 | if (err < 0) |
2349 | return err; | 2349 | return err; |
2350 | card->private_free = snd_rme96_card_free; | 2350 | card->private_free = snd_rme96_card_free; |
2351 | rme96 = (struct rme96 *)card->private_data; | 2351 | rme96 = card->private_data; |
2352 | rme96->card = card; | 2352 | rme96->card = card; |
2353 | rme96->pci = pci; | 2353 | rme96->pci = pci; |
2354 | snd_card_set_dev(card, &pci->dev); | 2354 | snd_card_set_dev(card, &pci->dev); |
diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index b92adef8e81e..599e09051663 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c | |||
@@ -3284,7 +3284,7 @@ static int snd_hdsp_create_controls(struct snd_card *card, struct hdsp *hdsp) | |||
3284 | static void | 3284 | static void |
3285 | snd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) | 3285 | snd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) |
3286 | { | 3286 | { |
3287 | struct hdsp *hdsp = (struct hdsp *) entry->private_data; | 3287 | struct hdsp *hdsp = entry->private_data; |
3288 | unsigned int status; | 3288 | unsigned int status; |
3289 | unsigned int status2; | 3289 | unsigned int status2; |
3290 | char *pref_sync_ref; | 3290 | char *pref_sync_ref; |
@@ -4566,7 +4566,7 @@ static int hdsp_get_peak(struct hdsp *hdsp, struct hdsp_peak_rms __user *peak_rm | |||
4566 | 4566 | ||
4567 | static int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigned int cmd, unsigned long arg) | 4567 | static int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigned int cmd, unsigned long arg) |
4568 | { | 4568 | { |
4569 | struct hdsp *hdsp = (struct hdsp *)hw->private_data; | 4569 | struct hdsp *hdsp = hw->private_data; |
4570 | void __user *argp = (void __user *)arg; | 4570 | void __user *argp = (void __user *)arg; |
4571 | int err; | 4571 | int err; |
4572 | 4572 | ||
@@ -5155,7 +5155,7 @@ static int snd_hdsp_free(struct hdsp *hdsp) | |||
5155 | 5155 | ||
5156 | static void snd_hdsp_card_free(struct snd_card *card) | 5156 | static void snd_hdsp_card_free(struct snd_card *card) |
5157 | { | 5157 | { |
5158 | struct hdsp *hdsp = (struct hdsp *) card->private_data; | 5158 | struct hdsp *hdsp = card->private_data; |
5159 | 5159 | ||
5160 | if (hdsp) | 5160 | if (hdsp) |
5161 | snd_hdsp_free(hdsp); | 5161 | snd_hdsp_free(hdsp); |
@@ -5181,7 +5181,7 @@ static int __devinit snd_hdsp_probe(struct pci_dev *pci, | |||
5181 | if (err < 0) | 5181 | if (err < 0) |
5182 | return err; | 5182 | return err; |
5183 | 5183 | ||
5184 | hdsp = (struct hdsp *) card->private_data; | 5184 | hdsp = card->private_data; |
5185 | card->private_free = snd_hdsp_card_free; | 5185 | card->private_free = snd_hdsp_card_free; |
5186 | hdsp->dev = dev; | 5186 | hdsp->dev = dev; |
5187 | hdsp->pci = pci; | 5187 | hdsp->pci = pci; |
diff --git a/sound/pci/sis7019.c b/sound/pci/sis7019.c index 9cc1b5aa0148..1b8f6742b5fa 100644 --- a/sound/pci/sis7019.c +++ b/sound/pci/sis7019.c | |||
@@ -264,11 +264,13 @@ static void sis_update_voice(struct voice *voice) | |||
264 | * if using small periods. | 264 | * if using small periods. |
265 | * | 265 | * |
266 | * If we're less than 9 samples behind, we're on target. | 266 | * If we're less than 9 samples behind, we're on target. |
267 | * Otherwise, shorten the next vperiod by the amount we've | ||
268 | * been delayed. | ||
267 | */ | 269 | */ |
268 | if (sync > -9) | 270 | if (sync > -9) |
269 | voice->vperiod = voice->sync_period_size + 1; | 271 | voice->vperiod = voice->sync_period_size + 1; |
270 | else | 272 | else |
271 | voice->vperiod = voice->sync_period_size - 4; | 273 | voice->vperiod = voice->sync_period_size + sync + 10; |
272 | 274 | ||
273 | if (voice->vperiod < voice->buffer_size) { | 275 | if (voice->vperiod < voice->buffer_size) { |
274 | sis_update_sso(voice, voice->vperiod); | 276 | sis_update_sso(voice, voice->vperiod); |
@@ -736,7 +738,7 @@ static void sis_prepare_timing_voice(struct voice *voice, | |||
736 | period_size = buffer_size; | 738 | period_size = buffer_size; |
737 | 739 | ||
738 | /* Initially, we want to interrupt just a bit behind the end of | 740 | /* Initially, we want to interrupt just a bit behind the end of |
739 | * the period we're clocking out. 10 samples seems to give a good | 741 | * the period we're clocking out. 12 samples seems to give a good |
740 | * delay. | 742 | * delay. |
741 | * | 743 | * |
742 | * We want to spread our interrupts throughout the virtual period, | 744 | * We want to spread our interrupts throughout the virtual period, |
@@ -747,7 +749,7 @@ static void sis_prepare_timing_voice(struct voice *voice, | |||
747 | * | 749 | * |
748 | * This is all moot if we don't need to use virtual periods. | 750 | * This is all moot if we don't need to use virtual periods. |
749 | */ | 751 | */ |
750 | vperiod = runtime->period_size + 10; | 752 | vperiod = runtime->period_size + 12; |
751 | if (vperiod > period_size) { | 753 | if (vperiod > period_size) { |
752 | u16 tail = vperiod % period_size; | 754 | u16 tail = vperiod % period_size; |
753 | u16 quarter_period = period_size / 4; | 755 | u16 quarter_period = period_size / 4; |
@@ -776,7 +778,7 @@ static void sis_prepare_timing_voice(struct voice *voice, | |||
776 | */ | 778 | */ |
777 | timing->flags |= VOICE_SYNC_TIMING; | 779 | timing->flags |= VOICE_SYNC_TIMING; |
778 | timing->sync_base = voice->ctrl_base; | 780 | timing->sync_base = voice->ctrl_base; |
779 | timing->sync_cso = runtime->period_size - 1; | 781 | timing->sync_cso = runtime->period_size; |
780 | timing->sync_period_size = runtime->period_size; | 782 | timing->sync_period_size = runtime->period_size; |
781 | timing->sync_buffer_size = runtime->buffer_size; | 783 | timing->sync_buffer_size = runtime->buffer_size; |
782 | timing->period_size = period_size; | 784 | timing->period_size = period_size; |
@@ -1047,7 +1049,7 @@ static int sis_chip_free(struct sis7019 *sis) | |||
1047 | /* Reset the chip, and disable all interrputs. | 1049 | /* Reset the chip, and disable all interrputs. |
1048 | */ | 1050 | */ |
1049 | outl(SIS_GCR_SOFTWARE_RESET, sis->ioport + SIS_GCR); | 1051 | outl(SIS_GCR_SOFTWARE_RESET, sis->ioport + SIS_GCR); |
1050 | udelay(10); | 1052 | udelay(25); |
1051 | outl(0, sis->ioport + SIS_GCR); | 1053 | outl(0, sis->ioport + SIS_GCR); |
1052 | outl(0, sis->ioport + SIS_GIER); | 1054 | outl(0, sis->ioport + SIS_GIER); |
1053 | 1055 | ||
@@ -1083,7 +1085,7 @@ static int sis_chip_init(struct sis7019 *sis) | |||
1083 | /* Reset the audio controller | 1085 | /* Reset the audio controller |
1084 | */ | 1086 | */ |
1085 | outl(SIS_GCR_SOFTWARE_RESET, io + SIS_GCR); | 1087 | outl(SIS_GCR_SOFTWARE_RESET, io + SIS_GCR); |
1086 | udelay(10); | 1088 | udelay(25); |
1087 | outl(0, io + SIS_GCR); | 1089 | outl(0, io + SIS_GCR); |
1088 | 1090 | ||
1089 | /* Get the AC-link semaphore, and reset the codecs | 1091 | /* Get the AC-link semaphore, and reset the codecs |
@@ -1096,7 +1098,7 @@ static int sis_chip_init(struct sis7019 *sis) | |||
1096 | return -EIO; | 1098 | return -EIO; |
1097 | 1099 | ||
1098 | outl(SIS_AC97_CMD_CODEC_COLD_RESET, io + SIS_AC97_CMD); | 1100 | outl(SIS_AC97_CMD_CODEC_COLD_RESET, io + SIS_AC97_CMD); |
1099 | udelay(10); | 1101 | udelay(250); |
1100 | 1102 | ||
1101 | count = 0xffff; | 1103 | count = 0xffff; |
1102 | while ((inw(io + SIS_AC97_STATUS) & SIS_AC97_STATUS_BUSY) && --count) | 1104 | while ((inw(io + SIS_AC97_STATUS) & SIS_AC97_STATUS_BUSY) && --count) |
diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c index 6d943f6f6b70..2870a4fdc130 100644 --- a/sound/pci/trident/trident_main.c +++ b/sound/pci/trident/trident_main.c | |||
@@ -1055,7 +1055,7 @@ static int snd_trident_capture_prepare(struct snd_pcm_substream *substream) | |||
1055 | 1055 | ||
1056 | spin_lock_irq(&trident->reg_lock); | 1056 | spin_lock_irq(&trident->reg_lock); |
1057 | 1057 | ||
1058 | // Initilize the channel and set channel Mode | 1058 | // Initialize the channel and set channel Mode |
1059 | outb(0, TRID_REG(trident, LEGACY_DMAR15)); | 1059 | outb(0, TRID_REG(trident, LEGACY_DMAR15)); |
1060 | 1060 | ||
1061 | // Set DMA channel operation mode register | 1061 | // Set DMA channel operation mode register |
diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index 7e494b6a1d0e..8c5f8b5a59f0 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c | |||
@@ -85,6 +85,7 @@ static int joystick; | |||
85 | static int ac97_clock = 48000; | 85 | static int ac97_clock = 48000; |
86 | static char *ac97_quirk; | 86 | static char *ac97_quirk; |
87 | static int dxs_support; | 87 | static int dxs_support; |
88 | static int dxs_init_volume = 31; | ||
88 | static int nodelay; | 89 | static int nodelay; |
89 | 90 | ||
90 | module_param(index, int, 0444); | 91 | module_param(index, int, 0444); |
@@ -103,6 +104,8 @@ module_param(ac97_quirk, charp, 0444); | |||
103 | MODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware."); | 104 | MODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware."); |
104 | module_param(dxs_support, int, 0444); | 105 | module_param(dxs_support, int, 0444); |
105 | MODULE_PARM_DESC(dxs_support, "Support for DXS channels (0 = auto, 1 = enable, 2 = disable, 3 = 48k only, 4 = no VRA, 5 = enable any sample rate)"); | 106 | MODULE_PARM_DESC(dxs_support, "Support for DXS channels (0 = auto, 1 = enable, 2 = disable, 3 = 48k only, 4 = no VRA, 5 = enable any sample rate)"); |
107 | module_param(dxs_init_volume, int, 0644); | ||
108 | MODULE_PARM_DESC(dxs_init_volume, "initial DXS volume (0-31)"); | ||
106 | module_param(nodelay, int, 0444); | 109 | module_param(nodelay, int, 0444); |
107 | MODULE_PARM_DESC(nodelay, "Disable 500ms init delay"); | 110 | MODULE_PARM_DESC(nodelay, "Disable 500ms init delay"); |
108 | 111 | ||
@@ -1245,8 +1248,10 @@ static int snd_via8233_playback_open(struct snd_pcm_substream *substream) | |||
1245 | return err; | 1248 | return err; |
1246 | stream = viadev->reg_offset / 0x10; | 1249 | stream = viadev->reg_offset / 0x10; |
1247 | if (chip->dxs_controls[stream]) { | 1250 | if (chip->dxs_controls[stream]) { |
1248 | chip->playback_volume[stream][0] = 0; | 1251 | chip->playback_volume[stream][0] = |
1249 | chip->playback_volume[stream][1] = 0; | 1252 | VIA_DXS_MAX_VOLUME - (dxs_init_volume & 31); |
1253 | chip->playback_volume[stream][1] = | ||
1254 | VIA_DXS_MAX_VOLUME - (dxs_init_volume & 31); | ||
1250 | chip->dxs_controls[stream]->vd[0].access &= | 1255 | chip->dxs_controls[stream]->vd[0].access &= |
1251 | ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; | 1256 | ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; |
1252 | snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE | | 1257 | snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE | |
diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf.c b/sound/pcmcia/pdaudiocf/pdaudiocf.c index df110df52a8b..7ab9174a8a84 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf.c | |||
@@ -139,8 +139,8 @@ static int snd_pdacf_probe(struct pcmcia_device *link) | |||
139 | pdacf->p_dev = link; | 139 | pdacf->p_dev = link; |
140 | link->priv = pdacf; | 140 | link->priv = pdacf; |
141 | 141 | ||
142 | link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; | 142 | link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; |
143 | link->io.NumPorts1 = 16; | 143 | link->resource[0]->end = 16; |
144 | 144 | ||
145 | link->conf.Attributes = CONF_ENABLE_IRQ | CONF_ENABLE_PULSE_IRQ; | 145 | link->conf.Attributes = CONF_ENABLE_IRQ | CONF_ENABLE_PULSE_IRQ; |
146 | link->conf.IntType = INT_MEMORY_AND_IO; | 146 | link->conf.IntType = INT_MEMORY_AND_IO; |
@@ -219,7 +219,7 @@ static int pdacf_config(struct pcmcia_device *link) | |||
219 | snd_printdd(KERN_DEBUG "pdacf_config called\n"); | 219 | snd_printdd(KERN_DEBUG "pdacf_config called\n"); |
220 | link->conf.ConfigIndex = 0x5; | 220 | link->conf.ConfigIndex = 0x5; |
221 | 221 | ||
222 | ret = pcmcia_request_io(link, &link->io); | 222 | ret = pcmcia_request_io(link); |
223 | if (ret) | 223 | if (ret) |
224 | goto failed; | 224 | goto failed; |
225 | 225 | ||
@@ -231,7 +231,8 @@ static int pdacf_config(struct pcmcia_device *link) | |||
231 | if (ret) | 231 | if (ret) |
232 | goto failed; | 232 | goto failed; |
233 | 233 | ||
234 | if (snd_pdacf_assign_resources(pdacf, link->io.BasePort1, link->irq) < 0) | 234 | if (snd_pdacf_assign_resources(pdacf, link->resource[0]->start, |
235 | link->irq) < 0) | ||
235 | goto failed; | 236 | goto failed; |
236 | 237 | ||
237 | return 0; | 238 | return 0; |
diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf.h b/sound/pcmcia/pdaudiocf/pdaudiocf.h index a0a7ec64222a..5cc3e4573074 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf.h +++ b/sound/pcmcia/pdaudiocf/pdaudiocf.h | |||
@@ -24,7 +24,6 @@ | |||
24 | #include <sound/pcm.h> | 24 | #include <sound/pcm.h> |
25 | #include <asm/io.h> | 25 | #include <asm/io.h> |
26 | #include <linux/interrupt.h> | 26 | #include <linux/interrupt.h> |
27 | #include <pcmcia/cs_types.h> | ||
28 | #include <pcmcia/cs.h> | 27 | #include <pcmcia/cs.h> |
29 | #include <pcmcia/cistpl.h> | 28 | #include <pcmcia/cistpl.h> |
30 | #include <pcmcia/ds.h> | 29 | #include <pcmcia/ds.h> |
diff --git a/sound/pcmcia/vx/vxpocket.c b/sound/pcmcia/vx/vxpocket.c index 624b47a85f0a..a6edfc3be29a 100644 --- a/sound/pcmcia/vx/vxpocket.c +++ b/sound/pcmcia/vx/vxpocket.c | |||
@@ -159,8 +159,8 @@ static int snd_vxpocket_new(struct snd_card *card, int ibl, | |||
159 | vxp->p_dev = link; | 159 | vxp->p_dev = link; |
160 | link->priv = chip; | 160 | link->priv = chip; |
161 | 161 | ||
162 | link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; | 162 | link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; |
163 | link->io.NumPorts1 = 16; | 163 | link->resource[0]->end = 16; |
164 | 164 | ||
165 | link->conf.Attributes = CONF_ENABLE_IRQ; | 165 | link->conf.Attributes = CONF_ENABLE_IRQ; |
166 | link->conf.IntType = INT_MEMORY_AND_IO; | 166 | link->conf.IntType = INT_MEMORY_AND_IO; |
@@ -226,7 +226,7 @@ static int vxpocket_config(struct pcmcia_device *link) | |||
226 | strcpy(chip->card->driver, vxp440_hw.name); | 226 | strcpy(chip->card->driver, vxp440_hw.name); |
227 | } | 227 | } |
228 | 228 | ||
229 | ret = pcmcia_request_io(link, &link->io); | 229 | ret = pcmcia_request_io(link); |
230 | if (ret) | 230 | if (ret) |
231 | goto failed; | 231 | goto failed; |
232 | 232 | ||
@@ -241,7 +241,8 @@ static int vxpocket_config(struct pcmcia_device *link) | |||
241 | chip->dev = &link->dev; | 241 | chip->dev = &link->dev; |
242 | snd_card_set_dev(chip->card, chip->dev); | 242 | snd_card_set_dev(chip->card, chip->dev); |
243 | 243 | ||
244 | if (snd_vxpocket_assign_resources(chip, link->io.BasePort1, link->irq) < 0) | 244 | if (snd_vxpocket_assign_resources(chip, link->resource[0]->start, |
245 | link->irq) < 0) | ||
245 | goto failed; | 246 | goto failed; |
246 | 247 | ||
247 | return 0; | 248 | return 0; |
diff --git a/sound/pcmcia/vx/vxpocket.h b/sound/pcmcia/vx/vxpocket.h index ea4df16a28ef..d9110669d042 100644 --- a/sound/pcmcia/vx/vxpocket.h +++ b/sound/pcmcia/vx/vxpocket.h | |||
@@ -23,7 +23,6 @@ | |||
23 | 23 | ||
24 | #include <sound/vx_core.h> | 24 | #include <sound/vx_core.h> |
25 | 25 | ||
26 | #include <pcmcia/cs_types.h> | ||
27 | #include <pcmcia/cs.h> | 26 | #include <pcmcia/cs.h> |
28 | #include <pcmcia/cistpl.h> | 27 | #include <pcmcia/cistpl.h> |
29 | #include <pcmcia/ds.h> | 28 | #include <pcmcia/ds.h> |
diff --git a/sound/ppc/snd_ps3.c b/sound/ppc/snd_ps3.c index 2f12da4da561..581a670e8261 100644 --- a/sound/ppc/snd_ps3.c +++ b/sound/ppc/snd_ps3.c | |||
@@ -579,7 +579,7 @@ static int snd_ps3_delay_to_bytes(struct snd_pcm_substream *substream, | |||
579 | rate * delay_ms / 1000) | 579 | rate * delay_ms / 1000) |
580 | * substream->runtime->channels; | 580 | * substream->runtime->channels; |
581 | 581 | ||
582 | pr_debug(KERN_ERR "%s: time=%d rate=%d bytes=%ld, frames=%d, ret=%d\n", | 582 | pr_debug("%s: time=%d rate=%d bytes=%ld, frames=%d, ret=%d\n", |
583 | __func__, | 583 | __func__, |
584 | delay_ms, | 584 | delay_ms, |
585 | rate, | 585 | rate, |
diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c index 20afdf9772ee..961d98297695 100644 --- a/sound/ppc/tumbler.c +++ b/sound/ppc/tumbler.c | |||
@@ -785,7 +785,7 @@ static int snapper_set_capture_source(struct pmac_tumbler *mix) | |||
785 | if (! mix->i2c.client) | 785 | if (! mix->i2c.client) |
786 | return -ENODEV; | 786 | return -ENODEV; |
787 | if (mix->capture_source) | 787 | if (mix->capture_source) |
788 | mix->acs = mix->acs |= 2; | 788 | mix->acs |= 2; |
789 | else | 789 | else |
790 | mix->acs &= ~2; | 790 | mix->acs &= ~2; |
791 | return i2c_smbus_write_byte_data(mix->i2c.client, TAS_REG_ACS, mix->acs); | 791 | return i2c_smbus_write_byte_data(mix->i2c.client, TAS_REG_ACS, mix->acs); |
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index b1749bc67979..3e598e756e54 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig | |||
@@ -28,9 +28,13 @@ source "sound/soc/atmel/Kconfig" | |||
28 | source "sound/soc/au1x/Kconfig" | 28 | source "sound/soc/au1x/Kconfig" |
29 | source "sound/soc/blackfin/Kconfig" | 29 | source "sound/soc/blackfin/Kconfig" |
30 | source "sound/soc/davinci/Kconfig" | 30 | source "sound/soc/davinci/Kconfig" |
31 | source "sound/soc/ep93xx/Kconfig" | ||
31 | source "sound/soc/fsl/Kconfig" | 32 | source "sound/soc/fsl/Kconfig" |
32 | source "sound/soc/imx/Kconfig" | 33 | source "sound/soc/imx/Kconfig" |
34 | source "sound/soc/jz4740/Kconfig" | ||
35 | source "sound/soc/nuc900/Kconfig" | ||
33 | source "sound/soc/omap/Kconfig" | 36 | source "sound/soc/omap/Kconfig" |
37 | source "sound/soc/kirkwood/Kconfig" | ||
34 | source "sound/soc/pxa/Kconfig" | 38 | source "sound/soc/pxa/Kconfig" |
35 | source "sound/soc/s3c24xx/Kconfig" | 39 | source "sound/soc/s3c24xx/Kconfig" |
36 | source "sound/soc/s6000/Kconfig" | 40 | source "sound/soc/s6000/Kconfig" |
diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 1470141d4167..eb183443eee4 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile | |||
@@ -6,9 +6,13 @@ obj-$(CONFIG_SND_SOC) += atmel/ | |||
6 | obj-$(CONFIG_SND_SOC) += au1x/ | 6 | obj-$(CONFIG_SND_SOC) += au1x/ |
7 | obj-$(CONFIG_SND_SOC) += blackfin/ | 7 | obj-$(CONFIG_SND_SOC) += blackfin/ |
8 | obj-$(CONFIG_SND_SOC) += davinci/ | 8 | obj-$(CONFIG_SND_SOC) += davinci/ |
9 | obj-$(CONFIG_SND_SOC) += ep93xx/ | ||
9 | obj-$(CONFIG_SND_SOC) += fsl/ | 10 | obj-$(CONFIG_SND_SOC) += fsl/ |
10 | obj-$(CONFIG_SND_SOC) += imx/ | 11 | obj-$(CONFIG_SND_SOC) += imx/ |
12 | obj-$(CONFIG_SND_SOC) += jz4740/ | ||
13 | obj-$(CONFIG_SND_SOC) += nuc900/ | ||
11 | obj-$(CONFIG_SND_SOC) += omap/ | 14 | obj-$(CONFIG_SND_SOC) += omap/ |
15 | obj-$(CONFIG_SND_SOC) += kirkwood/ | ||
12 | obj-$(CONFIG_SND_SOC) += pxa/ | 16 | obj-$(CONFIG_SND_SOC) += pxa/ |
13 | obj-$(CONFIG_SND_SOC) += s3c24xx/ | 17 | obj-$(CONFIG_SND_SOC) += s3c24xx/ |
14 | obj-$(CONFIG_SND_SOC) += s6000/ | 18 | obj-$(CONFIG_SND_SOC) += s6000/ |
diff --git a/sound/soc/atmel/atmel-pcm.c b/sound/soc/atmel/atmel-pcm.c index f6b3cc04b34b..dc5249fba85c 100644 --- a/sound/soc/atmel/atmel-pcm.c +++ b/sound/soc/atmel/atmel-pcm.c | |||
@@ -77,7 +77,6 @@ struct atmel_runtime_data { | |||
77 | size_t period_size; | 77 | size_t period_size; |
78 | 78 | ||
79 | dma_addr_t period_ptr; /* physical address of next period */ | 79 | dma_addr_t period_ptr; /* physical address of next period */ |
80 | int periods; /* period index of period_ptr */ | ||
81 | 80 | ||
82 | /* PDC register save */ | 81 | /* PDC register save */ |
83 | u32 pdc_xpr_save; | 82 | u32 pdc_xpr_save; |
diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index 0b59806905d1..c85844d4845b 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c | |||
@@ -549,7 +549,6 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, | |||
549 | printk(KERN_WARNING "atmel_ssc_dai: unsupported DAI format 0x%x\n", | 549 | printk(KERN_WARNING "atmel_ssc_dai: unsupported DAI format 0x%x\n", |
550 | ssc_p->daifmt); | 550 | ssc_p->daifmt); |
551 | return -EINVAL; | 551 | return -EINVAL; |
552 | break; | ||
553 | } | 552 | } |
554 | pr_debug("atmel_ssc_hw_params: " | 553 | pr_debug("atmel_ssc_hw_params: " |
555 | "RCMR=%08x RFMR=%08x TCMR=%08x TFMR=%08x\n", | 554 | "RCMR=%08x RFMR=%08x TCMR=%08x TFMR=%08x\n", |
diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c index a61ccd2d505f..d14a5a91a465 100644 --- a/sound/soc/au1x/psc-ac97.c +++ b/sound/soc/au1x/psc-ac97.c | |||
@@ -375,12 +375,10 @@ static int __devinit au1xpsc_ac97_drvprobe(struct platform_device *pdev) | |||
375 | } | 375 | } |
376 | 376 | ||
377 | ret = -EBUSY; | 377 | ret = -EBUSY; |
378 | wd->ioarea = request_mem_region(r->start, r->end - r->start + 1, | 378 | if (!request_mem_region(r->start, resource_size(r), pdev->name)) |
379 | "au1xpsc_ac97"); | ||
380 | if (!wd->ioarea) | ||
381 | goto out0; | 379 | goto out0; |
382 | 380 | ||
383 | wd->mmio = ioremap(r->start, 0xffff); | 381 | wd->mmio = ioremap(r->start, resource_size(r)); |
384 | if (!wd->mmio) | 382 | if (!wd->mmio) |
385 | goto out1; | 383 | goto out1; |
386 | 384 | ||
@@ -410,8 +408,7 @@ static int __devinit au1xpsc_ac97_drvprobe(struct platform_device *pdev) | |||
410 | 408 | ||
411 | snd_soc_unregister_dai(&au1xpsc_ac97_dai); | 409 | snd_soc_unregister_dai(&au1xpsc_ac97_dai); |
412 | out1: | 410 | out1: |
413 | release_resource(wd->ioarea); | 411 | release_mem_region(r->start, resource_size(r)); |
414 | kfree(wd->ioarea); | ||
415 | out0: | 412 | out0: |
416 | kfree(wd); | 413 | kfree(wd); |
417 | return ret; | 414 | return ret; |
@@ -420,6 +417,7 @@ out0: | |||
420 | static int __devexit au1xpsc_ac97_drvremove(struct platform_device *pdev) | 417 | static int __devexit au1xpsc_ac97_drvremove(struct platform_device *pdev) |
421 | { | 418 | { |
422 | struct au1xpsc_audio_data *wd = platform_get_drvdata(pdev); | 419 | struct au1xpsc_audio_data *wd = platform_get_drvdata(pdev); |
420 | struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
423 | 421 | ||
424 | if (wd->dmapd) | 422 | if (wd->dmapd) |
425 | au1xpsc_pcm_destroy(wd->dmapd); | 423 | au1xpsc_pcm_destroy(wd->dmapd); |
@@ -433,8 +431,7 @@ static int __devexit au1xpsc_ac97_drvremove(struct platform_device *pdev) | |||
433 | au_sync(); | 431 | au_sync(); |
434 | 432 | ||
435 | iounmap(wd->mmio); | 433 | iounmap(wd->mmio); |
436 | release_resource(wd->ioarea); | 434 | release_mem_region(r->start, resource_size(r)); |
437 | kfree(wd->ioarea); | ||
438 | kfree(wd); | 435 | kfree(wd); |
439 | 436 | ||
440 | au1xpsc_ac97_workdata = NULL; /* MDEV */ | 437 | au1xpsc_ac97_workdata = NULL; /* MDEV */ |
diff --git a/sound/soc/au1x/psc-i2s.c b/sound/soc/au1x/psc-i2s.c index 24454c98d0ee..6083fe7799fa 100644 --- a/sound/soc/au1x/psc-i2s.c +++ b/sound/soc/au1x/psc-i2s.c | |||
@@ -321,12 +321,10 @@ static int __devinit au1xpsc_i2s_drvprobe(struct platform_device *pdev) | |||
321 | } | 321 | } |
322 | 322 | ||
323 | ret = -EBUSY; | 323 | ret = -EBUSY; |
324 | wd->ioarea = request_mem_region(r->start, r->end - r->start + 1, | 324 | if (!request_mem_region(r->start, resource_size(r), pdev->name)) |
325 | "au1xpsc_i2s"); | ||
326 | if (!wd->ioarea) | ||
327 | goto out0; | 325 | goto out0; |
328 | 326 | ||
329 | wd->mmio = ioremap(r->start, 0xffff); | 327 | wd->mmio = ioremap(r->start, resource_size(r)); |
330 | if (!wd->mmio) | 328 | if (!wd->mmio) |
331 | goto out1; | 329 | goto out1; |
332 | 330 | ||
@@ -362,8 +360,7 @@ static int __devinit au1xpsc_i2s_drvprobe(struct platform_device *pdev) | |||
362 | 360 | ||
363 | snd_soc_unregister_dai(&au1xpsc_i2s_dai); | 361 | snd_soc_unregister_dai(&au1xpsc_i2s_dai); |
364 | out1: | 362 | out1: |
365 | release_resource(wd->ioarea); | 363 | release_mem_region(r->start, resource_size(r)); |
366 | kfree(wd->ioarea); | ||
367 | out0: | 364 | out0: |
368 | kfree(wd); | 365 | kfree(wd); |
369 | return ret; | 366 | return ret; |
@@ -372,6 +369,7 @@ out0: | |||
372 | static int __devexit au1xpsc_i2s_drvremove(struct platform_device *pdev) | 369 | static int __devexit au1xpsc_i2s_drvremove(struct platform_device *pdev) |
373 | { | 370 | { |
374 | struct au1xpsc_audio_data *wd = platform_get_drvdata(pdev); | 371 | struct au1xpsc_audio_data *wd = platform_get_drvdata(pdev); |
372 | struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
375 | 373 | ||
376 | if (wd->dmapd) | 374 | if (wd->dmapd) |
377 | au1xpsc_pcm_destroy(wd->dmapd); | 375 | au1xpsc_pcm_destroy(wd->dmapd); |
@@ -384,8 +382,7 @@ static int __devexit au1xpsc_i2s_drvremove(struct platform_device *pdev) | |||
384 | au_sync(); | 382 | au_sync(); |
385 | 383 | ||
386 | iounmap(wd->mmio); | 384 | iounmap(wd->mmio); |
387 | release_resource(wd->ioarea); | 385 | release_mem_region(r->start, resource_size(r)); |
388 | kfree(wd->ioarea); | ||
389 | kfree(wd); | 386 | kfree(wd); |
390 | 387 | ||
391 | au1xpsc_i2s_workdata = NULL; /* MDEV */ | 388 | au1xpsc_i2s_workdata = NULL; /* MDEV */ |
diff --git a/sound/soc/au1x/psc.h b/sound/soc/au1x/psc.h index 32d3807d3f5a..093775d4dc3e 100644 --- a/sound/soc/au1x/psc.h +++ b/sound/soc/au1x/psc.h | |||
@@ -32,7 +32,6 @@ struct au1xpsc_audio_data { | |||
32 | unsigned long rate; | 32 | unsigned long rate; |
33 | 33 | ||
34 | unsigned long pm[2]; | 34 | unsigned long pm[2]; |
35 | struct resource *ioarea; | ||
36 | struct mutex lock; | 35 | struct mutex lock; |
37 | struct platform_device *dmapd; | 36 | struct platform_device *dmapd; |
38 | }; | 37 | }; |
diff --git a/sound/soc/blackfin/Kconfig b/sound/soc/blackfin/Kconfig index 8ef25025f3dc..3abeeddc67d3 100644 --- a/sound/soc/blackfin/Kconfig +++ b/sound/soc/blackfin/Kconfig | |||
@@ -105,13 +105,18 @@ config SND_BF5XX_RESET_GPIO_NUM | |||
105 | Set the correct GPIO for RESET the sound chip. | 105 | Set the correct GPIO for RESET the sound chip. |
106 | 106 | ||
107 | config SND_BF5XX_SOC_AD1980 | 107 | config SND_BF5XX_SOC_AD1980 |
108 | tristate "SoC AD1980/1 Audio support for BF5xx" | 108 | tristate "SoC AD1980/1 Audio support for BF5xx (Obsolete)" |
109 | depends on SND_BF5XX_AC97 | 109 | depends on SND_BF5XX_AC97 |
110 | select SND_BF5XX_SOC_AC97 | 110 | select SND_BF5XX_SOC_AC97 |
111 | select SND_SOC_AD1980 | 111 | select SND_SOC_AD1980 |
112 | help | 112 | help |
113 | Say Y if you want to add support for SoC audio on BF5xx STAMP/EZKIT. | 113 | Say Y if you want to add support for SoC audio on BF5xx STAMP/EZKIT. |
114 | 114 | ||
115 | Warning: | ||
116 | Because Analog Devices Inc. discontinued the ad1980 sound chip since | ||
117 | Sep. 2009, this ad1980 driver is not maintained, tested and supported | ||
118 | by ADI now. | ||
119 | |||
115 | config SND_BF5XX_SOC_SPORT | 120 | config SND_BF5XX_SOC_SPORT |
116 | tristate | 121 | tristate |
117 | 122 | ||
diff --git a/sound/soc/blackfin/bf5xx-ac97.c b/sound/soc/blackfin/bf5xx-ac97.c index 523b7fc33f4e..c0eba5109980 100644 --- a/sound/soc/blackfin/bf5xx-ac97.c +++ b/sound/soc/blackfin/bf5xx-ac97.c | |||
@@ -255,8 +255,7 @@ EXPORT_SYMBOL_GPL(soc_ac97_ops); | |||
255 | #ifdef CONFIG_PM | 255 | #ifdef CONFIG_PM |
256 | static int bf5xx_ac97_suspend(struct snd_soc_dai *dai) | 256 | static int bf5xx_ac97_suspend(struct snd_soc_dai *dai) |
257 | { | 257 | { |
258 | struct sport_device *sport = | 258 | struct sport_device *sport = dai->private_data; |
259 | (struct sport_device *)dai->private_data; | ||
260 | 259 | ||
261 | pr_debug("%s : sport %d\n", __func__, dai->id); | 260 | pr_debug("%s : sport %d\n", __func__, dai->id); |
262 | if (!dai->active) | 261 | if (!dai->active) |
@@ -271,8 +270,7 @@ static int bf5xx_ac97_suspend(struct snd_soc_dai *dai) | |||
271 | static int bf5xx_ac97_resume(struct snd_soc_dai *dai) | 270 | static int bf5xx_ac97_resume(struct snd_soc_dai *dai) |
272 | { | 271 | { |
273 | int ret; | 272 | int ret; |
274 | struct sport_device *sport = | 273 | struct sport_device *sport = dai->private_data; |
275 | (struct sport_device *)dai->private_data; | ||
276 | 274 | ||
277 | pr_debug("%s : sport %d\n", __func__, dai->id); | 275 | pr_debug("%s : sport %d\n", __func__, dai->id); |
278 | if (!dai->active) | 276 | if (!dai->active) |
diff --git a/sound/soc/blackfin/bf5xx-ad1980.c b/sound/soc/blackfin/bf5xx-ad1980.c index d8f591273778..92f7c327bb7a 100644 --- a/sound/soc/blackfin/bf5xx-ad1980.c +++ b/sound/soc/blackfin/bf5xx-ad1980.c | |||
@@ -26,6 +26,14 @@ | |||
26 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | 26 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
27 | */ | 27 | */ |
28 | 28 | ||
29 | /* | ||
30 | * WARNING: | ||
31 | * | ||
32 | * Because Analog Devices Inc. discontinued the ad1980 sound chip since | ||
33 | * Sep. 2009, this ad1980 driver is not maintained, tested and supported | ||
34 | * by ADI now. | ||
35 | */ | ||
36 | |||
29 | #include <linux/module.h> | 37 | #include <linux/module.h> |
30 | #include <linux/moduleparam.h> | 38 | #include <linux/moduleparam.h> |
31 | #include <linux/device.h> | 39 | #include <linux/device.h> |
@@ -109,5 +117,5 @@ module_exit(bf5xx_board_exit); | |||
109 | 117 | ||
110 | /* Module information */ | 118 | /* Module information */ |
111 | MODULE_AUTHOR("Cliff Cai"); | 119 | MODULE_AUTHOR("Cliff Cai"); |
112 | MODULE_DESCRIPTION("ALSA SoC AD1980/1 BF5xx board"); | 120 | MODULE_DESCRIPTION("ALSA SoC AD1980/1 BF5xx board (Obsolete)"); |
113 | MODULE_LICENSE("GPL"); | 121 | MODULE_LICENSE("GPL"); |
diff --git a/sound/soc/blackfin/bf5xx-tdm.c b/sound/soc/blackfin/bf5xx-tdm.c index 4b360124083e..24c14269f4bc 100644 --- a/sound/soc/blackfin/bf5xx-tdm.c +++ b/sound/soc/blackfin/bf5xx-tdm.c | |||
@@ -210,8 +210,7 @@ static int bf5xx_tdm_set_channel_map(struct snd_soc_dai *dai, | |||
210 | #ifdef CONFIG_PM | 210 | #ifdef CONFIG_PM |
211 | static int bf5xx_tdm_suspend(struct snd_soc_dai *dai) | 211 | static int bf5xx_tdm_suspend(struct snd_soc_dai *dai) |
212 | { | 212 | { |
213 | struct sport_device *sport = | 213 | struct sport_device *sport = dai->private_data; |
214 | (struct sport_device *)dai->private_data; | ||
215 | 214 | ||
216 | if (!dai->active) | 215 | if (!dai->active) |
217 | return 0; | 216 | return 0; |
@@ -225,8 +224,7 @@ static int bf5xx_tdm_suspend(struct snd_soc_dai *dai) | |||
225 | static int bf5xx_tdm_resume(struct snd_soc_dai *dai) | 224 | static int bf5xx_tdm_resume(struct snd_soc_dai *dai) |
226 | { | 225 | { |
227 | int ret; | 226 | int ret; |
228 | struct sport_device *sport = | 227 | struct sport_device *sport = dai->private_data; |
229 | (struct sport_device *)dai->private_data; | ||
230 | 228 | ||
231 | if (!dai->active) | 229 | if (!dai->active) |
232 | return 0; | 230 | return 0; |
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 5da30eb6ad00..83f5c67d3c41 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig | |||
@@ -22,9 +22,11 @@ config SND_SOC_ALL_CODECS | |||
22 | select SND_SOC_AK4642 if I2C | 22 | select SND_SOC_AK4642 if I2C |
23 | select SND_SOC_AK4671 if I2C | 23 | select SND_SOC_AK4671 if I2C |
24 | select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC | 24 | select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC |
25 | select SND_SOC_CS42L51 if I2C | ||
25 | select SND_SOC_CS4270 if I2C | 26 | select SND_SOC_CS4270 if I2C |
26 | select SND_SOC_MAX9877 if I2C | ||
27 | select SND_SOC_DA7210 if I2C | 27 | select SND_SOC_DA7210 if I2C |
28 | select SND_SOC_JZ4740 if SOC_JZ4740 | ||
29 | select SND_SOC_MAX9877 if I2C | ||
28 | select SND_SOC_PCM3008 | 30 | select SND_SOC_PCM3008 |
29 | select SND_SOC_SPDIF | 31 | select SND_SOC_SPDIF |
30 | select SND_SOC_SSM2602 if I2C | 32 | select SND_SOC_SSM2602 if I2C |
@@ -48,6 +50,7 @@ config SND_SOC_ALL_CODECS | |||
48 | select SND_SOC_WM8727 | 50 | select SND_SOC_WM8727 |
49 | select SND_SOC_WM8728 if SND_SOC_I2C_AND_SPI | 51 | select SND_SOC_WM8728 if SND_SOC_I2C_AND_SPI |
50 | select SND_SOC_WM8731 if SND_SOC_I2C_AND_SPI | 52 | select SND_SOC_WM8731 if SND_SOC_I2C_AND_SPI |
53 | select SND_SOC_WM8741 if SND_SOC_I2C_AND_SPI | ||
51 | select SND_SOC_WM8750 if SND_SOC_I2C_AND_SPI | 54 | select SND_SOC_WM8750 if SND_SOC_I2C_AND_SPI |
52 | select SND_SOC_WM8753 if SND_SOC_I2C_AND_SPI | 55 | select SND_SOC_WM8753 if SND_SOC_I2C_AND_SPI |
53 | select SND_SOC_WM8776 if SND_SOC_I2C_AND_SPI | 56 | select SND_SOC_WM8776 if SND_SOC_I2C_AND_SPI |
@@ -120,13 +123,13 @@ config SND_SOC_AK4671 | |||
120 | config SND_SOC_CQ0093VC | 123 | config SND_SOC_CQ0093VC |
121 | tristate | 124 | tristate |
122 | 125 | ||
126 | config SND_SOC_CS42L51 | ||
127 | tristate | ||
128 | |||
123 | # Cirrus Logic CS4270 Codec | 129 | # Cirrus Logic CS4270 Codec |
124 | config SND_SOC_CS4270 | 130 | config SND_SOC_CS4270 |
125 | tristate | 131 | tristate |
126 | 132 | ||
127 | config SND_SOC_DA7210 | ||
128 | tristate | ||
129 | |||
130 | # Cirrus Logic CS4270 Codec VD = 3.3V Errata | 133 | # Cirrus Logic CS4270 Codec VD = 3.3V Errata |
131 | # Select if you are affected by the errata where the part will not function | 134 | # Select if you are affected by the errata where the part will not function |
132 | # if MCLK divide-by-1.5 is selected and VD is set to 3.3V. The driver will | 135 | # if MCLK divide-by-1.5 is selected and VD is set to 3.3V. The driver will |
@@ -138,9 +141,15 @@ config SND_SOC_CS4270_VD33_ERRATA | |||
138 | config SND_SOC_CX20442 | 141 | config SND_SOC_CX20442 |
139 | tristate | 142 | tristate |
140 | 143 | ||
144 | config SND_SOC_JZ4740_CODEC | ||
145 | tristate | ||
146 | |||
141 | config SND_SOC_L3 | 147 | config SND_SOC_L3 |
142 | tristate | 148 | tristate |
143 | 149 | ||
150 | config SND_SOC_DA7210 | ||
151 | tristate | ||
152 | |||
144 | config SND_SOC_PCM3008 | 153 | config SND_SOC_PCM3008 |
145 | tristate | 154 | tristate |
146 | 155 | ||
@@ -206,6 +215,9 @@ config SND_SOC_WM8728 | |||
206 | config SND_SOC_WM8731 | 215 | config SND_SOC_WM8731 |
207 | tristate | 216 | tristate |
208 | 217 | ||
218 | config SND_SOC_WM8741 | ||
219 | tristate | ||
220 | |||
209 | config SND_SOC_WM8750 | 221 | config SND_SOC_WM8750 |
210 | tristate | 222 | tristate |
211 | 223 | ||
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 91429eab0707..53524095759c 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile | |||
@@ -9,6 +9,7 @@ snd-soc-ak4535-objs := ak4535.o | |||
9 | snd-soc-ak4642-objs := ak4642.o | 9 | snd-soc-ak4642-objs := ak4642.o |
10 | snd-soc-ak4671-objs := ak4671.o | 10 | snd-soc-ak4671-objs := ak4671.o |
11 | snd-soc-cq93vc-objs := cq93vc.o | 11 | snd-soc-cq93vc-objs := cq93vc.o |
12 | snd-soc-cs42l51-objs := cs42l51.o | ||
12 | snd-soc-cs4270-objs := cs4270.o | 13 | snd-soc-cs4270-objs := cs4270.o |
13 | snd-soc-cx20442-objs := cx20442.o | 14 | snd-soc-cx20442-objs := cx20442.o |
14 | snd-soc-da7210-objs := da7210.o | 15 | snd-soc-da7210-objs := da7210.o |
@@ -34,6 +35,7 @@ snd-soc-wm8711-objs := wm8711.o | |||
34 | snd-soc-wm8727-objs := wm8727.o | 35 | snd-soc-wm8727-objs := wm8727.o |
35 | snd-soc-wm8728-objs := wm8728.o | 36 | snd-soc-wm8728-objs := wm8728.o |
36 | snd-soc-wm8731-objs := wm8731.o | 37 | snd-soc-wm8731-objs := wm8731.o |
38 | snd-soc-wm8741-objs := wm8741.o | ||
37 | snd-soc-wm8750-objs := wm8750.o | 39 | snd-soc-wm8750-objs := wm8750.o |
38 | snd-soc-wm8753-objs := wm8753.o | 40 | snd-soc-wm8753-objs := wm8753.o |
39 | snd-soc-wm8776-objs := wm8776.o | 41 | snd-soc-wm8776-objs := wm8776.o |
@@ -56,6 +58,7 @@ snd-soc-wm9705-objs := wm9705.o | |||
56 | snd-soc-wm9712-objs := wm9712.o | 58 | snd-soc-wm9712-objs := wm9712.o |
57 | snd-soc-wm9713-objs := wm9713.o | 59 | snd-soc-wm9713-objs := wm9713.o |
58 | snd-soc-wm-hubs-objs := wm_hubs.o | 60 | snd-soc-wm-hubs-objs := wm_hubs.o |
61 | snd-soc-jz4740-codec-objs := jz4740.o | ||
59 | 62 | ||
60 | # Amp | 63 | # Amp |
61 | snd-soc-max9877-objs := max9877.o | 64 | snd-soc-max9877-objs := max9877.o |
@@ -74,10 +77,12 @@ obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o | |||
74 | obj-$(CONFIG_SND_SOC_AK4642) += snd-soc-ak4642.o | 77 | obj-$(CONFIG_SND_SOC_AK4642) += snd-soc-ak4642.o |
75 | obj-$(CONFIG_SND_SOC_AK4671) += snd-soc-ak4671.o | 78 | obj-$(CONFIG_SND_SOC_AK4671) += snd-soc-ak4671.o |
76 | obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o | 79 | obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o |
80 | obj-$(CONFIG_SND_SOC_CS42L51) += snd-soc-cs42l51.o | ||
77 | obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o | 81 | obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o |
78 | obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o | 82 | obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o |
79 | obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o | 83 | obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o |
80 | obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o | 84 | obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o |
85 | obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o | ||
81 | obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o | 86 | obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o |
82 | obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif.o | 87 | obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif.o |
83 | obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o | 88 | obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o |
@@ -99,6 +104,7 @@ obj-$(CONFIG_SND_SOC_WM8711) += snd-soc-wm8711.o | |||
99 | obj-$(CONFIG_SND_SOC_WM8727) += snd-soc-wm8727.o | 104 | obj-$(CONFIG_SND_SOC_WM8727) += snd-soc-wm8727.o |
100 | obj-$(CONFIG_SND_SOC_WM8728) += snd-soc-wm8728.o | 105 | obj-$(CONFIG_SND_SOC_WM8728) += snd-soc-wm8728.o |
101 | obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o | 106 | obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o |
107 | obj-$(CONFIG_SND_SOC_WM8741) += snd-soc-wm8741.o | ||
102 | obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o | 108 | obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o |
103 | obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o | 109 | obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o |
104 | obj-$(CONFIG_SND_SOC_WM8776) += snd-soc-wm8776.o | 110 | obj-$(CONFIG_SND_SOC_WM8776) += snd-soc-wm8776.o |
diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c index 217538423225..a01006c8c606 100644 --- a/sound/soc/codecs/ad1836.c +++ b/sound/soc/codecs/ad1836.c | |||
@@ -272,6 +272,7 @@ static int ad1836_register(struct ad1836_priv *ad1836) | |||
272 | 272 | ||
273 | if (ad1836_codec) { | 273 | if (ad1836_codec) { |
274 | dev_err(codec->dev, "Another ad1836 is registered\n"); | 274 | dev_err(codec->dev, "Another ad1836 is registered\n"); |
275 | kfree(ad1836); | ||
275 | return -EINVAL; | 276 | return -EINVAL; |
276 | } | 277 | } |
277 | 278 | ||
diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c index c8ca1142b2f4..1def75e4862f 100644 --- a/sound/soc/codecs/ad193x.c +++ b/sound/soc/codecs/ad193x.c | |||
@@ -24,6 +24,7 @@ | |||
24 | 24 | ||
25 | /* codec private data */ | 25 | /* codec private data */ |
26 | struct ad193x_priv { | 26 | struct ad193x_priv { |
27 | unsigned int sysclk; | ||
27 | struct snd_soc_codec codec; | 28 | struct snd_soc_codec codec; |
28 | u8 reg_cache[AD193X_NUM_REGS]; | 29 | u8 reg_cache[AD193X_NUM_REGS]; |
29 | }; | 30 | }; |
@@ -251,15 +252,32 @@ static int ad193x_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
251 | return 0; | 252 | return 0; |
252 | } | 253 | } |
253 | 254 | ||
255 | static int ad193x_set_dai_sysclk(struct snd_soc_dai *codec_dai, | ||
256 | int clk_id, unsigned int freq, int dir) | ||
257 | { | ||
258 | struct snd_soc_codec *codec = codec_dai->codec; | ||
259 | struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec); | ||
260 | switch (freq) { | ||
261 | case 12288000: | ||
262 | case 18432000: | ||
263 | case 24576000: | ||
264 | case 36864000: | ||
265 | ad193x->sysclk = freq; | ||
266 | return 0; | ||
267 | } | ||
268 | return -EINVAL; | ||
269 | } | ||
270 | |||
254 | static int ad193x_hw_params(struct snd_pcm_substream *substream, | 271 | static int ad193x_hw_params(struct snd_pcm_substream *substream, |
255 | struct snd_pcm_hw_params *params, | 272 | struct snd_pcm_hw_params *params, |
256 | struct snd_soc_dai *dai) | 273 | struct snd_soc_dai *dai) |
257 | { | 274 | { |
258 | int word_len = 0, reg = 0; | 275 | int word_len = 0, reg = 0, master_rate = 0; |
259 | 276 | ||
260 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 277 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
261 | struct snd_soc_device *socdev = rtd->socdev; | 278 | struct snd_soc_device *socdev = rtd->socdev; |
262 | struct snd_soc_codec *codec = socdev->card->codec; | 279 | struct snd_soc_codec *codec = socdev->card->codec; |
280 | struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec); | ||
263 | 281 | ||
264 | /* bit size */ | 282 | /* bit size */ |
265 | switch (params_format(params)) { | 283 | switch (params_format(params)) { |
@@ -275,6 +293,25 @@ static int ad193x_hw_params(struct snd_pcm_substream *substream, | |||
275 | break; | 293 | break; |
276 | } | 294 | } |
277 | 295 | ||
296 | switch (ad193x->sysclk) { | ||
297 | case 12288000: | ||
298 | master_rate = AD193X_PLL_INPUT_256; | ||
299 | break; | ||
300 | case 18432000: | ||
301 | master_rate = AD193X_PLL_INPUT_384; | ||
302 | break; | ||
303 | case 24576000: | ||
304 | master_rate = AD193X_PLL_INPUT_512; | ||
305 | break; | ||
306 | case 36864000: | ||
307 | master_rate = AD193X_PLL_INPUT_768; | ||
308 | break; | ||
309 | } | ||
310 | |||
311 | reg = snd_soc_read(codec, AD193X_PLL_CLK_CTRL0); | ||
312 | reg = (reg & AD193X_PLL_INPUT_MASK) | master_rate; | ||
313 | snd_soc_write(codec, AD193X_PLL_CLK_CTRL0, reg); | ||
314 | |||
278 | reg = snd_soc_read(codec, AD193X_DAC_CTRL2); | 315 | reg = snd_soc_read(codec, AD193X_DAC_CTRL2); |
279 | reg = (reg & (~AD193X_DAC_WORD_LEN_MASK)) | word_len; | 316 | reg = (reg & (~AD193X_DAC_WORD_LEN_MASK)) | word_len; |
280 | snd_soc_write(codec, AD193X_DAC_CTRL2, reg); | 317 | snd_soc_write(codec, AD193X_DAC_CTRL2, reg); |
@@ -348,6 +385,7 @@ static int ad193x_bus_probe(struct device *dev, void *ctrl_data, int bus_type) | |||
348 | /* pll input: mclki/xi */ | 385 | /* pll input: mclki/xi */ |
349 | snd_soc_write(codec, AD193X_PLL_CLK_CTRL0, 0x99); /* mclk=24.576Mhz: 0x9D; mclk=12.288Mhz: 0x99 */ | 386 | snd_soc_write(codec, AD193X_PLL_CLK_CTRL0, 0x99); /* mclk=24.576Mhz: 0x9D; mclk=12.288Mhz: 0x99 */ |
350 | snd_soc_write(codec, AD193X_PLL_CLK_CTRL1, 0x04); | 387 | snd_soc_write(codec, AD193X_PLL_CLK_CTRL1, 0x04); |
388 | ad193x->sysclk = 12288000; | ||
351 | 389 | ||
352 | ret = snd_soc_register_codec(codec); | 390 | ret = snd_soc_register_codec(codec); |
353 | if (ret != 0) { | 391 | if (ret != 0) { |
@@ -383,6 +421,7 @@ static struct snd_soc_dai_ops ad193x_dai_ops = { | |||
383 | .hw_params = ad193x_hw_params, | 421 | .hw_params = ad193x_hw_params, |
384 | .digital_mute = ad193x_mute, | 422 | .digital_mute = ad193x_mute, |
385 | .set_tdm_slot = ad193x_set_tdm_slot, | 423 | .set_tdm_slot = ad193x_set_tdm_slot, |
424 | .set_sysclk = ad193x_set_dai_sysclk, | ||
386 | .set_fmt = ad193x_set_dai_fmt, | 425 | .set_fmt = ad193x_set_dai_fmt, |
387 | }; | 426 | }; |
388 | 427 | ||
diff --git a/sound/soc/codecs/ad193x.h b/sound/soc/codecs/ad193x.h index a03c880d52f9..654ba64ae04c 100644 --- a/sound/soc/codecs/ad193x.h +++ b/sound/soc/codecs/ad193x.h | |||
@@ -11,6 +11,11 @@ | |||
11 | 11 | ||
12 | #define AD193X_PLL_CLK_CTRL0 0x800 | 12 | #define AD193X_PLL_CLK_CTRL0 0x800 |
13 | #define AD193X_PLL_POWERDOWN 0x01 | 13 | #define AD193X_PLL_POWERDOWN 0x01 |
14 | #define AD193X_PLL_INPUT_MASK (~0x6) | ||
15 | #define AD193X_PLL_INPUT_256 (0 << 1) | ||
16 | #define AD193X_PLL_INPUT_384 (1 << 1) | ||
17 | #define AD193X_PLL_INPUT_512 (2 << 1) | ||
18 | #define AD193X_PLL_INPUT_768 (3 << 1) | ||
14 | #define AD193X_PLL_CLK_CTRL1 0x801 | 19 | #define AD193X_PLL_CLK_CTRL1 0x801 |
15 | #define AD193X_DAC_CTRL0 0x802 | 20 | #define AD193X_DAC_CTRL0 0x802 |
16 | #define AD193X_DAC_POWERDOWN 0x01 | 21 | #define AD193X_DAC_POWERDOWN 0x01 |
diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c index 042072738cdc..70cfaec3be2c 100644 --- a/sound/soc/codecs/ad1980.c +++ b/sound/soc/codecs/ad1980.c | |||
@@ -11,6 +11,14 @@ | |||
11 | * option) any later version. | 11 | * option) any later version. |
12 | */ | 12 | */ |
13 | 13 | ||
14 | /* | ||
15 | * WARNING: | ||
16 | * | ||
17 | * Because Analog Devices Inc. discontinued the ad1980 sound chip since | ||
18 | * Sep. 2009, this ad1980 driver is not maintained, tested and supported | ||
19 | * by ADI now. | ||
20 | */ | ||
21 | |||
14 | #include <linux/init.h> | 22 | #include <linux/init.h> |
15 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
16 | #include <linux/module.h> | 24 | #include <linux/module.h> |
@@ -298,6 +306,6 @@ struct snd_soc_codec_device soc_codec_dev_ad1980 = { | |||
298 | }; | 306 | }; |
299 | EXPORT_SYMBOL_GPL(soc_codec_dev_ad1980); | 307 | EXPORT_SYMBOL_GPL(soc_codec_dev_ad1980); |
300 | 308 | ||
301 | MODULE_DESCRIPTION("ASoC ad1980 driver"); | 309 | MODULE_DESCRIPTION("ASoC ad1980 driver (Obsolete)"); |
302 | MODULE_AUTHOR("Roy Huang, Cliff Cai"); | 310 | MODULE_AUTHOR("Roy Huang, Cliff Cai"); |
303 | MODULE_LICENSE("GPL"); | 311 | MODULE_LICENSE("GPL"); |
diff --git a/sound/soc/codecs/ad1980.h b/sound/soc/codecs/ad1980.h index db6c8500d66b..538f37c90806 100644 --- a/sound/soc/codecs/ad1980.h +++ b/sound/soc/codecs/ad1980.h | |||
@@ -1,5 +1,11 @@ | |||
1 | /* | 1 | /* |
2 | * ad1980.h -- ad1980 Soc Audio driver | 2 | * ad1980.h -- ad1980 Soc Audio driver |
3 | * | ||
4 | * WARNING: | ||
5 | * | ||
6 | * Because Analog Devices Inc. discontinued the ad1980 sound chip since | ||
7 | * Sep. 2009, this ad1980 driver is not maintained, tested and supported | ||
8 | * by ADI now. | ||
3 | */ | 9 | */ |
4 | 10 | ||
5 | #ifndef _AD1980_H | 11 | #ifndef _AD1980_H |
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index 7528a54102b5..3d7dc55305ec 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c | |||
@@ -22,20 +22,13 @@ | |||
22 | * AK4643 is tested. | 22 | * AK4643 is tested. |
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/moduleparam.h> | ||
27 | #include <linux/init.h> | ||
28 | #include <linux/delay.h> | 25 | #include <linux/delay.h> |
29 | #include <linux/pm.h> | ||
30 | #include <linux/i2c.h> | 26 | #include <linux/i2c.h> |
31 | #include <linux/platform_device.h> | 27 | #include <linux/platform_device.h> |
32 | #include <linux/slab.h> | 28 | #include <linux/slab.h> |
33 | #include <sound/core.h> | ||
34 | #include <sound/pcm.h> | ||
35 | #include <sound/pcm_params.h> | ||
36 | #include <sound/soc.h> | ||
37 | #include <sound/soc-dapm.h> | 29 | #include <sound/soc-dapm.h> |
38 | #include <sound/initval.h> | 30 | #include <sound/initval.h> |
31 | #include <sound/tlv.h> | ||
39 | 32 | ||
40 | #include "ak4642.h" | 33 | #include "ak4642.h" |
41 | 34 | ||
@@ -111,6 +104,23 @@ | |||
111 | 104 | ||
112 | struct snd_soc_codec_device soc_codec_dev_ak4642; | 105 | struct snd_soc_codec_device soc_codec_dev_ak4642; |
113 | 106 | ||
107 | /* | ||
108 | * Playback Volume (table 39) | ||
109 | * | ||
110 | * max : 0x00 : +12.0 dB | ||
111 | * ( 0.5 dB step ) | ||
112 | * min : 0xFE : -115.0 dB | ||
113 | * mute: 0xFF | ||
114 | */ | ||
115 | static const DECLARE_TLV_DB_SCALE(out_tlv, -11500, 50, 1); | ||
116 | |||
117 | static const struct snd_kcontrol_new ak4642_snd_controls[] = { | ||
118 | |||
119 | SOC_DOUBLE_R_TLV("Digital Playback Volume", L_DVC, R_DVC, | ||
120 | 0, 0xFF, 1, out_tlv), | ||
121 | }; | ||
122 | |||
123 | |||
114 | /* codec private data */ | 124 | /* codec private data */ |
115 | struct ak4642_priv { | 125 | struct ak4642_priv { |
116 | struct snd_soc_codec codec; | 126 | struct snd_soc_codec codec; |
@@ -204,7 +214,6 @@ static int ak4642_dai_startup(struct snd_pcm_substream *substream, | |||
204 | * | 214 | * |
205 | * PLL, Master Mode | 215 | * PLL, Master Mode |
206 | * Audio I/F Format :MSB justified (ADC & DAC) | 216 | * Audio I/F Format :MSB justified (ADC & DAC) |
207 | * Digital Volume: -8dB | ||
208 | * Bass Boost Level : Middle | 217 | * Bass Boost Level : Middle |
209 | * | 218 | * |
210 | * This operation came from example code of | 219 | * This operation came from example code of |
@@ -214,8 +223,6 @@ static int ak4642_dai_startup(struct snd_pcm_substream *substream, | |||
214 | ak4642_write(codec, 0x0e, 0x19); | 223 | ak4642_write(codec, 0x0e, 0x19); |
215 | ak4642_write(codec, 0x09, 0x91); | 224 | ak4642_write(codec, 0x09, 0x91); |
216 | ak4642_write(codec, 0x0c, 0x91); | 225 | ak4642_write(codec, 0x0c, 0x91); |
217 | ak4642_write(codec, 0x0a, 0x28); | ||
218 | ak4642_write(codec, 0x0d, 0x28); | ||
219 | ak4642_write(codec, 0x00, 0x64); | 226 | ak4642_write(codec, 0x00, 0x64); |
220 | snd_soc_update_bits(codec, PW_MGMT2, PMHP_MASK, PMHP); | 227 | snd_soc_update_bits(codec, PW_MGMT2, PMHP_MASK, PMHP); |
221 | snd_soc_update_bits(codec, PW_MGMT2, HPMTN, HPMTN); | 228 | snd_soc_update_bits(codec, PW_MGMT2, HPMTN, HPMTN); |
@@ -491,8 +498,10 @@ static int ak4642_i2c_probe(struct i2c_client *i2c, | |||
491 | codec->control_data = i2c; | 498 | codec->control_data = i2c; |
492 | 499 | ||
493 | ret = ak4642_init(ak4642); | 500 | ret = ak4642_init(ak4642); |
494 | if (ret < 0) | 501 | if (ret < 0) { |
495 | printk(KERN_ERR "failed to initialise AK4642\n"); | 502 | printk(KERN_ERR "failed to initialise AK4642\n"); |
503 | kfree(ak4642); | ||
504 | } | ||
496 | 505 | ||
497 | return ret; | 506 | return ret; |
498 | } | 507 | } |
@@ -548,6 +557,9 @@ static int ak4642_probe(struct platform_device *pdev) | |||
548 | goto pcm_err; | 557 | goto pcm_err; |
549 | } | 558 | } |
550 | 559 | ||
560 | snd_soc_add_controls(ak4642_codec, ak4642_snd_controls, | ||
561 | ARRAY_SIZE(ak4642_snd_controls)); | ||
562 | |||
551 | dev_info(&pdev->dev, "AK4642 Audio Codec %s", AK4642_VERSION); | 563 | dev_info(&pdev->dev, "AK4642 Audio Codec %s", AK4642_VERSION); |
552 | return ret; | 564 | return ret; |
553 | 565 | ||
diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c new file mode 100644 index 000000000000..dd9b8550c402 --- /dev/null +++ b/sound/soc/codecs/cs42l51.c | |||
@@ -0,0 +1,763 @@ | |||
1 | /* | ||
2 | * cs42l51.c | ||
3 | * | ||
4 | * ASoC Driver for Cirrus Logic CS42L51 codecs | ||
5 | * | ||
6 | * Copyright (c) 2010 Arnaud Patard <apatard@mandriva.com> | ||
7 | * | ||
8 | * Based on cs4270.c - Copyright (c) Freescale Semiconductor | ||
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 | * 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 | * For now: | ||
20 | * - Only I2C is support. Not SPI | ||
21 | * - master mode *NOT* supported | ||
22 | */ | ||
23 | |||
24 | #include <linux/module.h> | ||
25 | #include <linux/platform_device.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <sound/core.h> | ||
28 | #include <sound/soc.h> | ||
29 | #include <sound/soc-dapm.h> | ||
30 | #include <sound/tlv.h> | ||
31 | #include <sound/initval.h> | ||
32 | #include <sound/pcm_params.h> | ||
33 | #include <sound/pcm.h> | ||
34 | #include <linux/i2c.h> | ||
35 | |||
36 | #include "cs42l51.h" | ||
37 | |||
38 | enum master_slave_mode { | ||
39 | MODE_SLAVE, | ||
40 | MODE_SLAVE_AUTO, | ||
41 | MODE_MASTER, | ||
42 | }; | ||
43 | |||
44 | struct cs42l51_private { | ||
45 | unsigned int mclk; | ||
46 | unsigned int audio_mode; /* The mode (I2S or left-justified) */ | ||
47 | enum master_slave_mode func; | ||
48 | struct snd_soc_codec codec; | ||
49 | u8 reg_cache[CS42L51_NUMREGS]; | ||
50 | }; | ||
51 | |||
52 | static struct snd_soc_codec *cs42l51_codec; | ||
53 | |||
54 | #define CS42L51_FORMATS ( \ | ||
55 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \ | ||
56 | SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \ | ||
57 | SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \ | ||
58 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE) | ||
59 | |||
60 | static int cs42l51_fill_cache(struct snd_soc_codec *codec) | ||
61 | { | ||
62 | u8 *cache = codec->reg_cache + 1; | ||
63 | struct i2c_client *i2c_client = codec->control_data; | ||
64 | s32 length; | ||
65 | |||
66 | length = i2c_smbus_read_i2c_block_data(i2c_client, | ||
67 | CS42L51_FIRSTREG | 0x80, CS42L51_NUMREGS, cache); | ||
68 | if (length != CS42L51_NUMREGS) { | ||
69 | dev_err(&i2c_client->dev, | ||
70 | "I2C read failure, addr=0x%x (ret=%d vs %d)\n", | ||
71 | i2c_client->addr, length, CS42L51_NUMREGS); | ||
72 | return -EIO; | ||
73 | } | ||
74 | |||
75 | return 0; | ||
76 | } | ||
77 | |||
78 | static int cs42l51_i2c_probe(struct i2c_client *i2c_client, | ||
79 | const struct i2c_device_id *id) | ||
80 | { | ||
81 | struct snd_soc_codec *codec; | ||
82 | struct cs42l51_private *cs42l51; | ||
83 | int ret = 0; | ||
84 | int reg; | ||
85 | |||
86 | if (cs42l51_codec) | ||
87 | return -EBUSY; | ||
88 | |||
89 | /* Verify that we have a CS42L51 */ | ||
90 | ret = i2c_smbus_read_byte_data(i2c_client, CS42L51_CHIP_REV_ID); | ||
91 | if (ret < 0) { | ||
92 | dev_err(&i2c_client->dev, "failed to read I2C\n"); | ||
93 | goto error; | ||
94 | } | ||
95 | |||
96 | if ((ret != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_A)) && | ||
97 | (ret != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_B))) { | ||
98 | dev_err(&i2c_client->dev, "Invalid chip id\n"); | ||
99 | ret = -ENODEV; | ||
100 | goto error; | ||
101 | } | ||
102 | |||
103 | dev_info(&i2c_client->dev, "found device cs42l51 rev %d\n", | ||
104 | ret & 7); | ||
105 | |||
106 | cs42l51 = kzalloc(sizeof(struct cs42l51_private), GFP_KERNEL); | ||
107 | if (!cs42l51) { | ||
108 | dev_err(&i2c_client->dev, "could not allocate codec\n"); | ||
109 | return -ENOMEM; | ||
110 | } | ||
111 | codec = &cs42l51->codec; | ||
112 | |||
113 | mutex_init(&codec->mutex); | ||
114 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
115 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
116 | |||
117 | codec->dev = &i2c_client->dev; | ||
118 | codec->name = "CS42L51"; | ||
119 | codec->owner = THIS_MODULE; | ||
120 | codec->dai = &cs42l51_dai; | ||
121 | codec->num_dai = 1; | ||
122 | snd_soc_codec_set_drvdata(codec, cs42l51); | ||
123 | |||
124 | codec->control_data = i2c_client; | ||
125 | codec->reg_cache = cs42l51->reg_cache; | ||
126 | codec->reg_cache_size = CS42L51_NUMREGS; | ||
127 | i2c_set_clientdata(i2c_client, codec); | ||
128 | |||
129 | ret = cs42l51_fill_cache(codec); | ||
130 | if (ret < 0) { | ||
131 | dev_err(&i2c_client->dev, "failed to fill register cache\n"); | ||
132 | goto error_alloc; | ||
133 | } | ||
134 | |||
135 | ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C); | ||
136 | if (ret < 0) { | ||
137 | dev_err(&i2c_client->dev, "Failed to set cache I/O: %d\n", ret); | ||
138 | goto error_alloc; | ||
139 | } | ||
140 | |||
141 | /* | ||
142 | * DAC configuration | ||
143 | * - Use signal processor | ||
144 | * - auto mute | ||
145 | * - vol changes immediate | ||
146 | * - no de-emphasize | ||
147 | */ | ||
148 | reg = CS42L51_DAC_CTL_DATA_SEL(1) | ||
149 | | CS42L51_DAC_CTL_AMUTE | CS42L51_DAC_CTL_DACSZ(0); | ||
150 | ret = snd_soc_write(codec, CS42L51_DAC_CTL, reg); | ||
151 | if (ret < 0) | ||
152 | goto error_alloc; | ||
153 | |||
154 | cs42l51_dai.dev = codec->dev; | ||
155 | cs42l51_codec = codec; | ||
156 | |||
157 | ret = snd_soc_register_codec(codec); | ||
158 | if (ret != 0) { | ||
159 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); | ||
160 | goto error_alloc; | ||
161 | } | ||
162 | |||
163 | ret = snd_soc_register_dai(&cs42l51_dai); | ||
164 | if (ret < 0) { | ||
165 | dev_err(&i2c_client->dev, "failed to register DAIe\n"); | ||
166 | goto error_reg; | ||
167 | } | ||
168 | |||
169 | return 0; | ||
170 | |||
171 | error_reg: | ||
172 | snd_soc_unregister_codec(codec); | ||
173 | error_alloc: | ||
174 | kfree(cs42l51); | ||
175 | error: | ||
176 | return ret; | ||
177 | } | ||
178 | |||
179 | static int cs42l51_i2c_remove(struct i2c_client *client) | ||
180 | { | ||
181 | struct cs42l51_private *cs42l51 = i2c_get_clientdata(client); | ||
182 | snd_soc_unregister_dai(&cs42l51_dai); | ||
183 | snd_soc_unregister_codec(cs42l51_codec); | ||
184 | cs42l51_codec = NULL; | ||
185 | kfree(cs42l51); | ||
186 | return 0; | ||
187 | } | ||
188 | |||
189 | |||
190 | static const struct i2c_device_id cs42l51_id[] = { | ||
191 | {"cs42l51", 0}, | ||
192 | {} | ||
193 | }; | ||
194 | MODULE_DEVICE_TABLE(i2c, cs42l51_id); | ||
195 | |||
196 | static struct i2c_driver cs42l51_i2c_driver = { | ||
197 | .driver = { | ||
198 | .name = "CS42L51 I2C", | ||
199 | .owner = THIS_MODULE, | ||
200 | }, | ||
201 | .id_table = cs42l51_id, | ||
202 | .probe = cs42l51_i2c_probe, | ||
203 | .remove = cs42l51_i2c_remove, | ||
204 | }; | ||
205 | |||
206 | static int cs42l51_get_chan_mix(struct snd_kcontrol *kcontrol, | ||
207 | struct snd_ctl_elem_value *ucontrol) | ||
208 | { | ||
209 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
210 | unsigned long value = snd_soc_read(codec, CS42L51_PCM_MIXER)&3; | ||
211 | |||
212 | switch (value) { | ||
213 | default: | ||
214 | case 0: | ||
215 | ucontrol->value.integer.value[0] = 0; | ||
216 | break; | ||
217 | /* same value : (L+R)/2 and (R+L)/2 */ | ||
218 | case 1: | ||
219 | case 2: | ||
220 | ucontrol->value.integer.value[0] = 1; | ||
221 | break; | ||
222 | case 3: | ||
223 | ucontrol->value.integer.value[0] = 2; | ||
224 | break; | ||
225 | } | ||
226 | |||
227 | return 0; | ||
228 | } | ||
229 | |||
230 | #define CHAN_MIX_NORMAL 0x00 | ||
231 | #define CHAN_MIX_BOTH 0x55 | ||
232 | #define CHAN_MIX_SWAP 0xFF | ||
233 | |||
234 | static int cs42l51_set_chan_mix(struct snd_kcontrol *kcontrol, | ||
235 | struct snd_ctl_elem_value *ucontrol) | ||
236 | { | ||
237 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
238 | unsigned char val; | ||
239 | |||
240 | switch (ucontrol->value.integer.value[0]) { | ||
241 | default: | ||
242 | case 0: | ||
243 | val = CHAN_MIX_NORMAL; | ||
244 | break; | ||
245 | case 1: | ||
246 | val = CHAN_MIX_BOTH; | ||
247 | break; | ||
248 | case 2: | ||
249 | val = CHAN_MIX_SWAP; | ||
250 | break; | ||
251 | } | ||
252 | |||
253 | snd_soc_write(codec, CS42L51_PCM_MIXER, val); | ||
254 | |||
255 | return 1; | ||
256 | } | ||
257 | |||
258 | static const DECLARE_TLV_DB_SCALE(adc_pcm_tlv, -5150, 50, 0); | ||
259 | static const DECLARE_TLV_DB_SCALE(tone_tlv, -1050, 150, 0); | ||
260 | /* This is a lie. after -102 db, it stays at -102 */ | ||
261 | /* maybe a range would be better */ | ||
262 | static const DECLARE_TLV_DB_SCALE(aout_tlv, -11550, 50, 0); | ||
263 | |||
264 | static const DECLARE_TLV_DB_SCALE(boost_tlv, 1600, 1600, 0); | ||
265 | static const char *chan_mix[] = { | ||
266 | "L R", | ||
267 | "L+R", | ||
268 | "R L", | ||
269 | }; | ||
270 | |||
271 | static const struct soc_enum cs42l51_chan_mix = | ||
272 | SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(chan_mix), chan_mix); | ||
273 | |||
274 | static const struct snd_kcontrol_new cs42l51_snd_controls[] = { | ||
275 | SOC_DOUBLE_R_SX_TLV("PCM Playback Volume", | ||
276 | CS42L51_PCMA_VOL, CS42L51_PCMB_VOL, | ||
277 | 7, 0xffffff99, 0x18, adc_pcm_tlv), | ||
278 | SOC_DOUBLE_R("PCM Playback Switch", | ||
279 | CS42L51_PCMA_VOL, CS42L51_PCMB_VOL, 7, 1, 1), | ||
280 | SOC_DOUBLE_R_SX_TLV("Analog Playback Volume", | ||
281 | CS42L51_AOUTA_VOL, CS42L51_AOUTB_VOL, | ||
282 | 8, 0xffffff19, 0x18, aout_tlv), | ||
283 | SOC_DOUBLE_R_SX_TLV("ADC Mixer Volume", | ||
284 | CS42L51_ADCA_VOL, CS42L51_ADCB_VOL, | ||
285 | 7, 0xffffff99, 0x18, adc_pcm_tlv), | ||
286 | SOC_DOUBLE_R("ADC Mixer Switch", | ||
287 | CS42L51_ADCA_VOL, CS42L51_ADCB_VOL, 7, 1, 1), | ||
288 | SOC_SINGLE("Playback Deemphasis Switch", CS42L51_DAC_CTL, 3, 1, 0), | ||
289 | SOC_SINGLE("Auto-Mute Switch", CS42L51_DAC_CTL, 2, 1, 0), | ||
290 | SOC_SINGLE("Soft Ramp Switch", CS42L51_DAC_CTL, 1, 1, 0), | ||
291 | SOC_SINGLE("Zero Cross Switch", CS42L51_DAC_CTL, 0, 0, 0), | ||
292 | SOC_DOUBLE_TLV("Mic Boost Volume", | ||
293 | CS42L51_MIC_CTL, 0, 1, 1, 0, boost_tlv), | ||
294 | SOC_SINGLE_TLV("Bass Volume", CS42L51_TONE_CTL, 0, 0xf, 1, tone_tlv), | ||
295 | SOC_SINGLE_TLV("Treble Volume", CS42L51_TONE_CTL, 4, 0xf, 1, tone_tlv), | ||
296 | SOC_ENUM_EXT("PCM channel mixer", | ||
297 | cs42l51_chan_mix, | ||
298 | cs42l51_get_chan_mix, cs42l51_set_chan_mix), | ||
299 | }; | ||
300 | |||
301 | /* | ||
302 | * to power down, one must: | ||
303 | * 1.) Enable the PDN bit | ||
304 | * 2.) enable power-down for the select channels | ||
305 | * 3.) disable the PDN bit. | ||
306 | */ | ||
307 | static int cs42l51_pdn_event(struct snd_soc_dapm_widget *w, | ||
308 | struct snd_kcontrol *kcontrol, int event) | ||
309 | { | ||
310 | unsigned long value; | ||
311 | |||
312 | value = snd_soc_read(w->codec, CS42L51_POWER_CTL1); | ||
313 | value &= ~CS42L51_POWER_CTL1_PDN; | ||
314 | |||
315 | switch (event) { | ||
316 | case SND_SOC_DAPM_PRE_PMD: | ||
317 | value |= CS42L51_POWER_CTL1_PDN; | ||
318 | break; | ||
319 | default: | ||
320 | case SND_SOC_DAPM_POST_PMD: | ||
321 | break; | ||
322 | } | ||
323 | snd_soc_update_bits(w->codec, CS42L51_POWER_CTL1, | ||
324 | CS42L51_POWER_CTL1_PDN, value); | ||
325 | |||
326 | return 0; | ||
327 | } | ||
328 | |||
329 | static const char *cs42l51_dac_names[] = {"Direct PCM", | ||
330 | "DSP PCM", "ADC"}; | ||
331 | static const struct soc_enum cs42l51_dac_mux_enum = | ||
332 | SOC_ENUM_SINGLE(CS42L51_DAC_CTL, 6, 3, cs42l51_dac_names); | ||
333 | static const struct snd_kcontrol_new cs42l51_dac_mux_controls = | ||
334 | SOC_DAPM_ENUM("Route", cs42l51_dac_mux_enum); | ||
335 | |||
336 | static const char *cs42l51_adcl_names[] = {"AIN1 Left", "AIN2 Left", | ||
337 | "MIC Left", "MIC+preamp Left"}; | ||
338 | static const struct soc_enum cs42l51_adcl_mux_enum = | ||
339 | SOC_ENUM_SINGLE(CS42L51_ADC_INPUT, 4, 4, cs42l51_adcl_names); | ||
340 | static const struct snd_kcontrol_new cs42l51_adcl_mux_controls = | ||
341 | SOC_DAPM_ENUM("Route", cs42l51_adcl_mux_enum); | ||
342 | |||
343 | static const char *cs42l51_adcr_names[] = {"AIN1 Right", "AIN2 Right", | ||
344 | "MIC Right", "MIC+preamp Right"}; | ||
345 | static const struct soc_enum cs42l51_adcr_mux_enum = | ||
346 | SOC_ENUM_SINGLE(CS42L51_ADC_INPUT, 6, 4, cs42l51_adcr_names); | ||
347 | static const struct snd_kcontrol_new cs42l51_adcr_mux_controls = | ||
348 | SOC_DAPM_ENUM("Route", cs42l51_adcr_mux_enum); | ||
349 | |||
350 | static const struct snd_soc_dapm_widget cs42l51_dapm_widgets[] = { | ||
351 | SND_SOC_DAPM_MICBIAS("Mic Bias", CS42L51_MIC_POWER_CTL, 1, 1), | ||
352 | SND_SOC_DAPM_PGA_E("Left PGA", CS42L51_POWER_CTL1, 3, 1, NULL, 0, | ||
353 | cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD), | ||
354 | SND_SOC_DAPM_PGA_E("Right PGA", CS42L51_POWER_CTL1, 4, 1, NULL, 0, | ||
355 | cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD), | ||
356 | SND_SOC_DAPM_ADC_E("Left ADC", "Left HiFi Capture", | ||
357 | CS42L51_POWER_CTL1, 1, 1, | ||
358 | cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD), | ||
359 | SND_SOC_DAPM_ADC_E("Right ADC", "Right HiFi Capture", | ||
360 | CS42L51_POWER_CTL1, 2, 1, | ||
361 | cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD), | ||
362 | SND_SOC_DAPM_DAC_E("Left DAC", "Left HiFi Playback", | ||
363 | CS42L51_POWER_CTL1, 5, 1, | ||
364 | cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD), | ||
365 | SND_SOC_DAPM_DAC_E("Right DAC", "Right HiFi Playback", | ||
366 | CS42L51_POWER_CTL1, 6, 1, | ||
367 | cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD), | ||
368 | |||
369 | /* analog/mic */ | ||
370 | SND_SOC_DAPM_INPUT("AIN1L"), | ||
371 | SND_SOC_DAPM_INPUT("AIN1R"), | ||
372 | SND_SOC_DAPM_INPUT("AIN2L"), | ||
373 | SND_SOC_DAPM_INPUT("AIN2R"), | ||
374 | SND_SOC_DAPM_INPUT("MICL"), | ||
375 | SND_SOC_DAPM_INPUT("MICR"), | ||
376 | |||
377 | SND_SOC_DAPM_MIXER("Mic Preamp Left", | ||
378 | CS42L51_MIC_POWER_CTL, 2, 1, NULL, 0), | ||
379 | SND_SOC_DAPM_MIXER("Mic Preamp Right", | ||
380 | CS42L51_MIC_POWER_CTL, 3, 1, NULL, 0), | ||
381 | |||
382 | /* HP */ | ||
383 | SND_SOC_DAPM_OUTPUT("HPL"), | ||
384 | SND_SOC_DAPM_OUTPUT("HPR"), | ||
385 | |||
386 | /* mux */ | ||
387 | SND_SOC_DAPM_MUX("DAC Mux", SND_SOC_NOPM, 0, 0, | ||
388 | &cs42l51_dac_mux_controls), | ||
389 | SND_SOC_DAPM_MUX("PGA-ADC Mux Left", SND_SOC_NOPM, 0, 0, | ||
390 | &cs42l51_adcl_mux_controls), | ||
391 | SND_SOC_DAPM_MUX("PGA-ADC Mux Right", SND_SOC_NOPM, 0, 0, | ||
392 | &cs42l51_adcr_mux_controls), | ||
393 | }; | ||
394 | |||
395 | static const struct snd_soc_dapm_route cs42l51_routes[] = { | ||
396 | {"HPL", NULL, "Left DAC"}, | ||
397 | {"HPR", NULL, "Right DAC"}, | ||
398 | |||
399 | {"Left ADC", NULL, "Left PGA"}, | ||
400 | {"Right ADC", NULL, "Right PGA"}, | ||
401 | |||
402 | {"Mic Preamp Left", NULL, "MICL"}, | ||
403 | {"Mic Preamp Right", NULL, "MICR"}, | ||
404 | |||
405 | {"PGA-ADC Mux Left", "AIN1 Left", "AIN1L" }, | ||
406 | {"PGA-ADC Mux Left", "AIN2 Left", "AIN2L" }, | ||
407 | {"PGA-ADC Mux Left", "MIC Left", "MICL" }, | ||
408 | {"PGA-ADC Mux Left", "MIC+preamp Left", "Mic Preamp Left" }, | ||
409 | {"PGA-ADC Mux Right", "AIN1 Right", "AIN1R" }, | ||
410 | {"PGA-ADC Mux Right", "AIN2 Right", "AIN2R" }, | ||
411 | {"PGA-ADC Mux Right", "MIC Right", "MICR" }, | ||
412 | {"PGA-ADC Mux Right", "MIC+preamp Right", "Mic Preamp Right" }, | ||
413 | |||
414 | {"Left PGA", NULL, "PGA-ADC Mux Left"}, | ||
415 | {"Right PGA", NULL, "PGA-ADC Mux Right"}, | ||
416 | }; | ||
417 | |||
418 | static int cs42l51_set_dai_fmt(struct snd_soc_dai *codec_dai, | ||
419 | unsigned int format) | ||
420 | { | ||
421 | struct snd_soc_codec *codec = codec_dai->codec; | ||
422 | struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec); | ||
423 | int ret = 0; | ||
424 | |||
425 | switch (format & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
426 | case SND_SOC_DAIFMT_I2S: | ||
427 | case SND_SOC_DAIFMT_LEFT_J: | ||
428 | case SND_SOC_DAIFMT_RIGHT_J: | ||
429 | cs42l51->audio_mode = format & SND_SOC_DAIFMT_FORMAT_MASK; | ||
430 | break; | ||
431 | default: | ||
432 | dev_err(codec->dev, "invalid DAI format\n"); | ||
433 | ret = -EINVAL; | ||
434 | } | ||
435 | |||
436 | switch (format & SND_SOC_DAIFMT_MASTER_MASK) { | ||
437 | case SND_SOC_DAIFMT_CBM_CFM: | ||
438 | cs42l51->func = MODE_MASTER; | ||
439 | break; | ||
440 | case SND_SOC_DAIFMT_CBS_CFS: | ||
441 | cs42l51->func = MODE_SLAVE_AUTO; | ||
442 | break; | ||
443 | default: | ||
444 | ret = -EINVAL; | ||
445 | break; | ||
446 | } | ||
447 | |||
448 | return ret; | ||
449 | } | ||
450 | |||
451 | struct cs42l51_ratios { | ||
452 | unsigned int ratio; | ||
453 | unsigned char speed_mode; | ||
454 | unsigned char mclk; | ||
455 | }; | ||
456 | |||
457 | static struct cs42l51_ratios slave_ratios[] = { | ||
458 | { 512, CS42L51_QSM_MODE, 0 }, { 768, CS42L51_QSM_MODE, 0 }, | ||
459 | { 1024, CS42L51_QSM_MODE, 0 }, { 1536, CS42L51_QSM_MODE, 0 }, | ||
460 | { 2048, CS42L51_QSM_MODE, 0 }, { 3072, CS42L51_QSM_MODE, 0 }, | ||
461 | { 256, CS42L51_HSM_MODE, 0 }, { 384, CS42L51_HSM_MODE, 0 }, | ||
462 | { 512, CS42L51_HSM_MODE, 0 }, { 768, CS42L51_HSM_MODE, 0 }, | ||
463 | { 1024, CS42L51_HSM_MODE, 0 }, { 1536, CS42L51_HSM_MODE, 0 }, | ||
464 | { 128, CS42L51_SSM_MODE, 0 }, { 192, CS42L51_SSM_MODE, 0 }, | ||
465 | { 256, CS42L51_SSM_MODE, 0 }, { 384, CS42L51_SSM_MODE, 0 }, | ||
466 | { 512, CS42L51_SSM_MODE, 0 }, { 768, CS42L51_SSM_MODE, 0 }, | ||
467 | { 128, CS42L51_DSM_MODE, 0 }, { 192, CS42L51_DSM_MODE, 0 }, | ||
468 | { 256, CS42L51_DSM_MODE, 0 }, { 384, CS42L51_DSM_MODE, 0 }, | ||
469 | }; | ||
470 | |||
471 | static struct cs42l51_ratios slave_auto_ratios[] = { | ||
472 | { 1024, CS42L51_QSM_MODE, 0 }, { 1536, CS42L51_QSM_MODE, 0 }, | ||
473 | { 2048, CS42L51_QSM_MODE, 1 }, { 3072, CS42L51_QSM_MODE, 1 }, | ||
474 | { 512, CS42L51_HSM_MODE, 0 }, { 768, CS42L51_HSM_MODE, 0 }, | ||
475 | { 1024, CS42L51_HSM_MODE, 1 }, { 1536, CS42L51_HSM_MODE, 1 }, | ||
476 | { 256, CS42L51_SSM_MODE, 0 }, { 384, CS42L51_SSM_MODE, 0 }, | ||
477 | { 512, CS42L51_SSM_MODE, 1 }, { 768, CS42L51_SSM_MODE, 1 }, | ||
478 | { 128, CS42L51_DSM_MODE, 0 }, { 192, CS42L51_DSM_MODE, 0 }, | ||
479 | { 256, CS42L51_DSM_MODE, 1 }, { 384, CS42L51_DSM_MODE, 1 }, | ||
480 | }; | ||
481 | |||
482 | static int cs42l51_set_dai_sysclk(struct snd_soc_dai *codec_dai, | ||
483 | int clk_id, unsigned int freq, int dir) | ||
484 | { | ||
485 | struct snd_soc_codec *codec = codec_dai->codec; | ||
486 | struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec); | ||
487 | struct cs42l51_ratios *ratios = NULL; | ||
488 | int nr_ratios = 0; | ||
489 | unsigned int rates = 0; | ||
490 | unsigned int rate_min = -1; | ||
491 | unsigned int rate_max = 0; | ||
492 | int i; | ||
493 | |||
494 | cs42l51->mclk = freq; | ||
495 | |||
496 | switch (cs42l51->func) { | ||
497 | case MODE_MASTER: | ||
498 | return -EINVAL; | ||
499 | case MODE_SLAVE: | ||
500 | ratios = slave_ratios; | ||
501 | nr_ratios = ARRAY_SIZE(slave_ratios); | ||
502 | break; | ||
503 | case MODE_SLAVE_AUTO: | ||
504 | ratios = slave_auto_ratios; | ||
505 | nr_ratios = ARRAY_SIZE(slave_auto_ratios); | ||
506 | break; | ||
507 | } | ||
508 | |||
509 | for (i = 0; i < nr_ratios; i++) { | ||
510 | unsigned int rate = freq / ratios[i].ratio; | ||
511 | rates |= snd_pcm_rate_to_rate_bit(rate); | ||
512 | if (rate < rate_min) | ||
513 | rate_min = rate; | ||
514 | if (rate > rate_max) | ||
515 | rate_max = rate; | ||
516 | } | ||
517 | rates &= ~SNDRV_PCM_RATE_KNOT; | ||
518 | |||
519 | if (!rates) { | ||
520 | dev_err(codec->dev, "could not find a valid sample rate\n"); | ||
521 | return -EINVAL; | ||
522 | } | ||
523 | |||
524 | codec_dai->playback.rates = rates; | ||
525 | codec_dai->playback.rate_min = rate_min; | ||
526 | codec_dai->playback.rate_max = rate_max; | ||
527 | |||
528 | codec_dai->capture.rates = rates; | ||
529 | codec_dai->capture.rate_min = rate_min; | ||
530 | codec_dai->capture.rate_max = rate_max; | ||
531 | |||
532 | return 0; | ||
533 | } | ||
534 | |||
535 | static int cs42l51_hw_params(struct snd_pcm_substream *substream, | ||
536 | struct snd_pcm_hw_params *params, | ||
537 | struct snd_soc_dai *dai) | ||
538 | { | ||
539 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
540 | struct snd_soc_device *socdev = rtd->socdev; | ||
541 | struct snd_soc_codec *codec = socdev->card->codec; | ||
542 | struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec); | ||
543 | int ret; | ||
544 | unsigned int i; | ||
545 | unsigned int rate; | ||
546 | unsigned int ratio; | ||
547 | struct cs42l51_ratios *ratios = NULL; | ||
548 | int nr_ratios = 0; | ||
549 | int intf_ctl, power_ctl, fmt; | ||
550 | |||
551 | switch (cs42l51->func) { | ||
552 | case MODE_MASTER: | ||
553 | return -EINVAL; | ||
554 | case MODE_SLAVE: | ||
555 | ratios = slave_ratios; | ||
556 | nr_ratios = ARRAY_SIZE(slave_ratios); | ||
557 | break; | ||
558 | case MODE_SLAVE_AUTO: | ||
559 | ratios = slave_auto_ratios; | ||
560 | nr_ratios = ARRAY_SIZE(slave_auto_ratios); | ||
561 | break; | ||
562 | } | ||
563 | |||
564 | /* Figure out which MCLK/LRCK ratio to use */ | ||
565 | rate = params_rate(params); /* Sampling rate, in Hz */ | ||
566 | ratio = cs42l51->mclk / rate; /* MCLK/LRCK ratio */ | ||
567 | for (i = 0; i < nr_ratios; i++) { | ||
568 | if (ratios[i].ratio == ratio) | ||
569 | break; | ||
570 | } | ||
571 | |||
572 | if (i == nr_ratios) { | ||
573 | /* We did not find a matching ratio */ | ||
574 | dev_err(codec->dev, "could not find matching ratio\n"); | ||
575 | return -EINVAL; | ||
576 | } | ||
577 | |||
578 | intf_ctl = snd_soc_read(codec, CS42L51_INTF_CTL); | ||
579 | power_ctl = snd_soc_read(codec, CS42L51_MIC_POWER_CTL); | ||
580 | |||
581 | intf_ctl &= ~(CS42L51_INTF_CTL_MASTER | CS42L51_INTF_CTL_ADC_I2S | ||
582 | | CS42L51_INTF_CTL_DAC_FORMAT(7)); | ||
583 | power_ctl &= ~(CS42L51_MIC_POWER_CTL_SPEED(3) | ||
584 | | CS42L51_MIC_POWER_CTL_MCLK_DIV2); | ||
585 | |||
586 | switch (cs42l51->func) { | ||
587 | case MODE_MASTER: | ||
588 | intf_ctl |= CS42L51_INTF_CTL_MASTER; | ||
589 | power_ctl |= CS42L51_MIC_POWER_CTL_SPEED(ratios[i].speed_mode); | ||
590 | break; | ||
591 | case MODE_SLAVE: | ||
592 | power_ctl |= CS42L51_MIC_POWER_CTL_SPEED(ratios[i].speed_mode); | ||
593 | break; | ||
594 | case MODE_SLAVE_AUTO: | ||
595 | power_ctl |= CS42L51_MIC_POWER_CTL_AUTO; | ||
596 | break; | ||
597 | } | ||
598 | |||
599 | switch (cs42l51->audio_mode) { | ||
600 | case SND_SOC_DAIFMT_I2S: | ||
601 | intf_ctl |= CS42L51_INTF_CTL_ADC_I2S; | ||
602 | intf_ctl |= CS42L51_INTF_CTL_DAC_FORMAT(CS42L51_DAC_DIF_I2S); | ||
603 | break; | ||
604 | case SND_SOC_DAIFMT_LEFT_J: | ||
605 | intf_ctl |= CS42L51_INTF_CTL_DAC_FORMAT(CS42L51_DAC_DIF_LJ24); | ||
606 | break; | ||
607 | case SND_SOC_DAIFMT_RIGHT_J: | ||
608 | switch (params_format(params)) { | ||
609 | case SNDRV_PCM_FORMAT_S16_LE: | ||
610 | case SNDRV_PCM_FORMAT_S16_BE: | ||
611 | fmt = CS42L51_DAC_DIF_RJ16; | ||
612 | break; | ||
613 | case SNDRV_PCM_FORMAT_S18_3LE: | ||
614 | case SNDRV_PCM_FORMAT_S18_3BE: | ||
615 | fmt = CS42L51_DAC_DIF_RJ18; | ||
616 | break; | ||
617 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
618 | case SNDRV_PCM_FORMAT_S20_3BE: | ||
619 | fmt = CS42L51_DAC_DIF_RJ20; | ||
620 | break; | ||
621 | case SNDRV_PCM_FORMAT_S24_LE: | ||
622 | case SNDRV_PCM_FORMAT_S24_BE: | ||
623 | fmt = CS42L51_DAC_DIF_RJ24; | ||
624 | break; | ||
625 | default: | ||
626 | dev_err(codec->dev, "unknown format\n"); | ||
627 | return -EINVAL; | ||
628 | } | ||
629 | intf_ctl |= CS42L51_INTF_CTL_DAC_FORMAT(fmt); | ||
630 | break; | ||
631 | default: | ||
632 | dev_err(codec->dev, "unknown format\n"); | ||
633 | return -EINVAL; | ||
634 | } | ||
635 | |||
636 | if (ratios[i].mclk) | ||
637 | power_ctl |= CS42L51_MIC_POWER_CTL_MCLK_DIV2; | ||
638 | |||
639 | ret = snd_soc_write(codec, CS42L51_INTF_CTL, intf_ctl); | ||
640 | if (ret < 0) | ||
641 | return ret; | ||
642 | |||
643 | ret = snd_soc_write(codec, CS42L51_MIC_POWER_CTL, power_ctl); | ||
644 | if (ret < 0) | ||
645 | return ret; | ||
646 | |||
647 | return 0; | ||
648 | } | ||
649 | |||
650 | static int cs42l51_dai_mute(struct snd_soc_dai *dai, int mute) | ||
651 | { | ||
652 | struct snd_soc_codec *codec = dai->codec; | ||
653 | int reg; | ||
654 | int mask = CS42L51_DAC_OUT_CTL_DACA_MUTE|CS42L51_DAC_OUT_CTL_DACB_MUTE; | ||
655 | |||
656 | reg = snd_soc_read(codec, CS42L51_DAC_OUT_CTL); | ||
657 | |||
658 | if (mute) | ||
659 | reg |= mask; | ||
660 | else | ||
661 | reg &= ~mask; | ||
662 | |||
663 | return snd_soc_write(codec, CS42L51_DAC_OUT_CTL, reg); | ||
664 | } | ||
665 | |||
666 | static struct snd_soc_dai_ops cs42l51_dai_ops = { | ||
667 | .hw_params = cs42l51_hw_params, | ||
668 | .set_sysclk = cs42l51_set_dai_sysclk, | ||
669 | .set_fmt = cs42l51_set_dai_fmt, | ||
670 | .digital_mute = cs42l51_dai_mute, | ||
671 | }; | ||
672 | |||
673 | struct snd_soc_dai cs42l51_dai = { | ||
674 | .name = "CS42L51 HiFi", | ||
675 | .playback = { | ||
676 | .stream_name = "Playback", | ||
677 | .channels_min = 1, | ||
678 | .channels_max = 2, | ||
679 | .rates = SNDRV_PCM_RATE_8000_96000, | ||
680 | .formats = CS42L51_FORMATS, | ||
681 | }, | ||
682 | .capture = { | ||
683 | .stream_name = "Capture", | ||
684 | .channels_min = 1, | ||
685 | .channels_max = 2, | ||
686 | .rates = SNDRV_PCM_RATE_8000_96000, | ||
687 | .formats = CS42L51_FORMATS, | ||
688 | }, | ||
689 | .ops = &cs42l51_dai_ops, | ||
690 | }; | ||
691 | EXPORT_SYMBOL_GPL(cs42l51_dai); | ||
692 | |||
693 | |||
694 | static int cs42l51_probe(struct platform_device *pdev) | ||
695 | { | ||
696 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
697 | struct snd_soc_codec *codec; | ||
698 | int ret = 0; | ||
699 | |||
700 | if (!cs42l51_codec) { | ||
701 | dev_err(&pdev->dev, "CS42L51 codec not yet registered\n"); | ||
702 | return -EINVAL; | ||
703 | } | ||
704 | |||
705 | socdev->card->codec = cs42l51_codec; | ||
706 | codec = socdev->card->codec; | ||
707 | |||
708 | /* Register PCMs */ | ||
709 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
710 | if (ret < 0) { | ||
711 | dev_err(&pdev->dev, "failed to create PCMs\n"); | ||
712 | return ret; | ||
713 | } | ||
714 | |||
715 | snd_soc_add_controls(codec, cs42l51_snd_controls, | ||
716 | ARRAY_SIZE(cs42l51_snd_controls)); | ||
717 | snd_soc_dapm_new_controls(codec, cs42l51_dapm_widgets, | ||
718 | ARRAY_SIZE(cs42l51_dapm_widgets)); | ||
719 | snd_soc_dapm_add_routes(codec, cs42l51_routes, | ||
720 | ARRAY_SIZE(cs42l51_routes)); | ||
721 | |||
722 | return 0; | ||
723 | } | ||
724 | |||
725 | |||
726 | static int cs42l51_remove(struct platform_device *pdev) | ||
727 | { | ||
728 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
729 | |||
730 | snd_soc_free_pcms(socdev); | ||
731 | snd_soc_dapm_free(socdev); | ||
732 | |||
733 | return 0; | ||
734 | } | ||
735 | |||
736 | struct snd_soc_codec_device soc_codec_device_cs42l51 = { | ||
737 | .probe = cs42l51_probe, | ||
738 | .remove = cs42l51_remove | ||
739 | }; | ||
740 | EXPORT_SYMBOL_GPL(soc_codec_device_cs42l51); | ||
741 | |||
742 | static int __init cs42l51_init(void) | ||
743 | { | ||
744 | int ret; | ||
745 | |||
746 | ret = i2c_add_driver(&cs42l51_i2c_driver); | ||
747 | if (ret != 0) { | ||
748 | printk(KERN_ERR "%s: can't add i2c driver\n", __func__); | ||
749 | return ret; | ||
750 | } | ||
751 | return 0; | ||
752 | } | ||
753 | module_init(cs42l51_init); | ||
754 | |||
755 | static void __exit cs42l51_exit(void) | ||
756 | { | ||
757 | i2c_del_driver(&cs42l51_i2c_driver); | ||
758 | } | ||
759 | module_exit(cs42l51_exit); | ||
760 | |||
761 | MODULE_AUTHOR("Arnaud Patard <apatard@mandriva.com>"); | ||
762 | MODULE_DESCRIPTION("Cirrus Logic CS42L51 ALSA SoC Codec Driver"); | ||
763 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/cs42l51.h b/sound/soc/codecs/cs42l51.h new file mode 100644 index 000000000000..8f0bd9786ad2 --- /dev/null +++ b/sound/soc/codecs/cs42l51.h | |||
@@ -0,0 +1,163 @@ | |||
1 | /* | ||
2 | * cs42l51.h | ||
3 | * | ||
4 | * ASoC Driver for Cirrus Logic CS42L51 codecs | ||
5 | * | ||
6 | * Copyright (c) 2010 Arnaud Patard <apatard@mandriva.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 as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | */ | ||
18 | #ifndef _CS42L51_H | ||
19 | #define _CS42L51_H | ||
20 | |||
21 | #define CS42L51_CHIP_ID 0x1B | ||
22 | #define CS42L51_CHIP_REV_A 0x00 | ||
23 | #define CS42L51_CHIP_REV_B 0x01 | ||
24 | |||
25 | #define CS42L51_CHIP_REV_ID 0x01 | ||
26 | #define CS42L51_MK_CHIP_REV(a, b) ((a)<<3|(b)) | ||
27 | |||
28 | #define CS42L51_POWER_CTL1 0x02 | ||
29 | #define CS42L51_POWER_CTL1_PDN_DACB (1<<6) | ||
30 | #define CS42L51_POWER_CTL1_PDN_DACA (1<<5) | ||
31 | #define CS42L51_POWER_CTL1_PDN_PGAB (1<<4) | ||
32 | #define CS42L51_POWER_CTL1_PDN_PGAA (1<<3) | ||
33 | #define CS42L51_POWER_CTL1_PDN_ADCB (1<<2) | ||
34 | #define CS42L51_POWER_CTL1_PDN_ADCA (1<<1) | ||
35 | #define CS42L51_POWER_CTL1_PDN (1<<0) | ||
36 | |||
37 | #define CS42L51_MIC_POWER_CTL 0x03 | ||
38 | #define CS42L51_MIC_POWER_CTL_AUTO (1<<7) | ||
39 | #define CS42L51_MIC_POWER_CTL_SPEED(x) (((x)&3)<<5) | ||
40 | #define CS42L51_QSM_MODE 3 | ||
41 | #define CS42L51_HSM_MODE 2 | ||
42 | #define CS42L51_SSM_MODE 1 | ||
43 | #define CS42L51_DSM_MODE 0 | ||
44 | #define CS42L51_MIC_POWER_CTL_3ST_SP (1<<4) | ||
45 | #define CS42L51_MIC_POWER_CTL_PDN_MICB (1<<3) | ||
46 | #define CS42L51_MIC_POWER_CTL_PDN_MICA (1<<2) | ||
47 | #define CS42L51_MIC_POWER_CTL_PDN_BIAS (1<<1) | ||
48 | #define CS42L51_MIC_POWER_CTL_MCLK_DIV2 (1<<0) | ||
49 | |||
50 | #define CS42L51_INTF_CTL 0x04 | ||
51 | #define CS42L51_INTF_CTL_LOOPBACK (1<<7) | ||
52 | #define CS42L51_INTF_CTL_MASTER (1<<6) | ||
53 | #define CS42L51_INTF_CTL_DAC_FORMAT(x) (((x)&7)<<3) | ||
54 | #define CS42L51_DAC_DIF_LJ24 0x00 | ||
55 | #define CS42L51_DAC_DIF_I2S 0x01 | ||
56 | #define CS42L51_DAC_DIF_RJ24 0x02 | ||
57 | #define CS42L51_DAC_DIF_RJ20 0x03 | ||
58 | #define CS42L51_DAC_DIF_RJ18 0x04 | ||
59 | #define CS42L51_DAC_DIF_RJ16 0x05 | ||
60 | #define CS42L51_INTF_CTL_ADC_I2S (1<<2) | ||
61 | #define CS42L51_INTF_CTL_DIGMIX (1<<1) | ||
62 | #define CS42L51_INTF_CTL_MICMIX (1<<0) | ||
63 | |||
64 | #define CS42L51_MIC_CTL 0x05 | ||
65 | #define CS42L51_MIC_CTL_ADC_SNGVOL (1<<7) | ||
66 | #define CS42L51_MIC_CTL_ADCD_DBOOST (1<<6) | ||
67 | #define CS42L51_MIC_CTL_ADCA_DBOOST (1<<5) | ||
68 | #define CS42L51_MIC_CTL_MICBIAS_SEL (1<<4) | ||
69 | #define CS42L51_MIC_CTL_MICBIAS_LVL(x) (((x)&3)<<2) | ||
70 | #define CS42L51_MIC_CTL_MICB_BOOST (1<<1) | ||
71 | #define CS42L51_MIC_CTL_MICA_BOOST (1<<0) | ||
72 | |||
73 | #define CS42L51_ADC_CTL 0x06 | ||
74 | #define CS42L51_ADC_CTL_ADCB_HPFEN (1<<7) | ||
75 | #define CS42L51_ADC_CTL_ADCB_HPFRZ (1<<6) | ||
76 | #define CS42L51_ADC_CTL_ADCA_HPFEN (1<<5) | ||
77 | #define CS42L51_ADC_CTL_ADCA_HPFRZ (1<<4) | ||
78 | #define CS42L51_ADC_CTL_SOFTB (1<<3) | ||
79 | #define CS42L51_ADC_CTL_ZCROSSB (1<<2) | ||
80 | #define CS42L51_ADC_CTL_SOFTA (1<<1) | ||
81 | #define CS42L51_ADC_CTL_ZCROSSA (1<<0) | ||
82 | |||
83 | #define CS42L51_ADC_INPUT 0x07 | ||
84 | #define CS42L51_ADC_INPUT_AINB_MUX(x) (((x)&3)<<6) | ||
85 | #define CS42L51_ADC_INPUT_AINA_MUX(x) (((x)&3)<<4) | ||
86 | #define CS42L51_ADC_INPUT_INV_ADCB (1<<3) | ||
87 | #define CS42L51_ADC_INPUT_INV_ADCA (1<<2) | ||
88 | #define CS42L51_ADC_INPUT_ADCB_MUTE (1<<1) | ||
89 | #define CS42L51_ADC_INPUT_ADCA_MUTE (1<<0) | ||
90 | |||
91 | #define CS42L51_DAC_OUT_CTL 0x08 | ||
92 | #define CS42L51_DAC_OUT_CTL_HP_GAIN(x) (((x)&7)<<5) | ||
93 | #define CS42L51_DAC_OUT_CTL_DAC_SNGVOL (1<<4) | ||
94 | #define CS42L51_DAC_OUT_CTL_INV_PCMB (1<<3) | ||
95 | #define CS42L51_DAC_OUT_CTL_INV_PCMA (1<<2) | ||
96 | #define CS42L51_DAC_OUT_CTL_DACB_MUTE (1<<1) | ||
97 | #define CS42L51_DAC_OUT_CTL_DACA_MUTE (1<<0) | ||
98 | |||
99 | #define CS42L51_DAC_CTL 0x09 | ||
100 | #define CS42L51_DAC_CTL_DATA_SEL(x) (((x)&3)<<6) | ||
101 | #define CS42L51_DAC_CTL_FREEZE (1<<5) | ||
102 | #define CS42L51_DAC_CTL_DEEMPH (1<<3) | ||
103 | #define CS42L51_DAC_CTL_AMUTE (1<<2) | ||
104 | #define CS42L51_DAC_CTL_DACSZ(x) (((x)&3)<<0) | ||
105 | |||
106 | #define CS42L51_ALC_PGA_CTL 0x0A | ||
107 | #define CS42L51_ALC_PGB_CTL 0x0B | ||
108 | #define CS42L51_ALC_PGX_ALCX_SRDIS (1<<7) | ||
109 | #define CS42L51_ALC_PGX_ALCX_ZCDIS (1<<6) | ||
110 | #define CS42L51_ALC_PGX_PGX_VOL(x) (((x)&0x1f)<<0) | ||
111 | |||
112 | #define CS42L51_ADCA_ATT 0x0C | ||
113 | #define CS42L51_ADCB_ATT 0x0D | ||
114 | |||
115 | #define CS42L51_ADCA_VOL 0x0E | ||
116 | #define CS42L51_ADCB_VOL 0x0F | ||
117 | #define CS42L51_PCMA_VOL 0x10 | ||
118 | #define CS42L51_PCMB_VOL 0x11 | ||
119 | #define CS42L51_MIX_MUTE_ADCMIX (1<<7) | ||
120 | #define CS42L51_MIX_VOLUME(x) (((x)&0x7f)<<0) | ||
121 | |||
122 | #define CS42L51_BEEP_FREQ 0x12 | ||
123 | #define CS42L51_BEEP_VOL 0x13 | ||
124 | #define CS42L51_BEEP_CONF 0x14 | ||
125 | |||
126 | #define CS42L51_TONE_CTL 0x15 | ||
127 | #define CS42L51_TONE_CTL_TREB(x) (((x)&0xf)<<4) | ||
128 | #define CS42L51_TONE_CTL_BASS(x) (((x)&0xf)<<0) | ||
129 | |||
130 | #define CS42L51_AOUTA_VOL 0x16 | ||
131 | #define CS42L51_AOUTB_VOL 0x17 | ||
132 | #define CS42L51_PCM_MIXER 0x18 | ||
133 | #define CS42L51_LIMIT_THRES_DIS 0x19 | ||
134 | #define CS42L51_LIMIT_REL 0x1A | ||
135 | #define CS42L51_LIMIT_ATT 0x1B | ||
136 | #define CS42L51_ALC_EN 0x1C | ||
137 | #define CS42L51_ALC_REL 0x1D | ||
138 | #define CS42L51_ALC_THRES 0x1E | ||
139 | #define CS42L51_NOISE_CONF 0x1F | ||
140 | |||
141 | #define CS42L51_STATUS 0x20 | ||
142 | #define CS42L51_STATUS_SP_CLKERR (1<<6) | ||
143 | #define CS42L51_STATUS_SPEA_OVFL (1<<5) | ||
144 | #define CS42L51_STATUS_SPEB_OVFL (1<<4) | ||
145 | #define CS42L51_STATUS_PCMA_OVFL (1<<3) | ||
146 | #define CS42L51_STATUS_PCMB_OVFL (1<<2) | ||
147 | #define CS42L51_STATUS_ADCA_OVFL (1<<1) | ||
148 | #define CS42L51_STATUS_ADCB_OVFL (1<<0) | ||
149 | |||
150 | #define CS42L51_CHARGE_FREQ 0x21 | ||
151 | |||
152 | #define CS42L51_FIRSTREG 0x01 | ||
153 | /* | ||
154 | * Hack: with register 0x21, it makes 33 registers. Looks like someone in the | ||
155 | * i2c layer doesn't like i2c smbus block read of 33 regs. Workaround by using | ||
156 | * 32 regs | ||
157 | */ | ||
158 | #define CS42L51_LASTREG 0x20 | ||
159 | #define CS42L51_NUMREGS (CS42L51_LASTREG - CS42L51_FIRSTREG + 1) | ||
160 | |||
161 | extern struct snd_soc_dai cs42l51_dai; | ||
162 | extern struct snd_soc_codec_device soc_codec_device_cs42l51; | ||
163 | #endif | ||
diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c index 75af2d6e0e78..3c51d6a57523 100644 --- a/sound/soc/codecs/da7210.c +++ b/sound/soc/codecs/da7210.c | |||
@@ -15,23 +15,15 @@ | |||
15 | * option) any later version. | 15 | * option) any later version. |
16 | */ | 16 | */ |
17 | 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> | 18 | #include <linux/delay.h> |
23 | #include <linux/pm.h> | ||
24 | #include <linux/i2c.h> | 19 | #include <linux/i2c.h> |
25 | #include <linux/platform_device.h> | 20 | #include <linux/platform_device.h> |
26 | #include <linux/slab.h> | 21 | #include <linux/slab.h> |
27 | #include <sound/core.h> | ||
28 | #include <sound/pcm.h> | 22 | #include <sound/pcm.h> |
29 | #include <sound/pcm_params.h> | 23 | #include <sound/pcm_params.h> |
30 | #include <sound/soc.h> | ||
31 | #include <sound/soc-dapm.h> | 24 | #include <sound/soc-dapm.h> |
32 | #include <sound/tlv.h> | ||
33 | #include <sound/initval.h> | 25 | #include <sound/initval.h> |
34 | #include <asm/div64.h> | 26 | #include <sound/tlv.h> |
35 | 27 | ||
36 | #include "da7210.h" | 28 | #include "da7210.h" |
37 | 29 | ||
@@ -145,6 +137,29 @@ | |||
145 | 137 | ||
146 | #define DA7210_VERSION "0.0.1" | 138 | #define DA7210_VERSION "0.0.1" |
147 | 139 | ||
140 | /* | ||
141 | * Playback Volume | ||
142 | * | ||
143 | * max : 0x3F (+15.0 dB) | ||
144 | * (1.5 dB step) | ||
145 | * min : 0x11 (-54.0 dB) | ||
146 | * mute : 0x10 | ||
147 | * reserved : 0x00 - 0x0F | ||
148 | * | ||
149 | * ** FIXME ** | ||
150 | * | ||
151 | * Reserved area are considered as "mute". | ||
152 | * -> min = -79.5 dB | ||
153 | */ | ||
154 | static const DECLARE_TLV_DB_SCALE(hp_out_tlv, -7950, 150, 1); | ||
155 | |||
156 | static const struct snd_kcontrol_new da7210_snd_controls[] = { | ||
157 | |||
158 | SOC_DOUBLE_R_TLV("HeadPhone Playback Volume", | ||
159 | DA7210_HP_L_VOL, DA7210_HP_R_VOL, | ||
160 | 0, 0x3F, 0, hp_out_tlv), | ||
161 | }; | ||
162 | |||
148 | /* Codec private data */ | 163 | /* Codec private data */ |
149 | struct da7210_priv { | 164 | struct da7210_priv { |
150 | struct snd_soc_codec codec; | 165 | struct snd_soc_codec codec; |
@@ -227,10 +242,6 @@ static int da7210_startup(struct snd_pcm_substream *substream, | |||
227 | struct snd_soc_codec *codec = dai->codec; | 242 | struct snd_soc_codec *codec = dai->codec; |
228 | 243 | ||
229 | if (is_play) { | 244 | if (is_play) { |
230 | /* PlayBack Volume 40 */ | ||
231 | snd_soc_update_bits(codec, DA7210_HP_L_VOL, 0x3F, 40); | ||
232 | snd_soc_update_bits(codec, DA7210_HP_R_VOL, 0x3F, 40); | ||
233 | |||
234 | /* Enable Out */ | 245 | /* Enable Out */ |
235 | snd_soc_update_bits(codec, DA7210_OUTMIX_L, 0x1F, 0x10); | 246 | snd_soc_update_bits(codec, DA7210_OUTMIX_L, 0x1F, 0x10); |
236 | snd_soc_update_bits(codec, DA7210_OUTMIX_R, 0x1F, 0x10); | 247 | snd_soc_update_bits(codec, DA7210_OUTMIX_R, 0x1F, 0x10); |
@@ -488,7 +499,7 @@ static int da7210_init(struct da7210_priv *da7210) | |||
488 | ret = snd_soc_register_dai(&da7210_dai); | 499 | ret = snd_soc_register_dai(&da7210_dai); |
489 | if (ret) { | 500 | if (ret) { |
490 | dev_err(codec->dev, "Failed to register DAI: %d\n", ret); | 501 | dev_err(codec->dev, "Failed to register DAI: %d\n", ret); |
491 | goto init_err; | 502 | goto codec_err; |
492 | } | 503 | } |
493 | 504 | ||
494 | /* FIXME | 505 | /* FIXME |
@@ -574,6 +585,8 @@ static int da7210_init(struct da7210_priv *da7210) | |||
574 | 585 | ||
575 | return ret; | 586 | return ret; |
576 | 587 | ||
588 | codec_err: | ||
589 | snd_soc_unregister_codec(codec); | ||
577 | init_err: | 590 | init_err: |
578 | kfree(codec->reg_cache); | 591 | kfree(codec->reg_cache); |
579 | codec->reg_cache = NULL; | 592 | codec->reg_cache = NULL; |
@@ -601,8 +614,10 @@ static int __devinit da7210_i2c_probe(struct i2c_client *i2c, | |||
601 | codec->control_data = i2c; | 614 | codec->control_data = i2c; |
602 | 615 | ||
603 | ret = da7210_init(da7210); | 616 | ret = da7210_init(da7210); |
604 | if (ret < 0) | 617 | if (ret < 0) { |
605 | pr_err("Failed to initialise da7210 audio codec\n"); | 618 | pr_err("Failed to initialise da7210 audio codec\n"); |
619 | kfree(da7210); | ||
620 | } | ||
606 | 621 | ||
607 | return ret; | 622 | return ret; |
608 | } | 623 | } |
@@ -656,6 +671,9 @@ static int da7210_probe(struct platform_device *pdev) | |||
656 | if (ret < 0) | 671 | if (ret < 0) |
657 | goto pcm_err; | 672 | goto pcm_err; |
658 | 673 | ||
674 | snd_soc_add_controls(da7210_codec, da7210_snd_controls, | ||
675 | ARRAY_SIZE(da7210_snd_controls)); | ||
676 | |||
659 | dev_info(&pdev->dev, "DA7210 Audio Codec %s\n", DA7210_VERSION); | 677 | dev_info(&pdev->dev, "DA7210 Audio Codec %s\n", DA7210_VERSION); |
660 | 678 | ||
661 | pcm_err: | 679 | pcm_err: |
diff --git a/sound/soc/codecs/jz4740.c b/sound/soc/codecs/jz4740.c new file mode 100644 index 000000000000..66557de1e4fe --- /dev/null +++ b/sound/soc/codecs/jz4740.c | |||
@@ -0,0 +1,511 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de> | ||
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 | * You should have received a copy of the GNU General Public License along | ||
9 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
10 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/platform_device.h> | ||
17 | #include <linux/slab.h> | ||
18 | |||
19 | #include <linux/delay.h> | ||
20 | |||
21 | #include <sound/core.h> | ||
22 | #include <sound/pcm.h> | ||
23 | #include <sound/pcm_params.h> | ||
24 | #include <sound/initval.h> | ||
25 | #include <sound/soc-dapm.h> | ||
26 | #include <sound/soc.h> | ||
27 | |||
28 | #define JZ4740_REG_CODEC_1 0x0 | ||
29 | #define JZ4740_REG_CODEC_2 0x1 | ||
30 | |||
31 | #define JZ4740_CODEC_1_LINE_ENABLE BIT(29) | ||
32 | #define JZ4740_CODEC_1_MIC_ENABLE BIT(28) | ||
33 | #define JZ4740_CODEC_1_SW1_ENABLE BIT(27) | ||
34 | #define JZ4740_CODEC_1_ADC_ENABLE BIT(26) | ||
35 | #define JZ4740_CODEC_1_SW2_ENABLE BIT(25) | ||
36 | #define JZ4740_CODEC_1_DAC_ENABLE BIT(24) | ||
37 | #define JZ4740_CODEC_1_VREF_DISABLE BIT(20) | ||
38 | #define JZ4740_CODEC_1_VREF_AMP_DISABLE BIT(19) | ||
39 | #define JZ4740_CODEC_1_VREF_PULLDOWN BIT(18) | ||
40 | #define JZ4740_CODEC_1_VREF_LOW_CURRENT BIT(17) | ||
41 | #define JZ4740_CODEC_1_VREF_HIGH_CURRENT BIT(16) | ||
42 | #define JZ4740_CODEC_1_HEADPHONE_DISABLE BIT(14) | ||
43 | #define JZ4740_CODEC_1_HEADPHONE_AMP_CHANGE_ANY BIT(13) | ||
44 | #define JZ4740_CODEC_1_HEADPHONE_CHARGE BIT(12) | ||
45 | #define JZ4740_CODEC_1_HEADPHONE_PULLDOWN (BIT(11) | BIT(10)) | ||
46 | #define JZ4740_CODEC_1_HEADPHONE_POWERDOWN_M BIT(9) | ||
47 | #define JZ4740_CODEC_1_HEADPHONE_POWERDOWN BIT(8) | ||
48 | #define JZ4740_CODEC_1_SUSPEND BIT(1) | ||
49 | #define JZ4740_CODEC_1_RESET BIT(0) | ||
50 | |||
51 | #define JZ4740_CODEC_1_LINE_ENABLE_OFFSET 29 | ||
52 | #define JZ4740_CODEC_1_MIC_ENABLE_OFFSET 28 | ||
53 | #define JZ4740_CODEC_1_SW1_ENABLE_OFFSET 27 | ||
54 | #define JZ4740_CODEC_1_ADC_ENABLE_OFFSET 26 | ||
55 | #define JZ4740_CODEC_1_SW2_ENABLE_OFFSET 25 | ||
56 | #define JZ4740_CODEC_1_DAC_ENABLE_OFFSET 24 | ||
57 | #define JZ4740_CODEC_1_HEADPHONE_DISABLE_OFFSET 14 | ||
58 | #define JZ4740_CODEC_1_HEADPHONE_POWERDOWN_OFFSET 8 | ||
59 | |||
60 | #define JZ4740_CODEC_2_INPUT_VOLUME_MASK 0x1f0000 | ||
61 | #define JZ4740_CODEC_2_SAMPLE_RATE_MASK 0x000f00 | ||
62 | #define JZ4740_CODEC_2_MIC_BOOST_GAIN_MASK 0x000030 | ||
63 | #define JZ4740_CODEC_2_HEADPHONE_VOLUME_MASK 0x000003 | ||
64 | |||
65 | #define JZ4740_CODEC_2_INPUT_VOLUME_OFFSET 16 | ||
66 | #define JZ4740_CODEC_2_SAMPLE_RATE_OFFSET 8 | ||
67 | #define JZ4740_CODEC_2_MIC_BOOST_GAIN_OFFSET 4 | ||
68 | #define JZ4740_CODEC_2_HEADPHONE_VOLUME_OFFSET 0 | ||
69 | |||
70 | static const uint32_t jz4740_codec_regs[] = { | ||
71 | 0x021b2302, 0x00170803, | ||
72 | }; | ||
73 | |||
74 | struct jz4740_codec { | ||
75 | void __iomem *base; | ||
76 | struct resource *mem; | ||
77 | |||
78 | uint32_t reg_cache[2]; | ||
79 | struct snd_soc_codec codec; | ||
80 | }; | ||
81 | |||
82 | static inline struct jz4740_codec *codec_to_jz4740(struct snd_soc_codec *codec) | ||
83 | { | ||
84 | return container_of(codec, struct jz4740_codec, codec); | ||
85 | } | ||
86 | |||
87 | static unsigned int jz4740_codec_read(struct snd_soc_codec *codec, | ||
88 | unsigned int reg) | ||
89 | { | ||
90 | struct jz4740_codec *jz4740_codec = codec_to_jz4740(codec); | ||
91 | return readl(jz4740_codec->base + (reg << 2)); | ||
92 | } | ||
93 | |||
94 | static int jz4740_codec_write(struct snd_soc_codec *codec, unsigned int reg, | ||
95 | unsigned int val) | ||
96 | { | ||
97 | struct jz4740_codec *jz4740_codec = codec_to_jz4740(codec); | ||
98 | |||
99 | jz4740_codec->reg_cache[reg] = val; | ||
100 | writel(val, jz4740_codec->base + (reg << 2)); | ||
101 | |||
102 | return 0; | ||
103 | } | ||
104 | |||
105 | static const struct snd_kcontrol_new jz4740_codec_controls[] = { | ||
106 | SOC_SINGLE("Master Playback Volume", JZ4740_REG_CODEC_2, | ||
107 | JZ4740_CODEC_2_HEADPHONE_VOLUME_OFFSET, 3, 0), | ||
108 | SOC_SINGLE("Master Capture Volume", JZ4740_REG_CODEC_2, | ||
109 | JZ4740_CODEC_2_INPUT_VOLUME_OFFSET, 31, 0), | ||
110 | SOC_SINGLE("Master Playback Switch", JZ4740_REG_CODEC_1, | ||
111 | JZ4740_CODEC_1_HEADPHONE_DISABLE_OFFSET, 1, 1), | ||
112 | SOC_SINGLE("Mic Capture Volume", JZ4740_REG_CODEC_2, | ||
113 | JZ4740_CODEC_2_MIC_BOOST_GAIN_OFFSET, 3, 0), | ||
114 | }; | ||
115 | |||
116 | static const struct snd_kcontrol_new jz4740_codec_output_controls[] = { | ||
117 | SOC_DAPM_SINGLE("Bypass Switch", JZ4740_REG_CODEC_1, | ||
118 | JZ4740_CODEC_1_SW1_ENABLE_OFFSET, 1, 0), | ||
119 | SOC_DAPM_SINGLE("DAC Switch", JZ4740_REG_CODEC_1, | ||
120 | JZ4740_CODEC_1_SW2_ENABLE_OFFSET, 1, 0), | ||
121 | }; | ||
122 | |||
123 | static const struct snd_kcontrol_new jz4740_codec_input_controls[] = { | ||
124 | SOC_DAPM_SINGLE("Line Capture Switch", JZ4740_REG_CODEC_1, | ||
125 | JZ4740_CODEC_1_LINE_ENABLE_OFFSET, 1, 0), | ||
126 | SOC_DAPM_SINGLE("Mic Capture Switch", JZ4740_REG_CODEC_1, | ||
127 | JZ4740_CODEC_1_MIC_ENABLE_OFFSET, 1, 0), | ||
128 | }; | ||
129 | |||
130 | static const struct snd_soc_dapm_widget jz4740_codec_dapm_widgets[] = { | ||
131 | SND_SOC_DAPM_ADC("ADC", "Capture", JZ4740_REG_CODEC_1, | ||
132 | JZ4740_CODEC_1_ADC_ENABLE_OFFSET, 0), | ||
133 | SND_SOC_DAPM_DAC("DAC", "Playback", JZ4740_REG_CODEC_1, | ||
134 | JZ4740_CODEC_1_DAC_ENABLE_OFFSET, 0), | ||
135 | |||
136 | SND_SOC_DAPM_MIXER("Output Mixer", JZ4740_REG_CODEC_1, | ||
137 | JZ4740_CODEC_1_HEADPHONE_POWERDOWN_OFFSET, 1, | ||
138 | jz4740_codec_output_controls, | ||
139 | ARRAY_SIZE(jz4740_codec_output_controls)), | ||
140 | |||
141 | SND_SOC_DAPM_MIXER_NAMED_CTL("Input Mixer", SND_SOC_NOPM, 0, 0, | ||
142 | jz4740_codec_input_controls, | ||
143 | ARRAY_SIZE(jz4740_codec_input_controls)), | ||
144 | SND_SOC_DAPM_MIXER("Line Input", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
145 | |||
146 | SND_SOC_DAPM_OUTPUT("LOUT"), | ||
147 | SND_SOC_DAPM_OUTPUT("ROUT"), | ||
148 | |||
149 | SND_SOC_DAPM_INPUT("MIC"), | ||
150 | SND_SOC_DAPM_INPUT("LIN"), | ||
151 | SND_SOC_DAPM_INPUT("RIN"), | ||
152 | }; | ||
153 | |||
154 | static const struct snd_soc_dapm_route jz4740_codec_dapm_routes[] = { | ||
155 | {"Line Input", NULL, "LIN"}, | ||
156 | {"Line Input", NULL, "RIN"}, | ||
157 | |||
158 | {"Input Mixer", "Line Capture Switch", "Line Input"}, | ||
159 | {"Input Mixer", "Mic Capture Switch", "MIC"}, | ||
160 | |||
161 | {"ADC", NULL, "Input Mixer"}, | ||
162 | |||
163 | {"Output Mixer", "Bypass Switch", "Input Mixer"}, | ||
164 | {"Output Mixer", "DAC Switch", "DAC"}, | ||
165 | |||
166 | {"LOUT", NULL, "Output Mixer"}, | ||
167 | {"ROUT", NULL, "Output Mixer"}, | ||
168 | }; | ||
169 | |||
170 | static int jz4740_codec_hw_params(struct snd_pcm_substream *substream, | ||
171 | struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) | ||
172 | { | ||
173 | uint32_t val; | ||
174 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
175 | struct snd_soc_device *socdev = rtd->socdev; | ||
176 | struct snd_soc_codec *codec = socdev->card->codec; | ||
177 | |||
178 | switch (params_rate(params)) { | ||
179 | case 8000: | ||
180 | val = 0; | ||
181 | break; | ||
182 | case 11025: | ||
183 | val = 1; | ||
184 | break; | ||
185 | case 12000: | ||
186 | val = 2; | ||
187 | break; | ||
188 | case 16000: | ||
189 | val = 3; | ||
190 | break; | ||
191 | case 22050: | ||
192 | val = 4; | ||
193 | break; | ||
194 | case 24000: | ||
195 | val = 5; | ||
196 | break; | ||
197 | case 32000: | ||
198 | val = 6; | ||
199 | break; | ||
200 | case 44100: | ||
201 | val = 7; | ||
202 | break; | ||
203 | case 48000: | ||
204 | val = 8; | ||
205 | break; | ||
206 | default: | ||
207 | return -EINVAL; | ||
208 | } | ||
209 | |||
210 | val <<= JZ4740_CODEC_2_SAMPLE_RATE_OFFSET; | ||
211 | |||
212 | snd_soc_update_bits(codec, JZ4740_REG_CODEC_2, | ||
213 | JZ4740_CODEC_2_SAMPLE_RATE_MASK, val); | ||
214 | |||
215 | return 0; | ||
216 | } | ||
217 | |||
218 | static struct snd_soc_dai_ops jz4740_codec_dai_ops = { | ||
219 | .hw_params = jz4740_codec_hw_params, | ||
220 | }; | ||
221 | |||
222 | struct snd_soc_dai jz4740_codec_dai = { | ||
223 | .name = "jz4740", | ||
224 | .playback = { | ||
225 | .stream_name = "Playback", | ||
226 | .channels_min = 2, | ||
227 | .channels_max = 2, | ||
228 | .rates = SNDRV_PCM_RATE_8000_48000, | ||
229 | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8, | ||
230 | }, | ||
231 | .capture = { | ||
232 | .stream_name = "Capture", | ||
233 | .channels_min = 2, | ||
234 | .channels_max = 2, | ||
235 | .rates = SNDRV_PCM_RATE_8000_48000, | ||
236 | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8, | ||
237 | }, | ||
238 | .ops = &jz4740_codec_dai_ops, | ||
239 | .symmetric_rates = 1, | ||
240 | }; | ||
241 | EXPORT_SYMBOL_GPL(jz4740_codec_dai); | ||
242 | |||
243 | static void jz4740_codec_wakeup(struct snd_soc_codec *codec) | ||
244 | { | ||
245 | int i; | ||
246 | uint32_t *cache = codec->reg_cache; | ||
247 | |||
248 | snd_soc_update_bits(codec, JZ4740_REG_CODEC_1, | ||
249 | JZ4740_CODEC_1_RESET, JZ4740_CODEC_1_RESET); | ||
250 | udelay(2); | ||
251 | |||
252 | snd_soc_update_bits(codec, JZ4740_REG_CODEC_1, | ||
253 | JZ4740_CODEC_1_SUSPEND | JZ4740_CODEC_1_RESET, 0); | ||
254 | |||
255 | for (i = 0; i < ARRAY_SIZE(jz4740_codec_regs); ++i) | ||
256 | jz4740_codec_write(codec, i, cache[i]); | ||
257 | } | ||
258 | |||
259 | static int jz4740_codec_set_bias_level(struct snd_soc_codec *codec, | ||
260 | enum snd_soc_bias_level level) | ||
261 | { | ||
262 | unsigned int mask; | ||
263 | unsigned int value; | ||
264 | |||
265 | switch (level) { | ||
266 | case SND_SOC_BIAS_ON: | ||
267 | break; | ||
268 | case SND_SOC_BIAS_PREPARE: | ||
269 | mask = JZ4740_CODEC_1_VREF_DISABLE | | ||
270 | JZ4740_CODEC_1_VREF_AMP_DISABLE | | ||
271 | JZ4740_CODEC_1_HEADPHONE_POWERDOWN_M; | ||
272 | value = 0; | ||
273 | |||
274 | snd_soc_update_bits(codec, JZ4740_REG_CODEC_1, mask, value); | ||
275 | break; | ||
276 | case SND_SOC_BIAS_STANDBY: | ||
277 | /* The only way to clear the suspend flag is to reset the codec */ | ||
278 | if (codec->bias_level == SND_SOC_BIAS_OFF) | ||
279 | jz4740_codec_wakeup(codec); | ||
280 | |||
281 | mask = JZ4740_CODEC_1_VREF_DISABLE | | ||
282 | JZ4740_CODEC_1_VREF_AMP_DISABLE | | ||
283 | JZ4740_CODEC_1_HEADPHONE_POWERDOWN_M; | ||
284 | value = JZ4740_CODEC_1_VREF_DISABLE | | ||
285 | JZ4740_CODEC_1_VREF_AMP_DISABLE | | ||
286 | JZ4740_CODEC_1_HEADPHONE_POWERDOWN_M; | ||
287 | |||
288 | snd_soc_update_bits(codec, JZ4740_REG_CODEC_1, mask, value); | ||
289 | break; | ||
290 | case SND_SOC_BIAS_OFF: | ||
291 | mask = JZ4740_CODEC_1_SUSPEND; | ||
292 | value = JZ4740_CODEC_1_SUSPEND; | ||
293 | |||
294 | snd_soc_update_bits(codec, JZ4740_REG_CODEC_1, mask, value); | ||
295 | break; | ||
296 | default: | ||
297 | break; | ||
298 | } | ||
299 | |||
300 | codec->bias_level = level; | ||
301 | |||
302 | return 0; | ||
303 | } | ||
304 | |||
305 | static struct snd_soc_codec *jz4740_codec_codec; | ||
306 | |||
307 | static int jz4740_codec_dev_probe(struct platform_device *pdev) | ||
308 | { | ||
309 | int ret; | ||
310 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
311 | struct snd_soc_codec *codec = jz4740_codec_codec; | ||
312 | |||
313 | BUG_ON(!codec); | ||
314 | |||
315 | socdev->card->codec = codec; | ||
316 | |||
317 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
318 | if (ret) { | ||
319 | dev_err(&pdev->dev, "Failed to create pcms: %d\n", ret); | ||
320 | return ret; | ||
321 | } | ||
322 | |||
323 | snd_soc_add_controls(codec, jz4740_codec_controls, | ||
324 | ARRAY_SIZE(jz4740_codec_controls)); | ||
325 | |||
326 | snd_soc_dapm_new_controls(codec, jz4740_codec_dapm_widgets, | ||
327 | ARRAY_SIZE(jz4740_codec_dapm_widgets)); | ||
328 | |||
329 | snd_soc_dapm_add_routes(codec, jz4740_codec_dapm_routes, | ||
330 | ARRAY_SIZE(jz4740_codec_dapm_routes)); | ||
331 | |||
332 | snd_soc_dapm_new_widgets(codec); | ||
333 | |||
334 | return 0; | ||
335 | } | ||
336 | |||
337 | static int jz4740_codec_dev_remove(struct platform_device *pdev) | ||
338 | { | ||
339 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
340 | |||
341 | snd_soc_free_pcms(socdev); | ||
342 | snd_soc_dapm_free(socdev); | ||
343 | |||
344 | return 0; | ||
345 | } | ||
346 | |||
347 | #ifdef CONFIG_PM_SLEEP | ||
348 | |||
349 | static int jz4740_codec_suspend(struct platform_device *pdev, pm_message_t state) | ||
350 | { | ||
351 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
352 | struct snd_soc_codec *codec = socdev->card->codec; | ||
353 | |||
354 | return jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
355 | } | ||
356 | |||
357 | static int jz4740_codec_resume(struct platform_device *pdev) | ||
358 | { | ||
359 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
360 | struct snd_soc_codec *codec = socdev->card->codec; | ||
361 | |||
362 | return jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
363 | } | ||
364 | |||
365 | #else | ||
366 | #define jz4740_codec_suspend NULL | ||
367 | #define jz4740_codec_resume NULL | ||
368 | #endif | ||
369 | |||
370 | struct snd_soc_codec_device soc_codec_dev_jz4740_codec = { | ||
371 | .probe = jz4740_codec_dev_probe, | ||
372 | .remove = jz4740_codec_dev_remove, | ||
373 | .suspend = jz4740_codec_suspend, | ||
374 | .resume = jz4740_codec_resume, | ||
375 | }; | ||
376 | EXPORT_SYMBOL_GPL(soc_codec_dev_jz4740_codec); | ||
377 | |||
378 | static int __devinit jz4740_codec_probe(struct platform_device *pdev) | ||
379 | { | ||
380 | int ret; | ||
381 | struct jz4740_codec *jz4740_codec; | ||
382 | struct snd_soc_codec *codec; | ||
383 | struct resource *mem; | ||
384 | |||
385 | jz4740_codec = kzalloc(sizeof(*jz4740_codec), GFP_KERNEL); | ||
386 | if (!jz4740_codec) | ||
387 | return -ENOMEM; | ||
388 | |||
389 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
390 | if (!mem) { | ||
391 | dev_err(&pdev->dev, "Failed to get mmio memory resource\n"); | ||
392 | ret = -ENOENT; | ||
393 | goto err_free_codec; | ||
394 | } | ||
395 | |||
396 | mem = request_mem_region(mem->start, resource_size(mem), pdev->name); | ||
397 | if (!mem) { | ||
398 | dev_err(&pdev->dev, "Failed to request mmio memory region\n"); | ||
399 | ret = -EBUSY; | ||
400 | goto err_free_codec; | ||
401 | } | ||
402 | |||
403 | jz4740_codec->base = ioremap(mem->start, resource_size(mem)); | ||
404 | if (!jz4740_codec->base) { | ||
405 | dev_err(&pdev->dev, "Failed to ioremap mmio memory\n"); | ||
406 | ret = -EBUSY; | ||
407 | goto err_release_mem_region; | ||
408 | } | ||
409 | jz4740_codec->mem = mem; | ||
410 | |||
411 | jz4740_codec_dai.dev = &pdev->dev; | ||
412 | |||
413 | codec = &jz4740_codec->codec; | ||
414 | |||
415 | codec->dev = &pdev->dev; | ||
416 | codec->name = "jz4740"; | ||
417 | codec->owner = THIS_MODULE; | ||
418 | |||
419 | codec->read = jz4740_codec_read; | ||
420 | codec->write = jz4740_codec_write; | ||
421 | codec->set_bias_level = jz4740_codec_set_bias_level; | ||
422 | codec->bias_level = SND_SOC_BIAS_OFF; | ||
423 | |||
424 | codec->dai = &jz4740_codec_dai; | ||
425 | codec->num_dai = 1; | ||
426 | |||
427 | codec->reg_cache = jz4740_codec->reg_cache; | ||
428 | codec->reg_cache_size = 2; | ||
429 | memcpy(codec->reg_cache, jz4740_codec_regs, sizeof(jz4740_codec_regs)); | ||
430 | |||
431 | mutex_init(&codec->mutex); | ||
432 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
433 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
434 | |||
435 | jz4740_codec_codec = codec; | ||
436 | |||
437 | snd_soc_update_bits(codec, JZ4740_REG_CODEC_1, | ||
438 | JZ4740_CODEC_1_SW2_ENABLE, JZ4740_CODEC_1_SW2_ENABLE); | ||
439 | |||
440 | platform_set_drvdata(pdev, jz4740_codec); | ||
441 | |||
442 | ret = snd_soc_register_codec(codec); | ||
443 | if (ret) { | ||
444 | dev_err(&pdev->dev, "Failed to register codec\n"); | ||
445 | goto err_iounmap; | ||
446 | } | ||
447 | |||
448 | ret = snd_soc_register_dai(&jz4740_codec_dai); | ||
449 | if (ret) { | ||
450 | dev_err(&pdev->dev, "Failed to register codec dai\n"); | ||
451 | goto err_unregister_codec; | ||
452 | } | ||
453 | |||
454 | jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
455 | |||
456 | return 0; | ||
457 | |||
458 | err_unregister_codec: | ||
459 | snd_soc_unregister_codec(codec); | ||
460 | err_iounmap: | ||
461 | iounmap(jz4740_codec->base); | ||
462 | err_release_mem_region: | ||
463 | release_mem_region(mem->start, resource_size(mem)); | ||
464 | err_free_codec: | ||
465 | kfree(jz4740_codec); | ||
466 | |||
467 | return ret; | ||
468 | } | ||
469 | |||
470 | static int __devexit jz4740_codec_remove(struct platform_device *pdev) | ||
471 | { | ||
472 | struct jz4740_codec *jz4740_codec = platform_get_drvdata(pdev); | ||
473 | struct resource *mem = jz4740_codec->mem; | ||
474 | |||
475 | snd_soc_unregister_dai(&jz4740_codec_dai); | ||
476 | snd_soc_unregister_codec(&jz4740_codec->codec); | ||
477 | |||
478 | iounmap(jz4740_codec->base); | ||
479 | release_mem_region(mem->start, resource_size(mem)); | ||
480 | |||
481 | platform_set_drvdata(pdev, NULL); | ||
482 | kfree(jz4740_codec); | ||
483 | |||
484 | return 0; | ||
485 | } | ||
486 | |||
487 | static struct platform_driver jz4740_codec_driver = { | ||
488 | .probe = jz4740_codec_probe, | ||
489 | .remove = __devexit_p(jz4740_codec_remove), | ||
490 | .driver = { | ||
491 | .name = "jz4740-codec", | ||
492 | .owner = THIS_MODULE, | ||
493 | }, | ||
494 | }; | ||
495 | |||
496 | static int __init jz4740_codec_init(void) | ||
497 | { | ||
498 | return platform_driver_register(&jz4740_codec_driver); | ||
499 | } | ||
500 | module_init(jz4740_codec_init); | ||
501 | |||
502 | static void __exit jz4740_codec_exit(void) | ||
503 | { | ||
504 | platform_driver_unregister(&jz4740_codec_driver); | ||
505 | } | ||
506 | module_exit(jz4740_codec_exit); | ||
507 | |||
508 | MODULE_DESCRIPTION("JZ4740 SoC internal codec driver"); | ||
509 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); | ||
510 | MODULE_LICENSE("GPL v2"); | ||
511 | MODULE_ALIAS("platform:jz4740-codec"); | ||
diff --git a/sound/soc/codecs/jz4740.h b/sound/soc/codecs/jz4740.h new file mode 100644 index 000000000000..b5a0691be763 --- /dev/null +++ b/sound/soc/codecs/jz4740.h | |||
@@ -0,0 +1,20 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009, Lars-Peter Clausen <lars@metafoo.de> | ||
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 | * You should have received a copy of the GNU General Public License along | ||
9 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
10 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #ifndef __SND_SOC_CODECS_JZ4740_CODEC_H__ | ||
15 | #define __SND_SOC_CODECS_JZ4740_CODEC_H__ | ||
16 | |||
17 | extern struct snd_soc_dai jz4740_codec_dai; | ||
18 | extern struct snd_soc_codec_device soc_codec_dev_jz4740_codec; | ||
19 | |||
20 | #endif | ||
diff --git a/sound/soc/codecs/spdif_transciever.c b/sound/soc/codecs/spdif_transciever.c index a63191141052..9119836051a4 100644 --- a/sound/soc/codecs/spdif_transciever.c +++ b/sound/soc/codecs/spdif_transciever.c | |||
@@ -16,8 +16,10 @@ | |||
16 | 16 | ||
17 | #include <linux/module.h> | 17 | #include <linux/module.h> |
18 | #include <linux/moduleparam.h> | 18 | #include <linux/moduleparam.h> |
19 | #include <linux/slab.h> | ||
19 | #include <sound/soc.h> | 20 | #include <sound/soc.h> |
20 | #include <sound/pcm.h> | 21 | #include <sound/pcm.h> |
22 | #include <sound/initval.h> | ||
21 | 23 | ||
22 | #include "spdif_transciever.h" | 24 | #include "spdif_transciever.h" |
23 | 25 | ||
@@ -26,6 +28,48 @@ MODULE_LICENSE("GPL"); | |||
26 | #define STUB_RATES SNDRV_PCM_RATE_8000_96000 | 28 | #define STUB_RATES SNDRV_PCM_RATE_8000_96000 |
27 | #define STUB_FORMATS SNDRV_PCM_FMTBIT_S16_LE | 29 | #define STUB_FORMATS SNDRV_PCM_FMTBIT_S16_LE |
28 | 30 | ||
31 | static struct snd_soc_codec *spdif_dit_codec; | ||
32 | |||
33 | static int spdif_dit_codec_probe(struct platform_device *pdev) | ||
34 | { | ||
35 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
36 | struct snd_soc_codec *codec; | ||
37 | int ret; | ||
38 | |||
39 | if (spdif_dit_codec == NULL) { | ||
40 | dev_err(&pdev->dev, "Codec device not registered\n"); | ||
41 | return -ENODEV; | ||
42 | } | ||
43 | |||
44 | socdev->card->codec = spdif_dit_codec; | ||
45 | codec = spdif_dit_codec; | ||
46 | |||
47 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
48 | if (ret < 0) { | ||
49 | dev_err(codec->dev, "failed to create pcms: %d\n", ret); | ||
50 | goto err_create_pcms; | ||
51 | } | ||
52 | |||
53 | return 0; | ||
54 | |||
55 | err_create_pcms: | ||
56 | return ret; | ||
57 | } | ||
58 | |||
59 | static int spdif_dit_codec_remove(struct platform_device *pdev) | ||
60 | { | ||
61 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
62 | |||
63 | snd_soc_free_pcms(socdev); | ||
64 | |||
65 | return 0; | ||
66 | } | ||
67 | |||
68 | struct snd_soc_codec_device soc_codec_dev_spdif_dit = { | ||
69 | .probe = spdif_dit_codec_probe, | ||
70 | .remove = spdif_dit_codec_remove, | ||
71 | }; EXPORT_SYMBOL_GPL(soc_codec_dev_spdif_dit); | ||
72 | |||
29 | struct snd_soc_dai dit_stub_dai = { | 73 | struct snd_soc_dai dit_stub_dai = { |
30 | .name = "DIT", | 74 | .name = "DIT", |
31 | .playback = { | 75 | .playback = { |
@@ -40,13 +84,61 @@ EXPORT_SYMBOL_GPL(dit_stub_dai); | |||
40 | 84 | ||
41 | static int spdif_dit_probe(struct platform_device *pdev) | 85 | static int spdif_dit_probe(struct platform_device *pdev) |
42 | { | 86 | { |
87 | struct snd_soc_codec *codec; | ||
88 | int ret; | ||
89 | |||
90 | if (spdif_dit_codec) { | ||
91 | dev_err(&pdev->dev, "Another Codec is registered\n"); | ||
92 | ret = -EINVAL; | ||
93 | goto err_reg_codec; | ||
94 | } | ||
95 | |||
96 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | ||
97 | if (codec == NULL) | ||
98 | return -ENOMEM; | ||
99 | |||
100 | codec->dev = &pdev->dev; | ||
101 | |||
102 | mutex_init(&codec->mutex); | ||
103 | |||
104 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
105 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
106 | |||
107 | codec->name = "spdif-dit"; | ||
108 | codec->owner = THIS_MODULE; | ||
109 | codec->dai = &dit_stub_dai; | ||
110 | codec->num_dai = 1; | ||
111 | |||
112 | spdif_dit_codec = codec; | ||
113 | |||
114 | ret = snd_soc_register_codec(codec); | ||
115 | if (ret < 0) { | ||
116 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); | ||
117 | goto err_reg_codec; | ||
118 | } | ||
119 | |||
43 | dit_stub_dai.dev = &pdev->dev; | 120 | dit_stub_dai.dev = &pdev->dev; |
44 | return snd_soc_register_dai(&dit_stub_dai); | 121 | ret = snd_soc_register_dai(&dit_stub_dai); |
122 | if (ret < 0) { | ||
123 | dev_err(codec->dev, "Failed to register dai: %d\n", ret); | ||
124 | goto err_reg_dai; | ||
125 | } | ||
126 | |||
127 | return 0; | ||
128 | |||
129 | err_reg_dai: | ||
130 | snd_soc_unregister_codec(codec); | ||
131 | err_reg_codec: | ||
132 | kfree(spdif_dit_codec); | ||
133 | return ret; | ||
45 | } | 134 | } |
46 | 135 | ||
47 | static int spdif_dit_remove(struct platform_device *pdev) | 136 | static int spdif_dit_remove(struct platform_device *pdev) |
48 | { | 137 | { |
49 | snd_soc_unregister_dai(&dit_stub_dai); | 138 | snd_soc_unregister_dai(&dit_stub_dai); |
139 | snd_soc_unregister_codec(spdif_dit_codec); | ||
140 | kfree(spdif_dit_codec); | ||
141 | spdif_dit_codec = NULL; | ||
50 | return 0; | 142 | return 0; |
51 | } | 143 | } |
52 | 144 | ||
diff --git a/sound/soc/codecs/spdif_transciever.h b/sound/soc/codecs/spdif_transciever.h index 296f2eb6c4ef..1e102124f546 100644 --- a/sound/soc/codecs/spdif_transciever.h +++ b/sound/soc/codecs/spdif_transciever.h | |||
@@ -12,6 +12,7 @@ | |||
12 | #ifndef CODEC_STUBS_H | 12 | #ifndef CODEC_STUBS_H |
13 | #define CODEC_STUBS_H | 13 | #define CODEC_STUBS_H |
14 | 14 | ||
15 | extern struct snd_soc_codec_device soc_codec_dev_spdif_dit; | ||
15 | extern struct snd_soc_dai dit_stub_dai; | 16 | extern struct snd_soc_dai dit_stub_dai; |
16 | 17 | ||
17 | #endif /* CODEC_STUBS_H */ | 18 | #endif /* CODEC_STUBS_H */ |
diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c index b0bae3508b29..0a4b0fef3355 100644 --- a/sound/soc/codecs/tlv320aic23.c +++ b/sound/soc/codecs/tlv320aic23.c | |||
@@ -560,13 +560,16 @@ static int tlv320aic23_set_bias_level(struct snd_soc_codec *codec, | |||
560 | switch (level) { | 560 | switch (level) { |
561 | case SND_SOC_BIAS_ON: | 561 | case SND_SOC_BIAS_ON: |
562 | /* vref/mid, osc on, dac unmute */ | 562 | /* vref/mid, osc on, dac unmute */ |
563 | reg &= ~(TLV320AIC23_DEVICE_PWR_OFF | TLV320AIC23_OSC_OFF | \ | ||
564 | TLV320AIC23_DAC_OFF); | ||
563 | tlv320aic23_write(codec, TLV320AIC23_PWR, reg); | 565 | tlv320aic23_write(codec, TLV320AIC23_PWR, reg); |
564 | break; | 566 | break; |
565 | case SND_SOC_BIAS_PREPARE: | 567 | case SND_SOC_BIAS_PREPARE: |
566 | break; | 568 | break; |
567 | case SND_SOC_BIAS_STANDBY: | 569 | case SND_SOC_BIAS_STANDBY: |
568 | /* everything off except vref/vmid, */ | 570 | /* everything off except vref/vmid, */ |
569 | tlv320aic23_write(codec, TLV320AIC23_PWR, reg | 0x0040); | 571 | tlv320aic23_write(codec, TLV320AIC23_PWR, reg | \ |
572 | TLV320AIC23_CLK_OFF); | ||
570 | break; | 573 | break; |
571 | case SND_SOC_BIAS_OFF: | 574 | case SND_SOC_BIAS_OFF: |
572 | /* everything off, dac mute, inactive */ | 575 | /* everything off, dac mute, inactive */ |
@@ -615,7 +618,6 @@ static int tlv320aic23_suspend(struct platform_device *pdev, | |||
615 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 618 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
616 | struct snd_soc_codec *codec = socdev->card->codec; | 619 | struct snd_soc_codec *codec = socdev->card->codec; |
617 | 620 | ||
618 | tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0); | ||
619 | tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF); | 621 | tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF); |
620 | 622 | ||
621 | return 0; | 623 | return 0; |
@@ -632,7 +634,6 @@ static int tlv320aic23_resume(struct platform_device *pdev) | |||
632 | u16 val = tlv320aic23_read_reg_cache(codec, reg); | 634 | u16 val = tlv320aic23_read_reg_cache(codec, reg); |
633 | tlv320aic23_write(codec, reg, val); | 635 | tlv320aic23_write(codec, reg, val); |
634 | } | 636 | } |
635 | |||
636 | tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 637 | tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
637 | 638 | ||
638 | return 0; | 639 | return 0; |
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index 65adc77eada1..8651b01ed223 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c | |||
@@ -49,8 +49,6 @@ | |||
49 | 49 | ||
50 | #define NSAMPLE_MAX 5700 | 50 | #define NSAMPLE_MAX 5700 |
51 | 51 | ||
52 | #define LATENCY_TIME_MS 20 | ||
53 | |||
54 | #define MODE7_LTHR 10 | 52 | #define MODE7_LTHR 10 |
55 | #define MODE7_UTHR (DAC33_BUFFER_SIZE_SAMPLES - 10) | 53 | #define MODE7_UTHR (DAC33_BUFFER_SIZE_SAMPLES - 10) |
56 | 54 | ||
@@ -62,6 +60,9 @@ | |||
62 | #define US_TO_SAMPLES(rate, us) \ | 60 | #define US_TO_SAMPLES(rate, us) \ |
63 | (rate / (1000000 / us)) | 61 | (rate / (1000000 / us)) |
64 | 62 | ||
63 | #define UTHR_FROM_PERIOD_SIZE(samples, playrate, burstrate) \ | ||
64 | ((samples * 5000) / ((burstrate * 5000) / (burstrate - playrate))) | ||
65 | |||
65 | static void dac33_calculate_times(struct snd_pcm_substream *substream); | 66 | static void dac33_calculate_times(struct snd_pcm_substream *substream); |
66 | static int dac33_prepare_chip(struct snd_pcm_substream *substream); | 67 | static int dac33_prepare_chip(struct snd_pcm_substream *substream); |
67 | 68 | ||
@@ -107,6 +108,10 @@ struct tlv320dac33_priv { | |||
107 | * this */ | 108 | * this */ |
108 | enum dac33_fifo_modes fifo_mode;/* FIFO mode selection */ | 109 | enum dac33_fifo_modes fifo_mode;/* FIFO mode selection */ |
109 | unsigned int nsample; /* burst read amount from host */ | 110 | unsigned int nsample; /* burst read amount from host */ |
111 | int mode1_latency; /* latency caused by the i2c writes in | ||
112 | * us */ | ||
113 | int auto_fifo_config; /* Configure the FIFO based on the | ||
114 | * period size */ | ||
110 | u8 burst_bclkdiv; /* BCLK divider value in burst mode */ | 115 | u8 burst_bclkdiv; /* BCLK divider value in burst mode */ |
111 | unsigned int burst_rate; /* Interface speed in Burst modes */ | 116 | unsigned int burst_rate; /* Interface speed in Burst modes */ |
112 | 117 | ||
@@ -120,6 +125,8 @@ struct tlv320dac33_priv { | |||
120 | * samples */ | 125 | * samples */ |
121 | unsigned int mode7_us_to_lthr; /* Time to reach lthr from uthr */ | 126 | unsigned int mode7_us_to_lthr; /* Time to reach lthr from uthr */ |
122 | 127 | ||
128 | unsigned int uthr; | ||
129 | |||
123 | enum dac33_state state; | 130 | enum dac33_state state; |
124 | }; | 131 | }; |
125 | 132 | ||
@@ -442,6 +449,39 @@ static int dac33_set_nsample(struct snd_kcontrol *kcontrol, | |||
442 | return ret; | 449 | return ret; |
443 | } | 450 | } |
444 | 451 | ||
452 | static int dac33_get_uthr(struct snd_kcontrol *kcontrol, | ||
453 | struct snd_ctl_elem_value *ucontrol) | ||
454 | { | ||
455 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
456 | struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec); | ||
457 | |||
458 | ucontrol->value.integer.value[0] = dac33->uthr; | ||
459 | |||
460 | return 0; | ||
461 | } | ||
462 | |||
463 | static int dac33_set_uthr(struct snd_kcontrol *kcontrol, | ||
464 | struct snd_ctl_elem_value *ucontrol) | ||
465 | { | ||
466 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
467 | struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec); | ||
468 | int ret = 0; | ||
469 | |||
470 | if (dac33->substream) | ||
471 | return -EBUSY; | ||
472 | |||
473 | if (dac33->uthr == ucontrol->value.integer.value[0]) | ||
474 | return 0; | ||
475 | |||
476 | if (ucontrol->value.integer.value[0] < (MODE7_LTHR + 10) || | ||
477 | ucontrol->value.integer.value[0] > MODE7_UTHR) | ||
478 | ret = -EINVAL; | ||
479 | else | ||
480 | dac33->uthr = ucontrol->value.integer.value[0]; | ||
481 | |||
482 | return ret; | ||
483 | } | ||
484 | |||
445 | static int dac33_get_fifo_mode(struct snd_kcontrol *kcontrol, | 485 | static int dac33_get_fifo_mode(struct snd_kcontrol *kcontrol, |
446 | struct snd_ctl_elem_value *ucontrol) | 486 | struct snd_ctl_elem_value *ucontrol) |
447 | { | 487 | { |
@@ -503,13 +543,18 @@ static const struct snd_kcontrol_new dac33_snd_controls[] = { | |||
503 | DAC33_LINEL_TO_LLO_VOL, DAC33_LINER_TO_RLO_VOL, 0, 127, 1), | 543 | DAC33_LINEL_TO_LLO_VOL, DAC33_LINER_TO_RLO_VOL, 0, 127, 1), |
504 | }; | 544 | }; |
505 | 545 | ||
506 | static const struct snd_kcontrol_new dac33_nsample_snd_controls[] = { | 546 | static const struct snd_kcontrol_new dac33_mode_snd_controls[] = { |
507 | SOC_SINGLE_EXT("nSample", 0, 0, 5900, 0, | ||
508 | dac33_get_nsample, dac33_set_nsample), | ||
509 | SOC_ENUM_EXT("FIFO Mode", dac33_fifo_mode_enum, | 547 | SOC_ENUM_EXT("FIFO Mode", dac33_fifo_mode_enum, |
510 | dac33_get_fifo_mode, dac33_set_fifo_mode), | 548 | dac33_get_fifo_mode, dac33_set_fifo_mode), |
511 | }; | 549 | }; |
512 | 550 | ||
551 | static const struct snd_kcontrol_new dac33_fifo_snd_controls[] = { | ||
552 | SOC_SINGLE_EXT("nSample", 0, 0, 5900, 0, | ||
553 | dac33_get_nsample, dac33_set_nsample), | ||
554 | SOC_SINGLE_EXT("UTHR", 0, 0, MODE7_UTHR, 0, | ||
555 | dac33_get_uthr, dac33_set_uthr), | ||
556 | }; | ||
557 | |||
513 | /* Analog bypass */ | 558 | /* Analog bypass */ |
514 | static const struct snd_kcontrol_new dac33_dapm_abypassl_control = | 559 | static const struct snd_kcontrol_new dac33_dapm_abypassl_control = |
515 | SOC_DAPM_SINGLE("Switch", DAC33_LINEL_TO_LLO_VOL, 7, 1, 1); | 560 | SOC_DAPM_SINGLE("Switch", DAC33_LINEL_TO_LLO_VOL, 7, 1, 1); |
@@ -612,7 +657,7 @@ static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33) | |||
612 | switch (dac33->fifo_mode) { | 657 | switch (dac33->fifo_mode) { |
613 | case DAC33_FIFO_MODE1: | 658 | case DAC33_FIFO_MODE1: |
614 | dac33_write16(codec, DAC33_NSAMPLE_MSB, | 659 | dac33_write16(codec, DAC33_NSAMPLE_MSB, |
615 | DAC33_THRREG(dac33->nsample + dac33->alarm_threshold)); | 660 | DAC33_THRREG(dac33->nsample)); |
616 | 661 | ||
617 | /* Take the timestamps */ | 662 | /* Take the timestamps */ |
618 | spin_lock_irq(&dac33->lock); | 663 | spin_lock_irq(&dac33->lock); |
@@ -761,6 +806,10 @@ static void dac33_shutdown(struct snd_pcm_substream *substream, | |||
761 | struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec); | 806 | struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec); |
762 | 807 | ||
763 | dac33->substream = NULL; | 808 | dac33->substream = NULL; |
809 | |||
810 | /* Reset the nSample restrictions */ | ||
811 | dac33->nsample_min = 0; | ||
812 | dac33->nsample_max = NSAMPLE_MAX; | ||
764 | } | 813 | } |
765 | 814 | ||
766 | static int dac33_hw_params(struct snd_pcm_substream *substream, | 815 | static int dac33_hw_params(struct snd_pcm_substream *substream, |
@@ -985,7 +1034,7 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream) | |||
985 | * Configure the threshold levels, and leave 10 sample space | 1034 | * Configure the threshold levels, and leave 10 sample space |
986 | * at the bottom, and also at the top of the FIFO | 1035 | * at the bottom, and also at the top of the FIFO |
987 | */ | 1036 | */ |
988 | dac33_write16(codec, DAC33_UTHR_MSB, DAC33_THRREG(MODE7_UTHR)); | 1037 | dac33_write16(codec, DAC33_UTHR_MSB, DAC33_THRREG(dac33->uthr)); |
989 | dac33_write16(codec, DAC33_LTHR_MSB, DAC33_THRREG(MODE7_LTHR)); | 1038 | dac33_write16(codec, DAC33_LTHR_MSB, DAC33_THRREG(MODE7_LTHR)); |
990 | break; | 1039 | break; |
991 | default: | 1040 | default: |
@@ -1003,57 +1052,71 @@ static void dac33_calculate_times(struct snd_pcm_substream *substream) | |||
1003 | struct snd_soc_device *socdev = rtd->socdev; | 1052 | struct snd_soc_device *socdev = rtd->socdev; |
1004 | struct snd_soc_codec *codec = socdev->card->codec; | 1053 | struct snd_soc_codec *codec = socdev->card->codec; |
1005 | struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec); | 1054 | struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec); |
1055 | unsigned int period_size = substream->runtime->period_size; | ||
1056 | unsigned int rate = substream->runtime->rate; | ||
1006 | unsigned int nsample_limit; | 1057 | unsigned int nsample_limit; |
1007 | 1058 | ||
1008 | /* In bypass mode we don't need to calculate */ | 1059 | /* In bypass mode we don't need to calculate */ |
1009 | if (!dac33->fifo_mode) | 1060 | if (!dac33->fifo_mode) |
1010 | return; | 1061 | return; |
1011 | 1062 | ||
1012 | /* Number of samples (16bit, stereo) in one period */ | ||
1013 | dac33->nsample_min = snd_pcm_lib_period_bytes(substream) / 4; | ||
1014 | |||
1015 | /* Number of samples (16bit, stereo) in ALSA buffer */ | ||
1016 | dac33->nsample_max = snd_pcm_lib_buffer_bytes(substream) / 4; | ||
1017 | /* Subtract one period from the total */ | ||
1018 | dac33->nsample_max -= dac33->nsample_min; | ||
1019 | |||
1020 | /* Number of samples for LATENCY_TIME_MS / 2 */ | ||
1021 | dac33->alarm_threshold = substream->runtime->rate / | ||
1022 | (1000 / (LATENCY_TIME_MS / 2)); | ||
1023 | |||
1024 | /* Find and fix up the lowest nsmaple limit */ | ||
1025 | nsample_limit = substream->runtime->rate / (1000 / LATENCY_TIME_MS); | ||
1026 | |||
1027 | if (dac33->nsample_min < nsample_limit) | ||
1028 | dac33->nsample_min = nsample_limit; | ||
1029 | |||
1030 | if (dac33->nsample < dac33->nsample_min) | ||
1031 | dac33->nsample = dac33->nsample_min; | ||
1032 | |||
1033 | /* | ||
1034 | * Find and fix up the highest nsmaple limit | ||
1035 | * In order to not overflow the DAC33 buffer substract the | ||
1036 | * alarm_threshold value from the size of the DAC33 buffer | ||
1037 | */ | ||
1038 | nsample_limit = DAC33_BUFFER_SIZE_SAMPLES - dac33->alarm_threshold; | ||
1039 | |||
1040 | if (dac33->nsample_max > nsample_limit) | ||
1041 | dac33->nsample_max = nsample_limit; | ||
1042 | |||
1043 | if (dac33->nsample > dac33->nsample_max) | ||
1044 | dac33->nsample = dac33->nsample_max; | ||
1045 | |||
1046 | switch (dac33->fifo_mode) { | 1063 | switch (dac33->fifo_mode) { |
1047 | case DAC33_FIFO_MODE1: | 1064 | case DAC33_FIFO_MODE1: |
1065 | /* Number of samples under i2c latency */ | ||
1066 | dac33->alarm_threshold = US_TO_SAMPLES(rate, | ||
1067 | dac33->mode1_latency); | ||
1068 | if (dac33->auto_fifo_config) { | ||
1069 | if (period_size <= dac33->alarm_threshold) | ||
1070 | /* | ||
1071 | * Configure nSamaple to number of periods, | ||
1072 | * which covers the latency requironment. | ||
1073 | */ | ||
1074 | dac33->nsample = period_size * | ||
1075 | ((dac33->alarm_threshold / period_size) + | ||
1076 | (dac33->alarm_threshold % period_size ? | ||
1077 | 1 : 0)); | ||
1078 | else | ||
1079 | dac33->nsample = period_size; | ||
1080 | } else { | ||
1081 | /* nSample time shall not be shorter than i2c latency */ | ||
1082 | dac33->nsample_min = dac33->alarm_threshold; | ||
1083 | /* | ||
1084 | * nSample should not be bigger than alsa buffer minus | ||
1085 | * size of one period to avoid overruns | ||
1086 | */ | ||
1087 | dac33->nsample_max = substream->runtime->buffer_size - | ||
1088 | period_size; | ||
1089 | nsample_limit = DAC33_BUFFER_SIZE_SAMPLES - | ||
1090 | dac33->alarm_threshold; | ||
1091 | if (dac33->nsample_max > nsample_limit) | ||
1092 | dac33->nsample_max = nsample_limit; | ||
1093 | |||
1094 | /* Correct the nSample if it is outside of the ranges */ | ||
1095 | if (dac33->nsample < dac33->nsample_min) | ||
1096 | dac33->nsample = dac33->nsample_min; | ||
1097 | if (dac33->nsample > dac33->nsample_max) | ||
1098 | dac33->nsample = dac33->nsample_max; | ||
1099 | } | ||
1100 | |||
1048 | dac33->mode1_us_burst = SAMPLES_TO_US(dac33->burst_rate, | 1101 | dac33->mode1_us_burst = SAMPLES_TO_US(dac33->burst_rate, |
1049 | dac33->nsample); | 1102 | dac33->nsample); |
1050 | dac33->t_stamp1 = 0; | 1103 | dac33->t_stamp1 = 0; |
1051 | dac33->t_stamp2 = 0; | 1104 | dac33->t_stamp2 = 0; |
1052 | break; | 1105 | break; |
1053 | case DAC33_FIFO_MODE7: | 1106 | case DAC33_FIFO_MODE7: |
1107 | if (dac33->auto_fifo_config) { | ||
1108 | dac33->uthr = UTHR_FROM_PERIOD_SIZE( | ||
1109 | period_size, | ||
1110 | rate, | ||
1111 | dac33->burst_rate) + 9; | ||
1112 | if (dac33->uthr > MODE7_UTHR) | ||
1113 | dac33->uthr = MODE7_UTHR; | ||
1114 | if (dac33->uthr < (MODE7_LTHR + 10)) | ||
1115 | dac33->uthr = (MODE7_LTHR + 10); | ||
1116 | } | ||
1054 | dac33->mode7_us_to_lthr = | 1117 | dac33->mode7_us_to_lthr = |
1055 | SAMPLES_TO_US(substream->runtime->rate, | 1118 | SAMPLES_TO_US(substream->runtime->rate, |
1056 | MODE7_UTHR - MODE7_LTHR + 1); | 1119 | dac33->uthr - MODE7_LTHR + 1); |
1057 | dac33->t_stamp1 = 0; | 1120 | dac33->t_stamp1 = 0; |
1058 | break; | 1121 | break; |
1059 | default: | 1122 | default: |
@@ -1104,7 +1167,7 @@ static snd_pcm_sframes_t dac33_dai_delay( | |||
1104 | struct snd_soc_codec *codec = socdev->card->codec; | 1167 | struct snd_soc_codec *codec = socdev->card->codec; |
1105 | struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec); | 1168 | struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec); |
1106 | unsigned long long t0, t1, t_now; | 1169 | unsigned long long t0, t1, t_now; |
1107 | unsigned int time_delta; | 1170 | unsigned int time_delta, uthr; |
1108 | int samples_out, samples_in, samples; | 1171 | int samples_out, samples_in, samples; |
1109 | snd_pcm_sframes_t delay = 0; | 1172 | snd_pcm_sframes_t delay = 0; |
1110 | 1173 | ||
@@ -1182,6 +1245,7 @@ static snd_pcm_sframes_t dac33_dai_delay( | |||
1182 | case DAC33_FIFO_MODE7: | 1245 | case DAC33_FIFO_MODE7: |
1183 | spin_lock(&dac33->lock); | 1246 | spin_lock(&dac33->lock); |
1184 | t0 = dac33->t_stamp1; | 1247 | t0 = dac33->t_stamp1; |
1248 | uthr = dac33->uthr; | ||
1185 | spin_unlock(&dac33->lock); | 1249 | spin_unlock(&dac33->lock); |
1186 | t_now = ktime_to_us(ktime_get()); | 1250 | t_now = ktime_to_us(ktime_get()); |
1187 | 1251 | ||
@@ -1194,7 +1258,7 @@ static snd_pcm_sframes_t dac33_dai_delay( | |||
1194 | * Either the timestamps are messed or equal. Report | 1258 | * Either the timestamps are messed or equal. Report |
1195 | * maximum delay | 1259 | * maximum delay |
1196 | */ | 1260 | */ |
1197 | delay = MODE7_UTHR; | 1261 | delay = uthr; |
1198 | goto out; | 1262 | goto out; |
1199 | } | 1263 | } |
1200 | 1264 | ||
@@ -1208,8 +1272,8 @@ static snd_pcm_sframes_t dac33_dai_delay( | |||
1208 | substream->runtime->rate, | 1272 | substream->runtime->rate, |
1209 | time_delta); | 1273 | time_delta); |
1210 | 1274 | ||
1211 | if (likely(MODE7_UTHR > samples_out)) | 1275 | if (likely(uthr > samples_out)) |
1212 | delay = MODE7_UTHR - samples_out; | 1276 | delay = uthr - samples_out; |
1213 | else | 1277 | else |
1214 | delay = 0; | 1278 | delay = 0; |
1215 | } else { | 1279 | } else { |
@@ -1227,8 +1291,8 @@ static snd_pcm_sframes_t dac33_dai_delay( | |||
1227 | time_delta); | 1291 | time_delta); |
1228 | delay = MODE7_LTHR + samples_in - samples_out; | 1292 | delay = MODE7_LTHR + samples_in - samples_out; |
1229 | 1293 | ||
1230 | if (unlikely(delay > MODE7_UTHR)) | 1294 | if (unlikely(delay > uthr)) |
1231 | delay = MODE7_UTHR; | 1295 | delay = uthr; |
1232 | } | 1296 | } |
1233 | break; | 1297 | break; |
1234 | default: | 1298 | default: |
@@ -1347,10 +1411,15 @@ static int dac33_soc_probe(struct platform_device *pdev) | |||
1347 | 1411 | ||
1348 | snd_soc_add_controls(codec, dac33_snd_controls, | 1412 | snd_soc_add_controls(codec, dac33_snd_controls, |
1349 | ARRAY_SIZE(dac33_snd_controls)); | 1413 | ARRAY_SIZE(dac33_snd_controls)); |
1350 | /* Only add the nSample controls, if we have valid IRQ number */ | 1414 | /* Only add the FIFO controls, if we have valid IRQ number */ |
1351 | if (dac33->irq >= 0) | 1415 | if (dac33->irq >= 0) { |
1352 | snd_soc_add_controls(codec, dac33_nsample_snd_controls, | 1416 | snd_soc_add_controls(codec, dac33_mode_snd_controls, |
1353 | ARRAY_SIZE(dac33_nsample_snd_controls)); | 1417 | ARRAY_SIZE(dac33_mode_snd_controls)); |
1418 | /* FIFO usage controls only, if autoio config is not selected */ | ||
1419 | if (!dac33->auto_fifo_config) | ||
1420 | snd_soc_add_controls(codec, dac33_fifo_snd_controls, | ||
1421 | ARRAY_SIZE(dac33_fifo_snd_controls)); | ||
1422 | } | ||
1354 | 1423 | ||
1355 | dac33_add_widgets(codec); | 1424 | dac33_add_widgets(codec); |
1356 | 1425 | ||
@@ -1481,9 +1550,14 @@ static int __devinit dac33_i2c_probe(struct i2c_client *client, | |||
1481 | /* Pre calculate the burst rate */ | 1550 | /* Pre calculate the burst rate */ |
1482 | dac33->burst_rate = BURST_BASEFREQ_HZ / dac33->burst_bclkdiv / 32; | 1551 | dac33->burst_rate = BURST_BASEFREQ_HZ / dac33->burst_bclkdiv / 32; |
1483 | dac33->keep_bclk = pdata->keep_bclk; | 1552 | dac33->keep_bclk = pdata->keep_bclk; |
1553 | dac33->auto_fifo_config = pdata->auto_fifo_config; | ||
1554 | dac33->mode1_latency = pdata->mode1_latency; | ||
1555 | if (!dac33->mode1_latency) | ||
1556 | dac33->mode1_latency = 10000; /* 10ms */ | ||
1484 | dac33->irq = client->irq; | 1557 | dac33->irq = client->irq; |
1485 | dac33->nsample = NSAMPLE_MAX; | 1558 | dac33->nsample = NSAMPLE_MAX; |
1486 | dac33->nsample_max = NSAMPLE_MAX; | 1559 | dac33->nsample_max = NSAMPLE_MAX; |
1560 | dac33->uthr = MODE7_UTHR; | ||
1487 | /* Disable FIFO use by default */ | 1561 | /* Disable FIFO use by default */ |
1488 | dac33->fifo_mode = DAC33_FIFO_BYPASS; | 1562 | dac33->fifo_mode = DAC33_FIFO_BYPASS; |
1489 | 1563 | ||
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index b4fcdb01fc49..7b618bbff884 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c | |||
@@ -43,37 +43,37 @@ | |||
43 | */ | 43 | */ |
44 | static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = { | 44 | static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = { |
45 | 0x00, /* this register not used */ | 45 | 0x00, /* this register not used */ |
46 | 0x91, /* REG_CODEC_MODE (0x1) */ | 46 | 0x00, /* REG_CODEC_MODE (0x1) */ |
47 | 0xc3, /* REG_OPTION (0x2) */ | 47 | 0x00, /* REG_OPTION (0x2) */ |
48 | 0x00, /* REG_UNKNOWN (0x3) */ | 48 | 0x00, /* REG_UNKNOWN (0x3) */ |
49 | 0x00, /* REG_MICBIAS_CTL (0x4) */ | 49 | 0x00, /* REG_MICBIAS_CTL (0x4) */ |
50 | 0x20, /* REG_ANAMICL (0x5) */ | 50 | 0x00, /* REG_ANAMICL (0x5) */ |
51 | 0x00, /* REG_ANAMICR (0x6) */ | 51 | 0x00, /* REG_ANAMICR (0x6) */ |
52 | 0x00, /* REG_AVADC_CTL (0x7) */ | 52 | 0x00, /* REG_AVADC_CTL (0x7) */ |
53 | 0x00, /* REG_ADCMICSEL (0x8) */ | 53 | 0x00, /* REG_ADCMICSEL (0x8) */ |
54 | 0x00, /* REG_DIGMIXING (0x9) */ | 54 | 0x00, /* REG_DIGMIXING (0x9) */ |
55 | 0x0c, /* REG_ATXL1PGA (0xA) */ | 55 | 0x0f, /* REG_ATXL1PGA (0xA) */ |
56 | 0x0c, /* REG_ATXR1PGA (0xB) */ | 56 | 0x0f, /* REG_ATXR1PGA (0xB) */ |
57 | 0x00, /* REG_AVTXL2PGA (0xC) */ | 57 | 0x0f, /* REG_AVTXL2PGA (0xC) */ |
58 | 0x00, /* REG_AVTXR2PGA (0xD) */ | 58 | 0x0f, /* REG_AVTXR2PGA (0xD) */ |
59 | 0x00, /* REG_AUDIO_IF (0xE) */ | 59 | 0x00, /* REG_AUDIO_IF (0xE) */ |
60 | 0x00, /* REG_VOICE_IF (0xF) */ | 60 | 0x00, /* REG_VOICE_IF (0xF) */ |
61 | 0x00, /* REG_ARXR1PGA (0x10) */ | 61 | 0x3f, /* REG_ARXR1PGA (0x10) */ |
62 | 0x00, /* REG_ARXL1PGA (0x11) */ | 62 | 0x3f, /* REG_ARXL1PGA (0x11) */ |
63 | 0x6c, /* REG_ARXR2PGA (0x12) */ | 63 | 0x3f, /* REG_ARXR2PGA (0x12) */ |
64 | 0x6c, /* REG_ARXL2PGA (0x13) */ | 64 | 0x3f, /* REG_ARXL2PGA (0x13) */ |
65 | 0x00, /* REG_VRXPGA (0x14) */ | 65 | 0x25, /* REG_VRXPGA (0x14) */ |
66 | 0x00, /* REG_VSTPGA (0x15) */ | 66 | 0x00, /* REG_VSTPGA (0x15) */ |
67 | 0x00, /* REG_VRX2ARXPGA (0x16) */ | 67 | 0x00, /* REG_VRX2ARXPGA (0x16) */ |
68 | 0x00, /* REG_AVDAC_CTL (0x17) */ | 68 | 0x00, /* REG_AVDAC_CTL (0x17) */ |
69 | 0x00, /* REG_ARX2VTXPGA (0x18) */ | 69 | 0x00, /* REG_ARX2VTXPGA (0x18) */ |
70 | 0x00, /* REG_ARXL1_APGA_CTL (0x19) */ | 70 | 0x32, /* REG_ARXL1_APGA_CTL (0x19) */ |
71 | 0x00, /* REG_ARXR1_APGA_CTL (0x1A) */ | 71 | 0x32, /* REG_ARXR1_APGA_CTL (0x1A) */ |
72 | 0x4a, /* REG_ARXL2_APGA_CTL (0x1B) */ | 72 | 0x32, /* REG_ARXL2_APGA_CTL (0x1B) */ |
73 | 0x4a, /* REG_ARXR2_APGA_CTL (0x1C) */ | 73 | 0x32, /* REG_ARXR2_APGA_CTL (0x1C) */ |
74 | 0x00, /* REG_ATX2ARXPGA (0x1D) */ | 74 | 0x00, /* REG_ATX2ARXPGA (0x1D) */ |
75 | 0x00, /* REG_BT_IF (0x1E) */ | 75 | 0x00, /* REG_BT_IF (0x1E) */ |
76 | 0x00, /* REG_BTPGA (0x1F) */ | 76 | 0x55, /* REG_BTPGA (0x1F) */ |
77 | 0x00, /* REG_BTSTPGA (0x20) */ | 77 | 0x00, /* REG_BTSTPGA (0x20) */ |
78 | 0x00, /* REG_EAR_CTL (0x21) */ | 78 | 0x00, /* REG_EAR_CTL (0x21) */ |
79 | 0x00, /* REG_HS_SEL (0x22) */ | 79 | 0x00, /* REG_HS_SEL (0x22) */ |
@@ -85,32 +85,32 @@ static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = { | |||
85 | 0x00, /* REG_PRECKR_CTL (0x28) */ | 85 | 0x00, /* REG_PRECKR_CTL (0x28) */ |
86 | 0x00, /* REG_HFL_CTL (0x29) */ | 86 | 0x00, /* REG_HFL_CTL (0x29) */ |
87 | 0x00, /* REG_HFR_CTL (0x2A) */ | 87 | 0x00, /* REG_HFR_CTL (0x2A) */ |
88 | 0x00, /* REG_ALC_CTL (0x2B) */ | 88 | 0x05, /* REG_ALC_CTL (0x2B) */ |
89 | 0x00, /* REG_ALC_SET1 (0x2C) */ | 89 | 0x00, /* REG_ALC_SET1 (0x2C) */ |
90 | 0x00, /* REG_ALC_SET2 (0x2D) */ | 90 | 0x00, /* REG_ALC_SET2 (0x2D) */ |
91 | 0x00, /* REG_BOOST_CTL (0x2E) */ | 91 | 0x00, /* REG_BOOST_CTL (0x2E) */ |
92 | 0x00, /* REG_SOFTVOL_CTL (0x2F) */ | 92 | 0x00, /* REG_SOFTVOL_CTL (0x2F) */ |
93 | 0x00, /* REG_DTMF_FREQSEL (0x30) */ | 93 | 0x13, /* REG_DTMF_FREQSEL (0x30) */ |
94 | 0x00, /* REG_DTMF_TONEXT1H (0x31) */ | 94 | 0x00, /* REG_DTMF_TONEXT1H (0x31) */ |
95 | 0x00, /* REG_DTMF_TONEXT1L (0x32) */ | 95 | 0x00, /* REG_DTMF_TONEXT1L (0x32) */ |
96 | 0x00, /* REG_DTMF_TONEXT2H (0x33) */ | 96 | 0x00, /* REG_DTMF_TONEXT2H (0x33) */ |
97 | 0x00, /* REG_DTMF_TONEXT2L (0x34) */ | 97 | 0x00, /* REG_DTMF_TONEXT2L (0x34) */ |
98 | 0x00, /* REG_DTMF_TONOFF (0x35) */ | 98 | 0x79, /* REG_DTMF_TONOFF (0x35) */ |
99 | 0x00, /* REG_DTMF_WANONOFF (0x36) */ | 99 | 0x11, /* REG_DTMF_WANONOFF (0x36) */ |
100 | 0x00, /* REG_I2S_RX_SCRAMBLE_H (0x37) */ | 100 | 0x00, /* REG_I2S_RX_SCRAMBLE_H (0x37) */ |
101 | 0x00, /* REG_I2S_RX_SCRAMBLE_M (0x38) */ | 101 | 0x00, /* REG_I2S_RX_SCRAMBLE_M (0x38) */ |
102 | 0x00, /* REG_I2S_RX_SCRAMBLE_L (0x39) */ | 102 | 0x00, /* REG_I2S_RX_SCRAMBLE_L (0x39) */ |
103 | 0x06, /* REG_APLL_CTL (0x3A) */ | 103 | 0x06, /* REG_APLL_CTL (0x3A) */ |
104 | 0x00, /* REG_DTMF_CTL (0x3B) */ | 104 | 0x00, /* REG_DTMF_CTL (0x3B) */ |
105 | 0x00, /* REG_DTMF_PGA_CTL2 (0x3C) */ | 105 | 0x44, /* REG_DTMF_PGA_CTL2 (0x3C) */ |
106 | 0x00, /* REG_DTMF_PGA_CTL1 (0x3D) */ | 106 | 0x69, /* REG_DTMF_PGA_CTL1 (0x3D) */ |
107 | 0x00, /* REG_MISC_SET_1 (0x3E) */ | 107 | 0x00, /* REG_MISC_SET_1 (0x3E) */ |
108 | 0x00, /* REG_PCMBTMUX (0x3F) */ | 108 | 0x00, /* REG_PCMBTMUX (0x3F) */ |
109 | 0x00, /* not used (0x40) */ | 109 | 0x00, /* not used (0x40) */ |
110 | 0x00, /* not used (0x41) */ | 110 | 0x00, /* not used (0x41) */ |
111 | 0x00, /* not used (0x42) */ | 111 | 0x00, /* not used (0x42) */ |
112 | 0x00, /* REG_RX_PATH_SEL (0x43) */ | 112 | 0x00, /* REG_RX_PATH_SEL (0x43) */ |
113 | 0x00, /* REG_VDL_APGA_CTL (0x44) */ | 113 | 0x32, /* REG_VDL_APGA_CTL (0x44) */ |
114 | 0x00, /* REG_VIBRA_CTL (0x45) */ | 114 | 0x00, /* REG_VIBRA_CTL (0x45) */ |
115 | 0x00, /* REG_VIBRA_SET (0x46) */ | 115 | 0x00, /* REG_VIBRA_SET (0x46) */ |
116 | 0x00, /* REG_VIBRA_PWM_SET (0x47) */ | 116 | 0x00, /* REG_VIBRA_PWM_SET (0x47) */ |
@@ -143,6 +143,9 @@ struct twl4030_priv { | |||
143 | u8 earpiece_enabled; | 143 | u8 earpiece_enabled; |
144 | u8 predrivel_enabled, predriver_enabled; | 144 | u8 predrivel_enabled, predriver_enabled; |
145 | u8 carkitl_enabled, carkitr_enabled; | 145 | u8 carkitl_enabled, carkitr_enabled; |
146 | |||
147 | /* Delay needed after enabling the digimic interface */ | ||
148 | unsigned int digimic_delay; | ||
146 | }; | 149 | }; |
147 | 150 | ||
148 | /* | 151 | /* |
@@ -244,58 +247,95 @@ static void twl4030_codec_enable(struct snd_soc_codec *codec, int enable) | |||
244 | udelay(10); | 247 | udelay(10); |
245 | } | 248 | } |
246 | 249 | ||
247 | static void twl4030_init_chip(struct snd_soc_codec *codec) | 250 | static inline void twl4030_check_defaults(struct snd_soc_codec *codec) |
248 | { | 251 | { |
249 | u8 *cache = codec->reg_cache; | 252 | int i, difference = 0; |
250 | int i; | 253 | u8 val; |
254 | |||
255 | dev_dbg(codec->dev, "Checking TWL audio default configuration\n"); | ||
256 | for (i = 1; i <= TWL4030_REG_MISC_SET_2; i++) { | ||
257 | twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &val, i); | ||
258 | if (val != twl4030_reg[i]) { | ||
259 | difference++; | ||
260 | dev_dbg(codec->dev, | ||
261 | "Reg 0x%02x: chip: 0x%02x driver: 0x%02x\n", | ||
262 | i, val, twl4030_reg[i]); | ||
263 | } | ||
264 | } | ||
265 | dev_dbg(codec->dev, "Found %d non maching registers. %s\n", | ||
266 | difference, difference ? "Not OK" : "OK"); | ||
267 | } | ||
251 | 268 | ||
252 | /* clear CODECPDZ prior to setting register defaults */ | 269 | static inline void twl4030_reset_registers(struct snd_soc_codec *codec) |
253 | twl4030_codec_enable(codec, 0); | 270 | { |
271 | int i; | ||
254 | 272 | ||
255 | /* set all audio section registers to reasonable defaults */ | 273 | /* set all audio section registers to reasonable defaults */ |
256 | for (i = TWL4030_REG_OPTION; i <= TWL4030_REG_MISC_SET_2; i++) | 274 | for (i = TWL4030_REG_OPTION; i <= TWL4030_REG_MISC_SET_2; i++) |
257 | if (i != TWL4030_REG_APLL_CTL) | 275 | if (i != TWL4030_REG_APLL_CTL) |
258 | twl4030_write(codec, i, cache[i]); | 276 | twl4030_write(codec, i, twl4030_reg[i]); |
259 | 277 | ||
260 | } | 278 | } |
261 | 279 | ||
262 | static void twl4030_apll_enable(struct snd_soc_codec *codec, int enable) | 280 | static void twl4030_init_chip(struct platform_device *pdev) |
263 | { | 281 | { |
282 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
283 | struct twl4030_setup_data *setup = socdev->codec_data; | ||
284 | struct snd_soc_codec *codec = socdev->card->codec; | ||
264 | struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); | 285 | struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); |
265 | int status = -1; | 286 | u8 reg, byte; |
287 | int i = 0; | ||
266 | 288 | ||
267 | if (enable) { | 289 | /* Check defaults, if instructed before anything else */ |
268 | twl4030->apll_enabled++; | 290 | if (setup && setup->check_defaults) |
269 | if (twl4030->apll_enabled == 1) | 291 | twl4030_check_defaults(codec); |
270 | status = twl4030_codec_enable_resource( | ||
271 | TWL4030_CODEC_RES_APLL); | ||
272 | } else { | ||
273 | twl4030->apll_enabled--; | ||
274 | if (!twl4030->apll_enabled) | ||
275 | status = twl4030_codec_disable_resource( | ||
276 | TWL4030_CODEC_RES_APLL); | ||
277 | } | ||
278 | 292 | ||
279 | if (status >= 0) | 293 | /* Reset registers, if no setup data or if instructed to do so */ |
280 | twl4030_write_reg_cache(codec, TWL4030_REG_APLL_CTL, status); | 294 | if (!setup || (setup && setup->reset_registers)) |
281 | } | 295 | twl4030_reset_registers(codec); |
282 | 296 | ||
283 | static void twl4030_power_up(struct snd_soc_codec *codec) | 297 | /* Refresh APLL_CTL register from HW */ |
284 | { | 298 | twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &byte, |
285 | struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); | 299 | TWL4030_REG_APLL_CTL); |
286 | u8 anamicl, regmisc1, byte; | 300 | twl4030_write_reg_cache(codec, TWL4030_REG_APLL_CTL, byte); |
287 | int i = 0; | 301 | |
302 | /* anti-pop when changing analog gain */ | ||
303 | reg = twl4030_read_reg_cache(codec, TWL4030_REG_MISC_SET_1); | ||
304 | twl4030_write(codec, TWL4030_REG_MISC_SET_1, | ||
305 | reg | TWL4030_SMOOTH_ANAVOL_EN); | ||
288 | 306 | ||
289 | if (twl4030->codec_powered) | 307 | twl4030_write(codec, TWL4030_REG_OPTION, |
308 | TWL4030_ATXL1_EN | TWL4030_ATXR1_EN | | ||
309 | TWL4030_ARXL2_EN | TWL4030_ARXR2_EN); | ||
310 | |||
311 | /* REG_ARXR2_APGA_CTL reset according to the TRM: 0dB, DA_EN */ | ||
312 | twl4030_write(codec, TWL4030_REG_ARXR2_APGA_CTL, 0x32); | ||
313 | |||
314 | /* Machine dependent setup */ | ||
315 | if (!setup) | ||
290 | return; | 316 | return; |
291 | 317 | ||
292 | /* set CODECPDZ to turn on codec */ | 318 | twl4030->digimic_delay = setup->digimic_delay; |
293 | twl4030_codec_enable(codec, 1); | 319 | |
320 | /* Configuration for headset ramp delay from setup data */ | ||
321 | if (setup->sysclk != twl4030->sysclk) | ||
322 | dev_warn(codec->dev, | ||
323 | "Mismatch in APLL mclk: %u (configured: %u)\n", | ||
324 | setup->sysclk, twl4030->sysclk); | ||
325 | |||
326 | reg = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET); | ||
327 | reg &= ~TWL4030_RAMP_DELAY; | ||
328 | reg |= (setup->ramp_delay_value << 2); | ||
329 | twl4030_write_reg_cache(codec, TWL4030_REG_HS_POPN_SET, reg); | ||
294 | 330 | ||
295 | /* initiate offset cancellation */ | 331 | /* initiate offset cancellation */ |
296 | anamicl = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICL); | 332 | twl4030_codec_enable(codec, 1); |
333 | |||
334 | reg = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICL); | ||
335 | reg &= ~TWL4030_OFFSET_CNCL_SEL; | ||
336 | reg |= setup->offset_cncl_path; | ||
297 | twl4030_write(codec, TWL4030_REG_ANAMICL, | 337 | twl4030_write(codec, TWL4030_REG_ANAMICL, |
298 | anamicl | TWL4030_CNCL_OFFSET_START); | 338 | reg | TWL4030_CNCL_OFFSET_START); |
299 | 339 | ||
300 | /* wait for offset cancellation to complete */ | 340 | /* wait for offset cancellation to complete */ |
301 | do { | 341 | do { |
@@ -310,23 +350,28 @@ static void twl4030_power_up(struct snd_soc_codec *codec) | |||
310 | /* Make sure that the reg_cache has the same value as the HW */ | 350 | /* Make sure that the reg_cache has the same value as the HW */ |
311 | twl4030_write_reg_cache(codec, TWL4030_REG_ANAMICL, byte); | 351 | twl4030_write_reg_cache(codec, TWL4030_REG_ANAMICL, byte); |
312 | 352 | ||
313 | /* anti-pop when changing analog gain */ | ||
314 | regmisc1 = twl4030_read_reg_cache(codec, TWL4030_REG_MISC_SET_1); | ||
315 | twl4030_write(codec, TWL4030_REG_MISC_SET_1, | ||
316 | regmisc1 | TWL4030_SMOOTH_ANAVOL_EN); | ||
317 | |||
318 | /* toggle CODECPDZ as per TRM */ | ||
319 | twl4030_codec_enable(codec, 0); | 353 | twl4030_codec_enable(codec, 0); |
320 | twl4030_codec_enable(codec, 1); | ||
321 | } | 354 | } |
322 | 355 | ||
323 | /* | 356 | static void twl4030_apll_enable(struct snd_soc_codec *codec, int enable) |
324 | * Unconditional power down | ||
325 | */ | ||
326 | static void twl4030_power_down(struct snd_soc_codec *codec) | ||
327 | { | 357 | { |
328 | /* power down */ | 358 | struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); |
329 | twl4030_codec_enable(codec, 0); | 359 | int status = -1; |
360 | |||
361 | if (enable) { | ||
362 | twl4030->apll_enabled++; | ||
363 | if (twl4030->apll_enabled == 1) | ||
364 | status = twl4030_codec_enable_resource( | ||
365 | TWL4030_CODEC_RES_APLL); | ||
366 | } else { | ||
367 | twl4030->apll_enabled--; | ||
368 | if (!twl4030->apll_enabled) | ||
369 | status = twl4030_codec_disable_resource( | ||
370 | TWL4030_CODEC_RES_APLL); | ||
371 | } | ||
372 | |||
373 | if (status >= 0) | ||
374 | twl4030_write_reg_cache(codec, TWL4030_REG_APLL_CTL, status); | ||
330 | } | 375 | } |
331 | 376 | ||
332 | /* Earpiece */ | 377 | /* Earpiece */ |
@@ -500,10 +545,11 @@ static const struct snd_kcontrol_new twl4030_dapm_abypassl2_control = | |||
500 | static const struct snd_kcontrol_new twl4030_dapm_abypassv_control = | 545 | static const struct snd_kcontrol_new twl4030_dapm_abypassv_control = |
501 | SOC_DAPM_SINGLE("Switch", TWL4030_REG_VDL_APGA_CTL, 2, 1, 0); | 546 | SOC_DAPM_SINGLE("Switch", TWL4030_REG_VDL_APGA_CTL, 2, 1, 0); |
502 | 547 | ||
503 | /* Digital bypass gain, 0 mutes the bypass */ | 548 | /* Digital bypass gain, mute instead of -30dB */ |
504 | static const unsigned int twl4030_dapm_dbypass_tlv[] = { | 549 | static const unsigned int twl4030_dapm_dbypass_tlv[] = { |
505 | TLV_DB_RANGE_HEAD(2), | 550 | TLV_DB_RANGE_HEAD(3), |
506 | 0, 3, TLV_DB_SCALE_ITEM(-2400, 0, 1), | 551 | 0, 1, TLV_DB_SCALE_ITEM(-3000, 600, 1), |
552 | 2, 3, TLV_DB_SCALE_ITEM(-2400, 0, 0), | ||
507 | 4, 7, TLV_DB_SCALE_ITEM(-1800, 600, 0), | 553 | 4, 7, TLV_DB_SCALE_ITEM(-1800, 600, 0), |
508 | }; | 554 | }; |
509 | 555 | ||
@@ -531,36 +577,6 @@ static const struct snd_kcontrol_new twl4030_dapm_dbypassv_control = | |||
531 | TWL4030_REG_VSTPGA, 0, 0x29, 0, | 577 | TWL4030_REG_VSTPGA, 0, 0x29, 0, |
532 | twl4030_dapm_dbypassv_tlv); | 578 | twl4030_dapm_dbypassv_tlv); |
533 | 579 | ||
534 | static int micpath_event(struct snd_soc_dapm_widget *w, | ||
535 | struct snd_kcontrol *kcontrol, int event) | ||
536 | { | ||
537 | struct soc_enum *e = (struct soc_enum *)w->kcontrols->private_value; | ||
538 | unsigned char adcmicsel, micbias_ctl; | ||
539 | |||
540 | adcmicsel = twl4030_read_reg_cache(w->codec, TWL4030_REG_ADCMICSEL); | ||
541 | micbias_ctl = twl4030_read_reg_cache(w->codec, TWL4030_REG_MICBIAS_CTL); | ||
542 | /* Prepare the bits for the given TX path: | ||
543 | * shift_l == 0: TX1 microphone path | ||
544 | * shift_l == 2: TX2 microphone path */ | ||
545 | if (e->shift_l) { | ||
546 | /* TX2 microphone path */ | ||
547 | if (adcmicsel & TWL4030_TX2IN_SEL) | ||
548 | micbias_ctl |= TWL4030_MICBIAS2_CTL; /* digimic */ | ||
549 | else | ||
550 | micbias_ctl &= ~TWL4030_MICBIAS2_CTL; | ||
551 | } else { | ||
552 | /* TX1 microphone path */ | ||
553 | if (adcmicsel & TWL4030_TX1IN_SEL) | ||
554 | micbias_ctl |= TWL4030_MICBIAS1_CTL; /* digimic */ | ||
555 | else | ||
556 | micbias_ctl &= ~TWL4030_MICBIAS1_CTL; | ||
557 | } | ||
558 | |||
559 | twl4030_write(w->codec, TWL4030_REG_MICBIAS_CTL, micbias_ctl); | ||
560 | |||
561 | return 0; | ||
562 | } | ||
563 | |||
564 | /* | 580 | /* |
565 | * Output PGA builder: | 581 | * Output PGA builder: |
566 | * Handle the muting and unmuting of the given output (turning off the | 582 | * Handle the muting and unmuting of the given output (turning off the |
@@ -814,6 +830,16 @@ static int headsetrpga_event(struct snd_soc_dapm_widget *w, | |||
814 | return 0; | 830 | return 0; |
815 | } | 831 | } |
816 | 832 | ||
833 | static int digimic_event(struct snd_soc_dapm_widget *w, | ||
834 | struct snd_kcontrol *kcontrol, int event) | ||
835 | { | ||
836 | struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(w->codec); | ||
837 | |||
838 | if (twl4030->digimic_delay) | ||
839 | mdelay(twl4030->digimic_delay); | ||
840 | return 0; | ||
841 | } | ||
842 | |||
817 | /* | 843 | /* |
818 | * Some of the gain controls in TWL (mostly those which are associated with | 844 | * Some of the gain controls in TWL (mostly those which are associated with |
819 | * the outputs) are implemented in an interesting way: | 845 | * the outputs) are implemented in an interesting way: |
@@ -1374,14 +1400,10 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { | |||
1374 | /* Analog/Digital mic path selection. | 1400 | /* Analog/Digital mic path selection. |
1375 | TX1 Left/Right: either analog Left/Right or Digimic0 | 1401 | TX1 Left/Right: either analog Left/Right or Digimic0 |
1376 | TX2 Left/Right: either analog Left/Right or Digimic1 */ | 1402 | TX2 Left/Right: either analog Left/Right or Digimic1 */ |
1377 | SND_SOC_DAPM_MUX_E("TX1 Capture Route", SND_SOC_NOPM, 0, 0, | 1403 | SND_SOC_DAPM_MUX("TX1 Capture Route", SND_SOC_NOPM, 0, 0, |
1378 | &twl4030_dapm_micpathtx1_control, micpath_event, | 1404 | &twl4030_dapm_micpathtx1_control), |
1379 | SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD| | 1405 | SND_SOC_DAPM_MUX("TX2 Capture Route", SND_SOC_NOPM, 0, 0, |
1380 | SND_SOC_DAPM_POST_REG), | 1406 | &twl4030_dapm_micpathtx2_control), |
1381 | SND_SOC_DAPM_MUX_E("TX2 Capture Route", SND_SOC_NOPM, 0, 0, | ||
1382 | &twl4030_dapm_micpathtx2_control, micpath_event, | ||
1383 | SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD| | ||
1384 | SND_SOC_DAPM_POST_REG), | ||
1385 | 1407 | ||
1386 | /* Analog input mixers for the capture amplifiers */ | 1408 | /* Analog input mixers for the capture amplifiers */ |
1387 | SND_SOC_DAPM_MIXER("Analog Left", | 1409 | SND_SOC_DAPM_MIXER("Analog Left", |
@@ -1398,10 +1420,17 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { | |||
1398 | SND_SOC_DAPM_PGA("ADC Physical Right", | 1420 | SND_SOC_DAPM_PGA("ADC Physical Right", |
1399 | TWL4030_REG_AVADC_CTL, 1, 0, NULL, 0), | 1421 | TWL4030_REG_AVADC_CTL, 1, 0, NULL, 0), |
1400 | 1422 | ||
1401 | SND_SOC_DAPM_PGA("Digimic0 Enable", | 1423 | SND_SOC_DAPM_PGA_E("Digimic0 Enable", |
1402 | TWL4030_REG_ADCMICSEL, 1, 0, NULL, 0), | 1424 | TWL4030_REG_ADCMICSEL, 1, 0, NULL, 0, |
1403 | SND_SOC_DAPM_PGA("Digimic1 Enable", | 1425 | digimic_event, SND_SOC_DAPM_POST_PMU), |
1404 | TWL4030_REG_ADCMICSEL, 3, 0, NULL, 0), | 1426 | SND_SOC_DAPM_PGA_E("Digimic1 Enable", |
1427 | TWL4030_REG_ADCMICSEL, 3, 0, NULL, 0, | ||
1428 | digimic_event, SND_SOC_DAPM_POST_PMU), | ||
1429 | |||
1430 | SND_SOC_DAPM_SUPPLY("micbias1 select", TWL4030_REG_MICBIAS_CTL, 5, 0, | ||
1431 | NULL, 0), | ||
1432 | SND_SOC_DAPM_SUPPLY("micbias2 select", TWL4030_REG_MICBIAS_CTL, 6, 0, | ||
1433 | NULL, 0), | ||
1405 | 1434 | ||
1406 | SND_SOC_DAPM_MICBIAS("Mic Bias 1", TWL4030_REG_MICBIAS_CTL, 0, 0), | 1435 | SND_SOC_DAPM_MICBIAS("Mic Bias 1", TWL4030_REG_MICBIAS_CTL, 0, 0), |
1407 | SND_SOC_DAPM_MICBIAS("Mic Bias 2", TWL4030_REG_MICBIAS_CTL, 1, 0), | 1436 | SND_SOC_DAPM_MICBIAS("Mic Bias 2", TWL4030_REG_MICBIAS_CTL, 1, 0), |
@@ -1419,8 +1448,11 @@ static const struct snd_soc_dapm_route intercon[] = { | |||
1419 | /* Supply for the digital part (APLL) */ | 1448 | /* Supply for the digital part (APLL) */ |
1420 | {"Digital Voice Playback Mixer", NULL, "APLL Enable"}, | 1449 | {"Digital Voice Playback Mixer", NULL, "APLL Enable"}, |
1421 | 1450 | ||
1422 | {"Digital R1 Playback Mixer", NULL, "AIF Enable"}, | 1451 | {"DAC Left1", NULL, "AIF Enable"}, |
1423 | {"Digital L1 Playback Mixer", NULL, "AIF Enable"}, | 1452 | {"DAC Right1", NULL, "AIF Enable"}, |
1453 | {"DAC Left2", NULL, "AIF Enable"}, | ||
1454 | {"DAC Right1", NULL, "AIF Enable"}, | ||
1455 | |||
1424 | {"Digital R2 Playback Mixer", NULL, "AIF Enable"}, | 1456 | {"Digital R2 Playback Mixer", NULL, "AIF Enable"}, |
1425 | {"Digital L2 Playback Mixer", NULL, "AIF Enable"}, | 1457 | {"Digital L2 Playback Mixer", NULL, "AIF Enable"}, |
1426 | 1458 | ||
@@ -1491,10 +1523,10 @@ static const struct snd_soc_dapm_route intercon[] = { | |||
1491 | 1523 | ||
1492 | /* outputs */ | 1524 | /* outputs */ |
1493 | /* Must be always connected (for AIF and APLL) */ | 1525 | /* Must be always connected (for AIF and APLL) */ |
1494 | {"Virtual HiFi OUT", NULL, "Digital L1 Playback Mixer"}, | 1526 | {"Virtual HiFi OUT", NULL, "DAC Left1"}, |
1495 | {"Virtual HiFi OUT", NULL, "Digital R1 Playback Mixer"}, | 1527 | {"Virtual HiFi OUT", NULL, "DAC Right1"}, |
1496 | {"Virtual HiFi OUT", NULL, "Digital L2 Playback Mixer"}, | 1528 | {"Virtual HiFi OUT", NULL, "DAC Left2"}, |
1497 | {"Virtual HiFi OUT", NULL, "Digital R2 Playback Mixer"}, | 1529 | {"Virtual HiFi OUT", NULL, "DAC Right2"}, |
1498 | /* Must be always connected (for APLL) */ | 1530 | /* Must be always connected (for APLL) */ |
1499 | {"Virtual Voice OUT", NULL, "Digital Voice Playback Mixer"}, | 1531 | {"Virtual Voice OUT", NULL, "Digital Voice Playback Mixer"}, |
1500 | /* Physical outputs */ | 1532 | /* Physical outputs */ |
@@ -1531,6 +1563,9 @@ static const struct snd_soc_dapm_route intercon[] = { | |||
1531 | {"Digimic0 Enable", NULL, "DIGIMIC0"}, | 1563 | {"Digimic0 Enable", NULL, "DIGIMIC0"}, |
1532 | {"Digimic1 Enable", NULL, "DIGIMIC1"}, | 1564 | {"Digimic1 Enable", NULL, "DIGIMIC1"}, |
1533 | 1565 | ||
1566 | {"DIGIMIC0", NULL, "micbias1 select"}, | ||
1567 | {"DIGIMIC1", NULL, "micbias2 select"}, | ||
1568 | |||
1534 | /* TX1 Left capture path */ | 1569 | /* TX1 Left capture path */ |
1535 | {"TX1 Capture Route", "Analog", "ADC Physical Left"}, | 1570 | {"TX1 Capture Route", "Analog", "ADC Physical Left"}, |
1536 | {"TX1 Capture Route", "Digimic0", "Digimic0 Enable"}, | 1571 | {"TX1 Capture Route", "Digimic0", "Digimic0 Enable"}, |
@@ -1605,10 +1640,10 @@ static int twl4030_set_bias_level(struct snd_soc_codec *codec, | |||
1605 | break; | 1640 | break; |
1606 | case SND_SOC_BIAS_STANDBY: | 1641 | case SND_SOC_BIAS_STANDBY: |
1607 | if (codec->bias_level == SND_SOC_BIAS_OFF) | 1642 | if (codec->bias_level == SND_SOC_BIAS_OFF) |
1608 | twl4030_power_up(codec); | 1643 | twl4030_codec_enable(codec, 1); |
1609 | break; | 1644 | break; |
1610 | case SND_SOC_BIAS_OFF: | 1645 | case SND_SOC_BIAS_OFF: |
1611 | twl4030_power_down(codec); | 1646 | twl4030_codec_enable(codec, 0); |
1612 | break; | 1647 | break; |
1613 | } | 1648 | } |
1614 | codec->bias_level = level; | 1649 | codec->bias_level = level; |
@@ -1794,13 +1829,6 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream, | |||
1794 | return -EINVAL; | 1829 | return -EINVAL; |
1795 | } | 1830 | } |
1796 | 1831 | ||
1797 | if (mode != old_mode) { | ||
1798 | /* change rate and set CODECPDZ */ | ||
1799 | twl4030_codec_enable(codec, 0); | ||
1800 | twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode); | ||
1801 | twl4030_codec_enable(codec, 1); | ||
1802 | } | ||
1803 | |||
1804 | /* sample size */ | 1832 | /* sample size */ |
1805 | old_format = twl4030_read_reg_cache(codec, TWL4030_REG_AUDIO_IF); | 1833 | old_format = twl4030_read_reg_cache(codec, TWL4030_REG_AUDIO_IF); |
1806 | format = old_format; | 1834 | format = old_format; |
@@ -1818,16 +1846,20 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream, | |||
1818 | return -EINVAL; | 1846 | return -EINVAL; |
1819 | } | 1847 | } |
1820 | 1848 | ||
1821 | if (format != old_format) { | 1849 | if (format != old_format || mode != old_mode) { |
1822 | 1850 | if (twl4030->codec_powered) { | |
1823 | /* clear CODECPDZ before changing format (codec requirement) */ | 1851 | /* |
1824 | twl4030_codec_enable(codec, 0); | 1852 | * If the codec is powered, than we need to toggle the |
1825 | 1853 | * codec power. | |
1826 | /* change format */ | 1854 | */ |
1827 | twl4030_write(codec, TWL4030_REG_AUDIO_IF, format); | 1855 | twl4030_codec_enable(codec, 0); |
1828 | 1856 | twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode); | |
1829 | /* set CODECPDZ afterwards */ | 1857 | twl4030_write(codec, TWL4030_REG_AUDIO_IF, format); |
1830 | twl4030_codec_enable(codec, 1); | 1858 | twl4030_codec_enable(codec, 1); |
1859 | } else { | ||
1860 | twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode); | ||
1861 | twl4030_write(codec, TWL4030_REG_AUDIO_IF, format); | ||
1862 | } | ||
1831 | } | 1863 | } |
1832 | 1864 | ||
1833 | /* Store the important parameters for the DAI configuration and set | 1865 | /* Store the important parameters for the DAI configuration and set |
@@ -1877,6 +1909,7 @@ static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
1877 | unsigned int fmt) | 1909 | unsigned int fmt) |
1878 | { | 1910 | { |
1879 | struct snd_soc_codec *codec = codec_dai->codec; | 1911 | struct snd_soc_codec *codec = codec_dai->codec; |
1912 | struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); | ||
1880 | u8 old_format, format; | 1913 | u8 old_format, format; |
1881 | 1914 | ||
1882 | /* get format */ | 1915 | /* get format */ |
@@ -1911,15 +1944,17 @@ static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
1911 | } | 1944 | } |
1912 | 1945 | ||
1913 | if (format != old_format) { | 1946 | if (format != old_format) { |
1914 | 1947 | if (twl4030->codec_powered) { | |
1915 | /* clear CODECPDZ before changing format (codec requirement) */ | 1948 | /* |
1916 | twl4030_codec_enable(codec, 0); | 1949 | * If the codec is powered, than we need to toggle the |
1917 | 1950 | * codec power. | |
1918 | /* change format */ | 1951 | */ |
1919 | twl4030_write(codec, TWL4030_REG_AUDIO_IF, format); | 1952 | twl4030_codec_enable(codec, 0); |
1920 | 1953 | twl4030_write(codec, TWL4030_REG_AUDIO_IF, format); | |
1921 | /* set CODECPDZ afterwards */ | 1954 | twl4030_codec_enable(codec, 1); |
1922 | twl4030_codec_enable(codec, 1); | 1955 | } else { |
1956 | twl4030_write(codec, TWL4030_REG_AUDIO_IF, format); | ||
1957 | } | ||
1923 | } | 1958 | } |
1924 | 1959 | ||
1925 | return 0; | 1960 | return 0; |
@@ -2011,6 +2046,7 @@ static int twl4030_voice_hw_params(struct snd_pcm_substream *substream, | |||
2011 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 2046 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
2012 | struct snd_soc_device *socdev = rtd->socdev; | 2047 | struct snd_soc_device *socdev = rtd->socdev; |
2013 | struct snd_soc_codec *codec = socdev->card->codec; | 2048 | struct snd_soc_codec *codec = socdev->card->codec; |
2049 | struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); | ||
2014 | u8 old_mode, mode; | 2050 | u8 old_mode, mode; |
2015 | 2051 | ||
2016 | /* Enable voice digital filters */ | 2052 | /* Enable voice digital filters */ |
@@ -2035,10 +2071,17 @@ static int twl4030_voice_hw_params(struct snd_pcm_substream *substream, | |||
2035 | } | 2071 | } |
2036 | 2072 | ||
2037 | if (mode != old_mode) { | 2073 | if (mode != old_mode) { |
2038 | /* change rate and set CODECPDZ */ | 2074 | if (twl4030->codec_powered) { |
2039 | twl4030_codec_enable(codec, 0); | 2075 | /* |
2040 | twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode); | 2076 | * If the codec is powered, than we need to toggle the |
2041 | twl4030_codec_enable(codec, 1); | 2077 | * codec power. |
2078 | */ | ||
2079 | twl4030_codec_enable(codec, 0); | ||
2080 | twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode); | ||
2081 | twl4030_codec_enable(codec, 1); | ||
2082 | } else { | ||
2083 | twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode); | ||
2084 | } | ||
2042 | } | 2085 | } |
2043 | 2086 | ||
2044 | return 0; | 2087 | return 0; |
@@ -2068,6 +2111,7 @@ static int twl4030_voice_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
2068 | unsigned int fmt) | 2111 | unsigned int fmt) |
2069 | { | 2112 | { |
2070 | struct snd_soc_codec *codec = codec_dai->codec; | 2113 | struct snd_soc_codec *codec = codec_dai->codec; |
2114 | struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); | ||
2071 | u8 old_format, format; | 2115 | u8 old_format, format; |
2072 | 2116 | ||
2073 | /* get format */ | 2117 | /* get format */ |
@@ -2099,10 +2143,17 @@ static int twl4030_voice_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
2099 | } | 2143 | } |
2100 | 2144 | ||
2101 | if (format != old_format) { | 2145 | if (format != old_format) { |
2102 | /* change format and set CODECPDZ */ | 2146 | if (twl4030->codec_powered) { |
2103 | twl4030_codec_enable(codec, 0); | 2147 | /* |
2104 | twl4030_write(codec, TWL4030_REG_VOICE_IF, format); | 2148 | * If the codec is powered, than we need to toggle the |
2105 | twl4030_codec_enable(codec, 1); | 2149 | * codec power. |
2150 | */ | ||
2151 | twl4030_codec_enable(codec, 0); | ||
2152 | twl4030_write(codec, TWL4030_REG_VOICE_IF, format); | ||
2153 | twl4030_codec_enable(codec, 1); | ||
2154 | } else { | ||
2155 | twl4030_write(codec, TWL4030_REG_VOICE_IF, format); | ||
2156 | } | ||
2106 | } | 2157 | } |
2107 | 2158 | ||
2108 | return 0; | 2159 | return 0; |
@@ -2202,31 +2253,15 @@ static struct snd_soc_codec *twl4030_codec; | |||
2202 | static int twl4030_soc_probe(struct platform_device *pdev) | 2253 | static int twl4030_soc_probe(struct platform_device *pdev) |
2203 | { | 2254 | { |
2204 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 2255 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
2205 | struct twl4030_setup_data *setup = socdev->codec_data; | ||
2206 | struct snd_soc_codec *codec; | 2256 | struct snd_soc_codec *codec; |
2207 | struct twl4030_priv *twl4030; | ||
2208 | int ret; | 2257 | int ret; |
2209 | 2258 | ||
2210 | BUG_ON(!twl4030_codec); | 2259 | BUG_ON(!twl4030_codec); |
2211 | 2260 | ||
2212 | codec = twl4030_codec; | 2261 | codec = twl4030_codec; |
2213 | twl4030 = snd_soc_codec_get_drvdata(codec); | ||
2214 | socdev->card->codec = codec; | 2262 | socdev->card->codec = codec; |
2215 | 2263 | ||
2216 | /* Configuration for headset ramp delay from setup data */ | 2264 | twl4030_init_chip(pdev); |
2217 | if (setup) { | ||
2218 | unsigned char hs_pop; | ||
2219 | |||
2220 | if (setup->sysclk != twl4030->sysclk) | ||
2221 | dev_warn(&pdev->dev, | ||
2222 | "Mismatch in APLL mclk: %u (configured: %u)\n", | ||
2223 | setup->sysclk, twl4030->sysclk); | ||
2224 | |||
2225 | hs_pop = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET); | ||
2226 | hs_pop &= ~TWL4030_RAMP_DELAY; | ||
2227 | hs_pop |= (setup->ramp_delay_value << 2); | ||
2228 | twl4030_write_reg_cache(codec, TWL4030_REG_HS_POPN_SET, hs_pop); | ||
2229 | } | ||
2230 | 2265 | ||
2231 | /* register pcms */ | 2266 | /* register pcms */ |
2232 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | 2267 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); |
@@ -2247,6 +2282,8 @@ static int twl4030_soc_remove(struct platform_device *pdev) | |||
2247 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 2282 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
2248 | struct snd_soc_codec *codec = socdev->card->codec; | 2283 | struct snd_soc_codec *codec = socdev->card->codec; |
2249 | 2284 | ||
2285 | /* Reset registers to their chip default before leaving */ | ||
2286 | twl4030_reset_registers(codec); | ||
2250 | twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF); | 2287 | twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF); |
2251 | snd_soc_free_pcms(socdev); | 2288 | snd_soc_free_pcms(socdev); |
2252 | snd_soc_dapm_free(socdev); | 2289 | snd_soc_dapm_free(socdev); |
@@ -2287,6 +2324,7 @@ static int __devinit twl4030_codec_probe(struct platform_device *pdev) | |||
2287 | codec->read = twl4030_read_reg_cache; | 2324 | codec->read = twl4030_read_reg_cache; |
2288 | codec->write = twl4030_write; | 2325 | codec->write = twl4030_write; |
2289 | codec->set_bias_level = twl4030_set_bias_level; | 2326 | codec->set_bias_level = twl4030_set_bias_level; |
2327 | codec->idle_bias_off = 1; | ||
2290 | codec->dai = twl4030_dai; | 2328 | codec->dai = twl4030_dai; |
2291 | codec->num_dai = ARRAY_SIZE(twl4030_dai); | 2329 | codec->num_dai = ARRAY_SIZE(twl4030_dai); |
2292 | codec->reg_cache_size = sizeof(twl4030_reg); | 2330 | codec->reg_cache_size = sizeof(twl4030_reg); |
@@ -2302,9 +2340,7 @@ static int __devinit twl4030_codec_probe(struct platform_device *pdev) | |||
2302 | 2340 | ||
2303 | /* Set the defaults, and power up the codec */ | 2341 | /* Set the defaults, and power up the codec */ |
2304 | twl4030->sysclk = twl4030_codec_get_mclk() / 1000; | 2342 | twl4030->sysclk = twl4030_codec_get_mclk() / 1000; |
2305 | twl4030_init_chip(codec); | ||
2306 | codec->bias_level = SND_SOC_BIAS_OFF; | 2343 | codec->bias_level = SND_SOC_BIAS_OFF; |
2307 | twl4030_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
2308 | 2344 | ||
2309 | ret = snd_soc_register_codec(codec); | 2345 | ret = snd_soc_register_codec(codec); |
2310 | if (ret != 0) { | 2346 | if (ret != 0) { |
@@ -2322,7 +2358,7 @@ static int __devinit twl4030_codec_probe(struct platform_device *pdev) | |||
2322 | return 0; | 2358 | return 0; |
2323 | 2359 | ||
2324 | error_codec: | 2360 | error_codec: |
2325 | twl4030_power_down(codec); | 2361 | twl4030_codec_enable(codec, 0); |
2326 | kfree(codec->reg_cache); | 2362 | kfree(codec->reg_cache); |
2327 | error_cache: | 2363 | error_cache: |
2328 | kfree(twl4030); | 2364 | kfree(twl4030); |
diff --git a/sound/soc/codecs/twl4030.h b/sound/soc/codecs/twl4030.h index f206d242ca31..6c57430f6e24 100644 --- a/sound/soc/codecs/twl4030.h +++ b/sound/soc/codecs/twl4030.h | |||
@@ -41,7 +41,11 @@ extern struct snd_soc_codec_device soc_codec_dev_twl4030; | |||
41 | 41 | ||
42 | struct twl4030_setup_data { | 42 | struct twl4030_setup_data { |
43 | unsigned int ramp_delay_value; | 43 | unsigned int ramp_delay_value; |
44 | unsigned int digimic_delay; /* in ms */ | ||
44 | unsigned int sysclk; | 45 | unsigned int sysclk; |
46 | unsigned int offset_cncl_path; | ||
47 | unsigned int check_defaults:1; | ||
48 | unsigned int reset_registers:1; | ||
45 | unsigned int hs_extmute:1; | 49 | unsigned int hs_extmute:1; |
46 | void (*set_hs_extmute)(int mute); | 50 | void (*set_hs_extmute)(int mute); |
47 | }; | 51 | }; |
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c index af36346ff336..64a807f1a8a1 100644 --- a/sound/soc/codecs/twl6040.c +++ b/sound/soc/codecs/twl6040.c | |||
@@ -360,6 +360,13 @@ static int headset_power_mode(struct snd_soc_codec *codec, int high_perf) | |||
360 | return 0; | 360 | return 0; |
361 | } | 361 | } |
362 | 362 | ||
363 | static int twl6040_hs_dac_event(struct snd_soc_dapm_widget *w, | ||
364 | struct snd_kcontrol *kcontrol, int event) | ||
365 | { | ||
366 | msleep(1); | ||
367 | return 0; | ||
368 | } | ||
369 | |||
363 | static int twl6040_power_mode_event(struct snd_soc_dapm_widget *w, | 370 | static int twl6040_power_mode_event(struct snd_soc_dapm_widget *w, |
364 | struct snd_kcontrol *kcontrol, int event) | 371 | struct snd_kcontrol *kcontrol, int event) |
365 | { | 372 | { |
@@ -371,6 +378,8 @@ static int twl6040_power_mode_event(struct snd_soc_dapm_widget *w, | |||
371 | else | 378 | else |
372 | priv->non_lp--; | 379 | priv->non_lp--; |
373 | 380 | ||
381 | msleep(1); | ||
382 | |||
374 | return 0; | 383 | return 0; |
375 | } | 384 | } |
376 | 385 | ||
@@ -471,20 +480,6 @@ static const struct snd_kcontrol_new hfdacl_switch_controls = | |||
471 | static const struct snd_kcontrol_new hfdacr_switch_controls = | 480 | static const struct snd_kcontrol_new hfdacr_switch_controls = |
472 | SOC_DAPM_SINGLE("Switch", TWL6040_REG_HFRCTL, 2, 1, 0); | 481 | SOC_DAPM_SINGLE("Switch", TWL6040_REG_HFRCTL, 2, 1, 0); |
473 | 482 | ||
474 | /* Headset driver switches */ | ||
475 | static const struct snd_kcontrol_new hsl_driver_switch_controls = | ||
476 | SOC_DAPM_SINGLE("Switch", TWL6040_REG_HSLCTL, 2, 1, 0); | ||
477 | |||
478 | static const struct snd_kcontrol_new hsr_driver_switch_controls = | ||
479 | SOC_DAPM_SINGLE("Switch", TWL6040_REG_HSRCTL, 2, 1, 0); | ||
480 | |||
481 | /* Handsfree driver switches */ | ||
482 | static const struct snd_kcontrol_new hfl_driver_switch_controls = | ||
483 | SOC_DAPM_SINGLE("Switch", TWL6040_REG_HFLCTL, 4, 1, 0); | ||
484 | |||
485 | static const struct snd_kcontrol_new hfr_driver_switch_controls = | ||
486 | SOC_DAPM_SINGLE("Switch", TWL6040_REG_HFRCTL, 4, 1, 0); | ||
487 | |||
488 | static const struct snd_kcontrol_new ep_driver_switch_controls = | 483 | static const struct snd_kcontrol_new ep_driver_switch_controls = |
489 | SOC_DAPM_SINGLE("Switch", TWL6040_REG_EARCTL, 0, 1, 0); | 484 | SOC_DAPM_SINGLE("Switch", TWL6040_REG_EARCTL, 0, 1, 0); |
490 | 485 | ||
@@ -548,10 +543,14 @@ static const struct snd_soc_dapm_widget twl6040_dapm_widgets[] = { | |||
548 | TWL6040_REG_DMICBCTL, 4, 0), | 543 | TWL6040_REG_DMICBCTL, 4, 0), |
549 | 544 | ||
550 | /* DACs */ | 545 | /* DACs */ |
551 | SND_SOC_DAPM_DAC("HSDAC Left", "Headset Playback", | 546 | SND_SOC_DAPM_DAC_E("HSDAC Left", "Headset Playback", |
552 | TWL6040_REG_HSLCTL, 0, 0), | 547 | TWL6040_REG_HSLCTL, 0, 0, |
553 | SND_SOC_DAPM_DAC("HSDAC Right", "Headset Playback", | 548 | twl6040_hs_dac_event, |
554 | TWL6040_REG_HSRCTL, 0, 0), | 549 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), |
550 | SND_SOC_DAPM_DAC_E("HSDAC Right", "Headset Playback", | ||
551 | TWL6040_REG_HSRCTL, 0, 0, | ||
552 | twl6040_hs_dac_event, | ||
553 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), | ||
555 | SND_SOC_DAPM_DAC_E("HFDAC Left", "Handsfree Playback", | 554 | SND_SOC_DAPM_DAC_E("HFDAC Left", "Handsfree Playback", |
556 | TWL6040_REG_HFLCTL, 0, 0, | 555 | TWL6040_REG_HFLCTL, 0, 0, |
557 | twl6040_power_mode_event, | 556 | twl6040_power_mode_event, |
@@ -571,18 +570,19 @@ static const struct snd_soc_dapm_widget twl6040_dapm_widgets[] = { | |||
571 | SND_SOC_DAPM_SWITCH("HFDAC Right Playback", | 570 | SND_SOC_DAPM_SWITCH("HFDAC Right Playback", |
572 | SND_SOC_NOPM, 0, 0, &hfdacr_switch_controls), | 571 | SND_SOC_NOPM, 0, 0, &hfdacr_switch_controls), |
573 | 572 | ||
574 | SND_SOC_DAPM_SWITCH("Headset Left Driver", | 573 | /* Analog playback drivers */ |
575 | SND_SOC_NOPM, 0, 0, &hsl_driver_switch_controls), | 574 | SND_SOC_DAPM_PGA_E("Handsfree Left Driver", |
576 | SND_SOC_DAPM_SWITCH("Headset Right Driver", | 575 | TWL6040_REG_HFLCTL, 4, 0, NULL, 0, |
577 | SND_SOC_NOPM, 0, 0, &hsr_driver_switch_controls), | ||
578 | SND_SOC_DAPM_SWITCH_E("Handsfree Left Driver", | ||
579 | SND_SOC_NOPM, 0, 0, &hfl_driver_switch_controls, | ||
580 | twl6040_power_mode_event, | 576 | twl6040_power_mode_event, |
581 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), | 577 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), |
582 | SND_SOC_DAPM_SWITCH_E("Handsfree Right Driver", | 578 | SND_SOC_DAPM_PGA_E("Handsfree Right Driver", |
583 | SND_SOC_NOPM, 0, 0, &hfr_driver_switch_controls, | 579 | TWL6040_REG_HFRCTL, 4, 0, NULL, 0, |
584 | twl6040_power_mode_event, | 580 | twl6040_power_mode_event, |
585 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), | 581 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), |
582 | SND_SOC_DAPM_PGA("Headset Left Driver", | ||
583 | TWL6040_REG_HSLCTL, 2, 0, NULL, 0), | ||
584 | SND_SOC_DAPM_PGA("Headset Right Driver", | ||
585 | TWL6040_REG_HSRCTL, 2, 0, NULL, 0), | ||
586 | SND_SOC_DAPM_SWITCH_E("Earphone Driver", | 586 | SND_SOC_DAPM_SWITCH_E("Earphone Driver", |
587 | SND_SOC_NOPM, 0, 0, &ep_driver_switch_controls, | 587 | SND_SOC_NOPM, 0, 0, &ep_driver_switch_controls, |
588 | twl6040_power_mode_event, | 588 | twl6040_power_mode_event, |
@@ -616,8 +616,8 @@ static const struct snd_soc_dapm_route intercon[] = { | |||
616 | {"HSDAC Left Playback", "Switch", "HSDAC Left"}, | 616 | {"HSDAC Left Playback", "Switch", "HSDAC Left"}, |
617 | {"HSDAC Right Playback", "Switch", "HSDAC Right"}, | 617 | {"HSDAC Right Playback", "Switch", "HSDAC Right"}, |
618 | 618 | ||
619 | {"Headset Left Driver", "Switch", "HSDAC Left Playback"}, | 619 | {"Headset Left Driver", NULL, "HSDAC Left Playback"}, |
620 | {"Headset Right Driver", "Switch", "HSDAC Right Playback"}, | 620 | {"Headset Right Driver", NULL, "HSDAC Right Playback"}, |
621 | 621 | ||
622 | {"HSOL", NULL, "Headset Left Driver"}, | 622 | {"HSOL", NULL, "Headset Left Driver"}, |
623 | {"HSOR", NULL, "Headset Right Driver"}, | 623 | {"HSOR", NULL, "Headset Right Driver"}, |
@@ -928,7 +928,7 @@ static int twl6040_set_dai_sysclk(struct snd_soc_dai *codec_dai, | |||
928 | case 19200000: | 928 | case 19200000: |
929 | /* mclk input, pll disabled */ | 929 | /* mclk input, pll disabled */ |
930 | hppllctl |= TWL6040_MCLK_19200KHZ | | 930 | hppllctl |= TWL6040_MCLK_19200KHZ | |
931 | TWL6040_HPLLSQRBP | | 931 | TWL6040_HPLLSQRENA | |
932 | TWL6040_HPLLBP; | 932 | TWL6040_HPLLBP; |
933 | break; | 933 | break; |
934 | case 26000000: | 934 | case 26000000: |
diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c index 28aac53c97bb..f3b4c1d6a82d 100644 --- a/sound/soc/codecs/uda134x.c +++ b/sound/soc/codecs/uda134x.c | |||
@@ -28,19 +28,6 @@ | |||
28 | #include "uda134x.h" | 28 | #include "uda134x.h" |
29 | 29 | ||
30 | 30 | ||
31 | #define POWER_OFF_ON_STANDBY 1 | ||
32 | /* | ||
33 | ALSA SOC usually puts the device in standby mode when it's not used | ||
34 | for sometime. If you define POWER_OFF_ON_STANDBY the driver will | ||
35 | turn off the ADC/DAC when this callback is invoked and turn it back | ||
36 | on when needed. Unfortunately this will result in a very light bump | ||
37 | (it can be audible only with good earphones). If this bothers you | ||
38 | just comment this line, you will have slightly higher power | ||
39 | consumption . Please note that sending the L3 command for ADC is | ||
40 | enough to make the bump, so it doesn't make difference if you | ||
41 | completely take off power from the codec. | ||
42 | */ | ||
43 | |||
44 | #define UDA134X_RATES SNDRV_PCM_RATE_8000_48000 | 31 | #define UDA134X_RATES SNDRV_PCM_RATE_8000_48000 |
45 | #define UDA134X_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \ | 32 | #define UDA134X_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \ |
46 | SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S20_3LE) | 33 | SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S20_3LE) |
@@ -58,7 +45,7 @@ static const char uda134x_reg[UDA134X_REGS_NUM] = { | |||
58 | /* Extended address registers */ | 45 | /* Extended address registers */ |
59 | 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, | 46 | 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, |
60 | /* Status, data regs */ | 47 | /* Status, data regs */ |
61 | 0x00, 0x83, 0x00, 0x40, 0x80, 0x00, | 48 | 0x00, 0x83, 0x00, 0x40, 0x80, 0xC0, 0x00, |
62 | }; | 49 | }; |
63 | 50 | ||
64 | /* | 51 | /* |
@@ -117,6 +104,7 @@ static int uda134x_write(struct snd_soc_codec *codec, unsigned int reg, | |||
117 | case UDA134X_DATA000: | 104 | case UDA134X_DATA000: |
118 | case UDA134X_DATA001: | 105 | case UDA134X_DATA001: |
119 | case UDA134X_DATA010: | 106 | case UDA134X_DATA010: |
107 | case UDA134X_DATA011: | ||
120 | addr = UDA134X_DATA0_ADDR; | 108 | addr = UDA134X_DATA0_ADDR; |
121 | break; | 109 | break; |
122 | case UDA134X_DATA1: | 110 | case UDA134X_DATA1: |
@@ -353,8 +341,22 @@ static int uda134x_set_bias_level(struct snd_soc_codec *codec, | |||
353 | switch (level) { | 341 | switch (level) { |
354 | case SND_SOC_BIAS_ON: | 342 | case SND_SOC_BIAS_ON: |
355 | /* ADC, DAC on */ | 343 | /* ADC, DAC on */ |
356 | reg = uda134x_read_reg_cache(codec, UDA134X_STATUS1); | 344 | switch (pd->model) { |
357 | uda134x_write(codec, UDA134X_STATUS1, reg | 0x03); | 345 | case UDA134X_UDA1340: |
346 | case UDA134X_UDA1344: | ||
347 | case UDA134X_UDA1345: | ||
348 | reg = uda134x_read_reg_cache(codec, UDA134X_DATA011); | ||
349 | uda134x_write(codec, UDA134X_DATA011, reg | 0x03); | ||
350 | break; | ||
351 | case UDA134X_UDA1341: | ||
352 | reg = uda134x_read_reg_cache(codec, UDA134X_STATUS1); | ||
353 | uda134x_write(codec, UDA134X_STATUS1, reg | 0x03); | ||
354 | break; | ||
355 | default: | ||
356 | printk(KERN_ERR "UDA134X SoC codec: " | ||
357 | "unsupported model %d\n", pd->model); | ||
358 | return -EINVAL; | ||
359 | } | ||
358 | break; | 360 | break; |
359 | case SND_SOC_BIAS_PREPARE: | 361 | case SND_SOC_BIAS_PREPARE: |
360 | /* power on */ | 362 | /* power on */ |
@@ -367,8 +369,22 @@ static int uda134x_set_bias_level(struct snd_soc_codec *codec, | |||
367 | break; | 369 | break; |
368 | case SND_SOC_BIAS_STANDBY: | 370 | case SND_SOC_BIAS_STANDBY: |
369 | /* ADC, DAC power off */ | 371 | /* ADC, DAC power off */ |
370 | reg = uda134x_read_reg_cache(codec, UDA134X_STATUS1); | 372 | switch (pd->model) { |
371 | uda134x_write(codec, UDA134X_STATUS1, reg & ~(0x03)); | 373 | case UDA134X_UDA1340: |
374 | case UDA134X_UDA1344: | ||
375 | case UDA134X_UDA1345: | ||
376 | reg = uda134x_read_reg_cache(codec, UDA134X_DATA011); | ||
377 | uda134x_write(codec, UDA134X_DATA011, reg & ~(0x03)); | ||
378 | break; | ||
379 | case UDA134X_UDA1341: | ||
380 | reg = uda134x_read_reg_cache(codec, UDA134X_STATUS1); | ||
381 | uda134x_write(codec, UDA134X_STATUS1, reg & ~(0x03)); | ||
382 | break; | ||
383 | default: | ||
384 | printk(KERN_ERR "UDA134X SoC codec: " | ||
385 | "unsupported model %d\n", pd->model); | ||
386 | return -EINVAL; | ||
387 | } | ||
372 | break; | 388 | break; |
373 | case SND_SOC_BIAS_OFF: | 389 | case SND_SOC_BIAS_OFF: |
374 | /* power off */ | 390 | /* power off */ |
@@ -531,9 +547,7 @@ static int uda134x_soc_probe(struct platform_device *pdev) | |||
531 | codec->num_dai = 1; | 547 | codec->num_dai = 1; |
532 | codec->read = uda134x_read_reg_cache; | 548 | codec->read = uda134x_read_reg_cache; |
533 | codec->write = uda134x_write; | 549 | codec->write = uda134x_write; |
534 | #ifdef POWER_OFF_ON_STANDBY | 550 | |
535 | codec->set_bias_level = uda134x_set_bias_level; | ||
536 | #endif | ||
537 | INIT_LIST_HEAD(&codec->dapm_widgets); | 551 | INIT_LIST_HEAD(&codec->dapm_widgets); |
538 | INIT_LIST_HEAD(&codec->dapm_paths); | 552 | INIT_LIST_HEAD(&codec->dapm_paths); |
539 | 553 | ||
@@ -544,6 +558,14 @@ static int uda134x_soc_probe(struct platform_device *pdev) | |||
544 | 558 | ||
545 | uda134x_reset(codec); | 559 | uda134x_reset(codec); |
546 | 560 | ||
561 | if (pd->is_powered_on_standby) { | ||
562 | codec->set_bias_level = NULL; | ||
563 | uda134x_set_bias_level(codec, SND_SOC_BIAS_ON); | ||
564 | } else { | ||
565 | codec->set_bias_level = uda134x_set_bias_level; | ||
566 | uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
567 | } | ||
568 | |||
547 | /* register pcms */ | 569 | /* register pcms */ |
548 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | 570 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); |
549 | if (ret < 0) { | 571 | if (ret < 0) { |
diff --git a/sound/soc/codecs/uda134x.h b/sound/soc/codecs/uda134x.h index 94f440490b31..205f03b3eaf8 100644 --- a/sound/soc/codecs/uda134x.h +++ b/sound/soc/codecs/uda134x.h | |||
@@ -23,9 +23,10 @@ | |||
23 | #define UDA134X_DATA000 10 | 23 | #define UDA134X_DATA000 10 |
24 | #define UDA134X_DATA001 11 | 24 | #define UDA134X_DATA001 11 |
25 | #define UDA134X_DATA010 12 | 25 | #define UDA134X_DATA010 12 |
26 | #define UDA134X_DATA1 13 | 26 | #define UDA134X_DATA011 13 |
27 | #define UDA134X_DATA1 14 | ||
27 | 28 | ||
28 | #define UDA134X_REGS_NUM 14 | 29 | #define UDA134X_REGS_NUM 15 |
29 | 30 | ||
30 | #define STATUS0_DAIFMT_MASK (~(7<<1)) | 31 | #define STATUS0_DAIFMT_MASK (~(7<<1)) |
31 | #define STATUS0_SYSCLK_MASK (~(3<<4)) | 32 | #define STATUS0_SYSCLK_MASK (~(3<<4)) |
diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c index 002e289d1255..4bcd168794e1 100644 --- a/sound/soc/codecs/wm2000.c +++ b/sound/soc/codecs/wm2000.c | |||
@@ -795,6 +795,8 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c, | |||
795 | 795 | ||
796 | dev_set_drvdata(&i2c->dev, wm2000); | 796 | dev_set_drvdata(&i2c->dev, wm2000); |
797 | wm2000->anc_eng_ena = 1; | 797 | wm2000->anc_eng_ena = 1; |
798 | wm2000->anc_active = 1; | ||
799 | wm2000->spk_ena = 1; | ||
798 | wm2000->i2c = i2c; | 800 | wm2000->i2c = i2c; |
799 | 801 | ||
800 | wm2000_reset(wm2000); | 802 | wm2000_reset(wm2000); |
diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c index 37242a7d3077..0ad039b4adf5 100644 --- a/sound/soc/codecs/wm8523.c +++ b/sound/soc/codecs/wm8523.c | |||
@@ -482,7 +482,8 @@ static int wm8523_register(struct wm8523_priv *wm8523, | |||
482 | 482 | ||
483 | if (wm8523_codec) { | 483 | if (wm8523_codec) { |
484 | dev_err(codec->dev, "Another WM8523 is registered\n"); | 484 | dev_err(codec->dev, "Another WM8523 is registered\n"); |
485 | return -EINVAL; | 485 | ret = -EINVAL; |
486 | goto err; | ||
486 | } | 487 | } |
487 | 488 | ||
488 | mutex_init(&codec->mutex); | 489 | mutex_init(&codec->mutex); |
@@ -570,18 +571,19 @@ static int wm8523_register(struct wm8523_priv *wm8523, | |||
570 | ret = snd_soc_register_codec(codec); | 571 | ret = snd_soc_register_codec(codec); |
571 | if (ret != 0) { | 572 | if (ret != 0) { |
572 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); | 573 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); |
573 | return ret; | 574 | goto err_enable; |
574 | } | 575 | } |
575 | 576 | ||
576 | ret = snd_soc_register_dai(&wm8523_dai); | 577 | ret = snd_soc_register_dai(&wm8523_dai); |
577 | if (ret != 0) { | 578 | if (ret != 0) { |
578 | dev_err(codec->dev, "Failed to register DAI: %d\n", ret); | 579 | dev_err(codec->dev, "Failed to register DAI: %d\n", ret); |
579 | snd_soc_unregister_codec(codec); | 580 | goto err_codec; |
580 | return ret; | ||
581 | } | 581 | } |
582 | 582 | ||
583 | return 0; | 583 | return 0; |
584 | 584 | ||
585 | err_codec: | ||
586 | snd_soc_unregister_codec(codec); | ||
585 | err_enable: | 587 | err_enable: |
586 | regulator_bulk_disable(ARRAY_SIZE(wm8523->supplies), wm8523->supplies); | 588 | regulator_bulk_disable(ARRAY_SIZE(wm8523->supplies), wm8523->supplies); |
587 | err_get: | 589 | err_get: |
diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index c3571ee5c11b..72deeabef4fe 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c | |||
@@ -269,9 +269,9 @@ SOC_DOUBLE("DAC2 Invert Switch", WM8580_DAC_CONTROL4, 2, 3, 1, 0), | |||
269 | SOC_DOUBLE("DAC3 Invert Switch", WM8580_DAC_CONTROL4, 4, 5, 1, 0), | 269 | SOC_DOUBLE("DAC3 Invert Switch", WM8580_DAC_CONTROL4, 4, 5, 1, 0), |
270 | 270 | ||
271 | SOC_SINGLE("DAC ZC Switch", WM8580_DAC_CONTROL5, 5, 1, 0), | 271 | SOC_SINGLE("DAC ZC Switch", WM8580_DAC_CONTROL5, 5, 1, 0), |
272 | SOC_SINGLE("DAC1 Switch", WM8580_DAC_CONTROL5, 0, 1, 0), | 272 | SOC_SINGLE("DAC1 Switch", WM8580_DAC_CONTROL5, 0, 1, 1), |
273 | SOC_SINGLE("DAC2 Switch", WM8580_DAC_CONTROL5, 1, 1, 0), | 273 | SOC_SINGLE("DAC2 Switch", WM8580_DAC_CONTROL5, 1, 1, 1), |
274 | SOC_SINGLE("DAC3 Switch", WM8580_DAC_CONTROL5, 2, 1, 0), | 274 | SOC_SINGLE("DAC3 Switch", WM8580_DAC_CONTROL5, 2, 1, 1), |
275 | 275 | ||
276 | SOC_DOUBLE("ADC Mute Switch", WM8580_ADC_CONTROL1, 0, 1, 1, 0), | 276 | SOC_DOUBLE("ADC Mute Switch", WM8580_ADC_CONTROL1, 0, 1, 1, 0), |
277 | SOC_SINGLE("ADC High-Pass Filter Switch", WM8580_ADC_CONTROL1, 4, 1, 0), | 277 | SOC_SINGLE("ADC High-Pass Filter Switch", WM8580_ADC_CONTROL1, 4, 1, 0), |
diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c index effb14eee7d4..e2dba07f0260 100644 --- a/sound/soc/codecs/wm8711.c +++ b/sound/soc/codecs/wm8711.c | |||
@@ -439,7 +439,8 @@ static int wm8711_register(struct wm8711_priv *wm8711, | |||
439 | 439 | ||
440 | if (wm8711_codec) { | 440 | if (wm8711_codec) { |
441 | dev_err(codec->dev, "Another WM8711 is registered\n"); | 441 | dev_err(codec->dev, "Another WM8711 is registered\n"); |
442 | return -EINVAL; | 442 | ret = -EINVAL; |
443 | goto err; | ||
443 | } | 444 | } |
444 | 445 | ||
445 | mutex_init(&codec->mutex); | 446 | mutex_init(&codec->mutex); |
diff --git a/sound/soc/codecs/wm8741.c b/sound/soc/codecs/wm8741.c new file mode 100644 index 000000000000..b9ea8904ad4b --- /dev/null +++ b/sound/soc/codecs/wm8741.c | |||
@@ -0,0 +1,579 @@ | |||
1 | /* | ||
2 | * wm8741.c -- WM8741 ALSA SoC Audio driver | ||
3 | * | ||
4 | * Copyright 2010 Wolfson Microelectronics plc | ||
5 | * | ||
6 | * Author: Ian Lartey <ian@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 <linux/slab.h> | ||
23 | #include <sound/core.h> | ||
24 | #include <sound/pcm.h> | ||
25 | #include <sound/pcm_params.h> | ||
26 | #include <sound/soc.h> | ||
27 | #include <sound/soc-dapm.h> | ||
28 | #include <sound/initval.h> | ||
29 | #include <sound/tlv.h> | ||
30 | |||
31 | #include "wm8741.h" | ||
32 | |||
33 | static struct snd_soc_codec *wm8741_codec; | ||
34 | struct snd_soc_codec_device soc_codec_dev_wm8741; | ||
35 | |||
36 | #define WM8741_NUM_SUPPLIES 2 | ||
37 | static const char *wm8741_supply_names[WM8741_NUM_SUPPLIES] = { | ||
38 | "AVDD", | ||
39 | "DVDD", | ||
40 | }; | ||
41 | |||
42 | #define WM8741_NUM_RATES 4 | ||
43 | |||
44 | /* codec private data */ | ||
45 | struct wm8741_priv { | ||
46 | struct snd_soc_codec codec; | ||
47 | u16 reg_cache[WM8741_REGISTER_COUNT]; | ||
48 | struct regulator_bulk_data supplies[WM8741_NUM_SUPPLIES]; | ||
49 | unsigned int sysclk; | ||
50 | unsigned int rate_constraint_list[WM8741_NUM_RATES]; | ||
51 | struct snd_pcm_hw_constraint_list rate_constraint; | ||
52 | }; | ||
53 | |||
54 | static const u16 wm8741_reg_defaults[WM8741_REGISTER_COUNT] = { | ||
55 | 0x0000, /* R0 - DACLLSB Attenuation */ | ||
56 | 0x0000, /* R1 - DACLMSB Attenuation */ | ||
57 | 0x0000, /* R2 - DACRLSB Attenuation */ | ||
58 | 0x0000, /* R3 - DACRMSB Attenuation */ | ||
59 | 0x0000, /* R4 - Volume Control */ | ||
60 | 0x000A, /* R5 - Format Control */ | ||
61 | 0x0000, /* R6 - Filter Control */ | ||
62 | 0x0000, /* R7 - Mode Control 1 */ | ||
63 | 0x0002, /* R8 - Mode Control 2 */ | ||
64 | 0x0000, /* R9 - Reset */ | ||
65 | 0x0002, /* R32 - ADDITONAL_CONTROL_1 */ | ||
66 | }; | ||
67 | |||
68 | |||
69 | static int wm8741_reset(struct snd_soc_codec *codec) | ||
70 | { | ||
71 | return snd_soc_write(codec, WM8741_RESET, 0); | ||
72 | } | ||
73 | |||
74 | static const DECLARE_TLV_DB_SCALE(dac_tlv_fine, -12700, 13, 0); | ||
75 | static const DECLARE_TLV_DB_SCALE(dac_tlv, -12700, 400, 0); | ||
76 | |||
77 | static const struct snd_kcontrol_new wm8741_snd_controls[] = { | ||
78 | SOC_DOUBLE_R_TLV("Fine Playback Volume", WM8741_DACLLSB_ATTENUATION, | ||
79 | WM8741_DACRLSB_ATTENUATION, 1, 255, 1, dac_tlv_fine), | ||
80 | SOC_DOUBLE_R_TLV("Playback Volume", WM8741_DACLMSB_ATTENUATION, | ||
81 | WM8741_DACRMSB_ATTENUATION, 0, 511, 1, dac_tlv), | ||
82 | }; | ||
83 | |||
84 | static const struct snd_soc_dapm_widget wm8741_dapm_widgets[] = { | ||
85 | SND_SOC_DAPM_DAC("DACL", "Playback", SND_SOC_NOPM, 0, 0), | ||
86 | SND_SOC_DAPM_DAC("DACR", "Playback", SND_SOC_NOPM, 0, 0), | ||
87 | SND_SOC_DAPM_OUTPUT("VOUTLP"), | ||
88 | SND_SOC_DAPM_OUTPUT("VOUTLN"), | ||
89 | SND_SOC_DAPM_OUTPUT("VOUTRP"), | ||
90 | SND_SOC_DAPM_OUTPUT("VOUTRN"), | ||
91 | }; | ||
92 | |||
93 | static const struct snd_soc_dapm_route intercon[] = { | ||
94 | { "VOUTLP", NULL, "DACL" }, | ||
95 | { "VOUTLN", NULL, "DACL" }, | ||
96 | { "VOUTRP", NULL, "DACR" }, | ||
97 | { "VOUTRN", NULL, "DACR" }, | ||
98 | }; | ||
99 | |||
100 | static int wm8741_add_widgets(struct snd_soc_codec *codec) | ||
101 | { | ||
102 | snd_soc_dapm_new_controls(codec, wm8741_dapm_widgets, | ||
103 | ARRAY_SIZE(wm8741_dapm_widgets)); | ||
104 | |||
105 | snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); | ||
106 | |||
107 | return 0; | ||
108 | } | ||
109 | |||
110 | static struct { | ||
111 | int value; | ||
112 | int ratio; | ||
113 | } lrclk_ratios[WM8741_NUM_RATES] = { | ||
114 | { 1, 256 }, | ||
115 | { 2, 384 }, | ||
116 | { 3, 512 }, | ||
117 | { 4, 768 }, | ||
118 | }; | ||
119 | |||
120 | |||
121 | static int wm8741_startup(struct snd_pcm_substream *substream, | ||
122 | struct snd_soc_dai *dai) | ||
123 | { | ||
124 | struct snd_soc_codec *codec = dai->codec; | ||
125 | struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec); | ||
126 | |||
127 | /* The set of sample rates that can be supported depends on the | ||
128 | * MCLK supplied to the CODEC - enforce this. | ||
129 | */ | ||
130 | if (!wm8741->sysclk) { | ||
131 | dev_err(codec->dev, | ||
132 | "No MCLK configured, call set_sysclk() on init\n"); | ||
133 | return -EINVAL; | ||
134 | } | ||
135 | |||
136 | snd_pcm_hw_constraint_list(substream->runtime, 0, | ||
137 | SNDRV_PCM_HW_PARAM_RATE, | ||
138 | &wm8741->rate_constraint); | ||
139 | |||
140 | return 0; | ||
141 | } | ||
142 | |||
143 | static int wm8741_hw_params(struct snd_pcm_substream *substream, | ||
144 | struct snd_pcm_hw_params *params, | ||
145 | struct snd_soc_dai *dai) | ||
146 | { | ||
147 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
148 | struct snd_soc_device *socdev = rtd->socdev; | ||
149 | struct snd_soc_codec *codec = socdev->card->codec; | ||
150 | struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec); | ||
151 | u16 iface = snd_soc_read(codec, WM8741_FORMAT_CONTROL) & 0x1FC; | ||
152 | int i; | ||
153 | |||
154 | /* Find a supported LRCLK ratio */ | ||
155 | for (i = 0; i < ARRAY_SIZE(lrclk_ratios); i++) { | ||
156 | if (wm8741->sysclk / params_rate(params) == | ||
157 | lrclk_ratios[i].ratio) | ||
158 | break; | ||
159 | } | ||
160 | |||
161 | /* Should never happen, should be handled by constraints */ | ||
162 | if (i == ARRAY_SIZE(lrclk_ratios)) { | ||
163 | dev_err(codec->dev, "MCLK/fs ratio %d unsupported\n", | ||
164 | wm8741->sysclk / params_rate(params)); | ||
165 | return -EINVAL; | ||
166 | } | ||
167 | |||
168 | /* bit size */ | ||
169 | switch (params_format(params)) { | ||
170 | case SNDRV_PCM_FORMAT_S16_LE: | ||
171 | break; | ||
172 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
173 | iface |= 0x0001; | ||
174 | break; | ||
175 | case SNDRV_PCM_FORMAT_S24_LE: | ||
176 | iface |= 0x0002; | ||
177 | break; | ||
178 | case SNDRV_PCM_FORMAT_S32_LE: | ||
179 | iface |= 0x0003; | ||
180 | break; | ||
181 | default: | ||
182 | dev_dbg(codec->dev, "wm8741_hw_params: Unsupported bit size param = %d", | ||
183 | params_format(params)); | ||
184 | return -EINVAL; | ||
185 | } | ||
186 | |||
187 | dev_dbg(codec->dev, "wm8741_hw_params: bit size param = %d", | ||
188 | params_format(params)); | ||
189 | |||
190 | snd_soc_write(codec, WM8741_FORMAT_CONTROL, iface); | ||
191 | return 0; | ||
192 | } | ||
193 | |||
194 | static int wm8741_set_dai_sysclk(struct snd_soc_dai *codec_dai, | ||
195 | int clk_id, unsigned int freq, int dir) | ||
196 | { | ||
197 | struct snd_soc_codec *codec = codec_dai->codec; | ||
198 | struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec); | ||
199 | unsigned int val; | ||
200 | int i; | ||
201 | |||
202 | dev_dbg(codec->dev, "wm8741_set_dai_sysclk info: freq=%dHz\n", freq); | ||
203 | |||
204 | wm8741->sysclk = freq; | ||
205 | |||
206 | wm8741->rate_constraint.count = 0; | ||
207 | |||
208 | for (i = 0; i < ARRAY_SIZE(lrclk_ratios); i++) { | ||
209 | dev_dbg(codec->dev, "index = %d, ratio = %d, freq = %d", | ||
210 | i, lrclk_ratios[i].ratio, freq); | ||
211 | |||
212 | val = freq / lrclk_ratios[i].ratio; | ||
213 | /* Check that it's a standard rate since core can't | ||
214 | * cope with others and having the odd rates confuses | ||
215 | * constraint matching. | ||
216 | */ | ||
217 | switch (val) { | ||
218 | case 32000: | ||
219 | case 44100: | ||
220 | case 48000: | ||
221 | case 64000: | ||
222 | case 88200: | ||
223 | case 96000: | ||
224 | dev_dbg(codec->dev, "Supported sample rate: %dHz\n", | ||
225 | val); | ||
226 | wm8741->rate_constraint_list[i] = val; | ||
227 | wm8741->rate_constraint.count++; | ||
228 | break; | ||
229 | default: | ||
230 | dev_dbg(codec->dev, "Skipping sample rate: %dHz\n", | ||
231 | val); | ||
232 | } | ||
233 | } | ||
234 | |||
235 | /* Need at least one supported rate... */ | ||
236 | if (wm8741->rate_constraint.count == 0) | ||
237 | return -EINVAL; | ||
238 | |||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | static int wm8741_set_dai_fmt(struct snd_soc_dai *codec_dai, | ||
243 | unsigned int fmt) | ||
244 | { | ||
245 | struct snd_soc_codec *codec = codec_dai->codec; | ||
246 | u16 iface = snd_soc_read(codec, WM8741_FORMAT_CONTROL) & 0x1C3; | ||
247 | |||
248 | /* check master/slave audio interface */ | ||
249 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
250 | case SND_SOC_DAIFMT_CBS_CFS: | ||
251 | break; | ||
252 | default: | ||
253 | return -EINVAL; | ||
254 | } | ||
255 | |||
256 | /* interface format */ | ||
257 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
258 | case SND_SOC_DAIFMT_I2S: | ||
259 | iface |= 0x0008; | ||
260 | break; | ||
261 | case SND_SOC_DAIFMT_RIGHT_J: | ||
262 | break; | ||
263 | case SND_SOC_DAIFMT_LEFT_J: | ||
264 | iface |= 0x0004; | ||
265 | break; | ||
266 | case SND_SOC_DAIFMT_DSP_A: | ||
267 | iface |= 0x0003; | ||
268 | break; | ||
269 | case SND_SOC_DAIFMT_DSP_B: | ||
270 | iface |= 0x0013; | ||
271 | break; | ||
272 | default: | ||
273 | return -EINVAL; | ||
274 | } | ||
275 | |||
276 | /* clock inversion */ | ||
277 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
278 | case SND_SOC_DAIFMT_NB_NF: | ||
279 | break; | ||
280 | case SND_SOC_DAIFMT_IB_IF: | ||
281 | iface |= 0x0010; | ||
282 | break; | ||
283 | case SND_SOC_DAIFMT_IB_NF: | ||
284 | iface |= 0x0020; | ||
285 | break; | ||
286 | case SND_SOC_DAIFMT_NB_IF: | ||
287 | iface |= 0x0030; | ||
288 | break; | ||
289 | default: | ||
290 | return -EINVAL; | ||
291 | } | ||
292 | |||
293 | |||
294 | dev_dbg(codec->dev, "wm8741_set_dai_fmt: Format=%x, Clock Inv=%x\n", | ||
295 | fmt & SND_SOC_DAIFMT_FORMAT_MASK, | ||
296 | ((fmt & SND_SOC_DAIFMT_INV_MASK))); | ||
297 | |||
298 | snd_soc_write(codec, WM8741_FORMAT_CONTROL, iface); | ||
299 | return 0; | ||
300 | } | ||
301 | |||
302 | #define WM8741_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ | ||
303 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | \ | ||
304 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | \ | ||
305 | SNDRV_PCM_RATE_192000) | ||
306 | |||
307 | #define WM8741_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | ||
308 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) | ||
309 | |||
310 | static struct snd_soc_dai_ops wm8741_dai_ops = { | ||
311 | .startup = wm8741_startup, | ||
312 | .hw_params = wm8741_hw_params, | ||
313 | .set_sysclk = wm8741_set_dai_sysclk, | ||
314 | .set_fmt = wm8741_set_dai_fmt, | ||
315 | }; | ||
316 | |||
317 | struct snd_soc_dai wm8741_dai = { | ||
318 | .name = "WM8741", | ||
319 | .playback = { | ||
320 | .stream_name = "Playback", | ||
321 | .channels_min = 2, /* Mono modes not yet supported */ | ||
322 | .channels_max = 2, | ||
323 | .rates = WM8741_RATES, | ||
324 | .formats = WM8741_FORMATS, | ||
325 | }, | ||
326 | .ops = &wm8741_dai_ops, | ||
327 | }; | ||
328 | EXPORT_SYMBOL_GPL(wm8741_dai); | ||
329 | |||
330 | #ifdef CONFIG_PM | ||
331 | static int wm8741_resume(struct platform_device *pdev) | ||
332 | { | ||
333 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
334 | struct snd_soc_codec *codec = socdev->card->codec; | ||
335 | u16 *cache = codec->reg_cache; | ||
336 | int i; | ||
337 | |||
338 | /* RESTORE REG Cache */ | ||
339 | for (i = 0; i < WM8741_REGISTER_COUNT; i++) { | ||
340 | if (cache[i] == wm8741_reg_defaults[i] || WM8741_RESET == i) | ||
341 | continue; | ||
342 | snd_soc_write(codec, i, cache[i]); | ||
343 | } | ||
344 | return 0; | ||
345 | } | ||
346 | #else | ||
347 | #define wm8741_suspend NULL | ||
348 | #define wm8741_resume NULL | ||
349 | #endif | ||
350 | |||
351 | static int wm8741_probe(struct platform_device *pdev) | ||
352 | { | ||
353 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
354 | struct snd_soc_codec *codec; | ||
355 | int ret = 0; | ||
356 | |||
357 | if (wm8741_codec == NULL) { | ||
358 | dev_err(&pdev->dev, "Codec device not registered\n"); | ||
359 | return -ENODEV; | ||
360 | } | ||
361 | |||
362 | socdev->card->codec = wm8741_codec; | ||
363 | codec = wm8741_codec; | ||
364 | |||
365 | /* register pcms */ | ||
366 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
367 | if (ret < 0) { | ||
368 | dev_err(codec->dev, "failed to create pcms: %d\n", ret); | ||
369 | goto pcm_err; | ||
370 | } | ||
371 | |||
372 | snd_soc_add_controls(codec, wm8741_snd_controls, | ||
373 | ARRAY_SIZE(wm8741_snd_controls)); | ||
374 | wm8741_add_widgets(codec); | ||
375 | |||
376 | return ret; | ||
377 | |||
378 | pcm_err: | ||
379 | return ret; | ||
380 | } | ||
381 | |||
382 | static int wm8741_remove(struct platform_device *pdev) | ||
383 | { | ||
384 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
385 | |||
386 | snd_soc_free_pcms(socdev); | ||
387 | snd_soc_dapm_free(socdev); | ||
388 | |||
389 | return 0; | ||
390 | } | ||
391 | |||
392 | struct snd_soc_codec_device soc_codec_dev_wm8741 = { | ||
393 | .probe = wm8741_probe, | ||
394 | .remove = wm8741_remove, | ||
395 | .resume = wm8741_resume, | ||
396 | }; | ||
397 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8741); | ||
398 | |||
399 | static int wm8741_register(struct wm8741_priv *wm8741, | ||
400 | enum snd_soc_control_type control) | ||
401 | { | ||
402 | int ret; | ||
403 | struct snd_soc_codec *codec = &wm8741->codec; | ||
404 | int i; | ||
405 | |||
406 | if (wm8741_codec) { | ||
407 | dev_err(codec->dev, "Another WM8741 is registered\n"); | ||
408 | return -EINVAL; | ||
409 | } | ||
410 | |||
411 | mutex_init(&codec->mutex); | ||
412 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
413 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
414 | |||
415 | snd_soc_codec_set_drvdata(codec, wm8741); | ||
416 | codec->name = "WM8741"; | ||
417 | codec->owner = THIS_MODULE; | ||
418 | codec->bias_level = SND_SOC_BIAS_OFF; | ||
419 | codec->set_bias_level = NULL; | ||
420 | codec->dai = &wm8741_dai; | ||
421 | codec->num_dai = 1; | ||
422 | codec->reg_cache_size = WM8741_REGISTER_COUNT; | ||
423 | codec->reg_cache = &wm8741->reg_cache; | ||
424 | |||
425 | wm8741->rate_constraint.list = &wm8741->rate_constraint_list[0]; | ||
426 | wm8741->rate_constraint.count = | ||
427 | ARRAY_SIZE(wm8741->rate_constraint_list); | ||
428 | |||
429 | memcpy(codec->reg_cache, wm8741_reg_defaults, | ||
430 | sizeof(wm8741->reg_cache)); | ||
431 | |||
432 | ret = snd_soc_codec_set_cache_io(codec, 7, 9, control); | ||
433 | if (ret != 0) { | ||
434 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); | ||
435 | goto err; | ||
436 | } | ||
437 | |||
438 | for (i = 0; i < ARRAY_SIZE(wm8741->supplies); i++) | ||
439 | wm8741->supplies[i].supply = wm8741_supply_names[i]; | ||
440 | |||
441 | ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8741->supplies), | ||
442 | wm8741->supplies); | ||
443 | if (ret != 0) { | ||
444 | dev_err(codec->dev, "Failed to request supplies: %d\n", ret); | ||
445 | goto err; | ||
446 | } | ||
447 | |||
448 | ret = regulator_bulk_enable(ARRAY_SIZE(wm8741->supplies), | ||
449 | wm8741->supplies); | ||
450 | if (ret != 0) { | ||
451 | dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); | ||
452 | goto err_get; | ||
453 | } | ||
454 | |||
455 | ret = wm8741_reset(codec); | ||
456 | if (ret < 0) { | ||
457 | dev_err(codec->dev, "Failed to issue reset\n"); | ||
458 | goto err_enable; | ||
459 | } | ||
460 | |||
461 | wm8741_dai.dev = codec->dev; | ||
462 | |||
463 | /* Change some default settings - latch VU */ | ||
464 | wm8741->reg_cache[WM8741_DACLLSB_ATTENUATION] |= WM8741_UPDATELL; | ||
465 | wm8741->reg_cache[WM8741_DACLMSB_ATTENUATION] |= WM8741_UPDATELM; | ||
466 | wm8741->reg_cache[WM8741_DACRLSB_ATTENUATION] |= WM8741_UPDATERL; | ||
467 | wm8741->reg_cache[WM8741_DACRLSB_ATTENUATION] |= WM8741_UPDATERM; | ||
468 | |||
469 | wm8741_codec = codec; | ||
470 | |||
471 | ret = snd_soc_register_codec(codec); | ||
472 | if (ret != 0) { | ||
473 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); | ||
474 | return ret; | ||
475 | } | ||
476 | |||
477 | ret = snd_soc_register_dai(&wm8741_dai); | ||
478 | if (ret != 0) { | ||
479 | dev_err(codec->dev, "Failed to register DAI: %d\n", ret); | ||
480 | snd_soc_unregister_codec(codec); | ||
481 | return ret; | ||
482 | } | ||
483 | |||
484 | dev_dbg(codec->dev, "Successful registration\n"); | ||
485 | return 0; | ||
486 | |||
487 | err_enable: | ||
488 | regulator_bulk_disable(ARRAY_SIZE(wm8741->supplies), wm8741->supplies); | ||
489 | |||
490 | err_get: | ||
491 | regulator_bulk_free(ARRAY_SIZE(wm8741->supplies), wm8741->supplies); | ||
492 | |||
493 | err: | ||
494 | kfree(wm8741); | ||
495 | return ret; | ||
496 | } | ||
497 | |||
498 | static void wm8741_unregister(struct wm8741_priv *wm8741) | ||
499 | { | ||
500 | regulator_bulk_free(ARRAY_SIZE(wm8741->supplies), wm8741->supplies); | ||
501 | |||
502 | snd_soc_unregister_dai(&wm8741_dai); | ||
503 | snd_soc_unregister_codec(&wm8741->codec); | ||
504 | kfree(wm8741); | ||
505 | wm8741_codec = NULL; | ||
506 | } | ||
507 | |||
508 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
509 | static __devinit int wm8741_i2c_probe(struct i2c_client *i2c, | ||
510 | const struct i2c_device_id *id) | ||
511 | { | ||
512 | struct wm8741_priv *wm8741; | ||
513 | struct snd_soc_codec *codec; | ||
514 | |||
515 | wm8741 = kzalloc(sizeof(struct wm8741_priv), GFP_KERNEL); | ||
516 | if (wm8741 == NULL) | ||
517 | return -ENOMEM; | ||
518 | |||
519 | codec = &wm8741->codec; | ||
520 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
521 | |||
522 | i2c_set_clientdata(i2c, wm8741); | ||
523 | codec->control_data = i2c; | ||
524 | |||
525 | codec->dev = &i2c->dev; | ||
526 | |||
527 | return wm8741_register(wm8741, SND_SOC_I2C); | ||
528 | } | ||
529 | |||
530 | static __devexit int wm8741_i2c_remove(struct i2c_client *client) | ||
531 | { | ||
532 | struct wm8741_priv *wm8741 = i2c_get_clientdata(client); | ||
533 | wm8741_unregister(wm8741); | ||
534 | return 0; | ||
535 | } | ||
536 | |||
537 | static const struct i2c_device_id wm8741_i2c_id[] = { | ||
538 | { "wm8741", 0 }, | ||
539 | { } | ||
540 | }; | ||
541 | MODULE_DEVICE_TABLE(i2c, wm8741_i2c_id); | ||
542 | |||
543 | |||
544 | static struct i2c_driver wm8741_i2c_driver = { | ||
545 | .driver = { | ||
546 | .name = "WM8741", | ||
547 | .owner = THIS_MODULE, | ||
548 | }, | ||
549 | .probe = wm8741_i2c_probe, | ||
550 | .remove = __devexit_p(wm8741_i2c_remove), | ||
551 | .id_table = wm8741_i2c_id, | ||
552 | }; | ||
553 | #endif | ||
554 | |||
555 | static int __init wm8741_modinit(void) | ||
556 | { | ||
557 | int ret; | ||
558 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
559 | ret = i2c_add_driver(&wm8741_i2c_driver); | ||
560 | if (ret != 0) { | ||
561 | printk(KERN_ERR "Failed to register WM8741 I2C driver: %d\n", | ||
562 | ret); | ||
563 | } | ||
564 | #endif | ||
565 | return 0; | ||
566 | } | ||
567 | module_init(wm8741_modinit); | ||
568 | |||
569 | static void __exit wm8741_exit(void) | ||
570 | { | ||
571 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
572 | i2c_del_driver(&wm8741_i2c_driver); | ||
573 | #endif | ||
574 | } | ||
575 | module_exit(wm8741_exit); | ||
576 | |||
577 | MODULE_DESCRIPTION("ASoC WM8741 driver"); | ||
578 | MODULE_AUTHOR("Ian Lartey <ian@opensource.wolfsonmicro.com>"); | ||
579 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/wm8741.h b/sound/soc/codecs/wm8741.h new file mode 100644 index 000000000000..fdef6ecd1f6f --- /dev/null +++ b/sound/soc/codecs/wm8741.h | |||
@@ -0,0 +1,214 @@ | |||
1 | /* | ||
2 | * wm8741.h -- WM8423 ASoC driver | ||
3 | * | ||
4 | * Copyright 2010 Wolfson Microelectronics, plc | ||
5 | * | ||
6 | * Author: Ian Lartey <ian@opensource.wolfsonmicro.com> | ||
7 | * | ||
8 | * Based on wm8753.h | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #ifndef _WM8741_H | ||
16 | #define _WM8741_H | ||
17 | |||
18 | /* | ||
19 | * Register values. | ||
20 | */ | ||
21 | #define WM8741_DACLLSB_ATTENUATION 0x00 | ||
22 | #define WM8741_DACLMSB_ATTENUATION 0x01 | ||
23 | #define WM8741_DACRLSB_ATTENUATION 0x02 | ||
24 | #define WM8741_DACRMSB_ATTENUATION 0x03 | ||
25 | #define WM8741_VOLUME_CONTROL 0x04 | ||
26 | #define WM8741_FORMAT_CONTROL 0x05 | ||
27 | #define WM8741_FILTER_CONTROL 0x06 | ||
28 | #define WM8741_MODE_CONTROL_1 0x07 | ||
29 | #define WM8741_MODE_CONTROL_2 0x08 | ||
30 | #define WM8741_RESET 0x09 | ||
31 | #define WM8741_ADDITIONAL_CONTROL_1 0x20 | ||
32 | |||
33 | #define WM8741_REGISTER_COUNT 11 | ||
34 | #define WM8741_MAX_REGISTER 0x20 | ||
35 | |||
36 | /* | ||
37 | * Field Definitions. | ||
38 | */ | ||
39 | |||
40 | /* | ||
41 | * R0 (0x00) - DACLLSB_ATTENUATION | ||
42 | */ | ||
43 | #define WM8741_UPDATELL 0x0020 /* UPDATELL */ | ||
44 | #define WM8741_UPDATELL_MASK 0x0020 /* UPDATELL */ | ||
45 | #define WM8741_UPDATELL_SHIFT 5 /* UPDATELL */ | ||
46 | #define WM8741_UPDATELL_WIDTH 1 /* UPDATELL */ | ||
47 | #define WM8741_LAT_4_0_MASK 0x001F /* LAT[4:0] - [4:0] */ | ||
48 | #define WM8741_LAT_4_0_SHIFT 0 /* LAT[4:0] - [4:0] */ | ||
49 | #define WM8741_LAT_4_0_WIDTH 5 /* LAT[4:0] - [4:0] */ | ||
50 | |||
51 | /* | ||
52 | * R1 (0x01) - DACLMSB_ATTENUATION | ||
53 | */ | ||
54 | #define WM8741_UPDATELM 0x0020 /* UPDATELM */ | ||
55 | #define WM8741_UPDATELM_MASK 0x0020 /* UPDATELM */ | ||
56 | #define WM8741_UPDATELM_SHIFT 5 /* UPDATELM */ | ||
57 | #define WM8741_UPDATELM_WIDTH 1 /* UPDATELM */ | ||
58 | #define WM8741_LAT_9_5_0_MASK 0x001F /* LAT[9:5] - [4:0] */ | ||
59 | #define WM8741_LAT_9_5_0_SHIFT 0 /* LAT[9:5] - [4:0] */ | ||
60 | #define WM8741_LAT_9_5_0_WIDTH 5 /* LAT[9:5] - [4:0] */ | ||
61 | |||
62 | /* | ||
63 | * R2 (0x02) - DACRLSB_ATTENUATION | ||
64 | */ | ||
65 | #define WM8741_UPDATERL 0x0020 /* UPDATERL */ | ||
66 | #define WM8741_UPDATERL_MASK 0x0020 /* UPDATERL */ | ||
67 | #define WM8741_UPDATERL_SHIFT 5 /* UPDATERL */ | ||
68 | #define WM8741_UPDATERL_WIDTH 1 /* UPDATERL */ | ||
69 | #define WM8741_RAT_4_0_MASK 0x001F /* RAT[4:0] - [4:0] */ | ||
70 | #define WM8741_RAT_4_0_SHIFT 0 /* RAT[4:0] - [4:0] */ | ||
71 | #define WM8741_RAT_4_0_WIDTH 5 /* RAT[4:0] - [4:0] */ | ||
72 | |||
73 | /* | ||
74 | * R3 (0x03) - DACRMSB_ATTENUATION | ||
75 | */ | ||
76 | #define WM8741_UPDATERM 0x0020 /* UPDATERM */ | ||
77 | #define WM8741_UPDATERM_MASK 0x0020 /* UPDATERM */ | ||
78 | #define WM8741_UPDATERM_SHIFT 5 /* UPDATERM */ | ||
79 | #define WM8741_UPDATERM_WIDTH 1 /* UPDATERM */ | ||
80 | #define WM8741_RAT_9_5_0_MASK 0x001F /* RAT[9:5] - [4:0] */ | ||
81 | #define WM8741_RAT_9_5_0_SHIFT 0 /* RAT[9:5] - [4:0] */ | ||
82 | #define WM8741_RAT_9_5_0_WIDTH 5 /* RAT[9:5] - [4:0] */ | ||
83 | |||
84 | /* | ||
85 | * R4 (0x04) - VOLUME_CONTROL | ||
86 | */ | ||
87 | #define WM8741_AMUTE 0x0080 /* AMUTE */ | ||
88 | #define WM8741_AMUTE_MASK 0x0080 /* AMUTE */ | ||
89 | #define WM8741_AMUTE_SHIFT 7 /* AMUTE */ | ||
90 | #define WM8741_AMUTE_WIDTH 1 /* AMUTE */ | ||
91 | #define WM8741_ZFLAG_MASK 0x0060 /* ZFLAG - [6:5] */ | ||
92 | #define WM8741_ZFLAG_SHIFT 5 /* ZFLAG - [6:5] */ | ||
93 | #define WM8741_ZFLAG_WIDTH 2 /* ZFLAG - [6:5] */ | ||
94 | #define WM8741_IZD 0x0010 /* IZD */ | ||
95 | #define WM8741_IZD_MASK 0x0010 /* IZD */ | ||
96 | #define WM8741_IZD_SHIFT 4 /* IZD */ | ||
97 | #define WM8741_IZD_WIDTH 1 /* IZD */ | ||
98 | #define WM8741_SOFT 0x0008 /* SOFT MUTE */ | ||
99 | #define WM8741_SOFT_MASK 0x0008 /* SOFT MUTE */ | ||
100 | #define WM8741_SOFT_SHIFT 3 /* SOFT MUTE */ | ||
101 | #define WM8741_SOFT_WIDTH 1 /* SOFT MUTE */ | ||
102 | #define WM8741_ATC 0x0004 /* ATC */ | ||
103 | #define WM8741_ATC_MASK 0x0004 /* ATC */ | ||
104 | #define WM8741_ATC_SHIFT 2 /* ATC */ | ||
105 | #define WM8741_ATC_WIDTH 1 /* ATC */ | ||
106 | #define WM8741_ATT2DB 0x0002 /* ATT2DB */ | ||
107 | #define WM8741_ATT2DB_MASK 0x0002 /* ATT2DB */ | ||
108 | #define WM8741_ATT2DB_SHIFT 1 /* ATT2DB */ | ||
109 | #define WM8741_ATT2DB_WIDTH 1 /* ATT2DB */ | ||
110 | #define WM8741_VOL_RAMP 0x0001 /* VOL_RAMP */ | ||
111 | #define WM8741_VOL_RAMP_MASK 0x0001 /* VOL_RAMP */ | ||
112 | #define WM8741_VOL_RAMP_SHIFT 0 /* VOL_RAMP */ | ||
113 | #define WM8741_VOL_RAMP_WIDTH 1 /* VOL_RAMP */ | ||
114 | |||
115 | /* | ||
116 | * R5 (0x05) - FORMAT_CONTROL | ||
117 | */ | ||
118 | #define WM8741_PWDN 0x0080 /* PWDN */ | ||
119 | #define WM8741_PWDN_MASK 0x0080 /* PWDN */ | ||
120 | #define WM8741_PWDN_SHIFT 7 /* PWDN */ | ||
121 | #define WM8741_PWDN_WIDTH 1 /* PWDN */ | ||
122 | #define WM8741_REV 0x0040 /* REV */ | ||
123 | #define WM8741_REV_MASK 0x0040 /* REV */ | ||
124 | #define WM8741_REV_SHIFT 6 /* REV */ | ||
125 | #define WM8741_REV_WIDTH 1 /* REV */ | ||
126 | #define WM8741_BCP 0x0020 /* BCP */ | ||
127 | #define WM8741_BCP_MASK 0x0020 /* BCP */ | ||
128 | #define WM8741_BCP_SHIFT 5 /* BCP */ | ||
129 | #define WM8741_BCP_WIDTH 1 /* BCP */ | ||
130 | #define WM8741_LRP 0x0010 /* LRP */ | ||
131 | #define WM8741_LRP_MASK 0x0010 /* LRP */ | ||
132 | #define WM8741_LRP_SHIFT 4 /* LRP */ | ||
133 | #define WM8741_LRP_WIDTH 1 /* LRP */ | ||
134 | #define WM8741_FMT_MASK 0x000C /* FMT - [3:2] */ | ||
135 | #define WM8741_FMT_SHIFT 2 /* FMT - [3:2] */ | ||
136 | #define WM8741_FMT_WIDTH 2 /* FMT - [3:2] */ | ||
137 | #define WM8741_IWL_MASK 0x0003 /* IWL - [1:0] */ | ||
138 | #define WM8741_IWL_SHIFT 0 /* IWL - [1:0] */ | ||
139 | #define WM8741_IWL_WIDTH 2 /* IWL - [1:0] */ | ||
140 | |||
141 | /* | ||
142 | * R6 (0x06) - FILTER_CONTROL | ||
143 | */ | ||
144 | #define WM8741_ZFLAG_HI 0x0080 /* ZFLAG_HI */ | ||
145 | #define WM8741_ZFLAG_HI_MASK 0x0080 /* ZFLAG_HI */ | ||
146 | #define WM8741_ZFLAG_HI_SHIFT 7 /* ZFLAG_HI */ | ||
147 | #define WM8741_ZFLAG_HI_WIDTH 1 /* ZFLAG_HI */ | ||
148 | #define WM8741_DEEMPH_MASK 0x0060 /* DEEMPH - [6:5] */ | ||
149 | #define WM8741_DEEMPH_SHIFT 5 /* DEEMPH - [6:5] */ | ||
150 | #define WM8741_DEEMPH_WIDTH 2 /* DEEMPH - [6:5] */ | ||
151 | #define WM8741_DSDFILT_MASK 0x0018 /* DSDFILT - [4:3] */ | ||
152 | #define WM8741_DSDFILT_SHIFT 3 /* DSDFILT - [4:3] */ | ||
153 | #define WM8741_DSDFILT_WIDTH 2 /* DSDFILT - [4:3] */ | ||
154 | #define WM8741_FIRSEL_MASK 0x0007 /* FIRSEL - [2:0] */ | ||
155 | #define WM8741_FIRSEL_SHIFT 0 /* FIRSEL - [2:0] */ | ||
156 | #define WM8741_FIRSEL_WIDTH 3 /* FIRSEL - [2:0] */ | ||
157 | |||
158 | /* | ||
159 | * R7 (0x07) - MODE_CONTROL_1 | ||
160 | */ | ||
161 | #define WM8741_MODE8X 0x0080 /* MODE8X */ | ||
162 | #define WM8741_MODE8X_MASK 0x0080 /* MODE8X */ | ||
163 | #define WM8741_MODE8X_SHIFT 7 /* MODE8X */ | ||
164 | #define WM8741_MODE8X_WIDTH 1 /* MODE8X */ | ||
165 | #define WM8741_OSR_MASK 0x0060 /* OSR - [6:5] */ | ||
166 | #define WM8741_OSR_SHIFT 5 /* OSR - [6:5] */ | ||
167 | #define WM8741_OSR_WIDTH 2 /* OSR - [6:5] */ | ||
168 | #define WM8741_SR_MASK 0x001C /* SR - [4:2] */ | ||
169 | #define WM8741_SR_SHIFT 2 /* SR - [4:2] */ | ||
170 | #define WM8741_SR_WIDTH 3 /* SR - [4:2] */ | ||
171 | #define WM8741_MODESEL_MASK 0x0003 /* MODESEL - [1:0] */ | ||
172 | #define WM8741_MODESEL_SHIFT 0 /* MODESEL - [1:0] */ | ||
173 | #define WM8741_MODESEL_WIDTH 2 /* MODESEL - [1:0] */ | ||
174 | |||
175 | /* | ||
176 | * R8 (0x08) - MODE_CONTROL_2 | ||
177 | */ | ||
178 | #define WM8741_DSD_GAIN 0x0040 /* DSD_GAIN */ | ||
179 | #define WM8741_DSD_GAIN_MASK 0x0040 /* DSD_GAIN */ | ||
180 | #define WM8741_DSD_GAIN_SHIFT 6 /* DSD_GAIN */ | ||
181 | #define WM8741_DSD_GAIN_WIDTH 1 /* DSD_GAIN */ | ||
182 | #define WM8741_SDOUT 0x0020 /* SDOUT */ | ||
183 | #define WM8741_SDOUT_MASK 0x0020 /* SDOUT */ | ||
184 | #define WM8741_SDOUT_SHIFT 5 /* SDOUT */ | ||
185 | #define WM8741_SDOUT_WIDTH 1 /* SDOUT */ | ||
186 | #define WM8741_DOUT 0x0010 /* DOUT */ | ||
187 | #define WM8741_DOUT_MASK 0x0010 /* DOUT */ | ||
188 | #define WM8741_DOUT_SHIFT 4 /* DOUT */ | ||
189 | #define WM8741_DOUT_WIDTH 1 /* DOUT */ | ||
190 | #define WM8741_DIFF_MASK 0x000C /* DIFF - [3:2] */ | ||
191 | #define WM8741_DIFF_SHIFT 2 /* DIFF - [3:2] */ | ||
192 | #define WM8741_DIFF_WIDTH 2 /* DIFF - [3:2] */ | ||
193 | #define WM8741_DITHER_MASK 0x0003 /* DITHER - [1:0] */ | ||
194 | #define WM8741_DITHER_SHIFT 0 /* DITHER - [1:0] */ | ||
195 | #define WM8741_DITHER_WIDTH 2 /* DITHER - [1:0] */ | ||
196 | |||
197 | /* | ||
198 | * R32 (0x20) - ADDITONAL_CONTROL_1 | ||
199 | */ | ||
200 | #define WM8741_DSD_LEVEL 0x0002 /* DSD_LEVEL */ | ||
201 | #define WM8741_DSD_LEVEL_MASK 0x0002 /* DSD_LEVEL */ | ||
202 | #define WM8741_DSD_LEVEL_SHIFT 1 /* DSD_LEVEL */ | ||
203 | #define WM8741_DSD_LEVEL_WIDTH 1 /* DSD_LEVEL */ | ||
204 | #define WM8741_DSD_NO_NOTCH 0x0001 /* DSD_NO_NOTCH */ | ||
205 | #define WM8741_DSD_NO_NOTCH_MASK 0x0001 /* DSD_NO_NOTCH */ | ||
206 | #define WM8741_DSD_NO_NOTCH_SHIFT 0 /* DSD_NO_NOTCH */ | ||
207 | #define WM8741_DSD_NO_NOTCH_WIDTH 1 /* DSD_NO_NOTCH */ | ||
208 | |||
209 | #define WM8741_SYSCLK 0 | ||
210 | |||
211 | extern struct snd_soc_dai wm8741_dai; | ||
212 | extern struct snd_soc_codec_device soc_codec_dev_wm8741; | ||
213 | |||
214 | #endif | ||
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index 9407e193fcc3..e2c05e3e323a 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c | |||
@@ -884,6 +884,7 @@ static int wm8750_i2c_remove(struct i2c_client *client) | |||
884 | 884 | ||
885 | static const struct i2c_device_id wm8750_i2c_id[] = { | 885 | static const struct i2c_device_id wm8750_i2c_id[] = { |
886 | { "wm8750", 0 }, | 886 | { "wm8750", 0 }, |
887 | { "wm8987", 0 }, /* WM8987 is register compatible with WM8750 */ | ||
887 | { } | 888 | { } |
888 | }; | 889 | }; |
889 | MODULE_DEVICE_TABLE(i2c, wm8750_i2c_id); | 890 | MODULE_DEVICE_TABLE(i2c, wm8750_i2c_id); |
@@ -925,14 +926,22 @@ static int __devexit wm8750_spi_remove(struct spi_device *spi) | |||
925 | return 0; | 926 | return 0; |
926 | } | 927 | } |
927 | 928 | ||
929 | static const struct spi_device_id wm8750_spi_id[] = { | ||
930 | { "wm8750", 0 }, | ||
931 | { "wm8987", 0 }, | ||
932 | { } | ||
933 | }; | ||
934 | MODULE_DEVICE_TABLE(spi, wm8750_spi_id); | ||
935 | |||
928 | static struct spi_driver wm8750_spi_driver = { | 936 | static struct spi_driver wm8750_spi_driver = { |
929 | .driver = { | 937 | .driver = { |
930 | .name = "wm8750", | 938 | .name = "WM8750 SPI Codec", |
931 | .bus = &spi_bus_type, | 939 | .bus = &spi_bus_type, |
932 | .owner = THIS_MODULE, | 940 | .owner = THIS_MODULE, |
933 | }, | 941 | }, |
934 | .probe = wm8750_spi_probe, | 942 | .probe = wm8750_spi_probe, |
935 | .remove = __devexit_p(wm8750_spi_remove), | 943 | .remove = __devexit_p(wm8750_spi_remove), |
944 | .id_table = wm8750_spi_id, | ||
936 | }; | 945 | }; |
937 | #endif | 946 | #endif |
938 | 947 | ||
diff --git a/sound/soc/codecs/wm8776.c b/sound/soc/codecs/wm8776.c index 4e212ed62ea6..f8154e661524 100644 --- a/sound/soc/codecs/wm8776.c +++ b/sound/soc/codecs/wm8776.c | |||
@@ -178,13 +178,6 @@ static int wm8776_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) | |||
178 | case SND_SOC_DAIFMT_LEFT_J: | 178 | case SND_SOC_DAIFMT_LEFT_J: |
179 | iface |= 0x0001; | 179 | iface |= 0x0001; |
180 | break; | 180 | break; |
181 | /* FIXME: CHECK A/B */ | ||
182 | case SND_SOC_DAIFMT_DSP_A: | ||
183 | iface |= 0x0003; | ||
184 | break; | ||
185 | case SND_SOC_DAIFMT_DSP_B: | ||
186 | iface |= 0x0007; | ||
187 | break; | ||
188 | default: | 181 | default: |
189 | return -EINVAL; | 182 | return -EINVAL; |
190 | } | 183 | } |
diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index 87f14f8675fa..f7dcabf6283c 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c | |||
@@ -2433,7 +2433,8 @@ static int wm8904_register(struct wm8904_priv *wm8904, | |||
2433 | 2433 | ||
2434 | if (wm8904_codec) { | 2434 | if (wm8904_codec) { |
2435 | dev_err(codec->dev, "Another WM8904 is registered\n"); | 2435 | dev_err(codec->dev, "Another WM8904 is registered\n"); |
2436 | return -EINVAL; | 2436 | ret = -EINVAL; |
2437 | goto err; | ||
2437 | } | 2438 | } |
2438 | 2439 | ||
2439 | mutex_init(&codec->mutex); | 2440 | mutex_init(&codec->mutex); |
@@ -2462,7 +2463,8 @@ static int wm8904_register(struct wm8904_priv *wm8904, | |||
2462 | default: | 2463 | default: |
2463 | dev_err(codec->dev, "Unknown device type %d\n", | 2464 | dev_err(codec->dev, "Unknown device type %d\n", |
2464 | wm8904->devtype); | 2465 | wm8904->devtype); |
2465 | return -EINVAL; | 2466 | ret = -EINVAL; |
2467 | goto err; | ||
2466 | } | 2468 | } |
2467 | 2469 | ||
2468 | memcpy(codec->reg_cache, wm8904_reg, sizeof(wm8904_reg)); | 2470 | memcpy(codec->reg_cache, wm8904_reg, sizeof(wm8904_reg)); |
@@ -2566,18 +2568,19 @@ static int wm8904_register(struct wm8904_priv *wm8904, | |||
2566 | ret = snd_soc_register_codec(codec); | 2568 | ret = snd_soc_register_codec(codec); |
2567 | if (ret != 0) { | 2569 | if (ret != 0) { |
2568 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); | 2570 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); |
2569 | return ret; | 2571 | goto err_enable; |
2570 | } | 2572 | } |
2571 | 2573 | ||
2572 | ret = snd_soc_register_dai(&wm8904_dai); | 2574 | ret = snd_soc_register_dai(&wm8904_dai); |
2573 | if (ret != 0) { | 2575 | if (ret != 0) { |
2574 | dev_err(codec->dev, "Failed to register DAI: %d\n", ret); | 2576 | dev_err(codec->dev, "Failed to register DAI: %d\n", ret); |
2575 | snd_soc_unregister_codec(codec); | 2577 | goto err_codec; |
2576 | return ret; | ||
2577 | } | 2578 | } |
2578 | 2579 | ||
2579 | return 0; | 2580 | return 0; |
2580 | 2581 | ||
2582 | err_codec: | ||
2583 | snd_soc_unregister_codec(codec); | ||
2581 | err_enable: | 2584 | err_enable: |
2582 | regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies), wm8904->supplies); | 2585 | regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies), wm8904->supplies); |
2583 | err_get: | 2586 | err_get: |
diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c index e3c4bbfaae27..f0c11138e610 100644 --- a/sound/soc/codecs/wm8940.c +++ b/sound/soc/codecs/wm8940.c | |||
@@ -845,6 +845,7 @@ static void wm8940_unregister(struct wm8940_priv *wm8940) | |||
845 | static int wm8940_i2c_probe(struct i2c_client *i2c, | 845 | static int wm8940_i2c_probe(struct i2c_client *i2c, |
846 | const struct i2c_device_id *id) | 846 | const struct i2c_device_id *id) |
847 | { | 847 | { |
848 | int ret; | ||
848 | struct wm8940_priv *wm8940; | 849 | struct wm8940_priv *wm8940; |
849 | struct snd_soc_codec *codec; | 850 | struct snd_soc_codec *codec; |
850 | 851 | ||
@@ -858,7 +859,11 @@ static int wm8940_i2c_probe(struct i2c_client *i2c, | |||
858 | codec->control_data = i2c; | 859 | codec->control_data = i2c; |
859 | codec->dev = &i2c->dev; | 860 | codec->dev = &i2c->dev; |
860 | 861 | ||
861 | return wm8940_register(wm8940, SND_SOC_I2C); | 862 | ret = wm8940_register(wm8940, SND_SOC_I2C); |
863 | if (ret < 0) | ||
864 | kfree(wm8940); | ||
865 | |||
866 | return ret; | ||
862 | } | 867 | } |
863 | 868 | ||
864 | static int __devexit wm8940_i2c_remove(struct i2c_client *client) | 869 | static int __devexit wm8940_i2c_remove(struct i2c_client *client) |
diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c index fedb76452f1b..5f025593d84d 100644 --- a/sound/soc/codecs/wm8955.c +++ b/sound/soc/codecs/wm8955.c | |||
@@ -964,7 +964,8 @@ static int wm8955_register(struct wm8955_priv *wm8955, | |||
964 | 964 | ||
965 | if (wm8955_codec) { | 965 | if (wm8955_codec) { |
966 | dev_err(codec->dev, "Another WM8955 is registered\n"); | 966 | dev_err(codec->dev, "Another WM8955 is registered\n"); |
967 | return -EINVAL; | 967 | ret = -EINVAL; |
968 | goto err; | ||
968 | } | 969 | } |
969 | 970 | ||
970 | mutex_init(&codec->mutex); | 971 | mutex_init(&codec->mutex); |
@@ -1047,18 +1048,19 @@ static int wm8955_register(struct wm8955_priv *wm8955, | |||
1047 | ret = snd_soc_register_codec(codec); | 1048 | ret = snd_soc_register_codec(codec); |
1048 | if (ret != 0) { | 1049 | if (ret != 0) { |
1049 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); | 1050 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); |
1050 | return ret; | 1051 | goto err_enable; |
1051 | } | 1052 | } |
1052 | 1053 | ||
1053 | ret = snd_soc_register_dai(&wm8955_dai); | 1054 | ret = snd_soc_register_dai(&wm8955_dai); |
1054 | if (ret != 0) { | 1055 | if (ret != 0) { |
1055 | dev_err(codec->dev, "Failed to register DAI: %d\n", ret); | 1056 | dev_err(codec->dev, "Failed to register DAI: %d\n", ret); |
1056 | snd_soc_unregister_codec(codec); | 1057 | goto err_codec; |
1057 | return ret; | ||
1058 | } | 1058 | } |
1059 | 1059 | ||
1060 | return 0; | 1060 | return 0; |
1061 | 1061 | ||
1062 | err_codec: | ||
1063 | snd_soc_unregister_codec(codec); | ||
1062 | err_enable: | 1064 | err_enable: |
1063 | regulator_bulk_disable(ARRAY_SIZE(wm8955->supplies), wm8955->supplies); | 1065 | regulator_bulk_disable(ARRAY_SIZE(wm8955->supplies), wm8955->supplies); |
1064 | err_get: | 1066 | err_get: |
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index 7233cc68435a..3c6ee61f6c95 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c | |||
@@ -79,12 +79,13 @@ struct wm8960_priv { | |||
79 | struct snd_soc_dapm_widget *lout1; | 79 | struct snd_soc_dapm_widget *lout1; |
80 | struct snd_soc_dapm_widget *rout1; | 80 | struct snd_soc_dapm_widget *rout1; |
81 | struct snd_soc_dapm_widget *out3; | 81 | struct snd_soc_dapm_widget *out3; |
82 | bool deemph; | ||
83 | int playback_fs; | ||
82 | }; | 84 | }; |
83 | 85 | ||
84 | #define wm8960_reset(c) snd_soc_write(c, WM8960_RESET, 0) | 86 | #define wm8960_reset(c) snd_soc_write(c, WM8960_RESET, 0) |
85 | 87 | ||
86 | /* enumerated controls */ | 88 | /* enumerated controls */ |
87 | static const char *wm8960_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"}; | ||
88 | static const char *wm8960_polarity[] = {"No Inversion", "Left Inverted", | 89 | static const char *wm8960_polarity[] = {"No Inversion", "Left Inverted", |
89 | "Right Inverted", "Stereo Inversion"}; | 90 | "Right Inverted", "Stereo Inversion"}; |
90 | static const char *wm8960_3d_upper_cutoff[] = {"High", "Low"}; | 91 | static const char *wm8960_3d_upper_cutoff[] = {"High", "Low"}; |
@@ -93,7 +94,6 @@ static const char *wm8960_alcfunc[] = {"Off", "Right", "Left", "Stereo"}; | |||
93 | static const char *wm8960_alcmode[] = {"ALC", "Limiter"}; | 94 | static const char *wm8960_alcmode[] = {"ALC", "Limiter"}; |
94 | 95 | ||
95 | static const struct soc_enum wm8960_enum[] = { | 96 | static const struct soc_enum wm8960_enum[] = { |
96 | SOC_ENUM_SINGLE(WM8960_DACCTL1, 1, 4, wm8960_deemph), | ||
97 | SOC_ENUM_SINGLE(WM8960_DACCTL1, 5, 4, wm8960_polarity), | 97 | SOC_ENUM_SINGLE(WM8960_DACCTL1, 5, 4, wm8960_polarity), |
98 | SOC_ENUM_SINGLE(WM8960_DACCTL2, 5, 4, wm8960_polarity), | 98 | SOC_ENUM_SINGLE(WM8960_DACCTL2, 5, 4, wm8960_polarity), |
99 | SOC_ENUM_SINGLE(WM8960_3D, 6, 2, wm8960_3d_upper_cutoff), | 99 | SOC_ENUM_SINGLE(WM8960_3D, 6, 2, wm8960_3d_upper_cutoff), |
@@ -102,6 +102,59 @@ static const struct soc_enum wm8960_enum[] = { | |||
102 | SOC_ENUM_SINGLE(WM8960_ALC3, 8, 2, wm8960_alcmode), | 102 | SOC_ENUM_SINGLE(WM8960_ALC3, 8, 2, wm8960_alcmode), |
103 | }; | 103 | }; |
104 | 104 | ||
105 | static const int deemph_settings[] = { 0, 32000, 44100, 48000 }; | ||
106 | |||
107 | static int wm8960_set_deemph(struct snd_soc_codec *codec) | ||
108 | { | ||
109 | struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); | ||
110 | int val, i, best; | ||
111 | |||
112 | /* If we're using deemphasis select the nearest available sample | ||
113 | * rate. | ||
114 | */ | ||
115 | if (wm8960->deemph) { | ||
116 | best = 1; | ||
117 | for (i = 2; i < ARRAY_SIZE(deemph_settings); i++) { | ||
118 | if (abs(deemph_settings[i] - wm8960->playback_fs) < | ||
119 | abs(deemph_settings[best] - wm8960->playback_fs)) | ||
120 | best = i; | ||
121 | } | ||
122 | |||
123 | val = best << 1; | ||
124 | } else { | ||
125 | val = 0; | ||
126 | } | ||
127 | |||
128 | dev_dbg(codec->dev, "Set deemphasis %d\n", val); | ||
129 | |||
130 | return snd_soc_update_bits(codec, WM8960_DACCTL1, | ||
131 | 0x6, val); | ||
132 | } | ||
133 | |||
134 | static int wm8960_get_deemph(struct snd_kcontrol *kcontrol, | ||
135 | struct snd_ctl_elem_value *ucontrol) | ||
136 | { | ||
137 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
138 | struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); | ||
139 | |||
140 | return wm8960->deemph; | ||
141 | } | ||
142 | |||
143 | static int wm8960_put_deemph(struct snd_kcontrol *kcontrol, | ||
144 | struct snd_ctl_elem_value *ucontrol) | ||
145 | { | ||
146 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
147 | struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); | ||
148 | int deemph = ucontrol->value.enumerated.item[0]; | ||
149 | |||
150 | if (deemph > 1) | ||
151 | return -EINVAL; | ||
152 | |||
153 | wm8960->deemph = deemph; | ||
154 | |||
155 | return wm8960_set_deemph(codec); | ||
156 | } | ||
157 | |||
105 | static const DECLARE_TLV_DB_SCALE(adc_tlv, -9700, 50, 0); | 158 | static const DECLARE_TLV_DB_SCALE(adc_tlv, -9700, 50, 0); |
106 | static const DECLARE_TLV_DB_SCALE(dac_tlv, -12700, 50, 1); | 159 | static const DECLARE_TLV_DB_SCALE(dac_tlv, -12700, 50, 1); |
107 | static const DECLARE_TLV_DB_SCALE(bypass_tlv, -2100, 300, 0); | 160 | static const DECLARE_TLV_DB_SCALE(bypass_tlv, -2100, 300, 0); |
@@ -131,23 +184,24 @@ SOC_SINGLE("Speaker DC Volume", WM8960_CLASSD3, 3, 5, 0), | |||
131 | SOC_SINGLE("Speaker AC Volume", WM8960_CLASSD3, 0, 5, 0), | 184 | SOC_SINGLE("Speaker AC Volume", WM8960_CLASSD3, 0, 5, 0), |
132 | 185 | ||
133 | SOC_SINGLE("PCM Playback -6dB Switch", WM8960_DACCTL1, 7, 1, 0), | 186 | SOC_SINGLE("PCM Playback -6dB Switch", WM8960_DACCTL1, 7, 1, 0), |
134 | SOC_ENUM("ADC Polarity", wm8960_enum[1]), | 187 | SOC_ENUM("ADC Polarity", wm8960_enum[0]), |
135 | SOC_ENUM("Playback De-emphasis", wm8960_enum[0]), | ||
136 | SOC_SINGLE("ADC High Pass Filter Switch", WM8960_DACCTL1, 0, 1, 0), | 188 | SOC_SINGLE("ADC High Pass Filter Switch", WM8960_DACCTL1, 0, 1, 0), |
137 | 189 | ||
138 | SOC_ENUM("DAC Polarity", wm8960_enum[2]), | 190 | SOC_ENUM("DAC Polarity", wm8960_enum[2]), |
191 | SOC_SINGLE_BOOL_EXT("DAC Deemphasis Switch", 0, | ||
192 | wm8960_get_deemph, wm8960_put_deemph), | ||
139 | 193 | ||
140 | SOC_ENUM("3D Filter Upper Cut-Off", wm8960_enum[3]), | 194 | SOC_ENUM("3D Filter Upper Cut-Off", wm8960_enum[2]), |
141 | SOC_ENUM("3D Filter Lower Cut-Off", wm8960_enum[4]), | 195 | SOC_ENUM("3D Filter Lower Cut-Off", wm8960_enum[3]), |
142 | SOC_SINGLE("3D Volume", WM8960_3D, 1, 15, 0), | 196 | SOC_SINGLE("3D Volume", WM8960_3D, 1, 15, 0), |
143 | SOC_SINGLE("3D Switch", WM8960_3D, 0, 1, 0), | 197 | SOC_SINGLE("3D Switch", WM8960_3D, 0, 1, 0), |
144 | 198 | ||
145 | SOC_ENUM("ALC Function", wm8960_enum[5]), | 199 | SOC_ENUM("ALC Function", wm8960_enum[4]), |
146 | SOC_SINGLE("ALC Max Gain", WM8960_ALC1, 4, 7, 0), | 200 | SOC_SINGLE("ALC Max Gain", WM8960_ALC1, 4, 7, 0), |
147 | SOC_SINGLE("ALC Target", WM8960_ALC1, 0, 15, 1), | 201 | SOC_SINGLE("ALC Target", WM8960_ALC1, 0, 15, 1), |
148 | SOC_SINGLE("ALC Min Gain", WM8960_ALC2, 4, 7, 0), | 202 | SOC_SINGLE("ALC Min Gain", WM8960_ALC2, 4, 7, 0), |
149 | SOC_SINGLE("ALC Hold Time", WM8960_ALC2, 0, 15, 0), | 203 | SOC_SINGLE("ALC Hold Time", WM8960_ALC2, 0, 15, 0), |
150 | SOC_ENUM("ALC Mode", wm8960_enum[6]), | 204 | SOC_ENUM("ALC Mode", wm8960_enum[5]), |
151 | SOC_SINGLE("ALC Decay", WM8960_ALC3, 4, 15, 0), | 205 | SOC_SINGLE("ALC Decay", WM8960_ALC3, 4, 15, 0), |
152 | SOC_SINGLE("ALC Attack", WM8960_ALC3, 0, 15, 0), | 206 | SOC_SINGLE("ALC Attack", WM8960_ALC3, 0, 15, 0), |
153 | 207 | ||
@@ -433,6 +487,21 @@ static int wm8960_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
433 | return 0; | 487 | return 0; |
434 | } | 488 | } |
435 | 489 | ||
490 | static struct { | ||
491 | int rate; | ||
492 | unsigned int val; | ||
493 | } alc_rates[] = { | ||
494 | { 48000, 0 }, | ||
495 | { 44100, 0 }, | ||
496 | { 32000, 1 }, | ||
497 | { 22050, 2 }, | ||
498 | { 24000, 2 }, | ||
499 | { 16000, 3 }, | ||
500 | { 11250, 4 }, | ||
501 | { 12000, 4 }, | ||
502 | { 8000, 5 }, | ||
503 | }; | ||
504 | |||
436 | static int wm8960_hw_params(struct snd_pcm_substream *substream, | 505 | static int wm8960_hw_params(struct snd_pcm_substream *substream, |
437 | struct snd_pcm_hw_params *params, | 506 | struct snd_pcm_hw_params *params, |
438 | struct snd_soc_dai *dai) | 507 | struct snd_soc_dai *dai) |
@@ -440,7 +509,9 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream, | |||
440 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 509 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
441 | struct snd_soc_device *socdev = rtd->socdev; | 510 | struct snd_soc_device *socdev = rtd->socdev; |
442 | struct snd_soc_codec *codec = socdev->card->codec; | 511 | struct snd_soc_codec *codec = socdev->card->codec; |
512 | struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); | ||
443 | u16 iface = snd_soc_read(codec, WM8960_IFACE1) & 0xfff3; | 513 | u16 iface = snd_soc_read(codec, WM8960_IFACE1) & 0xfff3; |
514 | int i; | ||
444 | 515 | ||
445 | /* bit size */ | 516 | /* bit size */ |
446 | switch (params_format(params)) { | 517 | switch (params_format(params)) { |
@@ -454,6 +525,18 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream, | |||
454 | break; | 525 | break; |
455 | } | 526 | } |
456 | 527 | ||
528 | /* Update filters for the new rate */ | ||
529 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
530 | wm8960->playback_fs = params_rate(params); | ||
531 | wm8960_set_deemph(codec); | ||
532 | } else { | ||
533 | for (i = 0; i < ARRAY_SIZE(alc_rates); i++) | ||
534 | if (alc_rates[i].rate == params_rate(params)) | ||
535 | snd_soc_update_bits(codec, | ||
536 | WM8960_ADDCTL3, 0x7, | ||
537 | alc_rates[i].val); | ||
538 | } | ||
539 | |||
457 | /* set iface */ | 540 | /* set iface */ |
458 | snd_soc_write(codec, WM8960_IFACE1, iface); | 541 | snd_soc_write(codec, WM8960_IFACE1, iface); |
459 | return 0; | 542 | return 0; |
diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c index 5b9a756242f1..2549d3a297ab 100644 --- a/sound/soc/codecs/wm8961.c +++ b/sound/soc/codecs/wm8961.c | |||
@@ -1102,7 +1102,7 @@ static int wm8961_register(struct wm8961_priv *wm8961) | |||
1102 | ret = wm8961_reset(codec); | 1102 | ret = wm8961_reset(codec); |
1103 | if (ret < 0) { | 1103 | if (ret < 0) { |
1104 | dev_err(codec->dev, "Failed to issue reset\n"); | 1104 | dev_err(codec->dev, "Failed to issue reset\n"); |
1105 | return ret; | 1105 | goto err; |
1106 | } | 1106 | } |
1107 | 1107 | ||
1108 | /* Enable class W */ | 1108 | /* Enable class W */ |
@@ -1147,18 +1147,19 @@ static int wm8961_register(struct wm8961_priv *wm8961) | |||
1147 | ret = snd_soc_register_codec(codec); | 1147 | ret = snd_soc_register_codec(codec); |
1148 | if (ret != 0) { | 1148 | if (ret != 0) { |
1149 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); | 1149 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); |
1150 | return ret; | 1150 | goto err; |
1151 | } | 1151 | } |
1152 | 1152 | ||
1153 | ret = snd_soc_register_dai(&wm8961_dai); | 1153 | ret = snd_soc_register_dai(&wm8961_dai); |
1154 | if (ret != 0) { | 1154 | if (ret != 0) { |
1155 | dev_err(codec->dev, "Failed to register DAI: %d\n", ret); | 1155 | dev_err(codec->dev, "Failed to register DAI: %d\n", ret); |
1156 | snd_soc_unregister_codec(codec); | 1156 | goto err_codec; |
1157 | return ret; | ||
1158 | } | 1157 | } |
1159 | 1158 | ||
1160 | return 0; | 1159 | return 0; |
1161 | 1160 | ||
1161 | err_codec: | ||
1162 | snd_soc_unregister_codec(codec); | ||
1162 | err: | 1163 | err: |
1163 | kfree(wm8961); | 1164 | kfree(wm8961); |
1164 | return ret; | 1165 | return ret; |
diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c index a2c4b2f37cca..1468fe10cbbe 100644 --- a/sound/soc/codecs/wm8974.c +++ b/sound/soc/codecs/wm8974.c | |||
@@ -670,7 +670,8 @@ static __devinit int wm8974_register(struct wm8974_priv *wm8974) | |||
670 | 670 | ||
671 | if (wm8974_codec) { | 671 | if (wm8974_codec) { |
672 | dev_err(codec->dev, "Another WM8974 is registered\n"); | 672 | dev_err(codec->dev, "Another WM8974 is registered\n"); |
673 | return -EINVAL; | 673 | ret = -EINVAL; |
674 | goto err; | ||
674 | } | 675 | } |
675 | 676 | ||
676 | mutex_init(&codec->mutex); | 677 | mutex_init(&codec->mutex); |
diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c index 51d5f433215c..8a1ad778e7e3 100644 --- a/sound/soc/codecs/wm8978.c +++ b/sound/soc/codecs/wm8978.c | |||
@@ -1076,7 +1076,6 @@ static __devinit int wm8978_register(struct wm8978_priv *wm8978) | |||
1076 | err_codec: | 1076 | err_codec: |
1077 | snd_soc_unregister_codec(codec); | 1077 | snd_soc_unregister_codec(codec); |
1078 | err: | 1078 | err: |
1079 | kfree(wm8978); | ||
1080 | return ret; | 1079 | return ret; |
1081 | } | 1080 | } |
1082 | 1081 | ||
@@ -1085,13 +1084,13 @@ static __devexit void wm8978_unregister(struct wm8978_priv *wm8978) | |||
1085 | wm8978_set_bias_level(&wm8978->codec, SND_SOC_BIAS_OFF); | 1084 | wm8978_set_bias_level(&wm8978->codec, SND_SOC_BIAS_OFF); |
1086 | snd_soc_unregister_dai(&wm8978_dai); | 1085 | snd_soc_unregister_dai(&wm8978_dai); |
1087 | snd_soc_unregister_codec(&wm8978->codec); | 1086 | snd_soc_unregister_codec(&wm8978->codec); |
1088 | kfree(wm8978); | ||
1089 | wm8978_codec = NULL; | 1087 | wm8978_codec = NULL; |
1090 | } | 1088 | } |
1091 | 1089 | ||
1092 | static __devinit int wm8978_i2c_probe(struct i2c_client *i2c, | 1090 | static __devinit int wm8978_i2c_probe(struct i2c_client *i2c, |
1093 | const struct i2c_device_id *id) | 1091 | const struct i2c_device_id *id) |
1094 | { | 1092 | { |
1093 | int ret; | ||
1095 | struct wm8978_priv *wm8978; | 1094 | struct wm8978_priv *wm8978; |
1096 | struct snd_soc_codec *codec; | 1095 | struct snd_soc_codec *codec; |
1097 | 1096 | ||
@@ -1107,13 +1106,18 @@ static __devinit int wm8978_i2c_probe(struct i2c_client *i2c, | |||
1107 | 1106 | ||
1108 | codec->dev = &i2c->dev; | 1107 | codec->dev = &i2c->dev; |
1109 | 1108 | ||
1110 | return wm8978_register(wm8978); | 1109 | ret = wm8978_register(wm8978); |
1110 | if (ret < 0) | ||
1111 | kfree(wm8978); | ||
1112 | |||
1113 | return ret; | ||
1111 | } | 1114 | } |
1112 | 1115 | ||
1113 | static __devexit int wm8978_i2c_remove(struct i2c_client *client) | 1116 | static __devexit int wm8978_i2c_remove(struct i2c_client *client) |
1114 | { | 1117 | { |
1115 | struct wm8978_priv *wm8978 = i2c_get_clientdata(client); | 1118 | struct wm8978_priv *wm8978 = i2c_get_clientdata(client); |
1116 | wm8978_unregister(wm8978); | 1119 | wm8978_unregister(wm8978); |
1120 | kfree(wm8978); | ||
1117 | return 0; | 1121 | return 0; |
1118 | } | 1122 | } |
1119 | 1123 | ||
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index c018772cc430..dd8d909788c1 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c | |||
@@ -30,8 +30,6 @@ | |||
30 | 30 | ||
31 | #include "wm8990.h" | 31 | #include "wm8990.h" |
32 | 32 | ||
33 | #define WM8990_VERSION "0.2" | ||
34 | |||
35 | /* codec private data */ | 33 | /* codec private data */ |
36 | struct wm8990_priv { | 34 | struct wm8990_priv { |
37 | unsigned int sysclk; | 35 | unsigned int sysclk; |
@@ -1511,8 +1509,6 @@ static int wm8990_probe(struct platform_device *pdev) | |||
1511 | struct wm8990_priv *wm8990; | 1509 | struct wm8990_priv *wm8990; |
1512 | int ret; | 1510 | int ret; |
1513 | 1511 | ||
1514 | pr_info("WM8990 Audio Codec %s\n", WM8990_VERSION); | ||
1515 | |||
1516 | setup = socdev->codec_data; | 1512 | setup = socdev->codec_data; |
1517 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | 1513 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); |
1518 | if (codec == NULL) | 1514 | if (codec == NULL) |
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index e84a1177f350..522249d5c2b4 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c | |||
@@ -95,6 +95,7 @@ struct wm8994_priv { | |||
95 | 95 | ||
96 | struct wm8994_micdet micdet[2]; | 96 | struct wm8994_micdet micdet[2]; |
97 | 97 | ||
98 | int revision; | ||
98 | struct wm8994_pdata *pdata; | 99 | struct wm8994_pdata *pdata; |
99 | }; | 100 | }; |
100 | 101 | ||
@@ -1677,6 +1678,26 @@ static struct { | |||
1677 | 1678 | ||
1678 | static int wm8994_readable(unsigned int reg) | 1679 | static int wm8994_readable(unsigned int reg) |
1679 | { | 1680 | { |
1681 | switch (reg) { | ||
1682 | case WM8994_GPIO_1: | ||
1683 | case WM8994_GPIO_2: | ||
1684 | case WM8994_GPIO_3: | ||
1685 | case WM8994_GPIO_4: | ||
1686 | case WM8994_GPIO_5: | ||
1687 | case WM8994_GPIO_6: | ||
1688 | case WM8994_GPIO_7: | ||
1689 | case WM8994_GPIO_8: | ||
1690 | case WM8994_GPIO_9: | ||
1691 | case WM8994_GPIO_10: | ||
1692 | case WM8994_GPIO_11: | ||
1693 | case WM8994_INTERRUPT_STATUS_1: | ||
1694 | case WM8994_INTERRUPT_STATUS_2: | ||
1695 | case WM8994_INTERRUPT_RAW_STATUS_2: | ||
1696 | return 1; | ||
1697 | default: | ||
1698 | break; | ||
1699 | } | ||
1700 | |||
1680 | if (reg >= ARRAY_SIZE(access_masks)) | 1701 | if (reg >= ARRAY_SIZE(access_masks)) |
1681 | return 0; | 1702 | return 0; |
1682 | return access_masks[reg].readable != 0; | 1703 | return access_masks[reg].readable != 0; |
@@ -2341,6 +2362,20 @@ SOC_DAPM_SINGLE("AIF2 Switch", WM8994_AIF1_ADC1_RIGHT_MIXER_ROUTING, | |||
2341 | 0, 1, 0), | 2362 | 0, 1, 0), |
2342 | }; | 2363 | }; |
2343 | 2364 | ||
2365 | static const struct snd_kcontrol_new aif1adc2l_mix[] = { | ||
2366 | SOC_DAPM_SINGLE("DMIC Switch", WM8994_AIF1_ADC2_LEFT_MIXER_ROUTING, | ||
2367 | 1, 1, 0), | ||
2368 | SOC_DAPM_SINGLE("AIF2 Switch", WM8994_AIF1_ADC2_LEFT_MIXER_ROUTING, | ||
2369 | 0, 1, 0), | ||
2370 | }; | ||
2371 | |||
2372 | static const struct snd_kcontrol_new aif1adc2r_mix[] = { | ||
2373 | SOC_DAPM_SINGLE("DMIC Switch", WM8994_AIF1_ADC2_RIGHT_MIXER_ROUTING, | ||
2374 | 1, 1, 0), | ||
2375 | SOC_DAPM_SINGLE("AIF2 Switch", WM8994_AIF1_ADC2_RIGHT_MIXER_ROUTING, | ||
2376 | 0, 1, 0), | ||
2377 | }; | ||
2378 | |||
2344 | static const struct snd_kcontrol_new aif2dac2l_mix[] = { | 2379 | static const struct snd_kcontrol_new aif2dac2l_mix[] = { |
2345 | SOC_DAPM_SINGLE("Right Sidetone Switch", WM8994_DAC2_LEFT_MIXER_ROUTING, | 2380 | SOC_DAPM_SINGLE("Right Sidetone Switch", WM8994_DAC2_LEFT_MIXER_ROUTING, |
2346 | 5, 1, 0), | 2381 | 5, 1, 0), |
@@ -2472,6 +2507,7 @@ static const struct snd_kcontrol_new aif3adc_mux = | |||
2472 | static const struct snd_soc_dapm_widget wm8994_dapm_widgets[] = { | 2507 | static const struct snd_soc_dapm_widget wm8994_dapm_widgets[] = { |
2473 | SND_SOC_DAPM_INPUT("DMIC1DAT"), | 2508 | SND_SOC_DAPM_INPUT("DMIC1DAT"), |
2474 | SND_SOC_DAPM_INPUT("DMIC2DAT"), | 2509 | SND_SOC_DAPM_INPUT("DMIC2DAT"), |
2510 | SND_SOC_DAPM_INPUT("Clock"), | ||
2475 | 2511 | ||
2476 | SND_SOC_DAPM_SUPPLY("CLK_SYS", SND_SOC_NOPM, 0, 0, clk_sys_event, | 2512 | SND_SOC_DAPM_SUPPLY("CLK_SYS", SND_SOC_NOPM, 0, 0, clk_sys_event, |
2477 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), | 2513 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), |
@@ -2506,6 +2542,11 @@ SND_SOC_DAPM_MIXER("AIF1ADC1L Mixer", SND_SOC_NOPM, 0, 0, | |||
2506 | SND_SOC_DAPM_MIXER("AIF1ADC1R Mixer", SND_SOC_NOPM, 0, 0, | 2542 | SND_SOC_DAPM_MIXER("AIF1ADC1R Mixer", SND_SOC_NOPM, 0, 0, |
2507 | aif1adc1r_mix, ARRAY_SIZE(aif1adc1r_mix)), | 2543 | aif1adc1r_mix, ARRAY_SIZE(aif1adc1r_mix)), |
2508 | 2544 | ||
2545 | SND_SOC_DAPM_MIXER("AIF1ADC2L Mixer", SND_SOC_NOPM, 0, 0, | ||
2546 | aif1adc2l_mix, ARRAY_SIZE(aif1adc2l_mix)), | ||
2547 | SND_SOC_DAPM_MIXER("AIF1ADC2R Mixer", SND_SOC_NOPM, 0, 0, | ||
2548 | aif1adc2r_mix, ARRAY_SIZE(aif1adc2r_mix)), | ||
2549 | |||
2509 | SND_SOC_DAPM_MIXER("AIF2DAC2L Mixer", SND_SOC_NOPM, 0, 0, | 2550 | SND_SOC_DAPM_MIXER("AIF2DAC2L Mixer", SND_SOC_NOPM, 0, 0, |
2510 | aif2dac2l_mix, ARRAY_SIZE(aif2dac2l_mix)), | 2551 | aif2dac2l_mix, ARRAY_SIZE(aif2dac2l_mix)), |
2511 | SND_SOC_DAPM_MIXER("AIF2DAC2R Mixer", SND_SOC_NOPM, 0, 0, | 2552 | SND_SOC_DAPM_MIXER("AIF2DAC2R Mixer", SND_SOC_NOPM, 0, 0, |
@@ -2668,6 +2709,14 @@ static const struct snd_soc_dapm_route intercon[] = { | |||
2668 | { "AIF1ADC1R Mixer", "ADC/DMIC Switch", "ADCR Mux" }, | 2709 | { "AIF1ADC1R Mixer", "ADC/DMIC Switch", "ADCR Mux" }, |
2669 | { "AIF1ADC1R Mixer", "AIF2 Switch", "AIF2DACR" }, | 2710 | { "AIF1ADC1R Mixer", "AIF2 Switch", "AIF2DACR" }, |
2670 | 2711 | ||
2712 | { "AIF1ADC2L", NULL, "AIF1ADC2L Mixer" }, | ||
2713 | { "AIF1ADC2L Mixer", "DMIC Switch", "DMIC2L" }, | ||
2714 | { "AIF1ADC2L Mixer", "AIF2 Switch", "AIF2DACL" }, | ||
2715 | |||
2716 | { "AIF1ADC2R", NULL, "AIF1ADC2R Mixer" }, | ||
2717 | { "AIF1ADC2R Mixer", "DMIC Switch", "DMIC2R" }, | ||
2718 | { "AIF1ADC2R Mixer", "AIF2 Switch", "AIF2DACR" }, | ||
2719 | |||
2671 | /* Pin level routing for AIF3 */ | 2720 | /* Pin level routing for AIF3 */ |
2672 | { "AIF1DAC1L", NULL, "AIF1DAC Mux" }, | 2721 | { "AIF1DAC1L", NULL, "AIF1DAC Mux" }, |
2673 | { "AIF1DAC1R", NULL, "AIF1DAC Mux" }, | 2722 | { "AIF1DAC1R", NULL, "AIF1DAC Mux" }, |
@@ -2946,11 +2995,14 @@ static int wm8994_set_fll(struct snd_soc_dai *dai, int id, int src, | |||
2946 | return 0; | 2995 | return 0; |
2947 | } | 2996 | } |
2948 | 2997 | ||
2998 | static int opclk_divs[] = { 10, 20, 30, 40, 55, 60, 80, 120, 160 }; | ||
2999 | |||
2949 | static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai, | 3000 | static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai, |
2950 | int clk_id, unsigned int freq, int dir) | 3001 | int clk_id, unsigned int freq, int dir) |
2951 | { | 3002 | { |
2952 | struct snd_soc_codec *codec = dai->codec; | 3003 | struct snd_soc_codec *codec = dai->codec; |
2953 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); | 3004 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); |
3005 | int i; | ||
2954 | 3006 | ||
2955 | switch (dai->id) { | 3007 | switch (dai->id) { |
2956 | case 1: | 3008 | case 1: |
@@ -2988,6 +3040,25 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai, | |||
2988 | dev_dbg(dai->dev, "AIF%d using FLL2\n", dai->id); | 3040 | dev_dbg(dai->dev, "AIF%d using FLL2\n", dai->id); |
2989 | break; | 3041 | break; |
2990 | 3042 | ||
3043 | case WM8994_SYSCLK_OPCLK: | ||
3044 | /* Special case - a division (times 10) is given and | ||
3045 | * no effect on main clocking. | ||
3046 | */ | ||
3047 | if (freq) { | ||
3048 | for (i = 0; i < ARRAY_SIZE(opclk_divs); i++) | ||
3049 | if (opclk_divs[i] == freq) | ||
3050 | break; | ||
3051 | if (i == ARRAY_SIZE(opclk_divs)) | ||
3052 | return -EINVAL; | ||
3053 | snd_soc_update_bits(codec, WM8994_CLOCKING_2, | ||
3054 | WM8994_OPCLK_DIV_MASK, i); | ||
3055 | snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_2, | ||
3056 | WM8994_OPCLK_ENA, WM8994_OPCLK_ENA); | ||
3057 | } else { | ||
3058 | snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_2, | ||
3059 | WM8994_OPCLK_ENA, 0); | ||
3060 | } | ||
3061 | |||
2991 | default: | 3062 | default: |
2992 | return -EINVAL; | 3063 | return -EINVAL; |
2993 | } | 3064 | } |
@@ -3000,6 +3071,8 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai, | |||
3000 | static int wm8994_set_bias_level(struct snd_soc_codec *codec, | 3071 | static int wm8994_set_bias_level(struct snd_soc_codec *codec, |
3001 | enum snd_soc_bias_level level) | 3072 | enum snd_soc_bias_level level) |
3002 | { | 3073 | { |
3074 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); | ||
3075 | |||
3003 | switch (level) { | 3076 | switch (level) { |
3004 | case SND_SOC_BIAS_ON: | 3077 | case SND_SOC_BIAS_ON: |
3005 | break; | 3078 | break; |
@@ -3012,11 +3085,16 @@ static int wm8994_set_bias_level(struct snd_soc_codec *codec, | |||
3012 | 3085 | ||
3013 | case SND_SOC_BIAS_STANDBY: | 3086 | case SND_SOC_BIAS_STANDBY: |
3014 | if (codec->bias_level == SND_SOC_BIAS_OFF) { | 3087 | if (codec->bias_level == SND_SOC_BIAS_OFF) { |
3015 | /* Tweak DC servo configuration for improved | 3088 | /* Tweak DC servo and DSP configuration for |
3016 | * performance. */ | 3089 | * improved performance. */ |
3017 | snd_soc_write(codec, 0x102, 0x3); | 3090 | if (wm8994->revision < 4) { |
3018 | snd_soc_write(codec, 0x56, 0x3); | 3091 | /* Tweak DC servo and DSP configuration for |
3019 | snd_soc_write(codec, 0x102, 0); | 3092 | * improved performance. */ |
3093 | snd_soc_write(codec, 0x102, 0x3); | ||
3094 | snd_soc_write(codec, 0x56, 0x3); | ||
3095 | snd_soc_write(codec, 0x817, 0); | ||
3096 | snd_soc_write(codec, 0x102, 0); | ||
3097 | } | ||
3020 | 3098 | ||
3021 | /* Discharge LINEOUT1 & 2 */ | 3099 | /* Discharge LINEOUT1 & 2 */ |
3022 | snd_soc_update_bits(codec, WM8994_ANTIPOP_1, | 3100 | snd_soc_update_bits(codec, WM8994_ANTIPOP_1, |
@@ -3849,7 +3927,6 @@ static int wm8994_codec_probe(struct platform_device *pdev) | |||
3849 | struct wm8994_priv *wm8994; | 3927 | struct wm8994_priv *wm8994; |
3850 | struct snd_soc_codec *codec; | 3928 | struct snd_soc_codec *codec; |
3851 | int i; | 3929 | int i; |
3852 | u16 rev; | ||
3853 | 3930 | ||
3854 | if (wm8994_codec) { | 3931 | if (wm8994_codec) { |
3855 | dev_err(&pdev->dev, "Another WM8994 is registered\n"); | 3932 | dev_err(&pdev->dev, "Another WM8994 is registered\n"); |
@@ -3903,8 +3980,8 @@ static int wm8994_codec_probe(struct platform_device *pdev) | |||
3903 | wm8994->reg_cache[i] = 0; | 3980 | wm8994->reg_cache[i] = 0; |
3904 | 3981 | ||
3905 | /* Set revision-specific configuration */ | 3982 | /* Set revision-specific configuration */ |
3906 | rev = snd_soc_read(codec, WM8994_CHIP_REVISION); | 3983 | wm8994->revision = snd_soc_read(codec, WM8994_CHIP_REVISION); |
3907 | switch (rev) { | 3984 | switch (wm8994->revision) { |
3908 | case 2: | 3985 | case 2: |
3909 | case 3: | 3986 | case 3: |
3910 | wm8994->hubs.dcs_codes = -5; | 3987 | wm8994->hubs.dcs_codes = -5; |
@@ -4004,6 +4081,11 @@ static int wm8994_codec_probe(struct platform_device *pdev) | |||
4004 | 1 << WM8994_AIF2DAC_3D_GAIN_SHIFT, | 4081 | 1 << WM8994_AIF2DAC_3D_GAIN_SHIFT, |
4005 | 1 << WM8994_AIF2DAC_3D_GAIN_SHIFT); | 4082 | 1 << WM8994_AIF2DAC_3D_GAIN_SHIFT); |
4006 | 4083 | ||
4084 | /* Unconditionally enable AIF1 ADC TDM mode; it only affects | ||
4085 | * behaviour on idle TDM clock cycles. */ | ||
4086 | snd_soc_update_bits(codec, WM8994_AIF1_CONTROL_1, | ||
4087 | WM8994_AIF1ADC_TDM, WM8994_AIF1ADC_TDM); | ||
4088 | |||
4007 | wm8994_update_class_w(codec); | 4089 | wm8994_update_class_w(codec); |
4008 | 4090 | ||
4009 | ret = snd_soc_register_codec(codec); | 4091 | ret = snd_soc_register_codec(codec); |
diff --git a/sound/soc/codecs/wm8994.h b/sound/soc/codecs/wm8994.h index 7072dc539354..2e0ca67a8df7 100644 --- a/sound/soc/codecs/wm8994.h +++ b/sound/soc/codecs/wm8994.h | |||
@@ -20,6 +20,9 @@ extern struct snd_soc_dai wm8994_dai[]; | |||
20 | #define WM8994_SYSCLK_FLL1 3 | 20 | #define WM8994_SYSCLK_FLL1 3 |
21 | #define WM8994_SYSCLK_FLL2 4 | 21 | #define WM8994_SYSCLK_FLL2 4 |
22 | 22 | ||
23 | /* OPCLK is also configured with set_dai_sysclk, specify division*10 as rate. */ | ||
24 | #define WM8994_SYSCLK_OPCLK 5 | ||
25 | |||
23 | #define WM8994_FLL1 1 | 26 | #define WM8994_FLL1 1 |
24 | #define WM8994_FLL2 2 | 27 | #define WM8994_FLL2 2 |
25 | 28 | ||
diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c index 13186fb4dcb4..76b37ff6c264 100644 --- a/sound/soc/codecs/wm9081.c +++ b/sound/soc/codecs/wm9081.c | |||
@@ -1356,7 +1356,7 @@ static int wm9081_register(struct wm9081_priv *wm9081, | |||
1356 | ret = snd_soc_codec_set_cache_io(codec, 8, 16, control); | 1356 | ret = snd_soc_codec_set_cache_io(codec, 8, 16, control); |
1357 | if (ret != 0) { | 1357 | if (ret != 0) { |
1358 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); | 1358 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); |
1359 | return ret; | 1359 | goto err; |
1360 | } | 1360 | } |
1361 | 1361 | ||
1362 | reg = snd_soc_read(codec, WM9081_SOFTWARE_RESET); | 1362 | reg = snd_soc_read(codec, WM9081_SOFTWARE_RESET); |
@@ -1369,7 +1369,7 @@ static int wm9081_register(struct wm9081_priv *wm9081, | |||
1369 | ret = wm9081_reset(codec); | 1369 | ret = wm9081_reset(codec); |
1370 | if (ret < 0) { | 1370 | if (ret < 0) { |
1371 | dev_err(codec->dev, "Failed to issue reset\n"); | 1371 | dev_err(codec->dev, "Failed to issue reset\n"); |
1372 | return ret; | 1372 | goto err; |
1373 | } | 1373 | } |
1374 | 1374 | ||
1375 | wm9081_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 1375 | wm9081_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
@@ -1388,18 +1388,19 @@ static int wm9081_register(struct wm9081_priv *wm9081, | |||
1388 | ret = snd_soc_register_codec(codec); | 1388 | ret = snd_soc_register_codec(codec); |
1389 | if (ret != 0) { | 1389 | if (ret != 0) { |
1390 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); | 1390 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); |
1391 | return ret; | 1391 | goto err; |
1392 | } | 1392 | } |
1393 | 1393 | ||
1394 | ret = snd_soc_register_dai(&wm9081_dai); | 1394 | ret = snd_soc_register_dai(&wm9081_dai); |
1395 | if (ret != 0) { | 1395 | if (ret != 0) { |
1396 | dev_err(codec->dev, "Failed to register DAI: %d\n", ret); | 1396 | dev_err(codec->dev, "Failed to register DAI: %d\n", ret); |
1397 | snd_soc_unregister_codec(codec); | 1397 | goto err_codec; |
1398 | return ret; | ||
1399 | } | 1398 | } |
1400 | 1399 | ||
1401 | return 0; | 1400 | return 0; |
1402 | 1401 | ||
1402 | err_codec: | ||
1403 | snd_soc_unregister_codec(codec); | ||
1403 | err: | 1404 | err: |
1404 | kfree(wm9081); | 1405 | kfree(wm9081); |
1405 | return ret; | 1406 | return ret; |
diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c index 16f1a57da08a..2cb81538cd91 100644 --- a/sound/soc/codecs/wm_hubs.c +++ b/sound/soc/codecs/wm_hubs.c | |||
@@ -410,6 +410,8 @@ static int hp_event(struct snd_soc_dapm_widget *w, | |||
410 | WM8993_HPOUT1L_DLY | | 410 | WM8993_HPOUT1L_DLY | |
411 | WM8993_HPOUT1R_DLY, 0); | 411 | WM8993_HPOUT1R_DLY, 0); |
412 | 412 | ||
413 | snd_soc_write(codec, WM8993_DC_SERVO_0, 0); | ||
414 | |||
413 | snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1, | 415 | snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1, |
414 | WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA, | 416 | WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA, |
415 | 0); | 417 | 0); |
diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index adadcd3aa1b1..9e8932abf158 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <mach/asp.h> | 26 | #include <mach/asp.h> |
27 | 27 | ||
28 | #include "davinci-pcm.h" | 28 | #include "davinci-pcm.h" |
29 | #include "davinci-i2s.h" | ||
29 | 30 | ||
30 | 31 | ||
31 | /* | 32 | /* |
@@ -68,16 +69,21 @@ | |||
68 | #define DAVINCI_MCBSP_RCR_RDATDLY(v) ((v) << 16) | 69 | #define DAVINCI_MCBSP_RCR_RDATDLY(v) ((v) << 16) |
69 | #define DAVINCI_MCBSP_RCR_RFIG (1 << 18) | 70 | #define DAVINCI_MCBSP_RCR_RFIG (1 << 18) |
70 | #define DAVINCI_MCBSP_RCR_RWDLEN2(v) ((v) << 21) | 71 | #define DAVINCI_MCBSP_RCR_RWDLEN2(v) ((v) << 21) |
72 | #define DAVINCI_MCBSP_RCR_RFRLEN2(v) ((v) << 24) | ||
73 | #define DAVINCI_MCBSP_RCR_RPHASE BIT(31) | ||
71 | 74 | ||
72 | #define DAVINCI_MCBSP_XCR_XWDLEN1(v) ((v) << 5) | 75 | #define DAVINCI_MCBSP_XCR_XWDLEN1(v) ((v) << 5) |
73 | #define DAVINCI_MCBSP_XCR_XFRLEN1(v) ((v) << 8) | 76 | #define DAVINCI_MCBSP_XCR_XFRLEN1(v) ((v) << 8) |
74 | #define DAVINCI_MCBSP_XCR_XDATDLY(v) ((v) << 16) | 77 | #define DAVINCI_MCBSP_XCR_XDATDLY(v) ((v) << 16) |
75 | #define DAVINCI_MCBSP_XCR_XFIG (1 << 18) | 78 | #define DAVINCI_MCBSP_XCR_XFIG (1 << 18) |
76 | #define DAVINCI_MCBSP_XCR_XWDLEN2(v) ((v) << 21) | 79 | #define DAVINCI_MCBSP_XCR_XWDLEN2(v) ((v) << 21) |
80 | #define DAVINCI_MCBSP_XCR_XFRLEN2(v) ((v) << 24) | ||
81 | #define DAVINCI_MCBSP_XCR_XPHASE BIT(31) | ||
77 | 82 | ||
78 | #define DAVINCI_MCBSP_SRGR_FWID(v) ((v) << 8) | 83 | #define DAVINCI_MCBSP_SRGR_FWID(v) ((v) << 8) |
79 | #define DAVINCI_MCBSP_SRGR_FPER(v) ((v) << 16) | 84 | #define DAVINCI_MCBSP_SRGR_FPER(v) ((v) << 16) |
80 | #define DAVINCI_MCBSP_SRGR_FSGM (1 << 28) | 85 | #define DAVINCI_MCBSP_SRGR_FSGM (1 << 28) |
86 | #define DAVINCI_MCBSP_SRGR_CLKSM BIT(29) | ||
81 | 87 | ||
82 | #define DAVINCI_MCBSP_PCR_CLKRP (1 << 0) | 88 | #define DAVINCI_MCBSP_PCR_CLKRP (1 << 0) |
83 | #define DAVINCI_MCBSP_PCR_CLKXP (1 << 1) | 89 | #define DAVINCI_MCBSP_PCR_CLKXP (1 << 1) |
@@ -116,6 +122,7 @@ static const unsigned char double_fmt[SNDRV_PCM_FORMAT_S32_LE + 1] = { | |||
116 | }; | 122 | }; |
117 | 123 | ||
118 | struct davinci_mcbsp_dev { | 124 | struct davinci_mcbsp_dev { |
125 | struct device *dev; | ||
119 | struct davinci_pcm_dma_params dma_params[2]; | 126 | struct davinci_pcm_dma_params dma_params[2]; |
120 | void __iomem *base; | 127 | void __iomem *base; |
121 | #define MOD_DSP_A 0 | 128 | #define MOD_DSP_A 0 |
@@ -144,6 +151,11 @@ struct davinci_mcbsp_dev { | |||
144 | * won't end up being swapped because of the underrun. | 151 | * won't end up being swapped because of the underrun. |
145 | */ | 152 | */ |
146 | unsigned enable_channel_combine:1; | 153 | unsigned enable_channel_combine:1; |
154 | |||
155 | unsigned int fmt; | ||
156 | int clk_div; | ||
157 | int clk_input_pin; | ||
158 | bool i2s_accurate_sck; | ||
147 | }; | 159 | }; |
148 | 160 | ||
149 | static inline void davinci_mcbsp_write_reg(struct davinci_mcbsp_dev *dev, | 161 | static inline void davinci_mcbsp_write_reg(struct davinci_mcbsp_dev *dev, |
@@ -254,10 +266,12 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, | |||
254 | struct davinci_mcbsp_dev *dev = cpu_dai->private_data; | 266 | struct davinci_mcbsp_dev *dev = cpu_dai->private_data; |
255 | unsigned int pcr; | 267 | unsigned int pcr; |
256 | unsigned int srgr; | 268 | unsigned int srgr; |
269 | /* Attention srgr is updated by hw_params! */ | ||
257 | srgr = DAVINCI_MCBSP_SRGR_FSGM | | 270 | srgr = DAVINCI_MCBSP_SRGR_FSGM | |
258 | DAVINCI_MCBSP_SRGR_FPER(DEFAULT_BITPERSAMPLE * 2 - 1) | | 271 | DAVINCI_MCBSP_SRGR_FPER(DEFAULT_BITPERSAMPLE * 2 - 1) | |
259 | DAVINCI_MCBSP_SRGR_FWID(DEFAULT_BITPERSAMPLE - 1); | 272 | DAVINCI_MCBSP_SRGR_FWID(DEFAULT_BITPERSAMPLE - 1); |
260 | 273 | ||
274 | dev->fmt = fmt; | ||
261 | /* set master/slave audio interface */ | 275 | /* set master/slave audio interface */ |
262 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | 276 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { |
263 | case SND_SOC_DAIFMT_CBS_CFS: | 277 | case SND_SOC_DAIFMT_CBS_CFS: |
@@ -268,11 +282,26 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, | |||
268 | DAVINCI_MCBSP_PCR_CLKRM; | 282 | DAVINCI_MCBSP_PCR_CLKRM; |
269 | break; | 283 | break; |
270 | case SND_SOC_DAIFMT_CBM_CFS: | 284 | case SND_SOC_DAIFMT_CBM_CFS: |
271 | /* McBSP CLKR pin is the input for the Sample Rate Generator. | 285 | pcr = DAVINCI_MCBSP_PCR_FSRM | DAVINCI_MCBSP_PCR_FSXM; |
272 | * McBSP FSR and FSX are driven by the Sample Rate Generator. */ | 286 | /* |
273 | pcr = DAVINCI_MCBSP_PCR_SCLKME | | 287 | * Selection of the clock input pin that is the |
274 | DAVINCI_MCBSP_PCR_FSXM | | 288 | * input for the Sample Rate Generator. |
275 | DAVINCI_MCBSP_PCR_FSRM; | 289 | * McBSP FSR and FSX are driven by the Sample Rate |
290 | * Generator. | ||
291 | */ | ||
292 | switch (dev->clk_input_pin) { | ||
293 | case MCBSP_CLKS: | ||
294 | pcr |= DAVINCI_MCBSP_PCR_CLKXM | | ||
295 | DAVINCI_MCBSP_PCR_CLKRM; | ||
296 | break; | ||
297 | case MCBSP_CLKR: | ||
298 | pcr |= DAVINCI_MCBSP_PCR_SCLKME; | ||
299 | break; | ||
300 | default: | ||
301 | dev_err(dev->dev, "bad clk_input_pin\n"); | ||
302 | return -EINVAL; | ||
303 | } | ||
304 | |||
276 | break; | 305 | break; |
277 | case SND_SOC_DAIFMT_CBM_CFM: | 306 | case SND_SOC_DAIFMT_CBM_CFM: |
278 | /* codec is master */ | 307 | /* codec is master */ |
@@ -372,6 +401,18 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, | |||
372 | return 0; | 401 | return 0; |
373 | } | 402 | } |
374 | 403 | ||
404 | static int davinci_i2s_dai_set_clkdiv(struct snd_soc_dai *cpu_dai, | ||
405 | int div_id, int div) | ||
406 | { | ||
407 | struct davinci_mcbsp_dev *dev = cpu_dai->private_data; | ||
408 | |||
409 | if (div_id != DAVINCI_MCBSP_CLKGDV) | ||
410 | return -ENODEV; | ||
411 | |||
412 | dev->clk_div = div; | ||
413 | return 0; | ||
414 | } | ||
415 | |||
375 | static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, | 416 | static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, |
376 | struct snd_pcm_hw_params *params, | 417 | struct snd_pcm_hw_params *params, |
377 | struct snd_soc_dai *dai) | 418 | struct snd_soc_dai *dai) |
@@ -380,8 +421,8 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, | |||
380 | struct davinci_pcm_dma_params *dma_params = | 421 | struct davinci_pcm_dma_params *dma_params = |
381 | &dev->dma_params[substream->stream]; | 422 | &dev->dma_params[substream->stream]; |
382 | struct snd_interval *i = NULL; | 423 | struct snd_interval *i = NULL; |
383 | int mcbsp_word_length; | 424 | int mcbsp_word_length, master; |
384 | unsigned int rcr, xcr, srgr; | 425 | unsigned int rcr, xcr, srgr, clk_div, freq, framesize; |
385 | u32 spcr; | 426 | u32 spcr; |
386 | snd_pcm_format_t fmt; | 427 | snd_pcm_format_t fmt; |
387 | unsigned element_cnt = 1; | 428 | unsigned element_cnt = 1; |
@@ -396,12 +437,59 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, | |||
396 | davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr); | 437 | davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr); |
397 | } | 438 | } |
398 | 439 | ||
399 | i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS); | 440 | master = dev->fmt & SND_SOC_DAIFMT_MASTER_MASK; |
400 | srgr = DAVINCI_MCBSP_SRGR_FSGM; | 441 | fmt = params_format(params); |
401 | srgr |= DAVINCI_MCBSP_SRGR_FWID(snd_interval_value(i) - 1); | 442 | mcbsp_word_length = asp_word_length[fmt]; |
402 | 443 | ||
403 | i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_FRAME_BITS); | 444 | switch (master) { |
404 | srgr |= DAVINCI_MCBSP_SRGR_FPER(snd_interval_value(i) - 1); | 445 | case SND_SOC_DAIFMT_CBS_CFS: |
446 | freq = clk_get_rate(dev->clk); | ||
447 | srgr = DAVINCI_MCBSP_SRGR_FSGM | | ||
448 | DAVINCI_MCBSP_SRGR_CLKSM; | ||
449 | srgr |= DAVINCI_MCBSP_SRGR_FWID(mcbsp_word_length * | ||
450 | 8 - 1); | ||
451 | if (dev->i2s_accurate_sck) { | ||
452 | clk_div = 256; | ||
453 | do { | ||
454 | framesize = (freq / (--clk_div)) / | ||
455 | params->rate_num * | ||
456 | params->rate_den; | ||
457 | } while (((framesize < 33) || (framesize > 4095)) && | ||
458 | (clk_div)); | ||
459 | clk_div--; | ||
460 | srgr |= DAVINCI_MCBSP_SRGR_FPER(framesize - 1); | ||
461 | } else { | ||
462 | /* symmetric waveforms */ | ||
463 | clk_div = freq / (mcbsp_word_length * 16) / | ||
464 | params->rate_num * params->rate_den; | ||
465 | srgr |= DAVINCI_MCBSP_SRGR_FPER(mcbsp_word_length * | ||
466 | 16 - 1); | ||
467 | } | ||
468 | clk_div &= 0xFF; | ||
469 | srgr |= clk_div; | ||
470 | break; | ||
471 | case SND_SOC_DAIFMT_CBM_CFS: | ||
472 | srgr = DAVINCI_MCBSP_SRGR_FSGM; | ||
473 | clk_div = dev->clk_div - 1; | ||
474 | srgr |= DAVINCI_MCBSP_SRGR_FWID(mcbsp_word_length * 8 - 1); | ||
475 | srgr |= DAVINCI_MCBSP_SRGR_FPER(mcbsp_word_length * 16 - 1); | ||
476 | clk_div &= 0xFF; | ||
477 | srgr |= clk_div; | ||
478 | break; | ||
479 | case SND_SOC_DAIFMT_CBM_CFM: | ||
480 | /* Clock and frame sync given from external sources */ | ||
481 | i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS); | ||
482 | srgr = DAVINCI_MCBSP_SRGR_FSGM; | ||
483 | srgr |= DAVINCI_MCBSP_SRGR_FWID(snd_interval_value(i) - 1); | ||
484 | pr_debug("%s - %d FWID set: re-read srgr = %X\n", | ||
485 | __func__, __LINE__, snd_interval_value(i) - 1); | ||
486 | |||
487 | i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_FRAME_BITS); | ||
488 | srgr |= DAVINCI_MCBSP_SRGR_FPER(snd_interval_value(i) - 1); | ||
489 | break; | ||
490 | default: | ||
491 | return -EINVAL; | ||
492 | } | ||
405 | davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, srgr); | 493 | davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, srgr); |
406 | 494 | ||
407 | rcr = DAVINCI_MCBSP_RCR_RFIG; | 495 | rcr = DAVINCI_MCBSP_RCR_RFIG; |
@@ -426,12 +514,41 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, | |||
426 | element_cnt = 1; | 514 | element_cnt = 1; |
427 | fmt = double_fmt[fmt]; | 515 | fmt = double_fmt[fmt]; |
428 | } | 516 | } |
517 | switch (master) { | ||
518 | case SND_SOC_DAIFMT_CBS_CFS: | ||
519 | case SND_SOC_DAIFMT_CBS_CFM: | ||
520 | rcr |= DAVINCI_MCBSP_RCR_RFRLEN2(0); | ||
521 | xcr |= DAVINCI_MCBSP_XCR_XFRLEN2(0); | ||
522 | rcr |= DAVINCI_MCBSP_RCR_RPHASE; | ||
523 | xcr |= DAVINCI_MCBSP_XCR_XPHASE; | ||
524 | break; | ||
525 | case SND_SOC_DAIFMT_CBM_CFM: | ||
526 | case SND_SOC_DAIFMT_CBM_CFS: | ||
527 | rcr |= DAVINCI_MCBSP_RCR_RFRLEN2(element_cnt - 1); | ||
528 | xcr |= DAVINCI_MCBSP_XCR_XFRLEN2(element_cnt - 1); | ||
529 | break; | ||
530 | default: | ||
531 | return -EINVAL; | ||
532 | } | ||
429 | } | 533 | } |
430 | dma_params->acnt = dma_params->data_type = data_type[fmt]; | 534 | dma_params->acnt = dma_params->data_type = data_type[fmt]; |
431 | dma_params->fifo_level = 0; | 535 | dma_params->fifo_level = 0; |
432 | mcbsp_word_length = asp_word_length[fmt]; | 536 | mcbsp_word_length = asp_word_length[fmt]; |
433 | rcr |= DAVINCI_MCBSP_RCR_RFRLEN1(element_cnt - 1); | 537 | |
434 | xcr |= DAVINCI_MCBSP_XCR_XFRLEN1(element_cnt - 1); | 538 | switch (master) { |
539 | case SND_SOC_DAIFMT_CBS_CFS: | ||
540 | case SND_SOC_DAIFMT_CBS_CFM: | ||
541 | rcr |= DAVINCI_MCBSP_RCR_RFRLEN1(0); | ||
542 | xcr |= DAVINCI_MCBSP_XCR_XFRLEN1(0); | ||
543 | break; | ||
544 | case SND_SOC_DAIFMT_CBM_CFM: | ||
545 | case SND_SOC_DAIFMT_CBM_CFS: | ||
546 | rcr |= DAVINCI_MCBSP_RCR_RFRLEN1(element_cnt - 1); | ||
547 | xcr |= DAVINCI_MCBSP_XCR_XFRLEN1(element_cnt - 1); | ||
548 | break; | ||
549 | default: | ||
550 | return -EINVAL; | ||
551 | } | ||
435 | 552 | ||
436 | rcr |= DAVINCI_MCBSP_RCR_RWDLEN1(mcbsp_word_length) | | 553 | rcr |= DAVINCI_MCBSP_RCR_RWDLEN1(mcbsp_word_length) | |
437 | DAVINCI_MCBSP_RCR_RWDLEN2(mcbsp_word_length); | 554 | DAVINCI_MCBSP_RCR_RWDLEN2(mcbsp_word_length); |
@@ -442,6 +559,10 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, | |||
442 | davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, xcr); | 559 | davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, xcr); |
443 | else | 560 | else |
444 | davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, rcr); | 561 | davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, rcr); |
562 | |||
563 | pr_debug("%s - %d srgr=%X\n", __func__, __LINE__, srgr); | ||
564 | pr_debug("%s - %d xcr=%X\n", __func__, __LINE__, xcr); | ||
565 | pr_debug("%s - %d rcr=%X\n", __func__, __LINE__, rcr); | ||
445 | return 0; | 566 | return 0; |
446 | } | 567 | } |
447 | 568 | ||
@@ -500,6 +621,7 @@ static struct snd_soc_dai_ops davinci_i2s_dai_ops = { | |||
500 | .trigger = davinci_i2s_trigger, | 621 | .trigger = davinci_i2s_trigger, |
501 | .hw_params = davinci_i2s_hw_params, | 622 | .hw_params = davinci_i2s_hw_params, |
502 | .set_fmt = davinci_i2s_set_dai_fmt, | 623 | .set_fmt = davinci_i2s_set_dai_fmt, |
624 | .set_clkdiv = davinci_i2s_dai_set_clkdiv, | ||
503 | 625 | ||
504 | }; | 626 | }; |
505 | 627 | ||
@@ -526,6 +648,8 @@ static int davinci_i2s_probe(struct platform_device *pdev) | |||
526 | struct snd_platform_data *pdata = pdev->dev.platform_data; | 648 | struct snd_platform_data *pdata = pdev->dev.platform_data; |
527 | struct davinci_mcbsp_dev *dev; | 649 | struct davinci_mcbsp_dev *dev; |
528 | struct resource *mem, *ioarea, *res; | 650 | struct resource *mem, *ioarea, *res; |
651 | enum dma_event_q asp_chan_q = EVENTQ_0; | ||
652 | enum dma_event_q ram_chan_q = EVENTQ_1; | ||
529 | int ret; | 653 | int ret; |
530 | 654 | ||
531 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 655 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
@@ -552,7 +676,17 @@ static int davinci_i2s_probe(struct platform_device *pdev) | |||
552 | pdata->sram_size_playback; | 676 | pdata->sram_size_playback; |
553 | dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].sram_size = | 677 | dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].sram_size = |
554 | pdata->sram_size_capture; | 678 | pdata->sram_size_capture; |
679 | dev->clk_input_pin = pdata->clk_input_pin; | ||
680 | dev->i2s_accurate_sck = pdata->i2s_accurate_sck; | ||
681 | asp_chan_q = pdata->asp_chan_q; | ||
682 | ram_chan_q = pdata->ram_chan_q; | ||
555 | } | 683 | } |
684 | |||
685 | dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].asp_chan_q = asp_chan_q; | ||
686 | dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].ram_chan_q = ram_chan_q; | ||
687 | dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].asp_chan_q = asp_chan_q; | ||
688 | dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].ram_chan_q = ram_chan_q; | ||
689 | |||
556 | dev->clk = clk_get(&pdev->dev, NULL); | 690 | dev->clk = clk_get(&pdev->dev, NULL); |
557 | if (IS_ERR(dev->clk)) { | 691 | if (IS_ERR(dev->clk)) { |
558 | ret = -ENODEV; | 692 | ret = -ENODEV; |
@@ -584,6 +718,7 @@ static int davinci_i2s_probe(struct platform_device *pdev) | |||
584 | goto err_free_mem; | 718 | goto err_free_mem; |
585 | } | 719 | } |
586 | dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].channel = res->start; | 720 | dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].channel = res->start; |
721 | dev->dev = &pdev->dev; | ||
587 | 722 | ||
588 | davinci_i2s_dai.private_data = dev; | 723 | davinci_i2s_dai.private_data = dev; |
589 | davinci_i2s_dai.capture.dma_data = dev->dma_params; | 724 | davinci_i2s_dai.capture.dma_data = dev->dma_params; |
diff --git a/sound/soc/davinci/davinci-i2s.h b/sound/soc/davinci/davinci-i2s.h index 241648ce8873..0b1e77b8c279 100644 --- a/sound/soc/davinci/davinci-i2s.h +++ b/sound/soc/davinci/davinci-i2s.h | |||
@@ -12,6 +12,11 @@ | |||
12 | #ifndef _DAVINCI_I2S_H | 12 | #ifndef _DAVINCI_I2S_H |
13 | #define _DAVINCI_I2S_H | 13 | #define _DAVINCI_I2S_H |
14 | 14 | ||
15 | /* McBSP dividers */ | ||
16 | enum davinci_mcbsp_div { | ||
17 | DAVINCI_MCBSP_CLKGDV, /* Sample rate generator divider */ | ||
18 | }; | ||
19 | |||
15 | extern struct snd_soc_dai davinci_i2s_dai; | 20 | extern struct snd_soc_dai davinci_i2s_dai; |
16 | 21 | ||
17 | #endif | 22 | #endif |
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index d3955096d872..b24720894af6 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c | |||
@@ -890,7 +890,8 @@ static int davinci_mcasp_probe(struct platform_device *pdev) | |||
890 | dev->rxnumevt = pdata->rxnumevt; | 890 | dev->rxnumevt = pdata->rxnumevt; |
891 | 891 | ||
892 | dma_data = &dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK]; | 892 | dma_data = &dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK]; |
893 | dma_data->eventq_no = pdata->eventq_no; | 893 | dma_data->asp_chan_q = pdata->asp_chan_q; |
894 | dma_data->ram_chan_q = pdata->ram_chan_q; | ||
894 | dma_data->dma_addr = (dma_addr_t) (pdata->tx_dma_offset + | 895 | dma_data->dma_addr = (dma_addr_t) (pdata->tx_dma_offset + |
895 | io_v2p(dev->base)); | 896 | io_v2p(dev->base)); |
896 | 897 | ||
@@ -904,7 +905,8 @@ static int davinci_mcasp_probe(struct platform_device *pdev) | |||
904 | dma_data->channel = res->start; | 905 | dma_data->channel = res->start; |
905 | 906 | ||
906 | dma_data = &dev->dma_params[SNDRV_PCM_STREAM_CAPTURE]; | 907 | dma_data = &dev->dma_params[SNDRV_PCM_STREAM_CAPTURE]; |
907 | dma_data->eventq_no = pdata->eventq_no; | 908 | dma_data->asp_chan_q = pdata->asp_chan_q; |
909 | dma_data->ram_chan_q = pdata->ram_chan_q; | ||
908 | dma_data->dma_addr = (dma_addr_t)(pdata->rx_dma_offset + | 910 | dma_data->dma_addr = (dma_addr_t)(pdata->rx_dma_offset + |
909 | io_v2p(dev->base)); | 911 | io_v2p(dev->base)); |
910 | 912 | ||
diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c index 2dc406f42fe7..a7124116d2e0 100644 --- a/sound/soc/davinci/davinci-pcm.c +++ b/sound/soc/davinci/davinci-pcm.c | |||
@@ -381,7 +381,7 @@ static int request_ping_pong(struct snd_pcm_substream *substream, | |||
381 | /* Request ram master channel */ | 381 | /* Request ram master channel */ |
382 | link = prtd->ram_channel = edma_alloc_channel(EDMA_CHANNEL_ANY, | 382 | link = prtd->ram_channel = edma_alloc_channel(EDMA_CHANNEL_ANY, |
383 | davinci_pcm_dma_irq, substream, | 383 | davinci_pcm_dma_irq, substream, |
384 | EVENTQ_1); | 384 | prtd->params->ram_chan_q); |
385 | if (link < 0) | 385 | if (link < 0) |
386 | goto exit1; | 386 | goto exit1; |
387 | 387 | ||
@@ -477,7 +477,8 @@ static int davinci_pcm_dma_request(struct snd_pcm_substream *substream) | |||
477 | 477 | ||
478 | /* Request asp master DMA channel */ | 478 | /* Request asp master DMA channel */ |
479 | link = prtd->asp_channel = edma_alloc_channel(params->channel, | 479 | link = prtd->asp_channel = edma_alloc_channel(params->channel, |
480 | davinci_pcm_dma_irq, substream, EVENTQ_0); | 480 | davinci_pcm_dma_irq, substream, |
481 | prtd->params->asp_chan_q); | ||
481 | if (link < 0) | 482 | if (link < 0) |
482 | goto exit1; | 483 | goto exit1; |
483 | 484 | ||
@@ -800,7 +801,7 @@ static void davinci_pcm_free(struct snd_pcm *pcm) | |||
800 | dma_free_writecombine(pcm->card->dev, buf->bytes, | 801 | dma_free_writecombine(pcm->card->dev, buf->bytes, |
801 | buf->area, buf->addr); | 802 | buf->area, buf->addr); |
802 | buf->area = NULL; | 803 | buf->area = NULL; |
803 | iram_dma = (struct snd_dma_buffer *)buf->private_data; | 804 | iram_dma = buf->private_data; |
804 | if (iram_dma) { | 805 | if (iram_dma) { |
805 | sram_free(iram_dma->area, iram_dma->bytes); | 806 | sram_free(iram_dma->area, iram_dma->bytes); |
806 | kfree(iram_dma); | 807 | kfree(iram_dma); |
diff --git a/sound/soc/davinci/davinci-pcm.h b/sound/soc/davinci/davinci-pcm.h index 0764944cf10f..b799a02333d8 100644 --- a/sound/soc/davinci/davinci-pcm.h +++ b/sound/soc/davinci/davinci-pcm.h | |||
@@ -21,7 +21,8 @@ struct davinci_pcm_dma_params { | |||
21 | unsigned short acnt; | 21 | unsigned short acnt; |
22 | dma_addr_t dma_addr; /* device physical address for DMA */ | 22 | dma_addr_t dma_addr; /* device physical address for DMA */ |
23 | unsigned sram_size; | 23 | unsigned sram_size; |
24 | enum dma_event_q eventq_no; /* event queue number */ | 24 | enum dma_event_q asp_chan_q; /* event queue number for ASP channel */ |
25 | enum dma_event_q ram_chan_q; /* event queue number for RAM channel */ | ||
25 | unsigned char data_type; /* xfer data type */ | 26 | unsigned char data_type; /* xfer data type */ |
26 | unsigned char convert_mono_stereo; | 27 | unsigned char convert_mono_stereo; |
27 | unsigned int fifo_level; | 28 | unsigned int fifo_level; |
diff --git a/sound/soc/davinci/davinci-vcif.c b/sound/soc/davinci/davinci-vcif.c index 9aa980d38231..48678533da7a 100644 --- a/sound/soc/davinci/davinci-vcif.c +++ b/sound/soc/davinci/davinci-vcif.c | |||
@@ -203,7 +203,7 @@ static int davinci_vcif_probe(struct platform_device *pdev) | |||
203 | int ret; | 203 | int ret; |
204 | 204 | ||
205 | davinci_vcif_dev = kzalloc(sizeof(struct davinci_vcif_dev), GFP_KERNEL); | 205 | davinci_vcif_dev = kzalloc(sizeof(struct davinci_vcif_dev), GFP_KERNEL); |
206 | if (!davinci_vc) { | 206 | if (!davinci_vcif_dev) { |
207 | dev_dbg(&pdev->dev, | 207 | dev_dbg(&pdev->dev, |
208 | "could not allocate memory for private data\n"); | 208 | "could not allocate memory for private data\n"); |
209 | return -ENOMEM; | 209 | return -ENOMEM; |
diff --git a/sound/soc/ep93xx/Kconfig b/sound/soc/ep93xx/Kconfig new file mode 100644 index 000000000000..f617f560f46b --- /dev/null +++ b/sound/soc/ep93xx/Kconfig | |||
@@ -0,0 +1,18 @@ | |||
1 | config SND_EP93XX_SOC | ||
2 | tristate "SoC Audio support for the Cirrus Logic EP93xx series" | ||
3 | depends on ARCH_EP93XX && SND_SOC | ||
4 | help | ||
5 | Say Y or M if you want to add support for codecs attached to | ||
6 | the EP93xx I2S interface. | ||
7 | |||
8 | config SND_EP93XX_SOC_I2S | ||
9 | tristate | ||
10 | |||
11 | config SND_EP93XX_SOC_SNAPPERCL15 | ||
12 | tristate "SoC Audio support for Bluewater Systems Snapper CL15 module" | ||
13 | depends on SND_EP93XX_SOC && MACH_SNAPPER_CL15 | ||
14 | select SND_EP93XX_SOC_I2S | ||
15 | select SND_SOC_TLV320AIC23 | ||
16 | help | ||
17 | Say Y or M here if you want to add support for I2S audio on the | ||
18 | Bluewater Systems Snapper CL15 module. | ||
diff --git a/sound/soc/ep93xx/Makefile b/sound/soc/ep93xx/Makefile new file mode 100644 index 000000000000..272e60f57b9a --- /dev/null +++ b/sound/soc/ep93xx/Makefile | |||
@@ -0,0 +1,11 @@ | |||
1 | # EP93xx Platform Support | ||
2 | snd-soc-ep93xx-objs := ep93xx-pcm.o | ||
3 | snd-soc-ep93xx-i2s-objs := ep93xx-i2s.o | ||
4 | |||
5 | obj-$(CONFIG_SND_EP93XX_SOC) += snd-soc-ep93xx.o | ||
6 | obj-$(CONFIG_SND_EP93XX_SOC_I2S) += snd-soc-ep93xx-i2s.o | ||
7 | |||
8 | # EP93XX Machine Support | ||
9 | snd-soc-snappercl15-objs := snappercl15.o | ||
10 | |||
11 | obj-$(CONFIG_SND_EP93XX_SOC_SNAPPERCL15) += snd-soc-snappercl15.o | ||
diff --git a/sound/soc/ep93xx/ep93xx-i2s.c b/sound/soc/ep93xx/ep93xx-i2s.c new file mode 100644 index 000000000000..00b946632184 --- /dev/null +++ b/sound/soc/ep93xx/ep93xx-i2s.c | |||
@@ -0,0 +1,487 @@ | |||
1 | /* | ||
2 | * linux/sound/soc/ep93xx-i2s.c | ||
3 | * EP93xx I2S driver | ||
4 | * | ||
5 | * Copyright (C) 2010 Ryan Mallon <ryan@bluewatersys.com> | ||
6 | * | ||
7 | * Based on the original driver by: | ||
8 | * Copyright (C) 2007 Chase Douglas <chasedouglas@gmail> | ||
9 | * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org> | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License version 2 as | ||
13 | * published by the Free Software Foundation. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #include <linux/module.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/clk.h> | ||
21 | #include <linux/io.h> | ||
22 | |||
23 | #include <sound/core.h> | ||
24 | #include <sound/pcm.h> | ||
25 | #include <sound/pcm_params.h> | ||
26 | #include <sound/initval.h> | ||
27 | #include <sound/soc.h> | ||
28 | |||
29 | #include <mach/hardware.h> | ||
30 | #include <mach/ep93xx-regs.h> | ||
31 | #include <mach/dma.h> | ||
32 | |||
33 | #include "ep93xx-pcm.h" | ||
34 | #include "ep93xx-i2s.h" | ||
35 | |||
36 | #define EP93XX_I2S_TXCLKCFG 0x00 | ||
37 | #define EP93XX_I2S_RXCLKCFG 0x04 | ||
38 | #define EP93XX_I2S_GLCTRL 0x0C | ||
39 | |||
40 | #define EP93XX_I2S_TXLINCTRLDATA 0x28 | ||
41 | #define EP93XX_I2S_TXCTRL 0x2C | ||
42 | #define EP93XX_I2S_TXWRDLEN 0x30 | ||
43 | #define EP93XX_I2S_TX0EN 0x34 | ||
44 | |||
45 | #define EP93XX_I2S_RXLINCTRLDATA 0x58 | ||
46 | #define EP93XX_I2S_RXCTRL 0x5C | ||
47 | #define EP93XX_I2S_RXWRDLEN 0x60 | ||
48 | #define EP93XX_I2S_RX0EN 0x64 | ||
49 | |||
50 | #define EP93XX_I2S_WRDLEN_16 (0 << 0) | ||
51 | #define EP93XX_I2S_WRDLEN_24 (1 << 0) | ||
52 | #define EP93XX_I2S_WRDLEN_32 (2 << 0) | ||
53 | |||
54 | #define EP93XX_I2S_LINCTRLDATA_R_JUST (1 << 2) /* Right justify */ | ||
55 | |||
56 | #define EP93XX_I2S_CLKCFG_LRS (1 << 0) /* lrclk polarity */ | ||
57 | #define EP93XX_I2S_CLKCFG_CKP (1 << 1) /* Bit clock polarity */ | ||
58 | #define EP93XX_I2S_CLKCFG_REL (1 << 2) /* First bit transition */ | ||
59 | #define EP93XX_I2S_CLKCFG_MASTER (1 << 3) /* Master mode */ | ||
60 | #define EP93XX_I2S_CLKCFG_NBCG (1 << 4) /* Not bit clock gating */ | ||
61 | |||
62 | struct ep93xx_i2s_info { | ||
63 | struct clk *mclk; | ||
64 | struct clk *sclk; | ||
65 | struct clk *lrclk; | ||
66 | struct ep93xx_pcm_dma_params *dma_params; | ||
67 | struct resource *mem; | ||
68 | void __iomem *regs; | ||
69 | }; | ||
70 | |||
71 | struct ep93xx_pcm_dma_params ep93xx_i2s_dma_params[] = { | ||
72 | [SNDRV_PCM_STREAM_PLAYBACK] = { | ||
73 | .name = "i2s-pcm-out", | ||
74 | .dma_port = EP93XX_DMA_M2P_PORT_I2S1, | ||
75 | }, | ||
76 | [SNDRV_PCM_STREAM_CAPTURE] = { | ||
77 | .name = "i2s-pcm-in", | ||
78 | .dma_port = EP93XX_DMA_M2P_PORT_I2S1, | ||
79 | }, | ||
80 | }; | ||
81 | |||
82 | static inline void ep93xx_i2s_write_reg(struct ep93xx_i2s_info *info, | ||
83 | unsigned reg, unsigned val) | ||
84 | { | ||
85 | __raw_writel(val, info->regs + reg); | ||
86 | } | ||
87 | |||
88 | static inline unsigned ep93xx_i2s_read_reg(struct ep93xx_i2s_info *info, | ||
89 | unsigned reg) | ||
90 | { | ||
91 | return __raw_readl(info->regs + reg); | ||
92 | } | ||
93 | |||
94 | static void ep93xx_i2s_enable(struct ep93xx_i2s_info *info, int stream) | ||
95 | { | ||
96 | unsigned base_reg; | ||
97 | int i; | ||
98 | |||
99 | if ((ep93xx_i2s_read_reg(info, EP93XX_I2S_TX0EN) & 0x1) == 0 && | ||
100 | (ep93xx_i2s_read_reg(info, EP93XX_I2S_RX0EN) & 0x1) == 0) { | ||
101 | /* Enable clocks */ | ||
102 | clk_enable(info->mclk); | ||
103 | clk_enable(info->sclk); | ||
104 | clk_enable(info->lrclk); | ||
105 | |||
106 | /* Enable i2s */ | ||
107 | ep93xx_i2s_write_reg(info, EP93XX_I2S_GLCTRL, 1); | ||
108 | } | ||
109 | |||
110 | /* Enable fifos */ | ||
111 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
112 | base_reg = EP93XX_I2S_TX0EN; | ||
113 | else | ||
114 | base_reg = EP93XX_I2S_RX0EN; | ||
115 | for (i = 0; i < 3; i++) | ||
116 | ep93xx_i2s_write_reg(info, base_reg + (i * 4), 1); | ||
117 | } | ||
118 | |||
119 | static void ep93xx_i2s_disable(struct ep93xx_i2s_info *info, int stream) | ||
120 | { | ||
121 | unsigned base_reg; | ||
122 | int i; | ||
123 | |||
124 | /* Disable fifos */ | ||
125 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
126 | base_reg = EP93XX_I2S_TX0EN; | ||
127 | else | ||
128 | base_reg = EP93XX_I2S_RX0EN; | ||
129 | for (i = 0; i < 3; i++) | ||
130 | ep93xx_i2s_write_reg(info, base_reg + (i * 4), 0); | ||
131 | |||
132 | if ((ep93xx_i2s_read_reg(info, EP93XX_I2S_TX0EN) & 0x1) == 0 && | ||
133 | (ep93xx_i2s_read_reg(info, EP93XX_I2S_RX0EN) & 0x1) == 0) { | ||
134 | /* Disable i2s */ | ||
135 | ep93xx_i2s_write_reg(info, EP93XX_I2S_GLCTRL, 0); | ||
136 | |||
137 | /* Disable clocks */ | ||
138 | clk_disable(info->lrclk); | ||
139 | clk_disable(info->sclk); | ||
140 | clk_disable(info->mclk); | ||
141 | } | ||
142 | } | ||
143 | |||
144 | static int ep93xx_i2s_startup(struct snd_pcm_substream *substream, | ||
145 | struct snd_soc_dai *dai) | ||
146 | { | ||
147 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
148 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | ||
149 | struct ep93xx_i2s_info *info = rtd->dai->cpu_dai->private_data; | ||
150 | |||
151 | snd_soc_dai_set_dma_data(cpu_dai, substream, | ||
152 | &info->dma_params[substream->stream]); | ||
153 | return 0; | ||
154 | } | ||
155 | |||
156 | static void ep93xx_i2s_shutdown(struct snd_pcm_substream *substream, | ||
157 | struct snd_soc_dai *dai) | ||
158 | { | ||
159 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
160 | struct ep93xx_i2s_info *info = rtd->dai->cpu_dai->private_data; | ||
161 | |||
162 | ep93xx_i2s_disable(info, substream->stream); | ||
163 | } | ||
164 | |||
165 | static int ep93xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, | ||
166 | unsigned int fmt) | ||
167 | { | ||
168 | struct ep93xx_i2s_info *info = cpu_dai->private_data; | ||
169 | unsigned int clk_cfg, lin_ctrl; | ||
170 | |||
171 | clk_cfg = ep93xx_i2s_read_reg(info, EP93XX_I2S_RXCLKCFG); | ||
172 | lin_ctrl = ep93xx_i2s_read_reg(info, EP93XX_I2S_RXLINCTRLDATA); | ||
173 | |||
174 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
175 | case SND_SOC_DAIFMT_I2S: | ||
176 | clk_cfg |= EP93XX_I2S_CLKCFG_REL; | ||
177 | lin_ctrl &= ~EP93XX_I2S_LINCTRLDATA_R_JUST; | ||
178 | break; | ||
179 | |||
180 | case SND_SOC_DAIFMT_LEFT_J: | ||
181 | clk_cfg &= ~EP93XX_I2S_CLKCFG_REL; | ||
182 | lin_ctrl &= ~EP93XX_I2S_LINCTRLDATA_R_JUST; | ||
183 | break; | ||
184 | |||
185 | case SND_SOC_DAIFMT_RIGHT_J: | ||
186 | clk_cfg &= ~EP93XX_I2S_CLKCFG_REL; | ||
187 | lin_ctrl |= EP93XX_I2S_LINCTRLDATA_R_JUST; | ||
188 | break; | ||
189 | |||
190 | default: | ||
191 | return -EINVAL; | ||
192 | } | ||
193 | |||
194 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
195 | case SND_SOC_DAIFMT_CBS_CFS: | ||
196 | /* CPU is master */ | ||
197 | clk_cfg |= EP93XX_I2S_CLKCFG_MASTER; | ||
198 | break; | ||
199 | |||
200 | case SND_SOC_DAIFMT_CBM_CFM: | ||
201 | /* Codec is master */ | ||
202 | clk_cfg &= ~EP93XX_I2S_CLKCFG_MASTER; | ||
203 | break; | ||
204 | |||
205 | default: | ||
206 | return -EINVAL; | ||
207 | } | ||
208 | |||
209 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
210 | case SND_SOC_DAIFMT_NB_NF: | ||
211 | /* Negative bit clock, lrclk low on left word */ | ||
212 | clk_cfg &= ~(EP93XX_I2S_CLKCFG_CKP | EP93XX_I2S_CLKCFG_REL); | ||
213 | break; | ||
214 | |||
215 | case SND_SOC_DAIFMT_NB_IF: | ||
216 | /* Negative bit clock, lrclk low on right word */ | ||
217 | clk_cfg &= ~EP93XX_I2S_CLKCFG_CKP; | ||
218 | clk_cfg |= EP93XX_I2S_CLKCFG_REL; | ||
219 | break; | ||
220 | |||
221 | case SND_SOC_DAIFMT_IB_NF: | ||
222 | /* Positive bit clock, lrclk low on left word */ | ||
223 | clk_cfg |= EP93XX_I2S_CLKCFG_CKP; | ||
224 | clk_cfg &= ~EP93XX_I2S_CLKCFG_REL; | ||
225 | break; | ||
226 | |||
227 | case SND_SOC_DAIFMT_IB_IF: | ||
228 | /* Positive bit clock, lrclk low on right word */ | ||
229 | clk_cfg |= EP93XX_I2S_CLKCFG_CKP | EP93XX_I2S_CLKCFG_REL; | ||
230 | break; | ||
231 | } | ||
232 | |||
233 | /* Write new register values */ | ||
234 | ep93xx_i2s_write_reg(info, EP93XX_I2S_RXCLKCFG, clk_cfg); | ||
235 | ep93xx_i2s_write_reg(info, EP93XX_I2S_TXCLKCFG, clk_cfg); | ||
236 | ep93xx_i2s_write_reg(info, EP93XX_I2S_RXLINCTRLDATA, lin_ctrl); | ||
237 | ep93xx_i2s_write_reg(info, EP93XX_I2S_TXLINCTRLDATA, lin_ctrl); | ||
238 | return 0; | ||
239 | } | ||
240 | |||
241 | static int ep93xx_i2s_hw_params(struct snd_pcm_substream *substream, | ||
242 | struct snd_pcm_hw_params *params, | ||
243 | struct snd_soc_dai *dai) | ||
244 | { | ||
245 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
246 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | ||
247 | struct ep93xx_i2s_info *info = cpu_dai->private_data; | ||
248 | unsigned word_len, div, sdiv, lrdiv; | ||
249 | int found = 0, err; | ||
250 | |||
251 | switch (params_format(params)) { | ||
252 | case SNDRV_PCM_FORMAT_S16_LE: | ||
253 | word_len = EP93XX_I2S_WRDLEN_16; | ||
254 | break; | ||
255 | |||
256 | case SNDRV_PCM_FORMAT_S24_LE: | ||
257 | word_len = EP93XX_I2S_WRDLEN_24; | ||
258 | break; | ||
259 | |||
260 | case SNDRV_PCM_FORMAT_S32_LE: | ||
261 | word_len = EP93XX_I2S_WRDLEN_32; | ||
262 | break; | ||
263 | |||
264 | default: | ||
265 | return -EINVAL; | ||
266 | } | ||
267 | |||
268 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
269 | ep93xx_i2s_write_reg(info, EP93XX_I2S_TXWRDLEN, word_len); | ||
270 | else | ||
271 | ep93xx_i2s_write_reg(info, EP93XX_I2S_RXWRDLEN, word_len); | ||
272 | |||
273 | /* | ||
274 | * Calculate the sdiv (bit clock) and lrdiv (left/right clock) values. | ||
275 | * If the lrclk is pulse length is larger than the word size, then the | ||
276 | * bit clock will be gated for the unused bits. | ||
277 | */ | ||
278 | div = (clk_get_rate(info->mclk) / params_rate(params)) * | ||
279 | params_channels(params); | ||
280 | for (sdiv = 2; sdiv <= 4; sdiv += 2) | ||
281 | for (lrdiv = 32; lrdiv <= 128; lrdiv <<= 1) | ||
282 | if (sdiv * lrdiv == div) { | ||
283 | found = 1; | ||
284 | goto out; | ||
285 | } | ||
286 | out: | ||
287 | if (!found) | ||
288 | return -EINVAL; | ||
289 | |||
290 | err = clk_set_rate(info->sclk, clk_get_rate(info->mclk) / sdiv); | ||
291 | if (err) | ||
292 | return err; | ||
293 | |||
294 | err = clk_set_rate(info->lrclk, clk_get_rate(info->sclk) / lrdiv); | ||
295 | if (err) | ||
296 | return err; | ||
297 | |||
298 | ep93xx_i2s_enable(info, substream->stream); | ||
299 | return 0; | ||
300 | } | ||
301 | |||
302 | static int ep93xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id, | ||
303 | unsigned int freq, int dir) | ||
304 | { | ||
305 | struct ep93xx_i2s_info *info = cpu_dai->private_data; | ||
306 | |||
307 | if (dir == SND_SOC_CLOCK_IN || clk_id != 0) | ||
308 | return -EINVAL; | ||
309 | |||
310 | return clk_set_rate(info->mclk, freq); | ||
311 | } | ||
312 | |||
313 | #ifdef CONFIG_PM | ||
314 | static int ep93xx_i2s_suspend(struct snd_soc_dai *dai) | ||
315 | { | ||
316 | struct ep93xx_i2s_info *info = dai->private_data; | ||
317 | |||
318 | if (!dai->active) | ||
319 | return; | ||
320 | |||
321 | ep93xx_i2s_disable(info, SNDRV_PCM_STREAM_PLAYBACK); | ||
322 | ep93xx_i2s_disable(info, SNDRV_PCM_STREAM_CAPTURE); | ||
323 | } | ||
324 | |||
325 | static int ep93xx_i2s_resume(struct snd_soc_dai *dai) | ||
326 | { | ||
327 | struct ep93xx_i2s_info *info = dai->private_data; | ||
328 | |||
329 | if (!dai->active) | ||
330 | return; | ||
331 | |||
332 | ep93xx_i2s_enable(info, SNDRV_PCM_STREAM_PLAYBACK); | ||
333 | ep93xx_i2s_enable(info, SNDRV_PCM_STREAM_CAPTURE); | ||
334 | } | ||
335 | #else | ||
336 | #define ep93xx_i2s_suspend NULL | ||
337 | #define ep93xx_i2s_resume NULL | ||
338 | #endif | ||
339 | |||
340 | static struct snd_soc_dai_ops ep93xx_i2s_dai_ops = { | ||
341 | .startup = ep93xx_i2s_startup, | ||
342 | .shutdown = ep93xx_i2s_shutdown, | ||
343 | .hw_params = ep93xx_i2s_hw_params, | ||
344 | .set_sysclk = ep93xx_i2s_set_sysclk, | ||
345 | .set_fmt = ep93xx_i2s_set_dai_fmt, | ||
346 | }; | ||
347 | |||
348 | #define EP93XX_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ | ||
349 | SNDRV_PCM_FMTBIT_S24_LE | \ | ||
350 | SNDRV_PCM_FMTBIT_S32_LE) | ||
351 | |||
352 | struct snd_soc_dai ep93xx_i2s_dai = { | ||
353 | .name = "ep93xx-i2s", | ||
354 | .id = 0, | ||
355 | .symmetric_rates= 1, | ||
356 | .suspend = ep93xx_i2s_suspend, | ||
357 | .resume = ep93xx_i2s_resume, | ||
358 | .playback = { | ||
359 | .channels_min = 2, | ||
360 | .channels_max = 2, | ||
361 | .rates = SNDRV_PCM_RATE_8000_48000, | ||
362 | .formats = EP93XX_I2S_FORMATS, | ||
363 | }, | ||
364 | .capture = { | ||
365 | .channels_min = 2, | ||
366 | .channels_max = 2, | ||
367 | .rates = SNDRV_PCM_RATE_8000_48000, | ||
368 | .formats = EP93XX_I2S_FORMATS, | ||
369 | }, | ||
370 | .ops = &ep93xx_i2s_dai_ops, | ||
371 | }; | ||
372 | EXPORT_SYMBOL_GPL(ep93xx_i2s_dai); | ||
373 | |||
374 | static int ep93xx_i2s_probe(struct platform_device *pdev) | ||
375 | { | ||
376 | struct ep93xx_i2s_info *info; | ||
377 | struct resource *res; | ||
378 | int err; | ||
379 | |||
380 | info = kzalloc(sizeof(struct ep93xx_i2s_info), GFP_KERNEL); | ||
381 | if (!info) { | ||
382 | err = -ENOMEM; | ||
383 | goto fail; | ||
384 | } | ||
385 | |||
386 | ep93xx_i2s_dai.dev = &pdev->dev; | ||
387 | ep93xx_i2s_dai.private_data = info; | ||
388 | info->dma_params = ep93xx_i2s_dma_params; | ||
389 | |||
390 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
391 | if (!res) { | ||
392 | err = -ENODEV; | ||
393 | goto fail; | ||
394 | } | ||
395 | |||
396 | info->mem = request_mem_region(res->start, resource_size(res), | ||
397 | pdev->name); | ||
398 | if (!info->mem) { | ||
399 | err = -EBUSY; | ||
400 | goto fail; | ||
401 | } | ||
402 | |||
403 | info->regs = ioremap(info->mem->start, resource_size(info->mem)); | ||
404 | if (!info->regs) { | ||
405 | err = -ENXIO; | ||
406 | goto fail_release_mem; | ||
407 | } | ||
408 | |||
409 | info->mclk = clk_get(&pdev->dev, "mclk"); | ||
410 | if (IS_ERR(info->mclk)) { | ||
411 | err = PTR_ERR(info->mclk); | ||
412 | goto fail_unmap_mem; | ||
413 | } | ||
414 | |||
415 | info->sclk = clk_get(&pdev->dev, "sclk"); | ||
416 | if (IS_ERR(info->sclk)) { | ||
417 | err = PTR_ERR(info->sclk); | ||
418 | goto fail_put_mclk; | ||
419 | } | ||
420 | |||
421 | info->lrclk = clk_get(&pdev->dev, "lrclk"); | ||
422 | if (IS_ERR(info->lrclk)) { | ||
423 | err = PTR_ERR(info->lrclk); | ||
424 | goto fail_put_sclk; | ||
425 | } | ||
426 | |||
427 | err = snd_soc_register_dai(&ep93xx_i2s_dai); | ||
428 | if (err) | ||
429 | goto fail_put_lrclk; | ||
430 | |||
431 | return 0; | ||
432 | |||
433 | fail_put_lrclk: | ||
434 | clk_put(info->lrclk); | ||
435 | fail_put_sclk: | ||
436 | clk_put(info->sclk); | ||
437 | fail_put_mclk: | ||
438 | clk_put(info->mclk); | ||
439 | fail_unmap_mem: | ||
440 | iounmap(info->regs); | ||
441 | fail_release_mem: | ||
442 | release_mem_region(info->mem->start, resource_size(info->mem)); | ||
443 | kfree(info); | ||
444 | fail: | ||
445 | return err; | ||
446 | } | ||
447 | |||
448 | static int __devexit ep93xx_i2s_remove(struct platform_device *pdev) | ||
449 | { | ||
450 | struct ep93xx_i2s_info *info = ep93xx_i2s_dai.private_data; | ||
451 | |||
452 | snd_soc_unregister_dai(&ep93xx_i2s_dai); | ||
453 | clk_put(info->lrclk); | ||
454 | clk_put(info->sclk); | ||
455 | clk_put(info->mclk); | ||
456 | iounmap(info->regs); | ||
457 | release_mem_region(info->mem->start, resource_size(info->mem)); | ||
458 | kfree(info); | ||
459 | return 0; | ||
460 | } | ||
461 | |||
462 | static struct platform_driver ep93xx_i2s_driver = { | ||
463 | .probe = ep93xx_i2s_probe, | ||
464 | .remove = __devexit_p(ep93xx_i2s_remove), | ||
465 | .driver = { | ||
466 | .name = "ep93xx-i2s", | ||
467 | .owner = THIS_MODULE, | ||
468 | }, | ||
469 | }; | ||
470 | |||
471 | static int __init ep93xx_i2s_init(void) | ||
472 | { | ||
473 | return platform_driver_register(&ep93xx_i2s_driver); | ||
474 | } | ||
475 | |||
476 | static void __exit ep93xx_i2s_exit(void) | ||
477 | { | ||
478 | platform_driver_unregister(&ep93xx_i2s_driver); | ||
479 | } | ||
480 | |||
481 | module_init(ep93xx_i2s_init); | ||
482 | module_exit(ep93xx_i2s_exit); | ||
483 | |||
484 | MODULE_ALIAS("platform:ep93xx-i2s"); | ||
485 | MODULE_AUTHOR("Ryan Mallon <ryan@bluewatersys.com>"); | ||
486 | MODULE_DESCRIPTION("EP93XX I2S driver"); | ||
487 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/ep93xx/ep93xx-i2s.h b/sound/soc/ep93xx/ep93xx-i2s.h new file mode 100644 index 000000000000..3bd4ebfaa1de --- /dev/null +++ b/sound/soc/ep93xx/ep93xx-i2s.h | |||
@@ -0,0 +1,18 @@ | |||
1 | /* | ||
2 | * linux/sound/soc/ep93xx-i2s.h | ||
3 | * EP93xx I2S driver | ||
4 | * | ||
5 | * Copyright (C) 2010 Ryan Mallon <ryan@bluewatersys.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 version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | */ | ||
12 | |||
13 | #ifndef _EP93XX_SND_SOC_I2S_H | ||
14 | #define _EP93XX_SND_SOC_I2S_H | ||
15 | |||
16 | extern struct snd_soc_dai ep93xx_i2s_dai; | ||
17 | |||
18 | #endif /* _EP93XX_SND_SOC_I2S_H */ | ||
diff --git a/sound/soc/ep93xx/ep93xx-pcm.c b/sound/soc/ep93xx/ep93xx-pcm.c new file mode 100644 index 000000000000..4ba938400791 --- /dev/null +++ b/sound/soc/ep93xx/ep93xx-pcm.c | |||
@@ -0,0 +1,319 @@ | |||
1 | /* | ||
2 | * linux/sound/arm/ep93xx-pcm.c - EP93xx ALSA PCM interface | ||
3 | * | ||
4 | * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org> | ||
5 | * Copyright (C) 2006 Applied Data Systems | ||
6 | * | ||
7 | * Rewritten for the SoC audio subsystem (Based on PXA2xx code): | ||
8 | * Copyright (c) 2008 Ryan Mallon <ryan@bluewatersys.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #include <linux/module.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/device.h> | ||
18 | #include <linux/slab.h> | ||
19 | #include <linux/dma-mapping.h> | ||
20 | |||
21 | #include <sound/core.h> | ||
22 | #include <sound/pcm.h> | ||
23 | #include <sound/pcm_params.h> | ||
24 | #include <sound/soc.h> | ||
25 | |||
26 | #include <mach/dma.h> | ||
27 | #include <mach/hardware.h> | ||
28 | #include <mach/ep93xx-regs.h> | ||
29 | |||
30 | #include "ep93xx-pcm.h" | ||
31 | |||
32 | static const struct snd_pcm_hardware ep93xx_pcm_hardware = { | ||
33 | .info = (SNDRV_PCM_INFO_MMAP | | ||
34 | SNDRV_PCM_INFO_MMAP_VALID | | ||
35 | SNDRV_PCM_INFO_INTERLEAVED | | ||
36 | SNDRV_PCM_INFO_BLOCK_TRANSFER), | ||
37 | |||
38 | .rates = SNDRV_PCM_RATE_8000_48000, | ||
39 | .rate_min = SNDRV_PCM_RATE_8000, | ||
40 | .rate_max = SNDRV_PCM_RATE_48000, | ||
41 | |||
42 | .formats = (SNDRV_PCM_FMTBIT_S16_LE | | ||
43 | SNDRV_PCM_FMTBIT_S24_LE | | ||
44 | SNDRV_PCM_FMTBIT_S32_LE), | ||
45 | |||
46 | .buffer_bytes_max = 131072, | ||
47 | .period_bytes_min = 32, | ||
48 | .period_bytes_max = 32768, | ||
49 | .periods_min = 1, | ||
50 | .periods_max = 32, | ||
51 | .fifo_size = 32, | ||
52 | }; | ||
53 | |||
54 | struct ep93xx_runtime_data | ||
55 | { | ||
56 | struct ep93xx_dma_m2p_client cl; | ||
57 | struct ep93xx_pcm_dma_params *params; | ||
58 | int pointer_bytes; | ||
59 | struct tasklet_struct period_tasklet; | ||
60 | int periods; | ||
61 | struct ep93xx_dma_buffer buf[32]; | ||
62 | }; | ||
63 | |||
64 | static void ep93xx_pcm_period_elapsed(unsigned long data) | ||
65 | { | ||
66 | struct snd_pcm_substream *substream = (struct snd_pcm_substream *)data; | ||
67 | snd_pcm_period_elapsed(substream); | ||
68 | } | ||
69 | |||
70 | static void ep93xx_pcm_buffer_started(void *cookie, | ||
71 | struct ep93xx_dma_buffer *buf) | ||
72 | { | ||
73 | } | ||
74 | |||
75 | static void ep93xx_pcm_buffer_finished(void *cookie, | ||
76 | struct ep93xx_dma_buffer *buf, | ||
77 | int bytes, int error) | ||
78 | { | ||
79 | struct snd_pcm_substream *substream = cookie; | ||
80 | struct ep93xx_runtime_data *rtd = substream->runtime->private_data; | ||
81 | |||
82 | if (buf == rtd->buf + rtd->periods - 1) | ||
83 | rtd->pointer_bytes = 0; | ||
84 | else | ||
85 | rtd->pointer_bytes += buf->size; | ||
86 | |||
87 | if (!error) { | ||
88 | ep93xx_dma_m2p_submit_recursive(&rtd->cl, buf); | ||
89 | tasklet_schedule(&rtd->period_tasklet); | ||
90 | } else { | ||
91 | snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); | ||
92 | } | ||
93 | } | ||
94 | |||
95 | static int ep93xx_pcm_open(struct snd_pcm_substream *substream) | ||
96 | { | ||
97 | struct snd_soc_pcm_runtime *soc_rtd = substream->private_data; | ||
98 | struct snd_soc_dai *cpu_dai = soc_rtd->dai->cpu_dai; | ||
99 | struct ep93xx_pcm_dma_params *dma_params; | ||
100 | struct ep93xx_runtime_data *rtd; | ||
101 | int ret; | ||
102 | |||
103 | dma_params = snd_soc_dai_get_dma_data(cpu_dai, substream); | ||
104 | snd_soc_set_runtime_hwparams(substream, &ep93xx_pcm_hardware); | ||
105 | |||
106 | rtd = kmalloc(sizeof(*rtd), GFP_KERNEL); | ||
107 | if (!rtd) | ||
108 | return -ENOMEM; | ||
109 | |||
110 | memset(&rtd->period_tasklet, 0, sizeof(rtd->period_tasklet)); | ||
111 | rtd->period_tasklet.func = ep93xx_pcm_period_elapsed; | ||
112 | rtd->period_tasklet.data = (unsigned long)substream; | ||
113 | |||
114 | rtd->cl.name = dma_params->name; | ||
115 | rtd->cl.flags = dma_params->dma_port | EP93XX_DMA_M2P_IGNORE_ERROR | | ||
116 | ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? | ||
117 | EP93XX_DMA_M2P_TX : EP93XX_DMA_M2P_RX); | ||
118 | rtd->cl.cookie = substream; | ||
119 | rtd->cl.buffer_started = ep93xx_pcm_buffer_started; | ||
120 | rtd->cl.buffer_finished = ep93xx_pcm_buffer_finished; | ||
121 | ret = ep93xx_dma_m2p_client_register(&rtd->cl); | ||
122 | if (ret < 0) { | ||
123 | kfree(rtd); | ||
124 | return ret; | ||
125 | } | ||
126 | |||
127 | substream->runtime->private_data = rtd; | ||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | static int ep93xx_pcm_close(struct snd_pcm_substream *substream) | ||
132 | { | ||
133 | struct ep93xx_runtime_data *rtd = substream->runtime->private_data; | ||
134 | |||
135 | ep93xx_dma_m2p_client_unregister(&rtd->cl); | ||
136 | kfree(rtd); | ||
137 | return 0; | ||
138 | } | ||
139 | |||
140 | static int ep93xx_pcm_hw_params(struct snd_pcm_substream *substream, | ||
141 | struct snd_pcm_hw_params *params) | ||
142 | { | ||
143 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
144 | struct ep93xx_runtime_data *rtd = runtime->private_data; | ||
145 | size_t totsize = params_buffer_bytes(params); | ||
146 | size_t period = params_period_bytes(params); | ||
147 | int i; | ||
148 | |||
149 | snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); | ||
150 | runtime->dma_bytes = totsize; | ||
151 | |||
152 | rtd->periods = (totsize + period - 1) / period; | ||
153 | for (i = 0; i < rtd->periods; i++) { | ||
154 | rtd->buf[i].bus_addr = runtime->dma_addr + (i * period); | ||
155 | rtd->buf[i].size = period; | ||
156 | if ((i + 1) * period > totsize) | ||
157 | rtd->buf[i].size = totsize - (i * period); | ||
158 | } | ||
159 | |||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | static int ep93xx_pcm_hw_free(struct snd_pcm_substream *substream) | ||
164 | { | ||
165 | snd_pcm_set_runtime_buffer(substream, NULL); | ||
166 | return 0; | ||
167 | } | ||
168 | |||
169 | static int ep93xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | ||
170 | { | ||
171 | struct ep93xx_runtime_data *rtd = substream->runtime->private_data; | ||
172 | int ret; | ||
173 | int i; | ||
174 | |||
175 | ret = 0; | ||
176 | switch (cmd) { | ||
177 | case SNDRV_PCM_TRIGGER_START: | ||
178 | case SNDRV_PCM_TRIGGER_RESUME: | ||
179 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
180 | rtd->pointer_bytes = 0; | ||
181 | for (i = 0; i < rtd->periods; i++) | ||
182 | ep93xx_dma_m2p_submit(&rtd->cl, rtd->buf + i); | ||
183 | break; | ||
184 | |||
185 | case SNDRV_PCM_TRIGGER_STOP: | ||
186 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
187 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
188 | ep93xx_dma_m2p_flush(&rtd->cl); | ||
189 | break; | ||
190 | |||
191 | default: | ||
192 | ret = -EINVAL; | ||
193 | break; | ||
194 | } | ||
195 | |||
196 | return ret; | ||
197 | } | ||
198 | |||
199 | static snd_pcm_uframes_t ep93xx_pcm_pointer(struct snd_pcm_substream *substream) | ||
200 | { | ||
201 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
202 | struct ep93xx_runtime_data *rtd = substream->runtime->private_data; | ||
203 | |||
204 | /* FIXME: implement this with sub-period granularity */ | ||
205 | return bytes_to_frames(runtime, rtd->pointer_bytes); | ||
206 | } | ||
207 | |||
208 | static int ep93xx_pcm_mmap(struct snd_pcm_substream *substream, | ||
209 | struct vm_area_struct *vma) | ||
210 | { | ||
211 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
212 | |||
213 | return dma_mmap_writecombine(substream->pcm->card->dev, vma, | ||
214 | runtime->dma_area, | ||
215 | runtime->dma_addr, | ||
216 | runtime->dma_bytes); | ||
217 | } | ||
218 | |||
219 | static struct snd_pcm_ops ep93xx_pcm_ops = { | ||
220 | .open = ep93xx_pcm_open, | ||
221 | .close = ep93xx_pcm_close, | ||
222 | .ioctl = snd_pcm_lib_ioctl, | ||
223 | .hw_params = ep93xx_pcm_hw_params, | ||
224 | .hw_free = ep93xx_pcm_hw_free, | ||
225 | .trigger = ep93xx_pcm_trigger, | ||
226 | .pointer = ep93xx_pcm_pointer, | ||
227 | .mmap = ep93xx_pcm_mmap, | ||
228 | }; | ||
229 | |||
230 | static int ep93xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) | ||
231 | { | ||
232 | struct snd_pcm_substream *substream = pcm->streams[stream].substream; | ||
233 | struct snd_dma_buffer *buf = &substream->dma_buffer; | ||
234 | size_t size = ep93xx_pcm_hardware.buffer_bytes_max; | ||
235 | |||
236 | buf->dev.type = SNDRV_DMA_TYPE_DEV; | ||
237 | buf->dev.dev = pcm->card->dev; | ||
238 | buf->private_data = NULL; | ||
239 | buf->area = dma_alloc_writecombine(pcm->card->dev, size, | ||
240 | &buf->addr, GFP_KERNEL); | ||
241 | buf->bytes = size; | ||
242 | |||
243 | return (buf->area == NULL) ? -ENOMEM : 0; | ||
244 | } | ||
245 | |||
246 | static void ep93xx_pcm_free_dma_buffers(struct snd_pcm *pcm) | ||
247 | { | ||
248 | struct snd_pcm_substream *substream; | ||
249 | struct snd_dma_buffer *buf; | ||
250 | int stream; | ||
251 | |||
252 | for (stream = 0; stream < 2; stream++) { | ||
253 | substream = pcm->streams[stream].substream; | ||
254 | if (!substream) | ||
255 | continue; | ||
256 | |||
257 | buf = &substream->dma_buffer; | ||
258 | if (!buf->area) | ||
259 | continue; | ||
260 | |||
261 | dma_free_writecombine(pcm->card->dev, buf->bytes, buf->area, | ||
262 | buf->addr); | ||
263 | buf->area = NULL; | ||
264 | } | ||
265 | } | ||
266 | |||
267 | static u64 ep93xx_pcm_dmamask = 0xffffffff; | ||
268 | |||
269 | static int ep93xx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, | ||
270 | struct snd_pcm *pcm) | ||
271 | { | ||
272 | int ret = 0; | ||
273 | |||
274 | if (!card->dev->dma_mask) | ||
275 | card->dev->dma_mask = &ep93xx_pcm_dmamask; | ||
276 | if (!card->dev->coherent_dma_mask) | ||
277 | card->dev->coherent_dma_mask = 0xffffffff; | ||
278 | |||
279 | if (dai->playback.channels_min) { | ||
280 | ret = ep93xx_pcm_preallocate_dma_buffer(pcm, | ||
281 | SNDRV_PCM_STREAM_PLAYBACK); | ||
282 | if (ret) | ||
283 | return ret; | ||
284 | } | ||
285 | |||
286 | if (dai->capture.channels_min) { | ||
287 | ret = ep93xx_pcm_preallocate_dma_buffer(pcm, | ||
288 | SNDRV_PCM_STREAM_CAPTURE); | ||
289 | if (ret) | ||
290 | return ret; | ||
291 | } | ||
292 | |||
293 | return 0; | ||
294 | } | ||
295 | |||
296 | struct snd_soc_platform ep93xx_soc_platform = { | ||
297 | .name = "ep93xx-audio", | ||
298 | .pcm_ops = &ep93xx_pcm_ops, | ||
299 | .pcm_new = &ep93xx_pcm_new, | ||
300 | .pcm_free = &ep93xx_pcm_free_dma_buffers, | ||
301 | }; | ||
302 | EXPORT_SYMBOL_GPL(ep93xx_soc_platform); | ||
303 | |||
304 | static int __init ep93xx_soc_platform_init(void) | ||
305 | { | ||
306 | return snd_soc_register_platform(&ep93xx_soc_platform); | ||
307 | } | ||
308 | |||
309 | static void __exit ep93xx_soc_platform_exit(void) | ||
310 | { | ||
311 | snd_soc_unregister_platform(&ep93xx_soc_platform); | ||
312 | } | ||
313 | |||
314 | module_init(ep93xx_soc_platform_init); | ||
315 | module_exit(ep93xx_soc_platform_exit); | ||
316 | |||
317 | MODULE_AUTHOR("Ryan Mallon <ryan@bluewatersys.com>"); | ||
318 | MODULE_DESCRIPTION("EP93xx ALSA PCM interface"); | ||
319 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/ep93xx/ep93xx-pcm.h b/sound/soc/ep93xx/ep93xx-pcm.h new file mode 100644 index 000000000000..4ffdd3f62fe9 --- /dev/null +++ b/sound/soc/ep93xx/ep93xx-pcm.h | |||
@@ -0,0 +1,22 @@ | |||
1 | /* | ||
2 | * sound/soc/ep93xx/ep93xx-pcm.h - EP93xx ALSA PCM interface | ||
3 | * | ||
4 | * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org> | ||
5 | * Copyright (C) 2006 Applied Data Systems | ||
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 version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #ifndef _EP93XX_SND_SOC_PCM_H | ||
13 | #define _EP93XX_SND_SOC_PCM_H | ||
14 | |||
15 | struct ep93xx_pcm_dma_params { | ||
16 | char *name; | ||
17 | int dma_port; | ||
18 | }; | ||
19 | |||
20 | extern struct snd_soc_platform ep93xx_soc_platform; | ||
21 | |||
22 | #endif /* _EP93XX_SND_SOC_PCM_H */ | ||
diff --git a/sound/soc/ep93xx/snappercl15.c b/sound/soc/ep93xx/snappercl15.c new file mode 100644 index 000000000000..64955340ff75 --- /dev/null +++ b/sound/soc/ep93xx/snappercl15.c | |||
@@ -0,0 +1,150 @@ | |||
1 | /* | ||
2 | * snappercl15.c -- SoC audio for Bluewater Systems Snapper CL15 module | ||
3 | * | ||
4 | * Copyright (C) 2008 Bluewater Systems Ltd | ||
5 | * Author: Ryan Mallon <ryan@bluewatersys.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 | |||
14 | #include <linux/platform_device.h> | ||
15 | #include <sound/core.h> | ||
16 | #include <sound/pcm.h> | ||
17 | #include <sound/soc.h> | ||
18 | #include <sound/soc-dapm.h> | ||
19 | |||
20 | #include <asm/mach-types.h> | ||
21 | #include <mach/hardware.h> | ||
22 | |||
23 | #include "../codecs/tlv320aic23.h" | ||
24 | #include "ep93xx-pcm.h" | ||
25 | #include "ep93xx-i2s.h" | ||
26 | |||
27 | #define CODEC_CLOCK 5644800 | ||
28 | |||
29 | static int snappercl15_hw_params(struct snd_pcm_substream *substream, | ||
30 | struct snd_pcm_hw_params *params) | ||
31 | { | ||
32 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
33 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; | ||
34 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | ||
35 | int err; | ||
36 | |||
37 | err = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | | ||
38 | SND_SOC_DAIFMT_NB_IF | | ||
39 | SND_SOC_DAIFMT_CBS_CFS); | ||
40 | |||
41 | err = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | | ||
42 | SND_SOC_DAIFMT_NB_IF | | ||
43 | SND_SOC_DAIFMT_CBS_CFS); | ||
44 | if (err) | ||
45 | return err; | ||
46 | |||
47 | err = snd_soc_dai_set_sysclk(codec_dai, 0, CODEC_CLOCK, | ||
48 | SND_SOC_CLOCK_IN); | ||
49 | if (err) | ||
50 | return err; | ||
51 | |||
52 | err = snd_soc_dai_set_sysclk(cpu_dai, 0, CODEC_CLOCK, | ||
53 | SND_SOC_CLOCK_OUT); | ||
54 | if (err) | ||
55 | return err; | ||
56 | |||
57 | return 0; | ||
58 | } | ||
59 | |||
60 | static struct snd_soc_ops snappercl15_ops = { | ||
61 | .hw_params = snappercl15_hw_params, | ||
62 | }; | ||
63 | |||
64 | static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = { | ||
65 | SND_SOC_DAPM_HP("Headphone Jack", NULL), | ||
66 | SND_SOC_DAPM_LINE("Line In", NULL), | ||
67 | SND_SOC_DAPM_MIC("Mic Jack", NULL), | ||
68 | }; | ||
69 | |||
70 | static const struct snd_soc_dapm_route audio_map[] = { | ||
71 | {"Headphone Jack", NULL, "LHPOUT"}, | ||
72 | {"Headphone Jack", NULL, "RHPOUT"}, | ||
73 | |||
74 | {"LLINEIN", NULL, "Line In"}, | ||
75 | {"RLINEIN", NULL, "Line In"}, | ||
76 | |||
77 | {"MICIN", NULL, "Mic Jack"}, | ||
78 | }; | ||
79 | |||
80 | static int snappercl15_tlv320aic23_init(struct snd_soc_codec *codec) | ||
81 | { | ||
82 | snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets, | ||
83 | ARRAY_SIZE(tlv320aic23_dapm_widgets)); | ||
84 | |||
85 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | ||
86 | return 0; | ||
87 | } | ||
88 | |||
89 | static struct snd_soc_dai_link snappercl15_dai = { | ||
90 | .name = "tlv320aic23", | ||
91 | .stream_name = "AIC23", | ||
92 | .cpu_dai = &ep93xx_i2s_dai, | ||
93 | .codec_dai = &tlv320aic23_dai, | ||
94 | .init = snappercl15_tlv320aic23_init, | ||
95 | .ops = &snappercl15_ops, | ||
96 | }; | ||
97 | |||
98 | static struct snd_soc_card snd_soc_snappercl15 = { | ||
99 | .name = "Snapper CL15", | ||
100 | .platform = &ep93xx_soc_platform, | ||
101 | .dai_link = &snappercl15_dai, | ||
102 | .num_links = 1, | ||
103 | }; | ||
104 | |||
105 | static struct snd_soc_device snappercl15_snd_devdata = { | ||
106 | .card = &snd_soc_snappercl15, | ||
107 | .codec_dev = &soc_codec_dev_tlv320aic23, | ||
108 | }; | ||
109 | |||
110 | static struct platform_device *snappercl15_snd_device; | ||
111 | |||
112 | static int __init snappercl15_init(void) | ||
113 | { | ||
114 | int ret; | ||
115 | |||
116 | if (!machine_is_snapper_cl15()) | ||
117 | return -ENODEV; | ||
118 | |||
119 | ret = ep93xx_i2s_acquire(EP93XX_SYSCON_DEVCFG_I2SONAC97, | ||
120 | EP93XX_SYSCON_I2SCLKDIV_ORIDE | | ||
121 | EP93XX_SYSCON_I2SCLKDIV_SPOL); | ||
122 | if (ret) | ||
123 | return ret; | ||
124 | |||
125 | snappercl15_snd_device = platform_device_alloc("soc-audio", -1); | ||
126 | if (!snappercl15_snd_device) | ||
127 | return -ENOMEM; | ||
128 | |||
129 | platform_set_drvdata(snappercl15_snd_device, &snappercl15_snd_devdata); | ||
130 | snappercl15_snd_devdata.dev = &snappercl15_snd_device->dev; | ||
131 | ret = platform_device_add(snappercl15_snd_device); | ||
132 | if (ret) | ||
133 | platform_device_put(snappercl15_snd_device); | ||
134 | |||
135 | return ret; | ||
136 | } | ||
137 | |||
138 | static void __exit snappercl15_exit(void) | ||
139 | { | ||
140 | platform_device_unregister(snappercl15_snd_device); | ||
141 | ep93xx_i2s_release(); | ||
142 | } | ||
143 | |||
144 | module_init(snappercl15_init); | ||
145 | module_exit(snappercl15_exit); | ||
146 | |||
147 | MODULE_AUTHOR("Ryan Mallon <ryan@bluewatersys.com>"); | ||
148 | MODULE_DESCRIPTION("ALSA SoC Snapper CL15"); | ||
149 | MODULE_LICENSE("GPL"); | ||
150 | |||
diff --git a/sound/soc/fsl/mpc5200_dma.c b/sound/soc/fsl/mpc5200_dma.c index 1d4e7164e80a..3dcd1469f283 100644 --- a/sound/soc/fsl/mpc5200_dma.c +++ b/sound/soc/fsl/mpc5200_dma.c | |||
@@ -369,7 +369,7 @@ struct snd_soc_platform mpc5200_audio_dma_platform = { | |||
369 | }; | 369 | }; |
370 | EXPORT_SYMBOL_GPL(mpc5200_audio_dma_platform); | 370 | EXPORT_SYMBOL_GPL(mpc5200_audio_dma_platform); |
371 | 371 | ||
372 | int mpc5200_audio_dma_create(struct of_device *op) | 372 | int mpc5200_audio_dma_create(struct platform_device *op) |
373 | { | 373 | { |
374 | phys_addr_t fifo; | 374 | phys_addr_t fifo; |
375 | struct psc_dma *psc_dma; | 375 | struct psc_dma *psc_dma; |
@@ -488,7 +488,7 @@ out_unmap: | |||
488 | } | 488 | } |
489 | EXPORT_SYMBOL_GPL(mpc5200_audio_dma_create); | 489 | EXPORT_SYMBOL_GPL(mpc5200_audio_dma_create); |
490 | 490 | ||
491 | int mpc5200_audio_dma_destroy(struct of_device *op) | 491 | int mpc5200_audio_dma_destroy(struct platform_device *op) |
492 | { | 492 | { |
493 | struct psc_dma *psc_dma = dev_get_drvdata(&op->dev); | 493 | struct psc_dma *psc_dma = dev_get_drvdata(&op->dev); |
494 | 494 | ||
diff --git a/sound/soc/fsl/mpc5200_dma.h b/sound/soc/fsl/mpc5200_dma.h index e1ec6d91ea38..ca99586f2ad9 100644 --- a/sound/soc/fsl/mpc5200_dma.h +++ b/sound/soc/fsl/mpc5200_dma.h | |||
@@ -81,8 +81,8 @@ to_psc_dma_stream(struct snd_pcm_substream *substream, struct psc_dma *psc_dma) | |||
81 | return &psc_dma->playback; | 81 | return &psc_dma->playback; |
82 | } | 82 | } |
83 | 83 | ||
84 | int mpc5200_audio_dma_create(struct of_device *op); | 84 | int mpc5200_audio_dma_create(struct platform_device *op); |
85 | int mpc5200_audio_dma_destroy(struct of_device *op); | 85 | int mpc5200_audio_dma_destroy(struct platform_device *op); |
86 | 86 | ||
87 | extern struct snd_soc_platform mpc5200_audio_dma_platform; | 87 | extern struct snd_soc_platform mpc5200_audio_dma_platform; |
88 | 88 | ||
diff --git a/sound/soc/fsl/mpc5200_psc_ac97.c b/sound/soc/fsl/mpc5200_psc_ac97.c index e2ee220bfb7e..a9560235daee 100644 --- a/sound/soc/fsl/mpc5200_psc_ac97.c +++ b/sound/soc/fsl/mpc5200_psc_ac97.c | |||
@@ -20,6 +20,7 @@ | |||
20 | 20 | ||
21 | #include <asm/time.h> | 21 | #include <asm/time.h> |
22 | #include <asm/delay.h> | 22 | #include <asm/delay.h> |
23 | #include <asm/mpc52xx.h> | ||
23 | #include <asm/mpc52xx_psc.h> | 24 | #include <asm/mpc52xx_psc.h> |
24 | 25 | ||
25 | #include "mpc5200_dma.h" | 26 | #include "mpc5200_dma.h" |
@@ -100,19 +101,32 @@ static void psc_ac97_warm_reset(struct snd_ac97 *ac97) | |||
100 | { | 101 | { |
101 | struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs; | 102 | struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs; |
102 | 103 | ||
104 | mutex_lock(&psc_dma->mutex); | ||
105 | |||
103 | out_be32(®s->sicr, psc_dma->sicr | MPC52xx_PSC_SICR_AWR); | 106 | out_be32(®s->sicr, psc_dma->sicr | MPC52xx_PSC_SICR_AWR); |
104 | udelay(3); | 107 | udelay(3); |
105 | out_be32(®s->sicr, psc_dma->sicr); | 108 | out_be32(®s->sicr, psc_dma->sicr); |
109 | |||
110 | mutex_unlock(&psc_dma->mutex); | ||
106 | } | 111 | } |
107 | 112 | ||
108 | static void psc_ac97_cold_reset(struct snd_ac97 *ac97) | 113 | static void psc_ac97_cold_reset(struct snd_ac97 *ac97) |
109 | { | 114 | { |
110 | struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs; | 115 | struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs; |
111 | 116 | ||
112 | /* Do a cold reset */ | 117 | mutex_lock(&psc_dma->mutex); |
113 | out_8(®s->op1, MPC52xx_PSC_OP_RES); | 118 | dev_dbg(psc_dma->dev, "cold reset\n"); |
114 | udelay(10); | 119 | |
115 | out_8(®s->op0, MPC52xx_PSC_OP_RES); | 120 | mpc5200_psc_ac97_gpio_reset(psc_dma->id); |
121 | |||
122 | /* Notify the PSC that a reset has occurred */ | ||
123 | out_be32(®s->sicr, psc_dma->sicr | MPC52xx_PSC_SICR_ACRB); | ||
124 | |||
125 | /* Re-enable RX and TX */ | ||
126 | out_8(®s->command, MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE); | ||
127 | |||
128 | mutex_unlock(&psc_dma->mutex); | ||
129 | |||
116 | msleep(1); | 130 | msleep(1); |
117 | psc_ac97_warm_reset(ac97); | 131 | psc_ac97_warm_reset(ac97); |
118 | } | 132 | } |
@@ -263,7 +277,7 @@ EXPORT_SYMBOL_GPL(psc_ac97_dai); | |||
263 | * - Probe/remove operations | 277 | * - Probe/remove operations |
264 | * - OF device match table | 278 | * - OF device match table |
265 | */ | 279 | */ |
266 | static int __devinit psc_ac97_of_probe(struct of_device *op, | 280 | static int __devinit psc_ac97_of_probe(struct platform_device *op, |
267 | const struct of_device_id *match) | 281 | const struct of_device_id *match) |
268 | { | 282 | { |
269 | int rc, i; | 283 | int rc, i; |
@@ -303,7 +317,7 @@ static int __devinit psc_ac97_of_probe(struct of_device *op, | |||
303 | return 0; | 317 | return 0; |
304 | } | 318 | } |
305 | 319 | ||
306 | static int __devexit psc_ac97_of_remove(struct of_device *op) | 320 | static int __devexit psc_ac97_of_remove(struct platform_device *op) |
307 | { | 321 | { |
308 | return mpc5200_audio_dma_destroy(op); | 322 | return mpc5200_audio_dma_destroy(op); |
309 | } | 323 | } |
diff --git a/sound/soc/fsl/mpc5200_psc_i2s.c b/sound/soc/fsl/mpc5200_psc_i2s.c index 4f455bd6851f..534f04cb15d7 100644 --- a/sound/soc/fsl/mpc5200_psc_i2s.c +++ b/sound/soc/fsl/mpc5200_psc_i2s.c | |||
@@ -16,7 +16,6 @@ | |||
16 | 16 | ||
17 | #include <asm/mpc52xx_psc.h> | 17 | #include <asm/mpc52xx_psc.h> |
18 | 18 | ||
19 | #include "mpc5200_psc_i2s.h" | ||
20 | #include "mpc5200_dma.h" | 19 | #include "mpc5200_dma.h" |
21 | 20 | ||
22 | /** | 21 | /** |
@@ -153,7 +152,7 @@ EXPORT_SYMBOL_GPL(psc_i2s_dai); | |||
153 | * - Probe/remove operations | 152 | * - Probe/remove operations |
154 | * - OF device match table | 153 | * - OF device match table |
155 | */ | 154 | */ |
156 | static int __devinit psc_i2s_of_probe(struct of_device *op, | 155 | static int __devinit psc_i2s_of_probe(struct platform_device *op, |
157 | const struct of_device_id *match) | 156 | const struct of_device_id *match) |
158 | { | 157 | { |
159 | int rc; | 158 | int rc; |
@@ -206,7 +205,7 @@ static int __devinit psc_i2s_of_probe(struct of_device *op, | |||
206 | 205 | ||
207 | } | 206 | } |
208 | 207 | ||
209 | static int __devexit psc_i2s_of_remove(struct of_device *op) | 208 | static int __devexit psc_i2s_of_remove(struct platform_device *op) |
210 | { | 209 | { |
211 | return mpc5200_audio_dma_destroy(op); | 210 | return mpc5200_audio_dma_destroy(op); |
212 | } | 211 | } |
diff --git a/sound/soc/fsl/mpc5200_psc_i2s.h b/sound/soc/fsl/mpc5200_psc_i2s.h deleted file mode 100644 index ce55e070fdf3..000000000000 --- a/sound/soc/fsl/mpc5200_psc_i2s.h +++ /dev/null | |||
@@ -1,12 +0,0 @@ | |||
1 | /* | ||
2 | * Freescale MPC5200 PSC in I2S mode | ||
3 | * ALSA SoC Digital Audio Interface (DAI) driver | ||
4 | * | ||
5 | */ | ||
6 | |||
7 | #ifndef __SOUND_SOC_FSL_MPC52xx_PSC_I2S_H__ | ||
8 | #define __SOUND_SOC_FSL_MPC52xx_PSC_I2S_H__ | ||
9 | |||
10 | extern struct snd_soc_dai psc_i2s_dai[]; | ||
11 | |||
12 | #endif /* __SOUND_SOC_FSL_MPC52xx_PSC_I2S_H__ */ | ||
diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c index 6a2764ee8203..3b13b8d65262 100644 --- a/sound/soc/fsl/mpc8610_hpcd.c +++ b/sound/soc/fsl/mpc8610_hpcd.c | |||
@@ -46,7 +46,7 @@ struct mpc8610_hpcd_data { | |||
46 | }; | 46 | }; |
47 | 47 | ||
48 | /** | 48 | /** |
49 | * mpc8610_hpcd_machine_probe: initalize the board | 49 | * mpc8610_hpcd_machine_probe: initialize the board |
50 | * | 50 | * |
51 | * This function is called when platform_device_add() is called. It is used | 51 | * This function is called when platform_device_add() is called. It is used |
52 | * to initialize the board-specific hardware. | 52 | * to initialize the board-specific hardware. |
@@ -200,7 +200,7 @@ static struct snd_soc_ops mpc8610_hpcd_ops = { | |||
200 | * SSI devices. We also probably aren't compatible with the generic Elo DMA | 200 | * SSI devices. We also probably aren't compatible with the generic Elo DMA |
201 | * device driver. | 201 | * device driver. |
202 | */ | 202 | */ |
203 | static int mpc8610_hpcd_probe(struct of_device *ofdev, | 203 | static int mpc8610_hpcd_probe(struct platform_device *ofdev, |
204 | const struct of_device_id *match) | 204 | const struct of_device_id *match) |
205 | { | 205 | { |
206 | struct device_node *np = ofdev->dev.of_node; | 206 | struct device_node *np = ofdev->dev.of_node; |
@@ -534,7 +534,7 @@ error: | |||
534 | * | 534 | * |
535 | * This function is called when the OF device is removed. | 535 | * This function is called when the OF device is removed. |
536 | */ | 536 | */ |
537 | static int mpc8610_hpcd_remove(struct of_device *ofdev) | 537 | static int mpc8610_hpcd_remove(struct platform_device *ofdev) |
538 | { | 538 | { |
539 | struct platform_device *sound_device = dev_get_drvdata(&ofdev->dev); | 539 | struct platform_device *sound_device = dev_get_drvdata(&ofdev->dev); |
540 | struct mpc8610_hpcd_data *machine_data = | 540 | struct mpc8610_hpcd_data *machine_data = |
diff --git a/sound/soc/imx/Kconfig b/sound/soc/imx/Kconfig index 252defea93b5..687c76fc0839 100644 --- a/sound/soc/imx/Kconfig +++ b/sound/soc/imx/Kconfig | |||
@@ -1,4 +1,4 @@ | |||
1 | config SND_IMX_SOC | 1 | menuconfig SND_IMX_SOC |
2 | tristate "SoC Audio for Freescale i.MX CPUs" | 2 | tristate "SoC Audio for Freescale i.MX CPUs" |
3 | depends on ARCH_MXC | 3 | depends on ARCH_MXC |
4 | select SND_PCM | 4 | select SND_PCM |
@@ -8,14 +8,12 @@ config SND_IMX_SOC | |||
8 | 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 |
9 | the i.MX SSI interface. | 9 | the i.MX SSI interface. |
10 | 10 | ||
11 | config SND_MXC_SOC_SSI | 11 | if SND_IMX_SOC |
12 | tristate | ||
13 | 12 | ||
14 | config SND_MXC_SOC_WM1133_EV1 | 13 | config SND_MXC_SOC_WM1133_EV1 |
15 | tristate "Audio on the the i.MX31ADS with WM1133-EV1 fitted" | 14 | tristate "Audio on the the i.MX31ADS with WM1133-EV1 fitted" |
16 | depends on SND_IMX_SOC && MACH_MX31ADS_WM1133_EV1 && EXPERIMENTAL | 15 | depends on MACH_MX31ADS_WM1133_EV1 && EXPERIMENTAL |
17 | select SND_SOC_WM8350 | 16 | select SND_SOC_WM8350 |
18 | select SND_MXC_SOC_SSI | ||
19 | help | 17 | help |
20 | Enable support for audio on the i.MX31ADS with the WM1133-EV1 | 18 | Enable support for audio on the i.MX31ADS with the WM1133-EV1 |
21 | PMIC board with WM8835x fitted. | 19 | PMIC board with WM8835x fitted. |
@@ -23,8 +21,19 @@ config SND_MXC_SOC_WM1133_EV1 | |||
23 | config SND_SOC_PHYCORE_AC97 | 21 | config SND_SOC_PHYCORE_AC97 |
24 | tristate "SoC Audio support for Phytec phyCORE (and phyCARD) boards" | 22 | tristate "SoC Audio support for Phytec phyCORE (and phyCARD) boards" |
25 | depends on MACH_PCM043 || MACH_PCA100 | 23 | depends on MACH_PCM043 || MACH_PCA100 |
26 | select SND_MXC_SOC_SSI | ||
27 | select SND_SOC_WM9712 | 24 | select SND_SOC_WM9712 |
28 | help | 25 | help |
29 | Say Y if you want to add support for SoC audio on Phytec phyCORE | 26 | Say Y if you want to add support for SoC audio on Phytec phyCORE |
30 | and phyCARD boards in AC97 mode | 27 | and phyCARD boards in AC97 mode |
28 | |||
29 | config SND_SOC_EUKREA_TLV320 | ||
30 | tristate "Eukrea TLV320" | ||
31 | depends on MACH_EUKREA_MBIMX27_BASEBOARD \ | ||
32 | || MACH_EUKREA_MBIMXSD25_BASEBOARD \ | ||
33 | || MACH_EUKREA_MBIMXSD35_BASEBOARD | ||
34 | select SND_SOC_TLV320AIC23 | ||
35 | help | ||
36 | Enable I2S based access to the TLV320AIC23B codec attached | ||
37 | to the SSI interface | ||
38 | |||
39 | endif # SND_IMX_SOC | ||
diff --git a/sound/soc/imx/Makefile b/sound/soc/imx/Makefile index 2d203635ac11..7bc57baf2b0e 100644 --- a/sound/soc/imx/Makefile +++ b/sound/soc/imx/Makefile | |||
@@ -8,8 +8,10 @@ endif | |||
8 | obj-$(CONFIG_SND_IMX_SOC) += snd-soc-imx.o | 8 | obj-$(CONFIG_SND_IMX_SOC) += snd-soc-imx.o |
9 | 9 | ||
10 | # i.MX Machine Support | 10 | # i.MX Machine Support |
11 | snd-soc-eukrea-tlv320-objs := eukrea-tlv320.o | ||
11 | snd-soc-phycore-ac97-objs := phycore-ac97.o | 12 | snd-soc-phycore-ac97-objs := phycore-ac97.o |
12 | snd-soc-wm1133-ev1-objs := wm1133-ev1.o | 13 | snd-soc-wm1133-ev1-objs := wm1133-ev1.o |
13 | 14 | ||
15 | obj-$(CONFIG_SND_SOC_EUKREA_TLV320) += snd-soc-eukrea-tlv320.o | ||
14 | obj-$(CONFIG_SND_SOC_PHYCORE_AC97) += snd-soc-phycore-ac97.o | 16 | obj-$(CONFIG_SND_SOC_PHYCORE_AC97) += snd-soc-phycore-ac97.o |
15 | obj-$(CONFIG_SND_MXC_SOC_WM1133_EV1) += snd-soc-wm1133-ev1.o | 17 | obj-$(CONFIG_SND_MXC_SOC_WM1133_EV1) += snd-soc-wm1133-ev1.o |
diff --git a/sound/soc/imx/eukrea-tlv320.c b/sound/soc/imx/eukrea-tlv320.c new file mode 100644 index 000000000000..f15dfbdc47ee --- /dev/null +++ b/sound/soc/imx/eukrea-tlv320.c | |||
@@ -0,0 +1,137 @@ | |||
1 | /* | ||
2 | * eukrea-tlv320.c -- SoC audio for eukrea_cpuimxXX in I2S mode | ||
3 | * | ||
4 | * Copyright 2010 Eric Bénard, Eukréa Electromatique <eric@eukrea.com> | ||
5 | * | ||
6 | * based on sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c | ||
7 | * which is Copyright 2009 Simtec Electronics | ||
8 | * and on sound/soc/imx/phycore-ac97.c which is | ||
9 | * Copyright 2009 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de> | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify it | ||
12 | * under the terms of the GNU General Public License as published by the | ||
13 | * Free Software Foundation; either version 2 of the License, or (at your | ||
14 | * option) any later version. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #include <linux/module.h> | ||
19 | #include <linux/moduleparam.h> | ||
20 | #include <linux/device.h> | ||
21 | #include <linux/i2c.h> | ||
22 | #include <sound/core.h> | ||
23 | #include <sound/pcm.h> | ||
24 | #include <sound/soc.h> | ||
25 | #include <sound/soc-dapm.h> | ||
26 | #include <asm/mach-types.h> | ||
27 | |||
28 | #include "../codecs/tlv320aic23.h" | ||
29 | #include "imx-ssi.h" | ||
30 | |||
31 | #define CODEC_CLOCK 12000000 | ||
32 | |||
33 | static int eukrea_tlv320_hw_params(struct snd_pcm_substream *substream, | ||
34 | struct snd_pcm_hw_params *params) | ||
35 | { | ||
36 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
37 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; | ||
38 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | ||
39 | int ret; | ||
40 | |||
41 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | | ||
42 | SND_SOC_DAIFMT_NB_NF | | ||
43 | SND_SOC_DAIFMT_CBM_CFM); | ||
44 | if (ret) { | ||
45 | pr_err("%s: failed set cpu dai format\n", __func__); | ||
46 | return ret; | ||
47 | } | ||
48 | |||
49 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | | ||
50 | SND_SOC_DAIFMT_NB_NF | | ||
51 | SND_SOC_DAIFMT_CBM_CFM); | ||
52 | if (ret) { | ||
53 | pr_err("%s: failed set codec dai format\n", __func__); | ||
54 | return ret; | ||
55 | } | ||
56 | |||
57 | ret = snd_soc_dai_set_sysclk(codec_dai, 0, | ||
58 | CODEC_CLOCK, SND_SOC_CLOCK_OUT); | ||
59 | if (ret) { | ||
60 | pr_err("%s: failed setting codec sysclk\n", __func__); | ||
61 | return ret; | ||
62 | } | ||
63 | snd_soc_dai_set_tdm_slot(cpu_dai, 0xffffffc, 0xffffffc, 2, 0); | ||
64 | |||
65 | ret = snd_soc_dai_set_sysclk(cpu_dai, IMX_SSP_SYS_CLK, 0, | ||
66 | SND_SOC_CLOCK_IN); | ||
67 | if (ret) { | ||
68 | pr_err("can't set CPU system clock IMX_SSP_SYS_CLK\n"); | ||
69 | return ret; | ||
70 | } | ||
71 | |||
72 | return 0; | ||
73 | } | ||
74 | |||
75 | static struct snd_soc_ops eukrea_tlv320_snd_ops = { | ||
76 | .hw_params = eukrea_tlv320_hw_params, | ||
77 | }; | ||
78 | |||
79 | static struct snd_soc_dai_link eukrea_tlv320_dai = { | ||
80 | .name = "tlv320aic23", | ||
81 | .stream_name = "TLV320AIC23", | ||
82 | .codec_dai = &tlv320aic23_dai, | ||
83 | .ops = &eukrea_tlv320_snd_ops, | ||
84 | }; | ||
85 | |||
86 | static struct snd_soc_card eukrea_tlv320 = { | ||
87 | .name = "cpuimx-audio", | ||
88 | .platform = &imx_soc_platform, | ||
89 | .dai_link = &eukrea_tlv320_dai, | ||
90 | .num_links = 1, | ||
91 | }; | ||
92 | |||
93 | static struct snd_soc_device eukrea_tlv320_snd_devdata = { | ||
94 | .card = &eukrea_tlv320, | ||
95 | .codec_dev = &soc_codec_dev_tlv320aic23, | ||
96 | }; | ||
97 | |||
98 | static struct platform_device *eukrea_tlv320_snd_device; | ||
99 | |||
100 | static int __init eukrea_tlv320_init(void) | ||
101 | { | ||
102 | int ret; | ||
103 | |||
104 | if (!machine_is_eukrea_cpuimx27() && !machine_is_eukrea_cpuimx25sd() | ||
105 | && !machine_is_eukrea_cpuimx35sd()) | ||
106 | /* return happy. We might run on a totally different machine */ | ||
107 | return 0; | ||
108 | |||
109 | eukrea_tlv320_snd_device = platform_device_alloc("soc-audio", -1); | ||
110 | if (!eukrea_tlv320_snd_device) | ||
111 | return -ENOMEM; | ||
112 | |||
113 | eukrea_tlv320_dai.cpu_dai = &imx_ssi_pcm_dai[0]; | ||
114 | |||
115 | platform_set_drvdata(eukrea_tlv320_snd_device, &eukrea_tlv320_snd_devdata); | ||
116 | eukrea_tlv320_snd_devdata.dev = &eukrea_tlv320_snd_device->dev; | ||
117 | ret = platform_device_add(eukrea_tlv320_snd_device); | ||
118 | |||
119 | if (ret) { | ||
120 | printk(KERN_ERR "ASoC: Platform device allocation failed\n"); | ||
121 | platform_device_put(eukrea_tlv320_snd_device); | ||
122 | } | ||
123 | |||
124 | return ret; | ||
125 | } | ||
126 | |||
127 | static void __exit eukrea_tlv320_exit(void) | ||
128 | { | ||
129 | platform_device_unregister(eukrea_tlv320_snd_device); | ||
130 | } | ||
131 | |||
132 | module_init(eukrea_tlv320_init); | ||
133 | module_exit(eukrea_tlv320_exit); | ||
134 | |||
135 | MODULE_AUTHOR("Eric Bénard <eric@eukrea.com>"); | ||
136 | MODULE_DESCRIPTION("CPUIMX ALSA SoC driver"); | ||
137 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/imx/imx-pcm-dma-mx2.c b/sound/soc/imx/imx-pcm-dma-mx2.c index 05f19c9284f4..0a595da4811d 100644 --- a/sound/soc/imx/imx-pcm-dma-mx2.c +++ b/sound/soc/imx/imx-pcm-dma-mx2.c | |||
@@ -292,12 +292,16 @@ static int snd_imx_open(struct snd_pcm_substream *substream) | |||
292 | int ret; | 292 | int ret; |
293 | 293 | ||
294 | iprtd = kzalloc(sizeof(*iprtd), GFP_KERNEL); | 294 | iprtd = kzalloc(sizeof(*iprtd), GFP_KERNEL); |
295 | if (iprtd == NULL) | ||
296 | return -ENOMEM; | ||
295 | runtime->private_data = iprtd; | 297 | runtime->private_data = iprtd; |
296 | 298 | ||
297 | ret = snd_pcm_hw_constraint_integer(substream->runtime, | 299 | ret = snd_pcm_hw_constraint_integer(substream->runtime, |
298 | SNDRV_PCM_HW_PARAM_PERIODS); | 300 | SNDRV_PCM_HW_PARAM_PERIODS); |
299 | if (ret < 0) | 301 | if (ret < 0) { |
302 | kfree(iprtd); | ||
300 | return ret; | 303 | return ret; |
304 | } | ||
301 | 305 | ||
302 | snd_soc_set_runtime_hwparams(substream, &snd_imx_hardware); | 306 | snd_soc_set_runtime_hwparams(substream, &snd_imx_hardware); |
303 | return 0; | 307 | return 0; |
diff --git a/sound/soc/imx/imx-pcm-fiq.c b/sound/soc/imx/imx-pcm-fiq.c index 6b518e07eea9..b2bf27282cd2 100644 --- a/sound/soc/imx/imx-pcm-fiq.c +++ b/sound/soc/imx/imx-pcm-fiq.c | |||
@@ -192,6 +192,8 @@ static int snd_imx_open(struct snd_pcm_substream *substream) | |||
192 | int ret; | 192 | int ret; |
193 | 193 | ||
194 | iprtd = kzalloc(sizeof(*iprtd), GFP_KERNEL); | 194 | iprtd = kzalloc(sizeof(*iprtd), GFP_KERNEL); |
195 | if (iprtd == NULL) | ||
196 | return -ENOMEM; | ||
195 | runtime->private_data = iprtd; | 197 | runtime->private_data = iprtd; |
196 | 198 | ||
197 | iprtd->substream = substream; | 199 | iprtd->substream = substream; |
@@ -202,8 +204,10 @@ static int snd_imx_open(struct snd_pcm_substream *substream) | |||
202 | 204 | ||
203 | ret = snd_pcm_hw_constraint_integer(substream->runtime, | 205 | ret = snd_pcm_hw_constraint_integer(substream->runtime, |
204 | SNDRV_PCM_HW_PARAM_PERIODS); | 206 | SNDRV_PCM_HW_PARAM_PERIODS); |
205 | if (ret < 0) | 207 | if (ret < 0) { |
208 | kfree(iprtd); | ||
206 | return ret; | 209 | return ret; |
210 | } | ||
207 | 211 | ||
208 | snd_soc_set_runtime_hwparams(substream, &snd_imx_hardware); | 212 | snd_soc_set_runtime_hwparams(substream, &snd_imx_hardware); |
209 | return 0; | 213 | return 0; |
diff --git a/sound/soc/imx/imx-ssi.c b/sound/soc/imx/imx-ssi.c index 80b4fee2442b..c81da05a4f11 100644 --- a/sound/soc/imx/imx-ssi.c +++ b/sound/soc/imx/imx-ssi.c | |||
@@ -23,7 +23,7 @@ | |||
23 | * between pcm data and GPIO status data changes. Our FIQ handler is not | 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 | 24 | * able to handle this, hence this driver only works with 48000Hz sampling |
25 | * rate. | 25 | * rate. |
26 | * Reading and writing AC97 registers is another challange. The core | 26 | * Reading and writing AC97 registers is another challenge. The core |
27 | * provides us status bits when the read register is updated with *another* | 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 | 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 | 29 | * contains the same value) these status bits are not set. We work |
@@ -83,8 +83,6 @@ static int imx_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, | |||
83 | /* | 83 | /* |
84 | * SSI DAI format configuration. | 84 | * SSI DAI format configuration. |
85 | * Should only be called when port is inactive (i.e. SSIEN = 0). | 85 | * Should only be called when port is inactive (i.e. SSIEN = 0). |
86 | * Note: We don't use the I2S modes but instead manually configure the | ||
87 | * SSI for I2S because the I2S mode is only a register preset. | ||
88 | */ | 86 | */ |
89 | static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) | 87 | static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) |
90 | { | 88 | { |
@@ -99,6 +97,10 @@ static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) | |||
99 | /* data on rising edge of bclk, frame low 1clk before data */ | 97 | /* data on rising edge of bclk, frame low 1clk before data */ |
100 | strcr |= SSI_STCR_TFSI | SSI_STCR_TEFS | SSI_STCR_TXBIT0; | 98 | strcr |= SSI_STCR_TFSI | SSI_STCR_TEFS | SSI_STCR_TXBIT0; |
101 | scr |= SSI_SCR_NET; | 99 | scr |= SSI_SCR_NET; |
100 | if (ssi->flags & IMX_SSI_USE_I2S_SLAVE) { | ||
101 | scr &= ~SSI_I2S_MODE_MASK; | ||
102 | scr |= SSI_SCR_I2S_MODE_SLAVE; | ||
103 | } | ||
102 | break; | 104 | break; |
103 | case SND_SOC_DAIFMT_LEFT_J: | 105 | case SND_SOC_DAIFMT_LEFT_J: |
104 | /* data on rising edge of bclk, frame high with data */ | 106 | /* data on rising edge of bclk, frame high with data */ |
@@ -143,6 +145,11 @@ static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) | |||
143 | 145 | ||
144 | strcr |= SSI_STCR_TFEN0; | 146 | strcr |= SSI_STCR_TFEN0; |
145 | 147 | ||
148 | if (ssi->flags & IMX_SSI_NET) | ||
149 | scr |= SSI_SCR_NET; | ||
150 | if (ssi->flags & IMX_SSI_SYN) | ||
151 | scr |= SSI_SCR_SYN; | ||
152 | |||
146 | writel(strcr, ssi->base + SSI_STCR); | 153 | writel(strcr, ssi->base + SSI_STCR); |
147 | writel(strcr, ssi->base + SSI_SRCR); | 154 | writel(strcr, ssi->base + SSI_SRCR); |
148 | writel(scr, ssi->base + SSI_SCR); | 155 | writel(scr, ssi->base + SSI_SCR); |
@@ -247,6 +254,9 @@ static int imx_ssi_hw_params(struct snd_pcm_substream *substream, | |||
247 | dma_data = &ssi->dma_params_rx; | 254 | dma_data = &ssi->dma_params_rx; |
248 | } | 255 | } |
249 | 256 | ||
257 | if (ssi->flags & IMX_SSI_SYN) | ||
258 | reg = SSI_STCCR; | ||
259 | |||
250 | snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data); | 260 | snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data); |
251 | 261 | ||
252 | sccr = readl(ssi->base + reg) & ~SSI_STCCR_WL_MASK; | 262 | sccr = readl(ssi->base + reg) & ~SSI_STCCR_WL_MASK; |
diff --git a/sound/soc/jz4740/Kconfig b/sound/soc/jz4740/Kconfig new file mode 100644 index 000000000000..5351cba66c9e --- /dev/null +++ b/sound/soc/jz4740/Kconfig | |||
@@ -0,0 +1,23 @@ | |||
1 | config SND_JZ4740_SOC | ||
2 | tristate "SoC Audio for Ingenic JZ4740 SoC" | ||
3 | depends on MACH_JZ4740 && SND_SOC | ||
4 | help | ||
5 | Say Y or M if you want to add support for codecs attached to | ||
6 | the JZ4740 I2S interface. You will also need to select the audio | ||
7 | interfaces to support below. | ||
8 | |||
9 | config SND_JZ4740_SOC_I2S | ||
10 | depends on SND_JZ4740_SOC | ||
11 | tristate "SoC Audio (I2S protocol) for Ingenic JZ4740 SoC" | ||
12 | help | ||
13 | Say Y if you want to use I2S protocol and I2S codec on Ingenic JZ4740 | ||
14 | based boards. | ||
15 | |||
16 | config SND_JZ4740_SOC_QI_LB60 | ||
17 | tristate "SoC Audio support for Qi LB60" | ||
18 | depends on SND_JZ4740_SOC && JZ4740_QI_LB60 | ||
19 | select SND_JZ4740_SOC_I2S | ||
20 | select SND_SOC_JZ4740_CODEC | ||
21 | help | ||
22 | Say Y if you want to add support for ASoC audio on the Qi LB60 board | ||
23 | a.k.a Qi Ben NanoNote. | ||
diff --git a/sound/soc/jz4740/Makefile b/sound/soc/jz4740/Makefile new file mode 100644 index 000000000000..be873c1b0c20 --- /dev/null +++ b/sound/soc/jz4740/Makefile | |||
@@ -0,0 +1,13 @@ | |||
1 | # | ||
2 | # Jz4740 Platform Support | ||
3 | # | ||
4 | snd-soc-jz4740-objs := jz4740-pcm.o | ||
5 | snd-soc-jz4740-i2s-objs := jz4740-i2s.o | ||
6 | |||
7 | obj-$(CONFIG_SND_JZ4740_SOC) += snd-soc-jz4740.o | ||
8 | obj-$(CONFIG_SND_JZ4740_SOC_I2S) += snd-soc-jz4740-i2s.o | ||
9 | |||
10 | # Jz4740 Machine Support | ||
11 | snd-soc-qi-lb60-objs := qi_lb60.o | ||
12 | |||
13 | obj-$(CONFIG_SND_JZ4740_SOC_QI_LB60) += snd-soc-qi-lb60.o | ||
diff --git a/sound/soc/jz4740/jz4740-i2s.c b/sound/soc/jz4740/jz4740-i2s.c new file mode 100644 index 000000000000..eb518f0c5e01 --- /dev/null +++ b/sound/soc/jz4740/jz4740-i2s.c | |||
@@ -0,0 +1,540 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms of the GNU General Public License as published by the | ||
6 | * Free Software Foundation; either version 2 of the License, or (at your | ||
7 | * option) any later version. | ||
8 | * | ||
9 | * You should have received a copy of the GNU General Public License along | ||
10 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
11 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #include <linux/init.h> | ||
16 | #include <linux/io.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/platform_device.h> | ||
20 | #include <linux/slab.h> | ||
21 | |||
22 | #include <linux/clk.h> | ||
23 | #include <linux/delay.h> | ||
24 | |||
25 | #include <linux/dma-mapping.h> | ||
26 | |||
27 | #include <sound/core.h> | ||
28 | #include <sound/pcm.h> | ||
29 | #include <sound/pcm_params.h> | ||
30 | #include <sound/soc.h> | ||
31 | #include <sound/soc-dapm.h> | ||
32 | #include <sound/initval.h> | ||
33 | |||
34 | #include "jz4740-i2s.h" | ||
35 | #include "jz4740-pcm.h" | ||
36 | |||
37 | #define JZ_REG_AIC_CONF 0x00 | ||
38 | #define JZ_REG_AIC_CTRL 0x04 | ||
39 | #define JZ_REG_AIC_I2S_FMT 0x10 | ||
40 | #define JZ_REG_AIC_FIFO_STATUS 0x14 | ||
41 | #define JZ_REG_AIC_I2S_STATUS 0x1c | ||
42 | #define JZ_REG_AIC_CLK_DIV 0x30 | ||
43 | #define JZ_REG_AIC_FIFO 0x34 | ||
44 | |||
45 | #define JZ_AIC_CONF_FIFO_RX_THRESHOLD_MASK (0xf << 12) | ||
46 | #define JZ_AIC_CONF_FIFO_TX_THRESHOLD_MASK (0xf << 8) | ||
47 | #define JZ_AIC_CONF_OVERFLOW_PLAY_LAST BIT(6) | ||
48 | #define JZ_AIC_CONF_INTERNAL_CODEC BIT(5) | ||
49 | #define JZ_AIC_CONF_I2S BIT(4) | ||
50 | #define JZ_AIC_CONF_RESET BIT(3) | ||
51 | #define JZ_AIC_CONF_BIT_CLK_MASTER BIT(2) | ||
52 | #define JZ_AIC_CONF_SYNC_CLK_MASTER BIT(1) | ||
53 | #define JZ_AIC_CONF_ENABLE BIT(0) | ||
54 | |||
55 | #define JZ_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET 12 | ||
56 | #define JZ_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET 8 | ||
57 | |||
58 | #define JZ_AIC_CTRL_OUTPUT_SAMPLE_SIZE_MASK (0x7 << 19) | ||
59 | #define JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_MASK (0x7 << 16) | ||
60 | #define JZ_AIC_CTRL_ENABLE_RX_DMA BIT(15) | ||
61 | #define JZ_AIC_CTRL_ENABLE_TX_DMA BIT(14) | ||
62 | #define JZ_AIC_CTRL_MONO_TO_STEREO BIT(11) | ||
63 | #define JZ_AIC_CTRL_SWITCH_ENDIANNESS BIT(10) | ||
64 | #define JZ_AIC_CTRL_SIGNED_TO_UNSIGNED BIT(9) | ||
65 | #define JZ_AIC_CTRL_FLUSH BIT(8) | ||
66 | #define JZ_AIC_CTRL_ENABLE_ROR_INT BIT(6) | ||
67 | #define JZ_AIC_CTRL_ENABLE_TUR_INT BIT(5) | ||
68 | #define JZ_AIC_CTRL_ENABLE_RFS_INT BIT(4) | ||
69 | #define JZ_AIC_CTRL_ENABLE_TFS_INT BIT(3) | ||
70 | #define JZ_AIC_CTRL_ENABLE_LOOPBACK BIT(2) | ||
71 | #define JZ_AIC_CTRL_ENABLE_PLAYBACK BIT(1) | ||
72 | #define JZ_AIC_CTRL_ENABLE_CAPTURE BIT(0) | ||
73 | |||
74 | #define JZ_AIC_CTRL_OUTPUT_SAMPLE_SIZE_OFFSET 19 | ||
75 | #define JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_OFFSET 16 | ||
76 | |||
77 | #define JZ_AIC_I2S_FMT_DISABLE_BIT_CLK BIT(12) | ||
78 | #define JZ_AIC_I2S_FMT_ENABLE_SYS_CLK BIT(4) | ||
79 | #define JZ_AIC_I2S_FMT_MSB BIT(0) | ||
80 | |||
81 | #define JZ_AIC_I2S_STATUS_BUSY BIT(2) | ||
82 | |||
83 | #define JZ_AIC_CLK_DIV_MASK 0xf | ||
84 | |||
85 | struct jz4740_i2s { | ||
86 | struct resource *mem; | ||
87 | void __iomem *base; | ||
88 | dma_addr_t phys_base; | ||
89 | |||
90 | struct clk *clk_aic; | ||
91 | struct clk *clk_i2s; | ||
92 | |||
93 | struct jz4740_pcm_config pcm_config_playback; | ||
94 | struct jz4740_pcm_config pcm_config_capture; | ||
95 | }; | ||
96 | |||
97 | static inline uint32_t jz4740_i2s_read(const struct jz4740_i2s *i2s, | ||
98 | unsigned int reg) | ||
99 | { | ||
100 | return readl(i2s->base + reg); | ||
101 | } | ||
102 | |||
103 | static inline void jz4740_i2s_write(const struct jz4740_i2s *i2s, | ||
104 | unsigned int reg, uint32_t value) | ||
105 | { | ||
106 | writel(value, i2s->base + reg); | ||
107 | } | ||
108 | |||
109 | static inline struct jz4740_i2s *jz4740_dai_to_i2s(struct snd_soc_dai *dai) | ||
110 | { | ||
111 | return dai->private_data; | ||
112 | } | ||
113 | |||
114 | static int jz4740_i2s_startup(struct snd_pcm_substream *substream, | ||
115 | struct snd_soc_dai *dai) | ||
116 | { | ||
117 | struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai); | ||
118 | uint32_t conf, ctrl; | ||
119 | |||
120 | if (dai->active) | ||
121 | return 0; | ||
122 | |||
123 | ctrl = jz4740_i2s_read(i2s, JZ_REG_AIC_CTRL); | ||
124 | ctrl |= JZ_AIC_CTRL_FLUSH; | ||
125 | jz4740_i2s_write(i2s, JZ_REG_AIC_CTRL, ctrl); | ||
126 | |||
127 | clk_enable(i2s->clk_i2s); | ||
128 | |||
129 | conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF); | ||
130 | conf |= JZ_AIC_CONF_ENABLE; | ||
131 | jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf); | ||
132 | |||
133 | return 0; | ||
134 | } | ||
135 | |||
136 | static void jz4740_i2s_shutdown(struct snd_pcm_substream *substream, | ||
137 | struct snd_soc_dai *dai) | ||
138 | { | ||
139 | struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai); | ||
140 | uint32_t conf; | ||
141 | |||
142 | if (!dai->active) | ||
143 | return; | ||
144 | |||
145 | conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF); | ||
146 | conf &= ~JZ_AIC_CONF_ENABLE; | ||
147 | jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf); | ||
148 | |||
149 | clk_disable(i2s->clk_i2s); | ||
150 | } | ||
151 | |||
152 | static int jz4740_i2s_trigger(struct snd_pcm_substream *substream, int cmd, | ||
153 | struct snd_soc_dai *dai) | ||
154 | { | ||
155 | struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai); | ||
156 | |||
157 | uint32_t ctrl; | ||
158 | uint32_t mask; | ||
159 | |||
160 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
161 | mask = JZ_AIC_CTRL_ENABLE_PLAYBACK | JZ_AIC_CTRL_ENABLE_TX_DMA; | ||
162 | else | ||
163 | mask = JZ_AIC_CTRL_ENABLE_CAPTURE | JZ_AIC_CTRL_ENABLE_RX_DMA; | ||
164 | |||
165 | ctrl = jz4740_i2s_read(i2s, JZ_REG_AIC_CTRL); | ||
166 | |||
167 | switch (cmd) { | ||
168 | case SNDRV_PCM_TRIGGER_START: | ||
169 | case SNDRV_PCM_TRIGGER_RESUME: | ||
170 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
171 | ctrl |= mask; | ||
172 | break; | ||
173 | case SNDRV_PCM_TRIGGER_STOP: | ||
174 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
175 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
176 | ctrl &= ~mask; | ||
177 | break; | ||
178 | default: | ||
179 | return -EINVAL; | ||
180 | } | ||
181 | |||
182 | jz4740_i2s_write(i2s, JZ_REG_AIC_CTRL, ctrl); | ||
183 | |||
184 | return 0; | ||
185 | } | ||
186 | |||
187 | static int jz4740_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) | ||
188 | { | ||
189 | struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai); | ||
190 | |||
191 | uint32_t format = 0; | ||
192 | uint32_t conf; | ||
193 | |||
194 | conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF); | ||
195 | |||
196 | conf &= ~(JZ_AIC_CONF_BIT_CLK_MASTER | JZ_AIC_CONF_SYNC_CLK_MASTER); | ||
197 | |||
198 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
199 | case SND_SOC_DAIFMT_CBS_CFS: | ||
200 | conf |= JZ_AIC_CONF_BIT_CLK_MASTER | JZ_AIC_CONF_SYNC_CLK_MASTER; | ||
201 | format |= JZ_AIC_I2S_FMT_ENABLE_SYS_CLK; | ||
202 | break; | ||
203 | case SND_SOC_DAIFMT_CBM_CFS: | ||
204 | conf |= JZ_AIC_CONF_SYNC_CLK_MASTER; | ||
205 | break; | ||
206 | case SND_SOC_DAIFMT_CBS_CFM: | ||
207 | conf |= JZ_AIC_CONF_BIT_CLK_MASTER; | ||
208 | break; | ||
209 | case SND_SOC_DAIFMT_CBM_CFM: | ||
210 | break; | ||
211 | default: | ||
212 | return -EINVAL; | ||
213 | } | ||
214 | |||
215 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
216 | case SND_SOC_DAIFMT_MSB: | ||
217 | format |= JZ_AIC_I2S_FMT_MSB; | ||
218 | break; | ||
219 | case SND_SOC_DAIFMT_I2S: | ||
220 | break; | ||
221 | default: | ||
222 | return -EINVAL; | ||
223 | } | ||
224 | |||
225 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
226 | case SND_SOC_DAIFMT_NB_NF: | ||
227 | break; | ||
228 | default: | ||
229 | return -EINVAL; | ||
230 | } | ||
231 | |||
232 | jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf); | ||
233 | jz4740_i2s_write(i2s, JZ_REG_AIC_I2S_FMT, format); | ||
234 | |||
235 | return 0; | ||
236 | } | ||
237 | |||
238 | static int jz4740_i2s_hw_params(struct snd_pcm_substream *substream, | ||
239 | struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) | ||
240 | { | ||
241 | struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai); | ||
242 | enum jz4740_dma_width dma_width; | ||
243 | struct jz4740_pcm_config *pcm_config; | ||
244 | unsigned int sample_size; | ||
245 | uint32_t ctrl; | ||
246 | |||
247 | ctrl = jz4740_i2s_read(i2s, JZ_REG_AIC_CTRL); | ||
248 | |||
249 | switch (params_format(params)) { | ||
250 | case SNDRV_PCM_FORMAT_S8: | ||
251 | sample_size = 0; | ||
252 | dma_width = JZ4740_DMA_WIDTH_8BIT; | ||
253 | break; | ||
254 | case SNDRV_PCM_FORMAT_S16: | ||
255 | sample_size = 1; | ||
256 | dma_width = JZ4740_DMA_WIDTH_16BIT; | ||
257 | break; | ||
258 | default: | ||
259 | return -EINVAL; | ||
260 | } | ||
261 | |||
262 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
263 | ctrl &= ~JZ_AIC_CTRL_OUTPUT_SAMPLE_SIZE_MASK; | ||
264 | ctrl |= sample_size << JZ_AIC_CTRL_OUTPUT_SAMPLE_SIZE_OFFSET; | ||
265 | if (params_channels(params) == 1) | ||
266 | ctrl |= JZ_AIC_CTRL_MONO_TO_STEREO; | ||
267 | else | ||
268 | ctrl &= ~JZ_AIC_CTRL_MONO_TO_STEREO; | ||
269 | |||
270 | pcm_config = &i2s->pcm_config_playback; | ||
271 | pcm_config->dma_config.dst_width = dma_width; | ||
272 | |||
273 | } else { | ||
274 | ctrl &= ~JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_MASK; | ||
275 | ctrl |= sample_size << JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_OFFSET; | ||
276 | |||
277 | pcm_config = &i2s->pcm_config_capture; | ||
278 | pcm_config->dma_config.src_width = dma_width; | ||
279 | } | ||
280 | |||
281 | jz4740_i2s_write(i2s, JZ_REG_AIC_CTRL, ctrl); | ||
282 | |||
283 | snd_soc_dai_set_dma_data(dai, substream, pcm_config); | ||
284 | |||
285 | return 0; | ||
286 | } | ||
287 | |||
288 | static int jz4740_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, | ||
289 | unsigned int freq, int dir) | ||
290 | { | ||
291 | struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai); | ||
292 | struct clk *parent; | ||
293 | int ret = 0; | ||
294 | |||
295 | switch (clk_id) { | ||
296 | case JZ4740_I2S_CLKSRC_EXT: | ||
297 | parent = clk_get(NULL, "ext"); | ||
298 | clk_set_parent(i2s->clk_i2s, parent); | ||
299 | break; | ||
300 | case JZ4740_I2S_CLKSRC_PLL: | ||
301 | parent = clk_get(NULL, "pll half"); | ||
302 | clk_set_parent(i2s->clk_i2s, parent); | ||
303 | ret = clk_set_rate(i2s->clk_i2s, freq); | ||
304 | break; | ||
305 | default: | ||
306 | return -EINVAL; | ||
307 | } | ||
308 | clk_put(parent); | ||
309 | |||
310 | return ret; | ||
311 | } | ||
312 | |||
313 | static int jz4740_i2s_suspend(struct snd_soc_dai *dai) | ||
314 | { | ||
315 | struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai); | ||
316 | uint32_t conf; | ||
317 | |||
318 | if (dai->active) { | ||
319 | conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF); | ||
320 | conf &= ~JZ_AIC_CONF_ENABLE; | ||
321 | jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf); | ||
322 | |||
323 | clk_disable(i2s->clk_i2s); | ||
324 | } | ||
325 | |||
326 | clk_disable(i2s->clk_aic); | ||
327 | |||
328 | return 0; | ||
329 | } | ||
330 | |||
331 | static int jz4740_i2s_resume(struct snd_soc_dai *dai) | ||
332 | { | ||
333 | struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai); | ||
334 | uint32_t conf; | ||
335 | |||
336 | clk_enable(i2s->clk_aic); | ||
337 | |||
338 | if (dai->active) { | ||
339 | clk_enable(i2s->clk_i2s); | ||
340 | |||
341 | conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF); | ||
342 | conf |= JZ_AIC_CONF_ENABLE; | ||
343 | jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf); | ||
344 | } | ||
345 | |||
346 | return 0; | ||
347 | } | ||
348 | |||
349 | static int jz4740_i2s_probe(struct platform_device *pdev, struct snd_soc_dai *dai) | ||
350 | { | ||
351 | struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai); | ||
352 | uint32_t conf; | ||
353 | |||
354 | conf = (7 << JZ_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET) | | ||
355 | (8 << JZ_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET) | | ||
356 | JZ_AIC_CONF_OVERFLOW_PLAY_LAST | | ||
357 | JZ_AIC_CONF_I2S | | ||
358 | JZ_AIC_CONF_INTERNAL_CODEC; | ||
359 | |||
360 | jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, JZ_AIC_CONF_RESET); | ||
361 | jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf); | ||
362 | |||
363 | return 0; | ||
364 | } | ||
365 | |||
366 | static struct snd_soc_dai_ops jz4740_i2s_dai_ops = { | ||
367 | .startup = jz4740_i2s_startup, | ||
368 | .shutdown = jz4740_i2s_shutdown, | ||
369 | .trigger = jz4740_i2s_trigger, | ||
370 | .hw_params = jz4740_i2s_hw_params, | ||
371 | .set_fmt = jz4740_i2s_set_fmt, | ||
372 | .set_sysclk = jz4740_i2s_set_sysclk, | ||
373 | }; | ||
374 | |||
375 | #define JZ4740_I2S_FMTS (SNDRV_PCM_FMTBIT_S8 | \ | ||
376 | SNDRV_PCM_FMTBIT_S16_LE) | ||
377 | |||
378 | struct snd_soc_dai jz4740_i2s_dai = { | ||
379 | .name = "jz4740-i2s", | ||
380 | .probe = jz4740_i2s_probe, | ||
381 | .playback = { | ||
382 | .channels_min = 1, | ||
383 | .channels_max = 2, | ||
384 | .rates = SNDRV_PCM_RATE_8000_48000, | ||
385 | .formats = JZ4740_I2S_FMTS, | ||
386 | }, | ||
387 | .capture = { | ||
388 | .channels_min = 2, | ||
389 | .channels_max = 2, | ||
390 | .rates = SNDRV_PCM_RATE_8000_48000, | ||
391 | .formats = JZ4740_I2S_FMTS, | ||
392 | }, | ||
393 | .symmetric_rates = 1, | ||
394 | .ops = &jz4740_i2s_dai_ops, | ||
395 | .suspend = jz4740_i2s_suspend, | ||
396 | .resume = jz4740_i2s_resume, | ||
397 | }; | ||
398 | EXPORT_SYMBOL_GPL(jz4740_i2s_dai); | ||
399 | |||
400 | static void __devinit jz4740_i2c_init_pcm_config(struct jz4740_i2s *i2s) | ||
401 | { | ||
402 | struct jz4740_dma_config *dma_config; | ||
403 | |||
404 | /* Playback */ | ||
405 | dma_config = &i2s->pcm_config_playback.dma_config; | ||
406 | dma_config->src_width = JZ4740_DMA_WIDTH_32BIT, | ||
407 | dma_config->transfer_size = JZ4740_DMA_TRANSFER_SIZE_16BYTE; | ||
408 | dma_config->request_type = JZ4740_DMA_TYPE_AIC_TRANSMIT; | ||
409 | dma_config->flags = JZ4740_DMA_SRC_AUTOINC; | ||
410 | dma_config->mode = JZ4740_DMA_MODE_SINGLE; | ||
411 | i2s->pcm_config_playback.fifo_addr = i2s->phys_base + JZ_REG_AIC_FIFO; | ||
412 | |||
413 | /* Capture */ | ||
414 | dma_config = &i2s->pcm_config_capture.dma_config; | ||
415 | dma_config->dst_width = JZ4740_DMA_WIDTH_32BIT, | ||
416 | dma_config->transfer_size = JZ4740_DMA_TRANSFER_SIZE_16BYTE; | ||
417 | dma_config->request_type = JZ4740_DMA_TYPE_AIC_RECEIVE; | ||
418 | dma_config->flags = JZ4740_DMA_DST_AUTOINC; | ||
419 | dma_config->mode = JZ4740_DMA_MODE_SINGLE; | ||
420 | i2s->pcm_config_capture.fifo_addr = i2s->phys_base + JZ_REG_AIC_FIFO; | ||
421 | } | ||
422 | |||
423 | static int __devinit jz4740_i2s_dev_probe(struct platform_device *pdev) | ||
424 | { | ||
425 | struct jz4740_i2s *i2s; | ||
426 | int ret; | ||
427 | |||
428 | i2s = kzalloc(sizeof(*i2s), GFP_KERNEL); | ||
429 | |||
430 | if (!i2s) | ||
431 | return -ENOMEM; | ||
432 | |||
433 | i2s->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
434 | if (!i2s->mem) { | ||
435 | ret = -ENOENT; | ||
436 | goto err_free; | ||
437 | } | ||
438 | |||
439 | i2s->mem = request_mem_region(i2s->mem->start, resource_size(i2s->mem), | ||
440 | pdev->name); | ||
441 | if (!i2s->mem) { | ||
442 | ret = -EBUSY; | ||
443 | goto err_free; | ||
444 | } | ||
445 | |||
446 | i2s->base = ioremap_nocache(i2s->mem->start, resource_size(i2s->mem)); | ||
447 | if (!i2s->base) { | ||
448 | ret = -EBUSY; | ||
449 | goto err_release_mem_region; | ||
450 | } | ||
451 | |||
452 | i2s->phys_base = i2s->mem->start; | ||
453 | |||
454 | i2s->clk_aic = clk_get(&pdev->dev, "aic"); | ||
455 | if (IS_ERR(i2s->clk_aic)) { | ||
456 | ret = PTR_ERR(i2s->clk_aic); | ||
457 | goto err_iounmap; | ||
458 | } | ||
459 | |||
460 | i2s->clk_i2s = clk_get(&pdev->dev, "i2s"); | ||
461 | if (IS_ERR(i2s->clk_i2s)) { | ||
462 | ret = PTR_ERR(i2s->clk_i2s); | ||
463 | goto err_clk_put_aic; | ||
464 | } | ||
465 | |||
466 | clk_enable(i2s->clk_aic); | ||
467 | |||
468 | jz4740_i2c_init_pcm_config(i2s); | ||
469 | |||
470 | jz4740_i2s_dai.private_data = i2s; | ||
471 | ret = snd_soc_register_dai(&jz4740_i2s_dai); | ||
472 | |||
473 | if (ret) { | ||
474 | dev_err(&pdev->dev, "Failed to register DAI\n"); | ||
475 | goto err_clk_put_i2s; | ||
476 | } | ||
477 | |||
478 | platform_set_drvdata(pdev, i2s); | ||
479 | |||
480 | return 0; | ||
481 | |||
482 | err_clk_put_i2s: | ||
483 | clk_disable(i2s->clk_aic); | ||
484 | clk_put(i2s->clk_i2s); | ||
485 | err_clk_put_aic: | ||
486 | clk_put(i2s->clk_aic); | ||
487 | err_iounmap: | ||
488 | iounmap(i2s->base); | ||
489 | err_release_mem_region: | ||
490 | release_mem_region(i2s->mem->start, resource_size(i2s->mem)); | ||
491 | err_free: | ||
492 | kfree(i2s); | ||
493 | |||
494 | return ret; | ||
495 | } | ||
496 | |||
497 | static int __devexit jz4740_i2s_dev_remove(struct platform_device *pdev) | ||
498 | { | ||
499 | struct jz4740_i2s *i2s = platform_get_drvdata(pdev); | ||
500 | |||
501 | snd_soc_unregister_dai(&jz4740_i2s_dai); | ||
502 | |||
503 | clk_disable(i2s->clk_aic); | ||
504 | clk_put(i2s->clk_i2s); | ||
505 | clk_put(i2s->clk_aic); | ||
506 | |||
507 | iounmap(i2s->base); | ||
508 | release_mem_region(i2s->mem->start, resource_size(i2s->mem)); | ||
509 | |||
510 | platform_set_drvdata(pdev, NULL); | ||
511 | kfree(i2s); | ||
512 | |||
513 | return 0; | ||
514 | } | ||
515 | |||
516 | static struct platform_driver jz4740_i2s_driver = { | ||
517 | .probe = jz4740_i2s_dev_probe, | ||
518 | .remove = __devexit_p(jz4740_i2s_dev_remove), | ||
519 | .driver = { | ||
520 | .name = "jz4740-i2s", | ||
521 | .owner = THIS_MODULE, | ||
522 | }, | ||
523 | }; | ||
524 | |||
525 | static int __init jz4740_i2s_init(void) | ||
526 | { | ||
527 | return platform_driver_register(&jz4740_i2s_driver); | ||
528 | } | ||
529 | module_init(jz4740_i2s_init); | ||
530 | |||
531 | static void __exit jz4740_i2s_exit(void) | ||
532 | { | ||
533 | platform_driver_unregister(&jz4740_i2s_driver); | ||
534 | } | ||
535 | module_exit(jz4740_i2s_exit); | ||
536 | |||
537 | MODULE_AUTHOR("Lars-Peter Clausen, <lars@metafoo.de>"); | ||
538 | MODULE_DESCRIPTION("Ingenic JZ4740 SoC I2S driver"); | ||
539 | MODULE_LICENSE("GPL"); | ||
540 | MODULE_ALIAS("platform:jz4740-i2s"); | ||
diff --git a/sound/soc/jz4740/jz4740-i2s.h b/sound/soc/jz4740/jz4740-i2s.h new file mode 100644 index 000000000000..da22ed88a589 --- /dev/null +++ b/sound/soc/jz4740/jz4740-i2s.h | |||
@@ -0,0 +1,18 @@ | |||
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 _JZ4740_I2S_H | ||
8 | #define _JZ4740_I2S_H | ||
9 | |||
10 | /* I2S clock source */ | ||
11 | #define JZ4740_I2S_CLKSRC_EXT 0 | ||
12 | #define JZ4740_I2S_CLKSRC_PLL 1 | ||
13 | |||
14 | #define JZ4740_I2S_BIT_CLK 0 | ||
15 | |||
16 | extern struct snd_soc_dai jz4740_i2s_dai; | ||
17 | |||
18 | #endif | ||
diff --git a/sound/soc/jz4740/jz4740-pcm.c b/sound/soc/jz4740/jz4740-pcm.c new file mode 100644 index 000000000000..ee68d850c8dd --- /dev/null +++ b/sound/soc/jz4740/jz4740-pcm.c | |||
@@ -0,0 +1,373 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms of the GNU General Public License as published by the | ||
6 | * Free Software Foundation; either version 2 of the License, or (at your | ||
7 | * option) any later version. | ||
8 | * | ||
9 | * You should have received a copy of the GNU General Public License along | ||
10 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
11 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #include <linux/init.h> | ||
16 | #include <linux/interrupt.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/platform_device.h> | ||
20 | #include <linux/slab.h> | ||
21 | |||
22 | #include <linux/dma-mapping.h> | ||
23 | |||
24 | #include <sound/core.h> | ||
25 | #include <sound/pcm.h> | ||
26 | #include <sound/pcm_params.h> | ||
27 | #include <sound/soc.h> | ||
28 | |||
29 | #include <asm/mach-jz4740/dma.h> | ||
30 | #include "jz4740-pcm.h" | ||
31 | |||
32 | struct jz4740_runtime_data { | ||
33 | unsigned long dma_period; | ||
34 | dma_addr_t dma_start; | ||
35 | dma_addr_t dma_pos; | ||
36 | dma_addr_t dma_end; | ||
37 | |||
38 | struct jz4740_dma_chan *dma; | ||
39 | |||
40 | dma_addr_t fifo_addr; | ||
41 | }; | ||
42 | |||
43 | /* identify hardware playback capabilities */ | ||
44 | static const struct snd_pcm_hardware jz4740_pcm_hardware = { | ||
45 | .info = SNDRV_PCM_INFO_MMAP | | ||
46 | SNDRV_PCM_INFO_MMAP_VALID | | ||
47 | SNDRV_PCM_INFO_INTERLEAVED | | ||
48 | SNDRV_PCM_INFO_BLOCK_TRANSFER, | ||
49 | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8, | ||
50 | |||
51 | .rates = SNDRV_PCM_RATE_8000_48000, | ||
52 | .channels_min = 1, | ||
53 | .channels_max = 2, | ||
54 | .period_bytes_min = 16, | ||
55 | .period_bytes_max = 2 * PAGE_SIZE, | ||
56 | .periods_min = 2, | ||
57 | .periods_max = 128, | ||
58 | .buffer_bytes_max = 128 * 2 * PAGE_SIZE, | ||
59 | .fifo_size = 32, | ||
60 | }; | ||
61 | |||
62 | static void jz4740_pcm_start_transfer(struct jz4740_runtime_data *prtd, | ||
63 | struct snd_pcm_substream *substream) | ||
64 | { | ||
65 | unsigned long count; | ||
66 | |||
67 | if (prtd->dma_pos == prtd->dma_end) | ||
68 | prtd->dma_pos = prtd->dma_start; | ||
69 | |||
70 | if (prtd->dma_pos + prtd->dma_period > prtd->dma_end) | ||
71 | count = prtd->dma_end - prtd->dma_pos; | ||
72 | else | ||
73 | count = prtd->dma_period; | ||
74 | |||
75 | jz4740_dma_disable(prtd->dma); | ||
76 | |||
77 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
78 | jz4740_dma_set_src_addr(prtd->dma, prtd->dma_pos); | ||
79 | jz4740_dma_set_dst_addr(prtd->dma, prtd->fifo_addr); | ||
80 | } else { | ||
81 | jz4740_dma_set_src_addr(prtd->dma, prtd->fifo_addr); | ||
82 | jz4740_dma_set_dst_addr(prtd->dma, prtd->dma_pos); | ||
83 | } | ||
84 | |||
85 | jz4740_dma_set_transfer_count(prtd->dma, count); | ||
86 | |||
87 | prtd->dma_pos += count; | ||
88 | |||
89 | jz4740_dma_enable(prtd->dma); | ||
90 | } | ||
91 | |||
92 | static void jz4740_pcm_dma_transfer_done(struct jz4740_dma_chan *dma, int err, | ||
93 | void *dev_id) | ||
94 | { | ||
95 | struct snd_pcm_substream *substream = dev_id; | ||
96 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
97 | struct jz4740_runtime_data *prtd = runtime->private_data; | ||
98 | |||
99 | snd_pcm_period_elapsed(substream); | ||
100 | |||
101 | jz4740_pcm_start_transfer(prtd, substream); | ||
102 | } | ||
103 | |||
104 | static int jz4740_pcm_hw_params(struct snd_pcm_substream *substream, | ||
105 | struct snd_pcm_hw_params *params) | ||
106 | { | ||
107 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
108 | struct jz4740_runtime_data *prtd = runtime->private_data; | ||
109 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
110 | struct jz4740_pcm_config *config; | ||
111 | |||
112 | config = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream); | ||
113 | |||
114 | if (!config) | ||
115 | return 0; | ||
116 | |||
117 | if (!prtd->dma) { | ||
118 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) | ||
119 | prtd->dma = jz4740_dma_request(substream, "PCM Capture"); | ||
120 | else | ||
121 | prtd->dma = jz4740_dma_request(substream, "PCM Playback"); | ||
122 | } | ||
123 | |||
124 | if (!prtd->dma) | ||
125 | return -EBUSY; | ||
126 | |||
127 | jz4740_dma_configure(prtd->dma, &config->dma_config); | ||
128 | prtd->fifo_addr = config->fifo_addr; | ||
129 | |||
130 | jz4740_dma_set_complete_cb(prtd->dma, jz4740_pcm_dma_transfer_done); | ||
131 | |||
132 | snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); | ||
133 | runtime->dma_bytes = params_buffer_bytes(params); | ||
134 | |||
135 | prtd->dma_period = params_period_bytes(params); | ||
136 | prtd->dma_start = runtime->dma_addr; | ||
137 | prtd->dma_pos = prtd->dma_start; | ||
138 | prtd->dma_end = prtd->dma_start + runtime->dma_bytes; | ||
139 | |||
140 | return 0; | ||
141 | } | ||
142 | |||
143 | static int jz4740_pcm_hw_free(struct snd_pcm_substream *substream) | ||
144 | { | ||
145 | struct jz4740_runtime_data *prtd = substream->runtime->private_data; | ||
146 | |||
147 | snd_pcm_set_runtime_buffer(substream, NULL); | ||
148 | if (prtd->dma) { | ||
149 | jz4740_dma_free(prtd->dma); | ||
150 | prtd->dma = NULL; | ||
151 | } | ||
152 | |||
153 | return 0; | ||
154 | } | ||
155 | |||
156 | static int jz4740_pcm_prepare(struct snd_pcm_substream *substream) | ||
157 | { | ||
158 | struct jz4740_runtime_data *prtd = substream->runtime->private_data; | ||
159 | |||
160 | if (!prtd->dma) | ||
161 | return -EBUSY; | ||
162 | |||
163 | prtd->dma_pos = prtd->dma_start; | ||
164 | |||
165 | return 0; | ||
166 | } | ||
167 | |||
168 | static int jz4740_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | ||
169 | { | ||
170 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
171 | struct jz4740_runtime_data *prtd = runtime->private_data; | ||
172 | |||
173 | switch (cmd) { | ||
174 | case SNDRV_PCM_TRIGGER_START: | ||
175 | case SNDRV_PCM_TRIGGER_RESUME: | ||
176 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
177 | jz4740_pcm_start_transfer(prtd, substream); | ||
178 | break; | ||
179 | case SNDRV_PCM_TRIGGER_STOP: | ||
180 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
181 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
182 | jz4740_dma_disable(prtd->dma); | ||
183 | break; | ||
184 | default: | ||
185 | break; | ||
186 | } | ||
187 | |||
188 | return 0; | ||
189 | } | ||
190 | |||
191 | static snd_pcm_uframes_t jz4740_pcm_pointer(struct snd_pcm_substream *substream) | ||
192 | { | ||
193 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
194 | struct jz4740_runtime_data *prtd = runtime->private_data; | ||
195 | unsigned long byte_offset; | ||
196 | snd_pcm_uframes_t offset; | ||
197 | struct jz4740_dma_chan *dma = prtd->dma; | ||
198 | |||
199 | /* prtd->dma_pos points to the end of the current transfer. So by | ||
200 | * subtracting prdt->dma_start we get the offset to the end of the | ||
201 | * current period in bytes. By subtracting the residue of the transfer | ||
202 | * we get the current offset in bytes. */ | ||
203 | byte_offset = prtd->dma_pos - prtd->dma_start; | ||
204 | byte_offset -= jz4740_dma_get_residue(dma); | ||
205 | |||
206 | offset = bytes_to_frames(runtime, byte_offset); | ||
207 | if (offset >= runtime->buffer_size) | ||
208 | offset = 0; | ||
209 | |||
210 | return offset; | ||
211 | } | ||
212 | |||
213 | static int jz4740_pcm_open(struct snd_pcm_substream *substream) | ||
214 | { | ||
215 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
216 | struct jz4740_runtime_data *prtd; | ||
217 | |||
218 | prtd = kzalloc(sizeof(*prtd), GFP_KERNEL); | ||
219 | if (prtd == NULL) | ||
220 | return -ENOMEM; | ||
221 | |||
222 | snd_soc_set_runtime_hwparams(substream, &jz4740_pcm_hardware); | ||
223 | |||
224 | runtime->private_data = prtd; | ||
225 | |||
226 | return 0; | ||
227 | } | ||
228 | |||
229 | static int jz4740_pcm_close(struct snd_pcm_substream *substream) | ||
230 | { | ||
231 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
232 | struct jz4740_runtime_data *prtd = runtime->private_data; | ||
233 | |||
234 | kfree(prtd); | ||
235 | |||
236 | return 0; | ||
237 | } | ||
238 | |||
239 | static int jz4740_pcm_mmap(struct snd_pcm_substream *substream, | ||
240 | struct vm_area_struct *vma) | ||
241 | { | ||
242 | return remap_pfn_range(vma, vma->vm_start, | ||
243 | substream->dma_buffer.addr >> PAGE_SHIFT, | ||
244 | vma->vm_end - vma->vm_start, vma->vm_page_prot); | ||
245 | } | ||
246 | |||
247 | static struct snd_pcm_ops jz4740_pcm_ops = { | ||
248 | .open = jz4740_pcm_open, | ||
249 | .close = jz4740_pcm_close, | ||
250 | .ioctl = snd_pcm_lib_ioctl, | ||
251 | .hw_params = jz4740_pcm_hw_params, | ||
252 | .hw_free = jz4740_pcm_hw_free, | ||
253 | .prepare = jz4740_pcm_prepare, | ||
254 | .trigger = jz4740_pcm_trigger, | ||
255 | .pointer = jz4740_pcm_pointer, | ||
256 | .mmap = jz4740_pcm_mmap, | ||
257 | }; | ||
258 | |||
259 | static int jz4740_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) | ||
260 | { | ||
261 | struct snd_pcm_substream *substream = pcm->streams[stream].substream; | ||
262 | struct snd_dma_buffer *buf = &substream->dma_buffer; | ||
263 | size_t size = jz4740_pcm_hardware.buffer_bytes_max; | ||
264 | |||
265 | buf->dev.type = SNDRV_DMA_TYPE_DEV; | ||
266 | buf->dev.dev = pcm->card->dev; | ||
267 | buf->private_data = NULL; | ||
268 | |||
269 | buf->area = dma_alloc_noncoherent(pcm->card->dev, size, | ||
270 | &buf->addr, GFP_KERNEL); | ||
271 | if (!buf->area) | ||
272 | return -ENOMEM; | ||
273 | |||
274 | buf->bytes = size; | ||
275 | |||
276 | return 0; | ||
277 | } | ||
278 | |||
279 | static void jz4740_pcm_free(struct snd_pcm *pcm) | ||
280 | { | ||
281 | struct snd_pcm_substream *substream; | ||
282 | struct snd_dma_buffer *buf; | ||
283 | int stream; | ||
284 | |||
285 | for (stream = 0; stream < SNDRV_PCM_STREAM_LAST; ++stream) { | ||
286 | substream = pcm->streams[stream].substream; | ||
287 | if (!substream) | ||
288 | continue; | ||
289 | |||
290 | buf = &substream->dma_buffer; | ||
291 | if (!buf->area) | ||
292 | continue; | ||
293 | |||
294 | dma_free_noncoherent(pcm->card->dev, buf->bytes, buf->area, | ||
295 | buf->addr); | ||
296 | buf->area = NULL; | ||
297 | } | ||
298 | } | ||
299 | |||
300 | static u64 jz4740_pcm_dmamask = DMA_BIT_MASK(32); | ||
301 | |||
302 | int jz4740_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, | ||
303 | struct snd_pcm *pcm) | ||
304 | { | ||
305 | int ret = 0; | ||
306 | |||
307 | if (!card->dev->dma_mask) | ||
308 | card->dev->dma_mask = &jz4740_pcm_dmamask; | ||
309 | |||
310 | if (!card->dev->coherent_dma_mask) | ||
311 | card->dev->coherent_dma_mask = DMA_BIT_MASK(32); | ||
312 | |||
313 | if (dai->playback.channels_min) { | ||
314 | ret = jz4740_pcm_preallocate_dma_buffer(pcm, | ||
315 | SNDRV_PCM_STREAM_PLAYBACK); | ||
316 | if (ret) | ||
317 | goto err; | ||
318 | } | ||
319 | |||
320 | if (dai->capture.channels_min) { | ||
321 | ret = jz4740_pcm_preallocate_dma_buffer(pcm, | ||
322 | SNDRV_PCM_STREAM_CAPTURE); | ||
323 | if (ret) | ||
324 | goto err; | ||
325 | } | ||
326 | |||
327 | err: | ||
328 | return ret; | ||
329 | } | ||
330 | |||
331 | struct snd_soc_platform jz4740_soc_platform = { | ||
332 | .name = "jz4740-pcm", | ||
333 | .pcm_ops = &jz4740_pcm_ops, | ||
334 | .pcm_new = jz4740_pcm_new, | ||
335 | .pcm_free = jz4740_pcm_free, | ||
336 | }; | ||
337 | EXPORT_SYMBOL_GPL(jz4740_soc_platform); | ||
338 | |||
339 | static int __devinit jz4740_pcm_probe(struct platform_device *pdev) | ||
340 | { | ||
341 | return snd_soc_register_platform(&jz4740_soc_platform); | ||
342 | } | ||
343 | |||
344 | static int __devexit jz4740_pcm_remove(struct platform_device *pdev) | ||
345 | { | ||
346 | snd_soc_unregister_platform(&jz4740_soc_platform); | ||
347 | return 0; | ||
348 | } | ||
349 | |||
350 | static struct platform_driver jz4740_pcm_driver = { | ||
351 | .probe = jz4740_pcm_probe, | ||
352 | .remove = __devexit_p(jz4740_pcm_remove), | ||
353 | .driver = { | ||
354 | .name = "jz4740-pcm", | ||
355 | .owner = THIS_MODULE, | ||
356 | }, | ||
357 | }; | ||
358 | |||
359 | static int __init jz4740_soc_platform_init(void) | ||
360 | { | ||
361 | return platform_driver_register(&jz4740_pcm_driver); | ||
362 | } | ||
363 | module_init(jz4740_soc_platform_init); | ||
364 | |||
365 | static void __exit jz4740_soc_platform_exit(void) | ||
366 | { | ||
367 | return platform_driver_unregister(&jz4740_pcm_driver); | ||
368 | } | ||
369 | module_exit(jz4740_soc_platform_exit); | ||
370 | |||
371 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); | ||
372 | MODULE_DESCRIPTION("Ingenic SoC JZ4740 PCM driver"); | ||
373 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/jz4740/jz4740-pcm.h b/sound/soc/jz4740/jz4740-pcm.h new file mode 100644 index 000000000000..e3f221e2779c --- /dev/null +++ b/sound/soc/jz4740/jz4740-pcm.h | |||
@@ -0,0 +1,22 @@ | |||
1 | /* | ||
2 | * | ||
3 | * This program is free software; you can redistribute it and/or modify | ||
4 | * it under the terms of the GNU General Public License version 2 as | ||
5 | * published by the Free Software Foundation. | ||
6 | */ | ||
7 | |||
8 | #ifndef _JZ4740_PCM_H | ||
9 | #define _JZ4740_PCM_H | ||
10 | |||
11 | #include <linux/dma-mapping.h> | ||
12 | #include <asm/mach-jz4740/dma.h> | ||
13 | |||
14 | /* platform data */ | ||
15 | extern struct snd_soc_platform jz4740_soc_platform; | ||
16 | |||
17 | struct jz4740_pcm_config { | ||
18 | struct jz4740_dma_config dma_config; | ||
19 | phys_addr_t fifo_addr; | ||
20 | }; | ||
21 | |||
22 | #endif | ||
diff --git a/sound/soc/jz4740/qi_lb60.c b/sound/soc/jz4740/qi_lb60.c new file mode 100644 index 000000000000..f15f4918f15f --- /dev/null +++ b/sound/soc/jz4740/qi_lb60.c | |||
@@ -0,0 +1,166 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009, Lars-Peter Clausen <lars@metafoo.de> | ||
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 | * You should have received a copy of the GNU General Public License along | ||
9 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
10 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
11 | * | ||
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 <linux/gpio.h> | ||
24 | |||
25 | #include "../codecs/jz4740.h" | ||
26 | #include "jz4740-pcm.h" | ||
27 | #include "jz4740-i2s.h" | ||
28 | |||
29 | |||
30 | #define QI_LB60_SND_GPIO JZ_GPIO_PORTB(29) | ||
31 | #define QI_LB60_AMP_GPIO JZ_GPIO_PORTD(4) | ||
32 | |||
33 | static int qi_lb60_spk_event(struct snd_soc_dapm_widget *widget, | ||
34 | struct snd_kcontrol *ctrl, int event) | ||
35 | { | ||
36 | int on = 0; | ||
37 | if (event & SND_SOC_DAPM_POST_PMU) | ||
38 | on = 1; | ||
39 | else if (event & SND_SOC_DAPM_PRE_PMD) | ||
40 | on = 0; | ||
41 | |||
42 | gpio_set_value(QI_LB60_SND_GPIO, on); | ||
43 | gpio_set_value(QI_LB60_AMP_GPIO, on); | ||
44 | |||
45 | return 0; | ||
46 | } | ||
47 | |||
48 | static const struct snd_soc_dapm_widget qi_lb60_widgets[] = { | ||
49 | SND_SOC_DAPM_SPK("Speaker", qi_lb60_spk_event), | ||
50 | SND_SOC_DAPM_MIC("Mic", NULL), | ||
51 | }; | ||
52 | |||
53 | static const struct snd_soc_dapm_route qi_lb60_routes[] = { | ||
54 | {"Mic", NULL, "MIC"}, | ||
55 | {"Speaker", NULL, "LOUT"}, | ||
56 | {"Speaker", NULL, "ROUT"}, | ||
57 | }; | ||
58 | |||
59 | #define QI_LB60_DAIFMT (SND_SOC_DAIFMT_I2S | \ | ||
60 | SND_SOC_DAIFMT_NB_NF | \ | ||
61 | SND_SOC_DAIFMT_CBM_CFM) | ||
62 | |||
63 | static int qi_lb60_codec_init(struct snd_soc_codec *codec) | ||
64 | { | ||
65 | int ret; | ||
66 | struct snd_soc_dai *cpu_dai = codec->socdev->card->dai_link->cpu_dai; | ||
67 | |||
68 | snd_soc_dapm_nc_pin(codec, "LIN"); | ||
69 | snd_soc_dapm_nc_pin(codec, "RIN"); | ||
70 | |||
71 | ret = snd_soc_dai_set_fmt(cpu_dai, QI_LB60_DAIFMT); | ||
72 | if (ret < 0) { | ||
73 | dev_err(codec->dev, "Failed to set cpu dai format: %d\n", ret); | ||
74 | return ret; | ||
75 | } | ||
76 | |||
77 | snd_soc_dapm_new_controls(codec, qi_lb60_widgets, ARRAY_SIZE(qi_lb60_widgets)); | ||
78 | snd_soc_dapm_add_routes(codec, qi_lb60_routes, ARRAY_SIZE(qi_lb60_routes)); | ||
79 | snd_soc_dapm_sync(codec); | ||
80 | |||
81 | return 0; | ||
82 | } | ||
83 | |||
84 | static struct snd_soc_dai_link qi_lb60_dai = { | ||
85 | .name = "jz4740", | ||
86 | .stream_name = "jz4740", | ||
87 | .cpu_dai = &jz4740_i2s_dai, | ||
88 | .codec_dai = &jz4740_codec_dai, | ||
89 | .init = qi_lb60_codec_init, | ||
90 | }; | ||
91 | |||
92 | static struct snd_soc_card qi_lb60 = { | ||
93 | .name = "QI LB60", | ||
94 | .dai_link = &qi_lb60_dai, | ||
95 | .num_links = 1, | ||
96 | .platform = &jz4740_soc_platform, | ||
97 | }; | ||
98 | |||
99 | static struct snd_soc_device qi_lb60_snd_devdata = { | ||
100 | .card = &qi_lb60, | ||
101 | .codec_dev = &soc_codec_dev_jz4740_codec, | ||
102 | }; | ||
103 | |||
104 | static struct platform_device *qi_lb60_snd_device; | ||
105 | |||
106 | static int __init qi_lb60_init(void) | ||
107 | { | ||
108 | int ret; | ||
109 | |||
110 | qi_lb60_snd_device = platform_device_alloc("soc-audio", -1); | ||
111 | |||
112 | if (!qi_lb60_snd_device) | ||
113 | return -ENOMEM; | ||
114 | |||
115 | ret = gpio_request(QI_LB60_SND_GPIO, "SND"); | ||
116 | if (ret) { | ||
117 | pr_err("qi_lb60 snd: Failed to request SND GPIO(%d): %d\n", | ||
118 | QI_LB60_SND_GPIO, ret); | ||
119 | goto err_device_put; | ||
120 | } | ||
121 | |||
122 | ret = gpio_request(QI_LB60_AMP_GPIO, "AMP"); | ||
123 | if (ret) { | ||
124 | pr_err("qi_lb60 snd: Failed to request AMP GPIO(%d): %d\n", | ||
125 | QI_LB60_AMP_GPIO, ret); | ||
126 | goto err_gpio_free_snd; | ||
127 | } | ||
128 | |||
129 | gpio_direction_output(QI_LB60_SND_GPIO, 0); | ||
130 | gpio_direction_output(QI_LB60_AMP_GPIO, 0); | ||
131 | |||
132 | platform_set_drvdata(qi_lb60_snd_device, &qi_lb60_snd_devdata); | ||
133 | qi_lb60_snd_devdata.dev = &qi_lb60_snd_device->dev; | ||
134 | |||
135 | ret = platform_device_add(qi_lb60_snd_device); | ||
136 | if (ret) { | ||
137 | pr_err("qi_lb60 snd: Failed to add snd soc device: %d\n", ret); | ||
138 | goto err_unset_pdata; | ||
139 | } | ||
140 | |||
141 | return 0; | ||
142 | |||
143 | err_unset_pdata: | ||
144 | platform_set_drvdata(qi_lb60_snd_device, NULL); | ||
145 | /*err_gpio_free_amp:*/ | ||
146 | gpio_free(QI_LB60_AMP_GPIO); | ||
147 | err_gpio_free_snd: | ||
148 | gpio_free(QI_LB60_SND_GPIO); | ||
149 | err_device_put: | ||
150 | platform_device_put(qi_lb60_snd_device); | ||
151 | |||
152 | return ret; | ||
153 | } | ||
154 | module_init(qi_lb60_init); | ||
155 | |||
156 | static void __exit qi_lb60_exit(void) | ||
157 | { | ||
158 | gpio_free(QI_LB60_AMP_GPIO); | ||
159 | gpio_free(QI_LB60_SND_GPIO); | ||
160 | platform_device_unregister(qi_lb60_snd_device); | ||
161 | } | ||
162 | module_exit(qi_lb60_exit); | ||
163 | |||
164 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); | ||
165 | MODULE_DESCRIPTION("ALSA SoC QI LB60 Audio support"); | ||
166 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/soc/kirkwood/Kconfig b/sound/soc/kirkwood/Kconfig new file mode 100644 index 000000000000..16ec2a2dba4d --- /dev/null +++ b/sound/soc/kirkwood/Kconfig | |||
@@ -0,0 +1,20 @@ | |||
1 | config SND_KIRKWOOD_SOC | ||
2 | tristate "SoC Audio for the Marvell Kirkwood chip" | ||
3 | depends on ARCH_KIRKWOOD | ||
4 | help | ||
5 | Say Y or M if you want to add support for codecs attached to | ||
6 | the Kirkwood I2S interface. You will also need to select the | ||
7 | audio interfaces to support below. | ||
8 | |||
9 | config SND_KIRKWOOD_SOC_I2S | ||
10 | tristate | ||
11 | |||
12 | config SND_KIRKWOOD_SOC_OPENRD | ||
13 | tristate "SoC Audio support for Kirkwood Openrd Client" | ||
14 | depends on SND_KIRKWOOD_SOC && MACH_OPENRD_CLIENT | ||
15 | select SND_KIRKWOOD_SOC_I2S | ||
16 | select SND_SOC_CS42L51 | ||
17 | help | ||
18 | Say Y if you want to add support for SoC audio on | ||
19 | Openrd Client. | ||
20 | |||
diff --git a/sound/soc/kirkwood/Makefile b/sound/soc/kirkwood/Makefile new file mode 100644 index 000000000000..33a16dcab5b5 --- /dev/null +++ b/sound/soc/kirkwood/Makefile | |||
@@ -0,0 +1,9 @@ | |||
1 | snd-soc-kirkwood-objs := kirkwood-dma.o | ||
2 | snd-soc-kirkwood-i2s-objs := kirkwood-i2s.o | ||
3 | |||
4 | obj-$(CONFIG_SND_KIRKWOOD_SOC) += snd-soc-kirkwood.o | ||
5 | obj-$(CONFIG_SND_KIRKWOOD_SOC_I2S) += snd-soc-kirkwood-i2s.o | ||
6 | |||
7 | snd-soc-openrd-objs := kirkwood-openrd.o | ||
8 | |||
9 | obj-$(CONFIG_SND_KIRKWOOD_SOC_OPENRD) += snd-soc-openrd.o | ||
diff --git a/sound/soc/kirkwood/kirkwood-dma.c b/sound/soc/kirkwood/kirkwood-dma.c new file mode 100644 index 000000000000..a30205be3e2b --- /dev/null +++ b/sound/soc/kirkwood/kirkwood-dma.c | |||
@@ -0,0 +1,383 @@ | |||
1 | /* | ||
2 | * kirkwood-dma.c | ||
3 | * | ||
4 | * (c) 2010 Arnaud Patard <apatard@mandriva.com> | ||
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 | #include <linux/init.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/device.h> | ||
15 | #include <linux/io.h> | ||
16 | #include <linux/slab.h> | ||
17 | #include <linux/interrupt.h> | ||
18 | #include <linux/dma-mapping.h> | ||
19 | #include <linux/mbus.h> | ||
20 | #include <sound/soc.h> | ||
21 | #include "kirkwood-dma.h" | ||
22 | #include "kirkwood.h" | ||
23 | |||
24 | #define KIRKWOOD_RATES \ | ||
25 | (SNDRV_PCM_RATE_44100 | \ | ||
26 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000) | ||
27 | #define KIRKWOOD_FORMATS \ | ||
28 | (SNDRV_PCM_FMTBIT_S16_LE | \ | ||
29 | SNDRV_PCM_FMTBIT_S24_LE | \ | ||
30 | SNDRV_PCM_FMTBIT_S32_LE) | ||
31 | |||
32 | struct kirkwood_dma_priv { | ||
33 | struct snd_pcm_substream *play_stream; | ||
34 | struct snd_pcm_substream *rec_stream; | ||
35 | struct kirkwood_dma_data *data; | ||
36 | }; | ||
37 | |||
38 | static struct snd_pcm_hardware kirkwood_dma_snd_hw = { | ||
39 | .info = (SNDRV_PCM_INFO_INTERLEAVED | | ||
40 | SNDRV_PCM_INFO_MMAP | | ||
41 | SNDRV_PCM_INFO_MMAP_VALID | | ||
42 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | ||
43 | SNDRV_PCM_INFO_PAUSE), | ||
44 | .formats = KIRKWOOD_FORMATS, | ||
45 | .rates = KIRKWOOD_RATES, | ||
46 | .rate_min = 44100, | ||
47 | .rate_max = 96000, | ||
48 | .channels_min = 1, | ||
49 | .channels_max = 2, | ||
50 | .buffer_bytes_max = KIRKWOOD_SND_MAX_PERIOD_BYTES * KIRKWOOD_SND_MAX_PERIODS, | ||
51 | .period_bytes_min = KIRKWOOD_SND_MIN_PERIOD_BYTES, | ||
52 | .period_bytes_max = KIRKWOOD_SND_MAX_PERIOD_BYTES, | ||
53 | .periods_min = KIRKWOOD_SND_MIN_PERIODS, | ||
54 | .periods_max = KIRKWOOD_SND_MAX_PERIODS, | ||
55 | .fifo_size = 0, | ||
56 | }; | ||
57 | |||
58 | static u64 kirkwood_dma_dmamask = 0xFFFFFFFFUL; | ||
59 | |||
60 | static irqreturn_t kirkwood_dma_irq(int irq, void *dev_id) | ||
61 | { | ||
62 | struct kirkwood_dma_priv *prdata = dev_id; | ||
63 | struct kirkwood_dma_data *priv = prdata->data; | ||
64 | unsigned long mask, status, cause; | ||
65 | |||
66 | mask = readl(priv->io + KIRKWOOD_INT_MASK); | ||
67 | status = readl(priv->io + KIRKWOOD_INT_CAUSE) & mask; | ||
68 | |||
69 | cause = readl(priv->io + KIRKWOOD_ERR_CAUSE); | ||
70 | if (unlikely(cause)) { | ||
71 | printk(KERN_WARNING "%s: got err interrupt 0x%lx\n", | ||
72 | __func__, cause); | ||
73 | writel(cause, priv->io + KIRKWOOD_ERR_CAUSE); | ||
74 | return IRQ_HANDLED; | ||
75 | } | ||
76 | |||
77 | /* we've enabled only bytes interrupts ... */ | ||
78 | if (status & ~(KIRKWOOD_INT_CAUSE_PLAY_BYTES | \ | ||
79 | KIRKWOOD_INT_CAUSE_REC_BYTES)) { | ||
80 | printk(KERN_WARNING "%s: unexpected interrupt %lx\n", | ||
81 | __func__, status); | ||
82 | return IRQ_NONE; | ||
83 | } | ||
84 | |||
85 | /* ack int */ | ||
86 | writel(status, priv->io + KIRKWOOD_INT_CAUSE); | ||
87 | |||
88 | if (status & KIRKWOOD_INT_CAUSE_PLAY_BYTES) | ||
89 | snd_pcm_period_elapsed(prdata->play_stream); | ||
90 | |||
91 | if (status & KIRKWOOD_INT_CAUSE_REC_BYTES) | ||
92 | snd_pcm_period_elapsed(prdata->rec_stream); | ||
93 | |||
94 | return IRQ_HANDLED; | ||
95 | } | ||
96 | |||
97 | static void kirkwood_dma_conf_mbus_windows(void __iomem *base, int win, | ||
98 | unsigned long dma, | ||
99 | struct mbus_dram_target_info *dram) | ||
100 | { | ||
101 | int i; | ||
102 | |||
103 | /* First disable and clear windows */ | ||
104 | writel(0, base + KIRKWOOD_AUDIO_WIN_CTRL_REG(win)); | ||
105 | writel(0, base + KIRKWOOD_AUDIO_WIN_BASE_REG(win)); | ||
106 | |||
107 | /* try to find matching cs for current dma address */ | ||
108 | for (i = 0; i < dram->num_cs; i++) { | ||
109 | struct mbus_dram_window *cs = dram->cs + i; | ||
110 | if ((cs->base & 0xffff0000) < (dma & 0xffff0000)) { | ||
111 | writel(cs->base & 0xffff0000, | ||
112 | base + KIRKWOOD_AUDIO_WIN_BASE_REG(win)); | ||
113 | writel(((cs->size - 1) & 0xffff0000) | | ||
114 | (cs->mbus_attr << 8) | | ||
115 | (dram->mbus_dram_target_id << 4) | 1, | ||
116 | base + KIRKWOOD_AUDIO_WIN_CTRL_REG(win)); | ||
117 | } | ||
118 | } | ||
119 | } | ||
120 | |||
121 | static int kirkwood_dma_open(struct snd_pcm_substream *substream) | ||
122 | { | ||
123 | int err; | ||
124 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
125 | struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; | ||
126 | struct snd_soc_dai *cpu_dai = soc_runtime->dai->cpu_dai; | ||
127 | struct kirkwood_dma_data *priv; | ||
128 | struct kirkwood_dma_priv *prdata = cpu_dai->private_data; | ||
129 | unsigned long addr; | ||
130 | |||
131 | priv = snd_soc_dai_get_dma_data(cpu_dai, substream); | ||
132 | snd_soc_set_runtime_hwparams(substream, &kirkwood_dma_snd_hw); | ||
133 | |||
134 | /* Ensure that all constraints linked to dma burst are fullfilled */ | ||
135 | err = snd_pcm_hw_constraint_minmax(runtime, | ||
136 | SNDRV_PCM_HW_PARAM_BUFFER_BYTES, | ||
137 | priv->burst * 2, | ||
138 | KIRKWOOD_AUDIO_BUF_MAX-1); | ||
139 | if (err < 0) | ||
140 | return err; | ||
141 | |||
142 | err = snd_pcm_hw_constraint_step(runtime, 0, | ||
143 | SNDRV_PCM_HW_PARAM_BUFFER_BYTES, | ||
144 | priv->burst); | ||
145 | if (err < 0) | ||
146 | return err; | ||
147 | |||
148 | err = snd_pcm_hw_constraint_step(substream->runtime, 0, | ||
149 | SNDRV_PCM_HW_PARAM_PERIOD_BYTES, | ||
150 | priv->burst); | ||
151 | if (err < 0) | ||
152 | return err; | ||
153 | |||
154 | if (soc_runtime->dai->cpu_dai->private_data == NULL) { | ||
155 | prdata = kzalloc(sizeof(struct kirkwood_dma_priv), GFP_KERNEL); | ||
156 | if (prdata == NULL) | ||
157 | return -ENOMEM; | ||
158 | |||
159 | prdata->data = priv; | ||
160 | |||
161 | err = request_irq(priv->irq, kirkwood_dma_irq, IRQF_SHARED, | ||
162 | "kirkwood-i2s", prdata); | ||
163 | if (err) { | ||
164 | kfree(prdata); | ||
165 | return -EBUSY; | ||
166 | } | ||
167 | |||
168 | soc_runtime->dai->cpu_dai->private_data = prdata; | ||
169 | |||
170 | /* | ||
171 | * Enable Error interrupts. We're only ack'ing them but | ||
172 | * it's usefull for diagnostics | ||
173 | */ | ||
174 | writel((unsigned long)-1, priv->io + KIRKWOOD_ERR_MASK); | ||
175 | } | ||
176 | |||
177 | addr = virt_to_phys(substream->dma_buffer.area); | ||
178 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
179 | prdata->play_stream = substream; | ||
180 | kirkwood_dma_conf_mbus_windows(priv->io, | ||
181 | KIRKWOOD_PLAYBACK_WIN, addr, priv->dram); | ||
182 | } else { | ||
183 | prdata->rec_stream = substream; | ||
184 | kirkwood_dma_conf_mbus_windows(priv->io, | ||
185 | KIRKWOOD_RECORD_WIN, addr, priv->dram); | ||
186 | } | ||
187 | |||
188 | return 0; | ||
189 | } | ||
190 | |||
191 | static int kirkwood_dma_close(struct snd_pcm_substream *substream) | ||
192 | { | ||
193 | struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; | ||
194 | struct snd_soc_dai *cpu_dai = soc_runtime->dai->cpu_dai; | ||
195 | struct kirkwood_dma_priv *prdata = cpu_dai->private_data; | ||
196 | struct kirkwood_dma_data *priv; | ||
197 | |||
198 | priv = snd_soc_dai_get_dma_data(cpu_dai, substream); | ||
199 | |||
200 | if (!prdata || !priv) | ||
201 | return 0; | ||
202 | |||
203 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
204 | prdata->play_stream = NULL; | ||
205 | else | ||
206 | prdata->rec_stream = NULL; | ||
207 | |||
208 | if (!prdata->play_stream && !prdata->rec_stream) { | ||
209 | writel(0, priv->io + KIRKWOOD_ERR_MASK); | ||
210 | free_irq(priv->irq, prdata); | ||
211 | kfree(prdata); | ||
212 | soc_runtime->dai->cpu_dai->private_data = NULL; | ||
213 | } | ||
214 | |||
215 | return 0; | ||
216 | } | ||
217 | |||
218 | static int kirkwood_dma_hw_params(struct snd_pcm_substream *substream, | ||
219 | struct snd_pcm_hw_params *params) | ||
220 | { | ||
221 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
222 | |||
223 | snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); | ||
224 | runtime->dma_bytes = params_buffer_bytes(params); | ||
225 | |||
226 | return 0; | ||
227 | } | ||
228 | |||
229 | static int kirkwood_dma_hw_free(struct snd_pcm_substream *substream) | ||
230 | { | ||
231 | snd_pcm_set_runtime_buffer(substream, NULL); | ||
232 | return 0; | ||
233 | } | ||
234 | |||
235 | static int kirkwood_dma_prepare(struct snd_pcm_substream *substream) | ||
236 | { | ||
237 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
238 | struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; | ||
239 | struct snd_soc_dai *cpu_dai = soc_runtime->dai->cpu_dai; | ||
240 | struct kirkwood_dma_data *priv; | ||
241 | unsigned long size, count; | ||
242 | |||
243 | priv = snd_soc_dai_get_dma_data(cpu_dai, substream); | ||
244 | |||
245 | /* compute buffer size in term of "words" as requested in specs */ | ||
246 | size = frames_to_bytes(runtime, runtime->buffer_size); | ||
247 | size = (size>>2)-1; | ||
248 | count = snd_pcm_lib_period_bytes(substream); | ||
249 | |||
250 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
251 | writel(count, priv->io + KIRKWOOD_PLAY_BYTE_INT_COUNT); | ||
252 | writel(runtime->dma_addr, priv->io + KIRKWOOD_PLAY_BUF_ADDR); | ||
253 | writel(size, priv->io + KIRKWOOD_PLAY_BUF_SIZE); | ||
254 | } else { | ||
255 | writel(count, priv->io + KIRKWOOD_REC_BYTE_INT_COUNT); | ||
256 | writel(runtime->dma_addr, priv->io + KIRKWOOD_REC_BUF_ADDR); | ||
257 | writel(size, priv->io + KIRKWOOD_REC_BUF_SIZE); | ||
258 | } | ||
259 | |||
260 | |||
261 | return 0; | ||
262 | } | ||
263 | |||
264 | static snd_pcm_uframes_t kirkwood_dma_pointer(struct snd_pcm_substream | ||
265 | *substream) | ||
266 | { | ||
267 | struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; | ||
268 | struct snd_soc_dai *cpu_dai = soc_runtime->dai->cpu_dai; | ||
269 | struct kirkwood_dma_data *priv; | ||
270 | snd_pcm_uframes_t count; | ||
271 | |||
272 | priv = snd_soc_dai_get_dma_data(cpu_dai, substream); | ||
273 | |||
274 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
275 | count = bytes_to_frames(substream->runtime, | ||
276 | readl(priv->io + KIRKWOOD_PLAY_BYTE_COUNT)); | ||
277 | else | ||
278 | count = bytes_to_frames(substream->runtime, | ||
279 | readl(priv->io + KIRKWOOD_REC_BYTE_COUNT)); | ||
280 | |||
281 | return count; | ||
282 | } | ||
283 | |||
284 | struct snd_pcm_ops kirkwood_dma_ops = { | ||
285 | .open = kirkwood_dma_open, | ||
286 | .close = kirkwood_dma_close, | ||
287 | .ioctl = snd_pcm_lib_ioctl, | ||
288 | .hw_params = kirkwood_dma_hw_params, | ||
289 | .hw_free = kirkwood_dma_hw_free, | ||
290 | .prepare = kirkwood_dma_prepare, | ||
291 | .pointer = kirkwood_dma_pointer, | ||
292 | }; | ||
293 | |||
294 | static int kirkwood_dma_preallocate_dma_buffer(struct snd_pcm *pcm, | ||
295 | int stream) | ||
296 | { | ||
297 | struct snd_pcm_substream *substream = pcm->streams[stream].substream; | ||
298 | struct snd_dma_buffer *buf = &substream->dma_buffer; | ||
299 | size_t size = kirkwood_dma_snd_hw.buffer_bytes_max; | ||
300 | |||
301 | buf->dev.type = SNDRV_DMA_TYPE_DEV; | ||
302 | buf->dev.dev = pcm->card->dev; | ||
303 | buf->area = dma_alloc_coherent(pcm->card->dev, size, | ||
304 | &buf->addr, GFP_KERNEL); | ||
305 | if (!buf->area) | ||
306 | return -ENOMEM; | ||
307 | buf->bytes = size; | ||
308 | buf->private_data = NULL; | ||
309 | |||
310 | return 0; | ||
311 | } | ||
312 | |||
313 | static int kirkwood_dma_new(struct snd_card *card, | ||
314 | struct snd_soc_dai *dai, struct snd_pcm *pcm) | ||
315 | { | ||
316 | int ret; | ||
317 | |||
318 | if (!card->dev->dma_mask) | ||
319 | card->dev->dma_mask = &kirkwood_dma_dmamask; | ||
320 | if (!card->dev->coherent_dma_mask) | ||
321 | card->dev->coherent_dma_mask = 0xffffffff; | ||
322 | |||
323 | if (dai->playback.channels_min) { | ||
324 | ret = kirkwood_dma_preallocate_dma_buffer(pcm, | ||
325 | SNDRV_PCM_STREAM_PLAYBACK); | ||
326 | if (ret) | ||
327 | return ret; | ||
328 | } | ||
329 | |||
330 | if (dai->capture.channels_min) { | ||
331 | ret = kirkwood_dma_preallocate_dma_buffer(pcm, | ||
332 | SNDRV_PCM_STREAM_CAPTURE); | ||
333 | if (ret) | ||
334 | return ret; | ||
335 | } | ||
336 | |||
337 | return 0; | ||
338 | } | ||
339 | |||
340 | static void kirkwood_dma_free_dma_buffers(struct snd_pcm *pcm) | ||
341 | { | ||
342 | struct snd_pcm_substream *substream; | ||
343 | struct snd_dma_buffer *buf; | ||
344 | int stream; | ||
345 | |||
346 | for (stream = 0; stream < 2; stream++) { | ||
347 | substream = pcm->streams[stream].substream; | ||
348 | if (!substream) | ||
349 | continue; | ||
350 | buf = &substream->dma_buffer; | ||
351 | if (!buf->area) | ||
352 | continue; | ||
353 | |||
354 | dma_free_coherent(pcm->card->dev, buf->bytes, | ||
355 | buf->area, buf->addr); | ||
356 | buf->area = NULL; | ||
357 | } | ||
358 | } | ||
359 | |||
360 | struct snd_soc_platform kirkwood_soc_platform = { | ||
361 | .name = "kirkwood-dma", | ||
362 | .pcm_ops = &kirkwood_dma_ops, | ||
363 | .pcm_new = kirkwood_dma_new, | ||
364 | .pcm_free = kirkwood_dma_free_dma_buffers, | ||
365 | }; | ||
366 | EXPORT_SYMBOL_GPL(kirkwood_soc_platform); | ||
367 | |||
368 | static int __init kirkwood_soc_platform_init(void) | ||
369 | { | ||
370 | return snd_soc_register_platform(&kirkwood_soc_platform); | ||
371 | } | ||
372 | module_init(kirkwood_soc_platform_init); | ||
373 | |||
374 | static void __exit kirkwood_soc_platform_exit(void) | ||
375 | { | ||
376 | snd_soc_unregister_platform(&kirkwood_soc_platform); | ||
377 | } | ||
378 | module_exit(kirkwood_soc_platform_exit); | ||
379 | |||
380 | MODULE_AUTHOR("Arnaud Patard <apatard@mandriva.com>"); | ||
381 | MODULE_DESCRIPTION("Marvell Kirkwood Audio DMA module"); | ||
382 | MODULE_LICENSE("GPL"); | ||
383 | |||
diff --git a/sound/soc/kirkwood/kirkwood-dma.h b/sound/soc/kirkwood/kirkwood-dma.h new file mode 100644 index 000000000000..ba4454cd34f1 --- /dev/null +++ b/sound/soc/kirkwood/kirkwood-dma.h | |||
@@ -0,0 +1,17 @@ | |||
1 | /* | ||
2 | * kirkwood-dma.h | ||
3 | * | ||
4 | * (c) 2010 Arnaud Patard <apatard@mandriva.com> | ||
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 | #ifndef _KIRKWOOD_DMA_H | ||
13 | #define _KIRKWOOD_DMA_H | ||
14 | |||
15 | extern struct snd_soc_platform kirkwood_soc_platform; | ||
16 | |||
17 | #endif | ||
diff --git a/sound/soc/kirkwood/kirkwood-i2s.c b/sound/soc/kirkwood/kirkwood-i2s.c new file mode 100644 index 000000000000..981ffc2a13c8 --- /dev/null +++ b/sound/soc/kirkwood/kirkwood-i2s.c | |||
@@ -0,0 +1,495 @@ | |||
1 | /* | ||
2 | * kirkwood-i2s.c | ||
3 | * | ||
4 | * (c) 2010 Arnaud Patard <apatard@mandriva.com> | ||
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 | #include <linux/init.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/platform_device.h> | ||
15 | #include <linux/io.h> | ||
16 | #include <linux/slab.h> | ||
17 | #include <linux/mbus.h> | ||
18 | #include <linux/delay.h> | ||
19 | #include <sound/pcm.h> | ||
20 | #include <sound/pcm_params.h> | ||
21 | #include <sound/soc.h> | ||
22 | #include <plat/audio.h> | ||
23 | #include "kirkwood-i2s.h" | ||
24 | #include "kirkwood.h" | ||
25 | |||
26 | #define DRV_NAME "kirkwood-i2s" | ||
27 | |||
28 | #define KIRKWOOD_I2S_RATES \ | ||
29 | (SNDRV_PCM_RATE_44100 | \ | ||
30 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000) | ||
31 | #define KIRKWOOD_I2S_FORMATS \ | ||
32 | (SNDRV_PCM_FMTBIT_S16_LE | \ | ||
33 | SNDRV_PCM_FMTBIT_S24_LE | \ | ||
34 | SNDRV_PCM_FMTBIT_S32_LE) | ||
35 | |||
36 | |||
37 | struct snd_soc_dai kirkwood_i2s_dai; | ||
38 | static struct kirkwood_dma_data *priv; | ||
39 | |||
40 | static int kirkwood_i2s_set_fmt(struct snd_soc_dai *cpu_dai, | ||
41 | unsigned int fmt) | ||
42 | { | ||
43 | unsigned long mask; | ||
44 | unsigned long value; | ||
45 | |||
46 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
47 | case SND_SOC_DAIFMT_RIGHT_J: | ||
48 | mask = KIRKWOOD_I2S_CTL_RJ; | ||
49 | break; | ||
50 | case SND_SOC_DAIFMT_LEFT_J: | ||
51 | mask = KIRKWOOD_I2S_CTL_LJ; | ||
52 | break; | ||
53 | case SND_SOC_DAIFMT_I2S: | ||
54 | mask = KIRKWOOD_I2S_CTL_I2S; | ||
55 | break; | ||
56 | default: | ||
57 | return -EINVAL; | ||
58 | } | ||
59 | |||
60 | /* | ||
61 | * Set same format for playback and record | ||
62 | * This avoids some troubles. | ||
63 | */ | ||
64 | value = readl(priv->io+KIRKWOOD_I2S_PLAYCTL); | ||
65 | value &= ~KIRKWOOD_I2S_CTL_JUST_MASK; | ||
66 | value |= mask; | ||
67 | writel(value, priv->io+KIRKWOOD_I2S_PLAYCTL); | ||
68 | |||
69 | value = readl(priv->io+KIRKWOOD_I2S_RECCTL); | ||
70 | value &= ~KIRKWOOD_I2S_CTL_JUST_MASK; | ||
71 | value |= mask; | ||
72 | writel(value, priv->io+KIRKWOOD_I2S_RECCTL); | ||
73 | |||
74 | return 0; | ||
75 | } | ||
76 | |||
77 | static inline void kirkwood_set_dco(void __iomem *io, unsigned long rate) | ||
78 | { | ||
79 | unsigned long value; | ||
80 | |||
81 | value = KIRKWOOD_DCO_CTL_OFFSET_0; | ||
82 | switch (rate) { | ||
83 | default: | ||
84 | case 44100: | ||
85 | value |= KIRKWOOD_DCO_CTL_FREQ_11; | ||
86 | break; | ||
87 | case 48000: | ||
88 | value |= KIRKWOOD_DCO_CTL_FREQ_12; | ||
89 | break; | ||
90 | case 96000: | ||
91 | value |= KIRKWOOD_DCO_CTL_FREQ_24; | ||
92 | break; | ||
93 | } | ||
94 | writel(value, io + KIRKWOOD_DCO_CTL); | ||
95 | |||
96 | /* wait for dco locked */ | ||
97 | do { | ||
98 | cpu_relax(); | ||
99 | value = readl(io + KIRKWOOD_DCO_SPCR_STATUS); | ||
100 | value &= KIRKWOOD_DCO_SPCR_STATUS; | ||
101 | } while (value == 0); | ||
102 | } | ||
103 | |||
104 | static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream, | ||
105 | struct snd_pcm_hw_params *params, | ||
106 | struct snd_soc_dai *dai) | ||
107 | { | ||
108 | unsigned int i2s_reg, reg; | ||
109 | unsigned long i2s_value, value; | ||
110 | |||
111 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
112 | i2s_reg = KIRKWOOD_I2S_PLAYCTL; | ||
113 | reg = KIRKWOOD_PLAYCTL; | ||
114 | } else { | ||
115 | i2s_reg = KIRKWOOD_I2S_RECCTL; | ||
116 | reg = KIRKWOOD_RECCTL; | ||
117 | } | ||
118 | |||
119 | /* set dco conf */ | ||
120 | kirkwood_set_dco(priv->io, params_rate(params)); | ||
121 | |||
122 | i2s_value = readl(priv->io+i2s_reg); | ||
123 | i2s_value &= ~KIRKWOOD_I2S_CTL_SIZE_MASK; | ||
124 | |||
125 | value = readl(priv->io+reg); | ||
126 | value &= ~KIRKWOOD_PLAYCTL_SIZE_MASK; | ||
127 | |||
128 | /* | ||
129 | * Size settings in play/rec i2s control regs and play/rec control | ||
130 | * regs must be the same. | ||
131 | */ | ||
132 | switch (params_format(params)) { | ||
133 | case SNDRV_PCM_FORMAT_S16_LE: | ||
134 | i2s_value |= KIRKWOOD_I2S_CTL_SIZE_16; | ||
135 | value |= KIRKWOOD_PLAYCTL_SIZE_16_C; | ||
136 | break; | ||
137 | /* | ||
138 | * doesn't work... S20_3LE != kirkwood 20bit format ? | ||
139 | * | ||
140 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
141 | i2s_value |= KIRKWOOD_I2S_CTL_SIZE_20; | ||
142 | value |= KIRKWOOD_PLAYCTL_SIZE_20; | ||
143 | break; | ||
144 | */ | ||
145 | case SNDRV_PCM_FORMAT_S24_LE: | ||
146 | i2s_value |= KIRKWOOD_I2S_CTL_SIZE_24; | ||
147 | value |= KIRKWOOD_PLAYCTL_SIZE_24; | ||
148 | break; | ||
149 | case SNDRV_PCM_FORMAT_S32_LE: | ||
150 | i2s_value |= KIRKWOOD_I2S_CTL_SIZE_32; | ||
151 | value |= KIRKWOOD_PLAYCTL_SIZE_32; | ||
152 | break; | ||
153 | default: | ||
154 | return -EINVAL; | ||
155 | } | ||
156 | |||
157 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
158 | value &= ~KIRKWOOD_PLAYCTL_MONO_MASK; | ||
159 | if (params_channels(params) == 1) | ||
160 | value |= KIRKWOOD_PLAYCTL_MONO_BOTH; | ||
161 | else | ||
162 | value |= KIRKWOOD_PLAYCTL_MONO_OFF; | ||
163 | } | ||
164 | |||
165 | writel(i2s_value, priv->io+i2s_reg); | ||
166 | writel(value, priv->io+reg); | ||
167 | |||
168 | return 0; | ||
169 | } | ||
170 | |||
171 | static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream, | ||
172 | int cmd, struct snd_soc_dai *dai) | ||
173 | { | ||
174 | unsigned long value; | ||
175 | |||
176 | /* | ||
177 | * specs says KIRKWOOD_PLAYCTL must be read 2 times before | ||
178 | * changing it. So read 1 time here and 1 later. | ||
179 | */ | ||
180 | value = readl(priv->io + KIRKWOOD_PLAYCTL); | ||
181 | |||
182 | switch (cmd) { | ||
183 | case SNDRV_PCM_TRIGGER_START: | ||
184 | /* stop audio, enable interrupts */ | ||
185 | value = readl(priv->io + KIRKWOOD_PLAYCTL); | ||
186 | value |= KIRKWOOD_PLAYCTL_PAUSE; | ||
187 | writel(value, priv->io + KIRKWOOD_PLAYCTL); | ||
188 | |||
189 | value = readl(priv->io + KIRKWOOD_INT_MASK); | ||
190 | value |= KIRKWOOD_INT_CAUSE_PLAY_BYTES; | ||
191 | writel(value, priv->io + KIRKWOOD_INT_MASK); | ||
192 | |||
193 | /* configure audio & enable i2s playback */ | ||
194 | value = readl(priv->io + KIRKWOOD_PLAYCTL); | ||
195 | value &= ~KIRKWOOD_PLAYCTL_BURST_MASK; | ||
196 | value &= ~(KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE | ||
197 | | KIRKWOOD_PLAYCTL_SPDIF_EN); | ||
198 | |||
199 | if (priv->burst == 32) | ||
200 | value |= KIRKWOOD_PLAYCTL_BURST_32; | ||
201 | else | ||
202 | value |= KIRKWOOD_PLAYCTL_BURST_128; | ||
203 | value |= KIRKWOOD_PLAYCTL_I2S_EN; | ||
204 | writel(value, priv->io + KIRKWOOD_PLAYCTL); | ||
205 | break; | ||
206 | |||
207 | case SNDRV_PCM_TRIGGER_STOP: | ||
208 | /* stop audio, disable interrupts */ | ||
209 | value = readl(priv->io + KIRKWOOD_PLAYCTL); | ||
210 | value |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE; | ||
211 | writel(value, priv->io + KIRKWOOD_PLAYCTL); | ||
212 | |||
213 | value = readl(priv->io + KIRKWOOD_INT_MASK); | ||
214 | value &= ~KIRKWOOD_INT_CAUSE_PLAY_BYTES; | ||
215 | writel(value, priv->io + KIRKWOOD_INT_MASK); | ||
216 | |||
217 | /* disable all playbacks */ | ||
218 | value = readl(priv->io + KIRKWOOD_PLAYCTL); | ||
219 | value &= ~(KIRKWOOD_PLAYCTL_I2S_EN | KIRKWOOD_PLAYCTL_SPDIF_EN); | ||
220 | writel(value, priv->io + KIRKWOOD_PLAYCTL); | ||
221 | break; | ||
222 | |||
223 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
224 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
225 | value = readl(priv->io + KIRKWOOD_PLAYCTL); | ||
226 | value |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE; | ||
227 | writel(value, priv->io + KIRKWOOD_PLAYCTL); | ||
228 | break; | ||
229 | |||
230 | case SNDRV_PCM_TRIGGER_RESUME: | ||
231 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
232 | value = readl(priv->io + KIRKWOOD_PLAYCTL); | ||
233 | value &= ~(KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE); | ||
234 | writel(value, priv->io + KIRKWOOD_PLAYCTL); | ||
235 | break; | ||
236 | |||
237 | default: | ||
238 | return -EINVAL; | ||
239 | } | ||
240 | |||
241 | return 0; | ||
242 | } | ||
243 | |||
244 | static int kirkwood_i2s_rec_trigger(struct snd_pcm_substream *substream, | ||
245 | int cmd, struct snd_soc_dai *dai) | ||
246 | { | ||
247 | unsigned long value; | ||
248 | |||
249 | value = readl(priv->io + KIRKWOOD_RECCTL); | ||
250 | |||
251 | switch (cmd) { | ||
252 | case SNDRV_PCM_TRIGGER_START: | ||
253 | /* stop audio, enable interrupts */ | ||
254 | value = readl(priv->io + KIRKWOOD_RECCTL); | ||
255 | value |= KIRKWOOD_RECCTL_PAUSE; | ||
256 | writel(value, priv->io + KIRKWOOD_RECCTL); | ||
257 | |||
258 | value = readl(priv->io + KIRKWOOD_INT_MASK); | ||
259 | value |= KIRKWOOD_INT_CAUSE_REC_BYTES; | ||
260 | writel(value, priv->io + KIRKWOOD_INT_MASK); | ||
261 | |||
262 | /* configure audio & enable i2s record */ | ||
263 | value = readl(priv->io + KIRKWOOD_RECCTL); | ||
264 | value &= ~KIRKWOOD_RECCTL_BURST_MASK; | ||
265 | value &= ~KIRKWOOD_RECCTL_MONO; | ||
266 | value &= ~(KIRKWOOD_RECCTL_PAUSE | KIRKWOOD_RECCTL_MUTE | ||
267 | | KIRKWOOD_RECCTL_SPDIF_EN); | ||
268 | |||
269 | if (priv->burst == 32) | ||
270 | value |= KIRKWOOD_RECCTL_BURST_32; | ||
271 | else | ||
272 | value |= KIRKWOOD_RECCTL_BURST_128; | ||
273 | value |= KIRKWOOD_RECCTL_I2S_EN; | ||
274 | |||
275 | writel(value, priv->io + KIRKWOOD_RECCTL); | ||
276 | break; | ||
277 | |||
278 | case SNDRV_PCM_TRIGGER_STOP: | ||
279 | /* stop audio, disable interrupts */ | ||
280 | value = readl(priv->io + KIRKWOOD_RECCTL); | ||
281 | value |= KIRKWOOD_RECCTL_PAUSE | KIRKWOOD_RECCTL_MUTE; | ||
282 | writel(value, priv->io + KIRKWOOD_RECCTL); | ||
283 | |||
284 | value = readl(priv->io + KIRKWOOD_INT_MASK); | ||
285 | value &= ~KIRKWOOD_INT_CAUSE_REC_BYTES; | ||
286 | writel(value, priv->io + KIRKWOOD_INT_MASK); | ||
287 | |||
288 | /* disable all records */ | ||
289 | value = readl(priv->io + KIRKWOOD_RECCTL); | ||
290 | value &= ~(KIRKWOOD_RECCTL_I2S_EN | KIRKWOOD_RECCTL_SPDIF_EN); | ||
291 | writel(value, priv->io + KIRKWOOD_RECCTL); | ||
292 | break; | ||
293 | |||
294 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
295 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
296 | value = readl(priv->io + KIRKWOOD_RECCTL); | ||
297 | value |= KIRKWOOD_RECCTL_PAUSE | KIRKWOOD_RECCTL_MUTE; | ||
298 | writel(value, priv->io + KIRKWOOD_RECCTL); | ||
299 | break; | ||
300 | |||
301 | case SNDRV_PCM_TRIGGER_RESUME: | ||
302 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
303 | value = readl(priv->io + KIRKWOOD_RECCTL); | ||
304 | value &= ~(KIRKWOOD_RECCTL_PAUSE | KIRKWOOD_RECCTL_MUTE); | ||
305 | writel(value, priv->io + KIRKWOOD_RECCTL); | ||
306 | break; | ||
307 | |||
308 | default: | ||
309 | return -EINVAL; | ||
310 | } | ||
311 | |||
312 | return 0; | ||
313 | } | ||
314 | |||
315 | static int kirkwood_i2s_trigger(struct snd_pcm_substream *substream, int cmd, | ||
316 | struct snd_soc_dai *dai) | ||
317 | { | ||
318 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
319 | return kirkwood_i2s_play_trigger(substream, cmd, dai); | ||
320 | else | ||
321 | return kirkwood_i2s_rec_trigger(substream, cmd, dai); | ||
322 | |||
323 | return 0; | ||
324 | } | ||
325 | |||
326 | static int kirkwood_i2s_probe(struct platform_device *pdev, | ||
327 | struct snd_soc_dai *dai) | ||
328 | { | ||
329 | unsigned long value; | ||
330 | unsigned int reg_data; | ||
331 | |||
332 | /* put system in a "safe" state : */ | ||
333 | /* disable audio interrupts */ | ||
334 | writel(0xffffffff, priv->io + KIRKWOOD_INT_CAUSE); | ||
335 | writel(0, priv->io + KIRKWOOD_INT_MASK); | ||
336 | |||
337 | reg_data = readl(priv->io + 0x1200); | ||
338 | reg_data &= (~(0x333FF8)); | ||
339 | reg_data |= 0x111D18; | ||
340 | writel(reg_data, priv->io + 0x1200); | ||
341 | |||
342 | msleep(500); | ||
343 | |||
344 | reg_data = readl(priv->io + 0x1200); | ||
345 | reg_data &= (~(0x333FF8)); | ||
346 | reg_data |= 0x111D18; | ||
347 | writel(reg_data, priv->io + 0x1200); | ||
348 | |||
349 | /* disable playback/record */ | ||
350 | value = readl(priv->io + KIRKWOOD_PLAYCTL); | ||
351 | value &= ~(KIRKWOOD_PLAYCTL_I2S_EN|KIRKWOOD_PLAYCTL_SPDIF_EN); | ||
352 | writel(value, priv->io + KIRKWOOD_PLAYCTL); | ||
353 | |||
354 | value = readl(priv->io + KIRKWOOD_RECCTL); | ||
355 | value &= ~(KIRKWOOD_RECCTL_I2S_EN | KIRKWOOD_RECCTL_SPDIF_EN); | ||
356 | writel(value, priv->io + KIRKWOOD_RECCTL); | ||
357 | |||
358 | return 0; | ||
359 | |||
360 | } | ||
361 | |||
362 | static void kirkwood_i2s_remove(struct platform_device *pdev, | ||
363 | struct snd_soc_dai *dai) | ||
364 | { | ||
365 | } | ||
366 | |||
367 | static struct snd_soc_dai_ops kirkwood_i2s_dai_ops = { | ||
368 | .trigger = kirkwood_i2s_trigger, | ||
369 | .hw_params = kirkwood_i2s_hw_params, | ||
370 | .set_fmt = kirkwood_i2s_set_fmt, | ||
371 | }; | ||
372 | |||
373 | |||
374 | struct snd_soc_dai kirkwood_i2s_dai = { | ||
375 | .name = DRV_NAME, | ||
376 | .id = 0, | ||
377 | .probe = kirkwood_i2s_probe, | ||
378 | .remove = kirkwood_i2s_remove, | ||
379 | .playback = { | ||
380 | .channels_min = 1, | ||
381 | .channels_max = 2, | ||
382 | .rates = KIRKWOOD_I2S_RATES, | ||
383 | .formats = KIRKWOOD_I2S_FORMATS,}, | ||
384 | .capture = { | ||
385 | .channels_min = 1, | ||
386 | .channels_max = 2, | ||
387 | .rates = KIRKWOOD_I2S_RATES, | ||
388 | .formats = KIRKWOOD_I2S_FORMATS,}, | ||
389 | .ops = &kirkwood_i2s_dai_ops, | ||
390 | }; | ||
391 | EXPORT_SYMBOL_GPL(kirkwood_i2s_dai); | ||
392 | |||
393 | static __devinit int kirkwood_i2s_dev_probe(struct platform_device *pdev) | ||
394 | { | ||
395 | struct resource *mem; | ||
396 | struct kirkwood_asoc_platform_data *data = | ||
397 | pdev->dev.platform_data; | ||
398 | int err; | ||
399 | |||
400 | priv = kzalloc(sizeof(struct kirkwood_dma_data), GFP_KERNEL); | ||
401 | if (!priv) { | ||
402 | dev_err(&pdev->dev, "allocation failed\n"); | ||
403 | err = -ENOMEM; | ||
404 | goto error; | ||
405 | } | ||
406 | |||
407 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
408 | if (!mem) { | ||
409 | dev_err(&pdev->dev, "platform_get_resource failed\n"); | ||
410 | err = -ENXIO; | ||
411 | goto err_alloc; | ||
412 | } | ||
413 | |||
414 | priv->mem = request_mem_region(mem->start, SZ_16K, DRV_NAME); | ||
415 | if (!priv->mem) { | ||
416 | dev_err(&pdev->dev, "request_mem_region failed\n"); | ||
417 | err = -EBUSY; | ||
418 | goto error; | ||
419 | } | ||
420 | |||
421 | priv->io = ioremap(priv->mem->start, SZ_16K); | ||
422 | if (!priv->io) { | ||
423 | dev_err(&pdev->dev, "ioremap failed\n"); | ||
424 | err = -ENOMEM; | ||
425 | goto err_iomem; | ||
426 | } | ||
427 | |||
428 | priv->irq = platform_get_irq(pdev, 0); | ||
429 | if (priv->irq <= 0) { | ||
430 | dev_err(&pdev->dev, "platform_get_irq failed\n"); | ||
431 | err = -ENXIO; | ||
432 | goto err_ioremap; | ||
433 | } | ||
434 | |||
435 | if (!data || !data->dram) { | ||
436 | dev_err(&pdev->dev, "no platform data ?!\n"); | ||
437 | err = -EINVAL; | ||
438 | goto err_ioremap; | ||
439 | } | ||
440 | |||
441 | priv->dram = data->dram; | ||
442 | priv->burst = data->burst; | ||
443 | |||
444 | kirkwood_i2s_dai.capture.dma_data = priv; | ||
445 | kirkwood_i2s_dai.playback.dma_data = priv; | ||
446 | |||
447 | return snd_soc_register_dai(&kirkwood_i2s_dai); | ||
448 | |||
449 | err_ioremap: | ||
450 | iounmap(priv->io); | ||
451 | err_iomem: | ||
452 | release_mem_region(priv->mem->start, SZ_16K); | ||
453 | err_alloc: | ||
454 | kfree(priv); | ||
455 | error: | ||
456 | return err; | ||
457 | } | ||
458 | |||
459 | static __devexit int kirkwood_i2s_dev_remove(struct platform_device *pdev) | ||
460 | { | ||
461 | if (priv) { | ||
462 | iounmap(priv->io); | ||
463 | release_mem_region(priv->mem->start, SZ_16K); | ||
464 | kfree(priv); | ||
465 | } | ||
466 | snd_soc_unregister_dai(&kirkwood_i2s_dai); | ||
467 | return 0; | ||
468 | } | ||
469 | |||
470 | static struct platform_driver kirkwood_i2s_driver = { | ||
471 | .probe = kirkwood_i2s_dev_probe, | ||
472 | .remove = kirkwood_i2s_dev_remove, | ||
473 | .driver = { | ||
474 | .name = DRV_NAME, | ||
475 | .owner = THIS_MODULE, | ||
476 | }, | ||
477 | }; | ||
478 | |||
479 | static int __init kirkwood_i2s_init(void) | ||
480 | { | ||
481 | return platform_driver_register(&kirkwood_i2s_driver); | ||
482 | } | ||
483 | module_init(kirkwood_i2s_init); | ||
484 | |||
485 | static void __exit kirkwood_i2s_exit(void) | ||
486 | { | ||
487 | platform_driver_unregister(&kirkwood_i2s_driver); | ||
488 | } | ||
489 | module_exit(kirkwood_i2s_exit); | ||
490 | |||
491 | /* Module information */ | ||
492 | MODULE_AUTHOR("Arnaud Patard, <apatard@mandriva.com>"); | ||
493 | MODULE_DESCRIPTION("Kirkwood I2S SoC Interface"); | ||
494 | MODULE_LICENSE("GPL"); | ||
495 | MODULE_ALIAS("platform:kirkwood-i2s"); | ||
diff --git a/sound/soc/kirkwood/kirkwood-i2s.h b/sound/soc/kirkwood/kirkwood-i2s.h new file mode 100644 index 000000000000..c5595c616d7a --- /dev/null +++ b/sound/soc/kirkwood/kirkwood-i2s.h | |||
@@ -0,0 +1,17 @@ | |||
1 | /* | ||
2 | * kirkwood-i2s.h | ||
3 | * | ||
4 | * (c) 2010 Arnaud Patard <apatard@mandriva.com> | ||
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 | #ifndef _KIRKWOOD_I2S_H | ||
13 | #define _KIRKWOOD_I2S_H | ||
14 | |||
15 | extern struct snd_soc_dai kirkwood_i2s_dai; | ||
16 | |||
17 | #endif | ||
diff --git a/sound/soc/kirkwood/kirkwood-openrd.c b/sound/soc/kirkwood/kirkwood-openrd.c new file mode 100644 index 000000000000..0353d06bc41a --- /dev/null +++ b/sound/soc/kirkwood/kirkwood-openrd.c | |||
@@ -0,0 +1,126 @@ | |||
1 | /* | ||
2 | * kirkwood-openrd.c | ||
3 | * | ||
4 | * (c) 2010 Arnaud Patard <apatard@mandriva.com> | ||
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 | #include <linux/module.h> | ||
13 | #include <linux/moduleparam.h> | ||
14 | #include <linux/interrupt.h> | ||
15 | #include <linux/platform_device.h> | ||
16 | #include <linux/slab.h> | ||
17 | #include <sound/soc.h> | ||
18 | #include <mach/kirkwood.h> | ||
19 | #include <plat/audio.h> | ||
20 | #include <asm/mach-types.h> | ||
21 | #include "kirkwood-i2s.h" | ||
22 | #include "kirkwood-dma.h" | ||
23 | #include "../codecs/cs42l51.h" | ||
24 | |||
25 | static int openrd_client_hw_params(struct snd_pcm_substream *substream, | ||
26 | struct snd_pcm_hw_params *params) | ||
27 | { | ||
28 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
29 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; | ||
30 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | ||
31 | int ret; | ||
32 | unsigned int freq, fmt; | ||
33 | |||
34 | fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS; | ||
35 | ret = snd_soc_dai_set_fmt(cpu_dai, fmt); | ||
36 | if (ret < 0) | ||
37 | return ret; | ||
38 | |||
39 | ret = snd_soc_dai_set_fmt(codec_dai, fmt); | ||
40 | if (ret < 0) | ||
41 | return ret; | ||
42 | |||
43 | switch (params_rate(params)) { | ||
44 | default: | ||
45 | case 44100: | ||
46 | freq = 11289600; | ||
47 | break; | ||
48 | case 48000: | ||
49 | freq = 12288000; | ||
50 | break; | ||
51 | case 96000: | ||
52 | freq = 24576000; | ||
53 | break; | ||
54 | } | ||
55 | |||
56 | return snd_soc_dai_set_sysclk(codec_dai, 0, freq, SND_SOC_CLOCK_IN); | ||
57 | |||
58 | } | ||
59 | |||
60 | static struct snd_soc_ops openrd_client_ops = { | ||
61 | .hw_params = openrd_client_hw_params, | ||
62 | }; | ||
63 | |||
64 | |||
65 | static struct snd_soc_dai_link openrd_client_dai[] = { | ||
66 | { | ||
67 | .name = "CS42L51", | ||
68 | .stream_name = "CS42L51 HiFi", | ||
69 | .cpu_dai = &kirkwood_i2s_dai, | ||
70 | .codec_dai = &cs42l51_dai, | ||
71 | .ops = &openrd_client_ops, | ||
72 | }, | ||
73 | }; | ||
74 | |||
75 | |||
76 | static struct snd_soc_card openrd_client = { | ||
77 | .name = "OpenRD Client", | ||
78 | .platform = &kirkwood_soc_platform, | ||
79 | .dai_link = openrd_client_dai, | ||
80 | .num_links = ARRAY_SIZE(openrd_client_dai), | ||
81 | }; | ||
82 | |||
83 | static struct snd_soc_device openrd_client_snd_devdata = { | ||
84 | .card = &openrd_client, | ||
85 | .codec_dev = &soc_codec_device_cs42l51, | ||
86 | }; | ||
87 | |||
88 | static struct platform_device *openrd_client_snd_device; | ||
89 | |||
90 | static int __init openrd_client_init(void) | ||
91 | { | ||
92 | int ret; | ||
93 | |||
94 | if (!machine_is_openrd_client()) | ||
95 | return 0; | ||
96 | |||
97 | openrd_client_snd_device = platform_device_alloc("soc-audio", -1); | ||
98 | if (!openrd_client_snd_device) | ||
99 | return -ENOMEM; | ||
100 | |||
101 | platform_set_drvdata(openrd_client_snd_device, | ||
102 | &openrd_client_snd_devdata); | ||
103 | openrd_client_snd_devdata.dev = &openrd_client_snd_device->dev; | ||
104 | |||
105 | ret = platform_device_add(openrd_client_snd_device); | ||
106 | if (ret) { | ||
107 | printk(KERN_ERR "%s: platform_device_add failed\n", __func__); | ||
108 | platform_device_put(openrd_client_snd_device); | ||
109 | } | ||
110 | |||
111 | return ret; | ||
112 | } | ||
113 | |||
114 | static void __exit openrd_client_exit(void) | ||
115 | { | ||
116 | platform_device_unregister(openrd_client_snd_device); | ||
117 | } | ||
118 | |||
119 | module_init(openrd_client_init); | ||
120 | module_exit(openrd_client_exit); | ||
121 | |||
122 | /* Module information */ | ||
123 | MODULE_AUTHOR("Arnaud Patard <apatard@mandriva.com>"); | ||
124 | MODULE_DESCRIPTION("ALSA SoC OpenRD Client"); | ||
125 | MODULE_LICENSE("GPL"); | ||
126 | MODULE_ALIAS("platform:soc-audio"); | ||
diff --git a/sound/soc/kirkwood/kirkwood.h b/sound/soc/kirkwood/kirkwood.h new file mode 100644 index 000000000000..bb6e6a5648c9 --- /dev/null +++ b/sound/soc/kirkwood/kirkwood.h | |||
@@ -0,0 +1,129 @@ | |||
1 | /* | ||
2 | * kirkwood.h | ||
3 | * | ||
4 | * (c) 2010 Arnaud Patard <apatard@mandriva.com> | ||
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 | #ifndef _KIRKWOOD_AUDIO_H | ||
13 | #define _KIRKWOOD_AUDIO_H | ||
14 | |||
15 | #define KIRKWOOD_RECORD_WIN 0 | ||
16 | #define KIRKWOOD_PLAYBACK_WIN 1 | ||
17 | #define KIRKWOOD_MAX_AUDIO_WIN 2 | ||
18 | |||
19 | #define KIRKWOOD_AUDIO_WIN_BASE_REG(win) (0xA00 + ((win)<<3)) | ||
20 | #define KIRKWOOD_AUDIO_WIN_CTRL_REG(win) (0xA04 + ((win)<<3)) | ||
21 | |||
22 | |||
23 | #define KIRKWOOD_RECCTL 0x1000 | ||
24 | #define KIRKWOOD_RECCTL_SPDIF_EN (1<<11) | ||
25 | #define KIRKWOOD_RECCTL_I2S_EN (1<<10) | ||
26 | #define KIRKWOOD_RECCTL_PAUSE (1<<9) | ||
27 | #define KIRKWOOD_RECCTL_MUTE (1<<8) | ||
28 | #define KIRKWOOD_RECCTL_BURST_MASK (3<<5) | ||
29 | #define KIRKWOOD_RECCTL_BURST_128 (2<<5) | ||
30 | #define KIRKWOOD_RECCTL_BURST_32 (1<<5) | ||
31 | #define KIRKWOOD_RECCTL_MONO (1<<4) | ||
32 | #define KIRKWOOD_RECCTL_MONO_CHAN_RIGHT (1<<3) | ||
33 | #define KIRKWOOD_RECCTL_MONO_CHAN_LEFT (0<<3) | ||
34 | #define KIRKWOOD_RECCTL_SIZE_MASK (7<<0) | ||
35 | #define KIRKWOOD_RECCTL_SIZE_16 (7<<0) | ||
36 | #define KIRKWOOD_RECCTL_SIZE_16_C (3<<0) | ||
37 | #define KIRKWOOD_RECCTL_SIZE_20 (2<<0) | ||
38 | #define KIRKWOOD_RECCTL_SIZE_24 (1<<0) | ||
39 | #define KIRKWOOD_RECCTL_SIZE_32 (0<<0) | ||
40 | |||
41 | #define KIRKWOOD_REC_BUF_ADDR 0x1004 | ||
42 | #define KIRKWOOD_REC_BUF_SIZE 0x1008 | ||
43 | #define KIRKWOOD_REC_BYTE_COUNT 0x100C | ||
44 | |||
45 | #define KIRKWOOD_PLAYCTL 0x1100 | ||
46 | #define KIRKWOOD_PLAYCTL_PLAY_BUSY (1<<16) | ||
47 | #define KIRKWOOD_PLAYCTL_BURST_MASK (3<<11) | ||
48 | #define KIRKWOOD_PLAYCTL_BURST_128 (2<<11) | ||
49 | #define KIRKWOOD_PLAYCTL_BURST_32 (1<<11) | ||
50 | #define KIRKWOOD_PLAYCTL_PAUSE (1<<9) | ||
51 | #define KIRKWOOD_PLAYCTL_SPDIF_MUTE (1<<8) | ||
52 | #define KIRKWOOD_PLAYCTL_MONO_MASK (3<<5) | ||
53 | #define KIRKWOOD_PLAYCTL_MONO_BOTH (3<<5) | ||
54 | #define KIRKWOOD_PLAYCTL_MONO_OFF (0<<5) | ||
55 | #define KIRKWOOD_PLAYCTL_I2S_MUTE (1<<7) | ||
56 | #define KIRKWOOD_PLAYCTL_SPDIF_EN (1<<4) | ||
57 | #define KIRKWOOD_PLAYCTL_I2S_EN (1<<3) | ||
58 | #define KIRKWOOD_PLAYCTL_SIZE_MASK (7<<0) | ||
59 | #define KIRKWOOD_PLAYCTL_SIZE_16 (7<<0) | ||
60 | #define KIRKWOOD_PLAYCTL_SIZE_16_C (3<<0) | ||
61 | #define KIRKWOOD_PLAYCTL_SIZE_20 (2<<0) | ||
62 | #define KIRKWOOD_PLAYCTL_SIZE_24 (1<<0) | ||
63 | #define KIRKWOOD_PLAYCTL_SIZE_32 (0<<0) | ||
64 | |||
65 | #define KIRKWOOD_PLAY_BUF_ADDR 0x1104 | ||
66 | #define KIRKWOOD_PLAY_BUF_SIZE 0x1108 | ||
67 | #define KIRKWOOD_PLAY_BYTE_COUNT 0x110C | ||
68 | |||
69 | #define KIRKWOOD_DCO_CTL 0x1204 | ||
70 | #define KIRKWOOD_DCO_CTL_OFFSET_MASK (0xFFF<<2) | ||
71 | #define KIRKWOOD_DCO_CTL_OFFSET_0 (0x800<<2) | ||
72 | #define KIRKWOOD_DCO_CTL_FREQ_MASK (3<<0) | ||
73 | #define KIRKWOOD_DCO_CTL_FREQ_11 (0<<0) | ||
74 | #define KIRKWOOD_DCO_CTL_FREQ_12 (1<<0) | ||
75 | #define KIRKWOOD_DCO_CTL_FREQ_24 (2<<0) | ||
76 | |||
77 | #define KIRKWOOD_DCO_SPCR_STATUS 0x120c | ||
78 | #define KIRKWOOD_DCO_SPCR_STATUS_DCO_LOCK (1<<16) | ||
79 | |||
80 | #define KIRKWOOD_ERR_CAUSE 0x1300 | ||
81 | #define KIRKWOOD_ERR_MASK 0x1304 | ||
82 | |||
83 | #define KIRKWOOD_INT_CAUSE 0x1308 | ||
84 | #define KIRKWOOD_INT_MASK 0x130C | ||
85 | #define KIRKWOOD_INT_CAUSE_PLAY_BYTES (1<<14) | ||
86 | #define KIRKWOOD_INT_CAUSE_REC_BYTES (1<<13) | ||
87 | #define KIRKWOOD_INT_CAUSE_DMA_PLAY_END (1<<7) | ||
88 | #define KIRKWOOD_INT_CAUSE_DMA_PLAY_3Q (1<<6) | ||
89 | #define KIRKWOOD_INT_CAUSE_DMA_PLAY_HALF (1<<5) | ||
90 | #define KIRKWOOD_INT_CAUSE_DMA_PLAY_1Q (1<<4) | ||
91 | #define KIRKWOOD_INT_CAUSE_DMA_REC_END (1<<3) | ||
92 | #define KIRKWOOD_INT_CAUSE_DMA_REC_3Q (1<<2) | ||
93 | #define KIRKWOOD_INT_CAUSE_DMA_REC_HALF (1<<1) | ||
94 | #define KIRKWOOD_INT_CAUSE_DMA_REC_1Q (1<<0) | ||
95 | |||
96 | #define KIRKWOOD_REC_BYTE_INT_COUNT 0x1310 | ||
97 | #define KIRKWOOD_PLAY_BYTE_INT_COUNT 0x1314 | ||
98 | #define KIRKWOOD_BYTE_INT_COUNT_MASK 0xffffff | ||
99 | |||
100 | #define KIRKWOOD_I2S_PLAYCTL 0x2508 | ||
101 | #define KIRKWOOD_I2S_RECCTL 0x2408 | ||
102 | #define KIRKWOOD_I2S_CTL_JUST_MASK (0xf<<26) | ||
103 | #define KIRKWOOD_I2S_CTL_LJ (0<<26) | ||
104 | #define KIRKWOOD_I2S_CTL_I2S (5<<26) | ||
105 | #define KIRKWOOD_I2S_CTL_RJ (8<<26) | ||
106 | #define KIRKWOOD_I2S_CTL_SIZE_MASK (3<<30) | ||
107 | #define KIRKWOOD_I2S_CTL_SIZE_16 (3<<30) | ||
108 | #define KIRKWOOD_I2S_CTL_SIZE_20 (2<<30) | ||
109 | #define KIRKWOOD_I2S_CTL_SIZE_24 (1<<30) | ||
110 | #define KIRKWOOD_I2S_CTL_SIZE_32 (0<<30) | ||
111 | |||
112 | #define KIRKWOOD_AUDIO_BUF_MAX (16*1024*1024) | ||
113 | |||
114 | /* Theses values come from the marvell alsa driver */ | ||
115 | /* need to find where they come from */ | ||
116 | #define KIRKWOOD_SND_MIN_PERIODS 8 | ||
117 | #define KIRKWOOD_SND_MAX_PERIODS 16 | ||
118 | #define KIRKWOOD_SND_MIN_PERIOD_BYTES 0x4000 | ||
119 | #define KIRKWOOD_SND_MAX_PERIOD_BYTES 0x4000 | ||
120 | |||
121 | struct kirkwood_dma_data { | ||
122 | struct resource *mem; | ||
123 | void __iomem *io; | ||
124 | int irq; | ||
125 | int burst; | ||
126 | struct mbus_dram_target_info *dram; | ||
127 | }; | ||
128 | |||
129 | #endif | ||
diff --git a/sound/soc/nuc900/Kconfig b/sound/soc/nuc900/Kconfig new file mode 100644 index 000000000000..a0ed1c618f60 --- /dev/null +++ b/sound/soc/nuc900/Kconfig | |||
@@ -0,0 +1,27 @@ | |||
1 | ## | ||
2 | ## NUC900 series AC97 API | ||
3 | ## | ||
4 | config SND_SOC_NUC900 | ||
5 | tristate "SoC Audio for NUC900 series" | ||
6 | depends on ARCH_W90X900 | ||
7 | help | ||
8 | This option enables support for AC97 mode on the NUC900 SoC. | ||
9 | |||
10 | config SND_SOC_NUC900_AC97 | ||
11 | tristate | ||
12 | select AC97_BUS | ||
13 | select SND_AC97_CODEC | ||
14 | select SND_SOC_AC97_BUS | ||
15 | |||
16 | |||
17 | ## | ||
18 | ## Boards | ||
19 | ## | ||
20 | config SND_SOC_NUC900EVB | ||
21 | tristate "NUC900 AC97 support for demo board" | ||
22 | depends on SND_SOC_NUC900 | ||
23 | select SND_SOC_NUC900_AC97 | ||
24 | select SND_SOC_AC97_CODEC | ||
25 | help | ||
26 | Select this option to enable audio (AC97) on the | ||
27 | NUC900 demoboard. | ||
diff --git a/sound/soc/nuc900/Makefile b/sound/soc/nuc900/Makefile new file mode 100644 index 000000000000..7e46c7150316 --- /dev/null +++ b/sound/soc/nuc900/Makefile | |||
@@ -0,0 +1,11 @@ | |||
1 | # NUC900 series audio | ||
2 | snd-soc-nuc900-pcm-objs := nuc900-pcm.o | ||
3 | snd-soc-nuc900-ac97-objs := nuc900-ac97.o | ||
4 | |||
5 | obj-$(CONFIG_SND_SOC_NUC900) += snd-soc-nuc900-pcm.o | ||
6 | obj-$(CONFIG_SND_SOC_NUC900_AC97) += snd-soc-nuc900-ac97.o | ||
7 | |||
8 | # Boards | ||
9 | snd-soc-nuc900-audio-objs := nuc900-audio.o | ||
10 | |||
11 | obj-$(CONFIG_SND_SOC_NUC900EVB) += snd-soc-nuc900-audio.o | ||
diff --git a/sound/soc/nuc900/nuc900-ac97.c b/sound/soc/nuc900/nuc900-ac97.c new file mode 100644 index 000000000000..caa7c901bc2e --- /dev/null +++ b/sound/soc/nuc900/nuc900-ac97.c | |||
@@ -0,0 +1,430 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2009-2010 Nuvoton technology corporation. | ||
3 | * | ||
4 | * Wan ZongShun <mcuos.com@gmail.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation;version 2 of the License. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #include <linux/init.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/slab.h> | ||
15 | #include <linux/device.h> | ||
16 | #include <linux/delay.h> | ||
17 | #include <linux/mutex.h> | ||
18 | #include <linux/suspend.h> | ||
19 | #include <sound/core.h> | ||
20 | #include <sound/pcm.h> | ||
21 | #include <sound/initval.h> | ||
22 | #include <sound/soc.h> | ||
23 | #include <linux/device.h> | ||
24 | #include <linux/clk.h> | ||
25 | |||
26 | #include <mach/mfp.h> | ||
27 | |||
28 | #include "nuc900-audio.h" | ||
29 | |||
30 | static DEFINE_MUTEX(ac97_mutex); | ||
31 | struct nuc900_audio *nuc900_ac97_data; | ||
32 | |||
33 | static int nuc900_checkready(void) | ||
34 | { | ||
35 | struct nuc900_audio *nuc900_audio = nuc900_ac97_data; | ||
36 | |||
37 | if (!(AUDIO_READ(nuc900_audio->mmio + ACTL_ACIS0) & CODEC_READY)) | ||
38 | return -EPERM; | ||
39 | |||
40 | return 0; | ||
41 | } | ||
42 | |||
43 | /* AC97 controller reads codec register */ | ||
44 | static unsigned short nuc900_ac97_read(struct snd_ac97 *ac97, | ||
45 | unsigned short reg) | ||
46 | { | ||
47 | struct nuc900_audio *nuc900_audio = nuc900_ac97_data; | ||
48 | unsigned long timeout = 0x10000, val; | ||
49 | |||
50 | mutex_lock(&ac97_mutex); | ||
51 | |||
52 | val = nuc900_checkready(); | ||
53 | if (!!val) { | ||
54 | dev_err(nuc900_audio->dev, "AC97 codec is not ready\n"); | ||
55 | goto out; | ||
56 | } | ||
57 | |||
58 | /* set the R_WB bit and write register index */ | ||
59 | AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS1, R_WB | reg); | ||
60 | |||
61 | /* set the valid frame bit and valid slots */ | ||
62 | val = AUDIO_READ(nuc900_audio->mmio + ACTL_ACOS0); | ||
63 | val |= (VALID_FRAME | SLOT1_VALID); | ||
64 | AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS0, val); | ||
65 | |||
66 | udelay(100); | ||
67 | |||
68 | /* polling the AC_R_FINISH */ | ||
69 | while (!(AUDIO_READ(nuc900_audio->mmio + ACTL_ACCON) & AC_R_FINISH) | ||
70 | && timeout--) | ||
71 | mdelay(1); | ||
72 | |||
73 | if (!timeout) { | ||
74 | dev_err(nuc900_audio->dev, "AC97 read register time out !\n"); | ||
75 | val = -EPERM; | ||
76 | goto out; | ||
77 | } | ||
78 | |||
79 | val = AUDIO_READ(nuc900_audio->mmio + ACTL_ACOS0) ; | ||
80 | val &= ~SLOT1_VALID; | ||
81 | AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS0, val); | ||
82 | |||
83 | if (AUDIO_READ(nuc900_audio->mmio + ACTL_ACIS1) >> 2 != reg) { | ||
84 | dev_err(nuc900_audio->dev, | ||
85 | "R_INDEX of REG_ACTL_ACIS1 not match!\n"); | ||
86 | } | ||
87 | |||
88 | udelay(100); | ||
89 | val = (AUDIO_READ(nuc900_audio->mmio + ACTL_ACIS2) & 0xFFFF); | ||
90 | |||
91 | out: | ||
92 | mutex_unlock(&ac97_mutex); | ||
93 | return val; | ||
94 | } | ||
95 | |||
96 | /* AC97 controller writes to codec register */ | ||
97 | static void nuc900_ac97_write(struct snd_ac97 *ac97, unsigned short reg, | ||
98 | unsigned short val) | ||
99 | { | ||
100 | struct nuc900_audio *nuc900_audio = nuc900_ac97_data; | ||
101 | unsigned long tmp, timeout = 0x10000; | ||
102 | |||
103 | mutex_lock(&ac97_mutex); | ||
104 | |||
105 | tmp = nuc900_checkready(); | ||
106 | if (!!tmp) | ||
107 | dev_err(nuc900_audio->dev, "AC97 codec is not ready\n"); | ||
108 | |||
109 | /* clear the R_WB bit and write register index */ | ||
110 | AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS1, reg); | ||
111 | |||
112 | /* write register value */ | ||
113 | AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS2, val); | ||
114 | |||
115 | /* set the valid frame bit and valid slots */ | ||
116 | tmp = AUDIO_READ(nuc900_audio->mmio + ACTL_ACOS0); | ||
117 | tmp |= SLOT1_VALID | SLOT2_VALID | VALID_FRAME; | ||
118 | AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS0, tmp); | ||
119 | |||
120 | udelay(100); | ||
121 | |||
122 | /* polling the AC_W_FINISH */ | ||
123 | while ((AUDIO_READ(nuc900_audio->mmio + ACTL_ACCON) & AC_W_FINISH) | ||
124 | && timeout--) | ||
125 | mdelay(1); | ||
126 | |||
127 | if (!timeout) | ||
128 | dev_err(nuc900_audio->dev, "AC97 write register time out !\n"); | ||
129 | |||
130 | tmp = AUDIO_READ(nuc900_audio->mmio + ACTL_ACOS0); | ||
131 | tmp &= ~(SLOT1_VALID | SLOT2_VALID); | ||
132 | AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS0, tmp); | ||
133 | |||
134 | mutex_unlock(&ac97_mutex); | ||
135 | |||
136 | } | ||
137 | |||
138 | static void nuc900_ac97_warm_reset(struct snd_ac97 *ac97) | ||
139 | { | ||
140 | struct nuc900_audio *nuc900_audio = nuc900_ac97_data; | ||
141 | unsigned long val; | ||
142 | |||
143 | mutex_lock(&ac97_mutex); | ||
144 | |||
145 | /* warm reset AC 97 */ | ||
146 | val = AUDIO_READ(nuc900_audio->mmio + ACTL_ACCON); | ||
147 | val |= AC_W_RES; | ||
148 | AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACCON, val); | ||
149 | |||
150 | udelay(100); | ||
151 | |||
152 | val = nuc900_checkready(); | ||
153 | if (!!val) | ||
154 | dev_err(nuc900_audio->dev, "AC97 codec is not ready\n"); | ||
155 | |||
156 | mutex_unlock(&ac97_mutex); | ||
157 | } | ||
158 | |||
159 | static void nuc900_ac97_cold_reset(struct snd_ac97 *ac97) | ||
160 | { | ||
161 | struct nuc900_audio *nuc900_audio = nuc900_ac97_data; | ||
162 | unsigned long val; | ||
163 | |||
164 | mutex_lock(&ac97_mutex); | ||
165 | |||
166 | /* reset Audio Controller */ | ||
167 | val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET); | ||
168 | val |= ACTL_RESET_BIT; | ||
169 | AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val); | ||
170 | |||
171 | val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET); | ||
172 | val &= (~ACTL_RESET_BIT); | ||
173 | AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val); | ||
174 | |||
175 | /* reset AC-link interface */ | ||
176 | |||
177 | val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET); | ||
178 | val |= AC_RESET; | ||
179 | AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val); | ||
180 | |||
181 | val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET); | ||
182 | val &= ~AC_RESET; | ||
183 | AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val); | ||
184 | |||
185 | /* cold reset AC 97 */ | ||
186 | val = AUDIO_READ(nuc900_audio->mmio + ACTL_ACCON); | ||
187 | val |= AC_C_RES; | ||
188 | AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACCON, val); | ||
189 | |||
190 | val = AUDIO_READ(nuc900_audio->mmio + ACTL_ACCON); | ||
191 | val &= (~AC_C_RES); | ||
192 | AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACCON, val); | ||
193 | |||
194 | udelay(100); | ||
195 | |||
196 | mutex_unlock(&ac97_mutex); | ||
197 | |||
198 | } | ||
199 | |||
200 | /* AC97 controller operations */ | ||
201 | struct snd_ac97_bus_ops soc_ac97_ops = { | ||
202 | .read = nuc900_ac97_read, | ||
203 | .write = nuc900_ac97_write, | ||
204 | .reset = nuc900_ac97_cold_reset, | ||
205 | .warm_reset = nuc900_ac97_warm_reset, | ||
206 | } | ||
207 | EXPORT_SYMBOL_GPL(soc_ac97_ops); | ||
208 | |||
209 | static int nuc900_ac97_trigger(struct snd_pcm_substream *substream, | ||
210 | int cmd, struct snd_soc_dai *dai) | ||
211 | { | ||
212 | struct nuc900_audio *nuc900_audio = nuc900_ac97_data; | ||
213 | int ret; | ||
214 | unsigned long val, tmp; | ||
215 | |||
216 | ret = 0; | ||
217 | |||
218 | switch (cmd) { | ||
219 | case SNDRV_PCM_TRIGGER_START: | ||
220 | case SNDRV_PCM_TRIGGER_RESUME: | ||
221 | val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET); | ||
222 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
223 | tmp = AUDIO_READ(nuc900_audio->mmio + ACTL_ACOS0); | ||
224 | tmp |= (SLOT3_VALID | SLOT4_VALID | VALID_FRAME); | ||
225 | AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS0, tmp); | ||
226 | |||
227 | tmp = AUDIO_READ(nuc900_audio->mmio + ACTL_PSR); | ||
228 | tmp |= (P_DMA_END_IRQ | P_DMA_MIDDLE_IRQ); | ||
229 | AUDIO_WRITE(nuc900_audio->mmio + ACTL_PSR, tmp); | ||
230 | val |= AC_PLAY; | ||
231 | } else { | ||
232 | tmp = AUDIO_READ(nuc900_audio->mmio + ACTL_RSR); | ||
233 | tmp |= (R_DMA_END_IRQ | R_DMA_MIDDLE_IRQ); | ||
234 | |||
235 | AUDIO_WRITE(nuc900_audio->mmio + ACTL_RSR, tmp); | ||
236 | val |= AC_RECORD; | ||
237 | } | ||
238 | |||
239 | AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val); | ||
240 | |||
241 | break; | ||
242 | case SNDRV_PCM_TRIGGER_STOP: | ||
243 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
244 | val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET); | ||
245 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
246 | tmp = AUDIO_READ(nuc900_audio->mmio + ACTL_ACOS0); | ||
247 | tmp &= ~(SLOT3_VALID | SLOT4_VALID); | ||
248 | AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS0, tmp); | ||
249 | |||
250 | AUDIO_WRITE(nuc900_audio->mmio + ACTL_PSR, RESET_PRSR); | ||
251 | val &= ~AC_PLAY; | ||
252 | } else { | ||
253 | AUDIO_WRITE(nuc900_audio->mmio + ACTL_RSR, RESET_PRSR); | ||
254 | val &= ~AC_RECORD; | ||
255 | } | ||
256 | |||
257 | AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val); | ||
258 | |||
259 | break; | ||
260 | default: | ||
261 | ret = -EINVAL; | ||
262 | } | ||
263 | |||
264 | return ret; | ||
265 | } | ||
266 | |||
267 | static int nuc900_ac97_probe(struct platform_device *pdev, | ||
268 | struct snd_soc_dai *dai) | ||
269 | { | ||
270 | struct nuc900_audio *nuc900_audio = nuc900_ac97_data; | ||
271 | unsigned long val; | ||
272 | |||
273 | mutex_lock(&ac97_mutex); | ||
274 | |||
275 | /* enable unit clock */ | ||
276 | clk_enable(nuc900_audio->clk); | ||
277 | |||
278 | /* enable audio controller and AC-link interface */ | ||
279 | val = AUDIO_READ(nuc900_audio->mmio + ACTL_CON); | ||
280 | val |= (IIS_AC_PIN_SEL | ACLINK_EN); | ||
281 | AUDIO_WRITE(nuc900_audio->mmio + ACTL_CON, val); | ||
282 | |||
283 | mutex_unlock(&ac97_mutex); | ||
284 | |||
285 | return 0; | ||
286 | } | ||
287 | |||
288 | static void nuc900_ac97_remove(struct platform_device *pdev, | ||
289 | struct snd_soc_dai *dai) | ||
290 | { | ||
291 | struct nuc900_audio *nuc900_audio = nuc900_ac97_data; | ||
292 | |||
293 | clk_disable(nuc900_audio->clk); | ||
294 | } | ||
295 | |||
296 | static struct snd_soc_dai_ops nuc900_ac97_dai_ops = { | ||
297 | .trigger = nuc900_ac97_trigger, | ||
298 | }; | ||
299 | |||
300 | struct snd_soc_dai nuc900_ac97_dai = { | ||
301 | .name = "nuc900-ac97", | ||
302 | .probe = nuc900_ac97_probe, | ||
303 | .remove = nuc900_ac97_remove, | ||
304 | .ac97_control = 1, | ||
305 | .playback = { | ||
306 | .rates = SNDRV_PCM_RATE_8000_48000, | ||
307 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
308 | .channels_min = 1, | ||
309 | .channels_max = 2, | ||
310 | }, | ||
311 | .capture = { | ||
312 | .rates = SNDRV_PCM_RATE_8000_48000, | ||
313 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
314 | .channels_min = 1, | ||
315 | .channels_max = 2, | ||
316 | }, | ||
317 | .ops = &nuc900_ac97_dai_ops, | ||
318 | } | ||
319 | EXPORT_SYMBOL_GPL(nuc900_ac97_dai); | ||
320 | |||
321 | static int __devinit nuc900_ac97_drvprobe(struct platform_device *pdev) | ||
322 | { | ||
323 | struct nuc900_audio *nuc900_audio; | ||
324 | int ret; | ||
325 | |||
326 | if (nuc900_ac97_data) | ||
327 | return -EBUSY; | ||
328 | |||
329 | nuc900_audio = kzalloc(sizeof(struct nuc900_audio), GFP_KERNEL); | ||
330 | if (!nuc900_audio) | ||
331 | return -ENOMEM; | ||
332 | |||
333 | spin_lock_init(&nuc900_audio->lock); | ||
334 | |||
335 | nuc900_audio->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
336 | if (!nuc900_audio->res) { | ||
337 | ret = -ENODEV; | ||
338 | goto out0; | ||
339 | } | ||
340 | |||
341 | if (!request_mem_region(nuc900_audio->res->start, | ||
342 | resource_size(nuc900_audio->res), pdev->name)) { | ||
343 | ret = -EBUSY; | ||
344 | goto out0; | ||
345 | } | ||
346 | |||
347 | nuc900_audio->mmio = ioremap(nuc900_audio->res->start, | ||
348 | resource_size(nuc900_audio->res)); | ||
349 | if (!nuc900_audio->mmio) { | ||
350 | ret = -ENOMEM; | ||
351 | goto out1; | ||
352 | } | ||
353 | |||
354 | nuc900_audio->clk = clk_get(&pdev->dev, NULL); | ||
355 | if (IS_ERR(nuc900_audio->clk)) { | ||
356 | ret = PTR_ERR(nuc900_audio->clk); | ||
357 | goto out2; | ||
358 | } | ||
359 | |||
360 | nuc900_audio->irq_num = platform_get_irq(pdev, 0); | ||
361 | if (!nuc900_audio->irq_num) { | ||
362 | ret = -EBUSY; | ||
363 | goto out2; | ||
364 | } | ||
365 | |||
366 | nuc900_ac97_data = nuc900_audio; | ||
367 | |||
368 | nuc900_audio->dev = nuc900_ac97_dai.dev = &pdev->dev; | ||
369 | |||
370 | ret = snd_soc_register_dai(&nuc900_ac97_dai); | ||
371 | if (ret) | ||
372 | goto out3; | ||
373 | |||
374 | mfp_set_groupg(nuc900_audio->dev); /* enbale ac97 multifunction pin*/ | ||
375 | |||
376 | return 0; | ||
377 | |||
378 | out3: | ||
379 | clk_put(nuc900_audio->clk); | ||
380 | out2: | ||
381 | iounmap(nuc900_audio->mmio); | ||
382 | out1: | ||
383 | release_mem_region(nuc900_audio->res->start, | ||
384 | resource_size(nuc900_audio->res)); | ||
385 | out0: | ||
386 | kfree(nuc900_audio); | ||
387 | return ret; | ||
388 | } | ||
389 | |||
390 | static int __devexit nuc900_ac97_drvremove(struct platform_device *pdev) | ||
391 | { | ||
392 | |||
393 | snd_soc_unregister_dai(&nuc900_ac97_dai); | ||
394 | |||
395 | clk_put(nuc900_ac97_data->clk); | ||
396 | iounmap(nuc900_ac97_data->mmio); | ||
397 | release_mem_region(nuc900_ac97_data->res->start, | ||
398 | resource_size(nuc900_ac97_data->res)); | ||
399 | |||
400 | nuc900_ac97_data = NULL; | ||
401 | |||
402 | return 0; | ||
403 | } | ||
404 | |||
405 | static struct platform_driver nuc900_ac97_driver = { | ||
406 | .driver = { | ||
407 | .name = "nuc900-audio", | ||
408 | .owner = THIS_MODULE, | ||
409 | }, | ||
410 | .probe = nuc900_ac97_drvprobe, | ||
411 | .remove = __devexit_p(nuc900_ac97_drvremove), | ||
412 | }; | ||
413 | |||
414 | static int __init nuc900_ac97_init(void) | ||
415 | { | ||
416 | return platform_driver_register(&nuc900_ac97_driver); | ||
417 | } | ||
418 | |||
419 | static void __exit nuc900_ac97_exit(void) | ||
420 | { | ||
421 | platform_driver_unregister(&nuc900_ac97_driver); | ||
422 | } | ||
423 | |||
424 | module_init(nuc900_ac97_init); | ||
425 | module_exit(nuc900_ac97_exit); | ||
426 | |||
427 | MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>"); | ||
428 | MODULE_DESCRIPTION("NUC900 AC97 SoC driver!"); | ||
429 | MODULE_LICENSE("GPL"); | ||
430 | MODULE_ALIAS("platform:nuc900-ac97"); | ||
diff --git a/sound/soc/nuc900/nuc900-audio.c b/sound/soc/nuc900/nuc900-audio.c new file mode 100644 index 000000000000..72e6f518f7b2 --- /dev/null +++ b/sound/soc/nuc900/nuc900-audio.c | |||
@@ -0,0 +1,81 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2010 Nuvoton technology corporation. | ||
3 | * | ||
4 | * Wan ZongShun <mcuos.com@gmail.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation;version 2 of the License. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/moduleparam.h> | ||
14 | #include <linux/timer.h> | ||
15 | #include <linux/interrupt.h> | ||
16 | #include <linux/platform_device.h> | ||
17 | |||
18 | #include <sound/core.h> | ||
19 | #include <sound/pcm.h> | ||
20 | #include <sound/soc.h> | ||
21 | #include <sound/soc-dapm.h> | ||
22 | |||
23 | #include "../codecs/ac97.h" | ||
24 | #include "nuc900-audio.h" | ||
25 | |||
26 | static struct snd_soc_dai_link nuc900evb_ac97_dai = { | ||
27 | .name = "AC97", | ||
28 | .stream_name = "AC97 HiFi", | ||
29 | .cpu_dai = &nuc900_ac97_dai, | ||
30 | .codec_dai = &ac97_dai, | ||
31 | }; | ||
32 | |||
33 | static struct snd_soc_card nuc900evb_audio_machine = { | ||
34 | .name = "NUC900EVB_AC97", | ||
35 | .dai_link = &nuc900evb_ac97_dai, | ||
36 | .num_links = 1, | ||
37 | .platform = &nuc900_soc_platform, | ||
38 | }; | ||
39 | |||
40 | static struct snd_soc_device nuc900evb_ac97_devdata = { | ||
41 | .card = &nuc900evb_audio_machine, | ||
42 | .codec_dev = &soc_codec_dev_ac97, | ||
43 | }; | ||
44 | |||
45 | static struct platform_device *nuc900evb_asoc_dev; | ||
46 | |||
47 | static int __init nuc900evb_audio_init(void) | ||
48 | { | ||
49 | int ret; | ||
50 | |||
51 | ret = -ENOMEM; | ||
52 | nuc900evb_asoc_dev = platform_device_alloc("soc-audio", -1); | ||
53 | if (!nuc900evb_asoc_dev) | ||
54 | goto out; | ||
55 | |||
56 | /* nuc900 board audio device */ | ||
57 | platform_set_drvdata(nuc900evb_asoc_dev, &nuc900evb_ac97_devdata); | ||
58 | |||
59 | nuc900evb_ac97_devdata.dev = &nuc900evb_asoc_dev->dev; | ||
60 | ret = platform_device_add(nuc900evb_asoc_dev); | ||
61 | |||
62 | if (ret) { | ||
63 | platform_device_put(nuc900evb_asoc_dev); | ||
64 | nuc900evb_asoc_dev = NULL; | ||
65 | } | ||
66 | |||
67 | out: | ||
68 | return ret; | ||
69 | } | ||
70 | |||
71 | static void __exit nuc900evb_audio_exit(void) | ||
72 | { | ||
73 | platform_device_unregister(nuc900evb_asoc_dev); | ||
74 | } | ||
75 | |||
76 | module_init(nuc900evb_audio_init); | ||
77 | module_exit(nuc900evb_audio_exit); | ||
78 | |||
79 | MODULE_LICENSE("GPL"); | ||
80 | MODULE_DESCRIPTION("NUC900 Series ASoC audio support"); | ||
81 | MODULE_AUTHOR("Wan ZongShun"); | ||
diff --git a/sound/soc/nuc900/nuc900-audio.h b/sound/soc/nuc900/nuc900-audio.h new file mode 100644 index 000000000000..3038f519729f --- /dev/null +++ b/sound/soc/nuc900/nuc900-audio.h | |||
@@ -0,0 +1,117 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2010 Nuvoton technology corporation. | ||
3 | * | ||
4 | * Wan ZongShun <mcuos.com@gmail.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation;version 2 of the License. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #ifndef _NUC900_AUDIO_H | ||
13 | #define _NUC900_AUDIO_H | ||
14 | |||
15 | #include <linux/io.h> | ||
16 | |||
17 | /* Audio Control Registers */ | ||
18 | #define ACTL_CON 0x00 | ||
19 | #define ACTL_RESET 0x04 | ||
20 | #define ACTL_RDSTB 0x08 | ||
21 | #define ACTL_RDST_LENGTH 0x0C | ||
22 | #define ACTL_RDSTC 0x10 | ||
23 | #define ACTL_RSR 0x14 | ||
24 | #define ACTL_PDSTB 0x18 | ||
25 | #define ACTL_PDST_LENGTH 0x1C | ||
26 | #define ACTL_PDSTC 0x20 | ||
27 | #define ACTL_PSR 0x24 | ||
28 | #define ACTL_IISCON 0x28 | ||
29 | #define ACTL_ACCON 0x2C | ||
30 | #define ACTL_ACOS0 0x30 | ||
31 | #define ACTL_ACOS1 0x34 | ||
32 | #define ACTL_ACOS2 0x38 | ||
33 | #define ACTL_ACIS0 0x3C | ||
34 | #define ACTL_ACIS1 0x40 | ||
35 | #define ACTL_ACIS2 0x44 | ||
36 | #define ACTL_COUNTER 0x48 | ||
37 | |||
38 | /* bit definition of REG_ACTL_CON register */ | ||
39 | #define R_DMA_IRQ 0x1000 | ||
40 | #define T_DMA_IRQ 0x0800 | ||
41 | #define IIS_AC_PIN_SEL 0x0100 | ||
42 | #define FIFO_TH 0x0080 | ||
43 | #define ADC_EN 0x0010 | ||
44 | #define M80_EN 0x0008 | ||
45 | #define ACLINK_EN 0x0004 | ||
46 | #define IIS_EN 0x0002 | ||
47 | |||
48 | /* bit definition of REG_ACTL_RESET register */ | ||
49 | #define W5691_PLAY 0x20000 | ||
50 | #define ACTL_RESET_BIT 0x10000 | ||
51 | #define RECORD_RIGHT_CHNNEL 0x08000 | ||
52 | #define RECORD_LEFT_CHNNEL 0x04000 | ||
53 | #define PLAY_RIGHT_CHNNEL 0x02000 | ||
54 | #define PLAY_LEFT_CHNNEL 0x01000 | ||
55 | #define DAC_PLAY 0x00800 | ||
56 | #define ADC_RECORD 0x00400 | ||
57 | #define M80_PLAY 0x00200 | ||
58 | #define AC_RECORD 0x00100 | ||
59 | #define AC_PLAY 0x00080 | ||
60 | #define IIS_RECORD 0x00040 | ||
61 | #define IIS_PLAY 0x00020 | ||
62 | #define DAC_RESET 0x00010 | ||
63 | #define ADC_RESET 0x00008 | ||
64 | #define M80_RESET 0x00004 | ||
65 | #define AC_RESET 0x00002 | ||
66 | #define IIS_RESET 0x00001 | ||
67 | |||
68 | /* bit definition of REG_ACTL_ACCON register */ | ||
69 | #define AC_BCLK_PU_EN 0x20 | ||
70 | #define AC_R_FINISH 0x10 | ||
71 | #define AC_W_FINISH 0x08 | ||
72 | #define AC_W_RES 0x04 | ||
73 | #define AC_C_RES 0x02 | ||
74 | |||
75 | /* bit definition of ACTL_RSR register */ | ||
76 | #define R_FIFO_EMPTY 0x04 | ||
77 | #define R_DMA_END_IRQ 0x02 | ||
78 | #define R_DMA_MIDDLE_IRQ 0x01 | ||
79 | |||
80 | /* bit definition of ACTL_PSR register */ | ||
81 | #define P_FIFO_EMPTY 0x04 | ||
82 | #define P_DMA_END_IRQ 0x02 | ||
83 | #define P_DMA_MIDDLE_IRQ 0x01 | ||
84 | |||
85 | /* bit definition of ACTL_ACOS0 register */ | ||
86 | #define SLOT1_VALID 0x01 | ||
87 | #define SLOT2_VALID 0x02 | ||
88 | #define SLOT3_VALID 0x04 | ||
89 | #define SLOT4_VALID 0x08 | ||
90 | #define VALID_FRAME 0x10 | ||
91 | |||
92 | /* bit definition of ACTL_ACOS1 register */ | ||
93 | #define R_WB 0x80 | ||
94 | |||
95 | #define CODEC_READY 0x10 | ||
96 | #define RESET_PRSR 0x00 | ||
97 | #define AUDIO_WRITE(addr, val) __raw_writel(val, addr) | ||
98 | #define AUDIO_READ(addr) __raw_readl(addr) | ||
99 | |||
100 | struct nuc900_audio { | ||
101 | void __iomem *mmio; | ||
102 | spinlock_t lock; | ||
103 | dma_addr_t dma_addr[2]; | ||
104 | unsigned long buffersize[2]; | ||
105 | unsigned long irq_num; | ||
106 | struct snd_pcm_substream *substream; | ||
107 | struct resource *res; | ||
108 | struct clk *clk; | ||
109 | struct device *dev; | ||
110 | |||
111 | }; | ||
112 | |||
113 | extern struct nuc900_audio *nuc900_ac97_data; | ||
114 | extern struct snd_soc_dai nuc900_ac97_dai; | ||
115 | extern struct snd_soc_platform nuc900_soc_platform; | ||
116 | |||
117 | #endif /*end _NUC900_AUDIO_H */ | ||
diff --git a/sound/soc/nuc900/nuc900-pcm.c b/sound/soc/nuc900/nuc900-pcm.c new file mode 100644 index 000000000000..e81e803b3a63 --- /dev/null +++ b/sound/soc/nuc900/nuc900-pcm.c | |||
@@ -0,0 +1,354 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2010 Nuvoton technology corporation. | ||
3 | * | ||
4 | * Wan ZongShun <mcuos.com@gmail.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation;version 2 of the License. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/io.h> | ||
15 | #include <linux/platform_device.h> | ||
16 | #include <linux/slab.h> | ||
17 | #include <linux/dma-mapping.h> | ||
18 | |||
19 | #include <sound/core.h> | ||
20 | #include <sound/pcm.h> | ||
21 | #include <sound/pcm_params.h> | ||
22 | #include <sound/soc.h> | ||
23 | |||
24 | #include <mach/hardware.h> | ||
25 | |||
26 | #include "nuc900-audio.h" | ||
27 | |||
28 | static const struct snd_pcm_hardware nuc900_pcm_hardware = { | ||
29 | .info = SNDRV_PCM_INFO_INTERLEAVED | | ||
30 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | ||
31 | SNDRV_PCM_INFO_MMAP | | ||
32 | SNDRV_PCM_INFO_MMAP_VALID | | ||
33 | SNDRV_PCM_INFO_PAUSE | | ||
34 | SNDRV_PCM_INFO_RESUME, | ||
35 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
36 | .channels_min = 1, | ||
37 | .channels_max = 2, | ||
38 | .buffer_bytes_max = 4*1024, | ||
39 | .period_bytes_min = 1*1024, | ||
40 | .period_bytes_max = 4*1024, | ||
41 | .periods_min = 1, | ||
42 | .periods_max = 1024, | ||
43 | }; | ||
44 | |||
45 | static int nuc900_dma_hw_params(struct snd_pcm_substream *substream, | ||
46 | struct snd_pcm_hw_params *params) | ||
47 | { | ||
48 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
49 | struct nuc900_audio *nuc900_audio = runtime->private_data; | ||
50 | unsigned long flags; | ||
51 | int ret = 0; | ||
52 | |||
53 | spin_lock_irqsave(&nuc900_audio->lock, flags); | ||
54 | |||
55 | ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); | ||
56 | if (ret < 0) | ||
57 | return ret; | ||
58 | |||
59 | nuc900_audio->substream = substream; | ||
60 | nuc900_audio->dma_addr[substream->stream] = runtime->dma_addr; | ||
61 | nuc900_audio->buffersize[substream->stream] = | ||
62 | params_buffer_bytes(params); | ||
63 | |||
64 | spin_unlock_irqrestore(&nuc900_audio->lock, flags); | ||
65 | |||
66 | return ret; | ||
67 | } | ||
68 | |||
69 | static void nuc900_update_dma_register(struct snd_pcm_substream *substream, | ||
70 | dma_addr_t dma_addr, size_t count) | ||
71 | { | ||
72 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
73 | struct nuc900_audio *nuc900_audio = runtime->private_data; | ||
74 | void __iomem *mmio_addr, *mmio_len; | ||
75 | |||
76 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
77 | mmio_addr = nuc900_audio->mmio + ACTL_PDSTB; | ||
78 | mmio_len = nuc900_audio->mmio + ACTL_PDST_LENGTH; | ||
79 | } else { | ||
80 | mmio_addr = nuc900_audio->mmio + ACTL_RDSTB; | ||
81 | mmio_len = nuc900_audio->mmio + ACTL_RDST_LENGTH; | ||
82 | } | ||
83 | |||
84 | AUDIO_WRITE(mmio_addr, dma_addr); | ||
85 | AUDIO_WRITE(mmio_len, count); | ||
86 | } | ||
87 | |||
88 | static void nuc900_dma_start(struct snd_pcm_substream *substream) | ||
89 | { | ||
90 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
91 | struct nuc900_audio *nuc900_audio = runtime->private_data; | ||
92 | unsigned long val; | ||
93 | |||
94 | val = AUDIO_READ(nuc900_audio->mmio + ACTL_CON); | ||
95 | val |= (T_DMA_IRQ | R_DMA_IRQ); | ||
96 | AUDIO_WRITE(nuc900_audio->mmio + ACTL_CON, val); | ||
97 | } | ||
98 | |||
99 | static void nuc900_dma_stop(struct snd_pcm_substream *substream) | ||
100 | { | ||
101 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
102 | struct nuc900_audio *nuc900_audio = runtime->private_data; | ||
103 | unsigned long val; | ||
104 | |||
105 | val = AUDIO_READ(nuc900_audio->mmio + ACTL_CON); | ||
106 | val &= ~(T_DMA_IRQ | R_DMA_IRQ); | ||
107 | AUDIO_WRITE(nuc900_audio->mmio + ACTL_CON, val); | ||
108 | } | ||
109 | |||
110 | static irqreturn_t nuc900_dma_interrupt(int irq, void *dev_id) | ||
111 | { | ||
112 | struct snd_pcm_substream *substream = dev_id; | ||
113 | struct nuc900_audio *nuc900_audio = substream->runtime->private_data; | ||
114 | unsigned long val; | ||
115 | |||
116 | spin_lock(&nuc900_audio->lock); | ||
117 | |||
118 | val = AUDIO_READ(nuc900_audio->mmio + ACTL_CON); | ||
119 | |||
120 | if (val & R_DMA_IRQ) { | ||
121 | AUDIO_WRITE(nuc900_audio->mmio + ACTL_CON, val | R_DMA_IRQ); | ||
122 | |||
123 | val = AUDIO_READ(nuc900_audio->mmio + ACTL_RSR); | ||
124 | |||
125 | if (val & R_DMA_MIDDLE_IRQ) { | ||
126 | val |= R_DMA_MIDDLE_IRQ; | ||
127 | AUDIO_WRITE(nuc900_audio->mmio + ACTL_RSR, val); | ||
128 | } | ||
129 | |||
130 | if (val & R_DMA_END_IRQ) { | ||
131 | val |= R_DMA_END_IRQ; | ||
132 | AUDIO_WRITE(nuc900_audio->mmio + ACTL_RSR, val); | ||
133 | } | ||
134 | } else if (val & T_DMA_IRQ) { | ||
135 | AUDIO_WRITE(nuc900_audio->mmio + ACTL_CON, val | T_DMA_IRQ); | ||
136 | |||
137 | val = AUDIO_READ(nuc900_audio->mmio + ACTL_PSR); | ||
138 | |||
139 | if (val & P_DMA_MIDDLE_IRQ) { | ||
140 | val |= P_DMA_MIDDLE_IRQ; | ||
141 | AUDIO_WRITE(nuc900_audio->mmio + ACTL_PSR, val); | ||
142 | } | ||
143 | |||
144 | if (val & P_DMA_END_IRQ) { | ||
145 | val |= P_DMA_END_IRQ; | ||
146 | AUDIO_WRITE(nuc900_audio->mmio + ACTL_PSR, val); | ||
147 | } | ||
148 | } else { | ||
149 | dev_err(nuc900_audio->dev, "Wrong DMA interrupt status!\n"); | ||
150 | spin_unlock(&nuc900_audio->lock); | ||
151 | return IRQ_HANDLED; | ||
152 | } | ||
153 | |||
154 | spin_unlock(&nuc900_audio->lock); | ||
155 | |||
156 | snd_pcm_period_elapsed(substream); | ||
157 | |||
158 | return IRQ_HANDLED; | ||
159 | } | ||
160 | |||
161 | static int nuc900_dma_hw_free(struct snd_pcm_substream *substream) | ||
162 | { | ||
163 | snd_pcm_lib_free_pages(substream); | ||
164 | return 0; | ||
165 | } | ||
166 | |||
167 | static int nuc900_dma_prepare(struct snd_pcm_substream *substream) | ||
168 | { | ||
169 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
170 | struct nuc900_audio *nuc900_audio = runtime->private_data; | ||
171 | unsigned long flags, val; | ||
172 | |||
173 | spin_lock_irqsave(&nuc900_audio->lock, flags); | ||
174 | |||
175 | nuc900_update_dma_register(substream, | ||
176 | nuc900_audio->dma_addr[substream->stream], | ||
177 | nuc900_audio->buffersize[substream->stream]); | ||
178 | |||
179 | val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET); | ||
180 | |||
181 | switch (runtime->channels) { | ||
182 | case 1: | ||
183 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
184 | val &= ~(PLAY_LEFT_CHNNEL | PLAY_RIGHT_CHNNEL); | ||
185 | val |= PLAY_RIGHT_CHNNEL; | ||
186 | } else { | ||
187 | val &= ~(RECORD_LEFT_CHNNEL | RECORD_RIGHT_CHNNEL); | ||
188 | val |= RECORD_RIGHT_CHNNEL; | ||
189 | } | ||
190 | AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val); | ||
191 | break; | ||
192 | case 2: | ||
193 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
194 | val |= (PLAY_LEFT_CHNNEL | PLAY_RIGHT_CHNNEL); | ||
195 | else | ||
196 | val |= (RECORD_LEFT_CHNNEL | RECORD_RIGHT_CHNNEL); | ||
197 | AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val); | ||
198 | break; | ||
199 | default: | ||
200 | return -EINVAL; | ||
201 | } | ||
202 | spin_unlock_irqrestore(&nuc900_audio->lock, flags); | ||
203 | return 0; | ||
204 | } | ||
205 | |||
206 | static int nuc900_dma_trigger(struct snd_pcm_substream *substream, int cmd) | ||
207 | { | ||
208 | int ret = 0; | ||
209 | |||
210 | switch (cmd) { | ||
211 | case SNDRV_PCM_TRIGGER_START: | ||
212 | case SNDRV_PCM_TRIGGER_RESUME: | ||
213 | nuc900_dma_start(substream); | ||
214 | break; | ||
215 | |||
216 | case SNDRV_PCM_TRIGGER_STOP: | ||
217 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
218 | nuc900_dma_stop(substream); | ||
219 | break; | ||
220 | |||
221 | default: | ||
222 | ret = -EINVAL; | ||
223 | break; | ||
224 | } | ||
225 | |||
226 | return ret; | ||
227 | } | ||
228 | |||
229 | int nuc900_dma_getposition(struct snd_pcm_substream *substream, | ||
230 | dma_addr_t *src, dma_addr_t *dst) | ||
231 | { | ||
232 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
233 | struct nuc900_audio *nuc900_audio = runtime->private_data; | ||
234 | |||
235 | if (src != NULL) | ||
236 | *src = AUDIO_READ(nuc900_audio->mmio + ACTL_PDSTC); | ||
237 | |||
238 | if (dst != NULL) | ||
239 | *dst = AUDIO_READ(nuc900_audio->mmio + ACTL_RDSTC); | ||
240 | |||
241 | return 0; | ||
242 | } | ||
243 | |||
244 | static snd_pcm_uframes_t nuc900_dma_pointer(struct snd_pcm_substream *substream) | ||
245 | { | ||
246 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
247 | dma_addr_t src, dst; | ||
248 | unsigned long res; | ||
249 | |||
250 | nuc900_dma_getposition(substream, &src, &dst); | ||
251 | |||
252 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) | ||
253 | res = dst - runtime->dma_addr; | ||
254 | else | ||
255 | res = src - runtime->dma_addr; | ||
256 | |||
257 | return bytes_to_frames(substream->runtime, res); | ||
258 | } | ||
259 | |||
260 | static int nuc900_dma_open(struct snd_pcm_substream *substream) | ||
261 | { | ||
262 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
263 | struct nuc900_audio *nuc900_audio; | ||
264 | |||
265 | snd_soc_set_runtime_hwparams(substream, &nuc900_pcm_hardware); | ||
266 | |||
267 | nuc900_audio = nuc900_ac97_data; | ||
268 | |||
269 | if (request_irq(nuc900_audio->irq_num, nuc900_dma_interrupt, | ||
270 | IRQF_DISABLED, "nuc900-dma", substream)) | ||
271 | return -EBUSY; | ||
272 | |||
273 | runtime->private_data = nuc900_audio; | ||
274 | |||
275 | return 0; | ||
276 | } | ||
277 | |||
278 | static int nuc900_dma_close(struct snd_pcm_substream *substream) | ||
279 | { | ||
280 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
281 | struct nuc900_audio *nuc900_audio = runtime->private_data; | ||
282 | |||
283 | free_irq(nuc900_audio->irq_num, substream); | ||
284 | |||
285 | return 0; | ||
286 | } | ||
287 | |||
288 | static int nuc900_dma_mmap(struct snd_pcm_substream *substream, | ||
289 | struct vm_area_struct *vma) | ||
290 | { | ||
291 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
292 | |||
293 | return dma_mmap_writecombine(substream->pcm->card->dev, vma, | ||
294 | runtime->dma_area, | ||
295 | runtime->dma_addr, | ||
296 | runtime->dma_bytes); | ||
297 | } | ||
298 | |||
299 | static struct snd_pcm_ops nuc900_dma_ops = { | ||
300 | .open = nuc900_dma_open, | ||
301 | .close = nuc900_dma_close, | ||
302 | .ioctl = snd_pcm_lib_ioctl, | ||
303 | .hw_params = nuc900_dma_hw_params, | ||
304 | .hw_free = nuc900_dma_hw_free, | ||
305 | .prepare = nuc900_dma_prepare, | ||
306 | .trigger = nuc900_dma_trigger, | ||
307 | .pointer = nuc900_dma_pointer, | ||
308 | .mmap = nuc900_dma_mmap, | ||
309 | }; | ||
310 | |||
311 | static void nuc900_dma_free_dma_buffers(struct snd_pcm *pcm) | ||
312 | { | ||
313 | snd_pcm_lib_preallocate_free_for_all(pcm); | ||
314 | } | ||
315 | |||
316 | static u64 nuc900_pcm_dmamask = DMA_BIT_MASK(32); | ||
317 | static int nuc900_dma_new(struct snd_card *card, | ||
318 | struct snd_soc_dai *dai, struct snd_pcm *pcm) | ||
319 | { | ||
320 | if (!card->dev->dma_mask) | ||
321 | card->dev->dma_mask = &nuc900_pcm_dmamask; | ||
322 | if (!card->dev->coherent_dma_mask) | ||
323 | card->dev->coherent_dma_mask = DMA_BIT_MASK(32); | ||
324 | |||
325 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, | ||
326 | card->dev, 4 * 1024, (4 * 1024) - 1); | ||
327 | |||
328 | return 0; | ||
329 | } | ||
330 | |||
331 | struct snd_soc_platform nuc900_soc_platform = { | ||
332 | .name = "nuc900-dma", | ||
333 | .pcm_ops = &nuc900_dma_ops, | ||
334 | .pcm_new = nuc900_dma_new, | ||
335 | .pcm_free = nuc900_dma_free_dma_buffers, | ||
336 | } | ||
337 | EXPORT_SYMBOL_GPL(nuc900_soc_platform); | ||
338 | |||
339 | static int __init nuc900_soc_platform_init(void) | ||
340 | { | ||
341 | return snd_soc_register_platform(&nuc900_soc_platform); | ||
342 | } | ||
343 | |||
344 | static void __exit nuc900_soc_platform_exit(void) | ||
345 | { | ||
346 | snd_soc_unregister_platform(&nuc900_soc_platform); | ||
347 | } | ||
348 | |||
349 | module_init(nuc900_soc_platform_init); | ||
350 | module_exit(nuc900_soc_platform_exit); | ||
351 | |||
352 | MODULE_AUTHOR("Wan ZongShun, <mcuos.com@gmail.com>"); | ||
353 | MODULE_DESCRIPTION("nuc900 Audio DMA module"); | ||
354 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index 6f44cb4d30b8..86f213905e2c 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c | |||
@@ -59,6 +59,7 @@ struct omap_mcbsp_data { | |||
59 | int configured; | 59 | int configured; |
60 | unsigned int in_freq; | 60 | unsigned int in_freq; |
61 | int clk_div; | 61 | int clk_div; |
62 | int wlen; | ||
62 | }; | 63 | }; |
63 | 64 | ||
64 | #define to_mcbsp(priv) container_of((priv), struct omap_mcbsp_data, bus_id) | 65 | #define to_mcbsp(priv) container_of((priv), struct omap_mcbsp_data, bus_id) |
@@ -154,20 +155,51 @@ static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream) | |||
154 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 155 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
155 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | 156 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; |
156 | struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); | 157 | struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); |
158 | struct omap_pcm_dma_data *dma_data; | ||
157 | int dma_op_mode = omap_mcbsp_get_dma_op_mode(mcbsp_data->bus_id); | 159 | int dma_op_mode = omap_mcbsp_get_dma_op_mode(mcbsp_data->bus_id); |
158 | int samples; | 160 | int words; |
161 | |||
162 | dma_data = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream); | ||
159 | 163 | ||
160 | /* TODO: Currently, MODE_ELEMENT == MODE_FRAME */ | 164 | /* TODO: Currently, MODE_ELEMENT == MODE_FRAME */ |
161 | if (dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) | 165 | if (dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) |
162 | samples = snd_pcm_lib_period_bytes(substream) >> 1; | 166 | /* |
167 | * Configure McBSP threshold based on either: | ||
168 | * packet_size, when the sDMA is in packet mode, or | ||
169 | * based on the period size. | ||
170 | */ | ||
171 | if (dma_data->packet_size) | ||
172 | words = dma_data->packet_size; | ||
173 | else | ||
174 | words = snd_pcm_lib_period_bytes(substream) / | ||
175 | (mcbsp_data->wlen / 8); | ||
163 | else | 176 | else |
164 | samples = 1; | 177 | words = 1; |
165 | 178 | ||
166 | /* Configure McBSP internal buffer usage */ | 179 | /* Configure McBSP internal buffer usage */ |
167 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 180 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
168 | omap_mcbsp_set_tx_threshold(mcbsp_data->bus_id, samples - 1); | 181 | omap_mcbsp_set_tx_threshold(mcbsp_data->bus_id, words); |
169 | else | 182 | else |
170 | omap_mcbsp_set_rx_threshold(mcbsp_data->bus_id, samples - 1); | 183 | omap_mcbsp_set_rx_threshold(mcbsp_data->bus_id, words); |
184 | } | ||
185 | |||
186 | static int omap_mcbsp_hwrule_min_buffersize(struct snd_pcm_hw_params *params, | ||
187 | struct snd_pcm_hw_rule *rule) | ||
188 | { | ||
189 | struct snd_interval *buffer_size = hw_param_interval(params, | ||
190 | SNDRV_PCM_HW_PARAM_BUFFER_SIZE); | ||
191 | struct snd_interval *channels = hw_param_interval(params, | ||
192 | SNDRV_PCM_HW_PARAM_CHANNELS); | ||
193 | struct omap_mcbsp_data *mcbsp_data = rule->private; | ||
194 | struct snd_interval frames; | ||
195 | int size; | ||
196 | |||
197 | snd_interval_any(&frames); | ||
198 | size = omap_mcbsp_get_fifo_size(mcbsp_data->bus_id); | ||
199 | |||
200 | frames.min = size / channels->min; | ||
201 | frames.integer = 1; | ||
202 | return snd_interval_refine(buffer_size, &frames); | ||
171 | } | 203 | } |
172 | 204 | ||
173 | static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream, | 205 | static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream, |
@@ -182,33 +214,35 @@ static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream, | |||
182 | if (!cpu_dai->active) | 214 | if (!cpu_dai->active) |
183 | err = omap_mcbsp_request(bus_id); | 215 | err = omap_mcbsp_request(bus_id); |
184 | 216 | ||
217 | /* | ||
218 | * OMAP3 McBSP FIFO is word structured. | ||
219 | * McBSP2 has 1024 + 256 = 1280 word long buffer, | ||
220 | * McBSP1,3,4,5 has 128 word long buffer | ||
221 | * This means that the size of the FIFO depends on the sample format. | ||
222 | * For example on McBSP3: | ||
223 | * 16bit samples: size is 128 * 2 = 256 bytes | ||
224 | * 32bit samples: size is 128 * 4 = 512 bytes | ||
225 | * It is simpler to place constraint for buffer and period based on | ||
226 | * channels. | ||
227 | * McBSP3 as example again (16 or 32 bit samples): | ||
228 | * 1 channel (mono): size is 128 frames (128 words) | ||
229 | * 2 channels (stereo): size is 128 / 2 = 64 frames (2 * 64 words) | ||
230 | * 4 channels: size is 128 / 4 = 32 frames (4 * 32 words) | ||
231 | */ | ||
185 | if (cpu_is_omap343x()) { | 232 | if (cpu_is_omap343x()) { |
186 | int dma_op_mode = omap_mcbsp_get_dma_op_mode(bus_id); | ||
187 | int max_period; | ||
188 | |||
189 | /* | 233 | /* |
190 | * McBSP2 in OMAP3 has 1024 * 32-bit internal audio buffer. | 234 | * Rule for the buffer size. We should not allow |
191 | * Set constraint for minimum buffer size to the same than FIFO | 235 | * smaller buffer than the FIFO size to avoid underruns |
192 | * size in order to avoid underruns in playback startup because | 236 | */ |
193 | * HW is keeping the DMA request active until FIFO is filled. | 237 | snd_pcm_hw_rule_add(substream->runtime, 0, |
194 | */ | 238 | SNDRV_PCM_HW_PARAM_CHANNELS, |
195 | if (bus_id == 1) | 239 | omap_mcbsp_hwrule_min_buffersize, |
196 | snd_pcm_hw_constraint_minmax(substream->runtime, | 240 | mcbsp_data, |
197 | SNDRV_PCM_HW_PARAM_BUFFER_BYTES, | 241 | SNDRV_PCM_HW_PARAM_BUFFER_SIZE, -1); |
198 | 4096, UINT_MAX); | 242 | |
199 | 243 | /* Make sure, that the period size is always even */ | |
200 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 244 | snd_pcm_hw_constraint_step(substream->runtime, 0, |
201 | max_period = omap_mcbsp_get_max_tx_threshold(bus_id); | 245 | SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 2); |
202 | else | ||
203 | max_period = omap_mcbsp_get_max_rx_threshold(bus_id); | ||
204 | |||
205 | max_period++; | ||
206 | max_period <<= 1; | ||
207 | |||
208 | if (dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) | ||
209 | snd_pcm_hw_constraint_minmax(substream->runtime, | ||
210 | SNDRV_PCM_HW_PARAM_PERIOD_BYTES, | ||
211 | 32, max_period); | ||
212 | } | 246 | } |
213 | 247 | ||
214 | return err; | 248 | return err; |
@@ -289,11 +323,14 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, | |||
289 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | 323 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; |
290 | struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); | 324 | struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); |
291 | struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs; | 325 | struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs; |
292 | int dma, bus_id = mcbsp_data->bus_id, id = cpu_dai->id; | 326 | struct omap_pcm_dma_data *dma_data; |
327 | int dma, bus_id = mcbsp_data->bus_id; | ||
293 | int wlen, channels, wpf, sync_mode = OMAP_DMA_SYNC_ELEMENT; | 328 | int wlen, channels, wpf, sync_mode = OMAP_DMA_SYNC_ELEMENT; |
329 | int pkt_size = 0; | ||
294 | unsigned long port; | 330 | unsigned long port; |
295 | unsigned int format, div, framesize, master; | 331 | unsigned int format, div, framesize, master; |
296 | 332 | ||
333 | dma_data = &omap_mcbsp_dai_dma_params[cpu_dai->id][substream->stream]; | ||
297 | if (cpu_class_is_omap1()) { | 334 | if (cpu_class_is_omap1()) { |
298 | dma = omap1_dma_reqs[bus_id][substream->stream]; | 335 | dma = omap1_dma_reqs[bus_id][substream->stream]; |
299 | port = omap1_mcbsp_port[bus_id][substream->stream]; | 336 | port = omap1_mcbsp_port[bus_id][substream->stream]; |
@@ -306,35 +343,74 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, | |||
306 | } else if (cpu_is_omap343x()) { | 343 | } else if (cpu_is_omap343x()) { |
307 | dma = omap24xx_dma_reqs[bus_id][substream->stream]; | 344 | dma = omap24xx_dma_reqs[bus_id][substream->stream]; |
308 | port = omap34xx_mcbsp_port[bus_id][substream->stream]; | 345 | port = omap34xx_mcbsp_port[bus_id][substream->stream]; |
309 | omap_mcbsp_dai_dma_params[id][substream->stream].set_threshold = | ||
310 | omap_mcbsp_set_threshold; | ||
311 | /* TODO: Currently, MODE_ELEMENT == MODE_FRAME */ | ||
312 | if (omap_mcbsp_get_dma_op_mode(bus_id) == | ||
313 | MCBSP_DMA_MODE_THRESHOLD) | ||
314 | sync_mode = OMAP_DMA_SYNC_FRAME; | ||
315 | } else { | 346 | } else { |
316 | return -ENODEV; | 347 | return -ENODEV; |
317 | } | 348 | } |
318 | omap_mcbsp_dai_dma_params[id][substream->stream].name = | ||
319 | substream->stream ? "Audio Capture" : "Audio Playback"; | ||
320 | omap_mcbsp_dai_dma_params[id][substream->stream].dma_req = dma; | ||
321 | omap_mcbsp_dai_dma_params[id][substream->stream].port_addr = port; | ||
322 | omap_mcbsp_dai_dma_params[id][substream->stream].sync_mode = sync_mode; | ||
323 | switch (params_format(params)) { | 349 | switch (params_format(params)) { |
324 | case SNDRV_PCM_FORMAT_S16_LE: | 350 | case SNDRV_PCM_FORMAT_S16_LE: |
325 | omap_mcbsp_dai_dma_params[id][substream->stream].data_type = | 351 | dma_data->data_type = OMAP_DMA_DATA_TYPE_S16; |
326 | OMAP_DMA_DATA_TYPE_S16; | 352 | wlen = 16; |
327 | break; | 353 | break; |
328 | case SNDRV_PCM_FORMAT_S32_LE: | 354 | case SNDRV_PCM_FORMAT_S32_LE: |
329 | omap_mcbsp_dai_dma_params[id][substream->stream].data_type = | 355 | dma_data->data_type = OMAP_DMA_DATA_TYPE_S32; |
330 | OMAP_DMA_DATA_TYPE_S32; | 356 | wlen = 32; |
331 | break; | 357 | break; |
332 | default: | 358 | default: |
333 | return -EINVAL; | 359 | return -EINVAL; |
334 | } | 360 | } |
361 | if (cpu_is_omap343x()) { | ||
362 | dma_data->set_threshold = omap_mcbsp_set_threshold; | ||
363 | /* TODO: Currently, MODE_ELEMENT == MODE_FRAME */ | ||
364 | if (omap_mcbsp_get_dma_op_mode(bus_id) == | ||
365 | MCBSP_DMA_MODE_THRESHOLD) { | ||
366 | int period_words, max_thrsh; | ||
367 | |||
368 | period_words = params_period_bytes(params) / (wlen / 8); | ||
369 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
370 | max_thrsh = omap_mcbsp_get_max_tx_threshold( | ||
371 | mcbsp_data->bus_id); | ||
372 | else | ||
373 | max_thrsh = omap_mcbsp_get_max_rx_threshold( | ||
374 | mcbsp_data->bus_id); | ||
375 | /* | ||
376 | * If the period contains less or equal number of words, | ||
377 | * we are using the original threshold mode setup: | ||
378 | * McBSP threshold = sDMA frame size = period_size | ||
379 | * Otherwise we switch to sDMA packet mode: | ||
380 | * McBSP threshold = sDMA packet size | ||
381 | * sDMA frame size = period size | ||
382 | */ | ||
383 | if (period_words > max_thrsh) { | ||
384 | int divider = 0; | ||
385 | |||
386 | /* | ||
387 | * Look for the biggest threshold value, which | ||
388 | * divides the period size evenly. | ||
389 | */ | ||
390 | divider = period_words / max_thrsh; | ||
391 | if (period_words % max_thrsh) | ||
392 | divider++; | ||
393 | while (period_words % divider && | ||
394 | divider < period_words) | ||
395 | divider++; | ||
396 | if (divider == period_words) | ||
397 | return -EINVAL; | ||
398 | |||
399 | pkt_size = period_words / divider; | ||
400 | sync_mode = OMAP_DMA_SYNC_PACKET; | ||
401 | } else { | ||
402 | sync_mode = OMAP_DMA_SYNC_FRAME; | ||
403 | } | ||
404 | } | ||
405 | } | ||
335 | 406 | ||
336 | snd_soc_dai_set_dma_data(cpu_dai, substream, | 407 | dma_data->name = substream->stream ? "Audio Capture" : "Audio Playback"; |
337 | &omap_mcbsp_dai_dma_params[id][substream->stream]); | 408 | dma_data->dma_req = dma; |
409 | dma_data->port_addr = port; | ||
410 | dma_data->sync_mode = sync_mode; | ||
411 | dma_data->packet_size = pkt_size; | ||
412 | |||
413 | snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data); | ||
338 | 414 | ||
339 | if (mcbsp_data->configured) { | 415 | if (mcbsp_data->configured) { |
340 | /* McBSP already configured by another stream */ | 416 | /* McBSP already configured by another stream */ |
@@ -360,7 +436,6 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, | |||
360 | switch (params_format(params)) { | 436 | switch (params_format(params)) { |
361 | case SNDRV_PCM_FORMAT_S16_LE: | 437 | case SNDRV_PCM_FORMAT_S16_LE: |
362 | /* Set word lengths */ | 438 | /* Set word lengths */ |
363 | wlen = 16; | ||
364 | regs->rcr2 |= RWDLEN2(OMAP_MCBSP_WORD_16); | 439 | regs->rcr2 |= RWDLEN2(OMAP_MCBSP_WORD_16); |
365 | regs->rcr1 |= RWDLEN1(OMAP_MCBSP_WORD_16); | 440 | regs->rcr1 |= RWDLEN1(OMAP_MCBSP_WORD_16); |
366 | regs->xcr2 |= XWDLEN2(OMAP_MCBSP_WORD_16); | 441 | regs->xcr2 |= XWDLEN2(OMAP_MCBSP_WORD_16); |
@@ -368,7 +443,6 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, | |||
368 | break; | 443 | break; |
369 | case SNDRV_PCM_FORMAT_S32_LE: | 444 | case SNDRV_PCM_FORMAT_S32_LE: |
370 | /* Set word lengths */ | 445 | /* Set word lengths */ |
371 | wlen = 32; | ||
372 | regs->rcr2 |= RWDLEN2(OMAP_MCBSP_WORD_32); | 446 | regs->rcr2 |= RWDLEN2(OMAP_MCBSP_WORD_32); |
373 | regs->rcr1 |= RWDLEN1(OMAP_MCBSP_WORD_32); | 447 | regs->rcr1 |= RWDLEN1(OMAP_MCBSP_WORD_32); |
374 | regs->xcr2 |= XWDLEN2(OMAP_MCBSP_WORD_32); | 448 | regs->xcr2 |= XWDLEN2(OMAP_MCBSP_WORD_32); |
@@ -409,6 +483,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, | |||
409 | } | 483 | } |
410 | 484 | ||
411 | omap_mcbsp_config(bus_id, &mcbsp_data->regs); | 485 | omap_mcbsp_config(bus_id, &mcbsp_data->regs); |
486 | mcbsp_data->wlen = wlen; | ||
412 | mcbsp_data->configured = 1; | 487 | mcbsp_data->configured = 1; |
413 | 488 | ||
414 | return 0; | 489 | return 0; |
diff --git a/sound/soc/omap/omap3pandora.c b/sound/soc/omap/omap3pandora.c index 87ce842fa2e8..9eecac135bbb 100644 --- a/sound/soc/omap/omap3pandora.c +++ b/sound/soc/omap/omap3pandora.c | |||
@@ -43,12 +43,14 @@ | |||
43 | 43 | ||
44 | static struct regulator *omap3pandora_dac_reg; | 44 | static struct regulator *omap3pandora_dac_reg; |
45 | 45 | ||
46 | static int omap3pandora_cmn_hw_params(struct snd_pcm_substream *substream, | 46 | static int omap3pandora_hw_params(struct snd_pcm_substream *substream, |
47 | struct snd_pcm_hw_params *params, unsigned int fmt) | 47 | struct snd_pcm_hw_params *params) |
48 | { | 48 | { |
49 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 49 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
50 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; | 50 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; |
51 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | 51 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; |
52 | int fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | | ||
53 | SND_SOC_DAIFMT_CBS_CFS; | ||
52 | int ret; | 54 | int ret; |
53 | 55 | ||
54 | /* Set codec DAI configuration */ | 56 | /* Set codec DAI configuration */ |
@@ -91,24 +93,6 @@ static int omap3pandora_cmn_hw_params(struct snd_pcm_substream *substream, | |||
91 | return 0; | 93 | return 0; |
92 | } | 94 | } |
93 | 95 | ||
94 | static int omap3pandora_out_hw_params(struct snd_pcm_substream *substream, | ||
95 | struct snd_pcm_hw_params *params) | ||
96 | { | ||
97 | return omap3pandora_cmn_hw_params(substream, params, | ||
98 | SND_SOC_DAIFMT_I2S | | ||
99 | SND_SOC_DAIFMT_IB_NF | | ||
100 | SND_SOC_DAIFMT_CBS_CFS); | ||
101 | } | ||
102 | |||
103 | static int omap3pandora_in_hw_params(struct snd_pcm_substream *substream, | ||
104 | struct snd_pcm_hw_params *params) | ||
105 | { | ||
106 | return omap3pandora_cmn_hw_params(substream, params, | ||
107 | SND_SOC_DAIFMT_I2S | | ||
108 | SND_SOC_DAIFMT_NB_NF | | ||
109 | SND_SOC_DAIFMT_CBS_CFS); | ||
110 | } | ||
111 | |||
112 | static int omap3pandora_dac_event(struct snd_soc_dapm_widget *w, | 96 | static int omap3pandora_dac_event(struct snd_soc_dapm_widget *w, |
113 | struct snd_kcontrol *k, int event) | 97 | struct snd_kcontrol *k, int event) |
114 | { | 98 | { |
@@ -231,12 +215,8 @@ static int omap3pandora_in_init(struct snd_soc_codec *codec) | |||
231 | return snd_soc_dapm_sync(codec); | 215 | return snd_soc_dapm_sync(codec); |
232 | } | 216 | } |
233 | 217 | ||
234 | static struct snd_soc_ops omap3pandora_out_ops = { | 218 | static struct snd_soc_ops omap3pandora_ops = { |
235 | .hw_params = omap3pandora_out_hw_params, | 219 | .hw_params = omap3pandora_hw_params, |
236 | }; | ||
237 | |||
238 | static struct snd_soc_ops omap3pandora_in_ops = { | ||
239 | .hw_params = omap3pandora_in_hw_params, | ||
240 | }; | 220 | }; |
241 | 221 | ||
242 | /* Digital audio interface glue - connects codec <--> CPU */ | 222 | /* Digital audio interface glue - connects codec <--> CPU */ |
@@ -246,14 +226,14 @@ static struct snd_soc_dai_link omap3pandora_dai[] = { | |||
246 | .stream_name = "HiFi Out", | 226 | .stream_name = "HiFi Out", |
247 | .cpu_dai = &omap_mcbsp_dai[0], | 227 | .cpu_dai = &omap_mcbsp_dai[0], |
248 | .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI], | 228 | .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI], |
249 | .ops = &omap3pandora_out_ops, | 229 | .ops = &omap3pandora_ops, |
250 | .init = omap3pandora_out_init, | 230 | .init = omap3pandora_out_init, |
251 | }, { | 231 | }, { |
252 | .name = "TWL4030", | 232 | .name = "TWL4030", |
253 | .stream_name = "Line/Mic In", | 233 | .stream_name = "Line/Mic In", |
254 | .cpu_dai = &omap_mcbsp_dai[1], | 234 | .cpu_dai = &omap_mcbsp_dai[1], |
255 | .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI], | 235 | .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI], |
256 | .ops = &omap3pandora_in_ops, | 236 | .ops = &omap3pandora_ops, |
257 | .init = omap3pandora_in_init, | 237 | .init = omap3pandora_in_init, |
258 | } | 238 | } |
259 | }; | 239 | }; |
diff --git a/sound/soc/omap/rx51.c b/sound/soc/omap/rx51.c index 47d831ef2dbb..88052d29617f 100644 --- a/sound/soc/omap/rx51.c +++ b/sound/soc/omap/rx51.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/gpio.h> | 27 | #include <linux/gpio.h> |
28 | #include <linux/platform_device.h> | 28 | #include <linux/platform_device.h> |
29 | #include <sound/core.h> | 29 | #include <sound/core.h> |
30 | #include <sound/jack.h> | ||
30 | #include <sound/pcm.h> | 31 | #include <sound/pcm.h> |
31 | #include <sound/soc.h> | 32 | #include <sound/soc.h> |
32 | #include <sound/soc-dapm.h> | 33 | #include <sound/soc-dapm.h> |
@@ -37,14 +38,22 @@ | |||
37 | #include "omap-pcm.h" | 38 | #include "omap-pcm.h" |
38 | #include "../codecs/tlv320aic3x.h" | 39 | #include "../codecs/tlv320aic3x.h" |
39 | 40 | ||
41 | #define RX51_TVOUT_SEL_GPIO 40 | ||
42 | #define RX51_JACK_DETECT_GPIO 177 | ||
40 | /* | 43 | /* |
41 | * REVISIT: TWL4030 GPIO base in RX-51. Now statically defined to 192. This | 44 | * REVISIT: TWL4030 GPIO base in RX-51. Now statically defined to 192. This |
42 | * gpio is reserved in arch/arm/mach-omap2/board-rx51-peripherals.c | 45 | * gpio is reserved in arch/arm/mach-omap2/board-rx51-peripherals.c |
43 | */ | 46 | */ |
44 | #define RX51_SPEAKER_AMP_TWL_GPIO (192 + 7) | 47 | #define RX51_SPEAKER_AMP_TWL_GPIO (192 + 7) |
45 | 48 | ||
49 | enum { | ||
50 | RX51_JACK_DISABLED, | ||
51 | RX51_JACK_TVOUT, /* tv-out */ | ||
52 | }; | ||
53 | |||
46 | static int rx51_spk_func; | 54 | static int rx51_spk_func; |
47 | static int rx51_dmic_func; | 55 | static int rx51_dmic_func; |
56 | static int rx51_jack_func; | ||
48 | 57 | ||
49 | static void rx51_ext_control(struct snd_soc_codec *codec) | 58 | static void rx51_ext_control(struct snd_soc_codec *codec) |
50 | { | 59 | { |
@@ -57,6 +66,9 @@ static void rx51_ext_control(struct snd_soc_codec *codec) | |||
57 | else | 66 | else |
58 | snd_soc_dapm_disable_pin(codec, "DMic"); | 67 | snd_soc_dapm_disable_pin(codec, "DMic"); |
59 | 68 | ||
69 | gpio_set_value(RX51_TVOUT_SEL_GPIO, | ||
70 | rx51_jack_func == RX51_JACK_TVOUT); | ||
71 | |||
60 | snd_soc_dapm_sync(codec); | 72 | snd_soc_dapm_sync(codec); |
61 | } | 73 | } |
62 | 74 | ||
@@ -162,6 +174,40 @@ static int rx51_set_input(struct snd_kcontrol *kcontrol, | |||
162 | return 1; | 174 | return 1; |
163 | } | 175 | } |
164 | 176 | ||
177 | static int rx51_get_jack(struct snd_kcontrol *kcontrol, | ||
178 | struct snd_ctl_elem_value *ucontrol) | ||
179 | { | ||
180 | ucontrol->value.integer.value[0] = rx51_jack_func; | ||
181 | |||
182 | return 0; | ||
183 | } | ||
184 | |||
185 | static int rx51_set_jack(struct snd_kcontrol *kcontrol, | ||
186 | struct snd_ctl_elem_value *ucontrol) | ||
187 | { | ||
188 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
189 | |||
190 | if (rx51_jack_func == ucontrol->value.integer.value[0]) | ||
191 | return 0; | ||
192 | |||
193 | rx51_jack_func = ucontrol->value.integer.value[0]; | ||
194 | rx51_ext_control(codec); | ||
195 | |||
196 | return 1; | ||
197 | } | ||
198 | |||
199 | static struct snd_soc_jack rx51_av_jack; | ||
200 | |||
201 | static struct snd_soc_jack_gpio rx51_av_jack_gpios[] = { | ||
202 | { | ||
203 | .gpio = RX51_JACK_DETECT_GPIO, | ||
204 | .name = "avdet-gpio", | ||
205 | .report = SND_JACK_VIDEOOUT, | ||
206 | .invert = 1, | ||
207 | .debounce_time = 200, | ||
208 | }, | ||
209 | }; | ||
210 | |||
165 | static const struct snd_soc_dapm_widget aic34_dapm_widgets[] = { | 211 | static const struct snd_soc_dapm_widget aic34_dapm_widgets[] = { |
166 | SND_SOC_DAPM_SPK("Ext Spk", rx51_spk_event), | 212 | SND_SOC_DAPM_SPK("Ext Spk", rx51_spk_event), |
167 | SND_SOC_DAPM_MIC("DMic", NULL), | 213 | SND_SOC_DAPM_MIC("DMic", NULL), |
@@ -177,10 +223,12 @@ static const struct snd_soc_dapm_route audio_map[] = { | |||
177 | 223 | ||
178 | static const char *spk_function[] = {"Off", "On"}; | 224 | static const char *spk_function[] = {"Off", "On"}; |
179 | static const char *input_function[] = {"ADC", "Digital Mic"}; | 225 | static const char *input_function[] = {"ADC", "Digital Mic"}; |
226 | static const char *jack_function[] = {"Off", "TV-OUT"}; | ||
180 | 227 | ||
181 | static const struct soc_enum rx51_enum[] = { | 228 | static const struct soc_enum rx51_enum[] = { |
182 | SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(spk_function), spk_function), | 229 | SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(spk_function), spk_function), |
183 | SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(input_function), input_function), | 230 | SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(input_function), input_function), |
231 | SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(jack_function), jack_function), | ||
184 | }; | 232 | }; |
185 | 233 | ||
186 | static const struct snd_kcontrol_new aic34_rx51_controls[] = { | 234 | static const struct snd_kcontrol_new aic34_rx51_controls[] = { |
@@ -188,10 +236,13 @@ static const struct snd_kcontrol_new aic34_rx51_controls[] = { | |||
188 | rx51_get_spk, rx51_set_spk), | 236 | rx51_get_spk, rx51_set_spk), |
189 | SOC_ENUM_EXT("Input Select", rx51_enum[1], | 237 | SOC_ENUM_EXT("Input Select", rx51_enum[1], |
190 | rx51_get_input, rx51_set_input), | 238 | rx51_get_input, rx51_set_input), |
239 | SOC_ENUM_EXT("Jack Function", rx51_enum[2], | ||
240 | rx51_get_jack, rx51_set_jack), | ||
191 | }; | 241 | }; |
192 | 242 | ||
193 | static int rx51_aic34_init(struct snd_soc_codec *codec) | 243 | static int rx51_aic34_init(struct snd_soc_codec *codec) |
194 | { | 244 | { |
245 | struct snd_soc_card *card = codec->socdev->card; | ||
195 | int err; | 246 | int err; |
196 | 247 | ||
197 | /* Set up NC codec pins */ | 248 | /* Set up NC codec pins */ |
@@ -214,7 +265,16 @@ static int rx51_aic34_init(struct snd_soc_codec *codec) | |||
214 | 265 | ||
215 | snd_soc_dapm_sync(codec); | 266 | snd_soc_dapm_sync(codec); |
216 | 267 | ||
217 | return 0; | 268 | /* AV jack detection */ |
269 | err = snd_soc_jack_new(card, "AV Jack", | ||
270 | SND_JACK_VIDEOOUT, &rx51_av_jack); | ||
271 | if (err) | ||
272 | return err; | ||
273 | err = snd_soc_jack_add_gpios(&rx51_av_jack, | ||
274 | ARRAY_SIZE(rx51_av_jack_gpios), | ||
275 | rx51_av_jack_gpios); | ||
276 | |||
277 | return err; | ||
218 | } | 278 | } |
219 | 279 | ||
220 | /* Digital audio interface glue - connects codec <--> CPU */ | 280 | /* Digital audio interface glue - connects codec <--> CPU */ |
@@ -259,6 +319,11 @@ static int __init rx51_soc_init(void) | |||
259 | if (!machine_is_nokia_rx51()) | 319 | if (!machine_is_nokia_rx51()) |
260 | return -ENODEV; | 320 | return -ENODEV; |
261 | 321 | ||
322 | err = gpio_request(RX51_TVOUT_SEL_GPIO, "tvout_sel"); | ||
323 | if (err) | ||
324 | goto err_gpio_tvout_sel; | ||
325 | gpio_direction_output(RX51_TVOUT_SEL_GPIO, 0); | ||
326 | |||
262 | rx51_snd_device = platform_device_alloc("soc-audio", -1); | 327 | rx51_snd_device = platform_device_alloc("soc-audio", -1); |
263 | if (!rx51_snd_device) { | 328 | if (!rx51_snd_device) { |
264 | err = -ENOMEM; | 329 | err = -ENOMEM; |
@@ -277,13 +342,19 @@ static int __init rx51_soc_init(void) | |||
277 | err2: | 342 | err2: |
278 | platform_device_put(rx51_snd_device); | 343 | platform_device_put(rx51_snd_device); |
279 | err1: | 344 | err1: |
345 | gpio_free(RX51_TVOUT_SEL_GPIO); | ||
346 | err_gpio_tvout_sel: | ||
280 | 347 | ||
281 | return err; | 348 | return err; |
282 | } | 349 | } |
283 | 350 | ||
284 | static void __exit rx51_soc_exit(void) | 351 | static void __exit rx51_soc_exit(void) |
285 | { | 352 | { |
353 | snd_soc_jack_free_gpios(&rx51_av_jack, ARRAY_SIZE(rx51_av_jack_gpios), | ||
354 | rx51_av_jack_gpios); | ||
355 | |||
286 | platform_device_unregister(rx51_snd_device); | 356 | platform_device_unregister(rx51_snd_device); |
357 | gpio_free(RX51_TVOUT_SEL_GPIO); | ||
287 | } | 358 | } |
288 | 359 | ||
289 | module_init(rx51_soc_init); | 360 | module_init(rx51_soc_init); |
diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig index 2a7cc222d098..213963ac3c28 100644 --- a/sound/soc/s3c24xx/Kconfig +++ b/sound/soc/s3c24xx/Kconfig | |||
@@ -1,6 +1,6 @@ | |||
1 | config SND_S3C24XX_SOC | 1 | config SND_S3C24XX_SOC |
2 | tristate "SoC Audio for the Samsung S3CXXXX chips" | 2 | tristate "SoC Audio for the Samsung S3CXXXX chips" |
3 | depends on ARCH_S3C2410 || ARCH_S3C64XX | 3 | depends on ARCH_S3C2410 || ARCH_S3C64XX || ARCH_S5PC100 || ARCH_S5PV210 |
4 | select S3C64XX_DMA if ARCH_S3C64XX | 4 | select S3C64XX_DMA if ARCH_S3C64XX |
5 | help | 5 | help |
6 | Say Y or M if you want to add support for codecs attached to | 6 | Say Y or M if you want to add support for codecs attached to |
@@ -120,8 +120,14 @@ config SND_S3C24XX_SOC_SIMTEC_HERMES | |||
120 | 120 | ||
121 | config SND_SOC_SMDK_WM9713 | 121 | config SND_SOC_SMDK_WM9713 |
122 | tristate "SoC AC97 Audio support for SMDK with WM9713" | 122 | tristate "SoC AC97 Audio support for SMDK with WM9713" |
123 | depends on SND_S3C24XX_SOC && MACH_SMDK6410 | 123 | depends on SND_S3C24XX_SOC && (MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110) |
124 | select SND_SOC_WM9713 | 124 | select SND_SOC_WM9713 |
125 | select SND_S3C_SOC_AC97 | 125 | select SND_S3C_SOC_AC97 |
126 | help | 126 | help |
127 | Sat Y if you want to add support for SoC audio on the SMDK. | 127 | Sat Y if you want to add support for SoC audio on the SMDK. |
128 | |||
129 | config SND_S3C64XX_SOC_SMARTQ | ||
130 | tristate "SoC I2S Audio support for SmartQ board" | ||
131 | depends on SND_S3C24XX_SOC && MACH_SMARTQ | ||
132 | select SND_S3C64XX_SOC_I2S | ||
133 | select SND_SOC_WM8750 | ||
diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile index 81d8dc503f87..50172c385d90 100644 --- a/sound/soc/s3c24xx/Makefile +++ b/sound/soc/s3c24xx/Makefile | |||
@@ -29,6 +29,7 @@ snd-soc-s3c24xx-simtec-hermes-objs := s3c24xx_simtec_hermes.o | |||
29 | snd-soc-s3c24xx-simtec-tlv320aic23-objs := s3c24xx_simtec_tlv320aic23.o | 29 | snd-soc-s3c24xx-simtec-tlv320aic23-objs := s3c24xx_simtec_tlv320aic23.o |
30 | snd-soc-smdk64xx-wm8580-objs := smdk64xx_wm8580.o | 30 | snd-soc-smdk64xx-wm8580-objs := smdk64xx_wm8580.o |
31 | snd-soc-smdk-wm9713-objs := smdk_wm9713.o | 31 | snd-soc-smdk-wm9713-objs := smdk_wm9713.o |
32 | snd-soc-s3c64xx-smartq-wm8987-objs := smartq_wm8987.o | ||
32 | 33 | ||
33 | obj-$(CONFIG_SND_S3C24XX_SOC_JIVE_WM8750) += snd-soc-jive-wm8750.o | 34 | obj-$(CONFIG_SND_S3C24XX_SOC_JIVE_WM8750) += snd-soc-jive-wm8750.o |
34 | obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o | 35 | obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o |
@@ -41,3 +42,4 @@ obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC_HERMES) += snd-soc-s3c24xx-simtec-hermes.o | |||
41 | obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC_TLV320AIC23) += snd-soc-s3c24xx-simtec-tlv320aic23.o | 42 | obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC_TLV320AIC23) += snd-soc-s3c24xx-simtec-tlv320aic23.o |
42 | obj-$(CONFIG_SND_S3C64XX_SOC_WM8580) += snd-soc-smdk64xx-wm8580.o | 43 | obj-$(CONFIG_SND_S3C64XX_SOC_WM8580) += snd-soc-smdk64xx-wm8580.o |
43 | obj-$(CONFIG_SND_SOC_SMDK_WM9713) += snd-soc-smdk-wm9713.o | 44 | obj-$(CONFIG_SND_SOC_SMDK_WM9713) += snd-soc-smdk-wm9713.o |
45 | obj-$(CONFIG_SND_S3C64XX_SOC_SMARTQ) += snd-soc-s3c64xx-smartq-wm8987.o | ||
diff --git a/sound/soc/s3c24xx/s3c-ac97.c b/sound/soc/s3c24xx/s3c-ac97.c index ecf4fd04ae96..31f6d45b6384 100644 --- a/sound/soc/s3c24xx/s3c-ac97.c +++ b/sound/soc/s3c24xx/s3c-ac97.c | |||
@@ -31,7 +31,6 @@ | |||
31 | #define AC_CMD_DATA(x) (x & 0xffff) | 31 | #define AC_CMD_DATA(x) (x & 0xffff) |
32 | 32 | ||
33 | struct s3c_ac97_info { | 33 | struct s3c_ac97_info { |
34 | unsigned state; | ||
35 | struct clk *ac97_clk; | 34 | struct clk *ac97_clk; |
36 | void __iomem *regs; | 35 | void __iomem *regs; |
37 | struct mutex lock; | 36 | struct mutex lock; |
diff --git a/sound/soc/s3c24xx/s3c-dma.c b/sound/soc/s3c24xx/s3c-dma.c index 1b61c23ff300..f1b1bc4bacfb 100644 --- a/sound/soc/s3c24xx/s3c-dma.c +++ b/sound/soc/s3c24xx/s3c-dma.c | |||
@@ -94,8 +94,7 @@ static void s3c_dma_enqueue(struct snd_pcm_substream *substream) | |||
94 | 94 | ||
95 | if ((pos + len) > prtd->dma_end) { | 95 | if ((pos + len) > prtd->dma_end) { |
96 | len = prtd->dma_end - pos; | 96 | len = prtd->dma_end - pos; |
97 | pr_debug(KERN_DEBUG "%s: corrected dma len %ld\n", | 97 | pr_debug("%s: corrected dma len %ld\n", __func__, len); |
98 | __func__, len); | ||
99 | } | 98 | } |
100 | 99 | ||
101 | ret = s3c2410_dma_enqueue(prtd->params->channel, | 100 | ret = s3c2410_dma_enqueue(prtd->params->channel, |
diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.c b/sound/soc/s3c24xx/s3c-i2s-v2.c index 13311c8cf965..64376b2aac73 100644 --- a/sound/soc/s3c24xx/s3c-i2s-v2.c +++ b/sound/soc/s3c24xx/s3c-i2s-v2.c | |||
@@ -32,7 +32,8 @@ | |||
32 | 32 | ||
33 | #undef S3C_IIS_V2_SUPPORTED | 33 | #undef S3C_IIS_V2_SUPPORTED |
34 | 34 | ||
35 | #if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413) | 35 | #if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413) \ |
36 | || defined(CONFIG_CPU_S5PV210) | ||
36 | #define S3C_IIS_V2_SUPPORTED | 37 | #define S3C_IIS_V2_SUPPORTED |
37 | #endif | 38 | #endif |
38 | 39 | ||
diff --git a/sound/soc/s3c24xx/smartq_wm8987.c b/sound/soc/s3c24xx/smartq_wm8987.c new file mode 100644 index 000000000000..b480348140b0 --- /dev/null +++ b/sound/soc/s3c24xx/smartq_wm8987.c | |||
@@ -0,0 +1,295 @@ | |||
1 | /* sound/soc/s3c24xx/smartq_wm8987.c | ||
2 | * | ||
3 | * Copyright 2010 Maurus Cuelenaere <mcuelenaere@gmail.com> | ||
4 | * | ||
5 | * Based on smdk6410_wm8987.c | ||
6 | * Copyright 2007 Wolfson Microelectronics PLC. - linux@wolfsonmicro.com | ||
7 | * Graeme Gregory - graeme.gregory@wolfsonmicro.com | ||
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 | |||
16 | #include <linux/module.h> | ||
17 | #include <linux/platform_device.h> | ||
18 | #include <linux/gpio.h> | ||
19 | |||
20 | #include <sound/pcm.h> | ||
21 | #include <sound/pcm_params.h> | ||
22 | #include <sound/soc-dapm.h> | ||
23 | #include <sound/jack.h> | ||
24 | |||
25 | #include <asm/mach-types.h> | ||
26 | |||
27 | #include "s3c-dma.h" | ||
28 | #include "s3c64xx-i2s.h" | ||
29 | |||
30 | #include "../codecs/wm8750.h" | ||
31 | |||
32 | /* | ||
33 | * WM8987 is register compatible with WM8750, so using that as base driver. | ||
34 | */ | ||
35 | |||
36 | static struct snd_soc_card snd_soc_smartq; | ||
37 | |||
38 | static int smartq_hifi_hw_params(struct snd_pcm_substream *substream, | ||
39 | struct snd_pcm_hw_params *params) | ||
40 | { | ||
41 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
42 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; | ||
43 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | ||
44 | struct s3c_i2sv2_rate_calc div; | ||
45 | unsigned int clk = 0; | ||
46 | int ret; | ||
47 | |||
48 | s3c_i2sv2_iis_calc_rate(&div, NULL, params_rate(params), | ||
49 | s3c_i2sv2_get_clock(cpu_dai)); | ||
50 | |||
51 | switch (params_rate(params)) { | ||
52 | case 8000: | ||
53 | case 16000: | ||
54 | case 32000: | ||
55 | case 48000: | ||
56 | case 96000: | ||
57 | clk = 12288000; | ||
58 | break; | ||
59 | case 11025: | ||
60 | case 22050: | ||
61 | case 44100: | ||
62 | case 88200: | ||
63 | clk = 11289600; | ||
64 | break; | ||
65 | } | ||
66 | |||
67 | /* set codec DAI configuration */ | ||
68 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | | ||
69 | SND_SOC_DAIFMT_NB_NF | | ||
70 | SND_SOC_DAIFMT_CBS_CFS); | ||
71 | if (ret < 0) | ||
72 | return ret; | ||
73 | |||
74 | /* set cpu DAI configuration */ | ||
75 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | | ||
76 | SND_SOC_DAIFMT_NB_NF | | ||
77 | SND_SOC_DAIFMT_CBS_CFS); | ||
78 | if (ret < 0) | ||
79 | return ret; | ||
80 | |||
81 | /* set the codec system clock for DAC and ADC */ | ||
82 | ret = snd_soc_dai_set_sysclk(codec_dai, WM8750_SYSCLK, clk, | ||
83 | SND_SOC_CLOCK_IN); | ||
84 | if (ret < 0) | ||
85 | return ret; | ||
86 | |||
87 | /* set MCLK division for sample rate */ | ||
88 | ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C_I2SV2_DIV_RCLK, div.fs_div); | ||
89 | if (ret < 0) | ||
90 | return ret; | ||
91 | |||
92 | /* set prescaler division for sample rate */ | ||
93 | ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C_I2SV2_DIV_PRESCALER, | ||
94 | div.clk_div - 1); | ||
95 | if (ret < 0) | ||
96 | return ret; | ||
97 | |||
98 | return 0; | ||
99 | } | ||
100 | |||
101 | /* | ||
102 | * SmartQ WM8987 HiFi DAI operations. | ||
103 | */ | ||
104 | static struct snd_soc_ops smartq_hifi_ops = { | ||
105 | .hw_params = smartq_hifi_hw_params, | ||
106 | }; | ||
107 | |||
108 | static struct snd_soc_jack smartq_jack; | ||
109 | |||
110 | static struct snd_soc_jack_pin smartq_jack_pins[] = { | ||
111 | /* Disable speaker when headphone is plugged in */ | ||
112 | { | ||
113 | .pin = "Internal Speaker", | ||
114 | .mask = SND_JACK_HEADPHONE, | ||
115 | }, | ||
116 | }; | ||
117 | |||
118 | static struct snd_soc_jack_gpio smartq_jack_gpios[] = { | ||
119 | { | ||
120 | .gpio = S3C64XX_GPL(12), | ||
121 | .name = "headphone detect", | ||
122 | .report = SND_JACK_HEADPHONE, | ||
123 | .debounce_time = 200, | ||
124 | }, | ||
125 | }; | ||
126 | |||
127 | static const struct snd_kcontrol_new wm8987_smartq_controls[] = { | ||
128 | SOC_DAPM_PIN_SWITCH("Internal Speaker"), | ||
129 | SOC_DAPM_PIN_SWITCH("Headphone Jack"), | ||
130 | SOC_DAPM_PIN_SWITCH("Internal Mic"), | ||
131 | }; | ||
132 | |||
133 | static int smartq_speaker_event(struct snd_soc_dapm_widget *w, | ||
134 | struct snd_kcontrol *k, | ||
135 | int event) | ||
136 | { | ||
137 | gpio_set_value(S3C64XX_GPK(12), SND_SOC_DAPM_EVENT_OFF(event)); | ||
138 | |||
139 | return 0; | ||
140 | } | ||
141 | |||
142 | static const struct snd_soc_dapm_widget wm8987_dapm_widgets[] = { | ||
143 | SND_SOC_DAPM_SPK("Internal Speaker", smartq_speaker_event), | ||
144 | SND_SOC_DAPM_HP("Headphone Jack", NULL), | ||
145 | SND_SOC_DAPM_MIC("Internal Mic", NULL), | ||
146 | }; | ||
147 | |||
148 | static const struct snd_soc_dapm_route audio_map[] = { | ||
149 | {"Headphone Jack", NULL, "LOUT2"}, | ||
150 | {"Headphone Jack", NULL, "ROUT2"}, | ||
151 | |||
152 | {"Internal Speaker", NULL, "LOUT2"}, | ||
153 | {"Internal Speaker", NULL, "ROUT2"}, | ||
154 | |||
155 | {"Mic Bias", NULL, "Internal Mic"}, | ||
156 | {"LINPUT2", NULL, "Mic Bias"}, | ||
157 | }; | ||
158 | |||
159 | static int smartq_wm8987_init(struct snd_soc_codec *codec) | ||
160 | { | ||
161 | int err = 0; | ||
162 | |||
163 | /* Add SmartQ specific widgets */ | ||
164 | snd_soc_dapm_new_controls(codec, wm8987_dapm_widgets, | ||
165 | ARRAY_SIZE(wm8987_dapm_widgets)); | ||
166 | |||
167 | /* add SmartQ specific controls */ | ||
168 | err = snd_soc_add_controls(codec, wm8987_smartq_controls, | ||
169 | ARRAY_SIZE(wm8987_smartq_controls)); | ||
170 | |||
171 | if (err < 0) | ||
172 | return err; | ||
173 | |||
174 | /* setup SmartQ specific audio path */ | ||
175 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | ||
176 | |||
177 | /* set endpoints to not connected */ | ||
178 | snd_soc_dapm_nc_pin(codec, "LINPUT1"); | ||
179 | snd_soc_dapm_nc_pin(codec, "RINPUT1"); | ||
180 | snd_soc_dapm_nc_pin(codec, "OUT3"); | ||
181 | snd_soc_dapm_nc_pin(codec, "ROUT1"); | ||
182 | |||
183 | /* set endpoints to default off mode */ | ||
184 | snd_soc_dapm_enable_pin(codec, "Internal Speaker"); | ||
185 | snd_soc_dapm_enable_pin(codec, "Internal Mic"); | ||
186 | snd_soc_dapm_disable_pin(codec, "Headphone Jack"); | ||
187 | |||
188 | err = snd_soc_dapm_sync(codec); | ||
189 | if (err) | ||
190 | return err; | ||
191 | |||
192 | /* Headphone jack detection */ | ||
193 | err = snd_soc_jack_new(&snd_soc_smartq, "Headphone Jack", | ||
194 | SND_JACK_HEADPHONE, &smartq_jack); | ||
195 | if (err) | ||
196 | return err; | ||
197 | |||
198 | err = snd_soc_jack_add_pins(&smartq_jack, ARRAY_SIZE(smartq_jack_pins), | ||
199 | smartq_jack_pins); | ||
200 | if (err) | ||
201 | return err; | ||
202 | |||
203 | err = snd_soc_jack_add_gpios(&smartq_jack, | ||
204 | ARRAY_SIZE(smartq_jack_gpios), | ||
205 | smartq_jack_gpios); | ||
206 | |||
207 | return err; | ||
208 | } | ||
209 | |||
210 | static struct snd_soc_dai_link smartq_dai[] = { | ||
211 | { | ||
212 | .name = "wm8987", | ||
213 | .stream_name = "SmartQ Hi-Fi", | ||
214 | .cpu_dai = &s3c64xx_i2s_dai[0], | ||
215 | .codec_dai = &wm8750_dai, | ||
216 | .init = smartq_wm8987_init, | ||
217 | .ops = &smartq_hifi_ops, | ||
218 | }, | ||
219 | }; | ||
220 | |||
221 | static struct snd_soc_card snd_soc_smartq = { | ||
222 | .name = "SmartQ", | ||
223 | .platform = &s3c24xx_soc_platform, | ||
224 | .dai_link = smartq_dai, | ||
225 | .num_links = ARRAY_SIZE(smartq_dai), | ||
226 | }; | ||
227 | |||
228 | static struct snd_soc_device smartq_snd_devdata = { | ||
229 | .card = &snd_soc_smartq, | ||
230 | .codec_dev = &soc_codec_dev_wm8750, | ||
231 | }; | ||
232 | |||
233 | static struct platform_device *smartq_snd_device; | ||
234 | |||
235 | static int __init smartq_init(void) | ||
236 | { | ||
237 | int ret; | ||
238 | |||
239 | if (!machine_is_smartq7() && !machine_is_smartq5()) { | ||
240 | pr_info("Only SmartQ is supported by this ASoC driver\n"); | ||
241 | return -ENODEV; | ||
242 | } | ||
243 | |||
244 | smartq_snd_device = platform_device_alloc("soc-audio", -1); | ||
245 | if (!smartq_snd_device) | ||
246 | return -ENOMEM; | ||
247 | |||
248 | platform_set_drvdata(smartq_snd_device, &smartq_snd_devdata); | ||
249 | smartq_snd_devdata.dev = &smartq_snd_device->dev; | ||
250 | |||
251 | ret = platform_device_add(smartq_snd_device); | ||
252 | if (ret) { | ||
253 | platform_device_put(smartq_snd_device); | ||
254 | return ret; | ||
255 | } | ||
256 | |||
257 | /* Initialise GPIOs used by amplifiers */ | ||
258 | ret = gpio_request(S3C64XX_GPK(12), "amplifiers shutdown"); | ||
259 | if (ret) { | ||
260 | dev_err(&smartq_snd_device->dev, "Failed to register GPK12\n"); | ||
261 | goto err_unregister_device; | ||
262 | } | ||
263 | |||
264 | /* Disable amplifiers */ | ||
265 | ret = gpio_direction_output(S3C64XX_GPK(12), 1); | ||
266 | if (ret) { | ||
267 | dev_err(&smartq_snd_device->dev, "Failed to configure GPK12\n"); | ||
268 | goto err_free_gpio_amp_shut; | ||
269 | } | ||
270 | |||
271 | return 0; | ||
272 | |||
273 | err_free_gpio_amp_shut: | ||
274 | gpio_free(S3C64XX_GPK(12)); | ||
275 | err_unregister_device: | ||
276 | platform_device_unregister(smartq_snd_device); | ||
277 | |||
278 | return ret; | ||
279 | } | ||
280 | |||
281 | static void __exit smartq_exit(void) | ||
282 | { | ||
283 | snd_soc_jack_free_gpios(&smartq_jack, ARRAY_SIZE(smartq_jack_gpios), | ||
284 | smartq_jack_gpios); | ||
285 | |||
286 | platform_device_unregister(smartq_snd_device); | ||
287 | } | ||
288 | |||
289 | module_init(smartq_init); | ||
290 | module_exit(smartq_exit); | ||
291 | |||
292 | /* Module information */ | ||
293 | MODULE_AUTHOR("Maurus Cuelenaere <mcuelenaere@gmail.com>"); | ||
294 | MODULE_DESCRIPTION("ALSA SoC SmartQ WM8987"); | ||
295 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/s3c24xx/smdk_wm9713.c b/sound/soc/s3c24xx/smdk_wm9713.c index 24fd39f38ccb..5527b9e88c98 100644 --- a/sound/soc/s3c24xx/smdk_wm9713.c +++ b/sound/soc/s3c24xx/smdk_wm9713.c | |||
@@ -25,6 +25,9 @@ static struct snd_soc_card smdk; | |||
25 | * Default CFG switch settings to use this driver: | 25 | * Default CFG switch settings to use this driver: |
26 | * | 26 | * |
27 | * SMDK6410: Set CFG1 1-3 On, CFG2 1-4 Off | 27 | * SMDK6410: Set CFG1 1-3 On, CFG2 1-4 Off |
28 | * SMDKC100: Set CFG6 1-3 On, CFG7 1 On | ||
29 | * SMDKC110: Set CFGB10 1-2 Off, CFGB12 1-3 On | ||
30 | * SMDKV210: Set CFGB10 1-2 Off, CFGB12 1-3 On | ||
28 | */ | 31 | */ |
29 | 32 | ||
30 | /* | 33 | /* |
diff --git a/sound/soc/s6000/s6000-i2s.c b/sound/soc/s6000/s6000-i2s.c index 5b9ac1759bd2..59e3fa7bcb05 100644 --- a/sound/soc/s6000/s6000-i2s.c +++ b/sound/soc/s6000/s6000-i2s.c | |||
@@ -451,16 +451,15 @@ static int __devinit s6000_i2s_probe(struct platform_device *pdev) | |||
451 | goto err_release_none; | 451 | goto err_release_none; |
452 | } | 452 | } |
453 | 453 | ||
454 | region = request_mem_region(scbmem->start, | 454 | region = request_mem_region(scbmem->start, resource_size(scbmem), |
455 | scbmem->end - scbmem->start + 1, | 455 | pdev->name); |
456 | pdev->name); | ||
457 | if (!region) { | 456 | if (!region) { |
458 | dev_err(&pdev->dev, "I2S SCB region already claimed\n"); | 457 | dev_err(&pdev->dev, "I2S SCB region already claimed\n"); |
459 | ret = -EBUSY; | 458 | ret = -EBUSY; |
460 | goto err_release_none; | 459 | goto err_release_none; |
461 | } | 460 | } |
462 | 461 | ||
463 | mmio = ioremap(scbmem->start, scbmem->end - scbmem->start + 1); | 462 | mmio = ioremap(scbmem->start, resource_size(scbmem)); |
464 | if (!mmio) { | 463 | if (!mmio) { |
465 | dev_err(&pdev->dev, "can't ioremap SCB region\n"); | 464 | dev_err(&pdev->dev, "can't ioremap SCB region\n"); |
466 | ret = -ENOMEM; | 465 | ret = -ENOMEM; |
@@ -474,9 +473,8 @@ static int __devinit s6000_i2s_probe(struct platform_device *pdev) | |||
474 | goto err_release_map; | 473 | goto err_release_map; |
475 | } | 474 | } |
476 | 475 | ||
477 | region = request_mem_region(sifmem->start, | 476 | region = request_mem_region(sifmem->start, resource_size(sifmem), |
478 | sifmem->end - sifmem->start + 1, | 477 | pdev->name); |
479 | pdev->name); | ||
480 | if (!region) { | 478 | if (!region) { |
481 | dev_err(&pdev->dev, "I2S SIF region already claimed\n"); | 479 | dev_err(&pdev->dev, "I2S SIF region already claimed\n"); |
482 | ret = -EBUSY; | 480 | ret = -EBUSY; |
@@ -490,8 +488,8 @@ static int __devinit s6000_i2s_probe(struct platform_device *pdev) | |||
490 | goto err_release_sif; | 488 | goto err_release_sif; |
491 | } | 489 | } |
492 | 490 | ||
493 | region = request_mem_region(dma1->start, dma1->end - dma1->start + 1, | 491 | region = request_mem_region(dma1->start, resource_size(dma1), |
494 | pdev->name); | 492 | pdev->name); |
495 | if (!region) { | 493 | if (!region) { |
496 | dev_err(&pdev->dev, "I2S DMA region already claimed\n"); | 494 | dev_err(&pdev->dev, "I2S DMA region already claimed\n"); |
497 | ret = -EBUSY; | 495 | ret = -EBUSY; |
@@ -500,9 +498,8 @@ static int __devinit s6000_i2s_probe(struct platform_device *pdev) | |||
500 | 498 | ||
501 | dma2 = platform_get_resource(pdev, IORESOURCE_DMA, 1); | 499 | dma2 = platform_get_resource(pdev, IORESOURCE_DMA, 1); |
502 | if (dma2) { | 500 | if (dma2) { |
503 | region = request_mem_region(dma2->start, | 501 | region = request_mem_region(dma2->start, resource_size(dma2), |
504 | dma2->end - dma2->start + 1, | 502 | pdev->name); |
505 | pdev->name); | ||
506 | if (!region) { | 503 | if (!region) { |
507 | dev_err(&pdev->dev, | 504 | dev_err(&pdev->dev, |
508 | "I2S DMA region already claimed\n"); | 505 | "I2S DMA region already claimed\n"); |
@@ -561,15 +558,15 @@ err_release_dev: | |||
561 | kfree(dev); | 558 | kfree(dev); |
562 | err_release_dma2: | 559 | err_release_dma2: |
563 | if (dma2) | 560 | if (dma2) |
564 | release_mem_region(dma2->start, dma2->end - dma2->start + 1); | 561 | release_mem_region(dma2->start, resource_size(dma2)); |
565 | err_release_dma1: | 562 | err_release_dma1: |
566 | release_mem_region(dma1->start, dma1->end - dma1->start + 1); | 563 | release_mem_region(dma1->start, resource_size(dma1)); |
567 | err_release_sif: | 564 | err_release_sif: |
568 | release_mem_region(sifmem->start, (sifmem->end - sifmem->start) + 1); | 565 | release_mem_region(sifmem->start, resource_size(sifmem)); |
569 | err_release_map: | 566 | err_release_map: |
570 | iounmap(mmio); | 567 | iounmap(mmio); |
571 | err_release_scb: | 568 | err_release_scb: |
572 | release_mem_region(scbmem->start, (scbmem->end - scbmem->start) + 1); | 569 | release_mem_region(scbmem->start, resource_size(scbmem)); |
573 | err_release_none: | 570 | err_release_none: |
574 | return ret; | 571 | return ret; |
575 | } | 572 | } |
@@ -590,19 +587,18 @@ static void __devexit s6000_i2s_remove(struct platform_device *pdev) | |||
590 | kfree(dev); | 587 | kfree(dev); |
591 | 588 | ||
592 | region = platform_get_resource(pdev, IORESOURCE_DMA, 0); | 589 | region = platform_get_resource(pdev, IORESOURCE_DMA, 0); |
593 | release_mem_region(region->start, region->end - region->start + 1); | 590 | release_mem_region(region->start, resource_size(region)); |
594 | 591 | ||
595 | region = platform_get_resource(pdev, IORESOURCE_DMA, 1); | 592 | region = platform_get_resource(pdev, IORESOURCE_DMA, 1); |
596 | if (region) | 593 | if (region) |
597 | release_mem_region(region->start, | 594 | release_mem_region(region->start, resource_size(region)); |
598 | region->end - region->start + 1); | ||
599 | 595 | ||
600 | region = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 596 | region = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
601 | release_mem_region(region->start, (region->end - region->start) + 1); | 597 | release_mem_region(region->start, resource_size(region)); |
602 | 598 | ||
603 | iounmap(mmio); | 599 | iounmap(mmio); |
604 | region = platform_get_resource(pdev, IORESOURCE_IO, 0); | 600 | region = platform_get_resource(pdev, IORESOURCE_IO, 0); |
605 | release_mem_region(region->start, (region->end - region->start) + 1); | 601 | release_mem_region(region->start, resource_size(region)); |
606 | } | 602 | } |
607 | 603 | ||
608 | static struct platform_driver s6000_i2s_driver = { | 604 | static struct platform_driver s6000_i2s_driver = { |
diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig index a1d14bc3c76f..52d7e8ed9c1f 100644 --- a/sound/soc/sh/Kconfig +++ b/sound/soc/sh/Kconfig | |||
@@ -48,7 +48,7 @@ config SND_SH7760_AC97 | |||
48 | 48 | ||
49 | config SND_FSI_AK4642 | 49 | config SND_FSI_AK4642 |
50 | bool "FSI-AK4642 sound support" | 50 | bool "FSI-AK4642 sound support" |
51 | depends on SND_SOC_SH4_FSI | 51 | depends on SND_SOC_SH4_FSI && I2C_SH_MOBILE |
52 | select SND_SOC_AK4642 | 52 | select SND_SOC_AK4642 |
53 | help | 53 | help |
54 | This option enables generic sound support for the | 54 | This option enables generic sound support for the |
@@ -56,7 +56,7 @@ config SND_FSI_AK4642 | |||
56 | 56 | ||
57 | config SND_FSI_DA7210 | 57 | config SND_FSI_DA7210 |
58 | bool "FSI-DA7210 sound support" | 58 | bool "FSI-DA7210 sound support" |
59 | depends on SND_SOC_SH4_FSI | 59 | depends on SND_SOC_SH4_FSI && I2C_SH_MOBILE |
60 | select SND_SOC_DA7210 | 60 | select SND_SOC_DA7210 |
61 | help | 61 | help |
62 | This option enables generic sound support for the | 62 | This option enables generic sound support for the |
diff --git a/sound/soc/sh/fsi-ak4642.c b/sound/soc/sh/fsi-ak4642.c index be018542314e..dad575a22622 100644 --- a/sound/soc/sh/fsi-ak4642.c +++ b/sound/soc/sh/fsi-ak4642.c | |||
@@ -9,16 +9,7 @@ | |||
9 | * for more details. | 9 | * for more details. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/moduleparam.h> | ||
14 | #include <linux/platform_device.h> | 12 | #include <linux/platform_device.h> |
15 | #include <linux/i2c.h> | ||
16 | #include <linux/io.h> | ||
17 | #include <sound/core.h> | ||
18 | #include <sound/pcm.h> | ||
19 | #include <sound/soc.h> | ||
20 | #include <sound/soc-dapm.h> | ||
21 | |||
22 | #include <sound/sh_fsi.h> | 13 | #include <sound/sh_fsi.h> |
23 | #include <../sound/soc/codecs/ak4642.h> | 14 | #include <../sound/soc/codecs/ak4642.h> |
24 | 15 | ||
@@ -38,7 +29,7 @@ static int fsi_ak4642_dai_init(struct snd_soc_codec *codec) | |||
38 | static struct snd_soc_dai_link fsi_dai_link = { | 29 | static struct snd_soc_dai_link fsi_dai_link = { |
39 | .name = "AK4642", | 30 | .name = "AK4642", |
40 | .stream_name = "AK4642", | 31 | .stream_name = "AK4642", |
41 | .cpu_dai = &fsi_soc_dai[0], /* fsi */ | 32 | .cpu_dai = &fsi_soc_dai[FSI_PORT_A], |
42 | .codec_dai = &ak4642_dai, | 33 | .codec_dai = &ak4642_dai, |
43 | .init = fsi_ak4642_dai_init, | 34 | .init = fsi_ak4642_dai_init, |
44 | .ops = NULL, | 35 | .ops = NULL, |
@@ -62,7 +53,7 @@ static int __init fsi_ak4642_init(void) | |||
62 | { | 53 | { |
63 | int ret = -ENOMEM; | 54 | int ret = -ENOMEM; |
64 | 55 | ||
65 | fsi_snd_device = platform_device_alloc("soc-audio", -1); | 56 | fsi_snd_device = platform_device_alloc("soc-audio", FSI_PORT_A); |
66 | if (!fsi_snd_device) | 57 | if (!fsi_snd_device) |
67 | goto out; | 58 | goto out; |
68 | 59 | ||
diff --git a/sound/soc/sh/fsi-da7210.c b/sound/soc/sh/fsi-da7210.c index 33b4d177f466..121bbb07bb03 100644 --- a/sound/soc/sh/fsi-da7210.c +++ b/sound/soc/sh/fsi-da7210.c | |||
@@ -10,16 +10,7 @@ | |||
10 | * option) any later version. | 10 | * option) any later version. |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <linux/interrupt.h> | ||
14 | #include <linux/platform_device.h> | 13 | #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> | 14 | #include <sound/sh_fsi.h> |
24 | #include "../codecs/da7210.h" | 15 | #include "../codecs/da7210.h" |
25 | 16 | ||
@@ -33,7 +24,7 @@ static int fsi_da7210_init(struct snd_soc_codec *codec) | |||
33 | static struct snd_soc_dai_link fsi_da7210_dai = { | 24 | static struct snd_soc_dai_link fsi_da7210_dai = { |
34 | .name = "DA7210", | 25 | .name = "DA7210", |
35 | .stream_name = "DA7210", | 26 | .stream_name = "DA7210", |
36 | .cpu_dai = &fsi_soc_dai[1], /* FSI B */ | 27 | .cpu_dai = &fsi_soc_dai[FSI_PORT_B], |
37 | .codec_dai = &da7210_dai, | 28 | .codec_dai = &da7210_dai, |
38 | .init = fsi_da7210_init, | 29 | .init = fsi_da7210_init, |
39 | }; | 30 | }; |
@@ -56,7 +47,7 @@ static int __init fsi_da7210_sound_init(void) | |||
56 | { | 47 | { |
57 | int ret; | 48 | int ret; |
58 | 49 | ||
59 | fsi_da7210_snd_device = platform_device_alloc("soc-audio", -1); | 50 | fsi_da7210_snd_device = platform_device_alloc("soc-audio", FSI_PORT_B); |
60 | if (!fsi_da7210_snd_device) | 51 | if (!fsi_da7210_snd_device) |
61 | return -ENOMEM; | 52 | return -ENOMEM; |
62 | 53 | ||
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index ec4acac49ebd..58c6bec642de 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c | |||
@@ -12,21 +12,12 @@ | |||
12 | * published by the Free Software Foundation. | 12 | * published by the Free Software Foundation. |
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/platform_device.h> | ||
18 | #include <linux/delay.h> | 15 | #include <linux/delay.h> |
19 | #include <linux/list.h> | ||
20 | #include <linux/pm_runtime.h> | 16 | #include <linux/pm_runtime.h> |
21 | #include <linux/io.h> | 17 | #include <linux/io.h> |
22 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
23 | #include <sound/core.h> | ||
24 | #include <sound/pcm.h> | ||
25 | #include <sound/initval.h> | ||
26 | #include <sound/soc.h> | 19 | #include <sound/soc.h> |
27 | #include <sound/pcm_params.h> | ||
28 | #include <sound/sh_fsi.h> | 20 | #include <sound/sh_fsi.h> |
29 | #include <asm/atomic.h> | ||
30 | 21 | ||
31 | #define DO_FMT 0x0000 | 22 | #define DO_FMT 0x0000 |
32 | #define DOFF_CTL 0x0004 | 23 | #define DOFF_CTL 0x0004 |
@@ -39,9 +30,11 @@ | |||
39 | #define DIDT 0x0020 | 30 | #define DIDT 0x0020 |
40 | #define DODT 0x0024 | 31 | #define DODT 0x0024 |
41 | #define MUTE_ST 0x0028 | 32 | #define MUTE_ST 0x0028 |
42 | #define REG_END MUTE_ST | 33 | #define OUT_SEL 0x0030 |
43 | 34 | #define REG_END OUT_SEL | |
44 | 35 | ||
36 | #define A_MST_CTLR 0x0180 | ||
37 | #define B_MST_CTLR 0x01A0 | ||
45 | #define CPU_INT_ST 0x01F4 | 38 | #define CPU_INT_ST 0x01F4 |
46 | #define CPU_IEMSK 0x01F8 | 39 | #define CPU_IEMSK 0x01F8 |
47 | #define CPU_IMSK 0x01FC | 40 | #define CPU_IMSK 0x01FC |
@@ -52,18 +45,18 @@ | |||
52 | #define CLK_RST 0x0210 | 45 | #define CLK_RST 0x0210 |
53 | #define SOFT_RST 0x0214 | 46 | #define SOFT_RST 0x0214 |
54 | #define FIFO_SZ 0x0218 | 47 | #define FIFO_SZ 0x0218 |
55 | #define MREG_START CPU_INT_ST | 48 | #define MREG_START A_MST_CTLR |
56 | #define MREG_END FIFO_SZ | 49 | #define MREG_END FIFO_SZ |
57 | 50 | ||
58 | /* DO_FMT */ | 51 | /* DO_FMT */ |
59 | /* DI_FMT */ | 52 | /* DI_FMT */ |
60 | #define CR_FMT(param) ((param) << 4) | 53 | #define CR_MONO (0x0 << 4) |
61 | # define CR_MONO 0x0 | 54 | #define CR_MONO_D (0x1 << 4) |
62 | # define CR_MONO_D 0x1 | 55 | #define CR_PCM (0x2 << 4) |
63 | # define CR_PCM 0x2 | 56 | #define CR_I2S (0x3 << 4) |
64 | # define CR_I2S 0x3 | 57 | #define CR_TDM (0x4 << 4) |
65 | # define CR_TDM 0x4 | 58 | #define CR_TDM_D (0x5 << 4) |
66 | # define CR_TDM_D 0x5 | 59 | #define CR_SPDIF 0x00100120 |
67 | 60 | ||
68 | /* DOFF_CTL */ | 61 | /* DOFF_CTL */ |
69 | /* DIFF_CTL */ | 62 | /* DIFF_CTL */ |
@@ -75,6 +68,14 @@ | |||
75 | #define ERR_UNDER 0x00000001 | 68 | #define ERR_UNDER 0x00000001 |
76 | #define ST_ERR (ERR_OVER | ERR_UNDER) | 69 | #define ST_ERR (ERR_OVER | ERR_UNDER) |
77 | 70 | ||
71 | /* CKG1 */ | ||
72 | #define ACKMD_MASK 0x00007000 | ||
73 | #define BPFMD_MASK 0x00000700 | ||
74 | |||
75 | /* A/B MST_CTLR */ | ||
76 | #define BP (1 << 4) /* Fix the signal of Biphase output */ | ||
77 | #define SE (1 << 0) /* Fix the master clock */ | ||
78 | |||
78 | /* CLK_RST */ | 79 | /* CLK_RST */ |
79 | #define B_CLK 0x00000010 | 80 | #define B_CLK 0x00000010 |
80 | #define A_CLK 0x00000001 | 81 | #define A_CLK 0x00000001 |
@@ -119,9 +120,13 @@ struct fsi_priv { | |||
119 | int period_len; | 120 | int period_len; |
120 | int buffer_len; | 121 | int buffer_len; |
121 | int periods; | 122 | int periods; |
123 | |||
124 | u32 mst_ctrl; | ||
122 | }; | 125 | }; |
123 | 126 | ||
124 | struct fsi_regs { | 127 | struct fsi_core { |
128 | int ver; | ||
129 | |||
125 | u32 int_st; | 130 | u32 int_st; |
126 | u32 iemsk; | 131 | u32 iemsk; |
127 | u32 imsk; | 132 | u32 imsk; |
@@ -132,7 +137,7 @@ struct fsi_master { | |||
132 | int irq; | 137 | int irq; |
133 | struct fsi_priv fsia; | 138 | struct fsi_priv fsia; |
134 | struct fsi_priv fsib; | 139 | struct fsi_priv fsib; |
135 | struct fsi_regs *regs; | 140 | struct fsi_core *core; |
136 | struct sh_fsi_platform_info *info; | 141 | struct sh_fsi_platform_info *info; |
137 | spinlock_t lock; | 142 | spinlock_t lock; |
138 | }; | 143 | }; |
@@ -169,24 +174,30 @@ static void __fsi_reg_mask_set(u32 reg, u32 mask, u32 data) | |||
169 | 174 | ||
170 | static void fsi_reg_write(struct fsi_priv *fsi, u32 reg, u32 data) | 175 | static void fsi_reg_write(struct fsi_priv *fsi, u32 reg, u32 data) |
171 | { | 176 | { |
172 | if (reg > REG_END) | 177 | if (reg > REG_END) { |
178 | pr_err("fsi: register access err (%s)\n", __func__); | ||
173 | return; | 179 | return; |
180 | } | ||
174 | 181 | ||
175 | __fsi_reg_write((u32)(fsi->base + reg), data); | 182 | __fsi_reg_write((u32)(fsi->base + reg), data); |
176 | } | 183 | } |
177 | 184 | ||
178 | static u32 fsi_reg_read(struct fsi_priv *fsi, u32 reg) | 185 | static u32 fsi_reg_read(struct fsi_priv *fsi, u32 reg) |
179 | { | 186 | { |
180 | if (reg > REG_END) | 187 | if (reg > REG_END) { |
188 | pr_err("fsi: register access err (%s)\n", __func__); | ||
181 | return 0; | 189 | return 0; |
190 | } | ||
182 | 191 | ||
183 | return __fsi_reg_read((u32)(fsi->base + reg)); | 192 | return __fsi_reg_read((u32)(fsi->base + reg)); |
184 | } | 193 | } |
185 | 194 | ||
186 | static void fsi_reg_mask_set(struct fsi_priv *fsi, u32 reg, u32 mask, u32 data) | 195 | static void fsi_reg_mask_set(struct fsi_priv *fsi, u32 reg, u32 mask, u32 data) |
187 | { | 196 | { |
188 | if (reg > REG_END) | 197 | if (reg > REG_END) { |
198 | pr_err("fsi: register access err (%s)\n", __func__); | ||
189 | return; | 199 | return; |
200 | } | ||
190 | 201 | ||
191 | __fsi_reg_mask_set((u32)(fsi->base + reg), mask, data); | 202 | __fsi_reg_mask_set((u32)(fsi->base + reg), mask, data); |
192 | } | 203 | } |
@@ -196,8 +207,10 @@ static void fsi_master_write(struct fsi_master *master, u32 reg, u32 data) | |||
196 | unsigned long flags; | 207 | unsigned long flags; |
197 | 208 | ||
198 | if ((reg < MREG_START) || | 209 | if ((reg < MREG_START) || |
199 | (reg > MREG_END)) | 210 | (reg > MREG_END)) { |
211 | pr_err("fsi: register access err (%s)\n", __func__); | ||
200 | return; | 212 | return; |
213 | } | ||
201 | 214 | ||
202 | spin_lock_irqsave(&master->lock, flags); | 215 | spin_lock_irqsave(&master->lock, flags); |
203 | __fsi_reg_write((u32)(master->base + reg), data); | 216 | __fsi_reg_write((u32)(master->base + reg), data); |
@@ -210,8 +223,10 @@ static u32 fsi_master_read(struct fsi_master *master, u32 reg) | |||
210 | unsigned long flags; | 223 | unsigned long flags; |
211 | 224 | ||
212 | if ((reg < MREG_START) || | 225 | if ((reg < MREG_START) || |
213 | (reg > MREG_END)) | 226 | (reg > MREG_END)) { |
227 | pr_err("fsi: register access err (%s)\n", __func__); | ||
214 | return 0; | 228 | return 0; |
229 | } | ||
215 | 230 | ||
216 | spin_lock_irqsave(&master->lock, flags); | 231 | spin_lock_irqsave(&master->lock, flags); |
217 | ret = __fsi_reg_read((u32)(master->base + reg)); | 232 | ret = __fsi_reg_read((u32)(master->base + reg)); |
@@ -226,8 +241,10 @@ static void fsi_master_mask_set(struct fsi_master *master, | |||
226 | unsigned long flags; | 241 | unsigned long flags; |
227 | 242 | ||
228 | if ((reg < MREG_START) || | 243 | if ((reg < MREG_START) || |
229 | (reg > MREG_END)) | 244 | (reg > MREG_END)) { |
245 | pr_err("fsi: register access err (%s)\n", __func__); | ||
230 | return; | 246 | return; |
247 | } | ||
231 | 248 | ||
232 | spin_lock_irqsave(&master->lock, flags); | 249 | spin_lock_irqsave(&master->lock, flags); |
233 | __fsi_reg_mask_set((u32)(master->base + reg), mask, data); | 250 | __fsi_reg_mask_set((u32)(master->base + reg), mask, data); |
@@ -349,8 +366,8 @@ static void fsi_irq_enable(struct fsi_priv *fsi, int is_play) | |||
349 | u32 data = fsi_port_ab_io_bit(fsi, is_play); | 366 | u32 data = fsi_port_ab_io_bit(fsi, is_play); |
350 | struct fsi_master *master = fsi_get_master(fsi); | 367 | struct fsi_master *master = fsi_get_master(fsi); |
351 | 368 | ||
352 | fsi_master_mask_set(master, master->regs->imsk, data, data); | 369 | fsi_master_mask_set(master, master->core->imsk, data, data); |
353 | fsi_master_mask_set(master, master->regs->iemsk, data, data); | 370 | fsi_master_mask_set(master, master->core->iemsk, data, data); |
354 | } | 371 | } |
355 | 372 | ||
356 | static void fsi_irq_disable(struct fsi_priv *fsi, int is_play) | 373 | static void fsi_irq_disable(struct fsi_priv *fsi, int is_play) |
@@ -358,18 +375,18 @@ static void fsi_irq_disable(struct fsi_priv *fsi, int is_play) | |||
358 | u32 data = fsi_port_ab_io_bit(fsi, is_play); | 375 | u32 data = fsi_port_ab_io_bit(fsi, is_play); |
359 | struct fsi_master *master = fsi_get_master(fsi); | 376 | struct fsi_master *master = fsi_get_master(fsi); |
360 | 377 | ||
361 | fsi_master_mask_set(master, master->regs->imsk, data, 0); | 378 | fsi_master_mask_set(master, master->core->imsk, data, 0); |
362 | fsi_master_mask_set(master, master->regs->iemsk, data, 0); | 379 | fsi_master_mask_set(master, master->core->iemsk, data, 0); |
363 | } | 380 | } |
364 | 381 | ||
365 | static u32 fsi_irq_get_status(struct fsi_master *master) | 382 | static u32 fsi_irq_get_status(struct fsi_master *master) |
366 | { | 383 | { |
367 | return fsi_master_read(master, master->regs->int_st); | 384 | return fsi_master_read(master, master->core->int_st); |
368 | } | 385 | } |
369 | 386 | ||
370 | static void fsi_irq_clear_all_status(struct fsi_master *master) | 387 | static void fsi_irq_clear_all_status(struct fsi_master *master) |
371 | { | 388 | { |
372 | fsi_master_write(master, master->regs->int_st, 0x0000000); | 389 | fsi_master_write(master, master->core->int_st, 0); |
373 | } | 390 | } |
374 | 391 | ||
375 | static void fsi_irq_clear_status(struct fsi_priv *fsi) | 392 | static void fsi_irq_clear_status(struct fsi_priv *fsi) |
@@ -381,7 +398,30 @@ static void fsi_irq_clear_status(struct fsi_priv *fsi) | |||
381 | data |= fsi_port_ab_io_bit(fsi, 1); | 398 | data |= fsi_port_ab_io_bit(fsi, 1); |
382 | 399 | ||
383 | /* clear interrupt factor */ | 400 | /* clear interrupt factor */ |
384 | fsi_master_mask_set(master, master->regs->int_st, data, 0); | 401 | fsi_master_mask_set(master, master->core->int_st, data, 0); |
402 | } | ||
403 | |||
404 | /************************************************************************ | ||
405 | |||
406 | |||
407 | SPDIF master clock function | ||
408 | |||
409 | These functions are used later FSI2 | ||
410 | ************************************************************************/ | ||
411 | static void fsi_spdif_clk_ctrl(struct fsi_priv *fsi, int enable) | ||
412 | { | ||
413 | struct fsi_master *master = fsi_get_master(fsi); | ||
414 | u32 val = BP | SE; | ||
415 | |||
416 | if (master->core->ver < 2) { | ||
417 | pr_err("fsi: register access err (%s)\n", __func__); | ||
418 | return; | ||
419 | } | ||
420 | |||
421 | if (enable) | ||
422 | fsi_master_mask_set(master, fsi->mst_ctrl, val, val); | ||
423 | else | ||
424 | fsi_master_mask_set(master, fsi->mst_ctrl, val, 0); | ||
385 | } | 425 | } |
386 | 426 | ||
387 | /************************************************************************ | 427 | /************************************************************************ |
@@ -662,8 +702,8 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream, | |||
662 | struct snd_soc_dai *dai) | 702 | struct snd_soc_dai *dai) |
663 | { | 703 | { |
664 | struct fsi_priv *fsi = fsi_get_priv(substream); | 704 | struct fsi_priv *fsi = fsi_get_priv(substream); |
665 | const char *msg; | ||
666 | u32 flags = fsi_get_info_flags(fsi); | 705 | u32 flags = fsi_get_info_flags(fsi); |
706 | struct fsi_master *master = fsi_get_master(fsi); | ||
667 | u32 fmt; | 707 | u32 fmt; |
668 | u32 reg; | 708 | u32 reg; |
669 | u32 data; | 709 | u32 data; |
@@ -700,36 +740,40 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream, | |||
700 | fmt = is_play ? SH_FSI_GET_OFMT(flags) : SH_FSI_GET_IFMT(flags); | 740 | fmt = is_play ? SH_FSI_GET_OFMT(flags) : SH_FSI_GET_IFMT(flags); |
701 | switch (fmt) { | 741 | switch (fmt) { |
702 | case SH_FSI_FMT_MONO: | 742 | case SH_FSI_FMT_MONO: |
703 | msg = "MONO"; | 743 | data = CR_MONO; |
704 | data = CR_FMT(CR_MONO); | ||
705 | fsi->chan = 1; | 744 | fsi->chan = 1; |
706 | break; | 745 | break; |
707 | case SH_FSI_FMT_MONO_DELAY: | 746 | case SH_FSI_FMT_MONO_DELAY: |
708 | msg = "MONO Delay"; | 747 | data = CR_MONO_D; |
709 | data = CR_FMT(CR_MONO_D); | ||
710 | fsi->chan = 1; | 748 | fsi->chan = 1; |
711 | break; | 749 | break; |
712 | case SH_FSI_FMT_PCM: | 750 | case SH_FSI_FMT_PCM: |
713 | msg = "PCM"; | 751 | data = CR_PCM; |
714 | data = CR_FMT(CR_PCM); | ||
715 | fsi->chan = 2; | 752 | fsi->chan = 2; |
716 | break; | 753 | break; |
717 | case SH_FSI_FMT_I2S: | 754 | case SH_FSI_FMT_I2S: |
718 | msg = "I2S"; | 755 | data = CR_I2S; |
719 | data = CR_FMT(CR_I2S); | ||
720 | fsi->chan = 2; | 756 | fsi->chan = 2; |
721 | break; | 757 | break; |
722 | case SH_FSI_FMT_TDM: | 758 | case SH_FSI_FMT_TDM: |
723 | msg = "TDM"; | ||
724 | fsi->chan = is_play ? | 759 | fsi->chan = is_play ? |
725 | SH_FSI_GET_CH_O(flags) : SH_FSI_GET_CH_I(flags); | 760 | SH_FSI_GET_CH_O(flags) : SH_FSI_GET_CH_I(flags); |
726 | data = CR_FMT(CR_TDM) | (fsi->chan - 1); | 761 | data = CR_TDM | (fsi->chan - 1); |
727 | break; | 762 | break; |
728 | case SH_FSI_FMT_TDM_DELAY: | 763 | case SH_FSI_FMT_TDM_DELAY: |
729 | msg = "TDM Delay"; | ||
730 | fsi->chan = is_play ? | 764 | fsi->chan = is_play ? |
731 | SH_FSI_GET_CH_O(flags) : SH_FSI_GET_CH_I(flags); | 765 | SH_FSI_GET_CH_O(flags) : SH_FSI_GET_CH_I(flags); |
732 | data = CR_FMT(CR_TDM_D) | (fsi->chan - 1); | 766 | data = CR_TDM_D | (fsi->chan - 1); |
767 | break; | ||
768 | case SH_FSI_FMT_SPDIF: | ||
769 | if (master->core->ver < 2) { | ||
770 | dev_err(dai->dev, "This FSI can not use SPDIF\n"); | ||
771 | return -EINVAL; | ||
772 | } | ||
773 | data = CR_SPDIF; | ||
774 | fsi->chan = 2; | ||
775 | fsi_spdif_clk_ctrl(fsi, 1); | ||
776 | fsi_reg_mask_set(fsi, OUT_SEL, 0x0010, 0x0010); | ||
733 | break; | 777 | break; |
734 | default: | 778 | default: |
735 | dev_err(dai->dev, "unknown format.\n"); | 779 | dev_err(dai->dev, "unknown format.\n"); |
@@ -737,12 +781,6 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream, | |||
737 | } | 781 | } |
738 | fsi_reg_write(fsi, reg, data); | 782 | fsi_reg_write(fsi, reg, data); |
739 | 783 | ||
740 | /* | ||
741 | * clear clk reset if master mode | ||
742 | */ | ||
743 | if (is_master) | ||
744 | fsi_clk_ctrl(fsi, 1); | ||
745 | |||
746 | /* irq clear */ | 784 | /* irq clear */ |
747 | fsi_irq_disable(fsi, is_play); | 785 | fsi_irq_disable(fsi, is_play); |
748 | fsi_irq_clear_status(fsi); | 786 | fsi_irq_clear_status(fsi); |
@@ -789,10 +827,93 @@ static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd, | |||
789 | return ret; | 827 | return ret; |
790 | } | 828 | } |
791 | 829 | ||
830 | static int fsi_dai_hw_params(struct snd_pcm_substream *substream, | ||
831 | struct snd_pcm_hw_params *params, | ||
832 | struct snd_soc_dai *dai) | ||
833 | { | ||
834 | struct fsi_priv *fsi = fsi_get_priv(substream); | ||
835 | struct fsi_master *master = fsi_get_master(fsi); | ||
836 | int (*set_rate)(int is_porta, int rate) = master->info->set_rate; | ||
837 | int fsi_ver = master->core->ver; | ||
838 | int is_play = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); | ||
839 | int ret; | ||
840 | |||
841 | /* if slave mode, set_rate is not needed */ | ||
842 | if (!fsi_is_master_mode(fsi, is_play)) | ||
843 | return 0; | ||
844 | |||
845 | /* it is error if no set_rate */ | ||
846 | if (!set_rate) | ||
847 | return -EIO; | ||
848 | |||
849 | ret = set_rate(fsi_is_port_a(fsi), params_rate(params)); | ||
850 | if (ret > 0) { | ||
851 | u32 data = 0; | ||
852 | |||
853 | switch (ret & SH_FSI_ACKMD_MASK) { | ||
854 | default: | ||
855 | /* FALL THROUGH */ | ||
856 | case SH_FSI_ACKMD_512: | ||
857 | data |= (0x0 << 12); | ||
858 | break; | ||
859 | case SH_FSI_ACKMD_256: | ||
860 | data |= (0x1 << 12); | ||
861 | break; | ||
862 | case SH_FSI_ACKMD_128: | ||
863 | data |= (0x2 << 12); | ||
864 | break; | ||
865 | case SH_FSI_ACKMD_64: | ||
866 | data |= (0x3 << 12); | ||
867 | break; | ||
868 | case SH_FSI_ACKMD_32: | ||
869 | if (fsi_ver < 2) | ||
870 | dev_err(dai->dev, "unsupported ACKMD\n"); | ||
871 | else | ||
872 | data |= (0x4 << 12); | ||
873 | break; | ||
874 | } | ||
875 | |||
876 | switch (ret & SH_FSI_BPFMD_MASK) { | ||
877 | default: | ||
878 | /* FALL THROUGH */ | ||
879 | case SH_FSI_BPFMD_32: | ||
880 | data |= (0x0 << 8); | ||
881 | break; | ||
882 | case SH_FSI_BPFMD_64: | ||
883 | data |= (0x1 << 8); | ||
884 | break; | ||
885 | case SH_FSI_BPFMD_128: | ||
886 | data |= (0x2 << 8); | ||
887 | break; | ||
888 | case SH_FSI_BPFMD_256: | ||
889 | data |= (0x3 << 8); | ||
890 | break; | ||
891 | case SH_FSI_BPFMD_512: | ||
892 | data |= (0x4 << 8); | ||
893 | break; | ||
894 | case SH_FSI_BPFMD_16: | ||
895 | if (fsi_ver < 2) | ||
896 | dev_err(dai->dev, "unsupported ACKMD\n"); | ||
897 | else | ||
898 | data |= (0x7 << 8); | ||
899 | break; | ||
900 | } | ||
901 | |||
902 | fsi_reg_mask_set(fsi, CKG1, (ACKMD_MASK | BPFMD_MASK) , data); | ||
903 | udelay(10); | ||
904 | fsi_clk_ctrl(fsi, 1); | ||
905 | ret = 0; | ||
906 | } | ||
907 | |||
908 | return ret; | ||
909 | |||
910 | } | ||
911 | |||
792 | static struct snd_soc_dai_ops fsi_dai_ops = { | 912 | static struct snd_soc_dai_ops fsi_dai_ops = { |
793 | .startup = fsi_dai_startup, | 913 | .startup = fsi_dai_startup, |
794 | .shutdown = fsi_dai_shutdown, | 914 | .shutdown = fsi_dai_shutdown, |
795 | .trigger = fsi_dai_trigger, | 915 | .trigger = fsi_dai_trigger, |
916 | .hw_params = fsi_dai_hw_params, | ||
796 | }; | 917 | }; |
797 | 918 | ||
798 | /************************************************************************ | 919 | /************************************************************************ |
@@ -965,11 +1086,6 @@ static int fsi_probe(struct platform_device *pdev) | |||
965 | unsigned int irq; | 1086 | unsigned int irq; |
966 | int ret; | 1087 | int ret; |
967 | 1088 | ||
968 | if (0 != pdev->id) { | ||
969 | dev_err(&pdev->dev, "current fsi support id 0 only now\n"); | ||
970 | return -ENODEV; | ||
971 | } | ||
972 | |||
973 | id_entry = pdev->id_entry; | 1089 | id_entry = pdev->id_entry; |
974 | if (!id_entry) { | 1090 | if (!id_entry) { |
975 | dev_err(&pdev->dev, "unknown fsi device\n"); | 1091 | dev_err(&pdev->dev, "unknown fsi device\n"); |
@@ -998,14 +1114,21 @@ static int fsi_probe(struct platform_device *pdev) | |||
998 | goto exit_kfree; | 1114 | goto exit_kfree; |
999 | } | 1115 | } |
1000 | 1116 | ||
1117 | /* master setting */ | ||
1001 | master->irq = irq; | 1118 | master->irq = irq; |
1002 | master->info = pdev->dev.platform_data; | 1119 | master->info = pdev->dev.platform_data; |
1120 | master->core = (struct fsi_core *)id_entry->driver_data; | ||
1121 | spin_lock_init(&master->lock); | ||
1122 | |||
1123 | /* FSI A setting */ | ||
1003 | master->fsia.base = master->base; | 1124 | master->fsia.base = master->base; |
1004 | master->fsia.master = master; | 1125 | master->fsia.master = master; |
1126 | master->fsia.mst_ctrl = A_MST_CTLR; | ||
1127 | |||
1128 | /* FSI B setting */ | ||
1005 | master->fsib.base = master->base + 0x40; | 1129 | master->fsib.base = master->base + 0x40; |
1006 | master->fsib.master = master; | 1130 | master->fsib.master = master; |
1007 | master->regs = (struct fsi_regs *)id_entry->driver_data; | 1131 | master->fsib.mst_ctrl = B_MST_CTLR; |
1008 | spin_lock_init(&master->lock); | ||
1009 | 1132 | ||
1010 | pm_runtime_enable(&pdev->dev); | 1133 | pm_runtime_enable(&pdev->dev); |
1011 | pm_runtime_resume(&pdev->dev); | 1134 | pm_runtime_resume(&pdev->dev); |
@@ -1085,21 +1208,27 @@ static struct dev_pm_ops fsi_pm_ops = { | |||
1085 | .runtime_resume = fsi_runtime_nop, | 1208 | .runtime_resume = fsi_runtime_nop, |
1086 | }; | 1209 | }; |
1087 | 1210 | ||
1088 | static struct fsi_regs fsi_regs = { | 1211 | static struct fsi_core fsi1_core = { |
1212 | .ver = 1, | ||
1213 | |||
1214 | /* Interrupt */ | ||
1089 | .int_st = INT_ST, | 1215 | .int_st = INT_ST, |
1090 | .iemsk = IEMSK, | 1216 | .iemsk = IEMSK, |
1091 | .imsk = IMSK, | 1217 | .imsk = IMSK, |
1092 | }; | 1218 | }; |
1093 | 1219 | ||
1094 | static struct fsi_regs fsi2_regs = { | 1220 | static struct fsi_core fsi2_core = { |
1221 | .ver = 2, | ||
1222 | |||
1223 | /* Interrupt */ | ||
1095 | .int_st = CPU_INT_ST, | 1224 | .int_st = CPU_INT_ST, |
1096 | .iemsk = CPU_IEMSK, | 1225 | .iemsk = CPU_IEMSK, |
1097 | .imsk = CPU_IMSK, | 1226 | .imsk = CPU_IMSK, |
1098 | }; | 1227 | }; |
1099 | 1228 | ||
1100 | static struct platform_device_id fsi_id_table[] = { | 1229 | static struct platform_device_id fsi_id_table[] = { |
1101 | { "sh_fsi", (kernel_ulong_t)&fsi_regs }, | 1230 | { "sh_fsi", (kernel_ulong_t)&fsi1_core }, |
1102 | { "sh_fsi2", (kernel_ulong_t)&fsi2_regs }, | 1231 | { "sh_fsi2", (kernel_ulong_t)&fsi2_core }, |
1103 | }; | 1232 | }; |
1104 | 1233 | ||
1105 | static struct platform_driver fsi_driver = { | 1234 | static struct platform_driver fsi_driver = { |
diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c index 472af38188c1..adbc68ce9050 100644 --- a/sound/soc/soc-cache.c +++ b/sound/soc/soc-cache.c | |||
@@ -340,7 +340,7 @@ static unsigned int snd_soc_16_8_read_i2c(struct snd_soc_codec *codec, | |||
340 | static unsigned int snd_soc_16_8_read(struct snd_soc_codec *codec, | 340 | static unsigned int snd_soc_16_8_read(struct snd_soc_codec *codec, |
341 | unsigned int reg) | 341 | unsigned int reg) |
342 | { | 342 | { |
343 | u16 *cache = codec->reg_cache; | 343 | u8 *cache = codec->reg_cache; |
344 | 344 | ||
345 | reg &= 0xff; | 345 | reg &= 0xff; |
346 | if (reg >= codec->reg_cache_size) | 346 | if (reg >= codec->reg_cache_size) |
@@ -351,7 +351,7 @@ static unsigned int snd_soc_16_8_read(struct snd_soc_codec *codec, | |||
351 | static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg, | 351 | static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg, |
352 | unsigned int value) | 352 | unsigned int value) |
353 | { | 353 | { |
354 | u16 *cache = codec->reg_cache; | 354 | u8 *cache = codec->reg_cache; |
355 | u8 data[3]; | 355 | u8 data[3]; |
356 | int ret; | 356 | int ret; |
357 | 357 | ||
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 998569d60330..acc91daa1c55 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c | |||
@@ -84,7 +84,7 @@ static int run_delayed_work(struct delayed_work *dwork) | |||
84 | /* codec register dump */ | 84 | /* codec register dump */ |
85 | static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf) | 85 | static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf) |
86 | { | 86 | { |
87 | int i, step = 1, count = 0; | 87 | int ret, i, step = 1, count = 0; |
88 | 88 | ||
89 | if (!codec->reg_cache_size) | 89 | if (!codec->reg_cache_size) |
90 | return 0; | 90 | return 0; |
@@ -101,12 +101,24 @@ static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf) | |||
101 | if (count >= PAGE_SIZE - 1) | 101 | if (count >= PAGE_SIZE - 1) |
102 | break; | 102 | break; |
103 | 103 | ||
104 | if (codec->display_register) | 104 | if (codec->display_register) { |
105 | count += codec->display_register(codec, buf + count, | 105 | count += codec->display_register(codec, buf + count, |
106 | PAGE_SIZE - count, i); | 106 | PAGE_SIZE - count, i); |
107 | else | 107 | } else { |
108 | count += snprintf(buf + count, PAGE_SIZE - count, | 108 | /* If the read fails it's almost certainly due to |
109 | "%4x", codec->read(codec, i)); | 109 | * the register being volatile and the device being |
110 | * powered off. | ||
111 | */ | ||
112 | ret = codec->read(codec, i); | ||
113 | if (ret >= 0) | ||
114 | count += snprintf(buf + count, | ||
115 | PAGE_SIZE - count, | ||
116 | "%4x", ret); | ||
117 | else | ||
118 | count += snprintf(buf + count, | ||
119 | PAGE_SIZE - count, | ||
120 | "<no data: %d>", ret); | ||
121 | } | ||
110 | 122 | ||
111 | if (count >= PAGE_SIZE - 1) | 123 | if (count >= PAGE_SIZE - 1) |
112 | break; | 124 | break; |
@@ -239,7 +251,7 @@ static void soc_init_codec_debugfs(struct snd_soc_codec *codec) | |||
239 | printk(KERN_WARNING | 251 | printk(KERN_WARNING |
240 | "ASoC: Failed to create codec register debugfs file\n"); | 252 | "ASoC: Failed to create codec register debugfs file\n"); |
241 | 253 | ||
242 | codec->debugfs_pop_time = debugfs_create_u32("dapm_pop_time", 0744, | 254 | codec->debugfs_pop_time = debugfs_create_u32("dapm_pop_time", 0644, |
243 | codec->debugfs_codec_root, | 255 | codec->debugfs_codec_root, |
244 | &codec->pop_time); | 256 | &codec->pop_time); |
245 | if (!codec->debugfs_pop_time) | 257 | if (!codec->debugfs_pop_time) |
@@ -1307,7 +1319,7 @@ cpu_dai_err: | |||
1307 | } | 1319 | } |
1308 | 1320 | ||
1309 | /* | 1321 | /* |
1310 | * Attempt to initialise any uninitalised cards. Must be called with | 1322 | * Attempt to initialise any uninitialised cards. Must be called with |
1311 | * client_mutex. | 1323 | * client_mutex. |
1312 | */ | 1324 | */ |
1313 | static void snd_soc_instantiate_cards(void) | 1325 | static void snd_soc_instantiate_cards(void) |
@@ -2353,6 +2365,99 @@ int snd_soc_limit_volume(struct snd_soc_codec *codec, | |||
2353 | EXPORT_SYMBOL_GPL(snd_soc_limit_volume); | 2365 | EXPORT_SYMBOL_GPL(snd_soc_limit_volume); |
2354 | 2366 | ||
2355 | /** | 2367 | /** |
2368 | * snd_soc_info_volsw_2r_sx - double with tlv and variable data size | ||
2369 | * mixer info callback | ||
2370 | * @kcontrol: mixer control | ||
2371 | * @uinfo: control element information | ||
2372 | * | ||
2373 | * Returns 0 for success. | ||
2374 | */ | ||
2375 | int snd_soc_info_volsw_2r_sx(struct snd_kcontrol *kcontrol, | ||
2376 | struct snd_ctl_elem_info *uinfo) | ||
2377 | { | ||
2378 | struct soc_mixer_control *mc = | ||
2379 | (struct soc_mixer_control *)kcontrol->private_value; | ||
2380 | int max = mc->max; | ||
2381 | int min = mc->min; | ||
2382 | |||
2383 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
2384 | uinfo->count = 2; | ||
2385 | uinfo->value.integer.min = 0; | ||
2386 | uinfo->value.integer.max = max-min; | ||
2387 | |||
2388 | return 0; | ||
2389 | } | ||
2390 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw_2r_sx); | ||
2391 | |||
2392 | /** | ||
2393 | * snd_soc_get_volsw_2r_sx - double with tlv and variable data size | ||
2394 | * mixer get callback | ||
2395 | * @kcontrol: mixer control | ||
2396 | * @uinfo: control element information | ||
2397 | * | ||
2398 | * Returns 0 for success. | ||
2399 | */ | ||
2400 | int snd_soc_get_volsw_2r_sx(struct snd_kcontrol *kcontrol, | ||
2401 | struct snd_ctl_elem_value *ucontrol) | ||
2402 | { | ||
2403 | struct soc_mixer_control *mc = | ||
2404 | (struct soc_mixer_control *)kcontrol->private_value; | ||
2405 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
2406 | unsigned int mask = (1<<mc->shift)-1; | ||
2407 | int min = mc->min; | ||
2408 | int val = snd_soc_read(codec, mc->reg) & mask; | ||
2409 | int valr = snd_soc_read(codec, mc->rreg) & mask; | ||
2410 | |||
2411 | ucontrol->value.integer.value[0] = ((val & 0xff)-min) & mask; | ||
2412 | ucontrol->value.integer.value[1] = ((valr & 0xff)-min) & mask; | ||
2413 | return 0; | ||
2414 | } | ||
2415 | EXPORT_SYMBOL_GPL(snd_soc_get_volsw_2r_sx); | ||
2416 | |||
2417 | /** | ||
2418 | * snd_soc_put_volsw_2r_sx - double with tlv and variable data size | ||
2419 | * mixer put callback | ||
2420 | * @kcontrol: mixer control | ||
2421 | * @uinfo: control element information | ||
2422 | * | ||
2423 | * Returns 0 for success. | ||
2424 | */ | ||
2425 | int snd_soc_put_volsw_2r_sx(struct snd_kcontrol *kcontrol, | ||
2426 | struct snd_ctl_elem_value *ucontrol) | ||
2427 | { | ||
2428 | struct soc_mixer_control *mc = | ||
2429 | (struct soc_mixer_control *)kcontrol->private_value; | ||
2430 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
2431 | unsigned int mask = (1<<mc->shift)-1; | ||
2432 | int min = mc->min; | ||
2433 | int ret; | ||
2434 | unsigned int val, valr, oval, ovalr; | ||
2435 | |||
2436 | val = ((ucontrol->value.integer.value[0]+min) & 0xff); | ||
2437 | val &= mask; | ||
2438 | valr = ((ucontrol->value.integer.value[1]+min) & 0xff); | ||
2439 | valr &= mask; | ||
2440 | |||
2441 | oval = snd_soc_read(codec, mc->reg) & mask; | ||
2442 | ovalr = snd_soc_read(codec, mc->rreg) & mask; | ||
2443 | |||
2444 | ret = 0; | ||
2445 | if (oval != val) { | ||
2446 | ret = snd_soc_write(codec, mc->reg, val); | ||
2447 | if (ret < 0) | ||
2448 | return ret; | ||
2449 | } | ||
2450 | if (ovalr != valr) { | ||
2451 | ret = snd_soc_write(codec, mc->rreg, valr); | ||
2452 | if (ret < 0) | ||
2453 | return ret; | ||
2454 | } | ||
2455 | |||
2456 | return 0; | ||
2457 | } | ||
2458 | EXPORT_SYMBOL_GPL(snd_soc_put_volsw_2r_sx); | ||
2459 | |||
2460 | /** | ||
2356 | * snd_soc_dai_set_sysclk - configure DAI system or master clock. | 2461 | * snd_soc_dai_set_sysclk - configure DAI system or master clock. |
2357 | * @dai: DAI | 2462 | * @dai: DAI |
2358 | * @clk_id: DAI specific clock ID | 2463 | * @clk_id: DAI specific clock ID |
diff --git a/sound/sound_core.c b/sound/sound_core.c index 7c2d677a2df5..cb61317df509 100644 --- a/sound/sound_core.c +++ b/sound/sound_core.c | |||
@@ -576,8 +576,6 @@ static int soundcore_open(struct inode *inode, struct file *file) | |||
576 | struct sound_unit *s; | 576 | struct sound_unit *s; |
577 | const struct file_operations *new_fops = NULL; | 577 | const struct file_operations *new_fops = NULL; |
578 | 578 | ||
579 | lock_kernel (); | ||
580 | |||
581 | chain=unit&0x0F; | 579 | chain=unit&0x0F; |
582 | if(chain==4 || chain==5) /* dsp/audio/dsp16 */ | 580 | if(chain==4 || chain==5) /* dsp/audio/dsp16 */ |
583 | { | 581 | { |
@@ -630,18 +628,19 @@ static int soundcore_open(struct inode *inode, struct file *file) | |||
630 | const struct file_operations *old_fops = file->f_op; | 628 | const struct file_operations *old_fops = file->f_op; |
631 | file->f_op = new_fops; | 629 | file->f_op = new_fops; |
632 | spin_unlock(&sound_loader_lock); | 630 | spin_unlock(&sound_loader_lock); |
633 | if(file->f_op->open) | 631 | |
632 | if (file->f_op->open) | ||
634 | err = file->f_op->open(inode,file); | 633 | err = file->f_op->open(inode,file); |
634 | |||
635 | if (err) { | 635 | if (err) { |
636 | fops_put(file->f_op); | 636 | fops_put(file->f_op); |
637 | file->f_op = fops_get(old_fops); | 637 | file->f_op = fops_get(old_fops); |
638 | } | 638 | } |
639 | |||
639 | fops_put(old_fops); | 640 | fops_put(old_fops); |
640 | unlock_kernel(); | ||
641 | return err; | 641 | return err; |
642 | } | 642 | } |
643 | spin_unlock(&sound_loader_lock); | 643 | spin_unlock(&sound_loader_lock); |
644 | unlock_kernel(); | ||
645 | return -ENODEV; | 644 | return -ENODEV; |
646 | } | 645 | } |
647 | 646 | ||
diff --git a/sound/sparc/amd7930.c b/sound/sparc/amd7930.c index 71221fd20944..f8bcfc30f800 100644 --- a/sound/sparc/amd7930.c +++ b/sound/sparc/amd7930.c | |||
@@ -336,7 +336,7 @@ struct snd_amd7930 { | |||
336 | int pgain; | 336 | int pgain; |
337 | int mgain; | 337 | int mgain; |
338 | 338 | ||
339 | struct of_device *op; | 339 | struct platform_device *op; |
340 | unsigned int irq; | 340 | unsigned int irq; |
341 | struct snd_amd7930 *next; | 341 | struct snd_amd7930 *next; |
342 | }; | 342 | }; |
@@ -906,7 +906,7 @@ static int __devinit snd_amd7930_mixer(struct snd_amd7930 *amd) | |||
906 | 906 | ||
907 | static int snd_amd7930_free(struct snd_amd7930 *amd) | 907 | static int snd_amd7930_free(struct snd_amd7930 *amd) |
908 | { | 908 | { |
909 | struct of_device *op = amd->op; | 909 | struct platform_device *op = amd->op; |
910 | 910 | ||
911 | amd7930_idle(amd); | 911 | amd7930_idle(amd); |
912 | 912 | ||
@@ -934,7 +934,7 @@ static struct snd_device_ops snd_amd7930_dev_ops = { | |||
934 | }; | 934 | }; |
935 | 935 | ||
936 | static int __devinit snd_amd7930_create(struct snd_card *card, | 936 | static int __devinit snd_amd7930_create(struct snd_card *card, |
937 | struct of_device *op, | 937 | struct platform_device *op, |
938 | int irq, int dev, | 938 | int irq, int dev, |
939 | struct snd_amd7930 **ramd) | 939 | struct snd_amd7930 **ramd) |
940 | { | 940 | { |
@@ -1002,7 +1002,7 @@ static int __devinit snd_amd7930_create(struct snd_card *card, | |||
1002 | return 0; | 1002 | return 0; |
1003 | } | 1003 | } |
1004 | 1004 | ||
1005 | static int __devinit amd7930_sbus_probe(struct of_device *op, const struct of_device_id *match) | 1005 | static int __devinit amd7930_sbus_probe(struct platform_device *op, const struct of_device_id *match) |
1006 | { | 1006 | { |
1007 | struct resource *rp = &op->resource[0]; | 1007 | struct resource *rp = &op->resource[0]; |
1008 | static int dev_num; | 1008 | static int dev_num; |
@@ -1010,7 +1010,7 @@ static int __devinit amd7930_sbus_probe(struct of_device *op, const struct of_de | |||
1010 | struct snd_amd7930 *amd; | 1010 | struct snd_amd7930 *amd; |
1011 | int err, irq; | 1011 | int err, irq; |
1012 | 1012 | ||
1013 | irq = op->irqs[0]; | 1013 | irq = op->archdata.irqs[0]; |
1014 | 1014 | ||
1015 | if (dev_num >= SNDRV_CARDS) | 1015 | if (dev_num >= SNDRV_CARDS) |
1016 | return -ENODEV; | 1016 | return -ENODEV; |
@@ -1075,7 +1075,7 @@ static struct of_platform_driver amd7930_sbus_driver = { | |||
1075 | 1075 | ||
1076 | static int __init amd7930_init(void) | 1076 | static int __init amd7930_init(void) |
1077 | { | 1077 | { |
1078 | return of_register_driver(&amd7930_sbus_driver, &of_bus_type); | 1078 | return of_register_platform_driver(&amd7930_sbus_driver); |
1079 | } | 1079 | } |
1080 | 1080 | ||
1081 | static void __exit amd7930_exit(void) | 1081 | static void __exit amd7930_exit(void) |
@@ -1092,7 +1092,7 @@ static void __exit amd7930_exit(void) | |||
1092 | 1092 | ||
1093 | amd7930_list = NULL; | 1093 | amd7930_list = NULL; |
1094 | 1094 | ||
1095 | of_unregister_driver(&amd7930_sbus_driver); | 1095 | of_unregister_platform_driver(&amd7930_sbus_driver); |
1096 | } | 1096 | } |
1097 | 1097 | ||
1098 | module_init(amd7930_init); | 1098 | module_init(amd7930_init); |
diff --git a/sound/sparc/cs4231.c b/sound/sparc/cs4231.c index fb4c6f2f29e5..c276086c3b57 100644 --- a/sound/sparc/cs4231.c +++ b/sound/sparc/cs4231.c | |||
@@ -111,7 +111,7 @@ struct snd_cs4231 { | |||
111 | struct mutex mce_mutex; /* mutex for mce register */ | 111 | struct mutex mce_mutex; /* mutex for mce register */ |
112 | struct mutex open_mutex; /* mutex for ALSA open/close */ | 112 | struct mutex open_mutex; /* mutex for ALSA open/close */ |
113 | 113 | ||
114 | struct of_device *op; | 114 | struct platform_device *op; |
115 | unsigned int irq[2]; | 115 | unsigned int irq[2]; |
116 | unsigned int regs_size; | 116 | unsigned int regs_size; |
117 | struct snd_cs4231 *next; | 117 | struct snd_cs4231 *next; |
@@ -1771,7 +1771,7 @@ static unsigned int sbus_dma_addr(struct cs4231_dma_control *dma_cont) | |||
1771 | 1771 | ||
1772 | static int snd_cs4231_sbus_free(struct snd_cs4231 *chip) | 1772 | static int snd_cs4231_sbus_free(struct snd_cs4231 *chip) |
1773 | { | 1773 | { |
1774 | struct of_device *op = chip->op; | 1774 | struct platform_device *op = chip->op; |
1775 | 1775 | ||
1776 | if (chip->irq[0]) | 1776 | if (chip->irq[0]) |
1777 | free_irq(chip->irq[0], chip); | 1777 | free_irq(chip->irq[0], chip); |
@@ -1794,7 +1794,7 @@ static struct snd_device_ops snd_cs4231_sbus_dev_ops = { | |||
1794 | }; | 1794 | }; |
1795 | 1795 | ||
1796 | static int __devinit snd_cs4231_sbus_create(struct snd_card *card, | 1796 | static int __devinit snd_cs4231_sbus_create(struct snd_card *card, |
1797 | struct of_device *op, | 1797 | struct platform_device *op, |
1798 | int dev) | 1798 | int dev) |
1799 | { | 1799 | { |
1800 | struct snd_cs4231 *chip = card->private_data; | 1800 | struct snd_cs4231 *chip = card->private_data; |
@@ -1832,14 +1832,14 @@ static int __devinit snd_cs4231_sbus_create(struct snd_card *card, | |||
1832 | chip->c_dma.request = sbus_dma_request; | 1832 | chip->c_dma.request = sbus_dma_request; |
1833 | chip->c_dma.address = sbus_dma_addr; | 1833 | chip->c_dma.address = sbus_dma_addr; |
1834 | 1834 | ||
1835 | if (request_irq(op->irqs[0], snd_cs4231_sbus_interrupt, | 1835 | if (request_irq(op->archdata.irqs[0], snd_cs4231_sbus_interrupt, |
1836 | IRQF_SHARED, "cs4231", chip)) { | 1836 | IRQF_SHARED, "cs4231", chip)) { |
1837 | snd_printdd("cs4231-%d: Unable to grab SBUS IRQ %d\n", | 1837 | snd_printdd("cs4231-%d: Unable to grab SBUS IRQ %d\n", |
1838 | dev, op->irqs[0]); | 1838 | dev, op->archdata.irqs[0]); |
1839 | snd_cs4231_sbus_free(chip); | 1839 | snd_cs4231_sbus_free(chip); |
1840 | return -EBUSY; | 1840 | return -EBUSY; |
1841 | } | 1841 | } |
1842 | chip->irq[0] = op->irqs[0]; | 1842 | chip->irq[0] = op->archdata.irqs[0]; |
1843 | 1843 | ||
1844 | if (snd_cs4231_probe(chip) < 0) { | 1844 | if (snd_cs4231_probe(chip) < 0) { |
1845 | snd_cs4231_sbus_free(chip); | 1845 | snd_cs4231_sbus_free(chip); |
@@ -1856,7 +1856,7 @@ static int __devinit snd_cs4231_sbus_create(struct snd_card *card, | |||
1856 | return 0; | 1856 | return 0; |
1857 | } | 1857 | } |
1858 | 1858 | ||
1859 | static int __devinit cs4231_sbus_probe(struct of_device *op, const struct of_device_id *match) | 1859 | static int __devinit cs4231_sbus_probe(struct platform_device *op, const struct of_device_id *match) |
1860 | { | 1860 | { |
1861 | struct resource *rp = &op->resource[0]; | 1861 | struct resource *rp = &op->resource[0]; |
1862 | struct snd_card *card; | 1862 | struct snd_card *card; |
@@ -1870,7 +1870,7 @@ static int __devinit cs4231_sbus_probe(struct of_device *op, const struct of_dev | |||
1870 | card->shortname, | 1870 | card->shortname, |
1871 | rp->flags & 0xffL, | 1871 | rp->flags & 0xffL, |
1872 | (unsigned long long)rp->start, | 1872 | (unsigned long long)rp->start, |
1873 | op->irqs[0]); | 1873 | op->archdata.irqs[0]); |
1874 | 1874 | ||
1875 | err = snd_cs4231_sbus_create(card, op, dev); | 1875 | err = snd_cs4231_sbus_create(card, op, dev); |
1876 | if (err < 0) { | 1876 | if (err < 0) { |
@@ -1931,7 +1931,7 @@ static unsigned int _ebus_dma_addr(struct cs4231_dma_control *dma_cont) | |||
1931 | 1931 | ||
1932 | static int snd_cs4231_ebus_free(struct snd_cs4231 *chip) | 1932 | static int snd_cs4231_ebus_free(struct snd_cs4231 *chip) |
1933 | { | 1933 | { |
1934 | struct of_device *op = chip->op; | 1934 | struct platform_device *op = chip->op; |
1935 | 1935 | ||
1936 | if (chip->c_dma.ebus_info.regs) { | 1936 | if (chip->c_dma.ebus_info.regs) { |
1937 | ebus_dma_unregister(&chip->c_dma.ebus_info); | 1937 | ebus_dma_unregister(&chip->c_dma.ebus_info); |
@@ -1960,7 +1960,7 @@ static struct snd_device_ops snd_cs4231_ebus_dev_ops = { | |||
1960 | }; | 1960 | }; |
1961 | 1961 | ||
1962 | static int __devinit snd_cs4231_ebus_create(struct snd_card *card, | 1962 | static int __devinit snd_cs4231_ebus_create(struct snd_card *card, |
1963 | struct of_device *op, | 1963 | struct platform_device *op, |
1964 | int dev) | 1964 | int dev) |
1965 | { | 1965 | { |
1966 | struct snd_cs4231 *chip = card->private_data; | 1966 | struct snd_cs4231 *chip = card->private_data; |
@@ -1979,12 +1979,12 @@ static int __devinit snd_cs4231_ebus_create(struct snd_card *card, | |||
1979 | chip->c_dma.ebus_info.flags = EBUS_DMA_FLAG_USE_EBDMA_HANDLER; | 1979 | chip->c_dma.ebus_info.flags = EBUS_DMA_FLAG_USE_EBDMA_HANDLER; |
1980 | chip->c_dma.ebus_info.callback = snd_cs4231_ebus_capture_callback; | 1980 | chip->c_dma.ebus_info.callback = snd_cs4231_ebus_capture_callback; |
1981 | chip->c_dma.ebus_info.client_cookie = chip; | 1981 | chip->c_dma.ebus_info.client_cookie = chip; |
1982 | chip->c_dma.ebus_info.irq = op->irqs[0]; | 1982 | chip->c_dma.ebus_info.irq = op->archdata.irqs[0]; |
1983 | strcpy(chip->p_dma.ebus_info.name, "cs4231(play)"); | 1983 | strcpy(chip->p_dma.ebus_info.name, "cs4231(play)"); |
1984 | chip->p_dma.ebus_info.flags = EBUS_DMA_FLAG_USE_EBDMA_HANDLER; | 1984 | chip->p_dma.ebus_info.flags = EBUS_DMA_FLAG_USE_EBDMA_HANDLER; |
1985 | chip->p_dma.ebus_info.callback = snd_cs4231_ebus_play_callback; | 1985 | chip->p_dma.ebus_info.callback = snd_cs4231_ebus_play_callback; |
1986 | chip->p_dma.ebus_info.client_cookie = chip; | 1986 | chip->p_dma.ebus_info.client_cookie = chip; |
1987 | chip->p_dma.ebus_info.irq = op->irqs[1]; | 1987 | chip->p_dma.ebus_info.irq = op->archdata.irqs[1]; |
1988 | 1988 | ||
1989 | chip->p_dma.prepare = _ebus_dma_prepare; | 1989 | chip->p_dma.prepare = _ebus_dma_prepare; |
1990 | chip->p_dma.enable = _ebus_dma_enable; | 1990 | chip->p_dma.enable = _ebus_dma_enable; |
@@ -2048,7 +2048,7 @@ static int __devinit snd_cs4231_ebus_create(struct snd_card *card, | |||
2048 | return 0; | 2048 | return 0; |
2049 | } | 2049 | } |
2050 | 2050 | ||
2051 | static int __devinit cs4231_ebus_probe(struct of_device *op, const struct of_device_id *match) | 2051 | static int __devinit cs4231_ebus_probe(struct platform_device *op, const struct of_device_id *match) |
2052 | { | 2052 | { |
2053 | struct snd_card *card; | 2053 | struct snd_card *card; |
2054 | int err; | 2054 | int err; |
@@ -2060,7 +2060,7 @@ static int __devinit cs4231_ebus_probe(struct of_device *op, const struct of_dev | |||
2060 | sprintf(card->longname, "%s at 0x%llx, irq %d", | 2060 | sprintf(card->longname, "%s at 0x%llx, irq %d", |
2061 | card->shortname, | 2061 | card->shortname, |
2062 | op->resource[0].start, | 2062 | op->resource[0].start, |
2063 | op->irqs[0]); | 2063 | op->archdata.irqs[0]); |
2064 | 2064 | ||
2065 | err = snd_cs4231_ebus_create(card, op, dev); | 2065 | err = snd_cs4231_ebus_create(card, op, dev); |
2066 | if (err < 0) { | 2066 | if (err < 0) { |
@@ -2072,7 +2072,7 @@ static int __devinit cs4231_ebus_probe(struct of_device *op, const struct of_dev | |||
2072 | } | 2072 | } |
2073 | #endif | 2073 | #endif |
2074 | 2074 | ||
2075 | static int __devinit cs4231_probe(struct of_device *op, const struct of_device_id *match) | 2075 | static int __devinit cs4231_probe(struct platform_device *op, const struct of_device_id *match) |
2076 | { | 2076 | { |
2077 | #ifdef EBUS_SUPPORT | 2077 | #ifdef EBUS_SUPPORT |
2078 | if (!strcmp(op->dev.of_node->parent->name, "ebus")) | 2078 | if (!strcmp(op->dev.of_node->parent->name, "ebus")) |
@@ -2086,7 +2086,7 @@ static int __devinit cs4231_probe(struct of_device *op, const struct of_device_i | |||
2086 | return -ENODEV; | 2086 | return -ENODEV; |
2087 | } | 2087 | } |
2088 | 2088 | ||
2089 | static int __devexit cs4231_remove(struct of_device *op) | 2089 | static int __devexit cs4231_remove(struct platform_device *op) |
2090 | { | 2090 | { |
2091 | struct snd_cs4231 *chip = dev_get_drvdata(&op->dev); | 2091 | struct snd_cs4231 *chip = dev_get_drvdata(&op->dev); |
2092 | 2092 | ||
@@ -2120,12 +2120,12 @@ static struct of_platform_driver cs4231_driver = { | |||
2120 | 2120 | ||
2121 | static int __init cs4231_init(void) | 2121 | static int __init cs4231_init(void) |
2122 | { | 2122 | { |
2123 | return of_register_driver(&cs4231_driver, &of_bus_type); | 2123 | return of_register_platform_driver(&cs4231_driver); |
2124 | } | 2124 | } |
2125 | 2125 | ||
2126 | static void __exit cs4231_exit(void) | 2126 | static void __exit cs4231_exit(void) |
2127 | { | 2127 | { |
2128 | of_unregister_driver(&cs4231_driver); | 2128 | of_unregister_platform_driver(&cs4231_driver); |
2129 | } | 2129 | } |
2130 | 2130 | ||
2131 | module_init(cs4231_init); | 2131 | module_init(cs4231_init); |
diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c index 1557bf132e73..39cd5d69d051 100644 --- a/sound/sparc/dbri.c +++ b/sound/sparc/dbri.c | |||
@@ -299,7 +299,7 @@ struct dbri_streaminfo { | |||
299 | /* This structure holds the information for both chips (DBRI & CS4215) */ | 299 | /* This structure holds the information for both chips (DBRI & CS4215) */ |
300 | struct snd_dbri { | 300 | struct snd_dbri { |
301 | int regs_size, irq; /* Needed for unload */ | 301 | int regs_size, irq; /* Needed for unload */ |
302 | struct of_device *op; /* OF device info */ | 302 | struct platform_device *op; /* OF device info */ |
303 | spinlock_t lock; | 303 | spinlock_t lock; |
304 | 304 | ||
305 | struct dbri_dma *dma; /* Pointer to our DMA block */ | 305 | struct dbri_dma *dma; /* Pointer to our DMA block */ |
@@ -2523,7 +2523,7 @@ static void __devinit snd_dbri_proc(struct snd_card *card) | |||
2523 | static void snd_dbri_free(struct snd_dbri *dbri); | 2523 | static void snd_dbri_free(struct snd_dbri *dbri); |
2524 | 2524 | ||
2525 | static int __devinit snd_dbri_create(struct snd_card *card, | 2525 | static int __devinit snd_dbri_create(struct snd_card *card, |
2526 | struct of_device *op, | 2526 | struct platform_device *op, |
2527 | int irq, int dev) | 2527 | int irq, int dev) |
2528 | { | 2528 | { |
2529 | struct snd_dbri *dbri = card->private_data; | 2529 | struct snd_dbri *dbri = card->private_data; |
@@ -2592,7 +2592,7 @@ static void snd_dbri_free(struct snd_dbri *dbri) | |||
2592 | (void *)dbri->dma, dbri->dma_dvma); | 2592 | (void *)dbri->dma, dbri->dma_dvma); |
2593 | } | 2593 | } |
2594 | 2594 | ||
2595 | static int __devinit dbri_probe(struct of_device *op, const struct of_device_id *match) | 2595 | static int __devinit dbri_probe(struct platform_device *op, const struct of_device_id *match) |
2596 | { | 2596 | { |
2597 | struct snd_dbri *dbri; | 2597 | struct snd_dbri *dbri; |
2598 | struct resource *rp; | 2598 | struct resource *rp; |
@@ -2608,7 +2608,7 @@ static int __devinit dbri_probe(struct of_device *op, const struct of_device_id | |||
2608 | return -ENOENT; | 2608 | return -ENOENT; |
2609 | } | 2609 | } |
2610 | 2610 | ||
2611 | irq = op->irqs[0]; | 2611 | irq = op->archdata.irqs[0]; |
2612 | if (irq <= 0) { | 2612 | if (irq <= 0) { |
2613 | printk(KERN_ERR "DBRI-%d: No IRQ.\n", dev); | 2613 | printk(KERN_ERR "DBRI-%d: No IRQ.\n", dev); |
2614 | return -ENODEV; | 2614 | return -ENODEV; |
@@ -2662,7 +2662,7 @@ _err: | |||
2662 | return err; | 2662 | return err; |
2663 | } | 2663 | } |
2664 | 2664 | ||
2665 | static int __devexit dbri_remove(struct of_device *op) | 2665 | static int __devexit dbri_remove(struct platform_device *op) |
2666 | { | 2666 | { |
2667 | struct snd_card *card = dev_get_drvdata(&op->dev); | 2667 | struct snd_card *card = dev_get_drvdata(&op->dev); |
2668 | 2668 | ||
@@ -2699,12 +2699,12 @@ static struct of_platform_driver dbri_sbus_driver = { | |||
2699 | /* Probe for the dbri chip and then attach the driver. */ | 2699 | /* Probe for the dbri chip and then attach the driver. */ |
2700 | static int __init dbri_init(void) | 2700 | static int __init dbri_init(void) |
2701 | { | 2701 | { |
2702 | return of_register_driver(&dbri_sbus_driver, &of_bus_type); | 2702 | return of_register_platform_driver(&dbri_sbus_driver); |
2703 | } | 2703 | } |
2704 | 2704 | ||
2705 | static void __exit dbri_exit(void) | 2705 | static void __exit dbri_exit(void) |
2706 | { | 2706 | { |
2707 | of_unregister_driver(&dbri_sbus_driver); | 2707 | of_unregister_platform_driver(&dbri_sbus_driver); |
2708 | } | 2708 | } |
2709 | 2709 | ||
2710 | module_init(dbri_init); | 2710 | module_init(dbri_init); |
diff --git a/sound/synth/emux/emux_hwdep.c b/sound/synth/emux/emux_hwdep.c index ff0b2a8fd25b..5ae1eae9f6db 100644 --- a/sound/synth/emux/emux_hwdep.c +++ b/sound/synth/emux/emux_hwdep.c | |||
@@ -128,6 +128,9 @@ snd_emux_init_hwdep(struct snd_emux *emu) | |||
128 | strcpy(hw->name, SNDRV_EMUX_HWDEP_NAME); | 128 | strcpy(hw->name, SNDRV_EMUX_HWDEP_NAME); |
129 | hw->iface = SNDRV_HWDEP_IFACE_EMUX_WAVETABLE; | 129 | hw->iface = SNDRV_HWDEP_IFACE_EMUX_WAVETABLE; |
130 | hw->ops.ioctl = snd_emux_hwdep_ioctl; | 130 | hw->ops.ioctl = snd_emux_hwdep_ioctl; |
131 | /* The ioctl parameter types are compatible between 32- and | ||
132 | * 64-bit architectures, so use the same function. */ | ||
133 | hw->ops.ioctl_compat = snd_emux_hwdep_ioctl; | ||
131 | hw->exclusive = 1; | 134 | hw->exclusive = 1; |
132 | hw->private_data = emu; | 135 | hw->private_data = emu; |
133 | if ((err = snd_card_register(emu->card)) < 0) | 136 | if ((err = snd_card_register(emu->card)) < 0) |
diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig index 44d6d2ec964f..112984f4080f 100644 --- a/sound/usb/Kconfig +++ b/sound/usb/Kconfig | |||
@@ -65,6 +65,7 @@ config SND_USB_CAIAQ | |||
65 | * Native Instruments Guitar Rig Session I/O | 65 | * Native Instruments Guitar Rig Session I/O |
66 | * Native Instruments Guitar Rig mobile | 66 | * Native Instruments Guitar Rig mobile |
67 | * Native Instruments Traktor Kontrol X1 | 67 | * Native Instruments Traktor Kontrol X1 |
68 | * Native Instruments Traktor Kontrol S4 | ||
68 | 69 | ||
69 | To compile this driver as a module, choose M here: the module | 70 | To compile this driver as a module, choose M here: the module |
70 | will be called snd-usb-caiaq. | 71 | will be called snd-usb-caiaq. |
@@ -82,6 +83,7 @@ config SND_USB_CAIAQ_INPUT | |||
82 | * Native Instruments Kore Controller | 83 | * Native Instruments Kore Controller |
83 | * Native Instruments Kore Controller 2 | 84 | * Native Instruments Kore Controller 2 |
84 | * Native Instruments Audio Kontrol 1 | 85 | * Native Instruments Audio Kontrol 1 |
86 | * Native Instruments Traktor Kontrol S4 | ||
85 | 87 | ||
86 | config SND_USB_US122L | 88 | config SND_USB_US122L |
87 | tristate "Tascam US-122L USB driver" | 89 | tristate "Tascam US-122L USB driver" |
diff --git a/sound/usb/caiaq/audio.c b/sound/usb/caiaq/audio.c index 4328cad6c3a2..68b97477577b 100644 --- a/sound/usb/caiaq/audio.c +++ b/sound/usb/caiaq/audio.c | |||
@@ -111,7 +111,7 @@ static int stream_start(struct snd_usb_caiaqdev *dev) | |||
111 | memset(dev->sub_capture, 0, sizeof(dev->sub_capture)); | 111 | memset(dev->sub_capture, 0, sizeof(dev->sub_capture)); |
112 | dev->input_panic = 0; | 112 | dev->input_panic = 0; |
113 | dev->output_panic = 0; | 113 | dev->output_panic = 0; |
114 | dev->first_packet = 1; | 114 | dev->first_packet = 4; |
115 | dev->streaming = 1; | 115 | dev->streaming = 1; |
116 | dev->warned = 0; | 116 | dev->warned = 0; |
117 | 117 | ||
@@ -169,7 +169,7 @@ static int snd_usb_caiaq_substream_close(struct snd_pcm_substream *substream) | |||
169 | } | 169 | } |
170 | 170 | ||
171 | static int snd_usb_caiaq_pcm_hw_params(struct snd_pcm_substream *sub, | 171 | static int snd_usb_caiaq_pcm_hw_params(struct snd_pcm_substream *sub, |
172 | struct snd_pcm_hw_params *hw_params) | 172 | struct snd_pcm_hw_params *hw_params) |
173 | { | 173 | { |
174 | debug("%s(%p)\n", __func__, sub); | 174 | debug("%s(%p)\n", __func__, sub); |
175 | return snd_pcm_lib_malloc_pages(sub, params_buffer_bytes(hw_params)); | 175 | return snd_pcm_lib_malloc_pages(sub, params_buffer_bytes(hw_params)); |
@@ -189,7 +189,7 @@ static int snd_usb_caiaq_pcm_hw_free(struct snd_pcm_substream *sub) | |||
189 | #endif | 189 | #endif |
190 | 190 | ||
191 | static unsigned int rates[] = { 5512, 8000, 11025, 16000, 22050, 32000, 44100, | 191 | static unsigned int rates[] = { 5512, 8000, 11025, 16000, 22050, 32000, 44100, |
192 | 48000, 64000, 88200, 96000, 176400, 192000 }; | 192 | 48000, 64000, 88200, 96000, 176400, 192000 }; |
193 | 193 | ||
194 | static int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream) | 194 | static int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream) |
195 | { | 195 | { |
@@ -201,12 +201,39 @@ static int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream) | |||
201 | debug("%s(%p)\n", __func__, substream); | 201 | debug("%s(%p)\n", __func__, substream); |
202 | 202 | ||
203 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 203 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
204 | dev->period_out_count[index] = BYTES_PER_SAMPLE + 1; | 204 | int out_pos; |
205 | dev->audio_out_buf_pos[index] = BYTES_PER_SAMPLE + 1; | 205 | |
206 | switch (dev->spec.data_alignment) { | ||
207 | case 0: | ||
208 | case 2: | ||
209 | out_pos = BYTES_PER_SAMPLE + 1; | ||
210 | break; | ||
211 | case 3: | ||
212 | default: | ||
213 | out_pos = 0; | ||
214 | break; | ||
215 | } | ||
216 | |||
217 | dev->period_out_count[index] = out_pos; | ||
218 | dev->audio_out_buf_pos[index] = out_pos; | ||
206 | } else { | 219 | } else { |
207 | int in_pos = (dev->spec.data_alignment == 2) ? 0 : 2; | 220 | int in_pos; |
208 | dev->period_in_count[index] = BYTES_PER_SAMPLE + in_pos; | 221 | |
209 | dev->audio_in_buf_pos[index] = BYTES_PER_SAMPLE + in_pos; | 222 | switch (dev->spec.data_alignment) { |
223 | case 0: | ||
224 | in_pos = BYTES_PER_SAMPLE + 2; | ||
225 | break; | ||
226 | case 2: | ||
227 | in_pos = BYTES_PER_SAMPLE; | ||
228 | break; | ||
229 | case 3: | ||
230 | default: | ||
231 | in_pos = 0; | ||
232 | break; | ||
233 | } | ||
234 | |||
235 | dev->period_in_count[index] = in_pos; | ||
236 | dev->audio_in_buf_pos[index] = in_pos; | ||
210 | } | 237 | } |
211 | 238 | ||
212 | if (dev->streaming) | 239 | if (dev->streaming) |
@@ -221,7 +248,7 @@ static int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream) | |||
221 | snd_pcm_limit_hw_rates(runtime); | 248 | snd_pcm_limit_hw_rates(runtime); |
222 | 249 | ||
223 | bytes_per_sample = BYTES_PER_SAMPLE; | 250 | bytes_per_sample = BYTES_PER_SAMPLE; |
224 | if (dev->spec.data_alignment == 2) | 251 | if (dev->spec.data_alignment >= 2) |
225 | bytes_per_sample++; | 252 | bytes_per_sample++; |
226 | 253 | ||
227 | bpp = ((runtime->rate / 8000) + CLOCK_DRIFT_TOLERANCE) | 254 | bpp = ((runtime->rate / 8000) + CLOCK_DRIFT_TOLERANCE) |
@@ -253,6 +280,8 @@ static int snd_usb_caiaq_pcm_trigger(struct snd_pcm_substream *sub, int cmd) | |||
253 | { | 280 | { |
254 | struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(sub); | 281 | struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(sub); |
255 | 282 | ||
283 | debug("%s(%p) cmd %d\n", __func__, sub, cmd); | ||
284 | |||
256 | switch (cmd) { | 285 | switch (cmd) { |
257 | case SNDRV_PCM_TRIGGER_START: | 286 | case SNDRV_PCM_TRIGGER_START: |
258 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 287 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
@@ -402,6 +431,61 @@ static void read_in_urb_mode2(struct snd_usb_caiaqdev *dev, | |||
402 | } | 431 | } |
403 | } | 432 | } |
404 | 433 | ||
434 | static void read_in_urb_mode3(struct snd_usb_caiaqdev *dev, | ||
435 | const struct urb *urb, | ||
436 | const struct usb_iso_packet_descriptor *iso) | ||
437 | { | ||
438 | unsigned char *usb_buf = urb->transfer_buffer + iso->offset; | ||
439 | int stream, i; | ||
440 | |||
441 | /* paranoia check */ | ||
442 | if (iso->actual_length % (BYTES_PER_SAMPLE_USB * CHANNELS_PER_STREAM)) | ||
443 | return; | ||
444 | |||
445 | for (i = 0; i < iso->actual_length;) { | ||
446 | for (stream = 0; stream < dev->n_streams; stream++) { | ||
447 | struct snd_pcm_substream *sub = dev->sub_capture[stream]; | ||
448 | char *audio_buf = NULL; | ||
449 | int c, n, sz = 0; | ||
450 | |||
451 | if (sub && !dev->input_panic) { | ||
452 | struct snd_pcm_runtime *rt = sub->runtime; | ||
453 | audio_buf = rt->dma_area; | ||
454 | sz = frames_to_bytes(rt, rt->buffer_size); | ||
455 | } | ||
456 | |||
457 | for (c = 0; c < CHANNELS_PER_STREAM; c++) { | ||
458 | /* 3 audio data bytes, followed by 1 check byte */ | ||
459 | if (audio_buf) { | ||
460 | for (n = 0; n < BYTES_PER_SAMPLE; n++) { | ||
461 | audio_buf[dev->audio_in_buf_pos[stream]++] = usb_buf[i+n]; | ||
462 | |||
463 | if (dev->audio_in_buf_pos[stream] == sz) | ||
464 | dev->audio_in_buf_pos[stream] = 0; | ||
465 | } | ||
466 | |||
467 | dev->period_in_count[stream] += BYTES_PER_SAMPLE; | ||
468 | } | ||
469 | |||
470 | i += BYTES_PER_SAMPLE; | ||
471 | |||
472 | if (usb_buf[i] != ((stream << 1) | c) && | ||
473 | !dev->first_packet) { | ||
474 | if (!dev->input_panic) | ||
475 | printk(" EXPECTED: %02x got %02x, c %d, stream %d, i %d\n", | ||
476 | ((stream << 1) | c), usb_buf[i], c, stream, i); | ||
477 | dev->input_panic = 1; | ||
478 | } | ||
479 | |||
480 | i++; | ||
481 | } | ||
482 | } | ||
483 | } | ||
484 | |||
485 | if (dev->first_packet > 0) | ||
486 | dev->first_packet--; | ||
487 | } | ||
488 | |||
405 | static void read_in_urb(struct snd_usb_caiaqdev *dev, | 489 | static void read_in_urb(struct snd_usb_caiaqdev *dev, |
406 | const struct urb *urb, | 490 | const struct urb *urb, |
407 | const struct usb_iso_packet_descriptor *iso) | 491 | const struct usb_iso_packet_descriptor *iso) |
@@ -419,6 +503,9 @@ static void read_in_urb(struct snd_usb_caiaqdev *dev, | |||
419 | case 2: | 503 | case 2: |
420 | read_in_urb_mode2(dev, urb, iso); | 504 | read_in_urb_mode2(dev, urb, iso); |
421 | break; | 505 | break; |
506 | case 3: | ||
507 | read_in_urb_mode3(dev, urb, iso); | ||
508 | break; | ||
422 | } | 509 | } |
423 | 510 | ||
424 | if ((dev->input_panic || dev->output_panic) && !dev->warned) { | 511 | if ((dev->input_panic || dev->output_panic) && !dev->warned) { |
@@ -429,9 +516,9 @@ static void read_in_urb(struct snd_usb_caiaqdev *dev, | |||
429 | } | 516 | } |
430 | } | 517 | } |
431 | 518 | ||
432 | static void fill_out_urb(struct snd_usb_caiaqdev *dev, | 519 | static void fill_out_urb_mode_0(struct snd_usb_caiaqdev *dev, |
433 | struct urb *urb, | 520 | struct urb *urb, |
434 | const struct usb_iso_packet_descriptor *iso) | 521 | const struct usb_iso_packet_descriptor *iso) |
435 | { | 522 | { |
436 | unsigned char *usb_buf = urb->transfer_buffer + iso->offset; | 523 | unsigned char *usb_buf = urb->transfer_buffer + iso->offset; |
437 | struct snd_pcm_substream *sub; | 524 | struct snd_pcm_substream *sub; |
@@ -457,9 +544,67 @@ static void fill_out_urb(struct snd_usb_caiaqdev *dev, | |||
457 | /* fill in the check bytes */ | 544 | /* fill in the check bytes */ |
458 | if (dev->spec.data_alignment == 2 && | 545 | if (dev->spec.data_alignment == 2 && |
459 | i % (dev->n_streams * BYTES_PER_SAMPLE_USB) == | 546 | i % (dev->n_streams * BYTES_PER_SAMPLE_USB) == |
460 | (dev->n_streams * CHANNELS_PER_STREAM)) | 547 | (dev->n_streams * CHANNELS_PER_STREAM)) |
461 | for (stream = 0; stream < dev->n_streams; stream++, i++) | 548 | for (stream = 0; stream < dev->n_streams; stream++, i++) |
462 | usb_buf[i] = MAKE_CHECKBYTE(dev, stream, i); | 549 | usb_buf[i] = MAKE_CHECKBYTE(dev, stream, i); |
550 | } | ||
551 | } | ||
552 | |||
553 | static void fill_out_urb_mode_3(struct snd_usb_caiaqdev *dev, | ||
554 | struct urb *urb, | ||
555 | const struct usb_iso_packet_descriptor *iso) | ||
556 | { | ||
557 | unsigned char *usb_buf = urb->transfer_buffer + iso->offset; | ||
558 | int stream, i; | ||
559 | |||
560 | for (i = 0; i < iso->length;) { | ||
561 | for (stream = 0; stream < dev->n_streams; stream++) { | ||
562 | struct snd_pcm_substream *sub = dev->sub_playback[stream]; | ||
563 | char *audio_buf = NULL; | ||
564 | int c, n, sz = 0; | ||
565 | |||
566 | if (sub) { | ||
567 | struct snd_pcm_runtime *rt = sub->runtime; | ||
568 | audio_buf = rt->dma_area; | ||
569 | sz = frames_to_bytes(rt, rt->buffer_size); | ||
570 | } | ||
571 | |||
572 | for (c = 0; c < CHANNELS_PER_STREAM; c++) { | ||
573 | for (n = 0; n < BYTES_PER_SAMPLE; n++) { | ||
574 | if (audio_buf) { | ||
575 | usb_buf[i+n] = audio_buf[dev->audio_out_buf_pos[stream]++]; | ||
576 | |||
577 | if (dev->audio_out_buf_pos[stream] == sz) | ||
578 | dev->audio_out_buf_pos[stream] = 0; | ||
579 | } else { | ||
580 | usb_buf[i+n] = 0; | ||
581 | } | ||
582 | } | ||
583 | |||
584 | if (audio_buf) | ||
585 | dev->period_out_count[stream] += BYTES_PER_SAMPLE; | ||
586 | |||
587 | i += BYTES_PER_SAMPLE; | ||
588 | |||
589 | /* fill in the check byte pattern */ | ||
590 | usb_buf[i++] = (stream << 1) | c; | ||
591 | } | ||
592 | } | ||
593 | } | ||
594 | } | ||
595 | |||
596 | static inline void fill_out_urb(struct snd_usb_caiaqdev *dev, | ||
597 | struct urb *urb, | ||
598 | const struct usb_iso_packet_descriptor *iso) | ||
599 | { | ||
600 | switch (dev->spec.data_alignment) { | ||
601 | case 0: | ||
602 | case 2: | ||
603 | fill_out_urb_mode_0(dev, urb, iso); | ||
604 | break; | ||
605 | case 3: | ||
606 | fill_out_urb_mode_3(dev, urb, iso); | ||
607 | break; | ||
463 | } | 608 | } |
464 | } | 609 | } |
465 | 610 | ||
diff --git a/sound/usb/caiaq/control.c b/sound/usb/caiaq/control.c index 91c804cd2782..00e5d0a469e1 100644 --- a/sound/usb/caiaq/control.c +++ b/sound/usb/caiaq/control.c | |||
@@ -55,6 +55,10 @@ static int control_info(struct snd_kcontrol *kcontrol, | |||
55 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): | 55 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): |
56 | maxval = 127; | 56 | maxval = 127; |
57 | break; | 57 | break; |
58 | |||
59 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4): | ||
60 | maxval = 31; | ||
61 | break; | ||
58 | } | 62 | } |
59 | 63 | ||
60 | if (is_intval) { | 64 | if (is_intval) { |
@@ -93,6 +97,7 @@ static int control_put(struct snd_kcontrol *kcontrol, | |||
93 | struct snd_usb_audio *chip = snd_kcontrol_chip(kcontrol); | 97 | struct snd_usb_audio *chip = snd_kcontrol_chip(kcontrol); |
94 | struct snd_usb_caiaqdev *dev = caiaqdev(chip->card); | 98 | struct snd_usb_caiaqdev *dev = caiaqdev(chip->card); |
95 | int pos = kcontrol->private_value; | 99 | int pos = kcontrol->private_value; |
100 | int v = ucontrol->value.integer.value[0]; | ||
96 | unsigned char cmd = EP1_CMD_WRITE_IO; | 101 | unsigned char cmd = EP1_CMD_WRITE_IO; |
97 | 102 | ||
98 | if (dev->chip.usb_id == | 103 | if (dev->chip.usb_id == |
@@ -100,12 +105,27 @@ static int control_put(struct snd_kcontrol *kcontrol, | |||
100 | cmd = EP1_CMD_DIMM_LEDS; | 105 | cmd = EP1_CMD_DIMM_LEDS; |
101 | 106 | ||
102 | if (pos & CNT_INTVAL) { | 107 | if (pos & CNT_INTVAL) { |
103 | dev->control_state[pos & ~CNT_INTVAL] | 108 | int i = pos & ~CNT_INTVAL; |
104 | = ucontrol->value.integer.value[0]; | 109 | |
105 | snd_usb_caiaq_send_command(dev, cmd, | 110 | dev->control_state[i] = v; |
106 | dev->control_state, sizeof(dev->control_state)); | 111 | |
112 | if (dev->chip.usb_id == | ||
113 | USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4)) { | ||
114 | int actual_len; | ||
115 | |||
116 | dev->ep8_out_buf[0] = i; | ||
117 | dev->ep8_out_buf[1] = v; | ||
118 | |||
119 | usb_bulk_msg(dev->chip.dev, | ||
120 | usb_sndbulkpipe(dev->chip.dev, 8), | ||
121 | dev->ep8_out_buf, sizeof(dev->ep8_out_buf), | ||
122 | &actual_len, 200); | ||
123 | } else { | ||
124 | snd_usb_caiaq_send_command(dev, cmd, | ||
125 | dev->control_state, sizeof(dev->control_state)); | ||
126 | } | ||
107 | } else { | 127 | } else { |
108 | if (ucontrol->value.integer.value[0]) | 128 | if (v) |
109 | dev->control_state[pos / 8] |= 1 << (pos % 8); | 129 | dev->control_state[pos / 8] |= 1 << (pos % 8); |
110 | else | 130 | else |
111 | dev->control_state[pos / 8] &= ~(1 << (pos % 8)); | 131 | dev->control_state[pos / 8] &= ~(1 << (pos % 8)); |
@@ -296,6 +316,179 @@ static struct caiaq_controller kontrolx1_controller[] = { | |||
296 | { "LED Deck B: SYNC", 8 | CNT_INTVAL }, | 316 | { "LED Deck B: SYNC", 8 | CNT_INTVAL }, |
297 | }; | 317 | }; |
298 | 318 | ||
319 | static struct caiaq_controller kontrols4_controller[] = { | ||
320 | { "LED: Master: Quant", 10 | CNT_INTVAL }, | ||
321 | { "LED: Master: Headphone", 11 | CNT_INTVAL }, | ||
322 | { "LED: Master: Master", 12 | CNT_INTVAL }, | ||
323 | { "LED: Master: Snap", 14 | CNT_INTVAL }, | ||
324 | { "LED: Master: Warning", 15 | CNT_INTVAL }, | ||
325 | { "LED: Master: Master button", 112 | CNT_INTVAL }, | ||
326 | { "LED: Master: Snap button", 113 | CNT_INTVAL }, | ||
327 | { "LED: Master: Rec", 118 | CNT_INTVAL }, | ||
328 | { "LED: Master: Size", 119 | CNT_INTVAL }, | ||
329 | { "LED: Master: Quant button", 120 | CNT_INTVAL }, | ||
330 | { "LED: Master: Browser button", 121 | CNT_INTVAL }, | ||
331 | { "LED: Master: Play button", 126 | CNT_INTVAL }, | ||
332 | { "LED: Master: Undo button", 127 | CNT_INTVAL }, | ||
333 | |||
334 | { "LED: Channel A: >", 4 | CNT_INTVAL }, | ||
335 | { "LED: Channel A: <", 5 | CNT_INTVAL }, | ||
336 | { "LED: Channel A: Meter 1", 97 | CNT_INTVAL }, | ||
337 | { "LED: Channel A: Meter 2", 98 | CNT_INTVAL }, | ||
338 | { "LED: Channel A: Meter 3", 99 | CNT_INTVAL }, | ||
339 | { "LED: Channel A: Meter 4", 100 | CNT_INTVAL }, | ||
340 | { "LED: Channel A: Meter 5", 101 | CNT_INTVAL }, | ||
341 | { "LED: Channel A: Meter 6", 102 | CNT_INTVAL }, | ||
342 | { "LED: Channel A: Meter clip", 103 | CNT_INTVAL }, | ||
343 | { "LED: Channel A: Active", 114 | CNT_INTVAL }, | ||
344 | { "LED: Channel A: Cue", 116 | CNT_INTVAL }, | ||
345 | { "LED: Channel A: FX1", 149 | CNT_INTVAL }, | ||
346 | { "LED: Channel A: FX2", 148 | CNT_INTVAL }, | ||
347 | |||
348 | { "LED: Channel B: >", 2 | CNT_INTVAL }, | ||
349 | { "LED: Channel B: <", 3 | CNT_INTVAL }, | ||
350 | { "LED: Channel B: Meter 1", 89 | CNT_INTVAL }, | ||
351 | { "LED: Channel B: Meter 2", 90 | CNT_INTVAL }, | ||
352 | { "LED: Channel B: Meter 3", 91 | CNT_INTVAL }, | ||
353 | { "LED: Channel B: Meter 4", 92 | CNT_INTVAL }, | ||
354 | { "LED: Channel B: Meter 5", 93 | CNT_INTVAL }, | ||
355 | { "LED: Channel B: Meter 6", 94 | CNT_INTVAL }, | ||
356 | { "LED: Channel B: Meter clip", 95 | CNT_INTVAL }, | ||
357 | { "LED: Channel B: Active", 122 | CNT_INTVAL }, | ||
358 | { "LED: Channel B: Cue", 125 | CNT_INTVAL }, | ||
359 | { "LED: Channel B: FX1", 147 | CNT_INTVAL }, | ||
360 | { "LED: Channel B: FX2", 146 | CNT_INTVAL }, | ||
361 | |||
362 | { "LED: Channel C: >", 6 | CNT_INTVAL }, | ||
363 | { "LED: Channel C: <", 7 | CNT_INTVAL }, | ||
364 | { "LED: Channel C: Meter 1", 105 | CNT_INTVAL }, | ||
365 | { "LED: Channel C: Meter 2", 106 | CNT_INTVAL }, | ||
366 | { "LED: Channel C: Meter 3", 107 | CNT_INTVAL }, | ||
367 | { "LED: Channel C: Meter 4", 108 | CNT_INTVAL }, | ||
368 | { "LED: Channel C: Meter 5", 109 | CNT_INTVAL }, | ||
369 | { "LED: Channel C: Meter 6", 110 | CNT_INTVAL }, | ||
370 | { "LED: Channel C: Meter clip", 111 | CNT_INTVAL }, | ||
371 | { "LED: Channel C: Active", 115 | CNT_INTVAL }, | ||
372 | { "LED: Channel C: Cue", 117 | CNT_INTVAL }, | ||
373 | { "LED: Channel C: FX1", 151 | CNT_INTVAL }, | ||
374 | { "LED: Channel C: FX2", 150 | CNT_INTVAL }, | ||
375 | |||
376 | { "LED: Channel D: >", 0 | CNT_INTVAL }, | ||
377 | { "LED: Channel D: <", 1 | CNT_INTVAL }, | ||
378 | { "LED: Channel D: Meter 1", 81 | CNT_INTVAL }, | ||
379 | { "LED: Channel D: Meter 2", 82 | CNT_INTVAL }, | ||
380 | { "LED: Channel D: Meter 3", 83 | CNT_INTVAL }, | ||
381 | { "LED: Channel D: Meter 4", 84 | CNT_INTVAL }, | ||
382 | { "LED: Channel D: Meter 5", 85 | CNT_INTVAL }, | ||
383 | { "LED: Channel D: Meter 6", 86 | CNT_INTVAL }, | ||
384 | { "LED: Channel D: Meter clip", 87 | CNT_INTVAL }, | ||
385 | { "LED: Channel D: Active", 123 | CNT_INTVAL }, | ||
386 | { "LED: Channel D: Cue", 124 | CNT_INTVAL }, | ||
387 | { "LED: Channel D: FX1", 145 | CNT_INTVAL }, | ||
388 | { "LED: Channel D: FX2", 144 | CNT_INTVAL }, | ||
389 | |||
390 | { "LED: Deck A: 1 (blue)", 22 | CNT_INTVAL }, | ||
391 | { "LED: Deck A: 1 (green)", 23 | CNT_INTVAL }, | ||
392 | { "LED: Deck A: 2 (blue)", 20 | CNT_INTVAL }, | ||
393 | { "LED: Deck A: 2 (green)", 21 | CNT_INTVAL }, | ||
394 | { "LED: Deck A: 3 (blue)", 18 | CNT_INTVAL }, | ||
395 | { "LED: Deck A: 3 (green)", 19 | CNT_INTVAL }, | ||
396 | { "LED: Deck A: 4 (blue)", 16 | CNT_INTVAL }, | ||
397 | { "LED: Deck A: 4 (green)", 17 | CNT_INTVAL }, | ||
398 | { "LED: Deck A: Load", 44 | CNT_INTVAL }, | ||
399 | { "LED: Deck A: Deck C button", 45 | CNT_INTVAL }, | ||
400 | { "LED: Deck A: In", 47 | CNT_INTVAL }, | ||
401 | { "LED: Deck A: Out", 46 | CNT_INTVAL }, | ||
402 | { "LED: Deck A: Shift", 24 | CNT_INTVAL }, | ||
403 | { "LED: Deck A: Sync", 27 | CNT_INTVAL }, | ||
404 | { "LED: Deck A: Cue", 26 | CNT_INTVAL }, | ||
405 | { "LED: Deck A: Play", 25 | CNT_INTVAL }, | ||
406 | { "LED: Deck A: Tempo up", 33 | CNT_INTVAL }, | ||
407 | { "LED: Deck A: Tempo down", 32 | CNT_INTVAL }, | ||
408 | { "LED: Deck A: Master", 34 | CNT_INTVAL }, | ||
409 | { "LED: Deck A: Keylock", 35 | CNT_INTVAL }, | ||
410 | { "LED: Deck A: Deck A", 37 | CNT_INTVAL }, | ||
411 | { "LED: Deck A: Deck C", 36 | CNT_INTVAL }, | ||
412 | { "LED: Deck A: Samples", 38 | CNT_INTVAL }, | ||
413 | { "LED: Deck A: On Air", 39 | CNT_INTVAL }, | ||
414 | { "LED: Deck A: Sample 1", 31 | CNT_INTVAL }, | ||
415 | { "LED: Deck A: Sample 2", 30 | CNT_INTVAL }, | ||
416 | { "LED: Deck A: Sample 3", 29 | CNT_INTVAL }, | ||
417 | { "LED: Deck A: Sample 4", 28 | CNT_INTVAL }, | ||
418 | { "LED: Deck A: Digit 1 - A", 55 | CNT_INTVAL }, | ||
419 | { "LED: Deck A: Digit 1 - B", 54 | CNT_INTVAL }, | ||
420 | { "LED: Deck A: Digit 1 - C", 53 | CNT_INTVAL }, | ||
421 | { "LED: Deck A: Digit 1 - D", 52 | CNT_INTVAL }, | ||
422 | { "LED: Deck A: Digit 1 - E", 51 | CNT_INTVAL }, | ||
423 | { "LED: Deck A: Digit 1 - F", 50 | CNT_INTVAL }, | ||
424 | { "LED: Deck A: Digit 1 - G", 49 | CNT_INTVAL }, | ||
425 | { "LED: Deck A: Digit 1 - dot", 48 | CNT_INTVAL }, | ||
426 | { "LED: Deck A: Digit 2 - A", 63 | CNT_INTVAL }, | ||
427 | { "LED: Deck A: Digit 2 - B", 62 | CNT_INTVAL }, | ||
428 | { "LED: Deck A: Digit 2 - C", 61 | CNT_INTVAL }, | ||
429 | { "LED: Deck A: Digit 2 - D", 60 | CNT_INTVAL }, | ||
430 | { "LED: Deck A: Digit 2 - E", 59 | CNT_INTVAL }, | ||
431 | { "LED: Deck A: Digit 2 - F", 58 | CNT_INTVAL }, | ||
432 | { "LED: Deck A: Digit 2 - G", 57 | CNT_INTVAL }, | ||
433 | { "LED: Deck A: Digit 2 - dot", 56 | CNT_INTVAL }, | ||
434 | |||
435 | { "LED: Deck B: 1 (blue)", 78 | CNT_INTVAL }, | ||
436 | { "LED: Deck B: 1 (green)", 79 | CNT_INTVAL }, | ||
437 | { "LED: Deck B: 2 (blue)", 76 | CNT_INTVAL }, | ||
438 | { "LED: Deck B: 2 (green)", 77 | CNT_INTVAL }, | ||
439 | { "LED: Deck B: 3 (blue)", 74 | CNT_INTVAL }, | ||
440 | { "LED: Deck B: 3 (green)", 75 | CNT_INTVAL }, | ||
441 | { "LED: Deck B: 4 (blue)", 72 | CNT_INTVAL }, | ||
442 | { "LED: Deck B: 4 (green)", 73 | CNT_INTVAL }, | ||
443 | { "LED: Deck B: Load", 180 | CNT_INTVAL }, | ||
444 | { "LED: Deck B: Deck D button", 181 | CNT_INTVAL }, | ||
445 | { "LED: Deck B: In", 183 | CNT_INTVAL }, | ||
446 | { "LED: Deck B: Out", 182 | CNT_INTVAL }, | ||
447 | { "LED: Deck B: Shift", 64 | CNT_INTVAL }, | ||
448 | { "LED: Deck B: Sync", 67 | CNT_INTVAL }, | ||
449 | { "LED: Deck B: Cue", 66 | CNT_INTVAL }, | ||
450 | { "LED: Deck B: Play", 65 | CNT_INTVAL }, | ||
451 | { "LED: Deck B: Tempo up", 185 | CNT_INTVAL }, | ||
452 | { "LED: Deck B: Tempo down", 184 | CNT_INTVAL }, | ||
453 | { "LED: Deck B: Master", 186 | CNT_INTVAL }, | ||
454 | { "LED: Deck B: Keylock", 187 | CNT_INTVAL }, | ||
455 | { "LED: Deck B: Deck B", 189 | CNT_INTVAL }, | ||
456 | { "LED: Deck B: Deck D", 188 | CNT_INTVAL }, | ||
457 | { "LED: Deck B: Samples", 190 | CNT_INTVAL }, | ||
458 | { "LED: Deck B: On Air", 191 | CNT_INTVAL }, | ||
459 | { "LED: Deck B: Sample 1", 71 | CNT_INTVAL }, | ||
460 | { "LED: Deck B: Sample 2", 70 | CNT_INTVAL }, | ||
461 | { "LED: Deck B: Sample 3", 69 | CNT_INTVAL }, | ||
462 | { "LED: Deck B: Sample 4", 68 | CNT_INTVAL }, | ||
463 | { "LED: Deck B: Digit 1 - A", 175 | CNT_INTVAL }, | ||
464 | { "LED: Deck B: Digit 1 - B", 174 | CNT_INTVAL }, | ||
465 | { "LED: Deck B: Digit 1 - C", 173 | CNT_INTVAL }, | ||
466 | { "LED: Deck B: Digit 1 - D", 172 | CNT_INTVAL }, | ||
467 | { "LED: Deck B: Digit 1 - E", 171 | CNT_INTVAL }, | ||
468 | { "LED: Deck B: Digit 1 - F", 170 | CNT_INTVAL }, | ||
469 | { "LED: Deck B: Digit 1 - G", 169 | CNT_INTVAL }, | ||
470 | { "LED: Deck B: Digit 1 - dot", 168 | CNT_INTVAL }, | ||
471 | { "LED: Deck B: Digit 2 - A", 167 | CNT_INTVAL }, | ||
472 | { "LED: Deck B: Digit 2 - B", 166 | CNT_INTVAL }, | ||
473 | { "LED: Deck B: Digit 2 - C", 165 | CNT_INTVAL }, | ||
474 | { "LED: Deck B: Digit 2 - D", 164 | CNT_INTVAL }, | ||
475 | { "LED: Deck B: Digit 2 - E", 163 | CNT_INTVAL }, | ||
476 | { "LED: Deck B: Digit 2 - F", 162 | CNT_INTVAL }, | ||
477 | { "LED: Deck B: Digit 2 - G", 161 | CNT_INTVAL }, | ||
478 | { "LED: Deck B: Digit 2 - dot", 160 | CNT_INTVAL }, | ||
479 | |||
480 | { "LED: FX1: dry/wet", 153 | CNT_INTVAL }, | ||
481 | { "LED: FX1: 1", 154 | CNT_INTVAL }, | ||
482 | { "LED: FX1: 2", 155 | CNT_INTVAL }, | ||
483 | { "LED: FX1: 3", 156 | CNT_INTVAL }, | ||
484 | { "LED: FX1: Mode", 157 | CNT_INTVAL }, | ||
485 | { "LED: FX2: dry/wet", 129 | CNT_INTVAL }, | ||
486 | { "LED: FX2: 1", 130 | CNT_INTVAL }, | ||
487 | { "LED: FX2: 2", 131 | CNT_INTVAL }, | ||
488 | { "LED: FX2: 3", 132 | CNT_INTVAL }, | ||
489 | { "LED: FX2: Mode", 133 | CNT_INTVAL }, | ||
490 | }; | ||
491 | |||
299 | static int __devinit add_controls(struct caiaq_controller *c, int num, | 492 | static int __devinit add_controls(struct caiaq_controller *c, int num, |
300 | struct snd_usb_caiaqdev *dev) | 493 | struct snd_usb_caiaqdev *dev) |
301 | { | 494 | { |
@@ -354,6 +547,11 @@ int __devinit snd_usb_caiaq_control_init(struct snd_usb_caiaqdev *dev) | |||
354 | ret = add_controls(kontrolx1_controller, | 547 | ret = add_controls(kontrolx1_controller, |
355 | ARRAY_SIZE(kontrolx1_controller), dev); | 548 | ARRAY_SIZE(kontrolx1_controller), dev); |
356 | break; | 549 | break; |
550 | |||
551 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4): | ||
552 | ret = add_controls(kontrols4_controller, | ||
553 | ARRAY_SIZE(kontrols4_controller), dev); | ||
554 | break; | ||
357 | } | 555 | } |
358 | 556 | ||
359 | return ret; | 557 | return ret; |
diff --git a/sound/usb/caiaq/device.c b/sound/usb/caiaq/device.c index cdfb856bddd2..6480c3283c05 100644 --- a/sound/usb/caiaq/device.c +++ b/sound/usb/caiaq/device.c | |||
@@ -36,7 +36,7 @@ | |||
36 | #include "input.h" | 36 | #include "input.h" |
37 | 37 | ||
38 | MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>"); | 38 | MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>"); |
39 | MODULE_DESCRIPTION("caiaq USB audio, version 1.3.21"); | 39 | MODULE_DESCRIPTION("caiaq USB audio"); |
40 | MODULE_LICENSE("GPL"); | 40 | MODULE_LICENSE("GPL"); |
41 | MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2}," | 41 | MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2}," |
42 | "{Native Instruments, RigKontrol3}," | 42 | "{Native Instruments, RigKontrol3}," |
@@ -48,7 +48,8 @@ MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2}," | |||
48 | "{Native Instruments, Audio 8 DJ}," | 48 | "{Native Instruments, Audio 8 DJ}," |
49 | "{Native Instruments, Session I/O}," | 49 | "{Native Instruments, Session I/O}," |
50 | "{Native Instruments, GuitarRig mobile}" | 50 | "{Native Instruments, GuitarRig mobile}" |
51 | "{Native Instruments, Traktor Kontrol X1}"); | 51 | "{Native Instruments, Traktor Kontrol X1}" |
52 | "{Native Instruments, Traktor Kontrol S4}"); | ||
52 | 53 | ||
53 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */ | 54 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */ |
54 | static char* id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for this card */ | 55 | static char* id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for this card */ |
@@ -134,6 +135,11 @@ static struct usb_device_id snd_usb_id_table[] = { | |||
134 | .idVendor = USB_VID_NATIVEINSTRUMENTS, | 135 | .idVendor = USB_VID_NATIVEINSTRUMENTS, |
135 | .idProduct = USB_PID_TRAKTORKONTROLX1 | 136 | .idProduct = USB_PID_TRAKTORKONTROLX1 |
136 | }, | 137 | }, |
138 | { | ||
139 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE, | ||
140 | .idVendor = USB_VID_NATIVEINSTRUMENTS, | ||
141 | .idProduct = USB_PID_TRAKTORKONTROLS4 | ||
142 | }, | ||
137 | { /* terminator */ } | 143 | { /* terminator */ } |
138 | }; | 144 | }; |
139 | 145 | ||
diff --git a/sound/usb/caiaq/device.h b/sound/usb/caiaq/device.h index f1117ecc84fd..e3d8a3efb35b 100644 --- a/sound/usb/caiaq/device.h +++ b/sound/usb/caiaq/device.h | |||
@@ -16,6 +16,7 @@ | |||
16 | #define USB_PID_SESSIONIO 0x1915 | 16 | #define USB_PID_SESSIONIO 0x1915 |
17 | #define USB_PID_GUITARRIGMOBILE 0x0d8d | 17 | #define USB_PID_GUITARRIGMOBILE 0x0d8d |
18 | #define USB_PID_TRAKTORKONTROLX1 0x2305 | 18 | #define USB_PID_TRAKTORKONTROLX1 0x2305 |
19 | #define USB_PID_TRAKTORKONTROLS4 0xbaff | ||
19 | 20 | ||
20 | #define EP1_BUFSIZE 64 | 21 | #define EP1_BUFSIZE 64 |
21 | #define EP4_BUFSIZE 512 | 22 | #define EP4_BUFSIZE 512 |
@@ -99,13 +100,14 @@ struct snd_usb_caiaqdev { | |||
99 | struct snd_pcm_substream *sub_capture[MAX_STREAMS]; | 100 | struct snd_pcm_substream *sub_capture[MAX_STREAMS]; |
100 | 101 | ||
101 | /* Controls */ | 102 | /* Controls */ |
102 | unsigned char control_state[64]; | 103 | unsigned char control_state[256]; |
104 | unsigned char ep8_out_buf[2]; | ||
103 | 105 | ||
104 | /* Linux input */ | 106 | /* Linux input */ |
105 | #ifdef CONFIG_SND_USB_CAIAQ_INPUT | 107 | #ifdef CONFIG_SND_USB_CAIAQ_INPUT |
106 | struct input_dev *input_dev; | 108 | struct input_dev *input_dev; |
107 | char phys[64]; /* physical device path */ | 109 | char phys[64]; /* physical device path */ |
108 | unsigned short keycode[64]; | 110 | unsigned short keycode[128]; |
109 | struct urb *ep4_in_urb; | 111 | struct urb *ep4_in_urb; |
110 | unsigned char ep4_in_buf[EP4_BUFSIZE]; | 112 | unsigned char ep4_in_buf[EP4_BUFSIZE]; |
111 | #endif | 113 | #endif |
diff --git a/sound/usb/caiaq/input.c b/sound/usb/caiaq/input.c index dcb620796d9e..4432ef7a70a9 100644 --- a/sound/usb/caiaq/input.c +++ b/sound/usb/caiaq/input.c | |||
@@ -67,7 +67,12 @@ static unsigned short keycode_kore[] = { | |||
67 | KEY_BRL_DOT5 | 67 | KEY_BRL_DOT5 |
68 | }; | 68 | }; |
69 | 69 | ||
70 | #define KONTROLX1_INPUTS 40 | 70 | #define KONTROLX1_INPUTS (40) |
71 | #define KONTROLS4_BUTTONS (12 * 8) | ||
72 | #define KONTROLS4_AXIS (46) | ||
73 | |||
74 | #define KONTROLS4_BUTTON(X) ((X) + BTN_MISC) | ||
75 | #define KONTROLS4_ABS(X) ((X) + ABS_HAT0X) | ||
71 | 76 | ||
72 | #define DEG90 (range / 2) | 77 | #define DEG90 (range / 2) |
73 | #define DEG180 (range) | 78 | #define DEG180 (range) |
@@ -139,6 +144,13 @@ static unsigned int decode_erp(unsigned char a, unsigned char b) | |||
139 | #undef HIGH_PEAK | 144 | #undef HIGH_PEAK |
140 | #undef LOW_PEAK | 145 | #undef LOW_PEAK |
141 | 146 | ||
147 | static inline void snd_caiaq_input_report_abs(struct snd_usb_caiaqdev *dev, | ||
148 | int axis, const unsigned char *buf, | ||
149 | int offset) | ||
150 | { | ||
151 | input_report_abs(dev->input_dev, axis, | ||
152 | (buf[offset * 2] << 8) | buf[offset * 2 + 1]); | ||
153 | } | ||
142 | 154 | ||
143 | static void snd_caiaq_input_read_analog(struct snd_usb_caiaqdev *dev, | 155 | static void snd_caiaq_input_read_analog(struct snd_usb_caiaqdev *dev, |
144 | const unsigned char *buf, | 156 | const unsigned char *buf, |
@@ -148,36 +160,30 @@ static void snd_caiaq_input_read_analog(struct snd_usb_caiaqdev *dev, | |||
148 | 160 | ||
149 | switch (dev->chip.usb_id) { | 161 | switch (dev->chip.usb_id) { |
150 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2): | 162 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2): |
151 | input_report_abs(input_dev, ABS_X, (buf[4] << 8) | buf[5]); | 163 | snd_caiaq_input_report_abs(dev, ABS_X, buf, 2); |
152 | input_report_abs(input_dev, ABS_Y, (buf[0] << 8) | buf[1]); | 164 | snd_caiaq_input_report_abs(dev, ABS_Y, buf, 0); |
153 | input_report_abs(input_dev, ABS_Z, (buf[2] << 8) | buf[3]); | 165 | snd_caiaq_input_report_abs(dev, ABS_Z, buf, 1); |
154 | input_sync(input_dev); | ||
155 | break; | 166 | break; |
156 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3): | 167 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3): |
157 | input_report_abs(input_dev, ABS_X, (buf[0] << 8) | buf[1]); | ||
158 | input_report_abs(input_dev, ABS_Y, (buf[2] << 8) | buf[3]); | ||
159 | input_report_abs(input_dev, ABS_Z, (buf[4] << 8) | buf[5]); | ||
160 | input_sync(input_dev); | ||
161 | break; | ||
162 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER): | 168 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER): |
163 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2): | 169 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2): |
164 | input_report_abs(input_dev, ABS_X, (buf[0] << 8) | buf[1]); | 170 | snd_caiaq_input_report_abs(dev, ABS_X, buf, 0); |
165 | input_report_abs(input_dev, ABS_Y, (buf[2] << 8) | buf[3]); | 171 | snd_caiaq_input_report_abs(dev, ABS_Y, buf, 1); |
166 | input_report_abs(input_dev, ABS_Z, (buf[4] << 8) | buf[5]); | 172 | snd_caiaq_input_report_abs(dev, ABS_Z, buf, 2); |
167 | input_sync(input_dev); | ||
168 | break; | 173 | break; |
169 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): | 174 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): |
170 | input_report_abs(input_dev, ABS_HAT0X, (buf[8] << 8) | buf[9]); | 175 | snd_caiaq_input_report_abs(dev, ABS_HAT0X, buf, 4); |
171 | input_report_abs(input_dev, ABS_HAT0Y, (buf[4] << 8) | buf[5]); | 176 | snd_caiaq_input_report_abs(dev, ABS_HAT0Y, buf, 2); |
172 | input_report_abs(input_dev, ABS_HAT1X, (buf[12] << 8) | buf[13]); | 177 | snd_caiaq_input_report_abs(dev, ABS_HAT1X, buf, 6); |
173 | input_report_abs(input_dev, ABS_HAT1Y, (buf[2] << 8) | buf[3]); | 178 | snd_caiaq_input_report_abs(dev, ABS_HAT1Y, buf, 1); |
174 | input_report_abs(input_dev, ABS_HAT2X, (buf[14] << 8) | buf[15]); | 179 | snd_caiaq_input_report_abs(dev, ABS_HAT2X, buf, 7); |
175 | input_report_abs(input_dev, ABS_HAT2Y, (buf[0] << 8) | buf[1]); | 180 | snd_caiaq_input_report_abs(dev, ABS_HAT2Y, buf, 0); |
176 | input_report_abs(input_dev, ABS_HAT3X, (buf[10] << 8) | buf[11]); | 181 | snd_caiaq_input_report_abs(dev, ABS_HAT3X, buf, 5); |
177 | input_report_abs(input_dev, ABS_HAT3Y, (buf[6] << 8) | buf[7]); | 182 | snd_caiaq_input_report_abs(dev, ABS_HAT3Y, buf, 3); |
178 | input_sync(input_dev); | ||
179 | break; | 183 | break; |
180 | } | 184 | } |
185 | |||
186 | input_sync(input_dev); | ||
181 | } | 187 | } |
182 | 188 | ||
183 | static void snd_caiaq_input_read_erp(struct snd_usb_caiaqdev *dev, | 189 | static void snd_caiaq_input_read_erp(struct snd_usb_caiaqdev *dev, |
@@ -250,6 +256,150 @@ static void snd_caiaq_input_read_io(struct snd_usb_caiaqdev *dev, | |||
250 | input_sync(input_dev); | 256 | input_sync(input_dev); |
251 | } | 257 | } |
252 | 258 | ||
259 | #define TKS4_MSGBLOCK_SIZE 16 | ||
260 | |||
261 | static void snd_usb_caiaq_tks4_dispatch(struct snd_usb_caiaqdev *dev, | ||
262 | const unsigned char *buf, | ||
263 | unsigned int len) | ||
264 | { | ||
265 | while (len) { | ||
266 | unsigned int i, block_id = (buf[0] << 8) | buf[1]; | ||
267 | |||
268 | switch (block_id) { | ||
269 | case 0: | ||
270 | /* buttons */ | ||
271 | for (i = 0; i < KONTROLS4_BUTTONS; i++) | ||
272 | input_report_key(dev->input_dev, KONTROLS4_BUTTON(i), | ||
273 | (buf[4 + (i / 8)] >> (i % 8)) & 1); | ||
274 | break; | ||
275 | |||
276 | case 1: | ||
277 | /* left wheel */ | ||
278 | input_report_abs(dev->input_dev, KONTROLS4_ABS(36), buf[9] | ((buf[8] & 0x3) << 8)); | ||
279 | /* right wheel */ | ||
280 | input_report_abs(dev->input_dev, KONTROLS4_ABS(37), buf[13] | ((buf[12] & 0x3) << 8)); | ||
281 | |||
282 | /* rotary encoders */ | ||
283 | input_report_abs(dev->input_dev, KONTROLS4_ABS(38), buf[3] & 0xf); | ||
284 | input_report_abs(dev->input_dev, KONTROLS4_ABS(39), buf[4] >> 4); | ||
285 | input_report_abs(dev->input_dev, KONTROLS4_ABS(40), buf[4] & 0xf); | ||
286 | input_report_abs(dev->input_dev, KONTROLS4_ABS(41), buf[5] >> 4); | ||
287 | input_report_abs(dev->input_dev, KONTROLS4_ABS(42), buf[5] & 0xf); | ||
288 | input_report_abs(dev->input_dev, KONTROLS4_ABS(43), buf[6] >> 4); | ||
289 | input_report_abs(dev->input_dev, KONTROLS4_ABS(44), buf[6] & 0xf); | ||
290 | input_report_abs(dev->input_dev, KONTROLS4_ABS(45), buf[7] >> 4); | ||
291 | input_report_abs(dev->input_dev, KONTROLS4_ABS(46), buf[7] & 0xf); | ||
292 | |||
293 | break; | ||
294 | case 2: | ||
295 | /* Volume Fader Channel D */ | ||
296 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(0), buf, 1); | ||
297 | /* Volume Fader Channel B */ | ||
298 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(1), buf, 2); | ||
299 | /* Volume Fader Channel A */ | ||
300 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(2), buf, 3); | ||
301 | /* Volume Fader Channel C */ | ||
302 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(3), buf, 4); | ||
303 | /* Loop Volume */ | ||
304 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(4), buf, 6); | ||
305 | /* Crossfader */ | ||
306 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(7), buf, 7); | ||
307 | |||
308 | break; | ||
309 | |||
310 | case 3: | ||
311 | /* Tempo Fader R */ | ||
312 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(6), buf, 3); | ||
313 | /* Tempo Fader L */ | ||
314 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(5), buf, 4); | ||
315 | /* Mic Volume */ | ||
316 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(8), buf, 6); | ||
317 | /* Cue Mix */ | ||
318 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(9), buf, 7); | ||
319 | |||
320 | break; | ||
321 | |||
322 | case 4: | ||
323 | /* Wheel distance sensor L */ | ||
324 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(10), buf, 1); | ||
325 | /* Wheel distance sensor R */ | ||
326 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(11), buf, 2); | ||
327 | /* Channel D EQ - Filter */ | ||
328 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(12), buf, 3); | ||
329 | /* Channel D EQ - Low */ | ||
330 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(13), buf, 4); | ||
331 | /* Channel D EQ - Mid */ | ||
332 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(14), buf, 5); | ||
333 | /* Channel D EQ - Hi */ | ||
334 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(15), buf, 6); | ||
335 | /* FX2 - dry/wet */ | ||
336 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(16), buf, 7); | ||
337 | |||
338 | break; | ||
339 | |||
340 | case 5: | ||
341 | /* FX2 - 1 */ | ||
342 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(17), buf, 1); | ||
343 | /* FX2 - 2 */ | ||
344 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(18), buf, 2); | ||
345 | /* FX2 - 3 */ | ||
346 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(19), buf, 3); | ||
347 | /* Channel B EQ - Filter */ | ||
348 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(20), buf, 4); | ||
349 | /* Channel B EQ - Low */ | ||
350 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(21), buf, 5); | ||
351 | /* Channel B EQ - Mid */ | ||
352 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(22), buf, 6); | ||
353 | /* Channel B EQ - Hi */ | ||
354 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(23), buf, 7); | ||
355 | |||
356 | break; | ||
357 | |||
358 | case 6: | ||
359 | /* Channel A EQ - Filter */ | ||
360 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(24), buf, 1); | ||
361 | /* Channel A EQ - Low */ | ||
362 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(25), buf, 2); | ||
363 | /* Channel A EQ - Mid */ | ||
364 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(26), buf, 3); | ||
365 | /* Channel A EQ - Hi */ | ||
366 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(27), buf, 4); | ||
367 | /* Channel C EQ - Filter */ | ||
368 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(28), buf, 5); | ||
369 | /* Channel C EQ - Low */ | ||
370 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(29), buf, 6); | ||
371 | /* Channel C EQ - Mid */ | ||
372 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(30), buf, 7); | ||
373 | |||
374 | break; | ||
375 | |||
376 | case 7: | ||
377 | /* Channel C EQ - Hi */ | ||
378 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(31), buf, 1); | ||
379 | /* FX1 - wet/dry */ | ||
380 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(32), buf, 2); | ||
381 | /* FX1 - 1 */ | ||
382 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(33), buf, 3); | ||
383 | /* FX1 - 2 */ | ||
384 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(34), buf, 4); | ||
385 | /* FX1 - 3 */ | ||
386 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(35), buf, 5); | ||
387 | |||
388 | break; | ||
389 | |||
390 | default: | ||
391 | debug("%s(): bogus block (id %d)\n", | ||
392 | __func__, block_id); | ||
393 | return; | ||
394 | } | ||
395 | |||
396 | len -= TKS4_MSGBLOCK_SIZE; | ||
397 | buf += TKS4_MSGBLOCK_SIZE; | ||
398 | } | ||
399 | |||
400 | input_sync(dev->input_dev); | ||
401 | } | ||
402 | |||
253 | static void snd_usb_caiaq_ep4_reply_dispatch(struct urb *urb) | 403 | static void snd_usb_caiaq_ep4_reply_dispatch(struct urb *urb) |
254 | { | 404 | { |
255 | struct snd_usb_caiaqdev *dev = urb->context; | 405 | struct snd_usb_caiaqdev *dev = urb->context; |
@@ -259,11 +409,11 @@ static void snd_usb_caiaq_ep4_reply_dispatch(struct urb *urb) | |||
259 | if (urb->status || !dev || urb != dev->ep4_in_urb) | 409 | if (urb->status || !dev || urb != dev->ep4_in_urb) |
260 | return; | 410 | return; |
261 | 411 | ||
262 | if (urb->actual_length < 24) | ||
263 | goto requeue; | ||
264 | |||
265 | switch (dev->chip.usb_id) { | 412 | switch (dev->chip.usb_id) { |
266 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): | 413 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): |
414 | if (urb->actual_length < 24) | ||
415 | goto requeue; | ||
416 | |||
267 | if (buf[0] & 0x3) | 417 | if (buf[0] & 0x3) |
268 | snd_caiaq_input_read_io(dev, buf + 1, 7); | 418 | snd_caiaq_input_read_io(dev, buf + 1, 7); |
269 | 419 | ||
@@ -271,6 +421,10 @@ static void snd_usb_caiaq_ep4_reply_dispatch(struct urb *urb) | |||
271 | snd_caiaq_input_read_analog(dev, buf + 8, 16); | 421 | snd_caiaq_input_read_analog(dev, buf + 8, 16); |
272 | 422 | ||
273 | break; | 423 | break; |
424 | |||
425 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4): | ||
426 | snd_usb_caiaq_tks4_dispatch(dev, buf, urb->actual_length); | ||
427 | break; | ||
274 | } | 428 | } |
275 | 429 | ||
276 | requeue: | 430 | requeue: |
@@ -289,6 +443,7 @@ static int snd_usb_caiaq_input_open(struct input_dev *idev) | |||
289 | 443 | ||
290 | switch (dev->chip.usb_id) { | 444 | switch (dev->chip.usb_id) { |
291 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): | 445 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): |
446 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4): | ||
292 | if (usb_submit_urb(dev->ep4_in_urb, GFP_KERNEL) != 0) | 447 | if (usb_submit_urb(dev->ep4_in_urb, GFP_KERNEL) != 0) |
293 | return -EIO; | 448 | return -EIO; |
294 | break; | 449 | break; |
@@ -306,6 +461,7 @@ static void snd_usb_caiaq_input_close(struct input_dev *idev) | |||
306 | 461 | ||
307 | switch (dev->chip.usb_id) { | 462 | switch (dev->chip.usb_id) { |
308 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): | 463 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): |
464 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4): | ||
309 | usb_kill_urb(dev->ep4_in_urb); | 465 | usb_kill_urb(dev->ep4_in_urb); |
310 | break; | 466 | break; |
311 | } | 467 | } |
@@ -456,6 +612,46 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev) | |||
456 | snd_usb_caiaq_set_auto_msg(dev, 1, 10, 5); | 612 | snd_usb_caiaq_set_auto_msg(dev, 1, 10, 5); |
457 | 613 | ||
458 | break; | 614 | break; |
615 | |||
616 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4): | ||
617 | input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); | ||
618 | BUILD_BUG_ON(sizeof(dev->keycode) < KONTROLS4_BUTTONS); | ||
619 | for (i = 0; i < KONTROLS4_BUTTONS; i++) | ||
620 | dev->keycode[i] = KONTROLS4_BUTTON(i); | ||
621 | input->keycodemax = KONTROLS4_BUTTONS; | ||
622 | |||
623 | for (i = 0; i < KONTROLS4_AXIS; i++) { | ||
624 | int axis = KONTROLS4_ABS(i); | ||
625 | input->absbit[BIT_WORD(axis)] |= BIT_MASK(axis); | ||
626 | } | ||
627 | |||
628 | /* 36 analog potentiometers and faders */ | ||
629 | for (i = 0; i < 36; i++) | ||
630 | input_set_abs_params(input, KONTROLS4_ABS(i), 0, 0xfff, 0, 10); | ||
631 | |||
632 | /* 2 encoder wheels */ | ||
633 | input_set_abs_params(input, KONTROLS4_ABS(36), 0, 0x3ff, 0, 1); | ||
634 | input_set_abs_params(input, KONTROLS4_ABS(37), 0, 0x3ff, 0, 1); | ||
635 | |||
636 | /* 9 rotary encoders */ | ||
637 | for (i = 0; i < 9; i++) | ||
638 | input_set_abs_params(input, KONTROLS4_ABS(38+i), 0, 0xf, 0, 1); | ||
639 | |||
640 | dev->ep4_in_urb = usb_alloc_urb(0, GFP_KERNEL); | ||
641 | if (!dev->ep4_in_urb) { | ||
642 | ret = -ENOMEM; | ||
643 | goto exit_free_idev; | ||
644 | } | ||
645 | |||
646 | usb_fill_bulk_urb(dev->ep4_in_urb, usb_dev, | ||
647 | usb_rcvbulkpipe(usb_dev, 0x4), | ||
648 | dev->ep4_in_buf, EP4_BUFSIZE, | ||
649 | snd_usb_caiaq_ep4_reply_dispatch, dev); | ||
650 | |||
651 | snd_usb_caiaq_set_auto_msg(dev, 1, 10, 5); | ||
652 | |||
653 | break; | ||
654 | |||
459 | default: | 655 | default: |
460 | /* no input methods supported on this device */ | 656 | /* no input methods supported on this device */ |
461 | goto exit_free_idev; | 657 | goto exit_free_idev; |
diff --git a/sound/usb/card.c b/sound/usb/card.c index 7a8ac1d81be7..800f7cb4f251 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c | |||
@@ -126,7 +126,7 @@ static void snd_usb_stream_disconnect(struct list_head *head) | |||
126 | for (idx = 0; idx < 2; idx++) { | 126 | for (idx = 0; idx < 2; idx++) { |
127 | subs = &as->substream[idx]; | 127 | subs = &as->substream[idx]; |
128 | if (!subs->num_formats) | 128 | if (!subs->num_formats) |
129 | return; | 129 | continue; |
130 | snd_usb_release_substream_urbs(subs, 1); | 130 | snd_usb_release_substream_urbs(subs, 1); |
131 | subs->interface = -1; | 131 | subs->interface = -1; |
132 | } | 132 | } |
@@ -216,8 +216,13 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif) | |||
216 | } | 216 | } |
217 | 217 | ||
218 | switch (protocol) { | 218 | switch (protocol) { |
219 | default: | ||
220 | snd_printdd(KERN_WARNING "unknown interface protocol %#02x, assuming v1\n", | ||
221 | protocol); | ||
222 | /* fall through */ | ||
223 | |||
219 | case UAC_VERSION_1: { | 224 | case UAC_VERSION_1: { |
220 | struct uac_ac_header_descriptor_v1 *h1 = control_header; | 225 | struct uac1_ac_header_descriptor *h1 = control_header; |
221 | 226 | ||
222 | if (!h1->bInCollection) { | 227 | if (!h1->bInCollection) { |
223 | snd_printk(KERN_INFO "skipping empty audio interface (v1)\n"); | 228 | snd_printk(KERN_INFO "skipping empty audio interface (v1)\n"); |
@@ -253,10 +258,6 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif) | |||
253 | 258 | ||
254 | break; | 259 | break; |
255 | } | 260 | } |
256 | |||
257 | default: | ||
258 | snd_printk(KERN_ERR "unknown protocol version 0x%02x\n", protocol); | ||
259 | return -EINVAL; | ||
260 | } | 261 | } |
261 | 262 | ||
262 | return 0; | 263 | return 0; |
@@ -299,9 +300,13 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx, | |||
299 | 300 | ||
300 | *rchip = NULL; | 301 | *rchip = NULL; |
301 | 302 | ||
302 | if (snd_usb_get_speed(dev) != USB_SPEED_LOW && | 303 | switch (snd_usb_get_speed(dev)) { |
303 | snd_usb_get_speed(dev) != USB_SPEED_FULL && | 304 | case USB_SPEED_LOW: |
304 | snd_usb_get_speed(dev) != USB_SPEED_HIGH) { | 305 | case USB_SPEED_FULL: |
306 | case USB_SPEED_HIGH: | ||
307 | case USB_SPEED_SUPER: | ||
308 | break; | ||
309 | default: | ||
305 | snd_printk(KERN_ERR "unknown device speed %d\n", snd_usb_get_speed(dev)); | 310 | snd_printk(KERN_ERR "unknown device speed %d\n", snd_usb_get_speed(dev)); |
306 | return -ENXIO; | 311 | return -ENXIO; |
307 | } | 312 | } |
@@ -377,11 +382,22 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx, | |||
377 | if (len < sizeof(card->longname)) | 382 | if (len < sizeof(card->longname)) |
378 | usb_make_path(dev, card->longname + len, sizeof(card->longname) - len); | 383 | usb_make_path(dev, card->longname + len, sizeof(card->longname) - len); |
379 | 384 | ||
380 | strlcat(card->longname, | 385 | switch (snd_usb_get_speed(dev)) { |
381 | snd_usb_get_speed(dev) == USB_SPEED_LOW ? ", low speed" : | 386 | case USB_SPEED_LOW: |
382 | snd_usb_get_speed(dev) == USB_SPEED_FULL ? ", full speed" : | 387 | strlcat(card->longname, ", low speed", sizeof(card->longname)); |
383 | ", high speed", | 388 | break; |
384 | sizeof(card->longname)); | 389 | case USB_SPEED_FULL: |
390 | strlcat(card->longname, ", full speed", sizeof(card->longname)); | ||
391 | break; | ||
392 | case USB_SPEED_HIGH: | ||
393 | strlcat(card->longname, ", high speed", sizeof(card->longname)); | ||
394 | break; | ||
395 | case USB_SPEED_SUPER: | ||
396 | strlcat(card->longname, ", super speed", sizeof(card->longname)); | ||
397 | break; | ||
398 | default: | ||
399 | break; | ||
400 | } | ||
385 | 401 | ||
386 | snd_usb_audio_create_proc(chip); | 402 | snd_usb_audio_create_proc(chip); |
387 | 403 | ||
@@ -465,7 +481,13 @@ static void *snd_usb_audio_probe(struct usb_device *dev, | |||
465 | goto __error; | 481 | goto __error; |
466 | } | 482 | } |
467 | 483 | ||
468 | chip->ctrl_intf = alts; | 484 | /* |
485 | * For devices with more than one control interface, we assume the | ||
486 | * first contains the audio controls. We might need a more specific | ||
487 | * check here in the future. | ||
488 | */ | ||
489 | if (!chip->ctrl_intf) | ||
490 | chip->ctrl_intf = alts; | ||
469 | 491 | ||
470 | if (err > 0) { | 492 | if (err > 0) { |
471 | /* create normal USB audio interfaces */ | 493 | /* create normal USB audio interfaces */ |
diff --git a/sound/usb/clock.c b/sound/usb/clock.c index b5855114667e..7754a1034545 100644 --- a/sound/usb/clock.c +++ b/sound/usb/clock.c | |||
@@ -19,33 +19,19 @@ | |||
19 | 19 | ||
20 | #include <linux/bitops.h> | 20 | #include <linux/bitops.h> |
21 | #include <linux/init.h> | 21 | #include <linux/init.h> |
22 | #include <linux/list.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/string.h> | 22 | #include <linux/string.h> |
25 | #include <linux/usb.h> | 23 | #include <linux/usb.h> |
26 | #include <linux/moduleparam.h> | ||
27 | #include <linux/mutex.h> | ||
28 | #include <linux/usb/audio.h> | 24 | #include <linux/usb/audio.h> |
29 | #include <linux/usb/audio-v2.h> | 25 | #include <linux/usb/audio-v2.h> |
30 | 26 | ||
31 | #include <sound/core.h> | 27 | #include <sound/core.h> |
32 | #include <sound/info.h> | 28 | #include <sound/info.h> |
33 | #include <sound/pcm.h> | 29 | #include <sound/pcm.h> |
34 | #include <sound/pcm_params.h> | ||
35 | #include <sound/initval.h> | ||
36 | 30 | ||
37 | #include "usbaudio.h" | 31 | #include "usbaudio.h" |
38 | #include "card.h" | 32 | #include "card.h" |
39 | #include "midi.h" | ||
40 | #include "mixer.h" | ||
41 | #include "proc.h" | ||
42 | #include "quirks.h" | ||
43 | #include "endpoint.h" | ||
44 | #include "helper.h" | 33 | #include "helper.h" |
45 | #include "debug.h" | 34 | #include "clock.h" |
46 | #include "pcm.h" | ||
47 | #include "urb.h" | ||
48 | #include "format.h" | ||
49 | 35 | ||
50 | static struct uac_clock_source_descriptor * | 36 | static struct uac_clock_source_descriptor * |
51 | snd_usb_find_clock_source(struct usb_host_interface *ctrl_iface, | 37 | snd_usb_find_clock_source(struct usb_host_interface *ctrl_iface, |
@@ -134,10 +120,7 @@ static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, int source_id) | |||
134 | return !!data; | 120 | return !!data; |
135 | } | 121 | } |
136 | 122 | ||
137 | /* Try to find the clock source ID of a given clock entity */ | ||
138 | |||
139 | static int __uac_clock_find_source(struct snd_usb_audio *chip, | 123 | static int __uac_clock_find_source(struct snd_usb_audio *chip, |
140 | struct usb_host_interface *host_iface, | ||
141 | int entity_id, unsigned long *visited) | 124 | int entity_id, unsigned long *visited) |
142 | { | 125 | { |
143 | struct uac_clock_source_descriptor *source; | 126 | struct uac_clock_source_descriptor *source; |
@@ -154,11 +137,11 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip, | |||
154 | } | 137 | } |
155 | 138 | ||
156 | /* first, see if the ID we're looking for is a clock source already */ | 139 | /* first, see if the ID we're looking for is a clock source already */ |
157 | source = snd_usb_find_clock_source(host_iface, entity_id); | 140 | source = snd_usb_find_clock_source(chip->ctrl_intf, entity_id); |
158 | if (source) | 141 | if (source) |
159 | return source->bClockID; | 142 | return source->bClockID; |
160 | 143 | ||
161 | selector = snd_usb_find_clock_selector(host_iface, entity_id); | 144 | selector = snd_usb_find_clock_selector(chip->ctrl_intf, entity_id); |
162 | if (selector) { | 145 | if (selector) { |
163 | int ret; | 146 | int ret; |
164 | 147 | ||
@@ -168,6 +151,8 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip, | |||
168 | if (ret < 0) | 151 | if (ret < 0) |
169 | return ret; | 152 | return ret; |
170 | 153 | ||
154 | /* Selector values are one-based */ | ||
155 | |||
171 | if (ret > selector->bNrInPins || ret < 1) { | 156 | if (ret > selector->bNrInPins || ret < 1) { |
172 | printk(KERN_ERR | 157 | printk(KERN_ERR |
173 | "%s(): selector reported illegal value, id %d, ret %d\n", | 158 | "%s(): selector reported illegal value, id %d, ret %d\n", |
@@ -176,27 +161,35 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip, | |||
176 | return -EINVAL; | 161 | return -EINVAL; |
177 | } | 162 | } |
178 | 163 | ||
179 | return __uac_clock_find_source(chip, host_iface, | 164 | return __uac_clock_find_source(chip, selector->baCSourceID[ret-1], |
180 | selector->baCSourceID[ret-1], | ||
181 | visited); | 165 | visited); |
182 | } | 166 | } |
183 | 167 | ||
184 | /* FIXME: multipliers only act as pass-thru element for now */ | 168 | /* FIXME: multipliers only act as pass-thru element for now */ |
185 | multiplier = snd_usb_find_clock_multiplier(host_iface, entity_id); | 169 | multiplier = snd_usb_find_clock_multiplier(chip->ctrl_intf, entity_id); |
186 | if (multiplier) | 170 | if (multiplier) |
187 | return __uac_clock_find_source(chip, host_iface, | 171 | return __uac_clock_find_source(chip, multiplier->bCSourceID, |
188 | multiplier->bCSourceID, visited); | 172 | visited); |
189 | 173 | ||
190 | return -EINVAL; | 174 | return -EINVAL; |
191 | } | 175 | } |
192 | 176 | ||
193 | int snd_usb_clock_find_source(struct snd_usb_audio *chip, | 177 | /* |
194 | struct usb_host_interface *host_iface, | 178 | * For all kinds of sample rate settings and other device queries, |
195 | int entity_id) | 179 | * the clock source (end-leaf) must be used. However, clock selectors, |
180 | * clock multipliers and sample rate converters may be specified as | ||
181 | * clock source input to terminal. This functions walks the clock path | ||
182 | * to its end and tries to find the source. | ||
183 | * | ||
184 | * The 'visited' bitfield is used internally to detect recursive loops. | ||
185 | * | ||
186 | * Returns the clock source UnitID (>=0) on success, or an error. | ||
187 | */ | ||
188 | int snd_usb_clock_find_source(struct snd_usb_audio *chip, int entity_id) | ||
196 | { | 189 | { |
197 | DECLARE_BITMAP(visited, 256); | 190 | DECLARE_BITMAP(visited, 256); |
198 | memset(visited, 0, sizeof(visited)); | 191 | memset(visited, 0, sizeof(visited)); |
199 | return __uac_clock_find_source(chip, host_iface, entity_id, visited); | 192 | return __uac_clock_find_source(chip, entity_id, visited); |
200 | } | 193 | } |
201 | 194 | ||
202 | static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface, | 195 | static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface, |
@@ -211,11 +204,8 @@ static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface, | |||
211 | ep = get_endpoint(alts, 0)->bEndpointAddress; | 204 | ep = get_endpoint(alts, 0)->bEndpointAddress; |
212 | 205 | ||
213 | /* if endpoint doesn't have sampling rate control, bail out */ | 206 | /* if endpoint doesn't have sampling rate control, bail out */ |
214 | if (!(fmt->attributes & UAC_EP_CS_ATTR_SAMPLE_RATE)) { | 207 | if (!(fmt->attributes & UAC_EP_CS_ATTR_SAMPLE_RATE)) |
215 | snd_printk(KERN_WARNING "%d:%d:%d: endpoint lacks sample rate attribute bit, cannot set.\n", | ||
216 | dev->devnum, iface, fmt->altsetting); | ||
217 | return 0; | 208 | return 0; |
218 | } | ||
219 | 209 | ||
220 | data[0] = rate; | 210 | data[0] = rate; |
221 | data[1] = rate >> 8; | 211 | data[1] = rate >> 8; |
@@ -254,12 +244,13 @@ static int set_sample_rate_v2(struct snd_usb_audio *chip, int iface, | |||
254 | struct usb_device *dev = chip->dev; | 244 | struct usb_device *dev = chip->dev; |
255 | unsigned char data[4]; | 245 | unsigned char data[4]; |
256 | int err, crate; | 246 | int err, crate; |
257 | int clock = snd_usb_clock_find_source(chip, chip->ctrl_intf, fmt->clock); | 247 | int clock = snd_usb_clock_find_source(chip, fmt->clock); |
258 | 248 | ||
259 | if (clock < 0) | 249 | if (clock < 0) |
260 | return clock; | 250 | return clock; |
261 | 251 | ||
262 | if (!uac_clock_source_is_valid(chip, clock)) { | 252 | if (!uac_clock_source_is_valid(chip, clock)) { |
253 | /* TODO: should we try to find valid clock setups by ourself? */ | ||
263 | snd_printk(KERN_ERR "%d:%d:%d: clock source %d is not valid, cannot use\n", | 254 | snd_printk(KERN_ERR "%d:%d:%d: clock source %d is not valid, cannot use\n", |
264 | dev->devnum, iface, fmt->altsetting, clock); | 255 | dev->devnum, iface, fmt->altsetting, clock); |
265 | return -ENXIO; | 256 | return -ENXIO; |
@@ -304,12 +295,11 @@ int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface, | |||
304 | 295 | ||
305 | switch (altsd->bInterfaceProtocol) { | 296 | switch (altsd->bInterfaceProtocol) { |
306 | case UAC_VERSION_1: | 297 | case UAC_VERSION_1: |
298 | default: | ||
307 | return set_sample_rate_v1(chip, iface, alts, fmt, rate); | 299 | return set_sample_rate_v1(chip, iface, alts, fmt, rate); |
308 | 300 | ||
309 | case UAC_VERSION_2: | 301 | case UAC_VERSION_2: |
310 | return set_sample_rate_v2(chip, iface, alts, fmt, rate); | 302 | return set_sample_rate_v2(chip, iface, alts, fmt, rate); |
311 | } | 303 | } |
312 | |||
313 | return -EINVAL; | ||
314 | } | 304 | } |
315 | 305 | ||
diff --git a/sound/usb/clock.h b/sound/usb/clock.h index beb253684e2d..46630936d31f 100644 --- a/sound/usb/clock.h +++ b/sound/usb/clock.h | |||
@@ -5,8 +5,6 @@ int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface, | |||
5 | struct usb_host_interface *alts, | 5 | struct usb_host_interface *alts, |
6 | struct audioformat *fmt, int rate); | 6 | struct audioformat *fmt, int rate); |
7 | 7 | ||
8 | int snd_usb_clock_find_source(struct snd_usb_audio *chip, | 8 | int snd_usb_clock_find_source(struct snd_usb_audio *chip, int entity_id); |
9 | struct usb_host_interface *host_iface, | ||
10 | int entity_id); | ||
11 | 9 | ||
12 | #endif /* __USBAUDIO_CLOCK_H */ | 10 | #endif /* __USBAUDIO_CLOCK_H */ |
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index 6f6596cf2b19..b0ef9f501896 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include "pcm.h" | 33 | #include "pcm.h" |
34 | #include "helper.h" | 34 | #include "helper.h" |
35 | #include "format.h" | 35 | #include "format.h" |
36 | #include "clock.h" | ||
36 | 37 | ||
37 | /* | 38 | /* |
38 | * free a substream | 39 | * free a substream |
@@ -274,8 +275,14 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) | |||
274 | 275 | ||
275 | /* get audio formats */ | 276 | /* get audio formats */ |
276 | switch (protocol) { | 277 | switch (protocol) { |
278 | default: | ||
279 | snd_printdd(KERN_WARNING "%d:%u:%d: unknown interface protocol %#02x, assuming v1\n", | ||
280 | dev->devnum, iface_no, altno, protocol); | ||
281 | protocol = UAC_VERSION_1; | ||
282 | /* fall through */ | ||
283 | |||
277 | case UAC_VERSION_1: { | 284 | case UAC_VERSION_1: { |
278 | struct uac_as_header_descriptor_v1 *as = | 285 | struct uac1_as_header_descriptor *as = |
279 | snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL); | 286 | snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL); |
280 | 287 | ||
281 | if (!as) { | 288 | if (!as) { |
@@ -297,7 +304,7 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) | |||
297 | case UAC_VERSION_2: { | 304 | case UAC_VERSION_2: { |
298 | struct uac2_input_terminal_descriptor *input_term; | 305 | struct uac2_input_terminal_descriptor *input_term; |
299 | struct uac2_output_terminal_descriptor *output_term; | 306 | struct uac2_output_terminal_descriptor *output_term; |
300 | struct uac_as_header_descriptor_v2 *as = | 307 | struct uac2_as_header_descriptor *as = |
301 | snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL); | 308 | snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL); |
302 | 309 | ||
303 | if (!as) { | 310 | if (!as) { |
@@ -335,11 +342,6 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) | |||
335 | dev->devnum, iface_no, altno, as->bTerminalLink); | 342 | dev->devnum, iface_no, altno, as->bTerminalLink); |
336 | continue; | 343 | continue; |
337 | } | 344 | } |
338 | |||
339 | default: | ||
340 | snd_printk(KERN_ERR "%d:%u:%d : unknown interface protocol %04x\n", | ||
341 | dev->devnum, iface_no, altno, protocol); | ||
342 | continue; | ||
343 | } | 345 | } |
344 | 346 | ||
345 | /* get format type */ | 347 | /* get format type */ |
@@ -403,8 +405,6 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) | |||
403 | break; | 405 | break; |
404 | case USB_ID(0x041e, 0x3020): /* Creative SB Audigy 2 NX */ | 406 | case USB_ID(0x041e, 0x3020): /* Creative SB Audigy 2 NX */ |
405 | case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */ | 407 | case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */ |
406 | case USB_ID(0x0763, 0x2080): /* M-Audio Fast Track Ultra 8 */ | ||
407 | case USB_ID(0x0763, 0x2081): /* M-Audio Fast Track Ultra 8R */ | ||
408 | /* doesn't set the sample rate attribute, but supports it */ | 408 | /* doesn't set the sample rate attribute, but supports it */ |
409 | fp->attributes |= UAC_EP_CS_ATTR_SAMPLE_RATE; | 409 | fp->attributes |= UAC_EP_CS_ATTR_SAMPLE_RATE; |
410 | break; | 410 | break; |
diff --git a/sound/usb/format.c b/sound/usb/format.c index 30364aba79cc..69148212aa70 100644 --- a/sound/usb/format.c +++ b/sound/usb/format.c | |||
@@ -49,7 +49,8 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip, | |||
49 | u64 pcm_formats; | 49 | u64 pcm_formats; |
50 | 50 | ||
51 | switch (protocol) { | 51 | switch (protocol) { |
52 | case UAC_VERSION_1: { | 52 | case UAC_VERSION_1: |
53 | default: { | ||
53 | struct uac_format_type_i_discrete_descriptor *fmt = _fmt; | 54 | struct uac_format_type_i_discrete_descriptor *fmt = _fmt; |
54 | sample_width = fmt->bBitResolution; | 55 | sample_width = fmt->bBitResolution; |
55 | sample_bytes = fmt->bSubframeSize; | 56 | sample_bytes = fmt->bSubframeSize; |
@@ -64,9 +65,6 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip, | |||
64 | format <<= 1; | 65 | format <<= 1; |
65 | break; | 66 | break; |
66 | } | 67 | } |
67 | |||
68 | default: | ||
69 | return -EINVAL; | ||
70 | } | 68 | } |
71 | 69 | ||
72 | pcm_formats = 0; | 70 | pcm_formats = 0; |
@@ -264,13 +262,12 @@ static int parse_uac2_sample_rate_range(struct audioformat *fp, int nr_triplets, | |||
264 | * on the audioformat table (audio class v2). | 262 | * on the audioformat table (audio class v2). |
265 | */ | 263 | */ |
266 | static int parse_audio_format_rates_v2(struct snd_usb_audio *chip, | 264 | static int parse_audio_format_rates_v2(struct snd_usb_audio *chip, |
267 | struct audioformat *fp, | 265 | struct audioformat *fp) |
268 | struct usb_host_interface *iface) | ||
269 | { | 266 | { |
270 | struct usb_device *dev = chip->dev; | 267 | struct usb_device *dev = chip->dev; |
271 | unsigned char tmp[2], *data; | 268 | unsigned char tmp[2], *data; |
272 | int nr_triplets, data_size, ret = 0; | 269 | int nr_triplets, data_size, ret = 0; |
273 | int clock = snd_usb_clock_find_source(chip, chip->ctrl_intf, fp->clock); | 270 | int clock = snd_usb_clock_find_source(chip, fp->clock); |
274 | 271 | ||
275 | if (clock < 0) { | 272 | if (clock < 0) { |
276 | snd_printk(KERN_ERR "%s(): unable to find clock source (clock %d)\n", | 273 | snd_printk(KERN_ERR "%s(): unable to find clock source (clock %d)\n", |
@@ -385,13 +382,17 @@ static int parse_audio_format_i(struct snd_usb_audio *chip, | |||
385 | * audio class v2 uses class specific EP0 range requests for that. | 382 | * audio class v2 uses class specific EP0 range requests for that. |
386 | */ | 383 | */ |
387 | switch (protocol) { | 384 | switch (protocol) { |
385 | default: | ||
386 | snd_printdd(KERN_WARNING "%d:%u:%d : invalid protocol version %d, assuming v1\n", | ||
387 | chip->dev->devnum, fp->iface, fp->altsetting, protocol); | ||
388 | /* fall through */ | ||
388 | case UAC_VERSION_1: | 389 | case UAC_VERSION_1: |
389 | fp->channels = fmt->bNrChannels; | 390 | fp->channels = fmt->bNrChannels; |
390 | ret = parse_audio_format_rates_v1(chip, fp, (unsigned char *) fmt, 7); | 391 | ret = parse_audio_format_rates_v1(chip, fp, (unsigned char *) fmt, 7); |
391 | break; | 392 | break; |
392 | case UAC_VERSION_2: | 393 | case UAC_VERSION_2: |
393 | /* fp->channels is already set in this case */ | 394 | /* fp->channels is already set in this case */ |
394 | ret = parse_audio_format_rates_v2(chip, fp, iface); | 395 | ret = parse_audio_format_rates_v2(chip, fp); |
395 | break; | 396 | break; |
396 | } | 397 | } |
397 | 398 | ||
@@ -435,6 +436,10 @@ static int parse_audio_format_ii(struct snd_usb_audio *chip, | |||
435 | fp->channels = 1; | 436 | fp->channels = 1; |
436 | 437 | ||
437 | switch (protocol) { | 438 | switch (protocol) { |
439 | default: | ||
440 | snd_printdd(KERN_WARNING "%d:%u:%d : invalid protocol version %d, assuming v1\n", | ||
441 | chip->dev->devnum, fp->iface, fp->altsetting, protocol); | ||
442 | /* fall through */ | ||
438 | case UAC_VERSION_1: { | 443 | case UAC_VERSION_1: { |
439 | struct uac_format_type_ii_discrete_descriptor *fmt = _fmt; | 444 | struct uac_format_type_ii_discrete_descriptor *fmt = _fmt; |
440 | brate = le16_to_cpu(fmt->wMaxBitRate); | 445 | brate = le16_to_cpu(fmt->wMaxBitRate); |
@@ -450,7 +455,7 @@ static int parse_audio_format_ii(struct snd_usb_audio *chip, | |||
450 | framesize = le16_to_cpu(fmt->wSamplesPerFrame); | 455 | framesize = le16_to_cpu(fmt->wSamplesPerFrame); |
451 | snd_printd(KERN_INFO "found format II with max.bitrate = %d, frame size=%d\n", brate, framesize); | 456 | snd_printd(KERN_INFO "found format II with max.bitrate = %d, frame size=%d\n", brate, framesize); |
452 | fp->frame_size = framesize; | 457 | fp->frame_size = framesize; |
453 | ret = parse_audio_format_rates_v2(chip, fp, iface); | 458 | ret = parse_audio_format_rates_v2(chip, fp); |
454 | break; | 459 | break; |
455 | } | 460 | } |
456 | } | 461 | } |
diff --git a/sound/usb/helper.c b/sound/usb/helper.c index d48d6f8f6ac9..f280c1903c25 100644 --- a/sound/usb/helper.c +++ b/sound/usb/helper.c | |||
@@ -103,11 +103,16 @@ int snd_usb_ctl_msg(struct usb_device *dev, unsigned int pipe, __u8 request, | |||
103 | unsigned char snd_usb_parse_datainterval(struct snd_usb_audio *chip, | 103 | unsigned char snd_usb_parse_datainterval(struct snd_usb_audio *chip, |
104 | struct usb_host_interface *alts) | 104 | struct usb_host_interface *alts) |
105 | { | 105 | { |
106 | if (snd_usb_get_speed(chip->dev) == USB_SPEED_HIGH && | 106 | switch (snd_usb_get_speed(chip->dev)) { |
107 | get_endpoint(alts, 0)->bInterval >= 1 && | 107 | case USB_SPEED_HIGH: |
108 | get_endpoint(alts, 0)->bInterval <= 4) | 108 | case USB_SPEED_SUPER: |
109 | return get_endpoint(alts, 0)->bInterval - 1; | 109 | if (get_endpoint(alts, 0)->bInterval >= 1 && |
110 | else | 110 | get_endpoint(alts, 0)->bInterval <= 4) |
111 | return 0; | 111 | return get_endpoint(alts, 0)->bInterval - 1; |
112 | break; | ||
113 | default: | ||
114 | break; | ||
115 | } | ||
116 | return 0; | ||
112 | } | 117 | } |
113 | 118 | ||
diff --git a/sound/usb/midi.c b/sound/usb/midi.c index 46785643c66d..156cd0716c42 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c | |||
@@ -434,7 +434,7 @@ static void snd_usbmidi_maudio_broken_running_status_input( | |||
434 | u8 cin = buffer[i] & 0x0f; | 434 | u8 cin = buffer[i] & 0x0f; |
435 | struct usbmidi_in_port *port = &ep->ports[cable]; | 435 | struct usbmidi_in_port *port = &ep->ports[cable]; |
436 | int length; | 436 | int length; |
437 | 437 | ||
438 | length = snd_usbmidi_cin_length[cin]; | 438 | length = snd_usbmidi_cin_length[cin]; |
439 | if (cin == 0xf && buffer[i + 1] >= 0xf8) | 439 | if (cin == 0xf && buffer[i + 1] >= 0xf8) |
440 | ; /* realtime msg: no running status change */ | 440 | ; /* realtime msg: no running status change */ |
@@ -628,13 +628,13 @@ static struct usb_protocol_ops snd_usbmidi_standard_ops = { | |||
628 | 628 | ||
629 | static struct usb_protocol_ops snd_usbmidi_midiman_ops = { | 629 | static struct usb_protocol_ops snd_usbmidi_midiman_ops = { |
630 | .input = snd_usbmidi_midiman_input, | 630 | .input = snd_usbmidi_midiman_input, |
631 | .output = snd_usbmidi_standard_output, | 631 | .output = snd_usbmidi_standard_output, |
632 | .output_packet = snd_usbmidi_output_midiman_packet, | 632 | .output_packet = snd_usbmidi_output_midiman_packet, |
633 | }; | 633 | }; |
634 | 634 | ||
635 | static struct usb_protocol_ops snd_usbmidi_maudio_broken_running_status_ops = { | 635 | static struct usb_protocol_ops snd_usbmidi_maudio_broken_running_status_ops = { |
636 | .input = snd_usbmidi_maudio_broken_running_status_input, | 636 | .input = snd_usbmidi_maudio_broken_running_status_input, |
637 | .output = snd_usbmidi_standard_output, | 637 | .output = snd_usbmidi_standard_output, |
638 | .output_packet = snd_usbmidi_output_standard_packet, | 638 | .output_packet = snd_usbmidi_output_standard_packet, |
639 | }; | 639 | }; |
640 | 640 | ||
@@ -834,7 +834,14 @@ static void snd_usbmidi_us122l_output(struct snd_usb_midi_out_endpoint *ep, | |||
834 | 834 | ||
835 | if (!ep->ports[0].active) | 835 | if (!ep->ports[0].active) |
836 | return; | 836 | return; |
837 | count = snd_usb_get_speed(ep->umidi->dev) == USB_SPEED_HIGH ? 1 : 2; | 837 | switch (snd_usb_get_speed(ep->umidi->dev)) { |
838 | case USB_SPEED_HIGH: | ||
839 | case USB_SPEED_SUPER: | ||
840 | count = 1; | ||
841 | break; | ||
842 | default: | ||
843 | count = 2; | ||
844 | } | ||
838 | count = snd_rawmidi_transmit(ep->ports[0].substream, | 845 | count = snd_rawmidi_transmit(ep->ports[0].substream, |
839 | urb->transfer_buffer, | 846 | urb->transfer_buffer, |
840 | count); | 847 | count); |
@@ -1248,7 +1255,7 @@ static void snd_usbmidi_out_endpoint_delete(struct snd_usb_midi_out_endpoint *ep | |||
1248 | */ | 1255 | */ |
1249 | static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi* umidi, | 1256 | static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi* umidi, |
1250 | struct snd_usb_midi_endpoint_info* ep_info, | 1257 | struct snd_usb_midi_endpoint_info* ep_info, |
1251 | struct snd_usb_midi_endpoint* rep) | 1258 | struct snd_usb_midi_endpoint* rep) |
1252 | { | 1259 | { |
1253 | struct snd_usb_midi_out_endpoint* ep; | 1260 | struct snd_usb_midi_out_endpoint* ep; |
1254 | unsigned int i; | 1261 | unsigned int i; |
@@ -1398,7 +1405,7 @@ static void snd_usbmidi_rawmidi_free(struct snd_rawmidi *rmidi) | |||
1398 | } | 1405 | } |
1399 | 1406 | ||
1400 | static struct snd_rawmidi_substream *snd_usbmidi_find_substream(struct snd_usb_midi* umidi, | 1407 | static struct snd_rawmidi_substream *snd_usbmidi_find_substream(struct snd_usb_midi* umidi, |
1401 | int stream, int number) | 1408 | int stream, int number) |
1402 | { | 1409 | { |
1403 | struct list_head* list; | 1410 | struct list_head* list; |
1404 | 1411 | ||
@@ -1811,7 +1818,7 @@ static int snd_usbmidi_detect_endpoints(struct snd_usb_midi* umidi, | |||
1811 | snd_usbmidi_switch_roland_altsetting(umidi); | 1818 | snd_usbmidi_switch_roland_altsetting(umidi); |
1812 | 1819 | ||
1813 | if (endpoint[0].out_ep || endpoint[0].in_ep) | 1820 | if (endpoint[0].out_ep || endpoint[0].in_ep) |
1814 | return 0; | 1821 | return 0; |
1815 | 1822 | ||
1816 | intf = umidi->iface; | 1823 | intf = umidi->iface; |
1817 | if (!intf || intf->num_altsetting < 1) | 1824 | if (!intf || intf->num_altsetting < 1) |
@@ -1849,7 +1856,7 @@ static int snd_usbmidi_detect_per_port_endpoints(struct snd_usb_midi* umidi, | |||
1849 | struct snd_usb_midi_endpoint_info* endpoints) | 1856 | struct snd_usb_midi_endpoint_info* endpoints) |
1850 | { | 1857 | { |
1851 | int err, i; | 1858 | int err, i; |
1852 | 1859 | ||
1853 | err = snd_usbmidi_detect_endpoints(umidi, endpoints, MIDI_MAX_ENDPOINTS); | 1860 | err = snd_usbmidi_detect_endpoints(umidi, endpoints, MIDI_MAX_ENDPOINTS); |
1854 | for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) { | 1861 | for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) { |
1855 | if (endpoints[i].out_ep) | 1862 | if (endpoints[i].out_ep) |
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 736d134cc03c..f2d74d654b3c 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c | |||
@@ -26,6 +26,22 @@ | |||
26 | * | 26 | * |
27 | */ | 27 | */ |
28 | 28 | ||
29 | /* | ||
30 | * TODOs, for both the mixer and the streaming interfaces: | ||
31 | * | ||
32 | * - support for UAC2 effect units | ||
33 | * - support for graphical equalizers | ||
34 | * - RANGE and MEM set commands (UAC2) | ||
35 | * - RANGE and MEM interrupt dispatchers (UAC2) | ||
36 | * - audio channel clustering (UAC2) | ||
37 | * - audio sample rate converter units (UAC2) | ||
38 | * - proper handling of clock multipliers (UAC2) | ||
39 | * - dispatch clock change notifications (UAC2) | ||
40 | * - stop PCM streams which use a clock that became invalid | ||
41 | * - stop PCM streams which use a clock selector that has changed | ||
42 | * - parse available sample rates again when clock sources changed | ||
43 | */ | ||
44 | |||
29 | #include <linux/bitops.h> | 45 | #include <linux/bitops.h> |
30 | #include <linux/init.h> | 46 | #include <linux/init.h> |
31 | #include <linux/list.h> | 47 | #include <linux/list.h> |
@@ -275,28 +291,28 @@ static int get_abs_value(struct usb_mixer_elem_info *cval, int val) | |||
275 | 291 | ||
276 | static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request, int validx, int *value_ret) | 292 | static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request, int validx, int *value_ret) |
277 | { | 293 | { |
294 | struct snd_usb_audio *chip = cval->mixer->chip; | ||
278 | unsigned char buf[2]; | 295 | unsigned char buf[2]; |
279 | int val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1; | 296 | int val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1; |
280 | int timeout = 10; | 297 | int timeout = 10; |
281 | 298 | ||
282 | while (timeout-- > 0) { | 299 | while (timeout-- > 0) { |
283 | if (snd_usb_ctl_msg(cval->mixer->chip->dev, | 300 | if (snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), request, |
284 | usb_rcvctrlpipe(cval->mixer->chip->dev, 0), | ||
285 | request, | ||
286 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, | 301 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, |
287 | validx, cval->mixer->ctrlif | (cval->id << 8), | 302 | validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), |
288 | buf, val_len, 100) >= val_len) { | 303 | buf, val_len, 100) >= val_len) { |
289 | *value_ret = convert_signed_value(cval, snd_usb_combine_bytes(buf, val_len)); | 304 | *value_ret = convert_signed_value(cval, snd_usb_combine_bytes(buf, val_len)); |
290 | return 0; | 305 | return 0; |
291 | } | 306 | } |
292 | } | 307 | } |
293 | snd_printdd(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n", | 308 | snd_printdd(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n", |
294 | request, validx, cval->mixer->ctrlif | (cval->id << 8), cval->val_type); | 309 | request, validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), cval->val_type); |
295 | return -EINVAL; | 310 | return -EINVAL; |
296 | } | 311 | } |
297 | 312 | ||
298 | static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int validx, int *value_ret) | 313 | static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int validx, int *value_ret) |
299 | { | 314 | { |
315 | struct snd_usb_audio *chip = cval->mixer->chip; | ||
300 | unsigned char buf[2 + 3*sizeof(__u16)]; /* enough space for one range */ | 316 | unsigned char buf[2 + 3*sizeof(__u16)]; /* enough space for one range */ |
301 | unsigned char *val; | 317 | unsigned char *val; |
302 | int ret, size; | 318 | int ret, size; |
@@ -312,16 +328,14 @@ static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int v | |||
312 | 328 | ||
313 | memset(buf, 0, sizeof(buf)); | 329 | memset(buf, 0, sizeof(buf)); |
314 | 330 | ||
315 | ret = snd_usb_ctl_msg(cval->mixer->chip->dev, | 331 | ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), bRequest, |
316 | usb_rcvctrlpipe(cval->mixer->chip->dev, 0), | ||
317 | bRequest, | ||
318 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, | 332 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, |
319 | validx, cval->mixer->ctrlif | (cval->id << 8), | 333 | validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), |
320 | buf, size, 1000); | 334 | buf, size, 1000); |
321 | 335 | ||
322 | if (ret < 0) { | 336 | if (ret < 0) { |
323 | snd_printk(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n", | 337 | snd_printk(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n", |
324 | request, validx, cval->mixer->ctrlif | (cval->id << 8), cval->val_type); | 338 | request, validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), cval->val_type); |
325 | return ret; | 339 | return ret; |
326 | } | 340 | } |
327 | 341 | ||
@@ -397,6 +411,7 @@ static int get_cur_mix_value(struct usb_mixer_elem_info *cval, | |||
397 | int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval, | 411 | int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval, |
398 | int request, int validx, int value_set) | 412 | int request, int validx, int value_set) |
399 | { | 413 | { |
414 | struct snd_usb_audio *chip = cval->mixer->chip; | ||
400 | unsigned char buf[2]; | 415 | unsigned char buf[2]; |
401 | int val_len, timeout = 10; | 416 | int val_len, timeout = 10; |
402 | 417 | ||
@@ -419,15 +434,14 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval, | |||
419 | buf[0] = value_set & 0xff; | 434 | buf[0] = value_set & 0xff; |
420 | buf[1] = (value_set >> 8) & 0xff; | 435 | buf[1] = (value_set >> 8) & 0xff; |
421 | while (timeout-- > 0) | 436 | while (timeout-- > 0) |
422 | if (snd_usb_ctl_msg(cval->mixer->chip->dev, | 437 | if (snd_usb_ctl_msg(chip->dev, |
423 | usb_sndctrlpipe(cval->mixer->chip->dev, 0), | 438 | usb_sndctrlpipe(chip->dev, 0), request, |
424 | request, | ||
425 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, | 439 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, |
426 | validx, cval->mixer->ctrlif | (cval->id << 8), | 440 | validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), |
427 | buf, val_len, 100) >= 0) | 441 | buf, val_len, 100) >= 0) |
428 | return 0; | 442 | return 0; |
429 | snd_printdd(KERN_ERR "cannot set ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d, data = %#x/%#x\n", | 443 | snd_printdd(KERN_ERR "cannot set ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d, data = %#x/%#x\n", |
430 | request, validx, cval->mixer->ctrlif | (cval->id << 8), cval->val_type, buf[0], buf[1]); | 444 | request, validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), cval->val_type, buf[0], buf[1]); |
431 | return -EINVAL; | 445 | return -EINVAL; |
432 | } | 446 | } |
433 | 447 | ||
@@ -582,9 +596,9 @@ static int get_term_name(struct mixer_build *state, struct usb_audio_term *iterm | |||
582 | switch (iterm->type >> 16) { | 596 | switch (iterm->type >> 16) { |
583 | case UAC_SELECTOR_UNIT: | 597 | case UAC_SELECTOR_UNIT: |
584 | strcpy(name, "Selector"); return 8; | 598 | strcpy(name, "Selector"); return 8; |
585 | case UAC_PROCESSING_UNIT_V1: | 599 | case UAC1_PROCESSING_UNIT: |
586 | strcpy(name, "Process Unit"); return 12; | 600 | strcpy(name, "Process Unit"); return 12; |
587 | case UAC_EXTENSION_UNIT_V1: | 601 | case UAC1_EXTENSION_UNIT: |
588 | strcpy(name, "Ext Unit"); return 8; | 602 | strcpy(name, "Ext Unit"); return 8; |
589 | case UAC_MIXER_UNIT: | 603 | case UAC_MIXER_UNIT: |
590 | strcpy(name, "Mixer"); return 5; | 604 | strcpy(name, "Mixer"); return 5; |
@@ -672,8 +686,8 @@ static int check_input_term(struct mixer_build *state, int id, struct usb_audio_ | |||
672 | term->name = uac_selector_unit_iSelector(d); | 686 | term->name = uac_selector_unit_iSelector(d); |
673 | return 0; | 687 | return 0; |
674 | } | 688 | } |
675 | case UAC_PROCESSING_UNIT_V1: | 689 | case UAC1_PROCESSING_UNIT: |
676 | case UAC_EXTENSION_UNIT_V1: { | 690 | case UAC1_EXTENSION_UNIT: { |
677 | struct uac_processing_unit_descriptor *d = p1; | 691 | struct uac_processing_unit_descriptor *d = p1; |
678 | if (d->bNrInPins) { | 692 | if (d->bNrInPins) { |
679 | id = d->baSourceID[0]; | 693 | id = d->baSourceID[0]; |
@@ -767,7 +781,7 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min) | |||
767 | if (get_ctl_value(cval, UAC_GET_MAX, (cval->control << 8) | minchn, &cval->max) < 0 || | 781 | if (get_ctl_value(cval, UAC_GET_MAX, (cval->control << 8) | minchn, &cval->max) < 0 || |
768 | get_ctl_value(cval, UAC_GET_MIN, (cval->control << 8) | minchn, &cval->min) < 0) { | 782 | get_ctl_value(cval, UAC_GET_MIN, (cval->control << 8) | minchn, &cval->min) < 0) { |
769 | snd_printd(KERN_ERR "%d:%d: cannot get min/max values for control %d (id %d)\n", | 783 | snd_printd(KERN_ERR "%d:%d: cannot get min/max values for control %d (id %d)\n", |
770 | cval->id, cval->mixer->ctrlif, cval->control, cval->id); | 784 | cval->id, snd_usb_ctrl_intf(cval->mixer->chip), cval->control, cval->id); |
771 | return -EINVAL; | 785 | return -EINVAL; |
772 | } | 786 | } |
773 | if (get_ctl_value(cval, UAC_GET_RES, (cval->control << 8) | minchn, &cval->res) < 0) { | 787 | if (get_ctl_value(cval, UAC_GET_RES, (cval->control << 8) | minchn, &cval->res) < 0) { |
@@ -1199,14 +1213,6 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void | |||
1199 | } | 1213 | } |
1200 | } else { /* UAC_VERSION_2 */ | 1214 | } else { /* UAC_VERSION_2 */ |
1201 | for (i = 0; i < 30/2; i++) { | 1215 | for (i = 0; i < 30/2; i++) { |
1202 | /* From the USB Audio spec v2.0: | ||
1203 | bmaControls() is a (ch+1)-element array of 4-byte bitmaps, | ||
1204 | each containing a set of bit pairs. If a Control is present, | ||
1205 | it must be Host readable. If a certain Control is not | ||
1206 | present then the bit pair must be set to 0b00. | ||
1207 | If a Control is present but read-only, the bit pair must be | ||
1208 | set to 0b01. If a Control is also Host programmable, the bit | ||
1209 | pair must be set to 0b11. The value 0b10 is not allowed. */ | ||
1210 | unsigned int ch_bits = 0; | 1216 | unsigned int ch_bits = 0; |
1211 | unsigned int ch_read_only = 0; | 1217 | unsigned int ch_read_only = 0; |
1212 | 1218 | ||
@@ -1634,9 +1640,10 @@ static int mixer_ctl_selector_info(struct snd_kcontrol *kcontrol, struct snd_ctl | |||
1634 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 1640 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; |
1635 | uinfo->count = 1; | 1641 | uinfo->count = 1; |
1636 | uinfo->value.enumerated.items = cval->max; | 1642 | uinfo->value.enumerated.items = cval->max; |
1637 | if ((int)uinfo->value.enumerated.item >= cval->max) | 1643 | if (uinfo->value.enumerated.item >= cval->max) |
1638 | uinfo->value.enumerated.item = cval->max - 1; | 1644 | uinfo->value.enumerated.item = cval->max - 1; |
1639 | strcpy(uinfo->value.enumerated.name, itemlist[uinfo->value.enumerated.item]); | 1645 | strlcpy(uinfo->value.enumerated.name, itemlist[uinfo->value.enumerated.item], |
1646 | sizeof(uinfo->value.enumerated.name)); | ||
1640 | return 0; | 1647 | return 0; |
1641 | } | 1648 | } |
1642 | 1649 | ||
@@ -1855,13 +1862,13 @@ static int parse_audio_unit(struct mixer_build *state, int unitid) | |||
1855 | return parse_audio_selector_unit(state, unitid, p1); | 1862 | return parse_audio_selector_unit(state, unitid, p1); |
1856 | case UAC_FEATURE_UNIT: | 1863 | case UAC_FEATURE_UNIT: |
1857 | return parse_audio_feature_unit(state, unitid, p1); | 1864 | return parse_audio_feature_unit(state, unitid, p1); |
1858 | case UAC_PROCESSING_UNIT_V1: | 1865 | case UAC1_PROCESSING_UNIT: |
1859 | /* UAC2_EFFECT_UNIT has the same value */ | 1866 | /* UAC2_EFFECT_UNIT has the same value */ |
1860 | if (state->mixer->protocol == UAC_VERSION_1) | 1867 | if (state->mixer->protocol == UAC_VERSION_1) |
1861 | return parse_audio_processing_unit(state, unitid, p1); | 1868 | return parse_audio_processing_unit(state, unitid, p1); |
1862 | else | 1869 | else |
1863 | return 0; /* FIXME - effect units not implemented yet */ | 1870 | return 0; /* FIXME - effect units not implemented yet */ |
1864 | case UAC_EXTENSION_UNIT_V1: | 1871 | case UAC1_EXTENSION_UNIT: |
1865 | /* UAC2_PROCESSING_UNIT_V2 has the same value */ | 1872 | /* UAC2_PROCESSING_UNIT_V2 has the same value */ |
1866 | if (state->mixer->protocol == UAC_VERSION_1) | 1873 | if (state->mixer->protocol == UAC_VERSION_1) |
1867 | return parse_audio_extension_unit(state, unitid, p1); | 1874 | return parse_audio_extension_unit(state, unitid, p1); |
@@ -1905,7 +1912,7 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer) | |||
1905 | struct usb_host_interface *hostif; | 1912 | struct usb_host_interface *hostif; |
1906 | void *p; | 1913 | void *p; |
1907 | 1914 | ||
1908 | hostif = &usb_ifnum_to_if(mixer->chip->dev, mixer->ctrlif)->altsetting[0]; | 1915 | hostif = mixer->chip->ctrl_intf; |
1909 | memset(&state, 0, sizeof(state)); | 1916 | memset(&state, 0, sizeof(state)); |
1910 | state.chip = mixer->chip; | 1917 | state.chip = mixer->chip; |
1911 | state.mixer = mixer; | 1918 | state.mixer = mixer; |
@@ -1925,7 +1932,7 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer) | |||
1925 | p = NULL; | 1932 | p = NULL; |
1926 | while ((p = snd_usb_find_csint_desc(hostif->extra, hostif->extralen, p, UAC_OUTPUT_TERMINAL)) != NULL) { | 1933 | while ((p = snd_usb_find_csint_desc(hostif->extra, hostif->extralen, p, UAC_OUTPUT_TERMINAL)) != NULL) { |
1927 | if (mixer->protocol == UAC_VERSION_1) { | 1934 | if (mixer->protocol == UAC_VERSION_1) { |
1928 | struct uac_output_terminal_descriptor_v1 *desc = p; | 1935 | struct uac1_output_terminal_descriptor *desc = p; |
1929 | 1936 | ||
1930 | if (desc->bLength < sizeof(*desc)) | 1937 | if (desc->bLength < sizeof(*desc)) |
1931 | continue; /* invalid descriptor? */ | 1938 | continue; /* invalid descriptor? */ |
@@ -1997,7 +2004,7 @@ static void snd_usb_mixer_proc_read(struct snd_info_entry *entry, | |||
1997 | list_for_each_entry(mixer, &chip->mixer_list, list) { | 2004 | list_for_each_entry(mixer, &chip->mixer_list, list) { |
1998 | snd_iprintf(buffer, | 2005 | snd_iprintf(buffer, |
1999 | "USB Mixer: usb_id=0x%08x, ctrlif=%i, ctlerr=%i\n", | 2006 | "USB Mixer: usb_id=0x%08x, ctrlif=%i, ctlerr=%i\n", |
2000 | chip->usb_id, mixer->ctrlif, | 2007 | chip->usb_id, snd_usb_ctrl_intf(chip), |
2001 | mixer->ignore_ctl_error); | 2008 | mixer->ignore_ctl_error); |
2002 | snd_iprintf(buffer, "Card: %s\n", chip->card->longname); | 2009 | snd_iprintf(buffer, "Card: %s\n", chip->card->longname); |
2003 | for (unitid = 0; unitid < MAX_ID_ELEMS; unitid++) { | 2010 | for (unitid = 0; unitid < MAX_ID_ELEMS; unitid++) { |
@@ -2115,7 +2122,7 @@ static int snd_usb_mixer_status_create(struct usb_mixer_interface *mixer) | |||
2115 | int buffer_length; | 2122 | int buffer_length; |
2116 | unsigned int epnum; | 2123 | unsigned int epnum; |
2117 | 2124 | ||
2118 | hostif = &usb_ifnum_to_if(mixer->chip->dev, mixer->ctrlif)->altsetting[0]; | 2125 | hostif = mixer->chip->ctrl_intf; |
2119 | /* we need one interrupt input endpoint */ | 2126 | /* we need one interrupt input endpoint */ |
2120 | if (get_iface_desc(hostif)->bNumEndpoints < 1) | 2127 | if (get_iface_desc(hostif)->bNumEndpoints < 1) |
2121 | return 0; | 2128 | return 0; |
@@ -2158,7 +2165,6 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, | |||
2158 | if (!mixer) | 2165 | if (!mixer) |
2159 | return -ENOMEM; | 2166 | return -ENOMEM; |
2160 | mixer->chip = chip; | 2167 | mixer->chip = chip; |
2161 | mixer->ctrlif = ctrlif; | ||
2162 | mixer->ignore_ctl_error = ignore_error; | 2168 | mixer->ignore_ctl_error = ignore_error; |
2163 | mixer->id_elems = kcalloc(MAX_ID_ELEMS, sizeof(*mixer->id_elems), | 2169 | mixer->id_elems = kcalloc(MAX_ID_ELEMS, sizeof(*mixer->id_elems), |
2164 | GFP_KERNEL); | 2170 | GFP_KERNEL); |
@@ -2168,7 +2174,15 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, | |||
2168 | } | 2174 | } |
2169 | 2175 | ||
2170 | host_iface = &usb_ifnum_to_if(chip->dev, ctrlif)->altsetting[0]; | 2176 | host_iface = &usb_ifnum_to_if(chip->dev, ctrlif)->altsetting[0]; |
2171 | mixer->protocol = get_iface_desc(host_iface)->bInterfaceProtocol; | 2177 | switch (get_iface_desc(host_iface)->bInterfaceProtocol) { |
2178 | case UAC_VERSION_1: | ||
2179 | default: | ||
2180 | mixer->protocol = UAC_VERSION_1; | ||
2181 | break; | ||
2182 | case UAC_VERSION_2: | ||
2183 | mixer->protocol = UAC_VERSION_2; | ||
2184 | break; | ||
2185 | } | ||
2172 | 2186 | ||
2173 | if ((err = snd_usb_mixer_controls(mixer)) < 0 || | 2187 | if ((err = snd_usb_mixer_controls(mixer)) < 0 || |
2174 | (err = snd_usb_mixer_status_create(mixer)) < 0) | 2188 | (err = snd_usb_mixer_status_create(mixer)) < 0) |
diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h index a7cf1007fbb0..26c636c5c93a 100644 --- a/sound/usb/mixer.h +++ b/sound/usb/mixer.h | |||
@@ -3,7 +3,6 @@ | |||
3 | 3 | ||
4 | struct usb_mixer_interface { | 4 | struct usb_mixer_interface { |
5 | struct snd_usb_audio *chip; | 5 | struct snd_usb_audio *chip; |
6 | unsigned int ctrlif; | ||
7 | struct list_head list; | 6 | struct list_head list; |
8 | unsigned int ignore_ctl_error; | 7 | unsigned int ignore_ctl_error; |
9 | struct urb *urb; | 8 | struct urb *urb; |
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 456829882f40..f49756c1b837 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c | |||
@@ -173,13 +173,12 @@ int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface, | |||
173 | 173 | ||
174 | switch (altsd->bInterfaceProtocol) { | 174 | switch (altsd->bInterfaceProtocol) { |
175 | case UAC_VERSION_1: | 175 | case UAC_VERSION_1: |
176 | default: | ||
176 | return init_pitch_v1(chip, iface, alts, fmt); | 177 | return init_pitch_v1(chip, iface, alts, fmt); |
177 | 178 | ||
178 | case UAC_VERSION_2: | 179 | case UAC_VERSION_2: |
179 | return init_pitch_v2(chip, iface, alts, fmt); | 180 | return init_pitch_v2(chip, iface, alts, fmt); |
180 | } | 181 | } |
181 | |||
182 | return -EINVAL; | ||
183 | } | 182 | } |
184 | 183 | ||
185 | /* | 184 | /* |
@@ -467,7 +466,7 @@ static int hw_check_valid_format(struct snd_usb_substream *subs, | |||
467 | return 0; | 466 | return 0; |
468 | } | 467 | } |
469 | /* check whether the period time is >= the data packet interval */ | 468 | /* check whether the period time is >= the data packet interval */ |
470 | if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH) { | 469 | if (snd_usb_get_speed(subs->dev) != USB_SPEED_FULL) { |
471 | ptime = 125 * (1 << fp->datainterval); | 470 | ptime = 125 * (1 << fp->datainterval); |
472 | if (ptime > pt->max || (ptime == pt->max && pt->openmax)) { | 471 | if (ptime > pt->max || (ptime == pt->max && pt->openmax)) { |
473 | hwc_debug(" > check: ptime %u > max %u\n", ptime, pt->max); | 472 | hwc_debug(" > check: ptime %u > max %u\n", ptime, pt->max); |
@@ -636,7 +635,7 @@ static int hw_rule_period_time(struct snd_pcm_hw_params *params, | |||
636 | min_datainterval = min(min_datainterval, fp->datainterval); | 635 | min_datainterval = min(min_datainterval, fp->datainterval); |
637 | } | 636 | } |
638 | if (min_datainterval == 0xff) { | 637 | if (min_datainterval == 0xff) { |
639 | hwc_debug(" --> get emtpy\n"); | 638 | hwc_debug(" --> get empty\n"); |
640 | it->empty = 1; | 639 | it->empty = 1; |
641 | return -EINVAL; | 640 | return -EINVAL; |
642 | } | 641 | } |
@@ -735,7 +734,7 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre | |||
735 | } | 734 | } |
736 | 735 | ||
737 | param_period_time_if_needed = SNDRV_PCM_HW_PARAM_PERIOD_TIME; | 736 | param_period_time_if_needed = SNDRV_PCM_HW_PARAM_PERIOD_TIME; |
738 | if (snd_usb_get_speed(subs->dev) != USB_SPEED_HIGH) | 737 | if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL) |
739 | /* full speed devices have fixed data packet interval */ | 738 | /* full speed devices have fixed data packet interval */ |
740 | ptmin = 1000; | 739 | ptmin = 1000; |
741 | if (ptmin == 1000) | 740 | if (ptmin == 1000) |
diff --git a/sound/usb/pcm.h b/sound/usb/pcm.h index 1c931b68f3b5..ed3e283f618d 100644 --- a/sound/usb/pcm.h +++ b/sound/usb/pcm.h | |||
@@ -7,8 +7,5 @@ int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface, | |||
7 | struct usb_host_interface *alts, | 7 | struct usb_host_interface *alts, |
8 | struct audioformat *fmt); | 8 | struct audioformat *fmt); |
9 | 9 | ||
10 | int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface, | ||
11 | struct usb_host_interface *alts, | ||
12 | struct audioformat *fmt, int rate); | ||
13 | 10 | ||
14 | #endif /* __USBAUDIO_PCM_H */ | 11 | #endif /* __USBAUDIO_PCM_H */ |
diff --git a/sound/usb/proc.c b/sound/usb/proc.c index f5e3f356b95f..3c650ab3c91d 100644 --- a/sound/usb/proc.c +++ b/sound/usb/proc.c | |||
@@ -107,7 +107,7 @@ static void proc_dump_substream_formats(struct snd_usb_substream *subs, struct s | |||
107 | } | 107 | } |
108 | snd_iprintf(buffer, "\n"); | 108 | snd_iprintf(buffer, "\n"); |
109 | } | 109 | } |
110 | if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH) | 110 | if (snd_usb_get_speed(subs->dev) != USB_SPEED_FULL) |
111 | snd_iprintf(buffer, " Data packet interval: %d us\n", | 111 | snd_iprintf(buffer, " Data packet interval: %d us\n", |
112 | 125 * (1 << fp->datainterval)); | 112 | 125 * (1 << fp->datainterval)); |
113 | // snd_iprintf(buffer, " Max Packet Size = %d\n", fp->maxpacksize); | 113 | // snd_iprintf(buffer, " Max Packet Size = %d\n", fp->maxpacksize); |
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index f8797f61a24b..c86c613e0b96 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h | |||
@@ -1136,11 +1136,34 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
1136 | } | 1136 | } |
1137 | }, | 1137 | }, |
1138 | { | 1138 | { |
1139 | /* has ID 0x0066 when not in "Advanced Driver" mode */ | ||
1140 | USB_DEVICE(0x0582, 0x0064), | ||
1141 | .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { | ||
1142 | /* .vendor_name = "EDIROL", */ | ||
1143 | /* .product_name = "PCR-1", */ | ||
1144 | .ifnum = QUIRK_ANY_INTERFACE, | ||
1145 | .type = QUIRK_COMPOSITE, | ||
1146 | .data = (const struct snd_usb_audio_quirk[]) { | ||
1147 | { | ||
1148 | .ifnum = 1, | ||
1149 | .type = QUIRK_AUDIO_STANDARD_INTERFACE | ||
1150 | }, | ||
1151 | { | ||
1152 | .ifnum = 2, | ||
1153 | .type = QUIRK_AUDIO_STANDARD_INTERFACE | ||
1154 | }, | ||
1155 | { | ||
1156 | .ifnum = -1 | ||
1157 | } | ||
1158 | } | ||
1159 | } | ||
1160 | }, | ||
1161 | { | ||
1139 | /* has ID 0x0067 when not in "Advanced Driver" mode */ | 1162 | /* has ID 0x0067 when not in "Advanced Driver" mode */ |
1140 | USB_DEVICE(0x0582, 0x0065), | 1163 | USB_DEVICE(0x0582, 0x0065), |
1141 | .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { | 1164 | .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { |
1142 | .vendor_name = "EDIROL", | 1165 | /* .vendor_name = "EDIROL", */ |
1143 | .product_name = "PCR-1", | 1166 | /* .product_name = "PCR-1", */ |
1144 | .ifnum = 0, | 1167 | .ifnum = 0, |
1145 | .type = QUIRK_MIDI_FIXED_ENDPOINT, | 1168 | .type = QUIRK_MIDI_FIXED_ENDPOINT, |
1146 | .data = & (const struct snd_usb_midi_endpoint_info) { | 1169 | .data = & (const struct snd_usb_midi_endpoint_info) { |
@@ -1525,6 +1548,50 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
1525 | } | 1548 | } |
1526 | } | 1549 | } |
1527 | }, | 1550 | }, |
1551 | { | ||
1552 | /* has ID 0x0110 when not in Advanced Driver mode */ | ||
1553 | USB_DEVICE_VENDOR_SPEC(0x0582, 0x010f), | ||
1554 | .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { | ||
1555 | /* .vendor_name = "Roland", */ | ||
1556 | /* .product_name = "A-PRO", */ | ||
1557 | .ifnum = 1, | ||
1558 | .type = QUIRK_MIDI_FIXED_ENDPOINT, | ||
1559 | .data = & (const struct snd_usb_midi_endpoint_info) { | ||
1560 | .out_cables = 0x0003, | ||
1561 | .in_cables = 0x0007 | ||
1562 | } | ||
1563 | } | ||
1564 | }, | ||
1565 | { | ||
1566 | USB_DEVICE(0x0582, 0x0113), | ||
1567 | .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { | ||
1568 | /* .vendor_name = "BOSS", */ | ||
1569 | /* .product_name = "ME-25", */ | ||
1570 | .ifnum = QUIRK_ANY_INTERFACE, | ||
1571 | .type = QUIRK_COMPOSITE, | ||
1572 | .data = (const struct snd_usb_audio_quirk[]) { | ||
1573 | { | ||
1574 | .ifnum = 0, | ||
1575 | .type = QUIRK_AUDIO_STANDARD_INTERFACE | ||
1576 | }, | ||
1577 | { | ||
1578 | .ifnum = 1, | ||
1579 | .type = QUIRK_AUDIO_STANDARD_INTERFACE | ||
1580 | }, | ||
1581 | { | ||
1582 | .ifnum = 2, | ||
1583 | .type = QUIRK_MIDI_FIXED_ENDPOINT, | ||
1584 | .data = & (const struct snd_usb_midi_endpoint_info) { | ||
1585 | .out_cables = 0x0001, | ||
1586 | .in_cables = 0x0001 | ||
1587 | } | ||
1588 | }, | ||
1589 | { | ||
1590 | .ifnum = -1 | ||
1591 | } | ||
1592 | } | ||
1593 | } | ||
1594 | }, | ||
1528 | 1595 | ||
1529 | /* Guillemot devices */ | 1596 | /* Guillemot devices */ |
1530 | { | 1597 | { |
@@ -1830,7 +1897,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
1830 | USB_DEVICE(0x0763, 0x2080), | 1897 | USB_DEVICE(0x0763, 0x2080), |
1831 | .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { | 1898 | .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { |
1832 | /* .vendor_name = "M-Audio", */ | 1899 | /* .vendor_name = "M-Audio", */ |
1833 | /* .product_name = "Fast Track Ultra 8", */ | 1900 | /* .product_name = "Fast Track Ultra", */ |
1834 | .ifnum = QUIRK_ANY_INTERFACE, | 1901 | .ifnum = QUIRK_ANY_INTERFACE, |
1835 | .type = QUIRK_COMPOSITE, | 1902 | .type = QUIRK_COMPOSITE, |
1836 | .data = & (const struct snd_usb_audio_quirk[]) { | 1903 | .data = & (const struct snd_usb_audio_quirk[]) { |
@@ -1840,11 +1907,51 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
1840 | }, | 1907 | }, |
1841 | { | 1908 | { |
1842 | .ifnum = 1, | 1909 | .ifnum = 1, |
1843 | .type = QUIRK_AUDIO_STANDARD_INTERFACE | 1910 | .type = QUIRK_AUDIO_FIXED_ENDPOINT, |
1911 | .data = & (const struct audioformat) { | ||
1912 | .formats = SNDRV_PCM_FMTBIT_S24_3LE, | ||
1913 | .channels = 8, | ||
1914 | .iface = 1, | ||
1915 | .altsetting = 1, | ||
1916 | .altset_idx = 1, | ||
1917 | .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE, | ||
1918 | .endpoint = 0x01, | ||
1919 | .ep_attr = 0x09, | ||
1920 | .rates = SNDRV_PCM_RATE_44100 | | ||
1921 | SNDRV_PCM_RATE_48000 | | ||
1922 | SNDRV_PCM_RATE_88200 | | ||
1923 | SNDRV_PCM_RATE_96000, | ||
1924 | .rate_min = 44100, | ||
1925 | .rate_max = 96000, | ||
1926 | .nr_rates = 4, | ||
1927 | .rate_table = (unsigned int[]) { | ||
1928 | 44100, 48000, 88200, 96000 | ||
1929 | } | ||
1930 | } | ||
1844 | }, | 1931 | }, |
1845 | { | 1932 | { |
1846 | .ifnum = 2, | 1933 | .ifnum = 2, |
1847 | .type = QUIRK_AUDIO_STANDARD_INTERFACE | 1934 | .type = QUIRK_AUDIO_FIXED_ENDPOINT, |
1935 | .data = & (const struct audioformat) { | ||
1936 | .formats = SNDRV_PCM_FMTBIT_S24_3LE, | ||
1937 | .channels = 8, | ||
1938 | .iface = 2, | ||
1939 | .altsetting = 1, | ||
1940 | .altset_idx = 1, | ||
1941 | .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE, | ||
1942 | .endpoint = 0x81, | ||
1943 | .ep_attr = 0x05, | ||
1944 | .rates = SNDRV_PCM_RATE_44100 | | ||
1945 | SNDRV_PCM_RATE_48000 | | ||
1946 | SNDRV_PCM_RATE_88200 | | ||
1947 | SNDRV_PCM_RATE_96000, | ||
1948 | .rate_min = 44100, | ||
1949 | .rate_max = 96000, | ||
1950 | .nr_rates = 4, | ||
1951 | .rate_table = (unsigned int[]) { | ||
1952 | 44100, 48000, 88200, 96000 | ||
1953 | } | ||
1954 | } | ||
1848 | }, | 1955 | }, |
1849 | /* interface 3 (MIDI) is standard compliant */ | 1956 | /* interface 3 (MIDI) is standard compliant */ |
1850 | { | 1957 | { |
@@ -1867,11 +1974,51 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
1867 | }, | 1974 | }, |
1868 | { | 1975 | { |
1869 | .ifnum = 1, | 1976 | .ifnum = 1, |
1870 | .type = QUIRK_AUDIO_STANDARD_INTERFACE | 1977 | .type = QUIRK_AUDIO_FIXED_ENDPOINT, |
1978 | .data = & (const struct audioformat) { | ||
1979 | .formats = SNDRV_PCM_FMTBIT_S24_3LE, | ||
1980 | .channels = 8, | ||
1981 | .iface = 1, | ||
1982 | .altsetting = 1, | ||
1983 | .altset_idx = 1, | ||
1984 | .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE, | ||
1985 | .endpoint = 0x01, | ||
1986 | .ep_attr = 0x09, | ||
1987 | .rates = SNDRV_PCM_RATE_44100 | | ||
1988 | SNDRV_PCM_RATE_48000 | | ||
1989 | SNDRV_PCM_RATE_88200 | | ||
1990 | SNDRV_PCM_RATE_96000, | ||
1991 | .rate_min = 44100, | ||
1992 | .rate_max = 96000, | ||
1993 | .nr_rates = 4, | ||
1994 | .rate_table = (unsigned int[]) { | ||
1995 | 44100, 48000, 88200, 96000 | ||
1996 | } | ||
1997 | } | ||
1871 | }, | 1998 | }, |
1872 | { | 1999 | { |
1873 | .ifnum = 2, | 2000 | .ifnum = 2, |
1874 | .type = QUIRK_AUDIO_STANDARD_INTERFACE | 2001 | .type = QUIRK_AUDIO_FIXED_ENDPOINT, |
2002 | .data = & (const struct audioformat) { | ||
2003 | .formats = SNDRV_PCM_FMTBIT_S24_3LE, | ||
2004 | .channels = 8, | ||
2005 | .iface = 2, | ||
2006 | .altsetting = 1, | ||
2007 | .altset_idx = 1, | ||
2008 | .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE, | ||
2009 | .endpoint = 0x81, | ||
2010 | .ep_attr = 0x05, | ||
2011 | .rates = SNDRV_PCM_RATE_44100 | | ||
2012 | SNDRV_PCM_RATE_48000 | | ||
2013 | SNDRV_PCM_RATE_88200 | | ||
2014 | SNDRV_PCM_RATE_96000, | ||
2015 | .rate_min = 44100, | ||
2016 | .rate_max = 96000, | ||
2017 | .nr_rates = 4, | ||
2018 | .rate_table = (unsigned int[]) { | ||
2019 | 44100, 48000, 88200, 96000 | ||
2020 | } | ||
2021 | } | ||
1875 | }, | 2022 | }, |
1876 | /* interface 3 (MIDI) is standard compliant */ | 2023 | /* interface 3 (MIDI) is standard compliant */ |
1877 | { | 2024 | { |
@@ -2152,7 +2299,21 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
2152 | } | 2299 | } |
2153 | }, | 2300 | }, |
2154 | { | 2301 | { |
2155 | USB_DEVICE_VENDOR_SPEC(0x2040, 0x7201), | 2302 | USB_DEVICE_VENDOR_SPEC(0x2040, 0x7240), |
2303 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | | ||
2304 | USB_DEVICE_ID_MATCH_INT_CLASS | | ||
2305 | USB_DEVICE_ID_MATCH_INT_SUBCLASS, | ||
2306 | .bInterfaceClass = USB_CLASS_AUDIO, | ||
2307 | .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL, | ||
2308 | .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { | ||
2309 | .vendor_name = "Hauppauge", | ||
2310 | .product_name = "HVR-850", | ||
2311 | .ifnum = QUIRK_ANY_INTERFACE, | ||
2312 | .type = QUIRK_AUDIO_ALIGN_TRANSFER, | ||
2313 | } | ||
2314 | }, | ||
2315 | { | ||
2316 | USB_DEVICE_VENDOR_SPEC(0x2040, 0x7210), | ||
2156 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | | 2317 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | |
2157 | USB_DEVICE_ID_MATCH_INT_CLASS | | 2318 | USB_DEVICE_ID_MATCH_INT_CLASS | |
2158 | USB_DEVICE_ID_MATCH_INT_SUBCLASS, | 2319 | USB_DEVICE_ID_MATCH_INT_SUBCLASS, |
@@ -2166,7 +2327,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
2166 | } | 2327 | } |
2167 | }, | 2328 | }, |
2168 | { | 2329 | { |
2169 | USB_DEVICE_VENDOR_SPEC(0x2040, 0x7202), | 2330 | USB_DEVICE_VENDOR_SPEC(0x2040, 0x7217), |
2170 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | | 2331 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | |
2171 | USB_DEVICE_ID_MATCH_INT_CLASS | | 2332 | USB_DEVICE_ID_MATCH_INT_CLASS | |
2172 | USB_DEVICE_ID_MATCH_INT_SUBCLASS, | 2333 | USB_DEVICE_ID_MATCH_INT_SUBCLASS, |
@@ -2180,7 +2341,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
2180 | } | 2341 | } |
2181 | }, | 2342 | }, |
2182 | { | 2343 | { |
2183 | USB_DEVICE_VENDOR_SPEC(0x2040, 0x7203), | 2344 | USB_DEVICE_VENDOR_SPEC(0x2040, 0x721b), |
2184 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | | 2345 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | |
2185 | USB_DEVICE_ID_MATCH_INT_CLASS | | 2346 | USB_DEVICE_ID_MATCH_INT_CLASS | |
2186 | USB_DEVICE_ID_MATCH_INT_SUBCLASS, | 2347 | USB_DEVICE_ID_MATCH_INT_SUBCLASS, |
@@ -2194,7 +2355,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
2194 | } | 2355 | } |
2195 | }, | 2356 | }, |
2196 | { | 2357 | { |
2197 | USB_DEVICE_VENDOR_SPEC(0x2040, 0x7204), | 2358 | USB_DEVICE_VENDOR_SPEC(0x2040, 0x721e), |
2198 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | | 2359 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | |
2199 | USB_DEVICE_ID_MATCH_INT_CLASS | | 2360 | USB_DEVICE_ID_MATCH_INT_CLASS | |
2200 | USB_DEVICE_ID_MATCH_INT_SUBCLASS, | 2361 | USB_DEVICE_ID_MATCH_INT_SUBCLASS, |
@@ -2208,7 +2369,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
2208 | } | 2369 | } |
2209 | }, | 2370 | }, |
2210 | { | 2371 | { |
2211 | USB_DEVICE_VENDOR_SPEC(0x2040, 0x7205), | 2372 | USB_DEVICE_VENDOR_SPEC(0x2040, 0x721f), |
2212 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | | 2373 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | |
2213 | USB_DEVICE_ID_MATCH_INT_CLASS | | 2374 | USB_DEVICE_ID_MATCH_INT_CLASS | |
2214 | USB_DEVICE_ID_MATCH_INT_SUBCLASS, | 2375 | USB_DEVICE_ID_MATCH_INT_SUBCLASS, |
@@ -2222,7 +2383,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
2222 | } | 2383 | } |
2223 | }, | 2384 | }, |
2224 | { | 2385 | { |
2225 | USB_DEVICE_VENDOR_SPEC(0x2040, 0x7250), | 2386 | USB_DEVICE_VENDOR_SPEC(0x2040, 0x7280), |
2226 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | | 2387 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | |
2227 | USB_DEVICE_ID_MATCH_INT_CLASS | | 2388 | USB_DEVICE_ID_MATCH_INT_CLASS | |
2228 | USB_DEVICE_ID_MATCH_INT_SUBCLASS, | 2389 | USB_DEVICE_ID_MATCH_INT_SUBCLASS, |
@@ -2236,7 +2397,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
2236 | } | 2397 | } |
2237 | }, | 2398 | }, |
2238 | { | 2399 | { |
2239 | USB_DEVICE_VENDOR_SPEC(0x2040, 0x7230), | 2400 | USB_DEVICE_VENDOR_SPEC(0x0fd9, 0x0008), |
2240 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | | 2401 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | |
2241 | USB_DEVICE_ID_MATCH_INT_CLASS | | 2402 | USB_DEVICE_ID_MATCH_INT_CLASS | |
2242 | USB_DEVICE_ID_MATCH_INT_SUBCLASS, | 2403 | USB_DEVICE_ID_MATCH_INT_SUBCLASS, |
@@ -2244,7 +2405,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
2244 | .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL, | 2405 | .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL, |
2245 | .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { | 2406 | .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { |
2246 | .vendor_name = "Hauppauge", | 2407 | .vendor_name = "Hauppauge", |
2247 | .product_name = "HVR-850", | 2408 | .product_name = "HVR-950Q", |
2248 | .ifnum = QUIRK_ANY_INTERFACE, | 2409 | .ifnum = QUIRK_ANY_INTERFACE, |
2249 | .type = QUIRK_AUDIO_ALIGN_TRANSFER, | 2410 | .type = QUIRK_AUDIO_ALIGN_TRANSFER, |
2250 | } | 2411 | } |
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index b45e54c09ba2..9a9da09586a5 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include "helper.h" | 32 | #include "helper.h" |
33 | #include "endpoint.h" | 33 | #include "endpoint.h" |
34 | #include "pcm.h" | 34 | #include "pcm.h" |
35 | #include "clock.h" | ||
35 | 36 | ||
36 | /* | 37 | /* |
37 | * handle the quirks for the contained interfaces | 38 | * handle the quirks for the contained interfaces |
diff --git a/sound/usb/urb.c b/sound/usb/urb.c index de607d4411ac..8deeaad10f10 100644 --- a/sound/usb/urb.c +++ b/sound/usb/urb.c | |||
@@ -244,7 +244,7 @@ int snd_usb_init_substream_urbs(struct snd_usb_substream *subs, | |||
244 | else | 244 | else |
245 | subs->curpacksize = maxsize; | 245 | subs->curpacksize = maxsize; |
246 | 246 | ||
247 | if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH) | 247 | if (snd_usb_get_speed(subs->dev) != USB_SPEED_FULL) |
248 | packs_per_ms = 8 >> subs->datainterval; | 248 | packs_per_ms = 8 >> subs->datainterval; |
249 | else | 249 | else |
250 | packs_per_ms = 1; | 250 | packs_per_ms = 1; |